pax_global_header00006660000000000000000000000064147561054770014532gustar00rootroot0000000000000052 comment=0260261a2302ce635cea1c02c9ea72d7b808d8f6 irino-softflowd-488a557/000077500000000000000000000000001475610547700151465ustar00rootroot00000000000000irino-softflowd-488a557/.travis.yml000066400000000000000000000006211475610547700172560ustar00rootroot00000000000000language: c os: - linux - osx arch: - amd64 - ppc64le matrix: exclude: - os: osx arch: ppc64le 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 irino-softflowd-488a557/AUTHORS000066400000000000000000000001521475610547700162140ustar00rootroot00000000000000Original creator: Damien Miller Current maintainer: Hitoshi Irino irino-softflowd-488a557/COPYING000077700000000000000000000000001475610547700172012LICENSEustar00rootroot00000000000000irino-softflowd-488a557/ChangeLog000066400000000000000000002215501475610547700167250ustar00rootroot00000000000000commit c5523e0f1a0681912fb2b6639173d9895a703fea Author: Hitoshi Irino Date: Thu Feb 20 14:26:03 2025 +0000 Update PROGVER to 1.1.1 commit 9b7431cc81f2c7435f36aa0b62ddcdb55c5563a9 Author: Hitoshi Irino Date: Tue Feb 11 00:56:31 2025 +0000 Update Changelog and NEWS for v1.1.1 commit faa13350605e6bbe67ecae0f2c7011ee7ee7ab30 Author: Hitoshi Irino Date: Tue Feb 11 00:32:59 2025 +0000 Add -e option in usage function commit bc0aeafbca13260e57b503e51ba1a74378787cb0 Author: Hitoshi Irino Date: Tue Feb 11 00:28:54 2025 +0000 Update man page for -e option. Add softflowd.html generated from softflowd.8 (groff -Thtml -mandoc -c softflowd.8 > softflowd.html) Update softflowd.md generated from softflowd.html (pandoc -f html -t markdown softflowd.html > softflowd.md) commit 05b207b3f291bbb6228d81457e0c9b69706191aa Author: Hitoshi Irino Date: Mon Feb 10 22:33:46 2025 +0000 Fix -e option bug (eternity loop bug) - fix for loop for exporter IP address and fix bug for memcpy source - and indent -lp -br -brs -brf -ce -cdw -nut softflowd.c ipfix.c commit c2eb21f931a223d7f0c1a5a8c447a87f161d3814 Merge: 698636b d20a549 Author: Hitoshi Irino Date: Sun Nov 24 14:51:07 2024 +0900 Merge pull request #57 from bu7cher/pcap_activate_fix Do not exit if pcap_activate() returns warning. commit d20a549c33f7c6fbeef31d33215dc4f4928c629e Author: Andrey V. Elsukov Date: Tue Nov 19 17:12:09 2024 +0300 Do not exit if pcap_activate() returns warning. pcap_activate() can return 0 on success, negative value on error and positive value on partial success, e.g. PCAP_WARNING_PROMISC_NOTSUP when an interface doesn't support promisc mode. This can happen with some DLT_NULL interfaces. When there was used pcap_open_live() it worked, but after switch to pcap_create+pcap_activate it stopped. Also, libpcap uses this in pcap_open_live(): status = pcap_activate(p); if (status < 0) goto fail; commit 698636b3b4ccb066eb7885996597df5fc447b931 Author: Hitoshi Irino Date: Sun Nov 17 16:44:34 2024 +0900 bug fix: replace from IPFIX_exporterIPv4Address to IPFIX_exporterIPv6Address and from IPFIX_originalExporterIPv4Address to IPFIX_originalExporterIPv6Address commit 3ceeacc3d08ed25fdc3dedf24d07ca540a1407d2 Author: Hitoshi Irino Date: Sun Nov 10 15:53:58 2024 +0900 add -e option to specify exporter IP address commit b2a58deb9b73d6424c394d2e640b56e8048975da Author: Hitoshi Irino Date: Sun Oct 6 04:44:12 2024 +0000 fix segmentation fault error in the case of reading file that introduced in last commit (05a11dbc657c2a5c0a4fac249a9e468bcc19f39b) commit 05a11dbc657c2a5c0a4fac249a9e468bcc19f39b Author: Hitoshi Irino Date: Sun Sep 1 06:25:19 2024 +0000 Get if_index value automatically in Linux environment. - Add ioctl SIOCGIFINDEX code - indent -lp -br -brs -brf -ce -cdw -nut softflowd.c commit c00902dc98ff134925191d488c0d967ffe672201 Author: Hitoshi Irino Date: Sun Mar 3 21:24:04 2024 +0900 use ft->param.track_level instead of track_level as global variable in process_packet commit 0fce1eda06c554aee86d93968f2b507498fb8b13 Author: Hitoshi Irino Date: Sun Mar 3 16:35:54 2024 +0900 Refactoring: reduce gcc warning with some configure's enable options commit 66db0961642b916ee1bf48cf1a9b80e4b66a8528 Author: Hitoshi Irino Date: Sun Mar 3 15:13:06 2024 +0900 Refactoring: change process_packet() arguments commit 100dad90bca34b2a05f6adb6d9d430b1f2456093 Author: Hitoshi Irino Date: Sun Mar 3 13:45:09 2024 +0900 Refactoring: change to make less gcc warnings commit af7296d8f00f289ef85872fcb03e54dcff4c8777 Author: Hitoshi Irino Date: Sat Mar 2 22:50:59 2024 +0900 Refactoring: change from int to void of return value in transport_to_flowrec and ether_to_flowrec commit 3369207b8947d66a5d9010c72ecee5930f59463d Author: Hitoshi Irino Date: Sat Mar 2 16:21:15 2024 +0900 Refactoring: changing process_packet and deleting make_ndx_ipv4 and make_ndx_ipv6. commit d5798cc9a6dc9a5a4daf9c00e24bf08829d58cfa Author: Hitoshi Irino Date: Tue Feb 27 23:10:16 2024 +0900 add -g option for benchmark and some refactoring commit 586591ec7a3f1cf4192a74df36033025d4f3a19b Author: Hitoshi Irino Date: Sun Feb 25 22:42:15 2024 +0900 change process in ipv4_to_flowrec and ipv6_to_flowrec commit 1d8f65aea054c2ad0d6fa2a56937f51077bcecbd Author: Hitoshi Irino Date: Sun Feb 25 16:23:07 2024 +0900 wrong description for -I option in usage () is delted commit 9e494e1a1d4e75b16abcb67dc48e2e34b76e2494 Author: Hitoshi Irino Date: Sun Nov 5 22:23:02 2023 +0900 add -I option to specify boot time reinitialization. commit 3b3473c451846e264ff5269411172627257e58dc Merge: 433fbb7 f96142c Author: Hitoshi Irino Date: Sat Oct 22 21:41:04 2022 +0900 Merge pull request #46 from micmac1/time64 Use %lld for time_t always commit f96142c9f3267a09976cd8a6bb4cc601830bce9b Author: Sebastian Kemper Date: Fri Oct 21 23:37:42 2022 +0200 Use %lld for time_t always Compiling softflowd against musl 1.2.x for 32 bit targets shows some warnings: softflowd.c: In function 'format_flow': softflowd.c:307:13: warning: format '%ld' expects argument of type 'long int', but argument 15 has type 'suseconds_t' {aka 'long long int'} [-Wformat=] 307 | "seq:%" PRIu64 " [%s]:%hu <> [%s]:%hu proto:%u " | ^~~~~~~ ...... 315 | (flow->flow_start.tv_usec + 500) / 1000, fin_time, | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | suseconds_t {aka long long int} softflowd.c:309:27: note: format string is defined here 309 | "start:%s.%03ld finish:%s.%03ld tcp>:%02x tcp<:%02x " | ~~~~^ | | | long int | %03lld softflowd.c:307:13: warning: format '%ld' expects argument of type 'long int', but argument 17 has type 'suseconds_t' {aka 'long long int'} [-Wformat=] 307 | "seq:%" PRIu64 " [%s]:%hu <> [%s]:%hu proto:%u " | ^~~~~~~ ...... 316 | (flow->flow_last.tv_usec + 500) / 1000, flow->tcp_flags[0], | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | suseconds_t {aka long long int} softflowd.c:309:43: note: format string is defined here 309 | "start:%s.%03ld finish:%s.%03ld tcp>:%02x tcp<:%02x " | ~~~~^ | | | long int | %03lld softflowd.c: In function 'dump_flows': softflowd.c:1173:16: warning: format '%ld' expects argument of type 'long int', but argument 4 has type 'time_t' {aka 'long long int'} [-Wformat=] 1173 | "EXPIRY EVENT for flow %" PRIu64 " in %ld seconds\n", | ^~~~~~~~~~~~~~~~~~~~~~~~~ 1174 | expiry->flow->flow_seq, (long int) expiry->expires_at - now); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | time_t {aka long long int} softflowd.c:1173:56: note: format string is defined here 1173 | "EXPIRY EVENT for flow %" PRIu64 " in %ld seconds\n", | ~~^ | | | long int | %lld Dumping flow data results in a segmentation fault: root@OpenWrt:~# softflowctl dump-flows softflowd[6688]: Dumping flow data: No further output. But in the system log a segmentation fault is visible: Fri Oct 21 07:13:47 2022 kern.info kernel: [745743.417947] do_page_fault(): sending SIGSEGV to softflowd for invalid read access from 00000326 Fri Oct 21 07:13:47 2022 kern.info kernel: [745743.427175] epc = 77de0dc0 in libc.so[77d62000+a9000] Fri Oct 21 07:13:47 2022 kern.info kernel: [745743.432682] ra = 77de2b04 in libc.so[77d62000+a9000] Fri Oct 21 07:13:47 2022 kern.info kernel: [745743.443552] device br-lan.1 left promiscuous mode Fri Oct 21 07:13:47 2022 kern.info kernel: [745743.448485] device br-lan left promiscuous mode Fri Oct 21 07:13:52 2022 kern.info kernel: [745748.464316] device br-lan.1 entered promiscuous mode Fri Oct 21 07:13:52 2022 kern.info kernel: [745748.469774] device br-lan entered promiscuous mode This was reported on the OpenWrt "packages" repository's issue tracker ([1]). musl 1.2 has time64 support, meaning it always uses 64 bit time_t (also when compiling for 32 bit targets), to be Y2K38 safe. This commit changes the format specifier from "%ld" to "%lld" to fix the compiler warnings and make the segmentation fault go away. [1] https://github.com/openwrt/packages/issues/19655 Signed-off-by: Sebastian Kemper commit 433fbb7102616c671d523d4e41ae5315cd70d442 Author: Hitoshi Irino Date: Tue Sep 20 00:13:12 2022 +0000 Update for release softflowd-v1.1.0 - Update NEWS - Updtae ChangeLog - Update PROGVER from "1.0.0" to "1.1.0" in common.h - Update AC_INIT from "1.0.0" to "1.1.0" in configure.ac - Update Version from "1.0.0" to "1.1.0" in softflowd.spec - Update configure.ac by autoupdate commit 1d5ca1ca6423a96a0065dd493e8280e73d09d7bc Author: Hitoshi Irino Date: Mon Sep 19 14:11:53 2022 +0000 solve warnings commit fb015b413b9b5d9708db8c5468b62c47284b497a Author: Hitoshi Irino Date: Sat Aug 13 06:57:19 2022 +0000 Update man page for -x option. Add softflowd.html generated from softflowd.8 (groff -Thtml -mandoc -c softflowd.8 > softflowd.html) Update softflowd.md generated from softflowd.html (pandoc -f html -t markdown softflowd.html > softflowd.md) commit 18049517c1eef937bfbe71a9da10ef83db76eb23 Author: Hitoshi Irino Date: Sat Aug 13 02:23:00 2022 +0000 Add -x option for supporting MPLS packet. commit 52eab7bd3c786a406fbf0e96c76b03accf5cc9b6 Merge: c96ad14 2fe941e Author: Hitoshi Irino Date: Sat Dec 19 00:01:47 2020 +0900 Merge pull request #36 from sanjaymsh/ppc64le Travis-ci:added support for ppc64le commit 2fe941e5505defffdcc8197c64300d44d3e97e32 Author: sanjay-cpu Date: Thu Dec 17 08:44:32 2020 +0000 Travis-ci:added support for ppc64le commit c96ad14fcab93d9c79e22cacc41cb149cfce7e19 Author: Hitoshi Irino Date: Sun Sep 20 05:58:47 2020 +0900 Add markdown files generated from manpages commit a305d9151e75939dae251ab17a7c7f999b0f9e5c Merge: b9bacb0 e3eff52 Author: Hitoshi Irino Date: Fri Jul 31 23:58:46 2020 +0900 Merge pull request #34 from atonkyra/add-buffer-size-argument Add option for setting libpcap buffer size commit e3eff52474625375ae64fb28c0fdf5989c7a8e0b Author: Antti Tönkyrä Date: Wed Jul 29 13:28:08 2020 +0300 Add option for setting libpcap buffer size commit b9bacb0c64e1a3adb45600706f160f9f0f5c3419 Merge: a86b5e3 f19307b Author: Hitoshi Irino Date: Sat Jul 25 14:39:39 2020 +0900 Merge pull request #33 from pwp333/ifname Amend configure help message to add IPFIX for enable-ifname commit f19307b0533bcadaadaccbc63ec26e8c23820c84 Author: Michael Hu Date: Thu Jul 23 16:10:12 2020 -0700 Amend configure help message to add IPFIX for enable-ifname commit a86b5e35e5cbfb9aa6ac0d0a02f70dbfc1232063 Merge: 72c1f9a dcedadb Author: Hitoshi Irino Date: Fri Jul 24 07:59:57 2020 +0900 Merge pull request #29 from pwp333/ifname Report interfaceName in normal data and tempalte record commit 72c1f9ab77205c7107d9aeb13eb01701b890dd14 Merge: f5dd974 2eebed3 Author: Hitoshi Irino Date: Thu Jul 23 13:42:42 2020 +0900 Merge pull request #32 from pwp333/icmp Report ip protocol number for ICMP flow for IPFIX commit 2eebed3a8aba2d84dbf71a13c0250467c2ff5989 Author: Michael Hu Date: Fri Jul 17 17:43:24 2020 -0700 Report ip protocol number for ICMP flow for IPFIX Currently protocol number is missing in v9/IPFIX for ICMP flow. commit dcedadb3cd302ddbbcc7fafea98de9b371c4ca69 Author: Michael Hu Date: Mon Jun 15 23:23:57 2020 -0700 Report interfaceName in normal data and template of v9 record Some popular netflow collectors like logstash and elasticsearch take if_name from common netflow records only. Add configure option --enable-ifname to report interfaceName in normal data and template of v9 record. Also fix if_name is empty string always since strlen(src_string) is 0 initially. Need to use sizeof() instead. commit f5dd97464623d0a58435cb74acefa8f7f78ed3d6 Author: Hitoshi Irino Date: Sat Jul 11 15:32:40 2020 +0900 Fix sequence in Netflow v9 header. commit 986358392821934f4629f3a306563f9206a13368 Merge: c8cc54a ab9faac Author: Hitoshi Irino Date: Thu May 28 07:21:29 2020 +0900 Merge pull request #28 from overhacked/vlan_mask_fix Correctly mask the 802.1q TCI bytes commit ab9faacae7b39230cecdb8e2b9edcea766c396fb Author: Ross Williams Date: Wed May 27 19:39:41 2020 +0000 Correctly mask the 802.1q TCI bytes The 802.1q tag is constructed as follows: 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | TPID | PCP | | VID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ^ | DEI \_______________________________/ TCI softflowd assumed that all 16 bits of the TCI represented the VLAN ID (VID). If the PCP or DEI were not zero, the reported VLAN ID would be incorrect (e.g. VLAN 4090 reported as 12282, not a valid VID). The solution here is to apply a 12-bit mask to the extracted TCI bytes. This discards the PCP and DEI value, but softflowd wasn't reporting those anyway. They could be recovered in the future if needed. For terms and definitions without reading the IEEE 802.1q standard, the Wikipedia article is excellent: https://en.wikipedia.org/wiki/IEEE_802.1Q commit c8cc54a30376a79960e8ad1264ace129f9e743af Merge: ebe6cc4 8f94ea2 Author: Hitoshi Irino Date: Mon May 25 06:38:43 2020 +0900 Merge pull request #27 from overhacked/patch-1 Fix ipfix.c `vlanId` & `postVlanId` network byte order commit 8f94ea27f27e17d508c6888681255dc0721e3c38 Author: Ross Williams Date: Sun May 24 08:08:03 2020 -0400 Fix ipfix.c vlanId network byte order IPFIX requires the vlanid to be in network byte order but it was being exported in host byte order. commit ebe6cc44d896334bb4b4f3e7f8f34f304fb0c56c Author: Hitoshi Irino Date: Sat May 9 20:44:15 2020 +0900 fix code to avoid gcc warnings about buffer overflow. commit 1c038e107469821da906192065139d5df48c5d74 Author: Hitoshi Irino Date: Sat May 9 19:52:45 2020 +0900 remove autogenerated file commit f690df8166341b543e86cd65d39841d08b9c3721 Author: Hitoshi Irino Date: Sat May 9 19:50:57 2020 +0900 update README commit ead968d2843019dfb9e686f1c114833be761b32c Author: Hitoshi Irino Date: Sun Apr 26 15:09:03 2020 +0900 Add flowDirection and flowEndReason in IPFIX and NetFlow v9 commit f1223c3e81dd0191f30edb05cee8cdcb0fc7162d Author: Hitoshi Irino Date: Sun Apr 26 11:11:26 2020 +0900 Add interfaceName in option tamplate of IPFIX and NetFlow v9 commit 1401758248ac7d31be6af68c293ff3b38d64b042 Merge: f510969 3e731d4 Author: Hitoshi Irino Date: Wed Apr 15 22:48:03 2020 +0900 Merge pull request #24 from tofurky/ntopng_ntohs_ports Convert ports to host byte order for ntopng commit 3e731d4d806250a37826a6cd283ba9ca2c6406bb Author: Matt Merhar Date: Sat Apr 11 21:40:50 2020 -0400 Convert ports to host byte order for ntopng ntopng expects the ports to be in host byte order and does no conversion of its own. Tested on both big (MIPS) and little (x86_64) endian devices with ntopng 4.0. Signed-off-by: Matt Merhar commit f5109693f76dd608c2ce40f51b039c68023dc6a7 Merge: 178c5ff 020dd2a Author: Hitoshi Irino Date: Fri Apr 10 21:33:30 2020 +0900 Merge pull request #23 from neheb/patch-1 fix compilation with musl commit 020dd2a325a15ba8bd995e5ea19ba23477b85e58 Author: Rosen Penev Date: Sat Mar 28 17:20:00 2020 -0700 fix compilation with musl __uid_t is a glibc type. commit 178c5ff522308a20986184306ae04ec1c276f33d Author: Hitoshi Irino Date: Sat Nov 30 00:18:05 2019 +0900 fix bug that displays wrong (dec instead of hex) MAC Address in ntopng commit db2fbb082fa9c7fbaacadfbf862c139099195202 Author: Hitoshi Irino Date: Sun Nov 17 17:38:24 2019 +0900 Add -S option for specifying send interface name. commit 479ca8fb32db4d74b543abc1437dd504502faf9d Merge: fe37a4e 07ae8b2 Author: Hitoshi Irino Date: Wed Sep 4 22:43:09 2019 +0900 Merge pull request #18 from bruceg/no-promisc Add support for non-promiscuous operation commit 07ae8b26890e8c4b0dbebd58438fe0e1aa990831 Author: Bruce Guenter Date: Mon Sep 2 10:30:16 2019 -0600 Add support for non-promiscuous operation Signed-off-by: Bruce Guenter commit fe37a4e64f12d1d571ef9c2b00dfd54debba4c16 Author: Hitoshi Irino Date: Sat Aug 24 09:21:07 2019 +0900 Update README about manpages commit 64d7e96f2aca9188cf847a49a1a7e1dd9dc91d07 Author: Hitoshi Irino Date: Sat Aug 24 08:52:31 2019 +0900 deleting pdfs from git commit 3681af73d21b3f34cb555de29b464b320e41745b Author: Hitoshi Irino Date: Sat Aug 24 07:14:56 2019 +0900 Changing installation directory from bin to sbin which is original installation directory. (Issue #16) commit 088cf827075dbd4ba6a73761d05d85d9d1d8ca66 Merge: 9cf249e f9a1e88 Author: Hitoshi Irino Date: Sat Aug 24 07:01:17 2019 +0900 Merge pull request #17 from neheb/master Replace deprecated bzero with memset commit f9a1e8829c6b442c1d8d8d0b78b7b672ede0cee2 Author: Rosen Penev Date: Fri Aug 23 12:39:36 2019 -0700 Replace deprecated bzero with memset bzero is optionally unavailable with uClibc-ng. commit 9cf249ebc18745a59418a62de124ff3975b59a01 Author: Hitoshi Irino Date: Fri Aug 16 22:42:16 2019 +0900 fix typo in NEWS commit f0a614318d1f9b39106da47b78659dfcb12568c8 Author: Hitoshi Irino Date: Fri Aug 16 20:31:36 2019 +0900 Minor fixes - fix typos. - update date in NEWS - symlink from LICENSE to COPYING - replace "0.9.9" to "1.0.0" commit 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 irino-softflowd-488a557/INSTALL000066400000000000000000000366261475610547700162140ustar00rootroot00000000000000Installation Instructions ************************* Copyright (C) 1994-1996, 1999-2002, 2004-2017, 2020-2021 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 timestamps 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. irino-softflowd-488a557/LICENSE000066400000000000000000000162371475610547700161640ustar00rootroot00000000000000Original 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. */ irino-softflowd-488a557/Makefile.am000066400000000000000000000011771475610547700172100ustar00rootroot00000000000000sbin_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 irino-softflowd-488a557/NEWS000066400000000000000000000035541475610547700156540ustar00rootroot00000000000000Fri Feb 11 2025 Softflowd 1.1.1 This release contains some new features and some bug fix by community. Details This release contains the following new features: Add -I option to specify boot time reinitialization. Add -g option for benchmark. Add -e option to specify exporter IP address Fri Sep 20 2022 Softflowd 1.1.0 This release contains some new features and some bug fix by community. Details This release contains the following new features: Add -x option which means number of MPLS shim label header for decoding and exporting MPLS packet. Add -B option for specifying Libpcap buffer size. Add exporting interface name with --enable-ifname configure option. Fri 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 flows irino-softflowd-488a557/README000066400000000000000000000066761475610547700160450ustar00rootroot00000000000000Welcome 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 softflowd wiki in following URLs: https://github.com/irino/softflowd/wiki/softflowd https://github.com/irino/softflowd/wiki/softflowctl PDF manpages can be built with: man -t ./softflowd.8 | ps2pdf - softflowd.pdf man -t ./softflowctl.8 | ps2pdf - softflowctl.pdf HTML manpages can be built with: groff -mandoc -Thtml softflowd.8 > softflowd.html groff -mandoc -Thtml softflowctl.8 > softflowctl.html Markdown manpages (which are published in wiki pages) can be built from above HtML manpages: pandoc -s softflowd.html -o softflowd.md pandoc -s softflowctl.html -o softflowctl.md 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: autoreconf -if # instead of "aclocal && autoheader && automake --add-missing && autoconf" ./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 irino-softflowd-488a557/TODO000066400000000000000000000104241475610547700156370ustar00rootroot00000000000000Things 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) irino-softflowd-488a557/closefrom.c000066400000000000000000000051621475610547700173070ustar00rootroot00000000000000/* * 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 */ irino-softflowd-488a557/collector.pl000077500000000000000000000151411475610547700174760ustar00rootroot00000000000000#!/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; irino-softflowd-488a557/common.h000066400000000000000000000136501475610547700166140ustar00rootroot00000000000000/* * 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.1.1" /* 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 */ #ifndef ETH_P_MPLS_UC #define ETH_P_MPLS_UC 0x8847 /* MPLS Unicast traffic */ #endif /* ETH_P_MPLS_UC */ #ifndef MPLS_LS_S_MASK #define MPLS_LS_S_MASK 0x00000100 #endif /* MPLS_LS_S_MASK */ #ifndef MPLS_LS_S_SHIFT #define MPLS_LS_S_SHIFT 8 #endif /* MPLS_LS_S_SHIFT */ #ifndef IFNAMSIZ /* defined in in linux */ #define IFNAMSIZ 16 #endif /* IFNAMSIZ */ #ifdef __APPLE__ #include #define htobe64(x) OSSwapHostToBigInt64(x) #endif /* __APPLE__ */ #endif /* _SFD_COMMON_H */ irino-softflowd-488a557/configure.ac000066400000000000000000000205201475610547700174330ustar00rootroot00000000000000# 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.1.0]) AC_CONFIG_SRCDIR([softflowd.c]) AM_INIT_AUTOMAKE AC_CONFIG_HEADERS([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, AS_HELP_STRING([--enable-legacy],[enable legacy NetFlow implementation (default NO)]), [legacy=yes],[legacy=no]) AC_ARG_ENABLE(pthread, AS_HELP_STRING([--enable-pthread],[enable pthread (default NO) (experimental, unstable)]), [pthread=yes],[pthread=no]) AC_ARG_ENABLE(ntopng, AS_HELP_STRING([--enable-ntopng],[enable flow sending to ntopng with zeromq (default NO)]), [ntopng=yes],[ntopng=no]) AC_ARG_ENABLE(ifname, AS_HELP_STRING([--enable-ifname],[enable flow reporting iface name in normal data of v9 and IPFIX (default NO)]), [ifname=yes],[ifname=no]) AC_ARG_ENABLE(flow-spray, AS_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, AS_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$ifname" = "xyes" ; then AC_DEFINE([ENABLE_IFNAME], 1, [enable reporting iface name]) fi 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_CANONICAL_HOST case "$host_os" in linux-gnu*) AC_DEFINE([LINUX], [], [Linux OS]) ;; esac AC_EXEEXT AC_CONFIG_FILES([Makefile]) AC_OUTPUT irino-softflowd-488a557/convtime.c000066400000000000000000000042511475610547700171400ustar00rootroot00000000000000/* * 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; } irino-softflowd-488a557/convtime.h000066400000000000000000000034501475610547700171450ustar00rootroot00000000000000/* * 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 */ irino-softflowd-488a557/daemon.c000066400000000000000000000047251475610547700165650ustar00rootroot00000000000000/* 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 */ irino-softflowd-488a557/freelist.c000066400000000000000000000115361475610547700171350ustar00rootroot00000000000000/* * 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)); memset(fl, 0, 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)); } irino-softflowd-488a557/freelist.h000066400000000000000000000037741475610547700171470ustar00rootroot00000000000000/* * 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 */ irino-softflowd-488a557/ipfix.c000066400000000000000000001130111475610547700164260ustar00rootroot00000000000000/* * 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}, {IPFIX_flowDirection, 1}, {IPFIX_flowEndReason, 1}, #ifdef ENABLE_IFNAME {IPFIX_interfaceName, IFNAMSIZ} #endif }; 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_protocolIdentifier, 1}, {IPFIX_ipVersion, 1}, {IPFIX_ipClassOfService, 1} }; const struct IPFIX_FIELD_SPECIFIER field_icmp6[] = { {IPFIX_icmpTypeCodeIPv6, 2}, {IPFIX_protocolIdentifier, 1}, {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}, {IPFIX_interfaceName, IFNAMSIZ}, {IPFIX_exporterIPv4Address, 4}, {IPFIX_exporterIPv6Address, 16}, {IPFIX_originalExporterIPv4Address, 4}, {IPFIX_originalExporterIPv6Address, 16} }; 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}, {IPFIX_interfaceName, IFNAMSIZ} }; /* 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; u_int8_t flowDirection, flowEndReason; #ifdef ENABLE_IFNAME char interfaceName[IFNAMSIZ]; #endif } __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 protocolIdentifier, 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; char interfaceName[IFNAMSIZ]; u_int32_t exporterIPv4Address; struct in6_addr exporterIPv6Address; u_int32_t originalExporterIPv4Address; struct in6_addr originalExporterIPv6Address; } __packed; struct NFLOW9_SOFTFLOWD_OPTION_DATA { struct IPFIX_SET_HEADER c; u_int32_t scope_ifidx; u_int32_t samplingInterval; u_int8_t samplingAlgorithm; char interfaceName[IFNAMSIZ]; } __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, u_int8_t max_num_label); // 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) return; ntp->second = tv.tv_sec + 0x83AA7E80; ntp->fraction = (uint32_t) ((double) (tv.tv_usec + 1) * (double) (1LL << 32) * 1.0e-6); } void conv_ntp_to_unix (struct ntp_time_t ntp, struct timeval *tv) { if (tv == NULL) return; tv->tv_sec = ntp.second - 0x83AA7E80; // the seconds from Jan 1, 1900 to Jan 1, 1970 tv->tv_usec = (uint32_t) ((double) ntp.fraction * 1.0e6 / (double) (1LL << 32)); } 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; memset (template, 0, 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 + param->max_num_label); // mpls 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) + param->max_num_label * sizeof (struct IPFIX_FIELD_SPECIFIER)); template->data_len = length + param->max_num_label * IPFIX_mplsLabelStackSection_SIZE; } 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); memset (&option_template, 0, 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); memset (&nf9opt_data, 0, 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; strncpy (nf9opt_data.interfaceName, option->interfaceName, strlen (option->interfaceName) < sizeof (nf9opt_data.interfaceName) ? strlen (option->interfaceName) : sizeof (nf9opt_data.interfaceName)); } static void ipfix_init_option (struct timeval *system_boot_time, struct OPTION *option) { u_int scope_index = 0, option_index = 0; memset (&option_template, 0, 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); memset (&option_data, 0, 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); strncpy (option_data.interfaceName, option->interfaceName, strlen (option->interfaceName) < sizeof (option_data.interfaceName) ? strlen (option->interfaceName) : sizeof (option_data.interfaceName)); if (option->exporterAddr != NULL) { struct addrinfo *rp; for (rp = option->exporterAddr; rp != NULL; rp = rp->ai_next) { if (rp->ai_family == AF_INET) { memcpy (&option_data.exporterIPv4Address, &((struct sockaddr_in *) rp->ai_addr)->sin_addr, sizeof (option_data.exporterIPv4Address)); memcpy (&option_data.originalExporterIPv4Address, rp->ai_addr, sizeof (option_data.originalExporterIPv4Address)); } else if (rp->ai_family == AF_INET6) { memcpy (&option_data.exporterIPv6Address, rp->ai_addr, sizeof (option_data.exporterIPv6Address)); memcpy (&option_data.originalExporterIPv6Address, &((struct sockaddr_in6 *) rp->ai_addr)->sin6_addr, sizeof (option_data.originalExporterIPv6Address)); } } } } 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; #ifdef ENABLE_IFNAME struct OPTION *option = ¶m->option; #endif /* ENABLE_IFNAME */ 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, k = 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); dc[i]->flowDirection = i; dc[i]->flowEndReason = flow->flowEndReason; #ifdef ENABLE_IFNAME strncpy (dc[i]->interfaceName, option->interfaceName, strlen (option->interfaceName) < sizeof (dc[i]->interfaceName) ? strlen (option->interfaceName) : sizeof (dc[i]->interfaceName)); #endif /* ENABLE_IFNAME */ 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]->protocolIdentifier = flow->protocol; 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 = htons (flow->vlanid[i]); dv[i]->postVlanId = htons (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); } } for (k = 0; k < param->max_num_label; k++) { memcpy (&packet[offset], &flow->mplsLabels[k], IPFIX_mplsLabelStackSection_SIZE); offset += IPFIX_mplsLabelStackSection_SIZE; } } *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, u_int8_t max_num_label) { int i = 0; int size = ntohs (template->h.c.length) - template->bi_count * sizeof (struct IPFIX_VENDOR_FIELD_SPECIFIER) - max_num_label * sizeof (struct IPFIX_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; } // mpls for (i = 0; i < max_num_label; i++) { struct IPFIX_FIELD_SPECIFIER *mpls_fs = (struct IPFIX_FIELD_SPECIFIER *) &packet[*offset]; mpls_fs->ie = htons (IPFIX_mplsTopLabelStackSection + i); mpls_fs->length = htons (IPFIX_mplsLabelStackSection_SIZE); *offset += sizeof (struct IPFIX_FIELD_SPECIFIER); } } /* * 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 = 0; 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; static u_int sequence = 1; 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;) { memset (packet, 0, 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, param->max_num_label); } 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) { if (version == 10) { ipfix->length = htons (offset); ipfix->sequence = htonl ((u_int32_t) (*records_sent & 0x00000000ffffffff)); } else if (version == 9) { nf9->flows = htons (++records); nf9->sequence = htonl (sequence++); } 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); } *records_sent += records; if (version == 10) { ipfix->length = htons (offset); ipfix->sequence = htonl ((u_int32_t) (*records_sent & 0x00000000ffffffff)); } else if (version == 9) { nf9->flows = htons (records); nf9->sequence = htonl (sequence++); } 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); } irino-softflowd-488a557/ipfix.h000066400000000000000000000124361475610547700164440ustar00rootroot00000000000000/* * 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_flowDirection 61 #define IPFIX_mplsTopLabelStackSection 70 /* ... */ #define IPFIX_interfaceName 82 /* ... */ #define IPFIX_exporterIPv4Address 130 #define IPFIX_exporterIPv6Address 131 /* ... */ #define IPFIX_flowEndReason 136 /* ... */ #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_originalExporterIPv4Address 403 #define IPFIX_originalExporterIPv6Address 404 /* ... */ // flow end reason for ipfix ie 136 #define IPFIX_flowEndReason_idleTimeout 0x01 #define IPFIX_flowEndReason_activeTimeout 0x02 #define IPFIX_flowEndReason_endOfFlow 0x03 #define IPFIX_flowEndReason_forceEnd 0x04 #define IPFIX_flowEndReason_lackOfResource 0x05 #define IPFIX_SOFTFLOWD_MAX_PACKET_SIZE 1428 #define IPFIX_mplsLabelStackSection_SIZE 3 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); void conv_ntp_to_unix (struct ntp_time_t ntp, struct timeval *tv); #endif /* _IPFIX_H */ irino-softflowd-488a557/log.c000066400000000000000000000033521475610547700160760ustar00rootroot00000000000000/* * 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); } irino-softflowd-488a557/log.h000066400000000000000000000027011475610547700161000ustar00rootroot00000000000000/* * 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 */ irino-softflowd-488a557/netflow1.c000066400000000000000000000143261475610547700170570ustar00rootroot00000000000000 /* * 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 */ irino-softflowd-488a557/netflow5.c000066400000000000000000000204701475610547700170600ustar00rootroot00000000000000/* * 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 */ irino-softflowd-488a557/netflow9.c000066400000000000000000000417201475610547700170650ustar00rootroot00000000000000/* * 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) { memset (&v4_template, 0, 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); memset (&v6_template, 0, 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) { memset (&option_template, 0, 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)); memset (&option_data, 0, 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; memset (d, 0, 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;) { memset (packet, 0, 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; } irino-softflowd-488a557/netflow9.h000066400000000000000000000041311475610547700170650ustar00rootroot00000000000000/* * 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 */ irino-softflowd-488a557/ntopng.c000066400000000000000000000165011475610547700166220ustar00rootroot00000000000000/* * 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 */ ntohs (flow->port[0]), ntohs (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\":\"%x:%x:%x:%x:%x:%x\"," /* ether mac src */ "\"57\":\"%x:%x:%x:%x:%x:%x\"", /* 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 static 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; } irino-softflowd-488a557/psamp.c000066400000000000000000000150661475610547700164420ustar00rootroot00000000000000/* * 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; memset (template_p, 0, 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); conv_ntp_to_unix (ntptime, &pkthdr.ts); //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; } irino-softflowd-488a557/psamp.h000066400000000000000000000037731475610547700164510ustar00rootroot00000000000000/* * 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 */ irino-softflowd-488a557/softflowctl.8000066400000000000000000000061331475610547700176100ustar00rootroot00000000000000.\" 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 irino-softflowd-488a557/softflowctl.c000066400000000000000000000062021475610547700176600ustar00rootroot00000000000000/* * 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); } irino-softflowd-488a557/softflowctl.md000066400000000000000000000033641475610547700200440ustar00rootroot00000000000000* * * SOFTFLOWCTL(8) BSD System Manager's Manual SOFTFLOWCTL(8) **NAME** **softflowctl** -- Remote control program for softflowd **SYNOPSIS** **softflowctl** [ **-h** ] [ **-c ** _ctl_sock_ ] _command_ **DESCRIPTION** **softflowctl** is a remote control program used to control a running softflowd(8) daemon. The command line options are as follows: **-c** _ctlsock_ Specify an alternate location for the remote control socket. Default is _/var/run/softflowd.ctl_ **-h** Display command line usage information. **COMMANDS** _ shutdown_ Ask softflowd(8) to gracefully exit. This is equivalent to sending it a SIGTERM or SIGINT. _exit_ Ask softflowd(8) to immediately exit. No flow expiry processing or data export is performed. _expire-all_ Immediately expire all tracked flows. _delete-all_ Immediately delete all tracked flows. No flow expiry processing or data export is performed. _statistics_ Return statistics collected by softflowd(8) on expired flows. _debug+_ Increase the debugging level of softflowd(8) _debug-_ Decrease the debugging level. _stop-gather_ Stops network data collection by softflowd(8). _start-gather_ Resumes network data collection. _dump-flows_ Return information on all tracked flows. _timeouts_ Print information on flow timeout parameters. _send-template_ Resend a NetFlow v.9 template record before the next flow export. Has no effect for other flow export versions. **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 **AUTHORS** Damien Miller Hitoshi Irino (current maintainer) **SEE ALSO** softflowd(8) BSD October 18, 2002 BSD * * * irino-softflowd-488a557/softflowd.8000066400000000000000000000345211475610547700172530ustar00rootroot00000000000000.\" 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 November 17, 2019 .Dt SOFTFLOWD 8 .Os .Sh NAME .Nm softflowd .Nd Traffic flow monitoring .Sh SYNOPSIS .Nm softflowd .Op Fl 6dDhbalN .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 Fl S Ar send_interface_name .Op Fl x Ar number_of_mpls_labels .Op Fl e Ar exporter_ip_address .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 (unless the .Fl N option is given) 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 N Do not put the interface into promiscuous mode. Note that the interface might be in promiscuous mode for some other reason. .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 Ar size_bytes Libpcap buffer size in bytes .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 x Ar number_of_mpls_labels specify number of mpls labels for export .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. .It Fl S Ar send_interface_name Specify send interface name. (This option works on Linux only because of use of SO_BINDTODEVICE for setsockopt.) .It Fl e Ar exporter_ip_address Specify exporter IPv4 or IPv6 address. .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 irino-softflowd-488a557/softflowd.c000066400000000000000000002411531475610547700173270ustar00rootroot00000000000000/* * 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 #ifdef LINUX #include #endif /* LINUX */ #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, i; 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); if (a->mplsLabelStackDepth != b->mplsLabelStackDepth) return (a->mplsLabelStackDepth > b->mplsLabelStackDepth ? 1 : -1); for (i = 0; i < a->mplsLabelStackDepth; i++) { if (a->mplsLabels[i] != b->mplsLabels[i]) return (a->mplsLabels[i] > b->mplsLabels[i] ? 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[4096]; 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.%03lld finish:%s.%03lld 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, (long long) ((flow->flow_start.tv_usec + 500) / 1000), fin_time, (long long) ((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[4096]; 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 void transport_to_flowrec (struct FLOW *flow, const u_int8_t *pkt, const size_t caplen, 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 */ if (caplen < sizeof (*tcp)) return; 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 */ if (caplen < sizeof (*udp)) return; 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; } /** * @fn ipv4_to_flowrec converts a IPv4 packet to a partial flow record (used for comparison) * @return return header size as posive value, return negative value when error occured */ static int ipv4_to_flowrec (struct FLOW *flow, const u_int8_t *pkt, size_t caplen, int *isfrag, int *isfirst, int *ndx, int track_lv) { const struct ip *ip = (const struct ip *) pkt; if (flow == NULL || ip == NULL || isfrag == NULL || isfirst == NULL || ndx == NULL || caplen < 20 || caplen < ip->ip_hl * 4 || ip->ip_v != 4) return (-1); /* Runt packet or Unsupported IP version */ /* Prepare to store flow in canonical format */ *ndx = memcmp (&ip->ip_src, &ip->ip_dst, sizeof (ip->ip_src)) > 0 ? 1 : 0; flow->addr[*ndx].v4 = ip->ip_src; flow->addr[*ndx ^ 1].v4 = ip->ip_dst; flow->protocol = track_lv >= TRACK_IP_PROTO ? ip->ip_p : 0; flow->tos[*ndx] = track_lv >= TRACK_FULL ? ip->ip_tos : 0; *isfrag = (ntohs (ip->ip_off) & (IP_OFFMASK | IP_MF)) ? 1 : 0; *isfirst = (ntohs (ip->ip_off) & IP_OFFMASK) == 0 ? 1 : 0; return (ip->ip_hl * 4); } /** * @fn ipv6_to_flowrec converts a IPv6 packet to a partial flow record (used for comparison) * @return return header size as posive value, return negative value when error occured */ static int ipv6_to_flowrec (struct FLOW *flow, const u_int8_t *pkt, size_t caplen, int *isfrag, int *isfirst, int *ndx, int track_lv) { const struct ip6_hdr *ip6 = (const struct ip6_hdr *) pkt; const struct ip6_ext *eh6; const struct ip6_frag *fh6; int nxt, size, remain; if (flow == NULL || ip6 == NULL || isfrag == NULL || isfirst == NULL || ndx == NULL || caplen < sizeof (*ip6) || (ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) return (-1); /* Runt packet or Unsupported IP version */ *ndx = memcmp (&ip6->ip6_src, &ip6->ip6_dst, sizeof (ip6->ip6_src)) > 0 ? 1 : 0; 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; *isfrag = 0; *isfirst = 1; nxt = ip6->ip6_nxt; size = sizeof (*ip6); /* Now loop through headers, looking for transport header */ for (;;) { remain = caplen - size; eh6 = (const struct ip6_ext *) pkt + size; if (nxt == IPPROTO_HOPOPTS || nxt == IPPROTO_ROUTING || nxt == IPPROTO_DSTOPTS) { int eh6size = remain < sizeof (*eh6) ? 0 : (eh6->ip6e_len + 1) << 3; if (remain < eh6size) return (size); /* Runt */ nxt = eh6->ip6e_nxt; size += eh6size; } else if (nxt == IPPROTO_FRAGMENT) { *isfrag = 1; fh6 = (const struct ip6_frag *) eh6; if (remain < sizeof (*fh6)) return (size); /* Runt */ if ((fh6->ip6f_offlg & IP6F_OFF_MASK) != 0) *isfirst = 0; nxt = fh6->ip6f_nxt; size += sizeof (*fh6); } else break; } flow->protocol = track_lv >= TRACK_IP_PROTO ? nxt : 0; flow->tos[*ndx] = track_lv >= TRACK_FULL ? (ntohl (ip6->ip6_flow) & ntohl (0x0ff00000)) >> 20 : 0; return size; } static void ether_to_flowrec (struct FLOW *flow, const struct ether_header *ether, int ndx) { if (ndx < 0 || ether == NULL) return; memcpy (flow->ethermac[ndx], ether->ether_shost, ETH_ALEN); memcpy (flow->ethermac[ndx ^ 1], ether->ether_dhost, ETH_ALEN); return; } 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; flow->flowEndReason = IPFIX_flowEndReason_lackOfResource; 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; flow->flowEndReason = IPFIX_flowEndReason_activeTimeout; 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; flow->flowEndReason = IPFIX_flowEndReason_endOfFlow; 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; flow->flowEndReason = IPFIX_flowEndReason_endOfFlow; 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; flow->flowEndReason = IPFIX_flowEndReason_idleTimeout; 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; flow->flowEndReason = IPFIX_flowEndReason_idleTimeout; 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; flow->flowEndReason = IPFIX_flowEndReason_idleTimeout; goto out; } /* Everything else */ flow->expiry->expires_at = flow->flow_last.tv_sec + ft->param.general_timeout; flow->expiry->reason = R_GENERAL; flow->flowEndReason = IPFIX_flowEndReason_idleTimeout; 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 CB_CTXT *cb_ctxt, const struct pcap_pkthdr *phdr, const u_char *frame, int datalink_size, int af, u_int16_t vlanid, u_int8_t num_label) { struct FLOW tmp, *flow; struct FLOWTRACK *ft = cb_ctxt->ft; const u_int32_t caplen = phdr->caplen - datalink_size; int frag = 0, first = 1, ndx = -1, i = 0, size = -1; const u_int8_t *pkt = frame + datalink_size + num_label * 4; /* Convert the IP packet to a flow identity */ memset (&tmp, 0, sizeof (tmp)); if (af == AF_INET) { size = ipv4_to_flowrec (&tmp, pkt, caplen, &frag, &first, &ndx, ft->param.track_level); } else if (af == AF_INET6) { size = ipv6_to_flowrec (&tmp, pkt, caplen, &frag, &first, &ndx, ft->param.track_level); } if ((af != AF_INET && af != AF_INET6) || ndx < 0 || size == -1) { /* bad packet */ ft->param.bad_packets++; return (PP_BAD_PACKET); } /* good packet */ tmp.af = af; tmp.octets[ndx] = phdr->len - datalink_size; tmp.packets[ndx] = 1; if (frag) ft->param.frag_packets++; if (first && ft->param.track_level >= TRACK_IP_PROTO_PORT) transport_to_flowrec (&tmp, pkt + size, caplen - size, tmp.protocol, ndx); if (ft->param.track_level >= TRACK_FULL_VLAN) tmp.vlanid[ndx] = vlanid; if (ft->param.track_level >= TRACK_FULL_VLAN_ETHER && cb_ctxt->linktype == DLT_EN10MB) ether_to_flowrec (&tmp, (const struct ether_header *) frame, ndx); tmp.mplsLabelStackDepth = num_label; for (i = 0; i < num_label && i < 10; i++) { tmp.mplsLabels[i] = *(((const u_int32_t *) (frame + datalink_size)) + i); } /* 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, &phdr->ts, 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; flow->flowEndReason = IPFIX_flowEndReason_idleTimeout; 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, &phdr->ts, 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); } if (ft->param.boot_time_reinit != 0) { if (now.tv_sec - ft->param.system_boot_time.tv_sec > ft->param.boot_time_reinit) { ft->param.system_boot_time = now; } } 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 %lld seconds\n", expiry->flow->flow_seq, (long long) 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, u_int16_t *vlanid, u_int8_t *num_label) { 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) { 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]; } /* Mask out the PCP and DEI values, leaving just the VID. */ *vlanid &= 0xFFF; 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 if (frametype == ETH_P_MPLS_UC && num_label != NULL) { u_int32_t shim = 0; u_int8_t ip_version = 0; do { shim = *((const u_int32_t *) (pkt + dl->skiplen + vlan_size) + *num_label); *num_label += 1; } while (!((ntohl (shim) & MPLS_LS_S_MASK) >> MPLS_LS_S_SHIFT)); ip_version = (pkt[dl->skiplen + vlan_size + *num_label * 4] & 0xf0) >> 4; if (ip_version == 4) *af = AF_INET; else if (ip_version == 6) *af = AF_INET6; else return (-1); } 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; u_int16_t vlanid = 0; u_int8_t num_label = 0; 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, &vlanid, &num_label); if (s < 0 || (!cb_ctxt->want_v6 && af == AF_INET6)) { cb_ctxt->ft->param.non_ip_packets++; cb_ctxt->ft->param.total_packets--; } else { if (process_packet (cb_ctxt, phdr, pkt, s, af, vlanid, num_label) == 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); } static 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); } return (arg); } #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; } #ifdef LINUX static void bind_device (int sock, char *ifname) { struct ifreq ifr; memset (&ifr, 0, sizeof (ifr)); strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); if (setsockopt (sock, SOL_SOCKET, SO_BINDTODEVICE, (void *) &ifr, sizeof (ifr)) < 0) { perror ("SO_BINDTODEVICE failed"); } } #endif /* LINUX */ static int connsock (struct sockaddr_storage *addr, socklen_t len, int hoplimit, int protocol, struct addrinfo *exporterAddr) { int s; unsigned int h6; unsigned char h4; struct sockaddr_in *in4 = (struct sockaddr_in *) addr; struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) addr; struct addrinfo *rp = NULL; 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 (exporterAddr != NULL) { for (rp = exporterAddr; rp != NULL; rp = rp->ai_next) { if (bind (s, rp->ai_addr, rp->ai_addrlen) == 0) { break; } } exporterAddr = rp; } 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, int promisc, int buffer_size_override) { char ebuf[PCAP_ERRBUF_SIZE]; struct bpf_program prog_c; u_int32_t bpf_mask, bpf_net; int res; /* Open pcap */ if (dev != NULL) { if (!snaplen) snaplen = need_v6 ? LIBPCAP_SNAPLEN_V6 : LIBPCAP_SNAPLEN_V4; if ((*pcap = pcap_create (dev, ebuf)) == NULL) { fprintf (stderr, "pcap_create: %s\n", ebuf); exit (1); } if ((res = pcap_set_snaplen (*pcap, snaplen)) != 0) { fprintf (stderr, "pcap_set_snaplen: %s\n", pcap_geterr (*pcap)); exit (1); } if ((res = pcap_set_promisc (*pcap, promisc)) != 0) { fprintf (stderr, "pcap_set_promisc: %s\n", pcap_geterr (*pcap)); exit (1); } if ((res = pcap_set_timeout (*pcap, 0)) != 0) { fprintf (stderr, "pcap_set_timeout: %s\n", pcap_geterr (*pcap)); exit (1); } if (buffer_size_override > 0) if ((res = pcap_set_buffer_size (*pcap, buffer_size_override)) != 0) { fprintf (stderr, "pcap_set_buffer_size: %s\n", pcap_geterr (*pcap)); exit (1); } if (pcap_lookupnet (dev, &bpf_net, &bpf_mask, ebuf) == -1) bpf_net = bpf_mask = 0; if ((res = pcap_activate (*pcap)) < 0) { fprintf (stderr, "pcap_activate: %s\n", pcap_geterr (*pcap)); exit (1); } } 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 bytes Libpcap buffer size in bytes\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 */ " -N Disable promiscuous mode\n" #ifdef LINUX " -S send_interface_name Specify send interface name\n" #endif /* LINUX */ " -x Specify number of MPLS labels\n" " -I Specify seconds for reinitialize boot time\n" " -g Gauge cpu clock for benchmark\n" " -e Specify Exporter IP (IPv4 or IPv6) address\n" " -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) { clock_t boottime = clock (); char *dev, *capfile, *bpf_prog; const char *pidfile_path, *ctlsock_path; extern char *optarg; extern int optind; int ch, dontfork_flag, linktype = 0, 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 pcap_override_buffer_size = 0; int protocol = IPPROTO_UDP; int version = 0; int rsock = 0, recvport = IPFIX_PORT, recvloop = 0; int user_ifindex_flag = 0; #ifdef LINUX struct ifreq ifr; char *send_ifname; #endif /* LINUX */ #ifdef ENABLE_PTHREAD use_thread = 0; pthread_t read_thread = 0; pthread_mutex_init (&read_mutex, NULL); pthread_cond_init (&read_cond, NULL); #endif /* ENABLE_PTHREAD */ int use_promisc = 1; long int boot_time_reinit_sec = 0; char *timeunit; int gauge_clock = 0; 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:B:baC:lR:MNS:x:I:ge:")) != -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; user_ifindex_flag = 1; } 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); strncpy (flowtrack.param.option.interfaceName, dev, strlen (dev) < sizeof (flowtrack.param.option.interfaceName) ? strlen (dev) : sizeof (flowtrack.param.option.interfaceName)); 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; strncpy (flowtrack.param.option.interfaceName, capfile, strlen (capfile) < sizeof (flowtrack.param.option.interfaceName) ? strlen (capfile) : sizeof (flowtrack.param.option.interfaceName)); 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 'B': pcap_override_buffer_size = atoi (optarg); 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; case 'N': use_promisc = 0; break; #ifdef LINUX case 'S': send_ifname = optarg; break; #endif /* LINUX */ case 'x': flowtrack.param.max_num_label = atoi (optarg); if (flowtrack.param.max_num_label < 0 || flowtrack.param.max_num_label > 10) { fprintf (stderr, "Invalid number of MPLS label\n\n"); usage (); exit (1); } break; case 'I': boot_time_reinit_sec = strtol (optarg, &timeunit, 10); if ((errno == ERANGE && (boot_time_reinit_sec == LONG_MAX || boot_time_reinit_sec == LONG_MIN)) || (errno != 0 && boot_time_reinit_sec == 0)) { perror ("strtol"); usage (); exit (EXIT_FAILURE); } if (timeunit == optarg) { fprintf (stderr, "No digits were found in boot_time_reinit\n"); usage (); exit (EXIT_FAILURE); } if (*timeunit == 'd' || *timeunit == 'D') { /* days */ if (boot_time_reinit_sec > BOOTTIME_MAX_DAY) { boot_time_reinit_sec = BOOTTIME_MAX_DAY; } boot_time_reinit_sec *= (24 * 60 * 60); /* convert to seconds */ } else if (*timeunit == 'h' || *timeunit == 'H') { /* hours */ if (boot_time_reinit_sec > BOOTTIME_MAX_HOUR) { boot_time_reinit_sec = BOOTTIME_MAX_HOUR; } boot_time_reinit_sec *= (60 * 60); /* convert to seconds */ } else if (*timeunit == 'm' || *timeunit == 'M') { /* minutes */ if (boot_time_reinit_sec > BOOTTIME_MAX_MIN) { boot_time_reinit_sec = BOOTTIME_MAX_MIN; } boot_time_reinit_sec *= 60; /* convert to seconds */ } else { if (boot_time_reinit_sec > BOOTTIME_MAX_SEC) { /* seconds */ boot_time_reinit_sec = BOOTTIME_MAX_SEC; } } if (verbose_flag) { fprintf (stderr, "boot_time_reinit is %ld seconds.\n", boot_time_reinit_sec); } break; case 'g': gauge_clock = 1; break; case 'e': if (optarg != NULL) { struct addrinfo hints; hints.ai_family = AF_UNSPEC; hints.ai_socktype = protocol == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; hints.ai_flags = 0; hints.ai_protocol = protocol; if (getaddrinfo (optarg, NULL, &hints, &flowtrack.param.option.exporterAddr) != 0) { perror ("getaddrinfo"); break; } } 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, use_promisc, pcap_override_buffer_size); 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, flowtrack.param.option.exporterAddr); #ifdef LINUX if (dest->sock > 0 && send_ifname != NULL) { bind_device (dest->sock, send_ifname); } if (dev != NULL && user_ifindex_flag == 0) { strncpy (ifr.ifr_name, dev, IFNAMSIZ - 1); if (ioctl (pcap_get_selectable_fd (pcap), SIOCGIFINDEX, &ifr) < 0) { perror ("ioctl SIOCGIFINDEX"); } if_index = ifr.ifr_ifindex; if (verbose_flag) fprintf (stderr, "Using %s (idx: %d as result of SIOCGIFINDEX)\n", dev, if_index); } #endif /* LINUX */ } } /* 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 from %s to [%s]:%s", flowtrack.param.option.interfaceName, dest->hostname, dest->servname); } } flowtrack.param.option.meteringProcessId = getpid (); flowtrack.param.boot_time_reinit = boot_time_reinit_sec; /* 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); if (gauge_clock) logit (LOG_INFO, "cpu clocks: %ld\n", clock () - boottime); return (r == 0 ? 0 : 1); } irino-softflowd-488a557/softflowd.h000066400000000000000000000250061475610547700173310ustar00rootroot00000000000000/* * 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 */ enum { TRACK_IP_ONLY, /* src/dst tuple */ TRACK_IP_PROTO, /* src/dst/proto 3-tuple */ TRACK_IP_PROTO_PORT, /* src/dst/addr/port/proto 5-tuple */ TRACK_FULL, /* src/dst/addr/port/proto/tos 6-tuple */ TRACK_FULL_VLAN, /* src/dst/addr/port/proto/tos/vlanid 7-tuple */ TRACK_FULL_VLAN_ETHER /* src/dst/addr/port/proto/tos/vlanid/src-mac/dst-mac 9-tuple */ }; #define SOFTFLOWD_MAX_DESTINATIONS 16 #define BOOTTIME_MAX_DAY 49 #define BOOTTIME_MAX_HOUR 1193 #define BOOTTIME_MAX_MIN 71582 #define BOOTTIME_MAX_SEC 4294944 /* * This structure contains optional information carried by Option Data * Record. */ struct OPTION { uint32_t sample; pid_t meteringProcessId; char interfaceName[IFNAMSIZ]; struct addrinfo *exporterAddr; }; 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; u_int8_t max_num_label; struct timeval last_packet_time; u_int32_t boot_time_reinit; /* seconds */ }; /* * 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 */ u_int8_t flowEndReason; u_int32_t mplsLabelStackDepth; u_int32_t mplsLabels[10]; }; /* * 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 */ irino-softflowd-488a557/softflowd.html000066400000000000000000000457601475610547700200570ustar00rootroot00000000000000

SOFTFLOWD(8) System Manager’s Manual SOFTFLOWD(8)

NAME

softflowd — Traffic flow monitoring

SYNOPSIS

softflowd [-6dDhbalN] [-L hoplimit] [-T track_level] [-c ctl_sock] [

-i  [
if_ndx
:]interface ] [-m max_flows] [-n host:port] [-p pidfile] [-r pcap_file] [-t timeout_name=seconds] [-v netflow_version] [-P transport_protocol] [-A time_format] [-s sampling_rate] [-C capture_length] [-R receive_port] [-S send_interface_name] [-x number_of_mpls_labels] [-e exporter_ip_address] [bpf_expression]

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(tm) traffic account system. softflowd supports data export using versions 1, 5, 9 or 10 (a.k.a. IPFIX) of the NetFlow protocol. softflowd 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.

Network traffic may be obtained by listening on a promiscuous network interface (unless the -N option is given) or by reading stored pcap(3) files, such as those written by tcpdump(8). Traffic may be filtered with an optional bpf(4) program, specified on the command-line as bpf_expression. softflowd 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).

softflowd 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 max_flows (default: 8192). In this last case, flows are expired oldest-first.

Upon expiry, the flow information is accumulated into statistics which may be viewed using softflowctl(8). If the -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 host and port. The host may represent a unicast host or a multicast group.

The command-line options are as follows:

-n host:port

Specify the host and 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 services(5) or a numeric port. Comma can be used for specifying multiple destinations.

-N

Do not put the interface into promiscuous mode. Note that the interface might be in promiscuous mode for some other reason.

-i
[
if_ndx
:]interface

Specify a network interface on which to listen for traffic. Either the -i or the -r options must be specified.

-r pcap_file

Specify that softflowd should read from a pcap(3) packet capture file (such as one created with the -w option of tcpdump(8)) file rather than a network interface. softflowd processes the whole capture file and only expires flows when max_flows is exceeded. In this mode, softflowd will not fork and will automatically print summary statistics before exiting.

-p pidfile

Specify an alternate location to store the process ID when in daemon mode. Default is /var/run/softflowd.pid

-c ctlsock

Specify an alternate location for the remote control socket in daemon mode. Default is /var/run/softflowd.ctl

-m 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.

-t timeout_name=time

Set the timeout names timeout_name to time. Refer to the “Timeouts” section for the valid timeout names and their meanings. The time parameter may be specified using one of the formats explained in the “Time Formats” section below.

-d

Specify that softflowd should not fork and daemonise itself.

-6

Force softflowd to track IPv6 flows even if the NetFlow export protocol does not support reporting them. This is useful for debugging and statistics gathering only.

-D

Places softflowd in a debugging mode. This implies the -d and -6 flags and turns on additional debugging output.

-B size_bytes

Libpcap buffer size in bytes

-b

Bidirectional mode in IPFIX (-b work with -v 10)

-a

Adjusting time for reading pcap file (-a work with -r)

-l

Load balancing mode for multiple destinations which are specified with -n

-x number_of_mpls_labels

specify number of mpls labels for export

-h

Display command-line usage information.

-L hoplimit

Set the IPv4 TTL or the IPv6 hop limit to hoplimit. softflowd 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).

-T track_level

Specify which flow elements softflowd should be used to define a flow. track_level may be one of: “ether” (track everything including source and destination addresses, source and destination port, source and destination ethernet address, vlanid and protocol), “vlan” (track source and destination addresses, source and destination port, vlanid and protocol), “full” (track source and destination addresses, source and destination port and protocol in the flow, the default), “proto” (track source and destination addresses and protocol), or “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 softflowd will place on the system at the cost of some detail being lost.

-v netflow_version

Specify which version of the NetFlow(tm) protocol softflowd should use for export of the flow data. Supported versions are 1, 5, 9, 10(IPFIX), and psamp. Default is version 5.

-P transport_protocol

Specify transport layer protocol for exporting packets. Supported transport layer protocols are udp, tcp, and sctp.

-A time_format

Specify absolute time format form exporting records. Supported time formats are sec, milli, micro, and nano.

-s sampling_rate

Specify periodical sampling rate (denominator).

-C capture_length

Specify length for packet capture (snaplen).

-R receive_port

Specify port number for PSAMP receive mode.

-S send_interface_name

Specify send interface name. (This option works on Linux only because of use of SO_BINDTODEVICE for setsockopt.)

-e exporter_ip_address

Specify exporter IPv4 or IPv6 address.

Any further command-line arguments will be concatenated together and applied as a bpf(4) packet filter. This filter will cause softflowd to ignore the specified traffic.

Timeouts

softflowd 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 -t option) and their meanings are:

general

This is the general timeout applied to all traffic unless overridden by one of the other timeouts.

tcp

This is the general TCP timeout, applied to open TCP connections.

tcp.rst

This timeout is applied to a TCP connection when a RST packet has been sent by one or both endpoints.

tcp.fin

This timeout is applied to a TCP connection when a FIN packet has been sent by both endpoints.

udp

This is the general UDP timeout, applied to all UDP connections.

maxlife

This is the maximum lifetime that a flow may exist for. All flows are forcibly expired when they pass maxlife seconds. To disable this feature, specify a maxlife of 0.

expint

Specify the interval between expiry checks. Increase this to group more flows into a NetFlow packet. To disable this feature, specify a expint of 0.

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. softflowctl(8) may be used to print information on the average lifetimes of flows and the reasons for their expiry.

Time Formats

softflowd command-line arguments that specify time may be expressed using a sequence of the form: time[qualifier], where time is a positive integer value and qualifier is one of the following:

<none>

seconds

s | S

seconds

m | M

minutes

h | H

hours

d | D

days

w | W

weeks

Each member of the sequence is added together to calculate the total time value.

Time format examples:

600

600 seconds (10 minutes)

10m

10 minutes

1h30m

1 hour 30 minutes (90 minutes)

Run-time Control

A daemonised softflowd instance may be controlled using the 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 SIGTERM or SIGINT will cause softflowd to exit, after expiring all flows (and thus sending flow export packets if -n was specified on the command-line). If you do not want to export flows upon shutdown, clear them first with softflowctl(8) or use softflowctl(8) ’s “exit” command.

EXAMPLES
softflowd -i fxp0

This command-line will cause softflowd to listen on interface fxp0 and to run in statistics gathering mode only (i.e. no NetFlow data export).

softflowd -i fxp0 -n 10.1.0.2:4432

This command-line will cause softflowd 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.

softflowd -i fxp0 -n 10.1.0.2:4432,10.1.0.3:4432

This command-line will cause softflowd 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.

softflowd -i fxp0 -l -n 10.1.0.2:4432,10.1.0.3:4432

This command-line will cause softflowd 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.

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 softflowd will track to 65536 and increases the timeout for UDP flows to 90 seconds.

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.

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 softflowd on a single machine.

FILES
/var/run/softflowd.pid

This file stores the process ID when softflowd is in daemon mode. This location may be overridden using the -p command-line option.

/var/run/softflowd.ctl

This is the remote control socket. softflowd listens on this socket for commands from softflowctl(8). This location may be overridden using the -c command-line option.

BUGS

Currently softflowd 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

AUTHORS

Damien Miller <djm@mindrot.org>
Hitoshi Irino (current maintainer) <irino@sfc.wide.ad.jp>

SEE ALSO

softflowctl(8), tcpdump(8), pcap(3), bpf(4)

http://www.ietf.org/rfc/rfc3954.txt
http://www.cisco.com/en/US/products/sw/netmgtsw/ps1964/products_implementation_design_guide09186a00800d6a11.html
http://www.ietf.org/rfc/rfc5101.txt
http://www.ietf.org/rfc/rfc5103.txt Debian November 17, 2019 SOFTFLOWD(8)


irino-softflowd-488a557/softflowd.init000066400000000000000000000021201475610547700200350ustar00rootroot00000000000000#!/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 $? irino-softflowd-488a557/softflowd.md000066400000000000000000000320461475610547700175040ustar00rootroot00000000000000------------------------------------------------------------------------ *SOFTFLOWD*(8) System Manager's Manual *SOFTFLOWD*(8) **NAME** softflowd --- Traffic flow monitoring **SYNOPSIS** **softflowd** \[**-6dDhbalN**\] \[**-L ***hoplimit*\] \[**-T ***track_level*\] \[**-c ***ctl_sock*\] \[ **-i ** \[ *\ if_ndx*:\]*interface* \] \[**-m ***max_flows*\] \[**-n ***host:port*\] \[**-p ***pidfile*\] \[**-r ***pcap_file*\] \[**-t ***timeout_name=seconds*\] \[**-v ***netflow_version*\] \[**-P ***transport_protocol*\] \[**-A ***time_format*\] \[**-s ***sampling_rate*\] \[**-C ***capture_length*\] \[**-R ***receive_port*\] \[**-S ***send_interface_name*\] \[**-x ***number_of_mpls_labels*\] \[**-e ***exporter_ip_address*\] \[bpf_expression\] **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(tm) traffic account system. **softflowd** supports data export using versions 1, 5, 9 or 10 (a.k.a. IPFIX) of the NetFlow protocol. **softflowd** 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. Network traffic may be obtained by listening on a promiscuous network interface (unless the **-N** option is given) or by reading stored *pcap*(3) files, such as those written by *tcpdump*(8). Traffic may be filtered with an optional *bpf*(4) program, specified on the command-line as *bpf_expression*. **softflowd** 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). **softflowd** 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 *max_flows* (default: 8192). In this last case, flows are expired oldest-first. Upon expiry, the flow information is accumulated into statistics which may be viewed using *softflowctl*(8). If the **-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 *host* and *port*. The host may represent a unicast host or a multicast group. The command-line options are as follows: **-n** *host:port* Specify the *host* and *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 *services*(5) or a numeric port. Comma can be used for specifying multiple destinations. **-N** Do not put the interface into promiscuous mode. Note that the interface might be in promiscuous mode for some other reason. **-i**\ \[ *\ if_ndx*:\]*interface* Specify a network interface on which to listen for traffic. Either the **-i** or the **-r** options must be specified. **-r** *pcap_file* Specify that **softflowd** should read from a *pcap*(3) packet capture file (such as one created with the **-w** option of *tcpdump*(8)) file rather than a network interface. **softflowd** processes the whole capture file and only expires flows when *max_flows* is exceeded. In this mode, **softflowd** will not fork and will automatically print summary statistics before exiting. **-p** *pidfile* Specify an alternate location to store the process ID when in daemon mode. Default is */var/run/softflowd.pid* **-c** *ctlsock* Specify an alternate location for the remote control socket in daemon mode. Default is */var/run/softflowd.ctl* **-m** *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. **-t** *timeout_name=time* Set the timeout names *timeout_name* to *time*. Refer to the "Timeouts" section for the valid timeout names and their meanings. The *time* parameter may be specified using one of the formats explained in the "Time Formats" section below. **-d** Specify that **softflowd** should not fork and daemonise itself. **-6** Force **softflowd** to track IPv6 flows even if the NetFlow export protocol does not support reporting them. This is useful for debugging and statistics gathering only. **-D** Places **softflowd** in a debugging mode. This implies the **-d** and **-6** flags and turns on additional debugging output. **-B** *size_bytes* Libpcap buffer size in bytes **-b** Bidirectional mode in IPFIX (-b work with -v 10) **-a** Adjusting time for reading pcap file (-a work with -r) **-l** Load balancing mode for multiple destinations which are specified with -n **-x** *number_of_mpls_labels* specify number of mpls labels for export **-h** Display command-line usage information. **-L** *hoplimit* Set the IPv4 TTL or the IPv6 hop limit to *hoplimit*. **softflowd** 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). **-T** *track_level* Specify which flow elements **softflowd** should be used to define a flow. *track_level* may be one of: "ether" (track everything including source and destination addresses, source and destination port, source and destination ethernet address, vlanid and protocol), "vlan" (track source and destination addresses, source and destination port, vlanid and protocol), "full" (track source and destination addresses, source and destination port and protocol in the flow, the default), "proto" (track source and destination addresses and protocol), or "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 **softflowd** will place on the system at the cost of some detail being lost. **-v** *netflow_version* Specify which version of the NetFlow(tm) protocol **softflowd** should use for export of the flow data. Supported versions are 1, 5, 9, 10(IPFIX), and psamp. Default is version 5. **-P** *transport_protocol* Specify transport layer protocol for exporting packets. Supported transport layer protocols are udp, tcp, and sctp. **-A** *time_format* Specify absolute time format form exporting records. Supported time formats are sec, milli, micro, and nano. **-s** *sampling_rate* Specify periodical sampling rate (denominator). **-C** *capture_length* Specify length for packet capture (snaplen). **-R** *receive_port* Specify port number for PSAMP receive mode. **-S** *send_interface_name* Specify send interface name. (This option works on Linux only because of use of SO_BINDTODEVICE for setsockopt.) **-e** *exporter_ip_address* Specify exporter IPv4 or IPv6 address. Any further command-line arguments will be concatenated together and applied as a *bpf*(4) packet filter. This filter will cause **softflowd** to ignore the specified traffic. **Timeouts** **softflowd** 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 **-t** option) and their meanings are: *general* This is the general timeout applied to all traffic unless overridden by one of the other timeouts. *tcp* This is the general TCP timeout, applied to open TCP connections. *tcp.rst* This timeout is applied to a TCP connection when a RST packet has been sent by one or both endpoints. *tcp.fin* This timeout is applied to a TCP connection when a FIN packet has been sent by both endpoints. *udp* This is the general UDP timeout, applied to all UDP connections. *maxlife* This is the maximum lifetime that a flow may exist for. All flows are forcibly expired when they pass *maxlife* seconds. To disable this feature, specify a *maxlife* of 0. *expint* Specify the interval between expiry checks. Increase this to group more flows into a NetFlow packet. To disable this feature, specify a *expint* of 0. 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. *softflowctl*(8) may be used to print information on the average lifetimes of flows and the reasons for their expiry. **Time Formats** **softflowd** command-line arguments that specify time may be expressed using a sequence of the form: *time*\[*qualifier*\], where *time* is a positive integer value and *qualifier* is one of the following: **\** seconds **s** \| **S** seconds **m** \| **M** minutes **h** \| **H** hours **d** \| **D** days **w** \| **W** weeks Each member of the sequence is added together to calculate the total time value. Time format examples: 600 600 seconds (10 minutes) 10m 10 minutes 1h30m 1 hour 30 minutes (90 minutes) **Run-time Control** A daemonised **softflowd** instance may be controlled using the *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 SIGTERM or SIGINT will cause **softflowd** to exit, after expiring all flows (and thus sending flow export packets if **-n** was specified on the command-line). If you do not want to export flows upon shutdown, clear them first with *softflowctl*(8) or use *softflowctl*(8) 's "exit" command. **EXAMPLES**\ softflowd -i fxp0 This command-line will cause **softflowd** to listen on interface fxp0 and to run in statistics gathering mode only (i.e. no NetFlow data export). softflowd -i fxp0 -n 10.1.0.2:4432 This command-line will cause **softflowd** 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. softflowd -i fxp0 -n 10.1.0.2:4432,10.1.0.3:4432 This command-line will cause **softflowd** 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. softflowd -i fxp0 -l -n 10.1.0.2:4432,10.1.0.3:4432 This command-line will cause **softflowd** 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. 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 **softflowd** will track to 65536 and increases the timeout for UDP flows to 90 seconds. 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. 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 **softflowd** on a single machine. **FILES** *\ /var/run/softflowd.pid* This file stores the process ID when **softflowd** is in daemon mode. This location may be overridden using the **-p** command-line option. */var/run/softflowd.ctl* This is the remote control socket. **softflowd** listens on this socket for commands from *softflowctl*(8). This location may be overridden using the **-c** command-line option. **BUGS** Currently **softflowd** 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 **AUTHORS** Damien Miller \\ Hitoshi Irino (current maintainer) \ **SEE ALSO** *softflowctl*(8), *tcpdump*(8), *pcap*(3), *bpf*(4) http://www.ietf.org/rfc/rfc3954.txt\ http://www.cisco.com/en/US/products/sw/netmgtsw/ps1964/products_implementation_design_guide09186a00800d6a11.html\ http://www.ietf.org/rfc/rfc5101.txt\ http://www.ietf.org/rfc/rfc5103.txt Debian November 17, 2019 *SOFTFLOWD*(8) ------------------------------------------------------------------------ irino-softflowd-488a557/softflowd.spec000066400000000000000000000030011475610547700200230ustar00rootroot00000000000000# 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.1.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 irino-softflowd-488a557/softflowd.sysconfig000066400000000000000000000004471475610547700211100ustar00rootroot00000000000000# 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" irino-softflowd-488a557/strlcat.c000066400000000000000000000037141475610547700167730ustar00rootroot00000000000000/* 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 */ irino-softflowd-488a557/strlcpy.c000066400000000000000000000035341475610547700170170ustar00rootroot00000000000000/* 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 */ irino-softflowd-488a557/sys-tree.h000066400000000000000000000542021475610547700170750ustar00rootroot00000000000000/* $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_ */ irino-softflowd-488a557/treetype.h000066400000000000000000000056251475610547700171700ustar00rootroot00000000000000/* * 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