This commit is contained in:
roy 2014-07-14 11:49:48 +00:00
parent 9d162be235
commit 1f96c74429
8 changed files with 406 additions and 285 deletions

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
__RCSID("$NetBSD: dhcp.c,v 1.13 2014/06/14 20:55:37 roy Exp $"); __RCSID("$NetBSD: dhcp.c,v 1.14 2014/07/14 11:49:48 roy Exp $");
/* /*
* dhcpcd - DHCP client daemon * dhcpcd - DHCP client daemon
@ -128,16 +128,24 @@ static const size_t udp_dhcp_len = sizeof(struct udp_dhcp_packet);
static int dhcp_open(struct interface *); static int dhcp_open(struct interface *);
void void
dhcp_printoptions(const struct dhcpcd_ctx *ctx) dhcp_printoptions(const struct dhcpcd_ctx *ctx,
const struct dhcp_opt *opts, size_t opts_len)
{ {
const char * const *p; const char * const *p;
size_t i; size_t i, j;
const struct dhcp_opt *opt; const struct dhcp_opt *opt, *opt2;
for (p = dhcp_params; *p; p++) for (p = dhcp_params; *p; p++)
printf(" %s\n", *p); printf(" %s\n", *p);
for (i = 0, opt = ctx->dhcp_opts; i < ctx->dhcp_opts_len; i++, opt++) for (i = 0, opt = ctx->dhcp_opts; i < ctx->dhcp_opts_len; i++, opt++) {
for (j = 0, opt2 = opts; j < opts_len; j++, opt2++)
if (opt->option == opt2->option)
break;
if (j == opts_len)
printf("%03d %s\n", opt->option, opt->var);
}
for (i = 0, opt = opts; i < opts_len; i++, opt++)
printf("%03d %s\n", opt->option, opt->var); printf("%03d %s\n", opt->option, opt->var);
} }
@ -289,7 +297,7 @@ decode_rfc3442(char *out, size_t len, const uint8_t *p, size_t pl)
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
ocets = (cidr + 7) / 8; ocets = (cidr + 7) / NBBY;
if (!out) { if (!out) {
p += 4 + ocets; p += 4 + ocets;
bytes += ((4 * 4) * 2) + 4; bytes += ((4 * 4) * 2) + 4;
@ -360,7 +368,7 @@ decode_rfc3442_rt(const uint8_t *data, size_t dl)
} }
TAILQ_INSERT_TAIL(routes, rt, next); TAILQ_INSERT_TAIL(routes, rt, next);
ocets = (cidr + 7) / 8; ocets = (cidr + 7) / NBBY;
/* If we have ocets then we have a destination and netmask */ /* If we have ocets then we have a destination and netmask */
if (ocets > 0) { if (ocets > 0) {
memcpy(&rt->dest.s_addr, p, ocets); memcpy(&rt->dest.s_addr, p, ocets);
@ -946,6 +954,30 @@ make_message(struct dhcp_message **message,
goto toobig; goto toobig;
*p++ = (uint8_t)opt->option; *p++ = (uint8_t)opt->option;
} }
for (i = 0, opt = ifo->dhcp_override;
i < ifo->dhcp_override_len;
i++, opt++)
{
/* Check if added above */
for (lp = n_params + 1; lp < p; lp++)
if (*lp == (uint8_t)opt->option)
break;
if (lp < p)
continue;
if (!(opt->type & REQUEST ||
has_option_mask(ifo->requestmask, opt->option)))
continue;
if (opt->type & NOREQ)
continue;
if (type == DHCP_INFORM &&
(opt->option == DHO_RENEWALTIME ||
opt->option == DHO_REBINDTIME))
continue;
len = (size_t)((p - m) + 2);
if (len > sizeof(*dhcp))
goto toobig;
*p++ = (uint8_t)opt->option;
}
*n_params = (uint8_t)(p - n_params - 1); *n_params = (uint8_t)(p - n_params - 1);
} }
@ -2736,40 +2768,23 @@ dhcp_open(struct interface *ifp)
} }
int int
dhcp_dump(struct dhcpcd_ctx *ctx, const char *ifname) dhcp_dump(struct interface *ifp)
{ {
struct interface *ifp;
struct dhcp_state *state; struct dhcp_state *state;
if (ctx->ifaces == NULL) {
ctx->ifaces = malloc(sizeof(*ctx->ifaces));
if (ctx->ifaces == NULL)
return -1;
TAILQ_INIT(ctx->ifaces);
}
state = NULL;
ifp = calloc(1, sizeof(*ifp));
if (ifp == NULL)
goto eexit;
ifp->ctx = ctx;
TAILQ_INSERT_HEAD(ctx->ifaces, ifp, next);
ifp->if_data[IF_DATA_DHCP] = state = calloc(1, sizeof(*state)); ifp->if_data[IF_DATA_DHCP] = state = calloc(1, sizeof(*state));
if (state == NULL) if (state == NULL)
goto eexit; goto eexit;
ifp->options = calloc(1, sizeof(*ifp->options));
if (ifp->options == NULL)
goto eexit;
strlcpy(ifp->name, ifname, sizeof(ifp->name));
snprintf(state->leasefile, sizeof(state->leasefile), snprintf(state->leasefile, sizeof(state->leasefile),
LEASEFILE, ifp->name); LEASEFILE, ifp->name);
state->new = read_lease(ifp); state->new = read_lease(ifp);
if (state->new == NULL && errno == ENOENT) { if (state->new == NULL && errno == ENOENT) {
strlcpy(state->leasefile, ifname, sizeof(state->leasefile)); strlcpy(state->leasefile, ifp->name, sizeof(state->leasefile));
state->new = read_lease(ifp); state->new = read_lease(ifp);
} }
if (state->new == NULL) { if (state->new == NULL) {
if (errno == ENOENT) if (errno == ENOENT)
syslog(LOG_ERR, "%s: no lease to dump", ifname); syslog(LOG_ERR, "%s: no lease to dump", ifp->name);
return -1; return -1;
} }
state->reason = "DUMP"; state->reason = "DUMP";
@ -3018,6 +3033,13 @@ dhcp_start(struct interface *ifp)
if (!(ifp->options->options & DHCPCD_IPV4)) if (!(ifp->options->options & DHCPCD_IPV4))
return; return;
/* No point in delaying a static configuration */
if (ifp->options->options & DHCPCD_STATIC &&
!(ifp->options->options & DHCPCD_INFORM))
{
tv.tv_sec = 0;
tv.tv_usec = 0;
} else {
tv.tv_sec = DHCP_MIN_DELAY; tv.tv_sec = DHCP_MIN_DELAY;
tv.tv_usec = (suseconds_t)arc4random_uniform( tv.tv_usec = (suseconds_t)arc4random_uniform(
(DHCP_MAX_DELAY - DHCP_MIN_DELAY) * 1000000); (DHCP_MAX_DELAY - DHCP_MIN_DELAY) * 1000000);
@ -3025,6 +3047,8 @@ dhcp_start(struct interface *ifp)
syslog(LOG_DEBUG, syslog(LOG_DEBUG,
"%s: delaying DHCP for %0.1f seconds", "%s: delaying DHCP for %0.1f seconds",
ifp->name, timeval_to_double(&tv)); ifp->name, timeval_to_double(&tv));
}
eloop_timeout_add_tv(ifp->ctx->eloop, &tv, dhcp_start1, ifp); eloop_timeout_add_tv(ifp->ctx->eloop, &tv, dhcp_start1, ifp);
} }

View File

@ -1,4 +1,4 @@
.\" $NetBSD: dhcpcd.8.in,v 1.28 2014/06/14 20:55:37 roy Exp $ .\" $NetBSD: dhcpcd.8.in,v 1.29 2014/07/14 11:49:48 roy Exp $
.\" Copyright (c) 2006-2014 Roy Marples .\" Copyright (c) 2006-2014 Roy Marples
.\" All rights reserved .\" All rights reserved
.\" .\"
@ -23,7 +23,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE. .\" SUCH DAMAGE.
.\" .\"
.Dd June 2, 2014 .Dd July 7, 2014
.Dt DHCPCD 8 .Dt DHCPCD 8
.Os .Os
.Sh NAME .Sh NAME
@ -76,7 +76,7 @@
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm .Nm
is an implementation of the DHCP client specified in is an implementation of the DHCP client specified in
.%R RFC 2131 . .Li RFC 2131 .
.Nm .Nm
gets the host information gets the host information
.Po .Po
@ -104,17 +104,17 @@ to renew early.
.Pp .Pp
.Nm .Nm
is also an implementation of the BOOTP client specified in is also an implementation of the BOOTP client specified in
.%R RFC 951 . .Li RFC 951 .
.Pp .Pp
.Nm .Nm
is also an implementation of the IPv6 Router Solicitor as specified in is also an implementation of the IPv6 Router Solicitor as specified in
.%R RFC 4861 .Li RFC 4861
and and
.%R RFC 6106 . .Li RFC 6106 .
.Pp .Pp
.Nm .Nm
is also an implemenation of the DHCPv6 client as specified in is also an implemenation of the DHCPv6 client as specified in
.%R RFC 3315 . .Li RFC 3315 .
By default, By default,
.Nm .Nm
only starts DHCPv6 when instructed to do so by an IPV6 Router Advertisement. only starts DHCPv6 when instructed to do so by an IPV6 Router Advertisement.
@ -212,7 +212,7 @@ instead of the default
.Pa @SCRIPT@ . .Pa @SCRIPT@ .
.It Fl D , Fl Fl duid .It Fl D , Fl Fl duid
Generate an Generate an
.%R RFC 4361 .Li RFC 4361
compliant clientid. compliant clientid.
This requires persistent storage and not all DHCP servers work with it so it This requires persistent storage and not all DHCP servers work with it so it
is not enabled by default. is not enabled by default.
@ -260,7 +260,7 @@ are disable, none, ptr and both.
itself never does any DNS updates. itself never does any DNS updates.
.Nm .Nm
encodes the FQDN hostname as specified in encodes the FQDN hostname as specified in
.%R RFC1035 . .Li RFC1035 .
.It Fl f , Fl Fl config Ar file .It Fl f , Fl Fl config Ar file
Specify a config to load instead of Specify a config to load instead of
.Pa @SYSCONFDIR@/dhcpcd.conf . .Pa @SYSCONFDIR@/dhcpcd.conf .
@ -553,6 +553,14 @@ Dumps the last lease for the
to stdout. to stdout.
.Ar interface .Ar interface
could also be a path to a DHCP wire formatted file. could also be a path to a DHCP wire formatted file.
Use the
.Fl 4
or
.Fl 6
flags to specify an address family.
Pass a 2nd
.Fl U, Fl Fl dumplease option to dump a secondary lease, such as
DHCPv6 Prefix Delegation when not being mixed with another IA type.
.It Fl V, Fl Fl variables .It Fl V, Fl Fl variables
Display a list of option codes and the associated variable for use in Display a list of option codes and the associated variable for use in
.Xr dhcpcd-run-hooks 8 . .Xr dhcpcd-run-hooks 8 .
@ -672,7 +680,8 @@ RFC\ 951, RFC\ 1534, RFC\ 2104, RFC\ 2131, RFC\ 2132, RFC\ 2563, RFC\ 2855,
RFC\ 3004, RFC\ 3118, RFC\ 3203, RFC\ 3315, RFC\ 3361, RFC\ 3633, RFC\ 3396, RFC\ 3004, RFC\ 3118, RFC\ 3203, RFC\ 3315, RFC\ 3361, RFC\ 3633, RFC\ 3396,
RFC\ 3397, RFC\ 3442, RFC\ 3495, RFC\ 3925, RFC\ 3927, RFC\ 4039, RFC\ 4075, RFC\ 3397, RFC\ 3442, RFC\ 3495, RFC\ 3925, RFC\ 3927, RFC\ 4039, RFC\ 4075,
RFC\ 4242, RFC\ 4361, RFC\ 4390, RFC\ 4702, RFC\ 4074, RFC\ 4861, RFC\ 4833, RFC\ 4242, RFC\ 4361, RFC\ 4390, RFC\ 4702, RFC\ 4074, RFC\ 4861, RFC\ 4833,
RFC\ 5227, RFC\ 5942, RFC\ 5969, RFC\ 6106, RFC\ 6334, RFC\ 6704, RFC\ 7217. RFC\ 5227, RFC\ 5942, RFC\ 5969, RFC\ 6106, RFC\ 6334, RFC\ 6603, RFC\ 6704,
RFC\ 7217.
.Sh AUTHORS .Sh AUTHORS
.An Roy Marples Aq Mt roy@marples.name .An Roy Marples Aq Mt roy@marples.name
.Sh BUGS .Sh BUGS

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
__RCSID("$NetBSD: dhcpcd.c,v 1.5 2014/06/14 20:55:37 roy Exp $"); __RCSID("$NetBSD: dhcpcd.c,v 1.6 2014/07/14 11:49:48 roy Exp $");
/* /*
* dhcpcd - DHCP client daemon * dhcpcd - DHCP client daemon
@ -142,14 +142,14 @@ free_globals(struct dhcpcd_ctx *ctx)
struct dhcp_opt *opt; struct dhcp_opt *opt;
if (ctx->ifac) { if (ctx->ifac) {
for (ctx->ifac--; ctx->ifac >= 0; ctx->ifac--) for (; ctx->ifac > 0; ctx->ifac--)
free(ctx->ifav[ctx->ifac]); free(ctx->ifav[ctx->ifac - 1]);
free(ctx->ifav); free(ctx->ifav);
ctx->ifav = NULL; ctx->ifav = NULL;
} }
if (ctx->ifdc) { if (ctx->ifdc) {
for (ctx->ifdc--; ctx->ifdc >= 0; ctx->ifdc--) for (; ctx->ifdc > 0; ctx->ifdc--)
free(ctx->ifdv[ctx->ifdc]); free(ctx->ifdv[ctx->ifdc - 1]);
free(ctx->ifdv); free(ctx->ifdv);
ctx->ifdv = NULL; ctx->ifdv = NULL;
} }
@ -326,6 +326,9 @@ configure_interface1(struct interface *ifp)
{ {
struct if_options *ifo = ifp->options; struct if_options *ifo = ifp->options;
int ra_global, ra_iface; int ra_global, ra_iface;
#ifdef INET6
size_t i;
#endif
/* Do any platform specific configuration */ /* Do any platform specific configuration */
if_conf(ifp); if_conf(ifp);
@ -342,7 +345,7 @@ configure_interface1(struct interface *ifp)
ifo->options &= ~(DHCPCD_ARP | DHCPCD_IPV4LL); ifo->options &= ~(DHCPCD_ARP | DHCPCD_IPV4LL);
if (!(ifp->flags & (IFF_POINTOPOINT | IFF_LOOPBACK | IFF_MULTICAST))) if (!(ifp->flags & (IFF_POINTOPOINT | IFF_LOOPBACK | IFF_MULTICAST)))
ifo->options &= ~DHCPCD_IPV6RS; ifo->options &= ~DHCPCD_IPV6RS;
if (ifo->options & DHCPCD_LINK && if_carrier(ifp) == LINK_UNKNOWN) if (ifo->options & DHCPCD_LINK && ifp->carrier == LINK_UNKNOWN)
ifo->options &= ~DHCPCD_LINK; ifo->options &= ~DHCPCD_LINK;
if (ifo->metric != -1) if (ifo->metric != -1)
@ -434,18 +437,28 @@ configure_interface1(struct interface *ifp)
} }
#ifdef INET6 #ifdef INET6
if (ifo->ia == NULL && ifo->options & DHCPCD_IPV6) { if (ifo->options & DHCPCD_IPV6) {
if (ifo->ia == NULL) {
ifo->ia = malloc(sizeof(*ifo->ia)); ifo->ia = malloc(sizeof(*ifo->ia));
if (ifo->ia == NULL) if (ifo->ia == NULL)
syslog(LOG_ERR, "%s: %m", __func__); syslog(LOG_ERR, "%s: %m", __func__);
else { else {
if (ifo->ia_type == 0)
ifo->ia_type = D6_OPTION_IA_NA;
memcpy(ifo->ia->iaid, ifo->iaid, sizeof(ifo->iaid));
ifo->ia_len = 1; ifo->ia_len = 1;
ifo->ia->ia_type = D6_OPTION_IA_NA;
memcpy(ifo->ia->iaid, ifo->iaid,
sizeof(ifo->iaid));
memset(&ifo->ia->addr, 0,
sizeof(ifo->ia->addr));
ifo->ia->sla = NULL; ifo->ia->sla = NULL;
ifo->ia->sla_len = 0; ifo->ia->sla_len = 0;
} }
} else {
for (i = 0; i < ifo->ia_len; i++) {
if (!ifo->ia[i].iaid_set)
memcpy(ifo->ia->iaid, ifo->iaid,
sizeof(ifo->iaid));
}
}
} }
#endif #endif
@ -496,10 +509,23 @@ dhcpcd_handlecarrier(struct dhcpcd_ctx *ctx, int carrier, unsigned int flags,
if (ifp == NULL || !(ifp->options->options & DHCPCD_LINK)) if (ifp == NULL || !(ifp->options->options & DHCPCD_LINK))
return; return;
if (carrier == LINK_UNKNOWN) switch(carrier) {
case LINK_UNKNOWN:
carrier = if_carrier(ifp); /* will set ifp->flags */ carrier = if_carrier(ifp); /* will set ifp->flags */
else break;
case LINK_UP:
/* we have a carrier! however, we need to ignore the flags
* set in the kernel message as sometimes this message is
* reported before IFF_UP is set by the kernel even though
* dhcpcd has already set it.
*
* So we check the flags now. If IFF_UP is still not set
* then we should expect an accompanying link_down message */
if_setflag(ifp, 0); /* will set ifp->flags */
break;
default:
ifp->flags = flags; ifp->flags = flags;
}
if (carrier == LINK_UNKNOWN) if (carrier == LINK_UNKNOWN)
syslog(LOG_ERR, "%s: carrier_status: %m", ifname); syslog(LOG_ERR, "%s: carrier_status: %m", ifname);
@ -547,6 +573,8 @@ warn_iaid_conflict(struct interface *ifp, uint8_t *iaid)
TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) { TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) {
if (ifn == ifp) if (ifn == ifp)
continue; continue;
if (ifn->options->options & DHCPCD_PFXDLGONLY)
continue;
if (memcmp(ifn->options->iaid, iaid, if (memcmp(ifn->options->iaid, iaid,
sizeof(ifn->options->iaid)) == 0) sizeof(ifn->options->iaid)) == 0)
break; break;
@ -558,12 +586,26 @@ warn_iaid_conflict(struct interface *ifp, uint8_t *iaid)
} }
/* This is only a problem if the interfaces are on the same network. */ /* This is only a problem if the interfaces are on the same network. */
if (ifn) if (ifn && strcmp(ifp->name, ifn->name))
syslog(LOG_ERR, syslog(LOG_ERR,
"%s: IAID conflicts with one assigned to %s", "%s: IAID conflicts with one assigned to %s",
ifp->name, ifn->name); ifp->name, ifn->name);
} }
static void
pre_start(struct interface *ifp)
{
/* Add our link-local address before upping the interface
* so our RFC7217 address beats the hwaddr based one.
* This is also a safety check incase it was ripped out
* from under us. */
if (ifp->options->options & DHCPCD_IPV6 && ipv6_start(ifp) == -1) {
syslog(LOG_ERR, "%s: ipv6_start: %m", ifp->name);
ifp->options->options &= DHCPCD_IPV6;
}
}
void void
dhcpcd_startinterface(void *arg) dhcpcd_startinterface(void *arg)
{ {
@ -572,24 +614,11 @@ dhcpcd_startinterface(void *arg)
size_t i; size_t i;
char buf[DUID_LEN * 3]; char buf[DUID_LEN * 3];
/* Add our link-local address before upping the interface pre_start(ifp);
* so our RFC7217 address beats the hwaddr based one.
* This is also a safety check incase it was ripped out
* from under us. */
if (ifo->options & DHCPCD_IPV6 && ipv6_start(ifp) == -1) {
syslog(LOG_ERR, "%s: ipv6_start: %m", ifp->name);
ifo->options &= DHCPCD_IPV6;
}
if (!(ifp->flags & IFF_UP) && if_carrier(ifp) != LINK_UNKNOWN) {
if (if_up(ifp) == -1) if (if_up(ifp) == -1)
syslog(LOG_ERR, "%s: if_up: %m", syslog(LOG_ERR, "%s: if_up: %m", ifp->name);
ifp->name);
}
if (ifp->carrier == LINK_UNKNOWN) if (ifp->carrier == LINK_DOWN && ifo->options & DHCPCD_LINK) {
dhcpcd_handlecarrier(ifp->ctx, LINK_UNKNOWN, 0, ifp->name);
if (ifp->carrier == LINK_DOWN) {
syslog(LOG_INFO, "%s: waiting for carrier", ifp->name); syslog(LOG_INFO, "%s: waiting for carrier", ifp->name);
return; return;
} }
@ -599,11 +628,17 @@ dhcpcd_startinterface(void *arg)
if (ifp->ctx->duid == NULL) { if (ifp->ctx->duid == NULL) {
if (duid_init(ifp) == 0) if (duid_init(ifp) == 0)
return; return;
if (!(ifo->options & DHCPCD_PFXDLGONLY))
syslog(LOG_INFO, "DUID %s", syslog(LOG_INFO, "DUID %s",
hwaddr_ntoa(ifp->ctx->duid, ifp->ctx->duid_len, hwaddr_ntoa(ifp->ctx->duid,
ifp->ctx->duid_len,
buf, sizeof(buf))); buf, sizeof(buf)));
} }
}
if (ifo->options & (DHCPCD_DUID | DHCPCD_IPV6) &&
!(ifo->options & DHCPCD_PFXDLGONLY))
{
/* Report IAIDs */ /* Report IAIDs */
syslog(LOG_INFO, "%s: IAID %s", ifp->name, syslog(LOG_INFO, "%s: IAID %s", ifp->name,
hwaddr_ntoa(ifo->iaid, sizeof(ifo->iaid), hwaddr_ntoa(ifo->iaid, sizeof(ifo->iaid),
@ -624,10 +659,12 @@ dhcpcd_startinterface(void *arg)
if (ifo->options & DHCPCD_IPV6) { if (ifo->options & DHCPCD_IPV6) {
if (ifo->options & DHCPCD_IPV6RS && if (ifo->options & DHCPCD_IPV6RS &&
!(ifo->options & DHCPCD_INFORM)) !(ifo->options & (DHCPCD_INFORM | DHCPCD_PFXDLGONLY)))
ipv6nd_startrs(ifp); ipv6nd_startrs(ifp);
if (!(ifo->options & DHCPCD_IPV6RS)) { if (!(ifo->options & DHCPCD_IPV6RS) ||
ifo->options & DHCPCD_IA_FORCED)
{
ssize_t nolease; ssize_t nolease;
if (ifo->options & DHCPCD_IA_FORCED) if (ifo->options & DHCPCD_IA_FORCED)
@ -654,6 +691,8 @@ dhcpcd_startinterface(void *arg)
"%s: dhcp6_start: %m", ifp->name); "%s: dhcp6_start: %m", ifp->name);
} }
} }
if (ifo->options & DHCPCD_PFXDLGONLY)
return;
if (ifo->options & DHCPCD_IPV4) if (ifo->options & DHCPCD_IPV4)
dhcp_start(ifp); dhcp_start(ifp);
@ -674,7 +713,7 @@ handle_link(void *arg)
} }
static void static void
init_state(struct interface *ifp, int argc, char **argv) dhcpcd_initstate1(struct interface *ifp, int argc, char **argv)
{ {
struct if_options *ifo; struct if_options *ifo;
@ -700,34 +739,27 @@ init_state(struct interface *ifp, int argc, char **argv)
} }
} }
void
dhcpcd_initstate(struct interface *ifp)
{
dhcpcd_initstate1(ifp, ifp->ctx->argc, ifp->ctx->argv);
}
static void static void
run_preinit(struct interface *ifp) run_preinit(struct interface *ifp)
{ {
const char *reason;
reason = NULL; /* appease gcc */ pre_start(ifp);
if (ifp->options->options & DHCPCD_LINK) { if (ifp->ctx->options & DHCPCD_TEST)
switch (if_carrier(ifp)) {
case LINK_DOWN:
ifp->carrier = LINK_DOWN;
reason = "NOCARRIER";
break;
case LINK_UP:
ifp->carrier = LINK_UP;
reason = "CARRIER";
break;
default:
ifp->carrier = LINK_UNKNOWN;
return; return;
}
} else
ifp->carrier = LINK_UNKNOWN;
if (!(ifp->ctx->options & DHCPCD_TEST))
script_runreason(ifp, "PREINIT"); script_runreason(ifp, "PREINIT");
if (ifp->carrier != LINK_UNKNOWN && !(ifp->ctx->options & DHCPCD_TEST)) if (ifp->carrier != LINK_UNKNOWN &&
script_runreason(ifp, reason); ifp->options->options & DHCPCD_LINK)
script_runreason(ifp,
ifp->carrier == LINK_UP ? "CARRIER" : "NOCARRIER");
} }
int int
@ -735,7 +767,7 @@ dhcpcd_handleinterface(void *arg, int action, const char *ifname)
{ {
struct dhcpcd_ctx *ctx; struct dhcpcd_ctx *ctx;
struct if_head *ifs; struct if_head *ifs;
struct interface *ifp, *ifn, *ifl = NULL; struct interface *ifp, *iff, *ifn;
const char * const argv[] = { ifname }; const char * const argv[] = { ifname };
int i; int i;
@ -746,6 +778,7 @@ dhcpcd_handleinterface(void *arg, int action, const char *ifname)
errno = ESRCH; errno = ESRCH;
return -1; return -1;
} }
syslog(LOG_DEBUG, "%s: interface departed", ifp->name);
ifp->options->options |= DHCPCD_DEPARTED; ifp->options->options |= DHCPCD_DEPARTED;
stop_interface(ifp); stop_interface(ifp);
return 0; return 0;
@ -767,22 +800,24 @@ dhcpcd_handleinterface(void *arg, int action, const char *ifname)
continue; continue;
i = 0; i = 0;
/* Check if we already have the interface */ /* Check if we already have the interface */
ifl = if_find(ctx, ifp->name); iff = if_find(ctx, ifp->name);
if (ifl) { if (iff) {
syslog(LOG_DEBUG, "%s: interface updated", iff->name);
/* The flags and hwaddr could have changed */ /* The flags and hwaddr could have changed */
ifl->flags = ifp->flags; iff->flags = ifp->flags;
ifl->hwlen = ifp->hwlen; iff->hwlen = ifp->hwlen;
if (ifp->hwlen != 0) if (ifp->hwlen != 0)
memcpy(ifl->hwaddr, ifp->hwaddr, ifl->hwlen); memcpy(iff->hwaddr, ifp->hwaddr, iff->hwlen);
} else { } else {
syslog(LOG_DEBUG, "%s: interface added", ifp->name);
TAILQ_REMOVE(ifs, ifp, next); TAILQ_REMOVE(ifs, ifp, next);
TAILQ_INSERT_TAIL(ctx->ifaces, ifp, next); TAILQ_INSERT_TAIL(ctx->ifaces, ifp, next);
} dhcpcd_initstate(ifp);
if (action > 0) {
init_state(ifp, ctx->argc, ctx->argv);
run_preinit(ifp); run_preinit(ifp);
dhcpcd_startinterface(ifp); iff = ifp;
} }
if (action > 0)
dhcpcd_startinterface(iff);
} }
/* Free our discovered list */ /* Free our discovered list */
@ -857,7 +892,7 @@ reconf_reboot(struct dhcpcd_ctx *ctx, int action, int argc, char **argv, int oi)
if_free(ifp); if_free(ifp);
} else { } else {
TAILQ_INSERT_TAIL(ctx->ifaces, ifp, next); TAILQ_INSERT_TAIL(ctx->ifaces, ifp, next);
init_state(ifp, argc, argv); dhcpcd_initstate1(ifp, argc, argv);
run_preinit(ifp); run_preinit(ifp);
dhcpcd_startinterface(ifp); dhcpcd_startinterface(ifp);
} }
@ -870,7 +905,7 @@ reconf_reboot(struct dhcpcd_ctx *ctx, int action, int argc, char **argv, int oi)
static void static void
stop_all_interfaces(struct dhcpcd_ctx *ctx, int do_release) stop_all_interfaces(struct dhcpcd_ctx *ctx, int do_release)
{ {
struct interface *ifp; struct interface *ifp, *ifpm;
/* drop_dhcp could change the order, so we do it like this. */ /* drop_dhcp could change the order, so we do it like this. */
for (;;) { for (;;) {
@ -878,6 +913,10 @@ stop_all_interfaces(struct dhcpcd_ctx *ctx, int do_release)
ifp = TAILQ_LAST(ctx->ifaces, if_head); ifp = TAILQ_LAST(ctx->ifaces, if_head);
if (ifp == NULL) if (ifp == NULL)
break; break;
/* Stop the master interface only */
ifpm = if_find(ifp->ctx, ifp->name);
if (ifpm)
ifp = ifpm;
if (do_release) { if (do_release) {
ifp->options->options |= DHCPCD_RELEASE; ifp->options->options |= DHCPCD_RELEASE;
ifp->options->options &= ~DHCPCD_PERSISTENT; ifp->options->options &= ~DHCPCD_PERSISTENT;
@ -1250,10 +1289,13 @@ main(int argc, char **argv)
i = 1; i = 1;
break; break;
case 'U': case 'U':
i = 2; if (i == 3)
i = 4;
else if (i != 4)
i = 3;
break; break;
case 'V': case 'V':
i = 3; i = 2;
break; break;
case '?': case '?':
usage(); usage();
@ -1267,25 +1309,36 @@ main(int argc, char **argv)
ctx.ifv = argv + optind; ctx.ifv = argv + optind;
ifo = read_config(&ctx, NULL, NULL, NULL); ifo = read_config(&ctx, NULL, NULL, NULL);
if (ifo == NULL)
goto exit_failure;
opt = add_options(&ctx, NULL, ifo, argc, argv); opt = add_options(&ctx, NULL, ifo, argc, argv);
if (opt != 1) { if (opt != 1) {
if (opt == 0) if (opt == 0)
usage(); usage();
goto exit_failure; goto exit_failure;
} }
if (i == 3) { if (i == 2) {
printf("Interface options:\n"); printf("Interface options:\n");
if (optind == argc - 1) {
free_options(ifo);
ifo = read_config(&ctx, argv[optind], NULL, NULL);
if (ifo == NULL)
goto exit_failure;
add_options(&ctx, NULL, ifo, argc, argv);
}
if_printoptions(); if_printoptions();
#ifdef INET #ifdef INET
if (family == 0 || family == AF_INET) { if (family == 0 || family == AF_INET) {
printf("\nDHCPv4 options:\n"); printf("\nDHCPv4 options:\n");
dhcp_printoptions(&ctx); dhcp_printoptions(&ctx,
ifo->dhcp_override, ifo->dhcp_override_len);
} }
#endif #endif
#ifdef INET6 #ifdef INET6
if (family == 0 || family == AF_INET6) { if (family == 0 || family == AF_INET6) {
printf("\nDHCPv6 options:\n"); printf("\nDHCPv6 options:\n");
dhcp6_printoptions(&ctx); dhcp6_printoptions(&ctx,
ifo->dhcp6_override, ifo->dhcp6_override_len);
} }
#endif #endif
goto exit_success; goto exit_success;
@ -1296,6 +1349,8 @@ main(int argc, char **argv)
ctx.options |= DHCPCD_TEST; ctx.options |= DHCPCD_TEST;
else else
ctx.options |= DHCPCD_DUMPLEASE; ctx.options |= DHCPCD_DUMPLEASE;
if (i == 4)
ctx.options |= DHCPCD_PFXDLGONLY;
ctx.options |= DHCPCD_PERSISTENT; ctx.options |= DHCPCD_PERSISTENT;
ctx.options &= ~DHCPCD_DAEMONISE; ctx.options &= ~DHCPCD_DAEMONISE;
} }
@ -1344,8 +1399,7 @@ main(int argc, char **argv)
} }
snprintf(pidfile, sizeof(pidfile), snprintf(pidfile, sizeof(pidfile),
PIDFILE, "-", argv[optind], per); PIDFILE, "-", argv[optind], per);
} } else {
else {
snprintf(pidfile, sizeof(pidfile), PIDFILE, "", "", ""); snprintf(pidfile, sizeof(pidfile), PIDFILE, "", "", "");
ctx.options |= DHCPCD_MASTER; ctx.options |= DHCPCD_MASTER;
} }
@ -1354,12 +1408,48 @@ main(int argc, char **argv)
if (chdir("/") == -1) if (chdir("/") == -1)
syslog(LOG_ERR, "chdir `/': %m"); syslog(LOG_ERR, "chdir `/': %m");
/* Freeing allocated addresses from dumping leases can trigger
* eloop removals as well, so init here. */
ctx.eloop = eloop_init();
if (ctx.eloop == NULL) {
syslog(LOG_ERR, "%s: %m", __func__);
goto exit_failure;
}
if (ctx.options & DHCPCD_DUMPLEASE) { if (ctx.options & DHCPCD_DUMPLEASE) {
if (optind != argc - 1) { if (optind != argc - 1) {
syslog(LOG_ERR, "dumplease requires an interface"); syslog(LOG_ERR, "dumplease requires an interface");
goto exit_failure; goto exit_failure;
} }
if (dhcp_dump(&ctx, argv[optind]) == -1) i = 0;
/* We need to try and find the interface so we can
* load the hardware address to compare automated IAID */
ctx.ifaces = if_discover(&ctx, 1, argv + optind);
if (ctx.ifaces == NULL)
goto exit_failure;
ifp = TAILQ_FIRST(ctx.ifaces);
if (ifp == NULL) {
ifp = calloc(1, sizeof(*ifp));
if (ifp == NULL) {
syslog(LOG_ERR, "%s: %m", __func__);
goto exit_failure;
}
strlcpy(ifp->name, argv[optind], sizeof(ifp->name));
ifp->ctx = &ctx;
TAILQ_INSERT_HEAD(ctx.ifaces, ifp, next);
}
configure_interface(ifp, ctx.argc, ctx.argv);
if (ctx.options & DHCPCD_PFXDLGONLY)
ifp->options->options |= DHCPCD_PFXDLGONLY;
if (family == 0 || family == AF_INET) {
if (dhcp_dump(ifp) == -1)
i = 1;
}
if (family == 0 || family == AF_INET6) {
if (dhcp6_dump(ifp) == -1)
i = 1;
}
if (i == -1)
goto exit_failure; goto exit_failure;
goto exit_success; goto exit_success;
} }
@ -1399,12 +1489,6 @@ main(int argc, char **argv)
syslog(LOG_WARNING, syslog(LOG_WARNING,
PACKAGE " will not work correctly unless run as root"); PACKAGE " will not work correctly unless run as root");
ctx.eloop = eloop_init();
if (ctx.eloop == NULL) {
syslog(LOG_ERR, "%s: %m", __func__);
goto exit_failure;
}
#ifdef USE_SIGNALS #ifdef USE_SIGNALS
if (sig != 0) { if (sig != 0) {
pid = read_pid(pidfile); pid = read_pid(pidfile);
@ -1556,7 +1640,7 @@ main(int argc, char **argv)
} }
TAILQ_FOREACH(ifp, ctx.ifaces, next) { TAILQ_FOREACH(ifp, ctx.ifaces, next) {
init_state(ifp, argc, argv); dhcpcd_initstate1(ifp, argc, argv);
} }
if (ctx.options & DHCPCD_BACKGROUND && dhcpcd_daemonise(&ctx)) if (ctx.options & DHCPCD_BACKGROUND && dhcpcd_daemonise(&ctx))
@ -1625,7 +1709,6 @@ exit1:
free_options(ifo); free_options(ifo);
free_globals(&ctx); free_globals(&ctx);
if_rarestore(&ctx);
ipv4_ctxfree(&ctx); ipv4_ctxfree(&ctx);
ipv6_ctxfree(&ctx); ipv6_ctxfree(&ctx);
dev_stop(&ctx, !(ctx.options & DHCPCD_FORKED)); dev_stop(&ctx, !(ctx.options & DHCPCD_FORKED));

View File

@ -1,4 +1,4 @@
.\" $NetBSD: dhcpcd.conf.5.in,v 1.8 2014/06/14 20:55:37 roy Exp $ .\" $NetBSD: dhcpcd.conf.5.in,v 1.9 2014/07/14 11:49:48 roy Exp $
.\" Copyright (c) 2006-2014 Roy Marples .\" Copyright (c) 2006-2014 Roy Marples
.\" All rights reserved .\" All rights reserved
.\" .\"
@ -23,7 +23,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE. .\" SUCH DAMAGE.
.\" .\"
.Dd June 6, 2014 .Dd July 7, 2014
.Dt DHCPCD.CONF 5 .Dt DHCPCD.CONF 5
.Os .Os
.Sh NAME .Sh NAME
@ -215,7 +215,7 @@ DNS if the domain part does not match theirs.
Also, see the Also, see the
.Ic env .Ic env
option above to control how the hostname is set on the host. option above to control how the hostname is set on the host.
.It Ic ia_na Op Ar iaid .It Ic ia_na Op Ar iaid Op / address
Request a DHCPv6 Normal Address for Request a DHCPv6 Normal Address for
.Ar iaid . .Ar iaid .
.Ar iaid .Ar iaid
@ -231,7 +231,7 @@ Request a DHCPv6 Temporary Address for
You can request more than one ia_ta by specifying a unique You can request more than one ia_ta by specifying a unique
.Ar iaid .Ar iaid
for each one. for each one.
.It Ic ia_pd Op Ar iaid Op Ar interface Op / Ar sla_id Op / Ar prefix_len .It Ic ia_pd Op Ar iaid Oo / Ar prefix / Ar prefix_len Oc Op Ar interface Op / Ar sla_id Op / Ar prefix_len
Request a DHCPv6 Delegated Prefix for Request a DHCPv6 Delegated Prefix for
.Ar iaid . .Ar iaid .
This option must be used in an This option must be used in an
@ -251,7 +251,10 @@ Otherwise addresses are only assigned for each
and and
.Ar sla_id . .Ar sla_id .
Each assigned address will have a suffix of 1. Each assigned address will have a suffix of 1.
You cannot assign a prefix to the requesting interface. You cannot assign a prefix to the requesting interface unless the
DHCPv6 server supports
.Li RFC6603
Prefix Exclude Option.
.Nm dhcpcd .Nm dhcpcd
has to be running for all the interfaces it is delegating to. has to be running for all the interfaces it is delegating to.
A default A default
@ -291,6 +294,18 @@ IPv6RS should be disabled globally when requesting a Prefix Delegation like so:
.D1 interface eth1 .D1 interface eth1
.D1 ipv4 .D1 ipv4
.D1 ipv6rs .D1 ipv6rs
.It Ic ia_pd_mix
To be RFC compliant,
.Nm dhcpcd
cannot mix Prefix Delegation with other DHCPv6 address types in the same
session.
This has a number of issues: additional DHCP traffic and potential collisions
between options.
.Ic ia_pd_mix
enables
.Li draft-ietf-dhc-dhcpv6-stateful-issues-06
support so that Prefix Delegation can be mixed with other address types in
the same session.
.It Ic ipv4only .It Ic ipv4only
Only configure IPv4. Only configure IPv4.
.It Ic ipv6only .It Ic ipv6only
@ -458,6 +473,9 @@ Subsequent options are only parsed for this wireless
.Ar ssid . .Ar ssid .
.It Ic slaac Op Ar hwaddr | Ar private .It Ic slaac Op Ar hwaddr | Ar private
Selects the interface identifier used for SLAAC generated IPv6 addresses. Selects the interface identifier used for SLAAC generated IPv6 addresses.
If
.Ar private
is used, a RFC7217 address is generated.
.It Ic static Ar value .It Ic static Ar value
Configures a static Configures a static
.Ar value . .Ar value .
@ -740,11 +758,5 @@ Same as
.Sh AUTHORS .Sh AUTHORS
.An Roy Marples Aq Mt roy@marples.name .An Roy Marples Aq Mt roy@marples.name
.Sh BUGS .Sh BUGS
When configuring DHCPv6 you can only select one IA type.
I can't think of a use case where you would want different types,
so if you have one then please bring it up for discussion on the
.Aq Mt dhcpcd-discuss@marples.name
mailing list.
.Pp
Please report them to Please report them to
.Lk http://roy.marples.name/projects/dhcpcd .Lk http://roy.marples.name/projects/dhcpcd

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
__RCSID("$NetBSD: if-bsd.c,v 1.6 2014/06/14 20:55:37 roy Exp $"); __RCSID("$NetBSD: if-bsd.c,v 1.7 2014/07/14 11:49:48 roy Exp $");
/* /*
* dhcpcd - DHCP client daemon * dhcpcd - DHCP client daemon
@ -891,9 +891,7 @@ if_managelink(struct dhcpcd_ctx *ctx)
case AF_INET6: case AF_INET6:
sin6 = (struct sockaddr_in6*)(void *) sin6 = (struct sockaddr_in6*)(void *)
rti_info[RTAX_IFA]; rti_info[RTAX_IFA];
memcpy(ia6.s6_addr, ia6 = sin6->sin6_addr;
sin6->sin6_addr.s6_addr,
sizeof(ia6.s6_addr));
if (rtm->rtm_type == RTM_NEWADDR) { if (rtm->rtm_type == RTM_NEWADDR) {
ifa_flags = if_addrflags6(ifname, &ia6); ifa_flags = if_addrflags6(ifname, &ia6);
if (ifa_flags == -1) if (ifa_flags == -1)
@ -1022,45 +1020,6 @@ if_nd6reachable(const char *ifname, struct in6_addr *addr)
return flags; return flags;
} }
void
if_rarestore(struct dhcpcd_ctx *ctx)
{
if (ctx->options & DHCPCD_FORKED)
return;
for (; ctx->ra_restore_len > 0; ctx->ra_restore_len--) {
#ifdef ND6_IFF_ACCEPT_RTADV
if (!(ctx->options & DHCPCD_FORKED)) {
syslog(LOG_DEBUG,
"%s: restoring kernel IPv6 RA support",
ctx->ra_restore[ctx->ra_restore_len - 1]);
if (set_if_nd6_flag(
ctx->ra_restore[ctx->ra_restore_len -1],
ND6_IFF_ACCEPT_RTADV) == -1)
syslog(LOG_ERR, "%s: set_if_nd6_flag: %m",
ctx->ra_restore[ctx->ra_restore_len - 1]);
#ifdef ND6_IFF_OVERRIDE_RTADV
if (ctx->ra_kernel_set == 0 && del_if_nd6_flag(
ctx->ra_restore[ctx->ra_restore_len -1],
ND6_IFF_OVERRIDE_RTADV) == -1)
syslog(LOG_ERR, "%s: del_if_nd6_flag: %m",
ctx->ra_restore[ctx->ra_restore_len - 1]);
#endif
}
#endif
free(ctx->ra_restore[ctx->ra_restore_len - 1]);
}
free(ctx->ra_restore);
ctx->ra_restore = NULL;
if (ctx->ra_kernel_set) {
syslog(LOG_DEBUG, "restoring kernel IPv6 RA support");
if (set_inet6_sysctl(IPV6CTL_ACCEPT_RTADV, 1) == -1)
syslog(LOG_ERR, "IPV6CTL_ACCEPT_RTADV: %m");
}
}
static int static int
if_raflush(void) if_raflush(void)
{ {
@ -1088,10 +1047,6 @@ if_checkipv6(struct dhcpcd_ctx *ctx, const char *ifname, int own)
#ifdef ND6_IFF_OVERRIDE_RTADV #ifdef ND6_IFF_OVERRIDE_RTADV
int override; int override;
#endif #endif
#ifdef ND6_IFF_ACCEPT_RTADV
size_t i;
char *p, **nrest;
#endif
#ifdef ND6_IFF_IFDISABLED #ifdef ND6_IFF_IFDISABLED
if (del_if_nd6_flag(ifname, ND6_IFF_IFDISABLED) == -1) { if (del_if_nd6_flag(ifname, ND6_IFF_IFDISABLED) == -1) {
@ -1169,7 +1124,7 @@ if_checkipv6(struct dhcpcd_ctx *ctx, const char *ifname, int own)
return ra; return ra;
} }
#ifdef ND6_IFF_OVERRIDE_RTADV #ifdef ND6_IFF_OVERRIDE_RTADV
if (override == 0 && ctx->ra_kernel_set == 0 && if (override == 0 &&
set_if_nd6_flag(ifname, ND6_IFF_OVERRIDE_RTADV) set_if_nd6_flag(ifname, ND6_IFF_OVERRIDE_RTADV)
== -1) == -1)
{ {
@ -1180,25 +1135,6 @@ if_checkipv6(struct dhcpcd_ctx *ctx, const char *ifname, int own)
return ra; return ra;
} }
#endif #endif
for (i = 0; i < ctx->ra_restore_len; i++)
if (strcmp(ctx->ra_restore[i], ifname) == 0)
break;
if (i == ctx->ra_restore_len) {
p = strdup(ifname);
if (p == NULL) {
syslog(LOG_ERR, "%s: %m", __func__);
return 0;
}
nrest = realloc(ctx->ra_restore,
(ctx->ra_restore_len + 1) * sizeof(char *));
if (nrest == NULL) {
syslog(LOG_ERR, "%s: %m", __func__);
free(p);
return 0;
}
ctx->ra_restore = nrest;
ctx->ra_restore[ctx->ra_restore_len++] = p;
}
return 0; return 0;
} }
return ra; return ra;
@ -1220,7 +1156,6 @@ if_checkipv6(struct dhcpcd_ctx *ctx, const char *ifname, int own)
return ra; return ra;
} }
ra = 0; ra = 0;
ctx->ra_kernel_set = 1;
/* Flush the kernel knowledge of advertised routers /* Flush the kernel knowledge of advertised routers
* and prefixes so the kernel does not expire prefixes * and prefixes so the kernel does not expire prefixes

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
__RCSID("$NetBSD: if-options.c,v 1.9 2014/06/14 20:55:37 roy Exp $"); __RCSID("$NetBSD: if-options.c,v 1.10 2014/07/14 11:49:48 roy Exp $");
/* /*
* dhcpcd - DHCP client daemon * dhcpcd - DHCP client daemon
@ -96,6 +96,7 @@
#define O_CONTROLGRP O_BASE + 34 #define O_CONTROLGRP O_BASE + 34
#define O_SLAAC O_BASE + 35 #define O_SLAAC O_BASE + 35
#define O_GATEWAY O_BASE + 36 #define O_GATEWAY O_BASE + 36
#define O_PFXDLGMIX O_BASE + 37
const struct option cf_options[] = { const struct option cf_options[] = {
{"background", no_argument, NULL, 'b'}, {"background", no_argument, NULL, 'b'},
@ -182,6 +183,7 @@ const struct option cf_options[] = {
{"controlgroup", required_argument, NULL, O_CONTROLGRP}, {"controlgroup", required_argument, NULL, O_CONTROLGRP},
{"slaac", required_argument, NULL, O_SLAAC}, {"slaac", required_argument, NULL, O_SLAAC},
{"gateway", no_argument, NULL, O_GATEWAY}, {"gateway", no_argument, NULL, O_GATEWAY},
{"ia_pd_mix", no_argument, NULL, O_PFXDLGMIX},
{NULL, 0, NULL, '\0'} {NULL, 0, NULL, '\0'}
}; };
@ -521,7 +523,9 @@ parse_addr(__unused struct in_addr *addr, __unused struct in_addr *net,
static const char * static const char *
set_option_space(struct dhcpcd_ctx *ctx, set_option_space(struct dhcpcd_ctx *ctx,
const char *arg, const struct dhcp_opt **d, size_t *dl, const char *arg,
const struct dhcp_opt **d, size_t *dl,
const struct dhcp_opt **od, size_t *odl,
struct if_options *ifo, struct if_options *ifo,
uint8_t *request[], uint8_t *require[], uint8_t *no[]) uint8_t *request[], uint8_t *require[], uint8_t *no[])
{ {
@ -530,6 +534,8 @@ set_option_space(struct dhcpcd_ctx *ctx,
if (strncmp(arg, "dhcp6_", strlen("dhcp6_")) == 0) { if (strncmp(arg, "dhcp6_", strlen("dhcp6_")) == 0) {
*d = ctx->dhcp6_opts; *d = ctx->dhcp6_opts;
*dl = ctx->dhcp6_opts_len; *dl = ctx->dhcp6_opts_len;
*od = ifo->dhcp6_override;
*odl = ifo->dhcp6_override_len;
*request = ifo->requestmask6; *request = ifo->requestmask6;
*require = ifo->requiremask6; *require = ifo->requiremask6;
*no = ifo->nomask6; *no = ifo->nomask6;
@ -540,9 +546,13 @@ set_option_space(struct dhcpcd_ctx *ctx,
#ifdef INET #ifdef INET
*d = ctx->dhcp_opts; *d = ctx->dhcp_opts;
*dl = ctx->dhcp_opts_len; *dl = ctx->dhcp_opts_len;
*od = ifo->dhcp_override;
*odl = ifo->dhcp_override_len;
#else #else
*d = NULL; *d = NULL;
*dl = 0; *dl = 0;
*od = NULL;
*odl = 0;
#endif #endif
*request = ifo->requestmask; *request = ifo->requestmask;
*require = ifo->requiremask; *require = ifo->requiremask;
@ -633,15 +643,14 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
struct in_addr addr, addr2; struct in_addr addr, addr2;
in_addr_t *naddr; in_addr_t *naddr;
struct rt *rt; struct rt *rt;
const struct dhcp_opt *d; const struct dhcp_opt *d, *od;
uint8_t *request, *require, *no; uint8_t *request, *require, *no;
struct dhcp_opt **dop, *ndop; struct dhcp_opt **dop, *ndop;
size_t *dop_len, dl; size_t *dop_len, dl, odl;
struct vivco *vivco; struct vivco *vivco;
struct token *token; struct token *token;
struct group *grp; struct group *grp;
#ifdef _REENTRANT #ifdef _REENTRANT
#error foo
struct group grpbuf; struct group grpbuf;
#endif #endif
#ifdef INET6 #ifdef INET6
@ -736,10 +745,10 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
} }
break; break;
case 'o': case 'o':
arg = set_option_space(ctx, arg, &d, &dl, ifo, arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
&request, &require, &no); &request, &require, &no);
if (make_option_mask(d, dl, request, arg, 1) != 0 || if (make_option_mask(d, dl, od, odl, request, arg, 1) != 0 ||
make_option_mask(d, dl, no, arg, -1) != 0) make_option_mask(d, dl, od, odl, no, arg, -1) != 0)
{ {
syslog(LOG_ERR, "unknown option `%s'", arg); syslog(LOG_ERR, "unknown option `%s'", arg);
return -1; return -1;
@ -955,22 +964,22 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
ifo->options |= DHCPCD_MASTER; ifo->options |= DHCPCD_MASTER;
break; break;
case 'O': case 'O':
arg = set_option_space(ctx, arg, &d, &dl, ifo, arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
&request, &require, &no); &request, &require, &no);
if (make_option_mask(d, dl, request, arg, -1) != 0 || if (make_option_mask(d, dl, od, odl, request, arg, -1) != 0 ||
make_option_mask(d, dl, require, arg, -1) != 0 || make_option_mask(d, dl, od, odl, require, arg, -1) != 0 ||
make_option_mask(d, dl, no, arg, 1) != 0) make_option_mask(d, dl, od, odl, no, arg, 1) != 0)
{ {
syslog(LOG_ERR, "unknown option `%s'", arg); syslog(LOG_ERR, "unknown option `%s'", arg);
return -1; return -1;
} }
break; break;
case 'Q': case 'Q':
arg = set_option_space(ctx, arg, &d, &dl, ifo, arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
&request, &require, &no); &request, &require, &no);
if (make_option_mask(d, dl, require, arg, 1) != 0 || if (make_option_mask(d, dl, od, odl, require, arg, 1) != 0 ||
make_option_mask(d, dl, request, arg, 1) != 0 || make_option_mask(d, dl, od, odl, request, arg, 1) != 0 ||
make_option_mask(d, dl, no, arg, -1) != 0) make_option_mask(d, dl, od, odl, no, arg, -1) != 0)
{ {
syslog(LOG_ERR, "unknown option `%s'", arg); syslog(LOG_ERR, "unknown option `%s'", arg);
return -1; return -1;
@ -1159,8 +1168,11 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
} }
break; break;
case O_DESTINATION: case O_DESTINATION:
if (make_option_mask(ctx->dhcp_opts, ctx->dhcp_opts_len, arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
ifo->dstmask, arg, 2) != 0) { &request, &require, &no);
if (make_option_mask(d, dl, od, odl,
ifo->dstmask, arg, 2) != 0)
{
if (errno == EINVAL) if (errno == EINVAL)
syslog(LOG_ERR, "option `%s' does not take" syslog(LOG_ERR, "option `%s' does not take"
" an IPv4 address", arg); " an IPv4 address", arg);
@ -1223,35 +1235,41 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
} }
i = D6_OPTION_IA_PD; i = D6_OPTION_IA_PD;
} }
if (arg != NULL && ifname == NULL) { if (ifname == NULL && arg) {
syslog(LOG_ERR, syslog(LOG_ERR,
"IA with IAID must belong in an interface block"); "IA with IAID must belong in an interface block");
return -1; return -1;
} }
ifo->options |= DHCPCD_IA_FORCED; ifo->options |= DHCPCD_IA_FORCED;
if (ifo->ia_type != 0 && ifo->ia_type != i) {
syslog(LOG_ERR, "cannot specify a different IA type");
return -1;
}
ifo->ia_type = (uint16_t)i;
if (arg == NULL)
break;
fp = strwhite(arg); fp = strwhite(arg);
if (fp) if (fp) {
*fp++ = '\0'; *fp++ = '\0';
fp = strskipwhite(fp);
}
if (arg) {
p = strchr(arg, '/');
if (p)
*p++ = '\0';
if (parse_iaid(iaid, arg, sizeof(iaid)) == -1) if (parse_iaid(iaid, arg, sizeof(iaid)) == -1)
return -1; return -1;
}
ia = NULL; ia = NULL;
for (sl = 0; sl < ifo->ia_len; sl++) { for (sl = 0; sl < ifo->ia_len; sl++) {
if (ifo->ia[sl].iaid[0] == iaid[0] && if ((arg == NULL && !ifo->ia[sl].iaid_set) ||
(ifo->ia[sl].iaid_set &&
ifo->ia[sl].iaid[0] == iaid[0] &&
ifo->ia[sl].iaid[1] == iaid[1] && ifo->ia[sl].iaid[1] == iaid[1] &&
ifo->ia[sl].iaid[2] == iaid[2] && ifo->ia[sl].iaid[2] == iaid[2] &&
ifo->ia[sl].iaid[3] == iaid[3]) ifo->ia[sl].iaid[3] == iaid[3]))
{ {
ia = &ifo->ia[sl]; ia = &ifo->ia[sl];
break; break;
} }
} }
if (ia && ia->ia_type != (uint16_t)i) {
syslog(LOG_ERR, "Cannot mix IA for the same IAID");
break;
}
if (ia == NULL) { if (ia == NULL) {
ia = realloc(ifo->ia, ia = realloc(ifo->ia,
sizeof(*ifo->ia) * (ifo->ia_len + 1)); sizeof(*ifo->ia) * (ifo->ia_len + 1));
@ -1261,14 +1279,47 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
} }
ifo->ia = ia; ifo->ia = ia;
ia = &ifo->ia[ifo->ia_len++]; ia = &ifo->ia[ifo->ia_len++];
ia->ia_type = (uint16_t)i;
if (arg) {
ia->iaid[0] = iaid[0]; ia->iaid[0] = iaid[0];
ia->iaid[1] = iaid[1]; ia->iaid[1] = iaid[1];
ia->iaid[2] = iaid[2]; ia->iaid[2] = iaid[2];
ia->iaid[3] = iaid[3]; ia->iaid[3] = iaid[3];
ia->sla = NULL; ia->iaid_set = 1;
ia->sla_len = 0; } else
ia->iaid_set = 0;
if (!ia->iaid_set ||
p == NULL ||
ia->ia_type == D6_OPTION_IA_TA)
{
memset(&ia->addr, 0, sizeof(ia->addr));
ia->prefix_len = 0;
} else {
arg = p;
p = strchr(arg, '/');
if (p)
*p++ = '\0';
if (inet_pton(AF_INET6, arg, &ia->addr) == -1) {
syslog(LOG_ERR, "%s: %m", arg);
memset(&ia->addr, 0, sizeof(ia->addr));
} }
if (ifo->ia_type != D6_OPTION_IA_PD) if (p && ia->ia_type == D6_OPTION_IA_PD) {
i = atoint(p);
if (i != -1 && (i < 8 || i > 120)) {
errno = EINVAL;
i = -1;
}
if (i == -1) {
syslog(LOG_ERR, "%s: %m", p);
ia->prefix_len = 0;
} else
ia->prefix_len = (uint8_t)i;
}
}
ia->sla_len = 0;
ia->sla = NULL;
}
if (ia->ia_type != D6_OPTION_IA_PD)
break; break;
for (p = fp; p; p = fp) { for (p = fp; p; p = fp) {
fp = strwhite(p); fp = strwhite(p);
@ -1287,12 +1338,6 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
np = strchr(p, '/'); np = strchr(p, '/');
if (np) if (np)
*np++ = '\0'; *np++ = '\0';
if (strcmp(ifname, p) == 0) {
syslog(LOG_ERR,
"%s: cannot assign IA_PD to itself",
ifname);
goto err_sla;
}
if (strlcpy(sla->ifname, p, if (strlcpy(sla->ifname, p,
sizeof(sla->ifname)) >= sizeof(sla->ifname)) sizeof(sla->ifname)) >= sizeof(sla->ifname))
{ {
@ -1856,6 +1901,9 @@ err_sla:
else else
ifo->options &= ~DHCPCD_SLAACPRIVATE; ifo->options &= ~DHCPCD_SLAACPRIVATE;
break; break;
case O_PFXDLGMIX:
ifo->options |= DHCPCD_PFXDLGMIX;
break;
default: default:
return 0; return 0;
} }
@ -2127,6 +2175,10 @@ read_config(struct dhcpcd_ctx *ctx,
skip = 1; skip = 1;
continue; continue;
} }
/* Skip arping if we have selected a profile but not parsing
* one. */
if (profile && !have_profile && strcmp(option, "arping") == 0)
continue;
if (skip) if (skip)
continue; continue;
parse_config_line(ctx, ifname, ifo, option, line, &ldop, &edop); parse_config_line(ctx, ifname, ifo, option, line, &ldop, &edop);

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
__RCSID("$NetBSD: ipv6nd.c,v 1.8 2014/06/14 20:55:37 roy Exp $"); __RCSID("$NetBSD: ipv6nd.c,v 1.9 2014/07/14 11:49:48 roy Exp $");
/* /*
* dhcpcd - DHCP client daemon * dhcpcd - DHCP client daemon
@ -282,7 +282,7 @@ ipv6nd_sendrsprobe(void *arg)
dst.sin6_len = sizeof(dst); dst.sin6_len = sizeof(dst);
#endif #endif
dst.sin6_scope_id = ifp->index; dst.sin6_scope_id = ifp->index;
if (inet_pton(AF_INET6, ALLROUTERS, &dst.sin6_addr.s6_addr) != 1) { if (inet_pton(AF_INET6, ALLROUTERS, &dst.sin6_addr) != 1) {
syslog(LOG_ERR, "%s: %m", __func__); syslog(LOG_ERR, "%s: %m", __func__);
return; return;
} }
@ -627,8 +627,7 @@ ipv6nd_dadcallback(void *arg)
ap->dadcounter = dadcounter; ap->dadcounter = dadcounter;
ap->flags &= ~(IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED); ap->flags &= ~(IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED);
ap->flags |= IPV6_AF_NEW; ap->flags |= IPV6_AF_NEW;
p = inet_ntop(AF_INET6, ap->addr.s6_addr, p = inet_ntop(AF_INET6, &ap->addr, buf, sizeof(buf));
buf, sizeof(buf));
if (p) if (p)
snprintf(ap->saddr, snprintf(ap->saddr,
sizeof(ap->saddr), sizeof(ap->saddr),
@ -734,8 +733,7 @@ ipv6nd_handlera(struct ipv6_ctx *ctx, struct interface *ifp,
TAILQ_FOREACH(rap, ctx->ra_routers, next) { TAILQ_FOREACH(rap, ctx->ra_routers, next) {
if (ifp == rap->iface && if (ifp == rap->iface &&
memcmp(rap->from.s6_addr, ctx->from.sin6_addr.s6_addr, IN6_ARE_ADDR_EQUAL(&rap->from, &ctx->from.sin6_addr))
sizeof(rap->from.s6_addr)) == 0)
break; break;
} }
@ -764,8 +762,7 @@ ipv6nd_handlera(struct ipv6_ctx *ctx, struct interface *ifp,
return; return;
} }
rap->iface = ifp; rap->iface = ifp;
memcpy(rap->from.s6_addr, ctx->from.sin6_addr.s6_addr, rap->from = ctx->from.sin6_addr;
sizeof(rap->from.s6_addr));
strlcpy(rap->sfrom, ctx->sfrom, sizeof(rap->sfrom)); strlcpy(rap->sfrom, ctx->sfrom, sizeof(rap->sfrom));
TAILQ_INIT(&rap->addrs); TAILQ_INIT(&rap->addrs);
TAILQ_INIT(&rap->options); TAILQ_INIT(&rap->options);
@ -852,9 +849,8 @@ ipv6nd_handlera(struct ipv6_ctx *ctx, struct interface *ifp,
} }
TAILQ_FOREACH(ap, &rap->addrs, next) TAILQ_FOREACH(ap, &rap->addrs, next)
if (ap->prefix_len ==pi->nd_opt_pi_prefix_len && if (ap->prefix_len ==pi->nd_opt_pi_prefix_len &&
memcmp(ap->prefix.s6_addr, IN6_ARE_ADDR_EQUAL(&ap->prefix,
pi->nd_opt_pi_prefix.s6_addr, &pi->nd_opt_pi_prefix))
sizeof(ap->prefix.s6_addr)) == 0)
break; break;
if (ap == NULL) { if (ap == NULL) {
if (!(pi->nd_opt_pi_flags_reserved & if (!(pi->nd_opt_pi_flags_reserved &
@ -868,9 +864,7 @@ ipv6nd_handlera(struct ipv6_ctx *ctx, struct interface *ifp,
ap->iface = rap->iface; ap->iface = rap->iface;
ap->flags = IPV6_AF_NEW; ap->flags = IPV6_AF_NEW;
ap->prefix_len = pi->nd_opt_pi_prefix_len; ap->prefix_len = pi->nd_opt_pi_prefix_len;
memcpy(ap->prefix.s6_addr, ap->prefix = pi->nd_opt_pi_prefix;
pi->nd_opt_pi_prefix.s6_addr,
sizeof(ap->prefix.s6_addr));
if (pi->nd_opt_pi_flags_reserved & if (pi->nd_opt_pi_flags_reserved &
ND_OPT_PI_FLAG_AUTO) ND_OPT_PI_FLAG_AUTO)
{ {
@ -884,7 +878,7 @@ ipv6nd_handlera(struct ipv6_ctx *ctx, struct interface *ifp,
break; break;
} }
cbp = inet_ntop(AF_INET6, cbp = inet_ntop(AF_INET6,
ap->addr.s6_addr, &ap->addr,
buf, sizeof(buf)); buf, sizeof(buf));
if (cbp) if (cbp)
snprintf(ap->saddr, snprintf(ap->saddr,
@ -947,7 +941,7 @@ ipv6nd_handlera(struct ipv6_ctx *ctx, struct interface *ifp,
op += sizeof(rdnss->nd_opt_rdnss_lifetime); op += sizeof(rdnss->nd_opt_rdnss_lifetime);
l = 0; l = 0;
for (n = ndo->nd_opt_len - 1; n > 1; n -= 2, for (n = ndo->nd_opt_len - 1; n > 1; n -= 2,
op += sizeof(addr.s6_addr)) op += sizeof(addr))
{ {
r = ipv6_printaddr(NULL, 0, op, ifp->name); r = ipv6_printaddr(NULL, 0, op, ifp->name);
if (r != -1) if (r != -1)
@ -961,7 +955,7 @@ ipv6nd_handlera(struct ipv6_ctx *ctx, struct interface *ifp,
if (opt == NULL) if (opt == NULL)
continue; continue;
for (n = ndo->nd_opt_len - 1; n > 1; n -= 2, for (n = ndo->nd_opt_len - 1; n > 1; n -= 2,
op += sizeof(addr.s6_addr)) op += sizeof(addr))
{ {
r = ipv6_printaddr(tmp, l, op, r = ipv6_printaddr(tmp, l, op,
ifp->name); ifp->name);
@ -1401,8 +1395,7 @@ ipv6nd_handlena(struct ipv6_ctx *ctx, struct interface *ifp,
TAILQ_FOREACH(rap, ctx->ra_routers, next) { TAILQ_FOREACH(rap, ctx->ra_routers, next) {
if (rap->iface == ifp && if (rap->iface == ifp &&
memcmp(rap->from.s6_addr, nd_na->nd_na_target.s6_addr, IN6_ARE_ADDR_EQUAL(&rap->from, &nd_na->nd_na_target))
sizeof(rap->from.s6_addr)) == 0)
break; break;
} }
if (rap == NULL) { if (rap == NULL) {

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
__RCSID("$NetBSD: script.c,v 1.6 2014/06/14 20:55:37 roy Exp $"); __RCSID("$NetBSD: script.c,v 1.7 2014/07/14 11:49:48 roy Exp $");
/* /*
* dhcpcd - DHCP client daemon * dhcpcd - DHCP client daemon
@ -315,6 +315,7 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
snprintf(env[7], e, "ifmtu=%d", if_getmtu(ifp->name)); snprintf(env[7], e, "ifmtu=%d", if_getmtu(ifp->name));
l = e = strlen("interface_order="); l = e = strlen("interface_order=");
TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) { TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
if (!(ifp2->options->options & DHCPCD_PFXDLGONLY))
e += strlen(ifp2->name) + 1; e += strlen(ifp2->name) + 1;
} }
EMALLOC(8, e); EMALLOC(8, e);
@ -323,12 +324,14 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
e -= l; e -= l;
p += l; p += l;
TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) { TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
if (!(ifp2->options->options & DHCPCD_PFXDLGONLY)) {
l = strlcpy(p, ifp2->name, e); l = strlcpy(p, ifp2->name, e);
p += l; p += l;
e -= l; e -= l;
*p++ = ' '; *p++ = ' ';
e--; e--;
} }
}
*--p = '\0'; *--p = '\0';
if (strcmp(reason, "TEST") == 0) { if (strcmp(reason, "TEST") == 0) {
env[9] = strdup("if_up=false"); env[9] = strdup("if_up=false");
@ -396,6 +399,16 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
} }
#endif #endif
#ifdef INET6 #ifdef INET6
if (dhcp6 && d6_state && ifo->options & DHCPCD_PFXDLGONLY) {
nenv = realloc(env, sizeof(char *) * (elen + 2));
if (nenv == NULL)
goto eexit;
env = nenv;
env[elen] = strdup("ifclass=pd");
if (env[elen] == NULL)
goto eexit;
elen++;
}
if (dhcp6 && d6_state && d6_state->old) { if (dhcp6 && d6_state && d6_state->old) {
n = dhcp6_env(NULL, NULL, ifp, n = dhcp6_env(NULL, NULL, ifp,
d6_state->old, d6_state->old_len); d6_state->old, d6_state->old_len);