diff -up net-tools-2.0/lib/interface.c.cycle net-tools-2.0/lib/interface.c
--- net-tools-2.0/lib/interface.c.cycle 2016-02-15 16:54:18.000000000 +0100
+++ net-tools-2.0/lib/interface.c 2016-03-30 09:58:18.247891588 +0200
@@ -93,6 +93,7 @@ int if_list_all = 0; /* do we have reque
static struct interface *int_list, *int_last;
static int if_readlist_proc(const char *);
+static int if_readlist_rep(const char *, struct interface *);
static struct interface *if_cache_add(const char *name)
{
@@ -138,11 +139,14 @@ struct interface *lookup_interface(const
int for_all_interfaces(int (*doit) (struct interface *, void *), void *cookie)
{
struct interface *ife;
+ int err;
if (!if_list_all && (if_readlist() < 0))
return -1;
for (ife = int_list; ife; ife = ife->next) {
- int err = doit(ife, cookie);
+ if_readlist_rep(ife->name, ife);
+ err = doit(ife, cookie);
+
if (err)
return err;
}
@@ -210,16 +214,24 @@ out:
return err;
}
-static const char *get_name(char *name, const char *p)
+static const char *get_name(char **namep, const char *p)
{
+ int count = 0;
while (isspace(*p))
p++;
+ char *name = *namep = p;
while (*p) {
if (isspace(*p))
break;
if (*p == ':') { /* could be an alias */
const char *dot = p++;
- while (*p && isdigit(*p)) p++;
+ count++;
+ while (*p && isdigit(*p)) {
+ p++;
+ count++;
+ if (count == (IFNAMSIZ-1))
+ break;
+ }
if (*p == ':') {
/* Yes it is, backup and copy it. */
p = dot;
@@ -235,6 +247,9 @@ static const char *get_name(char *name,
break;
}
*name++ = *p++;
+ count++;
+ if (count == (IFNAMSIZ-1))
+ break;
}
*name++ = '\0';
return p;
@@ -316,9 +331,10 @@ static int get_dev_fields(const char *bp
static int if_readlist_proc(const char *target)
{
FILE *fh;
- char buf[512];
struct interface *ife;
int err;
+ char *line = NULL;
+ size_t linelen = 0;
fh = fopen(_PATH_PROCNET_DEV, "r");
if (!fh) {
@@ -326,10 +342,11 @@ static int if_readlist_proc(const char *
_PATH_PROCNET_DEV, strerror(errno));
return -2;
}
- if (fgets(buf, sizeof buf, fh))
- /* eat line */;
- if (fgets(buf, sizeof buf, fh))
- /* eat line */;
+ if (getline(&line, &linelen, fh) == -1 /* eat line */
+ || getline(&line, &linelen, fh) == -1) { /* eat line */
+ err = -1;
+ goto out;
+ }
#if 0 /* pretty, but can't cope with missing fields */
fmt = proc_gen_fmt(_PATH_PROCNET_DEV, 1, fh,
@@ -354,14 +371,14 @@ static int if_readlist_proc(const char *
if (!fmt)
return -1;
#else
- procnetdev_vsn = procnetdev_version(buf);
+ procnetdev_vsn = procnetdev_version(line);
#endif
err = 0;
- while (fgets(buf, sizeof buf, fh)) {
+ while (getline(&line, &linelen, fh) != -1) {
const char *s;
- char name[IFNAMSIZ];
- s = get_name(name, buf);
+ char *name;
+ s = get_name(&name, line);
ife = if_cache_add(name);
get_dev_fields(s, ife);
ife->statistics_valid = 1;
@@ -376,6 +393,51 @@ static int if_readlist_proc(const char *
#if 0
free(fmt);
#endif
+ out:
+ free(line);
+ fclose(fh);
+ return err;
+}
+
+static int if_readlist_rep(const char *target, struct interface *ife)
+{
+ FILE *fh;
+ int err;
+ char *line = NULL;
+ size_t linelen = 0;
+
+ fh = fopen(_PATH_PROCNET_DEV, "r");
+ if (!fh) {
+ fprintf(stderr, _("Warning: cannot open %s (%s). Limited output.\n"),
+ _PATH_PROCNET_DEV, strerror(errno));
+ return if_readconf();
+ }
+ if (getline(&line, &linelen, fh) == -1 /* eat line */
+ || getline(&line, &linelen, fh) == -1) { /* eat line */
+ err = -1;
+ goto out;
+ }
+
+ procnetdev_vsn = procnetdev_version(line);
+
+ err = 0;
+ while (getline(&line, &linelen, fh) != -1) {
+ char *s, *name;
+ s = get_name(&name, line);
+ get_dev_fields(s, ife);
+ if (target && !strcmp(target,name))
+ {
+ ife->statistics_valid = 1;
+ break;
+ }
+ }
+ if (ferror(fh)) {
+ perror(_PATH_PROCNET_DEV);
+ err = -1;
+ }
+
+ out:
+ free(line);
fclose(fh);
return err;
}
diff -up net-tools-2.0/man/en_US/netstat.8.cycle net-tools-2.0/man/en_US/netstat.8
--- net-tools-2.0/man/en_US/netstat.8.cycle 2016-02-15 16:54:18.000000000 +0100
+++ net-tools-2.0/man/en_US/netstat.8 2016-03-30 09:58:18.241891637 +0200
@@ -36,6 +36,7 @@ netstat \- Print network connections, ro
.RB [ \-\-verbose | \-v ]
.RB [ \-\-continuous | \-c]
.RB [ \-\-wide | \-W ]
+.RB [delay]
.P
.B netstat
.RB { \-\-route | \-r }
@@ -45,22 +46,25 @@ netstat \- Print network connections, ro
.RB [ \-\-numeric | \-n ]
.RB [ \-\-numeric\-hosts "] [" \-\-numeric\-ports "] [" \-\-numeric\-users ]
.RB [ \-\-continuous | \-c ]
+.RB [delay]
.P
.B netstat
-.RB { \-\-interfaces | \-i }
+.RB { \-\-interfaces | \-I | \-i }
.RB [ \-\-all | \-a ]
-.RB [ \-\-extend | \-e [ \-\-extend | \-e] ]
+.RB [ \-\-extend | \-e ]
.RB [ \-\-verbose | \-v ]
.RB [ \-\-program | \-p ]
.RB [ \-\-numeric | \-n ]
.RB [ \-\-numeric-hosts "] [" \-\-numeric-ports "] [" \-\-numeric-users ]
.RB [ \-\-continuous | \-c ]
+.RB [delay]
.P
.B netstat
.RB { \-\-groups | \-g }
.RB [ \-\-numeric | \-n ]
.RB [ \-\-numeric\-hosts "] [" \-\-numeric\-ports "] [" \-\-numeric\-users ]
.RB [ \-\-continuous | \-c ]
+.RB [delay]
.P
.B netstat
.RB { \-\-masquerade | \-M }
@@ -68,6 +72,7 @@ netstat \- Print network connections, ro
.RB [ \-\-numeric | \-n ]
.RB [ \-\-numeric\-hosts "] [" \-\-numeric\-ports "] [" \-\-numeric\-users ]
.RB [ \-\-continuous | \-c ]
+.RB [delay]
.P
.B netstat
.RB { \-\-statistics | -s }
@@ -76,6 +81,7 @@ netstat \- Print network connections, ro
.RB [ \-\-udplite | \-U ]
.RB [ \-\-sctp | \-S ]
.RB [ \-\-raw | \-w ]
+.RB [delay]
.P
.B netstat
.RB { \-\-version | \-V }
@@ -128,8 +134,8 @@ and
produce the same output.
.SS "\-\-groups, \-g"
Display multicast group membership information for IPv4 and IPv6.
-.SS "\-\-interfaces, \-i"
-Display a table of all network interfaces.
+.SS "\-\-interfaces=\fIiface \fR, \fB\-I=\fIiface \fR, \fB\-i"
+Display a table of all network interfaces, or the specified \fIiface\fR.
.SS "\-\-masquerade, \-M"
Display a list of masqueraded connections.
.SS "\-\-statistics, \-s"
@@ -201,13 +207,18 @@ Show the PID and name of the program to
.SS "\-l, \-\-listening"
Show only listening sockets. (These are omitted by default.)
.SS "\-a, \-\-all"
-Show both listening and non-listening sockets. With the
+Show both listening and non-listening (for TCP this means established
+connections) sockets. With the
.B \-\-interfaces
option, show interfaces that are not up
.SS "\-F"
Print routing information from the FIB. (This is the default.)
.SS "\-C"
Print routing information from the route cache.
+.SS delay
+Netstat will cycle printing through statistics every
+.B delay
+seconds.
.P
.SH OUTPUT
.P
diff -up net-tools-2.0/netstat.c.cycle net-tools-2.0/netstat.c
--- net-tools-2.0/netstat.c.cycle 2016-02-15 16:54:18.000000000 +0100
+++ net-tools-2.0/netstat.c 2016-03-30 10:04:07.617171984 +0200
@@ -115,8 +115,8 @@
#endif
/* prototypes for statistics.c */
-void parsesnmp(int, int, int, int);
-void parsesnmp6(int, int, int);
+int parsesnmp(int, int, int, int);
+int parsesnmp6(int, int, int);
typedef enum {
SS_FREE = 0, /* not allocated */
@@ -142,6 +142,7 @@ static char *Release = RELEASE, *Signatu
#define E_IOCTL -3
int flag_int = 0;
+char *flag_int_name = NULL;
int flag_rou = 0;
int flag_mas = 0;
int flag_sta = 0;
@@ -340,10 +341,10 @@ static void prg_cache_clear(void)
prg_cache_loaded = 0;
}
-static void wait_continous(void)
+static void wait_continous(int reptimer)
{
fflush(stdout);
- sleep(1);
+ sleep(reptimer);
}
static int extract_type_1_socket_inode(const char lname[], unsigned long * inode_p) {
@@ -501,6 +502,121 @@ static void prg_cache_load(void)
" will not be shown, you would have to be root to see it all.)\n"));
}
+#define TCP_HASH_SIZE 1009
+
+static struct tcp_node {
+ struct tcp_node *next;
+ char *socket_pair;
+} *tcp_node_hash[TCP_HASH_SIZE];
+
+static unsigned int tcp_node_compute_string_hash(const char *p)
+{
+ unsigned int h = *p;
+
+ if (h)
+ for (p += 1; *p != '\0'; p++)
+ h = (h << 5) - h + *p;
+
+ return h;
+}
+
+#define TCP_NODE_HASH_STRING(x) \
+ (tcp_node_compute_string_hash(x) % TCP_HASH_SIZE)
+
+static void tcp_node_hash_clear(void)
+{
+ int i;
+ struct tcp_node *next_node;
+ struct tcp_node *tmp_node;
+ for (i=0; i < TCP_HASH_SIZE; i++) {
+ if (tcp_node_hash[i]) {
+ /* free the children of this hash bucket */
+ next_node = tcp_node_hash[i]->next;
+ while (next_node) {
+ tmp_node = next_node;
+ next_node = next_node->next;
+ free(tmp_node->socket_pair);
+ free(tmp_node);
+ }
+
+ /* free the bucket itself */
+ free(tcp_node_hash[i]->socket_pair);
+ free(tcp_node_hash[i]);
+ tcp_node_hash[i] = NULL;
+ }
+ }
+}
+
+/* This function takes a socket pair string. If it already exists in
+ the hash it returns -1, otherwise it returns 0. */
+
+static int tcp_node_hash_check_and_append(const char *local_addr,
+ int local_port,
+ const char *rem_addr,
+ int rem_port)
+{
+ unsigned int hash_val;
+ struct tcp_node *tmp_node;
+ int tmp_string_len;
+ char *tmp_string;;
+
+ /* Size of the string is the size of the two lengths of the address
+ strings plus enough sizes for the colons and the ports. */
+ tmp_string_len = strlen(local_addr) + strlen(rem_addr) + 32;
+ tmp_string = malloc(tmp_string_len);
+ if (!tmp_string)
+ return 0;
+
+ if (snprintf(tmp_string, tmp_string_len - 1, "%s:%d:%s:%d",
+ local_addr, local_port, rem_addr, rem_port) < 0) {
+ free(tmp_string);
+ return 0;
+ }
+
+ hash_val = TCP_NODE_HASH_STRING(tmp_string);
+
+ /* See if we have to allocate this node */
+ if (!tcp_node_hash[hash_val]) {
+ tcp_node_hash[hash_val] = malloc(sizeof(struct tcp_node));
+ if (!tcp_node_hash[hash_val]) {
+ free(tmp_string);
+ return 0;
+ }
+
+ memset(tcp_node_hash[hash_val], 0, sizeof(struct tcp_node));
+
+ /* Stuff this new value into the hash bucket and return early */
+ tcp_node_hash[hash_val]->socket_pair = tmp_string;
+ return 0;
+ }
+
+ /* Try to find the value in the hash bucket. */
+ tmp_node = tcp_node_hash[hash_val];
+ while (tmp_node) {
+ if (!strcmp(tmp_node->socket_pair, tmp_string)) {
+ free(tmp_string);
+ return -1;
+ }
+ tmp_node = tmp_node->next;
+ }
+
+ /* If we got this far it means that it isn't in the hash bucket.
+ Add it to the front since it's faster that way. */
+ tmp_node = tcp_node_hash[hash_val];
+
+ tcp_node_hash[hash_val] = malloc(sizeof(struct tcp_node));
+ if (!tcp_node_hash[hash_val]) {
+ free(tmp_string);
+ tcp_node_hash[hash_val] = tmp_node;
+ return 0;
+ }
+
+ tcp_node_hash[hash_val]->socket_pair = tmp_string;
+ tcp_node_hash[hash_val]->next = tmp_node;
+
+ return 0;
+}
+
#if HAVE_AFNETROM
static const char *netrom_state[] =
{
@@ -1109,6 +1225,12 @@ static void tcp_do_one(int lnr, const ch
return;
}
+ /* make sure that we haven't seen this socket pair before */
+ if (tcp_node_hash_check_and_append(local_addr, local_port, rem_addr, rem_port) < 0) {
+ /* fprintf(stderr, _("warning, got duplicate tcp line.\n")); */
+ return;
+ }
+
addr_do_one(local_addr, sizeof(local_addr), 22, ap, &localsas, local_port, "tcp");
addr_do_one(rem_addr, sizeof(rem_addr), 22, ap, &remsas, rem_port, "tcp");
@@ -1877,6 +1999,9 @@ static int rfcomm_info(void)
static int iface_info(void)
{
+ static int count=0;
+ struct interface *ife = NULL;
+
if (skfd < 0) {
if ((skfd = sockets_open(0)) < 0) {
perror("socket");
@@ -1886,20 +2011,25 @@ static int iface_info(void)
}
if (flag_exp < 2) {
ife_short = 1;
- printf(_("Iface MTU RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg\n"));
+ if(!(count % 8))
+ printf(_("Iface MTU RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg\n"));
}
- if (for_all_interfaces(do_if_print, &flag_all) < 0) {
+ if (flag_int_name) {
+ ife = lookup_interface(flag_int_name);
+ do_if_print(ife, &flag_all);
+ }
+ else if (for_all_interfaces(do_if_print, &flag_all) < 0) {
perror(_("missing interface information"));
exit(1);
}
- if (flag_cnt)
+ if (!flag_cnt) {
if_cache_free();
- else {
close(skfd);
skfd = -1;
}
+ count++;
return 0;
}
@@ -1915,9 +2045,10 @@ static void usage(int rc)
{
fprintf(stderr, _("usage: netstat [-vWeenNcCF] [<Af>] -r netstat {-V|--version|-h|--help}\n"));
fprintf(stderr, _(" netstat [-vWnNcaeol] [<Socket> ...]\n"));
- fprintf(stderr, _(" netstat { [-vWeenNac] -i | [-cnNe] -M | -s [-6tuw] }\n\n"));
+ fprintf(stderr, _(" netstat { [-vWeenNac] -I[<Iface>] | [-veenNac] -i | [-cnNe] -M | -s [-6tuw] } [delay]\n\n"));
fprintf(stderr, _(" -r, --route display routing table\n"));
+ fprintf(stderr, _(" -I, --interfaces=<Iface> display interface table for <Iface>\n"));
fprintf(stderr, _(" -i, --interfaces display interface table\n"));
fprintf(stderr, _(" -g, --groups display multicast group memberships\n"));
fprintf(stderr, _(" -s, --statistics display networking statistics (like SNMP)\n"));
@@ -1957,11 +2088,12 @@ int main
(int argc, char *argv[]) {
int i;
int lop;
+ int reptimer = 1;
static struct option longopts[] =
{
AFTRANS_OPTS,
{"version", 0, 0, 'V'},
- {"interfaces", 0, 0, 'i'},
+ {"interfaces", 2, 0, 'I'},
{"help", 0, 0, 'h'},
{"route", 0, 0, 'r'},
#if HAVE_FW_MASQUERADE
@@ -2005,7 +2137,7 @@ int main
getroute_init(); /* Set up AF routing support */
afname[0] = '\0';
- while ((i = getopt_long(argc, argv, "A:CFMacdeghilnNoprsStuUvVWw2fx64?Z", longopts, &lop)) != EOF)
+ while ((i = getopt_long(argc, argv, "A:CFMacdeghiI::lnNoprsStuUvVWw2fx64?Z", longopts, &lop)) != EOF)
switch (i) {
case -1:
break;
@@ -2046,6 +2178,13 @@ int main
case 'p':
flag_prg++;
break;
+ case 'I':
+ if (optarg && strcmp(optarg, "(null)"))
+ if (optarg[0] == '=') optarg++;
+ if (optarg && strcmp(optarg, "(null)"))
+ flag_int_name = strdup(optarg);
+ flag_int++;
+ break;
case 'i':
flag_int++;
break;
@@ -2140,6 +2279,12 @@ int main
flag_sta++;
}
+ if(argc == optind + 1) {
+ if((reptimer = atoi(argv[optind])) <= 0)
+ usage(E_USAGE);
+ flag_cnt++;
+ }
+
if (flag_int + flag_rou + flag_mas + flag_sta > 1)
usage(E_OPTERR);
@@ -2169,7 +2314,7 @@ int main
flag_not & FLAG_NUM_PORT, flag_exp);
if (i || !flag_cnt)
break;
- wait_continous();
+ wait_continous(reptimer);
}
#else
ENOSUPP("netstat", "FW_MASQUERADE");
@@ -2182,15 +2327,16 @@ int main
if (!afname[0])
safe_strncpy(afname, DFLT_AF, sizeof(afname));
+ for (;;) {
if (!strcmp(afname, "inet")) {
#if HAVE_AFINET
- parsesnmp(flag_raw, flag_tcp, flag_udp, flag_sctp);
+ i = parsesnmp(flag_raw, flag_tcp, flag_udp, flag_sctp);
#else
ENOSUPP("netstat", "AF INET");
#endif
} else if(!strcmp(afname, "inet6")) {
#if HAVE_AFINET6
- parsesnmp6(flag_raw, flag_tcp, flag_udp);
+ i = parsesnmp6(flag_raw, flag_tcp, flag_udp);
#else
ENOSUPP("netstat", "AF INET6");
#endif
@@ -2198,7 +2344,11 @@ int main
printf(_("netstat: No statistics support for specified address family: %s\n"), afname);
exit(1);
}
- exit(0);
+ if(i || !flag_cnt)
+ break;
+ sleep(reptimer);
+ }
+ return (i);
}
if (flag_rou) {
@@ -2220,7 +2370,7 @@ int main
i = route_info(afname, options);
if (i || !flag_cnt)
break;
- wait_continous();
+ wait_continous(reptimer);
}
return (i);
}
@@ -2229,7 +2379,7 @@ int main
i = iface_info();
if (!flag_cnt || i)
break;
- wait_continous();
+ wait_continous(reptimer);
}
return (i);
}
@@ -2416,8 +2566,9 @@ int main
if (!flag_cnt || i)
break;
- wait_continous();
+ wait_continous(reptimer);
prg_cache_clear();
+ tcp_node_hash_clear();
}
return (i);
}
diff -up net-tools-2.0/statistics.c.cycle net-tools-2.0/statistics.c
--- net-tools-2.0/statistics.c.cycle 2016-02-15 16:54:18.000000000 +0100
+++ net-tools-2.0/statistics.c 2016-03-30 09:58:18.238891661 +0200
@@ -527,7 +527,7 @@ static void process_fd2(FILE *f, const c
}
}
-void parsesnmp(int flag_raw, int flag_tcp, int flag_udp, int flag_sctp)
+int parsesnmp(int flag_raw, int flag_tcp, int flag_udp, int flag_sctp)
{
FILE *f;
@@ -536,14 +536,17 @@ void parsesnmp(int flag_raw, int flag_tc
f = proc_fopen("/proc/net/snmp");
if (!f) {
perror(_("cannot open /proc/net/snmp"));
- return;
+ return(1);
}
if (process_fd(f, 1, NULL) < 0)
fprintf(stderr, _("Problem while parsing /proc/net/snmp\n"));
- if (ferror(f))
+ if (ferror(f)) {
perror("/proc/net/snmp");
+ fclose(f);
+ return(1);
+ }
fclose(f);
@@ -553,8 +556,11 @@ void parsesnmp(int flag_raw, int flag_tc
if (process_fd(f, 1, NULL) <0)
fprintf(stderr, _("Problem while parsing /proc/net/netstat\n"));
- if (ferror(f))
- perror("/proc/net/netstat");
+ if (ferror(f)) {
+ perror("/proc/net/netstat");
+ fclose(f);
+ return(1);
+ }
fclose(f);
}
@@ -567,9 +573,10 @@ void parsesnmp(int flag_raw, int flag_tc
fclose(f);
}
}
+ return(0);
}
-void parsesnmp6(int flag_raw, int flag_tcp, int flag_udp)
+int parsesnmp6(int flag_raw, int flag_tcp, int flag_udp)
{
FILE *f;
@@ -578,7 +585,7 @@ void parsesnmp6(int flag_raw, int flag_t
f = fopen("/proc/net/snmp6", "r");
if (!f) {
perror(_("cannot open /proc/net/snmp6"));
- return;
+ return(1);
}
process6_fd(f);
if (ferror(f))
@@ -588,11 +595,14 @@ void parsesnmp6(int flag_raw, int flag_t
f = fopen("/proc/net/snmp", "r");
if (!f) {
perror(_("cannot open /proc/net/snmp"));
- return;
+ return(1);
}
process_fd(f, 0, "Tcp");
- if (ferror(f))
+ if (ferror(f)) {
perror("/proc/net/snmp");
+ return(1);
+ }
fclose(f);
+ return(0);
}