summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
authortuexen <tuexen@FreeBSD.org>2018-04-07 20:44:30 +0000
committertuexen <tuexen@FreeBSD.org>2018-04-07 20:44:30 +0000
commitcb2ec2b4dc297a836eb58c6b4386a6a906eaacbb (patch)
treedd9cf49aacc2b28e94e89cbfd091f3e547474ba9 /usr.sbin
parent4d97f549585f62fa20946417217e2a6657b0f413 (diff)
downloadFreeBSD-src-cb2ec2b4dc297a836eb58c6b4386a6a906eaacbb.zip
FreeBSD-src-cb2ec2b4dc297a836eb58c6b4386a6a906eaacbb.tar.gz
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.
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/traceroute6/traceroute6.87
-rw-r--r--usr.sbin/traceroute6/traceroute6.c112
2 files changed, 98 insertions, 21 deletions
diff --git a/usr.sbin/traceroute6/traceroute6.8 b/usr.sbin/traceroute6/traceroute6.8
index 4aa5155..84aa263 100644
--- a/usr.sbin/traceroute6/traceroute6.8
+++ b/usr.sbin/traceroute6/traceroute6.8
@@ -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
diff --git a/usr.sbin/traceroute6/traceroute6.c b/usr.sbin/traceroute6/traceroute6.c
index 0bcf7c4..61c93d1 100644
--- a/usr.sbin/traceroute6/traceroute6.c
+++ b/usr.sbin/traceroute6/traceroute6.c
@@ -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;
OpenPOWER on IntegriCloud