package com.moparisthebest.dns; import com.moparisthebest.dns.listen.Listener; import com.moparisthebest.dns.net.ParsedUrl; import com.moparisthebest.dns.resolve.*; import java.io.File; import java.io.FileInputStream; import java.util.*; import java.util.concurrent.*; import java.util.stream.Collectors; import static com.moparisthebest.dns.Util.tryClose; public class DnsProxy { public static void main(String[] args) throws Throwable { if (args.length == 2) { // quick hack to run direct proxy todo: make this shut down clean Listener.of(ParsedUrl.of(args[0]), Resolver.of(ParsedUrl.of(args[1])), ForkJoinPool.commonPool()).run(); return; } final Map config; final File propsFile = new File(args.length > 0 ? args[0] : "jdnsproxy.properties"); if(propsFile.canRead()) { try (FileInputStream fis = new FileInputStream(propsFile)) { final Properties props = new Properties(); props.load(fis); @SuppressWarnings("unchecked") final Map configUnchecked = (Map) (Object) props; config = configUnchecked; } } else { if(args.length > 0) { System.err.printf("Error: config file '%s' does not exist or can't be read%n", args[0]); return; } config = Collections.emptyMap(); } System.out.println("config:" + config); final int minTtl = Integer.parseInt(config.getOrDefault("minTtl", "600")); final int staleResponseTtl = Integer.parseInt(config.getOrDefault("staleResponseTtl", "10")); final long staleResponseTimeout = Long.parseLong(config.getOrDefault("staleResponseTimeout", "1000")); final int packetQueueLength = Integer.parseInt(config.getOrDefault("packetQueueLength", "100")); final String cacheFile = config.get("cacheFile"); final long cacheDelayMinutes = Long.parseLong(config.getOrDefault("cacheDelayMinutes", "60")); final String[] resolvers = config.getOrDefault("resolvers", "https://dns.google.com/experimental?ct#name=dns.google.com").split("\\s+"); if (!config.containsKey("maxRetries")) config.put("maxRetries", String.valueOf(resolvers.length * 2)); //System.out.println("resolvers: " + Arrays.toString(resolvers)); final List queueProcessingResolvers = Arrays.stream(resolvers).map(s -> ParsedUrl.of(s, config)).map(QueueProcessingResolver::of).collect(Collectors.toList()); //final List queueProcessingResolvers = new ArrayList<>(); //queueProcessingResolvers.add(new SocketResolver(5, "socket1", SocketFactory.getDefault(), new InetSocketAddress("8.8.4.4", 53))); //queueProcessingResolvers.add(new HttpResolver(5, "http1", "https://dns.google.com/experimental?ct")); final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(40); final ExecutorService executor = scheduledExecutorService;//ForkJoinPool.commonPool(); final CacheResolver resolver = new CacheResolver( MapResolver.minTtl(minTtl, new BlockingQueueResolver(packetQueueLength) .startQueueProcessingResolvers(executor, queueProcessingResolvers) ), staleResponseTtl, staleResponseTimeout, scheduledExecutorService, cacheFile, cacheDelayMinutes) ; final List listeners = Arrays.stream(config.getOrDefault("listeners", "tcp://127.0.0.1:5353 udp://127.0.0.1:5353").split("\\s+")) .map(url -> Listener.ofAndStart(ParsedUrl.of(url), resolver, executor)).collect(Collectors.toList()); //final List listeners = new ArrayList<>(); //listeners.add(Listener.ofAndStart("tcp://127.0.0.1:5556", resolver, executor)); //listeners.add(Listener.ofAndStart("udp://127.0.0.1:5556", resolver, executor)); System.out.println("startup complete"); final Thread cleanKill = new Thread(() -> { System.out.println("shutdown requested"); //if(true) return; executor.shutdown(); scheduledExecutorService.shutdown(); queueProcessingResolvers.forEach(Util::tryClose); listeners.forEach(Util::tryClose); tryClose(resolver); System.out.println("shutdown complete"); }); Runtime.getRuntime().addShutdownHook(cleanKill); executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); } }