Source code for switchyard.lib.interface

from ipaddress import ip_interface, ip_address, IPv6Interface, IPv4Interface, IPv6Address, IPv4Address
from enum import Enum
from socket import if_nametoindex

from .address import EthAddr
from .logging import log_debug
from ..pcapffi import pcap_devices

[docs]class InterfaceType(Enum): Unknown=1 Loopback=2 Wired=3 Wireless=4
[docs]class Interface(object): __slots__ = ['__name','__ethaddr','__ipaddrset','__ifnum','__iftype'] __nextnum = 1 ''' Class that models a single logical interface on a network device. An interface has a name, 48-bit Ethernet MAC address, and (optionally) set of IP addresses with network masks. An interface also has a number associated with it and a type, which is one of the values of the enumerated type ``InterfaceType``. ''' def __init__(self, name, ethaddr, ifnum=None, iftype=InterfaceType.Unknown): self.__name = name self.ethaddr = ethaddr self.__ipaddrset = set() self.ifnum = ifnum self.__iftype = iftype @property def name(self): '''Get the name of the interface''' return self.__name @property def ethaddr(self): '''Get the Ethernet address associated with the interface''' return self.__ethaddr @ethaddr.setter def ethaddr(self, value): if isinstance(value, EthAddr): self.__ethaddr = value elif isinstance(value, (str,bytes)): self.__ethaddr = EthAddr(value) elif value is None: self.__ethaddr = EthAddr('00:00:00:00:00:00') else: raise ValueError("Can't initialize ethaddr with {}".format(value)) @property def ipaddrs(self): '''Get the IP addresses associated with the interface, as a (frozen) set of ipaddress.IPv4Interface or ipaddress.IPv6Interface objects''' return frozenset(self.__ipaddrset)
[docs] def assign_ipaddr(self, value): ''' Assign a new IP address (v4 or v6) to this interface. Address can either be a IPv4Interface object, IPv6Interface object, or string in the form 'addr/prefix' (i.e., something that ipaddress.ip_interface will parse). ''' if isinstance(value, (IPv4Interface, IPv6Interface)): self.__ipaddrset.add(value) elif isinstance(value, (str,IPv4Address,IPv6Address)): self.__ipaddrset.add(ip_interface(value)) elif value is None: self.__ipaddrset.add(ip_interface('0.0.0.0')) else: raise Exception("Invalid type assignment to IP address (must be string or existing IP address) ({})".format(value))
[docs] def remove_ipaddr(self, value): ''' Remove an IP address from this interface. Value to remove can be as a string or IPAddress object. ''' ipa = ip_interface(value) for addr in self.__ipaddrset: if addr.ip == ipa.ip: self.__ipaddrset.remove(addr) return raise Exception("No such address {} exists to remove from interface".format(ipa))
@property def ifnum(self): '''Get the interface number (integer) associated with the interface''' return self.__ifnum @ifnum.setter def ifnum(self, value): if not isinstance(value, int): value = Interface.__nextnum Interface.__nextnum += 1 self.__ifnum = int(value) @property def iftype(self): '''Get the type of the interface as a value from the InterfaceType enumeration.''' return self.__iftype def __str__(self): s = "{} mac:{}".format(str(self.name), str(self.ethaddr)) for ipa in self.ipaddrs: if int(ipa) != 0: s += " ip:{}".format(ipa) return s
def make_device_list(includes=set(), excludes=set()): log_debug("Making device list. Includes: {}, Excludes: {}".format(includes, excludes)) non_interfaces = set() devs = set([ dev.name for dev in pcap_devices() if not dev.isloop or dev.name in includes]) includes = set(includes) # may have been given as a list includes.intersection_update(devs) # only include devs that actually exist for d in devs: try: ifnum = if_nametoindex(d) except: non_interfaces.add(d) devs.difference_update(non_interfaces) log_debug("Devices found: {}".format(devs)) # remove devs from excludelist devs.difference_update(set(excludes)) # if includelist is non-empty, perform # intersection with devs found and includelist if includes: devs.intersection_update(includes) log_debug("Using these devices: {}".format(devs)) return devs