def main(): """Main function called upon script execution.""" # First open a socket to the kernel. Same one used for sending and receiving. sk = nl_socket_alloc() # Creates an `nl_sock` instance. ret = nl_connect(sk, NETLINK_ROUTE) # Create file descriptor and bind socket. if ret < 0: reason = errmsg[abs(ret)] return error('nl_connect() returned {0} ({1})'.format(ret, reason)) # Next we send the request to the kernel. rt_hdr = rtgenmsg(rtgen_family=socket.AF_PACKET) ret = nl_send_simple(sk, RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP, rt_hdr, rt_hdr.SIZEOF) if ret < 0: reason = errmsg[abs(ret)] return error('nl_send_simple() returned {0} ({1})'.format(ret, reason)) print('Sent {0} bytes to the kernel.'.format(ret)) # Finally we'll retrieve the kernel's answer, process it, and call any callbacks attached to the `nl_sock` instance. nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, callback, None) # Add callback to the `nl_sock` instance. ret = nl_recvmsgs_default( sk) # Get kernel's answer, and call attached callbacks. if ret < 0: reason = errmsg[abs(ret)] return error('nl_recvmsgs_default() returned {0} ({1})'.format( ret, reason))
def test_dissect(monkeypatch): r"""Diff of C code (from test_bare()) to test against. --- test_bare.c 2015-02-08 12:43:15.543135855 -0800 +++ test_dissect.c 2015-02-08 13:25:31.375715668 -0800 @@ -16,8 +16,22 @@ sk->s_local.nl_pid = 0; sk->s_seq_next = 0; - int ret = nl_send_simple(sk, RTM_GETLINK, 0, NULL, 0); + struct rtgenmsg rt_hdr = { .rtgen_family = AF_PACKET, }; + struct nl_msg *msg = nlmsg_alloc_simple(RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP); + nlmsg_append(msg, &rt_hdr, sizeof(rt_hdr), NLMSG_ALIGNTO); + nl_complete_msg(sk, msg); + struct nlmsghdr *nlh = nlmsg_hdr(msg); + printf("%d == nlh->nlmsg_len\n", nlh->nlmsg_len); + printf("%d == nlh->nlmsg_type\n", nlh->nlmsg_type); + printf("%d == nlh->nlmsg_flags\n", nlh->nlmsg_flags); + printf("%d == nlh->nlmsg_seq\n", nlh->nlmsg_seq); + printf("%d == nlh->nlmsg_pid\n", nlh->nlmsg_pid); + + struct iovec iov = { .iov_base = nlh, .iov_len = nlh->nlmsg_len }; + struct msghdr hdr = { .msg_iov = &iov, .msg_iovlen = 1, }; + + int ret = nl_sendmsg(sk, msg, &hdr); printf("Bytes: %d\n", ret); return 0; } """ monkeypatch.setattr(libnl.socket_, 'generate_local_port', lambda: 0) sk = nl_socket_alloc() nl_connect(sk, NETLINK_ROUTE) sk.socket_instance.close() sk.s_local.nl_pid = 0 sk.s_seq_next = 0 rt_hdr = rtgenmsg(rtgen_family=socket.AF_PACKET) msg = nlmsg_alloc_simple(RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP) nlmsg_append(msg, rt_hdr, rt_hdr.SIZEOF, NLMSG_ALIGNTO) nl_complete_msg(sk, msg) nlh = nlmsg_hdr(msg) assert 20 == nlh.nlmsg_len assert 18 == nlh.nlmsg_type assert 773 == nlh.nlmsg_flags assert 0 == nlh.nlmsg_seq assert 0 == nlh.nlmsg_pid assert b'FAAAABIABQMAAAAAAAAAABEAAAA=' == base64.b64encode( buffer(nlh.bytearray[:nlh.nlmsg_len])) nl_socket_free(sk)
def test_dissect(monkeypatch): r"""Diff of C code (from test_bare()) to test against. --- test_bare.c 2015-02-08 12:43:15.543135855 -0800 +++ test_dissect.c 2015-02-08 13:25:31.375715668 -0800 @@ -16,8 +16,22 @@ sk->s_local.nl_pid = 0; sk->s_seq_next = 0; - int ret = nl_send_simple(sk, RTM_GETLINK, 0, NULL, 0); + struct rtgenmsg rt_hdr = { .rtgen_family = AF_PACKET, }; + struct nl_msg *msg = nlmsg_alloc_simple(RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP); + nlmsg_append(msg, &rt_hdr, sizeof(rt_hdr), NLMSG_ALIGNTO); + nl_complete_msg(sk, msg); + struct nlmsghdr *nlh = nlmsg_hdr(msg); + printf("%d == nlh->nlmsg_len\n", nlh->nlmsg_len); + printf("%d == nlh->nlmsg_type\n", nlh->nlmsg_type); + printf("%d == nlh->nlmsg_flags\n", nlh->nlmsg_flags); + printf("%d == nlh->nlmsg_seq\n", nlh->nlmsg_seq); + printf("%d == nlh->nlmsg_pid\n", nlh->nlmsg_pid); + + struct iovec iov = { .iov_base = nlh, .iov_len = nlh->nlmsg_len }; + struct msghdr hdr = { .msg_iov = &iov, .msg_iovlen = 1, }; + + int ret = nl_sendmsg(sk, msg, &hdr); printf("Bytes: %d\n", ret); return 0; } """ monkeypatch.setattr(libnl.socket_, 'generate_local_port', lambda: 0) sk = nl_socket_alloc() nl_connect(sk, NETLINK_ROUTE) sk.socket_instance.close() sk.s_local.nl_pid = 0 sk.s_seq_next = 0 rt_hdr = rtgenmsg(rtgen_family=socket.AF_PACKET) msg = nlmsg_alloc_simple(RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP) nlmsg_append(msg, rt_hdr, rt_hdr.SIZEOF, NLMSG_ALIGNTO) nl_complete_msg(sk, msg) nlh = nlmsg_hdr(msg) assert 20 == nlh.nlmsg_len assert 18 == nlh.nlmsg_type assert 773 == nlh.nlmsg_flags assert 0 == nlh.nlmsg_seq assert 0 == nlh.nlmsg_pid assert b'FAAAABIABQMAAAAAAAAAABEAAAA=' == base64.b64encode(buffer(nlh.bytearray[:nlh.nlmsg_len])) nl_socket_free(sk)
def test_full(tcp_server, monkeypatch): r"""Diff of C code (from test_bare()) to test against. --- test_bare.c 2015-02-08 12:43:15.543135855 -0800 +++ test_full.c 2015-02-08 12:43:08.533183752 -0800 @@ -13,10 +13,11 @@ struct nl_sock *sk = nl_socket_alloc(); nl_connect(sk, NETLINK_ROUTE); sk->s_fd = fd; - sk->s_local.nl_pid = 0; - sk->s_seq_next = 0; + sk->s_local.nl_pid = 1234; + sk->s_seq_next = 10; - int ret = nl_send_simple(sk, RTM_GETLINK, 0, NULL, 0); + struct rtgenmsg rt_hdr = { .rtgen_family = AF_PACKET, }; + int ret = nl_send_simple(sk, RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP, &rt_hdr, sizeof(rt_hdr)); printf("Bytes: %d\n", ret); return 0; """ monkeypatch.setattr(libnl.socket_, 'generate_local_port', lambda: 1234) sk = nl_socket_alloc() nl_connect(sk, NETLINK_ROUTE) sk.socket_instance.close() sk.socket_instance = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sk.socket_instance.connect(tcp_server.server.server_address) sk.s_local.nl_pid = 1234 sk.s_seq_next = 10 rt_hdr = rtgenmsg(rtgen_family=socket.AF_PACKET) assert 20 == nl_send_simple(sk, RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP, rt_hdr, rt_hdr.SIZEOF) assert 1 == len(tcp_server.data) assert b'FAAAABIABQMKAAAA0gQAABEAAAA=' == base64.b64encode( buffer(tcp_server.data[0])) nl_socket_free(sk)
def main(): """Main function called upon script execution.""" # First open a socket to the kernel. Same one used for sending and receiving. sk = nl_socket_alloc() # Creates an `nl_sock` instance. ret = nl_connect(sk, NETLINK_ROUTE) # Create file descriptor and bind socket. if ret < 0: reason = errmsg[abs(ret)] return error('nl_connect() returned {0} ({1})'.format(ret, reason)) # Next we send the request to the kernel. rt_hdr = rtgenmsg(rtgen_family=socket.AF_PACKET) ret = nl_send_simple(sk, RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP, rt_hdr, rt_hdr.SIZEOF) if ret < 0: reason = errmsg[abs(ret)] return error('nl_send_simple() returned {0} ({1})'.format(ret, reason)) print('Sent {0} bytes to the kernel.'.format(ret)) # Finally we'll retrieve the kernel's answer, process it, and call any callbacks attached to the `nl_sock` instance. nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, callback, None) # Add callback to the `nl_sock` instance. ret = nl_recvmsgs_default(sk) # Get kernel's answer, and call attached callbacks. if ret < 0: reason = errmsg[abs(ret)] return error('nl_recvmsgs_default() returned {0} ({1})'.format(ret, reason))
def test_full(tcp_server, monkeypatch): r"""Diff of C code (from test_bare()) to test against. --- test_bare.c 2015-02-08 12:43:15.543135855 -0800 +++ test_full.c 2015-02-08 12:43:08.533183752 -0800 @@ -13,10 +13,11 @@ struct nl_sock *sk = nl_socket_alloc(); nl_connect(sk, NETLINK_ROUTE); sk->s_fd = fd; - sk->s_local.nl_pid = 0; - sk->s_seq_next = 0; + sk->s_local.nl_pid = 1234; + sk->s_seq_next = 10; - int ret = nl_send_simple(sk, RTM_GETLINK, 0, NULL, 0); + struct rtgenmsg rt_hdr = { .rtgen_family = AF_PACKET, }; + int ret = nl_send_simple(sk, RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP, &rt_hdr, sizeof(rt_hdr)); printf("Bytes: %d\n", ret); return 0; """ monkeypatch.setattr(libnl.socket_, 'generate_local_port', lambda: 1234) sk = nl_socket_alloc() nl_connect(sk, NETLINK_ROUTE) sk.socket_instance.close() sk.socket_instance = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sk.socket_instance.connect(tcp_server.server.server_address) sk.s_local.nl_pid = 1234 sk.s_seq_next = 10 rt_hdr = rtgenmsg(rtgen_family=socket.AF_PACKET) assert 20 == nl_send_simple(sk, RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP, rt_hdr, rt_hdr.SIZEOF) assert 1 == len(tcp_server.data) assert b'FAAAABIABQMKAAAA0gQAABEAAAA=' == base64.b64encode(buffer(tcp_server.data[0])) nl_socket_free(sk)
def test_list_interfaces(ifacesi): r"""C code to test against. // gcc a.c $(pkg-config --cflags --libs libnl-genl-3.0) && ./a.out #include <netlink/msg.h> static int callback(struct nl_msg *msg, void *arg) { struct nlmsghdr *nlh = nlmsg_hdr(msg); struct ifinfomsg *iface = NLMSG_DATA(nlh); struct rtattr *hdr = IFLA_RTA(iface); int remaining = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*iface)); while (RTA_OK(hdr, remaining)) { if (hdr->rta_type == IFLA_IFNAME) { printf("Found network interface %d: %s\n", iface->ifi_index, (char *) RTA_DATA(hdr)); } hdr = RTA_NEXT(hdr, remaining); } return NL_OK; } int main() { // Send data to the kernel. struct nl_sock *sk = nl_socket_alloc(); printf("%d == nl_connect(sk, NETLINK_ROUTE)\n", nl_connect(sk, NETLINK_ROUTE)); struct rtgenmsg rt_hdr = { .rtgen_family = AF_PACKET, }; int ret = nl_send_simple(sk, RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP, &rt_hdr, sizeof(rt_hdr)); printf("Bytes Sent: %d\n", ret); // Retrieve kernel's response. nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, callback, NULL); printf("%d == nl_recvmsgs_default(sk)\n", nl_recvmsgs_default(sk)); nl_socket_free(sk); return 0; } // Expected output: // 0 == nl_connect(sk, NETLINK_ROUTE) // Bytes Sent: 20 // Found network interface 1: lo // Found network interface 2: eth0 // Found network interface 4: wlan0 // 0 == nl_recvmsgs_default(sk) """ got_something = dict() def callback(msg, arg): nlh = nlmsg_hdr(msg) iface = ifinfomsg(nlmsg_data(nlh)) hdr = IFLA_RTA(iface) remaining = c_int(nlh.nlmsg_len - NLMSG_LENGTH(iface.SIZEOF)) while RTA_OK(hdr, remaining): if hdr.rta_type == IFLA_IFNAME: arg[int(iface.ifi_index)] = str(get_string(RTA_DATA(hdr)).decode('ascii')) hdr = RTA_NEXT(hdr, remaining) return NL_OK sk = nl_socket_alloc() nl_connect(sk, NETLINK_ROUTE) rt_hdr = rtgenmsg(rtgen_family=socket.AF_PACKET) assert 20 == nl_send_simple(sk, RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP, rt_hdr, rt_hdr.SIZEOF) assert 0 == nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, callback, got_something) assert 0 == nl_recvmsgs_default(sk) assert dict(ifacesi) == got_something nl_socket_free(sk)
def test_nl_socket_modify_cb_error_verbose(log): r"""C code to test against. // gcc a.c $(pkg-config --cflags --libs libnl-genl-3.0) && NLDBG=4 NLCB=verbose ./a.out #include <netlink/msg.h> static int callback(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) { int *ret = arg; *ret = err->error; printf("Got something.\n"); return NL_STOP; } int main() { // Send data to the kernel. struct nl_sock *sk = nl_socket_alloc(); printf("%d == nl_connect(sk, NETLINK_ROUTE)\n", nl_connect(sk, NETLINK_ROUTE)); struct rtgenmsg rt_hdr = { .rtgen_family = AF_PACKET, }; int ret = nl_send_simple(sk, RTM_GETLINK, 0, &rt_hdr, sizeof(rt_hdr)); printf("Bytes Sent: %d\n", ret); // Retrieve kernel's response. int err = 0; nl_socket_modify_err_cb(sk, NL_CB_CUSTOM, callback, &err); printf("%d == err\n", err); printf("%d == nl_recvmsgs_default(sk)\n", nl_recvmsgs_default(sk)); printf("%d == err\n", err); nl_socket_free(sk); return 0; } // Expected output (trimmed): // nl_cache_mngt_register: Registered cache operations genl/family // 0 == nl_connect(sk, NETLINK_ROUTE) // __nlmsg_alloc: msg 0x124e0b8: Allocated new message, maxlen=4096 // nlmsg_alloc_simple: msg 0x124e0b8: Allocated new simple message // nlmsg_reserve: msg 0x124e0b8: Reserved 4 (1) bytes, pad=4, nlmsg_len=20 // nlmsg_append: msg 0x124e0b8: Appended 1 bytes with padding 4 // nl_sendmsg: sent 20 bytes // nlmsg_free: Returned message reference 0x124e0b8, 0 remaining // nlmsg_free: msg 0x124e0b8: Freed // Bytes Sent: 20 // 0 == err // recvmsgs: Attempting to read from 0x124e080 // recvmsgs: recvmsgs(0x124e080): Read 40 bytes // recvmsgs: recvmsgs(0x124e080): Processing valid message... // __nlmsg_alloc: msg 0x12520c0: Allocated new message, maxlen=40 // recvmsgs: recvmsgs(0x124e080): Increased expected sequence number to 1424136270 // Got something. // nlmsg_free: Returned message reference 0x12520c0, 0 remaining // nlmsg_free: msg 0x12520c0: Freed // -7 == nl_recvmsgs_default(sk) // -22 == err // nl_cache_mngt_unregister: Unregistered cache operations genl/family """ got_something = list() def callback(_, err, arg): arg.append(err.error) return NL_STOP del log[:] sk = nl_socket_alloc() nl_connect(sk, NETLINK_ROUTE) rt_hdr = rtgenmsg(rtgen_family=socket.AF_PACKET) assert 20 == nl_send_simple(sk, RTM_GETLINK, 0, rt_hdr, rt_hdr.SIZEOF) assert match('nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=4096', log, True) assert match('nlmsg_alloc_simple: msg 0x[a-f0-9]+: Allocated new simple message', log, True) assert match('nlmsg_reserve: msg 0x[a-f0-9]+: Reserved 4 \(1\) bytes, pad=4, nlmsg_len=20', log, True) assert match('nlmsg_append: msg 0x[a-f0-9]+: Appended 1 bytes with padding 4', log, True) assert match('nl_sendmsg: sent 20 bytes', log) assert not log assert 0 == nl_socket_modify_err_cb(sk, NL_CB_CUSTOM, callback, got_something) assert -7 == nl_recvmsgs_default(sk) assert [-22] == got_something assert match('recvmsgs: Attempting to read from 0x[a-f0-9]+', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Read 40 bytes', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Processing valid message...', log, True) assert match('nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=40', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Increased expected sequence number to \d{4,}', log, True) nl_socket_free(sk) assert not log
def test_nl_socket_modify_cb(log, ifaces): r"""C code to test against. // gcc a.c $(pkg-config --cflags --libs libnl-genl-3.0) && NLDBG=4 ./a.out #include <netlink/msg.h> static int callback(struct nl_msg *msg, void *arg) { printf("Got something.\n"); nl_msg_dump(msg, stdout); return NL_OK; } int main() { // Send data to the kernel. struct nl_sock *sk = nl_socket_alloc(); printf("%d == nl_connect(sk, NETLINK_ROUTE)\n", nl_connect(sk, NETLINK_ROUTE)); struct rtgenmsg rt_hdr = { .rtgen_family = AF_PACKET, }; int ret = nl_send_simple(sk, RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP, &rt_hdr, sizeof(rt_hdr)); printf("Bytes Sent: %d\n", ret); // Retrieve kernel's response. nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, callback, NULL); printf("%d == nl_recvmsgs_default(sk)\n", nl_recvmsgs_default(sk)); nl_socket_free(sk); return 0; } // Expected output (trimmed): // nl_cache_mngt_register: Registered cache operations genl/family // 0 == nl_connect(sk, NETLINK_ROUTE) // __nlmsg_alloc: msg 0x1b840b8: Allocated new message, maxlen=4096 // nlmsg_alloc_simple: msg 0x1b840b8: Allocated new simple message // nlmsg_reserve: msg 0x1b840b8: Reserved 4 (1) bytes, pad=4, nlmsg_len=20 // nlmsg_append: msg 0x1b840b8: Appended 1 bytes with padding 4 // nl_sendmsg: sent 20 bytes // nlmsg_free: Returned message reference 0x1b840b8, 0 remaining // nlmsg_free: msg 0x1b840b8: Freed // Bytes Sent: 20 // recvmsgs: Attempting to read from 0x1b84080 // recvmsgs: recvmsgs(0x1b84080): Read 3364 bytes // recvmsgs: recvmsgs(0x1b84080): Processing valid message... // __nlmsg_alloc: msg 0x1b880c0: Allocated new message, maxlen=1116 // Got something. // -------------------------- BEGIN NETLINK MESSAGE --------------------------- // [NETLINK HEADER] 16 octets // .nlmsg_len = 1116 // .type = 16 <0x10> // .flags = 2 <MULTI> // .seq = 1424133909 // .port = 6192 // [PAYLOAD] 1100 octets // 00 00 04 03 01 00 00 00 49 00 01 00 00 00 00 00 ........I....... // 07 00 03 00 6c 6f 00 00 08 00 0d 00 00 00 00 00 ....lo.......... // <trimmed> // 00 00 00 00 00 00 00 00 00 00 00 00 ............ // --------------------------- END NETLINK MESSAGE --------------------------- // recvmsgs: recvmsgs(0x1b84080): Processing valid message... // nlmsg_free: Returned message reference 0x1b880c0, 0 remaining // nlmsg_free: msg 0x1b880c0: Freed // __nlmsg_alloc: msg 0x1b880c0: Allocated new message, maxlen=1124 // Got something. // -------------------------- BEGIN NETLINK MESSAGE --------------------------- // [NETLINK HEADER] 16 octets // .nlmsg_len = 1124 // .type = 16 <0x10> // .flags = 2 <MULTI> // .seq = 1424133909 // .port = 6192 // [PAYLOAD] 1108 octets // 00 00 01 00 02 00 00 00 43 10 01 00 00 00 00 00 ........C....... // 09 00 03 00 65 74 68 30 00 00 00 00 08 00 0d 00 ....eth0........ // <trimmed> // 00 00 00 00 .... // --------------------------- END NETLINK MESSAGE --------------------------- // recvmsgs: recvmsgs(0x1b84080): Processing valid message... // nlmsg_free: Returned message reference 0x1b880c0, 0 remaining // nlmsg_free: msg 0x1b880c0: Freed // __nlmsg_alloc: msg 0x1b880c0: Allocated new message, maxlen=1124 // Got something. // -------------------------- BEGIN NETLINK MESSAGE --------------------------- // [NETLINK HEADER] 16 octets // .nlmsg_len = 1124 // .type = 16 <0x10> // .flags = 2 <MULTI> // .seq = 1424133909 // .port = 6192 // [PAYLOAD] 1108 octets // 00 00 01 00 04 00 00 00 03 10 00 00 00 00 00 00 ................ // 0a 00 03 00 77 6c 61 6e 30 00 00 00 08 00 0d 00 ....wlan0....... // <trimmed> // 00 00 00 00 .... // --------------------------- END NETLINK MESSAGE --------------------------- // nlmsg_free: Returned message reference 0x1b880c0, 0 remaining // nlmsg_free: msg 0x1b880c0: Freed // recvmsgs: Attempting to read from 0x1b84080 // recvmsgs: recvmsgs(0x1b84080): Read 20 bytes // recvmsgs: recvmsgs(0x1b84080): Processing valid message... // __nlmsg_alloc: msg 0x1b880c0: Allocated new message, maxlen=20 // recvmsgs: recvmsgs(0x1b84080): Increased expected sequence number to 1424133910 // nlmsg_free: Returned message reference 0x1b880c0, 0 remaining // nlmsg_free: msg 0x1b880c0: Freed // 0 == nl_recvmsgs_default(sk) // nl_cache_mngt_unregister: Unregistered cache operations genl/family """ got_something = list() def callback(msg, arg): got_something.append(arg) nl_msg_dump(msg) return NL_OK del log[:] sk = nl_socket_alloc() nl_connect(sk, NETLINK_ROUTE) rt_hdr = rtgenmsg(rtgen_family=socket.AF_PACKET) assert 20 == nl_send_simple(sk, RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP, rt_hdr, rt_hdr.SIZEOF) assert match('nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=4096', log, True) assert match('nlmsg_alloc_simple: msg 0x[a-f0-9]+: Allocated new simple message', log, True) assert match('nlmsg_reserve: msg 0x[a-f0-9]+: Reserved 4 \(1\) bytes, pad=4, nlmsg_len=20', log, True) assert match('nlmsg_append: msg 0x[a-f0-9]+: Appended 1 bytes with padding 4', log, True) assert match('nl_sendmsg: sent 20 bytes', log) assert not log assert 0 == nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, callback, 95) assert 0 == nl_recvmsgs_default(sk) assert [95] * len(ifaces) == got_something assert match('recvmsgs: Attempting to read from 0x[a-f0-9]+', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Read \d{4,} bytes', log, True) for _ in ifaces: if 'Attempting to read' in log[0]: # Lots of network interfaces on this host. assert match('recvmsgs: Attempting to read from 0x[a-f0-9]+', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Read \d{4,} bytes', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Processing valid message...', log, True) assert match('nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=\d{3,}', log, True) assert match('nl_msg_dump: -------------------------- BEGIN NETLINK MESSAGE ---------------------------', log) assert match('nl_msg_dump: [NETLINK HEADER] 16 octets', log) assert match('print_hdr: .nlmsg_len = \d{3,}', log, True) assert match('print_hdr: .type = 16 <0x10>', log) assert match('print_hdr: .flags = 2 <MULTI>', log) assert match('print_hdr: .seq = \d{10}', log, True) assert match('print_hdr: .port = \d{3,}', log, True) assert match('print_msg: \[PAYLOAD\] \d{3,} octets', log, True) rem = log.index('nl_msg_dump: --------------------------- END NETLINK MESSAGE ---------------------------') assert 20 < rem # At least check that there were a lot of log statements skipped. log = log[rem:] assert match('nl_msg_dump: --------------------------- END NETLINK MESSAGE ---------------------------', log) assert match('recvmsgs: Attempting to read from 0x[a-f0-9]+', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Read 20 bytes', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Processing valid message...', log, True) assert match('nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=20', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Increased expected sequence number to \d{4,}', log, True) nl_socket_free(sk) assert not log
def test_multipart_verbose(log, ifaces): """Expected output (trimmed). // nl_cache_mngt_register: Registered cache operations genl/family // Begin main() // Allocated socket. // 0 == nl_connect(sk, NETLINK_ROUTE) // __nlmsg_alloc: msg 0xa180b8: Allocated new message, maxlen=4096 // nlmsg_alloc_simple: msg 0xa180b8: Allocated new simple message // nlmsg_reserve: msg 0xa180b8: Reserved 4 (1) bytes, pad=4, nlmsg_len=20 // nlmsg_append: msg 0xa180b8: Appended 1 bytes with padding 4 // nl_sendmsg: sent 20 bytes // nlmsg_free: Returned message reference 0xa180b8, 0 remaining // nlmsg_free: msg 0xa180b8: Freed // Bytes Sent: 20 // recvmsgs: Attempting to read from 0xa18080 // recvmsgs: recvmsgs(0xa18080): Read 3364 bytes // recvmsgs: recvmsgs(0xa18080): Processing valid message... // __nlmsg_alloc: msg 0xa1c0c0: Allocated new message, maxlen=1116 // -- Warning: unhandled valid message: type=0x10 length=1116 flags=<MULTI> sequence-nr=1424132449 pid=5810 // recvmsgs: recvmsgs(0xa18080): Processing valid message... // nlmsg_free: Returned message reference 0xa1c0c0, 0 remaining // nlmsg_free: msg 0xa1c0c0: Freed // __nlmsg_alloc: msg 0xa1c0c0: Allocated new message, maxlen=1124 // -- Warning: unhandled valid message: type=0x10 length=1124 flags=<MULTI> sequence-nr=1424132449 pid=5810 // recvmsgs: recvmsgs(0xa18080): Processing valid message... // nlmsg_free: Returned message reference 0xa1c0c0, 0 remaining // nlmsg_free: msg 0xa1c0c0: Freed // __nlmsg_alloc: msg 0xa1c0c0: Allocated new message, maxlen=1124 // -- Warning: unhandled valid message: type=0x10 length=1124 flags=<MULTI> sequence-nr=1424132449 pid=5810 // nlmsg_free: Returned message reference 0xa1c0c0, 0 remaining // nlmsg_free: msg 0xa1c0c0: Freed // recvmsgs: Attempting to read from 0xa18080 // recvmsgs: recvmsgs(0xa18080): Read 20 bytes // recvmsgs: recvmsgs(0xa18080): Processing valid message... // __nlmsg_alloc: msg 0xa1c0c0: Allocated new message, maxlen=20 // recvmsgs: recvmsgs(0xa18080): Increased expected sequence number to 1424132450 // nlmsg_free: Returned message reference 0xa1c0c0, 0 remaining // nlmsg_free: msg 0xa1c0c0: Freed // 0 == nl_recvmsgs_default(sk) // nl_cache_mngt_unregister: Unregistered cache operations genl/family """ del log[:] sk = nl_socket_alloc() nl_connect(sk, NETLINK_ROUTE) rt_hdr = rtgenmsg(rtgen_family=socket.AF_PACKET) assert 20 == nl_send_simple(sk, RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP, rt_hdr, rt_hdr.SIZEOF) assert match( 'nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=4096', log, True) assert match( 'nlmsg_alloc_simple: msg 0x[a-f0-9]+: Allocated new simple message', log, True) assert match( 'nlmsg_reserve: msg 0x[a-f0-9]+: Reserved 4 \(1\) bytes, pad=4, nlmsg_len=20', log, True) assert match( 'nlmsg_append: msg 0x[a-f0-9]+: Appended 1 bytes with padding 4', log, True) assert match('nl_sendmsg: sent 20 bytes', log) assert not log assert 0 == nl_recvmsgs_default(sk) assert match('recvmsgs: Attempting to read from 0x[a-f0-9]+', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Read \d{4,} bytes', log, True) for _ in ifaces: if 'Attempting to read' in log[0]: # Lots of network interfaces on this host. assert match('recvmsgs: Attempting to read from 0x[a-f0-9]+', log, True) assert match( 'recvmsgs: recvmsgs\(0x[a-f0-9]+\): Read \d{4,} bytes', log, True) assert match( 'recvmsgs: recvmsgs\(0x[a-f0-9]+\): Processing valid message...', log, True) assert match( 'nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=\d{3,}', log, True) assert match( 'nl_valid_handler_verbose: -- Warning: unhandled valid message: type=0x10 length=\d{3,} ' 'flags=<MULTI> sequence-nr=\d{10,} pid=\d{3,}', log, True) assert match('recvmsgs: Attempting to read from 0x[a-f0-9]+', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Read 20 bytes', log, True) assert match( 'recvmsgs: recvmsgs\(0x[a-f0-9]+\): Processing valid message...', log, True) assert match( 'nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=20', log, True) assert match( 'recvmsgs: recvmsgs\(0x[a-f0-9]+\): Increased expected sequence number to \d{4,}', log, True) nl_socket_free(sk) assert not log
def test_multipart(log, ifaces): r"""C code to test against. // gcc a.c $(pkg-config --cflags --libs libnl-genl-3.0) && NLDBG=4 NLCB=debug ./a.out #include <netlink/msg.h> struct nl_sock { struct sockaddr_nl s_local; struct sockaddr_nl s_peer; int s_fd; int s_proto; unsigned int s_seq_next; unsigned int s_seq_expect; int s_flags; struct nl_cb *s_cb; size_t s_bufsize; }; int main() { // Send data to the kernel. printf("Begin main()\n"); struct nl_sock *sk = nl_socket_alloc(); printf("Allocated socket.\n"); printf("%d == nl_connect(sk, NETLINK_ROUTE)\n", nl_connect(sk, NETLINK_ROUTE)); struct rtgenmsg rt_hdr = { .rtgen_family = AF_PACKET, }; int ret = nl_send_simple(sk, RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP, &rt_hdr, sizeof(rt_hdr)); printf("Bytes Sent: %d\n", ret); // Retrieve kernel's response. printf("%d == nl_recvmsgs_default(sk)\n", nl_recvmsgs_default(sk)); nl_socket_free(sk); return 0; } // Expected output (trimmed): // nl_cache_mngt_register: Registered cache operations genl/family // Begin main() // Allocated socket. // 0 == nl_connect(sk, NETLINK_ROUTE) // __nlmsg_alloc: msg 0x1bbe0b8: Allocated new message, maxlen=4096 // nlmsg_alloc_simple: msg 0x1bbe0b8: Allocated new simple message // nlmsg_reserve: msg 0x1bbe0b8: Reserved 4 (1) bytes, pad=4, nlmsg_len=20 // nlmsg_append: msg 0x1bbe0b8: Appended 1 bytes with padding 4 // -- Debug: Sent Message: // -------------------------- BEGIN NETLINK MESSAGE --------------------------- // [NETLINK HEADER] 16 octets // .nlmsg_len = 20 // .type = 18 <0x12> // .flags = 773 <REQUEST,ACK,ROOT,MATCH> // .seq = 1424053819 // .port = 18409 // [PAYLOAD] 4 octets // 11 00 00 00 .... // --------------------------- END NETLINK MESSAGE --------------------------- // nl_sendmsg: sent 20 bytes // nlmsg_free: Returned message reference 0x1bbe0b8, 0 remaining // nlmsg_free: msg 0x1bbe0b8: Freed // Bytes Sent: 20 // recvmsgs: Attempting to read from 0x1bbe080 // recvmsgs: recvmsgs(0x1bbe080): Read 3364 bytes // recvmsgs: recvmsgs(0x1bbe080): Processing valid message... // __nlmsg_alloc: msg 0x1bc20c0: Allocated new message, maxlen=1116 // -- Debug: Received Message: // -------------------------- BEGIN NETLINK MESSAGE --------------------------- // [NETLINK HEADER] 16 octets // .nlmsg_len = 1116 // .type = 16 <0x10> // .flags = 2 <MULTI> // .seq = 1424053819 // .port = 18409 // [PAYLOAD] 1100 octets // 00 00 04 03 01 00 00 00 49 00 01 00 00 00 00 00 ........I....... // <trimmed> // 00 00 00 00 00 00 00 00 00 00 00 00 ............ // --------------------------- END NETLINK MESSAGE --------------------------- // -- Debug: Unhandled Valid message: type=0x10 length=1116 flags=<MULTI> sequence-nr=1424053819 pid=18409 // recvmsgs: recvmsgs(0x1bbe080): Processing valid message... // nlmsg_free: Returned message reference 0x1bc20c0, 0 remaining // nlmsg_free: msg 0x1bc20c0: Freed // __nlmsg_alloc: msg 0x1bc20c0: Allocated new message, maxlen=1124 // -- Debug: Received Message: // -------------------------- BEGIN NETLINK MESSAGE --------------------------- // [NETLINK HEADER] 16 octets // .nlmsg_len = 1124 // .type = 16 <0x10> // .flags = 2 <MULTI> // .seq = 1424053819 // .port = 18409 // [PAYLOAD] 1108 octets // 00 00 01 00 02 00 00 00 43 10 01 00 00 00 00 00 ........C....... // <trimmed> // 00 00 00 00 .... // --------------------------- END NETLINK MESSAGE --------------------------- // -- Debug: Unhandled Valid message: type=0x10 length=1124 flags=<MULTI> sequence-nr=1424053819 pid=18409 // recvmsgs: recvmsgs(0x1bbe080): Processing valid message... // nlmsg_free: Returned message reference 0x1bc20c0, 0 remaining // nlmsg_free: msg 0x1bc20c0: Freed // __nlmsg_alloc: msg 0x1bc20c0: Allocated new message, maxlen=1124 // -- Debug: Received Message: // -------------------------- BEGIN NETLINK MESSAGE --------------------------- // [NETLINK HEADER] 16 octets // .nlmsg_len = 1124 // .type = 16 <0x10> // .flags = 2 <MULTI> // .seq = 1424053819 // .port = 18409 // [PAYLOAD] 1108 octets // 00 00 01 00 03 00 00 00 03 10 00 00 00 00 00 00 ................ // <trimmed> // 00 00 00 00 .... // --------------------------- END NETLINK MESSAGE --------------------------- // -- Debug: Unhandled Valid message: type=0x10 length=1124 flags=<MULTI> sequence-nr=1424053819 pid=18409 // nlmsg_free: Returned message reference 0x1bc20c0, 0 remaining // nlmsg_free: msg 0x1bc20c0: Freed // recvmsgs: Attempting to read from 0x1bbe080 // recvmsgs: recvmsgs(0x1bbe080): Read 20 bytes // recvmsgs: recvmsgs(0x1bbe080): Processing valid message... // __nlmsg_alloc: msg 0x1bc20c0: Allocated new message, maxlen=20 // -- Debug: Received Message: // -------------------------- BEGIN NETLINK MESSAGE --------------------------- // [NETLINK HEADER] 16 octets // .nlmsg_len = 20 // .type = 3 <DONE> // .flags = 2 <MULTI> // .seq = 1424053819 // .port = 18409 // [PAYLOAD] 4 octets // 00 00 00 00 .... // --------------------------- END NETLINK MESSAGE --------------------------- // recvmsgs: recvmsgs(0x1bbe080): Increased expected sequence number to 1424053820 // -- Debug: End of multipart message block: type=DONE length=20 flags=<MULTI> sequence-nr=1424053819 pid=18409 // nlmsg_free: Returned message reference 0x1bc20c0, 0 remaining // nlmsg_free: msg 0x1bc20c0: Freed // 0 == nl_recvmsgs_default(sk) // nl_cache_mngt_unregister: Unregistered cache operations genl/family """ del log[:] sk = nl_socket_alloc() nl_connect(sk, NETLINK_ROUTE) rt_hdr = rtgenmsg(rtgen_family=socket.AF_PACKET) assert 20 == nl_send_simple(sk, RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP, rt_hdr, rt_hdr.SIZEOF) assert match( 'nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=4096', log, True) assert match( 'nlmsg_alloc_simple: msg 0x[a-f0-9]+: Allocated new simple message', log, True) assert match( 'nlmsg_reserve: msg 0x[a-f0-9]+: Reserved 4 \(1\) bytes, pad=4, nlmsg_len=20', log, True) assert match( 'nlmsg_append: msg 0x[a-f0-9]+: Appended 1 bytes with padding 4', log, True) assert match('nl_msg_out_handler_debug: -- Debug: Sent Message:', log) assert match( 'nl_msg_dump: -------------------------- BEGIN NETLINK MESSAGE ---------------------------', log) assert match('nl_msg_dump: [NETLINK HEADER] 16 octets', log) assert match('print_hdr: .nlmsg_len = 20', log) assert match('print_hdr: .type = 18 <0x12>', log) assert match('print_hdr: .flags = 773 <REQUEST,ACK,ROOT,MATCH>', log) assert match('print_hdr: .seq = \d{10}', log, True) assert match('print_hdr: .port = \d{3,}', log, True) assert match('print_msg: [PAYLOAD] 4 octets', log) assert match( 'dump_hex: 11 00 00 00 ....', log) assert match( 'nl_msg_dump: --------------------------- END NETLINK MESSAGE ---------------------------', log) assert match('nl_sendmsg: sent 20 bytes', log) assert not log assert 0 == nl_recvmsgs_default(sk) assert match('recvmsgs: Attempting to read from 0x[a-f0-9]+', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Read \d{4,} bytes', log, True) assert match( 'recvmsgs: recvmsgs\(0x[a-f0-9]+\): Processing valid message...', log, True) assert match( 'nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=\d{3,}', log, True) assert match('nl_msg_in_handler_debug: -- Debug: Received Message:', log) assert match( 'nl_msg_dump: -------------------------- BEGIN NETLINK MESSAGE ---------------------------', log) assert match('nl_msg_dump: [NETLINK HEADER] 16 octets', log) assert match('print_hdr: .nlmsg_len = \d{3,}', log, True) assert match('print_hdr: .type = 16 <0x10>', log) assert match('print_hdr: .flags = 2 <MULTI>', log) assert match('print_hdr: .seq = \d{10}', log, True) assert match('print_hdr: .port = \d{3,}', log, True) assert match('print_msg: \[PAYLOAD\] \d{3,} octets', log, True) assert match( 'dump_hex: 00 00 04 03 01 00 00 00 49 00 01 00 00 00 00 00 ........I.......', log) assert match( 'dump_hex: 07 00 03 00 6c 6f 00 00 08 00 0d 00 00 00 00 00 ....lo..........', log) assert match( 'dump_hex: 05 00 10 00 00 00 00 00 05 00 11 00 00 00 00 00 ................', log) for _ in ifaces: # Done testing this payload. Differs too much between Travis and Raspbian, and probably others. rem = log.index( 'nl_msg_dump: --------------------------- END NETLINK MESSAGE ---------------------------' ) assert 20 < rem # At least check that there were a lot of log statements skipped. log = log[rem:] assert match( 'nl_msg_dump: --------------------------- END NETLINK MESSAGE ---------------------------', log) assert match( 'nl_valid_handler_debug: -- Debug: Unhandled Valid message: type=0x10 length=\d{3,} flags=<MULTI> ' 'sequence-nr=\d{10,} pid=\d{3,}', log, True) assert match('recvmsgs: Attempting to read from 0x[a-f0-9]+', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Read 20 bytes', log, True) assert match( 'recvmsgs: recvmsgs\(0x[a-f0-9]+\): Processing valid message...', log, True) assert match( 'nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=20', log, True) assert match('nl_msg_in_handler_debug: -- Debug: Received Message:', log) assert match( 'nl_msg_dump: -------------------------- BEGIN NETLINK MESSAGE ---------------------------', log) assert match('nl_msg_dump: [NETLINK HEADER] 16 octets', log) assert match('print_hdr: .nlmsg_len = 20', log) assert match('print_hdr: .type = 3 <DONE>', log) assert match('print_hdr: .flags = 2 <MULTI>', log) assert match('print_hdr: .seq = \d{10}', log, True) assert match('print_hdr: .port = \d{3,}', log, True) assert match('print_msg: [PAYLOAD] 4 octets', log) assert match( 'dump_hex: 00 00 00 00 ....', log) assert match( 'nl_msg_dump: --------------------------- END NETLINK MESSAGE ---------------------------', log) assert match( 'recvmsgs: recvmsgs\(0x[a-f0-9]+\): Increased expected sequence number to \d{4,}', log, True) assert match( 'nl_finish_handler_debug: -- Debug: End of multipart message block: type=DONE length=20 flags=<MULTI> ' 'sequence-nr=\d{10,} pid=\d{3,}', log, True) nl_socket_free(sk) assert not log
def test_nl_socket_modify_cb_error_verbose(log): r"""C code to test against. // gcc a.c $(pkg-config --cflags --libs libnl-genl-3.0) && NLDBG=4 NLCB=verbose ./a.out #include <netlink/msg.h> static int callback(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) { int *ret = arg; *ret = err->error; printf("Got something.\n"); return NL_STOP; } int main() { // Send data to the kernel. struct nl_sock *sk = nl_socket_alloc(); printf("%d == nl_connect(sk, NETLINK_ROUTE)\n", nl_connect(sk, NETLINK_ROUTE)); struct rtgenmsg rt_hdr = { .rtgen_family = AF_PACKET, }; int ret = nl_send_simple(sk, RTM_GETLINK, 0, &rt_hdr, sizeof(rt_hdr)); printf("Bytes Sent: %d\n", ret); // Retrieve kernel's response. int err = 0; nl_socket_modify_err_cb(sk, NL_CB_CUSTOM, callback, &err); printf("%d == err\n", err); printf("%d == nl_recvmsgs_default(sk)\n", nl_recvmsgs_default(sk)); printf("%d == err\n", err); nl_socket_free(sk); return 0; } // Expected output (trimmed): // nl_cache_mngt_register: Registered cache operations genl/family // 0 == nl_connect(sk, NETLINK_ROUTE) // __nlmsg_alloc: msg 0x124e0b8: Allocated new message, maxlen=4096 // nlmsg_alloc_simple: msg 0x124e0b8: Allocated new simple message // nlmsg_reserve: msg 0x124e0b8: Reserved 4 (1) bytes, pad=4, nlmsg_len=20 // nlmsg_append: msg 0x124e0b8: Appended 1 bytes with padding 4 // nl_sendmsg: sent 20 bytes // nlmsg_free: Returned message reference 0x124e0b8, 0 remaining // nlmsg_free: msg 0x124e0b8: Freed // Bytes Sent: 20 // 0 == err // recvmsgs: Attempting to read from 0x124e080 // recvmsgs: recvmsgs(0x124e080): Read 40 bytes // recvmsgs: recvmsgs(0x124e080): Processing valid message... // __nlmsg_alloc: msg 0x12520c0: Allocated new message, maxlen=40 // recvmsgs: recvmsgs(0x124e080): Increased expected sequence number to 1424136270 // Got something. // nlmsg_free: Returned message reference 0x12520c0, 0 remaining // nlmsg_free: msg 0x12520c0: Freed // -7 == nl_recvmsgs_default(sk) // -22 == err // nl_cache_mngt_unregister: Unregistered cache operations genl/family """ got_something = list() def callback(_, err, arg): arg.append(err.error) return NL_STOP del log[:] sk = nl_socket_alloc() nl_connect(sk, NETLINK_ROUTE) rt_hdr = rtgenmsg(rtgen_family=socket.AF_PACKET) assert 20 == nl_send_simple(sk, RTM_GETLINK, 0, rt_hdr, rt_hdr.SIZEOF) assert match( 'nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=4096', log, True) assert match( 'nlmsg_alloc_simple: msg 0x[a-f0-9]+: Allocated new simple message', log, True) assert match( 'nlmsg_reserve: msg 0x[a-f0-9]+: Reserved 4 \(1\) bytes, pad=4, nlmsg_len=20', log, True) assert match( 'nlmsg_append: msg 0x[a-f0-9]+: Appended 1 bytes with padding 4', log, True) assert match('nl_sendmsg: sent 20 bytes', log) assert not log assert 0 == nl_socket_modify_err_cb(sk, NL_CB_CUSTOM, callback, got_something) assert -7 == nl_recvmsgs_default(sk) assert [-22] == got_something assert match('recvmsgs: Attempting to read from 0x[a-f0-9]+', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Read 40 bytes', log, True) assert match( 'recvmsgs: recvmsgs\(0x[a-f0-9]+\): Processing valid message...', log, True) assert match( 'nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=40', log, True) assert match( 'recvmsgs: recvmsgs\(0x[a-f0-9]+\): Increased expected sequence number to \d{4,}', log, True) nl_socket_free(sk) assert not log
def test_nl_socket_modify_cb(log, ifaces): r"""C code to test against. // gcc a.c $(pkg-config --cflags --libs libnl-genl-3.0) && NLDBG=4 ./a.out #include <netlink/msg.h> static int callback(struct nl_msg *msg, void *arg) { printf("Got something.\n"); nl_msg_dump(msg, stdout); return NL_OK; } int main() { // Send data to the kernel. struct nl_sock *sk = nl_socket_alloc(); printf("%d == nl_connect(sk, NETLINK_ROUTE)\n", nl_connect(sk, NETLINK_ROUTE)); struct rtgenmsg rt_hdr = { .rtgen_family = AF_PACKET, }; int ret = nl_send_simple(sk, RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP, &rt_hdr, sizeof(rt_hdr)); printf("Bytes Sent: %d\n", ret); // Retrieve kernel's response. nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, callback, NULL); printf("%d == nl_recvmsgs_default(sk)\n", nl_recvmsgs_default(sk)); nl_socket_free(sk); return 0; } // Expected output (trimmed): // nl_cache_mngt_register: Registered cache operations genl/family // 0 == nl_connect(sk, NETLINK_ROUTE) // __nlmsg_alloc: msg 0x1b840b8: Allocated new message, maxlen=4096 // nlmsg_alloc_simple: msg 0x1b840b8: Allocated new simple message // nlmsg_reserve: msg 0x1b840b8: Reserved 4 (1) bytes, pad=4, nlmsg_len=20 // nlmsg_append: msg 0x1b840b8: Appended 1 bytes with padding 4 // nl_sendmsg: sent 20 bytes // nlmsg_free: Returned message reference 0x1b840b8, 0 remaining // nlmsg_free: msg 0x1b840b8: Freed // Bytes Sent: 20 // recvmsgs: Attempting to read from 0x1b84080 // recvmsgs: recvmsgs(0x1b84080): Read 3364 bytes // recvmsgs: recvmsgs(0x1b84080): Processing valid message... // __nlmsg_alloc: msg 0x1b880c0: Allocated new message, maxlen=1116 // Got something. // -------------------------- BEGIN NETLINK MESSAGE --------------------------- // [NETLINK HEADER] 16 octets // .nlmsg_len = 1116 // .type = 16 <0x10> // .flags = 2 <MULTI> // .seq = 1424133909 // .port = 6192 // [PAYLOAD] 1100 octets // 00 00 04 03 01 00 00 00 49 00 01 00 00 00 00 00 ........I....... // 07 00 03 00 6c 6f 00 00 08 00 0d 00 00 00 00 00 ....lo.......... // <trimmed> // 00 00 00 00 00 00 00 00 00 00 00 00 ............ // --------------------------- END NETLINK MESSAGE --------------------------- // recvmsgs: recvmsgs(0x1b84080): Processing valid message... // nlmsg_free: Returned message reference 0x1b880c0, 0 remaining // nlmsg_free: msg 0x1b880c0: Freed // __nlmsg_alloc: msg 0x1b880c0: Allocated new message, maxlen=1124 // Got something. // -------------------------- BEGIN NETLINK MESSAGE --------------------------- // [NETLINK HEADER] 16 octets // .nlmsg_len = 1124 // .type = 16 <0x10> // .flags = 2 <MULTI> // .seq = 1424133909 // .port = 6192 // [PAYLOAD] 1108 octets // 00 00 01 00 02 00 00 00 43 10 01 00 00 00 00 00 ........C....... // 09 00 03 00 65 74 68 30 00 00 00 00 08 00 0d 00 ....eth0........ // <trimmed> // 00 00 00 00 .... // --------------------------- END NETLINK MESSAGE --------------------------- // recvmsgs: recvmsgs(0x1b84080): Processing valid message... // nlmsg_free: Returned message reference 0x1b880c0, 0 remaining // nlmsg_free: msg 0x1b880c0: Freed // __nlmsg_alloc: msg 0x1b880c0: Allocated new message, maxlen=1124 // Got something. // -------------------------- BEGIN NETLINK MESSAGE --------------------------- // [NETLINK HEADER] 16 octets // .nlmsg_len = 1124 // .type = 16 <0x10> // .flags = 2 <MULTI> // .seq = 1424133909 // .port = 6192 // [PAYLOAD] 1108 octets // 00 00 01 00 04 00 00 00 03 10 00 00 00 00 00 00 ................ // 0a 00 03 00 77 6c 61 6e 30 00 00 00 08 00 0d 00 ....wlan0....... // <trimmed> // 00 00 00 00 .... // --------------------------- END NETLINK MESSAGE --------------------------- // nlmsg_free: Returned message reference 0x1b880c0, 0 remaining // nlmsg_free: msg 0x1b880c0: Freed // recvmsgs: Attempting to read from 0x1b84080 // recvmsgs: recvmsgs(0x1b84080): Read 20 bytes // recvmsgs: recvmsgs(0x1b84080): Processing valid message... // __nlmsg_alloc: msg 0x1b880c0: Allocated new message, maxlen=20 // recvmsgs: recvmsgs(0x1b84080): Increased expected sequence number to 1424133910 // nlmsg_free: Returned message reference 0x1b880c0, 0 remaining // nlmsg_free: msg 0x1b880c0: Freed // 0 == nl_recvmsgs_default(sk) // nl_cache_mngt_unregister: Unregistered cache operations genl/family """ got_something = list() def callback(msg, arg): got_something.append(arg) nl_msg_dump(msg) return NL_OK del log[:] sk = nl_socket_alloc() nl_connect(sk, NETLINK_ROUTE) rt_hdr = rtgenmsg(rtgen_family=socket.AF_PACKET) assert 20 == nl_send_simple(sk, RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP, rt_hdr, rt_hdr.SIZEOF) assert match( 'nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=4096', log, True) assert match( 'nlmsg_alloc_simple: msg 0x[a-f0-9]+: Allocated new simple message', log, True) assert match( 'nlmsg_reserve: msg 0x[a-f0-9]+: Reserved 4 \(1\) bytes, pad=4, nlmsg_len=20', log, True) assert match( 'nlmsg_append: msg 0x[a-f0-9]+: Appended 1 bytes with padding 4', log, True) assert match('nl_sendmsg: sent 20 bytes', log) assert not log assert 0 == nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, callback, 95) assert 0 == nl_recvmsgs_default(sk) assert [95] * len(ifaces) == got_something assert match('recvmsgs: Attempting to read from 0x[a-f0-9]+', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Read \d{4,} bytes', log, True) for _ in ifaces: if 'Attempting to read' in log[0]: # Lots of network interfaces on this host. assert match('recvmsgs: Attempting to read from 0x[a-f0-9]+', log, True) assert match( 'recvmsgs: recvmsgs\(0x[a-f0-9]+\): Read \d{4,} bytes', log, True) assert match( 'recvmsgs: recvmsgs\(0x[a-f0-9]+\): Processing valid message...', log, True) assert match( 'nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=\d{3,}', log, True) assert match( 'nl_msg_dump: -------------------------- BEGIN NETLINK MESSAGE ---------------------------', log) assert match('nl_msg_dump: [NETLINK HEADER] 16 octets', log) assert match('print_hdr: .nlmsg_len = \d{3,}', log, True) assert match('print_hdr: .type = 16 <0x10>', log) assert match('print_hdr: .flags = 2 <MULTI>', log) assert match('print_hdr: .seq = \d{10}', log, True) assert match('print_hdr: .port = \d{3,}', log, True) assert match('print_msg: \[PAYLOAD\] \d{3,} octets', log, True) rem = log.index( 'nl_msg_dump: --------------------------- END NETLINK MESSAGE ---------------------------' ) assert 20 < rem # At least check that there were a lot of log statements skipped. log = log[rem:] assert match( 'nl_msg_dump: --------------------------- END NETLINK MESSAGE ---------------------------', log) assert match('recvmsgs: Attempting to read from 0x[a-f0-9]+', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Read 20 bytes', log, True) assert match( 'recvmsgs: recvmsgs\(0x[a-f0-9]+\): Processing valid message...', log, True) assert match( 'nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=20', log, True) assert match( 'recvmsgs: recvmsgs\(0x[a-f0-9]+\): Increased expected sequence number to \d{4,}', log, True) nl_socket_free(sk) assert not log
def test_multipart_verbose(log, ifaces): """Expected output (trimmed). // nl_cache_mngt_register: Registered cache operations genl/family // Begin main() // Allocated socket. // 0 == nl_connect(sk, NETLINK_ROUTE) // __nlmsg_alloc: msg 0xa180b8: Allocated new message, maxlen=4096 // nlmsg_alloc_simple: msg 0xa180b8: Allocated new simple message // nlmsg_reserve: msg 0xa180b8: Reserved 4 (1) bytes, pad=4, nlmsg_len=20 // nlmsg_append: msg 0xa180b8: Appended 1 bytes with padding 4 // nl_sendmsg: sent 20 bytes // nlmsg_free: Returned message reference 0xa180b8, 0 remaining // nlmsg_free: msg 0xa180b8: Freed // Bytes Sent: 20 // recvmsgs: Attempting to read from 0xa18080 // recvmsgs: recvmsgs(0xa18080): Read 3364 bytes // recvmsgs: recvmsgs(0xa18080): Processing valid message... // __nlmsg_alloc: msg 0xa1c0c0: Allocated new message, maxlen=1116 // -- Warning: unhandled valid message: type=0x10 length=1116 flags=<MULTI> sequence-nr=1424132449 pid=5810 // recvmsgs: recvmsgs(0xa18080): Processing valid message... // nlmsg_free: Returned message reference 0xa1c0c0, 0 remaining // nlmsg_free: msg 0xa1c0c0: Freed // __nlmsg_alloc: msg 0xa1c0c0: Allocated new message, maxlen=1124 // -- Warning: unhandled valid message: type=0x10 length=1124 flags=<MULTI> sequence-nr=1424132449 pid=5810 // recvmsgs: recvmsgs(0xa18080): Processing valid message... // nlmsg_free: Returned message reference 0xa1c0c0, 0 remaining // nlmsg_free: msg 0xa1c0c0: Freed // __nlmsg_alloc: msg 0xa1c0c0: Allocated new message, maxlen=1124 // -- Warning: unhandled valid message: type=0x10 length=1124 flags=<MULTI> sequence-nr=1424132449 pid=5810 // nlmsg_free: Returned message reference 0xa1c0c0, 0 remaining // nlmsg_free: msg 0xa1c0c0: Freed // recvmsgs: Attempting to read from 0xa18080 // recvmsgs: recvmsgs(0xa18080): Read 20 bytes // recvmsgs: recvmsgs(0xa18080): Processing valid message... // __nlmsg_alloc: msg 0xa1c0c0: Allocated new message, maxlen=20 // recvmsgs: recvmsgs(0xa18080): Increased expected sequence number to 1424132450 // nlmsg_free: Returned message reference 0xa1c0c0, 0 remaining // nlmsg_free: msg 0xa1c0c0: Freed // 0 == nl_recvmsgs_default(sk) // nl_cache_mngt_unregister: Unregistered cache operations genl/family """ del log[:] sk = nl_socket_alloc() nl_connect(sk, NETLINK_ROUTE) rt_hdr = rtgenmsg(rtgen_family=socket.AF_PACKET) assert 20 == nl_send_simple(sk, RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP, rt_hdr, rt_hdr.SIZEOF) assert match('nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=4096', log, True) assert match('nlmsg_alloc_simple: msg 0x[a-f0-9]+: Allocated new simple message', log, True) assert match('nlmsg_reserve: msg 0x[a-f0-9]+: Reserved 4 \(1\) bytes, pad=4, nlmsg_len=20', log, True) assert match('nlmsg_append: msg 0x[a-f0-9]+: Appended 1 bytes with padding 4', log, True) assert match('nl_sendmsg: sent 20 bytes', log) assert not log assert 0 == nl_recvmsgs_default(sk) assert match('recvmsgs: Attempting to read from 0x[a-f0-9]+', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Read \d{4,} bytes', log, True) for _ in ifaces: if 'Attempting to read' in log[0]: # Lots of network interfaces on this host. assert match('recvmsgs: Attempting to read from 0x[a-f0-9]+', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Read \d{4,} bytes', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Processing valid message...', log, True) assert match('nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=\d{3,}', log, True) assert match('nl_valid_handler_verbose: -- Warning: unhandled valid message: type=0x10 length=\d{3,} ' 'flags=<MULTI> sequence-nr=\d{10,} pid=\d{3,}', log, True) assert match('recvmsgs: Attempting to read from 0x[a-f0-9]+', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Read 20 bytes', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Processing valid message...', log, True) assert match('nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=20', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Increased expected sequence number to \d{4,}', log, True) nl_socket_free(sk) assert not log
def test_multipart(log, ifaces): r"""C code to test against. // gcc a.c $(pkg-config --cflags --libs libnl-genl-3.0) && NLDBG=4 NLCB=debug ./a.out #include <netlink/msg.h> struct nl_sock { struct sockaddr_nl s_local; struct sockaddr_nl s_peer; int s_fd; int s_proto; unsigned int s_seq_next; unsigned int s_seq_expect; int s_flags; struct nl_cb *s_cb; size_t s_bufsize; }; int main() { // Send data to the kernel. printf("Begin main()\n"); struct nl_sock *sk = nl_socket_alloc(); printf("Allocated socket.\n"); printf("%d == nl_connect(sk, NETLINK_ROUTE)\n", nl_connect(sk, NETLINK_ROUTE)); struct rtgenmsg rt_hdr = { .rtgen_family = AF_PACKET, }; int ret = nl_send_simple(sk, RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP, &rt_hdr, sizeof(rt_hdr)); printf("Bytes Sent: %d\n", ret); // Retrieve kernel's response. printf("%d == nl_recvmsgs_default(sk)\n", nl_recvmsgs_default(sk)); nl_socket_free(sk); return 0; } // Expected output (trimmed): // nl_cache_mngt_register: Registered cache operations genl/family // Begin main() // Allocated socket. // 0 == nl_connect(sk, NETLINK_ROUTE) // __nlmsg_alloc: msg 0x1bbe0b8: Allocated new message, maxlen=4096 // nlmsg_alloc_simple: msg 0x1bbe0b8: Allocated new simple message // nlmsg_reserve: msg 0x1bbe0b8: Reserved 4 (1) bytes, pad=4, nlmsg_len=20 // nlmsg_append: msg 0x1bbe0b8: Appended 1 bytes with padding 4 // -- Debug: Sent Message: // -------------------------- BEGIN NETLINK MESSAGE --------------------------- // [NETLINK HEADER] 16 octets // .nlmsg_len = 20 // .type = 18 <0x12> // .flags = 773 <REQUEST,ACK,ROOT,MATCH> // .seq = 1424053819 // .port = 18409 // [PAYLOAD] 4 octets // 11 00 00 00 .... // --------------------------- END NETLINK MESSAGE --------------------------- // nl_sendmsg: sent 20 bytes // nlmsg_free: Returned message reference 0x1bbe0b8, 0 remaining // nlmsg_free: msg 0x1bbe0b8: Freed // Bytes Sent: 20 // recvmsgs: Attempting to read from 0x1bbe080 // recvmsgs: recvmsgs(0x1bbe080): Read 3364 bytes // recvmsgs: recvmsgs(0x1bbe080): Processing valid message... // __nlmsg_alloc: msg 0x1bc20c0: Allocated new message, maxlen=1116 // -- Debug: Received Message: // -------------------------- BEGIN NETLINK MESSAGE --------------------------- // [NETLINK HEADER] 16 octets // .nlmsg_len = 1116 // .type = 16 <0x10> // .flags = 2 <MULTI> // .seq = 1424053819 // .port = 18409 // [PAYLOAD] 1100 octets // 00 00 04 03 01 00 00 00 49 00 01 00 00 00 00 00 ........I....... // <trimmed> // 00 00 00 00 00 00 00 00 00 00 00 00 ............ // --------------------------- END NETLINK MESSAGE --------------------------- // -- Debug: Unhandled Valid message: type=0x10 length=1116 flags=<MULTI> sequence-nr=1424053819 pid=18409 // recvmsgs: recvmsgs(0x1bbe080): Processing valid message... // nlmsg_free: Returned message reference 0x1bc20c0, 0 remaining // nlmsg_free: msg 0x1bc20c0: Freed // __nlmsg_alloc: msg 0x1bc20c0: Allocated new message, maxlen=1124 // -- Debug: Received Message: // -------------------------- BEGIN NETLINK MESSAGE --------------------------- // [NETLINK HEADER] 16 octets // .nlmsg_len = 1124 // .type = 16 <0x10> // .flags = 2 <MULTI> // .seq = 1424053819 // .port = 18409 // [PAYLOAD] 1108 octets // 00 00 01 00 02 00 00 00 43 10 01 00 00 00 00 00 ........C....... // <trimmed> // 00 00 00 00 .... // --------------------------- END NETLINK MESSAGE --------------------------- // -- Debug: Unhandled Valid message: type=0x10 length=1124 flags=<MULTI> sequence-nr=1424053819 pid=18409 // recvmsgs: recvmsgs(0x1bbe080): Processing valid message... // nlmsg_free: Returned message reference 0x1bc20c0, 0 remaining // nlmsg_free: msg 0x1bc20c0: Freed // __nlmsg_alloc: msg 0x1bc20c0: Allocated new message, maxlen=1124 // -- Debug: Received Message: // -------------------------- BEGIN NETLINK MESSAGE --------------------------- // [NETLINK HEADER] 16 octets // .nlmsg_len = 1124 // .type = 16 <0x10> // .flags = 2 <MULTI> // .seq = 1424053819 // .port = 18409 // [PAYLOAD] 1108 octets // 00 00 01 00 03 00 00 00 03 10 00 00 00 00 00 00 ................ // <trimmed> // 00 00 00 00 .... // --------------------------- END NETLINK MESSAGE --------------------------- // -- Debug: Unhandled Valid message: type=0x10 length=1124 flags=<MULTI> sequence-nr=1424053819 pid=18409 // nlmsg_free: Returned message reference 0x1bc20c0, 0 remaining // nlmsg_free: msg 0x1bc20c0: Freed // recvmsgs: Attempting to read from 0x1bbe080 // recvmsgs: recvmsgs(0x1bbe080): Read 20 bytes // recvmsgs: recvmsgs(0x1bbe080): Processing valid message... // __nlmsg_alloc: msg 0x1bc20c0: Allocated new message, maxlen=20 // -- Debug: Received Message: // -------------------------- BEGIN NETLINK MESSAGE --------------------------- // [NETLINK HEADER] 16 octets // .nlmsg_len = 20 // .type = 3 <DONE> // .flags = 2 <MULTI> // .seq = 1424053819 // .port = 18409 // [PAYLOAD] 4 octets // 00 00 00 00 .... // --------------------------- END NETLINK MESSAGE --------------------------- // recvmsgs: recvmsgs(0x1bbe080): Increased expected sequence number to 1424053820 // -- Debug: End of multipart message block: type=DONE length=20 flags=<MULTI> sequence-nr=1424053819 pid=18409 // nlmsg_free: Returned message reference 0x1bc20c0, 0 remaining // nlmsg_free: msg 0x1bc20c0: Freed // 0 == nl_recvmsgs_default(sk) // nl_cache_mngt_unregister: Unregistered cache operations genl/family """ del log[:] sk = nl_socket_alloc() nl_connect(sk, NETLINK_ROUTE) rt_hdr = rtgenmsg(rtgen_family=socket.AF_PACKET) assert 20 == nl_send_simple(sk, RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP, rt_hdr, rt_hdr.SIZEOF) assert match('nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=4096', log, True) assert match('nlmsg_alloc_simple: msg 0x[a-f0-9]+: Allocated new simple message', log, True) assert match('nlmsg_reserve: msg 0x[a-f0-9]+: Reserved 4 \(1\) bytes, pad=4, nlmsg_len=20', log, True) assert match('nlmsg_append: msg 0x[a-f0-9]+: Appended 1 bytes with padding 4', log, True) assert match('nl_msg_out_handler_debug: -- Debug: Sent Message:', log) assert match('nl_msg_dump: -------------------------- BEGIN NETLINK MESSAGE ---------------------------', log) assert match('nl_msg_dump: [NETLINK HEADER] 16 octets', log) assert match('print_hdr: .nlmsg_len = 20', log) assert match('print_hdr: .type = 18 <0x12>', log) assert match('print_hdr: .flags = 773 <REQUEST,ACK,ROOT,MATCH>', log) assert match('print_hdr: .seq = \d{10}', log, True) assert match('print_hdr: .port = \d{3,}', log, True) assert match('print_msg: [PAYLOAD] 4 octets', log) assert match('dump_hex: 11 00 00 00 ....', log) assert match('nl_msg_dump: --------------------------- END NETLINK MESSAGE ---------------------------', log) assert match('nl_sendmsg: sent 20 bytes', log) assert not log assert 0 == nl_recvmsgs_default(sk) assert match('recvmsgs: Attempting to read from 0x[a-f0-9]+', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Read \d{4,} bytes', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Processing valid message...', log, True) assert match('nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=\d{3,}', log, True) assert match('nl_msg_in_handler_debug: -- Debug: Received Message:', log) assert match('nl_msg_dump: -------------------------- BEGIN NETLINK MESSAGE ---------------------------', log) assert match('nl_msg_dump: [NETLINK HEADER] 16 octets', log) assert match('print_hdr: .nlmsg_len = \d{3,}', log, True) assert match('print_hdr: .type = 16 <0x10>', log) assert match('print_hdr: .flags = 2 <MULTI>', log) assert match('print_hdr: .seq = \d{10}', log, True) assert match('print_hdr: .port = \d{3,}', log, True) assert match('print_msg: \[PAYLOAD\] \d{3,} octets', log, True) assert match('dump_hex: 00 00 04 03 01 00 00 00 49 00 01 00 00 00 00 00 ........I.......', log) assert match('dump_hex: 07 00 03 00 6c 6f 00 00 08 00 0d 00 00 00 00 00 ....lo..........', log) assert match('dump_hex: 05 00 10 00 00 00 00 00 05 00 11 00 00 00 00 00 ................', log) for _ in ifaces: # Done testing this payload. Differs too much between Travis and Raspbian, and probably others. rem = log.index('nl_msg_dump: --------------------------- END NETLINK MESSAGE ---------------------------') assert 20 < rem # At least check that there were a lot of log statements skipped. log = log[rem:] assert match('nl_msg_dump: --------------------------- END NETLINK MESSAGE ---------------------------', log) assert match('nl_valid_handler_debug: -- Debug: Unhandled Valid message: type=0x10 length=\d{3,} flags=<MULTI> ' 'sequence-nr=\d{10,} pid=\d{3,}', log, True) assert match('recvmsgs: Attempting to read from 0x[a-f0-9]+', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Read 20 bytes', log, True) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Processing valid message...', log, True) assert match('nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=20', log, True) assert match('nl_msg_in_handler_debug: -- Debug: Received Message:', log) assert match('nl_msg_dump: -------------------------- BEGIN NETLINK MESSAGE ---------------------------', log) assert match('nl_msg_dump: [NETLINK HEADER] 16 octets', log) assert match('print_hdr: .nlmsg_len = 20', log) assert match('print_hdr: .type = 3 <DONE>', log) assert match('print_hdr: .flags = 2 <MULTI>', log) assert match('print_hdr: .seq = \d{10}', log, True) assert match('print_hdr: .port = \d{3,}', log, True) assert match('print_msg: [PAYLOAD] 4 octets', log) assert match('dump_hex: 00 00 00 00 ....', log) assert match('nl_msg_dump: --------------------------- END NETLINK MESSAGE ---------------------------', log) assert match('recvmsgs: recvmsgs\(0x[a-f0-9]+\): Increased expected sequence number to \d{4,}', log, True) assert match('nl_finish_handler_debug: -- Debug: End of multipart message block: type=DONE length=20 flags=<MULTI> ' 'sequence-nr=\d{10,} pid=\d{3,}', log, True) nl_socket_free(sk) assert not log