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