xref: /freebsd/lib/libsysdecode/netlink.c (revision 8ef0093f297af7c917037f058af9813105e67662)
1 /*
2  * Copyright (c) 2026 Ishan Agrawal
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  */
6 
7 #include <sys/param.h>
8 #include <netlink/netlink.h>
9 
10 #include <stdio.h>
11 #include <stdbool.h>
12 #include <stddef.h>
13 
14 #include "sysdecode.h"
15 
16 /*
17  * Decodes a buffer as a Netlink message stream.
18  *
19  * Returns true if the data was successfully decoded as Netlink.
20  * Returns false if the data is malformed, allowing the caller
21  * to fallback to a standard hex/string dump.
22  */
23 bool
sysdecode_netlink(FILE * fp,const void * buf,size_t len)24 sysdecode_netlink(FILE *fp, const void *buf, size_t len)
25 {
26 	const struct nlmsghdr *nl = buf;
27 	size_t remaining = len;
28 	bool first = true;
29 
30 	/* Basic sanity check: Buffer must be at least one header size. */
31 	if (remaining < sizeof(struct nlmsghdr))
32 		return (false);
33 
34 	/* * Protocol Sanity Check:
35 	 * The first message length must be valid (>= header) and fit
36 	 * inside the provided buffer snapshot.
37 	 */
38 	if (nl->nlmsg_len < sizeof(struct nlmsghdr) || nl->nlmsg_len > remaining)
39 		return (false);
40 
41 	fprintf(fp, "netlink{");
42 
43 	while (remaining >= sizeof(struct nlmsghdr)) {
44 		if (!first)
45 			fprintf(fp, ",");
46 
47 		/* Safety check for current message. */
48 		if (nl->nlmsg_len < sizeof(struct nlmsghdr) ||
49 		    nl->nlmsg_len > remaining) {
50 			fprintf(fp, "<truncated>");
51 			break;
52 		}
53 
54 		fprintf(fp, "len=%u,type=", nl->nlmsg_len);
55 
56 		/* Decode Standard Message Types. */
57 		switch (nl->nlmsg_type) {
58 		case NLMSG_NOOP:
59 			fprintf(fp, "NLMSG_NOOP");
60 			break;
61 		case NLMSG_ERROR:
62 			fprintf(fp, "NLMSG_ERROR");
63 			break;
64 		case NLMSG_DONE:
65 			fprintf(fp, "NLMSG_DONE");
66 			break;
67 		case NLMSG_OVERRUN:
68 			fprintf(fp, "NLMSG_OVERRUN");
69 			break;
70 		default:
71 			fprintf(fp, "%u", nl->nlmsg_type);
72 			break;
73 		}
74 
75 		fprintf(fp, ",flags=");
76 		/* TODO: decode flags symbolically using sysdecode_mask. */
77 		fprintf(fp, "0x%x", nl->nlmsg_flags);
78 
79 		fprintf(fp, ",seq=%u,pid=%u", nl->nlmsg_seq, nl->nlmsg_pid);
80 
81 		/* Handle Alignment (Netlink messages are 4-byte aligned). */
82 		size_t aligned_len = NLMSG_ALIGN(nl->nlmsg_len);
83 		if (aligned_len > remaining)
84 			remaining = 0;
85 		else
86 			remaining -= aligned_len;
87 
88 		nl = (const struct nlmsghdr *)(const void *)((const char *)nl + aligned_len);
89 		first = false;
90 	}
91 
92 	fprintf(fp, "}");
93 	return (true);
94 }
95