]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
Intermediate changes to support actual DHCP protocol engine
authorTed Lemon <source@isc.org>
Wed, 21 Feb 1996 12:11:09 +0000 (12:11 +0000)
committerTed Lemon <source@isc.org>
Wed, 21 Feb 1996 12:11:09 +0000 (12:11 +0000)
29 files changed:
Makefile
client/dhclient.c
common/conflex.c
common/hash.c
common/inet.c
common/memory.c
common/options.c
common/print.c
common/socket.c
conflex.c
confpars.c
dhclient.c
dhcp.c
dhcpd.c
dhcpd.conf
dhcpd.h
dhctoken.h
hash.c
includes/dhcpd.h
includes/dhctoken.h
inet.c
memory.c
options.c
print.c
server/confpars.c
server/dhcp.c
server/dhcpd.c
server/dhcpd.conf
socket.c

index e745f08e50a5d2d1fa40d8e62ade1decc3c8a6c2..c90b3043babf90096b620632770127f0bfea8cf8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -11,6 +11,8 @@ CFLAGS += -DDEBUG -g -Wall -Wstrict-prototypes -Wno-unused \
          -Wno-uninitialized -Werror
 
 dhclient:      dhclient.o confpars.o alloc.o memory.o options.o \
-               hash.o tables.o inet.o convert.o conflex.o errwarn.o tree.o
+               hash.o tables.o inet.o convert.o conflex.o errwarn.o \
+               tree.o print.o
        cc -o dhclient dhclient.o confpars.o alloc.o memory.o options.o \
-               hash.o tables.o inet.o convert.o conflex.o errwarn.o tree.o
\ No newline at end of file
+               hash.o tables.o inet.o convert.o conflex.o errwarn.o \
+               print.o tree.o
\ No newline at end of file
index 0a66c41d7b6bdb493add2af002ed3cca8afea61a..c9d9e64dbb95bfe69c394f39e294718ddf87acef 100644 (file)
@@ -189,11 +189,51 @@ int main (argc, argv, envp)
 
                        cons_options ((struct packet *)0,
                                      &outgoing, &decl, bufs);
-                       memset (&raw.ciaddr, 0, sizeof raw.ciaddr);
-                       memset (&raw.yiaddr, 0, sizeof raw.ciaddr);
-                       memset (&raw.siaddr, 0, sizeof raw.ciaddr);
-                       memset (&raw.giaddr, 0, sizeof raw.ciaddr);
-                       
+
+                       if (decl.ciaddr) {
+                               if (tree_evaluate (decl.ciaddr) != 4)
+                                       warn ("ciaddr is more"
+                                             " than one address");
+                               else
+                                       memcpy (&raw.ciaddr,
+                                               decl.ciaddr -> value,
+                                               decl.ciaddr -> len);
+                       } else
+                               memset (&raw.ciaddr, 0, sizeof raw.ciaddr);
+
+                       if (decl.yiaddr) {
+                               if (tree_evaluate (decl.yiaddr) != 4)
+                                       warn ("yiaddr is more"
+                                             " than one address");
+                               else
+                                       memcpy (&raw.yiaddr,
+                                               decl.yiaddr -> value,
+                                               decl.yiaddr -> len);
+                       } else
+                               memset (&raw.yiaddr, 0, sizeof raw.yiaddr);
+
+                       if (decl.siaddr) {
+                               if (tree_evaluate (decl.siaddr) != 4)
+                                       warn ("siaddr is more"
+                                             " than one address");
+                               else
+                                       memcpy (&raw.siaddr,
+                                               decl.siaddr -> value,
+                                               decl.siaddr -> len);
+                       } else
+                               memset (&raw.siaddr, 0, sizeof raw.siaddr);
+
+                       if (decl.giaddr) {
+                               if (tree_evaluate (decl.giaddr) != 4)
+                                       warn ("giaddr is more"
+                                             " than one address");
+                               else
+                                       memcpy (&raw.giaddr,
+                                               decl.giaddr -> value,
+                                               decl.giaddr -> len);
+                       } else
+                               memset (&raw.giaddr, 0, sizeof raw.giaddr);
+
                        raw.xid = xid++;
                        raw.xid = htons (raw.xid);
                        raw.secs = 0;
index 33e583186c9b5e2d58b69ab8dbbca931d34cde11..28a9f65e3e8da00a108a3c200ee775e3a4375cfd 100644 (file)
@@ -274,6 +274,8 @@ static int intern (atom, dfv)
              case 'c':
                if (!strcasecmp (atom + 1, "lass"))
                        return CLASS;
+               if (!strcasecmp (atom + 1, "iaddr"))
+                       return CIADDR;
                break;
              case 'e':
                if (!strcasecmp (atom + 1, "thernet"))
@@ -287,6 +289,10 @@ static int intern (atom, dfv)
                if (!strcasecmp (atom + 1, "ixed-address"))
                        return FIXED_ADDR;
                break;
+             case 'g':
+               if (!strcasecmp (atom + 1, "iaddr"))
+                       return GIADDR;
+               break;
              case 'h':
                if (!strcasecmp (atom + 1, "ost"))
                        return HOST;
@@ -312,6 +318,8 @@ static int intern (atom, dfv)
              case 's':
                if (!strcasecmp (atom + 1, "tarts"))
                        return STARTS;
+               if (!strcasecmp (atom + 1, "iaddr"))
+                       return SIADDR;
                break;
              case 't':
                if (!strcasecmp (atom + 1, "timestamp"))
@@ -321,6 +329,10 @@ static int intern (atom, dfv)
                if (!strcasecmp (atom + 1, "id"))
                        return UID;
                break;
+             case 'y':
+               if (!strcasecmp (atom + 1, "iaddr"))
+                       return YIADDR;
+               break;
        }
        return dfv;
 }
index 8bc724e7aa298545beb8e8923e1927bf5cdc47f7..cf15ba315cf28425cd80f554a206198bcb9b3cc4 100644 (file)
@@ -103,6 +103,7 @@ void add_hash (table, name, len, pointer)
        bp -> name = name;
        bp -> value = pointer;
        bp -> next = table -> buckets [hashno];
+       bp -> len = len;
        table -> buckets [hashno] = bp;
 }
 
@@ -140,10 +141,11 @@ unsigned char *hash_lookup (table, name, len)
        struct hash_bucket *bp;
 
        if (len) {
-               for (bp = table -> buckets [hashno]; bp; bp = bp -> next)
+               for (bp = table -> buckets [hashno]; bp; bp = bp -> next) {
                        if (len == bp -> len
                            && !memcmp (bp -> name, name, len))
                                return bp -> value;
+               }
        } else {
                for (bp = table -> buckets [hashno]; bp; bp = bp -> next)
                        if (!strcmp (bp -> name, name))
index fa25efc1ae3ac797a77212455258cf26baef0167..ce63a2b4d856f12e1f707cae8af10c26a94e1198 100644 (file)
@@ -87,7 +87,7 @@ struct iaddr ip_addr (subnet, mask, host_address)
        j = rv.len - sizeof habuf;
        for (i = sizeof habuf - 1; i >= 0; i--) {
                if (mask.iabuf [i + j]) {
-                       if (habuf [i] > ~mask.iabuf [i + j]) {
+                       if (habuf [i] > (mask.iabuf [i + j] ^ 0xFF)) {
                                rv.len = 0;
                                return rv;
                        }
@@ -97,10 +97,10 @@ struct iaddr ip_addr (subnet, mask, host_address)
                                        return rv;
                                }
                        }
-                       rv.iabuf [i + j] &= habuf [i];
+                       rv.iabuf [i + j] |= habuf [i];
                        break;
-               }
-               rv.iabuf [i + j] = habuf [i];
+               } else
+                       rv.iabuf [i + j] = habuf [i];
        }
                
        return rv;
index 21b1c010f9485b8c9751d9b65bc1c68091cbbc71..13bf3492f9cec9be5a27598d6bba9369cd23a442 100644 (file)
@@ -48,7 +48,7 @@ static char copyright[] =
 #include "dhcpd.h"
 
 static struct host_decl *hosts;
-static struct hash_table *subnet_hash;
+static struct subnet *subnets;
 static struct hash_table *lease_uid_hash;
 static struct hash_table *lease_ip_addr_hash;
 static struct hash_table *lease_hw_addr_hash;
@@ -98,12 +98,10 @@ void new_address_range (low, high, netmask)
        struct lease *address_range, *lp, *plp;
        struct subnet *subnet;
        struct iaddr net;
-       int i, max;
+       int min, max, i;
        char lowbuf [16], highbuf [16], netbuf [16];
 
        /* Initialize the hash table if it hasn't been done yet. */
-       if (!subnet_hash)
-               subnet_hash = new_hash ();
        if (!lease_uid_hash)
                lease_uid_hash = new_hash ();
        if (!lease_ip_addr_hash)
@@ -130,32 +128,40 @@ void new_address_range (low, high, netmask)
                subnet -> net = net;
                subnet -> netmask = netmask;
                subnet -> leases = (struct lease *)0;
+               subnet -> last_lease = (struct lease *)0;
+               subnet -> next = (struct subnet *)0;
+               subnet -> default_lease_time = default_lease_time;
+               subnet -> max_lease_time = max_lease_time;
                enter_subnet (subnet);
        }
 
        /* Get the high and low host addresses... */
        max = host_addr (high, netmask);
-       i = host_addr (low, netmask);
+       min = host_addr (low, netmask);
 
        /* Allow range to be specified high-to-low as well as low-to-high. */
-       if (i > max) {
-               max = i;
-               i = host_addr (high, netmask);
+       if (min > max) {
+               max = min;
+               min = host_addr (high, netmask);
        }
 
        /* Get a lease structure for each address in the range. */
-       address_range = new_leases (max - i + 1, "new_address_range");
+       address_range = new_leases (max - min + 1, "new_address_range");
        if (!address_range) {
                strcpy (lowbuf, piaddr (low));
                strcpy (highbuf, piaddr (high));
                error ("No memory for address range %s-%s.", lowbuf, highbuf);
        }
-       memset (address_range, 0, (sizeof *address_range) * (max - i + 1));
+       memset (address_range, 0, (sizeof *address_range) * (max - min + 1));
+
+       /* Fill in the last lease if it hasn't been already... */
+       if (!subnet -> last_lease)
+               subnet -> last_lease = &address_range [0];
 
        /* Fill out the lease structures with some minimal information. */
-       for (; i <= max; i++) {
+       for (i = 0; i < max - min + 1; i++) {
                address_range [i].ip_addr =
-                       ip_addr (subnet -> net, subnet -> netmask, i);
+                       ip_addr (subnet -> net, subnet -> netmask, i + min);
                address_range [i].starts =
                        address_range [i].timestamp = MIN_TIME;
                address_range [i].ends = MIN_TIME;
@@ -200,13 +206,16 @@ void new_address_range (low, high, netmask)
        }
 }
 
-struct subnet *find_subnet (subnet)
-       struct iaddr subnet;
+struct subnet *find_subnet (addr)
+       struct iaddr addr;
 {
        struct subnet *rv;
 
-       return (struct subnet *)hash_lookup (subnet_hash,
-                                            (char *)subnet.iabuf, subnet.len);
+       for (rv = subnets; rv; rv = rv -> next) {
+               if (addr_eq (subnet_number (addr, rv -> netmask), rv -> net))
+                       return rv;
+       }
+       return (struct subnet *)0;
 }
 
 /* Enter a new subnet into the subnet hash. */
@@ -214,8 +223,9 @@ struct subnet *find_subnet (subnet)
 void enter_subnet (subnet)
        struct subnet *subnet;
 {
-       add_hash (subnet_hash, (char *)subnet -> net.iabuf,
-                 subnet -> net.len, (unsigned char *)subnet);
+       /* XXX Sort the nets into a balanced tree to make searching quicker. */
+       subnet -> next = subnets;
+       subnets = subnet;
 }
        
 /* Enter a lease into the system.   This is called by the parser each
@@ -259,6 +269,11 @@ void supersede_lease (comp, lease)
        struct subnet *parent;
        struct lease *lp;
 
+printf ("Supersede_lease:\n");
+print_lease (comp);
+print_lease (lease);
+printf ("\n");
+
        /* If the existing lease hasn't expired and has a different
           unique identifier or, if it doesn't have a unique
           identifier, a different hardware address, then the two
@@ -290,7 +305,9 @@ void supersede_lease (comp, lease)
                                enter_uid = 1;
                        }
                        free (comp -> uid);
-               }
+               } else
+                       enter_uid = 1;
+
                if (comp -> hardware_addr.htype &&
                    ((comp -> hardware_addr.hlen !=
                      lease -> hardware_addr.hlen) ||
@@ -303,7 +320,8 @@ void supersede_lease (comp, lease)
                                           comp -> hardware_addr.haddr,
                                           comp -> hardware_addr.hlen);
                        enter_hwaddr = 1;
-               }
+               } else if (!comp -> hardware_addr.htype)
+                       enter_hwaddr = 1;
 
                /* Copy the data files, but not the linkages. */
                comp -> starts = lease -> starts;
@@ -317,16 +335,16 @@ void supersede_lease (comp, lease)
 
                /* Record the lease in the uid hash if necessary. */
                if (enter_uid && lease -> uid) {
-                       add_hash (lease_uid_hash, lease -> uid,
-                                 lease -> uid_len, (unsigned char *)lease);
+                       add_hash (lease_uid_hash, comp -> uid,
+                                 comp -> uid_len, (unsigned char *)comp);
                }
 
                /* Record it in the hardware address hash if necessary. */
                if (enter_hwaddr && lease -> hardware_addr.htype) {
                        add_hash (lease_hw_addr_hash,
-                                 lease -> hardware_addr.haddr,
-                                 lease -> hardware_addr.hlen,
-                                 (unsigned char *)lease);
+                                 comp -> hardware_addr.haddr,
+                                 comp -> hardware_addr.hlen,
+                                 (unsigned char *)comp);
                }
 
                /* Remove the lease from its current place in the list. */
@@ -338,6 +356,9 @@ void supersede_lease (comp, lease)
                if (comp -> next) {
                        comp -> next -> prev = comp -> prev;
                }
+               if (comp -> contain -> last_lease == comp) {
+                       comp -> contain -> last_lease = comp -> prev;
+               }
 
                /* Find the last insertion point... */
                if (comp == comp -> contain -> insertion_point ||
@@ -351,18 +372,20 @@ void supersede_lease (comp, lease)
                        /* Nothing on the list yet?    Just make comp the
                           head of the list. */
                        comp -> contain -> leases = comp;
-               } else if (lp -> ends <= comp -> ends) {
+                       comp -> contain -> last_lease = comp;
+               } else if (lp -> ends > comp -> ends) {
                        /* Skip down the list until we run out of list
                           or find a place for comp. */
-                       while (lp -> next && lp -> ends < comp -> ends) {
+                       while (lp -> next && lp -> ends > comp -> ends) {
                                lp = lp -> next;
                        }
-                       if (lp -> ends < comp -> ends) {
+                       if (lp -> ends > comp -> ends) {
                                /* If we ran out of list, put comp
                                   at the end. */
                                lp -> next = comp;
                                comp -> prev = lp;
                                comp -> next = (struct lease *)0;
+                               comp -> contain -> last_lease = comp;
                        } else {
                                /* If we didn't, put it between lp and
                                   the previous item on the list. */
@@ -372,12 +395,12 @@ void supersede_lease (comp, lease)
                                lp -> prev = comp;
                        }
                } else {
-                       /* Skip ip the list until we run out of list
+                       /* Skip up the list until we run out of list
                           or find a place for comp. */
-                       while (lp -> prev && lp -> ends > comp -> ends) {
+                       while (lp -> prev && lp -> ends < comp -> ends) {
                                lp = lp -> prev;
                        }
-                       if (lp -> ends > comp -> ends) {
+                       if (lp -> ends < comp -> ends) {
                                /* If we ran out of list, put comp
                                   at the beginning. */
                                lp -> prev = comp;
@@ -397,6 +420,18 @@ void supersede_lease (comp, lease)
        }
 }
 
+/* Release the specified lease and re-hash it as appropriate. */
+
+void release_lease (lease)
+       struct lease *lease;
+{
+       struct lease lt;
+
+       lease -> ends = 0;
+       lt = *lease;
+       supersede_lease (lease, &lt);
+}
+
 /* Locate the lease associated with a given IP address... */
 
 struct lease *find_lease_by_ip_addr (addr)
@@ -417,3 +452,29 @@ struct lease *find_lease_by_uid (uid, len)
        return lease;
 }
 
+struct lease *find_lease_by_hw_addr (hwaddr, hwlen)
+       unsigned char *hwaddr;
+       int hwlen;
+{
+       struct lease *lease = (struct lease *)hash_lookup (lease_hw_addr_hash,
+                                                          hwaddr, hwlen);
+       return lease;
+}
+
+void dump_subnets ()
+{
+       struct lease *l;
+       struct subnet *s;
+       int i;
+
+       for (s = subnets; s; s = s -> next) {
+               printf ("Subnet %s", piaddr (s -> net));
+               printf (" netmask %s\n",
+                       piaddr (s -> netmask));
+               for (l = s -> leases; l; l = l -> next) {
+                       print_lease (l);
+               }
+               printf ("Last Lease:\n");
+               print_lease (s -> last_lease);
+       }
+}
index 75bfc5e5dd9fe7a30e7eef421ade871de3dc3257..f9fa44d384c8a113ab3cce4c62fcff63fd47de20 100644 (file)
@@ -94,8 +94,6 @@ void parse_option_buffer (packet, buffer, length)
        int len;
        int code;
 
-printf ("parse_option_buffer (%x, %x, %d)\n",
-(unsigned long)packet, (unsigned long)buffer, length);
        for (s = buffer; *s != DHO_END && s < end; ) {
                code = s [0];
                /* Pad options don't have a length - just skip them. */
@@ -126,8 +124,6 @@ printf ("parse_option_buffer (%x, %x, %d)\n",
                        t [len] = 0;
                        packet -> options [code].len = len;
                        packet -> options [code].data = t;
-printf ("%s=%s\n", dhcp_options [code].name,
-pretty_print_option (code, t, len));
                } else {
                        /* If it's a repeat, concatenate it to whatever
                           we last saw.   This is really only required
index 55d17159593c031de5ba58e3fc25d0e9b51aa801..4686e2e33e54f91ef883bf7a0ad1825143723175 100644 (file)
@@ -55,13 +55,46 @@ char *print_hw_addr (htype, hlen, data)
        char *s;
        int i;
 
-       s = habuf;
-       for (i = 0; i < hlen; i++) {
-               sprintf (s, "%x", data [i]);
-               s += strlen (s);
-               *s++ = ':';
+       if (htype == 0 || hlen == 0) {
+               strcpy (habuf, "<null>");
+       } else {
+               s = habuf;
+               for (i = 0; i < hlen; i++) {
+                       sprintf (s, "%x", data [i]);
+                       s += strlen (s);
+                       *s++ = ':';
+               }
+               *--s = 0;
        }
-       *--s = 0;
        return habuf;
 }
 
+void print_lease (lease)
+       struct lease *lease;
+{
+       struct tm *t;
+       char tbuf [32];
+
+       printf ("  Lease %s",
+               piaddr (lease -> ip_addr));
+       
+       t = gmtime (&lease -> starts);
+       strftime (tbuf, sizeof tbuf, "%D %H:%M:%S", t);
+       printf ("  start %s", tbuf);
+       
+       t = gmtime (&lease -> ends);
+       strftime (tbuf, sizeof tbuf, "%D %H:%M:%S", t);
+       printf ("  end %s", tbuf);
+       
+       t = gmtime (&lease -> timestamp);
+       strftime (tbuf, sizeof tbuf, "%D %H:%M:%S", t);
+       printf ("  stamp %s\n", tbuf);
+       
+       printf ("    hardware addr = %s",
+               print_hw_addr (lease -> hardware_addr.htype,
+                              lease -> hardware_addr.hlen,
+                              lease -> hardware_addr.haddr));
+       printf ("  host %s  state %x\n",
+               lease -> host ? lease -> host -> name : "<none>",
+               lease -> state);
+}      
index 3a013cf07eca976466a33f74a7e60ab4c660dece..c69e68ccc1f2cc9a793dde6a8db31bcfc7665e0a 100644 (file)
@@ -184,6 +184,9 @@ void dispatch ()
                /* Wait for a packet or a timeout... XXX */
                count = select (max + 1, &r, &w, &x, (struct timeval *)0);
 
+               /* Get the current time... */
+               GET_TIME (&cur_time);
+
                /* Not likely to be transitory... */
                if (count < 0)
                        error ("select: %m");
index 33e583186c9b5e2d58b69ab8dbbca931d34cde11..28a9f65e3e8da00a108a3c200ee775e3a4375cfd 100644 (file)
--- a/conflex.c
+++ b/conflex.c
@@ -274,6 +274,8 @@ static int intern (atom, dfv)
              case 'c':
                if (!strcasecmp (atom + 1, "lass"))
                        return CLASS;
+               if (!strcasecmp (atom + 1, "iaddr"))
+                       return CIADDR;
                break;
              case 'e':
                if (!strcasecmp (atom + 1, "thernet"))
@@ -287,6 +289,10 @@ static int intern (atom, dfv)
                if (!strcasecmp (atom + 1, "ixed-address"))
                        return FIXED_ADDR;
                break;
+             case 'g':
+               if (!strcasecmp (atom + 1, "iaddr"))
+                       return GIADDR;
+               break;
              case 'h':
                if (!strcasecmp (atom + 1, "ost"))
                        return HOST;
@@ -312,6 +318,8 @@ static int intern (atom, dfv)
              case 's':
                if (!strcasecmp (atom + 1, "tarts"))
                        return STARTS;
+               if (!strcasecmp (atom + 1, "iaddr"))
+                       return SIADDR;
                break;
              case 't':
                if (!strcasecmp (atom + 1, "timestamp"))
@@ -321,6 +329,10 @@ static int intern (atom, dfv)
                if (!strcasecmp (atom + 1, "id"))
                        return UID;
                break;
+             case 'y':
+               if (!strcasecmp (atom + 1, "iaddr"))
+                       return YIADDR;
+               break;
        }
        return dfv;
 }
index 7335de6fe95bdc25e7c38d63c48c1b5899eebc10..1be52bb9af07916702a21727591e3bde7b5e0c64 100644 (file)
@@ -234,6 +234,22 @@ void parse_host_decl (cfile, bc, decl)
              case OPTION:
                parse_option_decl (cfile, bc, decl);
                break;
+             case CIADDR:
+               decl -> ciaddr =
+                       tree_cache (parse_ip_addr_or_hostname (cfile, bc, 0));
+               break;
+             case YIADDR:
+               decl -> yiaddr =
+                       tree_cache (parse_ip_addr_or_hostname (cfile, bc, 0));
+               break;
+             case SIADDR:
+               decl -> siaddr =
+                       tree_cache (parse_ip_addr_or_hostname (cfile, bc, 0));
+               break;
+             case GIADDR:
+               decl -> giaddr =
+                       tree_cache (parse_ip_addr_or_hostname (cfile, bc, 0));
+               break;
              default:
                parse_warn ("expecting a dhcp option declaration.");
                skip_to_semi (cfile);
index 0a66c41d7b6bdb493add2af002ed3cca8afea61a..c9d9e64dbb95bfe69c394f39e294718ddf87acef 100644 (file)
@@ -189,11 +189,51 @@ int main (argc, argv, envp)
 
                        cons_options ((struct packet *)0,
                                      &outgoing, &decl, bufs);
-                       memset (&raw.ciaddr, 0, sizeof raw.ciaddr);
-                       memset (&raw.yiaddr, 0, sizeof raw.ciaddr);
-                       memset (&raw.siaddr, 0, sizeof raw.ciaddr);
-                       memset (&raw.giaddr, 0, sizeof raw.ciaddr);
-                       
+
+                       if (decl.ciaddr) {
+                               if (tree_evaluate (decl.ciaddr) != 4)
+                                       warn ("ciaddr is more"
+                                             " than one address");
+                               else
+                                       memcpy (&raw.ciaddr,
+                                               decl.ciaddr -> value,
+                                               decl.ciaddr -> len);
+                       } else
+                               memset (&raw.ciaddr, 0, sizeof raw.ciaddr);
+
+                       if (decl.yiaddr) {
+                               if (tree_evaluate (decl.yiaddr) != 4)
+                                       warn ("yiaddr is more"
+                                             " than one address");
+                               else
+                                       memcpy (&raw.yiaddr,
+                                               decl.yiaddr -> value,
+                                               decl.yiaddr -> len);
+                       } else
+                               memset (&raw.yiaddr, 0, sizeof raw.yiaddr);
+
+                       if (decl.siaddr) {
+                               if (tree_evaluate (decl.siaddr) != 4)
+                                       warn ("siaddr is more"
+                                             " than one address");
+                               else
+                                       memcpy (&raw.siaddr,
+                                               decl.siaddr -> value,
+                                               decl.siaddr -> len);
+                       } else
+                               memset (&raw.siaddr, 0, sizeof raw.siaddr);
+
+                       if (decl.giaddr) {
+                               if (tree_evaluate (decl.giaddr) != 4)
+                                       warn ("giaddr is more"
+                                             " than one address");
+                               else
+                                       memcpy (&raw.giaddr,
+                                               decl.giaddr -> value,
+                                               decl.giaddr -> len);
+                       } else
+                               memset (&raw.giaddr, 0, sizeof raw.giaddr);
+
                        raw.xid = xid++;
                        raw.xid = htons (raw.xid);
                        raw.secs = 0;
diff --git a/dhcp.c b/dhcp.c
index fa49eccc952ad7968cc264e58737e5cc3873623d..640c726f054016ec74bb769b587f33261c9f8bc1 100644 (file)
--- a/dhcp.c
+++ b/dhcp.c
@@ -49,5 +49,205 @@ static char copyright[] =
 void dhcp (packet)
        struct packet *packet;
 {
+       struct lease *uid_lease, *ip_lease, *hw_lease, *lease;
+       struct iaddr cip;
+       struct lease lt;
+       TIME lease_time;
+
        dump_packet (packet);
+
+       /* Try to find a lease that's been assigned to the specified
+          unique client identifier. */
+       if (packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len)
+               uid_lease =
+                       find_lease_by_uid (packet -> options
+                                          [DHO_DHCP_CLIENT_IDENTIFIER].data,
+                                          packet -> options
+                                          [DHO_DHCP_CLIENT_IDENTIFIER].len);
+       else
+               uid_lease = (struct lease *)0;
+
+       /* Try to find a lease that's been attached to the client's
+          hardware address... */
+       hw_lease = find_lease_by_hw_addr (packet -> raw -> chaddr,
+                                         packet -> raw -> hlen);
+
+       /* Try to find a lease that's been allocated to the client's
+          IP address. */
+       if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len &&
+           packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len
+           <= sizeof cip.iabuf) {
+               cip.len = packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len;
+               memcpy (cip.iabuf,
+                       packet -> options [DHO_DHCP_REQUESTED_ADDRESS].data,
+                       packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len);
+               memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4);
+               ip_lease = find_lease_by_ip_addr (cip);
+       } else
+               ip_lease = (struct lease *)0;
+
+       printf ("First blush:\n");
+       if (ip_lease) {
+               printf ("ip_lease: ");
+               print_lease (ip_lease);
+       }
+       if (hw_lease) {
+               printf ("hw_lease: ");
+               print_lease (hw_lease);
+       }
+       if (uid_lease) {
+               printf ("uid_lease: ");
+               print_lease (uid_lease);
+       }
+
+       /* Toss extra pointers to the same lease... */
+       if (ip_lease == hw_lease)
+               ip_lease = (struct lease *)0;
+       if (hw_lease == uid_lease)
+               hw_lease = (struct lease *)0;
+       if (ip_lease == uid_lease)
+               ip_lease = (struct lease *)0;
+
+       printf ("Second blush:\n");
+       if (ip_lease) {
+               printf ("ip_lease: ");
+               print_lease (ip_lease);
+       }
+       if (hw_lease) {
+               printf ("hw_lease: ");
+               print_lease (hw_lease);
+       }
+       if (uid_lease) {
+               printf ("uid_lease: ");
+               print_lease (uid_lease);
+       }
+
+       /* If we got an ip address lease, make sure it isn't assigned to
+          some *other* client!   If it was assigned to this client, we'd
+          have zeroed it out above, so the only way we can take it at this
+          point is if some other client had it but it's timed out, or if no
+          other client has ever had it. */
+       if (ip_lease &&
+           ip_lease -> ends >= cur_time)
+               ip_lease = (struct lease *)0;
+
+       /* Now eliminate leases that are on the wrong subnet... */
+       if (ip_lease && packet -> subnet != ip_lease -> contain) {
+               release_lease (ip_lease);
+               ip_lease = (struct lease *)0;
+       }
+       if (uid_lease && packet -> subnet != uid_lease -> contain) {
+               release_lease (uid_lease);
+               uid_lease = (struct lease *)0;
+       }
+       if (hw_lease && packet -> subnet != hw_lease -> contain) {
+               release_lease (hw_lease);
+               hw_lease = (struct lease *)0;
+       }
+
+       printf ("Third blush:\n");
+       if (ip_lease) {
+               printf ("ip_lease: ");
+               print_lease (ip_lease);
+       }
+       if (hw_lease) {
+               printf ("hw_lease: ");
+               print_lease (hw_lease);
+       }
+       if (uid_lease) {
+               printf ("uid_lease: ");
+               print_lease (uid_lease);
+       }
+
+       /* At this point, if ip_lease is nonzero, we can assign it to
+          this client. */
+       lease = ip_lease;
+
+       /* If we got a lease that matched the client identifier, we may want
+          to use it, but if we already have a lease we like, we must free
+          the lease that matched the client identifier. */
+       if (uid_lease) {
+               if (lease) {
+                       release_lease (uid_lease);
+               } else
+                       lease = uid_lease;
+       }
+
+       /* The lease that matched the hardware address is treated likewise. */
+       if (hw_lease) {
+               if (lease) {
+                       release_lease (hw_lease);
+               } else
+                       lease = hw_lease;
+       }
+
+       /* If we didn't find a lease, try to allocate one... */
+       if (!lease) {
+               lease = packet -> subnet -> last_lease;
+
+               /* If there are no leases in that subnet that have
+                  expired, we have nothing to offer this client. */
+               if (lease -> ends >= cur_time) {
+                       note ("no free leases on subnet %s",
+                             piaddr (packet -> subnet -> net));
+                       return;
+               }
+               lease -> host = (struct host_decl *)0;
+       }
+
+       /* At this point, we have a lease that we can offer the client.
+          Now we construct a lease structure that contains what we want,
+          and call supersede_lease to do the right thing with it. */
+
+       memset (&lt, 0, sizeof lt);
+
+       /* Use the ip address of the lease that we finally found in
+          the database. */
+       lt.ip_addr = lease -> ip_addr;
+
+       /* Start now. */
+       lt.starts = cur_time;
+
+       /* Figure out how long a lease to assign. */
+       if (packet -> options [DHO_DHCP_LEASE_TIME].len == 4) {
+               lease_time = getULong (packet ->
+                                      options [DHO_DHCP_LEASE_TIME].data);
+
+               /* Don't let the client ask for a longer lease than
+                  is supported for this subnet. */
+               if (lease_time > packet -> subnet -> max_lease_time)
+                       lease_time = packet -> subnet -> max_lease_time;
+       } else
+               lease_time = packet -> subnet -> default_lease_time;
+       lt.ends = cur_time + lease_time;
+
+       lt.timestamp = cur_time;
+
+       /* Record the uid, if given... */
+       if (packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len) {
+               lt.uid_len =
+                       packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len;
+               lt.uid = packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].data;
+               packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].data =
+                       (unsigned char *)0;
+               packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len = 0;
+       }
+
+       /* Record the hardware address, if given... */
+       lt.hardware_addr.hlen = packet -> raw -> hlen;
+       lt.hardware_addr.htype = packet -> raw -> htype;
+       memcpy (lt.hardware_addr.haddr, packet -> raw -> chaddr,
+               packet -> raw -> hlen);
+
+       lt.host = lease -> host; /* XXX */
+       lt.contain = lease -> contain;
+
+       /* Record the transaction id... */
+       lt.xid = packet -> raw -> xid;
+
+       /* Install the new information about this lease in the database. */
+       supersede_lease (lease, &lt);
+
+       /* Send a response to the client... */
+       dump_subnets ();
 }
diff --git a/dhcpd.c b/dhcpd.c
index b9e527c862e7b885b9cbf5c065566160b7324f3c..159d3b85c93da732371665f5df6c425e91800f82 100644 (file)
--- a/dhcpd.c
+++ b/dhcpd.c
@@ -50,7 +50,10 @@ static char copyright[] =
 static void usage PROTO ((void));
 
 TIME cur_time;
+TIME default_lease_time = 43200; /* 12 hours... */
+TIME max_lease_time = 86400; /* 24 hours... */
 
+struct subnet *local_subnet;
 u_int32_t *server_addrlist;
 int server_addrcount;
 u_int16_t server_port;
@@ -63,6 +66,7 @@ int main (argc, argv, envp)
        int port = 0;
        int i;
        struct sockaddr_in name;
+       struct iaddr taddr;
        u_int32_t *addrlist = (u_int32_t *)0;
        int addrcount = 0;
        struct tree *addrtree = (struct tree *)0;
@@ -148,7 +152,23 @@ int main (argc, argv, envp)
        }
 #endif
 
+       taddr.len = 0;
        server_addrlist = get_interface_list (&server_addrcount);
+       for (i = 0; i < server_addrcount; i++) {
+               struct sockaddr_in foo;
+               foo.sin_addr.s_addr = server_addrlist [i];
+               printf ("Address %d: %s\n", i, inet_ntoa (foo.sin_addr));
+
+               if (server_addrlist [i] != htonl (INADDR_LOOPBACK)) {
+                       if (taddr.len) {
+                               error ("dhcpd currently does not support "
+                                      "multiple interfaces");
+                       }
+                       taddr.len = 4;
+                       memcpy (taddr.iabuf, &server_addrlist [i], 4);
+                       local_subnet = find_subnet (taddr);
+               }
+       }
 
        /* Listen on the specified (or default) port on each specified
           (or default) IP address. */
@@ -164,6 +184,8 @@ int main (argc, argv, envp)
                close (i);
        }
 
+       dump_subnets ();
+
        /* Receive packets and dispatch them... */
        dispatch ();
 
@@ -191,6 +213,7 @@ void do_packet (packbuf, len, from_port, from, sock)
 {
        struct packet *tp;
        struct dhcp_packet *tdp;
+       struct iaddr ia;
 
        if (!(tp = new_packet ("do_packet")))
                return;
@@ -205,12 +228,29 @@ void do_packet (packbuf, len, from_port, from, sock)
        tp -> client_port = from_port;
        tp -> client_addr = from;
        tp -> client_sock = sock;
-       parse_options (tp);
-       if (tp -> options_valid &&
-           tp -> options [DHO_DHCP_MESSAGE_TYPE].data)
-               dhcp (tp);
-       else
-               bootp (tp);
+       
+       /* If this came through a gateway, find the corresponding subnet... */
+       if (tp -> raw -> giaddr.s_addr) {
+               ia.len = 4;
+               memcpy (ia.iabuf, &tp -> raw -> giaddr, 4);
+               tp -> subnet = find_subnet (ia);
+       } else {
+               tp -> subnet = local_subnet;
+       }
+
+       /* If the subnet from whence this packet came is unknown to us,
+          drop it on the floor... */
+       if (!tp -> subnet)
+               note ("Packet from unknown subnet: %s",
+                     inet_ntoa (tp -> raw -> giaddr));
+       else {
+               parse_options (tp);
+               if (tp -> options_valid &&
+                   tp -> options [DHO_DHCP_MESSAGE_TYPE].data)
+                       dhcp (tp);
+               else
+                       bootp (tp);
+       }
 }
 
 void dump_packet (tp)
index 10d66a37f7e53857f6616b5e09f091b8995f4a50..bc8a1d7760ec6ab76d0beb135493f17e693ee675 100644 (file)
@@ -1,4 +1,5 @@
-range 204.254.239.11 204.254.239.254 255.255.255.0;
+range 204.254.239.11 204.254.239.17 255.255.255.0;
+range 204.254.240.11 204.254.240.12 255.255.255.0;
 
 host minuet
        hardware ethernet 08:00:2b:35:0c:18
diff --git a/dhcpd.h b/dhcpd.h
index 655b57ebec7e9530dac26e8035884d35677aa28f..81d5ccccaaa5d9add0dc156d96a28962e40ddadb 100644 (file)
--- a/dhcpd.h
+++ b/dhcpd.h
@@ -53,6 +53,7 @@
 #include <stdlib.h>
 #include <sys/stat.h>
 #include <ctype.h>
+#include <time.h>
 
 #include "dhcp.h"
 #include "cdefs.h"
@@ -70,6 +71,7 @@ struct packet {
        int client_port;
        struct iaddr client_addr;
        int client_sock;
+       struct subnet *subnet;
        struct {
                int len;
                unsigned char *data;
@@ -91,6 +93,10 @@ struct host_decl {
        char *filename;
        char *server_name;      
        struct tree_cache *fixed_addr;
+       struct tree_cache *ciaddr;
+       struct tree_cache *yiaddr;
+       struct tree_cache *siaddr;
+       struct tree_cache *giaddr;
        struct tree_cache *options [256];
 };
 
@@ -106,13 +112,18 @@ struct lease {
        struct subnet *contain;
        struct hardware hardware_addr;
        int state;
+       int xid;
 };
 
 struct subnet {
+       struct subnet *next;
        struct iaddr net;
        struct iaddr netmask;
+       TIME default_lease_time;
+       TIME max_lease_time;
        struct lease *leases;
        struct lease *insertion_point;
+       struct lease *last_lease;
 };
 
 /* Bitmask of dhcp option codes. */
@@ -162,6 +173,8 @@ int parse_warn PROTO ((char *, ...));
 
 /* dhcpd.c */
 TIME cur_time;
+TIME default_lease_time;
+TIME max_lease_time;
 extern u_int32_t *server_addrlist;
 extern int server_addrcount;
 extern u_int16_t server_port;
@@ -225,8 +238,11 @@ extern struct subnet *find_subnet (struct iaddr);
 void enter_subnet (struct subnet *);
 void enter_lease PROTO ((struct lease *));
 void supersede_lease PROTO ((struct lease *, struct lease *));
+void release_lease PROTO ((struct lease *));
 struct lease *find_lease_by_uid PROTO ((unsigned char *, int));
+struct lease *find_lease_by_hw_addr PROTO ((unsigned char *, int));
 struct lease *find_lease_by_ip_addr PROTO ((struct iaddr));
+void dump_subnets PROTO ((void));
 
 /* alloc.c */
 VOIDPTR dmalloc PROTO ((int, char *));
@@ -251,6 +267,7 @@ void free_tree PROTO ((struct tree *, char *));
 
 /* print.c */
 char *print_hw_addr PROTO ((int, int, unsigned char *));
+void print_lease PROTO ((struct lease *));
 
 /* socket.c */
 u_int32_t *get_interface_list PROTO ((int *));
index f04fae5be0fe2f79e28093dff5b7c370edf91196..e3132f995f0d6a9f9ed37c6259984002b3c9e10b 100644 (file)
 #define LEASE          271
 #define RANGE          272
 #define PACKET         273
-#define LAST_TOKEN     PACKET
+#define CIADDR         274
+#define YIADDR         275
+#define SIADDR         276
+#define GIADDR         277
+#define LAST_TOKEN     GIADDR
 
 #define is_identifier(x)       ((x) >= FIRST_TOKEN &&  \
                                 (x) <= LAST_TOKEN &&   \
diff --git a/hash.c b/hash.c
index 8bc724e7aa298545beb8e8923e1927bf5cdc47f7..cf15ba315cf28425cd80f554a206198bcb9b3cc4 100644 (file)
--- a/hash.c
+++ b/hash.c
@@ -103,6 +103,7 @@ void add_hash (table, name, len, pointer)
        bp -> name = name;
        bp -> value = pointer;
        bp -> next = table -> buckets [hashno];
+       bp -> len = len;
        table -> buckets [hashno] = bp;
 }
 
@@ -140,10 +141,11 @@ unsigned char *hash_lookup (table, name, len)
        struct hash_bucket *bp;
 
        if (len) {
-               for (bp = table -> buckets [hashno]; bp; bp = bp -> next)
+               for (bp = table -> buckets [hashno]; bp; bp = bp -> next) {
                        if (len == bp -> len
                            && !memcmp (bp -> name, name, len))
                                return bp -> value;
+               }
        } else {
                for (bp = table -> buckets [hashno]; bp; bp = bp -> next)
                        if (!strcmp (bp -> name, name))
index 655b57ebec7e9530dac26e8035884d35677aa28f..81d5ccccaaa5d9add0dc156d96a28962e40ddadb 100644 (file)
@@ -53,6 +53,7 @@
 #include <stdlib.h>
 #include <sys/stat.h>
 #include <ctype.h>
+#include <time.h>
 
 #include "dhcp.h"
 #include "cdefs.h"
@@ -70,6 +71,7 @@ struct packet {
        int client_port;
        struct iaddr client_addr;
        int client_sock;
+       struct subnet *subnet;
        struct {
                int len;
                unsigned char *data;
@@ -91,6 +93,10 @@ struct host_decl {
        char *filename;
        char *server_name;      
        struct tree_cache *fixed_addr;
+       struct tree_cache *ciaddr;
+       struct tree_cache *yiaddr;
+       struct tree_cache *siaddr;
+       struct tree_cache *giaddr;
        struct tree_cache *options [256];
 };
 
@@ -106,13 +112,18 @@ struct lease {
        struct subnet *contain;
        struct hardware hardware_addr;
        int state;
+       int xid;
 };
 
 struct subnet {
+       struct subnet *next;
        struct iaddr net;
        struct iaddr netmask;
+       TIME default_lease_time;
+       TIME max_lease_time;
        struct lease *leases;
        struct lease *insertion_point;
+       struct lease *last_lease;
 };
 
 /* Bitmask of dhcp option codes. */
@@ -162,6 +173,8 @@ int parse_warn PROTO ((char *, ...));
 
 /* dhcpd.c */
 TIME cur_time;
+TIME default_lease_time;
+TIME max_lease_time;
 extern u_int32_t *server_addrlist;
 extern int server_addrcount;
 extern u_int16_t server_port;
@@ -225,8 +238,11 @@ extern struct subnet *find_subnet (struct iaddr);
 void enter_subnet (struct subnet *);
 void enter_lease PROTO ((struct lease *));
 void supersede_lease PROTO ((struct lease *, struct lease *));
+void release_lease PROTO ((struct lease *));
 struct lease *find_lease_by_uid PROTO ((unsigned char *, int));
+struct lease *find_lease_by_hw_addr PROTO ((unsigned char *, int));
 struct lease *find_lease_by_ip_addr PROTO ((struct iaddr));
+void dump_subnets PROTO ((void));
 
 /* alloc.c */
 VOIDPTR dmalloc PROTO ((int, char *));
@@ -251,6 +267,7 @@ void free_tree PROTO ((struct tree *, char *));
 
 /* print.c */
 char *print_hw_addr PROTO ((int, int, unsigned char *));
+void print_lease PROTO ((struct lease *));
 
 /* socket.c */
 u_int32_t *get_interface_list PROTO ((int *));
index f04fae5be0fe2f79e28093dff5b7c370edf91196..e3132f995f0d6a9f9ed37c6259984002b3c9e10b 100644 (file)
 #define LEASE          271
 #define RANGE          272
 #define PACKET         273
-#define LAST_TOKEN     PACKET
+#define CIADDR         274
+#define YIADDR         275
+#define SIADDR         276
+#define GIADDR         277
+#define LAST_TOKEN     GIADDR
 
 #define is_identifier(x)       ((x) >= FIRST_TOKEN &&  \
                                 (x) <= LAST_TOKEN &&   \
diff --git a/inet.c b/inet.c
index fa25efc1ae3ac797a77212455258cf26baef0167..ce63a2b4d856f12e1f707cae8af10c26a94e1198 100644 (file)
--- a/inet.c
+++ b/inet.c
@@ -87,7 +87,7 @@ struct iaddr ip_addr (subnet, mask, host_address)
        j = rv.len - sizeof habuf;
        for (i = sizeof habuf - 1; i >= 0; i--) {
                if (mask.iabuf [i + j]) {
-                       if (habuf [i] > ~mask.iabuf [i + j]) {
+                       if (habuf [i] > (mask.iabuf [i + j] ^ 0xFF)) {
                                rv.len = 0;
                                return rv;
                        }
@@ -97,10 +97,10 @@ struct iaddr ip_addr (subnet, mask, host_address)
                                        return rv;
                                }
                        }
-                       rv.iabuf [i + j] &= habuf [i];
+                       rv.iabuf [i + j] |= habuf [i];
                        break;
-               }
-               rv.iabuf [i + j] = habuf [i];
+               } else
+                       rv.iabuf [i + j] = habuf [i];
        }
                
        return rv;
index 21b1c010f9485b8c9751d9b65bc1c68091cbbc71..13bf3492f9cec9be5a27598d6bba9369cd23a442 100644 (file)
--- a/memory.c
+++ b/memory.c
@@ -48,7 +48,7 @@ static char copyright[] =
 #include "dhcpd.h"
 
 static struct host_decl *hosts;
-static struct hash_table *subnet_hash;
+static struct subnet *subnets;
 static struct hash_table *lease_uid_hash;
 static struct hash_table *lease_ip_addr_hash;
 static struct hash_table *lease_hw_addr_hash;
@@ -98,12 +98,10 @@ void new_address_range (low, high, netmask)
        struct lease *address_range, *lp, *plp;
        struct subnet *subnet;
        struct iaddr net;
-       int i, max;
+       int min, max, i;
        char lowbuf [16], highbuf [16], netbuf [16];
 
        /* Initialize the hash table if it hasn't been done yet. */
-       if (!subnet_hash)
-               subnet_hash = new_hash ();
        if (!lease_uid_hash)
                lease_uid_hash = new_hash ();
        if (!lease_ip_addr_hash)
@@ -130,32 +128,40 @@ void new_address_range (low, high, netmask)
                subnet -> net = net;
                subnet -> netmask = netmask;
                subnet -> leases = (struct lease *)0;
+               subnet -> last_lease = (struct lease *)0;
+               subnet -> next = (struct subnet *)0;
+               subnet -> default_lease_time = default_lease_time;
+               subnet -> max_lease_time = max_lease_time;
                enter_subnet (subnet);
        }
 
        /* Get the high and low host addresses... */
        max = host_addr (high, netmask);
-       i = host_addr (low, netmask);
+       min = host_addr (low, netmask);
 
        /* Allow range to be specified high-to-low as well as low-to-high. */
-       if (i > max) {
-               max = i;
-               i = host_addr (high, netmask);
+       if (min > max) {
+               max = min;
+               min = host_addr (high, netmask);
        }
 
        /* Get a lease structure for each address in the range. */
-       address_range = new_leases (max - i + 1, "new_address_range");
+       address_range = new_leases (max - min + 1, "new_address_range");
        if (!address_range) {
                strcpy (lowbuf, piaddr (low));
                strcpy (highbuf, piaddr (high));
                error ("No memory for address range %s-%s.", lowbuf, highbuf);
        }
-       memset (address_range, 0, (sizeof *address_range) * (max - i + 1));
+       memset (address_range, 0, (sizeof *address_range) * (max - min + 1));
+
+       /* Fill in the last lease if it hasn't been already... */
+       if (!subnet -> last_lease)
+               subnet -> last_lease = &address_range [0];
 
        /* Fill out the lease structures with some minimal information. */
-       for (; i <= max; i++) {
+       for (i = 0; i < max - min + 1; i++) {
                address_range [i].ip_addr =
-                       ip_addr (subnet -> net, subnet -> netmask, i);
+                       ip_addr (subnet -> net, subnet -> netmask, i + min);
                address_range [i].starts =
                        address_range [i].timestamp = MIN_TIME;
                address_range [i].ends = MIN_TIME;
@@ -200,13 +206,16 @@ void new_address_range (low, high, netmask)
        }
 }
 
-struct subnet *find_subnet (subnet)
-       struct iaddr subnet;
+struct subnet *find_subnet (addr)
+       struct iaddr addr;
 {
        struct subnet *rv;
 
-       return (struct subnet *)hash_lookup (subnet_hash,
-                                            (char *)subnet.iabuf, subnet.len);
+       for (rv = subnets; rv; rv = rv -> next) {
+               if (addr_eq (subnet_number (addr, rv -> netmask), rv -> net))
+                       return rv;
+       }
+       return (struct subnet *)0;
 }
 
 /* Enter a new subnet into the subnet hash. */
@@ -214,8 +223,9 @@ struct subnet *find_subnet (subnet)
 void enter_subnet (subnet)
        struct subnet *subnet;
 {
-       add_hash (subnet_hash, (char *)subnet -> net.iabuf,
-                 subnet -> net.len, (unsigned char *)subnet);
+       /* XXX Sort the nets into a balanced tree to make searching quicker. */
+       subnet -> next = subnets;
+       subnets = subnet;
 }
        
 /* Enter a lease into the system.   This is called by the parser each
@@ -259,6 +269,11 @@ void supersede_lease (comp, lease)
        struct subnet *parent;
        struct lease *lp;
 
+printf ("Supersede_lease:\n");
+print_lease (comp);
+print_lease (lease);
+printf ("\n");
+
        /* If the existing lease hasn't expired and has a different
           unique identifier or, if it doesn't have a unique
           identifier, a different hardware address, then the two
@@ -290,7 +305,9 @@ void supersede_lease (comp, lease)
                                enter_uid = 1;
                        }
                        free (comp -> uid);
-               }
+               } else
+                       enter_uid = 1;
+
                if (comp -> hardware_addr.htype &&
                    ((comp -> hardware_addr.hlen !=
                      lease -> hardware_addr.hlen) ||
@@ -303,7 +320,8 @@ void supersede_lease (comp, lease)
                                           comp -> hardware_addr.haddr,
                                           comp -> hardware_addr.hlen);
                        enter_hwaddr = 1;
-               }
+               } else if (!comp -> hardware_addr.htype)
+                       enter_hwaddr = 1;
 
                /* Copy the data files, but not the linkages. */
                comp -> starts = lease -> starts;
@@ -317,16 +335,16 @@ void supersede_lease (comp, lease)
 
                /* Record the lease in the uid hash if necessary. */
                if (enter_uid && lease -> uid) {
-                       add_hash (lease_uid_hash, lease -> uid,
-                                 lease -> uid_len, (unsigned char *)lease);
+                       add_hash (lease_uid_hash, comp -> uid,
+                                 comp -> uid_len, (unsigned char *)comp);
                }
 
                /* Record it in the hardware address hash if necessary. */
                if (enter_hwaddr && lease -> hardware_addr.htype) {
                        add_hash (lease_hw_addr_hash,
-                                 lease -> hardware_addr.haddr,
-                                 lease -> hardware_addr.hlen,
-                                 (unsigned char *)lease);
+                                 comp -> hardware_addr.haddr,
+                                 comp -> hardware_addr.hlen,
+                                 (unsigned char *)comp);
                }
 
                /* Remove the lease from its current place in the list. */
@@ -338,6 +356,9 @@ void supersede_lease (comp, lease)
                if (comp -> next) {
                        comp -> next -> prev = comp -> prev;
                }
+               if (comp -> contain -> last_lease == comp) {
+                       comp -> contain -> last_lease = comp -> prev;
+               }
 
                /* Find the last insertion point... */
                if (comp == comp -> contain -> insertion_point ||
@@ -351,18 +372,20 @@ void supersede_lease (comp, lease)
                        /* Nothing on the list yet?    Just make comp the
                           head of the list. */
                        comp -> contain -> leases = comp;
-               } else if (lp -> ends <= comp -> ends) {
+                       comp -> contain -> last_lease = comp;
+               } else if (lp -> ends > comp -> ends) {
                        /* Skip down the list until we run out of list
                           or find a place for comp. */
-                       while (lp -> next && lp -> ends < comp -> ends) {
+                       while (lp -> next && lp -> ends > comp -> ends) {
                                lp = lp -> next;
                        }
-                       if (lp -> ends < comp -> ends) {
+                       if (lp -> ends > comp -> ends) {
                                /* If we ran out of list, put comp
                                   at the end. */
                                lp -> next = comp;
                                comp -> prev = lp;
                                comp -> next = (struct lease *)0;
+                               comp -> contain -> last_lease = comp;
                        } else {
                                /* If we didn't, put it between lp and
                                   the previous item on the list. */
@@ -372,12 +395,12 @@ void supersede_lease (comp, lease)
                                lp -> prev = comp;
                        }
                } else {
-                       /* Skip ip the list until we run out of list
+                       /* Skip up the list until we run out of list
                           or find a place for comp. */
-                       while (lp -> prev && lp -> ends > comp -> ends) {
+                       while (lp -> prev && lp -> ends < comp -> ends) {
                                lp = lp -> prev;
                        }
-                       if (lp -> ends > comp -> ends) {
+                       if (lp -> ends < comp -> ends) {
                                /* If we ran out of list, put comp
                                   at the beginning. */
                                lp -> prev = comp;
@@ -397,6 +420,18 @@ void supersede_lease (comp, lease)
        }
 }
 
+/* Release the specified lease and re-hash it as appropriate. */
+
+void release_lease (lease)
+       struct lease *lease;
+{
+       struct lease lt;
+
+       lease -> ends = 0;
+       lt = *lease;
+       supersede_lease (lease, &lt);
+}
+
 /* Locate the lease associated with a given IP address... */
 
 struct lease *find_lease_by_ip_addr (addr)
@@ -417,3 +452,29 @@ struct lease *find_lease_by_uid (uid, len)
        return lease;
 }
 
+struct lease *find_lease_by_hw_addr (hwaddr, hwlen)
+       unsigned char *hwaddr;
+       int hwlen;
+{
+       struct lease *lease = (struct lease *)hash_lookup (lease_hw_addr_hash,
+                                                          hwaddr, hwlen);
+       return lease;
+}
+
+void dump_subnets ()
+{
+       struct lease *l;
+       struct subnet *s;
+       int i;
+
+       for (s = subnets; s; s = s -> next) {
+               printf ("Subnet %s", piaddr (s -> net));
+               printf (" netmask %s\n",
+                       piaddr (s -> netmask));
+               for (l = s -> leases; l; l = l -> next) {
+                       print_lease (l);
+               }
+               printf ("Last Lease:\n");
+               print_lease (s -> last_lease);
+       }
+}
index 75bfc5e5dd9fe7a30e7eef421ade871de3dc3257..f9fa44d384c8a113ab3cce4c62fcff63fd47de20 100644 (file)
--- a/options.c
+++ b/options.c
@@ -94,8 +94,6 @@ void parse_option_buffer (packet, buffer, length)
        int len;
        int code;
 
-printf ("parse_option_buffer (%x, %x, %d)\n",
-(unsigned long)packet, (unsigned long)buffer, length);
        for (s = buffer; *s != DHO_END && s < end; ) {
                code = s [0];
                /* Pad options don't have a length - just skip them. */
@@ -126,8 +124,6 @@ printf ("parse_option_buffer (%x, %x, %d)\n",
                        t [len] = 0;
                        packet -> options [code].len = len;
                        packet -> options [code].data = t;
-printf ("%s=%s\n", dhcp_options [code].name,
-pretty_print_option (code, t, len));
                } else {
                        /* If it's a repeat, concatenate it to whatever
                           we last saw.   This is really only required
diff --git a/print.c b/print.c
index 55d17159593c031de5ba58e3fc25d0e9b51aa801..4686e2e33e54f91ef883bf7a0ad1825143723175 100644 (file)
--- a/print.c
+++ b/print.c
@@ -55,13 +55,46 @@ char *print_hw_addr (htype, hlen, data)
        char *s;
        int i;
 
-       s = habuf;
-       for (i = 0; i < hlen; i++) {
-               sprintf (s, "%x", data [i]);
-               s += strlen (s);
-               *s++ = ':';
+       if (htype == 0 || hlen == 0) {
+               strcpy (habuf, "<null>");
+       } else {
+               s = habuf;
+               for (i = 0; i < hlen; i++) {
+                       sprintf (s, "%x", data [i]);
+                       s += strlen (s);
+                       *s++ = ':';
+               }
+               *--s = 0;
        }
-       *--s = 0;
        return habuf;
 }
 
+void print_lease (lease)
+       struct lease *lease;
+{
+       struct tm *t;
+       char tbuf [32];
+
+       printf ("  Lease %s",
+               piaddr (lease -> ip_addr));
+       
+       t = gmtime (&lease -> starts);
+       strftime (tbuf, sizeof tbuf, "%D %H:%M:%S", t);
+       printf ("  start %s", tbuf);
+       
+       t = gmtime (&lease -> ends);
+       strftime (tbuf, sizeof tbuf, "%D %H:%M:%S", t);
+       printf ("  end %s", tbuf);
+       
+       t = gmtime (&lease -> timestamp);
+       strftime (tbuf, sizeof tbuf, "%D %H:%M:%S", t);
+       printf ("  stamp %s\n", tbuf);
+       
+       printf ("    hardware addr = %s",
+               print_hw_addr (lease -> hardware_addr.htype,
+                              lease -> hardware_addr.hlen,
+                              lease -> hardware_addr.haddr));
+       printf ("  host %s  state %x\n",
+               lease -> host ? lease -> host -> name : "<none>",
+               lease -> state);
+}      
index 7335de6fe95bdc25e7c38d63c48c1b5899eebc10..1be52bb9af07916702a21727591e3bde7b5e0c64 100644 (file)
@@ -234,6 +234,22 @@ void parse_host_decl (cfile, bc, decl)
              case OPTION:
                parse_option_decl (cfile, bc, decl);
                break;
+             case CIADDR:
+               decl -> ciaddr =
+                       tree_cache (parse_ip_addr_or_hostname (cfile, bc, 0));
+               break;
+             case YIADDR:
+               decl -> yiaddr =
+                       tree_cache (parse_ip_addr_or_hostname (cfile, bc, 0));
+               break;
+             case SIADDR:
+               decl -> siaddr =
+                       tree_cache (parse_ip_addr_or_hostname (cfile, bc, 0));
+               break;
+             case GIADDR:
+               decl -> giaddr =
+                       tree_cache (parse_ip_addr_or_hostname (cfile, bc, 0));
+               break;
              default:
                parse_warn ("expecting a dhcp option declaration.");
                skip_to_semi (cfile);
index fa49eccc952ad7968cc264e58737e5cc3873623d..640c726f054016ec74bb769b587f33261c9f8bc1 100644 (file)
@@ -49,5 +49,205 @@ static char copyright[] =
 void dhcp (packet)
        struct packet *packet;
 {
+       struct lease *uid_lease, *ip_lease, *hw_lease, *lease;
+       struct iaddr cip;
+       struct lease lt;
+       TIME lease_time;
+
        dump_packet (packet);
+
+       /* Try to find a lease that's been assigned to the specified
+          unique client identifier. */
+       if (packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len)
+               uid_lease =
+                       find_lease_by_uid (packet -> options
+                                          [DHO_DHCP_CLIENT_IDENTIFIER].data,
+                                          packet -> options
+                                          [DHO_DHCP_CLIENT_IDENTIFIER].len);
+       else
+               uid_lease = (struct lease *)0;
+
+       /* Try to find a lease that's been attached to the client's
+          hardware address... */
+       hw_lease = find_lease_by_hw_addr (packet -> raw -> chaddr,
+                                         packet -> raw -> hlen);
+
+       /* Try to find a lease that's been allocated to the client's
+          IP address. */
+       if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len &&
+           packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len
+           <= sizeof cip.iabuf) {
+               cip.len = packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len;
+               memcpy (cip.iabuf,
+                       packet -> options [DHO_DHCP_REQUESTED_ADDRESS].data,
+                       packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len);
+               memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4);
+               ip_lease = find_lease_by_ip_addr (cip);
+       } else
+               ip_lease = (struct lease *)0;
+
+       printf ("First blush:\n");
+       if (ip_lease) {
+               printf ("ip_lease: ");
+               print_lease (ip_lease);
+       }
+       if (hw_lease) {
+               printf ("hw_lease: ");
+               print_lease (hw_lease);
+       }
+       if (uid_lease) {
+               printf ("uid_lease: ");
+               print_lease (uid_lease);
+       }
+
+       /* Toss extra pointers to the same lease... */
+       if (ip_lease == hw_lease)
+               ip_lease = (struct lease *)0;
+       if (hw_lease == uid_lease)
+               hw_lease = (struct lease *)0;
+       if (ip_lease == uid_lease)
+               ip_lease = (struct lease *)0;
+
+       printf ("Second blush:\n");
+       if (ip_lease) {
+               printf ("ip_lease: ");
+               print_lease (ip_lease);
+       }
+       if (hw_lease) {
+               printf ("hw_lease: ");
+               print_lease (hw_lease);
+       }
+       if (uid_lease) {
+               printf ("uid_lease: ");
+               print_lease (uid_lease);
+       }
+
+       /* If we got an ip address lease, make sure it isn't assigned to
+          some *other* client!   If it was assigned to this client, we'd
+          have zeroed it out above, so the only way we can take it at this
+          point is if some other client had it but it's timed out, or if no
+          other client has ever had it. */
+       if (ip_lease &&
+           ip_lease -> ends >= cur_time)
+               ip_lease = (struct lease *)0;
+
+       /* Now eliminate leases that are on the wrong subnet... */
+       if (ip_lease && packet -> subnet != ip_lease -> contain) {
+               release_lease (ip_lease);
+               ip_lease = (struct lease *)0;
+       }
+       if (uid_lease && packet -> subnet != uid_lease -> contain) {
+               release_lease (uid_lease);
+               uid_lease = (struct lease *)0;
+       }
+       if (hw_lease && packet -> subnet != hw_lease -> contain) {
+               release_lease (hw_lease);
+               hw_lease = (struct lease *)0;
+       }
+
+       printf ("Third blush:\n");
+       if (ip_lease) {
+               printf ("ip_lease: ");
+               print_lease (ip_lease);
+       }
+       if (hw_lease) {
+               printf ("hw_lease: ");
+               print_lease (hw_lease);
+       }
+       if (uid_lease) {
+               printf ("uid_lease: ");
+               print_lease (uid_lease);
+       }
+
+       /* At this point, if ip_lease is nonzero, we can assign it to
+          this client. */
+       lease = ip_lease;
+
+       /* If we got a lease that matched the client identifier, we may want
+          to use it, but if we already have a lease we like, we must free
+          the lease that matched the client identifier. */
+       if (uid_lease) {
+               if (lease) {
+                       release_lease (uid_lease);
+               } else
+                       lease = uid_lease;
+       }
+
+       /* The lease that matched the hardware address is treated likewise. */
+       if (hw_lease) {
+               if (lease) {
+                       release_lease (hw_lease);
+               } else
+                       lease = hw_lease;
+       }
+
+       /* If we didn't find a lease, try to allocate one... */
+       if (!lease) {
+               lease = packet -> subnet -> last_lease;
+
+               /* If there are no leases in that subnet that have
+                  expired, we have nothing to offer this client. */
+               if (lease -> ends >= cur_time) {
+                       note ("no free leases on subnet %s",
+                             piaddr (packet -> subnet -> net));
+                       return;
+               }
+               lease -> host = (struct host_decl *)0;
+       }
+
+       /* At this point, we have a lease that we can offer the client.
+          Now we construct a lease structure that contains what we want,
+          and call supersede_lease to do the right thing with it. */
+
+       memset (&lt, 0, sizeof lt);
+
+       /* Use the ip address of the lease that we finally found in
+          the database. */
+       lt.ip_addr = lease -> ip_addr;
+
+       /* Start now. */
+       lt.starts = cur_time;
+
+       /* Figure out how long a lease to assign. */
+       if (packet -> options [DHO_DHCP_LEASE_TIME].len == 4) {
+               lease_time = getULong (packet ->
+                                      options [DHO_DHCP_LEASE_TIME].data);
+
+               /* Don't let the client ask for a longer lease than
+                  is supported for this subnet. */
+               if (lease_time > packet -> subnet -> max_lease_time)
+                       lease_time = packet -> subnet -> max_lease_time;
+       } else
+               lease_time = packet -> subnet -> default_lease_time;
+       lt.ends = cur_time + lease_time;
+
+       lt.timestamp = cur_time;
+
+       /* Record the uid, if given... */
+       if (packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len) {
+               lt.uid_len =
+                       packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len;
+               lt.uid = packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].data;
+               packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].data =
+                       (unsigned char *)0;
+               packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len = 0;
+       }
+
+       /* Record the hardware address, if given... */
+       lt.hardware_addr.hlen = packet -> raw -> hlen;
+       lt.hardware_addr.htype = packet -> raw -> htype;
+       memcpy (lt.hardware_addr.haddr, packet -> raw -> chaddr,
+               packet -> raw -> hlen);
+
+       lt.host = lease -> host; /* XXX */
+       lt.contain = lease -> contain;
+
+       /* Record the transaction id... */
+       lt.xid = packet -> raw -> xid;
+
+       /* Install the new information about this lease in the database. */
+       supersede_lease (lease, &lt);
+
+       /* Send a response to the client... */
+       dump_subnets ();
 }
index b9e527c862e7b885b9cbf5c065566160b7324f3c..159d3b85c93da732371665f5df6c425e91800f82 100644 (file)
@@ -50,7 +50,10 @@ static char copyright[] =
 static void usage PROTO ((void));
 
 TIME cur_time;
+TIME default_lease_time = 43200; /* 12 hours... */
+TIME max_lease_time = 86400; /* 24 hours... */
 
+struct subnet *local_subnet;
 u_int32_t *server_addrlist;
 int server_addrcount;
 u_int16_t server_port;
@@ -63,6 +66,7 @@ int main (argc, argv, envp)
        int port = 0;
        int i;
        struct sockaddr_in name;
+       struct iaddr taddr;
        u_int32_t *addrlist = (u_int32_t *)0;
        int addrcount = 0;
        struct tree *addrtree = (struct tree *)0;
@@ -148,7 +152,23 @@ int main (argc, argv, envp)
        }
 #endif
 
+       taddr.len = 0;
        server_addrlist = get_interface_list (&server_addrcount);
+       for (i = 0; i < server_addrcount; i++) {
+               struct sockaddr_in foo;
+               foo.sin_addr.s_addr = server_addrlist [i];
+               printf ("Address %d: %s\n", i, inet_ntoa (foo.sin_addr));
+
+               if (server_addrlist [i] != htonl (INADDR_LOOPBACK)) {
+                       if (taddr.len) {
+                               error ("dhcpd currently does not support "
+                                      "multiple interfaces");
+                       }
+                       taddr.len = 4;
+                       memcpy (taddr.iabuf, &server_addrlist [i], 4);
+                       local_subnet = find_subnet (taddr);
+               }
+       }
 
        /* Listen on the specified (or default) port on each specified
           (or default) IP address. */
@@ -164,6 +184,8 @@ int main (argc, argv, envp)
                close (i);
        }
 
+       dump_subnets ();
+
        /* Receive packets and dispatch them... */
        dispatch ();
 
@@ -191,6 +213,7 @@ void do_packet (packbuf, len, from_port, from, sock)
 {
        struct packet *tp;
        struct dhcp_packet *tdp;
+       struct iaddr ia;
 
        if (!(tp = new_packet ("do_packet")))
                return;
@@ -205,12 +228,29 @@ void do_packet (packbuf, len, from_port, from, sock)
        tp -> client_port = from_port;
        tp -> client_addr = from;
        tp -> client_sock = sock;
-       parse_options (tp);
-       if (tp -> options_valid &&
-           tp -> options [DHO_DHCP_MESSAGE_TYPE].data)
-               dhcp (tp);
-       else
-               bootp (tp);
+       
+       /* If this came through a gateway, find the corresponding subnet... */
+       if (tp -> raw -> giaddr.s_addr) {
+               ia.len = 4;
+               memcpy (ia.iabuf, &tp -> raw -> giaddr, 4);
+               tp -> subnet = find_subnet (ia);
+       } else {
+               tp -> subnet = local_subnet;
+       }
+
+       /* If the subnet from whence this packet came is unknown to us,
+          drop it on the floor... */
+       if (!tp -> subnet)
+               note ("Packet from unknown subnet: %s",
+                     inet_ntoa (tp -> raw -> giaddr));
+       else {
+               parse_options (tp);
+               if (tp -> options_valid &&
+                   tp -> options [DHO_DHCP_MESSAGE_TYPE].data)
+                       dhcp (tp);
+               else
+                       bootp (tp);
+       }
 }
 
 void dump_packet (tp)
index 10d66a37f7e53857f6616b5e09f091b8995f4a50..bc8a1d7760ec6ab76d0beb135493f17e693ee675 100644 (file)
@@ -1,4 +1,5 @@
-range 204.254.239.11 204.254.239.254 255.255.255.0;
+range 204.254.239.11 204.254.239.17 255.255.255.0;
+range 204.254.240.11 204.254.240.12 255.255.255.0;
 
 host minuet
        hardware ethernet 08:00:2b:35:0c:18
index 3a013cf07eca976466a33f74a7e60ab4c660dece..c69e68ccc1f2cc9a793dde6a8db31bcfc7665e0a 100644 (file)
--- a/socket.c
+++ b/socket.c
@@ -184,6 +184,9 @@ void dispatch ()
                /* Wait for a packet or a timeout... XXX */
                count = select (max + 1, &r, &w, &x, (struct timeval *)0);
 
+               /* Get the current time... */
+               GET_TIME (&cur_time);
+
                /* Not likely to be transitory... */
                if (count < 0)
                        error ("select: %m");