|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* vim:textwidth=80:tabstop=2:shiftwidth=2:expandtab:ai
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* iptstate.cc
|
|
Packit |
021a8a |
* IPTables State
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* -----------------------------------
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* Copyright (C) 2002 - present Phil Dibowitz
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* This software is provided 'as-is', without any express or
|
|
Packit |
021a8a |
* implied warranty. In no event will the authors be held
|
|
Packit |
021a8a |
* liable for any damages arising from the use of this software.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* Permission is granted to anyone to use this software for any
|
|
Packit |
021a8a |
* purpose, including commercial applications, and to alter it
|
|
Packit |
021a8a |
* and redistribute it freely, subject to the following restrictions:
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* 1. The origin of this software must not be misrepresented; you
|
|
Packit |
021a8a |
* must not claim that you wrote the original software. If you use
|
|
Packit |
021a8a |
* this software in a product, an acknowledgment in the product
|
|
Packit |
021a8a |
* documentation would be appreciated but is not required.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* 2. Altered source versions must be plainly marked as such, and
|
|
Packit |
021a8a |
* must not be misrepresented as being the original software.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* 3. This notice may not be removed or altered from any source
|
|
Packit |
021a8a |
* distribution.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* -----------------------------------
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* The idea of statetop comes from IP Filter by Darren Reed.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* This package's main purpose is to provide a state-top type
|
|
Packit |
021a8a |
* interface for IP Tables. I've added in the "single run"
|
|
Packit |
021a8a |
* option since there's no nice way to do that either.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* NOTE: If you are planning on packaging and/or submitting my software for/to
|
|
Packit |
021a8a |
* a Linux distribution, I would appreciate a heads up.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
#include <cerrno>
|
|
Packit |
021a8a |
#include <cmath>
|
|
Packit |
021a8a |
#include <csignal>
|
|
Packit |
021a8a |
#include <cstdlib>
|
|
Packit |
021a8a |
#include <cstring>
|
|
Packit |
021a8a |
#include <ctime>
|
|
Packit |
021a8a |
#include <fstream>
|
|
Packit |
021a8a |
#include <iostream>
|
|
Packit |
021a8a |
#include <sstream>
|
|
Packit |
021a8a |
#include <string>
|
|
Packit |
021a8a |
#include <vector>
|
|
Packit |
021a8a |
#include <algorithm>
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// There are no C++-ified versions of these.
|
|
Packit |
021a8a |
#include <arpa/inet.h>
|
|
Packit |
021a8a |
#include <getopt.h>
|
|
Packit |
021a8a |
extern "C" {
|
|
Packit |
021a8a |
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
|
|
Packit |
021a8a |
};
|
|
Packit |
021a8a |
#include <netdb.h>
|
|
Packit |
021a8a |
#include <ncurses.h>
|
|
Packit |
021a8a |
#include <unistd.h>
|
|
Packit |
021a8a |
using namespace std;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
#define VERSION "2.2.6"
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* MAXCONS is set to 16k, the default number of states in iptables. Generally
|
|
Packit |
021a8a |
* speaking the ncurses pad is this many lines long, but since ncurses
|
|
Packit |
021a8a |
* uses a short for their dimensions, a pad can never be longer than 32767.
|
|
Packit |
021a8a |
* Thus we define both of these values and NLINES as the lesser of the two.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
#define MAXCONS 16384
|
|
Packit |
021a8a |
#define MAXLINES 32767
|
|
Packit |
021a8a |
#if MAXCONS < MAXLINES
|
|
Packit |
021a8a |
#define NLINES MAXCONS
|
|
Packit |
021a8a |
#else
|
|
Packit |
021a8a |
#define NLINES MAXLINES
|
|
Packit |
021a8a |
#endif
|
|
Packit |
021a8a |
#define MAXFIELDS 20
|
|
Packit |
021a8a |
// This is the default format string if we don't dynamically determine it
|
|
Packit |
021a8a |
#define DEFAULT_FORMAT "%-21s %-21s %-7s %-12s %-9s\n"
|
|
Packit |
021a8a |
// The following MUST be the same as the above
|
|
Packit |
021a8a |
#define DEFAULT_SRC 21
|
|
Packit |
021a8a |
#define DEFAULT_DST 21
|
|
Packit |
021a8a |
#define DEFAULT_PROTO 7
|
|
Packit |
021a8a |
#define DEFAULT_STATE 12
|
|
Packit |
021a8a |
#define DEFAULT_TTL 9
|
|
Packit |
021a8a |
// This is the format string for the "totals" line, always.
|
|
Packit |
021a8a |
#define TOTALS_FORMAT \
|
|
Packit |
021a8a |
"Total States: %i -- TCP: %i UDP: %i ICMP: %i Other: %i (Filtered: %i)\n"
|
|
Packit |
021a8a |
// Options for truncating from the front or the back
|
|
Packit |
021a8a |
#define TRUNC_FRONT 0
|
|
Packit |
021a8a |
#define TRUNC_END 1
|
|
Packit |
021a8a |
// maxlength for string we pass to inet_ntop()
|
|
Packit |
021a8a |
#define NAMELEN 100
|
|
Packit |
021a8a |
// Sorting options
|
|
Packit |
021a8a |
#define SORT_SRC 0
|
|
Packit |
021a8a |
#define SORT_SRC_PT 1
|
|
Packit |
021a8a |
#define SORT_DST 2
|
|
Packit |
021a8a |
#define SORT_DST_PT 3
|
|
Packit |
021a8a |
#define SORT_PROTO 4
|
|
Packit |
021a8a |
#define SORT_STATE 5
|
|
Packit |
021a8a |
#define SORT_TTL 6
|
|
Packit |
021a8a |
#define SORT_BYTES 7
|
|
Packit |
021a8a |
#define SORT_PACKETS 8
|
|
Packit |
021a8a |
#define SORT_MAX 8
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* GLOBAL CONSTANTS
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* GLOBAL VARS
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
int sort_factor = 1;
|
|
Packit |
021a8a |
bool need_resize = false;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/* shameless stolen from libnetfilter_conntrack_tcp.c */
|
|
Packit |
021a8a |
static const char *states[] = {
|
|
Packit |
021a8a |
"NONE",
|
|
Packit |
021a8a |
"SYN_SENT",
|
|
Packit |
021a8a |
"SYN_RECV",
|
|
Packit |
021a8a |
"ESTABLISHED",
|
|
Packit |
021a8a |
"FIN_WAIT",
|
|
Packit |
021a8a |
"CLOSE_WAIT",
|
|
Packit |
021a8a |
"LAST_ACK",
|
|
Packit |
021a8a |
"TIME_WAIT",
|
|
Packit |
021a8a |
"CLOSE",
|
|
Packit |
021a8a |
"LISTEN"
|
|
Packit |
021a8a |
};
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* STRUCTS
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
// One state-table entry
|
|
Packit |
021a8a |
struct tentry_t {
|
|
Packit |
021a8a |
string proto, state, ttl, sname, dname, spname, dpname;
|
|
Packit |
021a8a |
in6_addr src, dst;
|
|
Packit |
021a8a |
uint8_t family;
|
|
Packit |
021a8a |
unsigned long srcpt, dstpt, bytes, packets, s;
|
|
Packit |
021a8a |
};
|
|
Packit |
021a8a |
// x/y of the terminal window
|
|
Packit |
021a8a |
struct screensize_t {
|
|
Packit |
021a8a |
unsigned int x, y;
|
|
Packit |
021a8a |
};
|
|
Packit |
021a8a |
// Struct 'o flags
|
|
Packit |
021a8a |
struct flags_t {
|
|
Packit |
021a8a |
bool single, totals, lookup, skiplb, staticsize, skipdns, tag_truncate,
|
|
Packit |
021a8a |
filter_src, filter_dst, filter_srcpt, filter_dstpt, noscroll, nocolor,
|
|
Packit |
021a8a |
counters;
|
|
Packit |
021a8a |
};
|
|
Packit |
021a8a |
// Struct 'o counters
|
|
Packit |
021a8a |
struct counters_t {
|
|
Packit |
021a8a |
unsigned int total, tcp, udp, icmp, other, skipped;
|
|
Packit |
021a8a |
};
|
|
Packit |
021a8a |
// Various filters to be applied pending the right flags in flags_t
|
|
Packit |
021a8a |
struct filters_t {
|
|
Packit |
021a8a |
in6_addr src, dst;
|
|
Packit |
021a8a |
uint8_t srcfam, dstfam;
|
|
Packit |
021a8a |
unsigned long srcpt, dstpt;
|
|
Packit |
021a8a |
};
|
|
Packit |
021a8a |
// The max-length of fields in the stable table
|
|
Packit |
021a8a |
struct max_t {
|
|
Packit |
021a8a |
unsigned int src, dst, proto, state, ttl;
|
|
Packit |
021a8a |
unsigned long bytes, packets;
|
|
Packit |
021a8a |
};
|
|
Packit |
021a8a |
struct hook_data {
|
|
Packit |
021a8a |
vector<tentry_t*> *stable;
|
|
Packit |
021a8a |
flags_t *flags;
|
|
Packit |
021a8a |
max_t *max;
|
|
Packit |
021a8a |
counters_t *counts;
|
|
Packit |
021a8a |
const filters_t *filters;
|
|
Packit |
021a8a |
};
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* GENERAL HELPER FUNCTIONS
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* split a string into two strings based on the first occurance
|
|
Packit |
021a8a |
* of any character
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
void split(char s, string line, string &p1, string &p2)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
int pos = line.find(s);
|
|
Packit |
021a8a |
p1 = line.substr(0, pos);
|
|
Packit |
021a8a |
p2 = line.substr(pos+1, line.size()-pos);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* split a string into an array of strings based on
|
|
Packit |
021a8a |
* any character
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
void splita(char s, string line, vector<string> &result)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
int pos, size;
|
|
Packit |
021a8a |
int i=0;
|
|
Packit |
021a8a |
string temp, temp1;
|
|
Packit |
021a8a |
temp = line;
|
|
Packit |
021a8a |
while ((temp.find(s) != string::npos) && (i < MAXFIELDS-1)) {
|
|
Packit |
021a8a |
pos = temp.find(s);
|
|
Packit |
021a8a |
result[i] = temp.substr(0, pos);
|
|
Packit |
021a8a |
size = temp.size();
|
|
Packit |
021a8a |
temp = temp.substr(pos+1, size-pos-1);
|
|
Packit |
021a8a |
if (result[i] != "") {
|
|
Packit |
021a8a |
i++;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
result[i] = temp;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* This determines the length of an integer (i.e. number of digits)
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
unsigned int digits(unsigned long x)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
return (unsigned int) floor(log10((double)x))+1;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Check to ensure an IP is valid
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
bool check_ip(const char *arg, in6_addr *addr, uint8_t *family)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
int ret;
|
|
Packit |
021a8a |
ret = inet_pton(AF_INET6, arg, addr);
|
|
Packit |
021a8a |
if (ret) {
|
|
Packit |
021a8a |
*family = AF_INET6;
|
|
Packit |
021a8a |
return true;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
ret = inet_pton(AF_INET, arg, addr);
|
|
Packit |
021a8a |
if (ret) {
|
|
Packit |
021a8a |
*family = AF_INET;
|
|
Packit |
021a8a |
return true;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
return false;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* The help
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
void version()
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
cout << "IPTables State Top Version " << VERSION << endl << endl;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
void help()
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
cout << "IPTables State Top Version " << VERSION << endl;
|
|
Packit |
021a8a |
cout << "Usage: iptstate [<options>]\n\n";
|
|
Packit |
021a8a |
cout << " -c, --no-color\n";
|
|
Packit |
021a8a |
cout << "\tToggle color-code by protocol\n\n";
|
|
Packit |
021a8a |
cout << " -C, --counters\n";
|
|
Packit |
021a8a |
cout << "\tToggle display of bytes/packets counters\n\n";
|
|
Packit |
021a8a |
cout << " -d, --dst-filter <IP>\n";
|
|
Packit |
021a8a |
cout << "\tOnly show states with a destination of <IP>\n";
|
|
Packit |
021a8a |
cout << "\tNote, that this must be an IP, hostname matching is"
|
|
Packit |
021a8a |
<< " not yet supported.\n\n";
|
|
Packit |
021a8a |
cout << " -D --dstpt-filter <port>\n";
|
|
Packit |
021a8a |
cout << "\tOnly show states with a destination port of <port>\n\n";
|
|
Packit |
021a8a |
cout << " -h, --help\n";
|
|
Packit |
021a8a |
cout << "\tThis help message\n\n";
|
|
Packit |
021a8a |
cout << " -l, --lookup\n";
|
|
Packit |
021a8a |
cout << "\tShow hostnames instead of IP addresses. Enabling this will also"
|
|
Packit |
021a8a |
<< " enable\n\t-L to prevent an ever-growing number of DNS requests.\n\n";
|
|
Packit |
021a8a |
cout << " -m, --mark-truncated\n";
|
|
Packit |
021a8a |
cout << "\tMark truncated hostnames with a '+'\n\n";
|
|
Packit |
021a8a |
cout << " -o, --no-dynamic\n";
|
|
Packit |
021a8a |
cout << "\tToggle dynamic formatting\n\n";
|
|
Packit |
021a8a |
cout << " -L, --no-dns\n";
|
|
Packit |
021a8a |
cout << "\tSkip outgoing DNS lookup states\n\n";
|
|
Packit |
021a8a |
cout << " -f, --no-loopback\n";
|
|
Packit |
021a8a |
cout << "\tFilter states on loopback\n\n";
|
|
Packit |
021a8a |
cout << " -p, --no-scroll\n";
|
|
Packit |
021a8a |
cout << "\tNo scrolling (don't use a \"pad\")\n\n";
|
|
Packit |
021a8a |
cout << " -r, --reverse\n";
|
|
Packit |
021a8a |
cout << "\tReverse sort order\n\n";
|
|
Packit |
021a8a |
cout << " -R, --rate <seconds>\n";
|
|
Packit |
021a8a |
cout << "\tRefresh rate, followed by rate in seconds\n";
|
|
Packit |
021a8a |
cout << "\tNote: For statetop, not applicable for -s\n\n";
|
|
Packit |
021a8a |
cout << " -1, --single\n";
|
|
Packit |
021a8a |
cout << "\tSingle run (no curses)\n\n";
|
|
Packit |
021a8a |
cout << " -b, --sort <column>\n";
|
|
Packit |
021a8a |
cout << "\tThis determines what column to sort by. Options:\n";
|
|
Packit |
021a8a |
cout << "\t d: Destination IP (or Name)\n";
|
|
Packit |
021a8a |
cout << "\t p: Protocol\n";
|
|
Packit |
021a8a |
cout << "\t s: State\n";
|
|
Packit |
021a8a |
cout << "\t t: TTL\n";
|
|
Packit |
021a8a |
cout << "\t b: Bytes\n";
|
|
Packit |
021a8a |
cout << "\t P: Packets\n";
|
|
Packit |
021a8a |
cout << "\tTo sort by Source IP (or Name), don't use -b.\n";
|
|
Packit |
021a8a |
cout << "\tNote that bytes/packets are only available when"
|
|
Packit |
021a8a |
<< " supported in the kernel,\n";
|
|
Packit |
021a8a |
cout << "\tand enabled with -C\n\n";
|
|
Packit |
021a8a |
cout << " -s, --src-filter <IP>\n";
|
|
Packit |
021a8a |
cout << "\tOnly show states with a source of <IP>\n";
|
|
Packit |
021a8a |
cout << "\tNote, that this must be an IP, hostname matching is"
|
|
Packit |
021a8a |
<< " not yet supported.\n\n";
|
|
Packit |
021a8a |
cout << " -S, --srcpt-filter <port>\n";
|
|
Packit |
021a8a |
cout << "\tOnly show states with a source port of <port>\n\n";
|
|
Packit |
021a8a |
cout << " -t, --totals\n";
|
|
Packit |
021a8a |
cout << "\tToggle display of totals\n\n";
|
|
Packit |
021a8a |
cout << "See man iptstate(8) or the interactive help for more"
|
|
Packit |
021a8a |
<< " information.\n";
|
|
Packit |
021a8a |
exit(0);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Resolve hostnames
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
void resolve_host(const uint8_t &family, const in6_addr &ip, string &name)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
struct hostent *hostinfo = NULL;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if ((hostinfo = gethostbyaddr((char *)&ip, sizeof(ip), family)) != NULL) {
|
|
Packit |
021a8a |
name = hostinfo->h_name;
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
char str[NAMELEN];
|
|
Packit |
021a8a |
name = inet_ntop(family, (void *)&ip, str, NAMELEN-1) ;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
void resolve_port(const unsigned int &port, string &name, const string &proto)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
struct servent *portinfo = NULL;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if ((portinfo = getservbyport(htons(port), proto.c_str())) != NULL) {
|
|
Packit |
021a8a |
name = portinfo->s_name;
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
ostringstream buf;
|
|
Packit |
021a8a |
buf.str("");
|
|
Packit |
021a8a |
buf << port;
|
|
Packit |
021a8a |
name = buf.str();
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* If lookup mode is on, we lookup the names and put them in the structure.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* If lookup mode is not on, we generate strings of the addresses and put
|
|
Packit |
021a8a |
* those in the structure.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* Finally, we update the max_t structure.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* NOTE: We stringify addresses largely because in the IPv6 case we need
|
|
Packit |
021a8a |
* to treat them like truncate-able strings.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
void stringify_entry(tentry_t *entry, max_t &max, const flags_t &flags)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
unsigned int size = 0;
|
|
Packit |
021a8a |
ostringstream buffer;
|
|
Packit |
021a8a |
char tmp[NAMELEN];
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
bool have_port = entry->proto == "tcp" || entry->proto == "udp";
|
|
Packit |
021a8a |
if (!have_port) {
|
|
Packit |
021a8a |
entry->spname = entry->dpname = "";
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (flags.lookup) {
|
|
Packit |
021a8a |
resolve_host(entry->family, entry->src, entry->sname);
|
|
Packit |
021a8a |
resolve_host(entry->family, entry->dst, entry->dname);
|
|
Packit |
021a8a |
if (have_port) {
|
|
Packit |
021a8a |
resolve_port(entry->srcpt, entry->spname, entry->proto);
|
|
Packit |
021a8a |
resolve_port(entry->dstpt, entry->dpname, entry->proto);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
buffer << inet_ntop(entry->family, (void*)&(entry->src), tmp, NAMELEN-1);
|
|
Packit |
021a8a |
entry->sname = buffer.str();
|
|
Packit |
021a8a |
buffer.str("");
|
|
Packit |
021a8a |
buffer << inet_ntop(entry->family, (void*)&(entry->dst), tmp, NAMELEN-1);
|
|
Packit |
021a8a |
entry->dname = buffer.str();
|
|
Packit |
021a8a |
buffer.str("");
|
|
Packit |
021a8a |
if (have_port) {
|
|
Packit |
021a8a |
buffer << entry->srcpt;
|
|
Packit |
021a8a |
entry->spname = buffer.str();
|
|
Packit |
021a8a |
buffer.str("");
|
|
Packit |
021a8a |
buffer << entry->dstpt;
|
|
Packit |
021a8a |
entry->dpname = buffer.str();
|
|
Packit |
021a8a |
buffer.str("");
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
size = entry->sname.size() + entry->spname.size() + 1;
|
|
Packit |
021a8a |
if (size > max.src)
|
|
Packit |
021a8a |
max.src = size;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
size = entry->dname.size() + entry->dpname.size() + 1;
|
|
Packit |
021a8a |
if (size > max.dst)
|
|
Packit |
021a8a |
max.dst = size;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* SORT FUNCTIONS
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
bool src_sort(tentry_t *one, tentry_t *two)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* memcmp() will properly sort v4 or v6 addresses, but not cross-family
|
|
Packit |
021a8a |
* (presumably because of garbage in the top 96 bytes when you store
|
|
Packit |
021a8a |
* a v4 address in a in6_addr), so we sort by family and then memcmp()
|
|
Packit |
021a8a |
* within the same family.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (one->family == two->family) {
|
|
Packit |
021a8a |
return memcmp(one->src.s6_addr, two->src.s6_addr, 16) * sort_factor < 0;
|
|
Packit |
021a8a |
} else if (one->family == AF_INET) {
|
|
Packit |
021a8a |
return sort_factor > 0;
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
return sort_factor < 0;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
bool srcname_sort(tentry_t *one, tentry_t *two)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
return one->sname.compare(two->sname) * sort_factor < 0;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
bool dst_sort(tentry_t *one, tentry_t *two)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
// See src_sort() for details
|
|
Packit |
021a8a |
if (one->family == two->family) {
|
|
Packit |
021a8a |
return memcmp(one->dst.s6_addr, two->dst.s6_addr, 16) * sort_factor < 0;
|
|
Packit |
021a8a |
} else if (one->family == AF_INET) {
|
|
Packit |
021a8a |
return sort_factor > 0;
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
return sort_factor < 0;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
bool dstname_sort(tentry_t *one, tentry_t *two)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
return one->dname.compare(two->dname) * sort_factor < 0;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* int comparison that takes care of sort_factor
|
|
Packit |
021a8a |
* used for ports, bytes, etc...
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
bool cmpint(int one, int two)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
return (sort_factor > 0) ? one < two : one > two;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
bool srcpt_sort(tentry_t *one, tentry_t *two)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
return cmpint(one->srcpt, two->srcpt);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
bool dstpt_sort(tentry_t *one, tentry_t *two)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
return cmpint(one->dstpt, two->dstpt);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
bool proto_sort(tentry_t *one, tentry_t *two)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
return one->proto.compare(two->proto) * sort_factor < 0;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
bool state_sort(tentry_t *one, tentry_t *two)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
return one->state.compare(two->state) * sort_factor < 0;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
bool ttl_sort(tentry_t *one, tentry_t *two)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
return one->ttl.compare(two->ttl) * sort_factor < 0;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
bool bytes_sort(tentry_t *one, tentry_t *two)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
return cmpint(one->bytes, two->bytes);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
bool packets_sort(tentry_t *one, tentry_t *two)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
return cmpint(one->packets, two->packets);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* CURSES HELPER FUNCTIONS
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Finish-up for curses environment
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
void end_curses()
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
curs_set(1);
|
|
Packit |
021a8a |
nocbreak();
|
|
Packit |
021a8a |
endwin();
|
|
Packit |
021a8a |
cout << endl;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* SIGWINCH signal handler.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
void winch_handler(int sig)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
sigset_t mask_set;
|
|
Packit |
021a8a |
sigset_t old_set;
|
|
Packit |
021a8a |
// Reset signal handler
|
|
Packit |
021a8a |
signal(28, winch_handler);
|
|
Packit |
021a8a |
// ignore this signal for a bit
|
|
Packit |
021a8a |
sigfillset(&mask_set);
|
|
Packit |
021a8a |
sigprocmask(SIG_SETMASK, &mask_set, &old_set);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
need_resize = true;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* SIGKILL signal handler
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
void kill_handler(int sig)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
end_curses();
|
|
Packit |
021a8a |
printf("Caught signal %d, cleaning up.\n", sig);
|
|
Packit |
021a8a |
exit(0);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Start-up for curses environment
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* NOTE: That by default we create a pad. A pad is a special type of window that
|
|
Packit |
021a8a |
* can be bigger than the screen. See the comments in interactive_help()
|
|
Packit |
021a8a |
* below for how to use it and how it works.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* However, pad's lack the double-buffering and other features of standard
|
|
Packit |
021a8a |
* ncurses windows and thus can appear slower. Thus we allow the user to
|
|
Packit |
021a8a |
* downgrade to standard windows if they choose. See the comments
|
|
Packit |
021a8a |
* switch_scroll() for more details.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
static WINDOW* start_curses(flags_t &flags)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
int y, x;
|
|
Packit |
021a8a |
initscr();
|
|
Packit |
021a8a |
cbreak();
|
|
Packit |
021a8a |
noecho();
|
|
Packit |
021a8a |
halfdelay(1);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* If we're starting curses, we care about SIGWNCH, SIGINT, and SIGTERM
|
|
Packit |
021a8a |
* so this seems like as good a place as any to setup our signal
|
|
Packit |
021a8a |
* handler.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
// Resize
|
|
Packit |
021a8a |
signal(28, winch_handler);
|
|
Packit |
021a8a |
// Shutdown
|
|
Packit |
021a8a |
signal(2, kill_handler);
|
|
Packit |
021a8a |
signal(15, kill_handler);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (has_colors()) {
|
|
Packit |
021a8a |
start_color();
|
|
Packit |
021a8a |
// for tcp
|
|
Packit |
021a8a |
init_pair(1, COLOR_GREEN, COLOR_BLACK);
|
|
Packit |
021a8a |
// for udp
|
|
Packit |
021a8a |
init_pair(2, COLOR_YELLOW, COLOR_BLACK);
|
|
Packit |
021a8a |
// for icmp
|
|
Packit |
021a8a |
init_pair(3, COLOR_RED, COLOR_BLACK);
|
|
Packit |
021a8a |
// for prompts
|
|
Packit |
021a8a |
init_pair(4, COLOR_BLACK, COLOR_RED);
|
|
Packit |
021a8a |
// for the currently selected row
|
|
Packit |
021a8a |
init_pair(5, COLOR_BLACK, COLOR_GREEN);
|
|
Packit |
021a8a |
init_pair(6, COLOR_BLACK, COLOR_YELLOW);
|
|
Packit |
021a8a |
init_pair(7, COLOR_BLACK, COLOR_RED);
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
flags.nocolor = true;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (!flags.noscroll) {
|
|
Packit |
021a8a |
getmaxyx(stdscr, y, x);
|
|
Packit |
021a8a |
return newpad(NLINES, x);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
return stdscr;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Figure out the best way to get the screensize_t, and then do it
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
screensize_t get_size(const bool &single)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
int maxx = 0, maxy = 0;
|
|
Packit |
021a8a |
if (!single) {
|
|
Packit |
021a8a |
getmaxyx(stdscr, maxy, maxx);
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
maxx = 72;
|
|
Packit |
021a8a |
if (getenv("COLS"))
|
|
Packit |
021a8a |
maxx=atoi(getenv("COLS"));
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
screensize_t a;
|
|
Packit |
021a8a |
a.x = maxx;
|
|
Packit |
021a8a |
a.y = maxy;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
return a;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Error function for screen being too small.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
void term_too_small()
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
end_curses();
|
|
Packit |
021a8a |
cout << "I'm sorry, your terminal must be atleast 72 columns"
|
|
Packit |
021a8a |
<< "wide to run iptstate\n";
|
|
Packit |
021a8a |
exit(3);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* This is one of those "well, I should impliment it to be complete, but
|
|
Packit |
021a8a |
* I doubt it'll get used very often features." It was a nice-thing-to-do
|
|
Packit |
021a8a |
* to impliment the ability for iptstate to use stdscr instead of a pad
|
|
Packit |
021a8a |
* as this provides the doulbe-buffering and other features that pads
|
|
Packit |
021a8a |
* do not. This is probably useful to a small subset of users. It's pretty
|
|
Packit |
021a8a |
* unlikely people will want to interactively want to change this during
|
|
Packit |
021a8a |
* runtime, but since I implimented noscroll, it's only proper to impliment
|
|
Packit |
021a8a |
* interactive toggling.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* TECH NOTE:
|
|
Packit |
021a8a |
* This is just a note for myself so I remember why this is the way it is.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* The syntax WINDOW *&mainwin is right, thought it's doing what you'd
|
|
Packit |
021a8a |
* expect WINDOW &*mainwin to do... except that's invalid. So it's just a
|
|
Packit |
021a8a |
* &foo pass on a WINDOW*.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
void switch_scroll(flags_t &flags, WINDOW *&mainwin)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
int x, y;
|
|
Packit |
021a8a |
if (flags.noscroll) {
|
|
Packit |
021a8a |
getmaxyx(stdscr, y, x);
|
|
Packit |
021a8a |
// remove stuff from the bottom window
|
|
Packit |
021a8a |
erase();
|
|
Packit |
021a8a |
// build pad
|
|
Packit |
021a8a |
wmove(mainwin, 0, 0);
|
|
Packit |
021a8a |
mainwin = newpad(NLINES, x);
|
|
Packit |
021a8a |
wmove(mainwin, 0, 0);
|
|
Packit |
021a8a |
keypad(mainwin,1);
|
|
Packit |
021a8a |
halfdelay(1);
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
// delete pad
|
|
Packit |
021a8a |
delwin(mainwin);
|
|
Packit |
021a8a |
mainwin = stdscr;
|
|
Packit |
021a8a |
keypad(mainwin,1);
|
|
Packit |
021a8a |
halfdelay(1);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
flags.noscroll = !flags.noscroll;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Prompt the user for something, and get an answer.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
void get_input(WINDOW *win, string &input, const string &prompt,
|
|
Packit |
021a8a |
const flags_t &flags)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* This function is here so that we can prompt and get an answer
|
|
Packit |
021a8a |
* and the user can get an echo of what they're inputting. This is
|
|
Packit |
021a8a |
* already a non-straight-forward thing to do in cbreak() mode, but
|
|
Packit |
021a8a |
* it turns out that using pads makes it even more difficult.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* It's worth noting that I tried doin a simple waddch() and then
|
|
Packit |
021a8a |
* prefresh as one would expect, but it didn't echo the chars.
|
|
Packit |
021a8a |
* Because we're using pads I have to do a waddchar() and then
|
|
Packit |
021a8a |
* a prefresh().
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* Note, that the documentation says that if we're using waddchar()
|
|
Packit |
021a8a |
* we shouldn't need any refresh, but it doesn't echo without it.
|
|
Packit |
021a8a |
* This is probably because waddch() calls wrefresh() instead of
|
|
Packit |
021a8a |
* prefresh().
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
input = "";
|
|
Packit |
021a8a |
int x, y;
|
|
Packit |
021a8a |
getmaxyx(stdscr, y, x);
|
|
Packit |
021a8a |
WINDOW *cmd = subpad(win, 1, x, 0, 0);
|
|
Packit |
021a8a |
if (!flags.nocolor)
|
|
Packit |
021a8a |
wattron(cmd, COLOR_PAIR(4));
|
|
Packit |
021a8a |
keypad(cmd, true);
|
|
Packit |
021a8a |
wprintw(cmd, prompt.c_str());
|
|
Packit |
021a8a |
wclrtoeol(cmd);
|
|
Packit |
021a8a |
prefresh(cmd, 0, 0, 0, 0, 0, x);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
int ch;
|
|
Packit |
021a8a |
int charcount = 0;
|
|
Packit |
021a8a |
echo();
|
|
Packit |
021a8a |
nodelay(cmd,0);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
while (1) {
|
|
Packit |
021a8a |
ch = wgetch(cmd);
|
|
Packit |
021a8a |
switch (ch) {
|
|
Packit |
021a8a |
case '\n':
|
|
Packit |
021a8a |
// 7 is ^G
|
|
Packit |
021a8a |
case 7:
|
|
Packit |
021a8a |
if (ch == 7)
|
|
Packit |
021a8a |
input = "";
|
|
Packit |
021a8a |
if (!flags.nocolor)
|
|
Packit |
021a8a |
wattroff(cmd, COLOR_PAIR(4));
|
|
Packit |
021a8a |
delwin(cmd);
|
|
Packit |
021a8a |
noecho();
|
|
Packit |
021a8a |
wmove(win, 0, 0);
|
|
Packit |
021a8a |
return;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
// 8 is shift-backspace - just incase
|
|
Packit |
021a8a |
case KEY_BACKSPACE:
|
|
Packit |
021a8a |
case 8:
|
|
Packit |
021a8a |
if (charcount > 0) {
|
|
Packit |
021a8a |
input = input.substr(0, input.size()-1);
|
|
Packit |
021a8a |
wechochar(cmd, '\b');
|
|
Packit |
021a8a |
wechochar(cmd, ' ');
|
|
Packit |
021a8a |
wechochar(cmd, '\b');
|
|
Packit |
021a8a |
charcount--;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case ERR:
|
|
Packit |
021a8a |
continue;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
default:
|
|
Packit |
021a8a |
input += ch;
|
|
Packit |
021a8a |
charcount++;
|
|
Packit |
021a8a |
wechochar(cmd, ch);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
prefresh(cmd, 0, 0, 0, 0, 0, x);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Create a window with noticable colors (if colors are enabled)
|
|
Packit |
021a8a |
* and print a warning. Means curses_warning.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
void c_warn(WINDOW *win, const string &warning, const flags_t &flags)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* This function is here so that we can warn a user in curses,
|
|
Packit |
021a8a |
* usually about bad input.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
int x, y;
|
|
Packit |
021a8a |
getmaxyx(stdscr, y, x);
|
|
Packit |
021a8a |
WINDOW *warn = subpad(win, 1, x, 0, 0);
|
|
Packit |
021a8a |
if (!flags.nocolor)
|
|
Packit |
021a8a |
wattron(warn, COLOR_PAIR(4));
|
|
Packit |
021a8a |
wprintw(warn, warning.c_str());
|
|
Packit |
021a8a |
wprintw(warn, " Press any key to continue...");
|
|
Packit |
021a8a |
wclrtoeol(warn);
|
|
Packit |
021a8a |
prefresh(warn, 0, 0, 0, 0, 0, x);
|
|
Packit |
021a8a |
while ((y = getch())) {
|
|
Packit |
021a8a |
if (y != ERR) {
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
prefresh(warn, 0, 0, 0, 0, 0, x);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
if (!flags.nocolor)
|
|
Packit |
021a8a |
wattroff(warn, COLOR_PAIR(4));
|
|
Packit |
021a8a |
delwin(warn);
|
|
Packit |
021a8a |
noecho();
|
|
Packit |
021a8a |
wmove(win, 0, 0);
|
|
Packit |
021a8a |
return;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Initialize the max_t structure with some sane defaults. We'll grow
|
|
Packit |
021a8a |
* them later as needed.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
void initialize_maxes(max_t &max, flags_t &flags)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* For NO lookup:
|
|
Packit |
021a8a |
* src/dst IP can be no bigger than 21 chars:
|
|
Packit |
021a8a |
* IP (max of 15) + colon (1) + port (max of 5) = 21
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* For lookup:
|
|
Packit |
021a8a |
* if it's a name, we start with the width of the header, and we can
|
|
Packit |
021a8a |
* grow from there as needed.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (flags.lookup) {
|
|
Packit |
021a8a |
max.src = 6;
|
|
Packit |
021a8a |
max.dst = 11;
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
max.src = max.dst = 21;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* The proto starts at 3, since tcp/udp are the most common, but will
|
|
Packit |
021a8a |
* grow if we see bigger proto strings such as "ICMP".
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
max.proto = 3;
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* "ESTABLISHED" is generally the longest state, we almost always have
|
|
Packit |
021a8a |
* several, so we'll start with this. It also looks really bad if state
|
|
Packit |
021a8a |
* is changing size a lot, so we start with a common minumum.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
max.state = 11;
|
|
Packit |
021a8a |
// TTL we statically make 7: xxx:xx:xx
|
|
Packit |
021a8a |
max.ttl = 9;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// Start with something sane
|
|
Packit |
021a8a |
max.bytes = 2;
|
|
Packit |
021a8a |
max.packets = 2;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* The actual work of handling a resize.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
void handle_resize(WINDOW *&win, const flags_t &flags, screensize_t &ssize)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
if (flags.noscroll) {
|
|
Packit |
021a8a |
endwin();
|
|
Packit |
021a8a |
refresh();
|
|
Packit |
021a8a |
return;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* OK, the above case without pads is easy. But pads is tricker.
|
|
Packit |
021a8a |
* In order to properly handle SIGWINCH we need to:
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* - Tear down the pad (delwin)
|
|
Packit |
021a8a |
* - Reset the terminal settings to non-visual mode (endwin)
|
|
Packit |
021a8a |
* - Return to visual mode (refresh)
|
|
Packit |
021a8a |
* - Get the new size (getmaxyx)
|
|
Packit |
021a8a |
* - Rebuild the pad
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* Note that we don't get the new size without the endwin/refresh
|
|
Packit |
021a8a |
* and thus the new pad doesn't get built right, and everything wraps.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* This order must be preserved.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Tear down...
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
delwin(win);
|
|
Packit |
021a8a |
endwin();
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Start up...
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
refresh();
|
|
Packit |
021a8a |
getmaxyx(stdscr, ssize.y, ssize.x);
|
|
Packit |
021a8a |
win = newpad(NLINES, ssize.x);
|
|
Packit |
021a8a |
keypad(win, true);
|
|
Packit |
021a8a |
wmove(win, 0, 0);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
return;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Take in a 'curr' value, and delete a given conntrack
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
void delete_state(WINDOW *&win, const tentry_t *entry, const flags_t &flags)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
struct nfct_handle *cth;
|
|
Packit |
021a8a |
struct nf_conntrack *ct;
|
|
Packit |
021a8a |
cth = nfct_open(CONNTRACK, 0);
|
|
Packit |
021a8a |
ct = nfct_new();
|
|
Packit |
021a8a |
int ret;
|
|
Packit |
021a8a |
string response;
|
|
Packit |
021a8a |
char str[NAMELEN];
|
|
Packit |
021a8a |
string src, dst;
|
|
Packit |
021a8a |
src = inet_ntop(entry->family, (void *)&(entry->src), str, NAMELEN-1);
|
|
Packit |
021a8a |
dst = inet_ntop(entry->family, (void *)&(entry->dst), str, NAMELEN-1);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
ostringstream msg;
|
|
Packit |
021a8a |
msg.str("");
|
|
Packit |
021a8a |
msg << "Deleting state: ";
|
|
Packit |
021a8a |
if (entry->proto == "tcp" || entry->proto == "udp") {
|
|
Packit |
021a8a |
msg << src << ":" << entry->srcpt << " -> " << dst << ":" << entry->dstpt;
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
msg << src << " -> " << dst;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
msg << " -- Are you sure? (y/n)";
|
|
Packit |
021a8a |
get_input(win, response, msg.str(), flags);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (response != "y" && response != "Y" && response != "yes" &&
|
|
Packit |
021a8a |
response != "YES" && response != "Yes") {
|
|
Packit |
021a8a |
c_warn(win, "NOT deleting state.", flags);
|
|
Packit |
021a8a |
return;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
nfct_set_attr_u8(ct, ATTR_ORIG_L3PROTO, entry->family);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (entry->family == AF_INET) {
|
|
Packit |
021a8a |
nfct_set_attr(ct, ATTR_ORIG_IPV4_SRC, (void *)&(entry->src.s6_addr));
|
|
Packit |
021a8a |
nfct_set_attr(ct, ATTR_ORIG_IPV4_DST, (void *)&(entry->dst.s6_addr));
|
|
Packit |
021a8a |
} else if (entry->family == AF_INET6) {
|
|
Packit |
021a8a |
nfct_set_attr(ct, ATTR_ORIG_IPV6_SRC, (void *)&(entry->src.s6_addr));
|
|
Packit |
021a8a |
nfct_set_attr(ct, ATTR_ORIG_IPV6_DST, (void *)&(entry->dst.s6_addr));
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// undo our space optimization so the kernel can find the state.
|
|
Packit |
021a8a |
protoent *pn;
|
|
Packit |
021a8a |
if (entry->proto == "icmp6")
|
|
Packit |
021a8a |
pn = getprotobyname("ipv6-icmp");
|
|
Packit |
021a8a |
else
|
|
Packit |
021a8a |
pn = getprotobyname(entry->proto.c_str());
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
nfct_set_attr_u8(ct, ATTR_ORIG_L4PROTO, pn->p_proto);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (entry->proto == "tcp" || entry->proto == "udp") {
|
|
Packit |
021a8a |
nfct_set_attr_u16(ct, ATTR_ORIG_PORT_SRC, htons(entry->srcpt));
|
|
Packit |
021a8a |
nfct_set_attr_u16(ct, ATTR_ORIG_PORT_DST, htons(entry->dstpt));
|
|
Packit |
021a8a |
} else if (entry->proto == "icmp" || entry->proto == "icmp6") {
|
|
Packit |
021a8a |
string type, code, id, tmp;
|
|
Packit |
021a8a |
split('/', entry->state, type, tmp);
|
|
Packit |
021a8a |
split(' ', tmp, code, tmp);
|
|
Packit |
021a8a |
split('(', tmp, tmp, id);
|
|
Packit |
021a8a |
split(')', id, id, tmp);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
nfct_set_attr_u8(ct, ATTR_ICMP_TYPE, atoi(type.c_str()));
|
|
Packit |
021a8a |
nfct_set_attr_u8(ct, ATTR_ICMP_CODE, atoi(code.c_str()));
|
|
Packit |
021a8a |
nfct_set_attr_u16(ct, ATTR_ICMP_ID, atoi(id.c_str()));
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
ret = nfct_query(cth, NFCT_Q_DESTROY, ct);
|
|
Packit |
021a8a |
if (ret < 0) {
|
|
Packit |
021a8a |
string msg = "Failed to delete state: ";
|
|
Packit |
021a8a |
msg += strerror(errno);
|
|
Packit |
021a8a |
c_warn(win, msg.c_str(), flags);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* CORE FUNCTIONS
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Callback for conntrack
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
int conntrack_hook(enum nf_conntrack_msg_type nf_type, struct nf_conntrack *ct,
|
|
Packit |
021a8a |
void *tmp)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* start by getting our struct back
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
struct hook_data *data = static_cast<struct hook_data *>(tmp);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* and pull out the pieces
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
vector<tentry_t*> *stable = data->stable;
|
|
Packit |
021a8a |
flags_t *flags = data->flags;
|
|
Packit |
021a8a |
max_t *max = data->max;
|
|
Packit |
021a8a |
counters_t *counts = data->counts;
|
|
Packit |
021a8a |
const filters_t *filters = data->filters;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// our table entry
|
|
Packit |
021a8a |
tentry_t *entry = new tentry_t;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// some vars
|
|
Packit |
021a8a |
struct protoent* pe = NULL;
|
|
Packit |
021a8a |
int seconds, minutes, hours;
|
|
Packit |
021a8a |
char ttlc[11];
|
|
Packit |
021a8a |
ostringstream buffer;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Clear the entry
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
entry->sname = "";
|
|
Packit |
021a8a |
entry->dname = "";
|
|
Packit |
021a8a |
entry->srcpt = 0;
|
|
Packit |
021a8a |
entry->dstpt = 0;
|
|
Packit |
021a8a |
entry->proto = "";
|
|
Packit |
021a8a |
entry->ttl = "";
|
|
Packit |
021a8a |
entry->state = "";
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* First, we read stuff into the array that's always the
|
|
Packit |
021a8a |
* same regardless of protocol
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
short int pr = nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO);
|
|
Packit |
021a8a |
pe = getprotobynumber(pr);
|
|
Packit |
021a8a |
if (pe == NULL) {
|
|
Packit |
021a8a |
buffer << pr;
|
|
Packit |
021a8a |
entry->proto = buffer.str();
|
|
Packit |
021a8a |
buffer.str("");
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
entry->proto = pe->p_name;
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* if proto is "ipv6-icmp" we can just say "icmp6" to save space...
|
|
Packit |
021a8a |
* it's more common/standard anyway
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (entry->proto == "ipv6-icmp")
|
|
Packit |
021a8a |
entry->proto = "icmp6";
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// ttl
|
|
Packit |
021a8a |
seconds = nfct_get_attr_u32(ct, ATTR_TIMEOUT);
|
|
Packit |
021a8a |
minutes = seconds/60;
|
|
Packit |
021a8a |
hours = minutes/60;
|
|
Packit |
021a8a |
minutes = minutes%60;
|
|
Packit |
021a8a |
seconds = seconds%60;
|
|
Packit |
021a8a |
// Format it with snprintf and store it in the table
|
|
Packit |
021a8a |
snprintf(ttlc,11, "%3i:%02i:%02i", hours, minutes, seconds);
|
|
Packit |
021a8a |
entry->ttl = ttlc;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
entry->family = nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO);
|
|
Packit |
021a8a |
// Everything has addresses
|
|
Packit |
021a8a |
if (entry->family == AF_INET) {
|
|
Packit |
021a8a |
memcpy(entry->src.s6_addr, nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC),
|
|
Packit |
021a8a |
sizeof(uint8_t[16]));
|
|
Packit |
021a8a |
memcpy(entry->dst.s6_addr, nfct_get_attr(ct, ATTR_ORIG_IPV4_DST),
|
|
Packit |
021a8a |
sizeof(uint8_t[16]));
|
|
Packit |
021a8a |
} else if (entry->family == AF_INET6) {
|
|
Packit |
021a8a |
memcpy(entry->src.s6_addr, nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC),
|
|
Packit |
021a8a |
sizeof(uint8_t[16]));
|
|
Packit |
021a8a |
memcpy(entry->dst.s6_addr, nfct_get_attr(ct, ATTR_ORIG_IPV6_DST),
|
|
Packit |
021a8a |
sizeof(uint8_t[16]));
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
fprintf(stderr, "UNKNOWN FAMILY!\n");
|
|
Packit |
021a8a |
exit(1);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// Counters (summary, in + out)
|
|
Packit |
021a8a |
entry->bytes = nfct_get_attr_u32(ct, ATTR_ORIG_COUNTER_BYTES) +
|
|
Packit |
021a8a |
nfct_get_attr_u32(ct, ATTR_REPL_COUNTER_BYTES);
|
|
Packit |
021a8a |
entry->packets = nfct_get_attr_u32(ct, ATTR_ORIG_COUNTER_PACKETS) +
|
|
Packit |
021a8a |
nfct_get_attr_u32(ct, ATTR_REPL_COUNTER_PACKETS);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (digits(entry->bytes) > max->bytes) {
|
|
Packit |
021a8a |
max->bytes = digits(entry->bytes);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
if (digits(entry->packets) > max->packets) {
|
|
Packit |
021a8a |
max->packets = digits(entry->packets);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (entry->proto.size() > max->proto)
|
|
Packit |
021a8a |
max->proto = entry->proto.size();
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// OK, proto dependent stuff
|
|
Packit |
021a8a |
if (entry->proto == "tcp" || entry->proto == "udp") {
|
|
Packit |
021a8a |
entry->srcpt = htons(nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC));
|
|
Packit |
021a8a |
entry->dstpt = htons(nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST));
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (entry->proto == "tcp") {
|
|
Packit |
021a8a |
entry->state = states[nfct_get_attr_u8(ct, ATTR_TCP_STATE)];
|
|
Packit |
021a8a |
counts->tcp++;
|
|
Packit |
021a8a |
} else if (entry->proto == "udp") {
|
|
Packit |
021a8a |
entry->state = "";
|
|
Packit |
021a8a |
counts->udp++;
|
|
Packit |
021a8a |
} else if (entry->proto == "icmp" || entry->proto == "icmp6") {
|
|
Packit |
021a8a |
buffer.str("");
|
|
Packit |
021a8a |
buffer << (int)nfct_get_attr_u8(ct, ATTR_ICMP_TYPE) << "/"
|
|
Packit |
021a8a |
<< (int)nfct_get_attr_u8(ct, ATTR_ICMP_CODE) << " ("
|
|
Packit |
021a8a |
<< nfct_get_attr_u16(ct, ATTR_ICMP_ID) << ")";
|
|
Packit |
021a8a |
entry->state = buffer.str();
|
|
Packit |
021a8a |
counts->icmp++;
|
|
Packit |
021a8a |
if (entry->state.size() > max->state)
|
|
Packit |
021a8a |
max->state = entry->state.size();
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
counts->other++;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* FILTERING
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* FIXME: Filtering needs to be pulled into it's own function.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
struct in_addr lb;
|
|
Packit |
021a8a |
struct in6_addr lb6;
|
|
Packit |
021a8a |
inet_pton(AF_INET, "127.0.0.1", &lb);
|
|
Packit |
021a8a |
inet_pton(AF_INET6, "::1", &lb6;;
|
|
Packit |
021a8a |
size_t entrysize = entry->family == AF_INET
|
|
Packit |
021a8a |
? sizeof(in_addr)
|
|
Packit |
021a8a |
: sizeof(in6_addr);
|
|
Packit |
021a8a |
if (flags->skiplb && (entry->family == AF_INET
|
|
Packit |
021a8a |
? !memcmp(&(entry->src), &lb, sizeof(in_addr))
|
|
Packit |
021a8a |
: !memcmp(&(entry->src), &lb6, sizeof(in6_addr)))) {
|
|
Packit |
021a8a |
counts->skipped++;
|
|
Packit |
021a8a |
return NFCT_CB_CONTINUE;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (flags->skipdns && (entry->dstpt == 53)) {
|
|
Packit |
021a8a |
counts->skipped++;
|
|
Packit |
021a8a |
return NFCT_CB_CONTINUE;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (flags->filter_src && (memcmp(&(entry->src), &(filters->src), entrysize))) {
|
|
Packit |
021a8a |
counts->skipped++;
|
|
Packit |
021a8a |
return NFCT_CB_CONTINUE;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (flags->filter_srcpt && (entry->srcpt != filters->srcpt)) {
|
|
Packit |
021a8a |
counts->skipped++;
|
|
Packit |
021a8a |
return NFCT_CB_CONTINUE;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (flags->filter_dst && (memcmp(&(entry->dst), &(filters->dst), entrysize))) {
|
|
Packit |
021a8a |
counts->skipped++;
|
|
Packit |
021a8a |
return NFCT_CB_CONTINUE;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (flags->filter_dstpt && (entry->dstpt != filters->dstpt)) {
|
|
Packit |
021a8a |
counts->skipped++;
|
|
Packit |
021a8a |
return NFCT_CB_CONTINUE;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* RESOLVE
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// Resolve names - if necessary - or generate strings of address,
|
|
Packit |
021a8a |
// and calculate max sizes
|
|
Packit |
021a8a |
stringify_entry(entry, *max, *flags);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Add this to the array
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
stable->push_back(entry);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
return NFCT_CB_CONTINUE;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* This is the core of this program - build a table of states.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* For the new libnetfilter_conntrack code, the bulk of build_table was moved
|
|
Packit |
021a8a |
* to the conntrack callback function.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
void build_table(flags_t &flags, const filters_t &filters, vector<tentry_t*>
|
|
Packit |
021a8a |
&stable, counters_t &counts, max_t &max)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Variables
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
int res=0;
|
|
Packit |
021a8a |
vector<string> fields(MAXFIELDS);
|
|
Packit |
021a8a |
static struct nfct_handle *cth;
|
|
Packit |
021a8a |
u_int8_t family = AF_UNSPEC;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* This is the ugly struct for the nfct hook, that holds pointers to
|
|
Packit |
021a8a |
* all of the things the callback will need to fill our table
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
struct hook_data hook;
|
|
Packit |
021a8a |
hook.stable = &stable;
|
|
Packit |
021a8a |
hook.flags = &flag;;
|
|
Packit |
021a8a |
hook.max = &max;
|
|
Packit |
021a8a |
hook.counts = &counts;
|
|
Packit |
021a8a |
hook.filters = &filters;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Initialization
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
// Nuke the tentry_t's we made before deleting the vector of pointers
|
|
Packit |
021a8a |
for (
|
|
Packit |
021a8a |
vector<tentry_t*>::iterator it = stable.begin();
|
|
Packit |
021a8a |
it != stable.end();
|
|
Packit |
021a8a |
it++
|
|
Packit |
021a8a |
) {
|
|
Packit |
021a8a |
delete *it;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
stable.clear();
|
|
Packit |
021a8a |
counts.tcp = counts.udp = counts.icmp = counts.other = counts.skipped = 0;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
cth = nfct_open(CONNTRACK, 0);
|
|
Packit |
021a8a |
if (!cth) {
|
|
Packit |
021a8a |
end_curses();
|
|
Packit |
021a8a |
printf("ERROR: couldn't establish conntrack connection\n");
|
|
Packit |
021a8a |
exit(2);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
nfct_callback_register(cth, NFCT_T_ALL, conntrack_hook, (void *)&hook);
|
|
Packit |
021a8a |
res = nfct_query(cth, NFCT_Q_DUMP, &family);
|
|
Packit |
021a8a |
if (res < 0) {
|
|
Packit |
021a8a |
end_curses();
|
|
Packit |
021a8a |
printf("ERROR: Couldn't retreive conntrack table: %s\n", strerror(errno));
|
|
Packit |
021a8a |
exit(2);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
nfct_close(cth);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* This sorts the table based on the current sorting preference
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
void sort_table(const int &sortby, const bool &lookup, const int &sort_factor,
|
|
Packit |
021a8a |
vector<tentry_t*> &stable, string &sorting)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
switch (sortby) {
|
|
Packit |
021a8a |
case SORT_SRC:
|
|
Packit |
021a8a |
if (lookup) {
|
|
Packit |
021a8a |
std::sort(stable.begin(), stable.end(), srcname_sort);
|
|
Packit |
021a8a |
sorting = "SrcName";
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
std::sort(stable.begin(), stable.end(), src_sort);
|
|
Packit |
021a8a |
sorting = "SrcIP";
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
case SORT_SRC_PT:
|
|
Packit |
021a8a |
std::sort(stable.begin(), stable.end(), srcpt_sort);
|
|
Packit |
021a8a |
sorting = "SrcPort";
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
case SORT_DST:
|
|
Packit |
021a8a |
if (lookup) {
|
|
Packit |
021a8a |
std::sort(stable.begin(), stable.end(), dstname_sort);
|
|
Packit |
021a8a |
sorting = "DstName";
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
std::sort(stable.begin(), stable.end(), dst_sort);
|
|
Packit |
021a8a |
sorting = "DstIP";
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
case SORT_DST_PT:
|
|
Packit |
021a8a |
std::sort(stable.begin(), stable.end(), dstpt_sort);
|
|
Packit |
021a8a |
sorting = "DstPort";
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
case SORT_PROTO:
|
|
Packit |
021a8a |
std::sort(stable.begin(), stable.end(), proto_sort);
|
|
Packit |
021a8a |
sorting = "Prt";
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
case SORT_STATE:
|
|
Packit |
021a8a |
std::sort(stable.begin(), stable.end(), state_sort);
|
|
Packit |
021a8a |
sorting = "State";
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
case SORT_TTL:
|
|
Packit |
021a8a |
std::sort(stable.begin(), stable.end(), ttl_sort);
|
|
Packit |
021a8a |
sorting = "TTL";
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
case SORT_BYTES:
|
|
Packit |
021a8a |
std::sort(stable.begin(), stable.end(), bytes_sort);
|
|
Packit |
021a8a |
sorting = "Bytes";
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
case SORT_PACKETS:
|
|
Packit |
021a8a |
std::sort(stable.begin(), stable.end(), packets_sort);
|
|
Packit |
021a8a |
sorting = "Packets";
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
default:
|
|
Packit |
021a8a |
//we should never get here
|
|
Packit |
021a8a |
sorting = "??unknown??";
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
} //switch
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (sort_factor == -1)
|
|
Packit |
021a8a |
sorting = sorting + " reverse";
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
void print_headers(const flags_t &flags, const string &format,
|
|
Packit |
021a8a |
const string &sorting, const filters_t &filters,
|
|
Packit |
021a8a |
const counters_t &counts, const screensize_t &ssize,
|
|
Packit |
021a8a |
int table_size, WINDOW *mainwin)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
if (flags.single) {
|
|
Packit |
021a8a |
cout << "IP Tables State Top -- Sort by: " << sorting << endl;
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
wmove(mainwin, 0, 0);
|
|
Packit |
021a8a |
wclrtoeol(mainwin);
|
|
Packit |
021a8a |
wmove(mainwin,0, ssize.x/2-15);
|
|
Packit |
021a8a |
wattron(mainwin, A_BOLD);
|
|
Packit |
021a8a |
wprintw(mainwin, "IPTState - IPTables State Top\n");
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wprintw(mainwin, "Version: ");
|
|
Packit |
021a8a |
wattroff(mainwin, A_BOLD);
|
|
Packit |
021a8a |
wprintw(mainwin, "%-13s", VERSION);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wattron(mainwin, A_BOLD);
|
|
Packit |
021a8a |
wprintw(mainwin, "Sort: ");
|
|
Packit |
021a8a |
wattroff(mainwin, A_BOLD);
|
|
Packit |
021a8a |
wprintw(mainwin, "%-16s", sorting.c_str());
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wattron(mainwin, A_BOLD);
|
|
Packit |
021a8a |
wprintw(mainwin, "b");
|
|
Packit |
021a8a |
wattroff(mainwin, A_BOLD);
|
|
Packit |
021a8a |
wprintw(mainwin, "%-19s", ": change sorting");
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wattron(mainwin, A_BOLD);
|
|
Packit |
021a8a |
wprintw(mainwin, "h");
|
|
Packit |
021a8a |
wattroff(mainwin, A_BOLD);
|
|
Packit |
021a8a |
wprintw(mainwin, "%-s\n", ": help");
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* If enabled, print totals
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (flags.totals) {
|
|
Packit |
021a8a |
if (flags.single)
|
|
Packit |
021a8a |
printf(TOTALS_FORMAT, table_size+counts.skipped, counts.tcp, counts.udp,
|
|
Packit |
021a8a |
counts.icmp, counts.other, counts.skipped);
|
|
Packit |
021a8a |
else
|
|
Packit |
021a8a |
wprintw(mainwin, TOTALS_FORMAT, table_size+counts.skipped, counts.tcp,
|
|
Packit |
021a8a |
counts.udp, counts.icmp, counts.other, counts.skipped);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* If any, print filters
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
char tmp[NAMELEN];
|
|
Packit |
021a8a |
if (flags.filter_src || flags.filter_dst || flags.filter_srcpt
|
|
Packit |
021a8a |
|| flags.filter_dstpt) {
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (flags.single) {
|
|
Packit |
021a8a |
printf("Filters: ");
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
wattron(mainwin, A_BOLD);
|
|
Packit |
021a8a |
wprintw(mainwin, "Filters: ");
|
|
Packit |
021a8a |
wattroff(mainwin, A_BOLD);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
bool printed_a_filter = false;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (flags.filter_src) {
|
|
Packit |
021a8a |
inet_ntop(filters.srcfam, &filters.src, tmp, NAMELEN-1);
|
|
Packit |
021a8a |
if (flags.single)
|
|
Packit |
021a8a |
printf("src: %s", tmp);
|
|
Packit |
021a8a |
else
|
|
Packit |
021a8a |
wprintw(mainwin, "src: %s", tmp);
|
|
Packit |
021a8a |
printed_a_filter = true;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
if (flags.filter_srcpt) {
|
|
Packit |
021a8a |
if (printed_a_filter) {
|
|
Packit |
021a8a |
if (flags.single)
|
|
Packit |
021a8a |
printf(", ");
|
|
Packit |
021a8a |
else
|
|
Packit |
021a8a |
waddstr(mainwin, ", ");
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
if (flags.single)
|
|
Packit |
021a8a |
printf("sport: %lu", filters.srcpt);
|
|
Packit |
021a8a |
else
|
|
Packit |
021a8a |
wprintw(mainwin, "sport: %lu", filters.srcpt);
|
|
Packit |
021a8a |
printed_a_filter = true;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
if (flags.filter_dst) {
|
|
Packit |
021a8a |
if (printed_a_filter) {
|
|
Packit |
021a8a |
if (flags.single)
|
|
Packit |
021a8a |
printf(", ");
|
|
Packit |
021a8a |
else
|
|
Packit |
021a8a |
waddstr(mainwin, ", ");
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
inet_ntop(filters.dstfam, &filters.dst, tmp, NAMELEN-1);
|
|
Packit |
021a8a |
if (flags.single)
|
|
Packit |
021a8a |
printf("dst: %s", tmp);
|
|
Packit |
021a8a |
else
|
|
Packit |
021a8a |
wprintw(mainwin, "dst: %s", tmp);
|
|
Packit |
021a8a |
printed_a_filter = true;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
if (flags.filter_dstpt) {
|
|
Packit |
021a8a |
if (printed_a_filter) {
|
|
Packit |
021a8a |
if (flags.single)
|
|
Packit |
021a8a |
printf(", ");
|
|
Packit |
021a8a |
else
|
|
Packit |
021a8a |
waddstr(mainwin, ", ");
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
if (flags.single)
|
|
Packit |
021a8a |
printf("dport: %lu", filters.dstpt);
|
|
Packit |
021a8a |
else
|
|
Packit |
021a8a |
wprintw(mainwin, "dport: %lu", filters.dstpt);
|
|
Packit |
021a8a |
printed_a_filter = true;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
if (flags.single)
|
|
Packit |
021a8a |
printf("\n");
|
|
Packit |
021a8a |
else
|
|
Packit |
021a8a |
wprintw(mainwin, "\n");
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Print column headers
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (flags.single) {
|
|
Packit |
021a8a |
if (flags.counters)
|
|
Packit |
021a8a |
printf(format.c_str(), "Source", "Destination", "Prt", "State", "TTL",
|
|
Packit |
021a8a |
"B", "P");
|
|
Packit |
021a8a |
else
|
|
Packit |
021a8a |
printf(format.c_str(), "Source", "Destination", "Prt", "State", "TTL");
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
wattron(mainwin, A_BOLD);
|
|
Packit |
021a8a |
if (flags.counters)
|
|
Packit |
021a8a |
wprintw(mainwin, format.c_str(), "Source", "Destination", "Prt",
|
|
Packit |
021a8a |
"State", "TTL", "B", "P");
|
|
Packit |
021a8a |
else
|
|
Packit |
021a8a |
wprintw(mainwin, format.c_str(), "Source", "Destination", "Prt",
|
|
Packit |
021a8a |
"State", "TTL");
|
|
Packit |
021a8a |
wattroff(mainwin, A_BOLD);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
void truncate(string &string, int length, bool mark, char direction)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
int s = (direction == 'f') ? string.size() - length : 0;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
string = string.substr(s, length);
|
|
Packit |
021a8a |
if (mark) {
|
|
Packit |
021a8a |
int m = (direction == 'f') ? 0 : string.size() - 1;
|
|
Packit |
021a8a |
string[m] = '+';
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Based on the format pre-chosen, truncate src/dst as needed, and then
|
|
Packit |
021a8a |
* generate the host:port strings and drop them off in the src/dst string
|
|
Packit |
021a8a |
* objects passed in.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
void format_src_dst(tentry_t *table, string &src, string &dst,
|
|
Packit |
021a8a |
const flags_t &flags, const max_t &max)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
ostringstream buffer;
|
|
Packit |
021a8a |
bool have_port = table->proto == "tcp" || table->proto == "udp";
|
|
Packit |
021a8a |
char direction;
|
|
Packit |
021a8a |
unsigned int length;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// What length would we currently use?
|
|
Packit |
021a8a |
length = table->sname.size();
|
|
Packit |
021a8a |
if (have_port)
|
|
Packit |
021a8a |
length += table->spname.size() + 1;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// If it's too long, figure out how room we have and truncate it
|
|
Packit |
021a8a |
if (length > max.src) {
|
|
Packit |
021a8a |
length = max.src;
|
|
Packit |
021a8a |
if (have_port)
|
|
Packit |
021a8a |
length -= 1 + table->spname.size();
|
|
Packit |
021a8a |
direction = (flags.lookup) ? 'e' : 'f';
|
|
Packit |
021a8a |
truncate(table->sname, length, flags.tag_truncate, direction);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// ... and repeat
|
|
Packit |
021a8a |
length = table->dname.size();
|
|
Packit |
021a8a |
if (have_port)
|
|
Packit |
021a8a |
length += table->dpname.size() + 1;
|
|
Packit |
021a8a |
if (length > max.dst) {
|
|
Packit |
021a8a |
length = max.dst;
|
|
Packit |
021a8a |
if (have_port)
|
|
Packit |
021a8a |
length -= 1 + table->dpname.size();
|
|
Packit |
021a8a |
direction = (flags.lookup) ? 'f' : 'e';
|
|
Packit |
021a8a |
truncate(table->dname, length, flags.tag_truncate, direction);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
buffer << table->sname;
|
|
Packit |
021a8a |
if (have_port)
|
|
Packit |
021a8a |
buffer << ":" << table->spname;
|
|
Packit |
021a8a |
src = buffer.str();
|
|
Packit |
021a8a |
buffer.str("");
|
|
Packit |
021a8a |
buffer << table->dname;
|
|
Packit |
021a8a |
if (have_port)
|
|
Packit |
021a8a |
buffer << ":" << table->dpname;
|
|
Packit |
021a8a |
dst = buffer.str();
|
|
Packit |
021a8a |
buffer.str("");
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* An abstraction of priting a line for both single/curses modes
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
void printline(tentry_t *table, const flags_t &flags, const string &format,
|
|
Packit |
021a8a |
const max_t &max, WINDOW *mainwin, const bool curr)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
ostringstream buffer;
|
|
Packit |
021a8a |
buffer.str("");
|
|
Packit |
021a8a |
string src, dst, b, p;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// Generate strings for src/dest, truncating and marking as necessary
|
|
Packit |
021a8a |
format_src_dst(table, src, dst, flags, max);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (flags.counters) {
|
|
Packit |
021a8a |
buffer << table->bytes;
|
|
Packit |
021a8a |
b = buffer.str();
|
|
Packit |
021a8a |
buffer.str("");
|
|
Packit |
021a8a |
buffer << table->packets;
|
|
Packit |
021a8a |
p = buffer.str();
|
|
Packit |
021a8a |
buffer.str("");
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (flags.single) {
|
|
Packit |
021a8a |
if (flags.counters)
|
|
Packit |
021a8a |
printf(format.c_str(), src.c_str(), dst.c_str(), table->proto.c_str(),
|
|
Packit |
021a8a |
table->state.c_str(), table->ttl.c_str(), b.c_str(), p.c_str());
|
|
Packit |
021a8a |
else
|
|
Packit |
021a8a |
printf(format.c_str(), src.c_str(), dst.c_str(), table->proto.c_str(),
|
|
Packit |
021a8a |
table->state.c_str(), table->ttl.c_str());
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
int color = 0;
|
|
Packit |
021a8a |
if (!flags.nocolor) {
|
|
Packit |
021a8a |
if (table->proto == "tcp")
|
|
Packit |
021a8a |
color = 1;
|
|
Packit |
021a8a |
else if (table->proto == "udp")
|
|
Packit |
021a8a |
color = 2;
|
|
Packit |
021a8a |
else if (table->proto == "icmp" || table->proto == "icmp6")
|
|
Packit |
021a8a |
color = 3;
|
|
Packit |
021a8a |
if (curr)
|
|
Packit |
021a8a |
color += 4;
|
|
Packit |
021a8a |
wattron(mainwin, COLOR_PAIR(color));
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
if (flags.counters)
|
|
Packit |
021a8a |
wprintw(mainwin, format.c_str(), src.c_str(), dst.c_str(),
|
|
Packit |
021a8a |
table->proto.c_str(), table->state.c_str(), table->ttl.c_str(),
|
|
Packit |
021a8a |
b.c_str(), p.c_str());
|
|
Packit |
021a8a |
else
|
|
Packit |
021a8a |
wprintw(mainwin, format.c_str(), src.c_str(), dst.c_str(),
|
|
Packit |
021a8a |
table->proto.c_str(), table->state.c_str(), table->ttl.c_str());
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (!flags.nocolor && color != 0)
|
|
Packit |
021a8a |
wattroff(mainwin, COLOR_PAIR(color));
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* This does all the work of actually printing the table including
|
|
Packit |
021a8a |
* various bits of formatting. It handles both curses and non-curses runs.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
void print_table(vector<tentry_t*> &stable, const flags_t &flags,
|
|
Packit |
021a8a |
const string &format, const string &sorting,
|
|
Packit |
021a8a |
const filters_t &filters, const counters_t &counts,
|
|
Packit |
021a8a |
const screensize_t &ssize, const max_t &max, WINDOW *mainwin,
|
|
Packit |
021a8a |
unsigned int &curr)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Print headers
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
print_headers(flags, format, sorting, filters, counts, ssize, stable.size(),
|
|
Packit |
021a8a |
mainwin);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Print the state table
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
unsigned int limit = (stable.size() < NLINES) ? stable.size() : NLINES;
|
|
Packit |
021a8a |
for (unsigned int tmpint=0; tmpint < limit; tmpint++) {
|
|
Packit |
021a8a |
printline(stable[tmpint], flags, format, max, mainwin, (curr == tmpint));
|
|
Packit |
021a8a |
if (!flags.single && flags.noscroll
|
|
Packit |
021a8a |
&& (tmpint >= ssize.y-4 || (flags.totals && tmpint >= ssize.y-5)))
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* We don't want to lave things on the screen we didn't draw
|
|
Packit |
021a8a |
* this time.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (!flags.single)
|
|
Packit |
021a8a |
wclrtobot(mainwin);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Dynamically build a format to fit the most amount of data on the screen
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
void determine_format(WINDOW *mainwin, max_t &max, screensize_t &ssize,
|
|
Packit |
021a8a |
string &format, flags_t &flags)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* NOTE: When doing proper dynamic format building, we fill the
|
|
Packit |
021a8a |
* entire screen, so curses puts in a newline for us. However
|
|
Packit |
021a8a |
* with "staticsize" we must add a newline. Also with "single"
|
|
Packit |
021a8a |
* mode we must add it as well since there's no curses there.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* Thus DEFAULT_FORMAT (only used for staticsize) has it, and
|
|
Packit |
021a8a |
* at the bottom of this function we add a \n if flags.single
|
|
Packit |
021a8a |
* is set.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (flags.staticsize) {
|
|
Packit |
021a8a |
format = DEFAULT_FORMAT;
|
|
Packit |
021a8a |
max.src = DEFAULT_SRC;
|
|
Packit |
021a8a |
max.dst = DEFAULT_DST;
|
|
Packit |
021a8a |
max.proto = DEFAULT_PROTO;
|
|
Packit |
021a8a |
max.state = DEFAULT_STATE;
|
|
Packit |
021a8a |
max.ttl = DEFAULT_TTL;
|
|
Packit |
021a8a |
return;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
ssize = get_size(flags.single);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/* The screen must be 85 chars wide to be able to fit in
|
|
Packit |
021a8a |
* counters when we display IP addresses...
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* in lookup mode, we can truncate names, but in IP mode,
|
|
Packit |
021a8a |
* truncation makes no sense, so we just disable counters if
|
|
Packit |
021a8a |
* we run into this.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (ssize.x < 85 && flags.counters && !flags.lookup) {
|
|
Packit |
021a8a |
string prompt = "Window too narrow for counters! Disabling.";
|
|
Packit |
021a8a |
c_warn(mainwin, prompt, flags);
|
|
Packit |
021a8a |
flags.counters = false;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/* what's left is the above three, plus 4 spaces
|
|
Packit |
021a8a |
* (one between each of 5 fields)
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
unsigned int left = ssize.x - max.ttl - max.state - max.proto - 4;
|
|
Packit |
021a8a |
if (flags.counters)
|
|
Packit |
021a8a |
left -= (max.bytes + max.packets + 2);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* The rest is *prolly* going to be divided between src
|
|
Packit |
021a8a |
* and dst, so we see if that works. If 'left' is odd though
|
|
Packit |
021a8a |
* we give the extra space to src.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
unsigned int src, dst;
|
|
Packit |
021a8a |
src = dst = left / 2;
|
|
Packit |
021a8a |
bool left_odd = false;
|
|
Packit |
021a8a |
if ((left % 2) == 1) {
|
|
Packit |
021a8a |
left_odd = true;
|
|
Packit |
021a8a |
src++;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
if ((max.src + max.dst) < left) {
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* This means we can fit without an truncation, but it doesn't
|
|
Packit |
021a8a |
* necessarily mean that we can just give half to src and half
|
|
Packit |
021a8a |
* to dst... so lets figure that out.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (max.src < src && max.dst < dst) {
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* This case applies if:
|
|
Packit |
021a8a |
* we're even and they both fit in left/2
|
|
Packit |
021a8a |
* OR
|
|
Packit |
021a8a |
* we're odd and dst fits in left/2
|
|
Packit |
021a8a |
* and src fits in left/2+1
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* Since we've already calculated src/dst that way
|
|
Packit |
021a8a |
* we just combine this check as they both require
|
|
Packit |
021a8a |
* the same outcome.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
} else if (left_odd && (src < left / 2) && (dst < left / 2 + 1)) {
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* If src can fit in left/2 and dst in left/2+1
|
|
Packit |
021a8a |
* then we switch them.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
src = dst;
|
|
Packit |
021a8a |
dst++;
|
|
Packit |
021a8a |
} else if (max.src > max.dst) {
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* If we're here, we can fit them, but we can't fit them
|
|
Packit |
021a8a |
* and still keep the two columns relatively equal. Ah
|
|
Packit |
021a8a |
* well.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* Either max gets the bigger chunk and everything else
|
|
Packit |
021a8a |
* to dst...
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
src = max.src;
|
|
Packit |
021a8a |
dst = left - max.src;
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* ...or the other way around
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
dst = max.dst;
|
|
Packit |
021a8a |
src = left - max.dst;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
} else if (max.src < src) {
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* If we're here, we do have to truncate, but if one column is
|
|
Packit |
021a8a |
* very small, we should not give it more space than it needs.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
src = max.src;
|
|
Packit |
021a8a |
dst = left - max.src;
|
|
Packit |
021a8a |
} else if (max.dst < dst) {
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* same as above.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
dst = max.dst;
|
|
Packit |
021a8a |
src = left - max.dst;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* If nothing matched, then they're both bigger than left/2, so we'll
|
|
Packit |
021a8a |
* leave the default we set above.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
ostringstream buffer;
|
|
Packit |
021a8a |
buffer << "\%-" << src << "s \%-" << dst << "s \%-" << max.proto << "s \%-"
|
|
Packit |
021a8a |
<< max.state << "s \%-" << max.ttl << "s";
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (flags.counters)
|
|
Packit |
021a8a |
buffer << " \%-" << max.bytes << "s \%-" << max.packets << "s";
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (flags.single)
|
|
Packit |
021a8a |
buffer << "\n";
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
format = buffer.str();
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
max.dst = dst;
|
|
Packit |
021a8a |
max.src = src;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Interactive help
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
void interactive_help(const string &sorting, const flags_t &flags,
|
|
Packit |
021a8a |
const filters_t &filters)
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* This is the max we need the pad to be, and thus how
|
|
Packit |
021a8a |
* big we're going to create the pad.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* In many cases we'd make the pad very very large and not
|
|
Packit |
021a8a |
* worry about it. However, in this case:
|
|
Packit |
021a8a |
* 1. We know exactly how big we need it to be, and it's
|
|
Packit |
021a8a |
* not going to change interactively.
|
|
Packit |
021a8a |
* 2. We want to draw a "box" around the window and if the
|
|
Packit |
021a8a |
* pad is huge then the box will get drawn around that.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* So... we have 32 lines of help, plus a top and bottom border,
|
|
Packit |
021a8a |
* thus maxrows is 34.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* Our help text is not wider than 80, so we'll se that standard
|
|
Packit |
021a8a |
* width.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* If the screen is bigger than this, we deal with it below.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
unsigned int maxrows = 41;
|
|
Packit |
021a8a |
unsigned int maxcols = 80;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* The actual screen size
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
screensize_t ssize = get_size(flags.single);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* If the biggest we think we'll need is smaller than the screen,
|
|
Packit |
021a8a |
* then lets grow the pad to the size of the screen so that the
|
|
Packit |
021a8a |
* main window isn't peeking through.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (maxrows < ssize.y)
|
|
Packit |
021a8a |
maxrows = ssize.y;
|
|
Packit |
021a8a |
if (maxcols < ssize.x)
|
|
Packit |
021a8a |
maxcols = ssize.x;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Where we are withing the pad (for printing). We can't just print
|
|
Packit |
021a8a |
* newlines and expect it to work. Cause, well, it doesn't. You have
|
|
Packit |
021a8a |
* to tell it where on the pad to print, specifically.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
unsigned int x, y;
|
|
Packit |
021a8a |
x = y = 0;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* The current position on the pad we're showing (top left)
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
unsigned int px, py;
|
|
Packit |
021a8a |
px = py = 0;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* As noted above, we create the biggest pad we might need
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
static WINDOW *helpwin;
|
|
Packit |
021a8a |
helpwin = newpad(maxrows, maxcols);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Create a box, and then add one to "x" and "y" so we don't write
|
|
Packit |
021a8a |
* on the line,
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
box(helpwin, ACS_VLINE, ACS_HLINE);
|
|
Packit |
021a8a |
x++;
|
|
Packit |
021a8a |
y++;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* we want arrow keys to work
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
keypad(helpwin, true);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// Prolly not needed
|
|
Packit |
021a8a |
wmove(helpwin, 0, 0);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// Print opener
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, "IPTState ");
|
|
Packit |
021a8a |
waddstr(helpwin, VERSION);
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
// this is \n
|
|
Packit |
021a8a |
y++;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// We don't want anything except the title up against the
|
|
Packit |
021a8a |
// border
|
|
Packit |
021a8a |
x++;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
string nav = "Up/j, Down/k, Left/h, Right/l, PageUp/^u, PageDown/^d, ";
|
|
Packit |
021a8a |
nav += " Home, or End";
|
|
Packit |
021a8a |
// Print instructions first
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, "Navigation:");
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, nav.c_str());
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " Press any other key to continue...");
|
|
Packit |
021a8a |
y++;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// Print settings
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, "Current settings:");
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " Sorting by: ");
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin, sorting.c_str());
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " Dynamic formatting: ");
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin,(!flags.staticsize) ? "yes" : "no");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " Skip loopback states: ");
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin,(flags.skiplb) ? "yes" : "no");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " Resolve hostnames: ");
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin,(flags.lookup) ? "yes" : "no");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " Mark truncated hostnames: ");
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin,(flags.tag_truncate) ? "yes" : "no");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " Colors: ");
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin,(!flags.nocolor) ? "yes" : "no");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " Skip outgoing DNS lookup states: ");
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin,(flags.skipdns) ? "yes" : "no");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " Enable scroll: ");
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin,(!flags.noscroll) ? "yes" : "no");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " Display totals: ");
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin,(flags.totals) ? "yes" : "no");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " Display counters: ");
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin,(flags.counters) ? "yes" : "no");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
char tmp[NAMELEN];
|
|
Packit |
021a8a |
if (flags.filter_src) {
|
|
Packit |
021a8a |
inet_ntop(filters.srcfam, &filters.src, tmp,
|
|
Packit |
021a8a |
filters.srcfam == AF_INET ? sizeof(in_addr) : sizeof(in6_addr));
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " Source filter: ");
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin, tmp);
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
if (flags.filter_dst) {
|
|
Packit |
021a8a |
inet_ntop(filters.dstfam, &filters.dst, tmp,
|
|
Packit |
021a8a |
filters.dstfam == AF_INET ? sizeof(in_addr) : sizeof(in6_addr));
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " Destination filter: ");
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin, tmp);
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
if (flags.filter_srcpt) {
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " Source port filter: ");
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
wprintw(helpwin, "%lu", filters.srcpt);
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
if (flags.filter_dstpt) {
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " Destination port filter: ");
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
wprintw(helpwin, "%lu", filters.dstpt);
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
y++;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// Print commands
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, "Interactive commands:");
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " c");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin, "\tUse colors");
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " C");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin, "\tToggle display of bytes/packets counters");
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " b");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin, "\tSort by next column");
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " B");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin, "\tSort by previous column");
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " d");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin, "\tChange destination filter");
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " D");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin, "\tChange destination port filter");
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " f");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin, "\tToggle display of loopback states");
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " h");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin, "\tDisplay this help message");
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " l");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin, "\tToggle DNS lookups");
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " L");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin, "\tToggle display of outgoing DNS states");
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " m");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin, "\tToggle marking truncated hostnames with a '+'");
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " o");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin, "\tToggle dynamic or old formatting");
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " p");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin, "\tToggle scrolling");
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " q");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin, "\tQuit");
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " r");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin, "\tToggle reverse sorting");
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " R");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin, "\tChange the refresh rate");
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " s");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin, "\tChange source filter");
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " S");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin, "\tChange source port filter");
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " t");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin, "\tToggle display of totals");
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wattron(helpwin, A_BOLD);
|
|
Packit |
021a8a |
mvwaddstr(helpwin, y++, x, " x");
|
|
Packit |
021a8a |
wattroff(helpwin, A_BOLD);
|
|
Packit |
021a8a |
waddstr(helpwin, "\tDelete the currently highlighted state from netfilter");
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
y++;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
wmove(helpwin, 0, 0);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* refresh from wherever we are the pad
|
|
Packit |
021a8a |
* and the top of the window to the bottom of the window.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
prefresh(helpwin, py, px, 0, 0, ssize.y - 1, ssize.x - 1);
|
|
Packit |
021a8a |
// kill line buffering
|
|
Packit |
021a8a |
cbreak();
|
|
Packit |
021a8a |
// nodelay with a 0 here causes getch() to block until key is pressed.
|
|
Packit |
021a8a |
nodelay( helpwin, 0 );
|
|
Packit |
021a8a |
int c;
|
|
Packit |
021a8a |
while ((c = wgetch(helpwin))) {
|
|
Packit |
021a8a |
switch (c) {
|
|
Packit |
021a8a |
case ERR:
|
|
Packit |
021a8a |
continue;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case KEY_DOWN:
|
|
Packit |
021a8a |
case 'j':
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* py is the top of the window,
|
|
Packit |
021a8a |
* ssize.y is the height of the window,
|
|
Packit |
021a8a |
* so py+ssize.y is the bottom of the window.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* Since y is the bottom of the text we've
|
|
Packit |
021a8a |
* written, if
|
|
Packit |
021a8a |
* py+ssize.y == y
|
|
Packit |
021a8a |
* then the bottom of the screen as at the
|
|
Packit |
021a8a |
* bottom of the text, no more scrolling.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (py + ssize.y < y)
|
|
Packit |
021a8a |
py++;
|
|
Packit |
021a8a |
prefresh(helpwin, py, px, 0, 0, ssize.y - 1, ssize.x - 1);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case KEY_UP:
|
|
Packit |
021a8a |
case 'k':
|
|
Packit |
021a8a |
if (py > 0)
|
|
Packit |
021a8a |
py--;
|
|
Packit |
021a8a |
prefresh(helpwin, py, px, 0, 0, ssize.y - 1, ssize.x - 1);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case KEY_RIGHT:
|
|
Packit |
021a8a |
case 'l':
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* px is the left of the window,
|
|
Packit |
021a8a |
* ssize.x is the width of the window,
|
|
Packit |
021a8a |
* so px+ssize.x os the right side of the window.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* So if px+ssize.x == 80 (more than the width
|
|
Packit |
021a8a |
* of our text), no more scrolling.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (px + ssize.x < 80)
|
|
Packit |
021a8a |
px++;
|
|
Packit |
021a8a |
prefresh(helpwin, py, px, 0, 0, ssize.y - 1, ssize.x - 1);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case KEY_LEFT:
|
|
Packit |
021a8a |
case 'h':
|
|
Packit |
021a8a |
if (px > 0)
|
|
Packit |
021a8a |
px--;
|
|
Packit |
021a8a |
prefresh(helpwin, py, px, 0, 0, ssize.y - 1, ssize.x - 1);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case KEY_HOME:
|
|
Packit |
021a8a |
case KEY_SHOME:
|
|
Packit |
021a8a |
case KEY_FIND:
|
|
Packit |
021a8a |
px = py = 0;
|
|
Packit |
021a8a |
prefresh(helpwin, py, px, 0, 0, ssize.y - 1, ssize.x - 1);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case KEY_END:
|
|
Packit |
021a8a |
py = y-ssize.y;
|
|
Packit |
021a8a |
prefresh(helpwin, py, px, 0, 0, ssize.y - 1, ssize.x - 1);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case 4:
|
|
Packit |
021a8a |
case KEY_NPAGE:
|
|
Packit |
021a8a |
case KEY_SNEXT:
|
|
Packit |
021a8a |
if (flags.noscroll)
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* If the screen is bigger than the text,
|
|
Packit |
021a8a |
* ignore
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (y < ssize.y)
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Otherwise, if the bottom of the screen
|
|
Packit |
021a8a |
* (current position + screen size
|
|
Packit |
021a8a |
* == py + ssize.y)
|
|
Packit |
021a8a |
* were to go down one screen (thus:
|
|
Packit |
021a8a |
* py + ssize.y*2),
|
|
Packit |
021a8a |
* and that is bigger than the whole text, just
|
|
Packit |
021a8a |
* go to the bottom.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* Otherwise, go down a screen size.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if ((py + (ssize.y * 2)) > y) {
|
|
Packit |
021a8a |
py = y-ssize.y;
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
py += ssize.y;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
prefresh(helpwin, py, px, 0, 0, ssize.y - 1, ssize.x - 1);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case 21:
|
|
Packit |
021a8a |
case KEY_PPAGE:
|
|
Packit |
021a8a |
case KEY_SPREVIOUS:
|
|
Packit |
021a8a |
if (flags.noscroll)
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* If we're at the top, ignore this.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (py == 0)
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Otherwise if we're less than a page from the
|
|
Packit |
021a8a |
* top, go to the top, else, go up a page.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (py < ssize.y)
|
|
Packit |
021a8a |
py = 0;
|
|
Packit |
021a8a |
else
|
|
Packit |
021a8a |
py -= ssize.y;
|
|
Packit |
021a8a |
prefresh(helpwin, py, px, 0, 0, ssize.y - 1, ssize.x - 1);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
case 'q':
|
|
Packit |
021a8a |
default:
|
|
Packit |
021a8a |
goto out;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
if (need_resize) {
|
|
Packit |
021a8a |
goto out;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
out:
|
|
Packit |
021a8a |
// once a key is pressed, tear down the help window.
|
|
Packit |
021a8a |
delwin(helpwin);
|
|
Packit |
021a8a |
refresh();
|
|
Packit |
021a8a |
halfdelay(1);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* MAIN
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
int main(int argc, char *argv[])
|
|
Packit |
021a8a |
{
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// Variables
|
|
Packit |
021a8a |
string line, src, dst, srcpt, dstpt, proto, code, type, state, ttl, mins,
|
|
Packit |
021a8a |
secs, hrs, sorting, tmpstring, format, prompt;
|
|
Packit |
021a8a |
ostringstream ostream;
|
|
Packit |
021a8a |
vector<tentry_t*> stable;
|
|
Packit |
021a8a |
int tmpint = 0, sortby = 0, rate = 1, hdrs = 0;
|
|
Packit |
021a8a |
unsigned int py = 0, px = 0, curr_state = 0;
|
|
Packit |
021a8a |
timeval selecttimeout;
|
|
Packit |
021a8a |
fd_set readfd;
|
|
Packit |
021a8a |
flags_t flags;
|
|
Packit |
021a8a |
counters_t counts;
|
|
Packit |
021a8a |
screensize_t ssize;
|
|
Packit |
021a8a |
filters_t filters;
|
|
Packit |
021a8a |
max_t max;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Initialize
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
flags.single = flags.totals = flags.lookup = flags.skiplb = flags.staticsize
|
|
Packit |
021a8a |
= flags.skipdns = flags.tag_truncate = flags.filter_src
|
|
Packit |
021a8a |
= flags.filter_dst = flags.filter_srcpt = flags.filter_dstpt
|
|
Packit |
021a8a |
= flags.noscroll = flags.nocolor = flags.counters = false;
|
|
Packit |
021a8a |
ssize.x = ssize.y = 0;
|
|
Packit |
021a8a |
counts.tcp = counts.udp = counts.icmp = counts.other = counts.skipped = 0;
|
|
Packit |
021a8a |
filters.src = filters.dst = in6addr_any;
|
|
Packit |
021a8a |
filters.srcpt = filters.dstpt = 0;
|
|
Packit |
021a8a |
max.src = max.dst = max.proto = max.state = max.ttl = 0;
|
|
Packit |
021a8a |
px = py = 0;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
static struct option long_options[] = {
|
|
Packit |
021a8a |
{"counters", no_argument , 0, 'C'},
|
|
Packit |
021a8a |
{"dst-filter", required_argument, 0, 'd'},
|
|
Packit |
021a8a |
{"dstpt-filter", required_argument, 0, 'D'},
|
|
Packit |
021a8a |
{"help", no_argument, 0, 'h'},
|
|
Packit |
021a8a |
{"lookup", no_argument, 0, 'l'},
|
|
Packit |
021a8a |
{"mark-truncated", no_argument, 0, 'm'},
|
|
Packit |
021a8a |
{"no-color", no_argument, 0, 'c'},
|
|
Packit |
021a8a |
{"no-dynamic", no_argument, 0, 'o'},
|
|
Packit |
021a8a |
{"no-dns", no_argument, 0, 'L'},
|
|
Packit |
021a8a |
{"no-loopback", no_argument, 0, 'f'},
|
|
Packit |
021a8a |
{"no-scroll", no_argument, 0, 'p'},
|
|
Packit |
021a8a |
{"rate", required_argument, 0, 'R'},
|
|
Packit |
021a8a |
{"reverse", no_argument, 0, 'r'},
|
|
Packit |
021a8a |
{"single", no_argument, 0, '1'},
|
|
Packit |
021a8a |
{"sort", required_argument, 0, 'b'},
|
|
Packit |
021a8a |
{"src-filter", required_argument, 0, 's'},
|
|
Packit |
021a8a |
{"srcpt-filter", required_argument, 0, 'S'},
|
|
Packit |
021a8a |
{"totals", no_argument, 0, 't'},
|
|
Packit |
021a8a |
{"version", no_argument, 0, 'v'},
|
|
Packit |
021a8a |
{0, 0, 0,0}
|
|
Packit |
021a8a |
};
|
|
Packit |
021a8a |
int option_index = 0;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// Command Line Arguments
|
|
Packit |
021a8a |
while ((tmpint = getopt_long(argc, argv, "Cd:D:hlmcoLfpR:r1b:s:S:tv",
|
|
Packit |
021a8a |
long_options, &option_index)) != EOF) {
|
|
Packit |
021a8a |
printf("loop: %d\n", tmpint);
|
|
Packit |
021a8a |
switch (tmpint) {
|
|
Packit |
021a8a |
case 0:
|
|
Packit |
021a8a |
/* Apparently this test is needed?! Seems lame! */
|
|
Packit |
021a8a |
if (long_options[option_index].flag != 0)
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Long-only options go here, like so:
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* tmpstring = long_options[option_index].name;
|
|
Packit |
021a8a |
* if (tmpstring == "srcpt-filter") {
|
|
Packit |
021a8a |
* ...
|
|
Packit |
021a8a |
* } else if (...) {
|
|
Packit |
021a8a |
* ...
|
|
Packit |
021a8a |
* }
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
// --counters
|
|
Packit |
021a8a |
case 'C':
|
|
Packit |
021a8a |
flags.counters = true;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
// --dst-filter
|
|
Packit |
021a8a |
case 'd':
|
|
Packit |
021a8a |
if (optarg == NULL)
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
// See check_ip() note above
|
|
Packit |
021a8a |
if (!check_ip(optarg, &filters.dst, &filters.dstfam)) {
|
|
Packit |
021a8a |
cerr << "Invalid IP address: " << optarg
|
|
Packit |
021a8a |
<< endl;
|
|
Packit |
021a8a |
exit(1);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
flags.filter_dst = true;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
// --dstpt-filter
|
|
Packit |
021a8a |
case 'D':
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* even though this won't be an IP address
|
|
Packit |
021a8a |
* aton() won't complain about anything that's
|
|
Packit |
021a8a |
* just digits, so it's an easy check.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (optarg == NULL)
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
flags.filter_dstpt = true;
|
|
Packit |
021a8a |
filters.dstpt = atoi(optarg);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
// --help
|
|
Packit |
021a8a |
case 'h':
|
|
Packit |
021a8a |
help();
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
// --lookup
|
|
Packit |
021a8a |
case 'l':
|
|
Packit |
021a8a |
flags.lookup = true;
|
|
Packit |
021a8a |
// and also set skipdns for sanity
|
|
Packit |
021a8a |
flags.skipdns = true;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
// --mark-truncated
|
|
Packit |
021a8a |
case 'm':
|
|
Packit |
021a8a |
flags.tag_truncate = true;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
// --color
|
|
Packit |
021a8a |
case 'c':
|
|
Packit |
021a8a |
flags.nocolor = false;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
// --no-dynamic
|
|
Packit |
021a8a |
case 'o':
|
|
Packit |
021a8a |
flags.staticsize = true;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
// --no-dns
|
|
Packit |
021a8a |
case 'L':
|
|
Packit |
021a8a |
flags.skipdns = true;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
// --no-loopback
|
|
Packit |
021a8a |
case 'f':
|
|
Packit |
021a8a |
flags.skiplb = true;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
// --no-scroll
|
|
Packit |
021a8a |
case 'p':
|
|
Packit |
021a8a |
flags.noscroll = true;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
// --reverse
|
|
Packit |
021a8a |
case 'r':
|
|
Packit |
021a8a |
sort_factor = -1;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
// --rate
|
|
Packit |
021a8a |
case 'R':
|
|
Packit |
021a8a |
rate = atoi(optarg);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
// --sort
|
|
Packit |
021a8a |
case 'b':
|
|
Packit |
021a8a |
if (*optarg == 'd')
|
|
Packit |
021a8a |
sortby = SORT_DST;
|
|
Packit |
021a8a |
else if (*optarg == 'D') {
|
|
Packit |
021a8a |
sortby = SORT_DST_PT;
|
|
Packit |
021a8a |
} else if (*optarg == 'S')
|
|
Packit |
021a8a |
sortby = SORT_SRC_PT;
|
|
Packit |
021a8a |
else if (*optarg == 'p')
|
|
Packit |
021a8a |
sortby = SORT_PROTO;
|
|
Packit |
021a8a |
else if (*optarg == 's')
|
|
Packit |
021a8a |
sortby = SORT_STATE;
|
|
Packit |
021a8a |
else if (*optarg == 't')
|
|
Packit |
021a8a |
sortby = SORT_TTL;
|
|
Packit |
021a8a |
else if (*optarg == 'b' && flags.counters)
|
|
Packit |
021a8a |
sortby = SORT_BYTES;
|
|
Packit |
021a8a |
else if (*optarg == 'P' && flags.counters)
|
|
Packit |
021a8a |
sortby = SORT_PACKETS;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
// --single
|
|
Packit |
021a8a |
case '1':
|
|
Packit |
021a8a |
flags.single = true;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
// --src-filter
|
|
Packit |
021a8a |
case 's':
|
|
Packit |
021a8a |
if (optarg == NULL)
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
if (!check_ip(optarg, &filters.src, &filters.srcfam)) {
|
|
Packit |
021a8a |
cerr << "Invalid IP address: " << optarg << endl;
|
|
Packit |
021a8a |
exit(1);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
flags.filter_src = true;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
// --srcpt-filter
|
|
Packit |
021a8a |
case 'S':
|
|
Packit |
021a8a |
if (optarg == NULL)
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
flags.filter_srcpt = true;
|
|
Packit |
021a8a |
filters.srcpt = atoi(optarg);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
// --totals
|
|
Packit |
021a8a |
case 't':
|
|
Packit |
021a8a |
flags.totals = true;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
// --version
|
|
Packit |
021a8a |
case 'v':
|
|
Packit |
021a8a |
version();
|
|
Packit |
021a8a |
exit(0);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
// catch-all
|
|
Packit |
021a8a |
default:
|
|
Packit |
021a8a |
// getopts should already have printed a message
|
|
Packit |
021a8a |
exit(1);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (rate < 0 || rate > 60) {
|
|
Packit |
021a8a |
rate = 1;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// Initialize Curses Stuff
|
|
Packit |
021a8a |
static WINDOW *mainwin = NULL;
|
|
Packit |
021a8a |
if (!flags.single) {
|
|
Packit |
021a8a |
mainwin = start_curses(flags);
|
|
Packit |
021a8a |
keypad(mainwin, true);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* We want to keep going until the user stops us
|
|
Packit |
021a8a |
* unless they use single run mode
|
|
Packit |
021a8a |
* in which case, we'll deal with that down below
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
while (1) {
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* We get the screensize_t up-front so we can die if the
|
|
Packit |
021a8a |
* screen doesn't meet our minimum requirements without making
|
|
Packit |
021a8a |
* the user wait while we gather and process all the data.
|
|
Packit |
021a8a |
* We'll do it again afterwards just in case
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
ssize = get_size(flags.single);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (ssize.x < 72) {
|
|
Packit |
021a8a |
term_too_small();
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// And our header size
|
|
Packit |
021a8a |
hdrs = 3;
|
|
Packit |
021a8a |
if (flags.totals) {
|
|
Packit |
021a8a |
hdrs++;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
if (flags.filter_src || flags.filter_dst || flags.filter_srcpt
|
|
Packit |
021a8a |
|| flags.filter_dstpt) {
|
|
Packit |
021a8a |
hdrs++;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// clear maxes
|
|
Packit |
021a8a |
initialize_maxes(max, flags);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// Build our table
|
|
Packit |
021a8a |
build_table(flags, filters, stable, counts, max);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Now that we have the new table, make sure our page/cursor
|
|
Packit |
021a8a |
* positions still make sense.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (curr_state > stable.size() - 1) {
|
|
Packit |
021a8a |
curr_state = stable.size() - 1;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* The bottom of the screen is stable.size()+hdrs+1
|
|
Packit |
021a8a |
* (the +1 is so we can have a blank line at the end)
|
|
Packit |
021a8a |
* but we want to never have py be more than that - ssize.y
|
|
Packit |
021a8a |
* so we're showing a page full of states.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
int bottom = stable.size() + hdrs + 1 - ssize.y;
|
|
Packit |
021a8a |
if (bottom < 0)
|
|
Packit |
021a8a |
bottom = 0;
|
|
Packit |
021a8a |
if (py > (unsigned)bottom)
|
|
Packit |
021a8a |
py = bottom;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Originally I strived to do this the "right" way by calling
|
|
Packit |
021a8a |
* nfct_is_set(ct, ATTR_ORIG_COUNGERS) to determine if
|
|
Packit |
021a8a |
* counters were enabled. BUT, if counters are not enabled,
|
|
Packit |
021a8a |
* nfct_get_attr() returns NULL, so this test is just as
|
|
Packit |
021a8a |
* valid.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* Conversely checking is_set and then get_attr() inside our
|
|
Packit |
021a8a |
* callback is twice the calls per-state if they are enabled,
|
|
Packit |
021a8a |
* for no additional benefit.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (flags.counters && stable.size() > 0 && stable[0]->bytes == 0) {
|
|
Packit |
021a8a |
prompt = "Counters requested, but not enabled in the";
|
|
Packit |
021a8a |
prompt += " kernel!";
|
|
Packit |
021a8a |
flags.counters = 0;
|
|
Packit |
021a8a |
c_warn(mainwin, prompt, flags);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// Sort our table
|
|
Packit |
021a8a |
sort_table(sortby, flags.lookup, sort_factor, stable, sorting);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* From here on out 'max' is no longer "the maximum size of
|
|
Packit |
021a8a |
* this field throughout the table", but is instead the actual
|
|
Packit |
021a8a |
* size to print each field.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* BTW, we do "get_size" again here incase the window changed
|
|
Packit |
021a8a |
* while we were off parsing and sorting data.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
determine_format(mainwin, max, ssize, format, flags);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Now we print out the table in whichever format we're
|
|
Packit |
021a8a |
* configured for
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
print_table(stable, flags, format, sorting, filters, counts, ssize, max,
|
|
Packit |
021a8a |
mainwin, curr_state);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// Exit if we're only supposed to run once
|
|
Packit |
021a8a |
if (flags.single)
|
|
Packit |
021a8a |
exit(0);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// Otherwise refresh the curses display
|
|
Packit |
021a8a |
if (flags.noscroll) {
|
|
Packit |
021a8a |
refresh();
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
prefresh(mainwin, py, px, 0, 0, ssize.y-1, ssize.x-1);
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
//check for key presses for one second
|
|
Packit |
021a8a |
//or whatever the user said
|
|
Packit |
021a8a |
selecttimeout.tv_sec = rate;
|
|
Packit |
021a8a |
selecttimeout.tv_usec = 0;
|
|
Packit |
021a8a |
// I don't care about fractions of seconds. I don't want them.
|
|
Packit |
021a8a |
FD_ZERO(&readfd);
|
|
Packit |
021a8a |
FD_SET(0, &readfd);
|
|
Packit |
021a8a |
select(1,&readfd, NULL, NULL, &selecttimeout);
|
|
Packit |
021a8a |
if (FD_ISSET(0, &readfd)) {
|
|
Packit |
021a8a |
tmpint = wgetch(mainwin);
|
|
Packit |
021a8a |
switch (tmpint) {
|
|
Packit |
021a8a |
// This is ^L
|
|
Packit |
021a8a |
case 12:
|
|
Packit |
021a8a |
handle_resize(mainwin, flags, ssize);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* This is at the top because the rest are in
|
|
Packit |
021a8a |
* order of longopts, and q isn't in longopts
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
case 'q':
|
|
Packit |
021a8a |
goto out;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* General option toggles
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
case 'c':
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* we only want to pay attention to this
|
|
Packit |
021a8a |
* command if colors are available
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (has_colors())
|
|
Packit |
021a8a |
flags.nocolor = !flags.nocolor;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case 'C':
|
|
Packit |
021a8a |
flags.counters = !flags.counters;
|
|
Packit |
021a8a |
if (sortby >= SORT_BYTES)
|
|
Packit |
021a8a |
sortby = SORT_BYTES-1;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case 'h':
|
|
Packit |
021a8a |
interactive_help(sorting, flags, filters);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case 'l':
|
|
Packit |
021a8a |
flags.lookup = !flags.lookup;
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* If we just turned on lookup, also turn on filtering DNS states.
|
|
Packit |
021a8a |
* They can turn it off if they want, but generally this is the safer
|
|
Packit |
021a8a |
* approach.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (flags.lookup) {
|
|
Packit |
021a8a |
flags.skipdns = true;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case 'm':
|
|
Packit |
021a8a |
flags.tag_truncate = !flags.tag_truncate;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case 'o':
|
|
Packit |
021a8a |
flags.staticsize = !flags.staticsize;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case 'L':
|
|
Packit |
021a8a |
flags.skipdns = !flags.skipdns;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case 'f':
|
|
Packit |
021a8a |
flags.skiplb = !flags.skiplb;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case 'p':
|
|
Packit |
021a8a |
switch_scroll(flags, mainwin);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case 'r':
|
|
Packit |
021a8a |
sort_factor = -sort_factor;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case 'b':
|
|
Packit |
021a8a |
if (sortby < SORT_MAX) {
|
|
Packit |
021a8a |
sortby++;
|
|
Packit |
021a8a |
if (!flags.counters && sortby >= SORT_BYTES)
|
|
Packit |
021a8a |
sortby = 0;
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
sortby = 0;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case 'B':
|
|
Packit |
021a8a |
if (sortby > 0) {
|
|
Packit |
021a8a |
sortby--;
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
if (flags.counters)
|
|
Packit |
021a8a |
sortby=SORT_MAX;
|
|
Packit |
021a8a |
else
|
|
Packit |
021a8a |
sortby=SORT_BYTES-1;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case 't':
|
|
Packit |
021a8a |
flags.totals = !flags.totals;
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Update-filters
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
case 'd':
|
|
Packit |
021a8a |
prompt = "New Destination Filter? (leave blank";
|
|
Packit |
021a8a |
prompt += " for none): ";
|
|
Packit |
021a8a |
get_input(mainwin, tmpstring, prompt, flags);
|
|
Packit |
021a8a |
if (tmpstring == "") {
|
|
Packit |
021a8a |
flags.filter_dst = false;
|
|
Packit |
021a8a |
filters.dst = in6addr_any;
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
if (!check_ip(tmpstring.c_str(), &filters.dst, &filters.dstfam)) {
|
|
Packit |
021a8a |
prompt = "Invalid IP,";
|
|
Packit |
021a8a |
prompt += " ignoring!";
|
|
Packit |
021a8a |
c_warn(mainwin, prompt, flags);
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
flags.filter_dst = true;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case 'D':
|
|
Packit |
021a8a |
prompt = "New dstpt filter? (leave blank for";
|
|
Packit |
021a8a |
prompt += " none): ";
|
|
Packit |
021a8a |
get_input(mainwin, tmpstring, prompt, flags);
|
|
Packit |
021a8a |
if (tmpstring == "") {
|
|
Packit |
021a8a |
flags.filter_dstpt = false;
|
|
Packit |
021a8a |
filters.dstpt = 0;
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
flags.filter_dstpt = true;
|
|
Packit |
021a8a |
filters.dstpt = atoi(tmpstring.c_str());
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
wmove(mainwin, 0, 0);
|
|
Packit |
021a8a |
wclrtoeol(mainwin);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case 'R':
|
|
Packit |
021a8a |
prompt = "Rate: ";
|
|
Packit |
021a8a |
get_input(mainwin, tmpstring, prompt, flags);
|
|
Packit |
021a8a |
if (tmpstring != "") {
|
|
Packit |
021a8a |
int i = atoi(tmpstring.c_str());
|
|
Packit |
021a8a |
if (i < 1) {
|
|
Packit |
021a8a |
prompt = "Invalid rate,";
|
|
Packit |
021a8a |
prompt += " ignoring!";
|
|
Packit |
021a8a |
c_warn(mainwin, prompt, flags);
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
rate = i;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case 's':
|
|
Packit |
021a8a |
prompt = "New src filter? (leave blank for";
|
|
Packit |
021a8a |
prompt += " none): ";
|
|
Packit |
021a8a |
get_input(mainwin, tmpstring, prompt, flags);
|
|
Packit |
021a8a |
if (tmpstring == "") {
|
|
Packit |
021a8a |
flags.filter_src = false;
|
|
Packit |
021a8a |
filters.src = in6addr_any;
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
if (!check_ip(tmpstring.c_str(), &filters.src, &filters.srcfam)) {
|
|
Packit |
021a8a |
prompt = "Invalid IP,";
|
|
Packit |
021a8a |
prompt += " ignoring!";
|
|
Packit |
021a8a |
c_warn(mainwin, prompt, flags);
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
flags.filter_src = true;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
wmove(mainwin, 0, 0);
|
|
Packit |
021a8a |
wclrtoeol(mainwin);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case 'S':
|
|
Packit |
021a8a |
prompt = "New srcpt filter? (leave blank for";
|
|
Packit |
021a8a |
prompt += " none): ";
|
|
Packit |
021a8a |
get_input(mainwin, tmpstring, prompt, flags);
|
|
Packit |
021a8a |
if (tmpstring == "") {
|
|
Packit |
021a8a |
flags.filter_srcpt = false;
|
|
Packit |
021a8a |
filters.srcpt = 0;
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
flags.filter_srcpt = true;
|
|
Packit |
021a8a |
filters.srcpt = atoi(tmpstring.c_str());
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
wmove(mainwin, 0, 0);
|
|
Packit |
021a8a |
wclrtoeol(mainwin);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case 'x':
|
|
Packit |
021a8a |
delete_state(mainwin, stable[curr_state], flags);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Window navigation
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
case KEY_DOWN:
|
|
Packit |
021a8a |
case 'j':
|
|
Packit |
021a8a |
if (flags.noscroll)
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* GENERAL NOTE:
|
|
Packit |
021a8a |
* py is the top of the window,
|
|
Packit |
021a8a |
* ssize.y is the height of the window,
|
|
Packit |
021a8a |
* so py+ssize.y is the bottom of the window.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* BOTTOM OF SCROLLING:
|
|
Packit |
021a8a |
* Since stable.size()+hdrs+1 is
|
|
Packit |
021a8a |
* the bottom of the text we've written, if
|
|
Packit |
021a8a |
* py+ssize.y == stable.size()+hdrs+1
|
|
Packit |
021a8a |
* then the bottom of the screen as at the
|
|
Packit |
021a8a |
* bottom of the text, no more scrolling.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* However, we only want to scroll the page
|
|
Packit |
021a8a |
* when the cursor is at the bottom, i.e.
|
|
Packit |
021a8a |
* when curr_state+4 == py+ssize.y
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* If we have room to scroll down AND if cur is
|
|
Packit |
021a8a |
* at the bottom of a page scroll down.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if ((py + ssize.y <= stable.size() + hdrs + 1)
|
|
Packit |
021a8a |
&& (curr_state + 4 == py + ssize.y))
|
|
Packit |
021a8a |
py++;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* As long as the cursor isn't at the end,
|
|
Packit |
021a8a |
* move it down one.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (curr_state < stable.size() - 1)
|
|
Packit |
021a8a |
curr_state++;
|
|
Packit |
021a8a |
prefresh(mainwin, py, px, 0, 0, ssize.y - 1, ssize.x - 1);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case KEY_UP:
|
|
Packit |
021a8a |
case 'k':
|
|
Packit |
021a8a |
if (flags.noscroll)
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* This one is tricky.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* First thing we need to know is when the cursor
|
|
Packit |
021a8a |
* is at the top of the page. This is simply when
|
|
Packit |
021a8a |
* curr_state+hdrs+1 cursor location), is
|
|
Packit |
021a8a |
* exactly one more than the top of the window
|
|
Packit |
021a8a |
* (py), * i.e. when curr_state+hdrs+1 == py+1.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* PAGE SCROLLING:
|
|
Packit |
021a8a |
* IF we're not page-scrolled all the way up
|
|
Packit |
021a8a |
* (i.e. py > 0)
|
|
Packit |
021a8a |
* AND the cursor is at the top of the page
|
|
Packit |
021a8a |
* OR the cursor is at the top of the list,
|
|
Packit |
021a8a |
* AND we're not yet at the top (showing
|
|
Packit |
021a8a |
* the headers).
|
|
Packit |
021a8a |
* THEN we scroll up.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* CURSOR SCROLLING:
|
|
Packit |
021a8a |
* Unlike KEY_DOWN, we don't break just because
|
|
Packit |
021a8a |
* the cursor can't move anymore - on the way
|
|
Packit |
021a8a |
* ip we may still have page-scrolling to do. So
|
|
Packit |
021a8a |
* test to make sure we're not at state 0, and
|
|
Packit |
021a8a |
* if so, we scroll up.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Basically:
|
|
Packit |
021a8a |
* IF the cursor bumps the top of the screen
|
|
Packit |
021a8a |
* OR we need to scroll up for headers
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if ((py > 0 && (curr_state + hdrs + 1) == (py + 1))
|
|
Packit |
021a8a |
|| (curr_state == 0 && py > 0))
|
|
Packit |
021a8a |
py--;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
if (curr_state > 0)
|
|
Packit |
021a8a |
curr_state--;
|
|
Packit |
021a8a |
prefresh(mainwin, py, px, 0, 0, ssize.y - 1, ssize.x - 1);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
// 4 is ^d
|
|
Packit |
021a8a |
case 4:
|
|
Packit |
021a8a |
case KEY_NPAGE:
|
|
Packit |
021a8a |
case KEY_SNEXT:
|
|
Packit |
021a8a |
if (flags.noscroll)
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* If the screen is bigger than the text,
|
|
Packit |
021a8a |
* and the cursor is at the bottom, ignore.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (stable.size() + hdrs + 1 < ssize.y && curr_state == stable.size())
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Otherwise, if the bottom of the screen
|
|
Packit |
021a8a |
* (current position + screen size
|
|
Packit |
021a8a |
* == py + ssize.y)
|
|
Packit |
021a8a |
* were to go down one screen (thus:
|
|
Packit |
021a8a |
* py + ssize.y*2),
|
|
Packit |
021a8a |
* and that is bigger than the whole pad, just
|
|
Packit |
021a8a |
* go to the bottom.
|
|
Packit |
021a8a |
*
|
|
Packit |
021a8a |
* Otherwise, go down a screen size.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (py + ssize.y * 2 > stable.size() + hdrs + 1) {
|
|
Packit |
021a8a |
py = stable.size() + hdrs + 1 - ssize.y;
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
py += ssize.y;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* For the cursor, we try to move it down one
|
|
Packit |
021a8a |
* screen as well, but if that's too far,
|
|
Packit |
021a8a |
* we bring it up to the largest number it can
|
|
Packit |
021a8a |
* be.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
curr_state += ssize.y;
|
|
Packit |
021a8a |
if (curr_state > stable.size()) {
|
|
Packit |
021a8a |
curr_state = stable.size();
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
prefresh(mainwin, py, px, 0, 0, ssize.y - 1, ssize.x - 1);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
// 21 is ^u
|
|
Packit |
021a8a |
case 21:
|
|
Packit |
021a8a |
case KEY_PPAGE:
|
|
Packit |
021a8a |
case KEY_SPREVIOUS:
|
|
Packit |
021a8a |
if (flags.noscroll)
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* If we're at the top, ignore
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (py == 0 && curr_state == 0)
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* Otherwise if we're less than a page from the
|
|
Packit |
021a8a |
* top, go to the top, else go up a page.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (py < ssize.y) {
|
|
Packit |
021a8a |
py = 0;
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
py -= ssize.y;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* We bring the cursor up a page too, unless
|
|
Packit |
021a8a |
* that's too far.
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (curr_state < ssize.y) {
|
|
Packit |
021a8a |
curr_state = 0;
|
|
Packit |
021a8a |
} else {
|
|
Packit |
021a8a |
curr_state -= ssize.y;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
prefresh(mainwin, py, px, 0, 0, ssize.y - 1, ssize.x - 1);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case KEY_HOME:
|
|
Packit |
021a8a |
if (flags.noscroll)
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
px = py = curr_state = 0;
|
|
Packit |
021a8a |
prefresh(mainwin, py, px, 0, 0, ssize.y - 1, ssize.x - 1);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
case KEY_END:
|
|
Packit |
021a8a |
if (flags.noscroll)
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
py = stable.size() + hdrs + 1 - ssize.y;
|
|
Packit |
021a8a |
if (py < 0)
|
|
Packit |
021a8a |
py = 0;
|
|
Packit |
021a8a |
curr_state = stable.size();
|
|
Packit |
021a8a |
prefresh(mainwin, py, px, 0, 0, ssize.y - 1, ssize.x - 1);
|
|
Packit |
021a8a |
break;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* If we got a sigwinch, we need to redraw
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
if (need_resize) {
|
|
Packit |
021a8a |
handle_resize(mainwin, flags, ssize);
|
|
Packit |
021a8a |
need_resize = false;
|
|
Packit |
021a8a |
}
|
|
Packit |
021a8a |
} // end while(1)
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
out:
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
/*
|
|
Packit |
021a8a |
* The user has broken out of the loop, take down the curses
|
|
Packit |
021a8a |
*/
|
|
Packit |
021a8a |
end_curses();
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
// And we're done
|
|
Packit |
021a8a |
return(0);
|
|
Packit |
021a8a |
|
|
Packit |
021a8a |
} // end main
|