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 DroneBL.
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 in all implemented DNS blacklists.
86 /// Returns: null, or an array with three elements:
87 /// 0. a string describing the reason this IP is listed
88 /// 1. the name of the DNS blacklist service
89 /// 2. an URL with more information about the listing.
90 string[] blacklistCheck(string hostname)
91 {
92 	string ip = getIP(hostname);
93 
94 	if (!ip)
95 		throw new Exception("Can't resolve hostname to IPv4 address: " ~ hostname);
96 
97 	string result;
98 
99 	result = lookupDroneBL(ip);
100 	if (result) return [result, "DroneBL"  , "http://dronebl.org/lookup?ip="~ip];
101 
102 	result = lookupEfnetRBL(ip);
103 	if (result) return [result, "EFnet RBL", "http://rbl.efnetrbl.org/?i="  ~ip];
104 
105 	return null;
106 }