1 /** 2 * Client for DNS blacklist services. 3 * 4 * License: 5 * This Source Code Form is subject to the terms of 6 * the Mozilla Public License, v. 2.0. If a copy of 7 * the MPL was not distributed with this file, You 8 * can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * Authors: 11 * Vladimir Panteleev <ae@cy.md> 12 */ 13 14 15 module ae.net.dns.dnsbl; 16 17 import std.socket; 18 import std.string; 19 import ae.net.asockets; 20 21 /// Resolve a hostname to an IPv4 dotted quad. 22 string getIP(string hostname) 23 { 24 try 25 return (new InternetAddress(hostname, 0)).toAddrString; 26 catch (Exception o) 27 return null; 28 } 29 30 /// Look up an IP address against a specific DNS blacklist. 31 /// Returns: the numeric code (generally indicating a 32 /// blacklist-specific list reason). 33 int lookupAgainst(string ip, string db) 34 { 35 string[] sections = split(ip, "."); 36 assert(sections.length == 4); 37 string addr = sections[3] ~ "." ~ sections[2] ~ "." ~ sections[1] ~ "." ~ sections[0] ~ "." ~ db; 38 InternetHost ih = new InternetHost; 39 if (ih.getHostByName(addr)) 40 return ih.addrList[0] & 0xFF; 41 else 42 return 0; 43 } 44 45 /// Look up an IP address against DroneBL. 46 /// Returns: a string describing the reason this IP is listed, 47 /// or `null` if the IP is not listed. 48 string lookupDroneBL(string ip) 49 { 50 switch (lookupAgainst(ip, "dnsbl.dronebl.org")) 51 { 52 case 0: return null; 53 case 2: return "Sample"; 54 case 3: return "IRC Drone"; 55 case 5: return "Bottler"; 56 case 6: return "Unknown spambot or drone"; 57 case 7: return "DDOS Drone"; 58 case 8: return "SOCKS Proxy"; 59 case 9: return "HTTP Proxy"; 60 case 10: return "ProxyChain"; 61 case 13: return "Brute force attackers"; 62 case 14: return "Open Wingate Proxy"; 63 case 15: return "Compromised router / gateway"; 64 default: return "Unknown"; 65 } 66 } 67 68 /// Look up an IP address against the EFnet RBL. 69 /// Returns: a string describing the reason this IP is listed, 70 /// or `null` if the IP is not listed. 71 string lookupEfnetRBL(string ip) 72 { 73 switch (lookupAgainst(ip, "rbl.efnetrbl.org")) 74 { 75 case 0: return null; 76 case 1: return "Open Proxy"; 77 case 2: return "spamtrap666"; 78 case 3: return "spamtrap50"; 79 case 4: return "TOR"; 80 case 5: return "Drones / Flooding"; 81 default: return "Unknown"; 82 } 83 } 84 85 /// Look up an IP address against the sectoor.de Tor exit node DNSBL. 86 /// Returns: a string describing the reason this IP is listed, 87 /// or `null` if the IP is not listed. 88 string lookupSectoorTorDNSBL(string ip) 89 { 90 switch (lookupAgainst(ip, "exitnodes.tor.dnsbl.sectoor.de")) 91 { 92 case 0: return null; 93 case 1: return "Tor exit node"; 94 default: return "Unknown"; 95 } 96 } 97 98 /// Look up an IP address against the dan.me's Tor exit node DNSBL. 99 /// Returns: a string describing the reason this IP is listed, 100 /// or `null` if the IP is not listed. 101 string lookupDanTorDNSBL(string ip) 102 { 103 switch (lookupAgainst(ip, "torexit.dan.me.uk")) 104 { 105 case 0: return null; 106 case 100: return "Tor exit node"; 107 default : return "Unknown"; 108 } 109 } 110 111 /// Look up an IP address in all implemented DNS blacklists. 112 /// Returns: null, or an array with three elements: 113 /// 0. a string describing the reason this IP is listed 114 /// 1. the name of the DNS blacklist service 115 /// 2. an URL with more information about the listing. 116 string[] blacklistCheck(string hostname) 117 { 118 string ip = getIP(hostname); 119 120 if (!ip) 121 throw new Exception("Can't resolve hostname to IPv4 address: " ~ hostname); 122 123 string result; 124 125 result = lookupDroneBL(ip); 126 if (result) return [result, "DroneBL" , "http://dronebl.org/lookup?ip="~ip]; 127 128 result = lookupEfnetRBL(ip); 129 if (result) return [result, "EFnet RBL", "http://rbl.efnetrbl.org/?i=" ~ip]; 130 131 result = lookupSectoorTorDNSBL(ip); 132 if (result) return [result, "Sectoor Tor exit node", "http://www.sectoor.de/tor.php"]; 133 134 result = lookupDanTorDNSBL(ip); 135 if (result) return [result, "Dan Tor exit node", "https://www.dan.me.uk/dnsbl"]; 136 137 return null; 138 }