1 /*-
2  * Copyright (c) 2007 Michael Telahun Makonnen
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 
34 #include <netinet/in.h>
35 #include <netinet/ip6.h>
36 
37 #include <netdb.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 
42 #include "test_subr.h"
43 
44 static void init_hdrs(struct msghdr *, struct cmsghdr *, char *, size_t);
45 static void test_cmsg_firsthdr();
46 static void test_cmsg_nexthdr();
47 static void test_rth_space();
48 static void test_rth_segments();
49 static void test_rth_add();
50 static void test_rth_init();
51 
52 int
53 main(int argc, char* argv[])
54 {
55 	/*
56 	 * Initialize global variables.
57 	 */
58 	g_total = 0;
59 	g_pass = 0;
60 	g_fail = 0;
61 	memset(g_funcname, 0, sizeof(g_funcname));
62 
63 	/*
64 	 * Start the tests.
65 	 */
66 	printf("Starting inet6_rth_* and cmsg macro regression tests...\n");
67 
68 	test_cmsg_firsthdr();			/* CMSG_FIRSTHDR    */
69 	test_cmsg_nexthdr();			/* CMSG_NEXTHDR	    */
70 	test_rth_space();			/* inet6_rth_space  */
71 	test_rth_segments();			/* inet6_rth_segments */
72 	test_rth_add();				/* inet6_rth_add    */
73 	test_rth_init();			/* inet6_rth_space  */
74 
75 	if (g_fail == 0)
76 		printf("OK. ");
77 	else
78 		printf("NOT OK. ");
79 	printf("Total: %d  Pass: %d  Fail: %d\n", g_total, g_pass, g_fail);
80 
81 	return (g_fail);
82 }
83 
84 void
85 test_rth_init()
86 {
87 	char buf[10240];
88 	char *pbuf;
89 
90 	set_funcname("test_rth_init", sizeof("test_rth_init\0"));
91 
92 	pbuf = inet6_rth_init((void *)buf, 10, IPV6_RTHDR_TYPE_0, 100);
93 	checkptr(NULL, pbuf, "buffer too small\0");
94 
95 	pbuf = inet6_rth_init((void *)buf, 10240, IPV6_RTHDR_TYPE_0, 0);
96 	checkptr((caddr_t)&buf, pbuf, "0 segments\0");
97 
98 	pbuf = inet6_rth_init((void *)buf, 10240, IPV6_RTHDR_TYPE_0, 127);
99 	checkptr((caddr_t)&buf, pbuf, "127 segments\0");
100 
101 	pbuf = inet6_rth_init((void *)buf, 10240, IPV6_RTHDR_TYPE_0, -1);
102 	checkptr(NULL, pbuf, "negative number of segments\0");
103 
104 	pbuf = inet6_rth_init((void *)buf, 10240, IPV6_RTHDR_TYPE_0, 128);
105 	checkptr(NULL, pbuf, "128 segments\0");
106 }
107 
108 void
109 test_rth_add()
110 {
111 	int	i, ret;
112 	char	buf[10240];
113 	struct addrinfo *res;
114 	struct addrinfo hints;
115 
116 	set_funcname("test_rth_add", sizeof("test_rth_add\0"));
117 
118 	if (NULL == inet6_rth_init(buf, 10240, IPV6_RTHDR_TYPE_0, 127))
119 		abort();
120 	memset((void *)&hints, 0, sizeof(struct addrinfo));
121 	hints.ai_family = AF_INET6;
122 	hints.ai_flags = AI_NUMERICHOST;
123 	if (0 != getaddrinfo("::1", NULL, (const struct addrinfo *)&hints, &res))
124 		abort();
125 	for (i = 0; i < 127; i++)
126 		inet6_rth_add((void *)buf,
127 		    &((struct sockaddr_in6 *)(res->ai_addr))->sin6_addr);
128 	checknum(127, ((struct ip6_rthdr0 *)buf)->ip6r0_segleft, 0,
129 	    "add 127 segments\0");
130 
131 	ret = inet6_rth_add((void *)buf,
132 	    &((struct sockaddr_in6 *)(res->ai_addr))->sin6_addr);
133 	checknum(-1, ret, 0, "add 128th segment to 127 segment header\0");
134 
135 	freeaddrinfo(res);
136 }
137 
138 void
139 test_rth_segments()
140 {
141 	int	seg;
142 	char	buf[10240];
143 
144 	set_funcname("test_rth_segments", sizeof("test_rth_segments\0"));
145 
146 	/*
147 	 * Test: invalid routing header type.
148 	 */
149 	if (NULL == inet6_rth_init((void *)buf, 10240, IPV6_RTHDR_TYPE_0, 0))
150 		abort();
151 	((struct ip6_rthdr *)buf)->ip6r_type = ~IPV6_RTHDR_TYPE_0;
152 	seg = inet6_rth_segments((const void *)buf);
153 	checknum(-1, seg, 0, "invalid routing header type\0");
154 
155 	/*
156 	 * Test: 0 segments.
157 	 */
158 	if (NULL == inet6_rth_init((void *)buf, 10240, IPV6_RTHDR_TYPE_0, 0))
159 		abort();
160 	seg = inet6_rth_segments((const void *)buf);
161 	checknum(0, seg, 0, "0 segments\0");
162 
163 	/*
164 	 * Test: 127 segments.
165 	 */
166 	if (NULL == inet6_rth_init((void *)buf, 10240, IPV6_RTHDR_TYPE_0, 127))
167 		abort();
168 	seg = inet6_rth_segments((const void *)buf);
169 	checknum(127, seg, 0, "127 segments\0");
170 
171 	/*
172 	 * Test: -1 segments.
173 	 */
174 /*
175 	if (NULL == inet6_rth_init((void *)buf, 10240, IPV6_RTHDR_TYPE_0, 0))
176 		abort();
177 	((struct ip6_rthdr0 *)buf)->ip6r0_len = -1 * 2;
178 	seg = inet6_rth_segments((const void *)buf);
179 	checknum(-1, seg, 0, "-1 segments\0");
180 */
181 	/*
182 	 * Test: 128 segments.
183 	 */
184 /*
185 	if (NULL == inet6_rth_init((void *)buf, 10240, IPV6_RTHDR_TYPE_0, 127))
186 		abort();
187 	((struct ip6_rthdr0 *)buf)->ip6r0_len = 128 * 2;
188 	seg = inet6_rth_segments((const void *)buf);
189 	checknum(-1, seg, 0, "128 segments\0");
190 */
191 }
192 
193 void
194 test_rth_space()
195 {
196 	socklen_t len;
197 
198 	set_funcname("test_rth_space", sizeof("test_rth_space\0"));
199 
200 	/*
201 	 * Test: invalid routing header type.
202 	 */
203 	len = inet6_rth_space(~IPV6_RTHDR_TYPE_0, 0);
204 	checknum(0, len, 0, "invalid routing header type\0");
205 
206 	/*
207 	 * Test: valid number of segments.
208 	 */
209 	len = inet6_rth_space(IPV6_RTHDR_TYPE_0, 0);
210 	checknum(0, len, 1, "0 segments\0");
211 	len = inet6_rth_space(IPV6_RTHDR_TYPE_0, 127);
212 	checknum(0, len, 1, "0 segments\0");
213 
214 	/*
215 	 * Test: invalid number of segments.
216 	 */
217 	len = inet6_rth_space(IPV6_RTHDR_TYPE_0, -1);
218 	checknum(0, len, 0, "-1 segments\0");
219 	len = inet6_rth_space(IPV6_RTHDR_TYPE_0, 128);
220 	checknum(0, len, 0, "128 segments\0");
221 }
222 
223 void
224 test_cmsg_nexthdr()
225 {
226 	struct msghdr  mh;
227 	struct cmsghdr cmh;
228 	struct cmsghdr *cmhp, *cmhnextp;
229 	char ancbuf[10240];
230 	char magic[] = "MAGIC";
231 
232 	set_funcname("test_cmsg_nexthdr", sizeof("test_cmsg_nexthdr"));
233 
234 	/*
235 	 * Test: More than one cmsghdr
236 	 */
237 	init_hdrs(&mh, &cmh, ancbuf, sizeof(ancbuf));
238 	mh.msg_control = (caddr_t)ancbuf;
239 	mh.msg_controllen  = CMSG_SPACE(0) * 2;	/* 2 cmsghdr with no data */
240 	cmh.cmsg_len = CMSG_LEN(0);
241 
242 	/*
243 	 * Copy the same instance of cmsghdr twice. Use a magic value
244 	 * to id the second copy.
245 	 */
246 	bcopy((void *)&cmh, (void *)ancbuf, sizeof(cmh));
247 	strlcpy((char *)&cmh, (const char *)&magic, sizeof(magic));
248 	bcopy((void *)&cmh,
249 	    (void *)((caddr_t)ancbuf + CMSG_SPACE(0)),
250 	    sizeof(cmh));
251 	cmhp = CMSG_FIRSTHDR(&mh);
252 	cmhnextp = CMSG_NXTHDR(&mh, cmhp);
253 	checkstr((const char *)&magic, (const char *)cmhnextp, sizeof(magic),
254 	    "more than one cmsghdr\0");
255 
256 	/*
257 	 * Test: only one cmsghdr
258 	 */
259 	init_hdrs(&mh, &cmh, ancbuf, sizeof(ancbuf));
260 	mh.msg_control = (caddr_t)ancbuf;
261 	mh.msg_controllen  = CMSG_SPACE(0);
262 	cmh.cmsg_len = CMSG_LEN(0);
263 	bcopy((void *)&cmh, (void *)ancbuf, sizeof(cmh));
264 	cmhp = CMSG_FIRSTHDR(&mh);
265 	cmhnextp = CMSG_NXTHDR(&mh, cmhp);
266 	checkptr(NULL, (caddr_t)cmhnextp, "only one cmsghdr\0");
267 
268 	/*
269 	 * Test: NULL cmsg pointer
270 	 */
271 	init_hdrs(&mh, &cmh, ancbuf, sizeof(ancbuf));
272 	mh.msg_control = (caddr_t)ancbuf;
273 	mh.msg_controllen  = sizeof(ancbuf);
274 	cmh.cmsg_len = sizeof(ancbuf);
275 	bcopy((void *)&cmh, (void *)ancbuf, sizeof(cmh));
276 	cmhp = CMSG_FIRSTHDR(&mh);
277 	cmhnextp = CMSG_NXTHDR(&mh, NULL);
278 	checkptr((caddr_t)cmhp, (caddr_t)cmhnextp, "null second argument\0");
279 }
280 
281 void
282 test_cmsg_firsthdr()
283 {
284 	struct msghdr  mh;
285 	struct cmsghdr cmh;
286 	struct cmsghdr *cmhp;
287 	char ancbuf[1024];
288 	char magic[] = "MAGIC";
289 
290 	set_funcname("test_cmsg_firsthdr", sizeof("test_cmsg_firsthdr"));
291 
292 	/* CMSG_FIRSTHDR() where msg_control is NULL */
293 	init_hdrs(&mh, NULL, NULL, 0);
294 	mh.msg_control = NULL;
295 	cmhp = CMSG_FIRSTHDR(&mh);
296 	checkptr(NULL, (caddr_t)cmhp,
297 	    "msg_control is NULL\0");
298 
299 	/* - where msg_controllen < sizeof cmsghdr */
300 	init_hdrs(&mh, NULL, NULL, 0);
301 	mh.msg_control = (caddr_t)&cmh;
302 	mh.msg_controllen = sizeof(cmh) - 1;
303 	cmhp = CMSG_FIRSTHDR(&mh);
304 	checkptr(NULL, (caddr_t)cmhp,
305 	    "msg_controllen < sizeof cmsghdr\0");
306 
307 	/* - where msg_controllen == 0 */
308 	init_hdrs(&mh, NULL, NULL, 0);
309 	mh.msg_control = (caddr_t)&cmh;
310 	mh.msg_controllen = 0;
311 	cmhp = CMSG_FIRSTHDR(&mh);
312 	checkptr(NULL, (caddr_t)cmhp,
313 	    "msg_controllen == 0\0");
314 
315 	/* no errors */
316 	init_hdrs(&mh, &cmh, ancbuf, sizeof(ancbuf));
317 	memset((void *)ancbuf, 0, sizeof(ancbuf));
318 	mh.msg_control = (caddr_t)ancbuf;
319 	mh.msg_controllen  = sizeof(ancbuf);
320 	strlcpy((char *)&cmh, (const char *)&magic, sizeof(magic));
321 	bcopy((void *)&cmh, (void *)ancbuf, sizeof(cmh));
322 	cmhp = CMSG_FIRSTHDR(&mh);
323 	checkstr((const char *)&magic, (const char *)cmhp, sizeof(magic),
324 	    "with payload\0");
325 }
326 
327 void
328 init_hdrs(struct msghdr *mhp, struct cmsghdr *cmhp, char *bufp, size_t bufsize)
329 {
330 	if (mhp != NULL)
331 		memset((void *)mhp, 0, sizeof(struct msghdr));
332 	if (cmhp != NULL)
333 		memset((void *)cmhp, 0, sizeof(struct cmsghdr));
334 	if (bufp != NULL)
335 		memset((void *)bufp, 0, bufsize);
336 }
337