Example #1
0
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)
Example #3
0
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))
Example #6
0
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)
Example #7
0
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)
Example #8
0
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
Example #9
0
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
Example #10
0
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
Example #11
0
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
Example #12
0
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
Example #13
0
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
Example #14
0
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
Example #15
0
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