Index: usr.sbin/traceroute6/Makefile =================================================================== --- usr.sbin/traceroute6/Makefile +++ usr.sbin/traceroute6/Makefile @@ -13,6 +13,8 @@ # A PARTICULAR PURPOSE. # $FreeBSD$ +.include + TRACEROUTE_DISTDIR?= ${SRCTOP}/contrib/traceroute .PATH: ${TRACEROUTE_DISTDIR} @@ -26,8 +28,14 @@ CFLAGS+= -DIPSEC -DHAVE_POLL CFLAGS+= -I${.CURDIR} -I${TRACEROUTE_DISTDIR} -I. +.if ${MK_CASPER} != "no" +LIBADD+= casper +LIBADD+= cap_dns +CFLAGS+=-DWITH_CASPER +.endif + WARNS?= 3 -LIBADD= ipsec +LIBADD+= ipsec .include Index: usr.sbin/traceroute6/traceroute6.c =================================================================== --- usr.sbin/traceroute6/traceroute6.c +++ usr.sbin/traceroute6/traceroute6.c @@ -247,8 +247,8 @@ * -- Van Jacobson (van@helios.ee.lbl.gov) * Tue Dec 20 03:50:13 PST 1988 */ - #include +#include #include #include #include @@ -260,6 +260,11 @@ #include +#ifdef WITH_CASPER +#include +#include +#endif + #include #include #include @@ -290,7 +295,7 @@ #define MAXPACKET 65535 /* max ip packet size */ #ifndef HAVE_GETIPNODEBYNAME -#define getipnodebyname(x, y, z, u) gethostbyname2((x), (y)) +#define getipnodebyname(x, y, z, u) cap_gethostbyname2(capdns, (x), (y)) #define freehostent(x) #endif @@ -314,6 +319,8 @@ const char *inetname(struct sockaddr *); u_int32_t sctp_crc32c(void *, u_int32_t); u_int16_t in_cksum(u_int16_t *addr, int); +u_int16_t udp_cksum(struct sockaddr_in6 *, struct sockaddr_in6 *, + void *, u_int32_t); u_int16_t tcp_chksum(struct sockaddr_in6 *, struct sockaddr_in6 *, void *, u_int32_t); void usage(void); @@ -337,6 +344,10 @@ char *source = NULL; char *hostname; +#ifdef WITH_CASPER +static cap_channel_t *capdns; +#endif + u_long nprobes = 3; u_long first_hop = 1; u_long max_hops = 30; @@ -366,6 +377,31 @@ size_t size, minlen; uid_t uid; u_char type, code; + cap_rights_t rights; + + #ifdef WITH_CASPER + const char *types[] = { "NAME", "ADDR" }; + int families[1]; + cap_channel_t *casper; + #endif + + #ifdef WITH_CASPER + casper = cap_init(); + if (casper == NULL) + errx(1, "unable to create casper process"); + capdns = cap_service_open(casper, "system.dns"); + if (capdns == NULL) + errx(1, "unable to open system.dns service"); + if (cap_dns_type_limit(capdns, types, 2) < 0) + errx(1, "unable to limit access to system.dns service"); + families[0] = AF_INET6; + if (cap_dns_family_limit(capdns, families, 1) < 0) + errx(1, "unable to limit access to system.dns service"); + #endif /* WITH_CASPER */ + + #ifdef WITH_CASPER + cap_close(casper); + #endif /* * Receive ICMP @@ -558,8 +594,8 @@ sndsock = rcvsock; break; case IPPROTO_UDP: - if ((sndsock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { - perror("socket(SOCK_DGRAM)"); + if ((sndsock = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP)) < 0) { + perror("socket(SOCK_RAW)"); exit(5); } break; @@ -604,7 +640,11 @@ hints.ai_socktype = SOCK_RAW; hints.ai_protocol = IPPROTO_ICMPV6; hints.ai_flags = AI_CANONNAME; - error = getaddrinfo(*argv, NULL, &hints, &res); + + if(capdns != NULL){ + error = cap_getaddrinfo(capdns, *argv, NULL, &hints, &res); + } + if (error) { fprintf(stderr, "traceroute6: %s\n", gai_strerror(error)); @@ -622,7 +662,7 @@ exit(1); } if (res->ai_next) { - if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, + if (cap_getnameinfo(capdns, res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) strlcpy(hbuf, "?", sizeof(hbuf)); fprintf(stderr, "traceroute6: Warning: %s has multiple " @@ -808,7 +848,7 @@ hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_DGRAM; /*dummy*/ hints.ai_flags = AI_NUMERICHOST; - error = getaddrinfo(source, "0", &hints, &res); + error = cap_getaddrinfo(capdns, source, "0", &hints, &res); if (error) { printf("traceroute6: %s: %s\n", source, gai_strerror(error)); @@ -844,7 +884,7 @@ perror("getsockname"); exit(1); } - if (getnameinfo((struct sockaddr *)&Src, Src.sin6_len, + if (cap_getnameinfo(capdns, (struct sockaddr *)&Src, Src.sin6_len, src0, sizeof(src0), NULL, 0, NI_NUMERICHOST)) { fprintf(stderr, "getnameinfo failed for source\n"); exit(1); @@ -884,7 +924,7 @@ /* * Message to users */ - if (getnameinfo((struct sockaddr *)&Dst, Dst.sin6_len, hbuf, + if (cap_getnameinfo(capdns, (struct sockaddr *)&Dst, Dst.sin6_len, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST)) strlcpy(hbuf, "(invalid)", sizeof(hbuf)); fprintf(stderr, "traceroute6"); @@ -899,6 +939,30 @@ if (first_hop > 1) printf("Skipping %lu intermediate hops\n", first_hop - 1); + if (connect(sndsock, (struct sockaddr *)&Dst, + sizeof(Dst)) != 0) { + fprintf(stderr, "connect: %s\n", strerror(errno)); + exit(1); + } + + /* + * Here we enter capability mode. Further down access to global + * namespaces (e.g filesystem) is restricted (see capsicum(4)). + * We must connect(2) our socket before this point. + */ + + if (cap_enter() < 0 && errno != ENOSYS) { + fprintf(stderr, "cap_enter: %s\n", strerror(errno)); + exit(1); + } + + cap_rights_init(&rights, CAP_SEND, CAP_SETSOCKOPT); + if (cap_rights_limit(sndsock, &rights) < 0) { + fprintf(stderr, "cap_rights_limit sndsock: %s\n", + strerror(errno)); + exit(1); + } + /* * Main loop */ @@ -1047,6 +1111,7 @@ { struct icmp6_hdr *icp; struct sctphdr *sctp; + struct udphdr *outudp; struct sctp_chunkhdr *chk; struct sctp_init_chunk *init; struct sctp_paramhdr *param; @@ -1072,6 +1137,11 @@ icp->icmp6_seq = htons(seq); break; case IPPROTO_UDP: + outudp = (struct udphdr *) outpacket; + outudp->uh_sport = htons(ident); + outudp->uh_dport = htons(port+seq); + outudp->uh_ulen = htons(datalen); + outudp->uh_sum = udp_cksum(&Src, &Dst, outpacket, datalen); break; case IPPROTO_NONE: /* No space for anything. No harm as seq/tv32 are decorative. */ @@ -1158,12 +1228,11 @@ fprintf(stderr, "Unknown probe protocol %d.\n", useproto); exit(1); } - - i = sendto(sndsock, (char *)outpacket, datalen, 0, - (struct sockaddr *)&Dst, Dst.sin6_len); + + i = send(sndsock, (char *)outpacket, datalen, 0); if (i < 0 || (u_long)i != datalen) { if (i < 0) - perror("sendto"); + perror("send"); printf("traceroute6: wrote %s %lu chars, ret=%d\n", hostname, datalen, i); (void) fflush(stdout); @@ -1275,7 +1344,7 @@ hlen = sizeof(struct ip6_hdr); if (cc < hlen + sizeof(struct icmp6_hdr)) { if (verbose) { - if (getnameinfo((struct sockaddr *)from, from->sin6_len, + if (cap_getnameinfo(capdns, (struct sockaddr *)from, from->sin6_len, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) strlcpy(hbuf, "invalid", sizeof(hbuf)); printf("packet too short (%d bytes) from %s\n", cc, @@ -1288,7 +1357,7 @@ #else if (cc < (int)sizeof(struct icmp6_hdr)) { if (verbose) { - if (getnameinfo((struct sockaddr *)from, from->sin6_len, + if (cap_getnameinfo(capdns, (struct sockaddr *)from, from->sin6_len, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) strlcpy(hbuf, "invalid", sizeof(hbuf)); printf("data too short (%d bytes) from %s\n", cc, hbuf); @@ -1354,7 +1423,7 @@ break; case IPPROTO_UDP: udp = (struct udphdr *)up; - if (udp->uh_sport == htons(srcport) && + if (udp->uh_sport == htons(ident) && udp->uh_dport == htons(port + seq)) return (1); break; @@ -1410,7 +1479,7 @@ u_int8_t *p; int i; - if (getnameinfo((struct sockaddr *)from, from->sin6_len, + if (cap_getnameinfo(capdns, (struct sockaddr *)from, from->sin6_len, sbuf, sizeof(sbuf), NULL, 0, NI_NUMERICHOST) != 0) strlcpy(sbuf, "invalid", sizeof(sbuf)); printf("\n%d bytes from %s to %s", cc, sbuf, @@ -1489,7 +1558,7 @@ struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name; char hbuf[NI_MAXHOST]; - if (getnameinfo((struct sockaddr *)from, from->sin6_len, + if (cap_getnameinfo(capdns, (struct sockaddr *)from, from->sin6_len, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) strlcpy(hbuf, "invalid", sizeof(hbuf)); if (as_path) @@ -1536,7 +1605,7 @@ } cp = NULL; if (!nflag) { - if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0, + if (cap_getnameinfo(capdns, sa, sa->sa_len, line, sizeof(line), NULL, 0, NI_NAMEREQD) == 0) { if ((cp = strchr(line, '.')) && !strcmp(cp + 1, domain)) @@ -1547,7 +1616,7 @@ if (cp) return cp; - if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0, + if (cap_getnameinfo(capdns, sa, sa->sa_len, line, sizeof(line), NULL, 0, NI_NUMERICHOST) != 0) strlcpy(line, "invalid", sizeof(line)); return line; @@ -1677,6 +1746,33 @@ return (answer); } +u_int16_t +udp_cksum(struct sockaddr_in6 *src, struct sockaddr_in6 *dst, + void *payload, u_int32_t len) +{ + struct { + struct in6_addr src; + struct in6_addr dst; + u_int32_t len; + u_int8_t zero[3]; + u_int8_t next; + } pseudo_hdr; + u_int16_t sum[2]; + + pseudo_hdr.src = src->sin6_addr; + pseudo_hdr.dst = dst->sin6_addr; + pseudo_hdr.len = htonl(len); + pseudo_hdr.zero[0] = 0; + pseudo_hdr.zero[1] = 0; + pseudo_hdr.zero[2] = 0; + pseudo_hdr.next = IPPROTO_UDP; + + sum[1] = in_cksum((u_int16_t *)&pseudo_hdr, sizeof(pseudo_hdr)); + sum[0] = in_cksum(payload, len); + + return (~in_cksum(sum, sizeof(sum))); +} + u_int16_t tcp_chksum(struct sockaddr_in6 *src, struct sockaddr_in6 *dst, void *payload, u_int32_t len)