blob: fa33a6f45139ec5bee28726fc08f09225557c1c4 [file] [log] [blame]
## This file is part of Scapy
## See http://www.secdev.org/projects/scapy for more informations
## Copyright (C) Philippe Biondi <phil@secdev.org>
## 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()