Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/net/routing/rtsock_common.h
39604 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2019 Alexander V. Chernikov
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
#ifndef _NET_ROUTING_RTSOCK_COMMON_H_
29
#define _NET_ROUTING_RTSOCK_COMMON_H_
30
31
#include <stdio.h>
32
#include <stdlib.h>
33
#include <string.h>
34
#include <unistd.h>
35
#include <fcntl.h>
36
#include <stdbool.h>
37
#include <ctype.h>
38
#include <poll.h>
39
40
#include <sys/types.h>
41
#include <sys/time.h>
42
#include <sys/param.h>
43
#include <sys/socket.h>
44
#include <sys/ioctl.h>
45
#include <sys/jail.h>
46
#include <sys/linker.h>
47
#include <net/if.h>
48
#include <net/if_dl.h>
49
#include <net/route.h>
50
51
#include <arpa/inet.h>
52
#include <net/ethernet.h>
53
54
#include <netinet/in.h>
55
#include <netinet6/in6_var.h>
56
#include <netinet6/nd6.h>
57
58
#include <ifaddrs.h>
59
60
#include <errno.h>
61
#include <err.h>
62
#include <sysexits.h>
63
64
#include <atf-c.h>
65
#include "freebsd_test_suite/macros.h"
66
67
#include "rtsock_print.h"
68
#include "params.h"
69
70
void rtsock_update_rtm_len(struct rt_msghdr *rtm);
71
void rtsock_validate_message(char *buffer, ssize_t len);
72
void rtsock_add_rtm_sa(struct rt_msghdr *rtm, int addr_type, struct sockaddr *sa);
73
74
void file_append_line(char *fname, char *text);
75
76
static int _rtm_seq = 42;
77
78
79
/*
80
* Checks if the interface cloner module is present for @name.
81
*/
82
static int
83
_check_cloner(char *name)
84
{
85
struct if_clonereq ifcr;
86
char *cp, *buf;
87
int idx;
88
int s;
89
int found = 0;
90
91
s = socket(AF_LOCAL, SOCK_DGRAM, 0);
92
if (s == -1)
93
err(1, "socket(AF_LOCAL,SOCK_DGRAM)");
94
95
memset(&ifcr, 0, sizeof(ifcr));
96
97
if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
98
err(1, "SIOCIFGCLONERS for count");
99
100
buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
101
if (buf == NULL)
102
err(1, "unable to allocate cloner name buffer");
103
104
ifcr.ifcr_count = ifcr.ifcr_total;
105
ifcr.ifcr_buffer = buf;
106
107
if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
108
err(1, "SIOCIFGCLONERS for names");
109
110
/*
111
* In case some disappeared in the mean time, clamp it down.
112
*/
113
if (ifcr.ifcr_count > ifcr.ifcr_total)
114
ifcr.ifcr_count = ifcr.ifcr_total;
115
116
for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {
117
if (!strcmp(cp, name)) {
118
found = 1;
119
break;
120
}
121
}
122
123
free(buf);
124
close(s);
125
126
return (found);
127
}
128
129
static char *
130
iface_create(char *ifname_orig)
131
{
132
struct ifreq ifr;
133
int s;
134
char prefix[IFNAMSIZ], ifname[IFNAMSIZ], *result;
135
136
char *src, *dst;
137
for (src = ifname_orig, dst = prefix; *src && isalpha(*src); src++)
138
*dst++ = *src;
139
*dst = '\0';
140
141
memset(&ifr, 0, sizeof(struct ifreq));
142
143
s = socket(AF_LOCAL, SOCK_DGRAM, 0);
144
strlcpy(ifr.ifr_name, ifname_orig, sizeof(ifr.ifr_name));
145
146
RLOG("creating iface %s %s", prefix, ifr.ifr_name);
147
if (ioctl(s, SIOCIFCREATE2, &ifr) < 0)
148
err(1, "SIOCIFCREATE2");
149
150
strlcpy(ifname, ifr.ifr_name, IFNAMSIZ);
151
RLOG("created interface %s", ifname);
152
153
result = strdup(ifname);
154
155
file_append_line(IFACES_FNAME, ifname);
156
if (strstr(ifname, "epair") == ifname) {
157
/* call returned epairXXXa, need to add epairXXXb */
158
ifname[strlen(ifname) - 1] = 'b';
159
file_append_line(IFACES_FNAME, ifname);
160
}
161
162
return (result);
163
}
164
165
static int
166
iface_destroy(char *ifname)
167
{
168
struct ifreq ifr;
169
int s;
170
171
s = socket(AF_LOCAL, SOCK_DGRAM, 0);
172
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
173
174
RLOG("destroying interface %s", ifname);
175
if (ioctl(s, SIOCIFDESTROY, &ifr) < 0)
176
return (0);
177
178
return (1);
179
}
180
181
/*
182
* Open tunneling device such as tuntap and returns fd.
183
*/
184
int
185
iface_open(char *ifname)
186
{
187
char path[256];
188
189
snprintf(path, sizeof(path), "/dev/%s", ifname);
190
191
RLOG("opening interface %s", ifname);
192
int fd = open(path, O_RDWR|O_EXCL);
193
if (fd == -1) {
194
RLOG_ERRNO("unable to open interface %s", ifname);
195
return (-1);
196
}
197
198
return (fd);
199
}
200
201
/*
202
* Sets primary IPv4 addr.
203
* Returns 0 on success.
204
*/
205
static inline int
206
iface_setup_addr(char *ifname, char *addr, int plen)
207
{
208
char cmd[512];
209
char *af;
210
211
if (strchr(addr, ':'))
212
af = "inet6";
213
else
214
af = "inet";
215
RLOG("setting af_%s %s/%d on %s", af, addr, plen, ifname);
216
snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s %s %s/%d", ifname,
217
af, addr, plen);
218
219
return system(cmd);
220
}
221
222
/*
223
* Removes primary IPv4 prefix.
224
* Returns 0 on success.
225
*/
226
static inline int
227
iface_delete_addr(char *ifname, char *addr)
228
{
229
char cmd[512];
230
231
if (strchr(addr, ':')) {
232
RLOG("removing IPv6 %s from %s", addr, ifname);
233
snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s inet6 %s delete", ifname, addr);
234
} else {
235
RLOG("removing IPv4 %s from %s", addr, ifname);
236
snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s -alias %s", ifname, addr);
237
}
238
239
return system(cmd);
240
}
241
242
int
243
iface_turn_up(char *ifname)
244
{
245
struct ifreq ifr;
246
int s;
247
248
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
249
RLOG_ERRNO("socket");
250
return (-1);
251
}
252
memset(&ifr, 0, sizeof(struct ifreq));
253
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
254
if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
255
RLOG_ERRNO("ioctl(SIOCGIFFLAGS)");
256
return (-1);
257
}
258
/* Update flags */
259
if ((ifr.ifr_flags & IFF_UP) == 0) {
260
ifr.ifr_flags |= IFF_UP;
261
if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
262
RLOG_ERRNO("ioctl(SIOSGIFFLAGS)");
263
return (-1);
264
}
265
RLOG("turned interface %s up", ifname);
266
}
267
268
return (0);
269
}
270
271
/*
272
* Removes ND6_IFF_IFDISABLED from IPv6 interface flags.
273
* Returns 0 on success.
274
*/
275
int
276
iface_enable_ipv6(char *ifname)
277
{
278
struct in6_ndireq nd;
279
int s;
280
281
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
282
err(1, "socket");
283
}
284
memset(&nd, 0, sizeof(nd));
285
strlcpy(nd.ifname, ifname, sizeof(nd.ifname));
286
if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
287
RLOG_ERRNO("ioctl(SIOCGIFINFO_IN6)");
288
return (-1);
289
}
290
/* Update flags */
291
if ((nd.ndi.flags & ND6_IFF_IFDISABLED) != 0) {
292
nd.ndi.flags &= ~ND6_IFF_IFDISABLED;
293
if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd) < 0) {
294
RLOG_ERRNO("ioctl(SIOCSIFINFO_IN6)");
295
return (-1);
296
}
297
RLOG("enabled IPv6 for %s", ifname);
298
}
299
300
return (0);
301
}
302
303
void
304
file_append_line(char *fname, char *text)
305
{
306
FILE *f;
307
308
f = fopen(fname, "a");
309
fputs(text, f);
310
fputs("\n", f);
311
fclose(f);
312
}
313
314
static int
315
vnet_wait_interface(char *vnet_name, char *ifname)
316
{
317
char buf[512], cmd[512], *line, *token;
318
FILE *fp;
319
int i;
320
321
snprintf(cmd, sizeof(cmd), "/usr/sbin/jexec %s /sbin/ifconfig -l", vnet_name);
322
for (int i = 0; i < 50; i++) {
323
fp = popen(cmd, "r");
324
line = fgets(buf, sizeof(buf), fp);
325
/* cut last\n */
326
if (line[0])
327
line[strlen(line)-1] = '\0';
328
while ((token = strsep(&line, " ")) != NULL) {
329
if (strcmp(token, ifname) == 0)
330
return (1);
331
}
332
333
/* sleep 100ms */
334
usleep(1000 * 100);
335
}
336
337
return (0);
338
}
339
340
void
341
vnet_switch(char *vnet_name, char **ifnames, int count)
342
{
343
char buf[512], cmd[512], *line;
344
FILE *fp;
345
int jid, len, ret;
346
347
RLOG("switching to vnet %s with interface(s) %s", vnet_name, ifnames[0]);
348
len = snprintf(cmd, sizeof(cmd),
349
"/usr/sbin/jail -i -c name=%s persist vnet", vnet_name);
350
for (int i = 0; i < count && len < sizeof(cmd); i++) {
351
len += snprintf(&cmd[len], sizeof(cmd) - len,
352
" vnet.interface=%s", ifnames[i]);
353
}
354
RLOG("jail cmd: \"%s\"\n", cmd);
355
356
fp = popen(cmd, "r");
357
if (fp == NULL)
358
atf_tc_fail("jail creation failed");
359
line = fgets(buf, sizeof(buf), fp);
360
if (line == NULL)
361
atf_tc_fail("empty output from jail(8)");
362
jid = strtol(line, NULL, 10);
363
if (jid <= 0) {
364
atf_tc_fail("invalid jail output: %s", line);
365
}
366
367
RLOG("created jail jid=%d", jid);
368
file_append_line(JAILS_FNAME, vnet_name);
369
370
/* Wait while interface appearsh inside vnet */
371
for (int i = 0; i < count; i++) {
372
if (vnet_wait_interface(vnet_name, ifnames[i]))
373
continue;
374
atf_tc_fail("unable to move interface %s to jail %s",
375
ifnames[i], vnet_name);
376
}
377
378
if (jail_attach(jid) == -1) {
379
RLOG_ERRNO("jail %s attach failed: ret=%d", vnet_name, errno);
380
atf_tc_fail("jail attach failed");
381
}
382
383
RLOG("attached to the jail");
384
}
385
386
void
387
vnet_switch_one(char *vnet_name, char *ifname)
388
{
389
char *ifnames[1];
390
391
ifnames[0] = ifname;
392
vnet_switch(vnet_name, ifnames, 1);
393
}
394
395
396
#define SA_F_IGNORE_IFNAME 0x01
397
#define SA_F_IGNORE_IFTYPE 0x02
398
#define SA_F_IGNORE_MEMCMP 0x04
399
int
400
sa_equal_msg_flags(const struct sockaddr *a, const struct sockaddr *b, char *msg, size_t sz, int flags)
401
{
402
char a_s[64], b_s[64];
403
const struct sockaddr_in *a4, *b4;
404
const struct sockaddr_in6 *a6, *b6;
405
const struct sockaddr_dl *al, *bl;
406
407
if (a == NULL) {
408
snprintf(msg, sz, "first sa is NULL");
409
return 0;
410
}
411
if (b == NULL) {
412
snprintf(msg, sz, "second sa is NULL");
413
return 0;
414
}
415
416
if (a->sa_family != b->sa_family) {
417
snprintf(msg, sz, "family: %d vs %d", a->sa_family, b->sa_family);
418
return 0;
419
}
420
if (a->sa_len != b->sa_len) {
421
snprintf(msg, sz, "len: %d vs %d", a->sa_len, b->sa_len);
422
return 0;
423
}
424
425
switch (a->sa_family) {
426
case AF_INET:
427
a4 = (const struct sockaddr_in *)a;
428
b4 = (const struct sockaddr_in *)b;
429
if (a4->sin_addr.s_addr != b4->sin_addr.s_addr) {
430
inet_ntop(AF_INET, &a4->sin_addr, a_s, sizeof(a_s));
431
inet_ntop(AF_INET, &b4->sin_addr, b_s, sizeof(b_s));
432
snprintf(msg, sz, "addr diff: %s vs %s", a_s, b_s);
433
return 0;
434
}
435
if (a4->sin_port != b4->sin_port) {
436
snprintf(msg, sz, "port diff: %d vs %d",
437
ntohs(a4->sin_port), ntohs(b4->sin_port));
438
//return 0;
439
}
440
const uint32_t *a32, *b32;
441
a32 = (const uint32_t *)a4->sin_zero;
442
b32 = (const uint32_t *)b4->sin_zero;
443
if ((*a32 != *b32) || (*(a32 + 1) != *(b32 + 1))) {
444
snprintf(msg, sz, "zero diff: 0x%08X%08X vs 0x%08X%08X",
445
ntohl(*a32), ntohl(*(a32 + 1)),
446
ntohl(*b32), ntohl(*(b32 + 1)));
447
return 0;
448
}
449
return 1;
450
case AF_INET6:
451
a6 = (const struct sockaddr_in6 *)a;
452
b6 = (const struct sockaddr_in6 *)b;
453
if (!IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr)) {
454
inet_ntop(AF_INET6, &a6->sin6_addr, a_s, sizeof(a_s));
455
inet_ntop(AF_INET6, &b6->sin6_addr, b_s, sizeof(b_s));
456
snprintf(msg, sz, "addr diff: %s vs %s", a_s, b_s);
457
return 0;
458
}
459
if (a6->sin6_scope_id != b6->sin6_scope_id) {
460
snprintf(msg, sz, "scope diff: %u vs %u", a6->sin6_scope_id, b6->sin6_scope_id);
461
return 0;
462
}
463
break;
464
case AF_LINK:
465
al = (const struct sockaddr_dl *)a;
466
bl = (const struct sockaddr_dl *)b;
467
468
if (al->sdl_index != bl->sdl_index) {
469
snprintf(msg, sz, "sdl_index diff: %u vs %u", al->sdl_index, bl->sdl_index);
470
return 0;
471
}
472
473
if ((al->sdl_alen != bl->sdl_alen) || (memcmp(LLADDR(al), LLADDR(bl), al->sdl_alen) != 0)) {
474
char abuf[64], bbuf[64];
475
sa_print_hd(abuf, sizeof(abuf), LLADDR(al), al->sdl_alen);
476
sa_print_hd(bbuf, sizeof(bbuf), LLADDR(bl), bl->sdl_alen);
477
snprintf(msg, sz, "sdl_alen diff: {%s} (%d) vs {%s} (%d)",
478
abuf, al->sdl_alen, bbuf, bl->sdl_alen);
479
return 0;
480
}
481
482
if (((flags & SA_F_IGNORE_IFTYPE) == 0) && (al->sdl_type != bl->sdl_type)) {
483
snprintf(msg, sz, "sdl_type diff: %u vs %u", al->sdl_type, bl->sdl_type);
484
return 0;
485
}
486
487
if (((flags & SA_F_IGNORE_IFNAME) == 0) && ((al->sdl_nlen != bl->sdl_nlen) ||
488
(memcmp(al->sdl_data, bl->sdl_data, al->sdl_nlen) != 0))) {
489
char abuf[64], bbuf[64];
490
memcpy(abuf, al->sdl_data, al->sdl_nlen);
491
abuf[al->sdl_nlen] = '\0';
492
memcpy(bbuf, bl->sdl_data, bl->sdl_nlen);
493
abuf[bl->sdl_nlen] = '\0';
494
snprintf(msg, sz, "sdl_nlen diff: {%s} (%d) vs {%s} (%d)",
495
abuf, al->sdl_nlen, bbuf, bl->sdl_nlen);
496
return 0;
497
}
498
499
if (flags & SA_F_IGNORE_MEMCMP)
500
return 1;
501
break;
502
}
503
504
if (memcmp(a, b, a->sa_len)) {
505
int i;
506
for (i = 0; i < a->sa_len; i++)
507
if (((const char *)a)[i] != ((const char *)b)[i])
508
break;
509
510
sa_print(a, 1);
511
sa_print(b, 1);
512
513
snprintf(msg, sz, "overall memcmp() reports diff for af %d offset %d",
514
a->sa_family, i);
515
return 0;
516
}
517
return 1;
518
}
519
520
int
521
sa_equal_msg(const struct sockaddr *a, const struct sockaddr *b, char *msg, size_t sz)
522
{
523
524
return sa_equal_msg_flags(a, b, msg, sz, 0);
525
}
526
527
void
528
sa_fill_mask4(struct sockaddr_in *sin, int plen)
529
{
530
531
memset(sin, 0, sizeof(struct sockaddr_in));
532
sin->sin_family = AF_INET;
533
sin->sin_len = sizeof(struct sockaddr_in);
534
sin->sin_addr.s_addr = htonl(plen ? ~((1 << (32 - plen)) - 1) : 0);
535
}
536
537
void
538
sa_fill_mask6(struct sockaddr_in6 *sin6, uint8_t mask)
539
{
540
uint32_t *cp;
541
542
memset(sin6, 0, sizeof(struct sockaddr_in6));
543
sin6->sin6_family = AF_INET6;
544
sin6->sin6_len = sizeof(struct sockaddr_in6);
545
546
for (cp = (uint32_t *)&sin6->sin6_addr; mask >= 32; mask -= 32)
547
*cp++ = 0xFFFFFFFF;
548
if (mask > 0)
549
*cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0);
550
}
551
552
/* 52:54:00:14:e3:10 */
553
#define ETHER_MAC_MAX_LENGTH 17
554
555
int
556
sa_convert_str_to_sa(const char *_addr, struct sockaddr *sa)
557
{
558
int error;
559
560
int af = AF_UNSPEC;
561
562
char *addr = strdup(_addr);
563
int retcode = 0;
564
565
/* classify AF by str */
566
if (strchr(addr, ':')) {
567
/* inet6 or ether */
568
char *k;
569
int delim_cnt = 0;
570
for (k = addr; *k; k++)
571
if (*k == ':')
572
delim_cnt++;
573
af = AF_INET6;
574
575
if (delim_cnt == 5) {
576
k = strchr(addr, '%');
577
if (k != NULL && (k - addr) <= ETHER_MAC_MAX_LENGTH)
578
af = AF_LINK;
579
}
580
} else if (strchr(addr, '.'))
581
af = AF_INET;
582
583
/* */
584
char *delimiter;
585
int ifindex = 0;
586
char *ifname = NULL;
587
if ((delimiter = strchr(addr, '%')) != NULL) {
588
*delimiter = '\0';
589
ifname = delimiter + 1;
590
ifindex = if_nametoindex(ifname);
591
if (ifindex == 0)
592
RLOG("unable to find ifindex for '%s'", ifname);
593
else
594
RLOG("if %s mapped to %d", ifname, ifindex);
595
}
596
597
if (af == AF_INET6) {
598
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
599
memset(sin6, 0, sizeof(struct sockaddr_in6));
600
sin6->sin6_family = AF_INET6;
601
sin6->sin6_len = sizeof(struct sockaddr_in6);
602
sin6->sin6_scope_id = ifindex;
603
error = inet_pton(AF_INET6, addr, &sin6->sin6_addr);
604
if (error != 1)
605
RLOG_ERRNO("inet_ntop() failed: ret=%d", error);
606
else
607
retcode = 1;
608
} else if (af == AF_INET) {
609
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
610
memset(sin, 0, sizeof(struct sockaddr_in));
611
sin->sin_family = AF_INET;
612
sin->sin_len = sizeof(struct sockaddr_in);
613
error = inet_pton(AF_INET, addr, &sin->sin_addr);
614
if (error != 1)
615
RLOG("inet_ntop() failed: ret=%d", error);
616
else
617
retcode = 1;
618
} else if (af == AF_LINK) {
619
struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
620
memset(sdl, 0, sizeof(struct sockaddr_dl));
621
sdl->sdl_family = AF_LINK;
622
sdl->sdl_len = sizeof(struct sockaddr_dl);
623
sdl->sdl_index = ifindex;
624
sdl->sdl_alen = 6;
625
struct ether_addr *ea = (struct ether_addr *)LLADDR(sdl);
626
if (ether_aton_r(addr, ea) == NULL)
627
RLOG("ether_aton() failed");
628
else
629
retcode = 1;
630
}
631
632
return (retcode);
633
}
634
635
636
int
637
rtsock_setup_socket()
638
{
639
int fd;
640
int af = AF_UNSPEC; /* 0 to capture messages from all AFs */
641
fd = socket(PF_ROUTE, SOCK_RAW, af);
642
643
ATF_REQUIRE_MSG(fd != -1, "rtsock open failed: %s", strerror(errno));
644
645
/* Listen for our messages */
646
int on = 1;
647
if (setsockopt(fd, SOL_SOCKET,SO_USELOOPBACK, &on, sizeof(on)) < 0)
648
RLOG_ERRNO("setsockopt failed");
649
650
return (fd);
651
}
652
653
ssize_t
654
rtsock_send_rtm(int fd, struct rt_msghdr *rtm)
655
{
656
int my_errno;
657
ssize_t len;
658
659
rtsock_update_rtm_len(rtm);
660
661
len = write(fd, rtm, rtm->rtm_msglen);
662
my_errno = errno;
663
RTSOCK_ATF_REQUIRE_MSG(rtm, len == rtm->rtm_msglen,
664
"rtsock write failed: want %d got %zd (%s)",
665
rtm->rtm_msglen, len, strerror(my_errno));
666
667
return (len);
668
}
669
670
struct rt_msghdr *
671
rtsock_read_rtm(int fd, char *buffer, size_t buflen)
672
{
673
ssize_t len;
674
struct pollfd pfd;
675
int poll_delay = 5 * 1000; /* 5 seconds */
676
677
/* Check for the data available to read first */
678
memset(&pfd, 0, sizeof(pfd));
679
pfd.fd = fd;
680
pfd.events = POLLIN;
681
682
if (poll(&pfd, 1, poll_delay) == 0)
683
ATF_REQUIRE_MSG(1 == 0, "rtsock read timed out (%d seconds passed)",
684
poll_delay / 1000);
685
686
len = read(fd, buffer, buflen);
687
int my_errno = errno;
688
ATF_REQUIRE_MSG(len > 0, "rtsock read failed: %s", strerror(my_errno));
689
690
rtsock_validate_message(buffer, len);
691
return ((struct rt_msghdr *)buffer);
692
}
693
694
struct rt_msghdr *
695
rtsock_read_rtm_reply(int fd, char *buffer, size_t buflen, int seq)
696
{
697
struct rt_msghdr *rtm;
698
int found = 0;
699
700
while (true) {
701
rtm = rtsock_read_rtm(fd, buffer, buflen);
702
if (rtm->rtm_pid == getpid() && rtm->rtm_seq == seq)
703
found = 1;
704
if (found)
705
RLOG("--- MATCHED RTSOCK MESSAGE ---");
706
else
707
RLOG("--- SKIPPED RTSOCK MESSAGE ---");
708
rtsock_print_rtm(rtm);
709
if (found)
710
return (rtm);
711
}
712
713
/* NOTREACHED */
714
}
715
716
void
717
rtsock_prepare_route_message_base(struct rt_msghdr *rtm, int cmd)
718
{
719
720
memset(rtm, 0, sizeof(struct rt_msghdr));
721
rtm->rtm_type = cmd;
722
rtm->rtm_version = RTM_VERSION;
723
rtm->rtm_seq = _rtm_seq++;
724
}
725
726
void
727
rtsock_prepare_route_message(struct rt_msghdr *rtm, int cmd, struct sockaddr *dst,
728
struct sockaddr *mask, struct sockaddr *gw)
729
{
730
731
rtsock_prepare_route_message_base(rtm, cmd);
732
if (dst != NULL)
733
rtsock_add_rtm_sa(rtm, RTA_DST, dst);
734
735
if (gw != NULL) {
736
rtsock_add_rtm_sa(rtm, RTA_GATEWAY, gw);
737
rtm->rtm_flags |= RTF_GATEWAY;
738
}
739
740
if (mask != NULL)
741
rtsock_add_rtm_sa(rtm, RTA_NETMASK, mask);
742
}
743
744
void
745
rtsock_add_rtm_sa(struct rt_msghdr *rtm, int addr_type, struct sockaddr *sa)
746
{
747
char *ptr = (char *)(rtm + 1);
748
for (int i = 0; i < RTAX_MAX; i++) {
749
if (rtm->rtm_addrs & (1 << i)) {
750
/* add */
751
ptr += ALIGN(((struct sockaddr *)ptr)->sa_len);
752
}
753
}
754
755
rtm->rtm_addrs |= addr_type;
756
memcpy(ptr, sa, sa->sa_len);
757
}
758
759
struct sockaddr *
760
rtsock_find_rtm_sa(struct rt_msghdr *rtm, int addr_type)
761
{
762
char *ptr = (char *)(rtm + 1);
763
for (int i = 0; i < RTAX_MAX; i++) {
764
if (rtm->rtm_addrs & (1 << i)) {
765
if (addr_type == (1 << i))
766
return ((struct sockaddr *)ptr);
767
/* add */
768
ptr += ALIGN(((struct sockaddr *)ptr)->sa_len);
769
}
770
}
771
772
return (NULL);
773
}
774
775
size_t
776
rtsock_calc_rtm_len(struct rt_msghdr *rtm)
777
{
778
size_t len = sizeof(struct rt_msghdr);
779
780
char *ptr = (char *)(rtm + 1);
781
for (int i = 0; i < RTAX_MAX; i++) {
782
if (rtm->rtm_addrs & (1 << i)) {
783
/* add */
784
int sa_len = ALIGN(((struct sockaddr *)ptr)->sa_len);
785
len += sa_len;
786
ptr += sa_len;
787
}
788
}
789
790
return len;
791
}
792
793
void
794
rtsock_update_rtm_len(struct rt_msghdr *rtm)
795
{
796
797
rtm->rtm_msglen = rtsock_calc_rtm_len(rtm);
798
}
799
800
static void
801
_validate_message_sockaddrs(char *buffer, int rtm_len, size_t offset, int rtm_addrs)
802
{
803
struct sockaddr *sa;
804
size_t parsed_len = offset;
805
806
/* Offset denotes initial header size */
807
sa = (struct sockaddr *)(buffer + offset);
808
809
for (int i = 0; i < RTAX_MAX; i++) {
810
if ((rtm_addrs & (1 << i)) == 0)
811
continue;
812
parsed_len += SA_SIZE(sa);
813
RTSOCK_ATF_REQUIRE_MSG((struct rt_msghdr *)buffer, parsed_len <= rtm_len,
814
"SA %d: len %d exceeds msg size %d", i, (int)sa->sa_len, rtm_len);
815
if (sa->sa_family == AF_LINK) {
816
struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
817
int data_len = sdl->sdl_nlen + sdl->sdl_alen;
818
data_len += offsetof(struct sockaddr_dl, sdl_data);
819
820
RTSOCK_ATF_REQUIRE_MSG((struct rt_msghdr *)buffer,
821
data_len <= rtm_len,
822
"AF_LINK data size exceeds total len: %u vs %u, nlen=%d alen=%d",
823
data_len, rtm_len, sdl->sdl_nlen, sdl->sdl_alen);
824
}
825
sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa));
826
}
827
}
828
829
/*
830
* Raises error if base syntax checks fails.
831
*/
832
void
833
rtsock_validate_message(char *buffer, ssize_t len)
834
{
835
struct rt_msghdr *rtm;
836
837
ATF_REQUIRE_MSG(len > 0, "read() return %zd, error: %s", len, strerror(errno));
838
839
rtm = (struct rt_msghdr *)buffer;
840
ATF_REQUIRE_MSG(rtm->rtm_version == RTM_VERSION, "unknown RTM_VERSION: expected %d got %d",
841
RTM_VERSION, rtm->rtm_version);
842
ATF_REQUIRE_MSG(rtm->rtm_msglen <= len, "wrong message length: expected %d got %d",
843
(int)len, (int)rtm->rtm_msglen);
844
845
switch (rtm->rtm_type) {
846
case RTM_GET:
847
case RTM_ADD:
848
case RTM_DELETE:
849
case RTM_CHANGE:
850
_validate_message_sockaddrs(buffer, rtm->rtm_msglen,
851
sizeof(struct rt_msghdr), rtm->rtm_addrs);
852
break;
853
case RTM_DELADDR:
854
case RTM_NEWADDR:
855
_validate_message_sockaddrs(buffer, rtm->rtm_msglen,
856
sizeof(struct ifa_msghdr), ((struct ifa_msghdr *)buffer)->ifam_addrs);
857
break;
858
}
859
}
860
861
void
862
rtsock_validate_pid_ours(struct rt_msghdr *rtm)
863
{
864
RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_pid == getpid(), "expected pid %d, got %d",
865
getpid(), rtm->rtm_pid);
866
}
867
868
void
869
rtsock_validate_pid_user(struct rt_msghdr *rtm)
870
{
871
RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_pid > 0, "expected non-zero pid, got %d",
872
rtm->rtm_pid);
873
}
874
875
void
876
rtsock_validate_pid_kernel(struct rt_msghdr *rtm)
877
{
878
RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_pid == 0, "expected zero pid, got %d",
879
rtm->rtm_pid);
880
}
881
882
#endif
883
884