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