etc/protocols - sync with NetBSD-8
[minix.git] / external / bsd / dhcp / dist / common / options.c
blobb3a59ccf83aa576772919c36e6ed40fb7be170dd
1 /* $NetBSD: options.c,v 1.1.1.3 2014/07/12 11:57:46 spz Exp $ */
2 /* options.c
4 DHCP options parsing and reassembly. */
6 /*
7 * Copyright (c) 2004-2012,2014 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 1995-2003 by Internet Software Consortium
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 * Internet Systems Consortium, Inc.
23 * 950 Charter Street
24 * Redwood City, CA 94063
25 * <info@isc.org>
26 * https://www.isc.org/
30 #include <sys/cdefs.h>
31 __RCSID("$NetBSD: options.c,v 1.1.1.3 2014/07/12 11:57:46 spz Exp $");
33 #define DHCP_OPTION_DATA
34 #include "dhcpd.h"
35 #include <omapip/omapip_p.h>
36 #include <limits.h>
38 struct option *vendor_cfg_option;
40 static int pretty_text(char **, char *, const unsigned char **,
41 const unsigned char *, int);
42 static int pretty_domain(char **, char *, const unsigned char **,
43 const unsigned char *);
44 static int prepare_option_buffer(struct universe *universe, struct buffer *bp,
45 unsigned char *buffer, unsigned length,
46 unsigned code, int terminatep,
47 struct option_cache **opp);
49 /* Parse all available options out of the specified packet. */
51 int parse_options (packet)
52 struct packet *packet;
54 struct option_cache *op = (struct option_cache *)0;
56 /* Allocate a new option state. */
57 if (!option_state_allocate (&packet -> options, MDL)) {
58 packet -> options_valid = 0;
59 return 0;
62 /* If we don't see the magic cookie, there's nothing to parse. */
63 if (memcmp (packet -> raw -> options, DHCP_OPTIONS_COOKIE, 4)) {
64 packet -> options_valid = 0;
65 return 1;
68 /* Go through the options field, up to the end of the packet
69 or the End field. */
70 if (!parse_option_buffer (packet -> options,
71 &packet -> raw -> options [4],
72 (packet -> packet_length -
73 DHCP_FIXED_NON_UDP - 4),
74 &dhcp_universe)) {
76 /* STSN servers have a bug where they send a mangled
77 domain-name option, and whatever is beyond that in
78 the packet is junk. Microsoft clients accept this,
79 which is probably why whoever implemented the STSN
80 server isn't aware of the problem yet. To work around
81 this, we will accept corrupt packets from the server if
82 they contain a valid DHCP_MESSAGE_TYPE option, but
83 will not accept any corrupt client packets (the ISC DHCP
84 server is sufficiently widely used that it is probably
85 beneficial for it to be picky) and will not accept
86 packets whose type can't be determined. */
88 if ((op = lookup_option (&dhcp_universe, packet -> options,
89 DHO_DHCP_MESSAGE_TYPE))) {
90 if (!op -> data.data ||
91 (op -> data.data [0] != DHCPOFFER &&
92 op -> data.data [0] != DHCPACK &&
93 op -> data.data [0] != DHCPNAK))
94 return 0;
95 } else
96 return 0;
99 /* If we parsed a DHCP Option Overload option, parse more
100 options out of the buffer(s) containing them. */
101 if ((op = lookup_option (&dhcp_universe, packet -> options,
102 DHO_DHCP_OPTION_OVERLOAD))) {
103 if (op -> data.data [0] & 1) {
104 if (!parse_option_buffer
105 (packet -> options,
106 (unsigned char *)packet -> raw -> file,
107 sizeof packet -> raw -> file,
108 &dhcp_universe))
109 return 0;
111 if (op -> data.data [0] & 2) {
112 if (!parse_option_buffer
113 (packet -> options,
114 (unsigned char *)packet -> raw -> sname,
115 sizeof packet -> raw -> sname,
116 &dhcp_universe))
117 return 0;
120 packet -> options_valid = 1;
121 return 1;
124 /* Parse options out of the specified buffer, storing addresses of option
125 * values in packet->options.
127 int parse_option_buffer (options, buffer, length, universe)
128 struct option_state *options;
129 const unsigned char *buffer;
130 unsigned length;
131 struct universe *universe;
133 unsigned len, offset;
134 unsigned code;
135 struct option_cache *op = NULL, *nop = NULL;
136 struct buffer *bp = (struct buffer *)0;
137 struct option *option = NULL;
138 char *reason = "general failure";
140 if (!buffer_allocate (&bp, length, MDL)) {
141 log_error ("no memory for option buffer.");
142 return 0;
144 memcpy (bp -> data, buffer, length);
146 for (offset = 0;
147 (offset + universe->tag_size) <= length &&
148 (code = universe->get_tag(buffer + offset)) != universe->end; ) {
149 offset += universe->tag_size;
151 /* Pad options don't have a length - just skip them. */
152 if (code == DHO_PAD)
153 continue;
155 /* Don't look for length if the buffer isn't that big. */
156 if ((offset + universe->length_size) > length) {
157 reason = "code tag at end of buffer - missing "
158 "length field";
159 goto bogus;
162 /* All other fields (except PAD and END handled above)
163 * have a length field, unless it's a DHCPv6 zero-length
164 * options space (eg any of the enterprise-id'd options).
166 * Zero-length-size option spaces basically consume the
167 * entire options buffer, so have at it.
169 if (universe->get_length != NULL)
170 len = universe->get_length(buffer + offset);
171 else if (universe->length_size == 0)
172 len = length - universe->tag_size;
173 else {
174 log_fatal("Improperly configured option space(%s): "
175 "may not have a nonzero length size "
176 "AND a NULL get_length function.",
177 universe->name);
179 /* Silence compiler warnings. */
180 return 0;
183 offset += universe->length_size;
185 option_code_hash_lookup(&option, universe->code_hash, &code,
186 0, MDL);
188 /* If the length is outrageous, the options are bad. */
189 if (offset + len > length) {
190 reason = "option length exceeds option buffer length";
191 bogus:
192 log_error("parse_option_buffer: malformed option "
193 "%s.%s (code %u): %s.", universe->name,
194 option ? option->name : "<unknown>",
195 code, reason);
196 buffer_dereference (&bp, MDL);
197 return 0;
200 /* If the option contains an encapsulation, parse it. If
201 the parse fails, or the option isn't an encapsulation (by
202 far the most common case), or the option isn't entirely
203 an encapsulation, keep the raw data as well. */
204 if (!(option &&
205 (option->format[0] == 'e' ||
206 option->format[0] == 'E') &&
207 (parse_encapsulated_suboptions(options, option,
208 bp->data + offset, len,
209 universe, NULL)))) {
210 op = lookup_option(universe, options, code);
212 if (op != NULL && universe->concat_duplicates) {
213 struct data_string new;
214 memset(&new, 0, sizeof new);
215 if (!buffer_allocate(&new.buffer,
216 op->data.len + len,
217 MDL)) {
218 log_error("parse_option_buffer: "
219 "No memory.");
220 buffer_dereference(&bp, MDL);
221 return 0;
223 /* Copy old option to new data object. */
224 memcpy(new.buffer->data, op->data.data,
225 op->data.len);
226 /* Concat new option behind old. */
227 memcpy(new.buffer->data + op->data.len,
228 bp->data + offset, len);
229 new.len = op->data.len + len;
230 new.data = new.buffer->data;
231 /* Save new concat'd object. */
232 data_string_forget(&op->data, MDL);
233 data_string_copy(&op->data, &new, MDL);
234 data_string_forget(&new, MDL);
235 } else if (op != NULL) {
236 /* We must append this statement onto the
237 * end of the list.
239 while (op->next != NULL)
240 op = op->next;
242 if (!option_cache_allocate(&nop, MDL)) {
243 log_error("parse_option_buffer: "
244 "No memory.");
245 buffer_dereference(&bp, MDL);
246 return 0;
249 option_reference(&nop->option, op->option, MDL);
251 nop->data.buffer = NULL;
252 buffer_reference(&nop->data.buffer, bp, MDL);
253 nop->data.data = bp->data + offset;
254 nop->data.len = len;
256 option_cache_reference(&op->next, nop, MDL);
257 option_cache_dereference(&nop, MDL);
258 } else {
259 if (save_option_buffer(universe, options, bp,
260 bp->data + offset, len,
261 code, 1) == 0) {
262 log_error("parse_option_buffer: "
263 "save_option_buffer failed");
264 buffer_dereference(&bp, MDL);
265 return 0;
269 option_dereference(&option, MDL);
270 offset += len;
272 buffer_dereference (&bp, MDL);
273 return 1;
276 /* If an option in an option buffer turns out to be an encapsulation,
277 figure out what to do. If we don't know how to de-encapsulate it,
278 or it's not well-formed, return zero; otherwise, return 1, indicating
279 that we succeeded in de-encapsulating it. */
281 struct universe *find_option_universe (struct option *eopt, const char *uname)
283 int i;
284 char *s, *t;
285 struct universe *universe = (struct universe *)0;
287 /* Look for the E option in the option format. */
288 s = strchr (eopt -> format, 'E');
289 if (!s) {
290 log_error ("internal encapsulation format error 1.");
291 return 0;
293 /* Look for the universe name in the option format. */
294 t = strchr (++s, '.');
295 /* If there was no trailing '.', or there's something after the
296 trailing '.', the option is bogus and we can't use it. */
297 if (!t || t [1]) {
298 log_error ("internal encapsulation format error 2.");
299 return 0;
301 if (t == s && uname) {
302 for (i = 0; i < universe_count; i++) {
303 if (!strcmp (universes [i] -> name, uname)) {
304 universe = universes [i];
305 break;
308 } else if (t != s) {
309 for (i = 0; i < universe_count; i++) {
310 if (strlen (universes [i] -> name) == t - s &&
311 !memcmp (universes [i] -> name,
312 s, (unsigned)(t - s))) {
313 universe = universes [i];
314 break;
318 return universe;
321 /* If an option in an option buffer turns out to be an encapsulation,
322 figure out what to do. If we don't know how to de-encapsulate it,
323 or it's not well-formed, return zero; otherwise, return 1, indicating
324 that we succeeded in de-encapsulating it. */
326 int parse_encapsulated_suboptions (struct option_state *options,
327 struct option *eopt,
328 const unsigned char *buffer,
329 unsigned len, struct universe *eu,
330 const char *uname)
332 int i;
333 struct universe *universe = find_option_universe (eopt, uname);
335 /* If we didn't find the universe, we can't do anything with it
336 right now (e.g., we can't decode vendor options until we've
337 decoded the packet and executed the scopes that it matches). */
338 if (!universe)
339 return 0;
341 /* If we don't have a decoding function for it, we can't decode
342 it. */
343 if (!universe -> decode)
344 return 0;
346 i = (*universe -> decode) (options, buffer, len, universe);
348 /* If there is stuff before the suboptions, we have to keep it. */
349 if (eopt -> format [0] != 'E')
350 return 0;
351 /* Otherwise, return the status of the decode function. */
352 return i;
355 int fqdn_universe_decode (struct option_state *options,
356 const unsigned char *buffer,
357 unsigned length, struct universe *u)
359 struct buffer *bp = (struct buffer *)0;
361 /* FQDN options have to be at least four bytes long. */
362 if (length < 3)
363 return 0;
365 /* Save the contents of the option in a buffer. */
366 if (!buffer_allocate (&bp, length + 4, MDL)) {
367 log_error ("no memory for option buffer.");
368 return 0;
370 memcpy (&bp -> data [3], buffer + 1, length - 1);
372 if (buffer [0] & 4) /* encoded */
373 bp -> data [0] = 1;
374 else
375 bp -> data [0] = 0;
376 if (!save_option_buffer(&fqdn_universe, options, bp,
377 bp->data, 1, FQDN_ENCODED, 0)) {
378 bad:
379 buffer_dereference (&bp, MDL);
380 return 0;
383 if (buffer [0] & 1) /* server-update */
384 bp -> data [2] = 1;
385 else
386 bp -> data [2] = 0;
387 if (buffer [0] & 2) /* no-client-update */
388 bp -> data [1] = 1;
389 else
390 bp -> data [1] = 0;
392 /* XXX Ideally we should store the name in DNS format, so if the
393 XXX label isn't in DNS format, we convert it to DNS format,
394 XXX rather than converting labels specified in DNS format to
395 XXX the plain ASCII representation. But that's hard, so
396 XXX not now. */
398 /* Not encoded using DNS format? */
399 if (!bp -> data [0]) {
400 unsigned i;
402 /* Some broken clients NUL-terminate this option. */
403 if (buffer [length - 1] == 0) {
404 --length;
405 bp -> data [1] = 1;
408 /* Determine the length of the hostname component of the
409 name. If the name contains no '.' character, it
410 represents a non-qualified label. */
411 for (i = 3; i < length && buffer [i] != '.'; i++);
412 i -= 3;
414 /* Note: If the client sends a FQDN, the first '.' will
415 be used as a NUL terminator for the hostname. */
416 if (i && (!save_option_buffer(&fqdn_universe, options, bp,
417 &bp->data[5], i,
418 FQDN_HOSTNAME, 0)))
419 goto bad;
420 /* Note: If the client sends a single label, the
421 FQDN_DOMAINNAME option won't be set. */
422 if (length > 4 + i &&
423 (!save_option_buffer(&fqdn_universe, options, bp,
424 &bp -> data[6 + i], length - 4 - i,
425 FQDN_DOMAINNAME, 1)))
426 goto bad;
427 /* Also save the whole name. */
428 if (length > 3) {
429 if (!save_option_buffer(&fqdn_universe, options, bp,
430 &bp -> data [5], length - 3,
431 FQDN_FQDN, 1))
432 goto bad;
434 } else {
435 unsigned len;
436 unsigned total_len = 0;
437 unsigned first_len = 0;
438 int terminated = 0;
439 unsigned char *s;
441 s = &bp -> data[5];
443 while (s < &bp -> data[0] + length + 2) {
444 len = *s;
445 if (len > 63) {
446 log_info ("fancy bits in fqdn option");
447 return 0;
449 if (len == 0) {
450 terminated = 1;
451 break;
453 if (s + len > &bp -> data [0] + length + 3) {
454 log_info ("fqdn tag longer than buffer");
455 return 0;
458 if (first_len == 0) {
459 first_len = len;
462 *s = '.';
463 s += len + 1;
464 total_len += len + 1;
467 /* We wind up with a length that's one too many because
468 we shouldn't increment for the last label, but there's
469 no way to tell we're at the last label until we exit
470 the loop. :'*/
471 if (total_len > 0)
472 total_len--;
474 if (!terminated) {
475 first_len = total_len;
478 if (first_len > 0 &&
479 !save_option_buffer(&fqdn_universe, options, bp,
480 &bp -> data[6], first_len,
481 FQDN_HOSTNAME, 0))
482 goto bad;
483 if (total_len > 0 && first_len != total_len) {
484 if (!save_option_buffer(&fqdn_universe, options, bp,
485 &bp->data[6 + first_len],
486 total_len - first_len,
487 FQDN_DOMAINNAME, 1))
488 goto bad;
490 if (total_len > 0)
491 if (!save_option_buffer (&fqdn_universe, options, bp,
492 &bp -> data [6], total_len,
493 FQDN_FQDN, 1))
494 goto bad;
497 if (!save_option_buffer (&fqdn_universe, options, bp,
498 &bp -> data [1], 1,
499 FQDN_NO_CLIENT_UPDATE, 0))
500 goto bad;
501 if (!save_option_buffer (&fqdn_universe, options, bp,
502 &bp -> data [2], 1,
503 FQDN_SERVER_UPDATE, 0))
504 goto bad;
506 if (!save_option_buffer (&fqdn_universe, options, bp,
507 &bp -> data [3], 1,
508 FQDN_RCODE1, 0))
509 goto bad;
510 if (!save_option_buffer (&fqdn_universe, options, bp,
511 &bp -> data [4], 1,
512 FQDN_RCODE2, 0))
513 goto bad;
515 buffer_dereference (&bp, MDL);
516 return 1;
520 * Load all options into a buffer, and then split them out into the three
521 * separate fields in the dhcp packet (options, file, and sname) where
522 * options can be stored.
524 * returns 0 on error, length of packet on success
527 cons_options(struct packet *inpacket, struct dhcp_packet *outpacket,
528 struct lease *lease, struct client_state *client_state,
529 int mms, struct option_state *in_options,
530 struct option_state *cfg_options,
531 struct binding_scope **scope,
532 int overload_avail, int terminate, int bootpp,
533 struct data_string *prl, const char *vuname)
535 #define PRIORITY_COUNT 300
536 unsigned priority_list[PRIORITY_COUNT];
537 int priority_len;
538 unsigned char buffer[4096], agentopts[1024];
539 unsigned index = 0;
540 unsigned mb_size = 0, mb_max = 0;
541 unsigned option_size = 0, agent_size = 0;
542 unsigned length;
543 int i;
544 struct option_cache *op;
545 struct data_string ds;
546 pair pp, *hash;
547 int overload_used = 0;
548 int of1 = 0, of2 = 0;
550 memset(&ds, 0, sizeof ds);
553 * If there's a Maximum Message Size option in the incoming packet
554 * and no alternate maximum message size has been specified, or
555 * if the one specified in the packet is shorter than the
556 * alternative, take the one in the packet.
559 if (inpacket &&
560 (op = lookup_option(&dhcp_universe, inpacket->options,
561 DHO_DHCP_MAX_MESSAGE_SIZE)) &&
562 (evaluate_option_cache(&ds, inpacket, lease,
563 client_state, in_options,
564 cfg_options, scope, op, MDL) != 0)) {
565 if (ds.len >= sizeof (u_int16_t)) {
566 i = getUShort(ds.data);
567 if(!mms || (i < mms))
568 mms = i;
570 data_string_forget(&ds, MDL);
574 * If the client has provided a maximum DHCP message size,
575 * use that, up to the MTU limit. Otherwise, if it's BOOTP,
576 * only 64 bytes; otherwise use up to the minimum IP MTU size
577 * (576 bytes).
579 * XXX if a BOOTP client specifies a max message size, we will
580 * honor it.
582 if (mms) {
583 if (mms < DHCP_MTU_MIN)
584 /* Enforce minimum packet size, per RFC 2132 */
585 mb_size = DHCP_MIN_OPTION_LEN;
586 else if (mms > DHCP_MTU_MAX)
588 * TODO: Packets longer than 1500 bytes really
589 * should be allowed, but it requires upstream
590 * changes to the way the packet is allocated. For
591 * now, we forbid them. They won't be needed very
592 * often anyway.
594 mb_size = DHCP_MAX_OPTION_LEN;
595 else
596 mb_size = mms - DHCP_FIXED_LEN;
597 } else if (bootpp) {
598 mb_size = 64;
599 if (inpacket != NULL &&
600 (inpacket->packet_length >= 64 + DHCP_FIXED_NON_UDP))
601 mb_size = inpacket->packet_length - DHCP_FIXED_NON_UDP;
602 } else
603 mb_size = DHCP_MIN_OPTION_LEN;
606 * If answering a client message, see whether any relay agent
607 * options were included with the message. If so, save them
608 * to copy back in later, and make space in the main buffer
609 * to accommodate them
611 if (client_state == NULL) {
612 priority_list[0] = DHO_DHCP_AGENT_OPTIONS;
613 priority_len = 1;
614 agent_size = store_options(NULL, agentopts, 0,
615 sizeof(agentopts),
616 inpacket, lease, client_state,
617 in_options, cfg_options, scope,
618 priority_list, priority_len,
619 0, 0, 0, NULL);
621 mb_size += agent_size;
622 if (mb_size > DHCP_MAX_OPTION_LEN)
623 mb_size = DHCP_MAX_OPTION_LEN;
627 * Set offsets for buffer data to be copied into filename
628 * and servername fields
630 mb_max = mb_size;
632 if (overload_avail & 1) {
633 of1 = mb_max;
634 mb_max += DHCP_FILE_LEN;
637 if (overload_avail & 2) {
638 of2 = mb_max;
639 mb_max += DHCP_SNAME_LEN;
643 * Preload the option priority list with protocol-mandatory options.
644 * This effectively gives these options the highest priority.
645 * This provides the order for any available options, the option
646 * must be in the option cache in order to actually be included.
648 priority_len = 0;
649 priority_list[priority_len++] = DHO_DHCP_MESSAGE_TYPE;
650 priority_list[priority_len++] = DHO_DHCP_SERVER_IDENTIFIER;
651 priority_list[priority_len++] = DHO_DHCP_LEASE_TIME;
652 priority_list[priority_len++] = DHO_DHCP_RENEWAL_TIME;
653 priority_list[priority_len++] = DHO_DHCP_REBINDING_TIME;
654 priority_list[priority_len++] = DHO_DHCP_MESSAGE;
655 priority_list[priority_len++] = DHO_DHCP_REQUESTED_ADDRESS;
656 priority_list[priority_len++] = DHO_ASSOCIATED_IP;
658 if (prl != NULL && prl->len > 0) {
659 if ((op = lookup_option(&dhcp_universe, cfg_options,
660 DHO_SUBNET_SELECTION))) {
661 if (priority_len < PRIORITY_COUNT)
662 priority_list[priority_len++] =
663 DHO_SUBNET_SELECTION;
666 data_string_truncate(prl, (PRIORITY_COUNT - priority_len));
669 * Copy the client's PRL onto the priority_list after our high
670 * priority header.
672 for (i = 0; i < prl->len; i++) {
674 * Prevent client from changing order of delivery
675 * of relay agent information option.
677 if (prl->data[i] != DHO_DHCP_AGENT_OPTIONS)
678 priority_list[priority_len++] = prl->data[i];
682 * If the client doesn't request the FQDN option explicitly,
683 * to indicate priority, consider it lowest priority. Fit
684 * in the packet if there is space. Note that the option
685 * may only be included if the client supplied one.
687 if ((inpacket != NULL) && (priority_len < PRIORITY_COUNT) &&
688 (lookup_option(&fqdn_universe, inpacket->options,
689 FQDN_ENCODED) != NULL))
690 priority_list[priority_len++] = DHO_FQDN;
693 * Some DHCP Servers will give the subnet-mask option if
694 * it is not on the parameter request list - so some client
695 * implementations have come to rely on this - so we will
696 * also make sure we supply this, at lowest priority.
698 * This is only done in response to DHCPDISCOVER or
699 * DHCPREQUEST messages, to avoid providing the option on
700 * DHCPINFORM or DHCPLEASEQUERY responses (if the client
701 * didn't request it).
703 if ((inpacket != NULL) && (priority_len < PRIORITY_COUNT) &&
704 ((inpacket->packet_type == DHCPDISCOVER) ||
705 (inpacket->packet_type == DHCPREQUEST)))
706 priority_list[priority_len++] = DHO_SUBNET_MASK;
707 } else {
709 * First, hardcode some more options that ought to be
710 * sent first...these are high priority to have in the
711 * packet.
713 priority_list[priority_len++] = DHO_SUBNET_MASK;
714 priority_list[priority_len++] = DHO_ROUTERS;
715 priority_list[priority_len++] = DHO_DOMAIN_NAME_SERVERS;
716 priority_list[priority_len++] = DHO_HOST_NAME;
717 priority_list[priority_len++] = DHO_FQDN;
720 * Append a list of the standard DHCP options from the
721 * standard DHCP option space. Actually, if a site
722 * option space hasn't been specified, we wind up
723 * treating the dhcp option space as the site option
724 * space, and the first for loop is skipped, because
725 * it's slightly more general to do it this way,
726 * taking the 1Q99 DHCP futures work into account.
728 if (cfg_options->site_code_min) {
729 for (i = 0; i < OPTION_HASH_SIZE; i++) {
730 hash = cfg_options->universes[dhcp_universe.index];
731 if (hash) {
732 for (pp = hash[i]; pp; pp = pp->cdr) {
733 op = (struct option_cache *)(pp->car);
734 if (op->option->code <
735 cfg_options->site_code_min &&
736 priority_len < PRIORITY_COUNT &&
737 op->option->code != DHO_DHCP_AGENT_OPTIONS)
738 priority_list[priority_len++] =
739 op->option->code;
746 * Now cycle through the site option space, or if there
747 * is no site option space, we'll be cycling through the
748 * dhcp option space.
750 for (i = 0; i < OPTION_HASH_SIZE; i++) {
751 hash = cfg_options->universes[cfg_options->site_universe];
752 if (hash != NULL)
753 for (pp = hash[i]; pp; pp = pp->cdr) {
754 op = (struct option_cache *)(pp->car);
755 if (op->option->code >=
756 cfg_options->site_code_min &&
757 priority_len < PRIORITY_COUNT &&
758 op->option->code != DHO_DHCP_AGENT_OPTIONS)
759 priority_list[priority_len++] =
760 op->option->code;
765 * Put any spaces that are encapsulated on the list,
766 * sort out whether they contain values later.
768 for (i = 0; i < cfg_options->universe_count; i++) {
769 if (universes[i]->enc_opt &&
770 priority_len < PRIORITY_COUNT &&
771 universes[i]->enc_opt->universe == &dhcp_universe) {
772 if (universes[i]->enc_opt->code !=
773 DHO_DHCP_AGENT_OPTIONS)
774 priority_list[priority_len++] =
775 universes[i]->enc_opt->code;
780 * The vendor option space can't stand on its own, so always
781 * add it to the list.
783 if (priority_len < PRIORITY_COUNT)
784 priority_list[priority_len++] =
785 DHO_VENDOR_ENCAPSULATED_OPTIONS;
788 /* Put the cookie up front... */
789 memcpy(buffer, DHCP_OPTIONS_COOKIE, 4);
790 index += 4;
792 /* Copy the options into the big buffer... */
793 option_size = store_options(&overload_used, buffer, index, mb_max,
794 inpacket, lease, client_state,
795 in_options, cfg_options, scope,
796 priority_list, priority_len,
797 of1, of2, terminate, vuname);
799 /* If store_options() failed */
800 if (option_size == 0)
801 return 0;
803 /* How much was stored in the main buffer? */
804 index += option_size;
807 * If we're going to have to overload, store the overload
808 * option first.
810 if (overload_used) {
811 if (mb_size - agent_size - index < 3)
812 return 0;
814 buffer[index++] = DHO_DHCP_OPTION_OVERLOAD;
815 buffer[index++] = 1;
816 buffer[index++] = overload_used;
818 if (overload_used & 1)
819 memcpy(outpacket->file, &buffer[of1], DHCP_FILE_LEN);
821 if (overload_used & 2)
822 memcpy(outpacket->sname, &buffer[of2], DHCP_SNAME_LEN);
825 /* Now copy in preserved agent options, if any */
826 if (agent_size) {
827 if (mb_size - index >= agent_size) {
828 memcpy(&buffer[index], agentopts, agent_size);
829 index += agent_size;
830 } else
831 log_error("Unable to store relay agent information "
832 "in reply packet.");
835 /* Tack a DHO_END option onto the packet if we need to. */
836 if (index < mb_size)
837 buffer[index++] = DHO_END;
839 /* Copy main buffer into the options buffer of the packet */
840 memcpy(outpacket->options, buffer, index);
842 /* Figure out the length. */
843 length = DHCP_FIXED_NON_UDP + index;
844 return length;
848 * XXX: We currently special case collecting VSIO options.
849 * We should be able to handle this in a more generic fashion, by
850 * including any encapsulated options that are present and desired.
851 * This will look something like the VSIO handling VSIO code.
852 * We may also consider handling the ORO-like options within
853 * encapsulated spaces.
856 struct vsio_state {
857 char *buf;
858 int buflen;
859 int bufpos;
862 static void
863 vsio_options(struct option_cache *oc,
864 struct packet *packet,
865 struct lease *dummy_lease,
866 struct client_state *dummy_client_state,
867 struct option_state *dummy_opt_state,
868 struct option_state *opt_state,
869 struct binding_scope **dummy_binding_scope,
870 struct universe *universe,
871 void *void_vsio_state) {
872 struct vsio_state *vs = (struct vsio_state *)void_vsio_state;
873 struct data_string ds;
874 int total_len;
876 memset(&ds, 0, sizeof(ds));
877 if (evaluate_option_cache(&ds, packet, NULL,
878 NULL, opt_state, NULL,
879 &global_scope, oc, MDL)) {
880 total_len = ds.len + universe->tag_size + universe->length_size;
881 if (total_len <= (vs->buflen - vs->bufpos)) {
882 if (universe->tag_size == 1) {
883 vs->buf[vs->bufpos++] = oc->option->code;
884 } else if (universe->tag_size == 2) {
885 putUShort((unsigned char *)vs->buf+vs->bufpos,
886 oc->option->code);
887 vs->bufpos += 2;
888 } else if (universe->tag_size == 4) {
889 putULong((unsigned char *)vs->buf+vs->bufpos,
890 oc->option->code);
891 vs->bufpos += 4;
893 if (universe->length_size == 1) {
894 vs->buf[vs->bufpos++] = ds.len;
895 } else if (universe->length_size == 2) {
896 putUShort((unsigned char *)vs->buf+vs->bufpos,
897 ds.len);
898 vs->bufpos += 2;
899 } else if (universe->length_size == 4) {
900 putULong((unsigned char *)vs->buf+vs->bufpos,
901 ds.len);
902 vs->bufpos += 4;
904 memcpy(vs->buf + vs->bufpos, ds.data, ds.len);
905 vs->bufpos += ds.len;
906 } else {
907 log_debug("No space for option %d in VSIO space %s.",
908 oc->option->code, universe->name);
910 data_string_forget(&ds, MDL);
911 } else {
912 log_error("Error evaluating option %d in VSIO space %s.",
913 oc->option->code, universe->name);
918 * Stores the options from the DHCPv6 universe into the buffer given.
920 * Required options are given as a 0-terminated list of option codes.
921 * Once those are added, the ORO is consulted.
925 store_options6(char *buf, int buflen,
926 struct option_state *opt_state,
927 struct packet *packet,
928 const int *required_opts,
929 struct data_string *oro) {
930 int i, j;
931 struct option_cache *oc;
932 struct option *o;
933 struct data_string ds;
934 int bufpos;
935 int oro_size;
936 u_int16_t code;
937 int in_required_opts;
938 int vsio_option_code;
939 int vsio_wanted;
940 struct vsio_state vs;
941 unsigned char *tmp;
943 bufpos = 0;
944 vsio_wanted = 0;
947 * Find the option code for the VSIO universe.
949 vsio_option_code = 0;
950 o = vsio_universe.enc_opt;
951 while (o != NULL) {
952 if (o->universe == &dhcpv6_universe) {
953 vsio_option_code = o->code;
954 break;
956 o = o->universe->enc_opt;
958 if (vsio_option_code == 0) {
959 log_fatal("No VSIO option code found.");
962 if (required_opts != NULL) {
963 for (i=0; required_opts[i] != 0; i++) {
964 if (required_opts[i] == vsio_option_code) {
965 vsio_wanted = 1;
968 oc = lookup_option(&dhcpv6_universe,
969 opt_state, required_opts[i]);
970 if (oc == NULL) {
971 continue;
973 memset(&ds, 0, sizeof(ds));
974 for (; oc != NULL ; oc = oc->next) {
975 if (evaluate_option_cache(&ds, packet, NULL,
976 NULL, opt_state,
977 NULL, &global_scope,
978 oc, MDL)) {
979 if ((ds.len + 4) <=
980 (buflen - bufpos)) {
981 tmp = (unsigned char *)buf;
982 tmp += bufpos;
983 /* option tag */
984 putUShort(tmp,
985 required_opts[i]);
986 /* option length */
987 putUShort(tmp+2, ds.len);
988 /* option data */
989 memcpy(tmp+4, ds.data, ds.len);
990 /* update position */
991 bufpos += (4 + ds.len);
992 } else {
993 log_debug("No space for "
994 "option %d",
995 required_opts[i]);
997 data_string_forget(&ds, MDL);
998 } else {
999 log_error("Error evaluating option %d",
1000 required_opts[i]);
1006 if (oro == NULL) {
1007 oro_size = 0;
1008 } else {
1009 oro_size = oro->len / 2;
1011 for (i=0; i<oro_size; i++) {
1012 memcpy(&code, oro->data+(i*2), 2);
1013 code = ntohs(code);
1016 * See if we've already included this option because
1017 * it is required.
1019 in_required_opts = 0;
1020 if (required_opts != NULL) {
1021 for (j=0; required_opts[j] != 0; j++) {
1022 if (required_opts[j] == code) {
1023 in_required_opts = 1;
1024 break;
1028 if (in_required_opts) {
1029 continue;
1033 * See if this is the VSIO option.
1035 if (code == vsio_option_code) {
1036 vsio_wanted = 1;
1040 * Not already added, find this option.
1042 oc = lookup_option(&dhcpv6_universe, opt_state, code);
1043 memset(&ds, 0, sizeof(ds));
1044 for (; oc != NULL ; oc = oc->next) {
1045 if (evaluate_option_cache(&ds, packet, NULL, NULL,
1046 opt_state, NULL,
1047 &global_scope, oc, MDL)) {
1048 if ((ds.len + 4) <= (buflen - bufpos)) {
1049 tmp = (unsigned char *)buf + bufpos;
1050 /* option tag */
1051 putUShort(tmp, code);
1052 /* option length */
1053 putUShort(tmp+2, ds.len);
1054 /* option data */
1055 memcpy(tmp+4, ds.data, ds.len);
1056 /* update position */
1057 bufpos += (4 + ds.len);
1058 } else {
1059 log_debug("No space for option %d",
1060 code);
1062 data_string_forget(&ds, MDL);
1063 } else {
1064 log_error("Error evaluating option %d", code);
1069 if (vsio_wanted) {
1070 for (i=0; i < opt_state->universe_count; i++) {
1071 if (opt_state->universes[i] != NULL) {
1072 o = universes[i]->enc_opt;
1073 if ((o != NULL) &&
1074 (o->universe == &vsio_universe)) {
1076 * Add the data from this VSIO option.
1078 vs.buf = buf;
1079 vs.buflen = buflen;
1080 vs.bufpos = bufpos+8;
1081 option_space_foreach(packet, NULL,
1082 NULL,
1083 NULL, opt_state,
1084 NULL,
1085 universes[i],
1086 (void *)&vs,
1087 vsio_options);
1090 * If there was actually data here,
1091 * add the "header".
1093 if (vs.bufpos > bufpos+8) {
1094 tmp = (unsigned char *)buf +
1095 bufpos;
1096 putUShort(tmp,
1097 vsio_option_code);
1098 putUShort(tmp+2,
1099 vs.bufpos-bufpos-4);
1100 putULong(tmp+4, o->code);
1102 bufpos = vs.bufpos;
1109 return bufpos;
1113 * Store all the requested options into the requested buffer.
1114 * XXX: ought to be static
1117 store_options(int *ocount,
1118 unsigned char *buffer, unsigned index, unsigned buflen,
1119 struct packet *packet, struct lease *lease,
1120 struct client_state *client_state,
1121 struct option_state *in_options,
1122 struct option_state *cfg_options,
1123 struct binding_scope **scope,
1124 unsigned *priority_list, int priority_len,
1125 unsigned first_cutoff, int second_cutoff, int terminate,
1126 const char *vuname)
1128 int bufix = 0, six = 0, tix = 0;
1129 int i;
1130 int ix;
1131 int tto;
1132 int bufend, sbufend;
1133 struct data_string od;
1134 struct option_cache *oc;
1135 struct option *option = NULL;
1136 unsigned code;
1139 * These arguments are relative to the start of the buffer, so
1140 * reduce them by the current buffer index, and advance the
1141 * buffer pointer to where we're going to start writing.
1143 buffer = &buffer[index];
1144 buflen -= index;
1145 if (first_cutoff)
1146 first_cutoff -= index;
1147 if (second_cutoff)
1148 second_cutoff -= index;
1150 /* Calculate the start and end of each section of the buffer */
1151 bufend = sbufend = buflen;
1152 if (first_cutoff) {
1153 if (first_cutoff >= buflen)
1154 log_fatal("%s:%d:store_options: Invalid first cutoff.", MDL);
1155 bufend = first_cutoff;
1157 if (second_cutoff) {
1158 if (second_cutoff >= buflen)
1159 log_fatal("%s:%d:store_options: Invalid second cutoff.",
1160 MDL);
1161 sbufend = second_cutoff;
1163 } else if (second_cutoff) {
1164 if (second_cutoff >= buflen)
1165 log_fatal("%s:%d:store_options: Invalid second cutoff.", MDL);
1166 bufend = second_cutoff;
1169 memset (&od, 0, sizeof od);
1171 /* Eliminate duplicate options from the parameter request list.
1172 * Enforce RFC-mandated ordering of options that are present.
1174 for (i = 0; i < priority_len - 1; i++) {
1175 /* Eliminate duplicates. */
1176 tto = 0;
1177 for (ix = i + 1; ix < priority_len + tto; ix++) {
1178 if (tto)
1179 priority_list [ix - tto] =
1180 priority_list [ix];
1181 if (priority_list [i] == priority_list [ix]) {
1182 tto++;
1183 priority_len--;
1187 /* Enforce ordering of SUBNET_MASK options, according to
1188 * RFC2132 Section 3.3:
1190 * If both the subnet mask and the router option are
1191 * specified in a DHCP reply, the subnet mask option MUST
1192 * be first.
1194 * This guidance does not specify what to do if the client
1195 * PRL explicitly requests the options out of order, it is
1196 * a general statement.
1198 if (priority_list[i] == DHO_SUBNET_MASK) {
1199 for (ix = i - 1 ; ix >= 0 ; ix--) {
1200 if (priority_list[ix] == DHO_ROUTERS) {
1201 /* swap */
1202 priority_list[ix] = DHO_SUBNET_MASK;
1203 priority_list[i] = DHO_ROUTERS;
1204 break;
1210 /* Copy out the options in the order that they appear in the
1211 priority list... */
1212 for (i = 0; i < priority_len; i++) {
1213 /* Number of bytes left to store (some may already
1214 have been stored by a previous pass). */
1215 unsigned length;
1216 int optstart, soptstart, toptstart;
1217 struct universe *u;
1218 int have_encapsulation = 0;
1219 struct data_string encapsulation;
1220 int splitup;
1222 memset (&encapsulation, 0, sizeof encapsulation);
1223 have_encapsulation = 0;
1225 if (option != NULL)
1226 option_dereference(&option, MDL);
1228 /* Code for next option to try to store. */
1229 code = priority_list [i];
1231 /* Look up the option in the site option space if the code
1232 is above the cutoff, otherwise in the DHCP option space. */
1233 if (code >= cfg_options -> site_code_min)
1234 u = universes [cfg_options -> site_universe];
1235 else
1236 u = &dhcp_universe;
1238 oc = lookup_option (u, cfg_options, code);
1240 if (oc && oc->option)
1241 option_reference(&option, oc->option, MDL);
1242 else
1243 option_code_hash_lookup(&option, u->code_hash, &code, 0, MDL);
1245 /* If it's a straight encapsulation, and the user supplied a
1246 * value for the entire option, use that. Otherwise, search
1247 * the encapsulated space.
1249 * If it's a limited encapsulation with preceding data, and the
1250 * user supplied values for the preceding bytes, search the
1251 * encapsulated space.
1253 if ((option != NULL) &&
1254 (((oc == NULL) && (option->format[0] == 'E')) ||
1255 ((oc != NULL) && (option->format[0] == 'e')))) {
1256 static char *s, *t;
1257 struct option_cache *tmp;
1258 struct data_string name;
1260 s = strchr (option->format, 'E');
1261 if (s)
1262 t = strchr (++s, '.');
1263 if (s && t) {
1264 memset (&name, 0, sizeof name);
1266 /* A zero-length universe name means the vendor
1267 option space, if one is defined. */
1268 if (t == s) {
1269 if (vendor_cfg_option) {
1270 tmp = lookup_option (vendor_cfg_option -> universe,
1271 cfg_options,
1272 vendor_cfg_option -> code);
1273 if (tmp)
1274 /* No need to check the return as we check name.len below */
1275 (void) evaluate_option_cache (&name, packet, lease,
1276 client_state,
1277 in_options,
1278 cfg_options,
1279 scope, tmp, MDL);
1280 } else if (vuname) {
1281 name.data = (unsigned char *)s;
1282 name.len = strlen (s);
1284 } else {
1285 name.data = (unsigned char *)s;
1286 name.len = t - s;
1289 /* If we found a universe, and there are options configured
1290 for that universe, try to encapsulate it. */
1291 if (name.len) {
1292 have_encapsulation =
1293 (option_space_encapsulate
1294 (&encapsulation, packet, lease, client_state,
1295 in_options, cfg_options, scope, &name));
1296 data_string_forget (&name, MDL);
1301 /* In order to avoid memory leaks, we have to get to here
1302 with any option cache that we allocated in tmp not being
1303 referenced by tmp, and whatever option cache is referenced
1304 by oc being an actual reference. lookup_option doesn't
1305 generate a reference (this needs to be fixed), so the
1306 preceding goop ensures that if we *didn't* generate a new
1307 option cache, oc still winds up holding an actual reference. */
1309 /* If no data is available for this option, skip it. */
1310 if (!oc && !have_encapsulation) {
1311 continue;
1314 /* Find the value of the option... */
1315 od.len = 0;
1316 if (oc) {
1317 /* No need to check the return as we check od.len below */
1318 (void) evaluate_option_cache (&od, packet,
1319 lease, client_state, in_options,
1320 cfg_options, scope, oc, MDL);
1322 /* If we have encapsulation for this option, and an oc
1323 * lookup succeeded, but the evaluation failed, it is
1324 * either because this is a complex atom (atoms before
1325 * E on format list) and the top half of the option is
1326 * not configured, or this is a simple encapsulated
1327 * space and the evaluator is giving us a NULL. Prefer
1328 * the evaluator's opinion over the subspace.
1330 if (!od.len) {
1331 data_string_forget (&encapsulation, MDL);
1332 data_string_forget (&od, MDL);
1333 continue;
1337 /* We should now have a constant length for the option. */
1338 length = od.len;
1339 if (have_encapsulation) {
1340 length += encapsulation.len;
1342 /* od.len can be nonzero if we got here without an
1343 * oc (cache lookup failed), but did have an encapsulated
1344 * simple encapsulation space.
1346 if (!od.len) {
1347 data_string_copy (&od, &encapsulation, MDL);
1348 data_string_forget (&encapsulation, MDL);
1349 } else {
1350 struct buffer *bp = (struct buffer *)0;
1351 if (!buffer_allocate (&bp, length, MDL)) {
1352 option_cache_dereference (&oc, MDL);
1353 data_string_forget (&od, MDL);
1354 data_string_forget (&encapsulation, MDL);
1355 continue;
1357 memcpy (&bp -> data [0], od.data, od.len);
1358 memcpy (&bp -> data [od.len], encapsulation.data,
1359 encapsulation.len);
1360 data_string_forget (&od, MDL);
1361 data_string_forget (&encapsulation, MDL);
1362 od.data = &bp -> data [0];
1363 buffer_reference (&od.buffer, bp, MDL);
1364 buffer_dereference (&bp, MDL);
1365 od.len = length;
1366 od.terminated = 0;
1370 /* Do we add a NUL? */
1371 if (terminate && option && format_has_text(option->format)) {
1372 length++;
1373 tto = 1;
1374 } else {
1375 tto = 0;
1378 /* Try to store the option. */
1380 /* If the option's length is more than 255, we must store it
1381 in multiple hunks. Store 255-byte hunks first. However,
1382 in any case, if the option data will cross a buffer
1383 boundary, split it across that boundary. */
1385 if (length > 255)
1386 splitup = 1;
1387 else
1388 splitup = 0;
1390 ix = 0;
1391 optstart = bufix;
1392 soptstart = six;
1393 toptstart = tix;
1394 while (length) {
1395 unsigned incr = length;
1396 int *pix;
1397 unsigned char *base;
1399 /* Try to fit it in the options buffer. */
1400 if (!splitup &&
1401 ((!six && !tix && (i == priority_len - 1) &&
1402 (bufix + 2 + length < bufend)) ||
1403 (bufix + 5 + length < bufend))) {
1404 base = buffer;
1405 pix = &bufix;
1406 /* Try to fit it in the second buffer. */
1407 } else if (!splitup && first_cutoff &&
1408 (first_cutoff + six + 3 + length < sbufend)) {
1409 base = &buffer[first_cutoff];
1410 pix = &six;
1411 /* Try to fit it in the third buffer. */
1412 } else if (!splitup && second_cutoff &&
1413 (second_cutoff + tix + 3 + length < buflen)) {
1414 base = &buffer[second_cutoff];
1415 pix = &tix;
1416 /* Split the option up into the remaining space. */
1417 } else {
1418 splitup = 1;
1420 /* Use any remaining options space. */
1421 if (bufix + 6 < bufend) {
1422 incr = bufend - bufix - 5;
1423 base = buffer;
1424 pix = &bufix;
1425 /* Use any remaining first_cutoff space. */
1426 } else if (first_cutoff &&
1427 (first_cutoff + six + 4 < sbufend)) {
1428 incr = sbufend - (first_cutoff + six) - 3;
1429 base = &buffer[first_cutoff];
1430 pix = &six;
1431 /* Use any remaining second_cutoff space. */
1432 } else if (second_cutoff &&
1433 (second_cutoff + tix + 4 < buflen)) {
1434 incr = buflen - (second_cutoff + tix) - 3;
1435 base = &buffer[second_cutoff];
1436 pix = &tix;
1437 /* Give up, roll back this option. */
1438 } else {
1439 bufix = optstart;
1440 six = soptstart;
1441 tix = toptstart;
1442 break;
1446 if (incr > length)
1447 incr = length;
1448 if (incr > 255)
1449 incr = 255;
1451 /* Everything looks good - copy it in! */
1452 base [*pix] = code;
1453 base [*pix + 1] = (unsigned char)incr;
1454 if (tto && incr == length) {
1455 if (incr > 1)
1456 memcpy (base + *pix + 2,
1457 od.data + ix, (unsigned)(incr - 1));
1458 base [*pix + 2 + incr - 1] = 0;
1459 } else {
1460 memcpy (base + *pix + 2,
1461 od.data + ix, (unsigned)incr);
1463 length -= incr;
1464 ix += incr;
1465 *pix += 2 + incr;
1467 data_string_forget (&od, MDL);
1470 if (option != NULL)
1471 option_dereference(&option, MDL);
1473 /* If we can overload, and we have, then PAD and END those spaces. */
1474 if (first_cutoff && six) {
1475 if ((first_cutoff + six + 1) < sbufend)
1476 memset (&buffer[first_cutoff + six + 1], DHO_PAD,
1477 sbufend - (first_cutoff + six + 1));
1478 else if (first_cutoff + six >= sbufend)
1479 log_fatal("Second buffer overflow in overloaded options.");
1481 buffer[first_cutoff + six] = DHO_END;
1482 if (ocount != NULL)
1483 *ocount |= 1; /* So that caller knows there's data there. */
1486 if (second_cutoff && tix) {
1487 if (second_cutoff + tix + 1 < buflen) {
1488 memset (&buffer[second_cutoff + tix + 1], DHO_PAD,
1489 buflen - (second_cutoff + tix + 1));
1490 } else if (second_cutoff + tix >= buflen)
1491 log_fatal("Third buffer overflow in overloaded options.");
1493 buffer[second_cutoff + tix] = DHO_END;
1494 if (ocount != NULL)
1495 *ocount |= 2; /* So that caller knows there's data there. */
1498 if ((six || tix) && (bufix + 3 > bufend))
1499 log_fatal("Not enough space for option overload option.");
1501 return bufix;
1504 /* Return true if the format string has a variable length text option
1505 * ("t"), return false otherwise.
1509 format_has_text(format)
1510 const char *format;
1512 const char *p;
1514 p = format;
1515 while (*p != '\0') {
1516 switch (*p++) {
1517 case 'd':
1518 case 't':
1519 return 1;
1521 /* These symbols are arbitrary, not fixed or
1522 * determinable length...text options with them is
1523 * invalid (whatever the case, they are never NULL
1524 * terminated).
1526 case 'A':
1527 case 'a':
1528 case 'X':
1529 case 'x':
1530 case 'D':
1531 return 0;
1533 case 'c':
1534 /* 'c' only follows 'D' atoms, and indicates that
1535 * compression may be used. If there was a 'D'
1536 * atom already, we would have returned. So this
1537 * is an error, but continue looking for 't' anyway.
1539 log_error("format_has_text(%s): 'c' atoms are illegal "
1540 "except after 'D' atoms.", format);
1541 break;
1543 /* 'E' is variable length, but not arbitrary...you
1544 * can find its length if you can find an END option.
1545 * N is (n)-byte in length but trails a name of a
1546 * space defining the enumeration values. So treat
1547 * both the same - valid, fixed-length fields.
1549 case 'E':
1550 case 'N':
1551 /* Consume the space name. */
1552 while ((*p != '\0') && (*p++ != '.'))
1554 break;
1556 default:
1557 break;
1561 return 0;
1564 /* Determine the minimum length of a DHCP option prior to any variable
1565 * or inconsistent length formats, according to its configured format
1566 * variable (and possibly from supplied option cache contents for variable
1567 * length format symbols).
1571 format_min_length(format, oc)
1572 const char *format;
1573 struct option_cache *oc;
1575 const char *p, *name;
1576 int min_len = 0;
1577 int last_size = 0;
1578 struct enumeration *espace;
1580 p = format;
1581 while (*p != '\0') {
1582 switch (*p++) {
1583 case '6': /* IPv6 Address */
1584 min_len += 16;
1585 last_size = 16;
1586 break;
1588 case 'I': /* IPv4 Address */
1589 case 'l': /* int32_t */
1590 case 'L': /* uint32_t */
1591 case 'T': /* Lease Time, uint32_t equivalent */
1592 min_len += 4;
1593 last_size = 4;
1594 break;
1596 case 's': /* int16_t */
1597 case 'S': /* uint16_t */
1598 min_len += 2;
1599 last_size = 2;
1600 break;
1602 case 'N': /* Enumeration value. */
1603 /* Consume space name. */
1604 name = p;
1605 p = strchr(p, '.');
1606 if (p == NULL)
1607 log_fatal("Corrupt format: %s", format);
1609 espace = find_enumeration(name, p - name);
1610 if (espace == NULL) {
1611 log_error("Unknown enumeration: %s", format);
1612 /* Max is safest value to return. */
1613 return INT_MAX;
1616 min_len += espace->width;
1617 last_size = espace->width;
1618 p++;
1620 break;
1622 case 'b': /* int8_t */
1623 case 'B': /* uint8_t */
1624 case 'F': /* Flag that is always true. */
1625 case 'f': /* Flag */
1626 min_len++;
1627 last_size = 1;
1628 break;
1630 case 'o': /* Last argument is optional. */
1631 min_len -= last_size;
1633 /* XXX: It MAY be possible to sense the end of an
1634 * encapsulated space, but right now this is too
1635 * hard to support. Return a safe value.
1637 case 'e': /* Encapsulation hint (there is an 'E' later). */
1638 case 'E': /* Encapsulated options. */
1639 return min_len;
1641 case 'd': /* "Domain name" */
1642 case 'D': /* "rfc1035 formatted names" */
1643 case 't': /* "ASCII Text" */
1644 case 'X': /* "ASCII or Hex Conditional */
1645 case 'x': /* "Hex" */
1646 case 'A': /* Array of all that precedes. */
1647 case 'a': /* Array of preceding symbol. */
1648 case 'Z': /* nothing. */
1649 return min_len;
1651 case 'c': /* Compress flag for D atom. */
1652 log_error("format_min_length(%s): 'c' atom is illegal "
1653 "except after 'D' atom.", format);
1654 return INT_MAX;
1656 default:
1657 /* No safe value is known. */
1658 log_error("format_min_length(%s): No safe value "
1659 "for unknown format symbols.", format);
1660 return INT_MAX;
1664 return min_len;
1668 /* Format the specified option so that a human can easily read it. */
1670 const char *pretty_print_option (option, data, len, emit_commas, emit_quotes)
1671 struct option *option;
1672 const unsigned char *data;
1673 unsigned len;
1674 int emit_commas;
1675 int emit_quotes;
1677 static char optbuf [32768]; /* XXX */
1678 static char *endbuf = &optbuf[sizeof(optbuf)];
1679 int hunksize = 0;
1680 int opthunk = 0;
1681 int hunkinc = 0;
1682 int numhunk = -1;
1683 int numelem = 0;
1684 int count;
1685 int i, j, k, l;
1686 char fmtbuf[32] = "";
1687 struct iaddr iaddr;
1688 struct enumeration *enumbuf[32]; /* MUST be same as fmtbuf */
1689 char *op = optbuf;
1690 const unsigned char *dp = data;
1691 char comma;
1692 unsigned long tval;
1693 isc_boolean_t a_array = ISC_FALSE;
1694 int len_used;
1696 if (emit_commas)
1697 comma = ',';
1698 else
1699 comma = ' ';
1701 memset (enumbuf, 0, sizeof enumbuf);
1703 /* Figure out the size of the data. */
1704 for (l = i = 0; option -> format [i]; i++, l++) {
1705 if (l >= sizeof(fmtbuf) - 1)
1706 log_fatal("Bounds failure on internal buffer at "
1707 "%s:%d", MDL);
1709 if (!numhunk) {
1710 log_error ("%s: Extra codes in format string: %s",
1711 option -> name,
1712 &(option -> format [i]));
1713 break;
1715 numelem++;
1716 fmtbuf [l] = option -> format [i];
1717 switch (option -> format [i]) {
1718 case 'a':
1719 a_array = ISC_TRUE;
1720 /* Fall through */
1721 case 'A':
1722 --numelem;
1723 fmtbuf [l] = 0;
1724 numhunk = 0;
1725 break;
1726 case 'E':
1727 /* Skip the universe name. */
1728 while (option -> format [i] &&
1729 option -> format [i] != '.')
1730 i++;
1731 /* Fall Through! */
1732 case 'X':
1733 for (k = 0; k < len; k++) {
1734 if (!isascii (data [k]) ||
1735 !isprint (data [k]))
1736 break;
1738 /* If we found no bogus characters, or the bogus
1739 character we found is a trailing NUL, it's
1740 okay to print this option as text. */
1741 if (k == len || (k + 1 == len && data [k] == 0)) {
1742 fmtbuf [l] = 't';
1743 numhunk = -2;
1744 } else {
1745 fmtbuf [l] = 'x';
1746 hunksize++;
1747 comma = ':';
1748 numhunk = 0;
1749 a_array = ISC_TRUE;
1750 hunkinc = 1;
1752 fmtbuf [l + 1] = 0;
1753 break;
1754 case 'c':
1755 /* The 'c' atom is a 'D' modifier only. */
1756 log_error("'c' atom not following D atom in format "
1757 "string: %s", option->format);
1758 break;
1759 case 'D':
1761 * Skip the 'c' atom, if present. It does not affect
1762 * how we convert wire->text format (if compression is
1763 * present either way, we still process it).
1765 if (option->format[i+1] == 'c')
1766 i++;
1767 fmtbuf[l + 1] = 0;
1768 numhunk = -2;
1769 break;
1770 case 'd':
1771 fmtbuf[l] = 't';
1772 /* Fall Through ! */
1773 case 't':
1774 fmtbuf[l + 1] = 0;
1775 numhunk = -2;
1776 break;
1777 case 'N':
1778 k = i;
1779 while (option -> format [i] &&
1780 option -> format [i] != '.')
1781 i++;
1782 enumbuf [l] =
1783 find_enumeration (&option -> format [k] + 1,
1784 i - k - 1);
1785 if (enumbuf[l] == NULL) {
1786 hunksize += 1;
1787 hunkinc = 1;
1788 } else {
1789 hunksize += enumbuf[l]->width;
1790 hunkinc = enumbuf[l]->width;
1792 break;
1793 case '6':
1794 hunksize += 16;
1795 hunkinc = 16;
1796 break;
1797 case 'I':
1798 case 'l':
1799 case 'L':
1800 case 'T':
1801 hunksize += 4;
1802 hunkinc = 4;
1803 break;
1804 case 's':
1805 case 'S':
1806 hunksize += 2;
1807 hunkinc = 2;
1808 break;
1809 case 'b':
1810 case 'B':
1811 case 'f':
1812 case 'F':
1813 hunksize++;
1814 hunkinc = 1;
1815 break;
1816 case 'e':
1817 case 'Z':
1818 break;
1819 case 'o':
1820 opthunk += hunkinc;
1821 break;
1822 default:
1823 log_error ("%s: garbage in format string: %s",
1824 option -> name,
1825 &(option -> format [i]));
1826 break;
1830 /* Check for too few bytes... */
1831 if (hunksize - opthunk > len) {
1832 log_error ("%s: expecting at least %d bytes; got %d",
1833 option -> name,
1834 hunksize, len);
1835 return "<error>";
1837 /* Check for too many bytes... */
1838 if (numhunk == -1 && hunksize < len)
1839 log_error ("%s: %d extra bytes",
1840 option -> name,
1841 len - hunksize);
1843 /* If this is an array, compute its size. */
1844 if (numhunk == 0) {
1845 if (a_array == ISC_TRUE) {
1847 * It is an 'a' type array - we repeat the
1848 * last format type. A binary string for 'X'
1849 * is also like this. hunkinc is the size
1850 * of the last format type and we add 1 to
1851 * cover the entire first record.
1853 numhunk = ((len - hunksize) / hunkinc) + 1;
1854 len_used = hunksize + ((numhunk - 1) * hunkinc);
1855 } else {
1857 * It is an 'A' type array - we repeat the
1858 * entire record
1860 numhunk = len / hunksize;
1861 len_used = numhunk * hunksize;
1864 /* See if we got an exact number of hunks. */
1865 if (len_used < len) {
1866 log_error ("%s: %d extra bytes at end of array\n",
1867 option -> name,
1868 len - len_used);
1873 /* A one-hunk array prints the same as a single hunk. */
1874 if (numhunk < 0)
1875 numhunk = 1;
1877 /* Cycle through the array (or hunk) printing the data. */
1878 for (i = 0; i < numhunk; i++) {
1879 if ((a_array == ISC_TRUE) && (i != 0) && (numelem > 0)) {
1881 * For 'a' type of arrays we repeat
1882 * only the last format character
1883 * We should never hit the case of numelem == 0
1884 * but let's include the check to be safe.
1886 j = numelem - 1;
1887 } else {
1889 * for other types of arrays or the first
1890 * time through for 'a' types, we go through
1891 * the entire set of format characters.
1893 j = 0;
1896 for (; j < numelem; j++) {
1897 switch (fmtbuf [j]) {
1898 case 't':
1899 /* endbuf-1 leaves room for NULL. */
1900 k = pretty_text(&op, endbuf - 1, &dp,
1901 data + len, emit_quotes);
1902 if (k == -1) {
1903 log_error("Error printing text.");
1904 break;
1906 *op = 0;
1907 break;
1908 case 'D': /* RFC1035 format name list */
1909 for( ; dp < (data + len) ; dp += k) {
1910 unsigned char nbuff[NS_MAXCDNAME];
1911 const unsigned char *nbp, *nend;
1913 nend = &nbuff[sizeof(nbuff)];
1915 /* If this is for ISC DHCP consumption
1916 * (emit_quotes), lay it out as a list
1917 * of STRING tokens. Otherwise, it is
1918 * a space-separated list of DNS-
1919 * escaped names as /etc/resolv.conf
1920 * might digest.
1922 if (dp != data) {
1923 if (op + 2 > endbuf)
1924 break;
1926 if (emit_quotes)
1927 *op++ = ',';
1928 *op++ = ' ';
1931 /* XXX: if fmtbuf[j+1] != 'c', we
1932 * should warn if the data was
1933 * compressed anyway.
1935 k = MRns_name_unpack(data,
1936 data + len,
1937 dp, nbuff,
1938 sizeof(nbuff));
1940 if (k == -1) {
1941 log_error("Invalid domain "
1942 "list.");
1943 break;
1946 /* If emit_quotes, then use ISC DHCP
1947 * escapes. Otherwise, rely only on
1948 * ns_name_ntop().
1950 if (emit_quotes) {
1951 nbp = nbuff;
1952 pretty_domain(&op, endbuf-1,
1953 &nbp, nend);
1954 } else {
1955 /* ns_name_ntop() includes
1956 * a trailing NUL in its
1957 * count.
1959 count = MRns_name_ntop(
1960 nbuff, op,
1961 (endbuf-op)-1);
1963 if (count <= 0) {
1964 log_error("Invalid "
1965 "domain name.");
1966 break;
1969 /* Consume all but the trailing
1970 * NUL.
1972 op += count - 1;
1974 /* Replace the trailing NUL
1975 * with the implicit root
1976 * (in the unlikely event the
1977 * domain name /is/ the root).
1979 *op++ = '.';
1982 *op = '\0';
1983 break;
1984 /* pretty-printing an array of enums is
1985 going to get ugly. */
1986 case 'N':
1987 if (!enumbuf [j]) {
1988 tval = *dp++;
1989 goto enum_as_num;
1992 switch (enumbuf[j]->width) {
1993 case 1:
1994 tval = getUChar(dp);
1995 break;
1997 case 2:
1998 tval = getUShort(dp);
1999 break;
2001 case 4:
2002 tval = getULong(dp);
2003 break;
2005 default:
2006 log_fatal("Impossible case at %s:%d.",
2007 MDL);
2008 return "<double impossible condition>";
2011 for (i = 0; ;i++) {
2012 if (!enumbuf [j] -> values [i].name)
2013 goto enum_as_num;
2014 if (enumbuf [j] -> values [i].value ==
2015 tval)
2016 break;
2018 strcpy (op, enumbuf [j] -> values [i].name);
2019 dp += enumbuf[j]->width;
2020 break;
2022 enum_as_num:
2023 sprintf(op, "%lu", tval);
2024 break;
2026 case 'I':
2027 iaddr.len = 4;
2028 memcpy(iaddr.iabuf, dp, 4);
2029 strcpy(op, piaddr(iaddr));
2030 dp += 4;
2031 break;
2032 case '6':
2033 iaddr.len = 16;
2034 memcpy(iaddr.iabuf, dp, 16);
2035 strcpy(op, piaddr(iaddr));
2036 dp += 16;
2037 break;
2038 case 'l':
2039 sprintf (op, "%ld", (long)getLong (dp));
2040 dp += 4;
2041 break;
2042 case 'T':
2043 tval = getULong (dp);
2044 if (tval == -1)
2045 sprintf (op, "%s", "infinite");
2046 else
2047 sprintf(op, "%lu", tval);
2048 break;
2049 case 'L':
2050 sprintf(op, "%lu",
2051 (unsigned long)getULong(dp));
2052 dp += 4;
2053 break;
2054 case 's':
2055 sprintf (op, "%d", (int)getShort (dp));
2056 dp += 2;
2057 break;
2058 case 'S':
2059 sprintf(op, "%u", (unsigned)getUShort(dp));
2060 dp += 2;
2061 break;
2062 case 'b':
2063 sprintf (op, "%d", *(const char *)dp++);
2064 break;
2065 case 'B':
2066 sprintf (op, "%d", *dp++);
2067 break;
2068 case 'X':
2069 case 'x':
2070 sprintf (op, "%x", *dp++);
2071 break;
2072 case 'f':
2073 strcpy (op, *dp++ ? "true" : "false");
2074 break;
2075 case 'F':
2076 strcpy (op, "true");
2077 break;
2078 case 'e':
2079 case 'Z':
2080 *op = '\0';
2081 break;
2082 default:
2083 log_error ("Unexpected format code %c",
2084 fmtbuf [j]);
2086 op += strlen (op);
2087 if (dp == data + len)
2088 break;
2089 if (j + 1 < numelem && comma != ':')
2090 *op++ = ' ';
2092 if (i + 1 < numhunk) {
2093 *op++ = comma;
2095 if (dp == data + len)
2096 break;
2098 return optbuf;
2101 int get_option (result, universe, packet, lease, client_state,
2102 in_options, cfg_options, options, scope, code, file, line)
2103 struct data_string *result;
2104 struct universe *universe;
2105 struct packet *packet;
2106 struct lease *lease;
2107 struct client_state *client_state;
2108 struct option_state *in_options;
2109 struct option_state *cfg_options;
2110 struct option_state *options;
2111 struct binding_scope **scope;
2112 unsigned code;
2113 const char *file;
2114 int line;
2116 struct option_cache *oc;
2118 if (!universe -> lookup_func)
2119 return 0;
2120 oc = ((*universe -> lookup_func) (universe, options, code));
2121 if (!oc)
2122 return 0;
2123 if (!evaluate_option_cache (result, packet, lease, client_state,
2124 in_options, cfg_options, scope, oc,
2125 file, line))
2126 return 0;
2127 return 1;
2130 void set_option (universe, options, option, op)
2131 struct universe *universe;
2132 struct option_state *options;
2133 struct option_cache *option;
2134 enum statement_op op;
2136 struct option_cache *oc, *noc;
2138 switch (op) {
2139 case if_statement:
2140 case add_statement:
2141 case eval_statement:
2142 case break_statement:
2143 default:
2144 log_error ("bogus statement type in set_option.");
2145 break;
2147 case default_option_statement:
2148 oc = lookup_option (universe, options,
2149 option -> option -> code);
2150 if (oc)
2151 break;
2152 save_option (universe, options, option);
2153 break;
2155 case supersede_option_statement:
2156 case send_option_statement:
2157 /* Install the option, replacing any existing version. */
2158 save_option (universe, options, option);
2159 break;
2161 case append_option_statement:
2162 case prepend_option_statement:
2163 oc = lookup_option (universe, options,
2164 option -> option -> code);
2165 if (!oc) {
2166 save_option (universe, options, option);
2167 break;
2169 /* If it's not an expression, make it into one. */
2170 if (!oc -> expression && oc -> data.len) {
2171 if (!expression_allocate (&oc -> expression, MDL)) {
2172 log_error ("Can't allocate const expression.");
2173 break;
2175 oc -> expression -> op = expr_const_data;
2176 data_string_copy
2177 (&oc -> expression -> data.const_data,
2178 &oc -> data, MDL);
2179 data_string_forget (&oc -> data, MDL);
2181 noc = (struct option_cache *)0;
2182 if (!option_cache_allocate (&noc, MDL))
2183 break;
2184 if (op == append_option_statement) {
2185 if (!make_concat (&noc -> expression,
2186 oc -> expression,
2187 option -> expression)) {
2188 option_cache_dereference (&noc, MDL);
2189 break;
2191 } else {
2192 if (!make_concat (&noc -> expression,
2193 option -> expression,
2194 oc -> expression)) {
2195 option_cache_dereference (&noc, MDL);
2196 break;
2199 option_reference(&(noc->option), oc->option, MDL);
2200 save_option (universe, options, noc);
2201 option_cache_dereference (&noc, MDL);
2202 break;
2206 struct option_cache *lookup_option (universe, options, code)
2207 struct universe *universe;
2208 struct option_state *options;
2209 unsigned code;
2211 if (!options)
2212 return (struct option_cache *)0;
2213 if (universe -> lookup_func)
2214 return (*universe -> lookup_func) (universe, options, code);
2215 else
2216 log_error ("can't look up options in %s space.",
2217 universe -> name);
2218 return (struct option_cache *)0;
2221 struct option_cache *lookup_hashed_option (universe, options, code)
2222 struct universe *universe;
2223 struct option_state *options;
2224 unsigned code;
2226 int hashix;
2227 pair bptr;
2228 pair *hash;
2230 /* Make sure there's a hash table. */
2231 if (universe -> index >= options -> universe_count ||
2232 !(options -> universes [universe -> index]))
2233 return (struct option_cache *)0;
2235 hash = options -> universes [universe -> index];
2237 hashix = compute_option_hash (code);
2238 for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
2239 if (((struct option_cache *)(bptr -> car)) -> option -> code ==
2240 code)
2241 return (struct option_cache *)(bptr -> car);
2243 return (struct option_cache *)0;
2246 /* Save a specified buffer into an option cache. */
2248 save_option_buffer(struct universe *universe, struct option_state *options,
2249 struct buffer *bp, unsigned char *buffer, unsigned length,
2250 unsigned code, int terminatep)
2252 struct option_cache *op = NULL;
2253 int status = 1;
2255 status = prepare_option_buffer(universe, bp, buffer, length, code,
2256 terminatep, &op);
2258 if (status == 0)
2259 goto cleanup;
2261 save_option(universe, options, op);
2263 cleanup:
2264 if (op != NULL)
2265 option_cache_dereference(&op, MDL);
2267 return status;
2270 /* Append a specified buffer onto the tail of an option cache. */
2272 append_option_buffer(struct universe *universe, struct option_state *options,
2273 struct buffer *bp, unsigned char *buffer, unsigned length,
2274 unsigned code, int terminatep)
2276 struct option_cache *op = NULL;
2277 int status = 1;
2279 status = prepare_option_buffer(universe, bp, buffer, length, code,
2280 terminatep, &op);
2282 if (status == 0)
2283 goto cleanup;
2285 also_save_option(universe, options, op);
2287 cleanup:
2288 if (op != NULL)
2289 option_cache_dereference(&op, MDL);
2291 return status;
2294 /* Create/copy a buffer into a new option cache. */
2295 static int
2296 prepare_option_buffer(struct universe *universe, struct buffer *bp,
2297 unsigned char *buffer, unsigned length, unsigned code,
2298 int terminatep, struct option_cache **opp)
2300 struct buffer *lbp = NULL;
2301 struct option *option = NULL;
2302 struct option_cache *op;
2303 int status = 1;
2305 /* Code sizes of 8, 16, and 32 bits are allowed. */
2306 switch(universe->tag_size) {
2307 case 1:
2308 if (code > 0xff)
2309 return 0;
2310 break;
2311 case 2:
2312 if (code > 0xffff)
2313 return 0;
2314 break;
2315 case 4:
2316 if (code > 0xffffffff)
2317 return 0;
2318 break;
2320 default:
2321 log_fatal("Inconsistent universe tag size at %s:%d.", MDL);
2324 option_code_hash_lookup(&option, universe->code_hash, &code, 0, MDL);
2326 /* If we created an option structure for each option a client
2327 * supplied, it's possible we may create > 2^32 option structures.
2328 * That's not feasible. So by failing to enter these option
2329 * structures into the code and name hash tables, references will
2330 * never be more than 1 - when the option cache is destroyed, this
2331 * will be cleaned up.
2333 if (!option) {
2334 char nbuf[sizeof("unknown-4294967295")];
2336 sprintf(nbuf, "unknown-%u", code);
2338 option = new_option(nbuf, MDL);
2340 if (!option)
2341 return 0;
2343 option->format = default_option_format;
2344 option->universe = universe;
2345 option->code = code;
2347 /* new_option() doesn't set references, pretend. */
2348 option->refcnt = 1;
2351 if (!option_cache_allocate (opp, MDL)) {
2352 log_error("No memory for option code %s.%s.",
2353 universe->name, option->name);
2354 status = 0;
2355 goto cleanup;
2358 /* Pointer rather than double pointer makes for less parens. */
2359 op = *opp;
2361 option_reference(&op->option, option, MDL);
2363 /* If we weren't passed a buffer in which the data are saved and
2364 refcounted, allocate one now. */
2365 if (!bp) {
2366 if (!buffer_allocate (&lbp, length + terminatep, MDL)) {
2367 log_error ("no memory for option buffer.");
2369 status = 0;
2370 goto cleanup;
2372 memcpy (lbp -> data, buffer, length + terminatep);
2373 bp = lbp;
2374 buffer = &bp -> data [0]; /* Refer to saved buffer. */
2377 /* Reference buffer copy to option cache. */
2378 op -> data.buffer = (struct buffer *)0;
2379 buffer_reference (&op -> data.buffer, bp, MDL);
2381 /* Point option cache into buffer. */
2382 op -> data.data = buffer;
2383 op -> data.len = length;
2385 if (terminatep) {
2386 /* NUL terminate (we can get away with this because we (or
2387 the caller!) allocated one more than the buffer size, and
2388 because the byte following the end of an option is always
2389 the code of the next option, which the caller is getting
2390 out of the *original* buffer. */
2391 buffer [length] = 0;
2392 op -> data.terminated = 1;
2393 } else
2394 op -> data.terminated = 0;
2396 /* If this option is ultimately a text option, null determinate to
2397 * comply with RFC2132 section 2. Mark a flag so this can be sensed
2398 * later to echo NULLs back to clients that supplied them (they
2399 * probably expect them).
2401 if (format_has_text(option->format)) {
2402 int min_len = format_min_length(option->format, op);
2404 while ((op->data.len > min_len) &&
2405 (op->data.data[op->data.len-1] == '\0')) {
2406 op->data.len--;
2407 op->flags |= OPTION_HAD_NULLS;
2411 /* And let go of our references. */
2412 cleanup:
2413 if (lbp != NULL)
2414 buffer_dereference(&lbp, MDL);
2415 option_dereference(&option, MDL);
2417 return status;
2420 static void
2421 count_options(struct option_cache *dummy_oc,
2422 struct packet *dummy_packet,
2423 struct lease *dummy_lease,
2424 struct client_state *dummy_client_state,
2425 struct option_state *dummy_opt_state,
2426 struct option_state *opt_state,
2427 struct binding_scope **dummy_binding_scope,
2428 struct universe *dummy_universe,
2429 void *void_accumulator) {
2430 int *accumulator = (int *)void_accumulator;
2432 *accumulator += 1;
2435 static void
2436 collect_oro(struct option_cache *oc,
2437 struct packet *dummy_packet,
2438 struct lease *dummy_lease,
2439 struct client_state *dummy_client_state,
2440 struct option_state *dummy_opt_state,
2441 struct option_state *opt_state,
2442 struct binding_scope **dummy_binding_scope,
2443 struct universe *dummy_universe,
2444 void *void_oro) {
2445 struct data_string *oro = (struct data_string *)void_oro;
2447 putUShort(oro->buffer->data + oro->len, oc->option->code);
2448 oro->len += 2;
2451 /* build_server_oro() is presently unusued, but may be used at a future date
2452 * with support for Reconfigure messages (as a hint to the client about new
2453 * option value contents).
2455 void
2456 build_server_oro(struct data_string *server_oro,
2457 struct option_state *options,
2458 const char *file, int line) {
2459 int num_opts;
2460 int i;
2461 struct option *o;
2464 * Count the number of options, so we can allocate enough memory.
2465 * We want to mention sub-options too, so check all universes.
2467 num_opts = 0;
2468 option_space_foreach(NULL, NULL, NULL, NULL, options,
2469 NULL, &dhcpv6_universe, (void *)&num_opts,
2470 count_options);
2471 for (i=0; i < options->universe_count; i++) {
2472 if (options->universes[i] != NULL) {
2473 o = universes[i]->enc_opt;
2474 while (o != NULL) {
2475 if (o->universe == &dhcpv6_universe) {
2476 num_opts++;
2477 break;
2479 o = o->universe->enc_opt;
2485 * Allocate space.
2487 memset(server_oro, 0, sizeof(*server_oro));
2488 if (!buffer_allocate(&server_oro->buffer, num_opts * 2, MDL)) {
2489 log_fatal("no memory to build server ORO");
2491 server_oro->data = server_oro->buffer->data;
2494 * Copy the data in.
2495 * We want to mention sub-options too, so check all universes.
2497 server_oro->len = 0; /* gets set in collect_oro */
2498 option_space_foreach(NULL, NULL, NULL, NULL, options,
2499 NULL, &dhcpv6_universe, (void *)server_oro,
2500 collect_oro);
2501 for (i=0; i < options->universe_count; i++) {
2502 if (options->universes[i] != NULL) {
2503 o = universes[i]->enc_opt;
2504 while (o != NULL) {
2505 if (o->universe == &dhcpv6_universe) {
2506 unsigned char *tmp;
2507 tmp = server_oro->buffer->data;
2508 putUShort(tmp + server_oro->len,
2509 o->code);
2510 server_oro->len += 2;
2511 break;
2513 o = o->universe->enc_opt;
2519 /* Wrapper function to put an option cache into an option state. */
2520 void
2521 save_option(struct universe *universe, struct option_state *options,
2522 struct option_cache *oc)
2524 if (universe->save_func)
2525 (*universe->save_func)(universe, options, oc, ISC_FALSE);
2526 else
2527 log_error("can't store options in %s space.", universe->name);
2530 /* Wrapper function to append an option cache into an option state's list. */
2531 void
2532 also_save_option(struct universe *universe, struct option_state *options,
2533 struct option_cache *oc)
2535 if (universe->save_func)
2536 (*universe->save_func)(universe, options, oc, ISC_TRUE);
2537 else
2538 log_error("can't store options in %s space.", universe->name);
2541 void
2542 save_hashed_option(struct universe *universe, struct option_state *options,
2543 struct option_cache *oc, isc_boolean_t appendp)
2545 int hashix;
2546 pair bptr;
2547 pair *hash = options -> universes [universe -> index];
2548 struct option_cache **ocloc;
2550 if (oc -> refcnt == 0)
2551 abort ();
2553 /* Compute the hash. */
2554 hashix = compute_option_hash (oc -> option -> code);
2556 /* If there's no hash table, make one. */
2557 if (!hash) {
2558 hash = (pair *)dmalloc (OPTION_HASH_SIZE * sizeof *hash, MDL);
2559 if (!hash) {
2560 log_error ("no memory to store %s.%s",
2561 universe -> name, oc -> option -> name);
2562 return;
2564 memset (hash, 0, OPTION_HASH_SIZE * sizeof *hash);
2565 options -> universes [universe -> index] = (void *)hash;
2566 } else {
2567 /* Try to find an existing option matching the new one. */
2568 for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
2569 if (((struct option_cache *)
2570 (bptr -> car)) -> option -> code ==
2571 oc -> option -> code)
2572 break;
2575 /* Deal with collisions on the hash list. */
2576 if (bptr) {
2577 ocloc = (struct option_cache **)&bptr->car;
2580 * If appendp is set, append it onto the tail of the
2581 * ->next list. If it is not set, rotate it into
2582 * position at the head of the list.
2584 if (appendp) {
2585 do {
2586 ocloc = &(*ocloc)->next;
2587 } while (*ocloc != NULL);
2588 } else {
2589 option_cache_dereference(ocloc, MDL);
2592 option_cache_reference(ocloc, oc, MDL);
2593 return;
2597 /* Otherwise, just put the new one at the head of the list. */
2598 bptr = new_pair (MDL);
2599 if (!bptr) {
2600 log_error ("No memory for option_cache reference.");
2601 return;
2603 bptr -> cdr = hash [hashix];
2604 bptr -> car = 0;
2605 option_cache_reference ((struct option_cache **)&bptr -> car, oc, MDL);
2606 hash [hashix] = bptr;
2609 void delete_option (universe, options, code)
2610 struct universe *universe;
2611 struct option_state *options;
2612 int code;
2614 if (universe -> delete_func)
2615 (*universe -> delete_func) (universe, options, code);
2616 else
2617 log_error ("can't delete options from %s space.",
2618 universe -> name);
2621 void delete_hashed_option (universe, options, code)
2622 struct universe *universe;
2623 struct option_state *options;
2624 int code;
2626 int hashix;
2627 pair bptr, prev = (pair)0;
2628 pair *hash = options -> universes [universe -> index];
2630 /* There may not be any options in this space. */
2631 if (!hash)
2632 return;
2634 /* Try to find an existing option matching the new one. */
2635 hashix = compute_option_hash (code);
2636 for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
2637 if (((struct option_cache *)(bptr -> car)) -> option -> code
2638 == code)
2639 break;
2640 prev = bptr;
2642 /* If we found one, wipe it out... */
2643 if (bptr) {
2644 if (prev)
2645 prev -> cdr = bptr -> cdr;
2646 else
2647 hash [hashix] = bptr -> cdr;
2648 option_cache_dereference
2649 ((struct option_cache **)(&bptr -> car), MDL);
2650 free_pair (bptr, MDL);
2654 extern struct option_cache *free_option_caches; /* XXX */
2656 int option_cache_dereference (ptr, file, line)
2657 struct option_cache **ptr;
2658 const char *file;
2659 int line;
2661 if (!ptr || !*ptr) {
2662 log_error ("Null pointer in option_cache_dereference: %s(%d)",
2663 file, line);
2664 #if defined (POINTER_DEBUG)
2665 abort ();
2666 #else
2667 return 0;
2668 #endif
2671 (*ptr) -> refcnt--;
2672 rc_register (file, line, ptr, *ptr, (*ptr) -> refcnt, 1, RC_MISC);
2673 if (!(*ptr) -> refcnt) {
2674 if ((*ptr) -> data.buffer)
2675 data_string_forget (&(*ptr) -> data, file, line);
2676 if ((*ptr)->option)
2677 option_dereference(&(*ptr)->option, MDL);
2678 if ((*ptr) -> expression)
2679 expression_dereference (&(*ptr) -> expression,
2680 file, line);
2681 if ((*ptr) -> next)
2682 option_cache_dereference (&((*ptr) -> next),
2683 file, line);
2684 /* Put it back on the free list... */
2685 (*ptr) -> expression = (struct expression *)free_option_caches;
2686 free_option_caches = *ptr;
2687 dmalloc_reuse (free_option_caches, (char *)0, 0, 0);
2689 if ((*ptr) -> refcnt < 0) {
2690 log_error ("%s(%d): negative refcnt!", file, line);
2691 #if defined (DEBUG_RC_HISTORY)
2692 dump_rc_history (*ptr);
2693 #endif
2694 #if defined (POINTER_DEBUG)
2695 abort ();
2696 #else
2697 *ptr = (struct option_cache *)0;
2698 return 0;
2699 #endif
2701 *ptr = (struct option_cache *)0;
2702 return 1;
2706 int hashed_option_state_dereference (universe, state, file, line)
2707 struct universe *universe;
2708 struct option_state *state;
2709 const char *file;
2710 int line;
2712 pair *heads;
2713 pair cp, next;
2714 int i;
2716 /* Get the pointer to the array of hash table bucket heads. */
2717 heads = (pair *)(state -> universes [universe -> index]);
2718 if (!heads)
2719 return 0;
2721 /* For each non-null head, loop through all the buckets dereferencing
2722 the attached option cache structures and freeing the buckets. */
2723 for (i = 0; i < OPTION_HASH_SIZE; i++) {
2724 for (cp = heads [i]; cp; cp = next) {
2725 next = cp -> cdr;
2726 option_cache_dereference
2727 ((struct option_cache **)&cp -> car,
2728 file, line);
2729 free_pair (cp, file, line);
2733 dfree (heads, file, line);
2734 state -> universes [universe -> index] = (void *)0;
2735 return 1;
2738 /* The 'data_string' primitive doesn't have an appension mechanism.
2739 * This function must then append a new option onto an existing buffer
2740 * by first duplicating the original buffer and appending the desired
2741 * values, followed by coping the new value into place.
2744 append_option(struct data_string *dst, struct universe *universe,
2745 struct option *option, struct data_string *src)
2747 struct data_string tmp;
2749 if (src->len == 0 && option->format[0] != 'Z')
2750 return 0;
2752 memset(&tmp, 0, sizeof(tmp));
2754 /* Allocate a buffer to hold existing data, the current option's
2755 * tag and length, and the option's content.
2757 if (!buffer_allocate(&tmp.buffer,
2758 (dst->len + universe->length_size +
2759 universe->tag_size + src->len), MDL)) {
2760 /* XXX: This kills all options presently stored in the
2761 * destination buffer. This is the way the original code
2762 * worked, and assumes an 'all or nothing' approach to
2763 * eg encapsulated option spaces. It may or may not be
2764 * desirable.
2766 data_string_forget(dst, MDL);
2767 return 0;
2769 tmp.data = tmp.buffer->data;
2771 /* Copy the existing data off the destination. */
2772 if (dst->len != 0)
2773 memcpy(tmp.buffer->data, dst->data, dst->len);
2774 tmp.len = dst->len;
2776 /* Place the new option tag and length. */
2777 (*universe->store_tag)(tmp.buffer->data + tmp.len, option->code);
2778 tmp.len += universe->tag_size;
2779 (*universe->store_length)(tmp.buffer->data + tmp.len, src->len);
2780 tmp.len += universe->length_size;
2782 /* Copy the option contents onto the end. */
2783 memcpy(tmp.buffer->data + tmp.len, src->data, src->len);
2784 tmp.len += src->len;
2786 /* Play the shell game. */
2787 data_string_forget(dst, MDL);
2788 data_string_copy(dst, &tmp, MDL);
2789 data_string_forget(&tmp, MDL);
2790 return 1;
2794 store_option(struct data_string *result, struct universe *universe,
2795 struct packet *packet, struct lease *lease,
2796 struct client_state *client_state,
2797 struct option_state *in_options, struct option_state *cfg_options,
2798 struct binding_scope **scope, struct option_cache *oc)
2800 struct data_string tmp;
2801 struct universe *subu=NULL;
2802 int status;
2803 char *start, *end;
2805 memset(&tmp, 0, sizeof(tmp));
2807 if (evaluate_option_cache(&tmp, packet, lease, client_state,
2808 in_options, cfg_options, scope, oc, MDL)) {
2809 /* If the option is an extended 'e'ncapsulation (not a
2810 * direct 'E'ncapsulation), append the encapsulated space
2811 * onto the currently prepared value.
2813 do {
2814 if (oc->option->format &&
2815 oc->option->format[0] == 'e') {
2816 /* Skip forward to the universe name. */
2817 start = strchr(oc->option->format, 'E');
2818 if (start == NULL)
2819 break;
2821 /* Locate the name-terminating '.'. */
2822 end = strchr(++start, '.');
2824 /* A zero-length name is not allowed in
2825 * these kinds of encapsulations.
2827 if (end == NULL || start == end)
2828 break;
2830 universe_hash_lookup(&subu, universe_hash,
2831 start, end - start, MDL);
2833 if (subu == NULL) {
2834 log_error("store_option: option %d "
2835 "refers to unknown "
2836 "option space '%.*s'.",
2837 oc->option->code,
2838 (int)(end - start), start);
2839 break;
2842 /* Append encapsulations, if any. We
2843 * already have the prepended values, so
2844 * we send those even if there are no
2845 * encapsulated options (and ->encapsulate()
2846 * returns zero).
2848 subu->encapsulate(&tmp, packet, lease,
2849 client_state, in_options,
2850 cfg_options, scope, subu);
2851 subu = NULL;
2853 } while (ISC_FALSE);
2855 status = append_option(result, universe, oc->option, &tmp);
2856 data_string_forget(&tmp, MDL);
2858 return status;
2861 return 0;
2864 int option_space_encapsulate (result, packet, lease, client_state,
2865 in_options, cfg_options, scope, name)
2866 struct data_string *result;
2867 struct packet *packet;
2868 struct lease *lease;
2869 struct client_state *client_state;
2870 struct option_state *in_options;
2871 struct option_state *cfg_options;
2872 struct binding_scope **scope;
2873 struct data_string *name;
2875 struct universe *u = NULL;
2876 int status = 0;
2878 universe_hash_lookup(&u, universe_hash,
2879 (const char *)name->data, name->len, MDL);
2880 if (u == NULL) {
2881 log_error("option_space_encapsulate: option space '%.*s' does "
2882 "not exist, but is configured.",
2883 (int)name->len, name->data);
2884 return status;
2887 if (u->encapsulate != NULL) {
2888 if (u->encapsulate(result, packet, lease, client_state,
2889 in_options, cfg_options, scope, u))
2890 status = 1;
2891 } else
2892 log_error("encapsulation requested for '%s' with no support.",
2893 name->data);
2895 return status;
2898 /* Attempt to store any 'E'ncapsulated options that have not yet been
2899 * placed on the option buffer by the above (configuring a value in
2900 * the space over-rides any values in the child universe).
2902 * Note that there are far fewer universes than there will ever be
2903 * options in any universe. So it is faster to traverse the
2904 * configured universes, checking if each is encapsulated in the
2905 * current universe, and if so attempting to do so.
2907 * For each configured universe for this configuration option space,
2908 * which is encapsulated within the current universe, can not be found
2909 * by the lookup function (the universe-specific encapsulation
2910 * functions would already have stored such a value), and encapsulates
2911 * at least one option, append it.
2913 static int
2914 search_subencapsulation(struct data_string *result, struct packet *packet,
2915 struct lease *lease, struct client_state *client_state,
2916 struct option_state *in_options,
2917 struct option_state *cfg_options,
2918 struct binding_scope **scope,
2919 struct universe *universe)
2921 struct data_string sub;
2922 struct universe *subu;
2923 int i, status = 0;
2925 memset(&sub, 0, sizeof(sub));
2926 for (i = 0 ; i < cfg_options->universe_count ; i++) {
2927 subu = universes[i];
2929 if (subu == NULL)
2930 log_fatal("Impossible condition at %s:%d.", MDL);
2932 if (subu->enc_opt != NULL &&
2933 subu->enc_opt->universe == universe &&
2934 subu->enc_opt->format != NULL &&
2935 subu->enc_opt->format[0] == 'E' &&
2936 lookup_option(universe, cfg_options,
2937 subu->enc_opt->code) == NULL &&
2938 subu->encapsulate(&sub, packet, lease, client_state,
2939 in_options, cfg_options,
2940 scope, subu)) {
2941 if (append_option(result, universe,
2942 subu->enc_opt, &sub))
2943 status = 1;
2945 data_string_forget(&sub, MDL);
2949 return status;
2952 int hashed_option_space_encapsulate (result, packet, lease, client_state,
2953 in_options, cfg_options, scope, universe)
2954 struct data_string *result;
2955 struct packet *packet;
2956 struct lease *lease;
2957 struct client_state *client_state;
2958 struct option_state *in_options;
2959 struct option_state *cfg_options;
2960 struct binding_scope **scope;
2961 struct universe *universe;
2963 pair p, *hash;
2964 int status;
2965 int i;
2967 if (universe -> index >= cfg_options -> universe_count)
2968 return 0;
2970 hash = cfg_options -> universes [universe -> index];
2971 if (!hash)
2972 return 0;
2974 /* For each hash bucket, and each configured option cache within
2975 * that bucket, append the option onto the buffer in encapsulated
2976 * format appropriate to the universe.
2978 status = 0;
2979 for (i = 0; i < OPTION_HASH_SIZE; i++) {
2980 for (p = hash [i]; p; p = p -> cdr) {
2981 if (store_option(result, universe, packet, lease,
2982 client_state, in_options, cfg_options,
2983 scope, (struct option_cache *)p->car))
2984 status = 1;
2988 if (search_subencapsulation(result, packet, lease, client_state,
2989 in_options, cfg_options, scope, universe))
2990 status = 1;
2992 return status;
2995 int nwip_option_space_encapsulate (result, packet, lease, client_state,
2996 in_options, cfg_options, scope, universe)
2997 struct data_string *result;
2998 struct packet *packet;
2999 struct lease *lease;
3000 struct client_state *client_state;
3001 struct option_state *in_options;
3002 struct option_state *cfg_options;
3003 struct binding_scope **scope;
3004 struct universe *universe;
3006 pair ocp;
3007 int status;
3008 static struct option_cache *no_nwip;
3009 struct data_string ds;
3010 struct option_chain_head *head;
3012 if (universe -> index >= cfg_options -> universe_count)
3013 return 0;
3014 head = ((struct option_chain_head *)
3015 cfg_options -> universes [nwip_universe.index]);
3016 if (!head)
3017 return 0;
3019 status = 0;
3020 for (ocp = head -> first; ocp; ocp = ocp -> cdr) {
3021 if (store_option (result, universe, packet,
3022 lease, client_state, in_options,
3023 cfg_options, scope,
3024 (struct option_cache *)ocp -> car))
3025 status = 1;
3028 /* If there's no data, the nwip suboption is supposed to contain
3029 a suboption saying there's no data. */
3030 if (!status) {
3031 if (!no_nwip) {
3032 unsigned one = 1;
3033 static unsigned char nni [] = { 1, 0 };
3035 memset (&ds, 0, sizeof ds);
3036 ds.data = nni;
3037 ds.len = 2;
3038 if (option_cache_allocate (&no_nwip, MDL))
3039 data_string_copy (&no_nwip -> data, &ds, MDL);
3040 if (!option_code_hash_lookup(&no_nwip->option,
3041 nwip_universe.code_hash,
3042 &one, 0, MDL))
3043 log_fatal("Nwip option hash does not contain "
3044 "1 (%s:%d).", MDL);
3046 if (no_nwip) {
3047 if (store_option (result, universe, packet, lease,
3048 client_state, in_options,
3049 cfg_options, scope, no_nwip))
3050 status = 1;
3052 } else {
3053 memset (&ds, 0, sizeof ds);
3055 /* If we have nwip options, the first one has to be the
3056 nwip-exists-in-option-area option. */
3057 if (!buffer_allocate (&ds.buffer, result -> len + 2, MDL)) {
3058 data_string_forget (result, MDL);
3059 return 0;
3061 ds.data = &ds.buffer -> data [0];
3062 ds.buffer -> data [0] = 2;
3063 ds.buffer -> data [1] = 0;
3064 memcpy (&ds.buffer -> data [2], result -> data, result -> len);
3065 data_string_forget (result, MDL);
3066 data_string_copy (result, &ds, MDL);
3067 data_string_forget (&ds, MDL);
3070 return status;
3073 /* We don't want to use ns_name_pton()...it doesn't tell us how many bytes
3074 * it has consumed, and it plays havoc with our escapes.
3076 * So this function does DNS encoding, and returns either the number of
3077 * octects consumed (on success), or -1 on failure.
3079 static int
3080 fqdn_encode(unsigned char *dst, int dstlen, const unsigned char *src,
3081 int srclen)
3083 unsigned char *out;
3084 int i, j, len, outlen=0;
3086 out = dst;
3087 for (i = 0, j = 0 ; i < srclen ; i = j) {
3088 while ((j < srclen) && (src[j] != '.') && (src[j] != '\0'))
3089 j++;
3091 len = j - i;
3092 if ((outlen + 1 + len) > dstlen)
3093 return -1;
3095 *out++ = len;
3096 outlen++;
3098 /* We only do one FQDN, ending in one root label. */
3099 if (len == 0)
3100 return outlen;
3102 memcpy(out, src + i, len);
3103 out += len;
3104 outlen += len;
3106 /* Advance past the root label. */
3107 j++;
3110 if ((outlen + 1) > dstlen)
3111 return -1;
3113 /* Place the root label. */
3114 *out++ = 0;
3115 outlen++;
3117 return outlen;
3120 int fqdn_option_space_encapsulate (result, packet, lease, client_state,
3121 in_options, cfg_options, scope, universe)
3122 struct data_string *result;
3123 struct packet *packet;
3124 struct lease *lease;
3125 struct client_state *client_state;
3126 struct option_state *in_options;
3127 struct option_state *cfg_options;
3128 struct binding_scope **scope;
3129 struct universe *universe;
3131 pair ocp;
3132 struct data_string results [FQDN_SUBOPTION_COUNT + 1];
3133 int status = 1;
3134 int i;
3135 unsigned len;
3136 struct buffer *bp = (struct buffer *)0;
3137 struct option_chain_head *head;
3139 /* If there's no FQDN universe, don't encapsulate. */
3140 if (fqdn_universe.index >= cfg_options -> universe_count)
3141 return 0;
3142 head = ((struct option_chain_head *)
3143 cfg_options -> universes [fqdn_universe.index]);
3144 if (!head)
3145 return 0;
3147 /* Figure out the values of all the suboptions. */
3148 memset (results, 0, sizeof results);
3149 for (ocp = head -> first; ocp; ocp = ocp -> cdr) {
3150 struct option_cache *oc = (struct option_cache *)(ocp -> car);
3151 if (oc -> option -> code > FQDN_SUBOPTION_COUNT)
3152 continue;
3153 /* No need to check the return code, we check the length later */
3154 (void) evaluate_option_cache (&results[oc->option->code],
3155 packet, lease, client_state,
3156 in_options, cfg_options, scope,
3157 oc, MDL);
3159 /* We add a byte for the flags field.
3160 * We add two bytes for the two RCODE fields.
3161 * We add a byte because we will prepend a label count.
3162 * We add a byte because the input len doesn't count null termination,
3163 * and we will add a root label.
3165 len = 5 + results [FQDN_FQDN].len;
3166 /* Save the contents of the option in a buffer. */
3167 if (!buffer_allocate (&bp, len, MDL)) {
3168 log_error ("no memory for option buffer.");
3169 status = 0;
3170 goto exit;
3172 buffer_reference (&result -> buffer, bp, MDL);
3173 result -> len = 3;
3174 result -> data = &bp -> data [0];
3176 memset (&bp -> data [0], 0, len);
3177 /* XXX: The server should set bit 4 (yes, 4, not 3) to 1 if it is
3178 * not going to perform any ddns updates. The client should set the
3179 * bit if it doesn't want the server to perform any updates.
3180 * The problem is at this layer of abstraction we have no idea if
3181 * the caller is a client or server.
3183 * See RFC4702, Section 3.1, 'The "N" bit'.
3185 * if (?)
3186 * bp->data[0] |= 8;
3188 if (results [FQDN_NO_CLIENT_UPDATE].len &&
3189 results [FQDN_NO_CLIENT_UPDATE].data [0])
3190 bp -> data [0] |= 2;
3191 if (results [FQDN_SERVER_UPDATE].len &&
3192 results [FQDN_SERVER_UPDATE].data [0])
3193 bp -> data [0] |= 1;
3194 if (results [FQDN_RCODE1].len)
3195 bp -> data [1] = results [FQDN_RCODE1].data [0];
3196 if (results [FQDN_RCODE2].len)
3197 bp -> data [2] = results [FQDN_RCODE2].data [0];
3199 if (results [FQDN_ENCODED].len &&
3200 results [FQDN_ENCODED].data [0]) {
3201 bp->data[0] |= 4;
3202 if (results [FQDN_FQDN].len) {
3203 i = fqdn_encode(&bp->data[3], len - 3,
3204 results[FQDN_FQDN].data,
3205 results[FQDN_FQDN].len);
3207 if (i < 0) {
3208 status = 0;
3209 goto exit;
3212 result->len += i;
3213 result->terminated = 0;
3215 } else {
3216 if (results [FQDN_FQDN].len) {
3217 memcpy (&bp -> data [3], results [FQDN_FQDN].data,
3218 results [FQDN_FQDN].len);
3219 result -> len += results [FQDN_FQDN].len;
3220 result -> terminated = 0;
3223 exit:
3224 for (i = 1; i <= FQDN_SUBOPTION_COUNT; i++) {
3225 if (results [i].len)
3226 data_string_forget (&results [i], MDL);
3228 buffer_dereference (&bp, MDL);
3229 if (!status)
3230 data_string_forget(result, MDL);
3231 return status;
3235 * Trap invalid attempts to inspect FQND6 contents.
3237 struct option_cache *
3238 lookup_fqdn6_option(struct universe *universe, struct option_state *options,
3239 unsigned code)
3241 log_fatal("Impossible condition at %s:%d.", MDL);
3242 return NULL;
3246 * Trap invalid attempts to save options directly to FQDN6 rather than FQDN.
3248 void
3249 save_fqdn6_option(struct universe *universe, struct option_state *options,
3250 struct option_cache *oc, isc_boolean_t appendp)
3252 log_fatal("Impossible condition at %s:%d.", MDL);
3256 * Trap invalid attempts to delete an option out of the FQDN6 universe.
3258 void
3259 delete_fqdn6_option(struct universe *universe, struct option_state *options,
3260 int code)
3262 log_fatal("Impossible condition at %s:%d.", MDL);
3265 /* Shill to the DHCPv4 fqdn option cache any attempts to traverse the
3266 * V6's option cache entry.
3268 * This function is called speculatively by dhclient to setup
3269 * environment variables. But it would have already called the
3270 * foreach on the normal fqdn universe, so this is superfluous.
3272 void
3273 fqdn6_option_space_foreach(struct packet *packet, struct lease *lease,
3274 struct client_state *client_state,
3275 struct option_state *in_options,
3276 struct option_state *cfg_options,
3277 struct binding_scope **scope,
3278 struct universe *u, void *stuff,
3279 void (*func)(struct option_cache *,
3280 struct packet *,
3281 struct lease *,
3282 struct client_state *,
3283 struct option_state *,
3284 struct option_state *,
3285 struct binding_scope **,
3286 struct universe *, void *))
3288 /* Pretend it is empty. */
3289 return;
3292 /* Turn the FQDN option space into a DHCPv6 FQDN option buffer.
3295 fqdn6_option_space_encapsulate(struct data_string *result,
3296 struct packet *packet, struct lease *lease,
3297 struct client_state *client_state,
3298 struct option_state *in_options,
3299 struct option_state *cfg_options,
3300 struct binding_scope **scope,
3301 struct universe *universe)
3303 pair ocp;
3304 struct option_chain_head *head;
3305 struct option_cache *oc;
3306 unsigned char *data;
3307 int i, len, rval = 0, count;
3308 struct data_string results[FQDN_SUBOPTION_COUNT + 1];
3310 if (fqdn_universe.index >= cfg_options->universe_count)
3311 return 0;
3312 head = ((struct option_chain_head *)
3313 cfg_options->universes[fqdn_universe.index]);
3314 if (head == NULL)
3315 return 0;
3317 memset(results, 0, sizeof(results));
3318 for (ocp = head->first ; ocp != NULL ; ocp = ocp->cdr) {
3319 oc = (struct option_cache *)(ocp->car);
3320 if (oc->option->code > FQDN_SUBOPTION_COUNT)
3321 log_fatal("Impossible condition at %s:%d.", MDL);
3322 /* No need to check the return code, we check the length later */
3323 (void) evaluate_option_cache(&results[oc->option->code], packet,
3324 lease, client_state, in_options,
3325 cfg_options, scope, oc, MDL);
3328 /* We add a byte for the flags field at the start of the option.
3329 * We add a byte because we will prepend a label count.
3330 * We add a byte because the input length doesn't include a trailing
3331 * NULL, and we will add a root label.
3333 len = results[FQDN_FQDN].len + 3;
3334 if (!buffer_allocate(&result->buffer, len, MDL)) {
3335 log_error("No memory for virtual option buffer.");
3336 goto exit;
3338 data = result->buffer->data;
3339 result->data = data;
3341 /* The first byte is the flags field. */
3342 result->len = 1;
3343 data[0] = 0;
3344 /* XXX: The server should set bit 3 (yes, 3, not 4) to 1 if we
3345 * are not going to perform any DNS updates. The problem is
3346 * that at this layer of abstraction, we do not know if the caller
3347 * is the client or the server.
3349 * See RFC4704 Section 4.1, 'The "N" bit'.
3351 * if (?)
3352 * data[0] |= 4;
3354 if (results[FQDN_NO_CLIENT_UPDATE].len &&
3355 results[FQDN_NO_CLIENT_UPDATE].data[0])
3356 data[0] |= 2;
3357 if (results[FQDN_SERVER_UPDATE].len &&
3358 results[FQDN_SERVER_UPDATE].data[0])
3359 data[0] |= 1;
3361 /* If there is no name, we're done. */
3362 if (results[FQDN_FQDN].len == 0) {
3363 rval = 1;
3364 goto exit;
3367 /* Convert textual representation to DNS format. */
3368 count = fqdn_encode(data + 1, len - 1,
3369 results[FQDN_FQDN].data, results[FQDN_FQDN].len);
3371 if (count < 0) {
3372 rval = 0;
3373 data_string_forget(result, MDL);
3374 goto exit;
3377 result->len += count;
3378 result->terminated = 0;
3380 /* Success! */
3381 rval = 1;
3383 exit:
3384 for (i = 1 ; i <= FQDN_SUBOPTION_COUNT ; i++) {
3385 if (result[i].len)
3386 data_string_forget(&results[i], MDL);
3389 return rval;
3392 /* Read the DHCPv6 FQDN option's contents into the FQDN virtual space.
3395 fqdn6_universe_decode(struct option_state *options,
3396 const unsigned char *buffer, unsigned length,
3397 struct universe *u)
3399 struct buffer *bp = NULL;
3400 unsigned char *first_dot;
3401 int len, hlen, dlen;
3403 /* The FQDN option has to be at least 1 byte long. */
3404 if (length < 1)
3405 return 0;
3407 /* Save the contents of the option in a buffer. There are 3
3408 * one-byte values we record from the packet, so we go ahead
3409 * and allocate a bigger buffer to accommodate them. But the
3410 * 'length' we got (because it is a DNS encoded string) is
3411 * one longer than we need...so we only add two extra octets.
3413 if (!buffer_allocate(&bp, length + 2, MDL)) {
3414 log_error("No memory for dhcp6.fqdn option buffer.");
3415 return 0;
3418 /* The v6 FQDN is always 'encoded' per DNS. */
3419 bp->data[0] = 1;
3420 if (!save_option_buffer(&fqdn_universe, options, bp,
3421 bp->data, 1, FQDN_ENCODED, 0))
3422 goto error;
3424 /* XXX: We need to process 'The "N" bit'. */
3426 if (buffer[0] & 1) /* server-update. */
3427 bp->data[2] = 1;
3428 else
3429 bp->data[2] = 0;
3431 if (!save_option_buffer(&fqdn_universe, options, bp, bp->data + 2, 1,
3432 FQDN_SERVER_UPDATE, 0))
3433 goto error;
3435 if (buffer[0] & 2) /* no-client-update. */
3436 bp->data[1] = 1;
3437 else
3438 bp->data[1] = 0;
3440 if (!save_option_buffer(&fqdn_universe, options, bp, bp->data + 1, 1,
3441 FQDN_NO_CLIENT_UPDATE, 0))
3442 goto error;
3444 /* Convert the domain name to textual representation for config. */
3445 len = MRns_name_ntop(buffer + 1, (char *)bp->data + 3, length - 1);
3446 if (len == -1) {
3447 log_error("Unable to convert dhcp6.fqdn domain name to "
3448 "printable form.");
3449 goto error;
3452 /* Save the domain name. */
3453 if (len > 0) {
3454 unsigned char *fqdn_start = bp->data + 3;
3456 if (!save_option_buffer(&fqdn_universe, options, bp,
3457 fqdn_start, len, FQDN_FQDN, 1))
3458 goto error;
3460 first_dot = (unsigned char *)strchr((char *)fqdn_start, '.');
3462 if (first_dot != NULL) {
3463 hlen = first_dot - fqdn_start;
3464 dlen = len - hlen;
3465 } else {
3466 hlen = len;
3467 dlen = 0;
3470 if (!save_option_buffer(&fqdn_universe, options, bp,
3471 fqdn_start, len, FQDN_FQDN, 1) ||
3472 ((hlen > 0) &&
3473 !save_option_buffer(&fqdn_universe, options, bp,
3474 fqdn_start, hlen,
3475 FQDN_HOSTNAME, 0)) ||
3476 ((dlen > 0) &&
3477 !save_option_buffer(&fqdn_universe, options, bp,
3478 first_dot, dlen, FQDN_DOMAINNAME, 0)))
3479 goto error;
3482 buffer_dereference(&bp, MDL);
3483 return 1;
3485 error:
3486 buffer_dereference(&bp, MDL);
3487 return 0;
3490 void option_space_foreach (struct packet *packet, struct lease *lease,
3491 struct client_state *client_state,
3492 struct option_state *in_options,
3493 struct option_state *cfg_options,
3494 struct binding_scope **scope,
3495 struct universe *u, void *stuff,
3496 void (*func) (struct option_cache *,
3497 struct packet *,
3498 struct lease *, struct client_state *,
3499 struct option_state *,
3500 struct option_state *,
3501 struct binding_scope **,
3502 struct universe *, void *))
3504 if (u -> foreach)
3505 (*u -> foreach) (packet, lease, client_state, in_options,
3506 cfg_options, scope, u, stuff, func);
3509 void suboption_foreach (struct packet *packet, struct lease *lease,
3510 struct client_state *client_state,
3511 struct option_state *in_options,
3512 struct option_state *cfg_options,
3513 struct binding_scope **scope,
3514 struct universe *u, void *stuff,
3515 void (*func) (struct option_cache *,
3516 struct packet *,
3517 struct lease *, struct client_state *,
3518 struct option_state *,
3519 struct option_state *,
3520 struct binding_scope **,
3521 struct universe *, void *),
3522 struct option_cache *oc,
3523 const char *vsname)
3525 struct universe *universe = find_option_universe (oc -> option,
3526 vsname);
3527 if (universe -> foreach)
3528 (*universe -> foreach) (packet, lease, client_state,
3529 in_options, cfg_options,
3530 scope, universe, stuff, func);
3533 void hashed_option_space_foreach (struct packet *packet, struct lease *lease,
3534 struct client_state *client_state,
3535 struct option_state *in_options,
3536 struct option_state *cfg_options,
3537 struct binding_scope **scope,
3538 struct universe *u, void *stuff,
3539 void (*func) (struct option_cache *,
3540 struct packet *,
3541 struct lease *,
3542 struct client_state *,
3543 struct option_state *,
3544 struct option_state *,
3545 struct binding_scope **,
3546 struct universe *, void *))
3548 pair *hash;
3549 int i;
3550 struct option_cache *oc;
3552 if (cfg_options -> universe_count <= u -> index)
3553 return;
3555 hash = cfg_options -> universes [u -> index];
3556 if (!hash)
3557 return;
3558 for (i = 0; i < OPTION_HASH_SIZE; i++) {
3559 pair p;
3560 /* XXX save _all_ options! XXX */
3561 for (p = hash [i]; p; p = p -> cdr) {
3562 oc = (struct option_cache *)p -> car;
3563 (*func) (oc, packet, lease, client_state,
3564 in_options, cfg_options, scope, u, stuff);
3569 void
3570 save_linked_option(struct universe *universe, struct option_state *options,
3571 struct option_cache *oc, isc_boolean_t appendp)
3573 pair *tail;
3574 struct option_chain_head *head;
3575 struct option_cache **ocloc;
3577 if (universe -> index >= options -> universe_count)
3578 return;
3579 head = ((struct option_chain_head *)
3580 options -> universes [universe -> index]);
3581 if (!head) {
3582 if (!option_chain_head_allocate (((struct option_chain_head **)
3583 &options -> universes
3584 [universe -> index]), MDL))
3585 return;
3586 head = ((struct option_chain_head *)
3587 options -> universes [universe -> index]);
3590 /* Find the tail of the list. */
3591 for (tail = &head -> first; *tail; tail = &((*tail) -> cdr)) {
3592 ocloc = (struct option_cache **)&(*tail)->car;
3594 if (oc->option->code == (*ocloc)->option->code) {
3595 if (appendp) {
3596 do {
3597 ocloc = &(*ocloc)->next;
3598 } while (*ocloc != NULL);
3599 } else {
3600 option_cache_dereference(ocloc, MDL);
3602 option_cache_reference(ocloc, oc, MDL);
3603 return;
3607 *tail = cons (0, 0);
3608 if (*tail) {
3609 option_cache_reference ((struct option_cache **)
3610 (&(*tail) -> car), oc, MDL);
3614 int linked_option_space_encapsulate (result, packet, lease, client_state,
3615 in_options, cfg_options, scope, universe)
3616 struct data_string *result;
3617 struct packet *packet;
3618 struct lease *lease;
3619 struct client_state *client_state;
3620 struct option_state *in_options;
3621 struct option_state *cfg_options;
3622 struct binding_scope **scope;
3623 struct universe *universe;
3625 int status = 0;
3626 pair oc;
3627 struct option_chain_head *head;
3629 if (universe -> index >= cfg_options -> universe_count)
3630 return status;
3631 head = ((struct option_chain_head *)
3632 cfg_options -> universes [universe -> index]);
3633 if (!head)
3634 return status;
3636 for (oc = head -> first; oc; oc = oc -> cdr) {
3637 if (store_option (result, universe, packet,
3638 lease, client_state, in_options, cfg_options,
3639 scope, (struct option_cache *)(oc -> car)))
3640 status = 1;
3643 if (search_subencapsulation(result, packet, lease, client_state,
3644 in_options, cfg_options, scope, universe))
3645 status = 1;
3647 return status;
3650 void delete_linked_option (universe, options, code)
3651 struct universe *universe;
3652 struct option_state *options;
3653 int code;
3655 pair *tail, tmp = (pair)0;
3656 struct option_chain_head *head;
3658 if (universe -> index >= options -> universe_count)
3659 return;
3660 head = ((struct option_chain_head *)
3661 options -> universes [universe -> index]);
3662 if (!head)
3663 return;
3665 for (tail = &head -> first; *tail; tail = &((*tail) -> cdr)) {
3666 if (code ==
3667 ((struct option_cache *)(*tail) -> car) -> option -> code)
3669 tmp = (*tail) -> cdr;
3670 option_cache_dereference ((struct option_cache **)
3671 (&(*tail) -> car), MDL);
3672 dfree (*tail, MDL);
3673 (*tail) = tmp;
3674 break;
3679 struct option_cache *lookup_linked_option (universe, options, code)
3680 struct universe *universe;
3681 struct option_state *options;
3682 unsigned code;
3684 pair oc;
3685 struct option_chain_head *head;
3687 if (universe -> index >= options -> universe_count)
3688 return 0;
3689 head = ((struct option_chain_head *)
3690 options -> universes [universe -> index]);
3691 if (!head)
3692 return 0;
3694 for (oc = head -> first; oc; oc = oc -> cdr) {
3695 if (code ==
3696 ((struct option_cache *)(oc -> car)) -> option -> code) {
3697 return (struct option_cache *)(oc -> car);
3701 return (struct option_cache *)0;
3704 int linked_option_state_dereference (universe, state, file, line)
3705 struct universe *universe;
3706 struct option_state *state;
3707 const char *file;
3708 int line;
3710 return (option_chain_head_dereference
3711 ((struct option_chain_head **)
3712 (&state -> universes [universe -> index]), MDL));
3715 void linked_option_space_foreach (struct packet *packet, struct lease *lease,
3716 struct client_state *client_state,
3717 struct option_state *in_options,
3718 struct option_state *cfg_options,
3719 struct binding_scope **scope,
3720 struct universe *u, void *stuff,
3721 void (*func) (struct option_cache *,
3722 struct packet *,
3723 struct lease *,
3724 struct client_state *,
3725 struct option_state *,
3726 struct option_state *,
3727 struct binding_scope **,
3728 struct universe *, void *))
3730 pair car;
3731 struct option_chain_head *head;
3733 if (u -> index >= cfg_options -> universe_count)
3734 return;
3735 head = ((struct option_chain_head *)
3736 cfg_options -> universes [u -> index]);
3737 if (!head)
3738 return;
3739 for (car = head -> first; car; car = car -> cdr) {
3740 (*func) ((struct option_cache *)(car -> car),
3741 packet, lease, client_state,
3742 in_options, cfg_options, scope, u, stuff);
3746 void do_packet (interface, packet, len, from_port, from, hfrom)
3747 struct interface_info *interface;
3748 struct dhcp_packet *packet;
3749 unsigned len;
3750 unsigned int from_port;
3751 struct iaddr from;
3752 struct hardware *hfrom;
3754 struct option_cache *op;
3755 struct packet *decoded_packet;
3756 #if defined (DEBUG_MEMORY_LEAKAGE)
3757 unsigned long previous_outstanding = dmalloc_outstanding;
3758 #endif
3760 #if defined (TRACING)
3761 trace_inpacket_stash(interface, packet, len, from_port, from, hfrom);
3762 #endif
3764 decoded_packet = NULL;
3765 if (!packet_allocate(&decoded_packet, MDL)) {
3766 log_error("do_packet: no memory for incoming packet!");
3767 return;
3769 decoded_packet->raw = packet;
3770 decoded_packet->packet_length = len;
3771 decoded_packet->client_port = from_port;
3772 decoded_packet->client_addr = from;
3773 interface_reference(&decoded_packet->interface, interface, MDL);
3774 decoded_packet->haddr = hfrom;
3776 if (packet->hlen > sizeof packet->chaddr) {
3777 packet_dereference(&decoded_packet, MDL);
3778 log_info("Discarding packet with bogus hlen.");
3779 return;
3782 /* If there's an option buffer, try to parse it. */
3783 if (decoded_packet->packet_length >= DHCP_FIXED_NON_UDP + 4) {
3784 if (!parse_options(decoded_packet)) {
3785 if (decoded_packet->options)
3786 option_state_dereference
3787 (&decoded_packet->options, MDL);
3788 packet_dereference (&decoded_packet, MDL);
3789 return;
3792 if (decoded_packet->options_valid &&
3793 (op = lookup_option(&dhcp_universe,
3794 decoded_packet->options,
3795 DHO_DHCP_MESSAGE_TYPE))) {
3796 struct data_string dp;
3797 memset(&dp, 0, sizeof dp);
3798 evaluate_option_cache(&dp, decoded_packet, NULL, NULL,
3799 decoded_packet->options, NULL,
3800 NULL, op, MDL);
3801 if (dp.len > 0)
3802 decoded_packet->packet_type = dp.data[0];
3803 else
3804 decoded_packet->packet_type = 0;
3805 data_string_forget(&dp, MDL);
3809 if (validate_packet(decoded_packet) != 0) {
3810 if (decoded_packet->packet_type)
3811 dhcp(decoded_packet);
3812 else
3813 bootp(decoded_packet);
3816 /* If the caller kept the packet, they'll have upped the refcnt. */
3817 packet_dereference(&decoded_packet, MDL);
3819 #if defined (DEBUG_MEMORY_LEAKAGE)
3820 log_info("generation %ld: %ld new, %ld outstanding, %ld long-term",
3821 dmalloc_generation,
3822 dmalloc_outstanding - previous_outstanding,
3823 dmalloc_outstanding, dmalloc_longterm);
3824 dmalloc_dump_outstanding();
3825 #endif
3826 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
3827 dump_rc_history(0);
3828 #endif
3832 packet6_len_okay(const char *packet, int len) {
3833 if (len < 1) {
3834 return 0;
3836 if ((packet[0] == DHCPV6_RELAY_FORW) ||
3837 (packet[0] == DHCPV6_RELAY_REPL)) {
3838 if (len >= offsetof(struct dhcpv6_relay_packet, options)) {
3839 return 1;
3840 } else {
3841 return 0;
3843 } else {
3844 if (len >= offsetof(struct dhcpv6_packet, options)) {
3845 return 1;
3846 } else {
3847 return 0;
3852 #ifdef DHCPv6
3853 void
3854 do_packet6(struct interface_info *interface, const char *packet,
3855 int len, int from_port, const struct iaddr *from,
3856 isc_boolean_t was_unicast) {
3857 unsigned char msg_type;
3858 const struct dhcpv6_packet *msg;
3859 const struct dhcpv6_relay_packet *relay;
3860 struct packet *decoded_packet;
3861 #if defined (DEBUG_MEMORY_LEAKAGE)
3862 unsigned long previous_outstanding = dmalloc_outstanding;
3863 #endif
3865 if (!packet6_len_okay(packet, len)) {
3866 log_info("do_packet6: "
3867 "short packet from %s port %d, len %d, dropped",
3868 piaddr(*from), from_port, len);
3869 return;
3872 decoded_packet = NULL;
3873 if (!packet_allocate(&decoded_packet, MDL)) {
3874 log_error("do_packet6: no memory for incoming packet.");
3875 return;
3878 if (!option_state_allocate(&decoded_packet->options, MDL)) {
3879 log_error("do_packet6: no memory for options.");
3880 packet_dereference(&decoded_packet, MDL);
3881 return;
3884 /* IPv4 information, already set to 0 */
3885 /* decoded_packet->packet_type = 0; */
3886 /* memset(&decoded_packet->haddr, 0, sizeof(decoded_packet->haddr)); */
3887 /* decoded_packet->circuit_id = NULL; */
3888 /* decoded_packet->circuit_id_len = 0; */
3889 /* decoded_packet->remote_id = NULL; */
3890 /* decoded_packet->remote_id_len = 0; */
3891 decoded_packet->raw = (struct dhcp_packet *)packet;
3892 decoded_packet->packet_length = (unsigned)len;
3893 decoded_packet->client_port = from_port;
3894 decoded_packet->client_addr = *from;
3895 interface_reference(&decoded_packet->interface, interface, MDL);
3897 decoded_packet->unicast = was_unicast;
3899 msg_type = packet[0];
3900 if ((msg_type == DHCPV6_RELAY_FORW) ||
3901 (msg_type == DHCPV6_RELAY_REPL)) {
3902 int relaylen = (int)(offsetof(struct dhcpv6_relay_packet, options));
3903 relay = (const struct dhcpv6_relay_packet *)packet;
3904 decoded_packet->dhcpv6_msg_type = relay->msg_type;
3906 /* relay-specific data */
3907 decoded_packet->dhcpv6_hop_count = relay->hop_count;
3908 memcpy(&decoded_packet->dhcpv6_link_address,
3909 relay->link_address, sizeof(relay->link_address));
3910 memcpy(&decoded_packet->dhcpv6_peer_address,
3911 relay->peer_address, sizeof(relay->peer_address));
3913 if (!parse_option_buffer(decoded_packet->options,
3914 relay->options, len - relaylen,
3915 &dhcpv6_universe)) {
3916 /* no logging here, as parse_option_buffer() logs all
3917 cases where it fails */
3918 packet_dereference(&decoded_packet, MDL);
3919 return;
3921 } else {
3922 int msglen = (int)(offsetof(struct dhcpv6_packet, options));
3923 msg = (const struct dhcpv6_packet *)packet;
3924 decoded_packet->dhcpv6_msg_type = msg->msg_type;
3926 /* message-specific data */
3927 memcpy(decoded_packet->dhcpv6_transaction_id,
3928 msg->transaction_id,
3929 sizeof(decoded_packet->dhcpv6_transaction_id));
3931 if (!parse_option_buffer(decoded_packet->options,
3932 msg->options, len - msglen,
3933 &dhcpv6_universe)) {
3934 /* no logging here, as parse_option_buffer() logs all
3935 cases where it fails */
3936 packet_dereference(&decoded_packet, MDL);
3937 return;
3941 dhcpv6(decoded_packet);
3943 packet_dereference(&decoded_packet, MDL);
3945 #if defined (DEBUG_MEMORY_LEAKAGE)
3946 log_info("generation %ld: %ld new, %ld outstanding, %ld long-term",
3947 dmalloc_generation,
3948 dmalloc_outstanding - previous_outstanding,
3949 dmalloc_outstanding, dmalloc_longterm);
3950 dmalloc_dump_outstanding();
3951 #endif
3952 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
3953 dump_rc_history(0);
3954 #endif
3956 #endif /* DHCPv6 */
3959 pretty_escape(char **dst, char *dend, const unsigned char **src,
3960 const unsigned char *send)
3962 int count = 0;
3964 /* If there aren't as many bytes left as there are in the source
3965 * buffer, don't even bother entering the loop.
3967 if (dst == NULL || dend == NULL || src == NULL || send == NULL ||
3968 *dst == NULL || *src == NULL || (*dst >= dend) || (*src > send) ||
3969 ((send - *src) > (dend - *dst)))
3970 return -1;
3972 for ( ; *src < send ; (*src)++) {
3973 if (!isascii (**src) || !isprint (**src)) {
3974 /* Skip trailing NUL. */
3975 if ((*src + 1) != send || **src != '\0') {
3976 if (*dst + 4 > dend)
3977 return -1;
3979 sprintf(*dst, "\\%03o",
3980 **src);
3981 (*dst) += 4;
3982 count += 4;
3984 } else if (**src == '"' || **src == '\'' || **src == '$' ||
3985 **src == '`' || **src == '\\' || **src == '|' ||
3986 **src == '&') {
3987 if (*dst + 2 > dend)
3988 return -1;
3990 **dst = '\\';
3991 (*dst)++;
3992 **dst = **src;
3993 (*dst)++;
3994 count += 2;
3995 } else {
3996 if (*dst + 1 > dend)
3997 return -1;
3999 **dst = **src;
4000 (*dst)++;
4001 count++;
4005 return count;
4008 static int
4009 pretty_text(char **dst, char *dend, const unsigned char **src,
4010 const unsigned char *send, int emit_quotes)
4012 int count;
4014 if (dst == NULL || dend == NULL || src == NULL || send == NULL ||
4015 *dst == NULL || *src == NULL ||
4016 ((*dst + (emit_quotes ? 2 : 0)) > dend) || (*src > send))
4017 return -1;
4019 if (emit_quotes) {
4020 **dst = '"';
4021 (*dst)++;
4024 /* dend-1 leaves 1 byte for the closing quote. */
4025 count = pretty_escape(dst, dend - (emit_quotes ? 1 : 0), src, send);
4027 if (count == -1)
4028 return -1;
4030 if (emit_quotes && (*dst < dend)) {
4031 **dst = '"';
4032 (*dst)++;
4034 /* Includes quote prior to pretty_escape(); */
4035 count += 2;
4038 return count;
4041 static int
4042 pretty_domain(char **dst, char *dend, const unsigned char **src,
4043 const unsigned char *send)
4045 const unsigned char *tend;
4046 int count = 2;
4047 int tsiz, status;
4049 if (dst == NULL || dend == NULL || src == NULL || send == NULL ||
4050 *dst == NULL || *src == NULL ||
4051 ((*dst + 2) > dend) || (*src >= send))
4052 return -1;
4054 **dst = '"';
4055 (*dst)++;
4057 do {
4058 /* Continue loop until end of src buffer. */
4059 if (*src >= send)
4060 break;
4062 /* Consume tag size. */
4063 tsiz = **src;
4064 (*src)++;
4066 /* At root, finis. */
4067 if (tsiz == 0)
4068 break;
4070 tend = (*src) + tsiz;
4072 /* If the tag exceeds the source buffer, it's illegal.
4073 * This should also trap compression pointers (which should
4074 * not be in these buffers).
4076 if (tend > send)
4077 return -1;
4079 /* dend-2 leaves room for a trailing dot and quote. */
4080 status = pretty_escape(dst, dend-2, src, tend);
4082 if ((status == -1) || ((*dst + 2) > dend))
4083 return -1;
4085 **dst = '.';
4086 (*dst)++;
4087 count += status + 1;
4089 while(1);
4091 **dst = '"';
4092 (*dst)++;
4094 return count;
4098 * Add the option identified with the option number and data to the
4099 * options state.
4102 add_option(struct option_state *options,
4103 unsigned int option_num,
4104 void *data,
4105 unsigned int data_len)
4107 struct option_cache *oc;
4108 struct option *option;
4110 /* INSIST(options != NULL); */
4111 /* INSIST(data != NULL); */
4113 option = NULL;
4114 if (!option_code_hash_lookup(&option, dhcp_universe.code_hash,
4115 &option_num, 0, MDL)) {
4116 log_error("Attempting to add unknown option %d.", option_num);
4117 return 0;
4120 oc = NULL;
4121 if (!option_cache_allocate(&oc, MDL)) {
4122 log_error("No memory for option cache adding %s (option %d).",
4123 option->name, option_num);
4124 return 0;
4127 if (!make_const_data(&oc->expression,
4128 data,
4129 data_len,
4132 MDL)) {
4133 log_error("No memory for constant data adding %s (option %d).",
4134 option->name, option_num);
4135 option_cache_dereference(&oc, MDL);
4136 return 0;
4139 option_reference(&(oc->option), option, MDL);
4140 save_option(&dhcp_universe, options, oc);
4141 option_cache_dereference(&oc, MDL);
4143 return 1;
4147 * Checks if received BOOTP/DHCPv4 packet is sane
4149 * @param packet received, decoded packet
4151 * @return 1 if packet is sane, 0 if it is not
4153 int validate_packet(struct packet *packet)
4155 struct option_cache *oc = NULL;
4157 oc = lookup_option (&dhcp_universe, packet->options,
4158 DHO_DHCP_CLIENT_IDENTIFIER);
4159 if (oc) {
4160 /* Let's check if client-identifier is sane */
4161 if (oc->data.len == 0) {
4162 log_debug("Dropped DHCPv4 packet with zero-length client-id");
4163 return (0);
4165 } else if (oc->data.len == 1) {
4167 * RFC2132, section 9.14 states that minimum length of client-id
4168 * is 2. We will allow single-character client-ids for now (for
4169 * backwards compatibility), but warn the user that support for
4170 * this is against the standard.
4172 log_debug("Accepted DHCPv4 packet with one-character client-id - "
4173 "a future version of ISC DHCP will reject this");
4175 } else {
4177 * If hlen is 0 we don't have any identifier, we warn the user
4178 * but continue processing the packet as we can.
4180 if (packet->raw->hlen == 0) {
4181 log_debug("Received DHCPv4 packet without client-id"
4182 " option and empty hlen field.");
4186 /* @todo: Add checks for other received options */
4188 return (1);