--- embedaddon/iftop/options.c 2012/02/21 16:57:34 1.1.1.1 +++ embedaddon/iftop/options.c 2016/10/18 14:04:50 1.1.1.2 @@ -30,7 +30,7 @@ options_t options; -char optstr[] = "+i:f:nNF:hpbBPm:c:"; +char optstr[] = "+i:f:nNF:G:lhpbBPm:c:s:tL:o:"; /* Global options. */ @@ -46,7 +46,8 @@ static char *bad_interface_names[] = { "gif", /* psuedo-device generic tunnel interface */ "dummy", "vmnet", - NULL /* last entry must be NULL */ + "wmaster", /* wmaster0 is an internal-use interface for mac80211, a Linux WiFi API. */ + NULL /* last entry must be NULL */ }; config_enumeration_type sort_enumeration[] = { @@ -54,7 +55,7 @@ config_enumeration_type sort_enumeration[] = { { "10s", OPTION_SORT_DIV2 }, { "40s", OPTION_SORT_DIV3 }, { "source", OPTION_SORT_SRC }, - { "destination", OPTION_SORT_SRC }, + { "destination", OPTION_SORT_DEST }, { NULL, -1 } }; @@ -86,8 +87,10 @@ static int is_bad_interface_name(char *i) { * interface or one of the interface types listed in bad_interface_names. */ static char *get_first_interface(void) { struct if_nameindex * nameindex; + struct ifreq ifr; char *i = NULL; int j = 0; + int s; /* Use if_nameindex(3) instead? */ nameindex = if_nameindex(); @@ -95,10 +98,15 @@ static char *get_first_interface(void) { return NULL; } + s = socket(AF_INET, SOCK_DGRAM, 0); /* any sort of IP socket will do */ + while(nameindex[j].if_index != 0) { if (strcmp(nameindex[j].if_name, "lo") != 0 && !is_bad_interface_name(nameindex[j].if_name)) { - i = xstrdup(nameindex[j].if_name); - break; + strncpy(ifr.ifr_name, nameindex[j].if_name, sizeof(ifr.ifr_name)); + if ((s == -1) || (ioctl(s, SIOCGIFFLAGS, &ifr) == -1) || (ifr.ifr_flags & IFF_UP)) { + i = xstrdup(nameindex[j].if_name); + break; + } } j++; } @@ -118,6 +126,10 @@ void options_set_defaults() { options.netfilter = 0; inet_aton("10.0.1.0", &options.netfilternet); inet_aton("255.255.255.0", &options.netfiltermask); + options.netfilter6 = 0; + inet_pton(AF_INET6, "fe80::", &options.netfilter6net); /* Link-local */ + inet_pton(AF_INET6, "ffff::", &options.netfilter6mask); + options.link_local = 0; options.dnsresolution = 1; options.portresolution = 1; #ifdef NEED_PROMISCUOUS_FOR_OUTGOING @@ -143,6 +155,9 @@ void options_set_defaults() { options.max_bandwidth = 0; /* auto */ options.log_scale = 0; options.bar_interval = 1; + options.timed_output = 0; + options.no_curses = 0; + options.num_lines = 10; /* Figure out the name for the config file */ s = getenv("HOME"); @@ -158,86 +173,14 @@ void options_set_defaults() { } -static void die(char *msg) { - fprintf(stderr, msg); - exit(1); -} - -static void set_max_bandwidth(char* arg) { - char* units; - long long mult = 1; - long long value; - units = arg + strspn(arg, "0123456789"); - if(strlen(units) > 1) { - die("Invalid units\n"); - } - if(strlen(units) == 1) { - if(*units == 'k' || *units == 'K') { - mult = 1024; - } - else if(*units == 'm' || *units == 'M') { - mult = 1024 * 1024; - } - else if(*units == 'g' || *units == 'G') { - mult = 1024 * 1024 * 1024; - } - } - *units = '\0'; - if(sscanf(arg, "%lld", &value) != 1) { - die("Error reading max bandwidth\n"); - } - options.max_bandwidth = value * mult; -} - -static void set_net_filter(char* arg) { - char* mask; - - mask = strchr(arg, '/'); - if (mask == NULL) { - die("Could not parse net/mask\n"); - } - *mask = '\0'; - mask++; - if (inet_aton(arg, &options.netfilternet) == 0) - die("Invalid network address\n"); - /* Accept a netmask like /24 or /255.255.255.0. */ - if (mask[strspn(mask, "0123456789")] == '\0') { - /* Whole string is numeric */ - int n; - n = atoi(mask); - if (n > 32) { - die("Invalid netmask"); - } - else { - if(n == 32) { - /* This needs to be special cased, although I don't fully - * understand why -pdw - */ - options.netfiltermask.s_addr = htonl(0xffffffffl); - } - else { - u_int32_t mm = 0xffffffffl; - mm >>= n; - options.netfiltermask.s_addr = htonl(~mm); - } - } - } - else if (inet_aton(mask, &options.netfiltermask) == 0) { - die("Invalid netmask\n"); - } - options.netfilternet.s_addr = options.netfilternet.s_addr & options.netfiltermask.s_addr; - - options.netfilter = 1; - -} - /* usage: * Print usage information. */ static void usage(FILE *fp) { fprintf(fp, "iftop: display bandwidth usage on an interface by host\n" "\n" -"Synopsis: iftop -h | [-npbBP] [-i interface] [-f filter code] [-N net/mask]\n" +"Synopsis: iftop -h | [-npblNBP] [-i interface] [-f filter code]\n" +" [-F net/mask] [-G net6/mask6]\n" "\n" " -h display this message\n" " -n don't do hostname lookups\n" @@ -249,12 +192,26 @@ static void usage(FILE *fp) { " -i interface listen on named interface\n" " -f filter code use filter code to select packets to count\n" " (default: none, but only IP packets are counted)\n" -" -F net/mask show traffic flows in/out of network\n" +" -F net/mask show traffic flows in/out of IPv4 network\n" +" -G net6/mask6 show traffic flows in/out of IPv6 network\n" +" -l display and count link-local IPv6 traffic (default: off)\n" " -P show ports as well as hosts\n" " -m limit sets the upper limit for the bandwidth scale\n" " -c config file specifies an alternative configuration file\n" +" -t use text interface without ncurses\n" "\n" -"iftop, version " IFTOP_VERSION "\n" +" Sorting orders:\n" +" -o 2s Sort by first column (2s traffic average)\n" +" -o 10s Sort by second column (10s traffic average) [default]\n" +" -o 40s Sort by third column (40s traffic average)\n" +" -o source Sort by source address\n" +" -o destination Sort by destination address\n" +"\n" +" The following options are only available in combination with -t\n" +" -s num print one single text output afer num seconds, then quit\n" +" -L num number of lines to print\n" +"\n" +"iftop, version " PACKAGE_VERSION "\n" "copyright (c) 2002 Paul Warren and contributors\n" ); } @@ -285,6 +242,10 @@ void options_read_args(int argc, char **argv) { config_set_string("filter-code", optarg); break; + case 'l': + config_set_string("link-local", "true"); + break; + case 'p': config_set_string("promiscuous", "true"); break; @@ -297,18 +258,38 @@ void options_read_args(int argc, char **argv) { config_set_string("net-filter", optarg); break; + case 'G': + config_set_string("net-filter6", optarg); + break; + case 'm': config_set_string("max-bandwidth", optarg); break; case 'b': - config_set_string("show-bars", "true"); + config_set_string("show-bars", "false"); break; case 'B': config_set_string("use-bytes", "true"); break; + case 's': + config_set_string("timed-output", optarg); + break; + + case 't': + config_set_string("no-curses", "true"); + break; + + case 'L': + config_set_string("num-lines", optarg); + break; + + case 'o': + config_set_string("sort", optarg); + break; + case 'c': xfree(options.config_file); options.config_file = xstrdup(optarg); @@ -327,6 +308,7 @@ void options_read_args(int argc, char **argv) { } } + if (optind != argc) { fprintf(stderr, "iftop: found arguments following options\n"); fprintf(stderr, "*** some options have changed names since v0.9 ***\n"); @@ -437,6 +419,8 @@ int options_config_get_net_filter() { if(s) { char* mask; + options.netfilter = 0; + mask = strchr(s, '/'); if (mask == NULL) { fprintf(stderr, "Could not parse net/mask: %s\n", s); @@ -454,7 +438,7 @@ int options_config_get_net_filter() { int n; n = atoi(mask); if (n > 32) { - fprintf(stderr, "Invalid netmask: %s\n", s); + fprintf(stderr, "Invalid netmask length: %s\n", mask); } else { if(n == 32) { @@ -469,18 +453,88 @@ int options_config_get_net_filter() { options.netfiltermask.s_addr = htonl(~mm); } } + options.netfilter = 1; } - else if (inet_aton(mask, &options.netfiltermask) == 0) { - fprintf(stderr, "Invalid netmask: %s\n", s); + else { + if (inet_aton(mask, &options.netfiltermask) != 0) + options.netfilter = 1; + else { + fprintf(stderr, "Invalid netmask: %s\n", s); + return 0; + } } options.netfilternet.s_addr = options.netfilternet.s_addr & options.netfiltermask.s_addr; - options.netfilter = 1; return 1; } return 0; } +/* + * Read the net filter IPv6 option. + */ +int options_config_get_net_filter6() { + char* s; + int j; + s = config_get_string("net-filter6"); + if(s) { + char* mask; + + options.netfilter6 = 0; + + mask = strchr(s, '/'); + if (mask == NULL) { + fprintf(stderr, "Could not parse IPv6 net/prefix: %s\n", s); + return 0; + } + *mask = '\0'; + mask++; + if (inet_pton(AF_INET6, s, &options.netfilter6net) == 0) { + fprintf(stderr, "Invalid IPv6 network address: %s\n", s); + return 0; + } + /* Accept prefix lengths and address expressions. */ + if (mask[strspn(mask, "0123456789")] == '\0') { + /* Whole string is numeric */ + unsigned int n; + + n = atoi(mask); + if (n > 128 || n < 1) { + fprintf(stderr, "Invalid IPv6 prefix length: %s\n", mask); + } + else { + int bl, rem; + const uint8_t mm = 0xff; + uint8_t part = mm; + + bl = n / 8; + rem = n % 8; + part <<= 8 - rem; + for (j=0; j < bl; ++j) + options.netfilter6mask.s6_addr[j] = mm; + + if (rem > 0) + options.netfilter6mask.s6_addr[bl] = part; + options.netfilter6 = 1; + } + } + else { + if (inet_pton(AF_INET6, mask, &options.netfilter6mask) != 0) + options.netfilter6 = 1; + else { + fprintf(stderr, "Invalid IPv6 netmask: %s\n", s); + return 0; + } + } + /* Prepare any comparison by masking the provided filtered net. */ + for (j=0; j < 16; ++j) + options.netfilter6net.s6_addr[j] &= options.netfilter6mask.s6_addr[j]; + + return 1; + } + return 0; +} + void options_make() { options_config_get_string("interface", &options.interface); options_config_get_bool("dns-resolution", &options.dnsresolution); @@ -498,5 +552,10 @@ void options_make() { options_config_get_bw_rate("max-bandwidth", &options.max_bandwidth); options_config_get_enum("port-display", showports_enumeration, (int*)&options.showports); options_config_get_string("screen-filter", &options.screenfilter); + options_config_get_bool("link-local", &options.link_local); + options_config_get_int("timed-output", &options.timed_output); + options_config_get_bool("no-curses", &options.no_curses); + options_config_get_int("num-lines", &options.num_lines); options_config_get_net_filter(); + options_config_get_net_filter6(); };