diff options
author | Dmitry Shmidt <dimitrysh@google.com> | 2010-01-08 10:47:26 -0800 |
---|---|---|
committer | Dmitry Shmidt <dimitrysh@google.com> | 2010-01-08 10:47:26 -0800 |
commit | 938bc384f44031877543765a9ae18c764f5da9c8 (patch) | |
tree | 3c5d3e2749b7b1bef613a1283373d61945db7421 | |
parent | b22386a3de85d94030c7071760f4a5e3368bfbe5 (diff) | |
download | external_dhcpcd-938bc384f44031877543765a9ae18c764f5da9c8.zip external_dhcpcd-938bc384f44031877543765a9ae18c764f5da9c8.tar.gz external_dhcpcd-938bc384f44031877543765a9ae18c764f5da9c8.tar.bz2 |
dhcpcd: Upgrade from 4.0.1 to 4.0.15
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
-rw-r--r-- | README | 11 | ||||
-rw-r--r-- | client.c | 181 | ||||
-rw-r--r-- | common.c | 9 | ||||
-rw-r--r-- | config.h | 2 | ||||
-rw-r--r-- | configure.c | 22 | ||||
-rw-r--r-- | dhcp.c | 179 | ||||
-rw-r--r-- | dhcp.h | 2 | ||||
-rw-r--r-- | dhcpcd-hooks/01-test | 7 | ||||
-rw-r--r-- | dhcpcd-hooks/50-dhcpcd-compat | 12 | ||||
-rw-r--r-- | dhcpcd-hooks/50-ntp.conf | 17 | ||||
-rw-r--r--[-rwxr-xr-x] | dhcpcd-run-hooks | 2 | ||||
-rw-r--r-- | dhcpcd-run-hooks.8 | 2 | ||||
-rw-r--r-- | dhcpcd-run-hooks.8.in | 3 | ||||
-rw-r--r-- | dhcpcd-run-hooks.in | 4 | ||||
-rw-r--r-- | dhcpcd.8.in | 20 | ||||
-rw-r--r-- | dhcpcd.c | 40 | ||||
-rw-r--r-- | dhcpcd.conf.5.in | 25 | ||||
-rw-r--r-- | dhcpcd.h | 10 | ||||
-rw-r--r-- | if-bsd.c | 104 | ||||
-rw-r--r-- | if-linux.c | 34 | ||||
-rw-r--r-- | mk/dist.mk | 4 | ||||
-rw-r--r-- | net.c | 54 | ||||
-rw-r--r-- | net.h | 17 | ||||
-rw-r--r-- | showlease.c | 8 | ||||
-rw-r--r-- | signals.c | 8 |
25 files changed, 457 insertions, 320 deletions
@@ -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/ @@ -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; } @@ -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(); @@ -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; } @@ -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)); @@ -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 @@ -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 @@ -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; @@ -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) @@ -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); @@ -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} @@ -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 @@ -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)) @@ -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; } |