xref: /dpdk/app/test/test_cmdline_ipaddr.c (revision aaa662e75c23c61a1d79bd4d1f9f35b4967c39db)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <stdio.h>
35 #include <string.h>
36 #include <inttypes.h>
37 #include <netinet/in.h>
38 
39 #ifndef __linux__
40 #ifndef __FreeBSD__
41 #include <net/socket.h>
42 #else
43 #include <sys/socket.h>
44 #endif
45 #endif
46 
47 #include <rte_string_fns.h>
48 
49 #include <cmdline_parse.h>
50 #include <cmdline_parse_ipaddr.h>
51 
52 #include "test_cmdline.h"
53 
54 #define IP4(a,b,c,d) {((uint32_t)(((a) & 0xff)) | \
55 					   (((b) & 0xff) << 8) | \
56 					   (((c) & 0xff) << 16)  | \
57 					   ((d) & 0xff)  << 24)}
58 
59 #define U16_SWAP(x) \
60 		(((x & 0xFF) << 8) | ((x & 0xFF00) >> 8))
61 
62 /* create IPv6 address, swapping bytes where needed */
63 #ifndef s6_addr16
64 # define s6_addr16      __u6_addr.__u6_addr16
65 #endif
66 #define IP6(a,b,c,d,e,f,g,h) .ipv6 = \
67 		{.s6_addr16 = \
68 		{U16_SWAP(a),U16_SWAP(b),U16_SWAP(c),U16_SWAP(d),\
69 		 U16_SWAP(e),U16_SWAP(f),U16_SWAP(g),U16_SWAP(h)}}
70 
71 /** these are defined in netinet/in.h but not present in linux headers */
72 #ifndef NIPQUAD
73 
74 #define NIPQUAD_FMT "%u.%u.%u.%u"
75 #define NIPQUAD(addr)				\
76 	(unsigned)((unsigned char *)&addr)[0],	\
77 	(unsigned)((unsigned char *)&addr)[1],	\
78 	(unsigned)((unsigned char *)&addr)[2],	\
79 	(unsigned)((unsigned char *)&addr)[3]
80 
81 #define NIP6_FMT "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x"
82 #define NIP6(addr)					\
83 	(unsigned)((addr).s6_addr[0]),			\
84 	(unsigned)((addr).s6_addr[1]),			\
85 	(unsigned)((addr).s6_addr[2]),			\
86 	(unsigned)((addr).s6_addr[3]),			\
87 	(unsigned)((addr).s6_addr[4]),			\
88 	(unsigned)((addr).s6_addr[5]),			\
89 	(unsigned)((addr).s6_addr[6]),			\
90 	(unsigned)((addr).s6_addr[7]),			\
91 	(unsigned)((addr).s6_addr[8]),			\
92 	(unsigned)((addr).s6_addr[9]),			\
93 	(unsigned)((addr).s6_addr[10]),			\
94 	(unsigned)((addr).s6_addr[11]),			\
95 	(unsigned)((addr).s6_addr[12]),			\
96 	(unsigned)((addr).s6_addr[13]),			\
97 	(unsigned)((addr).s6_addr[14]),			\
98 	(unsigned)((addr).s6_addr[15])
99 
100 #endif
101 
102 
103 
104 struct ipaddr_str {
105 	const char * str;
106 	cmdline_ipaddr_t addr;
107 	unsigned flags;
108 };
109 
110 const struct ipaddr_str ipaddr_valid_strs[] = {
111 		{"0.0.0.0", {AF_INET, {IP4(0,0,0,0)}, 0},
112 				CMDLINE_IPADDR_V4},
113 		{"0.0.0.0/0", {AF_INET, {IP4(0,0,0,0)}, 0},
114 				CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
115 		{"0.0.0.0/24", {AF_INET, {IP4(0,0,0,0)}, 24},
116 				CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
117 		{"192.168.1.0/24", {AF_INET, {IP4(192,168,1,0)}, 24},
118 				CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
119 		{"012.34.56.78/24", {AF_INET, {IP4(12,34,56,78)}, 24},
120 				CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
121 		{"34.56.78.90/1", {AF_INET, {IP4(34,56,78,90)}, 1},
122 				CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
123 		{"::", {AF_INET6, {IP6(0,0,0,0,0,0,0,0)}, 0},
124 					CMDLINE_IPADDR_V6},
125 		{"::1", {AF_INET6, {IP6(0,0,0,0,0,0,0,1)}, 0},
126 				CMDLINE_IPADDR_V6},
127 		{"::1/32", {AF_INET6, {IP6(0,0,0,0,0,0,0,1)}, 32},
128 				CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
129 		{"::/32", {AF_INET6, {IP6(0,0,0,0,0,0,0,0)}, 32},
130 					CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
131 		/* RFC5952 requests that only lowercase should be used */
132 		{"1234:5678:90ab:cdef:4321:8765:BA09:FEDC", {AF_INET6,
133 				{IP6(0x1234,0x5678,0x90AB,0xCDEF,0x4321,0x8765,0xBA09,0xFEDC)},
134 				0},
135 				CMDLINE_IPADDR_V6},
136 		{"1234::1234/64", {AF_INET6,
137 				{IP6(0x1234,0,0,0,0,0,0,0x1234)},
138 				64},
139 				CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
140 		{"1234::/64", {AF_INET6,
141 				{IP6(0x1234,0,0,0,0,0,0,0)},
142 				64},
143 				CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
144 		{"1:1::1/32", {AF_INET6,
145 				{IP6(1,1,0,0,0,0,0,1)},
146 				32},
147 				CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
148 		{"1:2:3:4::/64", {AF_INET6,
149 				{IP6(1,2,3,4,0,0,0,0)},
150 				64},
151 			CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
152 		{"::ffff:192.168.1.0/64", {AF_INET6,
153 				{IP6(0,0,0,0,0,0xFFFF,0xC0A8,0x100)},
154 				64},
155 			CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
156 		/* RFC5952 requests not using :: to skip one block of zeros*/
157 		{"1::2:3:4:5:6:7", {AF_INET6,
158 				{IP6(1,0,2,3,4,5,6,7)},
159 				0},
160 			CMDLINE_IPADDR_V6},
161 };
162 
163 const char * ipaddr_garbage_addr4_strs[] = {
164 		/* IPv4 */
165 		"192.168.1.0 garbage",
166 		"192.168.1.0\0garbage",
167 		"192.168.1.0#garbage",
168 		"192.168.1.0\tgarbage",
169 		"192.168.1.0\rgarbage",
170 		"192.168.1.0\ngarbage",
171 };
172 #define IPv4_GARBAGE_ADDR IP4(192,168,1,0)
173 
174 const char * ipaddr_garbage_addr6_strs[] = {
175 		/* IPv6 */
176 		"1:2:3:4::8 garbage",
177 		"1:2:3:4::8#garbage",
178 		"1:2:3:4::8\0garbage",
179 		"1:2:3:4::8\rgarbage",
180 		"1:2:3:4::8\ngarbage",
181 		"1:2:3:4::8\tgarbage",
182 };
183 #define IPv6_GARBAGE_ADDR {IP6(1,2,3,4,0,0,0,8)}
184 
185 const char * ipaddr_garbage_network4_strs[] = {
186 		/* IPv4 */
187 		"192.168.1.0/24 garbage",
188 		"192.168.1.0/24\0garbage",
189 		"192.168.1.0/24#garbage",
190 		"192.168.1.0/24\tgarbage",
191 		"192.168.1.0/24\rgarbage",
192 		"192.168.1.0/24\ngarbage",
193 };
194 #define IPv4_GARBAGE_PREFIX 24
195 
196 const char * ipaddr_garbage_network6_strs[] = {
197 		/* IPv6 */
198 		"1:2:3:4::8/64 garbage",
199 		"1:2:3:4::8/64#garbage",
200 		"1:2:3:4::8/64\0garbage",
201 		"1:2:3:4::8/64\rgarbage",
202 		"1:2:3:4::8/64\ngarbage",
203 		"1:2:3:4::8/64\tgarbage",
204 };
205 #define IPv6_GARBAGE_PREFIX 64
206 
207 
208 
209 const char * ipaddr_invalid_strs[] = {
210 		/** IPv4 **/
211 
212 		/* invalid numbers */
213 		"0.0.0.-1",
214 		"0.0.-1.0",
215 		"0.-1.0.0",
216 		"-1.0.0.0",
217 		"0.0.0.-1/24",
218 		"256.123.123.123",
219 		"255.256.123.123",
220 		"255.255.256.123",
221 		"255.255.255.256",
222 		"256.123.123.123/24",
223 		"255.256.123.123/24",
224 		"255.255.256.123/24",
225 		"255.255.255.256/24",
226 		/* invalid network mask */
227 		"1.2.3.4/33",
228 		"1.2.3.4/33231313",
229 		"1.2.3.4/-1",
230 		"1.2.3.4/24/33",
231 		"1.2.3.4/24/-1",
232 		"1.2.3.4/24/",
233 		/* wrong format */
234 		"1/24"
235 		"/24"
236 		"123.123.123",
237 		"123.123.123.",
238 		"123.123.123.123.",
239 		"123.123.123..123",
240 		"123.123.123.123.123",
241 		".123.123.123",
242 		".123.123.123.123",
243 		"123.123.123/24",
244 		"123.123.123./24",
245 		"123.123.123.123./24",
246 		"123.123.123..123/24",
247 		"123.123.123.123.123/24",
248 		".123.123.123/24",
249 		".123.123.123.123/24",
250 		/* invalid characters */
251 		"123.123.123.12F",
252 		"123.123.12F.123",
253 		"123.12F.123.123",
254 		"12F.123.123.123",
255 		"12J.123.123.123",
256 		"123,123,123,123",
257 		"123!123!123!12F",
258 		"123.123.123.123/4F",
259 
260 		/** IPv6 **/
261 
262 		/* wrong format */
263 		"::fffff",
264 		"ffff:",
265 		"1:2:3:4:5:6:7:192.168.1.1",
266 		"1234:192.168.1.1:ffff::",
267 		"1:2:3:4:5:6:7:890ab",
268 		"1:2:3:4:5:6:7890a:b",
269 		"1:2:3:4:5:67890:a:b",
270 		"1:2:3:4:56789:0:a:b",
271 		"1:2:3:45678:9:0:a:b",
272 		"1:2:34567:8:9:0:a:b",
273 		"1:23456:7:8:9:0:a:b",
274 		"12345:6:7:8:9:0:a:b",
275 		"1:::2",
276 		"1::::2",
277 		"::fffff/64",
278 		"1::2::3",
279 		"1::2::3/64",
280 		":1:2",
281 		":1:2/64",
282 		":1::2",
283 		":1::2/64",
284 		"1::2:3:4:5:6:7:8/64",
285 
286 		/* invalid network mask */
287 		"1:2:3:4:5:6:7:8/129",
288 		"1:2:3:4:5:6:7:8/-1",
289 
290 		/* invalid characters */
291 		"a:b:c:d:e:f:g::",
292 
293 		/** misc **/
294 
295 		/* too long */
296 		"1234:1234:1234:1234:1234:1234:1234:1234:1234:1234:1234"
297 		"random invalid text",
298 		"",
299 		"\0",
300 		" ",
301 };
302 
303 #define IPADDR_VALID_STRS_SIZE \
304 	(sizeof(ipaddr_valid_strs) / sizeof(ipaddr_valid_strs[0]))
305 #define IPADDR_GARBAGE_ADDR4_STRS_SIZE \
306 	(sizeof(ipaddr_garbage_addr4_strs) / sizeof(ipaddr_garbage_addr4_strs[0]))
307 #define IPADDR_GARBAGE_ADDR6_STRS_SIZE \
308 	(sizeof(ipaddr_garbage_addr6_strs) / sizeof(ipaddr_garbage_addr6_strs[0]))
309 #define IPADDR_GARBAGE_NETWORK4_STRS_SIZE \
310 	(sizeof(ipaddr_garbage_network4_strs) / sizeof(ipaddr_garbage_network4_strs[0]))
311 #define IPADDR_GARBAGE_NETWORK6_STRS_SIZE \
312 	(sizeof(ipaddr_garbage_network6_strs) / sizeof(ipaddr_garbage_network6_strs[0]))
313 #define IPADDR_INVALID_STRS_SIZE \
314 	(sizeof(ipaddr_invalid_strs) / sizeof(ipaddr_invalid_strs[0]))
315 
316 static void
317 dump_addr(cmdline_ipaddr_t addr)
318 {
319 	switch (addr.family) {
320 	case AF_INET:
321 	{
322 		printf(NIPQUAD_FMT " prefixlen=%u\n",
323 				NIPQUAD(addr.addr.ipv4.s_addr), addr.prefixlen);
324 		break;
325 	}
326 	case AF_INET6:
327 	{
328 		printf(NIP6_FMT " prefixlen=%u\n",
329 				NIP6(addr.addr.ipv6), addr.prefixlen);
330 		break;
331 	}
332 	default:
333 		printf("Can't dump: unknown address family.\n");
334 		return;
335 	}
336 }
337 
338 
339 static int
340 is_addr_different(cmdline_ipaddr_t addr1, cmdline_ipaddr_t addr2)
341 {
342 	if (addr1.family != addr2.family)
343 		return 1;
344 
345 	if (addr1.prefixlen != addr2.prefixlen)
346 		return 1;
347 
348 	switch (addr1.family) {
349 	/* IPv4 */
350 	case AF_INET:
351 		if (memcmp(&addr1.addr.ipv4, &addr2.addr.ipv4,
352 				sizeof(struct in_addr)) != 0)
353 			return 1;
354 		break;
355 	/* IPv6 */
356 	case AF_INET6:
357 	{
358 		if (memcmp(&addr1.addr.ipv6, &addr2.addr.ipv6,
359 				sizeof(struct in6_addr)) != 0)
360 			return 1;
361 		break;
362 	}
363 	/* thing that should not be */
364 	default:
365 		return -1;
366 	}
367 	return 0;
368 }
369 
370 static int
371 can_parse_addr(unsigned addr_flags, unsigned test_flags)
372 {
373 	if ((test_flags & addr_flags) == addr_flags) {
374 		/* if we are not trying to parse network addresses */
375 		if (test_flags < CMDLINE_IPADDR_NETWORK)
376 			return 1;
377 		/* if this is a network address */
378 		else if (addr_flags & CMDLINE_IPADDR_NETWORK)
379 			return 1;
380 	}
381 	return 0;
382 }
383 
384 int
385 test_parse_ipaddr_valid(void)
386 {
387 	cmdline_parse_token_ipaddr_t token;
388 	char buf[CMDLINE_TEST_BUFSIZE];
389 	cmdline_ipaddr_t result;
390 	unsigned i;
391 	uint8_t flags;
392 	int ret;
393 
394 	/* cover all cases in help */
395 	for (flags = 0x1; flags < 0x8; flags++) {
396 		token.ipaddr_data.flags = flags;
397 
398 		memset(buf, 0, sizeof(buf));
399 
400 		if (cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
401 				buf, sizeof(buf)) == -1) {
402 			printf("Error: help rejected valid parameters!\n");
403 			return -1;
404 		}
405 	}
406 
407 	/* test valid strings */
408 	for (i = 0; i < IPADDR_VALID_STRS_SIZE; i++) {
409 
410 		/* test each valid string against different flags */
411 		for (flags = 1; flags < 0x8; flags++) {
412 
413 			/* skip bad flag */
414 			if (flags == CMDLINE_IPADDR_NETWORK)
415 				continue;
416 
417 			/* clear out everything */
418 			memset(buf, 0, sizeof(buf));
419 			memset(&result, 0, sizeof(result));
420 			memset(&token, 0, sizeof(token));
421 
422 			token.ipaddr_data.flags = flags;
423 
424 			cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
425 							buf, sizeof(buf));
426 
427 			ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
428 				ipaddr_valid_strs[i].str, (void*)&result,
429 				sizeof(result));
430 
431 			/* if should have passed, or should have failed */
432 			if ((ret < 0) ==
433 					(can_parse_addr(ipaddr_valid_strs[i].flags, flags))) {
434 				printf("Error: unexpected behavior when parsing %s as %s!\n",
435 						ipaddr_valid_strs[i].str, buf);
436 				printf("Parsed result: ");
437 				dump_addr(result);
438 				printf("Expected result: ");
439 				dump_addr(ipaddr_valid_strs[i].addr);
440 				return -1;
441 			}
442 			if (ret != -1 &&
443 					is_addr_different(result, ipaddr_valid_strs[i].addr)) {
444 				printf("Error: result mismatch when parsing %s as %s!\n",
445 						ipaddr_valid_strs[i].str, buf);
446 				printf("Parsed result: ");
447 				dump_addr(result);
448 				printf("Expected result: ");
449 				dump_addr(ipaddr_valid_strs[i].addr);
450 				return -1;
451 			}
452 		}
453 	}
454 
455 	/* test garbage ipv4 address strings */
456 	for (i = 0; i < IPADDR_GARBAGE_ADDR4_STRS_SIZE; i++) {
457 
458 		struct in_addr tmp = IPv4_GARBAGE_ADDR;
459 
460 		/* test each valid string against different flags */
461 		for (flags = 1; flags < 0x8; flags++) {
462 
463 			/* skip bad flag */
464 			if (flags == CMDLINE_IPADDR_NETWORK)
465 				continue;
466 
467 			/* clear out everything */
468 			memset(buf, 0, sizeof(buf));
469 			memset(&result, 0, sizeof(result));
470 			memset(&token, 0, sizeof(token));
471 
472 			token.ipaddr_data.flags = flags;
473 
474 			cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
475 							buf, sizeof(buf));
476 
477 			ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
478 				ipaddr_garbage_addr4_strs[i], (void*)&result,
479 				sizeof(result));
480 
481 			/* if should have passed, or should have failed */
482 			if ((ret < 0) ==
483 					(can_parse_addr(CMDLINE_IPADDR_V4, flags))) {
484 				printf("Error: unexpected behavior when parsing %s as %s!\n",
485 						ipaddr_garbage_addr4_strs[i], buf);
486 				return -1;
487 			}
488 			if (ret != -1 &&
489 					memcmp(&result.addr.ipv4, &tmp, sizeof(tmp))) {
490 				printf("Error: result mismatch when parsing %s as %s!\n",
491 						ipaddr_garbage_addr4_strs[i], buf);
492 				return -1;
493 			}
494 		}
495 	}
496 
497 	/* test garbage ipv6 address strings */
498 	for (i = 0; i < IPADDR_GARBAGE_ADDR6_STRS_SIZE; i++) {
499 
500 		cmdline_ipaddr_t tmp = {.addr = IPv6_GARBAGE_ADDR};
501 
502 		/* test each valid string against different flags */
503 		for (flags = 1; flags < 0x8; flags++) {
504 
505 			/* skip bad flag */
506 			if (flags == CMDLINE_IPADDR_NETWORK)
507 				continue;
508 
509 			/* clear out everything */
510 			memset(buf, 0, sizeof(buf));
511 			memset(&result, 0, sizeof(result));
512 			memset(&token, 0, sizeof(token));
513 
514 			token.ipaddr_data.flags = flags;
515 
516 			cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
517 							buf, sizeof(buf));
518 
519 			ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
520 				ipaddr_garbage_addr6_strs[i], (void*)&result,
521 				sizeof(result));
522 
523 			/* if should have passed, or should have failed */
524 			if ((ret < 0) ==
525 					(can_parse_addr(CMDLINE_IPADDR_V6, flags))) {
526 				printf("Error: unexpected behavior when parsing %s as %s!\n",
527 						ipaddr_garbage_addr6_strs[i], buf);
528 				return -1;
529 			}
530 			if (ret != -1 &&
531 					memcmp(&result.addr.ipv6, &tmp.addr.ipv6, sizeof(struct in6_addr))) {
532 				printf("Error: result mismatch when parsing %s as %s!\n",
533 						ipaddr_garbage_addr6_strs[i], buf);
534 				return -1;
535 			}
536 		}
537 	}
538 
539 
540 	/* test garbage ipv4 network strings */
541 	for (i = 0; i < IPADDR_GARBAGE_NETWORK4_STRS_SIZE; i++) {
542 
543 		struct in_addr tmp = IPv4_GARBAGE_ADDR;
544 
545 		/* test each valid string against different flags */
546 		for (flags = 1; flags < 0x8; flags++) {
547 
548 			/* skip bad flag */
549 			if (flags == CMDLINE_IPADDR_NETWORK)
550 				continue;
551 
552 			/* clear out everything */
553 			memset(buf, 0, sizeof(buf));
554 			memset(&result, 0, sizeof(result));
555 			memset(&token, 0, sizeof(token));
556 
557 			token.ipaddr_data.flags = flags;
558 
559 			cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
560 							buf, sizeof(buf));
561 
562 			ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
563 				ipaddr_garbage_network4_strs[i], (void*)&result,
564 				sizeof(result));
565 
566 			/* if should have passed, or should have failed */
567 			if ((ret < 0) ==
568 					(can_parse_addr(CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK, flags))) {
569 				printf("Error: unexpected behavior when parsing %s as %s!\n",
570 						ipaddr_garbage_network4_strs[i], buf);
571 				return -1;
572 			}
573 			if (ret != -1 &&
574 					memcmp(&result.addr.ipv4, &tmp, sizeof(tmp))) {
575 				printf("Error: result mismatch when parsing %s as %s!\n",
576 						ipaddr_garbage_network4_strs[i], buf);
577 				return -1;
578 			}
579 		}
580 	}
581 
582 	/* test garbage ipv6 address strings */
583 	for (i = 0; i < IPADDR_GARBAGE_NETWORK6_STRS_SIZE; i++) {
584 
585 		cmdline_ipaddr_t tmp = {.addr = IPv6_GARBAGE_ADDR};
586 
587 		/* test each valid string against different flags */
588 		for (flags = 1; flags < 0x8; flags++) {
589 
590 			/* skip bad flag */
591 			if (flags == CMDLINE_IPADDR_NETWORK)
592 				continue;
593 
594 			/* clear out everything */
595 			memset(buf, 0, sizeof(buf));
596 			memset(&result, 0, sizeof(result));
597 			memset(&token, 0, sizeof(token));
598 
599 			token.ipaddr_data.flags = flags;
600 
601 			cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
602 							buf, sizeof(buf));
603 
604 			ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
605 				ipaddr_garbage_network6_strs[i], (void*)&result,
606 				sizeof(result));
607 
608 			/* if should have passed, or should have failed */
609 			if ((ret < 0) ==
610 					(can_parse_addr(CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK, flags))) {
611 				printf("Error: unexpected behavior when parsing %s as %s!\n",
612 						ipaddr_garbage_network6_strs[i], buf);
613 				return -1;
614 			}
615 			if (ret != -1 &&
616 					memcmp(&result.addr.ipv6, &tmp.addr.ipv6, sizeof(struct in6_addr))) {
617 				printf("Error: result mismatch when parsing %s as %s!\n",
618 						ipaddr_garbage_network6_strs[i], buf);
619 				return -1;
620 			}
621 		}
622 	}
623 
624 	return 0;
625 }
626 
627 int
628 test_parse_ipaddr_invalid_data(void)
629 {
630 	cmdline_parse_token_ipaddr_t token;
631 	char buf[CMDLINE_TEST_BUFSIZE];
632 	cmdline_ipaddr_t result;
633 	unsigned i;
634 	uint8_t flags;
635 	int ret;
636 
637 	memset(&result, 0, sizeof(result));
638 
639 	/* test invalid strings */
640 	for (i = 0; i < IPADDR_INVALID_STRS_SIZE; i++) {
641 
642 		/* test each valid string against different flags */
643 		for (flags = 1; flags < 0x8; flags++) {
644 
645 			/* skip bad flag */
646 			if (flags == CMDLINE_IPADDR_NETWORK)
647 				continue;
648 
649 			/* clear out everything */
650 			memset(buf, 0, sizeof(buf));
651 			memset(&token, 0, sizeof(token));
652 
653 			token.ipaddr_data.flags = flags;
654 
655 			cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
656 					buf, sizeof(buf));
657 
658 			ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
659 				ipaddr_invalid_strs[i], (void*)&result,
660 				sizeof(result));
661 
662 			if (ret != -1) {
663 				printf("Error: parsing %s as %s succeeded!\n",
664 						ipaddr_invalid_strs[i], buf);
665 				printf("Parsed result: ");
666 				dump_addr(result);
667 				return -1;
668 			}
669 		}
670 	}
671 
672 	return 0;
673 }
674 
675 int
676 test_parse_ipaddr_invalid_param(void)
677 {
678 	cmdline_parse_token_ipaddr_t token;
679 	char buf[CMDLINE_TEST_BUFSIZE];
680 	cmdline_ipaddr_t result;
681 
682 	snprintf(buf, sizeof(buf), "1.2.3.4");
683 	token.ipaddr_data.flags = CMDLINE_IPADDR_V4;
684 
685 	/* null token */
686 	if (cmdline_parse_ipaddr(NULL, buf, (void*)&result,
687 			sizeof(result)) != -1) {
688 		printf("Error: parser accepted invalid parameters!\n");
689 		return -1;
690 	}
691 	/* null buffer */
692 	if (cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
693 			NULL, (void*)&result, sizeof(result)) != -1) {
694 		printf("Error: parser accepted invalid parameters!\n");
695 		return -1;
696 	}
697 	/* empty buffer */
698 	if (cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
699 			"", (void*)&result, sizeof(result)) != -1) {
700 		printf("Error: parser accepted invalid parameters!\n");
701 		return -1;
702 	}
703 	/* null result */
704 	if (cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
705 			buf, NULL, 0) == -1) {
706 		printf("Error: parser rejected null result!\n");
707 		return -1;
708 	}
709 
710 	/* null token */
711 	if (cmdline_get_help_ipaddr(NULL, buf, 0) != -1) {
712 		printf("Error: help accepted invalid parameters!\n");
713 		return -1;
714 	}
715 	/* null buffer */
716 	if (cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
717 			NULL, 0) != -1) {
718 		printf("Error: help accepted invalid parameters!\n");
719 		return -1;
720 	}
721 	return 0;
722 }
723