Package: netselect
Version: 0.3.ds1-14
Severity: important
Tags: patch
Currently, netselect uses traceroute to test the distance to remote hosts.
Unfortunately, many hosts now block traceroute probes. I've found this to be
the case of many ftp.XX.debian.org mirrors, sadly, when I was setting up a new
(secondary) mirror for Spain (a replacemente for ftp.es.debian.org).
Netselect should be changed to make it possible:
a) use ICMP probes instead of the normal (UDP) probes used for traceroutes. This
is guaranteed to work in more cases even if the end host blocks UDP
traceroutes.
b) skip the 'HOPS' check altogether and just use ICMP probes to check
the latency for the host.
This was discussed in bug #217256, but I feel it appropiate to report it
separately to other issues (high TTLs) discussed in the bug report.
I have worked on a patch for netselect to implemented the a) option. It patches
netselect and its manpage to add this new option. It took me a few hours, but
it seems to work OK.
Please consider including it in the package.
In order to make this (new) feature fully useful it should be implemented in
netselect-apt too. It seems that there is a long-standing TODO to make it
possible to pass options from netselect-apt to netselect. That would be an
alternative.
Best regards
Javier
-- System Information:
Debian Release: squeeze/sid
APT prefers unstable
APT policy: (500, 'unstable'), (500, 'testing'), (1, 'experimental')
Architecture: i386 (i686)
Kernel: Linux 2.6.32-5-686 (SMP w/2 CPU cores)
Locale: lang=es...@euro, lc_ctype=es...@euro (charmap=ISO-8859-15)
Shell: /bin/sh linked to /bin/bash
Versions of packages netselect depends on:
ii debconf [debconf-2.0] 1.5.36 Debian configuration management sy
ii libc6 2.11.2-6 Embedded GNU C Library: Shared lib
netselect recommends no packages.
Versions of packages netselect suggests:
ii netselect-apt 0.3.ds1-14 speed tester for choosing a fast D
-- debconf information:
* netselect/install-setuid: false
--- netselect.c.orig 2010-10-24 12:09:52.550208453 +0200
+++ netselect.c 2010-10-24 15:18:36.062206999 +0200
@@ -87,6 +87,19 @@
struct timeval tv; /* time packet left */
} OPacket;
+/*
+ * format of a (icmp) probe packet.
+ */
+typedef struct
+{
+ struct ip ip;
+ struct icmp icmp;
+ u_char seq; /* sequence number of this packet */
+ u_char ttl; /* ttl packet left with */
+ struct timeval tv; /* time packet left */
+} IPacket;
+
+
/*
* currently-known information about a host
@@ -122,6 +135,8 @@
static void send_probe(int seq, int ttl, OPacket *op,
HostData *host);
+static void send_icmp_probe(int seq, int ttl, IPacket *op,
+ HostData *host);
static time_t deltaT(struct timeval *t1p, struct timeval *t2p);
static HostData *wait_for_reply(HostData *hosts, int numhosts,
int sock, int msec_timeout);
@@ -152,10 +167,13 @@
extern int optind;
int hostcount, startcount, endcount = 0, sent_one, lag, min_lag = 100;
int ch, seq, ttl, max_ttl = 30, num_score = 1;
+ int use_icmp = 0;
unsigned int min_tries = 10;
struct timeval now;
struct timezone tz;
- OPacket outpacket; /* last output (udp) packet */
+ OPacket udppacket; /* last output (udp) packet */
+ IPacket icmppacket; /* last output (udp) packet */
+
HostData *host, *hosts;
int numhosts, delay, must_continue, count;
int socket_errno = 0;
@@ -182,7 +200,7 @@
#ifdef __EMX__
_response(&argc,&argv);
#endif
- while ((ch = getopt(argc, argv, "s:t:m:v?")) != EOF)
+ while ((ch = getopt(argc, argv, "s:t:m:Iv?")) != EOF)
{
switch (ch)
{
@@ -208,6 +226,10 @@
}
break;
+ case 'I':
+ use_icmp = 1;
+ break;
+
case 'v':
verbose++;
break;
@@ -240,10 +262,20 @@
return 5;
}
- memset(&outpacket, 0, sizeof(OPacket));
- outpacket.ip.ip_tos = 0;
- outpacket.ip.ip_v = IPVERSION;
- outpacket.ip.ip_id = 0;
+ if ( use_icmp )
+ {
+ memset(&icmppacket, 0, sizeof(IPacket));
+ icmppacket.ip.ip_tos = 0;
+ icmppacket.ip.ip_v = IPVERSION;
+ icmppacket.ip.ip_id = 0;
+ }
+ else
+ {
+ memset(&udppacket, 0, sizeof(OPacket));
+ udppacket.ip.ip_tos = 0;
+ udppacket.ip.ip_v = IPVERSION;
+ udppacket.ip.ip_id = 0;
+ }
ident = (getpid() & 0xffff) | 0x8000;
@@ -308,7 +340,10 @@
host->retries++;
host->num_out++;
- send_probe(host->seq, ttl, &outpacket, host);
+ if ( use_icmp )
+ send_icmp_probe(host->seq, ttl, &icmppacket, host);
+ else
+ send_probe(host->seq, ttl, &udppacket, host);
endcount = hostcount;
sent_one = 1;
}
@@ -370,7 +405,7 @@
}
host->total_lag += lag;
break;
-
+
case ICMP_UNREACH_NET:
case ICMP_UNREACH_HOST:
case ICMP_UNREACH_PROTOCOL:
@@ -757,7 +792,7 @@
up->uh_sum = 0;
if (verbose >= 4)
- fprintf(stderr, "%-35s>>\n", host->shortname);
+ fprintf(stderr, "%-35s(UDP)>>\n", host->shortname);
i = sendto(sndsock, op, sizeof(OPacket), 0,
(struct sockaddr *)&host->addr, sizeof(host->addr));
@@ -786,6 +821,77 @@
}
}
+uint16_t
+checksum (uint16_t *header, size_t len)
+{
+ uint32_t sum = 0;
+ int i;
+
+ for (i = 0; i < len / sizeof (uint16_t); i++)
+ sum += ntohs (header[i]);
+
+ return htons (~((sum >> 16) + (sum & 0xffff)));
+}
+
+static void send_icmp_probe(int seq, int ttl, IPacket *op, HostData *host)
+{
+ struct ip *ip = &op->ip;
+ struct icmp *icmp = &op->icmp;
+ struct timezone tz;
+ int i;
+
+ op->ip.ip_dst = host->addr.sin_addr;
+ op->seq = seq;
+ op->ttl = ttl;
+ gettimeofday(&op->tv, &tz);
+
+ ip->ip_off = 0;
+ ip->ip_hl = sizeof(*ip) >> 2;
+ ip->ip_p = IPPROTO_ICMP;
+ ip->ip_len = 0; /* kernel fills this in */
+ ip->ip_ttl = ttl;
+ ip->ip_v = IPVERSION;
+ ip->ip_id = htons(ident + seq);
+
+ icmp->icmp_type= ICMP_ECHO;
+ icmp->icmp_code = 0;
+ icmp->icmp_cksum = 0;
+ icmp->icmp_id = htons (ident);
+ icmp->icmp_seq = htons (seq);
+ icmp->icmp_cksum = checksum((void *)icmp, sizeof(IPacket) - sizeof(struct ip));
+
+ if (verbose >= 4)
+ fprintf(stderr, "%-35s(ICMP)>>\n", host->shortname);
+ if (verbose >= 5)
+ fprintf(stderr, "ICMP sequence: %i, identifier: %i\n", icmp->icmp_seq, icmp->icmp_id);
+
+ i = sendto(sndsock, op, sizeof(IPacket), 0,
+ (struct sockaddr *)&host->addr, sizeof(host->addr));
+ if (i < 0 || i != sizeof(IPacket))
+ {
+ if (i < 0)
+ {
+ switch (errno)
+ {
+ case ENETDOWN:
+ case ENETUNREACH:
+ case EHOSTDOWN:
+ case EHOSTUNREACH:
+ if (verbose >= 3)
+ fprintf(stderr, "unreachable or down!\n");
+ if (!host->invalid)
+ validhosts--;
+ host->invalid = 1;
+ break;
+
+ default:
+ perror("sendto");
+ }
+ }
+ fflush(stdout);
+ }
+}
+
static time_t deltaT(struct timeval *t1p, struct timeval *t2p)
{
@@ -864,8 +970,12 @@
type = icp->icmp_type;
code = icp->icmp_code;
+
+ if (verbose >= 5)
+ fprintf(stderr, "Received ICMP type: %i, code: %i, from %s\n", type, code, inet_ntoa(ip->ip_src) );
+
if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS)
- || type == ICMP_UNREACH)
+ || type == ICMP_UNREACH || type == ICMP_ECHOREPLY )
{
struct ip *hip;
struct udphdr *up;
@@ -873,11 +983,31 @@
hip = &icp->icmp_ip;
hlen = hip->ip_hl << 2;
up = (struct udphdr *) ((u_char *) hip + hlen);
+
for (hcount = 0, host = hosts; hcount < numhosts; hcount++, host++)
{
if (host->invalid) continue;
+
+ /* Valid ICMP echo reply packet */
+ if ( type == ICMP_ECHOREPLY &&
+ ip->ip_src.s_addr == host->addr.sin_addr.s_addr &&
+ icp->icmp_id == htons(ident) &&
+ icp->icmp_seq == htons(host->seq) )
+ {
+ host->code = ICMP_UNREACH_PORT + 1; /* Behave like if a UDP packet was received even though we used ICMP */
+ return host;
+ }
+ /* Time exceeded reply to an ICMP echo request */
+ if ( type == ICMP_TIMXCEED &&
+ hip->ip_dst.s_addr == host->addr.sin_addr.s_addr &&
+ hip->ip_id == htons(ident+host->seq) )
+ {
+ host->code = -1;
+ return host;
+ }
+ /* Valid reply to an UDP probe packet */
if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
up->uh_sport == htons(ident) &&
up->uh_dport == htons(port + host->seq) &&
@@ -889,7 +1019,8 @@
}
}
- /* fprintf(stderr, "received an unknown packet!\n"); */
+ if (verbose >= 3)
+ fprintf(stderr, "received an unknown packet!\n");
return NULL;
}
@@ -908,7 +1039,7 @@
static void usage(void)
{
fprintf(stderr,
- "Usage: netselect [-v|-vv|-vvv] [-m max_ttl] [-s servers] "
+ "Usage: netselect [-v|-vv|-vvv] [-I] [-m max_ttl] [-s servers] "
"[-t min_tries] host ...\n");
}
@@ -978,3 +1109,4 @@
return score;
}
+
--- netselect.1.orig 2010-10-24 15:16:27.038205598 +0200
+++ netselect.1 2010-10-24 15:17:54.471204894 +0200
@@ -114,6 +114,16 @@
The more packets you use, the more accurate are the results... and the
longer it takes to run. The default is 10, which is usually okay.
+.TP
+.BI \-I
+Use ICMP instead of UDP probes. In some occassions (firewalled hosts)
+UDP probes like those used in
+.BR traceroute
+will get filtered out and hosts might be perceived as dead. Using this
+option will make
+.BR netselect
+use ICMP probes instead.
+
.SH SEE ALSO
.BR ping (8),
.BR traceroute (8),