]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
Merged rt12324, DHCPLEASEQUERY.
authorShane Kerr <shane@isc.org>
Tue, 25 Jul 2006 13:26:00 +0000 (13:26 +0000)
committerShane Kerr <shane@isc.org>
Tue, 25 Jul 2006 13:26:00 +0000 (13:26 +0000)
13 files changed:
RELNOTES
common/conflex.c
common/options.c
common/tables.c
includes/dhcp.h
includes/dhcpd.h
includes/dhctoken.h
server/Makefile.dist
server/confpars.c
server/dhcp.c
server/dhcpd.conf.5
server/dhcpleasequery.c [new file with mode: 0644]
server/mdb.c

index dd1a95db15f1b5360de31447e857de26f13ea4c4..3f6ac7298b1f98ab52f74c990dfdc20ae1212689 100644 (file)
--- 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
index 7184a4aae13679f40898eb14baa91bf77223111e..fd4418b43393f8a3afcfd4c570a86fc15e2a47a3 100644 (file)
@@ -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"))
index 0e0abfa5f72df8553eeb0d1d4bb9e0d981511c8c..304f456b999c3d43eb1c81c8ff33ad9f3c59769d 100644 (file)
@@ -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;
+}
+
+
index eefad58f357aa82eef619e4b28fcefb11e230b06..030f8dd711d8779fe514932833a28ade43a38f5a 100644 (file)
@@ -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 },
index 23b76fc18cca0bc8756c4248f5352bba2288be5a..1be7b04f046f71dbffad5a7f27929c5dd101dd64 100644 (file)
@@ -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
index 2f66d1c121134ebe0b33d26ebc80bd193e53a068..994be098b19b709c8487dac0042def4d3b4c0125 100644 (file)
@@ -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 *));
index 0315c7c9fecbe79ffd1b04f61eec45ec3503f75f..7c3b38dadb36175058d4d7e834bf5472d7b485e0 100644 (file)
@@ -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 &&  \
index 4d59d0a687c35e615f1670d9177f54721eb33f16..4ead8f0aa01a055bffa8ff0cb98e22ec4c31e99e 100644 (file)
@@ -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
 
index a8907e70857e71f9c49cc9ed16cf043d06ec7593..8679284924c00b17ac659c339c0fa53fc3192c40 100644 (file)
@@ -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 :== <nil>
@@ -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);
index ff3db5285b7cbd133fedec9ab74fd031bf67e964..5d068909750aed698958ea163ca94e05b289e2e7 100644 (file)
@@ -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)
                     : "<no identifier>")),
                  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)
                     : "<no identifier>")),
                 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)
                     : "<no identifier>")),
                 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)
                     : "<no identifier>")),
                 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));
+       }
+}
+
index 7ef0cad6c5a362bc8d89fe96f7469b5c2449a817..66629da6e6be35524a115b63ab409afa50e834b3 100644 (file)
@@ -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 (file)
index 0000000..1b9b43b
--- /dev/null
@@ -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);
+}
+
index 000f027b8e948f33e898f83c45966baa144cbd8d..1986d608cf84cd428201ce38986f89cef2567cb4 100644 (file)
@@ -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) {