Author: tuexen
Date: Sat Apr  7 20:44:30 2018
New Revision: 332237
URL: https://svnweb.freebsd.org/changeset/base/332237

Log:
  MFC r328488:
  
  When using SCTP for sending probe packets, use INIT chunks for payloads
  larger than or equal to 32 bytes. For smaller probe packets, keep using
  SHUTDOWN-ACK chunks, possibly bundled with a PAD chunk.
  Packets with INIT chunks more likely pass through firewalls. Therefore,
  use them when possible.

Modified:
  stable/11/contrib/traceroute/traceroute.c
  stable/11/usr.sbin/traceroute6/traceroute6.8
  stable/11/usr.sbin/traceroute6/traceroute6.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/contrib/traceroute/traceroute.c
==============================================================================
--- stable/11/contrib/traceroute/traceroute.c   Sat Apr  7 20:42:06 2018        
(r332236)
+++ stable/11/contrib/traceroute/traceroute.c   Sat Apr  7 20:44:30 2018        
(r332237)
@@ -220,6 +220,7 @@ static const char rcsid[] =
 #include <netinet/ip_var.h>
 #include <netinet/ip_icmp.h>
 #include <netinet/sctp.h>
+#include <netinet/sctp_header.h>
 #include <netinet/udp.h>
 #include <netinet/tcp.h>
 #include <netinet/tcpip.h>
@@ -1489,26 +1490,71 @@ sctp_prep(struct outdata *outdata)
 {
        struct sctphdr *const sctp = (struct sctphdr *) outp;
        struct sctp_chunkhdr *chk;
+       struct sctp_init_chunk *init;
+       struct sctp_paramhdr *param;
 
        sctp->src_port = htons(ident);
        sctp->dest_port = htons(port + (fixedPort ? 0 : outdata->seq));
-       sctp->v_tag = (sctp->src_port << 16) | sctp->dest_port;
+       if (protlen >= (int)(sizeof(struct sctphdr) +
+           sizeof(struct sctp_init_chunk))) {
+               sctp->v_tag = 0;
+       } else {
+               sctp->v_tag = (sctp->src_port << 16) | sctp->dest_port;
+       }
        sctp->checksum = htonl(0);
-       if (protlen >=
-           (int)(sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr))) {
-               chk = (struct sctp_chunkhdr *)(sctp + 1);
-               chk->chunk_type = SCTP_SHUTDOWN_ACK;
-               chk->chunk_flags = 0;
-               chk->chunk_length = htons(4);
+       if (protlen >= (int)(sizeof(struct sctphdr) +
+           sizeof(struct sctp_init_chunk))) {
+               /*
+                * Send a packet containing an INIT chunk. This works
+                * better in case of firewalls on the path, but
+                * results in a probe packet containing at least
+                * 32 bytes of payload. For shorter payloads, use
+                * SHUTDOWN-ACK chunks.
+                */
+               init = (struct sctp_init_chunk *)(sctp + 1);
+               init->ch.chunk_type = SCTP_INITIATION;
+               init->ch.chunk_flags = 0;
+               init->ch.chunk_length = htons((u_int16_t)(protlen -
+                   sizeof(struct sctphdr)));
+               init->init.initiate_tag = (sctp->src_port << 16) |
+                   sctp->dest_port;
+               init->init.a_rwnd = htonl(1500);
+               init->init.num_outbound_streams = htons(1);
+               init->init.num_inbound_streams = htons(1);
+               init->init.initial_tsn = htonl(0);
+               if (protlen >= (int)(sizeof(struct sctphdr) +
+                   sizeof(struct sctp_init_chunk) +
+                   sizeof(struct sctp_paramhdr))) {
+                       param = (struct sctp_paramhdr *)(init + 1);
+                       param->param_type = htons(SCTP_PAD);
+                       param->param_length =
+                           htons((u_int16_t)(protlen -
+                           sizeof(struct sctphdr) -
+                           sizeof(struct sctp_init_chunk)));
+               }
+       } else {
+               /*
+                * Send a packet containing a SHUTDOWN-ACK chunk,
+                * possibly followed by a PAD chunk.
+                */
+               if (protlen >=
+                   (int)(sizeof(struct sctphdr) +
+                   sizeof(struct sctp_chunkhdr))) {
+                       chk = (struct sctp_chunkhdr *)(sctp + 1);
+                       chk->chunk_type = SCTP_SHUTDOWN_ACK;
+                       chk->chunk_flags = 0;
+                       chk->chunk_length = htons(4);
+               }
+               if (protlen >=
+                   (int)(sizeof(struct sctphdr) +
+                   2 * sizeof(struct sctp_chunkhdr))) {
+                       chk = chk + 1;
+                       chk->chunk_type = SCTP_PAD_CHUNK;
+                       chk->chunk_flags = 0;
+                       chk->chunk_length = htons(protlen -
+                           (sizeof(struct sctphdr) + sizeof(struct 
sctp_chunkhdr)));
+               }
        }
-       if (protlen >=
-           (int)(sizeof(struct sctphdr) + 2 * sizeof(struct sctp_chunkhdr))) {
-               chk = chk + 1;
-               chk->chunk_type = SCTP_PAD_CHUNK;
-               chk->chunk_flags = 0;
-               chk->chunk_length = htons(protlen -
-                   (sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr)));
-       }
        if (doipcksum) {
                sctp->checksum = sctp_crc32c(sctp, protlen);
        }
@@ -1519,10 +1565,20 @@ sctp_check(const u_char *data, int seq)
 {
        struct sctphdr *const sctp = (struct sctphdr *) data;
 
-       return (ntohs(sctp->src_port) == ident
-           && ntohs(sctp->dest_port) == port + (fixedPort ? 0 : seq)
-           && sctp->v_tag ==
-           (u_int32_t)((sctp->src_port << 16) | sctp->dest_port));
+       if (ntohs(sctp->src_port) != ident ||
+           ntohs(sctp->dest_port) != port + (fixedPort ? 0 : seq))
+               return (0);
+       if (protlen < (int)(sizeof(struct sctphdr) +
+           sizeof(struct sctp_init_chunk))) {
+               return (sctp->v_tag ==
+                   (u_int32_t)((sctp->src_port << 16) | sctp->dest_port));
+       } else {
+               /*
+                * Don't verify the initiate_tag, since it is not available,
+                * most of the time.
+                */
+               return (sctp->v_tag == 0);
+       }
 }
 
 void

Modified: stable/11/usr.sbin/traceroute6/traceroute6.8
==============================================================================
--- stable/11/usr.sbin/traceroute6/traceroute6.8        Sat Apr  7 20:42:06 
2018        (r332236)
+++ stable/11/usr.sbin/traceroute6/traceroute6.8        Sat Apr  7 20:44:30 
2018        (r332237)
@@ -29,7 +29,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd September 30, 2017
+.Dd January 27, 2018
 .Dt TRACEROUTE6 8
 .Os
 .\"
@@ -140,6 +140,11 @@ that has no route through it
 specifies the source IPv6 address to be used.
 .It Fl S
 Use SCTP packets for the probes.
+The size of probe packets must be a multiple of 4.
+If
+.Ar datalen
+is up to 28, probe packets consist of a SHUTDOWN-ACK chunk possibly bundled
+with a PAD chunk. For larger probe packets, an INIT chunk is used.
 .It Fl T
 Use TCP segments for the probes.
 .It Fl U

Modified: stable/11/usr.sbin/traceroute6/traceroute6.c
==============================================================================
--- stable/11/usr.sbin/traceroute6/traceroute6.c        Sat Apr  7 20:42:06 
2018        (r332236)
+++ stable/11/usr.sbin/traceroute6/traceroute6.c        Sat Apr  7 20:44:30 
2018        (r332237)
@@ -272,6 +272,7 @@ static const char rcsid[] =
 #include <netinet/ip6.h>
 #include <netinet/icmp6.h>
 #include <netinet/sctp.h>
+#include <netinet/sctp_header.h>
 #include <netinet/tcp.h>
 #include <netinet/udp.h>
 
@@ -676,6 +677,11 @@ main(int argc, char *argv[])
        }
        if (useproto == IPPROTO_UDP)
                datalen -= sizeof(struct udphdr);
+       if ((useproto == IPPROTO_SCTP) && (datalen & 3)) {
+               fprintf(stderr, 
+                   "traceroute6: packet size must be a multiple of 4.\n");
+               exit(1);
+       }
        outpacket = malloc(datalen);
        if (!outpacket) {
                perror("malloc");
@@ -1049,6 +1055,8 @@ send_probe(int seq, u_long hops)
        struct icmp6_hdr *icp;
        struct sctphdr *sctp;
        struct sctp_chunkhdr *chk;
+       struct sctp_init_chunk *init;
+       struct sctp_paramhdr *param;
        struct tcphdr *tcp;
        int i;
 
@@ -1080,23 +1088,64 @@ send_probe(int seq, u_long hops)
 
                sctp->src_port = htons(ident);
                sctp->dest_port = htons(port + seq);
-               sctp->v_tag = (sctp->src_port << 16) | sctp->dest_port;
-               sctp->checksum = htonl(0);
                if (datalen >= (u_long)(sizeof(struct sctphdr) +
-                   sizeof(struct sctp_chunkhdr))) {
-                       chk = (struct sctp_chunkhdr *)(sctp + 1);
-                       chk->chunk_type = SCTP_SHUTDOWN_ACK;
-                       chk->chunk_flags = 0;
-                       chk->chunk_length = htons(4);
+                   sizeof(struct sctp_init_chunk))) {
+                       sctp->v_tag = 0;
+               } else {
+                       sctp->v_tag = (sctp->src_port << 16) | sctp->dest_port;
                }
+               sctp->checksum = htonl(0);
                if (datalen >= (u_long)(sizeof(struct sctphdr) +
-                   2 * sizeof(struct sctp_chunkhdr))) {
-                       chk = chk + 1;
-                       chk->chunk_type = SCTP_PAD_CHUNK;
-                       chk->chunk_flags = 0;
-                       chk->chunk_length = htons((u_int16_t)(datalen -
-                           sizeof(struct sctphdr) -
-                           sizeof(struct sctp_chunkhdr)));
+                   sizeof(struct sctp_init_chunk))) {
+                       /*
+                        * Send a packet containing an INIT chunk. This works
+                        * better in case of firewalls on the path, but
+                        * results in a probe packet containing at least
+                        * 32 bytes of payload. For shorter payloads, use
+                        * SHUTDOWN-ACK chunks.
+                        */
+                       init = (struct sctp_init_chunk *)(sctp + 1);
+                       init->ch.chunk_type = SCTP_INITIATION;
+                       init->ch.chunk_flags = 0;
+                       init->ch.chunk_length = htons((u_int16_t)(datalen -
+                           sizeof(struct sctphdr)));
+                       init->init.initiate_tag = (sctp->src_port << 16) |
+                           sctp->dest_port;
+                       init->init.a_rwnd = htonl(1500);
+                       init->init.num_outbound_streams = htons(1);
+                       init->init.num_inbound_streams = htons(1);
+                       init->init.initial_tsn = htonl(0);
+                       if (datalen >= (u_long)(sizeof(struct sctphdr) +
+                           sizeof(struct sctp_init_chunk) +
+                           sizeof(struct sctp_paramhdr))) {
+                               param = (struct sctp_paramhdr *)(init + 1);
+                               param->param_type = htons(SCTP_PAD);
+                               param->param_length =
+                                   htons((u_int16_t)(datalen -
+                                   sizeof(struct sctphdr) -
+                                   sizeof(struct sctp_init_chunk)));
+                       }
+               } else {
+                       /*
+                        * Send a packet containing a SHUTDOWN-ACK chunk,
+                        * possibly followed by a PAD chunk.
+                        */
+                       if (datalen >= (u_long)(sizeof(struct sctphdr) +
+                           sizeof(struct sctp_chunkhdr))) {
+                               chk = (struct sctp_chunkhdr *)(sctp + 1);
+                               chk->chunk_type = SCTP_SHUTDOWN_ACK;
+                               chk->chunk_flags = 0;
+                               chk->chunk_length = htons(4);
+                       }
+                       if (datalen >= (u_long)(sizeof(struct sctphdr) +
+                           2 * sizeof(struct sctp_chunkhdr))) {
+                               chk = chk + 1;
+                               chk->chunk_type = SCTP_PAD_CHUNK;
+                               chk->chunk_flags = 0;
+                               chk->chunk_length = htons((u_int16_t)(datalen -
+                                   sizeof(struct sctphdr) -
+                                   sizeof(struct sctp_chunkhdr)));
+                       }
                }
                sctp->checksum = sctp_crc32c(outpacket, datalen);
                break;
@@ -1289,6 +1338,7 @@ packet_ok(struct msghdr *mhdr, int cc, int seq)
            || type == ICMP6_DST_UNREACH) {
                struct ip6_hdr *hip;
                struct icmp6_hdr *icmp;
+               struct sctp_init_chunk *init;
                struct sctphdr *sctp;
                struct tcphdr *tcp;
                struct udphdr *udp;
@@ -1317,12 +1367,34 @@ packet_ok(struct msghdr *mhdr, int cc, int seq)
                        break;
                case IPPROTO_SCTP:
                        sctp = (struct sctphdr *)up;
-                       if (sctp->src_port == htons(ident) &&
-                           sctp->dest_port == htons(port + seq) &&
-                           sctp->v_tag ==
-                           (u_int32_t)((sctp->src_port << 16) | 
sctp->dest_port))
-                               return (type == ICMP6_TIME_EXCEEDED ?
-                                   -1 : code + 1);
+                       if (sctp->src_port != htons(ident) ||
+                           sctp->dest_port != htons(port + seq)) {
+                               break;
+                       }
+                       if (datalen >= (u_long)(sizeof(struct sctphdr) +
+                           sizeof(struct sctp_init_chunk))) {
+                               if (sctp->v_tag != 0) {
+                                       break;
+                               }
+                               init = (struct sctp_init_chunk *)(sctp + 1);
+                               /* Check the initiate tag, if available. */
+                               if ((char *)&init->init.a_rwnd > buf + cc) {
+                                       return (type == ICMP6_TIME_EXCEEDED ?
+                                           -1 : code + 1);
+                               }
+                               if (init->init.initiate_tag == (u_int32_t)
+                                   ((sctp->src_port << 16) | sctp->dest_port)) 
{
+                                       return (type == ICMP6_TIME_EXCEEDED ?
+                                           -1 : code + 1);
+                               }
+                       } else {
+                               if (sctp->v_tag ==
+                                   (u_int32_t)((sctp->src_port << 16) |
+                                   sctp->dest_port)) {
+                                       return (type == ICMP6_TIME_EXCEEDED ?
+                                           -1 : code + 1);
+                               }
+                       }
                        break;
                case IPPROTO_TCP:
                        tcp = (struct tcphdr *)up;
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to