Exemplo n.º 1
0
    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))
Exemplo n.º 2
0
    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))
Exemplo n.º 3
0
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)
Exemplo n.º 4
0
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.

    '''
    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)