Skip to content

Commit

Permalink
kernel_xfrm: record extended ack from netlink response
Browse files Browse the repository at this point in the history
This enables pluto to log any error message reported through extended
ACK attributes[1] in a netlink response, to make diagnostic easier
when an error occurs.  Suggested by Sabrina Dubroca.

1. https://docs.kernel.org/userspace-api/netlink/intro.html#ext-ack

Signed-off-by: Daiki Ueno <dueno@redhat.com>
  • Loading branch information
ueno committed May 24, 2024
1 parent da6f564 commit 6ec5c74
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 0 deletions.
4 changes: 4 additions & 0 deletions include/netlink_attrib.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,8 @@ void nl_addattrstrz(struct nlmsghdr *n, int maxlen, int type,
const char *str);
void nl_addattr32(struct nlmsghdr *n, int maxlen, int type, const uint32_t data);

const struct nlattr *nl_getattr(const struct nlmsghdr *n, size_t *offset);
const char *nl_getattrvalstrz(const struct nlmsghdr *n,
const struct nlattr *attr);

#endif
29 changes: 29 additions & 0 deletions lib/libswan/netlink_attrib.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,32 @@ void nl_addattr32(struct nlmsghdr *n, int maxlen, int type, const uint32_t data)
{
nl_addattr_l(n, maxlen, type, &data, sizeof(uint32_t));
}

const struct nlattr *nl_getattr(const struct nlmsghdr *n, size_t *offset)
{
struct nlattr *attr = (void *)n + NLMSG_HDRLEN + NLMSG_ALIGN(*offset);
struct nlattr *tail = (void *)n + NLMSG_ALIGN(n->nlmsg_len);

if (attr == tail) {
return NULL;
}

*offset += NLA_ALIGN(attr->nla_len);
return attr;
}

const char *nl_getattrvalstrz(const struct nlmsghdr *n,
const struct nlattr *attr)
{
struct nlattr *tail = (void *)n + NLMSG_ALIGN(n->nlmsg_len);

ptrdiff_t len = (void *)tail - (void *)attr;
if (len < (ptrdiff_t)sizeof(struct nlattr) ||
attr->nla_len <= sizeof(struct nlattr) ||
attr->nla_len > len ||
!memchr(attr + NLA_HDRLEN, '\0', attr->nla_len - NLA_HDRLEN)) {
return NULL;
}

return (void *)attr + NLA_HDRLEN;
}
49 changes: 49 additions & 0 deletions programs/pluto/kernel_xfrm.c
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,19 @@ static void kernel_xfrm_init(struct logger *logger)
"socket() in init_netlink()");
}

static const int on = true;

if (setsockopt(nl_send_fd, SOL_NETLINK, NETLINK_CAP_ACK,
(const void *)&on, sizeof(on)) < 0) {
llog_errno(DEBUG_STREAM, logger, errno,
"setsockopt NETLINK_CAP_ACK in kernel_xfrm_init()");
}
if (setsockopt(nl_send_fd, SOL_NETLINK, NETLINK_EXT_ACK,
(const void *)&on, sizeof(on)) < 0) {
llog_errno(DEBUG_STREAM, logger, errno,
"setsockopt NETLINK_EXT_ACK in kernel_xfrm_init()");
}

init_netlink_rtm_fd(logger);
init_netlink_xfrm_fd(logger);

Expand Down Expand Up @@ -387,6 +400,36 @@ static void kernel_xfrm_flush(struct logger *logger)
&recv_errno, logger);
}

static void print_ext_ack(const struct nlmsghdr *n, struct jambuf *buf)
{
if (n->nlmsg_type != NLMSG_ERROR ||
!(n->nlmsg_flags & NLM_F_ACK_TLVS)) {
return;
}

struct nlmsgerr *err = (void *)n + NLMSG_HDRLEN;
size_t offset = sizeof(*err);
if (!(n->nlmsg_flags & NLM_F_CAPPED)) {
offset += err->msg.nlmsg_len - NLMSG_HDRLEN;
}

bool first = true;
for (const struct nlattr *attr = nl_getattr(n, &offset);
attr != NULL; attr = nl_getattr(n, &offset)) {
if ((attr->nla_type & NLA_TYPE_MASK) == NLMSGERR_ATTR_MSG) {
const char *msg = nl_getattrvalstrz(n, attr);
if (msg) {
if (first) {
jam(buf, "netlink ext_ack: %s", msg);
first = false;
} else {
jam(buf, "; %s", msg);
}
}
}
}
}

/*
* sendrecv_xfrm_msg()
*
Expand Down Expand Up @@ -505,6 +548,9 @@ static bool sendrecv_xfrm_msg(struct nlmsghdr *hdr,
if (rsp.u.e.error != 0) {
llog_error(logger, -rsp.u.e.error,
"netlink response for %s %s", description, story);
LLOG_JAMBUF(RC_LOG, logger, buf) {
print_ext_ack(&rsp.n, buf);
}
return false;
}
/*
Expand All @@ -515,6 +561,9 @@ static bool sendrecv_xfrm_msg(struct nlmsghdr *hdr,
*/
ldbg(logger, "%s() netlink response for %s %s included non-error error",
__func__, description, story);
LDBGP_JAMBUF(DBG_BASE, logger, buf) {
print_ext_ack(&rsp.n, buf);
}
/* ignore */
}
if (rbuf == NULL) {
Expand Down

0 comments on commit 6ec5c74

Please sign in to comment.