summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2020-07-30 07:36:32 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2020-07-30 07:36:32 +0000
commitb2a49bfedb5ec10a8d521b8ff8d00829842c4567 (patch)
tree72824c919215a7331d5655d2a645bed3df60da90
parentInitial commit. (diff)
downloadiptraf-ng-b2a49bfedb5ec10a8d521b8ff8d00829842c4567.tar.xz
iptraf-ng-b2a49bfedb5ec10a8d521b8ff8d00829842c4567.zip
Adding upstream version 1:1.2.0.upstream/1%1.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--.gitignore44
-rw-r--r--AUTHORS23
-rw-r--r--CHANGES121
-rw-r--r--CHANGES.old960
-rw-r--r--Documentation/iptraf-configmenu.pngbin0 -> 7013 bytes
-rw-r--r--Documentation/iptraf-dstat1.pngbin0 -> 6357 bytes
-rw-r--r--Documentation/iptraf-editfilter.pngbin0 -> 4909 bytes
-rw-r--r--Documentation/iptraf-filtermenu.pngbin0 -> 4576 bytes
-rw-r--r--Documentation/iptraf-gstat1.pngbin0 -> 2133 bytes
-rw-r--r--Documentation/iptraf-hw.pngbin0 -> 5533 bytes
-rw-r--r--Documentation/iptraf-hwsort.pngbin0 -> 9774 bytes
-rw-r--r--Documentation/iptraf-ipfltdlg.pngbin0 -> 8864 bytes
-rw-r--r--Documentation/iptraf-ipfltlist.pngbin0 -> 4167 bytes
-rw-r--r--Documentation/iptraf-ipfltmenu.pngbin0 -> 4736 bytes
-rw-r--r--Documentation/iptraf-ipfltnamedlg.pngbin0 -> 4400 bytes
-rw-r--r--Documentation/iptraf-iptm1.pngbin0 -> 12368 bytes
-rw-r--r--Documentation/iptraf-iptmsort.pngbin0 -> 11705 bytes
-rw-r--r--Documentation/iptraf-logprompt.pngbin0 -> 5549 bytes
-rw-r--r--Documentation/iptraf-mmenu.pngbin0 -> 3925 bytes
-rw-r--r--Documentation/iptraf-othipfltdefine.pngbin0 -> 5134 bytes
-rw-r--r--Documentation/iptraf-othipfltdlg.pngbin0 -> 8148 bytes
-rw-r--r--Documentation/iptraf-othipfltselect.pngbin0 -> 4532 bytes
-rw-r--r--Documentation/iptraf-pktsize.pngbin0 -> 7379 bytes
-rw-r--r--Documentation/iptraf-tcpflt-dlg2.pngbin0 -> 6728 bytes
-rw-r--r--Documentation/iptraf-tcpfltmenu.pngbin0 -> 5716 bytes
-rw-r--r--Documentation/iptraf-tcpudp.pngbin0 -> 9398 bytes
-rw-r--r--Documentation/iptraf-tcpudpsort.pngbin0 -> 10159 bytes
-rw-r--r--Documentation/iptraf-timermenu.pngbin0 -> 7608 bytes
-rw-r--r--Documentation/iptraf.xpm10
-rw-r--r--Documentation/manual.sgml.in4500
-rw-r--r--Documentation/stylesheet-images/next.gifbin0 -> 964 bytes
-rw-r--r--Documentation/stylesheet-images/note.gifbin0 -> 1070 bytes
-rw-r--r--Documentation/stylesheet-images/prev.gifbin0 -> 944 bytes
-rw-r--r--Documentation/stylesheet-images/tip.gifbin0 -> 1029 bytes
-rw-r--r--Documentation/stylesheet-images/up.gifbin0 -> 922 bytes
-rw-r--r--FAQ74
-rwxr-xr-xGEN-VERSION-FILE34
-rw-r--r--INSTALL20
-rw-r--r--LICENSE341
-rw-r--r--Makefile446
-rw-r--r--README81
-rw-r--r--README.contact16
-rw-r--r--README.indent19
-rw-r--r--README.interfaces58
-rw-r--r--README.resolving51
-rw-r--r--iptraf-ng-logrotate.conf9
-rw-r--r--src/addproto.h28
-rw-r--r--src/arphdr.h24
-rw-r--r--src/attrs.h38
-rw-r--r--src/built-in.h9
-rw-r--r--src/capt-mmap-v2.c154
-rw-r--r--src/capt-mmap-v2.h6
-rw-r--r--src/capt-mmap-v3.c196
-rw-r--r--src/capt-mmap-v3.h6
-rw-r--r--src/capt-recvmmsg.c143
-rw-r--r--src/capt-recvmmsg.h6
-rw-r--r--src/capt-recvmsg.c89
-rw-r--r--src/capt-recvmsg.h6
-rw-r--r--src/capt.c212
-rw-r--r--src/capt.h36
-rw-r--r--src/capture-pkt.c76
-rw-r--r--src/cidr.c90
-rw-r--r--src/cidr.h9
-rw-r--r--src/counters.c40
-rw-r--r--src/counters.h22
-rw-r--r--src/deskman.c300
-rw-r--r--src/deskman.h26
-rw-r--r--src/detstats.c671
-rw-r--r--src/detstats.h6
-rw-r--r--src/dirs.h139
-rw-r--r--src/error.c25
-rw-r--r--src/error.h6
-rw-r--r--src/fltdefs.h70
-rw-r--r--src/fltedit.c617
-rw-r--r--src/fltedit.h11
-rw-r--r--src/fltmgr.c341
-rw-r--r--src/fltmgr.h34
-rw-r--r--src/fltselect.c203
-rw-r--r--src/fltselect.h27
-rw-r--r--src/getpath.c41
-rw-r--r--src/getpath.h11
-rw-r--r--src/hostmon.c996
-rw-r--r--src/hostmon.h7
-rw-r--r--src/ifaces.c267
-rw-r--r--src/ifaces.h16
-rw-r--r--src/ifstats.c726
-rw-r--r--src/ifstats.h7
-rw-r--r--src/ipfilter.c430
-rw-r--r--src/ipfilter.h12
-rw-r--r--src/ipfrag.c248
-rw-r--r--src/ipfrag.h34
-rw-r--r--src/iptraf-ng-compat.h147
-rw-r--r--src/iptraf-ng.898
-rw-r--r--src/iptraf.c549
-rw-r--r--src/itrafmon.c939
-rw-r--r--src/itrafmon.h6
-rw-r--r--src/landesc.c365
-rw-r--r--src/landesc.h27
-rw-r--r--src/list.h89
-rw-r--r--src/log.c156
-rw-r--r--src/log.h23
-rw-r--r--src/logvars.h8
-rw-r--r--src/options.c387
-rw-r--r--src/options.h19
-rw-r--r--src/othptab.c797
-rw-r--r--src/othptab.h141
-rw-r--r--src/packet.c555
-rw-r--r--src/packet.h63
-rw-r--r--src/parse-options.c160
-rw-r--r--src/parse-options.h42
-rw-r--r--src/parseproto.c160
-rw-r--r--src/parseproto.h15
-rw-r--r--src/pktsize.c366
-rw-r--r--src/pktsize.h6
-rw-r--r--src/promisc.c110
-rw-r--r--src/promisc.h9
-rw-r--r--src/rate.c131
-rw-r--r--src/rate.h36
-rw-r--r--src/revname.c263
-rw-r--r--src/revname.h22
-rw-r--r--src/rvnamed.c409
-rw-r--r--src/rvnamed.h32
-rw-r--r--src/serv.c1313
-rw-r--r--src/serv.h23
-rw-r--r--src/servname.c34
-rw-r--r--src/servname.h12
-rw-r--r--src/sockaddr.c185
-rw-r--r--src/sockaddr.h19
-rw-r--r--src/tcptable.c1131
-rw-r--r--src/tcptable.h147
-rw-r--r--src/timer.c49
-rw-r--r--src/timer.h8
-rw-r--r--src/tui/README25
-rw-r--r--src/tui/input.c181
-rw-r--r--src/tui/input.h40
-rw-r--r--src/tui/labels.c39
-rw-r--r--src/tui/labels.h9
-rw-r--r--src/tui/listbox.c226
-rw-r--r--src/tui/listbox.h44
-rw-r--r--src/tui/menurt.c283
-rw-r--r--src/tui/menurt.h57
-rw-r--r--src/tui/msgboxes.c105
-rw-r--r--src/tui/msgboxes.h12
-rw-r--r--src/tui/winops.c72
-rw-r--r--src/tui/winops.h19
-rw-r--r--src/usage.c69
-rw-r--r--src/wrapper.c80
147 files changed, 23580 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6079c91
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,44 @@
+# NOTE! Please use 'git ls-files -i --exclude-standard'
+# command after changing this file, to see if there are
+# any tracked files which get ignored after the change.
+
+# normal rules
+.*
+*.o
+*.lo
+*.la
+*.html
+*.pdf
+*.sgml
+
+# ignore binaries
+/iptraf-ng
+/rvnamed-ng
+
+# don't ignore git files
+!.gitignore
+
+# gnu global files
+GPATH
+GRTAGS
+GSYMS
+GTAGS
+
+# cscope files
+cscope.*
+ncscope.*
+
+# autotools
+/configure
+/autom4te.cache/
+/config.log
+/config.mak.append
+/config.mak.autogen
+/config.status
+
+# misc
+*~
+\#*#
+/iptraf-ng.spec
+VERSION-FILE
+Documentation/version
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..96f896c
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,23 @@
+Original author of iptraf:
+--------------------------
+
+ 1997 - 2004 Gerard Paul Java
+
+Since no progress was made since 2004 and the author didn't answer
+any question if he will be working on iptraf anytime soon again,
+Nikola Pajkovsky from RedHat took over the project in 2010 and made
+a fork named iptraf-ng.
+
+iptraf-ng maintainer:
+---------------------
+ 2010 -2015 Nikola Pajkovsky <npajkovs@redhat.com>
+ 2016 - Phil Cameron <pcameron@redhat.com>
+
+Contributors:
+-------------
+ 2010 - 2015 Nikola Pajkovsky <npajkovs@redhat.com>
+ 2010 Jan Rafaj <jr-tools@cedric.unob.cz>
+ 2010 Petr Uzel <petr.uzel@suse.cz>
+ 2011 Jan Engelhardt <jengelh@medozas.de>
+ 2012 - now Vitezslav Samel <vitezslav@samel.cz>
+ 2016 - now Phil Cameron <pcameron@redhat.com>
diff --git a/CHANGES b/CHANGES
new file mode 100644
index 0000000..e7140a2
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,121 @@
+CHANGES file for iptraf-ng
+
+* Thu Jun 04 2020 Vitezslav Samel <vitezslav@samel.cz> - 1.2.0
+- ipfrag: code refactoring (Nikola Pajkovsky)
+- ifstats: sort interfaces by name (Jan Engelhardt)
+- ifstats: fix memory leak (Phil Cameron)
+- documentation update (Phil Cameron)
+All changes below are done by Vitezslav Samel:
+Fixes:
+- ipmon: fix division by zero
+- fix: detstats(), ifstats(): handle packets with incorrect header checksum
+- fix: positionptr(): properly allocate newly created interfaces
+- fix: detstats(): properly account non-IP packets
+- fix: properly init curses (fixes view on some utf-8 terminals)
+- fix: cidr_split_address(): fix buffer overflow
+- ipmon: printentry(): fix printing of huge values
+- build: use correct libraries (wide version of -lpanel)
+- fix unsafe handling of printf() args (RedHat Bugzilla: 1842690)
+- fix the CPU hog if the interface gets removed (RedHat Bugzilla: 1572750)
+Enhancements:
+- introduce packet capturing abstraction: add recvmmsg(), TPACKET_V2
+ and TPACKET_V3 mmap()ed capturing modules: this allow us to capture
+ in multigigabit speeds
+- add partial support for IPoIB interfaces (full support cannot be done
+ because the kernel interface doesn't give us source address)
+ (RedHat Bugzilla: 1140211)
+- merge rvnamed-ng into iptraf-ng
+- allow scrolling with Home, End, PageUp and PageDown keys
+- show dropped packet count
+- pktsize: print in and out counters
+- ifstats: show total packet rate and packet drop across all interfaces
+- ipmon: show OSPF protocol version
+- hostmon, ipmon: update screen only when needed (vastly reduces CPU
+ usage and also reduces packet drops)
+- update source code to compile cleanly on modern gcc
+- numerous code refactoring/cleaning up all over the source tree
+
+* Tue Jul 23 2013 Nikola Pajkovsky <npajkovs@redhat.com> - 1.1.4
+- locking code rewrite: only one instance is allowed now
+- promiscuous mode rewrite
+- build system: install iptraf-ng to sbin
+- remove token-ring support
+- remove ISDN interfaces support
+- preparation for packet capturing into the file
+- source code cleanups
+- bugfix: don't segfault when there are no ports to remove
+- rvnamed: fix the IPv6 resolving
+- add 802.1ad and QinQ VLAN handling
+- optimize code (to not use that much CPU)
+
+* Wed May 23 2012 Nikola Pajkovsky <npajkovs@redhat.com> - 1.1.3
+- new building system (based only on make, no automake/autoconf)
+- code cleanups
+- SIT tunnels support
+- space for HW addresses fix
+- sort interfaces by ifindex
+- print rates every second using moving average (over last 5 seconds)
+- packet_get() bugfix (don't count packets when there's no packet ready)
+- fix segfault in the tui/* code
+- fix checksumming for odd-sized IPv4 header
+
+* Fri May 04 2012 Nikola Pajkovsky <npajkovs@redhat.com> - 1.1.2
+- massive code cleanup
+- fix PPP handling
+- move the splash screen to the main menu
+- fix capturing on tun-like interfaces
+- support GRE-over-IP tunnels
+- fix ethernet descriptions
+- change units: bits/sec (bytes/sec) to kbps (kBps)
+- use bind() to lock the socket on interface (should decrease CPU
+ utilization on systems with very busy interfaces)
+- warnings cleanup
+- fix packet length counting for large packets
+- hostmon(): count IPv6 as IP protocol too
+
+* Thu Feb 02 2012 Nikola Pajkovsky <npajkovs@redhat.com> - 1.1.1
+- fix frames in UTF-8 locales
+- fix IPv6 port stats
+- fix IPv6 byte counting
+- fix port data rate
+- fix for interfaces with long name
+
+* Wed Jan 11 2012 Nikola Pajkovsky <npajkovs@redhat.com> - 1.1.0
+- build system fixes
+- brand new command line options parser
+- rename iptraf to iptraf-ng (binaries, mans)
+- code cleanup (useless code removal, warnings erradication, ...)
+- new ip checksum based on rfc1071 implementation
+- landesc.[c,h]: full rewrite
+
+* Sun Apr 11 2010 Nikola Pajkovsky <npajkovs@redhat.com> - 1.0.3
+- documentation cleanup
+
+* Wed Mar 24 2010 Nikola Pajkovsky <npajkovs@redhat.com> - 1.0.2
+- remove warnings
+- rif of PKG_CHECK_MODULES
+- tx_operate_listbox(): use proper format string for size_t in snprintf
+- ltrim(): simplify function and fix situation when strings overlap in strcpy
+- build: pass libpanel_CFLAGS and ncurses_CFLAGS to compiler
+- selectiface(): use strncpy to prevent buffer overflow and thus avoid gcc warning
+- init_promisc_list(): use IF_NAMESIZE as size of buffer for interface name
+- main(): allow regular users to run iptraf if the sticky-bit is set
+- fix strcpy overlap memory
+- remove -Werror option
+
+* Thu Mar 04 2010 Nikola Pajkovsky <npajkovs@redhat.com> - 1.0.1
+- remove dereferencing type-punned pointer will break strict-aliasing rules
+- convmacaddr(): fix assignment casting. One more warning gone.
+- ipmon(), servmon(): unnecessary casting is gone. Fixes strict-aliasing.
+- Fix compilation issues and crash within LAN station monitor
+
+* Mon Mar 01 2010 Nikola Pajkovsky <npajkovs@redhat.com> - 1.0.0
+- compile with -std=gnu99 -pedantic -Wall -Werror
+- add support for devices(used patches from gentoo, debian and fedora):
+ vlan, hsi, ctc, ath, bond, ra, bnep, dsl, modem, ni, br, tap, dummy, vmnet
+- add longer intefaces names(18 chars)
+- add iptraf -u - show unsupported interfaces(fpeters@debian.org)
+- check if macro is defined ICMP6_DST_UNREACH_NOTNEIGHBOR(jer@gentoo.org)
+- add ipv6 support
+- remove wierd Setup compilation and replaced it by autotools
+- import original iptraf-3.0.0
diff --git a/CHANGES.old b/CHANGES.old
new file mode 100644
index 0000000..29bee6b
--- /dev/null
+++ b/CHANGES.old
@@ -0,0 +1,960 @@
+CHANGES File for IPTraf 3.0.0
+
+Changes to IPTraf 2.7.0 and new features in IPTraf 3.0.0
+
+ New filter behavior. Except for TCP traffic in the IP traffic
+ monitor, filters now do not automatically match reverse packets
+ for TCP and UDP IPTraf-wide. Rather, each filter entry has
+ a field which tells IPTraf whether to match packets flowing
+ in the direction opposite that specified.
+
+ The filters for non-TCP, non-UDP IP traffic (ICMP, IGRP, OSPF,
+ etc.) which never automatically matched packets flowing in the
+ opposite direction, now have that same option field. This way
+ related packets (like ICMP echo request/echo reply) can be
+ matched with a single entry.
+
+ Because reverse-matching is no longer the default IPTraf-wide,
+ the labels are now changed to read Source and Destination.
+
+ Default value for blank address filter fields is now 0.0.0.0,
+ rather than 255.255.255.255. Fields are therefore no longer
+ pre-filled with 0.0.0.0.
+
+ Miscellaneous IP filter entries feature a field for other IP
+ protocols not specifically indicated in the dialog. The user
+ must enter a comma-separated list of individual protocols or a
+ range. IP protocols are defined in the /etc/protocols file.
+
+ The IP traffic monitor consults the /etc/protocols file for
+ miscellaneous IP packets for the protocol names. Previously
+ recognized protocols (ICMP, UDP, OSPF, etc) are still looked up
+ internally for performance reasons.
+
+ The filter rule selection now indicates the mask in CIDR format
+ (e.g. 10.1.0.0/16) for clarity and to save screen space.
+
+ Filter selection list box is now alphabetically sorted.
+
+ Likewise, the CIDR notation can be used when entering IP address
+ data. However the CIDR notation is translated into a mask and
+ discarded. Subsequent editing of the filter will show the
+ corresponding mask.
+
+ Changed color coding for unknown IP packets (those looked up
+ from /etc/services to bright white on blue (instead of yellow on
+ red, which looked like "errors").
+
+ Added internal recognition for L2TP, IPSec AH, and IPSec ESP
+ packets.
+
+ Changed size of the IP traffic monitor's TCP hash table to 1033
+ buckets. Prime number used to improve hash efficiency.
+
+ A new function tx_box() has been added to the screen support
+ library as a solution to the ncurses box() function not accepting
+ the color set by wattrset(), at least on Red Hat 7.3. All calls
+ to box() have been replaced with this tx_box() instead. It takes
+ exactly the same parameters.
+
+ Added support for tun and brg (tunneling and bridging) interfaces.
+ Thanks to Marcio Gomes <tecnica_at_microlink.com.br>.
+
+ Modified logging options. The -L parameter now works with any
+ command-line invocation of a facility, even in foreground mode.
+
+ Added -I command-line parameter to override logging interval
+ configuration option.
+
+ (Thanks to the contributors of the -I and -L patches. I lost your
+ emails when SEUL reinstalled. Please acknowledge. Thanks.
+
+ Corrected promiscuous mode control code. It ignored Token Ring
+ interfaces.
+
+Changes to IPTraf 2.6.1 and new features in IPTraf 2.7.0
+
+ Corrected bug wherein the detailed interface statistics
+ did not filter out the packets based on the selected
+ interface. Thanks to the members of the mailing list for
+ this.
+
+ Corrected minor interface name comparison bugs in the
+ general interface statistics and TCP/UDP service statistics.
+
+ Corrected stale locks when IPTraf did not start due to an
+ improper terminal size.
+
+ Added support for additional DVB interfaces sm2*, sm3*, penta*.
+
+ Added support for wireless LAN interfaces (wlan*, wvlan*).
+
+ Fixed segfault that occurs when /proc/net/dev is empty or
+ contains no active interfaces. Thanks to Chris Armstrong
+ <wolfwings_at_zana.changa.nu> for actually trying it out.
+
+ Added error box to handle the /proc/net/dev error condition
+ mentioned above.
+
+ Added error box when tx_operate_listbox is invoked on an empty
+ list.
+
+Changes to IPTraf 2.6.0
+
+ Corrected a segfault in the IP traffic monitor and TCP/UDP service
+ breakdown when a sort is attempted on an empty screen. Thanks
+ to <lord_at_elreyforce.org> for the report.
+
+ Corrected segfaults in the TCP/UDP service monitor when
+ scrolling using PgUp and PgDn (or space and '-'). Thanks
+ to Ross Gibson <windows_at_prefixservice.com>.
+
+ Corrected post-sorting PgUp problem in TCP/UDP monitor.
+
+ Corrected inaccuracies in the IP traffic monitor's TCP byte
+ counts and flow rates. *** THE BUG ADDRESSED BY THIS CORRECTION
+ DEFERS IPTRAF 2.6.0. ***
+
+ Adjusted black-and-white color scheme.
+
+ Minor adjustments to the printlargenumber() function.
+
+ Minor cosmetic adjustments.
+
+New features in IPTraf 2.6.0 and changes to IPTraf 2.5.0
+
+ Added support for Token Ring interfaces. Thanks to many people
+ for help with patches and testing, including J. Kahn Koontz
+ <csjmk_at_eiu.edu>, Dan Seto <mail_at_seto.org>, and Tomas Dvorak
+ <avatar_at_kanal.ucw.cz>.
+
+ Added support for sbni long-range modem interfaces (Dmitry
+ Sergienko <trooper_at_dolphin.unity.net>).
+
+ Added support for Free s/WAN IPSec logical interfaces (Doug Nazar
+ <nazard_at_dragoninc.on.ca>).
+
+ Code cleanup. Got rid of an ugly goto in itrafmon.c. I hate
+ goto no matter what.
+
+ Moved write_timeout_log.c to tcptable.c.
+
+ Recoded the PgUp/PgDn routines in the IP traffic monitor,
+ TCP/UDP service monitor, and LAN station monitor. These
+ routines now directly manipulate the table pointers instead
+ of merely calling the single-line scrolling routines repeatedly.
+ Faster. More efficient.
+
+ Added a highlight bar to the IP traffic monitor, allowing better
+ readability, especially on long-line screens (> 80 characters),
+ and individual flow rate computation.
+
+ Added flow rates for the highlighted TCP flows (IP traffic
+ monitor) and TCP/UDP ports (TCP/UDP statistical breakdown) I
+ believe this is the best way to allow viewing of data rates
+ without excessively sacrificing CPU time for packet capture.
+
+ Filters now apply to all facilities except the packet size
+ breakdown and LAN station monitor. You can now view the loads
+ and protocol breakdowns on selected packets only using the
+ filters.
+
+ No more byte counters in the IP traffic monitor. This line now
+ just contains a simple packet counter at one end, and the TCP
+ flow rate information at the other.
+
+ Moved menu, selection listbox, and dialog box functions to a
+ separate support/ directory. These routines are first compiled
+ into a library and later on linked into iptraf.
+
+ Added a confirmation box to the main menu's Exit command. This
+ is as much for me as it is for a lot of people. I accidentaly
+ exit too.
+
+ Added broadcast packet and byte counts to the detailed interface
+ statistics log.
+
+ Some cosmetic adjustment.
+
+ Added 5-minute timeout for rvnamed child processes.
+
+New features in IPTraf 2.5.0 and changes to IPTraf 2.4.0
+
+ Now includes a more specific dialog for non-TCP and non-UDP
+ filters. Allows specification of packets by source and
+ destination IP addresses.
+
+ Better organized the filter management and manipulation
+ functions in fltedit.c, fltselect.c, othipflt.c, and utfilter.c.
+
+ othfilter.c renamed to fltselect.c, same thing with the .h.
+
+ All filters are now unified in a single data structure allowing
+ handling of TCP, UDP, misc IP, and non-IP toggles with one set
+ of functions.
+
+ Separate TCP and non-TCP filter menus abolished, everything
+ is now grouped under a Filters... submenu under the main menu.
+
+ Corrected wrong placement of timer in the packet size breakdown.
+
+ Corrected scanning code for timed out entries in the IP traffic
+ monitor sort function. Wrong computation for elapsed time
+ resulted in active connections being placed in the list of
+ closed entries. Thanks to Gal Laszlo <slowTCP_at_hotmail.com> for
+ pointing out the symptom.
+
+ Added support for Frame Relay FRAD/DLCI interfaces. Thanks to
+ Raffaele Gariboldi <lele_at_italynetwork.it> for the information
+ and testing.
+
+ Sorting is now done with the Quicksort algorithm.
+
+ IP Traffic Monitor now adds connection entries to the TCP window
+ upon the receipt of header-only packets. There are cases in which
+ we have to check for possible TCP scans which are implemented with
+ non-SYN packets.
+
+ The reverse DNS lookup function revname() now times out after
+ five seconds, and stops reverse lookups for that session in case
+ rvnamed dies.
+
+ Added some notes to the packet size breakdown window.
+
+ Moved rvnamed cache index update code such that updating of the
+ cache indexes will only be performed once fork() succeeds,
+ otherwise, the allocated slot will just be reallocated for
+ the next queries. This is so that should the fork() fail,
+ future invocations for that IP address won't have the rvnamed
+ parent thinking its resolving when there actually wasn't a child
+ performing the resolution. If the fork() problem condition was
+ temporary, the next invocation can still have rvnamed fork() off
+ to resolve the address. This of course assumes the IP address
+ hasn't expired from the cache.
+
+ Some cosmetic updates (as always).
+
+ The manual features a new format for the sidebars. Corrected
+ typos and spelling errors.
+
+ iptraf-x.y.z.tar.gz no longer comes with precompiled
+ binaries. However a separate iptraf-x.y.z.i386.bin.tar.gz will
+ come only with the precompiled x86 executable programs
+ (i386/glibc-2.1/ncurses-5.0).
+
+New features in IPTraf 2.4.0 and changes to IPTraf 2.3.1
+
+ This version now allows multiple instances of the same facility
+ in different processes, but only one instance can monitor an
+ interface.
+
+ As a consequence of the above changes, the default names of the
+ logfiles then reflect the instance or interface being
+ monitored.
+
+ Implemented a dialog box allowing the user to log to a custom
+ log file.
+
+ Implemented -L command-line parameter to allow specification of
+ the log file name when IPTraf is started with the -B parameter.
+
+ Removed hardcoded UNIX-domain socket name bound by IPTraf, instead
+ a socket name is generated from the current time and pid. Also
+ removed hardcoded socket name in rvnamed, to which it directs
+ replies to IPTraf. rvnamed still binds to hardcoded socket names
+ though.
+
+ IP Traffic Monitor can optionally display the source MAC addresses
+ for LAN-based packets. Added appropriate configuration item.
+
+ IPTraf now reads /etc/ethers in addition to its own database of
+ MAC addresses. Thanks to Frederic Peters <fpeters_at_debian.org> for
+ the patch.
+
+ Moved time-related configuration items to a Timers... submenu to
+ save on screen space.
+
+ The version.h file no longer exists, rather, a plain version file
+ is in place containing merely the version number. The Makefile
+ reads this file, determines the target machine information
+ and passes this data to the compiler with -D parameters.
+
+ Imposed an upper limit of 200 on rvnamed child processes.
+ rvnamed should really not go runaway with a normally-functioning
+ DNS server, but I had the good fortune of experiencing a dead DNS
+ server while monitoring. Took my machine down real fast.
+
+ Precompiled executables now require glibc-2.1 dynamic libaries.
+
+ Included a Setup installation script to ease somewhat the
+ installation process (installation can still be done the old way
+ though).
+
+ Cosmetic/color changes.
+
+ Reflected changes to manual.
+
+Changes to IPTraf 2.3.0
+
+ Fixed segfault bug when sorting is attempted on an empty TCP
+ window. Thanks to Ramon van Elten <mainwave_at_datura.cx> for the
+ report and for the assistance in diagnosis.
+
+ Fixed cosmetic error (sort progress window doesn't disappear)
+ when attempt is made to sort a TCP window with only 1 entry.
+ Thanks again to Ramon for the report.
+
+ Updated some comments.
+
+New features in IPTraf 2.3.0 and changes to IPTraf 2.2.2
+
+ Implemented sorting in the IP traffic monitor, TCP/UDP statistical
+ breakdown, and LAN station monitor. Great thanks go to Gal Laszlo
+ <slowTCP_at_hotmail.com> for the patch. (Note to Gal: I had to do a
+ heck of a lot of overhaul, and had to implement a clearer screen
+ design, but your patch provided the basis :) Thanks a lot.)
+
+ Implemented better bounds checking in the text input routine.
+
+ Added information boxes to TCP/UDP delete and detach filter
+ functions.
+
+ Added recognition of GRE packets. Modified non-TCP display filters
+ accordingly.
+
+ Fixed bug in unrecognized IP display and filter code.
+
+ Added filter item for unrecognized IP packets.
+
+ Removed leftover code from the old warning on IP masquerading.
+
+ Reflected changes and corrected typos in manual.
+
+Changes to IPTraf 2.2.1
+
+ Fixed recognition problem with DVB interfaces.
+
+ Fixed small buffer overrun in TCP timeout log routine, which can
+ cause a segmentation fault under certain conditions.
+
+ Minor cosmetic adjustment in TCP connection window.
+
+Changes to IPTraf 2.2.0
+
+ Fixed segfault in IP Traffic Monitor due to packets from an
+ unsupported link type.
+
+ Fixed segfault in promiscuous mode management module in the (rare)
+ case of a failure to save or load the interface flags from the
+ temporary storage files. Normally due to a bad installation.
+ Thanks to Udo A. Steinberg <sorisor_at_Hell.WH8.TU-Dresden.De> for
+ the report.
+
+ Added support for Ethernet-emulated FDDI interfaces. Thanks to Udo
+ A. Steinberg <sorisor_at_Hell.WH8.TU-Dresden.De> for the report and
+ help with the testing.
+
+ Added support for DVB interfaces, thanks to Alex
+ <vasile_at_keeper.meganet.ro> for the notification and the help.
+
+ Replaced inet_addr() references on filter address entries with
+ inet_aton(). This fixes failure of filters on packets with
+ 255.255.255.255 in their source or destination address fields.
+ Thanks for Peter Magnusson for the report and the test
+ environment.
+
+ Overhauled TCP/UDP editing facility. Fixed bug wherein garbage
+ entries remain in the filter's parameter list even if an insert/
+ add dialog is aborted.
+
+ Fixed detailed interface statistics logging bug (activity and
+ packets-per-second figures were the same).
+
+ Apologies to Dustin Trammell for my failure to credit him for his
+ report on the behavior of IPTraf on bridges.
+
+Changes to IPTraf 2.1.1 and new features in IPTraf 2.2.0
+
+ Immediate flushing of disk buffers after a log file write to
+ better accomodate separate logfile parsing scripts.
+
+ Addition of a manual and automatic clearing of closed and idle
+ TCP entries in the IP Traffic Monitor
+
+ Added a TCP closed/idle persistence configuration option to
+ control the TCP closed/idle clearing interval.
+
+ Clarified TCP timeout logfile entries.
+
+ Saves the state of the interface flags at startup of a facility,
+ and restores them on exit, allowing interfaces previously set to
+ promiscuous mode to retain that state. Important on bridges.
+ Thanks to Dustin D. Trammell <dtrammell_at_cautech.com> and Holger Friese
+ <evildead_at_bs-pc5.et-inf.fho-emden.de> for the patch. However, I had
+ to modify it a little more than a bit and had to overhaul quite a
+ good deal of the rest of the software to better accomodate
+ multiple instances.
+
+ Promiscuous mode is set only when a facility is started, and
+ restored when it exits. Promiscuous mode is no longer forced at
+ menus. Restoration is not performed though if there is still
+ another facility running, but the interface state remains saved.
+
+ Fixed a minor bug in the LAN station monitor. The raw socket is
+ now closed when the facility exits. duh.
+
+ Fixed rare bug in the packet size distribution. The lock file didn't
+ get deleted if the raw socket open failed.
+
+ Changed the promiscuous mode option to "Force promiscuous".
+ Cosmetic.
+
+ Added PID's (a la syslog) to daemon log entries.
+
+ Minor cosmetic adjustments.
+
+Changes to IPTraf 2.1.0
+
+ Fixed bug in the packet size statistical breakdown. The facility
+ didn't filter packets based on interface name, thus causing
+ inaccurate counts on systems with multiple network interfaces.
+
+ Fixed a few minor cosmetic errors.
+
+ Corrected some typographical errors in the manual.
+
+ Added a FAQ (or the beginnings thereof).
+
+ Added a spec file for RPM generation. Thanks to Dag Wieers
+ <dag_at_life.be>. I'm not a really good RPM'er beyond RPM
+ installation and removal. :)
+
+Changes to IPTraf 2.0.2 and new features in IPTraf 2.1.0
+
+ Added non-IP to the display/logging filter selections
+
+ Added interface selection to the IP Traffic Monitor and LAN
+ Station Monitor (with an "All Interfaces" option).
+
+ Related to the above: now requires an interface name as an
+ argument to the -i and -l command-line parameters. 'all' may be
+ specified for monitoring all interfaces.
+
+ Added -B command-line parameter to fork program into the
+ background solely for logging purposes. Several people had
+ requested this.
+
+ Corrected TCP/UDP filter file placement error. Included cfconv
+ program to move files to the proper place.
+
+ Added program-wide Ctrl+L sequence to redraw the screen if
+ corrupted by outside factors (write, talk, syslog).
+
+ Added TCP/UDP filter editing facility.
+
+ Corrected several possible buffer overruns in TCP/UDP filter
+ module.
+
+ Corrected errors and reflected changes to manual and man pages.
+
+Changes to IPTraf 2.0.1
+
+ Fixed a rarely-occuring but nevertheless severe segmentation fault
+ bug when long hostnames are coupled with long service names.
+ Great thanks go to Ronald Wahl <rwahl_at_gmx.net> for the advice and
+ the help. Ron, I'm really gonna find the time to do the code the
+ Right Way :)
+
+Changes to IPTraf 2.0.0
+
+ Fixed minor non-IP byte count bug in detailed interface statistics.
+
+ Fixed minor cosmetic bug causing elapsed time indicator to appear
+ in the wrong line on screens not containing 25 lines. Thanks to
+ Uwe Storbeck <uwe_at_datacomm.ch> for the patch.
+
+New features/changes in IPTraf 2.0 from 1.4.2
+
+ Now uses the new PF_PACKET socket family as its packet capture
+ mechanism. Requires Linux 2.2.
+
+ Added target/source IP addresses in ARP packet
+ request/reply packet entries in the IP traffic monitor. Also
+ added target/source MAC addresses to RARP request/reply entries.
+
+ Reorganized menu structure, see the README file for details.
+
+ Moved packet counts by size to a facility of its own. Added
+ corresponding -z command-line option.
+
+ New incoming/outgoing packet and byte counts and activity rates in
+ the detailed interface statistics facility.
+
+ Corrected a bug in the FDDI packet parsing code (wrong link type).
+
+ Added a check for the IFF_UP flag when generating interface
+ lists, to omit inactive interfaces (but still in /proc/net/dev).
+ This covers the General Interface Statistics and all interface
+ selection lists.
+
+ Now uses the maximum number of columns on the screen. High thanks
+ to Michael "M." Brown <m2brown_at_waterloo.ca> for the patch. Saved
+ me a lot of tedious work. :)
+
+ Reformatted TCP screen to show only one hostname:port per line,
+ with connections indicated by the green "brackets". I think
+ that's clear enough.
+
+ Added ARP/RARP opcode and target addresses in the ARP/RARP
+ indicator lines.
+
+ Added vertical scrolling to the lower (non-TCP) window in the
+ IP traffic monitor to allow for long lines (ICMP, OSPF, some UDP).
+
+ Allowed for slightly longer host names in the lower IP traffic
+ monitor window.
+
+ Still increased the rvnamed cache size to 2048 entries.
+
+ Miscellaneous cosmetic changes.
+
+ Manual now includes screen shots and comes in HTML format only.
+
+Changes to IPTraf 1.4.1
+
+ Fixed SEGV condition when attempts are made to load a filter list
+ application or deletion with a zero-length filter list file, which
+ could be caused by deleting the last filter. Thanks to Daniel
+ Savard <daniel.savard_at_gespro.com> for the report.
+
+ Makefile comes with the -m486 option commented out
+
+Changes to IPTraf 1.4.0
+
+ Moved configuration status window to unobscure a long menu option.
+
+Changes to IPTraf 1.3.0 and new features in 1.4.0
+
+ Support for PLIP interfaces.
+
+ Support for other ISDN encapsulations (specifically raw IP and
+ Cisco HDLC) high thanks to Gerald Richter <richter_at_ecos.de> for
+ the information and testing.
+
+ Added -q parameter to suppress the 1.3.0 masquerading warning for
+ users who wish to automate the various facilities from their
+ inittab and similar non-interactive fashions. Incorporated into
+ the Debian version of 1.3.0 by Debian maintainer Frederic Peters
+ (<fpeters_at_debian.org>, carried over to general release 1.4.0.
+
+ Added an option to change activity indications between kbits/s and
+ kbytes/s. On a suggestion by Paul G. Fitzgerald
+ <pgfitzgerald_at_buckman.com>.
+
+ Incorporated more flexible compile-time control of directories for
+ configuration, log, and other files. Thanks to Stefan Luethje
+ <luethje_at_sl-gw.lake.de> for the patch.
+
+ Corrected minor flaws in the default screen update delay code
+ (visually insignificant), that led to occasional skips of the
+ delays. (Call it nitpicking if you will. :))
+
+ Moved signal() calls to after terminal checks in iptraf.c,
+ allowing standard behavior of signals when error/warning messages
+ may still be sent to stderr. Allows the user to break out of it
+ with Ctrl+C at the terminal warning if so desired.
+
+ Reformatted IP traffic monitor log entries on Gerald Richter's
+ <richter_at_ecos.de> suggestions for easier processing with Perl
+ scripts.
+
+ Included logfile rotation with the USR1 signal. Again on Gerald
+ Richter's <richter_at_ecos.de> suggestion.
+
+ Moved first-instance tag sequence to after the initscr() call.
+
+ Indicated IP fragments with no additional information in the lower
+ traffic monitor window. Datagram size, addresses, and interface
+ are still indicated.
+
+ Changed Non-IP count in IP traffic monitor to byte count
+ (including data-link header lengths) from packet counts.
+ Consistency purposes.
+
+ Added some extra information for certain non-IP packets. These
+ may eventually grow, but not in too much detail, since this is an
+ IP-oriented utility. Thanks to David Harbaugh
+ <dlh_at_linux.cayuga-cc.edu> for the patch.
+
+ Removed bind() operation on raw socket to address a condition in
+ which the detailed interface statistics and TCP/UDP statistics
+ stop counting if an interface goes down then up again. This will
+ be studied further. Symptom report sent in by Roeland Jansen
+ <bengel_at_xs4all.nl>.
+
+ Changed Ethernet/FDDI/PLIP description file formats from binary to
+ plain text, allowing database appends. Other files (configuration
+ and filters) are still binary. On a suggestion by David Harbaugh
+ <dlh_at_linux.cayuga-cc.edu>.
+
+ Copied IP and upper-layer headers and some data from Ethernet,
+ PLIP, FDDI, and loopback frames into an aligned buffer. Avoids
+ SIGBUS on picky systems (like SPARCs) and general alignment
+ problems. I don't know yet which is worse, the overhead of
+ a 96-byte transfer or the performance hit with misaligned reads.
+ Thanks to Jonas Majauskas <jmajau_at_soften.ktu.lt> for reports and
+ tests.
+
+ Replaced __-type references with u_int-type references.
+
+ Increased cache array size in rvnamed to 1024 entries from the
+ previous 512, to better handle combinations of busy networks and
+ slow DNS servers.
+
+ Cleared up a few instructions in the Makefile, thanks to Arjan
+ Opmeer <a.d.opmeer_at_student.utwente.nl>
+
+New features in IPTraf 1.3.0 and changes to IPTraf 1.2.0
+
+ Experimental FDDI support. High thanks to Paonia Ezrine
+ <paonia_at_massart.edu> for the initial tests on the FDDI code. More
+ feedback is requested on the FDDI functionality. Bugs may still
+ be present.
+
+ Reestablished ippp interfaces (synchronous PPP over ISDN) after
+ reports that the ISDN problem was fixed with Linux 2.0.34.
+
+ Fixed fragmentation oversight in TCP/UDP service monitor.
+
+ Applied the bind() system call to the raw socket to have the
+ kernel filter out packets from interfaces we're not interested in.
+ Makes for better capture times on multiple-interfaced machines.
+ However, a strncmp() is still performed on the returned interface
+ name to counter the race condition between the socket() and bind()
+ calls.
+
+ Fixed interface statistics print routines to print unsigned
+ rather than signed numbers.
+
+ Added additional option to adjust screen updates. Useful for
+ IPTraf sessions run on remote terminals (thanks to Lutz Vieweg
+ <lkv_at_isg.de> for the suggestion and Dean Gaudet
+ <dgaudet_at_arctic.org> for the base patch. I modified it a bit,
+ Dean.)
+
+ Discovered terrible performance penalty due to screen refresh with
+ heavily loaded LAN segments. Therefore, with the new screen
+ update interval option set to 0, all facilities have a 50 ms delay
+ between refreshes (exception: the LAN station monitor has a delay
+ of 100 ms). This is still visually fast (although updates
+ look kinda slower), but this gives more time to packet capture,
+ therefore increasing accuracy and capture performance. Thanks to
+ everyone who responded to my request for advice on this matter and
+ to Ronald Wahl <rwahl_at_gmx.net> for giving me the symptom report.
+
+ Modified IP traffic monitor to mark TCP connection entries for reuse
+ once one side is fully closed and acknowledged ("CLOSED" on the
+ screen) and the other closed but even if not acknowledged ("DONE"
+ on the screen. This is because many times, the last ACK gets lost.
+
+ Included an additional parameter used together with the other
+ command-line arguments to specify an amount of time for which the
+ selected facility would run before automatically terminating (on a
+ suggestion by Linux HOWTO coordinator Tim Bynum
+ <tjbynum_at_wallybox.cei.net)>.
+
+ Supplemented the main data structure for the IP traffic monitor
+ with an open hash table for increased search efficiency,
+ especially after the facility has been running for quite some
+ time (the other facilities, which don't grow as much still use
+ linearly-searched linked lists. I'll probably hash them depending
+ on feedback.)
+
+ Fixed rare bugs in various facilities that caused IPTraf to
+ attempt to proceed even in the event of a raw socket open failure.
+
+ Fixed SEGV condition when IPTraf is invoked with a command-line
+ parameter that cannot be parsed with getopt().
+
+ Added labels to LAN address description selection box.
+
+ Fixed unsightly LAN address description dialog scrolling.
+
+ Added a separator feature to the menurt.c module, allowing
+ separation lines within menus.
+
+ Added separator lines between related groups of menu items in both
+ main and configuration menus.
+
+ Changed the Options main menu item to Configure.
+
+ Added the space bar and the '-' key as "unofficial" alternates to
+ the PgUp and PgDn keys (it's not in the manual).
+
+ Transferred Ethernet description facility option to the Configure
+ submenu, and added a related facility for FDDI addresses.
+
+ Removed Ethernet-specific references where FDDI and (potentially)
+ other LAN technologies also fit. We'll just use "LAN" as a
+ general term.
+
+ Adjusted detailed statistics screen to automatically generate the
+ appropriate packet size distribution brackets based on interface
+ MTU. This means the brackets may no longer end on numbers
+ divisible by 10, but rather on boundaries based on the MTU divided
+ by 16 (the number of brackets). But at least 1500 is not
+ hardcoded anymore as the maximum.
+
+ Related to the immediately preceeding change: packet size
+ distribution updates are done one at a time now, no longer as a
+ whole bunch. In other words, as a frame arrives, only the
+ appropriate bracket is updated.
+
+ Also related to previous two: changed basis for packet size
+ distribution to the Ethernet frame length from the IP datagram
+ length (which really doesn't matter except for a few frames).
+
+ Fixed bug which causes the existing log interval to multiply by 60
+ when the dialog is aborted (instead of retaining the current
+ setting). Thanks to Chris Higgins <chiggins_at_pobox.com> for the
+ bug report and the patch. (I had to modify it a bit to fit in
+ with the screen update interval patch sent in by Dean Gaudet.)
+
+ Potentially large counts have been changed to type "unsigned long
+ long" to significantly increase running time on heavily loaded
+ networks, plus automatic switching of denominations (from exact
+ counts to K(ilo) to M(ega) to G(iga) to T(era)) to prevent screen
+ disruption (on a suggestion by Lutz Vieweg <lkv_at_isg.de>).
+
+ Separated log file into different logs for each facility.
+
+ Moved log files to /var/log/iptraf to avoid mixing them with the
+ mess in the /var/local/iptraf directory. At least that way,
+ we humans don't have to look in /var/local/iptraf anymore.
+
+ Relaxed multiple-instance restriction from a
+ no-multiple-instances-of-IPTraf requirement to a
+ no-multiple-instance-of-the-same-facility. In other words,
+ several copies of IPTraf can run, but only one instance of each
+ facility can run at any one time. The -f parameter removes the
+ tags, overriding the restrictions on that IPTraf instance. This
+ modification was done to address needs indicated by Chris Panayis
+ <chris_at_freedom2surf.net>).
+
+ Added a startup warning box if IPTraf detects IP Masquerading
+ enabled on the computer. IPTraf will continue to work, but its
+ results may be quite confusing. The detection is done by
+ opening /proc/net/ip_masquerade.
+
+ Modified additional port facility to accept ranges of ports rather
+ than several single port numbers (on a suggestion by Lutz Vieweg
+ <lkv_at_isg.de>)
+
+ Reduced minimum number of lines from 25 to 24 for better VT100
+ terminal compliance.
+
+ Miscellaneous cosmetic retouches. (I consider user interface an
+ important factor too, ya know! :)
+
+ Distribution binary now comes statically linked with ncurses 4.2.
+ You may recompile to suit your system.
+
+ Included manual pages derived from the Debian GNU/Linux 2.0
+ distribution. Man pages written by Frederic Peters
+ <fpeters_at_debian.org> who is now maintaining the Debian IPTraf
+ package.
+
+ Reversed version order (newest first) in the CHANGES file.
+
+New features in IPTraf 1.2.0 and changes to IPTraf 1.1.0
+
+ Increased buffer size in ifstats.c for /proc/net/dev lines to 161
+ to better accomodate the longer lines in the new 2.1.x kernels
+ (which will be carried over to the new stable kernel series).
+ Based on bug reports by Dop Ganger <DopG_at_sprint.ca> and Christoph
+ Lameter <christoph_at_lameter.com> et al.
+
+ Fixed rarely occuring high CPU utilization bug occuring whenever
+ a terminal connection is lost, resulting in a SIGHUP which is
+ ignored. (This is an example of a software author's temporary
+ insanity. I mean, what sane programmer would set SIGHUP to
+ SIG_IGN for a terminal-based program huh? Thought so :) Thanks
+ to Dop Ganger <DopG_at_sprint.ca> for the symptom report.
+
+ Refined Ethernet station monitor rate updates and scrolling code.
+
+ Fixed autosave bug for non-TCP filters (this was working before
+ 1.1.0. All of a sudden, the function call disappeared
+ mysteriously. Must have been sleepy that time :)
+
+ Fixed bug in UDP filter default settings.
+
+ Added option to display TCP and UDP ports in either name form or
+ numeric form (on a suggestion by Felix von Leitner
+ <leitner_at_math.fu-berlin.de> and others).
+
+ Added facility to describe Ethernet addresses for the Ethernet
+ station monitor (to address needs as presented by Erlend Middtun
+ <erlendbm_at_funcom.com> via James Ullman <james_at_irc.ingok.hitos.no>)
+
+ Added an additional field to the TCP/UDP filter dialogs to allow
+ the user to "exclude" certain addresses from the display allowing
+ all others. Details on the new behavior are in the manual (on a
+ suggestion by Sean Hough <seh_at_javanet.com>)
+
+ Relaxed screen management code to better adjust to the number of
+ lines on the screen. As of this release, columns are still based
+ on a maximum number of 80 though. Also under study is a
+ SIGWINCH handler, but this will have to come later (on comments and
+ suggestions by a *lot* of users...thanks guys :-) ).
+
+ Fixed a subtle bug in the rvnamed interface IPC code, resulting in
+ an accurate transfer of data but causing recvfrom() to return an
+ EINVAL at unpredictable intervals. Bug was an uninitialized address
+ structure length parameter. Code in both iptraf and rvnamed was
+ fixed.
+
+ Eliminated unsupported interfaces from interface selection lists.
+
+ Included enforced restriction disallowng multiple instances of
+ IPTraf and an overriding command-line parameter. (This may
+ just be temporary, in lieu of a more elegant solution).
+
+ Included autosave for TCP and UDP filters. Filters now survive
+ IPTraf exits and restarts without requiring manual reapplication
+ (on a suggestion by Chad Clark <cclark_at_comstar.net>).
+
+ Included upgrade program and makefile rule to convert IPTraf 1.1.0
+ configuration and filter files to 1.2.0 format.
+
+ Clarified TCP/UDP and non-TCP/UDP filter error messages.
+
+ Color-coded the TCP and UDP protocol/port indicators in the
+ TCP/UDP service monitor for better identification.
+
+ Revised IP traffic monitor to query rvnamed only once per
+ invocation of the facility. Less overhead.
+
+ Revised IP traffic monitor to open and close the rvnamed
+ communication socket only once per invocation of the facility.
+ Less overhead.
+
+ Added a 2-second delay after the rvnamed invocation to give
+ the daemon more than enough time to open its sockets.
+
+ Fixed SEGV condition which occurs when an attempt is made to
+ destroy an interface list never loaded (which could only occur
+ if the /proc system is unreadable, something which shouldn't
+ happen on any decent Linux system).
+
+ Moved filter list load routine to fltmgr.c, for better linking with
+ the cfconv module.
+
+ Makefile now installs rvnamed together with the iptraf executable
+ in /usr/local/bin by default.
+
+ Added table of contents (hyperlinked in the HTML version) to the
+ manual.
+
+ Cleaned up the Makefile.
+
+New features in IPTraf 1.1.0 and changes to IPTraf 1.0.3
+
+ Added command-line options for direct facility access from the
+ shell, and an appropriate help screen for IPTraf invocation (on a
+ suggestion by BJ Goodwin <latency_at_radiolink.net>).
+
+ Added separate DNS reverse name lookup program (rvnamed) for
+ quicker response time on reverse DNS lookups. Subsequently
+ modified the revname function to use the new functionality.
+ This also required additions of address resolution state fields
+ to struct tcptableent in tcptable.h.
+
+ Added checkrvnamed() and killrvnamed() to revname.c, used by
+ itrafmon.c to query and stop the rvnamed daemon.
+
+ Added scrolling capability to the general interface statistics.
+ Interface list will now grow as packets from newly created
+ interfaces are received (e.g. PPP interfaces). This now makes
+ IPTraf better suited to monitor Linux machines configured as
+ access servers.
+
+ Interface selection lists can now be scrolled.
+
+ Increased maximum number of entries in for the non-TCP window
+ in the IP traffic monitor from 256 to 512.
+
+ Fixed SEGV condition in itrafmon.c that happens whenever the
+ Down cursor key is pressed with the lower window active, but
+ not yet full.
+
+ Added elapsed time indicators to each facility, showing the
+ hours and minutes that have passed since the start of the
+ monitor (on a suggestion by James Ullman
+ <james_at_irc.Ingok.Hitos.No>)
+
+ Changed ncurses include file references from <ncurses.h>
+ to <curses.h>
+
+ Cleaned up preprocessor code for glibc2 support. Thanks for
+ help and suggestions from John Labovitz <johnl_at_meer.net>. Thanks
+ also for a test account on debs.fuller.edu opened by Christoph
+ Lameter <christoph_at_lameter.com>.
+
+ Fixed SEGV condition which may occur when trying to close the
+ log file which may never have opened (thanks to John Labovitz
+ <johnl_at_meer.net> for the patch).
+
+ Adjusted cosmetic code to better indicate the closed status in
+ the TCP monitor.
+
+ TCP and UDP filters now accept host names in in place of IP
+ addresses. Host names will be resolved and can still be used
+ with wildcard masks (may be useful for names that resolve to
+ several IP addresses)
+
+ Distribution now includes an HTML-formatted manual.
+
+Changes to IPTraf 1.0.2
+
+ Fixed SEGV condition when scrolling commands are applied to
+ an empty Ethernet station monitor
+
+ Distribution executable now comes compiled with -m486 by default.
+ Binary will still execute on a 386, but a 486 or higher is still
+ preferred.
+
+Changes to IPTraf 1.0.1
+
+ Fixed conflicting hotkey for non-TCP filter menu items RARP and
+ IGRP (the "R" key). Changed the shortcut key for RARP to "P".
+
+ Modified layer-2 header stripping code to cleanly ignore packets
+ from unrecognized interfaces (see README).
+
+ Fixed "duplicate port" misbehavior for the "Additional port"
+ dialog's Cancel command
+
+ Added error-checking for the port list file open sequence.
+
+ Added PgUp/PgDn capability to the facilities that can be scrolled
+ (IP traffic monitor, TCP/UDP services, and Ethernet station
+ monitor).
+
+ Cleaned up scrolling code a bit.
+
+ Fixed bug in the non-TCP logging facility that caused extraneous
+ log entries whenever the window is scrolled.
+
+ Sent non-fancy messages to standard error rather than standard
+ output.
+
+ Changed a few messages
+
+Changes to IPTraf 1.0.0
+
+ Fixed X/Ctrl-X keystroke bug in the General Interface Statistics
+ module (thanks to BJ Goodwin <latency_at_radiolink.net>). This was
+ kinda an emergency, so I fixed this and released 1.0.1
+ immediately.
+
diff --git a/Documentation/iptraf-configmenu.png b/Documentation/iptraf-configmenu.png
new file mode 100644
index 0000000..cf4a9ad
--- /dev/null
+++ b/Documentation/iptraf-configmenu.png
Binary files differ
diff --git a/Documentation/iptraf-dstat1.png b/Documentation/iptraf-dstat1.png
new file mode 100644
index 0000000..d56c5d5
--- /dev/null
+++ b/Documentation/iptraf-dstat1.png
Binary files differ
diff --git a/Documentation/iptraf-editfilter.png b/Documentation/iptraf-editfilter.png
new file mode 100644
index 0000000..3db0bf7
--- /dev/null
+++ b/Documentation/iptraf-editfilter.png
Binary files differ
diff --git a/Documentation/iptraf-filtermenu.png b/Documentation/iptraf-filtermenu.png
new file mode 100644
index 0000000..1298e3e
--- /dev/null
+++ b/Documentation/iptraf-filtermenu.png
Binary files differ
diff --git a/Documentation/iptraf-gstat1.png b/Documentation/iptraf-gstat1.png
new file mode 100644
index 0000000..b333cd1
--- /dev/null
+++ b/Documentation/iptraf-gstat1.png
Binary files differ
diff --git a/Documentation/iptraf-hw.png b/Documentation/iptraf-hw.png
new file mode 100644
index 0000000..f874f97
--- /dev/null
+++ b/Documentation/iptraf-hw.png
Binary files differ
diff --git a/Documentation/iptraf-hwsort.png b/Documentation/iptraf-hwsort.png
new file mode 100644
index 0000000..11497f3
--- /dev/null
+++ b/Documentation/iptraf-hwsort.png
Binary files differ
diff --git a/Documentation/iptraf-ipfltdlg.png b/Documentation/iptraf-ipfltdlg.png
new file mode 100644
index 0000000..e8de177
--- /dev/null
+++ b/Documentation/iptraf-ipfltdlg.png
Binary files differ
diff --git a/Documentation/iptraf-ipfltlist.png b/Documentation/iptraf-ipfltlist.png
new file mode 100644
index 0000000..1595311
--- /dev/null
+++ b/Documentation/iptraf-ipfltlist.png
Binary files differ
diff --git a/Documentation/iptraf-ipfltmenu.png b/Documentation/iptraf-ipfltmenu.png
new file mode 100644
index 0000000..db117b4
--- /dev/null
+++ b/Documentation/iptraf-ipfltmenu.png
Binary files differ
diff --git a/Documentation/iptraf-ipfltnamedlg.png b/Documentation/iptraf-ipfltnamedlg.png
new file mode 100644
index 0000000..2354174
--- /dev/null
+++ b/Documentation/iptraf-ipfltnamedlg.png
Binary files differ
diff --git a/Documentation/iptraf-iptm1.png b/Documentation/iptraf-iptm1.png
new file mode 100644
index 0000000..d66ce51
--- /dev/null
+++ b/Documentation/iptraf-iptm1.png
Binary files differ
diff --git a/Documentation/iptraf-iptmsort.png b/Documentation/iptraf-iptmsort.png
new file mode 100644
index 0000000..8158d21
--- /dev/null
+++ b/Documentation/iptraf-iptmsort.png
Binary files differ
diff --git a/Documentation/iptraf-logprompt.png b/Documentation/iptraf-logprompt.png
new file mode 100644
index 0000000..e6927d8
--- /dev/null
+++ b/Documentation/iptraf-logprompt.png
Binary files differ
diff --git a/Documentation/iptraf-mmenu.png b/Documentation/iptraf-mmenu.png
new file mode 100644
index 0000000..f7212a3
--- /dev/null
+++ b/Documentation/iptraf-mmenu.png
Binary files differ
diff --git a/Documentation/iptraf-othipfltdefine.png b/Documentation/iptraf-othipfltdefine.png
new file mode 100644
index 0000000..671913a
--- /dev/null
+++ b/Documentation/iptraf-othipfltdefine.png
Binary files differ
diff --git a/Documentation/iptraf-othipfltdlg.png b/Documentation/iptraf-othipfltdlg.png
new file mode 100644
index 0000000..5c72886
--- /dev/null
+++ b/Documentation/iptraf-othipfltdlg.png
Binary files differ
diff --git a/Documentation/iptraf-othipfltselect.png b/Documentation/iptraf-othipfltselect.png
new file mode 100644
index 0000000..1c21a0e
--- /dev/null
+++ b/Documentation/iptraf-othipfltselect.png
Binary files differ
diff --git a/Documentation/iptraf-pktsize.png b/Documentation/iptraf-pktsize.png
new file mode 100644
index 0000000..10902a2
--- /dev/null
+++ b/Documentation/iptraf-pktsize.png
Binary files differ
diff --git a/Documentation/iptraf-tcpflt-dlg2.png b/Documentation/iptraf-tcpflt-dlg2.png
new file mode 100644
index 0000000..b63928c
--- /dev/null
+++ b/Documentation/iptraf-tcpflt-dlg2.png
Binary files differ
diff --git a/Documentation/iptraf-tcpfltmenu.png b/Documentation/iptraf-tcpfltmenu.png
new file mode 100644
index 0000000..d7a1884
--- /dev/null
+++ b/Documentation/iptraf-tcpfltmenu.png
Binary files differ
diff --git a/Documentation/iptraf-tcpudp.png b/Documentation/iptraf-tcpudp.png
new file mode 100644
index 0000000..a68b2d6
--- /dev/null
+++ b/Documentation/iptraf-tcpudp.png
Binary files differ
diff --git a/Documentation/iptraf-tcpudpsort.png b/Documentation/iptraf-tcpudpsort.png
new file mode 100644
index 0000000..a7e7950
--- /dev/null
+++ b/Documentation/iptraf-tcpudpsort.png
Binary files differ
diff --git a/Documentation/iptraf-timermenu.png b/Documentation/iptraf-timermenu.png
new file mode 100644
index 0000000..7d1b6c4
--- /dev/null
+++ b/Documentation/iptraf-timermenu.png
Binary files differ
diff --git a/Documentation/iptraf.xpm b/Documentation/iptraf.xpm
new file mode 100644
index 0000000..96aec98
--- /dev/null
+++ b/Documentation/iptraf.xpm
@@ -0,0 +1,10 @@
+/* XPM */
+static char * iptraf_xpm[] = {
+"5 5 2 1",
+" c None",
+". c #15FF00",
+" ... ",
+".....",
+".....",
+".....",
+" ... "};
diff --git a/Documentation/manual.sgml.in b/Documentation/manual.sgml.in
new file mode 100644
index 0000000..3fec617
--- /dev/null
+++ b/Documentation/manual.sgml.in
@@ -0,0 +1,4500 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
+]>
+<book id="manual">
+<bookinfo>
+<title>IPTraf-ng User's Manual</title>
+
+<releaseinfo>
+Version @@version@@
+</releaseinfo>
+
+<copyright>
+<year>1997</year>
+<year>2003</year>
+<holder>Gerard Paul Java</holder>
+</copyright>
+<copyright>
+<year>2016</year>
+<holder>Phil Cameron</holder>
+</copyright>
+
+<legalnotice id="legalinfo">
+<para>
+This manual is released under the terms of the GNU
+Free Documentation License of March, 2000 as published by the
+Free Software Foundation, reproduced in this manual as Appendix B.
+</para>
+<para>
+IPTraf-ng is open-source software released under the terms of the GNU General
+Public License version 2 or any later version as published by the Free
+Software Foundation, reproduced in the LICENSE file in the distribution's
+top-level directory.
+</para>
+<para>
+The accomanying software and the information contained in this
+document are provided "AS IS" without warranty of any kind, express or
+implied, including, without limitation, the implied warranties
+of mercantability or fitness for any particular purpose.
+</para>
+<para>
+In no event shall the author be liable for any indirect,
+special, consequential, or incidental damages arising from the use of this
+manual or the accompanying software even if the author has been advised of
+the possibility of such damages.
+</para>
+<para>
+Linux is a registered trademark of Linus Torvalds. Pentium is a
+registered trademark of Intel Corporation. All other trademarks are
+property of their respective owners.
+</para>
+<para>
+Some structure declarations were based on code copyrighted by the Regents
+of the University of California.
+</para>
+</legalnotice>
+</bookinfo>
+<toc></toc>
+<lot></lot>
+<preface id="preface">
+<title>About This Document</title>
+<para>
+This document contains the instructions on how to use the IPTraf-ng network
+monitoring software version @@major@@. This manual details the
+different statistical facilities, the user
+interface, and the important features of the software.
+</para>
+
+<sect1 id="addinfo">
+<title>For Additional Information</title>
+<para>
+See the included README file for summarized and late-breaking information.
+The CHANGES file contains a record of the changes made to the software
+since 1.0.0. README.resolving contains information on the reverse resolution
+function. See the other README files for support and development
+information.
+</para>
+</sect1>
+
+<sect1 id="conventions">
+<title>Document Conventions</title>
+<para>
+ The following symbols and typefaces are used throughout this manual:
+</para>
+
+<variablelist>
+<varlistentry>
+<term><computeroutput>[ ]</computeroutput></term>
+<listitem>
+<para>
+items in brackets are optional. Brackets also denote items that may or may
+not be displayed onscreen depending on settings or conditions.
+</para></listitem></varlistentry>
+
+<varlistentry>
+<term><computeroutput>{ }</computeroutput></term>
+<listitem><para>
+ curly braces enclose items you choose from
+</para></listitem></varlistentry>
+
+<varlistentry>
+<term><computeroutput>|</computeroutput></term>
+<listitem><para>
+ the vertical bar separates choices in curly braces
+</para></listitem></varlistentry>
+
+<varlistentry>
+<term><computeroutput>normal monospace</computeroutput></term>
+<listitem><para>
+ normal monospace text in syntax specifications should be typed in exactly as presented. Because UNIX and variants are case-sensitive, case must be preserved. Monospace is also used in presenting items that appear on the screen.
+</para></listitem></varlistentry>
+
+<varlistentry>
+<term><computeroutput><replaceable>
+ monospace italics
+</replaceable></computeroutput></term>
+<listitem><para>
+
+ italics in syntax specifications indicate items that are to be
+ replaced with an actual item (e.g.
+ <replaceable>interface</replaceable> should be replaced with an
+ actual interface name, like <computeroutput>eth0</computeroutput>).
+
+</para></listitem></varlistentry>
+</variablelist>
+
+<para>
+Additional information appears distinctively set apart from the main text.
+This information includes Notes, Tips, or Technical Notes.
+</para>
+
+<para>
+<emphasis>Notes</emphasis> are additional pieces of information that may be useful or may
+ clarify the preceeding paragraphs of the manual.
+</para>
+<para>
+ <emphasis>Tips</emphasis> provide shortcuts, clarify tasks that may not
+ be immediately obvious, or provide references to additional sources of information.
+</para>
+<para>
+<emphasis>Technical notes</emphasis> are explanations of a
+ more technical nature and may be of more use to programmers and advanced
+ users.
+</para>
+</sect1>
+</preface>
+
+<chapter id="gettingstarted"><title>
+Getting Started
+</title>
+<sect1>
+<title>About IPTraf-ng</title>
+<para>
+IPTraf-ng is a network monitoring utility and traffic analyzer for IP networks. It
+intercepts packets and returns data about captured the network traffic
+in various statistical facilities.
+</para>
+<para>
+IPTraf-ng includes these major features:
+</para>
+<itemizedlist spacing="compact" mark="bullet">
+<listitem><para>An IP traffic monitor that shows TCP
+connection information (hosts, packet/byte counts, flags,
+window sizes), and color-coded information about other
+IP packets</para></listitem>
+<listitem><para>Statistics (counts and load rates) for network interfaces
+in general and detailed views</para></listitem>
+<listitem><para>Statistics per TCP/UDP port</para></listitem>
+<listitem><para>Statistical breakdown according to packet sizes</para></listitem>
+<listitem><para>A LAN host monitor that returns counts and loads per
+detected MAC address</para></listitem>
+<listitem><para>A powerful filtering system for users to view
+only interesting traffic</para></listitem>
+<listitem><para>Logging</para></listitem>
+<listitem><para>An asynchronous DNS resolver for the
+IP traffic monitor</para></listitem>
+<listitem><para>A text-based, full-color, menu-driven user interface
+suitable for use on all Linux systems with terminals, especially Linux
+consoles and color xterms</para></listitem>
+<listitem><para>Easy configuration</para></listitem>
+<listitem><para>Fully software-based. No additional
+hardware required</para></listitem>
+</itemizedlist>
+<para>
+ Basic knowledge of the important TCP/IP protocols (IP, TCP, UDP, ICMP,
+ etc.) is necessary for you to best understand the information generated
+ by the program.
+</para>
+
+</sect1>
+<sect1 id="installation">
+<title>
+ Installation
+</title>
+<sect2>
+<title>System Requirements</title>
+<para>
+IPTraf-ng requires:
+</para>
+
+<sect3>
+<title>Hardware Requirements</title>
+
+<itemizedlist spacing="compact" mark="bullet">
+<listitem><para>
+ 16 megabytes of physical RAM (more recommended, at least 64 MB for very busy networks)
+</para></listitem>
+<listitem><para>
+ 2 megabytes of free disk space for installation (more will be needed if you log high amounts of traffic over time)
+</para></listitem>
+<listitem><para>
+ Pentium-class processor or higher (Pentium-II 200 MHz or higher recommended) or equivalent.
+</para></listitem>
+<listitem><para>
+ One or more of the supported network interfaces.
+</para></listitem>
+</itemizedlist>
+</sect3>
+<sect3>
+ <title>Operating System Requirements</title>
+
+<itemizedlist spacing="compact" mark="bullet">
+<listitem><para>
+ Linux kernel 2.2.0 or higher
+</para></listitem>
+<listitem><para>
+ GNU C Library 2.1 or later
+</para></listitem>
+<listitem><para>
+
+ ncurses 4.2 or later with the complete terminfo database in
+ <filename>/usr/share/terminfo</filename>. Support for
+ <computeroutput>linux</computeroutput>, <computeroutput>vt100</computeroutput>,
+ <computeroutput>xterm</computeroutput>,
+ <computeroutput>xterm-color</computeroutput> recommended.
+
+</para></listitem>
+</itemizedlist>
+</sect3>
+<sect3>
+ <title>Compilation Requirements</title>
+<para>
+The following components are required when compiling IPTraf-ng from the
+source code.
+</para>
+<itemizedlist spacing="compact" mark="bullet">
+<listitem><para>
+ gcc 2.7.2.3 or later
+</para></listitem>
+<listitem><para>
+
+ GNU C (glibc) development library 2.1 or later
+</para></listitem>
+<listitem><para>
+
+ ncurses development libraries 4.2 or later
+</para>
+</listitem>
+<listitem><para>
+
+ git
+</para>
+</listitem>
+</itemizedlist>
+</sect3>
+</sect2>
+
+<sect2>
+<title>Availability</title>
+<para>
+ IPTraf-ng is available in binary form
+ from many Linux Distributions including
+ Red Hat RHEL, Centos, Fedora, and Ubuntu.
+</para>
+<para>
+ IPTraf-ng git source repository can be cloned from from:
+</para>
+<para>
+<ulink url="https://git.fedorahosted.org/git/iptraf-ng.git">
+</ulink>
+</para>
+</sect2>
+
+</sect1>
+<sect1 id="startstop">
+<title>Starting and Stopping IPTraf-ng</title>
+<para>
+ After installation, you can start the program, as root, by simply entering
+</para>
+<synopsis>
+iptraf-ng
+</synopsis>
+<para>
+ Entering the IPTraf-ng command without any command-line parameters brings
+ up the program's main menu. From there, you can select the
+ facilities you want.
+</para>
+<para>
+ IPTraf-ng determines and makes use of the maximum number
+ of lines and columns on the terminal.
+</para>
+
+<note>
+
+ <title>Note</title><para>
+ IPTraf-ng does not have a SIGWINCH handler; it does not
+ adjust itself when an xterm or some other X terminal is resized.
+</para></note>
+
+
+<note>
+ <title>Technical note</title>
+ <para>
+
+ IPTraf-ng needs to refer to the terminfo database
+in <filename>/usr/share/terminfo</filename>.
+ If the supplied executable program fails with <computeroutput>Error
+opening
+ terminal</computeroutput>, your terminfo database may be located somewhere else. You can
+ control the terminfo search path
+by using the <envar>TERMINFO</envar> environment
+ variable. For example, if you're using the <command>sh</command>
+or <command>bash</command> shell, and
+ your terminfo database is in <filename>/usr/lib/terminfo</filename>
+ (typical for Slackware distributions), you can use the commands:
+
+</para>
+<synopsis>
+TERMINFO=/usr/lib/terminfo
+export TERMINFO
+</synopsis>
+<para>
+ You can place these commands in your <filename>~/.profile</filename> or the
+ systemwide <filename>/etc/profile</filename> startup files.
+</para>
+<para>
+ You can also create a symbolic
+ link named <filename>/usr/share/terminfo</filename> to let
+ it point to your existing terminfo (assuming again your terminfo is in
+ <filename>/usr/lib/terminfo</filename>):
+</para>
+<synopsis>
+ln -s /usr/lib/terminfo /usr/share/terminfo
+</synopsis>
+<para>
+ Or you can recompile your program to use your existing ncurses library
+ installation. If you do this, make sure you have ncurses 4.2 or later.
+</para>
+</note>
+</sect1>
+<sect1 id="cmdline">
+<title>Command-line Options</title>
+<para>
+ IPTraf-ng has a few optional command-line parameters. As with most UNIX
+ commands, IPTraf-ng command-line parameters are
+case-sensitive (<computeroutput>-l</computeroutput>
+ is NOT the same as <computeroutput>-L</computeroutput>).
+</para>
+<para>
+ The following command-line parameters can be supplied
+ to the <command>iptraf-ng</command> command:
+</para>
+<variablelist>
+<varlistentry>
+<term><computeroutput>-i <replaceable>iface</replaceable></computeroutput></term>
+<listitem><para>
+ causes the IP traffic monitor to start immediately on the specified interface.
+ If -i all is specified, all interfaces are monitored.
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><computeroutput>-g</computeroutput></term>
+<listitem><para>
+ starts the general interface statistics
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><computeroutput>-d <replaceable>iface</replaceable></computeroutput></term>
+<listitem><para>
+ shows detailed statistics for the specified interface
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><computeroutput>-s <replaceable>iface</replaceable></computeroutput></term>
+<listitem><para>
+ starts the TCP/UDP traffic monitor for the specified interface
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><computeroutput>-z <replaceable>iface</replaceable></computeroutput></term>
+<listitem><para>
+ starts the packet size breakdown for the specified interface
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><computeroutput>-l <replaceable>iface</replaceable></computeroutput></term>
+<listitem><para>
+ starts the LAN station monitor on the specified interface. If
+<computeroutput>-l all</computeroutput> is specified, all LAN interfaces are monitored.
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><computeroutput>-t <replaceable>timeout</replaceable></computeroutput></term>
+<listitem><para>
+ The <computeroutput>-t</computeroutput> parameter, when used with one
+ of the other parameters that specify a facility to start, tells
+ IPTraf-ng to run the indicated facility for only timeout
+ minutes, after which the facility
+ exits. The <computeroutput>-t</computeroutput> parameter is ignored in menu
+ mode.
+</para>
+<para>
+ If this parameter is not specified, the facility runs until the
+ exit keystroke is pressed.
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><computeroutput>-B</computeroutput></term>
+<listitem><para>
+ Redirects all terminal output to the "bit bucket"
+<filename>/dev/null</filename>, closes standard input, and
+places the program in the background. This parameter can be used only with
+one of the <computeroutput>-i</computeroutput>, <computeroutput>-g</computeroutput>,
+<computeroutput>-d</computeroutput>,
+<computeroutput>-s</computeroutput>, <computeroutput>-z</computeroutput>, or
+<computeroutput>-l</computeroutput> parameters. See
+<link linkend="backop">Background Operation</link> in Chapter 9. <computeroutput>-B</computeroutput> is ignored in menu
+mode.
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><computeroutput>-L <replaceable>filename</replaceable></computeroutput></term>
+<listitem><para>
+ Allows you to specify an alternate log file name when the
+ any facility is directly started from the command line, whether in foreground or
+ background mode. If specified in foreground mode, the log filename prompt is
+ bypassed, even when logging is turned on in the <emphasis>Configure...</emphasis>
+ menu. If this parameter is omitted in background mode, the default log filename
+ is used.
+</para>
+<para>
+ This parameter always turns on logging.
+</para>
+<para>
+ If an absolute path is not specified, the log
+ file will be created in the default log file directory
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><computeroutput>-f</computeroutput></term>
+<listitem><para>
+ Forces IPTraf-ng to clear all lock files and reset all instance counters
+ to zero before running any facilities. IPTraf-ng will then think
+ it's the first instance of itself.
+</para>
+<para>
+ The <computeroutput>-f</computeroutput> parameter overrides the
+ existing locks and counters imposed by the IPTraf-ng process and
+ by the various facilities, causing this instance to think it is the
+ first and that there are no other facilities running. Use
+ this parameter with great caution. A common use for this parameter is
+ to recover from abrupt or abnormal terminations which may leave stale
+ locks and counters still lying around.
+</para>
+<para>
+ The <computeroutput>-f</computeroutput> parameter may be used together with the others.
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><computeroutput>-h</computeroutput></term>
+<listitem><para>
+ displays a short help screen
+</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+<para>
+ While the command-line options are case-sensitive, interactive keystroke
+ at the IPTraf-ng full-screen interface are not.
+</para>
+</sect1>
+
+<sect1 id="menus">
+<title>Using the Menus</title>
+<para>
+ Menu items with a trailing ellipsis (<computeroutput>...</computeroutput>) either
+ pop up a submenu with further items, or require additional information
+ before it can complete the task and return to the menu.
+ Menu items without an ellipsis execute immediately.
+</para>
+<para>
+ Use the Up and Down arrow keys on your keyboard to move the selection
+ bar. Press Enter to execute the selected item. Alternatively, you can
+ also directly press the highlighted letter of the item you want. This
+ will immediately execute the option.
+</para>
+<figure>
+<title>The IPTraf-ng Main Menu</title>
+<graphic format="png" fileref="iptraf-mmenu">
+</figure>
+</sect1>
+<sect1 id="exiting">
+<title>Exiting IPTraf-ng</title>
+<para>
+ You can exit IPTraf-ng with the Exit command in the main menu.
+</para>
+<para>
+ When started with one of the command-line options to
+ directly start a statistical facility, pressing X or Q will exit the
+ facility directly, without any confirmation. The
+<computeroutput>-t</computeroutput>
+ command-line parameter will automatically exit the
+ facility after the specified length of time without any confirmation
+ as well. Daemon facilities started with the <computeroutput>-B</computeroutput> parameter
+ will immediately terminate after being sent a
+ USR2 signal. See <link linkend="backop">background
+ operation</link> in chapter 9 for more information.
+</para>
+</sect1>
+</chapter>
+
+<chapter id="preparingtouse">
+<title>Preparing to Use IPTraf-ng</title>
+<para>
+This chapter provides information applicable to all of IPTraf-ng's statistical
+monitors.
+</para>
+<sect1 id="numbers">
+<title>Number Display Notations</title>
+<para>
+ IPTraf-ng initially returns exact counts of bytes and packets. However, as they
+ grow larger, IPTraf-ng begins displaying them in increasingly higher denominations.
+</para>
+<para>
+ A number standing alone with no suffix represents an exact count. A
+ number with a K following is a kilo (thousand) figure. An M,
+ G, and T suffix represents mega (million), giga (billion), and
+ tera (trillion) respectively. The following table shows examples.
+</para>
+
+<table frame="all">
+<title>Numeric Display Notations</title>
+<tgroup cols="2" align="left" colsep="0" rowsep="0">
+<tbody>
+<row>
+<entry>1024067</entry><entry>exactly 1024067</entry>
+</row>
+<row>
+<entry>1024K</entry><entry>approximately 1024000</entry>
+</row>
+<row>
+<entry>1024M</entry><entry>approximately 1024000000</entry>
+</row>
+<row>
+<entry>1024G</entry><entry>approximately 1024000000000</entry>
+</row>
+<row>
+<entry>1024T</entry><entry>approximately 1024000000000000</entry>
+</row>
+</tbody>
+</tgroup>
+</table>
+
+<para>
+ These notations apply to both packet and byte counts.
+</para>
+</sect1>
+<sect1 id="instances">
+<title>Instances and Logging</title>
+<para>
+ IPTraf-ng allows multiple instances of the
+ facilities at the same time in different processes (for example, you can
+ run two or more IP Traffic Monitors at the same time).
+ However only one can listen on a specific interface or all interfaces
+ at once. The only exception is the general interface
+ statistics, which is still restricted to only one instance at a time.
+</para>
+<para>
+ Because of this, each instance now generates log files with
+ unique names for instances, depending on either their instance
+ or the interface they're listening on. If the <emphasis>Logging</emphasis> option is turned
+ on (see the <link linkend="config">Configuration</link> chapter), IPTraf-ng
+ will prompt you for a log file name while presenting a
+ default. You may accept this default or change it. Press Enter
+ to accept, or Ctrl+X to cancel. Canceling will turn logging off for that
+ particular session.
+</para>
+<para>
+ If you don't specify an absolute path, the log file will be placed in:
+</para>
+<para>
+<filename>/var/log/iptraf-ng</filename>.
+</para>
+<figure>
+<title>The logfile prompt dialog</title>
+<graphic format="png" fileref="iptraf-logprompt">
+</figure>
+<para>
+ See the Logging section
+in the <link linkend="config">Configuration</link> chapter for
+detailed information on logging. See also the documentation on
+each statistical facility for the default log file names.
+</para>
+<para>
+ The default log file names will also be used
+if the <computeroutput>-B</computeroutput> parameter is used
+ to run IPTraf-ng in the background. You can override the defaults with the
+ <computeroutput>-L</computeroutput> parameter. See
+<link linkend="backop">Background Operation</link> in Chapter 9.
+</para>
+</sect1>
+<sect1 id="updates">
+<title>Screen Update Delays</title>
+<para>
+ A configuration option is available to control screen update speed.
+</para>
+<para>
+ See the <emphasis>Screen update interval...</emphasis> configuration option under the
+ <link linkend="config">Configuration</link> chapter of this manual.
+</para>
+</sect1>
+<sect1 id="ifaces">
+<title>Supported Network Interfaces</title>
+<para>
+ IPTraf-ng currently supports the following network interface types and names.
+</para>
+<variablelist>
+<varlistentry>
+<term><filename>lo</filename></term>
+<listitem><para>
+ The loopback interface. Every machine has one, and has an IP address
+ of 127.0.0.1. <filename>lo</filename> is also indicated if data
+ is detected on the
+<filename>dummy<replaceable>n</replaceable></filename> interface(s).
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><filename>eth<replaceable>n</replaceable></filename></term>
+<listitem><para>
+ An Ethernet interface. <replaceable>n</replaceable> starts from 0.
+ Therefore, <filename>eth0</filename> refers to the first
+ Ethernet interface, <filename>eth1</filename> to the second, and
+ so on. Most machines only have one.
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><filename>fddi<replaceable>n</replaceable></filename></term>
+<listitem><para>
+ An FDDI interface. <replaceable>n</replaceable> starts from 0.
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><filename>ppp<replaceable>n</replaceable></filename></term>
+<listitem><para>
+ A PPP interface. <replaceable>n</replaceable> starts from 0.
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><filename>sli<replaceable>n</replaceable></filename></term>
+<listitem><para>
+A SLIP interface. <replaceable>n</replaceable> starts from 0.
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><filename>plip<replaceable>n</replaceable></filename></term>
+<listitem><para>
+ PLIP interfaces. These are point-to-point IP connections using the PC
+ parallel port.
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><filename>ipsec<replaceable>n</replaceable></filename></term>
+<listitem><para>
+ This refers to Free s/WAN (and possibly other) logical VPN interfaces.
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><filename>sbni<replaceable>n</replaceable></filename></term>
+<listitem><para>
+ SBNI long-range modem interfaces
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><filename>dvb<replaceable>n</replaceable></filename>,
+<filename>sm200</filename>, <filename>sm300</filename></term>
+<listitem><para>
+ DVB satellite-receive interfaces
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><filename>wlan<replaceable>n</replaceable></filename>,
+<filename>wvlan<replaceable>n</replaceable></filename></term>
+<listitem><para>
+ Wireless LAN interfaces
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><filename>tun<replaceable>n</replaceable></filename></term>
+<listitem><para>
+general logical tunnel interfaces
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><filename>brg<replaceable>n</replaceable></filename></term>
+<listitem><para>
+general logical bridge interfaces
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><filename>hdlc<replaceable>n</replaceable></filename></term>
+<listitem><para>
+ Frame Relay base (FRAD) interfaces (non-PVC)
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><filename>pvc<replaceable>n</replaceable></filename></term>
+<listitem><para>
+ Frame Relay Permanent Virtual Circuit interfaces
+</para>
+</listitem>
+</varlistentry>
+</variablelist>
+<para>
+ Your system's network interfaces must be named according
+ to the schemes specified above.
+</para>
+</sect1>
+</chapter>
+<chapter id="itrafmon">
+<title>The IP Traffic Monitor</title>
+<para>
+ Executing the first menu item or specifying <computeroutput>-i</computeroutput>
+ to the <command>iptraf-ng</command> command takes you to the IP traffic monitor. The traffic
+ monitor is a real-time monitoring system that intercepts all packets
+ on all detected network interfaces, decodes the IP information on all IP packets and
+ displays the appropriate information, most notably the
+ source and destination addresses. It also
+ determines the encapsulated protocol within the IP packet, and
+ displays some important information about that as well.
+</para>
+<para>
+ There are two windows in the traffic monitor, both of which can be
+ scrolled with the Up and Down cursor keys. Just press W to
+ move the <computeroutput>Active</computeroutput> indicator to the window you
+ want to control.
+</para>
+<figure>
+<title>The IP traffic monitor</title>
+<graphic format="png" fileref="iptraf-iptm1">
+</figure>
+
+<sect1 id="upperwin">
+<title>The Upper Window</title>
+<para>
+ The upper window of the traffic monitor displays the currently
+ detected TCP
+ connections. Information about TCP packets are displayed here. The
+ window contains these pieces of information:
+</para>
+
+<itemizedlist spacing="compact">
+<listitem><para>Source address and port</para></listitem>
+<listitem><para>Packet count</para></listitem>
+<listitem><para>Byte count</para></listitem>
+<listitem><para>Source MAC address</para></listitem>
+<listitem><para>Packet Size</para></listitem>
+<listitem><para>Window Size</para></listitem>
+<listitem><para>TCP flag statuses</para></listitem>
+<listitem><para>Interface</para></listitem>
+</itemizedlist>
+
+
+<para>
+ The Up and Down cursor keys move an indicator bar between entries in the
+ TCP monitor, scrolling the window if necessary. The PgUp and PgDn keys
+ display the previous and next screenfuls of entries respectively.
+</para>
+<para>
+ The IP traffic monitor computes the data flow rate
+ of the currently highlighted TCP flow and displays it on the lower-right
+ corner of the screen. The flow rate is in kilobits or kilobytes per
+ second depending on the <emphasis>Activity mode</emphasis> switch
+in the <emphasis><link linkend="config">Configure...</link></emphasis> menu.
+</para>
+<para>
+ Because this monitoring system relies solely on packet information, it
+ does not determine which endpoint initiated the connection. In other
+ words, it does not know which endpoints are the client and server.
+ This is necessary because it can operate in promiscuous
+ mode, and as such cannot determine the socket statuses for other
+ machines on the LAN. However, a little knowledge of the well-known TCP
+port numbers can give a good idea about which address is that of the server.
+</para>
+<para>
+ The system therefore displays two entries for each connection, one for
+ each direction of the TCP connection. To make it easier to determine the
+ direction pairs of each connection, a bracket is used to "join" both
+ together. This bracket appears at the leftmost part of each entry.
+</para>
+<para>
+ Just because a host entry appears at the upper end of a
+ connection bracket doesn't mean it was the initiator of the connection.
+</para>
+<para>
+ Each entry in the window contains these fields:
+</para>
+
+<variablelist>
+<varlistentry>
+<term><emphasis role="bold">Source address and port</emphasis></term>
+<listitem><para>
+ The source address and port indicator is
+in <replaceable>address</replaceable>:<replaceable>port</replaceable> format.
+ This indicates the source machine and TCP port on that machine
+ from which this data is coming.
+</para>
+<para>
+ The destination is the host:port at the other end of the bracket.
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><emphasis role="bold">Packet count</emphasis></term>
+<listitem><para>
+ The number of packets received for this direction of the TCP connection
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><emphasis role="bold">Byte count</emphasis></term>
+<listitem><para>
+ The number of bytes received for this direction
+ of the TCP connection. These bytes include total IP and TCP header
+ information, in addition to the actual data. Data link
+ header (e.g. Ethernet and FDDI) data are not included.
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><emphasis role="bold">Source MAC address</emphasis></term>
+<listitem><para>
+ The address of the host on your local LAN that delivered this packet.
+ This can be viewed by pressing M once if <emphasis>Source MAC
+addrs</emphasis> in traffic
+ monitor is enabled in the <emphasis><link linkend="config">Configure...</link></emphasis> menu.
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><emphasis role="bold">Packet Size</emphasis></term>
+<listitem><para>
+ The size of the most recently received packet. This item
+ is visible if you press M for more TCP information. This is the size
+ of the IP datagram only, not including the data link header.
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><emphasis role="bold">Window Size</emphasis></term>
+<listitem><para>
+ The advertised window size of the most recently received packet. This
+ item is visible if you press M for more TCP information.
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><emphasis role="bold">Flag statuses</emphasis></term>
+<listitem><para>
+ The flags of the most recently received packet.
+
+<variablelist>
+<varlistentry>
+<term><computeroutput>S</computeroutput></term>
+<listitem><para>
+ SYN. A synchronization is taking place in preparation for
+ connection establishment. If only an <computeroutput>S</computeroutput>
+ is present (<computeroutput>S---</computeroutput>) the source is trying
+ to initiate a connection. If an <computeroutput>A</computeroutput> is
+ also present (<computeroutput>S-A-</computeroutput>), this is an
+ acknowledgment of a previous connection request, and is responding.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><computeroutput>A</computeroutput></term>
+<listitem><para>
+ ACK. This is an acknowledgment of a previously received packet
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><computeroutput>P</computeroutput></term>
+<listitem><para>
+ PSH. A request to push all data to the top of the receiving queue
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><computeroutput>U</computeroutput></term>
+<listitem><para>
+ URG. This packet contains urgent data
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><computeroutput>RESET</computeroutput></term>
+<listitem><para>
+ RST. The source machine indicated in this direction reset the entire connection. The direction entries for reset connections become available for new connections.
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><computeroutput>DONE</computeroutput></term>
+<listitem><para>
+ The connection is done sending data in this direction, and has sent a FIN (finished) packet, but has not yet been acknowledged by the other host.
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><computeroutput>CLOSED</computeroutput></term>
+<listitem><para>
+ The FIN has been acknowledged by the other host. When both directions of a connection are marked CLOSED, the entries they occupy become available for new connection entries.
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><computeroutput>-</computeroutput></term>
+<listitem><para>
+ The flag is not set
+</para></listitem>
+</varlistentry>
+</variablelist>
+</para></listitem>
+</varlistentry>
+</variablelist>
+
+<para>
+ Some other pieces of information can be viewed as well. The M key
+ displays more TCP information. Pressing M once
+ displays the MAC addresses of the LAN hosts
+ that delivered the packets (if the <emphasis>Source MAC addrs in traffic
+monitor</emphasis>
+ option is enabled in the <emphasis><link linkend="config">Configure...</link></emphasis>
+menu). <computeroutput>N/A</computeroutput> is displayed if
+ no packets have been received from the source yet, or if the interface
+ doesn't support MAC addresses (such as PPP interfaces).
+</para>
+<para>
+ If the <emphasis>Source MAC addrs in traffic monitor</emphasis> option is not enabled,
+ pressing M simply toggles between the counts and the packet and window
+ sizes.
+</para>
+<para>
+ By default, only IP addresses are displayed, but if you have access to a
+ name server or host table, you may enable reverse lookup for the
+ IP addresses. Just enable reverse lookup
+in the <emphasis><link linkend="config">Configure...</link></emphasis> menu.
+</para>
+
+<sidebar>
+<title>The Asynchronous Resolving Process</title>
+<para>
+ The IP traffic monitor starts a process to help speed up reverse lookups
+ without sacrificing too much keyboard control and accuracy of the counts.
+ While reverse lookup is being conducted in the background, IP addresses
+ will be used until the resolution is complete.
+</para>
+<para>
+ If for some reason the resolving process cannot start, and you are on the
+ Internet, and you enable reverse lookup, your keyboard control can become
+ very slow. This is because the standard lookup functions do not return
+ until they have completed their tasks, and it can take several seconds
+ for a name resolution in the foreground to complete.
+</para>
+<para>
+ The resolving process will spawn up to 200 children to process reverse
+ DNS queries.
+</para>
+</sidebar>
+
+<tip>
+<title>Tip</title>
+<para>If you notice unusual SYN activity (too many
+initial (<computeroutput>S---</computeroutput>) but frozen SYN entries, or rapidly
+increasing initial SYN packets for a single connection), you may
+be under a SYN flooding attack or TCP port scan. Apply appropriate measures, or the
+targeted machines may begin denying network services.
+</para>
+</tip>
+
+<para>
+ Entries not updated within a user-configurable amount of
+ time may get replaced with new connections. The default time is 15
+ minutes. This is regardless of whether the connection is closed or
+ not. (Some unclosed connections may be due to extremely slow links
+ or crashes at either end of the connection.) This figure can be changed
+ at the <emphasis><link linkend="config">Configure...</link></emphasis> menu.
+</para>
+<para>
+ Some early entries may have a &gt; symbol in front of its packet
+ count. This means the connection was already established
+ when the monitor started. In other words, the figures indicated do not
+ reflect the counts since the start
+ of the TCP connection, but rather, since the start of the traffic
+ monitor. Eventually, these &gt; entries will close (or time out) and
+ disappear. TCP entries without the >
+ were initiated after the traffic monitor started, and the counts
+ indicate the totals of the connection itself. Just consider entries
+ with &gt; partial.
+</para>
+<para>
+ Some &gt entries may go idle if the traffic monitor was started
+ when these connections were already half-closed (FIN sent
+ by one host, but data still being sent by the other). This
+ is because the traffic monitor cannot determine if a
+ connection was already half-closed when it started. These entries will
+ eventually time out. (To minimize these entries, an entry is not added
+ by the monitor until a packet with data or a SYN packet is received.)
+</para>
+<para>
+ Direction entries also become available for reuse if an ICMP Destination
+ Unreachable message is received for the connection.
+</para>
+<para>
+ The lower part of the screen contains a summary line showing the IP,
+ TCP, UDP, ICMP, and non-IP byte counts since the start of the
+ monitor. The IP, TCP, UDP, and ICMP counts include only the IP
+ datagram header and data, not the data-link headers. The
+ non-IP count includes the data-link headers.
+</para>
+
+<note>
+<title>
+ Technical note: IP Forwarding and Masquerading
+</title>
+<para>
+ Previous versions of IPTraf-ng issued a warning if the kernel had
+ IP masquerading enabled due to the way the
+ kernel masqueraded and translated the IP addresses. The new kernels no
+ longer do it as before and IPTraf-ng now gives output properly on
+ masquerading machines. The <computeroutput>-q</computeroutput> parameter is no
+ longer required to suppress the warning screen.
+</para>
+<para>
+ On forwarding (non-masquerading)
+ machines packets and TCP connections simply appear twice, one
+ each for the incoming and outgoing interfaces if all interafaces
+ are being monitored.
+</para>
+<para>
+ On masquerading machines, packets and connections from the
+ internal network to the external network also appear
+ twice, one for the internal and external interface. Packets coming
+ from the internal network will be indicated as coming from the internal
+ IP address that sourced them, and also as coming from the IP address
+ of the external interface on your masquerading machine. In much the same
+ way, packets coming in from the external network will look
+ like they're destined for the external interface's IP address, and again
+ as destined for the final host on the internal network.
+</para>
+</note>
+
+<sect2>
+ <title>Closed/Idle/Timed Out Connections</title>
+<para>
+ A TCP connection entry that closes, gets reset, or stays idle too long
+ normally gets replaced with new connections. However,
+ if there are too many of these, active connections may become
+ interspersed among closed, reset, or idle entries.
+</para>
+<para>
+ IPTraf-ng can be set to automatically remove all closed, reset, and
+ idle entries with the <emphasis>TCP closed/idle
+ persistence...</emphasis> configuration option. You can also press the F key to
+ immediately clear them at any time.
+</para>
+
+<note>
+ <title>Note</title>
+<para>
+The <emphasis>TCP timeout...</emphasis> option only tells
+IPTraf-ng how long it should take before a connection should be considered
+idle and open to replacement by new connections. This
+does not determine how long it remains on-screen. The <emphasis>TCP closed/idle
+persistence...</emphasis> parameter flushes entries that have been idle for the
+number of minutes defined by the <emphasis>TCP timeout...</emphasis> option.
+</para> </note>
+</sect2>
+<sect2>
+<title>Sorting TCP Entries</title>
+<para>
+ The TCP connection entries can be sorted by pressing the S key, then
+ by selecting a sort criterion. Pressing S will display a box showing the
+ available sort criteria. Press P to sort by packet count, B to sort by
+ byte count. Pressing any other key cancels the sort.
+</para>
+<para>
+ The sort operation compares the larger values in each connection entry
+ pair and sorts the counts in descending order.
+</para>
+<para>
+ Over time, the entries will go out of order as counts proceed at varying
+ rates. Sorting is not done automatically so as not to degrade performance
+and accuracy.
+</para>
+<figure>
+<title>The IP traffic monitor sort criteria</title>
+<graphic format="png" fileref="iptraf-iptmsort">
+</figure>
+</sect2>
+</sect1>
+<sect1 id="lowerwin">
+<title>Lower Window</title>
+<para>
+ The lower window displays information about the other types of traffic
+ on your network. The following protocols are detected internally:
+</para>
+<itemizedlist spacing="compact">
+<listitem><para>User Datagram Protocol (UDP)</para></listitem>
+
+<listitem><para>Internet Control Message Protocol (ICMP)</para></listitem>
+
+<listitem><para>Open Shortest-Path First (OSPF)</para></listitem>
+
+<listitem><para>Interior Gateway Routing Protocol (IGRP)</para></listitem>
+
+<listitem><para>Interior Gateway Protocol (IGP)</para></listitem>
+
+<listitem><para>Internet Group Management Protocol (IGMP)</para></listitem>
+
+<listitem><para>General Routing Encapsulation (GRE)</para></listitem>
+
+<listitem><para>Layer 2 Tunneling Protocol (L2TP)</para></listitem>
+
+<listitem><para>IPSec AH and ESP protocols (IPSec AH and IPSec ESP)</para></listitem>
+
+<listitem><para>Address Resolution Protocol (ARP)</para></listitem>
+
+<listitem><para>Reverse Address Resolution Protocol (RARP)</para></listitem>
+</itemizedlist>
+
+<para>
+ Other IP protocols are looked up from the <filename>/etc/services</filename>
+ file. If <filename>/etc/services</filename> doesn't contain information about
+ that protocol, the protocol number is indicated.
+</para>
+<para>
+ Non-IP packets are indicated as
+<computeroutput>Non-IP</computeroutput> in the lower window.
+</para>
+
+<note>
+<title>Note</title>
+<para>The source and destination addresses for ARP and
+RARP entries are MAC addresses.
+</para>
+<para>
+ Strictly speaking, ARP and RARP packets aren't IP packets, since
+ they are not encapsulated in an IP datagram. They're
+ just indicated because they are integral to proper IP operation on LANs.
+</para>
+</note>
+
+<para>
+ For all packets in the lower window, only the first IP fragment is
+ indicated (since that contains the header
+ of the IP-encapsulated protocol) but with no further information
+ from the encapsulated protocol.
+</para>
+<para>
+UDP packets are also displayed
+in
+<computeroutput><replaceable>address</replaceable>:<replaceable>port</replaceable>
+</computeroutput> format while ICMP entries also contain the
+ICMP message type. For easier location, each type of protocol
+is color-coded (only on color terminals such as the Linux console).
+</para>
+
+<variablelist>
+<varlistentry><term>UDP</term><listitem><para>Red on White</para></listitem></varlistentry>
+<varlistentry><term>ICMP</term><listitem><para>Yellow on Blue</para></listitem></varlistentry>
+<varlistentry><term>OSPF</term><listitem><para>Black on Cyan</para></listitem></varlistentry>
+<varlistentry><term>IGRP</term><listitem><para>Bright white on Cyan</para></listitem></varlistentry>
+<varlistentry><term>IGP</term><listitem><para>Red on Cyan</para></listitem></varlistentry>
+<varlistentry><term>IGMP</term><listitem><para>Bright green on Blue</para></listitem></varlistentry>
+<varlistentry><term>GRE</term><listitem><para>Blue on white</para></listitem></varlistentry>
+<varlistentry><term>ARP</term><listitem><para>Bright white on Red</para></listitem></varlistentry>
+<varlistentry><term>RARP</term><listitem><para>Bright white on Red</para></listitem></varlistentry>
+<varlistentry><term>Other IP</term><listitem><para>Yellow on red</para></listitem></varlistentry>
+<varlistentry><term>Non-IP</term><listitem><para>Yellow on Red</para></listitem></varlistentry>
+</variablelist>
+
+<para>
+ The lower window can hold up to 512 entries. You can
+ scroll the lower window by using the W key to move the Active indicator
+ to it, and by using the Up and Down cursor keys. The lower
+ window automatically scrolls every time a new entry is added, and either
+ the first entry or last entry is visible. Upon reaching 512 entries, old
+ entries are thrown out as new entries are added.
+</para>
+<para>
+ Some entries may be too long to completely fit in a screen line. You can
+ use the Left and Right cursor keys to vertically scroll the lower window
+ when it is marked <computeroutput>Active</computeroutput>. If your
+terminal can be resized (e.g. xterm), you may do so before starting
+IPTraf-ng.
+</para>
+<para>
+ Entries for packets received on LAN interfaces also include the
+ source MAC address of the LAN host which delivered it. This behavior
+ is enabled by turning on the Source MAC addrs in traffic monitor toggle
+ in the <emphasis><link linkend="config">Configure...</link></emphasis> menu.
+</para>
+
+<sect2>
+<title>Entry Details</title>
+<para>
+ In general, the entries in the lower window indicate the protocol, the
+ IP datagram size (full frame size for non-IP, including ARP and
+ RARP), the source address, the destination
+ address, and the network interface the packet was detected on.
+ However, some protocols have a little more information.
+</para>
+<sect3>
+<title>ICMP</title>
+<para>
+ ICMP entries are displayed in this format:
+</para>
+<synopsis>
+ICMP <replaceable>type</replaceable> [(<replaceable>subtype</replaceable>)] (<replaceable>size</replaceable> bytes) from <replaceable>source</replaceable> to <replaceable>destination</replaceable>
+[(src HWaddr <replaceable>srcMACaddress</replaceable>)] on <replaceable>interface</replaceable>
+</synopsis>
+<para>
+ where type could be any of the following:
+</para>
+
+<variablelist>
+<varlistentry>
+<term><computeroutput>echo req, echo rply</computeroutput></term>
+<listitem><para>
+ ICMP echo request and reply. Usually used by the ping program and other network monitoring and diagnostic program.
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>dest unrch</computeroutput></term>
+<listitem><para>
+ ICMP destination unreachable. Something failed to reach its target. The dest unreach type is supplemented with a further indicator of the problem. Destination unreachable messages for TCP traffic causes the corresponding TCP entry in the upper
+ window to be made available for reuse by new connections.
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>redirct</computeroutput></term>
+<listitem><para>
+ ICMP redirect. Usually generated by a router to tell a host that a better gateway is available.
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>src qnch</computeroutput></term>
+<listitem><para>
+ The ICMP source quench is used to stop a host from transmitting. It's a
+flow control mechanism for IP.
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>time excd</computeroutput></term>
+<listitem><para>
+ Indicates a packet's time-to-live value expired before it got
+to its destination. Mostly happens if a destination is too far away.
+Also used by the traceroute program.
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>router adv</computeroutput></term>
+<listitem><para>
+ ICMP router advertisement
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>router sol</computeroutput></term>
+<listitem><para>
+ ICMP router solicitation
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>timestmp req</computeroutput></term>
+<listitem><para>
+ ICMP timestamp request
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>timestmp rep</computeroutput></term>
+<listitem><para>
+ ICMP timestamp reply
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>info req</computeroutput></term>
+<listitem><para>
+ ICMP information request
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>info rep</computeroutput></term>
+<listitem><para>
+ ICMP information reply
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>addr mask req</computeroutput></term>
+<listitem><para>
+ ICMP address mask request
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>addr mask rep</computeroutput></term>
+<listitem><para>
+ ICMP address mask reply
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>param prob</computeroutput></term>
+<listitem><para>
+ ICMP parameter problem
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>bad/unknown</computeroutput></term>
+<listitem><para>
+ An unrecognized ICMP packet was received, or the packet is corrupted.
+</para></listitem></varlistentry>
+</variablelist>
+<para>
+ The destination unreachable message also includes information on the
+ type of error encountered. Here are the destination unreachable codes:
+</para>
+
+<variablelist>
+<varlistentry>
+<term><computeroutput>ntwk</computeroutput></term>
+<listitem><para>
+ network unreachable
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>host</computeroutput></term>
+<listitem><para>
+ host unreachable
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>proto</computeroutput></term>
+<listitem><para>
+ protocol unreachable
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>port</computeroutput></term>
+<listitem><para>
+ port unreachable
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>pkt fltrd</computeroutput></term>
+<listitem><para>
+ packet filtered (normally by an access rule on a router or firewall)
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>DF set</computeroutput></term>
+<listitem><para>
+ the packet has to be fragmented somewhere, but its don't fragment
+ (DF) bit is set.
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>src rte fail</computeroutput></term>
+<listitem><para>
+ source route failed
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>src isltd</computeroutput></term>
+<listitem><para>
+ source isolated (obsolete)
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>net comm denied</computeroutput></term>
+<listitem><para>
+ network communication denied
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>host comm denied</computeroutput></term>
+<listitem><para>
+ host communication denied
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>net unrch for TOS</computeroutput></term>
+<listitem><para>
+ network unreachable for specified IP type-of-service
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>host unrch for TOS</computeroutput></term>
+<listitem><para>
+ host unreachable for specified IP type-of-service
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>prec violtn</computeroutput></term>
+<listitem><para>
+ precedence violation
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>prec cutoff</computeroutput></term>
+<listitem><para>
+ precedence cutoff
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>dest net unkn</computeroutput></term>
+<listitem><para>
+ destination network unknown
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>dest host unkn</computeroutput></term>
+<listitem><para>
+ destination network unknown
+</para></listitem></varlistentry>
+</variablelist>
+
+<para>
+ For more information on ICMP, see RFC 792.
+</para>
+</sect3>
+
+<sect3>
+<title>OSPF</title>
+
+<para>
+OSPF messages also include a little more information. The format of an
+OSPF message in the window is:
+</para>
+
+<synopsis>
+OSPF <replaceable>type</replaceable> (a=<replaceable>area</replaceable> r=<replaceable>router</replaceable>) (<replaceable>size</replaceable>bytes) from <replaceable>source</replaceable> to <replaceable>destination</replaceable>
+[(src HWaddr <replaceable>srcMACaddress</replaceable>)] on <replaceable>interface</replaceable>
+</synopsis>
+
+<para>
+ The type can be one of the following:
+</para>
+
+<variablelist>
+<varlistentry>
+<term><computeroutput>hlo</computeroutput></term>
+<listitem><para>
+ OSPF hello. Hello messages establish OSPF communications and keep routers informed of each other's presence.
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>DB desc</computeroutput></term>
+<listitem><para>
+ OSPF Database Description
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>LSR</computeroutput></term>
+<listitem><para>
+ OSPF Link State Request
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>LSU</computeroutput></term>
+<listitem><para>
+ OSPF Link State Update. Messages indicating the states of the OSPF network links
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>LSA</computeroutput></term>
+<listitem><para>
+ OSPF Link State Acknowledgment
+</para></listitem></varlistentry>
+</variablelist>
+<para>
+ The entries in parentheses:
+</para>
+<variablelist>
+<varlistentry>
+<term><computeroutput>a=<replaceable>area</replaceable></computeroutput></term>
+<listitem><para>
+ The area number of the OSPF message
+</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>r=<replaceable>router</replaceable></computeroutput></term>
+<listitem><para>
+ The IP address of the router that generated the message. It
+ is not necessarily the same as the source address
+ of the encapsulating IP packet.
+</para></listitem></varlistentry>
+</variablelist>
+
+<para>
+ Many times, the destination addresses for OSPF packets are class D
+ multicast addresses in standard dotted decimal notation or (if reverse
+ lookup is enabled), hosts under the <computeroutput>MCAST.NET</computeroutput> domain. Such multicast
+ addresses are defined as follows:
+</para>
+
+<variablelist>
+<varlistentry>
+<term><computeroutput>224.0.0.5 (OSPF-ALL.MCAST.NET)</computeroutput></term>
+<listitem><para>OSPF all routers</para></listitem></varlistentry>
+<varlistentry>
+<term><computeroutput>224.0.0.6 (OSPF-DSIG.MCAST.NET)</computeroutput></term>
+<listitem><para>OSPF all designated routers</para></listitem></varlistentry>
+</variablelist>
+
+<para>
+ See RFC 1247 for details on the OSPF protocol.
+</para>
+</sect3>
+</sect2>
+</sect1>
+<sect1>
+<title>Additional Information</title>
+<para>
+ When started from the main menu and logging is enabled, the IP traffic
+ monitor prompts you for a log file name. The default name is
+<filename>ip_traffic-<replaceable>n</replaceable>.log (where
+<replaceable>n</replaceable></filename> is what
+ instance of the traffic monitor this is (1, 2, 3, and so on). (e.g. if
+ this is the first instance, the default file name will
+ be <filename>ip_traffic-1.log</filename>.)
+</para>
+<para>
+ When started with the <computeroutput>-i</computeroutput> parameter,
+ the log filename can be specified with the <computeroutput>-L</computeroutput>
+ parameter. See the <link linkend="cmdline">Command-line Parameters</link>
+ section above for more information.
+</para>
+<para>
+On busy networks, the display may become cluttered with traffic you're not
+interested in. To control the traffic monitor's output, you can apply a
+<emphasis>filter</emphasis>. See Chapter 7, <link
+linkend="filters">Filters</link> for more information on IPTraf-ng's filters.
+</para>
+<para>
+ At any time, you can press X or Q to return to the main menu (or back to
+ the shell if the monitor was started with <command>iptraf-ng -i</command>).
+</para>
+</sect1>
+</chapter>
+
+<chapter id="netstats">
+<title>Network Interface Statistics</title>
+<para>
+There are two network interface
+statistics facilities: the general interface statistics, which
+displays a statistical summary of all attached interfaces, and the
+detailed interface statistics, which shows more statistical and
+load information about a single selected interface.
+</para>
+<sect1 id="genstats">
+
+<title>General Interface Statistics</title>
+<para>
+ The second menu option displays a list of
+ attached network interfaces, and some general
+ packet counts. Specifically, it displays counts of IP, non-IP, and bad
+ IP packets (packets with IP checksum errors). It also includes an
+ activity indicator, which shows the number of kilobits and packets the
+ interface sees per second. All figures are for incoming and outgoing
+ packets. (Again, considering promiscuous
+ mode for LAN interfaces, which simply causes the machine
+ to intercept all packets). This is useful for general monitoring
+ of all attached interfaces. If byte counts and
+ additional information are needed for a specific interface, the <emphasis>Detailed
+ interface statistics</emphasis> option is also available.
+</para>
+<para>
+ The activity indicators can be toggled between kbits/s and kbytes/s with
+ the <emphasis>Activity mode</emphasis> configuration option.
+</para>
+<para>
+ The general statistics window will dynamically add new entries
+ as packets from newly-created interfaces (e.g. new PPP interfaces) are
+ intercepted. Long lists can be scrolled with the Up, Down, PgUp, and
+ PgDn keys.
+</para>
+<para>
+This monitor is affected by IPTraf-ng's <link
+linkend="filters">filters</link> as described in Chapter 7.
+</para>
+<para>
+ Copies of the statistics are written to the log file
+ <filename>iface_stats_general.log</filename> at regular intervals if logging is
+ enabled. See the <emphasis>Logging</emphasis>
+option int the <link linkend="config">Configuration</link> chapter.
+</para>
+<para>
+ This facility can be started directly from the command line with the
+ <command>-g</command> option to the <command>iptraf-ng</command> command.
+ When started from the command line, the log filename and log interval can be
+ specified with the <computeroutput>-L</computeroutput> and <computeroutput>-I</computeroutput>
+ parameters respectively. See the <link linkend="cmdline">Command-line Parameters</link>
+ section above for more information.
+</para>
+<figure>
+<title>The general interface statistics screen</title>
+<graphic format="png" fileref="iptraf-gstat1">
+</figure>
+<para>
+ You can press X or Q to return to the main menu.
+</para>
+</sect1>
+<sect1 id="detstats">
+<title>Detailed Interface Statistics</title>
+<para>
+ The third menu option displays packet statistics for any
+ selected interface. It provides basically the same information
+ as the <emphasis>General interface statistics</emphasis>
+ option, with additional details.
+ This facility provides the following information:
+</para>
+<itemizedlist spacing="compact" mark="bullet">
+<listitem><para>
+ Total packet and byte counts
+</para></listitem>
+<listitem><para>
+ IP packet and byte counts
+</para></listitem>
+<listitem><para>
+ TCP packet and byte counts
+</para></listitem>
+<listitem><para>
+ UDP packet and byte count
+</para></listitem>
+<listitem><para>
+ ICMP packet and byte counts
+</para></listitem>
+<listitem><para>
+ Other IP-type packet and byte counts
+</para></listitem>
+<listitem><para>
+ Non-IP packet and byte counts
+</para></listitem>
+<listitem><para>
+ Checksum error count
+</para></listitem>
+<listitem><para>
+ Interface activity
+</para></listitem>
+<listitem><para>
+ Broadcast packet and byte counts
+</para></listitem>
+</itemizedlist>
+<para>
+ All IP byte counts (IP, TCP, UDP, ICMP, other IP) include IP header data
+ and payload. The data link header is not included. The full frame length
+ (including data-link header) is included in the non-IP and Total
+ byte count. All data-link headers are also included in the Total byte
+ counts.
+</para>
+<figure>
+<title>The detailed interface statistics screen</title>
+<graphic format="png" fileref="iptraf-dstat1">
+</figure>
+<para>
+ The upper portion of the screen
+ contains the packet and byte counts for all IP and
+ non-IP packets intercepted on the interface. The lower portion
+ contains the total, incoming, and outgoing interface data rates.
+</para>
+<para>
+ This facility also displays incoming and outgoing counts and data rates.
+</para>
+<para>
+ An outgoing packet is one that exits your interface, regardless
+ of whether it originated from your machine or came
+ from another machine and was routed through yours. An incoming packet is
+ one that enters your interface, either addressed
+ to you directly, broadcast, multicast, or captured promiscuously.
+</para>
+<para>
+ The rate indicators can be set to display kbits/s or kbytes/s with the
+ <emphasis>Activity mode</emphasis> configuration option.
+</para>
+
+<note>
+ <title>Note</title>
+ <para>
+ Buffering and some other factors may affect the data rates, notably
+ the outgoing rate, causing it to reflect a higher figure than the actual
+ rate at which the interface is sending.
+</para>
+</note>
+<para>
+ The figures are logged at regular intervals if logging is enabled. The
+ default log file name at the prompt is
+ <filename>iface_stats_detailed-<replaceable>iface</replaceable>.log</filename>
+ where iface is the selected interface for this session (for example,
+ <filename>iface_stats_detailed-eth0.log</filename>).
+</para>
+<para>
+ If you wish to start this facility directly
+ from the command line, you can specify the
+<computeroutput>-d</computeroutput> parameter and an interface
+ to monitor. For example,
+</para>
+<synopsis>
+iptraf-ng -d eth0
+</synopsis>
+<para>
+ starts the statistics for <filename>eth0</filename>. The interface must be specified, or
+ IPTraf-ng will not start the facility.
+</para>
+<para>
+ When started from the command line, the log filename and log interval can be
+ specified with the <computeroutput>-L</computeroutput> and <computeroutput>-I</computeroutput>
+ parameters respectively. See the <link linkend="cmdline">Command-line Parameters</link>
+ section above for more information.
+</para>
+<note>
+ <title>Note</title>
+ <para>
+ In both the general and detailed statistics screens, as well as
+ in the IP traffic monitor, the packet counts are for
+ actual network packets (layer 2), not the logical IP packets (layer 3)
+ that may be reconstructed after fragmentation. That means, if a
+ packet was fragmented into four pieces, and these four fragments pass
+ over your interface, the packet counts will indicate four separate
+ packets.
+ </para>
+</note>
+<para>
+ The figure for the IP checksum errors is a packet count only, because the
+ corrupted IP header cannot be relied upon to give a correct IP
+ packet length value.
+</para>
+<para>
+ This facility's output is also affected by IPTraf-ng's <link
+linkend="filters">filters</link>. See Chapter 7 for more information
+on filters.
+</para>
+<para>
+ Pressing X or Q takes you back to the main menu (if this
+ facility was started with the command-line option, X or Q drops you back
+ to the shell).
+</para>
+</sect1>
+</chapter>
+
+<chapter id="statbreakdowns">
+<title>Statistical Breakdowns</title>
+<para>
+ Statistical breakdowns contain two facilities that break
+ down traffic counts by either packet size or TCP/UDP port.
+</para>
+<sect1 id="pktsize">
+<title>Packet Sizes</title>
+
+<para>
+ The packet size breakdown takes the interface's Maximum Transmission
+ Unit (MTU) size and divides it into 20 brackets, each bracket
+ containing a range of sizes. As a packet is captured, its size
+ is determined and the appropriate bracket is incremented.
+</para>
+<para>
+ This facility provides an idea as to the packet sizes passing over
+ your network, and can aid in network (re)design decisions.
+</para>
+<figure>
+<title>The packet size statistical breakdown</title>
+<graphic format="png" fileref="iptraf-pktsize">
+</figure>
+<para>
+ If logging is enabled, copies of the statistics are written at regular
+ intervals to a log file. The default log file name
+ is
+ <filename>packet_size-<replaceable>iface</replaceable>.log</filename> where
+ <replaceable>iface</replaceable>
+ is the selected interface for this session (for example,
+ <filename>packet_size-eth0.log</filename>).
+</para>
+<para>
+IPTraf-ng's filters do not affect this facility.
+</para>
+<para>
+ The packet size breakdown can also be invoked straight
+ from the command line by specifying the <computeroutput>-z</computeroutput> iface
+ parameter. The interface parameter is required. For example,
+ this command runs the facility on interface <filename>eth0</filename>.
+</para>
+<synopsis>
+iptraf-ng -z eth0
+</synopsis>
+<para>
+ When started from the command line, the log filename and log interval can be
+ specified with the <computeroutput>-L</computeroutput> and <computeroutput>-I</computeroutput>
+ parameters respectively. See the <link linkend="cmdline">Command-line Parameters</link>
+ section above for more information.
+</para>
+<para>
+ To exit, press X or Ctrl+X.
+</para>
+</sect1>
+
+<sect1 id="servmon">
+<title>TCP and UDP Traffic Statistics</title>
+<para>
+ IPTraf-ng also includes a facility that generates statistics on TCP and UDP
+ traffic. This facility displays counts of all TCP and UDP packets with
+ source or destination ports numbered less than 1024. Ports 1 to 1023 are
+ reserved for the TCP/IP application protocols (well-known ports).
+</para>
+<figure>
+<title>The TCP/UDP service monitor</title>
+<graphic format="png" fileref="iptraf-tcpudp">
+</figure>
+<para>
+ The statistics window indicates the protocol (TCP or UDP), the
+ port number, the total packets and bytes counted for this particular
+ protocol/port combination, the packets and bytes destined for that
+ protocol and port, and the packets and bytes coming
+ from that protocol and port.
+</para>
+<para>
+ Byte counts include the IP header and payload only. The data link header
+ is not included.
+</para>
+<para>
+ The protocol/port indicators are color-coded for easier identification
+ on color terminals. TCP indicators are in yellow, UDP in bright green.
+</para>
+<para>
+ Some network applications or protocols may use port numbers higher
+ than 1023. Examples
+ of these include application proxy servers (HTTP proxy servers typically
+ use values like 8000, 8080, 8888, and the like), and IRC
+ (IRC servers commonly accept connections on ports 6660 to 6669). These
+ ports are by default not included in the counts. If you do want
+ to include a higher-numbered port in the statistics, you can add
+ them yourself from the <emphasis><link linkend="config">Configure...</link>/Additional ports...</emphasis>
+ menu item. See the section below.
+</para>
+<para>
+ If logging is enabled, The statistics are also written to a log file
+ (the default name is
+<filename>tcp_udp_services-<replaceable>iface</replaceable>.log</filename>, where iface
+ is the selected interface (for example,
+<filename>tcp_udp_services-eth0.log</filename>).
+</para>
+<para>
+ IPTraf-ng computes the total, incoming, outgoing, and data rates of the
+ protocol currently indicated by the facility's highlight bar. The data
+ rates are indicated at the bottom of the screen. If logging is
+ enabled, the average data rates since the start of the facility are
+ placed in the log file.
+</para>
+<para>
+ The Up and Down cursor keys move the highlight bar. Pressing X or Ctrl+X
+ exits and returns to the main menu (or the shell if it was started
+ from the command line).
+</para>
+
+<sect2>
+ <title>Sorting TCP/UDP Entries</title>
+<para>
+ Pressing the S key brings up a window which allows you to
+ select the field by which the entries will be sorted. You can press R to
+ sort by port, P to sort by total packets, B to sort by total bytes, T to
+ sort by incoming packets (packets to), O to sort by incoming bytes
+ (bytes to), F to sort by outgoing packets (packets from) and M to sort
+ by outgoing bytes (bytes from). Pressing any other key cancels the sort.
+</para>
+<para>
+ Port numbers are sorted in ascending order (least first) but
+ statistics are sorted in descending order (largest counts first).
+</para>
+<para>
+ As with the IP traffic monitor, sorting is performed only with
+ this sequence. Automatic sorting is not performed so as not to
+ affect performance.
+</para>
+<figure>
+<title>The TCP/UDP monitor's sort criteria</title>
+<graphic format="png" fileref="iptraf-tcpudpsort">
+</figure>
+</sect2>
+<sect2>
+<title>Additional Information</title>
+<para>
+IPTraf-ng's filters affect the output of this facility. See Chapter 7, <link
+linkend="filters">Filters</link> for more information about filters.
+</para>
+<para>
+ If you wish to start this facility from the command line, you can
+ use the <computeroutput>-s</computeroutput> option followed by an interface to monitor. For example,
+</para>
+<synopsis>
+iptraf-ng -s eth0
+</synopsis>
+<para>
+ brings up this module for traffic on
+ <filename>eth0</filename>. The interface must be specified, or
+ IPTraf-ng will drop back to the shell.
+</para>
+<para>
+ When started from the command line, the log filename and log interval can be
+ specified with the <computeroutput>-L</computeroutput> and <computeroutput>-I</computeroutput>
+ parameters respectively. See the <link linkend="cmdline">Command-line Parameters</link>
+ section above for more information.
+</para>
+</sect2>
+</sect1>
+</chapter>
+
+<chapter id="hostmon">
+<title>LAN Station Statistics</title>
+<para>
+ The LAN station monitor (Ethernet station monitor on versions prior to
+ 1.3.0) discovers MAC addresses and displays statistics on the number
+ of incoming, and outgoing packets. It also includes figures for incoming
+ and outgoing kilobits per second for each discovered station.
+</para>
+<para>
+ The entry above each line of statistics is the station's LAN
+ type (Ethernet, PLIP, or FDDI) and the hardware MAC address.
+ Each statistics line consists of the following information:
+</para>
+
+<itemizedlist spacing="compact" mark="bullet">
+<listitem><para>Total packets incoming</para></listitem>
+
+ <listitem><para>IP packets incoming</para></listitem>
+
+ <listitem><para>Total bytes incoming</para></listitem>
+
+ <listitem><para>Incoming rate</para></listitem>
+
+ <listitem><para>Total packets outgoing</para></listitem>
+
+ <listitem><para>IP packets outgoing</para></listitem>
+
+ <listitem><para>Total bytes outgoing</para></listitem>
+
+ <listitem><para>Outgoing rate</para></listitem>
+</itemizedlist>
+<para>
+ The byte counts include the data link header. The activity
+ indicators can be set to display kbits/s or kbytes/s with the <emphasis>Activity
+ mode</emphasis> configuration option.
+</para>
+<para>
+ This facility works only for Ethernet, PLIP, and
+ FDDI frames. Loopback. SLIP/PPP networks are not monitored here.
+</para>
+<figure>
+<title>The LAN station monitor</title>
+<graphic format="png" fileref="iptraf-hw">
+</figure>
+<para>
+ Copies of the statistics are written to a log file at regular intervals
+ if logging is enabled. The default log file name
+ is <filename>lan_statistics-<replaceable>n</replaceable>.log</filename>, where n is the instance number of this facility
+ (for example, if this is the first instance, the generated default log
+ file name is <filename>lan_statistics-1.log</filename>).
+</para>
+<sect1 id="sortinglan">
+ <title>Sorting the LAN Station Monitor Entries</title>
+<para>
+ Press S to sort the entries. A box will pop up and display the
+ keys you can press to select the field by which the entries will
+ be sorted. Press P to sort by total incoming packets, I to sort by
+ incoming IP packets, B to sort by total incoming bytes, K to sort
+ by total outgoing packets, O to sort by outgoing IP packets, and Y to
+ sort by total outgoing bytes. Pressing any other key cancels the sort.
+</para>
+<figure>
+<title>The LAN station monitor's sort criteria</title>
+<graphic format="png" fileref="iptraf-hwsort"
+</figure>
+<para>
+ When started from the command line, the log filename and log interval can be
+ specified with the <computeroutput>-L</computeroutput> and <computeroutput>-I</computeroutput>
+ parameters respectively. See the <link linkend="cmdline">Command-line Parameters</link>
+ section above for more information.
+</para>
+</sect1>
+<sect1 id="morelanmoninfo">
+<title>Additional Information</title>
+<para>
+ The window can be scrolled with the Up and Down cursor keys. Press X
+ or Q to return to the main menu (or the shell if this
+ facility was started with the <computeroutput>-l</computeroutput> command-line option).
+</para>
+<para>
+The output of this facility is affected by any applied IPTraf-ng filter.
+</para>
+</sect1>
+</chapter>
+
+<chapter id="filters">
+ <title>Filters</title>
+
+<para>
+ Filters are used to control the information displayed by all facilities.
+ You may want to view statistics only on particular traffic
+ so you must restrict the information displayed. The filters also apply
+ to logging activity.
+</para>
+
+<para>
+ The IPTraf-ng filter management system is accessible through the
+ <emphasis>Filters...</emphasis> submenu.
+</para>
+<figure>
+<title>The Filters submenu</title>
+<graphic format="png" fileref="iptraf-filtermenu">
+</figure>
+
+<sect1 id="ipfilters">
+ <title>IP Filters</title>
+
+ <para>
+ The <emphasis>Filters/IP...</emphasis> menu option
+ allows you to define a set of rules that determine what IP traffic
+ to pass to the monitors. Selecting this option pops up another menu with
+ the tasks used to define and apply custom IP filters.
+</para>
+<figure>
+<title>The IP filter menu</title>
+<graphic format="png" fileref="iptraf-ipfltmenu">
+</figure>
+<sect2>
+ <title>Defining a New Filter</title>
+<para>
+ A freshly installed program will have no filters defined, so
+ before anything else, you will have to define a filter. You can do this
+ by selecting the <emphasis>Define new filter...</emphasis> option.
+</para>
+<para>
+ Selecting this option displays a box asking you to enter a short
+ description of the filter you are going to define. Just enter any text
+ that clearly identifies the nature of the filter.
+</para>
+<figure>
+<title>The IP filter name dialog</title>
+<graphic format="png" fileref="iptraf-ipfltnamedlg">
+</figure>
+<para>
+ Press Enter when you're done with that box. As an alternative, you can
+ also press Ctrl+X to cancel the operation.
+</para>
+<sect3>
+<title>The Filter Rule Selection Screen</title>
+<para>
+After you enter the filter's description, you will be taken to a blank
+rule selection box. At this screen you manage the various rules you
+define for this filter. You can opt to insert, append, edit, or delete
+rules.
+</para>
+<figure>
+<title>The filter rule selection screen. Selecting an entry
+displays that set for editing</title>
+<graphic format="png" fileref="iptraf-ipfltlist">
+</figure>
+<para>
+Any rules defined will appear here. You will see the
+source and destination
+addresses, masks and ports (long addresses and masks may
+be truncated) and whether this rule includes or excludes matching
+packets.
+</para>
+<para>Between the source and destination parameters is an arrow that
+indicates whether the rule matches packets (single-headed) only exactly or whether
+it matches packets flowing in the opposite direction (double-headed).
+</para>
+<para>
+At this screen, press I to insert at the current position of the selection
+bar, A to append a rule to the end of the list, Enter to
+edit the highlighted rule and D to delete the selected rule. With
+an empty list, A or I can be used to add the first rule.
+</para>
+<para>To add the first rule, press A or I. You will then be presented with
+a dialog box that allows you to enter the rule's parameters.
+</para>
+</sect3>
+<sect3>
+<title>Entering Filter Rules</title>
+<para>
+ You can enter addresses of individual hosts, networks,
+ or a catch-all address. The nature of the address will be determined
+ by the wildcard mask.
+</para>
+<para>
+ You'll notice two sets of fields, marked <computeroutput>Source</computeroutput>
+ and <computeroutput>Destination</computeroutput>. You fill these out
+ with the information about your source and targets.
+</para>
+<para>
+ Fill out the host name or IP address of the hosts or networks in
+ the first field
+ marked <computeroutput>Host name/IP Address</computeroutput>. Enter it in
+ standard dotted-decimal notation. When done, press Tab to move to the
+ <computeroutput>Wildcard mask</computeroutput> field. The wildcard mask
+ is similar but not exactly identical to the standard IP subnet
+ mask. The wildcard mask is used to determine which bits to ignore
+ when processing the filter. In most cases, it will work very closely
+ like a subnet mask. Place ones (1) under the bits you want the filter to
+ recognize, and keep zeros (0) under the bits you want the filter
+ to ignore. For example:
+</para>
+<para>
+To recognize the host 207.0.115.44
+</para>
+<informaltable pgwide="1" frame="none">
+<tgroup cols="2">
+<colspec colname="c1">
+<colspec colname="c2">
+<tbody>
+<row><entry>IP address</entry><entry><computeroutput>207.0.115.44</computeroutput></entry></row>
+<row><entry>Wildcard mask</entry><entry><computeroutput>255.255.255.255</computeroutput></entry></row>
+</tbody>
+</tgroup>
+</informaltable>
+<para>
+To recognize all hosts belonging to network
+202.47.132.<replaceable>x</replaceable>
+</para>
+<informaltable pgwide="1" frame="none">
+<tgroup cols="2">
+<colspec colname="c1">
+<colspec colname="c2">
+<tbody>
+<row><entry>IP address</entry><entry><computeroutput>202.47.132.0</computeroutput></entry></row>
+<row><entry>Wildcard mask</entry><entry><computeroutput>255.255.255.0</computeroutput></entry></row>
+</tbody>
+</tgroup>
+</informaltable>
+<para>
+To recognize all hosts with any address:
+</para>
+<informaltable pgwide="1" frame="none">
+<tgroup cols="2">
+<colspec colname="c1">
+<colspec colname="c2">
+<tbody>
+<row><entry>IP address</entry><entry><computeroutput>0.0.0.0</computeroutput></entry></row>
+<row><entry>Wildcard mask</entry><entry><computeroutput>0.0.0.0</computeroutput></entry></row>
+</tbody>
+</tgroup>
+</informaltable>
+
+<para>
+ The IP address/wildcard mask mechanism of the display filter doesn't
+ recognize IP address class. It uses a simple bit- pattern matching
+ algorithm.
+</para>
+<para>
+ The wildcard mask also does not have to end on a
+ byte boundary; you may mask right into a byte itself. For example,
+ 255.255.255.224 masks 27 bits (255 is 11111111, 224 is 11100000 in
+ binary).
+</para>
+<para>
+ IPTraf-ng also accepts host names in place of the IP addresses. IPTraf-ng will
+ resolve the host name when the filter is loaded. When the filter
+ is interpreted, the wildcard mask will also be applied. This can be
+ useful in cases where a single host name may resolve to several IP
+ addresses.
+</para>
+
+<tip> <title>Tip</title>
+ <para> See the <emphasis>Linux Network Administrator's Guide</emphasis>
+ if you need more information on IP addresses and subnet masking.
+</para>
+</tip>
+
+<tip><title>Tip</title>
+<para>
+IPTraf-ng allows you to specify the wildcard mask in Classless Interdomain Routing
+(CIDR) format. This format allows you to specify the number of 1-bits that
+mask the address. CIDR notation is the form
+<emphasis><computeroutput>address/bits</computeroutput></emphasis> where the
+<emphasis><computeroutput>address</computeroutput></emphasis> is the IP
+address or host name and
+<emphasis><computeroutput>bits</computeroutput></emphasis> is the number of
+1-bits in the mask. For example, if you want to mask 10.1.1.0 with
+<computeroutput>255.255.255.0</computeroutput>, note that
+<computeroutput>255.255.255.0</computeroutput> has 24 1-bits, so instead
+of specifying <computeroutput>255.255.255.0</computeroutput> in the wildcard
+mask field, you can just enter <computeroutput>10.1.1.0/24</computeroutput>
+in the address field. IPTraf-ng will translate the mask bits into an
+appropriate wildcard mask and fill in the mask field the next time you edit
+the filter rule.
+</para>
+<para>
+If you specify the mask in CIDR notation, leave the wildcard mask fields
+blank. If you fill them up, the wildcard mask fields will take precedence.
+</para>
+</tip>
+
+<para>
+ The <computeroutput>Port</computeroutput> fields should contain a
+ port number or range of any TCP or UDP service you may be
+ interested in. If you want to match only a single port number, fill
+ in the first field, while leaving the second blank or set to zero.
+ Fill in the second field if you want to match a range of ports (e.g. 80 to
+ 90).
+ Leave the first field blank or set to zero to let the filter ignore
+ the ports altogether.
+ You will most likely be interested in target ports rather than source ports
+ (which are usually unpredictable anyway, perhaps with the exception
+ of FTP data).
+</para>
+<para>
+Non-TCP and non-UDP packets are not affected by these fields, and these
+are used only when filtering TCP or UDP packets.
+</para>
+<para>
+ Fill out the second set of fields with the parameters of the
+ opposite end of the connection.
+</para>
+<tip>
+<title>Tip</title>
+<para>
+Any address or mask fields left blank default to
+0.0.0.0 while blank
+<computeroutput>Port</computeroutput> fields default to 0.
+This makes it easy to define
+filter rules if you're interested only in either the source or destination,
+but not the other. For example, you may be interested
+in traffic originating from network 61.9.88.0, in which case you just enter
+the source address, mask and port
+in the
+<computeroutput>Source</computeroutput> fields, while leaving the
+<computeroutput>Destination</computeroutput> fields blank.
+</para>
+</tip>
+<para>
+The next fields let you specify which IP-type protocols you want matched by
+this filter rule. Any packet whose protocol's corresponding field
+is marked with a <computeroutput>Y</computeroutput> is matched against the
+filter's defined IP addresses and ports, otherwise
+they don't pass through this filter rule.
+</para>
+<para>
+If you want to evaluate all IP packets just mark
+with <computeroutput>Y</computeroutput> the <computeroutput>All
+IP</computeroutput> field.
+</para>
+<para>
+For example, if you want to see only all TCP traffic, mark the
+<computeroutput>TCP</computeroutput> field
+with <computeroutput>Y</computeroutput>.
+</para>
+<para>
+The long field marked <computeroutput>Additional
+protocols</computeroutput> allows you to specify other protocols
+by their IANA number. (You can view the common IP protocol number
+in the <filename>/etc/protocols</filename> file). You can specify a list
+of protocol numbers or ranges separated by commas,
+Ranges have the beginning and ending protocol numbers separated with a
+hyphen.
+</para>
+<para>
+For example, to see the RSVP (46), IP mobile (55), and protocols
+(101 to 104), you use an entry that looks like this:
+</para>
+<synopsis>
+46, 55, 101-104
+</synopsis>
+<para>
+It's certainly possible to specify any of the protocols listed above in
+this field. Entering <computeroutput>1-255</computeroutput> is
+functionally identical
+to marking <computeroutput>All IP</computeroutput>
+with a <computeroutput>Y</computeroutput>.
+</para>
+<para>
+ The next field is marked <computeroutput>Include/Exclude</computeroutput>.
+ This field allows you to decide whether to include or filter out matching
+ packets. Setting this field to <computeroutput>I</computeroutput> causes the filter to
+ pass matching packets, while setting it to <computeroutput>E</computeroutput> causes
+ the filter to drop them. This field is set to
+ <computeroutput>I</computeroutput> by default.
+</para>
+<para>
+The last field in the dialog is labeled <computeroutput>Match opposite</computeroutput>. When set
+to <computeroutput>Y</computeroutput>, the filter will match packets flowing in the opposite direction.
+Previous versions of IPTraf-ng used to match TCP packets flowing in either direction, so the source
+and destination address/mask/port combinations were actually interchangeable. Starting with
+IPTraf 3.0, when filters extended to more than just the IP traffic monitor, this behavior is no longer
+the default throughout IPTraf-ng except in the IP traffic monitor's TCP window.
+</para>
+<note>
+<title>Note</title>
+<para>
+For TCP packets, this field is used in all facilities except the IP traffic monitor. Because
+the IP traffic monitor must capture TCP packets in both directions
+to properly determine a closed connection, the filter automatically matches
+packets in the opposite direction, regardless of this field's setting. However
+iin all other facilities, automatic matching of the reverse packets is not performed
+unless you set this field to <computeroutput>Y</computeroutput>.
+</para>
+<para>
+Filters for UDP and other IP protocols do not automatically match packets in the opposite direction
+unless you set the field to <computeroutput>Y</computeroutput>, even in the IP traffic monitor.
+</para>
+</note>
+<para>
+ Press Enter to accept all parameters when done. The parameters will be
+ accepted and you'll be taken back to the rule selection box. You can
+then add more rules by pressing A or you can insert new rules at any point
+by pressing I. Should you make a mistake, you can press Enter to
+edit the selected filter. You may enter
+ as many sets of parameters as you wish. Press Ctrl+X when done.
+</para>
+<note>
+<title>Note</title>
+<para>
+Because of the major changes in the filtering system since IPTraf 2.7,
+old filters will no longer work and will have to be redefined.
+</para>
+</note>
+<figure>
+<title>The IP filter parameters dialog</title>
+<graphic format="png" fileref="iptraf-ipfltdlg">
+</figure>
+</sect3>
+<sect3>
+ <title>Examples</title>
+<para>
+To see all traffic to/from host 202.47.132.1 from/to 207.0.115.44, regardless of TCP port
+</para>
+<informaltable frame="none" pgwide="1">
+<tgroup cols="3">
+<colspec colname="c1">
+<colspec colname="c2">
+<colspec colname="c3">
+<tbody>
+<row><entry>Host name/IP Address</entry><entry><computeroutput>202.47.132.2</computeroutput></entry><entry><computeroutput>207.0.115.44</computeroutput></entry></row>
+<row><entry>Wildcard mask</entry><entry><computeroutput>255.255.255.255</computeroutput></entry><entry><computeroutput>255.255.255.255</computeroutput></entry></row>
+<row><entry>Port</entry><entry><computeroutput>0</computeroutput></entry><entry><computeroutput>0</computeroutput></entry></row>
+<row><entry>Protocols</entry><entry><computeroutput>TCP: Y</computeroutput></entry></row>
+<row><entry>Include/Exclude</entry><entry><computeroutput>I</computeroutput></entry></row>
+<row><entry>Match opposite</entry><entry><computeroutput>Y</computeroutput></entry></row>
+</tbody>
+</tgroup>
+</informaltable>
+
+<para>
+To see all traffic from host 207.0.115.44 to all hosts
+on network 202.47.132.x
+</para>
+<informaltable frame="none" pgwide="1">
+<tgroup cols="3">
+<colspec colname="c1">
+<colspec colname="c2">
+<colspec colname="c3">
+<tbody>
+<row><entry>Host name/IP Address</entry><entry><computeroutput>207.0.115.44</computeroutput></entry><entry><computeroutput>202.47.132.0</computeroutput></entry></row>
+<row><entry>Wildcard mask</entry><entry><computeroutput>255.255.255.255</computeroutput></entry><entry><computeroutput>255.255.255.0</computeroutput></entry></row>
+<row><entry>Port</entry><entry><computeroutput>0</computeroutput></entry><entry><computeroutput>0</computeroutput></entry></row>
+<row><entry>Protocols</entry><entry><computeroutput>All IP: Y</computeroutput></entry></row>
+<row><entry>Include/Exclude</entry><entry><computeroutput>I</computeroutput></entry></row>
+<row><entry>Match opposite</entry><entry><computeroutput>N</computeroutput></entry></row>
+</tbody>
+</tgroup>
+</informaltable>
+
+<para>
+ To see all Web traffic (to and from port 80)
+ regardless of source or destination
+</para>
+<informaltable frame="none" pgwide="1">
+<tgroup cols="3">
+<colspec colname="c1">
+<colspec colname="c2">
+<colspec colname="c3">
+<tbody>
+<row><entry>Host name/IP Address</entry><entry><computeroutput>0.0.0.0</computeroutput></entry><entry><computeroutput>0.0.0.0</computeroutput></entry></row>
+<row><entry>Wildcard mask</entry><entry><computeroutput>0.0.0.0</computeroutput></entry><entry><computeroutput>0.0.0.0</computeroutput></entry></row>
+<row><entry>Port</entry><entry><computeroutput>80</computeroutput></entry><entry><computeroutput>0</computeroutput></entry></row>
+<row><entry>Protocols</entry><entry><computeroutput>TCP: Y</computeroutput></entry></row>
+<row><entry>Include/Exclude</entry><entry><computeroutput>I</computeroutput></entry></row>
+<row><entry>Match opposite</entry><entry><computeroutput>Y</computeroutput></entry></row>
+</tbody>
+</tgroup>
+</informaltable>
+
+<para>
+ To see all IRC traffic from port 6666 to 6669
+</para>
+<informaltable frame="none" pgwide="1">
+<tgroup cols="3">
+<colspec colname="c1">
+<colspec colname="c2">
+<colspec colname="c3">
+<tbody>
+<row><entry>Host name/IP Address</entry><entry><computeroutput>0.0.0.0</computeroutput></entry><entry><computeroutput>0.0.0.0</computeroutput></entry></row>
+<row><entry>Wildcard mask</entry><entry><computeroutput>0.0.0.0</computeroutput></entry><entry><computeroutput>0.0.0.0</computeroutput></entry></row>
+<row><entry>Port</entry><entry><computeroutput>0</computeroutput></entry><entry><computeroutput>6666</computeroutput>
+to <computeroutput>6669</computeroutput></entry></row>
+<row><entry>Protocols</entry><entry><computeroutput>TCP: Y</computeroutput></entry></row>
+<row><entry>Include/Exclude</entry><entry><computeroutput>I</computeroutput></entry></row>
+<row><entry>Match opposite</entry><entry><computeroutput>Y</computeroutput></entry></row>
+</tbody>
+</tgroup>
+</informaltable>
+
+<para>
+ To see all DNS traffic, (TCP and UDP, destination port 53)
+ regardless of source or destination
+</para>
+<informaltable frame="none" pgwide="1">
+<tgroup cols="3">
+<colspec colname="c1">
+<colspec colname="c2">
+<colspec colname="c3">
+<tbody>
+<row><entry>Host name/IP Address</entry><entry><computeroutput>0.0.0.0</computeroutput></entry><entry><computeroutput>0.0.0.0</computeroutput></entry></row>
+<row><entry>Wildcard
+mask</entry><entry><computeroutput>0.0.0.0</computeroutput></entry><entry><computeroutput>0.0.0.0</computeroutput></entry></row>
+<row><entry>Port</entry><entry><computeroutput>0</computeroutput></entry><entry><computeroutput>53</computeroutput></entry></row>
+<row><entry>Protocols</entry><entry><computeroutput>TCP: Y UDP: Y</computeroutput></entry></row>
+<row><entry>Include/Exclude</entry><entry><computeroutput>I</computeroutput></entry></row>
+<row><entry>Match opposite</entry><entry><computeroutput>Y</computeroutput></entry></row>
+</tbody>
+</tgroup>
+</informaltable>
+
+<para>
+ To see all mail (SMTP) traffic to a single host (202.47.132.2) from anywhere
+</para>
+<informaltable frame="none" pgwide="1">
+<tgroup cols="3">
+<colspec colname="c1">
+<colspec colname="c2">
+<colspec colname="c3">
+<tbody>
+<row><entry>Host name/IP Address</entry><entry><computeroutput>0.0.0.0</computeroutput></entry><entry><computeroutput>202.47.132.2</computeroutput></entry></row>
+<row><entry>Wildcard mask</entry><entry><computeroutput>0.0.0.0</computeroutput></entry><entry><computeroutput>255.255.255.255</computeroutput></entry></row>
+<row><entry>Port</entry><entry><computeroutput>0</computeroutput></entry><entry><computeroutput>25</computeroutput></entry></row>
+<row><entry>Protocols</entry><entry><computeroutput>TCP: Y</computeroutput></entry></row>
+<row><entry>Include/Exclude</entry><entry><computeroutput>I</computeroutput></entry></row>
+<row><entry>Match opposite</entry><entry><computeroutput>N</computeroutput></entry></row>
+
+</tbody>
+</tgroup>
+
+</informaltable>
+<para>
+ To see traffic from from/to host sunsite.unc.edu to/from cebu.mozcom.com
+</para>
+<informaltable frame="none" pgwide="1">
+<tgroup cols="3">
+<colspec colname="c1">
+<colspec colname="c2">
+<colspec colname="c3">
+<tbody>
+<row><entry>Host name/IP Address</entry><entry><computeroutput>sunsite.unc.edu</computeroutput></entry><entry><computeroutput>cebu.mozcom.com</computeroutput></entry></row>
+<row><entry>Wildcard mask</entry><entry><computeroutput>255.255.255.255</computeroutput></entry><entry><computeroutput>255.255.255.255</computeroutput></entry></row>
+<row><entry>Port</entry><entry><computeroutput>0</computeroutput></entry><entry><computeroutput>0</computeroutput></entry></row>
+<row><entry>Protocols</entry><entry><computeroutput>All IP: Y</computeroutput></entry></row>
+<row><entry>Include/Exclude</entry><entry><computeroutput>I</computeroutput></entry></row>
+<row><entry>Match opposite</entry><entry><computeroutput>Y</computeroutput></entry></row>
+</tbody>
+</tgroup>
+</informaltable>
+<para>
+ To omit display of traffic to/from 140.66.5.x from/to anywhere
+</para>
+<informaltable frame="none" pgwide="1">
+<tgroup cols="3">
+<colspec colname="c1">
+<colspec colname="c2">
+<colspec colname="c3">
+<tbody>
+<row><entry>Host name/IP Address</entry><entry><computeroutput>140.66.5.0</computeroutput></entry><entry><computeroutput>0.0.0.0</computeroutput></entry></row>
+<row><entry>Wildcard mask</entry><entry><computeroutput>255.255.255.0</computeroutput></entry><entry><computeroutput>0.0.0.0</computeroutput></entry></row>
+<row><entry>Port</entry><entry><computeroutput>0</computeroutput></entry><entry><computeroutput>0</computeroutput></entry></row>
+<row><entry>Protocols</entry><entry><computeroutput>All IP: Y</computeroutput></entry></row>
+<row><entry>Include/Exclude</entry><entry><computeroutput>E</computeroutput></entry></row>
+<row><entry>Match opposite</entry><entry><computeroutput>Y</computeroutput></entry></row>
+</tbody>
+</tgroup>
+</informaltable>
+<para>
+ You can enter as many parameters as you wish. All of them will
+ be interpreted until the first match is found.
+</para>
+</sect3>
+<sect3>
+ <title>Excluding Certain Sites</title>
+<para>
+
+ Filters follow an implicit "no-match" policy, that is, only packets
+ matching defined rules will be matched, others will be filtered out.
+ This is similar
+ to the access-list policy "whatever is not explicitly permitted is
+ denied". If you want to show all traffic to/from everywhere,
+ except certain places, you can specify the sites you wish to exclude,
+ mark them with <computeroutput>E</computeroutput> in the <computeroutput>Include/Exclude
+field</computeroutput>, and
+ define a general catch-all entry with source address
+<computeroutput>0.0.0.0</computeroutput>, mask
+ <computeroutput>0.0.0.0</computeroutput>, port <computeroutput>0</computeroutput>, and destination
+<computeroutput>0.0.0.0</computeroutput>, mask <computeroutput>0.0.0.0</computeroutput>,
+port <computeroutput>0</computeroutput>, tagged
+ with an <computeroutput>I</computeroutput>
+in the <computeroutput>Include/Exclude</computeroutput> field as the last entry.
+</para>
+
+<para>
+ For example:
+</para>
+<para>
+To see all traffic except all SMTP (both directions), Web (both directions), and traffic
+(only) from 207.0.115.44
+</para>
+<informaltable frame="none" pgwide="1">
+<tgroup cols="3">
+<colspec colname="c1">
+<colspec colname="c2">
+<colspec colname="c3">
+<tbody>
+<row><entry>Host name/IP address</entry><entry><computeroutput>0.0.0.0</computeroutput></entry><entry><computeroutput>0.0.0.0</computeroutput></entry></row>
+<row><entry>Wildcard mask</entry><entry><computeroutput>0.0.0.0</computeroutput></entry><entry><computeroutput>0.0.0.0</computeroutput></entry></row>
+<row><entry>Port</entry><entry><computeroutput>25</computeroutput></entry><entry><computeroutput>0</computeroutput></entry></row>
+<row><entry>Protocols</entry><entry><computeroutput>TCP: Y</computeroutput></entry></row>
+<row><entry>Include/Exclude</entry><entry><computeroutput>E</computeroutput></entry></row>
+<row><entry>Match opposite</entry><entry><computeroutput>Y</computeroutput></entry></row>
+<row><entry></entry></row>
+<row><entry>Host name/IP address</entry><entry><computeroutput>0.0.0.0</computeroutput></entry><entry><computeroutput> 0.0.0.0</computeroutput></entry></row>
+<row><entry>Wildcard mask</entry><entry><computeroutput>0.0.0.0</computeroutput></entry><entry><computeroutput>0.0.0.0</computeroutput></entry></row>
+<row><entry>Port</entry><entry><computeroutput>80</computeroutput></entry><entry><computeroutput>0</computeroutput></entry></row>
+<row><entry>Protocols</entry><entry><computeroutput>TCP: Y</computeroutput></entry></row>
+<row><entry>Include/Exclude</entry><entry><computeroutput>E</computeroutput></entry></row>
+<row><entry>Match opposite</entry><entry><computeroutput>Y</computeroutput></entry></row>
+<row><entry></entry></row>
+<row><entry>Host name/IP address</entry><entry><computeroutput>207.0.115.44</computeroutput></entry><entry><computeroutput>0.0.0.0</computeroutput></entry></row>
+<row><entry>Wildcard mask</entry><entry><computeroutput>255.255.255.255</computeroutput></entry><entry><computeroutput>0.0.0.0</computeroutput></entry></row>
+<row><entry>Port</entry><entry><computeroutput>0</computeroutput></entry><entry><computeroutput>0</computeroutput></entry></row>
+<row><entry>Protocols</entry><entry><computeroutput>All IP: Y</computeroutput></entry></row>
+<row><entry>Include/Exclude</entry><entry><computeroutput>E</computeroutput></entry></row>
+<row><entry>Match opposite</entry><entry><computeroutput>N</computeroutput></entry></row>
+<row><entry></entry></row>
+<row><entry>Host name/IP address</entry><entry><computeroutput>0.0.0.0</computeroutput></entry><entry><computeroutput>0.0.0.0</computeroutput></entry></row>
+<row><entry>Wildcard mask</entry><entry><computeroutput>0.0.0.0</computeroutput></entry><entry><computeroutput>0.0.0.0</computeroutput></entry></row>
+<row><entry>Port</entry><entry><computeroutput>0</computeroutput></entry><entry><computeroutput>0</computeroutput></entry></row>
+<row><entry>Protocols</entry><entry><computeroutput>All IP: Y</computeroutput></entry></row>
+<row><entry>Include/Exclude</entry><entry><computeroutput>I</computeroutput></entry></row>
+<row><entry>Match opposite</entry><entry><computeroutput>N</computeroutput></entry></row>
+</tbody>
+</tgroup>
+</informaltable>
+
+<tip>
+ <title>Tip</title>
+ <para>
+ To filter out all TCP, define a filter with a single entry, with a source of
+ <computeroutput>0.0.0.0</computeroutput> mask
+<computeroutput>0.0.0.0</computeroutput> port <computeroutput>0</computeroutput>, and a destination
+ of <computeroutput>0.0.0.0</computeroutput> mask <computeroutput>0.0.0.0</computeroutput>
+port <computeroutput>0</computeroutput>,
+with the <computeroutput>Include/Exclude</computeroutput> field
+ marked <computeroutput>E</computeroutput> (exclude). Then apply this filter.
+</para>
+</tip>
+</sect3>
+</sect2>
+<sect2>
+
+ <title>Applying a Filter</title>
+<para>
+ The above steps only add the filter to a defined list. To actually apply
+ the filter, you must select <emphasis>Apply filter...</emphasis> from the menu. You will be
+ presented with a list of filters you already defined. Select the one you
+ want to apply, and press Enter.
+</para>
+<para>
+ The applied filter stays in effect over exits and restarts of the IPTraf-ng program until it is detached.
+</para>
+</sect2>
+<sect2>
+ <title>Editing a Defined Filter</title>
+<para>
+ Select <emphasis>Edit filter...</emphasis> to modify an existing filter. Once you select this
+ option, you will be presented with the list of defined filters.
+ Select the filter you want to edit by moving the selection bar and press
+ Enter.
+</para>
+<para>
+ Edit the description if you wish. Pressing Ctrl+X at this point
+ will abort the operation, and the filter will remain unmodified. Press
+ Enter to accept any changes to the filter description.
+</para>
+<para>
+ After pressing Enter, you will see the filter's rules. To edit an
+ existing filter rule, move the selection bar
+ to the desired entry and press Enter. A prefilled dialog box
+ will appear. Edit its contents as desired. Press Enter to accept the
+ changes or Ctrl+X to discard.
+</para>
+<para>
+ You can add a new filter rule by pressing I to insert at the selection
+ bar's current position. When you press I, you will be presented with a
+ dialog box asking you to enter the new rule data. Pressing A results
+ in a similar operation, except the rule will be appended as the
+ last entry in the rule list.
+</para>
+<para>
+ Pressing D deletes the currently pointed entry.
+</para>
+<para>
+ Press X or Ctrl+X to end the edit and save the changes.
+</para>
+
+<note>
+ <title>Note</title>
+ <para>If you're editing the currently applied filter, you will need
+ to re-apply the filter for the changes to take effect.
+ </para>
+</note>
+
+
+<note>
+ <title>Note</title>
+<para>
+ Be aware that the filter processes the rules in order. In other
+ words, if a packet matches more than one rule, only the first matching
+ rule is followed.
+</para>
+</note>
+</sect2>
+<sect2>
+ <title>Deleting a Defined Filter</title>
+<para>
+ Select <emphasis>Delete filter...</emphasis> from the menu to remove a filter
+ from the list. Just move the selection bar to the filter you want to
+ delete, and press Enter.
+</para>
+</sect2>
+<sect2>
+ <title>Detaching a Filter</title>
+<para>
+ The <emphasis>Detach filter</emphasis> option deactivates the filter currently in
+ use. Selecting this option causes all TCP traffic to be passed
+ to the monitors.
+</para>
+<para>
+ When you're done with the menu, just select the Exit menu option.
+</para>
+</sect2>
+</sect1>
+<sect1 id="nonipfilters">
+<title>ARP, RARP, and other Non-IP Packet Filters</title>
+<para>
+ The <emphasis>Non-IP</emphasis> filter option toggles the display and logging of all non-IP
+ packets, except ARP and RARP, which are toggled separately.
+</para>
+</sect1>
+</chapter>
+<chapter id="config">
+<title>Configuring IPTraf-ng</title>
+
+<para>
+ IPTraf-ng can be easily configured
+with the <emphasis><link linkend="config">Configure...</link></emphasis> item in the
+ main menu. The configuration is stored in the
+ <filename>/var/local/iptraf-ng/iptraf.cfg</filename> file. If the file is not found, IPTraf-ng uses
+ the default settings. Any changes to the configuration immediately get
+ stored in the configuration file.
+</para>
+<figure>
+<title>The IPTraf-ng configuration menu</title>
+<graphic format="png" fileref="iptraf-configmenu">
+</figure>
+<sect1 id="toggles">
+ <title>Toggles</title>
+
+<sect2> <title>Reverse DNS Lookups</title>
+<para>
+ Activating reverse lookup causes IPTraf-ng to find out the name of the
+ hosts with the addresses in the IP packets. When this option is enabled,
+ IPTraf-ng's IP traffic monitor starts the DNS lookup server to help resolve
+ IP addresses in the background while allowing IPTraf-ng to continue
+ capturing packets.
+</para>
+<para>
+ This option is off by default.
+</para>
+</sect2>
+<sect2>
+ <title>TCP/UDP Service Names</title>
+<para>
+
+ This option, when on, causes IPTraf-ng to display the TCP/UDP service names
+ (<computeroutput>smtp</computeroutput>, <computeroutput>www</computeroutput>,
+ <computeroutput>pop3</computeroutput>, etc.) instead of their numeric ports (25, 80,
+ 110, etc). The number-to-name mappings will depend on the systems
+ services database file (usually <filename>/etc/services</filename>).
+ Should there be no corresponding service name for the
+ port number, the numeric form will still be displayed.
+
+</para>
+<para>
+ This setting is off by default.
+</para>
+
+<note>
+ <title>Note</title>
+ <para>
+ Reverse lookup and service name lookup take some
+ time and may impact performance and increase the chances of dropped
+ packets. Performance and results are best (albeit more cryptic) with both
+ these settings off.
+</para>
+</note>
+</sect2>
+
+<sect2>
+ <title>Force promiscuous</title>
+<para>
+
+ If this option is enabled, your LAN interfaces will capture all packets
+ on your LAN. Using this option enables you
+ to see all TCP connections and packets passing your LAN segment, even if
+ they're not from or for your machine. When this option is active
+ in the statistics windows, the Activity indicators will show a
+ good estimate of the load on your LAN segment.
+</para>
+<para>
+ When this option is disabled, you'll
+ only receive information about packets coming from and entering your
+ machine.
+</para>
+<para>
+ The setting of this option affects all LAN (
+ Ethernet, FDDI) interfaces on your machine, if you have more than one.
+</para>
+<para>
+ The interface's promiscuous flag is set only when a facility is started,
+ and turned off when it exits. However, if promiscuous
+ mode was already set when a facility was started, it remains set on exit.
+</para>
+<para>
+ If multiple instances of IPTraf-ng are started, the promiscuous setting
+ is restored only upon exit of the last facility.
+</para>
+
+<note>
+ <title>Note</title>
+<para>
+ Do not use other programs that change the interface's promiscuous flag at
+ the same time you're using IPTraf-ng. The programs can interfere with
+ each other's expected operations. While IPTraf-ng tries to obtain the
+ initial setting of any promiscuous flags for restoration
+ upon exit, other programs may not be as well-behaved, and they may
+ turn off the promiscuous flags while IPTraf-ng is still monitoring.
+</para>
+</note>
+</sect2>
+<sect2>
+ <title>Color</title>
+<para>
+ Turn this on with color monitors. Turn it off with
+ black-and- white monitors or non-color terminals (like xterms). Changes
+ to this setting will take effect the next time the program is started.
+</para>
+<para>
+ Color is on by default on consoles and color xterms, off on non-color terminals like xterms and VT100s.
+</para>
+</sect2>
+<sect2>
+ <title>Logging</title>
+<para>
+ When this option is active, IPTraf-ng will log information to a
+ disk file, which can be examined or analyzed later. Since IPTraf-ng
+ 2.4.0, IPTraf-ng prompts you for the name of the file to which to write the
+ logs. It will provide a default name, which you are free to accept
+ or change. The IP traffic monitor and LAN station monitor will
+ generate a log file name that is based on what instance they are (first,
+ second, and so on). The general interface statistics' default log file
+ name is constant, because it listens to all interfaces at once, and only
+ one instance can run at one time.
+</para>
+<para>
+ The other facilities generate a log file name based
+ on the interface they're listening on.
+</para>
+<para>
+ See the descriptions on the facilities above for the default log file names.
+</para>
+<para>
+ Press Enter to accept the log file name, or Ctrl+X to cancel. Canceling will turn logging off for that session.
+</para>
+<para>
+ The IP traffic monitor will write the following pieces of information to its log file:
+</para>
+<itemizedlist spacing="compact" mark="bullet">
+ <listitem><para>Start of the traffic monitor</para></listitem>
+
+ <listitem><para>Receipt of the first TCP packet for a connection. If that packet is a
+ SYN, (SYN) will be indicated in the log entry. (Of course, the traffic
+ monitor may start in the middle of established connections. It
+ will still count those packets. This also explains why some connection
+ entries may become idle if the traffic monitor is started in the
+ middle of a half-closed connection, and miss the first FIN.
+ Such entries time out in a while.)</para></listitem>
+
+ <listitem><para>Receipt of a FIN (with average flow rate)</para></listitem>
+
+ <listitem><para>ACK of a FIN</para></listitem>
+
+ <listitem><para>Timeouts of TCP entries (with average flow rate)</para></listitem>
+
+ <listitem><para>Reset connections (with average flow rate)</para></listitem>
+
+ <listitem><para>Everything that appears in the bottom window of the traffic monitor</para></listitem>
+
+ <listitem><para>Stopping of the traffic monitor</para></listitem>
+</itemizedlist>
+<para>
+ Each log entry includes the date and time the entry was written. Logging
+ is also affected by the defined filters.
+</para>
+<para>
+ Log files can grow very fast, so be prepared with plenty of
+ free space and delete unneeded logs. Log write errors are not indicated.
+</para>
+<para>
+ Copies of the interface statistics, TCP/UDP statistics, packet
+ size statistics, and LAN host statistics are also written
+ to the log files at regular intervals. See <emphasis>Log
+Interval...</emphasis> in this chapter.
+</para>
+<para>
+ IPTraf-ng closes and reopens the active log file when it receives a
+ <computeroutput>USR1</computeroutput> signal. This is useful in cases where a facility is run for
+ long periods of time but the log files have to be cleared or moved.
+</para>
+<para>
+ To clear or move an active log file, rename it first. IPTraf-ng will
+ continue to write to the file despite the new name. Then use the UNIX
+ kill command to send the running IPTraf-ng process a <computeroutput>USR1</computeroutput> signal. IPTraf-ng
+ will then close the log file and open another with the
+ original name. You can then safely remove or delete the renamed file.
+</para>
+<para>
+ Do not delete an open log file. Doing so will only result in a file just
+ as large but filled with null characters (ASCII code 0).
+</para>
+<para>
+ Logging comes disabled by default. The <computeroutput>USR1</computeroutput> signal is caught only if
+ logging is enabled, it is ignored otherwise.
+</para>
+<para>
+ A valid specification of <computeroutput>-L</computeroutput> on the command line with automatically
+ enable logging for that particular session. The saved configuration setting is not affected.
+</para>
+</sect2>
+<sect2>
+ <title>Activity mode</title>
+<para>
+ Toggles activity indicators in the interface and LAN statistics
+ facilities between kilobits per second (kbits/s) or kilobytes per second
+ (kbytes/s).
+</para>
+<para>
+ The default setting is kilobits per second.
+</para>
+</sect2>
+<sect2>
+ <title>Source MAC addrs in traffic monitor</title>
+<para>
+ When enabled, the IP traffic monitor retrieves the packets' source MAC
+ addresses if they came in on an Ethernet, FDDI, or PLIP interface. The
+ addresses appear in the lower window for non-TCP
+ packets, while for TCP connections, they can be viewed by pressing M.
+</para>
+<para>
+ No such information is displayed
+ if the network interface doesn't use MAC addresses (such
+ as PPP interfaces).
+</para>
+<para>
+ This can be used to determine the actual source of the packets on your local LAN.
+</para>
+<para>
+ The traffic monitor also logs the MAC addresses with this option
+ enabled. The default setting is off.
+</para>
+</sect2>
+</sect1>
+
+<sect1 id="timers">
+ <title>Timers</title>
+<para>
+ The <emphasis>Timers...</emphasis> submenu allows you to IPTraf-ng's
+ interval and timeout functions.
+</para>
+<figure>
+<title>The Timers configuration submenu</title>
+<graphic format="png" fileref="iptraf-timermenu">
+</figure>
+<sect2>
+ <title>TCP Timeout</title>
+<para>
+ This figure determines the amount of time (in minutes) a
+ connection entry may remain idle before it becomes
+ eligible for replacement by a new connection. The default is 15 minutes.
+ You may want to reduce this on an isolated (not connected
+ to the Internet) LAN or a LAN connected to the Internet with
+ high-speed links. Just enter the new value and press
+ Enter. You can press Ctrl+X to leave the current value unchanged.
+</para>
+</sect2>
+<sect2>
+<title>Log Interval</title>
+<para>
+ This figure determines the number of minutes between logging
+ of interface statistics, TCP/UDP figures, and LAN host statistics. The
+ default is 60 minutes. This figure is meaningless if logging is disabled.
+</para>
+<para>
+ This configuration item can be overridden with the <computeroutput>-I</computeroutput> when
+ a facility is directly invoked from the command line (not accessed via the main menu), and
+ remains effective for that particular session. The configured value is not affected.
+</para>
+</sect2>
+<sect2>
+ <title>Screen Update Interval</title>
+<para>
+ This value determines the rate in seconds at which the screen is
+ updated. The default is 0, which means the screen is updated as fast
+ as possible, giving close-to-realtime reflection
+ of network activity. However, this high-speed update can cause
+ incredible amounts of traffic if IPTraf-ng is run on a remote
+ terminal (e.g. a Telnet or Secure Shell session). You can set this
+ to a higher value, such as 1 or 2 seconds to slow down the updates.
+</para>
+<para>
+ This figure does not affect the rate of data capture. Only the
+ screen refresh is affected. The figures are still updated as fast as
+ possible, although the figure display will no longer be as close
+ to realtime.
+</para>
+<para>
+ The default setting is 0, which shouldn't be a problem on the
+ console. Set it to a slightly higher value on remote terminals or slow
+ links. The setting affects all monitoring facilities.
+</para>
+<note>
+ <title>Note</title>
+ <para>
+ Updating the screen is one of the slowest operations in a
+ program. Older versions of IPTraf-ng had a problem once network
+ activity became very high. Because each packet caused a screen update,
+ IPTraf-ng began spending more time with the screen updates, causing a loss
+ of packets once network activity reached a certain point.
+</para>
+<para>
+ However, since many users like rapid counts on their screen, a
+ compromise was incorporated. Even when the screen update interval is set
+ to 0, there is still a 50ms delay between screen updates (except the LAN
+ station monitor, which has a 100 ms delay). This is still visually fast,
+ but provides more time to the packet capture routine. Higher
+ delays may result in better accuracy of counts and activity.
+</para>
+<para>
+ In any case, this setting only affects screen updates. Capture still
+ proceeds as fast as possible.
+</para>
+</note>
+</sect2>
+<sect2>
+ <title>TCP closed/idle persistence</title>
+ <para>
+ This parameter
+ determines the interval (in minutes) at which the IP Traffic Monitor
+ clears from the TCP display window all closed, idle, and timed out
+ entries. Enter <computeroutput>0</computeroutput> to keep such entries on the
+ screen indefinitely, disappearing only when replaced by new connections.
+</para>
+
+<note>
+ <title>Note</title>
+<para>
+ The <emphasis>TCP timeout...</emphasis> option
+ only tells IPTraf-ng how long it should take before a connection should
+ be considered idle and open to replacement by new connections. This does
+ not determine how long
+ it remains onscreen. The <emphasis>TCP closed/idle
+ persistence...</emphasis>
+ parameter flushes entries that have been closed or reset, or idle for the number
+ of minutes defined by the <emphasis>TCP timeout...</emphasis> option.
+</para>
+</note>
+</sect2>
+</sect1>
+
+<sect1 id="customports">
+ <title>Custom Information</title>
+<para>
+ The remaining configuration items allow you to enter information which
+ IPTraf-ng uses for its displays and logs.
+</para>
+<sect2>
+ <title>Additional ports</title>
+ <para>Select this item to enter a port
+ number to be included in the TCP/UDP counts in the TCP/UDP service
+ statistics main menu item described above. By default,
+ port numbers above 1023 are not monitored. If you do
+ have a higher-numbered port to monitor, enter it here.
+</para>
+<para>
+ You will see two fields. If you have only one port to enter, just fill
+ up the first field. To specify a range, fill both fields, the first port
+ in the first field, the last port in the second field.
+</para>
+<para>
+ You can select this option multiple times to add more values or ranges.
+</para>
+</sect2>
+<sect2>
+ <title>Delete port/range</title>
+<para>
+ Select this item to remove a higher-numbered port number or
+ port range you entered earlier with the <emphasis>Additional
+ ports...</emphasis> option. A window will come up
+ containing the entered ports and ranges. Select the entry you want
+ delete and press Enter.
+</para>
+</sect2>
+<sect2>
+ <title>LAN Station Identifiers</title>
+
+<para>
+ The LAN station statistics facility monitors stations based
+ on their respective MAC addresses. The hexadecimal notation of these
+ addresses make them even more difficult to remember than the
+ dotted-decimal IP addresses, so these facilities were added to
+ help you better determine which station is which.
+</para>
+<para>
+ Selecting the <emphasis>Ethernet/PLIP host descriptions...</emphasis> or
+ <emphasis>FDDI host descriptions...</emphasis> options brings
+ up a submenu asking you to add, edit, or delete descriptions.
+</para>
+<para>
+ To add a new description, select the <emphasis>Add
+description...</emphasis> option. A dialog
+ box will appear, asking you for the MAC address and an appropriate
+ description. Type in the address in hexadecimal notation with no
+ punctuation of any kind. The dialog box is
+ case-insensitive for the address; the alphabetical digits A to F will be
+ stored in lowercase.
+</para>
+<para>
+ Use the Tab key to move between fields and Enter to accept. Press Ctrl+X
+ to discard this dialog and return to the main menu.
+</para>
+<para>
+ The description may be anything: the IP address, a fully-qualified
+ domain name, or a description of your liking as long
+ as the field can hold.
+</para>
+<para>
+ Enter as many descriptions as you need. Press Ctrl+X at a blank dialog
+ after you have entered the last entry
+</para>
+<para>
+ These descriptions will be displayed alongside the MAC addresses
+ in the LAN station monitor, together with the type of frame (Ethernet,
+ PLIP, or FDDI).
+</para>
+<para>
+ An existing address or description may be edited
+by selecting the <emphasis>Edit
+ description...</emphasis> option from the submenu. A panel will appear with a list
+ of existing address descriptions. Select the one you wish to
+ edit and press Enter. A dialog box identical to that
+ when you add a description will appear with prefilled fields. Just
+ backspace over and edit the fields. Press Enter to accept or Ctrl+X to
+ cancel.
+</para>
+<para>
+ Selecting the <emphasis>Delete description...</emphasis> submenu
+ item brings up the selection panel. Select the description you want to
+ delete and press Enter. You can also press Ctrl+X to cancel the operation.
+</para>
+<para>
+ IPTraf 2.4 and later also recognizes the <filename>/etc/ethers</filename> file.
+ Should a hardware address be present in the IPTraf-ng definition files and
+ in <filename>/etc/ethers</filename>, the IPTraf-ng definition will be used.
+</para>
+<note>
+ <title>Note</title>
+<para>
+ The description file for Ethernet and PLIP is
+ <filename>ethernet.desc</filename>, while the FDDI mappings are stored
+ in <filename>fddi.desc</filename> in the IPTraf-ng working directory. These files are in
+ colon-delimited text format. Database engines or custom scripts can be
+ told to append data lines to those files. Each line follows this
+ simple format:
+</para>
+<synopsis>
+<replaceable>address</replaceable>:<replaceable>description</replaceable>
+</synopsis>
+<para>
+ For example
+</para>
+<synopsis>
+00201e457e:Cisco 3640 gateway
+</synopsis>
+<para>
+ Do not put colons, periods, or any invalid characters in the MAC address.
+</para>
+</note>
+</sect2>
+</sect1>
+</chapter>
+<chapter id="backop">
+<title>Background Operation</title>
+
+<para>
+ IPTraf-ng's facilities can be placed in the background solely for
+ logging. When running in the background, it doesn't display any output
+ on the screen, and doesn't receive input
+ from the keyboard, and drops you back to the shell.
+</para>
+<para>
+ Before starting a statistical facility in the background, configure
+ IPTraf-ng in the usual way (set filters, add TCP/UDP ports, etc).
+</para>
+<para>
+ Once that's done, exit all instances of IPTraf-ng on the system, then
+ invoke IPTraf-ng from the command line with the parameter
+ to start the facility you want, the timeout (<computeroutput>-t</computeroutput>) parameter
+ if you wish, and the <computeroutput>-B</computeroutput> parameter to actually daemonize the program.
+ For example, to run the IP traffic monitor in the
+ background for all interfaces, issue the command
+</para>
+<synopsis>
+iptraf-ng -i all -B
+</synopsis>
+<para>
+ To run the detailed interface statistics
+on interface <filename>eth0</filename> for 5 minutes
+ in the background:
+</para>
+<synopsis>
+iptraf-ng -d eth0 -t 5 -B
+</synopsis>
+<para>
+ If the timeout parameter is not specified, the facility
+ will run until the process receives a USR2 signal. To stop a facility in
+ the background, do a
+</para>
+<synopsis>
+ps x
+</synopsis>
+<para>
+ at the command line, and find the process id (pid) of the iptraf-ng process
+ you're looking for. Then send that process a USR2 signal with the kill
+ command:
+</para>
+<synopsis>
+kill -USR2 pid
+</synopsis>
+<para>
+ Since IPTraf-ng cannot send error messages to the terminal, all
+ messages are written to the file daemon.log in the
+ IPTraf-ng logging directory.
+</para>
+<para>
+ The <computeroutput>-B</computeroutput> parameter automatically enables logging regardless of its configured
+ setting. The parameter is ignored if not used with one of the parameters
+ to start a facility from the command line.
+</para>
+<para>
+ The log file can be specified with the <computeroutput>-L</computeroutput> command-line parameter. If
+ this parameter is not specified, the default log file name for the
+ facility will be used (see the descriptions of the
+ facilities above for the default log name patterns).
+ If you don't specify an path, the log file will be placed in
+ <filename>/var/log/iptraf-ng</filename>.
+</para>
+<para>
+ The logging interval for all facilities (except the IP traffic monitor) can also be overriden
+ with the <computeroutput>-I</computeroutput> command-line parameter.
+</para>
+</chapter>
+
+<appendix id="messages">
+ <title>Messages</title>
+<para>
+IPTraf-ng's messages are presented in two ways. In interactive mode, messages
+are displayed in a distictive message box. In daemon (background) mode,
+appropriate messages are written to the <filename>iptraf-ng.log</filename>
+file in the IPTraf-ng log directory (normally
+<filename>/var/log/iptraf-ng</filename>.
+</para>
+
+<sect1 id="iptrafmessages">
+<title>IPTraf-ng Messages</title>
+<msgset>
+<simplemsgentry>
+<msgtext>
+<para><computeroutput>
+Unable to create config file
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+ IPTraf-ng cannot create the configuration file. The most likely cause of
+ this is that you didn't properly install the
+ program, and the necessary directory
+<filename>/var/local/iptraf-ng</filename> does not
+ exist. Can also be generated if you have a disk problem or if you
+ have too many files open.
+</para>
+</msgexplan>
+</simplemsgentry>
+
+<simplemsgentry>
+<msgtext>
+<para><computeroutput>Unable to read config file
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+ The configuration record cannot be read. You most likely have a disk
+ problem.
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Unable to write config file
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ The configuration file cannot be written. You either have a disk
+ problem, or (more likely), your disk is full.
+</para>
+</msgexplan>
+</simplemsgentry>
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Enter an appropriate description for this filter
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ Enter something to clearly describe the filter you are defining.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Error loading filter list file
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+ IPTraf-ng cannot access the list of defined TCP or UDP filters. Can also be
+ an indicator of a bad disk.
+</para>
+</msgexplan>
+</simplemsgentry>
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Error writing filter list file
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ The filter list file cannot be written to. You may
+ have trouble accessing your filters.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Unable to read TCP/UDP/misc IP filter file
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ IPTraf-ng cannot read the filter data off the file. Could be caused
+ by a bad disk.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Error opening filter data file
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+ IPTraf-ng cannot open the filter file. Could be caused by a shortage of
+ file descriptors or a bad disk.
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Unable to write filter data
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+ IPTraf-ng cannot add the newly defined filter to the filter list. This may
+ be due to a bad disk.
+</para>
+</msgexplan>
+</simplemsgentry>
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Cannot create filter data file
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+ IPTraf-ng cannot create the filter record file. The defined filter is lost.
+</para>
+</msgexplan>
+</simplemsgentry>
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Unable to save filter changes
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+ IPTraf-ng cannot save the changes you made to the filter. You probably
+ have a disk error.
+</para>
+</msgexplan>
+</simplemsgentry>
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Unable to write filter state information
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+ The current state of the filters cannot be saved. IPTraf-ng will be unable
+ to correctly reload the filters the next time it's started. This can
+ be caused by a bad disk or improper installation.
+</para>
+</msgexplan>
+</simplemsgentry>
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Unable to save interface flags
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+ IPTraf-ng was unable to save the flags of the network interfaces. This is
+ probably due to a bad installation or full filesystem.
+</para>
+</msgexplan>
+</simplemsgentry>
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Unable to retrieve saved interface flags
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+ IPTraf-ng was unable to retrieve the save interface flags.
+ Probably again due to a bad installation or full filesystem.
+</para>
+</msgexplan>
+</simplemsgentry>
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>
+<replaceable>protocol</replaceable> filter data file in use; try again later
+</computeroutput></para>
+<para><computeroutput>
+Filter state file in use; try again later
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+ Another IPTraf-ng process is modifying the TCP, UDP or miscellaneous IP
+ filter data or the filter state file and has locked the files
+ or file. Try again once the other IPTraf-ng process has terminated or
+ completed its modifications and unlocked the files.
+</para>
+</msgexplan>
+</simplemsgentry>
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Unable to resolve hostname
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+ The indicated host name in the filter cannot be resolved into an
+ IP address. Check the local hosts database <filename>/etc/hosts</filename> or
+ your machine's DNS configuration or DNS server.
+</para>
+<para>
+ The filter parameters will not be used.
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Unable to open host description file
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ IPTraf-ng cannot open the file containing the descriptions for Ethernet
+ or FDDI addresses. Could be due to a bad disk or a hit on the file
+ descriptor limit.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Unable to write host description
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ IPTraf-ng was unable to write the description record for this Ethernet or
+ FDDI address. Could be due to a bad disk or corrupted filesystem.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>No descriptions
+
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ You tried to edit or delete a description with no previous
+ descriptions defined.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Cannot open log file
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ There is a problem opening the log file. There is most
+ likely a problem with the disk, or there are too many open files.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Unable to obtain interface list
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ IPTraf-ng was unable to retrieve the list of network interfaces
+ from the <filename>/proc</filename> filesystem. This may be due
+ to a badly configured kernel. IPTraf-ng needs <filename>/proc</filename>
+ filesystem support.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>
+No active interfaces. Check their status or the /proc filesystem.
+</computeroutput></para>
+</msgtext>
+<msgexplan>
+<para>
+
+ IPTraf-ng found no active interfaces. Either all interfaces are down or the
+ <filename>/proc/net/dev</filename> file was empty or unavailable. Activate at least one
+ interface or check the <filename>/proc/net/dev</filename> file.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Unable to obtain interface parameters for interface
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ The system call to retrieve the interface's flags failed. Check your
+ interface or kernel driver.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Promisc change failed for interface
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ The system call to change the promiscuous flag failed. Check
+ your interface or its kernel driver.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Unable to open raw socket for flag change
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ IPTraf-ng was unable to open the necessary socket for the promiscuous
+ change operation. May be due to a shortage of file descriptors.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Unable to open socket for MTU determination
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ Returned by the facility for detailed interface statistics
+ if the raw socket's opening sequence failed. The facility will abort.
+</para>
+</msgexplan>
+</simplemsgentry>
+
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Unable to open raw socket
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+ IPTraf-ng was unable to open the raw socket for packet capture. May be due
+ to a shortage of file descriptors.
+</para>
+
+<note>
+ <title>Reminder</title>
+<para> IPTraf 2.x.x requires Linux kernel 2.2.x, with the Packet
+ Socket option compiled in or installed as a module. IPTraf 2.x will
+ return this error on a pre-2.2 kernel or on a 2.2 kernel without
+ Packet Socket.
+</para>
+</note>
+</msgexplan>
+</simplemsgentry>
+
+
+<simplemsgentry>
+<msgtext>
+<para><computeroutput>Unable to obtain interface MTU
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ The detailed statistics facility was unable to
+ obtain the maximum transmission unit (MTU) for the selected
+ interface. The facility will abort.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Specified interface not supported
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ The interface specified with the <computeroutput>-i</computeroutput>,
+ <computeroutput>-d</computeroutput>, <computeroutput>-s</computeroutput>, <computeroutput>-l</computeroutput>,
+ or <computeroutput>-z</computeroutput> command-line parameters is not supported
+ by IPTraf-ng.
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Specified interface not active
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ The interface specified with the <computeroutput>-i</computeroutput>,
+ <computeroutput>-d</computeroutput>,
+ <computeroutput>-s</computeroutput>, <computeroutput>-l</computeroutput>, or
+ <computeroutput>-z</computeroutput> command-line parameters is
+ supported, but not currently activated.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Fatal: memory allocation error
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ May occur if you have too little memory to allocate for windows, the
+ menu system, or dialog boxes. IPTraf-ng tries
+ to prevent further allocations if memory runs out during a
+ monitor. However, this could also mean a bug if you're reasonably sure
+ you're not out of memory. An instructional message
+ on bug reporting follows this message.
+</para>
+<note>
+ <title>Technical note</title>
+<para>This is actually a response to the
+ segmentation fault error (SIGSEGV).
+</para>
+</note>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>This program can be run only by the system administrator
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ IPTraf-ng normally does not allow anybody but uid 0 (root) to run it.
+ This measure is included for safety reasons. See the section
+ on recompiling the program below if you want to override this.
+ This feature is built in, and not part of the configuration
+
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Your TERM variable is not set
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ The <envar>TERM</envar> (terminal type) environment variable
+ must be set to a valid terminal type so that the screen management
+ routines can function properly. Set it to the appropriate terminal type.
+ Linux consoles typically have their <envar>TERM</envar> variables set to
+<computeroutput>linux</computeroutput>.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Received TERM signal
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+ Not related to the previous message. The
+<computeroutput>TERM</computeroutput> (terminate) signal
+ is normally used to gracefully shut down a program. This message
+ simply indicates that the <computeroutput>TERM</computeroutput> signal was caught and IPTraf-ng is
+ attempting to shut down as gracefully as possible.
+</para>
+</msgexplan>
+</simplemsgentry>
+<simplemsgentry>
+<msgtext>
+<para><computeroutput>
+ Invalid option or missing parameter, use iptraf-ng -h for help
+</computeroutput></para>
+</msgtext>
+<msgexplan>
+<para>
+ The <computeroutput>-i</computeroutput>,
+ <computeroutput>-d</computeroutput>,
+ <computeroutput>-s</computeroutput>, <computeroutput>-l</computeroutput>, or
+ <computeroutput>-z</computeroutput> options were specified but
+ no interface was specified on the command line. These
+ parameters require a valid interface name (or
+ <computeroutput>all</computeroutput> for <computeroutput>-i</computeroutput>
+or <computeroutput>-l</computeroutput>).
+</para>
+<para>
+ This message also appears if an unknown option is passed
+to the <command>iptraf-ng</command> command.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+
+<simplemsgentry>
+<msgtext>
+<para><computeroutput>Warning: unable to tag this process
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ IPTraf-ng normally tags itself when it runs to prevent multiple instances
+ of the statistical facilities from running.
+ This message means the program was unable to
+ create the necessary tag file. This may be due to a bad or
+ improper installation. Try running the
+<command>make install</command> procedure or the
+<command>Setup</command> in the distribution's top-level directory.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Warning: unable to tag facility
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ IPTraf-ng was unable to create the tag file for the facility you
+ started. The facility will still run, but other instances of IPTraf-ng that
+ may be running simultaneously will allow the same facility to run.
+ This may cause both instances of the facility to malfunction. This could
+ be due to a bad disk or bad installation.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+
+<simplemsgentry>
+<msgtext>
+<para><computeroutput><replaceable>facility</replaceable> already running/listening on interface
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ The facility you tried to start is currently running
+ on the indicated interface in another IPTraf-ng process on the machine.
+ This restriction is placed to prevent conflicts involving
+ internal sockets or the log files.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>General interface statistics already active in another process
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ Only one instance of the general interface statistics can run at a time.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Duplicate port/range entry
+
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+ You entered a port number or range that was already added to the list of
+ additional ports to be monitored by the TCP/UDP service monitor
+
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>No custom ports
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ There are no ports or port ranges earlier added. There's nothing
+ to delete.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Can't get communication sockets; lookups will block
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ IPTraf-ng cannot communicate with the resolving process. IPTraf-ng will
+ fall back to blocking lookups.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Can't spawn new process; lookups will block
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ IPTraf-ng cannot start a new process. This may be due to memory shortage.
+ IPTraf-ng will fall back to blocking lookups.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Fork error, IPTraf-ng cannot run in background
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ IPTraf-ng cannot start a new process, and can go into the background.
+ This may be due to memory shortage. IPTraf-ng aborts.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>No memory for new filter entry
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ IPTraf-ng was unable to allocate memory for a new filter entry. Most likely
+ due to memory shortage.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Memory Low
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+
+ This indicator appears if memory runs low due to a lot of entries in a
+ facility. Should critical functions fail (window creation,
+ internal allocation), the program could terminate with a
+ segmentation violation.
+</para>
+
+<note>
+ <title>Note</title>
+<para>
+ Any message or indicator about low memory means that your system
+ does not have enough memory to handle the entries. It is
+ almost certain that sooner or later, IPTraf-ng or other applications will
+ abort due to the failure of important system calls or library functions.
+ Memory must be added right away.
+</para>
+</note>
+</msgexplan>
+</simplemsgentry>
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>IPC Error
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+ This indicator appears if an error occurs receiving data
+ from the resolving process (IPC stands for Interprocess Communication).
+ This indication should not occur under normal circumstances.
+ Report instances of this condition and the circumstances under which
+ it happens. You may also include data from the
+<filename>rvnamed-ng.log</filename> file.
+
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>Error opening terminal: <replaceable>terminal</replaceable>
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+ The screen management routines cannot find the
+<filename>terminfo</filename> entry for your
+ terminal. IPTraf-ng expects the terminfo database located
+ in <filename>/usr/share/terminfo</filename>. This error could occur when your terminfo
+ database is located somewhere else.
+</para>
+<para>
+ See the section on controlling the <filename>terminfo</filename> search path.
+</para>
+</msgexplan>
+</simplemsgentry>
+
+ <simplemsgentry>
+<msgtext>
+<para><computeroutput>This will end your IPTraf-ng session
+ </computeroutput></para></msgtext>
+<msgexplan>
+<para>
+In interactive mode IPTraf-ng asks you to confirm your exit
+command. Press Enter to return to the shell or any other key to cancel
+your command and return to the main menu.
+</para>
+</msgexplan>
+</simplemsgentry>
+</msgset>
+</sect1>
+<sect1 id="rvnamedmessages">
+<title>
+ Resolving Process Messages
+</title>
+<para>
+ Resolving process does not send messages to the screen. It
+ writes its messages to the file <filename>rvnamed-ng.log</filename> in the
+ IPTraf-ng log directory.
+</para>
+<msgset>
+
+<simplemsgentry>
+<msgtext>
+<para><computeroutput>
+ Unable to open child communication socket
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+ Resolving process was unable to open the communication endpoint for
+ data reception from the children it creates. This is highly unusual
+ and should it occur, report the circumstances.
+</para>
+</msgexplan>
+</simplemsgentry>
+
+
+<simplemsgentry>
+<msgtext>
+<para><computeroutput>
+ Unable to open client communication socket
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+ Resolving process was unable to open the communication endpoint for
+ data exchange with the IPTraf-ng program. This is highly unusual and
+ should it occur, report the circumstances.
+</para>
+</msgexplan>
+</simplemsgentry>
+
+
+<simplemsgentry>
+<msgtext>
+<para><computeroutput>
+ Error binding client communication socket
+ Error binding child communication socket
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+ Resolving process was unable to assign a name to the indicated
+ communication socket. This may be due to a bad, full or corrupted
+ filesystem.
+</para>
+</msgexplan>
+</simplemsgentry>
+
+
+<simplemsgentry>
+<msgtext>
+<para><computeroutput>
+ Fatal error: no memory for descriptor monitoring
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+ Resolving process ran out of memory. IPTraf-ng will resort to blocking
+ and may freeze.
+</para>
+</msgexplan>
+</simplemsgentry>
+
+
+<simplemsgentry>
+<msgtext>
+<para><computeroutput>
+ Error on fork, returning IP address
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+ Resolving process had a problem spawning a copy of itself to resolve the IP
+ address; it will simply return the IP address in its literal,
+ dotted-decimal notation. IPTraf-ng will still function normally. This may
+ be due to lack of memory or a process limit hit.
+</para>
+</msgexplan>
+</simplemsgentry>
+
+
+
+<simplemsgentry>
+<msgtext>
+<para><computeroutput>
+ Maximum child process limit reached
+</computeroutput></para></msgtext>
+<msgexplan>
+<para>
+ Resolving process has reached its maximum number of child processes. This
+ is intended as a "brake" to prevent too many children from hogging
+ your computer's resources and possibly crashing it.
+</para>
+<para>
+ Unless IPTraf-ng is monitoring an extremely busy network without filters,
+ this shouldn't happen, at least, not that often. If you notice
+ this message, try applying filters or check your DNS server. Many times,
+ this can happen when the DNS server goes down for whatever reason
+ and you have resolving process children taking too long to resolve.
+</para>
+</msgexplan>
+</simplemsgentry>
+</msgset>
+</sect1>
+</appendix>
+<appendix id="gfdl">
+<title>GNU Free Documentation License</title>
+<!-- - GNU Project - Free Software Foundation (FSF) -->
+<!-- LINK REV="made" HREF="mailto:webmasters@gnu.org" -->
+
+
+ <!-- sect1>
+ <title>GNU Free Documentation License</title -->
+
+ <para>Version 1.1, March 2000</para>
+
+ <blockquote>
+ <para>Copyright (C) 2000 Free Software Foundation, Inc.
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.</para>
+ </blockquote>
+
+ <sect1 id="gfdl-0">
+ <title>PREAMBLE</title>
+
+ <para>The purpose of this License is to make a manual, textbook,
+ or other written document "free" in the sense of freedom: to
+ assure everyone the effective freedom to copy and redistribute it,
+ with or without modifying it, either commercially or
+ noncommercially. Secondarily, this License preserves for the
+ author and publisher a way to get credit for their work, while not
+ being considered responsible for modifications made by
+ others.</para>
+
+ <para>This License is a kind of "copyleft", which means that
+ derivative works of the document must themselves be free in the
+ same sense. It complements the GNU General Public License, which
+ is a copyleft license designed for free software.</para>
+
+ <para>We have designed this License in order to use it for manuals
+ for free software, because free software needs free documentation:
+ a free program should come with manuals providing the same
+ freedoms that the software does. But this License is not limited
+ to software manuals; it can be used for any textual work,
+ regardless of subject matter or whether it is published as a
+ printed book. We recommend this License principally for works
+ whose purpose is instruction or reference.</para>
+ </sect1>
+
+ <sect1 id="gfdl-1">
+ <title>APPLICABILITY AND DEFINITIONS</title>
+
+ <para>This License applies to any manual or other work that
+ contains a notice placed by the copyright holder saying it can be
+ distributed under the terms of this License. The "Document",
+ below, refers to any such manual or work. Any member of the
+ public is a licensee, and is addressed as "you".</para>
+
+ <para>A "Modified Version" of the Document means any work
+ containing the Document or a portion of it, either copied
+ verbatim, or with modifications and/or translated into another
+ language.</para>
+
+ <para>A "Secondary Section" is a named appendix or a front-matter
+ section of the Document that deals exclusively with the
+ relationship of the publishers or authors of the Document to the
+ Document's overall subject (or to related matters) and contains
+ nothing that could fall directly within that overall subject.
+ (For example, if the Document is in part a textbook of
+ mathematics, a Secondary Section may not explain any mathematics.)
+ The relationship could be a matter of historical connection with
+ the subject or with related matters, or of legal, commercial,
+ philosophical, ethical or political position regarding
+ them.</para>
+
+ <para>The "Invariant Sections" are certain Secondary Sections
+ whose titles are designated, as being those of Invariant Sections,
+ in the notice that says that the Document is released under this
+ License.</para>
+
+ <para>The "Cover Texts" are certain short passages of text that
+ are listed, as Front-Cover Texts or Back-Cover Texts, in the
+ notice that says that the Document is released under this
+ License.</para>
+
+ <para>A "Transparent" copy of the Document means a
+ machine-readable copy, represented in a format whose specification
+ is available to the general public, whose contents can be viewed
+ and edited directly and straightforwardly with generic text
+ editors or (for images composed of pixels) generic paint programs
+ or (for drawings) some widely available drawing editor, and that
+ is suitable for input to text formatters or for automatic
+ translation to a variety of formats suitable for input to text
+ formatters. A copy made in an otherwise Transparent file format
+ whose markup has been designed to thwart or discourage subsequent
+ modification by readers is not Transparent. A copy that is not
+ "Transparent" is called "Opaque".</para>
+
+ <para>Examples of suitable formats for Transparent copies include
+ plain ASCII without markup, Texinfo input format, LaTeX input
+ format, SGML or XML using a publicly available DTD, and
+ standard-conforming simple HTML designed for human modification.
+ Opaque formats include PostScript, PDF, proprietary formats that
+ can be read and edited only by proprietary word processors, SGML
+ or XML for which the DTD and/or processing tools are not generally
+ available, and the machine-generated HTML produced by some word
+ processors for output purposes only.</para>
+
+ <para>The "Title Page" means, for a printed book, the title page
+ itself, plus such following pages as are needed to hold, legibly,
+ the material this License requires to appear in the title page.
+ For works in formats which do not have any title page as such,
+ "Title Page" means the text near the most prominent appearance of
+ the work's title, preceding the beginning of the body of the
+ text.</para>
+ </sect1>
+
+ <sect1 id="gfdl-2">
+ <title>VERBATIM COPYING</title>
+
+ <para>You may copy and distribute the Document in any medium,
+ either commercially or noncommercially, provided that this
+ License, the copyright notices, and the license notice saying this
+ License applies to the Document are reproduced in all copies, and
+ that you add no other conditions whatsoever to those of this
+ License. You may not use technical measures to obstruct or
+ control the reading or further copying of the copies you make or
+ distribute. However, you may accept compensation in exchange for
+ copies. If you distribute a large enough number of copies you
+ must also follow the conditions in section 3.</para>
+
+ <para>You may also lend copies, under the same conditions stated
+ above, and you may publicly display copies.</para>
+ </sect1>
+
+ <sect1 id="gfdl-3">
+ <title>COPYING IN QUANTITY</title>
+
+ <para>If you publish printed copies of the Document numbering more
+ than 100, and the Document's license notice requires Cover Texts,
+ you must enclose the copies in covers that carry, clearly and
+ legibly, all these Cover Texts: Front-Cover Texts on the front
+ cover, and Back-Cover Texts on the back cover. Both covers must
+ also clearly and legibly identify you as the publisher of these
+ copies. The front cover must present the full title with all
+ words of the title equally prominent and visible. You may add
+ other material on the covers in addition. Copying with changes
+ limited to the covers, as long as they preserve the title of the
+ Document and satisfy these conditions, can be treated as verbatim
+ copying in other respects.</para>
+
+ <para>If the required texts for either cover are too voluminous to
+ fit legibly, you should put the first ones listed (as many as fit
+ reasonably) on the actual cover, and continue the rest onto
+ adjacent pages.</para>
+
+ <para>If you publish or distribute Opaque copies of the Document
+ numbering more than 100, you must either include a
+ machine-readable Transparent copy along with each Opaque copy, or
+ state in or with each Opaque copy a publicly-accessible
+ computer-network location containing a complete Transparent copy
+ of the Document, free of added material, which the general
+ network-using public has access to download anonymously at no
+ charge using public-standard network protocols. If you use the
+ latter option, you must take reasonably prudent steps, when you
+ begin distribution of Opaque copies in quantity, to ensure that
+ this Transparent copy will remain thus accessible at the stated
+ location until at least one year after the last time you
+ distribute an Opaque copy (directly or through your agents or
+ retailers) of that edition to the public.</para>
+
+ <para>It is requested, but not required, that you contact the
+ authors of the Document well before redistributing any large
+ number of copies, to give them a chance to provide you with an
+ updated version of the Document.</para>
+ </sect1>
+
+ <sect1 id="gfdl-4">
+ <title>MODIFICATIONS</title>
+
+ <para>You may copy and distribute a Modified Version of the
+ Document under the conditions of sections 2 and 3 above, provided
+ that you release the Modified Version under precisely this
+ License, with the Modified Version filling the role of the
+ Document, thus licensing distribution and modification of the
+ Modified Version to whoever possesses a copy of it. In addition,
+ you must do these things in the Modified Version:</para>
+
+ <orderedlist numeration="upperalpha">
+ <listitem><para>Use in the Title Page
+ (and on the covers, if any) a title distinct from that of the
+ Document, and from those of previous versions (which should, if
+ there were any, be listed in the History section of the
+ Document). You may use the same title as a previous version if
+ the original publisher of that version gives permission.</para>
+ </listitem>
+
+ <listitem><para>List on the Title Page,
+ as authors, one or more persons or entities responsible for
+ authorship of the modifications in the Modified Version,
+ together with at least five of the principal authors of the
+ Document (all of its principal authors, if it has less than
+ five).</para>
+ </listitem>
+
+ <listitem><para>State on the Title page
+ the name of the publisher of the Modified Version, as the
+ publisher.</para>
+ </listitem>
+
+ <listitem><para>Preserve all the
+ copyright notices of the Document.</para>
+ </listitem>
+
+ <listitem><para>Add an appropriate
+ copyright notice for your modifications adjacent to the other
+ copyright notices.</para>
+ </listitem>
+
+ <listitem><para>Include, immediately
+ after the copyright notices, a license notice giving the public
+ permission to use the Modified Version under the terms of this
+ License, in the form shown in the Addendum below.</para>
+ </listitem>
+
+ <listitem><para>Preserve in that license
+ notice the full lists of Invariant Sections and required Cover
+ Texts given in the Document's license notice.</para>
+ </listitem>
+
+ <listitem><para>Include an unaltered
+ copy of this License.</para>
+ </listitem>
+
+ <listitem><para>Preserve the section
+ entitled "History", and its title, and add to it an item stating
+ at least the title, year, new authors, and publisher of the
+ Modified Version as given on the Title Page. If there is no
+ section entitled "History" in the Document, create one stating
+ the title, year, authors, and publisher of the Document as given
+ on its Title Page, then add an item describing the Modified
+ Version as stated in the previous sentence.</para>
+ </listitem>
+
+ <listitem><para>Preserve the network
+ location, if any, given in the Document for public access to a
+ Transparent copy of the Document, and likewise the network
+ locations given in the Document for previous versions it was
+ based on. These may be placed in the "History" section. You
+ may omit a network location for a work that was published at
+ least four years before the Document itself, or if the original
+ publisher of the version it refers to gives permission.</para>
+ </listitem>
+
+ <listitem><para>In any section entitled
+ "Acknowledgements" or "Dedications", preserve the section's
+ title, and preserve in the section all the substance and tone of
+ each of the contributor acknowledgements and/or dedications
+ given therein.</para>
+ </listitem>
+
+ <listitem><para>Preserve all the
+ Invariant Sections of the Document, unaltered in their text and
+ in their titles. Section numbers or the equivalent are not
+ considered part of the section titles.</para>
+ </listitem>
+
+ <listitem><para>Delete any section
+ entitled "Endorsements". Such a section may not be included in
+ the Modified Version.</para>
+ </listitem>
+
+ <listitem><para>Do not retitle any
+ existing section as "Endorsements" or to conflict in title with
+ any Invariant Section.</para>
+ </listitem>
+ </orderedlist>
+
+ <para>If the Modified Version includes new front-matter sections
+ or appendices that qualify as Secondary Sections and contain no
+ material copied from the Document, you may at your option
+ designate some or all of these sections as invariant. To do this,
+ add their titles to the list of Invariant Sections in the Modified
+ Version's license notice. These titles must be distinct from any
+ other section titles.</para>
+
+ <para>You may add a section entitled "Endorsements", provided it
+ contains nothing but endorsements of your Modified Version by
+ various parties--for example, statements of peer review or that
+ the text has been approved by an organization as the authoritative
+ definition of a standard.</para>
+
+ <para>You may add a passage of up to five words as a Front-Cover
+ Text, and a passage of up to 25 words as a Back-Cover Text, to the
+ end of the list of Cover Texts in the Modified Version. Only one
+ passage of Front-Cover Text and one of Back-Cover Text may be
+ added by (or through arrangements made by) any one entity. If the
+ Document already includes a cover text for the same cover,
+ previously added by you or by arrangement made by the same entity
+ you are acting on behalf of, you may not add another; but you may
+ replace the old one, on explicit permission from the previous
+ publisher that added the old one.</para>
+
+ <para>The author(s) and publisher(s) of the Document do not by
+ this License give permission to use their names for publicity for
+ or to assert or imply endorsement of any Modified Version.</para>
+ </sect1>
+
+ <sect1 id="gfdl-5">
+ <title>COMBINING DOCUMENTS</title>
+
+ <para>You may combine the Document with other documents released
+ under this License, under the terms defined in section 4 above for
+ modified versions, provided that you include in the combination
+ all of the Invariant Sections of all of the original documents,
+ unmodified, and list them all as Invariant Sections of your
+ combined work in its license notice.</para>
+
+ <para>The combined work need only contain one copy of this
+ License, and multiple identical Invariant Sections may be replaced
+ with a single copy. If there are multiple Invariant Sections with
+ the same name but different contents, make the title of each such
+ section unique by adding at the end of it, in parentheses, the
+ name of the original author or publisher of that section if known,
+ or else a unique number. Make the same adjustment to the section
+ titles in the list of Invariant Sections in the license notice of
+ the combined work.</para>
+
+ <para>In the combination, you must combine any sections entitled
+ "History" in the various original documents, forming one section
+ entitled "History"; likewise combine any sections entitled
+ "Acknowledgements", and any sections entitled "Dedications". You
+ must delete all sections entitled "Endorsements."</para>
+ </sect1>
+
+ <sect1 id="gfdl-6">
+ <title>COLLECTIONS OF DOCUMENTS</title>
+
+ <para>You may make a collection consisting of the Document and
+ other documents released under this License, and replace the
+ individual copies of this License in the various documents with a
+ single copy that is included in the collection, provided that you
+ follow the rules of this License for verbatim copying of each of
+ the documents in all other respects.</para>
+
+ <para>You may extract a single document from such a collection,
+ and distribute it individually under this License, provided you
+ insert a copy of this License into the extracted document, and
+ follow this License in all other respects regarding verbatim
+ copying of that document.</para>
+ </sect1>
+
+ <sect1 id="gfdl-7">
+ <title>AGGREGATION WITH INDEPENDENT WORKS</title>
+
+ <para>A compilation of the Document or its derivatives with other
+ separate and independent documents or works, in or on a volume of
+ a storage or distribution medium, does not as a whole count as a
+ Modified Version of the Document, provided no compilation
+ copyright is claimed for the compilation. Such a compilation is
+ called an "aggregate", and this License does not apply to the
+ other self-contained works thus compiled with the Document, on
+ account of their being thus compiled, if they are not themselves
+ derivative works of the Document.</para>
+
+ <para>If the Cover Text requirement of section 3 is applicable to
+ these copies of the Document, then if the Document is less than
+ one quarter of the entire aggregate, the Document's Cover Texts
+ may be placed on covers that surround only the Document within the
+ aggregate. Otherwise they must appear on covers around the whole
+ aggregate.</para>
+ </sect1>
+
+ <sect1 id="gfdl-8">
+ <title>TRANSLATION</title>
+
+ <para>Translation is considered a kind of modification, so you may
+ distribute translations of the Document under the terms of section
+ 4. Replacing Invariant Sections with translations requires
+ special permission from their copyright holders, but you may
+ include translations of some or all Invariant Sections in addition
+ to the original versions of these Invariant Sections. You may
+ include a translation of this License provided that you also
+ include the original English version of this License. In case of
+ a disagreement between the translation and the original English
+ version of this License, the original English version will
+ prevail.</para>
+ </sect1>
+
+ <sect1 id="gfdl-9">
+ <title>TERMINATION</title>
+
+ <para>You may not copy, modify, sublicense, or distribute the
+ Document except as expressly provided for under this License. Any
+ other attempt to copy, modify, sublicense or distribute the
+ Document is void, and will automatically terminate your rights
+ under this License. However, parties who have received copies, or
+ rights, from you under this License will not have their licenses
+ terminated so long as such parties remain in full
+ compliance.</para>
+ </sect1>
+
+ <sect1 id="gfdl-10">
+ <title>FUTURE REVISIONS OF THIS LICENSE</title>
+
+ <para>The Free Software Foundation may publish new, revised
+ versions of the GNU Free Documentation License from time to time.
+ Such new versions will be similar in spirit to the present
+ version, but may differ in detail to address new problems or
+ concerns. See <ulink
+ url="http://www.gnu.org/copyleft/">http://www.gnu.org/copyleft/</ulink>.</para>
+
+ <para>Each version of the License is given a distinguishing
+ version number. If the Document specifies that a particular
+ numbered version of this License "or any later version" applies to
+ it, you have the option of following the terms and conditions
+ either of that specified version or of any later version that has
+ been published (not as a draft) by the Free Software Foundation.
+ If the Document does not specify a version number of this License,
+ you may choose any version ever published (not as a draft) by the
+ Free Software Foundation.</para>
+ </sect1>
+
+ <sect1 id="gfdl-11">
+ <title>How to use this License for your documents</title>
+
+ <para>To use this License in a document you have written, include
+ a copy of the License in the document and put the following
+ copyright and license notices just after the title page:</para>
+
+<blockquote><para>
+ Copyright (c) YEAR YOUR NAME.
+ Permission is granted to copy, distribute and/or modify this document
+ under the terms of the GNU Free Documentation License, Version 1.1
+ or any later version published by the Free Software Foundation;
+ with the Invariant Sections being LIST THEIR TITLES, with the
+ Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
+ A copy of the license is included in the section entitled "GNU
+ Free Documentation License".
+</para></blockquote>
+
+ <para>If you have no Invariant Sections, write "with no Invariant
+ Sections" instead of saying which ones are invariant. If you have
+ no Front-Cover Texts, write "no Front-Cover Texts" instead of
+ "Front-Cover Texts being LIST"; likewise for Back-Cover
+ Texts.</para>
+
+ <para>If your document contains nontrivial examples of program
+ code, we recommend releasing these examples in parallel under your
+ choice of free software license, such as the GNU General Public
+ License, to permit their use in free software.</para>
+ </sect1>
+
+</appendix>
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:nil
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-parent-document: ("referenz.sgml" "appendix")
+sgml-exposed-tags:nil
+sgml-local-ecat-files:nil
+sgml-local-catalogs: CATALOG
+sgml-validate-command: "nsgmls -s referenz.sgml"
+ispell-skip-sgml: t
+End:
+-->
+</book>
diff --git a/Documentation/stylesheet-images/next.gif b/Documentation/stylesheet-images/next.gif
new file mode 100644
index 0000000..8c502e7
--- /dev/null
+++ b/Documentation/stylesheet-images/next.gif
Binary files differ
diff --git a/Documentation/stylesheet-images/note.gif b/Documentation/stylesheet-images/note.gif
new file mode 100644
index 0000000..7322e8e
--- /dev/null
+++ b/Documentation/stylesheet-images/note.gif
Binary files differ
diff --git a/Documentation/stylesheet-images/prev.gif b/Documentation/stylesheet-images/prev.gif
new file mode 100644
index 0000000..0894d9e
--- /dev/null
+++ b/Documentation/stylesheet-images/prev.gif
Binary files differ
diff --git a/Documentation/stylesheet-images/tip.gif b/Documentation/stylesheet-images/tip.gif
new file mode 100644
index 0000000..f062955
--- /dev/null
+++ b/Documentation/stylesheet-images/tip.gif
Binary files differ
diff --git a/Documentation/stylesheet-images/up.gif b/Documentation/stylesheet-images/up.gif
new file mode 100644
index 0000000..e899a27
--- /dev/null
+++ b/Documentation/stylesheet-images/up.gif
Binary files differ
diff --git a/FAQ b/FAQ
new file mode 100644
index 0000000..d0db17c
--- /dev/null
+++ b/FAQ
@@ -0,0 +1,74 @@
+This is the beginning of a FAQ for IPTraf-ng.
+---
+
+Q: Could you include support for <this-and-that> interface?
+
+A: Please read the README.interfaces file for what is needed for a new
+interface type to be supported.
+
+Q: I try to start IPTraf-ng but it tells me that <facility> is already active
+in another process. But I'm sure IPTraf-ng isn't running at the time!
+
+A: Probably due to a faulty installation or abnormal termination. If
+you're sure you've installed the software properly, you may have stale
+lock files from a previous abort. Just issue the iptraf-ng command with the
+-f parameter (iptraf-ng -f). This will override stale locks and IPTraf-ng
+should proceed normally.
+
+Q: I want to configure IPTraf-ng but it tells me only the first instance can
+configure.
+
+A: Similar to the previous question. Issue the iptraf-ng command with the -f
+parameter.
+
+Q: Is there a way to make IPTraf-ng run in the background and collect
+statistics to a log file?
+
+A: Use the -B command-line parameter to force IPTraf-ng to dump all
+its screen output into oblivion and move into the background. See the
+manual for details on background operation.
+
+Q: I'm getting a "cannot allocate memory" error but I've got loads of
+memory available.
+
+A: The "cannot allocate memory" error is a reponse to the "segmentation
+fault" condition (SIGSEGV). If you're sure it's not a memory condition on
+your machine, please report it to me, and if possible, include a gdb trace
+or strace output to help me debug.
+
+Q: Is there Web/HTTP/HTML/whatever version available?
+
+A: I've received several requests for this one. Perhaps in time, I've
+been caught up in some work and some personal stuff. Suggestions on
+implementation of such a feature are welcome. (Addition: I hope to get
+this incorporated into the next major release. Who knows? If I have the
+time, I might be able to WAP it in the near future :))
+
+Q: It would be great if the statistics could be sorted.
+
+A: Sorting is now available with the IP traffic monitor, TCP/UDP statistical
+breakdown, and LAN station monitor. Sorting is invoked by pressing the
+S key and selecting a sort criterion.
+
+Q: I want to run IPTraf-ng from a Secure Shell terminal but the output of the
+program causes a heavy load on the network. What should I do?
+
+A: The output of the program is returned over the network, which in turn
+tells IPTraf-ng about the new traffic, which IPTraf-ng then outputs, which is
+then sent over the network... in other words, it's a feedback effect. The
+solution to this is to set the screen update interval to 1 second or more.
+To do that, go to Configuration... then select Timers... then Screen
+update interval... and enter the interval value in seconds. One second
+should be fine.
+
+Q: Does IPTraf-ng run on FreeBSD?
+
+A: I wish it did. IPTraf-ng was designed from the ground up to use the Linux
+PF_PACKET mechanism, not libpcap. The main reasons for doing this are
+less overhead and more control over the captured packets. Since Linux
+kernel 2.2, the raw socket API featured more goodies, like the direction
+of the packets.
+
+I hope to be able to successfully port to FreeBSD, but I do not have the
+resources to do so now.
+
diff --git a/GEN-VERSION-FILE b/GEN-VERSION-FILE
new file mode 100755
index 0000000..9a8a22d
--- /dev/null
+++ b/GEN-VERSION-FILE
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+GVF=VERSION-FILE
+DEF_VER=1.2.0
+LF='
+'
+
+if test -d .git -o -f .git &&
+ VN=$(git describe --tags --match '[0-9]*' --match 'v[0-9]*' --abbrev=4 HEAD 2>/dev/null) &&
+ case "$VN" in
+ *$LF*) (exit 1) ;;
+ [0-9]*)
+ git update-index -q --refresh
+ test -z "$(git diff-index --name-only HEAD --)" || VN="$VN-dirty"
+ esac
+then
+ VN=$(echo "$VN" | sed -e 's/-/./g');
+else
+ VN="$DEF_VER"
+fi
+
+# strip "v" prefix
+VN=$(expr "$VN" : v*'\(.*\)')
+
+if test -r $GVF
+then
+ VC=$(sed -e 's/^IPTRAF_VERSION = //' <$GVF)
+else
+ VC=unset
+fi
+test "$VN" = "$VC" || {
+ echo >&2 "IPTRAF_VERSION = $VN"
+ echo "IPTRAF_VERSION = $VN" >$GVF
+}
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..ad1dd52
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,20 @@
+Basic Installation
+==================
+
+Each supported distribution provides an installable version if iptraf-ng.
+Follow the distribution's practices for installing new software.
+
+Building from source:
+
+iptraf-ng uses the usual gcc based build environment. It also uses ncurses
+so that must be installed as well.
+
+This was built on an x86_64 running Fedora-23 which includes gcc 5.3.1
+
+$ git clone https://github.com/iptraf-ng/iptraf-ng
+$ cd iptraf-ng
+$ make
+
+To run:
+$ sudo ./iptraf-ng
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..21fdd9c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,341 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..a1fd3d2
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,446 @@
+# The default target of this Makefile is this
+all::
+
+# Define V=1 to have a more verbose compile.
+#
+# Define NO_PANEL if you don't want to use -lpanel.
+#
+# Define NEEDS_NCURSES5 if you need linking with ncurses5.
+#
+# Define NEEDS_NCURSESW5 if you need linking with ncursesw5.
+#
+# Define NEEDS_NCURSES6 if you need linking with ncurses6.
+#
+# Define NEEDS_NCURSESW6 if you need linking with ncursesw6.
+
+
+VERSION-FILE: FORCE
+ @$(SHELL_PATH) ./GEN-VERSION-FILE
+-include VERSION-FILE
+
+CFLAGS = -g -O2 -Wall -W -std=gnu99 -Werror=format-security -D_GNU_SOURCE
+LDFLAGS =
+ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS)
+ALL_LDFLAGS = $(LDFLAGS)
+STRIP ?= strip
+
+prefix = $(HOME)
+sbindir_relative = sbin
+sbindir = $(prefix)/$(sbindir_relative)
+mandir = $(prefix)/share/man
+sharedir = $(prefix)/share
+localedir = $(sharedir)/locale
+lib = lib
+man8dir = $(mandir)/man8
+
+# DESTDIR=
+pathsep = :
+
+export prefix bindir sharedir sysconfdir gitwebdir localedir
+
+CC = cc
+RM = rm -f
+INSTALL = install
+RPMBUILD = rpmbuild
+TAR = tar
+
+### --- END CONFIGURATION SECTION ---
+
+
+# Those must not be GNU-specific; they are shared with perl/ which may
+# be built by a different compiler. (Note that this is an artifact now
+# but it still might be nice to keep that distinction.)
+BASIC_CFLAGS = -I. -Isrc/
+BASIC_LDFLAGS =
+
+# Guard against environment variables
+iptraf-h :=
+iptraf-o :=
+
+ALL_PROGRAMS := iptraf-ng
+
+ifndef SHELL_PATH
+ SHELL_PATH = /bin/sh
+endif
+
+iptraf-h += src/tui/input.h
+iptraf-h += src/tui/labels.h
+iptraf-h += src/tui/listbox.h
+iptraf-h += src/tui/menurt.h
+iptraf-h += src/tui/msgboxes.h
+iptraf-h += src/tui/winops.h
+iptraf-h += src/iptraf-ng-compat.h
+iptraf-h += src/parse-options.h
+iptraf-h += src/packet.h
+iptraf-h += src/tcptable.h
+iptraf-h += src/othptab.h
+iptraf-h += src/ifstats.h
+iptraf-h += src/deskman.h
+iptraf-h += src/hostmon.h
+iptraf-h += src/fltedit.h
+iptraf-h += src/cidr.h
+iptraf-h += src/fltselect.h
+iptraf-h += src/ipfilter.h
+iptraf-h += src/fltmgr.h
+iptraf-h += src/ipfrag.h
+iptraf-h += src/serv.h
+iptraf-h += src/servname.h
+iptraf-h += src/timer.h
+iptraf-h += src/ifaces.h
+iptraf-h += src/error.h
+iptraf-h += src/revname.h
+iptraf-h += src/log.h
+iptraf-h += src/pktsize.h
+iptraf-h += src/landesc.h
+iptraf-h += src/dirs.h
+iptraf-h += src/getpath.h
+iptraf-h += src/options.h
+iptraf-h += src/promisc.h
+iptraf-h += src/parseproto.h
+iptraf-h += src/addproto.h
+iptraf-h += src/arphdr.h
+iptraf-h += src/attrs.h
+iptraf-h += src/fltdefs.h
+iptraf-h += src/logvars.h
+iptraf-h += src/list.h
+iptraf-h += src/counters.h
+iptraf-h += src/rate.h
+iptraf-h += src/built-in.h
+iptraf-h += src/sockaddr.h
+iptraf-h += src/capt.h
+iptraf-h += src/capt-recvmsg.h
+iptraf-h += src/capt-recvmmsg.h
+iptraf-h += src/capt-mmap-v2.h
+iptraf-h += src/capt-mmap-v3.h
+
+iptraf-o += src/tui/input.o
+iptraf-o += src/tui/labels.o
+iptraf-o += src/tui/listbox.o
+iptraf-o += src/tui/menurt.o
+iptraf-o += src/tui/msgboxes.o
+iptraf-o += src/tui/winops.o
+iptraf-o += src/error.o
+iptraf-o += src/log.o
+iptraf-o += src/getpath.o
+iptraf-o += src/parseproto.o
+iptraf-o += src/fltselect.o
+iptraf-o += src/ipfilter.o
+iptraf-o += src/fltmgr.o
+iptraf-o += src/ipfrag.o
+iptraf-o += src/serv.o
+iptraf-o += src/servname.o
+iptraf-o += src/timer.o
+iptraf-o += src/revname.o
+iptraf-o += src/pktsize.o
+iptraf-o += src/landesc.o
+iptraf-o += src/options.o
+iptraf-o += src/promisc.o
+iptraf-o += src/ifaces.o
+iptraf-o += src/usage.o
+iptraf-o += src/iptraf.o
+iptraf-o += src/itrafmon.o
+iptraf-o += src/wrapper.o
+iptraf-o += src/parse-options.o
+iptraf-o += src/packet.o
+iptraf-o += src/tcptable.o
+iptraf-o += src/othptab.o
+iptraf-o += src/ifstats.o
+iptraf-o += src/detstats.o
+iptraf-o += src/deskman.o
+iptraf-o += src/hostmon.o
+iptraf-o += src/fltedit.o
+iptraf-o += src/cidr.o
+iptraf-o += src/counters.o
+iptraf-o += src/rate.o
+iptraf-o += src/capture-pkt.o
+iptraf-o += src/sockaddr.o
+iptraf-o += src/capt.o
+iptraf-o += src/capt-recvmsg.o
+iptraf-o += src/capt-recvmmsg.o
+iptraf-o += src/capt-mmap-v2.o
+iptraf-o += src/capt-mmap-v3.o
+iptraf-o += src/rvnamed.o
+
+ifndef sysconfdir
+ifeq ($(prefix),/usr)
+sysconfdir = /etc
+else
+sysconfdir = etc
+endif
+endif
+
+ifdef CHECK_HEADER_DEPENDENCIES
+COMPUTE_HEADER_DEPENDENCIES = no
+USE_COMPUTED_HEADER_DEPENDENCIES =
+endif
+
+ifndef COMPUTE_HEADER_DEPENDENCIES
+COMPUTE_HEADER_DEPENDENCIES = auto
+endif
+
+ifeq ($(COMPUTE_HEADER_DEPENDENCIES),auto)
+dep_check = $(shell $(CC) $(ALL_CFLAGS) \
+ -c -MF /dev/null -MMD -MP -x c /dev/null -o /dev/null 2>&1; \
+ echo $$?)
+ifeq ($(dep_check),0)
+override COMPUTE_HEADER_DEPENDENCIES = yes
+else
+override COMPUTE_HEADER_DEPENDENCIES = no
+endif
+endif
+
+ifeq ($(COMPUTE_HEADER_DEPENDENCIES),yes)
+USE_COMPUTED_HEADER_DEPENDENCIES = YesPlease
+else
+ifneq ($(COMPUTE_HEADER_DEPENDENCIES),no)
+$(error please set COMPUTE_HEADER_DEPENDENCIES to yes, no, or auto \
+(not "$(COMPUTE_HEADER_DEPENDENCIES)"))
+endif
+endif
+
+ifndef NCURSES_LDFLAGS
+ifdef NEEDS_NCURSES5
+ NCURSES_CFLAGS := $(shell ncurses5-config --cflags 2>/dev/null)
+ NCURSES_LDFLAGS := $(shell ncurses5-config --libs 2>/dev/null)
+ ifndef NO_PANEL
+ NCURSES_LDFLAGS += -lpanel
+ endif
+endif
+endif
+
+ifndef NCURSES_LDFLAGS
+ifdef NEEDS_NCURSESW5
+ NCURSES_CFLAGS := $(shell ncursesw5-config --cflags 2>/dev/null)
+ NCURSES_LDFLAGS := $(shell ncursesw5-config --libs 2>/dev/null)
+ ifndef NO_PANEL
+ NCURSES_LDFLAGS += -lpanelw
+ endif
+endif
+endif
+
+ifndef NCURSES_LDFLAGS
+ifdef NEEDS_NCURSES6
+ NCURSES_CFLAGS := $(shell ncurses6-config --cflags 2>/dev/null)
+ NCURSES_LDFLAGS := $(shell ncurses6-config --libs 2>/dev/null)
+ ifndef NO_PANEL
+ NCURSES_LDFLAGS += -lpanel
+ endif
+endif
+endif
+
+ifndef NCURSES_LDFLAGS
+ifdef NEEDS_NCURSESW6
+ NCURSES_CFLAGS := $(shell ncursesw6-config --cflags 2>/dev/null)
+ NCURSES_LDFLAGS := $(shell ncursesw6-config --libs 2>/dev/null)
+ ifndef NO_PANEL
+ NCURSES_LDFLAGS += -lpanelw
+ endif
+endif
+endif
+
+# try find ncuses by autodetect
+ifndef NCURSES_LDFLAGS
+ ifneq ($(shell ncursesw6-config --libs 2>/dev/null),)
+ NCURSES_CFLAGS := $(shell ncursesw6-config --cflags 2>/dev/null)
+ NCURSES_LDFLAGS := $(shell ncursesw6-config --libs 2>/dev/null)
+ ifndef NO_PANEL
+ NCURSES_LDFLAGS += -lpanelw
+ endif
+ else ifneq ($(shell ncurses6-config --libs 2>/dev/null),)
+ NCURSES_CFLAGS := $(shell ncurses6-config --cflags 2>/dev/null)
+ NCURSES_LDFLAGS := $(shell ncurses6-config --libs 2>/dev/null)
+ ifndef NO_PANEL
+ NCURSES_LDFLAGS += -lpanel
+ endif
+ else ifneq ($(shell ncursesw5-config --libs 2>/dev/null),)
+ NCURSES_CFLAGS := $(shell ncursesw5-config --cflags 2>/dev/null)
+ NCURSES_LDFLAGS := $(shell ncursesw5-config --libs 2>/dev/null)
+ ifndef NO_PANEL
+ NCURSES_LDFLAGS += -lpanelw
+ endif
+ else ifneq ($(shell ncurses5-config --libs 2>/dev/null),)
+ NCURSES_CFLAGS := $(shell ncurses5-config --cflags 2>/dev/null)
+ NCURSES_LDFLAGS := $(shell ncurses5-config --libs 2>/dev/null)
+ ifndef NO_PANEL
+ NCURSES_LDFLAGS += -lpanel
+ endif
+ endif
+endif
+
+QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
+QUIET_SUBDIR1 =
+
+ifneq ($(findstring $(MAKEFLAGS),w),w)
+PRINT_DIR = --no-print-directory
+else # "make -w"
+NO_SUBDIR = :
+endif
+
+ifneq ($(findstring $(MAKEFLAGS),s),s)
+ifndef V
+ QUIET_CC = @echo ' ' CC $@;
+ QUIET_LINK = @echo ' ' LINK $@;
+ QUIET_GEN = @echo ' ' GEN $@;
+ QUIET_SUBDIR0 = +@subdir=
+ QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
+ $(MAKE) $(PRINT_DIR) -C $$subdir
+ export V
+ export QUIET_GEN
+ export QUIET_BUILT_IN
+endif
+endif
+
+
+DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
+sbindir_SQ = $(subst ','\'',$(sbindir))
+
+ALL_CFLAGS += $(BASIC_CFLAGS)
+ALL_LDFLAGS += $(BASIC_LDFLAGS)
+
+export TAR INSTALL DESTDIR SHELL_PATH
+
+### Build rules
+
+SHELL = $(SHELL_PATH)
+
+#all:: shell_compatibility_test
+#please_set_SHELL_PATH_to_a_more_modern_shell:
+# @$$(:)
+#shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
+
+
+all:: $(ALL_PROGRAMS)
+
+iptraf-ng: $(iptraf-o)
+ $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ \
+ $(iptraf-o) $(ALL_LDFLAGS) $(NCURSES_LDFLAGS)
+
+src/deskman.o src/iptraf.o: VERSION-FILE
+src/deskman.o src/iptraf.o src/capture-pkt.o: EXTRA_CPPFLAGS = \
+ -DIPTRAF_VERSION='"$(IPTRAF_VERSION)"' \
+ -DIPTRAF_NAME='"iptraf-ng"'
+
+OBJECTS := $(sort $(iptraf-o))
+
+dep_files := $(foreach f,$(OBJECTS),$(dir $f).depend/$(notdir $f).d)
+dep_dirs := $(addsuffix .depend,$(sort $(dir $(OBJECTS))))
+
+ifeq ($(COMPUTE_HEADER_DEPENDENCIES),yes)
+$(dep_dirs):
+ @mkdir -p $@
+
+missing_dep_dirs := $(filter-out $(wildcard $(dep_dirs)),$(dep_dirs))
+dep_file = $(dir $@).depend/$(notdir $@).d
+dep_args = -MF $(dep_file) -MMD -MP
+ifdef CHECK_HEADER_DEPENDENCIES
+$(error cannot compute header dependencies outside a normal build. \
+Please unset CHECK_HEADER_DEPENDENCIES and try again)
+endif
+endif
+
+.SUFFIXES:
+
+ifdef PRINT_HEADER_DEPENDENCIES
+$(OBJECTS): %.o: %.c FORCE
+ echo $^
+
+ifndef CHECK_HEADER_DEPENDENCIES
+$(error cannot print header dependencies during a normal build. \
+Please set CHECK_HEADER_DEPENDENCIES and try again)
+endif
+endif
+
+ifndef PRINT_HEADER_DEPENDENCIES
+ifdef CHECK_HEADER_DEPENDENCIES
+$(OBJECTS): %.o: %.c $(dep_files) FORCE
+ @set -e; echo CHECK $@; \
+ missing_deps="$(missing_deps)"; \
+ if test "$$missing_deps"; \
+ then \
+ echo missing dependencies: $$missing_deps; \
+ false; \
+ fi
+endif
+endif
+
+ifndef CHECK_HEADER_DEPENDENCIES
+$(OBJECTS): %.o: %.c $(missing_dep_dirs)
+ $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(NCURSES_CFLAGS) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
+endif
+
+ifdef USE_COMPUTED_HEADER_DEPENDENCIES
+# Take advantage of gcc's on-the-fly dependency generation
+# See <http://gcc.gnu.org/gcc-3.0/features.html>.
+dep_files_present := $(wildcard $(dep_files))
+ifneq ($(dep_files_present),)
+include $(dep_files_present)
+endif
+else
+# Dependencies on header files, for platforms that do not support
+# the gcc -MMD option.
+#
+# Dependencies on automatically generated headers such as common-cmds.h
+# should _not_ be included here, since they are necessary even when
+# building an object for the first time.
+#
+# XXX. Please check occasionally that these include all dependencies
+# gcc detects!
+
+$(OBJECTS): $(iptraf-h)
+endif
+
+
+### Maintainer's dist rules
+
+IPTRAF_TARNAME = iptraf-ng-$(IPTRAF_VERSION)
+dist:
+ @mkdir -p $(IPTRAF_TARNAME)
+ @cp --parents `git ls-files` $(IPTRAF_TARNAME)
+ $(TAR) cf $(IPTRAF_TARNAME).tar $(IPTRAF_TARNAME)
+ @$(RM) -rf $(IPTRAF_TARNAME)
+ gzip -f -9 $(IPTRAF_TARNAME).tar
+
+### Documentation rules
+html: Documentation/book1.html
+pdf: Documentation/manual.pdf
+
+Documentation/book1.html: Documentation/manual.sgml
+ cd Documentation && docbook2html manual.sgml
+
+Documentation/manual.pdf: Documentation/manual.sgml
+ cd Documentation && docbook2pdf manual.sgml
+
+Documentation/manual.sgml: Documentation/manual.sgml.in VERSION-FILE
+ cat $< | sed \
+ -e s/@@version@@/`echo $(IPTRAF_VERSION) | cut -d. -f1-3`/ \
+ -e s/@@major@@/`echo $(IPTRAF_VERSION) | cut -d. -f1-2`/ \
+ > $@
+
+## TODO: use asciidoc to generate mans
+
+### Installation rules
+install: all
+ @echo $(DESTDIR_SQ)$(man8dir)
+ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sbindir_SQ)'
+ $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(sbindir_SQ)'
+ $(INSTALL) -d -m 755 $(DESTDIR)$(man8dir)
+ $(INSTALL) -m 644 src/iptraf-ng.8 $(DESTDIR)$(man8dir)
+
+### Cleaning rules
+
+distclean: clean
+
+clean:
+ $(RM) Documentation/manual.sgml
+ $(RM) Documentation/manual.pdf
+ $(RM) Documentation/*.html
+ $(RM) $(iptraf-o)
+ $(RM) $(ALL_PROGRAMS)
+ $(RM) -r $(dep_dirs)
+ $(RM) $(IPTRAF_TARNAME).tar.gz
+ $(RM) VERSION-FILE
+
+gtags:
+ $(QUIET_GEN) gtags
+
+.PHONY: clean distclean all install html pdf gtags FORCE
diff --git a/README b/README
new file mode 100644
index 0000000..9200a96
--- /dev/null
+++ b/README
@@ -0,0 +1,81 @@
+==========================================================================
+IPTraf-ng README
+--------------------------------------------------------------------------
+See the CHANGES file for the history of changes.
+See the INSTALL file for installation instructions.
+--------------------------------------------------------------------------
+
+DESCRIPTION
+-----------
+
+IPTraf-ng is a console-based network monitoring program for Linux that
+displays information about IP traffic. It returns such information as:
+
+ Current TCP connections
+ UDP, ICMP, OSPF, and other types of IP packets
+ Packet and byte counts on TCP connections
+ IP, TCP, UDP, ICMP, non-IP, and other packet and byte counts
+ TCP/UDP counts by ports
+ Packet counts by packet sizes
+ Packet and byte counts by IP address
+ Interface activity
+ Flag statuses on TCP packets
+ LAN station statistics
+
+This program can be used to determine the type of traffic on your network,
+and what kind of service is the most heavily used on what machines, among
+others.
+
+IPTraf-ng works on Ethernet, FDDI, PLIP, loopback, and SLIP/PPP
+interfaces. Also supports GRE-over-IP tunnels, 802.1ad and QinQ VLAN,
+and SIT tunnels.
+
+Updates and announcements are at the iptraf-ng@lists.fedorahosted.org,
+see README.contact for more information.
+
+IMPORTANT CHANGES
+-----------------
+
+Important changes are detailed in the CHANGES file, please take some
+time to read it. There are some changes in the log file names, and
+the policies on multiple instances have been somewhat relaxed.
+
+DISTRIBUTION NOTICE
+-------------------
+
+This is the general release of IPTraf-ng. IPTraf-ng has been incorporated into
+the Fedora, RHEL-7.0, Centos-7.0, Ubuntu, Debian GNU/Linux, Turbolinux and S.u.S.E.
+distributions, as well as the Trinux security toolkit distribution.
+
+Linux distributions may have tailored the IPTraf-ng package to suit their
+purposes. Send direct questions, comments or inquiries about a
+distribution-specific package to its maintainer.
+
+SYSTEM REQUIREMENTS
+-------------------
+
+IPTraf-ng 1.1.x and later requires at least Linux kernel 2.2. It uses the new
+PF_PACKET socket family as its capture mechanism. This feature is new to
+the 2.2 kernel. Make sure you have the Packet Socket driver compiled in or
+installed as a module, or IPTraf-ng will fail (and so will others like it:
+tcpdump, netwatch, etc).
+
+IPTraf-ng also requires glibc 2.1 or later.
+
+COPYING AND DISTRIBUTION
+------------------------
+
+This software is OSI Certified Open Source Software
+OSI Certified is a certification mark of the Open Source Initiative.
+
+Redistribution and modification of this software is permitted under the
+terms of the GNU General Public License V2. See the included LICENSE file
+for details.
+
+FOR FURTHER INFORMATION
+-----------------------
+
+Full information is in the manual in the Documentation directory. See
+also the CHANGES file for a record of fixes and new features. Updates and
+announcements are in the IPTraf-ng Web page indicated above. Other README
+files contain some other bits of information.
diff --git a/README.contact b/README.contact
new file mode 100644
index 0000000..19ea57a
--- /dev/null
+++ b/README.contact
@@ -0,0 +1,16 @@
+============================================================================
+CONTACT INFORMATION
+----------------------------------------------------------------------------
+
+==================
+Individual Contact
+~~~~~~~~~~~~~~~~~~
+ IPTraf was written and primarily maintained by Gerard Paul Java
+(riker@seul.org). Fork to IPTraf-ng was made by Nikola Pajkovsky(npajkovs@redhat.com).
+Current maintainer is Philip Cameron(pcameron@redhat.com)
+
+===============
+Web information
+~~~~~~~~~~~~~~~
+IPTraf-ng sites are https://github.com/iptraf-ng/iptraf-ng/
+
diff --git a/README.indent b/README.indent
new file mode 100644
index 0000000..44272eb
--- /dev/null
+++ b/README.indent
@@ -0,0 +1,19 @@
+Sources are indented using the GNU indent program with the following
+arguments:
+
+--k-and-r-style
+--indent-level8
+--blank-lines-after-declarations
+--blank-lines-after-procedures
+--braces-on-if-line
+--cuddle-else
+--space-special-semicolon
+--no-space-after-function-call-names
+--no-blank-before-sizeof
+--no-space-after-parentheses
+--continue-at-parentheses
+--line-length80
+--comment-line-length80
+--honour-newlines
+--case-indentation0
+--break-before-boolean-operator
diff --git a/README.interfaces b/README.interfaces
new file mode 100644
index 0000000..e6562ac
--- /dev/null
+++ b/README.interfaces
@@ -0,0 +1,58 @@
+============================================================================
+Supported Interface Information (Needs update)
+as of version 2.8, July 2002
+----------------------------------------------------------------------------
+
+IPTraf has been slowly improving with its interface support since its
+first release. IPTraf currently supports the following types of links:
+
+Local loopback
+Ethernet (10 and 100 Mbps)
+SLIP and variants
+Asynchronous PPP over analog telephone lines
+FDDI (now includes Ethernet-emulating interfces)
+Frame Relay FRAD/DLCI interfaces (new as of IPTraf 2.5.0)
+PLIP (Parallel Line IP)
+DVB satellite-receive interfaces
+SBNI long-range modem interfaces
+Wireless LAN interfaces
+Free s/WAN logical interfaces
+IPsec logical interfaces
+Some tunnelling interfaces
+Some bridging interfaces
+- add 802.1ad and QinQ VLAN handling
+- SIT tunnels support
+- support GRE-over-IP tunnels
+
+ADDITIONAL INTERFACE SUPPORT
+
+As much as I would like to support every concievable interface in
+existence, we know that's just not possible. I myself do not have a lot
+of interface types. However, that does not mean I'm unwilling to support
+more.
+
+So here's the deal. If you'd like me to include support for a new type of
+interface I will need this information as much as possible:
+
+* Resulting link type in spkt_family after a recvfrom() on a (PF_PACKET,
+ SOCK_RAW) socket (ARPHRD_ETHER, ARPHRD_PPP, etc).
+* Standard interface name for the type of network medium (eth0, eth1,
+ ppp0, etc) after the recvfrom() mentioned above.
+* Packet structure. How many bytes are there in its data-link header
+ (with Ethernet, there are 14, with FDDI, 21) as returned by recvfrom on
+ a (PF_PACKET, SOCK_RAW) socket?
+* Pointers to other sources of information if possible.
+
+Then finally, if you come up with a request for support for a new
+interface, I'd really like an offer to have it tested, obviously, since I
+do not have the interface myself If I do not receive an offer to test, then
+support cannot be included.
+
+Patches, even quick-and-dirty ones, are very much welcome.
+
+All information and patches will be fully credited in the CHANGES file.
+
+Looking forward to serving you.
+
+-- Gerard <riker@seul.org>
+-- Phil <pcameron@redhat.com>
diff --git a/README.resolving b/README.resolving
new file mode 100644
index 0000000..c1e4820
--- /dev/null
+++ b/README.resolving
@@ -0,0 +1,51 @@
+============================================================================
+README DOCUMENT FOR ASYNCHRONOUS REVERSE NAME RESOLVING
+----------------------------------------------------------------------------
+
+DESCRIPTION
+-----------
+
+IPTraf-ng incorporates a function to resolve IP addresses to host names
+in the background, keeping IPTraf-ng from waiting until the lookup is
+completed.
+
+If Reverse Lookup is enabled in the Options menu, the IP Traffic Monitor
+will fork another process and this process will attempt to resolve
+addresses.
+
+When the traffic monitor is done, IPTraf-ng tells this resolving process
+to quit.
+
+
+PROTOCOL
+--------
+
+Resolving process and IPTraf-ng communicate with each other with the UNIX
+domain socket IPC facility. They use datagram sockets.
+
+The communication protocol recognizes only 4 types of messages:
+
+RVN_HELLO the Hello packet. This simply causes to throw it back,
+ telling it is active.
+
+RVN_REQUEST a reverse lookup request. This message includes an IP address
+ to resolve. Upon receive of this request, resolving process
+ checks its internal cache to see if this IP address is
+ already resolved or being resolved. If it isn't in the cache
+ yet, it forks off a copy which resolves in the background,
+ while it returns the IP address in the meantime. Subsequent
+ requests will get the IP address until such time that the
+ child has completed the resolution, at which time, a request
+ will get the host name in reply.
+
+RVN_REPLY resolving process marks reply packets with this tag. Reply
+ packets contain the resolved host name or the ASCII
+ representation of the IP address, and an indicator of the
+ state of the resolution for this address (NOTRESOLVED,
+ RESOLVING or RESOLVED).
+
+RVN_QUIT Tells resolving process to terminate.
+
+The datagram structure and #define's are found in the rvnamed.h header file.
+
+Important rvnamed messages are written to /var/log/iptraf-ng/rvnamed.log.
diff --git a/iptraf-ng-logrotate.conf b/iptraf-ng-logrotate.conf
new file mode 100644
index 0000000..895ebe3
--- /dev/null
+++ b/iptraf-ng-logrotate.conf
@@ -0,0 +1,9 @@
+# Logrotate file for iptraf
+/var/log/iptraf/*.log {
+ compress
+ delaycompress
+ missingok
+ notifempty
+ rotate 4
+ create 0600 root root
+}
diff --git a/src/addproto.h b/src/addproto.h
new file mode 100644
index 0000000..9f2cb22
--- /dev/null
+++ b/src/addproto.h
@@ -0,0 +1,28 @@
+#ifndef IPTRAF_NG_ADDPROTO_H
+#define IPTRAF_NG_ADDPROTO_H
+
+#ifndef IPPROTO_IGP
+#define IPPROTO_IGP 9
+#endif
+
+#ifndef IPPROTO_IGRP
+#define IPPROTO_IGRP 88
+#endif
+
+#ifndef IPPROTO_OSPFIGP
+#define IPPROTO_OSPFIGP 89
+#endif
+
+#ifndef IPPROTO_GRE
+#define IPPROTO_GRE 47
+#endif
+
+#ifndef IPPROTO_IPSEC_AH
+#define IPPROTO_IPSEC_AH 51
+#endif
+
+#ifndef IPPROTO_IPSEC_ESP
+#define IPPROTO_IPSEC_ESP 50
+#endif
+
+#endif /* IPTRAF_NG_ADDPROTO_H */
diff --git a/src/arphdr.h b/src/arphdr.h
new file mode 100644
index 0000000..762a5be
--- /dev/null
+++ b/src/arphdr.h
@@ -0,0 +1,24 @@
+#ifndef IPTRAF_NG_ARPHDR_H
+#define IPTRAF_NG_ARPHDR_H
+
+/*
+ * arp header format, stolen from the Linux include files.
+ */
+
+struct arp_hdr {
+ unsigned short ar_hrd; /* format of hardware address */
+ unsigned short ar_pro; /* format of protocol address */
+ unsigned char ar_hln; /* length of hardware address */
+ unsigned char ar_pln; /* length of protocol address */
+ unsigned short ar_op; /* ARP opcode (command) */
+
+ /*
+ * Ethernet looks like this : This bit is variable sized however...
+ */
+ unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
+ unsigned char ar_sip[4]; /* sender IP address */
+ unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
+ unsigned char ar_tip[4]; /* target IP address */
+};
+
+#endif /* IPTRAF_NG_ARPHDR_H */
diff --git a/src/attrs.h b/src/attrs.h
new file mode 100644
index 0000000..d963550
--- /dev/null
+++ b/src/attrs.h
@@ -0,0 +1,38 @@
+#ifndef IPTRAF_NG_ATTRS_H
+#define IPTRAF_NG_ATTRS_H
+
+/* Attribute variables */
+
+extern int STDATTR;
+extern int HIGHATTR;
+extern int BOXATTR;
+extern int ACTIVEATTR;
+extern int BARSTDATTR;
+extern int BARHIGHATTR;
+extern int BARPTRATTR;
+extern int DLGTEXTATTR;
+extern int DLGHIGHATTR;
+extern int DLGBOXATTR;
+extern int DESCATTR;
+extern int STATUSBARATTR;
+extern int IPSTATATTR;
+extern int IPSTATLABELATTR;
+extern int DESKTEXTATTR;
+extern int PTRATTR;
+extern int FIELDATTR;
+extern int ERRBOXATTR;
+extern int ERRTXTATTR;
+extern int ERRRESPATTR;
+extern int OSPFATTR;
+extern int UDPATTR;
+extern int IGPATTR;
+extern int IGMPATTR;
+extern int IGRPATTR;
+extern int ARPATTR;
+extern int GREATTR;
+extern int UNKNIPATTR;
+extern int UNKNATTR;
+extern int IPV6ATTR;
+extern int ICMPV6ATTR;
+
+#endif /* IPTRAF_NG_ATTRS_H */
diff --git a/src/built-in.h b/src/built-in.h
new file mode 100644
index 0000000..659311d
--- /dev/null
+++ b/src/built-in.h
@@ -0,0 +1,9 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+#ifndef IPTRAF_NG_BUILT_IN_H
+#define IPTRAF_NG_BUILT_IN_H
+
+int cmd_capture(int argc, char **argv);
+
+#endif
diff --git a/src/capt-mmap-v2.c b/src/capt-mmap-v2.c
new file mode 100644
index 0000000..19757cb
--- /dev/null
+++ b/src/capt-mmap-v2.c
@@ -0,0 +1,154 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+#include "iptraf-ng-compat.h"
+
+#include "packet.h"
+#include "capt.h"
+
+struct capt_data_mmap_v2 {
+ void *mmap;
+ size_t mmap_size;
+ struct tpacket2_hdr **hdr;
+ struct sockaddr_ll **sll;
+ unsigned int lastslot;
+ unsigned int slot;
+};
+
+#define FRAMES 512
+#define FRAME_SIZE TPACKET_ALIGN(MAX_PACKET_SIZE + TPACKET2_HDRLEN)
+
+static unsigned int capt_mmap_find_filled_slot(struct capt_data_mmap_v2 *data)
+{
+ for (unsigned int i = data->lastslot; i < data->lastslot + FRAMES; i++) {
+ unsigned int slot = i >= FRAMES ? i - FRAMES : i;
+
+ if (data->hdr[slot]->tp_status & TP_STATUS_USER)
+ return slot;
+ }
+ return FRAMES;
+}
+
+static bool capt_have_packet_mmap_v2(struct capt *capt)
+{
+ struct capt_data_mmap_v2 *data = capt->priv;
+
+ if (capt_mmap_find_filled_slot(data) != FRAMES)
+ return true;
+ else
+ return false;
+}
+
+static int capt_get_packet_mmap_v2(struct capt *capt, struct pkt_hdr *pkt)
+{
+ struct capt_data_mmap_v2 *data = capt->priv;
+ int ss = 0;
+
+ unsigned int slot = capt_mmap_find_filled_slot(data);
+ if (slot < FRAMES) {
+ struct tpacket2_hdr *hdr = data->hdr[slot];
+ struct sockaddr_ll *sll = data->sll[slot];
+
+ pkt->pkt_buf = (char *)hdr + hdr->tp_mac;
+ pkt->pkt_payload = NULL;
+ pkt->pkt_caplen = hdr->tp_snaplen;
+ pkt->pkt_len = hdr->tp_len;
+ pkt->from = sll;
+ pkt->pkt_protocol = ntohs(sll->sll_protocol);
+
+ data->slot = slot;
+ ss = hdr->tp_len;
+ }
+ return ss;
+}
+
+static int capt_put_packet_mmap_v2(struct capt *capt, struct pkt_hdr *pkt __unused)
+{
+ struct capt_data_mmap_v2 *data = capt->priv;
+
+ /* hand out processed slot to kernel */
+ if (data->slot < FRAMES) {
+ data->hdr[data->slot]->tp_status = TP_STATUS_KERNEL;
+ data->lastslot = data->slot;
+ } else
+ data->slot = FRAMES;
+
+ return 0;
+}
+
+static void capt_cleanup_mmap_v2(struct capt *capt)
+{
+ struct capt_data_mmap_v2 *data = capt->priv;
+
+ free(data->sll);
+ data->sll = NULL;
+
+ free(data->hdr);
+ data->hdr = NULL;
+
+ munlock(data->mmap, data->mmap_size);
+ munmap(data->mmap, data->mmap_size);
+ data->mmap = NULL;
+ data->mmap_size = 0;
+
+ free(capt->priv);
+ capt->priv = NULL;
+
+ capt->cleanup = NULL;
+ capt->put_packet = NULL;
+ capt->get_packet = NULL;
+ capt->have_packet = NULL;
+}
+
+int capt_setup_mmap_v2(struct capt *capt)
+{
+ int version = TPACKET_V2;
+ if (setsockopt(capt->fd, SOL_PACKET, PACKET_VERSION, &version, sizeof(version)) != 0)
+ return -1;
+
+ int hdrlen = version;
+ socklen_t socklen = sizeof(hdrlen);
+ if (getsockopt(capt->fd, SOL_PACKET, PACKET_HDRLEN, &hdrlen, &socklen) != 0)
+ return -1;
+
+ struct tpacket_req req;
+
+ req.tp_block_nr = 1; /* TODO: number of CPUs */
+ req.tp_frame_nr = FRAMES;
+ req.tp_frame_size = FRAME_SIZE;
+ req.tp_block_size = req.tp_frame_nr * req.tp_frame_size;
+
+ if(setsockopt(capt->fd, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req)) != 0)
+ return -1;
+
+ size_t size = req.tp_block_size * req.tp_block_nr;
+ void *map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, capt->fd, 0);
+ if (map == MAP_FAILED)
+ return -1;
+
+ if(mlock(map, size) != 0) {
+ munmap(map, size);
+ return -1;
+ }
+
+ struct capt_data_mmap_v2 *data = xmallocz(sizeof(struct capt_data_mmap_v2));
+
+ data->mmap = map;
+ data->mmap_size = size;
+ data->hdr = xmallocz(FRAMES * sizeof(*data->hdr));
+ data->sll = xmallocz(FRAMES * sizeof(*data->sll));
+ for (int i = 0; i < FRAMES; i++) {
+ data->hdr[i] = (struct tpacket2_hdr *)((char *)map + i * FRAME_SIZE);
+ data->sll[i] = (struct sockaddr_ll *)((char *)data->hdr[i] + TPACKET_ALIGN(hdrlen));
+ }
+ data->lastslot = 0;
+ data->slot = FRAMES;
+
+ capt->priv = data;
+ capt->have_packet = capt_have_packet_mmap_v2;
+ capt->get_packet = capt_get_packet_mmap_v2;
+ capt->put_packet = capt_put_packet_mmap_v2;
+ capt->cleanup = capt_cleanup_mmap_v2;
+
+ return 0; /* All O.K. */
+}
diff --git a/src/capt-mmap-v2.h b/src/capt-mmap-v2.h
new file mode 100644
index 0000000..daa92e7
--- /dev/null
+++ b/src/capt-mmap-v2.h
@@ -0,0 +1,6 @@
+#ifndef IPTRAF_NG_CAPT_MMAP_V2_H
+#define IPTRAF_NG_CAPT_MMAP_V2_H
+
+int capt_setup_mmap_v2(struct capt *capt);
+
+#endif /* IPTRAF_NG_CAPT_MMAP_V2_H */
diff --git a/src/capt-mmap-v3.c b/src/capt-mmap-v3.c
new file mode 100644
index 0000000..6b823af
--- /dev/null
+++ b/src/capt-mmap-v3.c
@@ -0,0 +1,196 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+#include "iptraf-ng-compat.h"
+
+#include "packet.h"
+#include "capt.h"
+
+struct capt_data_mmap_v3 {
+ void *mmap;
+ size_t mmap_size;
+ int hdrlen;
+ struct tpacket_block_desc **pbds;
+ struct tpacket_block_desc *pbd;
+ struct tpacket3_hdr *ppd;
+ unsigned int curblock;
+ unsigned int lastblock;
+
+ uint32_t num_pkts; /* only for debug */
+ uint32_t cur_pkt; /* only for debug */
+};
+
+#define BLOCKS 256 /* 256 blocks / 512 frames in each block:
+ * this gets room for 128k packets, which
+ * "should be enough for everybody" ;-) */
+
+#define FRAMES_PER_BLOCK 512 /* keep it as power-of-two (dramaticly lowers
+ * CPU utilization) */
+
+#define FRAMES (BLOCKS * FRAMES_PER_BLOCK) /* frames over all blocks */
+
+#define FRAME_SIZE TPACKET_ALIGN(MAX_PACKET_SIZE + TPACKET3_HDRLEN)
+
+static struct tpacket_block_desc *capt_mmap_find_filled_block(struct capt_data_mmap_v3 *data)
+{
+ for (unsigned int i = data->lastblock; i < data->lastblock + BLOCKS; i++) {
+ unsigned int block = i >= BLOCKS ? i - BLOCKS : i;
+
+ if (data->pbds[block]->hdr.bh1.block_status & TP_STATUS_USER) {
+ data->curblock = block;
+ return data->pbds[block];
+ }
+ }
+ return NULL;
+}
+
+static bool capt_have_packet_mmap_v3(struct capt *capt)
+{
+ struct capt_data_mmap_v3 *data = capt->priv;
+
+ if (data->pbd != NULL)
+ return true;
+
+ data->pbd = capt_mmap_find_filled_block(data);
+ if (data->pbd != NULL)
+ return true;
+ else
+ return false;
+}
+
+static int capt_get_packet_mmap_v3(struct capt *capt, struct pkt_hdr *pkt)
+{
+ struct capt_data_mmap_v3 *data = capt->priv;
+
+ if (data->pbd == NULL)
+ data->pbd = capt_mmap_find_filled_block(data);
+
+ if (data->pbd == NULL)
+ return 0; /* no packet ready */
+
+ if (data->ppd == NULL) {
+ data->ppd = (struct tpacket3_hdr *) ((uint8_t *)data->pbd + data->pbd->hdr.bh1.offset_to_first_pkt);
+ data->num_pkts = data->pbd->hdr.bh1.num_pkts;
+ }
+
+ /* here should be at least one packet ready */
+ pkt->pkt_buf = (char *)data->ppd + data->ppd->tp_mac;
+ pkt->pkt_payload = NULL;
+ pkt->pkt_caplen = data->ppd->tp_snaplen;
+ pkt->pkt_len = data->ppd->tp_len;
+ pkt->from = (struct sockaddr_ll *)((uint8_t *)data->ppd + data->hdrlen);
+ pkt->pkt_protocol = ntohs(pkt->from->sll_protocol);
+
+ return pkt->pkt_len;
+}
+
+static int capt_put_packet_mmap_v3(struct capt *capt, struct pkt_hdr *pkt __unused)
+{
+ struct capt_data_mmap_v3 *data = capt->priv;
+
+ if (data->ppd->tp_next_offset != 0) {
+ data->ppd = (struct tpacket3_hdr *)((uint8_t *)data->ppd + data->ppd->tp_next_offset);
+ data->cur_pkt++;
+ } else {
+ data->ppd = NULL;
+ data->num_pkts = 0;
+ data->cur_pkt = 0;
+ data->pbd->hdr.bh1.block_status = TP_STATUS_KERNEL;
+ data->pbd = NULL;
+ data->lastblock = data->curblock;
+ }
+
+ return 0;
+}
+
+static unsigned long capt_get_dropped_mmap_v3(struct capt *capt)
+{
+ struct tpacket_stats_v3 stats;
+ socklen_t len = sizeof(stats);
+
+ memset(&stats, 0, len);
+ int err = getsockopt(capt->fd, SOL_PACKET, PACKET_STATISTICS, &stats, &len);
+ if (err < 0)
+ die_errno("%s(): getsockopt(PACKET_STATISTICS)", __func__);
+
+ capt->dropped += stats.tp_drops;
+
+ return capt->dropped;
+}
+
+static void capt_cleanup_mmap_v3(struct capt *capt)
+{
+ struct capt_data_mmap_v3 *data = capt->priv;
+
+ free(data->pbds);
+
+ munlock(data->mmap, data->mmap_size);
+ munmap(data->mmap, data->mmap_size);
+
+ memset(data, 0, sizeof(*data));
+
+ free(capt->priv);
+ capt->priv = NULL;
+
+ capt->cleanup = NULL;
+ capt->get_dropped = NULL;
+ capt->put_packet = NULL;
+ capt->get_packet = NULL;
+ capt->have_packet = NULL;
+}
+
+int capt_setup_mmap_v3(struct capt *capt)
+{
+ int version = TPACKET_V3;
+ if (setsockopt(capt->fd, SOL_PACKET, PACKET_VERSION, &version, sizeof(version)) != 0)
+ return -1;
+
+ int hdrlen = version;
+ socklen_t socklen = sizeof(hdrlen);
+ if (getsockopt(capt->fd, SOL_PACKET, PACKET_HDRLEN, &hdrlen, &socklen) != 0)
+ return -1;
+
+ struct tpacket_req3 req;
+
+ req.tp_block_nr = BLOCKS;
+ req.tp_frame_nr = FRAMES;
+ req.tp_frame_size = FRAME_SIZE;
+ req.tp_block_size = FRAMES_PER_BLOCK * req.tp_frame_size;
+
+ req.tp_retire_blk_tov = 20; /* block retire timeout in msec */
+ req.tp_sizeof_priv = 0;
+ // req.tp_feature_req_word = TP_FT_REQ_FILL_RXHASH;
+
+ if(setsockopt(capt->fd, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req)) != 0)
+ return -1;
+
+ size_t size = req.tp_block_size * req.tp_block_nr;
+ void *map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, capt->fd, 0);
+ if (map == MAP_FAILED)
+ return -1;
+
+ if (mlock(map, size) != 0) {
+ munmap(map, size);
+ return -1;
+ }
+
+ struct capt_data_mmap_v3 *data = xmallocz(sizeof(struct capt_data_mmap_v3));
+
+ data->hdrlen = hdrlen;
+ data->mmap = map;
+ data->mmap_size = size;
+
+ data->pbds = xmallocz(BLOCKS * sizeof(*data->pbd));
+ for (int i = 0; i < BLOCKS; i++) {
+ data->pbds[i] = map + i * req.tp_block_size;
+ }
+
+ capt->priv = data;
+ capt->have_packet = capt_have_packet_mmap_v3;
+ capt->get_packet = capt_get_packet_mmap_v3;
+ capt->put_packet = capt_put_packet_mmap_v3;
+ capt->get_dropped = capt_get_dropped_mmap_v3;
+ capt->cleanup = capt_cleanup_mmap_v3;
+
+ return 0; /* All O.K. */
+}
diff --git a/src/capt-mmap-v3.h b/src/capt-mmap-v3.h
new file mode 100644
index 0000000..53948ad
--- /dev/null
+++ b/src/capt-mmap-v3.h
@@ -0,0 +1,6 @@
+#ifndef IPTRAF_NG_CAPT_MMAP_V3_H
+#define IPTRAF_NG_CAPT_MMAP_V3_H
+
+int capt_setup_mmap_v3(struct capt *capt);
+
+#endif /* IPTRAF_NG_CAPT_MMAP_V3_H */
diff --git a/src/capt-recvmmsg.c b/src/capt-recvmmsg.c
new file mode 100644
index 0000000..712bf0d
--- /dev/null
+++ b/src/capt-recvmmsg.c
@@ -0,0 +1,143 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+#include "iptraf-ng-compat.h"
+
+#include "packet.h"
+#include "capt.h"
+
+#define FRAMES 128
+
+struct capt_data_recvmmsg {
+ char *buf;
+
+ struct mmsghdr *msgvec;
+ struct iovec *iov;
+ struct sockaddr_ll *from;
+
+ unsigned int lastslot;
+ unsigned int slot;
+};
+
+static unsigned int capt_recvmmsg_find_filled_slot(struct capt_data_recvmmsg *data)
+{
+ for (unsigned int i = data->lastslot; i < data->lastslot + FRAMES; i++) {
+ unsigned int slot = i >= FRAMES ? i - FRAMES : i;
+
+ if (data->msgvec[slot].msg_len != 0)
+ return slot;
+ }
+ return FRAMES;
+}
+
+static bool capt_have_packet_recvmmsg(struct capt *capt)
+{
+ struct capt_data_recvmmsg *data = capt->priv;
+
+ if (capt_recvmmsg_find_filled_slot(data) != FRAMES)
+ return true;
+ else
+ return false;
+}
+
+static int capt_get_packet_recvmmsg(struct capt *capt, struct pkt_hdr *pkt)
+{
+ struct capt_data_recvmmsg *data = capt->priv;
+ int ret = 0;
+
+ unsigned int slot = capt_recvmmsg_find_filled_slot(data);
+ if (slot == FRAMES) {
+ /* these are set upon return from recvmsg() so clean */
+ /* them beforehand */
+ for (unsigned int i = 0; i < FRAMES; i++) {
+ data->msgvec[i].msg_hdr.msg_controllen = 0;
+ data->msgvec[i].msg_hdr.msg_flags = 0;
+ data->msgvec[i].msg_len = 0;
+ }
+
+ int received = recvmmsg(capt->fd, data->msgvec, FRAMES, MSG_TRUNC | MSG_DONTWAIT, NULL);
+ if (received <= 0)
+ return received;
+ slot = 0;
+ }
+ pkt->pkt_len = data->msgvec[slot].msg_len;
+ pkt->pkt_caplen = data->msgvec[slot].msg_len;
+ if (pkt->pkt_caplen > MAX_PACKET_SIZE)
+ pkt->pkt_caplen = MAX_PACKET_SIZE;
+ pkt->pkt_buf = data->buf + slot * MAX_PACKET_SIZE;
+ pkt->from = &data->from[slot];
+ pkt->pkt_payload = NULL;
+ pkt->pkt_protocol = ntohs(pkt->from->sll_protocol);
+
+ data->slot = slot;
+
+ return ret;
+}
+
+static int capt_put_packet_recvmmsg(struct capt *capt, struct pkt_hdr *pkt __unused)
+{
+ struct capt_data_recvmmsg *data = capt->priv;
+
+ /* hand out processed slot to kernel */
+ if (data->slot < FRAMES) {
+ data->msgvec[data->slot].msg_len = 0;
+ data->lastslot = data->slot;
+ } else
+ data->slot = FRAMES;
+
+ return 0;
+}
+
+static void capt_cleanup_recvmmsg(struct capt *capt)
+{
+ struct capt_data_recvmmsg *data = capt->priv;
+
+ capt->cleanup = NULL;
+ capt->put_packet = NULL;
+ capt->get_packet = NULL;
+ capt->have_packet = NULL;
+
+ free(data->from);
+ data->from = NULL;
+ free(data->iov);
+ data->iov = NULL;
+ free(data->msgvec);
+ data->msgvec = NULL;
+ free(data->buf);
+ data->buf = NULL;
+
+ free(capt->priv);
+ capt->priv = NULL;
+}
+
+int capt_setup_recvmmsg(struct capt *capt)
+{
+ struct capt_data_recvmmsg *data;
+
+ data = xmallocz(sizeof(struct capt_data_recvmmsg));
+ data->buf = xmallocz(FRAMES * MAX_PACKET_SIZE);
+ data->msgvec = xmallocz(FRAMES * sizeof(*data->msgvec));
+ data->iov = xmallocz(FRAMES * sizeof(*data->iov));
+ data->from = xmallocz(FRAMES * sizeof(*data->from));
+
+ for (unsigned int i = 0; i < FRAMES; i++) {
+ data->iov[i].iov_len = MAX_PACKET_SIZE;
+ data->iov[i].iov_base = data->buf + i * MAX_PACKET_SIZE;
+
+ data->msgvec[i].msg_hdr.msg_name = &data->from[i];
+ data->msgvec[i].msg_hdr.msg_namelen = sizeof(data->from[i]);
+ data->msgvec[i].msg_hdr.msg_iov = &data->iov[i];
+ data->msgvec[i].msg_hdr.msg_iovlen = 1;
+ data->msgvec[i].msg_hdr.msg_control = NULL;
+ }
+ data->slot = FRAMES;
+ data->lastslot = 0;
+
+ capt->priv = data;
+ capt->have_packet = capt_have_packet_recvmmsg;
+ capt->get_packet = capt_get_packet_recvmmsg;
+ capt->put_packet = capt_put_packet_recvmmsg;
+ capt->cleanup = capt_cleanup_recvmmsg;
+
+ return 0;
+}
diff --git a/src/capt-recvmmsg.h b/src/capt-recvmmsg.h
new file mode 100644
index 0000000..8461eed
--- /dev/null
+++ b/src/capt-recvmmsg.h
@@ -0,0 +1,6 @@
+#ifndef IPTRAF_NG_CAPT_RECVMMSG_H
+#define IPTRAF_NG_CAPT_RECVMMSG_H
+
+int capt_setup_recvmmsg(struct capt *capt);
+
+#endif /* IPTRAF_NG_CAPT_RECVMMSG_H */
diff --git a/src/capt-recvmsg.c b/src/capt-recvmsg.c
new file mode 100644
index 0000000..4ef7263
--- /dev/null
+++ b/src/capt-recvmsg.c
@@ -0,0 +1,89 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+#include "iptraf-ng-compat.h"
+
+#include "packet.h"
+#include "capt.h"
+
+struct capt_data_recvmsg {
+ char *buf;
+
+ struct iovec iov;
+ struct msghdr *msg;
+ struct sockaddr_ll *from;
+};
+
+static bool capt_have_packet_recvmsg(struct capt *capt __unused)
+{
+ return false;
+}
+
+static int capt_get_packet_recvmsg(struct capt *capt, struct pkt_hdr *pkt)
+{
+ struct capt_data_recvmsg *data = capt->priv;
+
+ /* these are set upon return from recvmsg() so clean */
+ /* them beforehand */
+ data->msg->msg_controllen = 0;
+ data->msg->msg_flags = 0;
+
+ ssize_t len = recvmsg(capt->fd, data->msg, MSG_TRUNC | MSG_DONTWAIT);
+ if (len > 0) {
+ pkt->pkt_len = len;
+ pkt->pkt_caplen = len;
+ if (pkt->pkt_caplen > MAX_PACKET_SIZE)
+ pkt->pkt_caplen = MAX_PACKET_SIZE;
+ pkt->pkt_buf = data->buf;
+ pkt->from = data->from;
+ pkt->pkt_payload = NULL;
+ pkt->pkt_protocol = ntohs(pkt->from->sll_protocol);
+ }
+ return len;
+}
+
+static void capt_cleanup_recvmsg(struct capt *capt)
+{
+ struct capt_data_recvmsg *data = capt->priv;
+
+ capt->cleanup = NULL;
+ capt->put_packet = NULL;
+ capt->get_packet = NULL;
+ capt->have_packet = NULL;
+
+ free(data->from);
+ data->from = NULL;
+ free(data->msg);
+ data->msg = NULL;
+
+ free(data->buf);
+ data->buf = NULL;
+ free(capt->priv);
+ capt->priv = NULL;
+}
+
+int capt_setup_recvmsg(struct capt *capt)
+{
+ struct capt_data_recvmsg *data = xmallocz(sizeof(struct capt_data_recvmsg));
+
+ data->buf = xmallocz(MAX_PACKET_SIZE);
+ data->iov.iov_len = MAX_PACKET_SIZE;
+ data->iov.iov_base = data->buf;
+
+ data->msg = xmallocz(sizeof(*data->msg));
+ data->from = xmallocz(sizeof(*data->from));
+
+ data->msg->msg_name = data->from;
+ data->msg->msg_namelen = sizeof(*data->from);
+ data->msg->msg_iov = &data->iov;
+ data->msg->msg_iovlen = 1;
+ data->msg->msg_control = NULL;
+
+ capt->priv = data;
+ capt->have_packet = capt_have_packet_recvmsg;
+ capt->get_packet = capt_get_packet_recvmsg;
+ capt->put_packet = NULL;
+ capt->cleanup = capt_cleanup_recvmsg;
+
+ return 0;
+}
diff --git a/src/capt-recvmsg.h b/src/capt-recvmsg.h
new file mode 100644
index 0000000..243761e
--- /dev/null
+++ b/src/capt-recvmsg.h
@@ -0,0 +1,6 @@
+#ifndef IPTRAF_NG_CAPT_RECVMSG_H
+#define IPTRAF_NG_CAPT_RECVMSG_H
+
+int capt_setup_recvmsg(struct capt *capt);
+
+#endif /* IPTRAF_NG_CAPT_RECVMSG_H */
diff --git a/src/capt.c b/src/capt.c
new file mode 100644
index 0000000..e14b398
--- /dev/null
+++ b/src/capt.c
@@ -0,0 +1,212 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+#include "iptraf-ng-compat.h"
+
+#include "options.h"
+#include "promisc.h"
+#include "error.h"
+#include "ifaces.h"
+#include "packet.h"
+#include "timer.h"
+#include "capt.h"
+#include "capt-recvmsg.h"
+#include "capt-recvmmsg.h"
+#include "capt-mmap-v2.h"
+#include "capt-mmap-v3.h"
+
+static int capt_set_recv_timeout(int fd, unsigned int msec)
+{
+ struct timeval timeout;
+ socklen_t len = sizeof(timeout);
+
+ timeout.tv_sec = msec / 1000;
+ timeout.tv_usec = (msec % 1000) * 1000;
+ if(setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, len) != 0)
+ return -1;
+ else
+ return 0;
+}
+
+static int capt_setup_receive_function(struct capt *capt)
+{
+ /* try packet mmap() TPACKET_V3 */
+ if (capt_setup_mmap_v3(capt) == 0)
+ return 0;
+
+ /* try packet mmap() TPACKET_V2 */
+ if (capt_setup_mmap_v2(capt) == 0)
+ return 0;
+
+ /* try packet recvmmsg() */
+ if (capt_setup_recvmmsg(capt) == 0)
+ return 0;
+
+ /* try packet recvmsg() */
+ if (capt_setup_recvmsg(capt) == 0)
+ return 0;
+
+ return -1;
+}
+
+int capt_init(struct capt *capt, char *ifname)
+{
+ capt->have_packet = NULL;
+ capt->get_packet = NULL;
+ capt->put_packet = NULL;
+ capt->get_dropped = NULL;
+ capt->cleanup = NULL;
+
+ capt->dropped = 0UL;
+
+ INIT_LIST_HEAD(&capt->promisc);
+
+ /* initialize socket first with some default protocol;
+ * the right protocol is then set with bind();
+ * this overcomes the problem with getting packets
+ * from other interfaces, because the socket was not
+ * properly initialized yet */
+ int fd = socket(PF_PACKET, SOCK_RAW, 0);
+ if (fd == -1)
+ return fd;
+ capt->fd = fd;
+
+ /* set socket receive timeout */
+ if (capt_set_recv_timeout(capt->fd, 250) == -1)
+ goto out;
+
+ /* try all available receive functions */
+ if (capt_setup_receive_function(capt) == -1)
+ goto out;
+
+ if (options.promisc)
+ promisc_enable(capt->fd, &capt->promisc, ifname);
+
+ /* bind interface (and protocol) to socket
+ * (interface can be NULL -> any interface) */
+ if (dev_bind_ifname(capt->fd, ifname) == -1)
+ goto out;
+
+ return 0; /* all O.K. */
+
+out:
+ capt_destroy(capt);
+
+ return -1;
+}
+
+void capt_destroy(struct capt *capt)
+{
+ promisc_disable(capt->fd, &capt->promisc);
+
+ if (capt->cleanup)
+ capt->cleanup(capt);
+
+ close(capt->fd);
+ capt->fd = -1;
+}
+
+static unsigned long capt_get_dropped_generic(struct capt *capt)
+{
+ struct tpacket_stats stats;
+ socklen_t len = sizeof(stats);
+
+ memset(&stats, 0, len);
+ int err = getsockopt(capt->fd, SOL_PACKET, PACKET_STATISTICS, &stats, &len);
+ if (err < 0)
+ die_errno("%s(): getsockopt(PACKET_STATISTICS)", __func__);
+
+ capt->dropped += stats.tp_drops;
+
+ return capt->dropped;
+}
+
+unsigned long capt_get_dropped(struct capt *capt)
+{
+ if (capt->get_dropped)
+ return capt->get_dropped(capt);
+
+ return capt_get_dropped_generic(capt);
+}
+
+int capt_get_packet(struct capt *capt, struct pkt_hdr *pkt, int *ch, WINDOW *win)
+{
+ struct pollfd pfds[2];
+ nfds_t nfds = 0;
+ int pfd_packet = -1;
+ int pfd_key = -1;
+ int ss = 0;
+ bool have_packet = capt->have_packet(capt);
+ int timeout = ch ? DEFAULT_UPDATE_DELAY : -1;
+ static struct timespec next_kbd_check = { 0 };
+
+ /* no packet ready, so poll() for it */
+ if (!have_packet) {
+ pfds[nfds].fd = capt->fd;
+ pfds[nfds].events = POLLIN;
+ pfd_packet = nfds;
+ nfds++;
+ }
+
+ /* check for key press */
+ /* Monitor stdin only if in interactive, not daemon mode. */
+ if (ch && !daemonized) {
+ struct timespec now;
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ /* if we're going to poll() for packet, check the key
+ * press too */
+ if (!have_packet || time_after(&now, &next_kbd_check)) {
+ pfds[nfds].fd = 0;
+ pfds[nfds].events = POLLIN;
+ pfd_key = nfds;
+ nfds++;
+ if (have_packet)
+ timeout = 0;
+
+ next_kbd_check = now;
+ time_add_msecs(&next_kbd_check, 10);
+ }
+ }
+
+ if (nfds > 0)
+ do {
+ ss = poll(pfds, nfds, timeout);
+ } while ((ss == -1) && (errno == EINTR));
+
+ /* no packet ready yet */
+ pkt->pkt_len = 0;
+
+ if ((pfd_packet != -1) && (ss > 0)) {
+ if (pfds[pfd_packet].revents & POLLERR) {
+ /* some error occured, don't try to get packet */
+ have_packet = false;
+ /* ... and return error */
+ ss = -1;
+ } else if (pfds[pfd_packet].revents & POLLIN) {
+ /* packet ready */
+ have_packet = true;
+ }
+ }
+ if (have_packet) {
+ int ret = capt->get_packet(capt, pkt);
+ if (ret <= 0)
+ ss = ret;
+ }
+
+ if (ch) {
+ *ch = ERR; /* signalize we have no key ready */
+ if (!daemonized && (((pfd_key != -1) && ((ss > 0) && ((pfds[pfd_key].revents & POLLIN) != 0)))))
+ *ch = wgetch(win);
+ }
+
+ return ss;
+}
+
+int capt_put_packet(struct capt *capt, struct pkt_hdr *pkt)
+{
+ if (capt->put_packet)
+ capt->put_packet(capt, pkt);
+
+ return 0;
+}
diff --git a/src/capt.h b/src/capt.h
new file mode 100644
index 0000000..d1399b5
--- /dev/null
+++ b/src/capt.h
@@ -0,0 +1,36 @@
+#ifndef IPTRAF_NG_CAPT_H
+#define IPTRAF_NG_CAPT_H
+
+/*
+ * Number of bytes from captured packet to move into a buffer.
+ * 96 bytes should be enough for the IP header, TCP/UDP/ICMP/whatever header
+ * with reasonable numbers of options.
+ *
+ * keep it aligned to 16 !!!
+ */
+#define MAX_PACKET_SIZE 96
+
+#include "list.h"
+
+struct capt {
+ int fd;
+ unsigned long dropped;
+
+ struct list_head promisc;
+
+ void *priv;
+
+ bool (*have_packet)(struct capt *capt);
+ int (*get_packet)(struct capt *capt, struct pkt_hdr *pkt);
+ int (*put_packet)(struct capt *capt, struct pkt_hdr *pkt);
+ unsigned long (*get_dropped)(struct capt *capt);
+ void (*cleanup)(struct capt *capt);
+};
+
+int capt_init(struct capt *capt, char *ifname);
+void capt_destroy(struct capt *capt);
+unsigned long capt_get_dropped(struct capt *capt);
+int capt_get_packet(struct capt *capt, struct pkt_hdr *pkt, int *ch, WINDOW *win);
+int capt_put_packet(struct capt *capt, struct pkt_hdr *pkt);
+
+#endif /* IPTRAF_NG_CAPT_H */
diff --git a/src/capture-pkt.c b/src/capture-pkt.c
new file mode 100644
index 0000000..d4fa7cc
--- /dev/null
+++ b/src/capture-pkt.c
@@ -0,0 +1,76 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+#include "iptraf-ng-compat.h"
+
+#include "built-in.h"
+#include "parse-options.h"
+#include "ifaces.h"
+#include "packet.h"
+#include "capt.h"
+
+static const char *const capture_usage[] = {
+ IPTRAF_NAME " capture [options] <device>",
+ NULL
+};
+
+static int cap_nr_pkt = 1, help_opt;
+static char *ofilename;
+
+static struct options capture_options[] = {
+ OPT__HELP(&help_opt),
+ OPT_GROUP(""),
+ OPT_INTEGER('c', "capture", &cap_nr_pkt, "capture <n> packets (default: 1)"),
+ OPT_STRING('o', "output", &ofilename, "file", "save captured packet into <file> (default: <stdout>)"),
+ OPT_END()
+};
+
+int cmd_capture(int argc, char **argv)
+{
+ parse_opts(argc, argv, capture_options, capture_usage);
+ argv += optind;
+ if (help_opt || !*argv || argv[1])
+ parse_usage_and_die(capture_usage, capture_options);
+
+ char *dev = argv[0];
+
+ struct capt capt;
+ if (capt_init(&capt, dev) == -1)
+ die_errno("Unable to initialize packet capture interface");
+
+ FILE *fp = stdout;
+ if (ofilename) {
+ fp = fopen(ofilename, "wb");
+ if (!fp)
+ die_errno("Unable to open file");
+ }
+
+ struct pkt_hdr pkt;
+ packet_init(&pkt);
+
+ int captured = 0;
+ do {
+ if (capt_get_packet(&capt, &pkt, NULL, NULL) == -1)
+ die_errno("Failed to get packet");
+
+ if (!pkt.pkt_len)
+ continue;
+
+ packet_dump(&pkt, fp);
+ capt_put_packet(&capt, &pkt);
+
+ captured++;
+ fprintf(stderr, "\rCaptured %d packet(s) out of %d", captured, cap_nr_pkt);
+ fflush(stderr);
+ } while (captured < cap_nr_pkt);
+ fprintf(stderr, "\n");
+
+ packet_destroy(&pkt);
+
+ if (fp && fp != stderr)
+ fclose(fp);
+
+ capt_destroy(&capt);
+
+ return 0;
+}
diff --git a/src/cidr.c b/src/cidr.c
new file mode 100644
index 0000000..768dd0c
--- /dev/null
+++ b/src/cidr.c
@@ -0,0 +1,90 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+#include "iptraf-ng-compat.h"
+
+// TODO: full rewrite
+
+/*
+ * Returns a binary subnet mask based on the number of mask bits. The
+ * dotted-decimal notation may be obtained with inet_ntoa.
+ */
+unsigned long cidr_get_mask(unsigned int maskbits)
+{
+ struct in_addr mask;
+
+ if (maskbits == 0)
+ return 0;
+
+ inet_aton("255.255.255.255", &mask);
+ mask.s_addr = htonl(mask.s_addr << (32 - maskbits));
+
+ return mask.s_addr;
+}
+
+/*
+ * Returns a subnet mask in dotted-decimal notation given the number of
+ * 1-bits in the mask.
+ */
+char *cidr_get_quad_mask(unsigned int maskbits)
+{
+ struct in_addr addr;
+
+ addr.s_addr = cidr_get_mask(maskbits);
+ return inet_ntoa(addr);
+}
+
+/*
+ * Returns the number of 1-bits in the given binary subnet mask in
+ * network byte order.
+ */
+unsigned int cidr_get_maskbits(unsigned long mask)
+{
+ unsigned int i = 32;
+
+ if (mask == 0)
+ return 0;
+
+ mask = ntohl(mask);
+ while (mask % 2 == 0) {
+ mask >>= 1;
+ i--;
+ }
+
+ return i;
+}
+
+/*
+ * Parse and cut off mask from CIDR-style address/mask string. In case of
+ * absent or invalid input in the mask, 255 is returned in *maskbits
+ * (255 is invalid for an IPv4 address).
+ */
+void cidr_split_address(char *cidr_addr, unsigned int *maskbits)
+{
+ char *slashptr = strchr(cidr_addr, '/');
+ if (slashptr == NULL) {
+ *maskbits = 255;
+ return;
+ }
+
+ /*
+ * Cut out the mask part and move past the slash
+ */
+ *slashptr = '\0';
+ slashptr++;
+
+ if (*slashptr != '\0') {
+ unsigned long val;
+ char *endptr;
+
+ val = strtoul(slashptr, &endptr, 10);
+ if (val > UINT_MAX)
+ val = UINT_MAX;
+ *maskbits = (unsigned int)val;
+ if (*endptr != '\0')
+ *maskbits = 255;
+ } else
+ *maskbits = 255;
+
+ return;
+}
diff --git a/src/cidr.h b/src/cidr.h
new file mode 100644
index 0000000..7449246
--- /dev/null
+++ b/src/cidr.h
@@ -0,0 +1,9 @@
+#ifndef IPTRAF_NG_CIDR_H
+#define IPTRAF_NG_CIDR_H
+
+unsigned long cidr_get_mask(unsigned int maskbits);
+char *cidr_get_quad_mask(unsigned int maskbits);
+unsigned int cidr_get_maskbits(unsigned long mask);
+void cidr_split_address(char *cidr_addr, unsigned int *maskbits);
+
+#endif /* IPTRAF_NG_CIDR_H */
diff --git a/src/counters.c b/src/counters.c
new file mode 100644
index 0000000..f71880c
--- /dev/null
+++ b/src/counters.c
@@ -0,0 +1,40 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+#include "iptraf-ng-compat.h"
+
+#include "counters.h"
+
+void pkt_counter_update(struct pkt_counter *count, int bytes)
+{
+ if (count) {
+ count->pc_packets++;
+ count->pc_bytes += bytes;
+ }
+}
+
+void pkt_counter_reset(struct pkt_counter *count)
+{
+ if (count)
+ memset(count, 0, sizeof(*count));
+}
+
+void proto_counter_update(struct proto_counter *proto_counter, int outgoing, int bytes)
+{
+ if (proto_counter) {
+ pkt_counter_update(&proto_counter->proto_total, bytes);
+ if (outgoing)
+ pkt_counter_update(&proto_counter->proto_out, bytes);
+ else
+ pkt_counter_update(&proto_counter->proto_in, bytes);
+ }
+}
+
+void proto_counter_reset(struct proto_counter *proto_counter)
+{
+ if (proto_counter) {
+ pkt_counter_reset(&proto_counter->proto_total);
+ pkt_counter_reset(&proto_counter->proto_out);
+ pkt_counter_reset(&proto_counter->proto_in);
+ }
+}
diff --git a/src/counters.h b/src/counters.h
new file mode 100644
index 0000000..1746d0c
--- /dev/null
+++ b/src/counters.h
@@ -0,0 +1,22 @@
+#ifndef IPTRAF_NG_COUNTERS_H
+#define IPTRAF_NG_COUNTERS_H
+
+struct pkt_counter {
+ unsigned long long pc_packets;
+ unsigned long long pc_bytes;
+};
+
+struct proto_counter {
+ struct pkt_counter proto_total;
+ struct pkt_counter proto_in;
+ struct pkt_counter proto_out;
+};
+
+void pkt_counter_update(struct pkt_counter *count, int bytes);
+void pkt_counter_reset(struct pkt_counter *count);
+
+void proto_counter_update(struct proto_counter *proto_counter, int outgoing,
+ int bytes);
+void proto_counter_reset(struct proto_counter *proto_counter);
+
+#endif /* IPTRAF_NG_COUNTERS_H */
diff --git a/src/deskman.c b/src/deskman.c
new file mode 100644
index 0000000..f9d8af4
--- /dev/null
+++ b/src/deskman.c
@@ -0,0 +1,300 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+/***
+
+deskman.c - desktop management routines
+
+***/
+
+#include "iptraf-ng-compat.h"
+
+#include "tui/labels.h"
+#include "tui/msgboxes.h"
+#include "tui/winops.h"
+
+#include "deskman.h"
+#include "options.h"
+#include "timer.h"
+
+/* Attribute variables */
+
+int STDATTR;
+int HIGHATTR;
+int BOXATTR;
+int ACTIVEATTR;
+int BARSTDATTR;
+int BARHIGHATTR;
+int BARPTRATTR;
+int DLGTEXTATTR;
+int DLGBOXATTR;
+int DLGHIGHATTR;
+int DESCATTR;
+int STATUSBARATTR;
+int IPSTATLABELATTR;
+int IPSTATATTR;
+int DESKTEXTATTR;
+int PTRATTR;
+int FIELDATTR;
+int ERRBOXATTR;
+int ERRTXTATTR;
+int OSPFATTR;
+int UDPATTR;
+int IGPATTR;
+int IGMPATTR;
+int IGRPATTR;
+int GREATTR;
+int ARPATTR;
+int UNKNIPATTR;
+int UNKNATTR;
+int IPV6ATTR;
+int ICMPV6ATTR;
+
+/* draw the basic desktop common to my screen-oriented programs */
+
+void draw_desktop(void)
+{
+ int row; /* counter for desktop construction */
+
+ scrollok(stdscr, 0);
+ attrset(STATUSBARATTR);
+ move(0, 0);
+ printw("%*c", COLS, ' '); /* these two print the top n' bottom */
+ move(LINES - 1, 0);
+ printw("%*c", COLS, ' '); /* lines */
+
+ attrset(FIELDATTR);
+
+ for (row = 1; row <= LINES - 2; row++) { /* draw the background */
+ move(row, 0);
+ printw("%*c", COLS, ' ');
+ }
+
+ refresh();
+}
+
+void about(void)
+{
+ WINDOW *win;
+ PANEL *panel;
+ int ch;
+
+ win = newwin(18, 62, (LINES - 17) / 2, (COLS - 62) / 2);
+
+ panel = new_panel(win);
+
+ tx_stdwinset(win);
+ wtimeout(win, -1);
+ wattrset(win, BOXATTR);
+ tx_colorwin(win);
+ tx_box(win, ACS_VLINE, ACS_HLINE);
+ wattrset(win, STDATTR);
+ mvwprintw(win, 1, 2, IPTRAF_NAME);
+ mvwprintw(win, 2, 2, "An IP Network Statistics Utility");
+ mvwprintw(win, 3, 2, "Version %s", IPTRAF_VERSION);
+ mvwprintw(win, 5, 2, "Written by Gerard Paul Java");
+ mvwprintw(win, 6, 2, "Copyright (c) Gerard Paul Java 1997-2004");
+ mvwprintw(win, 8, 2, "This program is open-source software released");
+ mvwprintw(win, 9, 2, "under the terms of the GNU General Public");
+ mvwprintw(win, 10, 2, "Public License Version 2 or any later version.");
+ mvwprintw(win, 11, 2, "See the included LICENSE file for details.");
+ mvwprintw(win, 13, 2,
+ "IPv6 support by Markus Ullmann <mail@markus-ullmann.de>");
+ mvwprintw(win, 14, 2,
+ "inspired by 2.7.0 diff by Guy Martin <gmsoft@tuxicoman.be>");
+
+ wattrset(win, HIGHATTR);
+
+ mvwprintw(win, 16, 2, ANYKEY_MSG);
+
+ update_panels();
+ doupdate();
+
+ do {
+ ch = wgetch(win);
+ if (ch == 12)
+ tx_refresh_screen();
+ } while (ch == 12);
+
+ del_panel(panel);
+ delwin(win);
+ update_panels();
+ doupdate();
+}
+
+void show_sort_statwin(WINDOW ** statwin, PANEL ** panel)
+{
+ *statwin = newwin(5, 30, (LINES - 5) / 2, (COLS - 30) / 2);
+ *panel = new_panel(*statwin);
+
+ wattrset(*statwin, BOXATTR);
+ tx_colorwin(*statwin);
+ tx_box(*statwin, ACS_VLINE, ACS_HLINE);
+
+ wattrset(*statwin, STDATTR);
+ mvwprintw(*statwin, 2, 2, "Sorting, please wait...");
+}
+
+void printipcerr(void)
+{
+ attrset(ERRTXTATTR);
+ mvprintw(0, 68, " IPC Error ");
+}
+
+void stdkeyhelp(WINDOW * win)
+{
+ tx_printkeyhelp("Enter", "-accept ", win, DLGHIGHATTR, DLGTEXTATTR);
+ tx_printkeyhelp("Ctrl+X", "-cancel", win, DLGHIGHATTR, DLGTEXTATTR);
+}
+
+void sortkeyhelp(void)
+{
+ tx_printkeyhelp("S", "-sort ", stdscr, HIGHATTR, STATUSBARATTR);
+}
+
+void stdexitkeyhelp(void)
+{
+ tx_printkeyhelp("X", "-exit", stdscr, HIGHATTR, STATUSBARATTR);
+ tx_coloreol();
+}
+
+void scrollkeyhelp(void)
+{
+ tx_printkeyhelp("Up/Down/PgUp/PgDn", "-scroll window ", stdscr,
+ HIGHATTR, STDATTR);
+}
+
+void tabkeyhelp(WINDOW * win)
+{
+ tx_printkeyhelp("Tab", "-next field ", win, DLGHIGHATTR, DLGTEXTATTR);
+}
+
+void indicate(char *message)
+{
+ attrset(STATUSBARATTR);
+ mvprintw(LINES - 1, 0, "%*c", COLS, ' ');
+ mvprintw(LINES - 1, 1, "%s", message);
+ refresh();
+}
+
+void printlargenum(unsigned long long i, WINDOW * win)
+{
+ if (i < 100000000) /* less than 100 million */
+ wprintw(win, "%9llu", i);
+ else if (i < 1000000000) /* less than 1 billion */
+ wprintw(win, "%8lluk", i / 1000);
+ else if (i < 1000000000000ULL) /* less than 1 trillion */
+ wprintw(win, "%8lluM", i / 1000000);
+ else if (i < 1000000000000000ULL) /* less than 1000 trillion */
+ wprintw(win, "%8lluG", i / 1000000000ULL);
+ else
+ wprintw(win, "%8lluT", i / 1000000000000ULL);
+}
+
+void print_packet_drops(unsigned long count, WINDOW *win, int x)
+{
+ wattrset(win, BOXATTR);
+ mvwprintw(win, getmaxy(win) - 1, x, " Drops: %9lu ", count);
+}
+
+static unsigned int get_screen_update_rate(void)
+{
+ if (options.updrate == 0)
+ return DEFAULT_UPDATE_DELAY;
+ else
+ return options.updrate * 1000UL;
+}
+
+void set_next_screen_update(struct timespec *next_screen_update,
+ struct timespec *now)
+{
+ *next_screen_update = *now;
+ time_add_msecs(next_screen_update, get_screen_update_rate());
+}
+
+void standardcolors(int color)
+{
+ if ((color) && (has_colors())) {
+ init_pair(1, COLOR_BLUE, COLOR_WHITE);
+ init_pair(2, COLOR_BLACK, COLOR_CYAN);
+ init_pair(3, COLOR_CYAN, COLOR_BLUE);
+ init_pair(4, COLOR_YELLOW, COLOR_RED);
+ init_pair(5, COLOR_WHITE, COLOR_RED);
+ init_pair(6, COLOR_BLUE, COLOR_CYAN);
+ init_pair(7, COLOR_BLUE, COLOR_WHITE);
+ init_pair(9, COLOR_RED, COLOR_WHITE);
+ init_pair(10, COLOR_GREEN, COLOR_BLUE);
+ init_pair(11, COLOR_CYAN, COLOR_BLACK);
+ init_pair(12, COLOR_RED, COLOR_CYAN);
+ init_pair(14, COLOR_YELLOW, COLOR_BLUE);
+ init_pair(15, COLOR_YELLOW, COLOR_BLACK);
+ init_pair(16, COLOR_WHITE, COLOR_CYAN);
+ init_pair(17, COLOR_YELLOW, COLOR_CYAN);
+ init_pair(18, COLOR_GREEN, COLOR_BLACK);
+ init_pair(19, COLOR_WHITE, COLOR_BLUE);
+
+ STDATTR = COLOR_PAIR(14) | A_BOLD;
+ HIGHATTR = COLOR_PAIR(3) | A_BOLD;
+ BOXATTR = COLOR_PAIR(3);
+ ACTIVEATTR = COLOR_PAIR(10) | A_BOLD;
+ BARSTDATTR = COLOR_PAIR(15) | A_BOLD;
+ BARHIGHATTR = COLOR_PAIR(11) | A_BOLD;
+ BARPTRATTR = COLOR_PAIR(18) | A_BOLD;
+ DESCATTR = COLOR_PAIR(2);
+ DLGTEXTATTR = COLOR_PAIR(2);
+ DLGBOXATTR = COLOR_PAIR(6);
+ DLGHIGHATTR = COLOR_PAIR(12);
+ STATUSBARATTR = STDATTR;
+ IPSTATLABELATTR = COLOR_PAIR(2);
+ IPSTATATTR = COLOR_PAIR(12);
+ DESKTEXTATTR = COLOR_PAIR(7);
+ PTRATTR = COLOR_PAIR(10) | A_BOLD;
+ FIELDATTR = COLOR_PAIR(1);
+ ERRBOXATTR = COLOR_PAIR(5) | A_BOLD;
+ ERRTXTATTR = COLOR_PAIR(4) | A_BOLD;
+ OSPFATTR = COLOR_PAIR(2);
+ UDPATTR = COLOR_PAIR(9);
+ IGPATTR = COLOR_PAIR(12);
+ IGMPATTR = COLOR_PAIR(10) | A_BOLD;
+ IGRPATTR = COLOR_PAIR(16) | A_BOLD;
+ ARPATTR = COLOR_PAIR(5) | A_BOLD;
+ GREATTR = COLOR_PAIR(1);
+ UNKNIPATTR = COLOR_PAIR(19) | A_BOLD;
+ ICMPV6ATTR = COLOR_PAIR(19) | A_BOLD;
+ IPV6ATTR = COLOR_PAIR(19);
+ UNKNATTR = COLOR_PAIR(4) | A_BOLD;
+ } else {
+ STDATTR = A_REVERSE;
+ HIGHATTR = A_REVERSE;
+ BOXATTR = A_REVERSE;
+ ACTIVEATTR = A_BOLD;
+ BARSTDATTR = A_NORMAL;
+ BARHIGHATTR = A_BOLD;
+ BARPTRATTR = A_NORMAL;
+ DESCATTR = A_BOLD;
+ DLGBOXATTR = A_REVERSE;
+ DLGTEXTATTR = A_REVERSE;
+ DLGHIGHATTR = A_BOLD;
+ STATUSBARATTR = A_REVERSE;
+ IPSTATLABELATTR = A_REVERSE;
+ IPSTATATTR = A_STANDOUT;
+ DESKTEXTATTR = A_NORMAL;
+ PTRATTR = A_REVERSE;
+ FIELDATTR = A_BOLD;
+ ERRBOXATTR = A_BOLD;
+ ERRTXTATTR = A_NORMAL;
+ OSPFATTR = A_REVERSE;
+ UDPATTR = A_BOLD;
+ IGPATTR = A_REVERSE;
+ IGMPATTR = A_REVERSE;
+ IGRPATTR = A_REVERSE;
+ ARPATTR = A_BOLD;
+ GREATTR = A_BOLD;
+ UNKNIPATTR = A_BOLD;
+ ICMPV6ATTR = A_REVERSE;
+ UNKNATTR = A_BOLD;
+ }
+
+ tx_init_error_attrs(ERRBOXATTR, ERRTXTATTR, ERRBOXATTR);
+ tx_init_info_attrs(BOXATTR, STDATTR, HIGHATTR);
+}
diff --git a/src/deskman.h b/src/deskman.h
new file mode 100644
index 0000000..8827d09
--- /dev/null
+++ b/src/deskman.h
@@ -0,0 +1,26 @@
+#ifndef IPTRAF_NG_DESKMAN_H
+#define IPTRAF_NG_DESKMAN_H
+
+/*
+ deskman.h - header file for deskman.c
+ */
+
+void draw_desktop(void);
+void about(void);
+void printipcerr(void);
+void printkeyhelp(char *keytext, char *desc, WINDOW * win, int highattr,
+ int textattr);
+void stdkeyhelp(WINDOW * win);
+void sortkeyhelp(void);
+void tabkeyhelp(WINDOW * win);
+void scrollkeyhelp(void);
+void stdexitkeyhelp(void);
+void indicate(char *message);
+void printlargenum(unsigned long long i, WINDOW * win);
+void print_packet_drops(unsigned long count, WINDOW *win, int x);
+void set_next_screen_update(struct timespec *next_screen_update, struct timespec *now);
+void infobox(char *text, char *prompt);
+void standardcolors(int color);
+void show_sort_statwin(WINDOW **, PANEL **);
+
+#endif /* IPTRAF_NG_DESKMAN_H */
diff --git a/src/detstats.c b/src/detstats.c
new file mode 100644
index 0000000..7c5ff3f
--- /dev/null
+++ b/src/detstats.c
@@ -0,0 +1,671 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+/***
+
+detstats.c - the interface statistics module
+
+ ***/
+
+#include "iptraf-ng-compat.h"
+
+#include "tui/winops.h"
+
+#include "counters.h"
+#include "ifaces.h"
+#include "fltdefs.h"
+#include "packet.h"
+#include "options.h"
+#include "log.h"
+#include "dirs.h"
+#include "deskman.h"
+#include "attrs.h"
+#include "serv.h"
+#include "timer.h"
+#include "logvars.h"
+#include "error.h"
+#include "detstats.h"
+#include "rate.h"
+#include "capt.h"
+
+struct ifcounts {
+ struct proto_counter total;
+ struct pkt_counter bad;
+ struct proto_counter ipv4;
+ struct proto_counter ipv6;
+ struct proto_counter nonip;
+ struct proto_counter bcast;
+
+ struct proto_counter tcp;
+ struct proto_counter udp;
+ struct proto_counter icmp;
+ struct proto_counter other;
+
+ struct proto_counter span;
+ struct pkt_counter span_bcast;
+};
+
+struct ifrates {
+ struct rate rate;
+ struct rate rate_in;
+ struct rate rate_out;
+ struct rate rate_bcast;
+ unsigned long activity;
+ unsigned long peakactivity;
+ unsigned long activity_in;
+ unsigned long peakactivity_in;
+ unsigned long activity_out;
+ unsigned long peakactivity_out;
+ unsigned long activity_bcast;
+
+ struct rate pps_rate;
+ struct rate pps_rate_in;
+ struct rate pps_rate_out;
+ struct rate pps_rate_bcast;
+ unsigned long pps;
+ unsigned long peakpps;
+ unsigned long pps_in;
+ unsigned long peakpps_in;
+ unsigned long pps_out;
+ unsigned long peakpps_out;
+ unsigned long pps_bcast;
+};
+
+/* USR1 log-rotation signal handlers */
+static void rotate_dstat_log(int s __unused)
+{
+ rotate_flag = 1;
+ strcpy(target_logname, current_logfile);
+ signal(SIGUSR1, rotate_dstat_log);
+}
+
+static void writedstatlog(char *ifname, struct ifcounts *ts,
+ struct ifrates *ifrates, unsigned long nsecs, FILE *fd)
+{
+ char atime[TIME_TARGET_MAX];
+
+ genatime(time(NULL), atime);
+
+ fprintf(fd,
+ "\n*** Detailed statistics for interface %s, generated %s\n\n",
+ ifname, atime);
+
+ fprintf(fd, "Total: \t%llu packets, %llu bytes\n",
+ ts->total.proto_total.pc_packets,
+ ts->total.proto_total.pc_bytes);
+ fprintf(fd,
+ "\t(incoming: %llu packets, %llu bytes; outgoing: %llu packets, %llu bytes)\n",
+ ts->total.proto_in.pc_packets,
+ ts->total.proto_in.pc_bytes,
+ ts->total.proto_out.pc_packets,
+ ts->total.proto_out.pc_bytes);
+ fprintf(fd, "IP: \t%llu packets, %llu bytes\n",
+ ts->ipv4.proto_total.pc_packets,
+ ts->ipv4.proto_total.pc_bytes);
+ fprintf(fd,
+ "\t(incoming: %llu packets, %llu bytes; outgoing: %llu packets, %llu bytes)\n",
+ ts->ipv4.proto_in.pc_packets,
+ ts->ipv4.proto_in.pc_bytes,
+ ts->ipv4.proto_out.pc_packets,
+ ts->ipv4.proto_out.pc_bytes);
+ fprintf(fd, "TCP: %llu packets, %llu bytes\n",
+ ts->tcp.proto_total.pc_packets,
+ ts->tcp.proto_total.pc_bytes);
+ fprintf(fd,
+ "\t(incoming: %llu packets, %llu bytes; outgoing: %llu packets, %llu bytes)\n",
+ ts->tcp.proto_in.pc_packets,
+ ts->tcp.proto_in.pc_bytes,
+ ts->tcp.proto_out.pc_packets,
+ ts->tcp.proto_out.pc_bytes);
+ fprintf(fd, "UDP: %llu packets, %llu bytes\n",
+ ts->udp.proto_total.pc_packets,
+ ts->udp.proto_total.pc_bytes);
+ fprintf(fd,
+ "\t(incoming: %llu packets, %llu bytes; outgoing: %llu packets, %llu bytes)\n",
+ ts->udp.proto_in.pc_packets,
+ ts->udp.proto_in.pc_bytes,
+ ts->udp.proto_out.pc_packets,
+ ts->udp.proto_out.pc_bytes);
+ fprintf(fd, "ICMP: %llu packets, %llu bytes\n",
+ ts->icmp.proto_total.pc_packets,
+ ts->icmp.proto_total.pc_bytes);
+ fprintf(fd,
+ "\t(incoming: %llu packets, %llu bytes; outgoing: %llu packets, %llu bytes)\n",
+ ts->icmp.proto_in.pc_packets,
+ ts->icmp.proto_in.pc_bytes,
+ ts->icmp.proto_out.pc_packets,
+ ts->icmp.proto_out.pc_bytes);
+ fprintf(fd, "Other IP: %llu packets, %llu bytes\n",
+ ts->other.proto_total.pc_packets,
+ ts->other.proto_total.pc_bytes);
+ fprintf(fd,
+ "\t(incoming: %llu packets, %llu bytes; outgoing: %llu packets, %llu bytes)\n",
+ ts->other.proto_in.pc_packets,
+ ts->other.proto_in.pc_bytes,
+ ts->other.proto_out.pc_packets,
+ ts->other.proto_out.pc_bytes);
+ fprintf(fd, "Non-IP: %llu packets, %llu bytes\n",
+ ts->nonip.proto_total.pc_packets,
+ ts->nonip.proto_total.pc_bytes);
+ fprintf(fd,
+ "\t(incoming: %llu packets, %llu bytes; outgoing: %llu packets, %llu bytes)\n",
+ ts->nonip.proto_in.pc_packets,
+ ts->nonip.proto_in.pc_bytes,
+ ts->nonip.proto_out.pc_packets,
+ ts->nonip.proto_out.pc_bytes);
+ fprintf(fd, "Broadcast: %llu packets, %llu bytes\n",
+ ts->bcast.proto_total.pc_packets,
+ ts->bcast.proto_total.pc_bytes);
+
+ if (nsecs > 5) {
+ char bps_string[64];
+ char pps_string[64];
+
+ fprintf(fd, "\nAverage rates:\n");
+
+ rate_print(ts->total.proto_total.pc_bytes / nsecs, bps_string, sizeof(bps_string));
+ rate_print_pps(ts->total.proto_total.pc_packets / nsecs, pps_string, sizeof(pps_string));
+ fprintf(fd, " Total:\t%s, %s\n", bps_string, pps_string);
+ rate_print(ts->total.proto_in.pc_bytes / nsecs, bps_string, sizeof(bps_string));
+ rate_print_pps(ts->total.proto_in.pc_packets / nsecs, pps_string, sizeof(pps_string));
+ fprintf(fd, " Incoming:\t%s, %s\n", bps_string, pps_string);
+ rate_print(ts->total.proto_out.pc_bytes / nsecs, bps_string, sizeof(bps_string));
+ rate_print_pps(ts->total.proto_out.pc_packets / nsecs, pps_string, sizeof(pps_string));
+ fprintf(fd, " Outgoing:\t%s, %s\n", bps_string, pps_string);
+ rate_print(ifrates->peakactivity, bps_string, sizeof(bps_string));
+ rate_print_pps(ifrates->peakpps, pps_string, sizeof(pps_string));
+ fprintf(fd, "\nPeak total activity: %s, %s\n", bps_string, pps_string);
+ rate_print(ifrates->peakactivity_in, bps_string, sizeof(bps_string));
+ rate_print_pps(ifrates->peakpps_in, pps_string, sizeof(pps_string));
+ fprintf(fd, "Peak incoming rate: %s, %s\n", bps_string, pps_string);
+ rate_print(ifrates->peakactivity_out, bps_string, sizeof(bps_string));
+ rate_print_pps(ifrates->peakpps_out, pps_string, sizeof(pps_string));
+ fprintf(fd, "Peak outgoing rate: %s, %s\n\n", bps_string, pps_string);
+ }
+ fprintf(fd, "IP checksum errors: %llu\n\n", ts->bad.pc_packets);
+ fprintf(fd, "Running time: %lu seconds\n", nsecs);
+ fflush(fd);
+}
+
+static void ifcounts_init(struct ifcounts *ifcounts)
+{
+ if (ifcounts == NULL)
+ return;
+
+ proto_counter_reset(&ifcounts->total);
+ pkt_counter_reset(&ifcounts->bad);
+ proto_counter_reset(&ifcounts->ipv4);
+ proto_counter_reset(&ifcounts->ipv6);
+ proto_counter_reset(&ifcounts->nonip);
+ proto_counter_reset(&ifcounts->bcast);
+
+ proto_counter_reset(&ifcounts->tcp);
+ proto_counter_reset(&ifcounts->udp);
+ proto_counter_reset(&ifcounts->icmp);
+ proto_counter_reset(&ifcounts->other);
+
+ proto_counter_reset(&ifcounts->span);
+ pkt_counter_reset(&ifcounts->span_bcast);
+}
+
+static void ifcounts_destroy(struct ifcounts *ifcounts __unused)
+{
+ /* do nothing for now */
+}
+
+static void ifrates_init(struct ifrates *ifrates)
+{
+ if (ifrates == NULL)
+ return;
+
+ rate_alloc(&ifrates->rate, 5);
+ rate_alloc(&ifrates->rate_in, 5);
+ rate_alloc(&ifrates->rate_out, 5);
+ rate_alloc(&ifrates->rate_bcast, 5);
+
+ ifrates->activity = 0UL;
+ ifrates->peakactivity = 0UL;
+ ifrates->activity_in = 0UL;
+ ifrates->peakactivity_in = 0UL;
+ ifrates->activity_out = 0UL;
+ ifrates->peakactivity_out = 0UL;
+ ifrates->activity_bcast = 0UL;
+
+ rate_alloc(&ifrates->pps_rate, 5);
+ rate_alloc(&ifrates->pps_rate_in, 5);
+ rate_alloc(&ifrates->pps_rate_out, 5);
+ rate_alloc(&ifrates->pps_rate_bcast, 5);
+
+ ifrates->pps = 0UL;
+ ifrates->peakpps = 0UL;
+ ifrates->pps_in = 0UL;
+ ifrates->peakpps_in = 0UL;
+ ifrates->pps_out = 0UL;
+ ifrates->peakpps_out = 0UL;
+ ifrates->pps_bcast = 0UL;
+}
+
+static void ifrates_destroy(struct ifrates *ifrates)
+{
+ if (ifrates == NULL)
+ return;
+
+ rate_destroy(&ifrates->pps_rate_bcast);
+ rate_destroy(&ifrates->pps_rate_out);
+ rate_destroy(&ifrates->pps_rate_in);
+ rate_destroy(&ifrates->pps_rate);
+
+ rate_destroy(&ifrates->rate_bcast);
+ rate_destroy(&ifrates->rate_out);
+ rate_destroy(&ifrates->rate_in);
+ rate_destroy(&ifrates->rate);
+}
+
+static void ifrates_update(struct ifrates *ifrates, struct ifcounts *ifcounts,
+ unsigned long msecs)
+{
+ rate_add_rate(&ifrates->rate, ifcounts->span.proto_total.pc_bytes, msecs);
+ ifrates->activity = rate_get_average(&ifrates->rate);
+ rate_add_rate(&ifrates->rate_in, ifcounts->span.proto_in.pc_bytes, msecs);
+ ifrates->activity_in = rate_get_average(&ifrates->rate_in);
+ rate_add_rate(&ifrates->rate_out, ifcounts->span.proto_out.pc_bytes, msecs);
+ ifrates->activity_out = rate_get_average(&ifrates->rate_out);
+ rate_add_rate(&ifrates->rate_bcast, ifcounts->span_bcast.pc_bytes, msecs);
+ ifrates->activity_bcast = rate_get_average(&ifrates->rate_bcast);
+
+ rate_add_rate(&ifrates->pps_rate, ifcounts->span.proto_total.pc_packets, msecs);
+ ifrates->pps = rate_get_average(&ifrates->pps_rate);
+ rate_add_rate(&ifrates->pps_rate_in, ifcounts->span.proto_in.pc_packets, msecs);
+ ifrates->pps_in = rate_get_average(&ifrates->pps_rate_in);
+ rate_add_rate(&ifrates->pps_rate_out, ifcounts->span.proto_out.pc_packets, msecs);
+ ifrates->pps_out = rate_get_average(&ifrates->pps_rate_out);
+ rate_add_rate(&ifrates->pps_rate_bcast, ifcounts->span_bcast.pc_packets, msecs);
+ ifrates->pps_bcast = rate_get_average(&ifrates->pps_rate_bcast);
+
+ proto_counter_reset(&ifcounts->span);
+ pkt_counter_reset(&ifcounts->span_bcast);
+
+ if (ifrates->activity > ifrates->peakactivity)
+ ifrates->peakactivity = ifrates->activity;
+
+ if (ifrates->activity_in > ifrates->peakactivity_in)
+ ifrates->peakactivity_in = ifrates->activity_in;
+
+ if (ifrates->activity_out > ifrates->peakactivity_out)
+ ifrates->peakactivity_out = ifrates->activity_out;
+
+ if (ifrates->pps > ifrates->peakpps)
+ ifrates->peakpps = ifrates->pps;
+
+ if (ifrates->pps_in > ifrates->peakpps_in)
+ ifrates->peakpps_in = ifrates->pps_in;
+
+ if (ifrates->pps_out > ifrates->peakpps_out)
+ ifrates->peakpps_out = ifrates->pps_out;
+}
+
+static void ifrates_show(struct ifrates *ifrates, WINDOW *statwin)
+{
+ char buf[64];
+
+ wattrset(statwin, HIGHATTR);
+ rate_print(ifrates->activity, buf, sizeof(buf));
+ mvwprintw(statwin, 14, 19, "%s", buf);
+ rate_print_pps(ifrates->pps, buf, sizeof(buf));
+ mvwprintw(statwin, 15, 19, "%s", buf);
+ rate_print(ifrates->activity_in, buf, sizeof(buf));
+ mvwprintw(statwin, 17, 19, "%s", buf);
+ rate_print_pps(ifrates->pps_in, buf, sizeof(buf));
+ mvwprintw(statwin, 18, 19, "%s", buf);
+ rate_print(ifrates->activity_out, buf, sizeof(buf));
+ mvwprintw(statwin, 20, 19, "%s", buf);
+ rate_print_pps(ifrates->pps_out, buf, sizeof(buf));
+ mvwprintw(statwin, 21, 19, "%s", buf);
+ rate_print(ifrates->activity_bcast, buf, sizeof(buf));
+ mvwprintw(statwin, 14, 64, "%s", buf);
+ rate_print_pps(ifrates->pps_bcast, buf, sizeof(buf));
+ mvwprintw(statwin, 15, 64, "%s", buf);
+}
+
+static void printdetlabels(WINDOW * win)
+{
+ wattrset(win, BOXATTR);
+ mvwprintw(win, 2, 14,
+ " Total Total Incoming Incoming Outgoing Outgoing");
+ mvwprintw(win, 3, 14,
+ "Packets Bytes Packets Bytes Packets Bytes");
+ wattrset(win, STDATTR);
+ mvwprintw(win, 4, 2, "Total:");
+ mvwprintw(win, 5, 2, "IPv4:");
+ mvwprintw(win, 6, 2, "IPv6:");
+ mvwprintw(win, 7, 2, "TCP:");
+ mvwprintw(win, 8, 2, "UDP:");
+ mvwprintw(win, 9, 2, "ICMP:");
+ mvwprintw(win, 10, 2, "Other IP:");
+ mvwprintw(win, 11, 2, "Non-IP:");
+ mvwprintw(win, 12, 2, "Broadcast:");
+ mvwprintw(win, 14, 2, "Total rates:");
+ mvwprintw(win, 17, 2, "Incoming rates:");
+ mvwprintw(win, 20, 2, "Outgoing rates:");
+
+ mvwprintw(win, 14, 45, "Broadcast rates:");
+ mvwprintw(win, 19, 45, "IP checksum errors:");
+
+ update_panels();
+ doupdate();
+}
+
+static void printstatrow(WINDOW * win, int row, unsigned long long total,
+ unsigned long long btotal, unsigned long long total_in,
+ unsigned long long btotal_in, unsigned long long total_out,
+ unsigned long long btotal_out)
+{
+ wmove(win, row, 12);
+ printlargenum(total, win);
+ wmove(win, row, 23);
+ printlargenum(btotal, win);
+ wmove(win, row, 35);
+ printlargenum(total_in, win);
+ wmove(win, row, 46);
+ printlargenum(btotal_in, win);
+ wmove(win, row, 58);
+ printlargenum(total_out, win);
+ wmove(win, row, 69);
+ printlargenum(btotal_out, win);
+}
+
+static void printstatrow_proto(WINDOW *win, int row, struct proto_counter *proto_counter)
+{
+ printstatrow(win, row,
+ proto_counter->proto_total.pc_packets,
+ proto_counter->proto_total.pc_bytes,
+ proto_counter->proto_in.pc_packets,
+ proto_counter->proto_in.pc_bytes,
+ proto_counter->proto_out.pc_packets,
+ proto_counter->proto_out.pc_bytes);
+}
+
+static void printdetails(struct ifcounts *ifcounts, WINDOW * win)
+{
+ wattrset(win, HIGHATTR);
+ /* Print totals on the IP protocols */
+ printstatrow_proto(win, 4, &ifcounts->total);
+ printstatrow_proto(win, 5, &ifcounts->ipv4);
+ printstatrow_proto(win, 6, &ifcounts->ipv6);
+ printstatrow_proto(win, 7, &ifcounts->tcp);
+ printstatrow_proto(win, 8, &ifcounts->udp);
+ printstatrow_proto(win, 9, &ifcounts->icmp);
+ printstatrow_proto(win, 10, &ifcounts->other);
+
+ /* Print non-IP totals */
+ printstatrow_proto(win, 11, &ifcounts->nonip);
+
+ /* Print broadcast totals */
+ printstatrow_proto(win, 12, &ifcounts->bcast);
+
+
+ /* Bad packet count */
+
+ mvwprintw(win, 19, 65, "%8lu", ifcounts->bad.pc_packets);
+}
+
+static void detstats_process_key(int ch)
+{
+ switch (ch) {
+ case 12:
+ case 'l':
+ case 'L':
+ tx_refresh_screen();
+ break;
+ case 'Q':
+ case 'q':
+ case 'X':
+ case 'x':
+ case 24:
+ case 27:
+ exitloop = 1;
+ break;
+ case ERR:
+ /* no key ready, do nothing */
+ /* fall through */
+ default:
+ /* do nothing */
+ break;
+ }
+}
+
+static void detstats_process_packet(struct ifcounts *ifcounts, struct pkt_hdr *pkt)
+{
+ int pkt_result = packet_process(pkt, NULL, NULL, NULL,
+ MATCH_OPPOSITE_USECONFIG,
+ options.v6inv4asv6);
+
+ switch (pkt_result) {
+ case PACKET_OK: /* we only handle these */
+ case MORE_FRAGMENTS:
+ case CHECKSUM_ERROR:
+ break;
+ default: /* drop others */
+ return;
+ }
+
+ int outgoing = (pkt->from->sll_pkttype == PACKET_OUTGOING);
+ proto_counter_update(&ifcounts->total, outgoing, pkt->pkt_len);
+ if (pkt->from->sll_pkttype == PACKET_BROADCAST) {
+ proto_counter_update(&ifcounts->bcast, outgoing, pkt->pkt_len);
+ pkt_counter_update(&ifcounts->span_bcast, pkt->pkt_len);
+ }
+
+ proto_counter_update(&ifcounts->span, outgoing, pkt->pkt_len);
+
+ unsigned int iplen = 0;
+
+ /* account network layer protocol */
+ switch(pkt->pkt_protocol) {
+ case ETH_P_IP:
+ if (pkt_result == CHECKSUM_ERROR) {
+ pkt_counter_update(&ifcounts->bad, pkt->pkt_len);
+ return;
+ }
+
+ iplen = ntohs(pkt->iphdr->tot_len);
+
+ proto_counter_update(&ifcounts->ipv4, outgoing, iplen);
+ break;
+ case ETH_P_IPV6:
+ iplen = ntohs(pkt->ip6_hdr->ip6_plen) + 40;
+
+ proto_counter_update(&ifcounts->ipv6, outgoing, iplen);
+ break;
+ default:
+ proto_counter_update(&ifcounts->nonip, outgoing, pkt->pkt_len);
+ return;
+ }
+
+ __u8 ip_protocol = pkt_ip_protocol(pkt);
+
+ /* account transport layer protocol */
+ switch (ip_protocol) {
+ case IPPROTO_TCP:
+ proto_counter_update(&ifcounts->tcp, outgoing, iplen);
+ break;
+ case IPPROTO_UDP:
+ proto_counter_update(&ifcounts->udp, outgoing, iplen);
+ break;
+ case IPPROTO_ICMP:
+ case IPPROTO_ICMPV6:
+ proto_counter_update(&ifcounts->icmp, outgoing, iplen);
+ break;
+ default:
+ proto_counter_update(&ifcounts->other, outgoing, iplen);
+ break;
+ }
+}
+
+/* detailed interface statistics function */
+void detstats(char *iface, time_t facilitytime)
+{
+ int logging = options.logging;
+
+ WINDOW *statwin;
+ PANEL *statpanel;
+
+ FILE *logfile = NULL;
+
+ struct ifcounts ifcounts;
+ struct ifrates ifrates;
+
+ int ch;
+
+ struct capt capt;
+
+ struct pkt_hdr pkt;
+
+ if (!dev_up(iface)) {
+ err_iface_down();
+ return;
+ }
+
+ move(LINES - 1, 1);
+ stdexitkeyhelp();
+ statwin = newwin(LINES - 2, COLS, 1, 0);
+ statpanel = new_panel(statwin);
+ tx_stdwinset(statwin);
+ wtimeout(statwin, -1);
+ wattrset(statwin, BOXATTR);
+ tx_colorwin(statwin);
+ tx_box(statwin, ACS_VLINE, ACS_HLINE);
+ wmove(statwin, 0, 1);
+ wprintw(statwin, " Statistics for %s ", iface);
+ wattrset(statwin, STDATTR);
+ leaveok(statwin, TRUE);
+
+ update_panels();
+ doupdate();
+
+ if (capt_init(&capt, iface) == -1) {
+ write_error("Unable to initialize packet capture interface");
+ goto err;
+ }
+
+ ifcounts_init(&ifcounts);
+ ifrates_init(&ifrates);
+
+ if (logging) {
+ if (strcmp(current_logfile, "") == 0) {
+ snprintf(current_logfile, 64, "%s-%s.log", DSTATLOG,
+ iface);
+
+ if (!daemonized)
+ input_logfile(current_logfile, &logging);
+ }
+ }
+
+ if (logging) {
+ opentlog(&logfile, current_logfile);
+
+ if (logfile == NULL)
+ logging = 0;
+ }
+ if (logging) {
+ signal(SIGUSR1, rotate_dstat_log);
+
+ rotate_flag = 0;
+ writelog(logging, logfile,
+ "******** Detailed interface statistics started ********");
+ }
+
+ printdetlabels(statwin);
+ printdetails(&ifcounts, statwin);
+ update_panels();
+ doupdate();
+
+ packet_init(&pkt);
+
+ exitloop = 0;
+
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ struct timespec last_time = now;
+ struct timespec next_screen_update = { 0 };
+
+ time_t starttime = now.tv_sec;
+ time_t endtime = INT_MAX;
+ if (facilitytime != 0)
+ endtime = now.tv_sec + facilitytime * 60;
+
+ time_t log_next = INT_MAX;
+ if (logging)
+ log_next = now.tv_sec + options.logspan;
+
+ /* data-gathering loop */
+ while (!exitloop) {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ if (now.tv_sec > last_time.tv_sec) {
+ unsigned long msecs = timespec_diff_msec(&now, &last_time);
+ ifrates_update(&ifrates, &ifcounts, msecs);
+ ifrates_show(&ifrates, statwin);
+
+ wattrset(statwin, BOXATTR);
+ printelapsedtime(now.tv_sec - starttime, 1, statwin);
+
+ print_packet_drops(capt_get_dropped(&capt), statwin, 49);
+
+ if (now.tv_sec > endtime)
+ exitloop = 1;
+
+ if (logging && (now.tv_sec > log_next)) {
+ check_rotate_flag(&logfile);
+ writedstatlog(iface, &ifcounts, &ifrates,
+ now.tv_sec - starttime,
+ logfile);
+ log_next = now.tv_sec + options.logspan;
+ }
+
+ last_time = now;
+ }
+ if (time_after(&now, &next_screen_update)) {
+ printdetails(&ifcounts, statwin);
+ update_panels();
+ doupdate();
+
+ set_next_screen_update(&next_screen_update, &now);
+ }
+
+ if (capt_get_packet(&capt, &pkt, &ch, statwin) == -1) {
+ write_error("Packet receive failed");
+ exitloop = 1;
+ break;
+ }
+
+ if (ch != ERR)
+ detstats_process_key(ch);
+
+ if (pkt.pkt_len > 0) {
+ detstats_process_packet(&ifcounts, &pkt);
+ capt_put_packet(&capt, &pkt);
+ }
+
+ }
+ packet_destroy(&pkt);
+
+ if (logging) {
+ signal(SIGUSR1, SIG_DFL);
+ writedstatlog(iface, &ifcounts, &ifrates,
+ time(NULL) - starttime, logfile);
+ writelog(logging, logfile,
+ "******** Detailed interface statistics stopped ********");
+ fclose(logfile);
+ }
+ strcpy(current_logfile, "");
+
+ ifrates_destroy(&ifrates);
+ ifcounts_destroy(&ifcounts);
+ capt_destroy(&capt);
+err:
+ del_panel(statpanel);
+ delwin(statwin);
+ update_panels();
+ doupdate();
+}
diff --git a/src/detstats.h b/src/detstats.h
new file mode 100644
index 0000000..95cbea8
--- /dev/null
+++ b/src/detstats.h
@@ -0,0 +1,6 @@
+#ifndef IPTRAF_NG_DETSTATS_H
+#define IPTRAF_NG_DETSTATS_H
+
+void detstats(char *iface, time_t facilitytime);
+
+#endif /* IPTRAF_NG_DETSTATS_H */
diff --git a/src/dirs.h b/src/dirs.h
new file mode 100644
index 0000000..6bb09af
--- /dev/null
+++ b/src/dirs.h
@@ -0,0 +1,139 @@
+#ifndef IPTRAF_NG_DIRS_H
+#define IPTRAF_NG_DIRS_H
+
+// TODO: full rewrite
+
+#include "getpath.h"
+
+/*
+ * IPTraf working file and directory definitions
+ */
+
+
+/***
+ *** Directory definitions. The definitions in the Makefile now override
+ *** these directives.
+ ***/
+
+/*
+ * The IPTraf working directory
+ */
+
+#ifndef WORKDIR
+#define WORKDIR "/var/lib/iptraf-ng"
+#endif
+
+#ifndef LOGDIR
+#define LOGDIR "/var/log/iptraf-ng"
+#endif
+
+/*
+ * Lock directory.
+ *
+ * !!!!!!! WARNING !!!!!!!!
+ * DO NOT LET THIS REFER TO AN EXISTING/SYSTEM DIRECTORY!!!! THE LOCK
+ * OVERRIDE (iptraf -f) WILL ERASE ALL FILES HERE!
+ */
+
+#ifndef LOCKDIR
+#define LOCKDIR "/var/lock/iptraf-ng"
+#endif
+
+/***
+ *** Directory environment variables. Overrides built in definitions.
+ *** You may suit this to your preferences.
+ ***/
+
+/*
+ * Environment variable for IPTraf working directory. Overrides builtin.
+ */
+
+#define WORKDIR_ENV "IPTRAF_WORK_PATH"
+
+/*
+ * Environment variable for LOGDIR
+ */
+
+#define LOGDIR_ENV "IPTRAF_LOG_PATH"
+
+/***
+ *** Filename definitions. They depend on the directory definitions
+ *** above.
+ ***/
+
+/*
+ * The IPTraf instance identification file. IPTraf is running if this
+ * file is present, and is deleted afterwards. As of this version, this
+ * file is used to restrict configuration to only the first instance.
+ */
+
+#define IPTIDFILE get_path(T_LOCKDIR, "iptraf.tag")
+
+/*
+ * The IPTraf facility identification files. These are used to identify which
+ * facilities are running, allowing only one instance any of them to run
+ * on a network interface.
+ */
+
+#define IPMONIDFILE get_path(T_LOCKDIR, "iptraf-ipmon.tag")
+#define GSTATIDFILE get_path(T_LOCKDIR, "iptraf-genstat.tag")
+#define DSTATIDFILE get_path(T_LOCKDIR, "iptraf-detstat.tag")
+#define TCPUDPIDFILE get_path(T_LOCKDIR, "iptraf-tcpudp.tag")
+#define LANMONIDFILE get_path(T_LOCKDIR, "iptraf-lanmon.tag")
+#define FLTIDFILE get_path(T_LOCKDIR, "iptraf-filters.tag")
+#define OTHIPFLTIDFILE get_path(T_LOCKDIR, "iptraf-othipfltchg.tag")
+#define PKTSIZEIDFILE get_path(T_LOCKDIR, "iptraf-packetsize.tag")
+#define PROCCOUNTFILE get_path(T_LOCKDIR, "iptraf-processcount.dat")
+#define ITRAFMONCOUNTFILE get_path(T_LOCKDIR, "iptraf-itrafmoncount.dat")
+#define LANMONCOUNTFILE get_path(T_LOCKDIR, "iptraf-lanmoncount.dat")
+#define PROMISCLISTFILE get_path(T_WORKDIR, "iptraf-promisclist.tmp")
+
+#define OTHIPFLNAME get_path(T_WORKDIR, "othipfilters.dat")
+
+/*
+ * The filter data file for other protocols
+ */
+
+#define FLTSTATEFILE get_path(T_WORKDIR, "savedfilters.dat")
+
+/*
+ * The IPTraf configuration data file
+ */
+
+#define CONFIGFILE get_path(T_WORKDIR, "iptraf.cfg")
+
+/*
+ * The IPTraf log files
+ */
+
+#define IPMONLOG get_path(T_LOGDIR, "ip_traffic")
+#define GSTATLOG get_path(T_LOGDIR, "iface_stats_general.log")
+#define DSTATLOG get_path(T_LOGDIR, "iface_stats_detailed")
+#define TCPUDPLOG get_path(T_LOGDIR, "tcp_udp_services")
+#define LANLOG get_path(T_LOGDIR, "lan_statistics")
+#define PKTSIZELOG get_path(T_LOGDIR, "packet_size")
+#define DAEMONLOG get_path(T_LOGDIR, "daemon.log")
+
+
+/*
+ * The additional TCP/UDP ports file
+ */
+#define PORTFILE get_path(T_WORKDIR, "ports.dat")
+
+/*
+ * The Ethernet and FDDI host description files
+ */
+
+#define ETHFILE get_path(T_WORKDIR, "ethernet.desc")
+#define FDDIFILE get_path(T_WORKDIR, "fddi.desc")
+
+/*
+ * The rvnamed log file
+ */
+#define RVNDLOGFILE get_path(T_LOGDIR, "rvnamed-ng.log")
+
+#ifndef PATH_MAX
+#define PATH_MAX 4095
+#endif
+
+#endif /* IPTRAF_NG_DIRS_H */
diff --git a/src/error.c b/src/error.c
new file mode 100644
index 0000000..91fbd17
--- /dev/null
+++ b/src/error.c
@@ -0,0 +1,25 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+/***
+
+error.c - Error-handling subroutines
+
+***/
+
+#include "iptraf-ng-compat.h"
+
+#include "log.h"
+#include "tui/msgboxes.h"
+
+void write_error(char *msg, ...)
+{
+ va_list vararg;
+
+ va_start(vararg, msg);
+ if (daemonized)
+ write_daemon_err(msg, vararg);
+ else
+ tui_error_va(ANYKEY_MSG, msg, vararg);
+ va_end(vararg);
+}
diff --git a/src/error.h b/src/error.h
new file mode 100644
index 0000000..73dbb29
--- /dev/null
+++ b/src/error.h
@@ -0,0 +1,6 @@
+#ifndef IPTRAF_NG_ERROR_H
+#define IPTRAF_NG_ERROR_H
+
+void write_error(char *msg, ...) __printf(1,2);
+
+#endif /* IPTRAF_NG_ERROR_H */
diff --git a/src/fltdefs.h b/src/fltdefs.h
new file mode 100644
index 0000000..cc0512f
--- /dev/null
+++ b/src/fltdefs.h
@@ -0,0 +1,70 @@
+#ifndef IPTRAF_NG_FLTDEFS_H
+#define IPTRAF_NG_FLTDEFS_H
+
+/***
+
+fltdefs.h - declarations for the TCP, UDP, and misc IP filters
+
+***/
+
+
+#define FLT_FILENAME_MAX 40
+
+#define FLT_RESOLVE 1
+#define FLT_DONTRESOLVE 0
+
+#define F_ALL_IP 0
+#define F_TCP 6
+#define F_UDP 17
+#define F_OTHERIP 59
+#define F_ICMP 1
+#define F_IGMP 2
+#define F_OSPF 89
+#define F_IGP 9
+#define F_IGRP 88
+#define F_GRE 47
+#define F_L2TP 115
+#define F_IPSEC_AH 51
+#define F_IPSEC_ESP 50
+
+#define MATCH_OPPOSITE_ALWAYS 1
+#define MATCH_OPPOSITE_USECONFIG 2
+
+/*
+ * IP filter parameter entry
+ */
+struct hostparams {
+ char s_fqdn[45];
+ char d_fqdn[45];
+ char s_mask[20];
+ char d_mask[20];
+ in_port_t sport1;
+ in_port_t sport2;
+ in_port_t dport1;
+ in_port_t dport2;
+ int filters[256];
+ char protolist[70];
+ char reverse;
+ char match_opposite;
+};
+
+
+struct filterent {
+ struct hostparams hp;
+
+ unsigned long saddr;
+ unsigned long daddr;
+ unsigned long smask;
+ unsigned long dmask;
+ unsigned int index;
+ struct filterent *next_entry;
+ struct filterent *prev_entry;
+};
+
+struct filterlist {
+ struct filterent *head;
+ struct filterent *tail;
+ unsigned int lastpos;
+};
+
+#endif /* IPTRAF_NG_FLTDEFS_H */
diff --git a/src/fltedit.c b/src/fltedit.c
new file mode 100644
index 0000000..300487f
--- /dev/null
+++ b/src/fltedit.c
@@ -0,0 +1,617 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+/***
+
+fltedit.c - the filter editing Facility
+
+***/
+
+#include "iptraf-ng-compat.h"
+
+#include "tui/labels.h"
+#include "tui/menurt.h"
+#include "tui/msgboxes.h"
+#include "tui/winops.h"
+
+#include "fltdefs.h"
+#include "fltmgr.h"
+#include "ipfilter.h"
+#include "dirs.h"
+#include "getpath.h"
+#include "attrs.h"
+#include "deskman.h"
+#include "error.h"
+#include "cidr.h"
+
+void init_filter_table(struct filterlist *fl)
+{
+ fl->head = fl->tail = NULL;
+}
+
+/*
+ * Loads the filter from the filter file
+ */
+
+int loadfilter(char *filename, struct filterlist *fl, int resolve)
+{
+ struct filterent *fe;
+ int pfd;
+ unsigned int idx = 0;
+ int br;
+ int resolv_err = 0;
+
+ init_filter_table(fl);
+
+ pfd = open(filename, O_RDONLY);
+
+ if (pfd < 0) {
+ write_error("Error opening IP filter data file");
+ fl->head = NULL;
+ return 1;
+ }
+ do {
+ fe = xmalloc(sizeof(struct filterent));
+ br = read(pfd, &(fe->hp), sizeof(struct hostparams));
+
+ if (br > 0) {
+ fe->index = idx;
+ if (resolve) {
+ fe->saddr =
+ nametoaddr(fe->hp.s_fqdn, &resolv_err);
+ fe->daddr =
+ nametoaddr(fe->hp.d_fqdn, &resolv_err);
+
+ if (resolv_err) {
+ free(fe);
+ continue;
+ }
+
+ fe->smask = inet_addr(fe->hp.s_mask);
+ fe->dmask = inet_addr(fe->hp.d_mask);
+ }
+ if (fl->head == NULL) {
+ fl->head = fe;
+ fe->prev_entry = NULL;
+ } else {
+ fl->tail->next_entry = fe;
+ fe->prev_entry = fl->tail;
+ }
+ fe->next_entry = NULL;
+ fl->tail = fe;
+ idx++;
+ } else {
+ free(fe);
+ }
+ } while (br > 0);
+
+ if (br == 0)
+ close(pfd);
+
+ return 0;
+}
+
+void savefilter(char *filename, struct filterlist *fl)
+{
+ struct filterent *fe = fl->head;
+ int pfd;
+ int bw;
+
+ pfd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR);
+
+ while (fe != NULL) {
+ bw = write(pfd, &(fe->hp), sizeof(struct hostparams));
+
+ if (bw < 0) {
+ tui_error(ANYKEY_MSG, "Unable to save filter changes");
+ return;
+ }
+ fe = fe->next_entry;
+ }
+
+ close(pfd);
+}
+
+void print_hostparam_line(struct filterent *fe, int idx, WINDOW * win, int attr)
+{
+ struct in_addr binmask;
+
+ wattrset(win, attr);
+
+ scrollok(win, 0);
+ mvwprintw(win, idx, 0, "%78c", ' ');
+
+ mvwaddnstr(win, idx, 1, fe->hp.s_fqdn, 20);
+ if (inet_aton(fe->hp.s_mask, &binmask) == 0)
+ inet_aton("255.255.255.255", &binmask);
+
+ wprintw(win, "/%u", cidr_get_maskbits(binmask.s_addr));
+ if (fe->hp.sport2 == 0)
+ wprintw(win, ":%u", fe->hp.sport1);
+ else
+ wprintw(win, ":%u-%u", fe->hp.sport1, fe->hp.sport2);
+
+ wmove(win, idx, 34);
+ if (fe->hp.match_opposite != 'Y')
+ wprintw(win, "-->");
+ else
+ wprintw(win, "<->");
+
+ mvwaddnstr(win, idx, 38, fe->hp.d_fqdn, 15);
+
+ if (inet_aton(fe->hp.d_mask, &binmask) == 0)
+ inet_aton("255.255.255.255", &binmask);
+
+ wprintw(win, "/%u", cidr_get_maskbits(binmask.s_addr));
+
+ if (fe->hp.dport2 == 0)
+ wprintw(win, ":%u", fe->hp.dport1);
+ else
+ wprintw(win, ":%u-%u", fe->hp.dport1, fe->hp.dport2);
+
+ mvwprintw(win, idx, 76, "%c", toupper(fe->hp.reverse));
+ wmove(win, idx, 0);
+}
+
+void update_hp_screen(struct filterent *firstvisible, WINDOW * win)
+{
+ struct filterent *ftmp = firstvisible;
+ int i;
+
+ wattrset(win, STDATTR);
+ if (firstvisible == NULL) {
+ mvwprintw(win, 0, 0, "%78c", ' ');
+ wmove(win, 0, 0);
+ return;
+ }
+
+ scrollok(win, 0);
+ for (i = 0; i <= 12; i++) {
+ if (ftmp != NULL) {
+ print_hostparam_line(ftmp, i, win, STDATTR);
+ ftmp = ftmp->next_entry;
+ } else {
+ mvwprintw(win, i, 0, "%78c", ' ');
+ wmove(win, i, 0);
+ }
+ }
+ scrollok(win, 1);
+}
+
+void modify_host_parameters(struct filterlist *fl)
+{
+ WINDOW *bwin;
+ PANEL *bpanel;
+ WINDOW *win;
+ PANEL *panel;
+ struct filterent *fe;
+ struct filterent *ftemp;
+
+ struct filterent *firstvisible = NULL;
+
+ unsigned int idx = 0;
+ int endloop_local = 0;
+ int ch;
+ int gh_aborted = 0;
+
+ char s_portstr1[8];
+ char d_portstr1[8];
+ char s_portstr2[8];
+ char d_portstr2[8];
+
+ char inexstr[2];
+ char matchop[2];
+
+ bwin = newwin(15, 80, (LINES - 15) / 2, (COLS - 80) / 2);
+
+ bpanel = new_panel(bwin);
+ win = newwin(13, 78, (LINES - 13) / 2, (COLS - 78) / 2);
+ panel = new_panel(win);
+
+ wattrset(bwin, BOXATTR);
+ tx_box(bwin, ACS_VLINE, ACS_HLINE);
+
+ mvwprintw(bwin, 0, 2, " Source ");
+ mvwprintw(bwin, 0, 38, " Destination ");
+ mvwprintw(bwin, 0, 74, " I/E ");
+
+ mvwprintw(bwin, 14, 1, " Filter Data ");
+ tx_stdwinset(win);
+ scrollok(win, 0);
+ wattrset(win, STDATTR);
+ tx_colorwin(win);
+
+ move(LINES - 1, 1);
+ tx_printkeyhelp("Up/Down", "-move ptr ", stdscr, HIGHATTR,
+ STATUSBARATTR);
+ tx_printkeyhelp("I", "-insert ", stdscr, HIGHATTR, STATUSBARATTR);
+ tx_printkeyhelp("A", "-add to list ", stdscr, HIGHATTR, STATUSBARATTR);
+ tx_printkeyhelp("D", "-delete ", stdscr, HIGHATTR, STATUSBARATTR);
+ tx_printkeyhelp("Enter", "-edit ", stdscr, HIGHATTR, STATUSBARATTR);
+ tx_printkeyhelp("X/Ctrl+X", "-exit", stdscr, HIGHATTR, STATUSBARATTR);
+
+ update_panels();
+ doupdate();
+
+ firstvisible = fl->head;
+
+ update_hp_screen(firstvisible, win);
+
+ idx = 0;
+ fe = firstvisible;
+
+ update_panels();
+ doupdate();
+
+ do {
+ if (fe != NULL) {
+ print_hostparam_line(fe, idx, win, BARSTDATTR);
+ }
+
+ ch = wgetch(win);
+
+ if (fe != NULL)
+ print_hostparam_line(fe, idx, win, STDATTR);
+
+ switch (ch) {
+ case KEY_UP:
+ if (fl->head != NULL) {
+ if (fe->prev_entry != NULL) {
+ if (idx > 0)
+ idx--;
+ else {
+ scrollok(win, 1);
+ wscrl(win, -1);
+ firstvisible =
+ firstvisible->prev_entry;
+ }
+ fe = fe->prev_entry;
+ }
+ }
+ break;
+ case KEY_DOWN:
+ if (fl->head != NULL) {
+ if (fe->next_entry != NULL) {
+ if (idx < 12)
+ idx++;
+ else {
+ scrollok(win, 1);
+ wscrl(win, 1);
+ firstvisible =
+ firstvisible->next_entry;
+ }
+ fe = fe->next_entry;
+ }
+ }
+ break;
+ case 'i':
+ case 'I':
+ case KEY_IC:
+ ftemp = xmallocz(sizeof(struct filterent));
+
+ gethostparams(&(ftemp->hp), "", "", "", "", "", "", "",
+ "", "I", "N", &gh_aborted);
+
+ if (gh_aborted) {
+ free(ftemp);
+ continue;
+ }
+
+ if (fl->head == NULL) {
+ ftemp->next_entry = ftemp->prev_entry = NULL;
+ fl->head = fl->tail = ftemp;
+ firstvisible = fl->head;
+ idx = 0;
+ } else {
+ ftemp->next_entry = fe;
+ ftemp->prev_entry = fe->prev_entry;
+
+ /*
+ * Point firstvisible at new entry if we inserted at the
+ * top of the list.
+ */
+
+ if (ftemp->prev_entry == NULL) {
+ fl->head = ftemp;
+ firstvisible = ftemp;
+ } else
+ fe->prev_entry->next_entry = ftemp;
+
+ fe->prev_entry = ftemp;
+ }
+
+ if (ftemp->next_entry == NULL)
+ fl->tail = ftemp;
+
+ fe = ftemp;
+ update_hp_screen(firstvisible, win);
+ break;
+ case 'a':
+ case 'A':
+ case 1:
+ ftemp = xmallocz(sizeof(struct filterent));
+
+ gethostparams(&(ftemp->hp), "", "", "", "", "", "", "",
+ "", "I", "N", &gh_aborted);
+
+ if (gh_aborted) {
+ free(ftemp);
+ continue;
+ }
+
+ /*
+ * Add new node to the end of the list (or to the head if the
+ * list is empty.
+ */
+ if (fl->tail != NULL) {
+ fl->tail->next_entry = ftemp;
+ ftemp->prev_entry = fl->tail;
+ } else {
+ fl->head = ftemp;
+ fl->tail = ftemp;
+ ftemp->prev_entry = ftemp->next_entry = NULL;
+ firstvisible = fl->head;
+ fe = ftemp;
+ idx = 0;
+ }
+
+ ftemp->next_entry = NULL;
+ fl->tail = ftemp;
+ update_hp_screen(firstvisible, win);
+ break;
+ case 'd':
+ case 'D':
+ case KEY_DC:
+ if (fl->head != NULL) {
+ /*
+ * Move firstvisible down if it's pointing to the target
+ * entry.
+ */
+
+ if (firstvisible == fe)
+ firstvisible = fe->next_entry;
+
+ /*
+ * Detach target node from list.
+ */
+ if (fe->next_entry != NULL)
+ fe->next_entry->prev_entry =
+ fe->prev_entry;
+ else
+ fl->tail = fe->prev_entry;
+
+ if (fe->prev_entry != NULL)
+ fe->prev_entry->next_entry =
+ fe->next_entry;
+ else
+ fl->head = fe->next_entry;
+
+ /*
+ * Move pointer up if we're deleting the last entry.
+ * The list tail pointer has since been moved to the
+ * previous entry.
+ */
+ if (fe->prev_entry == fl->tail) {
+ ftemp = fe->prev_entry;
+
+ /*
+ * Move screen pointer up. Really adjust the index if
+ * the pointer is anywhere below the top of the screen.
+ */
+ if (idx > 0)
+ idx--;
+ else {
+ /*
+ * Otherwise scroll the list down, and adjust the
+ * firstvisible pointer to point to the entry
+ * previous to the target.
+ */
+ if (ftemp != NULL) {
+ firstvisible = ftemp;
+ }
+ }
+ } else
+ /*
+ * If we reach this point, we're deleting from before
+ * the tail of the list. In that case, we point the
+ * screen pointer at the entry following the target.
+ */
+ ftemp = fe->next_entry;
+
+ free(fe);
+ fe = ftemp;
+ update_hp_screen(firstvisible, win);
+ }
+ break;
+ case 13:
+ if (fe != NULL) {
+ sprintf(s_portstr1, "%u", fe->hp.sport1);
+ sprintf(s_portstr2, "%u", fe->hp.sport2);
+ sprintf(d_portstr1, "%u", fe->hp.dport1);
+ sprintf(d_portstr2, "%u", fe->hp.dport2);
+ inexstr[0] = toupper(fe->hp.reverse);
+ inexstr[1] = '\0';
+ matchop[0] = toupper(fe->hp.match_opposite);
+ matchop[1] = '\0';
+
+ gethostparams(&(fe->hp), fe->hp.s_fqdn,
+ fe->hp.s_mask, s_portstr1,
+ s_portstr2, fe->hp.d_fqdn,
+ fe->hp.d_mask, d_portstr1,
+ d_portstr2, inexstr, matchop,
+ &gh_aborted);
+
+ update_hp_screen(firstvisible, win);
+ }
+
+ break;
+ case 'x':
+ case 'X':
+ case 'q':
+ case 'Q':
+ case 27:
+ case 24:
+ endloop_local = 1;
+ break;
+ case 'l':
+ case 'L':
+ tx_refresh_screen();
+ break;
+ }
+ update_panels();
+ doupdate();
+ } while (!endloop_local);
+
+ del_panel(panel);
+ delwin(win);
+ del_panel(bpanel);
+ delwin(bwin);
+ update_panels();
+ doupdate();
+}
+
+/* remove a currently applied filter from memory */
+void destroyfilter(struct filterlist *fl)
+{
+ struct filterent *fe = fl->head;
+
+ while (fe != NULL) {
+ struct filterent *cfe = fe->next_entry;
+
+ free(fe);
+ fe = cfe;
+ }
+
+ fl->head = NULL;
+ fl->tail = NULL;
+}
+
+
+void definefilter(int *aborted)
+{
+ struct filterfileent ffile;
+ char fntemp[14];
+ struct filterlist fl;
+
+ int pfd;
+ int bw;
+
+ get_filter_description(ffile.desc, aborted, "");
+
+ if (*aborted)
+ return;
+
+ genname(time(NULL), fntemp);
+
+ pfd =
+ open(get_path(T_WORKDIR, fntemp), O_CREAT | O_WRONLY | O_TRUNC,
+ S_IRUSR | S_IWUSR);
+ if (pfd < 0) {
+ tui_error(ANYKEY_MSG, "Cannot create filter data file");
+ *aborted = 1;
+ return;
+ }
+
+ close(pfd);
+
+ pfd =
+ open(OTHIPFLNAME, O_CREAT | O_WRONLY | O_APPEND, S_IRUSR | S_IWUSR);
+
+ if (pfd < 0) {
+ listfileerr(1);
+ return;
+ }
+ strcpy(ffile.filename, fntemp);
+ bw = write(pfd, &ffile, sizeof(struct filterfileent));
+ if (bw < 0)
+ listfileerr(2);
+
+ close(pfd);
+
+ init_filter_table(&fl);
+ modify_host_parameters(&fl);
+ savefilter(get_path(T_WORKDIR, fntemp), &fl);
+ destroyfilter(&fl);
+}
+
+/*
+ * Edit an existing filter
+ */
+void editfilter(int *aborted)
+{
+ char filename[FLT_FILENAME_MAX];
+ struct filterlist fl;
+ struct ffnode *flist;
+ struct ffnode *ffile;
+ struct filterfileent *ffe;
+
+ if (loadfilterlist(&flist) == 1) {
+ listfileerr(1);
+ destroyfilterlist(flist);
+ return;
+ }
+ pickafilter(flist, &ffile, aborted);
+
+ if ((*aborted)) {
+ destroyfilterlist(flist);
+ return;
+ }
+ ffe = &(ffile->ffe);
+
+ get_filter_description(ffe->desc, aborted, ffe->desc);
+
+ if (*aborted) {
+ destroyfilterlist(flist);
+ return;
+ }
+ strncpy(filename, get_path(T_WORKDIR, ffe->filename),
+ FLT_FILENAME_MAX - 1);
+
+ if (loadfilter(filename, &fl, FLT_DONTRESOLVE))
+ return;
+
+ modify_host_parameters(&fl);
+
+ save_filterlist(flist); /* This also destroys it */
+ savefilter(filename, &fl);
+ destroyfilter(&fl);
+}
+
+/*
+ * Delete a filter record from the disk
+ */
+
+void delfilter(int *aborted)
+{
+ struct ffnode *fltfile;
+ struct ffnode *fltlist;
+
+ if (loadfilterlist(&fltlist) == 1) {
+ *aborted = 1;
+ listfileerr(1);
+ destroyfilterlist(fltlist);
+ return;
+ }
+ pickafilter(fltlist, &fltfile, aborted);
+
+ if (*aborted)
+ return;
+
+ unlink(get_path(T_WORKDIR, fltfile->ffe.filename));
+
+ if (fltfile->prev_entry == NULL) {
+ fltlist = fltlist->next_entry;
+ if (fltlist != NULL)
+ fltlist->prev_entry = NULL;
+ } else {
+ fltfile->prev_entry->next_entry = fltfile->next_entry;
+
+ if (fltfile->next_entry != NULL)
+ fltfile->next_entry->prev_entry = fltfile->prev_entry;
+ }
+
+ free(fltfile);
+
+ save_filterlist(fltlist);
+ *aborted = 0;
+}
diff --git a/src/fltedit.h b/src/fltedit.h
new file mode 100644
index 0000000..009fcaa
--- /dev/null
+++ b/src/fltedit.h
@@ -0,0 +1,11 @@
+#ifndef IPTRAF_NG_FLTEDIT_H
+#define IPTRAF_NG_FLTEDIT_H
+
+void definefilter(int *aborted);
+int loadfilter(char *filename, struct filterlist *fl, int resolve);
+void savefilter(char *filename, struct filterlist *fl);
+void destroyfilter(struct filterlist *fl);
+void editfilter(int *aborted);
+void delfilter(int *aborted);
+
+#endif /* IPTRAF_NG_FLTEDIT_H */
diff --git a/src/fltmgr.c b/src/fltmgr.c
new file mode 100644
index 0000000..e7c31e7
--- /dev/null
+++ b/src/fltmgr.c
@@ -0,0 +1,341 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+/***
+
+fltmgr.c - filter list management routines
+
+***/
+
+#include "iptraf-ng-compat.h"
+
+#include "tui/input.h"
+#include "tui/labels.h"
+#include "tui/listbox.h"
+#include "tui/menurt.h"
+#include "tui/msgboxes.h"
+#include "tui/winops.h"
+
+#include "attrs.h"
+#include "deskman.h"
+#include "dirs.h"
+#include "fltdefs.h"
+#include "fltmgr.h"
+#include "error.h"
+
+void makestdfiltermenu(struct MENU *menu)
+{
+ tx_initmenu(menu, 9, 31, (LINES - 8) / 2, (COLS - 31) / 2 + 15, BOXATTR,
+ STDATTR, HIGHATTR, BARSTDATTR, BARHIGHATTR, DESCATTR);
+ tx_additem(menu, " ^D^efine new filter...",
+ "Defines a new set of IP filter parameters");
+ tx_additem(menu, " ^A^pply filter...", "Applies a defined filter");
+ tx_additem(menu, " Detac^h^ filter",
+ "Removes the currently applied filter");
+ tx_additem(menu, " ^E^dit filter...", "Modifies existing filter data");
+ tx_additem(menu, " Dele^t^e filter...",
+ "Removes an IP filter from the filter list");
+ tx_additem(menu, NULL, NULL);
+ tx_additem(menu, " E^x^it menu", "Returns to the main menu");
+}
+
+
+/*
+ * Generate a string representation of a number to be used as a name.
+ */
+
+void genname(unsigned long n, char *m)
+{
+ sprintf(m, "%lu", n);
+}
+
+void listfileerr(int code)
+{
+ if (code == 1)
+ write_error("Error loading filter list file");
+ else
+ write_error("Error writing filter list file");
+}
+
+unsigned long int nametoaddr(char *ascname, int *err)
+{
+ unsigned long int result;
+ struct hostent *he;
+ char imsg[45];
+ struct in_addr inp;
+ int resolv_err = 0;
+
+ resolv_err = inet_aton(ascname, &inp);
+ if (resolv_err == 0) {
+ snprintf(imsg, 44, "Resolving %s", ascname);
+ indicate(imsg);
+
+ he = gethostbyname(ascname);
+ if (he != NULL)
+ bcopy((he->h_addr_list)[0], &result, he->h_length);
+ else {
+ write_error("Unable to resolve %s", ascname);
+ *err = 1;
+ return (-1);
+ }
+ } else
+ result = inp.s_addr;
+
+ return (result);
+ *err = 0;
+}
+
+int loadfilterlist(struct ffnode **fltfile)
+{
+ int pfd = 0;
+ int result = 0;
+
+ struct ffnode *ffiles = NULL;
+ struct ffnode *ptemp;
+ struct ffnode *tail = NULL;
+ struct ffnode *insert_point = NULL; /* new node is inserted *above* this */
+
+ int br;
+
+ pfd = open(OTHIPFLNAME, O_RDONLY);
+
+ if (pfd < 0) {
+ *fltfile = NULL;
+ return 1;
+ }
+
+ do {
+ ptemp = xmalloc(sizeof(struct ffnode));
+ br = read(pfd, &(ptemp->ffe), sizeof(struct filterfileent));
+
+ if (br > 0) {
+ if (ffiles == NULL) {
+ /*
+ * Create single-node list should initial list pointer be empty
+ */
+ ffiles = ptemp;
+ ffiles->prev_entry = ffiles->next_entry = NULL;
+ tail = ffiles;
+ } else {
+ /*
+ * Find appropriate point for insertion into sorted list.
+ */
+
+ insert_point = ffiles;
+ while (insert_point != NULL) {
+ if (strcasecmp
+ (insert_point->ffe.desc,
+ ptemp->ffe.desc)
+ < 0)
+ insert_point =
+ insert_point->next_entry;
+ else
+ break;
+ }
+
+ /*
+ * Insert new node depending on whether insert_point = top of list;
+ * middle of list; end of list.
+ */
+
+ if (insert_point == NULL) {
+ /* Case 1: end of list; if insert_point is NULL, we get it
+ out of the way first */
+ tail->next_entry = ptemp;
+ ptemp->prev_entry = tail;
+ tail = ptemp;
+ ptemp->next_entry = NULL;
+ } else if (insert_point->prev_entry == NULL) {
+ /* Case 2: top of list */
+ insert_point->prev_entry = ptemp;
+ ffiles = ptemp;
+ ffiles->prev_entry = NULL;
+ ffiles->next_entry = insert_point;
+ insert_point->prev_entry = ffiles;
+ } else {
+ /* Case 3: middle of list */
+ ptemp->prev_entry =
+ insert_point->prev_entry;
+ ptemp->next_entry = insert_point;
+ insert_point->prev_entry->next_entry =
+ ptemp;
+ insert_point->prev_entry = ptemp;
+ }
+ }
+ } else {
+ free(ptemp);
+
+ if (br < 0)
+ result = 1;
+ }
+ } while (br > 0);
+
+ close(pfd);
+ *fltfile = ffiles;
+
+ if (ffiles == NULL)
+ result = 1;
+
+ return result;
+}
+
+void destroyfilterlist(struct ffnode *fltlist)
+{
+ while (fltlist != NULL) {
+ struct ffnode *fftemp = fltlist->next_entry;
+
+ free(fltlist);
+ fltlist = fftemp;
+ }
+}
+
+void save_filterlist(struct ffnode *fltlist)
+{
+ struct ffnode *fltfile;
+ struct ffnode *ffntemp;
+ int fd;
+ int bw;
+
+ fd = open(OTHIPFLNAME, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+
+ if (fd < 0) {
+ listfileerr(2);
+ return;
+ }
+
+ fltfile = fltlist;
+ while (fltfile != NULL) {
+ bw = write(fd, &(fltfile->ffe), sizeof(struct filterfileent));
+
+ if (bw < 0) {
+ listfileerr(2);
+ return;
+ }
+ ffntemp = fltfile;
+ fltfile = fltfile->next_entry;
+ free(ffntemp);
+ }
+
+ close(fd);
+}
+
+void operate_select(struct ffnode *ffiles, struct ffnode **item, int *aborted)
+{
+ struct ffnode *pptr;
+ struct scroll_list list;
+
+ tx_listkeyhelp(STDATTR, HIGHATTR);
+ update_panels();
+ doupdate();
+
+ pptr = ffiles;
+
+ tx_init_listbox(&list, 60, 10, (COLS - 60) / 2 - 2,
+ (LINES - 10) / 2 - 2, STDATTR, BOXATTR, BARSTDATTR,
+ HIGHATTR);
+
+ tx_set_listbox_title(&list, "Select Filter", 1);
+
+ while (pptr != NULL) {
+ tx_add_list_entry(&list, (char *) pptr, pptr->ffe.desc);
+ pptr = pptr->next_entry;
+ }
+
+ tx_show_listbox(&list);
+ tx_operate_listbox(&list, aborted);
+
+ if (!(*aborted))
+ *item = (struct ffnode *) list.textptr->nodeptr;
+
+ tx_close_listbox(&list);
+ tx_destroy_list(&list);
+}
+
+void pickafilter(struct ffnode *ffiles, struct ffnode **fltfile, int *aborted)
+{
+ operate_select(ffiles, fltfile, aborted);
+
+ update_panels();
+ doupdate();
+}
+
+char *pickfilterbyname(struct ffnode *ffiles, char *filtername)
+{
+ struct ffnode *ftmp = ffiles;
+ static char filterfile[160];
+
+ while (ftmp != NULL) {
+ if (strcmp(ftmp->ffe.desc, filtername) == 0) {
+ strncpy(filterfile, ftmp->ffe.filename, 40);
+ return filterfile;
+ }
+
+ ftmp = ftmp->next_entry;
+ }
+
+ return NULL;
+}
+
+void selectfilter(struct filterfileent *ffe, int *aborted)
+{
+ struct ffnode *fltfile;
+ struct ffnode *ffiles;
+
+ if (loadfilterlist(&ffiles)) {
+ listfileerr(1);
+ *aborted = 1;
+ destroyfilterlist(ffiles);
+ return;
+ }
+ pickafilter(ffiles, &fltfile, aborted);
+
+ if (!(*aborted))
+ *ffe = fltfile->ffe;
+
+ destroyfilterlist(ffiles);
+}
+
+
+void get_filter_description(char *description, int *aborted, char *pre_edit)
+{
+ struct FIELDLIST descfield;
+ int dlgwintop;
+ WINDOW *dlgwin;
+ PANEL *dlgpanel;
+
+ dlgwintop = (LINES - 9) / 2;
+ dlgwin = newwin(7, 42, dlgwintop, (COLS - 42) / 2 - 10);
+ dlgpanel = new_panel(dlgwin);
+ wattrset(dlgwin, DLGBOXATTR);
+ tx_colorwin(dlgwin);
+ tx_box(dlgwin, ACS_VLINE, ACS_HLINE);
+ wattrset(dlgwin, DLGTEXTATTR);
+ wmove(dlgwin, 2, 2);
+ wprintw(dlgwin, "Enter a description for this filter");
+ wmove(dlgwin, 5, 2);
+ stdkeyhelp(dlgwin);
+ update_panels();
+ doupdate();
+
+ tx_initfields(&descfield, 1, 35, dlgwintop + 3, (COLS - 42) / 2 - 8,
+ DLGTEXTATTR, FIELDATTR);
+ tx_addfield(&descfield, 33, 0, 0, pre_edit);
+
+ do {
+ tx_fillfields(&descfield, aborted);
+
+ if ((descfield.list->buf[0] == '\0') && (!(*aborted)))
+ tui_error(ANYKEY_MSG,
+ "Enter an appropriate description for this filter");
+
+ } while ((descfield.list->buf[0] == '\0') && (!(*aborted)));
+
+ if (!(*aborted))
+ strcpy(description, descfield.list->buf);
+
+ tx_destroyfields(&descfield);
+ del_panel(dlgpanel);
+ delwin(dlgwin);
+ update_panels();
+ doupdate();
+}
diff --git a/src/fltmgr.h b/src/fltmgr.h
new file mode 100644
index 0000000..0477631
--- /dev/null
+++ b/src/fltmgr.h
@@ -0,0 +1,34 @@
+#ifndef IPTRAF_NG_FLTMGR_H
+#define IPTRAF_NG_FLTMGR_H
+
+/***
+
+fltmgr.h - filter list management routine prototypes
+
+***/
+
+struct filterfileent {
+ char desc[35];
+ char filename[40];
+};
+
+struct ffnode {
+ struct filterfileent ffe;
+ struct ffnode *next_entry;
+ struct ffnode *prev_entry;
+};
+
+void makestdfiltermenu(struct MENU *menu);
+void makemainfiltermenu(struct MENU *menu);
+int loadfilterlist(struct ffnode **fltfile);
+void save_filterlist(struct ffnode *fltlist);
+void pickafilter(struct ffnode *files, struct ffnode **fltfile, int *aborted);
+char *pickfilterbyname(struct ffnode *fltlist, char *filename);
+void selectfilter(struct filterfileent *ffe, int *aborted);
+void destroyfilterlist(struct ffnode *fltlist);
+void get_filter_description(char *description, int *aborted, char *pre_edit);
+void genname(unsigned long n, char *m);
+unsigned long int nametoaddr(char *ascname, int *err);
+void listfileerr(int code);
+
+#endif /* IPTRAF_NG_FLTMGR_H */
diff --git a/src/fltselect.c b/src/fltselect.c
new file mode 100644
index 0000000..4be6243
--- /dev/null
+++ b/src/fltselect.c
@@ -0,0 +1,203 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+/***
+
+fltselect.c - a menu-based module that allows selection of
+ other protocols to display
+
+ ***/
+
+#include "iptraf-ng-compat.h"
+
+#include "tui/menurt.h"
+#include "tui/msgboxes.h"
+#include "tui/winops.h"
+
+#include "addproto.h"
+#include "dirs.h"
+#include "fltdefs.h"
+#include "fltselect.h"
+#include "fltedit.h"
+#include "fltmgr.h"
+#include "ipfilter.h"
+#include "deskman.h"
+#include "attrs.h"
+
+struct filterstate ofilter;
+
+void makemainfiltermenu(struct MENU *menu)
+{
+ tx_initmenu(menu, 8, 18, (LINES - 8) / 2, (COLS - 31) / 2, BOXATTR,
+ STDATTR, HIGHATTR, BARSTDATTR, BARHIGHATTR, DESCATTR);
+ tx_additem(menu, " ^I^P...", "Manages IP packet filters");
+ tx_additem(menu, " ^A^RP",
+ "Toggles Address Resolution Protocol filter");
+ tx_additem(menu, " ^R^ARP", "Toggles Reverse ARP filter");
+ tx_additem(menu, " ^N^on-IP",
+ "Toggles filter for all other non-IP packets");
+ tx_additem(menu, NULL, NULL);
+ tx_additem(menu, " E^x^it menu",
+ "Returns to the filter management menu");
+}
+
+void setfilters(unsigned int row)
+{
+ int aborted;
+
+ switch (row) {
+ case 1:
+ ipfilterselect(&aborted);
+ break;
+ case 2:
+ ofilter.arp = ~ofilter.arp;
+ break;
+ case 3:
+ ofilter.rarp = ~ofilter.rarp;
+ break;
+ case 4:
+ ofilter.nonip = ~ofilter.nonip;
+ break;
+ }
+}
+
+void toggleprotodisplay(WINDOW *win, unsigned int row)
+{
+ wmove(win, row, 2);
+ switch (row) {
+ case 1:
+ if (ofilter.filtercode == 0)
+ wprintw(win, "No IP filter active");
+ else
+ wprintw(win, "IP filter active ");
+ break;
+ case 2:
+ if (ofilter.arp)
+ wprintw(win, "ARP visible ");
+ else
+ wprintw(win, "ARP not visible");
+
+ break;
+ case 3:
+ if (ofilter.rarp)
+ wprintw(win, "RARP visible ");
+ else
+ wprintw(win, "RARP not visible");
+
+ break;
+ case 4:
+ if (ofilter.nonip)
+ wprintw(win, "Non-IP visible ");
+ else
+ wprintw(win, "Non-IP not visible");
+
+ break;
+ }
+}
+
+/*
+ * Filter for non-IP packets
+ */
+int nonipfilter(unsigned int protocol)
+{
+ int result = 0;
+
+ switch (protocol) {
+ case ETH_P_ARP:
+ result = ofilter.arp;
+ break;
+ case ETH_P_RARP:
+ result = ofilter.rarp;
+ break;
+ default:
+ result = ofilter.nonip;
+ break;
+ }
+
+ return result;
+}
+
+void config_filters(void)
+{
+ struct MENU menu;
+ WINDOW *statwin;
+ PANEL *statpanel;
+ int row;
+ int aborted;
+
+ statwin = newwin(6, 30, (LINES - 8) / 2, (COLS - 15) / 2 + 10);
+ statpanel = new_panel(statwin);
+ wattrset(statwin, BOXATTR);
+ tx_colorwin(statwin);
+ tx_box(statwin, ACS_VLINE, ACS_HLINE);
+ tx_stdwinset(statwin);
+ wmove(statwin, 0, 1);
+ wprintw(statwin, " Filter Status ");
+ wattrset(statwin, STDATTR);
+
+ for (row = 1; row <= 4; row++)
+ toggleprotodisplay(statwin, row);
+
+ makemainfiltermenu(&menu);
+
+ row = 1;
+ do {
+ tx_showmenu(&menu);
+ tx_operatemenu(&menu, &row, &aborted);
+ setfilters(row);
+ toggleprotodisplay(statwin, row);
+ } while (row != 6);
+
+ tx_destroymenu(&menu);
+ del_panel(statpanel);
+ delwin(statwin);
+ update_panels();
+ doupdate();
+}
+
+void setodefaults(void)
+{
+ memset(&ofilter, 0, sizeof(struct filterstate));
+ ofilter.filtercode = 0;
+}
+
+void loadfilters(void)
+{
+ int pfd;
+ int br;
+
+ pfd = open(FLTSTATEFILE, O_RDONLY); /* open filter state file */
+
+ if (pfd < 0) {
+ setodefaults();
+ return;
+ }
+ br = read(pfd, &ofilter, sizeof(struct filterstate));
+ if (br < 0)
+ setodefaults();
+
+ close(pfd);
+
+ /*
+ * Reload IP filter if one was previously applied
+ */
+
+ if (ofilter.filtercode != 0)
+ loadfilter(ofilter.filename, &ofilter.fl, FLT_RESOLVE);
+}
+
+void savefilters(void)
+{
+ int pfd;
+ int bw;
+
+ pfd =
+ open(FLTSTATEFILE, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR);
+ bw = write(pfd, &ofilter, sizeof(struct filterstate));
+ if (bw < 1)
+ tui_error(ANYKEY_MSG,
+ "Unable to write filter state information");
+
+ close(pfd);
+
+}
diff --git a/src/fltselect.h b/src/fltselect.h
new file mode 100644
index 0000000..a33ee68
--- /dev/null
+++ b/src/fltselect.h
@@ -0,0 +1,27 @@
+#ifndef IPTRAF_NG_FLTSELECT_H
+#define IPTRAF_NG_FLTSELECT_H
+
+/***
+
+othfilter.h - declarations for the non-TCP filter module
+
+ ***/
+
+#include "fltdefs.h"
+
+struct filterstate {
+ char filename[FLT_FILENAME_MAX];
+ int filtercode;
+ struct filterlist fl;
+
+ unsigned int arp:1, rarp:1, nonip:1, padding:13;
+};
+
+extern struct filterstate ofilter;
+
+void config_filters(void);
+void loadfilters(void);
+void savefilters(void);
+int nonipfilter(unsigned int protocol);
+
+#endif /* IPTRAF_NG_FLTSELECT_H */
diff --git a/src/getpath.c b/src/getpath.c
new file mode 100644
index 0000000..0a44b76
--- /dev/null
+++ b/src/getpath.c
@@ -0,0 +1,41 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+// TODO: full rewrite
+
+#include "iptraf-ng-compat.h"
+
+#include "dirs.h"
+
+char *get_path(int dirtype, char *file)
+{
+ static char path[PATH_MAX];
+ char *ptr = NULL;
+ char *dir, *env = NULL;
+
+ switch (dirtype) {
+ case T_WORKDIR:
+ dir = WORKDIR;
+ env = WORKDIR_ENV;
+ break;
+ case T_LOGDIR:
+ dir = LOGDIR;
+ env = LOGDIR_ENV;
+ break;
+ case T_LOCKDIR:
+ dir = LOCKDIR;
+ break;
+ default:
+ return file;
+ }
+
+ if ((dirtype != T_LOCKDIR) && (ptr = getenv(env)) != NULL)
+ dir = ptr;
+
+ if (dir == NULL || *dir == '\0')
+ return file;
+
+ snprintf(path, PATH_MAX - 1, "%s/%s", dir, file);
+
+ return path;
+}
diff --git a/src/getpath.h b/src/getpath.h
new file mode 100644
index 0000000..e9f7819
--- /dev/null
+++ b/src/getpath.h
@@ -0,0 +1,11 @@
+#ifndef IPTRAF_NG_GETPATH_H
+#define IPTRAF_NG_GETPATH_H
+
+#define T_WORKDIR 1
+#define T_LOGDIR 2
+#define T_EXECDIR 3
+#define T_LOCKDIR 4
+
+char *get_path(int dirtype, char *file);
+
+#endif /* IPTRAF_NG_GETPATH_H */
diff --git a/src/hostmon.c b/src/hostmon.c
new file mode 100644
index 0000000..1214483
--- /dev/null
+++ b/src/hostmon.c
@@ -0,0 +1,996 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+/***
+
+hostmon.c - Host traffic monitor
+Discovers LAN hosts and displays packet statistics for them
+
+***/
+
+#include "iptraf-ng-compat.h"
+
+#include "tui/labels.h"
+#include "tui/winops.h"
+
+#include "dirs.h"
+#include "deskman.h"
+#include "fltdefs.h"
+#include "packet.h"
+#include "ifaces.h"
+#include "hostmon.h"
+#include "attrs.h"
+#include "log.h"
+#include "timer.h"
+#include "landesc.h"
+#include "options.h"
+#include "logvars.h"
+#include "error.h"
+#include "rate.h"
+#include "capt.h"
+
+#define SCROLLUP 0
+#define SCROLLDOWN 1
+
+struct ethtabent {
+ int type;
+ union {
+ struct {
+ unsigned long long inpcount;
+ unsigned long long inbcount;
+ unsigned long long inippcount;
+ unsigned long inspanbr;
+ unsigned long long outpcount;
+ unsigned long long outbcount;
+ unsigned long long outippcount;
+ unsigned long outspanbr;
+ struct rate inrate;
+ struct rate outrate;
+ } figs;
+
+ struct {
+ char eth_addr[ETH_ALEN];
+ char ascaddr[18];
+ char desc[65];
+ char ifname[IFNAMSIZ];
+ int withdesc;
+ int printed;
+ unsigned int linktype;
+ } desc;
+ } un;
+
+ unsigned int index;
+ struct ethtabent *prev_entry;
+ struct ethtabent *next_entry;
+};
+
+struct ethtab {
+ struct ethtabent *head;
+ struct ethtabent *tail;
+ struct ethtabent *firstvisible;
+ struct ethtabent *lastvisible;
+ unsigned long count;
+ unsigned long entcount;
+ int units;
+ struct eth_desc *elist;
+ struct eth_desc *flist;
+
+ WINDOW *borderwin;
+ PANEL *borderpanel;
+ WINDOW *tabwin;
+ PANEL *tabpanel;
+};
+
+/*
+ * SIGUSR1 logfile rotation handler
+ */
+
+static void rotate_lanlog(int s __unused)
+{
+ rotate_flag = 1;
+ strcpy(target_logname, current_logfile);
+ signal(SIGUSR1, rotate_lanlog);
+}
+
+static void writeethlog(struct ethtabent *list, unsigned long nsecs, FILE *fd)
+{
+ char atime[TIME_TARGET_MAX];
+ struct ethtabent *ptmp = list;
+
+ genatime(time(NULL), atime);
+
+ fprintf(fd, "\n*** LAN traffic log, generated %s\n\n", atime);
+
+ while (ptmp != NULL) {
+ if (ptmp->type == 0) {
+ if (ptmp->un.desc.linktype == ARPHRD_ETHER)
+ fprintf(fd, "\nEthernet address: %s",
+ ptmp->un.desc.ascaddr);
+ else if (ptmp->un.desc.linktype == ARPHRD_FDDI)
+ fprintf(fd, "\nFDDI address: %s",
+ ptmp->un.desc.ascaddr);
+
+ if (ptmp->un.desc.withdesc)
+ fprintf(fd, " (%s)", ptmp->un.desc.desc);
+
+ fprintf(fd, "\n");
+ } else {
+ fprintf(fd,
+ "\tIncoming total %llu packets, %llu bytes; %llu IP packets\n",
+ ptmp->un.figs.inpcount, ptmp->un.figs.inbcount,
+ ptmp->un.figs.inippcount);
+ fprintf(fd,
+ "\tOutgoing total %llu packets, %llu bytes; %llu IP packets\n",
+ ptmp->un.figs.outpcount,
+ ptmp->un.figs.outbcount,
+ ptmp->un.figs.outippcount);
+
+ fprintf(fd, "\tAverage rates: ");
+ char buf_in[32];
+ char buf_out[32];
+ rate_print(ptmp->un.figs.inbcount / nsecs, buf_in, sizeof(buf_in));
+ rate_print(ptmp->un.figs.outbcount / nsecs, buf_out, sizeof(buf_out));
+ fprintf(fd, "%s incoming, %s outgoing\n",
+ buf_in, buf_out);
+
+ if (nsecs > 5) {
+ rate_print(rate_get_average(&ptmp->un.figs.inrate),
+ buf_in, sizeof(buf_in));
+ rate_print(rate_get_average(&ptmp->un.figs.outrate),
+ buf_out, sizeof(buf_out));
+ fprintf(fd,
+ "\tLast 5-second rates: %s incoming, %s outgoing\n",
+ buf_in, buf_out);
+ }
+ }
+
+ ptmp = ptmp->next_entry;
+ }
+
+ fprintf(fd, "\nRunning time: %lu seconds\n", nsecs);
+ fflush(fd);
+}
+
+static void hostmonhelp(void)
+{
+ move(LINES - 1, 1);
+ scrollkeyhelp();
+ sortkeyhelp();
+ stdexitkeyhelp();
+}
+
+static void initethtab(struct ethtab *table)
+{
+ table->head = table->tail = NULL;
+ table->firstvisible = table->lastvisible = NULL;
+ table->count = table->entcount = 0;
+
+ table->borderwin = newwin(LINES - 2, COLS, 1, 0);
+ table->borderpanel = new_panel(table->borderwin);
+
+ table->tabwin = newwin(LINES - 4, COLS - 2, 2, 1);
+ table->tabpanel = new_panel(table->tabwin);
+
+ wattrset(table->borderwin, BOXATTR);
+ tx_box(table->borderwin, ACS_VLINE, ACS_HLINE);
+
+ mvwprintw(table->borderwin, 0, 5 * COLS / 80, " PktsIn ");
+ mvwprintw(table->borderwin, 0, 16 * COLS / 80, " IP In ");
+ mvwprintw(table->borderwin, 0, 24 * COLS / 80, " BytesIn ");
+ mvwprintw(table->borderwin, 0, 34 * COLS / 80, " InRate ");
+ mvwprintw(table->borderwin, 0, 42 * COLS / 80, " PktsOut ");
+ mvwprintw(table->borderwin, 0, 53 * COLS / 80, " IP Out ");
+ mvwprintw(table->borderwin, 0, 61 * COLS / 80, " BytesOut ");
+ mvwprintw(table->borderwin, 0, 70 * COLS / 80, " OutRate ");
+
+ wattrset(table->tabwin, STDATTR);
+ tx_colorwin(table->tabwin);
+ tx_stdwinset(table->tabwin);
+ wtimeout(table->tabwin, -1);
+ leaveok(table->tabwin, TRUE);
+
+ hostmonhelp();
+
+ update_panels();
+ doupdate();
+
+ /* Ethernet description list */
+ table->elist = load_eth_desc(ARPHRD_ETHER);
+
+ /* FDDI description list */
+ table->flist = load_eth_desc(ARPHRD_FDDI);
+}
+
+static struct ethtabent *addethnode(struct ethtab *table)
+{
+ struct ethtabent *ptemp;
+
+ ptemp = xmalloc(sizeof(struct ethtabent));
+
+ if (table->head == NULL) {
+ ptemp->prev_entry = NULL;
+ table->head = ptemp;
+ table->firstvisible = ptemp;
+ } else {
+ ptemp->prev_entry = table->tail;
+ table->tail->next_entry = ptemp;
+ }
+
+ table->tail = ptemp;
+ ptemp->next_entry = NULL;
+
+ table->count++;
+ ptemp->index = table->count;
+
+ if (table->count <= (unsigned) LINES - 4)
+ table->lastvisible = ptemp;
+
+ return ptemp;
+}
+
+void convmacaddr(char *addr, char *result)
+{
+ u_int8_t *ptmp = (u_int8_t *) addr;
+
+ sprintf(result, "%02x:%02x:%02x:%02x:%02x:%02x",
+ *ptmp,
+ *(ptmp + 1),
+ *(ptmp + 2),
+ *(ptmp + 3),
+ *(ptmp + 4),
+ *(ptmp + 5));
+}
+
+static struct ethtabent *addethentry(struct ethtab *table,
+ unsigned int linktype, int ifindex,
+ char *addr, struct eth_desc *list)
+{
+ struct ethtabent *ptemp;
+
+ ptemp = addethnode(table);
+
+ if (ptemp == NULL)
+ return NULL;
+
+ ptemp->type = 0;
+ memcpy(&(ptemp->un.desc.eth_addr), addr, ETH_ALEN);
+ strcpy(ptemp->un.desc.desc, "");
+
+ convmacaddr(addr, ptemp->un.desc.ascaddr);
+
+ ptemp->un.desc.linktype = linktype;
+ struct eth_desc *desc = NULL;
+
+ list_for_each_entry(desc, &list->hd_list, hd_list)
+ if (!strcasecmp(desc->hd_mac, ptemp->un.desc.ascaddr))
+ strcpy(ptemp->un.desc.desc, desc->hd_desc);
+
+ dev_get_ifname(ifindex, ptemp->un.desc.ifname);
+
+ if (strcmp(ptemp->un.desc.desc, "") == 0)
+ ptemp->un.desc.withdesc = 0;
+ else
+ ptemp->un.desc.withdesc = 1;
+
+ ptemp->un.desc.printed = 0;
+
+ ptemp = addethnode(table);
+
+ if (ptemp == NULL)
+ return NULL;
+
+ ptemp->type = 1;
+ ptemp->un.figs.inpcount = 0;
+ ptemp->un.figs.outpcount = 0;
+ ptemp->un.figs.inspanbr = ptemp->un.figs.outspanbr = 0;
+ ptemp->un.figs.inippcount = ptemp->un.figs.outippcount = 0;
+ ptemp->un.figs.inbcount = ptemp->un.figs.outbcount = 0;
+ rate_alloc(&ptemp->un.figs.inrate, 5);
+ rate_alloc(&ptemp->un.figs.outrate, 5);
+
+ table->entcount++;
+
+ mvwprintw(table->borderwin, LINES - 3, 1, " %u entries ",
+ table->entcount);
+
+ return ptemp;
+}
+
+static struct ethtabent *in_ethtable(struct ethtab *table,
+ unsigned int linktype, char *addr)
+{
+ struct ethtabent *ptemp = table->head;
+
+ while (ptemp != NULL) {
+ if ((ptemp->type == 0)
+ && (memcmp(addr, ptemp->un.desc.eth_addr, ETH_ALEN) == 0)
+ && (ptemp->un.desc.linktype == linktype))
+ return ptemp->next_entry;
+
+ ptemp = ptemp->next_entry;
+ }
+
+ return NULL;
+}
+
+static void updateethent(struct ethtabent *entry, int pktsize, int is_ip,
+ int inout)
+{
+ if (inout == 0) {
+ entry->un.figs.inpcount++;
+ entry->un.figs.inbcount += pktsize;
+ entry->un.figs.inspanbr += pktsize;
+ if (is_ip)
+ entry->un.figs.inippcount++;
+ } else {
+ entry->un.figs.outpcount++;
+ entry->un.figs.outbcount += pktsize;
+ entry->un.figs.outspanbr += pktsize;
+ if (is_ip)
+ entry->un.figs.outippcount++;
+ }
+}
+
+static void printethent(struct ethtab *table, struct ethtabent *entry)
+{
+ unsigned int target_row;
+
+ if ((entry->index < table->firstvisible->index) ||
+ (entry->index > table->lastvisible->index))
+ return;
+
+ target_row = entry->index - table->firstvisible->index;
+
+ if (entry->type == 0) {
+ wmove(table->tabwin, target_row, 1);
+ wattrset(table->tabwin, STDATTR);
+
+ if (entry->un.desc.linktype == ARPHRD_ETHER)
+ wprintw(table->tabwin, "Ethernet");
+ else if (entry->un.desc.linktype == ARPHRD_FDDI)
+ wprintw(table->tabwin, "FDDI");
+
+ wprintw(table->tabwin, " HW addr: %s", entry->un.desc.ascaddr);
+
+ if (entry->un.desc.withdesc)
+ wprintw(table->tabwin, " (%s)", entry->un.desc.desc);
+
+ wprintw(table->tabwin, " on %s ", entry->un.desc.ifname);
+
+ entry->un.desc.printed = 1;
+ } else {
+ wattrset(table->tabwin, PTRATTR);
+ wmove(table->tabwin, target_row, 1);
+ waddch(table->tabwin, ACS_LLCORNER);
+
+ wattrset(table->tabwin, HIGHATTR);
+
+ /* Inbound traffic counts */
+
+ wmove(table->tabwin, target_row, 2 * COLS / 80);
+ printlargenum(entry->un.figs.inpcount, table->tabwin);
+ wmove(table->tabwin, target_row, 12 * COLS / 80);
+ printlargenum(entry->un.figs.inippcount, table->tabwin);
+ wmove(table->tabwin, target_row, 22 * COLS / 80);
+ printlargenum(entry->un.figs.inbcount, table->tabwin);
+
+ /* Outbound traffic counts */
+
+ wmove(table->tabwin, target_row, 40 * COLS / 80);
+ printlargenum(entry->un.figs.outpcount, table->tabwin);
+ wmove(table->tabwin, target_row, 50 * COLS / 80);
+ printlargenum(entry->un.figs.outippcount, table->tabwin);
+ wmove(table->tabwin, target_row, 60 * COLS / 80);
+ printlargenum(entry->un.figs.outbcount, table->tabwin);
+ }
+}
+
+static void destroyethtab(struct ethtab *table)
+{
+ struct ethtabent *ptemp = table->head;
+
+ while (ptemp != NULL) {
+ struct ethtabent *next = ptemp->next_entry;
+
+ if (ptemp->type == 1) {
+ rate_destroy(&ptemp->un.figs.outrate);
+ rate_destroy(&ptemp->un.figs.inrate);
+ }
+ free(ptemp);
+ ptemp = next;
+ }
+
+ free_eth_desc(table->elist);
+ free_eth_desc(table->flist);
+
+ del_panel(table->tabpanel);
+ delwin(table->tabwin);
+
+ del_panel(table->borderpanel);
+ delwin(table->borderwin);
+
+ update_panels();
+ doupdate();
+}
+
+static void print_entry_rates(struct ethtab *table, struct ethtabent *entry)
+{
+ char buf[32];
+
+ if (entry == NULL)
+ return;
+ if (entry->type != 1)
+ return;
+
+ int target_row = entry->index - table->firstvisible->index;
+
+ wattrset(table->tabwin, HIGHATTR);
+ rate_print_no_units(rate_get_average(&entry->un.figs.inrate),
+ buf, sizeof(buf));
+ mvwprintw(table->tabwin, target_row, 32 * COLS / 80, "%s", buf);
+
+ rate_print_no_units(rate_get_average(&entry->un.figs.outrate),
+ buf, sizeof(buf));
+ mvwprintw(table->tabwin, target_row, 69 * COLS / 80, "%s", buf);
+}
+
+static void updateethrates(struct ethtab *table, unsigned long msecs)
+{
+ struct ethtabent *ptmp = table->head;
+
+ if (table->lastvisible == NULL)
+ return;
+
+ while (ptmp != NULL) {
+ if (ptmp->type == 1) {
+ rate_add_rate(&ptmp->un.figs.inrate, ptmp->un.figs.inspanbr, msecs);
+ ptmp->un.figs.inspanbr = 0;
+
+ rate_add_rate(&ptmp->un.figs.outrate, ptmp->un.figs.outspanbr, msecs);
+ ptmp->un.figs.outspanbr = 0;
+ }
+ ptmp = ptmp->next_entry;
+ }
+}
+
+static void print_visible_entries(struct ethtab *table)
+{
+ struct ethtabent *ptmp = table->firstvisible;
+
+ while ((ptmp != NULL) && (ptmp->prev_entry != table->lastvisible)) {
+ printethent(table, ptmp);
+ print_entry_rates(table, ptmp);
+
+ ptmp = ptmp->next_entry;
+ }
+}
+
+static void refresh_hostmon_screen(struct ethtab *table)
+{
+ wattrset(table->tabwin, STDATTR);
+ tx_colorwin(table->tabwin);
+
+ print_visible_entries(table);
+
+ update_panels();
+ doupdate();
+}
+
+static void scrollethwin_one(struct ethtab *table, int direction)
+{
+ wattrset(table->tabwin, STDATTR);
+ if (direction == SCROLLUP) {
+ if (table->lastvisible != table->tail) {
+ table->firstvisible = table->firstvisible->next_entry;
+ table->lastvisible = table->lastvisible->next_entry;
+
+ wscrl(table->tabwin, 1);
+ scrollok(table->tabwin, 0);
+ mvwprintw(table->tabwin, LINES - 5, 0, "%*c", COLS - 2, ' ');
+ scrollok(table->tabwin, 1);
+
+ printethent(table, table->lastvisible);
+ print_entry_rates(table, table->lastvisible);
+ }
+ } else {
+ if (table->firstvisible != table->head) {
+ table->firstvisible = table->firstvisible->prev_entry;
+ table->lastvisible = table->lastvisible->prev_entry;
+
+ wscrl(table->tabwin, -1);
+ mvwprintw(table->tabwin, 0, 0, "%*c", COLS - 2, ' ');
+
+ printethent(table, table->firstvisible);
+ print_entry_rates(table, table->firstvisible);
+ }
+ }
+}
+
+static void scrollethwin_many(struct ethtab *table, int direction, int lines)
+{
+ switch (direction) {
+ case SCROLLUP:
+ while (lines && (table->lastvisible != table->tail)) {
+ table->firstvisible = table->firstvisible->next_entry;
+ table->lastvisible = table->lastvisible->next_entry;
+ lines--;
+ }
+ break;
+ case SCROLLDOWN:
+ while (lines && (table->firstvisible != table->head)) {
+ table->firstvisible = table->firstvisible->prev_entry;
+ table->lastvisible = table->lastvisible->prev_entry;
+ lines--;
+ }
+ break;
+ }
+ refresh_hostmon_screen(table);
+}
+
+static void scrollethwin(struct ethtab *table, int direction, int lines)
+{
+ if (table->head == NULL)
+ return;
+ if (lines < 1)
+ return;
+ if (lines < 16)
+ while (lines--)
+ scrollethwin_one(table, direction);
+ else
+ scrollethwin_many(table, direction, lines);
+}
+
+static void show_hostsort_keywin(WINDOW ** win, PANEL ** panel)
+{
+ *win = newwin(13, 35, (LINES - 10) / 2, COLS - 40);
+ *panel = new_panel(*win);
+
+ wattrset(*win, DLGBOXATTR);
+ tx_colorwin(*win);
+ tx_box(*win, ACS_VLINE, ACS_HLINE);
+
+ wattrset(*win, DLGTEXTATTR);
+ mvwprintw(*win, 2, 2, "Select sort criterion");
+ wmove(*win, 4, 2);
+ tx_printkeyhelp("P", " - total packets in", *win, DLGHIGHATTR,
+ DLGTEXTATTR);
+ wmove(*win, 5, 2);
+ tx_printkeyhelp("I", " - IP packets in", *win, DLGHIGHATTR,
+ DLGTEXTATTR);
+ wmove(*win, 6, 2);
+ tx_printkeyhelp("B", " - total bytes in", *win, DLGHIGHATTR,
+ DLGTEXTATTR);
+ wmove(*win, 7, 2);
+ tx_printkeyhelp("K", " - total packets out", *win, DLGHIGHATTR,
+ DLGTEXTATTR);
+ wmove(*win, 8, 2);
+ tx_printkeyhelp("O", " - IP packets out", *win, DLGHIGHATTR,
+ DLGTEXTATTR);
+ wmove(*win, 9, 2);
+ tx_printkeyhelp("Y", " - total bytes out", *win, DLGHIGHATTR,
+ DLGTEXTATTR);
+ wmove(*win, 10, 2);
+ tx_printkeyhelp("Any other key", " - cancel sort", *win, DLGHIGHATTR,
+ DLGTEXTATTR);
+ update_panels();
+ doupdate();
+}
+
+/*
+ * Swap two host table entries.
+ */
+
+static void swaphostents(struct ethtab *list, struct ethtabent *p1,
+ struct ethtabent *p2)
+{
+ register unsigned int tmp;
+ struct ethtabent *p1prevsaved;
+ struct ethtabent *p2nextsaved;
+
+ if (p1 == p2)
+ return;
+
+ tmp = p1->index;
+ p1->index = p2->index;
+ p2->index = tmp;
+ p1->next_entry->index = p1->index + 1;
+ p2->next_entry->index = p2->index + 1;
+
+ if (p1->prev_entry != NULL)
+ p1->prev_entry->next_entry = p2;
+ else
+ list->head = p2;
+
+ if (p2->next_entry->next_entry != NULL)
+ p2->next_entry->next_entry->prev_entry = p1->next_entry;
+ else
+ list->tail = p1->next_entry;
+
+ p2nextsaved = p2->next_entry->next_entry;
+ p1prevsaved = p1->prev_entry;
+
+ if (p1->next_entry->next_entry == p2) {
+ p2->next_entry->next_entry = p1;
+ p1->prev_entry = p2->next_entry;
+ } else {
+ p2->next_entry->next_entry = p1->next_entry->next_entry;
+ p1->prev_entry = p2->prev_entry;
+ p2->prev_entry->next_entry = p1;
+ p1->next_entry->next_entry->prev_entry = p2->next_entry;
+ }
+
+ p2->prev_entry = p1prevsaved;
+ p1->next_entry->next_entry = p2nextsaved;
+}
+
+static unsigned long long ql_getkey(struct ethtabent *entry, int ch)
+{
+ unsigned long long result = 0;
+
+ switch (ch) {
+ case 'P':
+ result = entry->next_entry->un.figs.inpcount;
+ break;
+ case 'I':
+ result = entry->next_entry->un.figs.inippcount;
+ break;
+ case 'B':
+ result = entry->next_entry->un.figs.inbcount;
+ break;
+ case 'K':
+ result = entry->next_entry->un.figs.outpcount;
+ break;
+ case 'O':
+ result = entry->next_entry->un.figs.outippcount;
+ break;
+ case 'Y':
+ result = entry->next_entry->un.figs.outbcount;
+ break;
+ }
+ return result;
+}
+
+static struct ethtabent *ql_partition(struct ethtab *table,
+ struct ethtabent **low,
+ struct ethtabent **high, int ch)
+{
+ struct ethtabent *pivot = *low;
+
+ struct ethtabent *left = *low;
+ struct ethtabent *right = *high;
+ struct ethtabent *ptmp;
+
+ unsigned long long pivot_value;
+
+ pivot_value = ql_getkey(pivot, ch);
+
+ while (left->index < right->index) {
+ while ((ql_getkey(left, ch) >= pivot_value)
+ && (left->next_entry->next_entry != NULL))
+ left = left->next_entry->next_entry;
+
+ while (ql_getkey(right, ch) < pivot_value)
+ right = right->prev_entry->prev_entry;
+
+ if (left->index < right->index) {
+ swaphostents(table, left, right);
+
+ if (*low == left)
+ *low = right;
+
+ if (*high == right)
+ *high = left;
+
+ ptmp = left;
+ left = right;
+ right = ptmp;
+ }
+ }
+ swaphostents(table, pivot, right);
+
+ if (*low == pivot)
+ *low = right;
+
+ if (*high == right)
+ *high = pivot;
+
+ return pivot;
+}
+
+/*
+ * Quicksort routine for the LAN station monitor
+ */
+
+static void quicksort_lan_entries(struct ethtab *table, struct ethtabent *low,
+ struct ethtabent *high, int ch)
+{
+ struct ethtabent *pivot;
+
+ if ((high == NULL) || (low == NULL))
+ return;
+
+ if (high->index > low->index) {
+ pivot = ql_partition(table, &low, &high, ch);
+
+ if (pivot->prev_entry != NULL)
+ quicksort_lan_entries(table, low,
+ pivot->prev_entry->prev_entry,
+ ch);
+
+ quicksort_lan_entries(table, pivot->next_entry->next_entry,
+ high, ch);
+ }
+}
+
+static void sort_hosttab(struct ethtab *list, int command)
+{
+ if (!list->head)
+ return;
+
+ command = toupper(command);
+
+ if ((command != 'P') && (command != 'I') && (command != 'B')
+ && (command != 'K') && (command != 'O') && (command != 'Y'))
+ return;
+
+ quicksort_lan_entries(list, list->head, list->tail->prev_entry,
+ command);
+
+ list->firstvisible = list->head;
+ struct ethtabent *ptmp = list->head;
+ while (ptmp && ((int)ptmp->index <= getmaxy(list->tabwin))) {
+ list->lastvisible = ptmp;
+ ptmp = ptmp->next_entry;
+ }
+}
+
+static void hostmon_process_key(struct ethtab *table, int ch)
+{
+ static WINDOW *sortwin;
+ static PANEL *sortpanel;
+ static int keymode = 0;
+
+ if (keymode == 0) {
+ switch (ch) {
+ case KEY_UP:
+ scrollethwin(table, SCROLLDOWN, 1);
+ break;
+ case KEY_DOWN:
+ scrollethwin(table, SCROLLUP, 1);
+ break;
+ case KEY_PPAGE:
+ case '-':
+ scrollethwin(table, SCROLLDOWN, LINES - 4);
+ break;
+ case KEY_NPAGE:
+ case ' ':
+ scrollethwin(table, SCROLLUP, LINES - 4);
+ break;
+ case KEY_HOME:
+ scrollethwin(table, SCROLLDOWN, INT_MAX);
+ break;
+ case KEY_END:
+ scrollethwin(table, SCROLLUP, INT_MAX);
+ break;
+ case 12:
+ case 'l':
+ case 'L':
+ tx_refresh_screen();
+ break;
+ case 's':
+ case 'S':
+ show_hostsort_keywin(&sortwin, &sortpanel);
+ keymode = 1;
+ break;
+ case 'q':
+ case 'Q':
+ case 'x':
+ case 'X':
+ case 27:
+ case 24:
+ exitloop = 1;
+ }
+ } else if (keymode == 1) {
+ del_panel(sortpanel);
+ delwin(sortwin);
+ sort_hosttab(table, ch);
+ keymode = 0;
+ refresh_hostmon_screen(table);
+ }
+}
+
+static void hostmon_process_packet(struct ethtab *table, struct pkt_hdr *pkt)
+{
+ int pkt_result = packet_process(pkt, NULL, NULL, NULL,
+ MATCH_OPPOSITE_USECONFIG, 0);
+
+ if (pkt_result != PACKET_OK)
+ return;
+
+ char scratch_saddr[ETH_ALEN];
+ char scratch_daddr[ETH_ALEN];
+ struct eth_desc *list = NULL;
+ struct ethtabent *entry;
+ int is_ip;
+
+ /* get HW addresses */
+ switch (pkt->from->sll_hatype) {
+ case ARPHRD_ETHER:
+ memcpy(scratch_saddr, pkt->ethhdr->h_source, ETH_ALEN);
+ memcpy(scratch_daddr, pkt->ethhdr->h_dest, ETH_ALEN);
+ list = table->elist;
+ break;
+ case ARPHRD_FDDI:
+ memcpy(scratch_saddr, pkt->fddihdr->saddr, FDDI_K_ALEN);
+ memcpy(scratch_daddr, pkt->fddihdr->daddr, FDDI_K_ALEN);
+ list = table->flist;
+ break;
+ default:
+ /* unknown link protocol */
+ return;
+ }
+
+ switch(pkt->pkt_protocol) {
+ case ETH_P_IP:
+ case ETH_P_IPV6:
+ is_ip = 1;
+ break;
+ default:
+ is_ip = 0;
+ break;
+ }
+
+ /* Check source address entry */
+ entry = in_ethtable(table, pkt->from->sll_hatype, scratch_saddr);
+ if (!entry)
+ entry = addethentry(table, pkt->from->sll_hatype,
+ pkt->from->sll_ifindex, scratch_saddr,
+ list);
+
+ if (entry != NULL)
+ updateethent(entry, pkt->pkt_len, is_ip, 1);
+
+ /* Check destination address entry */
+ entry = in_ethtable(table, pkt->from->sll_hatype, scratch_daddr);
+ if (!entry)
+ entry = addethentry(table, pkt->from->sll_hatype,
+ pkt->from->sll_ifindex, scratch_daddr,
+ list);
+
+ if (entry != NULL)
+ updateethent(entry, pkt->pkt_len, is_ip, 0);
+}
+
+/*
+ * The LAN station monitor
+ */
+
+void hostmon(time_t facilitytime, char *ifptr)
+{
+ int logging = options.logging;
+ struct ethtab table;
+
+ int ch;
+
+ FILE *logfile = NULL;
+
+ struct capt capt;
+
+ struct pkt_hdr pkt;
+
+ if (ifptr && !dev_up(ifptr)) {
+ err_iface_down();
+ return;
+ }
+
+ initethtab(&table);
+
+ if (capt_init(&capt, ifptr) == -1) {
+ write_error("Unable to initialize packet capture interface");
+ goto err;
+ }
+
+ if (logging) {
+ if (strcmp(current_logfile, "") == 0) {
+ strncpy(current_logfile,
+ gen_instance_logname(LANLOG, getpid()), 80);
+
+ if (!daemonized)
+ input_logfile(current_logfile, &logging);
+ }
+ }
+
+ if (logging) {
+ opentlog(&logfile, current_logfile);
+
+ if (logfile == NULL)
+ logging = 0;
+ }
+ if (logging) {
+ signal(SIGUSR1, rotate_lanlog);
+
+ rotate_flag = 0;
+ writelog(logging, logfile,
+ "******** LAN traffic monitor started ********");
+ }
+
+ packet_init(&pkt);
+
+ exitloop = 0;
+
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ struct timespec last_time = now;
+ struct timespec next_screen_update = { 0 };
+
+ time_t starttime = now.tv_sec;
+ time_t endtime = INT_MAX;
+ if (facilitytime != 0)
+ endtime = now.tv_sec + facilitytime * 60;
+
+ time_t log_next = INT_MAX;
+ if (logging)
+ log_next = now.tv_sec + options.logspan;
+
+ while (!exitloop) {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ if (now.tv_sec > last_time.tv_sec) {
+ unsigned long msecs = timespec_diff_msec(&now, &last_time);
+ updateethrates(&table, msecs);
+
+ printelapsedtime(now.tv_sec - starttime, 15, table.borderwin);
+
+ print_packet_drops(capt_get_dropped(&capt), table.borderwin, 49);
+
+ if (logging && (now.tv_sec > log_next)) {
+ check_rotate_flag(&logfile);
+ writeethlog(table.head, now.tv_sec - starttime,
+ logfile);
+ log_next = now.tv_sec + options.logspan;
+ }
+
+ if (now.tv_sec > endtime)
+ exitloop = 1;
+
+ last_time = now;
+ }
+ if (time_after(&now, &next_screen_update)) {
+ print_visible_entries(&table);
+ update_panels();
+ doupdate();
+
+ set_next_screen_update(&next_screen_update, &now);
+ }
+
+ if (capt_get_packet(&capt, &pkt, &ch, table.tabwin) == -1) {
+ write_error("Packet receive failed");
+ exitloop = 1;
+ break;
+ }
+
+ if (ch != ERR)
+ hostmon_process_key(&table, ch);
+
+ if (pkt.pkt_len > 0) {
+ hostmon_process_packet(&table, &pkt);
+ capt_put_packet(&capt, &pkt);
+ }
+
+ }
+
+ packet_destroy(&pkt);
+
+ if (logging) {
+ signal(SIGUSR1, SIG_DFL);
+ writeethlog(table.head, time(NULL) - starttime, logfile);
+ writelog(logging, logfile,
+ "******** LAN traffic monitor stopped ********");
+ fclose(logfile);
+ }
+ strcpy(current_logfile, "");
+
+ capt_destroy(&capt);
+err:
+ destroyethtab(&table);
+}
diff --git a/src/hostmon.h b/src/hostmon.h
new file mode 100644
index 0000000..6b23b54
--- /dev/null
+++ b/src/hostmon.h
@@ -0,0 +1,7 @@
+#ifndef IPTRAF_NG_HOSTMON_H
+#define IPTRAF_NG_HOSTMON_H
+
+void convmacaddr(char *addr, char *result);
+void hostmon(time_t facilitytime, char *ifptr);
+
+#endif /* IPTRAF_NG_HOSTMON_H */
diff --git a/src/ifaces.c b/src/ifaces.c
new file mode 100644
index 0000000..aeb1614
--- /dev/null
+++ b/src/ifaces.c
@@ -0,0 +1,267 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+/***
+
+ifaces.c - routine that determines whether a given interface is supported
+ by IPTraf
+
+***/
+
+#include "iptraf-ng-compat.h"
+
+#include "error.h"
+
+/*
+ * Open /proc/net/dev and move file pointer past the two table header lines
+ * at the top of the file.
+ */
+
+FILE *open_procnetdev(void)
+{
+ FILE *fd;
+ char buf[161];
+
+ fd = fopen("/proc/net/dev", "r");
+
+ /*
+ * Read and discard the table header lines in the file
+ */
+
+ if (fd != NULL) {
+ fgets(buf, 160, fd);
+ fgets(buf, 160, fd);
+ }
+
+ return fd;
+}
+
+/*
+ * Get the next interface from /proc/net/dev.
+ */
+int get_next_iface(FILE * fd, char *ifname, int n)
+{
+ char buf[161];
+
+ strcpy(ifname, "");
+
+ if (!feof(fd)) {
+ strcpy(buf, "");
+ fgets(buf, 160, fd);
+ if (strcmp(buf, "") != 0) {
+ memset(ifname, 0, n);
+ strncpy(ifname, skip_whitespace(strtok(buf, ":")), n);
+ if (ifname[n - 1] != '\0')
+ strcpy(ifname, "");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int dev_up(char *iface)
+{
+ int fd;
+ int ir;
+ struct ifreq ifr;
+
+ fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+
+ strcpy(ifr.ifr_name, iface);
+ ir = ioctl(fd, SIOCGIFFLAGS, &ifr);
+
+ close(fd);
+
+ if ((ir != 0) || (!(ifr.ifr_flags & IFF_UP)))
+ return 0;
+
+ return 1;
+}
+
+void err_iface_down(void)
+{
+ write_error("Specified interface not active");
+}
+
+int dev_get_ifindex(const char *iface)
+{
+ int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (fd == -1)
+ return fd;
+
+ struct ifreq ifr;
+ strcpy(ifr.ifr_name, iface);
+ int ir = ioctl(fd, SIOCGIFINDEX, &ifr);
+
+ /* need to preserve errno across call to close() */
+ int saved_errno = errno;
+
+ close(fd);
+
+ /* bug out if ioctl() failed */
+ if (ir != 0) {
+ errno = saved_errno;
+ return ir;
+ }
+
+ return ifr.ifr_ifindex;
+}
+
+int dev_get_mtu(const char *iface)
+{
+ int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (fd == -1)
+ return fd;
+
+ struct ifreq ifr;
+ strcpy(ifr.ifr_name, iface);
+ int ir = ioctl(fd, SIOCGIFMTU, &ifr);
+
+ /* need to preserve errno across call to close() */
+ int saved_errno = errno;
+
+ close(fd);
+
+ /* bug out if ioctl() failed */
+ if (ir != 0) {
+ errno = saved_errno;
+ return ir;
+ }
+
+ return ifr.ifr_mtu;
+}
+
+int dev_get_flags(const char *iface)
+{
+ int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (fd == -1)
+ return fd;
+
+ struct ifreq ifr;
+ strcpy(ifr.ifr_name, iface);
+ int ir = ioctl(fd, SIOCGIFFLAGS, &ifr);
+
+ /* need to preserve errno across call to close() */
+ int saved_errno = errno;
+
+ close(fd);
+
+ /* bug out if ioctl() failed */
+ if (ir != 0) {
+ errno = saved_errno;
+ return ir;
+ }
+
+ return ifr.ifr_flags;
+}
+
+int dev_set_flags(const char *iface, int flags)
+{
+ int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (fd == -1)
+ return fd;
+
+ struct ifreq ifr;
+ strcpy(ifr.ifr_name, iface);
+ int ir = ioctl(fd, SIOCGIFFLAGS, &ifr);
+ if (ir == -1)
+ goto err;
+
+ ifr.ifr_flags |= flags;
+ ir = ioctl(fd, SIOCSIFFLAGS, &ifr);
+
+ int saved_errno;
+err: /* need to preserve errno across call to close() */
+ saved_errno = errno;
+
+ close(fd);
+
+ /* bug out if ioctl() failed */
+ if (ir != 0)
+ errno = saved_errno;
+
+ return ir;
+}
+
+int dev_clear_flags(const char *iface, int flags)
+{
+ int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (fd == -1)
+ return fd;
+
+ struct ifreq ifr;
+ strcpy(ifr.ifr_name, iface);
+ int ir = ioctl(fd, SIOCGIFFLAGS, &ifr);
+ if (ir == -1)
+ goto err;
+
+ ifr.ifr_flags &= ~flags;
+ ir = ioctl(fd, SIOCSIFFLAGS, &ifr);
+
+ int saved_errno;
+err: /* need to preserve errno across call to close() */
+ saved_errno = errno;
+
+ close(fd);
+
+ /* bug out if ioctl() failed */
+ if (ir != 0)
+ errno = saved_errno;
+
+ return ir;
+}
+
+int dev_get_ifname(int ifindex, char *ifname)
+{
+ int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (fd == -1)
+ return fd;
+
+ struct ifreq ifr = {
+ .ifr_ifindex = ifindex
+ };
+ int ir = ioctl(fd, SIOCGIFNAME, &ifr);
+
+ /* need to preserve errno across call to close() */
+ int saved_errno = errno;
+
+ close(fd);
+
+ /* bug out if ioctl() failed */
+ if (ir != 0) {
+ errno = saved_errno;
+ return ir;
+ }
+
+ strncpy(ifname, ifr.ifr_name, IFNAMSIZ);
+ return ir;
+}
+
+static int dev_bind_ifindex(int fd, const int ifindex)
+{
+ struct sockaddr_ll fromaddr;
+ socklen_t addrlen = sizeof(fromaddr);
+
+ fromaddr.sll_family = AF_PACKET;
+ fromaddr.sll_protocol = htons(ETH_P_ALL);
+ fromaddr.sll_ifindex = ifindex;
+ return bind(fd, (struct sockaddr *) &fromaddr, addrlen);
+}
+
+int dev_bind_ifname(int fd, const char * const ifname)
+{
+ int ifindex = 0;
+
+ if (ifname) {
+ int ir;
+ struct ifreq ifr;
+
+ strcpy(ifr.ifr_name, ifname);
+ ir = ioctl(fd, SIOCGIFINDEX, &ifr);
+ if (ir)
+ return ir;
+ ifindex = ifr.ifr_ifindex;
+ }
+
+ return dev_bind_ifindex(fd, ifindex);
+}
diff --git a/src/ifaces.h b/src/ifaces.h
new file mode 100644
index 0000000..ea94fd1
--- /dev/null
+++ b/src/ifaces.h
@@ -0,0 +1,16 @@
+#ifndef IPTRAF_NG_IFACES_H
+#define IPTRAF_NG_IFACES_H
+
+FILE *open_procnetdev(void);
+int get_next_iface(FILE * fd, char *ifname, int n);
+int dev_up(char *iface);
+void err_iface_down(void);
+int dev_get_ifindex(const char *iface);
+int dev_get_mtu(const char *iface);
+int dev_get_flags(const char *iface);
+int dev_set_flags(const char *iface, int flags);
+int dev_clear_flags(const char *iface, int flags);
+int dev_get_ifname(int ifindex, char *ifname);
+int dev_bind_ifname(const int fd, const char * const ifname);
+
+#endif /* IPTRAF_NG_IFACES_H */
diff --git a/src/ifstats.c b/src/ifstats.c
new file mode 100644
index 0000000..00a2a3f
--- /dev/null
+++ b/src/ifstats.c
@@ -0,0 +1,726 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+/***
+
+ifstats.c - the interface statistics module
+
+ ***/
+
+#include "iptraf-ng-compat.h"
+
+#include "tui/labels.h"
+#include "tui/listbox.h"
+#include "tui/msgboxes.h"
+#include "tui/winops.h"
+
+#include "ifaces.h"
+#include "fltdefs.h"
+#include "packet.h"
+#include "options.h"
+#include "log.h"
+#include "dirs.h"
+#include "deskman.h"
+#include "attrs.h"
+#include "serv.h"
+#include "timer.h"
+#include "logvars.h"
+#include "error.h"
+#include "ifstats.h"
+#include "rate.h"
+#include "capt.h"
+#include "counters.h"
+
+#define SCROLLUP 0
+#define SCROLLDOWN 1
+
+struct iflist {
+ char ifname[IFNAMSIZ];
+ int ifindex;
+ unsigned long long iptotal;
+ unsigned long long ip6total;
+ unsigned long badtotal;
+ unsigned long long noniptotal;
+ unsigned long long total;
+ unsigned int spanbr;
+ unsigned long br;
+ struct rate rate;
+ unsigned long peakrate;
+ unsigned int index;
+ struct iflist *prev_entry;
+ struct iflist *next_entry;
+};
+
+struct iftab {
+ struct iflist *head;
+ struct iflist *tail;
+ struct iflist *firstvisible;
+ struct iflist *lastvisible;
+ struct pkt_counter totals;
+ struct rate rate_total;
+ struct rate rate_totalpps;
+ WINDOW *borderwin;
+ PANEL *borderpanel;
+ WINDOW *statwin;
+ PANEL *statpanel;
+};
+
+/*
+ * USR1 log-rotation signal handlers
+ */
+
+static void rotate_gstat_log(int s __unused)
+{
+ rotate_flag = 1;
+ strcpy(target_logname, GSTATLOG);
+ signal(SIGUSR1, rotate_gstat_log);
+}
+
+static void writegstatlog(struct iftab *table, unsigned long nsecs, FILE *fd)
+{
+ struct iflist *ptmp = table->head;
+ char atime[TIME_TARGET_MAX];
+
+ genatime(time(NULL), atime);
+ fprintf(fd, "\n*** General interface statistics log generated %s\n\n",
+ atime);
+
+ while (ptmp != NULL) {
+
+ fprintf(fd,
+ "%s: %llu total, %llu IP, %llu non-IP, %lu IP checksum errors",
+ ptmp->ifname, ptmp->total, ptmp->iptotal,
+ ptmp->noniptotal, ptmp->badtotal);
+
+ if (nsecs > 5) {
+ char buf[64];
+
+ rate_print(ptmp->br / nsecs, buf, sizeof(buf));
+ fprintf(fd, ", average activity %s", buf);
+ rate_print(ptmp->peakrate, buf, sizeof(buf));
+ fprintf(fd, ", peak activity %s", buf);
+ rate_print(rate_get_average(&ptmp->rate), buf, sizeof(buf));
+ fprintf(fd, ", last 5-second average activity %s", buf);
+ }
+ fprintf(fd, "\n");
+
+ ptmp = ptmp->next_entry;
+ }
+
+ fprintf(fd, "\n%lu seconds running time\n", nsecs);
+ fflush(fd);
+}
+
+/*
+ * Function to check if an interface is already in the interface list.
+ * This eliminates duplicate interface entries due to aliases
+ */
+
+static int ifinlist(struct iflist *list, char *ifname)
+{
+ struct iflist *ptmp = list;
+ int result = 0;
+
+ while ((ptmp != NULL) && (result == 0)) {
+ result = (strcmp(ifname, ptmp->ifname) == 0);
+ ptmp = ptmp->next_entry;
+ }
+
+ return result;
+}
+
+static struct iflist *alloc_iflist_entry(void)
+{
+ struct iflist *tmp = xmallocz(sizeof(struct iflist));
+
+ rate_alloc(&tmp->rate, 5);
+
+ return tmp;
+}
+
+static void free_iflist_entry(struct iflist *ptr)
+{
+ if (!ptr)
+ return;
+
+ rate_destroy(&ptr->rate);
+ free(ptr);
+}
+
+/*
+ * Initialize the list of interfaces. This linked list is used in the
+ * selection boxes as well as in the general interface statistics screen.
+ *
+ * This function parses the /proc/net/dev file and grabs the interface names
+ * from there. The SIOGIFFLAGS ioctl() call is used to determine whether the
+ * interfaces are active. Inactive interfaces are omitted from selection
+ * lists.
+ */
+
+static void initiflist(struct iflist **list)
+{
+ char ifname[IFNAMSIZ];
+
+ *list = NULL;
+
+ FILE *fd = open_procnetdev();
+ if (fd == NULL) {
+ tui_error(ANYKEY_MSG, "Unable to obtain interface list");
+ return;
+ }
+
+ while (get_next_iface(fd, ifname, sizeof(ifname))) {
+ if (!*ifname)
+ continue;
+
+ if (ifinlist(*list, ifname)) /* ignore entry if already in */
+ continue; /* interface list */
+
+ /*
+ * Check if the interface is actually up running. This prevents
+ * inactive devices in /proc/net/dev from actually appearing in
+ * interface lists used by IPTraf.
+ */
+
+ if (!dev_up(ifname))
+ continue;
+
+ int ifindex = dev_get_ifindex(ifname);
+ if (ifindex < 0)
+ continue;
+ /*
+ * At this point, the interface is now sure to be up and running.
+ */
+
+ struct iflist *itmp = alloc_iflist_entry();
+ itmp->ifindex = ifindex;
+ strcpy(itmp->ifname, ifname);
+
+ /* make the linked list sorted by ifindex */
+ struct iflist *cur = *list, *last = NULL;
+ while (cur != NULL && strcmp(cur->ifname, ifname) < 0) {
+ last = cur;
+ cur = cur->next_entry;
+ }
+ itmp->prev_entry = last;
+ itmp->next_entry = cur;
+ if (cur)
+ cur->prev_entry = itmp;
+ if (last)
+ last->next_entry = itmp;
+ else
+ *list = itmp;
+ }
+ fclose(fd);
+
+ /* let the index follow the sorted linked list */
+ unsigned int index = 1;
+ struct iflist *cur;
+ for (cur = *list; cur != NULL; cur = cur->next_entry)
+ cur->index = index++;
+}
+
+static struct iflist *positionptr(struct iflist *iflist, const int ifindex)
+{
+ struct iflist *ptmp = iflist;
+ struct iflist *last = ptmp;
+
+ while ((ptmp != NULL) && (ptmp->ifindex != ifindex)) {
+ last = ptmp;
+ ptmp = ptmp->next_entry;
+ }
+ /* no interface was found, try to create new one */
+ if (ptmp == NULL) {
+ struct iflist *itmp = alloc_iflist_entry();
+ itmp->ifindex = ifindex;
+ itmp->index = last->index + 1;
+ int r = dev_get_ifname(ifindex, itmp->ifname);
+ if (r != 0) {
+ write_error("Error getting interface name");
+ free_iflist_entry(itmp);
+ return(NULL);
+ }
+
+ /* last can't be NULL otherwise we will have empty iflist */
+ last->next_entry = itmp;
+ itmp->prev_entry = last;
+ itmp->next_entry = NULL;
+ ptmp = itmp;
+ }
+ return(ptmp);
+}
+
+static void destroyiflist(struct iflist *list)
+{
+ struct iflist *ptmp = list;
+
+ while (ptmp != NULL) {
+ struct iflist *ctmp = ptmp->next_entry;
+
+ free_iflist_entry(ptmp);
+ ptmp = ctmp;
+ }
+}
+
+static void no_ifaces_error(void)
+{
+ write_error("No active interfaces. Check their status or the /proc filesystem");
+}
+
+static void updaterates(struct iftab *table, unsigned long msecs)
+{
+ struct iflist *ptmp = table->head;
+ unsigned long rate;
+
+ rate_add_rate(&table->rate_total, table->totals.pc_bytes, msecs);
+ rate_add_rate(&table->rate_totalpps, table->totals.pc_packets, msecs);
+ pkt_counter_reset(&table->totals);
+ while (ptmp != NULL) {
+ rate_add_rate(&ptmp->rate, ptmp->spanbr, msecs);
+ rate = rate_get_average(&ptmp->rate);
+
+ if (rate > ptmp->peakrate)
+ ptmp->peakrate = rate;
+
+ ptmp->spanbr = 0;
+ ptmp = ptmp->next_entry;
+ }
+}
+
+static void showrates(struct iftab *table)
+{
+ struct iflist *ptmp = table->firstvisible;
+ unsigned int idx = table->firstvisible->index;
+ unsigned long rate;
+ char buf[64];
+
+ wattrset(table->statwin, HIGHATTR);
+ do {
+ rate = rate_get_average(&ptmp->rate);
+ rate_print(rate, buf, sizeof(buf));
+ wmove(table->statwin, ptmp->index - idx, 63 * COLS / 80);
+ wprintw(table->statwin, "%s", buf);
+
+ ptmp = ptmp->next_entry;
+ } while (ptmp != table->lastvisible->next_entry);
+}
+
+static void printifentry(struct iftab *table, struct iflist *ptmp)
+{
+ int target_row = ptmp->index - table->firstvisible->index;
+ WINDOW *win = table->statwin;
+
+ if ((target_row < 0) || (target_row > LINES - 5))
+ return;
+
+ wattrset(win, STDATTR);
+ mvwprintw(win, target_row, 1, "%s", ptmp->ifname);
+ wattrset(win, HIGHATTR);
+ wmove(win, target_row, 14 * COLS / 80);
+ printlargenum(ptmp->total, win);
+ wmove(win, target_row, 24 * COLS / 80);
+ printlargenum(ptmp->iptotal, win);
+ wmove(win, target_row, 34 * COLS / 80);
+ printlargenum(ptmp->ip6total, win);
+ wmove(win, target_row, 44 * COLS / 80);
+ printlargenum(ptmp->noniptotal, win);
+ wmove(win, target_row, 53 * COLS / 80);
+ wprintw(win, "%7lu", ptmp->badtotal);
+}
+
+static void print_if_entries(struct iftab *table)
+{
+ struct iflist *ptmp = table->firstvisible;
+ unsigned int i = 1;
+
+ unsigned int winht = LINES - 4;
+
+ do {
+ printifentry(table, ptmp);
+
+ if (i <= winht)
+ table->lastvisible = ptmp;
+
+ ptmp = ptmp->next_entry;
+ i++;
+ } while ((ptmp != NULL) && (i <= winht));
+}
+
+static void labelstats(WINDOW *win)
+{
+ mvwprintw(win, 0, 1, " Iface ");
+ /* 14, 24, 34, ... from printifentry() */
+ /* 10 = strlen(printed number); from printlargenum() */
+ /* 7 = strlen(" Total ") */
+ /* 1 = align the string on 'l' from " Total " */
+ mvwprintw(win, 0, (14 * COLS / 80) + 10 - 7 + 1, " Total ");
+ mvwprintw(win, 0, (24 * COLS / 80) + 10 - 6 + 1, " IPv4 ");
+ mvwprintw(win, 0, (34 * COLS / 80) + 10 - 6 + 1, " IPv6 ");
+ mvwprintw(win, 0, (44 * COLS / 80) + 10 - 7 + 1, " NonIP ");
+ mvwprintw(win, 0, (53 * COLS / 80) + 8 - 7 + 1, " BadIP ");
+ mvwprintw(win, 0, (63 * COLS / 80) + 14 - 10, " Activity ");
+}
+
+static void initiftab(struct iftab *table)
+{
+ table->borderwin = newwin(LINES - 2, COLS, 1, 0);
+ table->borderpanel = new_panel(table->borderwin);
+
+ rate_alloc(&table->rate_total, 5);
+ rate_alloc(&table->rate_totalpps, 5);
+ pkt_counter_reset(&table->totals);
+
+ move(LINES - 1, 1);
+ scrollkeyhelp();
+ stdexitkeyhelp();
+ wattrset(table->borderwin, BOXATTR);
+ tx_box(table->borderwin, ACS_VLINE, ACS_HLINE);
+ labelstats(table->borderwin);
+ table->statwin = newwin(LINES - 4, COLS - 2, 2, 1);
+ table->statpanel = new_panel(table->statwin);
+ tx_stdwinset(table->statwin);
+ wtimeout(table->statwin, -1);
+ wattrset(table->statwin, STDATTR);
+ tx_colorwin(table->statwin);
+}
+
+/*
+ * Scrolling routines for the general interface statistics window
+ */
+
+static void scrollgstatwin(struct iftab *table, int direction, int lines)
+{
+ if (lines < 1)
+ return;
+
+ wattrset(table->statwin, STDATTR);
+ if (direction == SCROLLUP) {
+ for (int i = 0; i < lines; i++) {
+ if (table->lastvisible->next_entry == NULL)
+ break;
+
+ table->firstvisible = table->firstvisible->next_entry;
+ table->lastvisible = table->lastvisible->next_entry;
+
+ wscrl(table->statwin, 1);
+ scrollok(table->statwin, 0);
+ mvwprintw(table->statwin, LINES - 5, 0, "%*c", COLS - 2, ' ');
+ scrollok(table->statwin, 1);
+
+ printifentry(table, table->lastvisible);
+ }
+ } else {
+ for (int i = 0; i < lines; i++) {
+ if (table->firstvisible == table->head)
+ break;
+
+ table->firstvisible = table->firstvisible->prev_entry;
+ table->lastvisible = table->lastvisible->prev_entry;
+
+ wscrl(table->statwin, -1);
+ mvwprintw(table->statwin, 0, 0, "%*c", COLS - 2, ' ');
+
+ printifentry(table, table->firstvisible);
+ }
+ }
+ showrates(table);
+}
+
+static void ifstats_process_key(struct iftab *table, int ch)
+{
+ switch (ch) {
+ case KEY_UP:
+ scrollgstatwin(table, SCROLLDOWN, 1);
+ break;
+ case KEY_DOWN:
+ scrollgstatwin(table, SCROLLUP, 1);
+ break;
+ case KEY_PPAGE:
+ case '-':
+ scrollgstatwin(table, SCROLLDOWN, LINES - 5);
+ break;
+ case KEY_NPAGE:
+ case ' ':
+ scrollgstatwin(table, SCROLLUP, LINES - 5);
+ break;
+ case KEY_HOME:
+ scrollgstatwin(table, SCROLLDOWN, INT_MAX);
+ break;
+ case KEY_END:
+ scrollgstatwin(table, SCROLLUP, INT_MAX);
+ break;
+ case 12:
+ case 'l':
+ case 'L':
+ tx_refresh_screen();
+ break;
+ case 'Q':
+ case 'q':
+ case 'X':
+ case 'x':
+ case 27:
+ case 24:
+ exitloop = 1;
+ break;
+ case ERR:
+ default:
+ /* no key ready, do nothing */
+ break;
+ }
+}
+
+static void ifstats_process_packet(struct iftab *table, struct pkt_hdr *pkt)
+{
+ int pkt_result = packet_process(pkt, NULL, NULL, NULL,
+ MATCH_OPPOSITE_USECONFIG,
+ options.v6inv4asv6);
+
+ switch (pkt_result) {
+ case PACKET_OK: /* we only handle these */
+ case MORE_FRAGMENTS:
+ case CHECKSUM_ERROR:
+ break;
+ default: /* drop others */
+ return;
+ }
+
+ pkt_counter_update(&table->totals, pkt->pkt_len);
+
+ struct iflist *ptmp = positionptr(table->head, pkt->from->sll_ifindex);
+ if (!ptmp)
+ return;
+
+ ptmp->total++;
+
+ ptmp->spanbr += pkt->pkt_len;
+ ptmp->br += pkt->pkt_len;
+
+ if (pkt->pkt_protocol == ETH_P_IP) {
+ ptmp->iptotal++;
+
+ if (pkt_result == CHECKSUM_ERROR) {
+ ptmp->badtotal++;
+ return;
+ }
+ } else if (pkt->pkt_protocol == ETH_P_IPV6) {
+ ptmp->ip6total++;
+ } else {
+ ptmp->noniptotal++;
+ }
+}
+
+/*
+ * The general interface statistics function
+ */
+
+void ifstats(time_t facilitytime)
+{
+ int logging = options.logging;
+ struct iftab table;
+
+ FILE *logfile = NULL;
+
+ int ch;
+
+ struct capt capt;
+
+ struct pkt_hdr pkt;
+
+ initiflist(&(table.head));
+ if (!table.head) {
+ no_ifaces_error();
+ return;
+ }
+
+ initiftab(&table);
+
+ if (capt_init(&capt, NULL) == -1) {
+ write_error("Unable to initialize packet capture interface");
+ goto err;
+ }
+
+ if (logging) {
+ if (strcmp(current_logfile, "") == 0) {
+ strcpy(current_logfile, GSTATLOG);
+
+ if (!daemonized)
+ input_logfile(current_logfile, &logging);
+ }
+ }
+
+ if (logging) {
+ opentlog(&logfile, GSTATLOG);
+
+ if (logfile == NULL)
+ logging = 0;
+ }
+ if (logging) {
+ signal(SIGUSR1, rotate_gstat_log);
+
+ rotate_flag = 0;
+ writelog(logging, logfile,
+ "******** General interface statistics started ********");
+ }
+
+ table.firstvisible = table.head;
+ print_if_entries(&table);
+ showrates(&table);
+
+ update_panels();
+ doupdate();
+
+ packet_init(&pkt);
+
+ exitloop = 0;
+
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ struct timespec last_time = now;
+ struct timespec next_screen_update = { 0 };
+
+ time_t starttime = now.tv_sec;
+ time_t endtime = INT_MAX;
+ if (facilitytime != 0)
+ endtime = now.tv_sec + facilitytime * 60;
+
+ time_t log_next = INT_MAX;
+ if (logging)
+ log_next = now.tv_sec + options.logspan;
+
+ while (!exitloop) {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ if (now.tv_sec > last_time.tv_sec) {
+ unsigned long msecs = timespec_diff_msec(&now, &last_time);
+ updaterates(&table, msecs);
+ showrates(&table);
+
+ printelapsedtime(now.tv_sec - starttime, 1, table.borderwin);
+
+ print_packet_drops(capt_get_dropped(&capt), table.borderwin, 61);
+
+ wattrset(table.borderwin, BOXATTR);
+ char buf[64];
+ rate_print(rate_get_average(&table.rate_total), buf, sizeof(buf));
+ mvwprintw(table.borderwin,
+ getmaxy(table.borderwin) - 1, 19,
+ " Total: %s / %9lu pps ",
+ buf,
+ rate_get_average(&table.rate_totalpps));
+
+ if (logging && (now.tv_sec > log_next)) {
+ check_rotate_flag(&logfile);
+ writegstatlog(&table, now.tv_sec - starttime, logfile);
+ log_next = now.tv_sec + options.logspan;
+ }
+
+ if (now.tv_sec > endtime)
+ exitloop = 1;
+
+ last_time = now;
+ }
+ if (time_after(&now, &next_screen_update)) {
+ print_if_entries(&table);
+ update_panels();
+ doupdate();
+
+ set_next_screen_update(&next_screen_update, &now);
+ }
+
+ if (capt_get_packet(&capt, &pkt, &ch, table.statwin) == -1) {
+ write_error("Packet receive failed");
+ exitloop = 1;
+ break;
+ }
+
+ if (ch != ERR)
+ ifstats_process_key(&table, ch);
+
+ if (pkt.pkt_len > 0) {
+ ifstats_process_packet(&table, &pkt);
+ capt_put_packet(&capt, &pkt);
+ }
+
+ }
+ packet_destroy(&pkt);
+
+ if (logging) {
+ signal(SIGUSR1, SIG_DFL);
+ writegstatlog(&table, time(NULL) - starttime, logfile);
+ writelog(logging, logfile,
+ "******** General interface statistics stopped ********");
+ fclose(logfile);
+ }
+ strcpy(current_logfile, "");
+
+ capt_destroy(&capt);
+err:
+ del_panel(table.statpanel);
+ delwin(table.statwin);
+ del_panel(table.borderpanel);
+ delwin(table.borderwin);
+ update_panels();
+ doupdate();
+
+ destroyiflist(table.head);
+ rate_destroy(&table.rate_total);
+ rate_destroy(&table.rate_totalpps);
+}
+
+void selectiface(char *ifname, int withall, int *aborted)
+{
+ struct iflist *list;
+ struct iflist *ptmp;
+
+ struct scroll_list scrolllist;
+
+ initiflist(&list);
+
+ if (list == NULL) {
+ no_ifaces_error();
+ *aborted = 1;
+ return;
+ }
+
+ if ((withall) && (list != NULL)) {
+ ptmp = alloc_iflist_entry();
+ strncpy(ptmp->ifname, "All interfaces", sizeof(ptmp->ifname));
+ ptmp->ifindex = 0;
+
+ ptmp->prev_entry = NULL;
+ list->prev_entry = ptmp;
+ ptmp->next_entry = list;
+ list = ptmp;
+ }
+ tx_listkeyhelp(STDATTR, HIGHATTR);
+
+ ptmp = list;
+
+ tx_init_listbox(&scrolllist, 24, 14, (COLS - 24) / 2 - 9,
+ (LINES - 14) / 2, STDATTR, BOXATTR, BARSTDATTR,
+ HIGHATTR);
+
+ tx_set_listbox_title(&scrolllist, "Select Interface", 1);
+
+ while (ptmp != NULL) {
+ tx_add_list_entry(&scrolllist, (char *) ptmp, ptmp->ifname);
+ ptmp = ptmp->next_entry;
+ }
+
+ tx_show_listbox(&scrolllist);
+ tx_operate_listbox(&scrolllist, aborted);
+ tx_close_listbox(&scrolllist);
+
+ if (!(*aborted) && (list != NULL)) {
+ ptmp = (struct iflist *) scrolllist.textptr->nodeptr;
+ if ((withall) && (ptmp->prev_entry == NULL)) /* All Interfaces */
+ strcpy(ifname, "");
+ else
+ strcpy(ifname, ptmp->ifname);
+ }
+
+ tx_destroy_list(&scrolllist);
+ destroyiflist(list);
+ update_panels();
+ doupdate();
+}
diff --git a/src/ifstats.h b/src/ifstats.h
new file mode 100644
index 0000000..5cf8b15
--- /dev/null
+++ b/src/ifstats.h
@@ -0,0 +1,7 @@
+#ifndef IPTRAF_NG_IFSTATS_H
+#define IPTRAF_NG_IFSTATS_H
+
+void selectiface(char *ifname, int withall, int *aborted);
+void ifstats(time_t facilitytime);
+
+#endif /* IPTRAF_NG_IFSTATS_H */
diff --git a/src/ipfilter.c b/src/ipfilter.c
new file mode 100644
index 0000000..71a0dbb
--- /dev/null
+++ b/src/ipfilter.c
@@ -0,0 +1,430 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+/***
+
+ipfilter.c - user interface and filter function for all IP packets
+
+***/
+
+#include "iptraf-ng-compat.h"
+
+#include "tui/input.h"
+#include "tui/menurt.h"
+#include "tui/msgboxes.h"
+
+#include "addproto.h"
+#include "dirs.h"
+#include "deskman.h"
+#include "attrs.h"
+#include "fltdefs.h"
+#include "fltmgr.h"
+#include "fltselect.h"
+#include "ipfilter.h"
+#include "fltedit.h"
+#include "getpath.h"
+#include "parseproto.h"
+#include "cidr.h"
+
+static in_port_t parse_port(char *buf)
+{
+ unsigned int value;
+
+ if ((strtoul_ui(buf, 10, &value) == 0) && (value <= 65535))
+ return value;
+ else
+ return 0;
+}
+void gethostparams(struct hostparams *data, char *init_saddr, char *init_smask,
+ char *init_sport1, char *init_sport2, char *init_daddr,
+ char *init_dmask, char *init_dport1, char *init_dport2,
+ char *initinex, char *initmatchop, int *aborted)
+{
+ WINDOW *dlgwin;
+ PANEL *dlgpanel;
+
+ struct FIELDLIST fields;
+ struct FIELD *fieldptr;
+
+ unsigned int rangeproto1, rangeproto2;
+ int parse_result;
+ char *bptr, *cptr;
+ int doagain;
+ unsigned int i;
+ char msgstr[60];
+ unsigned int maskbits;
+
+ const char *WILDCARD = "0.0.0.0";
+
+ dlgwin = newwin(22, 80, (LINES - 22) / 2, (COLS - 80) / 2);
+ dlgpanel = new_panel(dlgwin);
+
+ wattrset(dlgwin, DLGBOXATTR);
+ tx_colorwin(dlgwin);
+ tx_box(dlgwin, ACS_VLINE, ACS_HLINE);
+
+ mvwprintw(dlgwin, 0, 22, " Source ");
+ mvwprintw(dlgwin, 0, 52, " Destination ");
+
+ wmove(dlgwin, 20, 2);
+ tabkeyhelp(dlgwin);
+ stdkeyhelp(dlgwin);
+ wattrset(dlgwin, DLGTEXTATTR);
+ mvwprintw(dlgwin, 2, 2, "IP address");
+ mvwprintw(dlgwin, 4, 2, "Wildcard mask");
+ mvwprintw(dlgwin, 6, 2, "Port");
+ mvwprintw(dlgwin, 9, 2, "Protocols to match");
+ mvwprintw(dlgwin, 10, 2, "(Enter Y beside each");
+ mvwprintw(dlgwin, 11, 2, "protocol to match.)");
+ mvwprintw(dlgwin, 18, 2, "Include/Exclude (I/E)");
+
+ tx_initfields(&fields, 19, 55, (LINES - 22) / 2 + 1,
+ (COLS - 80) / 2 + 23, DLGTEXTATTR, FIELDATTR);
+
+ mvwprintw(fields.fieldwin, 5, 6, "to");
+ mvwprintw(fields.fieldwin, 5, 36, "to");
+ mvwprintw(fields.fieldwin, 6, 0,
+ "Port fields apply only to TCP and UDP packets");
+ mvwprintw(fields.fieldwin, 8, 3, "All IP");
+ mvwprintw(fields.fieldwin, 8, 16, "TCP");
+ mvwprintw(fields.fieldwin, 8, 26, "UDP");
+ mvwprintw(fields.fieldwin, 8, 35, "ICMP");
+ mvwprintw(fields.fieldwin, 8, 45, "IGMP");
+ mvwprintw(fields.fieldwin, 10, 5, "OSPF");
+ mvwprintw(fields.fieldwin, 10, 16, "IGP");
+ mvwprintw(fields.fieldwin, 10, 25, "IGRP");
+ mvwprintw(fields.fieldwin, 10, 36, "GRE");
+ mvwprintw(fields.fieldwin, 10, 45, "L2TP");
+ mvwprintw(fields.fieldwin, 12, 1, "IPSec AH");
+ mvwprintw(fields.fieldwin, 12, 13, "IPSec ESP");
+ mvwprintw(fields.fieldwin, 14, 1,
+ "Additional protocols or ranges (e.g. 8, 18-20, 69, 90)");
+ mvwprintw(fields.fieldwin, 17, 11, "Match opposite (Y/N)");
+
+ tx_addfield(&fields, 25, 1, 0, init_saddr);
+ tx_addfield(&fields, 25, 3, 0, init_smask);
+ tx_addfield(&fields, 5, 5, 0, init_sport1);
+ tx_addfield(&fields, 5, 5, 9, init_sport2);
+ tx_addfield(&fields, 25, 1, 30, init_daddr);
+ tx_addfield(&fields, 25, 3, 30, init_dmask);
+ tx_addfield(&fields, 5, 5, 30, init_dport1);
+ tx_addfield(&fields, 5, 5, 39, init_dport2);
+
+ tx_addfield(&fields, 1, 8, 10, (data->filters[F_ALL_IP]) ? "Y" : "");
+ tx_addfield(&fields, 1, 8, 20, (data->filters[F_TCP]) ? "Y" : "");
+ tx_addfield(&fields, 1, 8, 30, (data->filters[F_UDP]) ? "Y" : "");
+ tx_addfield(&fields, 1, 8, 40, (data->filters[F_ICMP]) ? "Y" : "");
+ tx_addfield(&fields, 1, 8, 50, (data->filters[F_IGMP]) ? "Y" : "");
+ tx_addfield(&fields, 1, 10, 10, (data->filters[F_OSPF]) ? "Y" : "");
+ tx_addfield(&fields, 1, 10, 20, (data->filters[F_IGP]) ? "Y" : "");
+ tx_addfield(&fields, 1, 10, 30, (data->filters[F_IGRP]) ? "Y" : "");
+ tx_addfield(&fields, 1, 10, 40, (data->filters[F_GRE]) ? "Y" : "");
+ tx_addfield(&fields, 1, 10, 50, (data->filters[F_L2TP]) ? "Y" : "");
+ tx_addfield(&fields, 1, 12, 10, (data->filters[F_IPSEC_AH]) ? "Y" : "");
+ tx_addfield(&fields, 1, 12, 23, (data->filters[F_IPSEC_ESP]) ? "Y" : "");
+
+ cptr = skip_whitespace(data->protolist);
+ tx_addfield(&fields, 54, 15, 1, cptr);
+ tx_addfield(&fields, 1, 17, 1, initinex);
+ tx_addfield(&fields, 1, 17, 32, initmatchop);
+
+ do {
+ tx_fillfields(&fields, aborted); /*get input */
+ if (!(*aborted)) {
+ fieldptr = fields.list;
+
+ /*
+ * Adjust upper loop bound depending on the number of fields
+ * before the "Additional IP protocols" field.
+ */
+ for (i = 2; i <= 21; i++)
+ fieldptr = fieldptr->nextfield;
+
+ if (!validate_ranges
+ (fieldptr->buf, &parse_result, &bptr)) {
+ snprintf(msgstr, 60,
+ "Invalid protocol input at or near token \"%s\"",
+ bptr);
+ tui_error(ANYKEY_MSG, "%s", msgstr);
+ doagain = 1;
+ } else
+ doagain = 0;
+ } else {
+ doagain = 0;
+ }
+ } while (doagain);
+
+ /*
+ * Store entered filter data into data structures
+ */
+ if (!(*aborted)) {
+ fieldptr = fields.list;
+ maskbits = 0;
+
+ /*
+ * Process Source Address field
+ */
+ if (fieldptr->buf[0] == '\0')
+ strcpy(data->s_fqdn, WILDCARD);
+ else
+ strcpy(data->s_fqdn, fieldptr->buf);
+
+ if (strchr(data->s_fqdn, '/') != NULL) {
+ cidr_split_address(data->s_fqdn, &maskbits);
+ }
+
+ /*
+ * Process Source Mask field
+ */
+ fieldptr = fieldptr->nextfield;
+ if (fieldptr->buf[0] == '\0') {
+ if (maskbits > 32) {
+ strcpy(data->s_mask, WILDCARD);
+ } else {
+ strncpy(data->s_mask,
+ cidr_get_quad_mask(maskbits),
+ sizeof(data->s_mask) - 1);
+ }
+ } else
+ strcpy(data->s_mask, fieldptr->buf);
+
+ /*
+ * Process Source Port fields
+ */
+ fieldptr = fieldptr->nextfield;
+ data->sport1 = parse_port(fieldptr->buf);
+
+ fieldptr = fieldptr->nextfield;
+ data->sport2 = parse_port(fieldptr->buf);
+
+ /*
+ * Process Destination Address field
+ */
+ fieldptr = fieldptr->nextfield;
+ if (fieldptr->buf[0] == '\0')
+ strcpy(data->d_fqdn, WILDCARD);
+ else
+ strcpy(data->d_fqdn, fieldptr->buf);
+
+ maskbits = 0;
+ if (strchr(data->d_fqdn, '/') != NULL) {
+ cidr_split_address(data->d_fqdn, &maskbits);
+ }
+
+ /*
+ * Process Destination mask field
+ */
+ fieldptr = fieldptr->nextfield;
+ if (fieldptr->buf[0] == '\0') {
+ if (maskbits > 32) {
+ strcpy(data->d_mask, WILDCARD);
+ } else {
+ strncpy(data->d_mask,
+ cidr_get_quad_mask(maskbits),
+ sizeof(data->d_mask) - 1);
+ }
+ } else
+ strcpy(data->d_mask, fieldptr->buf);
+
+ /*
+ * Process Dedination Port fields
+ */
+ fieldptr = fieldptr->nextfield;
+ data->dport1 = parse_port(fieldptr->buf);
+
+ fieldptr = fieldptr->nextfield;
+ data->dport2 = parse_port(fieldptr->buf);
+
+ /*
+ * Process IP protocol filter fields
+ */
+ fieldptr = fieldptr->nextfield;
+ memset(&(data->filters), 0, sizeof(data->filters));
+
+ if (toupper(fieldptr->buf[0]) == 'Y')
+ data->filters[F_ALL_IP] = 1;
+ fieldptr = fieldptr->nextfield;
+ if (toupper(fieldptr->buf[0]) == 'Y')
+ data->filters[F_TCP] = 1;
+ fieldptr = fieldptr->nextfield;
+ if (toupper(fieldptr->buf[0]) == 'Y')
+ data->filters[F_UDP] = 1;
+ fieldptr = fieldptr->nextfield;
+ if (toupper(fieldptr->buf[0]) == 'Y')
+ data->filters[F_ICMP] = 1;
+ fieldptr = fieldptr->nextfield;
+ if (toupper(fieldptr->buf[0]) == 'Y')
+ data->filters[F_IGMP] = 1;
+ fieldptr = fieldptr->nextfield;
+ if (toupper(fieldptr->buf[0]) == 'Y')
+ data->filters[F_OSPF] = 1;
+ fieldptr = fieldptr->nextfield;
+ if (toupper(fieldptr->buf[0]) == 'Y')
+ data->filters[F_IGP] = 1;
+ fieldptr = fieldptr->nextfield;
+ if (toupper(fieldptr->buf[0]) == 'Y')
+ data->filters[F_IGRP] = 1;
+ fieldptr = fieldptr->nextfield;
+ if (toupper(fieldptr->buf[0]) == 'Y')
+ data->filters[F_GRE] = 1;
+ fieldptr = fieldptr->nextfield;
+ if (toupper(fieldptr->buf[0]) == 'Y')
+ data->filters[F_L2TP] = 1;
+ fieldptr = fieldptr->nextfield;
+ if (toupper(fieldptr->buf[0]) == 'Y')
+ data->filters[F_IPSEC_AH] = 1;
+ fieldptr = fieldptr->nextfield;
+ if (toupper(fieldptr->buf[0]) == 'Y')
+ data->filters[F_IPSEC_ESP] = 1;
+ fieldptr = fieldptr->nextfield;
+
+ /*
+ * Parse protocol string
+ */
+ cptr = fieldptr->buf;
+ strncpy(data->protolist, cptr, 60);
+
+ do {
+ get_next_protorange(&cptr, &rangeproto1,
+ &rangeproto2, &parse_result, &bptr);
+ if (parse_result == RANGE_OK) {
+ if (rangeproto2 != 0) {
+ for (i = rangeproto1; i <= rangeproto2;
+ i++) {
+ data->filters[i] = 1;
+ }
+ } else {
+ data->filters[rangeproto1] = 1;
+ }
+ }
+ } while (parse_result == RANGE_OK);
+
+ data->reverse = toupper(fieldptr->nextfield->buf[0]);
+ if (data->reverse != 'E')
+ data->reverse = 'I';
+
+ data->match_opposite =
+ toupper(fieldptr->nextfield->nextfield->buf[0]);
+ if (data->match_opposite != 'Y')
+ data->match_opposite = 'N';
+ }
+
+ tx_destroyfields(&fields);
+ del_panel(dlgpanel);
+ delwin(dlgwin);
+ update_panels();
+ doupdate();
+}
+
+void ipfilterselect(int *aborted)
+{
+ struct MENU menu;
+ int row = 1;
+ struct filterfileent fflist;
+
+ makestdfiltermenu(&menu);
+ do {
+ tx_showmenu(&menu);
+ tx_operatemenu(&menu, &row, aborted);
+ switch (row) {
+ case 1:
+ definefilter(aborted);
+ break;
+ case 2:
+ selectfilter(&fflist, aborted);
+ if (!(*aborted)) {
+ memset(ofilter.filename, 0, FLT_FILENAME_MAX);
+ strncpy(ofilter.filename,
+ get_path(T_WORKDIR, fflist.filename),
+ FLT_FILENAME_MAX - 1);
+ if (!loadfilter(ofilter.filename, &ofilter.fl, FLT_RESOLVE))
+ ofilter.filtercode = 1;
+ else
+ ofilter.filtercode = 0;
+ }
+ break;
+ case 3:
+ destroyfilter(&ofilter.fl);
+ ofilter.filtercode = 0;
+ tx_infobox("IP filter deactivated", ANYKEY_MSG);
+ break;
+ case 4:
+ editfilter(aborted);
+ break;
+ case 5:
+ delfilter(aborted);
+ if (!(*aborted))
+ tx_infobox("IP filter deleted", ANYKEY_MSG);
+ }
+ } while (row != 7);
+ tx_destroymenu(&menu);
+ update_panels();
+ doupdate();
+}
+
+static int addr_in_net(unsigned long addr, unsigned long net,
+ unsigned long mask)
+{
+ return (addr & mask) == (net & mask);
+}
+
+static int port_in_range(in_port_t port, in_port_t port1, in_port_t port2)
+{
+ if (port2 == 0)
+ return port == port1 || port1 == 0;
+ else
+ return port >= port1 && port <= port2;
+}
+
+/* Display/logging filter for other (non-TCP, non-UDP) IP protocols. */
+int ipfilter(unsigned long saddr, unsigned long daddr, in_port_t sport,
+ in_port_t dport, unsigned int protocol, int match_opp_mode)
+{
+ struct filterent *fe;
+ int result = 0;
+ int fltexpr1;
+ int fltexpr2;
+
+ for (fe = ofilter.fl.head; fe != NULL; fe = fe->next_entry) {
+ if (protocol == IPPROTO_TCP || protocol == IPPROTO_UDP) {
+ fltexpr1 = addr_in_net(saddr, fe->saddr, fe->smask)
+ && addr_in_net(daddr, fe->daddr, fe->dmask)
+ && port_in_range(sport, fe->hp.sport1, fe->hp.sport2)
+ && port_in_range(dport, fe->hp.dport1, fe->hp.dport2);
+
+ if ((protocol == IPPROTO_TCP
+ && match_opp_mode == MATCH_OPPOSITE_ALWAYS)
+ || (fe->hp.match_opposite == 'Y'))
+ fltexpr2 = addr_in_net(saddr, fe->daddr, fe->dmask)
+ && addr_in_net(daddr, fe->saddr, fe->smask)
+ && port_in_range(sport, fe->hp.dport1, fe->hp.dport2)
+ && port_in_range(dport, fe->hp.sport1, fe->hp.sport2);
+ else
+ fltexpr2 = 0;
+ } else {
+ fltexpr1 = addr_in_net(saddr, fe->saddr, fe->smask)
+ && addr_in_net(daddr, fe->daddr, fe->dmask);
+
+ if (fe->hp.match_opposite == 'Y') {
+ fltexpr2 = addr_in_net(saddr, fe->daddr, fe->dmask)
+ && addr_in_net(daddr, fe->saddr, fe->smask);
+ } else
+ fltexpr2 = 0;
+ }
+
+ if (fltexpr1 || fltexpr2) {
+ result = fe->hp.filters[protocol]
+ || fe->hp.filters[F_ALL_IP];
+
+ if (result) {
+ if (toupper(fe->hp.reverse) == 'E') {
+ return 0;
+ }
+
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/src/ipfilter.h b/src/ipfilter.h
new file mode 100644
index 0000000..ac82b93
--- /dev/null
+++ b/src/ipfilter.h
@@ -0,0 +1,12 @@
+#ifndef IPTRAF_NG_IPFILTER_H
+#define IPTRAF_NG_IPFILTER_H
+
+void gethostparams(struct hostparams *data, char *init_saddr, char *init_smask,
+ char *init_sport1, char *init_sport2, char *init_daddr,
+ char *init_dmask, char *init_dport1, char *init_dport2,
+ char *initinex, char *initmatchop, int *aborted);
+void ipfilterselect(int *faborted);
+int ipfilter(unsigned long saddr, unsigned long daddr, in_port_t sport,
+ in_port_t dport, unsigned int protocol, int match_opp_mode);
+
+#endif /* IPTRAF_NG_IPFILTER_H */
diff --git a/src/ipfrag.c b/src/ipfrag.c
new file mode 100644
index 0000000..5ba61e3
--- /dev/null
+++ b/src/ipfrag.c
@@ -0,0 +1,248 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+/***
+
+ipfrag.c - module that handles fragmented IP packets.
+
+This module is necessary to maintain accurate counts in case
+fragmented IP packets are received. TCP and UDP headers are not copied
+in fragments.
+
+This module is based on RFC 815, but does not really reassemble packets.
+The routines here merely accumulate packet sizes and pass them off to
+the IP traffic monitor routine.
+
+***/
+
+#include "iptraf-ng-compat.h"
+
+#include "ipfrag.h"
+#include "list.h"
+
+struct fragdescent {
+ unsigned int min;
+ unsigned int max;
+ struct fragdescent *prev_entry;
+ struct fragdescent *next_entry;
+};
+
+struct fragent {
+ struct list_head fragent_list;
+ unsigned long s_addr;
+ in_port_t s_port;
+ unsigned long d_addr;
+ in_port_t d_port;
+ unsigned int id;
+ unsigned int protocol;
+ int firstin;
+ struct fragdescent *fragdesclist;
+ struct fragdescent *fragdesctail;
+ unsigned int bcount;
+};
+
+LIST_HEAD(frag_head);
+
+static struct fragent *addnewdgram(struct iphdr *packet)
+{
+ struct fragent *ptmp;
+
+ ptmp = xmallocz(sizeof(struct fragent));
+ list_add_tail(&ptmp->fragent_list, &frag_head);
+
+ ptmp->fragdesclist = xmalloc(sizeof(struct fragdescent));
+ ptmp->fragdesclist->min = 0;
+ ptmp->fragdesclist->max = 65535;
+ ptmp->fragdesclist->next_entry = NULL;
+ ptmp->fragdesclist->prev_entry = NULL;
+ ptmp->fragdesctail = ptmp->fragdesclist;
+
+ ptmp->s_addr = packet->saddr;
+ ptmp->d_addr = packet->daddr;
+ ptmp->protocol = packet->protocol;
+ ptmp->id = packet->id;
+
+ return ptmp;
+}
+
+static struct fragdescent *addnewhole(struct fragent *frag)
+{
+ struct fragdescent *ptmp;
+
+ ptmp = xmalloc(sizeof(struct fragdescent));
+
+ if (frag->fragdesclist == NULL) {
+ frag->fragdesclist = ptmp;
+ ptmp->prev_entry = NULL;
+ }
+ if (frag->fragdesctail != NULL) {
+ frag->fragdesctail->next_entry = ptmp;
+ ptmp->prev_entry = frag->fragdesctail;
+ }
+ ptmp->next_entry = NULL;
+ frag->fragdesctail = ptmp;
+
+ return ptmp;
+}
+
+static struct fragent *searchfrags(unsigned long saddr, unsigned long daddr,
+ unsigned int protocol, unsigned int id)
+{
+ struct fragent *ftmp;
+
+ list_for_each_entry(ftmp, &frag_head, fragent_list) {
+ if ((saddr == ftmp->s_addr) && (daddr == ftmp->d_addr)
+ && (protocol == ftmp->protocol) && (id == ftmp->id))
+ return ftmp;
+ }
+
+ return NULL;
+}
+
+static void deldgram(struct fragent *ftmp)
+{
+ list_del(&ftmp->fragent_list);
+ free(ftmp);
+}
+
+/* destroy hole descriptor list */
+static void destroyholes(struct fragent *ftmp)
+{
+ struct fragdescent *dtmp = ftmp->fragdesclist;
+
+ while (dtmp != NULL) {
+ struct fragdescent *ntmp = dtmp->next_entry;
+
+ free(dtmp);
+ dtmp = ntmp;
+ }
+}
+
+void destroyfraglist(void)
+{
+ struct fragent *entry, *tmp;
+
+ list_for_each_entry_safe(entry, tmp, &frag_head, fragent_list) {
+ destroyholes(entry);
+ deldgram(entry);
+ }
+}
+
+/*
+ * Process IP fragment. Returns number of bytes to report to the traffic
+ * monitor or 0 for an error condition.
+ */
+
+unsigned int processfragment(struct iphdr *packet, in_port_t *sport,
+ in_port_t *dport, int *firstin)
+{
+ struct fragent *ftmp;
+ struct fragdescent *dtmp;
+ struct fragdescent *ntmp;
+ char *tpacket;
+
+ unsigned int offset;
+ unsigned int lastbyte;
+ unsigned int retval;
+
+ /* Determine appropriate hole descriptor list */
+
+ ftmp =
+ searchfrags(packet->saddr, packet->daddr, packet->protocol,
+ packet->id);
+
+ if (ftmp == NULL) /* No such datagram for this frag yet */
+ ftmp = addnewdgram(packet);
+
+ if (ftmp == NULL)
+ return 0;
+
+ /*
+ * At this point, ftmp should contain the address of the appropriate
+ * descriptor list.
+ */
+
+ dtmp = ftmp->fragdesclist; /* Point to hole descriptors */
+ offset = ipv4_frag_offset(packet);
+ lastbyte = (offset + (ntohs(packet->tot_len) - (packet->ihl) * 4)) - 1;
+
+ if (ipv4_is_first_fragment(packet)) { /* first fragment? */
+ ftmp->firstin = 1;
+ tpacket = ((char *) (packet)) + (packet->ihl * 4);
+ if (packet->protocol == IPPROTO_TCP) {
+ ftmp->s_port = ntohs(((struct tcphdr *) tpacket)->source);
+ ftmp->d_port = ntohs(((struct tcphdr *) tpacket)->dest);
+ } else if (packet->protocol == IPPROTO_UDP) {
+ ftmp->s_port = ntohs(((struct udphdr *) tpacket)->source);
+ ftmp->d_port = ntohs(((struct udphdr *) tpacket)->dest);
+ }
+ }
+ while (dtmp != NULL) {
+ if ((offset <= dtmp->max) && (lastbyte >= dtmp->min))
+ break;
+
+ dtmp = dtmp->next_entry;
+ }
+
+ if (dtmp != NULL) { /* Duplicate/overlap or something out of the
+ loopback interface */
+ /*
+ * Delete current entry from hole descriptor list
+ */
+
+ if (dtmp->prev_entry != NULL)
+ dtmp->prev_entry->next_entry = dtmp->next_entry;
+ else
+ ftmp->fragdesclist = dtmp->next_entry;
+
+ if (dtmp->next_entry != NULL)
+ dtmp->next_entry->prev_entry = dtmp->prev_entry;
+ else
+ ftmp->fragdesctail = dtmp->prev_entry;
+
+ /*
+ * Memory for the hole descriptor will not be released yet.
+ */
+
+ if (offset > dtmp->min) {
+ /*
+ * If offset in fragment is greater than offset in the descriptor,
+ * create a new hole descriptor.
+ */
+
+ ntmp = addnewhole(ftmp);
+ ntmp->min = dtmp->min;
+ ntmp->max = offset - 1;
+ }
+ if ((lastbyte < dtmp->max)
+ && ipv4_more_fragments(packet)) {
+ /*
+ * If last byte in fragment is less than the last byte of the
+ * hole descriptor, and more fragments, create a new hole
+ * descriptor.
+ */
+
+ ntmp = addnewhole(ftmp);
+ ntmp->min = lastbyte + 1;
+ ntmp->max = dtmp->max;
+ }
+ free(dtmp);
+
+ }
+ *firstin = ftmp->firstin;
+
+ ftmp->bcount += ntohs(packet->tot_len);
+
+ if (ftmp->firstin) {
+ *sport = ftmp->s_port;
+ *dport = ftmp->d_port;
+ retval = ftmp->bcount;
+ ftmp->bcount = 0;
+
+ if (ftmp->fragdesclist == NULL)
+ deldgram(ftmp);
+
+ return retval;
+ } else
+ return 0;
+}
diff --git a/src/ipfrag.h b/src/ipfrag.h
new file mode 100644
index 0000000..6a0bc85
--- /dev/null
+++ b/src/ipfrag.h
@@ -0,0 +1,34 @@
+#ifndef IPTRAF_NG_IPFRAG_H
+#define IPTRAF_NG_IPFRAG_H
+
+/***
+
+ipfrag.h - IP fragmentation hander definitions
+
+***/
+
+static inline unsigned int ipv4_frag_offset(struct iphdr *ip)
+{
+ return (ntohs(ip->frag_off) & 0x1fff) * 8;
+}
+
+static inline int ipv4_is_first_fragment(struct iphdr *ip)
+{
+ return (ntohs(ip->frag_off) & 0x1fff) == 0;
+}
+
+static inline int ipv4_is_fragmented(struct iphdr *ip)
+{
+ return (ntohs(ip->frag_off) & 0x3fff) != 0;
+}
+
+static inline int ipv4_more_fragments(struct iphdr *ip)
+{
+ return (ntohs(ip->frag_off) & 0x2000) != 0;
+}
+
+void destroyfraglist(void);
+unsigned int processfragment(struct iphdr *packet, in_port_t *sport,
+ in_port_t *dport, int *firstin);
+
+#endif /* IPTRAF_NG_IPFRAG_H */
diff --git a/src/iptraf-ng-compat.h b/src/iptraf-ng-compat.h
new file mode 100644
index 0000000..5aec185
--- /dev/null
+++ b/src/iptraf-ng-compat.h
@@ -0,0 +1,147 @@
+#ifndef IPTRAF_NG_COMPAT_H
+#define IPTRAF_NG_COMPAT_H
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <signal.h>
+#include <string.h>
+#include <time.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <curses.h>
+#include <panel.h>
+#include <assert.h>
+#include <stddef.h>
+#include <poll.h>
+#include <limits.h>
+#include <locale.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+#include <sys/mman.h>
+
+#include <netinet/in.h>
+#include <netinet/udp.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#include <netinet/ip_icmp.h>
+
+#include <arpa/inet.h>
+
+#include <linux/if_ether.h>
+#include <linux/if_packet.h>
+#include <linux/if_fddi.h>
+#include <linux/types.h>
+
+#include <linux/if.h>
+#include <linux/if_arp.h>
+
+#ifndef ETH_P_8021AD
+#define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */
+#endif
+
+#ifndef ETH_P_QINQ1
+#define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
+#endif
+
+#ifndef ETH_P_QINQ2
+#define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
+#endif
+
+#ifndef ETH_P_QINQ3
+#define ETH_P_QINQ3 0x9300 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
+#endif
+
+#define debug(...) \
+ do { \
+ fprintf(stderr, "%s:%s():%d:", \
+ __FILE__, __func__, __LINE__); \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, "\n"); \
+ } while(0)
+
+#define KBITS 0
+
+#define __noreturn __attribute__((noreturn))
+#define __unused __attribute__((unused))
+#define __printf(x, y) __attribute__((format(printf, (x), (y))))
+
+/* screen delay (in msecs) if update rate == 0 */
+#define DEFAULT_UPDATE_DELAY 50
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+#define alloc_nr(x) (((x)+16)*3/2)
+
+/*
+ * Realloc the buffer pointed at by variable 'x' so that it can hold
+ * at least 'nr' entries; the number of entries currently allocated
+ * is 'alloc', using the standard growing factor alloc_nr() macro.
+ *
+ * DO NOT USE any expression with side-effect for 'x', 'nr', or 'alloc'.
+ */
+#define ALLOC_GROW(x, nr, alloc) \
+ do { \
+ if ((nr) > alloc) { \
+ if (alloc_nr(alloc) < (nr)) \
+ alloc = (nr); \
+ else \
+ alloc = alloc_nr(alloc); \
+ x = xrealloc((x), alloc * sizeof(*(x))); \
+ } \
+ } while (0)
+
+extern int daemonized;
+extern int exitloop;
+
+extern void *xmalloc(size_t size);
+extern void *xcalloc(size_t nmemb, size_t size);
+extern void *xrealloc(void *ptr, size_t size);
+extern void *xmallocz(size_t size);
+extern char *xstrdup(const char *s);
+extern int strtoul_ui(char const *s, int base, unsigned int *result);
+extern int strtol_i(char const *s, int base, int *result);
+
+extern void die(const char *err, ...) __noreturn __printf(1,2);
+extern void die_errno(const char *fmt, ...) __noreturn __printf(1,2);
+extern void error(const char *err, ...) __printf(1,2);
+
+static inline char *skip_whitespace(char *str)
+{
+ while (isspace(*str))
+ ++str;
+
+ return str;
+}
+
+static inline unsigned long timespec_diff_msec(const struct timespec *end,
+ const struct timespec *start)
+{
+ if (!start || !end)
+ return 0UL;
+
+ signed long secs = end->tv_sec - start->tv_sec;
+ signed long nsecs = end->tv_nsec - start->tv_nsec;
+
+ if(nsecs < 0) {
+ nsecs = 1000000000UL - nsecs;
+ secs -= 1;
+ }
+ if(secs >= 0)
+ return secs * 1000UL + nsecs / 1000000UL;
+ else
+ return 0UL;
+}
+
+#endif /* IPTRAF_NG_COMPAT_H */
diff --git a/src/iptraf-ng.8 b/src/iptraf-ng.8
new file mode 100644
index 0000000..ca574fd
--- /dev/null
+++ b/src/iptraf-ng.8
@@ -0,0 +1,98 @@
+.TH IPTRAF-NG 8 "IPTraf-ng Help Page"
+.SH NAME
+iptraf \- Interactive Colorful IP LAN Monitor
+.SH SYNOPSIS
+.BR iptraf-ng " { [ " \-f " ] [ { " \-i
+.IR iface " | "
+.BR \-g " | " \-d
+.IR iface " | "
+.BR \-s
+.IR iface " | "
+.BR \-z
+.IR iface " | "
+.BR \-l
+.IR iface " } [ "
+.BR \-t
+.IR timeout " ] [ "
+.BR \-B " [ "
+.BR \-L
+.IR logfile " ] ] ] | [ "
+.BR \-h " ] }"
+.br
+.SH DESCRIPTION
+.B iptraf-ng
+is an ncurses-based IP LAN monitor that generates various network statistics including TCP info, UDP counts, ICMP and OSPF information, Ethernet load info, node stats, IP checksum errors, and others.
+.PP
+If the
+.B iptraf-ng
+command is issued without any command-line options, the program comes up in interactive mode, with the various facilities accessed through the main menu.
+
+.SH OPTIONS
+These options can also be supplied to the command:
+.TP
+.BI "\-i " iface
+immediately start the IP traffic monitor on the specified interface, or
+all interfaces if "\-i all" is specified
+.TP
+.B "\-g"
+immediately start the general interface statistics
+.TP
+.BI "\-d " iface
+allows you to immediately start the detailed on the indicated interface (iface)
+.TP
+.BI "\-s " iface
+allows you to immediately monitor TCP and UDP traffic on the specified interface (iface)
+.TP
+.BI "\-z " iface
+shows packet counts by size on the specified interface
+.TP
+.BI "\-l " iface
+start the LAN station monitor on the specified interface, or all LAN
+interfaces if "\-l all" is specified
+.TP
+.BI "\-t " timeout
+tells IPTraf-ng to run the specified facility for only
+.I timeout
+minutes. This option is used only with one of the above parameters.
+.TP
+.B "\-B"
+redirect standard output to /dev/null, closes standard input, and forks
+the program into the background. Can be used only with one of the
+facility invocation parameters above. Send the backgrounded process a
+USR2 signal to terminate.
+.TP
+.B "\-L logfile"
+allows you to specify an alternate log file name. The default log file
+name is based on either the interface selected (detailed interface
+statistics, TCP/UDP service statistics, packet size breakdown), or the
+instance of the facility (IP traffic monitor, LAN station monitor). If a
+path is not specified, the log file is placed in
+.B /var/log/iptraf-ng
+.TP
+.B "\-f"
+clears all locks and counters, causing this instance of IPTraf-ng to think
+it's the first one running. This should only be used to recover from
+an abnormal termination or system crash.
+.TP
+.B "\-h"
+shows a command summary
+.SH SIGNALS
+
+ SIGUSR1 - rotates log files while program is running
+ SIGUSR2 - terminates an IPTraf-ng process running in the background.
+
+.SH FILES
+ /var/log/iptraf-ng/*.log - log file
+ /var/lib/iptraf-ng/* - important IPTraf-ng data files
+
+.SH SEE ALSO
+ Documentation/* - complete documentation written by the author
+
+.SH AUTHOR
+Gerard Paul Java (riker@mozcom.com)
+
+.SH MANUAL AUTHOR
+Frederic Peters (fpeters@debian.org), using iptraf-ng \-h
+General manual page modifications by Gerard Paul Java (riker@mozcom.com),
+Phil Cameron (pcameron@redhat.com)
+
diff --git a/src/iptraf.c b/src/iptraf.c
new file mode 100644
index 0000000..95f8e53
--- /dev/null
+++ b/src/iptraf.c
@@ -0,0 +1,549 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+/*
+IPTraf
+An IP Network Statistics Utility
+*/
+
+#include "iptraf-ng-compat.h"
+#include "built-in.h"
+
+#include "tui/menurt.h"
+#include "tui/winops.h"
+
+#include "dirs.h"
+#include "deskman.h"
+#include "fltdefs.h"
+#include "fltselect.h"
+#include "fltmgr.h"
+#include "fltedit.h"
+#include "serv.h"
+#include "options.h"
+#include "attrs.h"
+#include "rvnamed.h"
+#include "logvars.h"
+#include "detstats.h"
+#include "ifstats.h"
+#include "itrafmon.h"
+#include "pktsize.h"
+#include "hostmon.h"
+
+#include "parse-options.h"
+
+#define WITHALL 1
+#define WITHOUTALL 0
+
+#ifndef IPTRAF_PIDFILE
+#define IPTRAF_PIDFILE "/var/run/iptraf-ng.pid"
+#endif
+
+const char *ALLSPEC = "all";
+
+#define CMD(name, h) { .cmd = #name, .fn = cmd_##name, .help = h }
+#define CMD_END() { NULL, NULL, NULL }
+
+struct cmd_struct {
+ const char *cmd;
+ int (*fn)(int, char **);
+ const char *help;
+};
+
+/*
+ * Important globals used throughout the
+ * program.
+ */
+int exitloop = 0;
+int daemonized = 0;
+int facility_running = 0;
+
+static void press_enter_to_continue(void)
+{
+ fprintf(stderr, "Press Enter to continue.\n");
+ getchar();
+}
+
+static void clearfiles(char *prefix, char *directory)
+{
+ DIR *dir;
+ struct dirent *dir_entry;
+ char target_name[PATH_MAX];
+
+ dir = opendir(directory);
+
+ if (dir == NULL) {
+ fprintf(stderr, "\nUnable to read directory %s\n%s\n",
+ directory, strerror(errno));
+ press_enter_to_continue();
+ return;
+ }
+
+ do {
+ dir_entry = readdir(dir);
+ if (dir_entry != NULL) {
+ if (strncmp(dir_entry->d_name, prefix, strlen(prefix))
+ == 0) {
+ snprintf(target_name, sizeof(target_name) - 1,
+ "%s/%s", directory, dir_entry->d_name);
+ target_name[sizeof(target_name) - 1] = '\0';
+ unlink(target_name);
+ }
+ }
+ } while (dir_entry != NULL);
+
+ closedir(dir);
+}
+
+static void removetags(void)
+{
+ clearfiles("iptraf", LOCKDIR);
+}
+
+static void remove_sockets(void)
+{
+ clearfiles(SOCKET_PREFIX, WORKDIR);
+}
+
+/*
+ * USR2 handler. Used to normally exit a daemonized facility.
+ */
+
+static void term_usr2_handler(int s __unused)
+{
+ exitloop = 1;
+}
+
+static void init_break_menu(struct MENU *break_menu)
+{
+ tx_initmenu(break_menu, 6, 20, (LINES - 6) / 2, COLS / 2, BOXATTR,
+ STDATTR, HIGHATTR, BARSTDATTR, BARHIGHATTR, DESCATTR);
+ tx_additem(break_menu, " By packet ^s^ize",
+ "Displays packet counts by packet size range");
+ tx_additem(break_menu, " By TCP/UDP ^p^ort",
+ "Displays packet and byte counts by service port");
+ tx_additem(break_menu, NULL, NULL);
+ tx_additem(break_menu, " E^x^it menu", "Return to main menu");
+}
+
+/*
+ * Get the ball rolling: The program interface routine.
+ */
+
+static void program_interface(void)
+{
+ struct MENU menu;
+ struct MENU break_menu;
+
+ int endloop = 0;
+ int row = 1;
+ int break_row = 1;
+ int aborted;
+ int break_aborted;
+
+ char ifname[IFNAMSIZ];
+ char *ifptr = NULL;
+
+ /*
+ * Load saved filter
+ */
+ loadfilters();
+ indicate("");
+
+ tx_initmenu(&menu, 15, 35, (LINES - 16) / 2, (COLS - 35) / 2, BOXATTR,
+ STDATTR, HIGHATTR, BARSTDATTR, BARHIGHATTR, DESCATTR);
+
+ tx_additem(&menu, " IP traffic ^m^onitor",
+ "Displays current IP traffic information");
+ tx_additem(&menu, " General interface ^s^tatistics",
+ "Displays some statistics for attached interfaces");
+ tx_additem(&menu, " ^D^etailed interface statistics",
+ "Displays more statistics for a selected interface");
+ tx_additem(&menu, " Statistical ^b^reakdowns...",
+ "Facilities for traffic counts by packet size or TCP/UDP port");
+ tx_additem(&menu, " ^L^AN station monitor",
+ "Displays statistics on detected LAN stations");
+ tx_additem(&menu, NULL, NULL);
+ tx_additem(&menu, " ^F^ilters...",
+ "Allows you to select traffic display and logging criteria");
+ tx_additem(&menu, NULL, NULL);
+ tx_additem(&menu, " C^o^nfigure...", "Set various program options");
+ tx_additem(&menu, NULL, NULL);
+ tx_additem(&menu, " ^A^bout...", "Displays program info");
+ tx_additem(&menu, NULL, NULL);
+ tx_additem(&menu, " E^x^it", "Exits program");
+
+ endloop = 0;
+
+ do {
+ tx_showmenu(&menu);
+ tx_operatemenu(&menu, &row, &aborted);
+
+ switch (row) {
+ case 1:
+ selectiface(ifname, WITHALL, &aborted);
+ if (!aborted) {
+ if (strcmp(ifname, "") != 0)
+ ifptr = ifname;
+ else
+ ifptr = NULL;
+
+ ipmon(0, ifptr);
+ }
+ break;
+ case 2:
+ ifstats(0);
+ break;
+ case 3:
+ selectiface(ifname, WITHOUTALL, &aborted);
+ if (!aborted)
+ detstats(ifname, 0);
+ break;
+ case 4:
+ break_row = 1;
+ init_break_menu(&break_menu);
+ tx_showmenu(&break_menu);
+ tx_operatemenu(&break_menu, &break_row, &break_aborted);
+
+ switch (break_row) {
+ case 1:
+ selectiface(ifname, WITHOUTALL, &aborted);
+ if (!aborted)
+ packet_size_breakdown(ifname, 0);
+ break;
+ case 2:
+ selectiface(ifname, WITHOUTALL, &aborted);
+ if (!aborted)
+ servmon(ifname, 0);
+ break;
+ case 4:
+ break;
+ }
+ tx_destroymenu(&break_menu);
+ break;
+ case 5:
+ selectiface(ifname, WITHALL, &aborted);
+ if (!aborted) {
+ if (strcmp(ifname, "") != 0)
+ ifptr = ifname;
+ else
+ ifptr = NULL;
+ hostmon(0, ifptr);
+ }
+ break;
+ case 7:
+ config_filters();
+ savefilters();
+ break;
+ case 9:
+ setoptions();
+ saveoptions();
+ break;
+ case 11:
+ about();
+ break;
+ case 13:
+ endloop = 1;
+ break;
+ }
+ } while (!endloop);
+
+ tx_destroymenu(&menu);
+}
+
+static const char *const iptraf_ng_usage[] = {
+ IPTRAF_NAME " [options]",
+ IPTRAF_NAME " [options] -B [-i <iface> | -d <iface> | -s <iface> | -z <iface> | -l <iface> | -g]",
+ NULL
+};
+
+static int help_opt, f_opt, g_opt, facilitytime, B_opt;
+static char *i_opt, *d_opt, *s_opt, *z_opt, *l_opt, *L_opt;
+
+static struct options iptraf_ng_options[] = {
+ OPT__HELP(&help_opt),
+ OPT_GROUP(""),
+ OPT_STRING('i', NULL, &i_opt, "iface",
+ "start the IP traffic monitor (use '-i all' for all interfaces)"),
+ OPT_STRING('d', NULL, &d_opt, "iface",
+ "start the detailed statistics facility on an interface"),
+ OPT_STRING('s', NULL, &s_opt, "iface",
+ "start the TCP and UDP monitor on an interface"),
+ OPT_STRING('z', NULL, &z_opt, "iface",
+ "shows the packet size counts on an interface"),
+ OPT_STRING('l', NULL, &l_opt, "iface",
+ "start the LAN station monitor (use '-l all' for all LAN interfaces)"),
+ OPT_BOOL('g', NULL, &g_opt, "start the general interface statistics"),
+ OPT_GROUP(""),
+ OPT_BOOL('B', NULL, &B_opt,
+ "run in background (use only with one of the above parameters"),
+ OPT_BOOL('f', NULL, &f_opt,
+ "clear all locks and counters"
+ /*. Use with great caution. Normally used to recover from an abnormal termination */
+ ),
+ OPT_INTEGER('t', NULL, &facilitytime,
+ "run only for the specified <n> number of minutes"),
+ OPT_STRING('L', NULL, &L_opt, "logfile",
+ "specifies an alternate log file"),
+ // OPT_INTEGER('I', NULL, &I_opt, "the log interval for all facilities except the IP traffic monitor. Value is in minutes"),
+// PHIL From manual:
+// Sets the logging interval (in minutes) when the -L parameter is used. This over-
+// rides the Log interval... setting in the Configure... menu. If omitted, the configured
+// value is used. This parameter is ignored when the -L parameter is omitted and
+// logging is disabled.
+// The value specified here will affect all facilities except for the IP traffic monitor.
+ OPT_END()
+};
+
+static int create_pidfile(void)
+{
+ int fd = open(IPTRAF_PIDFILE, O_WRONLY|O_CREAT, 0644);
+ if (fd < 0) {
+ perror("can not open "IPTRAF_PIDFILE);
+ return -1;
+ }
+
+ if (lockf(fd, F_TLOCK, 0) < 0) {
+ error("The PID file is locked "IPTRAF_PIDFILE". "
+ "Maybe other iptraf-ng instance is running?can not acquire ");
+ return -1;
+ }
+
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+ char buf[sizeof(long) * 3 + 2];
+ int len = sprintf(buf, "%lu\n", (long) getpid());
+ write(fd, buf, len);
+ ftruncate(fd, len);
+ /* we leak opened+locked fd intentionally */
+ return 0;
+}
+
+static void sanitize_dir(const char *dir)
+{
+ /* Check whether LOCKDIR exists (/var/run is on a tmpfs in Ubuntu) */
+ if (access(dir, F_OK) != 0) {
+ if (mkdir(dir, 0700) == -1)
+ die("Cannot create %s: %s", dir, strerror(errno));
+
+ if (chown(dir, 0, 0) == -1)
+ die("Cannot change owner of %s: %s", dir,
+ strerror(errno));
+ }
+}
+
+static void handle_internal_command(int argc, char **argv,
+ const struct cmd_struct *commands)
+{
+ const char *cmd = argv[0];
+
+ for (const struct cmd_struct *p = commands; p->cmd; ++p)
+ {
+ if (!strcmp(p->cmd, cmd))
+ exit(p->fn(argc, argv));
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int current_log_interval = 0;
+
+ if (geteuid() != 0)
+ die("This program can be run only by the system administrator");
+
+ const struct cmd_struct commands[] = {
+ CMD(capture, "capture packet"),
+ CMD_END(),
+ };
+
+ /* stupid, but for now needed machinery with argc, args
+ *
+ */
+ char **internal_argv = argv;
+ argc--;
+ internal_argv++;
+
+ if (argc > 0)
+ handle_internal_command(argc, internal_argv, commands);
+
+ argc++;
+
+ /*
+ * Parse command line
+ */
+
+ parse_opts(argc, argv, iptraf_ng_options, iptraf_ng_usage);
+
+ if (help_opt)
+ parse_usage_and_die(iptraf_ng_usage, iptraf_ng_options);
+
+ int command = 0;
+
+ command |= (i_opt) ? (1 << 0) : 0;
+ command |= (d_opt) ? (1 << 1) : 0;
+ command |= (s_opt) ? (1 << 2) : 0;
+ command |= (z_opt) ? (1 << 3) : 0;
+ command |= (l_opt) ? (1 << 4) : 0;
+ command |= (g_opt) ? (1 << 5) : 0;
+
+ if (__builtin_popcount(command) > 1)
+ die("only one of -i|-d|-s|-z|-l|-g options must be used");
+
+ strcpy(current_logfile, "");
+
+ if (f_opt) {
+ removetags();
+ remove_sockets();
+ }
+
+ if (B_opt) {
+ if (!command)
+ die("one of -i|-d|-s|-z|-l|-g option is missing\n");
+ daemonized = 1;
+ setenv("TERM", "linux", 1);
+ }
+
+ if (L_opt) {
+ if (strchr(L_opt, '/') != NULL)
+ strncpy(current_logfile, L_opt, 80);
+ else
+ strncpy(current_logfile, get_path(T_LOGDIR, L_opt), 80);
+ }
+#if 0 /* this could never work */
+ /* origin
+ } else if (opt == 'I') {
+ //this could never work
+ current_log_interval = atoi(optarg);
+ if (current_log_interval == 0)
+ fprintf(stderr, "Invalid log interval value\n");
+
+ exit(1);
+ } else if (opt == 'G') {
+ */
+ if (I_opt == 0) {
+ fprintf(stderr, "fatal: Invalid log interval value\n");
+ exit(1);
+ } else
+ current_log_interval = I_opt;
+#endif
+
+ if ((getenv("TERM") == NULL) && (!daemonized))
+ die("Your TERM variable is not set.\n"
+ "Please set it to an appropriate value");
+
+ loadoptions();
+
+
+ if (create_pidfile() < 0)
+ goto bailout;
+
+ /*
+ * If a facility is directly invoked from the command line, check for
+ * a daemonization request
+ */
+
+ if (daemonized && command) {
+ switch (fork()) {
+ case 0: /* child */
+ setsid();
+ freopen("/dev/null", "w", stdout); /* redirect std output */
+ freopen("/dev/null", "r", stdin); /* redirect std input */
+ freopen("/dev/null", "w", stderr); /* redirect std error */
+ signal(SIGUSR2, term_usr2_handler);
+
+ options.logging = 1;
+ break;
+ case -1: /* error */
+ error("Fork error, %s cannot run in background", IPTRAF_NAME);
+ goto cleanup;
+ default: /* parent */
+ goto cleanup;
+ }
+ }
+
+ sanitize_dir(LOCKDIR);
+ sanitize_dir(WORKDIR);
+
+ setlocale(LC_ALL, ""); /* needed to properly init (n)curses library */
+ initscr();
+
+ if ((LINES < 24) || (COLS < 80)) {
+ endwin();
+ die("This program requires a screen size of at least 80 columns by 24 lines\n" "Please resize your window");
+ }
+
+ signal(SIGTSTP, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGUSR1, SIG_IGN);
+
+ start_color();
+ standardcolors(options.color);
+ noecho();
+ nonl();
+ cbreak();
+ curs_set(0);
+
+ /*
+ * Set logfilename variable to NULL if -L was specified without an
+ * appropriate facility on the command line.
+ */
+
+ if (command == 0)
+ strcpy(current_logfile, "");
+
+ /*
+ * If by this time the logfile is still acceptable, obtain the
+ * logspan from the command line if so specified.
+ */
+
+ if (current_logfile[0] != '\0') {
+ options.logging = 1;
+ if (current_log_interval != 0) {
+ options.logspan = current_log_interval;
+ }
+ }
+
+ /*
+ * Load saved filter
+ */
+ loadfilters();
+ indicate("");
+
+ /* bad, bad, bad name draw_desktop()
+ * hide all into tui_top_panel(char *msg)
+ * */
+ draw_desktop();
+ attrset(STATUSBARATTR);
+ mvprintw(0, 1, "%s %s", IPTRAF_NAME, IPTRAF_VERSION);
+
+ /* simplify */
+ if (g_opt)
+ ifstats(facilitytime);
+ else if (i_opt)
+ if (strcmp(i_opt, "all") == 0)
+ ipmon(facilitytime, NULL);
+ else
+ ipmon(facilitytime, i_opt);
+ else if (l_opt)
+ if (strcmp(l_opt, "all") == 0)
+ hostmon(facilitytime, NULL);
+ else
+ hostmon(facilitytime, l_opt);
+ else if (d_opt)
+ detstats(d_opt, facilitytime);
+ else if (s_opt)
+ servmon(s_opt, facilitytime);
+ else if (z_opt)
+ packet_size_breakdown(z_opt, facilitytime);
+ else
+ program_interface();
+
+ erase();
+ update_panels();
+ doupdate();
+ endwin();
+
+cleanup:
+ unlink(IPTRAF_PIDFILE);
+bailout:
+ return 0;
+}
diff --git a/src/itrafmon.c b/src/itrafmon.c
new file mode 100644
index 0000000..6255160
--- /dev/null
+++ b/src/itrafmon.c
@@ -0,0 +1,939 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+/***
+
+itrafmon.c - the IP traffic monitor module
+
+***/
+
+#include "iptraf-ng-compat.h"
+
+#include "tui/labels.h"
+#include "tui/winops.h"
+
+#include "options.h"
+#include "revname.h"
+#include "tcptable.h"
+#include "othptab.h"
+#include "fltdefs.h"
+#include "packet.h"
+#include "ifaces.h"
+#include "deskman.h"
+#include "error.h"
+#include "attrs.h"
+#include "log.h"
+#include "rvnamed.h"
+#include "dirs.h"
+#include "timer.h"
+#include "ipfrag.h"
+#include "logvars.h"
+#include "itrafmon.h"
+#include "sockaddr.h"
+#include "capt.h"
+
+#define SCROLLUP 0
+#define SCROLLDOWN 1
+
+static void rotate_ipmon_log(int s __unused)
+{
+ rotate_flag = 1;
+ strcpy(target_logname, current_logfile);
+ signal(SIGUSR1, rotate_ipmon_log);
+}
+
+/* Hot key indicators for the bottom line */
+
+static void ipmonhelp(void)
+{
+ move(LINES - 1, 1);
+ tx_printkeyhelp("Up/Dn/PgUp/PgDn", "-scroll ", stdscr, HIGHATTR,
+ STATUSBARATTR);
+ move(LINES - 1, 43);
+ tx_printkeyhelp("W", "-chg actv win ", stdscr, HIGHATTR,
+ STATUSBARATTR);
+ tx_printkeyhelp("S", "-sort TCP ", stdscr, HIGHATTR, STATUSBARATTR);
+ stdexitkeyhelp();
+}
+
+static void uniq_help(int what)
+{
+ move(LINES - 1, 25);
+ if (!what)
+ tx_printkeyhelp("M", "-more TCP info ", stdscr, HIGHATTR,
+ STATUSBARATTR);
+ else
+ tx_printkeyhelp("Lft/Rt", "-vtcl scrl ", stdscr, HIGHATTR,
+ STATUSBARATTR);
+}
+
+static void markactive(int curwin, WINDOW * tw, WINDOW * ow)
+{
+ WINDOW *win1;
+ WINDOW *win2;
+ int x1 __unused, y1, x2 __unused, y2;
+
+ if (!curwin) {
+ win1 = tw;
+ win2 = ow;
+ } else {
+ win1 = ow;
+ win2 = tw;
+ }
+
+ getmaxyx(win1, y1, x1);
+ getmaxyx(win2, y2, x2);
+
+ wmove(win1, --y1, COLS - 10);
+ wattrset(win1, ACTIVEATTR);
+ wprintw(win1, " Active ");
+ wattrset(win1, BOXATTR);
+ wmove(win2, --y2, COLS - 10);
+ whline(win2, ACS_HLINE, 8);
+}
+
+static void update_flowrates(struct tcptable *table, unsigned long msecs)
+{
+ struct tcptableent *entry;
+ for (entry = table->head; entry != NULL; entry = entry->next_entry) {
+ rate_add_rate(&entry->rate, entry->spanbr, msecs);
+ entry->spanbr = 0;
+ }
+}
+
+static void print_flowrate(struct tcptable *table)
+{
+ if (table->barptr == NULL) {
+ wattrset(table->statwin, IPSTATATTR);
+ mvwprintw(table->statwin, 0, COLS * 47 / 80,
+ "No TCP entries ");
+ } else {
+ wattrset(table->statwin, IPSTATLABELATTR);
+ mvwprintw(table->statwin, 0, COLS * 47 / 80,
+ "TCP flow rate: ");
+
+ char buf[32];
+ rate_print(rate_get_average(&table->barptr->rate), buf, sizeof(buf));
+ wattrset(table->statwin, IPSTATATTR);
+ mvwprintw(table->statwin, 0, COLS * 52 / 80 + 13, "%s", buf);
+ }
+}
+
+/*
+ * Scrolling and paging routines for the upper (TCP) window
+ */
+
+static void scrollupperwin(struct tcptable *table, int direction)
+{
+ wattrset(table->tcpscreen, STDATTR);
+ if (direction == SCROLLUP) {
+ if (table->lastvisible != table->tail) {
+ table->firstvisible = table->firstvisible->next_entry;
+ table->lastvisible = table->lastvisible->next_entry;
+
+ wscrl(table->tcpscreen, 1);
+ scrollok(table->tcpscreen, 0);
+ wmove(table->tcpscreen, table->imaxy - 1, 0);
+ wprintw(table->tcpscreen, "%*c", COLS - 2, ' ');
+ scrollok(table->tcpscreen, 1);
+
+ printentry(table, table->lastvisible);
+ }
+ } else {
+ if (table->firstvisible != table->head) {
+ table->firstvisible = table->firstvisible->prev_entry;
+ table->lastvisible = table->lastvisible->prev_entry;
+
+ wscrl(table->tcpscreen, -1);
+ mvwprintw(table->tcpscreen, 0, 0, "%*c", COLS - 2, ' ');
+
+ printentry(table, table->firstvisible);
+ }
+ }
+}
+
+static void move_tcp_bar_one(struct tcptable *table, int direction)
+{
+ switch (direction) {
+ case SCROLLUP:
+ if (table->barptr->next_entry == NULL)
+ break;
+
+ if (table->barptr == table->lastvisible)
+ scrollupperwin(table, SCROLLUP);
+
+ table->barptr = table->barptr->next_entry;
+
+ break;
+ case SCROLLDOWN:
+ if (table->barptr->prev_entry == NULL)
+ break;
+
+ if (table->barptr == table->firstvisible)
+ scrollupperwin(table, SCROLLDOWN);
+
+ table->barptr = table->barptr->prev_entry;
+
+ break;
+ }
+}
+
+static void move_tcp_bar_many(struct tcptable *table, int direction, int lines)
+{
+ switch (direction) {
+ case SCROLLUP:
+ while (lines && (table->lastvisible != table->tail)) {
+ table->firstvisible = table->firstvisible->next_entry;
+ table->lastvisible = table->lastvisible->next_entry;
+ lines--;
+ }
+ if (lines == 0)
+ table->barptr = table->firstvisible;
+ else
+ table->barptr = table->lastvisible;
+ break;
+ case SCROLLDOWN:
+ while (lines && (table->firstvisible != table->head)) {
+ table->firstvisible = table->firstvisible->prev_entry;
+ table->lastvisible = table->lastvisible->prev_entry;
+ lines--;
+ }
+ table->barptr = table->firstvisible;
+ break;
+ }
+}
+
+static void move_tcp_bar(struct tcptable *table, int direction, int lines)
+{
+ if (table->barptr == NULL)
+ return;
+ if (lines < 1)
+ return;
+ if (lines < 10)
+ while (lines--)
+ move_tcp_bar_one(table, direction);
+ else
+ move_tcp_bar_many(table, direction, lines);
+
+ print_flowrate(table);
+ refreshtcpwin(table, false);
+}
+
+/*
+ * Scrolling and paging routines for the lower (non-TCP) window.
+ */
+
+static void scroll_othp_one(struct othptable *table, int direction)
+{
+ switch (direction) {
+ case SCROLLUP:
+ if (table->lastvisible != table->tail) {
+ table->firstvisible = table->firstvisible->next_entry;
+ table->lastvisible = table->lastvisible->next_entry;
+
+ wscrl(table->othpwin, 1);
+ printothpentry(table, table->lastvisible,
+ table->oimaxy - 1, 0, NULL);
+
+ if (table->htstat == HIND) { /* Head indicator on? */
+ wmove(table->borderwin, table->obmaxy - 1, 1);
+ whline(table->borderwin, ACS_HLINE, 8);
+ table->htstat = NOHTIND;
+ }
+ }
+ break;
+ case SCROLLDOWN:
+ if (table->firstvisible != table->head) {
+ table->firstvisible = table->firstvisible->prev_entry;
+ table->lastvisible = table->lastvisible->prev_entry;
+
+ wscrl(table->othpwin, -1);
+ printothpentry(table, table->firstvisible, 0, 0, NULL);
+
+ if (table->htstat == TIND) { /* Tail indicator on? */
+ wmove(table->borderwin, table->obmaxy - 1, 1);
+ whline(table->borderwin, ACS_HLINE, 8);
+ table->htstat = NOHTIND;
+ }
+ }
+ break;
+ }
+}
+
+static void scroll_othp_many(struct othptable *table, int direction, int lines)
+{
+ switch (direction) {
+ case SCROLLUP:
+ while (lines-- && (table->lastvisible != table->tail)) {
+ table->firstvisible = table->firstvisible->next_entry;
+ table->lastvisible = table->lastvisible->next_entry;
+ }
+ if (table->htstat == HIND) { /* Head indicator on? */
+ wmove(table->borderwin, table->obmaxy - 1, 1);
+ whline(table->borderwin, ACS_HLINE, 8);
+ table->htstat = NOHTIND;
+ }
+ break;
+ case SCROLLDOWN:
+ while (lines-- && (table->firstvisible != table->head)) {
+ table->firstvisible = table->firstvisible->prev_entry;
+ table->lastvisible = table->lastvisible->prev_entry;
+ }
+ if (table->htstat == TIND) { /* Tail indicator on? */
+ wmove(table->borderwin, table->obmaxy - 1, 1);
+ whline(table->borderwin, ACS_HLINE, 8);
+ table->htstat = NOHTIND;
+ }
+ break;
+ }
+ refresh_othwindow(table);
+}
+
+static void scroll_othp(struct othptable *table, int direction, int lines)
+{
+ if (table->head == NULL)
+ return;
+ if (lines < 1)
+ return;
+ if (lines < getmaxy(table->othpwin))
+ while (lines--)
+ scroll_othp_one(table, direction);
+ else
+ scroll_othp_many(table, direction, lines);
+}
+
+/*
+ * Pop up sorting key window
+ */
+
+static void show_tcpsort_win(WINDOW ** win, PANEL ** panel)
+{
+ *win = newwin(9, 35, (LINES - 8) / 2, COLS - 40);
+ *panel = new_panel(*win);
+
+ wattrset(*win, DLGBOXATTR);
+ tx_colorwin(*win);
+ tx_box(*win, ACS_VLINE, ACS_HLINE);
+ wattrset(*win, DLGTEXTATTR);
+ mvwprintw(*win, 2, 2, "Select sort criterion");
+ wmove(*win, 4, 2);
+ tx_printkeyhelp("P", " - sort by packet count", *win, DLGHIGHATTR,
+ DLGTEXTATTR);
+ wmove(*win, 5, 2);
+ tx_printkeyhelp("B", " - sort by byte count", *win, DLGHIGHATTR,
+ DLGTEXTATTR);
+ wmove(*win, 6, 2);
+ tx_printkeyhelp("Any other key", " - cancel sort", *win, DLGHIGHATTR,
+ DLGTEXTATTR);
+ update_panels();
+ doupdate();
+}
+
+/*
+ * Routine to swap two TCP entries. p1 and p2 are pointers to TCP entries,
+ * but p1 must be ahead of p2. It's a linked list thing.
+ */
+static void swap_tcp_entries(struct tcptable *table, struct tcptableent *p1,
+ struct tcptableent *p2)
+{
+ struct tcptableent *p2nextsaved;
+ struct tcptableent *p1prevsaved;
+ unsigned int tmp;
+
+ if (p1 == p2)
+ return;
+
+ tmp = p1->index;
+ p1->index = p2->index;
+ p2->index = tmp;
+
+ p1->next_entry->index = p1->index + 1;
+ p2->next_entry->index = p2->index + 1;
+
+ if (p1->prev_entry != NULL)
+ p1->prev_entry->next_entry = p2;
+ else
+ table->head = p2;
+
+ if (p2->next_entry->next_entry != NULL)
+ p2->next_entry->next_entry->prev_entry = p1->next_entry;
+ else
+ table->tail = p1->next_entry;
+
+ p2nextsaved = p2->next_entry->next_entry;
+ p1prevsaved = p1->prev_entry;
+
+ if (p1->next_entry->next_entry == p2) { /* swapping adjacent entries */
+ p2->next_entry->next_entry = p1;
+ p1->prev_entry = p2->next_entry;
+ } else {
+ p2->next_entry->next_entry = p1->next_entry->next_entry;
+ p1->prev_entry = p2->prev_entry;
+ p2->prev_entry->next_entry = p1;
+ p1->next_entry->next_entry->prev_entry = p2->next_entry;
+ }
+
+ p2->prev_entry = p1prevsaved;
+ p1->next_entry->next_entry = p2nextsaved;
+}
+
+static unsigned long long qt_getkey(struct tcptableent *entry, int ch)
+{
+ if (ch == 'B')
+ return (max(entry->bcount, entry->oth_connection->bcount));
+
+ return (max(entry->pcount, entry->oth_connection->pcount));
+}
+
+static struct tcptableent *qt_partition(struct tcptable *table,
+ struct tcptableent **low,
+ struct tcptableent **high, int ch)
+{
+ struct tcptableent *pivot = *low;
+
+ struct tcptableent *left = *low;
+ struct tcptableent *right = *high;
+ struct tcptableent *ptmp;
+
+ unsigned long long pivot_value;
+
+ pivot_value = qt_getkey(pivot, ch);
+
+ while (left->index < right->index) {
+ while ((qt_getkey(left, ch) >= pivot_value)
+ && (left->next_entry->next_entry != NULL))
+
+ left = left->next_entry->next_entry;
+
+ while (qt_getkey(right, ch) < pivot_value)
+ right = right->prev_entry->prev_entry;
+
+ if (left->index < right->index) {
+ swap_tcp_entries(table, left, right);
+
+ if (*low == left)
+ *low = right;
+
+ if (*high == right)
+ *high = left;
+
+ ptmp = left;
+ left = right;
+ right = ptmp;
+ }
+ }
+ swap_tcp_entries(table, pivot, right);
+
+ if (*low == pivot)
+ *low = right;
+
+ if (*high == right)
+ *high = pivot;
+
+ return pivot;
+}
+
+/*
+ * Quicksort the TCP entries.
+ */
+static void quicksort_tcp_entries(struct tcptable *table,
+ struct tcptableent *low,
+ struct tcptableent *high, int ch)
+{
+ struct tcptableent *pivot;
+
+ if ((high == NULL) || (low == NULL))
+ return;
+
+ if (high->index > low->index) {
+ pivot =
+ qt_partition(table, &low, &high, ch);
+
+ if (pivot->prev_entry != NULL)
+ quicksort_tcp_entries(table, low,
+ pivot->prev_entry->prev_entry, ch);
+
+ quicksort_tcp_entries(table, pivot->next_entry->next_entry,
+ high, ch);
+ }
+}
+
+/*
+ * This function sorts the TCP window. The old exchange sort has been
+ * replaced with a Quicksort algorithm.
+ */
+
+static void sortipents(struct tcptable *table, int ch)
+{
+ if ((table->head == NULL)
+ || (table->head->next_entry->next_entry == NULL))
+ return;
+
+ ch = toupper(ch);
+
+ if ((ch != 'P') && (ch != 'B'))
+ return;
+
+ quicksort_tcp_entries(table, table->head, table->tail->prev_entry, ch);
+
+ table->firstvisible = table->head;
+ struct tcptableent *ptmp = table->head;
+
+ while (ptmp && ((int)ptmp->index <= getmaxy(table->tcpscreen))) {
+ table->lastvisible = ptmp;
+ ptmp = ptmp->next_entry;
+ }
+}
+
+static void ipmon_process_key(int ch, int *curwin, struct tcptable *table, struct othptable *othptbl)
+{
+ static int keymode = 0;
+ static WINDOW *sortwin;
+ static PANEL *sortpanel;
+
+ if (keymode == 0) {
+ switch (ch) {
+ case KEY_UP:
+ if (*curwin)
+ scroll_othp(othptbl, SCROLLDOWN, 1);
+ else
+ move_tcp_bar(table, SCROLLDOWN, 1);
+ break;
+ case KEY_DOWN:
+ if (*curwin)
+ scroll_othp(othptbl, SCROLLUP, 1);
+ else
+ move_tcp_bar(table, SCROLLUP, 1);
+ break;
+ case KEY_RIGHT:
+ if (!*curwin)
+ break;
+
+ if (othptbl->strindex != VSCRL_OFFSET)
+ othptbl->strindex = VSCRL_OFFSET;
+
+ refresh_othwindow(othptbl);
+ break;
+ case KEY_LEFT:
+ if (!*curwin)
+ break;
+
+ if (othptbl->strindex != 0)
+ othptbl->strindex = 0;
+
+ refresh_othwindow(othptbl);
+ break;
+ case KEY_PPAGE:
+ case '-':
+ if (*curwin)
+ scroll_othp(othptbl, SCROLLDOWN, othptbl->oimaxy);
+ else
+ move_tcp_bar(table, SCROLLDOWN, table->imaxy);
+ break;
+ case KEY_NPAGE:
+ case ' ':
+ if (*curwin)
+ scroll_othp(othptbl, SCROLLUP, othptbl->oimaxy);
+ else
+ move_tcp_bar(table, SCROLLUP, table->imaxy);
+ break;
+ case KEY_HOME:
+ if (*curwin)
+ scroll_othp(othptbl, SCROLLDOWN, INT_MAX);
+ else
+ move_tcp_bar(table, SCROLLDOWN, INT_MAX);
+ break;
+ case KEY_END:
+ if (*curwin)
+ scroll_othp(othptbl, SCROLLUP, INT_MAX);
+ else
+ move_tcp_bar(table, SCROLLUP, INT_MAX);
+ break;
+ case KEY_F(6):
+ case 'w':
+ case 'W':
+ case 9:
+ *curwin = !*curwin;
+ markactive(*curwin, table->borderwin,
+ othptbl->borderwin);
+ uniq_help(*curwin);
+ refreshtcpwin(table, false);
+ break;
+ case 'm':
+ case 'M':
+ if (*curwin)
+ break;
+ table->mode = (table->mode + 1) % 3;
+ if ((table->mode == 1) && !options.mac)
+ table->mode = 2;
+ refreshtcpwin(table, true);
+ break;
+ case 12:
+ case 'l':
+ case 'L':
+ tx_refresh_screen();
+ break;
+
+ case 'F':
+ case 'f':
+ case 'c':
+ case 'C':
+ flushclosedentries(table);
+ refreshtcpwin(table, true);
+ break;
+ case 's':
+ case 'S':
+ keymode = 1;
+ show_tcpsort_win(&sortwin, &sortpanel);
+ break;
+ case 'Q':
+ case 'q':
+ case 'X':
+ case 'x':
+ case 24:
+ case 27:
+ exitloop = 1;
+ break;
+ }
+ } else if (keymode == 1) {
+ keymode = 0;
+ del_panel(sortpanel);
+ delwin(sortwin);
+ flushclosedentries(table);
+ sortipents(table, ch);
+ if (table->barptr != NULL) {
+ table->barptr = table->firstvisible;
+ }
+ refreshtcpwin(table, true);
+ }
+}
+
+static void ipmon_process_packet(struct pkt_hdr *pkt, char *ifname,
+ struct tcptable *table,
+ struct othptable *othptbl,
+ int logging, FILE *logfile,
+ struct resolver *res)
+{
+ in_port_t sport = 0, dport = 0; /* TCP/UDP port values */
+ unsigned int br; /* bytes read. Differs from readlen */
+ char ifnamebuf[IFNAMSIZ];
+ struct tcptableent *tcpentry;
+
+ int pkt_result = packet_process(pkt, &br, &sport, &dport,
+ MATCH_OPPOSITE_ALWAYS,
+ options.v6inv4asv6);
+
+ if (pkt_result != PACKET_OK)
+ return;
+
+ if (!ifname) {
+ /* we're capturing on "All interfaces", */
+ /* so get the name of the interface */
+ /* of this packet */
+ int r = dev_get_ifname(pkt->from->sll_ifindex, ifnamebuf);
+ if (r != 0) {
+ write_error("Unable to get interface name");
+ return; /* error getting interface name, get out! */
+ }
+ ifname = ifnamebuf;
+ }
+
+ struct sockaddr_storage saddr, daddr;
+ switch(pkt->pkt_protocol) {
+ case ETH_P_IP:
+ sockaddr_make_ipv4(&saddr, pkt->iphdr->saddr);
+ sockaddr_make_ipv4(&daddr, pkt->iphdr->daddr);
+ break;
+ case ETH_P_IPV6:
+ sockaddr_make_ipv6(&saddr, &pkt->ip6_hdr->ip6_src);
+ sockaddr_make_ipv6(&daddr, &pkt->ip6_hdr->ip6_dst);
+ break;
+ default:
+ add_othp_entry(othptbl, pkt, NULL, NULL,
+ NOT_IP,
+ pkt->pkt_protocol,
+ pkt->pkt_payload, ifname, NULL,
+ logging, logfile);
+ return;
+ }
+
+ /* only when packets fragmented */
+ char *ip_payload = pkt->pkt_payload + pkt_iph_len(pkt);
+ switch (pkt_ip_protocol(pkt)) {
+ case IPPROTO_TCP: {
+ struct tcphdr *tcp = (struct tcphdr *)ip_payload;
+ sockaddr_set_port(&saddr, sport);
+ sockaddr_set_port(&daddr, dport);
+ tcpentry = in_table(table, &saddr, &daddr, ifname);
+
+ /*
+ * Add a new entry if it doesn't exist, and,
+ * to reduce the chances of stales, not a FIN.
+ */
+
+ if (packet_is_first_fragment(pkt) /* first frag only */
+ && (tcpentry == NULL)
+ && !tcp->fin) {
+
+ /*
+ * Ok, so we have a packet. Add it if this connection
+ * is not yet closed, or if it is a SYN packet.
+ */
+ tcpentry = addentry(table, &saddr, &daddr,
+ pkt_ip_protocol(pkt),
+ ifname, res);
+ }
+ /*
+ * If we had an addentry() success, we should have no
+ * problem here. Same thing if we had a table lookup
+ * success.
+ */
+
+ if ((tcpentry != NULL)
+ && !(tcpentry->stat & FLAG_RST)) {
+
+ /*
+ * Don't bother updating the entry if the connection
+ * has been previously reset. (Does this really
+ * happen in practice?)
+ */
+
+ if (pkt->iphdr)
+ updateentry(table, pkt, tcpentry, tcp,
+ br,
+ res,
+ logging, logfile);
+ else
+ updateentry(table, pkt, tcpentry, tcp,
+ pkt->pkt_len,
+ res,
+ logging, logfile);
+ /*
+ * Log first packet of a TCP connection except if
+ * it's a RST, which was already logged earlier in
+ * updateentry()
+ */
+
+ if (logging
+ && (tcpentry->pcount == 1)
+ && (!(tcpentry->stat & FLAG_RST))) {
+ char msgstring[80];
+ strcpy(msgstring, "first packet");
+ if (tcp->syn)
+ strcat(msgstring, " (SYN)");
+
+ writetcplog(logging, logfile, tcpentry,
+ pkt->pkt_len, msgstring);
+ }
+ }
+ break; }
+ case IPPROTO_ICMP:
+ case IPPROTO_ICMPV6:
+ check_icmp_dest_unreachable(table, pkt, ifname);
+ /* print this ICMP(v6) and ... */
+ /* fall through */
+ default:
+ add_othp_entry(othptbl, pkt, &saddr, &daddr,
+ IS_IP, pkt_ip_protocol(pkt),
+ ip_payload, ifname,
+ res, logging, logfile);
+ break;
+ }
+}
+
+/* the IP Traffic Monitor */
+void ipmon(time_t facilitytime, char *ifptr)
+{
+ int logging = options.logging;
+
+ FILE *logfile = NULL;
+
+ int curwin = 0;
+
+ unsigned long long total_pkts = 0;
+
+ struct tcptable table;
+
+ struct othptable othptbl;
+
+ struct capt capt;
+
+ struct pkt_hdr pkt;
+
+ struct resolver res;
+
+ int ch;
+
+ if (ifptr && !dev_up(ifptr)) {
+ err_iface_down();
+ return;
+ }
+
+ if (capt_init(&capt, ifptr) == -1) {
+ write_error("Unable to initialize packet capture interface");
+ return;
+ }
+
+ resolver_init(&res, options.revlook);
+
+ if (options.servnames)
+ setservent(1);
+ setprotoent(1);
+
+ /*
+ * Try to open log file if logging activated. Turn off logging
+ * (for this session only) if an error was discovered in opening
+ * the log file. Configuration setting is kept. Who knows, the
+ * situation may be corrected later.
+ */
+
+ if (logging) {
+ if (strcmp(current_logfile, "") == 0) {
+ strncpy(current_logfile,
+ gen_instance_logname(IPMONLOG, getpid()),
+ 80);
+
+ if (!daemonized)
+ input_logfile(current_logfile, &logging);
+ }
+ }
+
+ if (logging) {
+ opentlog(&logfile, current_logfile);
+
+ if (logfile == NULL)
+ logging = 0;
+ }
+ if (logging) {
+ signal(SIGUSR1, rotate_ipmon_log);
+
+ rotate_flag = 0;
+ writelog(logging, logfile,
+ "******** IP traffic monitor started ********");
+ }
+
+ init_tcp_table(&table);
+ init_othp_table(&othptbl);
+
+ markactive(curwin, table.borderwin, othptbl.borderwin);
+ ipmonhelp();
+ uniq_help(0);
+ update_panels();
+ doupdate();
+
+ packet_init(&pkt);
+
+ exitloop = 0;
+
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ struct timespec last_time = now;
+ struct timespec next_screen_update = { 0 };
+ time_t starttime = now.tv_sec;
+
+ time_t check_closed;
+ if (options.closedint != 0)
+ check_closed = now.tv_sec + options.closedint * 60;
+ else
+ check_closed = INT_MAX;
+
+ /* set the time after which we terminate the process */
+ time_t endtime;
+ if (facilitytime != 0)
+ endtime = now.tv_sec + facilitytime * 60;
+ else
+ endtime = INT_MAX;
+
+ while (!exitloop) {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ if (now.tv_sec > last_time.tv_sec) {
+ unsigned long msecs = timespec_diff_msec(&now, &last_time);
+ /* update all flowrates ... */
+ update_flowrates(&table, msecs);
+ /* ... and print the current one every second */
+ print_flowrate(&table);
+
+ resolve_visible_entries(&table, &res);
+
+ /* print timer at bottom of screen */
+ printelapsedtime(now.tv_sec - starttime, 15, othptbl.borderwin);
+
+ print_packet_drops(capt_get_dropped(&capt), othptbl.borderwin, 40);
+
+ mark_timeouted_entries(&table, logging, logfile);
+
+ /* automatically clear closed/timed out entries */
+ if (now.tv_sec > check_closed) {
+ flushclosedentries(&table);
+ refreshtcpwin(&table, true);
+ check_closed = now.tv_sec + options.closedint * 60;
+ }
+
+ /* terminate after lifetime specified at the cmdline */
+ if (now.tv_sec > endtime)
+ exitloop = 1;
+
+ /* close and rotate log file if signal was received */
+ if (logging && (rotate_flag == 1)) {
+ announce_rotate_prepare(logfile);
+ write_tcp_unclosed(logging, logfile, &table);
+ rotate_logfile(&logfile, target_logname);
+ announce_rotate_complete(logfile);
+ rotate_flag = 0;
+ }
+
+ last_time = now;
+ }
+
+ /* update screen at configured intervals. */
+ if (time_after(&now, &next_screen_update)) {
+ refreshtcpwin(&table, false);
+ show_stats(table.statwin, total_pkts);
+
+ update_panels();
+ doupdate();
+
+ set_next_screen_update(&next_screen_update, &now);
+ }
+
+ if (capt_get_packet(&capt, &pkt, &ch, table.tcpscreen) == -1) {
+ write_error("Packet receive failed");
+ exitloop = 1;
+ break;
+ }
+
+ if (ch != ERR)
+ ipmon_process_key(ch, &curwin, &table, &othptbl);
+
+ if (pkt.pkt_len > 0) {
+ total_pkts++;
+ ipmon_process_packet(&pkt, ifptr, &table, &othptbl,
+ logging, logfile,
+ &res);
+ capt_put_packet(&capt, &pkt);
+ }
+ }
+ packet_destroy(&pkt);
+
+ destroyothptable(&othptbl);
+ destroytcptable(&table);
+ update_panels();
+ doupdate();
+
+ if (logging) {
+ signal(SIGUSR1, SIG_DFL);
+ writelog(logging, logfile,
+ "******** IP traffic monitor stopped ********\n");
+ fclose(logfile);
+ strcpy(current_logfile, "");
+ }
+
+ endprotoent();
+ if (options.servnames)
+ endservent();
+
+ resolver_destroy(&res);
+
+ capt_destroy(&capt);
+}
diff --git a/src/itrafmon.h b/src/itrafmon.h
new file mode 100644
index 0000000..2a62431
--- /dev/null
+++ b/src/itrafmon.h
@@ -0,0 +1,6 @@
+#ifndef IPTRAF_NG_ITRAFMON_H
+#define IPTRAF_NG_ITRAFMON_H
+
+void ipmon(time_t facilitytime, char *ifptr);
+
+#endif /* IPTRAF_NG_ITRAFMON_H */
diff --git a/src/landesc.c b/src/landesc.c
new file mode 100644
index 0000000..d51c094
--- /dev/null
+++ b/src/landesc.c
@@ -0,0 +1,365 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+/***
+
+landesc.c - LAN host description management module
+ Currently includes support for Ethernet, PLIP,
+ and FDDI
+
+***/
+
+#include "iptraf-ng-compat.h"
+
+#include "tui/input.h"
+#include "tui/listbox.h"
+#include "tui/msgboxes.h"
+#include "tui/menurt.h"
+
+#include "landesc.h"
+#include "deskman.h"
+#include "attrs.h"
+#include "dirs.h"
+
+static int check_mac_addr(const char *mac)
+{
+ if (strlen(mac) != 17)
+ return 0;
+
+ char a[3], b[3], c[3], d[3], e[3], f[3];
+
+ int success = sscanf(mac, "%02s:%02s:%02s:%02s:%02s:%02s",
+ a, b, c, d, e, f);
+
+ if (success != 6)
+ return 0;
+
+ char mac_hex[13];
+
+ sprintf(mac_hex, "%s%s%s%s%s%s", a, b, c, d, e, f);
+
+ for (int ii = 0; ii < 12; ++ii)
+ if (!isxdigit(mac_hex[ii]))
+ return 0;
+
+ return 1;
+}
+
+/* parse and insert unique eth description.
+ * caller is responsible for freeing whole list
+ */
+static void parse_eth_desc(FILE * fp, struct eth_desc *hd)
+{
+ char *l = NULL;
+ size_t len = 0;
+ ssize_t read;
+
+ while ((read = getline(&l, &len, fp)) != -1) {
+ if (l[0] == '\n' || l[0] == '#')
+ continue;
+
+ char *line = l;
+
+ if (strchr(line, '\n'))
+ strchr(line, '\n')[0] = '\0';
+ char mac[18] = { 0 };
+ strncpy(mac, line, 17);
+
+ if (!check_mac_addr(mac)) {
+ tui_error(ANYKEY_MSG, "Not a mac '%s' address, skipped",
+ mac);
+ continue;
+ }
+
+ /* skip mac address */
+ line += 17;
+
+ /* mandatory space between mac and ip */
+ if (!isspace(*line)) {
+ tui_error(ANYKEY_MSG,
+ "Missing mandatory space between"
+ "mac and host/ip address, skipped");
+ continue;
+ }
+
+ line = skip_whitespace(line);
+
+ if (!*line) {
+ tui_error(ANYKEY_MSG, "Missing description, skipped");
+ continue;
+ }
+
+ struct eth_desc *new = xmalloc(sizeof(struct eth_desc));
+
+ memcpy(new->hd_mac, mac, sizeof(mac));
+ new->hd_desc = xstrdup(line);
+
+ struct eth_desc *desc = NULL;
+
+ list_for_each_entry(desc, &hd->hd_list, hd_list)
+ if ((strcmp(desc->hd_mac, mac) == 0)
+ || (strcmp(desc->hd_desc, line) == 0))
+ goto dupe;
+
+ list_add_tail(&new->hd_list, &hd->hd_list);
+ dupe:;
+ }
+
+ free(l);
+}
+
+struct eth_desc *load_eth_desc(unsigned link_type)
+{
+/* why is usefull to have it two files with same content?
+ * There is two options how to merge it.
+ * 1) separate by comments
+ * $ cat ETHFILE
+ * # ethernet host description
+ * MAC ip/hostname
+ *
+ * # fddi host description
+ * MAC ip/hostname
+ * 2) put it into groups
+ * [ethernet]
+ * MAC ip/hostname
+ *
+ * [fddi]
+ * MAC ip/hostname
+ */
+ char *filename = NULL;
+ FILE *fp = NULL;
+
+ if (link_type == ARPHRD_ETHER)
+ filename = ETHFILE;
+ else if (link_type == ARPHRD_FDDI)
+ filename = FDDIFILE;
+
+ struct eth_desc *hd = xmallocz(sizeof(struct eth_desc));
+
+ INIT_LIST_HEAD(&hd->hd_list);
+
+ fp = fopen(filename, "r");
+ if (fp) {
+ parse_eth_desc(fp, hd);
+ fclose(fp);
+ }
+
+ /* merge with /etc/ethers */
+ fp = fopen("/etc/ethers", "r");
+ if (fp) {
+ parse_eth_desc(fp, hd);
+ fclose(fp);
+ }
+
+ return hd;
+}
+
+static void save_eth_desc(struct eth_desc *hd, unsigned linktype)
+{
+ FILE *fd = NULL;
+
+ if (linktype == ARPHRD_ETHER)
+ fd = fopen(ETHFILE, "w");
+ else if (linktype == ARPHRD_FDDI)
+ fd = fopen(FDDIFILE, "w");
+
+ if (!fd) {
+ tui_error(ANYKEY_MSG, "Unable to save host description file");
+ return;
+ }
+
+ fprintf(fd, "# see man ethers for syntax\n\n");
+ struct eth_desc *desc = NULL;
+
+ list_for_each_entry(desc, &hd->hd_list, hd_list)
+ fprintf(fd, "%s %s\n", desc->hd_mac, desc->hd_desc);
+
+ fclose(fd);
+}
+
+
+void free_eth_desc(struct eth_desc *hd)
+{
+ struct eth_desc *entry = NULL;
+ struct list_head *l, *n;
+
+ list_for_each_safe(l, n, &hd->hd_list) {
+ entry = list_entry(l, struct eth_desc, hd_list);
+
+ free(entry->hd_desc);
+ list_del(l);
+ free(entry);
+ }
+}
+
+static struct eth_desc *select_eth_desc(const struct eth_desc *hd)
+{
+
+ struct scroll_list slist;
+ char descline[80];
+
+ if (list_empty(&hd->hd_list)) {
+ tui_error(ANYKEY_MSG, "No descriptions");
+ return NULL;
+ }
+
+ tx_init_listbox(&slist, COLS, 20, 0, (LINES - 20) / 2, STDATTR, BOXATTR,
+ BARSTDATTR, HIGHATTR);
+
+ tx_set_listbox_title(&slist, "Address", 1);
+ tx_set_listbox_title(&slist, "Description", 19);
+
+ struct eth_desc *entry = NULL;
+
+ list_for_each_entry(entry, &hd->hd_list, hd_list) {
+ snprintf(descline, 80, "%-18s%s", entry->hd_mac,
+ entry->hd_desc);
+ tx_add_list_entry(&slist, (char *) entry, descline);
+ }
+
+ tx_show_listbox(&slist);
+
+ int aborted = 0;
+
+ tx_operate_listbox(&slist, &aborted);
+
+ if (!aborted)
+ entry = (struct eth_desc *) slist.textptr->nodeptr;
+ else
+ entry = NULL;
+
+ tx_close_listbox(&slist);
+ tx_destroy_list(&slist);
+
+ update_panels();
+ doupdate();
+
+ return entry;
+}
+
+static int dialog_eth_desc(struct FIELDLIST *fields, const char *initaddr,
+ const char *initdesc)
+{
+ /* TODO: move to tui */
+ WINDOW *win = newwin(8, 70, 8, (COLS - 70) / 2);
+ PANEL *panel = new_panel(win);
+
+ wattrset(win, DLGBOXATTR);
+ tx_colorwin(win);
+ tx_box(win, ACS_VLINE, ACS_HLINE);
+ wmove(win, 6, 2 * COLS / 80);
+ tabkeyhelp(win);
+ wmove(win, 6, 20 * COLS / 80);
+ stdkeyhelp(win);
+
+ wattrset(win, DLGTEXTATTR);
+ mvwprintw(win, 2, 2 * COLS / 80, "MAC Address:");
+ mvwprintw(win, 4, 2 * COLS / 80, "Description:");
+
+ tx_initfields(fields, 3, 52, 10, (COLS - 52) / 2 + 6 * COLS / 80,
+ DLGTEXTATTR, FIELDATTR);
+ tx_addfield(fields, 17, 0, 0, initaddr);
+ tx_addfield(fields, 50, 2, 0, initdesc);
+
+ int aborted = 0;
+
+ tx_fillfields(fields, &aborted);
+
+ del_panel(panel);
+ delwin(win);
+
+ return aborted;
+}
+
+static void add_eth_desc(struct eth_desc *list)
+{
+ struct FIELDLIST fields;
+
+ int aborted = dialog_eth_desc(&fields, "", "");
+
+ if (!aborted) {
+ struct eth_desc *new = xmalloc(sizeof(struct eth_desc));
+
+ memcpy(new->hd_mac, fields.list->buf, sizeof(new->hd_mac));
+ new->hd_desc = xstrdup(fields.list->nextfield->buf);
+
+ list_add_tail(&new->hd_list, &list->hd_list);
+ }
+
+ tx_destroyfields(&fields);
+ update_panels();
+ doupdate();
+}
+
+static void edit_eth_desc(struct eth_desc *list)
+{
+ struct eth_desc *hd = select_eth_desc(list);
+
+ if (!hd)
+ return;
+
+ struct FIELDLIST fields;
+ int aborted = dialog_eth_desc(&fields, hd->hd_mac, hd->hd_desc);
+
+ if (!aborted) {
+ free(hd->hd_desc);
+ memcpy(hd->hd_mac, fields.list->buf, sizeof(hd->hd_mac));
+ hd->hd_desc = xstrdup(fields.list->nextfield->buf);
+ }
+
+ tx_destroyfields(&fields);
+}
+
+static void del_eth_desc(struct eth_desc *list)
+{
+ struct eth_desc *hd = select_eth_desc(list);
+
+ if (hd) {
+ free(hd->hd_desc);
+ list_del(&hd->hd_list);
+ free(hd);
+ }
+}
+
+void manage_eth_desc(unsigned linktype)
+{
+ struct MENU menu;
+ int row = 1;
+ int aborted = 0;
+
+ tx_initmenu(&menu, 7, 31, (LINES - 6) / 2, (COLS - 31) / 2, BOXATTR,
+ STDATTR, HIGHATTR, BARSTDATTR, BARHIGHATTR, DESCATTR);
+ tx_additem(&menu, " ^A^dd description...",
+ "Adds a description for a MAC address");
+ tx_additem(&menu, " ^E^dit description...",
+ "Modifies an existing MAC address description");
+ tx_additem(&menu, " ^D^elete description...",
+ "Deletes an existing MAC address description");
+ tx_additem(&menu, NULL, NULL);
+ tx_additem(&menu, " E^x^it menu", "Returns to the main menu");
+
+ struct eth_desc *list =
+ load_eth_desc(linktype /*, WITHOUTETCETHERS */ );
+
+ do {
+ tx_showmenu(&menu);
+ tx_operatemenu(&menu, &row, &aborted);
+
+ switch (row) {
+ case 1:
+ add_eth_desc(list);
+ break;
+ case 2:
+ edit_eth_desc(list);
+ break;
+ case 3:
+ del_eth_desc(list);
+ break;
+ }
+ } while (row != 5);
+
+ tx_destroymenu(&menu);
+ update_panels();
+ doupdate();
+ save_eth_desc(list, linktype);
+}
diff --git a/src/landesc.h b/src/landesc.h
new file mode 100644
index 0000000..078c428
--- /dev/null
+++ b/src/landesc.h
@@ -0,0 +1,27 @@
+#ifndef IPTRAF_NG_LANDESC_H
+#define IPTRAF_NG_LANDESC_H
+
+/***
+
+ethdesc.c - Ethernet host description management module
+
+***/
+
+#include "list.h"
+
+#define WITHETCETHERS 1
+#define WITHOUTETCETHERS 0
+
+struct eth_desc {
+ struct list_head hd_list;
+ char hd_mac[18];
+ char *hd_desc;
+};
+
+struct eth_desc *load_eth_desc(unsigned link_type);
+
+void free_eth_desc(struct eth_desc *hd);
+
+void manage_eth_desc(unsigned int linktype);
+
+#endif /* IPTRAF_NG_LANDESC_H */
diff --git a/src/list.h b/src/list.h
new file mode 100644
index 0000000..a7b495e
--- /dev/null
+++ b/src/list.h
@@ -0,0 +1,89 @@
+#ifndef IPTRAF_NG_LIST_H
+#define IPTRAF_NG_LIST_H
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+ list->next = list;
+ list->prev = list;
+}
+
+static inline void __list_add(struct list_head *new, struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+static inline void list_add_tail_unique(struct list_head *new,
+ struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+static inline void __list_del(struct list_head *prev, struct list_head *next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = NULL;
+ entry->prev = NULL;
+}
+
+static inline int list_is_last(const struct list_head *list,
+ const struct list_head *head)
+{
+ return list->next == head;
+}
+
+static inline int list_empty(const struct list_head *head)
+{
+ return head->next == head;
+}
+
+#define list_entry(ptr, type, member) \
+ ((type *)( (char *)(ptr) - offsetof(type, member) ))
+
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+#endif /* IPTRAF_NG_LIST_H */
diff --git a/src/log.c b/src/log.c
new file mode 100644
index 0000000..e956853
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,156 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+/***
+
+log.c - the iptraf logging facility
+
+***/
+
+#include "iptraf-ng-compat.h"
+
+#include "attrs.h"
+#include "deskman.h"
+#include "dirs.h"
+#include "log.h"
+
+#include "tui/input.h"
+#include "tui/msgboxes.h"
+#include "tui/winops.h"
+
+#define TARGET_LOGNAME_MAX 160
+
+int rotate_flag;
+char target_logname[TARGET_LOGNAME_MAX];
+char current_logfile[TARGET_LOGNAME_MAX];
+
+/*
+ * Generates a log file based on a template for a particular instance of
+ * a facility. Used by the IP Traffic Monitor and LAN Station Monitor.
+ */
+
+char *gen_instance_logname(char *template, int instance_num)
+{
+ static char filename[80];
+
+ snprintf(filename, 80, "%s-%d.log", template, instance_num);
+ return filename;
+}
+
+void input_logfile(char *target, int *logging)
+{
+ WINDOW *dlgwin;
+ PANEL *dlgpanel;
+ struct FIELDLIST fieldlist;
+ int aborted;
+
+ dlgwin = newwin(11, 60, (LINES - 11) / 2, (COLS - 60) / 2);
+ dlgpanel = new_panel(dlgwin);
+
+ wattrset(dlgwin, DLGBOXATTR);
+ tx_colorwin(dlgwin);
+ tx_box(dlgwin, ACS_VLINE, ACS_HLINE);
+ mvwprintw(dlgwin, 0, 1, " Logging Enabled ");
+ wattrset(dlgwin, DLGTEXTATTR);
+ mvwprintw(dlgwin, 2, 2,
+ "Enter the name of the file to which to write the log.");
+ mvwprintw(dlgwin, 4, 2,
+ "If you don't specify a path, the log file will");
+ mvwprintw(dlgwin, 5, 2, "be placed in %s.", LOGDIR);
+ wmove(dlgwin, 9, 2);
+ stdkeyhelp(dlgwin);
+ wprintw(dlgwin, " (turns logging off)");
+
+ tx_initfields(&fieldlist, 1, 50, (LINES - 1) / 2 + 2,
+ (COLS - 50) / 2 - 3, DLGTEXTATTR, FIELDATTR);
+ tx_addfield(&fieldlist, 48, 0, 0, target);
+ tx_fillfields(&fieldlist, &aborted);
+
+ if (!aborted) {
+ if (strchr(fieldlist.list->buf, '/') == NULL)
+ snprintf(target, 48, "%s/%s", LOGDIR,
+ fieldlist.list->buf);
+ else
+ strncpy(target, fieldlist.list->buf, 48);
+ }
+
+ *logging = !aborted;
+
+ tx_destroyfields(&fieldlist);
+ del_panel(dlgpanel);
+ delwin(dlgwin);
+ update_panels();
+ doupdate();
+}
+
+void opentlog(FILE ** fd, char *logfilename)
+{
+ *fd = fopen(logfilename, "a");
+
+ if (*fd == NULL)
+ tui_error(ANYKEY_MSG, "Unable to open log file");
+
+ rotate_flag = 0;
+ strcpy(target_logname, "");
+}
+
+void genatime(time_t now, char *atime)
+{
+ memset(atime, 0, TIME_TARGET_MAX);
+ strncpy(atime, ctime(&now), 26);
+ atime[strlen(atime) - 1] = '\0';
+}
+
+void writelog(int logging, FILE * fd, char *msg)
+{
+ char atime[TIME_TARGET_MAX];
+
+ if (logging) {
+ genatime(time(NULL), atime);
+ fprintf(fd, "%s; %s\n", atime, msg);
+ }
+
+ fflush(fd);
+}
+
+void write_daemon_err(char *msg, va_list vararg)
+{
+ char atime[TIME_TARGET_MAX];
+ FILE *fd;
+
+ genatime(time(NULL), atime);
+ fd = fopen(DAEMONLOG, "a");
+ fprintf(fd, "%s iptraf[%u]: ", atime, getpid());
+ vfprintf(fd, msg, vararg);
+ fprintf(fd, "\n");
+ fclose(fd);
+}
+
+void rotate_logfile(FILE ** fd, char *name)
+{
+ fclose(*fd);
+ *fd = fopen(name, "a");
+ rotate_flag = 0;
+}
+
+
+void announce_rotate_prepare(FILE * fd)
+{
+ writelog(1, fd,
+ "***** USR1 signal received, preparing to reopen log file *****");
+}
+
+void announce_rotate_complete(FILE * fd)
+{
+ writelog(1, fd, "***** Logfile reopened *****");
+}
+
+void check_rotate_flag(FILE ** logfile)
+{
+ if (rotate_flag == 1) {
+ announce_rotate_prepare(*logfile);
+ rotate_logfile(logfile, target_logname);
+ announce_rotate_complete(*logfile);
+ rotate_flag = 0;
+ }
+}
diff --git a/src/log.h b/src/log.h
new file mode 100644
index 0000000..aa786f7
--- /dev/null
+++ b/src/log.h
@@ -0,0 +1,23 @@
+#ifndef IPTRAF_NG_LOG_H
+#define IPTRAF_NG_LOG_H
+
+/***
+
+log.h - the iptraf logging facility header file
+
+***/
+
+#define TIME_TARGET_MAX 30
+
+char *gen_instance_logname(char *template, int instance_id);
+void input_logfile(char *target, int *aborted);
+void opentlog(FILE ** fd, char *logfilename);
+void writelog(int logging, FILE * fd, char *msg);
+void genatime(time_t now, char *atime);
+void write_daemon_err(char *msg, va_list vararg);
+void rotate_logfile(FILE ** fd, char *name);
+void check_rotate_flag(FILE ** fd);
+void announce_rotate_prepare(FILE * fd);
+void announce_rotate_complete(FILE * fd);
+
+#endif /* IPTRAF_NG_LOG_H */
diff --git a/src/logvars.h b/src/logvars.h
new file mode 100644
index 0000000..83e86df
--- /dev/null
+++ b/src/logvars.h
@@ -0,0 +1,8 @@
+#ifndef IPTRAF_NG_LOGVARS_H
+#define IPTRAF_NG_LOGVARS_H
+
+extern int rotate_flag;
+extern char target_logname[160];
+extern char current_logfile[160];
+
+#endif /* IPTRAF_NG_LOGVARS_H */
diff --git a/src/options.c b/src/options.c
new file mode 100644
index 0000000..3d7985e
--- /dev/null
+++ b/src/options.c
@@ -0,0 +1,387 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+/***
+
+options.c - implements the configuration section of the utility
+
+***/
+
+#include "iptraf-ng-compat.h"
+
+#include "tui/input.h"
+#include "tui/menurt.h"
+#include "tui/msgboxes.h"
+#include "tui/winops.h"
+
+#include "serv.h"
+#include "options.h"
+#include "deskman.h"
+#include "attrs.h"
+#include "landesc.h"
+#include "dirs.h"
+
+#define ALLOW_ZERO 1
+#define DONT_ALLOW_ZERO 0
+
+struct OPTIONS options;
+
+static void makeoptionmenu(struct MENU *menu)
+{
+ tx_initmenu(menu, 20, 40, (LINES - 19) / 2 - 1, (COLS - 40) / 16,
+ BOXATTR, STDATTR, HIGHATTR, BARSTDATTR, BARHIGHATTR,
+ DESCATTR);
+ tx_additem(menu, " ^R^everse DNS lookups",
+ "Toggles resolution of IP addresses into host names");
+ tx_additem(menu, " TCP/UDP ^s^ervice names",
+ "Displays TCP/UDP service names instead of numeric ports");
+ tx_additem(menu, " Force ^p^romiscuous mode",
+ "Toggles capture of all packets by LAN interfaces");
+ tx_additem(menu, " ^C^olor",
+ "Turns color on or off (restart IPTraf to effect change)");
+ tx_additem(menu, " ^L^ogging",
+ "Toggles logging of traffic to a data file");
+ tx_additem(menu, " Acti^v^ity mode",
+ "Toggles activity indicators between kbits/s and kbytes/s");
+ tx_additem(menu, " Source ^M^AC addrs in traffic monitor",
+ "Toggles display of source MAC addresses in the IP Traffic Monitor");
+ tx_additem(menu, " ^S^how v6-in-v4 traffic as IPv6",
+ "Toggled display of IPv6 tunnel in IPv4 as IPv6 traffic");
+ tx_additem(menu, NULL, NULL);
+ tx_additem(menu, " ^T^imers...", "Configures timeouts and intervals");
+ tx_additem(menu, NULL, NULL);
+ tx_additem(menu, " ^A^dditional ports...",
+ "Allows you to add port numbers higher than 1023 for the service stats");
+ tx_additem(menu, " ^D^elete port/range...",
+ "Deletes a port or range of ports earlier added");
+ tx_additem(menu, NULL, NULL);
+ tx_additem(menu, " ^E^thernet/PLIP host descriptions...",
+ "Manages descriptions for Ethernet and PLIP addresses");
+ tx_additem(menu, " ^F^DDI host descriptions...",
+ "Manages descriptions for FDDI and FDDI addresses");
+ tx_additem(menu, NULL, NULL);
+ tx_additem(menu, " E^x^it configuration", "Returns to main menu");
+}
+
+static void maketimermenu(struct MENU *menu)
+{
+ tx_initmenu(menu, 8, 35, (LINES - 19) / 2 + 7, (COLS - 35) / 2, BOXATTR,
+ STDATTR, HIGHATTR, BARSTDATTR, BARHIGHATTR, DESCATTR);
+
+ tx_additem(menu, " TCP ^t^imeout...",
+ "Sets the length of time before inactive TCP entries are considered idle");
+ tx_additem(menu, " ^L^ogging interval...",
+ "Sets the time between loggings for interface, host, and service stats");
+ tx_additem(menu, " ^S^creen update interval...",
+ "Sets the screen update interval in seconds (set to 0 for fastest updates)");
+ tx_additem(menu, " TCP closed/idle ^p^ersistence...",
+ "Determines how long closed/idle/reset entries stay onscreen");
+ tx_additem(menu, NULL, NULL);
+ tx_additem(menu, " E^x^it menu", "Returns to the configuration menu");
+}
+
+static void printoptonoff(unsigned int option, WINDOW * win)
+{
+ if (option)
+ wprintw(win, " On");
+ else
+ wprintw(win, "Off");
+}
+
+static void indicatesetting(int row, WINDOW *win)
+{
+ wmove(win, row, 30);
+ wattrset(win, HIGHATTR);
+
+ switch (row) {
+ case 1:
+ printoptonoff(options.revlook, win);
+ break;
+ case 2:
+ printoptonoff(options.servnames, win);
+ break;
+ case 3:
+ printoptonoff(options.promisc, win);
+ break;
+ case 4:
+ printoptonoff(options.color, win);
+ break;
+ case 5:
+ printoptonoff(options.logging, win);
+ break;
+ case 6:
+ wmove(win, row, 25);
+ if (options.actmode == KBITS)
+ wprintw(win, " kbits/s");
+ else
+ wprintw(win, "kbytes/s");
+ break;
+ case 7:
+ printoptonoff(options.mac, win);
+ break;
+ case 8:
+ printoptonoff(options.v6inv4asv6, win);
+ }
+
+}
+
+void saveoptions(void)
+{
+ int fd;
+ int bw;
+
+ fd = open(CONFIGFILE, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR);
+
+ if (fd < 0) {
+ tui_error(ANYKEY_MSG, "Cannot create config file: %s %s",
+ CONFIGFILE, strerror(errno));
+ return;
+ }
+ bw = write(fd, &options, sizeof(struct OPTIONS));
+
+ if (bw < 0)
+ tui_error(ANYKEY_MSG, "Unable to write config file");
+
+ close(fd);
+}
+
+static void setdefaultopts(void)
+{
+ options.revlook = 0;
+ options.promisc = 0;
+ options.servnames = 0;
+ options.color = 1;
+ options.logging = 0;
+ options.actmode = KBITS;
+ options.mac = 0;
+ options.timeout = 15;
+ options.logspan = 3600;
+ options.updrate = 0;
+ options.closedint = 0;
+ options.v6inv4asv6 = 1;
+}
+
+void loadoptions(void)
+{
+ int fd;
+
+ setdefaultopts();
+ fd = open(CONFIGFILE, O_RDONLY);
+
+ if (fd < 0)
+ return;
+
+ read(fd, &options, sizeof(struct OPTIONS));
+
+ close(fd);
+}
+
+static void updatetimes(WINDOW *win)
+{
+ wattrset(win, HIGHATTR);
+ mvwprintw(win, 10, 25, "%3u mins", options.timeout);
+ mvwprintw(win, 11, 25, "%3u mins", options.logspan / 60);
+ mvwprintw(win, 12, 25, "%3u secs", options.updrate);
+ mvwprintw(win, 13, 25, "%3u mins", options.closedint);
+}
+
+static void showoptions(WINDOW *win)
+{
+ int i;
+
+ for (i = 1; i <= 8; i++)
+ indicatesetting(i, win);
+
+ updatetimes(win);
+}
+
+static void settimeout(time_t *value, const char *units, int allow_zero,
+ int *aborted)
+{
+ WINDOW *dlgwin;
+ PANEL *dlgpanel;
+ struct FIELDLIST field;
+ time_t tmval = 0;
+
+ dlgwin = newwin(7, 40, (LINES - 7) / 2, (COLS - 40) / 4);
+ dlgpanel = new_panel(dlgwin);
+
+ wattrset(dlgwin, DLGBOXATTR);
+ tx_colorwin(dlgwin);
+ tx_box(dlgwin, ACS_VLINE, ACS_HLINE);
+
+ wattrset(dlgwin, DLGTEXTATTR);
+ mvwprintw(dlgwin, 2, 2, "Enter value in %s", units);
+ wmove(dlgwin, 5, 2);
+ stdkeyhelp(dlgwin);
+
+ tx_initfields(&field, 1, 10, (LINES - 7) / 2 + 3, (COLS - 40) / 4 + 2,
+ DLGTEXTATTR, FIELDATTR);
+ tx_addfield(&field, 3, 0, 0, "");
+
+ do {
+ tx_fillfields(&field, aborted);
+
+ if (!(*aborted)) {
+ unsigned int tm;
+
+ tmval = 0;
+ int ret = strtoul_ui(field.list->buf, 10, &tm);
+ if ((ret == -1) || (!allow_zero && (tm == 0)))
+ tui_error(ANYKEY_MSG, "Invalid timeout value");
+ else
+ tmval = tm;
+ }
+ } while (((!allow_zero) && (tmval == 0)) && (!(*aborted)));
+
+ if (!(*aborted))
+ *value = tmval;
+
+ del_panel(dlgpanel);
+ delwin(dlgwin);
+
+ tx_destroyfields(&field);
+ update_panels();
+ doupdate();
+}
+
+void setoptions(void)
+{
+ int row = 1;
+ int trow = 1; /* row for timer submenu */
+ int aborted;
+
+ struct MENU menu;
+ struct MENU timermenu;
+
+ WINDOW *statwin;
+ PANEL *statpanel;
+
+ struct porttab *ports;
+
+ loadaddports(&ports);
+
+ makeoptionmenu(&menu);
+
+ statwin = newwin(15, 35, (LINES - 19) / 2 - 1, (COLS - 40) / 16 + 40);
+ statpanel = new_panel(statwin);
+
+ wattrset(statwin, BOXATTR);
+ tx_colorwin(statwin);
+ tx_box(statwin, ACS_VLINE, ACS_HLINE);
+ wmove(statwin, 9, 1);
+ whline(statwin, ACS_HLINE, 33);
+ mvwprintw(statwin, 0, 1, " Current Settings ");
+ wattrset(statwin, STDATTR);
+ mvwprintw(statwin, 1, 2, "Reverse DNS lookups:");
+ mvwprintw(statwin, 2, 2, "Service names:");
+ mvwprintw(statwin, 3, 2, "Promiscuous:");
+ mvwprintw(statwin, 4, 2, "Color:");
+ mvwprintw(statwin, 5, 2, "Logging:");
+ mvwprintw(statwin, 6, 2, "Activity mode:");
+ mvwprintw(statwin, 7, 2, "MAC addresses:");
+ mvwprintw(statwin, 8, 2, "v6-in-v4 as IPv6:");
+ mvwprintw(statwin, 10, 2, "TCP timeout:");
+ mvwprintw(statwin, 11, 2, "Log interval:");
+ mvwprintw(statwin, 12, 2, "Update interval:");
+ mvwprintw(statwin, 13, 2, "Closed/idle persist:");
+ showoptions(statwin);
+
+ do {
+ tx_showmenu(&menu);
+ tx_operatemenu(&menu, &row, &aborted);
+
+ switch (row) {
+ case 1:
+ options.revlook = ~options.revlook;
+ break;
+ case 2:
+ options.servnames = ~options.servnames;
+ break;
+ case 3:
+ options.promisc = ~options.promisc;
+ break;
+ case 4:
+ options.color = ~options.color;
+ break;
+ case 5:
+ options.logging = ~options.logging;
+ break;
+ case 6:
+ options.actmode = ~options.actmode;
+ break;
+ case 7:
+ options.mac = ~options.mac;
+ break;
+ case 8:
+ options.v6inv4asv6 = ~options.v6inv4asv6;
+ break;
+ case 10:
+ maketimermenu(&timermenu);
+ trow = 1;
+ do {
+ tx_showmenu(&timermenu);
+ tx_operatemenu(&timermenu, &trow, &aborted);
+
+ switch (trow) {
+ case 1:
+ settimeout(&options.timeout,
+ "minutes", DONT_ALLOW_ZERO,
+ &aborted);
+ if (!aborted)
+ updatetimes(statwin);
+ break;
+ case 2:
+ settimeout(&options.logspan,
+ "minutes", DONT_ALLOW_ZERO,
+ &aborted);
+ if (!aborted) {
+ options.logspan =
+ options.logspan * 60;
+ updatetimes(statwin);
+ }
+ break;
+ case 3:
+ settimeout(&options.updrate, "seconds",
+ ALLOW_ZERO, &aborted);
+ if (!aborted)
+ updatetimes(statwin);
+ break;
+ case 4:
+ settimeout(&options.closedint,
+ "minutes", ALLOW_ZERO,
+ &aborted);
+ if (!aborted)
+ updatetimes(statwin);
+ break;
+ }
+ } while (trow != 6);
+
+ tx_destroymenu(&timermenu);
+ update_panels();
+ doupdate();
+ break;
+ case 12:
+ addmoreports(&ports);
+ break;
+ case 13:
+ removeaport(&ports);
+ break;
+ case 15:
+ manage_eth_desc(ARPHRD_ETHER);
+ break;
+ case 16:
+ manage_eth_desc(ARPHRD_FDDI);
+ break;
+ }
+
+ indicatesetting(row, statwin);
+ } while (row != 18);
+
+ destroyporttab(ports);
+ tx_destroymenu(&menu);
+ del_panel(statpanel);
+ delwin(statwin);
+ update_panels();
+ doupdate();
+}
diff --git a/src/options.h b/src/options.h
new file mode 100644
index 0000000..2304600
--- /dev/null
+++ b/src/options.h
@@ -0,0 +1,19 @@
+#ifndef IPTRAF_NG_OPTIONS_H
+#define IPTRAF_NG_OPTIONS_H
+
+struct OPTIONS {
+ unsigned int color:1, logging:1, revlook:1, servnames:1, promisc:1,
+ actmode:1, mac:1, v6inv4asv6:1, dummy:8;
+ time_t timeout;
+ time_t logspan;
+ time_t updrate;
+ time_t closedint;
+};
+
+extern struct OPTIONS options;
+
+void setoptions(void);
+void loadoptions(void);
+void saveoptions(void);
+
+#endif /* IPTRAF_NG_OPTIONS_H */
diff --git a/src/othptab.c b/src/othptab.c
new file mode 100644
index 0000000..d1d9658
--- /dev/null
+++ b/src/othptab.c
@@ -0,0 +1,797 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+/***
+
+othptab.c - non-TCP protocol display module
+
+***/
+
+#include "iptraf-ng-compat.h"
+
+#include "tui/winops.h"
+
+#include "arphdr.h"
+#include "options.h"
+#include "revname.h"
+#include "tcptable.h"
+#include "othptab.h"
+#include "deskman.h"
+#include "attrs.h"
+#include "log.h"
+#include "rvnamed.h"
+#include "servname.h"
+#include "addproto.h"
+#include "packet.h"
+#include "hostmon.h"
+#include "sockaddr.h"
+
+#define MSGSTRING_MAX 240
+#define SHORTSTRING_MAX 40
+
+static void writeothplog(int logging, FILE *fd, char *protname,
+ char *description, char *additional, int is_ip,
+ int withmac, struct othptabent *entry)
+{
+ char msgbuffer[MSGSTRING_MAX];
+ char scratchpad[MSGSTRING_MAX];
+
+ if (logging) {
+ memset(msgbuffer, 0, MSGSTRING_MAX);
+
+ strcpy(msgbuffer, protname);
+ strcat(msgbuffer, "; ");
+ strcat(msgbuffer, entry->iface);
+ sprintf(scratchpad, "; %u bytes;", entry->pkt_length);
+ strcat(msgbuffer, scratchpad);
+
+ if ((entry->smacaddr[0] != '\0') && (withmac)) {
+ sprintf(scratchpad, " source MAC address %s;",
+ entry->smacaddr);
+ strcat(msgbuffer, scratchpad);
+ }
+
+ if (is_ip) {
+ if (((entry->protocol == IPPROTO_UDP)
+ && (!(entry->fragment)))
+ || (entry->protocol == IPPROTO_TCP))
+ sprintf(scratchpad, " from %s:%s to %s:%s",
+ entry->s_fqdn, entry->un.udp.s_sname,
+ entry->d_fqdn, entry->un.udp.d_sname);
+ else
+ sprintf(scratchpad, " from %s to %s",
+ entry->s_fqdn, entry->d_fqdn);
+ } else
+ sprintf(scratchpad, " from %s to %s ", entry->smacaddr,
+ entry->dmacaddr);
+
+ strcat(msgbuffer, scratchpad);
+ strcpy(scratchpad, "");
+ if (strcmp(description, "") != 0) {
+ sprintf(scratchpad, "; %s", description);
+ strcat(msgbuffer, scratchpad);
+ }
+ strcpy(scratchpad, "");
+ if (strcmp(additional, "") != 0) {
+ sprintf(scratchpad, " (%s)", additional);
+ strcat(msgbuffer, scratchpad);
+ }
+ writelog(logging, fd, msgbuffer);
+ }
+}
+
+void init_othp_table(struct othptable *table)
+{
+ unsigned int winht;
+ unsigned int wintop;
+ unsigned int obmaxx __unused;
+
+ wintop = (LINES * 0.6) + 1;
+ winht = LINES - wintop - 2;
+
+ table->count = 0;
+ table->lastpos = 0;
+ table->strindex = 0;
+ table->htstat = NOHTIND;
+ table->head = table->tail = NULL;
+ table->firstvisible = table->lastvisible = NULL;
+ table->borderwin = newwin(winht, COLS, wintop, 0);
+ table->borderpanel = new_panel(table->borderwin);
+ wattrset(table->borderwin, BOXATTR);
+ tx_box(table->borderwin, ACS_VLINE, ACS_HLINE);
+
+ table->head = table->tail = NULL;
+ table->othpwin = newwin(winht - 2, COLS - 2, wintop + 1, 1);
+ table->othppanel = new_panel(table->othpwin);
+ wattrset(table->othpwin, STDATTR);
+ tx_colorwin(table->othpwin);
+ update_panels();
+ doupdate();
+
+ tx_stdwinset(table->othpwin);
+ getmaxyx(table->borderwin, table->obmaxy, obmaxx);
+ table->oimaxy = table->obmaxy - 2;
+}
+
+/* Cancel the corresponding TCP entry if an ICMP Destination Unreachable
+ * is received.
+ */
+void check_icmp_dest_unreachable(struct tcptable *table, struct pkt_hdr *pkt,
+ char *ifname)
+{
+ char *ip_payload = pkt->pkt_payload + pkt_iph_len(pkt);
+ struct tcphdr *tcp;
+ struct tcptableent *tcpentry = NULL;
+
+ switch (pkt_ip_protocol(pkt)) {
+ case IPPROTO_ICMP: {
+ struct icmphdr *icmp = (struct icmphdr *)ip_payload;
+ if (icmp->type != ICMP_DEST_UNREACH)
+ return;
+
+ /* get an original IP header located after ICMP header */
+ struct iphdr *ip = (struct iphdr *)(ip_payload + 8);
+ if (ip->protocol != IPPROTO_TCP)
+ return;
+
+ struct sockaddr_storage saddr, daddr;
+ sockaddr_make_ipv4(&saddr, ip->saddr);
+ sockaddr_make_ipv4(&daddr, ip->daddr);
+
+ /* get an original TCP header */
+ tcp = (struct tcphdr *) (ip_payload + 8 + (ip->ihl * 4));
+ sockaddr_set_port(&saddr, ntohs(tcp->source));
+ sockaddr_set_port(&daddr, ntohs(tcp->dest));
+
+ /* check if this tcpentry exists */
+ tcpentry = in_table(table, &saddr, &daddr, ifname);
+
+ break; }
+ case IPPROTO_ICMPV6: {
+ struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)ip_payload;
+ if (icmp6->icmp6_type != ICMP6_DST_UNREACH)
+ return;
+
+ /* get an original IPv6 header located after ICMPv6 header */
+ struct ip6_hdr *ip6 = (struct ip6_hdr *)(ip_payload + 8);
+ if (ip6->ip6_nxt != IPPROTO_TCP) /* FIXME: IPv6 extension headers ??? */
+ return;
+
+ struct sockaddr_storage saddr, daddr;
+ sockaddr_make_ipv6(&saddr, &ip6->ip6_src);
+ sockaddr_make_ipv6(&daddr, &ip6->ip6_dst);
+
+ /* get an original TCP header */
+ tcp = (struct tcphdr *) (ip_payload + 8 + 40); /* FIXME: 40: IPv6 extension headers ??? */
+ sockaddr_set_port(&saddr, ntohs(tcp->source));
+ sockaddr_set_port(&daddr, ntohs(tcp->dest));
+
+ /* check if this tcpentry exists */
+ tcpentry = in_table(table, &saddr, &daddr, ifname);
+
+ break; }
+ default:
+ return;
+ }
+
+ if (tcpentry != NULL) {
+ /* yes, tcpentry exists --> reset it */
+ tcpentry->stat = FLAG_RST;
+ tcpentry->oth_connection->stat = FLAG_RST;
+ addtoclosedlist(table, tcpentry);
+ }
+}
+
+struct othptabent *add_othp_entry(struct othptable *table, struct pkt_hdr *pkt,
+ struct sockaddr_storage *saddr,
+ struct sockaddr_storage *daddr,
+ int is_ip,
+ int protocol,
+ char *packet2,
+ char *ifname, struct resolver *res,
+ int logging, FILE *logfile)
+{
+ struct othptabent *new_entry;
+ struct othptabent *temp;
+
+ new_entry = xmallocz(sizeof(struct othptabent));
+
+ new_entry->is_ip = is_ip;
+ new_entry->fragment = !packet_is_first_fragment(pkt);
+
+ if (options.mac || !is_ip) {
+ if (pkt->from->sll_hatype == ARPHRD_ETHER) {
+ convmacaddr((char *) pkt->ethhdr->h_source, new_entry->smacaddr);
+ convmacaddr((char *) pkt->ethhdr->h_dest, new_entry->dmacaddr);
+ } else if (pkt->from->sll_hatype == ARPHRD_FDDI) {
+ convmacaddr((char *) pkt->fddihdr->saddr, new_entry->smacaddr);
+ convmacaddr((char *) pkt->fddihdr->daddr, new_entry->dmacaddr);
+ }
+ }
+
+ if (is_ip) {
+ sockaddr_copy(&new_entry->saddr, saddr);
+ sockaddr_copy(&new_entry->daddr, daddr);
+
+ revname(res, saddr, new_entry->s_fqdn,
+ sizeof(new_entry->s_fqdn));
+ revname(res, daddr, new_entry->d_fqdn,
+ sizeof(new_entry->d_fqdn));
+
+ if (!new_entry->fragment) {
+ if (protocol == IPPROTO_ICMP) {
+ new_entry->un.icmp.type =
+ ((struct icmphdr *) packet2)->type;
+ new_entry->un.icmp.code =
+ ((struct icmphdr *) packet2)->code;
+ } else if (protocol == IPPROTO_ICMPV6) {
+ new_entry->un.icmp6.type =
+ ((struct icmp6_hdr *) packet2)->icmp6_type;
+ new_entry->un.icmp6.code =
+ ((struct icmp6_hdr *) packet2)->icmp6_code;
+ } else if (protocol == IPPROTO_UDP) {
+ servlook(ntohs(((struct udphdr *) packet2)->source),
+ IPPROTO_UDP, new_entry->un.udp.s_sname,
+ 10);
+ servlook(ntohs(((struct udphdr *) packet2)->dest),
+ IPPROTO_UDP, new_entry->un.udp.d_sname,
+ 10);
+ } else if (protocol == IPPROTO_OSPFIGP) {
+ new_entry->un.ospf.version =
+ ((struct ospfhdr *) packet2)->ospf_version;
+ new_entry->un.ospf.type =
+ ((struct ospfhdr *) packet2)->ospf_type;
+ new_entry->un.ospf.area =
+ ntohl(((struct ospfhdr *) packet2)->
+ ospf_areaid.s_addr);
+ inet_ntop(AF_INET,
+ &((struct ospfhdr *)packet2)->ospf_routerid,
+ new_entry->un.ospf.routerid,
+ sizeof(new_entry->un.ospf.routerid));
+ }
+ }
+ } else {
+ new_entry->linkproto = pkt->from->sll_hatype;
+
+ if (protocol == ETH_P_ARP) {
+ new_entry->un.arp.opcode =
+ ((struct arp_hdr *) packet2)->ar_op;
+ memcpy(&new_entry->un.arp.src_ip_address.s_addr,
+ &(((struct arp_hdr *) packet2)->ar_sip), 4);
+ memcpy(&new_entry->un.arp.dest_ip_address.s_addr,
+ &(((struct arp_hdr *) packet2)->ar_tip), 4);
+ } else if (protocol == ETH_P_RARP) {
+ new_entry->un.rarp.opcode =
+ ((struct arphdr *) packet2)->ar_op;
+ memcpy(&(new_entry->un.rarp.src_mac_address),
+ &(((struct arp_hdr *) packet2)->ar_sha), 6);
+ memcpy(&(new_entry->un.rarp.dest_mac_address),
+ &(((struct arp_hdr *) packet2)->ar_tha), 6);
+ }
+ }
+
+ new_entry->protocol = protocol;
+ strcpy(new_entry->iface, ifname);
+
+ new_entry->pkt_length = pkt->pkt_len;
+
+ if (table->head == NULL) {
+ new_entry->prev_entry = NULL;
+ table->head = new_entry;
+ table->firstvisible = new_entry;
+ }
+ /*
+ * Max number of entries in the lower window is 512. Upon reaching
+ * this figure, oldest entries are thrown out.
+ */
+
+ if (table->count == 512) {
+ if (table->firstvisible == table->head) {
+ wscrl(table->othpwin, 1);
+ printothpentry(table, table->lastvisible->next_entry,
+ table->oimaxy - 1, logging, logfile);
+ table->firstvisible = table->firstvisible->next_entry;
+ table->lastvisible = table->lastvisible->next_entry;
+ }
+ temp = table->head;
+ table->head = table->head->next_entry;
+ table->head->prev_entry = NULL;
+ free(temp);
+ } else
+ table->count++;
+
+ if (table->tail != NULL) {
+ new_entry->prev_entry = table->tail;
+ table->tail->next_entry = new_entry;
+ }
+ table->tail = new_entry;
+ new_entry->next_entry = NULL;
+
+ table->lastpos++;
+ new_entry->index = table->lastpos;
+
+ if (table->count <= table->oimaxy) {
+ table->lastvisible = new_entry;
+ printothpentry(table, new_entry, table->count - 1, logging,
+ logfile);
+ } else if (table->lastvisible == table->tail->prev_entry) {
+ wscrl(table->othpwin, 1);
+ table->firstvisible = table->firstvisible->next_entry;
+ table->lastvisible = table->tail;
+ printothpentry(table, new_entry, table->oimaxy - 1, logging,
+ logfile);
+ }
+ return new_entry;
+}
+
+/*
+ * Function to retrieve non-IP packet tags. No further details are
+ * provided beyond the type.
+ */
+
+static char *packetlookup(unsigned int protocol)
+{
+ unsigned int i = 0;
+ static struct packetstruct packettypes[] = {
+ {"DEC MOP dump/load", 0x6001},
+ {"DEC MOP remote console", 0x6002},
+ {"DEC DECnet Phase IV", 0x6003},
+ {"DEC LAT", 0x6004},
+ {"DEC DECnet Diagnostics", 0x6005},
+ {"DEC DECnet Customer Use", 0x6006},
+ {"DEC DECnet SCA", 0x6007},
+ {"IPX", 0x8137},
+ {NULL, 0x0}
+ };
+
+
+ while ((packettypes[i].packet_name != NULL)
+ && (packettypes[i].protocol != protocol))
+ i++;
+
+ return packettypes[i].packet_name;
+
+}
+
+void printothpentry(struct othptable *table, struct othptabent *entry,
+ unsigned int target_row, int logging, FILE * logfile)
+{
+ char protname[SHORTSTRING_MAX];
+ char description[SHORTSTRING_MAX];
+ char additional[MSGSTRING_MAX];
+ char msgstring[MSGSTRING_MAX];
+ char scratchpad[2 * MSGSTRING_MAX];
+ char *startstr;
+
+ char *packet_type;
+
+ char rarp_mac_addr[18];
+
+ unsigned int unknown = 0;
+
+ struct protoent *protptr;
+
+ wmove(table->borderwin, table->obmaxy - 1, 1);
+ if ((table->lastvisible == table->tail) && (table->htstat != TIND)
+ && (table->count >= table->oimaxy)) {
+ wprintw(table->borderwin, " Bottom ");
+ table->htstat = TIND;
+ } else if ((table->firstvisible == table->head)
+ && (table->htstat != HIND)) {
+ wprintw(table->borderwin, " Top ");
+ table->htstat = HIND;
+ }
+ if (!(entry->is_ip)) {
+ struct in_addr *saddr = NULL;
+
+ wmove(table->othpwin, target_row, 0);
+ scrollok(table->othpwin, 0);
+ wattrset(table->othpwin, UNKNATTR);
+ wprintw(table->othpwin, "%*c", COLS - 2, ' ');
+ scrollok(table->othpwin, 1);
+ wmove(table->othpwin, target_row, 1);
+
+ switch (entry->protocol) {
+ case ETH_P_ARP:
+ sprintf(msgstring, "ARP ");
+ switch (ntohs(entry->un.arp.opcode)) {
+ case ARPOP_REQUEST:
+ strcat(msgstring, "request for ");
+ saddr = &entry->un.arp.dest_ip_address;
+ break;
+ case ARPOP_REPLY:
+ strcat(msgstring, "reply from ");
+ saddr = &entry->un.arp.src_ip_address;
+ break;
+ }
+
+ inet_ntop(AF_INET, saddr, scratchpad, sizeof(scratchpad));
+ strcat(msgstring, scratchpad);
+ wattrset(table->othpwin, ARPATTR);
+ break;
+ case ETH_P_RARP:
+ sprintf(msgstring, "RARP ");
+ memset(rarp_mac_addr, 0, sizeof(rarp_mac_addr));
+ switch (ntohs(entry->un.rarp.opcode)) {
+ case ARPOP_RREQUEST:
+ strcat(msgstring, "request for ");
+ convmacaddr(entry->un.rarp.dest_mac_address,
+ rarp_mac_addr);
+ break;
+ case ARPOP_RREPLY:
+ strcat(msgstring, "reply from ");
+ convmacaddr(entry->un.rarp.src_mac_address,
+ rarp_mac_addr);
+ break;
+ }
+
+ sprintf(scratchpad, "%s", rarp_mac_addr);
+ strcat(msgstring, scratchpad);
+ wattrset(table->othpwin, ARPATTR);
+ break;
+ default:
+ packet_type = packetlookup(entry->protocol);
+ if (packet_type == NULL)
+ sprintf(msgstring, "Non-IP (0x%x)",
+ entry->protocol);
+ else
+ sprintf(msgstring, "Non-IP (%s)", packet_type);
+
+ wattrset(table->othpwin, UNKNATTR);
+ }
+
+ strcpy(protname, msgstring);
+ sprintf(scratchpad, " (%u bytes)", entry->pkt_length);
+ strcat(msgstring, scratchpad);
+
+ if ((entry->linkproto == ARPHRD_ETHER)
+ || (entry->linkproto == ARPHRD_FDDI)) {
+ sprintf(scratchpad, " from %s to %s on %s",
+ entry->smacaddr, entry->dmacaddr, entry->iface);
+
+ strcat(msgstring, scratchpad);
+ }
+ startstr = msgstring + table->strindex;
+ waddnstr(table->othpwin, startstr, COLS - 4);
+ writeothplog(logging, logfile, protname, "", "", 0, 0, entry);
+ return;
+ }
+ strcpy(additional, "");
+ strcpy(description, "");
+
+ switch (entry->protocol) {
+ case IPPROTO_UDP:
+ wattrset(table->othpwin, UDPATTR);
+ strcpy(protname, "UDP");
+ break;
+ case IPPROTO_ICMP:
+ wattrset(table->othpwin, STDATTR);
+ strcpy(protname, "ICMP");
+ break;
+ case IPPROTO_OSPFIGP:
+ wattrset(table->othpwin, OSPFATTR);
+ strcpy(protname, "OSPF");
+ break;
+ case IPPROTO_IGP:
+ wattrset(table->othpwin, IGPATTR);
+ strcpy(protname, "IGP");
+ break;
+ case IPPROTO_IGMP:
+ wattrset(table->othpwin, IGMPATTR);
+ strcpy(protname, "IGMP");
+ break;
+ case IPPROTO_IGRP:
+ wattrset(table->othpwin, IGRPATTR);
+ strcpy(protname, "IGRP");
+ break;
+ case IPPROTO_GRE:
+ wattrset(table->othpwin, GREATTR);
+ strcpy(protname, "GRE");
+ break;
+ case IPPROTO_ICMPV6:
+ wattrset(table->othpwin, ICMPV6ATTR);
+ strcpy(protname, "ICMPv6");
+ break;
+ case IPPROTO_IPV6:
+ wattrset(table->othpwin, IPV6ATTR);
+ strcpy(protname, "IPv6 tun");
+ break;
+ default:
+ wattrset(table->othpwin, UNKNIPATTR);
+ protptr = getprotobynumber(entry->protocol);
+ if (protptr != NULL) {
+ sprintf(protname, "%s", protptr->p_aliases[0]);
+ } else {
+ sprintf(protname, "IP protocol");
+ unknown = 1;
+ }
+ }
+
+ if (!(entry->fragment)) {
+ if (entry->protocol == IPPROTO_ICMP) {
+ switch (entry->un.icmp.type) {
+ case ICMP_ECHOREPLY:
+ strcpy(description, "echo rply");
+ break;
+ case ICMP_ECHO:
+ strcpy(description, "echo req");
+ break;
+ case ICMP_DEST_UNREACH:
+ strcpy(description, "dest unrch");
+ switch (entry->un.icmp.code) {
+ case ICMP_NET_UNREACH:
+ strcpy(additional, "ntwk");
+ break;
+ case ICMP_HOST_UNREACH:
+ strcpy(additional, "host");
+ break;
+ case ICMP_PROT_UNREACH:
+ strcpy(additional, "proto");
+ break;
+ case ICMP_PORT_UNREACH:
+ strcpy(additional, "port");
+ break;
+ case ICMP_FRAG_NEEDED:
+ strcpy(additional, "DF set");
+ break;
+ case ICMP_SR_FAILED:
+ strcpy(additional, "src rte fail");
+ break;
+ case ICMP_NET_UNKNOWN:
+ strcpy(additional, "net unkn");
+ break;
+ case ICMP_HOST_UNKNOWN:
+ strcpy(additional, "host unkn");
+ break;
+ case ICMP_HOST_ISOLATED:
+ strcpy(additional, "src isltd");
+ break;
+ case ICMP_NET_ANO:
+ strcpy(additional, "net comm denied");
+ break;
+ case ICMP_HOST_ANO:
+ strcpy(additional, "host comm denied");
+ break;
+ case ICMP_NET_UNR_TOS:
+ strcpy(additional, "net unrch for TOS");
+ break;
+ case ICMP_HOST_UNR_TOS:
+ strcpy(additional,
+ "host unrch for TOS");
+ break;
+ case ICMP_PKT_FILTERED:
+ strcpy(additional, "pkt fltrd");
+ break;
+ case ICMP_PREC_VIOLATION:
+ strcpy(additional, "prec violtn");
+ break;
+ case ICMP_PREC_CUTOFF:
+ strcpy(additional, "prec cutoff");
+ break;
+ }
+
+ break;
+ case ICMP_SOURCE_QUENCH:
+ strcpy(description, "src qnch");
+ break;
+ case ICMP_REDIRECT:
+ strcpy(description, "redirct");
+ break;
+ case ICMP_TIME_EXCEEDED:
+ strcpy(description, "time excd");
+ break;
+ case ICMP_PARAMETERPROB:
+ strcpy(description, "param prob");
+ break;
+ case ICMP_TIMESTAMP:
+ strcpy(description, "timestmp req");
+ break;
+ case ICMP_INFO_REQUEST:
+ strcpy(description, "info req");
+ break;
+ case ICMP_INFO_REPLY:
+ strcpy(description, "info rep");
+ break;
+ case ICMP_ADDRESS:
+ strcpy(description, "addr mask req");
+ break;
+ case ICMP_ADDRESSREPLY:
+ strcpy(description, "addr mask rep");
+ break;
+ default:
+ strcpy(description, "bad/unkn");
+ break;
+ }
+ } else if (entry->protocol == IPPROTO_ICMPV6) {
+ switch (entry->un.icmp6.type) {
+ case ICMP6_DST_UNREACH:
+ strcpy(description, "dest unrch");
+ switch (entry->un.icmp6.code) {
+ case ICMP6_DST_UNREACH_NOROUTE:
+ strcpy(additional, "no route");
+ break;
+ case ICMP6_DST_UNREACH_ADMIN:
+ strcpy(additional, "admin");
+ break;
+#ifdef ICMP6_DST_UNREACH_NOTNEIGHBOR
+ case ICMP6_DST_UNREACH_NOTNEIGHBOR:
+ strcpy(additional, "not neigh");
+#else
+ case ICMP6_DST_UNREACH_BEYONDSCOPE:
+ strcpy(additional, "not beyondsp");
+#endif
+ break;
+ case ICMP6_DST_UNREACH_ADDR:
+ strcpy(additional, "unreach addr");
+ break;
+ case ICMP6_DST_UNREACH_NOPORT:
+ strcpy(additional, "no port");
+ break;
+ }
+ break;
+ case ICMP6_PACKET_TOO_BIG:
+ strcpy(description, "pkt too big");
+ break;
+ case ICMP6_TIME_EXCEEDED:
+ strcpy(description, "time exceeded");
+ break;
+ case ICMP6_PARAM_PROB:
+ strcpy(description, "param prob");
+ break;
+ case ICMP6_ECHO_REQUEST:
+ strcpy(description, "echo req");
+ break;
+ case ICMP6_ECHO_REPLY:
+ strcpy(description, "echo rply");
+ break;
+ case ND_ROUTER_SOLICIT:
+ strcpy(description, "router sol");
+ break;
+ case ND_ROUTER_ADVERT:
+ strcpy(description, "router adv");
+ break;
+#ifdef ICMP6_MEMBERSHIP_QUERY
+ case ICMP6_MEMBERSHIP_QUERY:
+ strcpy(description, "mbrship query");
+ break;
+#endif
+#ifdef ICMP6_MEMBERSHIP_REPORT
+ case ICMP6_MEMBERSHIP_REPORT:
+ strcpy(description, "mbrship report");
+ break;
+#endif
+#ifdef ICMP6_MEMBERSHIP_REDUCTION
+ case ICMP6_MEMBERSHIP_REDUCTION:
+ strcpy(description, "mbrship reduc");
+ break;
+#endif
+ case ND_NEIGHBOR_SOLICIT:
+ strcpy(description, "neigh sol");
+ break;
+ case ND_NEIGHBOR_ADVERT:
+ strcpy(description, "neigh adv");
+ break;
+ case ND_REDIRECT:
+ strcpy(description, "redirect");
+ break;
+ default:
+ strcpy(description, "bad/unkn");
+ break;
+ }
+ } else if (entry->protocol == IPPROTO_OSPFIGP) {
+ switch (entry->un.ospf.version) {
+ case 2:
+ strcat(protname, "v2");
+ break;
+ case 3:
+ strcat(protname, "v3");
+ break;
+ }
+ switch (entry->un.ospf.type) {
+ case OSPF_TYPE_HELLO:
+ strcpy(description, "hlo");
+ break;
+ case OSPF_TYPE_DB:
+ strcpy(description, "DB desc");
+ break;
+ case OSPF_TYPE_LSR:
+ strcpy(description, "LSR");
+ break;
+ case OSPF_TYPE_LSU:
+ strcpy(description, "LSU");
+ break;
+ case OSPF_TYPE_LSA:
+ strcpy(description, "LSA");
+ break;
+ }
+ sprintf(additional, "a=%lu r=%s", entry->un.ospf.area,
+ entry->un.ospf.routerid);
+ }
+ } else
+ strcpy(description, "fragment");
+
+ strcpy(msgstring, protname);
+ strcat(msgstring, " ");
+
+ if (strcmp(description, "") != 0) {
+ strcat(msgstring, description);
+ strcat(msgstring, " ");
+ }
+ if (strcmp(additional, "") != 0) {
+ sprintf(scratchpad, "(%s) ", additional);
+ strcat(msgstring, scratchpad);
+ }
+ if (unknown) {
+ sprintf(scratchpad, "%u ", entry->protocol);
+ strcat(msgstring, scratchpad);
+ }
+ sprintf(scratchpad, "(%u bytes) ", entry->pkt_length);
+ strcat(msgstring, scratchpad);
+
+ if ((entry->protocol == IPPROTO_UDP) && (!(entry->fragment))) {
+ sprintf(scratchpad, "from %.40s:%s to %.40s:%s", entry->s_fqdn,
+ entry->un.udp.s_sname, entry->d_fqdn,
+ entry->un.udp.d_sname);
+ } else {
+ sprintf(scratchpad, "from %.40s to %.40s", entry->s_fqdn,
+ entry->d_fqdn);
+ }
+
+ strcat(msgstring, scratchpad);
+
+ if (((entry->smacaddr)[0] != '\0') && options.mac) {
+ snprintf(scratchpad, MSGSTRING_MAX, " (src HWaddr %s)",
+ entry->smacaddr);
+ strcat(msgstring, scratchpad);
+ }
+ strcat(msgstring, " on ");
+ strcat(msgstring, entry->iface);
+
+ scrollok(table->othpwin, 0);
+ mvwprintw(table->othpwin, target_row, 0, "%*c", COLS - 2, ' ');
+ scrollok(table->othpwin, 1);
+ wmove(table->othpwin, target_row, 1);
+ startstr = msgstring + table->strindex;
+ waddnstr(table->othpwin, startstr, COLS - 4);
+
+ if (logging)
+ writeothplog(logging, logfile, protname, description,
+ additional, 1, options.mac, entry);
+}
+
+void refresh_othwindow(struct othptable *table)
+{
+ int target_row = 0;
+ struct othptabent *entry;
+
+ wattrset(table->othpwin, STDATTR);
+ tx_colorwin(table->othpwin);
+
+ entry = table->firstvisible;
+
+ while ((entry != NULL) && (entry != table->lastvisible->next_entry)) {
+ printothpentry(table, entry, target_row, 0, NULL);
+ target_row++;
+ entry = entry->next_entry;
+ }
+
+ update_panels();
+ doupdate();
+}
+
+void destroyothptable(struct othptable *table)
+{
+ struct othptabent *ctemp = table->head;
+
+ while (ctemp != NULL) {
+ struct othptabent *next = ctemp->next_entry;
+
+ free(ctemp);
+ ctemp = next;
+ }
+
+ del_panel(table->othppanel);
+ delwin(table->othpwin);
+ del_panel(table->borderpanel);
+ delwin(table->borderwin);
+}
diff --git a/src/othptab.h b/src/othptab.h
new file mode 100644
index 0000000..a7736ed
--- /dev/null
+++ b/src/othptab.h
@@ -0,0 +1,141 @@
+#ifndef IPTRAF_NG_OTHPTAB_H
+#define IPTRAF_NG_OTHPTAB_H
+
+/***
+
+othptab.h - header file for the non-TCP routines
+
+***/
+
+#include "packet.h"
+
+#define NONIP -1
+#define IS_IP 1
+#define NOT_IP 0
+
+#define NOHTIND 0 /* Bottom or Top (head or tail) indicator printed */
+#define TIND 1 /* Tail indicator printed */
+#define HIND 2 /* Head indicator printed */
+
+#define VSCRL_OFFSET 60 /* Characters to vertically scroll */
+
+struct othptabent {
+ struct sockaddr_storage saddr;
+ struct sockaddr_storage daddr;
+ char smacaddr[18]; /* FIXME: use dynamicly allocated space */
+ char dmacaddr[18];
+ unsigned short linkproto;
+ char s_fqdn[100];
+ char d_fqdn[100];
+ int s_fstat;
+ int d_fstat;
+ unsigned int protocol;
+ char iface[IFNAMSIZ];
+ unsigned int pkt_length;
+
+ union {
+ struct {
+ char s_sname[15];
+ char d_sname[15];
+ } udp;
+ struct {
+ unsigned int type;
+ unsigned int code;
+ } icmp;
+ struct {
+ unsigned char version;
+ unsigned char type;
+ unsigned long area;
+ char routerid[16];
+ } ospf;
+ struct {
+ unsigned short opcode;
+ struct in_addr src_ip_address;
+ struct in_addr dest_ip_address;
+ } arp;
+ struct {
+ unsigned short opcode;
+ char src_mac_address[6];
+ char dest_mac_address[6];
+ } rarp;
+ struct {
+ uint8_t type;
+ uint8_t code;
+ } icmp6;
+ } un;
+ unsigned int type;
+ unsigned int code;
+ unsigned int index;
+ int is_ip;
+ int fragment;
+ struct othptabent *prev_entry;
+ struct othptabent *next_entry;
+};
+
+struct othptable {
+ struct othptabent *head;
+ struct othptabent *tail;
+ struct othptabent *firstvisible;
+ struct othptabent *lastvisible;
+ unsigned int count;
+ unsigned int lastpos;
+ unsigned int strindex; /* starting index of the string to display */
+ int htstat;
+ unsigned int obmaxy; /* number of lines in the border window */
+ unsigned int oimaxy; /* number of lines inside the border */
+ WINDOW *othpwin;
+ PANEL *othppanel;
+ WINDOW *borderwin;
+ PANEL *borderpanel;
+};
+
+/* Added by David Harbaugh for Non-IP protocol identification */
+
+struct packetstruct {
+ char *packet_name; /* Name of packet type */
+ unsigned int protocol; /* Number of packet type */
+};
+
+
+/* partially stolen from ospf.h from tcpdump */
+
+#define OSPF_TYPE_UMD 0
+#define OSPF_TYPE_HELLO 1
+#define OSPF_TYPE_DB 2
+#define OSPF_TYPE_LSR 3
+#define OSPF_TYPE_LSU 4
+#define OSPF_TYPE_LSA 5
+#define OSPF_TYPE_MAX 6
+
+struct ospfhdr {
+ u_char ospf_version;
+ u_char ospf_type;
+ u_short ospf_len;
+ struct in_addr ospf_routerid;
+ struct in_addr ospf_areaid;
+ u_short ospf_chksum;
+ u_short ospf_authtype;
+};
+
+void init_othp_table(struct othptable *table);
+
+void check_icmp_dest_unreachable(struct tcptable *table, struct pkt_hdr *pkt,
+ char *ifname);
+
+struct othptabent *add_othp_entry(struct othptable *table, struct pkt_hdr *pkt,
+ struct sockaddr_storage *saddr,
+ struct sockaddr_storage *daddr,
+ int is_ip,
+ int protocol,
+ char *packet2,
+ char *ifname, struct resolver *res,
+ int logging, FILE *logfile);
+
+void printothpentry(struct othptable *table, struct othptabent *entry,
+ unsigned int screen_idx, int logging, FILE * logfile);
+
+void refresh_othwindow(struct othptable *table);
+
+void destroyothptable(struct othptable *table);
+
+#endif /* IPTRAF_NG_OTHPTAB_H */
diff --git a/src/packet.c b/src/packet.c
new file mode 100644
index 0000000..86cdecd
--- /dev/null
+++ b/src/packet.c
@@ -0,0 +1,555 @@
+/* For terms of usage/redistribution/modification see the LICENSE file */
+/* For authors and contributors see the AUTHORS file */
+
+/***
+
+packet.c - routines to open the raw socket, read socket data and
+ adjust the initial packet pointer
+
+***/
+
+#include "iptraf-ng-compat.h"
+
+#include "deskman.h"
+#include "error.h"
+#include "options.h"
+#include "fltdefs.h"
+#include "fltselect.h"
+#include "ipfilter.h"
+#include "ifaces.h"
+#include "packet.h"
+#include "ipfrag.h"
+
+#define pkt_cast_hdrp_l2off_t(hdr, pkt, off) \
+ do { \
+ pkt->hdr = (struct hdr *) (pkt->pkt_buf + off); \
+ } while (0)
+
+#define pkt_cast_hdrp_l2(hdr, pkt) \
+ pkt_cast_hdrp_l2off_t(hdr, pkt, 0)
+
+
+#define pkt_cast_hdrp_l3off_t(hdr, pkt, off) \
+ do { \
+ pkt->hdr = (struct hdr *) (pkt->pkt_payload + off); \
+ } while (0)
+
+#define pkt_cast_hdrp_l3(hdr, pkt) \
+ pkt_cast_hdrp_l3off_t(hdr, pkt, 0)
+
+/* code taken from http://www.faqs.org/rfcs/rfc1071.html. See section 4.1 "C" */
+static int verify_ipv4_hdr_chksum(struct iphdr *ip)
+{
+ register int sum = 0;
+ u_short *addr = (u_short *)ip;
+ int len = ip->ihl * 4;
+
+ while (len > 1) {
+ sum += *addr++;
+ len -= 2;
+ }
+
+ while (sum >> 16)
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ return ((u_short) ~sum) == 0;
+}
+
+static int packet_adjust(struct pkt_hdr *pkt)
+{
+ int retval = 0;
+
+ switch (pkt->from->sll_hatype) {
+ case ARPHRD_ETHER:
+ case ARPHRD_LOOPBACK:
+ pkt_cast_hdrp_l2(ethhdr, pkt);
+ pkt->pkt_payload = pkt->pkt_buf;
+ pkt->pkt_payload += ETH_HLEN;
+ pkt->pkt_len -= ETH_HLEN;
+ break;
+ case ARPHRD_SLIP:
+ case ARPHRD_CSLIP:
+ case ARPHRD_SLIP6:
+ case ARPHRD_CSLIP6:
+ case ARPHRD_PPP:
+ case ARPHRD_TUNNEL:
+ case ARPHRD_SIT:
+ case ARPHRD_NONE:
+ case ARPHRD_IPGRE:
+ pkt->pkt_payload = pkt->pkt_buf;
+ break;
+ case ARPHRD_FRAD:
+ case ARPHRD_DLCI:
+ pkt->pkt_payload = pkt->pkt_buf;
+ pkt->pkt_payload += 4;
+ pkt->pkt_len -= 4;
+ break;
+ case ARPHRD_FDDI:
+ pkt_cast_hdrp_l2(fddihdr, pkt);
+ pkt->pkt_payload = pkt->pkt_buf;
+ pkt->pkt_payload += sizeof(struct fddihdr);
+ pkt->pkt_len -= sizeof(struct fddihdr);
+ break;
+ case ARPHRD_INFINIBAND:
+ pkt->pkt_payload = pkt->pkt_buf;
+ pkt->pkt_payload += 24;
+ pkt->pkt_len -= 24;
+ break;
+ default:
+ /* return a NULL packet to signal an unrecognized link */
+ /* protocol to the caller. Hopefully, this switch statement */
+ /* will grow. */
+ pkt->pkt_payload = NULL;
+ retval = -1;
+ break;
+ }
+ return retval;
+}
+
+/* initialize all layer3 protocol pointers (we need to initialize all
+ * of them, because of case we change pkt->pkt_protocol) */
+static void packet_set_l3_hdrp(struct pkt_hdr *pkt)
+{
+ switch (pkt->pkt_protocol) {
+ case ETH_P_IP:
+ pkt_cast_hdrp_l3(iphdr, pkt);
+ pkt->ip6_hdr = NULL;
+ break;
+ case ETH_P_IPV6:
+ pkt->iphdr = NULL;
+ pkt_cast_hdrp_l3(ip6_hdr, pkt);
+ break;
+ default:
+ pkt->iphdr = NULL;
+ pkt->ip6_hdr = NULL;
+ break;
+ }
+}
+
+int packet_process(struct pkt_hdr *pkt, unsigned int *total_br,
+ in_port_t *sport, in_port_t *dport,
+ int match_opposite, int v6inv4asv6)
+{
+ /* move packet pointer (pkt->pkt_payload) past data link header */
+ if (packet_adjust(pkt) != 0)
+ return INVALID_PACKET;
+
+again:
+ packet_set_l3_hdrp(pkt);
+ switch (pkt->pkt_protocol) {
+ case ETH_P_IP: {
+ struct iphdr *ip = pkt->iphdr;
+ in_port_t f_sport = 0, f_dport = 0;
+
+ if (!verify_ipv4_hdr_chksum(ip))
+ return CHECKSUM_ERROR;
+
+ if ((ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP)
+ && (sport != NULL && dport != NULL)) {
+ in_port_t sport_tmp, dport_tmp;
+
+ /*
+ * Process TCP/UDP fragments
+ */
+ if (ipv4_is_fragmented(ip)) {
+ int firstin = 0;
+
+ /*
+ * total_br contains total byte count of all fragments
+ * not yet retrieved. Will differ only if fragments
+ * arrived before the first fragment, in which case
+ * the total accumulated fragment sizes will be returned
+ * once the first fragment arrives.
+ */
+
+ if (total_br != NULL)
+ *total_br =
+ processfragment(ip, &sport_tmp,
+ &dport_tmp,
+ &firstin);
+
+ if (!firstin)
+ return MORE_FRAGMENTS;
+ } else {
+ struct tcphdr *tcp;
+ struct udphdr *udp;
+ char *ip_payload = (char *) ip + pkt_iph_len(pkt);
+
+ switch (ip->protocol) {
+ case IPPROTO_TCP:
+ tcp = (struct tcphdr *) ip_payload;
+ sport_tmp = ntohs(tcp->source);
+ dport_tmp = ntohs(tcp->dest);
+ break;
+ case IPPROTO_UDP:
+ udp = (struct udphdr *) ip_payload;
+ sport_tmp = ntohs(udp->source);
+ dport_tmp = ntohs(udp->dest);
+ break;
+ default:
+ sport_tmp = 0;
+ dport_tmp = 0;
+ break;
+ }
+
+ if (total_br != NULL)
+ *total_br = pkt->pkt_len;
+ }
+
+ if (sport != NULL)
+ *sport = sport_tmp;
+
+ if (dport != NULL)
+ *dport = dport_tmp;
+
+ f_sport = sport_tmp;
+ f_dport = dport_tmp;
+ }
+ /* Process IP filter */
+ if ((ofilter.filtercode != 0)
+ &&
+ (!ipfilter
+ (ip->saddr, ip->daddr, f_sport, f_dport, ip->protocol,
+ match_opposite)))
+ return PACKET_FILTERED;
+ if (v6inv4asv6 && (ip->protocol == IPPROTO_IPV6)) {
+ pkt->pkt_protocol = ETH_P_IPV6;
+ pkt->pkt_payload += pkt_iph_len(pkt);
+ pkt->pkt_len -= pkt_iph_len(pkt);
+ goto again;
+ }
+ break; }
+ case ETH_P_IPV6: {
+ struct tcphdr *tcp;
+ struct udphdr *udp;
+ struct ip6_hdr *ip6 = pkt->ip6_hdr;
+ char *ip_payload = (char *) ip6 + pkt_iph_len(pkt);
+
+ //TODO: Filter packets
+ switch (pkt_ip_protocol(pkt)) {
+ case IPPROTO_TCP:
+ tcp = (struct tcphdr *) ip_payload;
+ if (sport)
+ *sport = ntohs(tcp->source);
+ if (dport)
+ *dport = ntohs(tcp->dest);
+ break;
+ case IPPROTO_UDP:
+ udp = (struct udphdr *) ip_payload;
+ if (sport)
+ *sport = ntohs(udp->source);
+ if (dport)
+ *dport = ntohs(udp->dest);
+ break;
+ default:
+ if (sport)
+ *sport = 0;
+ if (dport)
+ *dport = 0;
+ break;
+ }
+ break; }
+ case ETH_P_8021Q:
+ case ETH_P_QINQ1: /* ETH_P_QINQx are not officially */
+ case ETH_P_QINQ2: /* registered IDs */
+ case ETH_P_QINQ3:
+ case ETH_P_8021AD:
+ /* strip 802.1Q/QinQ/802.1ad VLAN header */
+ pkt->pkt_payload += 4;
+ pkt->pkt_len -= 4;
+ /* update network protocol */
+ pkt->pkt_protocol = ntohs(*((unsigned short *) pkt->pkt_payload));
+ goto again;
+ default:
+ /* not IPv4 and not IPv6: apply non-IP packet filter */
+ if (!nonipfilter(pkt->pkt_protocol)) {
+ return PACKET_FILTERED;
+ }
+ }
+ return PACKET_OK;
+}
+
+int packet_init(struct pkt_hdr *pkt)
+{
+ pkt->pkt_payload = NULL;
+ pkt->ethhdr = NULL;
+ pkt->fddihdr = NULL;
+ pkt->iphdr = NULL;
+ pkt->ip6_hdr = NULL;
+ pkt->pkt_len = 0; /* signalize we have no packet prepared */
+
+ pkt->pkt_buf = NULL;
+ pkt->from = NULL;
+
+ return 0; /* all O.K. */
+}
+
+void packet_destroy(struct pkt_hdr *pkt __unused)
+{
+ destroyfraglist();
+}
+
+int packet_is_first_fragment(struct pkt_hdr *pkt)
+{
+ switch (pkt->pkt_protocol) {
+ case ETH_P_IP:
+ return ipv4_is_first_fragment(pkt->iphdr);
+ case ETH_P_IPV6:
+ /* FIXME: IPv6 can also be fragmented !!! */
+ /* fall through for now */
+ default:
+ return !0;
+ }
+}
+
+static char *pkttype_to_string(unsigned int type)
+{
+ switch(type) {
+ case PACKET_HOST: return "PACKET_HOST";
+ case PACKET_BROADCAST: return "PACKET_BROADCAST";
+ case PACKET_MULTICAST: return "PACKET_MULTICAST";
+ case PACKET_OTHERHOST: return "PACKET_OTHERHOST";
+ case PACKET_OUTGOING: return "PACKET_OUTGOING";
+ case PACKET_LOOPBACK: return "PACKET_LOOPBACK";
+ case PACKET_USER: return "PACKET_USER";
+ case PACKET_KERNEL: return "PACKET_KERNEL";
+ default: return NULL;
+ }
+}
+
+static char *l2_type_to_string(unsigned int type)
+{
+ switch(type) {
+ case 0: return "ARPHRD_NETROM";
+ case 0xFFFE: return "ARPHRD_NONE";
+ case 0xFFFF: return "ARPHRD_VOID";
+ case 1: return "ARPHRD_ETHER";
+ case 2: return "ARPHRD_EETHER";
+ case 3: return "ARPHRD_AX25";
+ case 4: return "ARPHRD_PRONET";
+ case 5: return "ARPHRD_CHAOS";
+ case 6: return "ARPHRD_IEEE802";
+ case 7: return "ARPHRD_ARCNET";
+ case 8: return "ARPHRD_APPLETLK";
+ case 15: return "ARPHRD_DLCI";
+ case 19: return "ARPHRD_ATM";
+ case 23: return "ARPHRD_METRICOM";
+ case 24: return "ARPHRD_IEEE1394";
+ case 27: return "ARPHRD_EUI64";
+ case 32: return "ARPHRD_INFINIBAND";
+ case 256: return "ARPHRD_SLIP";
+ case 257: return "ARPHRD_CSLIP";
+ case 258: return "ARPHRD_SLIP6";
+ case 259: return "ARPHRD_CSLIP6";
+ case 260: return "ARPHRD_RSRVD";
+ case 264: return "ARPHRD_ADAPT";
+ case 270: return "ARPHRD_ROSE";
+ case 271: return "ARPHRD_X25";
+ case 272: return "ARPHRD_HWX25";
+ case 280: return "ARPHRD_CAN";
+ case 512: return "ARPHRD_PPP";
+ case 513: return "ARPHRD_CISCO";
+ case 516: return "ARPHRD_LAPB";
+ case 517: return "ARPHRD_DDCMP";
+ case 518: return "ARPHRD_RAWHDLC";
+ case 519: return "ARPHRD_RAWIP";
+ case 768: return "ARPHRD_TUNNEL";
+ case 769: return "ARPHRD_TUNNEL6";
+ case 770: return "ARPHRD_FRAD";
+ case 771: return "ARPHRD_SKIP";
+ case 772: return "ARPHRD_LOOPBACK";
+ case 773: return "ARPHRD_LOCALTLK";
+ case 774: return "ARPHRD_FDDI";
+ case 775: return "ARPHRD_BIF";
+ case 776: return "ARPHRD_SIT";
+ case 777: return "ARPHRD_IPDDP";
+ case 778: return "ARPHRD_IPGRE";
+ case 779: return "ARPHRD_PIMREG";
+ case 780: return "ARPHRD_HIPPI";
+ case 781: return "ARPHRD_ASH";
+ case 782: return "ARPHRD_ECONET";
+ case 783: return "ARPHRD_IRDA";
+ case 784: return "ARPHRD_FCPP";
+ case 785: return "ARPHRD_FCAL";
+ case 786: return "ARPHRD_FCPL";
+ case 787: return "ARPHRD_FCFABRIC";
+ case 800: return "ARPHRD_IEEE802_TR";
+ case 801: return "ARPHRD_IEEE80211";
+ case 802: return "ARPHRD_IEEE80211_PRISM";
+ case 803: return "ARPHRD_IEEE80211_RADIOTAP";
+ case 804: return "ARPHRD_IEEE802154";
+ case 805: return "ARPHRD_IEEE802154_MONITOR";
+ case 820: return "ARPHRD_PHONET";
+ case 821: return "ARPHRD_PHONET_PIPE";
+ case 822: return "ARPHRD_CAIF";
+ case 823: return "ARPHRD_IP6GRE";
+ case 824: return "ARPHRD_NETLINK";
+ case 825: return "ARPHRD_6LOWPAN";
+ case 826: return "ARPHRD_VSOCKMON";
+ default: return NULL;
+ }
+}
+
+static char *l3_proto_to_string(unsigned short protocol)
+{
+ switch(protocol) {
+ case 0x0001: return "ETH_P_802_3";
+ case 0x0002: return "ETH_P_AX25";
+ case 0x0003: return "ETH_P_ALL";
+ case 0x0004: return "ETH_P_802_2";
+ case 0x0005: return "ETH_P_SNAP";
+ case 0x0006: return "ETH_P_DDCMP";
+ case 0x0007: return "ETH_P_WAN_PPP";
+ case 0x0008: return "ETH_P_PPP_MP";
+ case 0x0009: return "ETH_P_LOCALTALK";
+ case 0x000C: return "ETH_P_CAN";
+ case 0x000D: return "ETH_P_CANFD";
+ case 0x0010: return "ETH_P_PPPTALK";
+ case 0x0011: return "ETH_P_TR_802_2";
+ case 0x0015: return "ETH_P_MOBITEX";
+ case 0x0016: return "ETH_P_CONTROL";
+ case 0x0017: return "ETH_P_IRDA";
+ case 0x0018: return "ETH_P_ECONET";
+ case 0x0019: return "ETH_P_HDLC";
+ case 0x001A: return "ETH_P_ARCNET";
+ case 0x001B: return "ETH_P_DSA";
+ case 0x001C: return "ETH_P_TRAILER";
+ case 0x0060: return "ETH_P_LOOP";
+ case 0x00F5: return "ETH_P_PHONET";
+ case 0x00F6: return "ETH_P_IEEE802154";
+ case 0x00F7: return "ETH_P_CAIF";
+ case 0x00F8: return "ETH_P_XDSA";
+ case 0x00F9: return "ETH_P_MAP";
+ case 0x0200: return "ETH_P_PUP";
+ case 0x0201: return "ETH_P_PUPAT";
+ case 0x0800: return "ETH_P_IP";
+ case 0x0805: return "ETH_P_X25";
+ case 0x0806: return "ETH_P_ARP";
+ case 0x08FF: return "ETH_P_BPQ";
+ case 0x0a00: return "ETH_P_IEEEPUP";
+ case 0x0a01: return "ETH_P_IEEEPUPAT";
+ case 0x22EB: return "ETH_P_ERSPAN2";
+ case 0x22F0: return "ETH_P_TSN";
+ case 0x4305: return "ETH_P_BATMAN";
+ case 0x6000: return "ETH_P_DEC";
+ case 0x6001: return "ETH_P_DNA_DL";
+ case 0x6002: return "ETH_P_DNA_RC";
+ case 0x6003: return "ETH_P_DNA_RT";
+ case 0x6004: return "ETH_P_LAT";
+ case 0x6005: return "ETH_P_DIAG";
+ case 0x6006: return "ETH_P_CUST";
+ case 0x6007: return "ETH_P_SCA";
+ case 0x6558: return "ETH_P_TEB";
+ case 0x8035: return "ETH_P_RARP";
+ case 0x809B: return "ETH_P_ATALK";
+ case 0x80F3: return "ETH_P_AARP";
+ case 0x8100: return "ETH_P_8021Q";
+ case 0x8137: return "ETH_P_IPX";
+ case 0x86DD: return "ETH_P_IPV6";
+ case 0x8808: return "ETH_P_PAUSE";
+ case 0x8809: return "ETH_P_SLOW";
+ case 0x883E: return "ETH_P_WCCP";
+ case 0x8847: return "ETH_P_MPLS_UC";
+ case 0x8848: return "ETH_P_MPLS_MC";
+ case 0x884c: return "ETH_P_ATMMPOA";
+ case 0x8863: return "ETH_P_PPP_DISC";
+ case 0x8864: return "ETH_P_PPP_SES";
+ case 0x886c: return "ETH_P_LINK_CTL";
+ case 0x8884: return "ETH_P_ATMFATE";
+ case 0x888E: return "ETH_P_PAE";
+ case 0x88A2: return "ETH_P_AOE";
+ case 0x88A8: return "ETH_P_8021AD";
+ case 0x88B5: return "ETH_P_802_EX1";
+ case 0x88BE: return "ETH_P_ERSPAN";
+ case 0x88C7: return "ETH_P_PREAUTH";
+ case 0x88CA: return "ETH_P_TIPC";
+ case 0x88CC: return "ETH_P_LLDP";
+ case 0x88E5: return "ETH_P_MACSEC";
+ case 0x88E7: return "ETH_P_8021AH";
+ case 0x88F5: return "ETH_P_MVRP";
+ case 0x88F7: return "ETH_P_1588";
+ case 0x88F8: return "ETH_P_NCSI";
+ case 0x88FB: return "ETH_P_PRP";
+ case 0x8906: return "ETH_P_FCOE";
+ case 0x890D: return "ETH_P_TDLS";
+ case 0x8914: return "ETH_P_FIP";
+ case 0x8915: return "ETH_P_IBOE";
+ case 0x8917: return "ETH_P_80221";
+ case 0x892F: return "ETH_P_HSR";
+ case 0x894F: return "ETH_P_NSH";
+ case 0x9000: return "ETH_P_LOOPBACK";
+ case 0x9100: return "ETH_P_QINQ1";
+ case 0x9200: return "ETH_P_QINQ2";
+ case 0x9300: return "ETH_P_QINQ3";
+ case 0xDADA: return "ETH_P_EDSA";
+ case 0xDADB: return "ETH_P_DSA_8021Q";
+ case 0xED3E: return "ETH_P_IFE";
+ case 0xFBFB: return "ETH_P_AF_IUCV";
+ default: return NULL;
+ }
+}
+
+void packet_dump(struct pkt_hdr *pkt, FILE *fp) {
+ unsigned i = 0;
+ unsigned len;
+ char *adr;
+ char *str;
+
+ if(pkt == NULL)
+ return;
+
+ len = pkt->pkt_caplen;
+ if(len == 0)
+ return;
+
+ if (pkt->pkt_caplen != pkt->pkt_len)
+ fprintf(fp, "length: %zu (out of %zu) bytes\n", pkt->pkt_caplen, pkt->pkt_len);
+ else
+ fprintf(fp, "length: %zu bytes\n", pkt->pkt_caplen);
+