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

📄 dhcp.c

📁 DHCP服务器源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* dhcp.c   DHCP Protocol engine. *//* * 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: dhcp.c,v 1.192.2.35 2004/06/17 20:54:40 dhankins Exp $ Copyright (c) 2004 Internet Systems 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 {			/* %Audit% Cannot exceed 28 bytes. %2004.06.17,Safe% */			sprintf (typebuf, "type %d", packet -> packet_type);			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)			while (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) {		if ((strlen (lease -> client_hostname) <= 64) &&		    db_printable (lease -> client_hostname))			s = lease -> client_hostname;		else			s = "Hostname Unsuitable for Printing";	} else		s = (char *)0;	/* %Audit% This is log output. %2004.06.17,Safe%	 * If we truncate we hope the user can get a hint from the log.	 */	snprintf (msgbuf, sizeof 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	int have_server_identifier = 0;	int have_requested_addr = 0;	oc = lookup_option (&dhcp_universe, packet -> options,			    DHO_DHCP_REQUESTED_ADDRESS);	memset (&data, 0, sizeof data);	if (oc &&	    evaluate_option_cache (&data, packet, (struct lease *)0,

⌨️ 快捷键说明

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