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 |