Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 
0003 /* Test that sockets listening on a specific address are preferred
0004  * over sockets listening on addr_any.
0005  */
0006 
0007 #define _GNU_SOURCE
0008 
0009 #include <arpa/inet.h>
0010 #include <errno.h>
0011 #include <error.h>
0012 #include <linux/dccp.h>
0013 #include <linux/in.h>
0014 #include <linux/unistd.h>
0015 #include <stdbool.h>
0016 #include <stdio.h>
0017 #include <stdlib.h>
0018 #include <string.h>
0019 #include <sys/epoll.h>
0020 #include <sys/types.h>
0021 #include <sys/socket.h>
0022 #include <unistd.h>
0023 
0024 #ifndef SOL_DCCP
0025 #define SOL_DCCP 269
0026 #endif
0027 
0028 static const char *IP4_ADDR = "127.0.0.1";
0029 static const char *IP6_ADDR = "::1";
0030 static const char *IP4_MAPPED6 = "::ffff:127.0.0.1";
0031 
0032 static const int PORT = 8888;
0033 
0034 static void build_rcv_fd(int family, int proto, int *rcv_fds, int count,
0035              const char *addr_str)
0036 {
0037     struct sockaddr_in  addr4 = {0};
0038     struct sockaddr_in6 addr6 = {0};
0039     struct sockaddr *addr;
0040     int opt, i, sz;
0041 
0042     memset(&addr, 0, sizeof(addr));
0043 
0044     switch (family) {
0045     case AF_INET:
0046         addr4.sin_family = family;
0047         if (!addr_str)
0048             addr4.sin_addr.s_addr = htonl(INADDR_ANY);
0049         else if (!inet_pton(family, addr_str, &addr4.sin_addr.s_addr))
0050             error(1, errno, "inet_pton failed: %s", addr_str);
0051         addr4.sin_port = htons(PORT);
0052         sz = sizeof(addr4);
0053         addr = (struct sockaddr *)&addr4;
0054         break;
0055     case AF_INET6:
0056         addr6.sin6_family = AF_INET6;
0057         if (!addr_str)
0058             addr6.sin6_addr = in6addr_any;
0059         else if (!inet_pton(family, addr_str, &addr6.sin6_addr))
0060             error(1, errno, "inet_pton failed: %s", addr_str);
0061         addr6.sin6_port = htons(PORT);
0062         sz = sizeof(addr6);
0063         addr = (struct sockaddr *)&addr6;
0064         break;
0065     default:
0066         error(1, 0, "Unsupported family %d", family);
0067         /* clang does not recognize error() above as terminating
0068          * the program, so it complains that saddr, sz are
0069          * not initialized when this code path is taken. Silence it.
0070          */
0071         return;
0072     }
0073 
0074     for (i = 0; i < count; ++i) {
0075         rcv_fds[i] = socket(family, proto, 0);
0076         if (rcv_fds[i] < 0)
0077             error(1, errno, "failed to create receive socket");
0078 
0079         opt = 1;
0080         if (setsockopt(rcv_fds[i], SOL_SOCKET, SO_REUSEPORT, &opt,
0081                    sizeof(opt)))
0082             error(1, errno, "failed to set SO_REUSEPORT");
0083 
0084         if (bind(rcv_fds[i], addr, sz))
0085             error(1, errno, "failed to bind receive socket");
0086 
0087         if (proto == SOCK_STREAM && listen(rcv_fds[i], 10))
0088             error(1, errno, "tcp: failed to listen on receive port");
0089         else if (proto == SOCK_DCCP) {
0090             if (setsockopt(rcv_fds[i], SOL_DCCP,
0091                     DCCP_SOCKOPT_SERVICE,
0092                     &(int) {htonl(42)}, sizeof(int)))
0093                 error(1, errno, "failed to setsockopt");
0094 
0095             if (listen(rcv_fds[i], 10))
0096                 error(1, errno, "dccp: failed to listen on receive port");
0097         }
0098     }
0099 }
0100 
0101 static int connect_and_send(int family, int proto)
0102 {
0103     struct sockaddr_in  saddr4 = {0};
0104     struct sockaddr_in  daddr4 = {0};
0105     struct sockaddr_in6 saddr6 = {0};
0106     struct sockaddr_in6 daddr6 = {0};
0107     struct sockaddr *saddr, *daddr;
0108     int fd, sz;
0109 
0110     switch (family) {
0111     case AF_INET:
0112         saddr4.sin_family = AF_INET;
0113         saddr4.sin_addr.s_addr = htonl(INADDR_ANY);
0114         saddr4.sin_port = 0;
0115 
0116         daddr4.sin_family = AF_INET;
0117         if (!inet_pton(family, IP4_ADDR, &daddr4.sin_addr.s_addr))
0118             error(1, errno, "inet_pton failed: %s", IP4_ADDR);
0119         daddr4.sin_port = htons(PORT);
0120 
0121         sz = sizeof(saddr4);
0122         saddr = (struct sockaddr *)&saddr4;
0123         daddr = (struct sockaddr *)&daddr4;
0124     break;
0125     case AF_INET6:
0126         saddr6.sin6_family = AF_INET6;
0127         saddr6.sin6_addr = in6addr_any;
0128 
0129         daddr6.sin6_family = AF_INET6;
0130         if (!inet_pton(family, IP6_ADDR, &daddr6.sin6_addr))
0131             error(1, errno, "inet_pton failed: %s", IP6_ADDR);
0132         daddr6.sin6_port = htons(PORT);
0133 
0134         sz = sizeof(saddr6);
0135         saddr = (struct sockaddr *)&saddr6;
0136         daddr = (struct sockaddr *)&daddr6;
0137     break;
0138     default:
0139         error(1, 0, "Unsupported family %d", family);
0140         /* clang does not recognize error() above as terminating
0141          * the program, so it complains that saddr, daddr, sz are
0142          * not initialized when this code path is taken. Silence it.
0143          */
0144         return -1;
0145     }
0146 
0147     fd = socket(family, proto, 0);
0148     if (fd < 0)
0149         error(1, errno, "failed to create send socket");
0150 
0151     if (proto == SOCK_DCCP &&
0152         setsockopt(fd, SOL_DCCP, DCCP_SOCKOPT_SERVICE,
0153                 &(int){htonl(42)}, sizeof(int)))
0154         error(1, errno, "failed to setsockopt");
0155 
0156     if (bind(fd, saddr, sz))
0157         error(1, errno, "failed to bind send socket");
0158 
0159     if (connect(fd, daddr, sz))
0160         error(1, errno, "failed to connect send socket");
0161 
0162     if (send(fd, "a", 1, 0) < 0)
0163         error(1, errno, "failed to send message");
0164 
0165     return fd;
0166 }
0167 
0168 static int receive_once(int epfd, int proto)
0169 {
0170     struct epoll_event ev;
0171     int i, fd;
0172     char buf[8];
0173 
0174     i = epoll_wait(epfd, &ev, 1, 3);
0175     if (i < 0)
0176         error(1, errno, "epoll_wait failed");
0177 
0178     if (proto == SOCK_STREAM || proto == SOCK_DCCP) {
0179         fd = accept(ev.data.fd, NULL, NULL);
0180         if (fd < 0)
0181             error(1, errno, "failed to accept");
0182         i = recv(fd, buf, sizeof(buf), 0);
0183         close(fd);
0184     } else {
0185         i = recv(ev.data.fd, buf, sizeof(buf), 0);
0186     }
0187 
0188     if (i < 0)
0189         error(1, errno, "failed to recv");
0190 
0191     return ev.data.fd;
0192 }
0193 
0194 static void test(int *rcv_fds, int count, int family, int proto, int fd)
0195 {
0196     struct epoll_event ev;
0197     int epfd, i, send_fd, recv_fd;
0198 
0199     epfd = epoll_create(1);
0200     if (epfd < 0)
0201         error(1, errno, "failed to create epoll");
0202 
0203     ev.events = EPOLLIN;
0204     for (i = 0; i < count; ++i) {
0205         ev.data.fd = rcv_fds[i];
0206         if (epoll_ctl(epfd, EPOLL_CTL_ADD, rcv_fds[i], &ev))
0207             error(1, errno, "failed to register sock epoll");
0208     }
0209 
0210     send_fd = connect_and_send(family, proto);
0211 
0212     recv_fd = receive_once(epfd, proto);
0213     if (recv_fd != fd)
0214         error(1, 0, "received on an unexpected socket");
0215 
0216     close(send_fd);
0217     close(epfd);
0218 }
0219 
0220 
0221 static void run_one_test(int fam_send, int fam_rcv, int proto,
0222              const char *addr_str)
0223 {
0224     /* Below we test that a socket listening on a specific address
0225      * is always selected in preference over a socket listening
0226      * on addr_any. Bugs where this is not the case often result
0227      * in sockets created first or last to get picked. So below
0228      * we make sure that there are always addr_any sockets created
0229      * before and after a specific socket is created.
0230      */
0231     int rcv_fds[10], i;
0232 
0233     build_rcv_fd(AF_INET, proto, rcv_fds, 2, NULL);
0234     build_rcv_fd(AF_INET6, proto, rcv_fds + 2, 2, NULL);
0235     build_rcv_fd(fam_rcv, proto, rcv_fds + 4, 1, addr_str);
0236     build_rcv_fd(AF_INET, proto, rcv_fds + 5, 2, NULL);
0237     build_rcv_fd(AF_INET6, proto, rcv_fds + 7, 2, NULL);
0238     test(rcv_fds, 9, fam_send, proto, rcv_fds[4]);
0239     for (i = 0; i < 9; ++i)
0240         close(rcv_fds[i]);
0241     fprintf(stderr, "pass\n");
0242 }
0243 
0244 static void test_proto(int proto, const char *proto_str)
0245 {
0246     if (proto == SOCK_DCCP) {
0247         int test_fd;
0248 
0249         test_fd = socket(AF_INET, proto, 0);
0250         if (test_fd < 0) {
0251             if (errno == ESOCKTNOSUPPORT) {
0252                 fprintf(stderr, "DCCP not supported: skipping DCCP tests\n");
0253                 return;
0254             } else
0255                 error(1, errno, "failed to create a DCCP socket");
0256         }
0257         close(test_fd);
0258     }
0259 
0260     fprintf(stderr, "%s IPv4 ... ", proto_str);
0261     run_one_test(AF_INET, AF_INET, proto, IP4_ADDR);
0262 
0263     fprintf(stderr, "%s IPv6 ... ", proto_str);
0264     run_one_test(AF_INET6, AF_INET6, proto, IP6_ADDR);
0265 
0266     fprintf(stderr, "%s IPv4 mapped to IPv6 ... ", proto_str);
0267     run_one_test(AF_INET, AF_INET6, proto, IP4_MAPPED6);
0268 }
0269 
0270 int main(void)
0271 {
0272     test_proto(SOCK_DGRAM, "UDP");
0273     test_proto(SOCK_STREAM, "TCP");
0274     test_proto(SOCK_DCCP, "DCCP");
0275 
0276     fprintf(stderr, "SUCCESS\n");
0277     return 0;
0278 }