// build a tree structure similar to catalogue for the naughtylist (one could be a subset of the other actually) // this is INCREDIBLY slow though... maybe need a conversion process that runs periodically and creates a nicer format for loading quickly. public static NaughtyList FromFile(string path) { NaughtyList naughtyList = new NaughtyList(); string[] entries = File.ReadAllLines(path); for (int i = 0; i < entries.Length; i++) { string[] parts = entries[i].Split('.', StringSplitOptions.RemoveEmptyEntries); Array.Reverse(parts); NaughtyList pointer = naughtyList; foreach (string part in parts) { NaughtyList child = pointer.ChildMatch(part); if (child == null) { pointer = pointer.AddChild(part); } else { pointer = child; } } } return(naughtyList); }
public NaughtyList AddChild(string label) { if (Children == null) { Children = new List <NaughtyList>(); } NaughtyList child = new NaughtyList(); child.Label = label; Children.Add(child); return(child); }
public bool Match(string host) { string[] parts = host.Split('.', System.StringSplitOptions.RemoveEmptyEntries); Array.Reverse(parts); NaughtyList pointer = null; for (int i = 0; i < parts.Length; i++) { bool match = false; foreach (NaughtyList child in pointer.Children) { if (string.Compare(parts[i], child.Label, true) == 0) { pointer = child; match = true; } } // we didn't get a match on this part so we could be on the host name where a domain is blocked // in which case we need to fall back to the domain level if (!match) { // there was no match at the root level, so no match if (pointer == null) { return(false); } else { // when pointer is pointing to something if (pointer.Children.Count == 0) { return(true); } else { return(false); } } } } return(false); }
static void Main(string[] args) { // ok, in the spirit of this project I grant that this parsing approach is not the fastest but it's one time to load the file(s) // and it provides robustness to the process - I will optimise the in-memory representation of the master zone records so that // this can be as fast as possible (maybe not quite faster than light but hopefully fast enough) dsl.MasterFileParser parser = new dsl.MasterFileParser(); parser.Parse("example.zone"); Catalogue catalogue = Catalogue.FromEntryList(parser.Entries); Console.WriteLine("read master file successfully"); // Message message = Message.FromFile("badanswer.txt"); // temporary, i want to do some analysis of the block list to see how evenly distributed the entries are // Dictionary<char, Dictionary<char, int>> frequencies = new Dictionary<char, Dictionary<char, int>>(); // StreamReader reader = new StreamReader("dnscrypt-proxy.blacklist.txt"); // string line = string.Empty; // while ((line = reader.ReadLine()) != null) // { // if (frequencies.ContainsKey(line[0]) == false) // { // frequencies.Add(line[0], new Dictionary<char, int>()); // } // if (frequencies[line[0]].ContainsKey(line[1])) // { // frequencies[line[0]][line[1]]++; // } // else // { // frequencies[line[0]].Add(line[1], 1); // } // } // foreach (KeyValuePair<char, Dictionary<char, int>> kvp in frequencies) // { // foreach (KeyValuePair<char, int> innerKvp in kvp.Value) // { // Console.WriteLine($"{kvp.Key} => {innerKvp.Key} => {innerKvp.Value}"); // } // } // return; // ok, so loading into a rough tree separating the first two characters as the first and second level branches isn't very balanced, but it's possibly fast enough // can look at optimising this later with a balanced tree for better speed, although to be fair this processes all 280,000 rows pretty quickly anyway // TODO: create a tree structure to hold the domains in the block list for a quicker decision on whether to block var exitEvent = new ManualResetEvent(false); Console.CancelKeyPress += (sender, eventArgs) => { eventArgs.Cancel = true; exitEvent.Set(); }; NaughtyList naughtyList = NaughtyList.FromFile("dnscrypt-proxy.blacklist.txt"); // TODO: configure secondary forwarder for greater resilience, and secondary server address if this is a multi-homed server Console.WriteLine(); Server server = new Server(); server.WithConfig(ServerConfig.FromFile(Environment.CurrentDirectory + "\\windows.json")).WithCatalogue(catalogue).WithNaughtyList(naughtyList).Start(); // TODO: make this a command line arg with default FileSystemWatcher watcher = new FileSystemWatcher(Environment.CurrentDirectory, "*.json"); watcher.Changed += (o, e) => { // wait a bit in case of race condition, it doesn't matter if it takes half a second to reload configuration Thread.Sleep(500); Console.WriteLine("Configuration changed, restarting server"); ServerConfig config = ServerConfig.FromFile(Environment.CurrentDirectory + "\\windows.json"); server.WithConfig(config).Restart(); }; watcher.EnableRaisingEvents = true; Console.WriteLine("Hello World!"); exitEvent.WaitOne(); server.Stop(); }
public Server WithNaughtyList(NaughtyList naughtyList) { this.naughtyList = naughtyList; return(this); }