11ad4bbf39716a7c25161cb118f02344291e0c102Phil## This file is part of Scapy 21ad4bbf39716a7c25161cb118f02344291e0c102Phil## See http://www.secdev.org/projects/scapy for more informations 31ad4bbf39716a7c25161cb118f02344291e0c102Phil## Copyright (C) Philippe Biondi <phil@secdev.org> 41ad4bbf39716a7c25161cb118f02344291e0c102Phil## This program is published under a GPLv2 license 51ad4bbf39716a7c25161cb118f02344291e0c102Phil 60ce149b41a10223c75f33a135d0a7ddc6bd2e022Dirk Loss""" 70ce149b41a10223c75f33a135d0a7ddc6bd2e022Dirk LossCommon customizations for all Unix-like operating systems other than Linux 80ce149b41a10223c75f33a135d0a7ddc6bd2e022Dirk Loss""" 91ad4bbf39716a7c25161cb118f02344291e0c102Phil 101ad4bbf39716a7c25161cb118f02344291e0c102Philimport sys,os,struct,socket,time 111ad4bbf39716a7c25161cb118f02344291e0c102Philfrom fcntl import ioctl 126057906368d55634d11e1d19a5cca1f127595b11Robin Jarryimport socket 136057906368d55634d11e1d19a5cca1f127595b11Robin Jarry 146057906368d55634d11e1d19a5cca1f127595b11Robin Jarryfrom scapy.error import warning, log_interactive 1510ee9eb026c24397a8f2fc2127bb21bf94da71d7Philimport scapy.config 161ad4bbf39716a7c25161cb118f02344291e0c102Philimport scapy.utils 172066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadonfrom scapy.utils6 import in6_getscope, construct_source_candidate_set 182066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadonfrom scapy.utils6 import in6_isvalid, in6_ismlladdr, in6_ismnladdr 19431b04a95da67282a59bdf0a1898e106b18814d0gpotterfrom scapy.consts import FREEBSD, NETBSD, OPENBSD, SOLARIS, LOOPBACK_NAME 2035f97efc53839f6366918c251dba5df2ac553c8dGuillaume Valadonfrom scapy.arch import get_if_addr 216d6dba222509bec6a01b5f7414685b7d59bb7fc9Guillaume Valadonfrom scapy.config import conf 221ad4bbf39716a7c25161cb118f02344291e0c102Phil 231ad4bbf39716a7c25161cb118f02344291e0c102Phil 241ad4bbf39716a7c25161cb118f02344291e0c102Phil################## 251ad4bbf39716a7c25161cb118f02344291e0c102Phil## Routes stuff ## 261ad4bbf39716a7c25161cb118f02344291e0c102Phil################## 271ad4bbf39716a7c25161cb118f02344291e0c102Phil 2802ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadondef _guess_iface_name(netif): 2902ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon """ 3002ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon We attempt to guess the name of interfaces that are truncated from the 3102ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon output of ifconfig -l. 3202ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon If there is only one possible candidate matching the interface name then we 3302ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon return it. 3402ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon If there are none or more, then we return None. 3502ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon """ 3602ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon with os.popen('%s -l' % conf.prog.ifconfig) as fdesc: 3702ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon ifaces = fdesc.readline().strip().split(' ') 3802ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon matches = [iface for iface in ifaces if iface.startswith(netif)] 3902ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon if len(matches) == 1: 4002ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon return matches[0] 4102ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon return None 4202ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon 431ad4bbf39716a7c25161cb118f02344291e0c102Phil 441ad4bbf39716a7c25161cb118f02344291e0c102Phildef read_routes(): 4535f97efc53839f6366918c251dba5df2ac553c8dGuillaume Valadon if SOLARIS: 461ad4bbf39716a7c25161cb118f02344291e0c102Phil f=os.popen("netstat -rvn") # -f inet 4735f97efc53839f6366918c251dba5df2ac553c8dGuillaume Valadon elif FREEBSD: 481ad4bbf39716a7c25161cb118f02344291e0c102Phil f=os.popen("netstat -rnW") # -W to handle long interface names 491ad4bbf39716a7c25161cb118f02344291e0c102Phil else: 501ad4bbf39716a7c25161cb118f02344291e0c102Phil f=os.popen("netstat -rn") # -f inet 511ad4bbf39716a7c25161cb118f02344291e0c102Phil ok = 0 521ad4bbf39716a7c25161cb118f02344291e0c102Phil mtu_present = False 53963c58e7bf45216aa225f56b721aa9261fd9fe5aPhil prio_present = False 541ad4bbf39716a7c25161cb118f02344291e0c102Phil routes = [] 5535125c23da6e8137a570583e754da9b918c8a63bPhil pending_if = [] 561ad4bbf39716a7c25161cb118f02344291e0c102Phil for l in f.readlines(): 571ad4bbf39716a7c25161cb118f02344291e0c102Phil if not l: 581ad4bbf39716a7c25161cb118f02344291e0c102Phil break 591ad4bbf39716a7c25161cb118f02344291e0c102Phil l = l.strip() 601ad4bbf39716a7c25161cb118f02344291e0c102Phil if l.find("----") >= 0: # a separation line 611ad4bbf39716a7c25161cb118f02344291e0c102Phil continue 62963c58e7bf45216aa225f56b721aa9261fd9fe5aPhil if not ok: 63963c58e7bf45216aa225f56b721aa9261fd9fe5aPhil if l.find("Destination") >= 0: 64963c58e7bf45216aa225f56b721aa9261fd9fe5aPhil ok = 1 65e787b56616650d08fec1a9fa702d7a09943c91fePierre LALET mtu_present = "Mtu" in l 66e787b56616650d08fec1a9fa702d7a09943c91fePierre LALET prio_present = "Prio" in l 67e787b56616650d08fec1a9fa702d7a09943c91fePierre LALET refs_present = "Refs" in l 681ad4bbf39716a7c25161cb118f02344291e0c102Phil continue 691ad4bbf39716a7c25161cb118f02344291e0c102Phil if not l: 701ad4bbf39716a7c25161cb118f02344291e0c102Phil break 7135f97efc53839f6366918c251dba5df2ac553c8dGuillaume Valadon if SOLARIS: 7235125c23da6e8137a570583e754da9b918c8a63bPhil lspl = l.split() 7335125c23da6e8137a570583e754da9b918c8a63bPhil if len(lspl) == 10: 7435125c23da6e8137a570583e754da9b918c8a63bPhil dest,mask,gw,netif,mxfrg,rtt,ref,flg = lspl[:8] 7535125c23da6e8137a570583e754da9b918c8a63bPhil else: # missing interface 7635125c23da6e8137a570583e754da9b918c8a63bPhil dest,mask,gw,mxfrg,rtt,ref,flg = lspl[:7] 7735125c23da6e8137a570583e754da9b918c8a63bPhil netif=None 781ad4bbf39716a7c25161cb118f02344291e0c102Phil else: 79963c58e7bf45216aa225f56b721aa9261fd9fe5aPhil rt = l.split() 80963c58e7bf45216aa225f56b721aa9261fd9fe5aPhil dest,gw,flg = rt[:3] 81e787b56616650d08fec1a9fa702d7a09943c91fePierre LALET netif = rt[4 + mtu_present + prio_present + refs_present] 821ad4bbf39716a7c25161cb118f02344291e0c102Phil if flg.find("Lc") >= 0: 830d92fc9fbb58df9cc4bbeb007bf65020fe1aa092Victor Pfautz continue 841ad4bbf39716a7c25161cb118f02344291e0c102Phil if dest == "default": 85291400c1b6f65363e33cc982aaf0d43d31cc424egpotter dest = 0 86291400c1b6f65363e33cc982aaf0d43d31cc424egpotter netmask = 0 871ad4bbf39716a7c25161cb118f02344291e0c102Phil else: 8835f97efc53839f6366918c251dba5df2ac553c8dGuillaume Valadon if SOLARIS: 891ad4bbf39716a7c25161cb118f02344291e0c102Phil netmask = scapy.utils.atol(mask) 901ad4bbf39716a7c25161cb118f02344291e0c102Phil elif "/" in dest: 911ad4bbf39716a7c25161cb118f02344291e0c102Phil dest,netmask = dest.split("/") 921ad4bbf39716a7c25161cb118f02344291e0c102Phil netmask = scapy.utils.itom(int(netmask)) 931ad4bbf39716a7c25161cb118f02344291e0c102Phil else: 941ad4bbf39716a7c25161cb118f02344291e0c102Phil netmask = scapy.utils.itom((dest.count(".") + 1) * 8) 951ad4bbf39716a7c25161cb118f02344291e0c102Phil dest += ".0"*(3-dest.count(".")) 961ad4bbf39716a7c25161cb118f02344291e0c102Phil dest = scapy.utils.atol(dest) 973fc82d65918606609ab12a449982e37891e1ade3gpotter # XXX: TODO: add metrics for unix.py (use -e option on netstat) 983fc82d65918606609ab12a449982e37891e1ade3gpotter metric = 1 991ad4bbf39716a7c25161cb118f02344291e0c102Phil if not "G" in flg: 1001ad4bbf39716a7c25161cb118f02344291e0c102Phil gw = '0.0.0.0' 10135125c23da6e8137a570583e754da9b918c8a63bPhil if netif is not None: 10202ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon try: 10335f97efc53839f6366918c251dba5df2ac553c8dGuillaume Valadon ifaddr = get_if_addr(netif) 1043fc82d65918606609ab12a449982e37891e1ade3gpotter routes.append((dest,netmask, gw, netif, ifaddr, metric)) 10502ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon except OSError as exc: 10602ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon if exc.message == 'Device not configured': 10702ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon # This means the interface name is probably truncated by 10802ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon # netstat -nr. We attempt to guess it's name and if not we 10902ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon # ignore it. 11002ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon guessed_netif = _guess_iface_name(netif) 11102ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon if guessed_netif is not None: 11235f97efc53839f6366918c251dba5df2ac553c8dGuillaume Valadon ifaddr = get_if_addr(guessed_netif) 1133fc82d65918606609ab12a449982e37891e1ade3gpotter routes.append((dest, netmask, gw, guessed_netif, ifaddr, metric)) 11402ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon else: 115edd4e843008c637bf3d1a2c8274a8429ac2a4185gpotter warning("Could not guess partial interface name: %s", netif) 11602ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon else: 11702ae08b4ad973184a167ffcfb10043dfeda1244dGuillaume Valadon raise 11835125c23da6e8137a570583e754da9b918c8a63bPhil else: 11935125c23da6e8137a570583e754da9b918c8a63bPhil pending_if.append((dest,netmask,gw)) 1201ad4bbf39716a7c25161cb118f02344291e0c102Phil f.close() 12135125c23da6e8137a570583e754da9b918c8a63bPhil 12235125c23da6e8137a570583e754da9b918c8a63bPhil # On Solaris, netstat does not provide output interfaces for some routes 12335125c23da6e8137a570583e754da9b918c8a63bPhil # We need to parse completely the routing table to route their gw and 12435125c23da6e8137a570583e754da9b918c8a63bPhil # know their output interface 12535125c23da6e8137a570583e754da9b918c8a63bPhil for dest,netmask,gw in pending_if: 12635125c23da6e8137a570583e754da9b918c8a63bPhil gw_l = scapy.utils.atol(gw) 12735125c23da6e8137a570583e754da9b918c8a63bPhil max_rtmask,gw_if,gw_if_addr, = 0,None,None 12835125c23da6e8137a570583e754da9b918c8a63bPhil for rtdst,rtmask,_,rtif,rtaddr in routes[:]: 12935125c23da6e8137a570583e754da9b918c8a63bPhil if gw_l & rtmask == rtdst: 13035125c23da6e8137a570583e754da9b918c8a63bPhil if rtmask >= max_rtmask: 13135125c23da6e8137a570583e754da9b918c8a63bPhil max_rtmask = rtmask 13235125c23da6e8137a570583e754da9b918c8a63bPhil gw_if = rtif 13335125c23da6e8137a570583e754da9b918c8a63bPhil gw_if_addr = rtaddr 1343fc82d65918606609ab12a449982e37891e1ade3gpotter # XXX: TODO add metrics 1353fc82d65918606609ab12a449982e37891e1ade3gpotter metric = 1 13635125c23da6e8137a570583e754da9b918c8a63bPhil if gw_if: 1373fc82d65918606609ab12a449982e37891e1ade3gpotter routes.append((dest,netmask, gw, gw_if, gw_if_addr, metric)) 13835125c23da6e8137a570583e754da9b918c8a63bPhil else: 139edd4e843008c637bf3d1a2c8274a8429ac2a4185gpotter warning("Did not find output interface to reach gateway %s", gw) 1400d92fc9fbb58df9cc4bbeb007bf65020fe1aa092Victor Pfautz 1411ad4bbf39716a7c25161cb118f02344291e0c102Phil return routes 1421ad4bbf39716a7c25161cb118f02344291e0c102Phil 143706c5f38284d9d57cc8f7a957b8577513b97bc16Phil############ 144706c5f38284d9d57cc8f7a957b8577513b97bc16Phil### IPv6 ### 145706c5f38284d9d57cc8f7a957b8577513b97bc16Phil############ 146706c5f38284d9d57cc8f7a957b8577513b97bc16Phil 147cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadondef _in6_getifaddr(ifname): 148cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon """ 149cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon Returns a list of IPv6 addresses configured on the interface ifname. 150cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon """ 151cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon 152cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon # Get the output of ifconfig 153cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon try: 154cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon f = os.popen("%s %s" % (conf.prog.ifconfig, ifname)) 155d51edef8530fe1e944f13eb65ef863c2d7f04b1dgpotter except OSError as msg: 156cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon log_interactive.warning("Failed to execute ifconfig.") 157cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon return [] 158cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon 159cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon # Iterate over lines and extract IPv6 addresses 160af70bfcbd63dca4b743b3b2b76210dc33d8679c1Guillaume Valadon ret = [] 16199e2f18c2b0187dcd9d21e13df44f981de4925f2Guillaume Valadon for line in f: 162af70bfcbd63dca4b743b3b2b76210dc33d8679c1Guillaume Valadon if "inet6" in line: 16399e2f18c2b0187dcd9d21e13df44f981de4925f2Guillaume Valadon addr = line.rstrip().split(None, 2)[1] # The second element is the IPv6 address 164cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon else: 165cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon continue 166af70bfcbd63dca4b743b3b2b76210dc33d8679c1Guillaume Valadon if '%' in line: # Remove the interface identifier if present 16799e2f18c2b0187dcd9d21e13df44f981de4925f2Guillaume Valadon addr = addr.split("%", 1)[0] 168cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon 169cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon # Check if it is a valid IPv6 address 170cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon try: 171cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon socket.inet_pton(socket.AF_INET6, addr) 172cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon except: 173cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon continue 174cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon 175cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon # Get the scope and keep the address 1762066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon scope = in6_getscope(addr) 177cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon ret.append((addr, scope, ifname)) 178cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon 179cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon return ret 180cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon 1810d92fc9fbb58df9cc4bbeb007bf65020fe1aa092Victor Pfautzdef in6_getifaddr(): 182706c5f38284d9d57cc8f7a957b8577513b97bc16Phil """ 183706c5f38284d9d57cc8f7a957b8577513b97bc16Phil Returns a list of 3-tuples of the form (addr, scope, iface) where 184706c5f38284d9d57cc8f7a957b8577513b97bc16Phil 'addr' is the address of scope 'scope' associated to the interface 185cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon 'iface'. 186706c5f38284d9d57cc8f7a957b8577513b97bc16Phil 187706c5f38284d9d57cc8f7a957b8577513b97bc16Phil This is the list of all addresses of all interfaces available on 188706c5f38284d9d57cc8f7a957b8577513b97bc16Phil the system. 189706c5f38284d9d57cc8f7a957b8577513b97bc16Phil """ 190706c5f38284d9d57cc8f7a957b8577513b97bc16Phil 191cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon # List all network interfaces 19235f97efc53839f6366918c251dba5df2ac553c8dGuillaume Valadon if OPENBSD: 193a7d199a93e4b8deeefaf4e85fd553ec0a1c002daDaniel Jakots try: 194a7d199a93e4b8deeefaf4e85fd553ec0a1c002daDaniel Jakots f = os.popen("%s" % conf.prog.ifconfig) 195d51edef8530fe1e944f13eb65ef863c2d7f04b1dgpotter except OSError as msg: 1960d92fc9fbb58df9cc4bbeb007bf65020fe1aa092Victor Pfautz log_interactive.warning("Failed to execute ifconfig.") 1970d92fc9fbb58df9cc4bbeb007bf65020fe1aa092Victor Pfautz return [] 198a7d199a93e4b8deeefaf4e85fd553ec0a1c002daDaniel Jakots 199a7d199a93e4b8deeefaf4e85fd553ec0a1c002daDaniel Jakots # Get the list of network interfaces 200a7d199a93e4b8deeefaf4e85fd553ec0a1c002daDaniel Jakots splitted_line = [] 201a7d199a93e4b8deeefaf4e85fd553ec0a1c002daDaniel Jakots for l in f: 202a7d199a93e4b8deeefaf4e85fd553ec0a1c002daDaniel Jakots if "flags" in l: 203a7d199a93e4b8deeefaf4e85fd553ec0a1c002daDaniel Jakots iface = l.split()[0].rstrip(':') 204a7d199a93e4b8deeefaf4e85fd553ec0a1c002daDaniel Jakots splitted_line.append(iface) 205a7d199a93e4b8deeefaf4e85fd553ec0a1c002daDaniel Jakots 206a7d199a93e4b8deeefaf4e85fd553ec0a1c002daDaniel Jakots else: # FreeBSD, NetBSD or Darwin 207a7d199a93e4b8deeefaf4e85fd553ec0a1c002daDaniel Jakots try: 2080d92fc9fbb58df9cc4bbeb007bf65020fe1aa092Victor Pfautz f = os.popen("%s -l" % conf.prog.ifconfig) 209d51edef8530fe1e944f13eb65ef863c2d7f04b1dgpotter except OSError as msg: 2100d92fc9fbb58df9cc4bbeb007bf65020fe1aa092Victor Pfautz log_interactive.warning("Failed to execute ifconfig.") 2110d92fc9fbb58df9cc4bbeb007bf65020fe1aa092Victor Pfautz return [] 212a7d199a93e4b8deeefaf4e85fd553ec0a1c002daDaniel Jakots 213a7d199a93e4b8deeefaf4e85fd553ec0a1c002daDaniel Jakots # Get the list of network interfaces 214a7d199a93e4b8deeefaf4e85fd553ec0a1c002daDaniel Jakots splitted_line = f.readline().rstrip().split() 215cb32e5344e075f97776c8043ffd312c2d3ce3477Guillaume Valadon 216706c5f38284d9d57cc8f7a957b8577513b97bc16Phil ret = [] 217af70bfcbd63dca4b743b3b2b76210dc33d8679c1Guillaume Valadon for i in splitted_line: 2180d92fc9fbb58df9cc4bbeb007bf65020fe1aa092Victor Pfautz ret += _in6_getifaddr(i) 2190d92fc9fbb58df9cc4bbeb007bf65020fe1aa092Victor Pfautz return ret 220706c5f38284d9d57cc8f7a957b8577513b97bc16Phil 2212066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon 222706c5f38284d9d57cc8f7a957b8577513b97bc16Phildef read_routes6(): 2232066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon """Return a list of IPv6 routes than can be used by Scapy.""" 2242066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon 2252066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon # Call netstat to retrieve IPv6 routes 2262066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon fd_netstat = os.popen("netstat -rn -f inet6") 2272066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon 2280d92fc9fbb58df9cc4bbeb007bf65020fe1aa092Victor Pfautz # List interfaces IPv6 addresses 2292066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon lifaddr = in6_getifaddr() 2302066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon if not lifaddr: 2312066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon return [] 2322066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon 2332066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon # Routes header information 2342066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon got_header = False 235963c58e7bf45216aa225f56b721aa9261fd9fe5aPhil mtu_present = False 236963c58e7bf45216aa225f56b721aa9261fd9fe5aPhil prio_present = False 2372066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon 2382066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon # Parse the routes 239706c5f38284d9d57cc8f7a957b8577513b97bc16Phil routes = [] 2402066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon for line in fd_netstat.readlines(): 2412066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon 2422066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon # Parse the routes header and try to identify extra columns 2432066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon if not got_header: 2442066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon if "Destination" == line[:11]: 2452066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon got_header = True 2462066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon mtu_present = "Mtu" in line 2472066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon prio_present = "Prio" in line 248706c5f38284d9d57cc8f7a957b8577513b97bc16Phil continue 2492066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon 2502066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon # Parse a route entry according to the operating system 2512066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon splitted_line = line.split() 25235f97efc53839f6366918c251dba5df2ac553c8dGuillaume Valadon if OPENBSD or NETBSD: 2532066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon index = 5 + mtu_present + prio_present 2542066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon if len(splitted_line) < index: 2552066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon warning("Not enough columns in route entry !") 2562066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon continue 2572066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon destination, next_hop, flags = splitted_line[:3] 2582066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon dev = splitted_line[index] 2592066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon else: 2600d92fc9fbb58df9cc4bbeb007bf65020fe1aa092Victor Pfautz # FREEBSD or DARWIN 2612066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon if len(splitted_line) < 4: 2622066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon warning("Not enough columns in route entry !") 2632066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon continue 2642066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon destination, next_hop, flags, dev = splitted_line[:4] 2652066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon 2663fc82d65918606609ab12a449982e37891e1ade3gpotter # XXX: TODO: add metrics for unix.py (use -e option on netstat) 2673fc82d65918606609ab12a449982e37891e1ade3gpotter metric = 1 2683fc82d65918606609ab12a449982e37891e1ade3gpotter 2692066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon # Check flags 2702066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon if not "U" in flags: # usable route 2712066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon continue 272ed95a6a3cea25583d339e564b7c93bdbcbbf9483Guillaume Valadon if "R" in flags: # Host or net unreachable 273706c5f38284d9d57cc8f7a957b8577513b97bc16Phil continue 2742066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon if "m" in flags: # multicast address 2752066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon # Note: multicast routing is handled in Route6.route() 276706c5f38284d9d57cc8f7a957b8577513b97bc16Phil continue 277706c5f38284d9d57cc8f7a957b8577513b97bc16Phil 2782066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon # Replace link with the default route in next_hop 2792066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon if "link" in next_hop: 2802066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon next_hop = "::" 281706c5f38284d9d57cc8f7a957b8577513b97bc16Phil 2822066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon # Default prefix length 2832066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon destination_plen = 128 284706c5f38284d9d57cc8f7a957b8577513b97bc16Phil 2852066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon # Extract network interface from the zone id 2862066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon if '%' in destination: 2872066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon destination, dev = destination.split('%') 2882066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon if '/' in dev: 2892066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon # Example: fe80::%lo0/64 ; dev = "lo0/64" 2902066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon dev, destination_plen = dev.split('/') 2912066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon if '%' in next_hop: 2922066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon next_hop, dev = next_hop.split('%') 293706c5f38284d9d57cc8f7a957b8577513b97bc16Phil 2942066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon # Ensure that the next hop is a valid IPv6 address 2952066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon if not in6_isvalid(next_hop): 2962066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon # Note: the 'Gateway' column might contain a MAC address 2972066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon next_hop = "::" 2981ad4bbf39716a7c25161cb118f02344291e0c102Phil 2992066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon # Modify parsed routing entries 3002066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon # Note: these rules are OS specific and may evolve over time 3012066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon if destination == "default": 3022066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon destination, destination_plen = "::", 0 3032066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon elif '/' in destination: 3042066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon # Example: fe80::/10 3052066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon destination, destination_plen = destination.split('/') 3062066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon if '/' in dev: 3072066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon # Example: ff02::%lo0/32 ; dev = "lo0/32" 3082066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon dev, destination_plen = dev.split('/') 3091ad4bbf39716a7c25161cb118f02344291e0c102Phil 3102066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon # Check route entries parameters consistency 3112066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon if not in6_isvalid(destination): 3122066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon warning("Invalid destination IPv6 address in route entry !") 3132066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon continue 3142066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon try: 3152066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon destination_plen = int(destination_plen) 3162066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon except: 3172066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon warning("Invalid IPv6 prefix length in route entry !") 3182066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon continue 3192066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon if in6_ismlladdr(destination) or in6_ismnladdr(destination): 3202066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon # Note: multicast routing is handled in Route6.route() 3212066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon continue 3221ad4bbf39716a7c25161cb118f02344291e0c102Phil 32335f97efc53839f6366918c251dba5df2ac553c8dGuillaume Valadon if LOOPBACK_NAME in dev: 3242066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon # Handle ::1 separately 3252066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon cset = ["::1"] 3262066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon next_hop = "::" 3272066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon else: 3282066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon # Get possible IPv6 source addresses 32952165d0dd55a1071b935d002a41a95210c97f8e7Guillaume Valadon devaddrs = (x for x in lifaddr if x[2] == dev) 330653d114f04a98dd7cc38c4f57a7cad78f28e50dcgpotter cset = construct_source_candidate_set(destination, destination_plen, devaddrs) 3311ad4bbf39716a7c25161cb118f02344291e0c102Phil 3322066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon if len(cset): 3333fc82d65918606609ab12a449982e37891e1ade3gpotter routes.append((destination, destination_plen, next_hop, dev, cset, metric)) 3342066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon 3352066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon fd_netstat.close() 3362066af02d4144547e3531c16a5ede1340b97938bGuillaume Valadon return routes 337