From: Roy Marples Date: Tue, 3 Jun 2014 20:52:42 +0000 (+0000) Subject: Check against reserved IPv6 addresses. X-Git-Tag: v6.4.0~24 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4f5b9dd2aad73e886f88e5f1a7023318ca5cb1c2;p=thirdparty%2Fdhcpcd.git Check against reserved IPv6 addresses. Start using be*enc BSD functions and supply own if missing in common.h. --- diff --git a/common.h b/common.h index 577b96cc..c2ecde69 100644 --- a/common.h +++ b/common.h @@ -28,6 +28,7 @@ #ifndef COMMON_H #define COMMON_H +#include #include #include @@ -106,6 +107,40 @@ # endif #endif +#ifndef BSD +static inline void +be32enc(uint8_t *buf, uint32_t u) +{ + + buf[0] = (uint8_t)((u >> 24) & 0xff); + buf[1] = (uint8_t)((u >> 16) & 0xff); + buf[2] = (uint8_t)((u >> 8) & 0xff); + buf[3] = (uint8_t)(u & 0xff); +} + +static inline void +be64enc(uint8_t *buf, uint64_t u) +{ + + be32enc(buf, (uint32_t)(u >> 32)); + be32enc(buf + sizeof(uint32_t), (uint32_t)(u & 0xffffffffULL)); +} + +static inline uint16_t +be16dec(const uint8_t *buf) +{ + + return (uint16_t)(buf[0] << 8 | buf[1]); +} + +static inline uint32_t +be32dec(const uint8_t *buf) +{ + + return (uint32_t)(be16dec(buf) << 16 | be16dec(buf + 2)); +} +#endif + void get_line_free(void); const char *get_hostname(char *, size_t, int); extern int clock_monotonic; diff --git a/crypt/sha256.c b/crypt/sha256.c index 64e0d5dd..7e3ab0fe 100755 --- a/crypt/sha256.c +++ b/crypt/sha256.c @@ -28,6 +28,7 @@ #include +#include "../common.h" #include "sha256.h" #if BYTE_ORDER == BIG_ENDIAN @@ -42,38 +43,6 @@ #else /* BYTE_ORDER != BIG_ENDIAN */ -static inline void -be32enc(uint8_t *buf, uint32_t u) -{ - - buf[0] = (uint8_t)((u >> 24) & 0xff); - buf[1] = (uint8_t)((u >> 16) & 0xff); - buf[2] = (uint8_t)((u >> 8) & 0xff); - buf[3] = (uint8_t)(u & 0xff); -} - -static inline void -be64enc(uint8_t *buf, uint64_t u) -{ - - be32enc(buf, (uint32_t)(u >> 32)); - be32enc(buf + sizeof(uint32_t), (uint32_t)(u & 0xffffffffULL)); -} - -static inline uint16_t -be16dec(const uint8_t *buf) -{ - - return (uint16_t)(buf[0] << 8 | buf[1]); -} - -static inline uint32_t -be32dec(const uint8_t *buf) -{ - - return (uint32_t)(be16dec(buf) << 16 | be16dec(buf + 2)); -} - /* * Encode a length len/4 vector of (uint32_t) into a length len vector of * (unsigned char) in big-endian form. Assumes len is a multiple of 4. diff --git a/ipv6.c b/ipv6.c index 5098da9e..94bc2a84 100644 --- a/ipv6.c +++ b/ipv6.c @@ -258,13 +258,45 @@ eexit: return -1; } +static const struct reslowhigh { + const uint8_t high[8]; + const uint8_t low[8]; +} reslowhigh[] = { + /* RFC4291 + RFC6543 */ + { { 0x02, 0x00, 0x5e, 0xff, 0xfe, 0x00, 0x00, 0x00 }, + { 0x02, 0x00, 0x5e, 0xff, 0xfe, 0xff, 0xff, 0xff } }, + /* RFC2526 */ + { { 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 }, + { 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } } +}; + +static int +ipv6_reserved(const struct in6_addr *addr) +{ + uint64_t id, low, high; + size_t i; + const struct reslowhigh *r; + + id = be64dec(addr->s6_addr + sizeof(id)); + if (id == 0) /* RFC4291 */ + return 1; + for (i = 0; i < sizeof(reslowhigh) / sizeof(reslowhigh[0]); i++) { + r = &reslowhigh[i]; + low = be64dec(r->low); + high = be64dec(r->high); + if (id >= low && id <= high) + return 1; + } + return 0; +} + /* RFC7217 */ static int ipv6_makestableprivate1(struct in6_addr *addr, const struct in6_addr *prefix, int prefix_len, const unsigned char *netiface, size_t netiface_len, const char *netid, size_t netid_len, - uint32_t dad_counter, + uint32_t *dad_counter, const unsigned char *secret, size_t secret_len) { unsigned char buf[2048], *p, digest[SHA256_DIGEST_LENGTH]; @@ -277,38 +309,47 @@ ipv6_makestableprivate1(struct in6_addr *addr, } l = (size_t)(ROUNDUP8(prefix_len) / NBBY); - len = l + netiface_len + netid_len + sizeof(dad_counter) + secret_len; + len = l + netiface_len + netid_len + sizeof(*dad_counter) + secret_len; if (len > sizeof(buf)) { errno = ENOBUFS; return -1; } - /* Combine all parameters into one buffer */ - p = buf; - memcpy(p, prefix, l); - p += l; - memcpy(p, netiface, netiface_len); - p += netiface_len; - memcpy(p, netid, netid_len); - p += netid_len; - memcpy(p, &dad_counter, sizeof(dad_counter)); - p += sizeof(dad_counter); - memcpy(p, secret, secret_len); - - /* Make an address using the prefix and the digest of the above. - * RFC7217 Section 5.1 states that we shouldn't use MD5. - * Pity as we use that for HMAC-MD5 which is still deemed OK. - * SHA-256 is recommended */ - SHA256_Init(&ctx); - SHA256_Update(&ctx, buf, len); - SHA256_Final(digest, &ctx); - - p = addr->s6_addr; - memcpy(p, prefix, l); - /* RFC7217 section 5.2 says we need to start taking the id from - * the least significant bit */ - len = sizeof(addr->s6_addr) - l; - memcpy(p + l, digest + (sizeof(digest) - len), len); + for (;; (*dad_counter)++) { + /* Combine all parameters into one buffer */ + p = buf; + memcpy(p, prefix, l); + p += l; + memcpy(p, netiface, netiface_len); + p += netiface_len; + memcpy(p, netid, netid_len); + p += netid_len; + memcpy(p, dad_counter, sizeof(*dad_counter)); + p += sizeof(*dad_counter); + memcpy(p, secret, secret_len); + + /* Make an address using the digest of the above. + * RFC7217 Section 5.1 states that we shouldn't use MD5. + * Pity as we use that for HMAC-MD5 which is still deemed OK. + * SHA-256 is recommended */ + SHA256_Init(&ctx); + SHA256_Update(&ctx, buf, len); + SHA256_Final(digest, &ctx); + + p = addr->s6_addr; + memcpy(p, prefix, l); + /* RFC7217 section 5.2 says we need to start taking the id from + * the least significant bit */ + len = sizeof(addr->s6_addr) - l; + memcpy(p + l, digest + (sizeof(digest) - len), len); + + /* Ensure that the Interface ID does not match a reserved one. + * RFC7217 section 5.2 */ + if (prefix_len != 64) + break; + if (!ipv6_reserved(addr)) + break; + } return 0; } @@ -317,17 +358,24 @@ int ipv6_makestableprivate(struct in6_addr *addr, const struct in6_addr *prefix, int prefix_len, const struct interface *ifp, - uint32_t dad_counter) + int *dad_counter) { + uint32_t dad; + int r; + + dad = (uint32_t)*dad_counter; /* For our implementation, we shall set the hardware address * as the interface identifier */ - - return ipv6_makestableprivate1(addr, prefix, prefix_len, + r = ipv6_makestableprivate1(addr, prefix, prefix_len, ifp->hwaddr, ifp->hwlen, ifp->ssid, strlen(ifp->ssid), - dad_counter, + &dad, ifp->ctx->secret, ifp->ctx->secret_len); + + if (r == 0) + *dad_counter = (int)dad; + return r; } int @@ -335,6 +383,7 @@ ipv6_makeaddr(struct in6_addr *addr, const struct interface *ifp, const struct in6_addr *prefix, int prefix_len) { const struct ipv6_addr *ap; + int dad; if (prefix_len < 0 || prefix_len > 120) { errno = EINVAL; @@ -346,10 +395,11 @@ ipv6_makeaddr(struct in6_addr *addr, const struct interface *ifp, if (ipv6_readsecret(ifp->ctx) == -1) return -1; } + dad = 0; if (ipv6_makestableprivate(addr, - prefix, prefix_len, ifp, 0) == -1) + prefix, prefix_len, ifp, &dad) == -1) return -1; - return 0; + return dad; } if (prefix_len > 64) { @@ -447,55 +497,19 @@ ipv6_prefixlen(const struct in6_addr *mask) } static void -in6_to_h64(const struct in6_addr *add, uint64_t *vhigh, uint64_t *vlow) +in6_to_h64(uint64_t *vhigh, uint64_t *vlow, const struct in6_addr *addr) { - uint64_t l, h; - const uint8_t *p = (const uint8_t *)&add->s6_addr; - - h = ((uint64_t)p[0] << 56) | - ((uint64_t)p[1] << 48) | - ((uint64_t)p[2] << 40) | - ((uint64_t)p[3] << 32) | - ((uint64_t)p[4] << 24) | - ((uint64_t)p[5] << 16) | - ((uint64_t)p[6] << 8) | - (uint64_t)p[7]; - p += 8; - l = ((uint64_t)p[0] << 56) | - ((uint64_t)p[1] << 48) | - ((uint64_t)p[2] << 40) | - ((uint64_t)p[3] << 32) | - ((uint64_t)p[4] << 24) | - ((uint64_t)p[5] << 16) | - ((uint64_t)p[6] << 8) | - (uint64_t)p[7]; - - *vhigh = h; - *vlow = l; + + *vhigh = be64dec(addr->s6_addr); + *vlow = be64dec(addr->s6_addr + 8); } static void -h64_to_in6(uint64_t vhigh, uint64_t vlow, struct in6_addr *add) +h64_to_in6(struct in6_addr *addr, uint64_t vhigh, uint64_t vlow) { - uint8_t *p = (uint8_t *)&add->s6_addr; - - p[0] = (uint8_t)(vhigh >> 56); - p[1] = (uint8_t)(vhigh >> 48); - p[2] = (uint8_t)(vhigh >> 40); - p[3] = (uint8_t)(vhigh >> 32); - p[4] = (uint8_t)(vhigh >> 24); - p[5] = (uint8_t)(vhigh >> 16); - p[6] = (uint8_t)(vhigh >> 8); - p[7] = (uint8_t)vhigh; - p += 8; - p[0] = (uint8_t)(vlow >> 56); - p[1] = (uint8_t)(vlow >> 48); - p[2] = (uint8_t)(vlow >> 40); - p[3] = (uint8_t)(vlow >> 32); - p[4] = (uint8_t)(vlow >> 24); - p[5] = (uint8_t)(vlow >> 16); - p[6] = (uint8_t)(vlow >> 8); - p[7] = (uint8_t)vlow; + + be64enc(addr->s6_addr, vhigh); + be64enc(addr->s6_addr + 8, vlow); } int @@ -533,13 +547,13 @@ ipv6_userprefix( } /* convert to two 64bit host order values */ - in6_to_h64(prefix, &vh, &vl); + in6_to_h64(&vh, &vl, prefix); vh |= user_high; vl |= user_low; /* copy back result */ - h64_to_in6(vh, vl, result); + h64_to_in6(result, vh, vl); return 0; } diff --git a/ipv6.h b/ipv6.h index bb89fc61..82a74b37 100644 --- a/ipv6.h +++ b/ipv6.h @@ -88,7 +88,7 @@ struct ipv6_addr { struct interface *delegating_iface; void (*dadcallback)(void *); - uint32_t dadcounter; + int dadcounter; uint8_t *ns; size_t nslen; int nsprobes; @@ -167,7 +167,7 @@ struct ipv6_ctx *ipv6_init(struct dhcpcd_ctx *); ssize_t ipv6_printaddr(char *, size_t, const uint8_t *, const char *); int ipv6_makestableprivate(struct in6_addr *addr, const struct in6_addr *prefix, int prefix_len, - const struct interface *ifp, uint32_t dad_counter); + const struct interface *ifp, int *dad_counter); int ipv6_makeaddr(struct in6_addr *, const struct interface *, const struct in6_addr *, int); int ipv6_makeprefix(struct in6_addr *, const struct in6_addr *, int); diff --git a/ipv6nd.c b/ipv6nd.c index 04d31fa4..0ed14304 100644 --- a/ipv6nd.c +++ b/ipv6nd.c @@ -589,6 +589,7 @@ ipv6nd_dadcallback(void *arg) struct timeval tv; char buf[INET6_ADDRSTRLEN]; const char *p; + int dadcounter; ifp = ap->iface; wascompleted = (ap->flags & IPV6_AF_DADCOMPLETED); @@ -610,15 +611,17 @@ ipv6nd_dadcallback(void *arg) if (if_deladdress6(ap) == -1 && errno != EADDRNOTAVAIL && errno != ENXIO) syslog(LOG_ERR, "if_deladdress6: %m"); + dadcounter = ap->dadcounter; if (ipv6_makestableprivate(&ap->addr, &ap->prefix, ap->prefix_len, - ifp, ap->dadcounter) == -1) + ifp, &dadcounter) == -1) { syslog(LOG_ERR, "%s: ipv6_makestableprivate: %m", ifp->name); return; } + ap->dadcounter = dadcounter; ap->flags &= ~(IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED); ap->flags |= IPV6_AF_NEW; p = inet_ntop(AF_INET6, ap->addr.s6_addr, @@ -869,9 +872,14 @@ ipv6nd_handlera(struct ipv6_ctx *ctx, struct interface *ifp, ND_OPT_PI_FLAG_AUTO) { ap->flags |= IPV6_AF_AUTOCONF; - ipv6_makeaddr(&ap->addr, ifp, + ap->dadcounter = + ipv6_makeaddr(&ap->addr, ifp, &ap->prefix, pi->nd_opt_pi_prefix_len); + if (ap->dadcounter == -1) { + free(ap); + break; + } cbp = inet_ntop(AF_INET6, ap->addr.s6_addr, buf, sizeof(buf));