xref: /minix3/external/bsd/dhcpcd/dist/dhcp-common.c (revision 9f20bfa6c4c442e2e798d91b11c2a5f8d6833a41)
1*9f20bfa6SDavid van Moolenbroek #include <sys/cdefs.h>
2*9f20bfa6SDavid van Moolenbroek  __RCSID("$NetBSD: dhcp-common.c,v 1.10 2015/07/09 10:15:34 roy Exp $");
3*9f20bfa6SDavid van Moolenbroek 
4*9f20bfa6SDavid van Moolenbroek /*
5*9f20bfa6SDavid van Moolenbroek  * dhcpcd - DHCP client daemon
6*9f20bfa6SDavid van Moolenbroek  * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
7*9f20bfa6SDavid van Moolenbroek  * All rights reserved
8*9f20bfa6SDavid van Moolenbroek 
9*9f20bfa6SDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
10*9f20bfa6SDavid van Moolenbroek  * modification, are permitted provided that the following conditions
11*9f20bfa6SDavid van Moolenbroek  * are met:
12*9f20bfa6SDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
13*9f20bfa6SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer.
14*9f20bfa6SDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright
15*9f20bfa6SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer in the
16*9f20bfa6SDavid van Moolenbroek  *    documentation and/or other materials provided with the distribution.
17*9f20bfa6SDavid van Moolenbroek  *
18*9f20bfa6SDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19*9f20bfa6SDavid van Moolenbroek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*9f20bfa6SDavid van Moolenbroek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*9f20bfa6SDavid van Moolenbroek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22*9f20bfa6SDavid van Moolenbroek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23*9f20bfa6SDavid van Moolenbroek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24*9f20bfa6SDavid van Moolenbroek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25*9f20bfa6SDavid van Moolenbroek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26*9f20bfa6SDavid van Moolenbroek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27*9f20bfa6SDavid van Moolenbroek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28*9f20bfa6SDavid van Moolenbroek  * SUCH DAMAGE.
29*9f20bfa6SDavid van Moolenbroek  */
30*9f20bfa6SDavid van Moolenbroek 
31*9f20bfa6SDavid van Moolenbroek #include <sys/utsname.h>
32*9f20bfa6SDavid van Moolenbroek 
33*9f20bfa6SDavid van Moolenbroek #include <arpa/nameser.h>
34*9f20bfa6SDavid van Moolenbroek 
35*9f20bfa6SDavid van Moolenbroek #include <ctype.h>
36*9f20bfa6SDavid van Moolenbroek #include <errno.h>
37*9f20bfa6SDavid van Moolenbroek #include <fcntl.h>
38*9f20bfa6SDavid van Moolenbroek #include <inttypes.h>
39*9f20bfa6SDavid van Moolenbroek #include <stdlib.h>
40*9f20bfa6SDavid van Moolenbroek #include <string.h>
41*9f20bfa6SDavid van Moolenbroek #include <unistd.h>
42*9f20bfa6SDavid van Moolenbroek 
43*9f20bfa6SDavid van Moolenbroek #include "config.h"
44*9f20bfa6SDavid van Moolenbroek 
45*9f20bfa6SDavid van Moolenbroek #include "common.h"
46*9f20bfa6SDavid van Moolenbroek #include "dhcp-common.h"
47*9f20bfa6SDavid van Moolenbroek #include "dhcp.h"
48*9f20bfa6SDavid van Moolenbroek #include "if.h"
49*9f20bfa6SDavid van Moolenbroek #include "ipv6.h"
50*9f20bfa6SDavid van Moolenbroek 
51*9f20bfa6SDavid van Moolenbroek /* Support very old arpa/nameser.h as found in OpenBSD */
52*9f20bfa6SDavid van Moolenbroek #ifndef NS_MAXDNAME
53*9f20bfa6SDavid van Moolenbroek #define NS_MAXCDNAME MAXCDNAME
54*9f20bfa6SDavid van Moolenbroek #define NS_MAXDNAME MAXDNAME
55*9f20bfa6SDavid van Moolenbroek #define NS_MAXLABEL MAXLABEL
56*9f20bfa6SDavid van Moolenbroek #endif
57*9f20bfa6SDavid van Moolenbroek 
58*9f20bfa6SDavid van Moolenbroek void
dhcp_print_option_encoding(const struct dhcp_opt * opt,int cols)59*9f20bfa6SDavid van Moolenbroek dhcp_print_option_encoding(const struct dhcp_opt *opt, int cols)
60*9f20bfa6SDavid van Moolenbroek {
61*9f20bfa6SDavid van Moolenbroek 
62*9f20bfa6SDavid van Moolenbroek 	while (cols < 40) {
63*9f20bfa6SDavid van Moolenbroek 		putchar(' ');
64*9f20bfa6SDavid van Moolenbroek 		cols++;
65*9f20bfa6SDavid van Moolenbroek 	}
66*9f20bfa6SDavid van Moolenbroek 	putchar('\t');
67*9f20bfa6SDavid van Moolenbroek 	if (opt->type & EMBED)
68*9f20bfa6SDavid van Moolenbroek 		printf(" embed");
69*9f20bfa6SDavid van Moolenbroek 	if (opt->type & ENCAP)
70*9f20bfa6SDavid van Moolenbroek 		printf(" encap");
71*9f20bfa6SDavid van Moolenbroek 	if (opt->type & INDEX)
72*9f20bfa6SDavid van Moolenbroek 		printf(" index");
73*9f20bfa6SDavid van Moolenbroek 	if (opt->type & ARRAY)
74*9f20bfa6SDavid van Moolenbroek 		printf(" array");
75*9f20bfa6SDavid van Moolenbroek 	if (opt->type & UINT8)
76*9f20bfa6SDavid van Moolenbroek 		printf(" byte");
77*9f20bfa6SDavid van Moolenbroek 	else if (opt->type & UINT16)
78*9f20bfa6SDavid van Moolenbroek 		printf(" uint16");
79*9f20bfa6SDavid van Moolenbroek 	else if (opt->type & SINT16)
80*9f20bfa6SDavid van Moolenbroek 		printf(" sint16");
81*9f20bfa6SDavid van Moolenbroek 	else if (opt->type & UINT32)
82*9f20bfa6SDavid van Moolenbroek 		printf(" uint32");
83*9f20bfa6SDavid van Moolenbroek 	else if (opt->type & SINT32)
84*9f20bfa6SDavid van Moolenbroek 		printf(" sint32");
85*9f20bfa6SDavid van Moolenbroek 	else if (opt->type & ADDRIPV4)
86*9f20bfa6SDavid van Moolenbroek 		printf(" ipaddress");
87*9f20bfa6SDavid van Moolenbroek 	else if (opt->type & ADDRIPV6)
88*9f20bfa6SDavid van Moolenbroek 		printf(" ip6address");
89*9f20bfa6SDavid van Moolenbroek 	else if (opt->type & FLAG)
90*9f20bfa6SDavid van Moolenbroek 		printf(" flag");
91*9f20bfa6SDavid van Moolenbroek 	else if (opt->type & BITFLAG)
92*9f20bfa6SDavid van Moolenbroek 		printf(" bitflags");
93*9f20bfa6SDavid van Moolenbroek 	else if (opt->type & RFC1035)
94*9f20bfa6SDavid van Moolenbroek 		printf(" domain");
95*9f20bfa6SDavid van Moolenbroek 	else if (opt->type & DOMAIN)
96*9f20bfa6SDavid van Moolenbroek 		printf(" dname");
97*9f20bfa6SDavid van Moolenbroek 	else if (opt->type & ASCII)
98*9f20bfa6SDavid van Moolenbroek 		printf(" ascii");
99*9f20bfa6SDavid van Moolenbroek 	else if (opt->type & RAW)
100*9f20bfa6SDavid van Moolenbroek 		printf(" raw");
101*9f20bfa6SDavid van Moolenbroek 	else if (opt->type & BINHEX)
102*9f20bfa6SDavid van Moolenbroek 		printf(" binhex");
103*9f20bfa6SDavid van Moolenbroek 	else if (opt->type & STRING)
104*9f20bfa6SDavid van Moolenbroek 		printf(" string");
105*9f20bfa6SDavid van Moolenbroek 	if (opt->type & RFC3361)
106*9f20bfa6SDavid van Moolenbroek 		printf(" rfc3361");
107*9f20bfa6SDavid van Moolenbroek 	if (opt->type & RFC3442)
108*9f20bfa6SDavid van Moolenbroek 		printf(" rfc3442");
109*9f20bfa6SDavid van Moolenbroek 	if (opt->type & RFC5969)
110*9f20bfa6SDavid van Moolenbroek 		printf(" rfc5969");
111*9f20bfa6SDavid van Moolenbroek 	if (opt->type & REQUEST)
112*9f20bfa6SDavid van Moolenbroek 		printf(" request");
113*9f20bfa6SDavid van Moolenbroek 	if (opt->type & NOREQ)
114*9f20bfa6SDavid van Moolenbroek 		printf(" norequest");
115*9f20bfa6SDavid van Moolenbroek 	putchar('\n');
116*9f20bfa6SDavid van Moolenbroek }
117*9f20bfa6SDavid van Moolenbroek 
118*9f20bfa6SDavid van Moolenbroek struct dhcp_opt *
vivso_find(uint32_t iana_en,const void * arg)119*9f20bfa6SDavid van Moolenbroek vivso_find(uint32_t iana_en, const void *arg)
120*9f20bfa6SDavid van Moolenbroek {
121*9f20bfa6SDavid van Moolenbroek 	const struct interface *ifp;
122*9f20bfa6SDavid van Moolenbroek 	size_t i;
123*9f20bfa6SDavid van Moolenbroek 	struct dhcp_opt *opt;
124*9f20bfa6SDavid van Moolenbroek 
125*9f20bfa6SDavid van Moolenbroek 	ifp = arg;
126*9f20bfa6SDavid van Moolenbroek 	for (i = 0, opt = ifp->options->vivso_override;
127*9f20bfa6SDavid van Moolenbroek 	    i < ifp->options->vivso_override_len;
128*9f20bfa6SDavid van Moolenbroek 	    i++, opt++)
129*9f20bfa6SDavid van Moolenbroek 		if (opt->option == iana_en)
130*9f20bfa6SDavid van Moolenbroek 			return opt;
131*9f20bfa6SDavid van Moolenbroek 	for (i = 0, opt = ifp->ctx->vivso;
132*9f20bfa6SDavid van Moolenbroek 	    i < ifp->ctx->vivso_len;
133*9f20bfa6SDavid van Moolenbroek 	    i++, opt++)
134*9f20bfa6SDavid van Moolenbroek 		if (opt->option == iana_en)
135*9f20bfa6SDavid van Moolenbroek 			return opt;
136*9f20bfa6SDavid van Moolenbroek 	return NULL;
137*9f20bfa6SDavid van Moolenbroek }
138*9f20bfa6SDavid van Moolenbroek 
139*9f20bfa6SDavid van Moolenbroek ssize_t
dhcp_vendor(char * str,size_t len)140*9f20bfa6SDavid van Moolenbroek dhcp_vendor(char *str, size_t len)
141*9f20bfa6SDavid van Moolenbroek {
142*9f20bfa6SDavid van Moolenbroek 	struct utsname utn;
143*9f20bfa6SDavid van Moolenbroek 	char *p;
144*9f20bfa6SDavid van Moolenbroek 	int l;
145*9f20bfa6SDavid van Moolenbroek 
146*9f20bfa6SDavid van Moolenbroek 	if (uname(&utn) != 0)
147*9f20bfa6SDavid van Moolenbroek 		return (ssize_t)snprintf(str, len, "%s-%s",
148*9f20bfa6SDavid van Moolenbroek 		    PACKAGE, VERSION);
149*9f20bfa6SDavid van Moolenbroek 	p = str;
150*9f20bfa6SDavid van Moolenbroek 	l = snprintf(p, len,
151*9f20bfa6SDavid van Moolenbroek 	    "%s-%s:%s-%s:%s", PACKAGE, VERSION,
152*9f20bfa6SDavid van Moolenbroek 	    utn.sysname, utn.release, utn.machine);
153*9f20bfa6SDavid van Moolenbroek 	if (l == -1 || (size_t)(l + 1) > len)
154*9f20bfa6SDavid van Moolenbroek 		return -1;
155*9f20bfa6SDavid van Moolenbroek 	p += l;
156*9f20bfa6SDavid van Moolenbroek 	len -= (size_t)l;
157*9f20bfa6SDavid van Moolenbroek 	l = if_machinearch(p, len);
158*9f20bfa6SDavid van Moolenbroek 	if (l == -1 || (size_t)(l + 1) > len)
159*9f20bfa6SDavid van Moolenbroek 		return -1;
160*9f20bfa6SDavid van Moolenbroek 	p += l;
161*9f20bfa6SDavid van Moolenbroek 	return p - str;
162*9f20bfa6SDavid van Moolenbroek }
163*9f20bfa6SDavid van Moolenbroek 
164*9f20bfa6SDavid van Moolenbroek int
make_option_mask(const struct dhcp_opt * dopts,size_t dopts_len,const struct dhcp_opt * odopts,size_t odopts_len,uint8_t * mask,const char * opts,int add)165*9f20bfa6SDavid van Moolenbroek make_option_mask(const struct dhcp_opt *dopts, size_t dopts_len,
166*9f20bfa6SDavid van Moolenbroek     const struct dhcp_opt *odopts, size_t odopts_len,
167*9f20bfa6SDavid van Moolenbroek     uint8_t *mask, const char *opts, int add)
168*9f20bfa6SDavid van Moolenbroek {
169*9f20bfa6SDavid van Moolenbroek 	char *token, *o, *p;
170*9f20bfa6SDavid van Moolenbroek 	const struct dhcp_opt *opt;
171*9f20bfa6SDavid van Moolenbroek 	int match, e;
172*9f20bfa6SDavid van Moolenbroek 	unsigned int n;
173*9f20bfa6SDavid van Moolenbroek 	size_t i;
174*9f20bfa6SDavid van Moolenbroek 
175*9f20bfa6SDavid van Moolenbroek 	if (opts == NULL)
176*9f20bfa6SDavid van Moolenbroek 		return -1;
177*9f20bfa6SDavid van Moolenbroek 	o = p = strdup(opts);
178*9f20bfa6SDavid van Moolenbroek 	while ((token = strsep(&p, ", "))) {
179*9f20bfa6SDavid van Moolenbroek 		if (*token == '\0')
180*9f20bfa6SDavid van Moolenbroek 			continue;
181*9f20bfa6SDavid van Moolenbroek 		match = 0;
182*9f20bfa6SDavid van Moolenbroek 		for (i = 0, opt = odopts; i < odopts_len; i++, opt++) {
183*9f20bfa6SDavid van Moolenbroek 			if (strcmp(opt->var, token) == 0)
184*9f20bfa6SDavid van Moolenbroek 				match = 1;
185*9f20bfa6SDavid van Moolenbroek 			else {
186*9f20bfa6SDavid van Moolenbroek 				n = (unsigned int)strtou(token, NULL, 0,
187*9f20bfa6SDavid van Moolenbroek 				    0, UINT_MAX, &e);
188*9f20bfa6SDavid van Moolenbroek 				if (e == 0 && opt->option == n)
189*9f20bfa6SDavid van Moolenbroek 					match = 1;
190*9f20bfa6SDavid van Moolenbroek 			}
191*9f20bfa6SDavid van Moolenbroek 			if (match)
192*9f20bfa6SDavid van Moolenbroek 				break;
193*9f20bfa6SDavid van Moolenbroek 		}
194*9f20bfa6SDavid van Moolenbroek 		if (match == 0) {
195*9f20bfa6SDavid van Moolenbroek 			for (i = 0, opt = dopts; i < dopts_len; i++, opt++) {
196*9f20bfa6SDavid van Moolenbroek 				if (strcmp(opt->var, token) == 0)
197*9f20bfa6SDavid van Moolenbroek 				        match = 1;
198*9f20bfa6SDavid van Moolenbroek 				else {
199*9f20bfa6SDavid van Moolenbroek 					n = (unsigned int)strtou(token, NULL, 0,
200*9f20bfa6SDavid van Moolenbroek 					    0, UINT_MAX, &e);
201*9f20bfa6SDavid van Moolenbroek 					if (e == 0 && opt->option == n)
202*9f20bfa6SDavid van Moolenbroek 						match = 1;
203*9f20bfa6SDavid van Moolenbroek 				}
204*9f20bfa6SDavid van Moolenbroek 				if (match)
205*9f20bfa6SDavid van Moolenbroek 					break;
206*9f20bfa6SDavid van Moolenbroek 			}
207*9f20bfa6SDavid van Moolenbroek 		}
208*9f20bfa6SDavid van Moolenbroek 		if (!match || !opt->option) {
209*9f20bfa6SDavid van Moolenbroek 			free(o);
210*9f20bfa6SDavid van Moolenbroek 			errno = ENOENT;
211*9f20bfa6SDavid van Moolenbroek 			return -1;
212*9f20bfa6SDavid van Moolenbroek 		}
213*9f20bfa6SDavid van Moolenbroek 		if (add == 2 && !(opt->type & ADDRIPV4)) {
214*9f20bfa6SDavid van Moolenbroek 			free(o);
215*9f20bfa6SDavid van Moolenbroek 			errno = EINVAL;
216*9f20bfa6SDavid van Moolenbroek 			return -1;
217*9f20bfa6SDavid van Moolenbroek 		}
218*9f20bfa6SDavid van Moolenbroek 		if (add == 1 || add == 2)
219*9f20bfa6SDavid van Moolenbroek 			add_option_mask(mask, opt->option);
220*9f20bfa6SDavid van Moolenbroek 		else
221*9f20bfa6SDavid van Moolenbroek 			del_option_mask(mask, opt->option);
222*9f20bfa6SDavid van Moolenbroek 	}
223*9f20bfa6SDavid van Moolenbroek 	free(o);
224*9f20bfa6SDavid van Moolenbroek 	return 0;
225*9f20bfa6SDavid van Moolenbroek }
226*9f20bfa6SDavid van Moolenbroek 
227*9f20bfa6SDavid van Moolenbroek size_t
encode_rfc1035(const char * src,uint8_t * dst)228*9f20bfa6SDavid van Moolenbroek encode_rfc1035(const char *src, uint8_t *dst)
229*9f20bfa6SDavid van Moolenbroek {
230*9f20bfa6SDavid van Moolenbroek 	uint8_t *p;
231*9f20bfa6SDavid van Moolenbroek 	uint8_t *lp;
232*9f20bfa6SDavid van Moolenbroek 	size_t len;
233*9f20bfa6SDavid van Moolenbroek 	uint8_t has_dot;
234*9f20bfa6SDavid van Moolenbroek 
235*9f20bfa6SDavid van Moolenbroek 	if (src == NULL || *src == '\0')
236*9f20bfa6SDavid van Moolenbroek 		return 0;
237*9f20bfa6SDavid van Moolenbroek 
238*9f20bfa6SDavid van Moolenbroek 	if (dst) {
239*9f20bfa6SDavid van Moolenbroek 		p = dst;
240*9f20bfa6SDavid van Moolenbroek 		lp = p++;
241*9f20bfa6SDavid van Moolenbroek 	}
242*9f20bfa6SDavid van Moolenbroek 	/* Silence bogus GCC warnings */
243*9f20bfa6SDavid van Moolenbroek 	else
244*9f20bfa6SDavid van Moolenbroek 		p = lp = NULL;
245*9f20bfa6SDavid van Moolenbroek 
246*9f20bfa6SDavid van Moolenbroek 	len = 1;
247*9f20bfa6SDavid van Moolenbroek 	has_dot = 0;
248*9f20bfa6SDavid van Moolenbroek 	for (; *src; src++) {
249*9f20bfa6SDavid van Moolenbroek 		if (*src == '\0')
250*9f20bfa6SDavid van Moolenbroek 			break;
251*9f20bfa6SDavid van Moolenbroek 		if (*src == '.') {
252*9f20bfa6SDavid van Moolenbroek 			/* Skip the trailing . */
253*9f20bfa6SDavid van Moolenbroek 			if (src[1] == '\0')
254*9f20bfa6SDavid van Moolenbroek 				break;
255*9f20bfa6SDavid van Moolenbroek 			has_dot = 1;
256*9f20bfa6SDavid van Moolenbroek 			if (dst) {
257*9f20bfa6SDavid van Moolenbroek 				*lp = (uint8_t)(p - lp - 1);
258*9f20bfa6SDavid van Moolenbroek 				if (*lp == '\0')
259*9f20bfa6SDavid van Moolenbroek 					return len;
260*9f20bfa6SDavid van Moolenbroek 				lp = p++;
261*9f20bfa6SDavid van Moolenbroek 			}
262*9f20bfa6SDavid van Moolenbroek 		} else if (dst)
263*9f20bfa6SDavid van Moolenbroek 			*p++ = (uint8_t)*src;
264*9f20bfa6SDavid van Moolenbroek 		len++;
265*9f20bfa6SDavid van Moolenbroek 	}
266*9f20bfa6SDavid van Moolenbroek 
267*9f20bfa6SDavid van Moolenbroek 	if (dst) {
268*9f20bfa6SDavid van Moolenbroek 		*lp = (uint8_t)(p - lp - 1);
269*9f20bfa6SDavid van Moolenbroek 		if (has_dot)
270*9f20bfa6SDavid van Moolenbroek 			*p++ = '\0';
271*9f20bfa6SDavid van Moolenbroek 	}
272*9f20bfa6SDavid van Moolenbroek 
273*9f20bfa6SDavid van Moolenbroek 	if (has_dot)
274*9f20bfa6SDavid van Moolenbroek 		len++;
275*9f20bfa6SDavid van Moolenbroek 
276*9f20bfa6SDavid van Moolenbroek 	return len;
277*9f20bfa6SDavid van Moolenbroek }
278*9f20bfa6SDavid van Moolenbroek 
279*9f20bfa6SDavid van Moolenbroek /* Decode an RFC1035 DNS search order option into a space
280*9f20bfa6SDavid van Moolenbroek  * separated string. Returns length of string (including
281*9f20bfa6SDavid van Moolenbroek  * terminating zero) or zero on error. out may be NULL
282*9f20bfa6SDavid van Moolenbroek  * to just determine output length. */
283*9f20bfa6SDavid van Moolenbroek ssize_t
decode_rfc1035(char * out,size_t len,const uint8_t * p,size_t pl)284*9f20bfa6SDavid van Moolenbroek decode_rfc1035(char *out, size_t len, const uint8_t *p, size_t pl)
285*9f20bfa6SDavid van Moolenbroek {
286*9f20bfa6SDavid van Moolenbroek 	const char *start;
287*9f20bfa6SDavid van Moolenbroek 	size_t start_len, l, count;
288*9f20bfa6SDavid van Moolenbroek 	const uint8_t *r, *q = p, *e;
289*9f20bfa6SDavid van Moolenbroek 	int hops;
290*9f20bfa6SDavid van Moolenbroek 	uint8_t ltype;
291*9f20bfa6SDavid van Moolenbroek 
292*9f20bfa6SDavid van Moolenbroek 	if (pl > NS_MAXCDNAME) {
293*9f20bfa6SDavid van Moolenbroek 		errno = E2BIG;
294*9f20bfa6SDavid van Moolenbroek 		return -1;
295*9f20bfa6SDavid van Moolenbroek 	}
296*9f20bfa6SDavid van Moolenbroek 
297*9f20bfa6SDavid van Moolenbroek 	count = 0;
298*9f20bfa6SDavid van Moolenbroek 	start = out;
299*9f20bfa6SDavid van Moolenbroek 	start_len = len;
300*9f20bfa6SDavid van Moolenbroek 	q = p;
301*9f20bfa6SDavid van Moolenbroek 	e = p + pl;
302*9f20bfa6SDavid van Moolenbroek 	while (q < e) {
303*9f20bfa6SDavid van Moolenbroek 		r = NULL;
304*9f20bfa6SDavid van Moolenbroek 		hops = 0;
305*9f20bfa6SDavid van Moolenbroek 		/* Check we are inside our length again in-case
306*9f20bfa6SDavid van Moolenbroek 		 * the name isn't fully qualified (ie, not terminated) */
307*9f20bfa6SDavid van Moolenbroek 		while (q < e && (l = (size_t)*q++)) {
308*9f20bfa6SDavid van Moolenbroek 			ltype = l & 0xc0;
309*9f20bfa6SDavid van Moolenbroek 			if (ltype == 0x80 || ltype == 0x40) {
310*9f20bfa6SDavid van Moolenbroek 				/* Currently reserved for future use as noted
311*9f20bfa6SDavid van Moolenbroek 				 * in RFC1035 4.1.4 as the 10 and 01
312*9f20bfa6SDavid van Moolenbroek 				 * combinations. */
313*9f20bfa6SDavid van Moolenbroek 				errno = ENOTSUP;
314*9f20bfa6SDavid van Moolenbroek 				return -1;
315*9f20bfa6SDavid van Moolenbroek 			}
316*9f20bfa6SDavid van Moolenbroek 			else if (ltype == 0xc0) { /* pointer */
317*9f20bfa6SDavid van Moolenbroek 				if (q == e) {
318*9f20bfa6SDavid van Moolenbroek 					errno = ERANGE;
319*9f20bfa6SDavid van Moolenbroek 					return -1;
320*9f20bfa6SDavid van Moolenbroek 				}
321*9f20bfa6SDavid van Moolenbroek 				l = (l & 0x3f) << 8;
322*9f20bfa6SDavid van Moolenbroek 				l |= *q++;
323*9f20bfa6SDavid van Moolenbroek 				/* save source of first jump. */
324*9f20bfa6SDavid van Moolenbroek 				if (!r)
325*9f20bfa6SDavid van Moolenbroek 					r = q;
326*9f20bfa6SDavid van Moolenbroek 				hops++;
327*9f20bfa6SDavid van Moolenbroek 				if (hops > 255) {
328*9f20bfa6SDavid van Moolenbroek 					errno = ERANGE;
329*9f20bfa6SDavid van Moolenbroek 					return -1;
330*9f20bfa6SDavid van Moolenbroek 				}
331*9f20bfa6SDavid van Moolenbroek 				q = p + l;
332*9f20bfa6SDavid van Moolenbroek 				if (q >= e) {
333*9f20bfa6SDavid van Moolenbroek 					errno = ERANGE;
334*9f20bfa6SDavid van Moolenbroek 					return -1;
335*9f20bfa6SDavid van Moolenbroek 				}
336*9f20bfa6SDavid van Moolenbroek 			} else {
337*9f20bfa6SDavid van Moolenbroek 				/* straightforward name segment, add with '.' */
338*9f20bfa6SDavid van Moolenbroek 				if (q + l > e) {
339*9f20bfa6SDavid van Moolenbroek 					errno = ERANGE;
340*9f20bfa6SDavid van Moolenbroek 					return -1;
341*9f20bfa6SDavid van Moolenbroek 				}
342*9f20bfa6SDavid van Moolenbroek 				count += l + 1;
343*9f20bfa6SDavid van Moolenbroek 				if (out) {
344*9f20bfa6SDavid van Moolenbroek 					if (l + 1 > len) {
345*9f20bfa6SDavid van Moolenbroek 						errno = ENOBUFS;
346*9f20bfa6SDavid van Moolenbroek 						return -1;
347*9f20bfa6SDavid van Moolenbroek 					}
348*9f20bfa6SDavid van Moolenbroek 					if (l + 1 > NS_MAXLABEL) {
349*9f20bfa6SDavid van Moolenbroek 						errno = EINVAL;
350*9f20bfa6SDavid van Moolenbroek 						return -1;
351*9f20bfa6SDavid van Moolenbroek 					}
352*9f20bfa6SDavid van Moolenbroek 					memcpy(out, q, l);
353*9f20bfa6SDavid van Moolenbroek 					out += l;
354*9f20bfa6SDavid van Moolenbroek 					*out++ = '.';
355*9f20bfa6SDavid van Moolenbroek 					len -= l;
356*9f20bfa6SDavid van Moolenbroek 					len--;
357*9f20bfa6SDavid van Moolenbroek 				}
358*9f20bfa6SDavid van Moolenbroek 				q += l;
359*9f20bfa6SDavid van Moolenbroek 			}
360*9f20bfa6SDavid van Moolenbroek 		}
361*9f20bfa6SDavid van Moolenbroek 		/* change last dot to space */
362*9f20bfa6SDavid van Moolenbroek 		if (out && out != start)
363*9f20bfa6SDavid van Moolenbroek 			*(out - 1) = ' ';
364*9f20bfa6SDavid van Moolenbroek 		if (r)
365*9f20bfa6SDavid van Moolenbroek 			q = r;
366*9f20bfa6SDavid van Moolenbroek 	}
367*9f20bfa6SDavid van Moolenbroek 
368*9f20bfa6SDavid van Moolenbroek 	/* change last space to zero terminator */
369*9f20bfa6SDavid van Moolenbroek 	if (out) {
370*9f20bfa6SDavid van Moolenbroek 		if (out != start)
371*9f20bfa6SDavid van Moolenbroek 			*(out - 1) = '\0';
372*9f20bfa6SDavid van Moolenbroek 		else if (start_len > 0)
373*9f20bfa6SDavid van Moolenbroek 			*out = '\0';
374*9f20bfa6SDavid van Moolenbroek 	}
375*9f20bfa6SDavid van Moolenbroek 
376*9f20bfa6SDavid van Moolenbroek 	if (count)
377*9f20bfa6SDavid van Moolenbroek 		/* Don't count the trailing NUL */
378*9f20bfa6SDavid van Moolenbroek 		count--;
379*9f20bfa6SDavid van Moolenbroek 	if (count > NS_MAXDNAME) {
380*9f20bfa6SDavid van Moolenbroek 		errno = E2BIG;
381*9f20bfa6SDavid van Moolenbroek 		return -1;
382*9f20bfa6SDavid van Moolenbroek 	}
383*9f20bfa6SDavid van Moolenbroek 	return (ssize_t)count;
384*9f20bfa6SDavid van Moolenbroek }
385*9f20bfa6SDavid van Moolenbroek 
386*9f20bfa6SDavid van Moolenbroek /* Check for a valid domain name as per RFC1123 with the exception of
387*9f20bfa6SDavid van Moolenbroek  * allowing - and _ (but not at start or end) as they seem to be widely used. */
388*9f20bfa6SDavid van Moolenbroek static int
valid_domainname(char * lbl,int type)389*9f20bfa6SDavid van Moolenbroek valid_domainname(char *lbl, int type)
390*9f20bfa6SDavid van Moolenbroek {
391*9f20bfa6SDavid van Moolenbroek 	char *slbl, *lst;
392*9f20bfa6SDavid van Moolenbroek 	unsigned char c;
393*9f20bfa6SDavid van Moolenbroek 	int start, len, errset;
394*9f20bfa6SDavid van Moolenbroek 
395*9f20bfa6SDavid van Moolenbroek 	if (lbl == NULL || *lbl == '\0') {
396*9f20bfa6SDavid van Moolenbroek 		errno = EINVAL;
397*9f20bfa6SDavid van Moolenbroek 		return 0;
398*9f20bfa6SDavid van Moolenbroek 	}
399*9f20bfa6SDavid van Moolenbroek 
400*9f20bfa6SDavid van Moolenbroek 	slbl = lbl;
401*9f20bfa6SDavid van Moolenbroek 	lst = NULL;
402*9f20bfa6SDavid van Moolenbroek 	start = 1;
403*9f20bfa6SDavid van Moolenbroek 	len = errset = 0;
404*9f20bfa6SDavid van Moolenbroek 	for (;;) {
405*9f20bfa6SDavid van Moolenbroek 		c = (unsigned char)*lbl++;
406*9f20bfa6SDavid van Moolenbroek 		if (c == '\0')
407*9f20bfa6SDavid van Moolenbroek 			return 1;
408*9f20bfa6SDavid van Moolenbroek 		if (c == ' ') {
409*9f20bfa6SDavid van Moolenbroek 			if (lbl - 1 == slbl) /* No space at start */
410*9f20bfa6SDavid van Moolenbroek 				break;
411*9f20bfa6SDavid van Moolenbroek 			if (!(type & ARRAY))
412*9f20bfa6SDavid van Moolenbroek 				break;
413*9f20bfa6SDavid van Moolenbroek 			/* Skip to the next label */
414*9f20bfa6SDavid van Moolenbroek 			if (!start) {
415*9f20bfa6SDavid van Moolenbroek 				start = 1;
416*9f20bfa6SDavid van Moolenbroek 				lst = lbl - 1;
417*9f20bfa6SDavid van Moolenbroek 			}
418*9f20bfa6SDavid van Moolenbroek 			if (len)
419*9f20bfa6SDavid van Moolenbroek 				len = 0;
420*9f20bfa6SDavid van Moolenbroek 			continue;
421*9f20bfa6SDavid van Moolenbroek 		}
422*9f20bfa6SDavid van Moolenbroek 		if (c == '.') {
423*9f20bfa6SDavid van Moolenbroek 			if (*lbl == '.')
424*9f20bfa6SDavid van Moolenbroek 				break;
425*9f20bfa6SDavid van Moolenbroek 			len = 0;
426*9f20bfa6SDavid van Moolenbroek 			continue;
427*9f20bfa6SDavid van Moolenbroek 		}
428*9f20bfa6SDavid van Moolenbroek 		if (((c == '-' || c == '_') &&
429*9f20bfa6SDavid van Moolenbroek 		    !start && *lbl != ' ' && *lbl != '\0') ||
430*9f20bfa6SDavid van Moolenbroek 		    isalnum(c))
431*9f20bfa6SDavid van Moolenbroek 		{
432*9f20bfa6SDavid van Moolenbroek 			if (++len > NS_MAXLABEL) {
433*9f20bfa6SDavid van Moolenbroek 				errno = ERANGE;
434*9f20bfa6SDavid van Moolenbroek 				errset = 1;
435*9f20bfa6SDavid van Moolenbroek 				break;
436*9f20bfa6SDavid van Moolenbroek 			}
437*9f20bfa6SDavid van Moolenbroek 		} else
438*9f20bfa6SDavid van Moolenbroek 			break;
439*9f20bfa6SDavid van Moolenbroek 		if (start)
440*9f20bfa6SDavid van Moolenbroek 			start = 0;
441*9f20bfa6SDavid van Moolenbroek 	}
442*9f20bfa6SDavid van Moolenbroek 
443*9f20bfa6SDavid van Moolenbroek 	if (!errset)
444*9f20bfa6SDavid van Moolenbroek 		errno = EINVAL;
445*9f20bfa6SDavid van Moolenbroek 	if (lst) {
446*9f20bfa6SDavid van Moolenbroek 		/* At least one valid domain, return it */
447*9f20bfa6SDavid van Moolenbroek 		*lst = '\0';
448*9f20bfa6SDavid van Moolenbroek 		return 1;
449*9f20bfa6SDavid van Moolenbroek 	}
450*9f20bfa6SDavid van Moolenbroek 	return 0;
451*9f20bfa6SDavid van Moolenbroek }
452*9f20bfa6SDavid van Moolenbroek 
453*9f20bfa6SDavid van Moolenbroek /*
454*9f20bfa6SDavid van Moolenbroek  * Prints a chunk of data to a string.
455*9f20bfa6SDavid van Moolenbroek  * PS_SHELL goes as it is these days, it's upto the target to validate it.
456*9f20bfa6SDavid van Moolenbroek  * PS_SAFE has all non ascii and non printables changes to escaped octal.
457*9f20bfa6SDavid van Moolenbroek  */
458*9f20bfa6SDavid van Moolenbroek static const char hexchrs[] = "0123456789abcdef";
459*9f20bfa6SDavid van Moolenbroek ssize_t
print_string(char * dst,size_t len,int type,const uint8_t * data,size_t dl)460*9f20bfa6SDavid van Moolenbroek print_string(char *dst, size_t len, int type, const uint8_t *data, size_t dl)
461*9f20bfa6SDavid van Moolenbroek {
462*9f20bfa6SDavid van Moolenbroek 	char *odst;
463*9f20bfa6SDavid van Moolenbroek 	uint8_t c;
464*9f20bfa6SDavid van Moolenbroek 	const uint8_t *e;
465*9f20bfa6SDavid van Moolenbroek 	size_t bytes;
466*9f20bfa6SDavid van Moolenbroek 
467*9f20bfa6SDavid van Moolenbroek 	odst = dst;
468*9f20bfa6SDavid van Moolenbroek 	bytes = 0;
469*9f20bfa6SDavid van Moolenbroek 	e = data + dl;
470*9f20bfa6SDavid van Moolenbroek 
471*9f20bfa6SDavid van Moolenbroek 	while (data < e) {
472*9f20bfa6SDavid van Moolenbroek 		c = *data++;
473*9f20bfa6SDavid van Moolenbroek 		if (type & BINHEX) {
474*9f20bfa6SDavid van Moolenbroek 			if (dst) {
475*9f20bfa6SDavid van Moolenbroek 				if (len  == 0 || len == 1) {
476*9f20bfa6SDavid van Moolenbroek 					errno = ENOSPC;
477*9f20bfa6SDavid van Moolenbroek 					return -1;
478*9f20bfa6SDavid van Moolenbroek 				}
479*9f20bfa6SDavid van Moolenbroek 				*dst++ = hexchrs[(c & 0xF0) >> 4];
480*9f20bfa6SDavid van Moolenbroek 				*dst++ = hexchrs[(c & 0x0F)];
481*9f20bfa6SDavid van Moolenbroek 				len -= 2;
482*9f20bfa6SDavid van Moolenbroek 			}
483*9f20bfa6SDavid van Moolenbroek 			bytes += 2;
484*9f20bfa6SDavid van Moolenbroek 			continue;
485*9f20bfa6SDavid van Moolenbroek 		}
486*9f20bfa6SDavid van Moolenbroek 		if (type & ASCII && (!isascii(c))) {
487*9f20bfa6SDavid van Moolenbroek 			errno = EINVAL;
488*9f20bfa6SDavid van Moolenbroek 			break;
489*9f20bfa6SDavid van Moolenbroek 		}
490*9f20bfa6SDavid van Moolenbroek 		if (!(type & (ASCII | RAW | ESCSTRING | ESCFILE)) /* plain */ &&
491*9f20bfa6SDavid van Moolenbroek 		    (!isascii(c) && !isprint(c)))
492*9f20bfa6SDavid van Moolenbroek 		{
493*9f20bfa6SDavid van Moolenbroek 			errno = EINVAL;
494*9f20bfa6SDavid van Moolenbroek 			break;
495*9f20bfa6SDavid van Moolenbroek 		}
496*9f20bfa6SDavid van Moolenbroek 		if ((type & (ESCSTRING | ESCFILE) &&
497*9f20bfa6SDavid van Moolenbroek 		    (c == '\\' || !isascii(c) || !isprint(c))) ||
498*9f20bfa6SDavid van Moolenbroek 		    (type & ESCFILE && (c == '/' || c == ' ')))
499*9f20bfa6SDavid van Moolenbroek 		{
500*9f20bfa6SDavid van Moolenbroek 			errno = EINVAL;
501*9f20bfa6SDavid van Moolenbroek 			if (c == '\\') {
502*9f20bfa6SDavid van Moolenbroek 				if (dst) {
503*9f20bfa6SDavid van Moolenbroek 					if (len  == 0 || len == 1) {
504*9f20bfa6SDavid van Moolenbroek 						errno = ENOSPC;
505*9f20bfa6SDavid van Moolenbroek 						return -1;
506*9f20bfa6SDavid van Moolenbroek 					}
507*9f20bfa6SDavid van Moolenbroek 					*dst++ = '\\'; *dst++ = '\\';
508*9f20bfa6SDavid van Moolenbroek 					len -= 2;
509*9f20bfa6SDavid van Moolenbroek 				}
510*9f20bfa6SDavid van Moolenbroek 				bytes += 2;
511*9f20bfa6SDavid van Moolenbroek 				continue;
512*9f20bfa6SDavid van Moolenbroek 			}
513*9f20bfa6SDavid van Moolenbroek 			if (dst) {
514*9f20bfa6SDavid van Moolenbroek 				if (len < 5) {
515*9f20bfa6SDavid van Moolenbroek 					errno = ENOSPC;
516*9f20bfa6SDavid van Moolenbroek 					return -1;
517*9f20bfa6SDavid van Moolenbroek 				}
518*9f20bfa6SDavid van Moolenbroek 				*dst++ = '\\';
519*9f20bfa6SDavid van Moolenbroek 		                *dst++ = (char)(((c >> 6) & 03) + '0');
520*9f20bfa6SDavid van Moolenbroek 		                *dst++ = (char)(((c >> 3) & 07) + '0');
521*9f20bfa6SDavid van Moolenbroek 		                *dst++ = (char)(( c       & 07) + '0');
522*9f20bfa6SDavid van Moolenbroek 				len -= 4;
523*9f20bfa6SDavid van Moolenbroek 			}
524*9f20bfa6SDavid van Moolenbroek 			bytes += 4;
525*9f20bfa6SDavid van Moolenbroek 		} else {
526*9f20bfa6SDavid van Moolenbroek 			if (dst) {
527*9f20bfa6SDavid van Moolenbroek 				if (len == 0) {
528*9f20bfa6SDavid van Moolenbroek 					errno = ENOSPC;
529*9f20bfa6SDavid van Moolenbroek 					return -1;
530*9f20bfa6SDavid van Moolenbroek 				}
531*9f20bfa6SDavid van Moolenbroek 				*dst++ = (char)c;
532*9f20bfa6SDavid van Moolenbroek 				len--;
533*9f20bfa6SDavid van Moolenbroek 			}
534*9f20bfa6SDavid van Moolenbroek 			bytes++;
535*9f20bfa6SDavid van Moolenbroek 		}
536*9f20bfa6SDavid van Moolenbroek 	}
537*9f20bfa6SDavid van Moolenbroek 
538*9f20bfa6SDavid van Moolenbroek 	/* NULL */
539*9f20bfa6SDavid van Moolenbroek 	if (dst) {
540*9f20bfa6SDavid van Moolenbroek 		if (len == 0) {
541*9f20bfa6SDavid van Moolenbroek 			errno = ENOSPC;
542*9f20bfa6SDavid van Moolenbroek 			return -1;
543*9f20bfa6SDavid van Moolenbroek 		}
544*9f20bfa6SDavid van Moolenbroek 		*dst = '\0';
545*9f20bfa6SDavid van Moolenbroek 
546*9f20bfa6SDavid van Moolenbroek 		/* Now we've printed it, validate the domain */
547*9f20bfa6SDavid van Moolenbroek 		if (type & DOMAIN && !valid_domainname(odst, type)) {
548*9f20bfa6SDavid van Moolenbroek 			*odst = '\0';
549*9f20bfa6SDavid van Moolenbroek 			return 1;
550*9f20bfa6SDavid van Moolenbroek 		}
551*9f20bfa6SDavid van Moolenbroek 
552*9f20bfa6SDavid van Moolenbroek 	}
553*9f20bfa6SDavid van Moolenbroek 
554*9f20bfa6SDavid van Moolenbroek 	return (ssize_t)bytes;
555*9f20bfa6SDavid van Moolenbroek }
556*9f20bfa6SDavid van Moolenbroek 
557*9f20bfa6SDavid van Moolenbroek #define ADDRSZ		4
558*9f20bfa6SDavid van Moolenbroek #define ADDR6SZ		16
559*9f20bfa6SDavid van Moolenbroek static ssize_t
dhcp_optlen(const struct dhcp_opt * opt,size_t dl)560*9f20bfa6SDavid van Moolenbroek dhcp_optlen(const struct dhcp_opt *opt, size_t dl)
561*9f20bfa6SDavid van Moolenbroek {
562*9f20bfa6SDavid van Moolenbroek 	size_t sz;
563*9f20bfa6SDavid van Moolenbroek 
564*9f20bfa6SDavid van Moolenbroek 	if (opt->type == 0 ||
565*9f20bfa6SDavid van Moolenbroek 	    opt->type & (STRING | BINHEX | RFC3442 | RFC5969))
566*9f20bfa6SDavid van Moolenbroek 	{
567*9f20bfa6SDavid van Moolenbroek 		if (opt->len) {
568*9f20bfa6SDavid van Moolenbroek 			if ((size_t)opt->len > dl)
569*9f20bfa6SDavid van Moolenbroek 				return -1;
570*9f20bfa6SDavid van Moolenbroek 			return (ssize_t)opt->len;
571*9f20bfa6SDavid van Moolenbroek 		}
572*9f20bfa6SDavid van Moolenbroek 		return (ssize_t)dl;
573*9f20bfa6SDavid van Moolenbroek 	}
574*9f20bfa6SDavid van Moolenbroek 
575*9f20bfa6SDavid van Moolenbroek 	if ((opt->type & (ADDRIPV4 | ARRAY)) == (ADDRIPV4 | ARRAY)) {
576*9f20bfa6SDavid van Moolenbroek 		if (dl < ADDRSZ)
577*9f20bfa6SDavid van Moolenbroek 			return -1;
578*9f20bfa6SDavid van Moolenbroek 		return (ssize_t)(dl - (dl % ADDRSZ));
579*9f20bfa6SDavid van Moolenbroek 	}
580*9f20bfa6SDavid van Moolenbroek 
581*9f20bfa6SDavid van Moolenbroek 	if ((opt->type & (ADDRIPV6 | ARRAY)) == (ADDRIPV6 | ARRAY)) {
582*9f20bfa6SDavid van Moolenbroek 		if (dl < ADDR6SZ)
583*9f20bfa6SDavid van Moolenbroek 			return -1;
584*9f20bfa6SDavid van Moolenbroek 		return (ssize_t)(dl - (dl % ADDR6SZ));
585*9f20bfa6SDavid van Moolenbroek 	}
586*9f20bfa6SDavid van Moolenbroek 
587*9f20bfa6SDavid van Moolenbroek 	if (opt->type & (UINT32 | ADDRIPV4))
588*9f20bfa6SDavid van Moolenbroek 		sz = sizeof(uint32_t);
589*9f20bfa6SDavid van Moolenbroek 	else if (opt->type & UINT16)
590*9f20bfa6SDavid van Moolenbroek 		sz = sizeof(uint16_t);
591*9f20bfa6SDavid van Moolenbroek 	else if (opt->type & (UINT8 | BITFLAG))
592*9f20bfa6SDavid van Moolenbroek 		sz = sizeof(uint8_t);
593*9f20bfa6SDavid van Moolenbroek 	else if (opt->type & ADDRIPV6)
594*9f20bfa6SDavid van Moolenbroek 		sz = ADDR6SZ;
595*9f20bfa6SDavid van Moolenbroek 	else
596*9f20bfa6SDavid van Moolenbroek 		/* If we don't know the size, assume it's valid */
597*9f20bfa6SDavid van Moolenbroek 		return (ssize_t)dl;
598*9f20bfa6SDavid van Moolenbroek 	return dl < sz ? -1 : (ssize_t)sz;
599*9f20bfa6SDavid van Moolenbroek }
600*9f20bfa6SDavid van Moolenbroek 
601*9f20bfa6SDavid van Moolenbroek static ssize_t
print_option(char * s,size_t len,const struct dhcp_opt * opt,const uint8_t * data,size_t dl,const char * ifname)602*9f20bfa6SDavid van Moolenbroek print_option(char *s, size_t len, const struct dhcp_opt *opt,
603*9f20bfa6SDavid van Moolenbroek     const uint8_t *data, size_t dl, const char *ifname)
604*9f20bfa6SDavid van Moolenbroek {
605*9f20bfa6SDavid van Moolenbroek 	const uint8_t *e, *t;
606*9f20bfa6SDavid van Moolenbroek 	uint16_t u16;
607*9f20bfa6SDavid van Moolenbroek 	int16_t s16;
608*9f20bfa6SDavid van Moolenbroek 	uint32_t u32;
609*9f20bfa6SDavid van Moolenbroek 	int32_t s32;
610*9f20bfa6SDavid van Moolenbroek 	struct in_addr addr;
611*9f20bfa6SDavid van Moolenbroek 	ssize_t bytes = 0, sl;
612*9f20bfa6SDavid van Moolenbroek 	size_t l;
613*9f20bfa6SDavid van Moolenbroek 	char *tmp;
614*9f20bfa6SDavid van Moolenbroek 
615*9f20bfa6SDavid van Moolenbroek #ifndef INET6
616*9f20bfa6SDavid van Moolenbroek 	UNUSED(ifname);
617*9f20bfa6SDavid van Moolenbroek #endif
618*9f20bfa6SDavid van Moolenbroek 
619*9f20bfa6SDavid van Moolenbroek 	if (opt->type & RFC1035) {
620*9f20bfa6SDavid van Moolenbroek 		sl = decode_rfc1035(NULL, 0, data, dl);
621*9f20bfa6SDavid van Moolenbroek 		if (sl == 0 || sl == -1)
622*9f20bfa6SDavid van Moolenbroek 			return sl;
623*9f20bfa6SDavid van Moolenbroek 		l = (size_t)sl + 1;
624*9f20bfa6SDavid van Moolenbroek 		tmp = malloc(l);
625*9f20bfa6SDavid van Moolenbroek 		if (tmp == NULL)
626*9f20bfa6SDavid van Moolenbroek 			return -1;
627*9f20bfa6SDavid van Moolenbroek 		decode_rfc1035(tmp, l, data, dl);
628*9f20bfa6SDavid van Moolenbroek 		sl = print_string(s, len, opt->type, (uint8_t *)tmp, l - 1);
629*9f20bfa6SDavid van Moolenbroek 		free(tmp);
630*9f20bfa6SDavid van Moolenbroek 		return sl;
631*9f20bfa6SDavid van Moolenbroek 	}
632*9f20bfa6SDavid van Moolenbroek 
633*9f20bfa6SDavid van Moolenbroek #ifdef INET
634*9f20bfa6SDavid van Moolenbroek 	if (opt->type & RFC3361) {
635*9f20bfa6SDavid van Moolenbroek 		if ((tmp = decode_rfc3361(data, dl)) == NULL)
636*9f20bfa6SDavid van Moolenbroek 			return -1;
637*9f20bfa6SDavid van Moolenbroek 		l = strlen(tmp);
638*9f20bfa6SDavid van Moolenbroek 		sl = print_string(s, len, opt->type, (uint8_t *)tmp, l);
639*9f20bfa6SDavid van Moolenbroek 		free(tmp);
640*9f20bfa6SDavid van Moolenbroek 		return sl;
641*9f20bfa6SDavid van Moolenbroek 	}
642*9f20bfa6SDavid van Moolenbroek 
643*9f20bfa6SDavid van Moolenbroek 	if (opt->type & RFC3442)
644*9f20bfa6SDavid van Moolenbroek 		return decode_rfc3442(s, len, data, dl);
645*9f20bfa6SDavid van Moolenbroek 
646*9f20bfa6SDavid van Moolenbroek 	if (opt->type & RFC5969)
647*9f20bfa6SDavid van Moolenbroek 		return decode_rfc5969(s, len, data, dl);
648*9f20bfa6SDavid van Moolenbroek #endif
649*9f20bfa6SDavid van Moolenbroek 
650*9f20bfa6SDavid van Moolenbroek 	if (opt->type & STRING)
651*9f20bfa6SDavid van Moolenbroek 		return print_string(s, len, opt->type, data, dl);
652*9f20bfa6SDavid van Moolenbroek 
653*9f20bfa6SDavid van Moolenbroek 	if (opt->type & FLAG) {
654*9f20bfa6SDavid van Moolenbroek 		if (s) {
655*9f20bfa6SDavid van Moolenbroek 			*s++ = '1';
656*9f20bfa6SDavid van Moolenbroek 			*s = '\0';
657*9f20bfa6SDavid van Moolenbroek 		}
658*9f20bfa6SDavid van Moolenbroek 		return 1;
659*9f20bfa6SDavid van Moolenbroek 	}
660*9f20bfa6SDavid van Moolenbroek 
661*9f20bfa6SDavid van Moolenbroek 	if (opt->type & BITFLAG) {
662*9f20bfa6SDavid van Moolenbroek 		/* bitflags are a string, MSB first, such as ABCDEFGH
663*9f20bfa6SDavid van Moolenbroek 		 * where A is 10000000, B is 01000000, etc. */
664*9f20bfa6SDavid van Moolenbroek 		bytes = 0;
665*9f20bfa6SDavid van Moolenbroek 		for (l = 0, sl = sizeof(opt->bitflags) - 1;
666*9f20bfa6SDavid van Moolenbroek 		    l < sizeof(opt->bitflags);
667*9f20bfa6SDavid van Moolenbroek 		    l++, sl--)
668*9f20bfa6SDavid van Moolenbroek 		{
669*9f20bfa6SDavid van Moolenbroek 			/* Don't print NULL or 0 flags */
670*9f20bfa6SDavid van Moolenbroek 			if (opt->bitflags[l] != '\0' &&
671*9f20bfa6SDavid van Moolenbroek 			    opt->bitflags[l] != '0' &&
672*9f20bfa6SDavid van Moolenbroek 			    *data & (1 << sl))
673*9f20bfa6SDavid van Moolenbroek 			{
674*9f20bfa6SDavid van Moolenbroek 				if (s)
675*9f20bfa6SDavid van Moolenbroek 					*s++ = opt->bitflags[l];
676*9f20bfa6SDavid van Moolenbroek 				bytes++;
677*9f20bfa6SDavid van Moolenbroek 			}
678*9f20bfa6SDavid van Moolenbroek 		}
679*9f20bfa6SDavid van Moolenbroek 		if (s)
680*9f20bfa6SDavid van Moolenbroek 			*s = '\0';
681*9f20bfa6SDavid van Moolenbroek 		return bytes;
682*9f20bfa6SDavid van Moolenbroek 	}
683*9f20bfa6SDavid van Moolenbroek 
684*9f20bfa6SDavid van Moolenbroek 	if (!s) {
685*9f20bfa6SDavid van Moolenbroek 		if (opt->type & UINT8)
686*9f20bfa6SDavid van Moolenbroek 			l = 3;
687*9f20bfa6SDavid van Moolenbroek 		else if (opt->type & UINT16) {
688*9f20bfa6SDavid van Moolenbroek 			l = 5;
689*9f20bfa6SDavid van Moolenbroek 			dl /= 2;
690*9f20bfa6SDavid van Moolenbroek 		} else if (opt->type & SINT16) {
691*9f20bfa6SDavid van Moolenbroek 			l = 6;
692*9f20bfa6SDavid van Moolenbroek 			dl /= 2;
693*9f20bfa6SDavid van Moolenbroek 		} else if (opt->type & UINT32) {
694*9f20bfa6SDavid van Moolenbroek 			l = 10;
695*9f20bfa6SDavid van Moolenbroek 			dl /= 4;
696*9f20bfa6SDavid van Moolenbroek 		} else if (opt->type & SINT32) {
697*9f20bfa6SDavid van Moolenbroek 			l = 11;
698*9f20bfa6SDavid van Moolenbroek 			dl /= 4;
699*9f20bfa6SDavid van Moolenbroek 		} else if (opt->type & ADDRIPV4) {
700*9f20bfa6SDavid van Moolenbroek 			l = 16;
701*9f20bfa6SDavid van Moolenbroek 			dl /= 4;
702*9f20bfa6SDavid van Moolenbroek 		}
703*9f20bfa6SDavid van Moolenbroek #ifdef INET6
704*9f20bfa6SDavid van Moolenbroek 		else if (opt->type & ADDRIPV6) {
705*9f20bfa6SDavid van Moolenbroek 			e = data + dl;
706*9f20bfa6SDavid van Moolenbroek 			l = 0;
707*9f20bfa6SDavid van Moolenbroek 			while (data < e) {
708*9f20bfa6SDavid van Moolenbroek 				if (l)
709*9f20bfa6SDavid van Moolenbroek 					l++; /* space */
710*9f20bfa6SDavid van Moolenbroek 				sl = ipv6_printaddr(NULL, 0, data, ifname);
711*9f20bfa6SDavid van Moolenbroek 				if (sl != -1)
712*9f20bfa6SDavid van Moolenbroek 					l += (size_t)sl;
713*9f20bfa6SDavid van Moolenbroek 				data += 16;
714*9f20bfa6SDavid van Moolenbroek 			}
715*9f20bfa6SDavid van Moolenbroek 			return (ssize_t)l;
716*9f20bfa6SDavid van Moolenbroek 		}
717*9f20bfa6SDavid van Moolenbroek #endif
718*9f20bfa6SDavid van Moolenbroek 		else {
719*9f20bfa6SDavid van Moolenbroek 			errno = EINVAL;
720*9f20bfa6SDavid van Moolenbroek 			return -1;
721*9f20bfa6SDavid van Moolenbroek 		}
722*9f20bfa6SDavid van Moolenbroek 		return (ssize_t)(l * dl);
723*9f20bfa6SDavid van Moolenbroek 	}
724*9f20bfa6SDavid van Moolenbroek 
725*9f20bfa6SDavid van Moolenbroek 	t = data;
726*9f20bfa6SDavid van Moolenbroek 	e = data + dl;
727*9f20bfa6SDavid van Moolenbroek 	while (data < e) {
728*9f20bfa6SDavid van Moolenbroek 		if (data != t) {
729*9f20bfa6SDavid van Moolenbroek 			*s++ = ' ';
730*9f20bfa6SDavid van Moolenbroek 			bytes++;
731*9f20bfa6SDavid van Moolenbroek 			len--;
732*9f20bfa6SDavid van Moolenbroek 		}
733*9f20bfa6SDavid van Moolenbroek 		if (opt->type & UINT8) {
734*9f20bfa6SDavid van Moolenbroek 			sl = snprintf(s, len, "%u", *data);
735*9f20bfa6SDavid van Moolenbroek 			data++;
736*9f20bfa6SDavid van Moolenbroek 		} else if (opt->type & UINT16) {
737*9f20bfa6SDavid van Moolenbroek 			memcpy(&u16, data, sizeof(u16));
738*9f20bfa6SDavid van Moolenbroek 			u16 = ntohs(u16);
739*9f20bfa6SDavid van Moolenbroek 			sl = snprintf(s, len, "%u", u16);
740*9f20bfa6SDavid van Moolenbroek 			data += sizeof(u16);
741*9f20bfa6SDavid van Moolenbroek 		} else if (opt->type & SINT16) {
742*9f20bfa6SDavid van Moolenbroek 			memcpy(&u16, data, sizeof(u16));
743*9f20bfa6SDavid van Moolenbroek 			s16 = (int16_t)ntohs(u16);
744*9f20bfa6SDavid van Moolenbroek 			sl = snprintf(s, len, "%d", s16);
745*9f20bfa6SDavid van Moolenbroek 			data += sizeof(u16);
746*9f20bfa6SDavid van Moolenbroek 		} else if (opt->type & UINT32) {
747*9f20bfa6SDavid van Moolenbroek 			memcpy(&u32, data, sizeof(u32));
748*9f20bfa6SDavid van Moolenbroek 			u32 = ntohl(u32);
749*9f20bfa6SDavid van Moolenbroek 			sl = snprintf(s, len, "%u", u32);
750*9f20bfa6SDavid van Moolenbroek 			data += sizeof(u32);
751*9f20bfa6SDavid van Moolenbroek 		} else if (opt->type & SINT32) {
752*9f20bfa6SDavid van Moolenbroek 			memcpy(&u32, data, sizeof(u32));
753*9f20bfa6SDavid van Moolenbroek 			s32 = (int32_t)ntohl(u32);
754*9f20bfa6SDavid van Moolenbroek 			sl = snprintf(s, len, "%d", s32);
755*9f20bfa6SDavid van Moolenbroek 			data += sizeof(u32);
756*9f20bfa6SDavid van Moolenbroek 		} else if (opt->type & ADDRIPV4) {
757*9f20bfa6SDavid van Moolenbroek 			memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
758*9f20bfa6SDavid van Moolenbroek 			sl = snprintf(s, len, "%s", inet_ntoa(addr));
759*9f20bfa6SDavid van Moolenbroek 			data += sizeof(addr.s_addr);
760*9f20bfa6SDavid van Moolenbroek 		}
761*9f20bfa6SDavid van Moolenbroek #ifdef INET6
762*9f20bfa6SDavid van Moolenbroek 		else if (opt->type & ADDRIPV6) {
763*9f20bfa6SDavid van Moolenbroek 			ssize_t r;
764*9f20bfa6SDavid van Moolenbroek 
765*9f20bfa6SDavid van Moolenbroek 			r = ipv6_printaddr(s, len, data, ifname);
766*9f20bfa6SDavid van Moolenbroek 			if (r != -1)
767*9f20bfa6SDavid van Moolenbroek 				sl = r;
768*9f20bfa6SDavid van Moolenbroek 			else
769*9f20bfa6SDavid van Moolenbroek 				sl = 0;
770*9f20bfa6SDavid van Moolenbroek 			data += 16;
771*9f20bfa6SDavid van Moolenbroek 		}
772*9f20bfa6SDavid van Moolenbroek #endif
773*9f20bfa6SDavid van Moolenbroek 		else
774*9f20bfa6SDavid van Moolenbroek 			sl = 0;
775*9f20bfa6SDavid van Moolenbroek 		len -= (size_t)sl;
776*9f20bfa6SDavid van Moolenbroek 		bytes += sl;
777*9f20bfa6SDavid van Moolenbroek 		s += sl;
778*9f20bfa6SDavid van Moolenbroek 	}
779*9f20bfa6SDavid van Moolenbroek 
780*9f20bfa6SDavid van Moolenbroek 	return bytes;
781*9f20bfa6SDavid van Moolenbroek }
782*9f20bfa6SDavid van Moolenbroek 
783*9f20bfa6SDavid van Moolenbroek int
dhcp_set_leasefile(char * leasefile,size_t len,int family,const struct interface * ifp)784*9f20bfa6SDavid van Moolenbroek dhcp_set_leasefile(char *leasefile, size_t len, int family,
785*9f20bfa6SDavid van Moolenbroek     const struct interface *ifp)
786*9f20bfa6SDavid van Moolenbroek {
787*9f20bfa6SDavid van Moolenbroek 	char ssid[len];
788*9f20bfa6SDavid van Moolenbroek 
789*9f20bfa6SDavid van Moolenbroek 	if (ifp->name[0] == '\0') {
790*9f20bfa6SDavid van Moolenbroek 		strlcpy(leasefile, ifp->ctx->pidfile, len);
791*9f20bfa6SDavid van Moolenbroek 		return 0;
792*9f20bfa6SDavid van Moolenbroek 	}
793*9f20bfa6SDavid van Moolenbroek 
794*9f20bfa6SDavid van Moolenbroek 	switch (family) {
795*9f20bfa6SDavid van Moolenbroek 	case AF_INET:
796*9f20bfa6SDavid van Moolenbroek 	case AF_INET6:
797*9f20bfa6SDavid van Moolenbroek 		break;
798*9f20bfa6SDavid van Moolenbroek 	default:
799*9f20bfa6SDavid van Moolenbroek 		errno = EINVAL;
800*9f20bfa6SDavid van Moolenbroek 		return -1;
801*9f20bfa6SDavid van Moolenbroek 	}
802*9f20bfa6SDavid van Moolenbroek 
803*9f20bfa6SDavid van Moolenbroek 	if (ifp->wireless) {
804*9f20bfa6SDavid van Moolenbroek 		ssid[0] = '-';
805*9f20bfa6SDavid van Moolenbroek 		print_string(ssid + 1, sizeof(ssid) - 1,
806*9f20bfa6SDavid van Moolenbroek 		    ESCFILE,
807*9f20bfa6SDavid van Moolenbroek 		    (const uint8_t *)ifp->ssid, ifp->ssid_len);
808*9f20bfa6SDavid van Moolenbroek 	} else
809*9f20bfa6SDavid van Moolenbroek 		ssid[0] = '\0';
810*9f20bfa6SDavid van Moolenbroek 	return snprintf(leasefile, len,
811*9f20bfa6SDavid van Moolenbroek 	    family == AF_INET ? LEASEFILE : LEASEFILE6,
812*9f20bfa6SDavid van Moolenbroek 	    ifp->name, ssid);
813*9f20bfa6SDavid van Moolenbroek }
814*9f20bfa6SDavid van Moolenbroek 
815*9f20bfa6SDavid van Moolenbroek static size_t
dhcp_envoption1(struct dhcpcd_ctx * ctx,char ** env,const char * prefix,const struct dhcp_opt * opt,int vname,const uint8_t * od,size_t ol,const char * ifname)816*9f20bfa6SDavid van Moolenbroek dhcp_envoption1(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
817*9f20bfa6SDavid van Moolenbroek     const struct dhcp_opt *opt, int vname, const uint8_t *od, size_t ol,
818*9f20bfa6SDavid van Moolenbroek     const char *ifname)
819*9f20bfa6SDavid van Moolenbroek {
820*9f20bfa6SDavid van Moolenbroek 	ssize_t len;
821*9f20bfa6SDavid van Moolenbroek 	size_t e;
822*9f20bfa6SDavid van Moolenbroek 	char *v, *val;
823*9f20bfa6SDavid van Moolenbroek 
824*9f20bfa6SDavid van Moolenbroek 	if (opt->len && opt->len < ol)
825*9f20bfa6SDavid van Moolenbroek 		ol = opt->len;
826*9f20bfa6SDavid van Moolenbroek 	len = print_option(NULL, 0, opt, od, ol, ifname);
827*9f20bfa6SDavid van Moolenbroek 	if (len < 0)
828*9f20bfa6SDavid van Moolenbroek 		return 0;
829*9f20bfa6SDavid van Moolenbroek 	if (vname)
830*9f20bfa6SDavid van Moolenbroek 		e = strlen(opt->var) + 1;
831*9f20bfa6SDavid van Moolenbroek 	else
832*9f20bfa6SDavid van Moolenbroek 		e = 0;
833*9f20bfa6SDavid van Moolenbroek 	if (prefix)
834*9f20bfa6SDavid van Moolenbroek 		e += strlen(prefix);
835*9f20bfa6SDavid van Moolenbroek 	e += (size_t)len + 2;
836*9f20bfa6SDavid van Moolenbroek 	if (env == NULL)
837*9f20bfa6SDavid van Moolenbroek 		return e;
838*9f20bfa6SDavid van Moolenbroek 	v = val = *env = malloc(e);
839*9f20bfa6SDavid van Moolenbroek 	if (v == NULL) {
840*9f20bfa6SDavid van Moolenbroek 		logger(ctx, LOG_ERR, "%s: %m", __func__);
841*9f20bfa6SDavid van Moolenbroek 		return 0;
842*9f20bfa6SDavid van Moolenbroek 	}
843*9f20bfa6SDavid van Moolenbroek 	if (vname)
844*9f20bfa6SDavid van Moolenbroek 		v += snprintf(val, e, "%s_%s=", prefix, opt->var);
845*9f20bfa6SDavid van Moolenbroek 	else
846*9f20bfa6SDavid van Moolenbroek 		v += snprintf(val, e, "%s=", prefix);
847*9f20bfa6SDavid van Moolenbroek 	if (len != 0)
848*9f20bfa6SDavid van Moolenbroek 		print_option(v, (size_t)len + 1, opt, od, ol, ifname);
849*9f20bfa6SDavid van Moolenbroek 	return e;
850*9f20bfa6SDavid van Moolenbroek }
851*9f20bfa6SDavid van Moolenbroek 
852*9f20bfa6SDavid van Moolenbroek size_t
dhcp_envoption(struct dhcpcd_ctx * ctx,char ** env,const char * prefix,const char * ifname,struct dhcp_opt * opt,const uint8_t * (* dgetopt)(struct dhcpcd_ctx *,size_t *,unsigned int *,size_t *,const uint8_t *,size_t,struct dhcp_opt **),const uint8_t * od,size_t ol)853*9f20bfa6SDavid van Moolenbroek dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
854*9f20bfa6SDavid van Moolenbroek     const char *ifname, struct dhcp_opt *opt,
855*9f20bfa6SDavid van Moolenbroek     const uint8_t *(*dgetopt)(struct dhcpcd_ctx *,
856*9f20bfa6SDavid van Moolenbroek     size_t *, unsigned int *, size_t *,
857*9f20bfa6SDavid van Moolenbroek     const uint8_t *, size_t, struct dhcp_opt **),
858*9f20bfa6SDavid van Moolenbroek     const uint8_t *od, size_t ol)
859*9f20bfa6SDavid van Moolenbroek {
860*9f20bfa6SDavid van Moolenbroek 	size_t e, i, n, eos, eol;
861*9f20bfa6SDavid van Moolenbroek 	ssize_t eo;
862*9f20bfa6SDavid van Moolenbroek 	unsigned int eoc;
863*9f20bfa6SDavid van Moolenbroek 	const uint8_t *eod;
864*9f20bfa6SDavid van Moolenbroek 	int ov;
865*9f20bfa6SDavid van Moolenbroek 	struct dhcp_opt *eopt, *oopt;
866*9f20bfa6SDavid van Moolenbroek 	char *pfx;
867*9f20bfa6SDavid van Moolenbroek 
868*9f20bfa6SDavid van Moolenbroek 	/* If no embedded or encapsulated options, it's easy */
869*9f20bfa6SDavid van Moolenbroek 	if (opt->embopts_len == 0 && opt->encopts_len == 0) {
870*9f20bfa6SDavid van Moolenbroek 		if (!(opt->type & RESERVED) &&
871*9f20bfa6SDavid van Moolenbroek 		    dhcp_envoption1(ctx, env == NULL ? NULL : &env[0],
872*9f20bfa6SDavid van Moolenbroek 		    prefix, opt, 1, od, ol, ifname))
873*9f20bfa6SDavid van Moolenbroek 			return 1;
874*9f20bfa6SDavid van Moolenbroek 		return 0;
875*9f20bfa6SDavid van Moolenbroek 	}
876*9f20bfa6SDavid van Moolenbroek 
877*9f20bfa6SDavid van Moolenbroek 	/* Create a new prefix based on the option */
878*9f20bfa6SDavid van Moolenbroek 	if (env) {
879*9f20bfa6SDavid van Moolenbroek 		if (opt->type & INDEX) {
880*9f20bfa6SDavid van Moolenbroek 			if (opt->index > 999) {
881*9f20bfa6SDavid van Moolenbroek 				errno = ENOBUFS;
882*9f20bfa6SDavid van Moolenbroek 				logger(ctx, LOG_ERR, "%s: %m", __func__);
883*9f20bfa6SDavid van Moolenbroek 				return 0;
884*9f20bfa6SDavid van Moolenbroek 			}
885*9f20bfa6SDavid van Moolenbroek 		}
886*9f20bfa6SDavid van Moolenbroek 		e = strlen(prefix) + strlen(opt->var) + 2 +
887*9f20bfa6SDavid van Moolenbroek 		    (opt->type & INDEX ? 3 : 0);
888*9f20bfa6SDavid van Moolenbroek 		pfx = malloc(e);
889*9f20bfa6SDavid van Moolenbroek 		if (pfx == NULL) {
890*9f20bfa6SDavid van Moolenbroek 			logger(ctx, LOG_ERR, "%s: %m", __func__);
891*9f20bfa6SDavid van Moolenbroek 			return 0;
892*9f20bfa6SDavid van Moolenbroek 		}
893*9f20bfa6SDavid van Moolenbroek 		if (opt->type & INDEX)
894*9f20bfa6SDavid van Moolenbroek 			snprintf(pfx, e, "%s_%s%d", prefix,
895*9f20bfa6SDavid van Moolenbroek 			    opt->var, ++opt->index);
896*9f20bfa6SDavid van Moolenbroek 		else
897*9f20bfa6SDavid van Moolenbroek 			snprintf(pfx, e, "%s_%s", prefix, opt->var);
898*9f20bfa6SDavid van Moolenbroek 	} else
899*9f20bfa6SDavid van Moolenbroek 		pfx = NULL;
900*9f20bfa6SDavid van Moolenbroek 
901*9f20bfa6SDavid van Moolenbroek 	/* Embedded options are always processed first as that
902*9f20bfa6SDavid van Moolenbroek 	 * is a fixed layout */
903*9f20bfa6SDavid van Moolenbroek 	n = 0;
904*9f20bfa6SDavid van Moolenbroek 	for (i = 0, eopt = opt->embopts; i < opt->embopts_len; i++, eopt++) {
905*9f20bfa6SDavid van Moolenbroek 		eo = dhcp_optlen(eopt, ol);
906*9f20bfa6SDavid van Moolenbroek 		if (eo == -1) {
907*9f20bfa6SDavid van Moolenbroek 			if (env == NULL)
908*9f20bfa6SDavid van Moolenbroek 				logger(ctx, LOG_ERR,
909*9f20bfa6SDavid van Moolenbroek 				    "%s: %s: malformed embedded option %d:%d",
910*9f20bfa6SDavid van Moolenbroek 				    ifname, __func__, opt->option,
911*9f20bfa6SDavid van Moolenbroek 				    eopt->option);
912*9f20bfa6SDavid van Moolenbroek 			goto out;
913*9f20bfa6SDavid van Moolenbroek 		}
914*9f20bfa6SDavid van Moolenbroek 		if (eo == 0) {
915*9f20bfa6SDavid van Moolenbroek 			/* An option was expected, but there is no data
916*9f20bfa6SDavid van Moolenbroek 			 * data for it.
917*9f20bfa6SDavid van Moolenbroek 			 * This may not be an error as some options like
918*9f20bfa6SDavid van Moolenbroek 			 * DHCP FQDN in RFC4702 have a string as the last
919*9f20bfa6SDavid van Moolenbroek 			 * option which is optional.
920*9f20bfa6SDavid van Moolenbroek 			 * FIXME: Add an flag to the options to indicate
921*9f20bfa6SDavid van Moolenbroek 			 * wether this is allowable or not. */
922*9f20bfa6SDavid van Moolenbroek 			if (env == NULL &&
923*9f20bfa6SDavid van Moolenbroek 			    (ol != 0 || i + 1 < opt->embopts_len))
924*9f20bfa6SDavid van Moolenbroek 				logger(ctx, LOG_ERR,
925*9f20bfa6SDavid van Moolenbroek 				    "%s: %s: malformed embedded option %d:%d",
926*9f20bfa6SDavid van Moolenbroek 				    ifname, __func__, opt->option,
927*9f20bfa6SDavid van Moolenbroek 				    eopt->option);
928*9f20bfa6SDavid van Moolenbroek 			goto out;
929*9f20bfa6SDavid van Moolenbroek 		}
930*9f20bfa6SDavid van Moolenbroek 		/* Use the option prefix if the embedded option
931*9f20bfa6SDavid van Moolenbroek 		 * name is different.
932*9f20bfa6SDavid van Moolenbroek 		 * This avoids new_fqdn_fqdn which would be silly. */
933*9f20bfa6SDavid van Moolenbroek 		if (!(eopt->type & RESERVED)) {
934*9f20bfa6SDavid van Moolenbroek 			ov = strcmp(opt->var, eopt->var);
935*9f20bfa6SDavid van Moolenbroek 			if (dhcp_envoption1(ctx, env == NULL ? NULL : &env[n],
936*9f20bfa6SDavid van Moolenbroek 			    pfx, eopt, ov, od, (size_t)eo, ifname))
937*9f20bfa6SDavid van Moolenbroek 				n++;
938*9f20bfa6SDavid van Moolenbroek 		}
939*9f20bfa6SDavid van Moolenbroek 		od += (size_t)eo;
940*9f20bfa6SDavid van Moolenbroek 		ol -= (size_t)eo;
941*9f20bfa6SDavid van Moolenbroek 	}
942*9f20bfa6SDavid van Moolenbroek 
943*9f20bfa6SDavid van Moolenbroek 	/* Enumerate our encapsulated options */
944*9f20bfa6SDavid van Moolenbroek 	if (opt->encopts_len && ol > 0) {
945*9f20bfa6SDavid van Moolenbroek 		/* Zero any option indexes
946*9f20bfa6SDavid van Moolenbroek 		 * We assume that referenced encapsulated options are NEVER
947*9f20bfa6SDavid van Moolenbroek 		 * recursive as the index order could break. */
948*9f20bfa6SDavid van Moolenbroek 		for (i = 0, eopt = opt->encopts;
949*9f20bfa6SDavid van Moolenbroek 		    i < opt->encopts_len;
950*9f20bfa6SDavid van Moolenbroek 		    i++, eopt++)
951*9f20bfa6SDavid van Moolenbroek 		{
952*9f20bfa6SDavid van Moolenbroek 			eoc = opt->option;
953*9f20bfa6SDavid van Moolenbroek 			if (eopt->type & OPTION) {
954*9f20bfa6SDavid van Moolenbroek 				dgetopt(ctx, NULL, &eoc, NULL, NULL, 0, &oopt);
955*9f20bfa6SDavid van Moolenbroek 				if (oopt)
956*9f20bfa6SDavid van Moolenbroek 					oopt->index = 0;
957*9f20bfa6SDavid van Moolenbroek 			}
958*9f20bfa6SDavid van Moolenbroek 		}
959*9f20bfa6SDavid van Moolenbroek 
960*9f20bfa6SDavid van Moolenbroek 		while ((eod = dgetopt(ctx, &eos, &eoc, &eol, od, ol, &oopt))) {
961*9f20bfa6SDavid van Moolenbroek 			for (i = 0, eopt = opt->encopts;
962*9f20bfa6SDavid van Moolenbroek 			    i < opt->encopts_len;
963*9f20bfa6SDavid van Moolenbroek 			    i++, eopt++)
964*9f20bfa6SDavid van Moolenbroek 			{
965*9f20bfa6SDavid van Moolenbroek 				if (eopt->option == eoc) {
966*9f20bfa6SDavid van Moolenbroek 					if (eopt->type & OPTION) {
967*9f20bfa6SDavid van Moolenbroek 						if (oopt == NULL)
968*9f20bfa6SDavid van Moolenbroek 							/* Report error? */
969*9f20bfa6SDavid van Moolenbroek 							continue;
970*9f20bfa6SDavid van Moolenbroek 					}
971*9f20bfa6SDavid van Moolenbroek 					n += dhcp_envoption(ctx,
972*9f20bfa6SDavid van Moolenbroek 					    env == NULL ? NULL : &env[n], pfx,
973*9f20bfa6SDavid van Moolenbroek 					    ifname,
974*9f20bfa6SDavid van Moolenbroek 					    eopt->type & OPTION ? oopt : eopt,
975*9f20bfa6SDavid van Moolenbroek 					    dgetopt, eod, eol);
976*9f20bfa6SDavid van Moolenbroek 					break;
977*9f20bfa6SDavid van Moolenbroek 				}
978*9f20bfa6SDavid van Moolenbroek 			}
979*9f20bfa6SDavid van Moolenbroek 			od += eos + eol;
980*9f20bfa6SDavid van Moolenbroek 			ol -= eos + eol;
981*9f20bfa6SDavid van Moolenbroek 		}
982*9f20bfa6SDavid van Moolenbroek 	}
983*9f20bfa6SDavid van Moolenbroek 
984*9f20bfa6SDavid van Moolenbroek out:
985*9f20bfa6SDavid van Moolenbroek 	if (env)
986*9f20bfa6SDavid van Moolenbroek 		free(pfx);
987*9f20bfa6SDavid van Moolenbroek 
988*9f20bfa6SDavid van Moolenbroek 	/* Return number of options found */
989*9f20bfa6SDavid van Moolenbroek 	return n;
990*9f20bfa6SDavid van Moolenbroek }
991*9f20bfa6SDavid van Moolenbroek 
992*9f20bfa6SDavid van Moolenbroek void
dhcp_zero_index(struct dhcp_opt * opt)993*9f20bfa6SDavid van Moolenbroek dhcp_zero_index(struct dhcp_opt *opt)
994*9f20bfa6SDavid van Moolenbroek {
995*9f20bfa6SDavid van Moolenbroek 	size_t i;
996*9f20bfa6SDavid van Moolenbroek 	struct dhcp_opt *o;
997*9f20bfa6SDavid van Moolenbroek 
998*9f20bfa6SDavid van Moolenbroek 	opt->index = 0;
999*9f20bfa6SDavid van Moolenbroek 	for (i = 0, o = opt->embopts; i < opt->embopts_len; i++, o++)
1000*9f20bfa6SDavid van Moolenbroek 		dhcp_zero_index(o);
1001*9f20bfa6SDavid van Moolenbroek 	for (i = 0, o = opt->encopts; i < opt->encopts_len; i++, o++)
1002*9f20bfa6SDavid van Moolenbroek 		dhcp_zero_index(o);
1003*9f20bfa6SDavid van Moolenbroek }
1004