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

📄 dhcp.c

📁 DHCP服务器源码
💻 C
📖 第 1 页 / 共 5 页
字号:
				   (struct client_state *)0,				   packet -> options, (struct option_state *)0,				   &global_scope, oc, MDL)) {		cip.len = 4;		memcpy (cip.iabuf, data.data, 4);		data_string_forget (&data, MDL);		have_requested_addr = 1;	} else {		oc = (struct option_cache *)0;		cip.len = 4;		memcpy (cip.iabuf, &packet -> raw -> ciaddr.s_addr, 4);	}	/* Find the lease that matches the address requested by the	   client. */	subnet = (struct subnet *)0;	lease = (struct lease *)0;	if (find_subnet (&subnet, cip, MDL))		find_lease (&lease, packet,			    subnet -> shared_network, &ours, 0, ip_lease, MDL);	/* XXX consider using allocatedp arg to find_lease to see	   XXX that this isn't a compliant DHCPREQUEST. */	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;	oc = lookup_option (&dhcp_universe, packet -> options,			    DHO_DHCP_SERVER_IDENTIFIER);	memset (&data, 0, sizeof data);	if (oc &&	    evaluate_option_cache (&data, packet, (struct lease *)0,				   (struct client_state *)0,				   packet -> options, (struct option_state *)0,				   &global_scope, oc, MDL)) {		sip.len = 4;		memcpy (sip.iabuf, data.data, 4);		data_string_forget (&data, MDL);		/* piaddr() should not return more than a 15 byte string.		 * safe.		 */		sprintf (smbuf, " (%s)", piaddr (sip));		have_server_identifier = 1;	} else		smbuf [0] = 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,		 "DHCPREQUEST for %s%s from %s %s%s%svia %s",		 piaddr (cip), smbuf,		 (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);#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;		}		/* Don't load balance if the client is RENEWING or REBINDING.		   If it's RENEWING, we are the only server to hear it, so		   we have to serve it.   If it's REBINDING, it's out of		   communication with the other server, so there's no point		   in waiting to serve it.    However, if the lease we're		   offering is not a free lease, then we may be the only		   server that can offer it, so we can't load balance if		   the lease isn't in the free or backup state. */		if (peer -> service_state == cooperating &&		    !packet -> raw -> ciaddr.s_addr &&		    (lease -> binding_state == FTS_FREE ||		     lease -> binding_state == FTS_BACKUP)) {			if (!load_balance_mine (packet, peer)) {				log_debug ("%s: load balance to peer %s",					   msgbuf, peer -> name);				goto out;			}		}		/* Don't let a client allocate a lease using DHCPREQUEST		   if the lease isn't ours to allocate. */		if ((lease -> binding_state == FTS_FREE ||		     lease -> binding_state == FTS_BACKUP) &&		    !lease_mine_to_reallocate (lease)) {			log_debug ("%s: lease owned by peer", msgbuf);			goto out;		}		/* If the lease is in a transitional state, we can't		   renew it. */		if ((lease -> binding_state == FTS_RELEASED ||		     lease -> binding_state == FTS_EXPIRED) &&		    !lease_mine_to_reallocate (lease)) {			log_debug ("%s: lease in transition state %s", msgbuf,				   lease -> binding_state == FTS_RELEASED				   ? "released" : "expired");			goto out;		}		/* It's actually very unlikely that we'll ever get here,		   but if we do, tell the client to stop using the lease,		   because the administrator reset it. */		if (lease -> binding_state == FTS_RESET &&		    !lease_mine_to_reallocate (lease)) {			log_debug ("%s: lease reset by administrator", msgbuf);			nak_lease (packet, &cip);			goto out;		}		/* At this point it's possible that we will get a broadcast		   DHCPREQUEST for a lease that we didn't offer, because		   both we and the peer are in a position to offer it.		   In that case, we probably shouldn't answer.   In order		   to not answer, we would have to compare the server		   identifier sent by the client with the list of possible		   server identifiers we can send, and if the client's		   identifier isn't on the list, drop the DHCPREQUEST.		   We aren't currently doing that for two reasons - first,		   it's not clear that all clients do the right thing		   with respect to sending the client identifier, which		   could mean that we might simply not respond to a client		   that is depending on us to respond.   Secondly, we allow		   the user to specify the server identifier to send, and		   we don't enforce that the server identifier should be		   one of our IP addresses.   This is probably not a big		   deal, but it's theoretically an issue.		   The reason we care about this is that if both servers		   send a DHCPACK to the DHCPREQUEST, they are then going		   to send dueling BNDUPD messages, which could cause		   trouble.   I think it causes no harm, but it seems		   wrong. */	} else		peer = (dhcp_failover_state_t *)0;#endif	/* If a client on a given network REQUESTs a lease on an	   address on a different network, NAK it.  If the Requested	   Address option was used, the protocol says that it must	   have been broadcast, so we can trust the source network	   information.	   If ciaddr was specified and Requested Address was not, then	   we really only know for sure what network a packet came from	   if it came through a BOOTP gateway - if it came through an	   IP router, we'll just have to assume that it's cool.	   If we don't think we know where the packet came from, it	   came through a gateway from an unknown network, so it's not	   from a RENEWING client.  If we recognize the network it	   *thinks* it's on, we can NAK it even though we don't	   recognize the network it's *actually* on; otherwise we just	   have to ignore it.	   We don't currently try to take advantage of access to the	   raw packet, because it's not available on all platforms.	   So a packet that was unicast to us through a router from a	   RENEWING client is going to look exactly like a packet that	   was broadcast to us from an INIT-REBOOT client.	   Since we can't tell the difference between these two kinds	   of packets, if the packet appears to have come in off the	   local wire, we have to treat it as if it's a RENEWING	   client.  This means that we can't NAK a RENEWING client on	   the local wire that has a bogus address.  The good news is	   that we won't ACK it either, so it should revert to INIT	   state and send us a DHCPDISCOVER, which we *can* work with.	   Because we can't detect that a RENEWING client is on the	   wrong wire, it's going to sit there trying to renew until	   it gets to the REBIND state, when we *can* NAK it because	   the packet will get to us through a BOOTP gateway.  We	   shouldn't actually see DHCPREQUEST packets from RENEWING	   clients on the wrong wire anyway, since their idea of their	   local router will be wrong.  In any case, the protocol	   doesn't really allow us to NAK a DHCPREQUEST from a	   RENEWING client, so we can punt on this issue. */	if (!packet -> shared_network ||	    (packet -> raw -> ciaddr.s_addr &&	     packet -> raw -> giaddr.s_addr) ||	    (have_requested_addr && !packet -> raw -> ciaddr.s_addr)) {				/* If we don't know where it came from but we do know		   where it claims to have come from, it didn't come		   from there. */		if (!packet -> shared_network) {			if (subnet && subnet -> group -> authoritative) {				log_info ("%s: wrong network.", msgbuf);				nak_lease (packet, &cip);				goto out;			}			/* Otherwise, ignore it. */			log_info ("%s: ignored (%s).", msgbuf,				  (subnet				   ? "not authoritative" : "unknown subnet"));			goto out;		}		/* If we do know where it came from and it asked for an		   address that is not on that shared network, nak it. */		if (subnet)			subnet_dereference (&subnet, MDL);		if (!find_grouped_subnet (&subnet, packet -> shared_network,					  cip, MDL)) {			if (packet -> shared_network -> group -> authoritative)			{				log_info ("%s: wrong network.", msgbuf);				nak_lease (packet, &cip);				goto out;			}			log_info ("%s: ignored (not authoritative).", msgbuf);			return;		}	}	/* If the address the client asked for is ours, but it wasn't           available for the client, NAK it. */	if (!lease && ours) {		log_info ("%s: lease %s unavailable.", msgbuf, piaddr (cip));		nak_lease (packet, &cip);		goto out;	}	/* Otherwise, send the lease to the client if we found one. */	if (lease) {		ack_lease (packet, lease, DHCPACK, 0, msgbuf, ms_nulltp);	} else		log_info ("%s: unknown lease %s.", msgbuf, piaddr (cip));      out:	if (subnet)		subnet_dereference (&subnet, MDL);	if (lease)		lease_dereference (&lease, MDL);	return;}void dhcprelease (packet, ms_nulltp)	struct packet *packet;	int ms_nulltp;{	struct lease *lease = (struct lease *)0, *next = (struct lease *)0;	struct iaddr cip;	struct option_cache *oc;	struct data_string data;	char *s;	char msgbuf [1024], cstr[16]; /* XXX */	/* DHCPRELEASE must not specify address in requested-address           option, but old protocol specs weren't explicit about this,           so let it go. */	if ((oc = lookup_option (&dhcp_universe, packet -> options,				 DHO_DHCP_REQUESTED_ADDRESS))) {		log_info ("DHCPRELEASE from %s specified requested-address.",		      print_hw_addr (packet -> raw -> htype,				     packet -> raw -> hlen,				     packet -> raw -> chaddr));	}	oc = lookup_option (&dhcp_universe, packet -> options,			    DHO_DHCP_CLIENT_IDENTIFIER);	memset (&data, 0, sizeof data);	if (oc &&	    evaluate_option_cache (&data, packet, (struct lease *)0,				   (struct client_state *)0,				   packet -> options, (struct option_state *)0,				   &global_scope, oc, MDL)) {		find_lease_by_uid (&lease, data.data, data.len, MDL);		data_string_forget (&data, MDL);		/* See if we can find a lease that matches the IP address		   the client is claiming. */		while (lease) {			if (lease -> n_uid)				lease_reference (&next, lease -> n_uid, MDL);			if (!memcmp (&packet -> raw -> ciaddr,				     lease -> ip_addr.iabuf, 4)) {				break;			}			lease_dereference (&lease, MDL);			if (next) {				lease_reference (&lease, next, MDL);				lease_dereference (&next, MDL);			}		}		if (next)			lease_dereference (&next, MDL);	}	/* The client is supposed to pass a valid client-identifier,	   but the spec on this has changed historically, so try the	   IP address in ciaddr if the client-identifier fails. */	if (!lease) {		cip.len = 4;		memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4);		find_lease_by_ip_addr (&lease, cip, MDL);	}	/* If the hardware address doesn't match, don't do the release. */	if (lease &&	    (lease -> hardware_addr.hlen != packet -> raw -> hlen + 1 ||	     lease -> hardware_addr.hbuf [0] != packet -> raw -> htype ||	     memcmp (&lease -> hardware_addr.hbuf [1],		     packet -> raw -> chaddr, packet -> raw -> hlen)))		lease_dereference (&lease, 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% Cannot exceed 16 bytes. %2004.06.17,Safe%	 * We copy this out to stack because we actually want to log two	 * inet_ntoa()'s in this message.	 */	strncpy(cstr, inet_ntoa (packet -> raw -> ciaddr), 15);	cstr[15] = '\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,		 "DHCPRELEASE of %s from %s %s%s%svia %s (%sfound)",		 cstr,		 (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,		 lease ? "" : "not ");#if defined (FAILOVER_PROTOCOL)	if (lease && lease -> pool && lease -> pool -> failover_peer) {		dhcp_failover_state_t *peer = lease -> pool -> failover_peer;		if (peer -> service_state == not_responding ||		    peer -> service_state == service_startup) {			log_info ("%s: ignored%s",				  peer -> name, peer -> nrr);			goto out;		}		/* DHCPRELEASE messages are unicast, so if the client		   sent the DHCPRELEASE to us, it's not going to send it		   to the peer.   Not sure why this would happen, and		   if it does happen I think we still have to change the		   lease state, so that's what we're doing.		   XXX See what it says in the draft about this. */	}#endif	/* If we found a lease, release it. */	if (lease && lease -> ends > cur_time) {		release_lease (lease, packet);	} 	log_info ("%s", msgbuf);      out:	if (lease)		lease_dereference (&lease, MDL);}void dhcpdecline (packet, ms_nulltp)	struct packet *packet;	int ms_nulltp;{	struct lease *lease = (struct lease *)0;	struct option_state *options = (struct option_state *)0;	int ignorep = 0;	int i;	const char *status;	char *s;	char msgbuf [1024]; /* XXX */	struct iaddr cip;	struct option_cache *oc;	struct data_string data;	/* DHCPDECLINE must specify address. */	if (!(oc = lookup_option (&dhcp_universe, packet -> options,				  DHO_DHCP_REQUESTED_ADDRESS)))		return;	memset (&data, 0, sizeof data);	if (!evaluate_option_cache (&data, packet, (struct lease *)0,

⌨️ 快捷键说明

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