-/* $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 $ */
/*
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 *);
}
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));
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;
}
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)
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)) {
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,
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);
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);
* 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;
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));
/*
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) {
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));
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;