diff options
author | Eric Faurot <eric@cvs.openbsd.org> | 2013-03-29 23:01:25 +0000 |
---|---|---|
committer | Eric Faurot <eric@cvs.openbsd.org> | 2013-03-29 23:01:25 +0000 |
commit | 660750c721c4aab22c25418ed275d00e99e37070 (patch) | |
tree | 5a9fd9158c96aee56256af6b113e2fee6b8ea2be | |
parent | 894eefca71654906959ba3d1217a65412e21edad (diff) |
properly handle scope when parsing IPv6 addresses.
ok bluhm@ naddy@ sthen@
-rw-r--r-- | lib/libc/asr/asr_utils.c | 34 |
1 files changed, 32 insertions, 2 deletions
diff --git a/lib/libc/asr/asr_utils.c b/lib/libc/asr/asr_utils.c index 1f35f11e24c..de1e3b45db2 100644 --- a/lib/libc/asr/asr_utils.c +++ b/lib/libc/asr/asr_utils.c @@ -1,4 +1,4 @@ -/* $OpenBSD: asr_utils.c,v 1.3 2012/11/24 15:12:48 eric Exp $ */ +/* $OpenBSD: asr_utils.c,v 1.4 2013/03/29 23:01:24 eric Exp $ */ /* * Copyright (c) 2009-2012 Eric Faurot <eric@faurot.net> * @@ -17,13 +17,16 @@ #include <sys/types.h> #include <sys/socket.h> +#include <net/if.h> #include <netinet/in.h> #include <arpa/inet.h> #include <arpa/nameser.h> #include <ctype.h> #include <errno.h> +#include <stdint.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <unistd.h> @@ -421,6 +424,8 @@ sockaddr_from_str(struct sockaddr *sa, int family, const char *str) struct in6_addr in6a; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; + char *cp, *str2; + const char *errstr; switch (family) { case PF_UNSPEC: @@ -440,7 +445,19 @@ sockaddr_from_str(struct sockaddr *sa, int family, const char *str) return (0); case PF_INET6: - if (inet_pton(PF_INET6, str, &in6a) != 1) + cp = strchr(str, SCOPE_DELIMITER); + if (cp) { + str2 = strdup(str); + if (str2 == NULL) + return (-1); + str2[cp - str] = '\0'; + if (inet_pton(PF_INET6, str2, &in6a) != 1) { + free(str2); + return (-1); + } + cp++; + free(str2); + } else if (inet_pton(PF_INET6, str, &in6a) != 1) return (-1); sin6 = (struct sockaddr_in6 *)sa; @@ -448,6 +465,19 @@ sockaddr_from_str(struct sockaddr *sa, int family, const char *str) sin6->sin6_len = sizeof(struct sockaddr_in6); sin6->sin6_family = PF_INET6; sin6->sin6_addr = in6a; + + if (cp == NULL) + return (0); + + if (IN6_IS_ADDR_LINKLOCAL(&in6a) || + IN6_IS_ADDR_MC_LINKLOCAL(&in6a) || + IN6_IS_ADDR_MC_INTFACELOCAL(&in6a)) + if ((sin6->sin6_scope_id = if_nametoindex(cp))) + return (0); + + sin6->sin6_scope_id = strtonum(cp, 0, UINT32_MAX, &errstr); + if (errstr) + return (-1); return (0); default: |