예제 #1
0
def genlmsg_len(gnlh):
    """Return length of message payload including user header.

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

    Positional arguments:
    gnlh -- Generic Netlink message header (genlmsghdr class instance).

    Returns:
    Length of user payload including an eventual user header in number of bytes.
    """
    nlh = nlmsghdr(bytearray_ptr(gnlh.bytearray, -NLMSG_HDRLEN, oob=True))
    return nlh.nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN
예제 #2
0
파일: genl.py 프로젝트: 0x90/libnl
def genlmsg_len(gnlh):
    """Return length of message payload including user header.

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

    Positional arguments:
    gnlh -- Generic Netlink message header (genlmsghdr class instance).

    Returns:
    Length of user payload including an eventual user header in number of bytes.
    """
    nlh = nlmsghdr(bytearray_ptr(gnlh.bytearray, -NLMSG_HDRLEN, oob=True))
    return nlh.nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN
예제 #3
0
파일: nl.py 프로젝트: kimocoder/libnl-1
def recvmsgs(sk, cb):
    """https://github.com/thom311/libnl/blob/libnl3_2_25/lib/nl.c#L775.

    This is where callbacks are called.

    Positional arguments:
    sk -- Netlink socket (nl_sock class instance).
    cb -- callbacks (nl_cb class instance).

    Returns:
    Number of bytes received or a negative error code.
    """
    multipart = 0
    interrupted = 0
    nrecv = 0
    buf = bytearray()

    # nla is passed on to not only to nl_recv() but may also be passed to a function pointer provided by the caller
    # which may or may not initialize the variable. Thomas Graf.
    nla = sockaddr_nl()
    creds = ucred()

    while True:  # This is the `goto continue_reading` implementation.
        _LOGGER.debug('Attempting to read from 0x%x', id(sk))
        n = c_int(
            cb.cb_recv_ow(sk, nla, buf, creds) if cb.
            cb_recv_ow else nl_recv(sk, nla, buf, creds))
        if n.value <= 0:
            return n.value

        _LOGGER.debug('recvmsgs(0x%x): Read %d bytes', id(sk), n.value)

        hdr = nlmsghdr(bytearray_ptr(buf))
        while nlmsg_ok(hdr, n):
            _LOGGER.debug('recvmsgs(0x%x): Processing valid message...',
                          id(sk))
            msg = nlmsg_convert(hdr)
            nlmsg_set_proto(msg, sk.s_proto)
            nlmsg_set_src(msg, nla)
            if creds:
                raise NotImplementedError  # nlmsg_set_creds(msg, creds)
            nrecv += 1

            # Raw callback is the first, it gives the most control to the user and he can do his very own parsing.
            if cb.cb_set[NL_CB_MSG_IN]:
                err = nl_cb_call(cb, NL_CB_MSG_IN,
                                 msg)  # NL_CB_CALL(cb, NL_CB_MSG_IN, msg)
                if err == NL_OK:
                    pass
                elif err == NL_SKIP:
                    hdr = nlmsg_next(hdr, n)
                    continue
                elif err == NL_STOP:
                    return -NLE_DUMP_INTR if interrupted else nrecv
                else:
                    return -NLE_DUMP_INTR if interrupted else (err or nrecv)

            if cb.cb_set[NL_CB_SEQ_CHECK]:
                # Sequence number checking. The check may be done by the user, otherwise a very simple check is applied
                # enforcing strict ordering.
                err = nl_cb_call(cb, NL_CB_SEQ_CHECK,
                                 msg)  # NL_CB_CALL(cb, NL_CB_SEQ_CHECK, msg)
                if err == NL_OK:
                    pass
                elif err == NL_SKIP:
                    hdr = nlmsg_next(hdr, n)
                    continue
                elif err == NL_STOP:
                    return -NLE_DUMP_INTR if interrupted else nrecv
                else:
                    return -NLE_DUMP_INTR if interrupted else (err or nrecv)
            elif not sk.s_flags & NL_NO_AUTO_ACK:
                # Only do sequence checking if auto-ack mode is enabled.
                if hdr.nlmsg_seq != sk.s_seq_expect:
                    if cb.cb_set[NL_CB_INVALID]:
                        err = nl_cb_call(
                            cb, NL_CB_INVALID,
                            msg)  # NL_CB_CALL(cb, NL_CB_INVALID, msg)
                        if err == NL_OK:
                            pass
                        elif err == NL_SKIP:
                            hdr = nlmsg_next(hdr, n)
                            continue
                        elif err == NL_STOP:
                            return -NLE_DUMP_INTR if interrupted else nrecv
                        else:
                            return -NLE_DUMP_INTR if interrupted else (
                                err or nrecv)
                    else:
                        return -NLE_SEQ_MISMATCH

            if hdr.nlmsg_type in (NLMSG_DONE, NLMSG_ERROR, NLMSG_NOOP,
                                  NLMSG_OVERRUN):
                # We can't check for !NLM_F_MULTI since some Netlink users in the kernel are broken.
                sk.s_seq_expect += 1
                _LOGGER.debug(
                    'recvmsgs(0x%x): Increased expected sequence number to %d',
                    id(sk), sk.s_seq_expect)

            if hdr.nlmsg_flags & NLM_F_MULTI:
                multipart = 1

            if hdr.nlmsg_flags & NLM_F_DUMP_INTR:
                if cb.cb_set[NL_CB_DUMP_INTR]:
                    err = nl_cb_call(
                        cb, NL_CB_DUMP_INTR,
                        msg)  # NL_CB_CALL(cb, NL_CB_DUMP_INTR, msg)
                    if err == NL_OK:
                        pass
                    elif err == NL_SKIP:
                        hdr = nlmsg_next(hdr, n)
                        continue
                    elif err == NL_STOP:
                        return -NLE_DUMP_INTR if interrupted else nrecv
                    else:
                        return -NLE_DUMP_INTR if interrupted else (err
                                                                   or nrecv)
                else:
                    # We have to continue reading to clear all messages until a NLMSG_DONE is received and report the
                    # inconsistency.
                    interrupted = 1

            if hdr.nlmsg_flags & NLM_F_ACK:
                # Other side wishes to see an ack for this message.
                if cb.cb_set[NL_CB_SEND_ACK]:
                    err = nl_cb_call(
                        cb, NL_CB_SEND_ACK,
                        msg)  # NL_CB_CALL(cb, NL_CB_SEND_ACK, msg)
                    if err == NL_OK:
                        pass
                    elif err == NL_SKIP:
                        hdr = nlmsg_next(hdr, n)
                        continue
                    elif err == NL_STOP:
                        return -NLE_DUMP_INTR if interrupted else nrecv
                    else:
                        return -NLE_DUMP_INTR if interrupted else (err
                                                                   or nrecv)

            if hdr.nlmsg_type == NLMSG_DONE:
                # Messages terminates a multipart message, this is usually the end of a message and therefore we slip
                # out of the loop by default. the user may overrule this action by skipping this packet.
                multipart = 0
                if cb.cb_set[NL_CB_FINISH]:
                    err = nl_cb_call(cb, NL_CB_FINISH,
                                     msg)  # NL_CB_CALL(cb, NL_CB_FINISH, msg)
                    if err == NL_OK:
                        pass
                    elif err == NL_SKIP:
                        hdr = nlmsg_next(hdr, n)
                        continue
                    elif err == NL_STOP:
                        return -NLE_DUMP_INTR if interrupted else nrecv
                    else:
                        return -NLE_DUMP_INTR if interrupted else (err
                                                                   or nrecv)
            elif hdr.nlmsg_type == NLMSG_NOOP:
                # Message to be ignored, the default action is to skip this message if no callback is specified. The
                # user may overrule this action by returning NL_PROCEED.
                if cb.cb_set[NL_CB_SKIPPED]:
                    err = nl_cb_call(cb, NL_CB_SKIPPED,
                                     msg)  # NL_CB_CALL(cb, NL_CB_SKIPPED, msg)
                    if err == NL_OK:
                        pass
                    elif err == NL_SKIP:
                        hdr = nlmsg_next(hdr, n)
                        continue
                    elif err == NL_STOP:
                        return -NLE_DUMP_INTR if interrupted else nrecv
                    else:
                        return -NLE_DUMP_INTR if interrupted else (err
                                                                   or nrecv)
                else:
                    hdr = nlmsg_next(hdr, n)
                    continue
            elif hdr.nlmsg_type == NLMSG_OVERRUN:
                # Data got lost, report back to user. The default action is to quit parsing. The user may overrule this
                # action by retuning NL_SKIP or NL_PROCEED (dangerous).
                if cb.cb_set[NL_CB_OVERRUN]:
                    err = nl_cb_call(cb, NL_CB_OVERRUN,
                                     msg)  # NL_CB_CALL(cb, NL_CB_OVERRUN, msg)
                    if err == NL_OK:
                        pass
                    elif err == NL_SKIP:
                        hdr = nlmsg_next(hdr, n)
                        continue
                    elif err == NL_STOP:
                        return -NLE_DUMP_INTR if interrupted else nrecv
                    else:
                        return -NLE_DUMP_INTR if interrupted else (err
                                                                   or nrecv)
                else:
                    return -NLE_DUMP_INTR if interrupted else -NLE_MSG_OVERFLOW
            elif hdr.nlmsg_type == NLMSG_ERROR:
                # Message carries a nlmsgerr.
                e = nlmsgerr(nlmsg_data(hdr))
                if hdr.nlmsg_len < nlmsg_size(e.SIZEOF):
                    # Truncated error message, the default action is to stop parsing. The user may overrule this action
                    # by returning NL_SKIP or NL_PROCEED (dangerous).
                    if cb.cb_set[NL_CB_INVALID]:
                        err = nl_cb_call(
                            cb, NL_CB_INVALID,
                            msg)  # NL_CB_CALL(cb, NL_CB_INVALID, msg)
                        if err == NL_OK:
                            pass
                        elif err == NL_SKIP:
                            hdr = nlmsg_next(hdr, n)
                            continue
                        elif err == NL_STOP:
                            return -NLE_DUMP_INTR if interrupted else nrecv
                        else:
                            return -NLE_DUMP_INTR if interrupted else (
                                err or nrecv)
                    else:
                        return -NLE_DUMP_INTR if interrupted else -NLE_MSG_TRUNC
                elif e.error:
                    # Error message reported back from kernel.
                    if cb.cb_err:
                        err = cb.cb_err(nla, e, cb.cb_err_arg)
                        if err < 0:
                            return -NLE_DUMP_INTR if interrupted else err
                        elif err == NL_SKIP:
                            hdr = nlmsg_next(hdr, n)
                            continue
                        elif err == NL_STOP:
                            return -NLE_DUMP_INTR if interrupted else -nl_syserr2nlerr(
                                e.error)
                    else:
                        return -NLE_DUMP_INTR if interrupted else -nl_syserr2nlerr(
                            e.error)
                elif cb.cb_set[NL_CB_ACK]:
                    err = nl_cb_call(cb, NL_CB_ACK,
                                     msg)  # NL_CB_CALL(cb, NL_CB_ACK, msg)
                    if err == NL_OK:
                        pass
                    elif err == NL_SKIP:
                        hdr = nlmsg_next(hdr, n)
                        continue
                    elif err == NL_STOP:
                        return -NLE_DUMP_INTR if interrupted else nrecv
                    else:
                        return -NLE_DUMP_INTR if interrupted else (err
                                                                   or nrecv)
            else:
                # Valid message (not checking for MULTIPART bit to get along with broken kernels. NL_SKIP has no effect
                # on this.
                if cb.cb_set[NL_CB_VALID]:
                    err = nl_cb_call(cb, NL_CB_VALID,
                                     msg)  # NL_CB_CALL(cb, NL_CB_VALID, msg)
                    if err == NL_OK:
                        pass
                    elif err == NL_SKIP:
                        hdr = nlmsg_next(hdr, n)
                        continue
                    elif err == NL_STOP:
                        return -NLE_DUMP_INTR if interrupted else nrecv
                    else:
                        return -NLE_DUMP_INTR if interrupted else (err
                                                                   or nrecv)

            hdr = nlmsg_next(hdr, n)

        del buf[:]
        creds = None

        if multipart:
            # Multipart message not yet complete, continue reading.
            continue

        err = 0
        if interrupted:
            return -NLE_DUMP_INTR
        if not err:
            err = nrecv
        return err
예제 #4
0
파일: nl.py 프로젝트: 0x90/libnl
def recvmsgs(sk, cb):
    """https://github.com/thom311/libnl/blob/libnl3_2_25/lib/nl.c#L775.

    This is where callbacks are called.

    Positional arguments:
    sk -- Netlink socket (nl_sock class instance).
    cb -- callbacks (nl_cb class instance).

    Returns:
    Number of bytes received or a negative error code.
    """
    multipart = 0
    interrupted = 0
    nrecv = 0
    buf = bytearray()

    # nla is passed on to not only to nl_recv() but may also be passed to a function pointer provided by the caller
    # which may or may not initialize the variable. Thomas Graf.
    nla = sockaddr_nl()
    creds = ucred()

    while True:  # This is the `goto continue_reading` implementation.
        _LOGGER.debug('Attempting to read from 0x%x', id(sk))
        n = c_int(cb.cb_recv_ow(sk, nla, buf, creds) if cb.cb_recv_ow else nl_recv(sk, nla, buf, creds))
        if n.value <= 0:
            return n.value

        _LOGGER.debug('recvmsgs(0x%x): Read %d bytes', id(sk), n.value)

        hdr = nlmsghdr(bytearray_ptr(buf))
        while nlmsg_ok(hdr, n):
            _LOGGER.debug('recvmsgs(0x%x): Processing valid message...', id(sk))
            msg = nlmsg_convert(hdr)
            nlmsg_set_proto(msg, sk.s_proto)
            nlmsg_set_src(msg, nla)
            if creds:
                raise NotImplementedError  # nlmsg_set_creds(msg, creds)
            nrecv += 1

            # Raw callback is the first, it gives the most control to the user and he can do his very own parsing.
            if cb.cb_set[NL_CB_MSG_IN]:
                err = nl_cb_call(cb, NL_CB_MSG_IN, msg)  # NL_CB_CALL(cb, NL_CB_MSG_IN, msg)
                if err == NL_OK:
                    pass
                elif err == NL_SKIP:
                    hdr = nlmsg_next(hdr, n)
                    continue
                elif err == NL_STOP:
                    return -NLE_DUMP_INTR if interrupted else nrecv
                else:
                    return -NLE_DUMP_INTR if interrupted else (err or nrecv)

            if cb.cb_set[NL_CB_SEQ_CHECK]:
                # Sequence number checking. The check may be done by the user, otherwise a very simple check is applied
                # enforcing strict ordering.
                err = nl_cb_call(cb, NL_CB_SEQ_CHECK, msg)  # NL_CB_CALL(cb, NL_CB_SEQ_CHECK, msg)
                if err == NL_OK:
                    pass
                elif err == NL_SKIP:
                    hdr = nlmsg_next(hdr, n)
                    continue
                elif err == NL_STOP:
                    return -NLE_DUMP_INTR if interrupted else nrecv
                else:
                    return -NLE_DUMP_INTR if interrupted else (err or nrecv)
            elif not sk.s_flags & NL_NO_AUTO_ACK:
                # Only do sequence checking if auto-ack mode is enabled.
                if hdr.nlmsg_seq != sk.s_seq_expect:
                    if cb.cb_set[NL_CB_INVALID]:
                        err = nl_cb_call(cb, NL_CB_INVALID, msg)  # NL_CB_CALL(cb, NL_CB_INVALID, msg)
                        if err == NL_OK:
                            pass
                        elif err == NL_SKIP:
                            hdr = nlmsg_next(hdr, n)
                            continue
                        elif err == NL_STOP:
                            return -NLE_DUMP_INTR if interrupted else nrecv
                        else:
                            return -NLE_DUMP_INTR if interrupted else (err or nrecv)
                    else:
                        return -NLE_SEQ_MISMATCH

            if hdr.nlmsg_type in (NLMSG_DONE, NLMSG_ERROR, NLMSG_NOOP, NLMSG_OVERRUN):
                # We can't check for !NLM_F_MULTI since some Netlink users in the kernel are broken.
                sk.s_seq_expect += 1
                _LOGGER.debug('recvmsgs(0x%x): Increased expected sequence number to %d', id(sk), sk.s_seq_expect)

            if hdr.nlmsg_flags & NLM_F_MULTI:
                multipart = 1

            if hdr.nlmsg_flags & NLM_F_DUMP_INTR:
                if cb.cb_set[NL_CB_DUMP_INTR]:
                    err = nl_cb_call(cb, NL_CB_DUMP_INTR, msg)  # NL_CB_CALL(cb, NL_CB_DUMP_INTR, msg)
                    if err == NL_OK:
                        pass
                    elif err == NL_SKIP:
                        hdr = nlmsg_next(hdr, n)
                        continue
                    elif err == NL_STOP:
                        return -NLE_DUMP_INTR if interrupted else nrecv
                    else:
                        return -NLE_DUMP_INTR if interrupted else (err or nrecv)
                else:
                    # We have to continue reading to clear all messages until a NLMSG_DONE is received and report the
                    # inconsistency.
                    interrupted = 1

            if hdr.nlmsg_flags & NLM_F_ACK:
                # Other side wishes to see an ack for this message.
                if cb.cb_set[NL_CB_SEND_ACK]:
                    err = nl_cb_call(cb, NL_CB_SEND_ACK, msg)  # NL_CB_CALL(cb, NL_CB_SEND_ACK, msg)
                    if err == NL_OK:
                        pass
                    elif err == NL_SKIP:
                        hdr = nlmsg_next(hdr, n)
                        continue
                    elif err == NL_STOP:
                        return -NLE_DUMP_INTR if interrupted else nrecv
                    else:
                        return -NLE_DUMP_INTR if interrupted else (err or nrecv)

            if hdr.nlmsg_type == NLMSG_DONE:
                # Messages terminates a multipart message, this is usually the end of a message and therefore we slip
                # out of the loop by default. the user may overrule this action by skipping this packet.
                multipart = 0
                if cb.cb_set[NL_CB_FINISH]:
                    err = nl_cb_call(cb, NL_CB_FINISH, msg)  # NL_CB_CALL(cb, NL_CB_FINISH, msg)
                    if err == NL_OK:
                        pass
                    elif err == NL_SKIP:
                        hdr = nlmsg_next(hdr, n)
                        continue
                    elif err == NL_STOP:
                        return -NLE_DUMP_INTR if interrupted else nrecv
                    else:
                        return -NLE_DUMP_INTR if interrupted else (err or nrecv)
            elif hdr.nlmsg_type == NLMSG_NOOP:
                # Message to be ignored, the default action is to skip this message if no callback is specified. The
                # user may overrule this action by returning NL_PROCEED.
                if cb.cb_set[NL_CB_SKIPPED]:
                    err = nl_cb_call(cb, NL_CB_SKIPPED, msg)  # NL_CB_CALL(cb, NL_CB_SKIPPED, msg)
                    if err == NL_OK:
                        pass
                    elif err == NL_SKIP:
                        hdr = nlmsg_next(hdr, n)
                        continue
                    elif err == NL_STOP:
                        return -NLE_DUMP_INTR if interrupted else nrecv
                    else:
                        return -NLE_DUMP_INTR if interrupted else (err or nrecv)
                else:
                    hdr = nlmsg_next(hdr, n)
                    continue
            elif hdr.nlmsg_type == NLMSG_OVERRUN:
                # Data got lost, report back to user. The default action is to quit parsing. The user may overrule this
                # action by retuning NL_SKIP or NL_PROCEED (dangerous).
                if cb.cb_set[NL_CB_OVERRUN]:
                    err = nl_cb_call(cb, NL_CB_OVERRUN, msg)  # NL_CB_CALL(cb, NL_CB_OVERRUN, msg)
                    if err == NL_OK:
                        pass
                    elif err == NL_SKIP:
                        hdr = nlmsg_next(hdr, n)
                        continue
                    elif err == NL_STOP:
                        return -NLE_DUMP_INTR if interrupted else nrecv
                    else:
                        return -NLE_DUMP_INTR if interrupted else (err or nrecv)
                else:
                    return -NLE_DUMP_INTR if interrupted else -NLE_MSG_OVERFLOW
            elif hdr.nlmsg_type == NLMSG_ERROR:
                # Message carries a nlmsgerr.
                e = nlmsgerr(nlmsg_data(hdr))
                if hdr.nlmsg_len < nlmsg_size(e.SIZEOF):
                    # Truncated error message, the default action is to stop parsing. The user may overrule this action
                    # by returning NL_SKIP or NL_PROCEED (dangerous).
                    if cb.cb_set[NL_CB_INVALID]:
                        err = nl_cb_call(cb, NL_CB_INVALID, msg)  # NL_CB_CALL(cb, NL_CB_INVALID, msg)
                        if err == NL_OK:
                            pass
                        elif err == NL_SKIP:
                            hdr = nlmsg_next(hdr, n)
                            continue
                        elif err == NL_STOP:
                            return -NLE_DUMP_INTR if interrupted else nrecv
                        else:
                            return -NLE_DUMP_INTR if interrupted else (err or nrecv)
                    else:
                        return -NLE_DUMP_INTR if interrupted else -NLE_MSG_TRUNC
                elif e.error:
                    # Error message reported back from kernel.
                    if cb.cb_err:
                        err = cb.cb_err(nla, e, cb.cb_err_arg)
                        if err < 0:
                            return -NLE_DUMP_INTR if interrupted else err
                        elif err == NL_SKIP:
                            hdr = nlmsg_next(hdr, n)
                            continue
                        elif err == NL_STOP:
                            return -NLE_DUMP_INTR if interrupted else -nl_syserr2nlerr(e.error)
                    else:
                        return -NLE_DUMP_INTR if interrupted else -nl_syserr2nlerr(e.error)
                elif cb.cb_set[NL_CB_ACK]:
                    err = nl_cb_call(cb, NL_CB_ACK, msg)  # NL_CB_CALL(cb, NL_CB_ACK, msg)
                    if err == NL_OK:
                        pass
                    elif err == NL_SKIP:
                        hdr = nlmsg_next(hdr, n)
                        continue
                    elif err == NL_STOP:
                        return -NLE_DUMP_INTR if interrupted else nrecv
                    else:
                        return -NLE_DUMP_INTR if interrupted else (err or nrecv)
            else:
                # Valid message (not checking for MULTIPART bit to get along with broken kernels. NL_SKIP has no effect
                # on this.
                if cb.cb_set[NL_CB_VALID]:
                    err = nl_cb_call(cb, NL_CB_VALID, msg)  # NL_CB_CALL(cb, NL_CB_VALID, msg)
                    if err == NL_OK:
                        pass
                    elif err == NL_SKIP:
                        hdr = nlmsg_next(hdr, n)
                        continue
                    elif err == NL_STOP:
                        return -NLE_DUMP_INTR if interrupted else nrecv
                    else:
                        return -NLE_DUMP_INTR if interrupted else (err or nrecv)

            hdr = nlmsg_next(hdr, n)

        del buf[:]
        creds = None

        if multipart:
            # Multipart message not yet complete, continue reading.
            continue

        err = 0
        if interrupted:
            return -NLE_DUMP_INTR
        if not err:
            err = nrecv
        return err