]> git.ipfire.org Git - thirdparty/mtr.git/commitdiff
Add SCTP support (same way with tcp)
authorswordfeng <swordfeng123@gmail.com>
Fri, 5 Jun 2015 12:16:29 +0000 (20:16 +0800)
committerswordfeng <swordfeng123@gmail.com>
Fri, 5 Jun 2015 12:16:29 +0000 (20:16 +0800)
mtr.c
net.c

diff --git a/mtr.c b/mtr.c
index 859e4f6f6ad562a25f927d3aba0ea8a678f4c676..a66d4ad7beeadf23265b531b88d0e9c70bfc22c6 100644 (file)
--- a/mtr.c
+++ b/mtr.c
@@ -303,6 +303,7 @@ void parse_arg (int argc, char **argv)
     { "max-ttl", 1, 0, 'm' },
     { "udp", 0, 0, 'u' },      /* UDP (default is ICMP) */
     { "tcp", 0, 0, 'T' },      /* TCP (default is ICMP) */
+    { "sctp", 0, 0, 'S' },     /* SCTP (default is ICMP) */
     { "port", 1, 0, 'P' },      /* target port number for TCP */
     { "timeout", 1, 0, 'Z' },   /* timeout for TCP sockets */
 #ifdef SO_MARK
@@ -314,7 +315,7 @@ void parse_arg (int argc, char **argv)
   opt = 0;
   while(1) {
     opt = getopt_long(argc, argv,
-                     "hv46F:rwxtglCpnbo:y:zi:c:s:B:Q:ea:f:m:uTP:Z:M:", long_options, NULL);
+                     "hv46F:rwxtglCpnbo:y:zi:c:s:B:Q:ea:f:m:uTSP:Z:M:", long_options, NULL);
     if(opt == -1)
       break;
 
@@ -435,18 +436,24 @@ void parse_arg (int argc, char **argv)
       break;
     case 'u':
       if (mtrtype != IPPROTO_ICMP) {
-        fprintf(stderr, "-u and -T are mutually exclusive.\n");
+        fprintf(stderr, "-u , -T and -S are mutually exclusive.\n");
         exit(EXIT_FAILURE);
       }
       mtrtype = IPPROTO_UDP;
       break;
     case 'T':
       if (mtrtype != IPPROTO_ICMP) {
-        fprintf(stderr, "-u and -T are mutually exclusive.\n");
+        fprintf(stderr, "-u , -T and -S are mutually exclusive.\n");
         exit(EXIT_FAILURE);
       }
       mtrtype = IPPROTO_TCP;
       break;
+    case 'S':
+      if (mtrtype != IPPROTO_ICMP) {
+        fprintf(stderr, "-u , -T and -S are mutually exclusive.\n");
+        exit(EXIT_FAILURE);
+      }
+      mtrtype = IPPROTO_SCTP;
     case 'b':
       show_ips = 1;
       break;
@@ -609,7 +616,7 @@ int main(int argc, char **argv)
               "\t\t[-i INTERVAL] [-c COUNT] [-s PACKETSIZE] [-B BITPATTERN]\n"
               "\t\t[-Q TOS] [--mpls]\n"
               "\t\t[-a ADDRESS] [-f FIRST-TTL] [-m MAX-TTL]\n"
-              "\t\t[--udp] [--tcp] [-P PORT] [-Z TIMEOUT]\n"
+              "\t\t[--udp] [--tcp] [--sctp] [-P PORT] [-Z TIMEOUT]\n"
               "\t\t[-M MARK] HOSTNAME\n", argv[0]);
        printf("See the man page for details.\n");
     exit(0);
diff --git a/net.c b/net.c
index 0ffffe9b9a2a091e997aa74829a9a7371ea0622d..9f1a95149149ca0faaca906476d118f4c61d1d95 100644 (file)
--- a/net.c
+++ b/net.c
@@ -70,6 +70,19 @@ struct TCPHeader {
   uint32 seq;
 };
 
+/* Structure of an SCTP header */
+struct SCTPHeader {
+  uint16 srcport;
+  uint16 dstport;
+  uint32 veri_tag;
+  uint32 checksum;
+  /*
+  uint8 chunk_type;
+  uint8 chunk_flag;
+  uint16 chunk_length;
+  * */
+};
+
 /* Structure of an IPv4 UDP pseudoheader.  */
 struct UDPv4PHeader {
   uint32 saddr;
@@ -414,6 +427,123 @@ void net_send_tcp(int index)
   connect(s, (struct sockaddr *) &remote, len);
 }
 
+/*  Attempt to connect to a SCTP port with a TTL */
+void net_send_sctp(int index)
+{
+  int ttl, s;
+  int opt = 1;
+  int port;
+  struct sockaddr_storage local;
+  struct sockaddr_storage remote;
+  struct sockaddr_in *local4 = (struct sockaddr_in *) &local;
+  struct sockaddr_in6 *local6 = (struct sockaddr_in6 *) &local;
+  struct sockaddr_in *remote4 = (struct sockaddr_in *) &remote;
+  struct sockaddr_in6 *remote6 = (struct sockaddr_in6 *) &remote;
+  socklen_t len;
+
+  ttl = index + 1;
+
+  s = socket(af, SOCK_STREAM, IPPROTO_SCTP);
+  if (s < 0) {
+    display_clear();
+    perror("socket()");
+    exit(EXIT_FAILURE);
+  }
+
+  memset(&local, 0, sizeof (local));
+  memset(&remote, 0, sizeof (remote));
+  local.ss_family = af;
+  remote.ss_family = af;
+
+  switch (af) {
+  case AF_INET:
+    addrcpy((void *) &local4->sin_addr, (void *) &ssa4->sin_addr, af);
+    addrcpy((void *) &remote4->sin_addr, (void *) remoteaddress, af);
+    remote4->sin_port = htons(remoteport);
+    len = sizeof (struct sockaddr_in);
+    break;
+#ifdef ENABLE_IPV6
+  case AF_INET6:
+    addrcpy((void *) &local6->sin6_addr, (void *) &ssa6->sin6_addr, af);
+    addrcpy((void *) &remote6->sin6_addr, (void *) remoteaddress, af);
+    remote6->sin6_port = htons(remoteport);
+    len = sizeof (struct sockaddr_in6);
+    break;
+#endif
+  }
+
+  if (bind(s, (struct sockaddr *) &local, len)) {
+    display_clear();
+    perror("bind()");
+    exit(EXIT_FAILURE);
+  }
+
+  if (getsockname(s, (struct sockaddr *) &local, &len)) {
+    display_clear();
+    perror("getsockname()");
+    exit(EXIT_FAILURE);
+  }
+
+  opt = 1;
+  if (ioctl(s, FIONBIO, &opt)) {
+    display_clear();
+    perror("ioctl FIONBIO");
+    exit(EXIT_FAILURE);
+  }
+
+  switch (af) {
+  case AF_INET:
+    if (setsockopt(s, IPPROTO_IP, IP_TTL, &ttl, sizeof (ttl))) {
+      display_clear();
+      perror("setsockopt IP_TTL");
+      exit(EXIT_FAILURE);
+    }
+    if (setsockopt(s, IPPROTO_IP, IP_TOS, &tos, sizeof (tos))) {
+      display_clear();
+      perror("setsockopt IP_TOS");
+      exit(EXIT_FAILURE);
+    }
+    break;
+#ifdef ENABLE_IPV6
+  case AF_INET6:
+    if (setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof (ttl))) {
+      display_clear();
+      perror("setsockopt IP_TTL");
+      exit(EXIT_FAILURE);
+    }
+    break;
+#endif
+  }
+
+#ifdef SO_MARK
+    if (mark >= 0 && setsockopt( s, SOL_SOCKET, SO_MARK, &mark, sizeof mark ) ) {
+      perror( "setsockopt SO_MARK" );
+      exit( EXIT_FAILURE );
+    }
+#endif
+
+  switch (local.ss_family) {
+  case AF_INET:
+    port = ntohs(local4->sin_port);
+    break;
+#ifdef ENABLE_IPV6
+  case AF_INET6:
+    port = ntohs(local6->sin6_port);
+    break;
+#endif
+  default:
+    display_clear();
+    perror("unknown AF?");
+    exit(EXIT_FAILURE);
+  }
+
+  save_sequence(index, port);
+  gettimeofday(&sequence[port].time, NULL);
+  sequence[port].socket = s;
+
+  connect(s, (struct sockaddr *) &remote, len);
+}
+
 /*  Attempt to find the host at a particular number of hops away  */
 void net_send_query(int index) 
 {
@@ -421,6 +551,11 @@ void net_send_query(int index)
     net_send_tcp(index);
     return;
   }
+  
+  if (mtrtype == IPPROTO_SCTP) {
+    net_send_sctp(index);
+    return;
+  }
 
   /*ok  char packet[sizeof(struct IPHeader) + sizeof(struct ICMPHeader)];*/
   char packet[MAXPACKET];
@@ -709,6 +844,7 @@ void net_process_return(void)
   struct ICMPHeader *header = NULL;
   struct UDPHeader *udpheader = NULL;
   struct TCPHeader *tcpheader = NULL;
+  struct SCTPHeader *sctpheader = NULL;
   struct timeval now;
   ip_t * fromaddress = NULL;
   int echoreplytype = 0, timeexceededtype = 0, unreachabletype = 0;
@@ -842,6 +978,43 @@ void net_process_return(void)
     break;
 
   case IPPROTO_TCP:
+    if (header->type == timeexceededtype || header->type == unreachabletype) {
+      switch ( af ) {
+      case AF_INET:
+
+        if ((size_t) num < sizeof(struct IPHeader) +
+                           sizeof(struct ICMPHeader) +
+                           sizeof (struct IPHeader) +
+                           sizeof (struct SCTPHeader))
+          return;
+        sctpheader = (struct SCTPHeader *)(packet + sizeof (struct IPHeader) +
+                                                  sizeof (struct ICMPHeader) +
+                                                  sizeof (struct IPHeader));
+
+        if(num > 160)
+          decodempls(num, packet, &mpls, 156);
+
+      break;
+#ifdef ENABLE_IPV6
+      case AF_INET6:
+        if ( num < sizeof (struct ICMPHeader) +
+                   sizeof (struct ip6_hdr) + sizeof (struct SCTPHeader) )
+          return;
+        sctpheader = (struct SCTPHeader *) ( packet +
+                                           sizeof (struct ICMPHeader) +
+                                           sizeof (struct ip6_hdr) );
+
+        if(num > 140)
+          decodempls(num, packet, &mpls, 136);
+
+        break;
+#endif
+      }
+      sequence = ntohs(tcpheader->srcport);
+    }
+    break;
+    
+  case IPPROTO_SCTP:
     if (header->type == timeexceededtype || header->type == unreachabletype) {
       switch ( af ) {
       case AF_INET: