Home | History | Annotate | Download | only in scapy
      1 ## This file is part of Scapy
      2 ## See http://www.secdev.org/projects/scapy for more informations
      3 ## Copyright (C) Philippe Biondi <phil (at] secdev.org>
      4 ## This program is published under a GPLv2 license
      5 
      6 """
      7 Resolve Autonomous Systems (AS).
      8 """
      9 
     10 
     11 from __future__ import absolute_import
     12 import socket, errno
     13 from scapy.config import conf
     14 from scapy.compat import *
     15 
     16 class AS_resolver:
     17     server = None
     18     options = "-k" 
     19     def __init__(self, server=None, port=43, options=None):
     20         if server is not None:
     21             self.server = server
     22         self.port = port
     23         if options is not None:
     24             self.options = options
     25         
     26     def _start(self):
     27         self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     28         self.s.connect((self.server,self.port))
     29         if self.options:
     30             self.s.send(self.options.encode("utf8")+b"\n")
     31             self.s.recv(8192)
     32     def _stop(self):
     33         self.s.close()
     34         
     35     def _parse_whois(self, txt):
     36         asn,desc = None,b""
     37         for l in txt.splitlines():
     38             if not asn and l.startswith(b"origin:"):
     39                 asn = plain_str(l[7:].strip())
     40             if l.startswith(b"descr:"):
     41                 if desc:
     42                     desc += r"\n"
     43                 desc += l[6:].strip()
     44             if asn is not None and desc:
     45                 break
     46         return asn, plain_str(desc.strip())
     47 
     48     def _resolve_one(self, ip):
     49         self.s.send(("%s\n" % ip).encode("utf8"))
     50         x = b""
     51         while not (b"%" in x  or b"source" in x):
     52             x += self.s.recv(8192)
     53         asn, desc = self._parse_whois(x)
     54         return ip,asn,desc
     55     def resolve(self, *ips):
     56         self._start()
     57         ret = []
     58         for ip in ips:
     59             ip,asn,desc = self._resolve_one(ip)
     60             if asn is not None:
     61                 ret.append((ip,asn,desc))
     62         self._stop()
     63         return ret
     64 
     65 class AS_resolver_riswhois(AS_resolver):
     66     server = "riswhois.ripe.net"
     67     options = "-k -M -1"
     68 
     69 
     70 class AS_resolver_radb(AS_resolver):
     71     server = "whois.ra.net"
     72     options = "-k -M"
     73     
     74 
     75 class AS_resolver_cymru(AS_resolver):
     76     server = "whois.cymru.com"
     77     options = None
     78     def resolve(self, *ips):
     79         s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     80         s.connect((self.server,self.port))
     81         s.send(b"begin\r\n"+b"\r\n".join(ip.encode("utf8") for ip in ips)+b"\r\nend\r\n")
     82         r = b""
     83         while True:
     84             l = s.recv(8192)
     85             if l == b"":
     86                 break
     87             r += l
     88         s.close()
     89 
     90         return self.parse(r)
     91 
     92     def parse(self, data):
     93         """Parse bulk cymru data"""
     94 
     95         ASNlist = []
     96         for l in data.splitlines()[1:]:
     97             l = plain_str(l)
     98             if "|" not in l:
     99                 continue
    100             asn, ip, desc = [elt.strip() for elt in l.split('|')]
    101             if asn == "NA":
    102                 continue
    103             asn = "AS%s" % asn
    104             ASNlist.append((ip, asn, desc))
    105         return ASNlist
    106 
    107 class AS_resolver_multi(AS_resolver):
    108     resolvers_list = ( AS_resolver_riswhois(),AS_resolver_radb(),AS_resolver_cymru() )
    109     def __init__(self, *reslist):
    110         if reslist:
    111             self.resolvers_list = reslist
    112     def resolve(self, *ips):
    113         todo = ips
    114         ret = []
    115         for ASres in self.resolvers_list:
    116             try:
    117                 res = ASres.resolve(*todo)
    118             except socket.error as e:
    119                 if e[0] in [errno.ECONNREFUSED, errno.ETIMEDOUT, errno.ECONNRESET]:
    120                     continue
    121             resolved = [ ip for ip,asn,desc in res ]
    122             todo = [ ip for ip in todo if ip not in resolved ]
    123             ret += res
    124             if len(todo) == 0:
    125                 break
    126         if len(ips) != len(ret):
    127             raise RuntimeError("Could not contact whois providers")
    128         return ret
    129 
    130 
    131 conf.AS_resolver = AS_resolver_multi()
    132