⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 options.c

📁 DHCP服务器源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* options.c   DHCP options parsing and reassembly. *//* * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * *   Internet Systems Consortium, Inc. *   950 Charter Street *   Redwood City, CA 94063 *   <info@isc.org> *   http://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems 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.13 2004/06/10 17:59:19 dhankins Exp $ Copyright (c) 2004 Internet Systems 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] &&		    !((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)))) {		    op = lookup_option (universe, options, code);		    if (op) {			struct data_string new;			memset (&new, 0, sizeof new);			if (!buffer_allocate (&new.buffer, op -> data.len + len,					      MDL)) {			    log_error ("parse_option_buffer: No memory.");			    return 0;			}			memcpy (new.buffer -> data, op -> data.data,				op -> data.len);			memcpy (&new.buffer -> data [op -> data.len],				&bp -> data [offset + 2], len);			new.len = op -> data.len + len;			new.data = new.buffer -> data;			data_string_forget (&op -> data, MDL);			data_string_copy (&op -> data, &new, MDL);			data_string_forget (&new, MDL);		    } else {			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 + 1;		}		/* We wind up with a length that's one too many because		   we shouldn't increment for the last label, but there's		   no way to tell we're at the last label until we exit		   the loop.   :'*/		if (total_len > 0)			total_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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -