## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Resolve Autonomous Systems (AS). """ from __future__ import absolute_import import socket, errno from scapy.config import conf from scapy.compat import * class AS_resolver: server = None options = "-k" def __init__(self, server=None, port=43, options=None): if server is not None: self.server = server self.port = port if options is not None: self.options = options def _start(self): self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.s.connect((self.server,self.port)) if self.options: self.s.send(self.options.encode("utf8")+b"\n") self.s.recv(8192) def _stop(self): self.s.close() def _parse_whois(self, txt): asn,desc = None,b"" for l in txt.splitlines(): if not asn and l.startswith(b"origin:"): asn = plain_str(l[7:].strip()) if l.startswith(b"descr:"): if desc: desc += r"\n" desc += l[6:].strip() if asn is not None and desc: break return asn, plain_str(desc.strip()) def _resolve_one(self, ip): self.s.send(("%s\n" % ip).encode("utf8")) x = b"" while not (b"%" in x or b"source" in x): x += self.s.recv(8192) asn, desc = self._parse_whois(x) return ip,asn,desc def resolve(self, *ips): self._start() ret = [] for ip in ips: ip,asn,desc = self._resolve_one(ip) if asn is not None: ret.append((ip,asn,desc)) self._stop() return ret class AS_resolver_riswhois(AS_resolver): server = "riswhois.ripe.net" options = "-k -M -1" class AS_resolver_radb(AS_resolver): server = "whois.ra.net" options = "-k -M" class AS_resolver_cymru(AS_resolver): server = "whois.cymru.com" options = None def resolve(self, *ips): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((self.server,self.port)) s.send(b"begin\r\n"+b"\r\n".join(ip.encode("utf8") for ip in ips)+b"\r\nend\r\n") r = b"" while True: l = s.recv(8192) if l == b"": break r += l s.close() return self.parse(r) def parse(self, data): """Parse bulk cymru data""" ASNlist = [] for l in data.splitlines()[1:]: l = plain_str(l) if "|" not in l: continue asn, ip, desc = [elt.strip() for elt in l.split('|')] if asn == "NA": continue asn = "AS%s" % asn ASNlist.append((ip, asn, desc)) return ASNlist class AS_resolver_multi(AS_resolver): resolvers_list = ( AS_resolver_riswhois(),AS_resolver_radb(),AS_resolver_cymru() ) def __init__(self, *reslist): if reslist: self.resolvers_list = reslist def resolve(self, *ips): todo = ips ret = [] for ASres in self.resolvers_list: try: res = ASres.resolve(*todo) except socket.error as e: if e[0] in [errno.ECONNREFUSED, errno.ETIMEDOUT, errno.ECONNRESET]: continue resolved = [ ip for ip,asn,desc in res ] todo = [ ip for ip in todo if ip not in resolved ] ret += res if len(todo) == 0: break if len(ips) != len(ret): raise RuntimeError("Could not contact whois providers") return ret conf.AS_resolver = AS_resolver_multi()