I am about to apply the attached patch to Ubuntu's version of net-tools. Here is the debian/changelog entry:
net-tools (1.60-15ubuntu1) breezy; urgency=low * Do not truncate numeric IPv6 addresses in netstat TCP and UDP. The new output format is not parseable with the same algorithms as before because it will be flexible about field widths, but it will not be used unless it is necessary to avoid truncating numeric addresses, so no existing non-broken netstat-output parsing code will be broken. (Also: made 4 copies(!) of endpoint formatting code into one common function. Urgh.) Ubuntu 7294, Debian #254243. -- Ian Jackson <[EMAIL PROTECTED]> Tue, 20 Sep 2005 15:28:53 +0100 I think that applying this patch to Debian's net-tools should fix #254243, and it would probably be useful upstream too. Looking at the code it looks like some serious overhaul is required. Unfortunately I don't think that I have time to do this now, especially at this point in Ubuntu's release cycle. Thanks, Ian. diff -u net-tools-1.60/netstat.c net-tools-1.60/netstat.c --- net-tools-1.60/netstat.c +++ net-tools-1.60/netstat.c @@ -85,6 +85,7 @@ #include <sys/ioctl.h> #include <net/if.h> #include <dirent.h> +#include <assert.h> #include "net-support.h" #include "pathnames.h" @@ -704,11 +705,71 @@ igmp_do_one); } +static void tcpudp_one_end(char *result_buf, size_t result_buf_size, + struct aftype *ap, int end_port, + struct sockaddr *endaddr) +{ + char buffer[8192]; + + snprintf(buffer, sizeof(buffer), "%s", + get_sname(htons(end_port), "udp", + flag_not & FLAG_NUM_PORT)); + + assert(result_buf_size > 23); + + safe_strncpy(result_buf, ap->sprint(endaddr, flag_not), result_buf_size); + if ((strlen(result_buf) + strlen(buffer)) > 22 && + !(flag_not & FLAG_NUM_HOST)) + result_buf[22 - strlen(buffer)] = '\0'; + + assert(strlen(result_buf) + strlen(buffer) + 1 < sizeof(buffer)); + strcat(result_buf, ":"); + strcat(result_buf, buffer); +} + +static void reduce_deficit(int *deficit, int *spc, int min_spc) +{ + int reduction; + reduction= netmin(*deficit, *spc - min_spc); + if (reduction <= 0) return; + *spc -= reduction; + *deficit -= reduction; +} + +static void tcpudp_write(const char *protname, + unsigned long rxq, unsigned long txq, + const char *local_addr, const char *rem_addr, + const char *state) { + int rxq_spc, txq_spc, local_addr_spc, rem_addr_spc, protname_spc; + int local_addr_len, rem_addr_len, deficit; + + protname_spc = 5; + rxq_spc = 6; + txq_spc = 6; + local_addr_spc = 23; + local_addr_len = strlen(local_addr); + rem_addr_spc = 23; + rem_addr_len = strlen(rem_addr); + deficit = netmax(local_addr_len - local_addr_spc, 0) + + netmax(rem_addr_len - rem_addr_spc, 0); + + reduce_deficit(&deficit, &rem_addr_spc, rem_addr_len); + reduce_deficit(&deficit, &local_addr_spc, local_addr_len); + reduce_deficit(&deficit, &txq_spc, 1); + reduce_deficit(&deficit, &rxq_spc, 1); + reduce_deficit(&deficit, &protname_spc, strlen(protname)); + + printf("%-*s %*ld %*ld %-*s %-*s %-11s", + protname_spc, protname, rxq_spc, rxq, txq_spc, txq, + local_addr_spc, local_addr, + rem_addr_spc, rem_addr, state); +} + static void tcp_do_one(int lnr, const char *line) { unsigned long rxq, txq, time_len, retr, inode; int num, local_port, rem_port, d, state, uid, timer_run, timeout; - char rem_addr[128], local_addr[128], timers[64], buffer[1024], more[512]; + char rem_addr[128], local_addr[128], timers[64], more[512]; char *protname; struct aftype *ap; #if HAVE_AFINET6 @@ -775,25 +836,13 @@ safe_strncpy(rem_addr, ap->sprint((struct sockaddr *) &remaddr, flag_not), sizeof(rem_addr)); if (flag_all || (flag_lst && !rem_port) || (!flag_lst && rem_port)) { - snprintf(buffer, sizeof(buffer), "%s", - get_sname(htons(local_port), "tcp", - flag_not & FLAG_NUM_PORT)); - - if ((strlen(local_addr) + strlen(buffer)) > 22) - local_addr[22 - strlen(buffer)] = '\0'; - - strcat(local_addr, ":"); - strcat(local_addr, buffer); - snprintf(buffer, sizeof(buffer), "%s", - get_sname(htons(rem_port), "tcp", flag_not & FLAG_NUM_PORT)); + tcpudp_one_end(local_addr, sizeof(local_addr), + ap, local_port, (struct sockaddr *) &localaddr); - if ((strlen(rem_addr) + strlen(buffer)) > 22) - rem_addr[22 - strlen(buffer)] = '\0'; + tcpudp_one_end(rem_addr, sizeof(rem_addr), + ap, rem_port, (struct sockaddr *) &remaddr); - strcat(rem_addr, ":"); - strcat(rem_addr, buffer); timers[0] = '\0'; - if (flag_opt) switch (timer_run) { case 0: @@ -820,8 +869,11 @@ timer_run, (double) time_len / HZ, retr, timeout); break; } - printf("%-4s %6ld %6ld %-*s %-*s %-11s", - protname, rxq, txq, netmax(23,strlen(local_addr)), local_addr, netmax(23,strlen(rem_addr)), rem_addr, _(tcp_state[state])); + + tcpudp_write(protname, + rxq, txq, + local_addr, rem_addr, + _(tcp_state[state])); finish_this_one(uid,inode,timers); } @@ -835,7 +887,7 @@ static void udp_do_one(int lnr, const char *line) { - char buffer[8192], local_addr[64], rem_addr[64]; + char local_addr[64], rem_addr[64]; char *udp_state, timers[64], more[512]; int num, local_port, rem_port, d, state, timer_run, uid, timeout; char *protname; @@ -927,24 +979,11 @@ if (flag_all || (notnull(remaddr) && !flag_lst) || (!notnull(remaddr) && flag_lst)) { - safe_strncpy(local_addr, ap->sprint((struct sockaddr *) &localaddr, - flag_not), sizeof(local_addr)); - snprintf(buffer, sizeof(buffer), "%s", - get_sname(htons(local_port), "udp", - flag_not & FLAG_NUM_PORT)); - if ((strlen(local_addr) + strlen(buffer)) > 22) - local_addr[22 - strlen(buffer)] = '\0'; - strcat(local_addr, ":"); - strcat(local_addr, buffer); - - snprintf(buffer, sizeof(buffer), "%s", - get_sname(htons(rem_port), "udp", flag_not & FLAG_NUM_PORT)); - safe_strncpy(rem_addr, ap->sprint((struct sockaddr *) &remaddr, - flag_not), sizeof(rem_addr)); - if ((strlen(rem_addr) + strlen(buffer)) > 22) - rem_addr[22 - strlen(buffer)] = '\0'; - strcat(rem_addr, ":"); - strcat(rem_addr, buffer); + tcpudp_one_end(local_addr, sizeof(local_addr), + ap, local_port, (struct sockaddr *) &localaddr); + + tcpudp_one_end(rem_addr, sizeof(rem_addr), + ap, rem_port, (struct sockaddr *) &remaddr); timers[0] = '\0'; if (flag_opt) @@ -963,8 +1002,11 @@ retr, timeout); break; } - printf("%-4s %6ld %6ld %-23s %-23s %-11s", - protname, rxq, txq, local_addr, rem_addr, udp_state); + + tcpudp_write(protname, + rxq, txq, + local_addr, rem_addr, + udp_state); finish_this_one(uid,inode,timers); } diff -u net-tools-1.60/debian/changelog net-tools-1.60/debian/changelog --- net-tools-1.60/debian/changelog +++ net-tools-1.60/debian/changelog @@ -1,3 +1,15 @@ +net-tools (1.60-15ubuntu1) breezy; urgency=low + + * Do not truncate numeric IPv6 addresses in netstat TCP and UDP. + The new output format is not parseable with the same algorithms as + before because it will be flexible about field widths, but it will not + be used unless it is necessary to avoid truncating numeric addresses, + so no existing non-broken netstat-output parsing code will be broken. + (Also: made 4 copies(!) of endpoint formatting code into one + common function. Urgh.) Ubuntu 7294, Debian #254243. + + -- Ian Jackson <[EMAIL PROTECTED]> Tue, 20 Sep 2005 15:28:53 +0100 + net-tools (1.60-15) unstable; urgency=low * minor formating fix to ifconfig(8) -- To UNSUBSCRIBE, email to [EMAIL PROTECTED] with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]