Exemple #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))
Exemple #2
0
def test_nl_recv():
    r"""C code to test against.

    // gcc a.c $(pkg-config --cflags --libs libnl-genl-3.0) && ./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.
        struct nl_sock *sk = nl_socket_alloc();
        sk->s_seq_next = 0;
        nl_connect(sk, NETLINK_ROUTE);
        int ret = nl_send_simple(sk, 0, NLM_F_REQUEST, NULL, 0);
        printf("Bytes Sent: %d\n", ret);

        // Retrieve kernel's response.
        // nl_recvmsgs_default(sk);
        // return 0;
        unsigned char *buf = NULL;
        struct sockaddr_nl nla = {0};
        printf("%d == nla.nl_family\n", nla.nl_family);
        int n = nl_recv(sk, &nla, &buf, NULL);
        printf("Bytes Recv: %d\n", n);

        int i = 0; for (i = 0; i<n; i++) printf("%02x", buf[i]); printf("\n");
        printf("%d == nla.nl_family\n", nla.nl_family);
        return 0;
    }
    // Expected output:
    // Bytes Sent: 16
    // 0 == nla.nl_family
    // Bytes Recv: 36
    // 240000000200000000000000844c000000000000100000000000050000000000844c0000
    // 16 == nla.nl_family
    // Output delta:
    // 240000000200000000000000ac4e000000000000100000000000050000000000ac4e0000
    """
    sk = nl_socket_alloc()
    sk.s_seq_next = 0
    nl_connect(sk, NETLINK_ROUTE)
    assert 16 == nl_send_simple(sk, 0, NLM_F_REQUEST, None)

    buf = bytearray()
    nla = sockaddr_nl()
    assert 0 == nla.nl_family
    assert 36 == nl_recv(sk, nla, buf, None)
    nl_socket_free(sk)

    buf_hex = binascii.hexlify(buffer(buf)).decode('ascii')
    assert re.match(
        r'240000000200000000000000....000000000000100000000000050000000000....0000',
        buf_hex)
    assert 16 == nla.nl_family
Exemple #3
0
def test_nl_recv():
    r"""C code to test against.

    // gcc a.c $(pkg-config --cflags --libs libnl-genl-3.0) && ./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.
        struct nl_sock *sk = nl_socket_alloc();
        sk->s_seq_next = 0;
        nl_connect(sk, NETLINK_ROUTE);
        int ret = nl_send_simple(sk, 0, NLM_F_REQUEST, NULL, 0);
        printf("Bytes Sent: %d\n", ret);

        // Retrieve kernel's response.
        // nl_recvmsgs_default(sk);
        // return 0;
        unsigned char *buf = NULL;
        struct sockaddr_nl nla = {0};
        printf("%d == nla.nl_family\n", nla.nl_family);
        int n = nl_recv(sk, &nla, &buf, NULL);
        printf("Bytes Recv: %d\n", n);

        int i = 0; for (i = 0; i<n; i++) printf("%02x", buf[i]); printf("\n");
        printf("%d == nla.nl_family\n", nla.nl_family);
        return 0;
    }
    // Expected output:
    // Bytes Sent: 16
    // 0 == nla.nl_family
    // Bytes Recv: 36
    // 240000000200000000000000844c000000000000100000000000050000000000844c0000
    // 16 == nla.nl_family
    // Output delta:
    // 240000000200000000000000ac4e000000000000100000000000050000000000ac4e0000
    """
    sk = nl_socket_alloc()
    sk.s_seq_next = 0
    nl_connect(sk, NETLINK_ROUTE)
    assert 16 == nl_send_simple(sk, 0, NLM_F_REQUEST, None)

    buf = bytearray()
    nla = sockaddr_nl()
    assert 0 == nla.nl_family
    assert 36 == nl_recv(sk, nla, buf, None)
    nl_socket_free(sk)

    buf_hex = binascii.hexlify(buffer(buf)).decode('ascii')
    assert re.match(r'240000000200000000000000....000000000000100000000000050000000000....0000', buf_hex)
    assert 16 == nla.nl_family
def test_bare(tcp_server, monkeypatch):
    r"""C code to test against.

    // gcc a.c $(pkg-config --cflags --libs libnl-genl-3.0) && (nc -l 2000 |base64 &) && sleep 0.1 && ./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() {
        struct sockaddr_in sin = { .sin_port = htons(2000), .sin_family = AF_INET, };
        sin.sin_addr.s_addr = inet_addr("127.0.0.1");
        int fd = socket(AF_INET, SOCK_STREAM, 0);
        connect(fd, (struct sockaddr *) &sin, sizeof(sin));

        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;

        int ret = nl_send_simple(sk, RTM_GETLINK, 0, NULL, 0);

        printf("Bytes: %d\n", ret);
        return 0;
    }
    // Expected bash output:
    // Bytes: 16
    // EAAAABIABQAAAAAAAAAAAA==
    """
    monkeypatch.setattr(libnl.socket_, 'generate_local_port', lambda: 0)

    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 = 0
    sk.s_seq_next = 0

    assert 16 == nl_send_simple(sk, RTM_GETLINK, 0, None)
    assert 1 == len(tcp_server.data)
    assert b'EAAAABIABQAAAAAAAAAAAA==' == base64.b64encode(
        buffer(tcp_server.data[0]))
    nl_socket_free(sk)
Exemple #5
0
def test_bare(tcp_server, monkeypatch):
    r"""C code to test against.

    // gcc a.c $(pkg-config --cflags --libs libnl-genl-3.0) && (nc -l 2000 |base64 &) && sleep 0.1 && ./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() {
        struct sockaddr_in sin = { .sin_port = htons(2000), .sin_family = AF_INET, };
        sin.sin_addr.s_addr = inet_addr("127.0.0.1");
        int fd = socket(AF_INET, SOCK_STREAM, 0);
        connect(fd, (struct sockaddr *) &sin, sizeof(sin));

        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;

        int ret = nl_send_simple(sk, RTM_GETLINK, 0, NULL, 0);

        printf("Bytes: %d\n", ret);
        return 0;
    }
    // Expected bash output:
    // Bytes: 16
    // EAAAABIABQAAAAAAAAAAAA==
    """
    monkeypatch.setattr(libnl.socket_, 'generate_local_port', lambda: 0)

    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 = 0
    sk.s_seq_next = 0

    assert 16 == nl_send_simple(sk, RTM_GETLINK, 0, None)
    assert 1 == len(tcp_server.data)
    assert b'EAAAABIABQAAAAAAAAAAAA==' == base64.b64encode(buffer(tcp_server.data[0]))
    nl_socket_free(sk)
Exemple #6
0
def genl_send_simple(sk, family, cmd, version, flags):
    """Send a Generic Netlink message consisting only of a header.

    https://github.com/thom311/libnl/blob/libnl3_2_25/lib/genl/genl.c#L84

    This function is a shortcut for sending a Generic Netlink message without any message payload. The message will only
    consist of the Netlink and Generic Netlink headers. The header is constructed based on the specified parameters and
    passed on to nl_send_simple() to send it on the specified socket.

    Positional arguments:
    sk -- Generic Netlink socket (nl_sock class instance).
    family -- numeric family identifier (integer).
    cmd -- numeric command identifier (integer).
    version -- interface version (integer).
    flags -- additional Netlink message flags (integer).

    Returns:
    0 on success or a negative error code.
    """
    hdr = genlmsghdr(cmd=cmd, version=version)
    return int(nl_send_simple(sk, family, flags, hdr, hdr.SIZEOF))
Exemple #7
0
def genl_send_simple(sk, family, cmd, version, flags):
    """Send a Generic Netlink message consisting only of a header.

    https://github.com/thom311/libnl/blob/libnl3_2_25/lib/genl/genl.c#L84

    This function is a shortcut for sending a Generic Netlink message without any message payload. The message will only
    consist of the Netlink and Generic Netlink headers. The header is constructed based on the specified parameters and
    passed on to nl_send_simple() to send it on the specified socket.

    Positional arguments:
    sk -- Generic Netlink socket (nl_sock class instance).
    family -- numeric family identifier (integer).
    cmd -- numeric command identifier (integer).
    version -- interface version (integer).
    flags -- additional Netlink message flags (integer).

    Returns:
    0 on success or a negative error code.
    """
    hdr = genlmsghdr(cmd=cmd, version=version)
    return int(nl_send_simple(sk, family, flags, hdr, hdr.SIZEOF))
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))
Exemple #10
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)
Exemple #11
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)
Exemple #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
Exemple #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
Exemple #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
Exemple #15
0
def test_error(log):
    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));
        int ret = nl_send_simple(sk, 0, NLM_F_REQUEST, NULL, 0);
        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 0x3df0b8: Allocated new message, maxlen=4096
    // nlmsg_alloc_simple: msg 0x3df0b8: Allocated new simple message
    // -- Debug: Sent Message:
    // --------------------------   BEGIN NETLINK MESSAGE ---------------------------
    //   [NETLINK HEADER] 16 octets
    //     .nlmsg_len = 16
    //     .type = 0 <0x0>
    //     .flags = 5 <REQUEST,ACK>
    //     .seq = 1423967746
    //     .port = 29930
    // ---------------------------  END NETLINK MESSAGE   ---------------------------
    // nl_sendmsg: sent 16 bytes
    // nlmsg_free: Returned message reference 0x3df0b8, 0 remaining
    // nlmsg_free: msg 0x3df0b8: Freed
    // Bytes Sent: 16
    // recvmsgs: Attempting to read from 0x3df080
    // recvmsgs: recvmsgs(0x3df080): Read 36 bytes
    // recvmsgs: recvmsgs(0x3df080): Processing valid message...
    // __nlmsg_alloc: msg 0x3e30c0: Allocated new message, maxlen=36
    // -- Debug: Received Message:
    // --------------------------   BEGIN NETLINK MESSAGE ---------------------------
    //   [NETLINK HEADER] 16 octets
    //     .nlmsg_len = 36
    //     .type = 2 <ERROR>
    //     .flags = 0 <>
    //     .seq = 1423967746
    //     .port = 29930
    //   [ERRORMSG] 20 octets
    //     .error = 0 "Success"
    //   [ORIGINAL MESSAGE] 16 octets
    // __nlmsg_alloc: msg 0x3e3128: Allocated new message, maxlen=4096
    //     .nlmsg_len = 16
    //     .type = 0 <0x0>
    //     .flags = 5 <REQUEST,ACK>
    //     .seq = 1423967746
    //     .port = 29930
    // nlmsg_free: Returned message reference 0x3e3128, 0 remaining
    // nlmsg_free: msg 0x3e3128: Freed
    // ---------------------------  END NETLINK MESSAGE   ---------------------------
    // recvmsgs: recvmsgs(0x3df080): Increased expected sequence number to 1423967746
    // -- Debug: ACK: type=ERROR length=36 flags=<> sequence-nr=1423967746 pid=29930
    // nlmsg_free: Returned message reference 0x3e30c0, 0 remaining
    // nlmsg_free: msg 0x3e30c0: 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)
    assert 16 == nl_send_simple(sk, 0, NLM_F_REQUEST, None)

    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('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 = 16', log)
    assert match('print_hdr:     .type = 0 <0x0>', log)
    assert match('print_hdr:     .flags = 5 <REQUEST,ACK>', log)
    assert match('print_hdr:     .seq = \d{10}', log, True)
    assert match('print_hdr:     .port = \d{3,}', log, True)
    assert match(
        'nl_msg_dump: ---------------------------  END NETLINK MESSAGE   ---------------------------',
        log)
    assert match('nl_sendmsg: sent 16 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 36 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=36', 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 = 36', log)
    assert match('print_hdr:     .type = 2 <ERROR>', log)
    assert match('print_hdr:     .flags = 0 <>', log)
    assert match('print_hdr:     .seq = \d{10}', log, True)
    assert match('print_hdr:     .port = \d{3,}', log, True)
    assert match('dump_error_msg:   [ERRORMSG] 20 octets', log)
    assert match('dump_error_msg:     .error = 0 "Success"', log)
    assert match('dump_error_msg:   [ORIGINAL MESSAGE] 16 octets', log)
    assert match(
        'nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=4096',
        log, True)
    assert match('print_hdr:     .nlmsg_len = 16', log)
    assert match('print_hdr:     .type = 0 <0x0>', log)
    assert match('print_hdr:     .flags = 5 <REQUEST,ACK>', log)
    assert match('print_hdr:     .seq = \d{10}', log, True)
    assert match('print_hdr:     .port = \d{3,}', log, True)
    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_ack_handler_debug: -- Debug: ACK: type=ERROR length=36 flags=<> sequence-nr=\d{10,} pid=\d{3,}',
        log, True)
    nl_socket_free(sk)
    assert not log
Exemple #16
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
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_error(log):
    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));
        int ret = nl_send_simple(sk, 0, NLM_F_REQUEST, NULL, 0);
        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 0x3df0b8: Allocated new message, maxlen=4096
    // nlmsg_alloc_simple: msg 0x3df0b8: Allocated new simple message
    // -- Debug: Sent Message:
    // --------------------------   BEGIN NETLINK MESSAGE ---------------------------
    //   [NETLINK HEADER] 16 octets
    //     .nlmsg_len = 16
    //     .type = 0 <0x0>
    //     .flags = 5 <REQUEST,ACK>
    //     .seq = 1423967746
    //     .port = 29930
    // ---------------------------  END NETLINK MESSAGE   ---------------------------
    // nl_sendmsg: sent 16 bytes
    // nlmsg_free: Returned message reference 0x3df0b8, 0 remaining
    // nlmsg_free: msg 0x3df0b8: Freed
    // Bytes Sent: 16
    // recvmsgs: Attempting to read from 0x3df080
    // recvmsgs: recvmsgs(0x3df080): Read 36 bytes
    // recvmsgs: recvmsgs(0x3df080): Processing valid message...
    // __nlmsg_alloc: msg 0x3e30c0: Allocated new message, maxlen=36
    // -- Debug: Received Message:
    // --------------------------   BEGIN NETLINK MESSAGE ---------------------------
    //   [NETLINK HEADER] 16 octets
    //     .nlmsg_len = 36
    //     .type = 2 <ERROR>
    //     .flags = 0 <>
    //     .seq = 1423967746
    //     .port = 29930
    //   [ERRORMSG] 20 octets
    //     .error = 0 "Success"
    //   [ORIGINAL MESSAGE] 16 octets
    // __nlmsg_alloc: msg 0x3e3128: Allocated new message, maxlen=4096
    //     .nlmsg_len = 16
    //     .type = 0 <0x0>
    //     .flags = 5 <REQUEST,ACK>
    //     .seq = 1423967746
    //     .port = 29930
    // nlmsg_free: Returned message reference 0x3e3128, 0 remaining
    // nlmsg_free: msg 0x3e3128: Freed
    // ---------------------------  END NETLINK MESSAGE   ---------------------------
    // recvmsgs: recvmsgs(0x3df080): Increased expected sequence number to 1423967746
    // -- Debug: ACK: type=ERROR length=36 flags=<> sequence-nr=1423967746 pid=29930
    // nlmsg_free: Returned message reference 0x3e30c0, 0 remaining
    // nlmsg_free: msg 0x3e30c0: 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)
    assert 16 == nl_send_simple(sk, 0, NLM_F_REQUEST, None)

    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('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 = 16', log)
    assert match('print_hdr:     .type = 0 <0x0>', log)
    assert match('print_hdr:     .flags = 5 <REQUEST,ACK>', log)
    assert match('print_hdr:     .seq = \d{10}', log, True)
    assert match('print_hdr:     .port = \d{3,}', log, True)
    assert match('nl_msg_dump: ---------------------------  END NETLINK MESSAGE   ---------------------------', log)
    assert match('nl_sendmsg: sent 16 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 36 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=36', 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 = 36', log)
    assert match('print_hdr:     .type = 2 <ERROR>', log)
    assert match('print_hdr:     .flags = 0 <>', log)
    assert match('print_hdr:     .seq = \d{10}', log, True)
    assert match('print_hdr:     .port = \d{3,}', log, True)
    assert match('dump_error_msg:   [ERRORMSG] 20 octets', log)
    assert match('dump_error_msg:     .error = 0 "Success"', log)
    assert match('dump_error_msg:   [ORIGINAL MESSAGE] 16 octets', log)
    assert match('nlmsg_alloc: msg 0x[a-f0-9]+: Allocated new message, maxlen=4096', log, True)
    assert match('print_hdr:     .nlmsg_len = 16', log)
    assert match('print_hdr:     .type = 0 <0x0>', log)
    assert match('print_hdr:     .flags = 5 <REQUEST,ACK>', log)
    assert match('print_hdr:     .seq = \d{10}', log, True)
    assert match('print_hdr:     .port = \d{3,}', log, True)
    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_ack_handler_debug: -- Debug: ACK: type=ERROR length=36 flags=<> sequence-nr=\d{10,} pid=\d{3,}',
                 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
Exemple #20
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
Exemple #21
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