]>
git.ipfire.org Git - ipfire.org.git/blob - src/backend/geoip.py
ba64760c595a93dee14921056fae59d660f768f0
9 import tornado
.platform
.caresresolver
11 from . import countries
13 from .decorators
import *
14 from .misc
import Object
16 # These lists are used to block access to the webapp
24 "all.de.bl.blocklist.de",
25 "all.spamblock.unit.liu.se",
26 "b.barracudacentral.org",
28 #"bl.emailbasura.org",
29 "bl.spamcannibal.org",
31 "blackholes.five-ten-sg.com",
32 #"blackholes.mail-abuse.org",
33 "blacklist.sci.kun.nl",
38 #"cbl.anti-spam.org.cn",
39 #"cblless.anti-spam.org.cn",
40 #"cblplus.anti-spam.org.cn",
41 #"cdl.anti-spam.org.cn",
42 #"combined.njabl.org",
43 "combined.rbl.msrbl.net",
46 #"dialups.mail-abuse.org",
47 "dnsbl-1.uceprotect.net",
48 "dnsbl-2.uceprotect.net",
49 "dnsbl-3.uceprotect.net",
51 "dnsbl.cyberlogic.net",
57 "dob.sibl.support-intelligence.net",
59 "dsn.rfc-ignorant.org",
61 #"dul.blackhole.cantv.net",
62 "dul.dnsbl.sorbs.net",
65 "dynablock.sorbs.net",
68 "forbidden.icm.edu.pl",
69 "http.dnsbl.sorbs.net",
71 "images.rbl.msrbl.net",
72 "ips.backscatterer.org",
73 "ix.dnsbl.manitu.net",
76 "misc.dnsbl.sorbs.net",
78 "netblock.pedantic.org",
83 "phishing.rbl.msrbl.net",
85 "query.senderbase.org",
86 #"rbl-plus.mail-abuse.org",
88 "rbl.interserver.net",
90 "rbl.suresupport.com",
92 "relays.bl.kundenserver.de",
93 #"relays.mail-abuse.org",
95 "residential.block.transip.nl",
96 #"rot.blackhole.cantv.net",
99 "smtp.dnsbl.sorbs.net",
100 "socks.dnsbl.sorbs.net",
102 "spam.dnsbl.sorbs.net",
103 "spam.rbl.msrbl.net",
105 "spamguard.leadmon.net",
110 "ubl.unsubscore.com",
115 "virus.rbl.msrbl.net",
116 "web.dnsbl.sorbs.net",
120 "zombie.dnsbl.sorbs.net",
123 class Resolver(tornado
.platform
.caresresolver
.CaresResolver
):
124 def initialize(self
, **kwargs
):
128 self
.channel
= pycares
.Channel(sock_state_cb
=self
._sock
_state
_cb
, **kwargs
)
130 @tornado.gen
.coroutine
131 def query(self
, name
, type=pycares
.QUERY_TYPE_A
):
132 # Create a new Future
133 fut
= tornado
.gen
.Future()
136 self
.channel
.query(name
, type, lambda result
, error
: fut
.set_result((result
, error
)))
138 # Wait for the response
139 result
, error
= yield fut
144 if error
== pycares
.errno
.ARES_ENOTFOUND
:
147 # Ignore responses with no data
148 elif error
== pycares
.errno
.ARES_ENODATA
:
152 "C-Ares returned error %s: %s while resolving %s"
153 % (error
, pycares
.errno
.strerror(error
), name
)
163 return Resolver(tries
=2, timeout
=2, domains
=[])
165 def lookup(self
, address
):
166 return Address(self
.backend
, address
)
168 def guess_address_family(self
, addr
):
174 def get_country(self
, addr
):
175 ret
= self
.get_all(addr
)
180 def get_location(self
, addr
):
181 query
= "SELECT * FROM geoip \
182 WHERE %s BETWEEN start_ip AND end_ip LIMIT 1"
184 return self
.db
.get(query
, addr
)
186 def get_asn(self
, addr
):
187 query
= "SELECT asn FROM geoip_asn \
188 WHERE %s BETWEEN start_ip AND end_ip LIMIT 1"
190 ret
= self
.db
.get(query
, addr
)
195 def get_all(self
, addr
):
196 location
= self
.get_location(addr
)
199 location
["asn"] = self
.get_asn(addr
)
204 "A1" : "Anonymous Proxy",
205 "A2" : "Satellite Provider",
206 "AP" : "Asia/Pacific Region",
210 def get_country_name(self
, code
):
211 return countries
.get_name(code
)
213 @tornado.gen
.coroutine
214 def test_blacklist(self
, address
):
215 address
= self
.lookup(address
)
217 # Determne blacklist status
218 status
= yield address
.is_blacklisted()
220 print("Blacklist status for %s: %s" % (address
, status
))
223 class Address(Object
):
224 def init(self
, address
):
225 self
.address
= ipaddress
.ip_address(address
)
228 return "%s" % self
.address
232 if isinstance(self
.address
, ipaddress
.IPv6Address
):
233 return socket
.AF_INET6
234 elif isinstance(self
.address
, ipaddress
.IPv4Address
):
235 return socket
.AF_INET
239 def _make_blacklist_rr(self
, blacklist
):
240 if self
.family
== socket
.AF_INET6
:
241 octets
= list(self
.address
.exploded
.replace(":", ""))
242 elif self
.family
== socket
.AF_INET
:
243 octets
= str(self
.address
).split(".")
245 raise NotImplementedError("Unknown IP protocol")
251 octets
.append(blacklist
)
253 return ".".join(octets
)
255 @tornado.gen
.coroutine
256 def _resolve_blacklist(self
, blacklist
):
259 # Get resource record name
260 rr
= self
._make
_blacklist
_rr
(blacklist
)
262 # Get query type from IP protocol version
263 if self
.family
== socket
.AF_INET6
:
264 type = pycares
.QUERY_TYPE_AAAA
265 elif self
.family
== socket
.AF_INET
:
266 type = pycares
.QUERY_TYPE_A
268 raise NotImplementedError("Unknown IP protocol")
272 res
= yield self
.backend
.geoip
.resolver
.query(rr
, type=type)
276 return return_code
, "%s" % e
280 logging
.debug("%s is not blacklisted on %s" % (self
, blacklist
))
281 return return_code
, None
283 # Extract return code from DNS response
285 return_code
= row
.host
288 # If the IP address is on a blacklist, we will try to fetch the TXT record
289 reason
= yield self
.backend
.geoip
.resolver
.query(rr
, type=pycares
.QUERY_TYPE_TXT
)
292 logging
.debug("%s is blacklisted on %s: %s" % (self
, blacklist
, reason
or "N/A"))
294 # Take the first reason
297 return return_code
, i
.text
299 # Blocked, but no reason
300 return return_code
, None
302 @tornado.gen
.coroutine
303 def get_blacklists(self
):
304 blacklists
= yield { bl
: self
._resolve
_blacklist
(bl
) for bl
in BLACKLISTS
}
308 @tornado.gen
.coroutine
309 def is_blacklisted(self
):
310 logging
.debug("Checking if %s is blacklisted..." % self
)
313 blacklists
= yield { bl
: self
._resolve
_blacklist
(bl
) for bl
in BLOCKLISTS
}
315 # If we are blacklisted on one list, this one is screwed
316 for bl
in blacklists
:
317 code
, message
= blacklists
[bl
]
319 logging
.debug("Response from %s is: %s (%s)" % (bl
, code
, message
))
321 # Exclude matches on SBLCSS
322 if bl
== "sbl.spamhaus.org" and code
== "127.0.0.3":
325 # Consider the host blocked for any non-zero return code