Program.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Net;
  6. using System.Net.Sockets;
  7. using System.Runtime.InteropServices;
  8. using System.Text;
  9. namespace DnsForwarder
  10. {
  11. internal class Program
  12. {
  13. private static string DefaultServer;
  14. private static string ChinaServer;
  15. private static Dictionary<string, string> ChinaList;
  16. private static void Main(string[] args)
  17. {
  18. if (args.Length != 3)
  19. {
  20. Console.WriteLine("<default dns server ip> <china dns server ip> <path to dnsmasq-china-list file>");
  21. Environment.Exit(-1);
  22. return;
  23. }
  24. Console.WriteLine("Starting...");
  25. Console.WriteLine($"Default Server:{DefaultServer = args[0]}");
  26. Console.WriteLine($"China DNS Server:{ChinaServer = args[1]}");
  27. Console.WriteLine($"dnsmasq-china-list file:{args[2]}");
  28. Console.WriteLine("Loading list file...");
  29. ChinaList = LoadListFile(args[2]).ToDictionary(p => p[0], p => p[1]);
  30. Console.WriteLine("OK. Listing...");
  31. var listen = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
  32. listen.Bind(new IPEndPoint(IPAddress.Any, 53));
  33. while (true)
  34. {
  35. EndPoint inEp = new IPEndPoint(IPAddress.Any, 0);
  36. var buf = new byte[1500];
  37. var count = listen.ReceiveFrom(buf, 0, buf.Length, SocketFlags.None, ref inEp);
  38. var domain = ExtractDomainName(buf, count);
  39. var target = MatchServer(domain);
  40. Console.WriteLine($"{DateTime.Now:yyyyMMdd HH:mm:ss} {inEp} [{target}]\t{domain}");
  41. listen.SendTo(GetDnsResponse(buf, count, target), inEp);
  42. }
  43. }
  44. private static string ExtractDomainName(byte[] buf, int count)
  45. {
  46. var lst = new List<byte[]>();
  47. var ptr = 12;
  48. while (buf[ptr] != 0)
  49. {
  50. ptr += buf[ptr] + 1;
  51. }
  52. var bufDomain = new byte[ptr - 12];
  53. Array.Copy(buf, 12, bufDomain, 0, bufDomain.Length);
  54. //dot fill
  55. ptr = 0;
  56. while (ptr < bufDomain.Length)
  57. {
  58. var b = bufDomain[ptr];
  59. bufDomain[ptr] = (byte)'.';
  60. ptr += b + 1;
  61. }
  62. return Encoding.ASCII.GetString(bufDomain, 1, bufDomain.Length - 1);
  63. }
  64. private static byte[] GetDnsResponse(byte[] buf, int count, string host, int port = 53)
  65. {
  66. using var to = new UdpClient();
  67. to.Connect(host, 53);
  68. to.Send(buf, count);
  69. IPEndPoint outEp = null;
  70. return to.Receive(ref outEp);
  71. }
  72. private static string MatchServer(string domain)
  73. {
  74. var lower = domain.ToLower();
  75. if (lower.EndsWith(".cn")) return ChinaServer;
  76. var parts = lower.Split('.').Reverse().ToArray();
  77. for (int i = parts.Length - 1; i >= 0; i--)
  78. {
  79. var d = string.Join(".", parts.Take(i + 1).Reverse());
  80. if (ChinaList.TryGetValue(d, out var tar)) return tar;
  81. }
  82. return DefaultServer;
  83. }
  84. private static string[][] LoadListFile(string path)
  85. {
  86. var lines = File.ReadAllLines(path);
  87. var items = lines.Select(p =>
  88. {
  89. if (p.StartsWith("#")) return null;
  90. var parts = p.Split('/');
  91. return new[] { parts[1], parts[2] };
  92. }).Where(p => p != null).ToArray();
  93. return items;
  94. }
  95. }
  96. }