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