Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 6 Sep 2020 14:04:03 +0000 (UTC)
From:      Mariusz Zaborski <oshogbo@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r365378 - head/usr.sbin/traceroute6
Message-ID:  <202009061404.086E43HH024712@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 <shubh@freebsd.org>
  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 <src.opts.mk>
+
+.include <src.opts.mk>
+
 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 <bsd.prog.mk>
 

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 <sys/param.h>
+#include <sys/capsicum.h>
 #include <sys/time.h>
 #include <sys/socket.h>
 #include <sys/uio.h>
@@ -260,6 +261,10 @@ static const char rcsid[] =
 
 #include <arpa/inet.h>
 
+#include <libcasper.h>
+#include <casper/cap_dns.h>
+#include <capsicum_helpers.h>
+
 #include <netdb.h>
 #include <stdio.h>
 #include <err.h>
@@ -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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202009061404.086E43HH024712>