Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Paul Warren
iftop
Commits
45804592
Commit
45804592
authored
Oct 19, 2003
by
pdw
Browse files
Added initial config file support.
parent
3824538a
Changes
11
Hide whitespace changes
Inline
Side-by-side
Makefile.am
View file @
45804592
...
...
@@ -15,12 +15,14 @@ sbin_PROGRAMS = iftop
iftop_SOURCES
=
addr_hash.c edline.c hash.c iftop.c ns_hash.c
\
options.c resolver.c screenfilter.c serv_hash.c
\
sorted_list.c threadprof.c ui.c util.c
\
addrs_ioctl.c addrs_dlpi.c dlcommon.c
addrs_ioctl.c addrs_dlpi.c dlcommon.c
\
stringmap.c cfgfile.c vector.c
noinst_HEADERS
=
addr_hash.h ether.h ethertype.h extract.h hash.h iftop.h
\
integers.h ip.h llc.h ns_hash.h options.h resolver.h
\
screenfilter.h serv_hash.h sll.h sorted_list.h tcp.h
\
threadprof.h token.h ui.h dlcommon.h
threadprof.h token.h ui.h dlcommon.h stringmap.h
\
vector.h
man_MANS
=
iftop.8
...
...
TODO
View file @
45804592
...
...
@@ -24,3 +24,6 @@ $Id$
* Linear bar graphs.
* Count obscured connections.
* Startup warnings cause pause.
cfgfile.c
0 → 100644
View file @
45804592
/*
* cfgfile.c:
*
* Copyright (c) 2003 DecisionSoft Ltd.
*
*/
#include <stdio.h>
#include <errno.h>
#include "stringmap.h"
#include "iftop.h"
#include "options.h"
#include "cfgfile.h"
#define CONFIG_TYPE_STRING 0
#define CONFIG_TYPE_BOOL 1
#define CONFIG_TYPE_INT 2
#define MAX_CONFIG_LINE 2048
typedef
struct
{
char
*
name
;
int
type
;
}
config_item_type
;
config_item_type
config_directives
[]
=
{
{
"interface"
,
CONFIG_TYPE_STRING
},
{
"dns-resolution"
,
CONFIG_TYPE_BOOL
},
{
"port-resolution"
,
CONFIG_TYPE_BOOL
},
{
"filter-code"
,
CONFIG_TYPE_STRING
},
{
"show-bars"
,
CONFIG_TYPE_BOOL
},
{
"promiscuous"
,
CONFIG_TYPE_BOOL
},
{
"show-ports"
,
CONFIG_TYPE_INT
},
{
"hide-source"
,
CONFIG_TYPE_INT
},
{
"hide-destination"
,
CONFIG_TYPE_INT
},
{
"use-bytes"
,
CONFIG_TYPE_INT
},
{
"sort"
,
CONFIG_TYPE_INT
},
{
"line-display"
,
CONFIG_TYPE_INT
},
{
"show-totals"
,
CONFIG_TYPE_INT
},
{
"log-scale"
,
CONFIG_TYPE_INT
},
{
"max-bandwidth"
,
CONFIG_TYPE_INT
},
{
"net-filter"
,
CONFIG_TYPE_INT
},
{
"port-display"
,
CONFIG_TYPE_INT
},
{
NULL
,
0
}
};
stringmap
config
;
extern
options_t
options
;
int
is_cfgdirective_valid
(
const
char
*
s
)
{
config_item_type
*
t
;
for
(
t
=
config_directives
;
t
->
name
!=
NULL
;
++
t
)
if
(
strcmp
(
s
,
t
->
name
)
==
0
)
return
1
;
return
0
;
}
int
config_init
()
{
config
=
stringmap_new
();
return
config
!=
NULL
;
}
/* read_config_file:
* Read a configuration file consisting of key: value tuples, returning a
* stringmap of the results. Prints errors to stderr, rather than using
* syslog, since this file is called at program startup. Returns 1 on success
* or 0 on failure. */
int
read_config_file
(
const
char
*
f
)
{
int
ret
=
0
;
FILE
*
fp
;
char
*
line
;
int
i
=
1
;
line
=
xmalloc
(
MAX_CONFIG_LINE
);
fp
=
fopen
(
f
,
"rt"
);
if
(
!
fp
)
{
fprintf
(
stderr
,
"%s: %s
\n
"
,
f
,
strerror
(
errno
));
goto
fail
;
}
while
(
fgets
(
line
,
MAX_CONFIG_LINE
,
fp
))
{
char
*
key
,
*
value
,
*
r
;
for
(
r
=
line
+
strlen
(
line
)
-
1
;
r
>
line
&&
*
r
==
'\n'
;
*
(
r
--
)
=
0
);
/* Get continuation lines. Ugly. */
while
(
*
(
line
+
strlen
(
line
)
-
1
)
==
'\\'
)
{
if
(
!
fgets
(
line
+
strlen
(
line
)
-
1
,
MAX_CONFIG_LINE
-
strlen
(
line
),
fp
))
break
;
for
(
r
=
line
+
strlen
(
line
)
-
1
;
r
>
line
&&
*
r
==
'\n'
;
*
(
r
--
)
=
0
);
}
/* Strip comment. */
key
=
strpbrk
(
line
,
"#
\n
"
);
if
(
key
)
*
key
=
0
;
/* foo : bar baz quux
* key^ ^value */
key
=
line
+
strspn
(
line
,
"
\t
"
);
value
=
strchr
(
line
,
':'
);
if
(
value
)
{
/* foo : bar baz quux
* key^ ^r ^value */
++
value
;
r
=
key
+
strcspn
(
key
,
"
\t
:"
);
if
(
r
!=
key
)
{
item
*
I
;
*
r
=
0
;
/* foo\0: bar baz quux
* key^ ^value ^r */
value
+=
strspn
(
value
,
"
\t
"
);
r
=
value
+
strlen
(
value
)
-
1
;
while
(
strchr
(
"
\t
"
,
*
r
)
&&
r
>
value
)
--
r
;
*
(
r
+
1
)
=
0
;
/* (Removed check for zero length value.) */
/* Check that this is a valid key. */
if
(
!
is_cfgdirective_valid
(
key
))
fprintf
(
stderr
,
"%s:%d: warning: unknown directive
\"
%s
\"\n
"
,
f
,
i
,
key
);
else
if
((
I
=
stringmap_insert
(
config
,
key
,
item_ptr
(
xstrdup
(
value
)))))
/* Don't warn of repeated directives, because they
* may have been specified via the command line
* Previous option takes precedence.
*/
fprintf
(
stderr
,
"%s:%d: warning: repeated directive
\"
%s
\"\n
"
,
f
,
i
,
key
);
}
}
memset
(
line
,
0
,
MAX_CONFIG_LINE
);
/* security paranoia */
++
i
;
}
ret
=
1
;
fail:
if
(
fp
)
fclose
(
fp
);
if
(
line
)
xfree
(
line
);
return
ret
;
}
int
config_get_int
(
const
char
*
directive
,
int
*
value
)
{
stringmap
S
;
char
*
s
,
*
t
;
if
(
!
value
)
return
-
1
;
S
=
stringmap_find
(
config
,
directive
);
if
(
!
S
)
return
0
;
s
=
(
char
*
)
S
->
d
.
v
;
if
(
!*
s
)
return
-
1
;
errno
=
0
;
*
value
=
strtol
(
s
,
&
t
,
10
);
if
(
*
t
)
return
-
1
;
return
errno
==
ERANGE
?
-
1
:
1
;
}
/* config_get_float:
* Get an integer value from a config string. Returns 1 on success, -1 on
* failure, or 0 if no value was found. */
int
config_get_float
(
const
char
*
directive
,
float
*
value
)
{
item
*
I
;
char
*
s
,
*
t
;
if
(
!
value
)
return
-
1
;
I
=
stringmap_find
(
config
,
directive
);
if
(
!
I
)
return
0
;
s
=
(
char
*
)
I
->
v
;
if
(
!*
s
)
return
-
1
;
errno
=
0
;
*
value
=
strtod
(
s
,
&
t
);
if
(
*
t
)
return
-
1
;
return
errno
==
ERANGE
?
-
1
:
1
;
}
/* config_get_string;
* Get a string value from the config file. Returns NULL if it is not
* present. */
char
*
config_get_string
(
const
char
*
directive
)
{
stringmap
S
;
S
=
stringmap_find
(
config
,
directive
);
if
(
S
)
return
(
char
*
)
S
->
d
.
v
;
else
return
NULL
;
}
/* config_get_bool:
* Get a boolean value from the config file. Returns false if not present. */
int
config_get_bool
(
const
char
*
directive
)
{
char
*
s
;
s
=
config_get_string
(
directive
);
if
(
s
&&
(
strcmp
(
s
,
"yes"
)
==
0
||
strcmp
(
s
,
"true"
)
==
0
))
return
1
;
else
return
0
;
}
/* config_get_enum:
* Get an enumeration value from the config file. Returns false if not
* present or an invalid value is found. */
int
config_get_enum
(
const
char
*
directive
,
config_enumeration_type
*
enumeration
,
int
*
value
)
{
char
*
s
;
config_enumeration_type
*
t
;
s
=
config_get_string
(
directive
);
if
(
s
)
{
for
(
t
=
enumeration
;
t
->
name
;
t
++
)
{
if
(
strcmp
(
s
,
t
->
name
)
==
0
)
{
*
value
=
t
->
value
;
return
1
;
}
}
fprintf
(
stderr
,
"Invalid enumeration value
\"
%s
\"
for directive
\"
%s
\"\n
"
,
s
,
directive
);
}
return
0
;
}
/* config_set_string; Sets a value in the config, possibly overriding
* an existing value
*/
void
config_set_string
(
const
char
*
directive
,
const
char
*
s
)
{
stringmap
S
;
S
=
stringmap_find
(
config
,
directive
);
if
(
S
)
stringmap_delete_free
(
S
);
stringmap_insert
(
config
,
directive
,
item_ptr
(
xstrdup
(
s
)));
}
int
read_config
(
char
*
file
)
{
config_item_type
*
t
;
void
*
o
;
read_config_file
(
file
);
if
(
config
==
NULL
)
{
fprintf
(
stderr
,
"Unable to read config file
\n
"
);
return
0
;
}
return
1
;
}
cfgfile.h
0 → 100644
View file @
45804592
/*
* cfgfile.h:
*
* Copyright (c) 2003 DecisionSoft Ltd.
*
*/
#ifndef __CFGFILE_H_
/* include guard */
#define __CFGFILE_H_
typedef
struct
{
char
*
name
;
int
value
;
}
config_enumeration_type
;
int
read_config
();
char
*
config_get_string
(
const
char
*
directive
);
int
config_get_bool
(
const
char
*
directive
);
int
config_get_int
(
const
char
*
directive
,
int
*
value
);
int
config_get_float
(
const
char
*
directive
,
float
*
value
);
int
config_init
();
#endif
/* __CFGFILE_H_ */
iftop.c
View file @
45804592
...
...
@@ -42,6 +42,7 @@
#include "llc.h"
#include "extract.h"
#include "ethertype.h"
#include "cfgfile.h"
/* ethernet address of interface. */
...
...
@@ -517,7 +518,12 @@ int main(int argc, char **argv) {
pthread_t
thread
;
struct
sigaction
sa
=
{};
options_read
(
argc
,
argv
);
/* read command line options and config file */
config_init
();
options_set_defaults
();
options_read_args
(
argc
,
argv
);
read_config
(
options
.
config_file
);
options_make
();
sa
.
sa_handler
=
finish
;
sigaction
(
SIGINT
,
&
sa
,
NULL
);
...
...
options.c
View file @
45804592
...
...
@@ -21,6 +21,7 @@
#include "iftop.h"
#include "options.h"
#include "cfgfile.h"
#if !defined(HAVE_INET_ATON) && defined(HAVE_INET_PTON)
# define inet_aton(a, b) inet_pton(AF_INET, (a), (b))
...
...
@@ -39,14 +40,39 @@ char optstr[] = "+i:f:nN:hpbBPm:";
* likely to want to listen. We also compare candidate interfaces to lo. */
static
char
*
bad_interface_names
[]
=
{
"lo:"
,
"lo"
,
"stf"
,
/* pseudo-device 6to4 tunnel interface */
"gif"
,
/* psuedo-device generic tunnel interface */
"lo"
,
"stf"
,
/* pseudo-device 6to4 tunnel interface */
"gif"
,
/* psuedo-device generic tunnel interface */
"dummy"
,
"vmnet"
,
NULL
/* last entry must be NULL */
};
config_enumeration_type
sort_enumeration
[]
=
{
{
"2s"
,
OPTION_SORT_DIV1
},
{
"10"
,
OPTION_SORT_DIV2
},
{
"40"
,
OPTION_SORT_DIV3
},
{
"source"
,
OPTION_SORT_SRC
},
{
"destination"
,
OPTION_SORT_SRC
},
{
NULL
,
-
1
}
};
config_enumeration_type
linedisplay_enumeration
[]
=
{
{
"two-line"
,
OPTION_LINEDISPLAY_TWO_LINE
},
{
"one-line-both"
,
OPTION_LINEDISPLAY_ONE_LINE_BOTH
},
{
"one-line-sent"
,
OPTION_LINEDISPLAY_ONE_LINE_SENT
},
{
"one-line-received"
,
OPTION_LINEDISPLAY_ONE_LINE_RECV
},
{
NULL
,
-
1
}
};
config_enumeration_type
showports_enumeration
[]
=
{
{
"off"
,
OPTION_PORTS_OFF
},
{
"source-only"
,
OPTION_PORTS_SRC
},
{
"destination-only"
,
OPTION_PORTS_DEST
},
{
"on"
,
OPTION_PORTS_ON
},
{
NULL
,
-
1
}
};
static
int
is_bad_interface_name
(
char
*
i
)
{
char
**
p
;
for
(
p
=
bad_interface_names
;
*
p
;
++
p
)
...
...
@@ -65,7 +91,7 @@ static char *get_first_interface(void) {
nameindex
=
if_nameindex
();
if
(
nameindex
==
NULL
)
{
return
NULL
;
return
NULL
;
}
while
(
nameindex
[
j
].
if_index
!=
0
)
{
...
...
@@ -79,7 +105,8 @@ static char *get_first_interface(void) {
return
i
;
}
static
void
set_defaults
()
{
void
options_set_defaults
()
{
char
*
s
;
/* Should go through the list of interfaces, and find the first one which
* is up and is not lo or dummy*. */
options
.
interface
=
get_first_interface
();
...
...
@@ -115,6 +142,18 @@ static void set_defaults() {
options
.
max_bandwidth
=
0
;
/* auto */
options
.
log_scale
=
0
;
options
.
bar_interval
=
1
;
s
=
getenv
(
"HOME"
);
if
(
s
!=
NULL
)
{
int
i
=
strlen
(
s
)
+
9
+
1
;
options
.
config_file
=
xmalloc
(
i
);
snprintf
(
options
.
config_file
,
i
,
"%s/.iftoprc"
,
s
);
fprintf
(
stderr
,
options
.
config_file
);
}
else
{
options
.
config_file
=
xstrdup
(
"iftoprc"
);
}
}
static
void
die
(
char
*
msg
)
{
...
...
@@ -216,11 +255,9 @@ static void usage(FILE *fp) {
);
}
void
options_read
(
int
argc
,
char
**
argv
)
{
void
options_read
_args
(
int
argc
,
char
**
argv
)
{
int
opt
;
set_defaults
();
opterr
=
0
;
while
((
opt
=
getopt
(
argc
,
argv
,
optstr
))
!=
-
1
)
{
switch
(
opt
)
{
...
...
@@ -229,41 +266,39 @@ void options_read(int argc, char **argv) {
exit
(
0
);
case
'n'
:
options
.
dnsresolution
=
0
;
config_set_string
(
"
dns
-
resolution
"
,
"true"
)
;
break
;
case
'i'
:
options
.
interface
=
optarg
;
config_set_string
(
"
interface
"
,
optarg
)
;
break
;
case
'f'
:
options
.
filtercode
=
xstrdup
(
optarg
);
config_set_string
(
"
filter
-
code
"
,
optarg
);
break
;
case
'p'
:
options
.
promiscuous
=
1
;
options
.
promiscuous_but_choosy
=
0
;
config_set_string
(
"promiscuous"
,
"true"
);
break
;
case
'P'
:
options
.
showports
=
OPTION_PORTS_ON
;
config_set_string
(
"port-display"
,
"on"
)
;
break
;
case
'N'
:
set_
net
_
filter
(
optarg
);
config_set_string
(
"
net
-
filter
"
,
optarg
);
break
;
case
'm'
:
set_
max
_
bandwidth
(
optarg
);
config_set_string
(
"
max
-
bandwidth
"
,
optarg
);
break
;
case
'b'
:
options
.
showbars
=
0
;
config_set_string
(
"
show
-
bars
"
,
"true"
)
;
break
;
case
'B'
:
options
.
bandwidth_in_bytes
=
1
;
config_set_string
(
"use-bytes"
,
"true"
)
;
break
;
case
'?'
:
...
...
@@ -285,3 +320,168 @@ void options_read(int argc, char **argv) {
exit
(
1
);
}
}
/* options_config_get_string:
* Gets a value from the config, sets *value to a copy of the value, if
* found. Leaves the option unchanged otherwise. */
int
options_config_get_string
(
const
char
*
name
,
char
**
value
)
{
char
*
s
;
s
=
config_get_string
(
name
);
if
(
s
!=
NULL
)
{
*
value
=
xstrdup
(
s
);
return
1
;
}
return
0
;
}
int
options_config_get_bool
(
const
char
*
name
,
int
*
value
)
{
if
(
config_get_string
(
name
))
{
*
value
=
config_get_bool
(
name
);
return
1
;
}
return
0
;
}
int
options_config_get_int
(
const
char
*
name
,
int
*
value
)
{
if
(
config_get_string
(
name
))
{
config_get_int
(
name
,
value
);
return
1
;
}
return
0
;
}
int
options_config_get_enum
(
char
*
name
,
config_enumeration_type
*
enumeration
,
int
*
result
)
{
int
i
;
if
(
config_get_string
(
name
))
{
if
(
config_get_enum
(
name
,
enumeration
,
&
i
))
{
*
result
=
i
;
return
1
;
}
}
return
0
;
}
int
options_config_get_promiscuous
()
{
if
(
config_get_string
(
"promiscuous"
))
{
options
.
promiscuous
=
config_get_bool
(
"promiscuous"
);
if
(
options
.
promiscuous
)
{
/* User has explicitly requested promiscuous mode, so don't be
* choosy */
options
.
promiscuous_but_choosy
=
0
;
}
return
1
;
}
return
0
;
}
int
options_config_get_bw_rate
(
char
*
directive
,
long
long
*
result
)
{
char
*
units
;
long
long
mult
=
1
;
long
long
value
;
char
*
s
;
s
=
config_get_string
(
directive
);
if
(
s
)
{
units
=
s
+
strspn
(
s
,
"0123456789"
);
if
(
strlen
(
units
)
>
1
)
{
fprintf
(
stderr
,
"Invalid units in value: %s
\n
"
,
s
);
return
0
;
}
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
;
}
else
if
(
*
units
==
'b'
||
*
units
==
'B'
)
{
/* bits => mult = 1 */
}
else
{
fprintf
(
stderr
,
"Invalid units in value: %s
\n
"
,
s
);
return
0
;
}
}
*
units
=
'\0'
;
if
(
sscanf
(
s
,
"%lld"
,
&
value
)
!=
1
)
{
fprintf
(
stderr
,
"Error reading rate: %s
\n
"
,
s
);
}
options
.
max_bandwidth
=
value
*
mult
;
return
1
;
}
return
0
;
}
/*
* Read the net filter option.
*/
int
options_config_get_net_filter
()
{
char
*
s
;
s
=
config_get_string
(
"net-filter"
);
if
(
s
)
{
char
*
mask
;
mask
=
strchr
(
s
,
'/'
);
if
(
mask
==
NULL
)
{
fprintf
(
stderr
,
"Could not parse net/mask: %s
\n
"
,
s
);
return
0
;
}
*
mask
=
'\0'
;
mask
++
;
if
(
inet_aton
(
s
,
&
options
.
netfilternet
)
==
0
)
{
fprintf
(
stderr
,
"Invalid network address: %s
\n
"
,
s
);
return
0
;
}
/* 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
)
{
fprintf
(
stderr
,
"Invalid netmask: %s
\n
"
,
s
);
}
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
)
{
fprintf
(
stderr
,
"Invalid netmask: %s
\n
"
,
s
);
}
options
.
netfilternet
.
s_addr
=
options
.
netfilternet
.
s_addr
&
options
.
netfiltermask
.
s_addr
;
options
.
netfilter
=
1
;
return
1
;
}
return
0
;
}
void
options_make
()
{
options_config_get_string
(
"interface"
,
&
options
.
interface
);
options_config_get_bool
(
"dns-resolution"
,
&
options
.
dnsresolution
);
options_config_get_bool
(
"port-resolution"
,
&
options
.
portresolution
);
options_config_get_string
(
"filter-code"
,
&
options
.
filtercode
);
options_config_get_bool
(
"show-bars"
,
&
options
.
showbars
);