From bfbec7cf43525c133234ed0e45d7cfe7c549785e Mon Sep 17 00:00:00 2001 From: itojun Date: Thu, 20 Apr 2000 12:08:50 +0000 Subject: [PATCH] support extended scoped address notation (fe80::1%de0). it hides implementation detail (embedded ifid) from the users. --- sbin/route/route.c | 138 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 115 insertions(+), 23 deletions(-) diff --git a/sbin/route/route.c b/sbin/route/route.c index 046bced9f11f..8eecf187c9af 100644 --- a/sbin/route/route.c +++ b/sbin/route/route.c @@ -1,4 +1,4 @@ -/* $NetBSD: route.c,v 1.35 1999/12/03 05:43:00 itojun Exp $ */ +/* $NetBSD: route.c,v 1.36 2000/04/20 12:08:50 itojun Exp $ */ /* * Copyright (c) 1983, 1989, 1991, 1993 @@ -43,7 +43,7 @@ __COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1991, 1993\n\ #if 0 static char sccsid[] = "@(#)route.c 8.6 (Berkeley) 4/28/95"; #else -__RCSID("$NetBSD: route.c,v 1.35 1999/12/03 05:43:00 itojun Exp $"); +__RCSID("$NetBSD: route.c,v 1.36 2000/04/20 12:08:50 itojun Exp $"); #endif #endif /* not lint */ @@ -86,6 +86,9 @@ static char *any_ntoa __P((const struct sockaddr *)); static void set_metric __P((char *, int)); static void newroute __P((int, char **)); static void inet_makenetandmask __P((u_int32_t, struct sockaddr_in *)); +#ifdef INET6 +static void inet6_makenetandmask __P((struct sockaddr_in6 *)); +#endif static int getaddr __P((int, char *, struct hostent **)); static void flushroutes __P((int, char *[])); #ifndef SMALL @@ -381,9 +384,6 @@ routename(sa) static char domain[MAXHOSTNAMELEN + 1]; static int first = 1; struct in_addr in; -#ifdef INET6 - static char ntop_buf[NI_MAXHOST]; -#endif if (first) { first = 0; @@ -429,14 +429,35 @@ routename(sa) #ifndef SMALL #ifdef INET6 case AF_INET6: - { struct in6_addr in6; - int gap; + { + struct sockaddr_in6 sin6; + int niflags; - in6 = ((struct sockaddr_in6 *)sa)->sin6_addr; - gap = 24 - sa->sa_len; - if (gap > 0) - bzero((char *)(&in6 + 1) - gap, gap); - return ((char *)inet_ntop(AF_INET6, &in6, ntop_buf, sizeof(ntop_buf))); +#ifdef NI_WITHSCOPEID + niflags = NI_WITHSCOPEID; +#else + niflags = 0; +#endif + if (nflag) + niflags |= NI_NUMERICHOST; + memset(&sin6, 0, sizeof(sin6)); + memcpy(&sin6, sa, sa->sa_len); + sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_family = AF_INET6; +#ifdef __KAME__ + if (sa->sa_len == sizeof(struct sockaddr_in6) && + IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) && + sin6.sin6_scope_id == 0) { + sin6.sin6_scope_id = + ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); + sin6.sin6_addr.s6_addr[2] = 0; + sin6.sin6_addr.s6_addr[3] = 0; + } +#endif + if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, + line, sizeof(line), NULL, 0, niflags) != 0) + strncpy(line, "invalid", sizeof(line)); + break; } #endif @@ -479,9 +500,6 @@ netname(sa) u_int32_t i; int subnetshift; struct in_addr in; -#ifdef INET6 - static char ntop_buf[NI_MAXHOST]; -#endif switch (sa->sa_family) { @@ -547,14 +565,35 @@ netname(sa) #ifndef SMALL #ifdef INET6 case AF_INET6: - { struct in6_addr in6; - int gap; + { + struct sockaddr_in6 sin6; + int niflags; - in6 = ((struct sockaddr_in6 *)sa)->sin6_addr; - gap = 24 - sa->sa_len; - if (gap > 0) - bzero((char *)(&in6 + 1) - gap, gap); - return ((char *)inet_ntop(AF_INET6, &in6, ntop_buf, sizeof(ntop_buf))); +#ifdef NI_WITHSCOPEID + niflags = NI_WITHSCOPEID; +#else + niflags = 0; +#endif + if (nflag) + niflags |= NI_NUMERICHOST; + memset(&sin6, 0, sizeof(sin6)); + memcpy(&sin6, sa, sa->sa_len); + sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_family = AF_INET6; +#ifdef __KAME__ + if (sa->sa_len == sizeof(struct sockaddr_in6) && + IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) && + sin6.sin6_scope_id == 0) { + sin6.sin6_scope_id = + ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); + sin6.sin6_addr.s6_addr[2] = 0; + sin6.sin6_addr.s6_addr[3] = 0; + } +#endif + if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, + line, sizeof(line), NULL, 0, niflags) != 0) + strncpy(line, "invalid", sizeof(line)); + break; } #endif @@ -903,6 +942,37 @@ inet_makenetandmask(net, sin) sin->sin_len = 1 + cp - (char *)sin; } +#ifdef INET6 +/* + * XXX the function may need more improvement... + */ +static void +inet6_makenetandmask(sin6) + struct sockaddr_in6 *sin6; +{ + char *plen; + struct in6_addr in6; + + plen = NULL; + if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && + sin6->sin6_scope_id == 0) { + plen = "0"; + } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) { + /* aggregatable global unicast - RFC2374 */ + memset(&in6, 0, sizeof(in6)); + if (!memcmp(&sin6->sin6_addr.s6_addr[8], &in6.s6_addr[8], 8)) + plen = "64"; + else + plen = "128"; + } + + if (plen) { + rtm_addrs |= RTA_NETMASK; + prefixlen(plen); + } +} +#endif + /* * Interpret an argument as a network address of some kind, * returning 1 if a host address, 0 if a network address. @@ -970,11 +1040,33 @@ getaddr(which, s, hpp) #ifndef SMALL #ifdef INET6 case AF_INET6: - if (inet_pton(AF_INET6, s, (void *)&su->sin6.sin6_addr) != 1) { + { + struct addrinfo hints, *res; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = afamily; /*AF_INET6*/ + hints.ai_flags = AI_NUMERICHOST; + hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + if (getaddrinfo(s, "0", &hints, &res) != 0 || + res->ai_family != AF_INET6 || + res->ai_addrlen != sizeof(su->sin6)) { (void) fprintf(stderr, "%s: bad value\n", s); exit(1); } + memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6)); +#ifdef __KAME__ + if (IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) && + su->sin6.sin6_scope_id) { + *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] = + htons(su->sin6.sin6_scope_id); + su->sin6.sin6_scope_id = 0; + } +#endif + if (which == RTA_DST) + inet6_makenetandmask(&su->sin6); + freeaddrinfo(res); return 0; + } #endif case AF_NS: