pax_global_header00006660000000000000000000000064137055555030014522gustar00rootroot0000000000000052 comment=1ad05c9c4b88e87bc0bd777249e27ef3137da78b iptraf-ng-1.2.1/000077500000000000000000000000001370555550300134125ustar00rootroot00000000000000iptraf-ng-1.2.1/.gitignore000066400000000000000000000010531370555550300154010ustar00rootroot00000000000000# 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 iptraf-ng-1.2.1/AUTHORS000066400000000000000000000013561370555550300144670ustar00rootroot00000000000000Original 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 2016 - Phil Cameron Contributors: ------------- 2010 - 2015 Nikola Pajkovsky 2010 Jan Rafaj 2010 Petr Uzel 2011 Jan Engelhardt 2012 - now Vitezslav Samel 2016 - now Phil Cameron iptraf-ng-1.2.1/CHANGES000066400000000000000000000126551370555550300144160ustar00rootroot00000000000000CHANGES file for iptraf-ng * Tue Jul 21 2020 Vitezslav Samel - 1.2.1 - Makefile: protect mandatory compile flags - packet capture: don't reuse socket for multiple receive functions - TPACKET_V[23]: continue even if mlock() fails * Thu Jun 04 2020 Vitezslav Samel - 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 - 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 - 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 - 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 - 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 - 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 - 1.0.3 - documentation cleanup * Wed Mar 24 2010 Nikola Pajkovsky - 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 - 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 - 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 iptraf-ng-1.2.1/CHANGES.old000066400000000000000000001107731370555550300151730ustar00rootroot00000000000000CHANGES 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 . 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 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 for the report. Corrected segfaults in the TCP/UDP service monitor when scrolling using PgUp and PgDn (or space and '-'). Thanks to Ross Gibson . 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 , Dan Seto , and Tomas Dvorak . Added support for sbni long-range modem interfaces (Dmitry Sergienko ). Added support for Free s/WAN IPSec logical interfaces (Doug Nazar ). 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 for pointing out the symptom. Added support for Frame Relay FRAD/DLCI interfaces. Thanks to Raffaele Gariboldi 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 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 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 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 for the report. Added support for Ethernet-emulated FDDI interfaces. Thanks to Udo A. Steinberg for the report and help with the testing. Added support for DVB interfaces, thanks to Alex 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 and Holger Friese 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 . 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 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 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 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 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 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 (, 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 . Incorporated more flexible compile-time control of directories for configuration, log, and other files. Thanks to Stefan Luethje 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 suggestions for easier processing with Perl scripts. Included logfile rotation with the USR1 signal. Again on Gerald Richter's 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 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 . 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 . 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 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 New features in IPTraf 1.3.0 and changes to IPTraf 1.2.0 Experimental FDDI support. High thanks to Paonia Ezrine 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 for the suggestion and Dean Gaudet 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 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 . 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 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 ). 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 ). 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 ) 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 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 and Christoph Lameter 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 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 and others). Added facility to describe Ethernet addresses for the Ethernet station monitor (to address needs as presented by Erlend Middtun via James Ullman ) 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 ) 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 ). 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 ). 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 ) Changed ncurses include file references from to Cleaned up preprocessor code for glibc2 support. Thanks for help and suggestions from John Labovitz . Thanks also for a test account on debs.fuller.edu opened by Christoph Lameter . Fixed SEGV condition which may occur when trying to close the log file which may never have opened (thanks to John Labovitz 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 ). This was kinda an emergency, so I fixed this and released 1.0.1 immediately. iptraf-ng-1.2.1/Documentation/000077500000000000000000000000001370555550300162235ustar00rootroot00000000000000iptraf-ng-1.2.1/Documentation/iptraf-configmenu.png000066400000000000000000000155451370555550300223600ustar00rootroot00000000000000PNG  IHDR2nzgAMA aPLTE4aYYYAAA000Yߪ}}}}}}}}}}}}}}}}}aaa}}}}}<Y]00}Ӛ000}}}}<<}AAAMMMϛdbKGDH pHYs  ~tIME;wJIDATx `OlܝYE_2g _t^T( "3*Xa/Iz7HZok2ok =^:X皒R7 :S_R/۴{ϫ%9aDe-奯AtLDzSDr2OQ)"C9Ed( "2SDrPN)"C9Ed( *zk z62Jo' Ԝtƭ#2?@aSt>1PtEɝ:fW8\Df28b,̎ r}l)=|k/S? >+:ٕGf/&ca ?!t=܇L_"2{TCf #Y2!KQDFzH犾*l,Cd@&l>=%[|=96٣KtA&l@fy}t;p2k32Gd>0wx^eM zw.T.F'j6ȼy7 H8[ƿBͩ^re^Vw{2: LSnaQ [Nn&2,7ΧD @[VfL^^dZ|22E.Pm$6]2E_y2yq72 2elZA&"Y~v̕$\ƾR>ʤ%TQےY ,ҩf<Oh#x;iBUh[`JUC&Ts9j';k26s+ J?V˄pT2w$27Xi äF!I/SϬߨ @eDIfKL u>]Ivn'Hd7+B6q5q#IZٖ_k:p$2P 2z,f_ }~7hu'{p8LP*!323ci"bR1;vfDqa@d"25" Fi{53͌iGu݃wiIȌޖ]ݟ[(d(Ґ;bF#LWax?Ɇ&4A(5PW%cUQP1 N뼡\EcŤv%2Ug>Zۋ4z/0)7,1n4ݵH"S^yňxkU}GηeNVdCFFi,#KMo"چWQ!ҷTˌI'H1ޮX̘  "WOgdW.<7 SDdXD8Ed\Ȩe GBFl;z}*lK>.%L؁#u2!XTxQ.Ӷ33z'{$Tb]szȍS+Kyu<8wȄXeȄ'e*2-]#,DdVdadg1D]avX0 2N"!2N2+?zn=.i@lח"#g1ȘGLφ1;ٸ0-?,/Nv]ngcu ^}w S]f~P1M 2O˕^&4Ed#7dj]vyB&Թ/T2jvaȘu;ܻcB `~V7 .6B1}]-Gܖ$2N29I|G~Mdabdx"fw5͡y]:BzMḇvg#s|2r*,F([ 9D.[.͓~`? -v2!8`4׿RsȘv߷eY^( ˗a2;ke2w52;2d#,ɼyXϴe"z4 - g"3fE(dr@,d9j,Kwm@@~ W#od jDH&(hl͘ YYfu.0j^&ΐppƔ!^ƭǹYKy^.HCq.C#]G 5q!i V<1 mDX KKб;~cZMqy&=j/D3ZqLiga!3-TS%+8NFF[ZEҸV#^MqX: XЙATXȩ[!ctش3f&'WeŒYw AȤ&5a`*GX7j(@l[;%IR,| ' ȈjN}\5*|ÞФ*3+x y4Khekdd[8`I֫YBZ[-VD9l/?02 ⶐIGSyˤJtXf mʬi .,ѵtNCfh{!3\ dDfDŽL[VRfCJ<4 2VuOuT<*3Hc:'f%K3l+jj[F/a@d"2D)"Cd"2D)"Cd"2D)"Cd"2D)"ӃL- Ks CeSD8EdSD8EdSD8EdSDƁL^9DžwTLe*ǺNj~Q|E!f/#_n2LdB-zfdFMdZ ^dO;V^L!f1y;ϩkP4 [ɉ~J,eI%xWkf&r3md>@>C@oȄzxIN/υ̨׽7BfwB c\[ PT:OtX>nU 9mCp(Kɶ8Y¡(ˌ19S^=="2D)"Cd"2D)81;t”5d=] 2u<2GΘp "s9NNzoha DfՖ|VX<˺r)opN6@F,Ӱ1'HP[8Xt\J}x#? A#AGZX^f wF&"3n'ZGTwt̰݁l B#SnNwᯞd ɦld`'qSyFx'3Cdϙ^fV7 >}Na٣=&. "2{mI"!DjCZ}{^1:[mғ lEfg ha*;٭a#28[/Wrn}ɎȔ۲),FAfnSUffK=4(d%ރ4 &ɋA##&Rƽ⿱E I&Q*e.eyא  w2p seI /1xN6x2Ӯ ܶ_Gm4)7L7JTD\nhz1\HPi(;%2mu/S.5C#X&^*7Oi1̨~L0fLɛ&MyS7${Lj7~1<ٿpT7`ZÃL i 9c?,CғeAFT"i=4Nf)V:`+z>+vY>tg|h`^&/$!ߌLjP= &2!#2$YKy58y $: JWl܋ =[-EdPܖAAAAPJDd!Cy("өk"2y("өk"2y("өk* "2SDrPN)"C9Ed( "2SDrPN)"C9Ed( "2SDrPN)"C9Ed( "2SDrPN)"C9Ed( "2SDrPN)"C9Ed( ?d( TFQ= oؙSz^ݹWhh#2/)̉gCi]+^˙W:K^J(ةgyAf/UEͲX_ʲ{YQ<_(bؼΡlQ^KdKd(Yu_^?Jqk2FgRvĠ /.Y*\Sw2Vr7 D&婲 LzOWx&EPҟ㑩J獲Z{@XPoJB|tA1P+y=Y-dd2J1{38+3 qX\tfʤ@S$tqR]xZPϨ%SUη#^/Gh9, B=EyQ3i5YWЅ TT_]7h  2PNd'> oXCo)p p2 -cY>be.ID=NlwlA p\>'U8?Q`^<덲OB&4I_Ԑ ·}leQ٩2w Hݽeτ𭎌VcVݎP,;&CF_)) 6!9*]S^2G QjciȈQVXfRcH |{dj^-_@EHJ. gL~("C9(>ѷZCIENDB`iptraf-ng-1.2.1/Documentation/iptraf-dstat1.png000066400000000000000000000143251370555550300214210ustar00rootroot00000000000000PNG  IHDR1`} gAMA aPLTEYYYAAA0004aYߪ}}}}}}}}}}}}}}}}}aaa}}}}}Y}}}}<]}A}<<AAZbKGDH pHYs  ~tIMEΓfpIDATx PaS $<,ԽWR!F?BEf_ @ d#(K$QGK2:!ƷM191_\(9qD 1:M&u[#1W1pzډA'e/lh@ 0Kb @ dlʉqߧܛ|wf\g;OT1<36~*+1;;tbm#FT9 0wd qLX91ǧ4(8QuI+1IY,~0[OBȩ%qn ĤE|!8ӈI:;w TbG_Vtb rbI@̮:%[.lQ’3-bĉ{f[VxR/co3WV"?f_b @ dl1M  @6&b @ dl1M  @6&b ~CL\/5d/$x3y1Ercs0Rac | O *c?&&.Ak7]#ycLR:X8]x6廮41o,TӌȯeW~nsN?L d:',&3ɔg|nsVt d'1ɟ Yg1Ȯbs>İ\ =[pE+Bc%F_467 {\0HLcf""/vvGmlb t\0Vgۍ&t1js"5=NJj ^Hɜ}+p ੕ˉ)Pĺk8F5m^ML1܉7/n 9x10($wls:O|{P4VƺtjbxUvI"7z)X18/q1vYˬm^M RZhb[YZuE੃^'b=3wJyl҈b;x?!Wl1IH8`&"ߔ?Q/l!ؒqg:XsjOf1cH);Xs}IiT@.b @ dFL{iN=E걠->:Dϼ_eP GRvo!9|:xŽ1a&ȝ뙒/|;%fvãhpXk@ԦI2b [+2t`ᄫvΚg.ZQG;X8Ž:1 TX;%aմpmǤVigK[dM `Ll>?%VG4T $_a'\eL'J1M f -[#NLuvlx,3Kb:=0[],~]0둬輮sp21#)3IkzC)1EY4[@a?qĈ5:o^ vwĊfWD!^Q Bڤ3:b(#&=<ɡAa8kS|r|1[7}i's11 &X-pkJgy2c[X;8~jL%ZY(@ X&b @ dl1M  @6&b @ dl1M  @6&b @ dl1M  @6&b @ d yϕ.FLFpRKfOއ.C4#no;6&sӛ&XA/ko&)1)#s$31r"_ČS)1W#3b*1vc$eήk,X'&_Dux㯵O؍IoTQ#9ͧ)_+~0yM^(bj"vgiu<7+QZ.yϜZ!IA. Wj :'F#fbÀ&U H/*~tJٛZ9K)2!oȈOKKY+yq[bUp) J2~ 7}ﭬ>CD1vNi(dJ)h/ I95 + H)kc8Nj[E)11VɛqN~} |$|ݢ''h8&b79x4#rreij6lC&~F ^ߑNF4U#]H||cbؐ5-&)P>:Q(e<֌ꔌKn2]LO'Ld>N$Xp@h;Ifr~MVF?1C6i$Ig뙗P!9 .6<,Y԰!/ɉ%#f+3y%qb<.(,YjVP ]F1RHS$C4,Y#<$҉݄C_YDŽ8 pNb#+8F'F [? |ŽJՑoէfcbJ]~y 1z_x.MCw  {VSW~I-ײ<ݖ\O XUD t@ dl1M  @6&b @ dl1M  @6Ȧ+]"O{!嗄>U-ݑn T4bb/Œ'RYww1m@r31Sv" [If]C|wL'hRD8, $i\HLY*<ҫU'[҈HbVK91 Y4.˴ˌcN+- m!o9jbdT"3!V"_(XiH#F.15bCy[ÈOj!eĄհ Z/N #Y58IDWJ!Ab֓[z;qzG[F_ɨRc w1bn\O f\^ĄuwM;G 6lЙ6& FlЙ6&F4]+,ބLn@L9Grөe #&݁Vԉ n@ ,l&m?NftbXW%BRV6O1uLcDZ$?NXBӪ)uadDoDzsb̘i p\ٚ|a! fL5bȏl;-3bZ ĈEVφ1C\R/įOj.|abH##qs*1 Y4Ťe|DprV(jQ;1Z!Hdv%Oڝ٭r˧]:Plib/@QB_S:1jO`F12AbPXu;bsׅmc݈]қ3݌^9a:Ӄ)oa&{T"&hs6Q4.x81PY$7?N>y fs4$[g}%M͏ȕ]vޮʈQ⃼@ dS1b "1'/hgn@6VIX z`5%T1yx0ʈcgC9+ *J?Q b? c Rw8#J򟯆^,@6ȦΖIENDB`iptraf-ng-1.2.1/Documentation/iptraf-editfilter.png000066400000000000000000000114551370555550300223550ustar00rootroot00000000000000PNG  IHDR2a]యgAMA a PLTE4aYYYAAA000Yߪ}}}}}}}}}}}}}}}}}aaa}}}}}Y}}}}}AAA<]0008Q}ۚ00㺾Ϛ0<<AMMM'/zbKGDH pHYs  ~tIME ;IDATxmr8C[pWq&if48B_\f̐tȎ_2_:|+Q~g6'͞2iK̟2w_3/!Sn(Gn.JiX{QsPgbKpc/?nL(_ @e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@e@:B3z3y]eoz{h2M|LU䱴/d,I~j5}q;Ɓ)g6ejk:0+e~S .+3Wsߟ۔߭֕Ny{ۤ]K2_g~6%g6\FHT?4ez ɗo2պi|C\uD=w[_LovqIp-ni(27t4[eT]{Q4Nɟe ԕygIjhL&ɮ qBNCe'_[iIW~Lh~Umqhim2&0'>>>l*5)D2=SpH9ÝSf^5Ӌ؅VӔL:;VZ*SZ;(g&$U_aSr?2*DΔj1T]4kJiYܯ-.xPԀH1AeUjc%qev5B}F:g܌`n"ʹr]-uYy̩?T*އ(Wm{D96hޙvlx2˜S& fMNJe/CRgs@#dl] N`KJ E *5CvKm:+sJe!(SϮ \ԛz?v Chu_#(SvG)5`3kc6-J[uM.,@^HZ? >p tm[ 6u;y98Tw?tDpߛpQkS`cv .?̷.̰̺}[SmGl}\l]TR+-8/#$rSE#uD{f'v͔xO7 {9UWK{qz_>CwbCW7 (aqqkJ&/Tv3ʄizWʤ=&JejtERg2e煺I#gJ}.2! ɨF;jpn4OGW*S;ԳkE]g{aMfv(:R*Q}*Ǖ)/Ե_aDr'ԵtyL]mZϤBO$$~m[+mv vx+l֔{;^;'k]XoAo.dqGJ]( ׼ kh0'y|7>/yۥyY>[]>$¯`+49m|ۅAʍ% 3Z:ԯ^QpN^M{)ie4C+EeҞWꚚwP8_)ei um I Y8LLF}6QkuwQJ/AP[8^!t}79y5Sj(:R*v|Ǖ)/_aD2oo:z j,%x=OզzyhLJNt$/M.[5&~dʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀʀHtR sTq2ap&!Q潹;2}e2^o>˝lvE w+xN(3YWfˬےWڌ oQ7(ӶLEtw(Ӫ8}Ȱ{}YKl+ e1}Rf;e);U5 guXZ[/)ʀPDPDPDPDPDPDPDPDPDPDPDPDPDPDP0>fM{ՉFW|{%{>@8V)38z:O~4uxLm|?Lfc1ycB;nfchnt ͹X7e+Rmogf`2^嘟focaqɭ]C]m}llcǬ ɕ_\J4ؘU&f]TXѬ5觵qGͷ|LH=ej]RƯ]QYJ9*e?ˤi)q1y~ IdOU&z;D7$2qrdݗqJ)KwM:_lO*u<2 z+S&^ |cizӚ>9zQ}q-7e5πqk(uȭ玚]1(3-U&Ǔ_-oeފ7 skIAAAAAAAAAAAAA"L:9F|æX!k5J/i<|!IuL9c#ܜa{l*UX} yp~|QmS&i0wW{osYם?6J?'2c?Ld eY';@LGmDPa&>~kaqm0{PvMØ!a~ W]~mΗ}&hCo)SܛaT׏{p&cUl(GUجevEw}hjg?ٍL.M@a"I#<\1'7;fɔ7)+{Ǽ a~7 D ~dGbO!z_ݨ̼7LkoCǐ՚빼#\Yzf0>ym=zrTPie$c<^ȊIENDB`iptraf-ng-1.2.1/Documentation/iptraf-filtermenu.png000066400000000000000000000107401370555550300223700ustar00rootroot00000000000000PNG  IHDR@P!gAMA alPLTEÂYYY000ϚeÚeee0eeϚee ammmeMMMA0U󲲲UƺvbKGDH pHYs  ~tIME *IDATx풫 @?Mw2J7n=MFePr Fgm~(8z}?dTY/ AĢv`I_7vI4Ԯ sǫUZ+h)[ B0(TnM.G#p!`P `~;, B0(  B0(  B0(  B0(  B0(  B0(  B0(  B0(  B0(  B0(  B0(  B0(  B0(  B0(  B0(  B0_@zi/Ct!^ZA]/eVP2DK+(x륕TOd/EPЂ ZPAA "(hAA_-(苠}/E2_^tGx*Lv(KYpo߮U} ʐ=c 2ג0%x<~q?AA_Q  rRbW*'q}V3SkFP)7/Ң :BPAA "{Lؤ nPpPC.|kT&%刾~WzFT@A_ : "(hAA_-(苠}/E*7eE϶&\;Qevֻ:(X^Qv!TOS; ~b|gSe+U5 "E%vΧ$糳*q$BMA;lkS2g'LܲϺ'Y5U=. ~-)l'FMLS, RH[AeBC+X1G+hx%4-d4|/Q9cCBm#.HL2v˷M_T0fSc!}dq\I' )a%cّ2>( AxEGWtpJ? "(hAA_-(苠}<' ‡|Z(x8Wt_5dYS' 3JYŵdɋs>O_$?IdYwy̘&MK i|O* mVS%aFv(N@WH]@A]'` /x|vXuQzB4T{ZAA]2BHLR#NU ]Mq}kլ( (hj6Sl3)حDA]gV4*h͛\k;(Q ٯ}>Һsl,aAA]b WfB`!&yLz}E1+(AA]( @AwPP @P'(5|LyCdbmS~j{mʹkN.Gԃ$t?nc~; C@A]N_yFkQYQp(X/ϐ} 7=a'O?E1(֫Jl~ @3\HN\Eqk{ `OP 6=AP'(~g*Iλ7?;ɝP(bi-uՇ$SYT0;>E11*8}NOdIν/?;3^FZ~{nuQLj鉯J~Jsfwe.xz%ſ`W;J R/K٩`έl8 |x)ޚ2 VQVuQL3 &.&˩uQL\IAs=R#>YQat|nvkZuQP ` 6=AP'( @`Tp;*=?wğ秶t1sؽE1bova<SYT0 EȺ)[*"|$Y8*83AE1MU%6?\mZS y sXk[٩`Ϊύ) @6^ohuzVGUP7o%(F]]@A]#V0S#lTP?2E?_aYQpw~f] 8L5=AP'( @`(l{ `OP 6=AP'(+h# xΒW>OYʧ=9K>\>Q'gɇ+' ,pD%|Z(ؓÕO{r|i}`Oq(l V8Tl VT R\bg >]MPaLeuFt / [-vѮ\Sw7((û ت`ݹ *_ &n)øN]竮7hU Rj&)T5 :RjtP(((HQPPБBU#FAAAG U)T5 :Rjtd,d4AAw[ ZPAA "(hAA_-(苠}/EPЂ ZP1 'xP`zg}1 E nYO /+i= H\[I /R >Ao2 'xaPݔYYO /R5AA_ : "(hAA_-(苠}/EPЂ ZPAA "(hAA_-(苜i=8%^ZA]/eVP2DK+(x ^zi/Ct µ@A!`PAA!`PAA!`PAA!`PAA!`PAA!`PAA!`PAA!`PAA!`PAA!`PAA!`PAA!`PAA!`PAA!`PAA!`PAA!`PAA!`PAA!`PAA!`PAA!`~~nw@~oGmTyMgޢYL ѐHBY\P0S:O~XQiUpy,QR0PcAvA4]*&~q|%\m;1iyHBS,CA; {Z~& ?>dáa|PK`G-B/;٠3lO2%lyfNep'fm cUG /Zr񹂂JA$pl$Qpz׋5sܞ_o&|ȶ+3#cl~$t~8R+ziX^S' ij*Ɲq$~>t&g{rƸeUզ_oljeMsc,,nsf[3i '= x [4쳏aobEǭr3Q7Bg0ܣU'$뱐4uB[E`%Qv(evJ.ETy[$muG0eVrwYM*/fy/+΂||`CcʹFY)Z4vW^ǭO6]ZDm4,[P> __FfYP}1+(?2>ͲDիr-ӣNCv,Q򃶻z!W>XQ~/?qXZ ~R9Ҵ8J,z]yhqo~{套uT4 =cKhfXmBu}3c;.׊|uJW8Z[}Q~M.׊GV>c*#@e2TFP*#@e2TFP*#@e2TFP*#@e2TFP*#@e2TFP*#@e2TFP*#@e2TFP*#@e2TFP*#@e2TFP*#@e2TFP*#@e2TFP*#@e2TFP*#@e2TFP*#@e2TFP*#@e2TFP*#@eh%)dW,W^1H 2Ml[*+p0b/(wN0(߆aP:,YL%m: ifqQXJRض-;lO Je6CPSH%7>\k*&aed)vSj %Ƞe{J4Q`D_=msur S{z/kISXru5, M^ Ǖ:ݗ'r;ЫrQD5U6bʋV C5f= ʋ6Qѩ 5|o=׃M6i+\vČJ$4W-캉{ʾjNK.5OK0[Ka`1e/Reuvz;}%Nnaj *E~.a8T V*:䣼6~,|͟X+PϵiGk3_F9D0/ʶ*SH~Uw:ʹSUg(c:QV~x_yIjgV^ec=̎7鷏yNnzWKk*Q6?vS9hFQQK<sy{mӏ&ǕzYJiΟE^̔cC 3\:zvK<.d^zYkf`4reQgU\;됲xvnfluS1tR'[luۦL6xb5*eˊ%O{7nޤB@YVo]÷&)FQpIENDB`iptraf-ng-1.2.1/Documentation/iptraf-hw.png000066400000000000000000000126351370555550300206410ustar00rootroot00000000000000PNG  IHDR3S>`6gAMA a-PLTE}}}aaa0t*xbKGDH pHYs  ~tIME -V IDATxIګk U`rj 0kXd U nB7hhd|da qӑfUbk4O hy@OgS" T& כfh[;Tk:::T4M>N;'r{/~IuINCɅ v֞)ͺHo+ O.>_KO0][x{.~:.--^S%csj*/˅=K4!BǮ.މJx7AUSm7gOSMBYznR*Y8}JBSmJζ,иa&QKd/e"jE-S&~Y*h^I5hu**=`29;%''WE :*:eO8hMf?Wv*^Wh|&]/lA0\bA2NB(1h`5o]Z>1hv>^6Wte{b4Z6I/cѡh\; >j4!51sl/5mfh% h7}H,j_VCmjEW cM 5%xB.NcM١YluCCpx͜vʭnf.)H =-_:j40粎FhP(Ӳ\@M@!P]E898kn̑.1&@ 4Q+q,?J//b'넛\L4*U%b{zڒ PѰd4b*×?/n4v jӥi4Fw4ԼrGٞ[ij]UQm#rB\ R)..8JT˙ձțlm(ښ7v!MMR -{|6DaioAKZrC&i:VC LKIN%TIciBW9,7Ш=*o5/قfsHih?aYDcdyc-^ZW(BBׁ7Ѵq>:`w(52 .W3/޶y_S5ּI(fV*-}Լ[x? [a =ˮy_::>y4ɲ MyY<";"O_QLZR:k$ߨ,pG{]1^5MPЌ9Gi 4̚hy:ܽ¢}.h4=v.ޖ(6 ȑy;hgyé}b@]=uo"; s=6Ji7T,x7 !Ez]m}=4мh&8oR4oRQsk׵F.ѨN7h⼿,7$vqqߕDȤW59ZbrE4ߓ%4 KmyOnvn4vj_1mXqތq*rs(49whySRlskޫVSÏԼS7 X3APOмS7]9k״F.Ѩv-6I{;;@4 l?罭T_ewc؛iv65+4G<́- tE< lZhYҚ7JQ>5yS@ ?DP7׼8ohiK4uk׵FS 簎Fyo c0Kv86:0mm&Q@{A׼&9l<;М#hdye |B8hYXй>qkBu4u4}AN]a+6I߬(sx=.bsOѼ$%2<]PcVꞬyyDcc.4.P'7PӼ!y4oo<{ By{5+XGZG}hr䳴/>czыx0J#PS.&4.O@6ǚh9e)d4!75.jXsUqj4S7t / e! .*l2#6V3-/qXU53/Eb^LB+W~I :: & E{ E_ jQQ!⺓? 3߹;wS~+Tj[fFhT [ j6i=|s|?ӝela^Y<Q[u;p% ͒ 4>Mif-, GEU iml?{tޖű?e%:^e.EHK iy U 2QcAg1=~jBqAl1zNͫiK4؆ŷ݌ yn2 oH cRg^'@Cc0kv(XT;~ $y|M 9X@  4s^e4yu{ȏ nfS>d@rz]2V*"mAa@4 Y`+ %i]l# Sl@U{lj. AAIENDB`iptraf-ng-1.2.1/Documentation/iptraf-hwsort.png000066400000000000000000000230561370555550300215500ustar00rootroot00000000000000PNG  IHDR4USgAMA aPLTE4aYYYAAA000Yߪ}}}}}}}}}}}}}}}}}aaa}}}}}Y}}}}}AAA}A<0008Q}ۚ00㺾Ϛ0<<MMM00ee0000000e0e000000eee0e0eeeeeeeeee0ee00e0<bKGDH pHYs  ~tIME 0,ݔ IDATx[ |@99FTZUMڦ  sp\.-\94a14!:%ɖ/H{ЩmMAm;rh~^]< ysO^]o"lTOr-;m]!h{rp/_kװװװװFY꿛o&V莼P.+lpAJ JAs.X {ٴr ;|G^Mi x=V.Y1ugޡЬAK@'UjeMH^ ȞD (tJ5+nC>YEдgCS…Adt pti4邚Zi.ءY¼4t@A\"إkN(ZWeTsA\M4]H;j/bǢ SaVL;/M2cٔB=]0 `//fvEv5M3д]p 3[)4.TR hD-v L+ U)ZifVں By6Ol1L兂OGÄ˩ù.[uAɊu3м]И.xh\CV fvvM@ܥFhxoZېGG!#)HiqWZ{e;lJ(Ci(;Kfʵ ǡ٢[`RJr=5H֜$[Nٓv:Ց4-J=9!K\JVllNJY_ ǽnfQB/փrH .P>CvtQ.XWr۴WMU]_S^g=QRCP Lԋ'kL;;ZByQ-L6{L{´M?Cb *^ nl |14a+*>ji> CAr~&(Uzh: M0]53 M8D)Д.\hj**WF^ HbLy´*VhD[(C߼ w jfys4ɛWBy;.J55a+2fuxR] j/5,5߄ߞWfS%C̉U 0f8`(biE`Z[ݓZM.V0Q-BeINдdt‡kuá642{+  )4^,B!ɴCk j݆&,T b-4f3eS%*48 Zv h lԥ㌵{ UJsE#e&̅ 3`^"fЃ*/ýP-|0KwI$[T dpAa7*s  `"% k ~^? *if|Yk\kX'@#*y+K hdW дof|hBNy 68JKs2Y2M#ΛVܶ DbrCCoBa2SJɮ4gDM1m#/"eUMԕ5;`[NG~-oehˡSq^vIA39K89,6Ϛݞc4eT^?s̓^ x4pDֲq \d)Yx^+Y ly7*KCE@?R. Z8I:A5´'ChuHS%hj#hګ4Q2eДvk(Pvѹ3rg{%_pbmҾA]OPȤ`Ι 5B5vDz`@5c_ɹQ_ 7{+qzzNe a.LOQwO9Y8mVK3WTGe W9‹~^? wW0r[O[y<͙I|F)I};鞃Фǫ5y:l'WS;uw"_ ^ 'CͨM˚Wćա'r2h5qq+ضe = Zr4X]sC#VRFO5pw-2 cCCf 5Gy~ضu@3.1+f+Ǡlhp4cZfxL@9Е> ͬܧqpnSIhrn σfk{7 XM_Xw[tvKph?%(94 EFM;chX AF`hš1Ttck랎X1z34AEz1ahYY [A+uh"R{n܃XۺoχfM({[7s*4{џQ d|N|4;6 eH/& Nn}'{DFl>Z6"@ wJ98x4L^2k+84C44i*Y9[ R1S2N UGF Ʀ9444"! >2P(4و|1tfѡQj@˵[FSJt*y#]`84>05O`pQ`|TsV(IӋΙU @#Y 44Ɍ'}If) ѡ9 R hC,'-@<4huHS%hӁMoKc֡PFh>X]#Pܱ)[{%HnL{AB֪f3I2;9(wòýh\C4W#|C4ѝ*K{Y=cdhU^kb1#4g,a9d%Oq@)BФ?j4aYЈ+cP͠\Al@/#+xjMC^R/Qdu/a9 cY+ݸKrˡn(6JtHEܛ4Ikn@*F&kn%xfu͂M4W/ccEsnKSYƲ}WQfRS|Kaf:4u#3BKhgAcwO?h~І/PZaYpH;Sip!sF.Nc˜A<]i3rg?t+g<3rס~iۋp7kY8 |4s jij7P7校c3hpSHfx),ay4rd;ݙʮYsyڦ>}-wĢZGO_mB b[4-wj>t]_huh-; j4t]_h&4F^٩4fiς-_hܹs"٥{Qh_˝{EqֆR21{|_hFxG0]rh+:4JW.a Ea4+;Xw7g'OZ"emGL{qwro 2?xJ֚7σFJp^а/_a͜c-ۡyӜXg)-j5"/*4Ve+z#ýÍא l~́~}rå}a++,fpLCZK#r[I7Zqhf`Y4l ]64RF<=M^=ͽ;@8:r64 4#kӼ,w;~;%O3Q+Z@xt-wn]j-{萯>x'H-S#+ K%(1dN,/E9y 7$ю<]|AYri牫M_ Di;b`7jpiv]ҟ3uBV#8x4l4X2]`h*[9$?W)XtάFp !b1wV'r0qJk-1H!GW>@цfYX]l MsL#k!ۋ?3smhR/D4uա)v{zM)> BIW4nLso.[^hR 2\)_ˍ0|o,:IḢCPthN_mRɡi(:4JW@sZ}Z{M{j65t_^֣ݼ4SVp*nDM3SuCB~GtZ3ZyKX~/uva+ =<4AhrK׿ .XI&)iơ㻽6uZ;>Mg$rC._d"τfNyrCVN&tB7wB}kQh?^Há7E#E᧠Ii&l04÷Gz84oBԍk&2yUr( MKMC_X*94 EF1?%sby)2Q΋igG^uَӖcdY}ֲ\qZUOć1cR9hD ˵]9搷c(5̃|{οX` P6e&8fLhjmzwMXeTM<.:gVic?4mCѫotO_]O[ QRD4$ʻrxrWc7uA#eAs˿!u8)gd1K{{zBS(p?teh,SMn!^q,fΨ[S{¶,݀o,7𺘛_Yr̀e9rW˳.F8Xnɡi(7+&_U=/,F(A˺KoWG O-y|&_wf(4|ZV#tz{h^L棬t@'[ xT~|n y/[s9 hχD<+B?1#(ȟ?"0V 3&4^hY "CAZώ8QxxYC^h(Xeʟ1BMAx6%@r?͟F2SVXܨ- \;nkw,AhdcIҊxm-5 {{r349aEowBQ= Қ/,jzj9Vښzk'j!ѯs4²OqEFM)EVdN,/Ey9G11-N[vh 1t8ǚ&nq<رe؞X,hh^gMmUAǦ\^܄dX5 ЌC֎:QJL@Chpd&}*mth1^'ftK 4<4f!uiCs@цfoUJ14sSШ&ϡ9 <'+ц&,2 milѡPFdP0شIA) @dH.8Uf7fK|{LL+g{P@@%(]{%(] AIoyXLGyrucb97LЬ/].cP'yZTm5@M1 lM]-5@3;4}4&x;4#dhfr-7=.$)SOc=r.hiHҠ [CSw>qh\rh\*AcoɜX^sԭbfّ9EAvc*C^{sbMn$]Jol8楝H0|[j@h!}۫Q\P.BaF$hshJiBL ܄fKh՜_t2ʠɁE*)^2 tO*tO|A{t()HC BȊCmh?F=Ѐ1ћr %.@<Ƽ) {Fr-YZP4c/P&]Ѹ252b>5rj>۫+9~mCD!gƒFp ˡq 6 _kXA ?sJ&n ^3ܳO}SScW]1+W~+9C$hi-Q1&R9e\veF;>#4%C3V<^X \5o勠S 7.Knww- gŻ SY-dHBL;=]agrCCC U_fVNFY?EIDATkWFQ}Ѓ 1n|A9}qdTA3844cY0i>gA>҂fܓ64ӊCqhZ~Q4vSlAr4Z5 - *7pzoKf^5LCR=fU4fId,H6*Zmh:.GC=Vl)[SSO̠.ѪYlR!DJ*i2Ac h C|X$rp-lUhO, U2؎GhɎA#Ь40^'p'YF1E|';dޚڄCJ+Di*r>YJa嬖lu0]dF֠!Bm>SgBWm/rGr i -IENDB`iptraf-ng-1.2.1/Documentation/iptraf-ipfltdlg.png000066400000000000000000000212401370555550300220200ustar00rootroot00000000000000PNG  IHDR2 pHYs  ~tIME 1 IDATxP|Du.so頼<)L./Y0MS |W B2tǣ0?W麮~kx,/OږDrC 4Kktzk%w;:]d5=?|y>,@>ǐc&y88=6. ]UvUЁv16' ВH -Ftq߿Qz<sih4$@K"14=].S@KŅ=k4ޘDI)4gju8ǂcDbvfڹúw4^] @staEpp>Pk?0't>ۥ}b t9jͱtsv8λh7|vޞ4D>cۥP؎[<Slh85cֵy+J r{'>:mȂEJN!C0[c+l1%jq;48A@CvJ$bKts6nx`weTOE qJ6\`sOQkӘӧˑ~ּH gN@K"1$@K"1$@K"1$@K"1$@K"1$@K"1$@K"1$@K"1$@K"1$@Kjnh3{(m>1z'K˷obNl9xק80h?[9Tt'+S1}fkxؼn~fœm}O, &RtcIW>'dt2DlX˸wCZ ۳BN1ck>|+_~G'+^|]=}*ڱOx 1f?=ʎ}<|ad˙(=϶> ޖD&YJ'JC]Q^npY]_|y;!qn]K̮n}j?:=V1 vc+= m}83|iqx/urzi B暯{H\i1s4x'DݙwG`u Noѷ;!4\Khx3m~%8vm8&_qgr{gFb>vw;)7: "@K"1\܉@K"1$@K"1$@K"1$@K"1$@K"1$@K"1$@K"1$@KOLW pK=O -?]}K鷪;;|>ևgoBP.zޛlQ|.fg[C7X[oc'ǎ_-n|d&v}{ '^}ұ`qp2\8·Ks_L$S\>~7?r{g7Eb>vw;)כw"@K"1\y܉@K"1$@K"1$@K"1$@K"1$@K"1$@K"1$@K"1$@KOLWٻ}cޒcc |2u?qW}L_cs-uXz_7[,ZM{4FaI02cknczw=a=r-%O™iϟB$Fq/x1xOAXy^ߝ\~>H= 5h=IG5=x NkɰCғ#ixxc2Ԝ;\)gvڻO\Ӗ]C{t?ĉv|k1 l1o?Z9QEbnt>H -ВS32Z.Z')Ա_ݺobI,W#ERn_\uB[Y^>P;vܾk˾\GWiƭtb{=l<ݬ:vΛeُ㷂Ly/4͌C=h$cMܩ -{si卩?ck>8}Jby:g:C;YTy뫢հLji۫'ϡڅ;!:.Z496yLdv!_*KMwB"ܿs^Z>qۯ䫷2;O& l _6p׵pw{!dwb`ܝ y46|O;M|M&}'8]$:;`zŶ*?Ĥ Tc8ɰVuz{rhJi3OӪzq“TU+)nyQn.Ĵݿq~ܬ 4W/o8>'8)=?FࣈВH -y>1t,7='}bhNxP?86%64PŭﺡuN U <|\Af"gpX@:I;I6>Ht/FwV?<Nc2qn6j.W+}t9L''|o8Ҏ3bqtڱ^' E `-'`lHd~pbߞg Ž}=BIPu 9Sd|>8[3+ ľO)?ҏGnB<Rx1nw|o{b'Yy*b=w(}nW2[99sO^W;~kk;|bhq)gv=?R*Y+$!z8Vyc;e#<OX'.{]/򷻮]F`O?V$ƥNs^k7hcy)g'`%s;5|*2?/7N5w-W^~_ >gZL&M+5iuUZ=*}۽F_=~J/]~B[C _'F,rgѰ86YP` |GiKO+oQn}>~ω[yyO^̯_5}B1Wo'r]eRn{^S'vN|ђ=GtlM+Q[ (Eŵ3]p\UlNKO{[znIoXޫTT,zSBct"W1I||>j<.9O f *{ls-ot /rMD[v^/Aܿ/}Z==彇}bhI=Y2^>kX^=KNӦ^vcYZ'>15 g9}uu穟v{ l's["lBCFi~@mETammfkl{&nJ$ZGZorU_V;I׾a8*rS.mw`lt:&-` ѪMlښ.tHO=+].M$_rM:W7]tblw u.q7W%6Sgޭu%JɫWN7: Lmwhu<J\ɏJ˻~VsrC1וwqyOe206F?Ng17x'Ϯ.A>zR7;a'̗w?q?Y\r"KmK~bU1Y?Dw3˕Uv~TǤ8kpg<CO=N 5 W7wE߃v'>_%CjrJm**"1<Ë_&&r:2: -ВH -ВH -ВH -ВH -ВH -ВH -ВH -y>1DC\NOO -ВH -ВH -ВH -ВH -ВH -ВH -ВH -y>1uDO܊v}cx~oO'? ~|luI$a|1>L~y_̤6VK,?i0>qtno-z(=I}5ӫ6b;93cf>6i9~ydqmkYV ^/ Gbl8M3Hiy+9V~x8'm8'WrO|p.M濖z G_K83~߇K'v<|R֕7%ZQC.pfbZ}H:q`$_K~=#jv!~(U 6 V;n'NGasrz匫TL-sS[.ݏz`.lWY$\ӭ9,iaymwZmxcy~=O?ޒ7%!1M48=dy:jq:ߑ e1?SZc2]GrI*$uv;7#bg]OI'm{;50]9{gFbii"A;q#ipgdL88~HL s`tZ%Z%Z%Z%Z%Z%Z%Z%Zcˇ_dZ\9ήhS̤b1.n_g]4I-[~kV{6-t\e8ߟnJ?;8am< |VDٲCs\WvP {`sfh~zOx>kf=>Qb`'F'[p.t3Jbи:Yg:GI҇s {x5YN¸P9S<ߘty"9r-q `?[B^k`P':]9:QIM/9bxcVp].wd/(]IGDR||1S-e~M}o{ySߏ3Ŋǭ~"wVK0 S c%H&H=n ԏNUºtmb ֚i(E7[5qyѭ\&jǺ|$nxsҰ__^K~Jh23ٸ?4j?[IC,9 :)<7%HJLO ~$I[;{$fluAӓ5b2w:|1^ػ5X?<˻g+̝c 8{i4k]~O JZ%Z%Z%Zs}`HpВH -ВH -ВH -?'+b8>1$@K"1$@K"1$@K"1$@K"1$@K"1$@K"1$@K"1φO -Wup"?DƵYuM*-WFҗ9ZZ9.׊q&-h&QZ?'? v*+7>wi$WUB>ާfp-?<:3fz"F32; M.&_uoMOowh0y'nz,ox{yqlt#i̭Is0?맴_]} 7&yornIH+hϴwsUσ)83*Ξݠa/2|JK֙?6yl+{[a,Ɩ'^[Pb\H|=,n%SQ~j/3G98;^Kגp3IDATX'Dw(}Oi=lXyf^U곉}E 2g>vm%]EaCf_sݶG{\0Pg~Jw?k-vknV3a0i?[)vs\Dϗ,2N.v9s o%6[?q)Gp+)W'ҹwyKC~_TF_T;{9ӓ5y{K5Dsz_Euo~;^9G"qQ贛)`\'2ċW>A4?IENDB`iptraf-ng-1.2.1/Documentation/iptraf-ipfltlist.png000066400000000000000000000101071370555550300222250ustar00rootroot00000000000000PNG  IHDRn+ pHYs  ~tIME_ IDATx=r8PzʋlauܡB/H'i-6ʙ"OΩjA 9f_*1=/맧G[ߺ@_ۚJf5\Y8b);չ_z4&^>=>].T 6?KF}1<ݿR 7qeRӮZ1Zw@<<>ZU~ت|Rsjy.[\Zlϻ/aW]^}`jؾ٥)l{4/KK|XS0>q?fd:RB/c{:/'IdzNv:f']kv."f}X=,+- Fϳ5;wY-lLGuaj+75n1ܬ's[\d6䮺Y4\*t+˼f?IT3"|-LKgVD{W/ſ|{D?{/m0?^v\ߦ~#ܭ l^}yNgmFj[K&y-֫' e~|<9 'oV0Oߪ}%KU~jTx=_(9u;5C⡲x8sFcZyoMéKaZIXjX`ߺByJL\mUkӸۥdk{Rp*\>= φy}wTܠMgh[U͂&[O"[_#KgZVnM%&_z /t4϶|:6x a+=}?<{iد_gjʗ+vHt[ Oo}(lveֱ)_{4<.Ȇef7̶E_ν?l~n5tj06Mxw F>Up\P #C5k/|֮W*_XB,?eÇSiD aeXO}T:t^yA t~Z|R?~<|P^!g12y y*{z O@<JΦ&_ThgWO))*֭W'[Xa[4=f׳;->jemt}|Fraa82JV^hRyXx}\y3 5BmmvSy @< [4p+ &puuy|SZZqoxXtt׮~xMMW' =Wn<6ҢtG o{VRlhZok/7FU+SPhq8 MǷ|-|?ôvMV]Gkvsp{~g?69|_fT~m޶:_v[L+Lz;wf]\_ [XgӵrB췢y [j'W@xl~jR;o?SzaN6Yb޷|Nҝڦ}d?L.<_=*YvvL[a֬/n \zaky}2=A-}9,?6?>kxux1PoUqFw;`ɪwL]fJ+c=v]w?3 k{-$RIENDB`iptraf-ng-1.2.1/Documentation/iptraf-ipfltmenu.png000066400000000000000000000112001370555550300222110ustar00rootroot00000000000000PNG  IHDRdgAMA aiPLTEÂYYY000Úeee0eeee ammmeMMMA0U󲲲UbKGDH pHYs  ~tIME FIDATx흁<@};d}Vm!MsU*nz,z 7B0/IS 3z8o!N;E=u0|zجVRa:.lx~XJuhpQ7܄9  hpAA!hpA!hpA!hpA!hpA!hpA!hpA!hpA!hpA!hpA!hpA!hpA!hpA!hpA!hpA!hpA!hA&)8xSp:D˧uO/!_>Ct|ʗ:1d`g-8A vFpЂ`g-8A vFpЂ`g-8~y|<>MN9I9<ďLjخQ/p3½: vFpЂ`g-8A vFpЂrիYvFqڜ>8.87}=z 4u޿PNoQ+/QRnW9h2Խ8YqYrk]ATqQd0yƲW:h:+$j꼯> lLrBAGA=YhvhiOq3rzPc]q8f[\?{NMmS7ƴII|$I;Ps ס9/)+vrŧvσ`g-8A vFpTlOlOlOlOlOlOlϋ8!bikq3[7NlzNlzNlzNlzNlzNlzNlzHt]Fq"Ա09tOJOۺ'/6v^ܷ5Tsp8UeF:oODÑ=4xP:<Ўɠyb ۸`ҋ]CCm8fcp9oϋ;x{E&JY\B]=]bvqGwSA1xqڟ8 ԱPXUegtqp|巏8Qt& OZr;V75/\y`7W'8c X:ࠎE : :n6q\ /2ov5Nwrq &X0~mfOs5吇_]] Ox.; /'3JČˆCkLL{7wӂ4biGd8AZ88b%Zߟ\^,2tTU Bz5'1割>n~&XЮwΐW?^,Xw+/4뭎țtb tb l&2r`aQoc^ߒG /#>N[cWVNe÷`‹Hvksw`‹Hr___: zOcA< Lx t8KEڹ},8b#l_>\HύyQ`‹Eܫtb tb tb tb tb lfK ySEº Zp0"S])o`'^XU}y Yt`‹EnRjsP  8-xȨϿs0818x|A &Xd`~񄽧OLg`‹EuZV;8ل$Jy||b哳`S8˼=/|BL4bq 8hF,p8hF,p\&pp`}/lqD!p0!A7jh8u9Fp0! TCtq*?oEz E|)4}kX>C`BP}`(ppbA8sLk329p0!owżXBå;;pE;;M&pppp88 DTb8:1o1 Lș쓷&v[r^{-F"-0n_b8\[rj-F 9}yQ`BNr?K;z 9OߟҎ^`BgiG/p0!8HQ{].K_܁8;p'LHࢼ qw*_${u|w^y{{\w^Aa-{'ZO\;^;#8hZp3;#1o8ؕ1D˧uO/!_>Ct| ^~)8xSA8 D B48 D B48 D B48 D B48 D B48 D B48 D B48 D B48 D B48 D B48 D B48 D B48 D B48 D B48 D B48 D B48 D B48 D B48 D B48 D@p/[~^5a/|޷;R=f:trЫհ({[[o`[~StpivwU8:D98>U3/OS>T0hHnRn owQ4~T5o8υ%q[=Wo,B iTwN55d R'IS^o;gRji|Eh'̼pv^,!4ՙ.8hZ.= @4 VCIENDB`iptraf-ng-1.2.1/Documentation/iptraf-ipfltnamedlg.png000066400000000000000000000104601370555550300226630ustar00rootroot00000000000000PNG  IHDRDgAMA alPLTEÂYYY000Úeee0eeee ammmeMMMA0U󲲲UQbKGDH pHYs  ~tIME *y*,:IDATx݋8a/cTMD }jmSۈB@:0k9X |,] o _en*X р ƥuCn"p^ vGfB*Btd'! E"@H ?B!E"@H R)B!E"@H R)B!E"@H R)B!E"@H R)B!E"@H R)B!E"@H R)B!E"@H R)B!E"@H R营..ۥޅz"PoBxRB] ]KKa`;{!Zؒ#@[rh`K-lE-9%G"ZؒK lol8`K.A &Sn/Kt!\]\" un|v#tM3}>O f74Gzaz] (`>9Mؒ[ft~> PL-]oA-9%IAwux_6&MA'!pe~kŸh[!oYؒ#@[rh`K-lE-9%2~n-hJ_! 7\٧6X\ 'lcCrv;Wg Ep=ŧ7:g>8-'X}e x| .횂̨It񪚉Avxee`3@3} ;]2~rer܅[??Q{nmwf52cvzt`K;W%2Lp̖^OsH3j1`~$q'{A $_U1\H3m~.9j-/,8O4_LγsJyؒ#@[rh`K-Vݨ`6xV: :fCgkY`6xV: :fS5@}qUsg Ps~Tdؕ""k!k!k!k!k!k!k!k!kS('Y~s&  :/ËvGd.=y vyiE G,1$@av!A%<ֲ?y x$$#tCAW`-X`-X`-X`-X`-X›`&_\_fQG"m9}>37gSxv` 7 po|6ġnŰ3|?"/ɞ,^ӏr 1ssK<>w+vrL!>b`rEMV'83O04 ^cu}.I.m^GL͚.6^ 0ހfe~!i^і>`Fm.13?y;G|+H(\hG%`c `0]f4@Vqt|oW~p^ 0sc&>L?LNon#lhyg>L'a_ VÜX ?x;;,{ Xk*|t>6W.u%rgge|4@]+?wZѿBQNyy#2+quptAu5-Sx[.nMkWÍA7\[`(ozƛ\4nG!^Wqչw=>xέaڽ#L` 0> p /<`Ќ87kv{EW >\ e%@3[`côCiXoa6r ?ʵ||\3V7dS<ݟp^^8ʵ5_^>: 4GCpx/"%|t>X X X X Xxj{1ө9No>"1x.#'ZlӲGL* pO:` O` O` O` O` O` o; 炞7]|V'%9,t0-/YNӳ}o_+\\?w|w9"ߗ`F(H_.>i,7CH>|8@!8nqoo+pj gt?2\V|i.vqeepgFG`|$˗x5=wӥF Ek<mW9=l< i`$d9@OE._hücg!r2W!,Ow ??Y k+ %%BO[$oan[q/!"6{#{A%<rkF'D%<B%<B%<B%<B%<B%y]W ] @T _- %2k _- %2`+.`jk/"#@칓8B#lND=w3ny_ӟҠ3 < /'6ѦmDӟjy߫X1::^xG^Ӑ"mE#py#s `0^;uQ F_eELd_Fςtq$[N ;φ?zB=w h{<, y6Y֣lG+s /Dޗ-6![z8K$@{sx ?{. pA~pS(_ %ʛ.nuTޜ7 pPGy~uTޜmUޜTޜTޜTޜxxlE-9%G"Zؒm!v{RoBxRB] ]K! v)Dw..ۥޅz^B!E"@H R)B!E"@H R)B!E"@H R)B!E"@H R)B!E"@H R)B!E"@H R)B!E"@H R)B!E"@H R)B!E"@H R)B!E"@H R)B!E"@H R)B!E"@H RtRs%S׍_>-Mkfg{Vw>Ŕ&dկ\~_v(a JVx/* 38Z _lypawl"*9 7~^Z`xn0Âz} C%+2Fc< ;u* C /%8F6{i7 w4QcI{4`gk,7 ]W-huf]_ 0g\0&n= e%@aT!/a9pO>⇶Qr g[;4J~igH.Yha{Ugfpp{vOEgz8zv a'> v!ς/V^ w a ?4ǏzIENDB`iptraf-ng-1.2.1/Documentation/iptraf-iptm1.png000066400000000000000000000301201370555550300212420ustar00rootroot00000000000000PNG  IHDR`{8gAMA afPLTEMMMYYYAÂ000 ammmeee0eeeee0ee0e$ A6bKGDH pHYs  ~tIME:gI IDATxݖ*:^;1P*I8NH;5c>lB@PhBJPrCa> 1xCHt [Fe  @RF]Ib(>PFT/C#* ͕"m'x x+ 04WA`h\ Csexi"P.)vwX>ϵKO~8;Q@\l(r n!!P{_ar A$"ը|4RI`i2.ZO+u#%G7H`'} @3,@SUߜ0Vxp/@4Hȣy_^Քjʋ K߯̾Kd#s3s6p!kgdVg(}TC!"Ӝwz c> 1 wvC} *": H`Ec+IGaA=R{vpr\p.?xZ.Is~q: wai >yG'%YEk* U 04WA`h\;rWYp' C"86cK{jqrn|5Ii ?uZ.^+=FkCU.2tp"^sD'W:*G p{:4_%*g~H0'=kXFg<d]GJ(NtPDp tV @rX2tr hl\9[:Co>mz4QNpnC!/r]XZ@z@4lk5 _(l\jA`(9E`%GcEZ+,2 rRTͽpH报NĂRgtz!(b  0VN<@as48{DFw",/_96H˺@G/Xtt𜜄@#>lpыĬA"_?𰯷u Q&QcP x~ s]OMb"Мp];s4}TDzdO<3Op@2V{ N[=Վ\ Cs* UZЉ!!D.e%WlY:6)_g2cDtaC{Aq[Հ~!KeC`e@Uĭ[%?PPz-$ R`Na9?YdC;ҋX19(;zRYu4M$tHs*!Ј04C*4B0mǨ>/5), >Ow"<  X]nY׶q~P1pT}Y3]9!^9@Owϊ>s~r*_) (Eu񳮲%i\G2k4߻^>sQvxBk COkEp(M`("}?p~`:_xז*Եc͎]i%4͍Qdվh7#\3E'8EOPr[Yֿ`5<_gu,khf[%}D>ܶDŽ$ΛD `hz0 CK5J4 #~3a)Qsd:gF<0y98Dy61o1R/buxaki3S'ciŀA`j\kp(SӸ6}?4>m gX  x&=?M`No䓄X~O~+&ջ8_'M $^ b]y೿_Aljz +\ 04WA`h\ CsUsȿd^Z^/%>2t ~ŘjC.m ,Wcpq{`Zp^7 , +4DDy5$Υ :wt+0 t­%"ëd,(N$Pnrb[-2ЍZ)H.1<Ί‡h˜g'8@?B”sF|C |@I^yV;.1 2[`LIk@~w:=?wEZr l߁jǩ \)'CEoJ`c* Qԫ'bFY*w VKpUe}s9Wc.ċ'i=p~XѶ9#{i@[灠$qMkh4#x/Ȕ~Hoj 8z{wV{/ov䷗w"Eў}?аo3 ~3×iY/:6:(^}?Ј3OOwa\P@v5GO:4(9^,^tw mJxW!4O"y'KxX-uWlOCgx ؘ.V<78+|WO>cvNY5Վ\ Cs* USiqU&ױO[;+,t7m ٪1NJ^2VE:6ӝV;~ r6$t+D2[c_;up|+~ 4GᕺYwc>16o8Nk+E*x ^}1ؗ^{PWu+#OyرP*yezr p] "D6' "tD:k^>G]z?@~B$y]?^#C0<Q?'yȐ!o-=~(0@usawOKN-W;Bs* U 04WA`h|jZM/Vz°]h]4}|;: hR3xgi?u]/KtGxg]ߜ%{[bϡY_H1E|,2t$BjU cgX'[X0,#PuSw,x ]ïf8N8$ y9ŝ8R?:ub}0>ommܧpOrsDt9/#FIDJӓwTv"+;H2U=2}1:{W!63}3ܵC \` x<{ch4vݖ՘dJ%klYVkz $pg(%P9":~!P?BP!0tZ Cs\xg[}yT}a+8z]XR۱u!cYs⹳}A~W@{eh VwH#=DNBg1XTJ mY|| 3X"p{a(X",)4ANUQ5f8y ~7PݳvUKVH]VOnpUr(CW5KWg t%rWwt$4G]^.oӔrǏ~?;sb O BFFT@#l1s=5ԥM9J =%BDk֍w0ǶŔ p v_ cHS%h7< ĺb@nMTṞ]GL!1뭷5sEvh|`S"\O碶i48hO71o3^g+b <@تK#S&F,b?Fˣ|WF 좏ovh'sD:R?$A#WS*΅I":Aeb]zAM-杗dw ,ᴿv"C/TbaMS n oL7]!h9v; #n||3t(zx;;tboLh\z@7hziC0VcSw-W:WA8'(巑`N.6*9񊞲?Љ֧\ҹh-f yx΅r #6ˀ]1Lks2N?/r~:ɵ`zZE'hrvP)nƝۣ|h'K*ؿԄNsR7w@Eum1~V_9{w @;3I䯈yIHBf L)+لS]mRJrT˧jٗPg֝?I WSV̍ԅ߸+qǨ>VO9 |Sⷸ[:w$A{@Ji!Gx(]bv@M`,HE{nc&l g(MUjZT;4@mjU pQŴ_Oi@'ƒ +{FO*xp:f80+SDLMy \,'7r@[X9#U~S:>8H f_Yz.giu(};K9U7&4WP CsS9~,)VbC[2:.%7fڐ/(W7GL&֌bݞ/na?(=A^TIDATjftէkF g ;Ú]?#y^w&ޙ@SO`5Qk eG.:_s"gCoЬ?uU.n է=Y*®P9u%1jK*C ]iiVHYUA4H<ӺZ/HOvi XPK (G`-W5Sll_wY_Oz#Bf@ϡf}`"(U)~BOVU#K͟gȮ<@q$\ǵNዑF#T,z@n]*\7vMrgVQ/+׋y2RQlvW%3xڱ"-s&/V|iJkzr̲ggo0r3N [SӾd=釕ߒa[|R+|+r?H{WkzL^{cBs* մ~L^~bek̾Z: /Ҽ^LƮ`o/zeꑼ0?GbV:1bZϐz݊ϳ$ 4Vޓ^?0W HҚrw](AF_Vi?tJ>9_YJ?뜟̧?-͗e1g1S#[~Jzd>w\V׹Tz%me?Z3J5έ ^ѷp>oť*v5}+@*F \&P8C@NK`LeE(xCы>@'Hz_-lO`"P7 [ھWїtʕ*K`M[~TJ W/֬+3N~ɐ0_F;V S%("U l=ffKjR pܬ/i6A0 v#M!Aw77$p<> ,V(4 iLGn[0"0wQh_#//~zM׎̐)`rnb5aIFp)˭"η,_\"z=@d}QN0QMR >K/Pi< ? @vzSɣ]GhԗY: '!P@tY{ÝZ[5MvчeYcVKk#ЪJ,uH4j4]f Q9 r6K: l̗юEƂG..s7_擢?~uU= `%V%uzwԃZ ;Ω 04WA`hbz>=FDHMDv#63}J7\ؼחEX,\CT#lMedO_q>-MK:TQn8 a8-,P?Lz/g*8N0QMR >K/Pi< ? @v^N@.GQ4H,ݓ(A N-r ݈-&}ò{׬q Zԏ("i}*?K?0G..sʏe奌'"ʃ|M9 ]5qDXDɏDA0ݯQv@r' &--7&O@[ɪx \GP"P*6x#p {c~ކ@9?$u;y@^| 4tsH^ZslC2Lta #["2rg uabK{ ϖ?AA`hޘ?BoL`#,5 }Ee+T~t;Qk<]nDQ h=\o?j98U%;w ҍE:_D9sυB/Jm } ތjؾ _ Zv0so卺wo2C?\!c$P|D $b 2!$ ^-zn?$dE5oiJϣLt{QEWr-y[Lz8_ \RWUTdi-Z*J_"%t/Y >Y_پ~ڿj=Y} Q*L_եx=,v.BP ׫w/zg-jÈVG'sg3 YFV}T<… $^"E#PKC vs{^Z&JrqW+\Q.:1ꣃ@uA'+R'@í$x^b NTbPP{ tWI A&k@'O]1%l͝Ty(:%0[^5 _W@/bM [8WE Q%+cY(^E կʠ]U`zw"MOɂp+=(=C"kıC)d$YE=x8Ϫ> gArsH$aԪ:@5sӾVe$XnO !1?= ,IENDB`iptraf-ng-1.2.1/Documentation/iptraf-iptmsort.png000066400000000000000000000266711370555550300221110ustar00rootroot00000000000000PNG  IHDR@P!gAMA afPLTEMMMYYYAÂ000 ammmeee0eeeee0ee0e$ A6bKGDH pHYs  ~tIMEjv IDATxۖ*ESCw%IFrl@2 ݏ\KpVt.Z1!5. dVwt*/֔Ds˵j._}^I4kr֦2r]zAAQbTI52NPrb*d(db{,A4##>NZ=? KUH?$|rQd1I2isr e v=f6sd@pO A,N ͓JL/(ȏ`YJn/[1GJ/kTGfk>K*#`x :3N"`}uW,'doagQ!(t}?]No ?_&`oeE"s A%NGAJICPvٯVVYE0 i, .悑GUMxNHUW7#)Xyoܑ|Y?jy{t!bw+HI>VgPӖfs}~o^I#Rb9e#H'\fwx ;t cE7:fIgܺ/1k7%#*h`?Gi!H A'*'ߡ C0Lz $l`i" k  ;9W |\:UvR]vZ A[_+^XEWN }3sr< OĊL}1+Gi%W 8?(ILSiQՇfjS/8j ?F=s`oQAp` ^j.?m Z`sEEmXYaeE6>`,C:4 7i&r,y׭x}`y~N6sƖb@tҩ&*\A:AnluI \\b9e#/IEbU낚_W6OZKË2FR\R#$ HWӿ -񭉭3 #;vek~i;Q3h#d'Êt91ĈH=["8vn!/H6>@ܬcă׃4T/Ж2=j߸OޫzG<_j`eqd~wilJ{2pұ #S!y"&7ݻ{A 80.5:$ A Q&e_Lh?|%T\j.Fʿ#&K2( cG;uUIҌy˃?Xb9.#Xb5e_X c4<_VӡSfUyEζVW,odiŘȏpuG\SF$F{Bbti&P+:#ߊGp~IK6BvP.ѽ䟴D72dVk6^5aVz%) J>>Cѭ!XE*f 1r\8%9sE,h&l4_8~` љ{A5LorWzg-p|Ɯ42Z\w/\CBzA 803SkTiCP#~ ]$ɫP74aAb*kie~"mɚpP—s`0pa(㽫`-Mw)'S (b9.#Xb9}AbFyӯ4x~À`@Wc\;ې8'dQWCN`iqd cb6J`q~_"_E4yI_FTeSPh<:>m^EjQf\05$;` ؋|NO!l ~Ut(D_)LOuAr]t],GuA}A2nk2iSem!~ p}[Y^aw_U [aޞXӆ鵩CSo8v}A[W#yk};B7d ./ܘ <ܶt}7gR/?/}An[w* '_01PS 2q%y0/ʬ Jma>qd}yr=Yѥr2?1uAr]t],Gp类U s{HWmZt!'8ۤV.erx[EM~l|պ*,KIv!O{tiV]vt<%>$p*|V]#MLiƻ^ng#|'L#M}WЪ~AԪ ԥ1x(emxQ@L(r=ǹ]#x7 M:Mq!RV aGGj1 ?b>98]fp!vn"| }Dc~ǙEGPQ3##vAEߎ  ,Mi4M%%X?(wI J2}A.ٛa_t?C(}AܦNԹ !eP\͔<_5d؂J}K ΂1=$הyfDQpQ6k' IVFjCJGlLgo6|4L'q>Any8! j~A Gk#rUpQ Β]Ԯa 5 5f0x"80oDP>B $u|UĮj*N *jkͧU]Svۯ< h$MŰ'Кh\"~n ٓCOĄA%^ {Vx ^κY6nmxAPpQ[0'uGt )8(G\GGPǔ)95ay'}MpQ aULrU|SGaLb6L_YZH<]"G% q#/"X\!iA~L7ߧ"KZAlNt*Pa`Q.W>ϿHp\6wK|Nu{,}B|'u+X31izs$<ήxACDP텊c6:K:Aܵ T1_?^OOAmC0PrӔ{BL޴ 9"V__Ooxw(!8-N#팚₂ǟK0}yuH h @8Oy!*u_1As(ց^ >8=dDD /oA 8˛(x82ҷ"HX bK]T%uu!FdM I& `si:Zb{Ԯ3{W,6,MS]C !M\pE#x&'o G\3V]c jÖU Gd&fk}=з%Dw+^ks͇m=z璣SfE# 0{z#w 9'u՜">jA{.QEPI"sI[4t*/bf ]hy{ߢ$duF޿1,-ɃlQ=JG߫W}vYצV]EB tp^+5E7i;x${F5z>A1LcDki/|\FT!O\PsA- Ks,U/V1EN09yxSba9MOpaElٜN<Óx"61T2_{A׀AU{mo_ M ~ b{]Aԫ>Zv@r Lݰy4tlm6Pd] *!Xm*@M|,*tfkه D-۹`Jy$cTb4Y)f:*VڹWk<3/XI{cL H!Q#h&W~8wٟDAGW0VPo XFbB8'8(VEvOgIKzhjv.z[U1WW#RWU4te\BLEPj/Gs=mu -oYt@péyb4M}W y\S'cqyb~ U"1 ح䇔ꦾTpȅ k$GRЫjU#JZ9n껪U"(O\vuuSUܹf]wUAr]\6Փk!U{B.zbQg0 2U$qRjf,De 4QzA*] zOUZ뚼叁p#Jez!H(/HH!hTHoן嗴EJYwQGtJ:=2*Um/]2i GԃJr[ꇘP5dס2zm}CP*AheM(AYy76  -_0‘ \zFBTѭ$ۺ;I{'RX,rˤ/ PݔrkCz/ //<ɘ]v}}-mm{*X 99NeU0?ĝm5_?x]rLh0'X՗l# ߬M_Wnҷ~Úk|b)\'t],ߟiJuUZ|dԔbp$"f)ec(юj: er%jz=VzD`B/f yx0ˑh7ŮK9Hv+0sՕu/}A TwD5z?ݼ.DPĝ]ԗq],GuAźn%_DXY5Pf`-}K׉_ Z1]!~{T-SZc@]jc//h$5TC\mw,<FS" IDATQ*KIgL)Y+Mҿ: q$qK7=]'DC~{Sa/H"Hy1jOCD)OկnmV !+ S~fXp(ѨM#gHD-ǪIZs 0]Џ7+YPv j*W `pXEPQ V$.=T8G"#(}A^_#,/xٴUl`Ti _2$oB%P/s4dzYtPz}،>)SؖsJb_i2֕[~Cw@ j rs[~HSu+.ViJ,M~m>uiN'z[%toJq7C <r\s}Agt],Gu|SY#,/OHE2E._)C QXY_u]LZMoεXBe䆝Xu^ZU݂NN_Pōή@V? Avo!xuJ[B"ʷAi3@Y:”'ջ}*%΄UUb vԉ5 w䗝;J##SAP2~u~J})G ذ!#,Ո)d+ԫ!XÏ DPkR?ԧ# A Q\> DW9MHy|+~&VX~GQx N ^НR)3f:7BP_!L)\'t],  ǝZ~́zޝ:@ɏdd6@fX<><[!wA/>Caj">-gd)f7!''#WP8T;BnsFD7Hdszz$^: x/`!M7&O䃢UG0!w"8Z>W2Vȣ?0};t\ح@KRDVdG"H;`#dA"w Te5f>]JA0F2"Fp2;LĜѰخ#wr]֍t}!xԪK+[#x/ҠV?OhЊCtǩCwrY,n,%}>וOns=.y3b=SLInr+uDO k`\gZ (AB+,P {l6/e:aW_,_7 'xcԐ2zx~B3{p؆rx Acd(~ ׋bJ<#Hښ\! 9}d[ZrUĊ#Ek"UTj9ɴ1#mEកsA *?C&٦ h~Vj` #H,AQoK+_`\UΑ Zd nU$Z L#x*u.hUYATru#^r("h=sA YXhR2r*L3OO2_ q+ysGP\Q  Z)`Εi=ZԢ_ )ER[/W")sUr] pII p*4#-·|JcOW%j+XV}dlv w`ůjUp:rځY6#V#ߒx赟Z&!zwz^Z__@%*ٸGwW2 L~ BiOT{sNK?-} 9N:Ddi -Z Jr)g =|iÚx'W'$Ưx=Z\H}4\=tͪɠDk٬Z9M(3'^ j*[Q}l utC{ aZ>4ЪYn}SysASh(rag˯N>L:QGf c$#,KA1%iijzA2 X)E)vF]Y,Ja d뱂FPsTs%87<A1"t!X`_Fh#hC{XnxS`UieL!QO̕CۑtӦ"׵tZz2[.yT*1Q(񤇽 Nd`abDg4p~ρz]|J^El/7]~Suc`5ic$nIu5UԼ-ɋ[ozeJE]c{PO/u&vDwPr2P/G݋ήq8U<hѾ6֌Ub*fz IݯF1? q&t6M/?+1?;{}vFݺޭ:n7V0p-,j Fdc~X ̶,yq* XFRq& b`5 k@ofXOIcDvZ*m@WGz3Нy;a`u Lu:khs:]RǙ̕;m~Q|%כQq;K t/yojVrJ, ~,zP9 (v~:".` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,d o͡,{9TziU{w8CUYn/q_Vq*˓5/t @"*C?reg^=m9B ܊WQ_@wEqT~Iɶ\ig_06?7V/ұvDy59)@xNǟ 0b@! X0b@! X0b@! X0b@! X0b@Wr858ywΠǝ5E{͚ߞ(o|YoZo m[~Ж5lۖ;e qCwCװ=M~O 5OGrЇ\n4'TK]{@sl!Afa`0bjeh*:݊(՚UkgsLmD.6eT*="J:LbU:? 7u)M- l 2pF të~5/*n2P}&,/oKm?n2P6i~U?cڰO?gw]ᔗu"x}Ns7Jmh@_:[w-7z/k`3lO^8wM`SV`Gnѓ ?=Ѱ[~Ἑr` ĂˋYi=sk7E e.N['o i#1gg29bG2d@]$l9 g19+?KDu ,Od98Xt>ҵXtwM6)H z{R3P%8kz@-x*c 41f.ٺd` tjCuOe:ow0s +EQfcU(ۙpSzQY{Y˭յTw*oVe ە'ߓ%$of|yx3@! X0b@! X0b@! X0b@! X0byQ>4/Qc`? i^ASkKntWL6Ujݪ_ChYtc3n4;J7;bF9N}E|?ƴ De[ [V֔zn՗qbmiF4pωG(r,"e/ ޲qNSdm/W/˹7Oל8o_~~~ev \W:5L'ec Slqضޗ8_u}ojݴ:kvwW0G1]i!Y-b4}f}GUCU0ZMDybY(-PB;Th}ǡ7p1ς=Ö}mρ戭 ,h l:d\Dz*_(*9Az"S7# Ժ7"K9i<'L s/2*c뵙Tw"SOuU_exYx{f][3@w6(Дz~ XN[Ý`-ҼD6` Ă B,` ĂySx;0Xq^m@! X0b@! X0byQ]#Q7w0ɹUK_v7;نׄFajyQ/\4f:WsUY;/.%4_q^owwcOLpw4_Շi=%kJ^V+}ZoNKV.`M̥ ҿYsZ1i~`10:(bu%_X_Bʶ7@ѽIrIE.ks^1`^7lRLrl2*&,XwXgTߔ 4X:e;UQ=)1py;(މ k_GVƬ´Mi1܈k2p= alc`IyoN`9R0'L{ubF-UIgs\gJ& d`o|yo޻OE <&8w+ojs `s7}80b@! X0b@! X^@xO^@xcUe@ˡ,{9Ta/` PU ʂCUY0r*  B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,` Ă B,@a` Ă B,` Ă B,d;0)v(2]\s`M6(n*6R~K!&媟H;aMi/? :DXo8Υ[]N5bV^9>BQJfIg&4ad;?T! X57[]m;~#a|+KPV~Dn~ٚTm Qf4vbnXԜa7 v "mhc m[Hbv׋OIn<| ${ T[o1n>S97޵e^wq4;mUxjrZ5Z:@@on+rT;9:t= o>ZOן'g{Tr^<9ɪ(fӽ*Z{8U0Ds +jRXq[ lίs>ަc`\@bk7hK 6zC2o迿*O/KV95huT66S.[[5="\tIL$d;^=,g!jyMH#l\⭇,_2ߤtw5-KUpG~T#*7~kgp\t6pLfl7b?}FV ǽIENDB`iptraf-ng-1.2.1/Documentation/iptraf-mmenu.png000066400000000000000000000075251370555550300213460ustar00rootroot00000000000000PNG  IHDR3a"ۑgAMA aPLTEYYYAAA0004aYߪ}}}}}}}}}}}}}}}}}aaa}}}}}Y}}}<}]}}A<<AAMMMvvbKGDH pHYs  ~tIME" 2 IDATx AJ{I$ďI0Iw `Cp2f$$b94&\;s4_fיJ™3aw9Uݤ_ vkř3c&2F87M87xvYpܜ@,8Yp dȂ3g @,8Yp dȂ3g @,8Yp dȂ3g @,8Yp dȂ3g @,8Yp dȂ3g @,8Yp dȂ3g @,8Yp dȂ3g KΜpEg싾 t}鎳/.8g_]p;ξLw}wޙgZ9sL333]3tt4#8!pfx0>>y8#r,:F.he8 G}98iFpCp+p3ѐhlH^4#+soiᓜ`#Τ3u ԁD=lRk)m n#LgA^hsUggXj0θI82,bOb$Yp3ZTM\;,rkgf%ŷ gMΜl0dvsά&s4 WyjS3l83@5oS8g3N^g3U:9Yӫ]R&NkN&sۛY",Zgޏwghg@.Sfg:gg ]l?y8ӌOuY.[4,YMDPն,\aG)AtlZiXџѭK]vF,r&_ռ(,z;OT0e<> Z4j;j}fg52q(M.nw71|pf36w?g.ZBYt9>ΘR6cSXؾ3>9H4klIU4gWkJ56=MA/z r\oo1&n@g~~v&p3wA%?ecu1}2FN V:7B 6K3S8S,#Q6>[Ѵ6'NL%a:O9I5s5] 6Tţ~%X+@J=NVDuUxi  g淂9#u3~kXs;#3)@8Ȗ35@83Y568DgřNG/t|<U9uFoEǴ ȰџQr&jglΘVe?3\oÌ9GT?%;..4)DHZaRJYHo<;{@i?A/IENDB`iptraf-ng-1.2.1/Documentation/iptraf-othipfltdefine.png000066400000000000000000000120161370555550300232200ustar00rootroot00000000000000PNG  IHDR2btgAMA aPLTE4aYYYAAA000Yߪ}}}}}}}}}}}}}}}}}aaa}}}}}Y}}}}}AAA<]0008Q}ۚ00㺾Ϛ0<<AMMMVbKGDH pHYs  ~tIME,ޑ܆vIDATxk*F3QL֒Ot'UEV|ɷ=Vy*WvbN2w"|rDE|7o(%eg)(P˔u Pl(7}>2_Jep( aK   N~y'P82 N pe(@'P82 N pe(@'P82 N pe(@'P82 N pe(@'P82 N pe(@'P82 N pe(@'P82 N pe( L?"ޅލލލލލލލ|Pf#tΟ eʌeʌeʌeR|s׼wle*F|v'S{wauL L+3OSqT&cZ\ґѧȽ8v\0(PqA@LKi7kV?xq̀s[i*cuZvW8B e.7tsZNfmBcgǼ3[v^d!4rH3Jyf%*FfZL}qeb&G8#"!F8wˤ=b4M_~1}ŜߦA4WLAʮ*SQ9r~i(cD*LX ;ƚ;}m0%d2941kdCᩌ\ 8)#{@wݯ7#ʨQШTF(Qcµٝ%'Ɵ en"@99ՔԨ51=sʰ{噂ٛWL,퐯RRY;o*#zҪQCCꦑ`ݗ(sɌe~iAe2s?BCg{} +(:I"ޭ =+Ϟ{[J1upoPfOUz,2qefi*A 6w`+ssן+<=*+{\Km )(N\*LEƒeʨ8bWV_L(Ck2t%e]e*ӜsŸ)WQP& e^uŻ}d1tj/ȷMgL_WWӋM]uʰĔ[MP3~eı1_?}ӡv*fRſbHfќt-p23g8 |u#hO\A\4D5䤙$eGICLi+{t 2;=ʜ+QP2P(e\P2P(e\P2P(e\P22ote T'P?(sZ}2g*O@w*SYR>bԹ2,e PXe[|̪3s-e%#VLk)3^.|2jIVb^22:>rAe2f:>r-e%A|ʕyW7GO@/b^2+8Mʬp ʬp ʬp gxeg_>)dteލލލލލލʀ2 N pe(@'P82 N pe(@'P82 N pe(@'P82 N pe(@'P82 N pe(@'P82 N@$Ô'9m"oF$"C喝(ft;]δҖn?ssSyWFgFOP(Zd0ê(cv9Ôy 2H`*#vx{ڲzke|l'V8xCكo|>K'"P+1KJ̼Of`;c+mytbemQщhfn[ʤɾg?+֒[LQFF(&dCWhYV (gkU[yGf!eQV~3Ze)PJS4Oُ"kK(#hBY(sdtO'A}dTQT)c~^*J> D%"W}5|ʘX>=3!OT6cSܙTz(SK0dkEZRόw2Vd*ebTЃ eEe)CMDar( ה7'&VetŊoV8a$Vb;S/M$eXđ:!aEK/MSꪈ5Ny}a =2w;?X $Q{R3f9\㊉EWtɄN1^RuɛxJgC2'P8YV5+po,X^(uP/RiE}LgW߱M<}9 _5j5atEtm$ eܹ8YZ7#O,eTW&؊bw-jde&KV=22i(g23Rrf;V]ME㪎O;:RYL.SF$NYc<e 2ր\Fph eYVf\Ђ_DҾRzh|xPK$kUQ&Aє\je+7( ̑Nn8f ]IENDB`iptraf-ng-1.2.1/Documentation/iptraf-othipfltdlg.png000066400000000000000000000177241370555550300225470ustar00rootroot00000000000000PNG  IHDR2`.obKGD pHYs  ~tIME . ,aIDATx_n*aQ5BGQAE[gGSTC?KX_/Jıc29}~e࿾?.IW THaC(%uP|/֬I;sx$h1{ʯCDf%u:Gt*-Ò~U\[J:,qIT:2w}ܙ㴣FH? @wx[;W^^y` a `a `a `a `a `a `a `a `a `a `a `a `a `a `a `a `a `a `a `a `a `a `a `a `a `a `wՅh `a6ރC\n[kibWK;73-cXdF#phkh8zڭ6-MbtəYX~W&n+}h٤{B֫I|oι7,,&5mUF:xUK돿~Kz .DGqoH,y.MSLƥ暰:,!τrz۞Ɔ4MI2MeQaJp[[0w 4tI~1гlGܯ]֬~!*0usm lFGL)Y=fҰ!.LG7,-%_j[M KQiH*Ią쵽|82p>ԘӨӟfѣ›ނ 'kxzO I6c  p!]^SzO TUX9T,,DNn.pOT4Ϡ|ܣCxMXͅwqI$>"ekbVח간5L| y'ތF1/̈́g$,Voe=##, !, !, !, !, !, !, !, !, !, !, !, W -^Uc0z~sy-闚_Rzo[o(.)~Cyrq!ik˯]v̝ׯ#2ZїI_ӵ o&|m~k”x[&q0jdMX3lTV GT aFKS,2W ]*[ `aaI3_'UUzg+`W.*2]..$Mk\$^g?Zf&Q}qsiqw>*LM9MK2:Dæ-LI!M,,:NTBQ즑iX!o&jϿ zd ޝSg a ¹<%~>-|EuV=>i>/?#vMwQo'WFމ?F3b%xi&<#a Rx-,V6Fa `a `a `a `a `a `a `a `a `a `a `a `a `a `a `a `a `a `a `a `a `a `a `a `a `a ` xH Vb$>h FKCFK/?ՐKۆ49eDl$B$ת-ۣe‹ Owj\"vߗmȾ;> €z_3$^nGaӜUPqs_t](֗GU{q1Enct~(C kT] ε%'q]D vS,|4Ecl}v~!bA~;3teXWbmuGy53zVu+Mm}?Md򡨂e8&_複 K[ΨBڌ?֔hnw&^@wy`cf B3[l7cK[_#أ5FKO< D{X _I;ݰ9 wA%M5N=GvC5b02ZҼ<Կ5z[{srH,JR B?Ͻ\ӌ` ~{=hiJ}-JGiF-L"6Wi}}THzq1'ʦvKe>p[&ҵ)45kuZ&F%p@AVrbg59WO |Uy_=^XOy 07?~.5h W=1FC`l .x@|M)gӿI#6 W:FR42ޜt 10n{/¼ī ϽB4dpmx;B[lՓx+oֿAU//$s7]>n:,l\{<g?ݳB?pnZExVO$Uxw'[`'׾0{Yi~Qzní{[@˽%M5o|/exF+6B=9Uo| .ڦ=މ$ XXզY\l?%FK*L@?M0Iͅ!&] z\]- &@򟿎x`x SyLPkې"L6J0]XrAX5ihU҈rԗDr.0tb_% هĤtH&1 ҭfz6ُ1j& `[4fR海|\t_Un4k:}&r%[>ǯqĽ[unW\^x\I<,2c70ZaprfEjuwh `a `a `a `a `a `a `a `a `a `a `a `a `oǖB^)&B6Z|}/u%R +SvhrUVrn7$(|;%:?=cd8e)m|Ul۶,,U<>˕;D2Յ:g 4{I<k>4J *k>{:h̚jZ].Y] a)wˣ8_x63:Ǵx[yyM=73W]nm|T@B'jK7_T.wOkbuZ*4\h'ƔI4]=)nPϸ*5MZ20¦ X3Igxxff\o*\y+ݺMӐ}^3Ip[c->fLTu4͓{k[t)|g% ]h\I1* mB:7/†Ǖx~ @ |KN%!%!%!%!%!%![ޯ(ι8,BXBXBXBX9g h v1~izϏ/}|ӱ~qgrJTn_y|K\^lʣkXDMs It"OmIJrٰ*˝,wGo'=k\&80|Wv='H,^`>[iK,{éh)G3u+"ZYWX45է_Xg7{Erv⎟鷍(sOsoU\4'Iْs iV^\d湅z U)f׸RXյ& _!Lyj5ŅBIn͞Y$}}RZ̈́<2mMVzvi'B)i!w\miaz]uUW4Y4Q׃bVC}L3w1$ጌ[_sE5D穽,Z&z(Y.8}`/՟m74g,kOvH֬KUOS4_hPѲ4:odiŃZ8`seYOsN[/}b;ؼ4=#B_P=ZnMdE׬%fT]?-YSRCt!2^NH6o‹ĚҼ&p=i-msߜsuu1vDΎGs27xy}x74 FK[憥IO&):'wm?#IUi-EҥSn8JD<{: 6Y~+Q(ŵޤw` 8"L =n15`ZJ_=[W->Q~taŸ.Dr _"MwqéUΚMTbF&'u{$|y.6.D䨙M{ǂr҉wkm?u+y0 Wo%3IddPہ ˅XaۘZ$;}HNh __Qei/tCE!qx\</$Åb.i/Cn!\ =ZߣQ%)EYor*ibܪZ*~i9{jI<7>}=ဣԎʙk!}΂w3StꞶ2:46ɚ{'S|˜SN-k6Zk!Gc#kd;WNnm9gFe] ұ}?Mf{i ]l>Ԑ*'R:\vOhv*Pp7yJ ce{٧?7Ӆ4<_N+$̨UuQa3ΝJ-99wvmɅ=R>P8ۺ6FRoι?~)Æ<;IfK$|2gW4hRIENDB`iptraf-ng-1.2.1/Documentation/iptraf-othipfltselect.png000066400000000000000000000106641370555550300232540ustar00rootroot00000000000000PNG  IHDR1a gAMA aPLTE4aYYYAAA000Yߪ}}}}}}}}}}}}}}}}}aaa}}}}}Y}}}}}AAA<]0008Q}ۚ00㺾Ϛ0<<AMMMVbKGDH pHYs  ~tIME6v?IDATxarF 6*fV#z76 Av ;041CBS>;[c>l4;2n 7;Ƭ{ӺEa۳oC>NG"$ܪט #/Ƽ=nj?;qv% nW_ @c@v` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h` h_H3f^+ۗMcȭ5&.-rL-LاzZpQO-c6Fi007//p!7o1 141 }cj솼zzN0f^7eU975%Z]0Mmz,}ʇ2CٺVjƬY_&wdZם/^z0Pε+iTҼą6¦t+kwpR1I=sz&Ol[n{w2>?7q8j%chϘ%j͋{]+dcvKMbM.W b\{DRYX:7m%{JS3v;i9Z:g2 n}5|sJc#s[ Oف3|x]LJ-shpfϽ+;ZFTbcbK35lyTZt-]cƘ'?LK^?G}u6f)SbE${~5 vMᙙ/w[nvewXj\ݘJ טgkcPI1>I$ة4$OgLHAcDcl]qcdk{2K]AW]Ӯ=%o(M֡sؘ%f2"5bCk7kϧisژZ &OJv{m'IZaBoz/|cH; oǛg]dK[+h;z׻6,4# =c&LFXm4Wo٥c&JyE_U&.scOɟ| O]bL[n]̅t]pǍ0njy]Ɇ[XM4&11ؕ^cvc|=3(1FyȞ\McmkټLɸ>+ 5J\.?O7 '1QVvOZcn~Qy*|>Wkܚ#]1us4`d_bL 1Ƙ2uKFfXa'{]r_Tecom|1G̘W i4$R&|{ƬR|rixŘ?L+n?+k}1 ƀva<'L5fGUڣ<+i=^~<c'T]Q5cLlKs-miv?ַsmfLxM!3ƝP'b3 cl9=UycF3ʵcw{Tͬi0elT,|Cwsr~1`hKd&$7s1k~͟1k\ÎgkF7_ٌ}{kky&ѦI'/^INNST^c]XӢxSX]L|͟I11cb>"ɹسq`LzC9U^p91\nMظK$$Ƥ[q[jJF!=71jƠw֘[@r1&hϘ޷ Giퟸ ͵/kL4njIJ\_XYlwzwW2=1&1Mssy%sLr"^c殜lL|tjå^>ܴ,Ƿiw`KЭ|V2C1)2bϜMg8c/c8𥞝9,Qa0~]cz Z~ @ˏ;;]1 tfy6}KƴO1f3ObL׾l226Yu[[7n0_F?ަr5d:ֈ$_21F9fLVwk= ל1>t3cF;|麝T/5xYǸm8su׸HW﹟vN8qmhr]=|=mkgo.n6my~DŽU_RR┣,ۙ6Mj{s|ڌJcn;5=cw/MYoSdYi͞y^_~u>g ^(}i?ge51c( 5dfe eڻm&89/Ou׻^kKb;K$h` h` h` h` h` h` h` h` h` h` h` h` h` h_H1cߚjg|7Z\l!+Ӌտ)Fr IUUqۦW%KeZo@-=c>L\Ԟ1IyӘNZwo:d-vJDc1y_3wbl1uz0,w?^5GX˖ {IclP4 cpE16t,{ۚ:vgFShjaެÛחGLۍQ U!^dQ9\}T{$[iv;_bOmniYmV-l{$cRoq;Θˏx`a}nc{fKz4-&,nw|b0 i}clv1^hŘ8gU$Bi/5dc1> (LGJ"Y'^$Bcl>Kfi2ٕL?go3b~҄%7c.nmy <115L٘l^]=nL!h.e$̆kfsىsIgkn@ zQ gv -J._D[`S'Gc^_6@-,:IENDB`iptraf-ng-1.2.1/Documentation/iptraf-pktsize.png000066400000000000000000000163231370555550300217120ustar00rootroot00000000000000PNG  IHDR1a gAMA aPLTEYYYAAA0004aYߪ}}}}}}}}}}}}}}}}}aaa}}}}}Y}}}}}AAA<]}<<A00ee0000000e0e000000eee0e0eeeeeeeeee00ee00eeϚ0<0}0e<e}e<}<}<0<0}000<00}000e<0e}0e0<0}00<0}0Ͼ0<0}0e> ?T Zc-ZR1>XİF1I4MrbbξEq~W>I:AG*7RнWt`?x8sFg!N˼C%AE1oՊi>'s\O+'NQNsHi*F<,<>/~W~pzp2g)@jh|7K*shbY*Ab$-/ĥEuKu.Y Op\̜hI:3_v1Sq GDTR7kPR (֨` Pcuj\5IkYQDѐNDY~Y,OKbj#'g8tHֺq)ʨvSLHQ;ۂd;n,b\EbQ) X]+zRs{9Hs^Y s6("%3W@C( l&%>>>>>>>>>>>>>>>>*f?洩+es2hz~trikbUםc؊n}>FY#.xX1V |Z1bz~b]??1KlrM޳yɚzvsyӟvb#+tnJyfPȂtC>NNyldGtNM^(2.X'!|(ճCz$8؛ZY FrG-+0C_1uswV MKBwf/@GxF1x2sJ$&ٍ X]8zvsyӟvbbV*l8=Z6x}.%1NyL\Y{W+rEUל^cb7szbߋ'Ű=f#~?c2t a1ζ sw.)܊ ^Ő#Z^Kå?ٮme2~ *&L(F;b/u;K1Ks^"זAoJA- +kW-PrVb_ N^/3Ս)vN~f-wSZ^Gz#>brbd,Uѫ@1G9JJQǗ(w"?w(|(WL:~i#ޮϔ㨩밷̀h'[ݻd&,mX{GW~p.ഹA2{ݻqSLYw_g3mnnRŕӹwG;x;LCۊb߻J1LXjbw\u龒Jރ֘czUo WLOs'|({oCmd?SS<{ag%Wmtb G%|5/)ng KyUrj3-S,kJ[[J l۔bv>>{21{|)k [2;zP"C;|y϶6vbY7#3<-o_;xyT >T,S[tkӶ-KCw{?<ofgy Фbd>k|!iEV5qڞ5fvl'Ϋ| =Wwr|ZQmݰdxVA{$U4["aWmJ;iE.AuE:`.SGM9fŜC3Y߭pVKqPw*ԃu9cz*Ae;Ǥs bu_3 3Ogng3?*$bsCkオY;t+{j*n CrOMJra->0~ձx{& =@>>gi[O[+كk)<66 {RצڡHKevno"x Ώׄ˞/Sب`g9p79V<y1MN,Փ悌а{ZbʪּL1J1|7Ң$vOocȳ zۭCrۻ[9"_T̀-,ccРbxqoKVG1iaQɬpK1wJ]4.)6U]:URoo&y\(|2 A2´cx+ ;[b(bAvTn'|馵sԜ0;1 a?f WzP7/˗iX= ^ tnts3j6[n&y{³.-rubĶL>Sۏ3W]i3˽Wݴyο˽nGlr봞*bW[fGzg|vUL|;|Zt o1+F^FI *}ȗVZX{G%dׯVu[W՗J駭mVâbrOtVZV{K;*BAX=3!oYK+7s]߻Ni^tUvz>fK"%>c|uMyfg^,)!)Z5DΙ{r>mOǽk1<߻>Sf[Zλ=vtlrZ*FoF" itˋMfKub##nҖiPlD[fFpZmbŐ1W|ynU{ocަy2~)bQi}P̀oVauyP =S1e۝]C,o)fis/.dưrI13< S0Ƽ-s\/'' ceUw͝w[㭌rzmϷO@1|@17*̎Ϙr-޻VǥZ6浱N>ٴcyu:Ȓx;]Ooc`*fWo Ǩ- a؝oY/wGob޾;T62twm{w[܉LcmǼRP M*8.^{iꢒ,//{׉!ah{ݻ>'&lBΖa[Z3 sYޣ@>>]壵N2q|SWm6?i-i5+ xk #ӫe%޲_1cV:gO{ױG%~45;܆~ԳkJJ%tT嗷9=;$ϖl㦢kA1|7ior<ȇ"r/R{e}i8:g~]IkJ)bb7 H?oK7ˊuCŐP =I1_QW?taqtb\wZ*m8*Iluﺪz Դp!1H[ W9F0{׹Ń<[LAPGݻ&6u޵vXf!~~@1|@1|@1|@1|@1|@1|@1|@1|@1|@1|@1|@1|@1|@1|@1|@1c$h?ɴa+ݣ7xY!m`}L &j}z0azO>}ܠ2Mşf=Z1}iQmdutbzIWLFqN> JzX#Kd>dnKQt~P8#hYgb([XZZkyf*+(H:-#Q C^qbjbYYҙR-dUl-i퍌Q蚊my0\f(2TMg/Hw|)eYF/V RZ;xՔM< rd*!<+3s/ӹyT4]QIל.ٝB~ T[pP a*6^OΤu>r*V<_{e/+ZٱK(BΖt.xRyuѻkWp@1OEH>{*>`wuҚ|H"K5]vH%1=-Fʟ |=uŤW1Q[]1wSݏ1ӝ %>xĭ^dIENDB`iptraf-ng-1.2.1/Documentation/iptraf-tcpflt-dlg2.png000066400000000000000000000151101370555550300223340ustar00rootroot00000000000000PNG  IHDR2`.obKGD pHYs  ~tIME$9IDATxm<PrE$[-L+E5xl%YQ3 1sE4cl\04 ×/? y\ۯ_?%j?HgÆ_n}~ äJ4[cANAoL~MUeT)~OIXK]jOsnؕV?fR2$S\y^u=͹Z7Y |9"ԥFcZzK?kU@&2"W{ox6#vtUq?ϔA<:sEL;߻|0sj+k_h.ؼOwyWB[bYkҲ>Q=Mn!{tS֒ZwO0|~3MBooDX a @%DX a @%DX a @%DX a @>@{o^!v聾kW)֐9[,Z[~ݖ察fJK5؅MN76և|/ɶirěFI菾`b/k*s8Z߶>̥0WU6 ^w=J9?~.k*mDYC\eҴ;qJAׯ9Mmڭ)9M|UՏ=u嫭=̖r<:oL;bUV8\VQ|ύ]\s_>Xx ?K=[ږH$ꄵ:,oo6hs"U:[SY'P$ XBܴGvLl:8G8al|1۶fc=;>)vBt>ʱ3V-Ǭw}UYj7ʤ qkb:j&^2VlO@kɻ^\XOXBWt\e"WM͍+Cцb>g0TO3U?-īh(uTdk5<|܎g Wr/ܗ?|ye-mO |hz~{[n͠־xރqMa*{}'戽֪>bMnʠB_>U_ |w <-@ K",@ K",@ K", }86^[Y:y%Y[*r#^{+hܶkr ?~Je;察S_2: y-mJ4_Ǟxܙx;7}AeR}.Y-YsڦOGa^uHzBif5Ms&IǤͻtÕWN)m-9X앁474:i>[z%;z,IMsc"sҊHeaii I(J͗Sv]L巄Sܓ$]NMpT0zr\k0NO,8nN+(YybW?:^ krW|Ptl})|& _>4 =m K0,}YkrC.| a3"NFUa7Ѫ!lt&IX a @%DX a @%DX a @%7i-E7-/ _ym9&Ճxӈ"-^M.㯪 uM` 0(ӣ#5.NO:^<^Q>S;$N?~Η1LLauX;Fs1 Ģ)Go<]"V18P> K84Ny.;3}v" v0q74׍O4Ȥ!ɼjO4<ZBxFBI-г% l:5mDX a @%DX a @%DX a @%7Qm:4l[v=5o][[J 9ߘ޲%19mc!iozl`ңim릹og.)z!9 Hnm:{@p;Lyxܕ]q$r۞ԏ \,|.y鑫sg&^\ n~H36,F.g K-]OSOi<:Nk3,&sKs~c'`G'xJ7 Kboi/awLCqJiMU.8kȶ>4y,qy}aeɎ+_zW}y)i?0mއn-ӌJ-N,<&N<`ۛFD }o {[ ,a @%DX a @%DX a @%DX 48o 8gv^b]XJt[΁tSӋiyEooV+.9hIvǾmOluoi,SZjݣ}磐Ɵ5!QqygoY{H w0i̟6ʏi~lٶunvG٬XZ:XPuԣxŽ08~PFbKXګ==v<ͤeȴ֞qmn[?pC yYm:{6hn uv9 ҆K_ֲx.in#2mY;6N;6}@ZA4W95.Ң,n,|?~P~ryM4X# ?=ONyؐ2m`j.7塳z/ȮM.nRROO{%5+씇>9r|Iaez"GT >+sZtn>d^_g r|MxA۾vO,|U+:g龕ĤmC/K<-|K",@ K",@ K",@ K",Ⱥ-}^G=ߋZŗ=7PQqK^'zqZPh/G 7Nio~ :ı.,^p%?=M LD?>_pa ^`R_{1I0赌xcx7Ɇ=nuGk)Hyl*;H4vKs#';i/<m4yGޓ3Щ؆慜~s4wCгp(9Ϲd[BuȪ9.~\Np);"byv7+Sƴ:bΗ*^xuk囟3/-mg/zw@;w =OsoT~k=|hm g7-O8ǁ3ven܈wiƼ-#&@!4;rӀjB6l7tJN˘|*kl))q郐uIdyqڳY9 H:^-ҹy~n0\0:cz~{{ݏ5t"a @%DX a @%ɾ\0 iX\ K",@ |!kx=ozK",@ K",@ K",@ K",@ K",@ K",@ K",@ Kc_ %'U= 5"9#? KVeisb<-?:tc6WX1$cK JraiX5x¦g7=Yyޝf bg6=6=bnuR{iMM|; j9-CcA$+ӂ57tfa(f+be\WUiƚ<1U/YYs mh/sn ᅹ_.mj 7̭s:^5da٨H`V~ui_l_X~!dZjH׶janϖzUiCӾ0sǕ]lpDyvK~nW(πiΝ7';jL?͹[vyi hf X|νX%οnۯmoX˰}Gy؅%hKʥ~N[<3t6Ϭ= \ӭ;`2ܥzJǝͣv|սǭ!DEm^s*{ohY0FAUK)m<{=mYjݲyK拉-5d-iV_57\>na4 Ͽ~^ w̹ټc7x;`ً/ No (ذtldOt~zO,)Ԫ4#ԥDTO, "`x46ٟܰ[w|;N Y=X8#xBaI&vFe(@b0?p(}8S9{/vD>>}14{qCnX6s*RZtuX#Ob;ү6c}>tk>n -do1=wOPong=3|a˒iՒ5a vg~%{sUcۢG Mzlɶ{)֍5-Ҫm(Ks,tU;]%w=PM9qrbc;B 'Ҭ͆%m"#8K",@ K",@ K",@ |~E#-wO16ׯV~Я_ 2=G-g7q*PyӅG_c|P):lpƔ׭o8ͺң3Ƙ^W4OԸʎcdAT}aүfX_wkNFŒ}0=Y'n+TQ Dz/!۶]ܼgGskyN~-v4WxN+U \nuX:iD҄w<ڔ)WIbIXml6:y;Ci/_~6] :CoA@ep9"IENDB`iptraf-ng-1.2.1/Documentation/iptraf-tcpfltmenu.png000066400000000000000000000131241370555550300223760ustar00rootroot00000000000000PNG  IHDR3b4?gAMA aPLTE4aYYYAAA000Yߪ}}}}}}}}}}}}}}}}}aaa}}}}}Y}}}}}AAA<]0008Q}ۚ00㺾Ϛ0<<AMMMVbKGDH pHYs  ~tIMEuGIDATxiv8F o&~T{0ht- d^83 sf2P)}I~ׇ?'/;!ͳY x6Mg*8xz|眪`:C8`'QgFښ/y<'Ix~1&8~g_g~pg8/px3 ^ g8/px3 ^ g8/px3 ^ g8/px3 ^ g8/px3 ^ g8/px3 ^ g8/px3 ^)&pr&pr&pr&pr&pr&pr&w,V~9],pf3\8s)f pR8sḀ3 p|3¿^z{_{F5\yz8ug|3H8nqg>2HL} dL/pf3O@ΰtyl 583 aj[g6Sr%Ǎ34X=û>6|3] ٌLul"32;ڞϤiвewb>s zקc#-qӱ$tyl%I1I>338g.y.k[ߤ$qPz\&!/uR.ҢK+vΐ\ P*gsgI̋9û άF;C3ޤU;&LvV1R?#v ܊)Kġ t3it4iD\z3סmgw3D}v <7Z@gK-oMikg猗k8p g)GcDCILr1)΁<ӣ9I8;#9}Uذv@31Bәt<LCz3zH3jOC_L 3S9Uի!W*wHO~0Owfy7}o/U35gI3zlpg6g6(pJLΰΤƳN1Y$43rN[r&Jy3zb!OY;^dPȢXim6Pga1;57!Kƈa7ZpppPSb.g'gJ02C9+q3L)qFo™#PڌFYcXy./o!?!s u)EC3q0}so/1d! KF]0gZ]BMk>Y<-Fr&%Yޅ9F^7aCax$yeΔngJ(3^gȦϜ13h[P35cgB3 n`&$ޫdbi=#3<Mp¦.gXMpppuM&#򽾯MR?-Xgo՛Vy3 ڙJDX|RYBM~f39^J55uY1<֙88ؙeНHZN*73΅3fje 'p&,̶LgKiӪa8l0qFg(錱%:ʥ;Öpm>(4zVE Zu+#"/gF.##"|L9#"|L9#"|L)ScaL@ v[3h{_0>퍰|iy"|L-GL@y"|L)* Z*L߂OFhp&<C y.V Z*_L .."\[N2Lݙ, 2gVgj8cPg3Dלcw3e˙h3h3h3h3has⌏oΔp4,g.ԎhadA>Xz:t2p#$zl$9^`8e*pNxw: ƵtDcD#_[03gy:e[Gc;9pv}} Gc;3=d~O!L7LݫGg~Y*p<ԣ{:O<:SX` g|3"3)pΨh4N3w/0Y3esy4)e,~FAN~ X`(itf~kУاUљ|<֠GO|3z[>U=(i8$i8aVwC<8 g(p8C3= PL{vAw\|yg g g g g gɵW/px3 ^ g8/px3 ^ g8/px3 ^ g8/px3 ^ g8/px3 ^ g8/px3b'G|%,!??HU1W!++m%hݔ46cs]>c3M1uLn2sEy8c^m;ah42$NӺvg= +$1gx֪:Rֹ A'#633V%()eGE*_Z.O/X卬RFEM1~MǗ=Gnxi4,r=agMKK&2א9#G^,A#PhTq;8_N(3_ŗU>: ByIqR9W*kfY k:ؙWp|Ό.e3gb9ŷgg狽ؙS옝L<1%J-]+:0Y.'Xܝ-u&/&ͣc]ˋ$.bCɱ#dXLUgJcSz=z3 ˙kknLi)J%_J)3t &~&n1FX.~<*jb-s4 ֍MڒI&7[EŜǦ]L;iCO{wZΌJ`cSҥ\pn1\8:pp>&[ -y/T:F}U32TcjS3LD! ԣe+\3s2KXO%+/"\gUOv9YB|4пטn b;I9ȝv$cfy /o>әPq&u7HRr&%hgQ)S?,g*HApf#5gUpfA43Dw33ƽydAY N.:#o!'xhVL^ i 3V;pʹ2$çM\oLܝM2t [CQ\kv*ED`oc=8?؅IENDB`iptraf-ng-1.2.1/Documentation/iptraf-tcpudp.png000066400000000000000000000222661370555550300215230ustar00rootroot00000000000000PNG  IHDR2btgAMA aPLTE4aYYYAAA000Yߪ}}}}}}}}}}}}}}}}}aaa}}}}}<Y]00}Ӛ000}}}}<<}AAAMMMϛdbKGDH pHYs  ~tIME8' IDATx]a* ퟻYa/w^ '! IP;VkBc㱰0‚2 J eұO2O:R"}g@eGEGe^|9׹҅I Q FOB;ik{e>i eV`ZxBKE'ւ2 J,,(aLj۠Lx<8tc+()VKPiUM-)G @Y3?c+JVZZTtmk.8K__jВN̑flI ?.}kZZUڥhA)CBQsLixU:K?VQYKтxQH!M4]v& 7nS^iu-}m)AFW(sX(erSR&` $8.t~e*]CRzV)KgQ7CKt eSF*]GZgR&5u(([R>T^-{).2ei>20F y/d猘H-pf!~]8U-]׵J*;kJt`4%-z>2UzMMD\s@ӭZ5|߯}?ݜRM7^6` F re^rj[r@: , @ 8E0FcT2ٛ`ZIDz X\K7eẺ15>){la׫,@K_ڝ lTn0rRx8xe2i4DaP#eZ%!V@q0o&}<*ad &L! [كӝ8tpQڕ% )P* !Z` Li*Q7wBfe/ l$ZJڶk, Y8ZU%Ii -E- ,,BKlH\"KrMx=oz (6~-@Ѷ%4!5d6l)Լ  ^yﵱԴ[5~Mr+SFrwڒ,=qI)#m 5GR&_?L2|Io\6bLb2Kgs{ >> l|`R"G[xh$ͩ1P˙yS I}4,^2&(Mɴg/z,V r2_q/yMV(úH429ŖlFS8xC.)/C!90 L!D!(s5e"{) (u  nr(8lή  ete>nC^]e& oMʤ< |~J7NyL? m~t^Ja*dbQ2IN>o1oax>N(<^Bٿ᧏Mk%4&({%(Q.:l\x ef9=jt0C(TZ )0RuLE2Te9)n:$1?aUCwjIF(CtZ)#R,VrriorƐvuw&Sݩ #b 񧇗Rt-Zj%XYPBA'Y!R&ͥs/cWeJXhL+Mȉ]%feۻ,Y~2`^fFntjd gO.؞7L{ITwF[ +u+)h/eeI!Al.3_٩ip"M@ػqOMrO%II2jes*er뜊61څ;PG;?9d+)2qe^&DV%'L_7ANq e@5y}1 ǜ˔+ٱ̵鯝2E (Ml8)#mJhXɮ:ԱCZ!nhLT4'c̔!題-K?ip@#4C?$8m);=Zj f,k(2 Oh)Cj%y"Y4/-ј2ݶ.0 Bd_MS)s!8N$:Fj[p&R†nhgqj|3ʄ{=bEhMoQS0ʸ髧0! _hEo);pX8ޢ+t>N#_`xE-zd|]StoD&T2"''}pȹtq<ճFLI_e ܶߐ*@ÒDz;ʰ\f$e,k.gٝrn_̘dL-@oU2$8!eTXU;3SFVT(3:j*9(#dkFL<28檴^-՝"\Θj!׬Q2ZXE%YXxBKN5ga~Ȕ%ƿ Ŝ9yv 3]lj'J7^)=aXЛnntyQ1Gɔ-Nft!$贈*s!\ԨX)wHE!`2.Sd)2;u] Fr9mQB9\$j(+߈H"0\P&`5~ lSCOĉHzʿw G ֘yGqkߤTWQfw 2P ") H~))ML@2 GMe@jL?cO]I;d˄2J9(C#n\Lc-a;Ѓ5ʸo1gRf[̔ymLk2%k/ =JIYl7qO/⌙1Qf2[l yOv BwaF.7>c#l[@UK2Z\XE%YXxBKN>"e+],cK(e@iLcj FTj=%v*Ik"9:3Z`42 !#e`-=%C)4Źtq F`TARp"${m1/$>2>,oń\?`xVM㵻R[A4Sy eIUP|q1lH2A2)@)U6f+{H0ȁN/WPf{-upPL eb2,$@Ґ>sڼ*I#R8b/ ekdj9.#dGHvr43XX*y쀙/\g:S-pn\^PaQfA eRfyHJ}9PٓE5܌s*T˲m9W{M'~/m'0}yļq%%5"LГy%-)21H=.K^h]#0>Xt:3e\؂I7xR!1.c&S= 8ʋ~fC"8)WKs5B:G[P"e&Iqdx=&!\5w%; Bi`3og)0Bٴjl znKs)c$>nC0eK1PrVhmIMc Leيl.R2٘ʪ ޓͣb%b0fu/Ѓ2ׂL.{eh`E{0_eb̞mc?;e{#&{[|iETsz 2 J((2˛|G3l22e qM9Oܰ|O0bw:8ʖIV;H>2 J((2ˏ|<#UWrLtO [c))z5PfdDK<]LY+5Cޞ2GJA3VvѬ1u/KedبaB]>2ozlTd+]4Y+GJd.2eJ1Zl e$eɅ'ePPfa -ex4GLJ6=f׼Rj5BZ'E`@h2e<)ovmgR挕lXqbr-:Jnq.>st$DrhiFb$9[(#dU%u#`2S&Mrg[9ՖEqrZ\h20hkzIуl{*N}2]Ȕid?<+{޻4T(#Ad3 bQfA eRf!Rl[a}7FRd˨}1-pD̠A{D^qoe&{jQe2&cgSc@juk7q*/ j(#';7e"2cA^ǿCA1R&>'c\LK#zB2a-Q?D!dLȾe-N-A- ak2o67*p-^-<ca,,(Z,O)^ɞ)BRΰwm1Z|=\+`m hhʌ_~s[t/d ZA fpvy-Iؘ@[)Ջkq^fL͖)C)-XNkq\Q Cl2xP\2OiP9-7Sd7)%9+圤fK2IL1jҙ? db}ly%}w0bzq[k@jMbSyhykskq e. L 7@A'ePfZYTh0-]& #dʄOsw:et \I(.P&OS< >\&~K?vsO7ФP¢Lu ҩ8 ɡAyd|~Hܵ:q#ԤKϔ^\l_)U:̣򹍭e۾(FR7~72)~H(S-(sS{~ʘPR~WACs)؎&҆u%fli.XL}<~SĥԡOeKS ^씡 )72[{GE.vә=Kh-&}n|)R[:7gL AdIDATorۡFڰ2ݒ"Z:SB` vGRmմDJk<ȘNymI=eBv{z'6*yH{Z~h ~ގ22c(nCp\[5$j~˟)J2bJ360MObrKxTT3}?q1d 4*-:i1qJ3*TeQ5"SS2G+76Y2),NN#r7Afo#mѥ%콷RJ}Eee0k)C[Ԕ#+gأ)cp_A@ &L_?{ "{1}ЦLǯƜ>5S:t#=Qz ?x𬒞ϘgPm4)?ϫu?`rv0G~ae [Dg}&erH}7{F)1;=DXx9ytPRK(e"eW^ wzJ \ؤ L}Wd2boA %>ade@P$hۥ޿]J@ rINj2m4)9J2)2 (s`TsX(S =^Y'R^2ϦLiQHzHύPF,%258"e\ RdDq>G2%3蘇 cUl7(&ˊ$k,'Q^z/% :gEIENDB`iptraf-ng-1.2.1/Documentation/iptraf-tcpudpsort.png000066400000000000000000000236571370555550300224400ustar00rootroot00000000000000PNG  IHDR5b9xgAMA aPLTE4aYYYAAA000Yߪ}}}}}}}}}}}}}}}}}aaa}}}}}<Y]00}Ӛ000}}}}<<}AAAMMMϛdbKGDH pHYs  ~tIME ۣe IDATx˺,LzL;?K:UDge4r^,LMY5kR3eׇ?5eФf.BK #zX[!⏊꿃ggKAMbw5ytԬl\٩@ lVb5$ۚ^*]zIGӣ0eפfʮI͔]qC25qs!>sRh>K;W(SXj>$uM,H25rS_[BۑiR/RK]s!ԭ9ٟ&GȯWnR[)PrR^T]oRO}+J,˱Rw\UzXԠ`BǶ5C/EK=v^4c*FT.%ۚ?:?Uиx,]=eGVT*%(* m[VTV9t ,KpI_C+PԠjC[pА%Fe5R5eͱԀɧš%dh VCI{(w=3b" j`ۙ˿6 N RFbI3H,3$ 5^&2Sn!%/r5"5 #q5)[-*b255}m"|Жq*8vOK!HM4^kJ:ktAC^҆T1/2S#`~\Hv79{E^ ɧ԰r&cy(N |MWn!zK9t3`4,:894"Dc(LgԤfC5SSMuP3]xI>ӛ dKA[eGۧjmOVWK1?i}@.^\|<߱!#Rik{?F&|ucX..s>~,gm{YpXSRdX "L2myI8j"<#B~jbJ52v.g{MȔyi  uS#t79'l-zoK=ɮ=/n8AHp"Z3~%TA(b)F6pЈL"/d"%+y%4m#첆mümk-z܁*Eȋ祛0 TЂ=R0S#To^pdzj kqHoF.yrN0&"CfsECM_"]Q !}4b/# J]"RԶSR.lzB"mt&L}4FG*QSy(j.-k63 4懘HJiݗbo8z\,#o0f4G¥YB'{j) <ꦣ8陯yi-y&h1U8LSRS@ P7=Ԥ)yK 㐾{Kڐv P\Ԥυ;Waw^@xzpioQ Y3m,iTO,BxU,˩&5Sv٨<^%j x*D5jN]4Ậa PGb{~l +2"Dj)e]^ӏS*<@USљt!wdLK ^9!RpW4cBB/ U6)L ܐjO`Xc4r05{ ghPupcM{pu XrV0c^'-{ĝx>j_{$Ty( 4*zjKѮbM)hh{n55{("9P-*bllkrnmM8X J:.0Y;H{ @SfDew DMkC\}5B!njpe%Ȍְ:IztTp3?=@jaVN'5[C?'NG)z( 70|oOJKμ@ܣ}1]Ӥf.5SSuP3ǫD}~ sG?C,P[h E]y@~tj(.MPB`vvcp+ٲwm!Q1K ,Mơɾo2E 2^e5,r4\;b3$u55}򣨡]2Ì[8Q{^}M8jp 5X]r搚hW{z莠Fj5A{/5(/]8GѢ}͓aOCQkUSæ;ף-lġ 6}y Ex!6jըNhR3e'*ͬaCoIM*48t$(5xsYRԐ59 5A߉A?\|矫HM١0މ݌0`O J yqz59}ԀA3\47 CeS!FgbpCIM,+5LSx$5uMjZ &5OT0uPi¤DMm7&IGbb {OAVIMug,9ڴQJOZ YC f5x5|Ů^>΅^j2A f-$AEwfK=hăvp7%PV"Ԭ㇪8?Wy 51gR5v0x%vp\ho<(#O럯AC8,NY^/߁PS/ 5j8!LӤ0aQDI S5{D0iۜvTsvp`$GRC}Kp.=Nٱ;(lٛ4J *kZ~<5kѵ5Wz'5:r>nsNIq J\ |WzCɅ2)Q1hl>¤u(<On1T~Kɡt@g_Nk_Qj|CGRAkkaDB"`l]u85ARMWEZ+l {55f,P帇NNjvanLT2v uj{(4acyO3jRR0٨y¤_}0a*QS]ߚ&t$\#p RJkhsF+v'S' s. G5)H}Ԡ'b 87BM:]xڌǞ'Jʒx0~K/ CD&lvό_f1`fC  {)~,HVuj5԰7zlm Ԓ %݌9EKTȰ}:oȋSz*eUvh'5mkVMyeD ]}FQSxZ悶5ޟFe O76k^jWuieP5鰼{)5#Q=}_[=X,p,_EB8Y"@aR|^2uP&LjJ|,K:.hZIKcA>略ux3zZzFM;QQclkP=QiJGc Y>4^D34`,QH/C_xZTK>{ tHP05mIl[(?K7[k[to,7@X8X-Rikҟ8S|TK\Ehk?SXPO-*JCPx C]ٽ$x!v>jD7_1h,dG]C dԴ0&Zc/Bdgi|;9(Ljϻ0L=>mT 7<{~28cȧ#|7q9JԔKw|j_0sdh롪o&ywr8Licٚb\pweNH{ 5f>seb|^(npȣ`ȒSفRӴk>o|X{Y(.7<@PWP1e+55;}2_wWa>AwwQ#Sٮ 5RJ~v}j5܎%줦^ f;=ʗ}{83Y0=}Ѫ몶w,~&1 ^~ح+QY5yP8uq"j(L%S{o=|¤}뱀kvO%5*ӝyocq`lC?B~ Km5(`jxR3ZGK݈ ~.{> zjzWo_[T5ye-M GG@ d < {O(Cn8z|F<5Ԩ>oP۷f[J:dR~LzT|]>;Q{9ZMz`7HC%5|$߷vBMkŃ)=廩}`{omvY1Trnznc(<ʊ^K3̷T3MjZ n)L%S5R0cߦi;5ƳP_r9)Vm$|1k} ~5m ;WU~wЯwPS0jjWJRx255q?m=|Jw{EM Fz^^n,kA3,jFCZnjrC~+%ˍg=&)t(1܆/7LFk$50"B5d kOM[Ep6Vϲ:\e +Woߞ.L Pթ5ÆQ]#o%/?vjXm~* 7Q&C Ba׷1X3޾ʱAe-1izrG-^Pzt9 v?[{^2MwKaRô})@U{ [U|H{C< +iVÕ\LP\*ju65c|ޕXIF{m^DlƵ=5ҽy:}j 7tkJݻ{IpaR-7s@ζP9b/QC55qvMz(";uw5%jza?b fj& p>[RfS;.#]EM,|}:g}RExuHǏ{\4i)Ljϻ0L;$¤DM?fp;ҹw05Vkjkb m*a4(P_;y5֑wf&?0jn*Hun˩3Cm~ٽ^^nèYhf5i-$әwrc-'S]joAM LMk'Q~jk۩ЌưɌeXFqP9.>|JGyˍoOÜ  s7Ӥ0y3MwKwqyP!j߲y3F>oFSTO{ed:?gzS}W|us\J,EMSӳ[C S\A?֟tUx/6N,g|3<ۻJS˱B$h\/WbjRt)5>o%\٨yoN{tM|*'q>;$5kŮoQq1<>MA3Sbs?z<25a!O԰7xtKjQj,Hr,9N@;xN}j4獩iCP*X3ж|m'&fRC#FMX ]/5#}߯{w=l^<E J7FH,XyH8$/Bu 9'j3 GA5{ԘX:ܣ kRCe|족4ua i(Lj|Y'}m\ uө9}\au4w\'5y]ޕ-“뽼5{{(83:ļHmu7fnRSQ}ZzdhRu:oְCUyWh]a[3GY5wm lEuMIMKaR4}-I S{o=|¤U'@5WT彼5q72L#vv{UZkus/ R3{BVNR]zʁl׌_G2mj͙ -c}BɱU]+5Lgi 5裂?~(TyPۚMf0 ̣]<5J&r5k{\(7\WW%Jh7CC/~ 8|ކY)2kmI#tu^FE =I/QL{ʮj;4GSW?6m>o \Sp:y)ciQ8Y؎ w cy%GsLMO۸!}ٿbGvpnrKjApZ%+!/܃t@LU&d5Uw.?:f9ioNXEj:Oy85Sh$jQ㼯ѥyOq&5XuQ$hz VstOw{䃥e`/~E+nA4VԢ VZL&LͲ*[.EGO} 7=k)w;ATBJQR9LH,umEGNQmQ#d(hS ?]&RQ_ 00),J#OL(42R#f^X{Yzlb%nH}-KX b Inj.3A5N5UU<% mbjވ ;)Vl~wmY RzͨQtѴY4j15EIouf7by 6jhxEVB-+N*e3.kT>O]. ˦>2@Qs£],W2CUhqU&H uS.]NMH5fhk𦇚H^) E,iDygԄEڳR~@ՑP/55&-#)$)j+V&񏤦ЁC5hlv͂‰),I|!5_d G{n H.%}*@ X5^, 82GƧ,0=pr*@ U Ö$2(Ի!|x*%h)iAq9*Pdc{{t[vۧ&tojt,#eOJLBMjO9e{ %S( P_Q~׃l&u!ƛH6!Ւ &d$+9ppS>uEr,Pj=,ǂoJԔIt_G!IENDB`iptraf-ng-1.2.1/Documentation/iptraf-timermenu.png000066400000000000000000000166701370555550300222330ustar00rootroot00000000000000PNG  IHDRLgAMA aiPLTEÂYYY000ϚeÚeee0eeϚee ammmeMMMA0U󲲲UWXbKGDH pHYs  ~tIME  MIDATx흋*F1vEyW: " FFE^ C`4X?>A yx-1၂&AЈC\3G <`&h wm^"IՂr<\TA4 @A0ĭis_r4 t`0P  @A0 ?`0P  @A0(`  `0P  @A0(` .`M  ?-5$<G~ (ǭ >(8 *6Nޘlb~.$蹥@aH"nHԵoq ST6h*(OobWfH<< 6s0OL &R򵥽[(؍کPx\MBiv$솽SH<$9\ v#QS_G34'KСX^ 4ǿ@nL =(؍)tPs(8PP v \UG덝xIa/W1 _\~ȡr->rU2] w1y00eCؐ)~M"tth!_BK<03 tΨ(؁ҜN"sDشIkȔL+P_:C%BEbKaK|R!S뙐d-*קK65L|0`ַ':B] xM`K&Bhԁĩŧᢂ$6 H&ֺb (Wġ"2!@s~A\7g=슘nǒoI#@7.~PPf=FVp`VQL@`7 FhMY'y_j$A3o{ wA$q_ߣ৓.w+\Z[1$= (RŌ!ce*UG [K t?FbTj@ LL]7tA碇H\GAӏ{|y?k!j$:mZ}*q/bq. &0}SwbWwqrwsx9aR12}pQEd aq D^{]I57FgSズ"`pcisY9//8?h݀6PP v @n@A( (hsUA`t)SIs(l!d>m_ݝ4QI=L3fY8ۊ}t?nVHeruazǔ Ohq߱6Z8C! 6j@x7(kV !Tθ\ ʐƯ}KC.ѻfx55}KF1`dr#r (P(Z6 9P~h[&~c/_PP𴂯y` ;KFZƼ؇(G t_ sRƯy-\}Ղ?z@n@A( (h@Ayj9K+,j'=)?`Xun;|x ead߫܆O~$[G:p&=,oy so ͐Y.3{[~A蟋OAƐmqmu|h{*4gt|6Ym;Mߧ NVWŶ_fqJւqJp]FS謋 ޴5䚙`7F+xO(ɁVP|{ ҐsB>3{[Q~.H ۼ\Б}ҾAo /QT>["eWNŏL0~/zE;+bR%6)q tkokD .Q s|- =e26PP v 4)SuRBoYnj̤fER2߳ӗ.v|S] :~+d>a_W)4ǭVxTq系`?e? TD(62岂սqc.ZtY݇[WWD,_*@_l4*74WhP2WNsuεOCHXhIձ|D.k+9Q:TVUtϒGxu*taD;4pD.Z@H3(&6T@.tS=ѥt[GѢhov:doTЦ8mNC+Ty.`yӇ8>' ʸ5 V /G^A9ߦ`erCN8W`M12`ȡʗYDq9G'+N/Sr ede*q_a l`7 ݀6P  @A0(`  UwR&.8&'ffx@=Ppyf\gx@=Ppyf\㱪?;O/=dAeq_W ;U`|D4|>Jgw^a_ǿ?:jTw/Cu3q<$k"G3v`!P*`|?Op/o,T!_gY50ՠ~?1_M$gx9B@^6k \N$o+j <`q?ׂ R Wn/g(hSБ$lSSP=p*(x 6;Ra+L2o)G~1wQ_яtio96əVxkZxEEqT7xC]?ӽ@Gp_PpYC\=d- (kN YA>^B ~.] !e۸WK(سl> C _p6 n?۱9]7eukW-s1?^".fB}3_p&?__ AE bsBf\gx>$?܇0$`d2έW/Lu7C쯻S&#? 酡&__X7'_0eɪmw ."IR 6]qniD U$dB^jx5'w|ʛ.t ?WWh|-$Gbf& cEr%扂̇ոW-4EK`#ΰۿaǝ1:k6TwBt/R0տN+fobOznTՠZ7G*{|V*ӓRA,yeoB2FNrd/#] m;qztƟAg5/8Nd,J 6]u9B;I$+ DMaZA2Yy9<k;DvRF~Οl_MIwL$$4 L#ht{|:^^URp_b;bXT9% qn8"8-]~|A=@V@:..VG`wf/_of\gx4ic9RWϽxY?2W; +U\W?XbOrVP[>Ԇyg,'\`J*X _;KHAs ]Od`lāO\˱ IJVXVC>7| h*v/>y")^E{>_şhN U+S汉U`[],lo3KϢ {q1Z9GɗXA6M>)Ӆ$+Ab;(OWz<]V=_~6$N  IbMt[.!䆊U?OO,@w)hx]A@ZA?[H_R<^U+ؼ?,k$E ٿK8*5炇Uq27g<,ZA~6` NyH#mB=W yԉTo|ex巷H?/X%Y Uw%sCTcgC<{gDSm*)< .3{<(< .3{<ZGw8#Q^<"Ppe(2\G #W+x@yD<(+HXp?2$?Ygm2҂>nb,=1C>_P.sO+tWUЬ(}#Lp, 2'O8Rpsd1qO~e7(؃8t}!7ɂdf? D-fWN;6vt(өRY g$tUn(8s7RA>YM*S~sOA끂㨽9To  (Dޔ,ɉ\JUWOg 8O[4<2=O׬d磟gޚfW<}(7?(؝(؝(؝(؝(؝כ7e{$^pO&?Li9+H)58pQ:#  kQ݃cN(OgAm$ opS-CE\M|L#ZO leD((s XGڄPA*hye*I*iB y ;50&T0^7)X*ԁ2&ޚ~S4OJ=pӄIyӄ TbP{0*ӄU P%E< ((Xl   V[+-@@ >Yul   V[+-@@ `K`P%P((Xl   VP`|I wMsiz+(O^R/,#*v"_-_g?C&jrAɘ#?'I3P`.P8g@o\͍ :j&N]@ P37ek$.B9qk:p.g=q?$>ܼz .ȠM V0@+j`#ju+@O@ `K`P%P((Xl   V[+-u@ ؋ 6g^|4P9⣁ l΀h`sG3`/>(؜{ (`  `0P  @A0(`  `0P  @A0(`  `0P  @A0(`  `0P  Spbw`?oܔ?{יլ0(S=7[|K--U|rJZQpf]P7.GNL>K&f)(`~W0%ȭUSKSW)؍ w)H[v 2ךrBg˳$^cCW̷yfU \\Ϗ,/_oj!|tF|tk'bKHvU;|EN#qI,0:&lZ/]ɇ*QJn/1gN?#qg7$3w@nqE,Db!bz LO+hPP)cWGLyI^햋Q#:n*tGF\UT9/"oʰo@(Kư"tm4jߌQμ۝ {z1R0gT_q9b^ ;vԟb}|Q (ؾ"/*??_LJ܊ t}@G `z,zʀSp+w`y)jl2{T K[Bƀ(V[LEL X)nc9 ]l})u|*^db 6t(G@Lx}3S#ӭ{jARiD=['trzȦ)g Q鐬9.(XAkiG/:@/L L)hׂZARmrXV*H=iJMT,lPA _dtzZƑb׶SP@AՁ@A e?yԹ8J;:Vrle%炛>m#JRL&K/Y>`{P]iqz̮Tm"V^xb+X tbp'P PI& ?P0p0kIENDB`iptraf-ng-1.2.1/Documentation/iptraf.xpm000066400000000000000000000001751370555550300202410ustar00rootroot00000000000000/* XPM */ static char * iptraf_xpm[] = { "5 5 2 1", " c None", ". c #15FF00", " ... ", ".....", ".....", ".....", " ... "}; iptraf-ng-1.2.1/Documentation/manual.sgml.in000066400000000000000000004776341370555550300210160ustar00rootroot00000000000000 IPTraf-ng User's Manual Version @@version@@ 1997 2003 Gerard Paul Java 2016 Phil Cameron 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. 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. 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. 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. 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. Some structure declarations were based on code copyrighted by the Regents of the University of California. About This Document 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. For Additional Information 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. Document Conventions The following symbols and typefaces are used throughout this manual: [ ] items in brackets are optional. Brackets also denote items that may or may not be displayed onscreen depending on settings or conditions. { } curly braces enclose items you choose from | the vertical bar separates choices in curly braces normal monospace 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. monospace italics italics in syntax specifications indicate items that are to be replaced with an actual item (e.g. interface should be replaced with an actual interface name, like eth0). Additional information appears distinctively set apart from the main text. This information includes Notes, Tips, or Technical Notes. Notes are additional pieces of information that may be useful or may clarify the preceeding paragraphs of the manual. Tips provide shortcuts, clarify tasks that may not be immediately obvious, or provide references to additional sources of information. Technical notes are explanations of a more technical nature and may be of more use to programmers and advanced users. Getting Started About IPTraf-ng 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. IPTraf-ng includes these major features: An IP traffic monitor that shows TCP connection information (hosts, packet/byte counts, flags, window sizes), and color-coded information about other IP packets Statistics (counts and load rates) for network interfaces in general and detailed views Statistics per TCP/UDP port Statistical breakdown according to packet sizes A LAN host monitor that returns counts and loads per detected MAC address A powerful filtering system for users to view only interesting traffic Logging An asynchronous DNS resolver for the IP traffic monitor A text-based, full-color, menu-driven user interface suitable for use on all Linux systems with terminals, especially Linux consoles and color xterms Easy configuration Fully software-based. No additional hardware required 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. Installation System Requirements IPTraf-ng requires: Hardware Requirements 16 megabytes of physical RAM (more recommended, at least 64 MB for very busy networks) 2 megabytes of free disk space for installation (more will be needed if you log high amounts of traffic over time) Pentium-class processor or higher (Pentium-II 200 MHz or higher recommended) or equivalent. One or more of the supported network interfaces. Operating System Requirements Linux kernel 2.2.0 or higher GNU C Library 2.1 or later ncurses 4.2 or later with the complete terminfo database in /usr/share/terminfo. Support for linux, vt100, xterm, xterm-color recommended. Compilation Requirements The following components are required when compiling IPTraf-ng from the source code. gcc 2.7.2.3 or later GNU C (glibc) development library 2.1 or later ncurses development libraries 4.2 or later git Availability IPTraf-ng is available in binary form from many Linux Distributions including Red Hat RHEL, Centos, Fedora, and Ubuntu. IPTraf-ng git source repository can be cloned from from: Starting and Stopping IPTraf-ng After installation, you can start the program, as root, by simply entering iptraf-ng 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. IPTraf-ng determines and makes use of the maximum number of lines and columns on the terminal. Note IPTraf-ng does not have a SIGWINCH handler; it does not adjust itself when an xterm or some other X terminal is resized. Technical note IPTraf-ng needs to refer to the terminfo database in /usr/share/terminfo. If the supplied executable program fails with Error opening terminal, your terminfo database may be located somewhere else. You can control the terminfo search path by using the TERMINFO environment variable. For example, if you're using the sh or bash shell, and your terminfo database is in /usr/lib/terminfo (typical for Slackware distributions), you can use the commands: TERMINFO=/usr/lib/terminfo export TERMINFO You can place these commands in your ~/.profile or the systemwide /etc/profile startup files. You can also create a symbolic link named /usr/share/terminfo to let it point to your existing terminfo (assuming again your terminfo is in /usr/lib/terminfo): ln -s /usr/lib/terminfo /usr/share/terminfo 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. Command-line Options IPTraf-ng has a few optional command-line parameters. As with most UNIX commands, IPTraf-ng command-line parameters are case-sensitive (-l is NOT the same as -L). The following command-line parameters can be supplied to the iptraf-ng command: -i iface causes the IP traffic monitor to start immediately on the specified interface. If -i all is specified, all interfaces are monitored. -g starts the general interface statistics -d iface shows detailed statistics for the specified interface -s iface starts the TCP/UDP traffic monitor for the specified interface -z iface starts the packet size breakdown for the specified interface -l iface starts the LAN station monitor on the specified interface. If -l all is specified, all LAN interfaces are monitored. -t timeout The -t 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 -t parameter is ignored in menu mode. If this parameter is not specified, the facility runs until the exit keystroke is pressed. -B Redirects all terminal output to the "bit bucket" /dev/null, closes standard input, and places the program in the background. This parameter can be used only with one of the -i, -g, -d, -s, -z, or -l parameters. See Background Operation in Chapter 9. -B is ignored in menu mode. -L filename 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 Configure... menu. If this parameter is omitted in background mode, the default log filename is used. This parameter always turns on logging. If an absolute path is not specified, the log file will be created in the default log file directory -f 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. The -f 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. The -f parameter may be used together with the others. -h displays a short help screen While the command-line options are case-sensitive, interactive keystroke at the IPTraf-ng full-screen interface are not. Using the Menus Menu items with a trailing ellipsis (...) 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. 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.
The IPTraf-ng Main Menu
Exiting IPTraf-ng You can exit IPTraf-ng with the Exit command in the main menu. 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 -t command-line parameter will automatically exit the facility after the specified length of time without any confirmation as well. Daemon facilities started with the -B parameter will immediately terminate after being sent a USR2 signal. See background operation in chapter 9 for more information.
Preparing to Use IPTraf-ng This chapter provides information applicable to all of IPTraf-ng's statistical monitors. Number Display Notations IPTraf-ng initially returns exact counts of bytes and packets. However, as they grow larger, IPTraf-ng begins displaying them in increasingly higher denominations. 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. Numeric Display Notations 1024067exactly 1024067 1024Kapproximately 1024000 1024Mapproximately 1024000000 1024Gapproximately 1024000000000 1024Tapproximately 1024000000000000
These notations apply to both packet and byte counts.
Instances and Logging 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. 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 Logging option is turned on (see the Configuration 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. If you don't specify an absolute path, the log file will be placed in: /var/log/iptraf-ng.
The logfile prompt dialog
See the Logging section in the Configuration chapter for detailed information on logging. See also the documentation on each statistical facility for the default log file names. The default log file names will also be used if the -B parameter is used to run IPTraf-ng in the background. You can override the defaults with the -L parameter. See Background Operation in Chapter 9.
Screen Update Delays A configuration option is available to control screen update speed. See the Screen update interval... configuration option under the Configuration chapter of this manual. Supported Network Interfaces IPTraf-ng currently supports the following network interface types and names. lo The loopback interface. Every machine has one, and has an IP address of 127.0.0.1. lo is also indicated if data is detected on the dummyn interface(s). ethn An Ethernet interface. n starts from 0. Therefore, eth0 refers to the first Ethernet interface, eth1 to the second, and so on. Most machines only have one. fddin An FDDI interface. n starts from 0. pppn A PPP interface. n starts from 0. slin A SLIP interface. n starts from 0. plipn PLIP interfaces. These are point-to-point IP connections using the PC parallel port. ipsecn This refers to Free s/WAN (and possibly other) logical VPN interfaces. sbnin SBNI long-range modem interfaces dvbn, sm200, sm300 DVB satellite-receive interfaces wlann, wvlann Wireless LAN interfaces tunn general logical tunnel interfaces brgn general logical bridge interfaces hdlcn Frame Relay base (FRAD) interfaces (non-PVC) pvcn Frame Relay Permanent Virtual Circuit interfaces Your system's network interfaces must be named according to the schemes specified above.
The IP Traffic Monitor Executing the first menu item or specifying -i to the iptraf-ng 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. 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 Active indicator to the window you want to control.
The IP traffic monitor
The Upper Window 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: Source address and port Packet count Byte count Source MAC address Packet Size Window Size TCP flag statuses Interface 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. 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 Activity mode switch in the Configure... menu. 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. 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. Just because a host entry appears at the upper end of a connection bracket doesn't mean it was the initiator of the connection. Each entry in the window contains these fields: Source address and port The source address and port indicator is in address:port format. This indicates the source machine and TCP port on that machine from which this data is coming. The destination is the host:port at the other end of the bracket. Packet count The number of packets received for this direction of the TCP connection Byte count 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. Source MAC address The address of the host on your local LAN that delivered this packet. This can be viewed by pressing M once if Source MAC addrs in traffic monitor is enabled in the Configure... menu. Packet Size 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. Window Size The advertised window size of the most recently received packet. This item is visible if you press M for more TCP information. Flag statuses The flags of the most recently received packet. S SYN. A synchronization is taking place in preparation for connection establishment. If only an S is present (S---) the source is trying to initiate a connection. If an A is also present (S-A-), this is an acknowledgment of a previous connection request, and is responding. A ACK. This is an acknowledgment of a previously received packet P PSH. A request to push all data to the top of the receiving queue U URG. This packet contains urgent data RESET RST. The source machine indicated in this direction reset the entire connection. The direction entries for reset connections become available for new connections. DONE 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. CLOSED 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. - The flag is not set 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 Source MAC addrs in traffic monitor option is enabled in the Configure... menu). N/A 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). If the Source MAC addrs in traffic monitor option is not enabled, pressing M simply toggles between the counts and the packet and window sizes. 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 Configure... menu. The Asynchronous Resolving Process 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. 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. The resolving process will spawn up to 200 children to process reverse DNS queries. Tip If you notice unusual SYN activity (too many initial (S---) 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. 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 Configure... menu. Some early entries may have a > 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 > 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 > partial. Some > 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.) Direction entries also become available for reuse if an ICMP Destination Unreachable message is received for the connection. 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. Technical note: IP Forwarding and Masquerading 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 -q parameter is no longer required to suppress the warning screen. 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. 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. Closed/Idle/Timed Out Connections 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. IPTraf-ng can be set to automatically remove all closed, reset, and idle entries with the TCP closed/idle persistence... configuration option. You can also press the F key to immediately clear them at any time. Note The TCP timeout... 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 TCP closed/idle persistence... parameter flushes entries that have been idle for the number of minutes defined by the TCP timeout... option. Sorting TCP Entries 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. The sort operation compares the larger values in each connection entry pair and sorts the counts in descending order. 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.
The IP traffic monitor sort criteria
Lower Window The lower window displays information about the other types of traffic on your network. The following protocols are detected internally: User Datagram Protocol (UDP) Internet Control Message Protocol (ICMP) Open Shortest-Path First (OSPF) Interior Gateway Routing Protocol (IGRP) Interior Gateway Protocol (IGP) Internet Group Management Protocol (IGMP) General Routing Encapsulation (GRE) Layer 2 Tunneling Protocol (L2TP) IPSec AH and ESP protocols (IPSec AH and IPSec ESP) Address Resolution Protocol (ARP) Reverse Address Resolution Protocol (RARP) Other IP protocols are looked up from the /etc/services file. If /etc/services doesn't contain information about that protocol, the protocol number is indicated. Non-IP packets are indicated as Non-IP in the lower window. Note The source and destination addresses for ARP and RARP entries are MAC addresses. 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. 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. UDP packets are also displayed in address:port 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). UDPRed on White ICMPYellow on Blue OSPFBlack on Cyan IGRPBright white on Cyan IGPRed on Cyan IGMPBright green on Blue GREBlue on white ARPBright white on Red RARPBright white on Red Other IPYellow on red Non-IPYellow on Red 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. 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 Active. If your terminal can be resized (e.g. xterm), you may do so before starting IPTraf-ng. 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 Configure... menu. Entry Details 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. ICMP ICMP entries are displayed in this format: ICMP type [(subtype)] (size bytes) from source to destination [(src HWaddr srcMACaddress)] on interface where type could be any of the following: echo req, echo rply ICMP echo request and reply. Usually used by the ping program and other network monitoring and diagnostic program. dest unrch 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. redirct ICMP redirect. Usually generated by a router to tell a host that a better gateway is available. src qnch The ICMP source quench is used to stop a host from transmitting. It's a flow control mechanism for IP. time excd 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. router adv ICMP router advertisement router sol ICMP router solicitation timestmp req ICMP timestamp request timestmp rep ICMP timestamp reply info req ICMP information request info rep ICMP information reply addr mask req ICMP address mask request addr mask rep ICMP address mask reply param prob ICMP parameter problem bad/unknown An unrecognized ICMP packet was received, or the packet is corrupted. The destination unreachable message also includes information on the type of error encountered. Here are the destination unreachable codes: ntwk network unreachable host host unreachable proto protocol unreachable port port unreachable pkt fltrd packet filtered (normally by an access rule on a router or firewall) DF set the packet has to be fragmented somewhere, but its don't fragment (DF) bit is set. src rte fail source route failed src isltd source isolated (obsolete) net comm denied network communication denied host comm denied host communication denied net unrch for TOS network unreachable for specified IP type-of-service host unrch for TOS host unreachable for specified IP type-of-service prec violtn precedence violation prec cutoff precedence cutoff dest net unkn destination network unknown dest host unkn destination network unknown For more information on ICMP, see RFC 792. OSPF OSPF messages also include a little more information. The format of an OSPF message in the window is: OSPF type (a=area r=router) (sizebytes) from source to destination [(src HWaddr srcMACaddress)] on interface The type can be one of the following: hlo OSPF hello. Hello messages establish OSPF communications and keep routers informed of each other's presence. DB desc OSPF Database Description LSR OSPF Link State Request LSU OSPF Link State Update. Messages indicating the states of the OSPF network links LSA OSPF Link State Acknowledgment The entries in parentheses: a=area The area number of the OSPF message r=router 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. 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 MCAST.NET domain. Such multicast addresses are defined as follows: 224.0.0.5 (OSPF-ALL.MCAST.NET) OSPF all routers 224.0.0.6 (OSPF-DSIG.MCAST.NET) OSPF all designated routers See RFC 1247 for details on the OSPF protocol. Additional Information 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 ip_traffic-n.log (where n 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 ip_traffic-1.log.) When started with the -i parameter, the log filename can be specified with the -L parameter. See the Command-line Parameters section above for more information. 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 filter. See Chapter 7, Filters for more information on IPTraf-ng's filters. 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 iptraf-ng -i).
Network Interface Statistics 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. General Interface Statistics 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 Detailed interface statistics option is also available. The activity indicators can be toggled between kbits/s and kbytes/s with the Activity mode configuration option. 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. This monitor is affected by IPTraf-ng's filters as described in Chapter 7. Copies of the statistics are written to the log file iface_stats_general.log at regular intervals if logging is enabled. See the Logging option int the Configuration chapter. This facility can be started directly from the command line with the -g option to the iptraf-ng command. When started from the command line, the log filename and log interval can be specified with the -L and -I parameters respectively. See the Command-line Parameters section above for more information.
The general interface statistics screen
You can press X or Q to return to the main menu.
Detailed Interface Statistics The third menu option displays packet statistics for any selected interface. It provides basically the same information as the General interface statistics option, with additional details. This facility provides the following information: Total packet and byte counts IP packet and byte counts TCP packet and byte counts UDP packet and byte count ICMP packet and byte counts Other IP-type packet and byte counts Non-IP packet and byte counts Checksum error count Interface activity Broadcast packet and byte counts 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.
The detailed interface statistics screen
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. This facility also displays incoming and outgoing counts and data rates. 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. The rate indicators can be set to display kbits/s or kbytes/s with the Activity mode configuration option. Note 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. The figures are logged at regular intervals if logging is enabled. The default log file name at the prompt is iface_stats_detailed-iface.log where iface is the selected interface for this session (for example, iface_stats_detailed-eth0.log). If you wish to start this facility directly from the command line, you can specify the -d parameter and an interface to monitor. For example, iptraf-ng -d eth0 starts the statistics for eth0. The interface must be specified, or IPTraf-ng will not start the facility. When started from the command line, the log filename and log interval can be specified with the -L and -I parameters respectively. See the Command-line Parameters section above for more information. Note 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. 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. This facility's output is also affected by IPTraf-ng's filters. See Chapter 7 for more information on filters. 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).
Statistical Breakdowns Statistical breakdowns contain two facilities that break down traffic counts by either packet size or TCP/UDP port. Packet Sizes 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. This facility provides an idea as to the packet sizes passing over your network, and can aid in network (re)design decisions.
The packet size statistical breakdown
If logging is enabled, copies of the statistics are written at regular intervals to a log file. The default log file name is packet_size-iface.log where iface is the selected interface for this session (for example, packet_size-eth0.log). IPTraf-ng's filters do not affect this facility. The packet size breakdown can also be invoked straight from the command line by specifying the -z iface parameter. The interface parameter is required. For example, this command runs the facility on interface eth0. iptraf-ng -z eth0 When started from the command line, the log filename and log interval can be specified with the -L and -I parameters respectively. See the Command-line Parameters section above for more information. To exit, press X or Ctrl+X.
TCP and UDP Traffic Statistics 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).
The TCP/UDP service monitor
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. Byte counts include the IP header and payload only. The data link header is not included. The protocol/port indicators are color-coded for easier identification on color terminals. TCP indicators are in yellow, UDP in bright green. 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 Configure.../Additional ports... menu item. See the section below. If logging is enabled, The statistics are also written to a log file (the default name is tcp_udp_services-iface.log, where iface is the selected interface (for example, tcp_udp_services-eth0.log). 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. 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). Sorting TCP/UDP Entries 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. Port numbers are sorted in ascending order (least first) but statistics are sorted in descending order (largest counts first). As with the IP traffic monitor, sorting is performed only with this sequence. Automatic sorting is not performed so as not to affect performance.
The TCP/UDP monitor's sort criteria
Additional Information IPTraf-ng's filters affect the output of this facility. See Chapter 7, Filters for more information about filters. If you wish to start this facility from the command line, you can use the -s option followed by an interface to monitor. For example, iptraf-ng -s eth0 brings up this module for traffic on eth0. The interface must be specified, or IPTraf-ng will drop back to the shell. When started from the command line, the log filename and log interval can be specified with the -L and -I parameters respectively. See the Command-line Parameters section above for more information.
LAN Station Statistics 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. 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: Total packets incoming IP packets incoming Total bytes incoming Incoming rate Total packets outgoing IP packets outgoing Total bytes outgoing Outgoing rate The byte counts include the data link header. The activity indicators can be set to display kbits/s or kbytes/s with the Activity mode configuration option. This facility works only for Ethernet, PLIP, and FDDI frames. Loopback. SLIP/PPP networks are not monitored here.
The LAN station monitor
Copies of the statistics are written to a log file at regular intervals if logging is enabled. The default log file name is lan_statistics-n.log, where n is the instance number of this facility (for example, if this is the first instance, the generated default log file name is lan_statistics-1.log). Sorting the LAN Station Monitor Entries 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.
The LAN station monitor's sort criteria When started from the command line, the log filename and log interval can be specified with the -L and -I parameters respectively. See the Command-line Parameters section above for more information. Additional Information 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 -l command-line option). The output of this facility is affected by any applied IPTraf-ng filter. Filters 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. The IPTraf-ng filter management system is accessible through the Filters... submenu.
The Filters submenu
IP Filters The Filters/IP... 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.
The IP filter menu
Defining a New Filter 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 Define new filter... option. 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.
The IP filter name dialog
Press Enter when you're done with that box. As an alternative, you can also press Ctrl+X to cancel the operation. The Filter Rule Selection Screen 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.
The filter rule selection screen. Selecting an entry displays that set for editing
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. 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). 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. 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.
Entering Filter Rules 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. You'll notice two sets of fields, marked Source and Destination. You fill these out with the information about your source and targets. Fill out the host name or IP address of the hosts or networks in the first field marked Host name/IP Address. Enter it in standard dotted-decimal notation. When done, press Tab to move to the Wildcard mask 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: To recognize the host 207.0.115.44 IP address207.0.115.44 Wildcard mask255.255.255.255 To recognize all hosts belonging to network 202.47.132.x IP address202.47.132.0 Wildcard mask255.255.255.0 To recognize all hosts with any address: IP address0.0.0.0 Wildcard mask0.0.0.0 The IP address/wildcard mask mechanism of the display filter doesn't recognize IP address class. It uses a simple bit- pattern matching algorithm. 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). 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. Tip See the Linux Network Administrator's Guide if you need more information on IP addresses and subnet masking. Tip 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 address/bits where the address is the IP address or host name and bits is the number of 1-bits in the mask. For example, if you want to mask 10.1.1.0 with 255.255.255.0, note that 255.255.255.0 has 24 1-bits, so instead of specifying 255.255.255.0 in the wildcard mask field, you can just enter 10.1.1.0/24 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. 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. The Port 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). Non-TCP and non-UDP packets are not affected by these fields, and these are used only when filtering TCP or UDP packets. Fill out the second set of fields with the parameters of the opposite end of the connection. Tip Any address or mask fields left blank default to 0.0.0.0 while blank Port 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 Source fields, while leaving the Destination fields blank. 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 Y is matched against the filter's defined IP addresses and ports, otherwise they don't pass through this filter rule. If you want to evaluate all IP packets just mark with Y the All IP field. For example, if you want to see only all TCP traffic, mark the TCP field with Y. The long field marked Additional protocols allows you to specify other protocols by their IANA number. (You can view the common IP protocol number in the /etc/protocols 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. For example, to see the RSVP (46), IP mobile (55), and protocols (101 to 104), you use an entry that looks like this: 46, 55, 101-104 It's certainly possible to specify any of the protocols listed above in this field. Entering 1-255 is functionally identical to marking All IP with a Y. The next field is marked Include/Exclude. This field allows you to decide whether to include or filter out matching packets. Setting this field to I causes the filter to pass matching packets, while setting it to E causes the filter to drop them. This field is set to I by default. The last field in the dialog is labeled Match opposite. When set to Y, 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. Note 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 Y. Filters for UDP and other IP protocols do not automatically match packets in the opposite direction unless you set the field to Y, even in the IP traffic monitor. 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. Note 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.
The IP filter parameters dialog
Examples To see all traffic to/from host 202.47.132.1 from/to 207.0.115.44, regardless of TCP port Host name/IP Address202.47.132.2207.0.115.44 Wildcard mask255.255.255.255255.255.255.255 Port00 ProtocolsTCP: Y Include/ExcludeI Match oppositeY To see all traffic from host 207.0.115.44 to all hosts on network 202.47.132.x Host name/IP Address207.0.115.44202.47.132.0 Wildcard mask255.255.255.255255.255.255.0 Port00 ProtocolsAll IP: Y Include/ExcludeI Match oppositeN To see all Web traffic (to and from port 80) regardless of source or destination Host name/IP Address0.0.0.00.0.0.0 Wildcard mask0.0.0.00.0.0.0 Port800 ProtocolsTCP: Y Include/ExcludeI Match oppositeY To see all IRC traffic from port 6666 to 6669 Host name/IP Address0.0.0.00.0.0.0 Wildcard mask0.0.0.00.0.0.0 Port06666 to 6669 ProtocolsTCP: Y Include/ExcludeI Match oppositeY To see all DNS traffic, (TCP and UDP, destination port 53) regardless of source or destination Host name/IP Address0.0.0.00.0.0.0 Wildcard mask0.0.0.00.0.0.0 Port053 ProtocolsTCP: Y UDP: Y Include/ExcludeI Match oppositeY To see all mail (SMTP) traffic to a single host (202.47.132.2) from anywhere Host name/IP Address0.0.0.0202.47.132.2 Wildcard mask0.0.0.0255.255.255.255 Port025 ProtocolsTCP: Y Include/ExcludeI Match oppositeN To see traffic from from/to host sunsite.unc.edu to/from cebu.mozcom.com Host name/IP Addresssunsite.unc.educebu.mozcom.com Wildcard mask255.255.255.255255.255.255.255 Port00 ProtocolsAll IP: Y Include/ExcludeI Match oppositeY To omit display of traffic to/from 140.66.5.x from/to anywhere Host name/IP Address140.66.5.00.0.0.0 Wildcard mask255.255.255.00.0.0.0 Port00 ProtocolsAll IP: Y Include/ExcludeE Match oppositeY You can enter as many parameters as you wish. All of them will be interpreted until the first match is found. Excluding Certain Sites 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 E in the Include/Exclude field, and define a general catch-all entry with source address 0.0.0.0, mask 0.0.0.0, port 0, and destination 0.0.0.0, mask 0.0.0.0, port 0, tagged with an I in the Include/Exclude field as the last entry. For example: To see all traffic except all SMTP (both directions), Web (both directions), and traffic (only) from 207.0.115.44 Host name/IP address0.0.0.00.0.0.0 Wildcard mask0.0.0.00.0.0.0 Port250 ProtocolsTCP: Y Include/ExcludeE Match oppositeY Host name/IP address0.0.0.0 0.0.0.0 Wildcard mask0.0.0.00.0.0.0 Port800 ProtocolsTCP: Y Include/ExcludeE Match oppositeY Host name/IP address207.0.115.440.0.0.0 Wildcard mask255.255.255.2550.0.0.0 Port00 ProtocolsAll IP: Y Include/ExcludeE Match oppositeN Host name/IP address0.0.0.00.0.0.0 Wildcard mask0.0.0.00.0.0.0 Port00 ProtocolsAll IP: Y Include/ExcludeI Match oppositeN Tip To filter out all TCP, define a filter with a single entry, with a source of 0.0.0.0 mask 0.0.0.0 port 0, and a destination of 0.0.0.0 mask 0.0.0.0 port 0, with the Include/Exclude field marked E (exclude). Then apply this filter.
Applying a Filter The above steps only add the filter to a defined list. To actually apply the filter, you must select Apply filter... 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. The applied filter stays in effect over exits and restarts of the IPTraf-ng program until it is detached. Editing a Defined Filter Select Edit filter... 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. 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. 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. 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. Pressing D deletes the currently pointed entry. Press X or Ctrl+X to end the edit and save the changes. Note If you're editing the currently applied filter, you will need to re-apply the filter for the changes to take effect. Note 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. Deleting a Defined Filter Select Delete filter... 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. Detaching a Filter The Detach filter option deactivates the filter currently in use. Selecting this option causes all TCP traffic to be passed to the monitors. When you're done with the menu, just select the Exit menu option.
ARP, RARP, and other Non-IP Packet Filters The Non-IP filter option toggles the display and logging of all non-IP packets, except ARP and RARP, which are toggled separately.
Configuring IPTraf-ng IPTraf-ng can be easily configured with the Configure... item in the main menu. The configuration is stored in the /var/local/iptraf-ng/iptraf.cfg 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.
The IPTraf-ng configuration menu
Toggles Reverse DNS Lookups 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. This option is off by default. TCP/UDP Service Names This option, when on, causes IPTraf-ng to display the TCP/UDP service names (smtp, www, pop3, etc.) instead of their numeric ports (25, 80, 110, etc). The number-to-name mappings will depend on the systems services database file (usually /etc/services). Should there be no corresponding service name for the port number, the numeric form will still be displayed. This setting is off by default. Note 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. Force promiscuous 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. When this option is disabled, you'll only receive information about packets coming from and entering your machine. The setting of this option affects all LAN ( Ethernet, FDDI) interfaces on your machine, if you have more than one. 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. If multiple instances of IPTraf-ng are started, the promiscuous setting is restored only upon exit of the last facility. Note 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. Color 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. Color is on by default on consoles and color xterms, off on non-color terminals like xterms and VT100s. Logging 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. The other facilities generate a log file name based on the interface they're listening on. See the descriptions on the facilities above for the default log file names. Press Enter to accept the log file name, or Ctrl+X to cancel. Canceling will turn logging off for that session. The IP traffic monitor will write the following pieces of information to its log file: Start of the traffic monitor 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.) Receipt of a FIN (with average flow rate) ACK of a FIN Timeouts of TCP entries (with average flow rate) Reset connections (with average flow rate) Everything that appears in the bottom window of the traffic monitor Stopping of the traffic monitor Each log entry includes the date and time the entry was written. Logging is also affected by the defined filters. Log files can grow very fast, so be prepared with plenty of free space and delete unneeded logs. Log write errors are not indicated. 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 Log Interval... in this chapter. IPTraf-ng closes and reopens the active log file when it receives a USR1 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. 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 USR1 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. 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). Logging comes disabled by default. The USR1 signal is caught only if logging is enabled, it is ignored otherwise. A valid specification of -L on the command line with automatically enable logging for that particular session. The saved configuration setting is not affected. Activity mode Toggles activity indicators in the interface and LAN statistics facilities between kilobits per second (kbits/s) or kilobytes per second (kbytes/s). The default setting is kilobits per second. Source MAC addrs in traffic monitor 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. No such information is displayed if the network interface doesn't use MAC addresses (such as PPP interfaces). This can be used to determine the actual source of the packets on your local LAN. The traffic monitor also logs the MAC addresses with this option enabled. The default setting is off. Timers The Timers... submenu allows you to IPTraf-ng's interval and timeout functions.
The Timers configuration submenu
TCP Timeout 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. Log Interval 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. This configuration item can be overridden with the -I 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. Screen Update Interval 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. 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. 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. Note 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. 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. In any case, this setting only affects screen updates. Capture still proceeds as fast as possible. TCP closed/idle persistence 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 0 to keep such entries on the screen indefinitely, disappearing only when replaced by new connections. Note The TCP timeout... 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 TCP closed/idle persistence... parameter flushes entries that have been closed or reset, or idle for the number of minutes defined by the TCP timeout... option.
Custom Information The remaining configuration items allow you to enter information which IPTraf-ng uses for its displays and logs. Additional ports 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. 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. You can select this option multiple times to add more values or ranges. Delete port/range Select this item to remove a higher-numbered port number or port range you entered earlier with the Additional ports... option. A window will come up containing the entered ports and ranges. Select the entry you want delete and press Enter. LAN Station Identifiers 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. Selecting the Ethernet/PLIP host descriptions... or FDDI host descriptions... options brings up a submenu asking you to add, edit, or delete descriptions. To add a new description, select the Add description... 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. 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. 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. Enter as many descriptions as you need. Press Ctrl+X at a blank dialog after you have entered the last entry These descriptions will be displayed alongside the MAC addresses in the LAN station monitor, together with the type of frame (Ethernet, PLIP, or FDDI). An existing address or description may be edited by selecting the Edit description... 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. Selecting the Delete description... 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. IPTraf 2.4 and later also recognizes the /etc/ethers file. Should a hardware address be present in the IPTraf-ng definition files and in /etc/ethers, the IPTraf-ng definition will be used. Note The description file for Ethernet and PLIP is ethernet.desc, while the FDDI mappings are stored in fddi.desc 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: address:description For example 00201e457e:Cisco 3640 gateway Do not put colons, periods, or any invalid characters in the MAC address.
Background Operation 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. Before starting a statistical facility in the background, configure IPTraf-ng in the usual way (set filters, add TCP/UDP ports, etc). 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 (-t) parameter if you wish, and the -B parameter to actually daemonize the program. For example, to run the IP traffic monitor in the background for all interfaces, issue the command iptraf-ng -i all -B To run the detailed interface statistics on interface eth0 for 5 minutes in the background: iptraf-ng -d eth0 -t 5 -B 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 ps x 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: kill -USR2 pid 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. The -B 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. The log file can be specified with the -L 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 /var/log/iptraf-ng. The logging interval for all facilities (except the IP traffic monitor) can also be overriden with the -I command-line parameter. Messages 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 iptraf-ng.log file in the IPTraf-ng log directory (normally /var/log/iptraf-ng. IPTraf-ng Messages Unable to create config file 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 /var/local/iptraf-ng does not exist. Can also be generated if you have a disk problem or if you have too many files open. Unable to read config file The configuration record cannot be read. You most likely have a disk problem. Unable to write config file The configuration file cannot be written. You either have a disk problem, or (more likely), your disk is full. Enter an appropriate description for this filter Enter something to clearly describe the filter you are defining. Error loading filter list file IPTraf-ng cannot access the list of defined TCP or UDP filters. Can also be an indicator of a bad disk. Error writing filter list file The filter list file cannot be written to. You may have trouble accessing your filters. Unable to read TCP/UDP/misc IP filter file IPTraf-ng cannot read the filter data off the file. Could be caused by a bad disk. Error opening filter data file IPTraf-ng cannot open the filter file. Could be caused by a shortage of file descriptors or a bad disk. Unable to write filter data IPTraf-ng cannot add the newly defined filter to the filter list. This may be due to a bad disk. Cannot create filter data file IPTraf-ng cannot create the filter record file. The defined filter is lost. Unable to save filter changes IPTraf-ng cannot save the changes you made to the filter. You probably have a disk error. Unable to write filter state information 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. Unable to save interface flags IPTraf-ng was unable to save the flags of the network interfaces. This is probably due to a bad installation or full filesystem. Unable to retrieve saved interface flags IPTraf-ng was unable to retrieve the save interface flags. Probably again due to a bad installation or full filesystem. protocol filter data file in use; try again later Filter state file in use; try again later 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. Unable to resolve hostname The indicated host name in the filter cannot be resolved into an IP address. Check the local hosts database /etc/hosts or your machine's DNS configuration or DNS server. The filter parameters will not be used. Unable to open host description file 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. Unable to write host description 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. No descriptions You tried to edit or delete a description with no previous descriptions defined. Cannot open log file There is a problem opening the log file. There is most likely a problem with the disk, or there are too many open files. Unable to obtain interface list IPTraf-ng was unable to retrieve the list of network interfaces from the /proc filesystem. This may be due to a badly configured kernel. IPTraf-ng needs /proc filesystem support. No active interfaces. Check their status or the /proc filesystem. IPTraf-ng found no active interfaces. Either all interfaces are down or the /proc/net/dev file was empty or unavailable. Activate at least one interface or check the /proc/net/dev file. Unable to obtain interface parameters for interface The system call to retrieve the interface's flags failed. Check your interface or kernel driver. Promisc change failed for interface The system call to change the promiscuous flag failed. Check your interface or its kernel driver. Unable to open raw socket for flag change IPTraf-ng was unable to open the necessary socket for the promiscuous change operation. May be due to a shortage of file descriptors. Unable to open socket for MTU determination Returned by the facility for detailed interface statistics if the raw socket's opening sequence failed. The facility will abort. Unable to open raw socket IPTraf-ng was unable to open the raw socket for packet capture. May be due to a shortage of file descriptors. Reminder 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. Unable to obtain interface MTU The detailed statistics facility was unable to obtain the maximum transmission unit (MTU) for the selected interface. The facility will abort. Specified interface not supported The interface specified with the -i, -d, -s, -l, or -z command-line parameters is not supported by IPTraf-ng. Specified interface not active The interface specified with the -i, -d, -s, -l, or -z command-line parameters is supported, but not currently activated. Fatal: memory allocation error 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. Technical note This is actually a response to the segmentation fault error (SIGSEGV). This program can be run only by the system administrator 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 Your TERM variable is not set The TERM (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 TERM variables set to linux. Received TERM signal Not related to the previous message. The TERM (terminate) signal is normally used to gracefully shut down a program. This message simply indicates that the TERM signal was caught and IPTraf-ng is attempting to shut down as gracefully as possible. Invalid option or missing parameter, use iptraf-ng -h for help The -i, -d, -s, -l, or -z options were specified but no interface was specified on the command line. These parameters require a valid interface name (or all for -i or -l). This message also appears if an unknown option is passed to the iptraf-ng command. Warning: unable to tag this process 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 make install procedure or the Setup in the distribution's top-level directory. Warning: unable to tag facility 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. facility already running/listening on interface 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. General interface statistics already active in another process Only one instance of the general interface statistics can run at a time. Duplicate port/range entry 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 No custom ports There are no ports or port ranges earlier added. There's nothing to delete. Can't get communication sockets; lookups will block IPTraf-ng cannot communicate with the resolving process. IPTraf-ng will fall back to blocking lookups. Can't spawn new process; lookups will block IPTraf-ng cannot start a new process. This may be due to memory shortage. IPTraf-ng will fall back to blocking lookups. Fork error, IPTraf-ng cannot run in background IPTraf-ng cannot start a new process, and can go into the background. This may be due to memory shortage. IPTraf-ng aborts. No memory for new filter entry IPTraf-ng was unable to allocate memory for a new filter entry. Most likely due to memory shortage. Memory Low 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. Note 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. IPC Error 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 rvnamed-ng.log file. Error opening terminal: terminal The screen management routines cannot find the terminfo entry for your terminal. IPTraf-ng expects the terminfo database located in /usr/share/terminfo. This error could occur when your terminfo database is located somewhere else. See the section on controlling the terminfo search path. This will end your IPTraf-ng session 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. Resolving Process Messages Resolving process does not send messages to the screen. It writes its messages to the file rvnamed-ng.log in the IPTraf-ng log directory. Unable to open child communication socket 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. Unable to open client communication socket 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. Error binding client communication socket Error binding child communication socket Resolving process was unable to assign a name to the indicated communication socket. This may be due to a bad, full or corrupted filesystem. Fatal error: no memory for descriptor monitoring Resolving process ran out of memory. IPTraf-ng will resort to blocking and may freeze. Error on fork, returning IP address 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. Maximum child process limit reached 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. 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. GNU Free Documentation License Version 1.1, March 2000
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.
PREAMBLE 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. 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. 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. APPLICABILITY AND DEFINITIONS 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". 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. 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. 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. 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. 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". 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. 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. VERBATIM COPYING 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. You may also lend copies, under the same conditions stated above, and you may publicly display copies. COPYING IN QUANTITY 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. 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. 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. 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. MODIFICATIONS 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: 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. 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). State on the Title page the name of the publisher of the Modified Version, as the publisher. Preserve all the copyright notices of the Document. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices. 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. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice. Include an unaltered copy of this License. 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. 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. 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. 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. Delete any section entitled "Endorsements". Such a section may not be included in the Modified Version. Do not retitle any existing section as "Endorsements" or to conflict in title with any Invariant Section. 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. 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. 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. 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. COMBINING DOCUMENTS 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. 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. 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." COLLECTIONS OF DOCUMENTS 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. 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. AGGREGATION WITH INDEPENDENT WORKS 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. 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. TRANSLATION 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. TERMINATION 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. FUTURE REVISIONS OF THIS LICENSE 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 http://www.gnu.org/copyleft/. 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. How to use this License for your documents 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:
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".
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. 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.
iptraf-ng-1.2.1/Documentation/stylesheet-images/000077500000000000000000000000001370555550300216575ustar00rootroot00000000000000iptraf-ng-1.2.1/Documentation/stylesheet-images/next.gif000066400000000000000000000017041370555550300233260ustar00rootroot00000000000000GIF87a#!!))11BBJJRRcckkƌΔΥ֭޵,#+H*\ȰÂL(!ć %pQ "8T@(>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~, HA*ثR:[1F{1J&R<(Zʓ[Hi&L5 :+ub)LS`QzRAJ5kr͚3F Ftn9 <Ҙ9Mu lFQE=5k-5Szҿw=QbsT¸$eJ{Jq\ǫ=@W˚Z!l3ƦR<-%3!c[B*'{ƚxyǨ^Sj lĊQ9o;6$H;iptraf-ng-1.2.1/Documentation/stylesheet-images/prev.gif000066400000000000000000000016601370555550300233250ustar00rootroot00000000000000GIF87a#!!))11BBJJRRkkssƌΔΥ֭,#)H*\ȰCH|bP(@":(P`D@ 4  Ӟ>A,J$ (u U0"A zh@#XA@ H@W߿; ;iptraf-ng-1.2.1/Documentation/stylesheet-images/tip.gif000066400000000000000000000020051370555550300231370ustar00rootroot00000000000000GIF87a  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~, HA*xX)J"Btvoa{&!%J,2M3QUQsj)TK!s W&tV{{BYTI7yFЛх*^Uh k`֔x˞ )Hv[?]m&V'^BxpBÀ#DẂV2 g-Oz3& kQ«k='ۘɔ=x"m|_@;iptraf-ng-1.2.1/Documentation/stylesheet-images/up.gif000066400000000000000000000016321370555550300227740ustar00rootroot00000000000000GIF87a#!!))11BBcckkƌΔ޵,##H*\p Dh` @ D(d ,(`KF@Pq̩PB "0PTrL jNjjMsB|4˶m€;iptraf-ng-1.2.1/FAQ000066400000000000000000000061471370555550300137540ustar00rootroot00000000000000This is the beginning of a FAQ for IPTraf-ng. --- Q: Could you include support for 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 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. iptraf-ng-1.2.1/GEN-VERSION-FILE000077500000000000000000000012011370555550300156030ustar00rootroot00000000000000#!/bin/bash GVF=VERSION-FILE DEF_VER=1.2.1 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 } iptraf-ng-1.2.1/INSTALL000066400000000000000000000007471370555550300144530ustar00rootroot00000000000000Basic 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 iptraf-ng-1.2.1/LICENSE000066400000000000000000000431051370555550300144220ustar00rootroot00000000000000 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. Copyright (C) 19yy 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. , 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. iptraf-ng-1.2.1/Makefile000066400000000000000000000262471370555550300150650ustar00rootroot00000000000000# 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 -Werror=format-security LDFLAGS = IPTRAF_CFLAGS := -std=gnu99 -D_GNU_SOURCE ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS) $(IPTRAF_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 . 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 iptraf-ng-1.2.1/README000066400000000000000000000057521370555550300143030ustar00rootroot00000000000000========================================================================== 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. iptraf-ng-1.2.1/README.contact000066400000000000000000000010531370555550300157230ustar00rootroot00000000000000============================================================================ 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/ iptraf-ng-1.2.1/README.indent000066400000000000000000000007201370555550300155510ustar00rootroot00000000000000Sources 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 iptraf-ng-1.2.1/README.interfaces000066400000000000000000000042721370555550300164210ustar00rootroot00000000000000============================================================================ 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 -- Phil iptraf-ng-1.2.1/README.resolving000066400000000000000000000036251370555550300163070ustar00rootroot00000000000000============================================================================ 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. iptraf-ng-1.2.1/iptraf-ng-logrotate.conf000066400000000000000000000002071370555550300201450ustar00rootroot00000000000000# Logrotate file for iptraf /var/log/iptraf/*.log { compress delaycompress missingok notifempty rotate 4 create 0600 root root } iptraf-ng-1.2.1/src/000077500000000000000000000000001370555550300142015ustar00rootroot00000000000000iptraf-ng-1.2.1/src/addproto.h000066400000000000000000000006621370555550300161720ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/arphdr.h000066400000000000000000000014441370555550300156350ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/attrs.h000066400000000000000000000014431370555550300155110ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/built-in.h000066400000000000000000000003561370555550300161010ustar00rootroot00000000000000/* 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 iptraf-ng-1.2.1/src/capt-mmap-v2.c000066400000000000000000000077471370555550300165700ustar00rootroot00000000000000/* 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) { if (capt_get_socket(capt) == -1) return -1; int version = TPACKET_V2; if (setsockopt(capt->fd, SOL_PACKET, PACKET_VERSION, &version, sizeof(version)) != 0) goto err; int hdrlen = version; socklen_t socklen = sizeof(hdrlen); if (getsockopt(capt->fd, SOL_PACKET, PACKET_HDRLEN, &hdrlen, &socklen) != 0) goto err; 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) goto err; 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) goto err; /* try to lock this memory to RAM */ (void)mlock(map, size); /* no need to check return value because the mlock() is * not mandatory; if it fails packet capture just works OK * albeit suboptimally */ 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. */ err: capt_put_socket(capt); return -1; } iptraf-ng-1.2.1/src/capt-mmap-v2.h000066400000000000000000000002251370555550300165550ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/capt-mmap-v3.c000066400000000000000000000123771370555550300165640ustar00rootroot00000000000000/* 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) { if (capt_get_socket(capt) == -1) return -1; int version = TPACKET_V3; if (setsockopt(capt->fd, SOL_PACKET, PACKET_VERSION, &version, sizeof(version)) != 0) goto err; int hdrlen = version; socklen_t socklen = sizeof(hdrlen); if (getsockopt(capt->fd, SOL_PACKET, PACKET_HDRLEN, &hdrlen, &socklen) != 0) goto err; 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) goto err; 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) goto err; /* try to lock this memory to RAM */ (void)mlock(map, size); /* no need to check return value because the mlock() is * not mandatory; if it fails packet capture just works OK * albeit suboptimally */ 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. */ err: capt_put_socket(capt); return -1; } iptraf-ng-1.2.1/src/capt-mmap-v3.h000066400000000000000000000002251370555550300165560ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/capt-recvmmsg.c000066400000000000000000000071211370555550300171160ustar00rootroot00000000000000/* 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; if (capt_get_socket(capt) == -1) return -1; 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; } iptraf-ng-1.2.1/src/capt-recvmmsg.h000066400000000000000000000002311370555550300171160ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/capt-recvmsg.c000066400000000000000000000041421370555550300167410ustar00rootroot00000000000000/* 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; if (capt_get_socket(capt) == -1) return -1; 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; } iptraf-ng-1.2.1/src/capt-recvmsg.h000066400000000000000000000002251370555550300167440ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/capt.c000066400000000000000000000113601370555550300152750ustar00rootroot00000000000000/* 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" int capt_get_socket(struct capt *capt) { /* 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 -1; capt->fd = fd; return 0; } void capt_put_socket(struct capt *capt) { close(capt->fd); capt->fd = -1; } 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->fd = -1; capt->dropped = 0UL; INIT_LIST_HEAD(&capt->promisc); /* try all available receive functions */ if (capt_setup_receive_function(capt) == -1) goto out; /* set socket receive timeout */ if (capt_set_recv_timeout(capt->fd, 250) == -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); capt_put_socket(capt); } 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; } iptraf-ng-1.2.1/src/capt.h000066400000000000000000000020411370555550300152760ustar00rootroot00000000000000#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_get_socket(struct capt *capt); void capt_put_socket(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 */ iptraf-ng-1.2.1/src/capture-pkt.c000066400000000000000000000032441370555550300166070ustar00rootroot00000000000000/* 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] ", 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 packets (default: 1)"), OPT_STRING('o', "output", &ofilename, "file", "save captured packet into (default: )"), 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; } iptraf-ng-1.2.1/src/cidr.c000066400000000000000000000033741370555550300152750ustar00rootroot00000000000000/* 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; } iptraf-ng-1.2.1/src/cidr.h000066400000000000000000000004551370555550300152770ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/counters.c000066400000000000000000000017131370555550300162110ustar00rootroot00000000000000/* 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); } } iptraf-ng-1.2.1/src/counters.h000066400000000000000000000010761370555550300162200ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/deskman.c000066400000000000000000000163231370555550300157740ustar00rootroot00000000000000/* 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 "); mvwprintw(win, 14, 2, "inspired by 2.7.0 diff by Guy Martin "); 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); } iptraf-ng-1.2.1/src/deskman.h000066400000000000000000000014331370555550300157750ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/detstats.c000066400000000000000000000445151370555550300162110ustar00rootroot00000000000000/* 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(); } iptraf-ng-1.2.1/src/detstats.h000066400000000000000000000002171370555550300162050ustar00rootroot00000000000000#ifndef IPTRAF_NG_DETSTATS_H #define IPTRAF_NG_DETSTATS_H void detstats(char *iface, time_t facilitytime); #endif /* IPTRAF_NG_DETSTATS_H */ iptraf-ng-1.2.1/src/dirs.h000066400000000000000000000066351370555550300153250ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/error.c000066400000000000000000000007011370555550300154740ustar00rootroot00000000000000/* 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); } iptraf-ng-1.2.1/src/error.h000066400000000000000000000002051370555550300155000ustar00rootroot00000000000000#ifndef IPTRAF_NG_ERROR_H #define IPTRAF_NG_ERROR_H void write_error(char *msg, ...) __printf(1,2); #endif /* IPTRAF_NG_ERROR_H */ iptraf-ng-1.2.1/src/fltdefs.h000066400000000000000000000022541370555550300160040ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/fltedit.c000066400000000000000000000302611370555550300160020ustar00rootroot00000000000000/* 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; } iptraf-ng-1.2.1/src/fltedit.h000066400000000000000000000005401370555550300160040ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/fltmgr.c000066400000000000000000000162751370555550300156530ustar00rootroot00000000000000/* 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(); } iptraf-ng-1.2.1/src/fltmgr.h000066400000000000000000000016661370555550300156560ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/fltselect.c000066400000000000000000000074131370555550300163370ustar00rootroot00000000000000/* 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); } iptraf-ng-1.2.1/src/fltselect.h000066400000000000000000000007531370555550300163440ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/getpath.c000066400000000000000000000013311370555550300157770ustar00rootroot00000000000000/* 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; } iptraf-ng-1.2.1/src/getpath.h000066400000000000000000000003241370555550300160050ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/hostmon.c000066400000000000000000000551771370555550300160530ustar00rootroot00000000000000/* 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); } iptraf-ng-1.2.1/src/hostmon.h000066400000000000000000000002671370555550300160460ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/ifaces.c000066400000000000000000000111511370555550300155760ustar00rootroot00000000000000/* 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); } iptraf-ng-1.2.1/src/ifaces.h000066400000000000000000000010401370555550300155770ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/ifstats.c000066400000000000000000000400741370555550300160270ustar00rootroot00000000000000/* 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(); } iptraf-ng-1.2.1/src/ifstats.h000066400000000000000000000002711370555550300160270ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/ipfilter.c000066400000000000000000000266721370555550300162000ustar00rootroot00000000000000/* 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; } iptraf-ng-1.2.1/src/ipfilter.h000066400000000000000000000010161370555550300161660ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/ipfrag.c000066400000000000000000000131721370555550300156210ustar00rootroot00000000000000/* 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; } iptraf-ng-1.2.1/src/ipfrag.h000066400000000000000000000013151370555550300156220ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/iptraf-ng-compat.h000066400000000000000000000070561370555550300175320ustar00rootroot00000000000000#ifndef IPTRAF_NG_COMPAT_H #define IPTRAF_NG_COMPAT_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 */ iptraf-ng-1.2.1/src/iptraf-ng.8000066400000000000000000000057211370555550300161660ustar00rootroot00000000000000.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) iptraf-ng-1.2.1/src/iptraf.c000066400000000000000000000311561370555550300156400ustar00rootroot00000000000000/* 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 | -d | -s | -z | -l | -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 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; } iptraf-ng-1.2.1/src/itrafmon.c000066400000000000000000000527111370555550300161720ustar00rootroot00000000000000/* 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); } iptraf-ng-1.2.1/src/itrafmon.h000066400000000000000000000002141370555550300161660ustar00rootroot00000000000000#ifndef IPTRAF_NG_ITRAFMON_H #define IPTRAF_NG_ITRAFMON_H void ipmon(time_t facilitytime, char *ifptr); #endif /* IPTRAF_NG_ITRAFMON_H */ iptraf-ng-1.2.1/src/landesc.c000066400000000000000000000166361370555550300157720ustar00rootroot00000000000000/* 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); } iptraf-ng-1.2.1/src/landesc.h000066400000000000000000000007061370555550300157660ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/list.h000066400000000000000000000043071370555550300153310ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/log.c000066400000000000000000000064601370555550300151340ustar00rootroot00000000000000/* 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; } } iptraf-ng-1.2.1/src/log.h000066400000000000000000000011641370555550300151350ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/logvars.h000066400000000000000000000002661370555550300160330ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/options.c000066400000000000000000000221361370555550300160440ustar00rootroot00000000000000/* 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(); } iptraf-ng-1.2.1/src/options.h000066400000000000000000000006201370555550300160430ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/othptab.c000066400000000000000000000516461370555550300160220ustar00rootroot00000000000000/* 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); } iptraf-ng-1.2.1/src/othptab.h000066400000000000000000000062231370555550300160160ustar00rootroot00000000000000#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 */ iptraf-ng-1.2.1/src/packet.c000066400000000000000000000344471370555550300156300ustar00rootroot00000000000000/* 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); str = pkttype_to_string(pkt->from->sll_pkttype); if (str) fprintf(fp, "type: %s", str); else fprintf(fp, "type: %02x", pkt->from->sll_pkttype); str = l2_type_to_string(pkt->from->sll_hatype); if (str) fprintf(fp, ", L2-proto: %s", str); else fprintf(fp, ", L2-proto: 0x%04x", pkt->from->sll_hatype); str = l3_proto_to_string(pkt->pkt_protocol); if (str) fprintf(fp, ", L3-proto: %s", str); else fprintf(fp, ", L3-proto: 0x%04x", pkt->pkt_protocol); fprintf(fp, "\n"); while(i < len) { adr = (char *)pkt->pkt_buf + i; if(i % 16 == 0) { if(i > 0) fprintf(fp, "\n"); fprintf(fp, "0x%04x:", i); } if(i % 8 == 0) fprintf(fp, " "); fprintf(fp, " "); if(adr == (char *)pkt->ethhdr) fprintf(fp, "^"); else if(adr == (char *)pkt->iphdr) fprintf(fp, "&"); else if(adr == (char *)pkt->ip6_hdr) fprintf(fp, "*"); else fprintf(fp, " "); fprintf(fp, "%02x", *(unsigned char *)adr & 0xff); i++; } fprintf(fp, "\n\n"); fflush(fp); } iptraf-ng-1.2.1/src/packet.h000066400000000000000000000025461370555550300156300ustar00rootroot00000000000000#ifndef IPTRAF_NG_PACKET_H #define IPTRAF_NG_PACKET_H /*** packet.h - external declarations for packet.c ***/ #define INVALID_PACKET 0 #define PACKET_OK 1 #define CHECKSUM_ERROR 2 #define PACKET_FILTERED 3 #define MORE_FRAGMENTS 4 struct pkt_hdr { char *pkt_buf; char *pkt_payload; size_t pkt_caplen; /* bytes captured */ size_t pkt_len; /* bytes on-the-wire */ unsigned short pkt_protocol; /* Physical layer protocol: ETH_P_* */ struct sockaddr_ll *from; struct ethhdr *ethhdr; struct fddihdr *fddihdr; struct iphdr *iphdr; struct ip6_hdr *ip6_hdr; }; static inline __u8 pkt_iph_len(const struct pkt_hdr *pkt) { switch (pkt->pkt_protocol) { case ETH_P_IP: return pkt->iphdr->ihl * 4; case ETH_P_IPV6: return 40; default: return 0; } } static inline __u8 pkt_ip_protocol(const struct pkt_hdr *p) { switch (p->pkt_protocol) { case ETH_P_IP: return p->iphdr->protocol; case ETH_P_IPV6: return p->ip6_hdr->ip6_nxt; /* FIXME: extension headers ??? */ }; return 0; } int packet_process(struct pkt_hdr *pkt, unsigned int *total_br, in_port_t *sport, in_port_t *dport, int match_opposite, int v6inv4asv6); int packet_init(struct pkt_hdr *pkt); void packet_destroy(struct pkt_hdr *pkt); int packet_is_first_fragment(struct pkt_hdr *pkt); void packet_dump(struct pkt_hdr *pkt, FILE *fp); #endif /* IPTRAF_NG_PACKET_H */ iptraf-ng-1.2.1/src/parse-options.c000066400000000000000000000064541370555550300171610ustar00rootroot00000000000000/* For terms of usage/redistribution/modification see the LICENSE file */ /* For authors and contributors see the AUTHORS file */ #include "iptraf-ng-compat.h" #include "parse-options.h" static int parse_opt_size(const struct options *opt) { unsigned size = 1; for (; opt->type != OPTION_END; opt++) size++; return size; } #define USAGE_OPTS_WIDTH 24 #define USAGE_GAP 2 void __noreturn parse_usage_and_die(const char *const *usage, const struct options *opt) { fprintf(stderr, "usage: %s\n", *usage++); while (*usage && **usage) fprintf(stderr, " or: %s\n", *usage++); if (opt->type != OPTION_GROUP) fputc('\n', stderr); for (; opt->type != OPTION_END; opt++) { size_t pos; int pad; if (opt->type == OPTION_GROUP) { fputc('\n', stderr); if (*opt->help) fprintf(stderr, "%s\n", opt->help); continue; } pos = fprintf(stderr, " "); if (opt->short_name) pos += fprintf(stderr, "-%c", opt->short_name); if (opt->short_name && opt->long_name) pos += fprintf(stderr, ", "); if (opt->long_name) pos += fprintf(stderr, "--%s", opt->long_name); if (opt->argh) pos += fprintf(stderr, " <%s>", opt->argh); if (pos <= USAGE_OPTS_WIDTH) pad = USAGE_OPTS_WIDTH - pos; else { fputc('\n', stderr); pad = USAGE_OPTS_WIDTH; } fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opt->help); } fputc('\n', stderr); exit(1); } static int get_value(const struct options *opt) { char *s = NULL; switch (opt->type) { case OPTION_BOOL: *(int *) opt->value += 1; break; case OPTION_INTEGER: *(int *) opt->value = strtol(optarg, (char **) &s, 10); if (*s) { error("invalid number -- %s", s); return -1; } break; case OPTION_STRING: if (optarg) *(char **) opt->value = (char *) optarg; break; case OPTION_GROUP: case OPTION_END: break; } return 0; } void parse_opts(int argc, char **argv, const struct options *opt, const char *const usage[]) { int size = parse_opt_size(opt); int nr = 0, alloc = 0; char *shortopts = NULL; struct option *longopts = xmallocz(sizeof(longopts[0]) * (size + 2)); const struct options *curopt = opt; struct option *curlongopts = longopts; for (; curopt->type != OPTION_END; curopt++, curlongopts++) { curlongopts->name = curopt->long_name; switch (curopt->type) { case OPTION_BOOL: curlongopts->has_arg = no_argument; if (curopt->short_name) { ALLOC_GROW(shortopts, nr + 1, alloc); shortopts[nr++] = curopt->short_name; } break; case OPTION_INTEGER: case OPTION_STRING: curlongopts->has_arg = required_argument; if (curopt->short_name) { ALLOC_GROW(shortopts, nr + 2, alloc); shortopts[nr++] = curopt->short_name; shortopts[nr++] = ':'; } break; case OPTION_GROUP: case OPTION_END: break; } curlongopts->flag = 0; curlongopts->val = curopt->short_name; } while (1) { curopt = opt; int c = getopt_long(argc, argv, shortopts, longopts, NULL); if (c == -1) break; if (c == '?') { free(longopts); free(shortopts); parse_usage_and_die(usage, opt); } for (; curopt->type != OPTION_END; curopt++) { if (curopt->short_name != c) continue; /* for now it fails only when string is badly converted */ if (get_value(curopt) < 0) parse_usage_and_die(usage, opt); } } free(longopts); free(shortopts); } iptraf-ng-1.2.1/src/parse-options.h000066400000000000000000000022211370555550300171520ustar00rootroot00000000000000#ifndef IPTRAF_NG_PARSE_OPTIONS_H #define IPTRAF_NG_PARSE_OPTIONS_H enum parse_opt_type { OPTION_BOOL, OPTION_GROUP, OPTION_STRING, OPTION_INTEGER, OPTION_END, }; struct options { enum parse_opt_type type; int short_name; const char *long_name; void *value; const char *argh; const char *help; }; /* * s - short_name * l - long_name * v - value * a - argh argument help * h - help */ #define OPT_END() { OPTION_END, 0, NULL, NULL, NULL, NULL } #define OPT_BOOL(s, l, v, h) { OPTION_BOOL, (s), (l), (v), NULL, (h) } #define OPT_GROUP(h) { OPTION_GROUP, 0, NULL, NULL, NULL, (h) } #define OPT_INTEGER(s, l, v, h) { OPTION_INTEGER, (s), (l), (v), "n", (h) } #define OPT_STRING(s, l, v, a, h) { OPTION_STRING, (s), (l), (v), (a), (h) } #define OPT__VERBOSE(v) OPT_BOOL('v', "verbose", (v), "be verbose") #define OPT__HELP(v) OPT_BOOL('h', "help", (v), "show this help message") void parse_opts(int argc, char **argv, const struct options *opt, const char *const usage[]); void parse_usage_and_die(const char *const *usage, const struct options *opt); #endif /* IPTRAF_NG_PARSE_OPTIONS_H */ iptraf-ng-1.2.1/src/parseproto.c000066400000000000000000000066741370555550300165600ustar00rootroot00000000000000/* For terms of usage/redistribution/modification see the LICENSE file */ /* For authors and contributors see the AUTHORS file */ /* * parseports.c - code to extract the protocol codes or ranges thereof from * the user-defined string. * */ #include "iptraf-ng-compat.h" #include "parseproto.h" /* * Extracts next token from the buffer. */ static char *get_next_token(char **cptr) { static char rtoken[32]; int i; i = 0; skip_whitespace(*cptr); if (**cptr == ',' || **cptr == '-') { rtoken[0] = **cptr; rtoken[1] = '\0'; (*cptr)++; } else { while (!isspace(**cptr) && **cptr != '-' && **cptr != ',' && **cptr != '\0') { rtoken[i] = **cptr; (*cptr)++; i++; } rtoken[i] = '\0'; } return rtoken; } void get_next_protorange(char **cptr, unsigned int *proto1, unsigned int *proto2, int *parse_result, char **badtokenptr) { char toktmp[6]; char prototmp1[6]; char prototmp2[6]; char *cerr_ptr; static char bad_token[6]; unsigned int tmp; memset(toktmp, 0, sizeof(toktmp)); memset(prototmp1, 0, sizeof(prototmp1)); memset(prototmp2, 0, sizeof(prototmp2)); memset(bad_token, 0, sizeof(bad_token)); strncpy(prototmp1, get_next_token(cptr), sizeof(prototmp1) - 1); if (prototmp1[0] == '\0') { *parse_result = NO_MORE_TOKENS; return; } strncpy(toktmp, get_next_token(cptr), sizeof(toktmp) - 1); *parse_result = RANGE_OK; switch (toktmp[0]) { case '-': strncpy(prototmp2, get_next_token(cptr), sizeof(prototmp2) - 1); /* * Check for missing right-hand token for - */ if (prototmp2[0] == '\0') { *parse_result = INVALID_RANGE; strcpy(bad_token, "-"); *badtokenptr = bad_token; break; } *proto2 = (unsigned int) strtoul(prototmp2, &cerr_ptr, 10); /* * First check for an invalid character */ if (*cerr_ptr != '\0') { *parse_result = INVALID_RANGE; strncpy(bad_token, prototmp2, sizeof(bad_token)); *badtokenptr = bad_token; } else { /* * Then check for the validity of the token */ if (*proto2 > 255) { strncpy(bad_token, prototmp2, sizeof(bad_token)); *badtokenptr = bad_token; *parse_result = OUT_OF_RANGE; } /* * Then check if the next token is a comma */ strncpy(toktmp, get_next_token(cptr), sizeof(toktmp) - 1); if (toktmp[0] != '\0' && toktmp[0] != ',') { *parse_result = COMMA_EXPECTED; strncpy(bad_token, toktmp, sizeof(bad_token)); *badtokenptr = bad_token; } } break; case ',': case '\0': *proto2 = 0; break; default: *parse_result = COMMA_EXPECTED; strncpy(bad_token, toktmp, sizeof(bad_token)); *badtokenptr = bad_token; break; } if (*parse_result != RANGE_OK) return; *proto1 = (unsigned int) strtoul(prototmp1, &cerr_ptr, 10); if (*cerr_ptr != '\0') { *parse_result = INVALID_RANGE; strncpy(bad_token, prototmp1, sizeof(bad_token)); *badtokenptr = bad_token; } else if (*proto1 > 255) { *parse_result = OUT_OF_RANGE; strncpy(bad_token, prototmp1, sizeof(bad_token)); *badtokenptr = bad_token; } else *badtokenptr = NULL; if (*proto2 != 0 && *proto1 > *proto2) { tmp = *proto1; *proto1 = *proto2; *proto2 = tmp; } } int validate_ranges(char *samplestring, int *parse_result, char **badtokenptr) { unsigned int proto1, proto2; char *cptr = samplestring; do { get_next_protorange(&cptr, &proto1, &proto2, parse_result, badtokenptr); } while (*parse_result == RANGE_OK); if (*parse_result != NO_MORE_TOKENS) return 0; return 1; } iptraf-ng-1.2.1/src/parseproto.h000066400000000000000000000006761370555550300165610ustar00rootroot00000000000000#ifndef IPTRAF_NG_PARSEPROTO_H #define IPTRAF_NG_PARSEPROTO_H #define RANGE_OK 0 #define COMMA_EXPECTED 1 #define INVALID_RANGE 2 #define OUT_OF_RANGE 4 #define NO_MORE_TOKENS 5 void get_next_protorange(char **cptr, unsigned int *proto1, unsigned int *proto2, int *parse_result, char **badtokenptr); int validate_ranges(char *src, int *parse_result, char **bptr); #endif /* IPTRAF_NG_PARSEPROTO_H */ iptraf-ng-1.2.1/src/pktsize.c000066400000000000000000000201641370555550300160410ustar00rootroot00000000000000/* For terms of usage/redistribution/modification see the LICENSE file */ /* For authors and contributors see the AUTHORS file */ /*** pktsize.c - the packet size breakdown facility ***/ #include "iptraf-ng-compat.h" #include "tui/winops.h" #include "attrs.h" #include "dirs.h" #include "fltdefs.h" #include "ifaces.h" #include "packet.h" #include "deskman.h" #include "error.h" #include "pktsize.h" #include "options.h" #include "timer.h" #include "log.h" #include "logvars.h" #include "capt.h" #include "timer.h" #define SIZES 20 struct psizetab { WINDOW *win; PANEL *panel; WINDOW *borderwin; PANEL *borderpanel; unsigned long size_in[SIZES + 1]; /* +1 for oversized count */ unsigned long size_out[SIZES + 1]; unsigned int mtu; unsigned int interval; unsigned int maxsize_in; unsigned int maxsize_out; }; static void rotate_size_log(int s __unused) { rotate_flag = 1; strcpy(target_logname, current_logfile); signal(SIGUSR1, rotate_size_log); } static void write_size_log(struct psizetab *table, unsigned long nsecs, char *ifname, FILE *logfile) { char atime[TIME_TARGET_MAX]; int i; genatime(time(NULL), atime); fprintf(logfile, "*** Packet Size Distribution, generated %s\n\n", atime); fprintf(logfile, "Interface: %s MTU: %u\n\n", ifname, table->mtu); fprintf(logfile, "Packet Size (bytes)\tIn\t\tOut\n"); for (i = 0; i < SIZES; i++) { fprintf(logfile, "%u to %u:\t\t%8lu\t%8lu\n", table->interval * i + 1, table->interval * (i + 1), table->size_in[i], table->size_out[i]); } fprintf(logfile, "\nRunning time: %lu seconds\n", nsecs); fflush(logfile); } static void psizetab_init(struct psizetab *table, char *ifname) { table->borderwin = newwin(LINES - 2, COLS, 1, 0); table->borderpanel = new_panel(table->borderwin); wattrset(table->borderwin, BOXATTR); tx_box(table->borderwin, ACS_VLINE, ACS_HLINE); mvwprintw(table->borderwin, 0, 1, " Packet Distribution by Size for interface %s ", ifname); table->win = newwin(LINES - 4, COLS - 2, 2, 1); table->panel = new_panel(table->win); tx_stdwinset(table->win); wtimeout(table->win, -1); wattrset(table->win, STDATTR); tx_colorwin(table->win); wattrset(table->win, BOXATTR); mvwprintw(table->win, 1, 1, "Packet Size (bytes)"); mvwprintw(table->win, 1, 23, "In Out"); mvwprintw(table->win, 1, 42, "Packet Size (bytes)"); mvwprintw(table->win, 1, 64, "In Out"); wattrset(table->win, HIGHATTR); move(LINES - 1, 1); stdexitkeyhelp(); update_panels(); doupdate(); } static void psizetab_destroy(struct psizetab *table) { del_panel(table->panel); delwin(table->win); del_panel(table->borderpanel); delwin(table->borderwin); update_panels(); doupdate(); } static void sizes_init(struct psizetab *table, unsigned int mtu) { table->mtu = mtu; unsigned int interval = mtu / SIZES; table->interval = interval; wattrset(table->win, STDATTR); for(unsigned int i = 0; i < SIZES; i++) { int row, column; table->size_in[i] = 0UL; /* initialize counters */ table->size_out[i] = 0UL; if (i < SIZES / 2) { row = i + 2; column = 1; } else { row = (i - 10) + 2; column = 42; } mvwprintw(table->win, row, column, "%5u to %5u:", interval * i + 1, interval * (i + 1)); } table->size_in[SIZES] = 0UL; /* initialize oversized counters */ table->size_out[SIZES] = 0UL; table->maxsize_in = 0UL; /* initialize maxsize counters */ table->maxsize_out = 0UL; mvwprintw(table->win, 12, 47, "oversized:"); mvwprintw(table->win, 14, 1, "max packet size in (bytes):"); mvwprintw(table->win, 15, 1, "max packet size out (bytes):"); mvwprintw(table->win, 17, 1, "Interface MTU is %u bytes, not counting the data-link header.", table->mtu); mvwprintw(table->win, 18, 1, "Maximum packet size is the MTU plus the data-link header length, but can be"); mvwprintw(table->win, 19, 1, " bigger due to various offloading techniques of the interface."); mvwprintw(table->win, 20, 1, "Packet size computations include data-link headers, if any."); } static void update_size_distrib(struct psizetab *table, struct pkt_hdr *pkt) { /* -1 is to keep interval boundary lengths within the proper brackets */ unsigned int i = (pkt->pkt_len - 1) / table->interval; if (i > SIZES) i = SIZES; /* last entry is for lengths > MTU */ if (pkt->from->sll_pkttype == PACKET_OUTGOING) { table->size_out[i]++; if (table->maxsize_out < pkt->pkt_len) table->maxsize_out = pkt->pkt_len; } else { table->size_in[i]++; if (table->maxsize_in < pkt->pkt_len) table->maxsize_in = pkt->pkt_len; } } static void print_size_distrib(struct psizetab *table) { wattrset(table->win, HIGHATTR); for (unsigned int i = 0; i < SIZES + 1; i++) { /* include oversized */ if (i < 10) wmove(table->win, i + 2, 17); else wmove(table->win, (i - 10) + 2, 58); wprintw(table->win, "%8lu %8lu", table->size_in[i], table->size_out[i]); } mvwprintw(table->win, 14, 33, "%5u", table->maxsize_in); mvwprintw(table->win, 15, 33, "%5u", table->maxsize_out); } static void psize_process_key(int ch) { switch (ch) { case 12: case 'l': case 'L': tx_refresh_screen(); break; case 'x': case 'X': case 'q': case 'Q': case 27: case 24: exitloop = 1; } } static void psize_process_packet(struct psizetab *table, struct pkt_hdr *pkt) { int pkt_result = packet_process(pkt, NULL, NULL, NULL, MATCH_OPPOSITE_USECONFIG, 0); if (pkt_result == PACKET_OK) update_size_distrib(table, pkt); } void packet_size_breakdown(char *ifname, time_t facilitytime) { int ch; int logging = options.logging; FILE *logfile = NULL; struct psizetab table; struct capt capt; struct pkt_hdr pkt; if (!dev_up(ifname)) { err_iface_down(); return; } psizetab_init(&table, ifname); if (capt_init(&capt, ifname) == -1) { write_error("Unable to initialize packet capture interface"); goto err; } int mtu = dev_get_mtu(ifname); if (mtu < 0) { write_error("Unable to obtain interface MTU"); goto err_close; } sizes_init(&table, mtu); print_size_distrib(&table); update_panels(); doupdate(); if (logging) { if (strcmp(current_logfile, "") == 0) { snprintf(current_logfile, 80, "%s-%s.log", PKTSIZELOG, ifname); if (!daemonized) input_logfile(current_logfile, &logging); } } if (logging) { opentlog(&logfile, current_logfile); if (logfile == NULL) logging = 0; } if (logging) { signal(SIGUSR1, rotate_size_log); rotate_flag = 0; writelog(logging, logfile, "******** Packet size distribution facility 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) { printelapsedtime(now.tv_sec - starttime, 1, table.borderwin); print_packet_drops(capt_get_dropped(&capt), table.borderwin, 49); if (logging && (now.tv_sec > log_next)) { check_rotate_flag(&logfile); write_size_log(&table, now.tv_sec - starttime, ifname, 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_size_distrib(&table); update_panels(); doupdate(); set_next_screen_update(&next_screen_update, &now); } if (capt_get_packet(&capt, &pkt, &ch, table.win) == -1) { write_error("Packet receive failed"); exitloop = 1; break; } if (ch != ERR) psize_process_key(ch); if (pkt.pkt_len > 0) { psize_process_packet(&table, &pkt); capt_put_packet(&capt, &pkt); } } packet_destroy(&pkt); if (logging) { signal(SIGUSR1, SIG_DFL); write_size_log(&table, time(NULL) - starttime, ifname, logfile); writelog(logging, logfile, "******** Packet size distribution facility stopped ********"); fclose(logfile); } strcpy(current_logfile, ""); err_close: capt_destroy(&capt); err: psizetab_destroy(&table); } iptraf-ng-1.2.1/src/pktsize.h000066400000000000000000000002311370555550300160370ustar00rootroot00000000000000#ifndef IPTRAF_NG_PKTSIZE_H #define IPTRAF_NG_PKTSIZE_H void packet_size_breakdown(char *iface, time_t facilitytime); #endif /* IPTRAF_NG_PKTSIZE_H */ iptraf-ng-1.2.1/src/promisc.c000066400000000000000000000045271370555550300160310ustar00rootroot00000000000000/* For terms of usage/redistribution/modification see the LICENSE file */ /* For authors and contributors see the AUTHORS file */ /*** promisc.c - handles the promiscuous mode flag for the Ethernet/FDDI/ Token Ring interfaces ***/ #include "iptraf-ng-compat.h" #include "ifaces.h" #include "error.h" #include "promisc.h" struct promisc_list { struct list_head list; int ifindex; char ifname[IFNAMSIZ]; }; static bool promisc_dev_suitable(const char *dev_name) { int flags = dev_get_flags(dev_name); if (flags < 0) return false; if ((flags & (IFF_UP | IFF_PROMISC)) == IFF_UP) return true; else return false; } static int sock_change_promisc(int sock, int action, int ifindex) { struct packet_mreq mreq; mreq.mr_ifindex = ifindex; mreq.mr_type = PACKET_MR_PROMISC; return setsockopt(sock, SOL_PACKET, action, &mreq, sizeof(mreq)); } static int sock_enable_promisc(int sock, int ifindex) { return sock_change_promisc(sock, PACKET_ADD_MEMBERSHIP, ifindex); } static int sock_disable_promisc(int sock, int ifindex) { return sock_change_promisc(sock, PACKET_DROP_MEMBERSHIP, ifindex); } static void promisc_enable_dev(struct list_head *promisc, int sock, const char *dev) { if (!promisc_dev_suitable(dev)) return; int ifindex = dev_get_ifindex(dev); if (ifindex < 0) return; int r = sock_enable_promisc(sock, ifindex); if (r < 0) { write_error("Failed to set promiscuous mode on %s", dev); return; } struct promisc_list *new = xmallocz(sizeof(*new)); new->ifindex = ifindex; strcpy(new->ifname, dev); list_add_tail(&new->list, promisc); } void promisc_enable(int sock, struct list_head *promisc, const char *device_name) { if (device_name) { promisc_enable_dev(promisc, sock, device_name); return; } FILE *fp = open_procnetdev(); if (!fp) die_errno("%s: open_procnetdev", __func__); char dev_name[IFNAMSIZ]; while (get_next_iface(fp, dev_name, sizeof(dev_name))) { if (!strcmp(dev_name, "")) continue; promisc_enable_dev(promisc, sock, dev_name); } fclose(fp); } void promisc_disable(int sock, struct list_head *promisc) { struct promisc_list *entry, *tmp; list_for_each_entry_safe(entry, tmp, promisc, list) { int r = sock_disable_promisc(sock, entry->ifindex); if (r < 0) write_error("Failed to clear promiscuous mode on %s", entry->ifname); list_del(&entry->list); free(entry); } } iptraf-ng-1.2.1/src/promisc.h000066400000000000000000000003741370555550300160320ustar00rootroot00000000000000#ifndef IPTRAF_NG_PROMISC_H #define IPTRAF_NG_PROMISC_H #include "list.h" void promisc_enable(int sock, struct list_head *promisc, const char *device_name); void promisc_disable(int sock, struct list_head *promisc); #endif /* IPTRAF_NG_PROMISC_H */ iptraf-ng-1.2.1/src/rate.c000066400000000000000000000046021370555550300153020ustar00rootroot00000000000000/* 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 "rate.h" void rate_init(struct rate *rate) { if (!rate) return; rate->index = 0; rate->sma = 0; memset(rate->rates, 0, rate->n * sizeof(rate->rates[0])); } void rate_alloc(struct rate *rate, unsigned int n) { if (!rate) return; rate->n = n; rate->rates = xmalloc(n * sizeof(rate->rates[0])); rate_init(rate); } void rate_destroy(struct rate *rate) { if (!rate) return; rate->n = 0; if (!rate->rates) return; free(rate->rates); rate->rates = NULL; } void rate_add_rate(struct rate *rate, unsigned long bytes, unsigned long msecs) { if (!rate) return; rate->rates[rate->index] = bytes * 1000ULL / msecs; if ((rate->index + 1) >= rate->n) rate->index = 0; else rate->index++; /* compute the moving average */ unsigned long long sum = 0; for(unsigned int i = 0; i < rate->n; i++) sum += rate->rates[i]; rate->sma = sum / rate->n; } unsigned long rate_get_average(struct rate *rate) { if (rate) return rate->sma; else return 0UL; } int rate_print(unsigned long rate, char *buf, unsigned n) { char *suffix[] = { "k", "M", "G", "T", "P", "E", "Z", "Y" }; unsigned n_suffix = ARRAY_SIZE(suffix); int chars; if (options.actmode == KBITS) { unsigned long tmp = rate; unsigned int i = 0; unsigned long divider = 1000; rate *= 8; while(tmp >= 100000000) { tmp /= 1000; i++; divider *= 1000; } if (i >= n_suffix) chars = snprintf(buf, n, "error"); else chars = snprintf(buf, n, "%9.2f %sbps", (double)rate / divider, suffix[i]); } else { unsigned int i = 0; while(rate > 99 * (1UL << 20)) { rate >>= 10; i++; } if (i >= n_suffix) chars = snprintf(buf, n, "error"); else chars = snprintf(buf, n, "%9.2f %sBps", (double)rate / 1024, suffix[i]); } buf[n - 1] = '\0'; return chars; } int rate_print_no_units(unsigned long rate, char *buf, unsigned n) { int chars; if (options.actmode == KBITS) { chars = snprintf(buf, n, "%8.1f", (double)rate * 8 / 1000); } else { chars = snprintf(buf, n, "%8.1f", (double)rate / 1024); } buf[n - 1] = '\0'; return chars; } int rate_print_pps(unsigned long rate, char *buf, unsigned n) { int chars; chars = snprintf(buf, n, "%9lu pps", rate); buf[n - 1] = '\0'; return chars; } iptraf-ng-1.2.1/src/rate.h000066400000000000000000000020131370555550300153010ustar00rootroot00000000000000#ifndef IPTRAF_NG_RATE_H #define IPTRAF_NG_RATE_H #include /* SMA = Simple Moving Average */ /* * SMA = (p(M) + p(M-1) + ... + p(M-n-1)) / n * * or * * SMA = last_SMA - (p(M-n) / n) + (p(M) / n) * * I choose the first one because there is smaller rounding * error when using integer divide. */ struct rate { unsigned int n; /* number of elements */ unsigned int index; /* index into the values array */ unsigned long long *rates; /* units are: bytes per second */ unsigned long sma; /* simple moving average */ }; void rate_init(struct rate *rate); void rate_alloc(struct rate *rate, unsigned int n); void rate_destroy(struct rate *rate); void rate_add_rate(struct rate *rate, unsigned long bytes, unsigned long msecs); unsigned long rate_get_average(struct rate *rate); int rate_print(unsigned long rate, char *buf, unsigned n); int rate_print_no_units(unsigned long rate, char *buf, unsigned n); int rate_print_pps(unsigned long rate, char *buf, unsigned n); #endif /* IPTRAF_NG_RATE_H */ iptraf-ng-1.2.1/src/revname.c000066400000000000000000000140251370555550300160040ustar00rootroot00000000000000/* For terms of usage/redistribution/modification see the LICENSE file */ /* For authors and contributors see the AUTHORS file */ /*** revname.c - reverse DNS resolution module for IPTraf. As of IPTraf 1.1, this module now communicates with the rvnamed process to resolve in the background while allowing the foreground process to continue with the interim IP addresses in the meantime. ***/ #include "iptraf-ng-compat.h" #include "deskman.h" #include "error.h" #include "getpath.h" #include "revname.h" #include "rvnamed.h" #include "sockaddr.h" static bool resolver_socket_ready(const struct resolver *res, const short events, const int timeout) { struct pollfd pfds[1]; nfds_t nfds; ssize_t ss; /* wait for server socket become readable/writable */ nfds = 0; pfds[nfds].fd = res->sock; pfds[nfds].events = events; nfds++; do { ss = poll(pfds, nfds, timeout); } while ((ss == -1) && (errno == EINTR)); if ((ss == -1) || (ss == 0) || (pfds[0].revents & POLLERR)) { /* poll() error or poll() timeout or res->sock error */ return false; } /* all O.K.: socket ready */ return true; } static bool resolver_socket_read_ready(const struct resolver *res, const int timeout) { return resolver_socket_ready(res, POLLIN, timeout); } static bool resolver_socket_write_ready(const struct resolver *res, const int timeout) { return resolver_socket_ready(res, POLLOUT, timeout); } static bool resolver_send_request(const struct resolver *res, const struct rvn *rpkt) { ssize_t ss; do { ss = send(res->sock, rpkt, sizeof(*rpkt), 0); } while ((ss == -1) && (errno == EINTR)); if ((ss == -1) || (ss < (ssize_t)sizeof(*rpkt))) { /* send() error or not enough bytes sent */ return false; } /* all O.K. */ return true; } static bool resolver_receive_response(const struct resolver *res, struct rvn *rpkt) { ssize_t ss; /* try to receive struct rvn packet */ do { ss = recv(res->sock, rpkt, sizeof(*rpkt), 0); } while ((ss == -1) && (errno == EINTR)); if ((ss == -1) || (ss < (ssize_t)sizeof(*rpkt) )) return false; /* all O.K. */ return true; } static bool resolver_active(const struct resolver *res) { struct rvn rpkt; /* check if we can write; * this first timeout is bigger than others * because we probably just fork()ed the resolver process */ if (resolver_socket_write_ready(res, 5000) == false) return false; /* send HELLO packet */ rpkt.type = RVN_HELLO; if (resolver_send_request(res, &rpkt) == false) return false; /* check if we can read */ if (resolver_socket_read_ready(res, 1000) == false) return false; memset(&rpkt, 0, sizeof(rpkt)); rpkt.type = -1; if (resolver_receive_response(res, &rpkt) == false) return false; if (rpkt.type != RVN_HELLO) return false; /* all O.K. */ return true; } void resolver_init(struct resolver *res, bool lookup) { int sockets[2]; res->lookup = lookup; res->sock = 0; res->server = 0; if (lookup == false) return; /* don't do lookups */ indicate("Starting reverse lookup server"); if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sockets) == -1) { write_error("Can't get communication sockets; lookups will block"); return; /* do synchronous lookups */ } pid_t p = fork(); if (p == -1) { /* fork() failed */ write_error("Can't spawn new process; lookups will block"); return; /* do synchronous lookups */ } else if (p == 0) { close(sockets[0]); rvnamed(sockets[1]); exit(0); } close(sockets[1]); res->sock = sockets[0]; res->server = p; indicate("Trying to communicate with reverse lookup server"); if (resolver_active(res) == false) { write_error("Can't communicate with resolver; will not lookup names"); resolver_destroy(res); } } static void resolver_quit(struct resolver *res) { /* send QUIT request */ if (resolver_socket_write_ready(res, 1000) == true) { struct rvn rpkt; rpkt.type = RVN_QUIT; resolver_send_request(res, &rpkt); } /* check if already exited */ int r = waitpid(res->server, NULL, WNOHANG); if (r == res->server) return; if (r == -1) die_errno("waitpid(resolver_child)"); if (r != 0) die("waitpid(): exited unknown process ???"); /* wait a little for child to process the QUIT request */ struct timespec t; t.tv_sec = 0; t.tv_nsec = 200000000; /* 200 ms */ nanosleep(&t, NULL); /* check if exited */ r = waitpid(res->server, NULL, WNOHANG); if (r == res->server) return; if (r == -1) die_errno("waitpid(resolver_child)"); if (r != 0) die("waitpid(): exited unknown process ???"); /* send SIGTERM to terminate the child ... */ if (kill(res->server, SIGTERM) == -1) { if(errno == ESRCH) return; /* already exited ??? */ die_errno("kill(resolver_child, TERM)"); } /* wait a little */ t.tv_sec = 0; t.tv_nsec = 200000000; /* 200 ms */ nanosleep(&t, NULL); /* check if exited */ waitpid(res->server, NULL, WNOHANG); /* no return value checking: we've done enough to reap the zombie ... */ } void resolver_destroy(struct resolver *res) { if (res->server > 0) resolver_quit(res); res->server = 0; if(res->sock > 0) close(res->sock); res->sock = 0; res->lookup = false; } int revname(struct resolver *res, struct sockaddr_storage *addr, char *target, size_t target_size) { memset(target, 0, target_size); if (res == NULL) { /* no lookup */ sockaddr_ntop(addr, target, target_size); return RESOLVED; } if (res->lookup == false) { /* no lookup */ sockaddr_ntop(addr, target, target_size); return RESOLVED; } if (res->sock <= 0) { /* blocking lookup */ sockaddr_gethostbyaddr(addr, target, target_size); return RESOLVED; } /* non-blocking/async lookup */ struct rvn rpkt; rpkt.type = RVN_REQUEST; sockaddr_copy(&rpkt.addr, addr); if ((resolver_socket_write_ready(res, 1000) == false) || (resolver_send_request(res, &rpkt) == false) || (resolver_socket_read_ready(res, 1000) == false) || (resolver_receive_response(res, &rpkt) == false)) { sockaddr_ntop(addr, target, target_size); printipcerr(); resolver_destroy(res); return RESOLVED; } strncpy(target, rpkt.fqdn, target_size - 1); return rpkt.ready; } iptraf-ng-1.2.1/src/revname.h000066400000000000000000000006631370555550300160140ustar00rootroot00000000000000#ifndef IPTRAF_NG_REVNAME_H #define IPTRAF_NG_REVNAME_H /*** revname.h - public declarations related to reverse name resolution ***/ struct resolver { bool lookup; int sock; pid_t server; }; void resolver_init(struct resolver *r, bool lookup); void resolver_destroy(struct resolver *r); int revname(struct resolver *res, struct sockaddr_storage *addr, char *target, size_t target_size); #endif /* IPTRAF_NG_REVNAME_H */ iptraf-ng-1.2.1/src/rvnamed.c000066400000000000000000000230061370555550300160020ustar00rootroot00000000000000/* For terms of usage/redistribution/modification see the LICENSE file */ /* For authors and contributors see the AUTHORS file */ /*** rvnamed - reverse DNS lookup daemon for the IPTraf network statistics utility. Version 2.6.1 Parallel with IPTraf 2.6 Written by Gerard Paul Java Copyright (c) Gerard Paul Java 1998-2001 rvnamed is a daemon designed to do reverse DNS lookups, but return the IP address immediately while the lookup goes on in the background. A process requesting the lookup issues a request, and will immediately get a reply with the IP address. Meanwhile, rvnamed will fork and do the lookup. The requesting process simply needs to reissue the request until a full domain name is returned. This program is designed to be used by the IPTraf program to minimize blocking and allow smoother keyboard control and packet counting when reverse DNS lookups are enabled. rvnamed and IPTraf communicate with each other using the BSD UNIX domain socket protocol. ***/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rvnamed.h" #include "dirs.h" #include "sockaddr.h" #define NUM_CACHE_ENTRIES 2048 #define TIME_TARGET_MAX 30 #define __unused __attribute__((unused)) struct hosts { struct sockaddr_storage addr; char fqdn[45]; int ready; }; static int fork_count = 0; static int max_fork_count = 0; /* * This is the classic zombie-preventer */ static void childreap(int s __unused) { signal(SIGCHLD, childreap); while (waitpid(-1, NULL, WNOHANG) > 0) fork_count--; } static void auto_terminate(int s __unused) { exit(2); } /* * Process reverse DNS request from the client */ static void process_rvn_packet(struct rvn *rvnpacket) { sockaddr_gethostbyaddr(&rvnpacket->addr, rvnpacket->fqdn, sizeof(rvnpacket->fqdn)); struct sockaddr_un ccsa; ccsa.sun_family = AF_UNIX; strcpy(ccsa.sun_path, CHILDSOCKNAME); int ccfd = socket(PF_UNIX, SOCK_DGRAM, 0); sendto(ccfd, rvnpacket, sizeof(struct rvn), 0, (struct sockaddr *) &ccsa, sizeof(ccsa.sun_family) + strlen(ccsa.sun_path)); close(ccfd); } /* * Check if name is already resolved and in the cache. */ static int name_resolved(struct rvn *rvnpacket, struct hosts *hostlist, unsigned int lastfree) { for (unsigned int i = 0; i != lastfree; i++) if ((hostlist[i].ready == RESOLVED) && sockaddr_addr_is_equal(&rvnpacket->addr, &hostlist[i].addr)) return i; return -1; } /* * Return the resolution status (NOTRESOLVED, RESOLVING, RESOLVED) of * the given IP address */ static int addrstat(struct rvn *rvnpacket, struct hosts *hostlist, unsigned int lastfree) { for (unsigned int i = 0; i != lastfree; i++) if (sockaddr_addr_is_equal(&rvnpacket->addr, &hostlist[i].addr)) return hostlist[i].ready; return NOTRESOLVED; } static void writervnlog(FILE * fd, char *msg) { time_t now; char atime[TIME_TARGET_MAX] = ""; now = time(NULL); strcpy(atime, ctime(&now)); atime[strlen(atime) - 1] = '\0'; fprintf(fd, "%s: %s\n", atime, msg); } int rvnamed(int ifd) { int cfd; struct hosts hostlist[NUM_CACHE_ENTRIES]; char logmsg[160]; unsigned int hostindex = 0; unsigned int lastfree = 0; unsigned int hi = 0; int readyidx = 0; int fr = 0; int maxlogged = 0; struct rvn rvnpacket; int br; int ss = 0; fd_set sockset; struct sockaddr_un csa; struct sockaddr_un fromaddr; socklen_t fromlen; FILE *logfile; signal(SIGCHLD, childreap); logfile = fopen(RVNDLOGFILE, "a"); if (logfile == NULL) logfile = fopen("/dev/null", "a"); writervnlog(logfile, "******** rvnamed started ********"); writervnlog(logfile, "Clearing socket names"); /* * Get rid of any residue socket names in case of a previous * abormal termination of rvnamed. */ unlink(CHILDSOCKNAME); writervnlog(logfile, "Opening sockets"); csa.sun_family = AF_UNIX; strcpy(csa.sun_path, CHILDSOCKNAME); cfd = socket(PF_UNIX, SOCK_DGRAM, 0); if (cfd < 0) { writervnlog(logfile, "Unable to open child communication socket, aborting"); exit(1); } if (bind (cfd, (struct sockaddr *) &csa, sizeof(csa.sun_family) + strlen(csa.sun_path)) < 0) { writervnlog(logfile, "Error binding child communication socket, aborting"); exit(1); } while (1) { FD_ZERO(&sockset); FD_SET(cfd, &sockset); FD_SET(ifd, &sockset); int maxfd = cfd > ifd ? cfd : ifd; do { ss = select(maxfd + 1, &sockset, NULL, NULL, NULL); } while ((ss < 0) && (errno != ENOMEM)); if (errno == ENOMEM) { writervnlog(logfile, "Fatal error: no memory for descriptor monitoring"); close(ifd); close(cfd); fclose(logfile); exit(1); } /* * Code to process packets coming from the forked child. */ if (FD_ISSET(cfd, &sockset)) { fromlen = sizeof(fromaddr.sun_family) + strlen(fromaddr.sun_path); br = recvfrom(cfd, &rvnpacket, sizeof(struct rvn), 0, (struct sockaddr *) &fromaddr, &fromlen); if (br > 0) { hi = 0; while (hi <= lastfree) { if (sockaddr_addr_is_equal(&hostlist[hi].addr, &rvnpacket.addr)) break; hi++; } if (hi == lastfree) { /* Address not in cache */ memset(&(hostlist[hi]), 0, sizeof(struct hosts)); hi = hostindex; hostindex++; if (hostindex == NUM_CACHE_ENTRIES) hostindex = 0; sockaddr_copy(&hostlist[hi].addr, &rvnpacket.addr); } strncpy(hostlist[hi].fqdn, rvnpacket.fqdn, sizeof(hostlist[hi].fqdn)); hostlist[hi].fqdn[sizeof(hostlist[hi].fqdn) - 1] = '\0'; hostlist[hi].ready = RESOLVED; } } /* * This code section processes packets received from the IPTraf * program. */ if (FD_ISSET(ifd, &sockset)) { br = recv(ifd, &rvnpacket, sizeof(struct rvn), 0); if (br > 0) { switch (rvnpacket.type) { case RVN_HELLO: send(ifd, &rvnpacket, sizeof(rvnpacket), 0); break; case RVN_QUIT: writervnlog(logfile, "Received quit instruction"); writervnlog(logfile, "Closing sockets"); close(ifd); close(cfd); writervnlog(logfile, "Clearing socket names"); unlink(CHILDSOCKNAME); sprintf(logmsg, "rvnamed terminating: max processes spawned: %d", max_fork_count); writervnlog(logfile, logmsg); writervnlog(logfile, "******** rvnamed terminated ********"); fclose(logfile); exit(0); case RVN_REQUEST: readyidx = name_resolved(&rvnpacket, hostlist, lastfree); if (readyidx >= 0) { rvnpacket.type = RVN_REPLY; memset(rvnpacket.fqdn, 0, sizeof(rvnpacket.fqdn)); strncpy(rvnpacket.fqdn, hostlist[readyidx].fqdn, sizeof(rvnpacket.fqdn)-1); rvnpacket.ready = RESOLVED; br = send(ifd, &rvnpacket, sizeof(struct rvn), 0); } else { /* * Add this IP address to the cache if this is a * new one. */ if (addrstat (&rvnpacket, hostlist, lastfree) == NOTRESOLVED) { fflush(logfile); /* flush all data prior */ /* to fork() */ if (fork_count <= MAX_RVNAMED_CHILDREN) { /* * If we can still fork(), we add the data * to the cache array, but we don't update * the indexes until after the fork() * succeeds. If the fork() fails, we'll * just reuse this slot for the next query. * * This is so that if the fork() fails due * to a temporary condition, rvnamed won't * think it's RESOLVING while there isn't * any actual child doing the resolution * before the entry expires. * * However, we'll still tell IPTraf that the * address is RESOLVING. * */ sockaddr_copy(&hostlist[hostindex].addr, &rvnpacket.addr); hostlist[hostindex].ready = RESOLVING; maxlogged = 0; fr = fork(); } else { fr = -1; if (!maxlogged) writervnlog (logfile, "Maximum child process limit reached"); maxlogged = 1; } switch (fr) { case 0: /* spawned child */ fclose(logfile); /* no logging in child */ close(ifd); /* no comm with client */ /* * Set auto-terminate timeout */ signal(SIGALRM, auto_terminate); alarm(300); process_rvn_packet (&rvnpacket); exit(0); case -1: if (!maxlogged) writervnlog (logfile, "Error on fork, returning IP address"); break; default: /* parent */ if (fork_count > max_fork_count) max_fork_count = fork_count; /* * Increase cache indexes only if fork() * succeeded, otherwise the previously * allocated slots will be used for the * next query. */ hostindex++; if (hostindex == NUM_CACHE_ENTRIES) hostindex = 0; if (lastfree < NUM_CACHE_ENTRIES) lastfree++; fork_count++; break; } } rvnpacket.type = RVN_REPLY; sockaddr_ntop(&rvnpacket.addr, rvnpacket.fqdn, sizeof(rvnpacket.fqdn)); rvnpacket.ready = RESOLVING; br = send(ifd, &rvnpacket, sizeof(struct rvn), 0); } } } } /* end block for packets from IPTraf */ } } iptraf-ng-1.2.1/src/rvnamed.h000066400000000000000000000010371370555550300160070ustar00rootroot00000000000000#ifndef IPTRAF_NG_RVNAMED_H #define IPTRAF_NG_RVNAMED_H #include #include #define CHILDSOCKNAME "/dev/rvndcldcomsk" #define PARENTSOCKNAME "/dev/rvndpntcomsk" #define SOCKET_PREFIX "isock" #define NOTRESOLVED 0 #define RESOLVING 1 #define RESOLVED 2 #define RVN_HELLO 0 #define RVN_REQUEST 1 #define RVN_REPLY 2 #define RVN_QUIT 3 #define MAX_RVNAMED_CHILDREN 200 struct rvn { int type; int ready; struct sockaddr_storage addr; char fqdn[45]; }; int rvnamed(int ifd); #endif /* IPTRAF_NG_RVNAMED_H */ iptraf-ng-1.2.1/src/serv.c000066400000000000000000000731031370555550300153300ustar00rootroot00000000000000/* For terms of usage/redistribution/modification see the LICENSE file */ /* For authors and contributors see the AUTHORS file */ /*** serv.c - TCP/UDP port statistics module ***/ #include "iptraf-ng-compat.h" #include "tui/input.h" #include "tui/labels.h" #include "tui/listbox.h" #include "tui/msgboxes.h" #include "dirs.h" #include "deskman.h" #include "fltdefs.h" #include "packet.h" #include "ipfrag.h" #include "ifaces.h" #include "attrs.h" #include "serv.h" #include "servname.h" #include "log.h" #include "timer.h" #include "options.h" #include "packet.h" #include "logvars.h" #include "error.h" #include "counters.h" #include "rate.h" #include "capt.h" #include "timer.h" #define SCROLLUP 0 #define SCROLLDOWN 1 #define LEFT 0 #define RIGHT 1 struct portlistent { in_port_t port; unsigned int protocol; char servname[11]; unsigned int idx; struct proto_counter serv_count; struct proto_counter span; struct timespec proto_starttime; struct rate rate; struct rate rate_in; struct rate rate_out; struct portlistent *prev_entry; struct portlistent *next_entry; }; struct portlist { struct portlistent *head; struct portlistent *tail; struct portlistent *firstvisible; struct portlistent *lastvisible; struct portlistent *barptr; unsigned int count; WINDOW *win; PANEL *panel; WINDOW *borderwin; PANEL *borderpanel; WINDOW *statwin; PANEL *statpanel; }; /* * SIGUSR1 logfile rotation signal handler */ static void rotate_serv_log(int s __unused) { rotate_flag = 1; strcpy(target_logname, current_logfile); signal(SIGUSR1, rotate_serv_log); } static void writeutslog(struct portlistent *list, unsigned long nsecs, FILE *fd) { char atime[TIME_TARGET_MAX]; struct portlistent *ptmp = list; struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); genatime(time(NULL), atime); fprintf(fd, "\n*** TCP/UDP traffic log, generated %s\n\n", atime); while (ptmp != NULL) { unsigned long secs = timespec_diff_msec(&now, &ptmp->proto_starttime) / 1000UL; char bps_string[64]; if (ptmp->protocol == IPPROTO_TCP) fprintf(fd, "TCP/%s: ", ptmp->servname); else fprintf(fd, "UDP/%s: ", ptmp->servname); fprintf(fd, "%llu packets, %llu bytes total", ptmp->serv_count.proto_total.pc_packets, ptmp->serv_count.proto_total.pc_bytes); rate_print(ptmp->serv_count.proto_total.pc_bytes / secs, bps_string, sizeof(bps_string)); fprintf(fd, ", %s", bps_string); fprintf(fd, "; %llu packets, %llu bytes incoming", ptmp->serv_count.proto_in.pc_packets, ptmp->serv_count.proto_in.pc_bytes); rate_print(ptmp->serv_count.proto_in.pc_bytes / secs, bps_string, sizeof(bps_string)); fprintf(fd, ", %s", bps_string); fprintf(fd, "; %llu packets, %llu bytes outgoing", ptmp->serv_count.proto_out.pc_packets, ptmp->serv_count.proto_out.pc_bytes); rate_print(ptmp->serv_count.proto_out.pc_bytes / secs, bps_string, sizeof(bps_string)); fprintf(fd, ", %s", bps_string); fprintf(fd, "\n\n"); ptmp = ptmp->next_entry; } fprintf(fd, "\nRunning time: %lu seconds\n", nsecs); fflush(fd); } static void initportlist(struct portlist *list) { float screen_scale = ((float) COLS / 80 + 1) / 2; list->head = list->tail = list->barptr = NULL; list->firstvisible = list->lastvisible = NULL; list->count = 0; list->borderwin = newwin(LINES - 3, COLS, 1, 0); list->borderpanel = new_panel(list->borderwin); wattrset(list->borderwin, BOXATTR); tx_box(list->borderwin, ACS_VLINE, ACS_HLINE); mvwprintw(list->borderwin, 0, 1 * screen_scale, " Proto/Port "); mvwprintw(list->borderwin, 0, 22 * screen_scale, " Pkts "); mvwprintw(list->borderwin, 0, 31 * screen_scale, " Bytes "); mvwprintw(list->borderwin, 0, 40 * screen_scale, " PktsTo "); mvwprintw(list->borderwin, 0, 49 * screen_scale, " BytesTo "); mvwprintw(list->borderwin, 0, 58 * screen_scale, " PktsFrom "); mvwprintw(list->borderwin, 0, 67 * screen_scale, " BytesFrom "); list->win = newwin(LINES - 5, COLS - 2, 2, 1); list->panel = new_panel(list->win); list->statwin = newwin(1, COLS, LINES - 2, 0); list->statpanel = new_panel(list->statwin); scrollok(list->statwin, 0); wattrset(list->statwin, IPSTATLABELATTR); mvwprintw(list->statwin, 0, 0, "%*c", COLS, ' '); tx_stdwinset(list->win); wtimeout(list->win, -1); wattrset(list->win, STDATTR); tx_colorwin(list->win); move(LINES - 1, 1); scrollkeyhelp(); sortkeyhelp(); stdexitkeyhelp(); update_panels(); doupdate(); } static void print_serv_rates(struct portlist *table) { if (table->barptr == NULL) { wattrset(table->statwin, IPSTATATTR); mvwprintw(table->statwin, 0, 1, "No entries"); } else { char buf[64]; wattrset(table->statwin, IPSTATLABELATTR); mvwprintw(table->statwin, 0, 1, "Protocol data rates:"); mvwprintw(table->statwin, 0, 36, "total"); mvwprintw(table->statwin, 0, 57, "in"); mvwprintw(table->statwin, 0, 76, "out"); wattrset(table->statwin, IPSTATATTR); rate_print(rate_get_average(&table->barptr->rate), buf, sizeof(buf)); mvwprintw(table->statwin, 0, 21, "%s", buf); rate_print(rate_get_average(&table->barptr->rate_in), buf, sizeof(buf)); mvwprintw(table->statwin, 0, 42, "%s", buf); rate_print(rate_get_average(&table->barptr->rate_out), buf, sizeof(buf)); mvwprintw(table->statwin, 0, 61, "%s", buf); } } static struct portlistent *addtoportlist(struct portlist *list, unsigned int protocol, in_port_t port) { struct portlistent *ptemp; ptemp = xmalloc(sizeof(struct portlistent)); if (list->head == NULL) { ptemp->prev_entry = NULL; list->head = ptemp; list->firstvisible = ptemp; } if (list->tail != NULL) { list->tail->next_entry = ptemp; ptemp->prev_entry = list->tail; } list->tail = ptemp; ptemp->next_entry = NULL; ptemp->protocol = protocol; ptemp->port = port; /* This is used in checks later. */ rate_alloc(&ptemp->rate, 5); rate_alloc(&ptemp->rate_in, 5); rate_alloc(&ptemp->rate_out, 5); /* * Obtain appropriate service name */ servlook(port, protocol, ptemp->servname, 10); proto_counter_reset(&ptemp->serv_count); proto_counter_reset(&ptemp->span); list->count++; ptemp->idx = list->count; clock_gettime(CLOCK_MONOTONIC, &ptemp->proto_starttime); if (list->count <= (unsigned) LINES - 5) list->lastvisible = ptemp; mvwprintw(list->borderwin, LINES - 4, 1, " %u entries ", list->count); if (list->barptr == NULL) list->barptr = ptemp; return ptemp; } static int portinlist(struct porttab *table, in_port_t port) { struct porttab *ptmp = table; while (ptmp != NULL) { if (((ptmp->port_max == 0) && (ptmp->port_min == port)) || ((port >= ptmp->port_min) && (port <= ptmp->port_max))) return 1; ptmp = ptmp->next_entry; } return 0; } static int goodport(in_port_t port, struct porttab *table) { return ((port < 1024) || (portinlist(table, port))); } static struct portlistent *inportlist(struct portlist *list, unsigned int protocol, in_port_t port) { struct portlistent *ptmp = list->head; while (ptmp != NULL) { if ((ptmp->port == port) && (ptmp->protocol == protocol)) return ptmp; ptmp = ptmp->next_entry; } return NULL; } static void printportent(struct portlist *list, struct portlistent *entry) { unsigned int target_row; float screen_scale = ((float) COLS / 80 + 1) / 2; int tcplabelattr; int udplabelattr; int highattr; if ((entry->idx < list->firstvisible->idx) || (entry->idx > list->lastvisible->idx)) return; target_row = entry->idx - list->firstvisible->idx; if (entry == list->barptr) { tcplabelattr = BARSTDATTR; udplabelattr = BARPTRATTR; highattr = BARHIGHATTR; } else { tcplabelattr = STDATTR; udplabelattr = PTRATTR; highattr = HIGHATTR; } wattrset(list->win, tcplabelattr); scrollok(list->win, 0); mvwprintw(list->win, target_row, 0, "%*c", COLS - 2, ' '); scrollok(list->win, 1); wmove(list->win, target_row, 1); if (entry->protocol == IPPROTO_TCP) { wattrset(list->win, tcplabelattr); wprintw(list->win, "TCP"); } else if (entry->protocol == IPPROTO_UDP) { wattrset(list->win, udplabelattr); wprintw(list->win, "UDP"); } wprintw(list->win, "/%s ", entry->servname); wattrset(list->win, highattr); wmove(list->win, target_row, 17 * screen_scale); printlargenum(entry->serv_count.proto_total.pc_packets, list->win); wmove(list->win, target_row, 27 * screen_scale); printlargenum(entry->serv_count.proto_total.pc_bytes, list->win); wmove(list->win, target_row, 37 * screen_scale); printlargenum(entry->serv_count.proto_in.pc_packets, list->win); wmove(list->win, target_row, 47 * screen_scale); printlargenum(entry->serv_count.proto_in.pc_bytes, list->win); wmove(list->win, target_row, 57 * screen_scale); printlargenum(entry->serv_count.proto_out.pc_packets, list->win); wmove(list->win, target_row, 67 * screen_scale); printlargenum(entry->serv_count.proto_out.pc_bytes, list->win); } static void destroyportlist(struct portlist *list) { struct portlistent *ptmp = list->head; while (ptmp != NULL) { struct portlistent *ctmp = ptmp->next_entry; rate_destroy(&ptmp->rate_out); rate_destroy(&ptmp->rate_in); rate_destroy(&ptmp->rate); free(ptmp); ptmp = ctmp; } del_panel(list->panel); delwin(list->win); del_panel(list->borderpanel); delwin(list->borderwin); del_panel(list->statpanel); delwin(list->statwin); update_panels(); doupdate(); } static void updateportent(struct portlist *list, unsigned int protocol, in_port_t sport, in_port_t dport, int br, struct porttab *ports) { struct portlistent *sport_listent = NULL; struct portlistent *dport_listent = NULL; enum { PORT_INCOMING = 0, PORT_OUTGOING }; if (goodport(sport, ports)) { sport_listent = inportlist(list, protocol, sport); if (!sport_listent) sport_listent = addtoportlist(list, protocol, sport); if (sport_listent == NULL) return; proto_counter_update(&sport_listent->serv_count, PORT_OUTGOING, br); proto_counter_update(&sport_listent->span, PORT_OUTGOING, br); } if (goodport(dport, ports)) { dport_listent = inportlist(list, protocol, dport); if (!dport_listent) dport_listent = addtoportlist(list, protocol, dport); if (dport_listent == NULL) return; proto_counter_update(&dport_listent->serv_count, PORT_INCOMING, br); proto_counter_update(&dport_listent->span, PORT_INCOMING, br); } } /* * Swap two port list entries. p1 must be previous to p2. */ static void swapportents(struct portlist *list, struct portlistent *p1, struct portlistent *p2) { register unsigned int tmp; struct portlistent *p1prevsaved; struct portlistent *p2nextsaved; if (p1 == p2) return; tmp = p1->idx; p1->idx = p2->idx; p2->idx = tmp; if (p1->prev_entry != NULL) p1->prev_entry->next_entry = p2; else list->head = p2; if (p2->next_entry != NULL) p2->next_entry->prev_entry = p1; else list->tail = p1; p2nextsaved = p2->next_entry; p1prevsaved = p1->prev_entry; if (p1->next_entry == p2) { p2->next_entry = p1; p1->prev_entry = p2; } else { p2->next_entry = p1->next_entry; p1->prev_entry = p2->prev_entry; p2->prev_entry->next_entry = p1; p1->next_entry->prev_entry = p2; } p2->prev_entry = p1prevsaved; p1->next_entry = p2nextsaved; } /* * Retrieve the appropriate sort criterion based on keystroke. */ static unsigned long long qp_getkey(struct portlistent *entry, int ch) { unsigned long long result = 0; switch (ch) { case 'R': result = entry->port; break; case 'B': result = entry->serv_count.proto_total.pc_bytes; break; case 'O': result = entry->serv_count.proto_in.pc_bytes; break; case 'M': result = entry->serv_count.proto_out.pc_bytes; break; case 'P': result = entry->serv_count.proto_total.pc_packets; break; case 'T': result = entry->serv_count.proto_in.pc_packets; break; case 'F': result = entry->serv_count.proto_out.pc_packets; break; } return result; } /* * Refresh TCP/UDP service screen. */ static void refresh_serv_screen(struct portlist *table) { struct portlistent *ptmp = table->firstvisible; wattrset(table->win, STDATTR); tx_colorwin(table->win); while ((ptmp != NULL) && (ptmp->prev_entry != table->lastvisible)) { printportent(table, ptmp); ptmp = ptmp->next_entry; } update_panels(); doupdate(); } /* * Compare the sort criterion with the pivot value. Receives a parameter * specifying whether the criterion is left or right of the pivot value. * * If criterion is the port number: return true if criterion is less than or * equal to the pivot when the SIDE is left. If SIDE is right, return * true if the value is greater than the pivot. This results in an * ascending sort. * * If the criterion is a count: return true when the criterion is greater than * or equal to the pivot when the SIDE is left, otherwise, when SIDE is * right, return true if the value is less than the pivot. This results * in a descending sort. */ static int qp_compare(struct portlistent *entry, unsigned long long pv, int ch, int side) { int result = 0; unsigned long long value; value = qp_getkey(entry, ch); if (ch == 'R') { if (side == LEFT) result = (value <= pv); else result = (value > pv); } else { if (side == LEFT) result = (value >= pv); else result = (value < pv); } return result; } /* * Partition port list such that a pivot is selected, and that all values * left of the pivot are less (or greater) than or equal to the pivot, * and that all values right of the pivot are greater (or less) than * the pivot. */ static struct portlistent *qp_partition(struct portlist *table, struct portlistent **low, struct portlistent **high, int ch) { struct portlistent *pivot = *low; struct portlistent *left = *low; struct portlistent *right = *high; struct portlistent *ptmp; unsigned long long pivot_value; pivot_value = qp_getkey(pivot, ch); while (left->idx < right->idx) { while ((qp_compare(left, pivot_value, ch, LEFT)) && (left->next_entry != NULL)) left = left->next_entry; while (qp_compare(right, pivot_value, ch, RIGHT)) right = right->prev_entry; if (left->idx < right->idx) { swapportents(table, left, right); if (*low == left) *low = right; if (*high == right) *high = left; ptmp = left; left = right; right = ptmp; } } swapportents(table, pivot, right); if (*low == pivot) *low = right; if (*high == right) *high = pivot; return pivot; } /* * Quicksort for the port list. */ static void quicksort_port_entries(struct portlist *table, struct portlistent *low, struct portlistent *high, int ch) { struct portlistent *pivot; if ((high == NULL) || (low == NULL)) return; if (high->idx > low->idx) { pivot = qp_partition(table, &low, &high, ch); quicksort_port_entries(table, low, pivot->prev_entry, ch); quicksort_port_entries(table, pivot->next_entry, high, ch); } } static void sortportents(struct portlist *list, int command) { if (!(list->head)) return; command = toupper(command); if ((command != 'R') && (command != 'B') && (command != 'O') && (command != 'M') && (command != 'P') && (command != 'T') && (command != 'F')) return; quicksort_port_entries(list, list->head, list->tail, command); list->firstvisible = list->head; struct portlistent *ptmp = list->head; while (ptmp && ((int)ptmp->idx <= getmaxy(list->win))) { list->lastvisible = ptmp; ptmp = ptmp->next_entry; } } static void scrollservwin(struct portlist *table, int direction) { wattrset(table->win, STDATTR); if (direction == SCROLLUP) { if (table->lastvisible != table->tail) { table->firstvisible = table->firstvisible->next_entry; table->lastvisible = table->lastvisible->next_entry; wscrl(table->win, 1); scrollok(table->win, 0); mvwprintw(table->win, LINES - 6, 0, "%*c", COLS - 2, ' '); scrollok(table->win, 1); printportent(table, table->lastvisible); } } else { if (table->firstvisible != table->head) { table->firstvisible = table->firstvisible->prev_entry; table->lastvisible = table->lastvisible->prev_entry; wscrl(table->win, -1); mvwprintw(table->win, 0, 0, "%*c", COLS - 2, ' '); printportent(table, table->firstvisible); } } } static void move_bar_one(struct portlist *table, int direction) { switch (direction) { case SCROLLDOWN: if (table->barptr->prev_entry == NULL) break; if (table->barptr == table->firstvisible) scrollservwin(table, SCROLLDOWN); table->barptr = table->barptr->prev_entry; printportent(table, table->barptr->next_entry); /* hide bar */ printportent(table, table->barptr); /* show bar */ break; case SCROLLUP: if (table->barptr->next_entry == NULL) break; if (table->barptr == table->lastvisible) scrollservwin(table, SCROLLUP); table->barptr = table->barptr->next_entry; printportent(table, table->barptr->prev_entry); /* hide bar */ printportent(table, table->barptr); /* show bar */ break; } } static void move_bar_many(struct portlist *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; } refresh_serv_screen(table); } static void move_bar(struct portlist *table, int direction, int lines) { if (table->barptr == NULL) return; if (lines < 1) return; if (lines < 16) while (lines--) move_bar_one(table, direction); else move_bar_many(table, direction, lines); print_serv_rates(table); } static void show_portsort_keywin(WINDOW ** win, PANEL ** panel) { *win = newwin(14, 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("R", " - port number", *win, DLGHIGHATTR, DLGTEXTATTR); wmove(*win, 5, 2); tx_printkeyhelp("P", " - total packets", *win, DLGHIGHATTR, DLGTEXTATTR); wmove(*win, 6, 2); tx_printkeyhelp("B", " - total bytes", *win, DLGHIGHATTR, DLGTEXTATTR); wmove(*win, 7, 2); tx_printkeyhelp("T", " - packets to", *win, DLGHIGHATTR, DLGTEXTATTR); wmove(*win, 8, 2); tx_printkeyhelp("O", " - bytes to", *win, DLGHIGHATTR, DLGTEXTATTR); wmove(*win, 9, 2); tx_printkeyhelp("F", " - packets from", *win, DLGHIGHATTR, DLGTEXTATTR); wmove(*win, 10, 2); tx_printkeyhelp("M", " - bytes from", *win, DLGHIGHATTR, DLGTEXTATTR); wmove(*win, 11, 2); tx_printkeyhelp("Any other key", " - cancel sort", *win, DLGHIGHATTR, DLGTEXTATTR); update_panels(); doupdate(); } static void update_serv_rates(struct portlist *list, unsigned long msecs) { /* update rates of all portlistents */ for (struct portlistent *ple = list->head; ple != NULL; ple = ple->next_entry) { rate_add_rate(&ple->rate, ple->span.proto_total.pc_bytes, msecs); rate_add_rate(&ple->rate_in, ple->span.proto_in.pc_bytes, msecs); rate_add_rate(&ple->rate_out, ple->span.proto_out.pc_bytes, msecs); proto_counter_reset(&ple->span); } } static void serv_process_key(struct portlist *table, int ch) { static WINDOW *sortwin; static PANEL *sortpanel; static int keymode = 0; if (keymode == 0) { switch (ch) { case KEY_UP: move_bar(table, SCROLLDOWN, 1); break; case KEY_DOWN: move_bar(table, SCROLLUP, 1); break; case KEY_PPAGE: case '-': move_bar(table, SCROLLDOWN, LINES - 5); break; case KEY_NPAGE: case ' ': move_bar(table, SCROLLUP, LINES - 5); break; case KEY_HOME: move_bar(table, SCROLLDOWN, INT_MAX); break; case KEY_END: move_bar(table, SCROLLUP, INT_MAX); break; case 12: case 'l': case 'L': tx_refresh_screen(); break; case 's': case 'S': show_portsort_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); sortportents(table, ch); keymode = 0; refresh_serv_screen(table); table->barptr = table->firstvisible; print_serv_rates(table); update_panels(); doupdate(); } } static void serv_process_packet(struct portlist *table, struct pkt_hdr *pkt, struct porttab *ports) { unsigned int tot_br; in_port_t sport = 0; in_port_t dport = 0; int pkt_result = packet_process(pkt, &tot_br, &sport, &dport, MATCH_OPPOSITE_USECONFIG, options.v6inv4asv6); if (pkt_result != PACKET_OK) return; unsigned short iplen; switch (pkt->pkt_protocol) { case ETH_P_IP: iplen = ntohs(pkt->iphdr->tot_len); break; case ETH_P_IPV6: iplen = ntohs(pkt->ip6_hdr->ip6_plen) + 40; break; default: /* unknown link protocol */ return; } __u8 ip_protocol = pkt_ip_protocol(pkt); switch (ip_protocol) { case IPPROTO_TCP: case IPPROTO_UDP: updateportent(table, ip_protocol, sport, dport, iplen, ports); break; default: /* unknown L4 protocol */ return; } } /* * The TCP/UDP service monitor */ void servmon(char *ifname, time_t facilitytime) { int logging = options.logging; int ch; struct portlist list; FILE *logfile = NULL; struct capt capt; struct porttab *ports; struct pkt_hdr pkt; if (!dev_up(ifname)) { err_iface_down(); return; } initportlist(&list); loadaddports(&ports); if (capt_init(&capt, ifname) == -1) { write_error("Unable to initialize packet capture interface"); goto err; } if (logging) { if (strcmp(current_logfile, "") == 0) { snprintf(current_logfile, 80, "%s-%s.log", TCPUDPLOG, ifname); if (!daemonized) input_logfile(current_logfile, &logging); } } if (logging) { opentlog(&logfile, current_logfile); if (logfile == NULL) logging = 0; } if (logging) { signal(SIGUSR1, rotate_serv_log); rotate_flag = 0; writelog(logging, logfile, "******** TCP/UDP service monitor started ********"); } if (options.servnames) setservent(1); 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 rate_msecs = timespec_diff_msec(&now, &last_time); /* update all portlistent rates ... */ update_serv_rates(&list, rate_msecs); /* ... and print the current one */ print_serv_rates(&list); printelapsedtime(now.tv_sec - starttime, 20, list.borderwin); print_packet_drops(capt_get_dropped(&capt), list.borderwin, 49); if (now.tv_sec > endtime) exitloop = 1; if (logging && (now.tv_sec > log_next)) { check_rotate_flag(&logfile); writeutslog(list.head, now.tv_sec - starttime, logfile); log_next = now.tv_sec + options.logspan; } last_time = now; } if (time_after(&now, &next_screen_update)) { refresh_serv_screen(&list); update_panels(); doupdate(); set_next_screen_update(&next_screen_update, &now); } if (capt_get_packet(&capt, &pkt, &ch, list.win) == -1) { write_error("Packet receive failed"); exitloop = 1; break; } if (ch != ERR) serv_process_key(&list, ch); if (pkt.pkt_len > 0) { serv_process_packet(&list, &pkt, ports); capt_put_packet(&capt, &pkt); } } packet_destroy(&pkt); if (options.servnames) endservent(); if (logging) { signal(SIGUSR1, SIG_DFL); writeutslog(list.head, time(NULL) - starttime, logfile); writelog(logging, logfile, "******** TCP/UDP service monitor stopped ********"); fclose(logfile); } strcpy(current_logfile, ""); capt_destroy(&capt); err: destroyporttab(ports); destroyportlist(&list); } static void portdlg(in_port_t *port_min, in_port_t *port_max, int *aborted) { WINDOW *bw; PANEL *bp; WINDOW *win; PANEL *panel; struct FIELDLIST list; bw = newwin(14, 50, (LINES - 14) / 2, (COLS - 50) / 2 - 10); bp = new_panel(bw); win = newwin(12, 48, (LINES - 14) / 2 + 1, (COLS - 50) / 2 - 9); panel = new_panel(win); wattrset(bw, DLGBOXATTR); tx_box(bw, ACS_VLINE, ACS_HLINE); wattrset(win, DLGTEXTATTR); tx_colorwin(win); tx_stdwinset(win); wtimeout(win, -1); mvwprintw(win, 1, 1, "Port numbers below 1024 are reserved for"); mvwprintw(win, 2, 1, "TCP/IP services, and are normally the only"); mvwprintw(win, 3, 1, "ones monitored by the TCP/UDP statistics"); mvwprintw(win, 4, 1, "module. If you wish to monitor a higher-"); mvwprintw(win, 5, 1, "numbered port or range of ports, enter it"); mvwprintw(win, 6, 1, "here. Fill just the first field for a"); mvwprintw(win, 7, 1, "single port, or both fields for a range."); wmove(win, 11, 1); tabkeyhelp(win); stdkeyhelp(win); tx_initfields(&list, 1, 20, (LINES - 14) / 2 + 10, (COLS - 50) / 2 - 8, DLGTEXTATTR, FIELDATTR); mvwprintw(list.fieldwin, 0, 6, "to"); tx_addfield(&list, 5, 0, 0, ""); tx_addfield(&list, 5, 0, 9, ""); int ok; do { unsigned int val; int ret; ok = 1; tx_fillfields(&list, aborted); if (*aborted) break; ret = strtoul_ui(list.list->buf, 10, &val); if (ret == -1 || val > 65535) { tui_error(ANYKEY_MSG, "Invalid port"); ok = 0; continue; } *port_min = val; if (list.list->nextfield->buf[0] != '\0') { ret = strtoul_ui(list.list->nextfield->buf, 10, &val); if (ret == -1 || val > 65535 || *port_min > val) { tui_error(ANYKEY_MSG, "Invalid port"); ok = 0; continue; } *port_max = val; } else *port_max = 0; } while (!ok); del_panel(bp); delwin(bw); del_panel(panel); delwin(win); tx_destroyfields(&list); } static void saveportlist(struct porttab *table) { struct porttab *ptmp = table; int fd; int bw; fd = open(PORTFILE, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR); if (fd < 0) { tui_error(ANYKEY_MSG, "Unable to open port list file"); return; } while (ptmp != NULL) { bw = write(fd, &(ptmp->port_min), sizeof(unsigned int)); bw = write(fd, &(ptmp->port_max), sizeof(unsigned int)); if (bw < 0) { tui_error(ANYKEY_MSG, "Unable to write port/range entry"); destroyporttab(table); close(fd); return; } ptmp = ptmp->next_entry; } close(fd); } static int dup_portentry(struct porttab *table, unsigned int min, unsigned int max) { struct porttab *ptmp = table; while (ptmp != NULL) { if ((ptmp->port_min == min) && (ptmp->port_max == max)) return 1; ptmp = ptmp->next_entry; } return 0; } void addmoreports(struct porttab **table) { in_port_t port_min = 0, port_max = 0; int aborted; struct porttab *ptmp; portdlg(&port_min, &port_max, &aborted); if (!aborted) { if (dup_portentry(*table, port_min, port_max)) tui_error(ANYKEY_MSG, "Duplicate port/range entry"); else { ptmp = xmalloc(sizeof(struct porttab)); ptmp->port_min = port_min; ptmp->port_max = port_max; ptmp->prev_entry = NULL; ptmp->next_entry = *table; if (*table != NULL) (*table)->prev_entry = ptmp; *table = ptmp; saveportlist(*table); } } update_panels(); doupdate(); } void loadaddports(struct porttab **table) { int fd; struct porttab *ptemp; struct porttab *tail = NULL; int br; *table = NULL; fd = open(PORTFILE, O_RDONLY); if (fd < 0) return; do { ptemp = xmalloc(sizeof(struct porttab)); br = read(fd, &(ptemp->port_min), sizeof(unsigned int)); br = read(fd, &(ptemp->port_max), sizeof(unsigned int)); if (br < 0) { tui_error(ANYKEY_MSG, "Error reading port list"); close(fd); destroyporttab(*table); return; } if (br > 0) { if (*table == NULL) { *table = ptemp; ptemp->prev_entry = NULL; } if (tail != NULL) { tail->next_entry = ptemp; ptemp->prev_entry = tail; } tail = ptemp; ptemp->next_entry = NULL; } else free(ptemp); } while (br > 0); close(fd); } static void operate_portselect(struct porttab **table, struct porttab **node, int *aborted) { struct scroll_list list; char listtext[20]; tx_init_listbox(&list, 25, 22, (COLS - 25) / 2, (LINES - 22) / 2, STDATTR, BOXATTR, BARSTDATTR, HIGHATTR); tx_set_listbox_title(&list, "Select Port/Range", 1); *node = *table; while (*node != NULL) { snprintf(listtext, 20, "%d to %d", (*node)->port_min, (*node)->port_max); tx_add_list_entry(&list, (char *) *node, listtext); *node = (*node)->next_entry; } tx_show_listbox(&list); tx_operate_listbox(&list, aborted); if (!(*aborted)) *node = (struct porttab *) list.textptr->nodeptr; tx_close_listbox(&list); tx_destroy_list(&list); } static void selectport(struct porttab **table, struct porttab **node, int *aborted) { if (*table == NULL) { tui_error(ANYKEY_MSG, "No custom ports"); return; } operate_portselect(table, node, aborted); } static void delport(struct porttab **table, struct porttab *ptmp) { if (ptmp != NULL) { if (ptmp == *table) { *table = (*table)->next_entry; if (*table != NULL) (*table)->prev_entry = NULL; } else { ptmp->prev_entry->next_entry = ptmp->next_entry; if (ptmp->next_entry != NULL) ptmp->next_entry->prev_entry = ptmp->prev_entry; } free(ptmp); } } void removeaport(struct porttab **table) { int aborted; struct porttab *ptmp = NULL; selectport(table, &ptmp, &aborted); if (!aborted && ptmp) { delport(table, ptmp); saveportlist(*table); } } void destroyporttab(struct porttab *table) { while (table != NULL) { struct porttab *ptemp = table->next_entry; free(table); table = ptemp; } } iptraf-ng-1.2.1/src/serv.h000066400000000000000000000007421370555550300153340ustar00rootroot00000000000000#ifndef IPTRAF_NG_SERV_H #define IPTRAF_NG_SERV_H /*** serv.h - TCP/UDP port statistics header file ***/ struct porttab { in_port_t port_min; in_port_t port_max; struct porttab *prev_entry; struct porttab *next_entry; }; void addmoreports(struct porttab **table); void loadaddports(struct porttab **table); void destroyporttab(struct porttab *table); void removeaport(struct porttab **table); void servmon(char *iface, time_t facilitytime); #endif /* IPTRAF_NG_SERV_H */ iptraf-ng-1.2.1/src/servname.c000066400000000000000000000013331370555550300161650ustar00rootroot00000000000000/* For terms of usage/redistribution/modification see the LICENSE file */ /* For authors and contributors see the AUTHORS file */ /*** servname.c - lookup module for TCP and UDP service names based on port numbers ***/ #include "iptraf-ng-compat.h" #include "options.h" void servlook(in_port_t port, unsigned int protocol, char *target, int maxlen) { static struct servent *sve; memset(target, 0, maxlen + 1); if (options.servnames) { if (protocol == IPPROTO_TCP) sve = getservbyport(htons(port), "tcp"); else sve = getservbyport(htons(port), "udp"); if (sve != NULL) { strncpy(target, sve->s_name, maxlen); } else { sprintf(target, "%u", port); } } else { sprintf(target, "%u", port); } } iptraf-ng-1.2.1/src/servname.h000066400000000000000000000003561370555550300161760ustar00rootroot00000000000000#ifndef IPTRAF_NG_SERVNAME_H #define IPTRAF_NG_SERVNAME_H /*** servname.h - function prototype for service lookup ***/ void servlook(in_port_t port, unsigned int protocol, char *target, int maxlen); #endif /* IPTRAF_NG_SERVNAME_H */ iptraf-ng-1.2.1/src/sockaddr.c000066400000000000000000000113351370555550300161420ustar00rootroot00000000000000/* For terms of usage/redistribution/modification see the LICENSE file */ /* For authors and contributors see the AUTHORS file */ #include "iptraf-ng-compat.h" void sockaddr_make_ipv4(struct sockaddr_storage *sockaddr, u_int32_t addr) { if (!sockaddr) die("%s(): sockaddr == NULL", __FUNCTION__); memset(sockaddr, 0, sizeof(*sockaddr)); struct sockaddr_in *sockaddr_in = (struct sockaddr_in *)sockaddr; sockaddr_in->sin_family = AF_INET; sockaddr_in->sin_port = 0; sockaddr_in->sin_addr.s_addr = addr; } void sockaddr_make_ipv6(struct sockaddr_storage *sockaddr, struct in6_addr *addr) { if (!sockaddr) die("%s(): sockaddr == NULL", __FUNCTION__); if (!addr) die("%s(): addr == NULL", __FUNCTION__); memset(sockaddr, 0, sizeof(*sockaddr)); struct sockaddr_in6 *sockaddr_in6 = (struct sockaddr_in6 *)sockaddr; sockaddr_in6->sin6_family = AF_INET6; sockaddr_in6->sin6_port = 0; sockaddr_in6->sin6_addr = *addr; sockaddr_in6->sin6_flowinfo = 0; sockaddr_in6->sin6_scope_id = 0; } in_port_t sockaddr_get_port(struct sockaddr_storage *sockaddr) { if (!sockaddr) die("%s(): sockaddr == NULL", __FUNCTION__); switch (sockaddr->ss_family) { case AF_INET: return ((struct sockaddr_in *)sockaddr)->sin_port; case AF_INET6: return ((struct sockaddr_in6 *)sockaddr)->sin6_port; default: die("%s(): Unknown address family", __FUNCTION__); } } void sockaddr_set_port(struct sockaddr_storage *sockaddr, in_port_t port) { if (!sockaddr) die("%s(): sockaddr == NULL", __FUNCTION__); switch (sockaddr->ss_family) { case AF_INET: ((struct sockaddr_in *)sockaddr)->sin_port = port; break; case AF_INET6: ((struct sockaddr_in6 *)sockaddr)->sin6_port = port; break; default: die("%s(): Unknown address family", __FUNCTION__); } } static bool _sockaddr_is_equal(struct sockaddr_storage const *addr1, struct sockaddr_storage const *addr2, bool check_address_only) { if (!addr1) die("%s(): addr1 == NULL", __FUNCTION__); if (!addr2) die("%s(): addr2 == NULL", __FUNCTION__); if (addr1->ss_family != addr2->ss_family) return false; switch (addr1->ss_family) { case AF_INET: { struct sockaddr_in *sa1 = (struct sockaddr_in *)addr1; struct sockaddr_in *sa2 = (struct sockaddr_in *)addr2; if (sa1->sin_addr.s_addr != sa2->sin_addr.s_addr) return false; if (check_address_only) return true; if (sa1->sin_port != sa2->sin_port) return false; /* all equal */ return true; } case AF_INET6: { struct sockaddr_in6 *sa1 = (struct sockaddr_in6 *)addr1; struct sockaddr_in6 *sa2 = (struct sockaddr_in6 *)addr2; if (memcmp(&sa1->sin6_addr, &sa2->sin6_addr, sizeof(sa1->sin6_addr)) != 0) return false; if (check_address_only) return true; if (sa1->sin6_port != sa2->sin6_port) return false; if (sa1->sin6_flowinfo != sa2->sin6_flowinfo) return false; if (sa1->sin6_scope_id != sa2->sin6_scope_id) return false; /* all equal */ return true; } default: die("%s(): Unknown address family", __FUNCTION__); } } bool sockaddr_is_equal(struct sockaddr_storage const *addr1, struct sockaddr_storage const *addr2) { return _sockaddr_is_equal(addr1, addr2, false); } bool sockaddr_addr_is_equal(struct sockaddr_storage const *addr1, struct sockaddr_storage const *addr2) { return _sockaddr_is_equal(addr1, addr2, true); } void sockaddr_ntop(const struct sockaddr_storage *addr, char *buf, size_t buflen) { if(!addr) die("%s(): addr == NULL", __FUNCTION__); const char *ret; size_t minlen; memset(buf, 0, buflen); switch (addr->ss_family) { case AF_INET: minlen = INET_ADDRSTRLEN; ret = inet_ntop(AF_INET, &((struct sockaddr_in *)addr)->sin_addr, buf, buflen - 1); break; case AF_INET6: minlen = INET6_ADDRSTRLEN; ret = inet_ntop(AF_INET6, &((struct sockaddr_in6 *)addr)->sin6_addr, buf, buflen - 1); break; default: die("%s(): Unknown address family", __FUNCTION__); } if (ret == NULL) { switch (errno) { case ENOSPC: die("%s(): buffer too small (must be at least %zu bytes)", __FUNCTION__, minlen); case EAFNOSUPPORT: die("%s(): Unknown address family", __FUNCTION__); } } } void sockaddr_gethostbyaddr(const struct sockaddr_storage *addr, char *buffer, size_t buflen) { char hostbuf[NI_MAXHOST]; int res = getnameinfo((struct sockaddr *)addr, sizeof(*addr), hostbuf, sizeof(hostbuf), NULL, 0, 0 /* flags */); if (res == 0) { snprintf(buffer, buflen - 1, "%s", hostbuf); buffer[buflen - 1] = '\0'; } else sockaddr_ntop(addr, buffer, buflen); } void sockaddr_copy(struct sockaddr_storage *dest, struct sockaddr_storage *src) { if (!src) die("%s(): src == NULL", __FUNCTION__); if (!dest) die("%s(): dest == NULL", __FUNCTION__); memcpy(dest, src, sizeof(struct sockaddr_storage)); } iptraf-ng-1.2.1/src/sockaddr.h000066400000000000000000000015651370555550300161530ustar00rootroot00000000000000#ifndef IPTRAF_NG_SOCKADDR_H #define IPTRAF_NG_SOCKADDR_H void sockaddr_make_ipv4(struct sockaddr_storage *sockaddr, u_int32_t addr); void sockaddr_make_ipv6(struct sockaddr_storage *sockaddr, struct in6_addr *addr); in_port_t sockaddr_get_port(struct sockaddr_storage *sockaddr); void sockaddr_set_port(struct sockaddr_storage *sockaddr, in_port_t port); bool sockaddr_is_equal(struct sockaddr_storage const *addr1, struct sockaddr_storage const *addr2); bool sockaddr_addr_is_equal(struct sockaddr_storage const *addr1, struct sockaddr_storage const *addr2); void sockaddr_ntop(const struct sockaddr_storage *addr, char *buf, size_t buflen); void sockaddr_gethostbyaddr(const struct sockaddr_storage *addr, char *buffer, size_t buflen); void sockaddr_copy(struct sockaddr_storage *dest, struct sockaddr_storage *src); #endif /* IPTRAF_NG_SOCKADDR_H */ iptraf-ng-1.2.1/src/tcptable.c000066400000000000000000000731061370555550300161520ustar00rootroot00000000000000/* For terms of usage/redistribution/modification see the LICENSE file */ /* For authors and contributors see the AUTHORS file */ /*** tcptable.c - table manipulation routines for the IP monitor ***/ #include "iptraf-ng-compat.h" #include "tui/winops.h" #include "options.h" #include "revname.h" #include "tcptable.h" #include "deskman.h" #include "attrs.h" #include "log.h" #include "rvnamed.h" #include "servname.h" #include "hostmon.h" #include "sockaddr.h" #define MSGSTRING_MAX 320 unsigned int bmaxy = 0; unsigned int imaxy = 0; static void setlabels(WINDOW *win, int mode) { wmove(win, 0, 42 * COLS / 80); whline(win, ACS_HLINE, 23 * COLS / 80); if (mode == 0) { mvwprintw(win, 0, 47 * COLS / 80, " Packets "); mvwprintw(win, 0, 59 * COLS / 80, " Bytes "); } else if (mode == 1) { mvwprintw(win, 0, 47 * COLS / 80, " Source MAC Addr "); } else if (mode == 2) { mvwprintw(win, 0, 45 * COLS / 80, " Pkt Size "); mvwprintw(win, 0, 56 * COLS / 80, " Win Size "); } } /* * The hash function for the TCP hash table */ static unsigned int tcp_hash(struct sockaddr_storage *saddr, struct sockaddr_storage *daddr, char *ifname) { size_t i; unsigned int ifsum = 0; for (i = 0; i < strlen(ifname); i++) ifsum += ifname[i]; switch (saddr->ss_family) { case AF_INET: ifsum += 4 * ((struct sockaddr_in *)saddr)->sin_addr.s_addr; ifsum += 3 * ((struct sockaddr_in *)saddr)->sin_port; break; case AF_INET6: { unsigned int ip6sum = 0; for (i = 0; i < 4; i++) ip6sum ^= ((struct sockaddr_in6 *)saddr)->sin6_addr.s6_addr32[i]; ifsum += 4 * ip6sum; ifsum += 3 * ((struct sockaddr_in6 *)saddr)->sin6_port; break; } default: die("%s(): saddr: unknown address family", __FUNCTION__); } switch (daddr->ss_family) { case AF_INET: ifsum += 2 * ((struct sockaddr_in *)daddr)->sin_addr.s_addr; ifsum += ((struct sockaddr_in *)daddr)->sin_port; break; case AF_INET6: { unsigned int ip6sum = 0; for (i = 0; i < 4; i++) ip6sum ^= ((struct sockaddr_in6 *)daddr)->sin6_addr.s6_addr32[i]; ifsum += 2 * ip6sum; ifsum += ((struct sockaddr_in6 *)daddr)->sin6_port; break; } default: die("%s(): daddr: unknown address family", __FUNCTION__); } return (ifsum % ENTRIES_IN_HASH_TABLE); } static void print_tcp_num_entries(struct tcptable *table) { mvwprintw(table->borderwin, table->bmaxy - 1, 1, " TCP: %6u entries ", table->count); } static void prepare_statwin(WINDOW *win) { wattrset(win, IPSTATLABELATTR); mvwprintw(win, 0, 1, "Packets captured:"); mvwaddch(win, 0, 45 * COLS / 80, ACS_VLINE); } void show_stats(WINDOW *win, unsigned long long total) { wattrset(win, IPSTATATTR); wmove(win, 0, 35 * COLS / 80); printlargenum(total, win); } void init_tcp_table(struct tcptable *table) { int i; table->bmaxy = LINES * 0.6; /* 60% of total screen */ table->imaxy = table->bmaxy - 2; table->borderwin = newwin(table->bmaxy, COLS, 1, 0); table->borderpanel = new_panel(table->borderwin); wattrset(table->borderwin, BOXATTR); tx_box(table->borderwin, ACS_VLINE, ACS_HLINE); mvwprintw(table->borderwin, 0, 1, " TCP Connections (Source Host:Port) "); setlabels(table->borderwin, 0); /* initially use mode 0 */ table->mode = 0; mvwprintw(table->borderwin, 0, 65 * COLS / 80, " Flag "); mvwprintw(table->borderwin, 0, 70 * COLS / 80, " Iface "); update_panels(); doupdate(); table->ifnamew = COLS - (70 * COLS / 80) - 3; if (table->ifnamew < 7) table->ifnamew = 7; if (table->ifnamew > IFNAMSIZ) table->ifnamew = IFNAMSIZ; table->head = table->tail = NULL; table->firstvisible = table->lastvisible = NULL; table->tcpscreen = newwin(table->imaxy, COLS - 2, 2, 1); table->tcppanel = new_panel(table->tcpscreen); table->closedentries = table->closedtail = NULL; wattrset(table->tcpscreen, BOXATTR); tx_colorwin(table->tcpscreen); table->lastpos = 0; table->count = 0; wtimeout(table->tcpscreen, -1); tx_stdwinset(table->tcpscreen); print_tcp_num_entries(table); table->statwin = newwin(1, COLS, LINES - 2, 0); table->statpanel = new_panel(table->statwin); wattrset(table->statwin, IPSTATLABELATTR); mvwprintw(table->statwin, 0, 0, "%*c", COLS, ' '); prepare_statwin(table->statwin); show_stats(table->statwin, 0); /* * Initialize hash table to nulls */ for (i = 0; i <= ENTRIES_IN_HASH_TABLE - 1; i++) { table->hash_table[i] = NULL; table->hash_tails[i] = NULL; } table->barptr = NULL; } /* * Add a TCP entry to the hash table. */ static void add_tcp_hash_entry(struct tcptable *table, struct tcptableent *entry) { unsigned int hp; /* hash position in table */ struct tcp_hashentry *ptmp; hp = tcp_hash(&entry->saddr, &entry->daddr, entry->ifname); ptmp = xmallocz(sizeof(struct tcp_hashentry)); /* * Add backpointer from screen node to hash node for deletion later * (Actually point to its predecessor coz of the header cell). */ entry->hash_node = ptmp; /* * Update hash node and add it to list. */ ptmp->tcpnode = entry; ptmp->hp = hp; if (table->hash_table[hp] == NULL) { ptmp->prev_entry = NULL; table->hash_table[hp] = ptmp; ptmp->index = 1; } if (table->hash_tails[hp] != NULL) { table->hash_tails[hp]->next_entry = ptmp; ptmp->prev_entry = table->hash_tails[hp]; ptmp->index = ptmp->prev_entry->index + 1; } table->hash_tails[hp] = ptmp; ptmp->next_entry = NULL; } /* * Delete a hash table node */ static void del_tcp_hash_node(struct tcptable *table, struct tcptableent *entry) { struct tcp_hashentry *ptmp; ptmp = entry->hash_node; /* ptmp now points to the target */ /* * If the targeted node is the last entry, adjust the corresponding tail * pointer to the preceeding node; */ if (ptmp->next_entry == NULL) table->hash_tails[ptmp->hp] = ptmp->prev_entry; if (ptmp->prev_entry != NULL) ptmp->prev_entry->next_entry = ptmp->next_entry; else table->hash_table[ptmp->hp] = ptmp->next_entry; if (ptmp->next_entry != NULL) ptmp->next_entry->prev_entry = ptmp->prev_entry; free(ptmp); } static void resolve_entry(struct tcptableent *entry, struct resolver *res) { if (entry->s_fstat != RESOLVED) { entry->s_fstat = revname(res, &entry->saddr, entry->s_fqdn, sizeof(entry->s_fqdn)); strcpy(entry->oth_connection->d_fqdn, entry->s_fqdn); entry->oth_connection->d_fstat = entry->s_fstat; } if (entry->d_fstat != RESOLVED) { entry->d_fstat = revname(res, &entry->daddr, entry->d_fqdn, sizeof(entry->d_fqdn)); strcpy(entry->oth_connection->s_fqdn, entry->d_fqdn); entry->oth_connection->s_fstat = entry->d_fstat; } } /* * Add a new entry to the TCP screen table */ struct tcptableent *addentry(struct tcptable *table, struct sockaddr_storage *saddr, struct sockaddr_storage *daddr, int protocol, char *ifname, struct resolver *res) { struct tcptableent *new_entry; struct closedlist *ctemp; /* * Allocate and attach a new node if no closed entries found */ if (table->closedentries == NULL) { new_entry = xmalloc(sizeof(struct tcptableent)); new_entry->oth_connection = xmalloc(sizeof(struct tcptableent)); new_entry->oth_connection->oth_connection = new_entry; if (table->head == NULL) { new_entry->prev_entry = NULL; table->head = new_entry; table->firstvisible = new_entry; table->barptr = new_entry; } if (table->tail != NULL) { table->tail->next_entry = new_entry; new_entry->prev_entry = table->tail; } table->lastpos++; new_entry->index = table->lastpos; table->lastpos++; new_entry->oth_connection->index = table->lastpos; table->tail = new_entry->oth_connection; new_entry->next_entry = new_entry->oth_connection; new_entry->next_entry->prev_entry = new_entry; new_entry->next_entry->next_entry = NULL; if (new_entry->oth_connection->index <= table->firstvisible->index + (table->imaxy - 1)) table->lastvisible = new_entry->oth_connection; else if (new_entry->index <= table->firstvisible->index + (table->imaxy - 1)) table->lastvisible = new_entry; table->count++; rate_alloc(&new_entry->rate, 5); rate_alloc(&new_entry->oth_connection->rate, 5); } else { /* * If we reach this point, we're allocating off the list of closed * entries. In this case, we take the top entry, let the new_entry * variable point to whatever the top is pointing to. The new_entry's * oth_connection also points to the reused entry's oth_connection */ new_entry = table->closedentries->closedentry; new_entry->oth_connection = table->closedentries->pair; ctemp = table->closedentries; table->closedentries = table->closedentries->next_entry; free(ctemp); /* * Mark the closed list's tail as NULL if we use the last entry * in the list to prevent a dangling reference. */ if (table->closedentries == NULL) table->closedtail = NULL; /* * Delete the old hash entries for this reallocated node; */ del_tcp_hash_node(table, new_entry); del_tcp_hash_node(table, new_entry->oth_connection); } /* * Fill in address fields with raw IP addresses */ sockaddr_copy(&new_entry->saddr, saddr); sockaddr_copy(&new_entry->oth_connection->daddr, saddr); sockaddr_copy(&new_entry->daddr, daddr); sockaddr_copy(&new_entry->oth_connection->saddr, daddr); new_entry->protocol = protocol; /* * Initialize count fields */ new_entry->pcount = new_entry->bcount = 0; new_entry->win = new_entry->psize = 0; new_entry->timedout = new_entry->oth_connection->timedout = 0; new_entry->oth_connection->pcount = new_entry->oth_connection->bcount = 0; new_entry->oth_connection->win = new_entry->oth_connection->psize = 0; /* * Store interface name */ strcpy(new_entry->ifname, ifname); strcpy(new_entry->oth_connection->ifname, ifname); /* * Zero out MAC address fields */ memset(new_entry->smacaddr, 0, sizeof(new_entry->smacaddr)); memset(new_entry->oth_connection->smacaddr, 0, sizeof(new_entry->oth_connection->smacaddr)); new_entry->stat = new_entry->oth_connection->stat = 0; new_entry->s_fstat = NOTRESOLVED; new_entry->d_fstat = NOTRESOLVED; resolve_entry(new_entry, res); /* set port service names (where applicable) */ servlook(sockaddr_get_port(saddr), IPPROTO_TCP, new_entry->s_sname, 10); servlook(sockaddr_get_port(daddr), IPPROTO_TCP, new_entry->d_sname, 10); strcpy(new_entry->oth_connection->s_sname, new_entry->d_sname); strcpy(new_entry->oth_connection->d_sname, new_entry->s_sname); strcpy(new_entry->oth_connection->d_fqdn, new_entry->s_fqdn); strcpy(new_entry->oth_connection->s_fqdn, new_entry->d_fqdn); new_entry->oth_connection->s_fstat = new_entry->d_fstat; new_entry->oth_connection->d_fstat = new_entry->s_fstat; if (new_entry->index < new_entry->oth_connection->index) { new_entry->half_bracket = ACS_ULCORNER; new_entry->oth_connection->half_bracket = ACS_LLCORNER; } else { new_entry->half_bracket = ACS_LLCORNER; new_entry->oth_connection->half_bracket = ACS_ULCORNER; } new_entry->inclosed = new_entry->oth_connection->inclosed = 0; new_entry->finack = new_entry->oth_connection->finack = 0; new_entry->finsent = new_entry->oth_connection->finsent = 0; new_entry->partial = new_entry->oth_connection->partial = 0; new_entry->spanbr = new_entry->oth_connection->spanbr = 0; new_entry->conn_starttime = new_entry->oth_connection->conn_starttime = time(NULL); rate_init(&new_entry->rate); rate_init(&new_entry->oth_connection->rate); /* * Mark flow rate start time and byte counter for flow computation * if the highlight bar is on either flow of the new connection. */ if (table->barptr == new_entry) new_entry->spanbr = 0; else if (table->barptr == new_entry->oth_connection) new_entry->oth_connection->spanbr = 0; /* * Add entries to hash table */ add_tcp_hash_entry(table, new_entry); add_tcp_hash_entry(table, new_entry->oth_connection); return new_entry; } void addtoclosedlist(struct tcptable *table, struct tcptableent *entry) { struct closedlist *ctemp; ctemp = xmalloc(sizeof(struct closedlist)); /* * Point to closed entries */ ctemp->closedentry = entry; ctemp->pair = entry->oth_connection; entry->inclosed = entry->oth_connection->inclosed = 1; /* * Add node to closed entry list. */ if (table->closedtail != NULL) table->closedtail->next_entry = ctemp; table->closedtail = ctemp; table->closedtail->next_entry = NULL; if (table->closedentries == NULL) table->closedentries = ctemp; } static char *tcplog_flowrate_msg(struct tcptableent *entry, char *buf, size_t bufsize) { time_t interval = time(NULL) - entry->conn_starttime; if (interval < 1) interval = 1; char rbuf[32]; rate_print(entry->bcount / interval, rbuf, sizeof(rbuf)); snprintf(buf, bufsize - 1, "avg flow rate %s", rbuf); buf[bufsize - 1] = '\0'; return buf; } void write_timeout_log(int logging, FILE *logfile, struct tcptableent *tcpnode) { char msgstring[MSGSTRING_MAX]; if (logging) { char flowrate1[64]; char flowrate2[64]; snprintf(msgstring, MSGSTRING_MAX, "TCP; Connection %s:%s to %s:%s timed out, %lu packets, %lu bytes, %s; opposite direction %lu packets, %lu bytes, %s", tcpnode->s_fqdn, tcpnode->s_sname, tcpnode->d_fqdn, tcpnode->d_sname, tcpnode->pcount, tcpnode->bcount, tcplog_flowrate_msg(tcpnode, flowrate1, sizeof(flowrate1)), tcpnode->oth_connection->pcount, tcpnode->oth_connection->bcount, tcplog_flowrate_msg(tcpnode->oth_connection, flowrate2, sizeof(flowrate2))); writelog(logging, logfile, msgstring); } } void mark_timeouted_entries(struct tcptable *table, int logging, FILE *logfile) { if (options.timeout == 0) return; time_t now = time(NULL); struct tcptableent *ptmp = table->head; while (ptmp != NULL) { if (((now - ptmp->lastupdate) / 60 > options.timeout) && !ptmp->inclosed) { ptmp->timedout = 1; ptmp->oth_connection->timedout = 1; addtoclosedlist(table, ptmp); if (logging) write_timeout_log(logging, logfile, ptmp); } ptmp = ptmp->next_entry; } } struct tcptableent *in_table(struct tcptable *table, struct sockaddr_storage *saddr, struct sockaddr_storage *daddr, char *ifname) { struct tcp_hashentry *hashptr; unsigned int hp; if (table->head == NULL) { return NULL; } /* * Determine hash table index for this set of addresses and ports */ hp = tcp_hash(saddr, daddr, ifname); hashptr = table->hash_table[hp]; while (hashptr != NULL) { if (sockaddr_is_equal(&hashptr->tcpnode->saddr, saddr) && sockaddr_is_equal(&hashptr->tcpnode->daddr, daddr) && (strcmp(hashptr->tcpnode->ifname, ifname) == 0)) break; hashptr = hashptr->next_entry; } if (hashptr != NULL) { /* needed to avoid SIGSEGV */ if ((((hashptr->tcpnode->finsent == 2) && (hashptr->tcpnode->oth_connection->finsent == 2))) || (((hashptr->tcpnode->stat & FLAG_RST) || (hashptr->tcpnode->oth_connection-> stat & FLAG_RST)))) { return NULL; } else { return hashptr->tcpnode; } } else { return NULL; } } /* * Update the TCP status record should an applicable packet arrive. */ void updateentry(struct tcptable *table, struct pkt_hdr *pkt, struct tcptableent *tableentry, struct tcphdr *tcp, unsigned int bcount, struct resolver *res, int logging, FILE *logfile) { char msgstring[MSGSTRING_MAX]; char newmacaddr[18]; resolve_entry(tableentry, res); tableentry->pcount++; tableentry->bcount += bcount; tableentry->psize = pkt->pkt_len; tableentry->spanbr += bcount; if (options.mac) { memset(newmacaddr, 0, sizeof(newmacaddr)); if (pkt->from->sll_hatype == ARPHRD_ETHER) { convmacaddr((char *) pkt->ethhdr->h_source, newmacaddr); } else if (pkt->from->sll_hatype == ARPHRD_FDDI) { convmacaddr((char *) pkt->fddihdr->saddr, newmacaddr); } if (tableentry->smacaddr[0] != '\0') { if (strcmp(tableentry->smacaddr, newmacaddr) != 0) { snprintf(msgstring, MSGSTRING_MAX, "TCP; %s; from %s:%s to %s:%s: new source MAC address %s (previously %s)", tableentry->ifname, tableentry->s_fqdn, tableentry->s_sname, tableentry->d_fqdn, tableentry->d_sname, newmacaddr, tableentry->smacaddr); writelog(logging, logfile, msgstring); strcpy(tableentry->smacaddr, newmacaddr); } } else strcpy(tableentry->smacaddr, newmacaddr); } /* * If this is not the first TCP fragment, skip interpretation of the * TCP header. */ if (!packet_is_first_fragment(pkt)) { tableentry->lastupdate = tableentry->oth_connection->lastupdate = time(NULL); return; } /* * At this point, we have a TCP header, and we proceed to process it. */ if (tableentry->pcount == 1) { if (tcp->syn || tcp->rst) tableentry->partial = 0; else tableentry->partial = 1; } tableentry->win = ntohs(tcp->window); tableentry->stat = 0; if (tcp->syn) tableentry->stat |= FLAG_SYN; if (tcp->ack) { tableentry->stat |= FLAG_ACK; /* * The following sequences are used when the ACK is in response to * a FIN (see comments for FIN below). If the opposite direction * already has its indicator set to 1 (FIN sent, not ACKed), and * the incoming ACK has the same sequence number as the previously * stored FIN's ack number (i.e. the ACK in response to the opposite * flow's FIN), the opposite direction's state is set to 2 (FIN sent * and ACKed). */ if ((tableentry->oth_connection->finsent == 1) && (ntohl(tcp->seq) == tableentry->oth_connection->finack)) { tableentry->oth_connection->finsent = 2; if (logging) { writetcplog(logging, logfile, tableentry, tableentry->psize, "FIN acknowleged"); } } } /* * The closing sequence is similar, but not identical to the TCP close * sequence described in the RFC. This sequence is primarily cosmetic. * * When a FIN is sent in a direction, a state indicator is set to 1, * to indicate a FIN sent, but not ACKed yet. For comparison later, * the acknowlegement number is also saved in the entry. See comments * in ACK above. */ if (tcp->fin) { /* * First, we check if the opposite direction has no counts, in which * case we simply mark the entire connection available for reuse. * This is in case packets from a machine pass an interface, but * on the return, completely bypasses any interface on our machine. * * Q: Could such a situation really happen in practice? I managed to * do it but under *really* ridiculous circumstances. * * A: (as of version 2.5.0, June 2001): Yes this DOES happen in * practice. Unidirectional satellite feeds can send data straight * to a remote network using you as your upstream. */ if (tableentry->oth_connection->pcount == 0) addtoclosedlist(table, tableentry); else { /* * That aside, mark the direction as being done, and make it * ready for a complete close upon receipt of an ACK. We save * the acknowlegement number for identification of the proper * ACK packet when it arrives in the other direction. */ tableentry->finsent = 1; tableentry->finack = ntohl(tcp->ack_seq); } if (logging) { char flowrate[64]; sprintf(msgstring, "FIN sent; %lu packets, %lu bytes, %s", tableentry->pcount, tableentry->bcount, tcplog_flowrate_msg(tableentry, flowrate, sizeof(flowrate))); writetcplog(logging, logfile, tableentry, tableentry->psize, msgstring); } } if (tcp->rst) { tableentry->stat |= FLAG_RST; if (!(tableentry->inclosed)) addtoclosedlist(table, tableentry); if (logging) { char flowrate1[64]; char flowrate2[64]; snprintf(msgstring, MSGSTRING_MAX, "Connection reset; %lu packets, %lu bytes, %s; opposite direction %lu packets, %lu bytes; %s", tableentry->pcount, tableentry->bcount, tcplog_flowrate_msg(tableentry, flowrate1, sizeof(flowrate1)), tableentry->oth_connection->pcount, tableentry->oth_connection->bcount, tcplog_flowrate_msg(tableentry->oth_connection, flowrate2, sizeof(flowrate2))); writetcplog(logging, logfile, tableentry, tableentry->psize, msgstring); } } if (tcp->psh) tableentry->stat |= FLAG_PSH; if (tcp->urg) tableentry->stat |= FLAG_URG; tableentry->lastupdate = tableentry->oth_connection->lastupdate = time(NULL); /* * Shall we add this entry to the closed entry list? If both * directions have their state indicators set to 2, or one direction * is set to 2, and the other 1, that's it. */ if ((!tableentry->inclosed) && (((tableentry->finsent == 2) && ((tableentry->oth_connection->finsent == 1) || (tableentry->oth_connection->finsent == 2))) || ((tableentry->oth_connection->finsent == 2) && ((tableentry->finsent == 1) || (tableentry->finsent == 2))))) addtoclosedlist(table, tableentry); } /* * Display a TCP connection line. Returns immediately if the entry is * not visible in the window. */ void printentry(struct tcptable *table, struct tcptableent *tableentry) { char stat[7] = ""; unsigned int target_row; int normalattr; int highattr; if ((tableentry->index < table->firstvisible->index) || (tableentry->index > table->lastvisible->index)) return; /* * Set appropriate attributes for this entry */ if (table->barptr == tableentry) { normalattr = BARSTDATTR; highattr = BARHIGHATTR; } else { normalattr = STDATTR; highattr = HIGHATTR; } target_row = tableentry->index - table->firstvisible->index; /* clear the target line */ wattrset(table->tcpscreen, normalattr); scrollok(table->tcpscreen, 0); mvwprintw(table->tcpscreen, target_row, 0, "%*c", COLS - 2, ' '); scrollok(table->tcpscreen, 1); /* print half of connection indicator bracket */ wattrset(table->tcpscreen, PTRATTR); mvwaddch(table->tcpscreen, target_row, 0, tableentry->half_bracket); /* proceed with the actual entry */ wattrset(table->tcpscreen, normalattr); mvwprintw(table->tcpscreen, target_row, 1, "%.*s:%.*s", 32 * COLS / 80, tableentry->s_fqdn, 10, tableentry->s_sname); wattrset(table->tcpscreen, highattr); /* * Print packet and byte counts or window size and packet size, depending * on the value of mode. */ switch (table->mode) { case 0: wmove(table->tcpscreen, target_row, 47 * COLS / 80 - 2); if (tableentry->partial) wprintw(table->tcpscreen, ">"); else wprintw(table->tcpscreen, "="); printlargenum(tableentry->pcount, table->tcpscreen); wmove(table->tcpscreen, target_row, 59 * COLS / 80 - 4); printlargenum(tableentry->bcount, table->tcpscreen); break; case 1: wmove(table->tcpscreen, target_row, 50 * COLS / 80); if (tableentry->smacaddr[0] == '\0') wprintw(table->tcpscreen, " N/A "); else wprintw(table->tcpscreen, "%s", tableentry->smacaddr); break; case 2: wmove(table->tcpscreen, target_row, 45 * COLS / 80 + 3); wprintw(table->tcpscreen, "%5u ", tableentry->psize); wmove(table->tcpscreen, target_row, 56 * COLS / 80 - 1); wprintw(table->tcpscreen, "%9u ", tableentry->win); } wattrset(table->tcpscreen, normalattr); if (tableentry->timedout) strcpy(stat, "TMOU"); else if (tableentry->finsent == 1) strcpy(stat, "DONE"); else if (tableentry->finsent == 2) strcpy(stat, "CLOS"); else if (tableentry->stat & FLAG_RST) strcpy(stat, "RSET"); else { strcat(stat, (tableentry->stat & FLAG_SYN) ? "S" : "-"); strcat(stat, (tableentry->stat & FLAG_PSH) ? "P" : "-"); strcat(stat, (tableentry->stat & FLAG_ACK) ? "A" : "-"); strcat(stat, (tableentry->stat & FLAG_URG) ? "U" : "-"); } wmove(table->tcpscreen, target_row, 65 * COLS / 80); wprintw(table->tcpscreen, "%4.4s", stat); wmove(table->tcpscreen, target_row, 70 * COLS / 80); wprintw(table->tcpscreen, "%-*.*s", table->ifnamew, table->ifnamew, tableentry->ifname); } void resolve_visible_entries(struct tcptable *table, struct resolver *res) { if(res->lookup == false) return; struct tcptableent *entry = table->firstvisible; while ((entry != NULL) && (entry->prev_entry != table->lastvisible)) { resolve_entry(entry, res); entry = entry->next_entry; } } /* * Redraw the TCP window */ void refreshtcpwin(struct tcptable *table, bool clear) { struct tcptableent *ptmp; if (clear) { setlabels(table->borderwin, table->mode); wattrset(table->tcpscreen, STDATTR); tx_colorwin(table->tcpscreen); } ptmp = table->firstvisible; while ((ptmp != NULL) && (ptmp->prev_entry != table->lastvisible)) { printentry(table, ptmp); ptmp = ptmp->next_entry; } print_tcp_num_entries(table); update_panels(); doupdate(); } static void destroy_closed_entries(struct tcptable *table) { struct closedlist *ptmp = table->closedentries; while (ptmp != NULL) { struct closedlist *ctmp = ptmp->next_entry; free(ptmp); ptmp = ctmp; } table->closedentries = NULL; table->closedtail = NULL; } static void destroy_tcp_entries(struct tcptable *table) { struct tcptableent *ptmp = table->head; while (ptmp != NULL) { struct tcptableent *ctmp = ptmp->next_entry; rate_destroy(&ptmp->rate); free(ptmp); ptmp = ctmp; } table->head = NULL; table->tail = NULL; } static void destroy_hash_entries(struct tcptable *table) { for (unsigned int i = 0; i < ENTRIES_IN_HASH_TABLE; i++) { struct tcp_hashentry *ptmp = table->hash_table[i]; while (ptmp != NULL) { struct tcp_hashentry *ctmp = ptmp->next_entry; free(ptmp); ptmp = ctmp; } table->hash_table[i] = NULL; } } /* kill the entire TCP table */ void destroytcptable(struct tcptable *table) { /* destroy main TCP table */ destroy_tcp_entries(table); /* destroy list of closed entries */ destroy_closed_entries(table); /* destroy hash table */ destroy_hash_entries(table); del_panel(table->statpanel); delwin(table->statwin); del_panel(table->tcppanel); delwin(table->tcpscreen); del_panel(table->borderpanel); delwin(table->borderwin); } /* * Kill an entry from the TCP table */ static void destroy_tcp_entry(struct tcptable *table, struct tcptableent *ptmp) { if (ptmp->prev_entry != NULL) ptmp->prev_entry->next_entry = ptmp->next_entry; else table->head = ptmp->next_entry; if (ptmp->next_entry != NULL) ptmp->next_entry->prev_entry = ptmp->prev_entry; else table->tail = ptmp->prev_entry; rate_destroy(&ptmp->rate); free(ptmp); if (table->head == NULL) { table->firstvisible = NULL; table->lastvisible = NULL; } } /* * Kill all closed entries from the table, and clear the list of closed * entries. */ void flushclosedentries(struct tcptable *table) { struct tcptableent *ptmp = table->head; struct tcptableent *ctmp = NULL; unsigned long idx = 1; unsigned long screen_idx = table->firstvisible->index; while (ptmp != NULL) { if (ptmp->inclosed) { ctmp = ptmp; /* * Advance to next entry and destroy target entry. */ ptmp = ptmp->next_entry; /* * If the targeted entry is highlighted, and the next entry is * not NULL (we're still in the list) we move the bar pointer to * the next entry otherwise we move it to the previous entry. */ if (ptmp != NULL) { if (table->barptr == ctmp) { table->barptr = ptmp; } } else { if (table->barptr == ctmp) { table->barptr = table->barptr->prev_entry; } } /* * Do the dirty deed */ del_tcp_hash_node(table, ctmp); destroy_tcp_entry(table, ctmp); /* * Adjust screen index if the deleted entry was "above" * the screen. */ if (idx < screen_idx) screen_idx--; } else { /* * Set the first visible pointer once the index matches * the screen index. */ if (idx == screen_idx) table->firstvisible = ptmp; /* * Keep setting the last visible pointer until the scan * index "leaves" the screen */ if (idx <= screen_idx + (table->imaxy - 1)) table->lastvisible = ptmp; ptmp->index = idx; idx++; ptmp = ptmp->next_entry; } } table->lastpos = idx - 1; table->count = table->lastpos / 2; destroy_closed_entries(table); /* * Shift entries down if the deletion causes the last entry to * occupy anywhere other than the last line of the TCP display * window. */ if (table->head != NULL) { /* * Point screen index to the last table entry if the tail entry is * "above" the screen index. Set the firstvisible pointer to that * as well. */ if (table->tail->index < screen_idx) { screen_idx = table->tail->index; table->firstvisible = table->tail; } /* * Move the screen index and firstvisible entry up until the tail * hits the bottom of the window (tail is at screen index plus * screen length minus 1) or the firstvisible pointer hits the * head of the table. The highlight bar should "go along" with * the shifting. */ while ((table->tail->index < screen_idx + table->imaxy - 1) && (table->firstvisible->prev_entry != NULL)) { table->firstvisible = table->firstvisible->prev_entry; screen_idx--; } } } void writetcplog(int logging, FILE *fd, struct tcptableent *entry, unsigned int pktlen, char *message) { char msgbuf[MSGSTRING_MAX]; if (logging) { if (options.mac) { snprintf(msgbuf, MSGSTRING_MAX, "TCP; %s; %u bytes; from %s:%s to %s:%s (source MAC addr %s); %s", entry->ifname, pktlen, entry->s_fqdn, entry->s_sname, entry->d_fqdn, entry->d_sname, entry->smacaddr, message); } else { snprintf(msgbuf, MSGSTRING_MAX, "TCP; %s; %u bytes; from %s:%s to %s:%s; %s", entry->ifname, pktlen, entry->s_fqdn, entry->s_sname, entry->d_fqdn, entry->d_sname, message); } writelog(logging, fd, msgbuf); } } void write_tcp_unclosed(int logging, FILE *fd, struct tcptable *table) { char msgbuf[MSGSTRING_MAX]; struct tcptableent *entry = table->head; while (entry != NULL) { if ((entry->finsent == 0) && ((entry->stat & FLAG_RST) == 0) && (!(entry->inclosed))) { sprintf(msgbuf, "TCP; %s; active; from %s:%s to %s:%s; %lu packets, %lu bytes", entry->ifname, entry->s_fqdn, entry->s_sname, entry->d_fqdn, entry->d_sname, entry->pcount, entry->bcount); writelog(logging, fd, msgbuf); } entry = entry->next_entry; } } iptraf-ng-1.2.1/src/tcptable.h000066400000000000000000000075021370555550300161540ustar00rootroot00000000000000#ifndef IPTRAF_NG_TCPTABLE_H #define IPTRAF_NG_TCPTABLE_H /*** tcptable.h -- table manipulation for the statistics display. ***/ #include "packet.h" #include "rate.h" /* * max() macros that also do * strict type-checking.. See the * "unnecessary" pointer comparison. */ #define max(x, y) ({ \ typeof(x) _max1 = (x); \ typeof(y) _max2 = (y); \ (void) (&_max1 == &_max2); \ _max1 > _max2 ? _max1 : _max2; }) #define FLAG_SYN 1 #define FLAG_RST 2 #define FLAG_PSH 4 #define FLAG_ACK 8 #define FLAG_URG 16 #define CLOSED 64 #define ENTRIES_IN_HASH_TABLE 1543 struct tcptableent { struct sockaddr_storage saddr; struct sockaddr_storage daddr; char s_fqdn[45]; /* fully-qualified domain names */ char d_fqdn[45]; int s_fstat; int d_fstat; char smacaddr[18]; char s_sname[11]; /* Service names, maxlen=10 */ char d_sname[11]; unsigned int protocol; unsigned long pcount; /* packet count */ unsigned long bcount; /* byte count */ unsigned int stat; /* TCP flags */ unsigned int win; unsigned int psize; unsigned long finack; int partial; int finsent; char ifname[IFNAMSIZ]; unsigned int index; int timedout; int inclosed; int half_bracket; unsigned long spanbr; struct rate rate; time_t lastupdate; time_t conn_starttime; struct tcp_hashentry *hash_node; struct tcptableent *oth_connection; /* the other half of the connection */ struct tcptableent *prev_entry; struct tcptableent *next_entry; }; struct closedlist { struct tcptableent *closedentry; struct tcptableent *pair; struct closedlist *next_entry; }; struct tcp_hashentry { unsigned int index; unsigned int hp; /* index position in bucket array */ struct tcptableent *tcpnode; struct tcp_hashentry *prev_entry; struct tcp_hashentry *next_entry; }; struct tcptable { struct tcp_hashentry *hash_table[ENTRIES_IN_HASH_TABLE]; struct tcp_hashentry *hash_tails[ENTRIES_IN_HASH_TABLE]; struct tcptableent *head; struct tcptableent *tail; struct closedlist *closedentries; struct closedlist *closedtail; struct tcptableent *firstvisible; struct tcptableent *lastvisible; struct tcptableent *barptr; unsigned int lastpos; unsigned int count; unsigned int bmaxy; /* number of lines of the border window */ unsigned int imaxy; /* number of lines inside the border */ int ifnamew; /* interface name width to display */ int mode; WINDOW *tcpscreen; PANEL *tcppanel; WINDOW *borderwin; PANEL *borderpanel; WINDOW *statwin; PANEL *statpanel; }; void show_stats(WINDOW *win, unsigned long long total); void init_tcp_table(struct tcptable *table); struct tcptableent *addentry(struct tcptable *table, struct sockaddr_storage *saddr, struct sockaddr_storage *daddr, int protocol, char *ifname, struct resolver *res); void mark_timeouted_entries(struct tcptable *table, int logging, FILE *logfile); struct tcptableent *in_table(struct tcptable *table, struct sockaddr_storage *saddr, struct sockaddr_storage *daddr, char *ifname); void updateentry(struct tcptable *table, struct pkt_hdr *pkt, struct tcptableent *tableentry, struct tcphdr *transpacket, unsigned int bcount, struct resolver *res, int logging, FILE *logfile); void addtoclosedlist(struct tcptable *table, struct tcptableent *tableentry); void printentry(struct tcptable *table, struct tcptableent *tableentry); void resolve_visible_entries(struct tcptable *table, struct resolver *res); void refreshtcpwin(struct tcptable *table, bool clear); void destroytcptable(struct tcptable *table); void flushclosedentries(struct tcptable *table); void write_timeout_log(int logging, FILE *logfile, struct tcptableent *tcpnode); void writetcplog(int logging, FILE *fd, struct tcptableent *entry, unsigned int pktlen, char *message); void write_tcp_unclosed(int logging, FILE *fd, struct tcptable *table); #endif /* IPTRAF_NG_TCPTABLE_H */ iptraf-ng-1.2.1/src/timer.c000066400000000000000000000020011370555550300154560ustar00rootroot00000000000000/* For terms of usage/redistribution/modification see the LICENSE file */ /* For authors and contributors see the AUTHORS file */ /*** timer.c - module to display the elapsed time since a facility was started ***/ #include "iptraf-ng-compat.h" #include "timer.h" void printelapsedtime(time_t elapsed, int x, WINDOW *win) { unsigned int hours = elapsed / 3600; unsigned int mins = (elapsed % 3600) / 60; int y = getmaxy(win) - 1; mvwprintw(win, y, x, " Time: %3u:%02u ", hours, mins); } inline bool time_after(struct timespec const *a, struct timespec const *b) { if (a->tv_sec > b->tv_sec) return true; if (a->tv_sec < b->tv_sec) return false; if(a->tv_nsec > b->tv_nsec) return true; else return false; } void time_add_msecs(struct timespec *time, unsigned int msecs) { if (time != NULL) { while (msecs >= 1000) { time->tv_sec++; msecs -= 1000; } time->tv_nsec += msecs * 1000000; while (time->tv_nsec >= 1000000000) { time->tv_sec++; time->tv_nsec -= 1000000000; } } } iptraf-ng-1.2.1/src/timer.h000066400000000000000000000004251370555550300154730ustar00rootroot00000000000000#ifndef IPTRAF_NG_TIMER_H #define IPTRAF_NG_TIMER_H void printelapsedtime(time_t elapsed, int x, WINDOW *win); bool time_after(struct timespec const *a, struct timespec const *b); void time_add_msecs(struct timespec *time, unsigned int msecs); #endif /* IPTRAF_NG_TIMER_H */ iptraf-ng-1.2.1/src/tui/000077500000000000000000000000001370555550300150025ustar00rootroot00000000000000iptraf-ng-1.2.1/src/tui/README000066400000000000000000000020661370555550300156660ustar00rootroot00000000000000========================================================================= IPTraf User Interface Support Library README ------------------------------------------------------------------------- Some of the more reusable user-interface functions originally part of the IPTraf source tree have been recoded and moved to this directory as a support library. This way it would be easier for interested developers to use these functions in other programs. Full programming information will be provided in an upcoming separate release of this library although documentation may be provided via mail should there be any requests for it. Then again, there's always the IPTraf source code. RELEASE INFORMATION This is currently code derived from IPTraf, and is for now released under the GNU General Public License version 2 or any later version. I may release it as a separate package soon under a less restrictive license. Should you be interested in this little library, and you have a concern regarding the GPL, I can still be reached privately via . Gerard iptraf-ng-1.2.1/src/tui/input.c000066400000000000000000000067541370555550300163210ustar00rootroot00000000000000/* For terms of usage/redistribution/modification see the LICENSE file */ /* For authors and contributors see the AUTHORS file */ /*** input.c - a custom keyboard input module ***/ #include "iptraf-ng-compat.h" #include "input.h" void tx_initfields(struct FIELDLIST *list, int leny, int lenx, int begy, int begx, int dlgtextattr, int fieldattr) { list->list = NULL; list->fieldwin = newwin(leny, lenx, begy, begx); list->fieldpanel = new_panel(list->fieldwin); tx_stdwinset(list->fieldwin); wtimeout(list->fieldwin, -1); wattrset(list->fieldwin, dlgtextattr); tx_colorwin(list->fieldwin); update_panels(); doupdate(); list->dlgtextattr = dlgtextattr; list->fieldattr = fieldattr; } void tx_addfield(struct FIELDLIST *list, unsigned int len, unsigned int y, unsigned int x, const char *initstr) { struct FIELD *newfield; newfield = xmalloc(sizeof(struct FIELD)); if (list->list == NULL) { list->list = newfield; newfield->prevfield = newfield; newfield->nextfield = newfield; } else { newfield->prevfield = list->list->prevfield; list->list->prevfield->nextfield = newfield; list->list->prevfield = newfield; newfield->nextfield = list->list; } newfield->xpos = x; newfield->ypos = y; newfield->len = len; newfield->tlen = strlen(initstr); newfield->buf = xmallocz(len + 1); strncpy(newfield->buf, initstr, len); if (newfield->tlen > (len)) newfield->tlen = len; wattrset(list->fieldwin, list->fieldattr); mvwprintw(list->fieldwin, y, x, "%-*s", len, newfield->buf); update_panels(); doupdate(); } void tx_getinput(struct FIELDLIST *list, struct FIELD *field, int *exitkey) { int ch; int y, x; int endloop = 0; wattrset(list->fieldwin, list->fieldattr); mvwprintw(list->fieldwin, field->ypos, field->xpos, "%s", field->buf); update_panels(); doupdate(); do { ch = wgetch(list->fieldwin); switch (ch) { case KEY_BACKSPACE: case 7: case 8: case KEY_DC: case KEY_LEFT: case 127: if (field->tlen > 0) { getyx(list->fieldwin, y, x); x--; mvwprintw(list->fieldwin, y, x, " "); wmove(list->fieldwin, y, x); field->tlen--; field->buf[field->tlen] = '\0'; } break; case 9: case 27: case 24: case 13: case 10: case KEY_UP: case KEY_DOWN: endloop = 1; *exitkey = ch; break; case 12: tx_refresh_screen(); break; default: if ((field->tlen < field->len) && ((ch >= 32) && (ch <= 127))) { wprintw(list->fieldwin, "%c", ch); if (ch == ' ') { getyx(list->fieldwin, y, x); wmove(list->fieldwin, y, x); } field->buf[field->tlen + 1] = '\0'; field->buf[field->tlen] = ch; field->tlen++; } break; } doupdate(); } while (!endloop); } void tx_fillfields(struct FIELDLIST *list, int *aborted) { struct FIELD *field; int exitkey; int endloop = 0; field = list->list; curs_set(1); do { tx_getinput(list, field, &exitkey); switch (exitkey) { case 9: case KEY_DOWN: field = field->nextfield; break; case KEY_UP: field = field->prevfield; break; case 13: case 10: *aborted = 0; endloop = 1; break; case 27: case 24: *aborted = 1; endloop = 1; break; } } while (!endloop); curs_set(0); } void tx_destroyfields(struct FIELDLIST *list) { struct FIELD *ptmp = list->list; /* break the circular list */ if (ptmp != NULL) ptmp->prevfield->nextfield = NULL; while (ptmp != NULL) { struct FIELD *pnext = ptmp->nextfield; free(ptmp); ptmp = pnext; } del_panel(list->fieldpanel); delwin(list->fieldwin); } iptraf-ng-1.2.1/src/tui/input.h000066400000000000000000000016301370555550300163120ustar00rootroot00000000000000#ifndef IPTRAF_NG_TUI_INPUT_H #define IPTRAF_NG_TUI_INPUT_H /*** input.h - structure declarations and function prototypes for input.c ***/ #include "winops.h" #define CTRL_X 24 struct FIELD { char *buf; unsigned int len; unsigned int tlen; unsigned int xpos; unsigned int ypos; struct FIELD *prevfield; struct FIELD *nextfield; }; struct FIELDLIST { struct FIELD *list; WINDOW *fieldwin; PANEL *fieldpanel; int dlgtextattr; int fieldattr; }; void tx_initfields(struct FIELDLIST *list, int leny, int lenx, int begy, int begx, int dlgtextattr, int dlgfieldattr); void tx_addfield(struct FIELDLIST *list, unsigned int len, unsigned int y, unsigned int x, const char *initstr); void tx_getinput(struct FIELDLIST *list, struct FIELD *field, int *exitkey); void tx_fillfields(struct FIELDLIST *list, int *aborted); void tx_destroyfields(struct FIELDLIST *list); #endif /* IPTRAF_NG_TUI_INPUT_H */ iptraf-ng-1.2.1/src/tui/labels.c000066400000000000000000000020211370555550300164030ustar00rootroot00000000000000/* For terms of usage/redistribution/modification see the LICENSE file */ /* For authors and contributors see the AUTHORS file */ /* * labels.c - some common keyhelp printing routines for the iptraf * user interface library */ #include "iptraf-ng-compat.h" #include "winops.h" void tx_printkeyhelp(char *keytext, char *desc, WINDOW * win, int highattr, int textattr) { wattrset(win, highattr); wprintw(win, "%s", keytext); wattrset(win, textattr); wprintw(win, "%s", desc); } void tx_menukeyhelp(int textattr, int highattr) { move(LINES - 1, 1); tx_printkeyhelp("Up/Down", "-Move selector ", stdscr, highattr, textattr); tx_printkeyhelp("Enter", "-execute", stdscr, highattr, textattr); tx_coloreol(); } void tx_listkeyhelp(int textattr, int highattr) { move(LINES - 1, 1); tx_printkeyhelp("Up/Down", "-move pointer ", stdscr, highattr, textattr); tx_printkeyhelp("Enter", "-select ", stdscr, highattr, textattr); tx_printkeyhelp("X/Ctrl+X", "-close list", stdscr, highattr, textattr); tx_coloreol(); } iptraf-ng-1.2.1/src/tui/labels.h000066400000000000000000000004501370555550300164140ustar00rootroot00000000000000#ifndef IPTRAF_NG_TUI_LABELS_H #define IPTRAF_NG_TUI_LABELS_H void tx_printkeyhelp(char *keytext, char *desc, WINDOW * win, int highattr, int textattr); void tx_menukeyhelp(int textattr, int highattr); void tx_listkeyhelp(int textattr, int highattr); #endif /* IPTRAF_NG_TUI_LABELS_H */ iptraf-ng-1.2.1/src/tui/listbox.c000066400000000000000000000113051370555550300166320ustar00rootroot00000000000000/* For terms of usage/redistribution/modification see the LICENSE file */ /* For authors and contributors see the AUTHORS file */ /* * listbox.c - scrollable listbox management module */ #include "iptraf-ng-compat.h" #include "winops.h" #include "labels.h" #include "listbox.h" #include "msgboxes.h" #define SCROLLUP 0 #define SCROLLDOWN 1 void tx_init_listbox(struct scroll_list *list, int width, int height, int startx, int starty, int mainattr, int borderattr, int selectattr, int keyattr) { memset(list, 0, sizeof(struct scroll_list)); list->borderwin = newwin(height, width, starty, startx); list->borderpanel = new_panel(list->borderwin); wattrset(list->borderwin, borderattr); tx_box(list->borderwin, ACS_VLINE, ACS_HLINE); list->win = newwin(height - 2, width - 2, starty + 1, startx + 1); list->panel = new_panel(list->win); wattrset(list->win, mainattr); tx_colorwin(list->win); list->mainattr = mainattr; list->selectattr = selectattr; list->height = height; list->width = width; list->keyattr = keyattr; list->row = 0; tx_stdwinset(list->win); scrollok(list->win, 0); } void tx_set_listbox_title(struct scroll_list *list, char *text, int x) { mvwprintw(list->borderwin, 0, x, " %s ", text); } void tx_add_list_entry(struct scroll_list *list, char *node, char *text) { struct textlisttype *ptmp; ptmp = xmallocz(sizeof(struct textlisttype)); strncpy(ptmp->text, text, MAX_TEXT_LENGTH - 1); ptmp->nodeptr = node; if (list->textlist == NULL) { list->textlist = ptmp; ptmp->prev_entry = NULL; } else { list->texttail->next_entry = ptmp; ptmp->prev_entry = list->texttail; } list->texttail = ptmp; ptmp->next_entry = NULL; } void tx_show_listbox(struct scroll_list *list) { int i = 0; struct textlisttype *tptr = list->textlist; while ((i <= list->height - 3) && (tptr != NULL)) { mvwprintw(list->win, i, 1, "%s", tptr->text); tptr = tptr->next_entry; i++; } update_panels(); doupdate(); } static void tx_print_row(struct scroll_list *list, int attr) { wattrset(list->win, attr); mvwprintw(list->win, list->row, 0, " %-*s", list->width - 3, list->textptr->text); } static void tx_scroll_listbox(struct scroll_list *list, int direction, int lines) { if (lines < 1) return; if (direction == SCROLLUP) { for (int i = 0; i < lines; i++) { if (list->textptr->next_entry == NULL) break; tx_print_row(list, list->mainattr); if (list->row == list->height - 3) { scrollok(list->win, 1); wscrl(list->win, 1); scrollok(list->win, 0); } else list->row++; list->textptr = list->textptr->next_entry; tx_print_row(list, list->selectattr); } } else { for (int i = 0; i < lines; i++) { if (list->textptr->prev_entry == NULL) break; tx_print_row(list, list->mainattr); if (list->row == 0) { scrollok(list->win, 1); wscrl(list->win, -1); scrollok(list->win, 0); } else list->row--; list->textptr = list->textptr->prev_entry; tx_print_row(list, list->selectattr); } } } void tx_operate_listbox(struct scroll_list *list, int *aborted) { int endloop = 0; if (list->textlist == NULL) { tui_error(ANYKEY_MSG, "No list entries"); *aborted = 1; return; } list->textptr = list->textlist; tx_listkeyhelp(list->mainattr, list->keyattr); update_panels(); doupdate(); tx_print_row(list, list->selectattr); while (!endloop) { switch (wgetch(list->win)) { case KEY_UP: tx_scroll_listbox(list, SCROLLDOWN, 1); break; case KEY_DOWN: tx_scroll_listbox(list, SCROLLUP, 1); break; case KEY_PPAGE: tx_scroll_listbox(list, SCROLLDOWN, list->height - 2); break; case KEY_NPAGE: tx_scroll_listbox(list, SCROLLUP, list->height - 2); break; case KEY_HOME: tx_scroll_listbox(list, SCROLLDOWN, INT_MAX); break; case KEY_END: tx_scroll_listbox(list, SCROLLUP, INT_MAX); break; case 13: *aborted = 0; endloop = 1; break; case 27: case 'x': case 'X': case 24: *aborted = 1; endloop = 1; /* fall through */ case 12: case 'l': case 'L': tx_refresh_screen(); break; } } } void tx_hide_listbox(struct scroll_list *list) { hide_panel(list->panel); hide_panel(list->borderpanel); update_panels(); doupdate(); } void tx_unhide_listbox(struct scroll_list *list) { show_panel(list->panel); show_panel(list->panel); update_panels(); doupdate(); } void tx_close_listbox(struct scroll_list *list) { del_panel(list->panel); del_panel(list->borderpanel); delwin(list->win); delwin(list->borderwin); update_panels(); doupdate(); } void tx_destroy_list(struct scroll_list *list) { struct textlisttype *ttmp = list->textlist; struct textlisttype *ctmp; while (ttmp != NULL) { ctmp = ttmp->next_entry; free(ttmp); ttmp = ctmp; } } iptraf-ng-1.2.1/src/tui/listbox.h000066400000000000000000000024111370555550300166350ustar00rootroot00000000000000#ifndef IPTRAF_NG_TUI_LISTBOX_H #define IPTRAF_NG_TUI_LISTBOX_H #define MAX_TEXT_LENGTH 240 struct textlisttype { char text[MAX_TEXT_LENGTH]; char *nodeptr; /* generic pointer, cast to appropriate type */ struct textlisttype *next_entry; struct textlisttype *prev_entry; }; struct scroll_list { struct textlisttype *textlist; /* list of raw text entries */ struct textlisttype *texttail; struct textlisttype *textptr; int height; int width; int mainattr; int selectattr; int keyattr; int row; WINDOW *win; PANEL *panel; WINDOW *borderwin; PANEL *borderpanel; }; void tx_init_listbox(struct scroll_list *list, int width, int height, int startx, int starty, int mainattr, int borderattr, int selectattr, int keyattr); void tx_set_listbox_title(struct scroll_list *list, char *text, int x); void tx_add_list_entry(struct scroll_list *list, char *node, char *text); void tx_show_listbox(struct scroll_list *list); void tx_operate_listbox(struct scroll_list *list, int *aborted); void tx_hide_listbox(struct scroll_list *list); void tx_unhide_listbox(struct scroll_list *list); void tx_close_listbox(struct scroll_list *list); void tx_destroy_list(struct scroll_list *list); #define tx_destroy_listbox tx_destroy_list #endif /* IPTRAF_NG_TUI_LISTBOX_H */ iptraf-ng-1.2.1/src/tui/menurt.c000066400000000000000000000141131370555550300164600ustar00rootroot00000000000000/* For terms of usage/redistribution/modification see the LICENSE file */ /* For authors and contributors see the AUTHORS file */ /*** menurt.c - ncurses-based menu definition module ***/ #include "iptraf-ng-compat.h" #include "menurt.h" #include "winops.h" #include "labels.h" /* initialize menu system */ void tx_initmenu(struct MENU *menu, int y1, int x1, int y2, int x2, int borderattr, int normalattr, int highattr, int barnormalattr, int barhighattr, int descattr) { menu->itemlist = NULL; menu->itemcount = 0; strcpy(menu->shortcuts, ""); menu->x1 = x1; menu->y1 = y1; menu->x2 = x2; menu->y2 = y2; menu->menuwin = newwin(y1, x1, y2, x2); menu->menupanel = new_panel(menu->menuwin); menu->menu_maxx = x1 - 2; keypad(menu->menuwin, 1); meta(menu->menuwin, 1); noecho(); wtimeout(menu->menuwin, -1); /* block until input */ notimeout(menu->menuwin, 0); /* disable Esc timer */ nonl(); cbreak(); menu->borderattr = borderattr; menu->normalattr = normalattr; menu->highattr = highattr; menu->barnormalattr = barnormalattr; menu->barhighattr = barhighattr; menu->descriptionattr = descattr; } /* add menu item */ void tx_additem(struct MENU *menu, char *item, char *desc) { struct ITEM *tnode; char cur_option[OPTIONSTRLEN_MAX]; char thekey[2]; if (menu->itemcount >= 25) return; tnode = xmalloc(sizeof(struct ITEM)); if (item != NULL) { strcpy(tnode->option, item); strcpy(tnode->desc, desc); tnode->itemtype = REGULARITEM; strcpy(cur_option, item); strtok(cur_option, "^"); strcpy(thekey, strtok(NULL, "^")); thekey[0] = toupper(thekey[0]); strcat(menu->shortcuts, thekey); } else { tnode->itemtype = SEPARATOR; strcat(menu->shortcuts, "^"); /* mark shortcut position for seps */ } if (menu->itemlist == NULL) { menu->itemlist = tnode; } else { menu->lastitem->next = tnode; tnode->prev = menu->lastitem; } menu->itemlist->prev = tnode; menu->lastitem = tnode; tnode->next = menu->itemlist; menu->itemcount++; } /* show each individual item */ void tx_showitem(struct MENU *menu, struct ITEM *itemptr, int selected) { int hiattr = 0; int loattr = 0; int ctr; char curoption[OPTIONSTRLEN_MAX]; char padding[OPTIONSTRLEN_MAX]; if (itemptr->itemtype == REGULARITEM) { switch (selected) { case NOTSELECTED: hiattr = menu->highattr; loattr = menu->normalattr; break; case SELECTED: hiattr = menu->barhighattr; loattr = menu->barnormalattr; break; } strcpy(curoption, itemptr->option); wattrset(menu->menuwin, loattr); wprintw(menu->menuwin, "%s", strtok(curoption, "^")); wattrset(menu->menuwin, hiattr); wprintw(menu->menuwin, "%s", strtok(NULL, "^")); wattrset(menu->menuwin, loattr); wprintw(menu->menuwin, "%s", strtok(NULL, "^")); strcpy(padding, ""); for (ctr = strlen(itemptr->option); ctr <= menu->x1 - 1; ctr++) strcat(padding, " "); wprintw(menu->menuwin, "%s", padding); } else { wattrset(menu->menuwin, menu->borderattr); whline(menu->menuwin, ACS_HLINE, menu->menu_maxx); } update_panels(); doupdate(); } /* repeatedly calls tx_showitem to display individual items */ void tx_showmenu(struct MENU *menu) { struct ITEM *itemptr; /* points to each item in turn */ int ctr = 1; /* counts each item */ wattrset(menu->menuwin, menu->borderattr); /* set to bg+/b */ tx_colorwin(menu->menuwin); /* color window */ tx_box(menu->menuwin, ACS_VLINE, ACS_HLINE); /* draw border */ itemptr = menu->itemlist; /* point to start */ wattrset(menu->menuwin, menu->normalattr); do { /* display items */ wmove(menu->menuwin, ctr, 1); tx_showitem(menu, itemptr, NOTSELECTED); /* show items, initially unselected */ ctr++; itemptr = itemptr->next; } while (ctr <= menu->itemcount); update_panels(); doupdate(); } void menumoveto(struct MENU *menu, struct ITEM **itemptr, unsigned int row) { struct ITEM *tnode; unsigned int i; tnode = menu->itemlist; for (i = 1; i < row; i++) tnode = tnode->next; *itemptr = tnode; } /* * Actually do the menu operation after all the initialization */ void tx_operatemenu(struct MENU *menu, int *position, int *aborted) { struct ITEM *itemptr; int row = *position; int endloop = 0; int ch; char *keyptr; tx_menukeyhelp(menu->normalattr, menu->highattr); *aborted = 0; menumoveto(menu, &itemptr, row); menu->descwin = newwin(1, COLS, LINES - 2, 0); menu->descpanel = new_panel(menu->descwin); do { wmove(menu->menuwin, row, 1); tx_showitem(menu, itemptr, SELECTED); /* * Print item description */ wattrset(menu->descwin, menu->descriptionattr); tx_colorwin(menu->descwin); mvwprintw(menu->descwin, 0, 0, " %s", itemptr->desc); update_panels(); doupdate(); wmove(menu->menuwin, row, 2); ch = wgetch(menu->menuwin); wmove(menu->menuwin, row, 1); tx_showitem(menu, itemptr, NOTSELECTED); switch (ch) { case KEY_UP: if (row == 1) row = menu->itemcount; else row--; itemptr = itemptr->prev; if (itemptr->itemtype == SEPARATOR) { row--; itemptr = itemptr->prev; } break; case KEY_DOWN: if (row == menu->itemcount) row = 1; else row++; itemptr = itemptr->next; if (itemptr->itemtype == SEPARATOR) { row++; itemptr = itemptr->next; } break; case 12: tx_refresh_screen(); break; case 13: endloop = 1; break; /* case 27: endloop = 1;*aborted = 1;row=menu->itemcount;break; */ case '^': break; /* ignore caret key */ default: keyptr = strchr(menu->shortcuts, toupper(ch)); if ((keyptr != NULL) && keyptr - menu->shortcuts < menu->itemcount) { row = keyptr - menu->shortcuts + 1; endloop = 1; } } } while (!endloop); *position = row; /* position of executed option is in *position */ del_panel(menu->descpanel); delwin(menu->descwin); update_panels(); doupdate(); } void tx_destroymenu(struct MENU *menu) { struct ITEM *tnode = menu->itemlist; /* break the circular list */ if (tnode != NULL) tnode->prev->next = NULL; while (tnode != NULL) { struct ITEM *tnextnode = tnode->next; free(tnode); tnode = tnextnode; } del_panel(menu->menupanel); delwin(menu->menuwin); update_panels(); doupdate(); } iptraf-ng-1.2.1/src/tui/menurt.h000066400000000000000000000024361370555550300164720ustar00rootroot00000000000000#ifndef IPTRAF_NG_TUI_MENURT_H #define IPTRAF_NG_TUI_MENURT_H /*** menu.h - declaration file for my menu library ***/ #define SELECTED 1 #define NOTSELECTED 0 #define SEPARATOR 0 #define REGULARITEM 1 #define OPTIONSTRLEN_MAX 50 #define DESCSTRLEN_MAX 81 #define SHORTCUTSTRLEN_MAX 25 struct ITEM { char option[OPTIONSTRLEN_MAX]; char desc[DESCSTRLEN_MAX]; unsigned int itemtype; struct ITEM *prev; struct ITEM *next; }; struct MENU { struct ITEM *itemlist; struct ITEM *selecteditem; struct ITEM *lastitem; int itemcount; int postn; int x1, y1; int x2, y2; unsigned int menu_maxx; WINDOW *menuwin; PANEL *menupanel; WINDOW *descwin; PANEL *descpanel; int borderattr; int normalattr; int highattr; int barnormalattr; int barhighattr; int descriptionattr; char shortcuts[SHORTCUTSTRLEN_MAX]; }; void tx_initmenu(struct MENU *menu, int y1, int x1, int y2, int x2, int borderattr, int normalattr, int highattr, int barnormalattr, int barhighattr, int descattr); void tx_additem(struct MENU *menu, char *item, char *desc); void tx_showitem(struct MENU *menu, struct ITEM *itemptr, int selected); void tx_showmenu(struct MENU *menu); void tx_operatemenu(struct MENU *menu, int *row, int *aborted); void tx_destroymenu(struct MENU *menu); #endif /* IPTRAF_NG_TUI_MENURT_H */ iptraf-ng-1.2.1/src/tui/msgboxes.c000066400000000000000000000037511370555550300170030ustar00rootroot00000000000000/* For terms of usage/redistribution/modification see the LICENSE file */ /* For authors and contributors see the AUTHORS file */ /* * msgboxes.c - message and error box display functions */ #include "iptraf-ng-compat.h" #include "winops.h" int ERR_BORDER_ATTR; int ERR_TEXT_ATTR; int ERR_PROMPT_ATTR; int INFO_BORDER_ATTR; int INFO_TEXT_ATTR; int INFO_PROMPT_ATTR; void tx_init_error_attrs(int border, int text, int prompt) { ERR_BORDER_ATTR = border; ERR_TEXT_ATTR = text; ERR_PROMPT_ATTR = prompt; } void tx_init_info_attrs(int border, int text, int prompt) { INFO_BORDER_ATTR = border; INFO_TEXT_ATTR = text; INFO_PROMPT_ATTR = prompt; } void tui_error_va(const char *prompt, const char *err, va_list vararg) { WINDOW *win = newwin(4, 70, (LINES - 4) / 2, (COLS - 70) / 2); PANEL *panel = new_panel(win); wattrset(win, ERR_BORDER_ATTR); tx_colorwin(win); tx_box(win, ACS_VLINE, ACS_HLINE); wattrset(win, ERR_PROMPT_ATTR); mvwprintw(win, 2, 2, "%s", prompt); wattrset(win, ERR_TEXT_ATTR); wmove(win, 1, 2); vw_printw(win, err, vararg); update_panels(); doupdate(); int response; do { response = wgetch(win); if (response == 12) tx_refresh_screen(); } while (response == 12); del_panel(panel); delwin(win); update_panels(); doupdate(); } void tui_error(const char *prompt, const char *err, ...) { va_list params; va_start(params, err); tui_error_va(prompt, err, params); va_end(params); } void tx_infobox(char *text, char *prompt) { WINDOW *win; PANEL *panel; int ch; win = newwin(4, 50, (LINES - 4) / 2, (COLS - 50) / 2); panel = new_panel(win); wattrset(win, INFO_BORDER_ATTR); tx_colorwin(win); tx_box(win, ACS_VLINE, ACS_HLINE); wattrset(win, INFO_TEXT_ATTR); mvwprintw(win, 1, 2, "%s", text); wattrset(win, INFO_PROMPT_ATTR); mvwprintw(win, 2, 2, "%s", prompt); update_panels(); doupdate(); do { ch = wgetch(win); if (ch == 12) tx_refresh_screen(); } while (ch == 12); del_panel(panel); delwin(win); update_panels(); doupdate(); } iptraf-ng-1.2.1/src/tui/msgboxes.h000066400000000000000000000007121370555550300170020ustar00rootroot00000000000000#ifndef IPTRAF_NG_TUI_MSGBOXES_H #define IPTRAF_NG_TUI_MSGBOXES_H #define ANYKEY_MSG "Press a key to continue" void tx_init_error_attrs(int border, int text, int prompt); void tx_init_info_attrs(int border, int text, int prompt); void tx_infobox(char *text, char *prompt); void tui_error(const char *prompt, const char *err, ...) __printf(2,3); void tui_error_va(const char *prompt, const char *err, va_list vararg); #endif /* IPTRAF_NG_TUI_MSGBOXES_H */ iptraf-ng-1.2.1/src/tui/winops.c000066400000000000000000000031161370555550300164660ustar00rootroot00000000000000/* For terms of usage/redistribution/modification see the LICENSE file */ /* For authors and contributors see the AUTHORS file */ /*** winops.c - screen configuration and setup functions ***/ #include "iptraf-ng-compat.h" void tx_stdwinset(WINDOW * win) { meta(win, TRUE); keypad(win, TRUE); notimeout(win, 0); scrollok(win, 1); } void tx_refresh_screen(void) { endwin(); doupdate(); curs_set(0); } void tx_colorwin(WINDOW *win) { scrollok(win, 0); for (int row = 0; row < getmaxy(win); row++) mvwprintw(win, row, 0, "%*c", getmaxx(win), ' '); scrollok(win, 1); } void tx_wcoloreol(WINDOW *win) { scrollok(win, 0); wprintw(win, "%*c", getmaxx(win) - getcurx(win) - 1, ' '); } /* * This function is written to address a strange symptom in ncurses 5.2, at * least on RedHat 7.3. The border drawn by the box() macro (actually an alias * for a call to wborder()) no longer uses the color attributes set by * wattrset(). However, the addch() and wvline() functions still do. * * The tx_box function is a drop-in replacement for box(). */ void tx_box(WINDOW *win, int vline, int hline) { int winwidth; int winheight; int i; scrollok(win, 0); getmaxyx(win, winheight, winwidth); winheight--; winwidth--; mvwaddch(win, 0, 0, ACS_ULCORNER); mvwhline(win, 0, 1, hline, winwidth - 1); mvwaddch(win, 0, winwidth, ACS_URCORNER); for (i = 1; i < winheight; i++) { mvwaddch(win, i, 0, vline); mvwaddch(win, i, winwidth, vline); } mvwaddch(win, winheight, 0, ACS_LLCORNER); mvwhline(win, winheight, 1, hline, winwidth - 1); mvwaddch(win, winheight, winwidth, ACS_LRCORNER); } iptraf-ng-1.2.1/src/tui/winops.h000066400000000000000000000006461370555550300165000ustar00rootroot00000000000000#ifndef IPTRAF_NG_TUI_WINOPS_H #define IPTRAF_NG_TUI_WINOPS_H /*** stdwinset.h - prototype declaration for setting the standard window settings for IPTraf ***/ #define tx_coloreol() tx_wcoloreol(stdscr) void tx_stdwinset(WINDOW * win); void tx_refresh_screen(void); void tx_colorwin(WINDOW * win); void tx_wcoloreol(WINDOW * win); void tx_box(WINDOW * win, int vline, int hline); #endif /* IPTRAF_NG_TUI_WINOPS_H */ iptraf-ng-1.2.1/src/usage.c000066400000000000000000000026111370555550300154510ustar00rootroot00000000000000/* For terms of usage/redistribution/modification see the LICENSE file */ /* For authors and contributors see the AUTHORS file */ #include "iptraf-ng-compat.h" static void vreportf(const char *prefix, const char *err, va_list params) { char msg[4096]; vsnprintf(msg, sizeof(msg), err, params); fprintf(stderr, "%s%s\n", prefix, msg); } static __noreturn void die_builtin(const char *err, va_list params) { vreportf("fatal: ", err, params); exit(129); } static void error_builtin(const char *err, va_list params) { vreportf("error: ", err, params); } void die(const char *err, ...) { va_list params; va_start(params, err); die_builtin(err, params); va_end(params); } void error(const char *err, ...) { va_list params; va_start(params, err); error_builtin(err, params); va_end(params); } void die_errno(const char *fmt, ...) { va_list params; char fmt_with_err[1024]; char str_error[256], *err; size_t i, j; err = strerror(errno); for (i = j = 0; err[i] && j < sizeof(str_error) - 1; ) { if ((str_error[j++] = err[i++]) != '%') continue; if (j < sizeof(str_error) - 1) { str_error[j++] = '%'; } else { /* No room to double the '%', so we overwrite it with * '\0' below */ j--; break; } } str_error[j] = 0; snprintf(fmt_with_err, sizeof(fmt_with_err), "%s: %s", fmt, str_error); va_start(params, fmt); die_builtin(fmt_with_err, params); va_end(params); } iptraf-ng-1.2.1/src/wrapper.c000066400000000000000000000026051370555550300160300ustar00rootroot00000000000000/* For terms of usage/redistribution/modification see the LICENSE file */ /* For authors and contributors see the AUTHORS file */ #include "iptraf-ng-compat.h" // Die if we can't allocate size bytes of memory. void *xmalloc(size_t size) { void *ptr = malloc(size); if (ptr == NULL && size != 0) die("Out of memory, xmalloc failed"); return ptr; } void *xmallocz(size_t size) { void *ptr = xmalloc(size); memset(ptr, 0, size); return ptr; } void *xcalloc(size_t nmemb, size_t size) { void *ptr = calloc(nmemb, size); if (!ptr && (!nmemb || !size)) die("Out of memory, xcalloc failed"); return ptr; } void *xrealloc(void *ptr, size_t size) { void *ret = realloc(ptr, size); if (!ret && !size) die("Out of memory, xrealloc failed"); return ret; } // Die if we can't copy a string to freshly allocated memory. char *xstrdup(const char *s) { if (!s) return NULL; char *t = strdup(s); if (!t) die("Out of memory, %s failed", __func__); return t; } int strtoul_ui(char const *s, int base, unsigned int *result) { unsigned long ul; char *p; errno = 0; ul = strtoul(s, &p, base); if (errno || *p || p == s || (unsigned int) ul != ul) return -1; *result = ul; return 0; } int strtol_i(char const *s, int base, int *result) { long ul; char *p; errno = 0; ul = strtol(s, &p, base); if (errno || *p || p == s || (int) ul != ul) return -1; *result = ul; return 0; }