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]