Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/netinet/ip6_mrouted.c
178478 views
1
/*
2
* Copyright (c) 2026 Stormshield
3
*
4
* SPDX-License-Identifier: BSD-2-Clause
5
*/
6
7
/*
8
* A dead-simple IPv6 multicast routing daemon. It registers itself with the
9
* multicast routing code and then waits for messages from the kernel. Received
10
* messages are handled by installing multicast routes.
11
*/
12
13
#include <sys/types.h>
14
#include <sys/event.h>
15
#include <sys/queue.h>
16
#include <sys/socket.h>
17
18
#include <net/if.h>
19
#include <netinet/in.h>
20
#include <netinet6/ip6_mroute.h>
21
#include <arpa/inet.h>
22
23
#include <assert.h>
24
#include <err.h>
25
#include <errno.h>
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <string.h>
29
#include <unistd.h>
30
31
struct mif {
32
const char *name;
33
int mifi;
34
int pifi;
35
STAILQ_ENTRY(mif) next;
36
};
37
static STAILQ_HEAD(, mif) miflist = STAILQ_HEAD_INITIALIZER(miflist);
38
39
static void *
40
xmalloc(size_t size)
41
{
42
void *ptr;
43
44
ptr = malloc(size);
45
if (ptr == NULL)
46
err(1, "malloc");
47
return (ptr);
48
}
49
50
static void
51
usage(void)
52
{
53
fprintf(stderr,
54
"usage: %s [-i <iface>] [-m <srcaddr>/<groupaddr>/<iface>]\n",
55
getprogname());
56
exit(1);
57
}
58
59
static void
60
add_route(int sd, const struct in6_addr *src, const struct in6_addr *group,
61
mifi_t mifi)
62
{
63
struct mf6cctl mfcc;
64
struct mif *mif;
65
int error;
66
67
memset(&mfcc, 0, sizeof(mfcc));
68
mfcc.mf6cc_parent = mifi;
69
mfcc.mf6cc_origin.sin6_family = AF_INET6;
70
mfcc.mf6cc_origin.sin6_len = sizeof(struct sockaddr_in6);
71
mfcc.mf6cc_origin.sin6_addr = *src;
72
mfcc.mf6cc_mcastgrp.sin6_family = AF_INET6;
73
mfcc.mf6cc_mcastgrp.sin6_len = sizeof(struct sockaddr_in6);
74
mfcc.mf6cc_mcastgrp.sin6_addr = *group;
75
76
STAILQ_FOREACH(mif, &miflist, next) {
77
if (mif->mifi != mifi)
78
IF_SET(mif->mifi, &mfcc.mf6cc_ifset);
79
}
80
81
error = setsockopt(sd, IPPROTO_IPV6, MRT6_ADD_MFC,
82
&mfcc, sizeof(mfcc));
83
if (error != 0)
84
err(1, "setsockopt(MRT6_ADD_MFC)");
85
}
86
87
static void
88
handle_upcalls(int sd)
89
{
90
struct kevent ev;
91
int kq;
92
93
kq = kqueue();
94
if (kq < 0)
95
err(1, "kqueue");
96
EV_SET(&ev, sd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL);
97
if (kevent(kq, &ev, 1, NULL, 0, NULL) < 0)
98
err(1, "kevent");
99
100
for (;;) {
101
char buf1[INET6_ADDRSTRLEN], buf2[INET6_ADDRSTRLEN];
102
struct mrt6msg msg;
103
ssize_t len;
104
int n;
105
106
n = kevent(kq, NULL, 0, &ev, 1, NULL);
107
if (n < 0) {
108
if (errno == EINTR)
109
break;
110
err(1, "kevent");
111
}
112
if (n == 0)
113
continue;
114
assert(n == 1);
115
assert(ev.filter == EVFILT_READ);
116
117
len = recv(sd, &msg, sizeof(msg), 0);
118
if (len < 0)
119
err(1, "recv");
120
if ((size_t)len < sizeof(msg)) {
121
warnx("short read on upcall, %zd bytes", len);
122
continue;
123
}
124
125
printf("upcall received:\n");
126
printf("msgtype=%d mif=%d src=%s dst=%s\n",
127
msg.im6_msgtype, msg.im6_mif,
128
inet_ntop(AF_INET6, &msg.im6_src, buf1, sizeof(buf1)),
129
inet_ntop(AF_INET6, &msg.im6_dst, buf2, sizeof(buf2)));
130
131
add_route(sd, &msg.im6_src, &msg.im6_dst, msg.im6_mif);
132
}
133
134
close(kq);
135
}
136
137
int
138
main(int argc, char **argv)
139
{
140
struct mif *mif;
141
int ch, error, mifi, sd, v;
142
143
mifi = 0;
144
while ((ch = getopt(argc, argv, "i:m:")) != -1) {
145
switch (ch) {
146
case 'i':
147
mif = xmalloc(sizeof(*mif));
148
mif->name = strdup(optarg);
149
mif->mifi = mifi++;
150
mif->pifi = if_nametoindex(optarg);
151
if (mif->pifi == 0)
152
errx(1, "unknown interface %s", optarg);
153
STAILQ_INSERT_TAIL(&miflist, mif, next);
154
break;
155
default:
156
usage();
157
/* NOTREACHED */
158
}
159
}
160
argc -= optind;
161
argv += optind;
162
163
sd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
164
if (sd < 0)
165
err(1, "socket");
166
167
v = 1;
168
error = setsockopt(sd, IPPROTO_IPV6, MRT6_INIT, &v, sizeof(v));
169
if (error != 0)
170
err(1, "setsockopt(MRT6_INIT)");
171
172
STAILQ_FOREACH(mif, &miflist, next) {
173
struct mif6ctl mifc;
174
175
mifc.mif6c_mifi = mif->mifi;
176
mifc.mif6c_pifi = mif->pifi;
177
mifc.mif6c_flags = 0;
178
error = setsockopt(sd, IPPROTO_IPV6, MRT6_ADD_MIF,
179
&mifc, sizeof(mifc));
180
if (error != 0)
181
err(1, "setsockopt(MRT6_ADD_MIF) on %s", mif->name);
182
}
183
184
handle_upcalls(sd);
185
186
error = setsockopt(sd, IPPROTO_IPV6, MRT6_DONE, NULL, 0);
187
if (error != 0)
188
err(1, "setsockopt(MRT6_DONE)");
189
190
return (0);
191
}
192
193