aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README11
-rw-r--r--client.c181
-rw-r--r--common.c9
-rw-r--r--config.h2
-rw-r--r--configure.c22
-rw-r--r--dhcp.c179
-rw-r--r--dhcp.h2
-rw-r--r--dhcpcd-hooks/01-test7
-rw-r--r--dhcpcd-hooks/50-dhcpcd-compat12
-rw-r--r--dhcpcd-hooks/50-ntp.conf17
-rw-r--r--[-rwxr-xr-x]dhcpcd-run-hooks2
-rw-r--r--dhcpcd-run-hooks.82
-rw-r--r--dhcpcd-run-hooks.8.in3
-rw-r--r--dhcpcd-run-hooks.in4
-rw-r--r--dhcpcd.8.in20
-rw-r--r--dhcpcd.c40
-rw-r--r--dhcpcd.conf.5.in25
-rw-r--r--dhcpcd.h10
-rw-r--r--if-bsd.c104
-rw-r--r--if-linux.c34
-rw-r--r--mk/dist.mk4
-rw-r--r--net.c54
-rw-r--r--net.h17
-rw-r--r--showlease.c8
-rw-r--r--signals.c8
25 files changed, 457 insertions, 320 deletions
diff --git a/README b/README
index 50294fe..1dff417 100644
--- a/README
+++ b/README
@@ -56,6 +56,13 @@ If CMDLINE_COMPAT is defined the we renable DUID support by default IF
the dhcpcd.duid file exits. This keeps the clients working as they were,
which is good.
+dhcpcd no longer sends a default ClientID for ethernet interfaces.
+This is so we can re-use the address the kernel DHCP client found.
+To retain the old behaviour of sending a default ClientID based on the
+hardware address for interface, simply add the keyword clientid to dhcpcd.conf.
+If CMDLINE_COMPAT is defined, we renable the sending of ClientID by default
+AND adding clientid to dhcpcd.conf causes it NOT to be sent.
+
dhcpcd-4 is NOT fully commandline compatible with dhcpcd-2 and older and
changes the meaning of some options.
@@ -63,5 +70,5 @@ changes the meaning of some options.
ChangeLog
---------
We no longer supply a ChangeLog.
-However, you're more than welcome to read the git commit comments at
-http://git.marples.name/?p=dhcpcd.git;a=summary
+However, you're more than welcome to read the commit log at
+http://roy.marples.name/projects/dhcpcd/log/
diff --git a/client.c b/client.c
index c34d318..90657b3 100644
--- a/client.c
+++ b/client.c
@@ -217,7 +217,8 @@ daemonise(struct if_state *state, const struct options *options)
setsid();
/* Notify parent it's safe to exit as we've detached. */
close(sidpipe[0]);
- write(sidpipe[1], &buf, 1);
+ if (write(sidpipe[1], &buf, 1) != 1)
+ logger(LOG_ERR, "write: %s", strerror(errno));
close(sidpipe[1]);
close_fds();
break;
@@ -226,7 +227,8 @@ daemonise(struct if_state *state, const struct options *options)
signal_reset();
/* Wait for child to detach */
close(sidpipe[1]);
- read(sidpipe[0], &buf, 1);
+ if (read(sidpipe[0], &buf, 1) != 1)
+ logger(LOG_ERR, "read: %s", strerror(errno));
close(sidpipe[0]);
break;
}
@@ -362,10 +364,11 @@ get_lease(struct dhcp_lease *lease, const struct dhcp_message *dhcp)
{
time_t t;
- lease->frominfo = 0;
+ if (lease->frominfo)
+ return;
lease->addr.s_addr = dhcp->yiaddr;
- if (get_option_addr(&lease->net.s_addr, dhcp, DHO_SUBNETMASK) == -1)
+ if (get_option_addr(&lease->net, dhcp, DHO_SUBNETMASK) == -1)
lease->net.s_addr = get_netmask(dhcp->yiaddr);
if (get_option_uint32(&lease->leasetime, dhcp, DHO_LEASETIME) == 0) {
/* Ensure that we can use the lease */
@@ -405,6 +408,7 @@ get_old_lease(struct if_state *state)
logger(LOG_INFO, "read_lease: %s", strerror(errno));
goto eexit;
}
+ lease->frominfo = 0;
get_lease(&state->lease, dhcp);
lease->frominfo = 1;
lease->leasedfrom = sb.st_mtime;
@@ -437,12 +441,11 @@ get_old_lease(struct if_state *state)
else
goto eexit;
}
+ lease->leasetime -= offset;
+ lease->rebindtime -= offset;
+ lease->renewaltime -= offset;
}
- if (lease->leasedfrom == 0)
- offset = 0;
- iface->start_uptime = uptime();
- state->timeout.tv_sec = lease->renewaltime - offset;
free(state->old);
state->old = state->new;
state->new = NULL;
@@ -492,16 +495,6 @@ client_setup(struct if_state *state, const struct options *options)
lease->net.s_addr = options->request_netmask.s_addr;
}
- if (options->options & DHCPCD_REQUEST &&
- state->options & DHCPCD_ARP &&
- !state->offer)
- {
- state->offer = xzalloc(sizeof(*state->offer));
- state->offer->yiaddr = options->request_address.s_addr;
- state->state = STATE_PROBING;
- state->xid = arc4random();
- }
-
/* If INFORMing, ensure the interface has the address */
if (state->options & DHCPCD_INFORM &&
has_address(iface->name, &lease->addr, &lease->net) < 1)
@@ -519,12 +512,18 @@ client_setup(struct if_state *state, const struct options *options)
iface->net.s_addr = lease->net.s_addr;
}
+ /* If we haven't specified a ClientID and our hardware address
+ * length is greater than DHCP_CHADDR_LEN then we enforce a ClientID
+ * of the hardware address family and the hardware address. */
+ if (!(state->options & DHCPCD_CLIENTID) && iface->hwlen > DHCP_CHADDR_LEN)
+ state->options |= DHCPCD_CLIENTID;
+
if (*options->clientid) {
iface->clientid = xmalloc(options->clientid[0] + 1);
memcpy(iface->clientid,
options->clientid, options->clientid[0] + 1);
- } else if (options->options & DHCPCD_CLIENTID) {
- if (options->options & DHCPCD_DUID) {
+ } else if (state->options & DHCPCD_CLIENTID) {
+ if (state->options & DHCPCD_DUID) {
duid = xmalloc(DUID_LEN);
if ((len = get_duid(duid, iface)) == 0)
logger(LOG_ERR, "get_duid: %s",
@@ -686,7 +685,9 @@ send_message(struct if_state *state, int type, const struct options *options)
if (r == -1) {
state->state = STATE_INIT;
timerclear(&state->timeout);
- timerclear(&state->stop);
+ /* We need to set a timeout so we fall through gracefully */
+ state->stop.tv_sec = 1;
+ state->stop.tv_usec = 0;
do_socket(state, SOCKET_CLOSED);
}
return r;
@@ -836,12 +837,24 @@ wait_for_fd(struct if_state *state, int *fd)
}
/* We configured our array in the order we should deal with them */
- for (i = 0; i < nfds; i++)
- if (fds[i].revents & POLLIN) {
+ for (i = 0; i < nfds; i++) {
+ if (fds[i].revents & POLLERR) {
+ syslog(LOG_ERR, "poll: POLLERR on fd %d", fds[i].fd);
+ errno = EBADF;
+ return -1;
+ }
+ if (fds[i].revents & POLLNVAL) {
+ syslog(LOG_ERR, "poll: POLLNVAL on fd %d", fds[i].fd);
+ errno = EINVAL;
+ return -1;
+ }
+ if (fds[i].revents & (POLLIN | POLLHUP)) {
*fd = fds[i].fd;
return r;
}
- return r;
+ }
+ /* We should never get here. */
+ return 0;
}
static int
@@ -940,24 +953,24 @@ static int bind_dhcp(struct if_state *state, const struct options *options)
state->state = STATE_BOUND;
timerclear(&state->stop);
} else {
- if (lease->rebindtime >= lease->leasetime) {
+ if (lease->rebindtime == 0)
+ lease->rebindtime = lease->leasetime * T2;
+ else if (lease->rebindtime >= lease->leasetime) {
lease->rebindtime = lease->leasetime * T2;
logger(LOG_ERR,
"rebind time greater than lease "
"time, forcing to %u seconds",
lease->rebindtime);
}
- if (lease->renewaltime > lease->rebindtime) {
+ if (lease->renewaltime == 0)
+ lease->renewaltime = lease->leasetime * T1;
+ else if (lease->renewaltime > lease->rebindtime) {
lease->renewaltime = lease->leasetime * T1;
logger(LOG_ERR,
"renewal time greater than rebind time, "
"forcing to %u seconds",
lease->renewaltime);
}
- if (!lease->renewaltime)
- lease->renewaltime = lease->leasetime * T1;
- if (!lease->rebindtime)
- lease->rebindtime = lease->leasetime * T2;
logger(LOG_INFO,
"leased %s for %u seconds",
inet_ntoa(lease->addr), lease->leasetime);
@@ -1001,7 +1014,7 @@ handle_timeout_fail(struct if_state *state, const struct options *options)
{
struct dhcp_lease *lease = &state->lease;
struct interface *iface = state->interface;
- int gotlease = -1;
+ int gotlease = -1, r;
const char *reason = NULL;
timerclear(&state->stop);
@@ -1040,12 +1053,14 @@ handle_timeout_fail(struct if_state *state, const struct options *options)
{
logger(LOG_INFO, "probing for an IPV4LL address");
free(state->offer);
+ lease->frominfo = 0;
state->offer = ipv4ll_get_dhcp(0);
gotlease = 0;
}
if (gotlease == 0 &&
- state->offer->yiaddr != iface->addr.s_addr)
+ state->offer->yiaddr != iface->addr.s_addr &&
+ state->options & DHCPCD_ARP)
{
state->state = STATE_PROBING;
state->claims = 0;
@@ -1055,9 +1070,12 @@ handle_timeout_fail(struct if_state *state, const struct options *options)
return 1;
}
- if (gotlease == 0)
- return bind_dhcp(state, options);
-
+ if (gotlease == 0) {
+ r = bind_dhcp(state, options);
+ logger(LOG_DEBUG, "renew in %ld seconds",
+ (long int)state->stop.tv_sec);
+ return r;
+ }
if (iface->addr.s_addr)
reason = "EXPIRE";
else
@@ -1170,14 +1188,11 @@ handle_timeout(struct if_state *state, const struct options *options)
} else {
/* We've waited for ANNOUNCE_WAIT after the final probe
* so the address is now ours */
- if (IN_LINKLOCAL(htonl(state->offer->yiaddr))) {
- i = bind_dhcp(state, options);
- state->state = STATE_ANNOUNCING;
- state->timeout.tv_sec = ANNOUNCE_INTERVAL;
- state->timeout.tv_usec = 0;
- return i;
- }
- state->state = STATE_REQUESTING;
+ i = bind_dhcp(state, options);
+ state->state = STATE_ANNOUNCING;
+ state->timeout.tv_sec = ANNOUNCE_INTERVAL;
+ state->timeout.tv_usec = 0;
+ return i;
}
break;
case STATE_ANNOUNCING:
@@ -1246,6 +1261,8 @@ handle_timeout(struct if_state *state, const struct options *options)
timerclear(&state->stop);
/* FALLTHROUGH */
case STATE_INIT:
+ if (state->carrier == LINK_DOWN)
+ return 0;
do_socket(state, SOCKET_OPEN);
state->xid = arc4random();
iface->start_uptime = uptime();
@@ -1269,8 +1286,6 @@ handle_timeout(struct if_state *state, const struct options *options)
}
/* FALLTHROUGH */
case STATE_INIT:
- if (state->carrier == LINK_DOWN)
- return 0;
if (lease->addr.s_addr == 0 ||
IN_LINKLOCAL(ntohl(iface->addr.s_addr)))
{
@@ -1346,7 +1361,7 @@ log_dhcp(int lvl, const char *msg, const struct dhcp_message *dhcp)
addr.s_addr = dhcp->yiaddr;
a = xstrdup(inet_ntoa(addr));
}
- r = get_option_addr(&addr.s_addr, dhcp, DHO_SERVERID);
+ r = get_option_addr(&addr, dhcp, DHO_SERVERID);
if (dhcp->servername[0] && r == 0)
logger(lvl, "%s %s from %s `%s'", msg, a,
inet_ntoa(addr), dhcp->servername);
@@ -1374,7 +1389,12 @@ handle_dhcp(struct if_state *state, struct dhcp_message **dhcpp,
/* We have to have DHCP type to work */
if (get_option_uint8(&type, dhcp, DHO_MESSAGETYPE) == -1) {
- log_dhcp(LOG_ERR, "no DHCP type in", dhcp);
+ logger(LOG_ERR, "ignoring message; no DHCP type");
+ return 0;
+ }
+ /* Every DHCP message should include ServerID */
+ if (get_option_addr(&addr, dhcp, DHO_SERVERID) == -1) {
+ logger(LOG_ERR, "ignoring message; no Server ID");
return 0;
}
@@ -1382,7 +1402,7 @@ handle_dhcp(struct if_state *state, struct dhcp_message **dhcpp,
* We should expand this to check IP and/or hardware address
* at the packet level. */
if (options->blacklist_len != 0 &&
- get_option_addr(&addr.s_addr, dhcp, DHO_SERVERID) == 0)
+ get_option_addr(&addr, dhcp, DHO_SERVERID) == 0)
{
for (i = 0; i < options->blacklist_len; i++) {
if (options->blacklist[i] != addr.s_addr)
@@ -1434,7 +1454,7 @@ handle_dhcp(struct if_state *state, struct dhcp_message **dhcpp,
if (type == DHCP_OFFER && state->state == STATE_DISCOVERING) {
lease->addr.s_addr = dhcp->yiaddr;
- get_option_addr(&lease->server.s_addr, dhcp, DHO_SERVERID);
+ get_option_addr(&lease->server, dhcp, DHO_SERVERID);
log_dhcp(LOG_INFO, "offered", dhcp);
if (state->options & DHCPCD_TEST) {
run_script(options, iface->name, "TEST", dhcp, NULL);
@@ -1446,21 +1466,6 @@ handle_dhcp(struct if_state *state, struct dhcp_message **dhcpp,
state->offer = dhcp;
*dhcpp = NULL;
timerclear(&state->timeout);
- if (state->options & DHCPCD_ARP &&
- iface->addr.s_addr != state->offer->yiaddr)
- {
- /* If the interface already has the address configured
- * then we can't ARP for duplicate detection. */
- addr.s_addr = state->offer->yiaddr;
- if (!has_address(iface->name, &addr, NULL)) {
- state->state = STATE_PROBING;
- state->claims = 0;
- state->probes = 0;
- state->conflicts = 0;
- timerclear(&state->stop);
- return 1;
- }
- }
state->state = STATE_REQUESTING;
return 1;
}
@@ -1482,7 +1487,7 @@ handle_dhcp(struct if_state *state, struct dhcp_message **dhcpp,
case STATE_RENEWING:
case STATE_REBINDING:
if (!(state->options & DHCPCD_INFORM)) {
- get_option_addr(&lease->server.s_addr,
+ get_option_addr(&lease->server,
dhcp, DHO_SERVERID);
log_dhcp(LOG_INFO, "acknowledged", dhcp);
}
@@ -1494,7 +1499,24 @@ handle_dhcp(struct if_state *state, struct dhcp_message **dhcpp,
logger(LOG_ERR, "wrong state %d", state->state);
}
+ lease->frominfo = 0;
do_socket(state, SOCKET_CLOSED);
+ if (state->options & DHCPCD_ARP &&
+ iface->addr.s_addr != state->offer->yiaddr)
+ {
+ /* If the interface already has the address configured
+ * then we can't ARP for duplicate detection. */
+ addr.s_addr = state->offer->yiaddr;
+ if (!has_address(iface->name, &addr, NULL)) {
+ state->state = STATE_PROBING;
+ state->claims = 0;
+ state->probes = 0;
+ state->conflicts = 0;
+ timerclear(&state->stop);
+ return 1;
+ }
+ }
+
r = bind_dhcp(state, options);
if (!(state->options & DHCPCD_ARP)) {
if (!(state->options & DHCPCD_INFORM))
@@ -1515,7 +1537,6 @@ handle_dhcp_packet(struct if_state *state, const struct options *options)
struct interface *iface = state->interface;
struct dhcp_message *dhcp = NULL;
const uint8_t *pp;
- uint8_t *p;
ssize_t bytes;
int retval = -1;
@@ -1532,7 +1553,7 @@ handle_dhcp_packet(struct if_state *state, const struct options *options)
}
if (bytes == -1)
break;
- if (valid_udp_packet(packet) == -1)
+ if (valid_udp_packet(packet, bytes) == -1)
continue;
bytes = get_udp_data(&pp, packet);
if ((size_t)bytes > sizeof(*dhcp)) {
@@ -1540,7 +1561,7 @@ handle_dhcp_packet(struct if_state *state, const struct options *options)
continue;
}
if (!dhcp)
- dhcp = xmalloc(sizeof(*dhcp));
+ dhcp = xzalloc(sizeof(*dhcp));
memcpy(dhcp, pp, bytes);
if (dhcp->cookie != htonl(MAGIC_COOKIE)) {
logger(LOG_DEBUG, "bogus cookie, ignoring");
@@ -1563,15 +1584,6 @@ handle_dhcp_packet(struct if_state *state, const struct options *options)
hwaddr_ntoa(dhcp->chaddr, sizeof(dhcp->chaddr)));
continue;
}
- /* We should ensure that the packet is terminated correctly
- * if we have space for the terminator */
- if ((size_t)bytes < sizeof(struct dhcp_message)) {
- p = (uint8_t *)dhcp + bytes - 1;
- while (p > dhcp->options && *p == DHO_PAD)
- p--;
- if (*p != DHO_END)
- *++p = DHO_END;
- }
retval = handle_dhcp(state, &dhcp, options);
if (retval == 0 && state->options & DHCPCD_TEST)
state->options |= DHCPCD_FORKED;
@@ -1658,17 +1670,19 @@ handle_arp_fail(struct if_state *state, const struct options *options)
int cookie = state->offer->cookie;
if (!IN_LINKLOCAL(htonl(state->fail.s_addr))) {
+ if (cookie) {
+ state->timeout.tv_sec = DHCP_ARP_FAIL;
+ state->timeout.tv_usec = 0;
+ do_socket(state, SOCKET_OPEN);
+ send_message(state, DHCP_DECLINE, options);
+ do_socket(state, SOCKET_CLOSED);
+ }
state->state = STATE_INIT;
free(state->offer);
state->offer = NULL;
state->lease.addr.s_addr = 0;
if (!cookie)
return 1;
- state->timeout.tv_sec = DHCP_ARP_FAIL;
- state->timeout.tv_usec = 0;
- do_socket(state, SOCKET_OPEN);
- send_message(state, DHCP_DECLINE, options);
- do_socket(state, SOCKET_CLOSED);
return 0;
}
@@ -1720,7 +1734,6 @@ handle_link(struct if_state *state)
if (retval == 0)
return 0;
- timerclear(&state->timeout);
switch (carrier_status(state->interface->name)) {
case -1:
logger(LOG_ERR, "carrier_status: %s", strerror(errno));
@@ -1730,6 +1743,7 @@ handle_link(struct if_state *state)
logger(LOG_INFO, "carrier lost");
state->carrier = LINK_DOWN;
do_socket(state, SOCKET_CLOSED);
+ timerclear(&state->timeout);
if (state->state != STATE_BOUND)
timerclear(&state->stop);
}
@@ -1739,6 +1753,7 @@ handle_link(struct if_state *state)
logger(LOG_INFO, "carrier acquired");
state->state = STATE_RENEW_REQUESTED;
state->carrier = LINK_UP;
+ timerclear(&state->timeout);
timerclear(&state->stop);
return 1;
}
diff --git a/common.c b/common.c
index d90c7d2..da22a5c 100644
--- a/common.c
+++ b/common.c
@@ -69,7 +69,8 @@ get_line(char **line, size_t *len, FILE *fp)
}
p = *line + last;
memset(p, 0, BUFSIZ);
- fgets(p, BUFSIZ, fp);
+ if (fgets(p, BUFSIZ, fp) == NULL)
+ break;
last += strlen(p);
if (last && (*line)[last - 1] == '\n') {
(*line)[last - 1] = '\0';
@@ -201,9 +202,8 @@ get_monotonic(struct timeval *tp)
if (posix_clock_set == 0) {
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
posix_clock = CLOCK_MONOTONIC;
- clock_monotonic = 1;
+ clock_monotonic = posix_clock_set = 1;
}
- posix_clock_set = 1;
}
if (clock_monotonic) {
@@ -225,9 +225,8 @@ get_monotonic(struct timeval *tp)
if (posix_clock_set == 0) {
if (mach_timebase_info(&info) == KERN_SUCCESS) {
factor = (double)info.numer / (double)info.denom;
- clock_monotonic = 1;
+ clock_monotonic = posix_clock_set = 1;
}
- posix_clock_set = 1;
}
if (clock_monotonic) {
nano = mach_absolute_time();
diff --git a/config.h b/config.h
index cff7079..595fb94 100644
--- a/config.h
+++ b/config.h
@@ -28,7 +28,7 @@
#define CONFIG_H
#define PACKAGE "dhcpcd"
-#define VERSION "4.0.1"
+#define VERSION "4.0.15"
/*
* By default we don't add a local link route if we got a routeable address.
diff --git a/configure.c b/configure.c
index dad3bce..1e6daeb 100644
--- a/configure.c
+++ b/configure.c
@@ -181,7 +181,7 @@ reverse_routes(struct rt *routes)
}
static int
-delete_route(const char *iface, struct rt *rt, int metric)
+delete_route(const struct interface *iface, struct rt *rt, int metric)
{
char *addr;
int retval;
@@ -206,7 +206,7 @@ delete_routes(struct interface *iface, int metric)
rt = reverse_routes(iface->routes);
while (rt) {
rtn = rt->next;
- retval += delete_route(iface->name, rt, metric);
+ retval += delete_route(iface, rt, metric);
free(rt);
rt = rtn;
}
@@ -272,7 +272,7 @@ configure_routes(struct interface *iface, const struct dhcp_message *dhcp,
iface->routes = reverse_routes(iface->routes);
for (rt = iface->routes; rt; rt = rt->next)
if (in_routes(ort, rt) != 0)
- delete_route(iface->name, rt, options->metric);
+ delete_route(iface, rt, options->metric);
for (rt = ort; rt; rt = rt->next) {
/* Don't set default routes if not asked to */
@@ -285,7 +285,7 @@ configure_routes(struct interface *iface, const struct dhcp_message *dhcp,
logger(LOG_DEBUG, "adding route to %s/%d via %s",
addr, inet_ntocidr(rt->net), inet_ntoa(rt->gate));
free(addr);
- remember = add_route(iface->name, &rt->dest,
+ remember = add_route(iface, &rt->dest,
&rt->net, &rt->gate,
options->metric);
retval += remember;
@@ -357,9 +357,9 @@ configure(struct interface *iface, const char *reason,
if (addr.s_addr == 0)
addr.s_addr = lease->addr.s_addr;
/* Ensure we have all the needed values */
- if (get_option_addr(&net.s_addr, dhcp, DHO_SUBNETMASK) == -1)
+ if (get_option_addr(&net, dhcp, DHO_SUBNETMASK) == -1)
net.s_addr = get_netmask(addr.s_addr);
- if (get_option_addr(&brd.s_addr, dhcp, DHO_BROADCAST) == -1)
+ if (get_option_addr(&brd, dhcp, DHO_BROADCAST) == -1)
brd.s_addr = addr.s_addr | ~net.s_addr;
}
@@ -400,21 +400,17 @@ configure(struct interface *iface, const char *reason,
{
dest.s_addr = addr.s_addr & net.s_addr;
gate.s_addr = 0;
- add_route(iface->name, &dest, &net, &gate, options->metric);
- del_route(iface->name, &dest, &net, &gate, 0);
+ add_route(iface, &dest, &net, &gate, options->metric);
+ del_route(iface, &dest, &net, &gate, 0);
}
#endif
- configure_routes(iface, dhcp, options);
- up = (iface->addr.s_addr != addr.s_addr ||
- iface->net.s_addr != net.s_addr);
iface->addr.s_addr = addr.s_addr;
iface->net.s_addr = net.s_addr;
-
+ configure_routes(iface, dhcp, options);
if (!lease->frominfo)
if (write_lease(iface, dhcp) == -1)
logger(LOG_ERR, "write_lease: %s", strerror(errno));
-
run_script(options, iface->name, reason, dhcp, old);
return 0;
}
diff --git a/dhcp.c b/dhcp.c
index 2469429..1854cf2 100644
--- a/dhcp.c
+++ b/dhcp.c
@@ -52,6 +52,8 @@
#define IPV4R IPV4 | REQUEST
+#define DAD "Duplicate address detected"
+
/* Our aggregate option buffer.
* We ONLY use this when options are split, which for most purposes is
* practically never. See RFC3396 for details. */
@@ -65,8 +67,13 @@ struct dhcp_opt {
static const struct dhcp_opt const dhcp_opts[] = {
{ 1, IPV4 | REQUEST, "subnet_mask" },
- { 2, UINT32, "time_offset" },
+ /* RFC 3442 states that the CSR has to come before all other routes.
+ * For completeness, we also specify static routes, then routers. */
+ { 121, RFC3442 | REQUEST, "classless_static_routes" },
+ { 249, RFC3442, "ms_classless_static_routes" },
+ { 33, IPV4 | ARRAY | REQUEST, "static_routes" },
{ 3, IPV4 | ARRAY | REQUEST, "routers" },
+ { 2, UINT32, "time_offset" },
{ 4, IPV4 | ARRAY, "time_servers" },
{ 5, IPV4 | ARRAY, "ien116_name_servers" },
{ 6, IPV4 | ARRAY, "domain_name_servers" },
@@ -96,7 +103,6 @@ static const struct dhcp_opt const dhcp_opts[] = {
{ 30, UINT8, "mask_supplier" },
{ 31, UINT8, "router_discovery" },
{ 32, IPV4, "router_solicitation_address" },
- { 33, IPV4 | ARRAY | REQUEST, "static_routes" },
{ 34, UINT8, "trailer_encapsulation" },
{ 35, UINT32, "arp_cache_timeout" },
{ 36, UINT16, "ieee802_3_encapsulation" },
@@ -151,8 +157,6 @@ static const struct dhcp_opt const dhcp_opts[] = {
{ 114, STRING, "default_url" },
{ 118, IPV4, "subnet_selection" },
{ 119, STRING | RFC3397, "domain_search" },
- { 121, RFC3442 | REQUEST, "classless_static_routes" },
- { 249, RFC3442, "ms_classless_static_routes" },
{ 0, 0, NULL }
};
@@ -323,25 +327,27 @@ exit:
}
int
-get_option_addr(uint32_t *a, const struct dhcp_message *dhcp, uint8_t option)
+get_option_addr(struct in_addr *a, const struct dhcp_message *dhcp,
+ uint8_t option)
{
const uint8_t *p = get_option_raw(dhcp, option);
if (!p)
return -1;
- memcpy(a, p, sizeof(*a));
+ memcpy(&a->s_addr, p, sizeof(a->s_addr));
return 0;
}
int
get_option_uint32(uint32_t *i, const struct dhcp_message *dhcp, uint8_t option)
{
- uint32_t a;
+ const uint8_t *p = get_option_raw(dhcp, option);
+ uint32_t d;
- if (get_option_addr(&a, dhcp, option) == -1)
+ if (!p)
return -1;
-
- *i = ntohl(a);
+ memcpy(&d, p, sizeof(d));
+ *i = ntohl(d);
return 0;
}
@@ -715,34 +721,39 @@ get_option_routes(const struct dhcp_message *dhcp)
}
static size_t
-encode_rfc1035(const char *src, uint8_t *dst, size_t len)
+encode_rfc1035(const char *src, uint8_t *dst)
{
- const char *c = src;
uint8_t *p = dst;
uint8_t *lp = p++;
- if (len == 0)
+ if (*src == '\0')
return 0;
- while (c < src + len) {
- if (*c == '\0')
+ for (; *src; src++) {
+ if (*src == '\0')
break;
- if (*c == '.') {
+ if (*src == '.') {
/* Skip the trailing . */
- if (c == src + len - 1)
+ if (src[1] == '\0')
break;
*lp = p - lp - 1;
if (*lp == '\0')
return p - dst;
lp = p++;
} else
- *p++ = (uint8_t) *c;
- c++;
+ *p++ = (uint8_t)*src;
}
*lp = p - lp - 1;
*p++ = '\0';
return p - dst;
}
+#define PUTADDR(_type, _val) \
+{ \
+ *p++ = _type; \
+ *p++ = 4; \
+ memcpy(p, &_val.s_addr, 4); \
+ p += 4; \
+}
ssize_t
make_message(struct dhcp_message **message,
const struct interface *iface, const struct dhcp_lease *lease,
@@ -755,6 +766,8 @@ make_message(struct dhcp_message **message,
uint32_t ul;
uint16_t sz;
const struct dhcp_opt *opt;
+ size_t len;
+ const char *hp;
dhcp = xzalloc(sizeof (*dhcp));
m = (uint8_t *)dhcp;
@@ -786,15 +799,18 @@ make_message(struct dhcp_message **message,
case ARPHRD_IEEE1394:
case ARPHRD_INFINIBAND:
dhcp->hwlen = 0;
- if (dhcp->ciaddr == 0)
+ if (dhcp->ciaddr == 0 &&
+ type != DHCP_DECLINE && type != DHCP_RELEASE)
dhcp->flags = htons(BROADCAST_FLAG);
break;
}
- if (up < 0 || up > (time_t)UINT16_MAX)
- dhcp->secs = htons((uint16_t)UINT16_MAX);
- else
- dhcp->secs = htons(up);
+ if (type != DHCP_DECLINE && type != DHCP_RELEASE) {
+ if (up < 0 || up > (time_t)UINT16_MAX)
+ dhcp->secs = htons((uint16_t)UINT16_MAX);
+ else
+ dhcp->secs = htons(up);
+ }
dhcp->xid = xid;
dhcp->cookie = htonl(MAGIC_COOKIE);
@@ -802,7 +818,41 @@ make_message(struct dhcp_message **message,
*p++ = 1;
*p++ = type;
- if (type == DHCP_REQUEST) {
+ if (iface->clientid) {
+ *p++ = DHO_CLIENTID;
+ memcpy(p, iface->clientid, iface->clientid[0] + 1);
+ p += iface->clientid[0] + 1;
+ }
+
+ if (lease->addr.s_addr && !IN_LINKLOCAL(htonl(lease->addr.s_addr))) {
+ if (type == DHCP_DECLINE ||
+ type == DHCP_DISCOVER ||
+ (type == DHCP_REQUEST &&
+ lease->addr.s_addr != iface->addr.s_addr))
+ {
+ PUTADDR(DHO_IPADDRESS, lease->addr);
+ if (lease->server.s_addr)
+ PUTADDR(DHO_SERVERID, lease->server);
+ }
+ }
+
+ if (type == DHCP_DECLINE) {
+ *p++ = DHO_MESSAGE;
+ len = strlen(DAD);
+ *p++ = len;
+ memcpy(p, DAD, len);
+ p += len;
+ }
+
+ if (type == DHCP_RELEASE) {
+ if (lease->server.s_addr)
+ PUTADDR(DHO_SERVERID, lease->server);
+ }
+
+ if (type == DHCP_DISCOVER ||
+ type == DHCP_INFORM ||
+ type == DHCP_REQUEST)
+ {
*p++ = DHO_MAXMESSAGESIZE;
*p++ = 2;
sz = get_mtu(iface->name);
@@ -813,15 +863,7 @@ make_message(struct dhcp_message **message,
sz = htons(sz);
memcpy(p, &sz, 2);
p += 2;
- }
- if (iface->clientid) {
- *p++ = DHO_CLIENTID;
- memcpy(p, iface->clientid, iface->clientid[0] + 1);
- p += iface->clientid[0] + 1;
- }
-
- if (type != DHCP_DECLINE && type != DHCP_RELEASE) {
if (options->userclass[0]) {
*p++ = DHO_USERCLASS;
memcpy(p, options->userclass, options->userclass[0] + 1);
@@ -834,43 +876,31 @@ make_message(struct dhcp_message **message,
options->vendorclassid[0] + 1);
p += options->vendorclassid[0] + 1;
}
- }
- if (type == DHCP_DISCOVER || type == DHCP_REQUEST) {
-#define PUTADDR(_type, _val) \
- { \
- *p++ = _type; \
- *p++ = 4; \
- memcpy(p, &_val.s_addr, 4); \
- p += 4; \
- }
- if (lease->addr.s_addr &&
- lease->addr.s_addr != iface->addr.s_addr &&
- !IN_LINKLOCAL(ntohl(lease->addr.s_addr)))
- {
- PUTADDR(DHO_IPADDRESS, lease->addr);
- if (lease->server.s_addr)
- PUTADDR(DHO_SERVERID, lease->server);
- }
-#undef PUTADDR
-
- if (options->leasetime != 0) {
- *p++ = DHO_LEASETIME;
- *p++ = 4;
- ul = htonl(options->leasetime);
- memcpy(p, &ul, 4);
- p += 4;
+ if (type != DHCP_INFORM) {
+ if (options->leasetime != 0) {
+ *p++ = DHO_LEASETIME;
+ *p++ = 4;
+ ul = htonl(options->leasetime);
+ memcpy(p, &ul, 4);
+ p += 4;
+ }
}
- }
- if (type == DHCP_DISCOVER ||
- type == DHCP_INFORM ||
- type == DHCP_REQUEST)
- {
+ /* Regardless of RFC2132, we should always send a hostname
+ * upto the first dot (the short hostname) as otherwise
+ * confuses some DHCP servers when updating DNS.
+ * The FQDN option should be used if a FQDN is required. */
if (options->hostname[0]) {
*p++ = DHO_HOSTNAME;
- memcpy(p, options->hostname, options->hostname[0] + 1);
- p += options->hostname[0] + 1;
+ hp = strchr(options->hostname, '.');
+ if (hp)
+ len = hp - options->hostname;
+ else
+ len = strlen(options->hostname);
+ *p++ = len;
+ memcpy(p, options->hostname, len);
+ p += len;
}
if (options->fqdn != FQDN_DISABLE) {
/* IETF DHC-FQDN option (81), RFC4702 */
@@ -890,8 +920,7 @@ make_message(struct dhcp_message **message,
*p++ = (options->fqdn & 0x09) | 0x04;
*p++ = 0; /* from server for PTR RR */
*p++ = 0; /* from server for A RR if S=1 */
- ul = encode_rfc1035(options->hostname + 1, p,
- options->hostname[0]);
+ ul = encode_rfc1035(options->hostname, p);
*lp += ul;
p += ul;
}
@@ -999,13 +1028,21 @@ static ssize_t
print_string(char *s, ssize_t len, int dl, const uint8_t *data)
{
uint8_t c;
- const uint8_t *e;
+ const uint8_t *e, *p;
ssize_t bytes = 0;
ssize_t r;
e = data + dl;
while (data < e) {
c = *data++;
+ if (c == '\0') {
+ /* If rest is all NULL, skip it. */
+ for (p = data; p < e; p++)
+ if (*p != '\0')
+ break;
+ if (p == e)
+ break;
+ }
if (!isascii(c) || !isprint(c)) {
if (s) {
if (len < 5) {
@@ -1203,16 +1240,16 @@ configure_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
* message but are not necessarily in the options */
addr.s_addr = dhcp->yiaddr;
setvar(&ep, prefix, "ip_address", inet_ntoa(addr));
- if (get_option_addr(&net.s_addr, dhcp, DHO_SUBNETMASK) == -1) {
+ if (get_option_addr(&net, dhcp, DHO_SUBNETMASK) == -1) {
net.s_addr = get_netmask(addr.s_addr);
setvar(&ep, prefix, "subnet_mask", inet_ntoa(net));
}
i = inet_ntocidr(net);
snprintf(cidr, sizeof(cidr), "%d", inet_ntocidr(net));
setvar(&ep, prefix, "subnet_cidr", cidr);
- if (get_option_addr(&brd.s_addr, dhcp, DHO_BROADCAST) == -1) {
+ if (get_option_addr(&brd, dhcp, DHO_BROADCAST) == -1) {
brd.s_addr = addr.s_addr | ~net.s_addr;
- setvar(&ep, prefix, "broadcast_address", inet_ntoa(net));
+ setvar(&ep, prefix, "broadcast_address", inet_ntoa(brd));
}
addr.s_addr = dhcp->yiaddr & net.s_addr;
setvar(&ep, prefix, "network_number", inet_ntoa(addr));
diff --git a/dhcp.h b/dhcp.h
index e584452..09e8ecb 100644
--- a/dhcp.h
+++ b/dhcp.h
@@ -160,7 +160,7 @@ struct dhcp_lease {
int make_option_mask(uint8_t *, char **, int);
void print_options(void);
char *get_option_string(const struct dhcp_message *, uint8_t);
-int get_option_addr(uint32_t *, const struct dhcp_message *, uint8_t);
+int get_option_addr(struct in_addr *, const struct dhcp_message *, uint8_t);
int get_option_uint32(uint32_t *, const struct dhcp_message *, uint8_t);
int get_option_uint16(uint16_t *, const struct dhcp_message *, uint8_t);
int get_option_uint8(uint8_t *, const struct dhcp_message *, uint8_t);
diff --git a/dhcpcd-hooks/01-test b/dhcpcd-hooks/01-test
index 609b3a1..ef7896d 100644
--- a/dhcpcd-hooks/01-test
+++ b/dhcpcd-hooks/01-test
@@ -1,7 +1,6 @@
# Just echo our DHCP options we have
-case ${reason} in
-TEST) set | grep "^\(interface\|metric\|pid\|reason\|skip_hooks\)=" | sort
+if [ "${reason}" = "TEST" ]; then
+ set | grep "^\(interface\|metric\|pid\|reason\|skip_hooks\)=" | sort
set | grep "^\(new_\|old_\)" | sort
- ;;
-esac
+fi
diff --git a/dhcpcd-hooks/50-dhcpcd-compat b/dhcpcd-hooks/50-dhcpcd-compat
index cba40a4..bb31fd3 100644
--- a/dhcpcd-hooks/50-dhcpcd-compat
+++ b/dhcpcd-hooks/50-dhcpcd-compat
@@ -28,4 +28,14 @@ case "${reason}" in
RENEW) x="up";;
BOUND|INFORM|REBIND|REBOOT|TEST|TIMEOUT|IPV4LL) x="new";;
esac
-set -- "" "${x}"
+
+if [ "${reason}" != "down" ]; then
+ rm -f /var/lib/dhcpcd-"${INTERFACE}".info
+ for x in IPADDR INTERFACE NETMASK BROADCAST NETWORK DHCPSID GATEWAYS \
+ DNSSERVERS DNSDOMAIN DNSSEARCH NISDOMAIN NISSERVERS \
+ NTPSERVERS GATEWAY DNS; do
+ eval echo "${x}=\'\$${x}\'" >> /var/lib/dhcpcd-"${INTERFACE}".info
+ done
+fi
+
+set -- /var/lib/dhcpcd-"${INTERFACE}".info "${x}"
diff --git a/dhcpcd-hooks/50-ntp.conf b/dhcpcd-hooks/50-ntp.conf
index 536f14e..8c92f27 100644
--- a/dhcpcd-hooks/50-ntp.conf
+++ b/dhcpcd-hooks/50-ntp.conf
@@ -2,21 +2,28 @@
# Like our resolv.conf hook script, we store a database of ntp.conf files
# and merge into /etc/ntp.conf
+# You can set the env var NTP_CONF to another file like this
+# dhcpcd -e NTP_CONF=/usr/pkg/etc/ntpd.conf
+# or by adding this to /etc/dhcpcd.enter-hook
+# NTP_CONF=/usr/pkg/etc/ntpd.conf
+# to use openntpd from pkgsrc instead of the system provided ntp.
+
# Detect OpenRC or BSD rc
# Distributions may want to just have their command here instead of this
if type rc-service >/dev/null 2>&1 && rc-service --exists ntpd; then
ntpd_restart_cmd="rc-service ntpd -- --ifstarted --quiet restart"
elif [ -x /etc/rc.d/ntpd ]; then
- ntpd_restart_cmd="/etc/rc.d/ntpd restart"
+ ntpd_restart_cmd="/etc/rc.d/ntpd status && /etc/rc.d/ntpd restart"
elif [ -x /usr/local/etc/rc.d/ntpd ]; then
- ntpd_restart_cmd="/usr/local/etc/rc.d/ntpd restart"
+ ntpd_restart_cmd="/usr/local/etc/rc.d/ntpd status && /usr/local/etc/rc.d/ntpd restart"
fi
ntp_conf_dir="${state_dir}/ntp.conf"
+ntp_conf=${NTP_CONF:-/etc/ntp.conf}
build_ntp_conf()
{
- local cf="/etc/ntp.conf.${interface}"
+ local cf="${ntp_conf}.${interface}"
local interfaces= header= srvs= servers= x=
# Build a list of interfaces
@@ -49,8 +56,8 @@ build_ntp_conf()
fi
# If we changed anything, restart ntpd
- if change_file /etc/ntp.conf "${cf}"; then
- [ -n "${ntpd_restart_cmd}" ] && ${ntpd_restart_cmd}
+ if change_file "${ntp_conf}" "${cf}"; then
+ [ -n "${ntpd_restart_cmd}" ] && eval ${ntpd_restart_cmd}
fi
}
diff --git a/dhcpcd-run-hooks b/dhcpcd-run-hooks
index db9c4f8..8b68c69 100755..100644
--- a/dhcpcd-run-hooks
+++ b/dhcpcd-run-hooks
@@ -20,7 +20,7 @@ for hook in \
do
for skip in ${skip_hooks}; do
case "${hook}" in
- "${skip}") continue 2;;
+ */"${skip}") continue 2;;
*/[0-9][0-9]"-${skip}") continue 2;;
*/[0-9][0-9]"-${skip}.sh") continue 2;;
esac
diff --git a/dhcpcd-run-hooks.8 b/dhcpcd-run-hooks.8
index dca5378..a6a1849 100644
--- a/dhcpcd-run-hooks.8
+++ b/dhcpcd-run-hooks.8
@@ -110,4 +110,4 @@ in a lexical order and then finally
.Sh AUTHORS
.An Roy Marples <roy@marples.name>
.Sh BUGS
-Please report them to http://bugs.marples.name
+Please report them to http://roy.marples.name/projects/dhcpcd
diff --git a/dhcpcd-run-hooks.8.in b/dhcpcd-run-hooks.8.in
index 72669f5..6776cf8 100644
--- a/dhcpcd-run-hooks.8.in
+++ b/dhcpcd-run-hooks.8.in
@@ -24,6 +24,7 @@
.\"
.Dd August 14, 2008
.Dt DHCPCD.SH 8 SMM
+.Os
.Sh NAME
.Nm dhcpcd-run-hooks
.Nd DHCP client configuration script
@@ -110,4 +111,4 @@ in a lexical order and then finally
.Sh AUTHORS
.An Roy Marples <roy@marples.name>
.Sh BUGS
-Please report them to http://bugs.marples.name
+Please report them to http://roy.marples.name/projects/dhcpcd
diff --git a/dhcpcd-run-hooks.in b/dhcpcd-run-hooks.in
index 1e5d5b3..a848260 100644
--- a/dhcpcd-run-hooks.in
+++ b/dhcpcd-run-hooks.in
@@ -79,7 +79,7 @@ remove_markers()
}
# Compare two files
-# It different, replace first with second otherwise remove second
+# If different, replace first with second otherwise remove second
change_file()
{
if type cmp >/dev/null 2>&1; then
@@ -127,7 +127,7 @@ for hook in \
do
for skip in ${skip_hooks}; do
case "${hook}" in
- "${skip}") continue 2;;
+ */"${skip}") continue 2;;
*/[0-9][0-9]"-${skip}") continue 2;;
*/[0-9][0-9]"-${skip}.sh") continue 2;;
esac
diff --git a/dhcpcd.8.in b/dhcpcd.8.in
index 6c82d3f..d3fbebf 100644
--- a/dhcpcd.8.in
+++ b/dhcpcd.8.in
@@ -22,14 +22,15 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd August 20, 2008
+.Dd November 18, 2008
.Dt DHCPCD 8 SMM
+.Os
.Sh NAME
.Nm dhcpcd
.Nd an RFC 2131 compliant DHCP client
.Sh SYNOPSIS
.Nm
-.Op Fl bdknpqABDEGKLSTV
+.Op Fl bdknpqABDEGKLTV
.Op Fl c , -script Ar script
.Op Fl f , -config Ar file
.Op Fl h , -hostname Ar hostname
@@ -324,11 +325,18 @@ itself never does any DNS updates.
encodes the FQDN hostname as specified in
.Li RFC1035 .
.It Fl I , -clientid Ar clientid
-Change the default clientid sent from the interface hardware address.
+Send the
+.Ar clientid .
If the string is of the format 01:02:03 then it is encoded as hex.
-If not set then none is sent.
+For interfaces whose hardware address is longer than 8 bytes, or if the
+.Ar clientid
+is an empty string then
+.Nm
+sends a default
+.Ar clientid
+of the hardware family and the hardware address.
.El
-.Ss Restriciting behaviour
+.Ss Restricting behaviour
.Nm
will try to do as much as it can by default.
However, there are sometimes situations where you don't want the things to be
@@ -427,4 +435,4 @@ RFC 3442, RFC 3927, RFC 4361, RFC 4390, RFC 4702.
.Sh AUTHORS
.An Roy Marples <roy@marples.name>
.Sh BUGS
-Please report them to http://bugs.marples.name
+Please report them to http://roy.marples.name/projects/dhcpcd
diff --git a/dhcpcd.c b/dhcpcd.c
index e674bd2..ff95a83 100644
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -144,14 +144,15 @@ static pid_t
read_pid(const char *pidfile)
{
FILE *fp;
- pid_t pid = 0;
+ pid_t pid;
if ((fp = fopen(pidfile, "r")) == NULL) {
errno = ENOENT;
return 0;
}
- fscanf(fp, "%d", &pid);
+ if (fscanf(fp, "%d", &pid) != 1)
+ pid = 0;
fclose(fp);
return pid;
@@ -240,7 +241,7 @@ parse_string_hwaddr(char *sbuf, ssize_t slen, char *str, int clid)
l = 0;
/* If processing a string on the clientid, first byte should be
* 0 to indicate a non hardware type */
- if (clid) {
+ if (clid && *str) {
*sbuf++ = 0;
l++;
}
@@ -323,7 +324,7 @@ parse_option(int opt, char *oarg, struct options *options)
break;
case 'h':
if (oarg)
- s = parse_string(options->hostname + 1,
+ s = parse_string(options->hostname,
HOSTNAME_MAX_LEN, oarg);
else
s = 0;
@@ -331,11 +332,11 @@ parse_option(int opt, char *oarg, struct options *options)
logger(LOG_ERR, "hostname: %s", strerror(errno));
return -1;
}
- if (s != 0 && options->hostname[1] == '.') {
+ if (s != 0 && options->hostname[0] == '.') {
logger(LOG_ERR, "hostname cannot begin with a .");
return -1;
}
- options->hostname[0] = (uint8_t)s;
+ options->hostname[s] = '\0';
break;
case 'i':
if (oarg)
@@ -528,10 +529,14 @@ parse_option(int opt, char *oarg, struct options *options)
return -1;
}
options->clientid[0] = (uint8_t)s;
+#ifdef CMDLINE_COMPAT
if (s == 0) {
options->options &= ~DHCPCD_DUID;
options->options &= ~DHCPCD_CLIENTID;
}
+#else
+ options->options |= DHCPCD_CLIENTID;
+#endif
break;
case 'K':
options->options &= ~DHCPCD_LINK;
@@ -646,11 +651,11 @@ main(int argc, char **argv)
closefrom(3);
/* Saves calling fflush(stream) in the logger */
setlinebuf(stdout);
- openlog(PACKAGE, LOG_PID, LOG_LOCAL0);
+ openlog(PACKAGE, LOG_PID, LOG_DAEMON);
setlogprefix(PACKAGE ": ");
options = xzalloc(sizeof(*options));
- options->options |= DHCPCD_CLIENTID | DHCPCD_GATEWAY | DHCPCD_DAEMONISE;
+ options->options |= DHCPCD_GATEWAY | DHCPCD_DAEMONISE;
options->options |= DHCPCD_ARP | DHCPCD_IPV4LL | DHCPCD_LINK;
options->timeout = DEFAULT_TIMEOUT;
strlcpy(options->script, SCRIPT, sizeof(options->script));
@@ -660,6 +665,7 @@ main(int argc, char **argv)
"%s %s", PACKAGE, VERSION);
#ifdef CMDLINE_COMPAT
+ options->options |= DHCPCD_CLIENTID;
add_option_mask(options->requestmask, DHO_DNSSERVER);
add_option_mask(options->requestmask, DHO_DNSDOMAIN);
add_option_mask(options->requestmask, DHO_DNSSEARCH);
@@ -675,11 +681,12 @@ main(int argc, char **argv)
}
#endif
- gethostname(options->hostname + 1, sizeof(options->hostname));
- if (strcmp(options->hostname + 1, "(none)") == 0 ||
- strcmp(options->hostname + 1, "localhost") == 0)
- options->hostname[1] = '\0';
- *options->hostname = strlen(options->hostname + 1);
+ gethostname(options->hostname, HOSTNAME_MAX_LEN);
+ /* Ensure that the hostname is NULL terminated */
+ options->hostname[HOSTNAME_MAX_LEN] = '\0';
+ if (strcmp(options->hostname, "(none)") == 0 ||
+ strcmp(options->hostname, "localhost") == 0)
+ options->hostname[0] = '\0';
while ((opt = getopt_long(argc, argv, OPTS EXTRA_OPTS,
longopts, &option_index)) != -1)
@@ -815,14 +822,17 @@ main(int argc, char **argv)
case 'H': /* FALLTHROUGH */
case 'M':
del_option_mask(options->requestmask, DHO_MTU);
+ add_environ(options, "skip_hooks=mtu", 0);
break;
case 'N':
del_option_mask(options->requestmask, DHO_NTPSERVER);
+ add_environ(options, "skip_hooks=ntp.conf", 0);
break;
case 'R':
del_option_mask(options->requestmask, DHO_DNSSERVER);
del_option_mask(options->requestmask, DHO_DNSDOMAIN);
del_option_mask(options->requestmask, DHO_DNSSEARCH);
+ add_environ(options, "skip_hooks=resolv.conf", 0);
break;
case 'S':
add_option_mask(options->requestmask, DHO_MSCSR);
@@ -830,6 +840,7 @@ main(int argc, char **argv)
case 'Y':
del_option_mask(options->requestmask, DHO_NISSERVER);
del_option_mask(options->requestmask, DHO_NISDOMAIN);
+ add_environ(options, "skip_hooks=yp.conf", 0);
break;
#endif
default:
@@ -903,7 +914,8 @@ main(int argc, char **argv)
goto abort;
}
- chdir("/");
+ if (chdir("/") == -1)
+ logger(LOG_ERR, "chdir `/': %s", strerror(errno));
umask(022);
if (sig != 0 && !(options->options & DHCPCD_DAEMONISED)) {
diff --git a/dhcpcd.conf.5.in b/dhcpcd.conf.5.in
index 899aea3..9e0a023 100644
--- a/dhcpcd.conf.5.in
+++ b/dhcpcd.conf.5.in
@@ -22,8 +22,9 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd August 18, 2008
+.Dd November 18, 2008
.Dt DHCPCD.CONF 5 SMM
+.Os
.Sh NAME
.Nm dhcpcd.conf
.Nd dhcpcd configuration file
@@ -47,10 +48,24 @@ Here's a list of available options:
Background immediately.
This is useful for startup scripts which don't disable link messages for
carrier status.
+.It Ic blacklist Ar address
+Ignores all DHCP messages which have this
+.Ar address
+as the server ID.
+This may be expanded in future releases to ignore all packets
+matching either the IP or hardware
+.Ar address .
.It Ic clientid Ar string
-Change the default clientid sent from the interface hardware address.
+Send the
+.Ar clientid .
If the string is of the format 01:02:03 then it is encoded as hex.
-If not set then none is sent.
+For interfaces whose hardware address is longer than 8 bytes, or if the
+.Ar clientid
+is an empty string then
+.Nm dhcpcd
+sends a default
+.Ar clientid
+of the hardware family and the hardware address.
.It Ic duid
Generate an
.Rs
@@ -111,6 +126,8 @@ It can be a variable to be used in
.Xr dhcpcd-run-hooks 8
or the numerical value.
You can specify more options seperated by commas, spaces or more option lines.
+.Ic quiet
+Supress any dhcpcd output to the console, except for errors.
.It Ic require Ar option
Requires the
.Ar option
@@ -152,4 +169,4 @@ If not set then none is sent.
.Sh AUTHORS
.An Roy Marples <roy@marples.name>
.Sh BUGS
-Please report them to http://bugs.marples.name
+Please report them to http://roy.marples.name/projects/dhcpcd
diff --git a/dhcpcd.h b/dhcpcd.h
index 1cd2b5d..7d93315 100644
--- a/dhcpcd.h
+++ b/dhcpcd.h
@@ -82,12 +82,12 @@ struct options {
char script[PATH_MAX];
char pidfile[PATH_MAX];
- char hostname[HOSTNAME_MAX_LEN + 1];
+ char hostname[HOSTNAME_MAX_LEN + 1]; /* We don't store the lenth */
int fqdn;
- uint8_t vendorclassid[VENDORCLASSID_MAX_LEN + 1];
- char clientid[CLIENTID_MAX_LEN + 1];
- uint8_t userclass[USERCLASS_MAX_LEN + 1];
- uint8_t vendor[VENDOR_MAX_LEN + 1];
+ uint8_t vendorclassid[VENDORCLASSID_MAX_LEN + 2];
+ char clientid[CLIENTID_MAX_LEN + 2];
+ uint8_t userclass[USERCLASS_MAX_LEN + 2];
+ uint8_t vendor[VENDOR_MAX_LEN + 2];
size_t blacklist_len;
in_addr_t *blacklist;
diff --git a/if-bsd.c b/if-bsd.c
index bbf1a95..d0ff246 100644
--- a/if-bsd.c
+++ b/if-bsd.c
@@ -98,12 +98,11 @@ if_address(const char *ifname, const struct in_addr *address,
}
int
-if_route(const char *ifname, const struct in_addr *destination,
- const struct in_addr *netmask, const struct in_addr *gateway,
+if_route(const struct interface *iface, const struct in_addr *dest,
+ const struct in_addr *net, const struct in_addr *gate,
_unused int metric, int action)
{
int s;
- static int seq;
union sockunion {
struct sockaddr sa;
struct sockaddr_in sin;
@@ -116,68 +115,83 @@ if_route(const char *ifname, const struct in_addr *destination,
struct rtm
{
struct rt_msghdr hdr;
- char buffer[sizeof(su) * 3];
+ char buffer[sizeof(su) * 4];
} rtm;
- char *bp = rtm.buffer;
+ char *bp = rtm.buffer, *p;
size_t l;
- unsigned char *hwaddr;
- size_t hwlen = 0;
int retval = 0;
+#define ADDSU(_su) { \
+ l = SA_SIZE(&(_su.sa)); \
+ memcpy(bp, &(_su), l); \
+ bp += l; \
+}
+#define ADDADDR(_addr) { \
+ memset (&su, 0, sizeof(su)); \
+ su.sin.sin_family = AF_INET; \
+ su.sin.sin_len = sizeof(su.sin); \
+ memcpy (&su.sin.sin_addr, _addr, sizeof(su.sin.sin_addr)); \
+ ADDSU(su); \
+}
+
if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
return -1;
memset(&rtm, 0, sizeof(rtm));
rtm.hdr.rtm_version = RTM_VERSION;
- rtm.hdr.rtm_seq = ++seq;
+ rtm.hdr.rtm_seq = 1;
if (action == 0)
rtm.hdr.rtm_type = RTM_CHANGE;
else if (action > 0)
rtm.hdr.rtm_type = RTM_ADD;
else
rtm.hdr.rtm_type = RTM_DELETE;
- rtm.hdr.rtm_flags = RTF_UP | RTF_STATIC;
- if (netmask->s_addr == INADDR_BROADCAST)
+ rtm.hdr.rtm_flags = RTF_UP;
+ /* None interface subnet routes are static. */
+ if (gate->s_addr != INADDR_ANY ||
+ net->s_addr != iface->net.s_addr ||
+ dest->s_addr != (iface->addr.s_addr & iface->net.s_addr))
+ rtm.hdr.rtm_flags |= RTF_STATIC;
+ rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
+ if (dest->s_addr == gate->s_addr && net->s_addr == INADDR_BROADCAST)
rtm.hdr.rtm_flags |= RTF_HOST;
+ else {
+ rtm.hdr.rtm_addrs |= RTA_NETMASK;
+ if (rtm.hdr.rtm_flags & RTF_STATIC)
+ rtm.hdr.rtm_flags |= RTF_GATEWAY;
+ if (action >= 0)
+ rtm.hdr.rtm_addrs |= RTA_IFA;
+ }
- /* This order is important */
- rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
-
-#define ADDADDR(_addr) \
- memset (&su, 0, sizeof(su)); \
- su.sin.sin_family = AF_INET; \
- su.sin.sin_len = sizeof(su.sin); \
- memcpy (&su.sin.sin_addr, _addr, sizeof(su.sin.sin_addr)); \
- l = SA_SIZE (&(su.sa)); \
- memcpy (bp, &(su), l); \
- bp += l;
-
- ADDADDR(destination);
-
- if (gateway->s_addr == INADDR_ANY) {
- /* Make us a link layer socket */
- hwaddr = xmalloc(sizeof(unsigned char) * HWADDR_LEN);
- do_interface(ifname, hwaddr, &hwlen, NULL, 0, 0);
+ ADDADDR(dest);
+ if (rtm.hdr.rtm_flags & RTF_HOST ||
+ !(rtm.hdr.rtm_flags & RTF_STATIC))
+ {
+ /* Make us a link layer socket for the host gateway */
memset(&su, 0, sizeof(su));
- su.sdl.sdl_len = sizeof(su.sdl);
- su.sdl.sdl_family = AF_LINK;
- su.sdl.sdl_nlen = strlen(ifname);
- memcpy(&su.sdl.sdl_data, ifname, (size_t)su.sdl.sdl_nlen);
- su.sdl.sdl_alen = hwlen;
- memcpy(((unsigned char *)&su.sdl.sdl_data) + su.sdl.sdl_nlen,
- hwaddr, (size_t)su.sdl.sdl_alen);
-
- l = SA_SIZE(&(su.sa));
- memcpy(bp, &su, l);
- bp += l;
- free(hwaddr);
- } else {
- rtm.hdr.rtm_flags |= RTF_GATEWAY;
- ADDADDR(gateway);
+ su.sdl.sdl_len = sizeof(struct sockaddr_dl);
+ link_addr(iface->name, &su.sdl);
+ ADDSU(su);
+ } else
+ ADDADDR(gate);
+
+ if (rtm.hdr.rtm_addrs & RTA_NETMASK) {
+ /* Ensure that netmask is set correctly */
+ memset(&su, 0, sizeof(su));
+ su.sin.sin_family = AF_INET;
+ su.sin.sin_len = sizeof(su.sin);
+ memcpy(&su.sin.sin_addr, &net->s_addr, sizeof(su.sin.sin_addr));
+ p = su.sa.sa_len + (char *)&su;
+ for (su.sa.sa_len = 0; p > (char *)&su;)
+ if (*--p != 0) {
+ su.sa.sa_len = 1 + p - (char *)&su;
+ break;
+ }
+ ADDSU(su);
}
- ADDADDR(netmask);
-#undef ADDADDR
+ if (rtm.hdr.rtm_addrs & RTA_IFA)
+ ADDADDR(&iface->addr);
rtm.hdr.rtm_msglen = l = bp - (char *)&rtm;
if (write(s, &rtm, l) == -1)
diff --git a/if-linux.c b/if-linux.c
index 1009270..114a084 100644
--- a/if-linux.c
+++ b/if-linux.c
@@ -317,7 +317,7 @@ if_address(const char *ifname,
}
int
-if_route(const char *ifname,
+if_route(const struct interface *iface,
const struct in_addr *destination, const struct in_addr *netmask,
const struct in_addr *gateway, int metric, int action)
{
@@ -325,8 +325,7 @@ if_route(const char *ifname,
unsigned int ifindex;
int retval = 0;
-
- if (!(ifindex = if_nametoindex(ifname))) {
+ if (!(ifindex = if_nametoindex(iface->name))) {
errno = ENODEV;
return -1;
}
@@ -335,8 +334,8 @@ if_route(const char *ifname,
nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
nlm->hdr.nlmsg_type = RTM_NEWROUTE;
if (action == 0)
- nlm->hdr.nlmsg_flags = NLM_F_REPLACE;
- else if (action > 0)
+ nlm->hdr.nlmsg_flags = NLM_F_REPLACE;
+ else if (action == 1)
/*
* ers@google:
* commented out NLM_F_EXCL here and below. We
@@ -351,12 +350,20 @@ if_route(const char *ifname,
nlm->rt.rtm_family = AF_INET;
nlm->rt.rtm_table = RT_TABLE_MAIN;
- if (action < 0)
+ if (action == -1 || action == -2)
nlm->rt.rtm_scope = RT_SCOPE_NOWHERE;
else {
nlm->hdr.nlmsg_flags |= NLM_F_CREATE /*| NLM_F_EXCL*/;
- nlm->rt.rtm_protocol = RTPROT_BOOT;
- if (gateway->s_addr == INADDR_ANY)
+ /* We only change route metrics for kernel routes */
+ if (destination->s_addr ==
+ (iface->addr.s_addr & iface->net.s_addr) &&
+ netmask->s_addr == iface->net.s_addr)
+ nlm->rt.rtm_protocol = RTPROT_KERNEL;
+ else
+ nlm->rt.rtm_protocol = RTPROT_BOOT;
+ if (gateway->s_addr == INADDR_ANY ||
+ (gateway->s_addr == destination->s_addr &&
+ netmask->s_addr == INADDR_BROADCAST))
nlm->rt.rtm_scope = RT_SCOPE_LINK;
else
nlm->rt.rtm_scope = RT_SCOPE_UNIVERSE;
@@ -366,8 +373,15 @@ if_route(const char *ifname,
nlm->rt.rtm_dst_len = inet_ntocidr(*netmask);
add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_DST,
&destination->s_addr, sizeof(destination->s_addr));
- add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_GATEWAY,
- &gateway->s_addr, sizeof(gateway->s_addr));
+ if (nlm->rt.rtm_protocol == RTPROT_KERNEL) {
+ add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_PREFSRC,
+ &iface->addr.s_addr, sizeof(iface->addr.s_addr));
+ }
+ /* If destination == gateway then don't add the gateway */
+ if (destination->s_addr != gateway->s_addr ||
+ netmask->s_addr != INADDR_BROADCAST)
+ add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_GATEWAY,
+ &gateway->s_addr, sizeof(gateway->s_addr));
add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_OIF, ifindex);
add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_PRIORITY, metric);
diff --git a/mk/dist.mk b/mk/dist.mk
index 3d9385b..c4c1947 100644
--- a/mk/dist.mk
+++ b/mk/dist.mk
@@ -1,5 +1,5 @@
-# rules to make a distribution tarball from a git repo
-# Copyright 2008 Roy Marples <roy@marples.name>
+# rules to make a distribution tarball from a svn repo
+# Copyright 2008-2009 Roy Marples <roy@marples.name>
GITREF?= HEAD
DISTPREFIX?= ${PROG}-${VERSION}
diff --git a/net.c b/net.c
index b905573..29344f8 100644
--- a/net.c
+++ b/net.c
@@ -112,9 +112,9 @@ get_netmask(uint32_t addr)
dst = htonl(addr);
if (IN_CLASSA(dst))
return ntohl(IN_CLASSA_NET);
- if (IN_CLASSB (dst))
+ if (IN_CLASSB(dst))
return ntohl(IN_CLASSB_NET);
- if (IN_CLASSC (dst))
+ if (IN_CLASSC(dst))
return ntohl(IN_CLASSC_NET);
return 0;
@@ -634,44 +634,42 @@ get_udp_data(const uint8_t **data, const uint8_t *udp)
}
int
-valid_udp_packet(const uint8_t *data)
+valid_udp_packet(const uint8_t *data, size_t data_len)
{
struct udp_dhcp_packet packet;
- uint16_t bytes;
- uint16_t ipsum;
- uint16_t iplen;
- uint16_t udpsum;
- struct in_addr source;
- struct in_addr dest;
- int retval = 0;
-
- memcpy(&packet, data, sizeof(packet));
- bytes = ntohs(packet.ip.ip_len);
- ipsum = packet.ip.ip_sum;
- iplen = packet.ip.ip_len;
- udpsum = packet.udp.uh_sum;
+ uint16_t bytes, udpsum;
- if (0 != checksum(&packet.ip, sizeof(packet.ip))) {
+ if (data_len > sizeof(packet)) {
+ errno = EINVAL;
+ return -1;
+ }
+ memcpy(&packet, data, data_len);
+ if (checksum(&packet.ip, sizeof(packet.ip)) != 0) {
errno = EINVAL;
return -1;
}
- packet.ip.ip_sum = 0;
- memcpy(&source, &packet.ip.ip_src, sizeof(packet.ip.ip_src));
- memcpy(&dest, &packet.ip.ip_dst, sizeof(packet.ip.ip_dst));
- memset(&packet.ip, 0, sizeof(packet.ip));
+ bytes = ntohs(packet.ip.ip_len);
+ if (data_len < bytes) {
+ errno = EINVAL;
+ return -1;
+ }
+ udpsum = packet.udp.uh_sum;
packet.udp.uh_sum = 0;
-
- packet.ip.ip_p = IPPROTO_UDP;
- memcpy(&packet.ip.ip_src, &source, sizeof(packet.ip.ip_src));
- memcpy(&packet.ip.ip_dst, &dest, sizeof(packet.ip.ip_dst));
+ packet.ip.ip_hl = 0;
+ packet.ip.ip_v = 0;
+ packet.ip.ip_tos = 0;
packet.ip.ip_len = packet.udp.uh_ulen;
- if (udpsum && udpsum != checksum(&packet, bytes)) {
+ packet.ip.ip_id = 0;
+ packet.ip.ip_off = 0;
+ packet.ip.ip_ttl = 0;
+ packet.ip.ip_sum = 0;
+ if (udpsum && checksum(&packet, bytes) != udpsum) {
errno = EINVAL;
- retval = -1;
+ return -1;
}
- return retval;
+ return 0;
}
int
diff --git a/net.h b/net.h
index 3ade025..1447aba 100644
--- a/net.h
+++ b/net.h
@@ -144,14 +144,15 @@ int if_address(const char *, const struct in_addr *, const struct in_addr *,
#define get_address(ifname, addr, net) \
do_interface(ifname, NULL, NULL, addr, net, 1)
-int if_route(const char *, const struct in_addr *, const struct in_addr *,
+int if_route(const struct interface *,
+ const struct in_addr *,const struct in_addr *,
const struct in_addr *, int, int);
-#define add_route(ifname, dest, mask, gate, metric) \
- if_route(ifname, dest, mask, gate, metric, 1)
-#define change_route(ifname, dest, mask, gate, metric) \
- if_route(ifname, dest, mask, gate, metric, 0)
-#define del_route(ifname, dest, mask, gate, metric) \
- if_route(ifname, dest, mask, gate, metric, -1)
+#define add_route(iface, dest, mask, gate, metric) \
+ if_route(iface, dest, mask, gate, metric, 1)
+#define change_route(iface, dest, mask, gate, metric) \
+ if_route(iface, dest, mask, gate, metric, 0)
+#define del_route(iface, dest, mask, gate, metric) \
+ if_route(iface, dest, mask, gate, metric, -1)
void free_routes(struct rt *);
int open_udp_socket(struct interface *);
@@ -159,7 +160,7 @@ const size_t udp_dhcp_len;
ssize_t make_udp_packet(uint8_t **, const uint8_t *, size_t,
struct in_addr, struct in_addr);
ssize_t get_udp_data(const uint8_t **, const uint8_t *);
-int valid_udp_packet(const uint8_t *);
+int valid_udp_packet(const uint8_t *, size_t);
int open_socket(struct interface *, int);
ssize_t send_packet(const struct interface *, struct in_addr,
diff --git a/showlease.c b/showlease.c
index 9bee4ab..27cc543 100644
--- a/showlease.c
+++ b/showlease.c
@@ -258,7 +258,7 @@ exit:
}
int
-get_option_addr(uint32_t *a, const struct dhcp_message *dhcp, uint8_t option)
+get_option_addr32(uint32_t *a, const struct dhcp_message *dhcp, uint8_t option)
{
const uint8_t *p = get_option_raw(dhcp, option);
@@ -273,7 +273,7 @@ get_option_uint32(uint32_t *i, const struct dhcp_message *dhcp, uint8_t option)
{
uint32_t a;
- if (get_option_addr(&a, dhcp, option) == -1)
+ if (get_option_addr32(&a, dhcp, option) == -1)
return -1;
*i = ntohl(a);
@@ -330,11 +330,11 @@ main(int argc, char *argv[])
lease->frominfo = 0;
lease->addr.s_addr = dhcp->yiaddr;
- if (get_option_addr(&lease->net.s_addr, dhcp, DHO_SUBNETMASK) == -1)
+ if (get_option_addr32(&lease->net.s_addr, dhcp, DHO_SUBNETMASK) == -1)
lease->net.s_addr = get_netmask(dhcp->yiaddr);
if (get_option_uint32(&lease->leasetime, dhcp, DHO_LEASETIME) != 0)
lease->leasetime = DEFAULT_LEASETIME;
- get_option_addr(&lease->server.s_addr, dhcp, DHO_SERVERID);
+ get_option_addr32(&lease->server.s_addr, dhcp, DHO_SERVERID);
/* Dm: limit lease time value to avoid negative numbers when
converting to milliseconds */
if ((lease->leasetime != ~0U) && (lease->leasetime > MAX_LEASETIME))
diff --git a/signals.c b/signals.c
index 58679d6..6576afd 100644
--- a/signals.c
+++ b/signals.c
@@ -31,6 +31,7 @@
#include <errno.h>
#include <signal.h>
#include <string.h>
+#include <syslog.h>
#include <unistd.h>
#include "common.h"
@@ -50,7 +51,8 @@ signal_handler(int sig)
{
int serrno = errno;
- write(signal_pipe[1], &sig, sizeof(sig));
+ if (write(signal_pipe[1], &sig, sizeof(sig)) != sizeof(sig))
+ syslog(LOG_ERR, "write signal %d: %s", sig, strerror(errno));
/* Restore errno */
errno = serrno;
}
@@ -69,11 +71,11 @@ signal_read(void)
{
int sig = -1;
char buf[16];
- size_t bytes;
+ ssize_t bytes;
memset(buf, 0, sizeof(buf));
bytes = read(signal_pipe[0], buf, sizeof(buf));
- if (bytes >= sizeof(sig))
+ if (bytes >= 0 && (size_t)bytes >= sizeof(sig))
memcpy(&sig, buf, sizeof(sig));
return sig;
}