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