Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netlink/netlink_message_parser.c
39475 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2022 Alexander V. Chernikov <[email protected]>
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
*
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
* SUCH DAMAGE.
26
*/
27
28
#include <sys/cdefs.h>
29
#include "opt_inet.h"
30
#include "opt_inet6.h"
31
#include <sys/types.h>
32
#include <sys/malloc.h>
33
#include <sys/rmlock.h>
34
#include <sys/socket.h>
35
#include <sys/stdarg.h>
36
37
#include <net/if.h>
38
#include <net/route.h>
39
#include <net/route/nhop.h>
40
41
#include <net/route/route_ctl.h>
42
#include <netinet/in.h>
43
#include <netlink/netlink.h>
44
#include <netlink/netlink_ctl.h>
45
#include <netlink/netlink_var.h>
46
#include <netlink/netlink_route.h>
47
48
#define DEBUG_MOD_NAME nl_parser
49
#define DEBUG_MAX_LEVEL LOG_DEBUG3
50
#include <netlink/netlink_debug.h>
51
_DECLARE_DEBUG(LOG_INFO);
52
53
bool
54
nlmsg_report_err_msg(struct nl_pstate *npt, const char *fmt, ...)
55
{
56
va_list ap;
57
58
if (npt->err_msg != NULL)
59
return (false);
60
char *buf = npt_alloc(npt, NL_MAX_ERROR_BUF);
61
if (buf == NULL)
62
return (false);
63
va_start(ap, fmt);
64
vsnprintf(buf, NL_MAX_ERROR_BUF, fmt, ap);
65
va_end(ap);
66
67
npt->err_msg = buf;
68
return (true);
69
}
70
71
bool
72
nlmsg_report_err_offset(struct nl_pstate *npt, uint32_t off)
73
{
74
if (npt->err_off != 0)
75
return (false);
76
npt->err_off = off;
77
return (true);
78
}
79
80
void
81
nlmsg_report_cookie(struct nl_pstate *npt, struct nlattr *nla)
82
{
83
MPASS(nla->nla_type == NLMSGERR_ATTR_COOKIE);
84
MPASS(nla->nla_len >= sizeof(struct nlattr));
85
npt->cookie = nla;
86
}
87
88
void
89
nlmsg_report_cookie_u32(struct nl_pstate *npt, uint32_t val)
90
{
91
struct nlattr *nla = npt_alloc(npt, sizeof(*nla) + sizeof(uint32_t));
92
93
nla->nla_type = NLMSGERR_ATTR_COOKIE;
94
nla->nla_len = sizeof(*nla) + sizeof(uint32_t);
95
memcpy(nla + 1, &val, sizeof(uint32_t));
96
nlmsg_report_cookie(npt, nla);
97
}
98
99
static const struct nlattr_parser *
100
search_states(const struct nlattr_parser *ps, u_int pslen, int key)
101
{
102
int left_i = 0, right_i = pslen - 1;
103
104
if (key < ps[0].type || key > ps[pslen - 1].type)
105
return (NULL);
106
107
while (left_i + 1 < right_i) {
108
int mid_i = (left_i + right_i) / 2;
109
if (key < ps[mid_i].type)
110
right_i = mid_i;
111
else if (key > ps[mid_i].type)
112
left_i = mid_i + 1;
113
else
114
return (&ps[mid_i]);
115
}
116
if (ps[left_i].type == key)
117
return (&ps[left_i]);
118
else if (ps[right_i].type == key)
119
return (&ps[right_i]);
120
return (NULL);
121
}
122
123
int
124
nl_parse_attrs_raw(struct nlattr *nla_head, uint16_t len,
125
const struct nlattr_parser *ps, u_int pslen, struct nl_pstate *npt,
126
void *target)
127
{
128
const struct nlattr_parser *s;
129
struct nlattr *nla;
130
uint16_t orig_len, off;
131
int error = 0;
132
133
NL_LOG(LOG_DEBUG3, "parse %p remaining_len %d", nla_head, len);
134
orig_len = len;
135
NLA_FOREACH(nla, nla_head, len) {
136
NL_LOG(LOG_DEBUG3, ">> parsing %p attr_type %u len %u (rem %u)",
137
nla, nla->nla_type, nla->nla_len, len);
138
if (nla->nla_len < sizeof(struct nlattr)) {
139
NLMSG_REPORT_ERR_MSG(npt,
140
"Invalid attr %p type %u len: %u",
141
nla, nla->nla_type, nla->nla_len);
142
off = (char *)nla - (char *)npt->hdr;
143
nlmsg_report_err_offset(npt, off);
144
return (EINVAL);
145
}
146
147
s = search_states(ps, pslen, nla->nla_type & NLA_TYPE_MASK);
148
if (s != NULL) {
149
void *ptr;
150
151
ptr = (void *)((char *)target + s->off);
152
error = s->cb(nla, npt, s->arg, ptr);
153
if (error != 0) {
154
off = (char *)nla - (char *)npt->hdr;
155
nlmsg_report_err_offset(npt, off);
156
NL_LOG(LOG_DEBUG3,
157
"parse failed at offset %u", off);
158
return (error);
159
}
160
} else {
161
/* Ignore non-specified attributes */
162
NL_LOG(LOG_DEBUG3, "ignoring attr %u", nla->nla_type);
163
}
164
}
165
if (len >= sizeof(struct nlattr)) {
166
nla = (struct nlattr *)((char *)nla_head + (orig_len - len));
167
NL_LOG(LOG_DEBUG3, " >>> end %p attr_type %u len %u", nla,
168
nla->nla_type, nla->nla_len);
169
}
170
NL_LOG(LOG_DEBUG3, "end parse: %p remaining_len %u", nla, len);
171
172
return (0);
173
}
174
175
void
176
nl_get_attrs_bmask_raw(struct nlattr *nla_head, uint32_t len,
177
struct nlattr_bmask *bm)
178
{
179
struct nlattr *nla = NULL;
180
uint16_t nla_type;
181
182
BIT_ZERO(NL_ATTR_BMASK_SIZE, bm);
183
184
NLA_FOREACH(nla, nla_head, len) {
185
if (nla->nla_len < sizeof(struct nlattr))
186
return;
187
nla_type = nla->nla_type & NLA_TYPE_MASK;
188
if (nla_type < NL_ATTR_BMASK_SIZE)
189
BIT_SET(NL_ATTR_BMASK_SIZE, nla_type, bm);
190
else
191
NL_LOG(LOG_DEBUG2,
192
"Skipping type %u in the mask: too short",
193
nla_type);
194
}
195
}
196
197
bool
198
nl_has_attr(const struct nlattr_bmask *bm, uint16_t nla_type)
199
{
200
MPASS(nla_type < NL_ATTR_BMASK_SIZE);
201
202
return (BIT_ISSET(NL_ATTR_BMASK_SIZE, nla_type, bm));
203
}
204
205
int
206
nlattr_get_flag(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
207
void *target)
208
{
209
if (__predict_false(NLA_DATA_LEN(nla) != 0)) {
210
NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not a flag",
211
nla->nla_type, NLA_DATA_LEN(nla));
212
return (EINVAL);
213
}
214
215
*((uint8_t *)target) = 1;
216
return (0);
217
}
218
219
static struct sockaddr *
220
parse_rta_ip4(void *rta_data, struct nl_pstate *npt, int *perror)
221
{
222
struct sockaddr_in *sin;
223
224
sin = (struct sockaddr_in *)npt_alloc_sockaddr(npt,
225
sizeof(struct sockaddr_in));
226
if (__predict_false(sin == NULL)) {
227
*perror = ENOBUFS;
228
return (NULL);
229
}
230
sin->sin_len = sizeof(struct sockaddr_in);
231
sin->sin_family = AF_INET;
232
memcpy(&sin->sin_addr, rta_data, sizeof(struct in_addr));
233
return ((struct sockaddr *)sin);
234
}
235
236
static struct sockaddr *
237
parse_rta_ip6(void *rta_data, struct nl_pstate *npt, int *perror)
238
{
239
struct sockaddr_in6 *sin6;
240
241
sin6 = (struct sockaddr_in6 *)npt_alloc_sockaddr(npt,
242
sizeof(struct sockaddr_in6));
243
if (__predict_false(sin6 == NULL)) {
244
*perror = ENOBUFS;
245
return (NULL);
246
}
247
sin6->sin6_len = sizeof(struct sockaddr_in6);
248
sin6->sin6_family = AF_INET6;
249
memcpy(&sin6->sin6_addr, rta_data, sizeof(struct in6_addr));
250
return ((struct sockaddr *)sin6);
251
}
252
253
static struct sockaddr *
254
parse_rta_ip(struct rtattr *rta, struct nl_pstate *npt, int *perror)
255
{
256
void *rta_data = NL_RTA_DATA(rta);
257
int rta_len = NL_RTA_DATA_LEN(rta);
258
259
if (rta_len == sizeof(struct in_addr)) {
260
return (parse_rta_ip4(rta_data, npt, perror));
261
} else if (rta_len == sizeof(struct in6_addr)) {
262
return (parse_rta_ip6(rta_data, npt, perror));
263
} else {
264
NLMSG_REPORT_ERR_MSG(npt, "unknown IP len: %d for rta type %d",
265
rta_len, rta->rta_type);
266
*perror = ENOTSUP;
267
return (NULL);
268
}
269
return (NULL);
270
}
271
272
int
273
nlattr_get_ip(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
274
void *target)
275
{
276
int error = 0;
277
278
struct sockaddr *sa = parse_rta_ip((struct rtattr *)nla, npt, &error);
279
280
*((struct sockaddr **)target) = sa;
281
return (error);
282
}
283
284
static struct sockaddr *
285
parse_rta_via(struct rtattr *rta, struct nl_pstate *npt, int *perror)
286
{
287
struct rtvia *via = NL_RTA_DATA(rta);
288
int data_len = NL_RTA_DATA_LEN(rta);
289
290
if (__predict_false(data_len) < sizeof(struct rtvia)) {
291
NLMSG_REPORT_ERR_MSG(npt, "undersized RTA_VIA(%d) attr: len %d",
292
rta->rta_type, data_len);
293
*perror = EINVAL;
294
return (NULL);
295
}
296
data_len -= offsetof(struct rtvia, rtvia_addr);
297
298
switch (via->rtvia_family) {
299
case AF_INET:
300
if (__predict_false(data_len < sizeof(struct in_addr))) {
301
*perror = EINVAL;
302
return (NULL);
303
}
304
return (parse_rta_ip4(via->rtvia_addr, npt, perror));
305
case AF_INET6:
306
if (__predict_false(data_len < sizeof(struct in6_addr))) {
307
*perror = EINVAL;
308
return (NULL);
309
}
310
return (parse_rta_ip6(via->rtvia_addr, npt, perror));
311
default:
312
*perror = ENOTSUP;
313
return (NULL);
314
}
315
}
316
317
int
318
nlattr_get_ipvia(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
319
void *target)
320
{
321
int error = 0;
322
323
struct sockaddr *sa = parse_rta_via((struct rtattr *)nla, npt, &error);
324
325
*((struct sockaddr **)target) = sa;
326
return (error);
327
}
328
329
int
330
nlattr_get_bool(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
331
void *target)
332
{
333
if (__predict_false(NLA_DATA_LEN(nla) != sizeof(bool))) {
334
NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not bool",
335
nla->nla_type, NLA_DATA_LEN(nla));
336
return (EINVAL);
337
}
338
*((bool *)target) = *((const bool *)NL_RTA_DATA_CONST(nla));
339
return (0);
340
}
341
342
int
343
nlattr_get_uint8(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
344
void *target)
345
{
346
if (__predict_false(NLA_DATA_LEN(nla) != sizeof(uint8_t))) {
347
NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not uint8",
348
nla->nla_type, NLA_DATA_LEN(nla));
349
return (EINVAL);
350
}
351
*((uint8_t *)target) = *((const uint8_t *)NL_RTA_DATA_CONST(nla));
352
return (0);
353
}
354
355
int
356
nlattr_get_uint16(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
357
void *target)
358
{
359
if (__predict_false(NLA_DATA_LEN(nla) != sizeof(uint16_t))) {
360
NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not uint16",
361
nla->nla_type, NLA_DATA_LEN(nla));
362
return (EINVAL);
363
}
364
*((uint16_t *)target) = *((const uint16_t *)NL_RTA_DATA_CONST(nla));
365
return (0);
366
}
367
368
int
369
nlattr_get_uint32(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
370
void *target)
371
{
372
if (__predict_false(NLA_DATA_LEN(nla) != sizeof(uint32_t))) {
373
NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not uint32",
374
nla->nla_type, NLA_DATA_LEN(nla));
375
return (EINVAL);
376
}
377
*((uint32_t *)target) = *((const uint32_t *)NL_RTA_DATA_CONST(nla));
378
return (0);
379
}
380
381
int
382
nlattr_get_uint64(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
383
void *target)
384
{
385
if (__predict_false(NLA_DATA_LEN(nla) != sizeof(uint64_t))) {
386
NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not uint64",
387
nla->nla_type, NLA_DATA_LEN(nla));
388
return (EINVAL);
389
}
390
memcpy(target, NL_RTA_DATA_CONST(nla), sizeof(uint64_t));
391
return (0);
392
}
393
394
int
395
nlattr_get_in_addr(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
396
void *target)
397
{
398
if (__predict_false(NLA_DATA_LEN(nla) != sizeof(in_addr_t))) {
399
NLMSG_REPORT_ERR_MSG(npt,
400
"nla type %d size(%u) is not in_addr_t",
401
nla->nla_type, NLA_DATA_LEN(nla));
402
return (EINVAL);
403
}
404
memcpy(target, NLA_DATA_CONST(nla), sizeof(in_addr_t));
405
return (0);
406
}
407
408
int
409
nlattr_get_in6_addr(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
410
void *target)
411
{
412
if (__predict_false(NLA_DATA_LEN(nla) != sizeof(struct in6_addr))) {
413
NLMSG_REPORT_ERR_MSG(npt,
414
"nla type %d size(%u) is not struct in6_addr",
415
nla->nla_type, NLA_DATA_LEN(nla));
416
return (EINVAL);
417
}
418
memcpy(target, NLA_DATA_CONST(nla), sizeof(struct in6_addr));
419
return (0);
420
}
421
422
static int
423
nlattr_get_ifp_internal(struct nlattr *nla, struct nl_pstate *npt,
424
void *target, bool zero_ok)
425
{
426
struct ifnet *ifp;
427
u_int ifindex;
428
429
if (__predict_false(NLA_DATA_LEN(nla) != sizeof(uint32_t))) {
430
NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not uint32",
431
nla->nla_type, NLA_DATA_LEN(nla));
432
return (EINVAL);
433
}
434
ifindex = *((const u_int *)NLA_DATA_CONST(nla));
435
436
if (ifindex == 0 && zero_ok) {
437
*((struct ifnet **)target) = NULL;
438
return (0);
439
}
440
441
NET_EPOCH_ASSERT();
442
443
ifp = ifnet_byindex(ifindex);
444
if (__predict_false(ifp == NULL)) {
445
NLMSG_REPORT_ERR_MSG(npt, "nla type %d: ifindex %u invalid",
446
nla->nla_type, ifindex);
447
return (ENOENT);
448
}
449
*((struct ifnet **)target) = ifp;
450
NL_LOG(LOG_DEBUG3, "nla type %d: ifindex %u -> %s", nla->nla_type,
451
ifindex, if_name(ifp));
452
453
return (0);
454
}
455
456
int
457
nlattr_get_ifp(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
458
void *target)
459
{
460
return (nlattr_get_ifp_internal(nla, npt, target, false));
461
}
462
463
int
464
nlattr_get_ifpz(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
465
void *target)
466
{
467
return (nlattr_get_ifp_internal(nla, npt, target, true));
468
}
469
470
int
471
nlattr_get_chara(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
472
void *target)
473
{
474
int maxlen = NLA_DATA_LEN(nla);
475
int target_size = (size_t)arg;
476
int len = strnlen((char *)NLA_DATA(nla), maxlen);
477
478
if (__predict_false(len >= maxlen) ||
479
__predict_false(len >= target_size)) {
480
NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not "
481
"NULL-terminated or longer than %u",
482
nla->nla_type, maxlen, target_size);
483
return (EINVAL);
484
}
485
486
strncpy((char *)target, (char *)NLA_DATA(nla), target_size);
487
return (0);
488
}
489
490
int
491
nlattr_get_string(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
492
void *target)
493
{
494
int maxlen = NLA_DATA_LEN(nla);
495
496
if (__predict_false(strnlen((char *)NLA_DATA(nla), maxlen) >= maxlen)) {
497
NLMSG_REPORT_ERR_MSG(npt,
498
"nla type %d size(%u) is not NULL-terminated",
499
nla->nla_type, maxlen);
500
return (EINVAL);
501
}
502
503
*((char **)target) = (char *)NLA_DATA(nla);
504
return (0);
505
}
506
507
int
508
nlattr_get_stringn(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
509
void *target)
510
{
511
int maxlen = NLA_DATA_LEN(nla);
512
513
char *buf = npt_alloc(npt, maxlen + 1);
514
if (buf == NULL)
515
return (ENOMEM);
516
buf[maxlen] = '\0';
517
memcpy(buf, NLA_DATA(nla), maxlen);
518
519
*((char **)target) = buf;
520
return (0);
521
}
522
523
int
524
nlattr_get_bytes(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
525
void *target)
526
{
527
size_t size = (size_t)arg;
528
529
if (NLA_DATA_LEN(nla) != size)
530
return (EINVAL);
531
532
memcpy(target, NLA_DATA(nla), size);
533
534
return (0);
535
}
536
537
int
538
nlattr_get_nla(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
539
void *target)
540
{
541
NL_LOG(LOG_DEBUG3, "STORING %p len %d", nla, nla->nla_len);
542
*((struct nlattr **)target) = nla;
543
return (0);
544
}
545
546
int
547
nlattr_get_nested(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
548
void *target)
549
{
550
const struct nlhdr_parser *p = (const struct nlhdr_parser *)arg;
551
552
/* Assumes target points to the beginning of the structure. */
553
return (nl_parse_header(NLA_DATA(nla), NLA_DATA_LEN(nla), p, npt,
554
target));
555
}
556
557
int
558
nlattr_get_nested_ptr(struct nlattr *nla, struct nl_pstate *npt,
559
const void *arg, void *target)
560
{
561
const struct nlhdr_parser *p = (const struct nlhdr_parser *)arg;
562
563
/* Assumes target points to the beginning of the structure. */
564
return (nl_parse_header(NLA_DATA(nla), NLA_DATA_LEN(nla), p, npt,
565
*(void **)target));
566
}
567
568
int
569
nlf_get_ifp(void *src, struct nl_pstate *npt, void *target)
570
{
571
struct ifnet *ifp;
572
u_int ifindex;
573
574
NET_EPOCH_ASSERT();
575
576
ifindex = *((const u_int *)src);
577
ifp = ifnet_byindex(ifindex);
578
if (ifp == NULL) {
579
NL_LOG(LOG_DEBUG, "ifindex %u invalid", ifindex);
580
return (ENOENT);
581
}
582
*((struct ifnet **)target) = ifp;
583
584
return (0);
585
}
586
587
int
588
nlf_get_ifpz(void *src, struct nl_pstate *npt, void *target)
589
{
590
struct ifnet *ifp;
591
u_int ifindex;
592
593
NET_EPOCH_ASSERT();
594
595
ifindex = *((const u_int *)src);
596
ifp = ifnet_byindex(ifindex);
597
if (ifindex != 0 && ifp == NULL) {
598
NL_LOG(LOG_DEBUG, "ifindex %u invalid", ifindex);
599
return (ENOENT);
600
}
601
*((struct ifnet **)target) = ifp;
602
603
return (0);
604
}
605
606
int
607
nlf_get_u8(void *src, struct nl_pstate *npt, void *target)
608
{
609
uint8_t val = *((const uint8_t *)src);
610
611
*((uint8_t *)target) = val;
612
613
return (0);
614
}
615
616
int
617
nlf_get_u8_u32(void *src, struct nl_pstate *npt, void *target)
618
{
619
*((uint32_t *)target) = *((const uint8_t *)src);
620
return (0);
621
}
622
623
int
624
nlf_get_u16(void *src, struct nl_pstate *npt, void *target)
625
{
626
*((uint16_t *)target) = *((const uint16_t *)src);
627
return (0);
628
}
629
630
int
631
nlf_get_u32(void *src, struct nl_pstate *npt, void *target)
632
{
633
*((uint32_t *)target) = *((const uint32_t *)src);
634
return (0);
635
}
636
637