Mercurial > hg > dhcpcd
changeset 2516:88bbfcbd9ec4 draft
Default SLAAC to use RFC7271 addresses.
Create an IPv6 link-local address if non exists at startup using the
configured SLAAC method.
| author | Roy Marples <roy@marples.name> |
|---|---|
| date | Wed, 04 Jun 2014 20:27:40 +0000 |
| parents | 1f5fc94ae1cf |
| children | 1d4beca0771f |
| files | dhcpcd.8.in dhcpcd.c dhcpcd.conf.5.in if-options.c if-options.h ipv6.c ipv6.h ipv6nd.c |
| diffstat | 8 files changed, 157 insertions(+), 29 deletions(-) [+] |
line wrap: on
line diff
--- a/dhcpcd.8.in Tue Jun 03 21:20:49 2014 +0000 +++ b/dhcpcd.8.in Wed Jun 04 20:27:40 2014 +0000 @@ -75,7 +75,7 @@ .Sh DESCRIPTION .Nm is an implementation of the DHCP client specified in -.Li RFC 2131 . +.%R RFC 2131 . .Nm gets the host information .Po @@ -103,27 +103,20 @@ .Pp .Nm is also an implementation of the BOOTP client specified in -.Li RFC 951 . +.%R RFC 951 . .Pp .Nm is also an implementation of the IPv6 Router Solicitor as specified in -.Li RFC 4861 +.%R RFC 4861 and -.Li RFC 6106 . -.Nm -can optionally handle address and route management itself, -and will do so by default if Router Solicitation is disabled in the kernel -or if stable private addresses are enabled in the configuration. -If -.Nm -is managing routes, -.Nm -sends Neighbor Solicitions to each advertising router periodically and will -expire the ones that do not respond. +.%R RFC 6106 +and will generate stable private Interface Identifiers for SLAAC +as specified in +.%R RFC 7212 . .Pp .Nm is also an implemenation of the DHCPv6 client as specified in -.Li RFC 3315 . +.%R RFC 3315 . By default, .Nm only starts DHCPv6 when instructed to do so by an IPV6 Router Advertisement. @@ -221,7 +214,7 @@ .Pa @SCRIPT@ . .It Fl D , Fl Fl duid Generate an -.Li RFC 4361 +.%R RFC 4361 compliant clientid. This requires persistent storage and not all DHCP servers work with it so it is not enabled by default. @@ -269,7 +262,7 @@ itself never does any DNS updates. .Nm encodes the FQDN hostname as specified in -.Li RFC1035 . +.%R RFC1035 . .It Fl f , Fl Fl config Ar file Specify a config to load instead of .Pa @SYSCONFDIR@/dhcpcd.conf .
--- a/dhcpcd.c Tue Jun 03 21:20:49 2014 +0000 +++ b/dhcpcd.c Wed Jun 04 20:27:40 2014 +0000 @@ -447,6 +447,8 @@ if (!(ifo->auth.options & DHCPCD_AUTH_SEND)) ifo->auth.options &= ~DHCPCD_AUTH_REQUIRE; + if (ifo->options & DHCPCD_SLAACPRIVATE) + ifo->options |= DHCPCD_IPV6RA_OWN; } int @@ -602,6 +604,10 @@ } } + if (ifo->options & DHCPCD_IPV6 && ipv6_start(ifp) == -1) { + syslog(LOG_ERR, "%s: ipv6_start: %m", ifp->name); + ifo->options &= DHCPCD_IPV6; + } if (ifo->options & DHCPCD_IPV6) { if (ifo->options & DHCPCD_IPV6RS && !(ifo->options & DHCPCD_INFORM))
--- a/dhcpcd.conf.5.in Tue Jun 03 21:20:49 2014 +0000 +++ b/dhcpcd.conf.5.in Wed Jun 04 20:27:40 2014 +0000 @@ -453,9 +453,11 @@ .It Ic ssid Ar ssid Subsequent options are only parsed for this wireless .Ar ssid . -.It Ic stableprivate -Configure stable private IPv6 addresses as per RFC7217 for SLAAC instead of -ones generated from hardware addresses for SLAAC. +.It Ic slaac Op Ar hwaddr | Ar private +Selects the interface identifier used for SLAAC generated IPv6 addresses. +.Ar private +is the default and complies with +.%R RFC 7217. .It Ic static Ar value Configures a static .Ar value .
--- a/if-options.c Tue Jun 03 21:20:49 2014 +0000 +++ b/if-options.c Wed Jun 04 20:27:40 2014 +0000 @@ -91,7 +91,7 @@ #define O_IPV4 O_BASE + 32 #define O_IPV6 O_BASE + 33 #define O_CONTROLGRP O_BASE + 34 -#define O_STABLEPRIVATE O_BASE + 35 +#define O_SLAAC O_BASE + 35 const struct option cf_options[] = { {"background", no_argument, NULL, 'b'}, @@ -176,7 +176,7 @@ {"dhcp6", no_argument, NULL, O_DHCP6}, {"nodhcp6", no_argument, NULL, O_NODHCP6}, {"controlgroup", required_argument, NULL, O_CONTROLGRP}, - {"stableprivate", no_argument, NULL, O_STABLEPRIVATE}, + {"slaac", required_argument, NULL, O_SLAAC}, {NULL, 0, NULL, '\0'} }; @@ -1837,10 +1837,13 @@ ctx->control_group = grp->gr_gid; #endif break; - case O_STABLEPRIVATE: - ifo->options |= DHCPCD_STABLEPRIVATE; - /* This option implies that we steal SLAAC from the kernel */ - ifo->options |= DHCPCD_IPV6RA_OWN; + case O_SLAAC: + if (strcmp(arg, "private") == 0 || + strcmp(arg, "stableprivate") == 0 || + strcmp(arg, "stable") == 0) + ifo->options |= DHCPCD_SLAACPRIVATE; + else + ifo->options &= ~DHCPCD_SLAACPRIVATE; break; default: return 0; @@ -1949,6 +1952,7 @@ #endif #ifdef INET6 ifo->options |= DHCPCD_IPV6 | DHCPCD_IPV6RS | DHCPCD_IPV6RA_REQRDNSS; + ifo->options |= DHCPCD_SLAACPRIVATE; ifo->options |= DHCPCD_DHCP6; #endif ifo->timeout = DEFAULT_TIMEOUT;
--- a/if-options.h Tue Jun 03 21:20:49 2014 +0000 +++ b/if-options.h Wed Jun 04 20:27:40 2014 +0000 @@ -102,7 +102,7 @@ #define DHCPCD_IAID (1ULL << 48) #define DHCPCD_DHCP (1ULL << 49) #define DHCPCD_DHCP6 (1ULL << 50) -#define DHCPCD_STABLEPRIVATE (1ULL << 51) +#define DHCPCD_SLAACPRIVATE (1ULL << 51) extern const struct option cf_options[];
--- a/ipv6.c Tue Jun 03 21:20:49 2014 +0000 +++ b/ipv6.c Wed Jun 04 20:27:40 2014 +0000 @@ -393,7 +393,7 @@ return -1; } - if (ifp->options->options & DHCPCD_STABLEPRIVATE) { + if (ifp->options->options & DHCPCD_SLAACPRIVATE) { if (ifp->ctx->secret_len == 0) { if (ipv6_readsecret(ifp->ctx) == -1) return -1; @@ -878,6 +878,122 @@ } } +static struct ipv6_addr * +ipv6_newlinklocal(struct interface *ifp) +{ + struct ipv6_addr *ap; + + ap = calloc(1, sizeof(*ap)); + if (ap != NULL) { + ap->iface = ifp; + ap->prefix.s6_addr32[0] = htonl(0xfe800000); + ap->prefix.s6_addr32[1] = 0; + ap->prefix_len = 64; + ap->dadcounter = 0; + ap->prefix_pltime = ND6_INFINITE_LIFETIME; + ap->prefix_vltime = ND6_INFINITE_LIFETIME; + ap->flags = IPV6_AF_NEW; + ap->addr_flags = IN6_IFF_TENTATIVE; + } + return ap; +} + +static const uint8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +static const uint8_t allone[8] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +static int +ipv6_addlinklocal(struct interface *ifp) +{ + struct ipv6_state *state; + struct ipv6_addr *ap; + int dadcounter; + + if (ipv6_linklocal(ifp)) + return 0; + + /* Check sanity before malloc */ + if (!(ifp->options->options & DHCPCD_SLAACPRIVATE)) { + switch (ifp->family) { + case ARPHRD_ETHER: + /* Check for a valid hardware address */ + if (ifp->hwlen != 6 & ifp->hwlen != 8) { + errno = ENOTSUP; + return -1; + } + if (memcmp(ifp->hwaddr, allzero, ifp->hwlen) == 0 || + memcmp(ifp->hwaddr, allone, ifp->hwlen) == 0) + { + errno = EINVAL; + return -1; + } + break; + default: + errno = ENOTSUP; + return -1; + } + } + + state = ipv6_getstate(ifp); + if (state == NULL) + return -1; + + ap = ipv6_newlinklocal(ifp); + if (ap == NULL) + return -1; + + if (ifp->options->options & DHCPCD_SLAACPRIVATE) { + dadcounter = 0; + if (ipv6_makestableprivate(&ap->addr, + &ap->prefix, ap->prefix_len, ifp, &dadcounter) == -1) + { + free(ap); + return -1; + } + ap->dadcounter = dadcounter; + } else { + memcpy(ap->addr.s6_addr, ap->prefix.s6_addr, ap->prefix_len); + switch (ifp->family) { + case ARPHRD_ETHER: + if (ifp->hwlen == 6) { + ap->addr.s6_addr[ 8] = ifp->hwaddr[0]; + ap->addr.s6_addr[ 9] = ifp->hwaddr[1]; + ap->addr.s6_addr[10] = ifp->hwaddr[2]; + ap->addr.s6_addr[11] = 0xff; + ap->addr.s6_addr[12] = 0xfe; + ap->addr.s6_addr[13] = ifp->hwaddr[3]; + ap->addr.s6_addr[14] = ifp->hwaddr[4]; + ap->addr.s6_addr[15] = ifp->hwaddr[5]; + } else if (ifp->hwlen == 8) + memcpy(&ap->addr.s6_addr[8], ifp->hwaddr, 8); + break; + } + + /* Sanity check: g bit must not indciate "group" */ + if (EUI64_GROUP(&ap->addr)) { + free(ap); + errno = EINVAL; + return -1; + } + EUI64_TO_IFID(&ap->addr); + } + + inet_ntop(AF_INET6, &ap->addr, ap->saddr, sizeof(ap->saddr)); + TAILQ_INSERT_TAIL(&state->addrs, ap, next); + ipv6_addaddr(ap); + return 1; +} + +/* Ensure the interface has a link-local address */ +int +ipv6_start(struct interface *ifp) +{ + + if (ipv6_linklocal(ifp) == NULL && ipv6_addlinklocal(ifp) == -1) + return -1; + return 0; +} + void ipv6_free(struct interface *ifp) {
--- a/ipv6.h Tue Jun 03 21:20:49 2014 +0000 +++ b/ipv6.h Wed Jun 04 20:27:40 2014 +0000 @@ -45,6 +45,11 @@ #define ROUNDUP8(a) (1 + (((a) - 1) | 7)) #define ROUNDUP16(a) (1 + (((a) - 1) | 16)) +#define EUI64_GBIT 0x01 +#define EUI64_UBIT 0x02 +#define EUI64_TO_IFID(in6) do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0) +#define EUI64_GROUP(in6) ((in6)->s6_addr[8] & EUI64_GBIT) + #ifndef ND6_INFINITE_LIFETIME # define ND6_INFINITE_LIFETIME ((uint32_t)~0) #endif @@ -189,6 +194,7 @@ #define ipv6_linklocal(ifp) (ipv6_findaddr((ifp), NULL)) int ipv6_addlinklocalcallback(struct interface *, void (*)(void *), void *); void ipv6_free_ll_callbacks(struct interface *); +int ipv6_start(struct interface *); void ipv6_free(struct interface *); void ipv6_ctxfree(struct dhcpcd_ctx *); int ipv6_removesubnet(struct interface *, struct ipv6_addr *); @@ -196,6 +202,7 @@ #else #define ipv6_init(a) NULL +#define ipv6_start(a) (-1) #define ipv6_free_ll_callbacks(a) #define ipv6_free(a) #define ipv6_ctxfree(a)
--- a/ipv6nd.c Tue Jun 03 21:20:49 2014 +0000 +++ b/ipv6nd.c Wed Jun 04 20:27:40 2014 +0000 @@ -603,7 +603,7 @@ * Because ap->dadcounter is always increamented, * a different address is generated. */ /* XXX Cache DAD counter per prefix/id/ssid? */ - if (ifp->options->options & DHCPCD_STABLEPRIVATE && + if (ifp->options->options & DHCPCD_SLAACPRIVATE && ap->dadcounter < IDGEN_RETRIES) { syslog(LOG_INFO, "%s: deleting address %s",
