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