pax_global_header00006660000000000000000000000064135255312700014515gustar00rootroot0000000000000052 comment=9cf249ebc18745a59418a62de124ff3975b59a01 softflowd-softflowd-1.0.0/000077500000000000000000000000001352553127000155275ustar00rootroot00000000000000softflowd-softflowd-1.0.0/.travis.yml000066400000000000000000000005031352553127000176360ustar00rootroot00000000000000language: c os: - linux - osx compiler: gcc sudo: false addons: apt: packages: libpcap-dev before_install: - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update ; fi - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew install libpcap; fi before_script: autoreconf -if script: ./configure && make softflowd-softflowd-1.0.0/AUTHORS000066400000000000000000000001521352553127000165750ustar00rootroot00000000000000Original creator: Damien Miller Current maintainer: Hitoshi Irino softflowd-softflowd-1.0.0/COPYING000077700000000000000000000000001352553127000175622LICENSEustar00rootroot00000000000000softflowd-softflowd-1.0.0/ChangeLog000066400000000000000000001504251352553127000173100ustar00rootroot00000000000000commit bf7f0ec0c335d8d367c9b1e64371acd8e7bcc1d0 Author: Hitoshi Irino Date: Thu Aug 15 23:05:08 2019 +0900 update NEWS commit a01f664f6b664d451799b511912c948edd57e93e Author: Hitoshi Irino Date: Thu Aug 15 22:56:31 2019 +0900 Add function for receiving PSAMP which is originated softflowd. commit 3a87c82424c1181e82a77c499724f90f56183085 Author: Hitoshi Irino Date: Sun Aug 11 16:10:10 2019 +0900 remove portable_endian.h commit f6cde9fb93c13aa85f3ce91f66a7f7398902c627 Author: Hitoshi Irino Date: Sun Aug 11 15:58:21 2019 +0900 move definition relating APPLE to common.h from portable_endian.h commit 43bdd0caf797c10885bc4cad95625db74467fca8 Author: Hitoshi Irino Date: Sun Aug 11 14:29:43 2019 +0900 fix error about initial declarations in for loop commit b2e4816533c485b9a0270b0209801aeb7f96eea5 Author: Hitoshi Irino Date: Sun Aug 11 08:53:29 2019 +0900 add .travis.yml commit 9925c0e78ea8f746a70afc5185147f1519ad47b8 Merge: 7d1c667 6bf55a5 Author: Hitoshi Irino Date: Thu Aug 8 19:57:04 2019 +0900 Merge pull request #13 from gsfjohnson/macos_mojave adjustments for MacOS Mojave commit 6bf55a5e4f30583a65eef5212770e5b8b25da622 Author: Glen Johnson Date: Tue Aug 6 17:45:21 2019 -0700 adjustments for MacOS Mojave commit 7d1c667e484563841066e0b08e87a39d3c5092fb Author: Hitoshi Irino Date: Sun Aug 4 12:08:04 2019 +0900 Fix segmentation fault error due to buffer overflow for ntopng direct injection. commit 61ef846c801f027cee5febc9ea06acb2b99ade90 Author: Hitoshi Irino Date: Sun Aug 4 10:09:38 2019 +0900 Change ntopng function - replace enable-zeromq to enable-ntopng - replace -v 11 to -v ntopng for NTOPNG direct injection commit b1e762e9c6915cf95cc9dbf4d2c95d00e21d6e0f Author: Hitoshi Irino Date: Sun Aug 4 08:31:25 2019 +0900 Remove Makefile.in because this file is autogenerated. commit 377efd931fcd92bff5c478885632bda2ca2e3b43 Merge: 01f77c1 cc2ee36 Author: Hitoshi Irino Date: Sat Aug 3 10:04:32 2019 +0900 Merge pull request #12 from deece/ntopng Push flows to ntopng commit cc2ee36e55b89dec007eafb425ba89bd5cd7942a Author: Alastair D'Silva Date: Thu Aug 1 13:47:56 2019 +1000 Push flows to ntopng Ntopng is a an open-source traffic analyser: https://www.ntop.org/products/traffic-analysis/ntop/ Unfortunately, it cannot ingest Netflow data directly, instead, it requires a payware component (Nprobe) to tranlate Netflow to JSON encapsulated in ZeroMQ messages. This patch allows softflowd to generate those messages directly, allowing Ntopng to be used without the need for the payware component. Signed-off-by: Alastair D'Silva commit 01f77c1e6fa03b1ed355e35a33b680f167f9a9ac Author: Hitoshi Irino Date: Sun Jul 21 17:06:35 2019 +0900 Merge netflow v1 code into netflow5.c commit eae2cd6b934e1713333658f37e39da95e631d7c5 Author: Hitoshi Irino Date: Mon Jul 15 16:40:51 2019 +0900 Add load balancing mode - change configure enable option from legacy-nf9 to legacy - indent -lp -br -brs -brf -ce -cdw -nut ipfix.c ipfix.h netflow1.c netflow5.c netflow9.c netflow9.h psamp.c psamp.h softflowd.c softflowd.h - update manpage commit 3d96d6be9a452bcd41bffd0bd0d0abfdaa22ff8d Author: Hitoshi Irino Date: Tue Jul 2 23:20:53 2019 +0900 Add new fuctionality for sending multiple destinations commit 8dc420c3b0a7ecc148e07ae92416694b6e00b38e Author: Hitoshi Irino Date: Sun Jun 30 20:51:57 2019 +0900 Add sending psamp functionality. In addition - separate Information Elements definitions to header files (netflow9.h ipfix.h psamp.h ) - indent -lp -br -brs -brf -ce -cdw -nut common.h ipfix.c ipfix.h netflow9.c psamp.c softflowd.c softflowd.h - update man page - update configure.ac and Makefile.am for exclude compiling netflow9.c without enable-legacy-nf9 commit 973fcf5e7a1424094ca10d56a43673c66f619413 Author: Hitoshi Irino Date: Sun Jun 2 00:18:00 2019 +0900 Add multithread option when configure --enable-pthread (It is unstable function) Additonally - indent -lp -br -brs -brf -ce -cdw -nut softflowd.c softflowd.h netflow*.c ipfix.c - upddate manpage - fix configure bug commit 2e18e6d0b0e4a2b2d6aeff1ea3cfe55f90ecc95b Author: Hitoshi Irino Date: Sat Jun 1 12:52:27 2019 +0900 Use automake and update manpage. commit ddda5064cbee8984edef09edec2357c5295775ae Author: Hitoshi Irino Date: Wed May 29 07:32:56 2019 +0900 indent -lp -br -brs -brf softflowd.c softflowd.h netflow*.c ipfix.c commit e6d29a172d9d0b922b6701838fe073f036746651 Author: Hitoshi Irino Date: Sun May 26 23:00:41 2019 +0900 Add option "-a" for reading pcap file and fix some bugs. - fix flow_compare for comparing vlan and ether - fix missing sequence in netflow v9 commit 5dc03fd092e5a9e05856f8221715a0b3eb1bd9cd Author: Hitoshi Irino Date: Mon May 6 11:33:06 2019 +0900 update explanation about -b option in usage function. commit 4fcb3c1f5a8dc2e91ed65ca1aeb802e878fd0ae2 Merge: 7526e9c 34ebfeb Author: Hitoshi Irino Date: Sat Dec 1 10:14:40 2018 +0900 Merge pull request #9 from nm-mrt/configure Add autoconf tools to build instructions in README commit 34ebfeb98e21e6ec36909ef3dde32cf3ea16bfb3 Author: Moritz Rosenthal Date: Tue Nov 20 16:20:06 2018 +0100 Add autoconf tools to build instructions in README The build instructions were misleading as the configure script is not inclueded in the files shipped with repository. commit 7526e9ca2627a7af22eb04aa35f4683de24b7f66 Merge: bbd0685 e2d1cbd Author: Hitoshi Irino Date: Fri Sep 14 21:57:25 2018 +0900 Merge pull request #7 from richb-hanover/documentation-tweaks Update documentation to include PDF pages. commit e2d1cbdc498b7cd5dc68dfd146d804d0b5e28f6d Author: Rich Brown Date: Fri Sep 14 08:27:29 2018 -0400 Update documentation to include PDF pages. Since this has become the official repo for softflowd, readers can learn about softflowd without running software. Also added Irino's name as maintainer in the man pages, as well as a link to the github repo for bugs and source code. commit bbd0685d69236844138f96df387a31506d641d0d Author: Hitoshi Irino Date: Fri Sep 14 18:32:33 2018 +0900 Add check of the length of string for -i (interface) option. commit 4391b4b749056298b69ea400de9e6472e6f25667 Author: Hitoshi Irino Date: Fri Sep 14 17:08:45 2018 +0900 Delete .cvsignore commit 8a47e875e2070e0dc50f1c63c99fae612e27e33c Author: Hitoshi Irino Date: Fri Sep 14 15:50:48 2018 +0900 Adding current repository information in README. commit 49c039a19203c2f20cfd097612e44481ce067831 Author: Hitoshi Irino Date: Fri Sep 14 15:37:53 2018 +0900 Added define _DEFAULT_SOURCE line to avoid warning in Linux. commit 8ea92c3545663a86497a892c53ad394c78a8856a Author: Hitoshi Irino Date: Sun Aug 6 08:17:43 2017 +0900 New implementation of IPFIX/Netflow v9 for supporting VLAN and Mac-address. commit 3aa2af5894dd420e049c61fe69aa124003a2390d Author: SysError956 Date: Tue Apr 25 18:26:07 2017 -0400 Fix format type for pid (%u for unsigned instead of %d for signed) commit 2f195a052b1bed1565d07e2cdfac0467a6be31d1 Author: SysError956 Date: Tue Apr 25 18:09:54 2017 -0400 Check pidfile to see if daemon already running commit b7e50ae4ebb3368a52c7938e1d2b046f90cf6d8f Author: SysError956 Date: Thu Mar 23 20:36:50 2017 -0400 Added support for the pflog datalink type and fixed some typos commit d53e821bb744c2475858c4d604058e0a475d6177 Author: Hitoshi Irino Date: Sun Oct 5 15:24:17 2014 +0900 Add bidirectional flow (RFC5103) support in IPFIX. Fix the compile warnings. commit 3f8e0fceec51047a27574395fb436ef52ceaf792 Author: Hitoshi Irino Date: Sun Sep 28 20:23:07 2014 +0900 This commit fix sequence number in ipfix header. And it display number of exported data records in statistics. commit 94786397a40326853462005f4434544528c23b76 Author: Hitoshi Irino Date: Mon Mar 17 13:10:54 2014 +0900 This commit includes 2 changes. 1. It enables metering and exporting vlanid when using NetFlow v9 and IPFIX. 2. When ICMP flow information are exported It uses the ICMP_TYPE field instead of the L4_DST_PORT field commit b4a7a1cd4541d89fc985c2caad4dc747378a7b69 Author: Hitoshi Irino Date: Sun Dec 23 23:44:10 2012 +0900 ToS field is metered and exported in NetFlow v1,v5,v9 and IPFIX in default settings. -A option is added for exporting absolute time field in IPFIX records to be able to receive with NFDUMP(nfcapd). -P option is added to select export transport protocol from UDP, TCP, and SCTP. (It is not tested yet.) commit 417e018c0aca09dbc9edc39a2d4ac0b125d536c0 Author: Hitoshi Irino Date: Mon Dec 10 22:33:53 2012 +0900 add ipfix.c to support exporting IPFIX formated flow records. commit bd8e31ecc0bc050f10d549d6e5d526ccd97733b3 Author: Hitoshi Irino Date: Sat Sep 29 22:35:18 2012 +0900 Fix bug. The sequence number field in NetFlow version 9 is number of exported packets. Older version used number of exported flows for this field. commit cdf7ae1e3ef368d6b1fa7ae0694bf6f4aaabb325 Author: Hitoshi Irino Date: Sun Sep 23 03:43:48 2012 +0900 Using strtok instead of strsep in environments which does not have strsep. commit 91b2a2ced9954777d417a0d4c58bc957622b0f6a Author: Hitoshi Irino Date: Fri Sep 21 14:46:18 2012 +0900 Changes for avoidance warnings in gcc compilation on Linux (Ubuntu 12.04), OpenBSD 5.1 and Oracle solaris 11 with AMD64 architecture when enables "--enable-gcc-warnings" option in configure. commit 5719206e1d0d6cedf92ba6d77909729c691ed6f4 Author: Damien Miller Date: Mon Feb 13 12:38:18 2012 +1100 Added tag softflowd-0.9.9 for changeset c496d4d49348 commit f7c9e6d8fa61fe9bece16ce9ac749286c764e43e Author: Damien Miller Date: Mon Feb 13 12:37:33 2012 +1100 Update version to 0.9.9 in anticipation of release commit 43e4ee1c5a1f8b5afb32d891fa968cc266ae99ef Author: Damien Miller Date: Mon Feb 13 12:36:54 2012 +1100 remove obsolete RCS Id markers commit 0f461a9e063190e35e66a73bb46dacd88286ac22 Author: Damien Miller Date: Mon Feb 13 12:32:11 2012 +1100 Changelog is now deprecated in favour of mercurial log. commit 69149d2383163f55411e1e81e2f412cf29e975e4 Author: Hitoshi Irino Date: Sat Nov 26 10:36:24 2011 +0900 Add AC_ARG_WITH chrootdir in configure.ac to be able to change privdrop chroot direcotry for non BSD environments. commit 49ad50331dac83e51f257680949312fb726b3118 Author: Hitoshi Irino Date: Fri Oct 14 21:04:09 2011 +0900 Fix roff errors. (http://lists.mindrot.org/pipermail/netflow-tools/2011-February/000487.html) commit 6e45d1e8f56c762e2cd99024be9a47d24f320ab8 Author: Hitoshi Irino Date: Fri Oct 14 19:01:12 2011 +0900 Broken URL in comments is replaced to another URL. commit 1083d3dd10b42bfe6f179856901ed414e3e31c6a Author: Hitoshi Irino Date: Wed Oct 12 23:08:40 2011 +0900 Broken URL in softflowd.8 man page is replaced to other URLs. commit 51495c4ee4114534bf0f1a97c96f7017a9bae562 Author: Hitoshi Irino Date: Mon Oct 10 16:53:45 2011 +0900 Some compiler warnings that are appears in AMD64 environment are reduced. "%llu" keywords are replaced with "%PRIu64". commit 4807417a8d632298256346336e29f39c0f60b43b Author: Hitoshi Irino Date: Mon Oct 10 16:10:39 2011 +0900 Description about "-s" sampling option is added in manpage of softflowd. commit b844d025df2619f9d7148c4628b64ae101ce5866 Author: Hitoshi Irino Date: Mon Oct 10 15:59:08 2011 +0900 Sampling function as "-s" option is added. If -s option is enabled, option template flow records and option data flow records are exported when export protocol is netflow version 9. commit 0dce54e9a289a36f3c0d0c85650b2604db0c7bcf Author: Hitoshi Irino Date: Thu Sep 22 09:43:38 2011 +0900 fix broken NetFlow v9 flow creation for IPv6 (http://lists.mindrot.org/pipermail/netflow-tools/2011-February/000489.html) commit 916db7f5bf456b8fd13a02c36f795098b21014f0 Author: Hitoshi Irino Date: Wed Sep 21 23:50:08 2011 +0900 avoid to leave main loop while listening on "any" interface. (http://lists.mindrot.org/pipermail/netflow-tools/2011-February/000488.html) commit cc60ffabafe969a05e6ed0a8fb64883c0aee45b8 Author: Damien Miller Date: Mon Nov 1 12:03:41 2010 +1100 fix some warnings commit c8eef71995f9a4c6af6c53239b408ee8ae65f77d Author: Damien Miller Date: Mon Nov 1 12:03:34 2010 +1100 remove broken -WformatC=2 flag that somehow snuck into configure.ac commit 9c8f5edc65a63566c62cb32021e708ea4d61c412 Author: Damien Miller Date: Mon Nov 1 12:03:02 2010 +1100 mention new Google Code repository commit c8c3065f6032d20115a971c46b70efdb91423e40 Author: convert-repo Date: Sun Oct 31 14:34:12 2010 +0000 update tags commit 2652c7b5c48ee6b9cf4f1d3fcfa704844313ff91 Author: djm Date: Tue May 4 02:23:51 2010 +0000 - (djm) Swap nf9 last/first switched. They were reversed in the struct vs our template flowset. Patch from stephen AT sfnelson.org. https://bugzilla.mindrot.org/show_bug.cgi?id=1760 commit 09512a462b17dff6d6c0c62190b28383abf2d481 Author: djm Date: Thu Oct 1 08:23:33 2009 +0000 - (djm) Display softflowd start time in "softflowctl statistics" display. Suggestion from Tamas TEVESZ. commit f57006dbe892990adf936a99c24bff3f13df10be Author: djm Date: Thu Oct 1 07:25:34 2009 +0000 - (djm) One more manpage tweak from Tamas TEVESZ. commit 0e41def7876bcb8ef2624fb5448d1586113b7fc4 Author: djm Date: Thu Oct 1 07:06:08 2009 +0000 - (djm) Support manual specification of an interface index to be used as the input and output interface of all flows generated. Patch from kempf AT rpi.edu commit 548decbf01ae5abfa0415e6353882642b4a3838d Author: djm Date: Thu Oct 1 06:29:19 2009 +0000 Lots of manpage tweaks from Tamas TEVESZ, ice AT extreme.hu commit afbd3cc9a747e3b1319ec320268b1d9e81c89854 Author: djm Date: Thu May 15 18:22:02 2008 +0000 - (djm) Fix typo in manpage for PID file location; patch from ice AT extreme.hu - (djm) Make privsep directory compile-time configurable; patch from ice AT extreme.hu commit 407dd0870cad7ddaed38180b2412aec0587564f6 Author: djm Date: Mon Sep 3 10:50:05 2007 +0000 - (djm) Implement a very simple freelist allocator for flows and expiry events commit ef74b9062cf531035fe7ebefa4d6f8d5f1457621 Author: djm Date: Fri Aug 31 03:11:03 2007 +0000 - (djm) Move max_flows into struct FLOWTRACK commit b0a0d54cd768b69f8f0c0f1e4f9845749c9a5f40 Author: djm Date: Thu Jul 26 00:50:31 2007 +0000 - (djm) Add flow_get/flow_put and expiry_get/expiry_put functions to allocate and deallocate flows and expiry events, instead of calling malloc/free directly. Right now these functions just call malloc/free anyway, but they will soon be used to implemented pooled flow/expiry allocations. commit 1592c1b3e60ce45e434d0dee6b4605ea42d8180b Author: djm Date: Tue Jul 24 23:50:35 2007 +0000 - (djm) openlog with LOG_NDELAY so socket is connected before privdrop - patch from Florian Weimer commit 38967c4173206bef65f26c784934024de98f326a Author: djm Date: Tue Jul 24 23:49:43 2007 +0000 - (djm) Correctly exit from mainloop on signal - patch from Florian Weimer commit 82477a6cfbc31c74d2f0940369e97bb0a007284e Author: djm Date: Tue Jul 24 23:48:58 2007 +0000 - (djm) KNF commit d76684d20fd1a1673b55e4659d009a353b0544c1 Author: djm Date: Fri Jan 5 05:00:34 2007 +0000 better place commit 3e21cd3e73cc511ea867cecf3a964c89825df7eb Author: djm Date: Fri Jan 5 04:56:29 2007 +0000 another commit f2cdbff13df68b60c644d0e324d1575420a3d2ab Author: djm Date: Fri Jan 5 04:54:44 2007 +0000 newline at EOF commit 6800ff1fa886c4ff25079c667e95931505a57ffe Author: djm Date: Thu Nov 2 22:50:01 2006 +0000 - (djm) Document -v option and close Ed in manpage; from Nino Jogun nino80 AT gmail.com commit aea9b2557d226afedeafdc516c00902d3f0f06c7 Author: djm Date: Thu Nov 2 06:36:16 2006 +0000 prep for release commit b934962bb7e52e21649dacdcf82167936dfba456 Author: djm Date: Thu Nov 2 06:34:18 2006 +0000 mention LICENSE commit 2dfbcf16d4980d9b045547a1ff9aef1f60862594 Author: djm Date: Thu Nov 2 06:29:40 2006 +0000 - (djm) Sync sys-tree.h commit 88c78fd672fc545cbad98839c0309638cf5e2b00 Author: djm Date: Thu Nov 2 06:29:33 2006 +0000 more commit a45adcfce6d50edadd6525e0060d58e286149a31 Author: djm Date: Thu Nov 2 06:23:29 2006 +0000 - (djm) malloc(x*y) -> calloc(x, y) commit 7d1ddaad792e975d1fd802805f59cf74d61b7c52 Author: djm Date: Thu Nov 2 00:15:48 2006 +0000 - (djm) Collect licenses into LICENSE file commit 7ec91dc3af1d4f665bf430d8ce2dbccdfb5792e3 Author: djm Date: Thu Mar 16 08:24:19 2006 +0000 - (djm) Add "send-template" softflowctl command to resend a NetFlow 9 template record immediately commit c055b70addfa0463b69224c252fa471b8a38bfb0 Author: djm Date: Thu Mar 16 08:23:13 2006 +0000 - (djm) Add "send-template" softflowctl command to resend a NetFlow 9 template record immediately commit d4242f6b645e7634527804faa987afef9a263b2b Author: djm Date: Tue Mar 14 23:15:41 2006 +0000 - (djm) Add RPM packaging files from ssnodgra AT pheran.com commit 1ab0c942ec56ae1095578acf9b51483bf43299b1 Author: djm Date: Tue Mar 14 23:14:23 2006 +0000 - (djm) Crank version number to 0.9.8 commit 1ca6e61046d4362039c46725763131f1b4ed39a4 Author: djm Date: Tue Mar 14 23:06:10 2006 +0000 - (djm) Encode ICMP type and code into port numbers (apparently this is what Cisco exporters do), patch from ssnodgra AT pheran.com slightly tweaked by me commit 685cfdf9b99f388e6e5a5b2fdfdd7da9ffe1780d Author: djm Date: Tue Mar 14 22:55:41 2006 +0000 - (djm) Support ${DESTDIR} in Makefile install target, from ssnodgra AT pheran.com commit 4fa859d3abccc05c43a00d9de10a88235c607af7 Author: djm Date: Tue Mar 14 22:51:48 2006 +0000 - (djm) Fix DLT_RAW support, from jhanna AT shaw.ca commit 5aca81ee9db65063b9e1e493e57769bedb6845a0 Author: djm Date: Mon Feb 13 20:48:15 2006 +0000 - (djm) Add missing getopt() bit for flowtrack mode commit 0bf0fe4260234f53ec226e6d31002efe3b43d3d5 Author: djm Date: Sat Feb 11 11:27:38 2006 +0000 - (djm) Add option to ignore port and protocol information from flows, allowing flows from the same IP addresses to be automatically coalesced commit 970c294671e89569270a2239b754957c25f9f42f Author: djm Date: Wed Jan 25 23:25:04 2006 +0000 - (djm) Correctly expire quiescent flows when they hit maximum_lifetime; bug noticed and patch tested by andreas.brillisauer AT hetzner.de commit 205988967ff8096c412efc52f0f2a4e43647535d Author: djm Date: Thu Dec 22 02:23:41 2005 +0000 - (djm) Make sure installation directories exist, spotted by alshu AT tut.by commit d2a71f153ed22b1fd973a3f5ddd884841faf680f Author: djm Date: Fri Nov 18 05:19:12 2005 +0000 - (djm) Support Linux "cooked socket" datalink type, from Tony Lewis gnutered AT yahoo.com.au commit 78874c4809fe0282c855a9d79ef146c493991806 Author: djm Date: Fri Nov 18 05:17:10 2005 +0000 - (djm) Some extra paranoia and verbosity on malloc failures commit 86fbc4bda72904df200693bb9bfc7386df22a9dc Author: djm Date: Sat Oct 1 00:14:21 2005 +0000 - (djm) Fix typo, from rbreathe AT brookes.ac.uk commit 60ab28b7a359d2fcd75c80489b34b8cdca0b36ba Author: djm Date: Sat May 14 06:47:46 2005 +0000 - (djm) Fix reversed NetFlow v.9 first_switched and last_switched times commit 966578170f1dd4f41c93a2ba80489442f0e15ac7 Author: djm Date: Sat May 14 06:47:16 2005 +0000 - (djm) Fix time printing bug in debug mode commit 81ac51ceb7627853382eb4117a669ecd9ae137a3 Author: djm Date: Sat May 14 06:17:18 2005 +0000 more commit 3b655023c6aa46d022bcf1bff53a9196c9537113 Author: djm Date: Thu May 5 03:32:57 2005 +0000 - (djm) Report pcap stats in statistics display commit 9bb3c79f9f197c4034a0fad9b1774a987bb8e45d Author: djm Date: Thu May 5 03:31:42 2005 +0000 - (djm) Fix bug in sequence number generation. Reported by b.ghita AT jack.see.plymouth.ac.uk and mwlucas AT blackhelicopters.org commit edf957dc8dec6447730dae968cb760589012c894 Author: djm Date: Tue Apr 19 11:59:02 2005 +0000 more commit 53baf7db99b5525d9c3559b9ab8506a77f379054 Author: djm Date: Sat Jan 15 04:09:50 2005 +0000 0.9.7 commit 3d6202ec66858f3a8b1f761c775daf359bf37fec Author: djm Date: Sat Jan 15 04:08:56 2005 +0000 prepare for release of 0.9.7 commit 8b9a86bfed9695c877df1a53b12aa87a0e1e7c04 Author: djm Date: Mon Jan 10 01:50:07 2005 +0000 - (djm) Add option to set hoplimit/TTL in support of multicast export support - (djm) Document multicast export commit da885e93aa46d9563a2937eb01cf3a23fc9ed935 Author: djm Date: Mon Jan 10 01:02:34 2005 +0000 - (djm) Fix endianness problem in NetFlow v.9 port number export. Found and fixed by paolo.lucente AT ic.cnr.it commit 92b6235ce56ba1be98ef854d9156d1a3d82cf980 Author: djm Date: Mon Nov 8 23:03:28 2004 +0000 - (djm) Test for struct ip6_ext in autoconf and define a replacement if missing, some systems lack it commit 21026e24a69634979608faf9de73867d0a660785 Author: djm Date: Thu Sep 30 04:37:11 2004 +0000 - (djm) Release 0.9.6 commit 2494b066d087cf84484e797135a782359fa8ef70 Author: djm Date: Thu Sep 30 04:37:06 2004 +0000 xxx no ipv6 commit 2ed6f1715d00ae33cdc6d0056a0e72fe6c5caeed Author: djm Date: Thu Sep 30 04:36:29 2004 +0000 - (djm) Update README with recent changes (NetFlow v.9, v6 flows) commit 02f154f70414c297af3aae9fa657a8613a9c3337 Author: djm Date: Thu Sep 30 04:31:33 2004 +0000 tidy commit 2daf944e715e4d9893ba0b7c5f6a4ff00f982ed0 Author: djm Date: Thu Sep 30 04:27:02 2004 +0000 - (djm) Unbreak compilation on non-OpenBSD commit e601d52b0a67b1d029a8673c0000890ab4ee041c Author: djm Date: Thu Sep 30 04:26:16 2004 +0000 - (djm) Unbreak v6 flow export commit 94fc2d47f67a2183e9987bd4d8628a136180d9a5 Author: djm Date: Thu Sep 30 04:12:36 2004 +0000 - (djm) Don't bother tracking IPv6 flows if NetFlow export version doesn't support it - (djm) Don't crank up pcap snaplen unless we are interested in IPv6 either commit b18bd03f2b43185d19b136b2cd25c824ccd6b136 Author: djm Date: Thu Sep 30 03:43:36 2004 +0000 - (djm) Include IP_PROTOCOL_VERSION field in NetFlow v.9 packets commit 5de4785a783717c36247292337389088502a69f4 Author: djm Date: Thu Sep 30 03:35:44 2004 +0000 - (djm) Add a timeout to cluster expiry expiry events, so we get more flows per packet. Default is to check for expiries every 60s - (djm) Allow timouts to be disabled (by setting them to 0) commit 55f53f97ce56a575ab18feda6ee5634aef337c7b Author: djm Date: Thu Sep 30 01:59:58 2004 +0000 - (djm) Remove unused debugging code from NetFlow v.9 support commit 042129df2c8391a22fc011d44d9b2eb23be0ac28 Author: djm Date: Thu Sep 30 00:42:55 2004 +0000 - (djm) Remove unused debugging code from NetFlow v.9 support commit 625f75b5c946381814359816e11d6c10b68b8c6d Author: djm Date: Thu Sep 30 00:19:52 2004 +0000 - (djm) Increase caplen a little for IPv6 commit f44c1f359753ae6aac25c35276434819dc199b5b Author: djm Date: Wed Sep 29 04:14:35 2004 +0000 - (djm) NetFlow v.9 support commit 233f736bfd94b3719b9e59373042029588ba181b Author: djm Date: Wed Sep 29 04:14:27 2004 +0000 more commit 6b8995478fafc3096fa8a601f2520431fb39e2a7 Author: djm Date: Wed Sep 29 03:57:10 2004 +0000 - (djm) Remove NetFlow v.1 types from NetFlow v.5 code commit 5b7e179f434d2eb80c8c24537c2f20683480826a Author: djm Date: Wed Sep 29 03:55:59 2004 +0000 - (djm) Improve IPv6 code: track flowlables bidirectionally (but don't key on them for now), print addresses:port tuples unambiguously and apply correct timeout for ICMPv6 flows commit a99908be013fbbc17759ab25dbd57efb6982ef0b Author: djm Date: Mon Sep 13 12:07:50 2004 +0000 more commit ed5fb095c7bbf13558906ffe408ac5c04065c782 Author: djm Date: Mon Sep 13 04:35:54 2004 +0000 - (djm) Switch to a table of netflow exporter functions in preparation for additional export protocols - (djm) Collect netflow export target information together in a struct, in preparation for more export protocols and support for multiple export targets - (djm) Optimise the datalink_check function, by caching the last datalink type used. commit 29f54a4cfa9ab97958ffaea72d02a4a6e37dfdcc Author: djm Date: Mon Sep 13 02:25:09 2004 +0000 - (djm) Split out netflow send functions into separate files commit a68b1c25a93b983a128c870979bcc6985bbe8f18 Author: djm Date: Fri Sep 10 09:45:47 2004 +0000 improve commit e01ead22f15534c0691bfdb79b8fcabea2f00207 Author: djm Date: Fri Sep 10 09:33:04 2004 +0000 add some, delete some, tidy lots commit 8c681d1f9b58ec0a125905a62795da8e21971a98 Author: djm Date: Fri Sep 10 09:21:53 2004 +0000 - (djm) Comment out dump_packet (uncomment when debugging) commit 95aa873b6c8fc8350fe99b6085218d27f35ca69b Author: djm Date: Fri Sep 10 09:20:56 2004 +0000 - (djm) Use strlcat/strlcpy instead of strn* functions commit 9ac877a7106359a0b14af29aeb3f77a18f629230 Author: djm Date: Fri Sep 10 09:08:08 2004 +0000 - (djm) Portability fixes for Linux, add closefrom() commit 94eb01cbe4ab957d88bb4b9fc10ab1807906263b Author: djm Date: Fri Sep 10 08:43:25 2004 +0000 - (djm) Implement IPv6 flow tracking. Currently no export functionality. commit a94df1e26e7cfdcfa21d22ab418362641410e0fb Author: djm Date: Fri Sep 10 08:43:02 2004 +0000 more commit d93be754d061cb2f75669dbc265adb0e880049f6 Author: djm Date: Thu Sep 9 10:20:55 2004 +0000 - (djm) Prepare for IPv6 packet to flow conversion routine commit 0ae18ad80f47b4503075ac4ae10f25c83d4bf503 Author: djm Date: Thu Sep 9 09:28:10 2004 +0000 - (djm) Be more careful about putting flows into canonical format commit 83adac9f39b6813dfdf861427333d0578ad80ecf Author: djm Date: Thu Sep 9 09:13:43 2004 +0000 - (djm) Another step on the road: factor out transport-layer protocol parsing from IPv4 parsing code commit e0343134798fd37b28c1887aa0bed6dc3d2b421c Author: djm Date: Thu Sep 9 09:11:37 2004 +0000 more commit a0bf456a6b4eb866de647f928a9667d86cd9b7bb Author: djm Date: Thu Sep 9 07:00:17 2004 +0000 - (djm) Next step in preparation of IPv6 support: make flow structure and lookup function support both IPv4 and IPv6 addresses (v6 addrs aren't yet used) commit d33141677ebad43a04c0dc42c545120b1830077b Author: djm Date: Thu Sep 9 06:19:06 2004 +0000 - (djm) Rework datalink processing, in preparation of IPv6 support commit 563888a83ee3e7dd9469e219de032cc2375ed831 Author: djm Date: Thu Sep 9 01:30:25 2004 +0000 - (djm) inline is unnecessary commit 8366bf6fac9119f332313ecf1aa68281beff17b7 Author: djm Date: Wed Sep 1 03:14:28 2004 +0000 - (djm) Release version 0.9.2 commit 41b5110230c30c40890974326549567bb593a21b Author: djm Date: Wed Sep 1 03:14:09 2004 +0000 - (djm) Fix a tiny, stupid bug that prevents flow export commit e7fd7bdeee0a6155bbeb050247e006993442c142 Author: djm Date: Fri Aug 27 14:40:43 2004 +0000 - (djm) Release version 0.9.1 commit 4431e3eb073d11bd8f1a77935c2c9362b676acf3 Author: djm Date: Fri Aug 27 14:40:27 2004 +0000 - (djm) Mention NetFlow v.5 support in manpage commit 307731b7614cb494b78064b64d8dcbe5e5c1279f Author: djm Date: Fri Aug 27 14:36:26 2004 +0000 - (djm) NetFlow v.5 supports 30 flows per packet - (djm) Use struct sockaddr in arguments (not sockaddr_storage), properly check length commit 3ba99b8ca738dd9137f88bef5c56be0bde8c7eaf Author: djm Date: Fri Jul 16 06:26:57 2004 +0000 - (djm) Fix collector.pl when no address family specified on commandline spotted by pgennai AT netstarnetworks.com commit 5f7394698a5ca3dd3ebcb1eb35c3bd75af621c0c Author: djm Date: Fri Jul 16 06:20:09 2004 +0000 more commit fb930278bfa5b0f85c5566d1ab4d23e0646ea58b Author: djm Date: Sat Jul 10 10:35:16 2004 +0000 - (djm) Add support for NetFlow v.5 export format to collector.pl commit 99ebc00ec7ffca33ebe7107922eae2c5d63bc6fd Author: djm Date: Sat Jul 10 10:34:50 2004 +0000 v.5 is done commit a5d0cafac4ced03f0be24bebf031a1f0ab900b63 Author: djm Date: Sat Jul 10 10:19:19 2004 +0000 - (djm) Tidy up code: remove some debugging gunk, kill a global - (djm) Add support for NetFlow v.5 export format commit d81074419d92286fd13dd495555c13f92ee3335a Author: djm Date: Sat Jul 10 10:18:21 2004 +0000 remove obselete comment commit 63165cb13c5146b78a2f29e6f27452a80c16e434 Author: djm Date: Fri Apr 30 03:25:30 2004 +0000 - (djm) Release version 0.9 commit 062759ff4fdd40a3c1537a4cd81e3c11149a8e40 Author: djm Date: Fri Apr 30 03:22:13 2004 +0000 we couldn't avoid it commit 6656fb8007a0910c84eaed425977158caced4ea6 Author: djm Date: Sun Apr 18 03:45:05 2004 +0000 - (djm) Fix invalid packet bug commit 70d88c1739eb5a6666c492f747e9f167d5888bef Author: djm Date: Sat Apr 17 09:51:54 2004 +0000 remove useless comment commit fa7405fefd11e23b110d04fc6e2b897a24c4ca6a Author: djm Date: Sat Apr 17 09:20:03 2004 +0000 sections commit 504e27c8f67a323906effa81619ff2b1f7ceb7cf Author: djm Date: Sat Apr 17 09:14:35 2004 +0000 - (djm) Separate timeout for ICMP traffic, generic timeout is too long commit 0d46c3a4715b1ae51ec94bae1da35edb41a621c4 Author: djm Date: Sat Apr 17 02:10:13 2004 +0000 - (djm) Eliminate periodic expiry scans, wait in poll() only until the next scheduled expiry event commit df15e70f6f9e9c1a67ee4b58e5ca2dab4650037b Author: djm Date: Fri Apr 16 23:46:09 2004 +0000 more & tidy commit 71cf7f3400b879101f4110101336ee07172cbc0e Author: djm Date: Fri Apr 16 10:46:48 2004 +0000 - (djm) Unbreak "make install" commit 7f41d483ae737ff82586db26847a721b9c99b823 Author: djm Date: Fri Apr 16 10:44:02 2004 +0000 update commit 93f8cec0c1377f0267d46dbf9103e276c983c50c Author: djm Date: Fri Apr 16 06:22:31 2004 +0000 - (djm) Unbreak Solaris, pass socklen around instead of using sa_len commit d54eb4a486bc85b4deaf0d04e9bbf87f5b28c68a Author: djm Date: Fri Apr 16 06:14:03 2004 +0000 - (djm) Tidy manpage and mention v6 export syntax commit 0493acd85f10e8aedc6195d6d9197adbaf85c7c3 Author: djm Date: Fri Apr 16 06:13:28 2004 +0000 - (djm) More flow export fixes commit 5df2c973ebc84126501fc3b345a948efa0c7f1e9 Author: djm Date: Fri Apr 16 05:18:44 2004 +0000 - (djm) Allow v4 operation of collector.pl if v6 modules aren't present commit 2dc06bd5d9a1e04f5509f3724fe2fd0c1bcd1e75 Author: djm Date: Fri Apr 16 04:46:26 2004 +0000 - (djm) IPv6 listen support for collector.pl commit 3647682bdc170a0d02a7cd9c3304bb59c8151154 Author: djm Date: Fri Apr 16 02:06:37 2004 +0000 todo commit 42b97ace9688803a0e3daed96b0a060c677de25e Author: djm Date: Fri Apr 16 02:00:50 2004 +0000 - (djm) Support "[host]:port" syntax to specify numeric IPv6 export target - (djm) Fix connect() for IPv6 export targets commit 0c4296580531f35ed32d740e1c3d0df7aecb6054 Author: djm Date: Fri Apr 16 01:53:26 2004 +0000 - (djm) Fix busted preprocessor commit 77bb2d5b15ccc50819ec82d0a8e37a5be4e37a66 Author: djm Date: Fri Apr 16 01:51:51 2004 +0000 - (djm) A bunch of changes necessary to support building on Solaris 9 (though the resultant binary doesn't seem to work properly): - Use getaddrinfo instead of inet_aton to parse host/port for export - Use setreuid if setresuid isn't around (ditto for gid) - Add replacement daemon() function from OpenBSD - Provide our own logit() function, because Solaris syslog() doesn't support LOG_PERROR - A heap of configure and common.h additions and fixes commit 60eb9dfa7ed6dec4a4f8315d6e1b62edf1e8549a Author: djm Date: Thu Apr 15 10:47:05 2004 +0000 - (djm) Detect int and define standard int types in configure commit 4b117ffb240576b7913c06ed1bb7f357a146c738 Author: djm Date: Thu Apr 15 04:44:47 2004 +0000 - (djm) Use autoconf to detect various things; in preparation of more portability commit acf77e9bbf0ba4b6cce858b202b5dbe55c451087 Author: djm Date: Thu Apr 15 01:19:41 2004 +0000 - (djm) Never endprotoent() commit b793969c8a21fac96c4b2f59508a509090a427f9 Author: djm Date: Thu Apr 15 01:19:16 2004 +0000 - (djm) Linux needs grp.h for setgroups() commit dd2b18c17c16bb78c3754042711d308bda1368b3 Author: djm Date: Thu Apr 15 01:02:08 2004 +0000 - (djm) Print flow start and finish times in collector.pl commit a46ccfbc57fe2000e125ed21bf33b719bc07b0e4 Author: djm Date: Thu Apr 15 00:17:41 2004 +0000 - (djm) Clear socket errors before UDP send; from pfflowd commit c24bf2e5ea15134a59da7f4a3903c2a3329973c0 Author: djm Date: Mon Nov 10 22:44:05 2003 +0000 ignore commit df1ba62226ac6183e8417555f07eaeb050593319 Author: djm Date: Mon Nov 10 22:43:43 2003 +0000 - (djm) Remove -Werror from CFLAGS, it causes problems in released software commit 4d12f9422e5a41e2d3f1d2e55a6b9a8283a1540a Author: djm Date: Sun Nov 9 00:38:08 2003 +0000 - (djm) Give compile-time choice over flow and expiry event tree type default is splay tree for flows and red-black tree for expiry events (limited benchmarking indicates that this is the fastest) - (djm) Lock the BPF device to prevent changes should the unpriv child be compromised (only OpenBSD supports this ioctl for now) commit b4cd6fc5fd6783db2b77f63b0a7a18288aad25f6 Author: djm Date: Sun Nov 9 00:25:20 2003 +0000 more commit fbb56c0cbf0bd1747920e8b247eb4578c86cfaf4 Author: djm Date: Thu Oct 2 01:37:31 2003 +0000 - (djm) Realloc audit - (djm) Chroot to /var/empty and drop privileges on daemonisation - (djm) More things TODO commit 5542dc13ff6070ade591770da1422f3c8a0426d4 Author: djm Date: Mon Jun 23 09:56:52 2003 +0000 more commit c5ce81fb84ff5b6f8937ed8b8c7606b7e544de68 Author: djm Date: Fri Jun 20 02:23:29 2003 +0000 - (djm) Release version 0.8.1 commit 1719ee32330c8e297418511ee8539719e1fd4695 Author: djm Date: Fri Jun 20 02:21:58 2003 +0000 Mention fragment handling issues commit 3aa51212346ce2fc0345aeaa3aba26a1eead3269 Author: djm Date: Fri Jun 20 02:21:50 2003 +0000 Mention bugzilla commit b8a99de57536d6fdbc2c1169c2df9b82c0c965b3 Author: djm Date: Fri Jun 20 02:21:38 2003 +0000 - (djm) Fix fragment handling bug: we would try to look into fragmented payload on later fragments. This could cause random tcp/udp port numbers to be recorded. - (djm) Fix malicious fragment handling bug: deliberately tiny fragments (e.g. http://citeseer.nj.nec.com/ptacek98insertion.html) would be ignored and would not create flow entries. - (djm) Count fragments that we have seen commit 657225fe550ed4d921fd8279773514be823828d6 Author: djm Date: Fri Jun 20 02:07:38 2003 +0000 - (djm) Add "strip" target to Makefile commit fe36b285e4f69cfb7fe8f2463cbbe53914bd090b Author: djm Date: Fri Jun 20 02:07:13 2003 +0000 - (djm) Rework TODO, add section on planned fragment handling commit a017f9d776bb8d147fdcb9d93bc4485ef8c4bcdf Author: djm Date: Fri Jun 20 02:06:53 2003 +0000 - (djm) Fixup collector timestamp printing commit 6a82d1fc0e5aa117d8be4bbcff8ea6485b830b67 Author: djm Date: Thu Mar 6 13:55:49 2003 +0000 sync commit 17ede4ff966ef9e2b931085619e4d663dd367d13 Author: djm Date: Thu Mar 6 13:51:23 2003 +0000 some goes in, some goes out commit 9b21ce76f054d25e1a31db0ca8b30aa119595a45 Author: djm Date: Thu Mar 6 13:27:10 2003 +0000 Trim out unused Netflow v5 and v7 support Tidy output Track sender address commit bff93f4a453d3584e1b9528656ff8dd358844af2 Author: djm Date: Thu Mar 6 13:26:32 2003 +0000 more commit a3c6263aba5e165fa7cb4c43b1a67ede3c360d99 Author: djm Date: Wed Jan 22 07:03:28 2003 +0000 do some commit 39a089a34baab30b791bacbe1ea8e82338eea8ce Author: djm Date: Sun Nov 10 09:46:41 2002 +0000 collector sucks commit 15f8be2abf589c316c687f06b3fdb12831a5673a Author: djm Date: Sun Nov 10 01:19:52 2002 +0000 Add simple perl netflow collector commit 5ed01438d916b0b6f0c4bd47fbd5b1a40b0512bf Author: djm Date: Sun Nov 10 01:05:40 2002 +0000 Refactor ctlsock handling from mainloop to separate function, shortens mainloop considerably. Rework struct poll setup while we're there commit abe4c7e444b56074ceaa92c8e78a6cc0a6e7a4aa Author: djm Date: Tue Nov 5 01:29:18 2002 +0000 - (djm) Don't exit on failure to lookup net/mask. From Alejandro Roman commit d892bc17e816dfb7cb1d47041296ddf5cd71460e Author: djm Date: Thu Oct 31 08:53:57 2002 +0000 verbiage commit 7fda27d3284f572ea3c693801ac22bd3c15466ce Author: djm Date: Thu Oct 31 08:48:12 2002 +0000 tidy commit e8cf1c3b2fa29e841b80834a76ea929b6966837c Author: djm Date: Thu Oct 31 08:48:02 2002 +0000 Add examples section commit 54647ffd84b2517247069e5db8a045e62b7e3b75 Author: djm Date: Wed Oct 30 11:24:44 2002 +0000 Always use local sys-tree.h commit 38ad1642b94c17543db9204e0e5488823b2c9d36 Author: djm Date: Wed Oct 30 11:21:14 2002 +0000 New user-friendly time specification code from OpenSSH/Kevin Steves Some doc fixes too commit 7fafecd5d63156b5c398c44d1f1797b3e44fea08 Author: djm Date: Tue Oct 29 12:56:47 2002 +0000 v8.0 commit 8670e48521c82dcdbd70ccbc1049018400050527 Author: djm Date: Tue Oct 29 12:56:04 2002 +0000 - (djm) Multiple fixes and improvements from Octavian Cerna - softflowd.c (connsock): Fix arguments to `connect': addr is a pointer, not a structure. (flow_update_expiry): Properly compute the flow lifetime. (send_netflow_v1): Count the leftover packet. Send flow_start, flow_finish and uptime_ms as Cisco equipment does: milliseconds since system boot. (timeval_sub_ms): New function. (main): Changed POLL_WAIT to be (EXPIRY_WAIT/2) as stated in the comment above `poll': twice per recheck. `poll' takes the last argument in milliseconds. Initialize system_boot_time as the time at the start of capture (fixme: how does this affect reading from capture files?) commit 63ecec4598ab730df87451428efba4dd4017feb4 Author: djm Date: Thu Oct 24 02:10:05 2002 +0000 Minor fixes commit 91c6de745ca18e2c3ccc664f01b73d1a63556c07 Author: djm Date: Mon Oct 21 10:37:33 2002 +0000 Fix a couple of bugs and compilation errors on OpenBSD. Includes a use-after-free error spotted by Aaron Turner commit 90d39b2d5270769c74c67668344aa0dfd3b266be Author: djm Date: Fri Oct 18 10:00:54 2002 +0000 More docs commit 7ec48f842b0a56dfd6adec15c8ff1e62029badc5 Author: djm Date: Fri Oct 18 09:16:26 2002 +0000 Much hacking: - Flesh out softflowctl - getopt - Allow specification of socket file - Give it a manpag - Lots of commands now - New TODO & README files - New common header file - New flow expiry code - Fast expiry of FIN'd and RST'd TCP connection - Separate general, UDP and TCP timeouts - Add maximum flow lifetime - Track statistics on flow expiry reasons - Fast expiry happens in its own function now - Tidy up of statistics code - Separate struct and update function - Prettier printing - Kill (heh) the signals based interface, use softflowctl instead - Refactor main() - Much code moved to helper functions commit b0aa7404379fcd8bc5e8f95f3b7716a7370ebb26 Author: djm Date: Thu Oct 17 14:52:00 2002 +0000 Add guts of socket based remote control commit 98d5598257fcdc28107fd50e8bb5b414d411c4b8 Author: djm Date: Thu Oct 17 14:50:52 2002 +0000 newline at EOF commit 451a1d1f310d9f17d6b311a269641979da012464 Author: djm Date: Thu Oct 17 14:50:37 2002 +0000 sys-queue.h commit 932e7a11103361f2f03c1607f0f36fbfec1a6eaf Author: djm Date: Thu Oct 17 13:30:59 2002 +0000 Make netflow data export option, i.e allow operation in statistics-only mode commit 696905cdd08748ea21ce6f111b24287a7856c03c Author: djm Date: Thu Oct 17 13:30:07 2002 +0000 More ideas commit 958201dbb28aaa310e9804b9850407440b0a92f2 Author: djm Date: Thu Oct 17 13:24:53 2002 +0000 Bump up pcap snaplen a little commit 408fe92e66984727f71d5b696c719f83291b46eb Author: djm Date: Thu Oct 17 12:47:53 2002 +0000 A few more states, more neatly printed commit ade6a1318a68de08484e9712be7070afc51cd015 Author: djm Date: Thu Oct 17 12:34:01 2002 +0000 Collect per-protocol lifetime (min/max) stats. This will be useful for tuning early expiry heuristics commit e34898b489b1e3ac2142c6f733305df1a6c9c388 Author: djm Date: Thu Oct 17 11:49:38 2002 +0000 tidy commit 2cdb95000a1363a56e91bcd3ef9556b0cf2d295b Author: djm Date: Thu Oct 17 11:47:09 2002 +0000 Fix crashes in RB-tree expiry code Rewrite comparison functions to be more paranoid about signed vs unsigned commit 732270b316d17a567c37a553c8c541eef4049e66 Author: djm Date: Thu Oct 17 11:20:31 2002 +0000 Change expiries queue to a RB tree, in preparation for fast expiry of TCP and transient flows commit 7ff8fb3ac13e15b547b3baacb91afc1b36bc1763 Author: djm Date: Thu Oct 17 11:04:11 2002 +0000 print protocol names commit 1ea197004c4a359009d96788a4c7134147abf1da Author: djm Date: Thu Oct 17 10:59:29 2002 +0000 Per protocol stats collection commit 09c7534f1ed2ce250cc95afd42c472e28a837447 Author: djm Date: Thu Oct 17 09:44:39 2002 +0000 tidy and comment commit 9e328e05323f3cfb44489f922befa69a4322b4d2 Author: djm Date: Thu Oct 17 09:32:41 2002 +0000 make mainloop timeout configurable commit 1ee7c3df97b39999bd9dbf6e912813b0e4914936 Author: djm Date: Thu Oct 17 08:56:03 2002 +0000 Fix flow export crash Unlink PID file on exit commit 190ba66a71f2a0c0b1481ff9d2e9e820264a7d6b Author: djm Date: Wed Oct 16 15:53:52 2002 +0000 newline after pid in pidfile commit 7a393108fb5884d3f1348a1f1033f7b48ef9614e Author: djm Date: Wed Oct 16 15:46:59 2002 +0000 really fix export bug commit eb9c3e7d0fefa288a3e66302f690c721d1fb9017 Author: djm Date: Wed Oct 16 15:43:36 2002 +0000 version commit f091729cb2a2ae6bd99b8392a9db55f4f849d79b Author: djm Date: Wed Oct 16 15:42:25 2002 +0000 Fix flow export bug when only 1/2 flows per export packet commit e62d696f0dbd9393e3b9dd8b86b051732649606c Author: djm Date: Wed Oct 16 13:08:35 2002 +0000 less debug commit 4dbedebe25e5446c1deb2d39d684833e60f372ba Author: djm Date: Wed Oct 16 12:02:10 2002 +0000 fix debug commit 63347f7800d3d2623ee5888c5bc47a926480657b Author: djm Date: Wed Oct 16 11:47:16 2002 +0000 more debug commit 6a56128d12bc454f410b282b9260c410c1798cd4 Author: djm Date: Wed Oct 16 11:37:33 2002 +0000 fix debug commit 62bff071cce04f64a04f1a5ea258b231136b72c8 Author: djm Date: Wed Oct 16 11:37:04 2002 +0000 more debug commit 0c974a3f8098a076335050666dc7567c142f74e8 Author: djm Date: Wed Oct 16 11:34:24 2002 +0000 fix debug commit 4e5b30365f379466c0054cd65fe063c947a0261e Author: djm Date: Wed Oct 16 11:32:45 2002 +0000 fix debug commit 4a525c9c540e97b2b20086f761329f5a8c86cb89 Author: djm Date: Wed Oct 16 11:32:05 2002 +0000 more debug commit 7a61a3b3501f8b999efd58eb5126e9047a70cffd Author: djm Date: Wed Oct 16 11:14:59 2002 +0000 Collect additional statistics commit e3836c5847d16b07fd9d1c2eb4eea085ad9e292c Author: djm Date: Wed Oct 16 09:54:07 2002 +0000 More large changes: - Tidy Makefile - Remove splay tree code (it is buggy or I am using it wrong) - Store flows in canonical format for bidirectional matching instead of relying on over-smart (and buggy) comaprison function - Improve capture file handling. - Don't read the entire capfile in one go - Perform expiry processing in capfile mode only when max_flows exceeded - Don't let pcap_dispatch process more than max_flows packets in one go commit eb45ed5ebe2ad173b97674f0f8ca3dd1a2ab7c50 Author: djm Date: Tue Oct 15 13:02:31 2002 +0000 doh commit 4648aa76b522c84f42996b4094ca05313e053b35 Author: djm Date: Tue Oct 15 12:56:59 2002 +0000 rewrite of flow export function commit 859cdff7a4b6c48c2a75adda6f73181bcc1024df Author: djm Date: Tue Oct 15 12:31:06 2002 +0000 memleak commit 1468dc0da0eb933af44249b33407bd89668853f9 Author: djm Date: Tue Oct 15 12:28:17 2002 +0000 Doc on signals commit 43a282a5ab10a4a32a59174e8c4d617da231de0a Author: djm Date: Tue Oct 15 02:30:57 2002 +0000 Make flow tracking bidirectional Collect a few more statistics Comment code fully Rename fakeflowd -> softflowd Turn on all GCC warnings and fix commit 99454daf85cb525dab10dd29de672c4f1bd1b426 Author: djm Date: Tue Oct 15 00:16:04 2002 +0000 Track and report TCP flags commit 7204c2975899c4283f2b44df00dbd8a0c95ff9df Author: djm Date: Mon Oct 14 23:51:16 2002 +0000 Fix export of more than 24 flows commit a7708da2e29d12a4ccd20d1ef37e3b1d6997ea52 Author: djm Date: Mon Oct 14 14:18:35 2002 +0000 Add support for DLT_LOOP (OpenBSD PPP) and DLT_NULL datalink types commit 1941d7e02b66c8284cf168613187f05aa45f41d3 Author: djm Date: Mon Oct 14 14:12:38 2002 +0000 More OpenBSD fixes commit ae1bbc37406a395471008f7ceb73c8c944d2d191 Author: djm Date: Mon Oct 14 14:09:00 2002 +0000 make compile on OpenBSD commit 11b5a37891cc1c3f5bb7273d583835730d748dfd Author: djm Date: Mon Oct 14 14:06:43 2002 +0000 Use OpenBSD header files if possible commit d4727b19f54ffa665f1256f3f1fb6a191d12a1c5 Author: djm Date: Mon Oct 14 14:05:00 2002 +0000 Initial revision commit d7ccc47e3957a745738aa7c00e02a25c48f12a2a Author: djm Date: Mon Oct 14 12:38:35 2002 +0000 fix options processing commit 0090b612fe00bb8e94f78c1ecc2893d7f71bdcc1 Author: djm Date: Mon Oct 14 12:29:25 2002 +0000 Make tree type selectable (splay or red-black) Rework main loop to not break on capture files Add no-fork option Rename debug option commit f157b65147f4b664367bd602527d7fa18b8e8b44 Author: djm Date: Mon Oct 14 12:03:53 2002 +0000 Fix commit 8bb336569112f892bae381a435fbb61694a35ae8 Author: djm Date: Mon Oct 14 12:01:45 2002 +0000 Manual page commit 40d75c4d001a2288f91929c0ff012682fe3e33fe Author: djm Date: Mon Oct 14 12:01:07 2002 +0000 Rename statistics print function and call it upon exit commit a86143c2c960dcc8b45795832f3184b71583bfed Author: djm Date: Mon Oct 14 11:05:10 2002 +0000 Version 0.1 commit 9a76fca5a62cc5ac254fe1d45524b84721f9bf04 Author: djm Date: Mon Oct 14 10:32:00 2002 +0000 openbsd compile fix commit 722157ed7c0aac8239f56501b82ebf2eea744a8b Author: djm Date: Mon Oct 14 10:30:57 2002 +0000 Make flow tracking bidirectional Collect a few more statistics Comment code fully Rename fakeflowd -> softflowd Turn on all GCC warnings and fix commit 187e0ae31c22420109351a56df135492630f6053 Author: djm Date: Mon Oct 14 09:05:00 2002 +0000 Initial revision softflowd-softflowd-1.0.0/INSTALL000066400000000000000000000366141352553127000165720ustar00rootroot00000000000000Installation Instructions ************************* Copyright (C) 1994-1996, 1999-2002, 2004-2016 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without warranty of any kind. Basic Installation ================== Briefly, the shell command './configure && make && make install' should configure, build, and install this package. The following more-detailed instructions are generic; see the 'README' file for instructions specific to this package. Some packages provide this 'INSTALL' file but do not implement all of the features documented below. The lack of an optional feature in a given package is not necessarily a bug. More recommendations for GNU packages can be found in *note Makefile Conventions: (standards)Makefile Conventions. The 'configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a 'Makefile' in each directory of the package. It may also create one or more '.h' files containing system-dependent definitions. Finally, it creates a shell script 'config.status' that you can run in the future to recreate the current configuration, and a file 'config.log' containing compiler output (useful mainly for debugging 'configure'). It can also use an optional file (typically called 'config.cache' and enabled with '--cache-file=config.cache' or simply '-C') that saves the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale cache files. If you need to do unusual things to compile the package, please try to figure out how 'configure' could check whether to do them, and mail diffs or instructions to the address given in the 'README' so they can be considered for the next release. If you are using the cache, and at some point 'config.cache' contains results you don't want to keep, you may remove or edit it. The file 'configure.ac' (or 'configure.in') is used to create 'configure' by a program called 'autoconf'. You need 'configure.ac' if you want to change it or regenerate 'configure' using a newer version of 'autoconf'. The simplest way to compile this package is: 1. 'cd' to the directory containing the package's source code and type './configure' to configure the package for your system. Running 'configure' might take a while. While running, it prints some messages telling which features it is checking for. 2. Type 'make' to compile the package. 3. Optionally, type 'make check' to run any self-tests that come with the package, generally using the just-built uninstalled binaries. 4. Type 'make install' to install the programs and any data files and documentation. When installing into a prefix owned by root, it is recommended that the package be configured and built as a regular user, and only the 'make install' phase executed with root privileges. 5. Optionally, type 'make installcheck' to repeat any self-tests, but this time using the binaries in their final installed location. This target does not install anything. Running this target as a regular user, particularly if the prior 'make install' required root privileges, verifies that the installation completed correctly. 6. You can remove the program binaries and object files from the source code directory by typing 'make clean'. To also remove the files that 'configure' created (so you can compile the package for a different kind of computer), type 'make distclean'. There is also a 'make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. 7. Often, you can also type 'make uninstall' to remove the installed files again. In practice, not all packages have tested that uninstallation works correctly, even though it is required by the GNU Coding Standards. 8. Some packages, particularly those that use Automake, provide 'make distcheck', which can by used by developers to test that all other targets like 'make install' and 'make uninstall' work correctly. This target is generally not run by end users. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the 'configure' script does not know about. Run './configure --help' for details on some of the pertinent environment variables. You can give 'configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you can use GNU 'make'. 'cd' to the directory where you want the object files and executables to go and run the 'configure' script. 'configure' automatically checks for the source code in the directory that 'configure' is in and in '..'. This is known as a "VPATH" build. With a non-GNU 'make', it is safer to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use 'make distclean' before reconfiguring for another architecture. On MacOS X 10.5 and later systems, you can create libraries and executables that work on multiple system types--known as "fat" or "universal" binaries--by specifying multiple '-arch' options to the compiler but only a single '-arch' option to the preprocessor. Like this: ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CPP="gcc -E" CXXCPP="g++ -E" This is not guaranteed to produce working output in all cases, you may have to build one architecture at a time and combine the results using the 'lipo' tool if you have problems. Installation Names ================== By default, 'make install' installs the package's commands under '/usr/local/bin', include files under '/usr/local/include', etc. You can specify an installation prefix other than '/usr/local' by giving 'configure' the option '--prefix=PREFIX', where PREFIX must be an absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option '--exec-prefix=PREFIX' to 'configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like '--bindir=DIR' to specify different values for particular kinds of files. Run 'configure --help' for a list of the directories you can set and what kinds of files go in them. In general, the default for these options is expressed in terms of '${prefix}', so that specifying just '--prefix' will affect all of the other directory specifications that were not explicitly provided. The most portable way to affect installation locations is to pass the correct locations to 'configure'; however, many packages provide one or both of the following shortcuts of passing variable assignments to the 'make install' command line to change installation locations without having to reconfigure or recompile. The first method involves providing an override variable for each affected directory. For example, 'make install prefix=/alternate/directory' will choose an alternate location for all directory configuration variables that were expressed in terms of '${prefix}'. Any directories that were specified during 'configure', but not in terms of '${prefix}', must each be overridden at install time for the entire installation to be relocated. The approach of makefile variable overrides for each directory variable is required by the GNU Coding Standards, and ideally causes no recompilation. However, some platforms have known limitations with the semantics of shared libraries that end up requiring recompilation when using this method, particularly noticeable in packages that use GNU Libtool. The second method involves providing the 'DESTDIR' variable. For example, 'make install DESTDIR=/alternate/directory' will prepend '/alternate/directory' before all installation names. The approach of 'DESTDIR' overrides is not required by the GNU Coding Standards, and does not work on platforms that have drive letters. On the other hand, it does better at avoiding recompilation issues, and works well even when some directory options were not specified in terms of '${prefix}' at 'configure' time. Optional Features ================= If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving 'configure' the option '--program-prefix=PREFIX' or '--program-suffix=SUFFIX'. Some packages pay attention to '--enable-FEATURE' options to 'configure', where FEATURE indicates an optional part of the package. They may also pay attention to '--with-PACKAGE' options, where PACKAGE is something like 'gnu-as' or 'x' (for the X Window System). The 'README' should mention any '--enable-' and '--with-' options that the package recognizes. For packages that use the X Window System, 'configure' can usually find the X include and library files automatically, but if it doesn't, you can use the 'configure' options '--x-includes=DIR' and '--x-libraries=DIR' to specify their locations. Some packages offer the ability to configure how verbose the execution of 'make' will be. For these packages, running './configure --enable-silent-rules' sets the default to minimal output, which can be overridden with 'make V=1'; while running './configure --disable-silent-rules' sets the default to verbose, which can be overridden with 'make V=0'. Particular systems ================== On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC is not installed, it is recommended to use the following options in order to use an ANSI C compiler: ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" and if that doesn't work, install pre-built binaries of GCC for HP-UX. HP-UX 'make' updates targets which have the same time stamps as their prerequisites, which makes it generally unusable when shipped generated files such as 'configure' are involved. Use GNU 'make' instead. On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot parse its '' header file. The option '-nodtk' can be used as a workaround. If GNU CC is not installed, it is therefore recommended to try ./configure CC="cc" and if that doesn't work, try ./configure CC="cc -nodtk" On Solaris, don't put '/usr/ucb' early in your 'PATH'. This directory contains several dysfunctional programs; working variants of these programs are available in '/usr/bin'. So, if you need '/usr/ucb' in your 'PATH', put it _after_ '/usr/bin'. On Haiku, software installed for all users goes in '/boot/common', not '/usr/local'. It is recommended to use the following options: ./configure --prefix=/boot/common Specifying the System Type ========================== There may be some features 'configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, 'configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the '--build=TYPE' option. TYPE can either be a short name for the system type, such as 'sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file 'config.sub' for the possible values of each field. If 'config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the option '--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with '--host=TYPE'. Sharing Defaults ================ If you want to set default values for 'configure' scripts to share, you can create a site shell script called 'config.site' that gives default values for variables like 'CC', 'cache_file', and 'prefix'. 'configure' looks for 'PREFIX/share/config.site' if it exists, then 'PREFIX/etc/config.site' if it exists. Or, you can set the 'CONFIG_SITE' environment variable to the location of the site script. A warning: not all 'configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to 'configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the 'configure' command line, using 'VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified 'gcc' to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for 'CONFIG_SHELL' due to an Autoconf limitation. Until the limitation is lifted, you can use this workaround: CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash 'configure' Invocation ====================== 'configure' recognizes the following options to control how it operates. '--help' '-h' Print a summary of all of the options to 'configure', and exit. '--help=short' '--help=recursive' Print a summary of the options unique to this package's 'configure', and exit. The 'short' variant lists options used only in the top level, while the 'recursive' variant lists options also present in any nested packages. '--version' '-V' Print the version of Autoconf used to generate the 'configure' script, and exit. '--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally 'config.cache'. FILE defaults to '/dev/null' to disable caching. '--config-cache' '-C' Alias for '--cache-file=config.cache'. '--quiet' '--silent' '-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to '/dev/null' (any error messages will still be shown). '--srcdir=DIR' Look for the package's source code in directory DIR. Usually 'configure' can determine that directory automatically. '--prefix=DIR' Use DIR as the installation prefix. *note Installation Names:: for more details, including other options available for fine-tuning the installation locations. '--no-create' '-n' Run the configure checks, but stop before creating any output files. 'configure' also accepts some other, not widely useful, options. Run 'configure --help' for more details. softflowd-softflowd-1.0.0/LICENSE000066400000000000000000000162371352553127000165450ustar00rootroot00000000000000Original code is licensed under the following BSD-style license: /* * Copyright 2002-2006 Damien Miller All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ closefrom.c: /* * Copyright (c) 2004 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ convtime.c: /* * Copyright (c) 2001 Kevin Steves. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ daemon.c: /*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ strlcat.c, strlcpy.c: /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ sys-tree.h: /* * Copyright 2002 Niels Provos * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ softflowd-softflowd-1.0.0/Makefile.am000066400000000000000000000011761352553127000175700ustar00rootroot00000000000000bin_PROGRAMS = softflowd softflowctl COMMON = common.h convtime.h treetype.h sys-tree.h\ convtime.c strlcpy.c strlcat.c closefrom.c daemon.c if ENABLE_LEGACY LEGACY_SOURCES = netflow9.c netflow1.c endif if ENABLE_NTOPNG NTOPNG_SOURCES = ntopng.c endif softflowd_SOURCES = freelist.h log.h softflowd.h netflow9.h ipfix.h psamp.h\ freelist.c softflowd.c log.c netflow5.c ipfix.c psamp.c\ $(COMMON) EXTRA_softflowd_SOURCES = $(LEGACY_SOURCES) $(NTOPNG_SOURCES) softflowd_LDADD = $(LEGACY) $(NTOPNG) softflowd_DEPENDENCIES = $(LEGACY) $(NTOPNG) softflowctl_SOURCES = softflowctl.c $(COMMON) dist_man_MANS = softflowd.8 softflowctl.8 softflowd-softflowd-1.0.0/NEWS000066400000000000000000000023141352553127000162260ustar00rootroot00000000000000Fri Aug 16 2019 Softflowd 1.0.0 This release contains some new features. Details This release contains the following new features: Add support sending packet capture data using PSAMP format, Add function for sending to multiple destination with/without load-balance. Add function for injecting to ntopng directly. Mon Feb 13 2012 Softflowd 0.9.9 This release contains a number of bug fixes and some new features. It also welcomes Hitoshi Irino as a developer. Details This release contains the following new features: Add support for flow sampling, controlled by a new -s option (see softflowd(8) manpage for details) Add compile-time --chrootdir option to specify alternate chroot directory. Allow specification of input and output interface indices using a new -i option. Introduce a freelist allocator for expiry and flow objects, faster than malloc And the following bug fixes: Correctly exit from mainloop when a signal is received Fix logging from reduced-privileged child Many manpage typo, consistency and formatting fixes The softflow statistics command now displays the time at which softflowd was started Avoid spurious exit from mainloop while listening on "any" interface Correct broken IPv6 Netflow v.9 flowssoftflowd-softflowd-1.0.0/README000066400000000000000000000056741352553127000164230ustar00rootroot00000000000000Welcome to softflowd, a flow-based network monitor. Introduction ------------ softflowd listens promiscuously on a network interface and semi-statefully tracks network flows. These flows can be reported using NetFlow version 1, 5 or 9 datagrams. softflowd is fully IPv6 capable: it can track IPv6 flows and export to IPv6 hosts. More details about softflowd's function and usage may be found in the supplied PDF manpages. They were built with: man -t ./softflowd.8 | ps2pdf - softflowd.pdf man -t ./softflowctl.8 | ps2pdf - softflowctl.pdf You can view those pages prior to installation using: /usr/bin/nroff -c -mandoc softflowd.8 | less /usr/bin/nroff -c -mandoc softflowctl.8 | less If you are in need of a NetFlow collector, you may be interested in softflowd's companion project "flowd" (http://www.mindrot.org/projects/flowd/). flowd is a NetFlow collector that is maintained in parallel with softflowd and includes a few handy features, such as the ability to filter flows it receives as well as Perl and Python APIs to its storage format. NB. You don't have to use flowd: any NetFlow compatible collector should work with softflowd. An example Perl collector is included for testing purposes as collector.pl, but it doesn't yet support NetFlow v.9 Installing ---------- Building softflowd should be as simple as typing: autoconf autoreconf ./configure make make install Unfortunately some systems like to make life complicated. Things work fine on the systems that I develop and test on (OpenBSD and Linux). There is peliminary support for Solaris 9 (i.e. it compiled), but no testing on this platform has been performed. Licensing --------- Softflowd is licensed under a two-term BSD license (see the source files for details). The code in sys-tree.h is Copyright Niels Provos and comes straight from OpenBSD CVS, convtime.c comes is Copyright Kevin Steves and comes from OpenSSH (misc.c). Both of these files are licensed under two-term BSD licenses too. strlcpy.c, strlcat.c and closefrom.c also come from OpenBSD CVS and are Copyright Todd C. Miller. Please refer to the LICENSE file for full details. Reporting Bugs -------------- Please report bugs in softflowd (https://github.com/irino/softflowd/) to https://github.com/irino/softflowd/issues Following descriptions are historical information: Please report bugs in softflowd to http://bugzilla.mindrot.org/ If you find a security bug, please report it directly by email. If you have any feedback or questions, please email me: Contributing ------------ Softflowd has an extensive TODO list of interesting features, large and small, that are waiting to be implemented. If you are interested in helping, please contact me. The latest source code may be obtained from Github: https://github.com/irino/softflowd/ (This repository was forked from http://code.google.com/p/softflowd/) Original creator: Damien Miller Current maintainer: Hitoshi Irino softflowd-softflowd-1.0.0/TODO000066400000000000000000000104241352553127000162200ustar00rootroot00000000000000Things yet to do: softflowd --------- - Use strtonum() Flow tracking engine - Calculate hash over flow and use it as a key to avoid lots of cache-trashing comparisons - Verify checksums (maybe. perhaps bad for accounting, good for flow tracking) - Fragment processing - We don't handle fragments right - This shouldn't be too hard or too memory intensive. We just need to keep a tree of fragment entries. Each entry would need to contain enough information to reconstruct the flow (source/dest addr, etc), but also fragment related info: IP id, list of fragment offsets. etc. - When we receive a new fragment, we add an entry to this tree (keyed by source IP, protocol, IP id) - Each new fragment matched in the tree gets its offset added to the list, until all fragments have been seen - Must be careful, as later fragments may arrive before inital one - When does accounting occur? - Upon receipt of inital fragment? (and thus for ever frag thereafter) - When we have seen all fragments? (what if we don't?) - Must limit size of tree - Must have fragment timeout (what happens then, apart from removal?) - Timeouts - Timeout for unanswered TCP connection - Ditto orphaned connections (one packet in one direction only) - Track ICMP generated by TCP/UDP session (painful, probably unecessary) - More datalink types - Improve fast-expiry of TCP session by tracking FIN sequence numbers - Multiple interface support - Requires some way to avoid duplicate recording of flows (IP ID) - Track IPsec SPIs - Track ToS / DSCP - Make counters 64 bits - We can report these directly for NetFlow v.9 - For older NetFlow, report by sending multiple flows until counter < 2^32 Misc features - Ability to open more than one interface (maybe) - Ability to read more than one pcap file (maybe) - Fork for ctlsock actions? (don't block mainloop) - Remote control over network (requires SSL) Performance - Profile and see where the hot spots are - Fast "new flow" test using a bloom filter - See if we can reduce per-packet overhead more - Cost of expiry remove and re-add per packet - Stop run-time malloc (maybe) - Preallocate a pool of expiry events and flow entries - keep a queue, pick/push first from head Exporter features - sflow support (www.sflow.org) - Needs XDR encoding - Ability to export to multiple hosts - Partly done, just need to keep a list of targets instead of a single one - Ability to directly write to file (maybe. If so, reuse flowd store code) - NetFlow v.9 field selection - Get AS numbers from bgpd and fill in to Netflow packets Statistics code - Collect more statistics (maybe) - Advanced packet analysis: store hash of packet payload, keep statistics on traffic similarity - Bloom filter? - Option to record histograms of - Flow lifetime and size, packet size - Flow bandwidth - Per well-known-port - How to do this quicky? Memory efficiently? - Per IP address/range - How to do this quicky? Memory efficiently? - Moving averages - Track traffic over lifetime of flow - Maintain linked list traffic counts, keyed by time interval - E.g. key by (now / 300) - Or (now - start_time) / 300 (better) - When new packet comes in: - If timestamp of HEAD of list == (now / xxx), then counter += octets - Otherwise create new traffic counter at HEAD and update it - Then trim tail if the list length is too big - Maybe store "hunks" of data, rather than individual counts in the list, as storing a single int is a huge waste of space - Maybe a rrdtool-like heirarchy of timespans - 300 seconds (5 minutes) (2400 bytes) - 360 1-minute blocks (6 hours) (2880 bytes) - 288 10-minute blocks (2 days) (2304 bytes) - 336 1-hour blocks (2 weeks) (2688 bytes) - Total 10kb worst-case per-flow (scary, probably overkill) softflowctl ----------- - Extend interface - Query for specific flows (e.g. by address) - Do this in softflowd or softflowctl? - Expire/delete specific flows (maybe) - Runtime respecify timeouts - Real-time binary dump of flowtable (shm/mmap fd pass?) - ntop like view - Spiffy GUI (separate tool) softflowd-softflowd-1.0.0/aclocal.m4000066400000000000000000001222431352553127000173730ustar00rootroot00000000000000# generated automatically by aclocal 1.15.1 -*- Autoconf -*- # Copyright (C) 1996-2017 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # Copyright (C) 2002-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.15' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.15.1], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.15.1])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each '.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC]) [_AM_PROG_CC_C_O ]) # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) fi fi dnl The trailing newline in this macro's definition is deliberate, for dnl backward compatibility and to allow trailing 'dnl'-style comments dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_CC_C_O # --------------- # Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC # to automatically call this. AC_DEFUN([_AM_PROG_CC_C_O], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl AC_LANG_PUSH([C])dnl AC_CACHE_CHECK( [whether $CC understands -c and -o together], [am_cv_prog_cc_c_o], [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i]) if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) # Copyright (C) 2001-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR softflowd-softflowd-1.0.0/closefrom.c000066400000000000000000000051621352553127000176700ustar00rootroot00000000000000/* * Copyright (c) 2004 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "common.h" #ifndef HAVE_CLOSEFROM #include #include #include #include #include #include #include #ifdef HAVE_DIRENT_H # include # define NAMLEN(dirent) strlen((dirent)->d_name) #else # define dirent direct # define NAMLEN(dirent) (dirent)->d_namlen # ifdef HAVE_SYS_NDIR_H # include # endif # ifdef HAVE_SYS_DIR_H # include # endif # ifdef HAVE_NDIR_H # include # endif #endif #ifndef OPEN_MAX # define OPEN_MAX 256 #endif #ifndef lint static const char rcsid[] = "$Sudo: closefrom.c,v 1.6 2004/06/01 20:51:56 millert Exp $"; #endif /* lint */ /* * Close all file descriptors greater than or equal to lowfd. */ void closefrom(int lowfd) { long fd, maxfd; #if defined(HAVE_DIRFD) && defined(HAVE_PROC_PID) char fdpath[PATH_MAX], *endp; struct dirent *dent; DIR *dirp; int len; /* Check for a /proc/$$/fd directory. */ len = snprintf(fdpath, sizeof(fdpath), "/proc/%ld/fd", (long)getpid()); if (len != -1 && len <= sizeof(fdpath) && (dirp = opendir(fdpath))) { while ((dent = readdir(dirp)) != NULL) { fd = strtol(dent->d_name, &endp, 10); if (dent->d_name != endp && *endp == '\0' && fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp)) (void) close((int) fd); } (void) closedir(dirp); } else #endif { /* * Fall back on sysconf() or getdtablesize(). We avoid checking * resource limits since it is possible to open a file descriptor * and then drop the rlimit such that it is below the open fd. */ #ifdef HAVE_SYSCONF maxfd = sysconf(_SC_OPEN_MAX); #else maxfd = getdtablesize(); #endif /* HAVE_SYSCONF */ if (maxfd < 0) maxfd = OPEN_MAX; for (fd = lowfd; fd < maxfd; fd++) (void) close((int) fd); } } #endif /* HAVE_CLOSEFROM */ softflowd-softflowd-1.0.0/collector.pl000077500000000000000000000151411352553127000200570ustar00rootroot00000000000000#!/usr/bin/perl -w # This is a Cisco NetFlow datagram collector # Netflow protocol reference: # http://www.cisco.com/en/US/products/sw/netmgtsw/ps1964/products_implementation_design_guide09186a00800d6a11.html # XXX Doesn't support NetFlow 9 my $af; BEGIN { use strict; use warnings; use IO qw(Socket); use Socket; use Carp; use POSIX qw(strftime); use Getopt::Long; eval "use IO::Socket::INET6;"; eval "use Socket6;"; } ############################################################################ sub timestamp() { return strftime "%Y-%m-%dT%H:%M:%S", localtime; } sub fuptime($) { my $t = shift; my $r = ""; my $tmp; # Milliseconds $tmp = $t % 1000; $r = sprintf ".%03u%s", $tmp, $r; # Seconds $t = int($t / 1000); $tmp = $t % 60; $r = "${tmp}s${r}"; # Minutes $t = int($t / 60); $tmp = $t % 60; $r = "${tmp}m${r}" if $tmp; # Hours $t = int($t / 60); $tmp = $t % 24; $r = "${tmp}h${r}" if $tmp; # Days $t = int($t / 24); $tmp = $t % 7; $r = "${tmp}d${r}" if $tmp; # Weeks $t = int($t / 7); $tmp = $t % 52; $r = "${tmp}w${r}" if $tmp; # Years $t = int($t / 52); $r = "${tmp}y${r}" if $tmp; return $r; } sub do_listen($$) { my $port = shift or confess "No UDP port specified"; my $socket; if ($af == 4) { $socket = IO::Socket::INET->new(Proto=>'udp', LocalPort=>$port) or croak "Couldn't open UDP socket: $!"; } elsif ($af == 6) { $socket = IO::Socket::INET6->new(Proto=>'udp', LocalPort=>$port) or croak "Couldn't open UDP socket: $!"; } else { croak "Unsupported AF"; } return $socket; } sub process_nf_v1($$) { my $sender = shift; my $pkt = shift; my %header; my %flow; my $sender_s; %header = qw(); $sender_s = inet_ntoa($sender) if $af == 4; $sender_s = inet_ntop(AF_INET6, $sender) if $af == 6; ($header{ver}, $header{flows}, $header{uptime}, $header{secs}, $header{nsecs}) = unpack("nnNNN", $pkt); if (length($pkt) < (16 + (48 * $header{flows}))) { printf STDERR timestamp()." Short Netflow v.1 packet: %d < %d\n", length($pkt), 16 + (48 * $header{flows}); return; } printf timestamp() . " HEADER v.%u (%u flow%s)\n", $header{ver}, $header{flows}, $header{flows} == 1 ? "" : "s"; for(my $i = 0; $i < $header{flows}; $i++) { my $off = 16 + (48 * $i); my $ptr = substr($pkt, $off, 52); %flow = qw(); (my $src1, my $src2, my $src3, my $src4, my $dst1, my $dst2, my $dst3, my $dst4, my $nxt1, my $nxt2, my $nxt3, my $nxt4, $flow{in_ndx}, $flow{out_ndx}, $flow{pkts}, $flow{bytes}, $flow{start}, $flow{finish}, $flow{src_port}, $flow{dst_port}, my $pad1, $flow{protocol}, $flow{tos}, $flow{tcp_flags}) = unpack("CCCCCCCCCCCCnnNNNNnnnCCC", $ptr); $flow{src} = sprintf "%u.%u.%u.%u", $src1, $src2, $src3, $src4; $flow{dst} = sprintf "%u.%u.%u.%u", $dst1, $dst2, $dst3, $dst4; $flow{nxt} = sprintf "%u.%u.%u.%u", $nxt1, $nxt2, $nxt3, $nxt4; printf timestamp() . " " . "from %s started %s finish %s proto %u %s:%u > %s:%u %u " . "packets %u octets\n", $sender_s, fuptime($flow{start}), fuptime($flow{finish}), $flow{protocol}, $flow{src}, $flow{src_port}, $flow{dst}, $flow{dst_port}, $flow{pkts}, $flow{bytes}; } } sub process_nf_v5($$) { my $sender = shift; my $pkt = shift; my %header; my %flow; my $sender_s; %header = qw(); $sender_s = inet_ntoa($sender) if $af == 4; $sender_s = inet_ntop(AF_INET6, $sender) if $af == 6; ($header{ver}, $header{flows}, $header{uptime}, $header{secs}, $header{nsecs}, $header{flow_seq}, ) = unpack("nnNNNN", $pkt); if (length($pkt) < (24 + (48 * $header{flows}))) { printf STDERR timestamp()." Short Netflow v.1 packet: %d < %d\n", length($pkt), 24 + (48 * $header{flows}); return; } printf timestamp() . " HEADER v.%u (%u flow%s) seq %u\n", $header{ver}, $header{flows}, $header{flows} == 1 ? "" : "s", $header{flow_seq}; for(my $i = 0; $i < $header{flows}; $i++) { my $off = 24 + (48 * $i); my $ptr = substr($pkt, $off, 52); %flow = qw(); (my $src1, my $src2, my $src3, my $src4, my $dst1, my $dst2, my $dst3, my $dst4, my $nxt1, my $nxt2, my $nxt3, my $nxt4, $flow{in_ndx}, $flow{out_ndx}, $flow{pkts}, $flow{bytes}, $flow{start}, $flow{finish}, $flow{src_port}, $flow{dst_port}, my $pad1, $flow{tcp_flags}, $flow{protocol}, $flow{tos}, $flow{src_as}, $flow{dst_as}, $flow{src_mask}, $flow{dst_mask}) = unpack("CCCCCCCCCCCCnnNNNNnnCCCCnnCC", $ptr); $flow{src} = sprintf "%u.%u.%u.%u", $src1, $src2, $src3, $src4; $flow{dst} = sprintf "%u.%u.%u.%u", $dst1, $dst2, $dst3, $dst4; $flow{nxt} = sprintf "%u.%u.%u.%u", $nxt1, $nxt2, $nxt3, $nxt4; printf timestamp() . " " . "from %s started %s finish %s proto %u %s:%u > %s:%u %u " . "packets %u octets\n", $sender_s, fuptime($flow{start}), fuptime($flow{finish}), $flow{protocol}, $flow{src}, $flow{src_port}, $flow{dst}, $flow{dst_port}, $flow{pkts}, $flow{bytes}; } } ############################################################################ # Commandline options my $debug = 0; my $af4 = 0; my $af6 = 0; my $port; # Long option Short option GetOptions( 'debug+' => \$debug, 'd+' => \$debug, '4+' => \$af4, '6+' => \$af6, 'port=i' => \$port, 'p=i' => \$port); # Unbuffer output $| = 1; die "The -4 and -6 are mutually exclusive\n" if $af4 && $af6; die "You must specify a port (collector.pl -p XXX).\n" unless $port; $af4 = $af = 4 if $af4 || (!$af4 && !$af6); $af6 = $af = 6 if $af6; # These modules aren't standard everywhere, so load them only if necessary # Main loop - receive and process a packet for (;;) { my $socket; my $from; my $payload; my $ver; my $failcount = 0; my $netflow; my $junk; my $sender; # Open the listening port if we haven't already $socket = do_listen($port, $af) unless defined $socket; # Fetch a packet $from = $socket->recv($payload, 8192, 0); ($junk, $sender) = unpack_sockaddr_in($from) if $af4; ($junk, $sender) = unpack_sockaddr_in6($from) if $af6; # Reopen listening socket on error if (!defined $from) { $socket->close; undef $socket; $failcount++; die "Couldn't recv: $!\n" if ($failcount > 5); next; # Socket will be reopened at start of loop } if (length($payload) < 16) { printf STDERR timestamp()." Short packet recevied: %d < 16\n", length($payload); next; } # The version is always the first 16 bits of the packet ($ver) = unpack("n", $payload); if ($ver == 1) { process_nf_v1($sender, $payload); } elsif ($ver == 5) { process_nf_v5($sender, $payload); } else { printf STDERR timestamp()." Unsupported netflow version %d\n", $ver; next; } undef $payload; next; } exit 0; softflowd-softflowd-1.0.0/common.h000066400000000000000000000130271352553127000171730ustar00rootroot00000000000000/* * Copyright (c) 2002 Damien Miller. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _SFD_COMMON_H #define _SFD_COMMON_H #include "config.h" #define _BSD_SOURCE /* Needed for BSD-style struct ip,tcp,udp on Linux */ #define _DEFAULT_SOURCE /* It is recommended to use instead of _BSD_SOURCE on Linux */ #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 #if defined(HAVE_NET_BPF_H) #include #elif defined(HAVE_PCAP_BPF_H) #include #endif #if defined(HAVE_INTTYPES_H) #include #endif #if defined(HAVE_SYS_ENDIAN_H) #include #elif defined(HAVE_ENDIAN_H) #include #endif /* The name of the program */ #define PROGNAME "softflowd" /* The name of the program */ #define PROGVER "1.0.0" /* Default pidfile */ #define DEFAULT_PIDFILE "/var/run/" PROGNAME ".pid" /* Default control socket */ #define DEFAULT_CTLSOCK "/var/run/" PROGNAME ".ctl" #define RCSID(msg) \ static /**/const char *const flowd_rcsid[] = \ { (const char *)flowd_rcsid, "\100(#)" msg } \ #ifndef IP_OFFMASK #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ #endif #ifndef IPV6_VERSION #define IPV6_VERSION 0x60 #endif #ifndef IPV6_VERSION_MASK #define IPV6_VERSION_MASK 0xf0 #endif #ifndef IPV6_FLOWINFO_MASK #define IPV6_FLOWINFO_MASK ntohl(0x0fffffff) #endif #ifndef IPV6_FLOWLABEL_MASK #define IPV6_FLOWLABEL_MASK ntohl(0x000fffff) #endif #ifndef _PATH_DEVNULL #define _PATH_DEVNULL "/dev/null" #endif #ifndef MIN #define MIN(a,b) (((a)<(b))?(a):(b)) #endif #ifndef MAX #define MAX(a,b) (((a)>(b))?(a):(b)) #endif #ifndef offsetof #define offsetof(type, member) ((size_t) &((type *)0)->member) #endif #if defined(__GNUC__) #ifndef __dead #define __dead __attribute__((__noreturn__)) #endif #ifndef __packed #define __packed __attribute__((__packed__)) #endif #endif #if !defined(HAVE_INT8_T) && defined(OUR_CFG_INT8_T) typedef OUR_CFG_INT8_T int8_t; #endif #if !defined(HAVE_INT16_T) && defined(OUR_CFG_INT16_T) typedef OUR_CFG_INT16_T int16_t; #endif #if !defined(HAVE_INT32_T) && defined(OUR_CFG_INT32_T) typedef OUR_CFG_INT32_T int32_t; #endif #if !defined(HAVE_INT64_T) && defined(OUR_CFG_INT64_T) typedef OUR_CFG_INT64_T int64_t; #endif #if !defined(HAVE_U_INT8_T) && defined(OUR_CFG_U_INT8_T) typedef OUR_CFG_U_INT8_T u_int8_t; #endif #if !defined(HAVE_U_INT16_T) && defined(OUR_CFG_U_INT16_T) typedef OUR_CFG_U_INT16_T u_int16_t; #endif #if !defined(HAVE_U_INT32_T) && defined(OUR_CFG_U_INT32_T) typedef OUR_CFG_U_INT32_T u_int32_t; #endif #if !defined(HAVE_U_INT64_T) && defined(OUR_CFG_U_INT64_T) typedef OUR_CFG_U_INT64_T u_int64_t; #endif #ifndef HAVE_STRLCPY size_t strlcpy (char *dst, const char *src, size_t siz); #endif #ifndef HAVE_STRLCAT size_t strlcat (char *dst, const char *src, size_t siz); #endif #ifndef HAVE_CLOSEFROM void closefrom (int lowfd); #endif #ifndef HAVE_STRUCT_IP6_EXT struct ip6_ext { u_int8_t ip6e_nxt; u_int8_t ip6e_len; } __packed; #endif /* following lines are copy from unistd.h in Linux for avoidance warnings in compilation */ #if defined(HAVE_SETRESGID) && !defined(_GNU_SOURCE) extern int setresgid (__uid_t __ruid, __uid_t __euid, __uid_t __suid); #endif #if defined(HAVE_SETRESUID) && !defined(_GNU_SOURCE) extern int setresuid (__uid_t __ruid, __uid_t __euid, __uid_t __suid); #endif #if defined (HAVE_DECL_HTONLL) && !defined (HAVE_DECL_HTOBE64) #define htobe64 htonll #endif #ifndef ETH_ALEN // https://cdn.kernel.org/pub/linux/kernel/people/marcelo/linux-2.4/include/linux/if_ether.h #define ETH_ALEN 6 /* Octets in one ethernet addr */ #endif /* ETH_ALEN */ #ifdef __APPLE__ #include #define htobe64(x) OSSwapHostToBigInt64(x) #endif /* __APPLE__ */ #endif /* _SFD_COMMON_H */ softflowd-softflowd-1.0.0/configure.ac000066400000000000000000000200471352553127000200200ustar00rootroot00000000000000# Copyright (c) 2004 Damien Miller # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_INIT([softflowd], [1.0.0]) AC_CONFIG_SRCDIR([softflowd.c]) AM_INIT_AUTOMAKE AC_CONFIG_HEADER(config.h) AC_PROG_CC AC_PROG_INSTALL # Optional verbose warnings for gcc, see below WFLAGS="-Wall -Waggregate-return -Wcast-align -Wcast-qual" WFLAGS="$WFLAGS -Wmissing-declarations -Wmissing-prototypes" WFLAGS="$WFLAGS -Wno-conversion -Wpointer-arith -Wshadow" WFLAGS="$WFLAGS -Wuninitialized -Wcast-align -Wcast-qual" WFLAGS="$WFLAGS -Wformat=2 -Wformat-nonliteral -Wwrite-strings" # Process flag arguments early, so they are available for tests later AC_ARG_ENABLE(gcc-warnings, [ --enable-gcc-warnings Enable verbose warnings (only for gcc)], [ if test "x$enableval" = "xyes" ; then CFLAGS="$CFLAGS $WFLAGS"; fi ] ) AC_ARG_ENABLE(legacy, AC_HELP_STRING([--enable-legacy], [enable legacy NetFlow implementation (default NO)]), [legacy=yes],[legacy=no]) AC_ARG_ENABLE(pthread, AC_HELP_STRING([--enable-pthread], [enable pthread (default NO) (experimental, unstable)]), [pthread=yes],[pthread=no]) AC_ARG_ENABLE(ntopng, AC_HELP_STRING([--enable-ntopng], [enable flow sending to ntopng with zeromq (default NO)]), [ntopng=yes],[ntopng=no]) AC_ARG_ENABLE(flow-spray, AC_HELP_STRING([--enable-flow-spray], [enable spray as flow tree type(default is RB)]), AC_DEFINE([FLOW_SPRAY], 1, [enable spray as flow tree type]), AC_DEFINE([FLOW_RB], 1, [enable RB(red-black) as flow tree type])) AC_ARG_ENABLE(expiry-spray, AC_HELP_STRING([--enable-expiry-spray], [enable spray as expiry tree type (default is RB)]), AC_DEFINE([EXPIRY_SPRAY], 1, [enable spray as flow tree type]), AC_DEFINE([EXPIRY_RB], 1, [enable RB(red-black) as flow tree type])) AC_ARG_WITH(cflags, [ --with-cflags Specify additional compiler flags], [ if test "x$withval" != "xno" ; then CFLAGS="$CFLAGS $withval"; fi ] ) AC_ARG_WITH(cppflags, [ --with-cppflags Specify additional preprocessor flags] , [ if test "x$withval" != "xno"; then CPPFLAGS="$CPPFLAGS $withval"; fi ] ) AC_ARG_WITH(ldflags, [ --with-ldflags Specify additional linker flags], [ if test "x$withval" != "xno" ; then LDFLAGS="$LDFLAGS $withval"; fi ] ) AC_ARG_WITH(libs, [ --with-libs Specify additional libraries to link with], [ if test "x$withval" != "xno" ; then LIBS="$LIBS $withval"; fi ] ) AC_ARG_WITH(chrootdir, [ --with-chrootdir Specify chroot directory], [ AC_DEFINE_UNQUOTED([PRIVDROP_CHROOT_DIR], ["${withval}"], [privdrop chroot directory]) ] ) AC_DEFINE([_BSD_SOURCE], [], [Define BSD SOURCE for Linux]) AC_CHECK_HEADERS(net/bpf.h pcap.h pcap-bpf.h sys/endian.h endian.h) dnl AC_CHECK_HEADERS(netinet/in_systm.h netinet/tcp.h netinet/udp.h) dnl dnl # This ugliness is because of autoconf's stupid default include list dnl AC_CHECK_HEADERS([netinet/ip.h], dnl [AC_DEFINE([HAVE_HAVE_NETINET_IP_H], 1, [has netinet/ip.h])], [], dnl [ dnl #include dnl #include dnl #if HAVE_NETINET_IN_SYSTM_H dnl #include dnl #endif dnl ]) AC_CHECK_MEMBER([struct sockaddr.sa_len], [AC_DEFINE([SOCK_HAS_LEN], 1, [struct sockaddr contains length])], , [#include #include ]) AC_CHECK_MEMBER(struct ip6_ext.ip6e_nxt, [AC_DEFINE([HAVE_STRUCT_IP6_EXT], 1, [struct ip6_ext.ip6e_nxt exists])], [], [ #include #include #include #include ]) AC_SEARCH_LIBS(daemon, bsd) AC_SEARCH_LIBS(gethostbyname, nsl) AC_SEARCH_LIBS(socket, socket) AC_CHECK_LIB(pcap, pcap_open_live) AC_CHECK_FUNCS(closefrom daemon setresuid setreuid setresgid setgid strlcpy strlcat strsep) AC_CHECK_DECLS([htobe64, htonll]) AC_CHECK_TYPES([u_int64_t, int64_t, uint64_t, u_int32_t, int32_t, uint32_t]) AC_CHECK_TYPES([u_int16_t, int16_t, uint16_t, u_int8_t, int8_t, uint8_t]) AC_CHECK_SIZEOF(char, 1) AC_CHECK_SIZEOF(short int, 2) AC_CHECK_SIZEOF(int, 4) AC_CHECK_SIZEOF(long int, 4) AC_CHECK_SIZEOF(long long int, 8) if test "x$legacy" = "xyes" ; then AC_DEFINE([ENABLE_LEGACY], 1, [enable legacy NetFlow implementation]) LEGACY='netflow9.$(OBJEXT) netflow1.$(OBJEXT)' AC_SUBST([LEGACY]) fi AM_CONDITIONAL([ENABLE_LEGACY], [test x$legacy = xyes]) if test "x$pthread" = "xyes" ; then AC_DEFINE([ENABLE_PTHREAD], 1, [enable pthread]) AC_CHECK_LIB(pthread, pthread_create, [],[AC_MSG_ERROR([pthread.h not found])]) AC_CHECK_HEADERS(pthread.h, [],[AC_MSG_ERROR([pthread.h not found])]) fi if test "x$ntopng" = "xyes" ; then AC_DEFINE([ENABLE_NTOPNG], 1, [enable ntopng]) AC_CHECK_LIB(zmq, zmq_connect, [],[AC_MSG_ERROR([libzmq not found])]) AC_CHECK_HEADERS(zmq.h, [],[AC_MSG_ERROR([zmq.h not found])]) NTOPNG='ntopng.$(OBJEXT)' AC_SUBST([NTOPNG]) fi AM_CONDITIONAL([ENABLE_NTOPNG], [test x$ntopng = xyes]) if test "x$ac_cv_type_uint8_t" = "xyes" ; then AC_DEFINE([OUR_CFG_U_INT8_T], [uint8_t], [8-bit unsigned int]) elif test "x$ac_cv_sizeof_char" = "x1" ; then AC_DEFINE([OUR_CFG_U_INT8_T], [unsigned char], [8-bit unsigned int]) else AC_MSG_ERROR([No 8-bit unsigned int type found]) fi if test "x$ac_cv_sizeof_char" = "x1" ; then AC_DEFINE([OUR_CFG_INT8_T], [signed char], [8-bit signed int]) else AC_MSG_ERROR([No 8-bit signed int type found]) fi if test "x$ac_cv_type_uint16_t" = "xyes" ; then AC_DEFINE([OUR_CFG_U_INT16_T], [uint16_t], [16-bit unsigned int]) elif test "x$ac_cv_sizeof_short_int" = "x2" ; then AC_DEFINE([OUR_CFG_U_INT16_T], [unsigned short int], [16-bit unsigned int]) else AC_MSG_ERROR([No 16-bit unsigned int type found]) fi if test "x$ac_cv_sizeof_short_int" = "x2" ; then AC_DEFINE([OUR_CFG_INT16_T], [short int], [16-bit signed int]) else AC_MSG_ERROR([No 16-bit signed int type found]) fi if test "x$ac_cv_type_uint32_t" = "xyes" ; then AC_DEFINE([OUR_CFG_U_INT32_T], [uint32_t], [32-bit unsigned int]) elif test "x$ac_cv_sizeof_int" = "x4" ; then AC_DEFINE([OUR_CFG_U_INT32_T], [unsigned int], [32-bit unsigned int]) else AC_MSG_ERROR([No 32-bit unsigned int type found]) fi if test "x$ac_cv_sizeof_int" = "x4" ; then AC_DEFINE([OUR_CFG_INT32_T], [int], [32-bit signed int]) else AC_MSG_ERROR([No 32-bit signed int type found]) fi if test "x$ac_cv_type_uint64_t" = "xyes" ; then AC_DEFINE([OUR_CFG_U_INT64_T], [uint64_t], [64-bit unsigned int]) elif test "x$ac_cv_sizeof_long_int" = "x8" ; then AC_DEFINE([OUR_CFG_U_INT64_T], [unsigned long int], [64-bit unsigned int]) elif test "x$ac_cv_sizeof_long_long_int" = "x8" ; then AC_DEFINE([OUR_CFG_U_INT64_T], [unsigned long long int], [64-bit unsigned int]) else AC_MSG_ERROR([No 64-bit unsigned int type found]) fi if test "x$ac_cv_sizeof_long_int" = "x8" ; then AC_DEFINE([OUR_CFG_INT64_T], [long int], [64-bit signed int]) elif test "x$ac_cv_sizeof_long_long_int" = "x8" ; then AC_DEFINE([OUR_CFG_INT64_T], [long long int], [64-bit signed int]) else AC_MSG_ERROR([No 64-bit signed int type found]) fi if test "x$ac_cv_header_pcap_bpf_h" != "xyes" && \ test "x$ac_cv_header_net_bpf_h" != "xyes" ; then AC_MSG_ERROR([No BPF header found]) fi if test "x$ac_cv_header_pcap_h" != "xyes" ; then AC_MSG_ERROR([No pcap.h header found]) fi if test "x$ac_cv_lib_pcap_pcap_open_live" != "xyes" ; then AC_MSG_ERROR([libpcap not found]) fi AC_EXEEXT AC_CONFIG_FILES([Makefile]) AC_OUTPUT softflowd-softflowd-1.0.0/convtime.c000066400000000000000000000042511352553127000175210ustar00rootroot00000000000000/* * Copyright (c) 2001 Kevin Steves. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "common.h" #include "convtime.h" #define SECONDS 1 #define MINUTES (SECONDS * 60) #define HOURS (MINUTES * 60) #define DAYS (HOURS * 24) #define WEEKS (DAYS * 7) long int convtime(const char *s) { long total, secs; const char *p; char *endp; errno = 0; total = 0; p = s; if (p == NULL || *p == '\0') return -1; while (*p) { secs = strtol(p, &endp, 10); if (p == endp || (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) || secs < 0) return -1; switch (*endp++) { case '\0': endp--; case 's': case 'S': break; case 'm': case 'M': secs *= MINUTES; break; case 'h': case 'H': secs *= HOURS; break; case 'd': case 'D': secs *= DAYS; break; case 'w': case 'W': secs *= WEEKS; break; default: return -1; } total += secs; if (total < 0) return -1; p = endp; } return total; } softflowd-softflowd-1.0.0/convtime.h000066400000000000000000000034501352553127000175260ustar00rootroot00000000000000/* * Copyright (c) 2001 Kevin Steves. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _SFD_CONVTIME_H /* * Convert a time string into seconds; format is * a sequence of: * time[qualifier] * * Valid time qualifiers are: * seconds * s|S seconds * m|M minutes * h|H hours * d|D days * w|W weeks * * Examples: * 90m 90 minutes * 1h30m 90 minutes * 2d 2 days * 1w 1 week * * Return -1 if time string is invalid. */ long int convtime(const char *s); #endif /* _SFD_CONVTIME_H */ softflowd-softflowd-1.0.0/daemon.c000066400000000000000000000047251352553127000171460ustar00rootroot00000000000000/* OPENBSD ORIGINAL: lib/libc/gen/daemon.c */ /*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "common.h" #ifndef HAVE_DAEMON #if defined(LIBC_SCCS) && !defined(lint) static char rcsid[] = "$OpenBSD: daemon.c,v 1.5 2003/07/15 17:32:41 deraadt Exp $"; #endif /* LIBC_SCCS and not lint */ int daemon(int nochdir, int noclose) { int fd; switch (fork()) { case -1: return (-1); case 0: #ifdef HAVE_CYGWIN register_9x_service(); #endif break; default: #ifdef HAVE_CYGWIN /* * This sleep avoids a race condition which kills the * child process if parent is started by a NT/W2K service. */ sleep(1); #endif _exit(0); } if (setsid() == -1) return (-1); if (!nochdir) (void)chdir("/"); if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { (void)dup2(fd, STDIN_FILENO); (void)dup2(fd, STDOUT_FILENO); (void)dup2(fd, STDERR_FILENO); if (fd > 2) (void)close (fd); } return (0); } #endif /* !HAVE_DAEMON */ softflowd-softflowd-1.0.0/freelist.c000066400000000000000000000115321352553127000175120ustar00rootroot00000000000000/* * Copyright (c) 2007 Damien Miller. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "common.h" #include "freelist.h" #include "log.h" #define FREELIST_MAX_ALLOC 0x1000000 #define FREELIST_ALLOC_ALIGN 16 #define FREELIST_INITIAL_ALLOC 16 #ifndef roundup #define roundup(x, y) ((((x) + (y) - 1)/(y))*(y)) #endif /* roundup */ #undef FREELIST_DEBUG #ifdef FREELIST_DEBUG # define FLOGIT(a) logit a #else # define FLOGIT(a) #endif void freelist_init(struct freelist *fl, size_t allocsz) { size_t sizeof_fl = sizeof(fl); FLOGIT((LOG_DEBUG, "%s: %s(%p, %zu)", __func__, __func__, fl, allocsz)); bzero(fl, sizeof_fl); fl->allocsz = roundup(allocsz, FREELIST_ALLOC_ALIGN); fl->free_entries = NULL; } static int freelist_grow(struct freelist *fl) { size_t i, oldnalloc, need; void *p; FLOGIT((LOG_DEBUG, "%s: %s(%p)", __func__, __func__, fl)); FLOGIT((LOG_DEBUG, "%s: nalloc = %zu", __func__, fl->nalloc)); /* Sanity check */ if (fl->nalloc > FREELIST_MAX_ALLOC) return -1; oldnalloc = fl->nalloc; if (fl->nalloc == 0) fl->nalloc = FREELIST_INITIAL_ALLOC; else fl->nalloc <<= 1; if (fl->nalloc > FREELIST_MAX_ALLOC) fl->nalloc = FREELIST_MAX_ALLOC; FLOGIT((LOG_DEBUG, "%s: nalloc now %zu", __func__, fl->nalloc)); /* Check for integer overflow */ if (SIZE_MAX / fl->nalloc < fl->allocsz || SIZE_MAX / fl->nalloc < sizeof(*fl->free_entries)) { FLOGIT((LOG_DEBUG, "%s: integer overflow", __func__)); resize_fail: fl->nalloc = oldnalloc; return -1; } /* Allocate freelist - max size of nalloc */ need = fl->nalloc * sizeof(*fl->free_entries); if ((p = realloc(fl->free_entries, need)) == NULL) { FLOGIT((LOG_DEBUG, "%s: realloc(%zu) failed", __func__, need)); goto resize_fail; } /* Allocate the entries */ fl->free_entries = p; need = (fl->nalloc - oldnalloc) * fl->allocsz; if ((p = malloc(need)) == NULL) { FLOGIT((LOG_DEBUG, "%s: malloc(%zu) failed", __func__, need)); goto resize_fail; } /* * XXX store these malloc ranges in a tree or list, so we can * validate them in _get/_put. Check that r_low <= addr < r_high, and * (addr - r_low) % fl->allocsz == 0 */ fl->navail = fl->nalloc - oldnalloc; for (i = 0; i < fl->navail; i++) fl->free_entries[i] = (u_char *)p + (i * fl->allocsz); for (i = fl->navail; i < fl->nalloc; i++) fl->free_entries[i] = NULL; FLOGIT((LOG_DEBUG, "%s: done, navail = %zu", __func__, fl->navail)); return 0; } void * freelist_get(struct freelist *fl) { void *r; FLOGIT((LOG_DEBUG, "%s: %s(%p)", __func__, __func__, fl)); FLOGIT((LOG_DEBUG, "%s: navail = %zu", __func__, fl->navail)); if (fl->navail == 0) { if (freelist_grow(fl) == -1) return NULL; } /* Sanity check */ if (fl->navail == 0 || fl->navail > FREELIST_MAX_ALLOC || fl->free_entries[fl->navail - 1] == NULL) { logit(LOG_ERR, "%s: invalid navail", __func__); raise(SIGSEGV); } fl->navail--; r = fl->free_entries[fl->navail]; fl->free_entries[fl->navail] = NULL; FLOGIT((LOG_DEBUG, "%s: done, navail = %zu", __func__, fl->navail)); return r; } void freelist_put(struct freelist *fl, void *p) { FLOGIT((LOG_DEBUG, "%s: %s(%p, %zu)", __func__, __func__, fl, p)); FLOGIT((LOG_DEBUG, "%s: navail = %zu", __func__, fl->navail)); FLOGIT((LOG_DEBUG, "%s: nalloc = %zu", __func__, fl->navail)); /* Sanity check */ if (fl->navail >= fl->nalloc) { logit(LOG_ERR, "%s: freelist navail >= nalloc", __func__); raise(SIGSEGV); } if (fl->free_entries[fl->navail] != NULL) { logit(LOG_ERR, "%s: free_entries[%lu] != NULL", __func__, (unsigned long)fl->navail); raise(SIGSEGV); } fl->free_entries[fl->navail] = p; fl->navail++; FLOGIT((LOG_DEBUG, "%s: done, navail = %zu", __func__, fl->navail)); } softflowd-softflowd-1.0.0/freelist.h000066400000000000000000000037741352553127000175300ustar00rootroot00000000000000/* * Copyright (c) 2007 Damien Miller. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _FREELIST_H #define _FREELIST_H #include "common.h" /* Simple freelist of fixed-sized allocations */ struct freelist { size_t allocsz; size_t nalloc; size_t navail; void **free_entries; }; /* * Initialise a freelist. * allocsz is the size of the individual allocations */ void freelist_init(struct freelist *freelist, size_t allocsz); /* * Get an entry from a freelist. * Will allocate new entries if necessary * Returns pointer to allocated memory or NULL on failure. */ void *freelist_get(struct freelist *freelist); /* * Returns an entry to the freelist. * p must be a pointer to an allocation from the freelist. */ void freelist_put(struct freelist *freelist, void *p); #endif /* FREELIST_H */ softflowd-softflowd-1.0.0/install-sh000077500000000000000000000354631352553127000175460ustar00rootroot00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2014-09-12.12; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. tab=' ' nl=' ' IFS=" $tab$nl" # Set DOITPROG to "echo" to test this script. doit=${DOITPROG-} doit_exec=${doit:-exec} # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false is_target_a_directory=possibly usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) is_target_a_directory=always dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) is_target_a_directory=never;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done # We allow the use of options -d and -T together, by making -d # take the precedence; this is for compatibility with GNU install. if test -n "$dir_arg"; then if test -n "$dst_arg"; then echo "$0: target directory not allowed when installing a directory." >&2 exit 1 fi fi if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then if test $# -gt 1 || test "$is_target_a_directory" = always; then if test ! -d "$dst_arg"; then echo "$0: $dst_arg: Is not a directory." >&2 exit 1 fi fi fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test "$is_target_a_directory" = never; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) # $RANDOM is not portable (e.g. dash); use it when possible to # lower collision chance tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0 # As "mkdir -p" follows symlinks and we work in /tmp possibly; so # create the $tmpdir first (and fail if unsuccessful) to make sure # that nobody tries to guess the $tmpdir name. if (umask $mkdir_umask && $mkdirprog $mkdir_mode "$tmpdir" && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. test_tmpdir="$tmpdir/a" ls_ld_tmpdir=`ls -ld "$test_tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac oIFS=$IFS IFS=/ set -f set fnord $dstdir shift set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: softflowd-softflowd-1.0.0/ipfix.c000066400000000000000000001040201352553127000170070ustar00rootroot00000000000000/* * Copyright 2002 Damien Miller All rights reserved. * Copyright 2012 Hitoshi Irino All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "common.h" #include "log.h" #include "treetype.h" #include "softflowd.h" #include "netflow9.h" #include "ipfix.h" #include "psamp.h" const struct IPFIX_FIELD_SPECIFIER field_v4[] = { {IPFIX_sourceIPv4Address, 4}, {IPFIX_destinationIPv4Address, 4} }; const struct IPFIX_FIELD_SPECIFIER field_v6[] = { {IPFIX_sourceIPv6Address, 16}, {IPFIX_destinationIPv6Address, 16} }; const struct IPFIX_FIELD_SPECIFIER field_common[] = { {IPFIX_octetDeltaCount, 4}, {IPFIX_packetDeltaCount, 4}, {IPFIX_ingressInterface, 4}, {IPFIX_egressInterface, 4} }; const struct IPFIX_FIELD_SPECIFIER field_transport[] = { {IPFIX_sourceTransportPort, 2}, {IPFIX_destinationTransportPort, 2}, {IPFIX_protocolIdentifier, 1}, {IPFIX_tcpControlBits, 1}, {IPFIX_ipVersion, 1}, {IPFIX_ipClassOfService, 1} }; const struct IPFIX_FIELD_SPECIFIER field_icmp4[] = { {IPFIX_icmpTypeCodeIPv4, 2}, {IPFIX_ipVersion, 1}, {IPFIX_ipClassOfService, 1} }; const struct IPFIX_FIELD_SPECIFIER field_icmp6[] = { {IPFIX_icmpTypeCodeIPv6, 2}, {IPFIX_ipVersion, 1}, {IPFIX_ipClassOfService, 1} }; const struct IPFIX_FIELD_SPECIFIER field_vlan[] = { {IPFIX_vlanId, 2}, {IPFIX_postVlanId, 2} }; const struct IPFIX_FIELD_SPECIFIER field_ether[] = { {IPFIX_sourceMacAddress, 6}, {IPFIX_postDestinationMacAddress, 6} }; const struct IPFIX_FIELD_SPECIFIER field_timesec[] = { {IPFIX_flowStartSeconds, 4}, {IPFIX_flowEndSeconds, 4} }; const struct IPFIX_FIELD_SPECIFIER field_timemsec[] = { {IPFIX_flowStartMilliSeconds, 8}, {IPFIX_flowEndMilliSeconds, 8} }; const struct IPFIX_FIELD_SPECIFIER field_timeusec[] = { {IPFIX_flowStartMicroSeconds, 8}, {IPFIX_flowEndMicroSeconds, 8} }; const struct IPFIX_FIELD_SPECIFIER field_timensec[] = { {IPFIX_flowStartNanoSeconds, 8}, {IPFIX_flowEndNanoSeconds, 8} }; const struct IPFIX_FIELD_SPECIFIER field_timesysup[] = { {IPFIX_flowStartSysUpTime, 4}, {IPFIX_flowEndSysUpTime, 4} }; const struct IPFIX_FIELD_SPECIFIER field_bicommon[] = { {IPFIX_octetDeltaCount, 4}, {IPFIX_packetDeltaCount, 4}, {IPFIX_ipClassOfService, 1} }; const struct IPFIX_FIELD_SPECIFIER field_bitransport[] = { {IPFIX_tcpControlBits, 1} }; const struct IPFIX_FIELD_SPECIFIER field_biicmp4[] = { {IPFIX_icmpTypeCodeIPv4, 2} }; const struct IPFIX_FIELD_SPECIFIER field_biicmp6[] = { {IPFIX_icmpTypeCodeIPv6, 2} }; const struct IPFIX_FIELD_SPECIFIER field_scope[] = { {IPFIX_meteringProcessId, 4} }; const struct IPFIX_FIELD_SPECIFIER field_option[] = { {IPFIX_systemInitTimeMilliseconds, 8}, {PSAMP_samplingPacketInterval, 4}, {PSAMP_samplingPacketSpace, 4}, {PSAMP_selectorAlgorithm, 2} }; const struct IPFIX_FIELD_SPECIFIER field_nf9scope[] = { {NFLOW9_OPTION_SCOPE_INTERFACE, 4} }; const struct IPFIX_FIELD_SPECIFIER field_nf9option[] = { {NFLOW9_SAMPLING_INTERVAL, 4}, {NFLOW9_SAMPLING_ALGORITHM, 1} }; /* Stuff pertaining to the templates that softflowd uses */ #define IPFIX_SOFTFLOWD_TEMPLATE_IPRECORDS \ sizeof(field_v4) / sizeof(struct IPFIX_FIELD_SPECIFIER) #define IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS \ sizeof(field_timesysup) / sizeof(struct IPFIX_FIELD_SPECIFIER) #define IPFIX_SOFTFLOWD_TEMPLATE_COMMONRECORDS \ sizeof(field_common) / sizeof(struct IPFIX_FIELD_SPECIFIER) #define IPFIX_SOFTFLOWD_TEMPLATE_TRANSPORTRECORDS \ sizeof(field_transport) / sizeof(struct IPFIX_FIELD_SPECIFIER) #define IPFIX_SOFTFLOWD_TEMPLATE_ICMPRECORDS \ sizeof(field_icmp4) / sizeof(struct IPFIX_FIELD_SPECIFIER) #define IPFIX_SOFTFLOWD_TEMPLATE_VLANRECORDS \ sizeof(field_vlan) / sizeof(struct IPFIX_FIELD_SPECIFIER) #define IPFIX_SOFTFLOWD_TEMPLATE_ETHERRECORDS \ sizeof(field_ether) / sizeof(struct IPFIX_FIELD_SPECIFIER) #define IPFIX_SOFTFLOWD_TEMPLATE_BICOMMONRECORDS \ sizeof(field_bicommon) / sizeof(struct IPFIX_FIELD_SPECIFIER) #define IPFIX_SOFTFLOWD_TEMPLATE_BITRANSPORTRECORDS \ sizeof(field_bitransport) / sizeof(struct IPFIX_FIELD_SPECIFIER) #define IPFIX_SOFTFLOWD_TEMPLATE_BIICMPRECORDS \ sizeof(field_biicmp4) / sizeof(struct IPFIX_FIELD_SPECIFIER) #define IPFIX_SOFTFLOWD_TEMPLATE_NRECORDS \ IPFIX_SOFTFLOWD_TEMPLATE_IPRECORDS + \ IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS + \ IPFIX_SOFTFLOWD_TEMPLATE_COMMONRECORDS + \ IPFIX_SOFTFLOWD_TEMPLATE_TRANSPORTRECORDS + \ IPFIX_SOFTFLOWD_TEMPLATE_VLANRECORDS + \ IPFIX_SOFTFLOWD_TEMPLATE_ETHERRECORDS #define IPFIX_SOFTFLOWD_TEMPLATE_BI_NRECORDS \ IPFIX_SOFTFLOWD_TEMPLATE_BICOMMONRECORDS + \ IPFIX_SOFTFLOWD_TEMPLATE_BITRANSPORTRECORDS struct IPFIX_SOFTFLOWD_TEMPLATE { struct IPFIX_TEMPLATE_SET_HEADER h; struct IPFIX_FIELD_SPECIFIER r[IPFIX_SOFTFLOWD_TEMPLATE_NRECORDS]; struct IPFIX_VENDOR_FIELD_SPECIFIER v[IPFIX_SOFTFLOWD_TEMPLATE_BI_NRECORDS]; u_int16_t data_len, bi_count; } __packed; #define IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS \ sizeof(field_scope) / sizeof(struct IPFIX_FIELD_SPECIFIER) #define IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS \ sizeof(field_option) / sizeof(struct IPFIX_FIELD_SPECIFIER) #define NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS \ sizeof(field_nf9scope) / sizeof(struct IPFIX_FIELD_SPECIFIER) #define NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS \ sizeof(field_nf9option) / sizeof(struct IPFIX_FIELD_SPECIFIER) struct IPFIX_SOFTFLOWD_OPTION_TEMPLATE { struct IPFIX_OPTION_TEMPLATE_SET_HEADER h; struct IPFIX_FIELD_SPECIFIER s[IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS]; struct IPFIX_FIELD_SPECIFIER r[IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS]; } __packed; /* softflowd data set */ struct IPFIX_SOFTFLOWD_DATA_COMMON { u_int32_t octetDeltaCount, packetDeltaCount; u_int32_t ingressInterface, egressInterface; } __packed; struct IPFIX_SOFTFLOWD_DATA_TRANSPORT { u_int16_t sourceTransportPort, destinationTransportPort; u_int8_t protocolIdentifier, tcpControlBits, ipVersion, ipClassOfService; } __packed; struct IPFIX_SOFTFLOWD_DATA_ICMP { u_int16_t icmpTypeCode; u_int8_t ipVersion, ipClassOfService; } __packed; struct IPFIX_SOFTFLOWD_DATA_VLAN { u_int16_t vlanId, postVlanId; } __packed; struct IPFIX_SOFTFLOWD_DATA_ETHER { u_int8_t sourceMacAddress[6], destinationMacAddress[6]; } __packed; struct IPFIX_SOFTFLOWD_DATA_BICOMMON { u_int32_t octetDeltaCount, packetDeltaCount; u_int8_t ipClassOfService; } __packed; struct IPFIX_SOFTFLOWD_DATA_BITRANSPORT { u_int8_t tcpControlBits; } __packed; struct IPFIX_SOFTFLOWD_DATA_BIICMP { u_int16_t icmpTypeCode; } __packed; union IPFIX_SOFTFLOWD_DATA_TIME { struct { u_int32_t start; u_int32_t end; } u32; struct { u_int64_t start; u_int64_t end; } u64; }; struct IPFIX_SOFTFLOWD_DATA_V4ADDR { u_int32_t sourceIPv4Address, destinationIPv4Address; } __packed; struct IPFIX_SOFTFLOWD_DATA_V6ADDR { struct in6_addr sourceIPv6Address, destinationIPv6Address; } __packed; struct IPFIX_SOFTFLOWD_OPTION_DATA { struct IPFIX_SET_HEADER c; u_int32_t scope_pid; u_int64_t systemInitTimeMilliseconds; u_int32_t samplingInterval; u_int32_t samplingSpace; u_int16_t samplingAlgorithm; } __packed; struct NFLOW9_SOFTFLOWD_OPTION_DATA { struct IPFIX_SET_HEADER c; u_int32_t scope_ifidx; u_int32_t samplingInterval; u_int8_t samplingAlgorithm; } __packed; /* Local data: templates and counters */ #define IPFIX_SOFTFLOWD_MAX_PACKET_SIZE 1428 #define IPFIX_SOFTFLOWD_V4_TEMPLATE_ID 1024 #define IPFIX_SOFTFLOWD_ICMPV4_TEMPLATE_ID 1025 #define IPFIX_SOFTFLOWD_V6_TEMPLATE_ID 2048 #define IPFIX_SOFTFLOWD_ICMPV6_TEMPLATE_ID 2049 #define IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID 256 #define IPFIX_DEFAULT_TEMPLATE_INTERVAL 16 /* ... */ #define IPFIX_OPTION_SCOPE_SYSTEM 1 #define IPFIX_OPTION_SCOPE_INTERFACE 2 #define IPFIX_OPTION_SCOPE_LINECARD 3 #define IPFIX_OPTION_SCOPE_CACHE 4 #define IPFIX_OPTION_SCOPE_TEMPLATE 5 /* ... */ #define IPFIX_SAMPLING_ALGORITHM_DETERMINISTIC 1 #define IPFIX_SAMPLING_ALGORITHM_RANDOM 2 /* ... */ // prototype void memcpy_template (u_char * packet, u_int * offset, struct IPFIX_SOFTFLOWD_TEMPLATE *template, u_int8_t bi_flag); // variables enum { TMPLV4, TMPLICMPV4, TMPLV6, TMPLICMPV6, TMPLMAX }; static struct IPFIX_SOFTFLOWD_TEMPLATE templates[TMPLMAX]; static struct IPFIX_SOFTFLOWD_OPTION_TEMPLATE option_template; static struct IPFIX_SOFTFLOWD_OPTION_DATA option_data; static struct NFLOW9_SOFTFLOWD_OPTION_DATA nf9opt_data; static int ipfix_pkts_until_template = -1; int ipfix_init_fields (struct IPFIX_FIELD_SPECIFIER *dst, u_int * index, const struct IPFIX_FIELD_SPECIFIER *src, u_int field_number) { int i, length = 0; for (i = 0; i < field_number; i++) { dst[*index + i].ie = htons (src[i].ie); dst[*index + i].length = htons (src[i].length); length += src[i].length; } *index += field_number; return length; } void conv_unix_to_ntp (struct timeval tv, struct ntp_time_t *ntp) { if (ntp != NULL) { ntp->second = tv.tv_sec + 0x83AA7E80; ntp->fraction = (uint32_t) ((double) (tv.tv_usec + 1) * (double) (1LL << 32) * 1.0e-6); } } struct timeval conv_ntp_to_unix (struct ntp_time_t ntp) { struct timeval tv = { ntp.second - 0x83AA7E80, // the seconds from Jan 1, 1900 to Jan 1, 1970 (uint32_t) ((double) ntp.fraction * 1.0e6 / (double) (1LL << 32)) }; return tv; } static int ipfix_init_bifields (struct IPFIX_SOFTFLOWD_TEMPLATE *template, u_int * index, const struct IPFIX_FIELD_SPECIFIER *fields, u_int field_number) { int i, length = 0; for (i = 0; i < field_number; i++) { template->v[*index + i].ie = htons (fields[i].ie | 0x8000); template->v[*index + i].length = htons (fields[i].length); template->v[*index + i].pen = htonl (REVERSE_PEN); length += fields[i].length; } *index += field_number; return length; } static int ipfix_init_template_time (struct FLOWTRACKPARAMETERS *param, struct IPFIX_SOFTFLOWD_TEMPLATE *template, u_int * index) { int length = 0; if (param->time_format == 's') { length = ipfix_init_fields (template->r, index, field_timesec, IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS); } else if (param->time_format == 'm') { length = ipfix_init_fields (template->r, index, field_timemsec, IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS); } else if (param->time_format == 'M') { length = ipfix_init_fields (template->r, index, field_timeusec, IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS); } else if (param->time_format == 'n') { length = ipfix_init_fields (template->r, index, field_timensec, IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS); } else { length = ipfix_init_fields (template->r, index, field_timesysup, IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS); } return length; } static void ipfix_init_template_unity (struct FLOWTRACKPARAMETERS *param, struct IPFIX_SOFTFLOWD_TEMPLATE *template, u_int template_id, u_int8_t v6_flag, u_int8_t icmp_flag, u_int8_t bi_flag, u_int16_t version) { u_int index = 0, bi_index = 0, length = 0; bzero (template, sizeof (*template)); template->h.c.set_id = htons (version == 10 ? IPFIX_TEMPLATE_SET_ID : NFLOW9_TEMPLATE_SET_ID); template->h.r.template_id = htons (template_id); if (v6_flag) { length += ipfix_init_fields (template->r, &index, field_v6, IPFIX_SOFTFLOWD_TEMPLATE_IPRECORDS); } else { length += ipfix_init_fields (template->r, &index, field_v4, IPFIX_SOFTFLOWD_TEMPLATE_IPRECORDS); } length += ipfix_init_template_time (param, template, &index); length += ipfix_init_fields (template->r, &index, field_common, IPFIX_SOFTFLOWD_TEMPLATE_COMMONRECORDS); if (icmp_flag) { if (v6_flag) { length += ipfix_init_fields (template->r, &index, field_icmp6, IPFIX_SOFTFLOWD_TEMPLATE_ICMPRECORDS); } else { length += ipfix_init_fields (template->r, &index, field_icmp4, IPFIX_SOFTFLOWD_TEMPLATE_ICMPRECORDS); } } else { length += ipfix_init_fields (template->r, &index, field_transport, IPFIX_SOFTFLOWD_TEMPLATE_TRANSPORTRECORDS); } if (param->track_level >= TRACK_FULL_VLAN) { length += ipfix_init_fields (template->r, &index, field_vlan, IPFIX_SOFTFLOWD_TEMPLATE_VLANRECORDS); } if (param->track_level >= TRACK_FULL_VLAN_ETHER) { length += ipfix_init_fields (template->r, &index, field_ether, IPFIX_SOFTFLOWD_TEMPLATE_ETHERRECORDS); } if (bi_flag) { length += ipfix_init_bifields (template, &bi_index, field_bicommon, IPFIX_SOFTFLOWD_TEMPLATE_BICOMMONRECORDS); if (icmp_flag) { if (v6_flag) { length += ipfix_init_bifields (template, &bi_index, field_biicmp6, IPFIX_SOFTFLOWD_TEMPLATE_BIICMPRECORDS); } else { length += ipfix_init_bifields (template, &bi_index, field_biicmp4, IPFIX_SOFTFLOWD_TEMPLATE_BIICMPRECORDS); } } else { length += ipfix_init_bifields (template, &bi_index, field_bitransport, IPFIX_SOFTFLOWD_TEMPLATE_BITRANSPORTRECORDS); } } template->bi_count = bi_index; template->h.r.count = htons (index + bi_index); template->h.c.length = htons (sizeof (struct IPFIX_TEMPLATE_SET_HEADER) + index * sizeof (struct IPFIX_FIELD_SPECIFIER) + bi_index * sizeof (struct IPFIX_VENDOR_FIELD_SPECIFIER)); template->data_len = length; } static void ipfix_init_template (struct FLOWTRACKPARAMETERS *param, u_int8_t bi_flag, u_int16_t version) { u_int8_t v6_flag = 0, icmp_flag = 0; u_int16_t template_id = 0; int i = 0; for (i = 0; i < TMPLMAX; i++) { switch (i) { case TMPLV4: v6_flag = 0; icmp_flag = 0; template_id = IPFIX_SOFTFLOWD_V4_TEMPLATE_ID; break; case TMPLICMPV4: v6_flag = 0; icmp_flag = 1; template_id = IPFIX_SOFTFLOWD_ICMPV4_TEMPLATE_ID; break; case TMPLV6: v6_flag = 1; icmp_flag = 0; template_id = IPFIX_SOFTFLOWD_V6_TEMPLATE_ID; break; case TMPLICMPV6: v6_flag = 1; icmp_flag = 1; template_id = IPFIX_SOFTFLOWD_ICMPV6_TEMPLATE_ID; break; } ipfix_init_template_unity (param, &templates[i], template_id, v6_flag, icmp_flag, bi_flag, version); } } static void nflow9_init_option (u_int16_t ifidx, struct OPTION *option) { u_int scope_index = 0, option_index = 0; u_int16_t scope_len = NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS * sizeof (struct IPFIX_FIELD_SPECIFIER); u_int16_t opt_len = NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS * sizeof (struct IPFIX_FIELD_SPECIFIER); bzero (&option_template, sizeof (option_template)); option_template.h.c.set_id = htons (NFLOW9_OPTION_TEMPLATE_SET_ID); option_template.h.c.length = htons (sizeof (option_template.h) + scope_len + opt_len); option_template.h.u.n.template_id = htons (IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID); option_template.h.u.n.scope_length = htons (scope_len); option_template.h.u.n.option_length = htons (opt_len); ipfix_init_fields (option_template.s, &scope_index, field_nf9scope, NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS); ipfix_init_fields (option_template.r, &option_index, field_nf9option, NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS); bzero (&nf9opt_data, sizeof (nf9opt_data)); nf9opt_data.c.set_id = htons (IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID); nf9opt_data.c.length = htons (sizeof (nf9opt_data)); nf9opt_data.scope_ifidx = htonl (ifidx); nf9opt_data.samplingInterval = htonl (option->sample > 1 ? option->sample : 1); nf9opt_data.samplingAlgorithm = NFLOW9_SAMPLING_ALGORITHM_DETERMINISTIC; } static void ipfix_init_option (struct timeval *system_boot_time, struct OPTION *option) { u_int scope_index = 0, option_index = 0; bzero (&option_template, sizeof (option_template)); option_template.h.c.set_id = htons (IPFIX_OPTION_TEMPLATE_SET_ID); option_template.h.c.length = htons (sizeof (option_template)); option_template.h.u.i.r.template_id = htons (IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID); option_template.h.u.i.r.count = htons (IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS + IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS); option_template.h.u.i.scope_count = htons (IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS); ipfix_init_fields (option_template.s, &scope_index, field_scope, IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS); ipfix_init_fields (option_template.r, &option_index, field_option, IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS); bzero (&option_data, sizeof (option_data)); option_data.c.set_id = htons (IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID); option_data.c.length = htons (sizeof (option_data)); option_data.scope_pid = htonl ((u_int32_t) option->meteringProcessId); #if defined(htobe64) || defined(HAVE_DECL_HTOBE64) option_data.systemInitTimeMilliseconds = htobe64 ((u_int64_t) system_boot_time->tv_sec * 1000 + (u_int64_t) system_boot_time->tv_usec / 1000); #endif option_data.samplingAlgorithm = htons (PSAMP_selectorAlgorithm_count); option_data.samplingInterval = htonl (1); option_data.samplingSpace = htonl (option->sample > 0 ? option->sample - 1 : 0); } static int copy_data_time (union IPFIX_SOFTFLOWD_DATA_TIME *dt, const struct FLOW *flow, const struct timeval *system_boot_time, struct FLOWTRACKPARAMETERS *param) { int length = (param->time_format == 'm' || param->time_format == 'M' || param->time_format == 'n') ? 16 : 8; if (dt == NULL) return -1; switch (param->time_format) { struct ntp_time_t ntptime; case 's': dt->u32.start = htonl (flow->flow_start.tv_sec); dt->u32.end = htonl (flow->flow_last.tv_sec); break; #if defined(htobe64) || defined(HAVE_DECL_HTOBE64) case 'm': dt->u64.start = htobe64 ((u_int64_t) flow->flow_start.tv_sec * 1000 + (u_int64_t) flow->flow_start.tv_usec / 1000); dt->u64.end = htobe64 ((u_int64_t) flow->flow_last.tv_sec * 1000 + (u_int64_t) flow->flow_last.tv_usec / 1000); break; case 'M': case 'n': conv_unix_to_ntp ((struct timeval) flow->flow_start, &ntptime); dt->u64.start = htobe64 ((u_int64_t) ntptime.second << 32 | ntptime.fraction); conv_unix_to_ntp ((struct timeval) flow->flow_last, &ntptime); dt->u64.end = htobe64 ((u_int64_t) ntptime.second << 32 | ntptime.fraction); break; #endif default: dt->u32.start = htonl (timeval_sub_ms (&flow->flow_start, system_boot_time)); dt->u32.end = htonl (timeval_sub_ms (&flow->flow_last, system_boot_time)); break; } return length; } static u_int ipfix_flow_to_template_index (const struct FLOW *flow) { u_int index = 0; if (flow->af == AF_INET) { index = (flow->protocol == IPPROTO_ICMP) ? TMPLICMPV4 : TMPLV4; } else if (flow->af == AF_INET6) { index = (flow->protocol == IPPROTO_ICMPV6) ? TMPLICMPV6 : TMPLV6; } return index; } static int ipfix_flow_to_flowset (const struct FLOW *flow, u_char * packet, u_int len, u_int16_t ifidx, const struct timeval *system_boot_time, u_int * len_used, struct FLOWTRACKPARAMETERS *param, u_int8_t bi_flag) { struct IPFIX_SOFTFLOWD_DATA_V4ADDR *d4[2] = { NULL, NULL }; struct IPFIX_SOFTFLOWD_DATA_V6ADDR *d6[2] = { NULL, NULL }; union IPFIX_SOFTFLOWD_DATA_TIME *dt[2] = { NULL, NULL }; struct IPFIX_SOFTFLOWD_DATA_COMMON *dc[2] = { NULL, NULL }; struct IPFIX_SOFTFLOWD_DATA_TRANSPORT *dtr[2] = { NULL, NULL }; struct IPFIX_SOFTFLOWD_DATA_ICMP *di[2] = { NULL, NULL }; struct IPFIX_SOFTFLOWD_DATA_VLAN *dv[2] = { NULL, NULL }; struct IPFIX_SOFTFLOWD_DATA_ETHER *de[2] = { NULL, NULL }; struct IPFIX_SOFTFLOWD_DATA_BICOMMON *dbc = NULL; struct IPFIX_SOFTFLOWD_DATA_BITRANSPORT *dbtr = NULL; struct IPFIX_SOFTFLOWD_DATA_BIICMP *dbi = NULL; u_int freclen = 0, nflows = 0, offset = 0; u_int frecnum = bi_flag ? 1 : 2; u_int tmplindex = ipfix_flow_to_template_index (flow); int i = 0; freclen = templates[tmplindex].data_len; if (len < freclen * frecnum) return (-1); for (i = 0; i < frecnum; i++) { if (bi_flag == 0 && flow->octets[i] == 0) continue; nflows++; if (flow->af == AF_INET) { d4[i] = (struct IPFIX_SOFTFLOWD_DATA_V4ADDR *) &packet[offset]; memcpy (&d4[i]->sourceIPv4Address, &flow->addr[i].v4, 4); memcpy (&d4[i]->destinationIPv4Address, &flow->addr[i ^ 1].v4, 4); offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_V4ADDR); } else if (flow->af == AF_INET6) { d6[i] = (struct IPFIX_SOFTFLOWD_DATA_V6ADDR *) &packet[offset]; memcpy (&d6[i]->sourceIPv6Address, &flow->addr[i].v6, 16); memcpy (&d6[i]->destinationIPv6Address, &flow->addr[i ^ 1].v6, 16); offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_V6ADDR); } dt[i] = (union IPFIX_SOFTFLOWD_DATA_TIME *) &packet[offset]; offset += copy_data_time (dt[i], flow, system_boot_time, param); dc[i] = (struct IPFIX_SOFTFLOWD_DATA_COMMON *) &packet[offset]; dc[i]->octetDeltaCount = htonl (flow->octets[i]); dc[i]->packetDeltaCount = htonl (flow->packets[i]); dc[i]->ingressInterface = dc[i]->egressInterface = htonl (ifidx); offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_COMMON); if (flow->protocol != IPPROTO_ICMP && flow->protocol != IPPROTO_ICMPV6) { dtr[i] = (struct IPFIX_SOFTFLOWD_DATA_TRANSPORT *) &packet[offset]; dtr[i]->sourceTransportPort = flow->port[i]; dtr[i]->destinationTransportPort = flow->port[i ^ 1]; dtr[i]->protocolIdentifier = flow->protocol; dtr[i]->tcpControlBits = flow->tcp_flags[i]; dtr[i]->ipClassOfService = flow->tos[i]; dtr[i]->ipVersion = (flow->af == AF_INET) ? 4 : 6; offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_TRANSPORT); } else { di[i] = (struct IPFIX_SOFTFLOWD_DATA_ICMP *) &packet[offset]; di[i]->icmpTypeCode = flow->port[i ^ 1]; di[i]->ipClassOfService = flow->tos[i]; di[i]->ipVersion = (flow->af == AF_INET) ? 4 : 6; offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_ICMP); } if (param->track_level >= TRACK_FULL_VLAN) { dv[i] = (struct IPFIX_SOFTFLOWD_DATA_VLAN *) &packet[offset]; dv[i]->vlanId = flow->vlanid[i]; dv[i]->postVlanId = flow->vlanid[i ^ 1]; offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_VLAN); } if (param->track_level >= TRACK_FULL_VLAN_ETHER) { de[i] = (struct IPFIX_SOFTFLOWD_DATA_ETHER *) &packet[offset]; memcpy (&de[i]->sourceMacAddress, &flow->ethermac[i], 6); memcpy (&de[i]->destinationMacAddress, &flow->ethermac[i ^ 1], 6); offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_ETHER); } if (bi_flag && i == 0) { dbc = (struct IPFIX_SOFTFLOWD_DATA_BICOMMON *) &packet[offset]; dbc->octetDeltaCount = htonl (flow->octets[1]); dbc->packetDeltaCount = htonl (flow->packets[1]); dbc->ipClassOfService = flow->tos[1]; offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_BICOMMON); if (flow->protocol != IPPROTO_ICMP && flow->protocol != IPPROTO_ICMPV6) { dbtr = (struct IPFIX_SOFTFLOWD_DATA_BITRANSPORT *) &packet[offset]; dbtr->tcpControlBits = flow->tcp_flags[1]; offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_BITRANSPORT); } else { dbi = (struct IPFIX_SOFTFLOWD_DATA_BIICMP *) &packet[offset]; dbi->icmpTypeCode = flow->port[1]; offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_BIICMP); } } } *len_used = offset; return (nflows); } static int valuate_icmp (struct FLOW *flow) { if (flow == NULL) return -1; if (flow->af == AF_INET) if (flow->protocol == IPPROTO_ICMP) return 1; else return 0; else if (flow->af == AF_INET6) if (flow->protocol == IPPROTO_ICMPV6) return 1; else return 0; else return -1; return -1; } void ipfix_resend_template (void) { if (ipfix_pkts_until_template > 0) ipfix_pkts_until_template = 0; } void memcpy_template (u_char * packet, u_int * offset, struct IPFIX_SOFTFLOWD_TEMPLATE *template, u_int8_t bi_flag) { int size = ntohs (template->h.c.length) - template->bi_count * sizeof (struct IPFIX_VENDOR_FIELD_SPECIFIER); memcpy (packet + *offset, template, size); *offset += size; if (bi_flag) { size = template->bi_count * sizeof (struct IPFIX_VENDOR_FIELD_SPECIFIER); memcpy (packet + *offset, template->v, size); *offset += size; } } /* * Given an array of expired flows, send ipfix report packets * Returns number of packets sent or -1 on error */ static int send_ipfix_common (struct FLOW **flows, int num_flows, struct NETFLOW_TARGET *target, u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param, int verbose_flag, u_int8_t bi_flag, u_int16_t version) { struct IPFIX_HEADER *ipfix; struct NFLOW9_HEADER *nf9; struct IPFIX_SET_HEADER *dh; struct timeval now; u_int offset, last_af, i, j, num_packets, inc, last_valid, tmplindex; int8_t icmp_flag, last_icmp_flag; int r; u_int records; u_char packet[IPFIX_SOFTFLOWD_MAX_PACKET_SIZE]; struct timeval *system_boot_time = ¶m->system_boot_time; u_int64_t *flows_exported = ¶m->flows_exported; u_int64_t *records_sent = ¶m->records_sent; struct OPTION *option = ¶m->option; if (version != 9 && version != 10) return (-1); if (param->adjust_time) now = param->last_packet_time; else gettimeofday (&now, NULL); if (ipfix_pkts_until_template == -1) { ipfix_init_template (param, bi_flag, version); ipfix_pkts_until_template = 0; if (option != NULL) { if (version == 10) { ipfix_init_option (system_boot_time, option); } else { nflow9_init_option (ifidx, option); } } } last_valid = num_packets = 0; for (j = 0; j < num_flows;) { bzero (packet, sizeof (packet)); if (version == 10) { ipfix = (struct IPFIX_HEADER *) packet; ipfix->version = htons (version); ipfix->length = 0; /* Filled as we go, htons at end */ if (param->adjust_time) ipfix->export_time = htonl (now.tv_sec); else ipfix->export_time = htonl (time (NULL)); ipfix->od_id = 0; offset = sizeof (*ipfix); } else if (version == 9) { nf9 = (struct NFLOW9_HEADER *) packet; nf9->version = htons (version); nf9->flows = 0; /* Filled as we go, htons at end */ nf9->uptime_ms = htonl (timeval_sub_ms (&now, system_boot_time)); if (param->adjust_time) nf9->export_time = htonl (now.tv_sec); else nf9->export_time = htonl (time (NULL)); nf9->od_id = 0; offset = sizeof (*nf9); } /* Refresh template headers if we need to */ if (ipfix_pkts_until_template <= 0) { for (i = 0; i < TMPLMAX; i++) { memcpy_template (packet, &offset, &templates[i], bi_flag); } if (option != NULL) { u_int16_t opt_tmpl_len = ntohs (option_template.h.c.length); memcpy (packet + offset, &option_template, opt_tmpl_len); offset += opt_tmpl_len; if (version == 10) { memcpy (packet + offset, &option_data, sizeof (option_data)); offset += sizeof (option_data); } else if (version == 9) { memcpy (packet + offset, &nf9opt_data, sizeof (nf9opt_data)); offset += sizeof (nf9opt_data); } } ipfix_pkts_until_template = IPFIX_DEFAULT_TEMPLATE_INTERVAL; if (target->is_loadbalance && target->num_destinations > 1) { ipfix->length = htons (offset); if (version == 10) { ipfix->sequence = htonl ((u_int32_t) (*records_sent & 0x00000000ffffffff)); } else if (version == 9) { nf9->sequence = htonl ((u_int32_t) (*records_sent & 0x00000000ffffffff)); } if (send_multi_destinations (target->num_destinations, target->destinations, 0, packet, offset) < 0) return (-1); offset = version == 10 ? sizeof (*ipfix) : sizeof (*nf9); // resest offset } } dh = NULL; last_af = 0; last_icmp_flag = -1; records = 0; for (i = 0; i + j < num_flows; i++) { icmp_flag = valuate_icmp (flows[i + j]); if (dh == NULL || flows[i + j]->af != last_af || icmp_flag != last_icmp_flag) { if (dh != NULL) { if (offset % 4 != 0) { /* Pad to multiple of 4 */ dh->length += 4 - (offset % 4); offset += 4 - (offset % 4); } /* Finalise last header */ dh->length = htons (dh->length); } if (offset + sizeof (*dh) > sizeof (packet)) { /* Mark header is finished */ dh = NULL; break; } dh = (struct IPFIX_SET_HEADER *) (packet + offset); tmplindex = ipfix_flow_to_template_index (flows[i + j]); dh->set_id = templates[tmplindex].h.r.template_id; last_af = flows[i + j]->af; last_icmp_flag = icmp_flag; last_valid = offset; dh->length = sizeof (*dh); /* Filled as we go */ offset += sizeof (*dh); } r = ipfix_flow_to_flowset (flows[i + j], packet + offset, sizeof (packet) - offset, ifidx, system_boot_time, &inc, param, bi_flag); if (r <= 0) { /* yank off data header, if we had to go back */ if (last_valid) offset = last_valid; break; } records += (u_int) r; offset += inc; dh->length += inc; last_valid = 0; /* Don't clobber this header now */ if (verbose_flag) { logit (LOG_DEBUG, "Flow %d/%d: " "r %d offset %d ie %04x len %d(0x%04x)", r, i, j, offset, dh->set_id, dh->length, dh->length); } } /* Don't finish header if it has already been done */ if (dh != NULL) { if (offset % 4 != 0) { /* Pad to multiple of 4 */ dh->length += 4 - (offset % 4); offset += 4 - (offset % 4); } /* Finalise last header */ dh->length = htons (dh->length); } ipfix->length = htons (offset); *records_sent += records; if (version == 10) { ipfix->sequence = htonl ((u_int32_t) (*records_sent & 0x00000000ffffffff)); } else if (version == 9) { nf9->sequence = htonl ((u_int32_t) (*records_sent & 0x00000000ffffffff)); } if (verbose_flag) logit (LOG_DEBUG, "Sending flow packet len = %d", offset); if (send_multi_destinations (target->num_destinations, target->destinations, target->is_loadbalance, packet, offset) < 0) return (-1); num_packets++; ipfix_pkts_until_template--; j += i; } *flows_exported += j; param->packets_sent += num_packets; #ifdef ENABLE_PTHREAD if (use_thread) free (flows); #endif /* ENABLE_PTHREAD */ return (num_packets); } int send_nflow9 (struct SENDPARAMETER sp) { return send_ipfix_common (sp.flows, sp.num_flows, sp.target, sp.ifidx, sp.param, sp.verbose_flag, 0, 9); } int send_ipfix (struct SENDPARAMETER sp) { return send_ipfix_common (sp.flows, sp.num_flows, sp.target, sp.ifidx, sp.param, sp.verbose_flag, 0, 10); } int send_ipfix_bi (struct SENDPARAMETER sp) { return send_ipfix_common (sp.flows, sp.num_flows, sp.target, sp.ifidx, sp.param, sp.verbose_flag, 1, 10); } softflowd-softflowd-1.0.0/ipfix.h000066400000000000000000000111751352553127000170240ustar00rootroot00000000000000/* * Copyright 2019 Hitoshi Irino All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _IPFIX_H #define _IPFIX_H #include "softflowd.h" #define IPFIX_TEMPLATE_SET_ID 2 #define IPFIX_OPTION_TEMPLATE_SET_ID 3 #define IPFIX_MIN_RECORD_SET_ID 256 /* Flowset record ies the we care about */ #define IPFIX_octetDeltaCount 1 #define IPFIX_packetDeltaCount 2 /* ... */ #define IPFIX_protocolIdentifier 4 #define IPFIX_ipClassOfService 5 /* ... */ #define IPFIX_tcpControlBits 6 #define IPFIX_sourceTransportPort 7 #define IPFIX_sourceIPv4Address 8 /* ... */ #define IPFIX_ingressInterface 10 #define IPFIX_destinationTransportPort 11 #define IPFIX_destinationIPv4Address 12 /* ... */ #define IPFIX_egressInterface 14 /* ... */ #define IPFIX_flowEndSysUpTime 21 #define IPFIX_flowStartSysUpTime 22 /* ... */ #define IPFIX_sourceIPv6Address 27 #define IPFIX_destinationIPv6Address 28 /* ... */ #define IPFIX_icmpTypeCodeIPv4 32 /* ... */ #define IPFIX_sourceMacAddress 56 #define IPFIX_postDestinationMacAddress 57 #define IPFIX_vlanId 58 #define IPFIX_postVlanId 59 #define IPFIX_ipVersion 60 /* ... */ #define IPFIX_icmpTypeCodeIPv6 139 /* ... */ #define IPFIX_meteringProcessId 143 /* ... */ #define IPFIX_flowStartSeconds 150 #define IPFIX_flowEndSeconds 151 #define IPFIX_flowStartMilliSeconds 152 #define IPFIX_flowEndMilliSeconds 153 #define IPFIX_flowStartMicroSeconds 154 #define IPFIX_flowEndMicroSeconds 155 #define IPFIX_flowStartNanoSeconds 156 #define IPFIX_flowEndNanoSeconds 157 /* ... */ #define IPFIX_systemInitTimeMilliseconds 160 /* ... */ #define IPFIX_SOFTFLOWD_MAX_PACKET_SIZE 1428 struct IPFIX_HEADER { u_int16_t version, length; u_int32_t export_time; /* in seconds */ u_int32_t sequence, od_id; } __packed; struct IPFIX_SET_HEADER { u_int16_t set_id, length; } __packed; struct IPFIX_TEMPLATE_RECORD_HEADER { u_int16_t template_id, count; } __packed; struct IPFIX_TEMPLATE_SET_HEADER { struct IPFIX_SET_HEADER c; struct IPFIX_TEMPLATE_RECORD_HEADER r; } __packed; struct IPFIX_FIELD_SPECIFIER { u_int16_t ie, length; } __packed; struct IPFIX_OPTION_TEMPLATE_SET_HEADER { struct IPFIX_SET_HEADER c; union { struct { struct IPFIX_TEMPLATE_RECORD_HEADER r; u_int16_t scope_count; } i; struct { u_int16_t template_id; u_int16_t scope_length; u_int16_t option_length; } n; } u; } __packed; struct IPFIX_VENDOR_FIELD_SPECIFIER { u_int16_t ie, length; u_int32_t pen; } __packed; #define REVERSE_PEN 29305 struct ntp_time_t { uint32_t second; uint32_t fraction; }; /* Prototypes for functions to send NetFlow packets */ int send_nflow9 (struct SENDPARAMETER sp); int send_ipfix (struct SENDPARAMETER sp); int send_ipfix_bi (struct SENDPARAMETER sp); /* Force a resend of the flow template */ void ipfix_resend_template (void); int ipfix_init_fields (struct IPFIX_FIELD_SPECIFIER *dst, u_int * index, const struct IPFIX_FIELD_SPECIFIER *src, u_int field_number); void conv_unix_to_ntp (struct timeval tv, struct ntp_time_t *ntp); struct timeval conv_ntp_to_unix (struct ntp_time_t ntp); #endif /* _IPFIX_H */ softflowd-softflowd-1.0.0/log.c000066400000000000000000000033521352553127000164570ustar00rootroot00000000000000/* * Copyright 2004 Damien Miller All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "common.h" #include "log.h" #include static int logstderr = 0; void loginit(const char *ident, int to_stderr) { if (to_stderr) logstderr = 1; else openlog(PROGNAME, LOG_PID|LOG_NDELAY, LOG_DAEMON); } void logit(int level, const char *fmt,...) { va_list args; va_start(args, fmt); if (logstderr) { vfprintf(stderr, fmt, args); fputs("\n", stderr); } else vsyslog(level, fmt, args); va_end(args); } softflowd-softflowd-1.0.0/log.h000066400000000000000000000027011352553127000164610ustar00rootroot00000000000000/* * Copyright 2004 Damien Miller All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _LOG_H #define _LOG_H void loginit(const char *ident, int to_stderr); void logit(int level, const char *fmt,...); #endif /* _LOG_H */ softflowd-softflowd-1.0.0/mkinstalldirs000077500000000000000000000067221352553127000203440ustar00rootroot00000000000000#! /bin/sh # mkinstalldirs --- make directory hierarchy scriptversion=2009-04-28.21; # UTC # Original author: Noah Friedman # Created: 1993-05-16 # Public domain. # # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' IFS=" "" $nl" errstatus=0 dirmode= usage="\ Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... Create each directory DIR (with mode MODE, if specified), including all leading file name components. Report bugs to ." # process command line arguments while test $# -gt 0 ; do case $1 in -h | --help | --h*) # -h for help echo "$usage" exit $? ;; -m) # -m PERM arg shift test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } dirmode=$1 shift ;; --version) echo "$0 $scriptversion" exit $? ;; --) # stop option processing shift break ;; -*) # unknown option echo "$usage" 1>&2 exit 1 ;; *) # first non-opt arg break ;; esac done for file do if test -d "$file"; then shift else break fi done case $# in 0) exit 0 ;; esac # Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and # mkdir -p a/c at the same time, both will detect that a is missing, # one will create a, then the other will try to create a and die with # a "File exists" error. This is a problem when calling mkinstalldirs # from a parallel make. We use --version in the probe to restrict # ourselves to GNU mkdir, which is thread-safe. case $dirmode in '') if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then echo "mkdir -p -- $*" exec mkdir -p -- "$@" else # On NextStep and OpenStep, the 'mkdir' command does not # recognize any option. It will interpret all options as # directories to create, and then abort because '.' already # exists. test -d ./-p && rmdir ./-p test -d ./--version && rmdir ./--version fi ;; *) if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 && test ! -d ./--version; then echo "mkdir -m $dirmode -p -- $*" exec mkdir -m "$dirmode" -p -- "$@" else # Clean up after NextStep and OpenStep mkdir. for d in ./-m ./-p ./--version "./$dirmode"; do test -d $d && rmdir $d done fi ;; esac for file do case $file in /*) pathcomp=/ ;; *) pathcomp= ;; esac oIFS=$IFS IFS=/ set fnord $file shift IFS=$oIFS for d do test "x$d" = x && continue pathcomp=$pathcomp$d case $pathcomp in -*) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" mkdir "$pathcomp" || lasterr=$? if test ! -d "$pathcomp"; then errstatus=$lasterr else if test ! -z "$dirmode"; then echo "chmod $dirmode $pathcomp" lasterr= chmod "$dirmode" "$pathcomp" || lasterr=$? if test ! -z "$lasterr"; then errstatus=$lasterr fi fi fi fi pathcomp=$pathcomp/ done done exit $errstatus # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: softflowd-softflowd-1.0.0/netflow1.c000066400000000000000000000143261352553127000174400ustar00rootroot00000000000000 /* * Copyright 2002 Damien Miller All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "common.h" #include "log.h" #include "treetype.h" #include "softflowd.h" #ifdef ENABLE_LEGACY /* * This is the Cisco Netflow(tm) version 1 packet format * Based on: * http://www.cisco.com/en/US/products/sw/netmgtsw/ps1964/products_implementation_design_guide09186a00800d6a11.html */ struct NF1_HEADER { u_int16_t version, flows; u_int32_t uptime_ms, time_sec, time_nanosec; }; struct NF1_FLOW { u_int32_t src_ip, dest_ip, nexthop_ip; u_int16_t if_index_in, if_index_out; u_int32_t flow_packets, flow_octets; u_int32_t flow_start, flow_finish; u_int16_t src_port, dest_port; u_int16_t pad1; u_int8_t protocol, tos, tcp_flags; u_int8_t pad2, pad3, pad4; u_int32_t reserved1; #if 0 u_int8_t reserved2; /* XXX: no longer used */ #endif }; /* Maximum of 24 flows per packet */ #define NF1_MAXFLOWS 24 #define NF1_MAXPACKET_SIZE (sizeof(struct NF1_HEADER) + \ (NF1_MAXFLOWS * sizeof(struct NF1_FLOW))) /* * Given an array of expired flows, send netflow v1 report packets * Returns number of packets sent or -1 on error */ int send_netflow_v1 (struct SENDPARAMETER sp) { struct FLOW **flows = sp.flows; int num_flows = sp.num_flows; u_int16_t ifidx = sp.ifidx; struct FLOWTRACKPARAMETERS *param = sp.param; int verbose_flag = sp.verbose_flag; struct timeval now; u_int32_t uptime_ms; u_int8_t packet[NF1_MAXPACKET_SIZE]; /* Maximum allowed packet size (24 flows) */ struct NF1_HEADER *hdr = NULL; struct NF1_FLOW *flw = NULL; int i, j, offset, num_packets; struct timeval *system_boot_time = ¶m->system_boot_time; u_int64_t *flows_exported = ¶m->flows_exported; if (param->adjust_time) now = param->last_packet_time; else gettimeofday (&now, NULL); uptime_ms = timeval_sub_ms (&now, system_boot_time); hdr = (struct NF1_HEADER *) packet; for (num_packets = offset = j = i = 0; i < num_flows; i++) { if (j >= NF1_MAXFLOWS - 1) { if (verbose_flag) logit (LOG_DEBUG, "Sending flow packet len = %d", offset); param->records_sent += hdr->flows; hdr->flows = htons (hdr->flows); if (send_multi_destinations (sp.target->num_destinations, sp.target->destinations, sp.target->is_loadbalance, packet, offset) < 0) return (-1); *flows_exported += j; j = 0; num_packets++; } if (j == 0) { memset (&packet, '\0', sizeof (packet)); hdr->version = htons (1); hdr->flows = 0; /* Filled in as we go */ hdr->uptime_ms = htonl (uptime_ms); hdr->time_sec = htonl (now.tv_sec); hdr->time_nanosec = htonl (now.tv_usec * 1000); offset = sizeof (*hdr); } flw = (struct NF1_FLOW *) (packet + offset); flw->if_index_in = flw->if_index_out = htons (ifidx); /* NetFlow v.1 doesn't do IPv6 */ if (flows[i]->af != AF_INET) continue; if (flows[i]->octets[0] > 0) { flw->src_ip = flows[i]->addr[0].v4.s_addr; flw->dest_ip = flows[i]->addr[1].v4.s_addr; flw->src_port = flows[i]->port[0]; flw->dest_port = flows[i]->port[1]; flw->flow_packets = htonl (flows[i]->packets[0]); flw->flow_octets = htonl (flows[i]->octets[0]); flw->flow_start = htonl (timeval_sub_ms (&flows[i]->flow_start, system_boot_time)); flw->flow_finish = htonl (timeval_sub_ms (&flows[i]->flow_last, system_boot_time)); flw->protocol = flows[i]->protocol; flw->tcp_flags = flows[i]->tcp_flags[0]; flw->tos = flows[i]->tos[0]; offset += sizeof (*flw); j++; hdr->flows++; } flw = (struct NF1_FLOW *) (packet + offset); flw->if_index_in = flw->if_index_out = htons (ifidx); if (flows[i]->octets[1] > 0) { flw->src_ip = flows[i]->addr[1].v4.s_addr; flw->dest_ip = flows[i]->addr[0].v4.s_addr; flw->src_port = flows[i]->port[1]; flw->dest_port = flows[i]->port[0]; flw->flow_packets = htonl (flows[i]->packets[1]); flw->flow_octets = htonl (flows[i]->octets[1]); flw->flow_start = htonl (timeval_sub_ms (&flows[i]->flow_start, system_boot_time)); flw->flow_finish = htonl (timeval_sub_ms (&flows[i]->flow_last, system_boot_time)); flw->protocol = flows[i]->protocol; flw->tcp_flags = flows[i]->tcp_flags[1]; flw->tos = flows[i]->tos[1]; offset += sizeof (*flw); j++; hdr->flows++; } } /* Send any leftovers */ if (j != 0) { if (verbose_flag) logit (LOG_DEBUG, "Sending flow packet len = %d", offset); param->records_sent += hdr->flows; hdr->flows = htons (hdr->flows); if (send_multi_destinations (sp.target->num_destinations, sp.target->destinations, sp.target->is_loadbalance, packet, offset) < 0) return (-1); num_packets++; } *flows_exported += j; param->packets_sent += num_packets; #ifdef ENABLE_PTHREAD if (use_thread) free (sp.flows); #endif /* ENABLE_PTHREAD */ return (num_packets); } #endif /* ENABLE_LEGACY */ softflowd-softflowd-1.0.0/netflow5.c000066400000000000000000000204701352553127000174410ustar00rootroot00000000000000/* * Copyright 2002 Damien Miller All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "common.h" #include "log.h" #include "treetype.h" #include "softflowd.h" /* * This is the Cisco Netflow(tm) version 5 packet format * Based on: * http://www.cisco.com/en/US/products/sw/netmgtsw/ps1964/products_implementation_design_guide09186a00800d6a11.html * https://www.cisco.com/c/en/us/td/docs/net_mgmt/netflow_collection_engine/3-6/user/guide/format.html#wp1007472 */ struct NF5_HEADER { u_int16_t version, flows; // same as netflow v1 u_int32_t uptime_ms, time_sec, time_nanosec; // same as netflow v1 u_int32_t flow_sequence; u_int8_t engine_type, engine_id; u_int16_t sampling_interval; }; struct NF5_FLOW { u_int32_t src_ip, dest_ip, nexthop_ip; // same as netflow v1 u_int16_t if_index_in, if_index_out; // same as netflow v1 u_int32_t flow_packets, flow_octets; // same as netflow v1 u_int32_t flow_start, flow_finish; // same as netflow v1 u_int16_t src_port, dest_port; // same as netflow v1 u_int8_t pad1; u_int8_t tcp_flags, protocol, tos; u_int16_t src_as, dest_as; u_int8_t src_mask, dst_mask; u_int16_t pad2; }; struct NF1_FLOW_PROTO_TOS_TCPF { u_int16_t pad1; u_int8_t protocol, tos, tcp_flags; u_int8_t pad2, pad3, pad4; u_int32_t reserved1; }; #define NF5_MAXFLOWS 30 #define NF5_MAXPACKET_SIZE (sizeof(struct NF5_HEADER) + \ (NF5_MAXFLOWS * sizeof(struct NF5_FLOW))) #define NF1_HEADER_SIZE 16 #define NF5_NF1_FLOW_COMMON_SIZE (sizeof(struct NF5_FLOW) - \ sizeof(struct NF1_FLOW_PROTO_TOS_TCPF)) static void fill_netflow_v1_proto_tos_tcp (u_int8_t * pkt, u_int8_t proto, u_int8_t tos, u_int8_t tcpf) { struct NF1_FLOW_PROTO_TOS_TCPF *flw = (struct NF1_FLOW_PROTO_TOS_TCPF *) pkt; memset (pkt, 0, sizeof (struct NF1_FLOW_PROTO_TOS_TCPF)); flw->protocol = proto; flw->tos = tos; flw->tcp_flags = tcpf; } /* * Given an array of expired flows, send netflow v5 report packets * Returns number of packets sent or -1 on error */ static int send_netflow_v5_v1 (struct SENDPARAMETER sp, u_int16_t version) { struct FLOW **flows = sp.flows; int num_flows = sp.num_flows; u_int16_t ifidx = sp.ifidx; struct FLOWTRACKPARAMETERS *param = sp.param; int verbose_flag = sp.verbose_flag; struct timeval now; u_int32_t uptime_ms; u_int8_t packet[NF5_MAXPACKET_SIZE]; /* Maximum allowed packet size (24 flows) */ struct NF5_HEADER *hdr = NULL; struct NF5_FLOW *flw = NULL; int i, j, offset, num_packets; struct timeval *system_boot_time = ¶m->system_boot_time; u_int64_t *flows_exported = ¶m->flows_exported; struct OPTION *option = ¶m->option; if (version != 5 && version != 1) return (-1); if (param->adjust_time) now = param->last_packet_time; else gettimeofday (&now, NULL); uptime_ms = timeval_sub_ms (&now, system_boot_time); hdr = (struct NF5_HEADER *) packet; for (num_packets = offset = j = i = 0; i < num_flows; i++) { if (j >= NF5_MAXFLOWS - 1) { if (verbose_flag) logit (LOG_DEBUG, "Sending flow packet len = %d", offset); param->records_sent += hdr->flows; hdr->flows = htons (hdr->flows); if (send_multi_destinations (sp.target->num_destinations, sp.target->destinations, sp.target->is_loadbalance, packet, offset) < 0) return (-1); *flows_exported += j; j = 0; num_packets++; } if (j == 0) { memset (&packet, '\0', sizeof (packet)); hdr->version = htons (version); hdr->flows = 0; /* Filled in as we go */ hdr->uptime_ms = htonl (uptime_ms); hdr->time_sec = htonl (now.tv_sec); hdr->time_nanosec = htonl (now.tv_usec * 1000); hdr->flow_sequence = htonl (*flows_exported); if (option->sample > 0) { hdr->sampling_interval = htons ((0x01 << 14) | (option->sample & 0x3FFF)); } /* Other fields are left zero */ offset = sizeof (*hdr); if (version == 1) offset = NF1_HEADER_SIZE; } flw = (struct NF5_FLOW *) (packet + offset); flw->if_index_in = flw->if_index_out = htons (ifidx); /* NetFlow v.5 doesn't do IPv6 */ if (flows[i]->af != AF_INET) continue; if (flows[i]->octets[0] > 0) { flw->src_ip = flows[i]->addr[0].v4.s_addr; flw->dest_ip = flows[i]->addr[1].v4.s_addr; flw->src_port = flows[i]->port[0]; flw->dest_port = flows[i]->port[1]; flw->flow_packets = htonl (flows[i]->packets[0]); flw->flow_octets = htonl (flows[i]->octets[0]); flw->flow_start = htonl (timeval_sub_ms (&flows[i]->flow_start, system_boot_time)); flw->flow_finish = htonl (timeval_sub_ms (&flows[i]->flow_last, system_boot_time)); flw->tcp_flags = flows[i]->tcp_flags[0]; flw->protocol = flows[i]->protocol; flw->tos = flows[i]->tos[0]; if (version == 1) { fill_netflow_v1_proto_tos_tcp (packet + offset + NF5_NF1_FLOW_COMMON_SIZE, flows[i]->protocol, flows[i]->tos[0], flows[i]->tcp_flags[0]); } offset += sizeof (*flw); j++; hdr->flows++; } flw = (struct NF5_FLOW *) (packet + offset); flw->if_index_in = flw->if_index_out = htons (ifidx); if (flows[i]->octets[1] > 0) { flw->src_ip = flows[i]->addr[1].v4.s_addr; flw->dest_ip = flows[i]->addr[0].v4.s_addr; flw->src_port = flows[i]->port[1]; flw->dest_port = flows[i]->port[0]; flw->flow_packets = htonl (flows[i]->packets[1]); flw->flow_octets = htonl (flows[i]->octets[1]); flw->flow_start = htonl (timeval_sub_ms (&flows[i]->flow_start, system_boot_time)); flw->flow_finish = htonl (timeval_sub_ms (&flows[i]->flow_last, system_boot_time)); flw->tcp_flags = flows[i]->tcp_flags[1]; flw->protocol = flows[i]->protocol; flw->tos = flows[i]->tos[1]; if (version == 1) { fill_netflow_v1_proto_tos_tcp (packet + offset + NF5_NF1_FLOW_COMMON_SIZE, flows[i]->protocol, flows[i]->tos[1], flows[i]->tcp_flags[1]); } offset += sizeof (*flw); j++; hdr->flows++; } } /* Send any leftovers */ if (j != 0) { if (verbose_flag) logit (LOG_DEBUG, "Sending v5 flow packet len = %d", offset); param->records_sent += hdr->flows; hdr->flows = htons (hdr->flows); if (send_multi_destinations (sp.target->num_destinations, sp.target->destinations, sp.target->is_loadbalance, packet, offset) < 0) return (-1); num_packets++; } *flows_exported += j; param->packets_sent += num_packets; #ifdef ENABLE_PTHREAD if (use_thread) free (sp.flows); #endif /* ENABLE_PTHREAD */ return (num_packets); } int send_netflow_v5 (struct SENDPARAMETER sp) { return send_netflow_v5_v1 (sp, 5); } #ifndef ENABLE_LEGACY int send_netflow_v1 (struct SENDPARAMETER sp) { return send_netflow_v5_v1 (sp, 1); } #endif /* ENABLE_LEGACY */ softflowd-softflowd-1.0.0/netflow9.c000066400000000000000000000416701352553127000174520ustar00rootroot00000000000000/* * Copyright 2002 Damien Miller All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "common.h" #include "log.h" #include "treetype.h" #include "softflowd.h" #include "netflow9.h" /* Netflow v.9 */ struct NF9_FLOWSET_HEADER_COMMON { u_int16_t flowset_id, length; } __packed; struct NF9_TEMPLATE_FLOWSET_HEADER { struct NF9_FLOWSET_HEADER_COMMON c; u_int16_t template_id, count; } __packed; struct NF9_OPTION_TEMPLATE_FLOWSET_HEADER { struct NF9_FLOWSET_HEADER_COMMON c; u_int16_t template_id, scope_length, option_length; } __packed; struct NF9_TEMPLATE_FLOWSET_RECORD { u_int16_t type, length; } __packed; struct NF9_DATA_FLOWSET_HEADER { struct NF9_FLOWSET_HEADER_COMMON c; } __packed; #define NF9_MIN_RECORD_FLOWSET_ID 256 /* Flowset record types the we care about */ #define NF9_IN_BYTES 1 #define NF9_IN_PACKETS 2 /* ... */ #define NF9_PROTOCOL 4 #define NF9_TOS 5 /* ... */ #define NF9_TCP_FLAGS 6 #define NF9_L4_SRC_PORT 7 #define NF9_IPV4_SRC_ADDR 8 /* ... */ #define NF9_IF_INDEX_IN 10 #define NF9_L4_DST_PORT 11 #define NF9_IPV4_DST_ADDR 12 /* ... */ #define NF9_IF_INDEX_OUT 14 /* ... */ #define NF9_LAST_SWITCHED 21 #define NF9_FIRST_SWITCHED 22 /* ... */ #define NF9_IPV6_SRC_ADDR 27 #define NF9_IPV6_DST_ADDR 28 /* ... */ #define NF9_ICMP_TYPE 32 /* ... */ #define NF9_SRC_VLAN 58 /* ... */ #define NF9_IP_PROTOCOL_VERSION 60 /* Stuff pertaining to the templates that softflowd uses */ #define NF9_SOFTFLOWD_TEMPLATE_NRECORDS 16 struct NF9_SOFTFLOWD_TEMPLATE { struct NF9_TEMPLATE_FLOWSET_HEADER h; struct NF9_TEMPLATE_FLOWSET_RECORD r[NF9_SOFTFLOWD_TEMPLATE_NRECORDS]; } __packed; #define NF9_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS 1 #define NF9_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS 2 struct NF9_SOFTFLOWD_OPTION_TEMPLATE { struct NF9_OPTION_TEMPLATE_FLOWSET_HEADER h; struct NF9_TEMPLATE_FLOWSET_RECORD s[NF9_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS]; struct NF9_TEMPLATE_FLOWSET_RECORD r[NF9_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS]; } __packed; /* softflowd data flowset types */ struct NF9_SOFTFLOWD_DATA_COMMON { u_int32_t last_switched, first_switched; u_int32_t bytes, packets; u_int32_t if_index_in, if_index_out; u_int16_t src_port, dst_port; u_int8_t protocol, tcp_flags, ipproto, tos; u_int16_t icmp_type, vlanid; } __packed; struct NF9_SOFTFLOWD_DATA_V4 { u_int32_t src_addr, dst_addr; struct NF9_SOFTFLOWD_DATA_COMMON c; } __packed; struct NF9_SOFTFLOWD_DATA_V6 { u_int8_t src_addr[16], dst_addr[16]; struct NF9_SOFTFLOWD_DATA_COMMON c; } __packed; struct NF9_SOFTFLOWD_OPTION_DATA { struct NF9_FLOWSET_HEADER_COMMON c; u_int32_t scope_ifidx; u_int32_t sampling_interval; u_int8_t sampling_algorithm; u_int8_t padding[3]; } __packed; /* Local data: templates and counters */ #define NF9_SOFTFLOWD_MAX_PACKET_SIZE 512 #define NF9_SOFTFLOWD_V4_TEMPLATE_ID 1024 #define NF9_SOFTFLOWD_V6_TEMPLATE_ID 2048 #define NF9_SOFTFLOWD_OPTION_TEMPLATE_ID 256 #define NF9_DEFAULT_TEMPLATE_INTERVAL 16 /* ... */ #define NF9_OPTION_SCOPE_SYSTEM 1 #define NF9_OPTION_SCOPE_INTERFACE 2 #define NF9_OPTION_SCOPE_LINECARD 3 #define NF9_OPTION_SCOPE_CACHE 4 #define NF9_OPTION_SCOPE_TEMPLATE 5 static struct NF9_SOFTFLOWD_TEMPLATE v4_template; static struct NF9_SOFTFLOWD_TEMPLATE v6_template; static struct NF9_SOFTFLOWD_OPTION_TEMPLATE option_template; static struct NF9_SOFTFLOWD_OPTION_DATA option_data; static int nf9_pkts_until_template = -1; static void nf9_init_template (void) { bzero (&v4_template, sizeof (v4_template)); v4_template.h.c.flowset_id = htons (NFLOW9_TEMPLATE_SET_ID); v4_template.h.c.length = htons (sizeof (v4_template)); v4_template.h.template_id = htons (NF9_SOFTFLOWD_V4_TEMPLATE_ID); v4_template.h.count = htons (NF9_SOFTFLOWD_TEMPLATE_NRECORDS); v4_template.r[0].type = htons (NF9_IPV4_SRC_ADDR); v4_template.r[0].length = htons (4); v4_template.r[1].type = htons (NF9_IPV4_DST_ADDR); v4_template.r[1].length = htons (4); v4_template.r[2].type = htons (NF9_LAST_SWITCHED); v4_template.r[2].length = htons (4); v4_template.r[3].type = htons (NF9_FIRST_SWITCHED); v4_template.r[3].length = htons (4); v4_template.r[4].type = htons (NF9_IN_BYTES); v4_template.r[4].length = htons (4); v4_template.r[5].type = htons (NF9_IN_PACKETS); v4_template.r[5].length = htons (4); v4_template.r[6].type = htons (NF9_IF_INDEX_IN); v4_template.r[6].length = htons (4); v4_template.r[7].type = htons (NF9_IF_INDEX_OUT); v4_template.r[7].length = htons (4); v4_template.r[8].type = htons (NF9_L4_SRC_PORT); v4_template.r[8].length = htons (2); v4_template.r[9].type = htons (NF9_L4_DST_PORT); v4_template.r[9].length = htons (2); v4_template.r[10].type = htons (NF9_PROTOCOL); v4_template.r[10].length = htons (1); v4_template.r[11].type = htons (NF9_TCP_FLAGS); v4_template.r[11].length = htons (1); v4_template.r[12].type = htons (NF9_IP_PROTOCOL_VERSION); v4_template.r[12].length = htons (1); v4_template.r[13].type = htons (NF9_TOS); v4_template.r[13].length = htons (1); v4_template.r[14].type = htons (NF9_ICMP_TYPE); v4_template.r[14].length = htons (2); v4_template.r[15].type = htons (NF9_SRC_VLAN); v4_template.r[15].length = htons (2); bzero (&v6_template, sizeof (v6_template)); v6_template.h.c.flowset_id = htons (NFLOW9_TEMPLATE_SET_ID); v6_template.h.c.length = htons (sizeof (v6_template)); v6_template.h.template_id = htons (NF9_SOFTFLOWD_V6_TEMPLATE_ID); v6_template.h.count = htons (NF9_SOFTFLOWD_TEMPLATE_NRECORDS); v6_template.r[0].type = htons (NF9_IPV6_SRC_ADDR); v6_template.r[0].length = htons (16); v6_template.r[1].type = htons (NF9_IPV6_DST_ADDR); v6_template.r[1].length = htons (16); v6_template.r[2].type = htons (NF9_LAST_SWITCHED); v6_template.r[2].length = htons (4); v6_template.r[3].type = htons (NF9_FIRST_SWITCHED); v6_template.r[3].length = htons (4); v6_template.r[4].type = htons (NF9_IN_BYTES); v6_template.r[4].length = htons (4); v6_template.r[5].type = htons (NF9_IN_PACKETS); v6_template.r[5].length = htons (4); v6_template.r[6].type = htons (NF9_IF_INDEX_IN); v6_template.r[6].length = htons (4); v6_template.r[7].type = htons (NF9_IF_INDEX_OUT); v6_template.r[7].length = htons (4); v6_template.r[8].type = htons (NF9_L4_SRC_PORT); v6_template.r[8].length = htons (2); v6_template.r[9].type = htons (NF9_L4_DST_PORT); v6_template.r[9].length = htons (2); v6_template.r[10].type = htons (NF9_PROTOCOL); v6_template.r[10].length = htons (1); v6_template.r[11].type = htons (NF9_TCP_FLAGS); v6_template.r[11].length = htons (1); v6_template.r[12].type = htons (NF9_IP_PROTOCOL_VERSION); v6_template.r[12].length = htons (1); v6_template.r[13].type = htons (NF9_TOS); v6_template.r[13].length = htons (1); v6_template.r[14].type = htons (NF9_ICMP_TYPE); v6_template.r[14].length = htons (2); v6_template.r[15].type = htons (NF9_SRC_VLAN); v6_template.r[15].length = htons (2); } static void nf9_init_option (u_int16_t ifidx, struct OPTION *option) { bzero (&option_template, sizeof (option_template)); option_template.h.c.flowset_id = htons (NFLOW9_OPTION_TEMPLATE_SET_ID); option_template.h.c.length = htons (sizeof (option_template)); option_template.h.template_id = htons (NF9_SOFTFLOWD_OPTION_TEMPLATE_ID); option_template.h.scope_length = htons (sizeof (option_template.s)); option_template.h.option_length = htons (sizeof (option_template.r)); option_template.s[0].type = htons (NF9_OPTION_SCOPE_INTERFACE); option_template.s[0].length = htons (sizeof (option_data.scope_ifidx)); option_template.r[0].type = htons (NFLOW9_SAMPLING_INTERVAL); option_template.r[0].length = htons (sizeof (option_data.sampling_interval)); option_template.r[1].type = htons (NFLOW9_SAMPLING_ALGORITHM); option_template.r[1].length = htons (sizeof (option_data.sampling_algorithm)); bzero (&option_data, sizeof (option_data)); option_data.c.flowset_id = htons (NF9_SOFTFLOWD_OPTION_TEMPLATE_ID); option_data.c.length = htons (sizeof (option_data)); option_data.scope_ifidx = htonl (ifidx); option_data.sampling_interval = htonl (option->sample); option_data.sampling_algorithm = NFLOW9_SAMPLING_ALGORITHM_DETERMINISTIC; } static int nf_flow_to_flowset (const struct FLOW *flow, u_char * packet, u_int len, u_int16_t ifidx, const struct timeval *system_boot_time, u_int * len_used) { union { struct NF9_SOFTFLOWD_DATA_V4 d4; struct NF9_SOFTFLOWD_DATA_V6 d6; } d[2]; struct NF9_SOFTFLOWD_DATA_COMMON *dc[2]; u_int freclen, ret_len, nflows; bzero (d, sizeof (d)); *len_used = nflows = ret_len = 0; switch (flow->af) { case AF_INET: freclen = sizeof (struct NF9_SOFTFLOWD_DATA_V4); memcpy (&d[0].d4.src_addr, &flow->addr[0].v4, 4); memcpy (&d[0].d4.dst_addr, &flow->addr[1].v4, 4); memcpy (&d[1].d4.src_addr, &flow->addr[1].v4, 4); memcpy (&d[1].d4.dst_addr, &flow->addr[0].v4, 4); dc[0] = &d[0].d4.c; dc[1] = &d[1].d4.c; dc[0]->ipproto = dc[1]->ipproto = 4; break; case AF_INET6: freclen = sizeof (struct NF9_SOFTFLOWD_DATA_V6); memcpy (&d[0].d6.src_addr, &flow->addr[0].v6, 16); memcpy (&d[0].d6.dst_addr, &flow->addr[1].v6, 16); memcpy (&d[1].d6.src_addr, &flow->addr[1].v6, 16); memcpy (&d[1].d6.dst_addr, &flow->addr[0].v6, 16); dc[0] = &d[0].d6.c; dc[1] = &d[1].d6.c; dc[0]->ipproto = dc[1]->ipproto = 6; break; default: return (-1); } dc[0]->first_switched = dc[1]->first_switched = htonl (timeval_sub_ms (&flow->flow_start, system_boot_time)); dc[0]->last_switched = dc[1]->last_switched = htonl (timeval_sub_ms (&flow->flow_last, system_boot_time)); dc[0]->bytes = htonl (flow->octets[0]); dc[1]->bytes = htonl (flow->octets[1]); dc[0]->packets = htonl (flow->packets[0]); dc[1]->packets = htonl (flow->packets[1]); dc[0]->if_index_in = dc[0]->if_index_out = htonl (ifidx); dc[1]->if_index_in = dc[1]->if_index_out = htonl (ifidx); dc[0]->src_port = dc[1]->dst_port = flow->port[0]; dc[1]->src_port = dc[0]->dst_port = flow->port[1]; dc[0]->protocol = dc[1]->protocol = flow->protocol; dc[0]->tcp_flags = flow->tcp_flags[0]; dc[1]->tcp_flags = flow->tcp_flags[1]; dc[0]->tos = flow->tos[0]; dc[1]->tos = flow->tos[1]; if (flow->protocol == IPPROTO_ICMP || flow->protocol == IPPROTO_ICMPV6) { dc[0]->icmp_type = dc[0]->dst_port; dc[1]->icmp_type = dc[1]->dst_port; } dc[0]->vlanid = dc[1]->vlanid = htons (flow->vlanid[0]); if (flow->octets[0] > 0) { if (ret_len + freclen > len) return (-1); memcpy (packet + ret_len, &d[0], freclen); ret_len += freclen; nflows++; } if (flow->octets[1] > 0) { if (ret_len + freclen > len) return (-1); memcpy (packet + ret_len, &d[1], freclen); ret_len += freclen; nflows++; } *len_used = ret_len; return (nflows); } /* * Given an array of expired flows, send netflow v9 report packets * Returns number of packets sent or -1 on error */ #ifdef ENABLE_LEGACY int send_netflow_v9 (struct SENDPARAMETER sp) { struct FLOW **flows = sp.flows; int num_flows = sp.num_flows; u_int16_t ifidx = sp.ifidx; struct FLOWTRACKPARAMETERS *param = sp.param; int verbose_flag = sp.verbose_flag; struct NFLOW9_HEADER *nf9; struct NF9_DATA_FLOWSET_HEADER *dh; struct timeval now; u_int offset, last_af, i, j, num_packets, inc, last_valid; int r; u_char packet[NF9_SOFTFLOWD_MAX_PACKET_SIZE]; struct timeval *system_boot_time = ¶m->system_boot_time; u_int64_t *flows_exported = ¶m->flows_exported; u_int64_t *packets_sent = ¶m->packets_sent; struct OPTION *option = ¶m->option; if (param->adjust_time) now = param->last_packet_time; else gettimeofday (&now, NULL); if (nf9_pkts_until_template == -1) { nf9_init_template (); nf9_pkts_until_template = 0; if (option != NULL && option->sample > 1) { nf9_init_option (ifidx, option); } } last_valid = num_packets = 0; for (j = 0; j < num_flows;) { bzero (packet, sizeof (packet)); nf9 = (struct NFLOW9_HEADER *) packet; nf9->version = htons (9); nf9->flows = 0; /* Filled as we go, htons at end */ nf9->uptime_ms = htonl (timeval_sub_ms (&now, system_boot_time)); nf9->export_time = htonl (time (NULL)); nf9->od_id = 0; offset = sizeof (*nf9); /* Refresh template headers if we need to */ if (nf9_pkts_until_template <= 0) { memcpy (packet + offset, &v4_template, sizeof (v4_template)); offset += sizeof (v4_template); nf9->flows++; memcpy (packet + offset, &v6_template, sizeof (v6_template)); offset += sizeof (v6_template); nf9->flows++; if (option != NULL && option->sample > 1) { memcpy (packet + offset, &option_template, sizeof (option_template)); offset += sizeof (option_template); nf9->flows++; memcpy (packet + offset, &option_data, sizeof (option_data)); offset += sizeof (option_data); nf9->flows++; } nf9_pkts_until_template = NF9_DEFAULT_TEMPLATE_INTERVAL; } dh = NULL; last_af = 0; for (i = 0; i + j < num_flows; i++) { if (dh == NULL || flows[i + j]->af != last_af) { if (dh != NULL) { if (offset % 4 != 0) { /* Pad to multiple of 4 */ dh->c.length += 4 - (offset % 4); offset += 4 - (offset % 4); } /* Finalise last header */ dh->c.length = htons (dh->c.length); } if (offset + sizeof (*dh) > sizeof (packet)) { /* Mark header is finished */ dh = NULL; break; } dh = (struct NF9_DATA_FLOWSET_HEADER *) (packet + offset); dh->c.flowset_id = (flows[i + j]->af == AF_INET) ? v4_template.h.template_id : v6_template.h.template_id; last_af = flows[i + j]->af; last_valid = offset; dh->c.length = sizeof (*dh); /* Filled as we go */ offset += sizeof (*dh); } r = nf_flow_to_flowset (flows[i + j], packet + offset, sizeof (packet) - offset, ifidx, system_boot_time, &inc); if (r <= 0) { /* yank off data header, if we had to go back */ if (last_valid) offset = last_valid; break; } offset += inc; dh->c.length += inc; nf9->flows += r; last_valid = 0; /* Don't clobber this header now */ if (verbose_flag) { logit (LOG_DEBUG, "Flow %d/%d: " "r %d offset %d type %04x len %d(0x%04x) " "flows %d", r, i, j, offset, dh->c.flowset_id, dh->c.length, dh->c.length, nf9->flows); } } /* Don't finish header if it has already been done */ if (dh != NULL) { if (offset % 4 != 0) { /* Pad to multiple of 4 */ dh->c.length += 4 - (offset % 4); offset += 4 - (offset % 4); } /* Finalise last header */ dh->c.length = htons (dh->c.length); } param->records_sent += nf9->flows; nf9->flows = htons (nf9->flows); nf9->sequence = htonl ((u_int32_t) ((*packets_sent + num_packets + 1) & 0x00000000ffffffff)); if (verbose_flag) logit (LOG_DEBUG, "Sending flow packet len = %d", offset); if (send_multi_destinations (sp.target->num_destinations, sp.target->destinations, sp.target->is_loadbalance, packet, offset) < 0) return (-1); num_packets++; nf9_pkts_until_template--; j += i; } *flows_exported += j; param->packets_sent += num_packets; #ifdef ENABLE_PTHREAD if (use_thread) free (sp.flows); #endif /* ENABLE_PTHREAD */ return (num_packets); } #endif /* ENABLE_LEGACY */ void netflow9_resend_template (void) { if (nf9_pkts_until_template > 0) nf9_pkts_until_template = 0; } softflowd-softflowd-1.0.0/netflow9.h000066400000000000000000000041311352553127000174460ustar00rootroot00000000000000/* * Copyright 2019 Hitoshi Irino All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _NETFLOW9_H #define _NETFLOW9_H #include "softflowd.h" #define NFLOW9_TEMPLATE_SET_ID 0 #define NFLOW9_OPTION_TEMPLATE_SET_ID 1 /* Information Elements */ #define NFLOW9_SAMPLING_INTERVAL 34 #define NFLOW9_SAMPLING_ALGORITHM 35 #define NFLOW9_OPTION_SCOPE_INTERFACE 2 #define NFLOW9_SAMPLING_ALGORITHM_DETERMINISTIC 1 struct NFLOW9_HEADER { u_int16_t version, flows; u_int32_t uptime_ms; u_int32_t export_time; // in seconds u_int32_t sequence, od_id; } __packed; #ifdef ENABLE_LEGACY /* Prototypes for functions to send NetFlow packets, from netflow*.c */ int send_netflow_v9 (struct SENDPARAMETER sp); /* Force a resend of the flow template */ void netflow9_resend_template (void); #endif /* ENABLE_LEGACY */ #endif /* _NETFLOW9_H */ softflowd-softflowd-1.0.0/ntopng.c000066400000000000000000000151041352553127000172010ustar00rootroot00000000000000/* * Copyright 2018 Alastair D'Silva All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "common.h" #include "log.h" #include "treetype.h" #include "softflowd.h" #include struct NTOPNG_MSG_HEADER { char url[16]; u_int8_t version, source_id; u_int16_t size; u_int32_t msg_id; } __attribute__((packed)); /* * Connect to NTOPNG collector */ int connect_ntopng(const char *host, const char *port, struct ZMQ *zmq) { void *context = zmq_ctx_new(); void *pub_socket = zmq_socket(context, ZMQ_PUB); char connect_str[6 + NI_MAXHOST + 1 + NI_MAXSERV + 1]; /* "tcp://hostname:port" */ if (!context) return errno; if (!pub_socket) { zmq_ctx_destroy(context); return errno; } snprintf(connect_str, sizeof(connect_str), "tcp://%s:%s", host, port); fprintf(stderr, "Connecting ZMQ socket '%s'\n", connect_str); if (zmq_connect (pub_socket, connect_str)) { zmq_close(pub_socket); zmq_ctx_destroy(context); return errno; } zmq->context = context; zmq->socket = pub_socket; return 0; } static int add_json_flow (struct SENDPARAMETER *sp, struct FLOW *flow, char *buf, size_t len) { int size = snprintf(buf, len, "{" "\"7\": %d," /* src port */ "\"11\": %d," /* dst port */ "\"1\": %d," /* in octets */ "\"2\": %d," /* in packets */ "\"23\": %d," /* out octets */ "\"24\": %d," /* out packets */ "\"22\": %d," /* start timestamp */ "\"21\": %d," /* last timestamp */ "\"6\": %d," /* tcp flags */ "\"4\": %d", /* protocol */ flow->port[0], flow->port[1], flow->octets[1], flow->packets[1], flow->octets[0], flow->packets[0], timeval_sub_ms (&flow->flow_start, &sp->param->system_boot_time), timeval_sub_ms (&flow->flow_last, &sp->param->system_boot_time), flow->tcp_flags[0], flow->protocol ); if (size > (len - 1)) return size; if (flow->af == AF_INET) { char src[INET_ADDRSTRLEN]; char dst[INET_ADDRSTRLEN]; /* safe to ignore errors, neither error case can occur */ inet_ntop(AF_INET, &flow->addr[0].v4, src, sizeof(src)); inet_ntop(AF_INET, &flow->addr[1].v4, dst, sizeof(dst)); size += snprintf(buf + size, len - size, ",\"8\":\"%s\"," /* ipv4 src addr */ "\"12\":\"%s\"", /* ipv4 dst addr */ src, dst ); } else { char src[INET6_ADDRSTRLEN]; char dst[INET6_ADDRSTRLEN]; /* safe to ignore errors, neither error case can occur */ inet_ntop(AF_INET6, &flow->addr[0].v6, src, sizeof(src)); inet_ntop(AF_INET6, &flow->addr[1].v6, dst, sizeof(dst)); size += snprintf(buf + size, len - size, ",\"27\":\"%s\"," /* ipv6 src addr */ "\"28\":\"%s\"", /* ipv6 dst addr */ src, dst ); } if (size > (len - 1)) return size; if (sp->param->track_level >= TRACK_FULL_VLAN) { size += snprintf(buf + size, len - size, ",\"58\":%d," /* vlan src */ "\"59\":%d", /* vlan dst */ flow->vlanid[0], flow->vlanid[1] ); if (size > (len - 1)) return size; } if (sp->param->track_level >= TRACK_FULL_VLAN_ETHER) { size += snprintf(buf + size, len - size, ",\"56\":\"%d:%d:%d:%d:%d:%d\"," /* ether mac src */ "\"57\":\"%d:%d:%d:%d:%d:%d\"", /* ether mac dst */ flow->ethermac[0][0],flow->ethermac[0][1],flow->ethermac[0][2], flow->ethermac[0][3],flow->ethermac[0][4],flow->ethermac[0][5], flow->ethermac[1][0],flow->ethermac[1][1],flow->ethermac[1][2], flow->ethermac[1][3],flow->ethermac[1][4],flow->ethermac[1][5] ); } if (size > (len - 1)) return size; size += snprintf(buf + size, len - size, "}"); return size; } #define MAX_JSON_SIZE 7168 int send_ntopng_message (struct SENDPARAMETER *sp, int start_at_flow) { struct NTOPNG_MSG_HEADER header; static uint32_t msg_id = 0; char json[MAX_JSON_SIZE]; int json_used = 0; int flow = start_at_flow; bool first = true; int target = 0; header.url[0] = 'f'; header.url[1] = 'l'; header.url[2] = 'o'; header.url[3] = 'w'; memset(header.url + 4, 0, sizeof(header.url) - 4); header.version = 2; header.msg_id = htonl(msg_id++); json_used += snprintf(json + json_used, MAX_JSON_SIZE - json_used, "["); while (flow < sp->num_flows) { int size = 0; if (first) { first = false; } else { json_used += snprintf (json + json_used, MAX_JSON_SIZE - json_used, ",\n"); } size = add_json_flow (sp, sp->flows[flow], json + json_used, MAX_JSON_SIZE - json_used); if (size > (MAX_JSON_SIZE - json_used - 2 -2)) { /* space for "]\0" and next ",\n"*/ break; } json_used += size; flow++; } json_used += snprintf (json + json_used, MAX_JSON_SIZE - json_used, "]"); header.size = htons(json_used); for (target = 0; target < sp->target->num_destinations; target++) { zmq_send(sp->target->destinations[target].zmq.socket, &header, sizeof(header), ZMQ_SNDMORE); zmq_send(sp->target->destinations[target].zmq.socket, json, json_used, 0); } return flow; } int send_ntopng(struct SENDPARAMETER sp) { int flow = 0; int packets = 0; while (flow < sp.num_flows) { flow = send_ntopng_message(&sp, flow); packets++; } sp.param->records_sent += flow; sp.param->packets_sent += packets; #ifdef ENABLE_PTHREAD if (use_thread) free (sp.flows); #endif /* ENABLE_PTHREAD */ return packets; } softflowd-softflowd-1.0.0/psamp.c000066400000000000000000000150621352553127000170170ustar00rootroot00000000000000/* * Copyright 2019 Hitoshi Irino All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "common.h" #include "log.h" #include "ipfix.h" #include "psamp.h" #include #define PSAMP_SOFTFLOWD_TEMPLATE_ID 3072 #define PSAMP_SOFTFLOWD_TEMPLATE_NRECORDS 4 #define PSAMP_DATALINKFRAME_SIZE IPFIX_SOFTFLOWD_MAX_PACKET_SIZE - \ sizeof(struct IPFIX_HEADER) - sizeof(struct IPFIX_SET_HEADER) - 8 - 8 -2 const struct IPFIX_FIELD_SPECIFIER field_psamp[] = { {PSAMP_selectionSequenceId, 8}, {PSAMP_observationTimeMicroseconds, 8}, {PSAMP_sectionExportedOctets, 2}, {PSAMP_dataLinkFrameSection, PSAMP_DATALINKFRAME_SIZE} }; struct PSAMP_SOFTFLOWD_TEMPLATE { struct IPFIX_TEMPLATE_SET_HEADER h; struct IPFIX_FIELD_SPECIFIER r[PSAMP_SOFTFLOWD_TEMPLATE_NRECORDS]; } __packed; struct PSAMP_SOFTFLOWD_TEMPLATE template; static int psamp_pkts_until_template = -1; static void psamp_init_template (struct PSAMP_SOFTFLOWD_TEMPLATE *template_p) { u_int index = 0; bzero (template_p, sizeof (*template_p)); template_p->h.c.set_id = htons (IPFIX_TEMPLATE_SET_ID); template_p->h.c.length = htons (sizeof (struct PSAMP_SOFTFLOWD_TEMPLATE)); template_p->h.r.template_id = htons (PSAMP_SOFTFLOWD_TEMPLATE_ID); template_p->h.r.count = htons (PSAMP_SOFTFLOWD_TEMPLATE_NRECORDS); ipfix_init_fields (template_p->r, &index, field_psamp, PSAMP_SOFTFLOWD_TEMPLATE_NRECORDS); } int send_psamp (const u_char * pkt, int caplen, struct timeval tv, struct NETFLOW_TARGET *target, uint64_t total_packets) { u_char packet[IPFIX_SOFTFLOWD_MAX_PACKET_SIZE]; struct IPFIX_HEADER *ipfix = (struct IPFIX_HEADER *) packet; struct IPFIX_SET_HEADER *dh; u_int64_t *sequenceId; struct ntp_time_t *ntptime; u_int16_t *exportedOctets; int offset = sizeof (struct IPFIX_HEADER); int copysize = caplen < PSAMP_DATALINKFRAME_SIZE ? caplen : PSAMP_DATALINKFRAME_SIZE; ipfix->version = htons (NF_VERSION_IPFIX); // PSAMP uses IPFIX ipfix->export_time = htonl (tv.tv_sec); ipfix->sequence = htonl ((u_int32_t) (total_packets & 0x00000000ffffffff)); ipfix->od_id = 0; if (psamp_pkts_until_template == -1) { psamp_init_template (&template); psamp_pkts_until_template = 0; memcpy (&packet[offset], &template, sizeof (template)); ipfix->length = htons (offset + sizeof (template)); if (send_multi_destinations (target->num_destinations, target->destinations, 0, packet, offset + sizeof (template)) < 0) return (-1); } dh = (struct IPFIX_SET_HEADER *) &packet[offset]; dh->set_id = htons (PSAMP_SOFTFLOWD_TEMPLATE_ID); dh->length = htons (IPFIX_SOFTFLOWD_MAX_PACKET_SIZE - sizeof (struct IPFIX_HEADER)); offset += sizeof (struct IPFIX_SET_HEADER); sequenceId = (u_int64_t *) & packet[offset]; *sequenceId = htobe64 (total_packets); offset += sizeof (u_int64_t); ntptime = (struct ntp_time_t *) &packet[offset]; conv_unix_to_ntp (tv, ntptime); ntptime->second = htonl (ntptime->second); ntptime->fraction = htonl (ntptime->fraction); offset += sizeof (struct ntp_time_t); exportedOctets = (u_int16_t *) & packet[offset]; *exportedOctets = htons (copysize); offset += sizeof (u_int16_t); memset (&packet[offset], 0, IPFIX_SOFTFLOWD_MAX_PACKET_SIZE - offset); memcpy (&packet[offset], pkt, copysize); ipfix->length = htons (IPFIX_SOFTFLOWD_MAX_PACKET_SIZE); if (send_multi_destinations (target->num_destinations, target->destinations, target->is_loadbalance, packet, IPFIX_SOFTFLOWD_MAX_PACKET_SIZE) < 0) return (-1); return 1; } // This function only process softflowd orignate psamp data record. int recv_psamp (int rsock, struct CB_CTXT *cb_ctxt) { char buf[IPFIX_SOFTFLOWD_MAX_PACKET_SIZE]; struct IPFIX_HEADER *ipfix = (struct IPFIX_HEADER *) buf; struct ntp_time_t ntptime; struct pcap_pkthdr pkthdr; int recvsize = 0; int offset = 0; memset (buf, 0, sizeof (buf)); recvsize = recv (rsock, buf, sizeof (buf), 0); if (recvsize < 0) { perror ("recv"); return -1; } else if (recvsize < (sizeof (struct IPFIX_HEADER) + sizeof (struct IPFIX_SET_HEADER) + sizeof (uint64_t) + sizeof (struct ntp_time_t) + sizeof (uint16_t))) { logit (LOG_DEBUG, "recv_psamp: recvsize: %d is shorter than needed size", recvsize); return -1; } offset = sizeof (struct IPFIX_HEADER); struct IPFIX_SET_HEADER *sh = (struct IPFIX_SET_HEADER *) &buf[offset]; offset += sizeof (struct IPFIX_SET_HEADER); if (ntohs (ipfix->version) != NF_VERSION_IPFIX) return -1; if (ntohs (sh->set_id) != PSAMP_SOFTFLOWD_TEMPLATE_ID) return 0; // This function only process softflowd orignate psamp data record. // disrgard selectionSequenceId offset += sizeof (uint64_t); // observationTimeMicroseconds ntptime = *((struct ntp_time_t *) &buf[offset]); offset += sizeof (struct ntp_time_t); ntptime.second = ntohl (ntptime.second); ntptime.fraction = ntohl (ntptime.fraction); pkthdr.ts = conv_ntp_to_unix (ntptime); //sectionExportedOctets pkthdr.caplen = pkthdr.len = ntohs (*((uint16_t *) & buf[offset])); offset += sizeof (uint16_t); pkthdr.caplen = pkthdr.caplen < sizeof (buf) - offset ? pkthdr.caplen : sizeof (buf) - offset; flow_cb ((u_char *) cb_ctxt, &pkthdr, (const u_char *) &buf[offset]); return 1; } softflowd-softflowd-1.0.0/psamp.h000066400000000000000000000037731352553127000170320ustar00rootroot00000000000000/* * Copyright 2019 Hitoshi Irino All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _PSAMP_H #define _PSAMP_H #include "common.h" #include "softflowd.h" #define PSAMP_selectionSequenceId 301 #define PSAMP_selectorAlgorithm 304 #define PSAMP_samplingPacketInterval 305 #define PSAMP_samplingPacketSpace 306 #define PSAMP_digestHashValue 326 #define PSAMP_observationTimeMicroseconds 324 #define PSAMP_dataLinkFrameSection 315 #define PSAMP_sectionExportedOctets 410 #define PSAMP_selectorAlgorithm_count 1 int send_psamp (const u_char * pkt, int caplen, struct timeval tv, struct NETFLOW_TARGET *target, uint64_t total_packets); int recv_psamp (int rsock, struct CB_CTXT *cb_ctxt); #endif /* _PSAMP_H */ softflowd-softflowd-1.0.0/softflowctl.8000066400000000000000000000061331352553127000201710ustar00rootroot00000000000000.\" Copyright (c) 2002 Damien Miller. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. .\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd October 18, 2002 .Dt SOFTFLOWCTL 8 .Os .Sh NAME .Nm softflowctl .Nd Remote control program for softflowd .Sh SYNOPSIS .Nm softflowctl .Op Fl h .Op Fl c Ar ctl_sock .Ar command .Sh DESCRIPTION .Nm is a remote control program used to control a running .Xr softflowd 8 daemon. .Pp The command line options are as follows: .Bl -tag -width Ds .It Fl c Ar ctlsock Specify an alternate location for the remote control socket. Default is .Pa /var/run/softflowd.ctl .It Fl h Display command line usage information. .El .Pp .Sh COMMANDS .Bl -tag -width Ds .It Pa shutdown Ask .Xr softflowd 8 to gracefully exit. This is equivalent to sending it a .Dv SIGTERM or .Dv SIGINT . .It Pa exit Ask .Xr softflowd 8 to immediately exit. No flow expiry processing or data export is performed. .It Pa expire-all Immediately expire all tracked flows. .It Pa delete-all Immediately delete all tracked flows. No flow expiry processing or data export is performed. .It Pa statistics Return statistics collected by .Xr softflowd 8 on expired flows. .It Pa debug+ Increase the debugging level of .Xr softflowd 8 .It Pa debug- Decrease the debugging level. .It Pa stop-gather Stops network data collection by .Xr softflowd 8 . .It Pa start-gather Resumes network data collection. .It Pa dump-flows Return information on all tracked flows. .It Pa timeouts Print information on flow timeout parameters. .It Pa send-template Resend a NetFlow v.9 template record before the next flow export. Has no effect for other flow export versions. .El .Sh BUGS All times are unconditionally displayed in UTC, regardless of the system timezone. Please report bugs in softflowctl to https://github.com/irino/softflowd/issues .Sh AUTHORS .An Damien Miller Aq djm@mindrot.org .An Hitoshi Irino (current maintainer) Aq irino@sfc.wide.ad.jp .Sh SEE ALSO .Xr softflowd 8 softflowd-softflowd-1.0.0/softflowctl.c000066400000000000000000000062021352553127000202410ustar00rootroot00000000000000/* * Copyright 2002 Damien Miller All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "common.h" static void usage(void) { fprintf(stderr, "Usage: [-c ctlsock] softflowctl [command]\n"); } int main(int argc, char **argv) { const char *ctlsock_path; char buf[8192], *command; struct sockaddr_un ctl; #ifdef SOCK_HAS_LEN socklen_t ctllen; #endif int ctlsock, ch; FILE *ctlf; extern char *optarg; extern int optind; ctlsock_path = DEFAULT_CTLSOCK; while ((ch = getopt(argc, argv, "hc:")) != -1) { switch (ch) { case 'h': usage(); return (0); case 'c': ctlsock_path = optarg; break; default: fprintf(stderr, "Invalid commandline option.\n"); usage(); exit(1); } } /* Accept only one argument */ if (optind != argc - 1) { usage(); exit(1); } command = argv[optind]; memset(&ctl, '\0', sizeof(ctl)); if (strlcpy(ctl.sun_path, ctlsock_path, sizeof(ctl.sun_path)) >= sizeof(ctl.sun_path)) { fprintf(stderr, "Control socket path too long.\n"); exit(1); } ctl.sun_path[sizeof(ctl.sun_path) - 1] = '\0'; ctl.sun_family = AF_UNIX; #ifdef SOCK_HAS_LEN ctllen = offsetof(struct sockaddr_un, sun_path) + strlen(ctlsock_path) + 1; ctl.sun_len = ctllen; #endif if ((ctlsock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { fprintf(stderr, "ctl socket() error: %s\n", strerror(errno)); exit(1); } if (connect(ctlsock, (struct sockaddr*)&ctl, sizeof(ctl)) == -1) { fprintf(stderr, "ctl connect(\"%s\") error: %s\n", ctl.sun_path, strerror(errno)); exit(1); } if ((ctlf = fdopen(ctlsock, "r+")) == NULL) { fprintf(stderr, "fdopen: %s\n", strerror(errno)); exit(1); } setlinebuf(ctlf); /* Send command */ if (fprintf(ctlf, "%s\n", command) < 0) { fprintf(stderr, "write: %s\n", strerror(errno)); exit(1); } /* Write out reply */ while((fgets(buf, sizeof(buf), ctlf)) != NULL) fputs(buf, stdout); fclose(ctlf); close(ctlsock); exit(0); } softflowd-softflowd-1.0.0/softflowctl.pdf000066400000000000000000000546271352553127000206060ustar00rootroot00000000000000%PDF-1.4 %쏢 5 0 obj <> stream xXnF}W#F8۸/B \ɌIB.P ҏ':˻hI>a@;3sfFidpѶ|5^Mf3 gVI"!v*X'GXEm:eՅBm&QP'&v _XZ|L֖߯L(TUvA6*GF5e6&>~XȰke* ލ ށk0҉PidQ}#Szu~uc(@qp^(U:+Lz+*7v27.#RN4&l :ȕ okiBm.IL; 6Z+PcH&RHZQE9=h0? OivYH]% 5a0ø7qhƥcp2 k07\ܞr5Ld6@iQ|̆\zیbr8|[ݏ :={SnKx #vmgZ­eRJR]MZyj;B+ f8H\,Tv&y)tL &z3fq*U)gZ03iusW< ч0^_Jc]p{nCmo A shr/ 5 [V7jD- GXʦ-iÆ1zTْ)cmrȣjDV&[ |mtꚝqWvxUg; eZ=sE%[^样~Z@b_)l?ˉITYU V(6a3h8CVo^Bä-\ѢΏ֨y@DjS[<}e*x:s)uRd.La=bY`K [OvobjI3j+^Xߖ7SA, EQʢaր ~^Z 8 Xf"jٮU☝kxrMk+J,ʕ0ZH s-B]}=:܅u3mUqs$ <7@K̻UF[U_H w#iD{cs UPPԯStjuSqsnC{!:fYeOj:[M~?endstream endobj 6 0 obj 1764 endobj 22 0 obj <> stream x1o0wJ1شd"B d@6n{ݽ 0\ dϠ\zBk wӑńqȄ3*f[+EZie s$1*ȍDC+G!T$ ļޠv]}@NS0 ќrz1DI R.T B⟻{=1B9 R)wTy/EU.<`H6#i\G} 62:Q6^} IBU>8c\SA(7/oendstream endobj 23 0 obj 289 endobj 4 0 obj <> /Contents 5 0 R >> endobj 21 0 obj <> /Contents 22 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R 21 0 R ] /Count 2 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 19 0 obj <> endobj 20 0 obj <> endobj 24 0 obj <> endobj 25 0 obj <> endobj 16 0 obj <> endobj 18 0 obj <> endobj 31 0 obj <> endobj 14 0 obj <> endobj 12 0 obj <> endobj 32 0 obj <> endobj 10 0 obj <> endobj 33 0 obj <> endobj 8 0 obj <> endobj 17 0 obj <> endobj 26 0 obj <>stream xWiTWW* D2E6hQ,Tiq /!qId\c\3FQdܚz2ۜs8W~+%FD"/M=Mp oX8DxiAfMUYxk+Zgvp5h X$z;hzJDhT77w܌k<096yBfTg#;!9-=%!5+81%V$94a<9&ջE9?K0;'fml\P|pªkB“SܦMj BQ*ZJRT5ZFQt*j!5ZDͤޢ`ʚElIJLUPD D<ݴ,._JN"tL726L:9#ZGbL IQ ~^ v@ucɋK׭S4r&E%yj5E*eHA9|c_e|wޜ,>iyijקFt;}̯]Ɛ R+n)v8`?;=q\ys}/8/›Z]kRsRp%XCnC4bdS߁Xc,Yh'}<vO`$:ۏgGh9"}q3շ71LBFcd|aQAY()XZ([!zن*tn>]4m.&2e>Y6qm,x%ٱbl KjnI1t& @}I,ٛ(RzJ]S\[ϥ+HOf1vj~&jHs \aT]7mFTid.;wMj>޽JmFME.WUT`NoyzllsgHphv)58Dڟ.enw&7rMMe)(_?zf5{P>ZhԊJ1R%j4^Jl@y7X3ˢxupiӧ=ݫW(JԆ4c&w]Iql#`z1yuc D+ ǾLV΄; &71GŁ)nB_.{~SUv|gv *6l*/yfal91'nCB eH?u{$HưBAeצ bŒbvU=A" H/\hӨ-Ȼsw2*ao猁kB 䎠$6@j!qQԅ> >>Y<oA,9n<{$OɅtb)j7uC"Vgq;P,Yf""ztDGxĈHV6C8?[¢kee|!S*RNvag-+ugxqlWKuw>xQHdV ,9s֊м1I JZT:\Qm1ր$^YaV^x*IJ-ѐq0*pAibyEB}I2+Xxo Ğ jLu/5xmsl˱K9IwǞu!OЙAt^UTwpiSݱ>ou<׬IHD,?ysnzqe۸9zӄ-%f$~Pw-Ox.)6jA1\^esvÏ4x$h .&J}k%b;k Ț"UhťS&۾pQW])vc'M6x,&#[O腯|Cey,.OO\-xh WG/\ 84 b),6wNx.M[﬒>%ӏH/;Ha7m8؀47Vݴ@ $ћļGнK!9KC<q>MRC7ִDg2#O9za9-y0o oFcwǂ@6! &=W–̉f = n6k HpE=;P)\`IϠi*rscسB(;:Rw$;(?^S[)ߛ?O'1 Qd3㛘/޽V-Q1QyN)Z 鵪uf Vܸnੋbȷ04/mdU Zm biŻƻ|A">$`M:vy9i_kTæ=y)K[|OE}ny,LRc ϰԼR endstream endobj 15 0 obj <> endobj 27 0 obj <>stream xTmLSgת)]F>צ0?Q ARhKK/ -mQ:)7爙#n:Dzd?L`fk~.ysss ,OɤE2dH l8]Į!>;N,Ls@0:VQi!{ j<gÎRZ /,-*ı1/bYNxQJE,?XO^ 'K+d6.)XZ /Vgf?FID2Bۉ^bH'&9Akos/2d,dxᔗGnn+6CCDw X0Fu:Zz)FJ@@4ڍMS8l'RirrA*6}sc=htz6j`20=ӀAD|$#=Αmo%J D74X`/bffBîdGH(2br&n2\oUWjZ:m#>zߧߗ= Ug 9aeO_?-D jNi3K!O0?Wµ렶=U* M%F0y{obmd.gފ#S7R0^qId{}:IznMzˁpZ? CqdY ]`YʅKP,L;rroP2(tmn$Βk<%-@f#> endobj 28 0 obj <>stream xXw|ך!kfh,%L$RJ Piް7Y%ҕdY%[.rb0fJ!tRRK%~ɾ;uvwdo?[3www9 ߸ IRn j9~$]ΚbJHkXJ2$` $Q ˙*vs$dV/6<ȐWzHE;SgXCa"4HH1FU;F\+{O$?&8Y'"L8XtKTD:OoԔz HVMr&n9EhK݋xvtπs`D4КԜb}rdXgZ6O=|ԉ` '0W3#.~Y3r# 2Xb'("tu%U d>ܲ }cDO! W]ϊw$ؒkq<=JIIĕ]nDIeI`ˇ\fOxo!exyYWe fb /{H*i3zol7g9{ze:E\{qH:o^Z7'#Fz>,-oK{$紗}~^9#ma͋Fht+ OKb:uZhx&pz֔d>M/1*-?L\n:7"@>y IU~VI3LR?2mDRʲkڲpŻ_l?wOag LwgWD^xBrؾ ~Tʊ؁`;Xjn*=zow{{?JyͣW7xǩtJ)jHe|{RP$SOR4Et vX_x'?ߒhq{ L0ύ;SflH;$WP B+[VD֠⡪LK"t+Ϯbg|2 L;Qze, D[D"HJdD"KL&22kH⬦B !y.noes3x(֜X.TfY7=΀ĔCzI˭_;C|-m/r8w|}1C5)grP?ˋ˗+$sn|p2q C.}ACRInyYNR7h%;FӻRWU)kQ+"`jiXO!! d"#-ך-A@ 2iY9Zrrߞ6|k2\uY@KY`h|Ȥ^8!cҽSHzg=2AIfZTxM5W! O>$yf\_vt} ӿ:p QQz ?/t%4&!vk5#5,9˪͚ K&%+ίF QЍ[A"]WC|QlgcU㥟TnIQ+,1pfZh~i Np*PH]aP';)JuF`dY!@ëW WgG"f]R*SB@n.Nc\:/GfW8rqڈ+;g:4T].25{2G0('GЙx6󽌟`cg{fgTV>cNϴHѤ6bpC0$Ki==eM*4LfKk-3rp-0as ]DMԲdc* _ѳ)xAjzVTVTThʴȆƃha5 ګ:@:qJ~t3Ҟ[{sgzI39]G 3?H:Ro Sε&QR%&N>ɱ'F|#=,ĸ; ѝg&'$ !~u*|xPbiyHIå'3 tmqcEC_E U 1f[MK8beLM|jkj8Q2a%\nt|{S[7JW5WP?U¶ѝeG,z "`mLb)K&Nn:?ZG;lry4+c:?maXї%uĪav "%tIHeյf pQғi`'P+{=CwZ^Y(@T,*%ٝѥn@(^{ 7G|םӍQ|cH#x{9XVY+lnPUXW Aǿ~>pL^yf('ߞPZEOё z?~ p4=*!FMos,kd*@B;$ͭie&g\hlt8_ib@:k8VK2jEuA6*5sW]2j '/m v!qU;Ii̷ٺSE˃\-VԆ"^ܠjRPI9b(ĚSmmKSsz9)!B|I>P)*ż$uf#C3YֿC6+#e(c90qPmֿDOTERB$ !lnG»ѿ'xg(@{?s ~~~Ðy<$aR6ɬ]e6 +^qB}`^̃b aYuQ&u*H[CCg<_GzNၺͰ>@R#h> ȫ);(xUM6"U`@?Fp^]Ss50yPsd9gosy!TBh|%y!O/3~@H.e dRh euQU h/We7;ݹ+Q7zZ.:!T\(oԶ okMuM mZȄk-e4Givnq`=WC8L/u [V#6S#m# bXʣC ~q/q4򝰰wvNCΖQp83ޭRO s4SN-29Щrͭ_܀t#&8-CFn4d*d(I w܇V^mT-6S@LF] WPᜤacZk{SC[{jS!mǿ2~S9ucb3rL%:] ߨ@UA|r_/09Z0'E-]k%{R$~|f[ϝ E`fϹ7;W?8?6q..CԳ9eO!r,hb46H΄a6kw$\ p=9qVl`!ڎvp/W'cc6ߣpZ^Ypjݤ+@.[b$͋ `/^<6rL=^+zϮk29>7QȄhG!c[~O$=uC\K)u(:^a|W6H踒`#fp~zF^$U9bu b#$ KNɑI'呅8aµ_/^TrE[)0%| r`5Vu1[ mLuAw㶣 }On!qu w(EӴKGX#苾T^tq(D̒zN'"_HpUO>H6+(3yN-Q(*|m0 D0kӋ}薙 ]@dўsVG6hK5$Tk'xIvg] O1)wج>1wOT2|o>.Sjy;7OGxo@h~B8AQ[wm@~y{o8KJ-'% }1ϰ` 16} endstream endobj 11 0 obj <> endobj 29 0 obj <>stream x{lSeƿuMH:E!QW`%32DK٥wlnm_X7n LB0*d$cp&~'9aP2矓{ޏB4DQTfCk)gv\X#.%iVwq6CԨ!tP)bK2.Gal~)(+ W^fԤnѽ2nKE^ i54UԷ+km Bl?rBhX^Y]{|h z mCy8$@Qi(("L8cM`w:t|EܦVIʕBiVɧ /%嬴L۵LӍ]on-Z~䍉[{2?L\3EH!8]1c,98seT(F^WRvk;61]]A;ev[osq(ߍcU`^9p~_\[)u6l,g],qVv7pkك!`NK藾-&LI4!d`Ak׼Vb+Jh-A?'!cO9ELJ;|6iY(wu6h` ~5 L]%=Vȡ z{tQ닒*`UKpNCV>rޒ9NȈ$1@Uok*{; *I?{tv|W0_G/ qDsYMn#,87˿\8[{/rC{#l ?(\\J9Hgipw;F4AıSqK_= y'^+\-%a`b1PD7,)0䌓2,R-ɜ3y4eqV-d:F4%]ǁ yE7FA)AH?C B_S taֹl[$V])~ۮ$ :-S\lW"jNʼ4xNr(BgZ8<@,!o.Ņd<ԑ]ٝAvNdbyUBՔ endstream endobj 9 0 obj <> endobj 30 0 obj <>stream xUyTSWwoDK jUF;u*Vp#KI $EY QxԢ@]sպU-HΌ9xǼ`g:Ιx}}oee}6gBµYɞ9TV%%!!RA_ uo]vscmsΝJcХ w%~Z P祧jf,mNZ7:=;1?/(F `Ko_fQ7nݼ%a3d23,&ü̈́0b3 wwoE ˼!x3wl<{+īM2M =X*=-஡7P1*~Uľ^yBW::ش,P*mo&=`?@>|%|sYjXJgJON /~Kr7a=i'i"۰`/<1}OAϪ;حGmFsD\~=~~i z;qRUQǠR>eoWȞ='dzNV`,6i]پhH93w uV.UBZᶆ Foti;a=}@g#ʒeOy`ie CX Q\!R 6dk3*}է\6}NaH^{A=Pw9Wb91Sm~SL]t 4 fљ vH'pO`4A& f *EQJ^iمݥH'y僑KG"R0swzνmnRzTcQAC# EPA%c'U(pT^n2֌Wn3D ceī6~8'!R+~^.w%dIi0Y+<yNB:#zd1b)ŃbPX58Y'n<`贎`a ң~QԡrGD¤4U9HB vku>8'b\k4T-&i6-fDcN*ѥ<xܙC)δvcUj=ijK-Ѝ`bp|8 KOj/=u0%tlj.] c~]ܯ>stream 2018-09-14T08:22:48-04:00 2018-09-14T08:22:48-04:00 UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 35 0000000000 65535 f 0000002638 00000 n 0000021958 00000 n 0000002572 00000 n 0000002250 00000 n 0000000015 00000 n 0000001849 00000 n 0000002703 00000 n 0000004734 00000 n 0000018211 00000 n 0000004329 00000 n 0000016677 00000 n 0000003728 00000 n 0000010079 00000 n 0000003501 00000 n 0000008321 00000 n 0000002941 00000 n 0000005041 00000 n 0000003316 00000 n 0000002744 00000 n 0000002774 00000 n 0000002410 00000 n 0000001869 00000 n 0000002230 00000 n 0000002859 00000 n 0000002889 00000 n 0000005377 00000 n 0000008618 00000 n 0000010521 00000 n 0000016941 00000 n 0000018468 00000 n 0000003394 00000 n 0000004219 00000 n 0000004646 00000 n 0000020537 00000 n trailer << /Size 35 /Root 1 0 R /Info 2 0 R /ID [] >> startxref 22081 %%EOF softflowd-softflowd-1.0.0/softflowd.8000066400000000000000000000333521352553127000176350ustar00rootroot00000000000000.\" Copyright (c) 2002 Damien Miller. All rights reserved. .\" Portions Copyright (c) 2001 Kevin Steves. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. .\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd July 15, 2019 .Dt SOFTFLOWD 8 .Os .Sh NAME .Nm softflowd .Nd Traffic flow monitoring .Sh SYNOPSIS .Nm softflowd .Op Fl 6dDhbal .Op Fl L Ar hoplimit .Op Fl T Ar track_level .Op Fl c Ar ctl_sock .Bk -words .Oo Fl i\ \& .Sm off .Oo Ar if_ndx : Oc .Ar interface .Sm on .Oc .Ek .Op Fl m Ar max_flows .Op Fl n Ar host:port .Op Fl p Ar pidfile .Op Fl r Ar pcap_file .Op Fl t Ar timeout_name=seconds .Op Fl v Ar netflow_version .Op Fl P Ar transport_protocol .Op Fl A Ar time_format .Op Fl s Ar sampling_rate .Op Fl C Ar capture_length .Op Fl R Ar receive_port .Op bpf_expression .Sh DESCRIPTION .Nm is a software implementation of a flow-based network traffic monitor. .Nm reads network traffic and gathers information about active traffic flows. A "traffic flow" is communication between two IP addresses or (if the overlying protocol is TCP or UDP) address/port tuples. .Pp The intended use of .Nm is as a software implementation of Cisco's NetFlow(tm) traffic account system. .Nm supports data export using versions 1, 5, 9 or 10 (a.k.a. IPFIX) of the NetFlow protocol. .Nm can also run in statistics-only mode, where it just collects summary information. However, too few statistics are collected to make this mode really useful for anything other than debugging. .Pp Network traffic may be obtained by listening on a promiscuous network interface or by reading stored .Xr pcap 3 files, such as those written by .Xr tcpdump 8 . Traffic may be filtered with an optional .Xr bpf 4 program, specified on the command-line as .Ar bpf_expression . .Nm is IPv6 capable and will track IPv6 flows if the NetFlow export protocol supports it (currently only NetFlow v.9 possesses an IPv6 export capability). .Pp .Nm tries to track only active traffic flows. When the flow has been quiescent for a period of time it is expired automatically. Flows may also be expired early if they approach their traffic counts exceed 2 Gib or if the number of flows being tracked exceeds .Ar max_flows (default: 8192). In this last case, flows are expired oldest-first. .Pp Upon expiry, the flow information is accumulated into statistics which may be viewed using .Xr softflowctl 8 . If the .Fl n option has been specified the flow information is formatted in a UDP datagram which is compatible with versions 1, 5 or 9 of Cisco's NetFlow(tm) accounting export format. These records are sent to the specified .Ar host and .Ar port . The host may represent a unicast host or a multicast group. .Pp The command-line options are as follows: .Bl -tag -width Ds .It Fl n Ar host:port Specify the .Ar host and .Ar port that the accounting datagrams are to be sent to. The host may be specified using a hostname or using a numeric IPv4 or IPv6 address. Numeric IPv6 addresses should be enclosed in square brackets to avoid ambiguity between the address and the port. The destination port may be a portname listed in .Xr services 5 or a numeric port. Comma can be used for specifying multiple destinations. .It Fl i Xo .Sm off .Oo Ar if_ndx : Oc .Ar interface .Sm on .Xc Specify a network interface on which to listen for traffic. Either the .Fl i or the .Fl r options must be specified. .It Fl r Ar pcap_file Specify that .Nm should read from a .Xr pcap 3 packet capture file (such as one created with the .Fl w option of .Xr tcpdump 8 ) file rather than a network interface. .Nm processes the whole capture file and only expires flows when .Ar max_flows is exceeded. In this mode, .Nm will not fork and will automatically print summary statistics before exiting. .It Fl p Ar pidfile Specify an alternate location to store the process ID when in daemon mode. Default is .Pa /var/run/softflowd.pid .It Fl c Ar ctlsock Specify an alternate location for the remote control socket in daemon mode. Default is .Pa /var/run/softflowd.ctl .It Fl m Ar max_flows Specify the maximum number of flows to concurrently track. If this limit is exceeded, the flows which have least recently seen traffic are forcibly expired. In practice, the actual maximum may briefly exceed this limit by a small amount as expiry processing happens less frequently than traffic collection. The default is 8192 flows, which corresponds to slightly less than 800k of working data. .It Fl t Ar timeout_name=time Set the timeout names .Ar timeout_name to .Ar time . Refer to the .Sx Timeouts section for the valid timeout names and their meanings. The .Ar time parameter may be specified using one of the formats explained in the .Sx Time Formats section below. .It Fl d Specify that .Nm should not fork and daemonise itself. .It Fl 6 Force .Nm to track IPv6 flows even if the NetFlow export protocol does not support reporting them. This is useful for debugging and statistics gathering only. .It Fl D Places .Nm in a debugging mode. This implies the .Fl d and .Fl 6 flags and turns on additional debugging output. .It Fl b Bidirectional mode in IPFIX (-b work with -v 10) .It Fl a Adjusting time for reading pcap file (-a work with -r) .It Fl l Load balancing mode for multiple destinations which are specified with -n .It Fl h Display command-line usage information. .It Fl L Ar hoplimit Set the IPv4 TTL or the IPv6 hop limit to .Ar hoplimit . .Nm will use the default system TTL when exporting flows to a unicast host. When exporting to a multicast group, the default TTL will be 1 (i.e. link-local). .It Fl T Ar track_level Specify which flow elements .Nm should be used to define a flow. .Ar track_level may be one of: .Dq ether (track everything including source and destination addresses, source and destination port, source and destination ethernet address, vlanid and protocol), .Dq vlan (track source and destination addresses, source and destination port, vlanid and protocol), .Dq full (track source and destination addresses, source and destination port and protocol in the flow, the default), .Dq proto (track source and destination addresses and protocol), or .Dq ip (only track source and destination addresses). Selecting either of the latter options will produce flows with less information in them (e.g. TCP/UDP ports will not be recorded). This will cause flows to be consolidated, reducing the quantity of output and CPU load that .Nm will place on the system at the cost of some detail being lost. .It Fl v Ar netflow_version Specify which version of the NetFlow(tm) protocol .Nm should use for export of the flow data. Supported versions are 1, 5, 9, 10(IPFIX), and psamp. Default is version 5. .It Fl P Ar transport_protocol Specify transport layer protocol for exporting packets. Supported transport layer protocols are udp, tcp, and sctp. .It Fl A Ar time_format Specify absolute time format form exporting records. Supported time formats are sec, milli, micro, and nano. .It Fl s Ar sampling_rate Specify periodical sampling rate (denominator). .It Fl C Ar capture_length Specify length for packet capture (snaplen). .It Fl R Ar receive_port Specify port number for PSAMP receive mode. .El .Pp Any further command-line arguments will be concatenated together and applied as a .Xr bpf 4 packet filter. This filter will cause .Nm to ignore the specified traffic. .Ss Timeouts .Pp .Nm will expire quiescent flows after user-configurable periods. The exact timeout used depends on the nature of the flow. The various timeouts that may be set from the command-line (using the .Fl t option) and their meanings are: .Bl -tag -width Ds .It Ar general This is the general timeout applied to all traffic unless overridden by one of the other timeouts. .It Ar tcp This is the general TCP timeout, applied to open TCP connections. .It Ar tcp.rst This timeout is applied to a TCP connection when a RST packet has been sent by one or both endpoints. .It Ar tcp.fin This timeout is applied to a TCP connection when a FIN packet has been sent by both endpoints. .It Ar udp This is the general UDP timeout, applied to all UDP connections. .It Ar maxlife This is the maximum lifetime that a flow may exist for. All flows are forcibly expired when they pass .Ar maxlife seconds. To disable this feature, specify a .Ar maxlife of 0. .It Ar expint Specify the interval between expiry checks. Increase this to group more flows into a NetFlow packet. To disable this feature, specify a .Ar expint of 0. .El .Pp Flows may also be expired if there are not enough flow entries to hold them or if their traffic exceeds 2 Gib in either direction. .Xr softflowctl 8 may be used to print information on the average lifetimes of flows and the reasons for their expiry. .Ss Time Formats .Pp .Nm command-line arguments that specify time may be expressed using a sequence of the form: .Sm off .Ar time Op Ar qualifier , .Sm on where .Ar time is a positive integer value and .Ar qualifier is one of the following: .Pp .Bl -tag -width Ds -compact -offset indent .It Cm seconds .It Cm s | Cm S seconds .It Cm m | Cm M minutes .It Cm h | Cm H hours .It Cm d | Cm D days .It Cm w | Cm W weeks .El .Pp Each member of the sequence is added together to calculate the total time value. .Pp Time format examples: .Pp .Bl -tag -width Ds -compact -offset indent .It 600 600 seconds (10 minutes) .It 10m 10 minutes .It 1h30m 1 hour 30 minutes (90 minutes) .El .Ss Run-time Control .Pp A daemonised .Nm instance may be controlled using the .Xr softflowctl 8 command. This interface allows one to shut down the daemon, force expiry of all tracked flows and extract debugging and summary data. Also, receipt of a .Dv SIGTERM or .Dv SIGINT will cause .Nm to exit, after expiring all flows (and thus sending flow export packets if .Fl n was specified on the command-line). If you do not want to export flows upon shutdown, clear them first with .Xr softflowctl 8 or use .Xr softflowctl 8 's .Dq exit command. .Sh EXAMPLES .Bl -tag -width Ds .It softflowd -i fxp0 This command-line will cause .Nm to listen on interface fxp0 and to run in statistics gathering mode only (i.e. no NetFlow data export). .It softflowd -i fxp0 -n 10.1.0.2:4432 This command-line will cause .Nm to listen on interface fxp0 and to export NetFlow v.5 datagrams on flow expiry to a flow collector running on 10.1.0.2 port 4432. .It softflowd -i fxp0 -n 10.1.0.2:4432,10.1.0.3:4432 This command-line will cause .Nm to listen on interface fxp0 and to export NetFlow v.5 datagrams on flow expiry to a flow collector running on 10.1.0.2 port 4432 and 10.1.0.3 port 4432. .It softflowd -i fxp0 -l -n 10.1.0.2:4432,10.1.0.3:4432 This command-line will cause .Nm to listen on interface fxp0 and to export NetFlow v.5 datagrams on flow expiry to a flow collector running on 10.1.0.2 port 4432 and 10.1.0.3 port 4432 with load balncing mode. Odd netflow packets will be sent to 10.1.0.2 port 4432 and even netflow packets will be sent to 10.1.0.3 port 4432. .It softflowd -v 5 -i fxp0 -n 10.1.0.2:4432 -m 65536 -t udp=1m30s This command-line increases the number of concurrent flows that .Nm will track to 65536 and increases the timeout for UDP flows to 90 seconds. .It softflowd -v 9 -i fxp0 -n 224.0.1.20:4432 -L 64 This command-line will export NetFlow v.9 flows to the multicast group 224.0.1.20. The export datagrams will have their TTL set to 64, so multicast receivers can be many hops away. .It softflowd -i fxp0 -p /var/run/sfd.pid.fxp0 -c /var/run/sfd.ctl.fxp0 This command-line specifies alternate locations for the control socket and pid file. Similar command-lines are useful when running multiple instances of .Nm on a single machine. .El .Sh FILES .Bl -tag -width Ds .It Pa /var/run/softflowd.pid This file stores the process ID when .Nm is in daemon mode. This location may be overridden using the .Fl p command-line option. .It Pa /var/run/softflowd.ctl This is the remote control socket. .Nm listens on this socket for commands from .Xr softflowctl 8 . This location may be overridden using the .Fl c command-line option. .El .Sh BUGS Currently .Nm does not handle maliciously fragmented packets properly, i.e. packets fragemented such that the UDP or TCP header does not fit into the first fragment. It will product correct traffic counts when presented with maliciously fragmented packets, but will not record TCP or UDP port information. Please report bugs in softflowd to https://github.com/irino/softflowd/issues .Sh AUTHORS .An Damien Miller Aq djm@mindrot.org .An Hitoshi Irino (current maintainer) Aq irino@sfc.wide.ad.jp .Sh SEE ALSO .Xr softflowctl 8 , .Xr tcpdump 8 , .Xr pcap 3 , .Xr bpf 4 .Bd -literal http://www.ietf.org/rfc/rfc3954.txt .br http://www.cisco.com/en/US/products/sw/netmgtsw/ps1964/products_implementation_design_guide09186a00800d6a11.html http://www.ietf.org/rfc/rfc5101.txt .br http://www.ietf.org/rfc/rfc5103.txt .br .Ed softflowd-softflowd-1.0.0/softflowd.c000066400000000000000000002226671352553127000177210ustar00rootroot00000000000000/* * Copyright 2002 Damien Miller All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * This is software implementation of Cisco's NetFlow(tm) traffic * reporting system. It operates by listening (via libpcap) on a * promiscuous interface and tracking traffic flows. * * Traffic flows are recorded by source/destination/protocol * IP address or, in the case of TCP and UDP, by * src_addr:src_port/dest_addr:dest_port/protocol * * Flows expire automatically after a period of inactivity (default: 1 * hour) They may also be evicted (in order of age) in situations where * there are more flows than slots available. * * Netflow compatible packets are sent to a specified target host upon * flow expiry. * * As this implementation watches traffic promiscuously, it is likely to * place significant load on hosts or gateways on which it is installed. */ #include "common.h" #include "sys-tree.h" #include "convtime.h" #include "softflowd.h" #include "treetype.h" #include "freelist.h" #include "log.h" #include "netflow9.h" #include "ipfix.h" #include "psamp.h" #include #define IPFIX_PORT 4739 /* Global variables */ static int verbose_flag = 0; /* Debugging flag */ static u_int16_t if_index = 0; /* "manual" interface index */ static int track_level; static int snaplen = 0; #ifdef ENABLE_PTHREAD pthread_mutex_t read_mutex; pthread_cond_t read_cond; int use_thread; u_char packet_data[1500]; struct pcap_pkthdr packet_header; struct FLOW *send_expired_flows; #endif /* ENABLE_PTHREAD */ /* Signal handler flags */ static volatile sig_atomic_t graceful_shutdown_request = 0; /* Describes a datalink header and how to extract v4/v6 frames from it */ struct DATALINK { int dlt; /* BPF datalink type */ int skiplen; /* Number of bytes to skip datalink header */ int ft_off; /* Datalink frametype offset */ int ft_len; /* Datalink frametype length */ int ft_is_be; /* Set if frametype is big-endian */ u_int32_t ft_mask; /* Mask applied to frametype */ u_int32_t ft_v4; /* IPv4 frametype */ u_int32_t ft_v6; /* IPv6 frametype */ }; /* Datalink types that we know about */ static const struct DATALINK lt[] = { {DLT_EN10MB, 14, 12, 2, 1, 0xffffffff, 0x0800, 0x86dd}, {DLT_PPP, 5, 3, 2, 1, 0xffffffff, 0x0021, 0x0057}, #ifdef DLT_LINUX_SLL {DLT_LINUX_SLL, 16, 14, 2, 1, 0xffffffff, 0x0800, 0x86dd}, #endif {DLT_RAW, 0, 0, 1, 1, 0x000000f0, 0x0040, 0x0060}, {DLT_NULL, 4, 0, 4, 0, 0xffffffff, AF_INET, AF_INET6}, #ifdef DLT_LOOP {DLT_LOOP, 4, 0, 4, 1, 0xffffffff, AF_INET, AF_INET6}, #endif #ifdef DLT_PFLOG {DLT_PFLOG, 48, 1, 1, 0, 0x000000ff, AF_INET, AF_INET6}, #endif {-1, -1, -1, -1, -1, 0x00000000, 0xffff, 0xffff}, }; /* Netflow send functions */ typedef int (netflow_send_func_t) (struct SENDPARAMETER); struct NETFLOW_SENDER { int version; netflow_send_func_t *func; netflow_send_func_t *bidir_func; int v6_capable; }; /* Array of NetFlow export function that we know of. NB. nf[0] is default */ static const struct NETFLOW_SENDER nf[] = { {5, send_netflow_v5, NULL, 0}, {1, send_netflow_v1, NULL, 0}, #ifdef ENABLE_LEGACY {9, send_netflow_v9, NULL, 1}, #else /* ENABLE_LEGACY */ {9, send_nflow9, NULL, 1}, #endif /* ENABLE_LEGACY */ {NF_VERSION_IPFIX, send_ipfix, send_ipfix_bi, 1}, #ifdef ENABLE_NTOPNG {SOFTFLOWD_NF_VERSION_NTOPNG, send_ntopng, NULL, 1}, #endif }; static const struct NETFLOW_SENDER * lookup_netflow_sender (int version) { int i, r; for (i = 0, r = version; i < sizeof (nf) / sizeof (struct NETFLOW_SENDER); i++) { if (nf[i].version == r) return &nf[i]; } return NULL; } /* Signal handlers */ static void sighand_graceful_shutdown (int signum) { graceful_shutdown_request = signum; } static void sighand_other (int signum) { /* XXX: this may not be completely safe */ logit (LOG_WARNING, "Exiting immediately on unexpected signal %d", signum); _exit (0); } /* * This is the flow comparison function. */ static int flow_compare (struct FLOW *a, struct FLOW *b) { /* Be careful to avoid signed vs unsigned issues here */ int r; if (track_level == TRACK_FULL_VLAN || track_level == TRACK_FULL_VLAN_ETHER) { if (a->vlanid[0] != b->vlanid[0]) return (a->vlanid[0] > b->vlanid[0] ? 1 : -1); if (a->vlanid[1] != b->vlanid[1]) return (a->vlanid[1] > b->vlanid[1] ? 1 : -1); } if (track_level == TRACK_FULL_VLAN_ETHER) { if ((r = memcmp (&a->ethermac[0], &b->ethermac[0], 6)) != 0) return (r > 0 ? 1 : -1); if ((r = memcmp (&a->ethermac[1], &b->ethermac[1], 6)) != 0) return (r > 0 ? 1 : -1); } if (a->af != b->af) return (a->af > b->af ? 1 : -1); if ((r = memcmp (&a->addr[0], &b->addr[0], sizeof (a->addr[0]))) != 0) return (r > 0 ? 1 : -1); if ((r = memcmp (&a->addr[1], &b->addr[1], sizeof (a->addr[1]))) != 0) return (r > 0 ? 1 : -1); #ifdef notyet if (a->ip6_flowlabel[0] != 0 && b->ip6_flowlabel[0] != 0 && a->ip6_flowlabel[0] != b->ip6_flowlabel[0]) return (a->ip6_flowlabel[0] > b->ip6_flowlabel[0] ? 1 : -1); if (a->ip6_flowlabel[1] != 0 && b->ip6_flowlabel[1] != 0 && a->ip6_flowlabel[1] != b->ip6_flowlabel[1]) return (a->ip6_flowlabel[1] > b->ip6_flowlabel[1] ? 1 : -1); #endif if (a->protocol != b->protocol) return (a->protocol > b->protocol ? 1 : -1); if (a->port[0] != b->port[0]) return (ntohs (a->port[0]) > ntohs (b->port[0]) ? 1 : -1); if (a->port[1] != b->port[1]) return (ntohs (a->port[1]) > ntohs (b->port[1]) ? 1 : -1); return (0); } /* Generate functions for flow tree */ FLOW_PROTOTYPE (FLOWS, FLOW, trp, flow_compare); FLOW_GENERATE (FLOWS, FLOW, trp, flow_compare); /* * This is the expiry comparison function. */ static int expiry_compare (struct EXPIRY *a, struct EXPIRY *b) { if (a->expires_at != b->expires_at) return (a->expires_at > b->expires_at ? 1 : -1); /* Make expiry entries unique by comparing flow sequence */ if (a->flow->flow_seq != b->flow->flow_seq) return (a->flow->flow_seq > b->flow->flow_seq ? 1 : -1); return (0); } /* Generate functions for flow tree */ EXPIRY_PROTOTYPE (EXPIRIES, EXPIRY, trp, expiry_compare); EXPIRY_GENERATE (EXPIRIES, EXPIRY, trp, expiry_compare); static struct FLOW * flow_get (struct FLOWTRACK *ft) { return freelist_get (&ft->flow_freelist); } static void flow_put (struct FLOWTRACK *ft, struct FLOW *flow) { return freelist_put (&ft->flow_freelist, flow); } static struct EXPIRY * expiry_get (struct FLOWTRACK *ft) { return freelist_get (&ft->expiry_freelist); } static void expiry_put (struct FLOWTRACK *ft, struct EXPIRY *expiry) { return freelist_put (&ft->expiry_freelist, expiry); } #if 0 /* Dump a packet */ static void dump_packet (const u_int8_t * p, int len) { char buf[1024], tmp[3]; int i; for (*buf = '\0', i = 0; i < len; i++) { snprintf (tmp, sizeof (tmp), "%02x%s", p[i], i % 2 ? " " : ""); if (strlcat (buf, tmp, sizeof (buf) - 4) >= sizeof (buf) - 4) { strlcat (buf, "...", sizeof (buf)); break; } } logit (LOG_INFO, "packet len %d: %s", len, buf); } #endif /* Format a time in an ISOish format */ static const char * format_time (time_t t) { struct tm *tm; static char buf[32]; tm = gmtime (&t); strftime (buf, sizeof (buf), "%Y-%m-%dT%H:%M:%S", tm); return (buf); } static const char * format_ethermac (uint8_t ethermac[6]) { static char buf[1024]; snprintf (buf, sizeof (buf), "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", ethermac[0], ethermac[1], ethermac[2], ethermac[3], ethermac[4], ethermac[5]); return buf; } /* Format a flow in a verbose and ugly way */ static const char * format_flow (struct FLOW *flow) { char addr1[64], addr2[64], start_time[32], fin_time[32]; static char buf[1024]; inet_ntop (flow->af, &flow->addr[0], addr1, sizeof (addr1)); inet_ntop (flow->af, &flow->addr[1], addr2, sizeof (addr2)); snprintf (start_time, sizeof (start_time), "%s", format_time (flow->flow_start.tv_sec)); snprintf (fin_time, sizeof (fin_time), "%s", format_time (flow->flow_last.tv_sec)); snprintf (buf, sizeof (buf), "seq:%" PRIu64 " [%s]:%hu <> [%s]:%hu proto:%u " "octets>:%u packets>:%u octets<:%u packets<:%u " "start:%s.%03ld finish:%s.%03ld tcp>:%02x tcp<:%02x " "flowlabel>:%08x flowlabel<:%08x " "vlan>:%u vlan<:%u ether:%s <> %s", flow->flow_seq, addr1, ntohs (flow->port[0]), addr2, ntohs (flow->port[1]), (int) flow->protocol, flow->octets[0], flow->packets[0], flow->octets[1], flow->packets[1], start_time, (flow->flow_start.tv_usec + 500) / 1000, fin_time, (flow->flow_last.tv_usec + 500) / 1000, flow->tcp_flags[0], flow->tcp_flags[1], flow->ip6_flowlabel[0], flow->ip6_flowlabel[1], flow->vlanid[0], flow->vlanid[1], format_ethermac (flow->ethermac[0]), format_ethermac (flow->ethermac[1])); return (buf); } /* Format a flow in a brief way */ static const char * format_flow_brief (struct FLOW *flow) { char addr1[64], addr2[64]; static char buf[1024]; inet_ntop (flow->af, &flow->addr[0], addr1, sizeof (addr1)); inet_ntop (flow->af, &flow->addr[1], addr2, sizeof (addr2)); snprintf (buf, sizeof (buf), "seq:%" PRIu64 " [%s]:%hu <> [%s]:%hu proto:%u " "vlan>:%u vlan<:%u ether:%s <> %s ", flow->flow_seq, addr1, ntohs (flow->port[0]), addr2, ntohs (flow->port[1]), (int) flow->protocol, flow->vlanid[0], flow->vlanid[1], format_ethermac (flow->ethermac[0]), format_ethermac (flow->ethermac[1])); return (buf); } /* Fill in transport-layer (tcp/udp) portions of flow record */ static int transport_to_flowrec (struct FLOW *flow, const u_int8_t * pkt, const size_t caplen, int isfrag, int protocol, int ndx) { const struct tcphdr *tcp = (const struct tcphdr *) pkt; const struct udphdr *udp = (const struct udphdr *) pkt; const struct icmp *icmp = (const struct icmp *) pkt; /* * XXX to keep flow in proper canonical format, it may be necessary to * swap the array slots based on the order of the port numbers does * this matter in practice??? I don't think so - return flows will * always match, because of their symmetrical addr/ports */ switch (protocol) { case IPPROTO_TCP: /* Check for runt packet, but don't error out on short frags */ if (caplen < sizeof (*tcp)) return (isfrag ? 0 : 1); flow->port[ndx] = tcp->th_sport; flow->port[ndx ^ 1] = tcp->th_dport; flow->tcp_flags[ndx] |= tcp->th_flags; break; case IPPROTO_UDP: /* Check for runt packet, but don't error out on short frags */ if (caplen < sizeof (*udp)) return (isfrag ? 0 : 1); flow->port[ndx] = udp->uh_sport; flow->port[ndx ^ 1] = udp->uh_dport; break; case IPPROTO_ICMP: case IPPROTO_ICMPV6: /* * Encode ICMP type * 256 + code into dest port like * Cisco routers */ flow->port[ndx] = 0; flow->port[ndx ^ 1] = htons (icmp->icmp_type * 256 + icmp->icmp_code); break; } return (0); } static int make_ndx_ipv4 (const struct ip *ip, size_t caplen) { if (caplen < 20 || caplen < ip->ip_hl * 4) return (-1); /* Runt packet */ if (ip->ip_v != 4) return (-1); /* Unsupported IP version */ /* Prepare to store flow in canonical format */ return (memcmp (&ip->ip_src, &ip->ip_dst, sizeof (ip->ip_src)) > 0 ? 1 : 0); } /* Convert a IPv4 packet to a partial flow record (used for comparison) */ static int ipv4_to_flowrec (struct FLOW *flow, const u_int8_t * pkt, size_t caplen, size_t len, int *isfrag, int af, int ndx) { const struct ip *ip = (const struct ip *) pkt; //int ndx = make_ndx_ipv4 (ip, caplen); if (ndx < 0) return (-1); flow->af = af; flow->addr[ndx].v4 = ip->ip_src; flow->addr[ndx ^ 1].v4 = ip->ip_dst; flow->protocol = ip->ip_p; flow->octets[ndx] = len; flow->packets[ndx] = 1; flow->tos[ndx] = ip->ip_tos; *isfrag = (ntohs (ip->ip_off) & (IP_OFFMASK | IP_MF)) ? 1 : 0; /* Don't try to examine higher level headers if not first fragment */ if (*isfrag && (ntohs (ip->ip_off) & IP_OFFMASK) != 0) return (0); return (transport_to_flowrec (flow, pkt + (ip->ip_hl * 4), caplen - (ip->ip_hl * 4), *isfrag, ip->ip_p, ndx)); } static int make_ndx_ipv6 (const struct ip6_hdr *ip6, size_t caplen) { if (caplen < sizeof (*ip6)) return (-1); /* Runt packet */ if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) return (-1); /* Unsupported IPv6 version */ /* Prepare to store flow in canonical format */ return (memcmp (&ip6->ip6_src, &ip6->ip6_dst, sizeof (ip6->ip6_src)) > 0 ? 1 : 0); } /* Convert a IPv6 packet to a partial flow record (used for comparison) */ static int ipv6_to_flowrec (struct FLOW *flow, const u_int8_t * pkt, size_t caplen, size_t len, int *isfrag, int af, int ndx) { const struct ip6_hdr *ip6 = (const struct ip6_hdr *) pkt; const struct ip6_ext *eh6; const struct ip6_frag *fh6; int nxt; if (ndx < 0) return (-1); flow->af = af; flow->ip6_flowlabel[ndx] = ip6->ip6_flow & IPV6_FLOWLABEL_MASK; flow->addr[ndx].v6 = ip6->ip6_src; flow->addr[ndx ^ 1].v6 = ip6->ip6_dst; flow->octets[ndx] = len; flow->packets[ndx] = 1; flow->tos[ndx] = (ntohl (ip6->ip6_flow) & ntohl (0x0ff00000)) >> 20; *isfrag = 0; nxt = ip6->ip6_nxt; pkt += sizeof (*ip6); caplen -= sizeof (*ip6); /* Now loop through headers, looking for transport header */ for (;;) { eh6 = (const struct ip6_ext *) pkt; if (nxt == IPPROTO_HOPOPTS || nxt == IPPROTO_ROUTING || nxt == IPPROTO_DSTOPTS) { if (caplen < sizeof (*eh6) || caplen < (eh6->ip6e_len + 1) << 3) return (1); /* Runt */ nxt = eh6->ip6e_nxt; pkt += (eh6->ip6e_len + 1) << 3; caplen -= (eh6->ip6e_len + 1) << 3; } else if (nxt == IPPROTO_FRAGMENT) { *isfrag = 1; fh6 = (const struct ip6_frag *) eh6; if (caplen < sizeof (*fh6)) return (1); /* Runt */ /* * Don't try to examine higher level headers if * not first fragment */ if ((fh6->ip6f_offlg & IP6F_OFF_MASK) != 0) return (0); nxt = fh6->ip6f_nxt; pkt += sizeof (*fh6); caplen -= sizeof (*fh6); } else break; } flow->protocol = nxt; return (transport_to_flowrec (flow, pkt, caplen, *isfrag, nxt, ndx)); } static int vlan_to_flowrec (struct FLOW *flow, u_int16_t vlanid, int ndx) { if (ndx < 0) return (-1); return (flow->vlanid[ndx] = vlanid); } static int ether_to_flowrec (struct FLOW *flow, struct ether_header *ether, int ndx) { if (ndx < 0) return (-1); if (ether == NULL) return (-1); memcpy (flow->ethermac[ndx], ether->ether_shost, ETH_ALEN); memcpy (flow->ethermac[ndx ^ 1], ether->ether_dhost, ETH_ALEN); return (1); } static void flow_update_expiry (struct FLOWTRACK *ft, struct FLOW *flow) { EXPIRY_REMOVE (EXPIRIES, &ft->expiries, flow->expiry); /* Flows over 2 GiB traffic */ if (flow->octets[0] > (1U << 31) || flow->octets[1] > (1U << 31)) { flow->expiry->expires_at = 0; flow->expiry->reason = R_OVERBYTES; goto out; } /* Flows over maximum life seconds */ if (ft->param.maximum_lifetime != 0 && flow->flow_last.tv_sec - flow->flow_start.tv_sec > ft->param.maximum_lifetime) { flow->expiry->expires_at = 0; flow->expiry->reason = R_MAXLIFE; goto out; } if (flow->protocol == IPPROTO_TCP) { /* Reset TCP flows */ if (ft->param.tcp_rst_timeout != 0 && ((flow->tcp_flags[0] & TH_RST) || (flow->tcp_flags[1] & TH_RST))) { flow->expiry->expires_at = flow->flow_last.tv_sec + ft->param.tcp_rst_timeout; flow->expiry->reason = R_TCP_RST; goto out; } /* Finished TCP flows */ if (ft->param.tcp_fin_timeout != 0 && ((flow->tcp_flags[0] & TH_FIN) && (flow->tcp_flags[1] & TH_FIN))) { flow->expiry->expires_at = flow->flow_last.tv_sec + ft->param.tcp_fin_timeout; flow->expiry->reason = R_TCP_FIN; goto out; } /* TCP flows */ if (ft->param.tcp_timeout != 0) { flow->expiry->expires_at = flow->flow_last.tv_sec + ft->param.tcp_timeout; flow->expiry->reason = R_TCP; goto out; } } if (ft->param.udp_timeout != 0 && flow->protocol == IPPROTO_UDP) { /* UDP flows */ flow->expiry->expires_at = flow->flow_last.tv_sec + ft->param.udp_timeout; flow->expiry->reason = R_UDP; goto out; } if (ft->param.icmp_timeout != 0 && ((flow->af == AF_INET && flow->protocol == IPPROTO_ICMP) || ((flow->af == AF_INET6 && flow->protocol == IPPROTO_ICMPV6)))) { /* ICMP flows */ flow->expiry->expires_at = flow->flow_last.tv_sec + ft->param.icmp_timeout; flow->expiry->reason = R_ICMP; goto out; } /* Everything else */ flow->expiry->expires_at = flow->flow_last.tv_sec + ft->param.general_timeout; flow->expiry->reason = R_GENERAL; out: if (ft->param.maximum_lifetime != 0 && flow->expiry->expires_at != 0) { flow->expiry->expires_at = MIN (flow->expiry->expires_at, flow->flow_start.tv_sec + ft->param.maximum_lifetime); } EXPIRY_INSERT (EXPIRIES, &ft->expiries, flow->expiry); } /* Return values from process_packet */ #define PP_OK 0 #define PP_BAD_PACKET -2 #define PP_MALLOC_FAIL -3 /* * Main per-packet processing function. Take a packet (provided by * libpcap) and attempt to find a matching flow. If no such flow exists, * then create one. * * Also marks flows for fast expiry, based on flow or packet attributes * (the actual expiry is performed elsewhere) */ static int process_packet (struct FLOWTRACK *ft, const u_int8_t * pkt, int af, const u_int32_t caplen, const u_int32_t len, struct ether_header *ether, u_int16_t vlanid, const struct timeval *received_time) { struct FLOW tmp, *flow; int frag, ndx; /* Convert the IP packet to a flow identity */ memset (&tmp, 0, sizeof (tmp)); switch (af) { case AF_INET: ndx = make_ndx_ipv4 ((const struct ip *) pkt, caplen); if (ipv4_to_flowrec (&tmp, pkt, caplen, len, &frag, af, ndx) == -1) goto bad; break; case AF_INET6: ndx = make_ndx_ipv6 ((const struct ip6_hdr *) pkt, caplen); if (ipv6_to_flowrec (&tmp, pkt, caplen, len, &frag, af, ndx) == -1) goto bad; break; default: bad: ft->param.bad_packets++; return (PP_BAD_PACKET); } if (frag) ft->param.frag_packets++; /* Zero out bits of the flow that aren't relevant to tracking level */ switch (ft->param.track_level) { case TRACK_IP_ONLY: tmp.protocol = 0; /* FALLTHROUGH */ case TRACK_IP_PROTO: tmp.port[0] = tmp.port[1] = 0; tmp.tcp_flags[0] = tmp.tcp_flags[1] = 0; /* FALLTHROUGH */ case TRACK_FULL: tmp.vlanid[0] = tmp.vlanid[1] = 0; break; case TRACK_FULL_VLAN_ETHER: ether_to_flowrec (&tmp, ether, ndx); /* FALLTHROUGH */ case TRACK_FULL_VLAN: vlan_to_flowrec (&tmp, vlanid, ndx); break; } /* If a matching flow does not exist, create and insert one */ if ((flow = FLOW_FIND (FLOWS, &ft->flows, &tmp)) == NULL) { /* Allocate and fill in the flow */ if ((flow = flow_get (ft)) == NULL) { logit (LOG_ERR, "process_packet: flow_get failed", sizeof (*flow)); return (PP_MALLOC_FAIL); } memcpy (flow, &tmp, sizeof (*flow)); memcpy (&flow->flow_start, received_time, sizeof (flow->flow_start)); flow->flow_seq = ft->param.next_flow_seq++; FLOW_INSERT (FLOWS, &ft->flows, flow); /* Allocate and fill in the associated expiry event */ if ((flow->expiry = expiry_get (ft)) == NULL) { logit (LOG_ERR, "process_packet: expiry_get failed", sizeof (*flow->expiry)); return (PP_MALLOC_FAIL); } flow->expiry->flow = flow; /* Must be non-zero (0 means expire immediately) */ flow->expiry->expires_at = 1; flow->expiry->reason = R_GENERAL; EXPIRY_INSERT (EXPIRIES, &ft->expiries, flow->expiry); ft->param.num_flows++; if (verbose_flag) logit (LOG_DEBUG, "ADD FLOW %s", format_flow_brief (flow)); } else { /* Update flow statistics */ flow->packets[0] += tmp.packets[0]; flow->octets[0] += tmp.octets[0]; flow->tcp_flags[0] |= tmp.tcp_flags[0]; flow->packets[1] += tmp.packets[1]; flow->octets[1] += tmp.octets[1]; flow->tcp_flags[1] |= tmp.tcp_flags[1]; } memcpy (&flow->flow_last, received_time, sizeof (flow->flow_last)); if (flow->expiry->expires_at != 0) flow_update_expiry (ft, flow); return (PP_OK); } /* * Subtract two timevals. Returns (t1 - t2) in milliseconds. */ u_int32_t timeval_sub_ms (const struct timeval * t1, const struct timeval * t2) { struct timeval res; res.tv_sec = t1->tv_sec - t2->tv_sec; res.tv_usec = t1->tv_usec - t2->tv_usec; if (res.tv_usec < 0) { res.tv_usec += 1000000L; res.tv_sec--; } return ((u_int32_t) res.tv_sec * 1000 + (u_int32_t) res.tv_usec / 1000); } int send_multi_destinations (int num_destinations, struct DESTINATION *destinations, u_int8_t is_loadbalance, u_int8_t * packet, int size) { struct DESTINATION *dest; int i, err; socklen_t errsz; static u_int64_t sent = 0; for (i = 0; i < num_destinations; i++) { if (!is_loadbalance || (is_loadbalance && (sent % num_destinations == i))) { dest = &destinations[i]; errsz = sizeof (err); getsockopt (dest->sock, SOL_SOCKET, SO_ERROR, &err, &errsz); // Clear ICMP errors if (send (dest->sock, packet, (size_t) size, 0) == -1) return (-1); } } sent++; return is_loadbalance ? 1 : i; } static void update_statistic (struct STATISTIC *s, double new, double n) { if (n == 1.0) { s->min = s->mean = s->max = new; return; } s->min = MIN (s->min, new); s->max = MAX (s->max, new); s->mean = s->mean + ((new - s->mean) / n); } /* Update global statistics */ static void update_statistics (struct FLOWTRACK *ft, struct FLOW *flow) { double tmp; static double n = 1.0; ft->param.flows_expired++; ft->param.flows_pp[flow->protocol % 256]++; tmp = (double) flow->flow_last.tv_sec + ((double) flow->flow_last.tv_usec / 1000000.0); tmp -= (double) flow->flow_start.tv_sec + ((double) flow->flow_start.tv_usec / 1000000.0); if (tmp < 0.0) tmp = 0.0; update_statistic (&ft->param.duration, tmp, n); update_statistic (&ft->param.duration_pp[flow->protocol], tmp, (double) ft->param.flows_pp[flow->protocol % 256]); tmp = flow->octets[0] + flow->octets[1]; update_statistic (&ft->param.octets, tmp, n); ft->param.octets_pp[flow->protocol % 256] += tmp; tmp = flow->packets[0] + flow->packets[1]; update_statistic (&ft->param.packets, tmp, n); ft->param.packets_pp[flow->protocol % 256] += tmp; n++; } static void update_expiry_stats (struct FLOWTRACK *ft, struct EXPIRY *e) { switch (e->reason) { case R_GENERAL: ft->param.expired_general++; break; case R_TCP: ft->param.expired_tcp++; break; case R_TCP_RST: ft->param.expired_tcp_rst++; break; case R_TCP_FIN: ft->param.expired_tcp_fin++; break; case R_UDP: ft->param.expired_udp++; break; case R_ICMP: ft->param.expired_icmp++; break; case R_MAXLIFE: ft->param.expired_maxlife++; break; case R_OVERBYTES: ft->param.expired_overbytes++; break; case R_OVERFLOWS: ft->param.expired_maxflows++; break; case R_FLUSH: ft->param.expired_flush++; break; } } /* How long before the next expiry event in millisecond */ static int next_expire (struct FLOWTRACK *ft) { struct EXPIRY *expiry; struct timeval now; u_int32_t expires_at, ret, fudge; if (ft->param.adjust_time) now = ft->param.last_packet_time; else gettimeofday (&now, NULL); if ((expiry = EXPIRY_MIN (EXPIRIES, &ft->expiries)) == NULL) return (-1); /* indefinite */ expires_at = expiry->expires_at; /* Don't cluster urgent expiries */ if (expires_at == 0 && (expiry->reason == R_OVERBYTES || expiry->reason == R_OVERFLOWS || expiry->reason == R_FLUSH)) return (0); /* Now */ /* Cluster expiries by expiry_interval */ if (ft->param.expiry_interval > 1) { if ((fudge = expires_at % ft->param.expiry_interval) > 0) expires_at += ft->param.expiry_interval - fudge; } if (expires_at < now.tv_sec) return (0); /* Now */ ret = 999 + (expires_at - now.tv_sec) * 1000; return (ret); } /* * Scan the tree of expiry events and process expired flows. If zap_all * is set, then forcibly expire all flows. */ #define CE_EXPIRE_NORMAL 0 /* Normal expiry processing */ #define CE_EXPIRE_ALL -1 /* Expire all flows immediately */ #define CE_EXPIRE_FORCED 1 /* Only expire force-expired flows */ static int check_expired (struct FLOWTRACK *ft, struct NETFLOW_TARGET *target, int ex) { struct FLOW **expired_flows, **oldexp; int num_expired, i, r; struct timeval now; struct EXPIRY *expiry, *nexpiry; if (ft->param.adjust_time) now = ft->param.last_packet_time; else gettimeofday (&now, NULL); r = 0; num_expired = 0; expired_flows = NULL; if (verbose_flag) logit (LOG_DEBUG, "Starting expiry scan: mode %d", ex); for (expiry = EXPIRY_MIN (EXPIRIES, &ft->expiries); expiry != NULL; expiry = nexpiry) { nexpiry = EXPIRY_NEXT (EXPIRIES, &ft->expiries, expiry); if ((expiry->expires_at == 0) || (ex == CE_EXPIRE_ALL) || (ex != CE_EXPIRE_FORCED && (expiry->expires_at < now.tv_sec))) { /* Flow has expired */ if (ft->param.maximum_lifetime != 0 && expiry->flow->flow_last.tv_sec - expiry->flow->flow_start.tv_sec >= ft->param.maximum_lifetime) expiry->reason = R_MAXLIFE; if (verbose_flag) logit (LOG_DEBUG, "Queuing flow seq:%" PRIu64 " (%p) for expiry " "reason %d", expiry->flow->flow_seq, expiry->flow, expiry->reason); /* Add to array of expired flows */ oldexp = expired_flows; expired_flows = realloc (expired_flows, sizeof (*expired_flows) * (num_expired + 1)); /* Don't fatal on realloc failures */ if (expired_flows == NULL) expired_flows = oldexp; else { expired_flows[num_expired] = expiry->flow; num_expired++; } if (ex == CE_EXPIRE_ALL) expiry->reason = R_FLUSH; update_expiry_stats (ft, expiry); /* Remove from flow tree, destroy expiry event */ FLOW_REMOVE (FLOWS, &ft->flows, expiry->flow); EXPIRY_REMOVE (EXPIRIES, &ft->expiries, expiry); expiry->flow->expiry = NULL; expiry_put (ft, expiry); ft->param.num_flows--; } } if (verbose_flag) logit (LOG_DEBUG, "Finished scan %d flow(s) to be evicted", num_expired); /* Processing for expired flows */ if (num_expired > 0) { if (target != NULL) { struct SENDPARAMETER sp = { expired_flows, num_expired, target, if_index, &ft->param, verbose_flag }; netflow_send_func_t *func = ft->param.bidirection == 1 ? target->dialect->bidir_func : target->dialect->func; if (func == NULL) { func = target->dialect->func; } #ifdef ENABLE_PTHREAD if (use_thread) { pthread_t write_thread = 0; sp.flows = calloc (num_expired, sizeof (struct FLOW)); memcpy (sp.flows, expired_flows, sizeof (struct FLOW) * num_expired); if (pthread_create (&write_thread, NULL, (void *) func, (void *) &sp) < 0) { perror ("pthread_create error"); exit (1); } if (pthread_detach (write_thread) != 0) { perror ("pthread_detach error"); exit (1); } r = 1; } else #endif /* ENABLE_PTHREAD */ r = func (sp); if (verbose_flag) logit (LOG_DEBUG, "sent %d netflow packets", r); if (r <= 0) ft->param.flows_dropped += num_expired * 2; /* XXX what if r < num_expired * 2 ? */ } for (i = 0; i < num_expired; i++) { if (verbose_flag) { logit (LOG_DEBUG, "EXPIRED: %s (%p)", format_flow (expired_flows[i]), expired_flows[i]); } update_statistics (ft, expired_flows[i]); flow_put (ft, expired_flows[i]); } free (expired_flows); } return (r == -1 ? -1 : num_expired); } /* * Force expiry of num_to_expire flows (e.g. when flow table overfull) */ static void force_expire (struct FLOWTRACK *ft, u_int32_t num_to_expire) { struct EXPIRY *expiry, **expiryv; int i; /* XXX move all overflow processing here (maybe) */ if (verbose_flag) logit (LOG_INFO, "Forcing expiry of %d flows", num_to_expire); /* * Do this in two steps, as it is dangerous to change a key on * a tree entry without first removing it and then re-adding it. * It is even worse when this has to be done during a FOREACH :) * To get around this, we make a list of expired flows and _then_ * alter them */ if ((expiryv = calloc (num_to_expire, sizeof (*expiryv))) == NULL) { /* * On malloc failure, expire ALL flows. I assume that * setting all the keys in a tree to the same value is * safe. */ logit (LOG_ERR, "Out of memory while expiring flows - " "all flows expired"); EXPIRY_FOREACH (expiry, EXPIRIES, &ft->expiries) { expiry->expires_at = 0; expiry->reason = R_OVERFLOWS; ft->param.flows_force_expired++; } return; } /* Make the list of flows to expire */ i = 0; EXPIRY_FOREACH (expiry, EXPIRIES, &ft->expiries) { if (i >= num_to_expire) break; expiryv[i++] = expiry; } if (i < num_to_expire) { logit (LOG_ERR, "Needed to expire %d flows, " "but only %d active", num_to_expire, i); num_to_expire = i; } for (i = 0; i < num_to_expire; i++) { EXPIRY_REMOVE (EXPIRIES, &ft->expiries, expiryv[i]); expiryv[i]->expires_at = 0; expiryv[i]->reason = R_OVERFLOWS; EXPIRY_INSERT (EXPIRIES, &ft->expiries, expiryv[i]); } ft->param.flows_force_expired += num_to_expire; free (expiryv); /* XXX - this is overcomplicated, perhaps use a separate queue */ } /* Delete all flows that we know about without processing */ static int delete_all_flows (struct FLOWTRACK *ft) { struct FLOW *flow, *nflow; int i; i = 0; for (flow = FLOW_MIN (FLOWS, &ft->flows); flow != NULL; flow = nflow) { nflow = FLOW_NEXT (FLOWS, &ft->flows, flow); FLOW_REMOVE (FLOWS, &ft->flows, flow); EXPIRY_REMOVE (EXPIRIES, &ft->expiries, flow->expiry); expiry_put (ft, flow->expiry); ft->param.num_flows--; flow_put (ft, flow); i++; } return (i); } /* * Log our current status. * Includes summary counters and (in verbose mode) the list of current flows * and the tree of expiry events. */ static int statistics (struct FLOWTRACK *ft, FILE * out, pcap_t * pcap) { int i; struct protoent *pe; char proto[32]; struct pcap_stat ps; fprintf (out, "Number of active flows: %d\n", ft->param.num_flows); fprintf (out, "Packets processed: %" PRIu64 "\n", ft->param.total_packets); if (ft->param.non_sampled_packets) fprintf (out, "Packets non-sampled: %" PRIu64 "\n", ft->param.non_sampled_packets); fprintf (out, "Fragments: %" PRIu64 "\n", ft->param.frag_packets); fprintf (out, "Ignored packets: %" PRIu64 " (%" PRIu64 " non-IP, %" PRIu64 " too short)\n", ft->param.non_ip_packets + ft->param.bad_packets, ft->param.non_ip_packets, ft->param.bad_packets); fprintf (out, "Flows expired: %" PRIu64 " (%" PRIu64 " forced)\n", ft->param.flows_expired, ft->param.flows_force_expired); fprintf (out, "Flows exported: %" PRIu64 " (%" PRIu64 " records) in %" PRIu64 " packets (%" PRIu64 " failures)\n", ft->param.flows_exported, ft->param.records_sent, ft->param.packets_sent, ft->param.flows_dropped); if (pcap_stats (pcap, &ps) == 0) { fprintf (out, "Packets received by libpcap: %lu\n", (unsigned long) ps.ps_recv); fprintf (out, "Packets dropped by libpcap: %lu\n", (unsigned long) ps.ps_drop); fprintf (out, "Packets dropped by interface: %lu\n", (unsigned long) ps.ps_ifdrop); } fprintf (out, "\n"); if (ft->param.flows_expired != 0) { fprintf (out, "Expired flow statistics: minimum average maximum\n"); fprintf (out, " Flow bytes: %12.0f %12.0f %12.0f\n", ft->param.octets.min, ft->param.octets.mean, ft->param.octets.max); fprintf (out, " Flow packets: %12.0f %12.0f %12.0f\n", ft->param.packets.min, ft->param.packets.mean, ft->param.packets.max); fprintf (out, " Duration: %12.2fs %12.2fs %12.2fs\n", ft->param.duration.min, ft->param.duration.mean, ft->param.duration.max); fprintf (out, "\n"); fprintf (out, "Expired flow reasons:\n"); fprintf (out, " tcp = %9" PRIu64 " tcp.rst = %9" PRIu64 " " "tcp.fin = %9" PRIu64 "\n", ft->param.expired_tcp, ft->param.expired_tcp_rst, ft->param.expired_tcp_fin); fprintf (out, " udp = %9" PRIu64 " icmp = %9" PRIu64 " " "general = %9" PRIu64 "\n", ft->param.expired_udp, ft->param.expired_icmp, ft->param.expired_general); fprintf (out, " maxlife = %9" PRIu64 "\n", ft->param.expired_maxlife); fprintf (out, "over 2 GiB = %9" PRIu64 "\n", ft->param.expired_overbytes); fprintf (out, " maxflows = %9" PRIu64 "\n", ft->param.expired_maxflows); fprintf (out, " flushed = %9" PRIu64 "\n", ft->param.expired_flush); fprintf (out, "\n"); fprintf (out, "Per-protocol statistics: Octets " "Packets Avg Life Max Life\n"); for (i = 0; i < 256; i++) { if (ft->param.packets_pp[i]) { pe = getprotobynumber (i); snprintf (proto, sizeof (proto), "%s (%d)", pe != NULL ? pe->p_name : "Unknown", i); fprintf (out, " %17s: %14" PRIu64 " %12" PRIu64 " %8.2fs " "%10.2fs\n", proto, ft->param.octets_pp[i], ft->param.packets_pp[i], ft->param.duration_pp[i].mean, ft->param.duration_pp[i].max); } } } return (0); } static void dump_flows (struct FLOWTRACK *ft, FILE * out) { struct EXPIRY *expiry; time_t now; now = time (NULL); EXPIRY_FOREACH (expiry, EXPIRIES, &ft->expiries) { fprintf (out, "ACTIVE %s\n", format_flow (expiry->flow)); if ((long int) expiry->expires_at - now < 0) { fprintf (out, "EXPIRY EVENT for flow %" PRIu64 " now%s\n", expiry->flow->flow_seq, expiry->expires_at == 0 ? " (FORCED)" : ""); } else { fprintf (out, "EXPIRY EVENT for flow %" PRIu64 " in %ld seconds\n", expiry->flow->flow_seq, (long int) expiry->expires_at - now); } fprintf (out, "\n"); } } /* * Figure out how many bytes to skip from front of packet to get past * datalink headers. If pkt is specified, also check whether determine * whether or not it is one that we are interested in (IPv4 or IPv6 for now) * * Returns number of bytes to skip or -1 to indicate that entire * packet should be skipped */ static int datalink_check (int linktype, const u_int8_t * pkt, u_int32_t caplen, int *af, struct ether_header **ether, u_int16_t * vlanid) { int i, j; u_int32_t frametype; int vlan_size = 0; static const struct DATALINK *dl = NULL; /* Try to cache last used linktype */ if (dl == NULL || dl->dlt != linktype) { for (i = 0; lt[i].dlt != linktype && lt[i].dlt != -1; i++); dl = <[i]; } if (dl->dlt == -1 || pkt == NULL) return (dl->dlt); if (caplen <= dl->skiplen) return (-1); /* Suck out the frametype */ frametype = 0; /* Processing 802.1Q vlan in ethernet */ if (linktype == DLT_EN10MB) { if (ether != NULL) *ether = (struct ether_header *) pkt; for (j = 0; j < dl->ft_len; j++) { frametype <<= 8; frametype |= pkt[j + dl->ft_off]; } frametype &= dl->ft_mask; if (frametype == ETHERTYPE_VLAN) { for (j = 0; j < 2; j++) { *vlanid <<= 8; *vlanid |= pkt[j + dl->skiplen]; } vlan_size = 4; } } frametype = 0; if (dl->ft_is_be) { for (j = 0; j < dl->ft_len; j++) { frametype <<= 8; frametype |= pkt[j + dl->ft_off + vlan_size]; } } else { for (j = dl->ft_len - 1; j >= 0; j--) { frametype <<= 8; frametype |= pkt[j + dl->ft_off + vlan_size]; } } frametype &= dl->ft_mask; if (frametype == dl->ft_v4) *af = AF_INET; else if (frametype == dl->ft_v6) *af = AF_INET6; else return (-1); return (dl->skiplen + vlan_size); } /* * Per-packet callback function from libpcap. Pass the packet (if it is IP) * sans datalink headers to process_packet. */ void flow_cb (u_char * user_data, const struct pcap_pkthdr *phdr, const u_char * pkt) { int s, af = 0; struct CB_CTXT *cb_ctxt = (struct CB_CTXT *) user_data; struct timeval tv; u_int16_t vlanid = 0; struct ether_header *ether = NULL; if (cb_ctxt->ft->param.total_packets == 0) { if (cb_ctxt->ft->param.adjust_time) { cb_ctxt->ft->param.system_boot_time = phdr->ts; } } if (cb_ctxt->ft->param.option.sample && (cb_ctxt->ft->param.total_packets + cb_ctxt->ft->param.non_sampled_packets) % cb_ctxt->ft->param.option.sample > 0) { cb_ctxt->ft->param.non_sampled_packets++; return; } cb_ctxt->ft->param.total_packets++; if (cb_ctxt->ft->param.is_psamp) { send_psamp (pkt, phdr->caplen, phdr->ts, cb_ctxt->target, cb_ctxt->ft->param.total_packets); return; } s = datalink_check (cb_ctxt->linktype, pkt, phdr->caplen, &af, ðer, &vlanid); if (s < 0 || (!cb_ctxt->want_v6 && af == AF_INET6)) { cb_ctxt->ft->param.non_ip_packets++; cb_ctxt->ft->param.total_packets--; } else { tv.tv_sec = phdr->ts.tv_sec; tv.tv_usec = phdr->ts.tv_usec; if (process_packet (cb_ctxt->ft, pkt + s, af, phdr->caplen - s, phdr->len - s, ether, vlanid, &tv) == PP_MALLOC_FAIL) cb_ctxt->fatal = 1; } if (cb_ctxt->ft->param.adjust_time) cb_ctxt->ft->param.last_packet_time = phdr->ts; } #ifdef ENABLE_PTHREAD static void pcap_memcpy (u_char * user_data, const struct pcap_pkthdr *phdr, const u_char * pkt) { pthread_mutex_lock (&read_mutex); memcpy (&packet_header, phdr, sizeof (struct pcap_pkthdr)); memcpy (&packet_data, pkt, sizeof (packet_data)); pthread_mutex_unlock (&read_mutex); pthread_cond_signal (&read_cond); } void * process_packet_loop (void *arg) { while (!graceful_shutdown_request) { pthread_mutex_lock (&read_mutex); pthread_cond_wait (&read_cond, &read_mutex); if (graceful_shutdown_request) break; flow_cb ((u_char *) arg, &packet_header, (u_char *) & packet_data); pthread_mutex_unlock (&read_mutex); } } #endif /* ENABLE_PTHREAD */ static void print_timeouts (struct FLOWTRACK *ft, FILE * out) { fprintf (out, " TCP timeout: %ds\n", ft->param.tcp_timeout); fprintf (out, " TCP post-RST timeout: %ds\n", ft->param.tcp_rst_timeout); fprintf (out, " TCP post-FIN timeout: %ds\n", ft->param.tcp_fin_timeout); fprintf (out, " UDP timeout: %ds\n", ft->param.udp_timeout); fprintf (out, " ICMP timeout: %ds\n", ft->param.icmp_timeout); fprintf (out, " General timeout: %ds\n", ft->param.general_timeout); fprintf (out, " Maximum lifetime: %ds\n", ft->param.maximum_lifetime); fprintf (out, " Expiry interval: %ds\n", ft->param.expiry_interval); } static int accept_control (int lsock, struct NETFLOW_TARGET *target, struct FLOWTRACK *ft, pcap_t * pcap, int *exit_request, int *stop_collection_flag) { char buf[64], *p; FILE *ctlf; int fd, ret; if ((fd = accept (lsock, NULL, NULL)) == -1) { logit (LOG_ERR, "ctl accept: %s - exiting", strerror (errno)); return (-1); } if ((ctlf = fdopen (fd, "r+")) == NULL) { logit (LOG_ERR, "fdopen: %s - exiting\n", strerror (errno)); close (fd); return (-1); } setlinebuf (ctlf); if (fgets (buf, sizeof (buf), ctlf) == NULL) { logit (LOG_ERR, "Control socket yielded no data"); return (0); } if ((p = strchr (buf, '\n')) != NULL) *p = '\0'; if (verbose_flag) logit (LOG_DEBUG, "Control socket \"%s\"", buf); /* XXX - use dispatch table */ ret = -1; if (strcmp (buf, "help") == 0) { fprintf (ctlf, "Valid control words are:\n"); fprintf (ctlf, "\tdebug+ debug- delete-all dump-flows exit " "expire-all\n"); fprintf (ctlf, "\tshutdown start-gather statistics stop-gather " "timeouts\n"); fprintf (ctlf, "\tsend-template\n"); ret = 0; } else if (strcmp (buf, "shutdown") == 0) { fprintf (ctlf, "softflowd[%u]: Shutting down gracefully...\n", (unsigned int) getpid ()); graceful_shutdown_request = 1; ret = 1; } else if (strcmp (buf, "exit") == 0) { fprintf (ctlf, "softflowd[%u]: Exiting now...\n", (unsigned int) getpid ()); *exit_request = 1; ret = 1; } else if (strcmp (buf, "expire-all") == 0) { #ifdef ENABLE_LEGACY netflow9_resend_template (); #else /* ENABLE_LEGACY */ ipfix_resend_template (); #endif /* ENABLE_LEGACY */ fprintf (ctlf, "softflowd[%u]: Expired %d flows.\n", (unsigned int) getpid (), check_expired (ft, target, CE_EXPIRE_ALL)); ret = 0; } else if (strcmp (buf, "send-template") == 0) { #ifdef ENABLE_LEGACY netflow9_resend_template (); #else /* ENABLE_LEGACY */ ipfix_resend_template (); #endif /* ENABLE_LEGACY */ fprintf (ctlf, "softflowd[%u]: Template will be sent at " "next flow export\n", (unsigned int) getpid ()); ret = 0; } else if (strcmp (buf, "delete-all") == 0) { fprintf (ctlf, "softflowd[%u]: Deleted %d flows.\n", (unsigned int) getpid (), delete_all_flows (ft)); ret = 0; } else if (strcmp (buf, "statistics") == 0) { fprintf (ctlf, "softflowd[%u]: Accumulated statistics " "since %s UTC:\n", (unsigned int) getpid (), format_time (ft->param.system_boot_time.tv_sec)); statistics (ft, ctlf, pcap); ret = 0; } else if (strcmp (buf, "debug+") == 0) { fprintf (ctlf, "softflowd[%u]: Debug level increased.\n", (unsigned int) getpid ()); verbose_flag = 1; ret = 0; } else if (strcmp (buf, "debug-") == 0) { fprintf (ctlf, "softflowd[%u]: Debug level decreased.\n", (unsigned int) getpid ()); verbose_flag = 0; ret = 0; } else if (strcmp (buf, "stop-gather") == 0) { fprintf (ctlf, "softflowd[%u]: Data collection stopped.\n", (unsigned int) getpid ()); *stop_collection_flag = 1; ret = 0; } else if (strcmp (buf, "start-gather") == 0) { fprintf (ctlf, "softflowd[%u]: Data collection resumed.\n", (unsigned int) getpid ()); *stop_collection_flag = 0; ret = 0; } else if (strcmp (buf, "dump-flows") == 0) { fprintf (ctlf, "softflowd[%u]: Dumping flow data:\n", (unsigned int) getpid ()); dump_flows (ft, ctlf); ret = 0; } else if (strcmp (buf, "timeouts") == 0) { fprintf (ctlf, "softflowd[%u]: Printing timeouts:\n", (unsigned int) getpid ()); print_timeouts (ft, ctlf); ret = 0; } else { fprintf (ctlf, "Unknown control command \"%s\"\n", buf); ret = 0; } fclose (ctlf); close (fd); return (ret); } static int recvsock (uint16_t portnumber) { struct sockaddr_in addr; int rsock = socket (AF_INET, SOCK_DGRAM, 0); if (rsock < 0) { perror ("socket"); return rsock; } addr.sin_family = AF_INET; addr.sin_port = htons (portnumber); addr.sin_addr.s_addr = INADDR_ANY; if (bind (rsock, (struct sockaddr *) &addr, sizeof (addr)) < 0) { perror ("bind"); return -1; }; return rsock; } static int connsock (struct sockaddr_storage *addr, socklen_t len, int hoplimit, int protocol) { int s; unsigned int h6; unsigned char h4; struct sockaddr_in *in4 = (struct sockaddr_in *) addr; struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) addr; if ((s = socket (addr->ss_family, protocol == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM, protocol)) == -1) { fprintf (stderr, "socket() error: %s\n", strerror (errno)); exit (1); } if (connect (s, (struct sockaddr *) addr, len) == -1) { fprintf (stderr, "connect() error: %s\n", strerror (errno)); exit (1); } switch (addr->ss_family) { case AF_INET: /* Default to link-local TTL for multicast addresses */ if (hoplimit == -1 && IN_MULTICAST (in4->sin_addr.s_addr)) hoplimit = 1; if (hoplimit == -1) break; h4 = hoplimit; if (setsockopt (s, IPPROTO_IP, IP_MULTICAST_TTL, &h4, sizeof (h4)) == -1) { fprintf (stderr, "setsockopt(IP_MULTICAST_TTL, " "%u): %s\n", h4, strerror (errno)); exit (1); } break; case AF_INET6: /* Default to link-local hoplimit for multicast addresses */ if (hoplimit == -1 && IN6_IS_ADDR_MULTICAST (&in6->sin6_addr)) hoplimit = 1; if (hoplimit == -1) break; h6 = hoplimit; if (setsockopt (s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &h6, sizeof (h6)) == -1) { fprintf (stderr, "setsockopt(IPV6_MULTICAST_HOPS, %u): " "%s\n", h6, strerror (errno)); exit (1); } } return (s); } static int unix_listener (const char *path) { struct sockaddr_un addr; socklen_t addrlen; int s; memset (&addr, '\0', sizeof (addr)); addr.sun_family = AF_UNIX; if (strlcpy (addr.sun_path, path, sizeof (addr.sun_path)) >= sizeof (addr.sun_path)) { fprintf (stderr, "control socket path too long\n"); exit (1); } addr.sun_path[sizeof (addr.sun_path) - 1] = '\0'; addrlen = offsetof (struct sockaddr_un, sun_path) + strlen (path) + 1; #ifdef SOCK_HAS_LEN addr.sun_len = addrlen; #endif if ((s = socket (PF_UNIX, SOCK_STREAM, 0)) < 0) { fprintf (stderr, "unix domain socket() error: %s\n", strerror (errno)); exit (1); } unlink (path); if (bind (s, (struct sockaddr *) &addr, addrlen) == -1) { fprintf (stderr, "unix domain bind(\"%s\") error: %s\n", addr.sun_path, strerror (errno)); exit (1); } if (listen (s, 64) == -1) { fprintf (stderr, "unix domain listen() error: %s\n", strerror (errno)); exit (1); } return (s); } static void setup_packet_capture (struct pcap **pcap, int *linktype, char *dev, char *capfile, char *bpf_prog, int need_v6) { char ebuf[PCAP_ERRBUF_SIZE]; struct bpf_program prog_c; u_int32_t bpf_mask, bpf_net; /* Open pcap */ if (dev != NULL) { if (!snaplen) snaplen = need_v6 ? LIBPCAP_SNAPLEN_V6 : LIBPCAP_SNAPLEN_V4; if ((*pcap = pcap_open_live (dev, snaplen, 1, 0, ebuf)) == NULL) { fprintf (stderr, "pcap_open_live: %s\n", ebuf); exit (1); } if (pcap_lookupnet (dev, &bpf_net, &bpf_mask, ebuf) == -1) bpf_net = bpf_mask = 0; } else { if ((*pcap = pcap_open_offline (capfile, ebuf)) == NULL) { fprintf (stderr, "pcap_open_offline(%s): %s\n", capfile, ebuf); exit (1); } bpf_net = bpf_mask = 0; } *linktype = pcap_datalink (*pcap); if (datalink_check (*linktype, NULL, 0, NULL, NULL, NULL) == -1) { fprintf (stderr, "Unsupported datalink type %d\n", *linktype); exit (1); } /* Attach BPF filter, if specified */ if (bpf_prog != NULL) { if (pcap_compile (*pcap, &prog_c, bpf_prog, 1, bpf_mask) == -1) { fprintf (stderr, "pcap_compile(\"%s\"): %s\n", bpf_prog, pcap_geterr (*pcap)); exit (1); } if (pcap_setfilter (*pcap, &prog_c) == -1) { fprintf (stderr, "pcap_setfilter: %s\n", pcap_geterr (*pcap)); exit (1); } } #ifdef BIOCLOCK /* * If we are reading from an device (not a file), then * lock the underlying BPF device to prevent changes in the * unprivileged child */ if (dev != NULL && ioctl (pcap_fileno (*pcap), BIOCLOCK) < 0) { fprintf (stderr, "ioctl(BIOCLOCK) failed: %s\n", strerror (errno)); exit (1); } #endif } static void init_flowtrack (struct FLOWTRACK *ft) { /* Set up flow-tracking structure */ memset (ft, '\0', sizeof (*ft)); ft->param.next_flow_seq = 1; FLOW_INIT (&ft->flows); EXPIRY_INIT (&ft->expiries); freelist_init (&ft->flow_freelist, sizeof (struct FLOW)); freelist_init (&ft->expiry_freelist, sizeof (struct EXPIRY)); ft->param.max_flows = DEFAULT_MAX_FLOWS; track_level = ft->param.track_level = TRACK_FULL; ft->param.tcp_timeout = DEFAULT_TCP_TIMEOUT; ft->param.tcp_rst_timeout = DEFAULT_TCP_RST_TIMEOUT; ft->param.tcp_fin_timeout = DEFAULT_TCP_FIN_TIMEOUT; ft->param.udp_timeout = DEFAULT_UDP_TIMEOUT; ft->param.icmp_timeout = DEFAULT_ICMP_TIMEOUT; ft->param.general_timeout = DEFAULT_GENERAL_TIMEOUT; ft->param.maximum_lifetime = DEFAULT_MAXIMUM_LIFETIME; ft->param.expiry_interval = DEFAULT_EXPIRY_INTERVAL; } static char * argv_join (int argc, char **argv) { int i; size_t ret_len; char *ret; ret_len = 0; ret = NULL; for (i = 0; i < argc; i++) { ret_len += strlen (argv[i]); if ((ret = realloc (ret, ret_len + 2)) == NULL) { fprintf (stderr, "Memory allocation failed.\n"); exit (1); } if (i == 0) ret[0] = '\0'; else { ret_len++; /* Make room for ' ' */ strlcat (ret, " ", ret_len + 1); } strlcat (ret, argv[i], ret_len + 1); } return (ret); } /* Display commandline usage information */ static void usage (void) { fprintf (stderr, "Usage: %s [options] [bpf_program]\n" "This is %s version %s. Valid commandline options:\n" " -i [idx:]interface Specify interface to listen on\n" " -r pcap_file Specify packet capture file to read\n" " -t timeout=time Specify named timeout\n" " -m max_flows Specify maximum number of flows to track (default %d)\n" " -n host:port Send Cisco NetFlow(tm)-compatible packets to host:port\n" " -p pidfile Record pid in specified file\n" " (default: %s)\n" " -c socketfile Location of control socket\n" " (default: %s)\n" " -v 1|5|9|10|psamp NetFlow export packet version\n" " 10 means IPFIX and psamp means PSAMP (packet sampling)\n" #ifdef ENABLE_NTOPNG " ntopng ntopng means direct injection to NTOPNG (if supported).\n" #endif " -L hoplimit Set TTL/hoplimit for export datagrams\n" " -T full|port|proto|ip| Set flow tracking level (default: full)\n" " vlan (\"vlan\" tracking means \"full\" tracking with vlanid)\n" " ether (\"ether\" tracking means \"vlan\" tracking with ether header)\n" " -6 Track IPv6 flows, regardless of whether selected \n" " NetFlow export protocol supports it\n" " -d Don't daemonise (run in foreground)\n" " -D Debug mode: foreground + verbosity + track v6 flows\n" " -P udp|tcp|sctp Specify transport layer protocol for exporting packets\n" " -A sec|milli|micro|nano Specify absolute time format form exporting records\n" " -s sampling_rate Specify periodical sampling rate (denominator)\n" " -b Bidirectional mode in IPFIX (-b work with -v 10)\n" " -a Adjusting time for reading pcap file (-a work with -r)\n" " -C capture_length Specify length for packet capture (snaplen)\n" " -l Load balancing mode for multiple destinations\n" " -R receive_port Specify port number for PSAMP receive mode\n" #ifdef ENABLE_PTHREAD " -M Enable multithread\n" #endif /* ENABLE_PTHREAD */ " -h Display this help\n" "\n" "Valid timeout names and default values:\n" " tcp (default %6d)" " tcp.rst (default %6d)" " tcp.fin (default %6d)\n" " udp (default %6d)" " icmp (default %6d)" " general (default %6d)\n" " maxlife (default %6d)" " expint (default %6d)\n" "\n", PROGNAME, PROGNAME, PROGVER, DEFAULT_MAX_FLOWS, DEFAULT_PIDFILE, DEFAULT_CTLSOCK, DEFAULT_TCP_TIMEOUT, DEFAULT_TCP_RST_TIMEOUT, DEFAULT_TCP_FIN_TIMEOUT, DEFAULT_UDP_TIMEOUT, DEFAULT_ICMP_TIMEOUT, DEFAULT_GENERAL_TIMEOUT, DEFAULT_MAXIMUM_LIFETIME, DEFAULT_EXPIRY_INTERVAL); } static void set_timeout (struct FLOWTRACK *ft, const char *to_spec) { char *name, *value; int timeout; if ((name = strdup (to_spec)) == NULL) { fprintf (stderr, "Out of memory\n"); exit (1); } if ((value = strchr (name, '=')) == NULL || *(++value) == '\0') { fprintf (stderr, "Invalid -t option \"%s\".\n", name); usage (); exit (1); } *(value - 1) = '\0'; timeout = convtime (value); if (timeout < 0) { fprintf (stderr, "Invalid -t timeout.\n"); usage (); exit (1); } if (strcmp (name, "tcp") == 0) ft->param.tcp_timeout = timeout; else if (strcmp (name, "tcp.rst") == 0) ft->param.tcp_rst_timeout = timeout; else if (strcmp (name, "tcp.fin") == 0) ft->param.tcp_fin_timeout = timeout; else if (strcmp (name, "udp") == 0) ft->param.udp_timeout = timeout; else if (strcmp (name, "icmp") == 0) ft->param.icmp_timeout = timeout; else if (strcmp (name, "general") == 0) ft->param.general_timeout = timeout; else if (strcmp (name, "maxlife") == 0) ft->param.maximum_lifetime = timeout; else if (strcmp (name, "expint") == 0) ft->param.expiry_interval = timeout; else { fprintf (stderr, "Invalid -t name.\n"); usage (); exit (1); } if (ft->param.general_timeout == 0) { fprintf (stderr, "\"general\" flow timeout must be " "greater than zero\n"); exit (1); } free (name); } static void parse_hostport (const char *s, struct sockaddr *addr, socklen_t * len) { char *orig, *host, *port; struct addrinfo hints, *res; int herr; if ((host = orig = strdup (s)) == NULL) { fprintf (stderr, "Out of memory\n"); exit (1); } if ((port = strrchr (host, ':')) == NULL || *(++port) == '\0' || *host == '\0') { fprintf (stderr, "Invalid -n argument.\n"); usage (); exit (1); } *(port - 1) = '\0'; /* Accept [host]:port for numeric IPv6 addresses */ if (*host == '[' && *(port - 2) == ']') { host++; *(port - 2) = '\0'; } memset (&hints, '\0', sizeof (hints)); hints.ai_socktype = SOCK_DGRAM; if ((herr = getaddrinfo (host, port, &hints, &res)) == -1) { fprintf (stderr, "Address lookup failed: %s\n", gai_strerror (herr)); exit (1); } if (res == NULL || res->ai_addr == NULL) { fprintf (stderr, "No addresses found for [%s]:%s\n", host, port); exit (1); } if (res->ai_addrlen > *len) { fprintf (stderr, "Address too long\n"); exit (1); } memcpy (addr, res->ai_addr, res->ai_addrlen); free (orig); *len = res->ai_addrlen; } static int parse_hostports (const char *s, struct DESTINATION *dest, int max_dest) { int i = 0; char *hostport; for (hostport = strsep ((char **) &s, ","); hostport != NULL && i < max_dest; hostport = strsep ((char **) &s, ",")) { dest[i].sslen = sizeof (dest[i].ss); parse_hostport (hostport, (struct sockaddr *) &dest[i].ss, &dest[i].sslen); i++; } return i; } /* * Drop privileges and chroot, will exit on failure */ static void drop_privs (void) { struct passwd *pw; if ((pw = getpwnam (PRIVDROP_USER)) == NULL) { logit (LOG_ERR, "Unable to find unprivileged user \"%s\"", PRIVDROP_USER); exit (1); } if (chdir (PRIVDROP_CHROOT_DIR) != 0) { logit (LOG_ERR, "Unable to chdir to chroot directory \"%s\": %s", PRIVDROP_CHROOT_DIR, strerror (errno)); exit (1); } if (chroot (PRIVDROP_CHROOT_DIR) != 0) { logit (LOG_ERR, "Unable to chroot to directory \"%s\": %s", PRIVDROP_CHROOT_DIR, strerror (errno)); exit (1); } if (chdir ("/") != 0) { logit (LOG_ERR, "Unable to chdir to chroot root: %s", strerror (errno)); exit (1); } if (setgroups (1, &pw->pw_gid) != 0) { logit (LOG_ERR, "Couldn't setgroups (%u): %s", (unsigned int) pw->pw_gid, strerror (errno)); exit (1); } #if defined(HAVE_SETRESGID) if (setresgid (pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1) { #elif defined(HAVE_SETREGID) if (setregid (pw->pw_gid, pw->pw_gid) == -1) { #else if (setegid (pw->pw_gid) == -1 || setgid (pw->pw_gid) == -1) { #endif logit (LOG_ERR, "Couldn't set gid (%u): %s", (unsigned int) pw->pw_gid, strerror (errno)); exit (1); } #if defined(HAVE_SETRESUID) if (setresuid (pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) { #elif defined(HAVE_SETREUID) if (setreuid (pw->pw_uid, pw->pw_uid) == -1) { #else if (seteuid (pw->pw_uid) == -1 || setuid (pw->pw_uid) == -1) { #endif logit (LOG_ERR, "Couldn't set uid (%u): %s", (unsigned int) pw->pw_uid, strerror (errno)); exit (1); } } int main (int argc, char **argv) { char *dev, *capfile, *bpf_prog; const char *pidfile_path, *ctlsock_path; extern char *optarg; extern int optind; int ch, dontfork_flag, linktype, ctlsock, err, always_v6, r, dest_idx; int stop_collection_flag, exit_request, hoplimit; pcap_t *pcap = NULL; struct FLOWTRACK flowtrack; struct NETFLOW_TARGET target; struct CB_CTXT cb_ctxt; struct pollfd pl[2]; struct DESTINATION *dest; int protocol = IPPROTO_UDP; int version = 0; int rsock = 0, recvport = IPFIX_PORT, recvloop = 0; #ifdef ENABLE_PTHREAD int use_thread = 0; pthread_t read_thread = 0; pthread_mutex_init (&read_mutex, NULL); pthread_cond_init (&read_cond, NULL); #endif /* ENABLE_PTHREAD */ closefrom (STDERR_FILENO + 1); init_flowtrack (&flowtrack); memset (&target, '\0', sizeof (target)); target.dialect = &nf[0]; hoplimit = -1; bpf_prog = NULL; ctlsock = -1; dev = capfile = NULL; pidfile_path = DEFAULT_PIDFILE; ctlsock_path = DEFAULT_CTLSOCK; dontfork_flag = 0; always_v6 = 0; while ((ch = getopt (argc, argv, "6hdDL:T:i:r:f:t:n:m:p:c:v:s:P:A:baC:lR:M")) != -1) { switch (ch) { case '6': always_v6 = 1; break; case 'h': usage (); return (0); case 'D': verbose_flag = 1; always_v6 = 1; /* FALLTHROUGH */ case 'd': dontfork_flag = 1; break; case 'i': if (capfile != NULL || dev != NULL) { fprintf (stderr, "Packet source already " "specified.\n\n"); usage (); exit (1); } #if defined(HAVE_STRSEP) dev = strsep (&optarg, ":"); #else /* defined(HAVE_STRSEP) */ dev = strtok (optarg, ":"); #endif /* defined(HAVE_STRSEP) */ if (optarg != NULL) { if (strlen (dev) > 0) { if_index = (u_int16_t) atoi (dev); } dev = optarg; } if (strlen (dev) == 0) { fprintf (stderr, "Wrong interface is specified.\n\n"); usage (); exit (1); } if (verbose_flag) fprintf (stderr, "Using %s (idx: %d)\n", dev, if_index); break; case 'r': if (capfile != NULL || dev != NULL) { fprintf (stderr, "Packet source already " "specified.\n\n"); usage (); exit (1); } capfile = optarg; dontfork_flag = 1; ctlsock_path = NULL; break; case 't': /* Will exit on failure */ set_timeout (&flowtrack, optarg); break; case 'T': if (strcasecmp (optarg, "full") == 0) flowtrack.param.track_level = TRACK_FULL; else if (strcasecmp (optarg, "port") == 0) flowtrack.param.track_level = TRACK_IP_PROTO_PORT; else if (strcasecmp (optarg, "proto") == 0) flowtrack.param.track_level = TRACK_IP_PROTO; else if (strcasecmp (optarg, "ip") == 0) flowtrack.param.track_level = TRACK_IP_ONLY; else if (strcasecmp (optarg, "vlan") == 0) flowtrack.param.track_level = TRACK_FULL_VLAN; else if (strcasecmp (optarg, "ether") == 0) flowtrack.param.track_level = TRACK_FULL_VLAN_ETHER; else { fprintf (stderr, "Unknown flow tracking " "level\n"); usage (); exit (1); } track_level = flowtrack.param.track_level; break; case 'L': hoplimit = atoi (optarg); if (hoplimit < 0 || hoplimit > 255) { fprintf (stderr, "Invalid hop limit\n\n"); usage (); exit (1); } break; case 'm': if ((flowtrack.param.max_flows = atoi (optarg)) < 0) { fprintf (stderr, "Invalid maximum flows\n\n"); usage (); exit (1); } break; case 'n': /* Will exit on failure */ target.num_destinations = parse_hostports (optarg, target.destinations, SOFTFLOWD_MAX_DESTINATIONS); break; case 'p': pidfile_path = optarg; break; case 'c': if (strcmp (optarg, "none") == 0) ctlsock_path = NULL; else ctlsock_path = optarg; break; case 'v': if (!strncmp (optarg, "psamp", sizeof ("psamp"))) { flowtrack.param.is_psamp = 1; break; } #ifdef ENABLE_NTOPNG if (!strncmp (optarg, SOFTFLOWD_NF_VERSION_NTOPNG_STRING, sizeof (SOFTFLOWD_NF_VERSION_NTOPNG_STRING))) { version = SOFTFLOWD_NF_VERSION_NTOPNG; } #endif /* ENABLE_NTOPNG */ version = version ? version : atoi (optarg); target.dialect = lookup_netflow_sender (version); if (target.dialect == NULL) { fprintf (stderr, "Invalid NetFlow version\n"); exit (1); } break; case 's': flowtrack.param.option.sample = atoi (optarg); if (flowtrack.param.option.sample < 2) { flowtrack.param.option.sample = 0; } break; case 'P': if (strcasecmp (optarg, "udp") == 0) protocol = IPPROTO_UDP; else if (strcasecmp (optarg, "tcp") == 0) protocol = IPPROTO_TCP; #ifdef IPPROTO_SCTP else if (strcasecmp (optarg, "sctp") == 0) protocol = IPPROTO_SCTP; #endif else { fprintf (stderr, "Unknown transport layer protocol" "\n"); usage (); exit (1); } break; case 'A': if (strcasecmp (optarg, "sec") == 0) flowtrack.param.time_format = 's'; else if (strcasecmp (optarg, "milli") == 0) flowtrack.param.time_format = 'm'; else if (strcasecmp (optarg, "micro") == 0) flowtrack.param.time_format = 'M'; else if (strcasecmp (optarg, "nano") == 0) flowtrack.param.time_format = 'n'; else { fprintf (stderr, "Unknown time format" "\n"); usage (); exit (1); } break; case 'b': flowtrack.param.bidirection = 1; break; case 'a': flowtrack.param.adjust_time = 1; break; case 'C': /* Capture Length */ snaplen = atoi (optarg); break; case 'l': // load balancing target.is_loadbalance = 1; break; case 'R': recvport = atoi (optarg); if (recvport < 0 && recvport > 65535) recvport = IPFIX_PORT; rsock = recvsock ((uint16_t) recvport); break; case 'M': #ifdef ENABLE_PTHREAD use_thread = 1; #endif /* ENABLE_PTHREAD */ break; default: fprintf (stderr, "Invalid commandline option.\n"); usage (); exit (1); } } if (capfile == NULL && dev == NULL && rsock <= 0) { fprintf (stderr, "-i, -r or -R option not specified.\n"); usage (); exit (1); } /* join remaining arguments (if any) into bpf program */ bpf_prog = argv_join (argc - optind, argv + optind); /* Will exit on failure */ if (capfile != NULL || dev != NULL) setup_packet_capture (&pcap, &linktype, dev, capfile, bpf_prog, target.dialect->v6_capable || always_v6); else if (rsock > 0) linktype = 1; //LINKTYPE_ETHERNET /* Netflow send socket */ for (dest_idx = 0; dest_idx < target.num_destinations; dest_idx++) { dest = &target.destinations[dest_idx]; if (dest->ss.ss_family != 0) { if ((err = getnameinfo ((struct sockaddr *) &dest->ss, dest->sslen, dest->hostname, sizeof (dest->hostname), dest->servname, sizeof (dest->servname), NI_NUMERICHOST | NI_NUMERICSERV)) == -1) { fprintf (stderr, "getnameinfo: %d\n", err); exit (1); } #ifdef ENABLE_NTOPNG if (target.dialect->version == SOFTFLOWD_NF_VERSION_NTOPNG) { int rc = connect_ntopng (dest->hostname, dest->servname, &dest->zmq); if (rc) { fprintf (stderr, "Could not create ZeroMQ socket for %s:%s: (%d) %s\n", dest->hostname, dest->servname, rc, strerror (rc)); exit (1); } } else #endif dest->sock = connsock (&dest->ss, dest->sslen, hoplimit, protocol); } } /* Control socket */ if (ctlsock_path != NULL) ctlsock = unix_listener (ctlsock_path); /* Will exit on fail */ if (dontfork_flag) { loginit (PROGNAME, 1); } else { FILE *pidfile; r = daemon (0, 0); loginit (PROGNAME, 0); if ((pidfile = fopen (pidfile_path, "r")) != NULL) { int pid; if (fscanf (pidfile, "%u", &pid) == EOF) { //fscanf error if (ferror (pidfile)) { perror ("fscanf"); } } fclose (pidfile); /* Check if the pid exists */ int pidfree = (kill (pid, 0) && errno == ESRCH); if (!pidfree) { fprintf (stderr, "Already running under pid %u\n", pid); exit (1); } } if ((pidfile = fopen (pidfile_path, "w")) == NULL) { fprintf (stderr, "Couldn't open pidfile %s: %s\n", pidfile_path, strerror (errno)); exit (1); } fprintf (pidfile, "%u\n", (unsigned int) getpid ()); fclose (pidfile); signal (SIGINT, sighand_graceful_shutdown); signal (SIGTERM, sighand_graceful_shutdown); signal (SIGSEGV, sighand_other); setprotoent (1); drop_privs (); } logit (LOG_NOTICE, "%s v%s starting data collection", PROGNAME, PROGVER); for (dest_idx = 0; dest_idx < target.num_destinations; dest_idx++) { dest = &target.destinations[dest_idx]; if (dest->ss.ss_family != 0) { logit (LOG_NOTICE, "Exporting flows to [%s]:%s", dest->hostname, dest->servname); } } flowtrack.param.option.meteringProcessId = getpid (); /* Main processing loop */ gettimeofday (&flowtrack.param.system_boot_time, NULL); stop_collection_flag = 0; memset (&cb_ctxt, '\0', sizeof (cb_ctxt)); cb_ctxt.ft = &flowtrack; cb_ctxt.target = ⌖ cb_ctxt.linktype = linktype; cb_ctxt.want_v6 = target.dialect->v6_capable || always_v6; #ifdef ENABLE_PTHREAD if (use_thread) { if (pthread_create (&read_thread, NULL, process_packet_loop, (void *) &cb_ctxt) < 0) { perror ("pthread_create error"); exit (1); } } #endif /* ENABLE_PTHREAD */ for (r = 0; graceful_shutdown_request == 0; r = 0) { /* * Silly libpcap's timeout function doesn't work, so we * do it here (only if we are reading live) */ if (capfile == NULL && (dev != NULL || rsock > 0)) { //online memset (pl, '\0', sizeof (pl)); /* This can only be set via the control socket */ if (!stop_collection_flag && dev != NULL) { pl[0].events = POLLIN | POLLERR | POLLHUP; pl[0].fd = pcap_fileno (pcap); } else if (!stop_collection_flag && rsock > 0) { pl[0].fd = rsock; pl[0].events = POLLIN | POLLERR | POLLHUP; } if (ctlsock != -1) { pl[1].fd = ctlsock; pl[1].events = POLLIN | POLLERR | POLLHUP; } r = poll (pl, (ctlsock == -1) ? 1 : 2, next_expire (&flowtrack)); if (r == -1 && errno != EINTR) { logit (LOG_ERR, "Exiting on poll: %s", strerror (errno)); break; } } /* Accept connection on control socket if present */ if (ctlsock != -1 && pl[1].revents != 0) { if (accept_control (ctlsock, &target, &flowtrack, pcap, &exit_request, &stop_collection_flag) != 0) break; } /* If we have data, run it through libpcap */ if (!stop_collection_flag && (capfile != NULL || pl[0].revents != 0)) { if (capfile != NULL || dev != NULL) { #ifdef ENABLE_PTHREAD if (use_thread) r = pcap_dispatch (pcap, flowtrack.param.max_flows, pcap_memcpy, NULL); else #endif /* ENABLE_PTHREAD */ r = pcap_dispatch (pcap, flowtrack.param.max_flows, flow_cb, (void *) &cb_ctxt); if (r == -1) { logit (LOG_ERR, "Exiting on pcap_dispatch: %s", pcap_geterr (pcap)); break; } else if (r == 0 && capfile != NULL) { logit (LOG_NOTICE, "Shutting down after " "pcap EOF"); graceful_shutdown_request = 1; break; } } else if (rsock > 0) { for (recvloop = 0; recvloop < flowtrack.param.max_flows && pl[0].revents != 0; recvloop++) { r = recv_psamp (rsock, &cb_ctxt); if (r == -1) { logit (LOG_ERR, "recv_psamp error"); break; } if (recvloop + 1 == flowtrack.param.max_flows) { r = poll (pl, 1, next_expire (&flowtrack)); if (r == -1 && errno != EINTR) { logit (LOG_ERR, "Exiting on poll: %s", strerror (errno)); break; } } } } } r = 0; /* Fatal error from per-packet functions */ if (cb_ctxt.fatal) { logit (LOG_WARNING, "Fatal error - exiting immediately"); break; } /* * Expiry processing happens every recheck_rate seconds * or whenever we have exceeded the maximum number of active * flows */ if (flowtrack.param.num_flows > flowtrack.param.max_flows || next_expire (&flowtrack) == 0) { expiry_check: /* * If we are reading from a capture file, we never * expire flows based on time - instead we only * expire flows when the flow table is full. */ if (check_expired (&flowtrack, &target, capfile == NULL ? CE_EXPIRE_NORMAL : CE_EXPIRE_FORCED) < 0) logit (LOG_WARNING, "Unable to export flows"); /* * If we are over max_flows, force-expire the oldest * out first and immediately reprocess to evict them */ if (flowtrack.param.num_flows > flowtrack.param.max_flows) { force_expire (&flowtrack, flowtrack.param.num_flows - flowtrack.param.max_flows); goto expiry_check; } } } /* Flags set by signal handlers or control socket */ if (graceful_shutdown_request) { logit (LOG_WARNING, "Shutting down on user request"); check_expired (&flowtrack, &target, CE_EXPIRE_ALL); } else if (exit_request) logit (LOG_WARNING, "Exiting immediately on user request"); else logit (LOG_ERR, "Exiting immediately on internal error"); if (capfile != NULL && dontfork_flag) statistics (&flowtrack, stdout, pcap); #ifdef ENABLE_PTHREAD if (use_thread) { pthread_cond_signal (&read_cond); pthread_join (read_thread, NULL); } #endif /* ENABLE_PTHREAD */ pcap_close (pcap); for (dest_idx = 0; dest_idx < target.num_destinations; dest_idx++) { dest = &target.destinations[dest_idx]; if (dest->sock != -1) close (dest->sock); } unlink (pidfile_path); if (ctlsock_path != NULL) unlink (ctlsock_path); if (rsock > 0) close (rsock); return (r == 0 ? 0 : 1); } softflowd-softflowd-1.0.0/softflowd.h000066400000000000000000000242461352553127000177170ustar00rootroot00000000000000/* * Copyright (c) 2002 Damien Miller. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _SOFTFLOWD_H #define _SOFTFLOWD_H #include "common.h" #include "sys-tree.h" #include "freelist.h" #include "treetype.h" #include #ifdef ENABLE_PTHREAD #include extern int use_thread; #endif /* ENABLE_PTHREAD */ #ifdef ENABLE_NTOPNG #include // The version field in NetFow and IPFIX headers is 16 bits unsiged int. // If the version number is over 0x7fff0000, it is unique number in softflowd. #define SOFTFLOWD_NF_VERSION_NTOPNG (0x7fff0001) #define SOFTFLOWD_NF_VERSION_NTOPNG_STRING "ntopng" struct ZMQ { void *context; void *socket; }; #endif /* ENABLE_NTOPNG */ /* User to setuid to and directory to chroot to when we drop privs */ #ifndef PRIVDROP_USER #define PRIVDROP_USER "nobody" #endif #ifndef PRIVDROP_CHROOT_DIR #define PRIVDROP_CHROOT_DIR "/var/empty" #endif /* * Capture length for libpcap: Must fit the link layer header, plus * a maximally sized ip/ipv6 header and most of a TCP header */ #define LIBPCAP_SNAPLEN_V4 96 #define LIBPCAP_SNAPLEN_V6 160 /* * Timeouts */ #define DEFAULT_TCP_TIMEOUT 3600 #define DEFAULT_TCP_RST_TIMEOUT 120 #define DEFAULT_TCP_FIN_TIMEOUT 300 #define DEFAULT_UDP_TIMEOUT 300 #define DEFAULT_ICMP_TIMEOUT 300 #define DEFAULT_GENERAL_TIMEOUT 3600 #define DEFAULT_MAXIMUM_LIFETIME (3600*24*7) #define DEFAULT_EXPIRY_INTERVAL 60 /* * Default maximum number of flow to track simultaneously * 8192 corresponds to just under 1Mb of flow data */ #define DEFAULT_MAX_FLOWS 8192 #define NF_VERSION_IPFIX 10 /* Store a couple of statistics, maybe more in the future */ struct STATISTIC { double min, mean, max; }; /* Flow tracking levels */ #define TRACK_FULL 1 /* src/dst/addr/port/proto/tos 6-tuple */ #define TRACK_IP_PROTO_PORT 2 /* src/dst/addr/port/proto 5-tuple */ #define TRACK_IP_PROTO 3 /* src/dst/proto 3-tuple */ #define TRACK_IP_ONLY 4 /* src/dst tuple */ #define TRACK_FULL_VLAN 5 /* src/dst/addr/port/proto/tos/vlanid 7-tuple */ #define TRACK_FULL_VLAN_ETHER 6 /* src/dst/addr/port/proto/tos/vlanid/src-mac/dst-mac 9-tuple */ #define SOFTFLOWD_MAX_DESTINATIONS 16 /* * This structure contains optional information carried by Option Data * Record. */ struct OPTION { uint32_t sample; pid_t meteringProcessId; }; struct FLOWTRACKPARAMETERS { unsigned int num_flows; /* # of active flows */ unsigned int max_flows; /* Max # of active flows */ u_int64_t next_flow_seq; /* Next flow ID */ /* Stuff related to flow export */ struct timeval system_boot_time; /* SysUptime */ int track_level; /* See TRACK_* above */ /* Flow timeouts */ int tcp_timeout; /* Open TCP connections */ int tcp_rst_timeout; /* TCP flows after RST */ int tcp_fin_timeout; /* TCP flows after bidi FIN */ int udp_timeout; /* UDP flows */ int icmp_timeout; /* ICMP flows */ int general_timeout; /* Everything else */ int maximum_lifetime; /* Maximum life for flows */ int expiry_interval; /* Interval between expiries */ /* Statistics */ u_int64_t total_packets; /* # of good packets */ u_int64_t non_sampled_packets; /* # of not sampled packets */ u_int64_t frag_packets; /* # of fragmented packets */ u_int64_t non_ip_packets; /* # of not-IP packets */ u_int64_t bad_packets; /* # of bad packets */ u_int64_t flows_expired; /* # expired */ u_int64_t flows_exported; /* # of flows sent */ u_int64_t flows_dropped; /* # of flows dropped */ u_int64_t flows_force_expired; /* # of flows forced out */ u_int64_t packets_sent; /* # netflow packets sent */ u_int64_t records_sent; /* # netflow records sent */ struct STATISTIC duration; /* Flow duration */ struct STATISTIC octets; /* Bytes (bidir) */ struct STATISTIC packets; /* Packets (bidir) */ /* Per protocol statistics */ u_int64_t flows_pp[256]; u_int64_t octets_pp[256]; u_int64_t packets_pp[256]; struct STATISTIC duration_pp[256]; /* Timeout statistics */ u_int64_t expired_general; u_int64_t expired_tcp; u_int64_t expired_tcp_rst; u_int64_t expired_tcp_fin; u_int64_t expired_udp; u_int64_t expired_icmp; u_int64_t expired_maxlife; u_int64_t expired_overbytes; u_int64_t expired_maxflows; u_int64_t expired_flush; /* Optional information */ struct OPTION option; char time_format; u_int8_t bidirection; u_int8_t adjust_time; u_int8_t is_psamp; struct timeval last_packet_time; }; /* * This structure is the root of the flow tracking system. * It holds the root of the tree of active flows and the head of the * tree of expiry events. It also collects miscellaneous statistics */ struct FLOWTRACK { /* The flows and their expiry events */ FLOW_HEAD (FLOWS, FLOW) flows; /* Top of flow tree */ EXPIRY_HEAD (EXPIRIES, EXPIRY) expiries; /* Top of expiries tree */ struct freelist flow_freelist; /* Freelist for flows */ struct freelist expiry_freelist; /* Freelist for expiry events */ struct FLOWTRACKPARAMETERS param; }; /* * This structure is an entry in the tree of flows that we are * currently tracking. * * Because flows are matched _bi-directionally_, they must be stored in * a canonical format: the numerically lowest address and port number must * be stored in the first address and port array slot respectively. */ struct FLOW { /* Housekeeping */ struct EXPIRY *expiry; /* Pointer to expiry record */ FLOW_ENTRY (FLOW) trp; /* Tree pointer */ /* Per-flow statistics (all in _host_ byte order) */ u_int64_t flow_seq; /* Flow ID */ struct timeval flow_start; /* Time of creation */ struct timeval flow_last; /* Time of last traffic */ /* Per-endpoint statistics (all in _host_ byte order) */ u_int32_t octets[2]; /* Octets so far */ u_int32_t packets[2]; /* Packets so far */ /* Flow identity (all are in network byte order) */ int af; /* Address family of flow */ u_int32_t ip6_flowlabel[2]; /* IPv6 Flowlabel */ union { struct in_addr v4; struct in6_addr v6; } addr[2]; /* Endpoint addresses */ u_int16_t port[2]; /* Endpoint ports */ u_int8_t tcp_flags[2]; /* Cumulative OR of flags */ u_int8_t tos[2]; /* Tos */ u_int16_t vlanid[2]; /* vlanid */ uint8_t ethermac[2][6]; u_int8_t protocol; /* Protocol */ }; /* * This is an entry in the tree of expiry events. The tree is used to * avoid traversion the whole tree of active flows looking for ones to * expire. "expires_at" is the time at which the flow should be discarded, * or zero if it is scheduled for immediate disposal. * * When a flow which hasn't been scheduled for immediate expiry registers * traffic, it is deleted from its current position in the tree and * re-inserted (subject to its updated timeout). * * Expiry scans operate by starting at the head of the tree and expiring * each entry with expires_at < now * */ struct EXPIRY { EXPIRY_ENTRY (EXPIRY) trp; /* Tree pointer */ struct FLOW *flow; /* pointer to flow */ u_int32_t expires_at; /* time_t */ enum { R_GENERAL, R_TCP, R_TCP_RST, R_TCP_FIN, R_UDP, R_ICMP, R_MAXLIFE, R_OVERBYTES, R_OVERFLOWS, R_FLUSH } reason; }; struct DESTINATION { char *arg; int sock; struct sockaddr_storage ss; socklen_t sslen; char hostname[NI_MAXHOST]; char servname[NI_MAXSERV]; #ifdef ENABLE_NTOPNG struct ZMQ zmq; #endif }; /* Describes a location where we send NetFlow packets to */ struct NETFLOW_TARGET { int num_destinations; struct DESTINATION destinations[SOFTFLOWD_MAX_DESTINATIONS]; const struct NETFLOW_SENDER *dialect; u_int8_t is_loadbalance; }; struct SENDPARAMETER { struct FLOW **flows; int num_flows; struct NETFLOW_TARGET *target; u_int16_t ifidx; struct FLOWTRACKPARAMETERS *param; int verbose_flag; }; /* Context for libpcap callback functions */ struct CB_CTXT { struct FLOWTRACK *ft; struct NETFLOW_TARGET *target; int linktype; int fatal; int want_v6; }; /* Prototype for functions shared from softflowd.c */ u_int32_t timeval_sub_ms (const struct timeval *t1, const struct timeval *t2); int send_multi_destinations (int num_destinations, struct DESTINATION *destinations, u_int8_t is_loadbalnce, u_int8_t * packet, int size); void flow_cb (u_char * user_data, const struct pcap_pkthdr *phdr, const u_char * pkt); /* Prototypes for functions to send NetFlow packets, from netflow*.c */ int send_netflow_v1 (struct SENDPARAMETER sp); int send_netflow_v5 (struct SENDPARAMETER sp); #ifdef ENABLE_NTOPNG /* Protypes for ntopng.c */ int connect_ntopng (const char *host, const char *port, struct ZMQ *zmq); int send_ntopng (struct SENDPARAMETER sp); #endif /* ENABLE_NTOPNG */ #endif /* _SOFTFLOWD_H */ softflowd-softflowd-1.0.0/softflowd.init000066400000000000000000000021201352553127000204160ustar00rootroot00000000000000#!/bin/bash # # softflowd Starts softflowd NetFlow probe # # chkconfig: 2345 95 02 # description: Starts and stops the softflowd Netflow probe # Source function library. . /etc/init.d/functions SOFTFLOW_CONF=/etc/sysconfig/softflowd SOFTFLOW_LOCK=/var/lock/subsys/softflowd SOFTFLOW_PROG=/usr/sbin/softflowd SOFTFLOW_OPTS="-i eth0" # Source config if [ -f $SOFTFLOW_CONF ]; then . $SOFTFLOW_CONF fi [ -x $SOFTFLOW_PROG ] || exit 0 RETVAL=0 start() { echo -n $"Starting softflowd: " daemon $SOFTFLOW_PROG $SOFTFLOW_OPTS RETVAL=$? echo [ $RETVAL -eq 0 ] && touch $SOFTFLOW_LOCK return $RETVAL } stop() { echo -n $"Shutting down softflowd: " killproc $SOFTFLOW_PROG RETVAL=$? echo [ $RETVAL -eq 0 ] && rm -f $SOFTFLOW_LOCK return $RETVAL } restart() { stop start } case "$1" in start) start ;; stop) stop ;; status) status $SOFTFLOW_PROG ;; restart|reload) restart ;; condrestart) [ -f $SOFTFLOW_LOCK ] && restart || : ;; *) echo $"Usage: $0 {start|stop|status|restart|condrestart}" exit 1 esac exit $? softflowd-softflowd-1.0.0/softflowd.pdf000066400000000000000000001207341352553127000202400ustar00rootroot00000000000000%PDF-1.4 %쏢 5 0 obj <> stream xZnV}WbyeEx]udHgs#%[NR<yξf޳,?r}O)OvsUwsՉ>Y*X~{oN翝Dϳ<8r-dvQRcG ArWzXQ.`E=}nj] 1QCWky'$_,<&-=SeJA$NPY Lą@2/ju,?_&_&>fݪ(ї8l}a5mT9ulvOO( c=RQe"ㆣ5Ueb-˲ma{%bm;U6mo/ĹtЖ1(A~Wm.X6lgb3l; |nn#vfRw,յR]?qdцS->l:S0 }ߊ,)xO7& (T=+ٝ~gid/ײTkWx LBDmAfKW4ͽ{E<-\dBS4y&OSVLdIe?8uٵchAscÖ&"%ŋfnNտdEyѩO.)VC#&R9CI6LhD6uH0qOM|o= Alz]3Uaw^ rG G@xҠlmSڼ"+em9^P|B}#kq#%Q]꠲Vo3O\R˞ubp/kmսt4N:yf|WE@c)+o'ٰER*` 3($J94!,j5Kj[IOP$Ig:CGy՗}MN0G_O4]j, 6dpXqr,m3XS{.'j:07R=Q"BP(z,S(H;mACG7ٞ3 YW^ _:7,luJ]灂g3I5IJn';d %=,$u߲n XOUڦ~.}+m(Ժ%|o뢻’- 1` J<n[*`^G+cL#G1i 2R踀KՂ)֨mVrBe~?E1q59L0CXܢȑ SQ֫m4+w*5fz9xE0Q0$~,\ ynb ldY}p@( U_$8:!d FK.ax6ZChQ^z%~GͲj[u*iJW]v-vۮC;D* yBZh2Ϧ%A, P Qb>=yUUW=pia^֭re*hS>)8%=X]st;HzkPSG7Bv']ӉTPvյg]]@l4>`vBio) {61'~yPANw<KWʔIbRQ iO Bw@\yEn3̳Fh0U^+0}.JJ"hxW#p֘L +Mٔuk$oɰ꾴,E 7k⤼];iiو\u*pقڅVR}7ņɅer$Qg\ &5*0/Mʅjb%6WvwU)XB4Y1-kI2c ϩMϖKܲ9naZq<JuySY:2uxӕ+;+${LԔb\@-Զ1 ɧʇ*ZK`+B;0Cg/+Zؑ! wy SԄ, #tC!܃]Y]ӊl!OӘɘ+Ld8=eU׮YqPzq9޹4k#ZJ{0uO6VB`+f8QqX蹝5 ؔ4RIQb]1Lm893 \PfwƑ־nb:Wa5 тϸ߶s6 4vУ06-!}fXCpKD>^ҤzbTn%%]=;'g| ^5b}ކm:D-'B؇jlxiQf3˜ީ$~Mx|,.gN? 1endstream endobj 6 0 obj 3604 endobj 21 0 obj <> stream xYێF}PӼ :8ɬGA/ lf^4?{/$ &NU:ĸ0NϬyǫOWY^p _6W;\%'lU]Y^~bוI8ʯ܎=?o{+~3ھp[vbu(kl]%:I`G>pۍ>;l:6O^ݼs\1[_V :B-MQ R`{ą8 Vd晥5KAtu:V6Y:M͆C 6lk&}ܲYQ<UM.lH;r+62Rߎ'rˁ"4qzoGIdOh9ql .&?Nl8yۊV364oS | _2I!dMYfП:W#@3b'qeR~rTMd o:ٗK/c?R?Q;#t)<R&Kbsxeé.J4N+ws݆lP 3zd#|С  ?4Ǟrs-t Pdk\sn9`PnpTިbu%g;Z 5M1ظ)WE21nj˴,rRն$33F#Uj }Qtir9o{<0n1tr3";~2ۦlbPC`=t("ńتT0u(*T8եJ۴eZԸLVNi^OSab<;%(m;Qm=ٓyK7ͱE5xSQGS:ÀہI47BӉm39( CMzQnhxjx>n]mLY (‰ `یmG.Tc!Z;TpH7׃U 7$}YA^BIP]&obxr?]AA98(?M7А7hSJK?NЏ('qC*n%|pń?c/6c)i# TH_|4_1ܳE G HWu=EX/g±=SweM|nnpLʁ }uMDJ.CuBՖ%!R.i{ ͨVŭķs_GMc HP8(D(PE&T:Ty;>UCe Gc[[N=Ö-w+%9QpT"6;6K[d;U-~zy6ii֙AUU MAS${ܨ/!3>=3tZU%f:8WS%oOmJ|~<<^ L[%$P\K%Ŷ֢o:%zOy* kIT$܏0ˆB.&lw̮CaURII muvm֟:wdAo=v^O=/ *fzyq9o 9ࡢtHa ɩ?.iq//.Vl;Q+{㫞xK-B<{uu4$֦Co:sF4HYS/&/T;814!> stream xXn#}W؞AJlxdh dBe O?T_Zo@(qΩ:U=~)3mf@?dٷK,zf,,ClYϼ_?2_{ gyEl,r?~}nNk(4K|ۛTFnT-r7zWf3l_r@YK,Axj`87rɛW y:)Iׇ$ x'AZnتm]@Qv 0;lXh]NyؤDLc[hc-){kkIycO҂gV?*u0ᵻlriFSFٱZ~TF5[gPU#]ek'\#%Rf,ll*Ճ)5)B`j}au ;?h!w8S C[Zd~nTA?X]?<ƭB)V5 wsqԡT~B(Z\6a=yI P<onLңu["5V+as౻ _nwIM{ܸ $H( LCNz닗jj*'^߳')q<6_9)E>tEˬP~I7$K@w@f%èb҈ogs?,epr{VT `>}%H.UwF1~ԩprg˜G3 ۵}9') 8LVo|(_Wf;\3OV$^Y3*#ke'٤wi:kO^88?o/;NO>kBKo.XfK|/Xڶcy}J>dff~`C{mgquzbg}98IuG YcEh>LJ6.-k yO/h+=eR;󳓹!\?B/jendstream endobj 27 0 obj 2154 endobj 31 0 obj <> stream xYˎ+jgv`V$ہxV,hj1CCR|@󏹷X$n=&@=bU׹>gQF"凘ܬ~^1󑸿| ޮFbNT$%z\~+i ZoVaD! | xqMG"˚ANY竔S^w)LQD~uRie!L+REgaą2Jh$ eb$K/1J~ٶ] (]V﫢oVQ#NBf޻t]<"鋼m6=h>0=7'뷫S}!s$`;ߞn~L2`{!X2Nph¡6CwtJ#)]b>'T̞ .8b3e$b +)b4 %TnmݩQ(QjeYɧ}[Uņ!îpvL\>TKZOńAЋP FzWl"*˖ t0dBR Ggm3﬘jB;`\VUW_{6Z/Q%_ep/{n92tY  ];Ҝ( ěC;< O@*=ijcqAP[Hs= Δ.2e #dy"U>']~0qqD՛?_}x #Umw|FN›D0|%8-}q^AL:aTrxN-:UDɸAL PkOxV&>(ʌ ;AgbD1XUH܋/r} d|U qDyFCVnĉ YչtTcܻp_g@mk!r2ʦx)z%4@FL -,j/ĺx9A)L,g!:Զ&))y)k1Rۑ z>6@1,YǷ9U:̏,(9&JOJ2WW}N4b &Ypܐ$ۻ}d KM$jKsܐGSAW8H2V1A B΀QGCp;m+eޓjD tp6BKCPM{JZP>^W~1 g5[e .sdP29bHb55? 8B@wR ~4r}&$*W Ԯ#Mldp@19=K. FF0>‡j]44✳%0`KEQ};TR%r#Y2"T959kn`T~#4 ?\P=-}e0>v"a1]7d!\vEّ-䌖Il2;e˘zRtD#k0!"ҫ( K}Oa wAoZԿCa'v{ ./ '"|vHx5!Αۙ6P0MofѰ$ % <UY : 8>@W wP"fаJ8+{| ϾPtuoGi .oǠ1x'򌢵M96q۾kȞyiqDAiBu`n1i EQʬ*#=j)Md~!V g%[F+7vx4S'TG_ڇ\>-QyzHP2S_R>IU|7CO×@W?HqӖv½ݶFJ+l5tTtrL'Q8m%Yags,$=MOIaB,)KCuokps¡$j7tYGendstream endobj 32 0 obj 2445 endobj 36 0 obj <> stream xUn8}W2SH(6Mm X>4@hYY*RP!);Nm-3sx L17^pB*A4?tV lj@iO駳Ez D$ޒ(<t'7 CYCROAi٠J91 G(=0B_1a@Gn1Dd4hpEɬveؽx6bLZRfa\ ۡn7u7#>$XDܐT4fmQKduWݨe,{A/Br_=haXU{ ^qF%bmnO V]3ꍍ`-LÏD'PmeV=jTi{YضSOB}hڈ-\ᩇl`cjfG;i+[ʹ9UzӘ7;83Άqin( ~ M;e-3%-B?  T tu~ w8 ~*F9E\N 'hB? !I?_\<'$~oIT9o7U[ ݰf#,St+ݩm0й68%hfZa&SUHx*(؞}8[_̓Ϲ&u~r{@Rtc?E5 ~d}q.ȃ%\pσ^44MQ͗(6yyvlu0 R7?"۪k{؉-@IRxW"JjӞV?M`Nh*:$ᛎFG*lX9Gf4Ͽendstream endobj 37 0 obj 954 endobj 4 0 obj <> /Contents 5 0 R >> endobj 20 0 obj <> /Contents 21 0 R >> endobj 25 0 obj <> /Contents 26 0 R >> endobj 30 0 obj <> /Contents 31 0 R >> endobj 35 0 obj <> /Contents 36 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R 20 0 R 25 0 R 30 0 R 35 0 R ] /Count 5 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 18 0 obj <> endobj 19 0 obj <> endobj 23 0 obj <> endobj 24 0 obj <> endobj 28 0 obj <> endobj 29 0 obj <> endobj 33 0 obj <> endobj 34 0 obj <> endobj 38 0 obj <> endobj 39 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 45 0 obj <> endobj 16 0 obj <> endobj 14 0 obj <> endobj 12 0 obj <> endobj 46 0 obj <> endobj 11 0 obj <> endobj 40 0 obj <>stream xWy|SױBC8Įɥ`C i([n0lw,﫼I,t}e,,+X iH چHCk^C}sȄ6]=3|q3gp"aOl"kcrB"aH;CxCLTϼl$̑#b8\gURgs3E/ܻ;`omJNQ+ccej{+b=E"!9%Q;91<jCR7+mMߖ^]~cMHty.nkΏ[p?r{E>Mn#[mrosp>2wrn'ˉ8'nCEswEjm#Rә;gH$}  }Y̊u󥀗N8x;T9)l1lPo 4k2OS^y)!ԊvUe4N\kCˠ+d=o!$C[+kz;hAcZ&q.ڵxm 䯻 }iT0 ]~Q2S? 0=aEE8 J,(Jk"̈T664`;sz[SڜrffYyVJiRZWJRHf~VO^NVrZܛ֬&M]lP悮8@G]&_P"ߚB{[&U}:s# 2π`0%%%MSO.@.`ˣ'oF_:* 3̓2ǟL_); ]š.kWPܐ ض x/<{hӡKC ]\le9E_/5$O bӕ:Z_v=\DpGKݐjXJԣTca;J=n}~ ڂ$Jƞj^mVh 6m -dћ4t!&ygՊQوӳ[Ak 2I!ɭhm94.^4"]${=a94F5Cg|"E#6!OД 脿HNN+;`He!m>%7C= DM.eͩ.ܼM%X)E)Ie%G'GYKyDDd(b Sy #)gAb,YeV; ~Ef/<\ g-Rfe #u9N;گH$wqK /+f|kCNf4þSVJUrя(# 11䧠IvqY1Ÿ[XWXn=nё@w17"}@K°鐫6Pء##40Ĥ|$MIK#81ῶ?,Jΐ%Md%GDk'*Q>eaNO*#L"gϱpyYꙮ‚/m4NTǫ JAB(\ŽJFz_mZ{)VZeBꩇ#}5/)+'|g֦/C)#O.Kˊ+&Df" S[NtkzLO` SYU2t[ _L⢐6E,zXLLxHwhOhlO/TfQn 8RP RHLDE)%jyLDΡsW.wn-dۖkXp%κ:#cţl-8OLS[3ۥ맆UQ}Sۉ\zj`.o+eu,/c|+8Uxʂt Vؙc3G5f͢w`rTl{Ni{&8M[Џa L ;*эFm3zȢ =sE}&u<0 M럗5(a'9f Fwn}ʠSlVg+db\ǟkyCTa`ЋM~wd@Y(va~gC}s(ت<#99ט57b/LCsNﲯH&ھkq%{6657t2KZMj5Q:fZ ܇uEP&A.x'U-|K svtYS endstream endobj 9 0 obj <> endobj 41 0 obj <>stream xxy\SW!{o'`4MljjqFEYy$$$$@SyFEqguVjGmZ۵;9wY+kzywIŚv$8?vcdo3o39`4y 3;0aabZK.`ͪk%-kelp`ĂȨp~ &?0>7?Omn#wDE;nOބ}"?N?r$9,uFL,>[Rzj-_rAG"l b!qXD8 'b qp&>$\Wb)Fl'܉rƒ#V;.bXM!~baO|B +BM#YM$s'\†O&db .'f’xJ fp5 ŸxȊd={]#j:')%oR[ZjEgO^<)SSvxڝ髧g[N |Nfcf߬MκϝrWp3esy7Bv~ \}sl|mO_;IBX(n=̻12^阛DG)jzQ Ba?́&giA!H &9EC`.5 󸐂FK&3܋/Gt6 2BNV̩ʂ@T"JOI -+ 0z}i۱O)U,s)ިtQ!DZJ KuϤ'2ӱDu<)<q;|EIPmW.!!d<9yWᖁ3QYɹ L5p*ZV |"dFjeK8gu<Frl%`F˭ gF?%cs#|v+=@iJm3!PS Km*WW0MKk74c뎣3:;X2$dgknw|^#8]9bFU""7oJh6FJuM[Qҵ>.4W*3U8׫6xl "4֚WCk >))eg eEs WLَsAlF<->)D@T^bYhc pSZS^%1Y\N/lIzQztԈPZhKWAq)T"] Cj m%k2UPHȠELe _`Pz4Ξ &r.H=LxJ/0 T6Է$FpHtN$\"1x R*2 GJ0Cd%8E!ZoBIi>˶pﶔQ["}FEWbIA|yYWeu;̀92RT%dqqٱéמ¡ĒXt9'HA IC^gd Ufh*j3m\{6P7"KՠT1dunnV3$c.M"ru[h z(j;ZKନ318 ]E@NL!C4g9f+;8`1ժSd VʢVz(|i[LudH]%ƘUȓ,S<>m»*u ڠxa9 aW~@2Ne|6wCWzR]AY2ˎC s3ܸ[dT%tO])0jWǷ9z6,M T5@5WvE8 Rh4DI0=l}b%4ǦTu%sJ D':(WEiu=[fc&2 $YЍN+k0&FL5@0R^WDMb,wœF-b#SB yD~rEH&_ Yv!BZԩ;!EFz1Yopg\OʏHP9Z=t1W8^Lk/ ss#J+=ޑFqSM킺aQ)ef'OEP UFLi#Jnje,q4Y9E$42w9dM܎"Ϟ( 3U&bFqS5J/dn`=>,kWl`tQ'D(|oV``-d_,?*Oee% (R,91Z_b g1} [oh՜TD~*LֿKq.#-"wQ>ǹ0U’\aD3Y2'b?p> :k4Jߔ74phQ(;`K#u0$N * # N_;oV̛!ɆENhS+/8 ;-Op^D82,|}R@Z M \bc₂\1U@6}4;Pyo]{зw̝ByD8@^-ViiUw!{(haWzf#mMevDe! oCKɪg;X3sσtcv[EUmQE&n4GժK4)8[}*NJ:_R`6׎.Q.N0җҕ]Ϫ SճL%>ˋ΋ƊbJZ!؄D,3aϗLh??|R{rPT :=۲7笋5bPV۞Yցmjk7AU%ib|.UDy߷rq86UMg%w69XPNAYg_`qgFA =.::&)>H~$e&,K6ݛ#ŴJwTj}%u5;ȃRۥUxSeY˙(LU'E"?Ã5΂AojGt* "Az޿6MU ۈ;+.lݩK:r:rܓy3|'ǢKf{=4jd9֟YJn"f+C G+pĘG t&ɜv1 lɌ%*t V!!"JbwN\y<߸mW'Z]x up&+GBui3@*HKKȒl2t'ib~Z<S= %3N6A} SGs>Y"ʔ[q V'Gy GufENA]D=kDImlfzvKP}Ӱ_+fC4w-%@fCk 5I ǣ)Dr [7z1Ϳ7 1&MatyCMUoI*pSjG̿q& H7hM56Ҩ BHJ)DEBe&Ň~rnчI뜁Jݰ~H)t.`[WnO!ʡN#XSxf"|njva⨆I }xq?  &Uxkk /9tl5B H&+S{r; Ui:." l ɸŒ`JdSB Sߝ5~eqwrh <;C ^S}g8(&ZvǾ7vOl~) )Eao?[FcqD{np l s;ĉiJ<#\+Թ]ԓH K襇nJL1T BqHcc=Wwԩ'8XT o,8 :w/3;[N]WA]^AqNCV#tn2=$29@>?6XXZ_¬ٌV."Ek>u{ ;/~ƒ$wǗhw^Xqki䇺 1;+֗M6Oݳj_Y+!ֆ]s?|p[|MA{ߵ:8mqzqgc~p:sNw{all!AfW_+RT+JK.Z]}0Y @y/cQj=υ * mWh6f1A>œ=~h=b/@ˢi8 Ǹ 1#M/ χp+’@sj$d+4l3fy77<&&4&)6\̒ʈUU~'U8{41ڽDs-]vwZꝀ.\V]_Ph4JJ=C+sr[.v alٿn??9<:eV_9 )8|0 Rlyǰ#<&ڠ%MhVG. -(m !x~/|^wZc!C v'}0X7m8Y?;],M}i_TzOVju0@XØ~K^7YAzN=zd> =anA;p. n=F/jj2hs›E{AR]]owy ;*8cC\hއ>A++:ע}3Ɩ[6ũOݓ&FG5PzSXV^m/Ъ1c Gl886[1 kQZIN-ڷow[/#Yǽr V(,xƦ~z j3(.e?7 57ih@0i˴ qEhfս#+ҚB\Wa*uۼpG0OH+S~XPY>kf>~n :lI}Ci)nP%7fWLo,M$Vۨ\/ΦGFb#OOd|Lۑl@j5o~%(H/" ӪlrDe*[n F1/VMXHc- B4: j]0k5ױQca5_+혧QYxܳJw&I7L7n=$J.ÐԎYղ?/)5ѐZ}ک\8zKۆ.vB4]EsܑSu'`)8RRĸA"siӞfMNE endstream endobj 17 0 obj <> endobj 42 0 obj <>stream xWiT׶TDӨtcT% O@ID+ڌ  'FA΀D!x=w۬{ߏUu>{w#t<o ٪=>}ܸ?~DzDat*m&B}/cbjjf%qkX ,Z8=0qȗ!1aQgq!["Cb]"1]*[A̍޲|k̊Xs\|@B`KkMa^_Y.\dx F&“Cx\‡%k {O,' GbD8Jb!"\WFdb*aLL#&v10I&tlkc1NN|xӤDͦ }qǏFۤwhÄFa&O1p757aIܠ>7ܰ>P:Y0q_ IqZFR4ܯE=AXTa Y--I ",b}Y5Kb-4J4ydU(I/4 \Do{,rޭVV-"&H 6;03olfͲ?a;@+:0 @fiex)xpMU(bF9Ē~ci0|1>?W$w[,u0k;eT9 Ʒq|0>!EjtiRR$NNXPqʯRu *N2mpTHn)=@||b72n{zrrIZ5Ӎz,SZ=Jo/g2&@9;L?S;˥RYqVQB9e(arRyXO0N(HSnY+IDc.%wMqO4ğf6lXgKr>}N-rVdM >š&`K֗zMe紹2h"SXsf[֡C)l*j3"lP-urDEduH725 LE"skD/KV`2sbwmK!+%xR33tTR;wOJzi\ϸPn[w1Z趀~Vs*O+|bY)ch%D ahE:F  ɯh{HXL#UIznMH 4bfE&9'hs{̽_ y `SK \ۣzwC0 &Er-bjlNc511el0+3zg`z=n#'yW ME70} U啘iJ%m9颵\cYs񭐵L^|aFJ _P/`- x#I\ *UL34gjj8 hhR ?mG+T*0+3Ԃ6;pu7x7 {tCnR;GxxSj7Sdu7m+t`cR \e*ne$j| 'Ƴa*X(Oqa!OfFhʗ4x_3O)/kGNV((^~.Vԁ*Q4 ?uG71C -F)??ǎD1!5 ^t LŜ `i@" Q]<ԩJ4d>]D)rܐW P $iJrxsߍ헹ZzVde6d[r鶆D5i,2tcu`xSooM &&a-M*)+,]/jhn_Ĥg#Ja0(|!A3Z[h>?{Sp@.D$X)rS5q|!H4ՐŒRѹF~Զjf>5gBeIjJY 1#|12|ⳗ  HcT>pEhrbg;eg?ds*`bi~+b@4n}X:`:)TwpLVԾbg`-# QdK;Mk.͙bMkEN!^M~z6:`+(l{z4twy;8x,֥ȩ~qحpQ ߄il:uMv Yo&)wf|IRc.޸yehY>ҟ f[qIQf06Hϫw]{UgU|MOqd`Trl'HOl_dS endstream endobj 15 0 obj <> endobj 43 0 obj <>stream xVkPSg>!9(UAR4'.V[;*W"BV@>@[-Z*j[񶶵N[J/8%1]gO;yQ<oVpzvfrBⰸwlo97׍aݍTy𑇠mĞpe6>E(r~ё1 -NLޓ$- X\+{EjBV4sONBJzFjB<495.;K%=-]%(ߕGEQ>iffɳsROHܓ7%u%oQTNEPTQ1T,NSRj=Hm6S[PʇROQA\%*He|w~```o2̕i }O}vw=,p4#|hV_b׫CLH1Y3 LGsckv k5C^Ԫim.}HtN)* T ʺ:T'=RܭII J ܱ~rӬ|nNb)cA*VXK2L-Ұ "@݅,7Y`>$Z<~5Il#wq=-b h`C=f{"޽$,fEޓ_`mפXxD|LL߳e#-Nǝ߱}Iqעh}ZT;36HsWCXי18^(XvFMZnU myQUoj0WK/TYT%%oEJT}0mc, 7e خWVMTԨ@Ja+oFB/BURP\_W\S*u&r kK;|J qH+fa^ L6JP$|$RQ]mj?bl0|lqjtRQ(I}$Z4hh S 2u^vڍ*os.0Ѣ 7edQ#SM em,3,YGX>k';Q#JqlE"EA4_.FzUCM%i~~ J,EZ][Z1M$`*h!+0XeRmO/FɃ0΁n @a8a+ nL6V10x5]Rk0` mKB81aw2 Bp#~ήԮ: $G9N -"Ǜ ˑH҇/)٦dl24*6v>-AlSFyt7쳔3; !Rs.3~lLjJ ڗk~=)2`N'"Չ/A/_*Եx7./hYV{/t-7`WpIng _tdk ps>QC<`be`{H_gtiZ]]kXPhIVXWrV ;C,tn }8[\͝ox2!9fnax䱣G2;Y+p z2;m[$[p]{exf>iUBby  &SQ]6{ &HkP3- -x̰k< endstream endobj 13 0 obj <> endobj 44 0 obj <>stream xXytTC2=!&Ĵg5d)0YYjhl:0{ꃀRr6Z|vG; mƦFەd 05,^zYi$,SwjF0)Dz֐#bb q慐SHm\U]%ZY7Ham0'#/.|Xr8zGw¥HogU;T^yUa~A&e[M4\F7TDz{e,W& dsh Q !aHs<׹ 梙(Rsl 0Q}O.l^fmkG/^0qLHԋCB fd}/K^jeX_][S#)UZJyFS<{Ez t=:-׫~96GtPfv^ R]Wښ,@Tm }ʐm|cּɜ֝aL wc~w%'jʯ'ivw]_TCFކ&eV}6CS Ix?urL*2c22PQugIa&bo* mtwpaΣ_(8 Ͷ(&ڵ,P hcR5ioLԆD¼ARR ͵aA)yU5NS./fdDw;O9n`Z/{/-쒹 _D } 85kH7kU FQۛeۆXtxN:Zg0 @6kR6g:cƣU@g6M҅@!})yI}W|0\rlGPZr?c4V7Zm=hTwKr;:$SxF \=AfUIul2TX+-S%XtFMJx?A>Ne}#3b5VIvVn3dݠmA;݂l 5 J0`>')ȓdl@G?@NPE8JTN pF{+f Vx⢀zFc⦓#7!3R8>6LMJ$TN.EŐ xY퍎0@8G)yQXF/`s{&E{q(b\$4 Ny.|'t9\^,6Ւu`kP >3x QiХoD0Cv4~:!hh}A&ַ_M_TED&fN:a }KBBB2>Әi`0#!F7m>U9јF[֮ Ex{٤#X,$ Gsk$'B5#kԌ~ر~:'kcn+aZoŴFXIINV$yu5`$Z񋐈2?'O|@n\B 4uR^#x _:# :cpƀ6UcSpn篘6BzPo`8_vn5FV= -Xdf @I?KT跷}SQůOK EFCeÃ} )%mLvŦMdÞ8nb%$-v#AYjthkp}h#}0&K4Il~ZPx 䉷fQ*'/ug6lD~̈i^3*9ҏ#!'Ө~+`X&E_Po7^fR7ԥѥ92H"Pe., wn=F*t0"Y.z&h֤Ǥ~{!*Sr)FqwoMD wn kb*|__NB!\&|+V9?2=_;hnp->stream 2019-07-15T16:40:44+09:00 2019-07-15T16:40:44+09:00 groff version 1.22.3 Untitled endstream endobj 2 0 obj <>endobj xref 0 48 0000000000 65535 f 0000013293 00000 n 0000040168 00000 n 0000013206 00000 n 0000012398 00000 n 0000000015 00000 n 0000003689 00000 n 0000013358 00000 n 0000014291 00000 n 0000019923 00000 n 0000013897 00000 n 0000016277 00000 n 0000015736 00000 n 0000034881 00000 n 0000015371 00000 n 0000031984 00000 n 0000014984 00000 n 0000027818 00000 n 0000013399 00000 n 0000013429 00000 n 0000012558 00000 n 0000003709 00000 n 0000006546 00000 n 0000013503 00000 n 0000013533 00000 n 0000012720 00000 n 0000006567 00000 n 0000008793 00000 n 0000013607 00000 n 0000013637 00000 n 0000012882 00000 n 0000008814 00000 n 0000011331 00000 n 0000013711 00000 n 0000013741 00000 n 0000013044 00000 n 0000011352 00000 n 0000012378 00000 n 0000013804 00000 n 0000013834 00000 n 0000016582 00000 n 0000020470 00000 n 0000028203 00000 n 0000032325 00000 n 0000035205 00000 n 0000014840 00000 n 0000016189 00000 n 0000038745 00000 n trailer << /Size 48 /Root 1 0 R /Info 2 0 R /ID [] >> startxref 40322 %%EOF softflowd-softflowd-1.0.0/softflowd.spec000066400000000000000000000030011352553127000204040ustar00rootroot00000000000000# Figure out release tag (e.g. rhel3, fc1) based on redhat-release file %global _RHTAG %(sed 's/(.*)//;s/ [A-Z]* //;s/[a-z ]*//g' /etc/redhat-release | tr '[:upper:]' '[:lower:]') Name: softflowd Summary: Network traffic analyser capable of Cisco NetFlow data export Version: 1.0.0 Release: 1.%{_RHTAG} Source: softflowd-%{version}.tar.gz Group: System/Utilities License: BSD BuildRoot: %{_tmppath}/%{name}-root URL: http://www.mindrot.org/softflowd.html Vendor: mindrot.org %description softflowd is a software implementation of a flow-based network traffic monitor. softflowd reads network traffic and gathers information about active traffic flows. A "traffic flow" is communication between two IP addresses or (if the overlying protocol is TCP or UDP) address/port tuples. The intended use of softflowd is as a software implementation of Cisco’s NetFlow traffic account system. softflowd supports data export using versions 1, 5 or 9 of the NetFlow protocol. %prep %setup %build %configure make %install rm -rf $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d mkdir -p $RPM_BUILD_ROOT/etc/sysconfig cp %_sourcedir/softflowd.init $RPM_BUILD_ROOT/etc/rc.d/init.d/softflowd cp %_sourcedir/softflowd.sysconfig $RPM_BUILD_ROOT/etc/sysconfig/softflowd %files %defattr(-,root,root) /usr/sbin/* /usr/share/man/* %attr(0755,root,root) /etc/rc.d/init.d/softflowd %config(noreplace) %attr(0644,root,root) /etc/sysconfig/softflowd %doc ChangeLog README TODO %clean rm -rf $RPM_BUILD_ROOT softflowd-softflowd-1.0.0/softflowd.sysconfig000066400000000000000000000004471352553127000214710ustar00rootroot00000000000000# Config file for softflowd startup # Location of softflowd binary #SOFTFLOW_PROG=/usr/sbin/softflowd # Options passed to the softflowd program # Default - not very useful #SOFTFLOW_OPTS="-i eth0" # Example NetFlow v5 export from traffic on eth1 #SOFTFLOW_OPTS="-v 5 -i eth1 -n hostname:2055" softflowd-softflowd-1.0.0/strlcat.c000066400000000000000000000037141352553127000173540ustar00rootroot00000000000000/* OPENBSD ORIGINAL: lib/libc/string/strlcat.c */ /* $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $ */ /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "common.h" #ifndef HAVE_STRLCAT #if defined(LIBC_SCCS) && !defined(lint) static char *rcsid = "$OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $"; #endif /* LIBC_SCCS and not lint */ #include #include /* * Appends src to string dst of size siz (unlike strncat, siz is the * full size of dst, not space left). At most siz-1 characters * will be copied. Always NUL terminates (unless siz <= strlen(dst)). * Returns strlen(src) + MIN(siz, strlen(initial dst)). * If retval >= siz, truncation occurred. */ size_t strlcat(char *dst, const char *src, size_t siz) { register char *d = dst; register const char *s = src; register size_t n = siz; size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end */ while (n-- != 0 && *d != '\0') d++; dlen = d - dst; n = siz - dlen; if (n == 0) return(dlen + strlen(s)); while (*s != '\0') { if (n != 1) { *d++ = *s; n--; } s++; } *d = '\0'; return(dlen + (s - src)); /* count does not include NUL */ } #endif /* !HAVE_STRLCAT */ softflowd-softflowd-1.0.0/strlcpy.c000066400000000000000000000035341352553127000174000ustar00rootroot00000000000000/* OPENBSD ORIGINAL: lib/libc/string/strlcpy.c */ /* $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $ */ /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "common.h" #ifndef HAVE_STRLCPY #if defined(LIBC_SCCS) && !defined(lint) static char *rcsid = "$OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $"; #endif /* LIBC_SCCS and not lint */ #include #include /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ size_t strlcpy(char *dst, const char *src, size_t siz) { register char *d = dst; register const char *s = src; register size_t n = siz; /* Copy as many bytes as will fit */ if (n != 0 && --n != 0) { do { if ((*d++ = *s++) == 0) break; } while (--n != 0); } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return(s - src - 1); /* count does not include NUL */ } #endif /* !HAVE_STRLCPY */ softflowd-softflowd-1.0.0/sys-tree.h000066400000000000000000000542021352553127000174560ustar00rootroot00000000000000/* $OpenBSD: tree.h,v 1.9 2004/11/24 18:10:42 tdeval Exp $ */ /* * Copyright 2002 Niels Provos * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _SYS_TREE_H_ #define _SYS_TREE_H_ /* * This file defines data structures for different types of trees: * splay trees and red-black trees. * * A splay tree is a self-organizing data structure. Every operation * on the tree causes a splay to happen. The splay moves the requested * node to the root of the tree and partly rebalances it. * * This has the benefit that request locality causes faster lookups as * the requested nodes move to the top of the tree. On the other hand, * every lookup causes memory writes. * * The Balance Theorem bounds the total access time for m operations * and n inserts on an initially empty tree as O((m + n)lg n). The * amortized cost for a sequence of m accesses to a splay tree is O(lg n); * * A red-black tree is a binary search tree with the node color as an * extra attribute. It fulfills a set of conditions: * - every search path from the root to a leaf consists of the * same number of black nodes, * - each red node (except for the root) has a black parent, * - each leaf node is black. * * Every operation on a red-black tree is bounded as O(lg n). * The maximum height of a red-black tree is 2lg (n+1). */ #define SPLAY_HEAD(name, type) \ struct name { \ struct type *sph_root; /* root of the tree */ \ } #define SPLAY_INITIALIZER(root) \ { NULL } #define SPLAY_INIT(root) do { \ (root)->sph_root = NULL; \ } while (0) #define SPLAY_ENTRY(type) \ struct { \ struct type *spe_left; /* left element */ \ struct type *spe_right; /* right element */ \ } #define SPLAY_LEFT(elm, field) (elm)->field.spe_left #define SPLAY_RIGHT(elm, field) (elm)->field.spe_right #define SPLAY_ROOT(head) (head)->sph_root #define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) /* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ #define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ (head)->sph_root = tmp; \ } while (0) #define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ SPLAY_LEFT(tmp, field) = (head)->sph_root; \ (head)->sph_root = tmp; \ } while (0) #define SPLAY_LINKLEFT(head, tmp, field) do { \ SPLAY_LEFT(tmp, field) = (head)->sph_root; \ tmp = (head)->sph_root; \ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ } while (0) #define SPLAY_LINKRIGHT(head, tmp, field) do { \ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ tmp = (head)->sph_root; \ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ } while (0) #define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ } while (0) /* Generates prototypes and inline functions */ #define SPLAY_PROTOTYPE(name, type, field, cmp) \ void name##_SPLAY(struct name *, struct type *); \ void name##_SPLAY_MINMAX(struct name *, int); \ struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ \ /* Finds the node with the same key as elm */ \ static __inline struct type * \ name##_SPLAY_FIND(struct name *head, struct type *elm) \ { \ if (SPLAY_EMPTY(head)) \ return(NULL); \ name##_SPLAY(head, elm); \ if ((cmp)(elm, (head)->sph_root) == 0) \ return (head->sph_root); \ return (NULL); \ } \ \ static __inline struct type * \ name##_SPLAY_NEXT(struct name *head, struct type *elm) \ { \ name##_SPLAY(head, elm); \ if (SPLAY_RIGHT(elm, field) != NULL) { \ elm = SPLAY_RIGHT(elm, field); \ while (SPLAY_LEFT(elm, field) != NULL) { \ elm = SPLAY_LEFT(elm, field); \ } \ } else \ elm = NULL; \ return (elm); \ } \ \ static __inline struct type * \ name##_SPLAY_MIN_MAX(struct name *head, int val) \ { \ name##_SPLAY_MINMAX(head, val); \ return (SPLAY_ROOT(head)); \ } /* Main splay operation. * Moves node close to the key of elm to top */ #define SPLAY_GENERATE(name, type, field, cmp) \ struct type * \ name##_SPLAY_INSERT(struct name *head, struct type *elm) \ { \ if (SPLAY_EMPTY(head)) { \ SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ } else { \ int __comp; \ name##_SPLAY(head, elm); \ __comp = (cmp)(elm, (head)->sph_root); \ if(__comp < 0) { \ SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ SPLAY_RIGHT(elm, field) = (head)->sph_root; \ SPLAY_LEFT((head)->sph_root, field) = NULL; \ } else if (__comp > 0) { \ SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ SPLAY_LEFT(elm, field) = (head)->sph_root; \ SPLAY_RIGHT((head)->sph_root, field) = NULL; \ } else \ return ((head)->sph_root); \ } \ (head)->sph_root = (elm); \ return (NULL); \ } \ \ struct type * \ name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ { \ struct type *__tmp; \ if (SPLAY_EMPTY(head)) \ return (NULL); \ name##_SPLAY(head, elm); \ if ((cmp)(elm, (head)->sph_root) == 0) { \ if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ } else { \ __tmp = SPLAY_RIGHT((head)->sph_root, field); \ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ name##_SPLAY(head, elm); \ SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ } \ return (elm); \ } \ return (NULL); \ } \ \ void \ name##_SPLAY(struct name *head, struct type *elm) \ { \ struct type __node, *__left, *__right, *__tmp; \ int __comp; \ \ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ __left = __right = &__node; \ \ while ((__comp = (cmp)(elm, (head)->sph_root))) { \ if (__comp < 0) { \ __tmp = SPLAY_LEFT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if ((cmp)(elm, __tmp) < 0){ \ SPLAY_ROTATE_RIGHT(head, __tmp, field); \ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKLEFT(head, __right, field); \ } else if (__comp > 0) { \ __tmp = SPLAY_RIGHT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if ((cmp)(elm, __tmp) > 0){ \ SPLAY_ROTATE_LEFT(head, __tmp, field); \ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKRIGHT(head, __left, field); \ } \ } \ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ } \ \ /* Splay with either the minimum or the maximum element \ * Used to find minimum or maximum element in tree. \ */ \ void name##_SPLAY_MINMAX(struct name *head, int __comp) \ { \ struct type __node, *__left, *__right, *__tmp; \ \ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ __left = __right = &__node; \ \ while (1) { \ if (__comp < 0) { \ __tmp = SPLAY_LEFT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if (__comp < 0){ \ SPLAY_ROTATE_RIGHT(head, __tmp, field); \ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKLEFT(head, __right, field); \ } else if (__comp > 0) { \ __tmp = SPLAY_RIGHT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if (__comp > 0) { \ SPLAY_ROTATE_LEFT(head, __tmp, field); \ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKRIGHT(head, __left, field); \ } \ } \ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ } #define SPLAY_NEGINF -1 #define SPLAY_INF 1 #define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) #define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) #define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) #define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) #define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) #define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) #define SPLAY_FOREACH(x, name, head) \ for ((x) = SPLAY_MIN(name, head); \ (x) != NULL; \ (x) = SPLAY_NEXT(name, head, x)) /* Macros that define a red-black tree */ #define RB_HEAD(name, type) \ struct name { \ struct type *rbh_root; /* root of the tree */ \ } #define RB_INITIALIZER(root) \ { NULL } #define RB_INIT(root) do { \ (root)->rbh_root = NULL; \ } while (0) #define RB_BLACK 0 #define RB_RED 1 #define RB_ENTRY(type) \ struct { \ struct type *rbe_left; /* left element */ \ struct type *rbe_right; /* right element */ \ struct type *rbe_parent; /* parent element */ \ int rbe_color; /* node color */ \ } #define RB_LEFT(elm, field) (elm)->field.rbe_left #define RB_RIGHT(elm, field) (elm)->field.rbe_right #define RB_PARENT(elm, field) (elm)->field.rbe_parent #define RB_COLOR(elm, field) (elm)->field.rbe_color #define RB_ROOT(head) (head)->rbh_root #define RB_EMPTY(head) (RB_ROOT(head) == NULL) #define RB_SET(elm, parent, field) do { \ RB_PARENT(elm, field) = parent; \ RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ RB_COLOR(elm, field) = RB_RED; \ } while (0) #define RB_SET_BLACKRED(black, red, field) do { \ RB_COLOR(black, field) = RB_BLACK; \ RB_COLOR(red, field) = RB_RED; \ } while (0) #ifndef RB_AUGMENT #define RB_AUGMENT(x) #endif #define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ (tmp) = RB_RIGHT(elm, field); \ if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \ RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ } \ RB_AUGMENT(elm); \ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ else \ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ } else \ (head)->rbh_root = (tmp); \ RB_LEFT(tmp, field) = (elm); \ RB_PARENT(elm, field) = (tmp); \ RB_AUGMENT(tmp); \ if ((RB_PARENT(tmp, field))) \ RB_AUGMENT(RB_PARENT(tmp, field)); \ } while (0) #define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ (tmp) = RB_LEFT(elm, field); \ if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \ RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ } \ RB_AUGMENT(elm); \ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ else \ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ } else \ (head)->rbh_root = (tmp); \ RB_RIGHT(tmp, field) = (elm); \ RB_PARENT(elm, field) = (tmp); \ RB_AUGMENT(tmp); \ if ((RB_PARENT(tmp, field))) \ RB_AUGMENT(RB_PARENT(tmp, field)); \ } while (0) /* Generates prototypes and inline functions */ #define RB_PROTOTYPE(name, type, field, cmp) \ void name##_RB_INSERT_COLOR(struct name *, struct type *); \ void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ struct type *name##_RB_REMOVE(struct name *, struct type *); \ struct type *name##_RB_INSERT(struct name *, struct type *); \ struct type *name##_RB_FIND(struct name *, struct type *); \ struct type *name##_RB_NEXT(struct type *); \ struct type *name##_RB_MINMAX(struct name *, int); \ \ /* Main rb operation. * Moves node close to the key of elm to top */ #define RB_GENERATE(name, type, field, cmp) \ void \ name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ { \ struct type *parent, *gparent, *tmp; \ while ((parent = RB_PARENT(elm, field)) && \ RB_COLOR(parent, field) == RB_RED) { \ gparent = RB_PARENT(parent, field); \ if (parent == RB_LEFT(gparent, field)) { \ tmp = RB_RIGHT(gparent, field); \ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ RB_COLOR(tmp, field) = RB_BLACK; \ RB_SET_BLACKRED(parent, gparent, field);\ elm = gparent; \ continue; \ } \ if (RB_RIGHT(parent, field) == elm) { \ RB_ROTATE_LEFT(head, parent, tmp, field);\ tmp = parent; \ parent = elm; \ elm = tmp; \ } \ RB_SET_BLACKRED(parent, gparent, field); \ RB_ROTATE_RIGHT(head, gparent, tmp, field); \ } else { \ tmp = RB_LEFT(gparent, field); \ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ RB_COLOR(tmp, field) = RB_BLACK; \ RB_SET_BLACKRED(parent, gparent, field);\ elm = gparent; \ continue; \ } \ if (RB_LEFT(parent, field) == elm) { \ RB_ROTATE_RIGHT(head, parent, tmp, field);\ tmp = parent; \ parent = elm; \ elm = tmp; \ } \ RB_SET_BLACKRED(parent, gparent, field); \ RB_ROTATE_LEFT(head, gparent, tmp, field); \ } \ } \ RB_COLOR(head->rbh_root, field) = RB_BLACK; \ } \ \ void \ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ { \ struct type *tmp; \ while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ elm != RB_ROOT(head)) { \ if (RB_LEFT(parent, field) == elm) { \ tmp = RB_RIGHT(parent, field); \ if (RB_COLOR(tmp, field) == RB_RED) { \ RB_SET_BLACKRED(tmp, parent, field); \ RB_ROTATE_LEFT(head, parent, tmp, field);\ tmp = RB_RIGHT(parent, field); \ } \ if ((RB_LEFT(tmp, field) == NULL || \ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ (RB_RIGHT(tmp, field) == NULL || \ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ RB_COLOR(tmp, field) = RB_RED; \ elm = parent; \ parent = RB_PARENT(elm, field); \ } else { \ if (RB_RIGHT(tmp, field) == NULL || \ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ struct type *oleft; \ if ((oleft = RB_LEFT(tmp, field)))\ RB_COLOR(oleft, field) = RB_BLACK;\ RB_COLOR(tmp, field) = RB_RED; \ RB_ROTATE_RIGHT(head, tmp, oleft, field);\ tmp = RB_RIGHT(parent, field); \ } \ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ RB_COLOR(parent, field) = RB_BLACK; \ if (RB_RIGHT(tmp, field)) \ RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ RB_ROTATE_LEFT(head, parent, tmp, field);\ elm = RB_ROOT(head); \ break; \ } \ } else { \ tmp = RB_LEFT(parent, field); \ if (RB_COLOR(tmp, field) == RB_RED) { \ RB_SET_BLACKRED(tmp, parent, field); \ RB_ROTATE_RIGHT(head, parent, tmp, field);\ tmp = RB_LEFT(parent, field); \ } \ if ((RB_LEFT(tmp, field) == NULL || \ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ (RB_RIGHT(tmp, field) == NULL || \ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ RB_COLOR(tmp, field) = RB_RED; \ elm = parent; \ parent = RB_PARENT(elm, field); \ } else { \ if (RB_LEFT(tmp, field) == NULL || \ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ struct type *oright; \ if ((oright = RB_RIGHT(tmp, field)))\ RB_COLOR(oright, field) = RB_BLACK;\ RB_COLOR(tmp, field) = RB_RED; \ RB_ROTATE_LEFT(head, tmp, oright, field);\ tmp = RB_LEFT(parent, field); \ } \ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ RB_COLOR(parent, field) = RB_BLACK; \ if (RB_LEFT(tmp, field)) \ RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ RB_ROTATE_RIGHT(head, parent, tmp, field);\ elm = RB_ROOT(head); \ break; \ } \ } \ } \ if (elm) \ RB_COLOR(elm, field) = RB_BLACK; \ } \ \ struct type * \ name##_RB_REMOVE(struct name *head, struct type *elm) \ { \ struct type *child, *parent, *old = elm; \ int color; \ if (RB_LEFT(elm, field) == NULL) \ child = RB_RIGHT(elm, field); \ else if (RB_RIGHT(elm, field) == NULL) \ child = RB_LEFT(elm, field); \ else { \ struct type *left; \ elm = RB_RIGHT(elm, field); \ while ((left = RB_LEFT(elm, field))) \ elm = left; \ child = RB_RIGHT(elm, field); \ parent = RB_PARENT(elm, field); \ color = RB_COLOR(elm, field); \ if (child) \ RB_PARENT(child, field) = parent; \ if (parent) { \ if (RB_LEFT(parent, field) == elm) \ RB_LEFT(parent, field) = child; \ else \ RB_RIGHT(parent, field) = child; \ RB_AUGMENT(parent); \ } else \ RB_ROOT(head) = child; \ if (RB_PARENT(elm, field) == old) \ parent = elm; \ (elm)->field = (old)->field; \ if (RB_PARENT(old, field)) { \ if (RB_LEFT(RB_PARENT(old, field), field) == old)\ RB_LEFT(RB_PARENT(old, field), field) = elm;\ else \ RB_RIGHT(RB_PARENT(old, field), field) = elm;\ RB_AUGMENT(RB_PARENT(old, field)); \ } else \ RB_ROOT(head) = elm; \ RB_PARENT(RB_LEFT(old, field), field) = elm; \ if (RB_RIGHT(old, field)) \ RB_PARENT(RB_RIGHT(old, field), field) = elm; \ if (parent) { \ left = parent; \ do { \ RB_AUGMENT(left); \ } while ((left = RB_PARENT(left, field))); \ } \ goto color; \ } \ parent = RB_PARENT(elm, field); \ color = RB_COLOR(elm, field); \ if (child) \ RB_PARENT(child, field) = parent; \ if (parent) { \ if (RB_LEFT(parent, field) == elm) \ RB_LEFT(parent, field) = child; \ else \ RB_RIGHT(parent, field) = child; \ RB_AUGMENT(parent); \ } else \ RB_ROOT(head) = child; \ color: \ if (color == RB_BLACK) \ name##_RB_REMOVE_COLOR(head, parent, child); \ return (old); \ } \ \ /* Inserts a node into the RB tree */ \ struct type * \ name##_RB_INSERT(struct name *head, struct type *elm) \ { \ struct type *tmp; \ struct type *parent = NULL; \ int comp = 0; \ tmp = RB_ROOT(head); \ while (tmp) { \ parent = tmp; \ comp = (cmp)(elm, parent); \ if (comp < 0) \ tmp = RB_LEFT(tmp, field); \ else if (comp > 0) \ tmp = RB_RIGHT(tmp, field); \ else \ return (tmp); \ } \ RB_SET(elm, parent, field); \ if (parent != NULL) { \ if (comp < 0) \ RB_LEFT(parent, field) = elm; \ else \ RB_RIGHT(parent, field) = elm; \ RB_AUGMENT(parent); \ } else \ RB_ROOT(head) = elm; \ name##_RB_INSERT_COLOR(head, elm); \ return (NULL); \ } \ \ /* Finds the node with the same key as elm */ \ struct type * \ name##_RB_FIND(struct name *head, struct type *elm) \ { \ struct type *tmp = RB_ROOT(head); \ int comp; \ while (tmp) { \ comp = cmp(elm, tmp); \ if (comp < 0) \ tmp = RB_LEFT(tmp, field); \ else if (comp > 0) \ tmp = RB_RIGHT(tmp, field); \ else \ return (tmp); \ } \ return (NULL); \ } \ \ struct type * \ name##_RB_NEXT(struct type *elm) \ { \ if (RB_RIGHT(elm, field)) { \ elm = RB_RIGHT(elm, field); \ while (RB_LEFT(elm, field)) \ elm = RB_LEFT(elm, field); \ } else { \ if (RB_PARENT(elm, field) && \ (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ elm = RB_PARENT(elm, field); \ else { \ while (RB_PARENT(elm, field) && \ (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ elm = RB_PARENT(elm, field); \ elm = RB_PARENT(elm, field); \ } \ } \ return (elm); \ } \ \ struct type * \ name##_RB_MINMAX(struct name *head, int val) \ { \ struct type *tmp = RB_ROOT(head); \ struct type *parent = NULL; \ while (tmp) { \ parent = tmp; \ if (val < 0) \ tmp = RB_LEFT(tmp, field); \ else \ tmp = RB_RIGHT(tmp, field); \ } \ return (parent); \ } #define RB_NEGINF -1 #define RB_INF 1 #define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) #define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) #define RB_FIND(name, x, y) name##_RB_FIND(x, y) #define RB_NEXT(name, x, y) name##_RB_NEXT(y) #define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) #define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) #define RB_FOREACH(x, name, head) \ for ((x) = RB_MIN(name, head); \ (x) != NULL; \ (x) = name##_RB_NEXT(x)) #endif /* _SYS_TREE_H_ */ softflowd-softflowd-1.0.0/treetype.h000066400000000000000000000056251352553127000175510ustar00rootroot00000000000000/* * Copyright 2002 Damien Miller All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Select our tree types for various data structures */ #if defined(FLOW_RB) #define FLOW_HEAD RB_HEAD #define FLOW_ENTRY RB_ENTRY #define FLOW_PROTOTYPE RB_PROTOTYPE #define FLOW_GENERATE RB_GENERATE #define FLOW_INSERT RB_INSERT #define FLOW_FIND RB_FIND #define FLOW_REMOVE RB_REMOVE #define FLOW_FOREACH RB_FOREACH #define FLOW_MIN RB_MIN #define FLOW_NEXT RB_NEXT #define FLOW_INIT RB_INIT #elif defined(FLOW_SPLAY) #define FLOW_HEAD SPLAY_HEAD #define FLOW_ENTRY SPLAY_ENTRY #define FLOW_PROTOTYPE SPLAY_PROTOTYPE #define FLOW_GENERATE SPLAY_GENERATE #define FLOW_INSERT SPLAY_INSERT #define FLOW_FIND SPLAY_FIND #define FLOW_REMOVE SPLAY_REMOVE #define FLOW_FOREACH SPLAY_FOREACH #define FLOW_MIN SPLAY_MIN #define FLOW_NEXT SPLAY_NEXT #define FLOW_INIT SPLAY_INIT #else #error No flow tree type defined #endif #if defined(EXPIRY_RB) #define EXPIRY_HEAD RB_HEAD #define EXPIRY_ENTRY RB_ENTRY #define EXPIRY_PROTOTYPE RB_PROTOTYPE #define EXPIRY_GENERATE RB_GENERATE #define EXPIRY_INSERT RB_INSERT #define EXPIRY_FIND RB_FIND #define EXPIRY_REMOVE RB_REMOVE #define EXPIRY_FOREACH RB_FOREACH #define EXPIRY_MIN RB_MIN #define EXPIRY_NEXT RB_NEXT #define EXPIRY_INIT RB_INIT #elif defined(EXPIRY_SPLAY) #define EXPIRY_HEAD SPLAY_HEAD #define EXPIRY_ENTRY SPLAY_ENTRY #define EXPIRY_PROTOTYPE SPLAY_PROTOTYPE #define EXPIRY_GENERATE SPLAY_GENERATE #define EXPIRY_INSERT SPLAY_INSERT #define EXPIRY_FIND SPLAY_FIND #define EXPIRY_REMOVE SPLAY_REMOVE #define EXPIRY_FOREACH SPLAY_FOREACH #define EXPIRY_MIN SPLAY_MIN #define EXPIRY_NEXT SPLAY_NEXT #define EXPIRY_INIT SPLAY_INIT #else #error No expiry tree type defined #endif