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