📄 options.c
字号:
/* options.c DHCP options parsing and reassembly. *//* * Copyright (c) 1995-2001 Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of The Internet Software Consortium nor the names * of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about the Internet Software Consortium, see * ``http://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */#ifndef lintstatic char copyright[] ="$Id: options.c,v 1.85.2.5 2001/08/23 16:11:34 mellon Exp $ Copyright (c) 1995-2001 The Internet Software Consortium. All rights reserved.\n";#endif /* not lint */#define DHCP_OPTION_DATA#include "dhcpd.h"#include <omapip/omapip_p.h>struct option *vendor_cfg_option;static void do_option_set PROTO ((pair *, struct option_cache *, enum statement_op));/* Parse all available options out of the specified packet. */int parse_options (packet) struct packet *packet;{ int i; struct option_cache *op = (struct option_cache *)0; /* Allocate a new option state. */ if (!option_state_allocate (&packet -> options, MDL)) { packet -> options_valid = 0; return 0; } /* If we don't see the magic cookie, there's nothing to parse. */ if (memcmp (packet -> raw -> options, DHCP_OPTIONS_COOKIE, 4)) { packet -> options_valid = 0; return 1; } /* Go through the options field, up to the end of the packet or the End field. */ if (!parse_option_buffer (packet -> options, &packet -> raw -> options [4], (packet -> packet_length - DHCP_FIXED_NON_UDP - 4), &dhcp_universe)) return 0; /* If we parsed a DHCP Option Overload option, parse more options out of the buffer(s) containing them. */ if (packet -> options_valid && (op = lookup_option (&dhcp_universe, packet -> options, DHO_DHCP_OPTION_OVERLOAD))) { if (op -> data.data [0] & 1) { if (!parse_option_buffer (packet -> options, (unsigned char *)packet -> raw -> file, sizeof packet -> raw -> file, &dhcp_universe)) return 0; } if (op -> data.data [0] & 2) { if (!parse_option_buffer (packet -> options, (unsigned char *)packet -> raw -> sname, sizeof packet -> raw -> sname, &dhcp_universe)) return 0; } } packet -> options_valid = 1; return 1;}/* Parse options out of the specified buffer, storing addresses of option values in packet -> options and setting packet -> options_valid if no errors are encountered. */int parse_option_buffer (options, buffer, length, universe) struct option_state *options; const unsigned char *buffer; unsigned length; struct universe *universe;{ unsigned char *t; const unsigned char *end = buffer + length; unsigned len, offset; int code; struct option_cache *op = (struct option_cache *)0; struct buffer *bp = (struct buffer *)0; if (!buffer_allocate (&bp, length, MDL)) { log_error ("no memory for option buffer."); return 0; } memcpy (bp -> data, buffer, length); for (offset = 0; buffer [offset] != DHO_END && offset < length; ) { code = buffer [offset]; /* Pad options don't have a length - just skip them. */ if (code == DHO_PAD) { ++offset; continue; } /* Don't look for length if the buffer isn't that big. */ if (offset + 2 > length) { len = 65536; goto bogus; } /* All other fields (except end, see above) have a one-byte length. */ len = buffer [offset + 1]; /* If the length is outrageous, the options are bad. */ if (offset + len + 2 > length) { bogus: log_error ("parse_option_buffer: option %s (%d) %s.", dhcp_options [code].name, len, "larger than buffer"); buffer_dereference (&bp, MDL); return 0; } /* If the option contains an encapsulation, parse it. If the parse fails, or the option isn't an encapsulation (by far the most common case), or the option isn't entirely an encapsulation, keep the raw data as well. */ if (!((universe -> options [code] -> format [0] == 'e' || universe -> options [code] -> format [0] == 'E') && (parse_encapsulated_suboptions (options, universe -> options [code], buffer + offset + 2, len, universe, (const char *)0)))) { save_option_buffer (universe, options, bp, &bp -> data [offset + 2], len, universe -> options [code], 1); } offset += len + 2; } buffer_dereference (&bp, MDL); return 1;}/* If an option in an option buffer turns out to be an encapsulation, figure out what to do. If we don't know how to de-encapsulate it, or it's not well-formed, return zero; otherwise, return 1, indicating that we succeeded in de-encapsulating it. */struct universe *find_option_universe (struct option *eopt, const char *uname){ int i; char *s, *t; struct universe *universe = (struct universe *)0; /* Look for the E option in the option format. */ s = strchr (eopt -> format, 'E'); if (!s) { log_error ("internal encapsulation format error 1."); return 0; } /* Look for the universe name in the option format. */ t = strchr (++s, '.'); /* If there was no trailing '.', or there's something after the trailing '.', the option is bogus and we can't use it. */ if (!t || t [1]) { log_error ("internal encapsulation format error 2."); return 0; } if (t == s && uname) { for (i = 0; i < universe_count; i++) { if (!strcmp (universes [i] -> name, uname)) { universe = universes [i]; break; } } } else if (t != s) { for (i = 0; i < universe_count; i++) { if (strlen (universes [i] -> name) == t - s && !memcmp (universes [i] -> name, s, (unsigned)(t - s))) { universe = universes [i]; break; } } } return universe;}/* If an option in an option buffer turns out to be an encapsulation, figure out what to do. If we don't know how to de-encapsulate it, or it's not well-formed, return zero; otherwise, return 1, indicating that we succeeded in de-encapsulating it. */int parse_encapsulated_suboptions (struct option_state *options, struct option *eopt, const unsigned char *buffer, unsigned len, struct universe *eu, const char *uname){ int i; struct universe *universe = find_option_universe (eopt, uname); /* If we didn't find the universe, we can't do anything with it right now (e.g., we can't decode vendor options until we've decoded the packet and executed the scopes that it matches). */ if (!universe) return 0; /* If we don't have a decoding function for it, we can't decode it. */ if (!universe -> decode) return 0; i = (*universe -> decode) (options, buffer, len, universe); /* If there is stuff before the suboptions, we have to keep it. */ if (eopt -> format [0] != 'E') return 0; /* Otherwise, return the status of the decode function. */ return i;}int fqdn_universe_decode (struct option_state *options, const unsigned char *buffer, unsigned length, struct universe *u){ char *name; struct buffer *bp = (struct buffer *)0; /* FQDN options have to be at least four bytes long. */ if (length < 3) return 0; /* Save the contents of the option in a buffer. */ if (!buffer_allocate (&bp, length + 4, MDL)) { log_error ("no memory for option buffer."); return 0; } memcpy (&bp -> data [3], buffer + 1, length - 1); if (buffer [0] & 4) /* encoded */ bp -> data [0] = 1; else bp -> data [0] = 0; if (!save_option_buffer (&fqdn_universe, options, bp, &bp -> data [0], 1, &fqdn_options [FQDN_ENCODED], 0)) { bad: buffer_dereference (&bp, MDL); return 0; } if (buffer [0] & 1) /* server-update */ bp -> data [2] = 1; else bp -> data [2] = 0; if (buffer [0] & 2) /* no-client-update */ bp -> data [1] = 1; else bp -> data [1] = 0; /* XXX Ideally we should store the name in DNS format, so if the XXX label isn't in DNS format, we convert it to DNS format, XXX rather than converting labels specified in DNS format to XXX the plain ASCII representation. But that's hard, so XXX not now. */ /* Not encoded using DNS format? */ if (!bp -> data [0]) { unsigned i; /* Some broken clients NUL-terminate this option. */ if (buffer [length - 1] == 0) { --length; bp -> data [1] = 1; } /* Determine the length of the hostname component of the name. If the name contains no '.' character, it represents a non-qualified label. */ for (i = 3; i < length && buffer [i] != '.'; i++); i -= 3; /* Note: If the client sends a FQDN, the first '.' will be used as a NUL terminator for the hostname. */ if (i) if (!save_option_buffer (&fqdn_universe, options, bp, &bp -> data[5], i, &fqdn_options [FQDN_HOSTNAME], 0)) goto bad; /* Note: If the client sends a single label, the FQDN_DOMAINNAME option won't be set. */ if (length > 4 + i && !save_option_buffer (&fqdn_universe, options, bp, &bp -> data[6 + i], length - 4 - i, &fqdn_options [FQDN_DOMAINNAME], 1)) goto bad; /* Also save the whole name. */ if (length > 3) if (!save_option_buffer (&fqdn_universe, options, bp, &bp -> data [5], length - 3, &fqdn_options [FQDN_FQDN], 1)) goto bad; } else { unsigned len; unsigned total_len = 0; unsigned first_len = 0; int terminated = 0; unsigned char *s; s = &bp -> data[5]; while (s < &bp -> data[0] + length + 2) { len = *s; if (len > 63) { log_info ("fancy bits in fqdn option"); return 0; } if (len == 0) { terminated = 1; break; } if (s + len > &bp -> data [0] + length + 3) { log_info ("fqdn tag longer than buffer"); return 0; } if (first_len == 0) { first_len = len; } *s = '.'; s += len + 1; total_len += len; } if (!terminated) { first_len = total_len; } if (first_len > 0 && !save_option_buffer (&fqdn_universe, options, bp, &bp -> data[6], first_len, &fqdn_options [FQDN_HOSTNAME], 0)) goto bad; if (total_len > 0 && first_len != total_len) { if (!save_option_buffer (&fqdn_universe, options, bp, &bp -> data[6 + first_len], total_len - first_len, &fqdn_options [FQDN_DOMAINNAME], 1)) goto bad; } if (total_len > 0) if (!save_option_buffer (&fqdn_universe, options, bp, &bp -> data [6], total_len, &fqdn_options [FQDN_FQDN], 1)) goto bad; } if (!save_option_buffer (&fqdn_universe, options, bp, &bp -> data [1], 1, &fqdn_options [FQDN_NO_CLIENT_UPDATE], 0)) goto bad; if (!save_option_buffer (&fqdn_universe, options, bp, &bp -> data [2], 1, &fqdn_options [FQDN_SERVER_UPDATE], 0)) goto bad; if (!save_option_buffer (&fqdn_universe, options, bp, &bp -> data [3], 1, &fqdn_options [FQDN_RCODE1], 0)) goto bad; if (!save_option_buffer (&fqdn_universe, options, bp, &bp -> data [4], 1, &fqdn_options [FQDN_RCODE2], 0)) goto bad; buffer_dereference (&bp, MDL); return 1;}/* cons options into a big buffer, and then split them out into the three seperate buffers if needed. This allows us to cons up a set of vendor options using the same routine. */int cons_options (inpacket, outpacket, lease, client_state, mms, in_options, cfg_options, scope, overload, terminate, bootpp, prl, vuname) struct packet *inpacket; struct dhcp_packet *outpacket; struct lease *lease; struct client_state *client_state; int mms; struct option_state *in_options; struct option_state *cfg_options; struct binding_scope **scope; int overload; /* Overload flags that may be set. */ int terminate; int bootpp; struct data_string *prl; const char *vuname;{#define PRIORITY_COUNT 300
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -