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]