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

📄 options.c

📁 DHCP服务器源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	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	unsigned priority_list [PRIORITY_COUNT];	int priority_len;	unsigned char buffer [4096];	/* Really big buffer... */	unsigned main_buffer_size;	unsigned mainbufix, bufix, agentix;	unsigned option_size;	unsigned length;	int i;	struct option_cache *op;	struct data_string ds;	pair pp, *hash;	int need_endopt = 0;	int have_sso = 0;	memset (&ds, 0, sizeof ds);	/* If there's a Maximum Message Size option in the incoming packet	   and no alternate maximum message size has been specified, take the	   one in the packet. */	if (inpacket &&	    (op = lookup_option (&dhcp_universe, inpacket -> options,				 DHO_DHCP_MAX_MESSAGE_SIZE))) {		evaluate_option_cache (&ds, inpacket,				       lease, client_state, in_options,				       cfg_options, scope, op, MDL);		if (ds.len >= sizeof (u_int16_t)) {			i = getUShort (ds.data);			if(!mms || (i < mms))				mms = i;		}		data_string_forget (&ds, MDL);	}	/* If the client has provided a maximum DHCP message size,	   use that; otherwise, if it's BOOTP, only 64 bytes; otherwise	   use up to the minimum IP MTU size (576 bytes). */	/* XXX if a BOOTP client specifies a max message size, we will	   honor it. */	if (mms) {		main_buffer_size = mms - DHCP_FIXED_LEN;		/* Enforce a minimum packet size... */		if (main_buffer_size < (576 - DHCP_FIXED_LEN))			main_buffer_size = 576 - DHCP_FIXED_LEN;	} else if (bootpp) {		if (inpacket) {			main_buffer_size =				inpacket -> packet_length - DHCP_FIXED_LEN;			if (main_buffer_size < 64)				main_buffer_size = 64;		} else			main_buffer_size = 64;	} else		main_buffer_size = 576 - DHCP_FIXED_LEN;	/* Set a hard limit at the size of the output buffer. */	if (main_buffer_size > sizeof buffer)		main_buffer_size = sizeof buffer;	/* Preload the option priority list with mandatory options. */	priority_len = 0;	priority_list [priority_len++] = DHO_DHCP_MESSAGE_TYPE;	priority_list [priority_len++] = DHO_DHCP_SERVER_IDENTIFIER;	priority_list [priority_len++] = DHO_DHCP_LEASE_TIME;	priority_list [priority_len++] = DHO_DHCP_MESSAGE;	priority_list [priority_len++] = DHO_DHCP_REQUESTED_ADDRESS;	priority_list [priority_len++] = DHO_FQDN;	if (prl && prl -> len > 0) {		if ((op = lookup_option (&dhcp_universe, cfg_options,					 DHO_SUBNET_SELECTION))) {			if (priority_len < PRIORITY_COUNT)				priority_list [priority_len++] =					DHO_SUBNET_SELECTION;		}			    		data_string_truncate (prl, (PRIORITY_COUNT - priority_len));		for (i = 0; i < prl -> len; i++) {			/* Prevent client from changing order of delivery			   of relay agent information option. */			if (prl -> data [i] != DHO_DHCP_AGENT_OPTIONS)				priority_list [priority_len++] =					prl -> data [i];		}	} else {		/* First, hardcode some more options that ought to be		   sent first... */		priority_list [priority_len++] = DHO_SUBNET_MASK;		priority_list [priority_len++] = DHO_ROUTERS;		priority_list [priority_len++] = DHO_DOMAIN_NAME_SERVERS;		priority_list [priority_len++] = DHO_HOST_NAME;		/* Append a list of the standard DHCP options from the		   standard DHCP option space.  Actually, if a site		   option space hasn't been specified, we wind up		   treating the dhcp option space as the site option		   space, and the first for loop is skipped, because		   it's slightly more general to do it this way,		   taking the 1Q99 DHCP futures work into account. */		if (cfg_options -> site_code_min) {		    for (i = 0; i < OPTION_HASH_SIZE; i++) {			hash = cfg_options -> universes [dhcp_universe.index];			if (hash) {			    for (pp = hash [i]; pp; pp = pp -> cdr) {				op = (struct option_cache *)(pp -> car);				if (op -> option -> code <				    cfg_options -> site_code_min &&				    priority_len < PRIORITY_COUNT &&				    (op -> option -> code !=				     DHO_DHCP_AGENT_OPTIONS))					priority_list [priority_len++] =						op -> option -> code;			    }			}		    }		}		/* Now cycle through the site option space, or if there		   is no site option space, we'll be cycling through the		   dhcp option space. */		for (i = 0; i < OPTION_HASH_SIZE; i++) {		    hash = (cfg_options -> universes			    [cfg_options -> site_universe]);		    if (hash)			for (pp = hash [i]; pp; pp = pp -> cdr) {				op = (struct option_cache *)(pp -> car);				if (op -> option -> code >=				    cfg_options -> site_code_min &&				    priority_len < PRIORITY_COUNT &&				    (op -> option -> code !=				     DHO_DHCP_AGENT_OPTIONS))					priority_list [priority_len++] =						op -> option -> code;			}		}		/* Now go through all the universes for which options		   were set and see if there are encapsulations for		   them; if there are, put the encapsulation options		   on the priority list as well. */		for (i = 0; i < cfg_options -> universe_count; i++) {		    if (cfg_options -> universes [i] &&			universes [i] -> enc_opt &&			priority_len < PRIORITY_COUNT &&			universes [i] -> enc_opt -> universe == &dhcp_universe)		    {			    if (universes [i] -> enc_opt -> code !=				DHO_DHCP_AGENT_OPTIONS)				    priority_list [priority_len++] =					    universes [i] -> enc_opt -> code;		    }		}		/* The vendor option space can't stand on its own, so always		   add it to the list. */		if (priority_len < PRIORITY_COUNT)			priority_list [priority_len++] =				DHO_VENDOR_ENCAPSULATED_OPTIONS;	}	/* Copy the options into the big buffer... */	option_size = store_options (buffer,				     (main_buffer_size - 7 +				      ((overload & 1) ? DHCP_FILE_LEN : 0) +				      ((overload & 2) ? DHCP_SNAME_LEN : 0)),				     inpacket, lease, client_state,				     in_options, cfg_options, scope,				     priority_list, priority_len,				     main_buffer_size,				     (main_buffer_size +				      ((overload & 1) ? DHCP_FILE_LEN : 0)),				     terminate, vuname);	/* Put the cookie up front... */	memcpy (outpacket -> options, DHCP_OPTIONS_COOKIE, 4);	mainbufix = 4;	/* If we're going to have to overload, store the overload	   option at the beginning.  If we can, though, just store the	   whole thing in the packet's option buffer and leave it at	   that. */	if (option_size <= main_buffer_size - mainbufix) {		memcpy (&outpacket -> options [mainbufix],			buffer, option_size);		mainbufix += option_size;		agentix = mainbufix;		if (mainbufix < main_buffer_size)			need_endopt = 1;		length = DHCP_FIXED_NON_UDP + mainbufix;	} else {		outpacket -> options [mainbufix++] = DHO_DHCP_OPTION_OVERLOAD;		outpacket -> options [mainbufix++] = 1;		if (option_size > main_buffer_size - mainbufix + DHCP_FILE_LEN)			outpacket -> options [mainbufix++] = 3;		else			outpacket -> options [mainbufix++] = 1;		memcpy (&outpacket -> options [mainbufix],			buffer, main_buffer_size - mainbufix);		length = DHCP_FIXED_NON_UDP + main_buffer_size;		agentix = main_buffer_size;		bufix = main_buffer_size - mainbufix;		if (overload & 1) {			if (option_size - bufix <= DHCP_FILE_LEN) {				memcpy (outpacket -> file,					&buffer [bufix], option_size - bufix);				mainbufix = option_size - bufix;				if (mainbufix < DHCP_FILE_LEN)					outpacket -> file [mainbufix++]						= DHO_END;				while (mainbufix < DHCP_FILE_LEN)					outpacket -> file [mainbufix++]						= DHO_PAD;			} else {				memcpy (outpacket -> file,					&buffer [bufix], DHCP_FILE_LEN);				bufix += DHCP_FILE_LEN;			}		}		if ((overload & 2) && option_size < bufix) {			memcpy (outpacket -> sname,				&buffer [bufix], option_size - bufix);			mainbufix = option_size - bufix;			if (mainbufix < DHCP_SNAME_LEN)				outpacket -> file [mainbufix++]					= DHO_END;			while (mainbufix < DHCP_SNAME_LEN)				outpacket -> file [mainbufix++]					= DHO_PAD;		}	}	/* Now hack in the agent options if there are any. */	priority_list [0] = DHO_DHCP_AGENT_OPTIONS;	priority_len = 1;	agentix +=		store_options (&outpacket -> options [agentix],			       1500 - DHCP_FIXED_LEN - agentix,			       inpacket, lease, client_state,			       in_options, cfg_options, scope,			       priority_list, priority_len,			       1500 - DHCP_FIXED_LEN - agentix,			       1500 - DHCP_FIXED_LEN - agentix, 0, (char *)0);	/* Tack a DHO_END option onto the packet if we need to. */	if (agentix < 1500 - DHCP_FIXED_LEN && need_endopt)		outpacket -> options [agentix++] = DHO_END;	/* Figure out the length. */	length = DHCP_FIXED_NON_UDP + agentix;	return length;}/* Store all the requested options into the requested buffer. */int store_options (buffer, buflen, packet, lease, client_state,		   in_options, cfg_options, scope, priority_list, priority_len,		   first_cutoff, second_cutoff, terminate, vuname)	unsigned char *buffer;	unsigned buflen;	struct packet *packet;	struct lease *lease;	struct client_state *client_state;	struct option_state *in_options;	struct option_state *cfg_options;	struct binding_scope **scope;	unsigned *priority_list;	int priority_len;	unsigned first_cutoff, second_cutoff;	int terminate;	const char *vuname;{	int bufix = 0;	int i;	int ix;	int tto;	struct data_string od;	struct option_cache *oc;	unsigned code;	int optstart;	memset (&od, 0, sizeof od);	/* Eliminate duplicate options in the parameter request list.	   There's got to be some clever knuthian way to do this:	   Eliminate all but the first occurance of a value in an array	   of values without otherwise disturbing the order of the array. */	for (i = 0; i < priority_len - 1; i++) {		tto = 0;		for (ix = i + 1; ix < priority_len + tto; ix++) {			if (tto)				priority_list [ix - tto] =					priority_list [ix];			if (priority_list [i] == priority_list [ix]) {				tto++;				priority_len--;			}		}	}	/* Copy out the options in the order that they appear in the	   priority list... */	for (i = 0; i < priority_len; i++) {	    /* Number of bytes left to store (some may already	       have been stored by a previous pass). */	    unsigned length;	    int optstart;	    struct universe *u;	    int have_encapsulation = 0;	    struct data_string encapsulation;	    memset (&encapsulation, 0, sizeof encapsulation);	    /* Code for next option to try to store. */	    code = priority_list [i];	    	    /* Look up the option in the site option space if the code	       is above the cutoff, otherwise in the DHCP option space. */	    if (code >= cfg_options -> site_code_min)		    u = universes [cfg_options -> site_universe];	    else		    u = &dhcp_universe;	    oc = lookup_option (u, cfg_options, code);	    /* It's an encapsulation, try to find the universe	       to be encapsulated first, except that if it's a straight	       encapsulation and the user has provided a value for the	       encapsulation option, use the user-provided value. */	    if (u -> options [code] &&		((u -> options [code] -> format [0] == 'E' && !oc) ||		 u -> options [code] -> format [0] == 'e')) {		int uix;		static char *s, *t;		struct option_cache *tmp;		struct data_string name;		s = strchr (u -> options [code] -> format, 'E');		if (s)		    t = strchr (++s, '.');		if (s && t) {		    memset (&name, 0, sizeof name);		    /* A zero-length universe name means the vendor		       option space, if one is defined. */		    if (t == s) {			if (vendor_cfg_option) {			    tmp = lookup_option (vendor_cfg_option -> universe,						 cfg_options,						 vendor_cfg_option -> code);			    if (tmp)				evaluate_option_cache (&name, packet, lease,						       client_state,						       in_options,						       cfg_options,						       scope, tmp, MDL);			} else if (vuname) {			    name.data = (unsigned char *)s;			    name.len = strlen (s);			}		    } else {			name.data = (unsigned char *)s;			name.len = t - s;		    }					    /* If we found a universe, and there are options configured		       for that universe, try to encapsulate it. */		    if (name.len) {			have_encapsulation =				(option_space_encapsulate				 (&encapsulation, packet, lease, client_state,				  in_options, cfg_options, scope, &name));			data_string_forget (&name, MDL);		    }		}	    }	    /* In order to avoid memory leaks, we have to get to here	       with any option cache that we allocated in tmp not being	       referenced by tmp, and whatever option cache is referenced	       by oc being an actual reference.   lookup_option doesn't	       generate a reference (this needs to be fixed), so the	       preceding goop ensures that if we *didn't* generate a new	       option cache, oc still winds up holding an actual reference. */	    /* If no data is available for this option, skip it. */	    if (!oc && !have_encapsulation) {		    continue;	    }	    	    /* Find the value of the option... */	    if (oc) {		evaluate_option_cache (&od, packet,				       lease, client_state, in_options,				       cfg_options, scope, oc, MDL);		if (!od.len) {		    data_string_forget (&encapsulation, MDL);		    data_string_forget (&od, MDL);		    have_encapsulation = 0;		    continue;		}	    }	    /* We should now have a constant length for the option. */	    length = od.len;	    if (have_encapsulation) {		    length += encapsulation.len;		    if (!od.len) {			    data_string_copy (&od, &encapsulation, MDL);			    data_string_forget (&encapsulation, MDL);		    } else {			    struct buffer *bp = (struct buffer *)0;			    if (!buffer_allocate (&bp, length, MDL)) {				    option_cache_dereference (&oc, MDL);				    data_string_forget (&od, MDL);				    data_string_forget (&encapsulation, MDL);				    continue;			    }			    memcpy (&bp -> data [0], od.data, od.len);			    memcpy (&bp -> data [od.len], encapsulation.data,				    encapsulation.len);			    data_string_forget (&od, MDL);			    data_string_forget (&encapsulation, MDL);			    od.data = &bp -> data [0];			    buffer_reference (&od.buffer, bp, MDL);			    buffer_dereference (&bp, MDL);			    od.len = length;			    od.terminated = 0;		    }	    }

⌨️ 快捷键说明

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