dhcp.c

来自「open source dhcp server client etc...」· C语言 代码 · 共 2,079 行 · 第 1/5 页

C
2,079
字号
/* dhcp.c   DHCP Protocol engine. *//* * 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: dhcp.c,v 1.192.2.15 2001/10/04 22:21:00 mellon Exp $ Copyright (c) 1995-2001 The Internet Software Consortium.  All rights reserved.\n";#endif /* not lint */#include "dhcpd.h"int outstanding_pings;static char dhcp_message [256];static const char *dhcp_type_names [] = { 	"DHCPDISCOVER",	"DHCPOFFER",	"DHCPREQUEST",	"DHCPDECLINE",	"DHCPACK",	"DHCPNAK",	"DHCPRELEASE",	"DHCPINFORM"};const int dhcp_type_name_max = ((sizeof dhcp_type_names) / sizeof (char *));#if defined (TRACING)# define send_packet trace_packet_send#endifvoid dhcp (packet)	struct packet *packet;{	int ms_nulltp = 0;	struct option_cache *oc;	struct lease *lease = (struct lease *)0;	const char *errmsg;	struct data_string data;	if (!locate_network (packet) &&	    packet -> packet_type != DHCPREQUEST &&	    packet -> packet_type != DHCPINFORM) {		const char *s;		char typebuf [32];		errmsg = "unknown network segment";	      bad_packet:				if (packet -> packet_type > 0 &&		    packet -> packet_type < dhcp_type_name_max - 1) {			s = dhcp_type_names [packet -> packet_type - 1];		} else {#if defined (HAVE_SNPRINTF)			snprintf (typebuf, sizeof typebuf,				  "type %d", packet -> packet_type);#else			sprintf (typebuf, 				  "type %d", packet -> packet_type);#endif			s = typebuf;		}				log_info ("%s from %s via %s: %s", s,			  (packet -> raw -> htype			   ? print_hw_addr (packet -> raw -> htype,					    packet -> raw -> hlen,					    packet -> raw -> chaddr)			   : "<no identifier>"),			  packet -> raw -> giaddr.s_addr			  ? inet_ntoa (packet -> raw -> giaddr)			  : packet -> interface -> name, errmsg);		goto out;	}	/* There is a problem with the relay agent information option,	   which is that in order for a normal relay agent to append	   this option, the relay agent has to have been involved in	   getting the packet from the client to the server.  Note	   that this is the software entity known as the relay agent,	   _not_ the hardware entity known as a router in which the	   relay agent may be running, so the fact that a router has	   forwarded a packet does not mean that the relay agent in	   the router was involved.	   So when the client is in INIT or INIT-REBOOT or REBINDING	   state, the relay agent gets to tack on its options, but	   when it's not, the relay agent doesn't get to do this,	   which means that any decisions the DHCP server may make	   based on the agent options will be made incorrectly.  	   We work around this in the following way: if this is a	   DHCPREQUEST and doesn't have relay agent information	   options, we see if there's an existing lease for this IP	   address and this client that _does_ have stashed agent	   options.   If so, then we tack those options onto the	   packet as if they came from the client.   Later on, when we	   are deciding whether to steal the agent options from the	   packet, if the agent options stashed on the lease are the	   same as those stashed on the packet, we don't steal them -	   this ensures that the client never receives its agent	   options. */	if (packet -> packet_type == DHCPREQUEST &&	    packet -> raw -> ciaddr.s_addr &&	    !packet -> raw -> giaddr.s_addr &&	    (packet -> options -> universe_count < agent_universe.index ||	     !packet -> options -> universes [agent_universe.index]))	{		struct iaddr cip;		cip.len = sizeof packet -> raw -> ciaddr;		memcpy (cip.iabuf, &packet -> raw -> ciaddr,			sizeof packet -> raw -> ciaddr);		if (!find_lease_by_ip_addr (&lease, cip, MDL))			goto nolease;		/* If there are no agent options on the lease, it's not		   interesting. */		if (!lease -> agent_options)			goto nolease;		/* The client should not be unicasting a renewal if its lease		   has expired, so make it go through the process of getting		   its agent options legally. */		if (lease -> ends < cur_time)			goto nolease;		if (lease -> uid_len) {			oc = lookup_option (&dhcp_universe, packet -> options,					    DHO_DHCP_CLIENT_IDENTIFIER);			if (!oc)				goto nolease;			memset (&data, 0, sizeof data);			if (!evaluate_option_cache (&data,						    packet, (struct lease *)0,						    (struct client_state *)0,						    packet -> options,						    (struct option_state *)0,						    &global_scope, oc, MDL))				goto nolease;			if (lease -> uid_len != data.len ||			    memcmp (lease -> uid, data.data, data.len)) {				data_string_forget (&data, MDL);				goto nolease;			}			data_string_forget (&data, MDL);		} else			if ((lease -> hardware_addr.hbuf [0] !=			     packet -> raw -> htype) ||			    (lease -> hardware_addr.hlen - 1 !=			     packet -> raw -> hlen) ||			    memcmp (&lease -> hardware_addr.hbuf [1],				    packet -> raw -> chaddr,				    packet -> raw -> hlen))				goto nolease;		/* Okay, so we found a lease that matches the client. */		option_chain_head_reference ((struct option_chain_head **)					     &(packet -> options -> universes					       [agent_universe.index]),					     lease -> agent_options, MDL);	}      nolease:	/* Classify the client. */	if ((oc = lookup_option (&dhcp_universe, packet -> options,				 DHO_HOST_NAME))) {		if (!oc -> expression)			if (oc -> data.len &&			    oc -> data.data [oc -> data.len - 1] == 0) {				ms_nulltp = 1;				oc -> data.len--;			}	}	classify_client (packet);	switch (packet -> packet_type) {	      case DHCPDISCOVER:		dhcpdiscover (packet, ms_nulltp);		break;	      case DHCPREQUEST:		dhcprequest (packet, ms_nulltp, lease);		break;	      case DHCPRELEASE:		dhcprelease (packet, ms_nulltp);		break;	      case DHCPDECLINE:		dhcpdecline (packet, ms_nulltp);		break;	      case DHCPINFORM:		dhcpinform (packet, ms_nulltp);		break;	      case DHCPACK:	      case DHCPOFFER:	      case DHCPNAK:		break;	      default:		errmsg = "unknown packet type";		goto bad_packet;	}      out:	if (lease)		lease_dereference (&lease, MDL);}void dhcpdiscover (packet, ms_nulltp)	struct packet *packet;	int ms_nulltp;{	struct lease *lease = (struct lease *)0;	char msgbuf [1024]; /* XXX */	TIME when;	char *s;	int allocatedp = 0;	int peer_has_leases = 0;#if defined (FAILOVER_PROTOCOL)	dhcp_failover_state_t *peer;#endif	find_lease (&lease, packet, packet -> shared_network,		    0, &allocatedp, (struct lease *)0, MDL);	if (lease && lease -> client_hostname &&	    db_printable (lease -> client_hostname))		s = lease -> client_hostname;	else		s = (char *)0;	/* Say what we're doing... */	sprintf (msgbuf, "DHCPDISCOVER from %s %s%s%svia %s",		 (packet -> raw -> htype		  ? print_hw_addr (packet -> raw -> htype,				   packet -> raw -> hlen,				   packet -> raw -> chaddr)		  : (lease		     ? print_hex_1 (lease -> uid_len, lease -> uid, 				    lease -> uid_len)		     : "<no identifier>")),		  s ? "(" : "", s ? s : "", s ? ") " : "",		  packet -> raw -> giaddr.s_addr		  ? inet_ntoa (packet -> raw -> giaddr)		  : packet -> interface -> name);	/* Sourceless packets don't make sense here. */	if (!packet -> shared_network) {		log_info ("Packet from unknown subnet: %s",		      inet_ntoa (packet -> raw -> giaddr));		goto out;	}#if defined (FAILOVER_PROTOCOL)	if (lease && lease -> pool && lease -> pool -> failover_peer) {		peer = lease -> pool -> failover_peer;		/* If the lease is ours to allocate, then allocate it,		   but set the allocatedp flag. */		if (lease_mine_to_reallocate (lease))			allocatedp = 1;		/* If the lease is active, do load balancing to see who		   allocates the lease (if it's active, it already belongs		   to the client, or we wouldn't have gotten it from		   find_lease (). */		else if (lease -> binding_state == FTS_ACTIVE &&			 (peer -> service_state != cooperating ||			  load_balance_mine (packet, peer)))			;		/* Otherwise, we can't let the client have this lease. */		else {#if defined (DEBUG_FIND_LEASE)		    log_debug ("discarding %s - %s",			       piaddr (lease -> ip_addr),			       binding_state_print (lease -> binding_state));#endif		    lease_dereference (&lease, MDL);		}	}#endif	/* If we didn't find a lease, try to allocate one... */	if (!lease) {		if (!allocate_lease (&lease, packet,				     packet -> shared_network -> pools, 				     &peer_has_leases)) {			if (peer_has_leases)				log_error ("%s: peer holds all free leases",					   msgbuf);			else				log_error ("%s: network %s: no free leases",					   msgbuf,					   packet -> shared_network -> name);			return;		}#if defined (FAILOVER_PROTOCOL)		if (lease -> pool && lease -> pool -> failover_peer)			dhcp_failover_pool_check (lease -> pool);#endif		allocatedp = 1;	}#if defined (FAILOVER_PROTOCOL)	if (lease && lease -> pool && lease -> pool -> failover_peer) {		peer = lease -> pool -> failover_peer;		if (peer -> service_state == not_responding ||		    peer -> service_state == service_startup) {			log_info ("%s: not responding%s",				  msgbuf, peer -> nrr);			goto out;		}	} else		peer = (dhcp_failover_state_t *)0;	/* Do load balancing if configured. */	/* If the lease is newly allocated, and we're not the server that	   the client would normally get with load balancing, and the	   failover protocol state is normal, let the other server get this.	   XXX Check protocol spec to make sure that predicating this on	   XXX allocatedp is okay - I'm doing this so that the client won't	   XXX be forced to switch servers (and IP addresses) just because	   XXX of bad luck, when it's possible for it to get the address it	   XXX is requesting.    Not sure this is allowed.  */	if (allocatedp && peer) {		if (peer -> service_state == cooperating) {			if (!load_balance_mine (packet, peer)) {				log_debug ("%s: load balance to peer %s",					   msgbuf, peer -> name);				goto out;			}		}	}#endif	/* If it's an expired lease, get rid of any bindings. */	if (lease -> ends < cur_time && lease -> scope)		binding_scope_dereference (&lease -> scope, MDL);	/* Set the lease to really expire in 2 minutes, unless it has	   not yet expired, in which case leave its expiry time alone. */	when = cur_time + 120;	if (when < lease -> ends)		when = lease -> ends;	ack_lease (packet, lease, DHCPOFFER, when, msgbuf, ms_nulltp);      out:	if (lease)		lease_dereference (&lease, MDL);}void dhcprequest (packet, ms_nulltp, ip_lease)	struct packet *packet;	int ms_nulltp;	struct lease *ip_lease;{	struct lease *lease;	struct iaddr cip;	struct iaddr sip;	struct subnet *subnet;	int ours = 0;	struct option_cache *oc;	struct data_string data;	int status;	char msgbuf [1024]; /* XXX */	char *s;	char smbuf [19];#if defined (FAILOVER_PROTOCOL)	dhcp_failover_state_t *peer;#endif

⌨️ 快捷键说明

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