123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- using System;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.IO;
- using System.Linq;
- using System.Net;
- using System.Net.Sockets;
- using System.Text;
- namespace DnsForwarder
- {
- internal class Program
- {
- private static string _defaultDns;
- private static string _cnDns;
- private static IReadOnlyDictionary<string, int> _chinaList;
- private static string[] _chinaListDns;
- private static Socket _listener;
- private static BlockingCollection<string> _consoleOutout;
- private static void Main(string[] args)
- {
- if (args.Length != 3)
- {
- Console.WriteLine("<default dns server ip> <.CN dns server ip> <path to dnsmasq-china-list file>");
- Environment.Exit(-1);
- return;
- }
- Console.WriteLine("Starting...");
- Console.WriteLine($"Default Server:{_defaultDns = args[0]}");
- Console.WriteLine($"China DNS Server:{_cnDns = args[1]}");
- Console.WriteLine($"dnsmasq-china-list file:{args[2]}");
- Console.WriteLine("Loading list file...");
- LoadListFile(args[2]);
- Console.WriteLine("OK. Listening...");
- _listener = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
- _listener.Bind(new IPEndPoint(IPAddress.Any, 53));
- _consoleOutout = new BlockingCollection<string>();
- StartHandleRequest();
- while (true)
- {
- Console.WriteLine(_consoleOutout.Take());
- }
- }
- private static void StartHandleRequest()
- {
- var buf = new byte[1500];
- EndPoint from = new IPEndPoint(IPAddress.Any, 0);
- _listener.BeginReceiveFrom(buf, 0, buf.Length, SocketFlags.None, ref from, Callback, buf);
- }
- private static void Callback(IAsyncResult ar)
- {
- EndPoint from = new IPEndPoint(IPAddress.Any, 0);
- var count = _listener.EndReceiveFrom(ar, ref from);
- var buf = (byte[])ar.AsyncState;
- StartHandleRequest();
- var domain = ExtractDomainName(buf, count);
- var target = MatchServer(domain);
- _consoleOutout.Add($"{DateTime.Now:yyyyMMdd HH:mm:ss} {from} [{target}]\t{domain}");
- var dnsResponse = GetDnsResponse(buf, count, target);
- if (dnsResponse != null) _listener.SendTo(dnsResponse, from);
- }
- protected static string ExtractDomainName(byte[] buf, int count)
- {
- var lst = new List<byte[]>();
- var ptr = 12;
- while (buf[ptr] != 0)
- {
- ptr += buf[ptr] + 1;
- }
- var bufDomain = new byte[ptr - 12];
- Array.Copy(buf, 12, bufDomain, 0, bufDomain.Length);
- //dot fill
- ptr = 0;
- while (ptr < bufDomain.Length)
- {
- var b = bufDomain[ptr];
- bufDomain[ptr] = (byte)'.';
- ptr += b + 1;
- }
- return Encoding.ASCII.GetString(bufDomain, 1, bufDomain.Length - 1);
- }
- protected static byte[] GetDnsResponse(byte[] buf, int count, string host, int port = 53)
- {
- using var to = new UdpClient();
- to.Connect(host, 53);
- to.Send(buf, count);
- //Handle Upstream TimeOut
- var asyncResult = to.BeginReceive(null, null);
- asyncResult.AsyncWaitHandle.WaitOne(2000);
- if (asyncResult.IsCompleted)
- {
- IPEndPoint remoteEP = null;
- byte[] receivedData = to.EndReceive(asyncResult, ref remoteEP);
- return receivedData;
- }
- return null;
- }
- protected static string MatchServer(string domain)
- {
- var lower = domain.ToLower();
- if (lower.EndsWith(".cn")) return _cnDns;
- var parts = lower.Split('.').Reverse().ToArray();
- for (int i = parts.Length - 1; i >= 0; i--)
- {
- var d = string.Join(".", parts.Take(i + 1).Reverse());
- if (_chinaList.TryGetValue(d, out var tar)) return _chinaListDns[tar];
- }
- return _defaultDns;
- }
- protected static void LoadListFile(params string[] paths)
- {
- var lines = paths.SelectMany(File.ReadAllLines);
- var dic = new Dictionary<string, int>();
- var tar = new List<string>();
- foreach (var line in lines)
- {
- var p = line.Trim();
- if (p.StartsWith("#")) continue;
- var parts = p.Split('/');
- if (parts.Length != 3 && parts[0] != "server=") continue;
- var domain = parts[1];
- var dns = parts[2];
- var dnsIndex = tar.IndexOf(dns);
- if (dnsIndex == -1)
- {
- tar.Add(dns);
- dnsIndex = tar.Count - 1;
- }
- dic[domain] = dnsIndex;
- }
- _chinaListDns = tar.ToArray();
- _chinaList = new ReadOnlyDictionary<string, int>(dic);
- }
- }
- }
|