diff options
author | 2009-09-06 23:05:28 +0000 | |
---|---|---|
committer | 2009-09-06 23:05:28 +0000 | |
commit | 83060639d2a7872260a26da20a5c87d12ad6b1f8 (patch) | |
tree | c908b85f47ec0b5e6cdf96242fdbd95c5e7810c2 | |
parent | ifconfig: fix no output when if_readlist_proc() fails (diff) | |
download | net-tools-83060639d2a7872260a26da20a5c87d12ad6b1f8.tar.gz net-tools-83060639d2a7872260a26da20a5c87d12ad6b1f8.tar.bz2 net-tools-83060639d2a7872260a26da20a5c87d12ad6b1f8.zip |
netstat: add sctp connection decoding (Debian #306428 and Gentoo #258714)
-rw-r--r-- | lib/pathnames.h | 4 | ||||
-rw-r--r-- | netstat.c | 183 |
2 files changed, 180 insertions, 7 deletions
diff --git a/lib/pathnames.h b/lib/pathnames.h index dd487f7..9bf0a82 100644 --- a/lib/pathnames.h +++ b/lib/pathnames.h @@ -18,6 +18,10 @@ #define _PATH_PROCNET_UDP6 "/proc/net/udp6" #define _PATH_PROCNET_UDPLITE "/proc/net/udplite" #define _PATH_PROCNET_UDPLITE6 "/proc/net/udplite6" +#define _PATH_PROCNET_SCTPEPTS "/proc/net/sctp/eps" +#define _PATH_PROCNET_SCTP6EPTS "/proc/net/sctp6/eps" +#define _PATH_PROCNET_SCTPASSOCS "/proc/net/sctp/assocs" +#define _PATH_PROCNET_SCTP6ASSOCS "/proc/net/sctp6/assocs" #define _PATH_PROCNET_RAW "/proc/net/raw" #define _PATH_PROCNET_RAW6 "/proc/net/raw6" #define _PATH_PROCNET_UNIX "/proc/net/unix" @@ -6,7 +6,7 @@ * NET-3 Networking Distribution for the LINUX operating * system. * - * Version: $Id: netstat.c,v 1.66 2009/09/06 22:47:46 vapier Exp $ + * Version: $Id: netstat.c,v 1.67 2009/09/06 23:05:28 vapier Exp $ * * Authors: Fred Baumgarten, <dc6iq@insu1.etec.uni-karlsruhe.de> * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> @@ -59,6 +59,7 @@ *990420 {1.38} Tuan Hoang removed a useless assignment from igmp_do_one() *20010404 {1.39} Arnaldo Carvalho de Melo - use setlocale *20081201 {1.42} Brian Micek added -L|--udplite options for RFC 3828 + *20020722 {1.51} Thomas Preusser added SCTP over IPv4 support * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General @@ -146,6 +147,7 @@ int flag_cf = 0; int flag_opt = 0; int flag_raw = 0; int flag_tcp = 0; +int flag_sctp= 0; int flag_udp = 0; int flag_udplite = 0; int flag_igmp= 0; @@ -710,6 +712,163 @@ static int igmp_info(void) igmp_do_one, "igmp", "igmp6"); } +static int ip_parse_dots(uint32_t *addr, char const *src) { + unsigned a, b, c, d; + unsigned ret = 4-sscanf(src, "%u.%u.%u.%u", &a, &b, &c, &d); + *addr = htonl((a << 24)|(b << 16)|(c << 8)|d); + return ret; +} + +static void print_ip_service(struct sockaddr_in *addr, char const *protname, + char *buf, unsigned size) { + struct aftype *ap; + + if(size == 0) return; + + /* print host */ + if((ap = get_afntype(addr->sin_family)) == NULL) { + fprintf(stderr, _("netstat: unsupported address family %d !\n"), + addr->sin_family); + return; + } + safe_strncpy(buf, ap->sprint((struct sockaddr*)addr, flag_not), size); + + /* print service */ + if(flag_all || (flag_lst && !addr->sin_port) || (!flag_lst && addr->sin_port)) { + char bfs[32]; + + snprintf(bfs, sizeof(bfs), "%s", + get_sname(addr->sin_port, (char*)protname, flag_not & FLAG_NUM_PORT)); + + /* check if we must cut on host and/or service name */ + { + unsigned const bufl = strlen(buf); + unsigned const bfsl = strlen(bfs); + + if(bufl+bfsl+2 > size) { + unsigned const half = (size-2)>>1; + if(bufl > half) { + if(bfsl > half) { + buf[size-2-half] = '\0'; + bfs[half+1] = '\0'; + } + else buf[size-2-bfsl] = '\0'; + } + else bfs[size-2-bufl] = '\0'; + } + } + strcat(buf, ":"); + strcat(buf, bfs); + } +} + +/* process single SCTP endpoint */ +static void sctp_do_ept(int lnr, char const *line, const char *prot) +{ + struct sockaddr_in laddr, raddr; + unsigned uid, inode; + + char l_addr[23], r_addr[23]; + + /* fill sockaddr_in structures */ + { + unsigned lport; + unsigned ate; + + if(lnr == 0) return; + if(sscanf(line, "%*X %*X %*u %*u %*u %u %u %u %n", + &lport, &uid, &inode, &ate) < 3) goto err; + + /* decode IP address */ + if(ip_parse_dots(&laddr.sin_addr.s_addr, line+ate)) goto err; + raddr.sin_addr.s_addr = htonl(0); + laddr.sin_family = raddr.sin_family = AF_INET; + laddr.sin_port = htons(lport); + raddr.sin_port = htons(0); + } + + /* print IP:service to l_addr and r_addr */ + print_ip_service(&laddr, prot, l_addr, sizeof(l_addr)); + print_ip_service(&raddr, prot, r_addr, sizeof(r_addr)); + + /* Print line */ + printf("%-4s %6d %6d %-*s %-*s %-11s", + prot, 0, 0, + (int)netmax(23,strlen(l_addr)), l_addr, + (int)netmax(23,strlen(r_addr)), r_addr, + _(tcp_state[TCP_LISTEN])); + finish_this_one(uid, inode, ""); + return; + err: + fprintf(stderr, "SCTP error in line: %d\n", lnr); +} + +/* process single SCTP association */ +static void sctp_do_assoc(int lnr, char const *line, const char *prot) +{ + struct sockaddr_in laddr, raddr; + unsigned long rxq, txq; + unsigned uid, inode; + + char l_addr[23], r_addr[23]; + + /* fill sockaddr_in structures */ + { + unsigned lport, rport; + unsigned ate; + char const *addr; + + if(lnr == 0) return; + if(sscanf(line, "%*X %*X %*u %*u %*u %*u %*u %lu %lu %u %u %u %u %n", + &txq, &rxq, &uid, &inode, &lport, &rport, &ate) < 6) goto err; + + /* decode IP addresses */ + addr = strchr(line+ate, '*'); + if(addr == 0) goto err; + if(ip_parse_dots(&laddr.sin_addr.s_addr, ++addr)) goto err; + addr = strchr(addr, '*'); + if(addr == 0) goto err; + if(ip_parse_dots(&raddr.sin_addr.s_addr, ++addr)) goto err; + + /* complete sockaddr_in structures */ + laddr.sin_family = raddr.sin_family = AF_INET; + laddr.sin_port = htons(lport); + raddr.sin_port = htons(rport); + } + + /* print IP:service to l_addr and r_addr */ + print_ip_service(&laddr, prot, l_addr, sizeof(l_addr)); + print_ip_service(&raddr, prot, r_addr, sizeof(r_addr)); + + /* Print line */ + printf("%-4s %6ld %6ld %-*s %-*s %-11s", + prot, rxq, txq, + (int)netmax(23,strlen(l_addr)), l_addr, + (int)netmax(23,strlen(r_addr)), r_addr, + _(tcp_state[TCP_ESTABLISHED])); + finish_this_one(uid, inode, ""); + return; + err: + fprintf(stderr, "SCTP error in line: %d\n", lnr); +} + +static int sctp_info_epts(void) { + INFO_GUTS6(_PATH_PROCNET_SCTPEPTS, _PATH_PROCNET_SCTP6EPTS, "AF INET (sctp)", + sctp_do_ept, "sctp", "sctp6"); +} + +static int sctp_info_assocs(void) { + INFO_GUTS6(_PATH_PROCNET_SCTPASSOCS, _PATH_PROCNET_SCTP6ASSOCS, "AF INET (sctp)", + sctp_do_assoc, "sctp", "sctp6"); +} + +static int sctp_info(void) { + int res; + res = sctp_info_epts(); + if(res) return res; + return sctp_info_assocs(); +} + static void tcp_do_one(int lnr, const char *line, const char *prot) { unsigned long rxq, txq, time_len, retr, inode; @@ -1563,6 +1722,7 @@ int main #endif {"protocol", 1, 0, 'A'}, {"tcp", 0, 0, 't'}, + {"sctp", 0, 0, 'S'}, {"udp", 0, 0, 'u'}, {"udplite", 0, 0, 'U'}, {"raw", 0, 0, 'w'}, @@ -1595,7 +1755,7 @@ int main getroute_init(); /* Set up AF routing support */ afname[0] = '\0'; - while ((i = getopt_long(argc, argv, "A:CFMacdeghilnNoprstuUvVWwx64?", longopts, &lop)) != EOF) + while ((i = getopt_long(argc, argv, "A:CFMacdeghilnNoprsStuUvVWwx64?", longopts, &lop)) != EOF) switch (i) { case -1: break; @@ -1686,6 +1846,9 @@ int main case 't': flag_tcp++; break; + case 'S': + flag_sctp++; + break; case 'u': flag_udp++; break; @@ -1710,14 +1873,14 @@ int main usage(); if ((flag_inet || flag_inet6 || flag_sta) && - !(flag_tcp || flag_udp || flag_udplite || flag_raw)) - flag_tcp = flag_udp = flag_udplite = flag_raw = 1; + !(flag_tcp || flag_sctp || flag_udp || flag_udplite || flag_raw)) + flag_tcp = flag_sctp = flag_udp = flag_udplite = flag_raw = 1; - if ((flag_tcp || flag_udp || flag_udplite || flag_raw || flag_igmp) && + if ((flag_tcp || flag_sctp || flag_udp || flag_udplite || flag_raw || flag_igmp) && !(flag_inet || flag_inet6)) flag_inet = flag_inet6 = 1; - flag_arg = flag_tcp + flag_udplite + flag_udp + flag_raw + flag_unx + flag_arg = flag_tcp + flag_sctp + flag_udplite + flag_udp + flag_raw + flag_unx + flag_ipx + flag_ax25 + flag_netrom + flag_igmp + flag_x25 + flag_rose; if (flag_mas) { @@ -1798,7 +1961,7 @@ int main return (i); } for (;;) { - if (!flag_arg || flag_tcp || flag_udp || flag_udplite || flag_raw) { + if (!flag_arg || flag_tcp || flag_sctp || flag_udp || flag_udplite || flag_raw) { #if HAVE_AFINET prg_cache_load(); printf(_("Active Internet connections ")); /* xxx */ @@ -1832,6 +1995,12 @@ int main return (i); } + if (!flag_arg || flag_sctp) { + i = sctp_info(); + if (i) + return (i); + } + if (!flag_arg || flag_udp) { i = udp_info(); if (i) |