2
0
mirror of https://gitlab.isc.org/isc-projects/dhcp synced 2025-09-01 23:05:29 +00:00

shared net support; static dhcp address assignment; dynamic bootp support

This commit is contained in:
Ted Lemon
1996-05-22 07:21:50 +00:00
parent bd11271c37
commit 7a049f2ccd
2 changed files with 872 additions and 440 deletions

656
dhcp.c
View File

@@ -82,24 +82,49 @@ void dhcpdiscover (packet)
struct packet *packet; struct packet *packet;
{ {
struct lease *lease = find_lease (packet); struct lease *lease = find_lease (packet);
struct host_decl *hp;
note ("Received DHCPDISCOVER from %s", note ("DHCPDISCOVER from %s",
print_hw_addr (packet -> raw -> htype, print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen, packet -> raw -> hlen,
packet -> raw -> chaddr)); packet -> raw -> chaddr));
/* If we didn't find a lease, try to allocate one... */ /* If we didn't find a lease, try to allocate one... */
if (!lease) { if (!lease) {
lease = packet -> subnet -> last_lease; lease = packet -> shared_network -> last_lease;
/* If there are no leases in that subnet that have /* If there are no leases in that subnet that have
expired, we have nothing to offer this client. */ expired, we have nothing to offer this client. */
if (lease -> ends >= cur_time) { if (lease -> ends > cur_time) {
note ("no free leases on subnet %s", note ("no free leases on subnet %s",
piaddr (packet -> subnet -> net)); packet -> shared_network -> name);
return; return;
} }
lease -> host = (struct host_decl *)0;
/* Try to find a host_decl that matches the client
identifier or hardware address on the packet, and
has no fixed IP address. If there is one, hang
it off the lease so that its option definitions
can be used. */
if (((packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len
!= 0) &&
((hp = find_hosts_by_uid
(packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].data,
packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len))
!= (struct host_decl *)0)) ||
((hp = find_hosts_by_haddr (packet -> raw -> htype,
packet -> raw -> chaddr,
packet -> raw -> hlen))
!= (struct host_decl *)0)) {
for (; hp; hp = hp -> n_ipaddr) {
if (!hp -> fixed_addr) {
lease -> host = hp;
break;
}
}
} else {
lease -> host = (struct host_decl *)0;
}
} }
ack_lease (packet, lease, DHCPOFFER, cur_time + 120); ack_lease (packet, lease, DHCPOFFER, cur_time + 120);
@@ -110,6 +135,8 @@ void dhcprequest (packet)
{ {
struct lease *lease = find_lease (packet); struct lease *lease = find_lease (packet);
struct iaddr cip; struct iaddr cip;
struct subnet *subnet;
struct lease *ip_lease;
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) { if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
cip.len = 4; cip.len = 4;
@@ -121,29 +148,23 @@ void dhcprequest (packet)
memcpy (cip.iabuf, &packet -> raw -> ciaddr.s_addr, 4); memcpy (cip.iabuf, &packet -> raw -> ciaddr.s_addr, 4);
} }
note ("Received DHCPREQUEST from %s for %s", note ("DHCPREQUEST for %s from %s",
print_hw_addr (packet -> raw -> htype, piaddr (cip),
packet -> raw -> hlen, print_hw_addr (packet -> raw -> htype,
packet -> raw -> chaddr), packet -> raw -> hlen,
piaddr (cip)); packet -> raw -> chaddr));
/* If a client on our local network wants to renew a lease on /* If a client on our local network wants to renew a lease on
an address off our local network, NAK it. */ an address off our local network, NAK it. */
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) { if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
if (!addr_eq (packet -> subnet -> net, subnet = find_grouped_subnet (packet -> shared_network, cip);
subnet_number (cip, if (!subnet) {
packet -> subnet -> netmask))) {
nak_lease (packet, &cip); nak_lease (packet, &cip);
return; return;
} }
} } else if (packet -> raw -> ciaddr.s_addr) {
subnet = find_grouped_subnet (packet -> shared_network, cip);
if (packet -> raw -> ciaddr.s_addr) { if (!subnet) {
cip.len = 4;
memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4);
if (!addr_eq (packet -> subnet -> net,
subnet_number (cip,
packet -> subnet -> netmask))) {
nak_lease (packet, &cip); nak_lease (packet, &cip);
return; return;
} }
@@ -151,12 +172,29 @@ void dhcprequest (packet)
/* Look for server identifier... */ /* Look for server identifier... */
if (packet -> options [DHO_DHCP_SERVER_IDENTIFIER].len) { if (packet -> options [DHO_DHCP_SERVER_IDENTIFIER].len) {
/* If there is one, and it isn't this server, and /* If we own the lease that the client is asking for,
we have a lease for this client, let it go. */ and it's already been assigned to the client,
ack it regardless. */
if ((lease -> uid_len && lease -> uid_len ==
packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len &&
!memcmp (packet -> options
[DHO_DHCP_CLIENT_IDENTIFIER].data,
lease -> uid, lease -> uid_len)) ||
(lease -> hardware_addr.hlen == packet -> raw -> hlen &&
lease -> hardware_addr.htype == packet -> raw -> htype &&
!memcmp (lease -> hardware_addr.haddr,
packet -> raw -> chaddr,
packet -> raw -> hlen))) {
ack_lease (packet, lease, DHCPACK, 0);
return;
}
/* Otherwise, if we have a lease for this client,
release it, and in any case don't reply to the
DHCPREQUEST. */
if (memcmp (packet -> if (memcmp (packet ->
options [DHO_DHCP_SERVER_IDENTIFIER].data, options [DHO_DHCP_SERVER_IDENTIFIER].data,
packet -> interface -> address.iabuf, server_identifier.iabuf, server_identifier.len)) {
packet -> interface -> address.len)) {
if (lease) if (lease)
release_lease (lease); release_lease (lease);
return; return;
@@ -179,11 +217,11 @@ void dhcprelease (packet)
{ {
struct lease *lease = find_lease (packet); struct lease *lease = find_lease (packet);
note ("Received DHCPRELEASE from %s for %s", note ("DHCPRELEASE of %s from %s",
inet_ntoa (packet -> raw -> ciaddr),
print_hw_addr (packet -> raw -> htype, print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen, packet -> raw -> hlen,
packet -> raw -> chaddr), packet -> raw -> chaddr));
inet_ntoa (packet -> raw -> ciaddr));
/* If we found a lease, release it. */ /* If we found a lease, release it. */
if (lease) { if (lease) {
@@ -206,11 +244,11 @@ void dhcpdecline (packet)
cip.len = 0; cip.len = 0;
} }
note ("Received DHCPDECLINE from %s for %s", note ("DHCPDECLINE on %s from %s",
piaddr (cip),
print_hw_addr (packet -> raw -> htype, print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen, packet -> raw -> hlen,
packet -> raw -> chaddr), packet -> raw -> chaddr));
piaddr (cip));
/* If we found a lease, mark it as unusable and complain. */ /* If we found a lease, mark it as unusable and complain. */
if (lease) { if (lease) {
@@ -221,10 +259,7 @@ void dhcpdecline (packet)
void dhcpinform (packet) void dhcpinform (packet)
struct packet *packet; struct packet *packet;
{ {
note ("Received DHCPINFORM from %s for %s", note ("DHCPINFORM from %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr),
inet_ntoa (packet -> raw -> ciaddr)); inet_ntoa (packet -> raw -> ciaddr));
} }
@@ -274,7 +309,7 @@ void nak_lease (packet, cip)
cons_options (packet, &outgoing, options, 0); cons_options (packet, &outgoing, options, 0);
/* memset (&raw.ciaddr, 0, sizeof raw.ciaddr);*/ /* memset (&raw.ciaddr, 0, sizeof raw.ciaddr);*/
memcpy (&raw.siaddr, packet -> interface -> address.iabuf, 4); memcpy (&raw.siaddr, server_identifier.iabuf, 4);
raw.giaddr = packet -> raw -> giaddr; raw.giaddr = packet -> raw -> giaddr;
memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr); memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
raw.hlen = packet -> raw -> hlen; raw.hlen = packet -> raw -> hlen;
@@ -286,38 +321,12 @@ void nak_lease (packet, cip)
raw.hops = packet -> raw -> hops; raw.hops = packet -> raw -> hops;
raw.op = BOOTREPLY; raw.op = BOOTREPLY;
/* If this was gatewayed, send it back to the gateway. /* Report what we're sending... */
Otherwise, broadcast it on the local network. */ note ("DHCPNAK on %s to %s",
if (raw.giaddr.s_addr) { piaddr (*cip),
to.sin_addr = raw.giaddr; print_hw_addr (packet -> raw -> htype,
to.sin_port = server_port; packet -> raw -> hlen,
} else { packet -> raw -> chaddr));
to.sin_addr.s_addr = htonl (INADDR_BROADCAST);
to.sin_port = packet->client_port;
}
to.sin_family = AF_INET;
#ifdef HAVE_SA_LEN
to.sin_len = sizeof to;
#endif
memset (to.sin_zero, 0, sizeof to.sin_zero);
note ("Sending DHCPNAK to %s at IP address %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr),
inet_ntoa (to.sin_addr), htons (to.sin_port));
hto.htype = packet -> raw -> htype;
hto.hlen = packet -> raw -> hlen;
memcpy (hto.haddr, packet -> raw -> chaddr, hto.hlen);
errno = 0;
result = send_packet (packet -> interface,
packet, &raw, outgoing.packet_length,
&to, (struct hardware *)0);
if (result < 0)
warn ("sendpkt: %m");
#ifdef DEBUG_PACKET #ifdef DEBUG_PACKET
dump_packet (packet); dump_packet (packet);
@@ -325,6 +334,43 @@ void nak_lease (packet, cip)
dump_packet (&outgoing); dump_packet (&outgoing);
dump_raw ((unsigned char *)&raw, outgoing.packet_length); dump_raw ((unsigned char *)&raw, outgoing.packet_length);
#endif #endif
hto.htype = packet -> raw -> htype;
hto.hlen = packet -> raw -> hlen;
memcpy (hto.haddr, packet -> raw -> chaddr, hto.hlen);
/* Set up the common stuff... */
to.sin_family = AF_INET;
#ifdef HAVE_SA_LEN
to.sin_len = sizeof to;
#endif
memset (to.sin_zero, 0, sizeof to.sin_zero);
/* If this was gatewayed, send it back to the gateway.
Otherwise, broadcast it on the local network. */
if (raw.giaddr.s_addr) {
to.sin_addr = raw.giaddr;
to.sin_port = server_port;
#ifdef USE_FALLBACK
result = send_fallback (&fallback_interface,
packet, &raw, outgoing.packet_length,
raw.siaddr, &to, &hto);
if (result < 0)
warn ("send_fallback: %m");
return;
#endif
} else {
to.sin_addr.s_addr = htonl (INADDR_BROADCAST);
to.sin_port = packet->client_port;
}
errno = 0;
result = send_packet (packet -> interface,
packet, &raw, outgoing.packet_length,
raw.siaddr, &to, (struct hardware *)0);
if (result < 0)
warn ("send_packet: %m");
} }
void ack_lease (packet, lease, offer, when) void ack_lease (packet, lease, offer, when)
@@ -353,6 +399,7 @@ void ack_lease (packet, lease, offer, when)
struct class *vendor_class, *user_class; struct class *vendor_class, *user_class;
char *filename; char *filename;
char *server_name;
int i; int i;
if (packet -> options [DHO_DHCP_CLASS_IDENTIFIER].len) { if (packet -> options [DHO_DHCP_CLASS_IDENTIFIER].len) {
@@ -377,12 +424,25 @@ void ack_lease (packet, lease, offer, when)
user_class = (struct class *)0; user_class = (struct class *)0;
} }
if (user_class && user_class -> filename) /* Choose a filename; first from the host_decl, if any, then from
the user class, then from the vendor class. */
if (lease -> host -> filename)
filename = lease -> host -> filename;
else if (user_class && user_class -> filename)
filename = user_class -> filename; filename = user_class -> filename;
else if (vendor_class && vendor_class -> filename) else if (vendor_class && vendor_class -> filename)
filename = vendor_class -> filename; filename = vendor_class -> filename;
else filename = (char *)0; else filename = (char *)0;
/* Choose a server name as above. */
if (lease -> host -> server_name)
server_name = lease -> host -> server_name;
else if (user_class && user_class -> server_name)
server_name = user_class -> server_name;
else if (vendor_class && vendor_class -> server_name)
server_name = vendor_class -> server_name;
else server_name = (char *)0;
/* At this point, we have a lease that we can offer the client. /* At this point, we have a lease that we can offer the client.
Now we construct a lease structure that contains what we want, Now we construct a lease structure that contains what we want,
and call supersede_lease to do the right thing with it. */ and call supersede_lease to do the right thing with it. */
@@ -396,23 +456,45 @@ void ack_lease (packet, lease, offer, when)
/* Start now. */ /* Start now. */
lt.starts = cur_time; lt.starts = cur_time;
/* Figure out how long a lease to assign. */ /* Figure out how long a lease to assign. If this is a
if (packet -> options [DHO_DHCP_LEASE_TIME].len == 4) { dynamic BOOTP lease, its duration must be infinite. */
lease_time = getULong (packet -> if (offer) {
options [DHO_DHCP_LEASE_TIME].data); if (packet -> options [DHO_DHCP_LEASE_TIME].len == 4) {
lease_time = getULong
/* Don't let the client ask for a longer lease than (packet -> options [DHO_DHCP_LEASE_TIME].data);
is supported for this subnet. */
if (lease_time > packet -> subnet -> max_lease_time) /* Don't let the client ask for a longer lease than
lease_time = packet -> subnet -> max_lease_time; is supported for this subnet or host. */
} else if (lease -> host && lease -> host -> max_lease_time) {
lease_time = packet -> subnet -> default_lease_time; if (lease_time >
lease -> host -> max_lease_time)
lt.offered_expiry = cur_time + lease_time; lease_time = (lease -> host ->
if (when) max_lease_time);
lt.ends = when; } else {
else if (lease_time >
lt.ends = lt.offered_expiry; lease -> subnet -> max_lease_time)
lease_time = (lease -> subnet ->
max_lease_time);
}
} else {
if (lease -> host
&& lease -> host -> default_lease_time)
lease_time = (lease -> host ->
default_lease_time);
else
lease_time = (lease -> subnet ->
default_lease_time);
}
lt.offered_expiry = cur_time + lease_time;
if (when)
lt.ends = when;
else
lt.ends = lt.offered_expiry;
} else {
lt.offered_expiry = lt.ends = MAX_TIME;
lt.flags = BOOTP_LEASE;
}
lt.timestamp = cur_time; lt.timestamp = cur_time;
@@ -432,18 +514,23 @@ void ack_lease (packet, lease, offer, when)
memcpy (lt.hardware_addr.haddr, packet -> raw -> chaddr, memcpy (lt.hardware_addr.haddr, packet -> raw -> chaddr,
packet -> raw -> hlen); packet -> raw -> hlen);
lt.host = lease -> host; /* XXX */ lt.host = lease -> host;
lt.contain = lease -> contain; lt.subnet = lease -> subnet;
lt.shared_network = lease -> shared_network;
/* Record the transaction id... */ /* Record the transaction id... */
lt.xid = packet -> raw -> xid; lt.xid = packet -> raw -> xid;
/* Don't call supersede_lease on a mocked-up lease. */
if (lease -> flags & STATIC_LEASE)
;
else
/* Install the new information about this lease in the database. /* Install the new information about this lease in the database.
If this is a DHCPACK and we can't write the lease, don't If this is a DHCPACK or a dynamic BOOTREPLY and we can't write
ACK it either. */ the lease, don't ACK it (or BOOTREPLY it) either. */
if (!(supersede_lease (lease, &lt, offer == DHCPACK) if (!(supersede_lease (lease, &lt, !offer || offer == DHCPACK)
|| offer != DHCPACK)) || (offer && offer != DHCPACK)))
return; return;
/* Send a response to the client... */ /* Send a response to the client... */
@@ -460,100 +547,135 @@ void ack_lease (packet, lease, offer, when)
/* Copy in the server name if given; otherwise, flag the /* Copy in the server name if given; otherwise, flag the
server_name buffer as available for options. */ server_name buffer as available for options. */
bufs |= 2; /* XXX */ if (server_name)
strncpy (raw.sname, server_name, sizeof raw.sname);
else
bufs |= 2; /* XXX */
memcpy (raw.chaddr, packet -> raw -> chaddr, packet -> raw -> hlen); memcpy (raw.chaddr, packet -> raw -> chaddr, packet -> raw -> hlen);
raw.hlen = packet -> raw -> hlen; raw.hlen = packet -> raw -> hlen;
raw.htype = packet -> raw -> htype; raw.htype = packet -> raw -> htype;
/* Start out with the subnet options... */ /* Start out with the subnet options... */
memcpy (options, packet -> subnet -> options, sizeof options); memcpy (options, lease -> subnet -> options, sizeof options);
/* If we have a vendor class, install those options, superceding /* Vendor and user classes are only supported for DHCP clients. */
any subnet options. */ if (offer) {
if (vendor_class) { /* If we have a vendor class, install those options,
superseding any subnet options. */
if (vendor_class) {
for (i = 0; i < 256; i++)
if (vendor_class -> options [i])
options [i] =
vendor_class -> options [i];
}
/* If we have a user class, install those options,
superseding any subnet and vendor class options. */
if (user_class) {
for (i = 0; i < 256; i++)
if (user_class -> options [i])
options [i] =
user_class -> options [i];
}
}
/* If we have a host_decl structure, install the associated
options, superseding anything that's in the way. */
if (lease -> host) {
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++)
if (vendor_class -> options [i]) if (lease -> host -> options [i])
options [i] = vendor_class -> options [i]; options [i] = lease -> host -> options [i];
} }
/* If we have a user class, install those options, superceding /* Now, if appropriate, put in DHCP-specific options that
any subnet and vendor class options. */ override those. */
if (user_class) { if (offer) {
for (i = 0; i < 256; i++) options [DHO_DHCP_MESSAGE_TYPE] = &dhcpoffer_tree;
if (user_class -> options [i]) options [DHO_DHCP_MESSAGE_TYPE] -> value = &offer;
options [i] = user_class -> options [i]; options [DHO_DHCP_MESSAGE_TYPE] -> len = sizeof offer;
} options [DHO_DHCP_MESSAGE_TYPE] -> buf_size = sizeof offer;
options [DHO_DHCP_MESSAGE_TYPE] -> timeout = 0xFFFFFFFF;
options [DHO_DHCP_MESSAGE_TYPE] -> tree = (struct tree *)0;
/* Now put in options that override those. */ options [DHO_DHCP_SERVER_IDENTIFIER] = &server_id_tree;
options [DHO_DHCP_MESSAGE_TYPE] = &dhcpoffer_tree; options [DHO_DHCP_SERVER_IDENTIFIER] ->
options [DHO_DHCP_MESSAGE_TYPE] -> value = &offer; value = server_identifier.iabuf;
options [DHO_DHCP_MESSAGE_TYPE] -> len = sizeof offer; options [DHO_DHCP_SERVER_IDENTIFIER] ->
options [DHO_DHCP_MESSAGE_TYPE] -> buf_size = sizeof offer; len = server_identifier.len;
options [DHO_DHCP_MESSAGE_TYPE] -> timeout = 0xFFFFFFFF; options [DHO_DHCP_SERVER_IDENTIFIER] ->
options [DHO_DHCP_MESSAGE_TYPE] -> tree = (struct tree *)0; buf_size = server_identifier.len;
options [DHO_DHCP_SERVER_IDENTIFIER] ->
timeout = 0xFFFFFFFF;
options [DHO_DHCP_SERVER_IDENTIFIER] ->
tree = (struct tree *)0;
options [DHO_DHCP_SERVER_IDENTIFIER] = &server_id_tree; /* Sanity check the lease time. */
options [DHO_DHCP_SERVER_IDENTIFIER] -> value = if ((lease->offered_expiry - cur_time) < 0)
packet -> interface -> address.iabuf; putULong (lease_time_buf,
options [DHO_DHCP_SERVER_IDENTIFIER] -> len = lease -> subnet -> default_lease_time);
packet -> interface -> address.len; else if (lease -> offered_expiry - cur_time >
options [DHO_DHCP_SERVER_IDENTIFIER] -> buf_size = lease -> subnet -> max_lease_time)
packet -> interface -> address.len; putULong (lease_time_buf,
options [DHO_DHCP_SERVER_IDENTIFIER] -> timeout = 0xFFFFFFFF; lease -> subnet -> max_lease_time);
options [DHO_DHCP_SERVER_IDENTIFIER] -> tree = (struct tree *)0; else
putULong (lease_time_buf,
lease -> offered_expiry - cur_time);
/* If we used the vendor class the client specified, we have to
return it. */
if (vendor_class) {
options [DHO_DHCP_CLASS_IDENTIFIER] = &vendor_class_tree;
options [DHO_DHCP_CLASS_IDENTIFIER] -> value =
(unsigned char *)vendor_class -> name;
options [DHO_DHCP_CLASS_IDENTIFIER] -> len =
strlen (vendor_class -> name);
options [DHO_DHCP_CLASS_IDENTIFIER] -> buf_size =
strlen (vendor_class -> name);
options [DHO_DHCP_CLASS_IDENTIFIER] -> timeout = 0xFFFFFFFF;
options [DHO_DHCP_CLASS_IDENTIFIER] -> tree = (struct tree *)0;
}
/* If we used the user class the client specified, we have to return
it. */
if (user_class) {
options [DHO_DHCP_USER_CLASS_ID] = &user_class_tree;
options [DHO_DHCP_USER_CLASS_ID] -> value =
(unsigned char *)user_class -> name;
options [DHO_DHCP_USER_CLASS_ID] -> len =
strlen (user_class -> name);
options [DHO_DHCP_USER_CLASS_ID] -> buf_size =
strlen (user_class -> name);
options [DHO_DHCP_USER_CLASS_ID] -> timeout = 0xFFFFFFFF;
options [DHO_DHCP_USER_CLASS_ID] -> tree = (struct tree *)0;
}
/* Sanity check the lease time. */
if ((lease->offered_expiry - cur_time) < 0)
putULong (lease_time_buf,
packet -> subnet -> default_lease_time);
else if (lease -> offered_expiry - cur_time >
packet -> subnet -> max_lease_time)
putULong (lease_time_buf, packet -> subnet -> max_lease_time);
else
putULong (lease_time_buf, lease -> offered_expiry - cur_time); putULong (lease_time_buf, lease -> offered_expiry - cur_time);
options [DHO_DHCP_LEASE_TIME] = &lease_time_tree;
options [DHO_DHCP_LEASE_TIME] -> value = lease_time_buf;
options [DHO_DHCP_LEASE_TIME] -> len = sizeof lease_time_buf;
options [DHO_DHCP_LEASE_TIME] ->
buf_size = sizeof lease_time_buf;
options [DHO_DHCP_LEASE_TIME] -> timeout = 0xFFFFFFFF;
options [DHO_DHCP_LEASE_TIME] -> tree = (struct tree *)0;
putULong (lease_time_buf, lease -> offered_expiry - cur_time); /* If we used the vendor class the client specified, we
options [DHO_DHCP_LEASE_TIME] = &lease_time_tree; have to return it. */
options [DHO_DHCP_LEASE_TIME] -> value = lease_time_buf; if (vendor_class) {
options [DHO_DHCP_LEASE_TIME] -> len = sizeof lease_time_buf; options [DHO_DHCP_CLASS_IDENTIFIER] =
options [DHO_DHCP_LEASE_TIME] -> buf_size = sizeof lease_time_buf; &vendor_class_tree;
options [DHO_DHCP_LEASE_TIME] -> timeout = 0xFFFFFFFF; options [DHO_DHCP_CLASS_IDENTIFIER] ->
options [DHO_DHCP_LEASE_TIME] -> tree = (struct tree *)0; value = (unsigned char *)vendor_class -> name;
options [DHO_DHCP_CLASS_IDENTIFIER] ->
len = strlen (vendor_class -> name);
options [DHO_DHCP_CLASS_IDENTIFIER] ->
buf_size = strlen (vendor_class -> name);
options [DHO_DHCP_CLASS_IDENTIFIER] ->
timeout = 0xFFFFFFFF;
options [DHO_DHCP_CLASS_IDENTIFIER] ->
tree = (struct tree *)0;
}
/* If we used the user class the client specified, we
have to return it. */
if (user_class) {
options [DHO_DHCP_USER_CLASS_ID] = &user_class_tree;
options [DHO_DHCP_USER_CLASS_ID] ->
value = (unsigned char *)user_class -> name;
options [DHO_DHCP_USER_CLASS_ID] ->
len = strlen (user_class -> name);
options [DHO_DHCP_USER_CLASS_ID] ->
buf_size = strlen (user_class -> name);
options [DHO_DHCP_USER_CLASS_ID] ->
timeout = 0xFFFFFFFF;
options [DHO_DHCP_USER_CLASS_ID] ->
tree = (struct tree *)0;
}
}
cons_options (packet, &outgoing, options, bufs); cons_options (packet, &outgoing, options, bufs);
raw.ciaddr = packet -> raw -> ciaddr; raw.ciaddr = packet -> raw -> ciaddr;
memcpy (&raw.yiaddr, lease -> ip_addr.iabuf, 4); memcpy (&raw.yiaddr, lease -> ip_addr.iabuf, 4);
memcpy (&raw.siaddr, packet -> interface -> address.iabuf, 4); if (lease -> subnet -> interface_address.len)
memcpy (&raw.siaddr,
lease -> subnet -> interface_address.iabuf, 4);
else
memcpy (&raw.siaddr, server_identifier.iabuf, 4);
raw.giaddr = packet -> raw -> giaddr; raw.giaddr = packet -> raw -> giaddr;
raw.xid = packet -> raw -> xid; raw.xid = packet -> raw -> xid;
@@ -562,25 +684,20 @@ void ack_lease (packet, lease, offer, when)
raw.hops = packet -> raw -> hops; raw.hops = packet -> raw -> hops;
raw.op = BOOTREPLY; raw.op = BOOTREPLY;
/* If this was gatewayed, send it back to the gateway... */ /* Say what we're doing... */
if (raw.giaddr.s_addr) { note ("%s on %s to %s",
to.sin_addr = raw.giaddr; (offer
to.sin_port = server_port; ? (offer == DHCPACK ? "DHCPACK" : "DHCPOFFER")
: "BOOTREPLY"),
piaddr (lease -> ip_addr),
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr));
/* If it comes from a client who already knows its address, /* Set up the hardware address... */
sent it directly to that client. */ hto.htype = packet -> raw -> htype;
} else if (raw.ciaddr.s_addr && offer == DHCPACK) { hto.hlen = packet -> raw -> hlen;
to.sin_addr = packet -> raw -> ciaddr; memcpy (hto.haddr, packet -> raw -> chaddr, hto.hlen);
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
/* Otherwise, if we can (we can't), unicast it to the client's
hardware address */
/* Otherwise, broadcast it on the local network. */
} else {
to.sin_addr.s_addr = htonl (INADDR_BROADCAST);
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
}
to.sin_family = AF_INET; to.sin_family = AF_INET;
#ifdef HAVE_SA_LEN #ifdef HAVE_SA_LEN
@@ -588,47 +705,89 @@ void ack_lease (packet, lease, offer, when)
#endif #endif
memset (to.sin_zero, 0, sizeof to.sin_zero); memset (to.sin_zero, 0, sizeof to.sin_zero);
note ("Sending %s to %s at IP address %s",
offer == DHCPACK ? "DHCPACK" : "DHCPOFFER",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr),
inet_ntoa (to.sin_addr), htons (to.sin_port));
hto.htype = packet -> raw -> htype;
hto.hlen = packet -> raw -> hlen;
memcpy (hto.haddr, packet -> raw -> chaddr, hto.hlen);
result = send_packet (packet -> interface,
packet, &raw, outgoing.packet_length,
&to, &hto);
if (result < 0)
warn ("sendpkt: %m");
#ifdef DEBUG_PACKET #ifdef DEBUG_PACKET
dump_packet (packet); dump_packet (packet);
dump_raw ((unsigned char *)packet -> raw, packet -> packet_length); dump_raw ((unsigned char *)packet -> raw, packet -> packet_length);
dump_packet (&outgoing); dump_packet (&outgoing);
dump_raw ((unsigned char *)&raw, outgoing.packet_length); dump_raw ((unsigned char *)&raw, outgoing.packet_length);
#endif #endif
/* If this was gatewayed, send it back to the gateway... */
if (raw.giaddr.s_addr) {
to.sin_addr = raw.giaddr;
to.sin_port = server_port;
#ifdef USE_FALLBACK
result = send_fallback (&fallback_interface,
packet, &raw, outgoing.packet_length,
raw.siaddr, &to, &hto);
if (result < 0)
warn ("send_fallback: %m");
return;
#endif
/* If it comes from a client who already knows its address,
sent it directly to that client. */
} else if (raw.ciaddr.s_addr && offer == DHCPACK) {
to.sin_addr = packet -> raw -> ciaddr;
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
/* Otherwise, broadcast it on the local network. */
} else {
to.sin_addr.s_addr = htonl (INADDR_BROADCAST);
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
}
result = send_packet (packet -> interface,
packet, &raw, outgoing.packet_length,
raw.siaddr, &to, &hto);
if (result < 0)
warn ("sendpkt: %m");
} }
struct lease *find_lease (packet) struct lease *find_lease (packet)
struct packet *packet; struct packet *packet;
{ {
struct lease *uid_lease, *ip_lease, *hw_lease, *lease; struct lease *uid_lease, *ip_lease, *hw_lease;
struct lease *lease = (struct lease *)0;
struct iaddr cip; struct iaddr cip;
struct host_decl *hp, *host;
struct lease *fixed_lease;
/* Try to find a lease that's been assigned to the specified /* Try to find a host or lease that's been assigned to the
unique client identifier. */ specified unique client identifier. */
if (packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len) if (packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len) {
uid_lease = /* First, try to find a fixed host entry for the specified
find_lease_by_uid (packet -> options client identifier... */
[DHO_DHCP_CLIENT_IDENTIFIER].data, hp = find_hosts_by_uid (packet -> options
packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].data,
[DHO_DHCP_CLIENT_IDENTIFIER].len); packet -> options
else [DHO_DHCP_CLIENT_IDENTIFIER].len);
if (hp) {
host = hp;
fixed_lease = mockup_lease (packet, hp);
} else
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; uid_lease = (struct lease *)0;
fixed_lease = (struct lease *)0;
}
/* If we didn't find a fixed lease using the uid, try doing
it with the hardware address... */
if (!fixed_lease) {
hp = find_hosts_by_haddr (packet -> raw -> htype,
packet -> raw -> chaddr,
packet -> raw -> hlen);
if (hp) {
host = hp; /* Save it for later. */
fixed_lease = mockup_lease (packet, hp);
}
}
/* Try to find a lease that's been attached to the client's /* Try to find a lease that's been attached to the client's
hardware address... */ hardware address... */
@@ -675,23 +834,38 @@ struct lease *find_lease (packet)
strcpy (dhcp_message, "requested address on bad subnet"); strcpy (dhcp_message, "requested address on bad subnet");
} }
/* Now eliminate leases that are on the wrong subnet... */ /* Now eliminate leases that are on the wrong network... */
if (ip_lease && packet -> subnet != ip_lease -> contain) { if (ip_lease &&
(packet -> shared_network != ip_lease -> shared_network)) {
release_lease (ip_lease); release_lease (ip_lease);
ip_lease = (struct lease *)0; ip_lease = (struct lease *)0;
} }
if (uid_lease && packet -> subnet != uid_lease -> contain) { if (uid_lease &&
(packet -> shared_network != uid_lease -> shared_network)) {
release_lease (uid_lease); release_lease (uid_lease);
uid_lease = (struct lease *)0; uid_lease = (struct lease *)0;
} }
if (hw_lease && packet -> subnet != hw_lease -> contain) { if (hw_lease &&
(packet -> shared_network != hw_lease -> shared_network)) {
release_lease (hw_lease); release_lease (hw_lease);
hw_lease = (struct lease *)0; hw_lease = (struct lease *)0;
} }
/* At this point, if ip_lease is nonzero, we can assign it to /* At this point, if fixed_lease is nonzero, we can assign it to
this client. */ this client. */
lease = ip_lease; if (fixed_lease)
lease = fixed_lease;
/* If we got a lease that matched the ip address and don't have
a better offer, use that; otherwise, release it. */
if (ip_lease) {
if (lease) {
release_lease (ip_lease);
} else {
lease = ip_lease;
lease -> host = (struct host_decl *)0;
}
}
/* If we got a lease that matched the client identifier, we may want /* 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 to use it, but if we already have a lease we like, we must free
@@ -699,17 +873,59 @@ struct lease *find_lease (packet)
if (uid_lease) { if (uid_lease) {
if (lease) { if (lease) {
release_lease (uid_lease); release_lease (uid_lease);
} else } else {
lease = uid_lease; lease = uid_lease;
lease -> host = (struct host_decl *)0;
}
} }
/* The lease that matched the hardware address is treated likewise. */ /* The lease that matched the hardware address is treated likewise. */
if (hw_lease) { if (hw_lease) {
if (lease) { if (lease) {
release_lease (hw_lease); release_lease (hw_lease);
} else } else {
lease = hw_lease; lease = hw_lease;
lease -> host = (struct host_decl *)0;
}
}
/* If we found a host_decl but no matching address, try to
find a host_decl that has no address, and if there is one,
hang it off the lease so that we can use the supplied
options. */
if (lease && host && !lease -> host) {
for (; host; host = host -> n_ipaddr) {
if (!host -> fixed_addr) {
lease -> host = host;
break;
}
}
} }
return lease; return lease;
} }
/* Search the provided host_decl structure list for an address that's on
the specified shared network. If one is found, mock up and return a
lease structure for it; otherwise return the null pointer. */
struct lease *mockup_lease (packet, hp)
struct packet *packet;
struct host_decl *hp;
{
static struct lease mock;
mock.subnet = find_host_for_network (&hp, &mock.ip_addr,
packet -> shared_network);
if (!mock.subnet)
return (struct lease *)0;
mock.next = mock.prev = (struct lease *)0;
mock.shared_network = mock.subnet -> shared_network;
mock.host = hp;
mock.uid_len = 0;
mock.hardware_addr.hlen = 0;
mock.uid = (unsigned char *)0;
mock.starts = mock.timestamp = mock.ends = MIN_TIME;
mock.flags = STATIC_LEASE;
return &mock;
}

View File

@@ -82,24 +82,49 @@ void dhcpdiscover (packet)
struct packet *packet; struct packet *packet;
{ {
struct lease *lease = find_lease (packet); struct lease *lease = find_lease (packet);
struct host_decl *hp;
note ("Received DHCPDISCOVER from %s", note ("DHCPDISCOVER from %s",
print_hw_addr (packet -> raw -> htype, print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen, packet -> raw -> hlen,
packet -> raw -> chaddr)); packet -> raw -> chaddr));
/* If we didn't find a lease, try to allocate one... */ /* If we didn't find a lease, try to allocate one... */
if (!lease) { if (!lease) {
lease = packet -> subnet -> last_lease; lease = packet -> shared_network -> last_lease;
/* If there are no leases in that subnet that have /* If there are no leases in that subnet that have
expired, we have nothing to offer this client. */ expired, we have nothing to offer this client. */
if (lease -> ends >= cur_time) { if (lease -> ends > cur_time) {
note ("no free leases on subnet %s", note ("no free leases on subnet %s",
piaddr (packet -> subnet -> net)); packet -> shared_network -> name);
return; return;
} }
lease -> host = (struct host_decl *)0;
/* Try to find a host_decl that matches the client
identifier or hardware address on the packet, and
has no fixed IP address. If there is one, hang
it off the lease so that its option definitions
can be used. */
if (((packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len
!= 0) &&
((hp = find_hosts_by_uid
(packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].data,
packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len))
!= (struct host_decl *)0)) ||
((hp = find_hosts_by_haddr (packet -> raw -> htype,
packet -> raw -> chaddr,
packet -> raw -> hlen))
!= (struct host_decl *)0)) {
for (; hp; hp = hp -> n_ipaddr) {
if (!hp -> fixed_addr) {
lease -> host = hp;
break;
}
}
} else {
lease -> host = (struct host_decl *)0;
}
} }
ack_lease (packet, lease, DHCPOFFER, cur_time + 120); ack_lease (packet, lease, DHCPOFFER, cur_time + 120);
@@ -110,6 +135,8 @@ void dhcprequest (packet)
{ {
struct lease *lease = find_lease (packet); struct lease *lease = find_lease (packet);
struct iaddr cip; struct iaddr cip;
struct subnet *subnet;
struct lease *ip_lease;
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) { if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
cip.len = 4; cip.len = 4;
@@ -121,29 +148,23 @@ void dhcprequest (packet)
memcpy (cip.iabuf, &packet -> raw -> ciaddr.s_addr, 4); memcpy (cip.iabuf, &packet -> raw -> ciaddr.s_addr, 4);
} }
note ("Received DHCPREQUEST from %s for %s", note ("DHCPREQUEST for %s from %s",
print_hw_addr (packet -> raw -> htype, piaddr (cip),
packet -> raw -> hlen, print_hw_addr (packet -> raw -> htype,
packet -> raw -> chaddr), packet -> raw -> hlen,
piaddr (cip)); packet -> raw -> chaddr));
/* If a client on our local network wants to renew a lease on /* If a client on our local network wants to renew a lease on
an address off our local network, NAK it. */ an address off our local network, NAK it. */
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) { if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
if (!addr_eq (packet -> subnet -> net, subnet = find_grouped_subnet (packet -> shared_network, cip);
subnet_number (cip, if (!subnet) {
packet -> subnet -> netmask))) {
nak_lease (packet, &cip); nak_lease (packet, &cip);
return; return;
} }
} } else if (packet -> raw -> ciaddr.s_addr) {
subnet = find_grouped_subnet (packet -> shared_network, cip);
if (packet -> raw -> ciaddr.s_addr) { if (!subnet) {
cip.len = 4;
memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4);
if (!addr_eq (packet -> subnet -> net,
subnet_number (cip,
packet -> subnet -> netmask))) {
nak_lease (packet, &cip); nak_lease (packet, &cip);
return; return;
} }
@@ -151,12 +172,29 @@ void dhcprequest (packet)
/* Look for server identifier... */ /* Look for server identifier... */
if (packet -> options [DHO_DHCP_SERVER_IDENTIFIER].len) { if (packet -> options [DHO_DHCP_SERVER_IDENTIFIER].len) {
/* If there is one, and it isn't this server, and /* If we own the lease that the client is asking for,
we have a lease for this client, let it go. */ and it's already been assigned to the client,
ack it regardless. */
if ((lease -> uid_len && lease -> uid_len ==
packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len &&
!memcmp (packet -> options
[DHO_DHCP_CLIENT_IDENTIFIER].data,
lease -> uid, lease -> uid_len)) ||
(lease -> hardware_addr.hlen == packet -> raw -> hlen &&
lease -> hardware_addr.htype == packet -> raw -> htype &&
!memcmp (lease -> hardware_addr.haddr,
packet -> raw -> chaddr,
packet -> raw -> hlen))) {
ack_lease (packet, lease, DHCPACK, 0);
return;
}
/* Otherwise, if we have a lease for this client,
release it, and in any case don't reply to the
DHCPREQUEST. */
if (memcmp (packet -> if (memcmp (packet ->
options [DHO_DHCP_SERVER_IDENTIFIER].data, options [DHO_DHCP_SERVER_IDENTIFIER].data,
packet -> interface -> address.iabuf, server_identifier.iabuf, server_identifier.len)) {
packet -> interface -> address.len)) {
if (lease) if (lease)
release_lease (lease); release_lease (lease);
return; return;
@@ -179,11 +217,11 @@ void dhcprelease (packet)
{ {
struct lease *lease = find_lease (packet); struct lease *lease = find_lease (packet);
note ("Received DHCPRELEASE from %s for %s", note ("DHCPRELEASE of %s from %s",
inet_ntoa (packet -> raw -> ciaddr),
print_hw_addr (packet -> raw -> htype, print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen, packet -> raw -> hlen,
packet -> raw -> chaddr), packet -> raw -> chaddr));
inet_ntoa (packet -> raw -> ciaddr));
/* If we found a lease, release it. */ /* If we found a lease, release it. */
if (lease) { if (lease) {
@@ -206,11 +244,11 @@ void dhcpdecline (packet)
cip.len = 0; cip.len = 0;
} }
note ("Received DHCPDECLINE from %s for %s", note ("DHCPDECLINE on %s from %s",
piaddr (cip),
print_hw_addr (packet -> raw -> htype, print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen, packet -> raw -> hlen,
packet -> raw -> chaddr), packet -> raw -> chaddr));
piaddr (cip));
/* If we found a lease, mark it as unusable and complain. */ /* If we found a lease, mark it as unusable and complain. */
if (lease) { if (lease) {
@@ -221,10 +259,7 @@ void dhcpdecline (packet)
void dhcpinform (packet) void dhcpinform (packet)
struct packet *packet; struct packet *packet;
{ {
note ("Received DHCPINFORM from %s for %s", note ("DHCPINFORM from %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr),
inet_ntoa (packet -> raw -> ciaddr)); inet_ntoa (packet -> raw -> ciaddr));
} }
@@ -274,7 +309,7 @@ void nak_lease (packet, cip)
cons_options (packet, &outgoing, options, 0); cons_options (packet, &outgoing, options, 0);
/* memset (&raw.ciaddr, 0, sizeof raw.ciaddr);*/ /* memset (&raw.ciaddr, 0, sizeof raw.ciaddr);*/
memcpy (&raw.siaddr, packet -> interface -> address.iabuf, 4); memcpy (&raw.siaddr, server_identifier.iabuf, 4);
raw.giaddr = packet -> raw -> giaddr; raw.giaddr = packet -> raw -> giaddr;
memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr); memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
raw.hlen = packet -> raw -> hlen; raw.hlen = packet -> raw -> hlen;
@@ -286,38 +321,12 @@ void nak_lease (packet, cip)
raw.hops = packet -> raw -> hops; raw.hops = packet -> raw -> hops;
raw.op = BOOTREPLY; raw.op = BOOTREPLY;
/* If this was gatewayed, send it back to the gateway. /* Report what we're sending... */
Otherwise, broadcast it on the local network. */ note ("DHCPNAK on %s to %s",
if (raw.giaddr.s_addr) { piaddr (*cip),
to.sin_addr = raw.giaddr; print_hw_addr (packet -> raw -> htype,
to.sin_port = server_port; packet -> raw -> hlen,
} else { packet -> raw -> chaddr));
to.sin_addr.s_addr = htonl (INADDR_BROADCAST);
to.sin_port = packet->client_port;
}
to.sin_family = AF_INET;
#ifdef HAVE_SA_LEN
to.sin_len = sizeof to;
#endif
memset (to.sin_zero, 0, sizeof to.sin_zero);
note ("Sending DHCPNAK to %s at IP address %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr),
inet_ntoa (to.sin_addr), htons (to.sin_port));
hto.htype = packet -> raw -> htype;
hto.hlen = packet -> raw -> hlen;
memcpy (hto.haddr, packet -> raw -> chaddr, hto.hlen);
errno = 0;
result = send_packet (packet -> interface,
packet, &raw, outgoing.packet_length,
&to, (struct hardware *)0);
if (result < 0)
warn ("sendpkt: %m");
#ifdef DEBUG_PACKET #ifdef DEBUG_PACKET
dump_packet (packet); dump_packet (packet);
@@ -325,6 +334,43 @@ void nak_lease (packet, cip)
dump_packet (&outgoing); dump_packet (&outgoing);
dump_raw ((unsigned char *)&raw, outgoing.packet_length); dump_raw ((unsigned char *)&raw, outgoing.packet_length);
#endif #endif
hto.htype = packet -> raw -> htype;
hto.hlen = packet -> raw -> hlen;
memcpy (hto.haddr, packet -> raw -> chaddr, hto.hlen);
/* Set up the common stuff... */
to.sin_family = AF_INET;
#ifdef HAVE_SA_LEN
to.sin_len = sizeof to;
#endif
memset (to.sin_zero, 0, sizeof to.sin_zero);
/* If this was gatewayed, send it back to the gateway.
Otherwise, broadcast it on the local network. */
if (raw.giaddr.s_addr) {
to.sin_addr = raw.giaddr;
to.sin_port = server_port;
#ifdef USE_FALLBACK
result = send_fallback (&fallback_interface,
packet, &raw, outgoing.packet_length,
raw.siaddr, &to, &hto);
if (result < 0)
warn ("send_fallback: %m");
return;
#endif
} else {
to.sin_addr.s_addr = htonl (INADDR_BROADCAST);
to.sin_port = packet->client_port;
}
errno = 0;
result = send_packet (packet -> interface,
packet, &raw, outgoing.packet_length,
raw.siaddr, &to, (struct hardware *)0);
if (result < 0)
warn ("send_packet: %m");
} }
void ack_lease (packet, lease, offer, when) void ack_lease (packet, lease, offer, when)
@@ -353,6 +399,7 @@ void ack_lease (packet, lease, offer, when)
struct class *vendor_class, *user_class; struct class *vendor_class, *user_class;
char *filename; char *filename;
char *server_name;
int i; int i;
if (packet -> options [DHO_DHCP_CLASS_IDENTIFIER].len) { if (packet -> options [DHO_DHCP_CLASS_IDENTIFIER].len) {
@@ -377,12 +424,25 @@ void ack_lease (packet, lease, offer, when)
user_class = (struct class *)0; user_class = (struct class *)0;
} }
if (user_class && user_class -> filename) /* Choose a filename; first from the host_decl, if any, then from
the user class, then from the vendor class. */
if (lease -> host -> filename)
filename = lease -> host -> filename;
else if (user_class && user_class -> filename)
filename = user_class -> filename; filename = user_class -> filename;
else if (vendor_class && vendor_class -> filename) else if (vendor_class && vendor_class -> filename)
filename = vendor_class -> filename; filename = vendor_class -> filename;
else filename = (char *)0; else filename = (char *)0;
/* Choose a server name as above. */
if (lease -> host -> server_name)
server_name = lease -> host -> server_name;
else if (user_class && user_class -> server_name)
server_name = user_class -> server_name;
else if (vendor_class && vendor_class -> server_name)
server_name = vendor_class -> server_name;
else server_name = (char *)0;
/* At this point, we have a lease that we can offer the client. /* At this point, we have a lease that we can offer the client.
Now we construct a lease structure that contains what we want, Now we construct a lease structure that contains what we want,
and call supersede_lease to do the right thing with it. */ and call supersede_lease to do the right thing with it. */
@@ -396,23 +456,45 @@ void ack_lease (packet, lease, offer, when)
/* Start now. */ /* Start now. */
lt.starts = cur_time; lt.starts = cur_time;
/* Figure out how long a lease to assign. */ /* Figure out how long a lease to assign. If this is a
if (packet -> options [DHO_DHCP_LEASE_TIME].len == 4) { dynamic BOOTP lease, its duration must be infinite. */
lease_time = getULong (packet -> if (offer) {
options [DHO_DHCP_LEASE_TIME].data); if (packet -> options [DHO_DHCP_LEASE_TIME].len == 4) {
lease_time = getULong
/* Don't let the client ask for a longer lease than (packet -> options [DHO_DHCP_LEASE_TIME].data);
is supported for this subnet. */
if (lease_time > packet -> subnet -> max_lease_time) /* Don't let the client ask for a longer lease than
lease_time = packet -> subnet -> max_lease_time; is supported for this subnet or host. */
} else if (lease -> host && lease -> host -> max_lease_time) {
lease_time = packet -> subnet -> default_lease_time; if (lease_time >
lease -> host -> max_lease_time)
lt.offered_expiry = cur_time + lease_time; lease_time = (lease -> host ->
if (when) max_lease_time);
lt.ends = when; } else {
else if (lease_time >
lt.ends = lt.offered_expiry; lease -> subnet -> max_lease_time)
lease_time = (lease -> subnet ->
max_lease_time);
}
} else {
if (lease -> host
&& lease -> host -> default_lease_time)
lease_time = (lease -> host ->
default_lease_time);
else
lease_time = (lease -> subnet ->
default_lease_time);
}
lt.offered_expiry = cur_time + lease_time;
if (when)
lt.ends = when;
else
lt.ends = lt.offered_expiry;
} else {
lt.offered_expiry = lt.ends = MAX_TIME;
lt.flags = BOOTP_LEASE;
}
lt.timestamp = cur_time; lt.timestamp = cur_time;
@@ -432,18 +514,23 @@ void ack_lease (packet, lease, offer, when)
memcpy (lt.hardware_addr.haddr, packet -> raw -> chaddr, memcpy (lt.hardware_addr.haddr, packet -> raw -> chaddr,
packet -> raw -> hlen); packet -> raw -> hlen);
lt.host = lease -> host; /* XXX */ lt.host = lease -> host;
lt.contain = lease -> contain; lt.subnet = lease -> subnet;
lt.shared_network = lease -> shared_network;
/* Record the transaction id... */ /* Record the transaction id... */
lt.xid = packet -> raw -> xid; lt.xid = packet -> raw -> xid;
/* Don't call supersede_lease on a mocked-up lease. */
if (lease -> flags & STATIC_LEASE)
;
else
/* Install the new information about this lease in the database. /* Install the new information about this lease in the database.
If this is a DHCPACK and we can't write the lease, don't If this is a DHCPACK or a dynamic BOOTREPLY and we can't write
ACK it either. */ the lease, don't ACK it (or BOOTREPLY it) either. */
if (!(supersede_lease (lease, &lt, offer == DHCPACK) if (!(supersede_lease (lease, &lt, !offer || offer == DHCPACK)
|| offer != DHCPACK)) || (offer && offer != DHCPACK)))
return; return;
/* Send a response to the client... */ /* Send a response to the client... */
@@ -460,100 +547,135 @@ void ack_lease (packet, lease, offer, when)
/* Copy in the server name if given; otherwise, flag the /* Copy in the server name if given; otherwise, flag the
server_name buffer as available for options. */ server_name buffer as available for options. */
bufs |= 2; /* XXX */ if (server_name)
strncpy (raw.sname, server_name, sizeof raw.sname);
else
bufs |= 2; /* XXX */
memcpy (raw.chaddr, packet -> raw -> chaddr, packet -> raw -> hlen); memcpy (raw.chaddr, packet -> raw -> chaddr, packet -> raw -> hlen);
raw.hlen = packet -> raw -> hlen; raw.hlen = packet -> raw -> hlen;
raw.htype = packet -> raw -> htype; raw.htype = packet -> raw -> htype;
/* Start out with the subnet options... */ /* Start out with the subnet options... */
memcpy (options, packet -> subnet -> options, sizeof options); memcpy (options, lease -> subnet -> options, sizeof options);
/* If we have a vendor class, install those options, superceding /* Vendor and user classes are only supported for DHCP clients. */
any subnet options. */ if (offer) {
if (vendor_class) { /* If we have a vendor class, install those options,
superseding any subnet options. */
if (vendor_class) {
for (i = 0; i < 256; i++)
if (vendor_class -> options [i])
options [i] =
vendor_class -> options [i];
}
/* If we have a user class, install those options,
superseding any subnet and vendor class options. */
if (user_class) {
for (i = 0; i < 256; i++)
if (user_class -> options [i])
options [i] =
user_class -> options [i];
}
}
/* If we have a host_decl structure, install the associated
options, superseding anything that's in the way. */
if (lease -> host) {
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++)
if (vendor_class -> options [i]) if (lease -> host -> options [i])
options [i] = vendor_class -> options [i]; options [i] = lease -> host -> options [i];
} }
/* If we have a user class, install those options, superceding /* Now, if appropriate, put in DHCP-specific options that
any subnet and vendor class options. */ override those. */
if (user_class) { if (offer) {
for (i = 0; i < 256; i++) options [DHO_DHCP_MESSAGE_TYPE] = &dhcpoffer_tree;
if (user_class -> options [i]) options [DHO_DHCP_MESSAGE_TYPE] -> value = &offer;
options [i] = user_class -> options [i]; options [DHO_DHCP_MESSAGE_TYPE] -> len = sizeof offer;
} options [DHO_DHCP_MESSAGE_TYPE] -> buf_size = sizeof offer;
options [DHO_DHCP_MESSAGE_TYPE] -> timeout = 0xFFFFFFFF;
options [DHO_DHCP_MESSAGE_TYPE] -> tree = (struct tree *)0;
/* Now put in options that override those. */ options [DHO_DHCP_SERVER_IDENTIFIER] = &server_id_tree;
options [DHO_DHCP_MESSAGE_TYPE] = &dhcpoffer_tree; options [DHO_DHCP_SERVER_IDENTIFIER] ->
options [DHO_DHCP_MESSAGE_TYPE] -> value = &offer; value = server_identifier.iabuf;
options [DHO_DHCP_MESSAGE_TYPE] -> len = sizeof offer; options [DHO_DHCP_SERVER_IDENTIFIER] ->
options [DHO_DHCP_MESSAGE_TYPE] -> buf_size = sizeof offer; len = server_identifier.len;
options [DHO_DHCP_MESSAGE_TYPE] -> timeout = 0xFFFFFFFF; options [DHO_DHCP_SERVER_IDENTIFIER] ->
options [DHO_DHCP_MESSAGE_TYPE] -> tree = (struct tree *)0; buf_size = server_identifier.len;
options [DHO_DHCP_SERVER_IDENTIFIER] ->
timeout = 0xFFFFFFFF;
options [DHO_DHCP_SERVER_IDENTIFIER] ->
tree = (struct tree *)0;
options [DHO_DHCP_SERVER_IDENTIFIER] = &server_id_tree; /* Sanity check the lease time. */
options [DHO_DHCP_SERVER_IDENTIFIER] -> value = if ((lease->offered_expiry - cur_time) < 0)
packet -> interface -> address.iabuf; putULong (lease_time_buf,
options [DHO_DHCP_SERVER_IDENTIFIER] -> len = lease -> subnet -> default_lease_time);
packet -> interface -> address.len; else if (lease -> offered_expiry - cur_time >
options [DHO_DHCP_SERVER_IDENTIFIER] -> buf_size = lease -> subnet -> max_lease_time)
packet -> interface -> address.len; putULong (lease_time_buf,
options [DHO_DHCP_SERVER_IDENTIFIER] -> timeout = 0xFFFFFFFF; lease -> subnet -> max_lease_time);
options [DHO_DHCP_SERVER_IDENTIFIER] -> tree = (struct tree *)0; else
putULong (lease_time_buf,
lease -> offered_expiry - cur_time);
/* If we used the vendor class the client specified, we have to
return it. */
if (vendor_class) {
options [DHO_DHCP_CLASS_IDENTIFIER] = &vendor_class_tree;
options [DHO_DHCP_CLASS_IDENTIFIER] -> value =
(unsigned char *)vendor_class -> name;
options [DHO_DHCP_CLASS_IDENTIFIER] -> len =
strlen (vendor_class -> name);
options [DHO_DHCP_CLASS_IDENTIFIER] -> buf_size =
strlen (vendor_class -> name);
options [DHO_DHCP_CLASS_IDENTIFIER] -> timeout = 0xFFFFFFFF;
options [DHO_DHCP_CLASS_IDENTIFIER] -> tree = (struct tree *)0;
}
/* If we used the user class the client specified, we have to return
it. */
if (user_class) {
options [DHO_DHCP_USER_CLASS_ID] = &user_class_tree;
options [DHO_DHCP_USER_CLASS_ID] -> value =
(unsigned char *)user_class -> name;
options [DHO_DHCP_USER_CLASS_ID] -> len =
strlen (user_class -> name);
options [DHO_DHCP_USER_CLASS_ID] -> buf_size =
strlen (user_class -> name);
options [DHO_DHCP_USER_CLASS_ID] -> timeout = 0xFFFFFFFF;
options [DHO_DHCP_USER_CLASS_ID] -> tree = (struct tree *)0;
}
/* Sanity check the lease time. */
if ((lease->offered_expiry - cur_time) < 0)
putULong (lease_time_buf,
packet -> subnet -> default_lease_time);
else if (lease -> offered_expiry - cur_time >
packet -> subnet -> max_lease_time)
putULong (lease_time_buf, packet -> subnet -> max_lease_time);
else
putULong (lease_time_buf, lease -> offered_expiry - cur_time); putULong (lease_time_buf, lease -> offered_expiry - cur_time);
options [DHO_DHCP_LEASE_TIME] = &lease_time_tree;
options [DHO_DHCP_LEASE_TIME] -> value = lease_time_buf;
options [DHO_DHCP_LEASE_TIME] -> len = sizeof lease_time_buf;
options [DHO_DHCP_LEASE_TIME] ->
buf_size = sizeof lease_time_buf;
options [DHO_DHCP_LEASE_TIME] -> timeout = 0xFFFFFFFF;
options [DHO_DHCP_LEASE_TIME] -> tree = (struct tree *)0;
putULong (lease_time_buf, lease -> offered_expiry - cur_time); /* If we used the vendor class the client specified, we
options [DHO_DHCP_LEASE_TIME] = &lease_time_tree; have to return it. */
options [DHO_DHCP_LEASE_TIME] -> value = lease_time_buf; if (vendor_class) {
options [DHO_DHCP_LEASE_TIME] -> len = sizeof lease_time_buf; options [DHO_DHCP_CLASS_IDENTIFIER] =
options [DHO_DHCP_LEASE_TIME] -> buf_size = sizeof lease_time_buf; &vendor_class_tree;
options [DHO_DHCP_LEASE_TIME] -> timeout = 0xFFFFFFFF; options [DHO_DHCP_CLASS_IDENTIFIER] ->
options [DHO_DHCP_LEASE_TIME] -> tree = (struct tree *)0; value = (unsigned char *)vendor_class -> name;
options [DHO_DHCP_CLASS_IDENTIFIER] ->
len = strlen (vendor_class -> name);
options [DHO_DHCP_CLASS_IDENTIFIER] ->
buf_size = strlen (vendor_class -> name);
options [DHO_DHCP_CLASS_IDENTIFIER] ->
timeout = 0xFFFFFFFF;
options [DHO_DHCP_CLASS_IDENTIFIER] ->
tree = (struct tree *)0;
}
/* If we used the user class the client specified, we
have to return it. */
if (user_class) {
options [DHO_DHCP_USER_CLASS_ID] = &user_class_tree;
options [DHO_DHCP_USER_CLASS_ID] ->
value = (unsigned char *)user_class -> name;
options [DHO_DHCP_USER_CLASS_ID] ->
len = strlen (user_class -> name);
options [DHO_DHCP_USER_CLASS_ID] ->
buf_size = strlen (user_class -> name);
options [DHO_DHCP_USER_CLASS_ID] ->
timeout = 0xFFFFFFFF;
options [DHO_DHCP_USER_CLASS_ID] ->
tree = (struct tree *)0;
}
}
cons_options (packet, &outgoing, options, bufs); cons_options (packet, &outgoing, options, bufs);
raw.ciaddr = packet -> raw -> ciaddr; raw.ciaddr = packet -> raw -> ciaddr;
memcpy (&raw.yiaddr, lease -> ip_addr.iabuf, 4); memcpy (&raw.yiaddr, lease -> ip_addr.iabuf, 4);
memcpy (&raw.siaddr, packet -> interface -> address.iabuf, 4); if (lease -> subnet -> interface_address.len)
memcpy (&raw.siaddr,
lease -> subnet -> interface_address.iabuf, 4);
else
memcpy (&raw.siaddr, server_identifier.iabuf, 4);
raw.giaddr = packet -> raw -> giaddr; raw.giaddr = packet -> raw -> giaddr;
raw.xid = packet -> raw -> xid; raw.xid = packet -> raw -> xid;
@@ -562,25 +684,20 @@ void ack_lease (packet, lease, offer, when)
raw.hops = packet -> raw -> hops; raw.hops = packet -> raw -> hops;
raw.op = BOOTREPLY; raw.op = BOOTREPLY;
/* If this was gatewayed, send it back to the gateway... */ /* Say what we're doing... */
if (raw.giaddr.s_addr) { note ("%s on %s to %s",
to.sin_addr = raw.giaddr; (offer
to.sin_port = server_port; ? (offer == DHCPACK ? "DHCPACK" : "DHCPOFFER")
: "BOOTREPLY"),
piaddr (lease -> ip_addr),
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr));
/* If it comes from a client who already knows its address, /* Set up the hardware address... */
sent it directly to that client. */ hto.htype = packet -> raw -> htype;
} else if (raw.ciaddr.s_addr && offer == DHCPACK) { hto.hlen = packet -> raw -> hlen;
to.sin_addr = packet -> raw -> ciaddr; memcpy (hto.haddr, packet -> raw -> chaddr, hto.hlen);
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
/* Otherwise, if we can (we can't), unicast it to the client's
hardware address */
/* Otherwise, broadcast it on the local network. */
} else {
to.sin_addr.s_addr = htonl (INADDR_BROADCAST);
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
}
to.sin_family = AF_INET; to.sin_family = AF_INET;
#ifdef HAVE_SA_LEN #ifdef HAVE_SA_LEN
@@ -588,47 +705,89 @@ void ack_lease (packet, lease, offer, when)
#endif #endif
memset (to.sin_zero, 0, sizeof to.sin_zero); memset (to.sin_zero, 0, sizeof to.sin_zero);
note ("Sending %s to %s at IP address %s",
offer == DHCPACK ? "DHCPACK" : "DHCPOFFER",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr),
inet_ntoa (to.sin_addr), htons (to.sin_port));
hto.htype = packet -> raw -> htype;
hto.hlen = packet -> raw -> hlen;
memcpy (hto.haddr, packet -> raw -> chaddr, hto.hlen);
result = send_packet (packet -> interface,
packet, &raw, outgoing.packet_length,
&to, &hto);
if (result < 0)
warn ("sendpkt: %m");
#ifdef DEBUG_PACKET #ifdef DEBUG_PACKET
dump_packet (packet); dump_packet (packet);
dump_raw ((unsigned char *)packet -> raw, packet -> packet_length); dump_raw ((unsigned char *)packet -> raw, packet -> packet_length);
dump_packet (&outgoing); dump_packet (&outgoing);
dump_raw ((unsigned char *)&raw, outgoing.packet_length); dump_raw ((unsigned char *)&raw, outgoing.packet_length);
#endif #endif
/* If this was gatewayed, send it back to the gateway... */
if (raw.giaddr.s_addr) {
to.sin_addr = raw.giaddr;
to.sin_port = server_port;
#ifdef USE_FALLBACK
result = send_fallback (&fallback_interface,
packet, &raw, outgoing.packet_length,
raw.siaddr, &to, &hto);
if (result < 0)
warn ("send_fallback: %m");
return;
#endif
/* If it comes from a client who already knows its address,
sent it directly to that client. */
} else if (raw.ciaddr.s_addr && offer == DHCPACK) {
to.sin_addr = packet -> raw -> ciaddr;
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
/* Otherwise, broadcast it on the local network. */
} else {
to.sin_addr.s_addr = htonl (INADDR_BROADCAST);
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
}
result = send_packet (packet -> interface,
packet, &raw, outgoing.packet_length,
raw.siaddr, &to, &hto);
if (result < 0)
warn ("sendpkt: %m");
} }
struct lease *find_lease (packet) struct lease *find_lease (packet)
struct packet *packet; struct packet *packet;
{ {
struct lease *uid_lease, *ip_lease, *hw_lease, *lease; struct lease *uid_lease, *ip_lease, *hw_lease;
struct lease *lease = (struct lease *)0;
struct iaddr cip; struct iaddr cip;
struct host_decl *hp, *host;
struct lease *fixed_lease;
/* Try to find a lease that's been assigned to the specified /* Try to find a host or lease that's been assigned to the
unique client identifier. */ specified unique client identifier. */
if (packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len) if (packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len) {
uid_lease = /* First, try to find a fixed host entry for the specified
find_lease_by_uid (packet -> options client identifier... */
[DHO_DHCP_CLIENT_IDENTIFIER].data, hp = find_hosts_by_uid (packet -> options
packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].data,
[DHO_DHCP_CLIENT_IDENTIFIER].len); packet -> options
else [DHO_DHCP_CLIENT_IDENTIFIER].len);
if (hp) {
host = hp;
fixed_lease = mockup_lease (packet, hp);
} else
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; uid_lease = (struct lease *)0;
fixed_lease = (struct lease *)0;
}
/* If we didn't find a fixed lease using the uid, try doing
it with the hardware address... */
if (!fixed_lease) {
hp = find_hosts_by_haddr (packet -> raw -> htype,
packet -> raw -> chaddr,
packet -> raw -> hlen);
if (hp) {
host = hp; /* Save it for later. */
fixed_lease = mockup_lease (packet, hp);
}
}
/* Try to find a lease that's been attached to the client's /* Try to find a lease that's been attached to the client's
hardware address... */ hardware address... */
@@ -675,23 +834,38 @@ struct lease *find_lease (packet)
strcpy (dhcp_message, "requested address on bad subnet"); strcpy (dhcp_message, "requested address on bad subnet");
} }
/* Now eliminate leases that are on the wrong subnet... */ /* Now eliminate leases that are on the wrong network... */
if (ip_lease && packet -> subnet != ip_lease -> contain) { if (ip_lease &&
(packet -> shared_network != ip_lease -> shared_network)) {
release_lease (ip_lease); release_lease (ip_lease);
ip_lease = (struct lease *)0; ip_lease = (struct lease *)0;
} }
if (uid_lease && packet -> subnet != uid_lease -> contain) { if (uid_lease &&
(packet -> shared_network != uid_lease -> shared_network)) {
release_lease (uid_lease); release_lease (uid_lease);
uid_lease = (struct lease *)0; uid_lease = (struct lease *)0;
} }
if (hw_lease && packet -> subnet != hw_lease -> contain) { if (hw_lease &&
(packet -> shared_network != hw_lease -> shared_network)) {
release_lease (hw_lease); release_lease (hw_lease);
hw_lease = (struct lease *)0; hw_lease = (struct lease *)0;
} }
/* At this point, if ip_lease is nonzero, we can assign it to /* At this point, if fixed_lease is nonzero, we can assign it to
this client. */ this client. */
lease = ip_lease; if (fixed_lease)
lease = fixed_lease;
/* If we got a lease that matched the ip address and don't have
a better offer, use that; otherwise, release it. */
if (ip_lease) {
if (lease) {
release_lease (ip_lease);
} else {
lease = ip_lease;
lease -> host = (struct host_decl *)0;
}
}
/* If we got a lease that matched the client identifier, we may want /* 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 to use it, but if we already have a lease we like, we must free
@@ -699,17 +873,59 @@ struct lease *find_lease (packet)
if (uid_lease) { if (uid_lease) {
if (lease) { if (lease) {
release_lease (uid_lease); release_lease (uid_lease);
} else } else {
lease = uid_lease; lease = uid_lease;
lease -> host = (struct host_decl *)0;
}
} }
/* The lease that matched the hardware address is treated likewise. */ /* The lease that matched the hardware address is treated likewise. */
if (hw_lease) { if (hw_lease) {
if (lease) { if (lease) {
release_lease (hw_lease); release_lease (hw_lease);
} else } else {
lease = hw_lease; lease = hw_lease;
lease -> host = (struct host_decl *)0;
}
}
/* If we found a host_decl but no matching address, try to
find a host_decl that has no address, and if there is one,
hang it off the lease so that we can use the supplied
options. */
if (lease && host && !lease -> host) {
for (; host; host = host -> n_ipaddr) {
if (!host -> fixed_addr) {
lease -> host = host;
break;
}
}
} }
return lease; return lease;
} }
/* Search the provided host_decl structure list for an address that's on
the specified shared network. If one is found, mock up and return a
lease structure for it; otherwise return the null pointer. */
struct lease *mockup_lease (packet, hp)
struct packet *packet;
struct host_decl *hp;
{
static struct lease mock;
mock.subnet = find_host_for_network (&hp, &mock.ip_addr,
packet -> shared_network);
if (!mock.subnet)
return (struct lease *)0;
mock.next = mock.prev = (struct lease *)0;
mock.shared_network = mock.subnet -> shared_network;
mock.host = hp;
mock.uid_len = 0;
mock.hardware_addr.hlen = 0;
mock.uid = (unsigned char *)0;
mock.starts = mock.timestamp = mock.ends = MIN_TIME;
mock.flags = STATIC_LEASE;
return &mock;
}