From: mpi Date: Wed, 3 Jun 2015 08:10:53 +0000 (+0000) Subject: Explicitly request the sockaddr_dl when doing a RTM_GET rather than X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=f3b11628a009ccfbc47a504210e1737cf43509bc;p=openbsd Explicitly request the sockaddr_dl when doing a RTM_GET rather than assuming that it will be in the gateway sa. Fixes a regression introduced with the support of multiple connected routes, found the hardway by deraadt@. ok claudio@ --- diff --git a/usr.sbin/arp/arp.c b/usr.sbin/arp/arp.c index fcd61491e3b..e2d36cd2e76 100644 --- a/usr.sbin/arp/arp.c +++ b/usr.sbin/arp/arp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: arp.c,v 1.63 2015/01/16 06:40:15 deraadt Exp $ */ +/* $OpenBSD: arp.c,v 1.64 2015/06/03 08:10:53 mpi Exp $ */ /* $NetBSD: arp.c,v 1.12 1995/04/24 13:25:18 cgd Exp $ */ /* @@ -75,6 +75,7 @@ int file(char *); int get(const char *); int getinetaddr(const char *, struct in_addr *); void getsocket(void); +int rtget(struct sockaddr_inarp **, struct sockaddr_dl **); int rtmsg(int); int set(int, char **); void usage(void); @@ -254,6 +255,7 @@ getsocket(void) struct sockaddr_in so_mask = { 8, 0, 0, { 0xffffffff } }; struct sockaddr_inarp blank_sin = { sizeof(blank_sin), AF_INET }, sin_m; struct sockaddr_dl blank_sdl = { sizeof(blank_sdl), AF_LINK }, sdl_m; +struct sockaddr_dl ifp_m = { sizeof(&ifp_m), AF_LINK }; time_t expire_time; int flags, export_only, doing_proxy, found_entry; struct { @@ -319,12 +321,11 @@ set(int argc, char *argv[]) } tryagain: - if (rtmsg(RTM_GET) < 0) { + if (rtget(&sin, &sdl)) { warn("%s", host); return (1); } - sin = (struct sockaddr_inarp *)((char *)rtm + rtm->rtm_hdrlen); - sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin_len) + (char *)sin); + if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) { if (sdl->sdl_family == AF_LINK && (rtm->rtm_flags & RTF_LLINFO) && @@ -412,15 +413,13 @@ delete(const char *host, const char *info) if (getinetaddr(host, &sin->sin_addr) == -1) return (1); tryagain: - if (rtmsg(RTM_GET) < 0) { + if (rtget(&sin, &sdl) < 0) { warn("%s", host); return (1); } - sin = (struct sockaddr_inarp *)((char *)rtm + rtm->rtm_hdrlen); - sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin_len) + (char *)sin); if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) { if (sdl->sdl_family == AF_LINK && rtm->rtm_flags & RTF_LLINFO) { - if (rtm->rtm_flags & (RTF_LOCAL|RTF_BROADCAST)) + if (rtm->rtm_flags & RTF_LOCAL) return (0); if (!(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) { @@ -493,8 +492,6 @@ search(in_addr_t addr, void (*action)(struct sockaddr_dl *sdl, rtm = (struct rt_msghdr *)next; if (rtm->rtm_version != RTM_VERSION) continue; - if (rtm->rtm_flags & RTF_BROADCAST) - continue; sin = (struct sockaddr_inarp *)(next + rtm->rtm_hdrlen); sdl = (struct sockaddr_dl *)(sin + 1); if (addr) { @@ -558,7 +555,7 @@ print_entry(struct sockaddr_dl *sdl, struct sockaddr_inarp *sin, printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host, llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname); - if (rtm->rtm_flags & (RTF_PERMANENT_ARP|RTF_LOCAL|RTF_BROADCAST)) + if (rtm->rtm_flags & (RTF_PERMANENT_ARP|RTF_LOCAL)) printf(" %-10.10s", "permanent"); else if (rtm->rtm_rmx.rmx_expire == 0) printf(" %-10.10s", "static"); @@ -654,7 +651,7 @@ rtmsg(int cmd) } /* FALLTHROUGH */ case RTM_GET: - rtm->rtm_addrs |= RTA_DST; + rtm->rtm_addrs |= (RTA_DST | RTA_IFP); } #define NEXTADDR(w, s) \ @@ -666,6 +663,7 @@ rtmsg(int cmd) NEXTADDR(RTA_DST, sin_m); NEXTADDR(RTA_GATEWAY, sdl_m); NEXTADDR(RTA_NETMASK, so_mask); + NEXTADDR(RTA_IFP, ifp_m); rtm->rtm_msglen = cp - (char *)&m_rtmsg; doit: @@ -688,6 +686,48 @@ doit: return (0); } +int +rtget(struct sockaddr_inarp **sinp, struct sockaddr_dl **sdlp) +{ + struct rt_msghdr *rtm = &(m_rtmsg.m_rtm); + struct sockaddr_inarp *sin = NULL; + struct sockaddr_dl *sdl = NULL; + struct sockaddr *sa; + char *cp; + int i; + + if (rtmsg(RTM_GET) < 0) + return (1); + + if (rtm->rtm_addrs) { + cp = ((char *)rtm + rtm->rtm_hdrlen); + for (i = 1; i; i <<= 1) { + if (i & rtm->rtm_addrs) { + sa = (struct sockaddr *)cp; + switch (i) { + case RTA_DST: + sin = (struct sockaddr_inarp *)sa; + break; + case RTA_IFP: + sdl = (struct sockaddr_dl *)sa; + break; + default: + break; + } + cp += ROUNDUP(sa->sa_len); + } + } + } + + if (sin == NULL || sdl == NULL) + return (1); + + *sinp = sin; + *sdlp = sdl; + + return (0); +} + int getinetaddr(const char *host, struct in_addr *inap) { diff --git a/usr.sbin/ndp/ndp.c b/usr.sbin/ndp/ndp.c index ce75ef718a0..46c12698287 100644 --- a/usr.sbin/ndp/ndp.c +++ b/usr.sbin/ndp/ndp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ndp.c,v 1.60 2015/04/18 18:28:38 deraadt Exp $ */ +/* $OpenBSD: ndp.c,v 1.61 2015/06/03 08:10:53 mpi Exp $ */ /* $KAME: ndp.c,v 1.101 2002/07/17 08:46:33 itojun Exp $ */ /* @@ -134,6 +134,7 @@ static char *ether_str(struct sockaddr_dl *); int ndp_ether_aton(char *, u_char *); void usage(void); int rtmsg(int); +int rtget(struct sockaddr_in6 **, struct sockaddr_dl **); void ifinfo(char *, int, char **); void rtrlist(void); void plist(void); @@ -343,6 +344,7 @@ getsocket(void) struct sockaddr_in6 so_mask = {sizeof(so_mask), AF_INET6 }; struct sockaddr_in6 blank_sin = {sizeof(blank_sin), AF_INET6 }, sin_m; struct sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m; +struct sockaddr_dl ifp_m = { sizeof(&ifp_m), AF_LINK }; time_t expire_time; int flags, found_entry; struct { @@ -400,12 +402,12 @@ set(int argc, char **argv) flags |= RTF_ANNOUNCE; argv++; } - if (rtmsg(RTM_GET) < 0) { + + if (rtget(&sin, &sdl)) { errx(1, "RTM_GET(%s) failed", host); /* NOTREACHED */ } - sin = (struct sockaddr_in6 *)((char *)rtm + rtm->rtm_hdrlen); - sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin); + if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) { if (sdl->sdl_family == AF_LINK && (rtm->rtm_flags & RTF_LLINFO) && @@ -499,12 +501,12 @@ delete(char *host) htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id); } #endif - if (rtmsg(RTM_GET) < 0) { + + if (rtget(&sin, &sdl)) { errx(1, "RTM_GET(%s) failed", host); /* NOTREACHED */ } - sin = (struct sockaddr_in6 *)((char *)rtm + rtm->rtm_hdrlen); - sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin); + if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) { if (sdl->sdl_family == AF_LINK && rtm->rtm_flags & RTF_LLINFO) { if (rtm->rtm_flags & (RTF_LOCAL|RTF_BROADCAST)) @@ -832,7 +834,7 @@ rtmsg(int cmd) #endif /* FALLTHROUGH */ case RTM_GET: - rtm->rtm_addrs |= RTA_DST; + rtm->rtm_addrs |= (RTA_DST | RTA_IFP); } #define NEXTADDR(w, s) \ if (rtm->rtm_addrs & (w)) { \ @@ -844,6 +846,7 @@ rtmsg(int cmd) memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr)); NEXTADDR(RTA_NETMASK, so_mask); #endif + NEXTADDR(RTA_IFP, ifp_m); rtm->rtm_msglen = cp - (char *)&m_rtmsg; doit: @@ -866,6 +869,48 @@ doit: return (0); } +int +rtget(struct sockaddr_in6 **sinp, struct sockaddr_dl **sdlp) +{ + struct rt_msghdr *rtm = &(m_rtmsg.m_rtm); + struct sockaddr_in6 *sin = NULL; + struct sockaddr_dl *sdl = NULL; + struct sockaddr *sa; + char *cp; + int i; + + if (rtmsg(RTM_GET) < 0) + return (1); + + if (rtm->rtm_addrs) { + cp = ((char *)rtm + rtm->rtm_hdrlen); + for (i = 1; i; i <<= 1) { + if (i & rtm->rtm_addrs) { + sa = (struct sockaddr *)cp; + switch (i) { + case RTA_DST: + sin = (struct sockaddr_in6 *)sa; + break; + case RTA_IFP: + sdl = (struct sockaddr_dl *)sa; + break; + default: + break; + } + cp += ROUNDUP(sa->sa_len); + } + } + } + + if (sin == NULL || sdl == NULL) + return (1); + + *sinp = sin; + *sdlp = sdl; + + return (0); +} + void ifinfo(char *ifname, int argc, char **argv) {