def make_route( self, dst, # type: str gw=None, # type: Optional[str] dev=None, # type: Optional[str] ): # type: (...) -> Tuple[str, int, str, str, List[str], int] """Internal function : create a route for 'dst' via 'gw'. """ prefix, plen_b = (dst.split("/") + ["128"])[:2] plen = int(plen_b) if gw is None: gw = "::" if dev is None: dev, ifaddr_uniq, x = self.route(gw) ifaddr = [ifaddr_uniq] else: lifaddr = in6_getifaddr() devaddrs = [x for x in lifaddr if x[2] == dev] ifaddr = construct_source_candidate_set(prefix, plen, devaddrs) self.ipv6_ifaces.add(dev) return (prefix, plen, gw, dev, ifaddr, 1)
def _append_route6(routes, dpref, dp, nh, iface, lifaddr, metric): cset = [] # candidate set (possible source addresses) if iface.name == scapy.consts.LOOPBACK_NAME: if dpref == '::': return cset = ['::1'] else: devaddrs = (x for x in lifaddr if x[2] == iface) cset = construct_source_candidate_set(dpref, dp, devaddrs) if not cset: return # APPEND (DESTINATION, NETMASK, NEXT HOP, IFACE, CANDIDATS, METRIC) routes.append((dpref, dp, nh, iface, cset, metric))
def make_route(self, dst, gw=None, dev=None): """Internal function : create a route for 'dst' via 'gw'. """ prefix, plen = (dst.split("/") + ["128"])[:2] plen = int(plen) if gw is None: gw = "::" if dev is None: dev, ifaddr, x = self.route(gw) else: # TODO: do better than that # replace that unique address by the list of all addresses lifaddr = in6_getifaddr() devaddrs = [x for x in lifaddr if x[2] == dev] ifaddr = construct_source_candidate_set(prefix, plen, devaddrs) return (prefix, plen, gw, dev, ifaddr, 1)
def make_route(self, dst, gw=None, dev=None): """Internal function : create a route for 'dst' via 'gw'. """ prefix, plen = (dst.split("/") + ["128"])[:2] plen = int(plen) if gw is None: gw = "::" if dev is None: dev, ifaddr, x = self.route(gw) else: lifaddr = in6_getifaddr() devaddrs = [x for x in lifaddr if x[2] == dev] ifaddr = construct_source_candidate_set(prefix, plen, devaddrs) self.ipv6_ifaces.add(dev) return (prefix, plen, gw, dev, ifaddr, 1)
def read_routes6(): """Return a list of IPv6 routes than can be used by Scapy.""" # Call netstat to retrieve IPv6 routes fd_netstat = os.popen("netstat -rn -f inet6") # List interfaces IPv6 addresses lifaddr = in6_getifaddr() if not lifaddr: return [] # Routes header information got_header = False mtu_present = False prio_present = False # Parse the routes routes = [] for line in fd_netstat.readlines(): # Parse the routes header and try to identify extra columns if not got_header: if "Destination" == line[:11]: got_header = True mtu_present = "Mtu" in line prio_present = "Prio" in line continue # Parse a route entry according to the operating system splitted_line = line.split() if OPENBSD or NETBSD: index = 5 + mtu_present + prio_present if len(splitted_line) < index: warning("Not enough columns in route entry !") continue destination, next_hop, flags = splitted_line[:3] dev = splitted_line[index] else: # FREEBSD or DARWIN if len(splitted_line) < 4: warning("Not enough columns in route entry !") continue destination, next_hop, flags, dev = splitted_line[:4] # XXX: TODO: add metrics for unix.py (use -e option on netstat) metric = 1 # Check flags if not "U" in flags: # usable route continue if "R" in flags: # Host or net unreachable continue if "m" in flags: # multicast address # Note: multicast routing is handled in Route6.route() continue # Replace link with the default route in next_hop if "link" in next_hop: next_hop = "::" # Default prefix length destination_plen = 128 # Extract network interface from the zone id if '%' in destination: destination, dev = destination.split('%') if '/' in dev: # Example: fe80::%lo0/64 ; dev = "lo0/64" dev, destination_plen = dev.split('/') if '%' in next_hop: next_hop, dev = next_hop.split('%') # Ensure that the next hop is a valid IPv6 address if not in6_isvalid(next_hop): # Note: the 'Gateway' column might contain a MAC address next_hop = "::" # Modify parsed routing entries # Note: these rules are OS specific and may evolve over time if destination == "default": destination, destination_plen = "::", 0 elif '/' in destination: # Example: fe80::/10 destination, destination_plen = destination.split('/') if '/' in dev: # Example: ff02::%lo0/32 ; dev = "lo0/32" dev, destination_plen = dev.split('/') # Check route entries parameters consistency if not in6_isvalid(destination): warning("Invalid destination IPv6 address in route entry !") continue try: destination_plen = int(destination_plen) except: warning("Invalid IPv6 prefix length in route entry !") continue if in6_ismlladdr(destination) or in6_ismnladdr(destination): # Note: multicast routing is handled in Route6.route() continue if LOOPBACK_NAME in dev: # Handle ::1 separately cset = ["::1"] next_hop = "::" else: # Get possible IPv6 source addresses devaddrs = (x for x in lifaddr if x[2] == dev) cset = construct_source_candidate_set(destination, destination_plen, devaddrs) if len(cset): routes.append((destination, destination_plen, next_hop, dev, cset, metric)) fd_netstat.close() return routes
def read_routes6(): """Return a list of IPv6 routes than can be used by Scapy.""" # Call netstat to retrieve IPv6 routes fd_netstat = os.popen("netstat -rn -f inet6") # List interfaces IPv6 addresses lifaddr = in6_getifaddr() if not lifaddr: return [] # Routes header information got_header = False mtu_present = False prio_present = False # Parse the routes routes = [] for line in fd_netstat.readlines(): # Parse the routes header and try to identify extra columns if not got_header: if "Destination" == line[:11]: got_header = True mtu_present = "Mtu" in line prio_present = "Prio" in line continue # Parse a route entry according to the operating system splitted_line = line.split() if OPENBSD or NETBSD: index = 5 + mtu_present + prio_present if len(splitted_line) < index: warning("Not enough columns in route entry !") continue destination, next_hop, flags = splitted_line[:3] dev = splitted_line[index] else: # FREEBSD or DARWIN if len(splitted_line) < 4: warning("Not enough columns in route entry !") continue destination, next_hop, flags, dev = splitted_line[:4] # XXX: TODO: add metrics for unix.py (use -e option on netstat) metric = 1 # Check flags if "U" not in flags: # usable route continue if "R" in flags: # Host or net unreachable continue if "m" in flags: # multicast address # Note: multicast routing is handled in Route6.route() continue # Replace link with the default route in next_hop if "link" in next_hop: next_hop = "::" # Default prefix length destination_plen = 128 # Extract network interface from the zone id if '%' in destination: destination, dev = destination.split('%') if '/' in dev: # Example: fe80::%lo0/64 ; dev = "lo0/64" dev, destination_plen = dev.split('/') if '%' in next_hop: next_hop, dev = next_hop.split('%') # Ensure that the next hop is a valid IPv6 address if not in6_isvalid(next_hop): # Note: the 'Gateway' column might contain a MAC address next_hop = "::" # Modify parsed routing entries # Note: these rules are OS specific and may evolve over time if destination == "default": destination, destination_plen = "::", 0 elif '/' in destination: # Example: fe80::/10 destination, destination_plen = destination.split('/') if '/' in dev: # Example: ff02::%lo0/32 ; dev = "lo0/32" dev, destination_plen = dev.split('/') # Check route entries parameters consistency if not in6_isvalid(destination): warning("Invalid destination IPv6 address in route entry !") continue try: destination_plen = int(destination_plen) except Exception: warning("Invalid IPv6 prefix length in route entry !") continue if in6_ismlladdr(destination) or in6_ismnladdr(destination): # Note: multicast routing is handled in Route6.route() continue if LOOPBACK_NAME in dev: # Handle ::1 separately cset = ["::1"] next_hop = "::" else: # Get possible IPv6 source addresses devaddrs = (x for x in lifaddr if x[2] == dev) cset = construct_source_candidate_set(destination, destination_plen, devaddrs) # noqa: E501 if len(cset): routes.append((destination, destination_plen, next_hop, dev, cset, metric)) # noqa: E501 fd_netstat.close() return routes