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 + -
显示快捷键?