def run(self) -> int: try: with IPRoute() as ipr: links = ipr.get_links("all") routes = ipr.get_default_routes(family=AF_INET6) except Exception as e: LOG.exception(f"Failed to get list of valid interfaces: {e}") return -1 for link in links: if link.get_attr("IFLA_IFNAME") != self.interface: continue self.interface_id = link["index"] break if not self.interface_id: LOG.error(f"Unable to find {self.interface} index") return 1 for route in routes: multi_routes = route.get_attr("RTA_MULTIPATH") for mr in multi_routes: if mr["oif"] == self.interface_id: return 0 return 2
def initdb(self, nl=None): ''' Restart IPRoute channel, and create all the DB from scratch. Can be used when sync is lost. ''' self.nl = nl or IPRoute() self.nl.monitor = True self.nl.bind(async=True) # resolvers self.interfaces = Dotkeys() self.routes = RoutingTables(ipdb=self) self.by_name = Dotkeys() self.by_index = Dotkeys() # caches self.ipaddr = {} self.neighbors = {} # load information links = self.nl.get_links() for link in links: self.device_put(link, skip_slaves=True) for link in links: self.update_slaves(link) self.update_addr(self.nl.get_addr()) self.update_neighbors(self.nl.get_neighbors()) routes = self.nl.get_routes() self.update_routes(routes)
def run(self): nat = {} clients = [] srv = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) srv.bind((self.addr, self.port)) ipr = IPRoute() ipr.bind() poll = select.poll() poll.register(ipr, select.POLLIN | select.POLLPRI) poll.register(srv, select.POLLIN | select.POLLPRI) while True: events = poll.poll() for (fd, event) in events: if fd == ipr.fileno(): bufsize = ipr.getsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF) // 2 data = ipr.recv(bufsize) cookie = struct.unpack('I', data[8:12])[0] if cookie == 0: for address in clients: srv.sendto(data, address) else: srv.sendto(data, nat[cookie]) else: data, address = srv.recvfrom(16384) if data is None: clients.remove(address) continue cookie = struct.unpack('I', data[8:12])[0] nat[cookie] = address ipr.sendto(data, (0, 0))
def __init__(self, ns_info): self.__ns_info = ns_info self.name = ns_info['name'] self.ip = IPRoute() self.__interfaces = {} self.__bridges = {} self.logger_topo = None
def __init__(self, vswitch_instance, ns_info): self.__ns_info = ns_info self.name = ns_info['name'] self.ip = IPRoute() # self.ipdb = IPDB(nl=NetNS(self.name)) self.main_ipdb = IPDB() self.__vswitch = vswitch_instance
def initdb(self): # flush all the DB objects with self.exclusive: # explicitly cleanup object references for event in tuple(self._event_map): del self._event_map[event] self._flush_db() # if the command socket is not provided, create it if self._nl_own: if self.nl is not None: self.nl.close() self.nl = IPRoute(sndbuf=self._sndbuf, rcvbuf=self._rcvbuf, async_qsize=0) # OBS: legacy design # setup monitoring socket if self.mnl is not None: self._flush_mnl() self.mnl.close() self.mnl = self.nl.clone() try: self.mnl.bind(groups=self.nl_bind_groups, async_cache=self._nl_async) except: self.mnl.close() if self._nl_own is None: self.nl.close() raise # explicitly cleanup references for key in tuple(self._deferred): del self._deferred[key] for module in self._plugins: if (module.groups & self.nl_bind_groups) != module.groups: continue for plugin in module.spec: self._deferred[plugin['name']] = module.spec if plugin['name'] in self._loaded: delattr(self, plugin['name']) self._loaded.remove(plugin['name']) # start service threads for tspec in (('_mthread', '_serve_main', 'IPDB main event loop'), ('_cthread', '_serve_cb', 'IPDB cb event loop')): tg = getattr(self, tspec[0], None) if not getattr(tg, 'is_alive', lambda: False)(): tx = threading.Thread(name=tspec[2], target=getattr(self, tspec[1])) setattr(self, tspec[0], tx) tx.setDaemon(True) tx.start()
def address_exists(cls, config, value): ip = IPRoute() if value.version == 4: family = socket.AF_INET elif value.version == 6: family = socket.AF_INET6 else: raise AssertionError("Unknown version {}".format(value.version)) if ip.get_addr(family=family, address=value.ip, prefixlen=value.prefixlen): raise OptionCheckError("No such address {}".format(value), option=cls.__name__)
def connection_down(parsed_args): ipsec_connection = load_ipsec_connection(parsed_args) connection_name = ipsec_connection['name'] ip_route = IPRoute() if is_connection_up(ip_route, ipsec_connection): ipsec_result = ipsec('down', connection_name) if ipsec_result.status != 0: raise DockerIPSecError('Failed to disconnect VPN: {0}\n{1}'.format( connection_name, ipsec_result.output)) filter_func = functools.partial(comment_matches_ipsec_connection, connection_name) remove_iptables_rules(filter_func)
def add_docker_networks(parsed_args): ipsec_connection = load_ipsec_connection(parsed_args) connection_name = ipsec_connection['name'] docker_networks = parsed_args.dockerNetworks docker_client = docker.DockerClient() docker_network_to_ip_network = functools.partial( ip_network_for_docker_network, docker_client) docker_ip_networks = tuple( map(docker_network_to_ip_network, docker_networks)) ip_route = IPRoute() if not is_connection_up(ip_route, ipsec_connection): raise DockerIPSecError( 'IPSec connection {0} is not connected!'.format(connection_name)) add_ip_networks(ip_route, docker_ip_networks, connection_name)
def create_interface(self): ifname = self.__intf_info["ifname"] IP_ROUTE = IPRoute() if len(IP_ROUTE.link_lookup(ifname=ifname)) > 0: self.logger_topo.warning( "ip link {} exists so not create it.".format(ifname)) IP_ROUTE.close() return if self.__peer: if len(IP_ROUTE.link_lookup(ifname=self.__peer)) > 0: self.logger_topo.warning( "ip link {} exists so not create it.".format(ifname)) IP_ROUTE.close() return else: # Close IP_ROUTE first anyway IP_ROUTE.close() ps_intf = r"^\d+: (?P<intf>[\w-]+): " p_intf = re.compile(ps_intf, re.MULTILINE) _, out, _ = exec_cmd_in_namespace(self.__namespace, ["ip", "link"]) m_intf = p_intf.findall(out) if ifname in m_intf: self.logger_topo.warning( "ip link {} exists in namespace {} so not create it.". format(ifname, self.__namespace)) return MAIN_IPDB = IPDB() MAIN_IPDB.create(ifname=ifname, kind="veth" if self.__peer else "dummy", peer=self.__peer).commit() with MAIN_IPDB.interfaces[ifname] as veth: try: veth.net_ns_fd = self.__namespace except netlink.exceptions.NetlinkError as e: MAIN_IPDB.release() if e.code == 17: # "File exists" pass else: raise e MAIN_IPDB.release() self.logger_topo.info( "interface {} in namespace {} is created, peer: {}.".format( ifname, self.__namespace, self.__peer))
def initdb(self, nl=None): ''' Restart IPRoute channel, and create all the DB from scratch. Can be used when sync is lost. ''' self.nl = nl or IPRoute() # resolvers self.interfaces = Dotkeys() self.routes = RoutingTableSet(ipdb=self, ignore_rtables=self._ignore_rtables) self.by_name = View(src=self.interfaces, constraint=lambda k, v: isinstance(k, basestring)) self.by_index = View(src=self.interfaces, constraint=lambda k, v: isinstance(k, int)) # caches self.ipaddr = {} self.neighbours = {} try: self.nl.bind(async=self._nl_async) # load information links = self.nl.get_links() for link in links: self.device_put(link, skip_slaves=True) for link in links: self.update_slaves(link) # bridge info links = self.nl.get_vlans() for link in links: self.update_dev(link) # self.update_addr(self.nl.get_addr()) self.update_neighbours(self.nl.get_neighbours()) routes4 = self.nl.get_routes(family=AF_INET) routes6 = self.nl.get_routes(family=AF_INET6) self.update_routes(routes4) self.update_routes(routes6) except Exception as e: try: self.nl.close() except: pass raise e
def create(self): """ Main function to build all infrasim virtual network referring to resolved topology """ self.__load() self.logger_topo.info("[Define openvswitches]") for _, ovs in self.__openvswitch.items(): ovs.add_vswitch() ovs.add_all_ports() # FIXME: substitute for below code # self.__vswitch_ex.set_interface("phy-br-ex", "int-br-ex") # self.__vswitch_int.set_interface("int-br-ex", "phy-br-ex") ovs.add_interface_d() self.logger_topo.info("[Define namespaces]") for _, ns in self.__namespace.items(): ns.create_namespace() ns.create_all_interfaces(ref=self.__connection) self.logger_topo.info("[Set openvswitch ports up]") IP_ROUTE = IPRoute() for _, ovs in self.__openvswitch.items(): idx = IP_ROUTE.link_lookup(ifname=ovs.name)[0] IP_ROUTE.link("set", index=idx, state="up") self.logger_topo.info("set openvswitch {} up.".format(ovs.name)) for _, ovs_port in self.__connection.items(): idx = IP_ROUTE.link_lookup(ifname=ovs_port)[0] IP_ROUTE.link("set", index=idx, state="up") self.logger_topo.info("set port {} up.".format(ovs_port)) self.logger_topo.info("[Set namespace interfaces up]") for _, ns in self.__namespace.items(): ns.create_interface_d() ns.link_up_all() ns.create_routes() self.logger_topo.info("[Setup portforward]") self.__port_forward.build() IP_ROUTE.close()
def connection_up(parsed_args): ipsec_connection = load_ipsec_connection(parsed_args) connection_name = ipsec_connection['name'] docker_networks = parsed_args.dockerNetworks if len(docker_networks) > 0: docker_client = docker.DockerClient() docker_network_to_ip_network = functools.partial( ip_network_for_docker_network, docker_client) docker_ip_networks = tuple( map(docker_network_to_ip_network, docker_networks)) else: docker_ip_networks = tuple() ip_route = IPRoute() if not is_connection_up(ip_route, ipsec_connection): ipsec_result = ipsec('up', connection_name) if ipsec_result.status != 0: raise DockerIPSecError('Failed to connect VPN: {0}\n{1}'.format( connection_name, ipsec_result.output)) add_ip_networks(ip_route, docker_ip_networks, connection_name)
def initdb(self): # common event map, empty by default, so all the # events aer just ignored self.release(complete=False) self._stop = False # explicitly cleanup object references for event in tuple(self._event_map): del self._event_map[event] # if the command socket is not provided, create it if self._nl_own: self.nl = IPRoute() # setup monitoring socket self.mnl = self.nl.clone() try: self.mnl.bind(groups=self.nl_bind_groups, async=self._nl_async) except: self.mnl.close() if self._nl_own is None: self.nl.close() raise # explicitly cleanup references for key in tuple(self._deferred): del self._deferred[key] for module in self._plugins: if (module.groups & self.nl_bind_groups) != module.groups: continue for plugin in module.spec: self._deferred[plugin['name']] = module.spec if plugin['name'] in self._loaded: delattr(self, plugin['name']) self._loaded.remove(plugin['name']) # start the monitoring thread self._mthread = threading.Thread(name="IPDB event loop", target=self.serve_forever) self._mthread.setDaemon(True) self._mthread.start()
def enable_static_routes(static_routes): """ 启用默认路由 :param static_routes: list 默认路由列表 """ with IPRoute() as route: for r in static_routes: if_id = route.link_lookup( ifname=r['interface'])[0] if 'interface' in r else None args = { 'dst': r['net'], 'oif': if_id, 'gateway': r.get('gateway'), 'metric': 1 } args = {k: v for k, v in args.iteritems() if v} try: route.route('add', **args) except NetlinkError as e: if e.code == 17: continue else: raise
def main(): """ Program entry point when run interactively. """ # prepare option parser parser = ArgumentParser(usage="usage: %(prog)s [options]", description="Executes a UDP broadcast to test for " "connectivity") parser.add_argument("-i", "--interface", dest="interface", default="poprow0", action="store", metavar="ifname", help="Interface to use [default: %(default)s]") parser.add_argument("-p", "--port", dest="port", type=int, default=12345, action="store", help="UDP port [default: %(default)s]", metavar="PORT") parser.add_argument( "-n", "--count", dest="count", type=int, default=100, action="store", help="Number of packets to send [default: %(default)s]", metavar="COUNT") parser.add_argument("-t", "--interval", dest="interval", type=float, default=0.2, action="store", help="Packet interval [default: %(default)s]") parser.add_argument("-v", "--verbose", dest="verbose", action="store_true") # parse options args = parser.parse_args() # copy options interface = args.interface port = args.port count = args.count interval = args.interval verbose = args.verbose ip = IPRoute() if_index = ip.link_lookup(ifname=interface) if len(if_index) == 0: print >> sys.stderr, "Can't find interface %s" % interface sys.exit(1) # from the given interface find unicast and broadcast addresses if_info = ip.get_addr(index=if_index[0])[0] address = if_info.get_attr("IFA_ADDRESS") netmask = if_info["prefixlen"] network = ipaddr.IPv4Network("%s/%d" % (address, netmask)) broadcast = str(network.broadcast) # get hostname as additional information to send in the packets hostname = socket.gethostname() sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) i = 0 run = True while i < count and run: try: payload = "POPROWPING %d %s" % (i, hostname) if verbose: print >> sys.stderr, "Sending packet #%d to %s:%d" % \ (i+1, broadcast, port) sock.sendto(payload, (broadcast, port)) i += 1 time.sleep(interval) except SystemExit: run = False if verbose: print >> sys.stderr, "Catching SystemExit. Quitting" except KeyboardInterrupt: run = False if verbose: print >> sys.stderr, "Keyboard Interrupt. Quitting" except: run = False if verbose: print >> sys.stderr, "Error while sending packet. Quitting" sock.close()
def main(): """ Program entry point when run interactively. """ # prepare option parser parser = ArgumentParser(usage="usage: %(prog)s [options]", description="Listens to UDP broadcasts to test for " "connectivity") parser.add_argument("-i", "--interface", dest="interface", default="poprow0", action="store", metavar="ifname", help="Interface to use [default: %(default)s]") parser.add_argument("-p", "--port", dest="port", type=int, default=12345, action="store", help="UDP port [default: %(default)s]", metavar="PORT") parser.add_argument("-f", "--filename", dest="filename", default="", action="store", help="Output file where to store results [default: " "stdout]", metavar="FILENAME") parser.add_argument("-v", "--verbose", dest="verbose", action="store_true") parser.add_argument("-d", "--daemon", dest="daemon", action="store_true", help="Daemonize the process") # parse options args = parser.parse_args() # copy options interface = args.interface port = args.port filename = args.filename verbose = args.verbose daemon = args.daemon ip = IPRoute() if_index = ip.link_lookup(ifname=interface) if len(if_index) == 0: print >> sys.stderr, "Can't find interface %s" % interface sys.exit(1) # from the given interface find unicast and broadcast addresses if_info = ip.get_addr(index=if_index[0])[0] address = if_info.get_attr("IFA_ADDRESS") netmask = if_info["prefixlen"] network = ipaddr.IPv4Network("%s/%d" % (address, netmask)) broadcast = str(network.broadcast) # get hostname as additional information for the log file hostname = socket.gethostname() if not daemon: signal.signal(signal.SIGTERM, signal_handler) else: daemonize() # setup output file if filename == "": outfile = sys.stdout else: outfile = open(filename, "w") if verbose: print >> sys.stderr, "Host with IP %s listening for packets on " \ "broadcast IP %s" % (address, broadcast) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind((broadcast, port)) run = True while run: try: datagram = sock.recvfrom(1024) payload = datagram[0].split(' ') src = datagram[1][0] src_port = datagram[1][1] # check that this is really our app message if payload[0] != "POPROWPING": continue count = int(payload[1]) remote_host = payload[2] if verbose: print >> sys.stderr, "Received packet #%d from %s:%d" % \ (count, src, src_port) outfile.write("%s,%s,%s,%s,%d\n" % (hostname, address, remote_host, src, count)) outfile.flush() except SystemExit: run = False if verbose: print >> sys.stderr, "Catching SystemExit. Quitting" except KeyboardInterrupt: run = False if verbose: print >> sys.stderr, "Keyboard Interrupt. Quitting" except: run = False if verbose: print >> sys.stderr, "Error while receiving packet. Quitting" sock.close() outfile.flush() outfile.close()
def NetNServer(netns, rcvch, cmdch, flags=os.O_CREAT): ''' The netns server supposed to be started automatically by NetNS. It has two communication channels: one simplex to forward incoming netlink packets, `rcvch`, and other synchronous duplex to get commands and send back responses, `cmdch`. Channels should support standard socket API, should be compatible with poll/select and should be able to transparently pickle objects. NetNS uses `multiprocessing.Pipe` for this purpose, but it can be any other implementation with compatible API. The first parameter, `netns`, is a netns name. Depending on the `flags`, the netns can be created automatically. The `flags` semantics is exactly the same as for `open(2)` system call. ... The server workflow is simple. The startup sequence:: 1. Create or open a netns. 2. Start `IPRoute` instance. It will be used only on the low level, the `IPRoute` will not parse any packet. 3. Start poll/select loop on `cmdch` and `IPRoute`. On the startup, the server sends via `cmdch` the status packet. It can be `None` if all is OK, or some exception. Further data handling, depending on the channel, server side:: 1. `IPRoute`: read an incoming netlink packet and send it unmodified to the peer via `rcvch`. The peer, polling `rcvch`, can handle the packet on its side. 2. `cmdch`: read tuple (cmd, argv, kwarg). If the `cmd` starts with "send", then take `argv[0]` as a packet buffer, treat it as one netlink packet and substitute PID field (offset 12, uint32) with its own. Strictly speaking, it is not mandatory for modern netlink implementations, but it is required by the protocol standard. ''' signal.signal(signal.SIGINT, signal.SIG_IGN) try: nsfd = setns(netns, flags) except OSError as e: cmdch.send(e) return e.errno except Exception as e: cmdch.send(OSError(errno.ECOMM, str(e), netns)) return 255 # try: ipr = IPRoute() rcvch_lock = ipr._sproxy.lock ipr._s_channel = rcvch poll = select.poll() poll.register(ipr, select.POLLIN | select.POLLPRI) poll.register(cmdch, select.POLLIN | select.POLLPRI) except Exception as e: cmdch.send(e) return 255 # all is OK so far cmdch.send(None) # 8<------------------------------------------------------------- while True: events = poll.poll() for (fd, event) in events: if fd == ipr.fileno(): bufsize = ipr.getsockopt(SOL_SOCKET, SO_RCVBUF) // 2 with rcvch_lock: rcvch.send(ipr.recv(bufsize)) elif fd == cmdch.fileno(): try: cmdline = cmdch.recv() if cmdline is None: poll.unregister(ipr) poll.unregister(cmdch) ipr.close() os.close(nsfd) return (cmd, argv, kwarg) = cmdline if cmd[:4] == 'send': # Achtung # # It's a hack, but we just have to do it: one # must use actual pid in netlink messages # # FIXME: there can be several messages in one # call buffer; but right now we can ignore it msg = argv[0][:12] msg += struct.pack("I", os.getpid()) msg += argv[0][16:] argv = list(argv) argv[0] = msg cmdch.send(getattr(ipr, cmd)(*argv, **kwarg)) except Exception as e: e.tb = traceback.format_exc() cmdch.send(e)
import os import shutil import json import re import subprocess import yaml from pyroute2 import netlink from pyroute2 import IPDB from pyroute2 import netns from pyroute2.iproute import IPRoute IP_ROUTE = IPRoute() MAIN_IPDB = IPDB() def start_process(args): """ Shell command agent """ try: p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate() return (p.returncode, out, err) except OSError: return (-1, None, None) def exec_cmd_in_namespace(ns, cmd):
# -*- coding: utf-8 -*- from __future__ import absolute_import, division, print_function, unicode_literals import os import ipaddress import threading #import pyroute2 # for pyinstaller # again for nuitka from pyroute2.iproute import IPRoute IP = IPRoute() def _transform_attrs_inplace(result): for item in result: item['attrs'] = dict(item['attrs']) return result def is_physical_iface(iface): device_path = os.readlink(os.path.join('/sys/class/net', iface)) return not device_path.startswith('../../devices/virtual/') def get_physical_ifaces(): ifaces = os.listdir('/sys/class/net') return [iface for iface in ifaces if is_physical_iface(iface)]