From owner-svn-src-head@freebsd.org Sun Sep 6 14:04:04 2020 Return-Path: Delivered-To: svn-src-head@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 031CD3D1E47; Sun, 6 Sep 2020 14:04:04 +0000 (UTC) (envelope-from oshogbo@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4BktSM5gYnz3f4C; Sun, 6 Sep 2020 14:04:03 +0000 (UTC) (envelope-from oshogbo@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 7ACCEF773; Sun, 6 Sep 2020 14:04:03 +0000 (UTC) (envelope-from oshogbo@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 086E437x024714; Sun, 6 Sep 2020 14:04:03 GMT (envelope-from oshogbo@FreeBSD.org) Received: (from oshogbo@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 086E43HH024712; Sun, 6 Sep 2020 14:04:03 GMT (envelope-from oshogbo@FreeBSD.org) Message-Id: <202009061404.086E43HH024712@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: oshogbo set sender to oshogbo@FreeBSD.org using -f From: Mariusz Zaborski Date: Sun, 6 Sep 2020 14:04:03 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r365378 - head/usr.sbin/traceroute6 X-SVN-Group: head X-SVN-Commit-Author: oshogbo X-SVN-Commit-Paths: head/usr.sbin/traceroute6 X-SVN-Commit-Revision: 365378 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.33 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 06 Sep 2020 14:04:04 -0000 Author: oshogbo Date: Sun Sep 6 14:04:02 2020 New Revision: 365378 URL: https://svnweb.freebsd.org/changeset/base/365378 Log: traceroute6: capsicumize it Submitted by: Shubh Gupta Sponsored by: Google (GSOC 2020) Differential Revision: https://reviews.freebsd.org/D25604 Modified: head/usr.sbin/traceroute6/Makefile head/usr.sbin/traceroute6/traceroute6.c Modified: head/usr.sbin/traceroute6/Makefile ============================================================================== --- head/usr.sbin/traceroute6/Makefile Sun Sep 6 11:29:06 2020 (r365377) +++ head/usr.sbin/traceroute6/Makefile Sun Sep 6 14:04:02 2020 (r365378) @@ -13,6 +13,10 @@ # A PARTICULAR PURPOSE. # $FreeBSD$ +.include + +.include + TRACEROUTE_DISTDIR?= ${SRCTOP}/contrib/traceroute .PATH: ${TRACEROUTE_DISTDIR} @@ -26,7 +30,13 @@ BINMODE= 4555 CFLAGS+= -DIPSEC -DHAVE_POLL CFLAGS+= -I${.CURDIR} -I${TRACEROUTE_DISTDIR} -I. -LIBADD= ipsec +.if ${MK_CASPER} != "no" +LIBADD+= casper +LIBADD+= cap_dns +CFLAGS+= -DWITH_CASPER +.endif + +LIBADD+= ipsec .include Modified: head/usr.sbin/traceroute6/traceroute6.c ============================================================================== --- head/usr.sbin/traceroute6/traceroute6.c Sun Sep 6 11:29:06 2020 (r365377) +++ head/usr.sbin/traceroute6/traceroute6.c Sun Sep 6 14:04:02 2020 (r365378) @@ -249,6 +249,7 @@ static const char rcsid[] = */ #include +#include #include #include #include @@ -260,6 +261,10 @@ static const char rcsid[] = #include +#include +#include +#include + #include #include #include @@ -289,11 +294,6 @@ static const char rcsid[] = #define MAXPACKET 65535 /* max ip packet size */ -#ifndef HAVE_GETIPNODEBYNAME -#define getipnodebyname(x, y, z, u) gethostbyname2((x), (y)) -#define freehostent(x) -#endif - static u_char packet[512]; /* last inbound (icmp) packet */ static char *outpacket; /* last output packet */ @@ -304,6 +304,7 @@ int setpolicy(int so, char *policy); #endif void send_probe(int, u_long); void *get_uphdr(struct ip6_hdr *, u_char *); +void capdns_open(void); int get_hoplim(struct msghdr *); double deltaT(struct timeval *, struct timeval *); const char *pr_type(int); @@ -312,6 +313,8 @@ void print(struct msghdr *, int); 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); @@ -335,6 +338,8 @@ static struct cmsghdr *cmsg; static char *source = NULL; static char *hostname; +static cap_channel_t *capdns; + static u_long nprobes = 3; static u_long first_hop = 1; static u_long max_hops = 30; @@ -368,7 +373,10 @@ main(int argc, char *argv[]) char ipsec_inpolicy[] = "in bypass"; char ipsec_outpolicy[] = "out bypass"; #endif + cap_rights_t rights; + capdns_open(); + /* * Receive ICMP */ @@ -429,6 +437,7 @@ main(int argc, char *argv[]) } break; case 'g': + /* XXX use after capability mode is entered */ hp = getipnodebyname(optarg, AF_INET6, 0, &h_errno); if (hp == NULL) { fprintf(stderr, @@ -560,8 +569,8 @@ main(int argc, char *argv[]) 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; @@ -606,7 +615,9 @@ main(int argc, char *argv[]) hints.ai_socktype = SOCK_RAW; hints.ai_protocol = IPPROTO_ICMPV6; hints.ai_flags = AI_CANONNAME; - error = getaddrinfo(*argv, NULL, &hints, &res); + + error = cap_getaddrinfo(capdns, *argv, NULL, &hints, &res); + if (error) { fprintf(stderr, "traceroute6: %s\n", gai_strerror(error)); @@ -624,7 +635,7 @@ main(int argc, char *argv[]) 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 " @@ -803,7 +814,7 @@ main(int argc, char *argv[]) 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)); @@ -839,7 +850,7 @@ main(int argc, char *argv[]) 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); @@ -879,7 +890,7 @@ main(int argc, char *argv[]) /* * 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"); @@ -894,7 +905,31 @@ main(int argc, char *argv[]) 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 (caph_enter_casper() < 0) { + fprintf(stderr, "caph_enter_casper: %s\n", strerror(errno)); + exit(1); + } + + cap_rights_init(&rights, CAP_SEND, CAP_SETSOCKOPT); + if (caph_rights_limit(sndsock, &rights) < 0) { + fprintf(stderr, "caph_rights_limit sndsock: %s\n", + strerror(errno)); + exit(1); + } + + /* * Main loop */ for (hops = first_hop; hops <= max_hops; ++hops) { @@ -1038,6 +1073,7 @@ send_probe(int seq, u_long hops) { struct icmp6_hdr *icp; struct sctphdr *sctp; + struct udphdr *outudp; struct sctp_chunkhdr *chk; struct sctp_init_chunk *init; struct sctp_paramhdr *param; @@ -1063,6 +1099,11 @@ send_probe(int seq, u_long hops) 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. */ @@ -1149,12 +1190,11 @@ send_probe(int seq, u_long hops) 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); @@ -1266,7 +1306,7 @@ packet_ok(struct msghdr *mhdr, int cc, int seq, u_char 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, @@ -1279,7 +1319,7 @@ packet_ok(struct msghdr *mhdr, int cc, int seq, u_char #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); @@ -1345,7 +1385,7 @@ packet_ok(struct msghdr *mhdr, int cc, int seq, u_char 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; @@ -1401,7 +1441,7 @@ packet_ok(struct msghdr *mhdr, int cc, int seq, u_char 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, @@ -1475,12 +1515,33 @@ get_uphdr(struct ip6_hdr *ip6, u_char *lim) } void +capdns_open() +{ + const char *types[] = { "NAME", "ADDR" }; + int families[1]; + cap_channel_t *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, nitems(types)) < 0) + errx(1, "unable to limit access to system.dns service"); + families[0] = AF_INET6; + if (cap_dns_family_limit(capdns, families, nitems(families)) < 0) + errx(1, "unable to limit access to system.dns service"); + cap_close(casper); +} + +void print(struct msghdr *mhdr, int cc) { 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) @@ -1527,7 +1588,7 @@ inetname(struct sockaddr *sa) } 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)) @@ -1538,7 +1599,7 @@ inetname(struct sockaddr *sa) 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; @@ -1666,6 +1727,33 @@ in_cksum(u_int16_t *addr, int len) sum += (sum >> 16); /* add carry */ answer = ~sum; /* truncate to 16 bits */ 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