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 <sh...@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
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to