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
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
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
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