From c07b958a0990782b2470082813cbf95e52a39935 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Tue, 6 Feb 2018 13:21:29 +0000 Subject: [PATCH] libnetwork: Properly handle errors from netlink messages Signed-off-by: Michael Tremer --- configure.ac | 1 + src/libnetwork/libnetwork.c | 74 ++++++++++++++++++++++++++++++------- 2 files changed, 61 insertions(+), 14 deletions(-) diff --git a/configure.ac b/configure.ac index cc5b21e..7cb5ef1 100644 --- a/configure.ac +++ b/configure.ac @@ -98,6 +98,7 @@ AC_SUBST([OUR_LDFLAGS], $with_ldflags) AC_CHECK_HEADERS_ONCE([ ctype.h errno.h + linux/netlink.h net/if.h stdarg.h stdio.h diff --git a/src/libnetwork/libnetwork.c b/src/libnetwork/libnetwork.c index 65faa93..17169b3 100644 --- a/src/libnetwork/libnetwork.c +++ b/src/libnetwork/libnetwork.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -214,30 +215,74 @@ struct nl_msg* network_make_netlink_message(struct network_ctx* ctx, return msg; } +struct network_netlink_message_status { + struct network_ctx* ctx; + int r; +}; + static int __nl_ack_handler(struct nl_msg* msg, void* data) { - int* r = data; - *r = 0; + struct network_netlink_message_status* status = data; + status->r = 0; return NL_STOP; } static int __nl_finish_handler(struct nl_msg* msg, void* data) { - int* r = data; - *r = 0; + struct network_netlink_message_status* status = data; + status->r = 0; return NL_SKIP; } +static int __nl_error_handler(struct sockaddr_nl* nla, struct nlmsgerr* err, void* data) { + struct network_netlink_message_status* status = data; + status->r = 0; + + struct nlattr *attrs; + struct nlattr *tb[NLMSGERR_ATTR_MAX + 1]; + struct nlmsghdr* nlh = (struct nlmsghdr*)err - 1; + + size_t len = nlh->nlmsg_len; + size_t ack_len = sizeof(*nlh) + sizeof(int) + sizeof(*nlh); + + status->r = err->error; + if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS)) + return NL_STOP; + + if (!(nlh->nlmsg_flags & NLM_F_CAPPED)) + ack_len += err->msg.nlmsg_len - sizeof(*nlh); + + if (len <= ack_len) + return NL_STOP; + + attrs = (void *)((unsigned char *)nlh + ack_len); + len -= ack_len; + + nla_parse(tb, NLMSGERR_ATTR_MAX, attrs, len, NULL); + if (tb[NLMSGERR_ATTR_MSG]) { + len = strnlen((char *)nla_data(tb[NLMSGERR_ATTR_MSG]), + nla_len(tb[NLMSGERR_ATTR_MSG])); + + ERROR(status->ctx, "Kernel reports: %*s\n", len, + (const char *)nla_data(tb[NLMSGERR_ATTR_MSG])); + } + + return NL_STOP; +} + // Sends a netlink message and calls the handler to handle the result int network_send_netlink_message(struct network_ctx* ctx, struct nl_msg* msg, int(*handler)(struct nl_msg* msg, void* data), void* data) { + struct network_netlink_message_status status; + status.ctx = ctx; + DEBUG(ctx, "Sending netlink message %p\n", msg); // Sending the message - int r = nl_send_auto(ctx->nl_socket, msg); - if (r < 0) { - ERROR(ctx, "Error sending netlink message: %d\n", r); - return r; + status.r = nl_send_auto(ctx->nl_socket, msg); + if (status.r < 0) { + ERROR(ctx, "Error sending netlink message: %d\n", status.r); + return status.r; } // Register callback @@ -249,16 +294,17 @@ int network_send_netlink_message(struct network_ctx* ctx, struct nl_msg* msg, return -1; } - r = 1; + status.r = 1; nl_cb_set(callback, NL_CB_VALID, NL_CB_CUSTOM, handler, data); - nl_cb_set(callback, NL_CB_ACK, NL_CB_CUSTOM, __nl_ack_handler, &r); - nl_cb_set(callback, NL_CB_FINISH, NL_CB_CUSTOM, __nl_finish_handler, &r); + nl_cb_set(callback, NL_CB_ACK, NL_CB_CUSTOM, __nl_ack_handler, &status); + nl_cb_set(callback, NL_CB_FINISH, NL_CB_CUSTOM, __nl_finish_handler, &status); + nl_cb_err(callback, NL_CB_CUSTOM, __nl_error_handler, &status); - while (r > 0) + while (status.r > 0) nl_recvmsgs(ctx->nl_socket, callback); - DEBUG(ctx, "Netlink message returned with status %d\n", r); + DEBUG(ctx, "Netlink message returned with status %d\n", status.r); - return r; + return status.r; } -- 2.47.3