1  | 
     | 
     | 
    /*	$OpenBSD: dhcp.c,v 1.57 2017/07/11 10:28:24 reyk Exp $ */  | 
    
    
    2  | 
     | 
     | 
     | 
    
    
    3  | 
     | 
     | 
    /*  | 
    
    
    4  | 
     | 
     | 
     * Copyright (c) 1995, 1996, 1997, 1998, 1999  | 
    
    
    5  | 
     | 
     | 
     * The Internet Software Consortium.   All rights reserved.  | 
    
    
    6  | 
     | 
     | 
     *  | 
    
    
    7  | 
     | 
     | 
     * Redistribution and use in source and binary forms, with or without  | 
    
    
    8  | 
     | 
     | 
     * modification, are permitted provided that the following conditions  | 
    
    
    9  | 
     | 
     | 
     * are met:  | 
    
    
    10  | 
     | 
     | 
     *  | 
    
    
    11  | 
     | 
     | 
     * 1. Redistributions of source code must retain the above copyright  | 
    
    
    12  | 
     | 
     | 
     *    notice, this list of conditions and the following disclaimer.  | 
    
    
    13  | 
     | 
     | 
     * 2. Redistributions in binary form must reproduce the above copyright  | 
    
    
    14  | 
     | 
     | 
     *    notice, this list of conditions and the following disclaimer in the  | 
    
    
    15  | 
     | 
     | 
     *    documentation and/or other materials provided with the distribution.  | 
    
    
    16  | 
     | 
     | 
     * 3. Neither the name of The Internet Software Consortium nor the names  | 
    
    
    17  | 
     | 
     | 
     *    of its contributors may be used to endorse or promote products derived  | 
    
    
    18  | 
     | 
     | 
     *    from this software without specific prior written permission.  | 
    
    
    19  | 
     | 
     | 
     *  | 
    
    
    20  | 
     | 
     | 
     * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND  | 
    
    
    21  | 
     | 
     | 
     * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,  | 
    
    
    22  | 
     | 
     | 
     * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  | 
    
    
    23  | 
     | 
     | 
     * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE  | 
    
    
    24  | 
     | 
     | 
     * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR  | 
    
    
    25  | 
     | 
     | 
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,  | 
    
    
    26  | 
     | 
     | 
     * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT  | 
    
    
    27  | 
     | 
     | 
     * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF  | 
    
    
    28  | 
     | 
     | 
     * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND  | 
    
    
    29  | 
     | 
     | 
     * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,  | 
    
    
    30  | 
     | 
     | 
     * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  | 
    
    
    31  | 
     | 
     | 
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF  | 
    
    
    32  | 
     | 
     | 
     * SUCH DAMAGE.  | 
    
    
    33  | 
     | 
     | 
     *  | 
    
    
    34  | 
     | 
     | 
     * This software has been written for the Internet Software Consortium  | 
    
    
    35  | 
     | 
     | 
     * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie  | 
    
    
    36  | 
     | 
     | 
     * Enterprises.  To learn more about the Internet Software Consortium,  | 
    
    
    37  | 
     | 
     | 
     * see ``http://www.vix.com/isc''.  To learn more about Vixie  | 
    
    
    38  | 
     | 
     | 
     * Enterprises, see ``http://www.vix.com''.  | 
    
    
    39  | 
     | 
     | 
     */  | 
    
    
    40  | 
     | 
     | 
     | 
    
    
    41  | 
     | 
     | 
    #include <sys/types.h>  | 
    
    
    42  | 
     | 
     | 
    #include <sys/socket.h>  | 
    
    
    43  | 
     | 
     | 
     | 
    
    
    44  | 
     | 
     | 
    #include <arpa/inet.h>  | 
    
    
    45  | 
     | 
     | 
     | 
    
    
    46  | 
     | 
     | 
    #include <net/if.h>  | 
    
    
    47  | 
     | 
     | 
     | 
    
    
    48  | 
     | 
     | 
    #include <netinet/in.h>  | 
    
    
    49  | 
     | 
     | 
     | 
    
    
    50  | 
     | 
     | 
    #include <errno.h>  | 
    
    
    51  | 
     | 
     | 
    #include <stdio.h>  | 
    
    
    52  | 
     | 
     | 
    #include <stdlib.h>  | 
    
    
    53  | 
     | 
     | 
    #include <string.h>  | 
    
    
    54  | 
     | 
     | 
     | 
    
    
    55  | 
     | 
     | 
    #include "dhcp.h"  | 
    
    
    56  | 
     | 
     | 
    #include "tree.h"  | 
    
    
    57  | 
     | 
     | 
    #include "dhcpd.h"  | 
    
    
    58  | 
     | 
     | 
    #include "log.h"  | 
    
    
    59  | 
     | 
     | 
    #include "sync.h"  | 
    
    
    60  | 
     | 
     | 
     | 
    
    
    61  | 
     | 
     | 
    int outstanding_pings;  | 
    
    
    62  | 
     | 
     | 
     | 
    
    
    63  | 
     | 
     | 
    static char dhcp_message[256];  | 
    
    
    64  | 
     | 
     | 
     | 
    
    
    65  | 
     | 
     | 
    void  | 
    
    
    66  | 
     | 
     | 
    dhcp(struct packet *packet, int is_udpsock)  | 
    
    
    67  | 
     | 
     | 
    { | 
    
    
    68  | 
     | 
     | 
    	if (!locate_network(packet) && packet->packet_type != DHCPREQUEST)  | 
    
    
    69  | 
     | 
     | 
    		return;  | 
    
    
    70  | 
     | 
     | 
     | 
    
    
    71  | 
     | 
     | 
    	if (is_udpsock && packet->packet_type != DHCPINFORM) { | 
    
    
    72  | 
     | 
     | 
    		log_info("Unable to handle a DHCP message type=%d on UDP " | 
    
    
    73  | 
     | 
     | 
    		    "socket", packet->packet_type);  | 
    
    
    74  | 
     | 
     | 
    		return;  | 
    
    
    75  | 
     | 
     | 
    	}  | 
    
    
    76  | 
     | 
     | 
     | 
    
    
    77  | 
     | 
     | 
    	switch (packet->packet_type) { | 
    
    
    78  | 
     | 
     | 
    	case DHCPDISCOVER:  | 
    
    
    79  | 
     | 
     | 
    		dhcpdiscover(packet);  | 
    
    
    80  | 
     | 
     | 
    		break;  | 
    
    
    81  | 
     | 
     | 
     | 
    
    
    82  | 
     | 
     | 
    	case DHCPREQUEST:  | 
    
    
    83  | 
     | 
     | 
    		dhcprequest(packet);  | 
    
    
    84  | 
     | 
     | 
    		break;  | 
    
    
    85  | 
     | 
     | 
     | 
    
    
    86  | 
     | 
     | 
    	case DHCPRELEASE:  | 
    
    
    87  | 
     | 
     | 
    		dhcprelease(packet);  | 
    
    
    88  | 
     | 
     | 
    		break;  | 
    
    
    89  | 
     | 
     | 
     | 
    
    
    90  | 
     | 
     | 
    	case DHCPDECLINE:  | 
    
    
    91  | 
     | 
     | 
    		dhcpdecline(packet);  | 
    
    
    92  | 
     | 
     | 
    		break;  | 
    
    
    93  | 
     | 
     | 
     | 
    
    
    94  | 
     | 
     | 
    	case DHCPINFORM:  | 
    
    
    95  | 
     | 
     | 
    		dhcpinform(packet);  | 
    
    
    96  | 
     | 
     | 
    		break;  | 
    
    
    97  | 
     | 
     | 
     | 
    
    
    98  | 
     | 
     | 
    	default:  | 
    
    
    99  | 
     | 
     | 
    		break;  | 
    
    
    100  | 
     | 
     | 
    	}  | 
    
    
    101  | 
     | 
     | 
    }  | 
    
    
    102  | 
     | 
     | 
     | 
    
    
    103  | 
     | 
     | 
    void  | 
    
    
    104  | 
     | 
     | 
    dhcpdiscover(struct packet *packet)  | 
    
    
    105  | 
     | 
     | 
    { | 
    
    
    106  | 
     | 
     | 
    	struct lease *lease = find_lease(packet, packet->shared_network, 0);  | 
    
    
    107  | 
     | 
     | 
    	struct host_decl *hp;  | 
    
    
    108  | 
     | 
     | 
     | 
    
    
    109  | 
     | 
     | 
    	log_info("DHCPDISCOVER from %s via %s", | 
    
    
    110  | 
     | 
     | 
    	    print_hw_addr(packet->raw->htype, packet->raw->hlen,  | 
    
    
    111  | 
     | 
     | 
    	    packet->raw->chaddr),  | 
    
    
    112  | 
     | 
     | 
    	    packet->raw->giaddr.s_addr ? inet_ntoa(packet->raw->giaddr) :  | 
    
    
    113  | 
     | 
     | 
    	    packet->interface->name);  | 
    
    
    114  | 
     | 
     | 
     | 
    
    
    115  | 
     | 
     | 
    	/* Sourceless packets don't make sense here. */  | 
    
    
    116  | 
     | 
     | 
    	if (!packet->shared_network) { | 
    
    
    117  | 
     | 
     | 
    		log_info("Packet from unknown subnet: %s", | 
    
    
    118  | 
     | 
     | 
    		    inet_ntoa(packet->raw->giaddr));  | 
    
    
    119  | 
     | 
     | 
    		return;  | 
    
    
    120  | 
     | 
     | 
    	}  | 
    
    
    121  | 
     | 
     | 
     | 
    
    
    122  | 
     | 
     | 
    	/* If we didn't find a lease, try to allocate one... */  | 
    
    
    123  | 
     | 
     | 
    	if (!lease) { | 
    
    
    124  | 
     | 
     | 
    		lease = packet->shared_network->last_lease;  | 
    
    
    125  | 
     | 
     | 
     | 
    
    
    126  | 
     | 
     | 
    		/*  | 
    
    
    127  | 
     | 
     | 
    		 * If there are no leases in that subnet that have  | 
    
    
    128  | 
     | 
     | 
    		 * expired, we have nothing to offer this client.  | 
    
    
    129  | 
     | 
     | 
    		 */  | 
    
    
    130  | 
     | 
     | 
    		if (!lease || lease->ends > cur_time) { | 
    
    
    131  | 
     | 
     | 
    			log_info("no free leases on subnet %s", | 
    
    
    132  | 
     | 
     | 
    			    packet->shared_network->name);  | 
    
    
    133  | 
     | 
     | 
    			return;  | 
    
    
    134  | 
     | 
     | 
    		}  | 
    
    
    135  | 
     | 
     | 
     | 
    
    
    136  | 
     | 
     | 
    		/*  | 
    
    
    137  | 
     | 
     | 
    		 * If we find an abandoned lease, take it, but print a  | 
    
    
    138  | 
     | 
     | 
    		 * warning message, so that if it continues to lose,  | 
    
    
    139  | 
     | 
     | 
    		 * the administrator will eventually investigate.  | 
    
    
    140  | 
     | 
     | 
    		 */  | 
    
    
    141  | 
     | 
     | 
    		if ((lease->flags & ABANDONED_LEASE)) { | 
    
    
    142  | 
     | 
     | 
    			struct lease *lp;  | 
    
    
    143  | 
     | 
     | 
     | 
    
    
    144  | 
     | 
     | 
    			/* See if we can find an unabandoned lease first. */  | 
    
    
    145  | 
     | 
     | 
    			for (lp = lease; lp; lp = lp->prev) { | 
    
    
    146  | 
     | 
     | 
    				if (lp->ends > cur_time)  | 
    
    
    147  | 
     | 
     | 
    					break;  | 
    
    
    148  | 
     | 
     | 
    				if (!(lp->flags & ABANDONED_LEASE)) { | 
    
    
    149  | 
     | 
     | 
    					lease = lp;  | 
    
    
    150  | 
     | 
     | 
    					break;  | 
    
    
    151  | 
     | 
     | 
    				}  | 
    
    
    152  | 
     | 
     | 
    			}  | 
    
    
    153  | 
     | 
     | 
     | 
    
    
    154  | 
     | 
     | 
    			/*  | 
    
    
    155  | 
     | 
     | 
    			 * If we can't find an unabandoned lease,  | 
    
    
    156  | 
     | 
     | 
    			 * reclaim the abandoned lease.  | 
    
    
    157  | 
     | 
     | 
    			 */  | 
    
    
    158  | 
     | 
     | 
    			if ((lease->flags & ABANDONED_LEASE)) { | 
    
    
    159  | 
     | 
     | 
    				log_warnx("Reclaiming abandoned IP address %s.", | 
    
    
    160  | 
     | 
     | 
    				    piaddr(lease->ip_addr));  | 
    
    
    161  | 
     | 
     | 
    				lease->flags &= ~ABANDONED_LEASE;  | 
    
    
    162  | 
     | 
     | 
     | 
    
    
    163  | 
     | 
     | 
    				pfmsg('L', lease); /* unabandon address */ | 
    
    
    164  | 
     | 
     | 
    			}  | 
    
    
    165  | 
     | 
     | 
    		}  | 
    
    
    166  | 
     | 
     | 
     | 
    
    
    167  | 
     | 
     | 
    		/* Try to find a host_decl that matches the client  | 
    
    
    168  | 
     | 
     | 
    		   identifier or hardware address on the packet, and  | 
    
    
    169  | 
     | 
     | 
    		   has no fixed IP address.   If there is one, hang  | 
    
    
    170  | 
     | 
     | 
    		   it off the lease so that its option definitions  | 
    
    
    171  | 
     | 
     | 
    		   can be used. */  | 
    
    
    172  | 
     | 
     | 
    		if (((packet->options[DHO_DHCP_CLIENT_IDENTIFIER].len != 0) &&  | 
    
    
    173  | 
     | 
     | 
    		    ((hp = find_hosts_by_uid(  | 
    
    
    174  | 
     | 
     | 
    		    packet->options[DHO_DHCP_CLIENT_IDENTIFIER].data,  | 
    
    
    175  | 
     | 
     | 
    		    packet->options[DHO_DHCP_CLIENT_IDENTIFIER].len)) !=  | 
    
    
    176  | 
     | 
     | 
    		    NULL)) ||  | 
    
    
    177  | 
     | 
     | 
    		    ((hp = find_hosts_by_haddr(packet->raw->htype,  | 
    
    
    178  | 
     | 
     | 
    		    packet->raw->chaddr, packet->raw->hlen)) != NULL)) { | 
    
    
    179  | 
     | 
     | 
    			for (; hp; hp = hp->n_ipaddr) { | 
    
    
    180  | 
     | 
     | 
    				if (!hp->fixed_addr) { | 
    
    
    181  | 
     | 
     | 
    					lease->host = hp;  | 
    
    
    182  | 
     | 
     | 
    					break;  | 
    
    
    183  | 
     | 
     | 
    				}  | 
    
    
    184  | 
     | 
     | 
    			}  | 
    
    
    185  | 
     | 
     | 
    		} else  | 
    
    
    186  | 
     | 
     | 
    			lease->host = NULL;  | 
    
    
    187  | 
     | 
     | 
    	}  | 
    
    
    188  | 
     | 
     | 
     | 
    
    
    189  | 
     | 
     | 
    	/* If this subnet won't boot unknown clients, ignore the  | 
    
    
    190  | 
     | 
     | 
    	   request. */  | 
    
    
    191  | 
     | 
     | 
    	if (!lease->host &&  | 
    
    
    192  | 
     | 
     | 
    	    !lease->subnet->group->boot_unknown_clients) { | 
    
    
    193  | 
     | 
     | 
    		log_info("Ignoring unknown client %s", | 
    
    
    194  | 
     | 
     | 
    		    print_hw_addr(packet->raw->htype, packet->raw->hlen,  | 
    
    
    195  | 
     | 
     | 
    		    packet->raw->chaddr));  | 
    
    
    196  | 
     | 
     | 
    	} else if (lease->host && !lease->host->group->allow_booting) { | 
    
    
    197  | 
     | 
     | 
    		log_info("Declining to boot client %s", | 
    
    
    198  | 
     | 
     | 
    		    lease->host->name ? lease->host->name :  | 
    
    
    199  | 
     | 
     | 
    		    print_hw_addr(packet->raw->htype, packet->raw->hlen,  | 
    
    
    200  | 
     | 
     | 
    		    packet->raw->chaddr));  | 
    
    
    201  | 
     | 
     | 
    	} else  | 
    
    
    202  | 
     | 
     | 
    		ack_lease(packet, lease, DHCPOFFER, cur_time + 120);  | 
    
    
    203  | 
     | 
     | 
    }  | 
    
    
    204  | 
     | 
     | 
     | 
    
    
    205  | 
     | 
     | 
    void  | 
    
    
    206  | 
     | 
     | 
    dhcprequest(struct packet *packet)  | 
    
    
    207  | 
     | 
     | 
    { | 
    
    
    208  | 
     | 
     | 
    	struct lease *lease;  | 
    
    
    209  | 
     | 
     | 
    	struct iaddr cip;  | 
    
    
    210  | 
     | 
     | 
    	struct subnet *subnet;  | 
    
    
    211  | 
     | 
     | 
    	int ours = 0;  | 
    
    
    212  | 
     | 
     | 
     | 
    
    
    213  | 
     | 
     | 
    	cip.len = 4;  | 
    
    
    214  | 
     | 
     | 
    	if (packet->options[DHO_DHCP_REQUESTED_ADDRESS].len == 4)  | 
    
    
    215  | 
     | 
     | 
    		memcpy(cip.iabuf,  | 
    
    
    216  | 
     | 
     | 
    		    packet->options[DHO_DHCP_REQUESTED_ADDRESS].data, 4);  | 
    
    
    217  | 
     | 
     | 
    	else  | 
    
    
    218  | 
     | 
     | 
    		memcpy(cip.iabuf, &packet->raw->ciaddr.s_addr, 4);  | 
    
    
    219  | 
     | 
     | 
    	subnet = find_subnet(cip);  | 
    
    
    220  | 
     | 
     | 
     | 
    
    
    221  | 
     | 
     | 
    	/* Find the lease that matches the address requested by the client. */  | 
    
    
    222  | 
     | 
     | 
     | 
    
    
    223  | 
     | 
     | 
    	if (subnet)  | 
    
    
    224  | 
     | 
     | 
    		lease = find_lease(packet, subnet->shared_network, &ours);  | 
    
    
    225  | 
     | 
     | 
    	else  | 
    
    
    226  | 
     | 
     | 
    		lease = NULL;  | 
    
    
    227  | 
     | 
     | 
     | 
    
    
    228  | 
     | 
     | 
    	log_info("DHCPREQUEST for %s from %s via %s", piaddr(cip), | 
    
    
    229  | 
     | 
     | 
    	    print_hw_addr(packet->raw->htype, packet->raw->hlen,  | 
    
    
    230  | 
     | 
     | 
    	    packet->raw->chaddr),  | 
    
    
    231  | 
     | 
     | 
    	    packet->raw->giaddr.s_addr ? inet_ntoa(packet->raw->giaddr) :  | 
    
    
    232  | 
     | 
     | 
    	    packet->interface->name);  | 
    
    
    233  | 
     | 
     | 
     | 
    
    
    234  | 
     | 
     | 
    	/* If a client on a given network REQUESTs a lease on an  | 
    
    
    235  | 
     | 
     | 
    	 * address on a different network, NAK it.  If the Requested  | 
    
    
    236  | 
     | 
     | 
    	 * Address option was used, the protocol says that it must  | 
    
    
    237  | 
     | 
     | 
    	 * have been broadcast, so we can trust the source network  | 
    
    
    238  | 
     | 
     | 
    	 * information.  | 
    
    
    239  | 
     | 
     | 
    	 *  | 
    
    
    240  | 
     | 
     | 
    	 * If ciaddr was specified and Requested Address was not, then  | 
    
    
    241  | 
     | 
     | 
    	 * we really only know for sure what network a packet came from  | 
    
    
    242  | 
     | 
     | 
    	 * if it came through a BOOTP gateway - if it came through an  | 
    
    
    243  | 
     | 
     | 
    	 * IP router, we'll just have to assume that it's cool.  | 
    
    
    244  | 
     | 
     | 
    	 *  | 
    
    
    245  | 
     | 
     | 
    	 * If we don't think we know where the packet came from, it  | 
    
    
    246  | 
     | 
     | 
    	 * came through a gateway from an unknown network, so it's not  | 
    
    
    247  | 
     | 
     | 
    	 * from a RENEWING client.  If we recognize the network it  | 
    
    
    248  | 
     | 
     | 
    	 * *thinks* it's on, we can NAK it even though we don't  | 
    
    
    249  | 
     | 
     | 
    	 * recognize the network it's *actually* on; otherwise we just  | 
    
    
    250  | 
     | 
     | 
    	 * have to ignore it.  | 
    
    
    251  | 
     | 
     | 
    	 *  | 
    
    
    252  | 
     | 
     | 
    	 * We don't currently try to take advantage of access to the  | 
    
    
    253  | 
     | 
     | 
    	 * raw packet, because it's not available on all platforms.  | 
    
    
    254  | 
     | 
     | 
    	 * So a packet that was unicast to us through a router from a  | 
    
    
    255  | 
     | 
     | 
    	 * RENEWING client is going to look exactly like a packet that  | 
    
    
    256  | 
     | 
     | 
    	 * was broadcast to us from an INIT-REBOOT client.  | 
    
    
    257  | 
     | 
     | 
    	 *  | 
    
    
    258  | 
     | 
     | 
    	 * Since we can't tell the difference between these two kinds  | 
    
    
    259  | 
     | 
     | 
    	 * of packets, if the packet appears to have come in off the  | 
    
    
    260  | 
     | 
     | 
    	 * local wire, we have to treat it as if it's a RENEWING  | 
    
    
    261  | 
     | 
     | 
    	 * client.  This means that we can't NAK a RENEWING client on  | 
    
    
    262  | 
     | 
     | 
    	 * the local wire that has a bogus address.  The good news is  | 
    
    
    263  | 
     | 
     | 
    	 * that we won't ACK it either, so it should revert to INIT  | 
    
    
    264  | 
     | 
     | 
    	 * state and send us a DHCPDISCOVER, which we *can* work with.  | 
    
    
    265  | 
     | 
     | 
    	 *  | 
    
    
    266  | 
     | 
     | 
    	 * Because we can't detect that a RENEWING client is on the  | 
    
    
    267  | 
     | 
     | 
    	 * wrong wire, it's going to sit there trying to renew until  | 
    
    
    268  | 
     | 
     | 
    	 * it gets to the REBIND state, when we *can* NAK it because  | 
    
    
    269  | 
     | 
     | 
    	 * the packet will get to us through a BOOTP gateway.  We  | 
    
    
    270  | 
     | 
     | 
    	 * shouldn't actually see DHCPREQUEST packets from RENEWING  | 
    
    
    271  | 
     | 
     | 
    	 * clients on the wrong wire anyway, since their idea of their  | 
    
    
    272  | 
     | 
     | 
    	 * local router will be wrong.  In any case, the protocol  | 
    
    
    273  | 
     | 
     | 
    	 * doesn't really allow us to NAK a DHCPREQUEST from a  | 
    
    
    274  | 
     | 
     | 
    	 * RENEWING client, so we can punt on this issue.  | 
    
    
    275  | 
     | 
     | 
    	 */  | 
    
    
    276  | 
     | 
     | 
    	if (!packet->shared_network ||  | 
    
    
    277  | 
     | 
     | 
    	    (packet->raw->ciaddr.s_addr && packet->raw->giaddr.s_addr) ||  | 
    
    
    278  | 
     | 
     | 
    	    (packet->options[DHO_DHCP_REQUESTED_ADDRESS].len == 4 &&  | 
    
    
    279  | 
     | 
     | 
    	    !packet->raw->ciaddr.s_addr)) { | 
    
    
    280  | 
     | 
     | 
     | 
    
    
    281  | 
     | 
     | 
    		/*  | 
    
    
    282  | 
     | 
     | 
    		 * If we don't know where it came from but we do know  | 
    
    
    283  | 
     | 
     | 
    		 * where it claims to have come from, it didn't come  | 
    
    
    284  | 
     | 
     | 
    		 * from there.   Fry it.  | 
    
    
    285  | 
     | 
     | 
    		 */  | 
    
    
    286  | 
     | 
     | 
    		if (!packet->shared_network) { | 
    
    
    287  | 
     | 
     | 
    			if (subnet &&  | 
    
    
    288  | 
     | 
     | 
    			    subnet->shared_network->group->authoritative) { | 
    
    
    289  | 
     | 
     | 
    				nak_lease(packet, &cip);  | 
    
    
    290  | 
     | 
     | 
    				return;  | 
    
    
    291  | 
     | 
     | 
    			}  | 
    
    
    292  | 
     | 
     | 
    			/* Otherwise, ignore it. */  | 
    
    
    293  | 
     | 
     | 
    			return;  | 
    
    
    294  | 
     | 
     | 
    		}  | 
    
    
    295  | 
     | 
     | 
     | 
    
    
    296  | 
     | 
     | 
    		/*  | 
    
    
    297  | 
     | 
     | 
    		 * If we do know where it came from and it asked for an  | 
    
    
    298  | 
     | 
     | 
    		 * address that is not on that shared network, nak it.  | 
    
    
    299  | 
     | 
     | 
    		 */  | 
    
    
    300  | 
     | 
     | 
    		subnet = find_grouped_subnet(packet->shared_network, cip);  | 
    
    
    301  | 
     | 
     | 
    		if (!subnet) { | 
    
    
    302  | 
     | 
     | 
    			if (packet->shared_network->group->authoritative)  | 
    
    
    303  | 
     | 
     | 
    				nak_lease(packet, &cip);  | 
    
    
    304  | 
     | 
     | 
    			return;  | 
    
    
    305  | 
     | 
     | 
    		}  | 
    
    
    306  | 
     | 
     | 
    	}  | 
    
    
    307  | 
     | 
     | 
     | 
    
    
    308  | 
     | 
     | 
    	/*  | 
    
    
    309  | 
     | 
     | 
    	 * If we found a lease for the client but it's not the one the  | 
    
    
    310  | 
     | 
     | 
    	 * client asked for, don't send it - some other server probably  | 
    
    
    311  | 
     | 
     | 
    	 * made the cut.  | 
    
    
    312  | 
     | 
     | 
    	 */  | 
    
    
    313  | 
     | 
     | 
    	if (lease && !addr_eq(lease->ip_addr, cip)) { | 
    
    
    314  | 
     | 
     | 
    		/*  | 
    
    
    315  | 
     | 
     | 
    		 * If we found the address the client asked for, but  | 
    
    
    316  | 
     | 
     | 
    		 * it wasn't what got picked, the lease belongs to us,  | 
    
    
    317  | 
     | 
     | 
    		 * so we should NAK it.  | 
    
    
    318  | 
     | 
     | 
    		 */  | 
    
    
    319  | 
     | 
     | 
    		if (ours)  | 
    
    
    320  | 
     | 
     | 
    			nak_lease(packet, &cip);  | 
    
    
    321  | 
     | 
     | 
    		return;  | 
    
    
    322  | 
     | 
     | 
    	}  | 
    
    
    323  | 
     | 
     | 
     | 
    
    
    324  | 
     | 
     | 
    	/*  | 
    
    
    325  | 
     | 
     | 
    	 * If the address the client asked for is ours, but it wasn't  | 
    
    
    326  | 
     | 
     | 
    	 * available for the client, NAK it.  | 
    
    
    327  | 
     | 
     | 
    	 */  | 
    
    
    328  | 
     | 
     | 
    	if (!lease && ours) { | 
    
    
    329  | 
     | 
     | 
    		nak_lease(packet, &cip);  | 
    
    
    330  | 
     | 
     | 
    		return;  | 
    
    
    331  | 
     | 
     | 
    	}  | 
    
    
    332  | 
     | 
     | 
     | 
    
    
    333  | 
     | 
     | 
    	/* If we're not allowed to serve this client anymore, don't. */  | 
    
    
    334  | 
     | 
     | 
    	if (lease && !lease->host &&  | 
    
    
    335  | 
     | 
     | 
    	    !lease->subnet->group->boot_unknown_clients) { | 
    
    
    336  | 
     | 
     | 
    		log_info("Ignoring unknown client %s", | 
    
    
    337  | 
     | 
     | 
    		    print_hw_addr(packet->raw->htype, packet->raw->hlen,  | 
    
    
    338  | 
     | 
     | 
    		    packet->raw->chaddr));  | 
    
    
    339  | 
     | 
     | 
    		return;  | 
    
    
    340  | 
     | 
     | 
    	} else if (lease && lease->host && !lease->host->group->allow_booting)  | 
    
    
    341  | 
     | 
     | 
    		{ | 
    
    
    342  | 
     | 
     | 
    		log_info("Declining to renew client %s", | 
    
    
    343  | 
     | 
     | 
    		    lease->host->name ? lease->host->name :  | 
    
    
    344  | 
     | 
     | 
    		    print_hw_addr(packet->raw->htype, packet->raw->hlen,  | 
    
    
    345  | 
     | 
     | 
    		    packet->raw->chaddr));  | 
    
    
    346  | 
     | 
     | 
    		return;  | 
    
    
    347  | 
     | 
     | 
    	}  | 
    
    
    348  | 
     | 
     | 
     | 
    
    
    349  | 
     | 
     | 
    	/*  | 
    
    
    350  | 
     | 
     | 
    	 * If we own the lease that the client is asking for,  | 
    
    
    351  | 
     | 
     | 
    	 * and it's already been assigned to the client, ack it.  | 
    
    
    352  | 
     | 
     | 
    	 */  | 
    
    
    353  | 
     | 
     | 
    	if (lease &&  | 
    
    
    354  | 
     | 
     | 
    	    ((lease->uid_len && lease->uid_len ==  | 
    
    
    355  | 
     | 
     | 
    	    packet->options[DHO_DHCP_CLIENT_IDENTIFIER].len &&  | 
    
    
    356  | 
     | 
     | 
    	    !memcmp(packet->options[DHO_DHCP_CLIENT_IDENTIFIER].data,  | 
    
    
    357  | 
     | 
     | 
    	    lease->uid, lease->uid_len)) ||  | 
    
    
    358  | 
     | 
     | 
    	    (lease->hardware_addr.hlen == packet->raw->hlen &&  | 
    
    
    359  | 
     | 
     | 
    	    lease->hardware_addr.htype == packet->raw->htype &&  | 
    
    
    360  | 
     | 
     | 
    	    !memcmp(lease->hardware_addr.haddr, packet->raw->chaddr,  | 
    
    
    361  | 
     | 
     | 
    	    packet->raw->hlen)))) { | 
    
    
    362  | 
     | 
     | 
    		ack_lease(packet, lease, DHCPACK, 0);  | 
    
    
    363  | 
     | 
     | 
    		sync_lease(lease);  | 
    
    
    364  | 
     | 
     | 
    		return;  | 
    
    
    365  | 
     | 
     | 
    	}  | 
    
    
    366  | 
     | 
     | 
     | 
    
    
    367  | 
     | 
     | 
    	/*  | 
    
    
    368  | 
     | 
     | 
    	 * At this point, the client has requested a lease, and it's  | 
    
    
    369  | 
     | 
     | 
    	 * available, but it wasn't assigned to the client, which  | 
    
    
    370  | 
     | 
     | 
    	 * means that the client probably hasn't gone through the  | 
    
    
    371  | 
     | 
     | 
    	 * DHCPDISCOVER part of the protocol.  We are within our  | 
    
    
    372  | 
     | 
     | 
    	 * rights to send a DHCPNAK.   We can also send a DHCPACK.  | 
    
    
    373  | 
     | 
     | 
    	 * The thing we probably should not do is to remain silent.  | 
    
    
    374  | 
     | 
     | 
    	 * For now, we'll just assign the lease to the client anyway.  | 
    
    
    375  | 
     | 
     | 
    	 */  | 
    
    
    376  | 
     | 
     | 
    	if (lease) { | 
    
    
    377  | 
     | 
     | 
    		ack_lease(packet, lease, DHCPACK, 0);  | 
    
    
    378  | 
     | 
     | 
    		sync_lease(lease);  | 
    
    
    379  | 
     | 
     | 
    	}  | 
    
    
    380  | 
     | 
     | 
    }  | 
    
    
    381  | 
     | 
     | 
     | 
    
    
    382  | 
     | 
     | 
    void  | 
    
    
    383  | 
     | 
     | 
    dhcprelease(struct packet *packet)  | 
    
    
    384  | 
     | 
     | 
    { | 
    
    
    385  | 
     | 
     | 
    	char ciaddrbuf[INET_ADDRSTRLEN];  | 
    
    
    386  | 
     | 
     | 
    	struct lease *lease;  | 
    
    
    387  | 
     | 
     | 
    	struct iaddr cip;  | 
    
    
    388  | 
     | 
     | 
    	int i;  | 
    
    
    389  | 
     | 
     | 
     | 
    
    
    390  | 
     | 
     | 
    	/*  | 
    
    
    391  | 
     | 
     | 
    	 * DHCPRELEASE must not specify address in requested-address  | 
    
    
    392  | 
     | 
     | 
    	 * option, but old protocol specs weren't explicit about this,  | 
    
    
    393  | 
     | 
     | 
    	 * so let it go.  | 
    
    
    394  | 
     | 
     | 
    	 */  | 
    
    
    395  | 
     | 
     | 
    	if (packet->options[DHO_DHCP_REQUESTED_ADDRESS].len) { | 
    
    
    396  | 
     | 
     | 
    		log_info("DHCPRELEASE from %s specified requested-address.", | 
    
    
    397  | 
     | 
     | 
    		    print_hw_addr(packet->raw->htype, packet->raw->hlen,  | 
    
    
    398  | 
     | 
     | 
    		    packet->raw->chaddr));  | 
    
    
    399  | 
     | 
     | 
    	}  | 
    
    
    400  | 
     | 
     | 
     | 
    
    
    401  | 
     | 
     | 
    	i = DHO_DHCP_CLIENT_IDENTIFIER;  | 
    
    
    402  | 
     | 
     | 
    	if (packet->options[i].len) { | 
    
    
    403  | 
     | 
     | 
    		lease = find_lease_by_uid(packet->options[i].data,  | 
    
    
    404  | 
     | 
     | 
    		    packet->options[i].len);  | 
    
    
    405  | 
     | 
     | 
     | 
    
    
    406  | 
     | 
     | 
    		/*  | 
    
    
    407  | 
     | 
     | 
    		 * See if we can find a lease that matches the  | 
    
    
    408  | 
     | 
     | 
    		 * IP address the client is claiming.  | 
    
    
    409  | 
     | 
     | 
    		 */  | 
    
    
    410  | 
     | 
     | 
    		for (; lease; lease = lease->n_uid) { | 
    
    
    411  | 
     | 
     | 
    			if (!memcmp(&packet->raw->ciaddr,  | 
    
    
    412  | 
     | 
     | 
    			    lease->ip_addr.iabuf, 4)) { | 
    
    
    413  | 
     | 
     | 
    				break;  | 
    
    
    414  | 
     | 
     | 
    			}  | 
    
    
    415  | 
     | 
     | 
    		}  | 
    
    
    416  | 
     | 
     | 
    	} else { | 
    
    
    417  | 
     | 
     | 
    		/*  | 
    
    
    418  | 
     | 
     | 
    		* The client is supposed to pass a valid client-identifier,  | 
    
    
    419  | 
     | 
     | 
    		 * but the spec on this has changed historically, so try the  | 
    
    
    420  | 
     | 
     | 
    		 * IP address in ciaddr if the client-identifier fails.  | 
    
    
    421  | 
     | 
     | 
    		 */  | 
    
    
    422  | 
     | 
     | 
    		cip.len = 4;  | 
    
    
    423  | 
     | 
     | 
    		memcpy(cip.iabuf, &packet->raw->ciaddr, 4);  | 
    
    
    424  | 
     | 
     | 
    		lease = find_lease_by_ip_addr(cip);  | 
    
    
    425  | 
     | 
     | 
    	}  | 
    
    
    426  | 
     | 
     | 
     | 
    
    
    427  | 
     | 
     | 
    	/* Can't do >1 inet_ntoa() in a printf()! */  | 
    
    
    428  | 
     | 
     | 
    	strlcpy(ciaddrbuf, inet_ntoa(packet->raw->ciaddr), sizeof(ciaddrbuf));  | 
    
    
    429  | 
     | 
     | 
     | 
    
    
    430  | 
     | 
     | 
    	log_info("DHCPRELEASE of %s from %s via %s (%sfound)", | 
    
    
    431  | 
     | 
     | 
    	    ciaddrbuf,  | 
    
    
    432  | 
     | 
     | 
    	    print_hw_addr(packet->raw->htype, packet->raw->hlen,  | 
    
    
    433  | 
     | 
     | 
    	    packet->raw->chaddr),  | 
    
    
    434  | 
     | 
     | 
    	    packet->raw->giaddr.s_addr ? inet_ntoa(packet->raw->giaddr) :  | 
    
    
    435  | 
     | 
     | 
    	    packet->interface->name,  | 
    
    
    436  | 
     | 
     | 
    	    lease ? "" : "not ");  | 
    
    
    437  | 
     | 
     | 
     | 
    
    
    438  | 
     | 
     | 
    	/* If we're already acking this lease, don't do it again. */  | 
    
    
    439  | 
     | 
     | 
    	if (lease && lease->state) { | 
    
    
    440  | 
     | 
     | 
    		log_info("DHCPRELEASE already acking lease %s", | 
    
    
    441  | 
     | 
     | 
    		    piaddr(lease->ip_addr));  | 
    
    
    442  | 
     | 
     | 
    		return;  | 
    
    
    443  | 
     | 
     | 
    	}  | 
    
    
    444  | 
     | 
     | 
     | 
    
    
    445  | 
     | 
     | 
    	/* If we found a lease, release it. */  | 
    
    
    446  | 
     | 
     | 
    	if (lease && lease->ends > cur_time) { | 
    
    
    447  | 
     | 
     | 
    		/*  | 
    
    
    448  | 
     | 
     | 
    		 * First, we ping this lease to see if it's still  | 
    
    
    449  | 
     | 
     | 
    		 * there. if it is, we don't release it. This avoids  | 
    
    
    450  | 
     | 
     | 
    		 * the problem of spoofed releases being used to liberate  | 
    
    
    451  | 
     | 
     | 
    		 * addresses from the server.  | 
    
    
    452  | 
     | 
     | 
    		 */  | 
    
    
    453  | 
     | 
     | 
    		if (!lease->releasing) { | 
    
    
    454  | 
     | 
     | 
    			log_info("DHCPRELEASE of %s from %s via %s (found)", | 
    
    
    455  | 
     | 
     | 
    			    ciaddrbuf,  | 
    
    
    456  | 
     | 
     | 
    			    print_hw_addr(packet->raw->htype,  | 
    
    
    457  | 
     | 
     | 
    			    packet->raw->hlen, packet->raw->chaddr),  | 
    
    
    458  | 
     | 
     | 
    			    packet->raw->giaddr.s_addr ?  | 
    
    
    459  | 
     | 
     | 
    			    inet_ntoa(packet->raw->giaddr) :  | 
    
    
    460  | 
     | 
     | 
    			    packet->interface->name);  | 
    
    
    461  | 
     | 
     | 
     | 
    
    
    462  | 
     | 
     | 
    			lease->releasing = 1;  | 
    
    
    463  | 
     | 
     | 
    			add_timeout(cur_time + 1, lease_ping_timeout, lease);  | 
    
    
    464  | 
     | 
     | 
    			icmp_echorequest(&(lease->ip_addr));  | 
    
    
    465  | 
     | 
     | 
    			++outstanding_pings;  | 
    
    
    466  | 
     | 
     | 
    		} else { | 
    
    
    467  | 
     | 
     | 
    			log_info("DHCPRELEASE of %s from %s via %s ignored " | 
    
    
    468  | 
     | 
     | 
    			    "(release already pending)",  | 
    
    
    469  | 
     | 
     | 
    			    ciaddrbuf,  | 
    
    
    470  | 
     | 
     | 
    			    print_hw_addr(packet->raw->htype,  | 
    
    
    471  | 
     | 
     | 
    			    packet->raw->hlen, packet->raw->chaddr),  | 
    
    
    472  | 
     | 
     | 
    			    packet->raw->giaddr.s_addr ?  | 
    
    
    473  | 
     | 
     | 
    			    inet_ntoa(packet->raw->giaddr) :  | 
    
    
    474  | 
     | 
     | 
    			    packet->interface->name);  | 
    
    
    475  | 
     | 
     | 
    		}  | 
    
    
    476  | 
     | 
     | 
    	} else { | 
    
    
    477  | 
     | 
     | 
    		log_info("DHCPRELEASE of %s from %s via %s for nonexistent " | 
    
    
    478  | 
     | 
     | 
    		    "lease", ciaddrbuf, print_hw_addr(packet->raw->htype,  | 
    
    
    479  | 
     | 
     | 
    		    packet->raw->hlen, packet->raw->chaddr),  | 
    
    
    480  | 
     | 
     | 
    		    packet->raw->giaddr.s_addr ?  | 
    
    
    481  | 
     | 
     | 
    		    inet_ntoa(packet->raw->giaddr) : packet->interface->name);  | 
    
    
    482  | 
     | 
     | 
    	}  | 
    
    
    483  | 
     | 
     | 
    }  | 
    
    
    484  | 
     | 
     | 
     | 
    
    
    485  | 
     | 
     | 
    void  | 
    
    
    486  | 
     | 
     | 
    dhcpdecline(struct packet *packet)  | 
    
    
    487  | 
     | 
     | 
    { | 
    
    
    488  | 
     | 
     | 
    	struct lease *lease;  | 
    
    
    489  | 
     | 
     | 
    	struct iaddr cip;  | 
    
    
    490  | 
     | 
     | 
     | 
    
    
    491  | 
     | 
     | 
    	/* DHCPDECLINE must specify address. */  | 
    
    
    492  | 
     | 
     | 
    	if (packet->options[DHO_DHCP_REQUESTED_ADDRESS].len != 4)  | 
    
    
    493  | 
     | 
     | 
    		return;  | 
    
    
    494  | 
     | 
     | 
     | 
    
    
    495  | 
     | 
     | 
    	cip.len = 4;  | 
    
    
    496  | 
     | 
     | 
    	memcpy(cip.iabuf,  | 
    
    
    497  | 
     | 
     | 
    	    packet->options[DHO_DHCP_REQUESTED_ADDRESS].data, 4);  | 
    
    
    498  | 
     | 
     | 
    	lease = find_lease_by_ip_addr(cip);  | 
    
    
    499  | 
     | 
     | 
     | 
    
    
    500  | 
     | 
     | 
    	log_info("DHCPDECLINE on %s from %s via %s", | 
    
    
    501  | 
     | 
     | 
    	    piaddr(cip), print_hw_addr(packet->raw->htype,  | 
    
    
    502  | 
     | 
     | 
    	    packet->raw->hlen, packet->raw->chaddr),  | 
    
    
    503  | 
     | 
     | 
    	    packet->raw->giaddr.s_addr ? inet_ntoa(packet->raw->giaddr) :  | 
    
    
    504  | 
     | 
     | 
    	    packet->interface->name);  | 
    
    
    505  | 
     | 
     | 
     | 
    
    
    506  | 
     | 
     | 
    	/* If we're already acking this lease, don't do it again. */  | 
    
    
    507  | 
     | 
     | 
    	if (lease && lease->state) { | 
    
    
    508  | 
     | 
     | 
    		log_info("DHCPDECLINE already acking lease %s", | 
    
    
    509  | 
     | 
     | 
    		    piaddr(lease->ip_addr));  | 
    
    
    510  | 
     | 
     | 
    		return;  | 
    
    
    511  | 
     | 
     | 
    	}  | 
    
    
    512  | 
     | 
     | 
     | 
    
    
    513  | 
     | 
     | 
    	/* If we found a lease, mark it as unusable and complain. */  | 
    
    
    514  | 
     | 
     | 
    	if (lease)  | 
    
    
    515  | 
     | 
     | 
    		abandon_lease(lease, "declined.");  | 
    
    
    516  | 
     | 
     | 
    }  | 
    
    
    517  | 
     | 
     | 
     | 
    
    
    518  | 
     | 
     | 
    void  | 
    
    
    519  | 
     | 
     | 
    dhcpinform(struct packet *packet)  | 
    
    
    520  | 
     | 
     | 
    { | 
    
    
    521  | 
     | 
     | 
    	struct lease lease;  | 
    
    
    522  | 
     | 
     | 
    	struct iaddr cip;  | 
    
    
    523  | 
     | 
     | 
    	struct subnet *subnet;  | 
    
    
    524  | 
     | 
     | 
     | 
    
    
    525  | 
     | 
     | 
    	/*  | 
    
    
    526  | 
     | 
     | 
    	 * ciaddr should be set to client's IP address but  | 
    
    
    527  | 
     | 
     | 
    	 * not all clients are standards compliant.  | 
    
    
    528  | 
     | 
     | 
    	 */  | 
    
    
    529  | 
     | 
     | 
    	cip.len = 4;  | 
    
    
    530  | 
     | 
     | 
    	if (packet->raw->ciaddr.s_addr && !packet->raw->giaddr.s_addr) { | 
    
    
    531  | 
     | 
     | 
    		if (memcmp(&packet->raw->ciaddr.s_addr,  | 
    
    
    532  | 
     | 
     | 
    		    packet->client_addr.iabuf, 4) != 0) { | 
    
    
    533  | 
     | 
     | 
    			log_info("DHCPINFORM from %s but ciaddr %s is not " | 
    
    
    534  | 
     | 
     | 
    			    "consistent with actual address",  | 
    
    
    535  | 
     | 
     | 
    			    piaddr(packet->client_addr),  | 
    
    
    536  | 
     | 
     | 
    			    inet_ntoa(packet->raw->ciaddr));  | 
    
    
    537  | 
     | 
     | 
    			return;  | 
    
    
    538  | 
     | 
     | 
    		}  | 
    
    
    539  | 
     | 
     | 
    		memcpy(cip.iabuf, &packet->raw->ciaddr.s_addr, 4);  | 
    
    
    540  | 
     | 
     | 
    	} else  | 
    
    
    541  | 
     | 
     | 
    		memcpy(cip.iabuf, &packet->client_addr.iabuf, 4);  | 
    
    
    542  | 
     | 
     | 
     | 
    
    
    543  | 
     | 
     | 
    	log_info("DHCPINFORM from %s", piaddr(cip)); | 
    
    
    544  | 
     | 
     | 
     | 
    
    
    545  | 
     | 
     | 
    	/* Find the lease that matches the address requested by the client. */  | 
    
    
    546  | 
     | 
     | 
    	subnet = find_subnet(cip);  | 
    
    
    547  | 
     | 
     | 
    	if (!subnet)  | 
    
    
    548  | 
     | 
     | 
    		return;  | 
    
    
    549  | 
     | 
     | 
     | 
    
    
    550  | 
     | 
     | 
    	/* Sourceless packets don't make sense here. */  | 
    
    
    551  | 
     | 
     | 
    	if (!subnet->shared_network) { | 
    
    
    552  | 
     | 
     | 
    		log_info("Packet from unknown subnet: %s", | 
    
    
    553  | 
     | 
     | 
    		    inet_ntoa(packet->raw->giaddr));  | 
    
    
    554  | 
     | 
     | 
    		return;  | 
    
    
    555  | 
     | 
     | 
    	}  | 
    
    
    556  | 
     | 
     | 
     | 
    
    
    557  | 
     | 
     | 
    	/* Use a fake lease entry */  | 
    
    
    558  | 
     | 
     | 
    	memset(&lease, 0, sizeof(lease));  | 
    
    
    559  | 
     | 
     | 
    	lease.subnet = subnet;  | 
    
    
    560  | 
     | 
     | 
    	lease.shared_network = subnet->shared_network;  | 
    
    
    561  | 
     | 
     | 
     | 
    
    
    562  | 
     | 
     | 
    	if (packet->options[DHO_DHCP_CLIENT_IDENTIFIER].len)  | 
    
    
    563  | 
     | 
     | 
    		lease.host = find_hosts_by_uid(  | 
    
    
    564  | 
     | 
     | 
    		    packet->options[DHO_DHCP_CLIENT_IDENTIFIER].data,  | 
    
    
    565  | 
     | 
     | 
    		    packet->options[DHO_DHCP_CLIENT_IDENTIFIER].len);  | 
    
    
    566  | 
     | 
     | 
     | 
    
    
    567  | 
     | 
     | 
    	lease.starts = lease.timestamp = lease.ends = MIN_TIME;  | 
    
    
    568  | 
     | 
     | 
    	lease.flags = INFORM_NOLEASE;  | 
    
    
    569  | 
     | 
     | 
    	ack_lease(packet, &lease, DHCPACK, 0);  | 
    
    
    570  | 
     | 
     | 
    	if (lease.state != NULL)  | 
    
    
    571  | 
     | 
     | 
    		free_lease_state(lease.state, "ack_lease");  | 
    
    
    572  | 
     | 
     | 
    }  | 
    
    
    573  | 
     | 
     | 
     | 
    
    
    574  | 
     | 
     | 
    void  | 
    
    
    575  | 
     | 
     | 
    nak_lease(struct packet *packet, struct iaddr *cip)  | 
    
    
    576  | 
     | 
     | 
    { | 
    
    
    577  | 
     | 
     | 
    	struct sockaddr_in to;  | 
    
    
    578  | 
     | 
     | 
    	struct in_addr from;  | 
    
    
    579  | 
     | 
     | 
    	ssize_t result;  | 
    
    
    580  | 
     | 
     | 
    	int i;  | 
    
    
    581  | 
     | 
     | 
    	struct dhcp_packet raw;  | 
    
    
    582  | 
     | 
     | 
    	unsigned char nak = DHCPNAK;  | 
    
    
    583  | 
     | 
     | 
    	struct packet outgoing;  | 
    
    
    584  | 
     | 
     | 
    	struct tree_cache *options[256];  | 
    
    
    585  | 
     | 
     | 
    	struct tree_cache dhcpnak_tree, dhcpmsg_tree;  | 
    
    
    586  | 
     | 
     | 
    	struct tree_cache client_tree, server_tree;  | 
    
    
    587  | 
     | 
     | 
     | 
    
    
    588  | 
     | 
     | 
    	memset(options, 0, sizeof options);  | 
    
    
    589  | 
     | 
     | 
    	memset(&outgoing, 0, sizeof outgoing);  | 
    
    
    590  | 
     | 
     | 
    	memset(&raw, 0, sizeof raw);  | 
    
    
    591  | 
     | 
     | 
    	outgoing.raw = &raw;  | 
    
    
    592  | 
     | 
     | 
     | 
    
    
    593  | 
     | 
     | 
    	/* Set DHCP_MESSAGE_TYPE to DHCPNAK */  | 
    
    
    594  | 
     | 
     | 
    	i = DHO_DHCP_MESSAGE_TYPE;  | 
    
    
    595  | 
     | 
     | 
    	options[i] = &dhcpnak_tree;  | 
    
    
    596  | 
     | 
     | 
    	options[i]->value = &nak;  | 
    
    
    597  | 
     | 
     | 
    	options[i]->len = sizeof nak;  | 
    
    
    598  | 
     | 
     | 
    	options[i]->buf_size = sizeof nak;  | 
    
    
    599  | 
     | 
     | 
    	options[i]->timeout = -1;  | 
    
    
    600  | 
     | 
     | 
    	options[i]->tree = NULL;  | 
    
    
    601  | 
     | 
     | 
    	options[i]->flags = 0;  | 
    
    
    602  | 
     | 
     | 
     | 
    
    
    603  | 
     | 
     | 
    	/* Set DHCP_MESSAGE to whatever the message is */  | 
    
    
    604  | 
     | 
     | 
    	i = DHO_DHCP_MESSAGE;  | 
    
    
    605  | 
     | 
     | 
    	options[i] = &dhcpmsg_tree;  | 
    
    
    606  | 
     | 
     | 
    	options[i]->value = (unsigned char *)dhcp_message;  | 
    
    
    607  | 
     | 
     | 
    	options[i]->len = strlen(dhcp_message);  | 
    
    
    608  | 
     | 
     | 
    	options[i]->buf_size = strlen(dhcp_message);  | 
    
    
    609  | 
     | 
     | 
    	options[i]->timeout = -1;  | 
    
    
    610  | 
     | 
     | 
    	options[i]->tree = NULL;  | 
    
    
    611  | 
     | 
     | 
    	options[i]->flags = 0;  | 
    
    
    612  | 
     | 
     | 
     | 
    
    
    613  | 
     | 
     | 
    	/* Include server identifier in the NAK. At least one  | 
    
    
    614  | 
     | 
     | 
    	 * router vendor depends on it when using dhcp relay proxy mode.  | 
    
    
    615  | 
     | 
     | 
    	 */  | 
    
    
    616  | 
     | 
     | 
    	i = DHO_DHCP_SERVER_IDENTIFIER;  | 
    
    
    617  | 
     | 
     | 
    	if (packet->options[i].len) { | 
    
    
    618  | 
     | 
     | 
    		options[i] = &server_tree;  | 
    
    
    619  | 
     | 
     | 
    		options[i]->value = packet->options[i].data,  | 
    
    
    620  | 
     | 
     | 
    		options[i]->len = packet->options[i].len;  | 
    
    
    621  | 
     | 
     | 
    		options[i]->buf_size = packet->options[i].len;  | 
    
    
    622  | 
     | 
     | 
    		options[i]->timeout = -1;  | 
    
    
    623  | 
     | 
     | 
    		options[i]->tree = NULL;  | 
    
    
    624  | 
     | 
     | 
    		options[i]->flags = 0;  | 
    
    
    625  | 
     | 
     | 
    	}  | 
    
    
    626  | 
     | 
     | 
     | 
    
    
    627  | 
     | 
     | 
    	/* Echo back the client-identifier as RFC 6842 mandates. */  | 
    
    
    628  | 
     | 
     | 
    	i = DHO_DHCP_CLIENT_IDENTIFIER;  | 
    
    
    629  | 
     | 
     | 
    	if (packet->options[i].len) { | 
    
    
    630  | 
     | 
     | 
    		options[i] = &client_tree;  | 
    
    
    631  | 
     | 
     | 
    		options[i]->value = packet->options[i].data,  | 
    
    
    632  | 
     | 
     | 
    		options[i]->len = packet->options[i].len;  | 
    
    
    633  | 
     | 
     | 
    		options[i]->buf_size = packet->options[i].len;  | 
    
    
    634  | 
     | 
     | 
    		options[i]->timeout = -1;  | 
    
    
    635  | 
     | 
     | 
    		options[i]->tree = NULL;  | 
    
    
    636  | 
     | 
     | 
    		options[i]->flags = 0;  | 
    
    
    637  | 
     | 
     | 
    	}  | 
    
    
    638  | 
     | 
     | 
     | 
    
    
    639  | 
     | 
     | 
    	/* Do not use the client's requested parameter list. */  | 
    
    
    640  | 
     | 
     | 
    	i = DHO_DHCP_PARAMETER_REQUEST_LIST;  | 
    
    
    641  | 
     | 
     | 
    	if (packet->options[i].data) { | 
    
    
    642  | 
     | 
     | 
    		packet->options[i].len = 0;  | 
    
    
    643  | 
     | 
     | 
    		free(packet->options[i].data);  | 
    
    
    644  | 
     | 
     | 
    		packet->options[i].data = NULL;  | 
    
    
    645  | 
     | 
     | 
    	}  | 
    
    
    646  | 
     | 
     | 
     | 
    
    
    647  | 
     | 
     | 
    	/* Set up the option buffer... */  | 
    
    
    648  | 
     | 
     | 
    	outgoing.packet_length = cons_options(packet, outgoing.raw,  | 
    
    
    649  | 
     | 
     | 
    	    0, options, 0, 0, 0, NULL, 0);  | 
    
    
    650  | 
     | 
     | 
     | 
    
    
    651  | 
     | 
     | 
    /*	memset(&raw.ciaddr, 0, sizeof raw.ciaddr);*/  | 
    
    
    652  | 
     | 
     | 
    	raw.siaddr = packet->interface->primary_address;  | 
    
    
    653  | 
     | 
     | 
    	raw.giaddr = packet->raw->giaddr;  | 
    
    
    654  | 
     | 
     | 
    	memcpy(raw.chaddr, packet->raw->chaddr, sizeof raw.chaddr);  | 
    
    
    655  | 
     | 
     | 
    	raw.hlen = packet->raw->hlen;  | 
    
    
    656  | 
     | 
     | 
    	raw.htype = packet->raw->htype;  | 
    
    
    657  | 
     | 
     | 
    	raw.xid = packet->raw->xid;  | 
    
    
    658  | 
     | 
     | 
    	raw.secs = packet->raw->secs;  | 
    
    
    659  | 
     | 
     | 
    	raw.flags = packet->raw->flags | htons(BOOTP_BROADCAST);  | 
    
    
    660  | 
     | 
     | 
    	raw.hops = packet->raw->hops;  | 
    
    
    661  | 
     | 
     | 
    	raw.op = BOOTREPLY;  | 
    
    
    662  | 
     | 
     | 
     | 
    
    
    663  | 
     | 
     | 
    	/* Report what we're sending... */  | 
    
    
    664  | 
     | 
     | 
    	log_info("DHCPNAK on %s to %s via %s", piaddr(*cip), | 
    
    
    665  | 
     | 
     | 
    	    print_hw_addr(packet->raw->htype, packet->raw->hlen,  | 
    
    
    666  | 
     | 
     | 
    	    packet->raw->chaddr), packet->raw->giaddr.s_addr ?  | 
    
    
    667  | 
     | 
     | 
    	    inet_ntoa(packet->raw->giaddr) : packet->interface->name);  | 
    
    
    668  | 
     | 
     | 
     | 
    
    
    669  | 
     | 
     | 
    	/* Set up the common stuff... */  | 
    
    
    670  | 
     | 
     | 
    	memset(&to, 0, sizeof to);  | 
    
    
    671  | 
     | 
     | 
    	to.sin_family = AF_INET;  | 
    
    
    672  | 
     | 
     | 
    	to.sin_len = sizeof to;  | 
    
    
    673  | 
     | 
     | 
     | 
    
    
    674  | 
     | 
     | 
    	from = packet->interface->primary_address;  | 
    
    
    675  | 
     | 
     | 
     | 
    
    
    676  | 
     | 
     | 
    	/* Make sure that the packet is at least as big as a BOOTP packet. */  | 
    
    
    677  | 
     | 
     | 
    	if (outgoing.packet_length < BOOTP_MIN_LEN)  | 
    
    
    678  | 
     | 
     | 
    		outgoing.packet_length = BOOTP_MIN_LEN;  | 
    
    
    679  | 
     | 
     | 
     | 
    
    
    680  | 
     | 
     | 
    	/*  | 
    
    
    681  | 
     | 
     | 
    	 * If this was gatewayed, send it back to the gateway.  | 
    
    
    682  | 
     | 
     | 
    	 * Otherwise, broadcast it on the local network.  | 
    
    
    683  | 
     | 
     | 
    	 */  | 
    
    
    684  | 
     | 
     | 
    	if (raw.giaddr.s_addr) { | 
    
    
    685  | 
     | 
     | 
    		to.sin_addr = raw.giaddr;  | 
    
    
    686  | 
     | 
     | 
    		to.sin_port = server_port;  | 
    
    
    687  | 
     | 
     | 
     | 
    
    
    688  | 
     | 
     | 
    		result = packet->interface->send_packet(packet->interface, &raw,  | 
    
    
    689  | 
     | 
     | 
    		    outgoing.packet_length, from, &to, packet->haddr);  | 
    
    
    690  | 
     | 
     | 
    		if (result == -1)  | 
    
    
    691  | 
     | 
     | 
    			log_warn("send_fallback"); | 
    
    
    692  | 
     | 
     | 
    		return;  | 
    
    
    693  | 
     | 
     | 
    	} else { | 
    
    
    694  | 
     | 
     | 
    		to.sin_addr.s_addr = htonl(INADDR_BROADCAST);  | 
    
    
    695  | 
     | 
     | 
    		to.sin_port = client_port;  | 
    
    
    696  | 
     | 
     | 
    	}  | 
    
    
    697  | 
     | 
     | 
     | 
    
    
    698  | 
     | 
     | 
    	errno = 0;  | 
    
    
    699  | 
     | 
     | 
    	result = packet->interface->send_packet(packet->interface, &raw,  | 
    
    
    700  | 
     | 
     | 
    	    outgoing.packet_length, from, &to, NULL);  | 
    
    
    701  | 
     | 
     | 
    }  | 
    
    
    702  | 
     | 
     | 
     | 
    
    
    703  | 
     | 
     | 
    void  | 
    
    
    704  | 
     | 
     | 
    ack_lease(struct packet *packet, struct lease *lease, unsigned int offer,  | 
    
    
    705  | 
     | 
     | 
        time_t when)  | 
    
    
    706  | 
     | 
     | 
    { | 
    
    
    707  | 
     | 
     | 
    	struct lease lt;  | 
    
    
    708  | 
     | 
     | 
    	struct lease_state *state;  | 
    
    
    709  | 
     | 
     | 
    	time_t lease_time, offered_lease_time, max_lease_time, default_lease_time;  | 
    
    
    710  | 
     | 
     | 
    	struct class *vendor_class, *user_class;  | 
    
    
    711  | 
     | 
     | 
    	int ulafdr, echo_client_id, i;  | 
    
    
    712  | 
     | 
     | 
     | 
    
    
    713  | 
     | 
     | 
    	/* If we're already acking this lease, don't do it again. */  | 
    
    
    714  | 
     | 
     | 
    	if (lease->state) { | 
    
    
    715  | 
     | 
     | 
    		if ((lease->flags & STATIC_LEASE) ||  | 
    
    
    716  | 
     | 
     | 
    		    cur_time - lease->timestamp < 60) { | 
    
    
    717  | 
     | 
     | 
    			log_info("already acking lease %s", | 
    
    
    718  | 
     | 
     | 
    			    piaddr(lease->ip_addr));  | 
    
    
    719  | 
     | 
     | 
    			return;  | 
    
    
    720  | 
     | 
     | 
    		}  | 
    
    
    721  | 
     | 
     | 
    		free_lease_state(lease->state, "ACK timed out");  | 
    
    
    722  | 
     | 
     | 
    		lease->state = NULL;  | 
    
    
    723  | 
     | 
     | 
    	}  | 
    
    
    724  | 
     | 
     | 
     | 
    
    
    725  | 
     | 
     | 
    	i = DHO_DHCP_CLASS_IDENTIFIER;  | 
    
    
    726  | 
     | 
     | 
    	if (packet->options[i].len) { | 
    
    
    727  | 
     | 
     | 
    		vendor_class = find_class(0, packet->options[i].data,  | 
    
    
    728  | 
     | 
     | 
    		    packet->options[i].len);  | 
    
    
    729  | 
     | 
     | 
    	} else  | 
    
    
    730  | 
     | 
     | 
    		vendor_class = NULL;  | 
    
    
    731  | 
     | 
     | 
     | 
    
    
    732  | 
     | 
     | 
    	i = DHO_DHCP_USER_CLASS_ID;  | 
    
    
    733  | 
     | 
     | 
    	if (packet->options[i].len) { | 
    
    
    734  | 
     | 
     | 
    		user_class = find_class(1, packet->options[i].data,  | 
    
    
    735  | 
     | 
     | 
    		    packet->options[i].len);  | 
    
    
    736  | 
     | 
     | 
    	} else  | 
    
    
    737  | 
     | 
     | 
    		user_class = NULL;  | 
    
    
    738  | 
     | 
     | 
     | 
    
    
    739  | 
     | 
     | 
    	/*  | 
    
    
    740  | 
     | 
     | 
    	 * If there is not a specific host entry, and either the  | 
    
    
    741  | 
     | 
     | 
    	 * vendor class or user class (if they exist) deny booting,  | 
    
    
    742  | 
     | 
     | 
    	 * then bug out.  | 
    
    
    743  | 
     | 
     | 
    	 */  | 
    
    
    744  | 
     | 
     | 
    	if (!lease->host) { | 
    
    
    745  | 
     | 
     | 
    		if (vendor_class && !vendor_class->group->allow_booting) { | 
    
    
    746  | 
     | 
     | 
    			log_debug("Booting denied by vendor class"); | 
    
    
    747  | 
     | 
     | 
    			return;  | 
    
    
    748  | 
     | 
     | 
    		}  | 
    
    
    749  | 
     | 
     | 
     | 
    
    
    750  | 
     | 
     | 
    		if (user_class && !user_class->group->allow_booting) { | 
    
    
    751  | 
     | 
     | 
    			log_debug("Booting denied by user class"); | 
    
    
    752  | 
     | 
     | 
    			return;  | 
    
    
    753  | 
     | 
     | 
    		}  | 
    
    
    754  | 
     | 
     | 
    	}  | 
    
    
    755  | 
     | 
     | 
     | 
    
    
    756  | 
     | 
     | 
    	/* Allocate a lease state structure... */  | 
    
    
    757  | 
     | 
     | 
    	state = new_lease_state("ack_lease"); | 
    
    
    758  | 
     | 
     | 
    	if (!state)  | 
    
    
    759  | 
     | 
     | 
    		fatalx("unable to allocate lease state!"); | 
    
    
    760  | 
     | 
     | 
    	memset(state, 0, sizeof *state);  | 
    
    
    761  | 
     | 
     | 
    	state->got_requested_address = packet->got_requested_address;  | 
    
    
    762  | 
     | 
     | 
    	state->shared_network = packet->interface->shared_network;  | 
    
    
    763  | 
     | 
     | 
     | 
    
    
    764  | 
     | 
     | 
    	/* Remember if we got a server identifier option. */  | 
    
    
    765  | 
     | 
     | 
    	i = DHO_DHCP_SERVER_IDENTIFIER;  | 
    
    
    766  | 
     | 
     | 
    	if (packet->options[i].len)  | 
    
    
    767  | 
     | 
     | 
    		state->got_server_identifier = 1;  | 
    
    
    768  | 
     | 
     | 
     | 
    
    
    769  | 
     | 
     | 
    	/* Replace the old lease hostname with the new one, if it's changed. */  | 
    
    
    770  | 
     | 
     | 
    	i = DHO_HOST_NAME;  | 
    
    
    771  | 
     | 
     | 
    	if (packet->options[i].len && lease->client_hostname &&  | 
    
    
    772  | 
     | 
     | 
    	    (strlen(lease->client_hostname) == packet->options[i].len) &&  | 
    
    
    773  | 
     | 
     | 
    	    !memcmp(lease->client_hostname, packet->options[i].data,  | 
    
    
    774  | 
     | 
     | 
    	    packet->options[i].len)) { | 
    
    
    775  | 
     | 
     | 
    	} else if (packet->options[i].len) { | 
    
    
    776  | 
     | 
     | 
    		free(lease->client_hostname);  | 
    
    
    777  | 
     | 
     | 
    		lease->client_hostname = malloc( packet->options[i].len + 1);  | 
    
    
    778  | 
     | 
     | 
    		if (!lease->client_hostname)  | 
    
    
    779  | 
     | 
     | 
    			fatalx("no memory for client hostname.\n"); | 
    
    
    780  | 
     | 
     | 
    		memcpy(lease->client_hostname, packet->options[i].data,  | 
    
    
    781  | 
     | 
     | 
    		    packet->options[i].len);  | 
    
    
    782  | 
     | 
     | 
    		lease->client_hostname[packet->options[i].len] = 0;  | 
    
    
    783  | 
     | 
     | 
    	} else if (lease->client_hostname) { | 
    
    
    784  | 
     | 
     | 
    		free(lease->client_hostname);  | 
    
    
    785  | 
     | 
     | 
    		lease->client_hostname = 0;  | 
    
    
    786  | 
     | 
     | 
    	}  | 
    
    
    787  | 
     | 
     | 
     | 
    
    
    788  | 
     | 
     | 
    	/* Replace the lease client identifier with a new one. */  | 
    
    
    789  | 
     | 
     | 
    	i = DHO_DHCP_CLIENT_IDENTIFIER;  | 
    
    
    790  | 
     | 
     | 
    	if (packet->options[i].len && lease->client_identifier &&  | 
    
    
    791  | 
     | 
     | 
    	    lease->client_identifier_len == packet->options[i].len &&  | 
    
    
    792  | 
     | 
     | 
    	    !memcmp(lease->client_identifier, packet->options[i].data,  | 
    
    
    793  | 
     | 
     | 
    	    packet->options[i].len)) { | 
    
    
    794  | 
     | 
     | 
    		/* Same client identifier. */  | 
    
    
    795  | 
     | 
     | 
    	} else if (packet->options[i].len) { | 
    
    
    796  | 
     | 
     | 
    		free(lease->client_identifier);  | 
    
    
    797  | 
     | 
     | 
    		lease->client_identifier = malloc(packet->options[i].len);  | 
    
    
    798  | 
     | 
     | 
    		if (!lease->client_identifier)  | 
    
    
    799  | 
     | 
     | 
    			fatalx("no memory for client identifier.\n"); | 
    
    
    800  | 
     | 
     | 
    		lease->client_identifier_len = packet->options[i].len;  | 
    
    
    801  | 
     | 
     | 
    		memcpy(lease->client_identifier, packet->options[i].data,  | 
    
    
    802  | 
     | 
     | 
    		    packet->options[i].len);  | 
    
    
    803  | 
     | 
     | 
    	} else if (lease->client_identifier) { | 
    
    
    804  | 
     | 
     | 
    		free(lease->client_identifier);  | 
    
    
    805  | 
     | 
     | 
    		lease->client_identifier = NULL;  | 
    
    
    806  | 
     | 
     | 
    		lease->client_identifier_len = 0;  | 
    
    
    807  | 
     | 
     | 
    	}  | 
    
    
    808  | 
     | 
     | 
     | 
    
    
    809  | 
     | 
     | 
    	/*  | 
    
    
    810  | 
     | 
     | 
    	 * Choose a filename; first from the host_decl, if any, then from  | 
    
    
    811  | 
     | 
     | 
    	 * the user class, then from the vendor class.  | 
    
    
    812  | 
     | 
     | 
    	 */  | 
    
    
    813  | 
     | 
     | 
    	if (lease->host && lease->host->group->filename)  | 
    
    
    814  | 
     | 
     | 
    		strlcpy(state->filename, lease->host->group->filename,  | 
    
    
    815  | 
     | 
     | 
    		    sizeof state->filename);  | 
    
    
    816  | 
     | 
     | 
    	else if (user_class && user_class->group->filename)  | 
    
    
    817  | 
     | 
     | 
    		strlcpy(state->filename, user_class->group->filename,  | 
    
    
    818  | 
     | 
     | 
    		    sizeof state->filename);  | 
    
    
    819  | 
     | 
     | 
    	else if (vendor_class && vendor_class->group->filename)  | 
    
    
    820  | 
     | 
     | 
    		strlcpy(state->filename, vendor_class->group->filename,  | 
    
    
    821  | 
     | 
     | 
    		    sizeof state->filename);  | 
    
    
    822  | 
     | 
     | 
    	else if (packet->raw->file[0])  | 
    
    
    823  | 
     | 
     | 
    		strlcpy(state->filename, packet->raw->file,  | 
    
    
    824  | 
     | 
     | 
    		    sizeof state->filename);  | 
    
    
    825  | 
     | 
     | 
    	else if (lease->subnet->group->filename)  | 
    
    
    826  | 
     | 
     | 
    		strlcpy(state->filename, lease->subnet->group->filename,  | 
    
    
    827  | 
     | 
     | 
    		    sizeof state->filename);  | 
    
    
    828  | 
     | 
     | 
    	else  | 
    
    
    829  | 
     | 
     | 
    		strlcpy(state->filename, "", sizeof state->filename);  | 
    
    
    830  | 
     | 
     | 
     | 
    
    
    831  | 
     | 
     | 
    	/* Choose a server name as above. */  | 
    
    
    832  | 
     | 
     | 
    	if (lease->host && lease->host->group->server_name)  | 
    
    
    833  | 
     | 
     | 
    		state->server_name = lease->host->group->server_name;  | 
    
    
    834  | 
     | 
     | 
    	else if (user_class && user_class->group->server_name)  | 
    
    
    835  | 
     | 
     | 
    		state->server_name = user_class->group->server_name;  | 
    
    
    836  | 
     | 
     | 
    	else if (vendor_class && vendor_class->group->server_name)  | 
    
    
    837  | 
     | 
     | 
    		state->server_name = vendor_class->group->server_name;  | 
    
    
    838  | 
     | 
     | 
    	else if (lease->subnet->group->server_name)  | 
    
    
    839  | 
     | 
     | 
    		state->server_name = lease->subnet->group->server_name;  | 
    
    
    840  | 
     | 
     | 
    	else state->server_name = NULL;  | 
    
    
    841  | 
     | 
     | 
     | 
    
    
    842  | 
     | 
     | 
    	/*  | 
    
    
    843  | 
     | 
     | 
    	 * At this point, we have a lease that we can offer the client.  | 
    
    
    844  | 
     | 
     | 
    	 * Now we construct a lease structure that contains what we want,  | 
    
    
    845  | 
     | 
     | 
    	 * and call supersede_lease to do the right thing with it.  | 
    
    
    846  | 
     | 
     | 
    	 */  | 
    
    
    847  | 
     | 
     | 
    	memset(<, 0, sizeof lt);  | 
    
    
    848  | 
     | 
     | 
     | 
    
    
    849  | 
     | 
     | 
    	/*  | 
    
    
    850  | 
     | 
     | 
    	 * Use the ip address of the lease that we finally found in  | 
    
    
    851  | 
     | 
     | 
    	 * the database.  | 
    
    
    852  | 
     | 
     | 
    	 */  | 
    
    
    853  | 
     | 
     | 
    	lt.ip_addr = lease->ip_addr;  | 
    
    
    854  | 
     | 
     | 
     | 
    
    
    855  | 
     | 
     | 
    	/* Start now. */  | 
    
    
    856  | 
     | 
     | 
    	lt.starts = cur_time;  | 
    
    
    857  | 
     | 
     | 
     | 
    
    
    858  | 
     | 
     | 
    	/* Figure out maximum lease time. */  | 
    
    
    859  | 
     | 
     | 
    	if (lease->host && lease->host->group->max_lease_time)  | 
    
    
    860  | 
     | 
     | 
    		max_lease_time = lease->host->group->max_lease_time;  | 
    
    
    861  | 
     | 
     | 
    	else  | 
    
    
    862  | 
     | 
     | 
    		max_lease_time = lease->subnet->group->max_lease_time;  | 
    
    
    863  | 
     | 
     | 
     | 
    
    
    864  | 
     | 
     | 
    	/* Figure out default lease time. */  | 
    
    
    865  | 
     | 
     | 
    	if (lease->host && lease->host->group->default_lease_time)  | 
    
    
    866  | 
     | 
     | 
    		default_lease_time = lease->host->group->default_lease_time;  | 
    
    
    867  | 
     | 
     | 
    	else  | 
    
    
    868  | 
     | 
     | 
    		default_lease_time = lease->subnet->group->default_lease_time;  | 
    
    
    869  | 
     | 
     | 
     | 
    
    
    870  | 
     | 
     | 
    	/*  | 
    
    
    871  | 
     | 
     | 
    	 * Figure out how long a lease to assign.    If this is a  | 
    
    
    872  | 
     | 
     | 
    	 * dynamic BOOTP lease, its duration must be infinite.  | 
    
    
    873  | 
     | 
     | 
    	 */  | 
    
    
    874  | 
     | 
     | 
    	if (offer) { | 
    
    
    875  | 
     | 
     | 
    		i = DHO_DHCP_LEASE_TIME;  | 
    
    
    876  | 
     | 
     | 
    		if (packet->options[i].len == 4) { | 
    
    
    877  | 
     | 
     | 
    			lease_time = getULong( packet->options[i].data);  | 
    
    
    878  | 
     | 
     | 
     | 
    
    
    879  | 
     | 
     | 
    			/*  | 
    
    
    880  | 
     | 
     | 
    			 * Don't let the client ask for a longer lease than  | 
    
    
    881  | 
     | 
     | 
    			 * is supported for this subnet or host.  | 
    
    
    882  | 
     | 
     | 
    			 *  | 
    
    
    883  | 
     | 
     | 
    			 * time_t is signed, so really large numbers come  | 
    
    
    884  | 
     | 
     | 
    			 * back as negative.  Don't allow lease_time of 0,  | 
    
    
    885  | 
     | 
     | 
    			 * either.  | 
    
    
    886  | 
     | 
     | 
    			 */  | 
    
    
    887  | 
     | 
     | 
    			if (lease_time < 1 || lease_time > max_lease_time)  | 
    
    
    888  | 
     | 
     | 
    				lease_time = max_lease_time;  | 
    
    
    889  | 
     | 
     | 
    		} else  | 
    
    
    890  | 
     | 
     | 
    			lease_time = default_lease_time;  | 
    
    
    891  | 
     | 
     | 
     | 
    
    
    892  | 
     | 
     | 
    		state->offered_expiry = cur_time + lease_time;  | 
    
    
    893  | 
     | 
     | 
    		if (when)  | 
    
    
    894  | 
     | 
     | 
    			lt.ends = when;  | 
    
    
    895  | 
     | 
     | 
    		else  | 
    
    
    896  | 
     | 
     | 
    			lt.ends = state->offered_expiry;  | 
    
    
    897  | 
     | 
     | 
    	} else { | 
    
    
    898  | 
     | 
     | 
    		if (lease->host &&  | 
    
    
    899  | 
     | 
     | 
    		    lease->host->group->bootp_lease_length)  | 
    
    
    900  | 
     | 
     | 
    			lt.ends = (cur_time +  | 
    
    
    901  | 
     | 
     | 
    			    lease->host->group->bootp_lease_length);  | 
    
    
    902  | 
     | 
     | 
    		else if (lease->subnet->group->bootp_lease_length)  | 
    
    
    903  | 
     | 
     | 
    			lt.ends = (cur_time +  | 
    
    
    904  | 
     | 
     | 
    			    lease->subnet->group->bootp_lease_length);  | 
    
    
    905  | 
     | 
     | 
    		else if (lease->host &&  | 
    
    
    906  | 
     | 
     | 
    		    lease->host->group->bootp_lease_cutoff)  | 
    
    
    907  | 
     | 
     | 
    			lt.ends = lease->host->group->bootp_lease_cutoff;  | 
    
    
    908  | 
     | 
     | 
    		else  | 
    
    
    909  | 
     | 
     | 
    			lt.ends = lease->subnet->group->bootp_lease_cutoff;  | 
    
    
    910  | 
     | 
     | 
    		state->offered_expiry = lt.ends;  | 
    
    
    911  | 
     | 
     | 
    		lt.flags = BOOTP_LEASE;  | 
    
    
    912  | 
     | 
     | 
    	}  | 
    
    
    913  | 
     | 
     | 
     | 
    
    
    914  | 
     | 
     | 
    	/* Record the uid, if given... */  | 
    
    
    915  | 
     | 
     | 
    	i = DHO_DHCP_CLIENT_IDENTIFIER;  | 
    
    
    916  | 
     | 
     | 
    	if (packet->options[i].len) { | 
    
    
    917  | 
     | 
     | 
    		if (packet->options[i].len <= sizeof lt.uid_buf) { | 
    
    
    918  | 
     | 
     | 
    			memcpy(lt.uid_buf, packet->options[i].data,  | 
    
    
    919  | 
     | 
     | 
    			    packet->options[i].len);  | 
    
    
    920  | 
     | 
     | 
    			lt.uid = lt.uid_buf;  | 
    
    
    921  | 
     | 
     | 
    			lt.uid_max = sizeof lt.uid_buf;  | 
    
    
    922  | 
     | 
     | 
    			lt.uid_len = packet->options[i].len;  | 
    
    
    923  | 
     | 
     | 
    		} else { | 
    
    
    924  | 
     | 
     | 
    			lt.uid_max = lt.uid_len = packet->options[i].len;  | 
    
    
    925  | 
     | 
     | 
    			lt.uid = malloc(lt.uid_max);  | 
    
    
    926  | 
     | 
     | 
    			if (!lt.uid)  | 
    
    
    927  | 
     | 
     | 
    				fatalx("can't allocate memory for large uid."); | 
    
    
    928  | 
     | 
     | 
    			memcpy(lt.uid, packet->options[i].data, lt.uid_len);  | 
    
    
    929  | 
     | 
     | 
    		}  | 
    
    
    930  | 
     | 
     | 
    	}  | 
    
    
    931  | 
     | 
     | 
     | 
    
    
    932  | 
     | 
     | 
    	lt.host = lease->host;  | 
    
    
    933  | 
     | 
     | 
    	lt.subnet = lease->subnet;  | 
    
    
    934  | 
     | 
     | 
    	lt.shared_network = lease->shared_network;  | 
    
    
    935  | 
     | 
     | 
     | 
    
    
    936  | 
     | 
     | 
    	/* Don't call supersede_lease on a mocked-up lease. */  | 
    
    
    937  | 
     | 
     | 
    	if (lease->flags & (STATIC_LEASE | INFORM_NOLEASE)) { | 
    
    
    938  | 
     | 
     | 
    		/* Copy the hardware address into the static lease  | 
    
    
    939  | 
     | 
     | 
    		   structure. */  | 
    
    
    940  | 
     | 
     | 
    		lease->hardware_addr.hlen = packet->raw->hlen;  | 
    
    
    941  | 
     | 
     | 
    		lease->hardware_addr.htype = packet->raw->htype;  | 
    
    
    942  | 
     | 
     | 
    		memcpy(lease->hardware_addr.haddr, packet->raw->chaddr,  | 
    
    
    943  | 
     | 
     | 
    		    sizeof packet->raw->chaddr); /* XXX */  | 
    
    
    944  | 
     | 
     | 
    	} else { | 
    
    
    945  | 
     | 
     | 
    		/* Record the hardware address, if given... */  | 
    
    
    946  | 
     | 
     | 
    		lt.hardware_addr.hlen = packet->raw->hlen;  | 
    
    
    947  | 
     | 
     | 
    		lt.hardware_addr.htype = packet->raw->htype;  | 
    
    
    948  | 
     | 
     | 
    		memcpy(lt.hardware_addr.haddr, packet->raw->chaddr,  | 
    
    
    949  | 
     | 
     | 
    		    sizeof packet->raw->chaddr);  | 
    
    
    950  | 
     | 
     | 
     | 
    
    
    951  | 
     | 
     | 
    		/* Install the new information about this lease in the  | 
    
    
    952  | 
     | 
     | 
    		   database.  If this is a DHCPACK or a dynamic BOOTREPLY  | 
    
    
    953  | 
     | 
     | 
    		   and we can't write the lease, don't ACK it (or BOOTREPLY  | 
    
    
    954  | 
     | 
     | 
    		   it) either. */  | 
    
    
    955  | 
     | 
     | 
     | 
    
    
    956  | 
     | 
     | 
    		if (!(supersede_lease(lease, <, !offer ||  | 
    
    
    957  | 
     | 
     | 
    		    offer == DHCPACK) || (offer && offer != DHCPACK))) { | 
    
    
    958  | 
     | 
     | 
    			free_lease_state(state, "ack_lease: !supersede_lease");  | 
    
    
    959  | 
     | 
     | 
    			return;  | 
    
    
    960  | 
     | 
     | 
    		}  | 
    
    
    961  | 
     | 
     | 
    	}  | 
    
    
    962  | 
     | 
     | 
     | 
    
    
    963  | 
     | 
     | 
    	/* Remember the interface on which the packet arrived. */  | 
    
    
    964  | 
     | 
     | 
    	state->ip = packet->interface;  | 
    
    
    965  | 
     | 
     | 
     | 
    
    
    966  | 
     | 
     | 
    	/* Set a flag if this client is a lame Microsoft client that NUL  | 
    
    
    967  | 
     | 
     | 
    	   terminates string options and expects us to do likewise. */  | 
    
    
    968  | 
     | 
     | 
    	i = DHO_HOST_NAME;  | 
    
    
    969  | 
     | 
     | 
    	if (packet->options[i].len &&  | 
    
    
    970  | 
     | 
     | 
    	    packet->options[i].data[packet->options[i].len - 1] == '\0')  | 
    
    
    971  | 
     | 
     | 
    		lease->flags |= MS_NULL_TERMINATION;  | 
    
    
    972  | 
     | 
     | 
    	else  | 
    
    
    973  | 
     | 
     | 
    		lease->flags &= ~MS_NULL_TERMINATION;  | 
    
    
    974  | 
     | 
     | 
     | 
    
    
    975  | 
     | 
     | 
    	/* Remember the giaddr, xid, secs, flags and hops. */  | 
    
    
    976  | 
     | 
     | 
    	state->giaddr = packet->raw->giaddr;  | 
    
    
    977  | 
     | 
     | 
    	state->ciaddr = packet->raw->ciaddr;  | 
    
    
    978  | 
     | 
     | 
    	state->xid = packet->raw->xid;  | 
    
    
    979  | 
     | 
     | 
    	state->secs = packet->raw->secs;  | 
    
    
    980  | 
     | 
     | 
    	state->bootp_flags = packet->raw->flags;  | 
    
    
    981  | 
     | 
     | 
    	state->hops = packet->raw->hops;  | 
    
    
    982  | 
     | 
     | 
    	state->offer = offer;  | 
    
    
    983  | 
     | 
     | 
    	memcpy(&state->haddr, packet->haddr, sizeof state->haddr);  | 
    
    
    984  | 
     | 
     | 
     | 
    
    
    985  | 
     | 
     | 
    	/* Figure out what options to send to the client: */  | 
    
    
    986  | 
     | 
     | 
     | 
    
    
    987  | 
     | 
     | 
    	/* Start out with the subnet options... */  | 
    
    
    988  | 
     | 
     | 
    	memcpy(state->options, lease->subnet->group->options,  | 
    
    
    989  | 
     | 
     | 
    	    sizeof state->options);  | 
    
    
    990  | 
     | 
     | 
     | 
    
    
    991  | 
     | 
     | 
    	/* Vendor and user classes are only supported for DHCP clients. */  | 
    
    
    992  | 
     | 
     | 
    	if (state->offer) { | 
    
    
    993  | 
     | 
     | 
    		/* If we have a vendor class, install those options,  | 
    
    
    994  | 
     | 
     | 
    		   superseding any subnet options. */  | 
    
    
    995  | 
     | 
     | 
    		if (vendor_class) { | 
    
    
    996  | 
     | 
     | 
    			for (i = 0; i < 256; i++)  | 
    
    
    997  | 
     | 
     | 
    				if (vendor_class->group->options[i])  | 
    
    
    998  | 
     | 
     | 
    					state->options[i] =  | 
    
    
    999  | 
     | 
     | 
    					    vendor_class->group->options[i];  | 
    
    
    1000  | 
     | 
     | 
    		}  | 
    
    
    1001  | 
     | 
     | 
     | 
    
    
    1002  | 
     | 
     | 
    		/* If we have a user class, install those options,  | 
    
    
    1003  | 
     | 
     | 
    		   superseding any subnet and vendor class options. */  | 
    
    
    1004  | 
     | 
     | 
    		if (user_class) { | 
    
    
    1005  | 
     | 
     | 
    			for (i = 0; i < 256; i++)  | 
    
    
    1006  | 
     | 
     | 
    				if (user_class->group->options[i])  | 
    
    
    1007  | 
     | 
     | 
    					state->options[i] =  | 
    
    
    1008  | 
     | 
     | 
    					    user_class->group->options[i];  | 
    
    
    1009  | 
     | 
     | 
    		}  | 
    
    
    1010  | 
     | 
     | 
     | 
    
    
    1011  | 
     | 
     | 
    	}  | 
    
    
    1012  | 
     | 
     | 
     | 
    
    
    1013  | 
     | 
     | 
    	/* If we have a host_decl structure, install the associated  | 
    
    
    1014  | 
     | 
     | 
    	   options, superseding anything that's in the way. */  | 
    
    
    1015  | 
     | 
     | 
    	if (lease->host) { | 
    
    
    1016  | 
     | 
     | 
    		for (i = 0; i < 256; i++)  | 
    
    
    1017  | 
     | 
     | 
    			if (lease->host->group->options[i])  | 
    
    
    1018  | 
     | 
     | 
    				state->options[i] =  | 
    
    
    1019  | 
     | 
     | 
    				    lease->host->group->options[i];  | 
    
    
    1020  | 
     | 
     | 
    	}  | 
    
    
    1021  | 
     | 
     | 
     | 
    
    
    1022  | 
     | 
     | 
    	/* Get the Maximum Message Size option from the packet, if one  | 
    
    
    1023  | 
     | 
     | 
    	   was sent. */  | 
    
    
    1024  | 
     | 
     | 
    	i = DHO_DHCP_MAX_MESSAGE_SIZE;  | 
    
    
    1025  | 
     | 
     | 
    	if (packet->options[i].data &&  | 
    
    
    1026  | 
     | 
     | 
    	    packet->options[i].len == sizeof(u_int16_t))  | 
    
    
    1027  | 
     | 
     | 
    		state->max_message_size = getUShort(packet->options[i].data);  | 
    
    
    1028  | 
     | 
     | 
    	/* Otherwise, if a maximum message size was specified, use that. */  | 
    
    
    1029  | 
     | 
     | 
    	else if (state->options[i] && state->options[i]->value)  | 
    
    
    1030  | 
     | 
     | 
    		state->max_message_size = getUShort(state->options[i]->value);  | 
    
    
    1031  | 
     | 
     | 
     | 
    
    
    1032  | 
     | 
     | 
    	/* Save the parameter request list if there is one. */  | 
    
    
    1033  | 
     | 
     | 
    	i = DHO_DHCP_PARAMETER_REQUEST_LIST;  | 
    
    
    1034  | 
     | 
     | 
    	if (packet->options[i].data) { | 
    
    
    1035  | 
     | 
     | 
    		state->prl = calloc(1, packet->options[i].len);  | 
    
    
    1036  | 
     | 
     | 
    		if (!state->prl)  | 
    
    
    1037  | 
     | 
     | 
    			log_warnx("no memory for parameter request list"); | 
    
    
    1038  | 
     | 
     | 
    		else { | 
    
    
    1039  | 
     | 
     | 
    			memcpy(state->prl, packet->options[i].data,  | 
    
    
    1040  | 
     | 
     | 
    			    packet->options[i].len);  | 
    
    
    1041  | 
     | 
     | 
    			state->prl_len = packet->options[i].len;  | 
    
    
    1042  | 
     | 
     | 
    		}  | 
    
    
    1043  | 
     | 
     | 
    	}  | 
    
    
    1044  | 
     | 
     | 
     | 
    
    
    1045  | 
     | 
     | 
    	/* If we didn't get a hostname from an option somewhere, see if  | 
    
    
    1046  | 
     | 
     | 
    	   we can get one from the lease. */  | 
    
    
    1047  | 
     | 
     | 
    	i = DHO_HOST_NAME;  | 
    
    
    1048  | 
     | 
     | 
    	if (!state->options[i] && lease->hostname) { | 
    
    
    1049  | 
     | 
     | 
    		state->options[i] = new_tree_cache("hostname"); | 
    
    
    1050  | 
     | 
     | 
    		state->options[i]->flags = TC_TEMPORARY;  | 
    
    
    1051  | 
     | 
     | 
    		state->options[i]->value = (unsigned char *)lease->hostname;  | 
    
    
    1052  | 
     | 
     | 
    		state->options[i]->len = strlen(lease->hostname);  | 
    
    
    1053  | 
     | 
     | 
    		state->options[i]->buf_size = state->options[i]->len;  | 
    
    
    1054  | 
     | 
     | 
    		state->options[i]->timeout = -1;  | 
    
    
    1055  | 
     | 
     | 
    		state->options[i]->tree = NULL;  | 
    
    
    1056  | 
     | 
     | 
    	}  | 
    
    
    1057  | 
     | 
     | 
     | 
    
    
    1058  | 
     | 
     | 
    	/*  | 
    
    
    1059  | 
     | 
     | 
    	 * Now, if appropriate, put in DHCP-specific options that  | 
    
    
    1060  | 
     | 
     | 
    	 * override those.  | 
    
    
    1061  | 
     | 
     | 
    	 */  | 
    
    
    1062  | 
     | 
     | 
    	if (state->offer) { | 
    
    
    1063  | 
     | 
     | 
    		i = DHO_DHCP_MESSAGE_TYPE;  | 
    
    
    1064  | 
     | 
     | 
    		state->options[i] = new_tree_cache("message-type"); | 
    
    
    1065  | 
     | 
     | 
    		state->options[i]->flags = TC_TEMPORARY;  | 
    
    
    1066  | 
     | 
     | 
    		state->options[i]->value = &state->offer;  | 
    
    
    1067  | 
     | 
     | 
    		state->options[i]->len = sizeof state->offer;  | 
    
    
    1068  | 
     | 
     | 
    		state->options[i]->buf_size = sizeof state->offer;  | 
    
    
    1069  | 
     | 
     | 
    		state->options[i]->timeout = -1;  | 
    
    
    1070  | 
     | 
     | 
    		state->options[i]->tree = NULL;  | 
    
    
    1071  | 
     | 
     | 
     | 
    
    
    1072  | 
     | 
     | 
    		i = DHO_DHCP_SERVER_IDENTIFIER;  | 
    
    
    1073  | 
     | 
     | 
    		if (!state->options[i]) { | 
    
    
    1074  | 
     | 
     | 
    		 use_primary:  | 
    
    
    1075  | 
     | 
     | 
    			state->options[i] = new_tree_cache("server-id"); | 
    
    
    1076  | 
     | 
     | 
    			state->options[i]->value =  | 
    
    
    1077  | 
     | 
     | 
    			    (unsigned char *)&state->ip->primary_address;  | 
    
    
    1078  | 
     | 
     | 
    			state->options[i]->len =  | 
    
    
    1079  | 
     | 
     | 
    			    sizeof state->ip->primary_address;  | 
    
    
    1080  | 
     | 
     | 
    			state->options[i]->buf_size = state->options[i]->len;  | 
    
    
    1081  | 
     | 
     | 
    			state->options[i]->timeout = -1;  | 
    
    
    1082  | 
     | 
     | 
    			state->options[i]->tree = NULL;  | 
    
    
    1083  | 
     | 
     | 
    			state->from.len = sizeof state->ip->primary_address;  | 
    
    
    1084  | 
     | 
     | 
    			memcpy(state->from.iabuf, &state->ip->primary_address,  | 
    
    
    1085  | 
     | 
     | 
    			    state->from.len);  | 
    
    
    1086  | 
     | 
     | 
    		} else { | 
    
    
    1087  | 
     | 
     | 
    			/* Find the value of the server identifier... */  | 
    
    
    1088  | 
     | 
     | 
    			if (!tree_evaluate(state->options[i]))  | 
    
    
    1089  | 
     | 
     | 
    				goto use_primary;  | 
    
    
    1090  | 
     | 
     | 
    			if (!state->options[i]->value ||  | 
    
    
    1091  | 
     | 
     | 
    			    (state->options[i]->len >  | 
    
    
    1092  | 
     | 
     | 
    			    sizeof state->from.iabuf))  | 
    
    
    1093  | 
     | 
     | 
    				goto use_primary;  | 
    
    
    1094  | 
     | 
     | 
     | 
    
    
    1095  | 
     | 
     | 
    			state->from.len = state->options[i]->len;  | 
    
    
    1096  | 
     | 
     | 
    			memcpy(state->from.iabuf, state->options[i]->value,  | 
    
    
    1097  | 
     | 
     | 
    			    state->from.len);  | 
    
    
    1098  | 
     | 
     | 
    		}  | 
    
    
    1099  | 
     | 
     | 
    		/*  | 
    
    
    1100  | 
     | 
     | 
    		 * Do not ACK a REQUEST intended for another server.  | 
    
    
    1101  | 
     | 
     | 
    		 */  | 
    
    
    1102  | 
     | 
     | 
    		if (packet->options[i].len == 4) { | 
    
    
    1103  | 
     | 
     | 
    			if (state->options[i]->len != 4 ||  | 
    
    
    1104  | 
     | 
     | 
    			    memcmp(packet->options[i].data,  | 
    
    
    1105  | 
     | 
     | 
    			    state->options[i]->value, 4) != 0) { | 
    
    
    1106  | 
     | 
     | 
    				free_lease_state(state, "ack_lease: "  | 
    
    
    1107  | 
     | 
     | 
    				    "server identifier");  | 
    
    
    1108  | 
     | 
     | 
    				return;  | 
    
    
    1109  | 
     | 
     | 
    			}  | 
    
    
    1110  | 
     | 
     | 
    		}  | 
    
    
    1111  | 
     | 
     | 
     | 
    
    
    1112  | 
     | 
     | 
    		/* If we used the vendor class the client specified, we  | 
    
    
    1113  | 
     | 
     | 
    		   have to return it. */  | 
    
    
    1114  | 
     | 
     | 
    		if (vendor_class) { | 
    
    
    1115  | 
     | 
     | 
    			i = DHO_DHCP_CLASS_IDENTIFIER;  | 
    
    
    1116  | 
     | 
     | 
    			state->options[i] = new_tree_cache("class-identifier"); | 
    
    
    1117  | 
     | 
     | 
    			state->options[i]->flags = TC_TEMPORARY;  | 
    
    
    1118  | 
     | 
     | 
    			state->options[i]->value =  | 
    
    
    1119  | 
     | 
     | 
    				(unsigned char *)vendor_class->name;  | 
    
    
    1120  | 
     | 
     | 
    			state->options[i]->len = strlen(vendor_class->name);  | 
    
    
    1121  | 
     | 
     | 
    			state->options[i]->buf_size = state->options[i]->len;  | 
    
    
    1122  | 
     | 
     | 
    			state->options[i]->timeout = -1;  | 
    
    
    1123  | 
     | 
     | 
    			state->options[i]->tree = NULL;  | 
    
    
    1124  | 
     | 
     | 
    		}  | 
    
    
    1125  | 
     | 
     | 
     | 
    
    
    1126  | 
     | 
     | 
    		/* If we used the user class the client specified, we  | 
    
    
    1127  | 
     | 
     | 
    		   have to return it. */  | 
    
    
    1128  | 
     | 
     | 
    		if (user_class) { | 
    
    
    1129  | 
     | 
     | 
    			i = DHO_DHCP_USER_CLASS_ID;  | 
    
    
    1130  | 
     | 
     | 
    			state->options[i] = new_tree_cache("user-class"); | 
    
    
    1131  | 
     | 
     | 
    			state->options[i]->flags = TC_TEMPORARY;  | 
    
    
    1132  | 
     | 
     | 
    			state->options[i]->value =  | 
    
    
    1133  | 
     | 
     | 
    				(unsigned char *)user_class->name;  | 
    
    
    1134  | 
     | 
     | 
    			state->options[i]->len = strlen(user_class->name);  | 
    
    
    1135  | 
     | 
     | 
    			state->options[i]->buf_size = state->options[i]->len;  | 
    
    
    1136  | 
     | 
     | 
    			state->options[i]->timeout = -1;  | 
    
    
    1137  | 
     | 
     | 
    			state->options[i]->tree = NULL;  | 
    
    
    1138  | 
     | 
     | 
    		}  | 
    
    
    1139  | 
     | 
     | 
    	}  | 
    
    
    1140  | 
     | 
     | 
     | 
    
    
    1141  | 
     | 
     | 
    	/* for DHCPINFORM, don't include lease time parameters */  | 
    
    
    1142  | 
     | 
     | 
    	if (state->offer && (lease->flags & INFORM_NOLEASE) == 0) { | 
    
    
    1143  | 
     | 
     | 
     | 
    
    
    1144  | 
     | 
     | 
    		/* Sanity check the lease time. */  | 
    
    
    1145  | 
     | 
     | 
    		if ((state->offered_expiry - cur_time) < 15)  | 
    
    
    1146  | 
     | 
     | 
    			offered_lease_time = default_lease_time;  | 
    
    
    1147  | 
     | 
     | 
    		else if (state->offered_expiry - cur_time > max_lease_time)  | 
    
    
    1148  | 
     | 
     | 
    			offered_lease_time = max_lease_time;  | 
    
    
    1149  | 
     | 
     | 
    		else  | 
    
    
    1150  | 
     | 
     | 
    			offered_lease_time =  | 
    
    
    1151  | 
     | 
     | 
    			    state->offered_expiry - cur_time;  | 
    
    
    1152  | 
     | 
     | 
     | 
    
    
    1153  | 
     | 
     | 
    		putULong((unsigned char *)&state->expiry, offered_lease_time);  | 
    
    
    1154  | 
     | 
     | 
    		i = DHO_DHCP_LEASE_TIME;  | 
    
    
    1155  | 
     | 
     | 
    		state->options[i] = new_tree_cache("lease-expiry"); | 
    
    
    1156  | 
     | 
     | 
    		state->options[i]->flags = TC_TEMPORARY;  | 
    
    
    1157  | 
     | 
     | 
    		state->options[i]->value = (unsigned char *)&state->expiry;  | 
    
    
    1158  | 
     | 
     | 
    		state->options[i]->len = sizeof state->expiry;  | 
    
    
    1159  | 
     | 
     | 
    		state->options[i]->buf_size = sizeof state->expiry;  | 
    
    
    1160  | 
     | 
     | 
    		state->options[i]->timeout = -1;  | 
    
    
    1161  | 
     | 
     | 
    		state->options[i]->tree = NULL;  | 
    
    
    1162  | 
     | 
     | 
     | 
    
    
    1163  | 
     | 
     | 
    		/* Renewal time is lease time * 0.5. */  | 
    
    
    1164  | 
     | 
     | 
    		offered_lease_time /= 2;  | 
    
    
    1165  | 
     | 
     | 
    		putULong((unsigned char *)&state->renewal, offered_lease_time);  | 
    
    
    1166  | 
     | 
     | 
    		i = DHO_DHCP_RENEWAL_TIME;  | 
    
    
    1167  | 
     | 
     | 
    		state->options[i] = new_tree_cache("renewal-time"); | 
    
    
    1168  | 
     | 
     | 
    		state->options[i]->flags = TC_TEMPORARY;  | 
    
    
    1169  | 
     | 
     | 
    		state->options[i]->value =  | 
    
    
    1170  | 
     | 
     | 
    			(unsigned char *)&state->renewal;  | 
    
    
    1171  | 
     | 
     | 
    		state->options[i]->len = sizeof state->renewal;  | 
    
    
    1172  | 
     | 
     | 
    		state->options[i]->buf_size = sizeof state->renewal;  | 
    
    
    1173  | 
     | 
     | 
    		state->options[i]->timeout = -1;  | 
    
    
    1174  | 
     | 
     | 
    		state->options[i]->tree = NULL;  | 
    
    
    1175  | 
     | 
     | 
     | 
    
    
    1176  | 
     | 
     | 
     | 
    
    
    1177  | 
     | 
     | 
    		/* Rebinding time is lease time * 0.875. */  | 
    
    
    1178  | 
     | 
     | 
    		offered_lease_time += (offered_lease_time / 2 +  | 
    
    
    1179  | 
     | 
     | 
    		    offered_lease_time / 4);  | 
    
    
    1180  | 
     | 
     | 
    		putULong((unsigned char *)&state->rebind, offered_lease_time);  | 
    
    
    1181  | 
     | 
     | 
    		i = DHO_DHCP_REBINDING_TIME;  | 
    
    
    1182  | 
     | 
     | 
    		state->options[i] = new_tree_cache("rebind-time"); | 
    
    
    1183  | 
     | 
     | 
    		state->options[i]->flags = TC_TEMPORARY;  | 
    
    
    1184  | 
     | 
     | 
    		state->options[i]->value = (unsigned char *)&state->rebind;  | 
    
    
    1185  | 
     | 
     | 
    		state->options[i]->len = sizeof state->rebind;  | 
    
    
    1186  | 
     | 
     | 
    		state->options[i]->buf_size = sizeof state->rebind;  | 
    
    
    1187  | 
     | 
     | 
    		state->options[i]->timeout = -1;  | 
    
    
    1188  | 
     | 
     | 
    		state->options[i]->tree = NULL;  | 
    
    
    1189  | 
     | 
     | 
    	}  | 
    
    
    1190  | 
     | 
     | 
     | 
    
    
    1191  | 
     | 
     | 
    	/* Use the subnet mask from the subnet declaration if no other  | 
    
    
    1192  | 
     | 
     | 
    	   mask has been provided. */  | 
    
    
    1193  | 
     | 
     | 
    	i = DHO_SUBNET_MASK;  | 
    
    
    1194  | 
     | 
     | 
    	if (!state->options[i]) { | 
    
    
    1195  | 
     | 
     | 
    		state->options[i] = new_tree_cache("subnet-mask"); | 
    
    
    1196  | 
     | 
     | 
    		state->options[i]->flags = TC_TEMPORARY;  | 
    
    
    1197  | 
     | 
     | 
    		state->options[i]->value = lease->subnet->netmask.iabuf;  | 
    
    
    1198  | 
     | 
     | 
    		state->options[i]->len = lease->subnet->netmask.len;  | 
    
    
    1199  | 
     | 
     | 
    		state->options[i]->buf_size = lease->subnet->netmask.len;  | 
    
    
    1200  | 
     | 
     | 
    		state->options[i]->timeout = -1;  | 
    
    
    1201  | 
     | 
     | 
    		state->options[i]->tree = NULL;  | 
    
    
    1202  | 
     | 
     | 
    	}  | 
    
    
    1203  | 
     | 
     | 
     | 
    
    
    1204  | 
     | 
     | 
    	/* If so directed, use the leased IP address as the router address.  | 
    
    
    1205  | 
     | 
     | 
    	   This supposedly makes Win95 machines ARP for all IP addresses,  | 
    
    
    1206  | 
     | 
     | 
    	   so if the local router does proxy arp, you win. */  | 
    
    
    1207  | 
     | 
     | 
     | 
    
    
    1208  | 
     | 
     | 
    	ulafdr = 0;  | 
    
    
    1209  | 
     | 
     | 
    	if (lease->host) { | 
    
    
    1210  | 
     | 
     | 
    		if (lease->host->group->use_lease_addr_for_default_route)  | 
    
    
    1211  | 
     | 
     | 
    			ulafdr = 1;  | 
    
    
    1212  | 
     | 
     | 
    	} else if (user_class) { | 
    
    
    1213  | 
     | 
     | 
    		if (user_class->group->use_lease_addr_for_default_route)  | 
    
    
    1214  | 
     | 
     | 
    			ulafdr = 1;  | 
    
    
    1215  | 
     | 
     | 
    	} else if (vendor_class) { | 
    
    
    1216  | 
     | 
     | 
    		if (vendor_class->group->use_lease_addr_for_default_route)  | 
    
    
    1217  | 
     | 
     | 
    			ulafdr = 1;  | 
    
    
    1218  | 
     | 
     | 
    	} else if (lease->subnet->group->use_lease_addr_for_default_route)  | 
    
    
    1219  | 
     | 
     | 
    		ulafdr = 1;  | 
    
    
    1220  | 
     | 
     | 
    	else  | 
    
    
    1221  | 
     | 
     | 
    		ulafdr = 0;  | 
    
    
    1222  | 
     | 
     | 
     | 
    
    
    1223  | 
     | 
     | 
    	i = DHO_ROUTERS;  | 
    
    
    1224  | 
     | 
     | 
    	if (ulafdr && !state->options[i]) { | 
    
    
    1225  | 
     | 
     | 
    		state->options[i] = new_tree_cache("routers"); | 
    
    
    1226  | 
     | 
     | 
    		state->options[i]->flags = TC_TEMPORARY;  | 
    
    
    1227  | 
     | 
     | 
    		state->options[i]->value = lease->ip_addr.iabuf;  | 
    
    
    1228  | 
     | 
     | 
    		state->options[i]->len = lease->ip_addr.len;  | 
    
    
    1229  | 
     | 
     | 
    		state->options[i]->buf_size = lease->ip_addr.len;  | 
    
    
    1230  | 
     | 
     | 
    		state->options[i]->timeout = -1;  | 
    
    
    1231  | 
     | 
     | 
    		state->options[i]->tree = NULL;  | 
    
    
    1232  | 
     | 
     | 
    	}  | 
    
    
    1233  | 
     | 
     | 
     | 
    
    
    1234  | 
     | 
     | 
    	/*  | 
    
    
    1235  | 
     | 
     | 
    	 * RFC 3046: MUST NOT echo relay agent information if the server  | 
    
    
    1236  | 
     | 
     | 
    	 * does not understand/use the data. We don't.  | 
    
    
    1237  | 
     | 
     | 
    	 */  | 
    
    
    1238  | 
     | 
     | 
    	i = DHO_RELAY_AGENT_INFORMATION;  | 
    
    
    1239  | 
     | 
     | 
    	memset(&state->options[i], 0, sizeof(state->options[i]));  | 
    
    
    1240  | 
     | 
     | 
     | 
    
    
    1241  | 
     | 
     | 
    	/* Echo back the client-identifier as RFC 6842 mandates. */  | 
    
    
    1242  | 
     | 
     | 
    	if (lease->host)  | 
    
    
    1243  | 
     | 
     | 
    		echo_client_id = lease->host->group->echo_client_id;  | 
    
    
    1244  | 
     | 
     | 
    	else if (user_class)  | 
    
    
    1245  | 
     | 
     | 
    		echo_client_id = user_class->group->echo_client_id;  | 
    
    
    1246  | 
     | 
     | 
    	else if (vendor_class)  | 
    
    
    1247  | 
     | 
     | 
    		echo_client_id = vendor_class->group->echo_client_id;  | 
    
    
    1248  | 
     | 
     | 
    	else  | 
    
    
    1249  | 
     | 
     | 
    		echo_client_id = lease->subnet->group->echo_client_id;  | 
    
    
    1250  | 
     | 
     | 
    	i = DHO_DHCP_CLIENT_IDENTIFIER;  | 
    
    
    1251  | 
     | 
     | 
    	if (lease->client_identifier && echo_client_id) { | 
    
    
    1252  | 
     | 
     | 
    		state->options[i] = new_tree_cache("dhcp-client-identifier"); | 
    
    
    1253  | 
     | 
     | 
    		state->options[i]->flags = TC_TEMPORARY;  | 
    
    
    1254  | 
     | 
     | 
    		state->options[i]->value = lease->client_identifier;  | 
    
    
    1255  | 
     | 
     | 
    		state->options[i]->len = lease->client_identifier_len;  | 
    
    
    1256  | 
     | 
     | 
    		state->options[i]->buf_size = lease->client_identifier_len;  | 
    
    
    1257  | 
     | 
     | 
    		state->options[i]->timeout = -1;  | 
    
    
    1258  | 
     | 
     | 
    		state->options[i]->tree = NULL;  | 
    
    
    1259  | 
     | 
     | 
    	} else  | 
    
    
    1260  | 
     | 
     | 
    		memset(&state->options[i], 0, sizeof(state->options[i]));  | 
    
    
    1261  | 
     | 
     | 
     | 
    
    
    1262  | 
     | 
     | 
    	lease->state = state;  | 
    
    
    1263  | 
     | 
     | 
     | 
    
    
    1264  | 
     | 
     | 
    	/* If this is a DHCPOFFER, ping the lease address before actually  | 
    
    
    1265  | 
     | 
     | 
    	   sending the offer. */  | 
    
    
    1266  | 
     | 
     | 
    	if (offer == DHCPOFFER && !(lease->flags & STATIC_LEASE) &&  | 
    
    
    1267  | 
     | 
     | 
    	    cur_time - lease->timestamp > 60) { | 
    
    
    1268  | 
     | 
     | 
    		lease->timestamp = cur_time;  | 
    
    
    1269  | 
     | 
     | 
    		icmp_echorequest(&lease->ip_addr);  | 
    
    
    1270  | 
     | 
     | 
    		add_timeout(cur_time + 1, lease_ping_timeout, lease);  | 
    
    
    1271  | 
     | 
     | 
    		++outstanding_pings;  | 
    
    
    1272  | 
     | 
     | 
    	} else { | 
    
    
    1273  | 
     | 
     | 
    		lease->timestamp = cur_time;  | 
    
    
    1274  | 
     | 
     | 
    		dhcp_reply(lease);  | 
    
    
    1275  | 
     | 
     | 
    	}  | 
    
    
    1276  | 
     | 
     | 
    }  | 
    
    
    1277  | 
     | 
     | 
     | 
    
    
    1278  | 
     | 
     | 
    void  | 
    
    
    1279  | 
     | 
     | 
    dhcp_reply(struct lease *lease)  | 
    
    
    1280  | 
     | 
     | 
    { | 
    
    
    1281  | 
     | 
     | 
    	char ciaddrbuf[INET_ADDRSTRLEN];  | 
    
    
    1282  | 
     | 
     | 
    	int bufs = 0, packet_length, i;  | 
    
    
    1283  | 
     | 
     | 
    	struct dhcp_packet raw;  | 
    
    
    1284  | 
     | 
     | 
    	struct sockaddr_in to;  | 
    
    
    1285  | 
     | 
     | 
    	struct in_addr from;  | 
    
    
    1286  | 
     | 
     | 
    	struct lease_state *state = lease->state;  | 
    
    
    1287  | 
     | 
     | 
    	int nulltp, bootpp;  | 
    
    
    1288  | 
     | 
     | 
    	u_int8_t *prl;  | 
    
    
    1289  | 
     | 
     | 
    	int prl_len;  | 
    
    
    1290  | 
     | 
     | 
     | 
    
    
    1291  | 
     | 
     | 
    	if (!state)  | 
    
    
    1292  | 
     | 
     | 
    		fatalx("dhcp_reply was supplied lease with no state!"); | 
    
    
    1293  | 
     | 
     | 
     | 
    
    
    1294  | 
     | 
     | 
    	/* Compose a response for the client... */  | 
    
    
    1295  | 
     | 
     | 
    	memset(&raw, 0, sizeof raw);  | 
    
    
    1296  | 
     | 
     | 
     | 
    
    
    1297  | 
     | 
     | 
    	/* Copy in the filename if given; otherwise, flag the filename  | 
    
    
    1298  | 
     | 
     | 
    	   buffer as available for options. */  | 
    
    
    1299  | 
     | 
     | 
    	if (state->filename[0])  | 
    
    
    1300  | 
     | 
     | 
    		strlcpy(raw.file, state->filename, sizeof raw.file);  | 
    
    
    1301  | 
     | 
     | 
    	else  | 
    
    
    1302  | 
     | 
     | 
    		bufs |= 1;  | 
    
    
    1303  | 
     | 
     | 
     | 
    
    
    1304  | 
     | 
     | 
    	/* Copy in the server name if given; otherwise, flag the  | 
    
    
    1305  | 
     | 
     | 
    	   server_name buffer as available for options. */  | 
    
    
    1306  | 
     | 
     | 
    	if (state->server_name)  | 
    
    
    1307  | 
     | 
     | 
    		strlcpy(raw.sname, state->server_name, sizeof raw.sname);  | 
    
    
    1308  | 
     | 
     | 
    	else  | 
    
    
    1309  | 
     | 
     | 
    		bufs |= 2; /* XXX */  | 
    
    
    1310  | 
     | 
     | 
     | 
    
    
    1311  | 
     | 
     | 
    	memcpy(raw.chaddr, lease->hardware_addr.haddr, sizeof raw.chaddr);  | 
    
    
    1312  | 
     | 
     | 
    	raw.hlen = lease->hardware_addr.hlen;  | 
    
    
    1313  | 
     | 
     | 
    	raw.htype = lease->hardware_addr.htype;  | 
    
    
    1314  | 
     | 
     | 
     | 
    
    
    1315  | 
     | 
     | 
    	/* See if this is a Microsoft client that NUL-terminates its  | 
    
    
    1316  | 
     | 
     | 
    	   strings and expects us to do likewise... */  | 
    
    
    1317  | 
     | 
     | 
    	if (lease->flags & MS_NULL_TERMINATION)  | 
    
    
    1318  | 
     | 
     | 
    		nulltp = 1;  | 
    
    
    1319  | 
     | 
     | 
    	else  | 
    
    
    1320  | 
     | 
     | 
    		nulltp = 0;  | 
    
    
    1321  | 
     | 
     | 
     | 
    
    
    1322  | 
     | 
     | 
    	/* See if this is a bootp client... */  | 
    
    
    1323  | 
     | 
     | 
    	if (state->offer)  | 
    
    
    1324  | 
     | 
     | 
    		bootpp = 0;  | 
    
    
    1325  | 
     | 
     | 
    	else  | 
    
    
    1326  | 
     | 
     | 
    		bootpp = 1;  | 
    
    
    1327  | 
     | 
     | 
     | 
    
    
    1328  | 
     | 
     | 
    	if (state->options[DHO_DHCP_PARAMETER_REQUEST_LIST] &&  | 
    
    
    1329  | 
     | 
     | 
    	    state->options[DHO_DHCP_PARAMETER_REQUEST_LIST]->value) { | 
    
    
    1330  | 
     | 
     | 
    		prl = state->options[DHO_DHCP_PARAMETER_REQUEST_LIST]->value;  | 
    
    
    1331  | 
     | 
     | 
    		prl_len = state->options[DHO_DHCP_PARAMETER_REQUEST_LIST]->len;  | 
    
    
    1332  | 
     | 
     | 
    	} else if (state->prl) { | 
    
    
    1333  | 
     | 
     | 
    		prl = state->prl;  | 
    
    
    1334  | 
     | 
     | 
    		prl_len = state->prl_len;  | 
    
    
    1335  | 
     | 
     | 
    	} else { | 
    
    
    1336  | 
     | 
     | 
    		prl = NULL;  | 
    
    
    1337  | 
     | 
     | 
    		prl_len = 0;  | 
    
    
    1338  | 
     | 
     | 
    	}  | 
    
    
    1339  | 
     | 
     | 
     | 
    
    
    1340  | 
     | 
     | 
    	/* Insert such options as will fit into the buffer. */  | 
    
    
    1341  | 
     | 
     | 
    	packet_length = cons_options(NULL, &raw, state->max_message_size,  | 
    
    
    1342  | 
     | 
     | 
    	    state->options, bufs, nulltp, bootpp, prl, prl_len);  | 
    
    
    1343  | 
     | 
     | 
     | 
    
    
    1344  | 
     | 
     | 
    	/* Having done the cons_options(), we can release the tree_cache  | 
    
    
    1345  | 
     | 
     | 
    	   entries. */  | 
    
    
    1346  | 
     | 
     | 
    	for (i = 0; i < 256; i++) { | 
    
    
    1347  | 
     | 
     | 
    		if (state->options[i] &&  | 
    
    
    1348  | 
     | 
     | 
    		    state->options[i]->flags & TC_TEMPORARY)  | 
    
    
    1349  | 
     | 
     | 
    			free_tree_cache(state->options[i]);  | 
    
    
    1350  | 
     | 
     | 
    	}  | 
    
    
    1351  | 
     | 
     | 
     | 
    
    
    1352  | 
     | 
     | 
    	memcpy(&raw.ciaddr, &state->ciaddr, sizeof raw.ciaddr);  | 
    
    
    1353  | 
     | 
     | 
    	if ((lease->flags & INFORM_NOLEASE) == 0)  | 
    
    
    1354  | 
     | 
     | 
    		memcpy(&raw.yiaddr, lease->ip_addr.iabuf, 4);  | 
    
    
    1355  | 
     | 
     | 
     | 
    
    
    1356  | 
     | 
     | 
    	/* Figure out the address of the next server. */  | 
    
    
    1357  | 
     | 
     | 
    	if (lease->host && lease->host->group->next_server.len)  | 
    
    
    1358  | 
     | 
     | 
    		memcpy(&raw.siaddr, lease->host->group->next_server.iabuf, 4);  | 
    
    
    1359  | 
     | 
     | 
    	else if (lease->subnet->group->next_server.len)  | 
    
    
    1360  | 
     | 
     | 
    		memcpy(&raw.siaddr, lease->subnet->group->next_server.iabuf,  | 
    
    
    1361  | 
     | 
     | 
    		    4);  | 
    
    
    1362  | 
     | 
     | 
    	else if (lease->subnet->interface_address.len)  | 
    
    
    1363  | 
     | 
     | 
    		memcpy(&raw.siaddr, lease->subnet->interface_address.iabuf, 4);  | 
    
    
    1364  | 
     | 
     | 
    	else  | 
    
    
    1365  | 
     | 
     | 
    		raw.siaddr = state->ip->primary_address;  | 
    
    
    1366  | 
     | 
     | 
     | 
    
    
    1367  | 
     | 
     | 
    	raw.giaddr = state->giaddr;  | 
    
    
    1368  | 
     | 
     | 
     | 
    
    
    1369  | 
     | 
     | 
    	raw.xid = state->xid;  | 
    
    
    1370  | 
     | 
     | 
    	raw.secs = state->secs;  | 
    
    
    1371  | 
     | 
     | 
    	raw.flags = state->bootp_flags;  | 
    
    
    1372  | 
     | 
     | 
    	raw.hops = state->hops;  | 
    
    
    1373  | 
     | 
     | 
    	raw.op = BOOTREPLY;  | 
    
    
    1374  | 
     | 
     | 
     | 
    
    
    1375  | 
     | 
     | 
    	/* Can't do >1 inet_ntoa() in a printf()! */  | 
    
    
    1376  | 
     | 
     | 
    	strlcpy(ciaddrbuf, inet_ntoa(state->ciaddr), sizeof(ciaddrbuf));  | 
    
    
    1377  | 
     | 
     | 
     | 
    
    
    1378  | 
     | 
     | 
    	/* Say what we're doing... */  | 
    
    
    1379  | 
     | 
     | 
    	if ((state->offer == DHCPACK) && (lease->flags & INFORM_NOLEASE))  | 
    
    
    1380  | 
     | 
     | 
    		log_info("DHCPACK to %s (%s) via %s", | 
    
    
    1381  | 
     | 
     | 
    		    ciaddrbuf,  | 
    
    
    1382  | 
     | 
     | 
    		    print_hw_addr(lease->hardware_addr.htype,  | 
    
    
    1383  | 
     | 
     | 
    		        lease->hardware_addr.hlen, lease->hardware_addr.haddr),  | 
    
    
    1384  | 
     | 
     | 
    		    state->giaddr.s_addr ? inet_ntoa(state->giaddr) :  | 
    
    
    1385  | 
     | 
     | 
    		        state->ip->name);  | 
    
    
    1386  | 
     | 
     | 
    	else  | 
    
    
    1387  | 
     | 
     | 
    		log_info("%s on %s to %s via %s", | 
    
    
    1388  | 
     | 
     | 
    		    (state->offer ? (state->offer == DHCPACK ? "DHCPACK" :  | 
    
    
    1389  | 
     | 
     | 
    			"DHCPOFFER") : "BOOTREPLY"),  | 
    
    
    1390  | 
     | 
     | 
    		    piaddr(lease->ip_addr),  | 
    
    
    1391  | 
     | 
     | 
    		    print_hw_addr(lease->hardware_addr.htype,  | 
    
    
    1392  | 
     | 
     | 
    		        lease->hardware_addr.hlen, lease->hardware_addr.haddr),  | 
    
    
    1393  | 
     | 
     | 
    		    state->giaddr.s_addr ? inet_ntoa(state->giaddr) :  | 
    
    
    1394  | 
     | 
     | 
    		        state->ip->name);  | 
    
    
    1395  | 
     | 
     | 
     | 
    
    
    1396  | 
     | 
     | 
    	memset(&to, 0, sizeof to);  | 
    
    
    1397  | 
     | 
     | 
    	to.sin_family = AF_INET;  | 
    
    
    1398  | 
     | 
     | 
    #ifdef HAVE_SA_LEN  | 
    
    
    1399  | 
     | 
     | 
    	to.sin_len = sizeof to;  | 
    
    
    1400  | 
     | 
     | 
    #endif  | 
    
    
    1401  | 
     | 
     | 
     | 
    
    
    1402  | 
     | 
     | 
    	/* Make sure outgoing packets are at least as big  | 
    
    
    1403  | 
     | 
     | 
    	   as a BOOTP packet. */  | 
    
    
    1404  | 
     | 
     | 
    	if (packet_length < BOOTP_MIN_LEN)  | 
    
    
    1405  | 
     | 
     | 
    		packet_length = BOOTP_MIN_LEN;  | 
    
    
    1406  | 
     | 
     | 
     | 
    
    
    1407  | 
     | 
     | 
    	/* If this was gatewayed, send it back to the gateway... */  | 
    
    
    1408  | 
     | 
     | 
    	if (raw.giaddr.s_addr) { | 
    
    
    1409  | 
     | 
     | 
    		to.sin_addr = raw.giaddr;  | 
    
    
    1410  | 
     | 
     | 
    		to.sin_port = server_port;  | 
    
    
    1411  | 
     | 
     | 
     | 
    
    
    1412  | 
     | 
     | 
    		memcpy(&from, state->from.iabuf, sizeof from);  | 
    
    
    1413  | 
     | 
     | 
     | 
    
    
    1414  | 
     | 
     | 
    		(void) state->ip->send_packet(state->ip, &raw,  | 
    
    
    1415  | 
     | 
     | 
    		    packet_length, from, &to, &state->haddr);  | 
    
    
    1416  | 
     | 
     | 
     | 
    
    
    1417  | 
     | 
     | 
    		free_lease_state(state, "dhcp_reply gateway");  | 
    
    
    1418  | 
     | 
     | 
    		lease->state = NULL;  | 
    
    
    1419  | 
     | 
     | 
    		return;  | 
    
    
    1420  | 
     | 
     | 
     | 
    
    
    1421  | 
     | 
     | 
    	/* If the client is RENEWING, unicast to the client using the  | 
    
    
    1422  | 
     | 
     | 
    	   regular IP stack.  Some clients, particularly those that  | 
    
    
    1423  | 
     | 
     | 
    	   follow RFC1541, are buggy, and send both ciaddr and  | 
    
    
    1424  | 
     | 
     | 
    	   server-identifier.  We deal with this situation by assuming  | 
    
    
    1425  | 
     | 
     | 
    	   that if we got both dhcp-server-identifier and ciaddr, and  | 
    
    
    1426  | 
     | 
     | 
    	   giaddr was not set, then the client is on the local  | 
    
    
    1427  | 
     | 
     | 
    	   network, and we can therefore unicast or broadcast to it  | 
    
    
    1428  | 
     | 
     | 
    	   successfully.  A client in REQUESTING state on another  | 
    
    
    1429  | 
     | 
     | 
    	   network that's making this mistake will have set giaddr,  | 
    
    
    1430  | 
     | 
     | 
    	   and will therefore get a relayed response from the above  | 
    
    
    1431  | 
     | 
     | 
    	   code. */  | 
    
    
    1432  | 
     | 
     | 
    	} else if (raw.ciaddr.s_addr &&  | 
    
    
    1433  | 
     | 
     | 
    	    !((state->got_server_identifier ||  | 
    
    
    1434  | 
     | 
     | 
    	    (raw.flags & htons(BOOTP_BROADCAST))) &&  | 
    
    
    1435  | 
     | 
     | 
    	    /* XXX This won't work if giaddr isn't zero, but it is: */  | 
    
    
    1436  | 
     | 
     | 
    	    (state->shared_network == lease->shared_network)) &&  | 
    
    
    1437  | 
     | 
     | 
    	    state->offer == DHCPACK) { | 
    
    
    1438  | 
     | 
     | 
    		to.sin_addr = raw.ciaddr;  | 
    
    
    1439  | 
     | 
     | 
    		to.sin_port = client_port;  | 
    
    
    1440  | 
     | 
     | 
     | 
    
    
    1441  | 
     | 
     | 
    	/* If it comes from a client that already knows its address  | 
    
    
    1442  | 
     | 
     | 
    	   and is not requesting a broadcast response, and we can  | 
    
    
    1443  | 
     | 
     | 
    	   unicast to a client without using the ARP protocol, sent it  | 
    
    
    1444  | 
     | 
     | 
    	   directly to that client. */  | 
    
    
    1445  | 
     | 
     | 
    	} else if (!(raw.flags & htons(BOOTP_BROADCAST))) { | 
    
    
    1446  | 
     | 
     | 
    		to.sin_addr = raw.yiaddr;  | 
    
    
    1447  | 
     | 
     | 
    		to.sin_port = client_port;  | 
    
    
    1448  | 
     | 
     | 
     | 
    
    
    1449  | 
     | 
     | 
    	/* Otherwise, broadcast it on the local network. */  | 
    
    
    1450  | 
     | 
     | 
    	} else { | 
    
    
    1451  | 
     | 
     | 
    		to.sin_addr.s_addr = htonl(INADDR_BROADCAST);  | 
    
    
    1452  | 
     | 
     | 
    		to.sin_port = client_port;  | 
    
    
    1453  | 
     | 
     | 
    		memset(&state->haddr, 0xff, sizeof state->haddr);  | 
    
    
    1454  | 
     | 
     | 
    	}  | 
    
    
    1455  | 
     | 
     | 
     | 
    
    
    1456  | 
     | 
     | 
    	memcpy(&from, state->from.iabuf, sizeof from);  | 
    
    
    1457  | 
     | 
     | 
     | 
    
    
    1458  | 
     | 
     | 
    	(void) state->ip->send_packet(state->ip, &raw, packet_length,  | 
    
    
    1459  | 
     | 
     | 
    	    from, &to, &state->haddr);  | 
    
    
    1460  | 
     | 
     | 
     | 
    
    
    1461  | 
     | 
     | 
    	free_lease_state(state, "dhcp_reply");  | 
    
    
    1462  | 
     | 
     | 
    	lease->state = NULL;  | 
    
    
    1463  | 
     | 
     | 
    }  | 
    
    
    1464  | 
     | 
     | 
     | 
    
    
    1465  | 
     | 
     | 
    struct lease *  | 
    
    
    1466  | 
     | 
     | 
    find_lease(struct packet *packet, struct shared_network *share,  | 
    
    
    1467  | 
     | 
     | 
        int *ours)  | 
    
    
    1468  | 
     | 
     | 
    { | 
    
    
    1469  | 
     | 
     | 
    	struct lease *uid_lease, *ip_lease, *hw_lease;  | 
    
    
    1470  | 
     | 
     | 
    	struct lease *lease = NULL;  | 
    
    
    1471  | 
     | 
     | 
    	struct iaddr cip;  | 
    
    
    1472  | 
     | 
     | 
    	struct host_decl *hp, *host = NULL;  | 
    
    
    1473  | 
     | 
     | 
    	struct lease *fixed_lease;  | 
    
    
    1474  | 
     | 
     | 
     | 
    
    
    1475  | 
     | 
     | 
    	/* Figure out what IP address the client is requesting, if any. */  | 
    
    
    1476  | 
     | 
     | 
    	if (packet->options[DHO_DHCP_REQUESTED_ADDRESS].len == 4) { | 
    
    
    1477  | 
     | 
     | 
    		packet->got_requested_address = 1;  | 
    
    
    1478  | 
     | 
     | 
    		cip.len = 4;  | 
    
    
    1479  | 
     | 
     | 
    		memcpy(cip.iabuf,  | 
    
    
    1480  | 
     | 
     | 
    		    packet->options[DHO_DHCP_REQUESTED_ADDRESS].data,  | 
    
    
    1481  | 
     | 
     | 
    		    cip.len);  | 
    
    
    1482  | 
     | 
     | 
    	} else if (packet->raw->ciaddr.s_addr) { | 
    
    
    1483  | 
     | 
     | 
    		cip.len = 4;  | 
    
    
    1484  | 
     | 
     | 
    		memcpy(cip.iabuf, &packet->raw->ciaddr, 4);  | 
    
    
    1485  | 
     | 
     | 
    	} else  | 
    
    
    1486  | 
     | 
     | 
    		cip.len = 0;  | 
    
    
    1487  | 
     | 
     | 
     | 
    
    
    1488  | 
     | 
     | 
    	/* Try to find a host or lease that's been assigned to the  | 
    
    
    1489  | 
     | 
     | 
    	   specified unique client identifier. */  | 
    
    
    1490  | 
     | 
     | 
    	if (packet->options[DHO_DHCP_CLIENT_IDENTIFIER].len) { | 
    
    
    1491  | 
     | 
     | 
    		/* First, try to find a fixed host entry for the specified  | 
    
    
    1492  | 
     | 
     | 
    		   client identifier... */  | 
    
    
    1493  | 
     | 
     | 
    		hp = find_hosts_by_uid(  | 
    
    
    1494  | 
     | 
     | 
    		    packet->options[DHO_DHCP_CLIENT_IDENTIFIER].data,  | 
    
    
    1495  | 
     | 
     | 
    		    packet->options[DHO_DHCP_CLIENT_IDENTIFIER].len);  | 
    
    
    1496  | 
     | 
     | 
    		if (hp) { | 
    
    
    1497  | 
     | 
     | 
    			host = hp;  | 
    
    
    1498  | 
     | 
     | 
    			fixed_lease = mockup_lease(packet, share, hp);  | 
    
    
    1499  | 
     | 
     | 
    			uid_lease = NULL;  | 
    
    
    1500  | 
     | 
     | 
    		} else { | 
    
    
    1501  | 
     | 
     | 
    			uid_lease = find_lease_by_uid(  | 
    
    
    1502  | 
     | 
     | 
    			    packet->options[DHO_DHCP_CLIENT_IDENTIFIER].data,  | 
    
    
    1503  | 
     | 
     | 
    			    packet->options[DHO_DHCP_CLIENT_IDENTIFIER].len);  | 
    
    
    1504  | 
     | 
     | 
    			/* Find the lease matching this uid that's on the  | 
    
    
    1505  | 
     | 
     | 
    			   network the packet came from (if any). */  | 
    
    
    1506  | 
     | 
     | 
    			for (; uid_lease; uid_lease = uid_lease->n_uid)  | 
    
    
    1507  | 
     | 
     | 
    				if (uid_lease->shared_network == share)  | 
    
    
    1508  | 
     | 
     | 
    					break;  | 
    
    
    1509  | 
     | 
     | 
    			fixed_lease = NULL;  | 
    
    
    1510  | 
     | 
     | 
    			if (uid_lease && (uid_lease->flags & ABANDONED_LEASE))  | 
    
    
    1511  | 
     | 
     | 
    				uid_lease = NULL;  | 
    
    
    1512  | 
     | 
     | 
    		}  | 
    
    
    1513  | 
     | 
     | 
    	} else { | 
    
    
    1514  | 
     | 
     | 
    		uid_lease = NULL;  | 
    
    
    1515  | 
     | 
     | 
    		fixed_lease = NULL;  | 
    
    
    1516  | 
     | 
     | 
    	}  | 
    
    
    1517  | 
     | 
     | 
     | 
    
    
    1518  | 
     | 
     | 
    	/* If we didn't find a fixed lease using the uid, try doing  | 
    
    
    1519  | 
     | 
     | 
    	   it with the hardware address... */  | 
    
    
    1520  | 
     | 
     | 
    	if (!fixed_lease) { | 
    
    
    1521  | 
     | 
     | 
    		hp = find_hosts_by_haddr(packet->raw->htype,  | 
    
    
    1522  | 
     | 
     | 
    		    packet->raw->chaddr, packet->raw->hlen);  | 
    
    
    1523  | 
     | 
     | 
    		if (hp) { | 
    
    
    1524  | 
     | 
     | 
    			host = hp; /* Save it for later. */  | 
    
    
    1525  | 
     | 
     | 
    			fixed_lease = mockup_lease(packet, share, hp);  | 
    
    
    1526  | 
     | 
     | 
    		}  | 
    
    
    1527  | 
     | 
     | 
    	}  | 
    
    
    1528  | 
     | 
     | 
     | 
    
    
    1529  | 
     | 
     | 
    	/* If fixed_lease is present but does not match the requested  | 
    
    
    1530  | 
     | 
     | 
    	   IP address, and this is a DHCPREQUEST, then we can't return  | 
    
    
    1531  | 
     | 
     | 
    	   any other lease, so we might as well return now. */  | 
    
    
    1532  | 
     | 
     | 
    	if (packet->packet_type == DHCPREQUEST && fixed_lease &&  | 
    
    
    1533  | 
     | 
     | 
    	    (fixed_lease->ip_addr.len != cip.len ||  | 
    
    
    1534  | 
     | 
     | 
    	    memcmp(fixed_lease->ip_addr.iabuf, cip.iabuf, cip.len))) { | 
    
    
    1535  | 
     | 
     | 
    		if (ours)  | 
    
    
    1536  | 
     | 
     | 
    			*ours = 1;  | 
    
    
    1537  | 
     | 
     | 
    		strlcpy(dhcp_message, "requested address is incorrect",  | 
    
    
    1538  | 
     | 
     | 
    		    sizeof(dhcp_message));  | 
    
    
    1539  | 
     | 
     | 
    		return NULL;  | 
    
    
    1540  | 
     | 
     | 
    	}  | 
    
    
    1541  | 
     | 
     | 
     | 
    
    
    1542  | 
     | 
     | 
    	/* Try to find a lease that's been attached to the client's  | 
    
    
    1543  | 
     | 
     | 
    	   hardware address... */  | 
    
    
    1544  | 
     | 
     | 
    	hw_lease = find_lease_by_hw_addr(packet->raw->chaddr,  | 
    
    
    1545  | 
     | 
     | 
    	    packet->raw->hlen);  | 
    
    
    1546  | 
     | 
     | 
    	/* Find the lease that's on the network the packet came from  | 
    
    
    1547  | 
     | 
     | 
    	   (if any). */  | 
    
    
    1548  | 
     | 
     | 
    	for (; hw_lease; hw_lease = hw_lease->n_hw) { | 
    
    
    1549  | 
     | 
     | 
    		if (hw_lease->shared_network == share) { | 
    
    
    1550  | 
     | 
     | 
    			if ((hw_lease->flags & ABANDONED_LEASE))  | 
    
    
    1551  | 
     | 
     | 
    				continue;  | 
    
    
    1552  | 
     | 
     | 
    			if (packet->packet_type)  | 
    
    
    1553  | 
     | 
     | 
    				break;  | 
    
    
    1554  | 
     | 
     | 
    			if (hw_lease->flags &  | 
    
    
    1555  | 
     | 
     | 
    			    (BOOTP_LEASE | DYNAMIC_BOOTP_OK))  | 
    
    
    1556  | 
     | 
     | 
    				break;  | 
    
    
    1557  | 
     | 
     | 
    		}  | 
    
    
    1558  | 
     | 
     | 
    	}  | 
    
    
    1559  | 
     | 
     | 
     | 
    
    
    1560  | 
     | 
     | 
    	/* Try to find a lease that's been allocated to the client's  | 
    
    
    1561  | 
     | 
     | 
    	   IP address. */  | 
    
    
    1562  | 
     | 
     | 
    	if (cip.len)  | 
    
    
    1563  | 
     | 
     | 
    		ip_lease = find_lease_by_ip_addr(cip);  | 
    
    
    1564  | 
     | 
     | 
    	else  | 
    
    
    1565  | 
     | 
     | 
    		ip_lease = NULL;  | 
    
    
    1566  | 
     | 
     | 
     | 
    
    
    1567  | 
     | 
     | 
    	/* If ip_lease is valid at this point, set ours to one, so that  | 
    
    
    1568  | 
     | 
     | 
    	   even if we choose a different lease, we know that the address  | 
    
    
    1569  | 
     | 
     | 
    	   the client was requesting was ours, and thus we can NAK it. */  | 
    
    
    1570  | 
     | 
     | 
    	if (ip_lease && ours)  | 
    
    
    1571  | 
     | 
     | 
    		*ours = 1;  | 
    
    
    1572  | 
     | 
     | 
     | 
    
    
    1573  | 
     | 
     | 
    	/* If the requested IP address isn't on the network the packet  | 
    
    
    1574  | 
     | 
     | 
    	   came from, don't use it.  Allow abandoned leases to be matched  | 
    
    
    1575  | 
     | 
     | 
    	   here - if the client is requesting it, there's a decent chance  | 
    
    
    1576  | 
     | 
     | 
    	   that it's because the lease database got trashed and a client  | 
    
    
    1577  | 
     | 
     | 
    	   that thought it had this lease answered an ARP or PING, causing the  | 
    
    
    1578  | 
     | 
     | 
    	   lease to be abandoned.   If so, this request probably came from  | 
    
    
    1579  | 
     | 
     | 
    	   that client. */  | 
    
    
    1580  | 
     | 
     | 
    	if (ip_lease && (ip_lease->shared_network != share)) { | 
    
    
    1581  | 
     | 
     | 
    		ip_lease = NULL;  | 
    
    
    1582  | 
     | 
     | 
    		strlcpy(dhcp_message, "requested address on bad subnet",  | 
    
    
    1583  | 
     | 
     | 
    		    sizeof(dhcp_message));  | 
    
    
    1584  | 
     | 
     | 
    	}  | 
    
    
    1585  | 
     | 
     | 
     | 
    
    
    1586  | 
     | 
     | 
    	/* Toss ip_lease if it hasn't yet expired and isn't owned by the  | 
    
    
    1587  | 
     | 
     | 
    	   client. */  | 
    
    
    1588  | 
     | 
     | 
    	if (ip_lease && ip_lease->ends >= cur_time && ip_lease != uid_lease) { | 
    
    
    1589  | 
     | 
     | 
    		int i = DHO_DHCP_CLIENT_IDENTIFIER;  | 
    
    
    1590  | 
     | 
     | 
     | 
    
    
    1591  | 
     | 
     | 
    		/* Make sure that ip_lease actually belongs to the client,  | 
    
    
    1592  | 
     | 
     | 
    		   and toss it if not. */  | 
    
    
    1593  | 
     | 
     | 
    		if ((ip_lease->uid_len && packet->options[i].data &&  | 
    
    
    1594  | 
     | 
     | 
    		    ip_lease->uid_len == packet->options[i].len &&  | 
    
    
    1595  | 
     | 
     | 
    		    !memcmp(packet->options[i].data, ip_lease->uid,  | 
    
    
    1596  | 
     | 
     | 
    		    ip_lease->uid_len)) ||  | 
    
    
    1597  | 
     | 
     | 
    		    (!ip_lease->uid_len &&  | 
    
    
    1598  | 
     | 
     | 
    		    ip_lease->hardware_addr.htype == packet->raw->htype &&  | 
    
    
    1599  | 
     | 
     | 
    		    ip_lease->hardware_addr.hlen == packet->raw->hlen &&  | 
    
    
    1600  | 
     | 
     | 
    		    !memcmp(ip_lease->hardware_addr.haddr, packet->raw->chaddr,  | 
    
    
    1601  | 
     | 
     | 
    		    ip_lease->hardware_addr.hlen))) { | 
    
    
    1602  | 
     | 
     | 
    			if (uid_lease) { | 
    
    
    1603  | 
     | 
     | 
    				if (uid_lease->ends > cur_time) { | 
    
    
    1604  | 
     | 
     | 
    					log_warnx("client %s has duplicate " | 
    
    
    1605  | 
     | 
     | 
    					    "leases on %s",  | 
    
    
    1606  | 
     | 
     | 
    					    print_hw_addr(packet->raw->htype,  | 
    
    
    1607  | 
     | 
     | 
    					    packet->raw->hlen,  | 
    
    
    1608  | 
     | 
     | 
    					    packet->raw->chaddr),  | 
    
    
    1609  | 
     | 
     | 
    					    ip_lease->shared_network->name);  | 
    
    
    1610  | 
     | 
     | 
     | 
    
    
    1611  | 
     | 
     | 
    					if (uid_lease &&  | 
    
    
    1612  | 
     | 
     | 
    					   !packet->raw->ciaddr.s_addr)  | 
    
    
    1613  | 
     | 
     | 
    						release_lease(uid_lease);  | 
    
    
    1614  | 
     | 
     | 
    				}  | 
    
    
    1615  | 
     | 
     | 
    				uid_lease = ip_lease;  | 
    
    
    1616  | 
     | 
     | 
    			}  | 
    
    
    1617  | 
     | 
     | 
    		} else { | 
    
    
    1618  | 
     | 
     | 
    			strlcpy(dhcp_message, "requested address is not "  | 
    
    
    1619  | 
     | 
     | 
    			    "available", sizeof(dhcp_message));  | 
    
    
    1620  | 
     | 
     | 
    			ip_lease = NULL;  | 
    
    
    1621  | 
     | 
     | 
    		}  | 
    
    
    1622  | 
     | 
     | 
     | 
    
    
    1623  | 
     | 
     | 
    		/* If we get to here and fixed_lease is not null, that means  | 
    
    
    1624  | 
     | 
     | 
    		   that there are both a dynamic lease and a fixed-address  | 
    
    
    1625  | 
     | 
     | 
    		   declaration for the same IP address. */  | 
    
    
    1626  | 
     | 
     | 
    		if (packet->packet_type == DHCPREQUEST && fixed_lease) { | 
    
    
    1627  | 
     | 
     | 
    			fixed_lease = NULL;  | 
    
    
    1628  | 
     | 
     | 
    db_conflict:  | 
    
    
    1629  | 
     | 
     | 
    			log_warnx("Both dynamic and static leases present for " | 
    
    
    1630  | 
     | 
     | 
    			    "%s.", piaddr(cip));  | 
    
    
    1631  | 
     | 
     | 
    			log_warnx("Either remove host declaration %s or " | 
    
    
    1632  | 
     | 
     | 
    			    "remove %s", (fixed_lease && fixed_lease->host ?  | 
    
    
    1633  | 
     | 
     | 
    			    (fixed_lease->host->name ?  | 
    
    
    1634  | 
     | 
     | 
    			    fixed_lease->host->name : piaddr(cip)) :  | 
    
    
    1635  | 
     | 
     | 
    			    piaddr(cip)), piaddr(cip));  | 
    
    
    1636  | 
     | 
     | 
    			log_warnx("from the dynamic address pool for %s", | 
    
    
    1637  | 
     | 
     | 
    			    share->name);  | 
    
    
    1638  | 
     | 
     | 
    			if (fixed_lease)  | 
    
    
    1639  | 
     | 
     | 
    				ip_lease = NULL;  | 
    
    
    1640  | 
     | 
     | 
    			strlcpy(dhcp_message, "database conflict - call for "  | 
    
    
    1641  | 
     | 
     | 
    			    "help!", sizeof(dhcp_message));  | 
    
    
    1642  | 
     | 
     | 
    		}  | 
    
    
    1643  | 
     | 
     | 
    	}  | 
    
    
    1644  | 
     | 
     | 
     | 
    
    
    1645  | 
     | 
     | 
    	/* If we get to here with both fixed_lease and ip_lease not  | 
    
    
    1646  | 
     | 
     | 
    	   null, then we have a configuration file bug. */  | 
    
    
    1647  | 
     | 
     | 
    	if (packet->packet_type == DHCPREQUEST && fixed_lease && ip_lease)  | 
    
    
    1648  | 
     | 
     | 
    		goto db_conflict;  | 
    
    
    1649  | 
     | 
     | 
     | 
    
    
    1650  | 
     | 
     | 
    	/* Toss hw_lease if it hasn't yet expired and the uid doesn't  | 
    
    
    1651  | 
     | 
     | 
    	   match, except that if the hardware address matches and the  | 
    
    
    1652  | 
     | 
     | 
    	   client is now doing dynamic BOOTP (and thus hasn't provided  | 
    
    
    1653  | 
     | 
     | 
    	   a uid) we let the client get away with it. */  | 
    
    
    1654  | 
     | 
     | 
    	if (hw_lease && hw_lease->ends >= cur_time && hw_lease->uid &&  | 
    
    
    1655  | 
     | 
     | 
    	    packet->options[DHO_DHCP_CLIENT_IDENTIFIER].len &&  | 
    
    
    1656  | 
     | 
     | 
    	    hw_lease != uid_lease)  | 
    
    
    1657  | 
     | 
     | 
    		hw_lease = NULL;  | 
    
    
    1658  | 
     | 
     | 
     | 
    
    
    1659  | 
     | 
     | 
    	/* Toss extra pointers to the same lease... */  | 
    
    
    1660  | 
     | 
     | 
    	if (hw_lease == uid_lease)  | 
    
    
    1661  | 
     | 
     | 
    		hw_lease = NULL;  | 
    
    
    1662  | 
     | 
     | 
    	if (ip_lease == hw_lease)  | 
    
    
    1663  | 
     | 
     | 
    		hw_lease = NULL;  | 
    
    
    1664  | 
     | 
     | 
    	if (ip_lease == uid_lease)  | 
    
    
    1665  | 
     | 
     | 
    		uid_lease = NULL;  | 
    
    
    1666  | 
     | 
     | 
     | 
    
    
    1667  | 
     | 
     | 
    	/* If we've already eliminated the lease, it wasn't there to  | 
    
    
    1668  | 
     | 
     | 
    	   begin with.   If we have come up with a matching lease,  | 
    
    
    1669  | 
     | 
     | 
    	   set the message to bad network in case we have to throw it out. */  | 
    
    
    1670  | 
     | 
     | 
    	if (!ip_lease) { | 
    
    
    1671  | 
     | 
     | 
    		strlcpy(dhcp_message, "requested address not available",  | 
    
    
    1672  | 
     | 
     | 
    		    sizeof(dhcp_message));  | 
    
    
    1673  | 
     | 
     | 
    	}  | 
    
    
    1674  | 
     | 
     | 
     | 
    
    
    1675  | 
     | 
     | 
    	/* Now eliminate leases that are on the wrong network... */  | 
    
    
    1676  | 
     | 
     | 
    	if (ip_lease && share != ip_lease->shared_network) { | 
    
    
    1677  | 
     | 
     | 
    		if (packet->packet_type == DHCPREQUEST)  | 
    
    
    1678  | 
     | 
     | 
    			release_lease(ip_lease);  | 
    
    
    1679  | 
     | 
     | 
    		ip_lease = NULL;  | 
    
    
    1680  | 
     | 
     | 
    	}  | 
    
    
    1681  | 
     | 
     | 
    	if (uid_lease && share != uid_lease->shared_network) { | 
    
    
    1682  | 
     | 
     | 
    		if (packet->packet_type == DHCPREQUEST)  | 
    
    
    1683  | 
     | 
     | 
    			release_lease(uid_lease);  | 
    
    
    1684  | 
     | 
     | 
    		uid_lease = NULL;  | 
    
    
    1685  | 
     | 
     | 
    	}  | 
    
    
    1686  | 
     | 
     | 
    	if (hw_lease && share != hw_lease->shared_network) { | 
    
    
    1687  | 
     | 
     | 
    		if (packet->packet_type == DHCPREQUEST)  | 
    
    
    1688  | 
     | 
     | 
    			release_lease(hw_lease);  | 
    
    
    1689  | 
     | 
     | 
    		hw_lease = NULL;  | 
    
    
    1690  | 
     | 
     | 
    	}  | 
    
    
    1691  | 
     | 
     | 
     | 
    
    
    1692  | 
     | 
     | 
    	/* If this is a DHCPREQUEST, make sure the lease we're going to return  | 
    
    
    1693  | 
     | 
     | 
    	   matches the requested IP address.   If it doesn't, don't return a  | 
    
    
    1694  | 
     | 
     | 
    	   lease at all. */  | 
    
    
    1695  | 
     | 
     | 
    	if (packet->packet_type == DHCPREQUEST && !ip_lease && !fixed_lease)  | 
    
    
    1696  | 
     | 
     | 
    		return NULL;  | 
    
    
    1697  | 
     | 
     | 
     | 
    
    
    1698  | 
     | 
     | 
    	/* At this point, if fixed_lease is nonzero, we can assign it to  | 
    
    
    1699  | 
     | 
     | 
    	   this client. */  | 
    
    
    1700  | 
     | 
     | 
    	if (fixed_lease)  | 
    
    
    1701  | 
     | 
     | 
    		lease = fixed_lease;  | 
    
    
    1702  | 
     | 
     | 
     | 
    
    
    1703  | 
     | 
     | 
    	/* If we got a lease that matched the ip address and don't have  | 
    
    
    1704  | 
     | 
     | 
    	   a better offer, use that; otherwise, release it. */  | 
    
    
    1705  | 
     | 
     | 
    	if (ip_lease) { | 
    
    
    1706  | 
     | 
     | 
    		if (lease) { | 
    
    
    1707  | 
     | 
     | 
    			if (packet->packet_type == DHCPREQUEST)  | 
    
    
    1708  | 
     | 
     | 
    				release_lease(ip_lease);  | 
    
    
    1709  | 
     | 
     | 
    		} else { | 
    
    
    1710  | 
     | 
     | 
    			lease = ip_lease;  | 
    
    
    1711  | 
     | 
     | 
    			lease->host = NULL;  | 
    
    
    1712  | 
     | 
     | 
    		}  | 
    
    
    1713  | 
     | 
     | 
    	}  | 
    
    
    1714  | 
     | 
     | 
     | 
    
    
    1715  | 
     | 
     | 
    	/* If we got a lease that matched the client identifier, we may want  | 
    
    
    1716  | 
     | 
     | 
    	   to use it, but if we already have a lease we like, we must free  | 
    
    
    1717  | 
     | 
     | 
    	   the lease that matched the client identifier. */  | 
    
    
    1718  | 
     | 
     | 
    	if (uid_lease) { | 
    
    
    1719  | 
     | 
     | 
    		if (lease) { | 
    
    
    1720  | 
     | 
     | 
    			if (packet->packet_type == DHCPREQUEST)  | 
    
    
    1721  | 
     | 
     | 
    				release_lease(uid_lease);  | 
    
    
    1722  | 
     | 
     | 
    		} else { | 
    
    
    1723  | 
     | 
     | 
    			lease = uid_lease;  | 
    
    
    1724  | 
     | 
     | 
    			lease->host = NULL;  | 
    
    
    1725  | 
     | 
     | 
    		}  | 
    
    
    1726  | 
     | 
     | 
    	}  | 
    
    
    1727  | 
     | 
     | 
     | 
    
    
    1728  | 
     | 
     | 
    	/* The lease that matched the hardware address is treated likewise. */  | 
    
    
    1729  | 
     | 
     | 
    	if (hw_lease) { | 
    
    
    1730  | 
     | 
     | 
    		if (lease) { | 
    
    
    1731  | 
     | 
     | 
    			if (packet->packet_type == DHCPREQUEST)  | 
    
    
    1732  | 
     | 
     | 
    				release_lease(hw_lease);  | 
    
    
    1733  | 
     | 
     | 
    		} else { | 
    
    
    1734  | 
     | 
     | 
    			lease = hw_lease;  | 
    
    
    1735  | 
     | 
     | 
    			lease->host = NULL;  | 
    
    
    1736  | 
     | 
     | 
    		}  | 
    
    
    1737  | 
     | 
     | 
    	}  | 
    
    
    1738  | 
     | 
     | 
     | 
    
    
    1739  | 
     | 
     | 
    	/* If we found a host_decl but no matching address, try to  | 
    
    
    1740  | 
     | 
     | 
    	   find a host_decl that has no address, and if there is one,  | 
    
    
    1741  | 
     | 
     | 
    	   hang it off the lease so that we can use the supplied  | 
    
    
    1742  | 
     | 
     | 
    	   options. */  | 
    
    
    1743  | 
     | 
     | 
    	if (lease && host && !lease->host) { | 
    
    
    1744  | 
     | 
     | 
    		for (; host; host = host->n_ipaddr) { | 
    
    
    1745  | 
     | 
     | 
    			if (!host->fixed_addr) { | 
    
    
    1746  | 
     | 
     | 
    				lease->host = host;  | 
    
    
    1747  | 
     | 
     | 
    				break;  | 
    
    
    1748  | 
     | 
     | 
    			}  | 
    
    
    1749  | 
     | 
     | 
    		}  | 
    
    
    1750  | 
     | 
     | 
    	}  | 
    
    
    1751  | 
     | 
     | 
     | 
    
    
    1752  | 
     | 
     | 
    	/* If we find an abandoned lease, take it, but print a  | 
    
    
    1753  | 
     | 
     | 
    	   warning message, so that if it continues to lose,  | 
    
    
    1754  | 
     | 
     | 
    	   the administrator will eventually investigate. */  | 
    
    
    1755  | 
     | 
     | 
    	if (lease && (lease->flags & ABANDONED_LEASE)) { | 
    
    
    1756  | 
     | 
     | 
    		if (packet->packet_type == DHCPREQUEST) { | 
    
    
    1757  | 
     | 
     | 
    			log_warnx("Reclaiming REQUESTed abandoned IP address " | 
    
    
    1758  | 
     | 
     | 
    			    "%s.", piaddr(lease->ip_addr));  | 
    
    
    1759  | 
     | 
     | 
    			lease->flags &= ~ABANDONED_LEASE;  | 
    
    
    1760  | 
     | 
     | 
    		} else  | 
    
    
    1761  | 
     | 
     | 
    			lease = NULL;  | 
    
    
    1762  | 
     | 
     | 
    	}  | 
    
    
    1763  | 
     | 
     | 
    	return lease;  | 
    
    
    1764  | 
     | 
     | 
    }  | 
    
    
    1765  | 
     | 
     | 
     | 
    
    
    1766  | 
     | 
     | 
    /*  | 
    
    
    1767  | 
     | 
     | 
     * Search the provided host_decl structure list for an address that's on  | 
    
    
    1768  | 
     | 
     | 
     * the specified shared network.  If one is found, mock up and return a  | 
    
    
    1769  | 
     | 
     | 
     * lease structure for it; otherwise return the null pointer.  | 
    
    
    1770  | 
     | 
     | 
     */  | 
    
    
    1771  | 
     | 
     | 
    struct lease *  | 
    
    
    1772  | 
     | 
     | 
    mockup_lease(struct packet *packet, struct shared_network *share,  | 
    
    
    1773  | 
     | 
     | 
        struct host_decl *hp)  | 
    
    
    1774  | 
     | 
     | 
    { | 
    
    
    1775  | 
     | 
     | 
    	static struct lease mock;  | 
    
    
    1776  | 
     | 
     | 
     | 
    
    
    1777  | 
     | 
     | 
    	mock.subnet = find_host_for_network(&hp, &mock.ip_addr, share);  | 
    
    
    1778  | 
     | 
     | 
    	if (!mock.subnet)  | 
    
    
    1779  | 
     | 
     | 
    		return (NULL);  | 
    
    
    1780  | 
     | 
     | 
    	mock.next = mock.prev = NULL;  | 
    
    
    1781  | 
     | 
     | 
    	mock.shared_network = mock.subnet->shared_network;  | 
    
    
    1782  | 
     | 
     | 
    	mock.host = hp;  | 
    
    
    1783  | 
     | 
     | 
     | 
    
    
    1784  | 
     | 
     | 
    	if (hp->group->options[DHO_DHCP_CLIENT_IDENTIFIER]) { | 
    
    
    1785  | 
     | 
     | 
    		mock.uid =  | 
    
    
    1786  | 
     | 
     | 
    		    hp->group->options[DHO_DHCP_CLIENT_IDENTIFIER]->value;  | 
    
    
    1787  | 
     | 
     | 
    		mock.uid_len =  | 
    
    
    1788  | 
     | 
     | 
    		    hp->group->options[DHO_DHCP_CLIENT_IDENTIFIER]->len;  | 
    
    
    1789  | 
     | 
     | 
    	} else { | 
    
    
    1790  | 
     | 
     | 
    		mock.uid = NULL;  | 
    
    
    1791  | 
     | 
     | 
    		mock.uid_len = 0;  | 
    
    
    1792  | 
     | 
     | 
    	}  | 
    
    
    1793  | 
     | 
     | 
     | 
    
    
    1794  | 
     | 
     | 
    	mock.hardware_addr = hp->interface;  | 
    
    
    1795  | 
     | 
     | 
    	mock.starts = mock.timestamp = mock.ends = MIN_TIME;  | 
    
    
    1796  | 
     | 
     | 
    	mock.flags = STATIC_LEASE;  | 
    
    
    1797  | 
     | 
     | 
    	return &mock;  | 
    
    
    1798  | 
     | 
     | 
    }  |