// SPDX-License-Identifier: GPL-2.0 /* * It is possible to use SO_REUSEPORT to open multiple sockets bound to * equivalent local addresses using AF_INET and AF_INET6 at the same time. If * the AF_INET6 socket has IPV6_V6ONLY set, it's clear which socket should * receive a given incoming packet. However, when it is not set, incoming v4 * packets should prefer the AF_INET socket(s). This behavior was defined with * the original SO_REUSEPORT implementation, but broke with * e32ea7e74727 ("soreuseport: fast reuseport UDP socket selection") * This test creates these mixed AF_INET/AF_INET6 sockets and asserts the * AF_INET preference for v4 packets.
*/
staticvoid build_rcv_fd(int family, int proto, int *rcv_fds, int count)
{ struct sockaddr_storage addr; struct sockaddr_in *addr4; struct sockaddr_in6 *addr6; int opt, i;
fd = socket(AF_INET, proto, 0); if (fd < 0)
error(1, errno, "failed to create send socket");
if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)))
error(1, errno, "failed to bind send socket");
if (connect(fd, (struct sockaddr *)&daddr, sizeof(daddr)))
error(1, errno, "failed to connect send socket");
if (send(fd, "a", 1, 0) < 0)
error(1, errno, "failed to send message");
close(fd);
}
staticint receive_once(int epfd, int proto)
{ struct epoll_event ev; int i, fd; char buf[8];
i = epoll_wait(epfd, &ev, 1, -1); if (i < 0)
error(1, errno, "epoll_wait failed");
if (proto == SOCK_STREAM) {
fd = accept(ev.data.fd, NULL, NULL); if (fd < 0)
error(1, errno, "failed to accept");
i = recv(fd, buf, sizeof(buf), 0);
close(fd);
} else {
i = recv(ev.data.fd, buf, sizeof(buf), 0);
}
if (i < 0)
error(1, errno, "failed to recv");
return ev.data.fd;
}
staticvoid test(int *rcv_fds, int count, int proto)
{ struct epoll_event ev; int epfd, i, test_fd; int test_family;
socklen_t len;
epfd = epoll_create(1); if (epfd < 0)
error(1, errno, "failed to create epoll");
ev.events = EPOLLIN; for (i = 0; i < count; ++i) {
ev.data.fd = rcv_fds[i]; if (epoll_ctl(epfd, EPOLL_CTL_ADD, rcv_fds[i], &ev))
error(1, errno, "failed to register sock epoll");
}
send_from_v4(proto);
test_fd = receive_once(epfd, proto);
len = sizeof(test_family); if (getsockopt(test_fd, SOL_SOCKET, SO_DOMAIN, &test_family, &len))
error(1, errno, "failed to read socket domain"); if (test_family != AF_INET)
error(1, 0, "expected to receive on v4 socket but got v6 (%d)",
test_family);
close(epfd);
}
int main(void)
{ int rcv_fds[32], i;
fprintf(stderr, "---- UDP IPv4 created before IPv6 ----\n");
build_rcv_fd(AF_INET, SOCK_DGRAM, rcv_fds, 5);
build_rcv_fd(AF_INET6, SOCK_DGRAM, &(rcv_fds[5]), 5);
test(rcv_fds, 10, SOCK_DGRAM); for (i = 0; i < 10; ++i)
close(rcv_fds[i]);
fprintf(stderr, "---- UDP IPv6 created before IPv4 ----\n");
build_rcv_fd(AF_INET6, SOCK_DGRAM, rcv_fds, 5);
build_rcv_fd(AF_INET, SOCK_DGRAM, &(rcv_fds[5]), 5);
test(rcv_fds, 10, SOCK_DGRAM); for (i = 0; i < 10; ++i)
close(rcv_fds[i]);
/* NOTE: UDP socket lookups traverse a different code path when there * are > 10 sockets in a group.
*/
fprintf(stderr, "---- UDP IPv4 created before IPv6 (large) ----\n");
build_rcv_fd(AF_INET, SOCK_DGRAM, rcv_fds, 16);
build_rcv_fd(AF_INET6, SOCK_DGRAM, &(rcv_fds[16]), 16);
test(rcv_fds, 32, SOCK_DGRAM); for (i = 0; i < 32; ++i)
close(rcv_fds[i]);
fprintf(stderr, "---- UDP IPv6 created before IPv4 (large) ----\n");
build_rcv_fd(AF_INET6, SOCK_DGRAM, rcv_fds, 16);
build_rcv_fd(AF_INET, SOCK_DGRAM, &(rcv_fds[16]), 16);
test(rcv_fds, 32, SOCK_DGRAM); for (i = 0; i < 32; ++i)
close(rcv_fds[i]);
fprintf(stderr, "---- TCP IPv4 created before IPv6 ----\n");
build_rcv_fd(AF_INET, SOCK_STREAM, rcv_fds, 5);
build_rcv_fd(AF_INET6, SOCK_STREAM, &(rcv_fds[5]), 5);
test(rcv_fds, 10, SOCK_STREAM); for (i = 0; i < 10; ++i)
close(rcv_fds[i]);
fprintf(stderr, "---- TCP IPv6 created before IPv4 ----\n");
build_rcv_fd(AF_INET6, SOCK_STREAM, rcv_fds, 5);
build_rcv_fd(AF_INET, SOCK_STREAM, &(rcv_fds[5]), 5);
test(rcv_fds, 10, SOCK_STREAM); for (i = 0; i < 10; ++i)
close(rcv_fds[i]);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.