Module Name: src Committed By: kefren Date: Tue Jun 21 14:33:14 UTC 2011
Modified Files: src/sbin/route: route.c Log Message: Alloc dynamically sockunions in sou. Teach route(8) about multiple tags. E.G.: -tag 100,20,33 XXX: needs documentation To generate a diff of this commit: cvs rdiff -u -r1.128 -r1.129 src/sbin/route/route.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sbin/route/route.c diff -u src/sbin/route/route.c:1.128 src/sbin/route/route.c:1.129 --- src/sbin/route/route.c:1.128 Tue Feb 1 01:39:19 2011 +++ src/sbin/route/route.c Tue Jun 21 14:33:14 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: route.c,v 1.128 2011/02/01 01:39:19 matt Exp $ */ +/* $NetBSD: route.c,v 1.129 2011/06/21 14:33:14 kefren Exp $ */ /* * Copyright (c) 1983, 1989, 1991, 1993 @@ -39,7 +39,7 @@ #if 0 static char sccsid[] = "@(#)route.c 8.6 (Berkeley) 4/28/95"; #else -__RCSID("$NetBSD: route.c,v 1.128 2011/02/01 01:39:19 matt Exp $"); +__RCSID("$NetBSD: route.c,v 1.129 2011/06/21 14:33:14 kefren Exp $"); #endif #endif /* not lint */ @@ -97,7 +97,8 @@ typedef union sockunion *sup; struct sou { - union sockunion so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp, so_mpls; + union sockunion *so_dst, *so_gate, *so_mask, *so_genmask, *so_ifa, + *so_ifp, *so_mpls; }; static char *any_ntoa(const struct sockaddr *); @@ -116,6 +117,8 @@ static void monitor(void); static int print_getmsg(struct rt_msghdr *, int, struct sou *); static const char *linkstate(struct if_msghdr *); +static sup readtag(sup, const char *); +static void addtag(sup, const char *, int); #endif /* SMALL */ static int rtmsg(int, int, struct sou *); static void mask_addr(struct sou *); @@ -588,11 +591,21 @@ case AF_MPLS: { union mpls_shim ms; + const union mpls_shim *pms; + int psize = sizeof(struct sockaddr_mpls); ms.s_addr =((const struct sockaddr_mpls*)sa)->smpls_addr.s_addr; ms.s_addr = ntohl(ms.s_addr); snprintf(line, sizeof(line), "%u", ms.shim.label); + pms = &((const struct sockaddr_mpls*)sa)->smpls_addr; + while(psize < sa->sa_len) { + pms++; + ms.s_addr = ntohl(pms->s_addr); + snprintf(line, sizeof(line), "%s %u", line, + ms.shim.label); + psize += sizeof(ms); + } break; } #endif /* SMALL */ @@ -795,7 +808,18 @@ struct hostent *hp = 0; struct sou sou, *soup = &sou; - memset(&sou, 0, sizeof(sou)); + sou.so_dst = calloc(1, sizeof(union sockunion)); + sou.so_gate = calloc(1, sizeof(union sockunion)); + sou.so_mask = calloc(1, sizeof(union sockunion)); + sou.so_genmask = calloc(1, sizeof(union sockunion)); + sou.so_ifa = calloc(1, sizeof(union sockunion)); + sou.so_ifp = calloc(1, sizeof(union sockunion)); + sou.so_mpls = calloc(1, sizeof(union sockunion)); + + if (sou.so_dst == NULL || sou.so_gate == NULL || sou.so_mask == NULL || + sou.so_genmask == NULL || sou.so_ifa == NULL || sou.so_ifp == NULL || + sou.so_mpls == NULL) + errx(EXIT_FAILURE, "Cannot allocate memory"); cmd = argv[0]; af = AF_UNSPEC; @@ -849,6 +873,7 @@ case K_TAG: if (!--argc) usage(1+*argv); + af = AF_MPLS; aflen = sizeof(struct sockaddr_mpls); (void)getaddr(RTA_TAG, *++argv, 0, soup); break; @@ -1016,7 +1041,7 @@ break; if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) { hp->h_addr_list++; - memmove(&soup->so_gate.sin.sin_addr, hp->h_addr_list[0], + memmove(&soup->so_gate->sin.sin_addr, hp->h_addr_list[0], hp->h_length); } else break; @@ -1030,13 +1055,21 @@ (void)printf(": gateway %s", gateway); if (attempts > 1 && ret == 0 && af == AF_INET) (void)printf(" (%s)", - inet_ntoa(soup->so_gate.sin.sin_addr)); + inet_ntoa(soup->so_gate->sin.sin_addr)); } if (ret == 0) (void)printf("\n"); else (void)printf(": %s\n", route_strerror(oerrno)); } + free(sou.so_dst); + free(sou.so_gate); + free(sou.so_mask); + free(sou.so_genmask); + free(sou.so_ifa); + free(sou.so_ifp); + free(sou.so_mpls); + return ret != 0; } @@ -1090,7 +1123,7 @@ mask = -1; } isin->sin_addr.s_addr = htonl(addr); - sin = &soup->so_mask.sin; + sin = &soup->so_mask->sin; sin->sin_addr.s_addr = htonl(mask); sin->sin_len = 0; sin->sin_family = 0; @@ -1154,28 +1187,28 @@ rtm_addrs |= which; switch (which) { case RTA_DST: - su = &soup->so_dst; + su = soup->so_dst; break; case RTA_GATEWAY: - su = &soup->so_gate; + su = soup->so_gate; break; case RTA_NETMASK: - su = &soup->so_mask; + su = soup->so_mask; break; case RTA_GENMASK: - su = &soup->so_genmask; + su = soup->so_genmask; break; case RTA_IFP: - su = &soup->so_ifp; + su = soup->so_ifp; afamily = AF_LINK; break; case RTA_IFA: - su = &soup->so_ifa; + su = soup->so_ifa; su->sa.sa_family = af; break; #ifndef SMALL case RTA_TAG: - su = &soup->so_mpls; + su = soup->so_mpls; afamily = AF_MPLS; break; #endif @@ -1285,15 +1318,13 @@ rtm_addrs |= RTA_NETMASK; return(forcehost || su->sat.sat_addr.s_node != 0); case AF_MPLS: - /* Tag should be a positive value, limited to 20 bits */ - if (atoi(s) < 0 || atoi(s) >= (1 << 20)) - errx(1, "bad tag: %s", s); - su->smpls.smpls_addr.s_addr = 0; - su->smpls.smpls_addr.shim.label = atoi(s); - su->smpls.smpls_addr.s_addr = - htonl(su->smpls.smpls_addr.s_addr); - - /* We don't have netmasks for tags */ + if (which == RTA_DST) + soup->so_dst = readtag(su, s); + else if (which == RTA_TAG) + soup->so_mpls = readtag(su, s); + else + errx(EXIT_FAILURE, "MPLS can be used only as " + "DST or TAG"); return 1; #endif @@ -1353,6 +1384,56 @@ /*NOTREACHED*/ } +static sup +readtag(sup su, const char *s) +{ + char *p, *n, *norig; + int mplssize = 0; + sup retsu = su; + + n = (char*)malloc(strlen(s) + 1); + if (n == NULL) + errx(EXIT_FAILURE, "%s: Cannot allocate memory", s); + norig = n; + strlcpy(n, s, strlen(s) + 1); + for (uint i = 0; i < strlen(n); i++) + if(n[i] == ',') + mplssize++; + +#define MPLS_NEW_SIZE (sizeof(struct sockaddr_mpls) + \ + mplssize * sizeof(union mpls_shim)) + + if (mplssize != 0 && sizeof(union sockunion) < MPLS_NEW_SIZE) { + free(su); + retsu = malloc(MPLS_NEW_SIZE); + retsu->smpls.smpls_family = AF_MPLS; + } + retsu->smpls.smpls_len = MPLS_NEW_SIZE; + mplssize = 0; + while ((p = strchr(n, ',')) != NULL) { + p[0] = '\0'; + addtag(retsu, n, mplssize); + n = p + 1; + mplssize++; + } + addtag(retsu, n, mplssize); + + free(norig); + return retsu; +} + +static void +addtag(sup su, const char *s, int where) +{ + union mpls_shim *ms = &su->smpls.smpls_addr; + + if (atoi(s) < 0 || atoi(s) >= (1 << 20)) + errx(EXIT_FAILURE, "%s: Bad tag", s); + ms[where].s_addr = 0; + ms[where].shim.label = atoi(s); + ms[where].s_addr = htonl(ms[where].s_addr); +} + int prefixlen(const char *s, struct sou *soup) { @@ -1381,22 +1462,22 @@ r = len & 7; switch (af) { case AF_INET: - memset(&soup->so_mask, 0, sizeof(soup->so_mask)); - soup->so_mask.sin.sin_family = AF_INET; - soup->so_mask.sin.sin_len = sizeof(struct sockaddr_in); - soup->so_mask.sin.sin_addr.s_addr = (len == 0 ? 0 + memset(soup->so_mask, 0, sizeof(soup->so_mask)); + soup->so_mask->sin.sin_family = AF_INET; + soup->so_mask->sin.sin_len = sizeof(struct sockaddr_in); + soup->so_mask->sin.sin_addr.s_addr = (len == 0 ? 0 : htonl(0xffffffff << (32 - len))); break; #ifdef INET6 case AF_INET6: - soup->so_mask.sin6.sin6_family = AF_INET6; - soup->so_mask.sin6.sin6_len = sizeof(struct sockaddr_in6); - memset(&soup->so_mask.sin6.sin6_addr, 0, - sizeof(soup->so_mask.sin6.sin6_addr)); + soup->so_mask->sin6.sin6_family = AF_INET6; + soup->so_mask->sin6.sin6_len = sizeof(struct sockaddr_in6); + memset(&soup->so_mask->sin6.sin6_addr, 0, + sizeof(soup->so_mask->sin6.sin6_addr)); if (q > 0) - memset(&soup->so_mask.sin6.sin6_addr, 0xff, q); + memset(&soup->so_mask->sin6.sin6_addr, 0xff, q); if (r > 0) - *((u_char *)&soup->so_mask.sin6.sin6_addr + q) = + *((u_char *)&soup->so_mask->sin6.sin6_addr + q) = (0xff00 >> r) & 0xff; break; #endif @@ -1478,8 +1559,8 @@ #define NEXTADDR(w, u) \ if (rtm_addrs & (w)) {\ - l = RT_ROUNDUP(u.sa.sa_len); memmove(cp, &(u), l); cp += l;\ - if (verbose && ! shortoutput) sodump(&(u),#u);\ + l = RT_ROUNDUP(u->sa.sa_len); memmove(cp, u, l); cp += l;\ + if (verbose && ! shortoutput) sodump(u,#u);\ } errno = 0; @@ -1493,9 +1574,9 @@ return -1; #else /* SMALL */ cmd = RTM_GET; - if (soup->so_ifp.sa.sa_family == AF_UNSPEC) { - soup->so_ifp.sa.sa_family = AF_LINK; - soup->so_ifp.sa.sa_len = sizeof(struct sockaddr_dl); + if (soup->so_ifp->sa.sa_family == AF_UNSPEC) { + soup->so_ifp->sa.sa_family = AF_LINK; + soup->so_ifp->sa.sa_len = sizeof(struct sockaddr_dl); rtm_addrs |= RTA_IFP; } #endif /* SMALL */ @@ -1556,17 +1637,17 @@ static void mask_addr(struct sou *soup) { - int olen = soup->so_mask.sa.sa_len; + int olen = soup->so_mask->sa.sa_len; char *cp1 = olen + (char *)&soup->so_mask, *cp2; - for (soup->so_mask.sa.sa_len = 0; cp1 > (char *)&soup->so_mask; ) + for (soup->so_mask->sa.sa_len = 0; cp1 > (char *)&soup->so_mask; ) if (*--cp1 != 0) { - soup->so_mask.sa.sa_len = 1 + cp1 - (char *)&soup->so_mask; + soup->so_mask->sa.sa_len = 1 + cp1 - (char *)&soup->so_mask; break; } if ((rtm_addrs & RTA_DST) == 0) return; - switch (soup->so_dst.sa.sa_family) { + switch (soup->so_dst->sa.sa_family) { case AF_INET: #ifdef INET6 case AF_INET6: @@ -1578,22 +1659,22 @@ return; #ifndef SMALL case AF_ISO: - olen = MIN(soup->so_dst.siso.siso_nlen, - MAX(soup->so_mask.sa.sa_len - 6, 0)); + olen = MIN(soup->so_dst->siso.siso_nlen, + MAX(soup->so_mask->sa.sa_len - 6, 0)); break; #endif /* SMALL */ } - cp1 = soup->so_mask.sa.sa_len + 1 + (char *)&soup->so_dst; - cp2 = soup->so_dst.sa.sa_len + 1 + (char *)&soup->so_dst; + cp1 = soup->so_mask->sa.sa_len + 1 + (char *)&soup->so_dst; + cp2 = soup->so_dst->sa.sa_len + 1 + (char *)&soup->so_dst; while (cp2 > cp1) *--cp2 = 0; - cp2 = soup->so_mask.sa.sa_len + 1 + (char *)&soup->so_mask; - while (cp1 > soup->so_dst.sa.sa_data) + cp2 = soup->so_mask->sa.sa_len + 1 + (char *)&soup->so_mask; + while (cp1 > soup->so_dst->sa.sa_data) *--cp1 &= *--cp2; #ifndef SMALL - switch (soup->so_dst.sa.sa_family) { + switch (soup->so_dst->sa.sa_family) { case AF_ISO: - soup->so_dst.siso.siso_nlen = olen; + soup->so_dst->siso.siso_nlen = olen; break; } #endif /* SMALL */ @@ -1802,7 +1883,7 @@ if (! shortoutput) { (void)printf(" route to: %s\n", - routename(&soup->so_dst.sa, NULL, RTF_HOST)); + routename(&soup->so_dst->sa, NULL, RTF_HOST)); } if (rtm->rtm_version != RTM_VERSION) { warnx("routing message version %d not understood", @@ -2059,13 +2140,24 @@ which, iso_ntoa(&su->siso.siso_addr)); break; case AF_MPLS: - { + { union mpls_shim ms; + const union mpls_shim *pms; + int psize = sizeof(struct sockaddr_mpls); + ms.s_addr = ntohl(su->smpls.smpls_addr.s_addr); printf("%s: mpls %u; ", which, ms.shim.label); + + pms = &su->smpls.smpls_addr; + while(psize < su->smpls.smpls_len) { + pms++; + ms.s_addr = ntohl(pms->s_addr); + printf("%u; ", ms.shim.label); + psize += sizeof(ms); } break; + } #endif /* SMALL */ default: (void)printf("%s: (%d) %s; ",