Ejemplo n.º 1
0
def main():
    frame_size = 16384
    with mnl.Socket(netlink.NETLINK_ROUTE) as nl:
        nl.set_ringopt(mnl.MNL_RING_RX, mnl.MNL_SOCKET_BUFFER_SIZE * 16, 64,
                       frame_size, int(64 * mnl.MNL_SOCKET_BUFFER_SIZE * 16 / frame_size))
        nl.set_ringopt(mnl.MNL_RING_TX, mnl.MNL_SOCKET_BUFFER_SIZE * 16, 64,
                       frame_size, int(64 * mnl.MNL_SOCKET_BUFFER_SIZE * 16 / frame_size))
        nl.map_ring(mmap.MAP_SHARED)
        txring = nl.get_ring(mnl.MNL_RING_TX)
        frame = txring.current_frame()
        buf = mnl.MNL_FRAME_PAYLOAD(frame, frame_size)

        nlh = mnl.nlmsg_put_header(buf, mnl.Nlmsg)
        nlh.nlmsg_type = rtnl.RTM_GETLINK
        nlh.nlmsg_flags = netlink.NLM_F_REQUEST | netlink.NLM_F_DUMP
        seq = int(time.time())
        nlh.nlmsg_seq = seq
        rt = nlh.put_extra_header_as(rtnl.Rtgenmsg)
        rt.rtm_family = socket.AF_PACKET

        frame.nm_len = nlh.nlmsg_len
        frame.nm_status = netlink.NL_MMAP_STATUS_VALID

        nl.bind(0, mnl.MNL_SOCKET_AUTOPID)
        portid = nl.get_portid()

        # ??? commit a8866ff6a5bce7d0ec465a63bc482a85c09b0d39
        # nl.sendto(None)
        nl.send_nlmsg(nlh)
        txring.advance()

        rxring = nl.get_ring(mnl.MNL_RING_RX)
        ret = mnl.MNL_CB_OK
        while ret > mnl.MNL_CB_STOP:
            # XXX: no try / except
            mnl_socket_poll(nl)
            frame = rxring.current_frame()
            if frame.nm_status == netlink.NL_MMAP_STATUS_VALID:
                buf = mnl.MNL_FRAME_PAYLOAD(frame, frame.nm_len)
            elif frame.nm_status == netlink.NL_MMAP_STATUS_COPY:
                buf = nl.recv(frame_size * 2)
            else:
                frame.nm_status = netlink.NL_MMAP_STATUS_UNUSED
                rxring.advance()
                continue

            try:
                ret = mnl.cb_run(buf, seq, portid, data_cb, None)
            except Exception as e:
                print("mnl_cb_run: %s" % e, file=sys.stderr)
                raise
            frame.nm_status = netlink.NL_MMAP_STATUS_UNUSED
            rxring.advance()
Ejemplo n.º 2
0
 def test_nlmsg_put_header(self):
     nlh = mnl.nlmsg_put_header(self.hbuf)
     self.assertTrue(nlh.nlmsg_len == mnl.MNL_NLMSG_HDRLEN)
     h = mnl.nlmsg_put_header(self.hbuf, mnl.Nlmsg)
     self.assertTrue(h.nlmsg_len == mnl.MNL_NLMSG_HDRLEN)
     self.assertRaises(TypeError, mnl.nlmsg_put_header, self.hbuf, list)
Ejemplo n.º 3
0
def main():
    global nl_socket
    global sending_nlh

    if len(sys.argv) != 2:
        print("Usage: %s <poll-secs>" % sys.argv[0])
        sys.exit(-1)

    secs = int(sys.argv[1])
    print("Polling every %s seconds from kernel..." % secs)

    # Set high priority for this process, less chances to overrun
    # the netlink receiver buffer since the scheduler gives this process
    # more chances to run
    os.nice(-20)

    # Open netlink socket to operate with netfilter
    with mnl.Socket(netlink.NETLINK_NETFILTER) as nl_socket:
        # Subscribe to destroy events to avoid leaking counters. The same
        # socket is used to periodically atomically dump and reset counters.
        nl_socket.bind(nfnlcm.NF_NETLINK_CONNTRACK_DESTROY, mnl.MNL_SOCKET_AUTOPID)

        # Set netlink receiver buffer to 16 MBytes, to avoid packet drops
        # XXX: has to use python's. socket.fromfd() is available only in Unix
        buffersize = 1 << 22
        sock = socket.fromfd(nl_socket.get_fd(), socket.AF_NETLINK, socket.SOCK_RAW)
        sock.setsockopt(socket.SOL_SOCKET, 33, buffersize) # SO_RCVBUFFORCE

        # The two tweaks below enable reliable event delivery, packets may
        # be dropped if the netlink receiver buffer overruns. This happens...
        #
        # a) if ther kernel spams this user-space process until the receiver
        #    is filled
        #
        # or:
        #
        # b) if the user-space process does not pull message from the
        #    receiver buffer so often.
        on = struct.pack("i", 1)
        nl_socket.setsockopt(netlink.NETLINK_BROADCAST_ERROR, on)
        nl_socket.setsockopt(netlink.NETLINK_NO_ENOBUFS, on)

        buf = bytearray(mnl.MNL_SOCKET_BUFFER_SIZE)
        sending_nlh = mnl.nlmsg_put_header(buf, mnl.Nlmsg)

        # Counters are atomically zerod in each dump
        sending_nlh.nlmsg_type = (nfnl.NFNL_SUBSYS_CTNETLINK << 8) | nfnlct.IPCTNL_MSG_CT_GET_CTRZERO
        sending_nlh.nlmsg_flags = netlink.NLM_F_REQUEST|netlink.NLM_F_DUMP

        nfh = sending_nlh.put_extra_header_as(nfnl.Nfgenmsg)
        nfh.nfgen_family = socket.AF_INET
        nfh.version = nfnl.NFNETLINK_V0
        nfh.res_id = 0

        # Filter by mark: We only want to dump entries whose mark is zefo
        sending_nlh.put_u32(nfnlct.CTA_MARK, socket.htonl(0))
        sending_nlh.put_u32(nfnlct.CTA_MARK_MASK, socket.htonl(0xffffffff))

        # Every N seconds...
        # unfotunately python does not return remainded time
        signal.signal(signal.SIGALRM, alarm_handler)
        signal.setitimer(signal.ITIMER_REAL, secs, secs)

        fd = nl_socket.get_fd()
        while True:
            try:
                rlist, wlist, xlist = select.select([fd], [], [])
            except select.error as e:
                if e[0] == errno.EINTR: continue
                raise

            # Handled event and periodic atomic-dump-and-reset messages
            if fd in rlist:
                if handle(nl_socket) < 0:
                    return -1