def update(self, data): """Update info about a network interface according to a given dictionary. Such data is provided by providers """ self.name = data.get('name', "") self.description = data.get('description', "") self.network_name = data.get('network_name', "") self.index = data.get('index', 0) self.ip = data.get('ip', "") self.mac = data.get('mac', "") self.flags = data.get('flags', 0) self.dummy = data.get('dummy', False) for ip in data.get('ips', []): if in6_isvalid(ip): self.ips[6].append(ip) else: self.ips[4].append(ip) # An interface often has multiple IPv6 so we don't store # a "main" one, unlike IPv4. if self.ips[4] and not self.ip: self.ip = self.ips[4][0]
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