svn commit: r332237 - in stable/11: contrib/traceroute usr.sbin/traceroute6
Michael Tuexen
tuexen at FreeBSD.org
Sat Apr 7 20:44:31 UTC 2018
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;
More information about the svn-src-stable
mailing list