2
0
mirror of https://gitlab.isc.org/isc-projects/dhcp synced 2025-09-03 15:56:00 +00:00

Intermediate changes to support actual DHCP protocol engine

This commit is contained in:
Ted Lemon
1996-02-21 12:11:09 +00:00
parent d9c6d82c49
commit 97ca16995f
29 changed files with 972 additions and 120 deletions

View File

@@ -11,6 +11,8 @@ CFLAGS += -DDEBUG -g -Wall -Wstrict-prototypes -Wno-unused \
-Wno-uninitialized -Werror -Wno-uninitialized -Werror
dhclient: dhclient.o confpars.o alloc.o memory.o options.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 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 \ 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 hash.o tables.o inet.o convert.o conflex.o errwarn.o \
print.o tree.o

View File

@@ -189,10 +189,50 @@ int main (argc, argv, envp)
cons_options ((struct packet *)0, cons_options ((struct packet *)0,
&outgoing, &decl, bufs); &outgoing, &decl, bufs);
memset (&raw.ciaddr, 0, sizeof raw.ciaddr);
memset (&raw.yiaddr, 0, sizeof raw.ciaddr); if (decl.ciaddr) {
memset (&raw.siaddr, 0, sizeof raw.ciaddr); if (tree_evaluate (decl.ciaddr) != 4)
memset (&raw.giaddr, 0, sizeof raw.ciaddr); 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 = xid++;
raw.xid = htons (raw.xid); raw.xid = htons (raw.xid);

View File

@@ -274,6 +274,8 @@ static int intern (atom, dfv)
case 'c': case 'c':
if (!strcasecmp (atom + 1, "lass")) if (!strcasecmp (atom + 1, "lass"))
return CLASS; return CLASS;
if (!strcasecmp (atom + 1, "iaddr"))
return CIADDR;
break; break;
case 'e': case 'e':
if (!strcasecmp (atom + 1, "thernet")) if (!strcasecmp (atom + 1, "thernet"))
@@ -287,6 +289,10 @@ static int intern (atom, dfv)
if (!strcasecmp (atom + 1, "ixed-address")) if (!strcasecmp (atom + 1, "ixed-address"))
return FIXED_ADDR; return FIXED_ADDR;
break; break;
case 'g':
if (!strcasecmp (atom + 1, "iaddr"))
return GIADDR;
break;
case 'h': case 'h':
if (!strcasecmp (atom + 1, "ost")) if (!strcasecmp (atom + 1, "ost"))
return HOST; return HOST;
@@ -312,6 +318,8 @@ static int intern (atom, dfv)
case 's': case 's':
if (!strcasecmp (atom + 1, "tarts")) if (!strcasecmp (atom + 1, "tarts"))
return STARTS; return STARTS;
if (!strcasecmp (atom + 1, "iaddr"))
return SIADDR;
break; break;
case 't': case 't':
if (!strcasecmp (atom + 1, "timestamp")) if (!strcasecmp (atom + 1, "timestamp"))
@@ -321,6 +329,10 @@ static int intern (atom, dfv)
if (!strcasecmp (atom + 1, "id")) if (!strcasecmp (atom + 1, "id"))
return UID; return UID;
break; break;
case 'y':
if (!strcasecmp (atom + 1, "iaddr"))
return YIADDR;
break;
} }
return dfv; return dfv;
} }

View File

@@ -103,6 +103,7 @@ void add_hash (table, name, len, pointer)
bp -> name = name; bp -> name = name;
bp -> value = pointer; bp -> value = pointer;
bp -> next = table -> buckets [hashno]; bp -> next = table -> buckets [hashno];
bp -> len = len;
table -> buckets [hashno] = bp; table -> buckets [hashno] = bp;
} }
@@ -140,10 +141,11 @@ unsigned char *hash_lookup (table, name, len)
struct hash_bucket *bp; struct hash_bucket *bp;
if (len) { if (len) {
for (bp = table -> buckets [hashno]; bp; bp = bp -> next) for (bp = table -> buckets [hashno]; bp; bp = bp -> next) {
if (len == bp -> len if (len == bp -> len
&& !memcmp (bp -> name, name, len)) && !memcmp (bp -> name, name, len))
return bp -> value; return bp -> value;
}
} else { } else {
for (bp = table -> buckets [hashno]; bp; bp = bp -> next) for (bp = table -> buckets [hashno]; bp; bp = bp -> next)
if (!strcmp (bp -> name, name)) if (!strcmp (bp -> name, name))

View File

@@ -87,7 +87,7 @@ struct iaddr ip_addr (subnet, mask, host_address)
j = rv.len - sizeof habuf; j = rv.len - sizeof habuf;
for (i = sizeof habuf - 1; i >= 0; i--) { for (i = sizeof habuf - 1; i >= 0; i--) {
if (mask.iabuf [i + j]) { if (mask.iabuf [i + j]) {
if (habuf [i] > ~mask.iabuf [i + j]) { if (habuf [i] > (mask.iabuf [i + j] ^ 0xFF)) {
rv.len = 0; rv.len = 0;
return rv; return rv;
} }
@@ -97,10 +97,10 @@ struct iaddr ip_addr (subnet, mask, host_address)
return rv; return rv;
} }
} }
rv.iabuf [i + j] &= habuf [i]; rv.iabuf [i + j] |= habuf [i];
break; break;
} } else
rv.iabuf [i + j] = habuf [i]; rv.iabuf [i + j] = habuf [i];
} }
return rv; return rv;

View File

@@ -48,7 +48,7 @@ static char copyright[] =
#include "dhcpd.h" #include "dhcpd.h"
static struct host_decl *hosts; 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_uid_hash;
static struct hash_table *lease_ip_addr_hash; static struct hash_table *lease_ip_addr_hash;
static struct hash_table *lease_hw_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 lease *address_range, *lp, *plp;
struct subnet *subnet; struct subnet *subnet;
struct iaddr net; struct iaddr net;
int i, max; int min, max, i;
char lowbuf [16], highbuf [16], netbuf [16]; char lowbuf [16], highbuf [16], netbuf [16];
/* Initialize the hash table if it hasn't been done yet. */ /* Initialize the hash table if it hasn't been done yet. */
if (!subnet_hash)
subnet_hash = new_hash ();
if (!lease_uid_hash) if (!lease_uid_hash)
lease_uid_hash = new_hash (); lease_uid_hash = new_hash ();
if (!lease_ip_addr_hash) if (!lease_ip_addr_hash)
@@ -130,32 +128,40 @@ void new_address_range (low, high, netmask)
subnet -> net = net; subnet -> net = net;
subnet -> netmask = netmask; subnet -> netmask = netmask;
subnet -> leases = (struct lease *)0; 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); enter_subnet (subnet);
} }
/* Get the high and low host addresses... */ /* Get the high and low host addresses... */
max = host_addr (high, netmask); 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. */ /* Allow range to be specified high-to-low as well as low-to-high. */
if (i > max) { if (min > max) {
max = i; max = min;
i = host_addr (high, netmask); min = host_addr (high, netmask);
} }
/* Get a lease structure for each address in the range. */ /* 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) { if (!address_range) {
strcpy (lowbuf, piaddr (low)); strcpy (lowbuf, piaddr (low));
strcpy (highbuf, piaddr (high)); strcpy (highbuf, piaddr (high));
error ("No memory for address range %s-%s.", lowbuf, highbuf); 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. */ /* 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 = 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].starts =
address_range [i].timestamp = MIN_TIME; address_range [i].timestamp = MIN_TIME;
address_range [i].ends = 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 subnet *find_subnet (addr)
struct iaddr subnet; struct iaddr addr;
{ {
struct subnet *rv; struct subnet *rv;
return (struct subnet *)hash_lookup (subnet_hash, for (rv = subnets; rv; rv = rv -> next) {
(char *)subnet.iabuf, subnet.len); if (addr_eq (subnet_number (addr, rv -> netmask), rv -> net))
return rv;
}
return (struct subnet *)0;
} }
/* Enter a new subnet into the subnet hash. */ /* Enter a new subnet into the subnet hash. */
@@ -214,8 +223,9 @@ struct subnet *find_subnet (subnet)
void enter_subnet (subnet) void enter_subnet (subnet)
struct subnet *subnet; struct subnet *subnet;
{ {
add_hash (subnet_hash, (char *)subnet -> net.iabuf, /* XXX Sort the nets into a balanced tree to make searching quicker. */
subnet -> net.len, (unsigned char *)subnet); subnet -> next = subnets;
subnets = subnet;
} }
/* Enter a lease into the system. This is called by the parser each /* 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 subnet *parent;
struct lease *lp; 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 /* If the existing lease hasn't expired and has a different
unique identifier or, if it doesn't have a unique unique identifier or, if it doesn't have a unique
identifier, a different hardware address, then the two identifier, a different hardware address, then the two
@@ -290,7 +305,9 @@ void supersede_lease (comp, lease)
enter_uid = 1; enter_uid = 1;
} }
free (comp -> uid); free (comp -> uid);
} } else
enter_uid = 1;
if (comp -> hardware_addr.htype && if (comp -> hardware_addr.htype &&
((comp -> hardware_addr.hlen != ((comp -> hardware_addr.hlen !=
lease -> hardware_addr.hlen) || lease -> hardware_addr.hlen) ||
@@ -303,7 +320,8 @@ void supersede_lease (comp, lease)
comp -> hardware_addr.haddr, comp -> hardware_addr.haddr,
comp -> hardware_addr.hlen); comp -> hardware_addr.hlen);
enter_hwaddr = 1; enter_hwaddr = 1;
} } else if (!comp -> hardware_addr.htype)
enter_hwaddr = 1;
/* Copy the data files, but not the linkages. */ /* Copy the data files, but not the linkages. */
comp -> starts = lease -> starts; comp -> starts = lease -> starts;
@@ -317,16 +335,16 @@ void supersede_lease (comp, lease)
/* Record the lease in the uid hash if necessary. */ /* Record the lease in the uid hash if necessary. */
if (enter_uid && lease -> uid) { if (enter_uid && lease -> uid) {
add_hash (lease_uid_hash, lease -> uid, add_hash (lease_uid_hash, comp -> uid,
lease -> uid_len, (unsigned char *)lease); comp -> uid_len, (unsigned char *)comp);
} }
/* Record it in the hardware address hash if necessary. */ /* Record it in the hardware address hash if necessary. */
if (enter_hwaddr && lease -> hardware_addr.htype) { if (enter_hwaddr && lease -> hardware_addr.htype) {
add_hash (lease_hw_addr_hash, add_hash (lease_hw_addr_hash,
lease -> hardware_addr.haddr, comp -> hardware_addr.haddr,
lease -> hardware_addr.hlen, comp -> hardware_addr.hlen,
(unsigned char *)lease); (unsigned char *)comp);
} }
/* Remove the lease from its current place in the list. */ /* Remove the lease from its current place in the list. */
@@ -338,6 +356,9 @@ void supersede_lease (comp, lease)
if (comp -> next) { if (comp -> next) {
comp -> next -> prev = comp -> prev; comp -> next -> prev = comp -> prev;
} }
if (comp -> contain -> last_lease == comp) {
comp -> contain -> last_lease = comp -> prev;
}
/* Find the last insertion point... */ /* Find the last insertion point... */
if (comp == comp -> contain -> 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 /* Nothing on the list yet? Just make comp the
head of the list. */ head of the list. */
comp -> contain -> leases = comp; 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 /* Skip down the list until we run out of list
or find a place for comp. */ or find a place for comp. */
while (lp -> next && lp -> ends < comp -> ends) { while (lp -> next && lp -> ends > comp -> ends) {
lp = lp -> next; lp = lp -> next;
} }
if (lp -> ends < comp -> ends) { if (lp -> ends > comp -> ends) {
/* If we ran out of list, put comp /* If we ran out of list, put comp
at the end. */ at the end. */
lp -> next = comp; lp -> next = comp;
comp -> prev = lp; comp -> prev = lp;
comp -> next = (struct lease *)0; comp -> next = (struct lease *)0;
comp -> contain -> last_lease = comp;
} else { } else {
/* If we didn't, put it between lp and /* If we didn't, put it between lp and
the previous item on the list. */ the previous item on the list. */
@@ -372,12 +395,12 @@ void supersede_lease (comp, lease)
lp -> prev = comp; lp -> prev = comp;
} }
} else { } 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. */ or find a place for comp. */
while (lp -> prev && lp -> ends > comp -> ends) { while (lp -> prev && lp -> ends < comp -> ends) {
lp = lp -> prev; lp = lp -> prev;
} }
if (lp -> ends > comp -> ends) { if (lp -> ends < comp -> ends) {
/* If we ran out of list, put comp /* If we ran out of list, put comp
at the beginning. */ at the beginning. */
lp -> prev = comp; 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... */ /* Locate the lease associated with a given IP address... */
struct lease *find_lease_by_ip_addr (addr) struct lease *find_lease_by_ip_addr (addr)
@@ -417,3 +452,29 @@ struct lease *find_lease_by_uid (uid, len)
return lease; 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);
}
}

View File

@@ -94,8 +94,6 @@ void parse_option_buffer (packet, buffer, length)
int len; int len;
int code; 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; ) { for (s = buffer; *s != DHO_END && s < end; ) {
code = s [0]; code = s [0];
/* Pad options don't have a length - just skip them. */ /* 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; t [len] = 0;
packet -> options [code].len = len; packet -> options [code].len = len;
packet -> options [code].data = t; packet -> options [code].data = t;
printf ("%s=%s\n", dhcp_options [code].name,
pretty_print_option (code, t, len));
} else { } else {
/* If it's a repeat, concatenate it to whatever /* If it's a repeat, concatenate it to whatever
we last saw. This is really only required we last saw. This is really only required

View File

@@ -55,13 +55,46 @@ char *print_hw_addr (htype, hlen, data)
char *s; char *s;
int i; int i;
s = habuf; if (htype == 0 || hlen == 0) {
for (i = 0; i < hlen; i++) { strcpy (habuf, "<null>");
sprintf (s, "%x", data [i]); } else {
s += strlen (s); s = habuf;
*s++ = ':'; for (i = 0; i < hlen; i++) {
sprintf (s, "%x", data [i]);
s += strlen (s);
*s++ = ':';
}
*--s = 0;
} }
*--s = 0;
return habuf; 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);
}

View File

@@ -184,6 +184,9 @@ void dispatch ()
/* Wait for a packet or a timeout... XXX */ /* Wait for a packet or a timeout... XXX */
count = select (max + 1, &r, &w, &x, (struct timeval *)0); count = select (max + 1, &r, &w, &x, (struct timeval *)0);
/* Get the current time... */
GET_TIME (&cur_time);
/* Not likely to be transitory... */ /* Not likely to be transitory... */
if (count < 0) if (count < 0)
error ("select: %m"); error ("select: %m");

View File

@@ -274,6 +274,8 @@ static int intern (atom, dfv)
case 'c': case 'c':
if (!strcasecmp (atom + 1, "lass")) if (!strcasecmp (atom + 1, "lass"))
return CLASS; return CLASS;
if (!strcasecmp (atom + 1, "iaddr"))
return CIADDR;
break; break;
case 'e': case 'e':
if (!strcasecmp (atom + 1, "thernet")) if (!strcasecmp (atom + 1, "thernet"))
@@ -287,6 +289,10 @@ static int intern (atom, dfv)
if (!strcasecmp (atom + 1, "ixed-address")) if (!strcasecmp (atom + 1, "ixed-address"))
return FIXED_ADDR; return FIXED_ADDR;
break; break;
case 'g':
if (!strcasecmp (atom + 1, "iaddr"))
return GIADDR;
break;
case 'h': case 'h':
if (!strcasecmp (atom + 1, "ost")) if (!strcasecmp (atom + 1, "ost"))
return HOST; return HOST;
@@ -312,6 +318,8 @@ static int intern (atom, dfv)
case 's': case 's':
if (!strcasecmp (atom + 1, "tarts")) if (!strcasecmp (atom + 1, "tarts"))
return STARTS; return STARTS;
if (!strcasecmp (atom + 1, "iaddr"))
return SIADDR;
break; break;
case 't': case 't':
if (!strcasecmp (atom + 1, "timestamp")) if (!strcasecmp (atom + 1, "timestamp"))
@@ -321,6 +329,10 @@ static int intern (atom, dfv)
if (!strcasecmp (atom + 1, "id")) if (!strcasecmp (atom + 1, "id"))
return UID; return UID;
break; break;
case 'y':
if (!strcasecmp (atom + 1, "iaddr"))
return YIADDR;
break;
} }
return dfv; return dfv;
} }

View File

@@ -234,6 +234,22 @@ void parse_host_decl (cfile, bc, decl)
case OPTION: case OPTION:
parse_option_decl (cfile, bc, decl); parse_option_decl (cfile, bc, decl);
break; 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: default:
parse_warn ("expecting a dhcp option declaration."); parse_warn ("expecting a dhcp option declaration.");
skip_to_semi (cfile); skip_to_semi (cfile);

View File

@@ -189,10 +189,50 @@ int main (argc, argv, envp)
cons_options ((struct packet *)0, cons_options ((struct packet *)0,
&outgoing, &decl, bufs); &outgoing, &decl, bufs);
memset (&raw.ciaddr, 0, sizeof raw.ciaddr);
memset (&raw.yiaddr, 0, sizeof raw.ciaddr); if (decl.ciaddr) {
memset (&raw.siaddr, 0, sizeof raw.ciaddr); if (tree_evaluate (decl.ciaddr) != 4)
memset (&raw.giaddr, 0, sizeof raw.ciaddr); 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 = xid++;
raw.xid = htons (raw.xid); raw.xid = htons (raw.xid);

200
dhcp.c
View File

@@ -49,5 +49,205 @@ static char copyright[] =
void dhcp (packet) void dhcp (packet)
struct packet *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); 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 ();
} }

52
dhcpd.c
View File

@@ -50,7 +50,10 @@ static char copyright[] =
static void usage PROTO ((void)); static void usage PROTO ((void));
TIME cur_time; 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; u_int32_t *server_addrlist;
int server_addrcount; int server_addrcount;
u_int16_t server_port; u_int16_t server_port;
@@ -63,6 +66,7 @@ int main (argc, argv, envp)
int port = 0; int port = 0;
int i; int i;
struct sockaddr_in name; struct sockaddr_in name;
struct iaddr taddr;
u_int32_t *addrlist = (u_int32_t *)0; u_int32_t *addrlist = (u_int32_t *)0;
int addrcount = 0; int addrcount = 0;
struct tree *addrtree = (struct tree *)0; struct tree *addrtree = (struct tree *)0;
@@ -148,7 +152,23 @@ int main (argc, argv, envp)
} }
#endif #endif
taddr.len = 0;
server_addrlist = get_interface_list (&server_addrcount); 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 /* Listen on the specified (or default) port on each specified
(or default) IP address. */ (or default) IP address. */
@@ -164,6 +184,8 @@ int main (argc, argv, envp)
close (i); close (i);
} }
dump_subnets ();
/* Receive packets and dispatch them... */ /* Receive packets and dispatch them... */
dispatch (); dispatch ();
@@ -191,6 +213,7 @@ void do_packet (packbuf, len, from_port, from, sock)
{ {
struct packet *tp; struct packet *tp;
struct dhcp_packet *tdp; struct dhcp_packet *tdp;
struct iaddr ia;
if (!(tp = new_packet ("do_packet"))) if (!(tp = new_packet ("do_packet")))
return; return;
@@ -205,12 +228,29 @@ void do_packet (packbuf, len, from_port, from, sock)
tp -> client_port = from_port; tp -> client_port = from_port;
tp -> client_addr = from; tp -> client_addr = from;
tp -> client_sock = sock; tp -> client_sock = sock;
parse_options (tp);
if (tp -> options_valid && /* If this came through a gateway, find the corresponding subnet... */
tp -> options [DHO_DHCP_MESSAGE_TYPE].data) if (tp -> raw -> giaddr.s_addr) {
dhcp (tp); ia.len = 4;
else memcpy (ia.iabuf, &tp -> raw -> giaddr, 4);
bootp (tp); 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) void dump_packet (tp)

View 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 host minuet
hardware ethernet 08:00:2b:35:0c:18 hardware ethernet 08:00:2b:35:0c:18

17
dhcpd.h
View File

@@ -53,6 +53,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <ctype.h> #include <ctype.h>
#include <time.h>
#include "dhcp.h" #include "dhcp.h"
#include "cdefs.h" #include "cdefs.h"
@@ -70,6 +71,7 @@ struct packet {
int client_port; int client_port;
struct iaddr client_addr; struct iaddr client_addr;
int client_sock; int client_sock;
struct subnet *subnet;
struct { struct {
int len; int len;
unsigned char *data; unsigned char *data;
@@ -91,6 +93,10 @@ struct host_decl {
char *filename; char *filename;
char *server_name; char *server_name;
struct tree_cache *fixed_addr; 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]; struct tree_cache *options [256];
}; };
@@ -106,13 +112,18 @@ struct lease {
struct subnet *contain; struct subnet *contain;
struct hardware hardware_addr; struct hardware hardware_addr;
int state; int state;
int xid;
}; };
struct subnet { struct subnet {
struct subnet *next;
struct iaddr net; struct iaddr net;
struct iaddr netmask; struct iaddr netmask;
TIME default_lease_time;
TIME max_lease_time;
struct lease *leases; struct lease *leases;
struct lease *insertion_point; struct lease *insertion_point;
struct lease *last_lease;
}; };
/* Bitmask of dhcp option codes. */ /* Bitmask of dhcp option codes. */
@@ -162,6 +173,8 @@ int parse_warn PROTO ((char *, ...));
/* dhcpd.c */ /* dhcpd.c */
TIME cur_time; TIME cur_time;
TIME default_lease_time;
TIME max_lease_time;
extern u_int32_t *server_addrlist; extern u_int32_t *server_addrlist;
extern int server_addrcount; extern int server_addrcount;
extern u_int16_t server_port; extern u_int16_t server_port;
@@ -225,8 +238,11 @@ extern struct subnet *find_subnet (struct iaddr);
void enter_subnet (struct subnet *); void enter_subnet (struct subnet *);
void enter_lease PROTO ((struct lease *)); void enter_lease PROTO ((struct lease *));
void supersede_lease PROTO ((struct lease *, 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_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)); struct lease *find_lease_by_ip_addr PROTO ((struct iaddr));
void dump_subnets PROTO ((void));
/* alloc.c */ /* alloc.c */
VOIDPTR dmalloc PROTO ((int, char *)); VOIDPTR dmalloc PROTO ((int, char *));
@@ -251,6 +267,7 @@ void free_tree PROTO ((struct tree *, char *));
/* print.c */ /* print.c */
char *print_hw_addr PROTO ((int, int, unsigned char *)); char *print_hw_addr PROTO ((int, int, unsigned char *));
void print_lease PROTO ((struct lease *));
/* socket.c */ /* socket.c */
u_int32_t *get_interface_list PROTO ((int *)); u_int32_t *get_interface_list PROTO ((int *));

View File

@@ -64,7 +64,11 @@
#define LEASE 271 #define LEASE 271
#define RANGE 272 #define RANGE 272
#define PACKET 273 #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 && \ #define is_identifier(x) ((x) >= FIRST_TOKEN && \
(x) <= LAST_TOKEN && \ (x) <= LAST_TOKEN && \

4
hash.c
View File

@@ -103,6 +103,7 @@ void add_hash (table, name, len, pointer)
bp -> name = name; bp -> name = name;
bp -> value = pointer; bp -> value = pointer;
bp -> next = table -> buckets [hashno]; bp -> next = table -> buckets [hashno];
bp -> len = len;
table -> buckets [hashno] = bp; table -> buckets [hashno] = bp;
} }
@@ -140,10 +141,11 @@ unsigned char *hash_lookup (table, name, len)
struct hash_bucket *bp; struct hash_bucket *bp;
if (len) { if (len) {
for (bp = table -> buckets [hashno]; bp; bp = bp -> next) for (bp = table -> buckets [hashno]; bp; bp = bp -> next) {
if (len == bp -> len if (len == bp -> len
&& !memcmp (bp -> name, name, len)) && !memcmp (bp -> name, name, len))
return bp -> value; return bp -> value;
}
} else { } else {
for (bp = table -> buckets [hashno]; bp; bp = bp -> next) for (bp = table -> buckets [hashno]; bp; bp = bp -> next)
if (!strcmp (bp -> name, name)) if (!strcmp (bp -> name, name))

View File

@@ -53,6 +53,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <ctype.h> #include <ctype.h>
#include <time.h>
#include "dhcp.h" #include "dhcp.h"
#include "cdefs.h" #include "cdefs.h"
@@ -70,6 +71,7 @@ struct packet {
int client_port; int client_port;
struct iaddr client_addr; struct iaddr client_addr;
int client_sock; int client_sock;
struct subnet *subnet;
struct { struct {
int len; int len;
unsigned char *data; unsigned char *data;
@@ -91,6 +93,10 @@ struct host_decl {
char *filename; char *filename;
char *server_name; char *server_name;
struct tree_cache *fixed_addr; 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]; struct tree_cache *options [256];
}; };
@@ -106,13 +112,18 @@ struct lease {
struct subnet *contain; struct subnet *contain;
struct hardware hardware_addr; struct hardware hardware_addr;
int state; int state;
int xid;
}; };
struct subnet { struct subnet {
struct subnet *next;
struct iaddr net; struct iaddr net;
struct iaddr netmask; struct iaddr netmask;
TIME default_lease_time;
TIME max_lease_time;
struct lease *leases; struct lease *leases;
struct lease *insertion_point; struct lease *insertion_point;
struct lease *last_lease;
}; };
/* Bitmask of dhcp option codes. */ /* Bitmask of dhcp option codes. */
@@ -162,6 +173,8 @@ int parse_warn PROTO ((char *, ...));
/* dhcpd.c */ /* dhcpd.c */
TIME cur_time; TIME cur_time;
TIME default_lease_time;
TIME max_lease_time;
extern u_int32_t *server_addrlist; extern u_int32_t *server_addrlist;
extern int server_addrcount; extern int server_addrcount;
extern u_int16_t server_port; extern u_int16_t server_port;
@@ -225,8 +238,11 @@ extern struct subnet *find_subnet (struct iaddr);
void enter_subnet (struct subnet *); void enter_subnet (struct subnet *);
void enter_lease PROTO ((struct lease *)); void enter_lease PROTO ((struct lease *));
void supersede_lease PROTO ((struct lease *, 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_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)); struct lease *find_lease_by_ip_addr PROTO ((struct iaddr));
void dump_subnets PROTO ((void));
/* alloc.c */ /* alloc.c */
VOIDPTR dmalloc PROTO ((int, char *)); VOIDPTR dmalloc PROTO ((int, char *));
@@ -251,6 +267,7 @@ void free_tree PROTO ((struct tree *, char *));
/* print.c */ /* print.c */
char *print_hw_addr PROTO ((int, int, unsigned char *)); char *print_hw_addr PROTO ((int, int, unsigned char *));
void print_lease PROTO ((struct lease *));
/* socket.c */ /* socket.c */
u_int32_t *get_interface_list PROTO ((int *)); u_int32_t *get_interface_list PROTO ((int *));

View File

@@ -64,7 +64,11 @@
#define LEASE 271 #define LEASE 271
#define RANGE 272 #define RANGE 272
#define PACKET 273 #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 && \ #define is_identifier(x) ((x) >= FIRST_TOKEN && \
(x) <= LAST_TOKEN && \ (x) <= LAST_TOKEN && \

8
inet.c
View File

@@ -87,7 +87,7 @@ struct iaddr ip_addr (subnet, mask, host_address)
j = rv.len - sizeof habuf; j = rv.len - sizeof habuf;
for (i = sizeof habuf - 1; i >= 0; i--) { for (i = sizeof habuf - 1; i >= 0; i--) {
if (mask.iabuf [i + j]) { if (mask.iabuf [i + j]) {
if (habuf [i] > ~mask.iabuf [i + j]) { if (habuf [i] > (mask.iabuf [i + j] ^ 0xFF)) {
rv.len = 0; rv.len = 0;
return rv; return rv;
} }
@@ -97,10 +97,10 @@ struct iaddr ip_addr (subnet, mask, host_address)
return rv; return rv;
} }
} }
rv.iabuf [i + j] &= habuf [i]; rv.iabuf [i + j] |= habuf [i];
break; break;
} } else
rv.iabuf [i + j] = habuf [i]; rv.iabuf [i + j] = habuf [i];
} }
return rv; return rv;

123
memory.c
View File

@@ -48,7 +48,7 @@ static char copyright[] =
#include "dhcpd.h" #include "dhcpd.h"
static struct host_decl *hosts; 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_uid_hash;
static struct hash_table *lease_ip_addr_hash; static struct hash_table *lease_ip_addr_hash;
static struct hash_table *lease_hw_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 lease *address_range, *lp, *plp;
struct subnet *subnet; struct subnet *subnet;
struct iaddr net; struct iaddr net;
int i, max; int min, max, i;
char lowbuf [16], highbuf [16], netbuf [16]; char lowbuf [16], highbuf [16], netbuf [16];
/* Initialize the hash table if it hasn't been done yet. */ /* Initialize the hash table if it hasn't been done yet. */
if (!subnet_hash)
subnet_hash = new_hash ();
if (!lease_uid_hash) if (!lease_uid_hash)
lease_uid_hash = new_hash (); lease_uid_hash = new_hash ();
if (!lease_ip_addr_hash) if (!lease_ip_addr_hash)
@@ -130,32 +128,40 @@ void new_address_range (low, high, netmask)
subnet -> net = net; subnet -> net = net;
subnet -> netmask = netmask; subnet -> netmask = netmask;
subnet -> leases = (struct lease *)0; 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); enter_subnet (subnet);
} }
/* Get the high and low host addresses... */ /* Get the high and low host addresses... */
max = host_addr (high, netmask); 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. */ /* Allow range to be specified high-to-low as well as low-to-high. */
if (i > max) { if (min > max) {
max = i; max = min;
i = host_addr (high, netmask); min = host_addr (high, netmask);
} }
/* Get a lease structure for each address in the range. */ /* 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) { if (!address_range) {
strcpy (lowbuf, piaddr (low)); strcpy (lowbuf, piaddr (low));
strcpy (highbuf, piaddr (high)); strcpy (highbuf, piaddr (high));
error ("No memory for address range %s-%s.", lowbuf, highbuf); 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. */ /* 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 = 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].starts =
address_range [i].timestamp = MIN_TIME; address_range [i].timestamp = MIN_TIME;
address_range [i].ends = 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 subnet *find_subnet (addr)
struct iaddr subnet; struct iaddr addr;
{ {
struct subnet *rv; struct subnet *rv;
return (struct subnet *)hash_lookup (subnet_hash, for (rv = subnets; rv; rv = rv -> next) {
(char *)subnet.iabuf, subnet.len); if (addr_eq (subnet_number (addr, rv -> netmask), rv -> net))
return rv;
}
return (struct subnet *)0;
} }
/* Enter a new subnet into the subnet hash. */ /* Enter a new subnet into the subnet hash. */
@@ -214,8 +223,9 @@ struct subnet *find_subnet (subnet)
void enter_subnet (subnet) void enter_subnet (subnet)
struct subnet *subnet; struct subnet *subnet;
{ {
add_hash (subnet_hash, (char *)subnet -> net.iabuf, /* XXX Sort the nets into a balanced tree to make searching quicker. */
subnet -> net.len, (unsigned char *)subnet); subnet -> next = subnets;
subnets = subnet;
} }
/* Enter a lease into the system. This is called by the parser each /* 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 subnet *parent;
struct lease *lp; 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 /* If the existing lease hasn't expired and has a different
unique identifier or, if it doesn't have a unique unique identifier or, if it doesn't have a unique
identifier, a different hardware address, then the two identifier, a different hardware address, then the two
@@ -290,7 +305,9 @@ void supersede_lease (comp, lease)
enter_uid = 1; enter_uid = 1;
} }
free (comp -> uid); free (comp -> uid);
} } else
enter_uid = 1;
if (comp -> hardware_addr.htype && if (comp -> hardware_addr.htype &&
((comp -> hardware_addr.hlen != ((comp -> hardware_addr.hlen !=
lease -> hardware_addr.hlen) || lease -> hardware_addr.hlen) ||
@@ -303,7 +320,8 @@ void supersede_lease (comp, lease)
comp -> hardware_addr.haddr, comp -> hardware_addr.haddr,
comp -> hardware_addr.hlen); comp -> hardware_addr.hlen);
enter_hwaddr = 1; enter_hwaddr = 1;
} } else if (!comp -> hardware_addr.htype)
enter_hwaddr = 1;
/* Copy the data files, but not the linkages. */ /* Copy the data files, but not the linkages. */
comp -> starts = lease -> starts; comp -> starts = lease -> starts;
@@ -317,16 +335,16 @@ void supersede_lease (comp, lease)
/* Record the lease in the uid hash if necessary. */ /* Record the lease in the uid hash if necessary. */
if (enter_uid && lease -> uid) { if (enter_uid && lease -> uid) {
add_hash (lease_uid_hash, lease -> uid, add_hash (lease_uid_hash, comp -> uid,
lease -> uid_len, (unsigned char *)lease); comp -> uid_len, (unsigned char *)comp);
} }
/* Record it in the hardware address hash if necessary. */ /* Record it in the hardware address hash if necessary. */
if (enter_hwaddr && lease -> hardware_addr.htype) { if (enter_hwaddr && lease -> hardware_addr.htype) {
add_hash (lease_hw_addr_hash, add_hash (lease_hw_addr_hash,
lease -> hardware_addr.haddr, comp -> hardware_addr.haddr,
lease -> hardware_addr.hlen, comp -> hardware_addr.hlen,
(unsigned char *)lease); (unsigned char *)comp);
} }
/* Remove the lease from its current place in the list. */ /* Remove the lease from its current place in the list. */
@@ -338,6 +356,9 @@ void supersede_lease (comp, lease)
if (comp -> next) { if (comp -> next) {
comp -> next -> prev = comp -> prev; comp -> next -> prev = comp -> prev;
} }
if (comp -> contain -> last_lease == comp) {
comp -> contain -> last_lease = comp -> prev;
}
/* Find the last insertion point... */ /* Find the last insertion point... */
if (comp == comp -> contain -> 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 /* Nothing on the list yet? Just make comp the
head of the list. */ head of the list. */
comp -> contain -> leases = comp; 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 /* Skip down the list until we run out of list
or find a place for comp. */ or find a place for comp. */
while (lp -> next && lp -> ends < comp -> ends) { while (lp -> next && lp -> ends > comp -> ends) {
lp = lp -> next; lp = lp -> next;
} }
if (lp -> ends < comp -> ends) { if (lp -> ends > comp -> ends) {
/* If we ran out of list, put comp /* If we ran out of list, put comp
at the end. */ at the end. */
lp -> next = comp; lp -> next = comp;
comp -> prev = lp; comp -> prev = lp;
comp -> next = (struct lease *)0; comp -> next = (struct lease *)0;
comp -> contain -> last_lease = comp;
} else { } else {
/* If we didn't, put it between lp and /* If we didn't, put it between lp and
the previous item on the list. */ the previous item on the list. */
@@ -372,12 +395,12 @@ void supersede_lease (comp, lease)
lp -> prev = comp; lp -> prev = comp;
} }
} else { } 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. */ or find a place for comp. */
while (lp -> prev && lp -> ends > comp -> ends) { while (lp -> prev && lp -> ends < comp -> ends) {
lp = lp -> prev; lp = lp -> prev;
} }
if (lp -> ends > comp -> ends) { if (lp -> ends < comp -> ends) {
/* If we ran out of list, put comp /* If we ran out of list, put comp
at the beginning. */ at the beginning. */
lp -> prev = comp; 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... */ /* Locate the lease associated with a given IP address... */
struct lease *find_lease_by_ip_addr (addr) struct lease *find_lease_by_ip_addr (addr)
@@ -417,3 +452,29 @@ struct lease *find_lease_by_uid (uid, len)
return lease; 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);
}
}

View File

@@ -94,8 +94,6 @@ void parse_option_buffer (packet, buffer, length)
int len; int len;
int code; 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; ) { for (s = buffer; *s != DHO_END && s < end; ) {
code = s [0]; code = s [0];
/* Pad options don't have a length - just skip them. */ /* 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; t [len] = 0;
packet -> options [code].len = len; packet -> options [code].len = len;
packet -> options [code].data = t; packet -> options [code].data = t;
printf ("%s=%s\n", dhcp_options [code].name,
pretty_print_option (code, t, len));
} else { } else {
/* If it's a repeat, concatenate it to whatever /* If it's a repeat, concatenate it to whatever
we last saw. This is really only required we last saw. This is really only required

45
print.c
View File

@@ -55,13 +55,46 @@ char *print_hw_addr (htype, hlen, data)
char *s; char *s;
int i; int i;
s = habuf; if (htype == 0 || hlen == 0) {
for (i = 0; i < hlen; i++) { strcpy (habuf, "<null>");
sprintf (s, "%x", data [i]); } else {
s += strlen (s); s = habuf;
*s++ = ':'; for (i = 0; i < hlen; i++) {
sprintf (s, "%x", data [i]);
s += strlen (s);
*s++ = ':';
}
*--s = 0;
} }
*--s = 0;
return habuf; 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);
}

View File

@@ -234,6 +234,22 @@ void parse_host_decl (cfile, bc, decl)
case OPTION: case OPTION:
parse_option_decl (cfile, bc, decl); parse_option_decl (cfile, bc, decl);
break; 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: default:
parse_warn ("expecting a dhcp option declaration."); parse_warn ("expecting a dhcp option declaration.");
skip_to_semi (cfile); skip_to_semi (cfile);

View File

@@ -49,5 +49,205 @@ static char copyright[] =
void dhcp (packet) void dhcp (packet)
struct packet *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); 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 ();
} }

View File

@@ -50,7 +50,10 @@ static char copyright[] =
static void usage PROTO ((void)); static void usage PROTO ((void));
TIME cur_time; 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; u_int32_t *server_addrlist;
int server_addrcount; int server_addrcount;
u_int16_t server_port; u_int16_t server_port;
@@ -63,6 +66,7 @@ int main (argc, argv, envp)
int port = 0; int port = 0;
int i; int i;
struct sockaddr_in name; struct sockaddr_in name;
struct iaddr taddr;
u_int32_t *addrlist = (u_int32_t *)0; u_int32_t *addrlist = (u_int32_t *)0;
int addrcount = 0; int addrcount = 0;
struct tree *addrtree = (struct tree *)0; struct tree *addrtree = (struct tree *)0;
@@ -148,7 +152,23 @@ int main (argc, argv, envp)
} }
#endif #endif
taddr.len = 0;
server_addrlist = get_interface_list (&server_addrcount); 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 /* Listen on the specified (or default) port on each specified
(or default) IP address. */ (or default) IP address. */
@@ -164,6 +184,8 @@ int main (argc, argv, envp)
close (i); close (i);
} }
dump_subnets ();
/* Receive packets and dispatch them... */ /* Receive packets and dispatch them... */
dispatch (); dispatch ();
@@ -191,6 +213,7 @@ void do_packet (packbuf, len, from_port, from, sock)
{ {
struct packet *tp; struct packet *tp;
struct dhcp_packet *tdp; struct dhcp_packet *tdp;
struct iaddr ia;
if (!(tp = new_packet ("do_packet"))) if (!(tp = new_packet ("do_packet")))
return; return;
@@ -205,12 +228,29 @@ void do_packet (packbuf, len, from_port, from, sock)
tp -> client_port = from_port; tp -> client_port = from_port;
tp -> client_addr = from; tp -> client_addr = from;
tp -> client_sock = sock; tp -> client_sock = sock;
parse_options (tp);
if (tp -> options_valid && /* If this came through a gateway, find the corresponding subnet... */
tp -> options [DHO_DHCP_MESSAGE_TYPE].data) if (tp -> raw -> giaddr.s_addr) {
dhcp (tp); ia.len = 4;
else memcpy (ia.iabuf, &tp -> raw -> giaddr, 4);
bootp (tp); 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) void dump_packet (tp)

View 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 host minuet
hardware ethernet 08:00:2b:35:0c:18 hardware ethernet 08:00:2b:35:0c:18

View File

@@ -184,6 +184,9 @@ void dispatch ()
/* Wait for a packet or a timeout... XXX */ /* Wait for a packet or a timeout... XXX */
count = select (max + 1, &r, &w, &x, (struct timeval *)0); count = select (max + 1, &r, &w, &x, (struct timeval *)0);
/* Get the current time... */
GET_TIME (&cur_time);
/* Not likely to be transitory... */ /* Not likely to be transitory... */
if (count < 0) if (count < 0)
error ("select: %m"); error ("select: %m");