"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "iptstate.cc" between
iptstate-2.2.6.tar.gz and iptstate-2.2.7.tar.bz2

About: IPTState (IP Tables State) is a top-like interface to your netfilter/iptables connection-tracking table.

iptstate.cc  (iptstate-2.2.6):iptstate.cc  (iptstate-2.2.7.tar.bz2)
skipping to change at line 62 skipping to change at line 62
#include <string> #include <string>
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
// There are no C++-ified versions of these. // There are no C++-ified versions of these.
#include <arpa/inet.h> #include <arpa/inet.h>
#include <getopt.h> #include <getopt.h>
extern "C" { extern "C" {
#include <libnetfilter_conntrack/libnetfilter_conntrack.h> #include <libnetfilter_conntrack/libnetfilter_conntrack.h>
}; };
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <locale.h>
#include <netdb.h> #include <netdb.h>
#include <ncurses.h> #include <ncurses.h>
#include <unistd.h> #include <unistd.h>
#include <sys/ioctl.h>
using namespace std; using namespace std;
#define VERSION "2.2.6" #define VERSION "2.2.7"
/* /*
* MAXCONS is set to 16k, the default number of states in iptables. Generally * MAXCONS is set to 16k, the default number of states in iptables. Generally
* speaking the ncurses pad is this many lines long, but since ncurses * speaking the ncurses pad is this many lines long, but since ncurses
* uses a short for their dimensions, a pad can never be longer than 32767. * uses a short for their dimensions, a pad can never be longer than 32767.
* Thus we define both of these values and NLINES as the lesser of the two. * Thus we define both of these values and NLINES as the lesser of the two.
*/ */
#define MAXCONS 16384 #define MAXCONS 16384
#define MAXLINES 32767 #define MAXLINES 32767
#if MAXCONS < MAXLINES #if MAXCONS < MAXLINES
#define NLINES MAXCONS #define NLINES MAXCONS
skipping to change at line 151 skipping to change at line 155
uint8_t family; uint8_t family;
unsigned long srcpt, dstpt, bytes, packets, s; unsigned long srcpt, dstpt, bytes, packets, s;
}; };
// x/y of the terminal window // x/y of the terminal window
struct screensize_t { struct screensize_t {
unsigned int x, y; unsigned int x, y;
}; };
// Struct 'o flags // Struct 'o flags
struct flags_t { struct flags_t {
bool single, totals, lookup, skiplb, staticsize, skipdns, tag_truncate, bool single, totals, lookup, skiplb, staticsize, skipdns, tag_truncate,
filter_src, filter_dst, filter_srcpt, filter_dstpt, noscroll, nocolor, filter_src, filter_dst, filter_srcpt, filter_dstpt, filter_inv, noscroll, nocolor,
counters; counters;
}; };
// Struct 'o counters // Struct 'o counters
struct counters_t { struct counters_t {
unsigned int total, tcp, udp, icmp, other, skipped; unsigned int total, tcp, udp, icmp, other, skipped;
}; };
// Various filters to be applied pending the right flags in flags_t // Various filters to be applied pending the right flags in flags_t
struct filters_t { struct filters_t {
in6_addr src, dst; in6_addr src, dst;
bool has_srcnet, has_dstnet;
uint8_t srcnet, dstnet;
uint8_t srcfam, dstfam; uint8_t srcfam, dstfam;
unsigned long srcpt, dstpt; unsigned long srcpt, dstpt;
}; };
// The max-length of fields in the stable table // The max-length of fields in the stable table
struct max_t { struct max_t {
unsigned int src, dst, proto, state, ttl; unsigned int src, dst, proto, state, ttl;
unsigned long bytes, packets; unsigned long bytes, packets;
}; };
struct hook_data { struct hook_data {
vector<tentry_t*> *stable; vector<tentry_t*> *stable;
skipping to change at line 223 skipping to change at line 229
/* /*
* This determines the length of an integer (i.e. number of digits) * This determines the length of an integer (i.e. number of digits)
*/ */
unsigned int digits(unsigned long x) unsigned int digits(unsigned long x)
{ {
return (unsigned int) floor(log10((double)x))+1; return (unsigned int) floor(log10((double)x))+1;
} }
/* /*
* Check to ensure an IP is valid * Check to ensure an IP & netmask are valid
*/ */
bool check_ip(const char *arg, in6_addr *addr, uint8_t *family) bool check_ip(const char *arg, in6_addr *addr, uint8_t *family, uint8_t *netmask , bool *has_netmask)
{ {
const char *p_arg;
char ip[NAMELEN];
// Check for netmask prefix
p_arg = strrchr(arg, '/');
if (p_arg == NULL) {
memcpy(ip, arg, (strlen(arg) + 1));
*has_netmask = false;
} else {
size_t ip_len = strlen(arg) - strlen(p_arg);
memcpy(ip, arg, ip_len);
ip[ip_len] = '\0';
const char *net_arg = arg + ip_len + 1;
if (net_arg[0] == '\0')
return false;
int net_int = atoi(net_arg);
if (net_int < 0 || net_int > 128)
return false; // Max IPv6 prefix length
*has_netmask = true;
*netmask = (uint8_t) net_int;
}
// Get IP
int ret; int ret;
ret = inet_pton(AF_INET6, arg, addr); ret = inet_pton(AF_INET6, ip, addr);
if (ret) { if (ret) {
*family = AF_INET6; *family = AF_INET6;
return true; return true;
} }
ret = inet_pton(AF_INET, arg, addr); ret = inet_pton(AF_INET, ip, addr);
if (ret) { if (ret) {
if (*has_netmask && *netmask > 32)
return false; // Max IPv4 prefix length
*family = AF_INET; *family = AF_INET;
return true; return true;
} }
return false; return false;
} }
/* /*
* Compare IPv4/6 addresses with a netmask
* https://gist.github.com/duedal/b83303b4988a4afb2a75
*/
bool match_netmask(uint8_t family, const in6_addr &address, const in6_addr &netw
ork, uint8_t bits) {
if (family == AF_INET) {
if (bits == 0) {
// C99 6.5.7 (3): u32 << 32 is undefined behaviour
return true;
}
struct in_addr addr4, net4;
memcpy(&addr4, &address, sizeof(in_addr));
memcpy(&net4, &network, sizeof(in_addr));
return !((addr4.s_addr ^ net4.s_addr) & htonl(0xFFFFFFFFu << (32 - bits)));
} else {
const uint32_t *a = address.s6_addr32;
const uint32_t *n = network.s6_addr32;
int bits_whole, bits_incomplete;
bits_whole = bits >> 5; // number of whole u32
bits_incomplete = bits & 0x1F; // number of bits in incomplete u32
if (bits_whole) {
if (memcmp(a, n, bits_whole << 2)) {
return false;
}
}
if (bits_incomplete) {
uint32_t mask = htonl((0xFFFFFFFFu) << (32 - bits_incomplete));
if ((a[bits_whole] ^ n[bits_whole]) & mask) {
return false;
}
}
return true;
}
return false;
}
/*
* The help * The help
*/ */
void version() void version()
{ {
cout << "IPTables State Top Version " << VERSION << endl << endl; cout << "IPTables State Top Version " << VERSION << endl << endl;
} }
void help() void help()
{ {
cout << "IPTables State Top Version " << VERSION << endl; cout << "IPTables State Top Version " << VERSION << endl;
cout << "Usage: iptstate [<options>]\n\n"; cout << "Usage: iptstate [<options>]\n\n";
cout << " -c, --no-color\n"; cout << " -c, --no-color\n";
cout << "\tToggle color-code by protocol\n\n"; cout << "\tToggle color-code by protocol\n\n";
cout << " -C, --counters\n"; cout << " -C, --counters\n";
cout << "\tToggle display of bytes/packets counters\n\n"; cout << "\tToggle display of bytes/packets counters\n\n";
cout << " -d, --dst-filter <IP>\n"; cout << " -d, --dst-filter <IP>[/<NETMASK>]\n";
cout << "\tOnly show states with a destination of <IP>\n"; cout << "\tOnly show states with a destination of <IP> and optional <NETMASK>\
cout << "\tNote, that this must be an IP, hostname matching is" n";
<< " not yet supported.\n\n"; cout << "\tNote: Hostname matching is not yet supported.\n\n";
cout << " -D --dstpt-filter <port>\n"; cout << " -D --dstpt-filter <port>\n";
cout << "\tOnly show states with a destination port of <port>\n\n"; cout << "\tOnly show states with a destination port of <port>\n\n";
cout << " -h, --help\n"; cout << " -h, --help\n";
cout << "\tThis help message\n\n"; cout << "\tThis help message\n\n";
cout << " -i, --invert-filters\n";
cout << "\tInvert filters to display non-matching results\n\n";
cout << " -l, --lookup\n"; cout << " -l, --lookup\n";
cout << "\tShow hostnames instead of IP addresses. Enabling this will also" cout << "\tShow hostnames instead of IP addresses. Enabling this will also"
<< " enable\n\t-L to prevent an ever-growing number of DNS requests.\n\n"; << " enable\n\t-L to prevent an ever-growing number of DNS requests.\n\n";
cout << " -m, --mark-truncated\n"; cout << " -m, --mark-truncated\n";
cout << "\tMark truncated hostnames with a '+'\n\n"; cout << "\tMark truncated hostnames with a '+'\n\n";
cout << " -o, --no-dynamic\n"; cout << " -o, --no-dynamic\n";
cout << "\tToggle dynamic formatting\n\n"; cout << "\tToggle dynamic formatting\n\n";
cout << " -L, --no-dns\n"; cout << " -L, --no-dns\n";
cout << "\tSkip outgoing DNS lookup states\n\n"; cout << "\tSkip outgoing DNS lookup states\n\n";
cout << " -f, --no-loopback\n"; cout << " -f, --no-loopback\n";
skipping to change at line 297 skipping to change at line 368
cout << "\t d: Destination IP (or Name)\n"; cout << "\t d: Destination IP (or Name)\n";
cout << "\t p: Protocol\n"; cout << "\t p: Protocol\n";
cout << "\t s: State\n"; cout << "\t s: State\n";
cout << "\t t: TTL\n"; cout << "\t t: TTL\n";
cout << "\t b: Bytes\n"; cout << "\t b: Bytes\n";
cout << "\t P: Packets\n"; cout << "\t P: Packets\n";
cout << "\tTo sort by Source IP (or Name), don't use -b.\n"; cout << "\tTo sort by Source IP (or Name), don't use -b.\n";
cout << "\tNote that bytes/packets are only available when" cout << "\tNote that bytes/packets are only available when"
<< " supported in the kernel,\n"; << " supported in the kernel,\n";
cout << "\tand enabled with -C\n\n"; cout << "\tand enabled with -C\n\n";
cout << " -s, --src-filter <IP>\n"; cout << " -s, --src-filter <IP>[/<NETMASK>]\n";
cout << "\tOnly show states with a source of <IP>\n"; cout << "\tOnly show states with a source of <IP> and optional <NETMASK>\n";
cout << "\tNote, that this must be an IP, hostname matching is" cout << "\tNote: Hostname matching is not yet supported.\n\n";
<< " not yet supported.\n\n";
cout << " -S, --srcpt-filter <port>\n"; cout << " -S, --srcpt-filter <port>\n";
cout << "\tOnly show states with a source port of <port>\n\n"; cout << "\tOnly show states with a source port of <port>\n\n";
cout << " -t, --totals\n"; cout << " -t, --totals\n";
cout << "\tToggle display of totals\n\n"; cout << "\tToggle display of totals\n\n";
cout << "See man iptstate(8) or the interactive help for more" cout << "See man iptstate(8) or the interactive help for more"
<< " information.\n"; << " information.\n";
exit(0); exit(0);
} }
/* /*
skipping to change at line 587 skipping to change at line 657
/* /*
* Figure out the best way to get the screensize_t, and then do it * Figure out the best way to get the screensize_t, and then do it
*/ */
screensize_t get_size(const bool &single) screensize_t get_size(const bool &single)
{ {
int maxx = 0, maxy = 0; int maxx = 0, maxy = 0;
if (!single) { if (!single) {
getmaxyx(stdscr, maxy, maxx); getmaxyx(stdscr, maxy, maxx);
} else { } else {
maxx = 72; // https://stackoverflow.com/questions/1022957/
struct winsize w;
ioctl(0, TIOCGWINSZ, &w);
maxx = w.ws_col;
if (getenv("COLS")) if (getenv("COLS"))
maxx=atoi(getenv("COLS")); maxx = atoi(getenv("COLS"));
} }
screensize_t a; screensize_t a;
a.x = maxx; a.x = maxx;
a.y = maxy; a.y = maxy;
return a; return a;
} }
/* /*
skipping to change at line 682 skipping to change at line 756
* prefresh(). * prefresh().
*/ */
input = ""; input = "";
int x, y; int x, y;
getmaxyx(stdscr, y, x); getmaxyx(stdscr, y, x);
WINDOW *cmd = subpad(win, 1, x, 0, 0); WINDOW *cmd = subpad(win, 1, x, 0, 0);
if (!flags.nocolor) if (!flags.nocolor)
wattron(cmd, COLOR_PAIR(4)); wattron(cmd, COLOR_PAIR(4));
keypad(cmd, true); keypad(cmd, true);
wprintw(cmd, prompt.c_str()); wprintw(cmd, "%s", prompt.c_str());
wclrtoeol(cmd); wclrtoeol(cmd);
prefresh(cmd, 0, 0, 0, 0, 0, x); prefresh(cmd, 0, 0, 0, 0, 0, x);
int ch; int ch;
int charcount = 0; int charcount = 0;
echo(); echo();
nodelay(cmd,0); nodelay(cmd,0);
while (1) { while (1) {
ch = wgetch(cmd); ch = wgetch(cmd);
skipping to change at line 706 skipping to change at line 780
case 7: case 7:
if (ch == 7) if (ch == 7)
input = ""; input = "";
if (!flags.nocolor) if (!flags.nocolor)
wattroff(cmd, COLOR_PAIR(4)); wattroff(cmd, COLOR_PAIR(4));
delwin(cmd); delwin(cmd);
noecho(); noecho();
wmove(win, 0, 0); wmove(win, 0, 0);
return; return;
break; break;
// 8 is shift-backspace - just incase // on most platforms KEY_BACKSPACE will catch
// all backspaces...
case KEY_BACKSPACE: case KEY_BACKSPACE:
// but on some platforms ncurses fails, so ensure we catch both 8 (0x8) an
d 127 (0x7e)
// which are the two valid backspace keycodes
case 8: case 8:
case 127:
if (charcount > 0) { if (charcount > 0) {
input = input.substr(0, input.size()-1); input = input.substr(0, input.size()-1);
wechochar(cmd, '\b'); wechochar(cmd, '\b');
wechochar(cmd, ' '); wechochar(cmd, ' ');
wechochar(cmd, '\b'); wechochar(cmd, '\b');
charcount--; charcount--;
} }
break; break;
case ERR: case ERR:
continue; continue;
skipping to change at line 746 skipping to change at line 824
/* /*
* This function is here so that we can warn a user in curses, * This function is here so that we can warn a user in curses,
* usually about bad input. * usually about bad input.
*/ */
int x, y; int x, y;
getmaxyx(stdscr, y, x); getmaxyx(stdscr, y, x);
WINDOW *warn = subpad(win, 1, x, 0, 0); WINDOW *warn = subpad(win, 1, x, 0, 0);
if (!flags.nocolor) if (!flags.nocolor)
wattron(warn, COLOR_PAIR(4)); wattron(warn, COLOR_PAIR(4));
wprintw(warn, warning.c_str()); wprintw(warn, "%s", warning.c_str());
wprintw(warn, " Press any key to continue..."); wprintw(warn, " Press any key to continue...");
wclrtoeol(warn); wclrtoeol(warn);
prefresh(warn, 0, 0, 0, 0, 0, x); prefresh(warn, 0, 0, 0, 0, 0, x);
while ((y = getch())) { while ((y = getch())) {
if (y != ERR) { if (y != ERR) {
break; break;
} }
prefresh(warn, 0, 0, 0, 0, 0, x); prefresh(warn, 0, 0, 0, 0, 0, x);
} }
if (!flags.nocolor) if (!flags.nocolor)
skipping to change at line 919 skipping to change at line 997
nfct_set_attr_u8(ct, ATTR_ICMP_TYPE, atoi(type.c_str())); nfct_set_attr_u8(ct, ATTR_ICMP_TYPE, atoi(type.c_str()));
nfct_set_attr_u8(ct, ATTR_ICMP_CODE, atoi(code.c_str())); nfct_set_attr_u8(ct, ATTR_ICMP_CODE, atoi(code.c_str()));
nfct_set_attr_u16(ct, ATTR_ICMP_ID, atoi(id.c_str())); nfct_set_attr_u16(ct, ATTR_ICMP_ID, atoi(id.c_str()));
} }
ret = nfct_query(cth, NFCT_Q_DESTROY, ct); ret = nfct_query(cth, NFCT_Q_DESTROY, ct);
if (ret < 0) { if (ret < 0) {
string msg = "Failed to delete state: "; string msg = "Failed to delete state: ";
msg += strerror(errno); msg += strerror(errno);
c_warn(win, msg.c_str(), flags); c_warn(win, msg, flags);
} }
} }
/* /*
* CORE FUNCTIONS * CORE FUNCTIONS
*/ */
/* /*
* Callback for conntrack * Callback for conntrack
skipping to change at line 997 skipping to change at line 1075
entry->proto = "icmp6"; entry->proto = "icmp6";
} }
// ttl // ttl
seconds = nfct_get_attr_u32(ct, ATTR_TIMEOUT); seconds = nfct_get_attr_u32(ct, ATTR_TIMEOUT);
minutes = seconds/60; minutes = seconds/60;
hours = minutes/60; hours = minutes/60;
minutes = minutes%60; minutes = minutes%60;
seconds = seconds%60; seconds = seconds%60;
// Format it with snprintf and store it in the table // Format it with snprintf and store it in the table
snprintf(ttlc,11, "%3i:%02i:%02i", hours, minutes, seconds); snprintf(ttlc, 11, "%3i:%02i:%02i", hours, minutes, seconds);
entry->ttl = ttlc; entry->ttl = ttlc;
entry->family = nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO); entry->family = nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO);
// Everything has addresses // Everything has addresses
if (entry->family == AF_INET) { if (entry->family == AF_INET) {
memcpy(entry->src.s6_addr, nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC), memcpy(entry->src.s6_addr, nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC),
sizeof(uint8_t[16])); sizeof(uint8_t[16]));
memcpy(entry->dst.s6_addr, nfct_get_attr(ct, ATTR_ORIG_IPV4_DST), memcpy(entry->dst.s6_addr, nfct_get_attr(ct, ATTR_ORIG_IPV4_DST),
sizeof(uint8_t[16])); sizeof(uint8_t[16]));
} else if (entry->family == AF_INET6) { } else if (entry->family == AF_INET6) {
skipping to change at line 1084 skipping to change at line 1162
: !memcmp(&(entry->src), &lb6, sizeof(in6_addr)))) { : !memcmp(&(entry->src), &lb6, sizeof(in6_addr)))) {
counts->skipped++; counts->skipped++;
return NFCT_CB_CONTINUE; return NFCT_CB_CONTINUE;
} }
if (flags->skipdns && (entry->dstpt == 53)) { if (flags->skipdns && (entry->dstpt == 53)) {
counts->skipped++; counts->skipped++;
return NFCT_CB_CONTINUE; return NFCT_CB_CONTINUE;
} }
if (flags->filter_src && (memcmp(&(entry->src), &(filters->src), entrysize))) if (flags->filter_src && !filters->has_srcnet) {
{ if ((flags->filter_inv && !memcmp(&(entry->src), &(filters->src), entrysize)
counts->skipped++; ) ||
return NFCT_CB_CONTINUE; (!flags->filter_inv && memcmp(&(entry->src), &(filters->src), entrysize)
)) {
counts->skipped++;
return NFCT_CB_CONTINUE;
}
} }
if (flags->filter_srcpt && (entry->srcpt != filters->srcpt)) { if (flags->filter_src && filters->has_srcnet) {
counts->skipped++; if ((flags->filter_inv && match_netmask(entry->family, entry->src, filters->
return NFCT_CB_CONTINUE; src, filters->srcnet)) ||
(!flags->filter_inv && !match_netmask(entry->family, entry->src, filters
->src, filters->srcnet))) {
counts->skipped++;
return NFCT_CB_CONTINUE;
}
} }
if (flags->filter_dst && (memcmp(&(entry->dst), &(filters->dst), entrysize))) if (flags->filter_srcpt) {
{ if ((flags->filter_inv && entry->srcpt == filters->srcpt) ||
counts->skipped++; (!flags->filter_inv && entry->srcpt != filters->srcpt)) {
return NFCT_CB_CONTINUE; counts->skipped++;
return NFCT_CB_CONTINUE;
}
} }
if (flags->filter_dstpt && (entry->dstpt != filters->dstpt)) { if (flags->filter_dst && !filters->has_dstnet) {
counts->skipped++; if ((flags->filter_inv && !memcmp(&(entry->dst), &(filters->dst), entrysize)
return NFCT_CB_CONTINUE; ) ||
(!flags->filter_inv && memcmp(&(entry->dst), &(filters->dst), entrysize)
)) {
counts->skipped++;
return NFCT_CB_CONTINUE;
}
}
if (flags->filter_dst && filters->has_dstnet) {
if ((flags->filter_inv && match_netmask(entry->family, entry->dst, filters->
dst, filters->dstnet)) ||
(!flags->filter_inv && !match_netmask(entry->family, entry->dst, filters
->dst, filters->dstnet))) {
counts->skipped++;
return NFCT_CB_CONTINUE;
}
}
if (flags->filter_dstpt) {
if ((flags->filter_inv && entry->dstpt == filters->dstpt) ||
(!flags->filter_inv && entry->dstpt != filters->dstpt)) {
counts->skipped++;
return NFCT_CB_CONTINUE;
}
} }
/* /*
* RESOLVE * RESOLVE
*/ */
// Resolve names - if necessary - or generate strings of address, // Resolve names - if necessary - or generate strings of address,
// and calculate max sizes // and calculate max sizes
stringify_entry(entry, *max, *flags); stringify_entry(entry, *max, *flags);
skipping to change at line 1321 skipping to change at line 1427
} }
bool printed_a_filter = false; bool printed_a_filter = false;
if (flags.filter_src) { if (flags.filter_src) {
inet_ntop(filters.srcfam, &filters.src, tmp, NAMELEN-1); inet_ntop(filters.srcfam, &filters.src, tmp, NAMELEN-1);
if (flags.single) if (flags.single)
printf("src: %s", tmp); printf("src: %s", tmp);
else else
wprintw(mainwin, "src: %s", tmp); wprintw(mainwin, "src: %s", tmp);
if (filters.has_srcnet) {
if (flags.single)
printf("/%" PRIu8, filters.srcnet);
else
wprintw(mainwin, "/%" PRIu8, filters.srcnet);
}
printed_a_filter = true; printed_a_filter = true;
} }
if (flags.filter_srcpt) { if (flags.filter_srcpt) {
if (printed_a_filter) { if (printed_a_filter) {
if (flags.single) if (flags.single)
printf(", "); printf(", ");
else else
waddstr(mainwin, ", "); waddstr(mainwin, ", ");
} }
if (flags.single) if (flags.single)
skipping to change at line 1348 skipping to change at line 1460
if (flags.single) if (flags.single)
printf(", "); printf(", ");
else else
waddstr(mainwin, ", "); waddstr(mainwin, ", ");
} }
inet_ntop(filters.dstfam, &filters.dst, tmp, NAMELEN-1); inet_ntop(filters.dstfam, &filters.dst, tmp, NAMELEN-1);
if (flags.single) if (flags.single)
printf("dst: %s", tmp); printf("dst: %s", tmp);
else else
wprintw(mainwin, "dst: %s", tmp); wprintw(mainwin, "dst: %s", tmp);
if (filters.has_dstnet) {
if (flags.single)
printf("/%" PRIu8, filters.dstnet);
else
wprintw(mainwin, "/%" PRIu8, filters.dstnet);
}
printed_a_filter = true; printed_a_filter = true;
} }
if (flags.filter_dstpt) { if (flags.filter_dstpt) {
if (printed_a_filter) { if (printed_a_filter) {
if (flags.single) if (flags.single)
printf(", "); printf(", ");
else else
waddstr(mainwin, ", "); waddstr(mainwin, ", ");
} }
if (flags.single) if (flags.single)
printf("dport: %lu", filters.dstpt); printf("dport: %lu", filters.dstpt);
else else
wprintw(mainwin, "dport: %lu", filters.dstpt); wprintw(mainwin, "dport: %lu", filters.dstpt);
printed_a_filter = true; printed_a_filter = true;
} }
if (flags.filter_inv) {
if (flags.single) {
printf(" (Inverted)");
} else {
wprintw(mainwin, " (Inverted)");
}
}
if (flags.single) if (flags.single)
printf("\n"); printf("\n");
else else
wprintw(mainwin, "\n"); wprintw(mainwin, "\n");
} }
/* /*
* Print column headers * Print column headers
*/ */
if (flags.single) { if (flags.single) {
skipping to change at line 1583 skipping to change at line 1708
/* The screen must be 85 chars wide to be able to fit in /* The screen must be 85 chars wide to be able to fit in
* counters when we display IP addresses... * counters when we display IP addresses...
* *
* in lookup mode, we can truncate names, but in IP mode, * in lookup mode, we can truncate names, but in IP mode,
* truncation makes no sense, so we just disable counters if * truncation makes no sense, so we just disable counters if
* we run into this. * we run into this.
*/ */
if (ssize.x < 85 && flags.counters && !flags.lookup) { if (ssize.x < 85 && flags.counters && !flags.lookup) {
string prompt = "Window too narrow for counters! Disabling."; string prompt = "Window too narrow for counters! Disabling.";
c_warn(mainwin, prompt, flags); if (flags.single)
cerr << prompt << endl;
else
c_warn(mainwin, prompt, flags);
flags.counters = false; flags.counters = false;
} }
/* what's left is the above three, plus 4 spaces /* what's left is the above three, plus 4 spaces
* (one between each of 5 fields) * (one between each of 5 fields)
*/ */
unsigned int left = ssize.x - max.ttl - max.state - max.proto - 4; unsigned int left = ssize.x - max.ttl - max.state - max.proto - 4;
if (flags.counters) if (flags.counters)
left -= (max.bytes + max.packets + 2); left -= (max.bytes + max.packets + 2);
skipping to change at line 1698 skipping to change at line 1826
*/ */
void interactive_help(const string &sorting, const flags_t &flags, void interactive_help(const string &sorting, const flags_t &flags,
const filters_t &filters) const filters_t &filters)
{ {
/* /*
* This is the max we need the pad to be, and thus how * This is the max we need the pad to be, and thus how
* big we're going to create the pad. * big we're going to create the pad.
* *
* In many cases we'd make the pad very very large and not * In many cases we'd make the pad very very large and not
* worry about it. However, in this case: * worry about it. However, in this case, we want to draw
* 1. We know exactly how big we need it to be, and it's * a "box" around the window and if the pad is huge then
* not going to change interactively. * the box will get drawn around that.
* 2. We want to draw a "box" around the window and if the
* pad is huge then the box will get drawn around that.
* *
* So... we have 32 lines of help, plus a top and bottom border, * So... we have 41 lines of help, plus a top and bottom border,
* thus maxrows is 34. * thus maxrows is 43. We also need to account for the filter settings
* that are only being displayed when enabled.
* *
* Our help text is not wider than 80, so we'll se that standard * Our help text is not wider than 80, so we'll set that standard
* width. * width.
* *
* If the screen is bigger than this, we deal with it below. * If the screen is bigger than this, we deal with it below.
*/ */
unsigned int maxrows = 41; unsigned int maxrows = 43;
unsigned int maxcols = 80; unsigned int maxcols = 80;
// Acount for dynamic filter settings
maxrows += flags.filter_src + flags.filter_srcpt + flags.filter_dst + flags.fi
lter_dstpt;
/* /*
* The actual screen size * The actual screen size
*/ */
screensize_t ssize = get_size(flags.single); screensize_t ssize = get_size(flags.single);
/* /*
* If the biggest we think we'll need is smaller than the screen, * If the biggest we think we'll need is smaller than the screen,
* then lets grow the pad to the size of the screen so that the * then lets grow the pad to the size of the screen so that the
* main window isn't peeking through. * main window isn't peeking through.
*/ */
skipping to change at line 1839 skipping to change at line 1969
mvwaddstr(helpwin, y++, x, " Display totals: "); mvwaddstr(helpwin, y++, x, " Display totals: ");
wattron(helpwin, A_BOLD); wattron(helpwin, A_BOLD);
waddstr(helpwin,(flags.totals) ? "yes" : "no"); waddstr(helpwin,(flags.totals) ? "yes" : "no");
wattroff(helpwin, A_BOLD); wattroff(helpwin, A_BOLD);
mvwaddstr(helpwin, y++, x, " Display counters: "); mvwaddstr(helpwin, y++, x, " Display counters: ");
wattron(helpwin, A_BOLD); wattron(helpwin, A_BOLD);
waddstr(helpwin,(flags.counters) ? "yes" : "no"); waddstr(helpwin,(flags.counters) ? "yes" : "no");
wattroff(helpwin, A_BOLD); wattroff(helpwin, A_BOLD);
mvwaddstr(helpwin, y++, x, " Invert filters: ");
wattron(helpwin, A_BOLD);
waddstr(helpwin,(flags.filter_inv) ? "yes" : "no");
wattroff(helpwin, A_BOLD);
char tmp[NAMELEN]; char tmp[NAMELEN];
if (flags.filter_src) { if (flags.filter_src) {
inet_ntop(filters.srcfam, &filters.src, tmp, inet_ntop(filters.srcfam, &filters.src, tmp, NAMELEN-1);
filters.srcfam == AF_INET ? sizeof(in_addr) : sizeof(in6_addr));
mvwaddstr(helpwin, y++, x, " Source filter: "); mvwaddstr(helpwin, y++, x, " Source filter: ");
wattron(helpwin, A_BOLD); wattron(helpwin, A_BOLD);
waddstr(helpwin, tmp); waddstr(helpwin, tmp);
if (filters.has_srcnet)
wprintw(helpwin, "/%" PRIu8, filters.srcnet);
wattroff(helpwin, A_BOLD); wattroff(helpwin, A_BOLD);
} }
if (flags.filter_dst) { if (flags.filter_dst) {
inet_ntop(filters.dstfam, &filters.dst, tmp, inet_ntop(filters.dstfam, &filters.dst, tmp, NAMELEN-1);
filters.dstfam == AF_INET ? sizeof(in_addr) : sizeof(in6_addr));
mvwaddstr(helpwin, y++, x, " Destination filter: "); mvwaddstr(helpwin, y++, x, " Destination filter: ");
wattron(helpwin, A_BOLD); wattron(helpwin, A_BOLD);
waddstr(helpwin, tmp); waddstr(helpwin, tmp);
if (filters.has_dstnet)
wprintw(helpwin, "/%" PRIu8, filters.dstnet);
wattroff(helpwin, A_BOLD); wattroff(helpwin, A_BOLD);
} }
if (flags.filter_srcpt) { if (flags.filter_srcpt) {
mvwaddstr(helpwin, y++, x, " Source port filter: "); mvwaddstr(helpwin, y++, x, " Source port filter: ");
wattron(helpwin, A_BOLD); wattron(helpwin, A_BOLD);
wprintw(helpwin, "%lu", filters.srcpt); wprintw(helpwin, "%lu", filters.srcpt);
wattroff(helpwin, A_BOLD); wattroff(helpwin, A_BOLD);
} }
if (flags.filter_dstpt) { if (flags.filter_dstpt) {
mvwaddstr(helpwin, y++, x, " Destination port filter: "); mvwaddstr(helpwin, y++, x, " Destination port filter: ");
skipping to change at line 1915 skipping to change at line 2052
mvwaddstr(helpwin, y++, x, " f"); mvwaddstr(helpwin, y++, x, " f");
wattroff(helpwin, A_BOLD); wattroff(helpwin, A_BOLD);
waddstr(helpwin, "\tToggle display of loopback states"); waddstr(helpwin, "\tToggle display of loopback states");
wattron(helpwin, A_BOLD); wattron(helpwin, A_BOLD);
mvwaddstr(helpwin, y++, x, " h"); mvwaddstr(helpwin, y++, x, " h");
wattroff(helpwin, A_BOLD); wattroff(helpwin, A_BOLD);
waddstr(helpwin, "\tDisplay this help message"); waddstr(helpwin, "\tDisplay this help message");
wattron(helpwin, A_BOLD); wattron(helpwin, A_BOLD);
mvwaddstr(helpwin, y++, x, " i");
wattroff(helpwin, A_BOLD);
waddstr(helpwin, "\tInvert filters to display non-matching results");
wattron(helpwin, A_BOLD);
mvwaddstr(helpwin, y++, x, " l"); mvwaddstr(helpwin, y++, x, " l");
wattroff(helpwin, A_BOLD); wattroff(helpwin, A_BOLD);
waddstr(helpwin, "\tToggle DNS lookups"); waddstr(helpwin, "\tToggle DNS lookups");
wattron(helpwin, A_BOLD); wattron(helpwin, A_BOLD);
mvwaddstr(helpwin, y++, x, " L"); mvwaddstr(helpwin, y++, x, " L");
wattroff(helpwin, A_BOLD); wattroff(helpwin, A_BOLD);
waddstr(helpwin, "\tToggle display of outgoing DNS states"); waddstr(helpwin, "\tToggle display of outgoing DNS states");
wattron(helpwin, A_BOLD); wattron(helpwin, A_BOLD);
skipping to change at line 2117 skipping to change at line 2259
delwin(helpwin); delwin(helpwin);
refresh(); refresh();
halfdelay(1); halfdelay(1);
} }
/* /*
* MAIN * MAIN
*/ */
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
// Use the locale specified by the environment
setlocale(LC_ALL, "");
// Variables // Variables
string line, src, dst, srcpt, dstpt, proto, code, type, state, ttl, mins, string line, src, dst, srcpt, dstpt, proto, code, type, state, ttl, mins,
secs, hrs, sorting, tmpstring, format, prompt; secs, hrs, sorting, tmpstring, format, prompt;
ostringstream ostream; ostringstream ostream;
vector<tentry_t*> stable; vector<tentry_t*> stable;
int tmpint = 0, sortby = 0, rate = 1, hdrs = 0; int tmpint = 0, sortby = 0, rate = 1, hdrs = 0;
unsigned int py = 0, px = 0, curr_state = 0; unsigned int py = 0, px = 0, curr_state = 0;
timeval selecttimeout; timeval selecttimeout;
fd_set readfd; fd_set readfd;
skipping to change at line 2139 skipping to change at line 2283
screensize_t ssize; screensize_t ssize;
filters_t filters; filters_t filters;
max_t max; max_t max;
/* /*
* Initialize * Initialize
*/ */
flags.single = flags.totals = flags.lookup = flags.skiplb = flags.staticsize flags.single = flags.totals = flags.lookup = flags.skiplb = flags.staticsize
= flags.skipdns = flags.tag_truncate = flags.filter_src = flags.skipdns = flags.tag_truncate = flags.filter_src
= flags.filter_dst = flags.filter_srcpt = flags.filter_dstpt = flags.filter_dst = flags.filter_srcpt = flags.filter_dstpt
= flags.noscroll = flags.nocolor = flags.counters = false; = flags.noscroll = flags.nocolor = flags.counters = flags.filter_inv = fal se;
ssize.x = ssize.y = 0; ssize.x = ssize.y = 0;
counts.tcp = counts.udp = counts.icmp = counts.other = counts.skipped = 0; counts.tcp = counts.udp = counts.icmp = counts.other = counts.skipped = 0;
filters.src = filters.dst = in6addr_any; filters.src = filters.dst = in6addr_any;
filters.srcpt = filters.dstpt = 0; filters.srcpt = filters.dstpt = 0;
max.src = max.dst = max.proto = max.state = max.ttl = 0; max.src = max.dst = max.proto = max.state = max.ttl = 0;
px = py = 0; px = py = 0;
static struct option long_options[] = { static struct option long_options[] = {
{"counters", no_argument , 0, 'C'}, {"counters", no_argument , 0, 'C'},
{"dst-filter", required_argument, 0, 'd'}, {"dst-filter", required_argument, 0, 'd'},
{"dstpt-filter", required_argument, 0, 'D'}, {"dstpt-filter", required_argument, 0, 'D'},
{"help", no_argument, 0, 'h'}, {"help", no_argument, 0, 'h'},
{"invert-filters", no_argument, 0, 'i'},
{"lookup", no_argument, 0, 'l'}, {"lookup", no_argument, 0, 'l'},
{"mark-truncated", no_argument, 0, 'm'}, {"mark-truncated", no_argument, 0, 'm'},
{"no-color", no_argument, 0, 'c'}, {"no-color", no_argument, 0, 'c'},
{"no-dynamic", no_argument, 0, 'o'}, {"no-dynamic", no_argument, 0, 'o'},
{"no-dns", no_argument, 0, 'L'}, {"no-dns", no_argument, 0, 'L'},
{"no-loopback", no_argument, 0, 'f'}, {"no-loopback", no_argument, 0, 'f'},
{"no-scroll", no_argument, 0, 'p'}, {"no-scroll", no_argument, 0, 'p'},
{"rate", required_argument, 0, 'R'}, {"rate", required_argument, 0, 'R'},
{"reverse", no_argument, 0, 'r'}, {"reverse", no_argument, 0, 'r'},
{"single", no_argument, 0, '1'}, {"single", no_argument, 0, '1'},
{"sort", required_argument, 0, 'b'}, {"sort", required_argument, 0, 'b'},
{"src-filter", required_argument, 0, 's'}, {"src-filter", required_argument, 0, 's'},
{"srcpt-filter", required_argument, 0, 'S'}, {"srcpt-filter", required_argument, 0, 'S'},
{"totals", no_argument, 0, 't'}, {"totals", no_argument, 0, 't'},
{"version", no_argument, 0, 'v'}, {"version", no_argument, 0, 'v'},
{0, 0, 0,0} {0, 0, 0,0}
}; };
int option_index = 0; int option_index = 0;
// Command Line Arguments // Command Line Arguments
while ((tmpint = getopt_long(argc, argv, "Cd:D:hlmcoLfpR:r1b:s:S:tv", while ((tmpint = getopt_long(argc, argv, "Cd:D:hilmcoLfpR:r1b:s:S:tv",
long_options, &option_index)) != EOF) { long_options, &option_index)) != EOF) {
printf("loop: %d\n", tmpint);
switch (tmpint) { switch (tmpint) {
case 0: case 0:
/* Apparently this test is needed?! Seems lame! */ /* Apparently this test is needed?! Seems lame! */
if (long_options[option_index].flag != 0) if (long_options[option_index].flag != 0)
break; break;
/* /*
* Long-only options go here, like so: * Long-only options go here, like so:
* *
* tmpstring = long_options[option_index].name; * tmpstring = long_options[option_index].name;
skipping to change at line 2203 skipping to change at line 2347
break; break;
// --counters // --counters
case 'C': case 'C':
flags.counters = true; flags.counters = true;
break; break;
// --dst-filter // --dst-filter
case 'd': case 'd':
if (optarg == NULL) if (optarg == NULL)
break; break;
// See check_ip() note above // See check_ip() note above
if (!check_ip(optarg, &filters.dst, &filters.dstfam)) { if (!check_ip(optarg, &filters.dst, &filters.dstfam, &filters.dstnet, &fil ters.has_dstnet)) {
cerr << "Invalid IP address: " << optarg cerr << "Invalid IP address: " << optarg
<< endl; << endl;
exit(1); exit(1);
} }
flags.filter_dst = true; flags.filter_dst = true;
break; break;
// --dstpt-filter // --dstpt-filter
case 'D': case 'D':
/* /*
* even though this won't be an IP address * even though this won't be an IP address
* aton() won't complain about anything that's * aton() won't complain about anything that's
* just digits, so it's an easy check. * just digits, so it's an easy check.
*/ */
if (optarg == NULL) if (optarg == NULL)
break; break;
flags.filter_dstpt = true; flags.filter_dstpt = true;
filters.dstpt = atoi(optarg); filters.dstpt = atoi(optarg);
break; break;
// --invert-filters
case 'i':
flags.filter_inv = true;
break;
// --help // --help
case 'h': case 'h':
help(); help();
break; break;
// --lookup // --lookup
case 'l': case 'l':
flags.lookup = true; flags.lookup = true;
// and also set skipdns for sanity // and also set skipdns for sanity
flags.skipdns = true; flags.skipdns = true;
break; break;
skipping to change at line 2291 skipping to change at line 2439
sortby = SORT_PACKETS; sortby = SORT_PACKETS;
break; break;
// --single // --single
case '1': case '1':
flags.single = true; flags.single = true;
break; break;
// --src-filter // --src-filter
case 's': case 's':
if (optarg == NULL) if (optarg == NULL)
break; break;
if (!check_ip(optarg, &filters.src, &filters.srcfam)) { if (!check_ip(optarg, &filters.src, &filters.srcfam, &filters.srcnet, &fil ters.has_srcnet)) {
cerr << "Invalid IP address: " << optarg << endl; cerr << "Invalid IP address: " << optarg << endl;
exit(1); exit(1);
} }
flags.filter_src = true; flags.filter_src = true;
break; break;
// --srcpt-filter // --srcpt-filter
case 'S': case 'S':
if (optarg == NULL) if (optarg == NULL)
break; break;
flags.filter_srcpt = true; flags.filter_srcpt = true;
skipping to change at line 2403 skipping to change at line 2551
* valid. * valid.
* *
* Conversely checking is_set and then get_attr() inside our * Conversely checking is_set and then get_attr() inside our
* callback is twice the calls per-state if they are enabled, * callback is twice the calls per-state if they are enabled,
* for no additional benefit. * for no additional benefit.
*/ */
if (flags.counters && stable.size() > 0 && stable[0]->bytes == 0) { if (flags.counters && stable.size() > 0 && stable[0]->bytes == 0) {
prompt = "Counters requested, but not enabled in the"; prompt = "Counters requested, but not enabled in the";
prompt += " kernel!"; prompt += " kernel!";
flags.counters = 0; flags.counters = 0;
c_warn(mainwin, prompt, flags); if (flags.single)
cerr << prompt << endl;
else
c_warn(mainwin, prompt, flags);
} }
// Sort our table // Sort our table
sort_table(sortby, flags.lookup, sort_factor, stable, sorting); sort_table(sortby, flags.lookup, sort_factor, stable, sorting);
/* /*
* From here on out 'max' is no longer "the maximum size of * From here on out 'max' is no longer "the maximum size of
* this field throughout the table", but is instead the actual * this field throughout the table", but is instead the actual
* size to print each field. * size to print each field.
* *
skipping to change at line 2478 skipping to change at line 2629
flags.nocolor = !flags.nocolor; flags.nocolor = !flags.nocolor;
break; break;
case 'C': case 'C':
flags.counters = !flags.counters; flags.counters = !flags.counters;
if (sortby >= SORT_BYTES) if (sortby >= SORT_BYTES)
sortby = SORT_BYTES-1; sortby = SORT_BYTES-1;
break; break;
case 'h': case 'h':
interactive_help(sorting, flags, filters); interactive_help(sorting, flags, filters);
break; break;
case 'i':
flags.filter_inv = !flags.filter_inv;
break;
case 'l': case 'l':
flags.lookup = !flags.lookup; flags.lookup = !flags.lookup;
/* /*
* If we just turned on lookup, also turn on filtering DNS states. * If we just turned on lookup, also turn on filtering DNS states.
* They can turn it off if they want, but generally this is the safer * They can turn it off if they want, but generally this is the safer
* approach. * approach.
*/ */
if (flags.lookup) { if (flags.lookup) {
flags.skipdns = true; flags.skipdns = true;
} }
skipping to change at line 2540 skipping to change at line 2694
* Update-filters * Update-filters
*/ */
case 'd': case 'd':
prompt = "New Destination Filter? (leave blank"; prompt = "New Destination Filter? (leave blank";
prompt += " for none): "; prompt += " for none): ";
get_input(mainwin, tmpstring, prompt, flags); get_input(mainwin, tmpstring, prompt, flags);
if (tmpstring == "") { if (tmpstring == "") {
flags.filter_dst = false; flags.filter_dst = false;
filters.dst = in6addr_any; filters.dst = in6addr_any;
} else { } else {
if (!check_ip(tmpstring.c_str(), &filters.dst, &filters.dstfam)) { if (!check_ip(tmpstring.c_str(), &filters.dst, &filters.dstfam, &filte rs.dstnet, &filters.has_dstnet)) {
prompt = "Invalid IP,"; prompt = "Invalid IP,";
prompt += " ignoring!"; prompt += " ignoring!";
c_warn(mainwin, prompt, flags); c_warn(mainwin, prompt, flags);
} else { } else {
flags.filter_dst = true; flags.filter_dst = true;
} }
} }
break; break;
case 'D': case 'D':
prompt = "New dstpt filter? (leave blank for"; prompt = "New dstpt filter? (leave blank for";
skipping to change at line 2585 skipping to change at line 2739
} }
break; break;
case 's': case 's':
prompt = "New src filter? (leave blank for"; prompt = "New src filter? (leave blank for";
prompt += " none): "; prompt += " none): ";
get_input(mainwin, tmpstring, prompt, flags); get_input(mainwin, tmpstring, prompt, flags);
if (tmpstring == "") { if (tmpstring == "") {
flags.filter_src = false; flags.filter_src = false;
filters.src = in6addr_any; filters.src = in6addr_any;
} else { } else {
if (!check_ip(tmpstring.c_str(), &filters.src, &filters.srcfam)) { if (!check_ip(tmpstring.c_str(), &filters.src, &filters.srcfam, &filte rs.srcnet, &filters.has_srcnet)) {
prompt = "Invalid IP,"; prompt = "Invalid IP,";
prompt += " ignoring!"; prompt += " ignoring!";
c_warn(mainwin, prompt, flags); c_warn(mainwin, prompt, flags);
} else { } else {
flags.filter_src = true; flags.filter_src = true;
} }
} }
wmove(mainwin, 0, 0); wmove(mainwin, 0, 0);
wclrtoeol(mainwin); wclrtoeol(mainwin);
break; break;
 End of changes. 55 change blocks. 
57 lines changed or deleted 221 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)