From 6d103865fbb24323051749eccc1d2ee39015673d Mon Sep 17 00:00:00 2001 From: Shane Kerr Date: Tue, 25 Jul 2006 13:26:00 +0000 Subject: [PATCH] Merged rt12324, DHCPLEASEQUERY. --- RELNOTES | 6 + common/conflex.c | 4 +- common/options.c | 54 +++- common/tables.c | 4 +- includes/dhcp.h | 175 +++++------ includes/dhcpd.h | 14 +- includes/dhctoken.h | 3 +- server/Makefile.dist | 4 +- server/confpars.c | 34 +-- server/dhcp.c | 235 ++++++--------- server/dhcpd.conf.5 | 15 +- server/dhcpleasequery.c | 646 ++++++++++++++++++++++++++++++++++++++++ server/mdb.c | 7 +- 13 files changed, 931 insertions(+), 270 deletions(-) create mode 100644 server/dhcpleasequery.c diff --git a/RELNOTES b/RELNOTES index dd1a95db1..3f6ac7298 100644 --- a/RELNOTES +++ b/RELNOTES @@ -146,6 +146,12 @@ and for prodding me into improving it. - Support for compressed 'domain name list' style DHCP option contents, and in particular the domain search option (#119) was added. +- The DHCP LEASEQUERY protocol as definied in RFC4388 is now implemented. + LEASEQUERY lets you query the DHCP server for information about a lease, + using either an IP address, MAC address, or client identifier. Thanks + to a patch from Justin Haddad. + + Changes since 3.0.4 - A warning that host statements declared within subnet or shared-network diff --git a/common/conflex.c b/common/conflex.c index 7184a4aae..fd4418b43 100644 --- a/common/conflex.c +++ b/common/conflex.c @@ -34,7 +34,7 @@ #ifndef lint static char copyright[] = -"$Id: conflex.c,v 1.101 2006/07/22 02:24:16 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; +"$Id: conflex.c,v 1.102 2006/07/25 13:25:59 shane Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -823,6 +823,8 @@ static enum dhcp_token intern (atom, dfv) return LEASED_ADDRESS; if (!strcasecmp (atom + 1, "ease-time")) return LEASE_TIME; + if (!strcasecmp(atom + 1, "easequery")) + return LEASEQUERY; if (!strcasecmp(atom + 1, "ength")) return LENGTH; if (!strcasecmp (atom + 1, "imit")) diff --git a/common/options.c b/common/options.c index 0e0abfa5f..304f456b9 100644 --- a/common/options.c +++ b/common/options.c @@ -34,7 +34,7 @@ #ifndef lint static char copyright[] = -"$Id: options.c,v 1.92 2006/07/22 02:24:16 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; +"$Id: options.c,v 1.93 2006/07/25 13:25:59 shane Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #define DHCP_OPTION_DATA @@ -1804,7 +1804,7 @@ int save_option_buffer (struct universe *universe, /* If we weren't passed a buffer in which the data are saved and refcounted, allocate one now. */ if (!bp) { - if (!buffer_allocate (&lbp, length, MDL)) { + if (!buffer_allocate (&lbp, length + tp, MDL)) { log_error ("no memory for option buffer."); option_cache_dereference (&op, MDL); @@ -2831,3 +2831,53 @@ pretty_domain(char **dst, char *dend, const unsigned char **src, return count; } +/* + * Add the option identified with the option number and data to the + * options state. + */ +int +add_option(struct option_state *options, + unsigned int option_num, + void *data, + unsigned int data_len) +{ + struct option_cache *oc; + struct option *option; + + /* INSIST(options != NULL); */ + /* INSIST(data != NULL); */ + + option = NULL; + if (!option_code_hash_lookup(&option, dhcp_universe.code_hash, + &option_num, 0, MDL)) { + log_error("Attempting to add unknown option %d.", option_num); + return 0; + } + + oc = NULL; + if (!option_cache_allocate(&oc, MDL)) { + log_error("No memory for option cache adding %s (option %d).", + option->name, option_num); + return 0; + } + + if (!make_const_data(&oc->expression, + data, + data_len, + 0, + 0, + MDL)) { + log_error("No memory for constant data adding %s (option %d).", + option->name, option_num); + option_cache_dereference(&oc, MDL); + return 0; + } + + oc->option = option; + save_option(&dhcp_universe, options, oc); + option_cache_dereference(&oc, MDL); + + return 1; +} + + diff --git a/common/tables.c b/common/tables.c index eefad58f3..030f8dd71 100644 --- a/common/tables.c +++ b/common/tables.c @@ -34,7 +34,7 @@ #ifndef lint static char copyright[] = -"$Id: tables.c,v 1.56 2006/07/22 02:24:16 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; +"$Id: tables.c,v 1.57 2006/07/25 13:25:59 shane Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -184,6 +184,8 @@ static struct option dhcp_options[] = { { "nds-servers", "IA", &dhcp_universe, 85, 1 }, { "nds-tree-name", "t", &dhcp_universe, 86, 1 }, { "nds-context", "t", &dhcp_universe, 87, 1 }, + { "client-last-transaction-time", "L", &dhcp_universe, 91, 1 }, + { "associated-ip", "Ia", &dhcp_universe, 92, 1 }, { "uap-servers", "t", &dhcp_universe, 98, 1 }, { "subnet-selection", "I", &dhcp_universe, 118, 1 }, { "domain-search", "D", &dhcp_universe, 119, 1 }, diff --git a/includes/dhcp.h b/includes/dhcp.h index 23b76fc18..1be7b04f0 100644 --- a/includes/dhcp.h +++ b/includes/dhcp.h @@ -31,7 +31,7 @@ */ #define DHCP_UDP_OVERHEAD (20 + /* IP header */ \ - 8) /* UDP header */ + 8) /* UDP header */ #define DHCP_SNAME_LEN 64 #define DHCP_FILE_LEN 128 #define DHCP_FIXED_NON_UDP 236 @@ -44,7 +44,7 @@ #define DHCP_MIN_LEN 548 struct dhcp_packet { - u_int8_t op; /* 0: Message opcode/type */ + u_int8_t op; /* 0: Message opcode/type */ u_int8_t htype; /* 1: Hardware addr type (net/if_types.h) */ u_int8_t hlen; /* 2: Hardware addr length */ u_int8_t hops; /* 3: Number of relay agent hops from client */ @@ -60,7 +60,7 @@ struct dhcp_packet { char file [DHCP_FILE_LEN]; /* 104: Boot filename */ unsigned char options [DHCP_OPTION_LEN]; /* 212: Optional parameters - (actual length dependent on MTU). */ + (actual length dependent on MTU). */ }; /* BOOTP (rfc951) message types */ @@ -81,95 +81,102 @@ struct dhcp_packet { /* DHCP Option codes: */ -#define DHO_PAD 0 -#define DHO_SUBNET_MASK 1 -#define DHO_TIME_OFFSET 2 -#define DHO_ROUTERS 3 -#define DHO_TIME_SERVERS 4 -#define DHO_NAME_SERVERS 5 -#define DHO_DOMAIN_NAME_SERVERS 6 -#define DHO_LOG_SERVERS 7 -#define DHO_COOKIE_SERVERS 8 -#define DHO_LPR_SERVERS 9 -#define DHO_IMPRESS_SERVERS 10 -#define DHO_RESOURCE_LOCATION_SERVERS 11 -#define DHO_HOST_NAME 12 -#define DHO_BOOT_SIZE 13 -#define DHO_MERIT_DUMP 14 -#define DHO_DOMAIN_NAME 15 -#define DHO_SWAP_SERVER 16 -#define DHO_ROOT_PATH 17 -#define DHO_EXTENSIONS_PATH 18 -#define DHO_IP_FORWARDING 19 -#define DHO_NON_LOCAL_SOURCE_ROUTING 20 -#define DHO_POLICY_FILTER 21 -#define DHO_MAX_DGRAM_REASSEMBLY 22 -#define DHO_DEFAULT_IP_TTL 23 -#define DHO_PATH_MTU_AGING_TIMEOUT 24 -#define DHO_PATH_MTU_PLATEAU_TABLE 25 -#define DHO_INTERFACE_MTU 26 -#define DHO_ALL_SUBNETS_LOCAL 27 -#define DHO_BROADCAST_ADDRESS 28 -#define DHO_PERFORM_MASK_DISCOVERY 29 -#define DHO_MASK_SUPPLIER 30 -#define DHO_ROUTER_DISCOVERY 31 -#define DHO_ROUTER_SOLICITATION_ADDRESS 32 -#define DHO_STATIC_ROUTES 33 -#define DHO_TRAILER_ENCAPSULATION 34 -#define DHO_ARP_CACHE_TIMEOUT 35 -#define DHO_IEEE802_3_ENCAPSULATION 36 -#define DHO_DEFAULT_TCP_TTL 37 -#define DHO_TCP_KEEPALIVE_INTERVAL 38 -#define DHO_TCP_KEEPALIVE_GARBAGE 39 -#define DHO_NIS_DOMAIN 40 -#define DHO_NIS_SERVERS 41 -#define DHO_NTP_SERVERS 42 -#define DHO_VENDOR_ENCAPSULATED_OPTIONS 43 -#define DHO_NETBIOS_NAME_SERVERS 44 -#define DHO_NETBIOS_DD_SERVER 45 -#define DHO_NETBIOS_NODE_TYPE 46 -#define DHO_NETBIOS_SCOPE 47 -#define DHO_FONT_SERVERS 48 -#define DHO_X_DISPLAY_MANAGER 49 -#define DHO_DHCP_REQUESTED_ADDRESS 50 -#define DHO_DHCP_LEASE_TIME 51 -#define DHO_DHCP_OPTION_OVERLOAD 52 -#define DHO_DHCP_MESSAGE_TYPE 53 -#define DHO_DHCP_SERVER_IDENTIFIER 54 -#define DHO_DHCP_PARAMETER_REQUEST_LIST 55 -#define DHO_DHCP_MESSAGE 56 -#define DHO_DHCP_MAX_MESSAGE_SIZE 57 -#define DHO_DHCP_RENEWAL_TIME 58 -#define DHO_DHCP_REBINDING_TIME 59 -#define DHO_VENDOR_CLASS_IDENTIFIER 60 -#define DHO_DHCP_CLIENT_IDENTIFIER 61 -#define DHO_NWIP_DOMAIN_NAME 62 -#define DHO_NWIP_SUBOPTIONS 63 -#define DHO_USER_CLASS 77 -#define DHO_FQDN 81 -#define DHO_DHCP_AGENT_OPTIONS 82 -#define DHO_SUBNET_SELECTION 118 /* RFC3011! */ -#define DHO_DOMAIN_SEARCH 119 /* RFC3397 */ -#define DHO_VIVCO_SUBOPTIONS 124 -#define DHO_VIVSO_SUBOPTIONS 125 +#define DHO_PAD 0 +#define DHO_SUBNET_MASK 1 +#define DHO_TIME_OFFSET 2 +#define DHO_ROUTERS 3 +#define DHO_TIME_SERVERS 4 +#define DHO_NAME_SERVERS 5 +#define DHO_DOMAIN_NAME_SERVERS 6 +#define DHO_LOG_SERVERS 7 +#define DHO_COOKIE_SERVERS 8 +#define DHO_LPR_SERVERS 9 +#define DHO_IMPRESS_SERVERS 10 +#define DHO_RESOURCE_LOCATION_SERVERS 11 +#define DHO_HOST_NAME 12 +#define DHO_BOOT_SIZE 13 +#define DHO_MERIT_DUMP 14 +#define DHO_DOMAIN_NAME 15 +#define DHO_SWAP_SERVER 16 +#define DHO_ROOT_PATH 17 +#define DHO_EXTENSIONS_PATH 18 +#define DHO_IP_FORWARDING 19 +#define DHO_NON_LOCAL_SOURCE_ROUTING 20 +#define DHO_POLICY_FILTER 21 +#define DHO_MAX_DGRAM_REASSEMBLY 22 +#define DHO_DEFAULT_IP_TTL 23 +#define DHO_PATH_MTU_AGING_TIMEOUT 24 +#define DHO_PATH_MTU_PLATEAU_TABLE 25 +#define DHO_INTERFACE_MTU 26 +#define DHO_ALL_SUBNETS_LOCAL 27 +#define DHO_BROADCAST_ADDRESS 28 +#define DHO_PERFORM_MASK_DISCOVERY 29 +#define DHO_MASK_SUPPLIER 30 +#define DHO_ROUTER_DISCOVERY 31 +#define DHO_ROUTER_SOLICITATION_ADDRESS 32 +#define DHO_STATIC_ROUTES 33 +#define DHO_TRAILER_ENCAPSULATION 34 +#define DHO_ARP_CACHE_TIMEOUT 35 +#define DHO_IEEE802_3_ENCAPSULATION 36 +#define DHO_DEFAULT_TCP_TTL 37 +#define DHO_TCP_KEEPALIVE_INTERVAL 38 +#define DHO_TCP_KEEPALIVE_GARBAGE 39 +#define DHO_NIS_DOMAIN 40 +#define DHO_NIS_SERVERS 41 +#define DHO_NTP_SERVERS 42 +#define DHO_VENDOR_ENCAPSULATED_OPTIONS 43 +#define DHO_NETBIOS_NAME_SERVERS 44 +#define DHO_NETBIOS_DD_SERVER 45 +#define DHO_NETBIOS_NODE_TYPE 46 +#define DHO_NETBIOS_SCOPE 47 +#define DHO_FONT_SERVERS 48 +#define DHO_X_DISPLAY_MANAGER 49 +#define DHO_DHCP_REQUESTED_ADDRESS 50 +#define DHO_DHCP_LEASE_TIME 51 +#define DHO_DHCP_OPTION_OVERLOAD 52 +#define DHO_DHCP_MESSAGE_TYPE 53 +#define DHO_DHCP_SERVER_IDENTIFIER 54 +#define DHO_DHCP_PARAMETER_REQUEST_LIST 55 +#define DHO_DHCP_MESSAGE 56 +#define DHO_DHCP_MAX_MESSAGE_SIZE 57 +#define DHO_DHCP_RENEWAL_TIME 58 +#define DHO_DHCP_REBINDING_TIME 59 +#define DHO_VENDOR_CLASS_IDENTIFIER 60 +#define DHO_DHCP_CLIENT_IDENTIFIER 61 +#define DHO_NWIP_DOMAIN_NAME 62 +#define DHO_NWIP_SUBOPTIONS 63 +#define DHO_USER_CLASS 77 +#define DHO_FQDN 81 +#define DHO_DHCP_AGENT_OPTIONS 82 +#define DHO_CLIENT_LAST_TRANSACTION_TIME 91 +#define DHO_ASSOCIATED_IP 92 +#define DHO_SUBNET_SELECTION 118 /* RFC3011! */ +#define DHO_DOMAIN_SEARCH 119 /* RFC3397 */ +#define DHO_VIVCO_SUBOPTIONS 124 +#define DHO_VIVSO_SUBOPTIONS 125 /* The DHO_AUTHENTICATE option is not a standard yet, so I've allocated an option out of the "local" option space for it on a temporary basis. Once an option code number is assigned, I will immediately and shamelessly break this, so don't count on it continuing to work. */ -#define DHO_AUTHENTICATE 210 +#define DHO_AUTHENTICATE 210 -#define DHO_END 255 +#define DHO_END 255 /* DHCP message types. */ -#define DHCPDISCOVER 1 -#define DHCPOFFER 2 -#define DHCPREQUEST 3 -#define DHCPDECLINE 4 -#define DHCPACK 5 -#define DHCPNAK 6 -#define DHCPRELEASE 7 -#define DHCPINFORM 8 +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 +#define DHCPINFORM 8 +#define DHCPLEASEQUERY 10 +#define DHCPLEASEUNASSIGNED 11 +#define DHCPLEASEUNKNOWN 12 +#define DHCPLEASEACTIVE 13 + /* Relay Agent Information option subtypes: */ #define RAI_CIRCUIT_ID 1 diff --git a/includes/dhcpd.h b/includes/dhcpd.h index 2f66d1c12..994be098b 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -358,7 +358,7 @@ struct lease { struct lease *n_uid, *n_hw; struct iaddr ip_addr; - TIME starts, ends, timestamp, sort_time; + TIME starts, ends, sort_time; char *client_hostname; struct binding_scope *scope; struct host_decl *host; @@ -511,6 +511,7 @@ struct lease_state { #define SV_PING_TIMEOUT 46 #define SV_RESERVE_INFINITE 47 #define SV_DDNS_CONFLICT_DETECT 48 +#define SV_LEASEQUERY 49 #if !defined (DEFAULT_PING_TIMEOUT) # define DEFAULT_PING_TIMEOUT 1 @@ -1249,6 +1250,11 @@ void do_packet PROTO ((struct interface_info *, struct dhcp_packet *, unsigned, unsigned int, struct iaddr, struct hardware *)); +int add_option(struct option_state *options, + unsigned int option_num, + void *data, + unsigned int data_len); + /* dhcpd.c */ extern TIME cur_time; @@ -1310,7 +1316,6 @@ void parse_subnet_declaration PROTO ((struct parse *, struct shared_network *)); void parse_group_declaration PROTO ((struct parse *, struct group *)); int parse_fixed_addr_param PROTO ((struct option_cache **, struct parse *)); -TIME parse_timestamp PROTO ((struct parse *)); int parse_lease_declaration PROTO ((struct lease **, struct parse *)); void parse_address_range PROTO ((struct parse *, struct group *, int, struct pool *, struct lease **)); @@ -1503,6 +1508,7 @@ void dhcprequest PROTO ((struct packet *, int, struct lease *)); void dhcprelease PROTO ((struct packet *, int)); void dhcpdecline PROTO ((struct packet *, int)); void dhcpinform PROTO ((struct packet *, int)); +void dhcpleasequery PROTO ((struct packet *, int)); void nak_lease PROTO ((struct packet *, struct iaddr *cip)); void ack_lease PROTO ((struct packet *, struct lease *, unsigned int, TIME, char *, int, struct host_decl *)); @@ -1523,6 +1529,9 @@ int parse_agent_information_option PROTO ((struct packet *, int, u_int8_t *)); unsigned cons_agent_information_options PROTO ((struct option_state *, struct dhcp_packet *, unsigned, unsigned)); +void get_server_source_address(struct in_addr *from, + struct option_state *options, + struct packet *packet); /* bootp.c */ void bootp PROTO ((struct packet *)); @@ -2104,7 +2113,6 @@ void convert_servername_decl PROTO ((struct parse *, jrefproto)); void convert_ip_addr_or_hostname PROTO ((struct parse *, jrefproto, int)); void convert_fixed_addr_decl PROTO ((struct parse *, jrefproto)); void convert_option_decl PROTO ((struct parse *, jrefproto)); -void convert_timestamp PROTO ((struct parse *, jrefproto)); void convert_lease_statement PROTO ((struct parse *, jrefproto)); void convert_address_range PROTO ((struct parse *, jrefproto)); void convert_date PROTO ((struct parse *, jrefproto, char *)); diff --git a/includes/dhctoken.h b/includes/dhctoken.h index 0315c7c9f..7c3b38dad 100644 --- a/includes/dhctoken.h +++ b/includes/dhctoken.h @@ -323,7 +323,8 @@ enum dhcp_token { MAX_LEASE_OWNERSHIP = 627, MAX_BALANCE = 628, MIN_BALANCE = 629, - DOMAIN_LIST = 630 + DOMAIN_LIST = 630, + LEASEQUERY = 631 }; #define is_identifier(x) ((x) >= FIRST_TOKEN && \ diff --git a/server/Makefile.dist b/server/Makefile.dist index 4d59d0a68..4ead8f0aa 100644 --- a/server/Makefile.dist +++ b/server/Makefile.dist @@ -25,9 +25,9 @@ CATMANPAGES = dhcpd.cat8 dhcpd.conf.cat5 dhcpd.leases.cat5 SEDMANPAGES = dhcpd.man8 dhcpd.conf.man5 dhcpd.leases.man5 SRCS = dhcpd.c dhcp.c bootp.c confpars.c db.c class.c failover.c \ - omapi.c mdb.c stables.c salloc.c ddns.c + omapi.c mdb.c stables.c salloc.c ddns.c dhcpleasequery.c OBJS = dhcpd.o dhcp.o bootp.o confpars.o db.o class.o failover.o \ - omapi.o mdb.o stables.o salloc.o ddns.o + omapi.o mdb.o stables.o salloc.o ddns.o dhcpleasequery.o PROG = dhcpd MAN = dhcpd.8 dhcpd.conf.5 dhcpd.leases.5 diff --git a/server/confpars.c b/server/confpars.c index a8907e708..867928492 100644 --- a/server/confpars.c +++ b/server/confpars.c @@ -34,7 +34,7 @@ #ifndef lint static char copyright[] = -"$Id: confpars.c,v 1.158 2006/07/20 16:04:03 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; +"$Id: confpars.c,v 1.159 2006/07/25 13:26:00 shane Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -295,8 +295,7 @@ isc_result_t lease_file_subparse (struct parse *cfile) /* statement :== parameter | declaration - parameter :== timestamp - | DEFAULT_LEASE_TIME lease_time + parameter :== DEFAULT_LEASE_TIME lease_time | MAX_LEASE_TIME lease_time | DYNAMIC_BOOTP_LEASE_CUTOFF date | DYNAMIC_BOOTP_LEASE_LENGTH lease_time @@ -395,11 +394,6 @@ int parse_statement (cfile, group, type, host_decl, declaration) } return 1; - case TIMESTAMP: - next_token (&val, (unsigned *)0, cfile); - parsed_time = parse_timestamp (cfile); - break; - case SHARED_NETWORK: next_token (&val, (unsigned *)0, cfile); if (type == SHARED_NET_DECL || @@ -2584,21 +2578,6 @@ int parse_fixed_addr_param (oc, cfile) return status; } -/* timestamp :== date - - Timestamps are actually not used in dhcpd.conf, which is a static file, - but rather in the database file and the journal file. (Okay, actually - they're not even used there yet). */ - -TIME parse_timestamp (cfile) - struct parse *cfile; -{ - TIME rv; - - rv = parse_date (cfile); - return rv; -} - /* lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE lease_parameters :== @@ -2690,11 +2669,6 @@ int parse_lease_declaration (struct lease **lp, struct parse *cfile) lease -> ends = t; break; - case TIMESTAMP: - seenbit = 4; - lease -> timestamp = t; - break; - case TSTP: seenbit = 65536; lease -> tstp = t; @@ -3421,6 +3395,10 @@ int parse_allow_deny (oc, cfile, flag) code = SV_CLIENT_UPDATES; break; + case LEASEQUERY: + code = SV_LEASEQUERY; + break; + default: parse_warn (cfile, "expecting allow/deny key"); skip_to_semi (cfile); diff --git a/server/dhcp.c b/server/dhcp.c index ff3db5285..5d0689097 100644 --- a/server/dhcp.c +++ b/server/dhcp.c @@ -34,7 +34,7 @@ #ifndef lint static char copyright[] = -"$Id: dhcp.c,v 1.208 2006/07/17 15:16:43 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; +"$Id: dhcp.c,v 1.209 2006/07/25 13:26:00 shane Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -51,7 +51,12 @@ static const char *dhcp_type_names [] = { "DHCPACK", "DHCPNAK", "DHCPRELEASE", - "DHCPINFORM" + "DHCPINFORM", + "(unknown)", + "DHCPLEASEQUERY", + "DHCPLEASEUNASSIGNED", + "DHCPLEASEUNKNOWN", + "DHCPLEASEACTIVE" }; const int dhcp_type_name_max = ((sizeof dhcp_type_names) / sizeof (char *)); @@ -70,7 +75,8 @@ void dhcp (packet) if (!locate_network (packet) && packet -> packet_type != DHCPREQUEST && - packet -> packet_type != DHCPINFORM) { + packet -> packet_type != DHCPINFORM && + packet -> packet_type != DHCPLEASEQUERY) { const char *s; char typebuf [32]; errmsg = "unknown network segment"; @@ -221,10 +227,16 @@ void dhcp (packet) dhcpinform (packet, ms_nulltp); break; + case DHCPLEASEQUERY: + dhcpleasequery(packet, ms_nulltp); + break; case DHCPACK: case DHCPOFFER: case DHCPNAK: + case DHCPLEASEUNASSIGNED: + case DHCPLEASEUNKNOWN: + case DHCPLEASEACTIVE: break; default: @@ -270,8 +282,7 @@ void dhcpdiscover (packet, ms_nulltp) packet -> raw -> hlen, packet -> raw -> chaddr) : (lease - ? print_hex_1 (lease -> uid_len, lease -> uid, - lease -> uid_len) + ? print_hex_1(lease->uid_len, lease->uid, 60) : "")), s ? "(" : "", s ? s : "", s ? ") " : "", packet -> raw -> giaddr.s_addr @@ -457,8 +468,7 @@ void dhcprequest (packet, ms_nulltp, ip_lease) packet -> raw -> hlen, packet -> raw -> chaddr) : (lease - ? print_hex_1 (lease -> uid_len, lease -> uid, - lease -> uid_len) + ? print_hex_1(lease->uid_len, lease->uid, 60) : "")), s ? "(" : "", s ? s : "", s ? ") " : "", packet -> raw -> giaddr.s_addr @@ -749,8 +759,7 @@ void dhcprelease (packet, ms_nulltp) packet -> raw -> hlen, packet -> raw -> chaddr) : (lease - ? print_hex_1 (lease -> uid_len, lease -> uid, - lease -> uid_len) + ? print_hex_1(lease->uid_len, lease->uid, 60) : "")), s ? "(" : "", s ? s : "", s ? ") " : "", packet -> raw -> giaddr.s_addr @@ -839,8 +848,7 @@ void dhcpdecline (packet, ms_nulltp) packet -> raw -> hlen, packet -> raw -> chaddr) : (lease - ? print_hex_1 (lease -> uid_len, lease -> uid, - lease -> uid_len) + ? print_hex_1(lease->uid_len, lease->uid, 60) : "")), s ? "(" : "", s ? s : "", s ? ") " : "", packet -> raw -> giaddr.s_addr @@ -1083,41 +1091,7 @@ void dhcpinform (packet, ms_nulltp) option_cache_dereference (&oc, MDL); } - i = DHO_DHCP_SERVER_IDENTIFIER; - if (!(oc = lookup_option (&dhcp_universe, options, i))) { - use_primary: - oc = (struct option_cache *)0; - if (packet -> interface -> address_count > 0) { - if (option_cache_allocate (&oc, MDL)) { - if (make_const_data - (&oc -> expression, - ((unsigned char *) - &packet -> interface -> addresses [0]), - sizeof packet -> interface -> addresses [0], - 0, 0, MDL)) { - option_code_hash_lookup(&oc->option, - dhcp_universe.code_hash, - &i, 0, MDL); - save_option (&dhcp_universe, options, oc); - } - option_cache_dereference (&oc, MDL); - } - from = packet -> interface -> addresses [0]; - } - } else { - if (evaluate_option_cache (&d1, packet, (struct lease *)0, - (struct client_state *)0, - packet -> options, options, - &global_scope, oc, MDL)) { - if (!d1.len || d1.len != sizeof from) { - data_string_forget (&d1, MDL); - goto use_primary; - } - memcpy (&from, d1.data, sizeof from); - data_string_forget (&d1, MDL); - } else - goto use_primary; - } + get_server_source_address(&from, options, packet); /* Use the subnet mask from the subnet declaration if no other mask has been provided. */ @@ -1314,7 +1288,6 @@ void nak_lease (packet, cip) struct option_state *options = (struct option_state *)0; struct expression *expr; struct option_cache *oc = (struct option_cache *)0; - struct iaddr myfrom; option_state_allocate (&options, MDL); memset (&outgoing, 0, sizeof outgoing); @@ -1360,46 +1333,7 @@ void nak_lease (packet, cip) save_option (&dhcp_universe, options, oc); option_cache_dereference (&oc, MDL); - i = DHO_DHCP_SERVER_IDENTIFIER; - if (packet -> interface -> address_count > 0) { - if (!(oc = lookup_option (&dhcp_universe, options, i))) { - use_primary: - oc = (struct option_cache *)0; - if (option_cache_allocate (&oc, MDL)) { - if (make_const_data - (&oc -> expression, - ((unsigned char *) - &packet -> interface -> addresses [0]), - sizeof packet -> interface -> addresses [0], - 0, 0, MDL)) { - option_code_hash_lookup(&oc->option, - dhcp_universe.code_hash, - &i, 0, MDL); - save_option (&dhcp_universe, options, oc); - } - option_cache_dereference (&oc, MDL); - } - myfrom.len = sizeof packet -> interface -> addresses [0]; - memcpy (myfrom.iabuf, - &packet -> interface -> addresses [0], myfrom.len); - } - } else { - memset (&data, 0, sizeof data); - if (evaluate_option_cache (&data, packet, (struct lease *)0, - (struct client_state *)0, - packet -> options, options, - &global_scope, oc, MDL)) { - if (!data.len || - data.len > sizeof myfrom.iabuf) { - data_string_forget (&data, MDL); - goto use_primary; - } - memcpy (myfrom.iabuf, data.data, data.len); - myfrom.len = data.len; - data_string_forget (&data, MDL); - } else - goto use_primary; - } + get_server_source_address(&from, options, packet); /* If there were agent options in the incoming packet, return them. */ @@ -1473,8 +1407,6 @@ void nak_lease (packet, cip) #endif memset (to.sin_zero, 0, sizeof to.sin_zero); - memcpy (&from, myfrom.iabuf, sizeof from); - /* Make sure that the packet is at least as big as a BOOTP packet. */ if (outgoing.packet_length < BOOTP_MIN_LEN) outgoing.packet_length = BOOTP_MIN_LEN; @@ -1531,6 +1463,8 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) isc_result_t result; int did_ping = 0; TIME ping_timeout; + TIME lease_cltt; + struct in_addr from; unsigned i, j; int s1, s2; @@ -1541,6 +1475,9 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) if (lease -> state) return; + /* Save original cltt for comparison later. */ + lease_cltt = lease->cltt; + /* If the lease carries a host record, remember it. */ if (hp) host_reference (&host, hp, MDL); @@ -2103,8 +2040,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) lt->tsfp = lease->tsfp; lt->atsfp = lease->atsfp; - /* Update Client Last Transaction Time. */ - lt->cltt = cur_time; + /* cltt set below */ /* Lease times less than MCLT are not a concern. */ if (lease_time > peer->mclt) { @@ -2201,7 +2137,8 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) lt -> next_binding_state = FTS_ACTIVE; } - lt -> timestamp = cur_time; + /* Update Client Last Transaction Time. */ + lt->cltt = cur_time; /* Record the uid, if given... */ oc = lookup_option (&dhcp_universe, packet -> options, @@ -2462,50 +2399,10 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) } option_cache_dereference (&oc, MDL); } - i = DHO_DHCP_SERVER_IDENTIFIER; - if (!(oc = lookup_option (&dhcp_universe, - state -> options, i))) { - use_primary: - if (state -> ip -> address_count > 0) { - oc = (struct option_cache *)0; - if (option_cache_allocate (&oc, MDL)) { - if (make_const_data - (&oc -> expression, - ((unsigned char *) - &state -> ip -> addresses [0]), - sizeof state -> ip -> addresses [0], - 0, 0, MDL)) { - option_code_hash_lookup(&oc->option, - dhcp_universe.code_hash, - &i, 0, MDL); - save_option (&dhcp_universe, - state -> options, oc); - } - option_cache_dereference (&oc, MDL); - } - state -> from.len = - sizeof state -> ip -> addresses [0]; - memcpy (state -> from.iabuf, - &state -> ip -> addresses [0], - state -> from.len); - } - } else { - if (evaluate_option_cache (&d1, packet, lease, - (struct client_state *)0, - packet -> options, - state -> options, - &lease -> scope, oc, MDL)) { - if (!d1.len || - d1.len > sizeof state -> from.iabuf) { - data_string_forget (&d1, MDL); - goto use_primary; - } - memcpy (state -> from.iabuf, d1.data, d1.len); - state -> from.len = d1.len; - data_string_forget (&d1, MDL); - } else - goto use_primary; - } + + get_server_source_address(&from, state->options, packet); + memcpy(state->from.iabuf, &from, sizeof(from)); + state->from.len = sizeof(from); offered_lease_time = state -> offered_expiry - cur_time; @@ -2569,6 +2466,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) option_cache_dereference (&oc, MDL); } } else { + /* XXXSK: should we use get_server_source_address() here? */ if (state -> ip -> address_count) { state -> from.len = sizeof state -> ip -> addresses [0]; @@ -2764,7 +2662,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) /* If this is a DHCPOFFER, ping the lease address before actually sending the offer. */ if (offer == DHCPOFFER && !(lease -> flags & STATIC_LEASE) && - cur_time - lease -> timestamp > 60 && + ((cur_time - lease_cltt) > 60) && (!(oc = lookup_option (&server_universe, state -> options, SV_PING_CHECKS)) || evaluate_boolean_option_cache (&ignorep, packet, lease, @@ -2772,7 +2670,6 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) packet -> options, state -> options, &lease -> scope, oc, MDL))) { - lease -> timestamp = cur_time; icmp_echorequest (&lease -> ip_addr); /* Determine whether to use configured or default ping timeout. @@ -2801,8 +2698,8 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) (tvunref_t)lease_dereference); ++outstanding_pings; } else { - lease -> timestamp = cur_time; - dhcp_reply (lease); + lease->cltt = cur_time; + dhcp_reply(lease); } } @@ -2915,8 +2812,7 @@ void dhcp_reply (lease) ? print_hw_addr (lease -> hardware_addr.hbuf [0], lease -> hardware_addr.hlen - 1, &lease -> hardware_addr.hbuf [1]) - : print_hex_1 (lease -> uid_len, lease -> uid, - lease -> uid_len)), + : print_hex_1(lease->uid_len, lease->uid, 60)), s ? "(" : "", s ? s : "", s ? ") " : "", (state -> giaddr.s_addr ? inet_ntoa (state -> giaddr) @@ -3729,7 +3625,7 @@ int mockup_lease (struct lease **lp, struct packet *packet, rhp -> client_identifier.len); lease -> uid_len = rhp -> client_identifier.len; lease -> hardware_addr = rhp -> interface; - lease -> starts = lease -> timestamp = lease -> ends = MIN_TIME; + lease -> starts = lease -> cltt = lease -> ends = MIN_TIME; lease -> flags = STATIC_LEASE; lease -> binding_state = FTS_FREE; @@ -3958,3 +3854,56 @@ int locate_network (packet) /* Otherwise, fail. */ return 0; } + +/* + * Try to figure out the source address to send packets from. + * + * If the packet we received specified the server address, then we + * will use that. + * + * Otherwise, use the first address from the interface. If we do + * this, we also save this into the option cache as the server + * address. + */ +void +get_server_source_address(struct in_addr *from, + struct option_state *options, + struct packet *packet) { + int option_num; + struct option_cache *oc; + struct data_string d; + struct in_addr *a; + struct option *option; + + option_num = DHO_DHCP_SERVER_IDENTIFIER; + oc = lookup_option(&dhcp_universe, options, option_num); + if ((oc != NULL) && + evaluate_option_cache(&d, packet, NULL, NULL, packet->options, + options, &global_scope, oc, MDL)) { + if (d.len == sizeof(*from)) { + memcpy(from, d.data, sizeof(*from)); + data_string_forget(&d, MDL); + return; + } + data_string_forget(&d, MDL); + } + + if (packet->interface->address_count > 0) { + if (option_cache_allocate(&oc, MDL)) { + a = &packet->interface->addresses[0]; + if (make_const_data(&oc->expression, + (char *)a, sizeof(*a), + 0, 0, MDL)) { + option_code_hash_lookup(&oc->option, + dhcp_universe.code_hash, + &option_num, 0, MDL); + save_option(&dhcp_universe, options, oc); + } + option_cache_dereference(&oc, MDL); + } + *from = packet->interface->addresses[0]; + } else { + memset(from, 0, sizeof(*from)); + } +} + diff --git a/server/dhcpd.conf.5 b/server/dhcpd.conf.5 index 7ef0cad6c..66629da6e 100644 --- a/server/dhcpd.conf.5 +++ b/server/dhcpd.conf.5 @@ -28,7 +28,7 @@ .\" see ``http://www.vix.com''. To learn more about Nominum, Inc., see .\" ``http://www.nominum.com''. .\" -.\" $Id: dhcpd.conf.5,v 1.77 2006/07/19 20:13:57 dhankins Exp $ +.\" $Id: dhcpd.conf.5,v 1.78 2006/07/25 13:26:00 shane Exp $ .\" .TH dhcpd.conf 5 .SH NAME @@ -1648,6 +1648,19 @@ honor the client's intention to do its own update of its A record. This is only relevant when doing \fIinterim\fR DNS updates. See the documentation under the heading THE INTERIM DNS UPDATE SCHEME for details. +.PP +.B The +.I leasequery +.B keyword +.PP + \fBallow leasequery;\fR + \fBdeny leasequery;\fR +.PP +The \fBleasequery\fR flag tells the DHCP server whether or not to +answer DHCPLEASEQUERY packets. The answer to a DHCPLEASEQUERY packet +includes information about a specific lease, such as when it was +issued and when it will expire. By default, the server will not +respond to these packets. .SH ALLOW AND DENY WITHIN POOL DECLARATIONS .PP The uses of the allow and deny keywords shown in the previous section diff --git a/server/dhcpleasequery.c b/server/dhcpleasequery.c new file mode 100644 index 000000000..1b9b43b52 --- /dev/null +++ b/server/dhcpleasequery.c @@ -0,0 +1,646 @@ +/* + * Copyright (C) 2006 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "dhcpd.h" + +/* + * TODO: RFC4388 specifies that the server SHOULD store the + * vendor-class-id. + * + * TODO: RFC4388 specifies that the server SHOULD return the same + * options it would for a DHCREQUEST message, if no Parameter + * Request List option (option 55) is passed. We do not do that. + * + * TODO: RFC4388 specifies the creation of a "non-sensitive options" + * configuration list, and that these SHOULD be returned. We + * have no such list. + * + * TODO: RFC4388 says the server SHOULD use RFC3118, "Authentication + * for DHCP Messages". + * + * TODO: RFC4388 specifies that you SHOULD insure that you cannot be + * DoS'ed by DHCPLEASEQUERY message. + */ + +/* + * If you query by hardware address or by client ID, then you may have + * more than one IP address for your query argument. We need to do two + * things: + * + * 1. Find the most recent lease. + * 2. Find all additional IP addresses for the query argument. + * + * We do this by looking through all of the leases associated with a + * given hardware address or client ID. We use the cltt (client last + * transaction time) of the lease, which only has a resolution of one + * second, so we might not actually give the very latest IP. + */ + +static struct lease* +next_hw(const struct lease *lease) { + /* INSIST(lease != NULL); */ + return lease->n_hw; +} + +static struct lease* +next_uid(const struct lease *lease) { + /* INSIST(lease != NULL); */ + return lease->n_uid; +} + +void +get_newest_lease(struct lease **retval, + struct lease *lease, + struct lease *(*next)(const struct lease *)) { + + struct lease *p; + struct lease *newest; + + /* INSIST(newest != NULL); */ + /* INSIST(next != NULL); */ + + *retval = NULL; + + if (lease == NULL) { + return; + } + + newest = lease; + for (p=next(lease); p != NULL; p=next(p)) { + if (newest->binding_state == FTS_ACTIVE) { + if ((p->binding_state == FTS_ACTIVE) && + (p->cltt > newest->cltt)) { + newest = p; + } + } else { + if (p->ends > newest->ends) { + newest = p; + } + } + } + + lease_reference(retval, newest, MDL); +} + +static int +get_associated_ips(const struct lease *lease, + struct lease *(*next)(const struct lease *), + const struct lease *newest, + u_int32_t *associated_ips, + unsigned int associated_ips_size) { + + const struct lease *p; + int cnt; + + /* INSIST(next != NULL); */ + /* INSIST(associated_ips != NULL); */ + + if (lease == NULL) { + return 0; + } + + cnt = 0; + for (p=lease; p != NULL; p=next(p)) { + if ((p->binding_state == FTS_ACTIVE) && (p != newest)) { + if (cnt < associated_ips_size) { + memcpy(&associated_ips[cnt], + p->ip_addr.iabuf, + sizeof(associated_ips[cnt])); + } + cnt++; + } + } + return cnt; +} + + +void +dhcpleasequery(struct packet *packet, int ms_nulltp) { + char msgbuf[256]; + char dbg_info[128]; + struct iaddr cip; + struct iaddr gip; + struct data_string uid; + struct hardware h; + struct lease *tmp_lease; + struct lease *lease; + int want_associated_ip; + int assoc_ip_cnt; + u_int32_t assoc_ips[40]; /* XXXSK: arbritrary maximum number of IPs */ + const int nassoc_ips = sizeof(assoc_ips) / sizeof(assoc_ips[0]); + + unsigned char dhcpMsgType; + const char *dhcp_msg_type_name; + struct subnet *subnet; + struct option_state *options; + struct option_cache *oc; + int allow_leasequery; + int ignorep; + u_int32_t lease_duration; + u_int32_t time_renewal; + u_int32_t time_rebinding; + u_int32_t time_expiry; + u_int32_t client_last_transaction_time; + struct sockaddr_in to; + struct in_addr siaddr; + struct data_string prl; + struct data_string *prl_ptr; + + int i; + struct interface_info *interface; + + /* INSIST(packet != NULL); */ + + /* + * Prepare log information. + */ + snprintf(msgbuf, sizeof(msgbuf), + "DHCPLEASEQUERY from %s", inet_ntoa(packet->raw->giaddr)); + + /* + * We can't reply if there is no giaddr field. + */ + if (!packet->raw->giaddr.s_addr) { + log_info("%s: missing giaddr, ciaddr is %s, no reply sent", + msgbuf, inet_ntoa(packet->raw->ciaddr)); + return; + } + + /* + * Set up our options, scope, and, um... stuff. + * This is basically copied from dhcpinform() in dhcp.c. + */ + gip.len = sizeof(packet->raw->giaddr); + memcpy(gip.iabuf, &packet->raw->giaddr, sizeof(packet->raw->giaddr)); + + subnet = NULL; + find_subnet(&subnet, gip, MDL); + if (subnet == NULL) { + log_info("%s: unknown subnet for address %s", + msgbuf, piaddr(gip)); + return; + } + + options = NULL; + if (!option_state_allocate(&options, MDL)) { + subnet_dereference(&subnet, MDL); + log_error("No memory for option state."); + log_info("%s: out of memory, no reply sent", msgbuf); + return; + } + + execute_statements_in_scope(NULL, + packet, + NULL, + NULL, + packet->options, + options, + &global_scope, + subnet->group, + NULL); + for (i=packet->class_count-1; i>=0; i--) { + execute_statements_in_scope(NULL, + packet, + NULL, + NULL, + packet->options, + options, + &global_scope, + packet->classes[i]->group, + subnet->group); + } + + subnet_dereference(&subnet, MDL); + + /* + * Because LEASEQUERY has some privacy concerns, default to deny. + */ + allow_leasequery = 0; + + /* + * See if we are authorised to do LEASEQUERY. + */ + oc = lookup_option(&server_universe, options, SV_LEASEQUERY); + if (oc != NULL) { + allow_leasequery = evaluate_boolean_option_cache(&ignorep, + packet, NULL, NULL, packet->options, + options, &global_scope, oc, MDL); + } + + if (!allow_leasequery) { + log_info("%s: LEASEQUERY not allowed, query ignored", msgbuf); + option_state_dereference(&options, MDL); + return; + } + + + /* + * Copy out the client IP address. + */ + cip.len = sizeof(packet->raw->ciaddr); + memcpy(cip.iabuf, &packet->raw->ciaddr, sizeof(packet->raw->ciaddr)); + + /* + * If the client IP address is valid (not all zero), then we + * are looking for information about that IP address. + */ + assoc_ip_cnt = 0; + if (memcmp(cip.iabuf, "\0\0\0", 4)) { + + want_associated_ip = 0; + + snprintf(dbg_info, sizeof(dbg_info), "IP %s", piaddr(cip)); + find_lease_by_ip_addr(&lease, cip, MDL); + + + } else { + + want_associated_ip = 1; + + /* + * If the client IP address is all zero, then we will + * either look up by the client identifier (if we have + * one), or by the MAC address. + */ + + memset(&uid, 0, sizeof(uid)); + if (get_option(&uid, + &dhcp_universe, + packet, + NULL, + NULL, + packet->options, + NULL, + packet->options, + &global_scope, + DHO_DHCP_CLIENT_IDENTIFIER, + MDL)) { + + snprintf(dbg_info, + sizeof(dbg_info), + "client-id %s", + print_hex_1(uid.len, uid.data, 60)); + + find_lease_by_uid(&tmp_lease, uid.data, uid.len, MDL); + data_string_forget(&uid, MDL); + get_newest_lease(&lease, tmp_lease, next_uid); + assoc_ip_cnt = get_associated_ips(tmp_lease, + next_uid, + lease, + assoc_ips, + nassoc_ips); + + } else { + + if (packet->raw->hlen+1 > sizeof(h.hbuf)) { + log_info("%s: hardware length too long, " + "no reply sent", msgbuf); + option_state_dereference(&options, MDL); + return; + } + + h.hlen = packet->raw->hlen + 1; + h.hbuf[0] = packet->raw->htype; + memcpy(&h.hbuf[1], + packet->raw->chaddr, + packet->raw->hlen); + + snprintf(dbg_info, + sizeof(dbg_info), + "MAC address %s", + print_hw_addr(h.hbuf[0], + h.hlen - 1, + &h.hbuf[1])); + + find_lease_by_hw_addr(&tmp_lease, h.hbuf, h.hlen, MDL); + get_newest_lease(&lease, tmp_lease, next_hw); + assoc_ip_cnt = get_associated_ips(tmp_lease, + next_hw, + lease, + assoc_ips, + nassoc_ips); + + } + + lease_dereference(&tmp_lease, MDL); + + if (lease != NULL) { + memcpy(&packet->raw->ciaddr, + lease->ip_addr.iabuf, + sizeof(packet->raw->ciaddr)); + } + + /* + * Log if we have too many IP addresses associated + * with this client. + */ + if (want_associated_ip && (assoc_ip_cnt > nassoc_ips)) { + log_info("%d IP addresses associated with %s, " + "only %d sent in reply.", + assoc_ip_cnt, dbg_info, nassoc_ips); + } + } + + /* + * We now know the query target too, so can report this in + * our log message. + */ + snprintf(msgbuf, sizeof(msgbuf), + "DHCPLEASEQUERY from %s for %s", + inet_ntoa(packet->raw->giaddr), dbg_info); + + /* + * Figure our our return type. + */ + if (lease == NULL) { + dhcpMsgType = DHCPLEASEUNKNOWN; + dhcp_msg_type_name = "DHCPLEASEUNKNOWN"; + } else { + if (lease->binding_state == FTS_ACTIVE) { + dhcpMsgType = DHCPLEASEACTIVE; + dhcp_msg_type_name = "DHCPLEASEACTIVE"; + } else { + dhcpMsgType = DHCPLEASEUNASSIGNED; + dhcp_msg_type_name = "DHCPLEASEUNASSIGNED"; + } + } + + /* + * Set options that only make sense if we have an active lease. + */ + + if (dhcpMsgType == DHCPLEASEACTIVE) + { + + /* + * Set the hardware address fields. + */ + + packet->raw->hlen = lease->hardware_addr.hlen - 1; + packet->raw->htype = lease->hardware_addr.hbuf[0]; + memcpy(packet->raw->chaddr, + &lease->hardware_addr.hbuf[1], + sizeof(packet->raw->chaddr)); + + /* + * Set client identifier option. + */ + if (lease->uid_len > 0) { + if (!add_option(options, + DHO_DHCP_CLIENT_IDENTIFIER, + lease->uid, + lease->uid_len)) { + option_state_dereference(&options, MDL); + lease_dereference(&lease, MDL); + log_info("%s: out of memory, no reply sent", + msgbuf); + return; + } + } + + + /* + * Calculate T1 and T2, the times when the client + * tries to extend its lease on its networking + * address. + * These seem to be hard-coded in ISC DHCP, to 0.5 and + * 0.875 of the lease time. + */ + + lease_duration = lease->ends - lease->starts; + time_renewal = lease->starts + + (lease_duration / 2); + time_rebinding = lease->starts + + (lease_duration / 2) + + (lease_duration / 4) + + (lease_duration / 8); + + if (time_renewal > cur_time) { + time_renewal = htonl(time_renewal - cur_time); + if (!add_option(options, + DHO_DHCP_RENEWAL_TIME, + &time_renewal, + sizeof(time_renewal))) { + option_state_dereference(&options, MDL); + lease_dereference(&lease, MDL); + log_info("%s: out of memory, no reply sent", + msgbuf); + return; + } + } + + if (time_rebinding > cur_time) { + time_rebinding = htonl(time_rebinding - cur_time); + if (!add_option(options, + DHO_DHCP_REBINDING_TIME, + &time_rebinding, + sizeof(time_rebinding))) { + option_state_dereference(&options, MDL); + lease_dereference(&lease, MDL); + log_info("%s: out of memory, no reply sent", + msgbuf); + return; + } + } + + if (lease->ends > cur_time) { + time_expiry = htonl(lease->ends - cur_time); + if (!add_option(options, + DHO_DHCP_LEASE_TIME, + &time_expiry, + sizeof(time_expiry))) { + option_state_dereference(&options, MDL); + lease_dereference(&lease, MDL); + log_info("%s: out of memory, no reply sent", + msgbuf); + return; + } + } + + + /* + * Set the relay agent info. + */ + + if (lease->agent_options != NULL) { + int idx = agent_universe.index; + struct option_chain_head **tmp1 = + (struct option_chain_head **) + &(options->universes[idx]); + struct option_chain_head *tmp2 = + (struct option_chain_head *) + lease->agent_options; + + option_chain_head_reference(tmp1, tmp2, MDL); + } + + /* + * Set the client last transaction time. + * We check to make sure we have a timestamp. For + * lease files that were saved before running a + * timestamp-aware version of the server, this may + * not be set. + */ + + if (lease->cltt != MIN_TIME) { + if (cur_time > lease->cltt) { + client_last_transaction_time = + htonl(cur_time - lease->cltt); + } else { + client_last_transaction_time = htonl(0); + } + if (!add_option(options, + DHO_CLIENT_LAST_TRANSACTION_TIME, + &client_last_transaction_time, + sizeof(client_last_transaction_time))) { + option_state_dereference(&options, MDL); + lease_dereference(&lease, MDL); + log_info("%s: out of memory, no reply sent", + msgbuf); + return; + } + } + + /* + * Set associated IPs, if requested and there are some. + */ + if (want_associated_ip && (assoc_ip_cnt > 0)) { + if (!add_option(options, + DHO_ASSOCIATED_IP, + assoc_ips, + assoc_ip_cnt * sizeof(assoc_ips[0]))) { + option_state_dereference(&options, MDL); + lease_dereference(&lease, MDL); + log_info("%s: out of memory, no reply sent", + msgbuf); + return; + } + } + } + + /* + * Set the message type. + */ + + packet->raw->op = BOOTREPLY; + + /* + * Set DHCP message type. + */ + if (!add_option(options, + DHO_DHCP_MESSAGE_TYPE, + &dhcpMsgType, + sizeof(dhcpMsgType))) { + option_state_dereference(&options, MDL); + lease_dereference(&lease, MDL); + log_info("%s: error adding option, no reply sent", msgbuf); + return; + } + + /* + * Log the message we've received. + */ + log_info("%s", msgbuf); + + /* + * Figure out which address to use to send from. + */ + get_server_source_address(&siaddr, options, packet); + + /* + * Set up the option buffer. + */ + + memset(&prl, 0, sizeof(prl)); + oc = lookup_option(&dhcp_universe, options, + DHO_DHCP_PARAMETER_REQUEST_LIST); + if (oc != NULL) { + evaluate_option_cache(&prl, + packet, + NULL, + NULL, + packet->options, + options, + &global_scope, + oc, + MDL); + } + if (prl.len > 0) { + prl_ptr = &prl; + } else { + prl_ptr = NULL; + } + + packet->packet_length = cons_options(packet, + packet->raw, + lease, + NULL, + 0, + packet->options, + options, + &global_scope, + 0, + 0, + 0, + prl_ptr, + NULL); + + data_string_forget(&prl, MDL); /* SK: safe, even if empty */ + option_state_dereference(&options, MDL); + lease_dereference(&lease, MDL); + + to.sin_family = AF_INET; +#ifdef HAVE_SA_LEN + to.sin_len = sizeof(to); +#endif + memset(to.sin_zero, 0, sizeof(to.sin_zero)); + + /* + * Leasequery packets are be sent to the gateway address. + */ + to.sin_addr = packet->raw->giaddr; + if (packet->raw->giaddr.s_addr != htonl(INADDR_LOOPBACK)) { + to.sin_port = local_port; + } else { + to.sin_port = remote_port; /* XXXSK: For debugging. */ + } + + /* + * The fallback_interface lets us send with a real IP + * address. The packet interface sends from all-zeros. + */ + if (fallback_interface != NULL) { + interface = fallback_interface; + } else { + interface = packet->interface; + } + + /* + * Report what we're sending. + */ + log_info("%s to %s for %s (%d associated IPs)", + dhcp_msg_type_name, + inet_ntoa(to.sin_addr), dbg_info, assoc_ip_cnt); + + send_packet(interface, + NULL, + packet->raw, + packet->packet_length, + siaddr, + &to, + NULL); +} + diff --git a/server/mdb.c b/server/mdb.c index 000f027b8..1986d608c 100644 --- a/server/mdb.c +++ b/server/mdb.c @@ -34,7 +34,7 @@ #ifndef lint static char copyright[] = -"$Id: mdb.c,v 1.82 2006/07/18 18:15:53 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; +"$Id: mdb.c,v 1.83 2006/07/25 13:26:00 shane Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -620,7 +620,7 @@ void new_address_range (cfile, low, high, subnet, pool, lpchain) #endif lp -> ip_addr = ip_addr (subnet -> net, subnet -> netmask, i + min); - lp -> starts = lp -> timestamp = MIN_TIME; + lp -> starts = MIN_TIME; lp -> ends = MIN_TIME; subnet_reference (&lp -> subnet, subnet, MDL); pool_reference (&lp -> pool, pool, MDL); @@ -1040,8 +1040,8 @@ int supersede_lease (comp, lease, commit, propogate, pimmediate) hw_hash_add (comp); } -#if defined (FAILOVER_PROTOCOL) comp->cltt = lease->cltt; +#if defined (FAILOVER_PROTOCOL) comp->tstp = lease->tstp; comp->tsfp = lease->tsfp; comp->atsfp = lease->atsfp; @@ -1384,7 +1384,6 @@ int lease_copy (struct lease **lp, lt -> ip_addr = lease -> ip_addr; lt -> starts = lease -> starts; lt -> ends = lease -> ends; - lt -> timestamp = lease -> timestamp; lt -> uid_len = lease -> uid_len; lt -> uid_max = lease -> uid_max; if (lease -> uid == lease -> uid_buf) { -- 2.39.5