xref: /illumos-gate/usr/src/test/util-tests/tests/libdhcputil/libdhcputil.c (revision ecd9ba3c681525bcbb1953941065d28b8ab9a4ec)
1*ecd9ba3cSJoshua M. Clulow /*
2*ecd9ba3cSJoshua M. Clulow  * This file and its contents are supplied under the terms of the
3*ecd9ba3cSJoshua M. Clulow  * Common Development and Distribution License ("CDDL"), version 1.0.
4*ecd9ba3cSJoshua M. Clulow  * You may only use this file in accordance with the terms of version
5*ecd9ba3cSJoshua M. Clulow  * 1.0 of the CDDL.
6*ecd9ba3cSJoshua M. Clulow  *
7*ecd9ba3cSJoshua M. Clulow  * A full copy of the text of the CDDL should have accompanied this
8*ecd9ba3cSJoshua M. Clulow  * source.  A copy of the CDDL is also available via the Internet at
9*ecd9ba3cSJoshua M. Clulow  * http://www.illumos.org/license/CDDL.
10*ecd9ba3cSJoshua M. Clulow  */
11*ecd9ba3cSJoshua M. Clulow 
12*ecd9ba3cSJoshua M. Clulow /*
13*ecd9ba3cSJoshua M. Clulow  * Copyright 2026 Oxide Computer Company
14*ecd9ba3cSJoshua M. Clulow  */
15*ecd9ba3cSJoshua M. Clulow 
16*ecd9ba3cSJoshua M. Clulow /*
17*ecd9ba3cSJoshua M. Clulow  * This program is a small test harness for libdhcputil.
18*ecd9ba3cSJoshua M. Clulow  */
19*ecd9ba3cSJoshua M. Clulow 
20*ecd9ba3cSJoshua M. Clulow #include <stdlib.h>
21*ecd9ba3cSJoshua M. Clulow #include <stdio.h>
22*ecd9ba3cSJoshua M. Clulow #include <string.h>
23*ecd9ba3cSJoshua M. Clulow #include <errno.h>
24*ecd9ba3cSJoshua M. Clulow #include <err.h>
25*ecd9ba3cSJoshua M. Clulow #include <netinet/in.h>
26*ecd9ba3cSJoshua M. Clulow #include <sys/sysmacros.h>
27*ecd9ba3cSJoshua M. Clulow 
28*ecd9ba3cSJoshua M. Clulow #include <netinet/dhcp.h>
29*ecd9ba3cSJoshua M. Clulow #include <dhcp_inittab.h>
30*ecd9ba3cSJoshua M. Clulow 
31*ecd9ba3cSJoshua M. Clulow typedef struct {
32*ecd9ba3cSJoshua M. Clulow 	uint8_t *tc_binary;
33*ecd9ba3cSJoshua M. Clulow 	size_t tc_binlen;
34*ecd9ba3cSJoshua M. Clulow 	const char *tc_string;
35*ecd9ba3cSJoshua M. Clulow } testcase_t;
36*ecd9ba3cSJoshua M. Clulow 
37*ecd9ba3cSJoshua M. Clulow #define	CASE(s, ...)	{					\
38*ecd9ba3cSJoshua M. Clulow 	.tc_binary = (uint8_t[]) { __VA_ARGS__ },		\
39*ecd9ba3cSJoshua M. Clulow 	.tc_binlen = sizeof ((uint8_t[]) { __VA_ARGS__ }),	\
40*ecd9ba3cSJoshua M. Clulow 	.tc_string = s,						\
41*ecd9ba3cSJoshua M. Clulow }
42*ecd9ba3cSJoshua M. Clulow 
43*ecd9ba3cSJoshua M. Clulow testcase_t such_cases[] = {
44*ecd9ba3cSJoshua M. Clulow 	/*
45*ecd9ba3cSJoshua M. Clulow 	 * A zero-length value should result in the empty string:
46*ecd9ba3cSJoshua M. Clulow 	 */
47*ecd9ba3cSJoshua M. Clulow 	CASE(""),
48*ecd9ba3cSJoshua M. Clulow 
49*ecd9ba3cSJoshua M. Clulow 	/*
50*ecd9ba3cSJoshua M. Clulow 	 * Confirm that we can support each possible prefix length:
51*ecd9ba3cSJoshua M. Clulow 	 */
52*ecd9ba3cSJoshua M. Clulow 	CASE("128.0.0.0/1:1.2.3.4",
53*ecd9ba3cSJoshua M. Clulow 	    1,		128,			1, 2, 3, 4),
54*ecd9ba3cSJoshua M. Clulow 	CASE("128.0.0.0/2:1.2.3.4",
55*ecd9ba3cSJoshua M. Clulow 	    2,		128,			1, 2, 3, 4),
56*ecd9ba3cSJoshua M. Clulow 	CASE("128.0.0.0/3:1.2.3.4",
57*ecd9ba3cSJoshua M. Clulow 	    3,		128,			1, 2, 3, 4),
58*ecd9ba3cSJoshua M. Clulow 	CASE("128.0.0.0/4:1.2.3.4",
59*ecd9ba3cSJoshua M. Clulow 	    4,		128,			1, 2, 3, 4),
60*ecd9ba3cSJoshua M. Clulow 	CASE("10.0.0.0/5:1.2.3.4",
61*ecd9ba3cSJoshua M. Clulow 	    5,		10,			1, 2, 3, 4),
62*ecd9ba3cSJoshua M. Clulow 	CASE("10.0.0.0/6:1.2.3.4",
63*ecd9ba3cSJoshua M. Clulow 	    6,		10,			1, 2, 3, 4),
64*ecd9ba3cSJoshua M. Clulow 	CASE("10.0.0.0/7:1.2.3.4",
65*ecd9ba3cSJoshua M. Clulow 	    7,		10,			1, 2, 3, 4),
66*ecd9ba3cSJoshua M. Clulow 	CASE("10.0.0.0/8:1.2.3.4",
67*ecd9ba3cSJoshua M. Clulow 	    8,		10,			1, 2, 3, 4),
68*ecd9ba3cSJoshua M. Clulow 	CASE("10.128.0.0/9:1.2.3.4",
69*ecd9ba3cSJoshua M. Clulow 	    9,		10, 128,		1, 2, 3, 4),
70*ecd9ba3cSJoshua M. Clulow 	CASE("10.128.0.0/10:1.2.3.4",
71*ecd9ba3cSJoshua M. Clulow 	    10,		10, 128,		1, 2, 3, 4),
72*ecd9ba3cSJoshua M. Clulow 	CASE("10.128.0.0/11:1.2.3.4",
73*ecd9ba3cSJoshua M. Clulow 	    11,		10, 128,		1, 2, 3, 4),
74*ecd9ba3cSJoshua M. Clulow 	CASE("10.128.0.0/12:1.2.3.4",
75*ecd9ba3cSJoshua M. Clulow 	    12,		10, 128,		1, 2, 3, 4),
76*ecd9ba3cSJoshua M. Clulow 	CASE("10.128.0.0/13:1.2.3.4",
77*ecd9ba3cSJoshua M. Clulow 	    13,		10, 128,		1, 2, 3, 4),
78*ecd9ba3cSJoshua M. Clulow 	CASE("10.128.0.0/14:1.2.3.4",
79*ecd9ba3cSJoshua M. Clulow 	    14,		10, 128,		1, 2, 3, 4),
80*ecd9ba3cSJoshua M. Clulow 	CASE("10.128.0.0/15:1.2.3.4",
81*ecd9ba3cSJoshua M. Clulow 	    15,		10, 128,		1, 2, 3, 4),
82*ecd9ba3cSJoshua M. Clulow 	CASE("1.255.0.0/16:1.2.3.4",
83*ecd9ba3cSJoshua M. Clulow 	    16,		1, 255,			1, 2, 3, 4),
84*ecd9ba3cSJoshua M. Clulow 	CASE("1.255.128.0/17:1.2.3.4",
85*ecd9ba3cSJoshua M. Clulow 	    17,		1, 255, 128,		1, 2, 3, 4),
86*ecd9ba3cSJoshua M. Clulow 	CASE("1.255.128.0/18:1.2.3.4",
87*ecd9ba3cSJoshua M. Clulow 	    18,		1, 255, 128,		1, 2, 3, 4),
88*ecd9ba3cSJoshua M. Clulow 	CASE("1.255.128.0/19:1.2.3.4",
89*ecd9ba3cSJoshua M. Clulow 	    19,		1, 255, 128,		1, 2, 3, 4),
90*ecd9ba3cSJoshua M. Clulow 	CASE("1.255.128.0/20:1.2.3.4",
91*ecd9ba3cSJoshua M. Clulow 	    20,		1, 255, 128,		1, 2, 3, 4),
92*ecd9ba3cSJoshua M. Clulow 	CASE("1.255.128.0/21:1.2.3.4",
93*ecd9ba3cSJoshua M. Clulow 	    21,		1, 255, 128,		1, 2, 3, 4),
94*ecd9ba3cSJoshua M. Clulow 	CASE("1.255.128.0/22:1.2.3.4",
95*ecd9ba3cSJoshua M. Clulow 	    22,		1, 255, 128,		1, 2, 3, 4),
96*ecd9ba3cSJoshua M. Clulow 	CASE("1.255.128.0/23:1.2.3.4",
97*ecd9ba3cSJoshua M. Clulow 	    23,		1, 255, 128,		1, 2, 3, 4),
98*ecd9ba3cSJoshua M. Clulow 	CASE("1.255.255.0/24:1.2.3.4",
99*ecd9ba3cSJoshua M. Clulow 	    24,		1, 255, 255,		1, 2, 3, 4),
100*ecd9ba3cSJoshua M. Clulow 
101*ecd9ba3cSJoshua M. Clulow 	CASE("1.77.99.128/25:1.2.3.4",
102*ecd9ba3cSJoshua M. Clulow 	    25,		1, 77, 99, 128,		1, 2, 3, 4),
103*ecd9ba3cSJoshua M. Clulow 	CASE("1.77.99.128/26:1.2.3.4",
104*ecd9ba3cSJoshua M. Clulow 	    26,		1, 77, 99, 128,		1, 2, 3, 4),
105*ecd9ba3cSJoshua M. Clulow 	CASE("1.77.99.128/27:1.2.3.4",
106*ecd9ba3cSJoshua M. Clulow 	    27,		1, 77, 99, 128,		1, 2, 3, 4),
107*ecd9ba3cSJoshua M. Clulow 	CASE("1.77.99.128/28:1.2.3.4",
108*ecd9ba3cSJoshua M. Clulow 	    28,		1, 77, 99, 128,		1, 2, 3, 4),
109*ecd9ba3cSJoshua M. Clulow 	CASE("1.77.99.128/29:1.2.3.4",
110*ecd9ba3cSJoshua M. Clulow 	    29,		1, 77, 99, 128,		1, 2, 3, 4),
111*ecd9ba3cSJoshua M. Clulow 	CASE("1.77.99.128/30:1.2.3.4",
112*ecd9ba3cSJoshua M. Clulow 	    30,		1, 77, 99, 128,		1, 2, 3, 4),
113*ecd9ba3cSJoshua M. Clulow 	CASE("1.77.99.128/31:1.2.3.4",
114*ecd9ba3cSJoshua M. Clulow 	    31,		1, 77, 99, 128,		1, 2, 3, 4),
115*ecd9ba3cSJoshua M. Clulow 	CASE("1.77.99.128/32:1.2.3.4",
116*ecd9ba3cSJoshua M. Clulow 	    32,		1, 77, 99, 128,		1, 2, 3, 4),
117*ecd9ba3cSJoshua M. Clulow 
118*ecd9ba3cSJoshua M. Clulow 	/*
119*ecd9ba3cSJoshua M. Clulow 	 * Check that interface routes work:
120*ecd9ba3cSJoshua M. Clulow 	 */
121*ecd9ba3cSJoshua M. Clulow 	CASE("1.2.3.0/24:0.0.0.0",
122*ecd9ba3cSJoshua M. Clulow 	    24,		1, 2, 3,		0, 0, 0, 0),
123*ecd9ba3cSJoshua M. Clulow 	CASE("1.2.3.0/24:0.0.0.0,4.5.0.0/15:0.0.0.0",
124*ecd9ba3cSJoshua M. Clulow 	    24,		1, 2, 3,		0, 0, 0, 0,
125*ecd9ba3cSJoshua M. Clulow 	    15,		4, 5,			0, 0, 0, 0),
126*ecd9ba3cSJoshua M. Clulow 
127*ecd9ba3cSJoshua M. Clulow 	/*
128*ecd9ba3cSJoshua M. Clulow 	 * This is the common pattern used for off-subnet gateways:
129*ecd9ba3cSJoshua M. Clulow 	 */
130*ecd9ba3cSJoshua M. Clulow 	CASE("9.10.11.12/32:0.0.0.0,0.0.0.0/0:9.10.11.12",
131*ecd9ba3cSJoshua M. Clulow 	    32,		9, 10, 11, 12,		0, 0, 0, 0,
132*ecd9ba3cSJoshua M. Clulow 	    0,					9, 10, 11, 12),
133*ecd9ba3cSJoshua M. Clulow 
134*ecd9ba3cSJoshua M. Clulow 	/*
135*ecd9ba3cSJoshua M. Clulow 	 * Shortest and longest possible single route string:
136*ecd9ba3cSJoshua M. Clulow 	 */
137*ecd9ba3cSJoshua M. Clulow 	CASE("255.255.255.255/32:255.255.255.255",
138*ecd9ba3cSJoshua M. Clulow 	    32,		255, 255, 255, 255,	255, 255, 255, 255),
139*ecd9ba3cSJoshua M. Clulow 	CASE("0.0.0.0/0:0.0.0.0",
140*ecd9ba3cSJoshua M. Clulow 	    0,					0, 0, 0, 0),
141*ecd9ba3cSJoshua M. Clulow 
142*ecd9ba3cSJoshua M. Clulow 	/*
143*ecd9ba3cSJoshua M. Clulow 	 * Lots of routes:
144*ecd9ba3cSJoshua M. Clulow 	 */
145*ecd9ba3cSJoshua M. Clulow 	CASE("255.255.255.255/32:255.255.255.255,"
146*ecd9ba3cSJoshua M. Clulow 	    "0.0.0.0/32:0.0.0.0,"
147*ecd9ba3cSJoshua M. Clulow 	    "255.255.255.255/32:255.255.255.255,"
148*ecd9ba3cSJoshua M. Clulow 	    "0.0.0.0/0:0.0.0.0,"
149*ecd9ba3cSJoshua M. Clulow 	    "0.0.0.0/32:255.255.255.255,"
150*ecd9ba3cSJoshua M. Clulow 	    "255.255.255.255/32:0.0.0.0,"
151*ecd9ba3cSJoshua M. Clulow 	    "255.255.255.255/32:255.255.255.255,"
152*ecd9ba3cSJoshua M. Clulow 	    "0.0.0.0/32:0.0.0.0",
153*ecd9ba3cSJoshua M. Clulow 	    32,		255, 255, 255, 255,	255, 255, 255, 255,
154*ecd9ba3cSJoshua M. Clulow 	    32,		0, 0, 0, 0,		0, 0, 0, 0,
155*ecd9ba3cSJoshua M. Clulow 	    32,		255, 255, 255, 255,	255, 255, 255, 255,
156*ecd9ba3cSJoshua M. Clulow 	    0,					0, 0, 0, 0,
157*ecd9ba3cSJoshua M. Clulow 	    32,		0, 0, 0, 0,		255, 255, 255, 255,
158*ecd9ba3cSJoshua M. Clulow 	    32,		255, 255, 255, 255,	0, 0, 0, 0,
159*ecd9ba3cSJoshua M. Clulow 	    32,		255, 255, 255, 255,	255, 255, 255, 255,
160*ecd9ba3cSJoshua M. Clulow 	    32,		0, 0, 0, 0,		0, 0, 0, 0),
161*ecd9ba3cSJoshua M. Clulow };
162*ecd9ba3cSJoshua M. Clulow 
163*ecd9ba3cSJoshua M. Clulow int
main(int argc,char ** argv)164*ecd9ba3cSJoshua M. Clulow main(int argc, char **argv)
165*ecd9ba3cSJoshua M. Clulow {
166*ecd9ba3cSJoshua M. Clulow 	int rc = EXIT_FAILURE;
167*ecd9ba3cSJoshua M. Clulow 
168*ecd9ba3cSJoshua M. Clulow 	dhcp_symbol_t *sym = inittab_getbycode(ITAB_CAT_STANDARD,
169*ecd9ba3cSJoshua M. Clulow 	    ITAB_CONS_INFO, CD_CLASSLESS_ROUTES);
170*ecd9ba3cSJoshua M. Clulow 	if (sym == NULL) {
171*ecd9ba3cSJoshua M. Clulow 		errx(1, "could not locate Classless Routes option");
172*ecd9ba3cSJoshua M. Clulow 	}
173*ecd9ba3cSJoshua M. Clulow 
174*ecd9ba3cSJoshua M. Clulow 	/*
175*ecd9ba3cSJoshua M. Clulow 	 * Confirm that we can decode binary representations into
176*ecd9ba3cSJoshua M. Clulow 	 * human-readable strings:
177*ecd9ba3cSJoshua M. Clulow 	 */
178*ecd9ba3cSJoshua M. Clulow 	for (uint_t n = 0; n < ARRAY_SIZE(such_cases); n++) {
179*ecd9ba3cSJoshua M. Clulow 		testcase_t *tc = &such_cases[n];
180*ecd9ba3cSJoshua M. Clulow 
181*ecd9ba3cSJoshua M. Clulow 		int ierrno = 0;
182*ecd9ba3cSJoshua M. Clulow 		char *o = inittab_decode_e(sym, tc->tc_binary, tc->tc_binlen,
183*ecd9ba3cSJoshua M. Clulow 		    B_TRUE, &ierrno);
184*ecd9ba3cSJoshua M. Clulow 
185*ecd9ba3cSJoshua M. Clulow 		if (o == NULL) {
186*ecd9ba3cSJoshua M. Clulow 			errx(1, "test case #%u: decode failure: %s", n,
187*ecd9ba3cSJoshua M. Clulow 			    inittab_errstr(ierrno));
188*ecd9ba3cSJoshua M. Clulow 		}
189*ecd9ba3cSJoshua M. Clulow 
190*ecd9ba3cSJoshua M. Clulow 		if (strcmp(o, tc->tc_string) != 0) {
191*ecd9ba3cSJoshua M. Clulow 			errx(1, "test case #%u: wanted \"%s\", got \"%s\"\n",
192*ecd9ba3cSJoshua M. Clulow 			    n, tc->tc_string, o);
193*ecd9ba3cSJoshua M. Clulow 		}
194*ecd9ba3cSJoshua M. Clulow 
195*ecd9ba3cSJoshua M. Clulow 		printf("test case #%u: ok! (%s)\n", n, o);
196*ecd9ba3cSJoshua M. Clulow 		free(o);
197*ecd9ba3cSJoshua M. Clulow 	}
198*ecd9ba3cSJoshua M. Clulow 
199*ecd9ba3cSJoshua M. Clulow 	/*
200*ecd9ba3cSJoshua M. Clulow 	 * Make sure we can also encode strings into binary:
201*ecd9ba3cSJoshua M. Clulow 	 */
202*ecd9ba3cSJoshua M. Clulow 	for (uint_t n = 0; n < ARRAY_SIZE(such_cases); n++) {
203*ecd9ba3cSJoshua M. Clulow 		testcase_t *tc = &such_cases[n];
204*ecd9ba3cSJoshua M. Clulow 
205*ecd9ba3cSJoshua M. Clulow 		int ierrno = 0;
206*ecd9ba3cSJoshua M. Clulow 		uint16_t olen = 0;
207*ecd9ba3cSJoshua M. Clulow 		uint8_t *o = inittab_encode_e(sym, tc->tc_string, &olen,
208*ecd9ba3cSJoshua M. Clulow 		    B_TRUE, &ierrno);
209*ecd9ba3cSJoshua M. Clulow 
210*ecd9ba3cSJoshua M. Clulow 		if (o == NULL) {
211*ecd9ba3cSJoshua M. Clulow 			errx(1, "test case #%u (%s): encode failure: %s", n,
212*ecd9ba3cSJoshua M. Clulow 			    tc->tc_string, inittab_errstr(ierrno));
213*ecd9ba3cSJoshua M. Clulow 		}
214*ecd9ba3cSJoshua M. Clulow 
215*ecd9ba3cSJoshua M. Clulow 		if (olen != tc->tc_binlen) {
216*ecd9ba3cSJoshua M. Clulow 			errx(1, "test case #%u (%s): encoded len %u != %u", n,
217*ecd9ba3cSJoshua M. Clulow 			    tc->tc_string, olen, (uint_t)tc->tc_binlen);
218*ecd9ba3cSJoshua M. Clulow 		}
219*ecd9ba3cSJoshua M. Clulow 
220*ecd9ba3cSJoshua M. Clulow 		if (memcmp(o, tc->tc_binary, olen) != 0) {
221*ecd9ba3cSJoshua M. Clulow 			errx(1, "test case #%u (%s): encoded output is wrong",
222*ecd9ba3cSJoshua M. Clulow 			    n, tc->tc_string);
223*ecd9ba3cSJoshua M. Clulow 		}
224*ecd9ba3cSJoshua M. Clulow 
225*ecd9ba3cSJoshua M. Clulow 		printf("test case #%u: ok! (%s) [len %u]\n", n, tc->tc_string,
226*ecd9ba3cSJoshua M. Clulow 		    olen);
227*ecd9ba3cSJoshua M. Clulow 		free(o);
228*ecd9ba3cSJoshua M. Clulow 	}
229*ecd9ba3cSJoshua M. Clulow 
230*ecd9ba3cSJoshua M. Clulow 	warnx("ok");
231*ecd9ba3cSJoshua M. Clulow 	rc = EXIT_SUCCESS;
232*ecd9ba3cSJoshua M. Clulow 
233*ecd9ba3cSJoshua M. Clulow 	return (rc);
234*ecd9ba3cSJoshua M. Clulow }
235