summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbeck <beck@openbsd.org>2000-07-21 00:33:53 +0000
committerbeck <beck@openbsd.org>2000-07-21 00:33:53 +0000
commit6f2840a99cbca5ec1471c2615c6023e2ab572dea (patch)
tree1c1c8d47424ea97e0658bb089893a03819edb547
parentCAST-128 keys are 40-128 bits long (not 40-160) (diff)
downloadwireguard-openbsd-6f2840a99cbca5ec1471c2615c6023e2ab572dea.tar.xz
wireguard-openbsd-6f2840a99cbca5ec1471c2615c6023e2ab572dea.zip
Deal with a bunch of dhcp issues, ok fries@:
- some minor cleanup (syscall return codes, dead code, use strlcpy, etc) - sanity check dhcp option values recieved by dhclient so that things that should look like a hostname look like a hostname, and things that should look like an ip address look like an ip address, if they don't ignore the lease offer because it's bogus. - Make the dhcp server attempt to ping an address when it recieves a RELEASE from it. If the address answers a ping, ignore the release offer. This helps make spoofing releases to liberate addresses more difficult.
-rw-r--r--usr.sbin/dhcp/common/dispatch.c214
-rw-r--r--usr.sbin/dhcp/common/memory.c4
-rw-r--r--usr.sbin/dhcp/dhclient/dhclient.c232
-rw-r--r--usr.sbin/dhcp/includes/dhcpd.h4
-rw-r--r--usr.sbin/dhcp/server/dhcp.c55
-rw-r--r--usr.sbin/dhcp/server/dhcpd.c37
6 files changed, 372 insertions, 174 deletions
diff --git a/usr.sbin/dhcp/common/dispatch.c b/usr.sbin/dhcp/common/dispatch.c
index fda88e57620..0d66a3cde74 100644
--- a/usr.sbin/dhcp/common/dispatch.c
+++ b/usr.sbin/dhcp/common/dispatch.c
@@ -42,11 +42,12 @@
#ifndef lint
static char copyright[] =
-"$Id: dispatch.c,v 1.2 2000/02/09 11:55:47 niklas Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
+"$Id: dispatch.c,v 1.3 2000/07/21 00:33:53 beck Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
#include <sys/ioctl.h>
+#include <net/if_media.h>
/* Most boxes has less than 16 interfaces, so this might be a good guess. */
#define INITIAL_IFREQ_COUNT 16
@@ -162,7 +163,7 @@ void discover_interfaces (state)
/* See if this is the sort of interface we want to
deal with. */
- strcpy (ifr.ifr_name, ifp -> ifr_name);
+ strlcpy (ifr.ifr_name, ifp -> ifr_name, sizeof(ifr.ifr_name));
if (ioctl (sock, SIOCGIFFLAGS, &ifr) < 0)
error ("Can't get interface flags for %s: %m",
ifr.ifr_name);
@@ -191,9 +192,11 @@ void discover_interfaces (state)
if (!tmp)
error ("Insufficient memory to %s %s",
"record interface", ifp -> ifr_name);
- strcpy (tmp -> name, ifp -> ifr_name);
+ strlcpy (tmp -> name, ifp -> ifr_name,
+ sizeof(tmp->name));
tmp -> next = interfaces;
tmp -> flags = ir;
+ tmp -> noifmedia = tmp -> dead = tmp->errors = 0;
interfaces = tmp;
}
@@ -402,7 +405,7 @@ void discover_interfaces (state)
close (sock);
#ifdef USE_FALLBACK
- strcpy (fallback_interface.name, "fallback");
+ strlcpy (fallback_interface.name, "fallback", sizeof(fallback_interface.name));
fallback_interface.shared_network = &fallback_network;
fallback_network.name = "fallback-net";
if_register_fallback (&fallback_interface);
@@ -427,102 +430,6 @@ void reinitialize_interfaces ()
interfaces_invalidated = 1;
}
-#ifdef USE_POLL
-/* Wait for packets to come in using poll(). Anyway, when a packet
- comes in, call receive_packet to receive the packet and possibly
- strip hardware addressing information from it, and then call
- do_packet to try to do something with it.
-
- As you can see by comparing this with the code that uses select(),
- below, this is gratuitously complex. Quelle surprise, eh? This is
- SysV we're talking about, after all, and even in the 90's, it
- wouldn't do for SysV to make networking *easy*, would it? Rant,
- rant... */
-
-void dispatch ()
-{
- struct protocol *l;
- int nfds = 0;
- struct pollfd *fds;
- int count;
- int i;
- int to_msec;
-
- nfds = 0;
- for (l = protocols; l; l = l -> next) {
- ++nfds;
- }
- fds = (struct pollfd *)malloc ((nfds) * sizeof (struct pollfd));
- if (!fds)
- error ("Can't allocate poll structures.");
-
- do {
- /* Call any expired timeouts, and then if there's
- still a timeout registered, time out the select
- call then. */
- another:
- if (timeouts) {
- struct timeout *t;
- if (timeouts -> when <= cur_time) {
- t = timeouts;
- timeouts = timeouts -> next;
- (*(t -> func)) (t -> what);
- t -> next = free_timeouts;
- free_timeouts = t;
- goto another;
- }
- /* Figure timeout in milliseconds, and check for
- potential overflow. We assume that integers
- are 32 bits, which is harmless if they're 64
- bits - we'll just get extra timeouts in that
- case. Lease times would have to be quite
- long in order for a 32-bit integer to overflow,
- anyway. */
- to_msec = timeouts -> when - cur_time;
- if (to_msec > 2147483)
- to_msec = 2147483;
- to_msec *= 1000;
- } else
- to_msec = -1;
-
- /* Set up the descriptors to be polled. */
- i = 0;
- for (l = protocols; l; l = l -> next) {
- fds [i].fd = l -> fd;
- fds [i].events = POLLIN;
- fds [i].revents = 0;
- ++i;
- }
-
- /* Wait for a packet or a timeout... XXX */
- count = poll (fds, nfds, to_msec);
-
- /* Get the current time... */
- GET_TIME (&cur_time);
-
- /* Not likely to be transitory... */
- if (count < 0) {
- if (errno == EAGAIN || errno == EINTR)
- continue;
- else
- error ("poll: %m");
- }
-
- i = 0;
- for (l = protocols; l; l = l -> next) {
- if ((fds [i].revents & POLLIN)) {
- fds [i].revents = 0;
- if (l -> handler)
- (*(l -> handler)) (l);
- if (interfaces_invalidated)
- break;
- }
- ++i;
- }
- interfaces_invalidated = 0;
- } while (1);
-}
-#else
/* Wait for packets to come in using select(). When one does, call
receive_packet to receive the packet and possibly strip hardware
addressing information from it, and then call do_packet to try to
@@ -563,12 +470,20 @@ void dispatch ()
/* Set up the read mask. */
FD_ZERO (&r);
+ max = -1;
+
for (l = protocols; l; l = l -> next) {
- FD_SET (l -> fd, &r);
- if (l -> fd > max)
- max = l -> fd;
+ struct interface_info *ip = l -> local;
+ if (ip && !ip->dead) {
+ FD_SET (l -> fd, &r);
+ if (l -> fd > max)
+ max = l -> fd;
+ }
}
+ if (max == -1)
+ error("No interfaces to select on - exiting.");
+
/* Wait for a packet or a timeout... XXX */
count = select (max + 1, &r, &w, &x, tvp);
@@ -576,13 +491,15 @@ void dispatch ()
GET_TIME (&cur_time);
/* Not likely to be transitory... */
- if (count < 0)
+ if (count == -1)
error ("select: %m");
for (l = protocols; l; l = l -> next) {
+ struct interface_info *ip;
if (!FD_ISSET (l -> fd, &r))
continue;
- if (l -> handler)
+ ip = l->local;
+ if (ip && !ip-> dead && l -> handler)
(*(l -> handler)) (l);
if (interfaces_invalidated)
break;
@@ -590,7 +507,7 @@ void dispatch ()
interfaces_invalidated = 0;
} while (1);
}
-#endif /* USE_POLL */
+
static void got_one (l)
struct protocol *l;
@@ -598,15 +515,27 @@ static void got_one (l)
struct sockaddr_in from;
struct hardware hfrom;
struct iaddr ifrom;
- int result;
+ static int death = 0;
+ size_t result;
static unsigned char packbuf [4095]; /* Packet input buffer.
Must be as large as largest
possible MTU. */
struct interface_info *ip = l -> local;
+
if ((result = receive_packet (ip, packbuf, sizeof packbuf,
- &from, &hfrom)) < 0) {
- warn ("receive_packet failed on %s: %m", ip -> name);
+ &from, &hfrom)) == -1) {
+ warn ("receive_packet failed on %s: %s", ip -> name,
+ strerror(errno));
+ ip->errors++;
+ if ((! interface_status(ip))
+ || (ip->noifmedia && ip->errors > 20)) {
+ /* our interface has gone away. */
+ warn("Interface %s appears to no longer be valid",
+ ip->name);
+ ip->dead = 1;
+ interfaces_invalidated = 1;
+ }
return;
}
if (result == 0)
@@ -771,3 +700,70 @@ void remove_protocol (proto)
}
}
}
+
+int
+interface_status(struct interface_info *ifinfo)
+{
+ char * ifname = ifinfo->name;
+ int ifsock = ifinfo->rfdesc;
+ struct ifreq ifr;
+ struct ifmediareq ifmr;
+
+
+
+ /* get interface flags */
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCGIFFLAGS) on %s: %m",
+ ifname);
+ goto inactive;
+ }
+ /*
+ * if one of UP and RUNNING flags is dropped,
+ * the interface is not active.
+ */
+ if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
+ goto inactive;
+ }
+
+ /* Next, check carrier on the interface, if possible */
+ if (ifinfo->noifmedia)
+ goto active;
+ memset(&ifmr, 0, sizeof(ifmr));
+ strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
+
+ if (ioctl(ifsock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
+ if (errno != EINVAL) {
+ syslog(LOG_DEBUG, "ioctl(SIOCGIFMEDIA) on %s: %m",
+ ifname);
+ ifinfo->noifmedia = 1;
+ goto active;
+ }
+ /*
+ * EINVAL (or ENOTTY) simply means that the interface
+ * does not support the SIOCGIFMEDIA ioctl. We regard it alive.
+ */
+ ifinfo->noifmedia = 1;
+ goto active;
+ }
+
+ if (ifmr.ifm_status & IFM_AVALID) {
+ switch(ifmr.ifm_active & IFM_NMASK) {
+ case IFM_ETHER:
+ if (ifmr.ifm_status & IFM_ACTIVE)
+ goto active;
+ else
+ goto inactive;
+ break;
+ default:
+ goto inactive;
+ }
+ }
+
+ inactive:
+ return(0);
+
+ active:
+ return(1);
+}
diff --git a/usr.sbin/dhcp/common/memory.c b/usr.sbin/dhcp/common/memory.c
index bdc90a97c02..b8674016f0a 100644
--- a/usr.sbin/dhcp/common/memory.c
+++ b/usr.sbin/dhcp/common/memory.c
@@ -42,7 +42,7 @@
#ifndef lint
static char copyright[] =
-"$Id: memory.c,v 1.2 2000/06/23 01:44:15 beck Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
+"$Id: memory.c,v 1.3 2000/07/21 00:33:53 beck Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
@@ -628,6 +628,8 @@ void release_lease (lease)
lt = *lease;
lt.ends = cur_time;
supersede_lease (lease, &lt, 1);
+ note ("Released lease for IP address %s",
+ piaddr (lease -> ip_addr));
}
/* Abandon the specified lease for the specified time. sets it's
diff --git a/usr.sbin/dhcp/dhclient/dhclient.c b/usr.sbin/dhcp/dhclient/dhclient.c
index f0796d8e3d0..2d40a89b208 100644
--- a/usr.sbin/dhcp/dhclient/dhclient.c
+++ b/usr.sbin/dhcp/dhclient/dhclient.c
@@ -56,11 +56,25 @@
#ifndef lint
static char copyright[] =
-"$Id: dhclient.c,v 1.8 2000/06/25 08:39:59 dugsong Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
+"$Id: dhclient.c,v 1.9 2000/07/21 00:33:53 beck Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
+
+#define PERIOD 0x2e
+#define hyphenchar(c) ((c) == 0x2d)
+#define bslashchar(c) ((c) == 0x5c)
+#define periodchar(c) ((c) == PERIOD)
+#define asterchar(c) ((c) == 0x2a)
+#define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) \
+ || ((c) >= 0x61 && (c) <= 0x7a))
+#define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
+
+#define borderchar(c) (alphachar(c) || digitchar(c))
+#define middlechar(c) (borderchar(c) || hyphenchar(c))
+#define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
+
TIME cur_time;
TIME default_lease_time = 43200; /* 12 hours... */
TIME max_lease_time = 86400; /* 24 hours... */
@@ -95,6 +109,10 @@ int onetry;
static void usage PROTO ((void));
+static int check_option (struct client_lease *l, int option);
+
+static int ipv4addrs(char * buf);
+
int main (argc, argv, envp)
int argc;
char **argv, **envp;
@@ -103,16 +121,7 @@ int main (argc, argv, envp)
struct servent *ent;
struct interface_info *ip;
-#ifdef SYSLOG_4_2
- openlog ("dhclient", LOG_NDELAY);
- log_priority = LOG_DAEMON;
-#else
openlog ("dhclient", LOG_NDELAY, LOG_DAEMON);
-#endif
-
-#if !(defined (DEBUG) || defined (SYSLOG_4_2) || defined (__CYGWIN32__))
- setlogmask (LOG_UPTO (LOG_INFO));
-#endif
for (i = 1; i < argc; i++) {
if (!strcmp (argv [i], "-p")) {
@@ -149,9 +158,6 @@ int main (argc, argv, envp)
local_port = htons (68);
else
local_port = ent -> s_port;
-#ifndef __CYGWIN32__
- endservent ();
-#endif
}
remote_port = htons (ntohs (local_port) - 1); /* XXX */
@@ -793,6 +799,12 @@ struct client_lease *packet_to_lease (packet)
lease -> options [i].data
[lease -> options [i].len] = 0;
}
+ if (!check_option(lease,i)) {
+ /* ignore a bogus lease offer */
+ warn ("Invalid lease option - ignoring offer");
+ free_client_lease (lease);
+ return (NULL);
+ }
}
}
@@ -804,42 +816,35 @@ struct client_lease *packet_to_lease (packet)
if ((!packet -> options [DHO_DHCP_OPTION_OVERLOAD].len ||
!(packet -> options [DHO_DHCP_OPTION_OVERLOAD].data [0] & 2)) &&
packet -> raw -> sname [0]) {
- int len;
/* Don't count on the NUL terminator. */
- for (len = 0; len < 64; len++)
- if (!packet -> raw -> sname [len])
- break;
- lease -> server_name = malloc (len + 1);
- if (!lease -> server_name) {
- warn ("dhcpoffer: no memory for filename.\n");
+ lease->server_name = malloc(DHCP_SNAME_LEN + 1);
+ if (!lease -> server_name ) {
+ warn ("dhcpoffer: no memory for filename.");
free_client_lease (lease);
return (struct client_lease *)0;
- } else {
- memcpy (lease -> server_name,
- packet -> raw -> sname, len);
- lease -> server_name [len] = 0;
}
+ memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN);
+ lease->server_name[DHCP_SNAME_LEN]='\0';
+ if (! res_hnok (lease->server_name) ) {
+ warn ("Bogus server name %s", lease->server_name );
+ free_client_lease (lease);
+ return (struct client_lease *)0;
+ }
}
/* Ditto for the filename. */
if ((!packet -> options [DHO_DHCP_OPTION_OVERLOAD].len ||
!(packet -> options [DHO_DHCP_OPTION_OVERLOAD].data [0] & 1)) &&
packet -> raw -> file [0]) {
- int len;
- /* Don't count on the NUL terminator. */
- for (len = 0; len < 64; len++)
- if (!packet -> raw -> file [len])
- break;
- lease -> filename = malloc (len + 1);
+ /* Don't count on the NUL terminator. */
+ lease->filename = malloc(DHCP_FILE_LEN + 1);
if (!lease -> filename) {
- warn ("dhcpoffer: no memory for filename.\n");
+ warn ("dhcpoffer: no memory for filename.");
free_client_lease (lease);
return (struct client_lease *)0;
- } else {
- memcpy (lease -> filename,
- packet -> raw -> file, len);
- lease -> filename [len] = 0;
}
+ memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN);
+ lease->filename[DHCP_FILE_LEN]='\0';
}
return lease;
}
@@ -984,9 +989,8 @@ void send_discover (ipp)
ip -> client -> packet_length,
inaddr_any, &sockaddr_broadcast,
(struct hardware *)0);
- if (result < 0)
- warn ("send_packet: %m");
-
+ if (result < 0)
+ warn ("send_discover/send_packet: %m");
add_timeout (cur_time + ip -> client -> interval, send_discover, ip);
}
@@ -1232,8 +1236,8 @@ void send_request (ipp)
from, &destination,
(struct hardware *)0);
- if (result < 0)
- warn ("send_packet: %m");
+ if (result < 0)
+ warn ("send_request/send_packet: %m");
add_timeout (cur_time + ip -> client -> interval,
send_request, ip);
@@ -1256,8 +1260,8 @@ void send_decline (ipp)
ip -> client -> packet_length,
inaddr_any, &sockaddr_broadcast,
(struct hardware *)0);
- if (result < 0)
- warn ("send_packet: %m");
+ if (result < 0)
+ warn ("send_decline/send_packet: %m");
}
void send_release (ipp)
@@ -1277,8 +1281,8 @@ void send_release (ipp)
ip -> client -> packet_length,
inaddr_any, &sockaddr_broadcast,
(struct hardware *)0);
- if (result < 0)
- warn ("send_packet: %m");
+ if (result < 0)
+ warn ("send_release/send_packet: %m");
}
void make_discover (ip, lease)
@@ -2088,3 +2092,143 @@ void write_client_pid_file ()
fclose (pf);
}
}
+
+int check_option (struct client_lease *l, int option) {
+ char *opbuf;
+
+ /* we use this, since this is what gets passed to dhclient-script */
+
+ opbuf = pretty_print_option (option, l->options[option].data,
+ l->options[option].len, 0, 0);
+ switch(option) {
+ case DHO_SUBNET_MASK :
+ case DHO_TIME_SERVERS :
+ case DHO_NAME_SERVERS :
+ case DHO_ROUTERS :
+ case DHO_DOMAIN_NAME_SERVERS :
+ case DHO_LOG_SERVERS :
+ case DHO_COOKIE_SERVERS :
+ case DHO_LPR_SERVERS :
+ case DHO_IMPRESS_SERVERS :
+ case DHO_RESOURCE_LOCATION_SERVERS :
+ case DHO_SWAP_SERVER :
+ case DHO_BROADCAST_ADDRESS :
+ case DHO_NIS_SERVERS :
+ case DHO_NTP_SERVERS :
+ case DHO_NETBIOS_NAME_SERVERS :
+ case DHO_NETBIOS_DD_SERVER :
+ case DHO_FONT_SERVERS :
+ /* These should be a list of one or more IP addresses, separated
+ * by spaces. If they aren't, this lease is not valid.
+ */
+ if (!ipv4addrs(opbuf)) {
+ warn("Invalid IP address in option: %s", opbuf);
+ return(0);
+ }
+ return(1) ;
+ case DHO_HOST_NAME :
+ case DHO_DOMAIN_NAME :
+ case DHO_NIS_DOMAIN :
+ case DHO_DHCP_SERVER_IDENTIFIER :
+ /* This has to be a valid internet domain name */
+ if (!res_hnok(opbuf)) {
+ warn("Bogus name option: %s", opbuf);
+ return(0);
+ }
+ return(1);
+ case DHO_PAD :
+ case DHO_TIME_OFFSET :
+ case DHO_BOOT_SIZE :
+ case DHO_MERIT_DUMP :
+ case DHO_ROOT_PATH :
+ case DHO_EXTENSIONS_PATH :
+ case DHO_IP_FORWARDING :
+ case DHO_NON_LOCAL_SOURCE_ROUTING :
+ case DHO_POLICY_FILTER :
+ case DHO_MAX_DGRAM_REASSEMBLY :
+ case DHO_DEFAULT_IP_TTL :
+ case DHO_PATH_MTU_AGING_TIMEOUT :
+ case DHO_PATH_MTU_PLATEAU_TABLE :
+ case DHO_INTERFACE_MTU :
+ case DHO_ALL_SUBNETS_LOCAL :
+ case DHO_PERFORM_MASK_DISCOVERY :
+ case DHO_MASK_SUPPLIER :
+ case DHO_ROUTER_DISCOVERY :
+ case DHO_ROUTER_SOLICITATION_ADDRESS :
+ case DHO_STATIC_ROUTES :
+ case DHO_TRAILER_ENCAPSULATION :
+ case DHO_ARP_CACHE_TIMEOUT :
+ case DHO_IEEE802_3_ENCAPSULATION :
+ case DHO_DEFAULT_TCP_TTL :
+ case DHO_TCP_KEEPALIVE_INTERVAL :
+ case DHO_TCP_KEEPALIVE_GARBAGE :
+ case DHO_VENDOR_ENCAPSULATED_OPTIONS :
+ case DHO_NETBIOS_NODE_TYPE :
+ case DHO_NETBIOS_SCOPE :
+ case DHO_X_DISPLAY_MANAGER :
+ case DHO_DHCP_REQUESTED_ADDRESS :
+ case DHO_DHCP_LEASE_TIME :
+ case DHO_DHCP_OPTION_OVERLOAD :
+ case DHO_DHCP_MESSAGE_TYPE :
+ case DHO_DHCP_PARAMETER_REQUEST_LIST :
+ case DHO_DHCP_MESSAGE :
+ case DHO_DHCP_MAX_MESSAGE_SIZE :
+ case DHO_DHCP_RENEWAL_TIME :
+ case DHO_DHCP_REBINDING_TIME :
+ case DHO_DHCP_CLASS_IDENTIFIER :
+ case DHO_DHCP_CLIENT_IDENTIFIER :
+ case DHO_DHCP_USER_CLASS_ID :
+ case DHO_END :
+ /* do nothing */
+ return(1);
+ default:
+ warn("unknown dhcp option value 0x%x", option);
+ return(0);
+ }
+}
+
+int
+res_hnok(dn)
+ const char *dn;
+{
+ int pch = PERIOD, ch = *dn++;
+
+ while (ch != '\0') {
+ int nch = *dn++;
+
+ if (periodchar(ch)) {
+ ;
+ } else if (periodchar(pch)) {
+ if (!borderchar(ch))
+ return (0);
+ } else if (periodchar(nch) || nch == '\0') {
+ if (!borderchar(ch))
+ return (0);
+ } else {
+ if (!middlechar(ch))
+ return (0);
+ }
+ pch = ch, ch = nch;
+ }
+ return (1);
+}
+
+/* Does buf consist only of dotted decimal ipv4 addrs?
+ * return how many if so,
+ * otherwise, return 0
+ */
+int ipv4addrs(char * buf) {
+ struct in_addr jnk;
+ int count = 0;
+
+ while (inet_aton(buf, &jnk) == 1){
+ count++;
+ while (periodchar(*buf) || digitchar(*buf))
+ buf++;
+ if (*buf == '\0')
+ return(count);
+ while (*buf == ' ')
+ buf++;
+ }
+ return(0);
+}
diff --git a/usr.sbin/dhcp/includes/dhcpd.h b/usr.sbin/dhcp/includes/dhcpd.h
index e9ea614e594..9ec584d9aea 100644
--- a/usr.sbin/dhcp/includes/dhcpd.h
+++ b/usr.sbin/dhcp/includes/dhcpd.h
@@ -144,6 +144,7 @@ struct lease {
# define ABANDONED_LEASE 16
struct lease_state *state;
+ u_int8_t releasing;
};
struct lease_state {
@@ -363,6 +364,9 @@ struct interface_info {
/* Only used by DHCP client code. */
struct client_state *client;
+ int noifmedia;
+ int errors;
+ int dead;
};
struct hardware_link {
diff --git a/usr.sbin/dhcp/server/dhcp.c b/usr.sbin/dhcp/server/dhcp.c
index 6cd75f2a654..5acd78cbd1a 100644
--- a/usr.sbin/dhcp/server/dhcp.c
+++ b/usr.sbin/dhcp/server/dhcp.c
@@ -42,7 +42,7 @@
#ifndef lint
static char copyright[] =
-"$Id: dhcp.c,v 1.1 1998/08/18 03:43:34 deraadt Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
+"$Id: dhcp.c,v 1.2 2000/07/21 00:33:54 beck Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
@@ -342,19 +342,50 @@ void dhcprelease (packet)
}
- note ("DHCPRELEASE of %s from %s via %s (%sfound)",
- inet_ntoa (packet -> raw -> ciaddr),
- print_hw_addr (packet -> raw -> htype,
- packet -> raw -> hlen,
- packet -> raw -> chaddr),
- packet -> raw -> giaddr.s_addr
- ? inet_ntoa (packet -> raw -> giaddr)
- : packet -> interface -> name,
- lease ? "" : "not ");
-
/* If we found a lease, release it. */
if (lease) {
- release_lease (lease);
+ /* first, we ping this lease to see if it's still
+ * there. if it is, we don't release it.
+ * this avoids the problem of spoofed releases
+ * being used to liberate addresses from the
+ * server.
+ */
+ if (! lease->releasing) {
+ note ("DHCPRELEASE of %s from %s via %s (found)",
+ inet_ntoa (packet -> raw -> ciaddr),
+ print_hw_addr (packet -> raw -> htype,
+ packet -> raw -> hlen,
+ packet -> raw -> chaddr),
+ packet -> raw -> giaddr.s_addr
+ ? inet_ntoa (packet -> raw -> giaddr)
+ : packet -> interface -> name,
+ lease ? "" : "not ");
+
+ lease->releasing = 1;
+ add_timeout (cur_time + 1, lease_ping_timeout, lease);
+ icmp_echorequest (&(lease -> ip_addr));
+ ++outstanding_pings;
+ }
+ else {
+ note ("DHCPRELEASE of %s from %s via %s ignored (release already pending)",
+ inet_ntoa (packet -> raw -> ciaddr),
+ print_hw_addr (packet -> raw -> htype,
+ packet -> raw -> hlen,
+ packet -> raw -> chaddr),
+ packet -> raw -> giaddr.s_addr
+ ? inet_ntoa (packet -> raw -> giaddr)
+ : packet -> interface -> name);
+ }
+ }
+ else {
+ note ("DHCPRELEASE of %s from %s via %s for nonexistent lease",
+ inet_ntoa (packet -> raw -> ciaddr),
+ print_hw_addr (packet -> raw -> htype,
+ packet -> raw -> hlen,
+ packet -> raw -> chaddr),
+ packet -> raw -> giaddr.s_addr
+ ? inet_ntoa (packet -> raw -> giaddr)
+ : packet -> interface -> name);
}
}
diff --git a/usr.sbin/dhcp/server/dhcpd.c b/usr.sbin/dhcp/server/dhcpd.c
index a4dfe5052cc..5c2dcc6b903 100644
--- a/usr.sbin/dhcp/server/dhcpd.c
+++ b/usr.sbin/dhcp/server/dhcpd.c
@@ -42,7 +42,7 @@
#ifndef lint
static char ocopyright[] =
-"$Id: dhcpd.c,v 1.1 1998/08/18 03:43:34 deraadt Exp $ Copyright 1995, 1996 The Internet Software Consortium.";
+"$Id: dhcpd.c,v 1.2 2000/07/21 00:33:55 beck Exp $ Copyright 1995, 1996 The Internet Software Consortium.";
#endif
static char copyright[] =
@@ -318,18 +318,33 @@ void lease_pinged (from, packet, length)
return;
}
- if (!lp -> state) {
+ if (!lp -> state && ! lp -> releasing) {
warn ("ICMP Echo Reply for %s arrived late or is spurious.\n",
piaddr (from));
return;
}
/* At this point it looks like we pinged a lease and got a
- response, which shouldn't have happened. */
- free_lease_state (lp -> state, "lease_pinged");
- lp -> state = (struct lease_state *)0;
+ * response, which shouldn't have happened.
+ * if it did it's either one of two two cases:
+ * 1 - we pinged this lease before offering it and
+ * something answered, so we abandon it.
+ * 2 - we pinged this lease before releaseing it
+ * and something answered, so we don't release it.
+ */
+ if (lp -> releasing) {
+ warn ("IP address %s answers a ping after sending a release",
+ piaddr (lp -> ip_addr));
+ warn ("Possible release spoof - Not releasing address %s",
+ piaddr (lp -> ip_addr));
+ lp -> releasing = 0;
+ }
+ else {
+ free_lease_state (lp -> state, "lease_pinged");
+ lp -> state = (struct lease_state *)0;
- abandon_lease (lp, "pinged before offer");
+ abandon_lease (lp, "pinged before offer");
+ }
cancel_timeout (lease_ping_timeout, lp);
--outstanding_pings;
}
@@ -338,7 +353,13 @@ void lease_ping_timeout (vlp)
void *vlp;
{
struct lease *lp = vlp;
-
+
--outstanding_pings;
- dhcp_reply (lp);
+ if (lp->releasing) {
+ lp->releasing = 0;
+ release_lease(lp);
+ }
+ else {
+ dhcp_reply (lp);
+ }
}