summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2012-11-24 20:17:33 +0000
committerRoy Marples <roy@marples.name>2012-11-24 20:17:33 +0000
commit586e542cb3231d44d2924fd8de695d82c3236b62 (patch)
tree1b283b71f1369396542ac9ac3a66fbd7a929a764
parent5aeb7be6f362243110fdfd5f88b57dd9fcbd64f5 (diff)
downloaddhcpcd-586e542cb3231d44d2924fd8de695d82c3236b62.tar.xz
Set %interface for exported IPv6 link local addresses.
-rw-r--r--ipv6.c32
-rw-r--r--ipv6.h1
-rw-r--r--ipv6rs.c39
3 files changed, 51 insertions, 21 deletions
diff --git a/ipv6.c b/ipv6.c
index 125b3872..793cf6b8 100644
--- a/ipv6.c
+++ b/ipv6.c
@@ -79,6 +79,38 @@ ipv6_open(void)
return socket_afnet6;
}
+ssize_t
+ipv6_printaddr(char *s, ssize_t sl, const uint8_t *d, const char *ifname)
+{
+ char buf[INET6_ADDRSTRLEN];
+ const char *p;
+ ssize_t l;
+
+ p = inet_ntop(AF_INET6, d, buf, sizeof(buf));
+ if (p == NULL)
+ return -1;
+
+ l = strlen(p);
+ if (d[0] == 0xfe && (d[1] & 0xc0) == 0x80)
+ l += 1 + strlen(ifname);
+
+ if (s == NULL)
+ return l;
+
+ if (sl < l) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ s += strlcpy(s, p, sl);
+ if (d[0] == 0xfe && (d[1] & 0xc0) == 0x80) {
+ *s++ = '%';
+ s += strlcpy(s, ifname, sl);
+ }
+ *s = '\0';
+ return l;
+}
+
struct in6_addr *
ipv6_linklocal(const char *ifname)
{
diff --git a/ipv6.h b/ipv6.h
index 8f6ef27f..ef3b2352 100644
--- a/ipv6.h
+++ b/ipv6.h
@@ -65,6 +65,7 @@ TAILQ_HEAD(rt6head, rt6);
extern int socket_afnet6;
int ipv6_open(void);
+ssize_t ipv6_printaddr(char *, ssize_t, const uint8_t *, const char *);
struct in6_addr *ipv6_linklocal(const char *);
int ipv6_makeaddr(struct in6_addr *, const char *, const struct in6_addr *, int);
int ipv6_mask(struct in6_addr *, int);
diff --git a/ipv6rs.c b/ipv6rs.c
index 4a0af375..0ca5b179 100644
--- a/ipv6rs.c
+++ b/ipv6rs.c
@@ -629,28 +629,25 @@ ipv6rs_handledata(_unused void *arg)
nd_opt_rdnss_lifetime);
op += sizeof(rdnss->nd_opt_rdnss_lifetime);
l = 0;
- for (n = ndo->nd_opt_len - 1; n > 1; n -= 2) {
- memcpy(&addr.s6_addr, op, sizeof(addr.s6_addr));
- cbp = inet_ntop(AF_INET6, &addr,
- ntopbuf, INET6_ADDRSTRLEN);
- if (cbp == NULL) {
- syslog(LOG_ERR,
- "%s: invalid RDNSS address",
- ifp->name);
- } else {
- if (opt) {
- l = strlen(opt);
- opt = xrealloc(opt,
- l + strlen(cbp) + 2);
- opt[l] = ' ';
- strcpy(opt + l + 1, cbp);
- } else
- opt = xstrdup(cbp);
- if (lifetime > 0)
- has_dns = 1;
- }
- op += sizeof(addr.s6_addr);
+ for (n = ndo->nd_opt_len - 1; n > 1; n -= 2,
+ op += sizeof(addr.s6_addr))
+ {
+ l += ipv6_printaddr(NULL, 0, op, ifp->name) + 1;
+ }
+ op = (uint8_t *)ndo;
+ op += offsetof(struct nd_opt_rdnss,
+ nd_opt_rdnss_lifetime);
+ op += sizeof(rdnss->nd_opt_rdnss_lifetime);
+ tmp = opt = malloc(l);
+ for (n = ndo->nd_opt_len - 1; n > 1; n -= 2,
+ op += sizeof(addr.s6_addr))
+ {
+ tmp += ipv6_printaddr(tmp, l, op, ifp->name);
+ *tmp++ = ' ';
+ if (lifetime > 0)
+ has_dns = 1;
}
+ (*--tmp) = '\0';
break;
case ND_OPT_DNSSL: