root/tools/testing/selftests/net/reuseport_addr_any.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. build_rcv_fd
  2. connect_and_send
  3. receive_once
  4. test
  5. run_one_test
  6. test_proto
  7. main

   1 // SPDX-License-Identifier: GPL-2.0
   2 
   3 /* Test that sockets listening on a specific address are preferred
   4  * over sockets listening on addr_any.
   5  */
   6 
   7 #define _GNU_SOURCE
   8 
   9 #include <arpa/inet.h>
  10 #include <errno.h>
  11 #include <error.h>
  12 #include <linux/dccp.h>
  13 #include <linux/in.h>
  14 #include <linux/unistd.h>
  15 #include <stdbool.h>
  16 #include <stdio.h>
  17 #include <stdlib.h>
  18 #include <string.h>
  19 #include <sys/epoll.h>
  20 #include <sys/types.h>
  21 #include <sys/socket.h>
  22 #include <unistd.h>
  23 
  24 #ifndef SOL_DCCP
  25 #define SOL_DCCP 269
  26 #endif
  27 
  28 static const char *IP4_ADDR = "127.0.0.1";
  29 static const char *IP6_ADDR = "::1";
  30 static const char *IP4_MAPPED6 = "::ffff:127.0.0.1";
  31 
  32 static const int PORT = 8888;
  33 
  34 static void build_rcv_fd(int family, int proto, int *rcv_fds, int count,
  35                          const char *addr_str)
  36 {
  37         struct sockaddr_in  addr4 = {0};
  38         struct sockaddr_in6 addr6 = {0};
  39         struct sockaddr *addr;
  40         int opt, i, sz;
  41 
  42         memset(&addr, 0, sizeof(addr));
  43 
  44         switch (family) {
  45         case AF_INET:
  46                 addr4.sin_family = family;
  47                 if (!addr_str)
  48                         addr4.sin_addr.s_addr = htonl(INADDR_ANY);
  49                 else if (!inet_pton(family, addr_str, &addr4.sin_addr.s_addr))
  50                         error(1, errno, "inet_pton failed: %s", addr_str);
  51                 addr4.sin_port = htons(PORT);
  52                 sz = sizeof(addr4);
  53                 addr = (struct sockaddr *)&addr4;
  54                 break;
  55         case AF_INET6:
  56                 addr6.sin6_family = AF_INET6;
  57                 if (!addr_str)
  58                         addr6.sin6_addr = in6addr_any;
  59                 else if (!inet_pton(family, addr_str, &addr6.sin6_addr))
  60                         error(1, errno, "inet_pton failed: %s", addr_str);
  61                 addr6.sin6_port = htons(PORT);
  62                 sz = sizeof(addr6);
  63                 addr = (struct sockaddr *)&addr6;
  64                 break;
  65         default:
  66                 error(1, 0, "Unsupported family %d", family);
  67                 /* clang does not recognize error() above as terminating
  68                  * the program, so it complains that saddr, sz are
  69                  * not initialized when this code path is taken. Silence it.
  70                  */
  71                 return;
  72         }
  73 
  74         for (i = 0; i < count; ++i) {
  75                 rcv_fds[i] = socket(family, proto, 0);
  76                 if (rcv_fds[i] < 0)
  77                         error(1, errno, "failed to create receive socket");
  78 
  79                 opt = 1;
  80                 if (setsockopt(rcv_fds[i], SOL_SOCKET, SO_REUSEPORT, &opt,
  81                                sizeof(opt)))
  82                         error(1, errno, "failed to set SO_REUSEPORT");
  83 
  84                 if (bind(rcv_fds[i], addr, sz))
  85                         error(1, errno, "failed to bind receive socket");
  86 
  87                 if (proto == SOCK_STREAM && listen(rcv_fds[i], 10))
  88                         error(1, errno, "tcp: failed to listen on receive port");
  89                 else if (proto == SOCK_DCCP) {
  90                         if (setsockopt(rcv_fds[i], SOL_DCCP,
  91                                         DCCP_SOCKOPT_SERVICE,
  92                                         &(int) {htonl(42)}, sizeof(int)))
  93                                 error(1, errno, "failed to setsockopt");
  94 
  95                         if (listen(rcv_fds[i], 10))
  96                                 error(1, errno, "dccp: failed to listen on receive port");
  97                 }
  98         }
  99 }
 100 
 101 static int connect_and_send(int family, int proto)
 102 {
 103         struct sockaddr_in  saddr4 = {0};
 104         struct sockaddr_in  daddr4 = {0};
 105         struct sockaddr_in6 saddr6 = {0};
 106         struct sockaddr_in6 daddr6 = {0};
 107         struct sockaddr *saddr, *daddr;
 108         int fd, sz;
 109 
 110         switch (family) {
 111         case AF_INET:
 112                 saddr4.sin_family = AF_INET;
 113                 saddr4.sin_addr.s_addr = htonl(INADDR_ANY);
 114                 saddr4.sin_port = 0;
 115 
 116                 daddr4.sin_family = AF_INET;
 117                 if (!inet_pton(family, IP4_ADDR, &daddr4.sin_addr.s_addr))
 118                         error(1, errno, "inet_pton failed: %s", IP4_ADDR);
 119                 daddr4.sin_port = htons(PORT);
 120 
 121                 sz = sizeof(saddr4);
 122                 saddr = (struct sockaddr *)&saddr4;
 123                 daddr = (struct sockaddr *)&daddr4;
 124         break;
 125         case AF_INET6:
 126                 saddr6.sin6_family = AF_INET6;
 127                 saddr6.sin6_addr = in6addr_any;
 128 
 129                 daddr6.sin6_family = AF_INET6;
 130                 if (!inet_pton(family, IP6_ADDR, &daddr6.sin6_addr))
 131                         error(1, errno, "inet_pton failed: %s", IP6_ADDR);
 132                 daddr6.sin6_port = htons(PORT);
 133 
 134                 sz = sizeof(saddr6);
 135                 saddr = (struct sockaddr *)&saddr6;
 136                 daddr = (struct sockaddr *)&daddr6;
 137         break;
 138         default:
 139                 error(1, 0, "Unsupported family %d", family);
 140                 /* clang does not recognize error() above as terminating
 141                  * the program, so it complains that saddr, daddr, sz are
 142                  * not initialized when this code path is taken. Silence it.
 143                  */
 144                 return -1;
 145         }
 146 
 147         fd = socket(family, proto, 0);
 148         if (fd < 0)
 149                 error(1, errno, "failed to create send socket");
 150 
 151         if (proto == SOCK_DCCP &&
 152                 setsockopt(fd, SOL_DCCP, DCCP_SOCKOPT_SERVICE,
 153                                 &(int){htonl(42)}, sizeof(int)))
 154                 error(1, errno, "failed to setsockopt");
 155 
 156         if (bind(fd, saddr, sz))
 157                 error(1, errno, "failed to bind send socket");
 158 
 159         if (connect(fd, daddr, sz))
 160                 error(1, errno, "failed to connect send socket");
 161 
 162         if (send(fd, "a", 1, 0) < 0)
 163                 error(1, errno, "failed to send message");
 164 
 165         return fd;
 166 }
 167 
 168 static int receive_once(int epfd, int proto)
 169 {
 170         struct epoll_event ev;
 171         int i, fd;
 172         char buf[8];
 173 
 174         i = epoll_wait(epfd, &ev, 1, 3);
 175         if (i < 0)
 176                 error(1, errno, "epoll_wait failed");
 177 
 178         if (proto == SOCK_STREAM || proto == SOCK_DCCP) {
 179                 fd = accept(ev.data.fd, NULL, NULL);
 180                 if (fd < 0)
 181                         error(1, errno, "failed to accept");
 182                 i = recv(fd, buf, sizeof(buf), 0);
 183                 close(fd);
 184         } else {
 185                 i = recv(ev.data.fd, buf, sizeof(buf), 0);
 186         }
 187 
 188         if (i < 0)
 189                 error(1, errno, "failed to recv");
 190 
 191         return ev.data.fd;
 192 }
 193 
 194 static void test(int *rcv_fds, int count, int family, int proto, int fd)
 195 {
 196         struct epoll_event ev;
 197         int epfd, i, send_fd, recv_fd;
 198 
 199         epfd = epoll_create(1);
 200         if (epfd < 0)
 201                 error(1, errno, "failed to create epoll");
 202 
 203         ev.events = EPOLLIN;
 204         for (i = 0; i < count; ++i) {
 205                 ev.data.fd = rcv_fds[i];
 206                 if (epoll_ctl(epfd, EPOLL_CTL_ADD, rcv_fds[i], &ev))
 207                         error(1, errno, "failed to register sock epoll");
 208         }
 209 
 210         send_fd = connect_and_send(family, proto);
 211 
 212         recv_fd = receive_once(epfd, proto);
 213         if (recv_fd != fd)
 214                 error(1, 0, "received on an unexpected socket");
 215 
 216         close(send_fd);
 217         close(epfd);
 218 }
 219 
 220 
 221 static void run_one_test(int fam_send, int fam_rcv, int proto,
 222                          const char *addr_str)
 223 {
 224         /* Below we test that a socket listening on a specific address
 225          * is always selected in preference over a socket listening
 226          * on addr_any. Bugs where this is not the case often result
 227          * in sockets created first or last to get picked. So below
 228          * we make sure that there are always addr_any sockets created
 229          * before and after a specific socket is created.
 230          */
 231         int rcv_fds[10], i;
 232 
 233         build_rcv_fd(AF_INET, proto, rcv_fds, 2, NULL);
 234         build_rcv_fd(AF_INET6, proto, rcv_fds + 2, 2, NULL);
 235         build_rcv_fd(fam_rcv, proto, rcv_fds + 4, 1, addr_str);
 236         build_rcv_fd(AF_INET, proto, rcv_fds + 5, 2, NULL);
 237         build_rcv_fd(AF_INET6, proto, rcv_fds + 7, 2, NULL);
 238         test(rcv_fds, 9, fam_send, proto, rcv_fds[4]);
 239         for (i = 0; i < 9; ++i)
 240                 close(rcv_fds[i]);
 241         fprintf(stderr, "pass\n");
 242 }
 243 
 244 static void test_proto(int proto, const char *proto_str)
 245 {
 246         if (proto == SOCK_DCCP) {
 247                 int test_fd;
 248 
 249                 test_fd = socket(AF_INET, proto, 0);
 250                 if (test_fd < 0) {
 251                         if (errno == ESOCKTNOSUPPORT) {
 252                                 fprintf(stderr, "DCCP not supported: skipping DCCP tests\n");
 253                                 return;
 254                         } else
 255                                 error(1, errno, "failed to create a DCCP socket");
 256                 }
 257                 close(test_fd);
 258         }
 259 
 260         fprintf(stderr, "%s IPv4 ... ", proto_str);
 261         run_one_test(AF_INET, AF_INET, proto, IP4_ADDR);
 262 
 263         fprintf(stderr, "%s IPv6 ... ", proto_str);
 264         run_one_test(AF_INET6, AF_INET6, proto, IP6_ADDR);
 265 
 266         fprintf(stderr, "%s IPv4 mapped to IPv6 ... ", proto_str);
 267         run_one_test(AF_INET, AF_INET6, proto, IP4_MAPPED6);
 268 }
 269 
 270 int main(void)
 271 {
 272         test_proto(SOCK_DGRAM, "UDP");
 273         test_proto(SOCK_STREAM, "TCP");
 274         test_proto(SOCK_DCCP, "DCCP");
 275 
 276         fprintf(stderr, "SUCCESS\n");
 277         return 0;
 278 }

/* [<][>][^][v][top][bottom][index][help] */