aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2009-09-06 23:05:28 +0000
committerMike Frysinger <vapier@gentoo.org>2009-09-06 23:05:28 +0000
commit83060639d2a7872260a26da20a5c87d12ad6b1f8 (patch)
treec908b85f47ec0b5e6cdf96242fdbd95c5e7810c2
parentifconfig: fix no output when if_readlist_proc() fails (diff)
downloadnet-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.h4
-rw-r--r--netstat.c183
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"
diff --git a/netstat.c b/netstat.c
index 302d10e..b711990 100644
--- a/netstat.c
+++ b/netstat.c
@@ -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)