"Fossies" - the Fresh Open Source Software Archive

Member "iftop-0.17/options.c" (8 Feb 2006, 14843 Bytes) of package /linux/privat/old/iftop-0.17.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "options.c": 1.0pre4_vs_0.17.

    1 /*
    2  * options.c:
    3  *
    4  *
    5  */
    6 
    7 #include "config.h"
    8 
    9 #include <sys/types.h>
   10 
   11 #include <stdio.h>
   12 #include <string.h>
   13 #include <stdlib.h>
   14 #include <unistd.h>
   15 
   16 #include <sys/ioctl.h>
   17 #include <sys/socket.h>
   18 #include <netinet/in.h>
   19 #include <arpa/inet.h>
   20 #include <net/if.h>
   21 
   22 #include "iftop.h"
   23 #include "options.h"
   24 #include "cfgfile.h"
   25 #include "integers.h"
   26 
   27 #if !defined(HAVE_INET_ATON) && defined(HAVE_INET_PTON)
   28 #   define inet_aton(a, b)  inet_pton(AF_INET, (a), (b))
   29 #endif
   30 
   31 options_t options;
   32 
   33 char optstr[] = "+i:f:nNF:hpbBPm:c:";
   34 
   35 /* Global options. */
   36 
   37 /* Selecting an interface on which to listen: */
   38 
   39 /* This is a list of interface name prefixes which are `bad' in the sense
   40  * that they don't refer to interfaces of external type on which we are
   41  * likely to want to listen. We also compare candidate interfaces to lo. */
   42 static char *bad_interface_names[] = {
   43             "lo:",
   44             "lo",
   45             "stf",     /* pseudo-device 6to4 tunnel interface */
   46             "gif",     /* psuedo-device generic tunnel interface */
   47             "dummy",
   48             "vmnet",
   49             NULL        /* last entry must be NULL */
   50         };
   51 
   52 config_enumeration_type sort_enumeration[] = {
   53     { "2s", OPTION_SORT_DIV1 },
   54     { "10s", OPTION_SORT_DIV2 },
   55     { "40s", OPTION_SORT_DIV3 },
   56     { "source", OPTION_SORT_SRC },
   57     { "destination", OPTION_SORT_SRC },
   58     { NULL, -1 }
   59 };
   60 
   61 config_enumeration_type linedisplay_enumeration[] = {
   62     { "two-line", OPTION_LINEDISPLAY_TWO_LINE },
   63     { "one-line-both", OPTION_LINEDISPLAY_ONE_LINE_BOTH },
   64     { "one-line-sent", OPTION_LINEDISPLAY_ONE_LINE_SENT },
   65     { "one-line-received", OPTION_LINEDISPLAY_ONE_LINE_RECV },
   66     { NULL, -1 }
   67 };
   68 
   69 config_enumeration_type showports_enumeration[] = {
   70     { "off", OPTION_PORTS_OFF },
   71     { "source-only", OPTION_PORTS_SRC },
   72     { "destination-only", OPTION_PORTS_DEST },
   73     { "on", OPTION_PORTS_ON },
   74     { NULL, -1 }
   75 };
   76 
   77 static int is_bad_interface_name(char *i) {
   78     char **p;
   79     for (p = bad_interface_names; *p; ++p)
   80         if (strncmp(i, *p, strlen(*p)) == 0)
   81             return 1;
   82     return 0;
   83 }
   84 
   85 /* This finds the first interface which is up and is not the loopback
   86  * interface or one of the interface types listed in bad_interface_names. */
   87 static char *get_first_interface(void) {
   88     struct if_nameindex * nameindex;
   89     char *i = NULL;
   90     int j = 0;
   91     /* Use if_nameindex(3) instead? */
   92 
   93     nameindex = if_nameindex();
   94     if(nameindex == NULL) {
   95         return NULL;
   96     }
   97 
   98     while(nameindex[j].if_index != 0) {
   99         if (strcmp(nameindex[j].if_name, "lo") != 0 && !is_bad_interface_name(nameindex[j].if_name)) {
  100             i = xstrdup(nameindex[j].if_name);
  101             break;
  102         }
  103         j++;
  104     }
  105     if_freenameindex(nameindex);
  106     return i;
  107 }
  108 
  109 void options_set_defaults() {
  110     char *s;
  111     /* Should go through the list of interfaces, and find the first one which
  112      * is up and is not lo or dummy*. */
  113     options.interface = get_first_interface();
  114     if (!options.interface)
  115         options.interface = "eth0";
  116 
  117     options.filtercode = NULL;
  118     options.netfilter = 0;
  119     inet_aton("10.0.1.0", &options.netfilternet);
  120     inet_aton("255.255.255.0", &options.netfiltermask);
  121     options.dnsresolution = 1;
  122     options.portresolution = 1;
  123 #ifdef NEED_PROMISCUOUS_FOR_OUTGOING
  124     options.promiscuous = 1;
  125     options.promiscuous_but_choosy = 1;
  126 #else
  127     options.promiscuous = 0;
  128     options.promiscuous_but_choosy = 0;
  129 #endif
  130     options.showbars = 1;
  131     options.showports = OPTION_PORTS_OFF;
  132     options.aggregate_src = 0;
  133     options.aggregate_dest = 0;
  134     options.paused = 0;
  135     options.showhelp = 0;
  136     options.bandwidth_in_bytes = 0;
  137     options.sort = OPTION_SORT_DIV2;
  138     options.screenfilter = NULL;
  139     options.freezeorder = 0;
  140     options.linedisplay = OPTION_LINEDISPLAY_TWO_LINE;
  141     options.screen_offset = 0;
  142     options.show_totals = 0;
  143     options.max_bandwidth = 0; /* auto */
  144     options.log_scale = 0;
  145     options.bar_interval = 1;
  146 
  147     /* Figure out the name for the config file */
  148     s = getenv("HOME");
  149     if(s != NULL) {
  150         int i = strlen(s) + 9 + 1;
  151         options.config_file = xmalloc(i);
  152         snprintf(options.config_file,i,"%s/.iftoprc",s);
  153     }
  154     else {
  155         options.config_file = xstrdup("iftoprc");
  156     }
  157     options.config_file_specified = 0;
  158     
  159 }
  160 
  161 static void die(char *msg) {
  162     fprintf(stderr, msg);
  163     exit(1);
  164 }
  165 
  166 static void set_max_bandwidth(char* arg) {
  167     char* units;
  168     long long mult = 1;
  169     long long value;
  170     units = arg + strspn(arg, "0123456789");
  171     if(strlen(units) > 1) {
  172         die("Invalid units\n");
  173     }
  174     if(strlen(units) == 1) {
  175         if(*units == 'k' || *units == 'K') {
  176             mult = 1024;
  177         }
  178         else if(*units == 'm' || *units == 'M') {
  179             mult = 1024 * 1024;
  180         }
  181         else if(*units == 'g' || *units == 'G') {
  182             mult = 1024 * 1024 * 1024;
  183         }
  184     }
  185     *units = '\0';
  186     if(sscanf(arg, "%lld", &value) != 1) {
  187         die("Error reading max bandwidth\n");
  188     }
  189     options.max_bandwidth = value * mult;
  190 }
  191 
  192 static void set_net_filter(char* arg) {
  193     char* mask;
  194 
  195     mask = strchr(arg, '/');
  196     if (mask == NULL) {
  197         die("Could not parse net/mask\n");
  198     }
  199     *mask = '\0';
  200     mask++;
  201     if (inet_aton(arg, &options.netfilternet) == 0)
  202         die("Invalid network address\n");
  203     /* Accept a netmask like /24 or /255.255.255.0. */
  204     if (mask[strspn(mask, "0123456789")] == '\0') {
  205         /* Whole string is numeric */
  206         int n;
  207         n = atoi(mask);
  208         if (n > 32) {
  209             die("Invalid netmask");
  210         }
  211         else {
  212             if(n == 32) {
  213               /* This needs to be special cased, although I don't fully 
  214                * understand why -pdw 
  215                */
  216               options.netfiltermask.s_addr = htonl(0xffffffffl);
  217             }
  218             else {
  219               u_int32_t mm = 0xffffffffl;
  220               mm >>= n;
  221               options.netfiltermask.s_addr = htonl(~mm);
  222             }
  223         }
  224     } 
  225     else if (inet_aton(mask, &options.netfiltermask) == 0) {
  226         die("Invalid netmask\n");
  227     }
  228     options.netfilternet.s_addr = options.netfilternet.s_addr & options.netfiltermask.s_addr;
  229 
  230     options.netfilter = 1;
  231 
  232 }
  233 
  234 /* usage:
  235  * Print usage information. */
  236 static void usage(FILE *fp) {
  237     fprintf(fp,
  238 "iftop: display bandwidth usage on an interface by host\n"
  239 "\n"
  240 "Synopsis: iftop -h | [-npbBP] [-i interface] [-f filter code] [-N net/mask]\n"
  241 "\n"
  242 "   -h                  display this message\n"
  243 "   -n                  don't do hostname lookups\n"
  244 "   -N                  don't convert port numbers to services\n"
  245 "   -p                  run in promiscuous mode (show traffic between other\n"
  246 "                       hosts on the same network segment)\n"
  247 "   -b                  don't display a bar graph of traffic\n"
  248 "   -B                  Display bandwidth in bytes\n"
  249 "   -i interface        listen on named interface\n"
  250 "   -f filter code      use filter code to select packets to count\n"
  251 "                       (default: none, but only IP packets are counted)\n"
  252 "   -F net/mask         show traffic flows in/out of network\n"
  253 "   -P                  show ports as well as hosts\n"
  254 "   -m limit            sets the upper limit for the bandwidth scale\n"
  255 "   -c config file      specifies an alternative configuration file\n"
  256 "\n"
  257 "iftop, version " IFTOP_VERSION "\n"
  258 "copyright (c) 2002 Paul Warren <pdw@ex-parrot.com> and contributors\n"
  259             );
  260 }
  261 
  262 void options_read_args(int argc, char **argv) {
  263     int opt;
  264 
  265     opterr = 0;
  266     while ((opt = getopt(argc, argv, optstr)) != -1) {
  267         switch (opt) {
  268             case 'h':
  269                 usage(stdout);
  270                 exit(0);
  271 
  272             case 'n':
  273                 config_set_string("dns-resolution","false");
  274                 break;
  275 
  276             case 'N':
  277                 config_set_string("port-resolution","false");
  278                 break;
  279 
  280             case 'i':
  281                 config_set_string("interface", optarg);
  282                 break;
  283 
  284             case 'f':
  285                 config_set_string("filter-code", optarg);
  286                 break;
  287 
  288             case 'p':
  289                 config_set_string("promiscuous", "true");
  290                 break;
  291 
  292             case 'P':
  293                 config_set_string("port-display", "on");
  294                 break;
  295 
  296             case 'F':
  297                 config_set_string("net-filter", optarg);
  298                 break;
  299             
  300             case 'm':
  301                 config_set_string("max-bandwidth", optarg);
  302                 break;
  303 
  304             case 'b':
  305                 config_set_string("show-bars", "true");
  306                 break;
  307 
  308             case 'B':
  309                 config_set_string("use-bytes", "true");
  310                 break;
  311 
  312             case 'c':
  313                 xfree(options.config_file);
  314                 options.config_file = xstrdup(optarg);
  315                 options.config_file_specified = 1;
  316                 break;
  317 
  318             case '?':
  319                 fprintf(stderr, "iftop: unknown option -%c\n", optopt);
  320                 usage(stderr);
  321                 exit(1);
  322 
  323             case ':':
  324                 fprintf(stderr, "iftop: option -%c requires an argument\n", optopt);
  325                 usage(stderr);
  326                 exit(1);
  327         }
  328     }
  329 
  330     if (optind != argc) {
  331         fprintf(stderr, "iftop: found arguments following options\n");
  332         fprintf(stderr, "*** some options have changed names since v0.9 ***\n");
  333         usage(stderr);
  334         exit(1);
  335     }
  336 }
  337 
  338 /* options_config_get_string:
  339  * Gets a value from the config, sets *value to a copy of the value, if
  340  * found.  Leaves the option unchanged otherwise. */
  341 int options_config_get_string(const char *name, char** value) {
  342     char *s;
  343     s = config_get_string(name);
  344     if(s != NULL) {
  345         *value = xstrdup(s);
  346         return 1;
  347     }
  348     return 0;
  349 }
  350 
  351 int options_config_get_bool(const char *name, int* value) {
  352     if(config_get_string(name)) {
  353         *value = config_get_bool(name);
  354         return 1;
  355     }
  356     return 0;
  357 }
  358 
  359 int options_config_get_int(const char *name, int* value) {
  360     if(config_get_string(name)) {
  361         config_get_int(name, value);
  362         return 1;
  363     }
  364     return 0;
  365 }
  366 
  367 int options_config_get_enum(char *name, config_enumeration_type* enumeration, int *result) {
  368     int i;
  369     if(config_get_string(name)) {
  370         if(config_get_enum(name, enumeration, &i)) {
  371             *result = i; 
  372             return 1;
  373         }
  374     }
  375     return 0;
  376 }
  377 
  378 int options_config_get_promiscuous() {
  379     if(config_get_string("promiscuous")) {
  380         options.promiscuous = config_get_bool("promiscuous");
  381         if(options.promiscuous) {
  382             /* User has explicitly requested promiscuous mode, so don't be
  383              * choosy */
  384             options.promiscuous_but_choosy = 0;
  385         }
  386         return 1;
  387     }
  388     return 0;
  389 }
  390 
  391 int options_config_get_bw_rate(char *directive, long long* result) {
  392     char* units;
  393     long long mult = 1;
  394     long long value;
  395     char *s;
  396     s = config_get_string(directive);
  397     if(s) {
  398         units = s + strspn(s, "0123456789");
  399         if(strlen(units) > 1) {
  400             fprintf(stderr, "Invalid units in value: %s\n", s);
  401             return 0;
  402         }
  403         if(strlen(units) == 1) {
  404             if(*units == 'k' || *units == 'K') {
  405                 mult = 1024;
  406             }
  407             else if(*units == 'm' || *units == 'M') {
  408                 mult = 1024 * 1024;
  409             }
  410             else if(*units == 'g' || *units == 'G') {
  411                 mult = 1024 * 1024 * 1024;
  412             }
  413             else if(*units == 'b' || *units == 'B') {
  414                 /* bits => mult = 1 */
  415             }
  416             else {
  417                 fprintf(stderr, "Invalid units in value: %s\n", s);
  418                 return 0;
  419             }
  420         }
  421         *units = '\0';
  422         if(sscanf(s, "%lld", &value) != 1) {
  423             fprintf(stderr, "Error reading rate: %s\n", s);
  424         }
  425         options.max_bandwidth = value * mult;
  426         return 1;
  427     }
  428     return 0;
  429 }
  430 
  431 /*
  432  * Read the net filter option.  
  433  */
  434 int options_config_get_net_filter() {
  435     char* s;
  436     s = config_get_string("net-filter");
  437     if(s) {
  438         char* mask;
  439 
  440         mask = strchr(s, '/');
  441         if (mask == NULL) {
  442             fprintf(stderr, "Could not parse net/mask: %s\n", s);
  443             return 0;
  444         }
  445         *mask = '\0';
  446         mask++;
  447         if (inet_aton(s, &options.netfilternet) == 0) {
  448             fprintf(stderr, "Invalid network address: %s\n", s);
  449             return 0;
  450         }
  451         /* Accept a netmask like /24 or /255.255.255.0. */
  452         if (mask[strspn(mask, "0123456789")] == '\0') {
  453             /* Whole string is numeric */
  454             int n;
  455             n = atoi(mask);
  456             if (n > 32) {
  457                 fprintf(stderr, "Invalid netmask: %s\n", s);
  458             }
  459             else {
  460                 if(n == 32) {
  461                   /* This needs to be special cased, although I don't fully 
  462                    * understand why -pdw 
  463                    */
  464                   options.netfiltermask.s_addr = htonl(0xffffffffl);
  465                 }
  466                 else {
  467                   u_int32_t mm = 0xffffffffl;
  468                   mm >>= n;
  469                   options.netfiltermask.s_addr = htonl(~mm);
  470                 }
  471             }
  472         } 
  473         else if (inet_aton(mask, &options.netfiltermask) == 0) {
  474             fprintf(stderr, "Invalid netmask: %s\n", s);
  475         }
  476         options.netfilternet.s_addr = options.netfilternet.s_addr & options.netfiltermask.s_addr;
  477         options.netfilter = 1;
  478         return 1;
  479     }
  480     return 0;
  481 }
  482 
  483 
  484 void options_make() {
  485     options_config_get_string("interface", &options.interface);
  486     options_config_get_bool("dns-resolution", &options.dnsresolution);
  487     options_config_get_bool("port-resolution", &options.portresolution);
  488     options_config_get_string("filter-code", &options.filtercode);
  489     options_config_get_bool("show-bars", &options.showbars);
  490     options_config_get_promiscuous();
  491     options_config_get_bool("hide-source", &options.aggregate_src);
  492     options_config_get_bool("hide-destination", &options.aggregate_dest);
  493     options_config_get_bool("use-bytes", &options.bandwidth_in_bytes);
  494     options_config_get_enum("sort", sort_enumeration, (int*)&options.sort);
  495     options_config_get_enum("line-display", linedisplay_enumeration, (int*)&options.linedisplay);
  496     options_config_get_bool("show-totals", &options.show_totals);
  497     options_config_get_bool("log-scale", &options.log_scale);
  498     options_config_get_bw_rate("max-bandwidth", &options.max_bandwidth);
  499     options_config_get_enum("port-display", showports_enumeration, (int*)&options.showports);
  500     options_config_get_string("screen-filter", &options.screenfilter);
  501     options_config_get_net_filter();
  502 };