changeset 1804:b3ac4d025b78 draft

Set %interface for exported IPv6 link local addresses.
author Roy Marples <roy@marples.name>
date Sat, 24 Nov 2012 20:17:33 +0000
parents 9507b4c2b0ee
children 725417fae1e5
files ipv6.c ipv6.h ipv6rs.c
diffstat 3 files changed, 51 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/ipv6.c	Fri Nov 16 20:50:18 2012 +0000
+++ b/ipv6.c	Sat Nov 24 20:17:33 2012 +0000
@@ -79,6 +79,38 @@
 	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)
 {
--- a/ipv6.h	Fri Nov 16 20:50:18 2012 +0000
+++ b/ipv6.h	Sat Nov 24 20:17:33 2012 +0000
@@ -65,6 +65,7 @@
 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);
--- a/ipv6rs.c	Fri Nov 16 20:50:18 2012 +0000
+++ b/ipv6rs.c	Sat Nov 24 20:17:33 2012 +0000
@@ -629,28 +629,25 @@
 			    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: