Package: iputils-tracepath
Version: 3:20020927-3
Severity: wishlist
Tags: patch

-> [EMAIL PROTECTED]  [patch] tracepath source port sweep
Dear maintainer,

The tracepath utility employs a destination port sweep to match a received 
ICMP packet to the sent UDP probe.  This trick recovers the probe TTL
even when the received ICMP carries a zero payload.  However, this also 
breaks the trace when a port filtering firewall is encountered.  

The patch below allows for a fixed destination port.  The code then 
creates multiple sockets to send each probe from a different source 
port.  Thus, the probe TTL follows from the file descriptor on which the 
ICMP packet is received.  

Both matching methods use a sequence/history table consisting of the 
4-tuple entries ( fd, destination port, (probe ttl, timeval) ).  The
first two fields are initialized once, in main(), and the next two upon 
probe transmission.

The extended argument syntax is:

tracepath 195.162.203.238 [base]
  source port: one random free port
  target port: incrementing: base, base+1, ...

tracepath [-b saddr] 195.162.203.238/53 
  source address: bind()'ed to saddr
  source port: multiple random free ports using 64 file descriptors
  target port: fixed, here at 53

tracepath -b saddr/sport 195.162.203.238[/base]
  source: bind()'ed to saddr and sport
  target port: incrementing: base, base+1, ...

The default destination base port is 44444.  The diff below is towards 
the original iputils-ss020927 but includes the bug#305062 
gethostbyname2() patch.  If required, I am willing to further clarify 
the proposed code. 

Yours sincerely
------------------------------------------------------------------------------
stargate:~$ uname -a
Linux stargate 2.4.23 #27 Mon Mar 22 23:09:25 CET 2004 i686 unknown
stargate:~$ tracepath 134.58.127.1/53
 1?: [LOCALHOST] (0.0.0.0)                                pmtu 1500
 1:  10.89.239.252 (10.89.239.252)                          9.365ms (0) 
 2:  be-bru-rr-01-fe-1-0-0.chello.be (195.162.196.182)      7.964ms (0) 
 3:  GW-kuleuven.customer.tvd.be (195.162.203.238)         16.407ms (0) 
 4:  bones1.kuleuven.net (134.58.253.58)                   10.922ms 
 5:  cisco-kulnet.kuleuven.ac.be (134.58.254.62)           10.069ms (0) 
 6:  lrswitch-ludit-srv-1.kuleuven.ac.be (134.58.255.13)    9.840ms (0) 
 7:  reply received from 134.58.127.1/53                   10.021ms (12)
     Resume: pmtu 1500 

reddwarf:~$ uname -a
Linux reddwarf 2.6.16.1 #2 Wed Mar 29 03:38:43 CEST 2006 i686 unknown unknown 
GNU/Linux
reddwarf:~$ tracepath 134.58.127.1/53
 1:  reddwarf.picaros.org (172.24.105.1)                    0.142ms pmtu 1500
 1:  stargate.picaros.org (172.24.105.14)                   1.058ms 
 2:  10.89.239.252 (10.89.239.252)                          9.468ms (0) 
 3:  be-bru-rr-01-fe-1-0-0.chello.be (195.162.196.182)      9.302ms (0) 
 4:  GW-kuleuven.customer.tvd.be (195.162.203.238)          9.889ms (0) 
 5:  bones1.kuleuven.net (134.58.253.58)                    9.132ms 
 6:  cisco-kulnet.kuleuven.ac.be (134.58.254.62)            9.371ms (0) 
 7:  lrswitch-ludit-srv-1.kuleuven.ac.be (134.58.255.13)   12.850ms (0) 
 8:  reply received from 134.58.127.1/53                   10.261ms (12)
     Resume: pmtu 1500 
------------------------------------------------------------------------------
Sat 16 Sep 2006 23:10:26 +0200 (CEST)
--- iputils-ss020927/tracepath-dist.c   2002-02-23 01:10:59.000000000 +0100
+++ iputils-ss020927/tracepath.c        2006-07-30 04:21:25.000000000 +0200
@@ -23,42 +23,81 @@
 #include <sys/uio.h>
 #include <arpa/inet.h>
 
-struct hhistory
-{
-       int     hops;
-       struct timeval sendtime;
+struct probehdr {
+       __u32 ttl;
+       struct timeval tv;
 };
 
-struct hhistory his[64];
-int hisptr;
+struct hhistory {
+  int ptr, size;
+  int *fd;
+  unsigned *port;
+  struct probehdr *hdr;
+};
 
-struct sockaddr_in target;
-__u16 base_port;
+struct hopsinfo {
+  int to, from;
+};
 
-const int overhead = 28;
-int mtu = 65535;
-int hops_to = -1;
-int hops_from = -1;
-int no_resolve = 0;
+const static int overhead=28, maxttl=255;
 
-struct probehdr
-{
-       __u32 ttl;
-       struct timeval tv;
-};
+/* in:  hptr    the slot just used to send a probe packet
+ *      toport  target port of the packet returned as ICMP payload
+ *
+ * out: slot number in history list
+ */
+int his_slot(int hptr, unsigned toport, struct hhistory *his) {
+  int ret=-1;
+
+  if(his->port[hptr]==toport) {
+    ret=hptr;
+    /* printf("** hit hptr=%i toport=%u\n", hptr, toport); */
+  } else {
+    int i;
+    int hfd=his->fd[hptr];
 
-void data_wait(int fd)
-{
+    i=hptr+1;
+    if(i>=his->size) i=0;
+
+    for(; i!=hptr; ) {
+      if(his->fd[i]==hfd && his->port[i]==toport) {
+       ret=i;
+       break;
+      }
+      i++;
+      if(i>=his->size) i=0;
+    }
+    /* printf("** nor hptr=%i toport=%u ret=%i\n", hptr, toport, ret); */
+  }
+
+  return ret;
+}
+
+int data_wait(struct hhistory *his) {
+  int err=0;
        fd_set fds;
        struct timeval tv;
+  int i, maxfd=-1, lastfd=-2;
+
        FD_ZERO(&fds);
+
+  for(i=0; i<his->size; i++) {
+    int fd=his->fd[i];                                    
+
+    if(fd>=0 && fd!=lastfd) {
+      lastfd=fd;
        FD_SET(fd, &fds);
+    }
+    if(maxfd<fd) maxfd=fd;
+  }
        tv.tv_sec = 1;
-       tv.tv_usec = 0;
-       select(fd+1, &fds, NULL, NULL, &tv);
+  tv.tv_usec = 10000;     /* ARP timeout is 3s */
+  err=select(maxfd+1, &fds, NULL, NULL, &tv);
+
+  return err;
 }
 
-int recverr(int fd, int ttl)
+int recv_err(int hptr, int ttl, int no_resolve, int *mtu, struct hhistory 
*his, struct hopsinfo *hops)
 {
        int res;
        struct probehdr rcvbuf;
@@ -70,14 +109,12 @@ int recverr(int fd, int ttl)
        struct sockaddr_in addr;
        struct timeval tv;
        struct timeval *rettv;
-       int slot;
-       int rethops;
-       int sndhops;
+       int fd=his->fd[hptr];
+       int slot, rethops, sndhops, broken_router;
        int progress = -1;
-       int broken_router;
        
 restart:
-       memset(&rcvbuf, -1, sizeof(rcvbuf));
+       memset(&rcvbuf, 0, sizeof(rcvbuf));
        iov.iov_base = &rcvbuf;
        iov.iov_len = sizeof(rcvbuf);
        msg.msg_name = (__u8*)&addr;
@@ -91,32 +128,36 @@ restart:
        gettimeofday(&tv, NULL);
        res = recvmsg(fd, &msg, MSG_ERRQUEUE);
        if (res < 0) {
-               if (errno == EAGAIN)
+               if (errno == EAGAIN || errno == EBADF || errno == ENOTSOCK 
+                   || errno == EINVAL)
                        return progress;
                goto restart;
        }
 
-       progress = mtu;
+       progress = *mtu;
 
        rethops = -1;
        sndhops = -1;
        e = NULL;
        rettv = NULL;
-       slot = ntohs(addr.sin_port) - base_port;
-       if (slot>=0 && slot < 63 && his[slot].hops) {
-               sndhops = his[slot].hops;
-               rettv = &his[slot].sendtime;
-               his[slot].hops = 0;
+       slot = his_slot(hptr, ntohs(addr.sin_port), his);
+       /* slot = ntohs(addr.sin_port) - base_port; */
+       if (slot>=0 && slot<his->size && his->hdr[slot].ttl) {
+               sndhops = his->hdr[slot].ttl;
+               rettv = &his->hdr[slot].tv;
+               his->hdr[slot].ttl = 0;
        }
        broken_router = 0;
        if (res == sizeof(rcvbuf)) {
-               if (rcvbuf.ttl == 0 || rcvbuf.tv.tv_sec == 0) {
+               if (rcvbuf.ttl==0 || rcvbuf.ttl>maxttl 
+                   || rcvbuf.tv.tv_sec==0) {
                        broken_router = 1;
                } else {
                        sndhops = rcvbuf.ttl;
                        rettv = &rcvbuf.tv;
                }
-       }
+       } else
+         broken_router = -1;
 
        for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
                if (cmsg->cmsg_level == SOL_IP) {
@@ -134,30 +175,50 @@ restart:
                return 0;
        }
        if (e->ee_origin == SO_EE_ORIGIN_LOCAL) {
-               printf("%2d?: %-15s ", ttl, "[LOCALHOST]");
+         char lobuf[]="[LOCALHOST]";
+         if(no_resolve) {
+           printf("%2d?: %-15s ", ttl, lobuf);
+         } else {
+           char abuf[128]="", fabuf[256];
+           struct sockaddr_in loin;
+           int lolen=sizeof(loin);
+
+           if(getsockname(fd, &loin, &lolen)<0) /* returns bind()'ed addr */
+             snprintf(abuf, sizeof(abuf), "getsockname: %i", errno);
+           else 
+             inet_ntop(loin.sin_family,&loin.sin_addr, abuf, sizeof(abuf));
+
+           snprintf(fabuf, sizeof(fabuf), "%s (%s)", lobuf, abuf);
+           printf("%2d?: %-52s ", ttl, fabuf);
+         }
        } else if (e->ee_origin == SO_EE_ORIGIN_ICMP) {
-               char abuf[128];
+               char abuf[128]="";
                struct sockaddr_in *sin = (struct sockaddr_in*)(e+1);
 
-               inet_ntop(AF_INET, &sin->sin_addr, abuf, sizeof(abuf));
+               inet_ntop(sin->sin_family,&sin->sin_addr, abuf, sizeof(abuf));
 
                if (sndhops>0)
                        printf("%2d:  ", sndhops);
                else
                        printf("%2d?: ", ttl);
 
-               if(!no_resolve) {
+               if(no_resolve) {
+                       printf("%-15s ", abuf);
+               } else {
                        char fabuf[256];
                        struct hostent *h;
                        fflush(stdout);
                        h = gethostbyaddr((char *) &sin->sin_addr, 
sizeof(sin->sin_addr), AF_INET);
                        snprintf(fabuf, sizeof(fabuf), "%s (%s)", h ? h->h_name 
: abuf, abuf);
                        printf("%-52s ", fabuf);
-               } else {
-                       printf("%-15s ", abuf);
                }
        }
 
+       if (rettv) {
+               int diff = 
(tv.tv_sec-rettv->tv_sec)*1000000+(tv.tv_usec-rettv->tv_usec);
+               printf("%3d.%03dms ", diff/1000, diff%1000);
+       }
+
        if (rethops>=0) {
                if (rethops<=64)
                        rethops = 65-rethops;
@@ -166,16 +227,16 @@ restart:
                else
                        rethops = 256-rethops;
                if (sndhops>=0 && rethops != sndhops)
-                       printf("asymm %2d ", rethops);
+                       printf("asym %2d ", rethops);
                else if (sndhops<0 && rethops != ttl)
-                       printf("asymm %2d ", rethops);
+                       printf("asym %2d ", rethops);
        }
 
        if (rettv) {
-               int diff = 
(tv.tv_sec-rettv->tv_sec)*1000000+(tv.tv_usec-rettv->tv_usec);
-               printf("%3d.%03dms ", diff/1000, diff%1000);
-               if (broken_router)
+               if (broken_router>0)
                        printf("(This broken router returned corrupted payload) 
");
+               else if(broken_router<0)
+                 printf("(%i) ",res);
        }
 
        switch (e->ee_errno) {
@@ -184,13 +245,12 @@ restart:
                break;
        case EMSGSIZE:
                printf("pmtu %d\n", e->ee_info);
-               mtu = e->ee_info;
-               progress = mtu;
+               progress = *mtu = e->ee_info;
                break;
        case ECONNREFUSED:
                printf("reached\n");
-               hops_to = sndhops<0 ? ttl : sndhops;
-               hops_from = rethops;
+               hops->to = sndhops<0 ? ttl : sndhops;
+               hops->from = rethops;
                return 0;
        case EPROTO:
                printf("!P\n");
@@ -203,6 +263,10 @@ restart:
                        break;
                }
                printf("!H\n");
+               /* Uncomment below to see repeat packets */
+               /*progress=0;
+                *break; 
+                */
                return 0;
        case ENETUNREACH:
                printf("!N\n");
@@ -219,70 +283,232 @@ restart:
        goto restart;
 }
 
-int probe_ttl(int fd, int ttl)
-{
-       int i;
-       char sndbuf[mtu];
-       struct probehdr *hdr = (struct probehdr*)sndbuf;
+/* Check for a replied probe.  The reported time is only correct if the target 
+ * host replied using the probed port e.g. dns at port 53. 
+ */
+int recv_reply(int hptr, int ttl, int no_resolve, int mtu, struct hhistory 
*his) { 
+  int al= (mtu<1500 ? 1500 : mtu)-overhead;
+  char buf[al];
+  struct timeval tv;
+  struct sockaddr_in from;
+  int flen=sizeof(from);
+  int fd=his->fd[hptr];
+  int cnt;
 
-       memset(sndbuf,0,mtu);
+  gettimeofday(&tv, NULL);
+  memset(&from, 0, sizeof(from));
 
-restart:
-       for (i=0; i<10; i++) {
-               int res;
+  cnt=recvfrom(fd, buf, sizeof(buf), MSG_DONTWAIT, &from, &flen);
+  if(cnt >= 0) {
+    char abuf[128]="", tbuf[16], xbuf[256];
+    unsigned port;
+    struct timeval *rettv=NULL;
+    int slot, sndhops=-1;
+
+    port=(unsigned )ntohs(from.sin_port);
+    slot=his_slot(hptr, port, his);
+
+    if(slot>=0 && slot<his->size && his->hdr[slot].ttl) {
+      sndhops = his->hdr[slot].ttl;
+      rettv = &his->hdr[slot].tv;
+      /* his->hdr[slot].ttl = 0; */
+      snprintf(tbuf,sizeof(tbuf), "%2d: ", sndhops);
+    } else {
+      snprintf(tbuf,sizeof(tbuf), "%2d?:", ttl);
+    }
+
+    inet_ntop(from.sin_family, &from.sin_addr, abuf, sizeof(abuf));
+    snprintf(xbuf,sizeof(xbuf), "reply received from %s/%u", abuf,port);
+
+    if(no_resolve)
+      printf("%s %-15s ", tbuf, xbuf);
+    else 
+      printf("%s %-52s ", tbuf, xbuf);
+
+    if (rettv) {
+      int diff = (tv.tv_sec-rettv->tv_sec)*1000000+(tv.tv_usec-rettv->tv_usec);
+      printf("%3d.%03dms ", diff/1000, diff%1000);
+    }
+    
+    printf("(%i)\n",cnt);
+  }
 
-               hdr->ttl = ttl;
-               target.sin_port = htons(base_port + hisptr);
+  return cnt;
+}
+
+int probe_ttl(struct sockaddr_in *target, int ttl, int no_resolve, int *mtu, 
struct hhistory *his, struct hopsinfo *hops)
+{
+       int err=-1;
+       int nal= *mtu<sizeof(struct probehdr) ? sizeof(struct probehdr):*mtu;
+       char sndbuf[nal];
+       struct probehdr *hdr = (struct probehdr *)sndbuf;
+       int hptr, hfd;
+       int m, i, res=0;
+
+       hptr=his->ptr;
+       hfd=his->fd[hptr];
+       target->sin_port= htons((__u16)his->port[hptr]);
+       memset(sndbuf,0, nal);
+       hdr->ttl= ttl;
+
+       for (i=0; i<256; i++) {  /* max 256 local mtu changes supported */
                gettimeofday(&hdr->tv, NULL);
-               his[hisptr].hops = ttl;
-               his[hisptr].sendtime = hdr->tv;
-               if (sendto(fd, sndbuf, mtu-overhead, 0, (struct 
sockaddr*)&target, sizeof(target)) > 0)
+               his->hdr[hptr]= *hdr;
+               if (sendto(hfd, sndbuf, *mtu-overhead, 0, 
+                          (struct sockaddr*)target, sizeof(*target)) >= 0)
                        break;
-               res = recverr(fd, ttl);
-               his[hisptr].hops = 0;
+
+               res = recv_err(hptr, ttl, no_resolve, mtu, his, hops);
+               his->hdr[hptr].ttl = 0;
                if (res==0)
                        return 0;
-               if (res > 0)
-                       goto restart;
+               if (res<0)      /* no error info in queue */
+                       i+=25;
        }
-       hisptr = (hisptr + 1)&63;
-
-       if (i<10) {
-               data_wait(fd);
-               if (recv(fd, sndbuf, sizeof(sndbuf), MSG_DONTWAIT) > 0) {
-                       printf("%2d?: reply received 8)\n", ttl);
+       if(i>=256) { 
+         char abuf[128]="";
+         inet_ntop(target->sin_family, &target->sin_addr, abuf, sizeof(abuf));
+         printf("%2d:  send failed dest %s/%u\n", ttl, abuf, 
+                (unsigned )ntohs(target->sin_port));
                        return 0;
                }
-               return recverr(fd, ttl);
+
+       /* packet is sent */
+       his->ptr++;
+       if(his->ptr>=his->size) his->ptr=0;
+
+       data_wait(his);
+
+       /* perhaps cache gettimeofday() ? */
+       m=*mtu;
+       for(i=his->ptr; i!=hptr; ) { /* other sockets for late packets */
+         int fd=his->fd[i];
+
+         if(fd != hfd) {
+           int r;
+
+           r=recv_reply(i, ttl, no_resolve, m, his);
+           if(r>=0) 
+             err=0;
+
+           r=recv_err(i, ttl, no_resolve, mtu, his, hops);
+           if(r>0 && *mtu!=m) /* remote mtu change */
+             err=-2;
+           else if(r>=0)
+             err=r;
        }
 
-       printf("%2d:  send failed\n", ttl);
-       return 0;
-}
+         i++;
+         if(i>=his->size) i=0;
+       }
+
+       res=recv_reply(hptr, ttl, no_resolve, m, his);
+       if(res>=0) 
+         err=0;
 
-static void usage(void) __attribute((noreturn));
+       res=recv_err(hptr, ttl, no_resolve, mtu, his, hops);
+       if(res>0 && *mtu!=m) /* remote mtu change */
+         err=-2;            /* <0 retry */
+       else if(res>=0)
+         err=res;           /* =0 all done  >0 proceed */
+
+       /* printf("**3 err=%i res=%i\n", err, res); */
+       return err;
+}
 
 static void usage(void)
 {
-       fprintf(stderr, "Usage: tracepath [-n] <destination>[/<port>]\n");
-       exit(-1);
+       fprintf(stderr, "Use: tracepath [-I dev] [-Q tos] [-b src[/port]]"
+                       " [-m mtu] [-n] [-t ttli[/f]] \n\tdst[/port]\n");
+       return;
 }
 
-int
-main(int argc, char **argv)
-{
-       struct hostent *he;
-       int fd;
-       int on;
-       int ttl;
+int div_string(char *argin, long *valout) {
+  int err=0;
        char *p;
-       int ch;
 
-       while ((ch = getopt(argc, argv, "nh?")) != EOF) {
+  p=strrchr(argin, '/');
+  if(!p) p=strrchr(argin, ':');
+
+  if(!p) {
+    err=1;  /* na */
+    goto end_error;
+  }
+  *p='\0';
+
+  if(p[1] == '\0') {
+    err=-1; /* eof */
+  } else {
+    char *pend;
+
+    *valout=strtol(&p[1], &pend, 0);
+    if(*pend != '\0')
+      err=-2; /* bad */
+  }
+
+end_error:
+  return err;
+}
+
+#define HISTSIZE 64
+int main(int argc, char **argv)
+{
+       struct hopsinfo hops={ -1, -1};
+       int fdbuf[HISTSIZE];
+       unsigned portbuf[HISTSIZE];
+       struct probehdr hdrbuf[HISTSIZE];
+       struct hhistory his={ 
+         .ptr=0, .size=HISTSIZE, .fd=fdbuf, .port=portbuf, .hdr=hdrbuf 
+       };
+       struct sockaddr_in source, target;
+       unsigned base_port=44444;
+       int base_fix=0;
+       char *bind_ini=NULL, *dev_ini=NULL;
+       char *mtu_ini=NULL, *ttl_ini=NULL, *tos_ini=NULL;
+       char dstname[262];
+       int mtu=65535;
+       int ttli=1, ttlf=31, ttl, tos=0;
+       int no_resolve=0;
+       int ch, res=0, err=0;
+
+       extern char *optarg;   
+       extern int optind;     /*, opterr, optopt; */
+
+       /* init history buffer */
+       { int i;
+         for(i=0; i<his.size; i++) {
+           his.fd[i]=-1;            /* fd used to send probe */
+           his.port[i]=0;           /* probe target port */
+         }
+       }
+       memset(hdrbuf, 0, sizeof(hdrbuf));
+
+       optarg=NULL;           /* init getopt */
+       optind=0;
+       while ((ch = getopt(argc, argv, "I:Q:b:m:ns:t:h")) != EOF) {
                switch(ch) {
+               case 'I':
+                 dev_ini=optarg;
+                 break;
+               case 'Q':
+                 tos_ini=optarg;
+                 break;
+               case 'b':
+               case 's':
+                 bind_ini=optarg;
+                 break;
+               case 'm':
+                 mtu_ini=optarg;
+                 break;
                case 'n':       
-                       no_resolve = 1;
+                 no_resolve ^= 1;
                        break;
+               case 't':
+                 ttl_ini=optarg;
+                 break;
+               case 'h':         
+                 usage();
+                 goto end_error;
                default: ;      
                }
        }
@@ -290,58 +516,204 @@ main(int argc, char **argv)
        argc -= optind;
        argv += optind;
 
-       if (argc != 1)
+       if (argc != 1 && argc != 2) {
                usage();
+         err=255; goto end_error;
+       }
+
+       /* destination address/port */
+       memset(&target, 0, sizeof(target));
+       target.sin_family = AF_INET;
+
+       { int len=strlen(argv[0]);
+         if(len >= sizeof(dstname)) {
+           fprintf(stderr, "Error: bad destination host name"
+                   " length=%i\n", len);
+           err=1; goto end_error;
+         }
+         strcpy(dstname, argv[0]);
+       }
+
+       if(argc>1) {      /* old parameter format: address port */
+         char *pend;
+         long val;
+
+         val=strtol(argv[1], &pend, 0);
+         if(*pend != '\0') {
+           fprintf(stderr, "Error: bad destination port\n");
+           err=2; goto end_error;
+         }
+         base_port=(unsigned )val;
+       } else {          /* new format, switch to multiple source ports */
+         int ret;
+         long val;
+
+         ret=div_string(dstname, &val);
+         if(ret < 0) {
+           fprintf(stderr, "Error: bad destination port\n");
+           err=3; goto end_error;
+         } else if(ret == 0) {
+           base_port=(unsigned )val;
+           base_fix=1; /* fixed target port */
+         }
+       }
+
+       { struct hostent *he;
+         he = gethostbyname2(dstname, target.sin_family);
+         if(he == NULL) {
+           herror("gethostbyname2");
+           err=3; goto end_error;
+         }
+         memcpy(&target.sin_addr, he->h_addr, 4);
+       }
 
+       /* source address/port */
+       memset(&source, 0, sizeof(source));
+       source.sin_family = AF_INET;
+       if(bind_ini) {
+         int ret, blen=strlen(bind_ini)+1;
+         char buf[blen];
+         long val;
+         __u16 sport=0;
+         struct hostent *she;
+
+         strcpy(buf, bind_ini);
+
+         ret=div_string(buf, &val);
+         if(ret < 0) {
+           fprintf(stderr, "Error: bad source port\n");
+           err=5; goto end_error;
+         } else if(ret == 0) {
+           sport = (unsigned )val;
+           base_fix=0;   /* must sweep target port: address already in use */
+         }
+         source.sin_port = htons(sport);
+
+         she = gethostbyname2(buf, source.sin_family);
+         if(she == NULL) {
+           herror("gethostbyname2");
+           err=6; goto end_error;
+         }
+         memcpy(&source.sin_addr, she->h_addr, 4);
+       }
+
+       /* initial mtu */
+       if(mtu_ini) {
+         char *pend;
+         long val;
+
+         val= strtol(mtu_ini, &pend, 0);
+         if(*pend != '\0') {
+           fprintf(stderr, "Error: bad mtu number\n");
+           err=7; goto end_error;
+         }
+         mtu=(int )val;
+         if(mtu<overhead) {
+           fprintf(stderr, "Error: bad mtu=%i<%i\n", mtu, overhead);
+           err=8; goto end_error;
+         }
+       }
+
+       /* ttl range */
+       if(ttl_ini) {
+         int ret, blen=strlen(ttl_ini)+1;
+         char buf[blen];
+         char *pend;
+         long val;
+
+         strcpy(buf, ttl_ini);
+
+         ret=div_string(buf, &val);
+         if(ret < 0) {
+           fprintf(stderr, "Error: bad ttlf\n");
+           err=9; goto end_error;
+         } else if(ret == 0)
+           ttlf=(int )val;
+
+         val=strtol(buf, &pend, 0);
+         if(*pend != '\0') {
+           fprintf(stderr, "Error: bad ttl numbers");
+           err=9; goto end_error;
+         }
+         ttli=(int )val;
+       }
+
+       /* tos */
+       if(tos_ini) {
+         char *pend;
+         long val;
+
+         val= strtol(tos_ini, &pend, 0);
+         if(*pend != '\0') {
+           fprintf(stderr, "Error: bad tos number");
+           err=10; goto end_error;
+         }
+         tos=(int )val;
+       }
+
+       /* create tot socket descriptors and set all target ports */
+       { int i, tot= base_fix ? his.size : 1;
+         for(i=0; i<tot; i++) {
+           int fd, on;
 
        fd = socket(AF_INET, SOCK_DGRAM, 0);
        if (fd < 0) {
                perror("socket");
-               exit(1);
+             err=20; goto end_error;
        }
-       target.sin_family = AF_INET;
-
-       p = strchr(argv[0], '/');
-       if (p) {
-               *p = 0;
-               base_port = atoi(p+1);
-       } else
-               base_port = 44444;
-       he = gethostbyname(argv[0]);
-       if (he == NULL) {
-               herror("gethostbyname");
-               exit(1);
+           if(dev_ini && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, 
+                                    dev_ini, strlen(dev_ini)+1)) {
+             perror("SO_BINDTODEVICE");
+             err=21; goto end_error;
+           }
+           if(bind_ini 
+              && bind(fd, (struct sockaddr*)&source, sizeof(source))<0) {
+             perror("bind");
+             err=22; goto end_error;
        }
-       memcpy(&target.sin_addr, he->h_addr, 4);
 
        on = IP_PMTUDISC_DO;
        if (setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &on, sizeof(on))) {
                perror("IP_MTU_DISCOVER");
-               exit(1);
+             err=23; goto end_error;
        }
        on = 1;
        if (setsockopt(fd, SOL_IP, IP_RECVERR, &on, sizeof(on))) {
                perror("IP_RECVERR");
-               exit(1);
+             err=24; goto end_error;
        }
        if (setsockopt(fd, SOL_IP, IP_RECVTTL, &on, sizeof(on))) {
                perror("IP_RECVTTL");
-               exit(1);
+             err=25; goto end_error;
+           }
+           if (tos_ini && setsockopt(fd, SOL_IP, IP_TOS, &tos, sizeof(tos))) {
+             perror("IP_TOS");
+             err=26; goto end_error;
        }
 
-       for (ttl=1; ttl<32; ttl++) {
-               int res;
-               int i;
+           his.fd[i]=fd;
+           his.port[i]=base_port;
+         } /* for */
+
+         for(; i<his.size; i++) {
+           his.fd[i]=his.fd[i-1];
+           his.port[i]=his.port[i-1]+1;
+         }
+       }
+
+       /* trace */
+       for (ttl=ttli; ttl<=ttlf; ttl++) {
+               int on, fd=his.fd[his.ptr], i;
 
                on = ttl;
                if (setsockopt(fd, SOL_IP, IP_TTL, &on, sizeof(on))) {
                        perror("IP_TTL");
-                       exit(1);
+                       err=28; goto end_error;
                }
 
                for (i=0; i<3; i++) {
-                       res = probe_ttl(fd, ttl);
-                       if (res == 0)
+                 res = probe_ttl(&target, ttl, no_resolve, &mtu, &his, &hops);
+                 if (res == 0) /* reached */
                                goto done;
                        if (res > 0)
                                break;
@@ -351,12 +723,26 @@ main(int argc, char **argv)
                        printf("%2d:  no reply\n", ttl);
        }
        printf("     Too many hops: pmtu %d\n", mtu);
+       err= res<0 ? 40-res : 39;
 done:
        printf("     Resume: pmtu %d ", mtu);
-       if (hops_to>=0)
-               printf("hops %d ", hops_to);
-       if (hops_from>=0)
-               printf("back %d ", hops_from);
+       if (hops.to>=0)
+               printf("hops %d ", hops.to);
+       if (hops.from>=0)
+               printf("back %d ", hops.from);
        printf("\n");
-       exit(0);
+end_error:
+       { int i, lastfd=-2;
+
+         for(i=0; i<his.size; i++) {
+           int fd=his.fd[i];
+           if(fd>=0 && fd!=lastfd) {
+             if(close(fd)<0)
+               fprintf(stderr, "Error close(%i): %s\n", fd, strerror(errno));
+             lastfd=fd;
+           }
+         }
+       }
+       return err;
 }
+#undef HISTSIZE


-- 
To UNSUBSCRIBE, email to [EMAIL PROTECTED]
with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]

Reply via email to