Blame iptstate.cc

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