1 #include <sys/types.h>
2 #include <sys/socket.h>
3
4 #include <arpa/inet.h>
5 #include <netinet/in.h>
6
7 #include <err.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13
14 static int
test_sendsrcaddr(int s,const struct sockaddr_in * remote,const struct in_addr * src)15 test_sendsrcaddr(int s, const struct sockaddr_in *remote,
16 const struct in_addr *src)
17 {
18 struct msghdr msg;
19 struct iovec iov;
20 union {
21 struct cmsghdr cm;
22 uint8_t data[CMSG_SPACE(sizeof(struct in_addr))];
23 } ctrl;
24 struct cmsghdr *cm;
25 int n;
26
27 iov.iov_base = &n;
28 iov.iov_len = sizeof(n);
29
30 memset(&msg, 0, sizeof(msg));
31 if (remote != NULL) {
32 msg.msg_name = __DECONST(void *, remote);
33 msg.msg_namelen = sizeof(*remote);
34 }
35 msg.msg_iov = &iov;
36 msg.msg_iovlen = 1;
37 msg.msg_control = ctrl.data;
38 msg.msg_controllen = sizeof(ctrl.data);
39
40 memset(&ctrl, 0, sizeof(ctrl));
41 cm = CMSG_FIRSTHDR(&msg);
42 cm->cmsg_len = CMSG_LEN(sizeof(int));
43 cm->cmsg_level = IPPROTO_IP;
44 cm->cmsg_type = IP_RECVDSTADDR;
45 *((struct in_addr *)CMSG_DATA(cm)) = *src;
46
47 return sendmsg(s, &msg, MSG_SYNC);
48 }
49
50 static void
usage(const char * cmd)51 usage(const char *cmd)
52 {
53 fprintf(stderr, "%s -4 ip4 -p port [-s src]\n", cmd);
54 exit(1);
55 }
56
57 int
main(int argc,char * argv[])58 main(int argc, char *argv[])
59 {
60 struct sockaddr_in remote, local;
61 struct in_addr src;
62 socklen_t local_len;
63 char local_str[INET_ADDRSTRLEN];
64 int s, opt, s2, on, n;
65
66 memset(&remote, 0, sizeof(remote));
67 remote.sin_family = AF_INET;
68
69 src.s_addr = INADDR_ANY;
70
71 while ((opt = getopt(argc, argv, "4:p:s:")) != -1) {
72 switch (opt) {
73 case '4':
74 if (inet_pton(AF_INET, optarg, &remote.sin_addr) <= 0)
75 usage(argv[0]);
76 break;
77
78 case 'p':
79 remote.sin_port = strtol(optarg, NULL, 10);
80 remote.sin_port = htons(remote.sin_port);
81 break;
82
83 case 's':
84 if (inet_pton(AF_INET, optarg, &src) <= 0)
85 usage(argv[0]);
86 break;
87
88 default:
89 usage(argv[0]);
90 }
91 }
92
93 s = socket(AF_INET, SOCK_DGRAM, 0);
94 if (s < 0)
95 err(2, "socket faild");
96
97 /*
98 * inp_laddr == ANY && src valid --> pass.
99 * inp_laddr == ANY && src invalid --> fail.
100 */
101 if (test_sendsrcaddr(s, &remote, &src) < 0)
102 err(2, "sendsrcaddr failed");
103
104 local_len = sizeof(local);
105 if (getsockname(s, (struct sockaddr *)&local, &local_len) < 0)
106 err(2, "getsockname failed");
107
108 fprintf(stderr, "wildcard: laddr %s, lport %u\n",
109 inet_ntop(AF_INET, &local.sin_addr, local_str, sizeof(local_str)),
110 ntohs(local.sin_port));
111 local.sin_addr = src;
112
113 s2 = socket(AF_INET, SOCK_DGRAM, 0);
114 if (s2 < 0)
115 err(2, "socket 2 failed");
116
117 on = 1;
118 if (setsockopt(s2, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
119 err(2, "setsockopt(REUSEADDR) failed");
120
121 if (bind(s2, (const struct sockaddr *)&local, sizeof(local)) < 0)
122 err(2, "bind src failed");
123
124 /*
125 * inp_laddr != ANY && src == inp_laddr --> pass.
126 */
127 if (test_sendsrcaddr(s2, &remote, &src) < 0)
128 err(2, "sendsrcaddr 2 failed");
129
130 /*
131 * Duplicated src/lport as s2 --> fail.
132 */
133 if (test_sendsrcaddr(s, &remote, &src) > 0)
134 errx(2, "sendsrcaddr succeeded!?");
135
136 close(s2);
137
138 if (connect(s, (const struct sockaddr *)&remote, sizeof(remote)) < 0)
139 err(2, "connect remote failed");
140
141 local_len = sizeof(local);
142 if (getsockname(s, (struct sockaddr *)&local, &local_len) < 0)
143 err(2, "getsockname failed");
144 fprintf(stderr, "connected: laddr %s, lport %u\n",
145 inet_ntop(AF_INET, &local.sin_addr, local_str, sizeof(local_str)),
146 ntohs(local.sin_port));
147
148 /*
149 * Connected socket:
150 * if inp_laddr == src --> pass.
151 * if inp_laddr != src --> fail.
152 */
153 n = test_sendsrcaddr(s, NULL, &src);
154 if (local.sin_addr.s_addr == src.s_addr) {
155 if (n < 0)
156 err(2, "sendsrcaddr 3 failed");
157 } else {
158 if (n > 0)
159 errx(2, "sendsrcaddr 2 succeeded!?");
160 }
161
162 s2 = socket(AF_INET, SOCK_DGRAM, 0);
163 if (s2 < 0)
164 err(2, "socket 3 failed");
165
166 on = 1;
167 if (setsockopt(s2, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
168 err(2, "setsockopt(REUSEADDR) failed");
169
170 local.sin_addr.s_addr = INADDR_ANY;
171 if (bind(s2, (const struct sockaddr *)&local, sizeof(local)) < 0)
172 err(2, "bind * failed");
173
174 /*
175 * Connected socket, implied laddr/lport bound:
176 * if inp_laddr == src --> pass.
177 * if inp_laddr != src --> fail.
178 *
179 * Wildcard bound above should not matter.
180 */
181 local_len = sizeof(local);
182 if (getsockname(s, (struct sockaddr *)&local, &local_len) < 0)
183 err(2, "getsockname failed");
184 n = test_sendsrcaddr(s, NULL, &src);
185 if (local.sin_addr.s_addr == src.s_addr) {
186 if (n < 0)
187 err(2, "sendsrcaddr 4 failed");
188 } else {
189 if (n > 0)
190 errx(2, "sendsrcaddr 3 succeeded!?");
191 }
192
193 close(s2);
194
195 exit(0);
196 }
197