summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Lemon <source@isc.org>1996-02-21 12:11:09 +0000
committerTed Lemon <source@isc.org>1996-02-21 12:11:09 +0000
commit97ca16995f70c396d4d69e742953cf80edf612cd (patch)
treef8ebd8a7fe4cc5a52e32b88bdd0a1aa4b0d8949b
parentd9c6d82c49360ee7d451d7cfc20d90bf600f9f2c (diff)
downloadisc-dhcp-97ca16995f70c396d4d69e742953cf80edf612cd.tar.gz
Intermediate changes to support actual DHCP protocol engine
-rw-r--r--Makefile6
-rw-r--r--client/dhclient.c50
-rw-r--r--common/conflex.c12
-rw-r--r--common/hash.c4
-rw-r--r--common/inet.c8
-rw-r--r--common/memory.c123
-rw-r--r--common/options.c4
-rw-r--r--common/print.c45
-rw-r--r--common/socket.c3
-rw-r--r--conflex.c12
-rw-r--r--confpars.c16
-rw-r--r--dhclient.c50
-rw-r--r--dhcp.c200
-rw-r--r--dhcpd.c52
-rw-r--r--dhcpd.conf3
-rw-r--r--dhcpd.h17
-rw-r--r--dhctoken.h6
-rw-r--r--hash.c4
-rw-r--r--includes/dhcpd.h17
-rw-r--r--includes/dhctoken.h6
-rw-r--r--inet.c8
-rw-r--r--memory.c123
-rw-r--r--options.c4
-rw-r--r--print.c45
-rw-r--r--server/confpars.c16
-rw-r--r--server/dhcp.c200
-rw-r--r--server/dhcpd.c52
-rw-r--r--server/dhcpd.conf3
-rw-r--r--socket.c3
29 files changed, 972 insertions, 120 deletions
diff --git a/Makefile b/Makefile
index e745f08e..c90b3043 100644
--- 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
diff --git a/client/dhclient.c b/client/dhclient.c
index 0a66c41d..c9d9e64d 100644
--- a/client/dhclient.c
+++ b/client/dhclient.c
@@ -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/common/conflex.c b/common/conflex.c
index 33e58318..28a9f65e 100644
--- a/common/conflex.c
+++ b/common/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;
}
diff --git a/common/hash.c b/common/hash.c
index 8bc724e7..cf15ba31 100644
--- a/common/hash.c
+++ b/common/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))
diff --git a/common/inet.c b/common/inet.c
index fa25efc1..ce63a2b4 100644
--- a/common/inet.c
+++ b/common/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;
diff --git a/common/memory.c b/common/memory.c
index 21b1c010..13bf3492 100644
--- a/common/memory.c
+++ b/common/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);
+ }
+}
diff --git a/common/options.c b/common/options.c
index 75bfc5e5..f9fa44d3 100644
--- a/common/options.c
+++ b/common/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/common/print.c b/common/print.c
index 55d17159..4686e2e3 100644
--- a/common/print.c
+++ b/common/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);
+}
diff --git a/common/socket.c b/common/socket.c
index 3a013cf0..c69e68cc 100644
--- a/common/socket.c
+++ b/common/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");
diff --git a/conflex.c b/conflex.c
index 33e58318..28a9f65e 100644
--- 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;
}
diff --git a/confpars.c b/confpars.c
index 7335de6f..1be52bb9 100644
--- a/confpars.c
+++ b/confpars.c
@@ -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);
diff --git a/dhclient.c b/dhclient.c
index 0a66c41d..c9d9e64d 100644
--- a/dhclient.c
+++ b/dhclient.c
@@ -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 fa49eccc..640c726f 100644
--- 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 b9e527c8..159d3b85 100644
--- 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)
diff --git a/dhcpd.conf b/dhcpd.conf
index 10d66a37..bc8a1d77 100644
--- a/dhcpd.conf
+++ b/dhcpd.conf
@@ -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 655b57eb..81d5cccc 100644
--- 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 *));
diff --git a/dhctoken.h b/dhctoken.h
index f04fae5b..e3132f99 100644
--- a/dhctoken.h
+++ b/dhctoken.h
@@ -64,7 +64,11 @@
#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 8bc724e7..cf15ba31 100644
--- 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))
diff --git a/includes/dhcpd.h b/includes/dhcpd.h
index 655b57eb..81d5cccc 100644
--- a/includes/dhcpd.h
+++ b/includes/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 *));
diff --git a/includes/dhctoken.h b/includes/dhctoken.h
index f04fae5b..e3132f99 100644
--- a/includes/dhctoken.h
+++ b/includes/dhctoken.h
@@ -64,7 +64,11 @@
#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 fa25efc1..ce63a2b4 100644
--- 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;
diff --git a/memory.c b/memory.c
index 21b1c010..13bf3492 100644
--- 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);
+ }
+}
diff --git a/options.c b/options.c
index 75bfc5e5..f9fa44d3 100644
--- 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 55d17159..4686e2e3 100644
--- 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);
+}
diff --git a/server/confpars.c b/server/confpars.c
index 7335de6f..1be52bb9 100644
--- a/server/confpars.c
+++ b/server/confpars.c
@@ -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);
diff --git a/server/dhcp.c b/server/dhcp.c
index fa49eccc..640c726f 100644
--- a/server/dhcp.c
+++ b/server/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/server/dhcpd.c b/server/dhcpd.c
index b9e527c8..159d3b85 100644
--- a/server/dhcpd.c
+++ b/server/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)
diff --git a/server/dhcpd.conf b/server/dhcpd.conf
index 10d66a37..bc8a1d77 100644
--- a/server/dhcpd.conf
+++ b/server/dhcpd.conf
@@ -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/socket.c b/socket.c
index 3a013cf0..c69e68cc 100644
--- 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");