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