From: florian Date: Sun, 24 Jan 2021 08:57:10 +0000 (+0000) Subject: Pass sockaddr_in6 arround so that we have space to store the scope in X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=f775b7d752fec8d6a72a2c018695ce37921d3e8f;p=openbsd Pass sockaddr_in6 arround so that we have space to store the scope in a proper field. Move KAME hack to kernel / userland boundaries. Due to the way -d (delete) works in ndp(8), once we flip the kernel over to not pass down embedded scope it also must not expect embeded scope passed to the kernel. OK claudio --- diff --git a/usr.sbin/ndp/ndp.c b/usr.sbin/ndp/ndp.c index a4e4a3cbc74..ad5c56af612 100644 --- a/usr.sbin/ndp/ndp.c +++ b/usr.sbin/ndp/ndp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ndp.c,v 1.101 2021/01/22 16:10:01 florian Exp $ */ +/* $OpenBSD: ndp.c,v 1.102 2021/01/24 08:57:10 florian Exp $ */ /* $KAME: ndp.c,v 1.101 2002/07/17 08:46:33 itojun Exp $ */ /* @@ -119,11 +119,11 @@ char ifix_buf[IFNAMSIZ]; /* if_indextoname() */ int file(char *); void getsocket(void); -int parse_host(const char *, struct in6_addr *); +int parse_host(const char *, struct sockaddr_in6 *); int set(int, char **); void get(const char *); int delete(const char *); -void dump(struct in6_addr *, int); +void dump(struct sockaddr_in6 *, int); static struct in6_nbrinfo *getnbrinfo(struct in6_addr *, int, int); static char *ether_str(struct sockaddr_dl *); int ndp_ether_aton(const char *, u_char *); @@ -288,10 +288,9 @@ getsocket(void) } int -parse_host(const char *host, struct in6_addr *in6) +parse_host(const char *host, struct sockaddr_in6 *sin6) { struct addrinfo hints, *res; - struct sockaddr_in6 *sin6; int gai_error; bzero(&hints, sizeof(hints)); @@ -304,15 +303,7 @@ parse_host(const char *host, struct in6_addr *in6) warnx("%s: %s", host, gai_strerror(gai_error)); return 1; } - - sin6 = (struct sockaddr_in6 *)res->ai_addr; - *in6 = sin6->sin6_addr; -#ifdef __KAME__ - if (IN6_IS_ADDR_LINKLOCAL(in6)) { - *(u_int16_t *)&in6->s6_addr[2] = htons(sin6->sin6_scope_id); - } -#endif - + *sin6 = *(struct sockaddr_in6 *)res->ai_addr; freeaddrinfo(res); return 0; } @@ -346,7 +337,7 @@ set(int argc, char *argv[]) sdl_m = blank_sdl; sin_m = blank_sin; - if (parse_host(host, &sin->sin6_addr)) + if (parse_host(host, sin)) return 1; ea = (u_char *)LLADDR(&sdl_m); if (ndp_ether_aton(eaddr, ea) == 0) @@ -368,7 +359,8 @@ set(int argc, char *argv[]) errx(1, "RTM_GET(%s) failed", host); } - if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) { + if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr) && + sin->sin6_scope_id == sin_m.sin6_scope_id) { if (sdl->sdl_family == AF_LINK && (rtm->rtm_flags & RTF_LLINFO) && !(rtm->rtm_flags & RTF_GATEWAY)) { @@ -404,10 +396,10 @@ get(const char *host) struct sockaddr_in6 *sin = &sin_m; sin_m = blank_sin; - if (parse_host(host, &sin->sin6_addr)) + if (parse_host(host, sin)) return; - dump(&sin->sin6_addr, 0); + dump(sin, 0); if (found_entry == 0) { getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, sizeof(host_buf), NULL ,0, @@ -429,13 +421,14 @@ delete(const char *host) getsocket(); sin_m = blank_sin; - if (parse_host(host, &sin->sin6_addr)) + if (parse_host(host, sin)) return 1; if (rtget(&sin, &sdl)) { errx(1, "RTM_GET(%s) failed", host); } - if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) { + if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr) && + sin->sin6_scope_id == sin_m.sin6_scope_id) { if (sdl->sdl_family == AF_LINK && rtm->rtm_flags & RTF_LLINFO) { if (rtm->rtm_flags & RTF_LOCAL) return (0); @@ -455,16 +448,8 @@ delete: return (1); } if (rtmsg(RTM_DELETE) == 0) { - struct sockaddr_in6 s6 = *sin; /* XXX: for safety */ - -#ifdef __KAME__ - if (IN6_IS_ADDR_LINKLOCAL(&s6.sin6_addr)) { - s6.sin6_scope_id = ntohs(*(u_int16_t *)&s6.sin6_addr.s6_addr[2]); - *(u_int16_t *)&s6.sin6_addr.s6_addr[2] = 0; - } -#endif - getnameinfo((struct sockaddr *)&s6, - s6.sin6_len, host_buf, + getnameinfo((struct sockaddr *)sin, + sin->sin6_len, host_buf, sizeof(host_buf), NULL, 0, (nflag ? NI_NUMERICHOST : 0)); printf("%s (%s) deleted\n", host, host_buf); @@ -481,7 +466,7 @@ delete: * Dump the entire neighbor cache */ void -dump(struct in6_addr *addr, int cflag) +dump(struct sockaddr_in6 *addr, int cflag) { int mib[7]; size_t needed; @@ -534,6 +519,19 @@ again:; if (rtm->rtm_version != RTM_VERSION) continue; sin = (struct sockaddr_in6 *)(next + rtm->rtm_hdrlen); +#ifdef __KAME__ + { + struct in6_addr *in6 = &sin->sin6_addr; + if ((IN6_IS_ADDR_LINKLOCAL(in6) || + IN6_IS_ADDR_MC_LINKLOCAL(in6) || + IN6_IS_ADDR_MC_INTFACELOCAL(in6)) && + sin->sin6_scope_id == 0) { + sin->sin6_scope_id = (u_int32_t) + ntohs(*(u_short *)&in6->s6_addr[2]); + *(u_short *)&in6->s6_addr[2] = 0; + } + } +#endif sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len)); /* @@ -556,21 +554,13 @@ again:; continue; if (addr) { - if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr)) + if (!IN6_ARE_ADDR_EQUAL(&addr->sin6_addr, + &sin->sin6_addr) || addr->sin6_scope_id != + sin->sin6_scope_id) continue; found_entry = 1; } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr)) continue; - if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) || - IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) { - /* XXX: should scope id be filled in the kernel? */ - if (sin->sin6_scope_id == 0) - sin->sin6_scope_id = sdl->sdl_index; -#ifdef __KAME__ - /* KAME specific hack; removed the embedded id */ - *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0; -#endif - } getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, sizeof(host_buf), NULL, 0, (nflag ? NI_NUMERICHOST : 0)); if (cflag) { @@ -778,7 +768,22 @@ rtmsg(int cmd) ADVANCE(cp, (struct sockaddr *)&(s)); \ } +#ifdef __KAME__ + { + struct sockaddr_in6 sin6 = sin_m; + struct in6_addr *in6 = &sin6.sin6_addr; + if (IN6_IS_ADDR_LINKLOCAL(in6) || + IN6_IS_ADDR_MC_LINKLOCAL(in6) || + IN6_IS_ADDR_MC_INTFACELOCAL(in6)) { + *(u_int16_t *)& in6->s6_addr[2] = + htons(sin6.sin6_scope_id); + sin6.sin6_scope_id = 0; + } + NEXTADDR(RTA_DST, sin6); + } +#else NEXTADDR(RTA_DST, sin_m); +#endif NEXTADDR(RTA_GATEWAY, sdl_m); #if 0 /* we don't support ipv6addr/128 type proxying. */ memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr)); @@ -841,6 +846,26 @@ rtget(struct sockaddr_in6 **sinp, struct sockaddr_dl **sdlp) if (sin == NULL || sdl == NULL) return (1); +#ifdef __KAME__ + { + static struct sockaddr_in6 ksin; + struct in6_addr *in6; + + /* do not damage the route message, we need it for delete */ + ksin = *sin; + sin = &ksin; + in6 = &sin->sin6_addr; + + if ((IN6_IS_ADDR_LINKLOCAL(in6) || + IN6_IS_ADDR_MC_LINKLOCAL(in6) || + IN6_IS_ADDR_MC_INTFACELOCAL(in6)) && + sin->sin6_scope_id == 0) { + sin->sin6_scope_id = (u_int32_t)ntohs(*(u_short *) + &in6->s6_addr[2]); + *(u_short *)&in6->s6_addr[2] = 0; + } + } +#endif *sinp = sin; *sdlp = sdl;