mirror of
https://github.com/opnsense/src.git
synced 2026-06-13 02:30:51 -04:00
tools: Add a small program to demonstrate FIB handling in bind(2)
MFC after: 2 weeks Sponsored by: Klara, Inc. Sponsored by: Stormshield
This commit is contained in:
parent
ca94f92c23
commit
3fa5521498
2 changed files with 241 additions and 0 deletions
4
tools/tools/fib_multibind/Makefile
Normal file
4
tools/tools/fib_multibind/Makefile
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
PROG= sink
|
||||
MAN=
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
237
tools/tools/fib_multibind/sink.c
Normal file
237
tools/tools/fib_multibind/sink.c
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2025 Klara, Inc.
|
||||
*/
|
||||
|
||||
/*
|
||||
* A program to demonstrate the effects of the net.inet.tcp.bind_all_fibs and
|
||||
* net.inet.udp.bind_all_fibs sysctls when they are set to 0.
|
||||
*
|
||||
* The program accepts TCP connections (default) or UDP datagrams (-u flag) and
|
||||
* prints the FIB on which they were received, then discards them. If -a is
|
||||
* specific, the program accepts data from all FIBs, otherwise it only accepts
|
||||
* data from the FIB specified by the -f option.
|
||||
*/
|
||||
|
||||
#include <sys/event.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <netdb.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct sink_softc {
|
||||
struct sockaddr_storage ss;
|
||||
enum { SINK_TCP, SINK_UDP } type;
|
||||
int nfibs;
|
||||
int kq;
|
||||
int *fds;
|
||||
};
|
||||
|
||||
static void _Noreturn
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: sink [-au] [-f <fib>] [<listen addr>] <listen port>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
check_multibind(struct sink_softc *sc)
|
||||
{
|
||||
const char *sysctl;
|
||||
size_t len;
|
||||
int error, val;
|
||||
|
||||
sysctl = sc->type == SINK_TCP ? "net.inet.tcp.bind_all_fibs" :
|
||||
"net.inet.udp.bind_all_fibs";
|
||||
len = sizeof(val);
|
||||
error = sysctlbyname(sysctl, &val, &len, NULL, 0);
|
||||
if (error != 0)
|
||||
err(1, "sysctlbyname(%s)", sysctl);
|
||||
if (val != 0)
|
||||
errx(1, "multibind is disabled, set %s=0 to enable", sysctl);
|
||||
}
|
||||
|
||||
static void
|
||||
addrinfo(struct sink_softc *sc, const char *addr, int port)
|
||||
{
|
||||
struct addrinfo hints, *res, *res1;
|
||||
char portstr[8];
|
||||
int error;
|
||||
|
||||
memset(&sc->ss, 0, sizeof(sc->ss));
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_socktype = sc->type == SINK_TCP ? SOCK_STREAM : SOCK_DGRAM;
|
||||
snprintf(portstr, sizeof(portstr), "%d", port);
|
||||
error = getaddrinfo(addr, portstr, &hints, &res);
|
||||
if (error != 0)
|
||||
errx(1, "%s", gai_strerror(error));
|
||||
for (res1 = res; res != NULL; res = res->ai_next) {
|
||||
if ((res->ai_protocol == IPPROTO_TCP && sc->type == SINK_TCP) ||
|
||||
(res->ai_protocol == IPPROTO_UDP && sc->type == SINK_UDP)) {
|
||||
memcpy(&sc->ss, res->ai_addr, res->ai_addrlen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (res == NULL) {
|
||||
errx(1, "no %s address found for '%s'",
|
||||
sc->type == SINK_TCP ? "TCP" : "UDP", addr);
|
||||
}
|
||||
freeaddrinfo(res1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct sink_softc sc;
|
||||
const char *laddr;
|
||||
int ch, error, fib, lport;
|
||||
bool all;
|
||||
|
||||
all = false;
|
||||
sc.type = SINK_TCP;
|
||||
fib = -1;
|
||||
while ((ch = getopt(argc, argv, "af:u")) != -1) {
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
all = true;
|
||||
break;
|
||||
case 'f':
|
||||
fib = atoi(optarg);
|
||||
break;
|
||||
case 'u':
|
||||
sc.type = SINK_UDP;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (all && fib != -1)
|
||||
errx(1, "-a and -f are mutually exclusive");
|
||||
if (fib == -1) {
|
||||
size_t len;
|
||||
|
||||
error = sysctlbyname("net.my_fibnum", &fib, &len, NULL, 0);
|
||||
if (error != 0)
|
||||
err(1, "sysctlbyname(net.my_fibnum)");
|
||||
}
|
||||
|
||||
if (argc == 2) {
|
||||
laddr = argv[0];
|
||||
lport = atoi(argv[1]);
|
||||
} else if (argc == 1) {
|
||||
laddr = NULL;
|
||||
lport = atoi(argv[0]);
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
addrinfo(&sc, laddr, lport);
|
||||
|
||||
check_multibind(&sc);
|
||||
|
||||
sc.kq = kqueue();
|
||||
if (sc.kq == -1)
|
||||
err(1, "kqueue");
|
||||
|
||||
if (all) {
|
||||
size_t len;
|
||||
|
||||
len = sizeof(sc.nfibs);
|
||||
error = sysctlbyname("net.fibs", &sc.nfibs, &len, NULL, 0);
|
||||
if (error != 0)
|
||||
err(1, "sysctlbyname(net.fibs)");
|
||||
} else {
|
||||
sc.nfibs = 1;
|
||||
}
|
||||
|
||||
sc.fds = calloc(all ? sc.nfibs : 1, sizeof(int));
|
||||
if (sc.fds == NULL)
|
||||
err(1, "calloc");
|
||||
for (int i = 0; i < sc.nfibs; i++) {
|
||||
struct kevent kev;
|
||||
int s;
|
||||
|
||||
if (sc.type == SINK_TCP)
|
||||
s = socket(sc.ss.ss_family, SOCK_STREAM, 0);
|
||||
else
|
||||
s = socket(sc.ss.ss_family, SOCK_DGRAM, 0);
|
||||
if (s == -1)
|
||||
err(1, "socket");
|
||||
error = setsockopt(s, SOL_SOCKET, SO_SETFIB,
|
||||
all ? &i : &fib, sizeof(int));
|
||||
if (error != 0)
|
||||
err(1, "setsockopt(SO_SETFIB)");
|
||||
|
||||
error = bind(s, (struct sockaddr *)&sc.ss, sc.ss.ss_len);
|
||||
if (error != 0)
|
||||
err(1, "bind");
|
||||
|
||||
if (sc.type == SINK_TCP) {
|
||||
error = listen(s, 5);
|
||||
if (error != 0)
|
||||
err(1, "listen");
|
||||
}
|
||||
|
||||
EV_SET(&kev, s, EVFILT_READ, EV_ADD, 0, 0, NULL);
|
||||
error = kevent(sc.kq, &kev, 1, NULL, 0, NULL);
|
||||
if (error != 0)
|
||||
err(1, "kevent");
|
||||
|
||||
sc.fds[i] = s;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
struct kevent kev;
|
||||
socklen_t optlen;
|
||||
int n;
|
||||
|
||||
n = kevent(sc.kq, NULL, 0, &kev, 1, NULL);
|
||||
if (n == -1)
|
||||
err(1, "kevent");
|
||||
if (n == 0)
|
||||
continue;
|
||||
|
||||
optlen = sizeof(fib);
|
||||
error = getsockopt((int)kev.ident, SOL_SOCKET, SO_FIB,
|
||||
&fib, &optlen);
|
||||
if (error == -1)
|
||||
err(1, "getsockopt(SO_FIB)");
|
||||
|
||||
if (sc.type == SINK_TCP) {
|
||||
int cs;
|
||||
|
||||
printf("accepting connection from FIB %d\n", fib);
|
||||
|
||||
cs = accept((int)kev.ident, NULL, NULL);
|
||||
if (cs == -1)
|
||||
err(1, "accept");
|
||||
close(cs);
|
||||
} else {
|
||||
char buf[1024];
|
||||
ssize_t nb;
|
||||
|
||||
printf("receiving datagram from FIB %d\n", fib);
|
||||
|
||||
nb = recvfrom((int)kev.ident, buf, sizeof(buf), 0,
|
||||
NULL, NULL);
|
||||
if (nb == -1)
|
||||
err(1, "recvfrom");
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
Loading…
Reference in a new issue