Initial git release 1.6.13
This commit is contained in:
parent
752de78504
commit
758237b450
32
BSD-license.txt
Normal file
32
BSD-license.txt
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
The nfdump project is distributed under the BSD license:
|
||||
|
||||
Copyright (c) 2014, Peter Haag
|
||||
Copyright (c) 2009, Peter Haag
|
||||
Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
|
438
ChangeLog
Executable file
438
ChangeLog
Executable file
@ -0,0 +1,438 @@
|
||||
2014-11-16
|
||||
- Fix v1 extension size bug
|
||||
- Add htonll check for autoconf
|
||||
- Fix AddExtensionMap compare bug
|
||||
- Fix ipfix templare withdraw problems - free all maps correctly
|
||||
- Add minilzo 2.08 - fixes CVE-2014-4607
|
||||
- Cleanup some stat code. more needs to be done ..
|
||||
- Cleanup man pages for -O -n
|
||||
- Remove SunPro test in configure - no longer supported anyway
|
||||
|
||||
2014-06-15 v1.6.12p1
|
||||
- Add pblock compare functions
|
||||
- Update extended filter: Allow modification left/right values
|
||||
|
||||
2014-02-16 v1.6.12
|
||||
- Add NAT pool port allocation
|
||||
- Modify/fix NAT vrf tags. Add egress vrf ID
|
||||
- Modify common record due to exporter exhaustion. new common record
|
||||
type 10 adds 4 extra bytes. Reads v1 common record transparently
|
||||
- Fix sflow potential crash
|
||||
|
||||
2013-11-13 v1.6.11
|
||||
- Add ASA/NSEL 9.x protcol changes
|
||||
- Make it llvm compilable
|
||||
|
||||
2013-08-12 v1.6.10p1
|
||||
- Fix -t +/- n timeslot option
|
||||
- Fix bug in nfanon - stat record update.
|
||||
- Fix bug in netflow v5 mudule: extension map size wrong.
|
||||
- Fix bug nfexport: In some cases could result in wrong flow counter.
|
||||
- Fix nftrack - could coredump in some cases.
|
||||
|
||||
2013-05-16 v1.6.10
|
||||
- Fix SPARC compile/optimise bug
|
||||
- Add output packet/bytes counter to global stat - importatnt for NSEL flows ASA > 8.5
|
||||
- Add NSEL filter options xnet
|
||||
- Modify extension descriptor code for nfdump1.7. Still use 1.6 extension map layout for compatibility
|
||||
- Add prototype for nfpcapd - pcap -> nfdump collector. Converts traffoc directly to nfdump files.
|
||||
- Fix bug in ipfix module: uninitialised variable
|
||||
- Cleanup syslog/LogError calls
|
||||
- Fix minor non critical bugs and compile issues
|
||||
|
||||
2013-03-02 v1.6.9
|
||||
- Fix some bugs in beta 1.6.9 NSEL code
|
||||
- Fix bug statistics update with aggreagted flow records
|
||||
- Fix sflow bug sfcapd stores wrong (ghost) dump by past samples in same sflow datagram
|
||||
|
||||
2012-12-31
|
||||
- Add time received in csv output
|
||||
- ICMP should handled better now - somewhat
|
||||
- Implement ASA NSEL records
|
||||
- Add definitions in nffile and nx for ASA NSEL extensions
|
||||
|
||||
2012-11-09 v1.6.8p1
|
||||
- Add dynamic source directory tree for multiple exporters
|
||||
- Fix exporter bug: 'too many exporters' with large time windows
|
||||
- Fix uninitialised exporter sysid in default sampler record - v9
|
||||
- Fix v9/ipfix cache initialisation with no templates > 1 in same packet
|
||||
|
||||
2012-10-26 v1.6.8
|
||||
- Add ip list option for 'next ip' in filter syntax
|
||||
- Accept v9 sampler_id in 2bytes
|
||||
- Fix IPFIX mac address bug - did not get collected
|
||||
- Add IPFIX packet/octet TotalCount fields 85/86
|
||||
- Add received timestamp to sflow collector
|
||||
- Fix long flow duration calculation - 32bit overflow
|
||||
- Fix v9 sampling ID: allow 2 byte ID
|
||||
- Add IPFIX options as rfc5101 section-6.2
|
||||
- Add exporter records for sflow collector
|
||||
- Fix bug for MAC address printing %idmc and %odmc.
|
||||
- Add received time stamp extension
|
||||
- Add recursive format parser. Allows to extend predefined formats.
|
||||
- Change flow record sorting to heapsort. remove limit 1000
|
||||
- Merge -m option to -O tstart. -m now depricated.
|
||||
- Add -O tend. Print order according to tend of flows ascending
|
||||
- Apply -O print order for printing flow cache. Applies to -A
|
||||
|
||||
2012-07-31 v1.6.7-tc-1
|
||||
- Special version for TC
|
||||
- Print exporter and sampling records with nfdump -E
|
||||
- Added exporter and sampling records to file.
|
||||
|
||||
2012-07-30 v1.6.7
|
||||
- Prepare for file catalog in current file format.
|
||||
- Fix bug in ReadBlock when reading flow from stdin pipe
|
||||
- Add new more flexible translation engine for v9
|
||||
- Add nprobe client/server delay fields
|
||||
- Prepare for NSEL merging
|
||||
- Fix memory corruption with double -A flags
|
||||
- Fix bug in nfreader with compat15 mode files
|
||||
|
||||
2012-03-12 v1.6.6
|
||||
- Minor IPFIX bug.
|
||||
- IPFIX implement template withdraw
|
||||
- For IPFIX, check packet sequence per template and observation domain
|
||||
- Fix time window, when no flows collected or no flows matched
|
||||
while processing
|
||||
- Fixed typos
|
||||
- Fix seg fault bug - test for EMPTY_LIST was missing at several places.
|
||||
|
||||
2012-02-19 v1.6.6b1
|
||||
- Fix bps/pps. make it uint64_t, as bps/pps > 4Gb/s overflows.
|
||||
- In record raw print mode: decode ICMP instead of src/dst ports
|
||||
- sflow use announced exporter IP instead of sending IP for router ID
|
||||
- sflow: Ignore extra fill bytes. Do not complain.
|
||||
- sflow: fix packet length issue.
|
||||
- Add IPFIX protokoll support
|
||||
|
||||
2011-12-31 v1.6.5
|
||||
- Fix 64bit bug when using byte/packet limits
|
||||
- for v5 and sampling use 64bit counters to prevent overflow for large sampled flows.
|
||||
- Fixed Ident printig bug
|
||||
|
||||
2011-07-11 v1.6.4
|
||||
- some code restructuring - prepare for IPFIX module
|
||||
- Add netflow v1 module. Some routers still use that
|
||||
- Add %sn, %dn output tags for src/dst networks
|
||||
- Fix buffer length check in v5.
|
||||
- Fix export bug: include last flow cache bucket, when exporting
|
||||
- number in all filter expressions accept hex values
|
||||
- fix an sflow colletor bug. Missing extension maps in rotated files
|
||||
- implement extended statistics. Currently ports and bpp distribution
|
||||
vectors can be collected automatically be nfcapd. Still experimental
|
||||
|
||||
2011-02-26 v1.6.3p1
|
||||
- Fix timebug fix :(, make it a compile time option
|
||||
- fix v7 sequence errors
|
||||
|
||||
2011-02-15
|
||||
- Zero out unused fields after aggregation
|
||||
|
||||
2011-02-05
|
||||
- Fix SysUptime 32bit overflow in v5 header
|
||||
- Add fix for strange first/last swap reported by some users.
|
||||
|
||||
2011-01-09 v1.6.3
|
||||
- Fix extension size bug
|
||||
- Move IP anonymisation to separate binary nfanon
|
||||
- Fix initialise bug of -o fmt: and not available fields
|
||||
|
||||
2010-09-09 v1.6.2
|
||||
- released
|
||||
- fixes some sflow bugs in sfcapd
|
||||
|
||||
2010-04-28 v1.6.1p0
|
||||
- Update flow tools converter to build with Google-Code version 0.68.5
|
||||
- Fix sflow bugs
|
||||
|
||||
2010-03-05 v1.6.1
|
||||
- Fix bug in man page for -t
|
||||
- Test sampler infos before using them ( nfcapd startup )
|
||||
- Add sampling tags #34, #35 used by JunOS
|
||||
- nfexpire: Fix empty .nfsat, when setting limits on an empty directory
|
||||
- Fix coredump for -B -m (-w) combination
|
||||
- Optimise some extension map code
|
||||
|
||||
2009-12-28 stable v1.6
|
||||
- Few bug fixes in release candidates rc1, rc2 and rc3
|
||||
|
||||
2009-11-16 snapshot-1.6b-20091116
|
||||
- Update sflow collector with new tags
|
||||
- Add router IP extension
|
||||
- Add router ID (engine type/ID) extension
|
||||
|
||||
2009-09-30 snapshot-1.6b-20090930
|
||||
- snapshot bugfix release
|
||||
|
||||
2009-11-0801 snapshot-1.6b-20090806
|
||||
- Add srcmask and dstmask aggregation
|
||||
- Add csv output mode. -o csv
|
||||
- Fix some bugs of previous beta
|
||||
- Add bidirectional aggregation of flows ( -b, -B )
|
||||
- Add possibility to save aggregated flows into file ( -w )
|
||||
Note: This results in a behaviour change for -w in combination
|
||||
with aggragation )
|
||||
- Extend -N ( do not scale numbers ) to all text output not just summary
|
||||
- Make extension handling more robust for some moody IOSes.
|
||||
- Remove header lines of -s stat, when using -q ( quiet )
|
||||
Note: This results in a behaviour change for -N
|
||||
- Remove -S option from nfdump ( legacy 1.4 compatibility )
|
||||
- Make use of log (syslog) functions for nfprofile.
|
||||
- Move log functions to util.c
|
||||
|
||||
2009-06-19 snapshot-1.6b-20090717
|
||||
- Flow-tools converter updated - supports more common elements.
|
||||
- Sflow collector updated. Supports more common elements.
|
||||
- Add sampling to nfdump. Sampling is automatically recognised
|
||||
in v5 undocumented header fields and in v9 option templates.
|
||||
see nfcapd.1(1)
|
||||
- Add @include option for filter to include more filter files.
|
||||
- Add flexible aggregation comparable to Flexible Netflow (FNF)
|
||||
- All new tags can be selected in -o fmt:... see nfdump(1)
|
||||
- topN stat for all new tags is implemented
|
||||
- Integrate developer code to read from pcap files into stable
|
||||
- Update filter syntax for new tags
|
||||
- Added more v9 tags for netflow v9.
|
||||
The detailed tags are listed in nfcapd(1)
|
||||
Adding new tags also extended the binary file format with
|
||||
data block format 2, which is extension based. File format
|
||||
for version <= 1.5.* ( Data block format 1 ) is read
|
||||
transparently. Data block 2 are skipped by nfdump 1.5.7.
|
||||
32bit but AS and interface numbers are supported.
|
||||
- Add flexible storage option for nfcapd. To save disk space, the
|
||||
data extensions to be stored in the data file are user selectable.
|
||||
- Added option for multiple netflow stream to same port.
|
||||
-n <Ident,IP,base_directory>
|
||||
Example: -n router1,192.168.100.1,/var/nfdump/router1
|
||||
So multiple -n options may be given at the command line
|
||||
Old style syntax still works for compatibility, ( -I .. -l ... )
|
||||
but then only one source is supported.
|
||||
- Move to automake for building nfdump
|
||||
- Switch scaling factor ( k, M, G ) from 1024 to 1000.
|
||||
- Make nfdump fully 64bit compliant. ( 8bit data alignments and access )
|
||||
|
||||
2009-04-17 stable 1.5.8
|
||||
- Fix daylight summer time bug, when guessing sub dirs. file access ( -M, -r )
|
||||
- Bug fixes for 64bits CPUs
|
||||
|
||||
2008-02-22 stable-1,5.7
|
||||
- Add icmp type/code decoding
|
||||
- Add proper icmp v9 decoding
|
||||
- Fix memory leaks in -e auto expire mode in nfcapd.
|
||||
- Fix somee potential dead locks with file locking, when expiring
|
||||
- Fix multicast bug in nfreplay
|
||||
- Add hostname lookup for IP addresses in filter.
|
||||
|
||||
2007-10-15 stable-1.5.6
|
||||
- Fix odd CISCO behaviour for ICMP type/code in src port.
|
||||
- Add fast LZO1X-1 compression option (-z) for output file.
|
||||
- Add lists for port in syntax -> port in [ 135 137 445]
|
||||
- Add lists for AS syntax -> as in [ 1024 1025 ]
|
||||
- Bug fix in filter for syntax 'src as and dst as'
|
||||
|
||||
2007-08-24 stable-1.5.5
|
||||
- Fix nfprofile bug, nfprofile crashes when last opts line is not valid for
|
||||
some reason.
|
||||
- Fix potential hand for nfexpire, on empty flow directories.
|
||||
|
||||
2007-08-08 snapshot-20070808
|
||||
- Idents may contain '-' in name.
|
||||
- Fixed install bugs in Makefile.in and configure.in
|
||||
- Installs now cleanly on Solaris
|
||||
- Handle 4byte interface numbers in v9. Quick fix: 4bytes reduced to 2bytes.
|
||||
- Fix aggregation bug in statistics.
|
||||
- ftok(3) C library call replaced by more reliable own implementation.
|
||||
Did result in error messages like "Another collector is already running"
|
||||
- Fix minor bugs iin file range selction -R.
|
||||
- Add recursive behaviour for -R <directory>
|
||||
- New option -i can canche Ident descriptor in data files.
|
||||
|
||||
2007-03-12 snapshot-20070312
|
||||
- Bug fix release of 20070306
|
||||
|
||||
2007-03-06 snapshot-20070306
|
||||
- Fix bug in flist.c. Resulted in a coredump when using sub dirs and -R . ( all files )
|
||||
- Fix minor bug in nfcapd.c.
|
||||
- Extend nfprofile for alerting system of nfsen - special version of profiles
|
||||
- Extend nfprofile for shadow profiles.
|
||||
|
||||
2007-08-10 snapshot-20070110
|
||||
- Fix some compiler warnings, when compiled on a 64bit LINUX
|
||||
- Fixes an sflow bug: IP address was printed in wrong direction. ( lower bits first )
|
||||
- Add new IP addr taging option -T for easy parsing for nfsen lookups
|
||||
- Add new IP list for massive address filtering:
|
||||
syntax: ip in [ 12345 23456 3456 ....]
|
||||
- Change nfprofile for channel based profiling. This breaks with old nfprofile
|
||||
functionality.
|
||||
- Remove space from ICMP type/code when followed by an IP address
|
||||
|
||||
2006-07-21 snapshot-20060809
|
||||
- Make nfexpire ready for profile expiration
|
||||
- Fix bug in nfrpofile. sub dir hierarchy not handled correctly.
|
||||
|
||||
2006-07-21 snapshot-20060721
|
||||
- Add -N option for plain number output in summary line
|
||||
|
||||
2006-07-21 snapshot-20060721
|
||||
- Do recursive file selection when a directory is given by -R
|
||||
|
||||
2006-06-14 snapshot-20060621
|
||||
- Add srcas/dstas/proto aggregation.
|
||||
Note: This changes the default aggregation behaviour, but gives more flexibility
|
||||
- Add tos to element statistics list
|
||||
|
||||
2006-06-14 snapshot-20060614
|
||||
- Add additional stat line at the end of output
|
||||
- Add new binary nfexpire. Manages data expiry on time and/or size based limits
|
||||
Includes new bookkeeping records in nfcapd. See nfexpire(1)
|
||||
- Add ICMP type/code decoding in flow listing instead of dst port
|
||||
- Add packet repeater in nfcapd/sfcapd. In addition, incoming UDP packets can
|
||||
be directly forwarded to another IP address/Port. See new option -R
|
||||
- Add sub directory hierarchies: Files can be stored into various sub dir levels
|
||||
based on different time formats. see new option -S
|
||||
- Some minor bug fixes.
|
||||
- Code cleanup in nfcapd. better daemonize code and communication with launcher.
|
||||
|
||||
2006-04-xx v.1.5.1
|
||||
Fix bug in nfdump.c: Writing anonymized flows to file did not work corretly
|
||||
stdin input format now compatible with file format, therefore
|
||||
'nfdump < file' works again as it did in nfdump 1.4.
|
||||
Fix bug in nfcapd.c: Error handling not correct when receiving a non
|
||||
recognized netflow packet. Resulted in an endless loop
|
||||
2006-03-27 snapshot 1.5-20060327
|
||||
Make all element statistics -s transport layer protocol
|
||||
independant by default. Add :p to stat name ( e.g. srcip:p ) to
|
||||
enable transport layer dependant statistics on request.
|
||||
2006-03-20 snapshot 1.5-20060320
|
||||
Fix bug in filter engine: 'not flags xyz' produces wrong results
|
||||
when more than a single flag is specified.
|
||||
Minor man page fixes.
|
||||
|
||||
2006-03-06 v1.5
|
||||
Fix bug nfcapd. Laucher signaled too early. File not yet properly
|
||||
closed.
|
||||
2006-02-14 v1.5-beta-5
|
||||
Add srcas, dstas, input and output interfaces in aggregated
|
||||
output.
|
||||
Fix IPv6 bug in filter: accept 1234:: address.
|
||||
rename nfcapd.curent tmp file to nfcapd.curren.<pid>. Poorly
|
||||
configured nfcapd processes may mess up themselves otherwise.
|
||||
2006-02-02 v1.5-beta-4
|
||||
Fix netflow v5 dPkts <-> dOctets collector bug.
|
||||
Update pipe format to include more information
|
||||
Allow AS number 0 in filter syntax.
|
||||
Add some more boundary checking - netflow exporters aren't bug free either - sigh ..
|
||||
2006-01-11 v1.5-beta-3
|
||||
Fix isnumber incompatibility in grammar.y
|
||||
Add 'if' statistics
|
||||
2006-01-10 v1.5-beta-2
|
||||
nf_common.c Fix bug in format parser.
|
||||
Extended 'proto <protocol>' syntax to support all protocols
|
||||
Change time format in summary line to ISO format
|
||||
2005-12-20 v1.5-beta-1
|
||||
*.* A lot of internal changes, not mentioned here. :(
|
||||
|
||||
nfdump Add subnet aggregation for option -A
|
||||
A new syntax e.g. srcip4/24, dstip6/64 is supported for subnet wise aggregation.
|
||||
example: traffic of a whole subnet -A srcip4/24 -s srcip/bytes
|
||||
|
||||
nfdump Add more stat element option. -s <stat> now supports:
|
||||
srcip, dstip, ip, srcport, dstport, port, srcas, dstas, as, inif, outif, proto
|
||||
|
||||
nfdump Add -z. Suppress writing flows to data files. Only stat information is written.
|
||||
nfprofile Used only be nfsen for upcoming shadow profiles. If you don't understand this
|
||||
simply ignore it.
|
||||
|
||||
nfdump Add -q option to suppress header as well as stat information at the bottom
|
||||
nfprofile for easier post processing with external programms.
|
||||
|
||||
nf_common.c Output format processsing rewritting for more flexibility. Besides standard
|
||||
nfdump.c output formats line, long extended etc., user defined output formats are now
|
||||
possible and can even be compiled into nfdump for easy access. See -o fmt:<format>
|
||||
and nfdump.c around line 100.
|
||||
|
||||
*.* Integrate netflow v9 into nfdump. Only a subset of v9 is stored into
|
||||
the data files, basically everything needed for nfdump to work as it did before.
|
||||
This also includes IPv6 support for any nfdump options. CryptoPAN extended
|
||||
to work with IPv6. IPv6 condensed output format for better readability.
|
||||
Output formats available in long and condensed mode: e.g. line -> line6
|
||||
extended -> extended6
|
||||
|
||||
*.* Replace binary data file format. Old format not flexible enough for
|
||||
upcoming netflow v9/sflow data. *.stat files are gone. The same
|
||||
information is now available under nfdump -I
|
||||
New format about 5% larger in size, but faster for reading and writing.
|
||||
speed gain eaten up by more complex processing - sigh ..
|
||||
compat14 mode enables transparent reading of old style format.
|
||||
nffile.[ch] now handles all data file stuff.
|
||||
|
||||
nfreplay Multicast enabled:
|
||||
Add -j <join group>. Joins the specified multicast group ( v4 or v6 )
|
||||
sending flows to this group.
|
||||
|
||||
nfreplay IPv6 enabled:
|
||||
Add option -4 and -6 to force a specific protocol, otherwise
|
||||
protocol is automatically selected according the hostname to send flows to.
|
||||
Add -K key, to send data anonymized, using CryptoPAn
|
||||
|
||||
nfcapd Multicast enabled:
|
||||
Add -j <join group>. Joins the specified multicast group ( v4 or v6 )
|
||||
for listening.
|
||||
|
||||
nfcapd IPv6 enabled:
|
||||
Add option -4 and -6 for IPv4 and IPv6. By default, listen on IPv4.
|
||||
Option -b <host/IP> to bind for a specific host/IP address automatically
|
||||
selects appropriate protocol.
|
||||
|
||||
nfnet.c All functions to setup network sockets for listening/sending are
|
||||
put into this file.
|
||||
|
||||
2005-08-22 v1.4
|
||||
- nfreplay: Bug fix sending flows.
|
||||
- nfdump: Add CryptoPAn code to anonymize IP addresses. New option -K
|
||||
- nfdump: Change time format in output to ISO 8601 compatible: e.g. 1981-04-05 14:30:30.100
|
||||
- nfdump: Add scaling factor k,m,g to number in filter syntax: e.g. bytes > 1m
|
||||
- nfdump: Create new output format extended with additional fields pps, bps and bpp
|
||||
- nfdump: Rename output format extended to raw
|
||||
- nfdump: More than one single flow element statistic ( -s ) is now possible
|
||||
- nfdump: Add user defined sort order in flow element statistic
|
||||
- nfdump: Flow element statistic can be ordered by more than one order in the same run
|
||||
- nfdump: Add pps, bps and bpp fields in flow element statistics
|
||||
- nfdump: Add more symbolic protocols ESP, AH, GRP and RVSP to filter syntax
|
||||
- nfdump: Add duration, pps, bps and bpp to filter syntax
|
||||
- nfdump: Make nfdump miliseconds aware. Older versions skipped msecs.
|
||||
Binary nfdump file format changed due to this.
|
||||
output formats changed, due to this.
|
||||
- nfdump: Add interface in/out if <num> syntax to filter
|
||||
- nfcapd: Add flow_sequence check. Reports missing flows now.
|
||||
- nfcapd: Report statistics to syslog LOG_INFO when data file is rotated.
|
||||
- ft2nfdump: Add ft2nfdump to read netflow data from flow-tools
|
||||
|
||||
2005-04-21 v1.3
|
||||
- Add option -A for more flexible aggregation.
|
||||
- Correct spelling errors :(
|
||||
|
||||
2005-03-04 v1.2.1
|
||||
Bug fix release
|
||||
- nfcapd: launcher subprocess may hang on Linux 2.6.x kernels.
|
||||
Cleaned up interrupt handling.
|
||||
- nfcapd: fix include order of socket.h and types.h in order to
|
||||
compile cleanly under FreeBSD 4.x
|
||||
- nfcapd: clean up syslog logging.
|
||||
- nfdump: Multiple sources ( -M ) and sort flows ( -m ) with
|
||||
-c <limit> did not list the correct flows.
|
||||
- nfprofile: Profiling with multiple sources may produce incorrect
|
||||
profiles.
|
||||
|
||||
2004-12-20 v1.2
|
||||
- nfcapd handles transparent v5 and v7 flows. v7 gets converted into v5
|
||||
- nfcapd can execute any command at the end of interval. New option -x
|
||||
- nfdump Extended filter syntax for flags, to, bytes and packets
|
||||
- Rearrange output formats in nfdump: new switch -o, remove switch -E
|
||||
output formats: 'line', 'long', 'extended' and 'pipe'
|
||||
- More flexible statistic handling in nfdump: cleanup ugly -s -s -s
|
||||
syntax. Replaced by -s <stat> option. New statistics for Port and AS.
|
||||
|
||||
2004-09-20 v 1.1
|
||||
First public Version.
|
133
CreateSubHierarchy.pl
Executable file
133
CreateSubHierarchy.pl
Executable file
@ -0,0 +1,133 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
#
|
||||
# Sample script to clean old data.
|
||||
# Run this script each hour to cleanup old files to make room for
|
||||
# new data. When max_size_spool is reached the oldest files are
|
||||
# deleted down to high_water.
|
||||
#
|
||||
# Copyright (c) 2004, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * 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.
|
||||
# * Neither the name of SWITCH 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
#
|
||||
# $Author: peter $
|
||||
#
|
||||
# $Id: CreateSubHierarchy.pl 77 2006-06-14 14:52:25Z peter $
|
||||
#
|
||||
# $LastChangedRevision: 77 $
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
use POSIX qw(strftime);
|
||||
use Time::Local;
|
||||
use Getopt::Std;
|
||||
|
||||
our(
|
||||
$opt_l, # Data directory
|
||||
$opt_S, # Sub hierarchy format. Correspondes to -S to nfcapd. See nfcapd(1)
|
||||
);
|
||||
|
||||
getopts('l:S:');
|
||||
|
||||
my $subdir_format;
|
||||
|
||||
my @subdir_formats = (
|
||||
"",
|
||||
"%Y/%m/%d",
|
||||
"%Y/%m/%d/%H",
|
||||
"%Y/%W/%u",
|
||||
"%Y/%W/%u/%H",
|
||||
"%Y/%j",
|
||||
"%Y/%j/%H",
|
||||
"%F",
|
||||
"%F/%H"
|
||||
);
|
||||
|
||||
sub usage {
|
||||
print "$0 [options]\n",
|
||||
" -l datadir Data directory\n",
|
||||
" -S <num> Sub hierarchy format. Correspondes to -S to nfcapd. See nfcapd(1)\n",
|
||||
"\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
sub ISO2UNIX {
|
||||
my $isotime = shift;
|
||||
|
||||
$isotime =~ s/\-//g; # allow '-' to structur time string
|
||||
|
||||
# 2004 02 13 12 45 /
|
||||
my $sec = 0;
|
||||
my ( $year, $mon, $mday, $hour, $min ) = $isotime =~ /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})/;
|
||||
$mon--;
|
||||
|
||||
# round down to nearest 5 min slot
|
||||
my $diff = $min % 5;
|
||||
if ( $diff ) {
|
||||
$min -= $diff;
|
||||
}
|
||||
|
||||
my $unixtime = Time::Local::timelocal($sec,$min,$hour,$mday,$mon,$year);
|
||||
|
||||
return $unixtime;
|
||||
|
||||
} # End of ISO2UNIX
|
||||
|
||||
if ( !defined $opt_l || !defined $opt_S ) {
|
||||
usage();
|
||||
}
|
||||
|
||||
my $data_dir = $opt_l;
|
||||
if ( !defined $subdir_formats[$opt_S] ) {
|
||||
die "Unknown format number $opt_S";
|
||||
}
|
||||
$subdir_format = $subdir_formats[$opt_S];
|
||||
|
||||
opendir DIR, "$data_dir" || die "Can't open current directory: $!\n";
|
||||
$| = 1;
|
||||
print "Reorganizing data files ... ";
|
||||
while ( my $entry = readdir DIR ) {
|
||||
next if $entry =~ /^\./;
|
||||
next unless -f "$data_dir/$entry";
|
||||
next unless $entry =~ /nfcapd\.(\d{12})$/;
|
||||
my $date = $1;
|
||||
my $unix_time = ISO2UNIX($date);
|
||||
my $sub_path = strftime $subdir_format, localtime($unix_time);
|
||||
if ( !-d "$data_dir/$sub_path" ) {
|
||||
print "Need to create '$data_dir/$sub_path'\n";
|
||||
my @dirlist = split '\/', $sub_path;
|
||||
my $all_dirs = undef;
|
||||
foreach my $dir ( @dirlist ) {
|
||||
$all_dirs = defined $all_dirs ? "$all_dirs/$dir" : $dir;
|
||||
if ( !-d "$data_dir/$all_dirs" ) {
|
||||
mkdir "$data_dir/$all_dirs" || die "Can't create subdir '$data_dir/$all_dirs'\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
rename "$data_dir/$entry", "$data_dir/$sub_path/$entry" || die "Can't move file: $!\n";
|
||||
|
||||
}
|
||||
print "done.\n";
|
370
INSTALL
Normal file
370
INSTALL
Normal file
@ -0,0 +1,370 @@
|
||||
Installation Instructions
|
||||
*************************
|
||||
|
||||
Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. This file is offered as-is,
|
||||
without warranty of any kind.
|
||||
|
||||
Basic Installation
|
||||
==================
|
||||
|
||||
Briefly, the shell command `./configure && make && make install'
|
||||
should configure, build, and install this package. The following
|
||||
more-detailed instructions are generic; see the `README' file for
|
||||
instructions specific to this package. Some packages provide this
|
||||
`INSTALL' file but do not implement all of the features documented
|
||||
below. The lack of an optional feature in a given package is not
|
||||
necessarily a bug. More recommendations for GNU packages can be found
|
||||
in *note Makefile Conventions: (standards)Makefile Conventions.
|
||||
|
||||
The `configure' shell script attempts to guess correct values for
|
||||
various system-dependent variables used during compilation. It uses
|
||||
those values to create a `Makefile' in each directory of the package.
|
||||
It may also create one or more `.h' files containing system-dependent
|
||||
definitions. Finally, it creates a shell script `config.status' that
|
||||
you can run in the future to recreate the current configuration, and a
|
||||
file `config.log' containing compiler output (useful mainly for
|
||||
debugging `configure').
|
||||
|
||||
It can also use an optional file (typically called `config.cache'
|
||||
and enabled with `--cache-file=config.cache' or simply `-C') that saves
|
||||
the results of its tests to speed up reconfiguring. Caching is
|
||||
disabled by default to prevent problems with accidental use of stale
|
||||
cache files.
|
||||
|
||||
If you need to do unusual things to compile the package, please try
|
||||
to figure out how `configure' could check whether to do them, and mail
|
||||
diffs or instructions to the address given in the `README' so they can
|
||||
be considered for the next release. If you are using the cache, and at
|
||||
some point `config.cache' contains results you don't want to keep, you
|
||||
may remove or edit it.
|
||||
|
||||
The file `configure.ac' (or `configure.in') is used to create
|
||||
`configure' by a program called `autoconf'. You need `configure.ac' if
|
||||
you want to change it or regenerate `configure' using a newer version
|
||||
of `autoconf'.
|
||||
|
||||
The simplest way to compile this package is:
|
||||
|
||||
1. `cd' to the directory containing the package's source code and type
|
||||
`./configure' to configure the package for your system.
|
||||
|
||||
Running `configure' might take a while. While running, it prints
|
||||
some messages telling which features it is checking for.
|
||||
|
||||
2. Type `make' to compile the package.
|
||||
|
||||
3. Optionally, type `make check' to run any self-tests that come with
|
||||
the package, generally using the just-built uninstalled binaries.
|
||||
|
||||
4. Type `make install' to install the programs and any data files and
|
||||
documentation. When installing into a prefix owned by root, it is
|
||||
recommended that the package be configured and built as a regular
|
||||
user, and only the `make install' phase executed with root
|
||||
privileges.
|
||||
|
||||
5. Optionally, type `make installcheck' to repeat any self-tests, but
|
||||
this time using the binaries in their final installed location.
|
||||
This target does not install anything. Running this target as a
|
||||
regular user, particularly if the prior `make install' required
|
||||
root privileges, verifies that the installation completed
|
||||
correctly.
|
||||
|
||||
6. You can remove the program binaries and object files from the
|
||||
source code directory by typing `make clean'. To also remove the
|
||||
files that `configure' created (so you can compile the package for
|
||||
a different kind of computer), type `make distclean'. There is
|
||||
also a `make maintainer-clean' target, but that is intended mainly
|
||||
for the package's developers. If you use it, you may have to get
|
||||
all sorts of other programs in order to regenerate files that came
|
||||
with the distribution.
|
||||
|
||||
7. Often, you can also type `make uninstall' to remove the installed
|
||||
files again. In practice, not all packages have tested that
|
||||
uninstallation works correctly, even though it is required by the
|
||||
GNU Coding Standards.
|
||||
|
||||
8. Some packages, particularly those that use Automake, provide `make
|
||||
distcheck', which can by used by developers to test that all other
|
||||
targets like `make install' and `make uninstall' work correctly.
|
||||
This target is generally not run by end users.
|
||||
|
||||
Compilers and Options
|
||||
=====================
|
||||
|
||||
Some systems require unusual options for compilation or linking that
|
||||
the `configure' script does not know about. Run `./configure --help'
|
||||
for details on some of the pertinent environment variables.
|
||||
|
||||
You can give `configure' initial values for configuration parameters
|
||||
by setting variables in the command line or in the environment. Here
|
||||
is an example:
|
||||
|
||||
./configure CC=c99 CFLAGS=-g LIBS=-lposix
|
||||
|
||||
*Note Defining Variables::, for more details.
|
||||
|
||||
Compiling For Multiple Architectures
|
||||
====================================
|
||||
|
||||
You can compile the package for more than one kind of computer at the
|
||||
same time, by placing the object files for each architecture in their
|
||||
own directory. To do this, you can use GNU `make'. `cd' to the
|
||||
directory where you want the object files and executables to go and run
|
||||
the `configure' script. `configure' automatically checks for the
|
||||
source code in the directory that `configure' is in and in `..'. This
|
||||
is known as a "VPATH" build.
|
||||
|
||||
With a non-GNU `make', it is safer to compile the package for one
|
||||
architecture at a time in the source code directory. After you have
|
||||
installed the package for one architecture, use `make distclean' before
|
||||
reconfiguring for another architecture.
|
||||
|
||||
On MacOS X 10.5 and later systems, you can create libraries and
|
||||
executables that work on multiple system types--known as "fat" or
|
||||
"universal" binaries--by specifying multiple `-arch' options to the
|
||||
compiler but only a single `-arch' option to the preprocessor. Like
|
||||
this:
|
||||
|
||||
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
|
||||
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
|
||||
CPP="gcc -E" CXXCPP="g++ -E"
|
||||
|
||||
This is not guaranteed to produce working output in all cases, you
|
||||
may have to build one architecture at a time and combine the results
|
||||
using the `lipo' tool if you have problems.
|
||||
|
||||
Installation Names
|
||||
==================
|
||||
|
||||
By default, `make install' installs the package's commands under
|
||||
`/usr/local/bin', include files under `/usr/local/include', etc. You
|
||||
can specify an installation prefix other than `/usr/local' by giving
|
||||
`configure' the option `--prefix=PREFIX', where PREFIX must be an
|
||||
absolute file name.
|
||||
|
||||
You can specify separate installation prefixes for
|
||||
architecture-specific files and architecture-independent files. If you
|
||||
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
|
||||
PREFIX as the prefix for installing programs and libraries.
|
||||
Documentation and other data files still use the regular prefix.
|
||||
|
||||
In addition, if you use an unusual directory layout you can give
|
||||
options like `--bindir=DIR' to specify different values for particular
|
||||
kinds of files. Run `configure --help' for a list of the directories
|
||||
you can set and what kinds of files go in them. In general, the
|
||||
default for these options is expressed in terms of `${prefix}', so that
|
||||
specifying just `--prefix' will affect all of the other directory
|
||||
specifications that were not explicitly provided.
|
||||
|
||||
The most portable way to affect installation locations is to pass the
|
||||
correct locations to `configure'; however, many packages provide one or
|
||||
both of the following shortcuts of passing variable assignments to the
|
||||
`make install' command line to change installation locations without
|
||||
having to reconfigure or recompile.
|
||||
|
||||
The first method involves providing an override variable for each
|
||||
affected directory. For example, `make install
|
||||
prefix=/alternate/directory' will choose an alternate location for all
|
||||
directory configuration variables that were expressed in terms of
|
||||
`${prefix}'. Any directories that were specified during `configure',
|
||||
but not in terms of `${prefix}', must each be overridden at install
|
||||
time for the entire installation to be relocated. The approach of
|
||||
makefile variable overrides for each directory variable is required by
|
||||
the GNU Coding Standards, and ideally causes no recompilation.
|
||||
However, some platforms have known limitations with the semantics of
|
||||
shared libraries that end up requiring recompilation when using this
|
||||
method, particularly noticeable in packages that use GNU Libtool.
|
||||
|
||||
The second method involves providing the `DESTDIR' variable. For
|
||||
example, `make install DESTDIR=/alternate/directory' will prepend
|
||||
`/alternate/directory' before all installation names. The approach of
|
||||
`DESTDIR' overrides is not required by the GNU Coding Standards, and
|
||||
does not work on platforms that have drive letters. On the other hand,
|
||||
it does better at avoiding recompilation issues, and works well even
|
||||
when some directory options were not specified in terms of `${prefix}'
|
||||
at `configure' time.
|
||||
|
||||
Optional Features
|
||||
=================
|
||||
|
||||
If the package supports it, you can cause programs to be installed
|
||||
with an extra prefix or suffix on their names by giving `configure' the
|
||||
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
||||
|
||||
Some packages pay attention to `--enable-FEATURE' options to
|
||||
`configure', where FEATURE indicates an optional part of the package.
|
||||
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
|
||||
is something like `gnu-as' or `x' (for the X Window System). The
|
||||
`README' should mention any `--enable-' and `--with-' options that the
|
||||
package recognizes.
|
||||
|
||||
For packages that use the X Window System, `configure' can usually
|
||||
find the X include and library files automatically, but if it doesn't,
|
||||
you can use the `configure' options `--x-includes=DIR' and
|
||||
`--x-libraries=DIR' to specify their locations.
|
||||
|
||||
Some packages offer the ability to configure how verbose the
|
||||
execution of `make' will be. For these packages, running `./configure
|
||||
--enable-silent-rules' sets the default to minimal output, which can be
|
||||
overridden with `make V=1'; while running `./configure
|
||||
--disable-silent-rules' sets the default to verbose, which can be
|
||||
overridden with `make V=0'.
|
||||
|
||||
Particular systems
|
||||
==================
|
||||
|
||||
On HP-UX, the default C compiler is not ANSI C compatible. If GNU
|
||||
CC is not installed, it is recommended to use the following options in
|
||||
order to use an ANSI C compiler:
|
||||
|
||||
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
|
||||
|
||||
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
|
||||
|
||||
HP-UX `make' updates targets which have the same time stamps as
|
||||
their prerequisites, which makes it generally unusable when shipped
|
||||
generated files such as `configure' are involved. Use GNU `make'
|
||||
instead.
|
||||
|
||||
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
|
||||
parse its `<wchar.h>' 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.
|
4
Makefile.am
Executable file
4
Makefile.am
Executable file
@ -0,0 +1,4 @@
|
||||
|
||||
SUBDIRS = . bin man
|
||||
|
||||
EXTRA_dist = CreateSubHierarchy.pl
|
765
Makefile.in
Normal file
765
Makefile.in
Normal file
@ -0,0 +1,765 @@
|
||||
# Makefile.in generated by automake 1.14.1 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994-2013 Free Software Foundation, Inc.
|
||||
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
VPATH = @srcdir@
|
||||
am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
|
||||
am__make_running_with_option = \
|
||||
case $${target_option-} in \
|
||||
?) ;; \
|
||||
*) echo "am__make_running_with_option: internal error: invalid" \
|
||||
"target option '$${target_option-}' specified" >&2; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
has_opt=no; \
|
||||
sane_makeflags=$$MAKEFLAGS; \
|
||||
if $(am__is_gnu_make); then \
|
||||
sane_makeflags=$$MFLAGS; \
|
||||
else \
|
||||
case $$MAKEFLAGS in \
|
||||
*\\[\ \ ]*) \
|
||||
bs=\\; \
|
||||
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
|
||||
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
|
||||
esac; \
|
||||
fi; \
|
||||
skip_next=no; \
|
||||
strip_trailopt () \
|
||||
{ \
|
||||
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
|
||||
}; \
|
||||
for flg in $$sane_makeflags; do \
|
||||
test $$skip_next = yes && { skip_next=no; continue; }; \
|
||||
case $$flg in \
|
||||
*=*|--*) continue;; \
|
||||
-*I) strip_trailopt 'I'; skip_next=yes;; \
|
||||
-*I?*) strip_trailopt 'I';; \
|
||||
-*O) strip_trailopt 'O'; skip_next=yes;; \
|
||||
-*O?*) strip_trailopt 'O';; \
|
||||
-*l) strip_trailopt 'l'; skip_next=yes;; \
|
||||
-*l?*) strip_trailopt 'l';; \
|
||||
-[dEDm]) skip_next=yes;; \
|
||||
-[JT]) skip_next=yes;; \
|
||||
esac; \
|
||||
case $$flg in \
|
||||
*$$target_option*) has_opt=yes; break;; \
|
||||
esac; \
|
||||
done; \
|
||||
test $$has_opt = yes
|
||||
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
|
||||
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
subdir = .
|
||||
DIST_COMMON = INSTALL NEWS README AUTHORS ChangeLog \
|
||||
$(srcdir)/Makefile.in $(srcdir)/Makefile.am \
|
||||
$(top_srcdir)/configure $(am__configure_deps) \
|
||||
$(srcdir)/config.h.in COPYING compile depcomp install-sh \
|
||||
missing ylwrap
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
|
||||
configure.lineno config.status.lineno
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
AM_V_P = $(am__v_P_@AM_V@)
|
||||
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
|
||||
am__v_P_0 = false
|
||||
am__v_P_1 = :
|
||||
AM_V_GEN = $(am__v_GEN_@AM_V@)
|
||||
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
am__v_GEN_1 =
|
||||
AM_V_at = $(am__v_at_@AM_V@)
|
||||
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
|
||||
am__v_at_0 = @
|
||||
am__v_at_1 =
|
||||
SOURCES =
|
||||
DIST_SOURCES =
|
||||
RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
|
||||
ctags-recursive dvi-recursive html-recursive info-recursive \
|
||||
install-data-recursive install-dvi-recursive \
|
||||
install-exec-recursive install-html-recursive \
|
||||
install-info-recursive install-pdf-recursive \
|
||||
install-ps-recursive install-recursive installcheck-recursive \
|
||||
installdirs-recursive pdf-recursive ps-recursive \
|
||||
tags-recursive uninstall-recursive
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
|
||||
distclean-recursive maintainer-clean-recursive
|
||||
am__recursive_targets = \
|
||||
$(RECURSIVE_TARGETS) \
|
||||
$(RECURSIVE_CLEAN_TARGETS) \
|
||||
$(am__extra_recursive_targets)
|
||||
AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
|
||||
cscope distdir dist dist-all distcheck
|
||||
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
|
||||
$(LISP)config.h.in
|
||||
# Read a list of newline-separated strings from the standard input,
|
||||
# and print each of them once, without duplicates. Input order is
|
||||
# *not* preserved.
|
||||
am__uniquify_input = $(AWK) '\
|
||||
BEGIN { nonempty = 0; } \
|
||||
{ items[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in items) print i; }; } \
|
||||
'
|
||||
# Make sure the list of sources is unique. This is necessary because,
|
||||
# e.g., the same source file might be shared among _SOURCES variables
|
||||
# for different programs/libraries.
|
||||
am__define_uniq_tagged_files = \
|
||||
list='$(am__tagged_files)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | $(am__uniquify_input)`
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
CSCOPE = cscope
|
||||
DIST_SUBDIRS = $(SUBDIRS)
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
distdir = $(PACKAGE)-$(VERSION)
|
||||
top_distdir = $(distdir)
|
||||
am__remove_distdir = \
|
||||
if test -d "$(distdir)"; then \
|
||||
find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
|
||||
&& rm -rf "$(distdir)" \
|
||||
|| { sleep 5 && rm -rf "$(distdir)"; }; \
|
||||
else :; fi
|
||||
am__post_remove_distdir = $(am__remove_distdir)
|
||||
am__relativize = \
|
||||
dir0=`pwd`; \
|
||||
sed_first='s,^\([^/]*\)/.*$$,\1,'; \
|
||||
sed_rest='s,^[^/]*/*,,'; \
|
||||
sed_last='s,^.*/\([^/]*\)$$,\1,'; \
|
||||
sed_butlast='s,/*[^/]*$$,,'; \
|
||||
while test -n "$$dir1"; do \
|
||||
first=`echo "$$dir1" | sed -e "$$sed_first"`; \
|
||||
if test "$$first" != "."; then \
|
||||
if test "$$first" = ".."; then \
|
||||
dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
|
||||
dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
|
||||
else \
|
||||
first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
|
||||
if test "$$first2" = "$$first"; then \
|
||||
dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
|
||||
else \
|
||||
dir2="../$$dir2"; \
|
||||
fi; \
|
||||
dir0="$$dir0"/"$$first"; \
|
||||
fi; \
|
||||
fi; \
|
||||
dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
|
||||
done; \
|
||||
reldir="$$dir2"
|
||||
DIST_ARCHIVES = $(distdir).tar.gz
|
||||
GZIP_ENV = --best
|
||||
DIST_TARGETS = dist-gzip
|
||||
distuninstallcheck_listfiles = find . -type f -print
|
||||
am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
|
||||
| sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
|
||||
distcleancheck_listfiles = find . -type f -print
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
FTS_OBJ = @FTS_OBJ@
|
||||
FT_INCLUDES = @FT_INCLUDES@
|
||||
FT_LDFLAGS = @FT_LDFLAGS@
|
||||
GREP = @GREP@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LEX = @LEX@
|
||||
LEXLIB = @LEXLIB@
|
||||
LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
|
||||
LFLAGS = @LFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
OBJEXT = @OBJEXT@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
RRD_LIBS = @RRD_LIBS@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
VERSION = @VERSION@
|
||||
YACC = @YACC@
|
||||
YFLAGS = @YFLAGS@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build_alias = @build_alias@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host_alias = @host_alias@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
SUBDIRS = . bin man
|
||||
EXTRA_dist = CreateSubHierarchy.pl
|
||||
all: config.h
|
||||
$(MAKE) $(AM_MAKEFLAGS) all-recursive
|
||||
|
||||
.SUFFIXES:
|
||||
am--refresh: Makefile
|
||||
@:
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \
|
||||
$(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \
|
||||
&& exit 0; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --gnu Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
echo ' $(SHELL) ./config.status'; \
|
||||
$(SHELL) ./config.status;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
$(SHELL) ./config.status --recheck
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
$(am__cd) $(srcdir) && $(AUTOCONF)
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
config.h: stamp-h1
|
||||
@test -f $@ || rm -f stamp-h1
|
||||
@test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
|
||||
|
||||
stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
|
||||
@rm -f stamp-h1
|
||||
cd $(top_builddir) && $(SHELL) ./config.status config.h
|
||||
$(srcdir)/config.h.in: $(am__configure_deps)
|
||||
($(am__cd) $(top_srcdir) && $(AUTOHEADER))
|
||||
rm -f stamp-h1
|
||||
touch $@
|
||||
|
||||
distclean-hdr:
|
||||
-rm -f config.h stamp-h1
|
||||
|
||||
# This directory's subdirectories are mostly independent; you can cd
|
||||
# into them and run 'make' without going through this Makefile.
|
||||
# To change the values of 'make' variables: instead of editing Makefiles,
|
||||
# (1) if the variable is set in 'config.status', edit 'config.status'
|
||||
# (which will cause the Makefiles to be regenerated when you run 'make');
|
||||
# (2) otherwise, pass the desired values on the 'make' command line.
|
||||
$(am__recursive_targets):
|
||||
@fail=; \
|
||||
if $(am__make_keepgoing); then \
|
||||
failcom='fail=yes'; \
|
||||
else \
|
||||
failcom='exit 1'; \
|
||||
fi; \
|
||||
dot_seen=no; \
|
||||
target=`echo $@ | sed s/-recursive//`; \
|
||||
case "$@" in \
|
||||
distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
|
||||
*) list='$(SUBDIRS)' ;; \
|
||||
esac; \
|
||||
for subdir in $$list; do \
|
||||
echo "Making $$target in $$subdir"; \
|
||||
if test "$$subdir" = "."; then \
|
||||
dot_seen=yes; \
|
||||
local_target="$$target-am"; \
|
||||
else \
|
||||
local_target="$$target"; \
|
||||
fi; \
|
||||
($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|
||||
|| eval $$failcom; \
|
||||
done; \
|
||||
if test "$$dot_seen" = "no"; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
|
||||
fi; test -z "$$fail"
|
||||
|
||||
ID: $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); mkid -fID $$unique
|
||||
tags: tags-recursive
|
||||
TAGS: tags
|
||||
|
||||
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
|
||||
include_option=--etags-include; \
|
||||
empty_fix=.; \
|
||||
else \
|
||||
include_option=--include; \
|
||||
empty_fix=; \
|
||||
fi; \
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
if test "$$subdir" = .; then :; else \
|
||||
test ! -f $$subdir/TAGS || \
|
||||
set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
|
||||
fi; \
|
||||
done; \
|
||||
$(am__define_uniq_tagged_files); \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: ctags-recursive
|
||||
|
||||
CTAGS: ctags
|
||||
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
cscope: cscope.files
|
||||
test ! -s cscope.files \
|
||||
|| $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
|
||||
clean-cscope:
|
||||
-rm -f cscope.files
|
||||
cscope.files: clean-cscope cscopelist
|
||||
cscopelist: cscopelist-recursive
|
||||
|
||||
cscopelist-am: $(am__tagged_files)
|
||||
list='$(am__tagged_files)'; \
|
||||
case "$(srcdir)" in \
|
||||
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
|
||||
*) sdir=$(subdir)/$(srcdir) ;; \
|
||||
esac; \
|
||||
for i in $$list; do \
|
||||
if test -f "$$i"; then \
|
||||
echo "$(subdir)/$$i"; \
|
||||
else \
|
||||
echo "$$sdir/$$i"; \
|
||||
fi; \
|
||||
done >> $(top_builddir)/cscope.files
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
-rm -f cscope.out cscope.in.out cscope.po.out cscope.files
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
$(am__remove_distdir)
|
||||
test -d "$(distdir)" || mkdir "$(distdir)"
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
|
||||
if test "$$subdir" = .; then :; else \
|
||||
$(am__make_dryrun) \
|
||||
|| test -d "$(distdir)/$$subdir" \
|
||||
|| $(MKDIR_P) "$(distdir)/$$subdir" \
|
||||
|| exit 1; \
|
||||
dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
|
||||
$(am__relativize); \
|
||||
new_distdir=$$reldir; \
|
||||
dir1=$$subdir; dir2="$(top_distdir)"; \
|
||||
$(am__relativize); \
|
||||
new_top_distdir=$$reldir; \
|
||||
echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
|
||||
echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
|
||||
($(am__cd) $$subdir && \
|
||||
$(MAKE) $(AM_MAKEFLAGS) \
|
||||
top_distdir="$$new_top_distdir" \
|
||||
distdir="$$new_distdir" \
|
||||
am__remove_distdir=: \
|
||||
am__skip_length_check=: \
|
||||
am__skip_mode_fix=: \
|
||||
distdir) \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
-test -n "$(am__skip_mode_fix)" \
|
||||
|| find "$(distdir)" -type d ! -perm -755 \
|
||||
-exec chmod u+rwx,go+rx {} \; -o \
|
||||
! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
|
||||
! -type d ! -perm -400 -exec chmod a+r {} \; -o \
|
||||
! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
|
||||
|| chmod -R a+r "$(distdir)"
|
||||
dist-gzip: distdir
|
||||
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist-bzip2: distdir
|
||||
tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist-lzip: distdir
|
||||
tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist-xz: distdir
|
||||
tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist-tarZ: distdir
|
||||
@echo WARNING: "Support for shar distribution archives is" \
|
||||
"deprecated." >&2
|
||||
@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
|
||||
tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist-shar: distdir
|
||||
@echo WARNING: "Support for distribution archives compressed with" \
|
||||
"legacy program 'compress' is deprecated." >&2
|
||||
@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
|
||||
shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist-zip: distdir
|
||||
-rm -f $(distdir).zip
|
||||
zip -rq $(distdir).zip $(distdir)
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist dist-all:
|
||||
$(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
# This target untars the dist file and tries a VPATH configuration. Then
|
||||
# it guarantees that the distribution is self-contained by making another
|
||||
# tarfile.
|
||||
distcheck: dist
|
||||
case '$(DIST_ARCHIVES)' in \
|
||||
*.tar.gz*) \
|
||||
GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
|
||||
*.tar.bz2*) \
|
||||
bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
|
||||
*.tar.lz*) \
|
||||
lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
|
||||
*.tar.xz*) \
|
||||
xz -dc $(distdir).tar.xz | $(am__untar) ;;\
|
||||
*.tar.Z*) \
|
||||
uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
|
||||
*.shar.gz*) \
|
||||
GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
|
||||
*.zip*) \
|
||||
unzip $(distdir).zip ;;\
|
||||
esac
|
||||
chmod -R a-w $(distdir)
|
||||
chmod u+w $(distdir)
|
||||
mkdir $(distdir)/_build $(distdir)/_inst
|
||||
chmod a-w $(distdir)
|
||||
test -d $(distdir)/_build || exit 0; \
|
||||
dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
|
||||
&& dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
|
||||
&& am__cwd=`pwd` \
|
||||
&& $(am__cd) $(distdir)/_build \
|
||||
&& ../configure \
|
||||
$(AM_DISTCHECK_CONFIGURE_FLAGS) \
|
||||
$(DISTCHECK_CONFIGURE_FLAGS) \
|
||||
--srcdir=.. --prefix="$$dc_install_base" \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) dvi \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) check \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) install \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) installcheck \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) uninstall \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
|
||||
distuninstallcheck \
|
||||
&& chmod -R a-w "$$dc_install_base" \
|
||||
&& ({ \
|
||||
(cd ../.. && umask 077 && mkdir "$$dc_destdir") \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
|
||||
distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
|
||||
} || { rm -rf "$$dc_destdir"; exit 1; }) \
|
||||
&& rm -rf "$$dc_destdir" \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) dist \
|
||||
&& rm -rf $(DIST_ARCHIVES) \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
|
||||
&& cd "$$am__cwd" \
|
||||
|| exit 1
|
||||
$(am__post_remove_distdir)
|
||||
@(echo "$(distdir) archives ready for distribution: "; \
|
||||
list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
|
||||
sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
|
||||
distuninstallcheck:
|
||||
@test -n '$(distuninstallcheck_dir)' || { \
|
||||
echo 'ERROR: trying to run $@ with an empty' \
|
||||
'$$(distuninstallcheck_dir)' >&2; \
|
||||
exit 1; \
|
||||
}; \
|
||||
$(am__cd) '$(distuninstallcheck_dir)' || { \
|
||||
echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
|
||||
exit 1; \
|
||||
}; \
|
||||
test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
|
||||
|| { echo "ERROR: files left after uninstall:" ; \
|
||||
if test -n "$(DESTDIR)"; then \
|
||||
echo " (check DESTDIR support)"; \
|
||||
fi ; \
|
||||
$(distuninstallcheck_listfiles) ; \
|
||||
exit 1; } >&2
|
||||
distcleancheck: distclean
|
||||
@if test '$(srcdir)' = . ; then \
|
||||
echo "ERROR: distcleancheck can only run from a VPATH build" ; \
|
||||
exit 1 ; \
|
||||
fi
|
||||
@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
|
||||
|| { echo "ERROR: files left in build directory after distclean:" ; \
|
||||
$(distcleancheck_listfiles) ; \
|
||||
exit 1; } >&2
|
||||
check-am: all-am
|
||||
check: check-recursive
|
||||
all-am: Makefile config.h
|
||||
installdirs: installdirs-recursive
|
||||
installdirs-am:
|
||||
install: install-recursive
|
||||
install-exec: install-exec-recursive
|
||||
install-data: install-data-recursive
|
||||
uninstall: uninstall-recursive
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-recursive
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-recursive
|
||||
|
||||
clean-am: clean-generic mostlyclean-am
|
||||
|
||||
distclean: distclean-recursive
|
||||
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-generic distclean-hdr distclean-tags
|
||||
|
||||
dvi: dvi-recursive
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-recursive
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-recursive
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am:
|
||||
|
||||
install-dvi: install-dvi-recursive
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am:
|
||||
|
||||
install-html: install-html-recursive
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-recursive
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-recursive
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-recursive
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-recursive
|
||||
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
|
||||
-rm -rf $(top_srcdir)/autom4te.cache
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-recursive
|
||||
|
||||
mostlyclean-am: mostlyclean-generic
|
||||
|
||||
pdf: pdf-recursive
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-recursive
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am:
|
||||
|
||||
.MAKE: $(am__recursive_targets) all install-am install-strip
|
||||
|
||||
.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
|
||||
am--refresh check check-am clean clean-cscope clean-generic \
|
||||
cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \
|
||||
dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \
|
||||
distcheck distclean distclean-generic distclean-hdr \
|
||||
distclean-tags distcleancheck distdir distuninstallcheck dvi \
|
||||
dvi-am html html-am info info-am install install-am \
|
||||
install-data install-data-am install-dvi install-dvi-am \
|
||||
install-exec install-exec-am install-html install-html-am \
|
||||
install-info install-info-am install-man install-pdf \
|
||||
install-pdf-am install-ps install-ps-am install-strip \
|
||||
installcheck installcheck-am installdirs installdirs-am \
|
||||
maintainer-clean maintainer-clean-generic mostlyclean \
|
||||
mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
|
||||
uninstall-am
|
||||
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
412
README.md
Normal file → Executable file
412
README.md
Normal file → Executable file
@ -1,4 +1,412 @@
|
||||
# nfdump
|
||||
Netflow processing tools
|
||||
|
||||
nfdump is moving here - stay tuned.
|
||||
Stable Release v1.6.13
|
||||
|
||||
See the Changelog file for all changes in release 1.6.10
|
||||
|
||||
Notes on NSEL/ASA support
|
||||
-------------------------
|
||||
|
||||
nfdump-1.6.9 includes a new written from scratch implemented NSEL/ASA
|
||||
module. It's based on the CISCO ASA Spec 8.4:
|
||||
"Implementation Note for NetFlow Collectors, Version 8.4"
|
||||
Due to this new implementation, nfdump-1.6.9 is not compatible with old
|
||||
nfdump-1.5.8-2-NSEL.
|
||||
To build nfdump, add --enable-nsel to the configure command. By enabling
|
||||
the ASA/NSEL option, nfdump processes normal flows as well ASA/NSEL records
|
||||
likewise. nfcapd adds by default all required NSEL extesions equivalent
|
||||
to '-Tnsel'
|
||||
|
||||
Note on NEL support
|
||||
-------------------
|
||||
|
||||
nfdump-1.6.9 includes a new module for decoding the CISCO NEL ( NAT event
|
||||
logging ) records. It's considered to be experimantal, as no official
|
||||
documentation can be found. Let me know otherwise.
|
||||
To build nfdump, add --enable-nel to the configure command. By enabling
|
||||
the NEL option, nfdump processes normal flows as well NEL records
|
||||
likewise. nfcapd adds by default all required NEL extesions equivalent
|
||||
to '-Tnel'
|
||||
|
||||
Although it's possibel to enable NSEL und NEL likewise, users could get
|
||||
confused by nfdump output, as NSEL output format overwrites NEL format.
|
||||
In that case you need explicitly to define -o nel.
|
||||
|
||||
Notes on IPFIX
|
||||
---------------
|
||||
|
||||
nfdump contains an IPFIX module for decoding IPFIX data. It
|
||||
is considered not yet to be complete and does not yet support full IPFIX.
|
||||
o Supports basically same feature set of elements as netflow_v9 module
|
||||
o Only UDP traffic is accepted no SCTP so far
|
||||
o No sampling support.
|
||||
o Still more test data needed. If you would like to see more IPFIX
|
||||
support, please contact me.
|
||||
|
||||
|
||||
General README
|
||||
--------------
|
||||
|
||||
This is a small description, what the nfdump tools do and how they work.
|
||||
Nfdump is distributed under the BSD license - see BSD-license.txt
|
||||
|
||||
The nfdump tools collect and process netflow data on the command line.
|
||||
They are part of the NFSEN project, which is explained more detailed at
|
||||
http://www.terena.nl/tech/task-forces/tf-csirt/meeting12/nfsen-Haag.pdf
|
||||
|
||||
The Web interface mentioned is not part of nfdump and is available at
|
||||
http://nfsen.sourceforge.net
|
||||
|
||||
nfdump tools overview:
|
||||
----------------------
|
||||
|
||||
nfcapd - netflow collector daemon.
|
||||
Reads the netflow data from the network and stores the flow records
|
||||
into files. Automatically rotates files every n minutes. ( typically
|
||||
every 5 min ) nfcapd reads netflow versions v1, v5, v7 and v9 flows
|
||||
as well as IPFIX flows transparently. Several netflow streams can be
|
||||
sent to a single or collector.
|
||||
|
||||
nfdump - netflow dump.
|
||||
Reads the netflow data from the files stored by nfcapd. It's filter
|
||||
syntax is similar to tcpdump ( pcap like ) but for netflow adapted.
|
||||
If you like tcpdump you will like nfdump. nfdump displays netflow
|
||||
data and/or creates top N statistics of flows, bytes, packets. nfdump
|
||||
has a powerful and flexible flow aggregation including bi-directional
|
||||
flows. The output format is user selectable and also includes a simple
|
||||
csv format for post processing.
|
||||
|
||||
nfreplay - netflow replay
|
||||
Reads the netflow data from the files stored by nfcapd and sends it
|
||||
over the network to another host.
|
||||
|
||||
nfexpire - expire old netflow data
|
||||
Manages data expiration. Sets appropriate limits.
|
||||
|
||||
Optional binaries:
|
||||
|
||||
nfprofile - netflow profiler. Required by NfSen
|
||||
Reads the netflow data from the files stored by nfcapd. Filters the
|
||||
netflow data according to the specified filter sets ( profiles ) and
|
||||
stores the filtered data into files for later use.
|
||||
|
||||
nftrack - Port tracking decoder for NfSen plugin PortTracker.
|
||||
|
||||
ft2nfdump - read flow-tools format - Optional tool
|
||||
ft2nfdump acts as a pipe converter for flow-tools data. It allows
|
||||
to read any flow-tools data and process and save it in nfdump format.
|
||||
|
||||
sfcapd - sflow collector daemon
|
||||
scfapd collects sflow data and stores it into nfcapd comaptible files.
|
||||
"sfcapd includes sFlow(TM), freely available from http://www.inmon.com/".
|
||||
|
||||
nfreader - Framework for programmers
|
||||
nfreader is a framework to read nfdump files for any other purpose.
|
||||
Own C code can be added to process flows. nfreader is not installed
|
||||
|
||||
parse_csv.pl - Simple reader, written in Perl.
|
||||
parse_csv.pl reads nfdump csv output and print the flows to stdout.
|
||||
This program is intended to be a framework for post processing flows
|
||||
for any other purpose.
|
||||
|
||||
Note for sflow users:
|
||||
sfcapd and nfcapd can be used concurrently to collect netflow and sflow
|
||||
data at the same time. Generic command line options apply to both
|
||||
collectors likewise. Due to lack of availability of sflow devices,
|
||||
I could not test the correct output of IPv6 records. Users are requested
|
||||
to send feedback to the list or directly to me. sfcapd's sflow decoding
|
||||
module is based on InMon's sflowtool code and supports similar fields as
|
||||
nfcapd does for netflow v9, which is a subset of all available sflow
|
||||
fields in an sflow record. More fields may be integrated in future
|
||||
versions of sfcapd.
|
||||
|
||||
|
||||
Compression
|
||||
-----------
|
||||
Binary data files can optionally be compressed using the fast LZO1X-1
|
||||
compression. For more details on this algorithm see,
|
||||
http://www.oberhumer.com/opensource/lzo. LZO1X-1 is very fast, so
|
||||
that compression can be used in real time by the collector. LZO1X-1
|
||||
reduces the file size around 50%. You can check the compression speed
|
||||
for your system by doing ./nftest <path/to/an/existing/netflow/file>.
|
||||
|
||||
|
||||
Principle of Operation:
|
||||
-----------------------
|
||||
The goal of the design is to able to analyze netflow data from
|
||||
the past as well as to track interesting traffic patterns
|
||||
continuously. The amount of time back in the past is limited only
|
||||
by the disk storage available for all the netflow data. The tools
|
||||
are optimized for speed for efficient filtering. The filter rules
|
||||
should look familiar to the syntax of tcpdump ( pcap compatible ).
|
||||
|
||||
All data is stored to disk, before it gets analyzed. This separates
|
||||
the process of storing and analyzing the data.
|
||||
|
||||
The data is organized in a time-based fashion. Every n minutes
|
||||
- typically 5 min - nfcapd rotates and renames the output file
|
||||
with the timestamp nfcapd.YYYYMMddhhmm of the interval e.g.
|
||||
nfcapd.200907110845 contains data from July 11th 2009 08:45 onward.
|
||||
Based on a 5min time interval, this results in 288 files per day.
|
||||
|
||||
Analyzing the data can be done for a single file, or by concatenating
|
||||
several files for a single output. The output is either ASCII text
|
||||
or binary data, when saved into a file, ready to be processed again
|
||||
with the same tools.
|
||||
|
||||
You may have several netflow sources - let's say 'router1' 'router2'
|
||||
and so on. The data is organized as follows:
|
||||
|
||||
/flow_base_dir/router1
|
||||
/flow_base_dir/router2
|
||||
|
||||
which means router1 and router2 are subdirs of the flow_base_dir.
|
||||
|
||||
Although several flow sources can be sent to a single collector,
|
||||
It's recommended to have multiple collector on busy networks for
|
||||
each source.
|
||||
Example: Start two collectors on different ports:
|
||||
|
||||
nfcapd -w -D -S 2 -B 1024000 -l /flow_base_dir/router1 -p 23456
|
||||
nfcapd -w -D -S 2 -B 1024000 -l /flow_base_dir/router2 -p 23457
|
||||
|
||||
nfcapd can handle multiple flow sources.
|
||||
All sources can go into a single file or can be split:
|
||||
|
||||
All into the same file:
|
||||
nfcapd -w -D -S 2 -l /flow_base_dir/routers -p 23456
|
||||
|
||||
Collected on one port and split per source:
|
||||
nfcapd -w -D -S 2 -n router1,172.16.17.18,/flow_base_dir/router1 \
|
||||
-n router2,172.16.17.20,/flow_base_dir/router2 -p 23456
|
||||
|
||||
See nfcapd(1) for a detailed explanation of all options.
|
||||
|
||||
Security: none of the tools requires root privileges, unless you have
|
||||
a port < 1024. However, there is no access control mechanism in nfcapd.
|
||||
It is assumed, that host level security is in place to filter the
|
||||
proper IP addresses.
|
||||
|
||||
See the manual pages or use the -h switch for details on using each of
|
||||
the programs. For any questions send email to phaag@users.sourceforge.net
|
||||
|
||||
Configure your router to export netflow. See the relevant documentation
|
||||
for your model.
|
||||
|
||||
A generic Cisco sample configuration enabling NetFlow on an interface:
|
||||
|
||||
ip address 192.168.92.162 255.255.255.224
|
||||
interface fastethernet 0/0
|
||||
ip route-cache flow
|
||||
|
||||
To tell the router where to send the NetFlow data, enter the following
|
||||
global configuration command:
|
||||
|
||||
ip flow-export 192.168.92.218 9995
|
||||
ip flow-export version 5
|
||||
|
||||
ip flow-cache timeout active 5
|
||||
|
||||
This breaks up long-lived flows into 5-minute segments. You can choose
|
||||
any number of minutes between 1 and 60;
|
||||
|
||||
|
||||
Netflow v9 full export example of a cisco 7200 with sampling enabled:
|
||||
|
||||
interface Ethernet1/0
|
||||
ip address 192.168.92.162 255.255.255.224
|
||||
duplex half
|
||||
flow-sampler my-map
|
||||
!
|
||||
!
|
||||
flow-sampler-map my-map
|
||||
mode random one-out-of 5
|
||||
!
|
||||
ip flow-cache timeout inactive 60
|
||||
ip flow-cache timeout active 1
|
||||
ip flow-capture fragment-offset
|
||||
ip flow-capture packet-length
|
||||
ip flow-capture ttl
|
||||
ip flow-capture vlan-id
|
||||
ip flow-capture icmp
|
||||
ip flow-capture ip-id
|
||||
ip flow-capture mac-addresses
|
||||
ip flow-export version 9
|
||||
ip flow-export template options export-stats
|
||||
ip flow-export template options sampler
|
||||
ip flow-export template options timeout-rate 1
|
||||
ip flow-export template timeout-rate 1
|
||||
ip flow-export destination 192.168.92.218 9995
|
||||
|
||||
|
||||
See the relevant documentation for a full description of netflow commands
|
||||
|
||||
Note: Netflow version v5 and v7 have 32 bit counter values. The number of
|
||||
packets or bytes may overflow this value, within the flow-cache timeout
|
||||
on very busy routers. To prevent overflow, you may consider to reduce the
|
||||
flow-cache timeout to lower values. All nfdump tools use 64 bit counters
|
||||
internally, which means, all aggregated values are correctly reported.
|
||||
|
||||
The binary format of the data files is netflow version independent.
|
||||
For speed reasons the binary format is machine architecture dependent, and
|
||||
as such can not be exchanged between little and big endian systems.
|
||||
Internally nfdump does all processing IP protocol independent, which means
|
||||
everything works for IPv4 as well as IPv6 addresses.
|
||||
See the nfdump(1) man page for details.
|
||||
|
||||
netflow version 9:
|
||||
nfcapd supports a large range of netflow v9 tags. Version 1.6 nfdump
|
||||
supports the following fields. This list can be found in netflow_v9.h
|
||||
|
||||
// Flowset record types
|
||||
#define NF9_IN_BYTES 1
|
||||
#define NF9_IN_PACKETS 2
|
||||
#define NF9_FLOWS_AGGR 3
|
||||
#define NF9_IN_PROTOCOL 4
|
||||
#define NF9_SRC_TOS 5
|
||||
#define NF9_TCP_FLAGS 6
|
||||
#define NF9_L4_SRC_PORT 7
|
||||
#define NF9_IPV4_SRC_ADDR 8
|
||||
#define NF9_SRC_MASK 9
|
||||
#define NF9_INPUT_SNMP 10
|
||||
#define NF9_L4_DST_PORT 11
|
||||
#define NF9_IPV4_DST_ADDR 12
|
||||
#define NF9_DST_MASK 13
|
||||
#define NF9_OUTPUT_SNMP 14
|
||||
#define NF9_V4_NEXT_HOP 15
|
||||
#define NF9_SRC_AS 16
|
||||
#define NF9_DST_AS 17
|
||||
#define NF9_BGP_V4_NEXT_HOP 18
|
||||
|
||||
#define NF9_LAST_SWITCHED 21
|
||||
#define NF9_FIRST_SWITCHED 22
|
||||
#define NF9_OUT_BYTES 23
|
||||
#define NF9_OUT_PKTS 24
|
||||
|
||||
#define NF9_IPV6_SRC_ADDR 27
|
||||
#define NF9_IPV6_DST_ADDR 28
|
||||
#define NF9_IPV6_SRC_MASK 29
|
||||
#define NF9_IPV6_DST_MASK 30
|
||||
|
||||
#define NF9_IPV6_FLOW_LABEL 31
|
||||
#define NF9_ICMP_TYPE 32
|
||||
|
||||
#define NF9_SAMPLING_INTERVAL 34
|
||||
#define NF9_SAMPLING_ALGORITHM 35
|
||||
|
||||
#define NF9_ENGINE_TYPE 38
|
||||
#define NF9_ENGINE_ID 39
|
||||
|
||||
#define NF9_FLOW_SAMPLER_ID 48
|
||||
#define FLOW_SAMPLER_MODE 49
|
||||
#define NF9_FLOW_SAMPLER_RANDOM_INTERVAL 50
|
||||
|
||||
// #define NF9_MIN_TTL 52
|
||||
// #define NF9_MAX_TTL 53
|
||||
// #define NF9_IPV4_IDENT 54
|
||||
|
||||
#define NF9_DST_TOS 55
|
||||
#define NF9_IN_SRC_MAC 56
|
||||
#define NF9_OUT_DST_MAC 57
|
||||
#define NF9_SRC_VLAN 58
|
||||
#define NF9_DST_VLAN 59
|
||||
|
||||
#define NF9_DIRECTION 61
|
||||
#define NF9_V6_NEXT_HOP 62
|
||||
#define NF9_BPG_V6_NEXT_HOP 63
|
||||
// #define NF9_V6_OPTION_HEADERS 64
|
||||
|
||||
#define NF9_MPLS_LABEL_1 70
|
||||
#define NF9_MPLS_LABEL_2 71
|
||||
#define NF9_MPLS_LABEL_3 72
|
||||
#define NF9_MPLS_LABEL_4 73
|
||||
#define NF9_MPLS_LABEL_5 74
|
||||
#define NF9_MPLS_LABEL_6 75
|
||||
#define NF9_MPLS_LABEL_7 76
|
||||
#define NF9_MPLS_LABEL_8 77
|
||||
#define NF9_MPLS_LABEL_9 78
|
||||
#define NF9_MPLS_LABEL_10 79
|
||||
#define NF9_IN_DST_MAC 80
|
||||
#define NF9_OUT_SRC_MAC 81
|
||||
|
||||
|
||||
#define NF9_FORWARDING_STATUS 89
|
||||
|
||||
#define NF9_BGP_ADJ_NEXT_AS 128
|
||||
#define NF9_BGP_ADJ_PREV_AS 129
|
||||
|
||||
// CISCO ASA NSEL extension - Network Security Event Logging
|
||||
#define NF_F_FLOW_BYTES 85
|
||||
#define NF_F_CONN_ID 148
|
||||
#define NF_F_FLOW_CREATE_TIME_MSEC 152
|
||||
#define NF_F_ICMP_TYPE 176
|
||||
#define NF_F_ICMP_CODE 177
|
||||
#define NF_F_ICMP_TYPE_IPV6 178
|
||||
#define NF_F_ICMP_CODE_IPV6 179
|
||||
#define NF_F_FWD_FLOW_DELTA_BYTES 231
|
||||
#define NF_F_REV_FLOW_DELTA_BYTES 232
|
||||
#define NF_F_FW_EVENT84 233
|
||||
#define NF_F_EVENT_TIME_MSEC 323
|
||||
#define NF_F_INGRESS_ACL_ID 33000
|
||||
#define NF_F_EGRESS_ACL_ID 33001
|
||||
#define NF_F_FW_EXT_EVENT 33002
|
||||
#define NF_F_USERNAME 40000
|
||||
#define NF_F_XLATE_SRC_ADDR_IPV4 40001
|
||||
#define NF_F_XLATE_DST_ADDR_IPV4 40002
|
||||
#define NF_F_XLATE_SRC_PORT 40003
|
||||
#define NF_F_XLATE_DST_PORT 40004
|
||||
#define NF_F_FW_EVENT 40005
|
||||
|
||||
// Cisco ASR 1000 series NEL extension - Nat Event Logging
|
||||
#define NF_N_NAT_EVENT 230
|
||||
#define NF_N_INGRESS_VRFID 234
|
||||
#define NF_N_NAT_INSIDE_GLOBAL_IPV4 225
|
||||
#define NF_N_NAT_OUTSIDE_GLOBAL_IPV4 226
|
||||
#define NF_N_POST_NAPT_SRC_PORT 227
|
||||
#define NF_N_POST_NAPT_DST_PORT 228
|
||||
|
||||
|
||||
// nprobe latency extensions
|
||||
#define NF9_NPROBE_CLIENT_NW_DELAY_SEC 57554
|
||||
#define NF9_NPROBE_CLIENT_NW_DELAY_USEC 57555
|
||||
#define NF9_NPROBE_SERVER_NW_DELAY_SEC 57556
|
||||
#define NF9_NPROBE_SERVER_NW_DELAY_USEC 57557
|
||||
#define NF9_NPROBE_APPL_LATENCY_SEC 57558
|
||||
#define NF9_NPROBE_APPL_LATENCY_USEC 57559
|
||||
|
||||
32 and 64 bit counters are supported for any counters. However, internally
|
||||
nfdump stores packets and bytes counters always as 64bit counters.
|
||||
16 and 32 bit AS numbers are supported.
|
||||
|
||||
Extensions: nfcapd supports a large number of v9 tags. In order to optimise
|
||||
disk space and performance, v9 tags are grouped into a number of extensions
|
||||
which may or may not be stored into the data file. Therefore the v9 templates
|
||||
configured on the exporter may be tuned with the collector. Only the tags
|
||||
common to both are stored into the data files. Extensions can be switch
|
||||
on/off by using the -T option.
|
||||
|
||||
Sampling: By default, the sampling rate is set to 1 (unsampled) or to
|
||||
any given value specified by the -s cmd line option. If sampling information
|
||||
is found in the netflow stream, it overwrites the default value. Sampling
|
||||
is automatically recognised when announced in v9 option templates
|
||||
(tags #48, #49, #50 ) or in the unofficial v5 header hack. Note: Not all
|
||||
platforms (or IOS versions) support exporting sampling information in
|
||||
netflow data, even if sampling is configured. The number of bytes/packets
|
||||
in each netflow record is automatically multiplied by the sampling rate.
|
||||
The total number of flows is not changed as this is not accurate enough.
|
||||
(Small flows versus large flows)
|
||||
|
||||
nfcapd can listen on IPv6 or IPv4. Furthermore multicast is supported.
|
||||
|
||||
Flow-tools compatibility
|
||||
------------------------
|
||||
When building with configure option --enable-ftconv, the flow-tools converter
|
||||
is compiled. Using this converter, any flow-tools created data can be read
|
||||
and processed and stored by nfdump.
|
||||
|
||||
Example:
|
||||
|
||||
flow-cat [options] | ft2nfdump | nfdump [options]
|
||||
|
||||
|
||||
See the INSTALL file for installation details.
|
||||
|
6
ToDo
Normal file
6
ToDo
Normal file
@ -0,0 +1,6 @@
|
||||
- Add ASA support.
|
||||
Port CISCO code from nfdump-1.5.7-nsel to v1.6
|
||||
- Add packeteer code from wm.edu
|
||||
- Add BGP merge for AS filtering
|
||||
- Add index for fast IP lookup.
|
||||
- ... and endless new user ideas ...
|
1149
aclocal.m4
vendored
Normal file
1149
aclocal.m4
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9524
autom4te.cache/output.0
Normal file
9524
autom4te.cache/output.0
Normal file
File diff suppressed because it is too large
Load Diff
9524
autom4te.cache/output.1
Normal file
9524
autom4te.cache/output.1
Normal file
File diff suppressed because it is too large
Load Diff
154
autom4te.cache/requests
Normal file
154
autom4te.cache/requests
Normal file
@ -0,0 +1,154 @@
|
||||
# This file was generated.
|
||||
# It contains the lists of macros which have been traced.
|
||||
# It can be safely removed.
|
||||
|
||||
@request = (
|
||||
bless( [
|
||||
'0',
|
||||
1,
|
||||
[
|
||||
'/opt/local/share/autoconf'
|
||||
],
|
||||
[
|
||||
'/opt/local/share/autoconf/autoconf/autoconf.m4f',
|
||||
'-',
|
||||
'/opt/local/share/aclocal-1.14/internal/ac-config-macro-dirs.m4',
|
||||
'/opt/local/share/aclocal-1.14/amversion.m4',
|
||||
'/opt/local/share/aclocal-1.14/auxdir.m4',
|
||||
'/opt/local/share/aclocal-1.14/cond.m4',
|
||||
'/opt/local/share/aclocal-1.14/depend.m4',
|
||||
'/opt/local/share/aclocal-1.14/depout.m4',
|
||||
'/opt/local/share/aclocal-1.14/init.m4',
|
||||
'/opt/local/share/aclocal-1.14/install-sh.m4',
|
||||
'/opt/local/share/aclocal-1.14/lead-dot.m4',
|
||||
'/opt/local/share/aclocal-1.14/make.m4',
|
||||
'/opt/local/share/aclocal-1.14/missing.m4',
|
||||
'/opt/local/share/aclocal-1.14/options.m4',
|
||||
'/opt/local/share/aclocal-1.14/prog-cc-c-o.m4',
|
||||
'/opt/local/share/aclocal-1.14/runlog.m4',
|
||||
'/opt/local/share/aclocal-1.14/sanity.m4',
|
||||
'/opt/local/share/aclocal-1.14/silent.m4',
|
||||
'/opt/local/share/aclocal-1.14/strip.m4',
|
||||
'/opt/local/share/aclocal-1.14/substnot.m4',
|
||||
'/opt/local/share/aclocal-1.14/tar.m4',
|
||||
'configure.ac'
|
||||
],
|
||||
{
|
||||
'm4_pattern_forbid' => 1,
|
||||
'AM_SET_CURRENT_AUTOMAKE_VERSION' => 1,
|
||||
'_AM_SET_OPTION' => 1,
|
||||
'AC_DEFUN' => 1,
|
||||
'AM_INIT_AUTOMAKE' => 1,
|
||||
'AM_AUTOMAKE_VERSION' => 1,
|
||||
'AM_MISSING_HAS_RUN' => 1,
|
||||
'AM_SUBST_NOTMAKE' => 1,
|
||||
'AM_MISSING_PROG' => 1,
|
||||
'AM_OUTPUT_DEPENDENCY_COMMANDS' => 1,
|
||||
'AC_DEFUN_ONCE' => 1,
|
||||
'_AM_CONFIG_MACRO_DIRS' => 1,
|
||||
'AM_PROG_INSTALL_STRIP' => 1,
|
||||
'_m4_warn' => 1,
|
||||
'AM_SANITY_CHECK' => 1,
|
||||
'AM_SILENT_RULES' => 1,
|
||||
'include' => 1,
|
||||
'_AM_PROG_TAR' => 1,
|
||||
'AM_AUX_DIR_EXPAND' => 1,
|
||||
'AM_DEP_TRACK' => 1,
|
||||
'_AM_SET_OPTIONS' => 1,
|
||||
'_AM_OUTPUT_DEPENDENCY_COMMANDS' => 1,
|
||||
'AM_RUN_LOG' => 1,
|
||||
'AC_CONFIG_MACRO_DIR' => 1,
|
||||
'_AM_IF_OPTION' => 1,
|
||||
'_AM_SUBST_NOTMAKE' => 1,
|
||||
'm4_pattern_allow' => 1,
|
||||
'_AM_AUTOCONF_VERSION' => 1,
|
||||
'AM_PROG_CC_C_O' => 1,
|
||||
'_AM_MANGLE_OPTION' => 1,
|
||||
'AM_CONDITIONAL' => 1,
|
||||
'AM_SET_LEADING_DOT' => 1,
|
||||
'AC_CONFIG_MACRO_DIR_TRACE' => 1,
|
||||
'AM_SET_DEPDIR' => 1,
|
||||
'_AM_DEPENDENCIES' => 1,
|
||||
'AM_PROG_INSTALL_SH' => 1,
|
||||
'm4_include' => 1,
|
||||
'_AM_PROG_CC_C_O' => 1,
|
||||
'_AC_AM_CONFIG_HEADER_HOOK' => 1,
|
||||
'AU_DEFUN' => 1,
|
||||
'AM_MAKE_INCLUDE' => 1
|
||||
}
|
||||
], 'Autom4te::Request' ),
|
||||
bless( [
|
||||
'1',
|
||||
1,
|
||||
[
|
||||
'/opt/local/share/autoconf'
|
||||
],
|
||||
[
|
||||
'/opt/local/share/autoconf/autoconf/autoconf.m4f',
|
||||
'aclocal.m4',
|
||||
'configure.ac'
|
||||
],
|
||||
{
|
||||
'AM_PROG_F77_C_O' => 1,
|
||||
'_LT_AC_TAGCONFIG' => 1,
|
||||
'm4_pattern_forbid' => 1,
|
||||
'AC_INIT' => 1,
|
||||
'_AM_COND_IF' => 1,
|
||||
'AC_CANONICAL_TARGET' => 1,
|
||||
'AC_SUBST' => 1,
|
||||
'AC_CONFIG_LIBOBJ_DIR' => 1,
|
||||
'AM_EXTRA_RECURSIVE_TARGETS' => 1,
|
||||
'AC_FC_SRCEXT' => 1,
|
||||
'AC_CANONICAL_HOST' => 1,
|
||||
'AC_PROG_LIBTOOL' => 1,
|
||||
'AM_PROG_MKDIR_P' => 1,
|
||||
'AM_INIT_AUTOMAKE' => 1,
|
||||
'AM_PATH_GUILE' => 1,
|
||||
'AC_CONFIG_SUBDIRS' => 1,
|
||||
'AM_AUTOMAKE_VERSION' => 1,
|
||||
'LT_CONFIG_LTDL_DIR' => 1,
|
||||
'AC_REQUIRE_AUX_FILE' => 1,
|
||||
'AC_CONFIG_LINKS' => 1,
|
||||
'LT_SUPPORTED_TAG' => 1,
|
||||
'm4_sinclude' => 1,
|
||||
'AM_MAINTAINER_MODE' => 1,
|
||||
'AM_NLS' => 1,
|
||||
'AC_FC_PP_DEFINE' => 1,
|
||||
'AM_GNU_GETTEXT_INTL_SUBDIR' => 1,
|
||||
'AM_MAKEFILE_INCLUDE' => 1,
|
||||
'_m4_warn' => 1,
|
||||
'AM_PROG_CXX_C_O' => 1,
|
||||
'_AM_MAKEFILE_INCLUDE' => 1,
|
||||
'_AM_COND_ENDIF' => 1,
|
||||
'AM_ENABLE_MULTILIB' => 1,
|
||||
'AM_SILENT_RULES' => 1,
|
||||
'AM_PROG_MOC' => 1,
|
||||
'AC_CONFIG_FILES' => 1,
|
||||
'LT_INIT' => 1,
|
||||
'include' => 1,
|
||||
'AM_PROG_AR' => 1,
|
||||
'AM_GNU_GETTEXT' => 1,
|
||||
'AC_LIBSOURCE' => 1,
|
||||
'AM_PROG_FC_C_O' => 1,
|
||||
'AC_CANONICAL_BUILD' => 1,
|
||||
'AC_FC_FREEFORM' => 1,
|
||||
'AH_OUTPUT' => 1,
|
||||
'AC_FC_PP_SRCEXT' => 1,
|
||||
'_AM_SUBST_NOTMAKE' => 1,
|
||||
'AC_CONFIG_AUX_DIR' => 1,
|
||||
'AM_PROG_CC_C_O' => 1,
|
||||
'm4_pattern_allow' => 1,
|
||||
'sinclude' => 1,
|
||||
'AM_XGETTEXT_OPTION' => 1,
|
||||
'AC_CANONICAL_SYSTEM' => 1,
|
||||
'AM_CONDITIONAL' => 1,
|
||||
'AC_CONFIG_HEADERS' => 1,
|
||||
'AC_DEFINE_TRACE_LITERAL' => 1,
|
||||
'AM_POT_TOOLS' => 1,
|
||||
'm4_include' => 1,
|
||||
'_AM_COND_ELSE' => 1,
|
||||
'AC_SUBST_TRACE' => 1
|
||||
}
|
||||
], 'Autom4te::Request' )
|
||||
);
|
||||
|
1090
autom4te.cache/traces.0
Normal file
1090
autom4te.cache/traces.0
Normal file
File diff suppressed because it is too large
Load Diff
909
autom4te.cache/traces.1
Normal file
909
autom4te.cache/traces.1
Normal file
@ -0,0 +1,909 @@
|
||||
m4trace:configure.ac:6: -1- AC_INIT([nfdump], [1.6.13], [phaag@users.sourceforge.net])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_forbid([^_?A[CHUM]_])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_forbid([_AC_])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_forbid([^LIBOBJS$], [do not use LIBOBJS directly, use AC_LIBOBJ (see section `AC_LIBOBJ vs LIBOBJS'])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^AS_FLAGS$])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_forbid([^_?m4_])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_forbid([^dnl$])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_forbid([^_?AS_])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([SHELL])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([SHELL])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^SHELL$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([PATH_SEPARATOR])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([PATH_SEPARATOR])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^PATH_SEPARATOR$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([PACKAGE_NAME], [m4_ifdef([AC_PACKAGE_NAME], ['AC_PACKAGE_NAME'])])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([PACKAGE_NAME])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^PACKAGE_NAME$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([PACKAGE_TARNAME], [m4_ifdef([AC_PACKAGE_TARNAME], ['AC_PACKAGE_TARNAME'])])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([PACKAGE_TARNAME])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^PACKAGE_TARNAME$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([PACKAGE_VERSION], [m4_ifdef([AC_PACKAGE_VERSION], ['AC_PACKAGE_VERSION'])])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([PACKAGE_VERSION])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^PACKAGE_VERSION$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([PACKAGE_STRING], [m4_ifdef([AC_PACKAGE_STRING], ['AC_PACKAGE_STRING'])])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([PACKAGE_STRING])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^PACKAGE_STRING$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([PACKAGE_BUGREPORT], [m4_ifdef([AC_PACKAGE_BUGREPORT], ['AC_PACKAGE_BUGREPORT'])])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([PACKAGE_BUGREPORT])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([PACKAGE_URL], [m4_ifdef([AC_PACKAGE_URL], ['AC_PACKAGE_URL'])])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([PACKAGE_URL])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^PACKAGE_URL$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([exec_prefix], [NONE])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([exec_prefix])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^exec_prefix$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([prefix], [NONE])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([prefix])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^prefix$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([program_transform_name], [s,x,x,])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([program_transform_name])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^program_transform_name$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([bindir], ['${exec_prefix}/bin'])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([bindir])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^bindir$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([sbindir], ['${exec_prefix}/sbin'])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([sbindir])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^sbindir$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([libexecdir], ['${exec_prefix}/libexec'])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([libexecdir])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^libexecdir$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([datarootdir], ['${prefix}/share'])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([datarootdir])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^datarootdir$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([datadir], ['${datarootdir}'])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([datadir])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^datadir$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([sysconfdir], ['${prefix}/etc'])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([sysconfdir])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^sysconfdir$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([sharedstatedir], ['${prefix}/com'])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([sharedstatedir])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^sharedstatedir$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([localstatedir], ['${prefix}/var'])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([localstatedir])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^localstatedir$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([includedir], ['${prefix}/include'])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([includedir])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^includedir$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([oldincludedir], ['/usr/include'])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([oldincludedir])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^oldincludedir$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([docdir], [m4_ifset([AC_PACKAGE_TARNAME],
|
||||
['${datarootdir}/doc/${PACKAGE_TARNAME}'],
|
||||
['${datarootdir}/doc/${PACKAGE}'])])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([docdir])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^docdir$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([infodir], ['${datarootdir}/info'])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([infodir])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^infodir$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([htmldir], ['${docdir}'])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([htmldir])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^htmldir$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([dvidir], ['${docdir}'])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([dvidir])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^dvidir$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([pdfdir], ['${docdir}'])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([pdfdir])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^pdfdir$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([psdir], ['${docdir}'])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([psdir])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^psdir$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([libdir], ['${exec_prefix}/lib'])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([libdir])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^libdir$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([localedir], ['${datarootdir}/locale'])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([localedir])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^localedir$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([mandir], ['${datarootdir}/man'])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([mandir])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^mandir$])
|
||||
m4trace:configure.ac:6: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_NAME])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^PACKAGE_NAME$])
|
||||
m4trace:configure.ac:6: -1- AH_OUTPUT([PACKAGE_NAME], [/* Define to the full name of this package. */
|
||||
@%:@undef PACKAGE_NAME])
|
||||
m4trace:configure.ac:6: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_TARNAME])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^PACKAGE_TARNAME$])
|
||||
m4trace:configure.ac:6: -1- AH_OUTPUT([PACKAGE_TARNAME], [/* Define to the one symbol short name of this package. */
|
||||
@%:@undef PACKAGE_TARNAME])
|
||||
m4trace:configure.ac:6: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_VERSION])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^PACKAGE_VERSION$])
|
||||
m4trace:configure.ac:6: -1- AH_OUTPUT([PACKAGE_VERSION], [/* Define to the version of this package. */
|
||||
@%:@undef PACKAGE_VERSION])
|
||||
m4trace:configure.ac:6: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_STRING])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^PACKAGE_STRING$])
|
||||
m4trace:configure.ac:6: -1- AH_OUTPUT([PACKAGE_STRING], [/* Define to the full name and version of this package. */
|
||||
@%:@undef PACKAGE_STRING])
|
||||
m4trace:configure.ac:6: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_BUGREPORT])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$])
|
||||
m4trace:configure.ac:6: -1- AH_OUTPUT([PACKAGE_BUGREPORT], [/* Define to the address where bug reports for this package should be sent. */
|
||||
@%:@undef PACKAGE_BUGREPORT])
|
||||
m4trace:configure.ac:6: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_URL])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^PACKAGE_URL$])
|
||||
m4trace:configure.ac:6: -1- AH_OUTPUT([PACKAGE_URL], [/* Define to the home page for this package. */
|
||||
@%:@undef PACKAGE_URL])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([DEFS])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([DEFS])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^DEFS$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([ECHO_C])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([ECHO_C])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^ECHO_C$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([ECHO_N])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([ECHO_N])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^ECHO_N$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([ECHO_T])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([ECHO_T])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^ECHO_T$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([LIBS])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([LIBS])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^LIBS$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([build_alias])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([build_alias])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^build_alias$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([host_alias])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([host_alias])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^host_alias$])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST([target_alias])
|
||||
m4trace:configure.ac:6: -1- AC_SUBST_TRACE([target_alias])
|
||||
m4trace:configure.ac:6: -1- m4_pattern_allow([^target_alias$])
|
||||
m4trace:configure.ac:9: -1- AC_CONFIG_HEADERS([config.h])
|
||||
m4trace:configure.ac:10: -1- AM_INIT_AUTOMAKE([subdir-objects])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^AM_[A-Z]+FLAGS$])
|
||||
m4trace:configure.ac:10: -1- AM_AUTOMAKE_VERSION([1.14.1])
|
||||
m4trace:configure.ac:10: -1- AC_REQUIRE_AUX_FILE([install-sh])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([INSTALL_PROGRAM])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([INSTALL_PROGRAM])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^INSTALL_PROGRAM$])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([INSTALL_SCRIPT])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([INSTALL_SCRIPT])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^INSTALL_SCRIPT$])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([INSTALL_DATA])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([INSTALL_DATA])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^INSTALL_DATA$])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([am__isrc], [' -I$(srcdir)'])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([am__isrc])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^am__isrc$])
|
||||
m4trace:configure.ac:10: -1- _AM_SUBST_NOTMAKE([am__isrc])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([CYGPATH_W])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([CYGPATH_W])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^CYGPATH_W$])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([PACKAGE])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^PACKAGE$])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([VERSION])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^VERSION$])
|
||||
m4trace:configure.ac:10: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^PACKAGE$])
|
||||
m4trace:configure.ac:10: -1- AH_OUTPUT([PACKAGE], [/* Name of package */
|
||||
@%:@undef PACKAGE])
|
||||
m4trace:configure.ac:10: -1- AC_DEFINE_TRACE_LITERAL([VERSION])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^VERSION$])
|
||||
m4trace:configure.ac:10: -1- AH_OUTPUT([VERSION], [/* Version number of package */
|
||||
@%:@undef VERSION])
|
||||
m4trace:configure.ac:10: -1- AC_REQUIRE_AUX_FILE([missing])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([ACLOCAL])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([ACLOCAL])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^ACLOCAL$])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([AUTOCONF])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([AUTOCONF])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^AUTOCONF$])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([AUTOMAKE])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([AUTOMAKE])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^AUTOMAKE$])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([AUTOHEADER])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([AUTOHEADER])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^AUTOHEADER$])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([MAKEINFO])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([MAKEINFO])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^MAKEINFO$])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([install_sh])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([install_sh])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^install_sh$])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([STRIP])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([STRIP])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^STRIP$])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([INSTALL_STRIP_PROGRAM])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([INSTALL_STRIP_PROGRAM])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^INSTALL_STRIP_PROGRAM$])
|
||||
m4trace:configure.ac:10: -1- AC_REQUIRE_AUX_FILE([install-sh])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([MKDIR_P])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([MKDIR_P])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^MKDIR_P$])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([mkdir_p])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^mkdir_p$])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([AWK])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([AWK])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^AWK$])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([SET_MAKE])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([SET_MAKE])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^SET_MAKE$])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([am__leading_dot])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([am__leading_dot])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^am__leading_dot$])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([AMTAR], ['$${TAR-tar}'])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([AMTAR])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^AMTAR$])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([am__tar])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([am__tar])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^am__tar$])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([am__untar])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([am__untar])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^am__untar$])
|
||||
m4trace:configure.ac:10: -1- AM_SILENT_RULES
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([AM_V])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([AM_V])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^AM_V$])
|
||||
m4trace:configure.ac:10: -1- _AM_SUBST_NOTMAKE([AM_V])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([AM_DEFAULT_V])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([AM_DEFAULT_V])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^AM_DEFAULT_V$])
|
||||
m4trace:configure.ac:10: -1- _AM_SUBST_NOTMAKE([AM_DEFAULT_V])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([AM_DEFAULT_VERBOSITY])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([AM_DEFAULT_VERBOSITY])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^AM_DEFAULT_VERBOSITY$])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST([AM_BACKSLASH])
|
||||
m4trace:configure.ac:10: -1- AC_SUBST_TRACE([AM_BACKSLASH])
|
||||
m4trace:configure.ac:10: -1- m4_pattern_allow([^AM_BACKSLASH$])
|
||||
m4trace:configure.ac:10: -1- _AM_SUBST_NOTMAKE([AM_BACKSLASH])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST([CC])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST_TRACE([CC])
|
||||
m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST([CFLAGS])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST_TRACE([CFLAGS])
|
||||
m4trace:configure.ac:13: -1- m4_pattern_allow([^CFLAGS$])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST([LDFLAGS])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST_TRACE([LDFLAGS])
|
||||
m4trace:configure.ac:13: -1- m4_pattern_allow([^LDFLAGS$])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST([LIBS])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST_TRACE([LIBS])
|
||||
m4trace:configure.ac:13: -1- m4_pattern_allow([^LIBS$])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST([CPPFLAGS])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST_TRACE([CPPFLAGS])
|
||||
m4trace:configure.ac:13: -1- m4_pattern_allow([^CPPFLAGS$])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST([CC])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST_TRACE([CC])
|
||||
m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST([CC])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST_TRACE([CC])
|
||||
m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST([CC])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST_TRACE([CC])
|
||||
m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST([CC])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST_TRACE([CC])
|
||||
m4trace:configure.ac:13: -1- m4_pattern_allow([^CC$])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST([ac_ct_CC])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST_TRACE([ac_ct_CC])
|
||||
m4trace:configure.ac:13: -1- m4_pattern_allow([^ac_ct_CC$])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST([EXEEXT], [$ac_cv_exeext])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST_TRACE([EXEEXT])
|
||||
m4trace:configure.ac:13: -1- m4_pattern_allow([^EXEEXT$])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST([OBJEXT], [$ac_cv_objext])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST_TRACE([OBJEXT])
|
||||
m4trace:configure.ac:13: -1- m4_pattern_allow([^OBJEXT$])
|
||||
m4trace:configure.ac:13: -1- AC_REQUIRE_AUX_FILE([compile])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST_TRACE([DEPDIR])
|
||||
m4trace:configure.ac:13: -1- m4_pattern_allow([^DEPDIR$])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST([am__include])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST_TRACE([am__include])
|
||||
m4trace:configure.ac:13: -1- m4_pattern_allow([^am__include$])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST([am__quote])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST_TRACE([am__quote])
|
||||
m4trace:configure.ac:13: -1- m4_pattern_allow([^am__quote$])
|
||||
m4trace:configure.ac:13: -1- AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST([AMDEP_TRUE])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST_TRACE([AMDEP_TRUE])
|
||||
m4trace:configure.ac:13: -1- m4_pattern_allow([^AMDEP_TRUE$])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST([AMDEP_FALSE])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST_TRACE([AMDEP_FALSE])
|
||||
m4trace:configure.ac:13: -1- m4_pattern_allow([^AMDEP_FALSE$])
|
||||
m4trace:configure.ac:13: -1- _AM_SUBST_NOTMAKE([AMDEP_TRUE])
|
||||
m4trace:configure.ac:13: -1- _AM_SUBST_NOTMAKE([AMDEP_FALSE])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST([AMDEPBACKSLASH])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST_TRACE([AMDEPBACKSLASH])
|
||||
m4trace:configure.ac:13: -1- m4_pattern_allow([^AMDEPBACKSLASH$])
|
||||
m4trace:configure.ac:13: -1- _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST([am__nodep])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST_TRACE([am__nodep])
|
||||
m4trace:configure.ac:13: -1- m4_pattern_allow([^am__nodep$])
|
||||
m4trace:configure.ac:13: -1- _AM_SUBST_NOTMAKE([am__nodep])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST([CCDEPMODE], [depmode=$am_cv_CC_dependencies_compiler_type])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST_TRACE([CCDEPMODE])
|
||||
m4trace:configure.ac:13: -1- m4_pattern_allow([^CCDEPMODE$])
|
||||
m4trace:configure.ac:13: -1- AM_CONDITIONAL([am__fastdepCC], [
|
||||
test "x$enable_dependency_tracking" != xno \
|
||||
&& test "$am_cv_CC_dependencies_compiler_type" = gcc3])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST([am__fastdepCC_TRUE])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST_TRACE([am__fastdepCC_TRUE])
|
||||
m4trace:configure.ac:13: -1- m4_pattern_allow([^am__fastdepCC_TRUE$])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST([am__fastdepCC_FALSE])
|
||||
m4trace:configure.ac:13: -1- AC_SUBST_TRACE([am__fastdepCC_FALSE])
|
||||
m4trace:configure.ac:13: -1- m4_pattern_allow([^am__fastdepCC_FALSE$])
|
||||
m4trace:configure.ac:13: -1- _AM_SUBST_NOTMAKE([am__fastdepCC_TRUE])
|
||||
m4trace:configure.ac:13: -1- _AM_SUBST_NOTMAKE([am__fastdepCC_FALSE])
|
||||
m4trace:configure.ac:14: -1- AM_PROG_CC_C_O
|
||||
m4trace:configure.ac:18: -1- _m4_warn([obsolete], [The macro `ac_cv_prog_gcc' is obsolete.
|
||||
You should run autoupdate.], [../../lib/autoconf/c.m4:436: ac_cv_prog_gcc is expanded from...
|
||||
configure.ac:18: the top level])
|
||||
m4trace:configure.ac:65: -1- AC_SUBST([YACC])
|
||||
m4trace:configure.ac:65: -1- AC_SUBST_TRACE([YACC])
|
||||
m4trace:configure.ac:65: -1- m4_pattern_allow([^YACC$])
|
||||
m4trace:configure.ac:65: -1- AC_SUBST([YACC])
|
||||
m4trace:configure.ac:65: -1- AC_SUBST_TRACE([YACC])
|
||||
m4trace:configure.ac:65: -1- m4_pattern_allow([^YACC$])
|
||||
m4trace:configure.ac:65: -1- AC_SUBST([YFLAGS])
|
||||
m4trace:configure.ac:65: -1- AC_SUBST_TRACE([YFLAGS])
|
||||
m4trace:configure.ac:65: -1- m4_pattern_allow([^YFLAGS$])
|
||||
m4trace:configure.ac:66: -1- AC_SUBST([LEX])
|
||||
m4trace:configure.ac:66: -1- AC_SUBST_TRACE([LEX])
|
||||
m4trace:configure.ac:66: -1- m4_pattern_allow([^LEX$])
|
||||
m4trace:configure.ac:66: -1- AC_SUBST([LEX_OUTPUT_ROOT], [$ac_cv_prog_lex_root])
|
||||
m4trace:configure.ac:66: -1- AC_SUBST_TRACE([LEX_OUTPUT_ROOT])
|
||||
m4trace:configure.ac:66: -1- m4_pattern_allow([^LEX_OUTPUT_ROOT$])
|
||||
m4trace:configure.ac:66: -1- AC_SUBST([LEXLIB])
|
||||
m4trace:configure.ac:66: -1- AC_SUBST_TRACE([LEXLIB])
|
||||
m4trace:configure.ac:66: -1- m4_pattern_allow([^LEXLIB$])
|
||||
m4trace:configure.ac:66: -1- AC_DEFINE_TRACE_LITERAL([YYTEXT_POINTER])
|
||||
m4trace:configure.ac:66: -1- m4_pattern_allow([^YYTEXT_POINTER$])
|
||||
m4trace:configure.ac:66: -1- AH_OUTPUT([YYTEXT_POINTER], [/* Define to 1 if `lex\' declares `yytext\' as a `char *\' by default, not a
|
||||
`char@<:@@:>@\'. */
|
||||
@%:@undef YYTEXT_POINTER])
|
||||
m4trace:configure.ac:105: -2- AH_OUTPUT([HAVE_LIBZ], [/* Define to 1 if you have the `z\' library (-lz). */
|
||||
@%:@undef HAVE_LIBZ])
|
||||
m4trace:configure.ac:105: -2- AC_DEFINE_TRACE_LITERAL([HAVE_LIBZ])
|
||||
m4trace:configure.ac:105: -2- m4_pattern_allow([^HAVE_LIBZ$])
|
||||
m4trace:configure.ac:120: -2- AM_CONDITIONAL([FT2NFDUMP], [true])
|
||||
m4trace:configure.ac:120: -2- AC_SUBST([FT2NFDUMP_TRUE])
|
||||
m4trace:configure.ac:120: -2- AC_SUBST_TRACE([FT2NFDUMP_TRUE])
|
||||
m4trace:configure.ac:120: -2- m4_pattern_allow([^FT2NFDUMP_TRUE$])
|
||||
m4trace:configure.ac:120: -2- AC_SUBST([FT2NFDUMP_FALSE])
|
||||
m4trace:configure.ac:120: -2- AC_SUBST_TRACE([FT2NFDUMP_FALSE])
|
||||
m4trace:configure.ac:120: -2- m4_pattern_allow([^FT2NFDUMP_FALSE$])
|
||||
m4trace:configure.ac:120: -2- _AM_SUBST_NOTMAKE([FT2NFDUMP_TRUE])
|
||||
m4trace:configure.ac:120: -2- _AM_SUBST_NOTMAKE([FT2NFDUMP_FALSE])
|
||||
m4trace:configure.ac:122: -2- AM_CONDITIONAL([FT2NFDUMP], [false])
|
||||
m4trace:configure.ac:122: -2- AC_SUBST([FT2NFDUMP_TRUE])
|
||||
m4trace:configure.ac:122: -2- AC_SUBST_TRACE([FT2NFDUMP_TRUE])
|
||||
m4trace:configure.ac:122: -2- m4_pattern_allow([^FT2NFDUMP_TRUE$])
|
||||
m4trace:configure.ac:122: -2- AC_SUBST([FT2NFDUMP_FALSE])
|
||||
m4trace:configure.ac:122: -2- AC_SUBST_TRACE([FT2NFDUMP_FALSE])
|
||||
m4trace:configure.ac:122: -2- m4_pattern_allow([^FT2NFDUMP_FALSE$])
|
||||
m4trace:configure.ac:122: -2- _AM_SUBST_NOTMAKE([FT2NFDUMP_TRUE])
|
||||
m4trace:configure.ac:122: -2- _AM_SUBST_NOTMAKE([FT2NFDUMP_FALSE])
|
||||
m4trace:configure.ac:156: -2- AM_CONDITIONAL([NFPROFILE], [false])
|
||||
m4trace:configure.ac:156: -2- AC_SUBST([NFPROFILE_TRUE])
|
||||
m4trace:configure.ac:156: -2- AC_SUBST_TRACE([NFPROFILE_TRUE])
|
||||
m4trace:configure.ac:156: -2- m4_pattern_allow([^NFPROFILE_TRUE$])
|
||||
m4trace:configure.ac:156: -2- AC_SUBST([NFPROFILE_FALSE])
|
||||
m4trace:configure.ac:156: -2- AC_SUBST_TRACE([NFPROFILE_FALSE])
|
||||
m4trace:configure.ac:156: -2- m4_pattern_allow([^NFPROFILE_FALSE$])
|
||||
m4trace:configure.ac:156: -2- _AM_SUBST_NOTMAKE([NFPROFILE_TRUE])
|
||||
m4trace:configure.ac:156: -2- _AM_SUBST_NOTMAKE([NFPROFILE_FALSE])
|
||||
m4trace:configure.ac:126: -1- AC_SUBST([RRD_LIBS])
|
||||
m4trace:configure.ac:126: -1- AC_SUBST_TRACE([RRD_LIBS])
|
||||
m4trace:configure.ac:126: -1- m4_pattern_allow([^RRD_LIBS$])
|
||||
m4trace:configure.ac:126: -1- AH_OUTPUT([HAVE_RRD_H], [/* Define to 1 if you have the <rrd.h> header file. */
|
||||
@%:@undef HAVE_RRD_H])
|
||||
m4trace:configure.ac:126: -1- AC_SUBST([CPP])
|
||||
m4trace:configure.ac:126: -1- AC_SUBST_TRACE([CPP])
|
||||
m4trace:configure.ac:126: -1- m4_pattern_allow([^CPP$])
|
||||
m4trace:configure.ac:126: -1- AC_SUBST([CPPFLAGS])
|
||||
m4trace:configure.ac:126: -1- AC_SUBST_TRACE([CPPFLAGS])
|
||||
m4trace:configure.ac:126: -1- m4_pattern_allow([^CPPFLAGS$])
|
||||
m4trace:configure.ac:126: -1- AC_SUBST([CPP])
|
||||
m4trace:configure.ac:126: -1- AC_SUBST_TRACE([CPP])
|
||||
m4trace:configure.ac:126: -1- m4_pattern_allow([^CPP$])
|
||||
m4trace:configure.ac:126: -1- AC_SUBST([GREP])
|
||||
m4trace:configure.ac:126: -1- AC_SUBST_TRACE([GREP])
|
||||
m4trace:configure.ac:126: -1- m4_pattern_allow([^GREP$])
|
||||
m4trace:configure.ac:126: -1- AC_SUBST([EGREP])
|
||||
m4trace:configure.ac:126: -1- AC_SUBST_TRACE([EGREP])
|
||||
m4trace:configure.ac:126: -1- m4_pattern_allow([^EGREP$])
|
||||
m4trace:configure.ac:126: -1- AC_DEFINE_TRACE_LITERAL([STDC_HEADERS])
|
||||
m4trace:configure.ac:126: -1- m4_pattern_allow([^STDC_HEADERS$])
|
||||
m4trace:configure.ac:126: -1- AH_OUTPUT([STDC_HEADERS], [/* Define to 1 if you have the ANSI C header files. */
|
||||
@%:@undef STDC_HEADERS])
|
||||
m4trace:configure.ac:126: -1- AH_OUTPUT([HAVE_SYS_TYPES_H], [/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
@%:@undef HAVE_SYS_TYPES_H])
|
||||
m4trace:configure.ac:126: -1- AH_OUTPUT([HAVE_SYS_STAT_H], [/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
@%:@undef HAVE_SYS_STAT_H])
|
||||
m4trace:configure.ac:126: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
@%:@undef HAVE_STDLIB_H])
|
||||
m4trace:configure.ac:126: -1- AH_OUTPUT([HAVE_STRING_H], [/* Define to 1 if you have the <string.h> header file. */
|
||||
@%:@undef HAVE_STRING_H])
|
||||
m4trace:configure.ac:126: -1- AH_OUTPUT([HAVE_MEMORY_H], [/* Define to 1 if you have the <memory.h> header file. */
|
||||
@%:@undef HAVE_MEMORY_H])
|
||||
m4trace:configure.ac:126: -1- AH_OUTPUT([HAVE_STRINGS_H], [/* Define to 1 if you have the <strings.h> header file. */
|
||||
@%:@undef HAVE_STRINGS_H])
|
||||
m4trace:configure.ac:126: -1- AH_OUTPUT([HAVE_INTTYPES_H], [/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
@%:@undef HAVE_INTTYPES_H])
|
||||
m4trace:configure.ac:126: -1- AH_OUTPUT([HAVE_STDINT_H], [/* Define to 1 if you have the <stdint.h> header file. */
|
||||
@%:@undef HAVE_STDINT_H])
|
||||
m4trace:configure.ac:126: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the <unistd.h> header file. */
|
||||
@%:@undef HAVE_UNISTD_H])
|
||||
m4trace:configure.ac:126: -1- AC_DEFINE_TRACE_LITERAL([HAVE_RRD_H])
|
||||
m4trace:configure.ac:126: -1- m4_pattern_allow([^HAVE_RRD_H$])
|
||||
m4trace:configure.ac:126: -1- AM_CONDITIONAL([NFPROFILE], [true])
|
||||
m4trace:configure.ac:126: -1- AC_SUBST([NFPROFILE_TRUE])
|
||||
m4trace:configure.ac:126: -1- AC_SUBST_TRACE([NFPROFILE_TRUE])
|
||||
m4trace:configure.ac:126: -1- m4_pattern_allow([^NFPROFILE_TRUE$])
|
||||
m4trace:configure.ac:126: -1- AC_SUBST([NFPROFILE_FALSE])
|
||||
m4trace:configure.ac:126: -1- AC_SUBST_TRACE([NFPROFILE_FALSE])
|
||||
m4trace:configure.ac:126: -1- m4_pattern_allow([^NFPROFILE_FALSE$])
|
||||
m4trace:configure.ac:126: -1- _AM_SUBST_NOTMAKE([NFPROFILE_TRUE])
|
||||
m4trace:configure.ac:126: -1- _AM_SUBST_NOTMAKE([NFPROFILE_FALSE])
|
||||
m4trace:configure.ac:126: -1- _m4_warn([cross], [AC_RUN_IFELSE called without default to allow cross compiling], [../../lib/autoconf/general.m4:2748: AC_RUN_IFELSE is expanded from...
|
||||
../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from...
|
||||
../../lib/autoconf/general.m4:1462: AC_ARG_ENABLE is expanded from...
|
||||
configure.ac:126: the top level])
|
||||
m4trace:configure.ac:189: -2- AM_CONDITIONAL([NFTRACK], [false])
|
||||
m4trace:configure.ac:189: -2- AC_SUBST([NFTRACK_TRUE])
|
||||
m4trace:configure.ac:189: -2- AC_SUBST_TRACE([NFTRACK_TRUE])
|
||||
m4trace:configure.ac:189: -2- m4_pattern_allow([^NFTRACK_TRUE$])
|
||||
m4trace:configure.ac:189: -2- AC_SUBST([NFTRACK_FALSE])
|
||||
m4trace:configure.ac:189: -2- AC_SUBST_TRACE([NFTRACK_FALSE])
|
||||
m4trace:configure.ac:189: -2- m4_pattern_allow([^NFTRACK_FALSE$])
|
||||
m4trace:configure.ac:189: -2- _AM_SUBST_NOTMAKE([NFTRACK_TRUE])
|
||||
m4trace:configure.ac:189: -2- _AM_SUBST_NOTMAKE([NFTRACK_FALSE])
|
||||
m4trace:configure.ac:159: -1- AC_SUBST([RRD_LIBS])
|
||||
m4trace:configure.ac:159: -1- AC_SUBST_TRACE([RRD_LIBS])
|
||||
m4trace:configure.ac:159: -1- m4_pattern_allow([^RRD_LIBS$])
|
||||
m4trace:configure.ac:159: -1- AH_OUTPUT([HAVE_RRD_H], [/* Define to 1 if you have the <rrd.h> header file. */
|
||||
@%:@undef HAVE_RRD_H])
|
||||
m4trace:configure.ac:159: -1- AC_DEFINE_TRACE_LITERAL([HAVE_RRD_H])
|
||||
m4trace:configure.ac:159: -1- m4_pattern_allow([^HAVE_RRD_H$])
|
||||
m4trace:configure.ac:159: -1- AM_CONDITIONAL([NFTRACK], [true])
|
||||
m4trace:configure.ac:159: -1- AC_SUBST([NFTRACK_TRUE])
|
||||
m4trace:configure.ac:159: -1- AC_SUBST_TRACE([NFTRACK_TRUE])
|
||||
m4trace:configure.ac:159: -1- m4_pattern_allow([^NFTRACK_TRUE$])
|
||||
m4trace:configure.ac:159: -1- AC_SUBST([NFTRACK_FALSE])
|
||||
m4trace:configure.ac:159: -1- AC_SUBST_TRACE([NFTRACK_FALSE])
|
||||
m4trace:configure.ac:159: -1- m4_pattern_allow([^NFTRACK_FALSE$])
|
||||
m4trace:configure.ac:159: -1- _AM_SUBST_NOTMAKE([NFTRACK_TRUE])
|
||||
m4trace:configure.ac:159: -1- _AM_SUBST_NOTMAKE([NFTRACK_FALSE])
|
||||
m4trace:configure.ac:159: -1- _m4_warn([cross], [AC_RUN_IFELSE called without default to allow cross compiling], [../../lib/autoconf/general.m4:2748: AC_RUN_IFELSE is expanded from...
|
||||
../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from...
|
||||
../../lib/autoconf/general.m4:1462: AC_ARG_ENABLE is expanded from...
|
||||
configure.ac:159: the top level])
|
||||
m4trace:configure.ac:194: -1- AM_CONDITIONAL([SFLOW], [test "$enable_sflow" = yes])
|
||||
m4trace:configure.ac:194: -1- AC_SUBST([SFLOW_TRUE])
|
||||
m4trace:configure.ac:194: -1- AC_SUBST_TRACE([SFLOW_TRUE])
|
||||
m4trace:configure.ac:194: -1- m4_pattern_allow([^SFLOW_TRUE$])
|
||||
m4trace:configure.ac:194: -1- AC_SUBST([SFLOW_FALSE])
|
||||
m4trace:configure.ac:194: -1- AC_SUBST_TRACE([SFLOW_FALSE])
|
||||
m4trace:configure.ac:194: -1- m4_pattern_allow([^SFLOW_FALSE$])
|
||||
m4trace:configure.ac:194: -1- _AM_SUBST_NOTMAKE([SFLOW_TRUE])
|
||||
m4trace:configure.ac:194: -1- _AM_SUBST_NOTMAKE([SFLOW_FALSE])
|
||||
m4trace:configure.ac:198: -1- AM_CONDITIONAL([READPCAP], [test "$enable_readpcap" = yes])
|
||||
m4trace:configure.ac:198: -1- AC_SUBST([READPCAP_TRUE])
|
||||
m4trace:configure.ac:198: -1- AC_SUBST_TRACE([READPCAP_TRUE])
|
||||
m4trace:configure.ac:198: -1- m4_pattern_allow([^READPCAP_TRUE$])
|
||||
m4trace:configure.ac:198: -1- AC_SUBST([READPCAP_FALSE])
|
||||
m4trace:configure.ac:198: -1- AC_SUBST_TRACE([READPCAP_FALSE])
|
||||
m4trace:configure.ac:198: -1- m4_pattern_allow([^READPCAP_FALSE$])
|
||||
m4trace:configure.ac:198: -1- _AM_SUBST_NOTMAKE([READPCAP_TRUE])
|
||||
m4trace:configure.ac:198: -1- _AM_SUBST_NOTMAKE([READPCAP_FALSE])
|
||||
m4trace:configure.ac:202: -1- AM_CONDITIONAL([BUILDNFPCAPD], [test "$enable_nfpcapd" = yes])
|
||||
m4trace:configure.ac:202: -1- AC_SUBST([BUILDNFPCAPD_TRUE])
|
||||
m4trace:configure.ac:202: -1- AC_SUBST_TRACE([BUILDNFPCAPD_TRUE])
|
||||
m4trace:configure.ac:202: -1- m4_pattern_allow([^BUILDNFPCAPD_TRUE$])
|
||||
m4trace:configure.ac:202: -1- AC_SUBST([BUILDNFPCAPD_FALSE])
|
||||
m4trace:configure.ac:202: -1- AC_SUBST_TRACE([BUILDNFPCAPD_FALSE])
|
||||
m4trace:configure.ac:202: -1- m4_pattern_allow([^BUILDNFPCAPD_FALSE$])
|
||||
m4trace:configure.ac:202: -1- _AM_SUBST_NOTMAKE([BUILDNFPCAPD_TRUE])
|
||||
m4trace:configure.ac:202: -1- _AM_SUBST_NOTMAKE([BUILDNFPCAPD_FALSE])
|
||||
m4trace:configure.ac:206: -2- AC_DEFINE_TRACE_LITERAL([HAVE_SOCKADDR_SA_LEN])
|
||||
m4trace:configure.ac:206: -2- m4_pattern_allow([^HAVE_SOCKADDR_SA_LEN$])
|
||||
m4trace:configure.ac:206: -2- AH_OUTPUT([HAVE_SOCKADDR_SA_LEN], [/* define if socket address structures have length fields */
|
||||
@%:@undef HAVE_SOCKADDR_SA_LEN])
|
||||
m4trace:configure.ac:210: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY])
|
||||
m4trace:configure.ac:210: -1- m4_pattern_allow([^HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY$])
|
||||
m4trace:configure.ac:210: -1- AH_OUTPUT([HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY], [/* Define to 1 if `ss_family\' is a member of `struct sockaddr_storage\'. */
|
||||
@%:@undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY])
|
||||
m4trace:configure.ac:210: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY])
|
||||
m4trace:configure.ac:210: -1- m4_pattern_allow([^HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY$])
|
||||
m4trace:configure.ac:210: -1- AH_OUTPUT([HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY], [/* Define to 1 if `__ss_family\' is a member of `struct sockaddr_storage\'. */
|
||||
@%:@undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY])
|
||||
m4trace:configure.ac:210: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN])
|
||||
m4trace:configure.ac:210: -1- m4_pattern_allow([^HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN$])
|
||||
m4trace:configure.ac:210: -1- AH_OUTPUT([HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN], [/* Define to 1 if `ss_len\' is a member of `struct sockaddr_storage\'. */
|
||||
@%:@undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN])
|
||||
m4trace:configure.ac:210: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_SOCKADDR_STORAGE___SS_LEN])
|
||||
m4trace:configure.ac:210: -1- m4_pattern_allow([^HAVE_STRUCT_SOCKADDR_STORAGE___SS_LEN$])
|
||||
m4trace:configure.ac:210: -1- AH_OUTPUT([HAVE_STRUCT_SOCKADDR_STORAGE___SS_LEN], [/* Define to 1 if `__ss_len\' is a member of `struct sockaddr_storage\'. */
|
||||
@%:@undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_LEN])
|
||||
m4trace:configure.ac:210: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_SOCKADDR_SA_LEN])
|
||||
m4trace:configure.ac:210: -1- m4_pattern_allow([^HAVE_STRUCT_SOCKADDR_SA_LEN$])
|
||||
m4trace:configure.ac:210: -1- AH_OUTPUT([HAVE_STRUCT_SOCKADDR_SA_LEN], [/* Define to 1 if `sa_len\' is a member of `struct sockaddr\'. */
|
||||
@%:@undef HAVE_STRUCT_SOCKADDR_SA_LEN])
|
||||
m4trace:configure.ac:220: -1- AC_SUBST([FT_INCLUDES])
|
||||
m4trace:configure.ac:220: -1- AC_SUBST_TRACE([FT_INCLUDES])
|
||||
m4trace:configure.ac:220: -1- m4_pattern_allow([^FT_INCLUDES$])
|
||||
m4trace:configure.ac:221: -1- AC_SUBST([FT_LDFLAGS])
|
||||
m4trace:configure.ac:221: -1- AC_SUBST_TRACE([FT_LDFLAGS])
|
||||
m4trace:configure.ac:221: -1- m4_pattern_allow([^FT_LDFLAGS$])
|
||||
m4trace:configure.ac:222: -1- AC_SUBST([LFLAGS])
|
||||
m4trace:configure.ac:222: -1- AC_SUBST_TRACE([LFLAGS])
|
||||
m4trace:configure.ac:222: -1- m4_pattern_allow([^LFLAGS$])
|
||||
m4trace:configure.ac:226: -1- AH_OUTPUT([HAVE_GETHOSTBYNAME], [/* Define to 1 if you have the `gethostbyname\' function. */
|
||||
@%:@undef HAVE_GETHOSTBYNAME])
|
||||
m4trace:configure.ac:226: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETHOSTBYNAME])
|
||||
m4trace:configure.ac:226: -1- m4_pattern_allow([^HAVE_GETHOSTBYNAME$])
|
||||
m4trace:configure.ac:226: -1- AH_OUTPUT([HAVE_LIBNSL], [/* Define to 1 if you have the `nsl\' library (-lnsl). */
|
||||
@%:@undef HAVE_LIBNSL])
|
||||
m4trace:configure.ac:226: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBNSL])
|
||||
m4trace:configure.ac:226: -1- m4_pattern_allow([^HAVE_LIBNSL$])
|
||||
m4trace:configure.ac:226: -1- AH_OUTPUT([HAVE_LIBSOCKET], [/* Define to 1 if you have the `socket\' library (-lsocket). */
|
||||
@%:@undef HAVE_LIBSOCKET])
|
||||
m4trace:configure.ac:226: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBSOCKET])
|
||||
m4trace:configure.ac:226: -1- m4_pattern_allow([^HAVE_LIBSOCKET$])
|
||||
m4trace:configure.ac:227: -1- AH_OUTPUT([HAVE_SETSOCKOPT], [/* Define to 1 if you have the `setsockopt\' function. */
|
||||
@%:@undef HAVE_SETSOCKOPT])
|
||||
m4trace:configure.ac:227: -1- AC_DEFINE_TRACE_LITERAL([HAVE_SETSOCKOPT])
|
||||
m4trace:configure.ac:227: -1- m4_pattern_allow([^HAVE_SETSOCKOPT$])
|
||||
m4trace:configure.ac:227: -1- AH_OUTPUT([HAVE_LIBSOCKET], [/* Define to 1 if you have the `socket\' library (-lsocket). */
|
||||
@%:@undef HAVE_LIBSOCKET])
|
||||
m4trace:configure.ac:227: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBSOCKET])
|
||||
m4trace:configure.ac:227: -1- m4_pattern_allow([^HAVE_LIBSOCKET$])
|
||||
m4trace:configure.ac:230: -1- AH_OUTPUT([HAVE_FPURGE], [/* Define to 1 if you have the `fpurge\' function. */
|
||||
@%:@undef HAVE_FPURGE])
|
||||
m4trace:configure.ac:230: -1- AH_OUTPUT([HAVE___FPURGE], [/* Define to 1 if you have the `__fpurge\' function. */
|
||||
@%:@undef HAVE___FPURGE])
|
||||
m4trace:configure.ac:235: -1- AC_DEFINE_TRACE_LITERAL([HAVE_HTONLL])
|
||||
m4trace:configure.ac:235: -1- m4_pattern_allow([^HAVE_HTONLL$])
|
||||
m4trace:configure.ac:235: -1- AH_OUTPUT([HAVE_HTONLL], [/* Define to 1 if the function (or macro) htonll exists. */
|
||||
@%:@undef HAVE_HTONLL])
|
||||
m4trace:configure.ac:254: -1- AH_OUTPUT([HAVE_DIRENT_H], [/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR\'.
|
||||
*/
|
||||
@%:@undef HAVE_DIRENT_H])
|
||||
m4trace:configure.ac:254: -1- AH_OUTPUT([HAVE_SYS_NDIR_H], [/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR\'.
|
||||
*/
|
||||
@%:@undef HAVE_SYS_NDIR_H])
|
||||
m4trace:configure.ac:254: -1- AH_OUTPUT([HAVE_SYS_DIR_H], [/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR\'.
|
||||
*/
|
||||
@%:@undef HAVE_SYS_DIR_H])
|
||||
m4trace:configure.ac:254: -1- AH_OUTPUT([HAVE_NDIR_H], [/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR\'. */
|
||||
@%:@undef HAVE_NDIR_H])
|
||||
m4trace:configure.ac:255: -1- AC_DEFINE_TRACE_LITERAL([STDC_HEADERS])
|
||||
m4trace:configure.ac:255: -1- m4_pattern_allow([^STDC_HEADERS$])
|
||||
m4trace:configure.ac:255: -1- AH_OUTPUT([STDC_HEADERS], [/* Define to 1 if you have the ANSI C header files. */
|
||||
@%:@undef STDC_HEADERS])
|
||||
m4trace:configure.ac:256: -1- AH_OUTPUT([HAVE_NAMESER8_COMPAT_H], [/* Define to 1 if you have the <nameser8_compat.h> header file. */
|
||||
@%:@undef HAVE_NAMESER8_COMPAT_H])
|
||||
m4trace:configure.ac:256: -1- AC_DEFINE_TRACE_LITERAL([HAVE_NAMESER8_COMPAT_H])
|
||||
m4trace:configure.ac:256: -1- m4_pattern_allow([^HAVE_NAMESER8_COMPAT_H$])
|
||||
m4trace:configure.ac:257: -1- AH_OUTPUT([HAVE_FEATURES_H], [/* Define to 1 if you have the <features.h> header file. */
|
||||
@%:@undef HAVE_FEATURES_H])
|
||||
m4trace:configure.ac:257: -1- AH_OUTPUT([HAVE_ARPA_INET_H], [/* Define to 1 if you have the <arpa/inet.h> header file. */
|
||||
@%:@undef HAVE_ARPA_INET_H])
|
||||
m4trace:configure.ac:257: -1- AH_OUTPUT([HAVE_FCNTL_H], [/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
@%:@undef HAVE_FCNTL_H])
|
||||
m4trace:configure.ac:257: -1- AH_OUTPUT([HAVE_NETINET_IN_H], [/* Define to 1 if you have the <netinet/in.h> header file. */
|
||||
@%:@undef HAVE_NETINET_IN_H])
|
||||
m4trace:configure.ac:257: -1- AH_OUTPUT([HAVE_FTS_H], [/* Define to 1 if you have the <fts.h> header file. */
|
||||
@%:@undef HAVE_FTS_H])
|
||||
m4trace:configure.ac:257: -1- AH_OUTPUT([HAVE_STDINT_H], [/* Define to 1 if you have the <stdint.h> header file. */
|
||||
@%:@undef HAVE_STDINT_H])
|
||||
m4trace:configure.ac:257: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
@%:@undef HAVE_STDLIB_H])
|
||||
m4trace:configure.ac:257: -1- AH_OUTPUT([HAVE_STDDEF_H], [/* Define to 1 if you have the <stddef.h> header file. */
|
||||
@%:@undef HAVE_STDDEF_H])
|
||||
m4trace:configure.ac:257: -1- AH_OUTPUT([HAVE_STRING_H], [/* Define to 1 if you have the <string.h> header file. */
|
||||
@%:@undef HAVE_STRING_H])
|
||||
m4trace:configure.ac:257: -1- AH_OUTPUT([HAVE_SYS_SOCKET_H], [/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
@%:@undef HAVE_SYS_SOCKET_H])
|
||||
m4trace:configure.ac:257: -1- AH_OUTPUT([HAVE_SYSLOG_H], [/* Define to 1 if you have the <syslog.h> header file. */
|
||||
@%:@undef HAVE_SYSLOG_H])
|
||||
m4trace:configure.ac:257: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the <unistd.h> header file. */
|
||||
@%:@undef HAVE_UNISTD_H])
|
||||
m4trace:configure.ac:257: -1- AH_OUTPUT([HAVE_ISO_LIMITS_ISO_H], [/* Define to 1 if you have the <iso/limits_iso.h> header file. */
|
||||
@%:@undef HAVE_ISO_LIMITS_ISO_H])
|
||||
m4trace:configure.ac:258: -1- AH_OUTPUT([HAVE_PCAP_BPF_H], [/* Define to 1 if you have the <pcap-bpf.h> header file. */
|
||||
@%:@undef HAVE_PCAP_BPF_H])
|
||||
m4trace:configure.ac:258: -1- AH_OUTPUT([HAVE_NET_BPF_H], [/* Define to 1 if you have the <net/bpf.h> header file. */
|
||||
@%:@undef HAVE_NET_BPF_H])
|
||||
m4trace:configure.ac:260: -1- AH_OUTPUT([HAVE_SYS_TYPES_H], [/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
@%:@undef HAVE_SYS_TYPES_H])
|
||||
m4trace:configure.ac:260: -1- AH_OUTPUT([HAVE_NETINET_IN_H], [/* Define to 1 if you have the <netinet/in.h> header file. */
|
||||
@%:@undef HAVE_NETINET_IN_H])
|
||||
m4trace:configure.ac:260: -1- AH_OUTPUT([HAVE_ARPA_NAMESER_H], [/* Define to 1 if you have the <arpa/nameser.h> header file. */
|
||||
@%:@undef HAVE_ARPA_NAMESER_H])
|
||||
m4trace:configure.ac:260: -1- AH_OUTPUT([HAVE_ARPA_NAMESER_COMPAT_H], [/* Define to 1 if you have the <arpa/nameser_compat.h> header file. */
|
||||
@%:@undef HAVE_ARPA_NAMESER_COMPAT_H])
|
||||
m4trace:configure.ac:260: -1- AH_OUTPUT([HAVE_NETDB_H], [/* Define to 1 if you have the <netdb.h> header file. */
|
||||
@%:@undef HAVE_NETDB_H])
|
||||
m4trace:configure.ac:260: -1- AH_OUTPUT([HAVE_RESOLV_H], [/* Define to 1 if you have the <resolv.h> header file. */
|
||||
@%:@undef HAVE_RESOLV_H])
|
||||
m4trace:configure.ac:279: -1- AC_SUBST([FTS_OBJ])
|
||||
m4trace:configure.ac:279: -1- AC_SUBST_TRACE([FTS_OBJ])
|
||||
m4trace:configure.ac:279: -1- m4_pattern_allow([^FTS_OBJ$])
|
||||
m4trace:configure.ac:283: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_VOID_P])
|
||||
m4trace:configure.ac:283: -1- m4_pattern_allow([^SIZEOF_VOID_P$])
|
||||
m4trace:configure.ac:283: -1- AH_OUTPUT([SIZEOF_VOID_P], [/* The size of `void *\', as computed by sizeof. */
|
||||
@%:@undef SIZEOF_VOID_P])
|
||||
m4trace:configure.ac:285: -1- AC_DEFINE_TRACE_LITERAL([const])
|
||||
m4trace:configure.ac:285: -1- m4_pattern_allow([^const$])
|
||||
m4trace:configure.ac:285: -1- AH_OUTPUT([const], [/* Define to empty if `const\' does not conform to ANSI C. */
|
||||
@%:@undef const])
|
||||
m4trace:configure.ac:286: -1- AH_OUTPUT([inline], [/* Define to `__inline__\' or `__inline\' if that\'s what the C compiler
|
||||
calls it, or to nothing if \'inline\' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
#undef inline
|
||||
#endif])
|
||||
m4trace:configure.ac:287: -1- AH_OUTPUT([WORDS_BIGENDIAN], [/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
||||
#if defined AC_APPLE_UNIVERSAL_BUILD
|
||||
# if defined __BIG_ENDIAN__
|
||||
# define WORDS_BIGENDIAN 1
|
||||
# endif
|
||||
#else
|
||||
# ifndef WORDS_BIGENDIAN
|
||||
# undef WORDS_BIGENDIAN
|
||||
# endif
|
||||
#endif])
|
||||
m4trace:configure.ac:287: -1- AC_DEFINE_TRACE_LITERAL([WORDS_BIGENDIAN])
|
||||
m4trace:configure.ac:287: -1- m4_pattern_allow([^WORDS_BIGENDIAN$])
|
||||
m4trace:configure.ac:287: -1- AC_DEFINE_TRACE_LITERAL([AC_APPLE_UNIVERSAL_BUILD])
|
||||
m4trace:configure.ac:287: -1- m4_pattern_allow([^AC_APPLE_UNIVERSAL_BUILD$])
|
||||
m4trace:configure.ac:287: -1- AH_OUTPUT([AC_APPLE_UNIVERSAL_BUILD], [/* Define if building universal (internal helper macro) */
|
||||
@%:@undef AC_APPLE_UNIVERSAL_BUILD])
|
||||
m4trace:configure.ac:288: -1- AC_DEFINE_TRACE_LITERAL([pid_t])
|
||||
m4trace:configure.ac:288: -1- m4_pattern_allow([^pid_t$])
|
||||
m4trace:configure.ac:288: -1- AH_OUTPUT([pid_t], [/* Define to `int\' if <sys/types.h> does not define. */
|
||||
@%:@undef pid_t])
|
||||
m4trace:configure.ac:289: -1- AC_DEFINE_TRACE_LITERAL([size_t])
|
||||
m4trace:configure.ac:289: -1- m4_pattern_allow([^size_t$])
|
||||
m4trace:configure.ac:289: -1- AH_OUTPUT([size_t], [/* Define to `unsigned int\' if <sys/types.h> does not define. */
|
||||
@%:@undef size_t])
|
||||
m4trace:configure.ac:290: -1- AC_DEFINE_TRACE_LITERAL([TM_IN_SYS_TIME])
|
||||
m4trace:configure.ac:290: -1- m4_pattern_allow([^TM_IN_SYS_TIME$])
|
||||
m4trace:configure.ac:290: -1- AH_OUTPUT([TM_IN_SYS_TIME], [/* Define to 1 if your <sys/time.h> declares `struct tm\'. */
|
||||
@%:@undef TM_IN_SYS_TIME])
|
||||
m4trace:configure.ac:291: -1- AC_DEFINE_TRACE_LITERAL([HAVE__BOOL])
|
||||
m4trace:configure.ac:291: -1- m4_pattern_allow([^HAVE__BOOL$])
|
||||
m4trace:configure.ac:291: -1- AH_OUTPUT([HAVE__BOOL], [/* Define to 1 if the system has the type `_Bool\'. */
|
||||
@%:@undef HAVE__BOOL])
|
||||
m4trace:configure.ac:291: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STDBOOL_H])
|
||||
m4trace:configure.ac:291: -1- m4_pattern_allow([^HAVE_STDBOOL_H$])
|
||||
m4trace:configure.ac:291: -1- AH_OUTPUT([HAVE_STDBOOL_H], [/* Define to 1 if stdbool.h conforms to C99. */
|
||||
@%:@undef HAVE_STDBOOL_H])
|
||||
m4trace:configure.ac:294: -1- AC_DEFINE_TRACE_LITERAL([CLOSEDIR_VOID])
|
||||
m4trace:configure.ac:294: -1- m4_pattern_allow([^CLOSEDIR_VOID$])
|
||||
m4trace:configure.ac:294: -1- AH_OUTPUT([CLOSEDIR_VOID], [/* Define to 1 if the `closedir\' function returns void instead of `int\'. */
|
||||
@%:@undef CLOSEDIR_VOID])
|
||||
m4trace:configure.ac:295: -1- AH_OUTPUT([HAVE_VFORK_H], [/* Define to 1 if you have the <vfork.h> header file. */
|
||||
@%:@undef HAVE_VFORK_H])
|
||||
m4trace:configure.ac:295: -1- AC_DEFINE_TRACE_LITERAL([HAVE_VFORK_H])
|
||||
m4trace:configure.ac:295: -1- m4_pattern_allow([^HAVE_VFORK_H$])
|
||||
m4trace:configure.ac:295: -1- AH_OUTPUT([HAVE_FORK], [/* Define to 1 if you have the `fork\' function. */
|
||||
@%:@undef HAVE_FORK])
|
||||
m4trace:configure.ac:295: -1- AH_OUTPUT([HAVE_VFORK], [/* Define to 1 if you have the `vfork\' function. */
|
||||
@%:@undef HAVE_VFORK])
|
||||
m4trace:configure.ac:295: -1- AC_DEFINE_TRACE_LITERAL([HAVE_WORKING_VFORK])
|
||||
m4trace:configure.ac:295: -1- m4_pattern_allow([^HAVE_WORKING_VFORK$])
|
||||
m4trace:configure.ac:295: -1- AH_OUTPUT([HAVE_WORKING_VFORK], [/* Define to 1 if `vfork\' works. */
|
||||
@%:@undef HAVE_WORKING_VFORK])
|
||||
m4trace:configure.ac:295: -1- AC_DEFINE_TRACE_LITERAL([vfork])
|
||||
m4trace:configure.ac:295: -1- m4_pattern_allow([^vfork$])
|
||||
m4trace:configure.ac:295: -1- AH_OUTPUT([vfork], [/* Define as `fork\' if `vfork\' does not work. */
|
||||
@%:@undef vfork])
|
||||
m4trace:configure.ac:295: -1- AC_DEFINE_TRACE_LITERAL([HAVE_WORKING_FORK])
|
||||
m4trace:configure.ac:295: -1- m4_pattern_allow([^HAVE_WORKING_FORK$])
|
||||
m4trace:configure.ac:295: -1- AH_OUTPUT([HAVE_WORKING_FORK], [/* Define to 1 if `fork\' works. */
|
||||
@%:@undef HAVE_WORKING_FORK])
|
||||
m4trace:configure.ac:296: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
@%:@undef HAVE_STDLIB_H])
|
||||
m4trace:configure.ac:296: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STDLIB_H])
|
||||
m4trace:configure.ac:296: -1- m4_pattern_allow([^HAVE_STDLIB_H$])
|
||||
m4trace:configure.ac:296: -1- AC_DEFINE_TRACE_LITERAL([HAVE_MALLOC])
|
||||
m4trace:configure.ac:296: -1- m4_pattern_allow([^HAVE_MALLOC$])
|
||||
m4trace:configure.ac:296: -1- AH_OUTPUT([HAVE_MALLOC], [/* Define to 1 if your system has a GNU libc compatible `malloc\' function, and
|
||||
to 0 otherwise. */
|
||||
@%:@undef HAVE_MALLOC])
|
||||
m4trace:configure.ac:296: -1- AC_DEFINE_TRACE_LITERAL([HAVE_MALLOC])
|
||||
m4trace:configure.ac:296: -1- m4_pattern_allow([^HAVE_MALLOC$])
|
||||
m4trace:configure.ac:296: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS malloc.$ac_objext"])
|
||||
m4trace:configure.ac:296: -1- AC_SUBST_TRACE([LIB@&t@OBJS])
|
||||
m4trace:configure.ac:296: -1- m4_pattern_allow([^LIB@&t@OBJS$])
|
||||
m4trace:configure.ac:296: -1- AC_LIBSOURCE([malloc.c])
|
||||
m4trace:configure.ac:296: -1- AC_DEFINE_TRACE_LITERAL([malloc])
|
||||
m4trace:configure.ac:296: -1- m4_pattern_allow([^malloc$])
|
||||
m4trace:configure.ac:296: -1- AH_OUTPUT([malloc], [/* Define to rpl_malloc if the replacement function should be used. */
|
||||
@%:@undef malloc])
|
||||
m4trace:configure.ac:297: -1- AC_DEFINE_TRACE_LITERAL([TIME_WITH_SYS_TIME])
|
||||
m4trace:configure.ac:297: -1- m4_pattern_allow([^TIME_WITH_SYS_TIME$])
|
||||
m4trace:configure.ac:297: -1- AH_OUTPUT([TIME_WITH_SYS_TIME], [/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
|
||||
@%:@undef TIME_WITH_SYS_TIME])
|
||||
m4trace:configure.ac:297: -1- AH_OUTPUT([HAVE_SYS_TIME_H], [/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
@%:@undef HAVE_SYS_TIME_H])
|
||||
m4trace:configure.ac:297: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the <unistd.h> header file. */
|
||||
@%:@undef HAVE_UNISTD_H])
|
||||
m4trace:configure.ac:297: -1- AH_OUTPUT([HAVE_ALARM], [/* Define to 1 if you have the `alarm\' function. */
|
||||
@%:@undef HAVE_ALARM])
|
||||
m4trace:configure.ac:297: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS mktime.$ac_objext"])
|
||||
m4trace:configure.ac:297: -1- AC_SUBST_TRACE([LIB@&t@OBJS])
|
||||
m4trace:configure.ac:297: -1- m4_pattern_allow([^LIB@&t@OBJS$])
|
||||
m4trace:configure.ac:297: -1- AC_LIBSOURCE([mktime.c])
|
||||
m4trace:configure.ac:298: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
@%:@undef HAVE_STDLIB_H])
|
||||
m4trace:configure.ac:298: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STDLIB_H])
|
||||
m4trace:configure.ac:298: -1- m4_pattern_allow([^HAVE_STDLIB_H$])
|
||||
m4trace:configure.ac:298: -1- AC_DEFINE_TRACE_LITERAL([HAVE_REALLOC])
|
||||
m4trace:configure.ac:298: -1- m4_pattern_allow([^HAVE_REALLOC$])
|
||||
m4trace:configure.ac:298: -1- AH_OUTPUT([HAVE_REALLOC], [/* Define to 1 if your system has a GNU libc compatible `realloc\' function,
|
||||
and to 0 otherwise. */
|
||||
@%:@undef HAVE_REALLOC])
|
||||
m4trace:configure.ac:298: -1- AC_DEFINE_TRACE_LITERAL([HAVE_REALLOC])
|
||||
m4trace:configure.ac:298: -1- m4_pattern_allow([^HAVE_REALLOC$])
|
||||
m4trace:configure.ac:298: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS realloc.$ac_objext"])
|
||||
m4trace:configure.ac:298: -1- AC_SUBST_TRACE([LIB@&t@OBJS])
|
||||
m4trace:configure.ac:298: -1- m4_pattern_allow([^LIB@&t@OBJS$])
|
||||
m4trace:configure.ac:298: -1- AC_LIBSOURCE([realloc.c])
|
||||
m4trace:configure.ac:298: -1- AC_DEFINE_TRACE_LITERAL([realloc])
|
||||
m4trace:configure.ac:298: -1- m4_pattern_allow([^realloc$])
|
||||
m4trace:configure.ac:298: -1- AH_OUTPUT([realloc], [/* Define to rpl_realloc if the replacement function should be used. */
|
||||
@%:@undef realloc])
|
||||
m4trace:configure.ac:299: -1- AC_DEFINE_TRACE_LITERAL([LSTAT_FOLLOWS_SLASHED_SYMLINK])
|
||||
m4trace:configure.ac:299: -1- m4_pattern_allow([^LSTAT_FOLLOWS_SLASHED_SYMLINK$])
|
||||
m4trace:configure.ac:299: -1- AH_OUTPUT([LSTAT_FOLLOWS_SLASHED_SYMLINK], [/* Define to 1 if `lstat\' dereferences a symlink specified with a trailing
|
||||
slash. */
|
||||
@%:@undef LSTAT_FOLLOWS_SLASHED_SYMLINK])
|
||||
m4trace:configure.ac:299: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS lstat.$ac_objext"])
|
||||
m4trace:configure.ac:299: -1- AC_SUBST_TRACE([LIB@&t@OBJS])
|
||||
m4trace:configure.ac:299: -1- m4_pattern_allow([^LIB@&t@OBJS$])
|
||||
m4trace:configure.ac:299: -1- AC_LIBSOURCE([lstat.c])
|
||||
m4trace:configure.ac:299: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS stat.$ac_objext"])
|
||||
m4trace:configure.ac:299: -1- AC_SUBST_TRACE([LIB@&t@OBJS])
|
||||
m4trace:configure.ac:299: -1- m4_pattern_allow([^LIB@&t@OBJS$])
|
||||
m4trace:configure.ac:299: -1- AC_LIBSOURCE([stat.c])
|
||||
m4trace:configure.ac:299: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STAT_EMPTY_STRING_BUG])
|
||||
m4trace:configure.ac:299: -1- m4_pattern_allow([^HAVE_STAT_EMPTY_STRING_BUG$])
|
||||
m4trace:configure.ac:299: -1- AH_OUTPUT([HAVE_STAT_EMPTY_STRING_BUG], [/* Define to 1 if `stat\' has the bug that it succeeds when given the
|
||||
zero-length file name argument. */
|
||||
@%:@undef HAVE_STAT_EMPTY_STRING_BUG])
|
||||
m4trace:configure.ac:300: -1- AH_OUTPUT([HAVE_STRFTIME], [/* Define to 1 if you have the `strftime\' function. */
|
||||
@%:@undef HAVE_STRFTIME])
|
||||
m4trace:configure.ac:300: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRFTIME])
|
||||
m4trace:configure.ac:300: -1- m4_pattern_allow([^HAVE_STRFTIME$])
|
||||
m4trace:configure.ac:300: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRFTIME])
|
||||
m4trace:configure.ac:300: -1- m4_pattern_allow([^HAVE_STRFTIME$])
|
||||
m4trace:configure.ac:301: -1- AH_OUTPUT([HAVE_INET_NTOA], [/* Define to 1 if you have the `inet_ntoa\' function. */
|
||||
@%:@undef HAVE_INET_NTOA])
|
||||
m4trace:configure.ac:301: -1- AH_OUTPUT([HAVE_SOCKET], [/* Define to 1 if you have the `socket\' function. */
|
||||
@%:@undef HAVE_SOCKET])
|
||||
m4trace:configure.ac:301: -1- AH_OUTPUT([HAVE_STRCHR], [/* Define to 1 if you have the `strchr\' function. */
|
||||
@%:@undef HAVE_STRCHR])
|
||||
m4trace:configure.ac:301: -1- AH_OUTPUT([HAVE_STRDUP], [/* Define to 1 if you have the `strdup\' function. */
|
||||
@%:@undef HAVE_STRDUP])
|
||||
m4trace:configure.ac:301: -1- AH_OUTPUT([HAVE_STRERROR], [/* Define to 1 if you have the `strerror\' function. */
|
||||
@%:@undef HAVE_STRERROR])
|
||||
m4trace:configure.ac:301: -1- AH_OUTPUT([HAVE_STRRCHR], [/* Define to 1 if you have the `strrchr\' function. */
|
||||
@%:@undef HAVE_STRRCHR])
|
||||
m4trace:configure.ac:301: -1- AH_OUTPUT([HAVE_STRSTR], [/* Define to 1 if you have the `strstr\' function. */
|
||||
@%:@undef HAVE_STRSTR])
|
||||
m4trace:configure.ac:301: -1- AH_OUTPUT([HAVE_SCANDIR], [/* Define to 1 if you have the `scandir\' function. */
|
||||
@%:@undef HAVE_SCANDIR])
|
||||
m4trace:configure.ac:306: -1- AH_OUTPUT([HAVE_LIBRESOLV], [/* Define to 1 if you have the `resolv\' library (-lresolv). */
|
||||
@%:@undef HAVE_LIBRESOLV])
|
||||
m4trace:configure.ac:306: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBRESOLV])
|
||||
m4trace:configure.ac:306: -1- m4_pattern_allow([^HAVE_LIBRESOLV$])
|
||||
m4trace:configure.ac:306: -1- AH_OUTPUT([HAVE_LIBRESOLV], [/* Define to 1 if you have the `resolv\' library (-lresolv). */
|
||||
@%:@undef HAVE_LIBRESOLV])
|
||||
m4trace:configure.ac:306: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBRESOLV])
|
||||
m4trace:configure.ac:306: -1- m4_pattern_allow([^HAVE_LIBRESOLV$])
|
||||
m4trace:configure.ac:306: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBSOCKET])
|
||||
m4trace:configure.ac:306: -1- m4_pattern_allow([^HAVE_LIBSOCKET$])
|
||||
m4trace:configure.ac:306: -1- AH_OUTPUT([HAVE_LIBSOCKET], [/* */
|
||||
@%:@undef HAVE_LIBSOCKET])
|
||||
m4trace:configure.ac:306: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBRESOLV])
|
||||
m4trace:configure.ac:306: -1- m4_pattern_allow([^HAVE_LIBRESOLV$])
|
||||
m4trace:configure.ac:306: -1- AH_OUTPUT([HAVE_LIBRESOLV], [/* */
|
||||
@%:@undef HAVE_LIBRESOLV])
|
||||
m4trace:configure.ac:306: -1- AH_OUTPUT([HAVE_LIBRESOLV], [/* Define to 1 if you have the `resolv\' library (-lresolv). */
|
||||
@%:@undef HAVE_LIBRESOLV])
|
||||
m4trace:configure.ac:306: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBRESOLV])
|
||||
m4trace:configure.ac:306: -1- m4_pattern_allow([^HAVE_LIBRESOLV$])
|
||||
m4trace:configure.ac:306: -1- AH_OUTPUT([HAVE_LIBRESOLV], [/* Define to 1 if you have the `resolv\' library (-lresolv). */
|
||||
@%:@undef HAVE_LIBRESOLV])
|
||||
m4trace:configure.ac:306: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBRESOLV])
|
||||
m4trace:configure.ac:306: -1- m4_pattern_allow([^HAVE_LIBRESOLV$])
|
||||
m4trace:configure.ac:321: -1- AC_DEFINE_TRACE_LITERAL([ptrdiff_t])
|
||||
m4trace:configure.ac:321: -1- m4_pattern_allow([^ptrdiff_t$])
|
||||
m4trace:configure.ac:321: -1- AH_OUTPUT([ptrdiff_t], [/* Define to `long\' if <sys/types.h> does not define. */
|
||||
@%:@undef ptrdiff_t])
|
||||
m4trace:configure.ac:322: -1- AC_DEFINE_TRACE_LITERAL([size_t])
|
||||
m4trace:configure.ac:322: -1- m4_pattern_allow([^size_t$])
|
||||
m4trace:configure.ac:322: -1- AH_OUTPUT([size_t], [/* Define to `unsigned int\' if <sys/types.h> does not define. */
|
||||
@%:@undef size_t])
|
||||
m4trace:configure.ac:323: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_SHORT])
|
||||
m4trace:configure.ac:323: -1- m4_pattern_allow([^SIZEOF_SHORT$])
|
||||
m4trace:configure.ac:323: -1- AH_OUTPUT([SIZEOF_SHORT], [/* The size of `short\', as computed by sizeof. */
|
||||
@%:@undef SIZEOF_SHORT])
|
||||
m4trace:configure.ac:324: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_INT])
|
||||
m4trace:configure.ac:324: -1- m4_pattern_allow([^SIZEOF_INT$])
|
||||
m4trace:configure.ac:324: -1- AH_OUTPUT([SIZEOF_INT], [/* The size of `int\', as computed by sizeof. */
|
||||
@%:@undef SIZEOF_INT])
|
||||
m4trace:configure.ac:325: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_LONG])
|
||||
m4trace:configure.ac:325: -1- m4_pattern_allow([^SIZEOF_LONG$])
|
||||
m4trace:configure.ac:325: -1- AH_OUTPUT([SIZEOF_LONG], [/* The size of `long\', as computed by sizeof. */
|
||||
@%:@undef SIZEOF_LONG])
|
||||
m4trace:configure.ac:326: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_LONG_LONG])
|
||||
m4trace:configure.ac:326: -1- m4_pattern_allow([^SIZEOF_LONG_LONG$])
|
||||
m4trace:configure.ac:326: -1- AH_OUTPUT([SIZEOF_LONG_LONG], [/* The size of `long long\', as computed by sizeof. */
|
||||
@%:@undef SIZEOF_LONG_LONG])
|
||||
m4trace:configure.ac:327: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF___INT64])
|
||||
m4trace:configure.ac:327: -1- m4_pattern_allow([^SIZEOF___INT64$])
|
||||
m4trace:configure.ac:327: -1- AH_OUTPUT([SIZEOF___INT64], [/* The size of `__int64\', as computed by sizeof. */
|
||||
@%:@undef SIZEOF___INT64])
|
||||
m4trace:configure.ac:328: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_VOID_P])
|
||||
m4trace:configure.ac:328: -1- m4_pattern_allow([^SIZEOF_VOID_P$])
|
||||
m4trace:configure.ac:328: -1- AH_OUTPUT([SIZEOF_VOID_P], [/* The size of `void *\', as computed by sizeof. */
|
||||
@%:@undef SIZEOF_VOID_P])
|
||||
m4trace:configure.ac:329: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_SIZE_T])
|
||||
m4trace:configure.ac:329: -1- m4_pattern_allow([^SIZEOF_SIZE_T$])
|
||||
m4trace:configure.ac:329: -1- AH_OUTPUT([SIZEOF_SIZE_T], [/* The size of `size_t\', as computed by sizeof. */
|
||||
@%:@undef SIZEOF_SIZE_T])
|
||||
m4trace:configure.ac:330: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_PTRDIFF_T])
|
||||
m4trace:configure.ac:330: -1- m4_pattern_allow([^SIZEOF_PTRDIFF_T$])
|
||||
m4trace:configure.ac:330: -1- AH_OUTPUT([SIZEOF_PTRDIFF_T], [/* The size of `ptrdiff_t\', as computed by sizeof. */
|
||||
@%:@undef SIZEOF_PTRDIFF_T])
|
||||
m4trace:configure.ac:331: -1- AC_DEFINE_TRACE_LITERAL([const])
|
||||
m4trace:configure.ac:331: -1- m4_pattern_allow([^const$])
|
||||
m4trace:configure.ac:331: -1- AH_OUTPUT([const], [/* Define to empty if `const\' does not conform to ANSI C. */
|
||||
@%:@undef const])
|
||||
m4trace:configure.ac:332: -1- AH_OUTPUT([HAVE_MEMCMP], [/* Define to 1 if you have the `memcmp\' function. */
|
||||
@%:@undef HAVE_MEMCMP])
|
||||
m4trace:configure.ac:332: -1- AH_OUTPUT([HAVE_MEMCPY], [/* Define to 1 if you have the `memcpy\' function. */
|
||||
@%:@undef HAVE_MEMCPY])
|
||||
m4trace:configure.ac:332: -1- AH_OUTPUT([HAVE_MEMMOVE], [/* Define to 1 if you have the `memmove\' function. */
|
||||
@%:@undef HAVE_MEMMOVE])
|
||||
m4trace:configure.ac:332: -1- AH_OUTPUT([HAVE_MEMSET], [/* Define to 1 if you have the `memset\' function. */
|
||||
@%:@undef HAVE_MEMSET])
|
||||
m4trace:configure.ac:335: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete.
|
||||
You should run autoupdate.], [../../lib/autoconf/general.m4:2614: AC_TRY_COMPILE is expanded from...
|
||||
../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from...
|
||||
../../lib/autoconf/general.m4:2031: AC_CACHE_VAL is expanded from...
|
||||
configure.ac:335: the top level])
|
||||
m4trace:configure.ac:353: -1- AC_DEFINE_TRACE_LITERAL([HAVE_SEMUN])
|
||||
m4trace:configure.ac:353: -1- m4_pattern_allow([^HAVE_SEMUN$])
|
||||
m4trace:configure.ac:353: -1- AH_OUTPUT([HAVE_SEMUN], [/* Define if sys/sem.h defines struct semun */
|
||||
@%:@undef HAVE_SEMUN])
|
||||
m4trace:configure.ac:357: -1- _m4_warn([obsolete], [The macro `AC_TRY_RUN' is obsolete.
|
||||
You should run autoupdate.], [../../lib/autoconf/general.m4:2764: AC_TRY_RUN is expanded from...
|
||||
configure.ac:357: the top level])
|
||||
m4trace:configure.ac:357: -1- AC_DEFINE_TRACE_LITERAL([HAVE_SIZE_T_Z_FORMAT])
|
||||
m4trace:configure.ac:357: -1- m4_pattern_allow([^HAVE_SIZE_T_Z_FORMAT$])
|
||||
m4trace:configure.ac:357: -1- AH_OUTPUT([HAVE_SIZE_T_Z_FORMAT], [/* Define to 1 if you have a printf() that supports the %z format string. */
|
||||
@%:@undef HAVE_SIZE_T_Z_FORMAT])
|
||||
m4trace:configure.ac:386: -1- AC_CONFIG_FILES([Makefile bin/Makefile man/Makefile])
|
||||
m4trace:configure.ac:386: -1- _m4_warn([obsolete], [AC_OUTPUT should be used without arguments.
|
||||
You should run autoupdate.], [])
|
||||
m4trace:configure.ac:386: -1- AC_SUBST([LIB@&t@OBJS], [$ac_libobjs])
|
||||
m4trace:configure.ac:386: -1- AC_SUBST_TRACE([LIB@&t@OBJS])
|
||||
m4trace:configure.ac:386: -1- m4_pattern_allow([^LIB@&t@OBJS$])
|
||||
m4trace:configure.ac:386: -1- AC_SUBST([LTLIBOBJS], [$ac_ltlibobjs])
|
||||
m4trace:configure.ac:386: -1- AC_SUBST_TRACE([LTLIBOBJS])
|
||||
m4trace:configure.ac:386: -1- m4_pattern_allow([^LTLIBOBJS$])
|
||||
m4trace:configure.ac:386: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])
|
||||
m4trace:configure.ac:386: -1- AC_SUBST([am__EXEEXT_TRUE])
|
||||
m4trace:configure.ac:386: -1- AC_SUBST_TRACE([am__EXEEXT_TRUE])
|
||||
m4trace:configure.ac:386: -1- m4_pattern_allow([^am__EXEEXT_TRUE$])
|
||||
m4trace:configure.ac:386: -1- AC_SUBST([am__EXEEXT_FALSE])
|
||||
m4trace:configure.ac:386: -1- AC_SUBST_TRACE([am__EXEEXT_FALSE])
|
||||
m4trace:configure.ac:386: -1- m4_pattern_allow([^am__EXEEXT_FALSE$])
|
||||
m4trace:configure.ac:386: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE])
|
||||
m4trace:configure.ac:386: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE])
|
||||
m4trace:configure.ac:386: -1- AC_SUBST_TRACE([top_builddir])
|
||||
m4trace:configure.ac:386: -1- AC_SUBST_TRACE([top_build_prefix])
|
||||
m4trace:configure.ac:386: -1- AC_SUBST_TRACE([srcdir])
|
||||
m4trace:configure.ac:386: -1- AC_SUBST_TRACE([abs_srcdir])
|
||||
m4trace:configure.ac:386: -1- AC_SUBST_TRACE([top_srcdir])
|
||||
m4trace:configure.ac:386: -1- AC_SUBST_TRACE([abs_top_srcdir])
|
||||
m4trace:configure.ac:386: -1- AC_SUBST_TRACE([builddir])
|
||||
m4trace:configure.ac:386: -1- AC_SUBST_TRACE([abs_builddir])
|
||||
m4trace:configure.ac:386: -1- AC_SUBST_TRACE([abs_top_builddir])
|
||||
m4trace:configure.ac:386: -1- AC_SUBST_TRACE([INSTALL])
|
||||
m4trace:configure.ac:386: -1- AC_SUBST_TRACE([MKDIR_P])
|
11
bin/AddExtension.txt
Executable file
11
bin/AddExtension.txt
Executable file
@ -0,0 +1,11 @@
|
||||
Add extensions:
|
||||
===============
|
||||
|
||||
1. Add appropriate definitions for new extension in nffile.h
|
||||
2. Update extension_descriptor array in nfx.c to reflect the new extension.
|
||||
Increase user index ( 3rd value )
|
||||
3. Add filter in grammar.y
|
||||
4. test filter with nftest.
|
||||
5. nffile_inline.c
|
||||
6. nf_common.c define printing functions
|
||||
7. nfsta.c add stat definitions
|
130
bin/Makefile.am
Executable file
130
bin/Makefile.am
Executable file
@ -0,0 +1,130 @@
|
||||
|
||||
bin_PROGRAMS = nfcapd nfdump nfreplay nfexpire nfanon
|
||||
EXTRA_PROGRAMS = nftest nfgen nfreader
|
||||
|
||||
check_PROGRAMMS = test.sh
|
||||
TESTS = nftest test.sh
|
||||
|
||||
if SFLOW
|
||||
bin_PROGRAMS += sfcapd
|
||||
endif
|
||||
|
||||
if NFPROFILE
|
||||
bin_PROGRAMS += nfprofile
|
||||
endif
|
||||
|
||||
if NFTRACK
|
||||
bin_PROGRAMS += nftrack
|
||||
endif
|
||||
|
||||
if FT2NFDUMP
|
||||
bin_PROGRAMS += ft2nfdump
|
||||
endif
|
||||
|
||||
BUILT_SOURCES = grammar.h
|
||||
AM_YFLAGS = -d
|
||||
|
||||
AM_CPPFLAGS = $(DEPS_CFLAGS)
|
||||
LDADD = $(DEPS_LIBS)
|
||||
|
||||
#Add extra debug info for gdb
|
||||
AM_CFLAGS = -ggdb
|
||||
|
||||
common = nf_common.c nf_common.h
|
||||
util = util.c util.h
|
||||
filelzo = minilzo.c minilzo.h lzoconf.h lzodefs.h nffile.c nffile.h nfx.c nfx.h nfxstat.h nfxstat.c
|
||||
nflist = flist.c flist.h fts_compat.c fts_compat.h
|
||||
filter = grammar.y scanner.l nftree.c nftree.h ipconv.c ipconv.h rbtree.h
|
||||
nfprof = nfprof.c nfprof.h
|
||||
nfnet = nfnet.c nfnet.h
|
||||
anon = panonymizer.c panonymizer.h rijndael.c rijndael.h
|
||||
collector = collector.c collector.h
|
||||
nfv1 = netflow_v1.c netflow_v1.h
|
||||
nfv9 = netflow_v9.c netflow_v9.h
|
||||
pcaproc = pcaproc.c pcaproc.h flowtree.c flowtree.h ipfrag.c ipfrag.h
|
||||
content = content_dns.c content_dns.h
|
||||
netflow_pcap = netflow_pcap.c netflow_pcap.h
|
||||
ipfix = ipfix.c ipfix.h
|
||||
nfv5v7 = netflow_v5_v7.c netflow_v5_v7.h
|
||||
nfstatfile = nfstatfile.c nfstatfile.h
|
||||
nflowcache = nflowcache.c nflowcache.h
|
||||
bookkeeper = bookkeeper.c bookkeeper.h
|
||||
exporter = exporter.c exporter.h
|
||||
expire= expire.c expire.h
|
||||
launch = launch.c launch.h
|
||||
|
||||
nfdump_SOURCES = nfdump.c nfdump.h nfstat.c nfstat.h nfexport.c nfexport.h \
|
||||
$(common) $(nflowcache) $(util) $(filelzo) $(nflist) $(filter) $(nfprof) $(exporter)
|
||||
|
||||
nfreplay_SOURCES = nfreplay.c \
|
||||
$(common) $(util) $(filelzo) $(nflist) $(filter) $(nfprof) \
|
||||
$(nfnet) $(collector) $(nfv1) $(nfv9) $(nfv5v7) $(ipfix) $(exporter)
|
||||
|
||||
nfprofile_SOURCES = nfprofile.c profile.c profile.h \
|
||||
$(common) $(util) $(filelzo) $(nflist) $(filter) $(nfstatfile) $(exporter)
|
||||
nfprofile_LDADD = -lrrd
|
||||
|
||||
nftrack_SOURCES = ../extra/nftrack/nftrack.c \
|
||||
../extra/nftrack/nftrack_rrd.c ../extra/nftrack/nftrack_rrd.h \
|
||||
../extra/nftrack/nftrack_stat.c ../extra/nftrack/nftrack_stat.h \
|
||||
$(common) $(util) $(filelzo) $(nflist) $(filter)
|
||||
nftrack_CFLAGS = -I ../extra/nftrack
|
||||
nftrack_LDADD = -lrrd
|
||||
|
||||
nfcapd_SOURCES = nfcapd.c \
|
||||
$(common) $(util) $(filelzo) $(nflist) $(nfstatfile) $(launch) \
|
||||
$(nfnet) $(collector) $(nfv1) $(nfv5v7) $(nfv9) $(ipfix) $(bookkeeper) $(expire)
|
||||
|
||||
nfpcapd_SOURCES = nfpcapd.c \
|
||||
$(pcaproc) $(netflow_pcap) \
|
||||
$(common) $(util) $(filelzo) $(nflist) $(nfstatfile) $(launch) \
|
||||
$(nfnet) $(collector) $(bookkeeper) $(expire) $(content)
|
||||
|
||||
if READPCAP
|
||||
nfcapd_CFLAGS = -DPCAP
|
||||
nfcapd_SOURCES += pcap_reader.c pcap_reader.h
|
||||
nfcapd_LDADD = -lpcap
|
||||
endif
|
||||
|
||||
if BUILDNFPCAPD
|
||||
bin_PROGRAMS += nfpcapd
|
||||
nfpcapd_CFLAGS = -D_BSD_SOURCE
|
||||
nfpcapd_LDADD = -lpcap
|
||||
nfpcapd_LDFLAGS = -pthread
|
||||
endif
|
||||
|
||||
sfcapd_SOURCES = sfcapd.c sflow.c sflow.h sflow_proto.h \
|
||||
$(common) $(util) $(filelzo) $(nflist) $(nfstatfile) $(launch) \
|
||||
$(nfnet) $(collector) $(bookkeeper) $(expire)
|
||||
|
||||
if READPCAP
|
||||
sfcapd_CFLAGS = -DPCAP
|
||||
sfcapd_SOURCES += pcap_reader.c pcap_reader.h
|
||||
sfcapd_LDADD = -lpcap
|
||||
endif
|
||||
|
||||
nfreader_SOURCES = nfreader.c \
|
||||
$(util) $(filelzo) $(nflist) $(exporter)
|
||||
|
||||
nfanon_SOURCES = nfanon.c \
|
||||
$(util) $(filelzo) $(nflist) $(anon)
|
||||
|
||||
nfgen_SOURCES = nfgen.c $(util) $(filelzo) $(nflist)
|
||||
|
||||
nfexpire_SOURCES = nfexpire.c \
|
||||
$(bookkeeper) $(expire) $(util) $(nfstatfile)
|
||||
nfexpire_LDADD = @FTS_OBJ@
|
||||
|
||||
nftest_SOURCES = nftest.c $(common) $(util) $(filter) $(filelzo)
|
||||
nftest_DEPENDENCIES = nfgen
|
||||
|
||||
if FT2NFDUMP
|
||||
ft2nfdump_SOURCES = ft2nfdump.c $(common) $(filelzo) $(util)
|
||||
ft2nfdump_CFLAGS = @FT_INCLUDES@
|
||||
ft2nfdump_LDADD = -lft -lz
|
||||
ft2nfdump_LDADD += @FT_LDFLAGS@
|
||||
endif
|
||||
|
||||
EXTRA_DIST = inline.c collector_inline.c nffile_inline.c nfdump_inline.c heapsort_inline.c applybits_inline.c test.sh nfdump.test.out parse_csv.pl
|
||||
|
||||
CLEANFILES = lex.yy.c grammar.c grammar.h scanner.c scanner.h
|
2549
bin/Makefile.in
Normal file
2549
bin/Makefile.in
Normal file
File diff suppressed because it is too large
Load Diff
92
bin/applybits_inline.c
Executable file
92
bin/applybits_inline.c
Executable file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: applybits_inline.c 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
static inline void ApplyNetMaskBits(master_record_t *flow_record, int apply_netbits);
|
||||
|
||||
static inline void ApplyNetMaskBits(master_record_t *flow_record, int apply_netbits) {
|
||||
|
||||
if ( (flow_record->flags & FLAG_IPV6_ADDR ) != 0 ) { // IPv6
|
||||
if ( apply_netbits & 1 ) {
|
||||
uint64_t mask;
|
||||
uint32_t mask_bits = flow_record->src_mask;
|
||||
if ( mask_bits > 64 ) {
|
||||
mask = 0xffffffffffffffffLL << ( 128 - mask_bits );
|
||||
flow_record->v6.srcaddr[1] &= mask;
|
||||
} else {
|
||||
mask = 0xffffffffffffffffLL << ( 64 - mask_bits );
|
||||
flow_record->v6.srcaddr[0] &= mask;
|
||||
flow_record->v6.srcaddr[1] = 0;
|
||||
}
|
||||
}
|
||||
if ( apply_netbits & 2 ) {
|
||||
uint64_t mask;
|
||||
uint32_t mask_bits = flow_record->dst_mask;
|
||||
|
||||
if ( mask_bits > 64 ) {
|
||||
mask = 0xffffffffffffffffLL << ( 128 - mask_bits );
|
||||
flow_record->v6.dstaddr[1] &= mask;
|
||||
} else {
|
||||
mask = 0xffffffffffffffffLL << ( 64 - mask_bits );
|
||||
flow_record->v6.dstaddr[0] &= mask;
|
||||
flow_record->v6.dstaddr[1] = 0;
|
||||
}
|
||||
}
|
||||
} else { // IPv4
|
||||
if ( apply_netbits & 1 ) {
|
||||
uint32_t srcmask = 0xffffffff << ( 32 - flow_record->src_mask );
|
||||
flow_record->v4.srcaddr &= srcmask;
|
||||
}
|
||||
if ( apply_netbits & 2 ) {
|
||||
uint32_t dstmask = 0xffffffff << ( 32 - flow_record->dst_mask );
|
||||
flow_record->v4.dstaddr &= dstmask;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of ApplyNetMaskBits
|
||||
|
||||
static inline void ApplyAggrMask(master_record_t *record, master_record_t *mask) {
|
||||
uint64_t *r = (uint64_t *)record;
|
||||
uint64_t *m = (uint64_t *)mask;
|
||||
int i, max_offset;
|
||||
|
||||
max_offset = offsetof(master_record_t, map_ref) >> 3;
|
||||
for (i=2; i<max_offset; i++) {
|
||||
r[i] &= m[i];
|
||||
}
|
||||
|
||||
} // End of ApplyAggrMask
|
619
bin/bookkeeper.c
Normal file
619
bin/bookkeeper.c
Normal file
@ -0,0 +1,619 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: bookkeeper.c 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/sem.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SEMUN
|
||||
union semun {
|
||||
int val; // value for SETVAL
|
||||
struct semid_ds *buf; // buffer for IPC_STAT & IPC_SET
|
||||
u_short *array; // array for GETALL & SETALL
|
||||
};
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "bookkeeper.h"
|
||||
|
||||
static bookkeeper_list_t *bookkeeper_list = NULL;
|
||||
|
||||
/* function prototypes */
|
||||
|
||||
/*
|
||||
* bookkeeper.c is needed for daemon code as well as normal stdio code
|
||||
* therefore a generic LogError is defined, which maps to the
|
||||
* approriate logging channel - either stderr or syslog
|
||||
*/
|
||||
void LogError(char *format, ...);
|
||||
|
||||
static key_t _ftok(const char *path, int id);
|
||||
|
||||
static void sem_lock(int sem_set_id);
|
||||
|
||||
static void sem_unlock(int sem_set_id);
|
||||
|
||||
static inline bookkeeper_list_t *Get_bookkeeper_list_entry(bookkeeper_t *bookkeeper);
|
||||
|
||||
/* Create shared memory object and set its size */
|
||||
|
||||
/* our own ftok implementation - the standard C library ftok is not reliable enough */
|
||||
static key_t _ftok(const char *path, int id) {
|
||||
struct stat st;
|
||||
|
||||
if (stat(path, &st) < 0)
|
||||
return (key_t)-1;
|
||||
|
||||
return (key_t) ( ((st.st_dev & 0xffff) << 16) ^ st.st_ino ) + id;
|
||||
}
|
||||
|
||||
|
||||
// locks the semaphore, for exclusive access to the bookkeeping record
|
||||
static void sem_lock(int sem_set_id) {
|
||||
struct sembuf sem_op;
|
||||
|
||||
/* wait on the semaphore, unless it's value is non-negative. */
|
||||
sem_op.sem_num = 0;
|
||||
sem_op.sem_op = -1;
|
||||
sem_op.sem_flg = 0;
|
||||
if ( semop(sem_set_id, &sem_op, 1) == 0 )
|
||||
return;
|
||||
|
||||
LogError("semop() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
|
||||
} // End of sem_lock
|
||||
|
||||
// sem_unlock. un-locks the semaphore.
|
||||
static void sem_unlock(int sem_set_id) {
|
||||
struct sembuf sem_op;
|
||||
|
||||
/* signal the semaphore - increase its value by one. */
|
||||
sem_op.sem_num = 0;
|
||||
sem_op.sem_op = 1;
|
||||
sem_op.sem_flg = 0;
|
||||
if ( semop(sem_set_id, &sem_op, 1) == 0 )
|
||||
return;
|
||||
|
||||
LogError("semop() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
|
||||
} // End of sem_unlock
|
||||
|
||||
static inline bookkeeper_list_t *Get_bookkeeper_list_entry(bookkeeper_t *bookkeeper) {
|
||||
bookkeeper_list_t *bookkeeper_list_entry;
|
||||
|
||||
if ( bookkeeper == NULL )
|
||||
return NULL;
|
||||
|
||||
bookkeeper_list_entry = bookkeeper_list;
|
||||
while ( bookkeeper_list_entry != NULL && bookkeeper_list_entry->bookkeeper != bookkeeper )
|
||||
bookkeeper_list_entry = bookkeeper_list_entry->next;
|
||||
|
||||
return bookkeeper_list_entry;
|
||||
|
||||
} // End of Get_bookkeeper_list_entry
|
||||
|
||||
int InitBookkeeper(bookkeeper_t **bookkeeper, char *path, pid_t nfcapd_pid, pid_t launcher_pid) {
|
||||
int sem_key, shm_key, shm_id, sem_id;
|
||||
union semun sem_val;
|
||||
bookkeeper_list_t **bookkeeper_list_entry;
|
||||
|
||||
*bookkeeper = NULL;
|
||||
|
||||
shm_key = _ftok(path, 1);
|
||||
if ( shm_key == - 1 )
|
||||
return ERR_PATHACCESS;
|
||||
|
||||
// check if the shared memory is already allocated
|
||||
shm_id = shmget(shm_key, sizeof(bookkeeper_t), 0600);
|
||||
|
||||
if ( shm_id >= 0 ) {
|
||||
// the segment already exists. Either a running process is active
|
||||
// or an unclean shutdown happened
|
||||
|
||||
// map the segement and check the record
|
||||
*bookkeeper = (bookkeeper_t *)shmat(shm_id, NULL, 0);
|
||||
if ( *bookkeeper == (bookkeeper_t *)-1 ) {
|
||||
LogError("shmat() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
return ERR_FAILED;
|
||||
}
|
||||
if ( (*bookkeeper)->nfcapd_pid <= 0 ) {
|
||||
// rubbish or invalid pid of nfcapd process.
|
||||
// Assume unclean shutdown or something else. We clean up and take this record.
|
||||
memset((void *)(*bookkeeper), 0, sizeof(bookkeeper_t));
|
||||
} else {
|
||||
// check if the process created this record is still alive
|
||||
int ret = kill((*bookkeeper)->nfcapd_pid, 0);
|
||||
if ( ret == - 1 ) {
|
||||
switch (errno) {
|
||||
case ESRCH:
|
||||
// process does not exist, we can clean up this record and use it
|
||||
memset((void *)(*bookkeeper), 0, sizeof(bookkeeper_t));
|
||||
break;
|
||||
case EPERM:
|
||||
// A process exists, but we are not allowed to signal this process
|
||||
LogError("Another collector with pid %i but different user ID is already running, and configured for '%s'",
|
||||
(*bookkeeper)->nfcapd_pid, path);
|
||||
return ERR_EXISTS;
|
||||
break;
|
||||
default:
|
||||
// This should never happen, but catch it anyway
|
||||
LogError("semop() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
return ERR_FAILED;
|
||||
}
|
||||
} else {
|
||||
// process exists;
|
||||
LogError("Another collector with pid %i is already running, and configured for '%s'",
|
||||
(*bookkeeper)->nfcapd_pid, path);
|
||||
return ERR_EXISTS;
|
||||
}
|
||||
// if we pass this point, we have recycled an existing record
|
||||
|
||||
}
|
||||
} else {
|
||||
// no valid shared segment was found
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
// this is ok - no shared segemtn exists, we can create a new one below
|
||||
break;
|
||||
case EACCES:
|
||||
// there is such a segment, but we are not allowed to get it
|
||||
// Assume it's another nfcapd
|
||||
LogError("Access denied to collector bookkeeping record.");
|
||||
return ERR_EXISTS;
|
||||
break;
|
||||
default:
|
||||
// This should never happen, but catch it anyway
|
||||
LogError("semop() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
return ERR_FAILED;
|
||||
}
|
||||
// we now create a new segement, this hould not fail now
|
||||
shm_id = shmget(shm_key, sizeof(bookkeeper_t), IPC_CREAT | 0600);
|
||||
if ( shm_id == - 1 ) {
|
||||
// but did anyway - give up
|
||||
LogError("shmget() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
return ERR_FAILED;
|
||||
}
|
||||
*bookkeeper = (bookkeeper_t *)shmat(shm_id, NULL, 0);
|
||||
if ( (*bookkeeper) == (bookkeeper_t *)-1 ) {
|
||||
LogError("shmget() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
return ERR_FAILED;
|
||||
}
|
||||
memset((void *)(*bookkeeper), 0, sizeof(bookkeeper_t));
|
||||
}
|
||||
// at this point we now have a valid record and can proceed
|
||||
(*bookkeeper)->nfcapd_pid = nfcapd_pid;
|
||||
(*bookkeeper)->launcher_pid = launcher_pid;
|
||||
(*bookkeeper)->sequence++;
|
||||
|
||||
// create semaphore
|
||||
|
||||
sem_key = _ftok(path, 2);
|
||||
// this should never fail, as we aleady got a key for the shared memory
|
||||
if ( sem_key == - 1 ) {
|
||||
// .. but catch it anyway .. and release shared memory. something is fishy
|
||||
struct shmid_ds buf;
|
||||
shmdt((void *)(*bookkeeper));
|
||||
shmctl(shm_id, IPC_RMID, &buf);
|
||||
return ERR_FAILED;
|
||||
}
|
||||
|
||||
// get the semaphore
|
||||
sem_id = semget(sem_key, 1, IPC_CREAT | 0600);
|
||||
if ( sem_id == - 1 ) {
|
||||
struct shmid_ds buf;
|
||||
|
||||
// this should not have failed
|
||||
LogError("semget() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
|
||||
// release shared memory
|
||||
shmdt((void *)(*bookkeeper));
|
||||
shmctl(shm_id, IPC_RMID, &buf);
|
||||
return ERR_FAILED;
|
||||
}
|
||||
|
||||
// initialize the semaphore
|
||||
sem_val.val = 1;
|
||||
if ( semctl(sem_id, 0, SETVAL, sem_val) == -1) {
|
||||
struct shmid_ds buf;
|
||||
|
||||
// this should not have failed
|
||||
LogError("semctl() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
|
||||
// release shared memory
|
||||
shmdt((void *)(*bookkeeper));
|
||||
shmctl(shm_id, IPC_RMID, &buf);
|
||||
return ERR_FAILED;
|
||||
}
|
||||
|
||||
bookkeeper_list_entry = &bookkeeper_list;
|
||||
while ( *bookkeeper_list_entry != NULL )
|
||||
bookkeeper_list_entry = &((*bookkeeper_list_entry)->next);
|
||||
|
||||
(*bookkeeper_list_entry) = (bookkeeper_list_t *)malloc(sizeof(bookkeeper_list_t));
|
||||
if ( !*bookkeeper_list_entry ) {
|
||||
struct shmid_ds buf;
|
||||
|
||||
LogError("malloc() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
shmdt((void *)(*bookkeeper));
|
||||
shmctl(shm_id, IPC_RMID, &buf);
|
||||
semctl( sem_id, 0, IPC_RMID );
|
||||
return ERR_FAILED;
|
||||
}
|
||||
memset((void *)*bookkeeper_list_entry, 0, sizeof(bookkeeper_list_t));
|
||||
|
||||
(*bookkeeper_list_entry)->shm_id = shm_id;
|
||||
(*bookkeeper_list_entry)->sem_id = sem_id;
|
||||
(*bookkeeper_list_entry)->bookkeeper = *bookkeeper;
|
||||
(*bookkeeper_list_entry)->next = NULL;
|
||||
|
||||
// we are done
|
||||
return BOOKKEEPER_OK;
|
||||
|
||||
} // End of InitBookkeeper
|
||||
|
||||
int AccessBookkeeper(bookkeeper_t **bookkeeper, char *path) {
|
||||
bookkeeper_list_t **bookkeeper_list_entry;
|
||||
int sem_key, shm_key, shm_id, sem_id;
|
||||
|
||||
*bookkeeper = NULL;
|
||||
|
||||
shm_key = _ftok(path, 1);
|
||||
if ( shm_key == - 1 )
|
||||
return ERR_PATHACCESS;
|
||||
|
||||
// check if the shared memory is already allocated
|
||||
shm_id = shmget(shm_key, sizeof(bookkeeper_t), 0600);
|
||||
|
||||
if ( shm_id < 0 ) {
|
||||
// the segment does not exists. Check why
|
||||
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
// no shared segemtn exists.
|
||||
return ERR_NOTEXISTS;
|
||||
break;
|
||||
case EACCES:
|
||||
// there is such a segment, but we are not allowed to get it
|
||||
// Assume it's another nfcapd
|
||||
LogError("Access denied to collector bookkeeping record.");
|
||||
return ERR_FAILED;
|
||||
break;
|
||||
default:
|
||||
// This should never happen, but catch it anyway
|
||||
LogError("semop() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
return ERR_FAILED;
|
||||
}
|
||||
// not reached
|
||||
}
|
||||
// at this point we now have a valid record and can proceed
|
||||
|
||||
// create semaphore
|
||||
sem_key = _ftok(path, 2);
|
||||
// this should never fail, as we aleady got a key for the shared memory
|
||||
if ( sem_key == - 1 ) {
|
||||
// .. but catch it anyway .. and release shared memory. something is fishy
|
||||
return ERR_FAILED;
|
||||
}
|
||||
|
||||
// get the semaphore
|
||||
sem_id = semget(sem_key, 1, 0600);
|
||||
if ( sem_id == - 1 ) {
|
||||
// this should not have failed
|
||||
LogError("semget() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
|
||||
return ERR_FAILED;
|
||||
}
|
||||
|
||||
// map the shared segment
|
||||
*bookkeeper = (bookkeeper_t *)shmat(shm_id, NULL, 0);
|
||||
if ( *bookkeeper == (bookkeeper_t *)-1 ) {
|
||||
LogError("shmat() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
return ERR_FAILED;
|
||||
}
|
||||
|
||||
bookkeeper_list_entry = &bookkeeper_list;
|
||||
while ( *bookkeeper_list_entry != NULL && (*bookkeeper_list_entry)->bookkeeper != NULL )
|
||||
bookkeeper_list_entry = &((*bookkeeper_list_entry)->next);
|
||||
|
||||
// allocate new slot, else use unused slot
|
||||
if ( *bookkeeper_list_entry == NULL ) {
|
||||
(*bookkeeper_list_entry) = (bookkeeper_list_t *)malloc(sizeof(bookkeeper_list_t));
|
||||
if ( !*bookkeeper_list_entry ) {
|
||||
LogError("malloc() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
return ERR_FAILED;
|
||||
}
|
||||
memset((void *)*bookkeeper_list_entry, 0, sizeof(bookkeeper_list_t));
|
||||
}
|
||||
|
||||
(*bookkeeper_list_entry)->shm_id = shm_id;
|
||||
(*bookkeeper_list_entry)->sem_id = sem_id;
|
||||
(*bookkeeper_list_entry)->bookkeeper = *bookkeeper;
|
||||
(*bookkeeper_list_entry)->next = NULL;
|
||||
|
||||
return BOOKKEEPER_OK;
|
||||
|
||||
|
||||
} // End of AccessBookkeeper
|
||||
|
||||
void ReleaseBookkeeper(bookkeeper_t *bookkeeper, int destroy) {
|
||||
bookkeeper_list_t *bookkeeper_list_entry;
|
||||
struct shmid_ds buf;
|
||||
|
||||
if ( !bookkeeper )
|
||||
return;
|
||||
|
||||
bookkeeper_list_entry = Get_bookkeeper_list_entry(bookkeeper);
|
||||
if ( !bookkeeper_list_entry ) {
|
||||
// this should never happen
|
||||
LogError("Software error in %s line %d: %s", __FILE__, __LINE__, "Entry not found in list");
|
||||
return;
|
||||
}
|
||||
|
||||
// detach from my process addr space memory
|
||||
if ( shmdt((void *)bookkeeper) == -1 ) {
|
||||
// ups ..
|
||||
LogError("shmdt() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
}
|
||||
bookkeeper = NULL;
|
||||
|
||||
if ( destroy == 0 ) {
|
||||
// Entry no longer valid
|
||||
bookkeeper_list_entry->bookkeeper = NULL;
|
||||
bookkeeper_list_entry->shm_id = 0;
|
||||
bookkeeper_list_entry->sem_id = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// prevent other proceeses to access the share memory, while we are removing it
|
||||
// try to clean up.
|
||||
sem_lock(bookkeeper_list_entry->sem_id);
|
||||
if ( shmctl(bookkeeper_list_entry->shm_id, IPC_RMID, &buf) ) {
|
||||
// ups ..
|
||||
LogError("shmctl() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
}
|
||||
sem_unlock(bookkeeper_list_entry->sem_id);
|
||||
|
||||
if ( semctl( bookkeeper_list_entry->sem_id, 0, IPC_RMID ) == -1 ) {
|
||||
// ups ..
|
||||
LogError("semctl() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
}
|
||||
|
||||
// Entry no longer valid
|
||||
bookkeeper_list_entry->bookkeeper = NULL;
|
||||
bookkeeper_list_entry->shm_id = 0;
|
||||
bookkeeper_list_entry->sem_id = 0;
|
||||
|
||||
|
||||
} // End of ReleaseBookkeeper
|
||||
|
||||
int LookBooks(bookkeeper_t *bookkeeper) {
|
||||
bookkeeper_list_t *bookkeeper_list_entry;
|
||||
|
||||
if ( !bookkeeper )
|
||||
return 0;
|
||||
|
||||
bookkeeper_list_entry = Get_bookkeeper_list_entry(bookkeeper);
|
||||
if ( !bookkeeper_list_entry ) {
|
||||
// this should never happen
|
||||
LogError("Software error in %s line %d: %s", __FILE__, __LINE__, "Entry not found in list");
|
||||
return 1;
|
||||
}
|
||||
|
||||
sem_lock(bookkeeper_list_entry->sem_id);
|
||||
|
||||
return 0;
|
||||
|
||||
} // End of LookBooks
|
||||
|
||||
int UnlookBooks(bookkeeper_t *bookkeeper) {
|
||||
bookkeeper_list_t *bookkeeper_list_entry;
|
||||
|
||||
if ( !bookkeeper )
|
||||
return 0;
|
||||
|
||||
bookkeeper_list_entry = Get_bookkeeper_list_entry(bookkeeper);
|
||||
if ( !bookkeeper_list_entry ) {
|
||||
// this should never happen
|
||||
LogError("Software error in %s line %d: %s", __FILE__, __LINE__, "Entry not found in list");
|
||||
return 1;
|
||||
}
|
||||
|
||||
sem_unlock(bookkeeper_list_entry->sem_id);
|
||||
|
||||
return 0;
|
||||
|
||||
} // End of UnlookBooks
|
||||
|
||||
void ClearBooks(bookkeeper_t *bookkeeper, bookkeeper_t *tmp_books) {
|
||||
bookkeeper_list_t *bookkeeper_list_entry;
|
||||
|
||||
if ( !bookkeeper )
|
||||
return;
|
||||
|
||||
bookkeeper_list_entry = Get_bookkeeper_list_entry(bookkeeper);
|
||||
if ( !bookkeeper_list_entry ) {
|
||||
// this should never happen
|
||||
LogError("Software error in %s line %d: %s", __FILE__, __LINE__, "Entry not found in list");
|
||||
return;
|
||||
}
|
||||
|
||||
sem_lock(bookkeeper_list_entry->sem_id);
|
||||
// backup copy
|
||||
if ( tmp_books != NULL ) {
|
||||
memcpy((void *)tmp_books, (void *)bookkeeper, sizeof(bookkeeper_t));
|
||||
}
|
||||
bookkeeper->first = 0;
|
||||
bookkeeper->last = 0;
|
||||
bookkeeper->numfiles = 0;
|
||||
bookkeeper->filesize = 0;
|
||||
bookkeeper->sequence++;
|
||||
sem_unlock(bookkeeper_list_entry->sem_id);
|
||||
|
||||
} // End of ClearBooks
|
||||
|
||||
uint64_t BookSequence(bookkeeper_t *bookkeeper) {
|
||||
bookkeeper_list_t *bookkeeper_list_entry;
|
||||
uint64_t seq;
|
||||
|
||||
if ( !bookkeeper )
|
||||
return 0;
|
||||
|
||||
bookkeeper_list_entry = Get_bookkeeper_list_entry(bookkeeper);
|
||||
if ( !bookkeeper_list_entry ) {
|
||||
// this should never happen
|
||||
LogError("Software error in %s line %d: %s", __FILE__, __LINE__, "Entry not found in list");
|
||||
return 0;
|
||||
}
|
||||
|
||||
sem_lock(bookkeeper_list_entry->sem_id);
|
||||
seq = bookkeeper->sequence;
|
||||
sem_unlock(bookkeeper_list_entry->sem_id);
|
||||
|
||||
return seq;
|
||||
|
||||
} // End of BookSequence
|
||||
|
||||
void UpdateBooks(bookkeeper_t *bookkeeper, time_t when, uint64_t size) {
|
||||
bookkeeper_list_t *bookkeeper_list_entry;
|
||||
|
||||
if ( !bookkeeper )
|
||||
return;
|
||||
|
||||
bookkeeper_list_entry = Get_bookkeeper_list_entry(bookkeeper);
|
||||
if ( !bookkeeper_list_entry ) {
|
||||
// this should never happen
|
||||
LogError("Software error in %s line %d: %s", __FILE__, __LINE__, "Entry not found in list");
|
||||
return;
|
||||
}
|
||||
|
||||
sem_lock(bookkeeper_list_entry->sem_id);
|
||||
if ( bookkeeper->first == 0 )
|
||||
bookkeeper->first = when;
|
||||
|
||||
bookkeeper->last = when;
|
||||
bookkeeper->numfiles++;
|
||||
bookkeeper->filesize += size;
|
||||
bookkeeper->sequence++;
|
||||
sem_unlock(bookkeeper_list_entry->sem_id);
|
||||
|
||||
} // End of UpdateBooks
|
||||
|
||||
void UpdateBooksParam(bookkeeper_t *bookkeeper, time_t lifetime, uint64_t maxsize) {
|
||||
bookkeeper_list_t *bookkeeper_list_entry;
|
||||
|
||||
if ( !bookkeeper )
|
||||
return;
|
||||
|
||||
bookkeeper_list_entry = Get_bookkeeper_list_entry(bookkeeper);
|
||||
if ( !bookkeeper_list_entry ) {
|
||||
// this should never happen
|
||||
LogError("Software error in %s line %d: %s", __FILE__, __LINE__, "Entry not found in list");
|
||||
return;
|
||||
}
|
||||
|
||||
sem_lock(bookkeeper_list_entry->sem_id);
|
||||
bookkeeper->max_lifetime = lifetime;
|
||||
bookkeeper->max_filesize = maxsize;
|
||||
bookkeeper->sequence++;
|
||||
sem_unlock(bookkeeper_list_entry->sem_id);
|
||||
|
||||
} // End of UpdateBooksParam
|
||||
|
||||
void PrintBooks(bookkeeper_t *bookkeeper) {
|
||||
bookkeeper_list_t *bookkeeper_list_entry;
|
||||
struct tm *ts;
|
||||
time_t t;
|
||||
char string[32];
|
||||
|
||||
if ( !bookkeeper ) {
|
||||
printf("No bookkeeper record available!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bookkeeper_list_entry = Get_bookkeeper_list_entry(bookkeeper);
|
||||
if ( !bookkeeper_list_entry ) {
|
||||
// this should never happen
|
||||
LogError("Software error in %s line %d: %s", __FILE__, __LINE__, "Entry not found in list");
|
||||
return;
|
||||
}
|
||||
|
||||
sem_lock(bookkeeper_list_entry->sem_id);
|
||||
printf("Collector process: %lu\n", (unsigned long)bookkeeper->nfcapd_pid);
|
||||
if ( bookkeeper->launcher_pid )
|
||||
printf("Launcher process: %lu\n", (unsigned long)bookkeeper->launcher_pid);
|
||||
else
|
||||
printf("Launcher process: <none>\n");
|
||||
printf("Record sequence : %llu\n", (unsigned long long)bookkeeper->sequence);
|
||||
|
||||
t = bookkeeper->first;
|
||||
ts = localtime(&t);
|
||||
strftime(string, 31, "%Y-%m-%d %H:%M:%S", ts);
|
||||
string[31] = '\0';
|
||||
printf("First : %s\n", bookkeeper->first ? string : "<not set>");
|
||||
|
||||
t = bookkeeper->last;
|
||||
ts = localtime(&t);
|
||||
strftime(string, 31, "%Y-%m-%d %H:%M:%S", ts);
|
||||
string[31] = '\0';
|
||||
printf("Last : %s\n", bookkeeper->last ? string : "<not set>");
|
||||
printf("Number of files : %llu\n", (unsigned long long)bookkeeper->numfiles);
|
||||
printf("Total file size : %llu\n", (unsigned long long)bookkeeper->filesize);
|
||||
printf("Max file size : %llu\n", (unsigned long long)bookkeeper->max_filesize);
|
||||
printf("Max life time : %llu\n", (unsigned long long)bookkeeper->max_lifetime);
|
||||
sem_unlock(bookkeeper_list_entry->sem_id);
|
||||
|
||||
} // End of PrintBooks
|
||||
|
100
bin/bookkeeper.h
Normal file
100
bin/bookkeeper.h
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: bookkeeper.h 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _BOOKKEEPER_H
|
||||
#define _BOOKKEEPER_H 1
|
||||
|
||||
enum { BOOKKEEPER_OK = 0, ERR_FAILED, ERR_NOTEXISTS, ERR_PATHACCESS, ERR_EXISTS };
|
||||
|
||||
#define DETACH_ONLY 0
|
||||
#define DESTROY_BOOKKEEPER 1
|
||||
|
||||
typedef struct bookkeeper_s {
|
||||
// collector infos
|
||||
pid_t nfcapd_pid;
|
||||
pid_t launcher_pid;
|
||||
|
||||
// track info
|
||||
uint64_t sequence;
|
||||
|
||||
// file infos
|
||||
time_t first;
|
||||
time_t last;
|
||||
uint64_t numfiles;
|
||||
uint64_t filesize;
|
||||
uint64_t max_filesize;
|
||||
uint64_t max_lifetime;
|
||||
|
||||
|
||||
} bookkeeper_t;
|
||||
|
||||
// All bookkeepers are put into a linked list, to have all the shm_id,sem_id
|
||||
typedef struct bookkeeper_list_s {
|
||||
struct bookkeeper_list_s *next;
|
||||
|
||||
bookkeeper_t *bookkeeper;
|
||||
|
||||
// shared parameters
|
||||
int sem_id;
|
||||
int shm_id;
|
||||
|
||||
} bookkeeper_list_t;
|
||||
|
||||
/* function prototypes */
|
||||
int InitBookkeeper(bookkeeper_t **bookkeeper, char *path, pid_t nfcapd_pid, pid_t launcher_pid);
|
||||
|
||||
int AccessBookkeeper(bookkeeper_t **bookkeeper, char *path);
|
||||
|
||||
void ReleaseBookkeeper(bookkeeper_t *bookkeeper, int destroy);
|
||||
|
||||
void ClearBooks(bookkeeper_t *bookkeeper, bookkeeper_t *tmp_books);
|
||||
|
||||
int LookBooks(bookkeeper_t *bookkeeper);
|
||||
|
||||
int UnlookBooks(bookkeeper_t *bookkeeper);
|
||||
|
||||
uint64_t BookSequence(bookkeeper_t *bookkeeper);
|
||||
|
||||
void UpdateBooks(bookkeeper_t *bookkeeper, time_t when, uint64_t size);
|
||||
|
||||
void UpdateBooksParam(bookkeeper_t *bookkeeper, time_t lifetime, uint64_t maxsize);
|
||||
|
||||
void PrintBooks(bookkeeper_t *bookkeeper);
|
||||
|
||||
#endif //_BOOKKEEPER_H
|
676
bin/collector.c
Executable file
676
bin/collector.c
Executable file
@ -0,0 +1,676 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: collector.c 69 2010-09-09 07:17:43Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 69 $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/param.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <syslog.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifndef DEVEL
|
||||
# define dbg_printf(...) /* printf(__VA_ARGS__) */
|
||||
#else
|
||||
# define dbg_printf(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
#include "nf_common.h"
|
||||
#include "nffile.h"
|
||||
#include "nfxstat.h"
|
||||
#include "bookkeeper.h"
|
||||
#include "collector.h"
|
||||
#include "nfx.h"
|
||||
|
||||
#include "nffile_inline.c"
|
||||
|
||||
/* globals */
|
||||
uint32_t default_sampling = 1;
|
||||
uint32_t overwrite_sampling = 0;
|
||||
|
||||
/* local variables */
|
||||
static uint32_t exporter_sysid = 0;
|
||||
static char *DynamicSourcesDir = NULL;
|
||||
|
||||
/* local prototypes */
|
||||
static uint32_t AssignExporterID(void);
|
||||
|
||||
/* local functions */
|
||||
static uint32_t AssignExporterID(void) {
|
||||
|
||||
if ( exporter_sysid >= 0xFFFF ) {
|
||||
LogError("Too many exporters (id > 65535). Flow records collected but without reference to exporter");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ++exporter_sysid;
|
||||
|
||||
} // End of AssignExporterID
|
||||
|
||||
/* global functions */
|
||||
|
||||
int SetDynamicSourcesDir(FlowSource_t **FlowSource, char *dir) {
|
||||
|
||||
if ( *FlowSource )
|
||||
return 0;
|
||||
|
||||
DynamicSourcesDir = dir;
|
||||
return 1;
|
||||
|
||||
} // End of SetDynamicSourcesDir
|
||||
|
||||
int AddFlowSource(FlowSource_t **FlowSource, char *ident) {
|
||||
FlowSource_t **source;
|
||||
struct stat fstat;
|
||||
char *p, *q, s[MAXPATHLEN];
|
||||
int has_any_source = 0;
|
||||
int ok;
|
||||
|
||||
if ( DynamicSourcesDir )
|
||||
return 0;
|
||||
|
||||
source = FlowSource;
|
||||
while ( *source ) {
|
||||
has_any_source |= (*source)->any_source;
|
||||
source = &((*source)->next);
|
||||
}
|
||||
if ( has_any_source ) {
|
||||
fprintf(stderr, "Ambiguous idents not allowed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
*source = (FlowSource_t *)calloc(1, sizeof(FlowSource_t));
|
||||
if ( !*source ) {
|
||||
LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return 0;
|
||||
}
|
||||
(*source)->next = NULL;
|
||||
(*source)->bookkeeper = NULL;
|
||||
(*source)->any_source = 0;
|
||||
(*source)->exporter_data = NULL;
|
||||
(*source)->xstat = NULL;
|
||||
(*FlowSource)->exporter_count = 0;
|
||||
|
||||
// separate IP address from ident
|
||||
if ( ( p = strchr(ident, ',')) == NULL ) {
|
||||
fprintf(stderr, "Syntax error for netflow source definition. Expect -n ident,IP,path\n");
|
||||
return 0;
|
||||
}
|
||||
*p++ = '\0';
|
||||
|
||||
// separate path from IP
|
||||
if ( ( q = strchr(p, ',')) == NULL ) {
|
||||
fprintf(stderr, "Syntax error for netflow source definition. Expect -n ident,IP,path\n");
|
||||
return 0;
|
||||
}
|
||||
*q++ = '\0';
|
||||
|
||||
if ( strchr(p, ':') != NULL ) {
|
||||
uint64_t _ip[2];
|
||||
ok = inet_pton(PF_INET6, p, _ip);
|
||||
(*source)->sa_family = PF_INET6;
|
||||
(*source)->ip.v6[0] = ntohll(_ip[0]);
|
||||
(*source)->ip.v6[1] = ntohll(_ip[1]);
|
||||
} else {
|
||||
uint32_t _ip;
|
||||
ok = inet_pton(PF_INET, p, &_ip);
|
||||
(*source)->sa_family = PF_INET;
|
||||
(*source)->ip.v6[0] = 0;
|
||||
(*source)->ip.v6[1] = 0;
|
||||
(*source)->ip.v4 = ntohl(_ip);
|
||||
}
|
||||
switch (ok) {
|
||||
case 0:
|
||||
fprintf(stderr, "Unparsable IP address: %s\n", p);
|
||||
return 0;
|
||||
case 1:
|
||||
// success
|
||||
break;
|
||||
case -1:
|
||||
fprintf(stderr, "Error while parsing IP address: %s\n", strerror(errno));
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// fill in ident
|
||||
if ( strlen(ident) >= IDENTLEN ) {
|
||||
fprintf(stderr, "Source identifier too long: %s\n", ident);
|
||||
return 0;
|
||||
}
|
||||
if ( strchr(ident, ' ') ) {
|
||||
fprintf(stderr,"Illegal characters in ident %s\n", ident);
|
||||
exit(255);
|
||||
}
|
||||
strncpy((*source)->Ident, ident, IDENTLEN-1 );
|
||||
(*source)->Ident[IDENTLEN-1] = '\0';
|
||||
|
||||
if ( strlen(q) >= MAXPATHLEN ) {
|
||||
fprintf(stderr,"Path too long: %s\n", q);
|
||||
exit(255);
|
||||
}
|
||||
|
||||
// check for existing path
|
||||
if ( stat(q, &fstat) ) {
|
||||
fprintf(stderr, "stat() error %s: %s\n", q, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
if ( !(fstat.st_mode & S_IFDIR) ) {
|
||||
fprintf(stderr, "No such directory: %s\n", q);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// remember path
|
||||
(*source)->datadir = strdup(q);
|
||||
if ( !(*source)->datadir ) {
|
||||
fprintf(stderr, "strdup() error: %s\n", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// cache current collector file
|
||||
if ( snprintf(s, MAXPATHLEN-1, "%s/%s.%lu", (*source)->datadir , NF_DUMPFILE, (unsigned long)getpid() ) >= (MAXPATHLEN-1)) {
|
||||
fprintf(stderr, "Path too long: %s\n", q);
|
||||
return 0;
|
||||
}
|
||||
(*source)->current = strdup(s);
|
||||
if ( !(*source)->current ) {
|
||||
fprintf(stderr, "strdup() error: %s\n", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
} // End of AddFlowSource
|
||||
|
||||
int AddDefaultFlowSource(FlowSource_t **FlowSource, char *ident, char *path) {
|
||||
struct stat fstat;
|
||||
char s[MAXPATHLEN];
|
||||
|
||||
if ( DynamicSourcesDir )
|
||||
return 0;
|
||||
|
||||
*FlowSource = (FlowSource_t *)calloc(1,sizeof(FlowSource_t));
|
||||
if ( !*FlowSource ) {
|
||||
fprintf(stderr, "calloc() allocation error: %s\n", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
(*FlowSource)->next = NULL;
|
||||
(*FlowSource)->bookkeeper = NULL;
|
||||
(*FlowSource)->any_source = 1;
|
||||
(*FlowSource)->exporter_data = NULL;
|
||||
(*FlowSource)->xstat = NULL;
|
||||
(*FlowSource)->exporter_count = 0;
|
||||
|
||||
// fill in ident
|
||||
if ( strlen(ident) >= IDENTLEN ) {
|
||||
fprintf(stderr, "Source identifier too long: %s\n", ident);
|
||||
return 0;
|
||||
}
|
||||
if ( strchr(ident, ' ') ) {
|
||||
fprintf(stderr,"Illegal characters in ident %s\n", ident);
|
||||
return 0;
|
||||
}
|
||||
strncpy((*FlowSource)->Ident, ident, IDENTLEN-1 );
|
||||
(*FlowSource)->Ident[IDENTLEN-1] = '\0';
|
||||
|
||||
if ( strlen(path) >= MAXPATHLEN ) {
|
||||
fprintf(stderr,"Path too long: %s\n",path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check for existing path
|
||||
if ( stat(path, &fstat) ) {
|
||||
fprintf(stderr, "stat() error %s: %s\n", path, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
if ( !(fstat.st_mode & S_IFDIR) ) {
|
||||
fprintf(stderr, "No such directory: %s\n", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// remember path
|
||||
(*FlowSource)->datadir = strdup(path);
|
||||
if ( !(*FlowSource)->datadir ) {
|
||||
fprintf(stderr, "strdup() error: %s\n", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// cache current collector file
|
||||
if ( snprintf(s, MAXPATHLEN-1, "%s/%s.%lu", (*FlowSource)->datadir , NF_DUMPFILE, (unsigned long)getpid() ) >= (MAXPATHLEN-1)) {
|
||||
fprintf(stderr, "Path too long: %s\n", path);
|
||||
return 0;
|
||||
}
|
||||
(*FlowSource)->current = strdup(s);
|
||||
if ( !(*FlowSource)->current ) {
|
||||
fprintf(stderr, "strdup() error: %s\n", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
} // End of AddDefaultFlowSource
|
||||
|
||||
FlowSource_t *AddDynamicSource(FlowSource_t **FlowSource, struct sockaddr_storage *ss) {
|
||||
FlowSource_t **source;
|
||||
void *ptr;
|
||||
char *s, ident[100], path[MAXPATHLEN];
|
||||
int err;
|
||||
|
||||
union {
|
||||
struct sockaddr_storage *ss;
|
||||
struct sockaddr *sa;
|
||||
struct sockaddr_in *sa_in;
|
||||
struct sockaddr_in6 *sa_in6;
|
||||
} u;
|
||||
u.ss = ss;
|
||||
|
||||
if ( !DynamicSourcesDir )
|
||||
return NULL;
|
||||
|
||||
source = FlowSource;
|
||||
while ( *source ) {
|
||||
source = &((*source)->next);
|
||||
}
|
||||
|
||||
*source = (FlowSource_t *)calloc(1, sizeof(FlowSource_t));
|
||||
if ( !*source ) {
|
||||
LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return NULL;
|
||||
}
|
||||
(*source)->next = NULL;
|
||||
(*source)->bookkeeper = NULL;
|
||||
(*source)->any_source = 0;
|
||||
(*source)->exporter_data = NULL;
|
||||
(*source)->xstat = NULL;
|
||||
(*FlowSource)->exporter_count = 0;
|
||||
|
||||
switch (ss->ss_family) {
|
||||
case PF_INET: {
|
||||
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
|
||||
if (ss->ss_len != sizeof(struct sockaddr_in) ) {
|
||||
// malformed struct
|
||||
LogError("Malformed IPv4 socket struct in '%s', line '%d'", __FILE__, __LINE__ );
|
||||
free(*source);
|
||||
*source = NULL;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
(*source)->sa_family = PF_INET;
|
||||
(*source)->ip.v6[0] = 0;
|
||||
(*source)->ip.v6[1] = 0;
|
||||
(*source)->ip.v4 = ntohl(u.sa_in->sin_addr.s_addr);
|
||||
ptr = &u.sa_in->sin_addr;
|
||||
} break;
|
||||
case PF_INET6: {
|
||||
uint64_t *ip_ptr = (uint64_t *)u.sa_in6->sin6_addr.s6_addr;
|
||||
|
||||
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
|
||||
if (ss->ss_len != sizeof(struct sockaddr_in6) ) {
|
||||
// malformed struct
|
||||
LogError("Malformed IPv6 socket struct in '%s', line '%d'", __FILE__, __LINE__ );
|
||||
free(*source);
|
||||
*source = NULL;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
// ptr = &((struct sockaddr_in6 *)sa)->sin6_addr;
|
||||
(*source)->sa_family = PF_INET6;
|
||||
(*source)->ip.v6[0] = ntohll(ip_ptr[0]);
|
||||
(*source)->ip.v6[1] = ntohll(ip_ptr[1]);
|
||||
ptr = &u.sa_in6->sin6_addr;
|
||||
} break;
|
||||
default:
|
||||
// keep compiler happy
|
||||
(*source)->ip.v6[0] = 0;
|
||||
(*source)->ip.v6[1] = 0;
|
||||
ptr = NULL;
|
||||
|
||||
LogError("Unknown sa fanily: %d in '%s', line '%d'", ss->ss_family, __FILE__, __LINE__ );
|
||||
free(*source);
|
||||
*source = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( !ptr ) {
|
||||
free(*source);
|
||||
*source = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inet_ntop(ss->ss_family, ptr, ident, sizeof(ident));
|
||||
ident[99] = '\0';
|
||||
dbg_printf("Dynamic Flow Source IP: %s\n", ident);
|
||||
|
||||
if ( strchr(ident, ':') ) { // condense IPv6 addresses
|
||||
condense_v6(ident);
|
||||
}
|
||||
|
||||
s = ident;
|
||||
while ( *s != '\0' ) {
|
||||
if ( *s == '.' || *s == ':' )
|
||||
*s = '-';
|
||||
s++;
|
||||
}
|
||||
dbg_printf("Dynamic Flow Source ident: %s\n", ident);
|
||||
|
||||
strncpy((*source)->Ident, ident, IDENTLEN-1 );
|
||||
(*source)->Ident[IDENTLEN-1] = '\0';
|
||||
|
||||
snprintf(path, MAXPATHLEN-1, "%s/%s", DynamicSourcesDir, ident);
|
||||
path[MAXPATHLEN-1] = '\0';
|
||||
|
||||
err = mkdir(path, 0755);
|
||||
if ( err != 0 && errno != EEXIST ) {
|
||||
LogError("mkdir() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
free(*source);
|
||||
*source = NULL;
|
||||
return NULL;
|
||||
}
|
||||
(*source)->datadir = strdup(path);
|
||||
|
||||
if ( snprintf(path, MAXPATHLEN-1, "%s/%s.%lu", (*source)->datadir, NF_DUMPFILE, (unsigned long)getpid() ) >= (MAXPATHLEN-1)) {
|
||||
fprintf(stderr, "Path too long: %s\n", path);
|
||||
free(*source);
|
||||
*source = NULL;
|
||||
return NULL;
|
||||
}
|
||||
(*source)->current = strdup(path);
|
||||
|
||||
LogInfo("Dynamically add source ident: %s in directory: %s", ident, path);
|
||||
return *source;
|
||||
|
||||
} // End of AddDynamicSource
|
||||
|
||||
int InitExtensionMapList(FlowSource_t *fs) {
|
||||
|
||||
fs->extension_map_list.maps = (extension_map_t **)calloc(BLOCK_SIZE, sizeof(extension_map_t *));
|
||||
if ( !fs->extension_map_list.maps ) {
|
||||
LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return 0;
|
||||
}
|
||||
fs->extension_map_list.max_maps = BLOCK_SIZE;
|
||||
fs->extension_map_list.next_free = 0;
|
||||
fs->extension_map_list.num_maps = 0;
|
||||
|
||||
return 1;
|
||||
|
||||
} // End of InitExtensionMapList
|
||||
|
||||
int ReInitExtensionMapList(FlowSource_t *fs) {
|
||||
|
||||
dbg_printf("Flush all extension maps!\n");
|
||||
free(fs->extension_map_list.maps);
|
||||
fs->extension_map_list.maps = NULL;
|
||||
|
||||
return InitExtensionMapList(fs);
|
||||
|
||||
} // End of ReInitExtensionMapList
|
||||
|
||||
int RemoveExtensionMap(FlowSource_t *fs, extension_map_t *map) {
|
||||
int slot = map->map_id;
|
||||
|
||||
dbg_printf("Remove extension map ID: %d\n", slot);
|
||||
if ( slot >= fs->extension_map_list.max_maps ) {
|
||||
// XXX hmm .. is simply return correct ///
|
||||
LogError("*** software error *** Try to remove extension map %d, while only %d slots are available\n", slot, fs->extension_map_list.max_maps);
|
||||
return 0;
|
||||
}
|
||||
fs->extension_map_list.maps[slot] = NULL;
|
||||
|
||||
return 1;
|
||||
|
||||
} // End of RemoveExtensionMap
|
||||
|
||||
int AddExtensionMap(FlowSource_t *fs, extension_map_t *map) {
|
||||
int next_slot = fs->extension_map_list.next_free;
|
||||
|
||||
dbg_printf("Add extension map\n");
|
||||
// is it a new map, we have not yet in the list
|
||||
if ( map->map_id == INIT_ID ) {
|
||||
if ( next_slot >= fs->extension_map_list.max_maps ) {
|
||||
// extend map list
|
||||
dbg_printf("List full - extend extension list to %d slots\n", fs->extension_map_list.max_maps + BLOCK_SIZE);
|
||||
extension_map_t **p = realloc((void *)fs->extension_map_list.maps,
|
||||
(fs->extension_map_list.max_maps + BLOCK_SIZE ) * sizeof(extension_map_t *));
|
||||
if ( !p ) {
|
||||
LogError("realloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return 0;
|
||||
}
|
||||
fs->extension_map_list.maps = p;
|
||||
fs->extension_map_list.max_maps += BLOCK_SIZE;
|
||||
}
|
||||
|
||||
dbg_printf("Add map to slot %d\n", next_slot);
|
||||
fs->extension_map_list.maps[next_slot] = map;
|
||||
map->map_id = next_slot;
|
||||
fs->extension_map_list.num_maps++;
|
||||
|
||||
if ( (next_slot + 1) == fs->extension_map_list.num_maps ) {
|
||||
// sequencially filled slots
|
||||
// next free is next slot
|
||||
fs->extension_map_list.next_free++;
|
||||
dbg_printf("Next slot is sequential: %d\n", fs->extension_map_list.next_free);
|
||||
} else {
|
||||
// fill gap in list - search for next free
|
||||
int i;
|
||||
dbg_printf("Search next slot ... \n");
|
||||
for ( i = (next_slot + 1); i < fs->extension_map_list.max_maps; i++ ) {
|
||||
if ( fs->extension_map_list.maps[i] == NULL ) {
|
||||
// empty slot found
|
||||
dbg_printf("Empty slot found at %d\n", i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// assign next_free - if none found up to max, the list will get extended
|
||||
// in the next round
|
||||
dbg_printf("Set next free to %d\n", i);
|
||||
fs->extension_map_list.next_free = i;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
AppendToBuffer(fs->nffile, (void *)map, map->size);
|
||||
|
||||
return 1;
|
||||
|
||||
} // End of AddExtensionMap
|
||||
|
||||
int FlushInfoExporter(FlowSource_t *fs, exporter_info_record_t *exporter) {
|
||||
|
||||
exporter->sysid = AssignExporterID();
|
||||
fs->exporter_count++;
|
||||
AppendToBuffer(fs->nffile, (void *)exporter, exporter->header.size);
|
||||
|
||||
#ifdef DEVEL
|
||||
{
|
||||
#define IP_STRING_LEN 40
|
||||
char ipstr[IP_STRING_LEN];
|
||||
printf("Flush Exporter: ");
|
||||
if ( exporter->sa_family == AF_INET ) {
|
||||
uint32_t _ip = htonl(exporter->ip.v4);
|
||||
inet_ntop(AF_INET, &_ip, ipstr, sizeof(ipstr));
|
||||
printf("SysID: %u, IP: %16s, version: %u, ID: %2u\n", exporter->sysid,
|
||||
ipstr, exporter->version, exporter->id);
|
||||
} else if ( exporter->sa_family == AF_INET6 ) {
|
||||
uint64_t _ip[2];
|
||||
_ip[0] = htonll(exporter->ip.v6[0]);
|
||||
_ip[1] = htonll(exporter->ip.v6[1]);
|
||||
inet_ntop(AF_INET6, &_ip, ipstr, sizeof(ipstr));
|
||||
printf("SysID: %u, IP: %40s, version: %u, ID: %2u\n", exporter->sysid,
|
||||
ipstr, exporter->version, exporter->id);
|
||||
} else {
|
||||
strncpy(ipstr, "<unknown>", IP_STRING_LEN);
|
||||
printf("**** Exporter IP version unknown ****\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
|
||||
} // End of FlushInfoExporter
|
||||
|
||||
int FlushInfoSampler(FlowSource_t *fs, sampler_info_record_t *sampler) {
|
||||
|
||||
AppendToBuffer(fs->nffile, (void *)sampler, sampler->header.size);
|
||||
|
||||
#ifdef DEVEL
|
||||
{
|
||||
printf("Flush Sampler: ");
|
||||
if ( sampler->id < 0 ) {
|
||||
printf("Exporter SysID: %u, Generic Sampler: mode: %u, interval: %u\n",
|
||||
sampler->exporter_sysid, sampler->mode, sampler->interval);
|
||||
} else {
|
||||
printf("Exporter SysID: %u, Sampler: id: %i, mode: %u, interval: %u\n",
|
||||
sampler->exporter_sysid, sampler->id, sampler->mode, sampler->interval);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
|
||||
} // End of FlushInfoSampler
|
||||
|
||||
void FlushStdRecords(FlowSource_t *fs) {
|
||||
generic_exporter_t *e = fs->exporter_data;
|
||||
int i;
|
||||
|
||||
while ( e ) {
|
||||
generic_sampler_t *sampler = e->sampler;
|
||||
AppendToBuffer(fs->nffile, (void *)&(e->info), e->info.header.size);
|
||||
while ( sampler ) {
|
||||
AppendToBuffer(fs->nffile, (void *)&(sampler->info), sampler->info.header.size);
|
||||
sampler = sampler->next;
|
||||
}
|
||||
e = e->next;
|
||||
}
|
||||
|
||||
for ( i=0; i<fs->extension_map_list.next_free; i++ ) {
|
||||
extension_map_t *map = fs->extension_map_list.maps[i];
|
||||
if ( map )
|
||||
AppendToBuffer(fs->nffile, (void *)map, map->size);
|
||||
}
|
||||
|
||||
} // End of FlushStdRecords
|
||||
|
||||
void FlushExporterStats(FlowSource_t *fs) {
|
||||
generic_exporter_t *e = fs->exporter_data;
|
||||
exporter_stats_record_t *exporter_stats;
|
||||
uint32_t i, size;
|
||||
|
||||
// idle collector ..
|
||||
if ( !fs->exporter_count )
|
||||
return;
|
||||
|
||||
size = sizeof(exporter_stats_record_t) + (fs->exporter_count -1) * sizeof(struct exporter_stat_s);
|
||||
exporter_stats = ( exporter_stats_record_t *)malloc(size);
|
||||
if ( !exporter_stats ) {
|
||||
LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return;
|
||||
}
|
||||
exporter_stats->header.type = ExporterStatRecordType;
|
||||
exporter_stats->header.size = size;
|
||||
exporter_stats->stat_count = fs->exporter_count;
|
||||
|
||||
#ifdef DEVEL
|
||||
printf("Flush Exporter Stats: %u exporters, size: %u\n", fs->exporter_count, size);
|
||||
#endif
|
||||
i = 0;
|
||||
while ( e ) {
|
||||
// prevent memory corruption - just in case .. should not happen anyway
|
||||
// continue loop for error reporting after while
|
||||
if ( i >= fs->exporter_count ) {
|
||||
i++;
|
||||
e = e->next;
|
||||
continue;
|
||||
}
|
||||
exporter_stats->stat[i].sysid = e->info.sysid;
|
||||
exporter_stats->stat[i].sequence_failure = e->sequence_failure;
|
||||
exporter_stats->stat[i].packets = e->packets;
|
||||
exporter_stats->stat[i].flows = e->flows;
|
||||
#ifdef DEVEL
|
||||
printf("Stat: SysID: %u, version: %u, ID: %2u, Packets: %llu, Flows: %llu, Sequence Failures: %u\n", e->info.sysid,
|
||||
e->info.version, e->info.id, e->packets, e->flows, e->sequence_failure);
|
||||
|
||||
#endif
|
||||
// reset counters
|
||||
e->sequence_failure = 0;
|
||||
e->packets = 0;
|
||||
e->flows = 0;
|
||||
|
||||
i++;
|
||||
e = e->next;
|
||||
}
|
||||
AppendToBuffer(fs->nffile, (void *)exporter_stats, size);
|
||||
free(exporter_stats);
|
||||
|
||||
if ( i != fs->exporter_count ) {
|
||||
LogError("ERROR: exporter stats: Expected %u records, but found %u in %s line %d: %s\n",
|
||||
fs->exporter_count, i, __FILE__, __LINE__, strerror(errno) );
|
||||
}
|
||||
|
||||
} // End of FlushExporterStats
|
||||
|
||||
|
||||
|
||||
int HasOptionTable(FlowSource_t *fs, uint16_t id ) {
|
||||
option_offset_t *t;
|
||||
|
||||
t = fs->option_offset_table;
|
||||
while ( t && t->id != id )
|
||||
t = t->next;
|
||||
|
||||
dbg_printf("Has option table: %s\n", t == NULL ? "not found" : "found");
|
||||
|
||||
return t != NULL;
|
||||
|
||||
} // End of HasOptionTable
|
184
bin/collector.h
Executable file
184
bin/collector.h
Executable file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: collector.h 51 2010-01-29 09:01:54Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 51 $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _COLLECTOR_H
|
||||
#define _COLLECTOR_H 1
|
||||
|
||||
#define FNAME_SIZE 256
|
||||
#define IDENT_SIZE 32
|
||||
|
||||
typedef struct srecord_s {
|
||||
char fname[FNAME_SIZE]; // file name
|
||||
char subdir[FNAME_SIZE]; // subdir name
|
||||
char tstring[16]; // actually 12 needed e.g. 200411011230
|
||||
time_t tstamp; // UNIX time stamp
|
||||
int failed; // in case of an error
|
||||
} srecord_t;
|
||||
|
||||
// common_record_t defines ext_map as uint_8, so max 256 extension maps allowed.
|
||||
// should be enough anyway
|
||||
|
||||
|
||||
typedef struct option_offset_s {
|
||||
struct option_offset_s *next;
|
||||
uint32_t id; // table id
|
||||
uint32_t flags; // info about this map
|
||||
|
||||
// sampling offsets
|
||||
#define HAS_SAMPLER_DATA 1
|
||||
uint16_t offset_id;
|
||||
uint16_t sampler_id_length;
|
||||
uint16_t offset_mode;
|
||||
uint16_t offset_interval;
|
||||
|
||||
#define HAS_STD_SAMPLER_DATA 2
|
||||
uint16_t offset_std_sampler_interval;
|
||||
uint16_t offset_std_sampler_algorithm;
|
||||
|
||||
} option_offset_t;
|
||||
|
||||
typedef struct generic_sampler_s {
|
||||
struct generic_sampler_s *next;
|
||||
sampler_info_record_t info;
|
||||
} generic_sampler_t;
|
||||
|
||||
typedef struct generic_exporter_s {
|
||||
// link chain
|
||||
struct generic_exporter_s *next;
|
||||
|
||||
// generic exporter information
|
||||
exporter_info_record_t info;
|
||||
|
||||
uint64_t packets; // number of packets sent by this exporter
|
||||
uint64_t flows; // number of flow records sent by this exporter
|
||||
uint32_t sequence_failure; // number of sequence failues
|
||||
|
||||
generic_sampler_t *sampler;
|
||||
|
||||
} generic_exporter_t;
|
||||
|
||||
typedef struct FlowSource_s {
|
||||
// link
|
||||
struct FlowSource_s *next;
|
||||
|
||||
// exporter identifiers
|
||||
char Ident[IDENTLEN];
|
||||
ip_addr_t ip;
|
||||
uint32_t sa_family;
|
||||
|
||||
int any_source;
|
||||
bookkeeper_t *bookkeeper;
|
||||
|
||||
// all about data storage
|
||||
char *datadir; // where to store data for this source
|
||||
char *current; // current file name - typically nfcad.current.pid
|
||||
nffile_t *nffile; // the writing file handle
|
||||
|
||||
// statistical data per source
|
||||
uint32_t bad_packets;
|
||||
uint64_t first_seen; // in msec
|
||||
uint64_t last_seen; // in msec
|
||||
|
||||
// port histogram data
|
||||
xstat_t *xstat;
|
||||
|
||||
// Any exporter specific data
|
||||
generic_exporter_t *exporter_data;
|
||||
uint32_t exporter_count;
|
||||
struct timeval received;
|
||||
|
||||
// extension map list
|
||||
struct {
|
||||
#define BLOCK_SIZE 16
|
||||
int next_free;
|
||||
int max_maps;
|
||||
int num_maps;
|
||||
extension_map_t **maps;
|
||||
} extension_map_list;
|
||||
|
||||
option_offset_t *option_offset_table;
|
||||
|
||||
} FlowSource_t;
|
||||
|
||||
/* input buffer size, to read data from the network */
|
||||
#define NETWORK_INPUT_BUFF_SIZE 65535 // Maximum UDP message size
|
||||
|
||||
// prototypes
|
||||
int AddFlowSource(FlowSource_t **FlowSource, char *ident);
|
||||
|
||||
int AddDefaultFlowSource(FlowSource_t **FlowSource, char *ident, char *path);
|
||||
|
||||
int SetDynamicSourcesDir(FlowSource_t **FlowSource, char *dir);
|
||||
|
||||
FlowSource_t *AddDynamicSource(FlowSource_t **FlowSource, struct sockaddr_storage *ss);
|
||||
|
||||
int InitExtensionMapList(FlowSource_t *fs);
|
||||
|
||||
int ReInitExtensionMapList(FlowSource_t *fs);
|
||||
|
||||
int RemoveExtensionMap(FlowSource_t *fs, extension_map_t *map);
|
||||
|
||||
int AddExtensionMap(FlowSource_t *fs, extension_map_t *map);
|
||||
|
||||
void FlushStdRecords(FlowSource_t *fs);
|
||||
|
||||
void FlushExporterStats(FlowSource_t *fs);
|
||||
|
||||
int FlushInfoExporter(FlowSource_t *fs, exporter_info_record_t *exporter);
|
||||
|
||||
int FlushInfoSampler(FlowSource_t *fs, sampler_info_record_t *sampler);
|
||||
|
||||
int HasOptionTable(FlowSource_t *fs, uint16_t id );
|
||||
|
||||
void launcher (char *commbuff, FlowSource_t *FlowSource, char *process, int expire);
|
||||
|
||||
/* Default time window in seconds to rotate files */
|
||||
#define TIME_WINDOW 300
|
||||
|
||||
/* overdue time:
|
||||
* if nfcapd does not get any data, wake up the receive system call
|
||||
* at least after OVERDUE_TIME seconds after the time window
|
||||
*/
|
||||
#define OVERDUE_TIME 10
|
||||
|
||||
// time nfcapd will wait for launcher to terminate
|
||||
#define LAUNCHER_TIMEOUT 60
|
||||
|
||||
#define SYSLOG_FACILITY "daemon"
|
||||
|
||||
#endif //_COLLECTOR_H
|
126
bin/collector_inline.c
Executable file
126
bin/collector_inline.c
Executable file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: collector_inline.c 37 2009-11-10 08:40:30Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 37 $
|
||||
*
|
||||
*/
|
||||
|
||||
static inline FlowSource_t *GetFlowSource(struct sockaddr_storage *ss) {
|
||||
FlowSource_t *fs;
|
||||
void *ptr;
|
||||
ip_addr_t ip;
|
||||
char as[100];
|
||||
|
||||
union {
|
||||
struct sockaddr_storage *ss;
|
||||
struct sockaddr *sa;
|
||||
struct sockaddr_in *sa_in;
|
||||
struct sockaddr_in6 *sa_in6;
|
||||
} u;
|
||||
u.ss = ss;
|
||||
|
||||
switch (ss->ss_family) {
|
||||
case PF_INET: {
|
||||
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
|
||||
if (ss->ss_len != sizeof(struct sockaddr_in) ) {
|
||||
// malformed struct
|
||||
LogError("Malformed IPv4 socket struct in '%s', line '%d'", __FILE__, __LINE__ );
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
ip.v6[0] = 0;
|
||||
ip.v6[1] = 0;
|
||||
ip.v4 = ntohl(u.sa_in->sin_addr.s_addr);
|
||||
ptr = &u.sa_in->sin_addr;
|
||||
} break;
|
||||
case PF_INET6: {
|
||||
uint64_t *ip_ptr = (uint64_t *)u.sa_in6->sin6_addr.s6_addr;
|
||||
|
||||
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
|
||||
if (ss->ss_len != sizeof(struct sockaddr_in6) ) {
|
||||
// malformed struct
|
||||
LogError("Malformed IPv6 socket struct in '%s', line '%d'", __FILE__, __LINE__ );
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
// ptr = &((struct sockaddr_in6 *)sa)->sin6_addr;
|
||||
ip.v6[0] = ntohll(ip_ptr[0]);
|
||||
ip.v6[1] = ntohll(ip_ptr[1]);
|
||||
ptr = &u.sa_in6->sin6_addr;
|
||||
} break;
|
||||
default:
|
||||
// keep compiler happy
|
||||
ip.v6[0] = 0;
|
||||
ip.v6[1] = 0;
|
||||
ptr = NULL;
|
||||
|
||||
LogError("Unknown sa fanily: %d in '%s', line '%d'", ss->ss_family, __FILE__, __LINE__ );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef DEVEL
|
||||
inet_ntop(ss->ss_family, ptr, as, sizeof(as));
|
||||
as[99] = '\0';
|
||||
printf("Flow Source IP: %s\n", as);
|
||||
#endif
|
||||
|
||||
fs = FlowSource;
|
||||
while ( fs ) {
|
||||
if ( ip.v6[0] == fs->ip.v6[0] && ip.v6[1] == fs->ip.v6[1] )
|
||||
return fs;
|
||||
|
||||
// if we match any source, store the current IP address - works as faster cache next time
|
||||
// and identifies the current source by IP
|
||||
if ( fs->any_source ) {
|
||||
fs->ip = ip;
|
||||
fs->sa_family = ss->ss_family;
|
||||
return fs;
|
||||
}
|
||||
fs = fs->next;
|
||||
}
|
||||
|
||||
if ( ptr ) {
|
||||
inet_ntop (ss->ss_family, ptr, as, 100);
|
||||
} else
|
||||
strncpy(as, "<unknown>", 99);
|
||||
|
||||
as[99] = '\0';
|
||||
LogError("Unknown flow source: '%s'" , as);
|
||||
|
||||
return NULL;
|
||||
|
||||
} // End of GetFlowSource
|
||||
|
||||
|
||||
|
273
bin/content_dns.c
Normal file
273
bin/content_dns.c
Normal file
@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2013, Peter Haag
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* $LastChangedRevision$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_FEATURES_H
|
||||
#include <features.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#ifdef HAVE_ARPA_NAMESER_H
|
||||
#include <arpa/nameser.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ARPA_NAMESER_COMPAT_H
|
||||
#include <arpa/nameser_compat.h>
|
||||
#endif
|
||||
|
||||
#include <resolv.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/udp.h>
|
||||
#include <netinet/ip_icmp.h>
|
||||
#include <netinet/icmp6.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <pcap.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "nffile.h"
|
||||
#include "bookkeeper.h"
|
||||
#include "nfxstat.h"
|
||||
#include "collector.h"
|
||||
#include "flowtree.h"
|
||||
#include "content_dns.h"
|
||||
|
||||
#ifndef DEVEL
|
||||
# define dbg_printf(...) /* printf(__VA_ARGS__) */
|
||||
#else
|
||||
# define dbg_printf(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#include "inline.c"
|
||||
|
||||
/*
|
||||
* Structure for query header. The order of the fields is machine- and
|
||||
* compiler-dependent, depending on the byte/bit order and the layout
|
||||
* of bit fields. We use bit fields only in int variables, as this
|
||||
* is all ANSI requires. This requires a somewhat confusing rearrangement.
|
||||
*/
|
||||
|
||||
typedef struct dns_header_s {
|
||||
unsigned id :16; /* query identification number */
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
/* fields in third byte */
|
||||
unsigned qr: 1; /* response flag */
|
||||
unsigned opcode: 4; /* purpose of message */
|
||||
unsigned aa: 1; /* authoritive answer */
|
||||
unsigned tc: 1; /* truncated message */
|
||||
unsigned rd: 1; /* recursion desired */
|
||||
/* fields in fourth byte */
|
||||
unsigned ra: 1; /* recursion available */
|
||||
unsigned unused :3; /* unused bits (MBZ as of 4.9.3a3) */
|
||||
unsigned rcode :4; /* response code */
|
||||
#else
|
||||
/* fields in third byte */
|
||||
unsigned rd :1; /* recursion desired */
|
||||
unsigned tc :1; /* truncated message */
|
||||
unsigned aa :1; /* authoritive answer */
|
||||
unsigned opcode :4; /* purpose of message */
|
||||
unsigned qr :1; /* response flag */
|
||||
/* fields in fourth byte */
|
||||
unsigned rcode :4; /* response code */
|
||||
unsigned unused :3; /* unused bits (MBZ as of 4.9.3a3) */
|
||||
unsigned ra :1; /* recursion available */
|
||||
#endif
|
||||
/* remaining bytes */
|
||||
unsigned qdcount :16; /* number of question entries */
|
||||
unsigned ancount :16; /* number of answer entries */
|
||||
unsigned nscount :16; /* number of authority entries */
|
||||
unsigned arcount :16; /* number of resource entries */
|
||||
} dns_header_t;
|
||||
|
||||
#define DNS_QUERY_TYPE_A (1)
|
||||
#define DNS_QUERY_TYPE_AAAA (2)
|
||||
#define DNS_QUERY_TYPE_SRV (3)
|
||||
|
||||
typedef struct dns_host_st {
|
||||
struct dns_host_st *next;
|
||||
|
||||
unsigned int type;
|
||||
unsigned int class;
|
||||
unsigned int ttl;
|
||||
|
||||
void *rr;
|
||||
} dns_host_t;
|
||||
|
||||
typedef struct dns_srv_st {
|
||||
unsigned int priority;
|
||||
unsigned int weight;
|
||||
unsigned int port;
|
||||
unsigned int rweight;
|
||||
|
||||
char name[256];
|
||||
} dns_srv_t;
|
||||
|
||||
static void *_a_rr(void **p) {
|
||||
struct in_addr in;
|
||||
|
||||
in.s_addr = ntohl(Get_val32(*p)); *p += 4;
|
||||
return strdup(inet_ntoa(in));
|
||||
}
|
||||
|
||||
static void *_aaaa_rr(void **p) {
|
||||
char addr[INET6_ADDRSTRLEN];
|
||||
uint64_t sa6[2];
|
||||
|
||||
memcpy((void *)sa6, *p, 16);
|
||||
inet_ntop(AF_INET6, (struct sockaddr_storage *)&sa6, addr, sizeof(addr));
|
||||
|
||||
return strdup(addr);
|
||||
}
|
||||
|
||||
void content_decode_dns(struct FlowNode *node, uint8_t *payload, uint32_t payload_size) {
|
||||
dns_header_t *dns_header = (dns_header_t *)payload;
|
||||
uint32_t qdcount, ancount;
|
||||
void *p, *eod;
|
||||
#define DN_LENGTH 256
|
||||
char dn[DN_LENGTH];
|
||||
int i;
|
||||
|
||||
if ( payload_size < sizeof(dns_header_t) ) {
|
||||
LogError("Unable to decode short DNS packet");
|
||||
return;
|
||||
}
|
||||
|
||||
// no of query packets
|
||||
qdcount = ntohs(dns_header->qdcount);
|
||||
dbg_printf("DNS Queries: %u\n", qdcount);
|
||||
|
||||
// no of answer packets
|
||||
ancount = ntohs(dns_header->ancount);
|
||||
dbg_printf("DNS Answers: %u\n", ancount);
|
||||
|
||||
// end of dns packet
|
||||
eod = (void *)(payload + payload_size);
|
||||
|
||||
// reord pointer
|
||||
p = (void *)(payload + sizeof(dns_header_t));
|
||||
|
||||
for (i=0; i<qdcount && p < eod; i++ ) {
|
||||
int32_t len = dn_expand(payload, eod, p, dn, DN_LENGTH);
|
||||
if (len < 0) {
|
||||
LogError("dn_expand() failed: %s", "");
|
||||
}
|
||||
dbg_printf("DNS Query dn_expand: %s\n", dn);
|
||||
p = (void *) (p + len + 4); // + 4 bytes of fixed data in query
|
||||
}
|
||||
|
||||
for (i=0; i<ancount && p < eod; i++ ) {
|
||||
uint32_t type, class, ttl;
|
||||
int32_t len = dn_expand(payload, eod, p, dn, DN_LENGTH);
|
||||
if(len < 0) {
|
||||
LogError("dn_expand() failed: %s", "");
|
||||
}
|
||||
dbg_printf("DNS Answer %i dn_expand: %s ", i, dn);
|
||||
|
||||
p += len;
|
||||
|
||||
/* extract the various parts of the record */
|
||||
type = Get_val16(p); p += 2;
|
||||
class = Get_val16(p); p += 2;
|
||||
ttl = Get_val32(p); p += 4;
|
||||
len = Get_val16(p); p += 2;
|
||||
|
||||
dbg_printf(" Type: %u, class: %u, ttl: %u, len: %u ", type, class, ttl, len);
|
||||
/* type-specific processing */
|
||||
switch(type) {
|
||||
char *s;
|
||||
#ifdef T_A
|
||||
case T_A:
|
||||
#else
|
||||
case ns_t_a:
|
||||
#endif
|
||||
s = _a_rr(&p);
|
||||
dbg_printf("A: %s\n", s);
|
||||
free(s);
|
||||
break;
|
||||
#ifdef T_A6
|
||||
case T_A6:
|
||||
#endif
|
||||
#ifdef T_AAAA
|
||||
case T_AAAA:
|
||||
#else
|
||||
case ns_t_a6:
|
||||
case ns_t_aaaa:
|
||||
#endif
|
||||
s = _aaaa_rr(&p);
|
||||
dbg_printf("AAAA: %s\n", s);
|
||||
free(s);
|
||||
break;
|
||||
#ifdef T_CNAME
|
||||
case T_CNAME: {
|
||||
#else
|
||||
case ns_t_cname: {
|
||||
#endif
|
||||
int32_t len = dn_expand(payload, eod, p, dn, DN_LENGTH);
|
||||
dbg_printf("CNAME: %s\n", dn);
|
||||
p = (void *)(p + len);
|
||||
} break;
|
||||
|
||||
default:
|
||||
dbg_printf("<unkn>\n");
|
||||
p = (void *)(p + len);
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // End of content_decode_dns
|
||||
|
39
bin/content_dns.h
Normal file
39
bin/content_dns.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2013, Peter Haag
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* $LastChangedRevision$
|
||||
*
|
||||
*/
|
||||
|
||||
void content_decode_dns(struct FlowNode *node, uint8_t *payload, uint32_t payload_size);
|
||||
|
822
bin/expire.c
Normal file
822
bin/expire.c
Normal file
@ -0,0 +1,822 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: expire.c 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef HAVE_FTS_H
|
||||
# include <fts.h>
|
||||
#else
|
||||
# include "fts_compat.h"
|
||||
#define fts_children fts_children_compat
|
||||
#define fts_close fts_close_compat
|
||||
#define fts_open fts_open_compat
|
||||
#define fts_read fts_read_compat
|
||||
#define fts_set fts_set_compat
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
#include "bookkeeper.h"
|
||||
#include "nfstatfile.h"
|
||||
#include "expire.h"
|
||||
|
||||
static uint32_t timeout = 0;
|
||||
|
||||
/*
|
||||
* expire.c is needed for daemon code as well as normal stdio code
|
||||
* therefore a generic LogError is defined, which maps to the
|
||||
* approriate logging channel - either stderr or syslog
|
||||
*/
|
||||
void LogError(char *format, ...);
|
||||
|
||||
static void PrepareDirLists(channel_t *channel);
|
||||
|
||||
static int compare(const FTSENT **f1, const FTSENT **f2);
|
||||
|
||||
#if 0
|
||||
#define unlink unlink_debug
|
||||
|
||||
static int unlink_debug (const char *path) {
|
||||
printf("Unlink %s\n", path);
|
||||
return 0;
|
||||
} // End of unlink_debug
|
||||
#endif
|
||||
|
||||
static void IntHandler(int signal) {
|
||||
|
||||
switch (signal) {
|
||||
case SIGALRM:
|
||||
timeout = 1;
|
||||
break;
|
||||
case SIGHUP:
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
timeout = 1;
|
||||
break;
|
||||
break;
|
||||
case SIGCHLD:
|
||||
default:
|
||||
// ignore everything we don't know
|
||||
break;
|
||||
}
|
||||
|
||||
} /* End of IntHandler */
|
||||
|
||||
static void SetupSignalHandler(void) {
|
||||
struct sigaction act;
|
||||
|
||||
memset((void *)&act,0,sizeof(struct sigaction));
|
||||
act.sa_handler = IntHandler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
sigaction(SIGTERM, &act, NULL);
|
||||
sigaction(SIGINT, &act, NULL);
|
||||
sigaction(SIGHUP, &act, NULL);
|
||||
sigaction(SIGALRM, &act, NULL);
|
||||
sigaction(SIGCHLD, &act, NULL);
|
||||
|
||||
} // End of SetupSignalHandler
|
||||
|
||||
uint64_t ParseSizeDef(char *s, uint64_t *value) {
|
||||
char *p;
|
||||
uint64_t fac;
|
||||
int dot;
|
||||
|
||||
dot = 0;
|
||||
*value = 0;
|
||||
p = s;
|
||||
while ( *p ) {
|
||||
if ( *p < '0' || *p > '9' ) {
|
||||
if ( *p == '.' ) {
|
||||
if ( dot ) {
|
||||
break;
|
||||
} else {
|
||||
dot = 1;
|
||||
}
|
||||
} else
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
if ( p == s ) {
|
||||
fprintf(stderr, "Missing number in '%s'\n", s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fac = 0;
|
||||
switch (*p) {
|
||||
case '\0':
|
||||
case 'b':
|
||||
case 'B':
|
||||
fac = 1;
|
||||
break;
|
||||
case 'k':
|
||||
case 'K':
|
||||
fac = 1024;
|
||||
break;
|
||||
case 'm':
|
||||
case 'M':
|
||||
fac = 1024 * 1024;
|
||||
break;
|
||||
case 'g':
|
||||
case 'G':
|
||||
fac = 1024 * 1024 * 1024;
|
||||
break;
|
||||
case 't':
|
||||
case 'T':
|
||||
fac = 1024LL * 1024LL * 1024LL * 1024LL;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Garbage character(s) '%s' in '%s'\n", p, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( *p ) {
|
||||
char *r = p++;
|
||||
|
||||
// skip optional 'B' for Bytes in KB etc.
|
||||
if ( fac != 1 && (*p == 'B' || *p == 'b') ) p++;
|
||||
|
||||
if ( *p ) {
|
||||
// extra garbage after factor
|
||||
fprintf(stderr, "Garbage character(s) '%s''in '%s'\n", p, s);
|
||||
return 0;
|
||||
}
|
||||
*r = '\0';
|
||||
}
|
||||
|
||||
// *value = strtoll(s, NULL, 10) * fac;
|
||||
*value = (uint64_t)(atof(s) * (double)fac);
|
||||
|
||||
return 1;
|
||||
|
||||
} // End of ParseSizeDef
|
||||
|
||||
/*
|
||||
* Accepted time scales
|
||||
*
|
||||
* w week
|
||||
* d day
|
||||
* H hour
|
||||
* M minute
|
||||
*/
|
||||
uint64_t ParseTimeDef(char *s, uint64_t *value) {
|
||||
char *p;
|
||||
uint64_t weeks, days, hours, minutes;
|
||||
|
||||
*value = 0;
|
||||
weeks=days=hours=minutes=0;
|
||||
|
||||
p = s;
|
||||
while ( *p ) {
|
||||
char *q = p;
|
||||
while ( *p ) {
|
||||
if ( *p < '0' || *p > '9' ) {
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
if ( p == q ) {
|
||||
fprintf(stderr, "Missing number before '%s'\n", q);
|
||||
return 0;
|
||||
}
|
||||
switch (*p) {
|
||||
case 'w':
|
||||
*p++ = '\0';
|
||||
if ( weeks ) {
|
||||
fprintf(stderr, "Ambiguous weeks %sw\n", q);
|
||||
return 0;
|
||||
}
|
||||
weeks = strtoll(q, NULL, 10);
|
||||
break;
|
||||
case 'd':
|
||||
*p++ = '\0';
|
||||
if ( days ) {
|
||||
fprintf(stderr, "Ambiguous days %sD\n", q);
|
||||
return 0;
|
||||
}
|
||||
days = strtoll(q, NULL, 10);
|
||||
break;
|
||||
case '\0': // without any units, assume hours
|
||||
case 'H':
|
||||
if ( *p ) *p++ = '\0';
|
||||
if ( hours ) {
|
||||
fprintf(stderr, "Ambiguous hours %sH\n", q);
|
||||
return 0;
|
||||
}
|
||||
hours = strtoll(q, NULL, 10);
|
||||
break;
|
||||
case 'M':
|
||||
*p++ = '\0';
|
||||
if ( minutes ) {
|
||||
fprintf(stderr, "Ambiguous minutes %sM\n", q);
|
||||
return 0;
|
||||
}
|
||||
minutes = strtoll(q, NULL, 10);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown time unit '%s'\n", q);
|
||||
return 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
*value = minutes*60 + hours*3600 + days*24*3600 + weeks*7*24*3600;
|
||||
|
||||
return 1;
|
||||
|
||||
} // End of ParseTimeDef
|
||||
|
||||
static int compare(const FTSENT **f1, const FTSENT **f2) {
|
||||
return strcmp( (*f1)->fts_name, (*f2)->fts_name);
|
||||
} // End of compare
|
||||
|
||||
void RescanDir(char *dir, dirstat_t *dirstat) {
|
||||
FTS *fts;
|
||||
FTSENT *ftsent;
|
||||
char *const path[] = { dir, NULL };
|
||||
char first_timestring[16], last_timestring[16];
|
||||
|
||||
dirstat->filesize = dirstat->numfiles = 0;
|
||||
dirstat->first = 0;
|
||||
dirstat->last = 0;
|
||||
strncpy(first_timestring, "999999999999", 15);
|
||||
strncpy(last_timestring, "000000000000", 15);
|
||||
|
||||
fts = fts_open(path, FTS_LOGICAL, compare);
|
||||
if ( !fts ) {
|
||||
LogError( "fts_open() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return;
|
||||
}
|
||||
while ( (ftsent = fts_read(fts)) != NULL) {
|
||||
if ( ftsent->fts_info == FTS_F && ftsent->fts_namelen == 19 ) {
|
||||
// nfcapd.200604301200 strlen = 19
|
||||
if ( strncmp(ftsent->fts_name, "nfcapd.", 7) == 0 ) {
|
||||
char *s, *p = &(ftsent->fts_name[7]);
|
||||
|
||||
// make sure, we have only digits
|
||||
s = p;
|
||||
while ( *s ) {
|
||||
if ( *s < '0' || *s > '9' )
|
||||
break;
|
||||
s++;
|
||||
}
|
||||
// otherwise skip
|
||||
if ( *s )
|
||||
continue;
|
||||
|
||||
if ( strcmp(p, first_timestring) < 0 ) {
|
||||
first_timestring[0] = '\0';
|
||||
strncat(first_timestring, p, 15);
|
||||
}
|
||||
if ( strcmp(p, last_timestring) > 0 ) {
|
||||
last_timestring[0] = '\0';
|
||||
strncat(last_timestring, p, 15);
|
||||
}
|
||||
|
||||
dirstat->filesize += 512 * ftsent->fts_statp->st_blocks;
|
||||
dirstat->numfiles++;
|
||||
}
|
||||
} else {
|
||||
switch (ftsent->fts_info) {
|
||||
case FTS_D:
|
||||
// skip all '.' entries as well as hidden directories
|
||||
if ( ftsent->fts_level > 0 && ftsent->fts_name[0] == '.' )
|
||||
fts_set(fts, ftsent, FTS_SKIP);
|
||||
// any valid dirctory need to start with a digit ( %Y -> year )
|
||||
if ( ftsent->fts_level > 0 && !isdigit(ftsent->fts_name[0]) )
|
||||
fts_set(fts, ftsent, FTS_SKIP);
|
||||
break;
|
||||
case FTS_DP:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
fts_close(fts);
|
||||
|
||||
// no files means do rebuild next time, otherwise the stat record may not be accurate
|
||||
if ( dirstat->numfiles == 0 ) {
|
||||
dirstat->first = dirstat->last = time(NULL);
|
||||
dirstat->status = FORCE_REBUILD;
|
||||
} else {
|
||||
dirstat->first = ISO2UNIX(first_timestring);
|
||||
dirstat->last = ISO2UNIX(last_timestring);
|
||||
dirstat->status = STATFILE_OK;
|
||||
}
|
||||
|
||||
} // End of RescanDir
|
||||
|
||||
void ExpireDir(char *dir, dirstat_t *dirstat, uint64_t maxsize, uint64_t maxlife, uint32_t runtime ) {
|
||||
FTS *fts;
|
||||
FTSENT *ftsent;
|
||||
uint64_t sizelimit, num_expired;
|
||||
int done, size_done, lifetime_done, dir_files;
|
||||
char *const path[] = { dir, NULL };
|
||||
char *expire_timelimit = NULL;
|
||||
time_t now = time(NULL);
|
||||
|
||||
dir_files = 0;
|
||||
if ( dirstat->low_water == 0 )
|
||||
dirstat->low_water = 95;
|
||||
|
||||
if ( runtime ) {
|
||||
SetupSignalHandler();
|
||||
alarm(runtime);
|
||||
}
|
||||
|
||||
if ( maxlife ) {
|
||||
// build an appropriate string for comparing
|
||||
time_t t_expire = now - maxlife;
|
||||
|
||||
time_t t_watermark = now - (time_t)((maxlife * dirstat->low_water)/100);
|
||||
|
||||
// printf("Expire files before %s", ctime(&t_expire));
|
||||
expire_timelimit = strdup(UNIX2ISO(t_watermark));
|
||||
// printf("down to %s", ctime(&t_watermark));
|
||||
// printf("Diff: %i\n", t_watermark - t_expire );
|
||||
|
||||
if ( dirstat->last < t_expire && (isatty(STDIN_FILENO) ) ) {
|
||||
// this means all files will get expired - are you sure ?
|
||||
char *s, s1[32], s2[32];
|
||||
time_t t;
|
||||
struct tm *when;
|
||||
|
||||
t = t_expire;
|
||||
when = localtime(&t);
|
||||
strftime(s1, 31, "%Y-%m-%d %H:%M:%S", when);
|
||||
s1[31] = '\0';
|
||||
|
||||
t = dirstat->last;
|
||||
when = localtime(&t);
|
||||
strftime(s2, 31, "%Y-%m-%d %H:%M:%S", when);
|
||||
s2[31] = '\0';
|
||||
|
||||
printf("Your max lifetime of %s will expire all file before %s\n", ScaleTime(maxlife), s1);
|
||||
printf("Your latest files are dated %s. This means all files will be deleted!\n", s2);
|
||||
printf("Are you sure? yes/[no] ");
|
||||
s = fgets(s1, 31, stdin);
|
||||
s1[31] = '\0';
|
||||
if ( s && strncasecmp(s1, "yes\n", 31) == 0 ) {
|
||||
printf("Ok - you've beeen warned!\n");
|
||||
} else {
|
||||
printf("Expire canceled!\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done = 0;
|
||||
size_done = maxsize == 0 || dirstat->filesize < maxsize;
|
||||
lifetime_done = maxlife == 0 || ( now - dirstat->first ) < maxlife;
|
||||
sizelimit = (dirstat->low_water * maxsize)/100;
|
||||
num_expired = 0;
|
||||
fts = fts_open(path, FTS_LOGICAL, compare);
|
||||
while ( !done && ((ftsent = fts_read(fts)) != NULL) ) {
|
||||
if ( ftsent->fts_info == FTS_F ) {
|
||||
dir_files++; // count files in directories
|
||||
if ( ftsent->fts_namelen == 19 && strncmp(ftsent->fts_name, "nfcapd.", 7) == 0 ) {
|
||||
// nfcapd.200604301200 strlen = 19
|
||||
char *s, *p = &(ftsent->fts_name[7]);
|
||||
|
||||
// process only nfcapd. files
|
||||
// make sure it's really an nfcapd. file and we have
|
||||
// only digits in the rest of the file name
|
||||
s = p;
|
||||
while ( *s ) {
|
||||
if ( *s < '0' || *s > '9' )
|
||||
break;
|
||||
s++;
|
||||
}
|
||||
// otherwise skip
|
||||
if ( *s )
|
||||
continue;
|
||||
|
||||
// expire size-wise if needed
|
||||
if ( !size_done ) {
|
||||
if ( dirstat->filesize > sizelimit ) {
|
||||
if ( unlink(ftsent->fts_path) == 0 ) {
|
||||
dirstat->filesize -= 512 * ftsent->fts_statp->st_blocks;
|
||||
num_expired++;
|
||||
dir_files--;
|
||||
} else {
|
||||
LogError( "unlink() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
}
|
||||
continue; // next file if file was unlinked
|
||||
} else {
|
||||
dirstat->first = ISO2UNIX(p); // time of first file not expired
|
||||
size_done = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// expire time-wise if needed
|
||||
// this part of the code is executed only when size-wise is fullfilled
|
||||
if ( !lifetime_done ) {
|
||||
if ( expire_timelimit && strcmp(p, expire_timelimit) < 0 ) {
|
||||
if ( unlink(ftsent->fts_path) == 0 ) {
|
||||
dirstat->filesize -= 512 * ftsent->fts_statp->st_blocks;
|
||||
num_expired++;
|
||||
dir_files--;
|
||||
} else {
|
||||
LogError( "unlink() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
}
|
||||
lifetime_done = 0;
|
||||
} else {
|
||||
dirstat->first = ISO2UNIX(p); // time of first file not expired
|
||||
lifetime_done = 1;
|
||||
}
|
||||
}
|
||||
done = (size_done && lifetime_done) || timeout;
|
||||
|
||||
}
|
||||
} else {
|
||||
switch (ftsent->fts_info) {
|
||||
case FTS_D:
|
||||
// set pre-order flag
|
||||
dir_files = 0;
|
||||
// skip all '.' entries as well as hidden directories
|
||||
if ( ftsent->fts_level > 0 && ftsent->fts_name[0] == '.' )
|
||||
fts_set(fts, ftsent, FTS_SKIP);
|
||||
// any valid directory needs to start with a digit ( %Y -> year )
|
||||
if ( ftsent->fts_level > 0 && !isdigit(ftsent->fts_name[0]) )
|
||||
fts_set(fts, ftsent, FTS_SKIP);
|
||||
break;
|
||||
case FTS_DP:
|
||||
// do not delete base data directory ( level == 0 )
|
||||
if ( dir_files == 0 && ftsent->fts_level > 0 ) {
|
||||
// directory is empty and can be deleted
|
||||
// printf("Will remove directory %s\n", ftsent->fts_path);
|
||||
if ( rmdir(ftsent->fts_path) != 0 ) {
|
||||
LogError( "rmdir() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
fts_close(fts);
|
||||
if ( !done ) {
|
||||
// all files expired and limits not reached
|
||||
// this may be possible, when files get time-wise expired and
|
||||
// the time limit is shorter than the latest file
|
||||
dirstat->first = dirstat->last;
|
||||
}
|
||||
if ( runtime )
|
||||
alarm(0);
|
||||
if ( timeout ) {
|
||||
LogError( "Maximum execution time reached! Interrupt expire.\n");
|
||||
}
|
||||
if ( num_expired > dirstat->numfiles ) {
|
||||
LogError( "Error updating stat record: Number of files inconsistent!\n");
|
||||
LogError( "Will automatically rebuild this directory next time\n");
|
||||
dirstat->numfiles = 0;
|
||||
dirstat->status = FORCE_REBUILD;
|
||||
} else {
|
||||
dirstat->numfiles -= num_expired;
|
||||
}
|
||||
if ( dirstat->numfiles == 0 ) {
|
||||
dirstat->first = dirstat->last = time(NULL);
|
||||
dirstat->status = FORCE_REBUILD;
|
||||
}
|
||||
|
||||
free(expire_timelimit);
|
||||
|
||||
} // End of ExpireDir
|
||||
|
||||
static void PrepareDirLists(channel_t *channel) {
|
||||
channel_t *current_channel = channel;
|
||||
|
||||
while ( current_channel ) {
|
||||
char *const path[] = { current_channel->datadir, NULL };
|
||||
|
||||
current_channel->fts = fts_open(path, FTS_LOGICAL|FTS_NOCHDIR, compare);
|
||||
if ( !current_channel->fts ) {
|
||||
LogError( "fts_open() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
continue;
|
||||
}
|
||||
|
||||
// get first entry
|
||||
current_channel->ftsent = fts_read(current_channel->fts);
|
||||
if ( current_channel->ftsent )
|
||||
// use fts_number as the number of files already seen in this directory.
|
||||
current_channel->ftsent->fts_number = 0;
|
||||
|
||||
while ( current_channel->ftsent ) {
|
||||
|
||||
/*
|
||||
FTSENT *ftsent = current_channel->ftsent;
|
||||
char *finfo;
|
||||
switch (ftsent->fts_info) {
|
||||
case FTS_ERR:
|
||||
case FTS_NS:
|
||||
LogError( "fts_read() %s error in %s line %d: %s\n",
|
||||
current_channel->ftsent->fts_path, __FILE__, __LINE__, strerror(current_channel->ftsent->fts_errno) );
|
||||
break;
|
||||
case FTS_D:
|
||||
finfo = "DIR pre ";
|
||||
break;
|
||||
case FTS_DP:
|
||||
finfo = "DIR post";
|
||||
break;
|
||||
case FTS_F:
|
||||
finfo = "FILE ";
|
||||
break;
|
||||
default:
|
||||
finfo = "<undef> ";
|
||||
}
|
||||
printf("%u %i %s %s %s\n", ftsent->fts_info, ftsent->fts_level, finfo, ftsent->fts_path, ftsent->fts_name);
|
||||
*/
|
||||
if ( current_channel->ftsent->fts_info == FTS_ERR ||
|
||||
current_channel->ftsent->fts_info == FTS_NS) {
|
||||
LogError( "fts_read() %s error in %s line %d: %s\n",
|
||||
current_channel->ftsent->fts_path, __FILE__, __LINE__, strerror(current_channel->ftsent->fts_errno) );
|
||||
continue;
|
||||
}
|
||||
if ( current_channel->ftsent->fts_info != FTS_F ) {
|
||||
current_channel->ftsent = fts_read(current_channel->fts);
|
||||
continue;
|
||||
}
|
||||
// it's now FTS_F
|
||||
current_channel->ftsent->fts_number++;
|
||||
|
||||
// if ftsent points to first valid file, break
|
||||
if ( current_channel->ftsent->fts_namelen == 19 && strncmp(current_channel->ftsent->fts_name, "nfcapd.", 7) == 0 )
|
||||
break;
|
||||
|
||||
// otherwise loop
|
||||
current_channel->ftsent = fts_read(current_channel->fts);
|
||||
}
|
||||
current_channel = current_channel->next;
|
||||
}
|
||||
|
||||
} // End of PrepareDirLists
|
||||
|
||||
void ExpireProfile(channel_t *channel, dirstat_t *current_stat, uint64_t maxsize, uint64_t maxlife, uint32_t runtime ) {
|
||||
int size_done, lifetime_done, done;
|
||||
char *expire_timelimit = "";
|
||||
time_t now = time(NULL);
|
||||
uint64_t sizelimit, num_expired;
|
||||
|
||||
if ( !channel )
|
||||
return;
|
||||
|
||||
done = 0;
|
||||
SetupSignalHandler();
|
||||
|
||||
if ( maxlife ) {
|
||||
// time_t t_expire = now - maxlife;
|
||||
// build an appropriate string for comparing
|
||||
time_t t_watermark = now - (time_t)((maxlife * current_stat->low_water)/100);
|
||||
|
||||
// printf("Expire files before %s", ctime(&t_expire));
|
||||
expire_timelimit = strdup(UNIX2ISO(t_watermark));
|
||||
// printf("down to %s", ctime(&t_watermark));
|
||||
// printf("Diff: %i\n", t_watermark - t_expire );
|
||||
|
||||
}
|
||||
|
||||
size_done = maxsize == 0 || current_stat->filesize < maxsize;
|
||||
sizelimit = (current_stat->low_water * maxsize)/100;
|
||||
lifetime_done = maxlife == 0 || ( now - current_stat->first ) < maxlife;
|
||||
|
||||
num_expired = 0;
|
||||
|
||||
PrepareDirLists(channel);
|
||||
if ( runtime )
|
||||
alarm(runtime);
|
||||
while ( !done ) {
|
||||
char *p;
|
||||
int file_removed;
|
||||
|
||||
// search for the channel with oldest file. If all channel have same age,
|
||||
// get the last in the list
|
||||
channel_t *expire_channel = channel;
|
||||
channel_t *compare_channel = expire_channel->next;
|
||||
while ( compare_channel ) {
|
||||
if ( expire_channel->ftsent == NULL ) {
|
||||
expire_channel = compare_channel;
|
||||
}
|
||||
if ( compare_channel->ftsent == NULL ) {
|
||||
compare_channel = compare_channel->next;
|
||||
continue;
|
||||
}
|
||||
// at this point expire_channel and current_channel fts entries are valid
|
||||
if ( strcmp(expire_channel->ftsent->fts_name, compare_channel->ftsent->fts_name) >= 0 ) {
|
||||
expire_channel = compare_channel;
|
||||
}
|
||||
compare_channel = compare_channel->next;
|
||||
}
|
||||
if ( !expire_channel->ftsent ) {
|
||||
// no more entries in any channel - we are done
|
||||
done = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// flag is file got removed
|
||||
file_removed = 0;
|
||||
|
||||
// expire_channel now points to the channel with oldest file
|
||||
// do expire
|
||||
p = &(expire_channel->ftsent->fts_name[7]);
|
||||
// printf("File: %s\n", expire_channel->ftsent->fts_path);
|
||||
|
||||
if ( !size_done ) {
|
||||
// expire size-wise if needed
|
||||
// printf(" Size expire %llu %llu\n", current_stat->filesize, sizelimit);
|
||||
if ( current_stat->filesize > sizelimit ) {
|
||||
// need to delete this file
|
||||
if ( unlink(expire_channel->ftsent->fts_path) == 0 ) {
|
||||
// Update profile stat
|
||||
current_stat->filesize -= 512 * expire_channel->ftsent->fts_statp->st_blocks;
|
||||
current_stat->numfiles--;
|
||||
|
||||
// Update channel stat
|
||||
expire_channel->dirstat->filesize -= 512 * expire_channel->ftsent->fts_statp->st_blocks;
|
||||
expire_channel->dirstat->numfiles--;
|
||||
|
||||
// decrement number of files seen in this directory
|
||||
expire_channel->ftsent->fts_number--;
|
||||
|
||||
file_removed = 1;
|
||||
num_expired++;
|
||||
} else {
|
||||
LogError( "unlink() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
}
|
||||
} else {
|
||||
// we are done size-wise
|
||||
// time of first file not expired = start time of channel/profile
|
||||
expire_channel->dirstat->first = current_stat->first = ISO2UNIX(p);
|
||||
size_done = 1;
|
||||
}
|
||||
} else if ( !lifetime_done ) {
|
||||
// printf(" Time expire \n");
|
||||
// expire time-wise if needed
|
||||
// this part of the code is executed only when size-wise is already fullfilled
|
||||
if ( strcmp(p, expire_timelimit) < 0 ) {
|
||||
// need to delete this file
|
||||
if ( unlink(expire_channel->ftsent->fts_path) == 0 ) {
|
||||
// Update profile stat
|
||||
current_stat->filesize -= 512 * expire_channel->ftsent->fts_statp->st_blocks;
|
||||
current_stat->numfiles--;
|
||||
|
||||
// Update channel stat
|
||||
expire_channel->dirstat->filesize -= 512 * expire_channel->ftsent->fts_statp->st_blocks;
|
||||
expire_channel->dirstat->numfiles--;
|
||||
|
||||
// decrement number of files seen in this directory
|
||||
expire_channel->ftsent->fts_number--;
|
||||
|
||||
file_removed = 1;
|
||||
num_expired++;
|
||||
} else {
|
||||
LogError( "unlink() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
}
|
||||
} else {
|
||||
// we are done time-wise
|
||||
// time of first file not expired = start time of channel/profile
|
||||
expire_channel->dirstat->first = current_stat->first = ISO2UNIX(p);
|
||||
lifetime_done = 1;
|
||||
}
|
||||
} else
|
||||
// all done
|
||||
done = 1;
|
||||
if ( timeout )
|
||||
done = 1;
|
||||
|
||||
// advance fts entry in expire channel to next file, if file was removed
|
||||
if ( file_removed ) {
|
||||
expire_channel->ftsent = fts_read(expire_channel->fts);
|
||||
while ( expire_channel->ftsent ) {
|
||||
if ( expire_channel->ftsent->fts_info == FTS_F ) { // entry is a file
|
||||
expire_channel->ftsent->fts_number++;
|
||||
if ( expire_channel->ftsent->fts_namelen == 19 &&
|
||||
strncmp(expire_channel->ftsent->fts_name, "nfcapd.", 7) == 0 ) {
|
||||
// if ftsent points to next valid file
|
||||
char *p = &(expire_channel->ftsent->fts_name[7]);
|
||||
// next file is first (oldest) for channel and for profile - update first mark
|
||||
expire_channel->dirstat->first = current_stat->first = ISO2UNIX(p);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
||||
switch (expire_channel->ftsent->fts_info) {
|
||||
case FTS_D: // entry is a directory
|
||||
// set number of files seen in this directory = 0
|
||||
expire_channel->ftsent->fts_number = 0;
|
||||
// skip all '.' entries as well as hidden directories
|
||||
if ( expire_channel->ftsent->fts_level > 0 && expire_channel->ftsent->fts_name[0] == '.' )
|
||||
fts_set(expire_channel->fts, expire_channel->ftsent, FTS_SKIP);
|
||||
// any valid directory needs to start with a digit ( %Y -> year )
|
||||
if ( expire_channel->ftsent->fts_level > 0 && !isdigit(expire_channel->ftsent->fts_name[0]) )
|
||||
fts_set(expire_channel->fts, expire_channel->ftsent, FTS_SKIP);
|
||||
break;
|
||||
case FTS_DP:
|
||||
// do not delete base data directory ( level == 0 )
|
||||
if ( expire_channel->ftsent->fts_number == 0 && expire_channel->ftsent->fts_level > 0 ) {
|
||||
// directory is empty and can be deleted
|
||||
// printf("Will remove directory %s\n", expire_channel->ftsent->fts_path);
|
||||
if ( rmdir(expire_channel->ftsent->fts_path) != 0 ) {
|
||||
LogError( "rmdir() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// otherwise loop
|
||||
expire_channel->ftsent = fts_read(expire_channel->fts);
|
||||
} // end advance fts entry
|
||||
file_removed = 0;
|
||||
}
|
||||
|
||||
if ( expire_channel->ftsent == NULL ) {
|
||||
// this channel has no more files now
|
||||
expire_channel->dirstat->first = expire_channel->dirstat->last;
|
||||
if ( expire_channel->dirstat->numfiles ) {
|
||||
// if channel is empty, no files must be reported, but rebuild is done anyway
|
||||
LogError( "Inconsitency detected in channel %s. Will rebuild automatically.\n", expire_channel->datadir);
|
||||
LogError( "No more files found, but %llu expected.\n", expire_channel->dirstat->numfiles);
|
||||
}
|
||||
expire_channel->dirstat->numfiles = 0;
|
||||
expire_channel->dirstat->status = FORCE_REBUILD;
|
||||
}
|
||||
} // while ( !done )
|
||||
|
||||
if ( runtime )
|
||||
alarm(0);
|
||||
if ( timeout ) {
|
||||
LogError( "Maximum execution time reached! Interrupt expire.\n");
|
||||
}
|
||||
|
||||
} // End of ExpireProfile
|
||||
|
||||
void UpdateBookStat(dirstat_t *dirstat, bookkeeper_t *books) {
|
||||
|
||||
if ( books->numfiles ) {
|
||||
/* prevent some faults and dublicates:
|
||||
* book records can never be timewise smaller than directory records => fishy!
|
||||
* in case book records == directory records, the user stopped and restarted nfcapd
|
||||
* this is not necessarily wrong, but results in overwriting an existing file
|
||||
* which results in wrong stats => rescan needed
|
||||
*/
|
||||
if ( books->last <= dirstat->last || books->first <= dirstat->first) {
|
||||
dirstat->status = FORCE_REBUILD;
|
||||
return;
|
||||
}
|
||||
dirstat->last = books->last;
|
||||
dirstat->numfiles += books->numfiles;
|
||||
dirstat->filesize += books->filesize;
|
||||
}
|
||||
|
||||
} // End of UpdateBookStat
|
||||
|
||||
|
68
bin/expire.h
Normal file
68
bin/expire.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: expire.h 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _EXPIRE_H
|
||||
#define _EXPIRE_H 1
|
||||
|
||||
typedef struct channel_s {
|
||||
struct channel_s *next;
|
||||
char *datadir;
|
||||
dirstat_t *dirstat;
|
||||
bookkeeper_t *books;
|
||||
int books_stat;
|
||||
int do_rescan;
|
||||
int status;
|
||||
FTS *fts;
|
||||
FTSENT *ftsent;
|
||||
} channel_t;
|
||||
|
||||
enum { OK = 0, NOFILES };
|
||||
|
||||
uint64_t ParseSizeDef(char *s, uint64_t *value);
|
||||
|
||||
uint64_t ParseTimeDef(char *s, uint64_t *value);
|
||||
|
||||
void RescanDir(char *dir, dirstat_t *dirstat);
|
||||
|
||||
void ExpireDir(char *dir, dirstat_t *dirstat, uint64_t maxsize, uint64_t maxlife, uint32_t runtime );
|
||||
|
||||
void ExpireProfile(channel_t *channel, dirstat_t *current_stat, uint64_t maxsize, uint64_t maxlife, uint32_t runtime );
|
||||
|
||||
void UpdateBookStat(dirstat_t *dirstat, bookkeeper_t *books);
|
||||
|
||||
#endif //_EXPIRE_H
|
465
bin/exporter.c
Executable file
465
bin/exporter.c
Executable file
@ -0,0 +1,465 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2012, Peter Haag
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: peter $
|
||||
*
|
||||
* $Id: exporter.c 224 2014-02-16 12:59:29Z peter $
|
||||
*
|
||||
* $LastChangedRevision: 224 $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifndef DEVEL
|
||||
# define dbg_printf(...) /* printf(__VA_ARGS__) */
|
||||
#else
|
||||
# define dbg_printf(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
#include "nffile.h"
|
||||
#include "nfx.h"
|
||||
#include "nfnet.h"
|
||||
#include "bookkeeper.h"
|
||||
#include "nfxstat.h"
|
||||
#include "collector.h"
|
||||
#include "exporter.h"
|
||||
#include "nf_common.h"
|
||||
#include "netflow_v1.h"
|
||||
#include "netflow_v5_v7.h"
|
||||
#include "netflow_v9.h"
|
||||
#include "ipfix.h"
|
||||
|
||||
/* global */
|
||||
generic_exporter_t **exporter_list;
|
||||
|
||||
/* local variables */
|
||||
#define MAX_EXPORTERS 65535
|
||||
static generic_exporter_t *exporter_root;
|
||||
|
||||
#include "nffile_inline.c"
|
||||
|
||||
/* local prototypes */
|
||||
|
||||
/* functions */
|
||||
int InitExporterList(void) {
|
||||
|
||||
exporter_list = calloc(MAX_EXPORTERS, sizeof(generic_exporter_t *));
|
||||
if ( !exporter_list ) {
|
||||
LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return 0;
|
||||
}
|
||||
exporter_root = NULL;
|
||||
return 1;
|
||||
|
||||
} // End of InitExporterList
|
||||
|
||||
int AddExporterInfo(exporter_info_record_t *exporter_record) {
|
||||
uint32_t id = exporter_record->sysid;
|
||||
int i;
|
||||
char *p1, *p2;
|
||||
|
||||
// sanity check
|
||||
if ( id >= MAX_EXPORTERS ) {
|
||||
LogError("Exporter id: %u out of range. Skip exporter", id);
|
||||
return 0;
|
||||
}
|
||||
if ( exporter_list[id] != NULL ) {
|
||||
// slot already taken - check if exporters are identical
|
||||
exporter_record->sysid = exporter_list[id]->info.sysid;
|
||||
if ( memcmp((void *)exporter_record, (void *)&(exporter_list[id]->info), sizeof(exporter_info_record_t)) == 0 ) {
|
||||
dbg_printf("Found identical exporter record at SysID: %i, Slot: %u\n", exporter_record->sysid, id);
|
||||
// we are done
|
||||
return 2;
|
||||
} else {
|
||||
// exporters not identical - move current slot
|
||||
int i;
|
||||
// search first emty slot at the top of the list
|
||||
for ( i = id+1; i < MAX_EXPORTERS && exporter_list[i] != NULL; i++ ) {;}
|
||||
if ( i >= MAX_EXPORTERS ) {
|
||||
// all slots taken
|
||||
LogError("Too many exporters (>256)\n");
|
||||
return 0;
|
||||
}
|
||||
dbg_printf("Move existing exporter from slot %u, to %i\n", id, i);
|
||||
// else - move slot
|
||||
exporter_list[i] = exporter_list[id];
|
||||
exporter_list[id] = NULL;
|
||||
exporter_record->sysid = i;
|
||||
}
|
||||
}
|
||||
|
||||
// slot[id] is now available
|
||||
exporter_list[id] = (generic_exporter_t *)calloc(1, sizeof(generic_exporter_t));
|
||||
if ( !exporter_list[id] ) {
|
||||
LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
// SPARC gcc fails here, if we use directly a pointer to the struct.
|
||||
// SPARC barfs and core dumps otherwise
|
||||
// memcpy((void *)&(exporter_list[id]->info), (void *)exporter_record, sizeof(exporter_info_record_t));
|
||||
p1 = (char *)&(exporter_list[id]->info);
|
||||
p2 = (char *)exporter_record;
|
||||
for ( i=0; i<sizeof(exporter_info_record_t); i++ )
|
||||
*p1++ = *p2++;
|
||||
|
||||
dbg_printf("Insert exporter record in Slot: %i, Sysid: %u\n", id, exporter_record->sysid);
|
||||
|
||||
#ifdef DEVEL
|
||||
{
|
||||
#define IP_STRING_LEN 40
|
||||
char ipstr[IP_STRING_LEN];
|
||||
if ( exporter_record->sa_family == AF_INET ) {
|
||||
uint32_t _ip = htonl(exporter_record->ip.v4);
|
||||
inet_ntop(AF_INET, &_ip, ipstr, sizeof(ipstr));
|
||||
printf("SysID: %u, IP: %16s, version: %u, ID: %2u, Slot: %u\n", exporter_record->sysid,
|
||||
ipstr, exporter_record->version, exporter_record->id, id);
|
||||
} else if ( exporter_record->sa_family == AF_INET6 ) {
|
||||
uint64_t _ip[2];
|
||||
_ip[0] = htonll(exporter_record->ip.v6[0]);
|
||||
_ip[1] = htonll(exporter_record->ip.v6[1]);
|
||||
inet_ntop(AF_INET6, &_ip, ipstr, sizeof(ipstr));
|
||||
printf("SysID: %u, IP: %40s, version: %u, ID: %2u, Slot: %u\n", exporter_record->sysid,
|
||||
ipstr, exporter_record->version, exporter_record->id, id);
|
||||
} else {
|
||||
strncpy(ipstr, "<unknown>", IP_STRING_LEN);
|
||||
printf("**** Exporter IP version unknown ****\n");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
if ( !exporter_root ) {
|
||||
exporter_root = exporter_list[id];
|
||||
}
|
||||
|
||||
return 1;
|
||||
} // End of AddExporterInfo
|
||||
|
||||
int AddSamplerInfo(sampler_info_record_t *sampler_record) {
|
||||
uint32_t id = sampler_record->exporter_sysid;
|
||||
generic_sampler_t **sampler;
|
||||
|
||||
if ( !exporter_list[id] ) {
|
||||
LogError("Exporter SysID: %u not found! - Skip sampler record", id);
|
||||
return 0;
|
||||
}
|
||||
sampler = &exporter_list[id]->sampler;
|
||||
while ( *sampler ) {
|
||||
if ( memcmp((void *)&(*sampler)->info, (void *)sampler_record, sizeof(sampler_info_record_t)) == 0 ) {
|
||||
// Found identical sampler already registered
|
||||
dbg_printf("Identical sampler already registered: Exporter SysID: %u, Sampler: id: %i, mode: %u, interval: %u\n",
|
||||
sampler_record->exporter_sysid, sampler_record->id, sampler_record->mode, sampler_record->interval);
|
||||
return 2;
|
||||
}
|
||||
sampler = &((*sampler)->next);
|
||||
}
|
||||
|
||||
*sampler = (generic_sampler_t *)malloc(sizeof(generic_sampler_t));
|
||||
if ( !*sampler ) {
|
||||
LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return 0;
|
||||
}
|
||||
(*sampler)->next = NULL;
|
||||
sampler_record->exporter_sysid = exporter_list[id]->info.sysid;
|
||||
|
||||
memcpy((void *)&(*sampler)->info, (void *)sampler_record, sizeof(sampler_info_record_t));
|
||||
dbg_printf("Insert sampler record for exporter at slot %i:\n", id);
|
||||
|
||||
#ifdef DEVEL
|
||||
{
|
||||
if ( sampler_record->id < 0 ) {
|
||||
printf("Exporter SysID: %u, Generic Sampler: mode: %u, interval: %u\n",
|
||||
sampler_record->exporter_sysid, sampler_record->mode, sampler_record->interval);
|
||||
} else {
|
||||
printf("Exporter SysID: %u, Sampler: id: %i, mode: %u, interval: %u\n",
|
||||
sampler_record->exporter_sysid, sampler_record->id, sampler_record->mode, sampler_record->interval);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
} // End of AddSamplerInfo
|
||||
|
||||
int AddExporterStat(exporter_stats_record_t *stat_record) {
|
||||
int i, use_copy;
|
||||
exporter_stats_record_t *rec;
|
||||
|
||||
// 64bit counters can be potentially unaligned
|
||||
if ( ((ptrdiff_t)stat_record & 0x7) != 0 ) {
|
||||
rec = malloc(stat_record->header.size);
|
||||
if ( !rec ) {
|
||||
LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
exit(255);
|
||||
}
|
||||
memcpy(rec, stat_record, stat_record->header.size);
|
||||
use_copy = 1;
|
||||
} else {
|
||||
rec = stat_record;
|
||||
use_copy = 0;
|
||||
}
|
||||
|
||||
for (i=0; i<rec->stat_count; i++ ) {
|
||||
uint32_t id = rec->stat[i].sysid;
|
||||
if ( !exporter_list[id] ) {
|
||||
LogError("Exporter SysID: %u not found! - Skip stat record record.\n");
|
||||
continue;
|
||||
}
|
||||
exporter_list[id]->sequence_failure += rec->stat[i].sequence_failure;
|
||||
exporter_list[id]->packets += rec->stat[i].packets;
|
||||
exporter_list[id]->flows += rec->stat[i].flows;
|
||||
dbg_printf("Update exporter stat for SysID: %i: Sequence failures: %u, packets: %llu, flows: %llu\n",
|
||||
id, exporter_list[id]->sequence_failure, exporter_list[id]->packets, exporter_list[id]->flows);
|
||||
}
|
||||
|
||||
if ( use_copy )
|
||||
free(rec);
|
||||
|
||||
return 1;
|
||||
|
||||
} // End of AddExporterStat
|
||||
|
||||
void ExportExporterList( nffile_t *nffile ) {
|
||||
int i;
|
||||
|
||||
// sysid 0 unused -> no exporter available
|
||||
i = 1;
|
||||
while ( i < MAX_EXPORTERS && exporter_list[i] != NULL ) {
|
||||
exporter_info_record_t *exporter;
|
||||
generic_sampler_t *sampler;
|
||||
|
||||
exporter = &exporter_list[i]->info;
|
||||
AppendToBuffer(nffile, (void *)exporter, exporter->header.size);
|
||||
|
||||
sampler = exporter_list[i]->sampler;
|
||||
while ( sampler ) {
|
||||
AppendToBuffer(nffile, (void *)&(sampler->info), sampler->info.header.size);
|
||||
sampler = sampler->next;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
} // End of ExportExporterList
|
||||
|
||||
void PrintExporters(char *filename) {
|
||||
int i, done, found = 0;
|
||||
nffile_t *nffile;
|
||||
record_header_t *record;
|
||||
uint32_t skipped_blocks;
|
||||
uint64_t total_bytes;
|
||||
|
||||
printf("Exporters:\n");
|
||||
|
||||
nffile = OpenFile(filename, NULL);
|
||||
if ( !nffile ) {
|
||||
return;
|
||||
}
|
||||
|
||||
total_bytes = 0;
|
||||
skipped_blocks = 0;
|
||||
done = 0;
|
||||
while ( !done ) {
|
||||
int i, ret;
|
||||
|
||||
// get next data block from file
|
||||
ret = ReadBlock(nffile);
|
||||
|
||||
switch (ret) {
|
||||
case NF_CORRUPT:
|
||||
case NF_ERROR:
|
||||
if ( ret == NF_CORRUPT )
|
||||
LogError("Corrupt data file '%s': '%s'\n",filename);
|
||||
else
|
||||
LogError("Read error in file '%s': %s\n",filename, strerror(errno) );
|
||||
done = 1;
|
||||
continue;
|
||||
break;
|
||||
// fall through - get next file in chain
|
||||
case NF_EOF:
|
||||
done = 1;
|
||||
continue;
|
||||
break;
|
||||
|
||||
default:
|
||||
// successfully read block
|
||||
total_bytes += ret;
|
||||
}
|
||||
|
||||
if ( nffile->block_header->id != DATA_BLOCK_TYPE_2 ) {
|
||||
skipped_blocks++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// block type = 2
|
||||
|
||||
record = (record_header_t *)nffile->buff_ptr;
|
||||
|
||||
for ( i=0; i < nffile->block_header->NumRecords; i++ ) {
|
||||
switch ( record->type ) {
|
||||
// ExporterRecordType and SamplerRecordype tc versions only
|
||||
case ExporterRecordType: {
|
||||
#define IP_STRING_LEN 40
|
||||
char ipstr[IP_STRING_LEN];
|
||||
exporter_record_t *exporter_record = (exporter_record_t *)record ;
|
||||
found = 1;
|
||||
printf("\n");
|
||||
if ( exporter_record->sa_family == AF_INET ) {
|
||||
uint32_t _ip = htonl(exporter_record->ip.v4);
|
||||
inet_ntop(AF_INET, &_ip, ipstr, sizeof(ipstr));
|
||||
printf("SysID: %u, IP: %16s, version: %u, ID: %2u, Sequence Failures: %u\n", exporter_record->sysid,
|
||||
ipstr, exporter_record->version, exporter_record->exporter_id, exporter_record->sequence_failure);
|
||||
} else if ( exporter_record->sa_family == AF_INET6 ) {
|
||||
uint64_t _ip[2];
|
||||
_ip[0] = htonll(exporter_record->ip.v6[0]);
|
||||
_ip[1] = htonll(exporter_record->ip.v6[1]);
|
||||
inet_ntop(AF_INET6, &_ip, ipstr, sizeof(ipstr));
|
||||
printf("SysID: %u, IP: %40s, version: %u, ID: %2u, Sequence Failures: %u\n", exporter_record->sysid,
|
||||
ipstr, exporter_record->version, exporter_record->exporter_id, exporter_record->sequence_failure);
|
||||
} else {
|
||||
strncpy(ipstr, "<unknown>", IP_STRING_LEN);
|
||||
printf("**** Exporter IP version unknown ****\n");
|
||||
}
|
||||
} break;
|
||||
case SamplerRecordype: {
|
||||
sampler_record_t *sampler_record = (sampler_record_t *)record;;
|
||||
if ( sampler_record->id < 0 ) {
|
||||
printf(" Generic Sampler: mode: %u, interval: %u\n",
|
||||
sampler_record->mode, sampler_record->interval);
|
||||
} else {
|
||||
printf(" Sampler: id: %i, mode: %u, interval: %u\n",
|
||||
sampler_record->id, sampler_record->mode, sampler_record->interval);
|
||||
}
|
||||
} break;
|
||||
case ExporterInfoRecordType:
|
||||
found = 1;
|
||||
if ( !AddExporterInfo((exporter_info_record_t *)record) ) {
|
||||
LogError("Failed to add Exporter Record\n");
|
||||
}
|
||||
break;
|
||||
case ExporterStatRecordType:
|
||||
AddExporterStat((exporter_stats_record_t *)record);
|
||||
break;
|
||||
case SamplerInfoRecordype:
|
||||
if ( !AddSamplerInfo((sampler_info_record_t *)record) ) {
|
||||
LogError("Failed to add Sampler Record\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Advance pointer by number of bytes for netflow record
|
||||
record = (record_header_t *)((pointer_addr_t)record + record->size);
|
||||
}
|
||||
}
|
||||
|
||||
CloseFile(nffile);
|
||||
DisposeFile(nffile);
|
||||
if ( !found ) {
|
||||
printf("No Exporter records found\n");
|
||||
}
|
||||
|
||||
i = 1;
|
||||
while ( i < MAX_EXPORTERS && exporter_list[i] != NULL ) {
|
||||
#define IP_STRING_LEN 40
|
||||
char ipstr[IP_STRING_LEN];
|
||||
|
||||
exporter_info_record_t *exporter;
|
||||
generic_sampler_t *sampler;
|
||||
|
||||
printf("\n");
|
||||
exporter = &exporter_list[i]->info;
|
||||
if ( exporter->sa_family == AF_INET ) {
|
||||
uint32_t _ip = htonl(exporter->ip.v4);
|
||||
inet_ntop(AF_INET, &_ip, ipstr, sizeof(ipstr));
|
||||
if ( exporter_list[i]->flows )
|
||||
printf("SysID: %u, IP: %16s, version: %u, ID: %2u, Sequence failures: %u, packets: %llu, flows: %llu\n",
|
||||
exporter->sysid, ipstr, exporter->version, exporter->id,
|
||||
exporter_list[i]->sequence_failure,
|
||||
(long long unsigned)exporter_list[i]->packets,
|
||||
(long long unsigned)exporter_list[i]->flows);
|
||||
else
|
||||
printf("SysID: %u, IP: %16s, version: %u, ID: %2u\n",
|
||||
exporter->sysid, ipstr, exporter->version, exporter->id);
|
||||
|
||||
} else if ( exporter->sa_family == AF_INET6 ) {
|
||||
uint64_t _ip[2];
|
||||
_ip[0] = htonll(exporter->ip.v6[0]);
|
||||
_ip[1] = htonll(exporter->ip.v6[1]);
|
||||
inet_ntop(AF_INET6, &_ip, ipstr, sizeof(ipstr));
|
||||
if ( exporter_list[i]->flows )
|
||||
printf("SysID: %u, IP: %40s, version: %u, ID: %2u, Sequence failures: %u, packets: %llu, flows: %llu\n ",
|
||||
exporter->sysid, ipstr, exporter->version, exporter->id,
|
||||
exporter_list[i]->sequence_failure,
|
||||
(long long unsigned)exporter_list[i]->packets,
|
||||
(long long unsigned)exporter_list[i]->flows);
|
||||
else
|
||||
printf("SysID: %u, IP: %40s, version: %u, ID: %2u\n ",
|
||||
exporter->sysid, ipstr, exporter->version, exporter->id);
|
||||
} else {
|
||||
strncpy(ipstr, "<unknown>", IP_STRING_LEN);
|
||||
printf("**** Exporter IP version unknown ****\n");
|
||||
}
|
||||
|
||||
sampler = exporter_list[i]->sampler;
|
||||
while ( sampler ) {
|
||||
if ( sampler->info.id < 0 ) {
|
||||
printf(" Sampler for Exporter SysID: %u, Generic Sampler: mode: %u, interval: %u\n",
|
||||
sampler->info.exporter_sysid, sampler->info.mode, sampler->info.interval);
|
||||
} else {
|
||||
printf(" Sampler for Exporter SysID: %u, Sampler: id: %i, mode: %u, interval: %u\n",
|
||||
sampler->info.exporter_sysid, sampler->info.id, sampler->info.mode, sampler->info.interval);
|
||||
}
|
||||
sampler = sampler->next;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
} // End of PrintExporters
|
||||
|
53
bin/exporter.h
Executable file
53
bin/exporter.h
Executable file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2012, Peter Haag
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: peter $
|
||||
*
|
||||
* $Id: exporter.h 224 2014-02-16 12:59:29Z peter $
|
||||
*
|
||||
* $LastChangedRevision: 224 $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _EXPORTER_H
|
||||
#define _EXPORTER_H 1
|
||||
|
||||
int InitExporterList(void);
|
||||
|
||||
int AddExporterInfo(exporter_info_record_t *exporter_record);
|
||||
|
||||
int AddSamplerInfo(sampler_info_record_t *sampler_record);
|
||||
|
||||
int AddExporterStat(exporter_stats_record_t *stat_record);
|
||||
|
||||
void ExportExporterList( nffile_t *nffile );
|
||||
|
||||
void PrintExporters(char *filename);
|
||||
|
||||
#endif //_EXPORTER_H
|
||||
|
1245
bin/flist.c
Normal file
1245
bin/flist.c
Normal file
File diff suppressed because it is too large
Load Diff
52
bin/flist.h
Normal file
52
bin/flist.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: flist.h 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _FLIST_H
|
||||
#define _FLIST_H 1
|
||||
|
||||
#define EMPTY_LIST ((nffile_t *)-1)
|
||||
|
||||
int InitHierPath(int num);
|
||||
|
||||
char *GetSubDir(struct tm *now);
|
||||
|
||||
int SetupSubDir(char *dir, char *subdir, char *error, size_t errlen );
|
||||
|
||||
nffile_t *GetNextFile(nffile_t *nffile, time_t twin_start, time_t twin_end);
|
||||
|
||||
#endif //_FLIST_H
|
626
bin/flowtree.c
Normal file
626
bin/flowtree.c
Normal file
@ -0,0 +1,626 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2011, Peter Haag
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* $LastChangedRevision$
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "rbtree.h"
|
||||
#include "util.h"
|
||||
#include "nffile.h"
|
||||
#include "bookkeeper.h"
|
||||
#include "nfxstat.h"
|
||||
#include "collector.h"
|
||||
#include "flowtree.h"
|
||||
#include "netflow_pcap.h"
|
||||
|
||||
#ifndef DEVEL
|
||||
# define dbg_printf(...) /* printf(__VA_ARGS__) */
|
||||
#else
|
||||
# define dbg_printf(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
static int FlowNodeCMP(struct FlowNode *e1, struct FlowNode *e2);
|
||||
|
||||
// Insert the IP RB tree code here
|
||||
RB_GENERATE(FlowTree, FlowNode, entry, FlowNodeCMP);
|
||||
|
||||
// Flow Cache to store all nodes
|
||||
#define FLOWELEMENTNUM 1024 * 1024
|
||||
//#define FLOWELEMENTNUM 128
|
||||
static struct FlowNode *FlowElementCache;
|
||||
|
||||
// free list
|
||||
static struct FlowNode *FlowNode_FreeList;
|
||||
static pthread_mutex_t m_FreeList = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_cond_t c_FreeList = PTHREAD_COND_INITIALIZER;
|
||||
static uint32_t CacheOverflow;
|
||||
static uint32_t Allocated;
|
||||
|
||||
// Flow tree
|
||||
static FlowTree_t *FlowTree;
|
||||
static int NumFlows;
|
||||
|
||||
// Simple unprotected list
|
||||
typedef struct FlowNode_list_s {
|
||||
struct FlowNode *list;
|
||||
struct FlowNode *tail;
|
||||
uint32_t size;
|
||||
} Linked_list_t;
|
||||
|
||||
static Linked_list_t UDP_list;
|
||||
|
||||
/* static prototypes */
|
||||
static void AppendFlowNode(Linked_list_t *LinkedList, struct FlowNode *node);
|
||||
|
||||
static void DisconnectFlowNode(Linked_list_t *LinkedList, struct FlowNode *node);
|
||||
|
||||
static void TouchFlowNode(Linked_list_t *LinkedList, struct FlowNode *node);
|
||||
|
||||
/* Free list handling functions */
|
||||
// Get next free node from free list
|
||||
struct FlowNode *New_Node(void) {
|
||||
struct FlowNode *node;
|
||||
|
||||
#ifdef USE_MALLOC
|
||||
node = malloc(sizeof(struct FlowNode));
|
||||
memset((void *)node, 'A', sizeof(struct FlowNode));
|
||||
node->left = NULL;
|
||||
node->right = NULL;
|
||||
node->data = NULL;
|
||||
node->memflag = NODE_IN_USE;
|
||||
dbg_printf("New node: %llx\n", (unsigned long long)node);
|
||||
return node;
|
||||
#endif
|
||||
|
||||
pthread_mutex_lock(&m_FreeList);
|
||||
while ( FlowNode_FreeList == NULL ) {
|
||||
CacheOverflow++;
|
||||
LogError("Free list exhausted: %u, Flows: %u - sleep", Allocated, NumFlows);
|
||||
pthread_cond_wait(&c_FreeList, &m_FreeList);
|
||||
}
|
||||
|
||||
node = FlowNode_FreeList;
|
||||
if ( node == NULL ) {
|
||||
// should never happen , as we were waiting for a free node
|
||||
LogError("*** Software ERROR *** New_Node() unexpected error in %s line %d: %s: %u\n",
|
||||
__FILE__, __LINE__, "Node list exhausted", NumFlows);
|
||||
pthread_mutex_unlock(&m_FreeList);
|
||||
return NULL;
|
||||
}
|
||||
if ( node->memflag != NODE_FREE ) {
|
||||
LogError("*** Software ERROR *** New_Node() unexpected error in %s line %d: %s\n",
|
||||
__FILE__, __LINE__, "Tried to allocate a non free Node");
|
||||
abort();
|
||||
}
|
||||
|
||||
FlowNode_FreeList = node->right;
|
||||
Allocated++;
|
||||
pthread_mutex_unlock(&m_FreeList);
|
||||
|
||||
node->left = NULL;
|
||||
node->right = NULL;
|
||||
node->memflag = NODE_IN_USE;
|
||||
|
||||
return node;
|
||||
|
||||
} // End of New_node
|
||||
|
||||
// return node into free list
|
||||
void Free_Node(struct FlowNode *node) {
|
||||
|
||||
if ( node->memflag == NODE_FREE ) {
|
||||
LogError("Free_Node() Fatal: Tried to free an already freed Node");
|
||||
abort();
|
||||
}
|
||||
|
||||
if ( node->memflag != NODE_IN_USE ) {
|
||||
LogError("Free_Node() Fatal: Tried to free a Node not in use");
|
||||
abort();
|
||||
}
|
||||
|
||||
if ( node->data ) {
|
||||
free(node->data);
|
||||
node->data = NULL;
|
||||
}
|
||||
|
||||
#ifdef DEVEL
|
||||
assert(node->left == NULL);
|
||||
assert(node->right == NULL);
|
||||
#endif
|
||||
|
||||
#ifdef USE_MALLOC
|
||||
dbg_printf("Free node: %llx\n", (unsigned long long)node);
|
||||
node->memflag = NODE_FREE;
|
||||
memset((void *)node, 'B', sizeof(struct FlowNode));
|
||||
free(node);
|
||||
return;
|
||||
#endif
|
||||
|
||||
memset((void *)node, 0, sizeof(struct FlowNode));
|
||||
|
||||
pthread_mutex_lock(&m_FreeList);
|
||||
node->right = FlowNode_FreeList;
|
||||
node->left = NULL;
|
||||
node->memflag = NODE_FREE;
|
||||
FlowNode_FreeList = node;
|
||||
Allocated--;
|
||||
pthread_mutex_unlock(&m_FreeList);
|
||||
if ( CacheOverflow ) {
|
||||
CacheOverflow = 0;
|
||||
pthread_cond_signal(&c_FreeList);
|
||||
}
|
||||
|
||||
} // End of Free_Node
|
||||
|
||||
/* safety check - this must never become 0 - otherwise the cache is too small */
|
||||
uint32_t CacheCheck(void) {
|
||||
return FLOWELEMENTNUM - NumFlows;
|
||||
} // End of CacheCheck
|
||||
|
||||
/* flow tree functions */
|
||||
int Init_FlowTree(uint32_t CacheSize) {
|
||||
int i;
|
||||
|
||||
FlowTree = malloc(sizeof(FlowTree_t));
|
||||
if ( !FlowTree ) {
|
||||
LogError("malloc() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
return 0;
|
||||
}
|
||||
RB_INIT(FlowTree);
|
||||
|
||||
if ( CacheSize == 0 )
|
||||
CacheSize = FLOWELEMENTNUM;
|
||||
FlowElementCache = calloc(CacheSize, sizeof(struct FlowNode));
|
||||
if ( !FlowElementCache ) {
|
||||
LogError("malloc() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
free(FlowTree);
|
||||
FlowTree = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// init free list
|
||||
FlowNode_FreeList = FlowElementCache;
|
||||
FlowNode_FreeList->left = NULL;
|
||||
FlowNode_FreeList->right = &FlowElementCache[1];
|
||||
FlowNode_FreeList->memflag = NODE_FREE;
|
||||
for (i=1; i < (CacheSize-1); i++ ) {
|
||||
FlowElementCache[i].memflag = NODE_FREE;
|
||||
FlowElementCache[i].left = &FlowElementCache[i-1];
|
||||
FlowElementCache[i].right = &FlowElementCache[i+1];
|
||||
}
|
||||
FlowElementCache[i].left = &FlowElementCache[i-1];
|
||||
FlowElementCache[i].right = NULL;
|
||||
FlowElementCache[i].memflag = NODE_FREE;
|
||||
|
||||
CacheOverflow = 0;
|
||||
Allocated = 0;
|
||||
NumFlows = 0;
|
||||
|
||||
UDP_list.list = NULL;
|
||||
UDP_list.tail = NULL;
|
||||
UDP_list.size = 0;
|
||||
|
||||
return 1;
|
||||
} // End of Init_FlowTree
|
||||
|
||||
void Dispose_FlowTree(void) {
|
||||
struct FlowNode *node, *nxt;
|
||||
|
||||
// Dump all incomplete flows to the file
|
||||
for (node = RB_MIN(FlowTree, FlowTree); node != NULL; node = nxt) {
|
||||
nxt = RB_NEXT(FlowTree, FlowTree, node);
|
||||
RB_REMOVE(FlowTree, FlowTree, node);
|
||||
if ( node->data )
|
||||
free(node->data);
|
||||
}
|
||||
free(FlowElementCache);
|
||||
FlowElementCache = NULL;
|
||||
FlowNode_FreeList = NULL;
|
||||
CacheOverflow = 0;
|
||||
|
||||
} // End of Dispose_FlowTree
|
||||
|
||||
static int FlowNodeCMP(struct FlowNode *e1, struct FlowNode *e2) {
|
||||
uint64_t *a = e1->src_addr.v6;
|
||||
uint64_t *b = e2->src_addr.v6;
|
||||
int i;
|
||||
|
||||
#define CMPLEN (offsetof(struct FlowNode, _ENDKEY_) - offsetof(struct FlowNode, src_addr))
|
||||
|
||||
i = memcmp((void *)a, (void *)b, CMPLEN );
|
||||
return i;
|
||||
|
||||
} // End of FlowNodeCMP
|
||||
|
||||
struct FlowNode *Lookup_Node(struct FlowNode *node) {
|
||||
return RB_FIND(FlowTree, FlowTree, node);
|
||||
} // End of Lookup_FlowTree
|
||||
|
||||
struct FlowNode *Insert_Node(struct FlowNode *node) {
|
||||
struct FlowNode *n;
|
||||
|
||||
// return RB_INSERT(FlowTree, FlowTree, node);
|
||||
n = RB_INSERT(FlowTree, FlowTree, node);
|
||||
if ( n ) { // existing node
|
||||
return n;
|
||||
} else {
|
||||
NumFlows++;
|
||||
return NULL;
|
||||
}
|
||||
} // End of Lookup_FlowTree
|
||||
|
||||
void Remove_Node(struct FlowNode *node) {
|
||||
|
||||
#ifdef DEVEL
|
||||
assert(node->memflag == NODE_IN_USE);
|
||||
if ( NumFlows == 0 ) {
|
||||
LogError("Remove_Node() Fatal Tried to remove a Node from empty tree");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
RB_REMOVE(FlowTree, FlowTree, node);
|
||||
Free_Node(node);
|
||||
NumFlows--;
|
||||
|
||||
} // End of Lookup_FlowTree
|
||||
|
||||
uint32_t Flush_FlowTree(FlowSource_t *fs) {
|
||||
struct FlowNode *node, *nxt;
|
||||
uint32_t n = NumFlows;
|
||||
|
||||
// Dump all incomplete flows to the file
|
||||
for (node = RB_MIN(FlowTree, FlowTree); node != NULL; node = nxt) {
|
||||
StorePcapFlow(fs, node);
|
||||
nxt = RB_NEXT(FlowTree, FlowTree, node);
|
||||
#ifdef DEVEL
|
||||
if ( node->left || node->right ) {
|
||||
assert(node->proto == 17);
|
||||
node->left = node->right = NULL;
|
||||
}
|
||||
#endif
|
||||
Remove_Node(node);
|
||||
}
|
||||
|
||||
#ifdef DEVEL
|
||||
if ( NumFlows != 0 )
|
||||
LogError("### Flush_FlowTree() remaining flows: %u\n", NumFlows);
|
||||
#endif
|
||||
|
||||
UDP_list.list = NULL;
|
||||
UDP_list.tail = NULL;
|
||||
UDP_list.size = 0;
|
||||
|
||||
return n;
|
||||
|
||||
} // End of Flush_FlowTree
|
||||
|
||||
void UDPexpire(FlowSource_t *fs, time_t t_expire) {
|
||||
struct FlowNode *node;
|
||||
uint32_t num = 0;
|
||||
|
||||
node = UDP_list.list;
|
||||
while ( node && (node->t_last.tv_sec < t_expire) ) {
|
||||
struct FlowNode *n = node;
|
||||
node = node->right;
|
||||
DisconnectFlowNode(&UDP_list, n);
|
||||
StorePcapFlow(fs, n);
|
||||
Remove_Node(n);
|
||||
num++;
|
||||
}
|
||||
dbg_printf("UDP expired %u flows - left %u\n", num, UDP_list.size);
|
||||
|
||||
} // End of UDPexpire
|
||||
|
||||
void AppendUDPNode(struct FlowNode *node) {
|
||||
AppendFlowNode(&UDP_list, node);
|
||||
} // End of AppendUDPNode
|
||||
|
||||
static void AppendFlowNode(Linked_list_t *LinkedList, struct FlowNode *node) {
|
||||
|
||||
#ifdef DEVEL
|
||||
if ( LinkedList->tail )
|
||||
assert(LinkedList->tail->right == NULL);
|
||||
assert(node->memflag == NODE_IN_USE);
|
||||
assert(node->left == NULL);
|
||||
assert(node->right == NULL);
|
||||
#endif
|
||||
if ( LinkedList->list == NULL ) {
|
||||
dbg_printf("AppendFlowNode(): First node\n");
|
||||
node->left = NULL;
|
||||
node->right = NULL;
|
||||
LinkedList->list = node;
|
||||
LinkedList->tail = node;
|
||||
LinkedList->size++;
|
||||
} else {
|
||||
// new node
|
||||
dbg_printf("AppendFlowNode(): next node: %u\n", LinkedList->size);
|
||||
LinkedList->tail->right = node;
|
||||
node->left = LinkedList->tail;
|
||||
node->right = NULL;
|
||||
LinkedList->tail = node;
|
||||
LinkedList->size++;
|
||||
}
|
||||
#ifdef DEVEL
|
||||
assert(LinkedList->tail->right == NULL);
|
||||
#endif
|
||||
} // End of AppendFlowNode
|
||||
|
||||
|
||||
static void DisconnectFlowNode(Linked_list_t *LinkedList, struct FlowNode *node) {
|
||||
|
||||
if ( node == NULL )
|
||||
return;
|
||||
|
||||
else {
|
||||
// disconnect node
|
||||
struct FlowNode *prev = node->left;
|
||||
struct FlowNode *next = node->right;
|
||||
if ( prev )
|
||||
prev->right = next;
|
||||
else
|
||||
LinkedList->list = next;
|
||||
|
||||
if ( next )
|
||||
next->left = prev;
|
||||
|
||||
if ( LinkedList->tail == node )
|
||||
LinkedList->tail = node->left;
|
||||
|
||||
node->left = NULL;
|
||||
node->right = NULL;
|
||||
|
||||
LinkedList->size--;
|
||||
}
|
||||
|
||||
} // End of DisconnectFlowNode
|
||||
|
||||
void TouchUDPNode(struct FlowNode *node) {
|
||||
TouchFlowNode(&UDP_list, node);
|
||||
} // End of TouchUDPNode
|
||||
|
||||
static void TouchFlowNode(Linked_list_t *LinkedList, struct FlowNode *node) {
|
||||
|
||||
dbg_printf("In TochFlowNode()\n");
|
||||
if ( LinkedList->list == NULL ) {
|
||||
// should never happen
|
||||
LogError("TouchFlowNode() error in %s line %d: %s\n", __FILE__, __LINE__, "Tried to touch node in empty list" );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( LinkedList->tail == node ) {
|
||||
// nothing to do
|
||||
dbg_printf("TochFlowNode() - last node - nothing to do\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ( node->left == NULL ) {
|
||||
// first node - disconnect node
|
||||
dbg_printf("TochFlowNode() - touch first node\n");
|
||||
LinkedList->list = node->right;
|
||||
LinkedList->list->left = NULL;
|
||||
} else {
|
||||
dbg_printf("TochFlowNode() - touch middle node\n");
|
||||
(node->right)->left = node->left;
|
||||
(node->left)->right = node->right;
|
||||
}
|
||||
|
||||
// append node
|
||||
LinkedList->tail->right = node;
|
||||
node->left = LinkedList->tail;
|
||||
node->right = NULL;
|
||||
LinkedList->tail = node;
|
||||
|
||||
} // End of TouchFlowNode
|
||||
|
||||
int AddNodeData(struct FlowNode *node, uint32_t seq, void *payload, uint32_t size) {
|
||||
|
||||
return 0;
|
||||
} // End of AddNodeData
|
||||
|
||||
/* Node list functions */
|
||||
NodeList_t *NewNodeList(void) {
|
||||
NodeList_t *NodeList;
|
||||
|
||||
NodeList = (NodeList_t *)malloc(sizeof(NodeList_t));
|
||||
if ( !NodeList ) {
|
||||
LogError("malloc() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
return NULL;
|
||||
}
|
||||
NodeList->list = NULL;
|
||||
NodeList->last = NULL;
|
||||
NodeList->length = 0;
|
||||
pthread_mutex_init(&NodeList->m_list, NULL);
|
||||
pthread_cond_init(&NodeList->c_list, NULL);
|
||||
|
||||
return NodeList;
|
||||
|
||||
} // End of NewNodeList
|
||||
|
||||
void DisposeNodeList(NodeList_t *NodeList) {
|
||||
|
||||
if ( !NodeList )
|
||||
return;
|
||||
|
||||
if ( NodeList->length ) {
|
||||
LogError("Try to free non empty NodeList");
|
||||
return;
|
||||
}
|
||||
free(NodeList);
|
||||
|
||||
} // End of DisposeNodeList
|
||||
|
||||
#ifdef DEVEL
|
||||
void ListCheck(NodeList_t *NodeList) {
|
||||
uint32_t len = 0, mem = 0, proto;
|
||||
static uint32_t loops = 0;
|
||||
struct FlowNode *node, *n;
|
||||
|
||||
// DumpList(NodeList);
|
||||
loops++;
|
||||
node = NodeList->list;
|
||||
while (node) {
|
||||
len++;
|
||||
if ( node == NodeList->last ) {
|
||||
mem = len;
|
||||
}
|
||||
if ( node->memflag != NODE_IN_USE ) {
|
||||
printf("mem flag error : len: %u, last: %u, Nodelist: %u, loops: %u\n", len, mem, NodeList->length, loops);
|
||||
}
|
||||
if ( node->right == NULL ) {
|
||||
proto = node->proto;
|
||||
n = node;
|
||||
}
|
||||
|
||||
node=node->right;
|
||||
}
|
||||
if ( len != NodeList->length) {
|
||||
printf("Len miss match: len: %u, last: %u, proto: %u, Nodelist: %u, loops: %u, allocated: %u, overlow: %u node: %llx\n", len, mem, proto, NodeList->length, loops, Allocated, CacheOverflow, (long long unsigned)n);
|
||||
assert(len==NodeList->length);
|
||||
} else {
|
||||
printf("Len: %u ok last: %u, proto: %u in loop %u, allocated: %u, overlow: %u\n",
|
||||
len, mem, proto, loops, Allocated, CacheOverflow);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void Push_Node(NodeList_t *NodeList, struct FlowNode *node) {
|
||||
|
||||
pthread_mutex_lock(&NodeList->m_list);
|
||||
if ( NodeList->length == 0 ) {
|
||||
// empty list
|
||||
NodeList->list = node;
|
||||
node->left = NULL;
|
||||
node->right = NULL;
|
||||
} else {
|
||||
NodeList->last->right = node;
|
||||
node->left = NodeList->last;
|
||||
node->right = NULL;
|
||||
}
|
||||
NodeList->last = node;
|
||||
NodeList->length++;
|
||||
#ifdef DEVEL
|
||||
int proto = node->proto;
|
||||
printf("pushed node 0x%llx proto: %u, length: %u first: %llx, last: %llx\n",
|
||||
(unsigned long long)node, proto, NodeList->length, (unsigned long long)NodeList->list, (unsigned long long)NodeList->last);
|
||||
ListCheck(NodeList);
|
||||
#endif
|
||||
pthread_mutex_unlock(&NodeList->m_list);
|
||||
pthread_cond_signal(&NodeList->c_list);
|
||||
|
||||
} // End of Push_Node
|
||||
|
||||
struct FlowNode *Pop_Node(NodeList_t *NodeList, int *done) {
|
||||
struct FlowNode *node;
|
||||
int proto;
|
||||
|
||||
pthread_mutex_lock(&NodeList->m_list);
|
||||
while ( NodeList->length == 0 && !*done )
|
||||
pthread_cond_wait(&NodeList->c_list, &NodeList->m_list);
|
||||
|
||||
if ( NodeList->length == 0 && *done ) {
|
||||
pthread_mutex_unlock(&NodeList->m_list);
|
||||
dbg_printf("Pop_Node done\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( NodeList->list == NULL ) {
|
||||
// should never happen - list is supposed to have at least one item
|
||||
pthread_mutex_unlock(&NodeList->m_list);
|
||||
LogError("Unexpected empty FlowNode_ProcessList");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = NodeList->list;
|
||||
NodeList->list = node->right;
|
||||
if ( NodeList->list )
|
||||
NodeList->list->left = NULL;
|
||||
else
|
||||
NodeList->last = NULL;
|
||||
|
||||
node->left = NULL;
|
||||
node->right = NULL;
|
||||
proto = node->proto;
|
||||
|
||||
NodeList->length--;
|
||||
#ifdef DEVEL
|
||||
printf("popped node 0x%llx proto: %u, length: %u first: %llx, last: %llx\n",
|
||||
(unsigned long long)node, proto, NodeList->length, (unsigned long long)NodeList->list, (unsigned long long)NodeList->last);
|
||||
|
||||
ListCheck(NodeList);
|
||||
#endif
|
||||
pthread_mutex_unlock(&NodeList->m_list);
|
||||
|
||||
return node;
|
||||
} // End of Pop_Node
|
||||
|
||||
void DumpList(NodeList_t *NodeList) {
|
||||
struct FlowNode *node;
|
||||
|
||||
printf("FlowNode_ProcessList: 0x%llx, length: %u\n",
|
||||
(unsigned long long)NodeList->list, NodeList->length);
|
||||
node = NodeList->list;
|
||||
while ( node ) {
|
||||
printf("node: 0x%llx\n", (unsigned long long)node);
|
||||
printf(" ->left: 0x%llx\n", (unsigned long long)node->left);
|
||||
printf(" ->right: 0x%llx\n", (unsigned long long)node->right);
|
||||
node = node->right;
|
||||
}
|
||||
printf("tail: 0x%llx\n\n", (unsigned long long)NodeList->last);
|
||||
} // End of DumpList
|
||||
|
||||
void DumpNodeStat(void) {
|
||||
LogInfo("Nodes in use: %u, Flows: %u CacheOverflow: %u", Allocated, NumFlows, CacheOverflow);
|
||||
} // End of NodesAllocated
|
||||
|
||||
/*
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
|
||||
return 0;
|
||||
} // End of main
|
||||
*/
|
149
bin/flowtree.h
Normal file
149
bin/flowtree.h
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2011, Peter Haag
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* $LastChangedRevision$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "rbtree.h"
|
||||
|
||||
#define v4 ip_union._v4
|
||||
#define v6 ip_union._v6
|
||||
|
||||
struct FlowNode {
|
||||
// tree
|
||||
RB_ENTRY(FlowNode) entry;
|
||||
|
||||
// linked list
|
||||
struct FlowNode *left;
|
||||
struct FlowNode *right;
|
||||
|
||||
struct FlowNode *biflow;
|
||||
|
||||
// flow key
|
||||
// IP addr
|
||||
ip_addr_t src_addr;
|
||||
ip_addr_t dst_addr;
|
||||
|
||||
uint16_t src_port;
|
||||
uint16_t dst_port;
|
||||
uint8_t proto;
|
||||
uint8_t version;
|
||||
uint16_t _ENDKEY_;
|
||||
// End of flow key
|
||||
|
||||
ip_addr_t tun_src_addr;
|
||||
ip_addr_t tun_dst_addr;
|
||||
uint8_t tun_proto;
|
||||
|
||||
#define NODE_FREE 0xA5
|
||||
#define NODE_IN_USE 0x5A
|
||||
uint16_t memflag; // internal houskeeping flag
|
||||
uint8_t flags;
|
||||
#define FIN_NODE 1
|
||||
#define SIGNAL_NODE 255
|
||||
uint8_t fin; // double use: 1: fin received - flow can be exported, if complete
|
||||
// 255: empty node - used to wake up flow thread priodically on quite lines
|
||||
|
||||
// flow stat data
|
||||
struct timeval t_first;
|
||||
struct timeval t_last;
|
||||
|
||||
uint32_t packets; // summed up number of packets
|
||||
uint32_t bytes; // summed up number of bytes
|
||||
|
||||
// flow payload
|
||||
#define DATABLOCKSIZE 256
|
||||
uint32_t DataSize; // max size of data buffer
|
||||
void *data; // start of data buffer
|
||||
// uint32_t eodata; // offset last byte in buffer
|
||||
|
||||
};
|
||||
|
||||
typedef struct NodeList_s {
|
||||
struct FlowNode *list;
|
||||
struct FlowNode *last;
|
||||
pthread_mutex_t m_list;
|
||||
pthread_cond_t c_list;
|
||||
uint32_t length;
|
||||
} NodeList_t;
|
||||
|
||||
|
||||
/* flow tree type */
|
||||
typedef RB_HEAD(FlowTree, FlowNode) FlowTree_t;
|
||||
|
||||
// Insert the RB prototypes here
|
||||
RB_PROTOTYPE(FlowTree, FlowNode, entry, FlowNodeCMP);
|
||||
|
||||
int Init_FlowTree(uint32_t CacheSize);
|
||||
|
||||
void Dispose_FlowTree(void);
|
||||
|
||||
uint32_t Flush_FlowTree(FlowSource_t *fs);
|
||||
|
||||
struct FlowNode *Lookup_Node(struct FlowNode *node);
|
||||
|
||||
struct FlowNode *New_Node(void);
|
||||
|
||||
void Free_Node(struct FlowNode *node);
|
||||
|
||||
uint32_t CacheCheck(void);
|
||||
|
||||
int AddNodeData(struct FlowNode *node, uint32_t seq, void *payload, uint32_t size);
|
||||
|
||||
struct FlowNode *Insert_Node(struct FlowNode *node);
|
||||
|
||||
void Remove_Node(struct FlowNode *node);
|
||||
|
||||
// Node list functions
|
||||
NodeList_t *NewNodeList(void);
|
||||
|
||||
void DisposeNodeList(NodeList_t *NodeList);
|
||||
|
||||
void Push_Node(NodeList_t *NodeList, struct FlowNode *node);
|
||||
|
||||
struct FlowNode *Pop_Node(NodeList_t *NodeList, int *done);
|
||||
|
||||
void DumpList(NodeList_t *NodeList);
|
||||
|
||||
// Liked lists
|
||||
void AppendUDPNode(struct FlowNode *node);
|
||||
|
||||
void TouchUDPNode(struct FlowNode *node);
|
||||
|
||||
void UDPexpire(FlowSource_t *fs, time_t t_expire);
|
||||
|
||||
// Stat functions
|
||||
void DumpNodeStat(void);
|
||||
|
||||
|
406
bin/ft2nfdump.c
Normal file
406
bin/ft2nfdump.c
Normal file
@ -0,0 +1,406 @@
|
||||
/*
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* Copyright (c) 2001 Mark Fullmer and The Ohio State University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* Flow-Tools related code taken from flow-tools-0.67 cretated by Mark Fullmer
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: ft2nfdump.c 69 2010-09-09 07:17:43Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 69 $
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/uio.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "ftlib.h"
|
||||
#include "nf_common.h"
|
||||
#include "nffile.h"
|
||||
#include "nfx.h"
|
||||
#include "launch.h"
|
||||
|
||||
/* Global defines */
|
||||
#define MAXRECORDS 30
|
||||
|
||||
/* Global consts */
|
||||
extern extension_descriptor_t extension_descriptor[];
|
||||
|
||||
const char *nfdump_version = VERSION;
|
||||
|
||||
typedef struct v5_block_s {
|
||||
uint32_t srcaddr;
|
||||
uint32_t dstaddr;
|
||||
uint32_t dPkts;
|
||||
uint32_t dOctets;
|
||||
uint8_t data[4]; // link to next record
|
||||
} v5_block_t;
|
||||
|
||||
/* externals */
|
||||
extern uint32_t Max_num_extensions;
|
||||
|
||||
/* prototypes */
|
||||
void usage(char *name);
|
||||
|
||||
extension_info_t *GenExtensionMap(struct ftio *ftio);
|
||||
|
||||
int flows2nfdump(struct ftio *ftio, extension_info_t *extension_info, int extended, uint32_t limitflows);
|
||||
|
||||
#define NEED_PACKRECORD
|
||||
#include "nffile_inline.c"
|
||||
#undef NEED_PACKRECORD
|
||||
|
||||
void usage(char *name) {
|
||||
printf("usage %s [options] \n"
|
||||
"-h\t\tthis text you see right here.\n"
|
||||
"-E\t\tDump records in ASCII extended format to stdout.\n"
|
||||
"-c\t\tLimit number of records to convert.\n"
|
||||
"-m\t\tPrint the extension map and exit.\n"
|
||||
"-V\t\tPrint version and exit.\n"
|
||||
"-r\t\tread input from file\n"
|
||||
"Convert flow-tools format to nfdump format:\n"
|
||||
"ft2nfdump -r <flow-tools-data-file> | nfdump -z -w <nfdump-file>\n"
|
||||
, name);
|
||||
|
||||
} // End of usage
|
||||
|
||||
extension_info_t *GenExtensionMap(struct ftio *ftio) {
|
||||
extension_info_t *extension_info;
|
||||
int i;
|
||||
|
||||
if (ftio_check_xfield(ftio, FT_XFIELD_DPKTS |
|
||||
FT_XFIELD_DOCTETS | FT_XFIELD_FIRST | FT_XFIELD_LAST |
|
||||
FT_XFIELD_SRCADDR | FT_XFIELD_DSTADDR |
|
||||
FT_XFIELD_SRCPORT | FT_XFIELD_DSTPORT |
|
||||
FT_XFIELD_UNIX_SECS | FT_XFIELD_UNIX_NSECS | FT_XFIELD_SYSUPTIME |
|
||||
FT_XFIELD_TOS | FT_XFIELD_TCP_FLAGS | FT_XFIELD_PROT)) {
|
||||
fprintf(stderr,"Flow-tools record missing required fields.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
InitExtensionMaps(NO_EXTENSION_LIST);
|
||||
extension_info = (extension_info_t *)malloc(sizeof(extension_info_t));
|
||||
if ( !extension_info ) {
|
||||
fprintf(stderr, "malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno));
|
||||
return NULL;
|
||||
}
|
||||
memset((void *)extension_info, 0, sizeof(extension_info_t));
|
||||
|
||||
extension_info->map = (extension_map_t *)malloc(sizeof(extension_map_t) + Max_num_extensions * sizeof(uint16_t));
|
||||
if ( !extension_info->map ) {
|
||||
fprintf(stderr, "malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
extension_info->map->type = ExtensionMapType;
|
||||
extension_info->map->map_id = 0;
|
||||
|
||||
if ( !ftio_check_xfield(ftio, FT_XFIELD_INPUT | FT_XFIELD_OUTPUT )) {
|
||||
extension_info->map->ex_id[i++] = EX_IO_SNMP_2;
|
||||
}
|
||||
|
||||
if (!ftio_check_xfield(ftio, FT_XFIELD_SRC_AS | FT_XFIELD_DST_AS)) {
|
||||
extension_info->map->ex_id[i++] = EX_AS_2;
|
||||
}
|
||||
|
||||
if (!ftio_check_xfield(ftio, FT_XFIELD_SRC_MASK | FT_XFIELD_DST_MASK)) {
|
||||
extension_info->map->ex_id[i++] = EX_MULIPLE;
|
||||
}
|
||||
|
||||
if (!ftio_check_xfield(ftio, FT_XFIELD_NEXTHOP )) {
|
||||
extension_info->map->ex_id[i++] = EX_NEXT_HOP_v4;
|
||||
}
|
||||
|
||||
if (!ftio_check_xfield(ftio, FT_XFIELD_EXADDR )) {
|
||||
extension_info->map->ex_id[i++] = EX_ROUTER_IP_v4;
|
||||
}
|
||||
|
||||
if (!ftio_check_xfield(ftio, FT_XFIELD_ENGINE_TYPE )) {
|
||||
extension_info->map->ex_id[i++] = EX_ROUTER_ID;
|
||||
}
|
||||
|
||||
extension_info->map->ex_id[i++] = 0;
|
||||
extension_info->map->size = sizeof(extension_map_t) + i * sizeof(uint16_t);
|
||||
|
||||
// align 32bits
|
||||
if (( extension_info->map->size & 0x3 ) != 0 ) {
|
||||
extension_info->map->size += 4 - ( extension_info->map->size & 0x3 );
|
||||
}
|
||||
|
||||
extension_info->map->extension_size = 0;
|
||||
i=0;
|
||||
while (extension_info->map->ex_id[i]) {
|
||||
int id = extension_info->map->ex_id[i];
|
||||
extension_info->map->extension_size += extension_descriptor[id].size;
|
||||
i++;
|
||||
}
|
||||
|
||||
return extension_info;
|
||||
|
||||
} // End of GenExtensionMap
|
||||
|
||||
int flows2nfdump(struct ftio *ftio, extension_info_t *extension_info, int extended, uint32_t limitflows) {
|
||||
// required flow tools variables
|
||||
struct fttime ftt;
|
||||
struct fts3rec_offsets fo;
|
||||
struct ftver ftv;
|
||||
char *rec;
|
||||
// nfdump variables
|
||||
nffile_t *nffile;
|
||||
master_record_t record;
|
||||
char *s;
|
||||
uint32_t cnt;
|
||||
|
||||
s = "flow-tools";
|
||||
nffile = OpenNewFile( "-", NULL, 0, 0, s);
|
||||
if ( !nffile ) {
|
||||
fprintf(stderr, "%s\n", s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
AppendToBuffer(nffile, (void *)extension_info->map, extension_info->map->size);
|
||||
|
||||
ftio_get_ver(ftio, &ftv);
|
||||
fts3rec_compute_offsets(&fo, &ftv);
|
||||
|
||||
memset((void *)&record, 0, sizeof(record));
|
||||
record.map_ref = extension_info->map;
|
||||
record.type = CommonRecordType;
|
||||
record.exporter_sysid = 0;
|
||||
|
||||
// only v4 addresses
|
||||
ClearFlag(record.flags, FLAG_IPV6_ADDR);
|
||||
|
||||
cnt = 0;
|
||||
while ((rec = ftio_read(ftio))) {
|
||||
uint32_t when, unix_secs, unix_nsecs, sysUpTime;
|
||||
int i, id;
|
||||
|
||||
unix_secs = *((uint32_t*)(rec+fo.unix_secs));
|
||||
unix_nsecs = *((uint32_t*)(rec+fo.unix_nsecs));
|
||||
sysUpTime = *((uint32_t*)(rec+fo.sysUpTime));
|
||||
|
||||
when = *((uint32_t*)(rec+fo.First));
|
||||
ftt = ftltime(sysUpTime, unix_secs, unix_nsecs, when);
|
||||
record.first = ftt.secs;
|
||||
record.msec_first = ftt.msecs;
|
||||
|
||||
when = *((uint32_t*)(rec+fo.Last));
|
||||
ftt = ftltime(sysUpTime, unix_secs, unix_nsecs, when);
|
||||
record.last = ftt.secs;
|
||||
record.msec_last = ftt.msecs;
|
||||
|
||||
record.v4.srcaddr = *((uint32_t*)(rec+fo.srcaddr));
|
||||
record.v4.dstaddr = *((uint32_t*)(rec+fo.dstaddr));
|
||||
record.srcport = *((uint16_t*)(rec+fo.srcport));
|
||||
record.dstport = *((uint16_t*)(rec+fo.dstport));
|
||||
|
||||
record.prot = *((uint8_t*)(rec+fo.prot));
|
||||
record.tcp_flags = *((uint8_t*)(rec+fo.tcp_flags));
|
||||
record.tos = *((uint8_t*)(rec+fo.tos));
|
||||
|
||||
record.dOctets = *((uint32_t*)(rec+fo.dOctets));
|
||||
record.dPkts = *((uint32_t*)(rec+fo.dPkts));
|
||||
|
||||
i = 0;
|
||||
while ( (id = extension_info->map->ex_id[i]) != 0 ) {
|
||||
switch (id) {
|
||||
case EX_IO_SNMP_2:
|
||||
record.input = *((uint16_t*)(rec+fo.input));
|
||||
record.output = *((uint16_t*)(rec+fo.output));
|
||||
break;
|
||||
case EX_AS_2:
|
||||
record.srcas = *((uint16_t*)(rec+fo.src_as));
|
||||
record.dstas = *((uint16_t*)(rec+fo.dst_as));
|
||||
break;
|
||||
case EX_MULIPLE:
|
||||
record.src_mask = *((uint8_t*)(rec+fo.src_mask));
|
||||
record.dst_mask = *((uint8_t*)(rec+fo.dst_mask));
|
||||
record.dir = 0;
|
||||
record.dst_tos = 0;
|
||||
break;
|
||||
case EX_ROUTER_IP_v4:
|
||||
record.ip_nexthop.v4 = *((uint32_t*)(rec+fo.peer_nexthop));
|
||||
break;
|
||||
case EX_NEXT_HOP_v4:
|
||||
record.ip_router.v4 = *((uint32_t*)(rec+fo.router_sc));
|
||||
break;
|
||||
case EX_ROUTER_ID:
|
||||
record.engine_type = *((uint8_t*)(rec+fo.engine_type));
|
||||
record.engine_id = *((uint8_t*)(rec+fo.engine_id));
|
||||
break;
|
||||
// default: Other extensions can not be sent with v5
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
if ( extended ) {
|
||||
char *string;
|
||||
format_file_block_record(&record, &string, 0);
|
||||
fprintf(stderr, "%s\n", string);
|
||||
}
|
||||
|
||||
cnt++;
|
||||
if ( cnt == limitflows )
|
||||
break;
|
||||
|
||||
} /* while */
|
||||
|
||||
// write the last records in buffer
|
||||
if ( nffile->block_header->NumRecords ) {
|
||||
if ( WriteBlock(nffile) <= 0 ) {
|
||||
fprintf(stderr, "Failed to write output buffer: '%s'" , strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
free((void *)extension_info->map);
|
||||
free((void *)extension_info);
|
||||
DisposeFile(nffile);
|
||||
|
||||
return 0;
|
||||
|
||||
} // End of flows2nfdump
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
struct ftio ftio;
|
||||
extension_info_t *extension_info;
|
||||
struct stat statbuf;
|
||||
uint32_t limitflows;
|
||||
int i, extended, printmap, ret, fd;
|
||||
char *ftfile;
|
||||
|
||||
/* init fterr */
|
||||
fterr_setid(argv[0]);
|
||||
|
||||
extended = 0;
|
||||
printmap = 0;
|
||||
limitflows = 0;
|
||||
ftfile = NULL;
|
||||
|
||||
while ((i = getopt(argc, argv, "EVc:hmr:?")) != -1)
|
||||
switch (i) {
|
||||
case 'h': /* help */
|
||||
case '?':
|
||||
usage(argv[0]);
|
||||
exit (0);
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
printf("%s: Version: %s\n",argv[0], nfdump_version);
|
||||
exit(0);
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
extended = 1;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
limitflows = atoi(optarg);
|
||||
if ( !limitflows ) {
|
||||
fprintf(stderr, "Option -c needs a number > 0\n");
|
||||
exit(255);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
printmap = 1;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
ftfile = optarg;
|
||||
if ( (stat(ftfile, &statbuf) < 0 ) || !(statbuf.st_mode & S_IFREG) ) {
|
||||
fprintf(stderr, "No such file: '%s'\n", ftfile);
|
||||
exit(255);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit (1);
|
||||
break;
|
||||
|
||||
} /* switch */
|
||||
// End while
|
||||
|
||||
if (argc - optind)
|
||||
fterr_errx(1, "Extra arguments starting with %s.", argv[optind]);
|
||||
|
||||
if ( ftfile ) {
|
||||
fd = open(ftfile, O_RDONLY, 0);
|
||||
if ( fd < 0 ) {
|
||||
fprintf(stderr, "Can't open file '%s': %s.", ftfile, strerror(errno));
|
||||
exit(255);
|
||||
}
|
||||
} else {
|
||||
fd = 0;
|
||||
}
|
||||
|
||||
/* read from fd */
|
||||
if (ftio_init(&ftio, fd, FT_IO_FLAG_READ) < 0)
|
||||
fterr_errx(1, "ftio_init(): failed");
|
||||
|
||||
extension_info = GenExtensionMap(&ftio);
|
||||
if ( !extension_info )
|
||||
exit(255);
|
||||
|
||||
if ( printmap ) {
|
||||
PrintExtensionMap(extension_info->map);
|
||||
exit(255);
|
||||
}
|
||||
|
||||
ret = flows2nfdump(&ftio, extension_info, extended, limitflows);
|
||||
|
||||
return ret;
|
||||
|
||||
} // End of main
|
||||
|
1129
bin/fts_compat.c
Executable file
1129
bin/fts_compat.c
Executable file
File diff suppressed because it is too large
Load Diff
126
bin/fts_compat.h
Executable file
126
bin/fts_compat.h
Executable file
@ -0,0 +1,126 @@
|
||||
/* $Id: fts_compat.h 16 2009-06-19 09:26:19Z haag $ */
|
||||
/* TNFTPD ORIGINAL: libnetbsd/ftpfts.h */
|
||||
|
||||
/* $NetBSD: ftpfts.h,v 1.3 2003/12/15 23:52:02 lukem Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 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.
|
||||
*
|
||||
* @(#)fts.h 8.3 (Berkeley) 8/14/94
|
||||
*/
|
||||
|
||||
#ifndef _FTS_H_
|
||||
#define _FTS_H_ 1
|
||||
|
||||
typedef struct {
|
||||
struct _ftsent *fts_cur; /* current node */
|
||||
struct _ftsent *fts_child; /* linked list of children */
|
||||
struct _ftsent **fts_array; /* sort array */
|
||||
dev_t fts_dev; /* starting device # */
|
||||
char *fts_path; /* path for this descent */
|
||||
int fts_rfd; /* fd for root */
|
||||
u_int fts_pathlen; /* sizeof(path) */
|
||||
u_int fts_nitems; /* elements in the sort array */
|
||||
int (*fts_compar) /* compare function */
|
||||
(const struct _ftsent **, const struct _ftsent **);
|
||||
|
||||
#define FTS_COMFOLLOW 0x001 /* follow command line symlinks */
|
||||
#define FTS_LOGICAL 0x002 /* logical walk */
|
||||
#define FTS_NOCHDIR 0x004 /* don't change directories */
|
||||
#define FTS_NOSTAT 0x008 /* don't get stat info */
|
||||
#define FTS_PHYSICAL 0x010 /* physical walk */
|
||||
#define FTS_SEEDOT 0x020 /* return dot and dot-dot */
|
||||
#define FTS_XDEV 0x040 /* don't cross devices */
|
||||
#define FTS_WHITEOUT 0x080 /* return whiteout information */
|
||||
#define FTS_OPTIONMASK 0x0ff /* valid user option mask */
|
||||
|
||||
#define FTS_NAMEONLY 0x100 /* (private) child names only */
|
||||
#define FTS_STOP 0x200 /* (private) unrecoverable error */
|
||||
int fts_options; /* fts_open options, global flags */
|
||||
} FTS;
|
||||
|
||||
typedef struct _ftsent {
|
||||
struct _ftsent *fts_cycle; /* cycle node */
|
||||
struct _ftsent *fts_parent; /* parent directory */
|
||||
struct _ftsent *fts_link; /* next file in directory */
|
||||
long fts_number; /* local numeric value */
|
||||
void *fts_pointer; /* local address value */
|
||||
char *fts_accpath; /* access path */
|
||||
char *fts_path; /* root path */
|
||||
int fts_errno; /* errno for this node */
|
||||
int fts_symfd; /* fd for symlink */
|
||||
u_short fts_pathlen; /* strlen(fts_path) */
|
||||
u_short fts_namelen; /* strlen(fts_name) */
|
||||
|
||||
ino_t fts_ino; /* inode */
|
||||
dev_t fts_dev; /* device */
|
||||
nlink_t fts_nlink; /* link count */
|
||||
|
||||
#define FTS_ROOTPARENTLEVEL -1
|
||||
#define FTS_ROOTLEVEL 0
|
||||
short fts_level; /* depth (-1 to N) */
|
||||
|
||||
#define FTS_D 1 /* preorder directory */
|
||||
#define FTS_DC 2 /* directory that causes cycles */
|
||||
#define FTS_DEFAULT 3 /* none of the above */
|
||||
#define FTS_DNR 4 /* unreadable directory */
|
||||
#define FTS_DOT 5 /* dot or dot-dot */
|
||||
#define FTS_DP 6 /* postorder directory */
|
||||
#define FTS_ERR 7 /* error; errno is set */
|
||||
#define FTS_F 8 /* regular file */
|
||||
#define FTS_INIT 9 /* initialized only */
|
||||
#define FTS_NS 10 /* stat(2) failed */
|
||||
#define FTS_NSOK 11 /* no stat(2) requested */
|
||||
#define FTS_SL 12 /* symbolic link */
|
||||
#define FTS_SLNONE 13 /* symbolic link without target */
|
||||
#define FTS_W 14 /* whiteout object */
|
||||
u_short fts_info; /* user flags for FTSENT structure */
|
||||
|
||||
#define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */
|
||||
#define FTS_SYMFOLLOW 0x02 /* followed a symlink to get here */
|
||||
#define FTS_ISW 0x04 /* this is a whiteout object */
|
||||
u_short fts_flags; /* private flags for FTSENT structure */
|
||||
|
||||
#define FTS_AGAIN 1 /* read node again */
|
||||
#define FTS_FOLLOW 2 /* follow symbolic link */
|
||||
#define FTS_NOINSTR 3 /* no instructions */
|
||||
#define FTS_SKIP 4 /* discard node */
|
||||
u_short fts_instr; /* fts_set() instructions */
|
||||
|
||||
struct stat *fts_statp; /* stat(2) information */
|
||||
char fts_name[1]; /* file name */
|
||||
} FTSENT;
|
||||
|
||||
FTSENT *fts_children_compat(FTS *, int);
|
||||
int fts_close_compat(FTS *);
|
||||
FTS *fts_open_compat(char * const *, int,
|
||||
int (*)(const FTSENT **, const FTSENT **));
|
||||
FTSENT *fts_read_compat(FTS *);
|
||||
int fts_set_compat(FTS *, FTSENT *, int);
|
||||
|
||||
#endif /* !_FTS_H_ */
|
2204
bin/grammar.y
Executable file
2204
bin/grammar.y
Executable file
File diff suppressed because it is too large
Load Diff
1732
bin/grammar.y.mine
Executable file
1732
bin/grammar.y.mine
Executable file
File diff suppressed because it is too large
Load Diff
91
bin/heapsort_inline.c
Executable file
91
bin/heapsort_inline.c
Executable file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: heapsort_inline.c 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
static void heapSort(SortElement_t *SortElement, uint32_t array_size, int topN);
|
||||
|
||||
static inline void siftDown(SortElement_t *SortElement, uint32_t root, uint32_t bottom);
|
||||
|
||||
static void heapSort(SortElement_t *SortElement, uint32_t array_size, int topN) {
|
||||
int32_t i, maxindex;
|
||||
|
||||
for(i = array_size - 1; i >= 0; i--)
|
||||
siftDown(SortElement,array_size,i);
|
||||
|
||||
/*
|
||||
* we are only interested in the first top N => skip sorting the rest
|
||||
* For topN == 0 -> all flows gets sorted
|
||||
*/
|
||||
if ( (topN >= (array_size - 1)) || topN == 0 )
|
||||
maxindex = 0;
|
||||
else
|
||||
maxindex = array_size - 1 - topN;
|
||||
|
||||
for(i = array_size-1; i > maxindex; i-- ) {
|
||||
SortElement_t temp = SortElement[0];
|
||||
SortElement[0] = SortElement[i];
|
||||
SortElement[i] = temp;
|
||||
siftDown(SortElement,i,0);
|
||||
}
|
||||
|
||||
} // End of heapSort
|
||||
|
||||
static inline void siftDown(SortElement_t *SortElement, uint32_t numbersSize, uint32_t node) {
|
||||
uint32_t i, parent, child;
|
||||
|
||||
parent = node;
|
||||
i = parent + 1;
|
||||
while( i != parent ) {
|
||||
i = parent;
|
||||
|
||||
// Compare with left child node
|
||||
child = 2*i+1;
|
||||
if( (child) < numbersSize && SortElement[child].count > SortElement[parent].count)
|
||||
parent = child;
|
||||
|
||||
// Compare with right child node
|
||||
child = 2*i+2;
|
||||
if( (child) < numbersSize && SortElement[child].count > SortElement[parent].count)
|
||||
parent = child;
|
||||
|
||||
if ( i != parent ) {
|
||||
SortElement_t temp = SortElement[i];
|
||||
SortElement[i] = SortElement[parent];
|
||||
SortElement[parent] = temp;
|
||||
}
|
||||
}
|
||||
} // End of siftDown
|
334
bin/inline.c
Normal file
334
bin/inline.c
Normal file
@ -0,0 +1,334 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: inline.c 40 2009-12-16 10:41:44Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 40 $
|
||||
*
|
||||
*/
|
||||
|
||||
static inline uint16_t Get_val16(void *p);
|
||||
|
||||
static inline uint32_t Get_val24(void *p);
|
||||
|
||||
static inline uint32_t Get_val32(void *p);
|
||||
|
||||
static inline uint64_t Get_val40(void *p);
|
||||
|
||||
static inline uint64_t Get_val48(void *p);
|
||||
|
||||
static inline uint64_t Get_val56(void *p);
|
||||
|
||||
static inline uint64_t Get_val64(void *p);
|
||||
|
||||
static inline void Put_val16(uint16_t v, void *p);
|
||||
|
||||
static inline void Put_val24(uint32_t v, void *p);
|
||||
|
||||
static inline void Put_val32(uint32_t v, void *p);
|
||||
|
||||
// static inline void Put_val40(uint64_t v, void *p);
|
||||
|
||||
static inline void Put_val48(uint64_t v, void *p);
|
||||
|
||||
// static inline void Put_val56(uint64_t v, void *p);
|
||||
|
||||
static inline void Put_val64(uint64_t v, void *p);
|
||||
|
||||
static inline uint16_t Get_val16(void *p) {
|
||||
uint8_t *in = (uint8_t *)p;
|
||||
type_mask_t mask;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
mask.val.val8[0] = in[0];
|
||||
mask.val.val8[1] = in[1];
|
||||
#else
|
||||
mask.val.val8[0] = in[1];
|
||||
mask.val.val8[1] = in[0];
|
||||
#endif
|
||||
return mask.val.val16[0];
|
||||
|
||||
} // End of Get_val16
|
||||
|
||||
static inline uint32_t Get_val24(void *p) {
|
||||
uint8_t *in = (uint8_t *)p;
|
||||
type_mask_t mask;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
mask.val.val8[0] = 0;
|
||||
mask.val.val8[1] = in[0];
|
||||
mask.val.val8[2] = in[1];
|
||||
mask.val.val8[3] = in[2];
|
||||
#else
|
||||
mask.val.val8[0] = in[2];
|
||||
mask.val.val8[1] = in[1];
|
||||
mask.val.val8[2] = in[0];
|
||||
mask.val.val8[3] = 0;
|
||||
#endif
|
||||
return mask.val.val32[0];
|
||||
|
||||
} // End of Get_val24
|
||||
|
||||
static inline uint32_t Get_val32(void *p) {
|
||||
uint8_t *in = (uint8_t *)p;
|
||||
type_mask_t mask;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
mask.val.val8[0] = in[0];
|
||||
mask.val.val8[1] = in[1];
|
||||
mask.val.val8[2] = in[2];
|
||||
mask.val.val8[3] = in[3];
|
||||
#else
|
||||
mask.val.val8[0] = in[3];
|
||||
mask.val.val8[1] = in[2];
|
||||
mask.val.val8[2] = in[1];
|
||||
mask.val.val8[3] = in[0];
|
||||
#endif
|
||||
|
||||
return mask.val.val32[0];
|
||||
|
||||
} // End of Get_val32
|
||||
|
||||
static inline uint64_t Get_val40(void *p) {
|
||||
uint8_t *in = (uint8_t *)p;
|
||||
type_mask_t mask;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
mask.val.val8[0] = 0;
|
||||
mask.val.val8[1] = 0;
|
||||
mask.val.val8[2] = 0;
|
||||
mask.val.val8[3] = in[0];
|
||||
mask.val.val8[4] = in[1];
|
||||
mask.val.val8[5] = in[2];
|
||||
mask.val.val8[6] = in[3];
|
||||
mask.val.val8[7] = in[4];
|
||||
#else
|
||||
mask.val.val8[0] = in[4];
|
||||
mask.val.val8[1] = in[3];
|
||||
mask.val.val8[2] = in[2];
|
||||
mask.val.val8[3] = in[1];
|
||||
mask.val.val8[4] = in[0];
|
||||
mask.val.val8[5] = 0;
|
||||
mask.val.val8[6] = 0;
|
||||
mask.val.val8[7] = 0;
|
||||
#endif
|
||||
|
||||
return mask.val.val64;
|
||||
|
||||
} // End of Get_val40
|
||||
|
||||
static inline uint64_t Get_val48(void *p) {
|
||||
uint8_t *in = (uint8_t *)p;
|
||||
type_mask_t mask;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
mask.val.val8[0] = 0;
|
||||
mask.val.val8[1] = 0;
|
||||
mask.val.val8[2] = in[0];
|
||||
mask.val.val8[3] = in[1];
|
||||
mask.val.val8[4] = in[2];
|
||||
mask.val.val8[5] = in[3];
|
||||
mask.val.val8[6] = in[4];
|
||||
mask.val.val8[7] = in[5];
|
||||
#else
|
||||
mask.val.val8[0] = in[5];
|
||||
mask.val.val8[1] = in[4];
|
||||
mask.val.val8[2] = in[3];
|
||||
mask.val.val8[3] = in[2];
|
||||
mask.val.val8[4] = in[1];
|
||||
mask.val.val8[5] = in[0];
|
||||
mask.val.val8[6] = 0;
|
||||
mask.val.val8[7] = 0;
|
||||
#endif
|
||||
|
||||
return mask.val.val64;
|
||||
|
||||
} // End of Get_val48
|
||||
|
||||
static inline uint64_t Get_val56(void *p) {
|
||||
uint8_t *in = (uint8_t *)p;
|
||||
type_mask_t mask;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
mask.val.val8[0] = 0;
|
||||
mask.val.val8[1] = in[0];
|
||||
mask.val.val8[2] = in[1];
|
||||
mask.val.val8[3] = in[2];
|
||||
mask.val.val8[4] = in[3];
|
||||
mask.val.val8[5] = in[4];
|
||||
mask.val.val8[6] = in[5];
|
||||
mask.val.val8[7] = in[6];
|
||||
#else
|
||||
mask.val.val8[0] = in[6];
|
||||
mask.val.val8[1] = in[5];
|
||||
mask.val.val8[2] = in[4];
|
||||
mask.val.val8[3] = in[3];
|
||||
mask.val.val8[4] = in[2];
|
||||
mask.val.val8[5] = in[1];
|
||||
mask.val.val8[6] = in[0];
|
||||
mask.val.val8[7] = 0;
|
||||
#endif
|
||||
|
||||
return mask.val.val64;
|
||||
|
||||
} // End of Get_val56
|
||||
|
||||
static inline uint64_t Get_val64(void *p) {
|
||||
uint8_t *in = (uint8_t *)p;
|
||||
type_mask_t mask;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
mask.val.val8[0] = in[0];
|
||||
mask.val.val8[1] = in[1];
|
||||
mask.val.val8[2] = in[2];
|
||||
mask.val.val8[3] = in[3];
|
||||
mask.val.val8[4] = in[4];
|
||||
mask.val.val8[5] = in[5];
|
||||
mask.val.val8[6] = in[6];
|
||||
mask.val.val8[7] = in[7];
|
||||
#else
|
||||
mask.val.val8[0] = in[7];
|
||||
mask.val.val8[1] = in[6];
|
||||
mask.val.val8[2] = in[5];
|
||||
mask.val.val8[3] = in[4];
|
||||
mask.val.val8[4] = in[3];
|
||||
mask.val.val8[5] = in[2];
|
||||
mask.val.val8[6] = in[1];
|
||||
mask.val.val8[7] = in[0];
|
||||
#endif
|
||||
|
||||
return mask.val.val64;
|
||||
|
||||
} // End of Get_val64
|
||||
|
||||
static inline void Put_val16(uint16_t v, void *p) {
|
||||
uint8_t *out = (uint8_t *)p;
|
||||
type_mask_t mask;
|
||||
|
||||
mask.val.val16[0] = v;
|
||||
out[0] = mask.val.val8[0];
|
||||
out[1] = mask.val.val8[1];
|
||||
|
||||
} // End of Put_val16
|
||||
|
||||
static inline void Put_val24(uint32_t v, void *p) {
|
||||
uint8_t *out = (uint8_t *)p;
|
||||
type_mask_t mask;
|
||||
|
||||
mask.val.val32[0] = v;
|
||||
out[0] = mask.val.val8[1];
|
||||
out[1] = mask.val.val8[2];
|
||||
out[2] = mask.val.val8[3];
|
||||
|
||||
} // End of Put_val24
|
||||
|
||||
static inline void Put_val32(uint32_t v, void *p) {
|
||||
uint8_t *out = (uint8_t *)p;
|
||||
type_mask_t mask;
|
||||
|
||||
mask.val.val32[0] = v;
|
||||
out[0] = mask.val.val8[0];
|
||||
out[1] = mask.val.val8[1];
|
||||
out[2] = mask.val.val8[2];
|
||||
out[3] = mask.val.val8[3];
|
||||
|
||||
} // End of Put_val32
|
||||
|
||||
/*
|
||||
* not yet used
|
||||
*
|
||||
static inline void Put_val40(uint64_t v, void *p) {
|
||||
uint8_t *out = (uint8_t *)p;
|
||||
type_mask_t mask;
|
||||
|
||||
mask.val.val64 = v;
|
||||
out[0] = mask.val.val8[3];
|
||||
out[1] = mask.val.val8[4];
|
||||
out[2] = mask.val.val8[5];
|
||||
out[3] = mask.val.val8[6];
|
||||
out[4] = mask.val.val8[7];
|
||||
|
||||
} // End of Put_val40
|
||||
*
|
||||
*/
|
||||
|
||||
static inline void Put_val48(uint64_t v, void *p) {
|
||||
uint8_t *out = (uint8_t *)p;
|
||||
type_mask_t mask;
|
||||
|
||||
mask.val.val64 = v;
|
||||
out[0] = mask.val.val8[2];
|
||||
out[1] = mask.val.val8[3];
|
||||
out[2] = mask.val.val8[4];
|
||||
out[3] = mask.val.val8[5];
|
||||
out[4] = mask.val.val8[6];
|
||||
out[5] = mask.val.val8[7];
|
||||
|
||||
} // End of Put_val48
|
||||
|
||||
/*
|
||||
* not yet used
|
||||
*
|
||||
static inline void Put_val56(uint64_t v, void *p) {
|
||||
uint8_t *out = (uint8_t *)p;
|
||||
type_mask_t mask;
|
||||
|
||||
mask.val.val64 = v;
|
||||
out[0] = mask.val.val8[1];
|
||||
out[1] = mask.val.val8[2];
|
||||
out[2] = mask.val.val8[3];
|
||||
out[3] = mask.val.val8[4];
|
||||
out[4] = mask.val.val8[5];
|
||||
out[5] = mask.val.val8[6];
|
||||
out[6] = mask.val.val8[7];
|
||||
|
||||
} // End of Put_val56
|
||||
*
|
||||
*/
|
||||
|
||||
static inline void Put_val64(uint64_t v, void *p) {
|
||||
uint8_t *out = (uint8_t *)p;
|
||||
type_mask_t mask;
|
||||
|
||||
mask.val.val64 = v;
|
||||
out[0] = mask.val.val8[0];
|
||||
out[1] = mask.val.val8[1];
|
||||
out[2] = mask.val.val8[2];
|
||||
out[3] = mask.val.val8[3];
|
||||
out[4] = mask.val.val8[4];
|
||||
out[5] = mask.val.val8[5];
|
||||
out[6] = mask.val.val8[6];
|
||||
out[7] = mask.val.val8[7];
|
||||
|
||||
} // End of Put_val64
|
||||
|
||||
|
361
bin/ipconv.c
Normal file
361
bin/ipconv.c
Normal file
@ -0,0 +1,361 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2008-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* Copyright (c) 1996 by Internet Software Consortium.
|
||||
*
|
||||
* 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
||||
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
||||
* CONSORTIUM 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.
|
||||
*
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: ipconv.c 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <arpa/nameser.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef HAVE_RESOLV_H
|
||||
#include <resolv.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "nffile.h"
|
||||
#include "util.h"
|
||||
#include "ipconv.h"
|
||||
|
||||
|
||||
static int parse_ipv4(const char *src, uint32_t *dst, int *bytes);
|
||||
static int parse_ipv6(const char *src, uint64_t *dst, int *bytes);
|
||||
static int lookup_host(const char *hostname, uint64_t *iplist, uint32_t *num_ip );
|
||||
|
||||
int parse_ip(int *af, const char *src, uint64_t *dst, int *bytes, int lookup, uint32_t *num_ip ) {
|
||||
char *alpha = "abcdefghijklmnopqrstuvwxzyABCDEFGHIJKLMNOPQRSTUVWXZY";
|
||||
uint32_t v4addr;
|
||||
int ret;
|
||||
|
||||
// check for IPv6 address
|
||||
if ( strchr(src, ':') != NULL ) {
|
||||
*af = PF_INET6;
|
||||
// check for alpha chars -> hostname -> lookup
|
||||
} else if ( strpbrk(src, alpha)) {
|
||||
*af = 0;
|
||||
if ( lookup == STRICT_IP )
|
||||
return -1;
|
||||
else
|
||||
return lookup_host(src, dst, num_ip );
|
||||
// it's IPv4
|
||||
} else
|
||||
*af = PF_INET;
|
||||
|
||||
*num_ip = 1;
|
||||
switch (*af) {
|
||||
case AF_INET:
|
||||
ret = (parse_ipv4(src, &v4addr, bytes));
|
||||
dst[0] = 0;
|
||||
dst[1] = ntohl(v4addr) & 0xffffffffLL ;
|
||||
return ret;
|
||||
break;
|
||||
case AF_INET6:
|
||||
ret = (parse_ipv6(src, dst, bytes));
|
||||
dst[0] = ntohll(dst[0]);
|
||||
dst[1] = ntohll(dst[1]);
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_ipv4(const char *src, uint32_t *dst, int *bytes) {
|
||||
static const char digits[] = "0123456789";
|
||||
int saw_digit, ch;
|
||||
uint8_t tmp[4], *tp;
|
||||
|
||||
saw_digit = 0;
|
||||
*bytes = 0;
|
||||
*(tp = tmp) = 0;
|
||||
memset(tmp, 0, sizeof(tmp));
|
||||
while ((ch = *src++) != '\0') {
|
||||
const char *pch;
|
||||
|
||||
if ((pch = strchr(digits, ch)) != NULL) {
|
||||
unsigned int new = *tp * 10 + (pch - digits);
|
||||
|
||||
if (new > 255)
|
||||
return (0);
|
||||
if (! saw_digit) {
|
||||
if (++(*bytes) > 4)
|
||||
return (0);
|
||||
saw_digit = 1;
|
||||
}
|
||||
*tp = new;
|
||||
} else if (ch == '.' && saw_digit) {
|
||||
if (*bytes == 4)
|
||||
return (0);
|
||||
*++tp = 0;
|
||||
saw_digit = 0;
|
||||
if ( !(*src) )
|
||||
return 0;
|
||||
} else
|
||||
return (0);
|
||||
}
|
||||
|
||||
memcpy(dst, tmp, sizeof(tmp));
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int parse_ipv6(const char *src, uint64_t *dst, int *bytes) {
|
||||
static const char xdigits_l[] = "0123456789abcdef",
|
||||
xdigits_u[] = "0123456789ABCDEF";
|
||||
uint8_t tmp[16], *tp, *endp, *colonp;
|
||||
const char *xdigits, *curtok;
|
||||
int ch, saw_xdigit;
|
||||
u_int val;
|
||||
|
||||
memset((tp = tmp), '\0', sizeof(tmp));
|
||||
endp = tp + sizeof(tmp);
|
||||
colonp = NULL;
|
||||
/* Leading :: requires some special handling. */
|
||||
if (*src == ':')
|
||||
if (*++src != ':')
|
||||
return (0);
|
||||
curtok = src;
|
||||
saw_xdigit = 0;
|
||||
val = 0;
|
||||
while ((ch = *src++) != '\0') {
|
||||
const char *pch;
|
||||
|
||||
if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
|
||||
pch = strchr((xdigits = xdigits_u), ch);
|
||||
if (pch != NULL) {
|
||||
val <<= 4;
|
||||
val |= (pch - xdigits);
|
||||
if (val > 0xffff)
|
||||
return (0);
|
||||
saw_xdigit = 1;
|
||||
continue;
|
||||
}
|
||||
if (ch == ':') {
|
||||
curtok = src;
|
||||
if (!saw_xdigit) {
|
||||
if (colonp)
|
||||
return (0);
|
||||
colonp = tp;
|
||||
continue;
|
||||
} else if (*src == '\0') {
|
||||
return (0);
|
||||
}
|
||||
if (tp + sizeof(uint16_t) > endp)
|
||||
return (0);
|
||||
*tp++ = (u_char) (val >> 8) & 0xff;
|
||||
*tp++ = (u_char) val & 0xff;
|
||||
saw_xdigit = 0;
|
||||
val = 0;
|
||||
continue;
|
||||
}
|
||||
if (ch == '.' && ((tp + 4) <= endp) &&
|
||||
parse_ipv4(curtok, (uint32_t *)tp, bytes) > 0) {
|
||||
tp += 4;
|
||||
saw_xdigit = 0;
|
||||
break; /* '\0' was seen by parse_ipv4(). */
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
if (saw_xdigit) {
|
||||
if (tp + sizeof(uint16_t) > endp)
|
||||
return (0);
|
||||
*tp++ = (u_char) (val >> 8) & 0xff;
|
||||
*tp++ = (u_char) val & 0xff;
|
||||
}
|
||||
if (colonp != NULL) {
|
||||
/*
|
||||
* Since some memmove()'s erroneously fail to handle
|
||||
* overlapping regions, we'll do the shift by hand.
|
||||
*/
|
||||
const int n = tp - colonp;
|
||||
int i;
|
||||
|
||||
for (i = 1; i <= n; i++) {
|
||||
endp[- i] = colonp[n - i];
|
||||
colonp[n - i] = 0;
|
||||
}
|
||||
tp = endp;
|
||||
}
|
||||
*bytes = 16 - ( endp - tp );
|
||||
|
||||
memcpy(dst, tmp, sizeof(tmp));
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int lookup_host(const char *hostname, uint64_t *iplist, uint32_t *num_ip ) {
|
||||
struct addrinfo hints, *res, *r;
|
||||
int errcode, i, len;
|
||||
char addrstr[128];
|
||||
char reverse[256];
|
||||
void *ptr;
|
||||
|
||||
printf("Resolving %s ...\n", hostname);
|
||||
|
||||
memset (&hints, 0, sizeof (hints));
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags |= AI_CANONNAME;
|
||||
|
||||
errcode = getaddrinfo (hostname, NULL, &hints, &res);
|
||||
if (errcode != 0) {
|
||||
fprintf(stderr, "Failed to resolve IP address for %s: %s\n", hostname, gai_strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// count the number of records found
|
||||
*num_ip = 0;
|
||||
|
||||
// remember res for later free()
|
||||
r = res;
|
||||
|
||||
i = 0;
|
||||
while (res) {
|
||||
if ( *num_ip >= MAXHOSTS ) {
|
||||
printf ("Too man IP addresses in DNS response\n");
|
||||
return 1;
|
||||
}
|
||||
switch (res->ai_family) {
|
||||
case PF_INET:
|
||||
ptr = &(((struct sockaddr_in *) res->ai_addr)->sin_addr);
|
||||
iplist[i++] = 0;
|
||||
iplist[i++] = ntohl(*(uint32_t *)ptr) & 0xffffffffLL ;
|
||||
len = sizeof(struct sockaddr_in);
|
||||
break;
|
||||
case AF_INET6:
|
||||
ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
|
||||
iplist[i++] = ntohll(((uint64_t *)ptr)[0]);
|
||||
iplist[i++] = ntohll(((uint64_t *)ptr)[1]);
|
||||
len = sizeof(struct sockaddr_in6);
|
||||
break;
|
||||
default: {
|
||||
// not handled
|
||||
res = res->ai_next;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
inet_ntop (res->ai_family, ptr, addrstr, 100);
|
||||
addrstr[99] = '\0';
|
||||
if ( (errcode = getnameinfo(res->ai_addr, len, reverse, sizeof(reverse), NULL,0,0)) != 0 ) {
|
||||
snprintf(reverse, sizeof(reverse)-1, "<reverse lookup failed>");
|
||||
// fprintf(stderr, "Failed to reverse lookup %s: %s\n", addrstr, gai_strerror(errcode));
|
||||
}
|
||||
|
||||
printf ("IPv%d address: %s (%s)\n", res->ai_family == PF_INET6 ? 6 : 4, addrstr, reverse );
|
||||
res = res->ai_next;
|
||||
(*num_ip)++;
|
||||
}
|
||||
|
||||
freeaddrinfo(r);
|
||||
return 1;
|
||||
|
||||
} // End of lookup_host
|
||||
|
||||
int set_nameserver(char *ns) {
|
||||
struct hostent *host;
|
||||
|
||||
res_init();
|
||||
host = gethostbyname(ns);
|
||||
if (host == NULL) {
|
||||
(void) fprintf(stderr,"Can not resolv nameserver %s: %s\n", ns, hstrerror(h_errno));
|
||||
return 0;
|
||||
}
|
||||
(void) memcpy((void *)&_res.nsaddr_list[0].sin_addr, (void *)host->h_addr_list[0], (size_t)host->h_length);
|
||||
_res.nscount = 1;
|
||||
return 1;
|
||||
|
||||
} // End of set_nameserver
|
||||
|
||||
|
||||
/*
|
||||
int main( int argc, char **argv ) {
|
||||
|
||||
char *s, t[64];
|
||||
uint64_t anyaddr[2];
|
||||
uint32_t num_ip;
|
||||
int af, ret, bytes;
|
||||
|
||||
|
||||
s = argv[1];
|
||||
if (argc == 3 && !set_nameserver(argv[2]) )
|
||||
return 0;
|
||||
|
||||
lookup_host(s, &num_ip);
|
||||
return 0;
|
||||
|
||||
ret = parse_ip(&af, s, anyaddr, &bytes);
|
||||
if ( ret != 1 ) {
|
||||
printf("Parse failed!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( af == PF_INET )
|
||||
inet_ntop(af, &(((uint32_t *)anyaddr)[3]), t, 64);
|
||||
else
|
||||
inet_ntop(af, anyaddr, t, 64);
|
||||
|
||||
printf("Convert back: %s => %s %i bytes\n", s, t, bytes);
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
52
bin/ipconv.h
Executable file
52
bin/ipconv.h
Executable file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author:$
|
||||
*
|
||||
* $Id:$
|
||||
*
|
||||
* $LastChangedRevision:$
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _IPCONV_H
|
||||
#define _IPCONV_H 1
|
||||
|
||||
int parse_ip(int *af, const char *src, uint64_t *dst, int *bytes, int lookup, uint32_t *num_ip );
|
||||
|
||||
int set_nameserver(char *ns);
|
||||
|
||||
#define MAXHOSTS 512
|
||||
|
||||
#define STRICT_IP 0
|
||||
#define ALLOW_LOOKUP 1
|
||||
|
||||
#endif //_IPCONV_H
|
1742
bin/ipfix.c
Normal file
1742
bin/ipfix.c
Normal file
File diff suppressed because it is too large
Load Diff
268
bin/ipfix.h
Normal file
268
bin/ipfix.h
Normal file
@ -0,0 +1,268 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author:$
|
||||
*
|
||||
* $Id:$
|
||||
*
|
||||
* $LastChangedRevision:$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _IPFIX_H
|
||||
#define _IPFIX_H 1
|
||||
|
||||
/* reference: http://tools.ietf.org/html/draft-ietf-ipfix-protocol-rfc5101bis-00 */
|
||||
|
||||
typedef struct ipfix_header {
|
||||
uint16_t Version; // set to 10 for IPFIX
|
||||
uint16_t Length; // Total length incl. this header. up to 65535 bytes
|
||||
uint32_t ExportTime; // UNIC epoch export Time of flow.
|
||||
uint32_t LastSequence; // Incremental sequence counter modulo 2^32 of all IPFIX Data Records
|
||||
uint32_t ObservationDomain; // identifier , unique to the exporter
|
||||
} ipfix_header_t;
|
||||
|
||||
#define IPFIX_HEADER_LENGTH sizeof(ipfix_header_t)
|
||||
|
||||
/*
|
||||
Message Header Field Descriptions:
|
||||
|
||||
Version
|
||||
|
||||
Version of Flow Record format exported in this message. The value
|
||||
of this field is 0x000a for the current version, incrementing by
|
||||
one the version used in the NetFlow services export version 9
|
||||
[RFC3954].
|
||||
|
||||
Length
|
||||
|
||||
Total length of the IPFIX Message, measured in octets, including
|
||||
Message Header and Set(s).
|
||||
|
||||
Export Time
|
||||
|
||||
Time at which the IPFIX Message Header leaves the Exporter,
|
||||
expressed in seconds since the UNIX epoch of 1 January 1970 at
|
||||
00:00 UTC, encoded as an unsigned 32-bit integer.
|
||||
|
||||
Sequence Number
|
||||
|
||||
Incremental sequence counter modulo 2^32 of all IPFIX Data Records
|
||||
sent on this PR-SCTP stream from the current Observation Domain by
|
||||
the Exporting Process. Check the specific meaning of this field
|
||||
in the subsections of Section 10 when UDP or TCP is selected as
|
||||
the transport protocol. This value SHOULD be used by the
|
||||
Collecting Process to identify whether any IPFIX Data Records have
|
||||
been missed. Template and Options Template Records do not
|
||||
increase the Sequence Number.
|
||||
|
||||
Observation Domain ID
|
||||
|
||||
A 32-bit identifier of the Observation Domain that is locally
|
||||
unique to the Exporting Process. The Exporting Process uses the
|
||||
Observation Domain ID to uniquely identify to the Collecting
|
||||
Process the Observation Domain that metered the Flows. It is
|
||||
RECOMMENDED that this identifier also be unique per IPFIX Device.
|
||||
|
||||
Collecting Processes SHOULD use the Transport Session and the
|
||||
Observation Domain ID field to separate different export streams
|
||||
originating from the same Exporter. The Observation Domain ID
|
||||
SHOULD be 0 when no specific Observation Domain ID is relevant for
|
||||
the entire IPFIX Message, for example, when exporting the
|
||||
Exporting Process Statistics, or in case of a hierarchy of
|
||||
Collectors when aggregated Data Records are exported.
|
||||
|
||||
*/
|
||||
|
||||
/* set format:
|
||||
A Set has the format shown in Figure H. The record types can be
|
||||
either Template Records, Options Template Records, or Data Records.
|
||||
The record types MUST NOT be mixed within a Set.
|
||||
|
||||
+--------------------------------------------------+
|
||||
| Set Header |
|
||||
+--------------------------------------------------+
|
||||
| record |
|
||||
+--------------------------------------------------+
|
||||
| record |
|
||||
+--------------------------------------------------+
|
||||
...
|
||||
+--------------------------------------------------+
|
||||
| record |
|
||||
+--------------------------------------------------+
|
||||
| Padding (opt.) |
|
||||
+--------------------------------------------------+
|
||||
*/
|
||||
|
||||
typedef struct set_header_s {
|
||||
uint16_t SetID; // SetIDs:
|
||||
// 0, 1: not used
|
||||
// 2: Template Set
|
||||
// 3: Options Template Set
|
||||
#define IPFIX_TEMPLATE_FLOWSET_ID 2
|
||||
#define IPFIX_OPTIONS_FLOWSET_ID 3
|
||||
#define IPFIX_MIN_RECORD_FLOWSET_ID 256
|
||||
uint16_t Length; // Length of bytes incl. this header
|
||||
uint32_t records[1]; // pointer to records
|
||||
} set_header_t;
|
||||
|
||||
/* Template Record Format
|
||||
The format of the Template Record is shown in Figure J. It consists
|
||||
of a Template Record Header and one or more Field Specifiers. The
|
||||
definition of the Field Specifiers is given in Figure G above.
|
||||
|
||||
+--------------------------------------------------+
|
||||
| Template Record Header |
|
||||
+--------------------------------------------------+
|
||||
| Field Specifier |
|
||||
+--------------------------------------------------+
|
||||
| Field Specifier |
|
||||
+--------------------------------------------------+
|
||||
...
|
||||
+--------------------------------------------------+
|
||||
| Field Specifier |
|
||||
+--------------------------------------------------+
|
||||
*/
|
||||
|
||||
typedef struct ipfix_template_record_s {
|
||||
uint16_t TemplateID; // Template ID:
|
||||
// 0-255 reserved for Template Sets, Options Template Sets,
|
||||
// and other reserved Sets yet to be created.
|
||||
// 256-65535 Template IDs of Data Sets
|
||||
uint16_t FieldCount;
|
||||
uint32_t elements[1];
|
||||
} ipfix_template_record_t;
|
||||
|
||||
/* Standard Information Elements
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|0| Information Element ident. | Field Length |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
typedef struct ipfix_template_elements_std_s {
|
||||
uint16_t Type;
|
||||
uint16_t Length;
|
||||
} ipfix_template_elements_std_t;
|
||||
|
||||
/* enterprise-specific Information Elements
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|1| Information Element ident. | Field Length |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Enterprise Number |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
typedef struct ipfix_template_elements_e_s {
|
||||
uint16_t Type;
|
||||
uint16_t Length;
|
||||
uint32_t EnterpriseNumber;
|
||||
} ipfix_template_elements_e_t;
|
||||
|
||||
#define _1byte 1
|
||||
#define _2bytes 2
|
||||
#define _3bytes 3
|
||||
#define _4bytes 4
|
||||
#define _6bytes 6
|
||||
#define _8bytes 8
|
||||
#define _16bytes 16
|
||||
|
||||
// IPFIX std element definitios
|
||||
// Flowset record types
|
||||
#define IPFIX_octetDeltaCount 1
|
||||
#define IPFIX_packetDeltaCount 2
|
||||
// reserved 3
|
||||
#define IPFIX_FLOWS_AGGR 3
|
||||
#define IPFIX_protocolIdentifier 4
|
||||
#define IPFIX_ipClassOfService 5
|
||||
#define IPFIX_tcpControlBits 6
|
||||
#define IPFIX_SourceTransportPort 7
|
||||
#define IPFIX_SourceIPv4Address 8
|
||||
#define IPFIX_SourceIPv4PrefixLength 9
|
||||
#define IPFIX_ingressInterface 10
|
||||
#define IPFIX_DestinationTransportPort 11
|
||||
#define IPFIX_DestinationIPv4Address 12
|
||||
#define IPFIX_DestinationIPv4PrefixLength 13
|
||||
#define IPFIX_egressInterface 14
|
||||
#define IPFIX_ipNextHopIPv4Address 15
|
||||
#define IPFIX_bgpSourceAsNumber 16
|
||||
#define IPFIX_bgpDestinationAsNumber 17
|
||||
#define IPFIX_bgpNextHopIPv4Address 18
|
||||
|
||||
#define IPFIX_flowEndSysUpTime 21
|
||||
#define IPFIX_flowStartSysUpTime 22
|
||||
#define IPFIX_postOctetDeltaCount 23
|
||||
#define IPFIX_postPacketDeltaCount 24
|
||||
#define IPFIX_SourceIPv6Address 27
|
||||
#define IPFIX_DestinationIPv6Address 28
|
||||
#define IPFIX_SourceIPv6PrefixLength 29
|
||||
#define IPFIX_DestinationIPv6PrefixLength 30
|
||||
#define IPFIX_flowLabelIPv6 31
|
||||
#define IPFIX_icmpTypeCodeIPv4 32
|
||||
// reserved 34, 35
|
||||
// reserved 38, 39
|
||||
// reserved 48, 49, 50, 51
|
||||
|
||||
// #define IPFIX_MIN_TTL 52
|
||||
// #define IPFIX_MAX_TTL 53
|
||||
// #define IPFIX_IPV4_IDENT 54
|
||||
|
||||
#define IPFIX_postIpClassOfService 55
|
||||
#define IPFIX_SourceMacAddress 56
|
||||
#define IPFIX_postDestinationMacAddress 57
|
||||
#define IPFIX_vlanId 58
|
||||
#define IPFIX_postVlanId 59
|
||||
|
||||
#define IPFIX_flowDirection 61
|
||||
#define IPFIX_ipNextHopIPv6Address 62
|
||||
#define IPFIX_bgpNextHopIPv6Address 63
|
||||
|
||||
#define IPFIX_mplsTopLabelStackSection 70
|
||||
#define IPFIX_mplsLabelStackSection2 71
|
||||
#define IPFIX_mplsLabelStackSection3 72
|
||||
#define IPFIX_mplsLabelStackSection4 73
|
||||
#define IPFIX_mplsLabelStackSection5 74
|
||||
#define IPFIX_mplsLabelStackSection6 75
|
||||
#define IPFIX_mplsLabelStackSection7 76
|
||||
#define IPFIX_mplsLabelStackSection8 77
|
||||
#define IPFIX_mplsLabelStackSection9 78
|
||||
#define IPFIX_mplsLabelStackSection10 79
|
||||
#define IPFIX_DestinationMacAddress 80
|
||||
#define IPFIX_postSourceMacAddress 81
|
||||
#define IPFIX_octetTotalCount 85
|
||||
#define IPFIX_packetTotalCount 86
|
||||
#define IPFIX_flowStartMilliseconds 152
|
||||
#define IPFIX_flowEndMilliseconds 153
|
||||
// reserved 89
|
||||
|
||||
/* prototypes */
|
||||
int Init_IPFIX(void);
|
||||
|
||||
void Process_IPFIX(void *in_buff, ssize_t in_buff_cnt, FlowSource_t *fs);
|
||||
|
||||
#endif //_IPFIX_H 1
|
302
bin/ipfrag.c
Normal file
302
bin/ipfrag.c
Normal file
@ -0,0 +1,302 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: phaag $
|
||||
*
|
||||
* $Id: ipfrag.c 40874 2014-03-06 09:58:20Z phaag $
|
||||
*
|
||||
* $LastChangedRevision: 40874 $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "rbtree.h"
|
||||
#include "ipfrag.h"
|
||||
|
||||
#ifndef DEVEL
|
||||
# define dbg_printf(...) /* printf(__VA_ARGS__) */
|
||||
#else
|
||||
# define dbg_printf(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define KEYLEN (offsetof(IPFragNode_t,data_size) - offsetof(IPFragNode_t, src_addr))
|
||||
static int IPFragNodeCMP(struct IPFragNode *e1, struct IPFragNode *e2);
|
||||
|
||||
static struct IPFragNode *New_node(void);
|
||||
|
||||
static void Free_node(struct IPFragNode *node, int free_data);
|
||||
|
||||
static void Remove_node(struct IPFragNode *node);
|
||||
|
||||
// Insert the IP RB tree code here
|
||||
RB_GENERATE(IPFragTree, IPFragNode, entry, IPFragNodeCMP);
|
||||
|
||||
static IPFragTree_t *IPFragTree;
|
||||
|
||||
static int IPFragNodeCMP(struct IPFragNode *e1, struct IPFragNode *e2) {
|
||||
uint32_t *a = &e1->src_addr;
|
||||
uint32_t *b = &e2->src_addr;
|
||||
int i;
|
||||
|
||||
// 2 x sizeof(uint32_t) (8) + frag_offset == 12
|
||||
i = memcmp((void *)a, (void *)b, KEYLEN );
|
||||
return i;
|
||||
|
||||
} // End of IPFragNodeCMP
|
||||
|
||||
static struct IPFragNode *New_node(void) {
|
||||
struct IPFragNode *node;
|
||||
|
||||
node = malloc(sizeof(struct IPFragNode));
|
||||
if ( !node ) {
|
||||
LogError("malloc() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
return NULL;
|
||||
}
|
||||
memset((void *)node, 0, sizeof(struct IPFragNode));
|
||||
|
||||
node->data = malloc(IP_MAXPACKET);
|
||||
if ( !node->data ) {
|
||||
LogError("malloc() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
free(node);
|
||||
return NULL;
|
||||
}
|
||||
memset(node->data, 0, IP_MAXPACKET);
|
||||
|
||||
node->eod = node->data;
|
||||
node->data_size = 0;
|
||||
|
||||
node->holes = malloc(sizeof(hole_t));
|
||||
if ( !node->holes ) {
|
||||
LogError("malloc() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
free(node);
|
||||
return NULL;
|
||||
}
|
||||
node->holes->next = NULL;
|
||||
node->holes->first = 0;
|
||||
node->holes->last = IP_MAXPACKET;
|
||||
|
||||
return node;
|
||||
|
||||
} // End of New_node
|
||||
|
||||
static void Free_node(struct IPFragNode *node, int free_data) {
|
||||
hole_t *hole, *h;
|
||||
|
||||
hole = node->holes;
|
||||
while (hole) {
|
||||
h = hole->next;
|
||||
free(hole);
|
||||
hole = h;
|
||||
}
|
||||
if ( free_data)
|
||||
free(node->data);
|
||||
free(node);
|
||||
|
||||
} // End of Free_node
|
||||
|
||||
static void Remove_node(struct IPFragNode *node) {
|
||||
struct IPFragNode *n;
|
||||
|
||||
n = RB_REMOVE(IPFragTree, IPFragTree, node);
|
||||
if ( n ) {
|
||||
Free_node(n, 0);
|
||||
} // else - node not in tree
|
||||
|
||||
} // End of Remove_node
|
||||
|
||||
int IPFragTree_init(void) {
|
||||
IPFragTree = malloc(sizeof(IPFragTree_t));
|
||||
if ( !IPFragTree ) {
|
||||
LogError("malloc() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
return 0;
|
||||
}
|
||||
RB_INIT(IPFragTree);
|
||||
dbg_printf("IPFrag key len: %lu\n", KEYLEN);
|
||||
return 1;
|
||||
} // End of IPFragTree_init
|
||||
|
||||
void IPFragTree_free(void) {
|
||||
struct IPFragNode *node, *nxt;
|
||||
|
||||
// Dump all incomplete flows to the file
|
||||
for (node = RB_MIN(IPFragTree, IPFragTree); node != NULL; node = nxt) {
|
||||
nxt = RB_NEXT(IPFragTree, IPFragTree, node);
|
||||
RB_REMOVE(IPFragTree, IPFragTree, node);
|
||||
Free_node(node, 1);
|
||||
}
|
||||
|
||||
free(IPFragTree);
|
||||
IPFragTree = NULL;
|
||||
} // End of IPFragTree_free
|
||||
|
||||
void *IPFrag_tree_Update(uint32_t src, uint32_t dst, uint32_t ident, uint32_t *length, uint32_t ip_off, void *data) {
|
||||
struct IPFragNode FindNode, *n;
|
||||
hole_t *hole, *h, *hole_parent;
|
||||
uint16_t more_fragments, first, last, max;
|
||||
int found_hole;
|
||||
|
||||
FindNode.src_addr = src;
|
||||
FindNode.dst_addr = dst;
|
||||
FindNode.ident = ident;
|
||||
n = RB_FIND(IPFragTree, IPFragTree, &FindNode);
|
||||
if ( !n ) {
|
||||
n = New_node();
|
||||
n->src_addr = src;
|
||||
n->dst_addr = dst;
|
||||
n->ident = ident;
|
||||
if ( RB_INSERT(IPFragTree, IPFragTree, n) ) {
|
||||
// must never happen
|
||||
LogError("Node insert returned existing node - Software error in %s line %d", __FILE__, __LINE__);
|
||||
}
|
||||
}
|
||||
hole = n->holes;
|
||||
hole_parent = NULL;
|
||||
|
||||
first = (ip_off & IP_OFFMASK) << 3;
|
||||
more_fragments = (ip_off & IP_MF) != 0 ? 1 : 0;
|
||||
last = first + *length - 1;
|
||||
|
||||
if ( last > IP_MAXPACKET ) {
|
||||
LogError("Fragment assembly error: last > IP_MAXPACKET");
|
||||
LogError("Fraget assembly: first: %u, last: %u, MF: %u\n", first, last, more_fragments);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// last fragment - sets max offset
|
||||
found_hole = 0;
|
||||
max = more_fragments == 0 ? last : 0;
|
||||
dbg_printf("Fraget assembly: first: %u, last: %u, MF: %u\n", first, last, more_fragments);
|
||||
while (hole) {
|
||||
uint16_t hole_last;
|
||||
if ( max ) {
|
||||
dbg_printf("max in last fragment: %u\n", max);
|
||||
// last fragment offset/length
|
||||
if ( hole->last == IP_MAXPACKET ) {
|
||||
// last fragment has max size
|
||||
if ( max > hole->first ) {
|
||||
dbg_printf("set max of last fragment: %u\n", max);
|
||||
hole->last = max;
|
||||
} else {
|
||||
LogError("last fragment offset error - teardrop attack??");
|
||||
}
|
||||
} else {
|
||||
// last fragment must always be max offset
|
||||
if ( max < hole->last ) {
|
||||
LogError("last fragment offset error - teardrop attack??");
|
||||
}
|
||||
}
|
||||
}
|
||||
dbg_printf("Check Hole: first: %u, last: %u\n", hole->first, hole->last);
|
||||
|
||||
if ( first > hole->last ) {
|
||||
hole_parent = hole;
|
||||
hole = hole->next;
|
||||
dbg_printf("Fragment right outside hole\n");
|
||||
continue;
|
||||
}
|
||||
if ( last < hole->first ) {
|
||||
hole_parent = hole;
|
||||
hole = hole->next;
|
||||
dbg_printf("Fragment left outside hole\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// fragment fits into hole
|
||||
found_hole = 1;
|
||||
if ( last > n->data_size )
|
||||
n->data_size = last;
|
||||
|
||||
hole_last = hole->last;
|
||||
if ( first == hole->first ) {
|
||||
dbg_printf("Fragment matches first\n");
|
||||
// fragment fits at beginning of hole
|
||||
if ( last == hole->last ) {
|
||||
dbg_printf("Fragment matches last\n");
|
||||
// fragment fits completly into hole - delete hole
|
||||
if ( hole_parent ) {
|
||||
hole_parent->next = hole->next;
|
||||
} else {
|
||||
n->holes = NULL;
|
||||
}
|
||||
free(hole);
|
||||
hole = NULL;
|
||||
} else {
|
||||
// fragment smaller than hole
|
||||
dbg_printf("Fragment smaller than hole\n");
|
||||
hole->first = last+1;
|
||||
}
|
||||
} else {
|
||||
// fragment start within hole
|
||||
dbg_printf("Fragment inside hole\n");
|
||||
hole->last = first - 1;
|
||||
if ( last < hole_last ) {
|
||||
// fragment ends within hole - add another hole
|
||||
h = malloc(sizeof(hole_t));
|
||||
if ( !h ) {
|
||||
LogError("malloc() error in %s line %d: %s", __FILE__, __LINE__, strerror(errno) );
|
||||
return NULL;
|
||||
}
|
||||
h->first = last + 1;
|
||||
h->last = hole_last;
|
||||
h->next = n->holes;
|
||||
n->holes = h;
|
||||
}
|
||||
}
|
||||
memcpy(n->data + first, data, *length);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !found_hole )
|
||||
LogError("No space - Fragment overlap: first: %u, last: %u\n", first, last);
|
||||
|
||||
if ( n->holes == NULL ) {
|
||||
void *data = n->data;
|
||||
n->data_size++;
|
||||
*length = n->data_size;
|
||||
Remove_node(n);
|
||||
dbg_printf("Datagramm complete - size: %u\n", n->data_size);
|
||||
return data;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // End of IPFrag_tree_Update
|
74
bin/ipfrag.h
Normal file
74
bin/ipfrag.h
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: phaag $
|
||||
*
|
||||
* $Id: ipfrag.h 40691 2014-03-03 11:24:22Z phaag $
|
||||
*
|
||||
* $LastChangedRevision: 40691 $
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct hole_s {
|
||||
struct hole_s *next;
|
||||
uint32_t first;
|
||||
uint32_t last;
|
||||
} hole_t;
|
||||
|
||||
struct IPFragNode {
|
||||
// tree
|
||||
RB_ENTRY(IPFragNode) entry;
|
||||
|
||||
// flow key
|
||||
// IP addr
|
||||
uint32_t src_addr;
|
||||
uint32_t dst_addr;
|
||||
uint32_t ident;
|
||||
// End of flow key
|
||||
|
||||
uint32_t data_size;
|
||||
// packet data
|
||||
void *data;
|
||||
void *eod;
|
||||
hole_t *holes;
|
||||
};
|
||||
|
||||
typedef struct IPFragNode IPFragNode_t;
|
||||
|
||||
/* flow tree type */
|
||||
typedef RB_HEAD(IPFragTree, IPFragNode) IPFragTree_t;
|
||||
|
||||
// Insert the RB prototypes here
|
||||
RB_PROTOTYPE(IPFragTree, IPFragNode, entry, IPFragNodeCMP);
|
||||
|
||||
int IPFragTree_init(void);
|
||||
|
||||
void IPFragTree_free(void);
|
||||
|
||||
void *IPFrag_tree_Update(uint32_t src, uint32_t dst, uint32_t ident, uint32_t *length, uint32_t ip_off, void *data);
|
||||
|
440
bin/launch.c
Normal file
440
bin/launch.c
Normal file
@ -0,0 +1,440 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: launch.c 69 2010-09-09 07:17:43Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 69 $
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/socket.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "nfstatfile.h"
|
||||
#include "bookkeeper.h"
|
||||
|
||||
#ifdef HAVE_FTS_H
|
||||
# include <fts.h>
|
||||
#else
|
||||
# include "fts_compat.h"
|
||||
#define fts_children fts_children_compat
|
||||
#define fts_close fts_close_compat
|
||||
#define fts_open fts_open_compat
|
||||
#define fts_read fts_read_compat
|
||||
#define fts_set fts_set_compat
|
||||
#endif
|
||||
|
||||
#include "expire.h"
|
||||
#include "nffile.h"
|
||||
#include "nfxstat.h"
|
||||
#include "collector.h"
|
||||
|
||||
static int done, launch, child_exit;
|
||||
|
||||
static void SignalHandler(int signal);
|
||||
|
||||
static char *cmd_expand(srecord_t *InfoRecord, char *ident, char *datadir, char *process);
|
||||
|
||||
static void cmd_parse(char *buf, char **args);
|
||||
|
||||
static void cmd_execute(char **args);
|
||||
|
||||
static void do_expire(char *datadir);
|
||||
|
||||
#define MAXARGS 256
|
||||
#define MAXCMDLEN 4096
|
||||
|
||||
static void SignalHandler(int signal) {
|
||||
|
||||
switch (signal) {
|
||||
case SIGTERM:
|
||||
// in case the process will not terminate, we
|
||||
// kill the process directly after the 2nd TERM signal
|
||||
if ( done > 1 )
|
||||
exit(234);
|
||||
done++;
|
||||
break;
|
||||
case SIGHUP:
|
||||
launch = 1;
|
||||
break;
|
||||
case SIGCHLD:
|
||||
child_exit++;
|
||||
break;
|
||||
}
|
||||
|
||||
} /* End of IntHandler */
|
||||
|
||||
/*
|
||||
* Expand % placeholders in command string
|
||||
* expand the memory needed in the command string and replace placeholders
|
||||
* prevent endless expansion
|
||||
*/
|
||||
static char *cmd_expand(srecord_t *InfoRecord, char *ident, char *datadir, char *process) {
|
||||
char *q, *s, tmp[16];
|
||||
int i;
|
||||
|
||||
q = strdup(process);
|
||||
if ( !q ) {
|
||||
perror("Process cmdline");
|
||||
return NULL;
|
||||
}
|
||||
i = 0;
|
||||
|
||||
while ( q[i] ) {
|
||||
if ( (q[i] == '%') && q[i+1] ) {
|
||||
// replace the %x var
|
||||
switch ( q[i+1] ) {
|
||||
case 'd' :
|
||||
s = datadir;
|
||||
break;
|
||||
case 'f' :
|
||||
s = InfoRecord->fname;
|
||||
break;
|
||||
case 't' :
|
||||
s = InfoRecord->tstring;
|
||||
break;
|
||||
case 'u' :
|
||||
#if defined __OpenBSD__ || defined __FreeBSD__
|
||||
snprintf(tmp, 16, "%i", InfoRecord->tstamp);
|
||||
#else
|
||||
snprintf(tmp, 16, "%li", InfoRecord->tstamp);
|
||||
#endif
|
||||
tmp[15] = 0;
|
||||
s = tmp;
|
||||
break;
|
||||
case 'i' :
|
||||
s = ident;
|
||||
break;
|
||||
default:
|
||||
syslog(LOG_ERR, "Unknown format token '%%%c'\n", q[i+1]);
|
||||
s = NULL;
|
||||
}
|
||||
if ( s ) {
|
||||
q = realloc(q, strlen(q) + strlen(s));
|
||||
if ( !q ) {
|
||||
perror("Process cmdline");
|
||||
return NULL;
|
||||
}
|
||||
// be a bit paranoid and prevent endless expansion
|
||||
if ( strlen(q) > MAXCMDLEN ) {
|
||||
// this is fishy
|
||||
syslog(LOG_ERR, "Error: cmdline too long!\n");
|
||||
return NULL;
|
||||
}
|
||||
memmove(&q[i] + strlen(s), &q[i+2], strlen(&q[i+2]) + 1); // include trailing '0' in memmove
|
||||
memcpy(&q[i], s, strlen(s));
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return q;
|
||||
|
||||
} // End of cmd_expand
|
||||
|
||||
/*
|
||||
* split the command in buf into individual arguments.
|
||||
*/
|
||||
static void cmd_parse(char *buf, char **args) {
|
||||
int i, argnum;
|
||||
|
||||
i = argnum = 0;
|
||||
while ( (i < MAXCMDLEN) && (buf[i] != 0) ) {
|
||||
|
||||
/*
|
||||
* Strip whitespace. Use nulls, so
|
||||
* that the previous argument is terminated
|
||||
* automatically.
|
||||
*/
|
||||
while ( (i < MAXCMDLEN) && ((buf[i] == ' ') || (buf[i] == '\t')))
|
||||
buf[i++] = 0;
|
||||
|
||||
/*
|
||||
* Save the argument.
|
||||
*/
|
||||
if ( argnum < MAXARGS )
|
||||
args[argnum++] = &(buf[i]);
|
||||
|
||||
/*
|
||||
* Skip over the argument.
|
||||
*/
|
||||
while ( (i < MAXCMDLEN) && ((buf[i] != 0) && (buf[i] != ' ') && (buf[i] != '\t')))
|
||||
i++;
|
||||
}
|
||||
|
||||
if ( argnum < MAXARGS )
|
||||
args[argnum] = NULL;
|
||||
|
||||
if ( (i >= MAXCMDLEN) || (argnum >= MAXARGS) ) {
|
||||
// for safety reason, disable the command
|
||||
args[0] = NULL;
|
||||
syslog(LOG_ERR, "Launcher: Unable to parse command: '%s'", buf);
|
||||
}
|
||||
|
||||
} // End of cmd_parse
|
||||
|
||||
/*
|
||||
* cmd_execute
|
||||
* spawn a child process and execute the program.
|
||||
*/
|
||||
static void cmd_execute(char **args) {
|
||||
int pid;
|
||||
|
||||
// Get a child process.
|
||||
syslog(LOG_DEBUG, "Launcher: fork child.");
|
||||
if ((pid = fork()) < 0) {
|
||||
syslog(LOG_ERR, "Can't fork: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if (pid == 0) { // we are the child
|
||||
execvp(*args, args);
|
||||
syslog(LOG_ERR, "Can't execvp: %s: %s", args[0], strerror(errno));
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
// we are the parent
|
||||
syslog(LOG_DEBUG, "Launcher: child exec done.");
|
||||
/* empty */
|
||||
|
||||
} // End of cmd_execute
|
||||
|
||||
static void do_expire(char *datadir) {
|
||||
bookkeeper_t *books;
|
||||
dirstat_t *dirstat, oldstat;
|
||||
int ret, bookkeeper_stat, do_rescan;
|
||||
|
||||
syslog(LOG_INFO, "Run expire on '%s'", datadir);
|
||||
|
||||
do_rescan = 0;
|
||||
ret = ReadStatInfo(datadir, &dirstat, CREATE_AND_LOCK);
|
||||
switch (ret) {
|
||||
case STATFILE_OK:
|
||||
break;
|
||||
case ERR_NOSTATFILE:
|
||||
dirstat->low_water = 95;
|
||||
case FORCE_REBUILD:
|
||||
syslog(LOG_INFO, "Force rebuild stat record");
|
||||
do_rescan = 1;
|
||||
break;
|
||||
case ERR_FAIL:
|
||||
syslog(LOG_ERR, "expire failed: can't read stat record");
|
||||
return;
|
||||
/* not reached */
|
||||
break;
|
||||
default:
|
||||
syslog(LOG_ERR, "expire failed: unexpected return code %i reading stat record", ret);
|
||||
return;
|
||||
/* not reached */
|
||||
}
|
||||
|
||||
bookkeeper_stat = AccessBookkeeper(&books, datadir);
|
||||
if ( do_rescan ) {
|
||||
RescanDir(datadir, dirstat);
|
||||
if ( bookkeeper_stat == BOOKKEEPER_OK ) {
|
||||
ClearBooks(books, NULL);
|
||||
// release the books below
|
||||
}
|
||||
}
|
||||
|
||||
if ( bookkeeper_stat == BOOKKEEPER_OK ) {
|
||||
bookkeeper_t tmp_books;
|
||||
ClearBooks(books, &tmp_books);
|
||||
UpdateBookStat(dirstat, &tmp_books);
|
||||
ReleaseBookkeeper(books, DETACH_ONLY);
|
||||
} else {
|
||||
syslog(LOG_ERR, "Error %i: can't access book keeping records", ret);
|
||||
}
|
||||
|
||||
syslog(LOG_INFO, "Limits: Filesize %s, Lifetime %s, Watermark: %llu%%\n",
|
||||
dirstat->max_size ? ScaleValue(dirstat->max_size) : "<none>",
|
||||
dirstat->max_lifetime ? ScaleTime(dirstat->max_lifetime) : "<none>",
|
||||
(unsigned long long)dirstat->low_water);
|
||||
|
||||
syslog(LOG_INFO, "Current size: %s, Current lifetime: %s, Number of files: %llu",
|
||||
ScaleValue(dirstat->filesize),
|
||||
ScaleTime(dirstat->last - dirstat->first),
|
||||
(unsigned long long)dirstat->numfiles);
|
||||
|
||||
oldstat = *dirstat;
|
||||
if ( dirstat->max_size || dirstat->max_lifetime )
|
||||
ExpireDir(datadir, dirstat, dirstat->max_size, dirstat->max_lifetime, 0);
|
||||
WriteStatInfo(dirstat);
|
||||
|
||||
if ( (oldstat.numfiles - dirstat->numfiles) > 0 ) {
|
||||
syslog(LOG_INFO, "expire completed");
|
||||
syslog(LOG_INFO, " expired files: %llu", (unsigned long long)(oldstat.numfiles - dirstat->numfiles));
|
||||
syslog(LOG_INFO, " expired time slot: %s", ScaleTime(dirstat->first - oldstat.first));
|
||||
syslog(LOG_INFO, " expired file size: %s", ScaleValue(oldstat.filesize - dirstat->filesize));
|
||||
syslog(LOG_INFO, "New size: %s, New lifetime: %s, Number of files: %llu",
|
||||
ScaleValue(dirstat->filesize),
|
||||
ScaleTime(dirstat->last - dirstat->first),
|
||||
(unsigned long long)dirstat->numfiles);
|
||||
} else {
|
||||
syslog(LOG_INFO, "expire completed - nothing to expire.");
|
||||
}
|
||||
ReleaseStatInfo(dirstat);
|
||||
|
||||
} // End of do_expire
|
||||
|
||||
void launcher (char *commbuff, FlowSource_t *FlowSource, char *process, int expire) {
|
||||
FlowSource_t *fs;
|
||||
struct sigaction act;
|
||||
char *args[MAXARGS];
|
||||
int pid, stat;
|
||||
srecord_t *InfoRecord;
|
||||
|
||||
InfoRecord = (srecord_t *)commbuff;
|
||||
|
||||
syslog(LOG_INFO, "Launcher: Startup. auto-expire %s", expire ? "enabled" : "off" );
|
||||
done = launch = child_exit = 0;
|
||||
|
||||
// process may be NULL, if we only expire data files
|
||||
if ( process ) {
|
||||
char *cmd = NULL;
|
||||
srecord_t TestRecord;
|
||||
// check for valid command expansion
|
||||
strncpy(TestRecord.fname, "test", FNAME_SIZE-1);
|
||||
TestRecord.fname[FNAME_SIZE-1] = 0;
|
||||
strncpy(TestRecord.tstring, "200407110845", 15);
|
||||
TestRecord.tstring[15] = 0;
|
||||
TestRecord.tstamp = 1;
|
||||
|
||||
fs = FlowSource;
|
||||
while ( fs ) {
|
||||
cmd = cmd_expand(&TestRecord, fs->Ident, fs->datadir, process);
|
||||
if ( cmd == NULL ) {
|
||||
syslog(LOG_ERR, "Launcher: ident: %s, Unable to expand command: '%s'", fs->Ident, process);
|
||||
exit(255);
|
||||
}
|
||||
|
||||
fs = fs->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Signal handling */
|
||||
memset((void *)&act,0,sizeof(struct sigaction));
|
||||
act.sa_handler = SignalHandler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
sigaction(SIGCHLD, &act, NULL); // child process terminated
|
||||
sigaction(SIGTERM, &act, NULL); // we are done
|
||||
sigaction(SIGINT, &act, NULL); // we are done
|
||||
sigaction(SIGHUP, &act, NULL); // run command
|
||||
|
||||
while ( !done ) {
|
||||
// sleep until we get signaled
|
||||
syslog(LOG_DEBUG, "Launcher: Sleeping");
|
||||
select(0, NULL, NULL, NULL, NULL);
|
||||
syslog(LOG_DEBUG, "Launcher: Wakeup");
|
||||
if ( launch ) { // SIGHUP
|
||||
launch = 0;
|
||||
|
||||
if ( process ) {
|
||||
char *cmd = NULL;
|
||||
|
||||
fs = FlowSource;
|
||||
while ( fs ) {
|
||||
// Expand % placeholders
|
||||
cmd = cmd_expand(InfoRecord, fs->Ident, fs->datadir, process);
|
||||
if ( cmd == NULL ) {
|
||||
syslog(LOG_ERR, "Launcher: ident: %s, Unable to expand command: '%s'", fs->Ident, process);
|
||||
continue;
|
||||
}
|
||||
// printf("Launcher: run command: '%s'\n", cmd);
|
||||
syslog(LOG_DEBUG, "Launcher: ident: %s run command: '%s'", fs->Ident, cmd);
|
||||
|
||||
// prepare args array
|
||||
cmd_parse(cmd, args);
|
||||
if ( args[0] )
|
||||
cmd_execute(args);
|
||||
|
||||
// do not flood the system with new processes
|
||||
sleep(1);
|
||||
// else cmd_parse already reported the error
|
||||
free(cmd);
|
||||
fs = fs->next;
|
||||
}
|
||||
}
|
||||
|
||||
fs = FlowSource;
|
||||
while ( fs ) {
|
||||
if ( expire )
|
||||
do_expire(fs->datadir);
|
||||
fs = fs->next;
|
||||
}
|
||||
}
|
||||
if ( child_exit ) {
|
||||
syslog(LOG_INFO, "laucher child exit %d childs.", child_exit);
|
||||
while ( (pid = waitpid (-1, &stat, WNOHANG)) > 0 ) {
|
||||
if ( WIFEXITED(stat) ) {
|
||||
syslog(LOG_DEBUG, "launcher child %i exit status: %i", pid, WEXITSTATUS(stat));
|
||||
}
|
||||
if ( WIFSIGNALED(stat) ) {
|
||||
syslog(LOG_WARNING, "laucher child %i died due to signal %i", pid, WTERMSIG(stat));
|
||||
}
|
||||
|
||||
child_exit--;
|
||||
}
|
||||
syslog(LOG_INFO, "laucher waiting childs done. %d childs", child_exit);
|
||||
child_exit = 0;
|
||||
}
|
||||
if ( done ) {
|
||||
syslog(LOG_INFO, "Launcher: Terminating.");
|
||||
}
|
||||
}
|
||||
|
||||
waitpid (-1, &stat, 0);
|
||||
|
||||
// we are done
|
||||
syslog(LOG_INFO, "Launcher: exit.");
|
||||
|
||||
} // End of launcher
|
||||
|
56
bin/launch.h
Normal file
56
bin/launch.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: launch.h 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LAUNCH_H
|
||||
#define _LAUNCH_H 1
|
||||
|
||||
#define FNAME_SIZE 256
|
||||
#define IDENT_SIZE 32
|
||||
|
||||
typedef struct srecord_s {
|
||||
char fname[FNAME_SIZE]; // file name
|
||||
char subdir[FNAME_SIZE]; // subdir name
|
||||
char ident[IDENT_SIZE]; // -I ident string
|
||||
char tstring[16]; // actually 12 needed e.g. 200411011230
|
||||
time_t tstamp; // UNIX time stamp
|
||||
} srecord_t;
|
||||
|
||||
void launcher (char *commbuff, char *datadir, char *process, int expire);
|
||||
|
||||
#endif //_LAUNCH_H
|
444
bin/lzoconf.h
Executable file
444
bin/lzoconf.h
Executable file
@ -0,0 +1,444 @@
|
||||
/* lzoconf.h -- configuration of the LZO data compression library
|
||||
|
||||
This file is part of the LZO real-time data compression library.
|
||||
|
||||
Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
The LZO library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
The LZO library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with the LZO library; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer
|
||||
<markus@oberhumer.com>
|
||||
http://www.oberhumer.com/opensource/lzo/
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __LZOCONF_H_INCLUDED
|
||||
#define __LZOCONF_H_INCLUDED 1
|
||||
|
||||
#define LZO_VERSION 0x2080
|
||||
#define LZO_VERSION_STRING "2.08"
|
||||
#define LZO_VERSION_DATE "Jun 29 2014"
|
||||
|
||||
/* internal Autoconf configuration file - only used when building LZO */
|
||||
#if defined(LZO_HAVE_CONFIG_H)
|
||||
# include <config.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
// LZO requires a conforming <limits.h>
|
||||
************************************************************************/
|
||||
|
||||
#if !defined(CHAR_BIT) || (CHAR_BIT != 8)
|
||||
# error "invalid CHAR_BIT"
|
||||
#endif
|
||||
#if !defined(UCHAR_MAX) || !defined(USHRT_MAX) || !defined(UINT_MAX) || !defined(ULONG_MAX)
|
||||
# error "check your compiler installation"
|
||||
#endif
|
||||
#if (USHRT_MAX < 1) || (UINT_MAX < 1) || (ULONG_MAX < 1)
|
||||
# error "your limits.h macros are broken"
|
||||
#endif
|
||||
|
||||
/* get OS and architecture defines */
|
||||
#ifndef __LZODEFS_H_INCLUDED
|
||||
#include "lzodefs.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
// some core defines
|
||||
************************************************************************/
|
||||
|
||||
/* memory checkers */
|
||||
#if !defined(__LZO_CHECKER)
|
||||
# if defined(__BOUNDS_CHECKING_ON)
|
||||
# define __LZO_CHECKER 1
|
||||
# elif defined(__CHECKER__)
|
||||
# define __LZO_CHECKER 1
|
||||
# elif defined(__INSURE__)
|
||||
# define __LZO_CHECKER 1
|
||||
# elif defined(__PURIFY__)
|
||||
# define __LZO_CHECKER 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
// integral and pointer types
|
||||
************************************************************************/
|
||||
|
||||
/* lzo_uint must match size_t */
|
||||
#if !defined(LZO_UINT_MAX)
|
||||
# if (LZO_ABI_LLP64)
|
||||
# if (LZO_OS_WIN64)
|
||||
typedef unsigned __int64 lzo_uint;
|
||||
typedef __int64 lzo_int;
|
||||
# else
|
||||
typedef lzo_ullong_t lzo_uint;
|
||||
typedef lzo_llong_t lzo_int;
|
||||
# endif
|
||||
# define LZO_SIZEOF_LZO_UINT 8
|
||||
# define LZO_UINT_MAX 0xffffffffffffffffull
|
||||
# define LZO_INT_MAX 9223372036854775807LL
|
||||
# define LZO_INT_MIN (-1LL - LZO_INT_MAX)
|
||||
# elif (LZO_ABI_IP32L64) /* MIPS R5900 */
|
||||
typedef unsigned int lzo_uint;
|
||||
typedef int lzo_int;
|
||||
# define LZO_SIZEOF_LZO_UINT LZO_SIZEOF_INT
|
||||
# define LZO_UINT_MAX UINT_MAX
|
||||
# define LZO_INT_MAX INT_MAX
|
||||
# define LZO_INT_MIN INT_MIN
|
||||
# elif (ULONG_MAX >= LZO_0xffffffffL)
|
||||
typedef unsigned long lzo_uint;
|
||||
typedef long lzo_int;
|
||||
# define LZO_SIZEOF_LZO_UINT LZO_SIZEOF_LONG
|
||||
# define LZO_UINT_MAX ULONG_MAX
|
||||
# define LZO_INT_MAX LONG_MAX
|
||||
# define LZO_INT_MIN LONG_MIN
|
||||
# else
|
||||
# error "lzo_uint"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* The larger type of lzo_uint and lzo_uint32_t. */
|
||||
#if (LZO_SIZEOF_LZO_UINT >= 4)
|
||||
# define lzo_xint lzo_uint
|
||||
#else
|
||||
# define lzo_xint lzo_uint32_t
|
||||
#endif
|
||||
|
||||
typedef int lzo_bool;
|
||||
|
||||
/* sanity checks */
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == LZO_SIZEOF_LZO_UINT)
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_xint) >= sizeof(lzo_uint))
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_xint) >= sizeof(lzo_uint32_t))
|
||||
|
||||
#ifndef __LZO_MMODEL
|
||||
#define __LZO_MMODEL /*empty*/
|
||||
#endif
|
||||
|
||||
/* no typedef here because of const-pointer issues */
|
||||
#define lzo_bytep unsigned char __LZO_MMODEL *
|
||||
#define lzo_charp char __LZO_MMODEL *
|
||||
#define lzo_voidp void __LZO_MMODEL *
|
||||
#define lzo_shortp short __LZO_MMODEL *
|
||||
#define lzo_ushortp unsigned short __LZO_MMODEL *
|
||||
#define lzo_intp lzo_int __LZO_MMODEL *
|
||||
#define lzo_uintp lzo_uint __LZO_MMODEL *
|
||||
#define lzo_xintp lzo_xint __LZO_MMODEL *
|
||||
#define lzo_voidpp lzo_voidp __LZO_MMODEL *
|
||||
#define lzo_bytepp lzo_bytep __LZO_MMODEL *
|
||||
|
||||
#define lzo_int8_tp lzo_int8_t __LZO_MMODEL *
|
||||
#define lzo_uint8_tp lzo_uint8_t __LZO_MMODEL *
|
||||
#define lzo_int16_tp lzo_int16_t __LZO_MMODEL *
|
||||
#define lzo_uint16_tp lzo_uint16_t __LZO_MMODEL *
|
||||
#define lzo_int32_tp lzo_int32_t __LZO_MMODEL *
|
||||
#define lzo_uint32_tp lzo_uint32_t __LZO_MMODEL *
|
||||
#if defined(lzo_int64_t)
|
||||
#define lzo_int64_tp lzo_int64_t __LZO_MMODEL *
|
||||
#define lzo_uint64_tp lzo_uint64_t __LZO_MMODEL *
|
||||
#endif
|
||||
|
||||
/* Older LZO versions used to support ancient systems and memory models
|
||||
* like 16-bit MSDOS with __huge pointers and Cray PVP, but these
|
||||
* obsolete configurations are not supported any longer.
|
||||
*/
|
||||
#if defined(__LZO_MMODEL_HUGE)
|
||||
#error "__LZO_MMODEL_HUGE is unsupported"
|
||||
#endif
|
||||
#if (LZO_MM_PVP)
|
||||
#error "LZO_MM_PVP is unsupported"
|
||||
#endif
|
||||
#if (LZO_SIZEOF_INT < 4)
|
||||
#error "LZO_SIZEOF_INT < 4 is unsupported"
|
||||
#endif
|
||||
#if (__LZO_UINTPTR_T_IS_POINTER)
|
||||
#error "__LZO_UINTPTR_T_IS_POINTER is unsupported"
|
||||
#endif
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(int) >= 4)
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) >= 4)
|
||||
/* Strange configurations where sizeof(lzo_uint) != sizeof(size_t) should
|
||||
* work but have not received much testing lately, so be strict here.
|
||||
*/
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == sizeof(size_t))
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == sizeof(ptrdiff_t))
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == sizeof(lzo_uintptr_t))
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(void *) == sizeof(lzo_uintptr_t))
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(char *) == sizeof(lzo_uintptr_t))
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long *) == sizeof(lzo_uintptr_t))
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(void *) == sizeof(lzo_voidp))
|
||||
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(char *) == sizeof(lzo_bytep))
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
// function types
|
||||
************************************************************************/
|
||||
|
||||
/* name mangling */
|
||||
#if !defined(__LZO_EXTERN_C)
|
||||
# ifdef __cplusplus
|
||||
# define __LZO_EXTERN_C extern "C"
|
||||
# else
|
||||
# define __LZO_EXTERN_C extern
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* calling convention */
|
||||
#if !defined(__LZO_CDECL)
|
||||
# define __LZO_CDECL __lzo_cdecl
|
||||
#endif
|
||||
|
||||
/* DLL export information */
|
||||
#if !defined(__LZO_EXPORT1)
|
||||
# define __LZO_EXPORT1 /*empty*/
|
||||
#endif
|
||||
#if !defined(__LZO_EXPORT2)
|
||||
# define __LZO_EXPORT2 /*empty*/
|
||||
#endif
|
||||
|
||||
/* __cdecl calling convention for public C and assembly functions */
|
||||
#if !defined(LZO_PUBLIC)
|
||||
# define LZO_PUBLIC(_rettype) __LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_CDECL
|
||||
#endif
|
||||
#if !defined(LZO_EXTERN)
|
||||
# define LZO_EXTERN(_rettype) __LZO_EXTERN_C LZO_PUBLIC(_rettype)
|
||||
#endif
|
||||
#if !defined(LZO_PRIVATE)
|
||||
# define LZO_PRIVATE(_rettype) static _rettype __LZO_CDECL
|
||||
#endif
|
||||
|
||||
/* function types */
|
||||
typedef int
|
||||
(__LZO_CDECL *lzo_compress_t) ( const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem );
|
||||
|
||||
typedef int
|
||||
(__LZO_CDECL *lzo_decompress_t) ( const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem );
|
||||
|
||||
typedef int
|
||||
(__LZO_CDECL *lzo_optimize_t) ( lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem );
|
||||
|
||||
typedef int
|
||||
(__LZO_CDECL *lzo_compress_dict_t)(const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem,
|
||||
const lzo_bytep dict, lzo_uint dict_len );
|
||||
|
||||
typedef int
|
||||
(__LZO_CDECL *lzo_decompress_dict_t)(const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem,
|
||||
const lzo_bytep dict, lzo_uint dict_len );
|
||||
|
||||
|
||||
/* Callback interface. Currently only the progress indicator ("nprogress")
|
||||
* is used, but this may change in a future release. */
|
||||
|
||||
struct lzo_callback_t;
|
||||
typedef struct lzo_callback_t lzo_callback_t;
|
||||
#define lzo_callback_p lzo_callback_t __LZO_MMODEL *
|
||||
|
||||
/* malloc & free function types */
|
||||
typedef lzo_voidp (__LZO_CDECL *lzo_alloc_func_t)
|
||||
(lzo_callback_p self, lzo_uint items, lzo_uint size);
|
||||
typedef void (__LZO_CDECL *lzo_free_func_t)
|
||||
(lzo_callback_p self, lzo_voidp ptr);
|
||||
|
||||
/* a progress indicator callback function */
|
||||
typedef void (__LZO_CDECL *lzo_progress_func_t)
|
||||
(lzo_callback_p, lzo_uint, lzo_uint, int);
|
||||
|
||||
struct lzo_callback_t
|
||||
{
|
||||
/* custom allocators (set to 0 to disable) */
|
||||
lzo_alloc_func_t nalloc; /* [not used right now] */
|
||||
lzo_free_func_t nfree; /* [not used right now] */
|
||||
|
||||
/* a progress indicator callback function (set to 0 to disable) */
|
||||
lzo_progress_func_t nprogress;
|
||||
|
||||
/* INFO: the first parameter "self" of the nalloc/nfree/nprogress
|
||||
* callbacks points back to this struct, so you are free to store
|
||||
* some extra info in the following variables. */
|
||||
lzo_voidp user1;
|
||||
lzo_xint user2;
|
||||
lzo_xint user3;
|
||||
};
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
// error codes and prototypes
|
||||
************************************************************************/
|
||||
|
||||
/* Error codes for the compression/decompression functions. Negative
|
||||
* values are errors, positive values will be used for special but
|
||||
* normal events.
|
||||
*/
|
||||
#define LZO_E_OK 0
|
||||
#define LZO_E_ERROR (-1)
|
||||
#define LZO_E_OUT_OF_MEMORY (-2) /* [lzo_alloc_func_t failure] */
|
||||
#define LZO_E_NOT_COMPRESSIBLE (-3) /* [not used right now] */
|
||||
#define LZO_E_INPUT_OVERRUN (-4)
|
||||
#define LZO_E_OUTPUT_OVERRUN (-5)
|
||||
#define LZO_E_LOOKBEHIND_OVERRUN (-6)
|
||||
#define LZO_E_EOF_NOT_FOUND (-7)
|
||||
#define LZO_E_INPUT_NOT_CONSUMED (-8)
|
||||
#define LZO_E_NOT_YET_IMPLEMENTED (-9) /* [not used right now] */
|
||||
#define LZO_E_INVALID_ARGUMENT (-10)
|
||||
#define LZO_E_INVALID_ALIGNMENT (-11) /* pointer argument is not properly aligned */
|
||||
#define LZO_E_OUTPUT_NOT_CONSUMED (-12)
|
||||
#define LZO_E_INTERNAL_ERROR (-99)
|
||||
|
||||
|
||||
#ifndef lzo_sizeof_dict_t
|
||||
# define lzo_sizeof_dict_t ((unsigned)sizeof(lzo_bytep))
|
||||
#endif
|
||||
|
||||
/* lzo_init() should be the first function you call.
|
||||
* Check the return code !
|
||||
*
|
||||
* lzo_init() is a macro to allow checking that the library and the
|
||||
* compiler's view of various types are consistent.
|
||||
*/
|
||||
#define lzo_init() __lzo_init_v2(LZO_VERSION,(int)sizeof(short),(int)sizeof(int),\
|
||||
(int)sizeof(long),(int)sizeof(lzo_uint32_t),(int)sizeof(lzo_uint),\
|
||||
(int)lzo_sizeof_dict_t,(int)sizeof(char *),(int)sizeof(lzo_voidp),\
|
||||
(int)sizeof(lzo_callback_t))
|
||||
LZO_EXTERN(int) __lzo_init_v2(unsigned,int,int,int,int,int,int,int,int,int);
|
||||
|
||||
/* version functions (useful for shared libraries) */
|
||||
LZO_EXTERN(unsigned) lzo_version(void);
|
||||
LZO_EXTERN(const char *) lzo_version_string(void);
|
||||
LZO_EXTERN(const char *) lzo_version_date(void);
|
||||
LZO_EXTERN(const lzo_charp) _lzo_version_string(void);
|
||||
LZO_EXTERN(const lzo_charp) _lzo_version_date(void);
|
||||
|
||||
/* string functions */
|
||||
LZO_EXTERN(int)
|
||||
lzo_memcmp(const lzo_voidp a, const lzo_voidp b, lzo_uint len);
|
||||
LZO_EXTERN(lzo_voidp)
|
||||
lzo_memcpy(lzo_voidp dst, const lzo_voidp src, lzo_uint len);
|
||||
LZO_EXTERN(lzo_voidp)
|
||||
lzo_memmove(lzo_voidp dst, const lzo_voidp src, lzo_uint len);
|
||||
LZO_EXTERN(lzo_voidp)
|
||||
lzo_memset(lzo_voidp buf, int c, lzo_uint len);
|
||||
|
||||
/* checksum functions */
|
||||
LZO_EXTERN(lzo_uint32_t)
|
||||
lzo_adler32(lzo_uint32_t c, const lzo_bytep buf, lzo_uint len);
|
||||
LZO_EXTERN(lzo_uint32_t)
|
||||
lzo_crc32(lzo_uint32_t c, const lzo_bytep buf, lzo_uint len);
|
||||
LZO_EXTERN(const lzo_uint32_tp)
|
||||
lzo_get_crc32_table(void);
|
||||
|
||||
/* misc. */
|
||||
LZO_EXTERN(int) _lzo_config_check(void);
|
||||
typedef union {
|
||||
lzo_voidp a00; lzo_bytep a01; lzo_uint a02; lzo_xint a03; lzo_uintptr_t a04;
|
||||
void *a05; unsigned char *a06; unsigned long a07; size_t a08; ptrdiff_t a09;
|
||||
#if defined(lzo_int64_t)
|
||||
lzo_uint64_t a10;
|
||||
#endif
|
||||
} lzo_align_t;
|
||||
|
||||
/* align a char pointer on a boundary that is a multiple of 'size' */
|
||||
LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp p, lzo_uint size);
|
||||
#define LZO_PTR_ALIGN_UP(p,size) \
|
||||
((p) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(p),(lzo_uint)(size)))
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
// deprecated macros - only for backward compatibility
|
||||
************************************************************************/
|
||||
|
||||
/* deprecated - use 'lzo_bytep' instead of 'lzo_byte *' */
|
||||
#define lzo_byte unsigned char
|
||||
/* deprecated type names */
|
||||
#define lzo_int32 lzo_int32_t
|
||||
#define lzo_uint32 lzo_uint32_t
|
||||
#define lzo_int32p lzo_int32_t __LZO_MMODEL *
|
||||
#define lzo_uint32p lzo_uint32_t __LZO_MMODEL *
|
||||
#define LZO_INT32_MAX LZO_INT32_C(2147483647)
|
||||
#define LZO_UINT32_MAX LZO_UINT32_C(4294967295)
|
||||
#if defined(lzo_int64_t)
|
||||
#define lzo_int64 lzo_int64_t
|
||||
#define lzo_uint64 lzo_uint64_t
|
||||
#define lzo_int64p lzo_int64_t __LZO_MMODEL *
|
||||
#define lzo_uint64p lzo_uint64_t __LZO_MMODEL *
|
||||
#define LZO_INT64_MAX LZO_INT64_C(9223372036854775807)
|
||||
#define LZO_UINT64_MAX LZO_UINT64_C(18446744073709551615)
|
||||
#endif
|
||||
/* deprecated types */
|
||||
typedef union { lzo_bytep a; lzo_uint b; } __lzo_pu_u;
|
||||
typedef union { lzo_bytep a; lzo_uint32_t b; } __lzo_pu32_u;
|
||||
|
||||
#if defined(LZO_CFG_COMPAT)
|
||||
|
||||
#define __LZOCONF_H 1
|
||||
|
||||
#if defined(LZO_ARCH_I086)
|
||||
# define __LZO_i386 1
|
||||
#elif defined(LZO_ARCH_I386)
|
||||
# define __LZO_i386 1
|
||||
#endif
|
||||
|
||||
#if defined(LZO_OS_DOS16)
|
||||
# define __LZO_DOS 1
|
||||
# define __LZO_DOS16 1
|
||||
#elif defined(LZO_OS_DOS32)
|
||||
# define __LZO_DOS 1
|
||||
#elif defined(LZO_OS_WIN16)
|
||||
# define __LZO_WIN 1
|
||||
# define __LZO_WIN16 1
|
||||
#elif defined(LZO_OS_WIN32)
|
||||
# define __LZO_WIN 1
|
||||
#endif
|
||||
|
||||
#define __LZO_CMODEL /*empty*/
|
||||
#define __LZO_DMODEL /*empty*/
|
||||
#define __LZO_ENTRY __LZO_CDECL
|
||||
#define LZO_EXTERN_CDECL LZO_EXTERN
|
||||
#define LZO_ALIGN LZO_PTR_ALIGN_UP
|
||||
|
||||
#define lzo_compress_asm_t lzo_compress_t
|
||||
#define lzo_decompress_asm_t lzo_decompress_t
|
||||
|
||||
#endif /* LZO_CFG_COMPAT */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* already included */
|
||||
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
2998
bin/lzodefs.h
Executable file
2998
bin/lzodefs.h
Executable file
File diff suppressed because it is too large
Load Diff
6053
bin/minilzo.c
Executable file
6053
bin/minilzo.c
Executable file
File diff suppressed because it is too large
Load Diff
94
bin/minilzo.h
Executable file
94
bin/minilzo.h
Executable file
@ -0,0 +1,94 @@
|
||||
/* minilzo.h -- mini subset of the LZO real-time data compression library
|
||||
|
||||
This file is part of the LZO real-time data compression library.
|
||||
|
||||
Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
The LZO library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
The LZO library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with the LZO library; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer
|
||||
<markus@oberhumer.com>
|
||||
http://www.oberhumer.com/opensource/lzo/
|
||||
*/
|
||||
|
||||
/*
|
||||
* NOTE:
|
||||
* the full LZO package can be found at
|
||||
* http://www.oberhumer.com/opensource/lzo/
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __MINILZO_H
|
||||
#define __MINILZO_H 1
|
||||
|
||||
#define MINILZO_VERSION 0x2080
|
||||
|
||||
#ifdef __LZOCONF_H
|
||||
# error "you cannot use both LZO and miniLZO"
|
||||
#endif
|
||||
|
||||
#undef LZO_HAVE_CONFIG_H
|
||||
#include "lzoconf.h"
|
||||
|
||||
#if !defined(LZO_VERSION) || (LZO_VERSION != MINILZO_VERSION)
|
||||
# error "version mismatch in header files"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
//
|
||||
************************************************************************/
|
||||
|
||||
/* Memory required for the wrkmem parameter.
|
||||
* When the required size is 0, you can also pass a NULL pointer.
|
||||
*/
|
||||
|
||||
#define LZO1X_MEM_COMPRESS LZO1X_1_MEM_COMPRESS
|
||||
#define LZO1X_1_MEM_COMPRESS ((lzo_uint32_t) (16384L * lzo_sizeof_dict_t))
|
||||
#define LZO1X_MEM_DECOMPRESS (0)
|
||||
|
||||
|
||||
/* compression */
|
||||
LZO_EXTERN(int)
|
||||
lzo1x_1_compress ( const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem );
|
||||
|
||||
/* decompression */
|
||||
LZO_EXTERN(int)
|
||||
lzo1x_decompress ( const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem /* NOT USED */ );
|
||||
|
||||
/* safe decompression with overrun testing */
|
||||
LZO_EXTERN(int)
|
||||
lzo1x_decompress_safe ( const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem /* NOT USED */ );
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* already included */
|
||||
|
353
bin/netflow_pcap.c
Normal file
353
bin/netflow_pcap.c
Normal file
@ -0,0 +1,353 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2013, Peter Haag
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author:$
|
||||
*
|
||||
* $Id:$
|
||||
*
|
||||
* $LastChangedRevision:$
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <syslog.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
#include "nffile.h"
|
||||
#include "nfx.h"
|
||||
#include "nfnet.h"
|
||||
#include "nf_common.h"
|
||||
#include "bookkeeper.h"
|
||||
#include "nfxstat.h"
|
||||
#include "collector.h"
|
||||
#include "exporter.h"
|
||||
|
||||
#include "flowtree.h"
|
||||
#include "netflow_pcap.h"
|
||||
|
||||
#ifndef DEVEL
|
||||
# define dbg_printf(...) /* printf(__VA_ARGS__) */
|
||||
#else
|
||||
# define dbg_printf(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
extern int verbose;
|
||||
extern extension_descriptor_t extension_descriptor[];
|
||||
|
||||
/* module limited globals */
|
||||
static extension_info_t pcap_extension_info; // common for all pcap records
|
||||
static extension_map_t *pcap_extension_map;
|
||||
|
||||
static uint32_t pcap_output_record_size_v4;
|
||||
static uint32_t pcap_output_record_size_v6;
|
||||
|
||||
typedef struct pcap_v4_block_s {
|
||||
uint32_t srcaddr;
|
||||
uint32_t dstaddr;
|
||||
uint32_t dPkts;
|
||||
uint32_t dOctets;
|
||||
uint32_t data[1]; // link to next record
|
||||
} __attribute__((__packed__ )) pcap_v4_block_t;
|
||||
#define PCAP_V4_BLOCK_DATA_SIZE (sizeof(pcap_v4_block_t) - sizeof(uint32_t))
|
||||
|
||||
typedef struct pcap_v6_block_s {
|
||||
uint64_t srcaddr[2];
|
||||
uint64_t dstaddr[2];
|
||||
uint32_t dPkts;
|
||||
uint32_t dOctets;
|
||||
uint32_t data[1]; // link to next record
|
||||
} __attribute__((__packed__ )) pcap_v6_block_t;
|
||||
#define PCAP_V6_BLOCK_DATA_SIZE (sizeof(pcap_v6_block_t) - sizeof(uint32_t))
|
||||
|
||||
// All required extension to save full pcap records
|
||||
static uint16_t pcap_full_map[] = { 0 };
|
||||
|
||||
#include "nffile_inline.c"
|
||||
|
||||
int Init_pcap2nf(void) {
|
||||
int i, id, map_index;
|
||||
int extension_size;
|
||||
uint16_t map_size;
|
||||
|
||||
// prepare pcap extension map
|
||||
pcap_extension_info.map = NULL;
|
||||
extension_size = 0;
|
||||
map_size = 0;
|
||||
|
||||
i=0;
|
||||
while ( (id = pcap_full_map[i]) != 0 ) {
|
||||
if ( extension_descriptor[id].enabled ) {
|
||||
extension_size += extension_descriptor[id].size;
|
||||
map_size += sizeof(uint16_t);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
// extension_size contains the sum of all optional extensions
|
||||
// caculate the record size
|
||||
pcap_output_record_size_v4 = COMMON_RECORD_DATA_SIZE + PCAP_V4_BLOCK_DATA_SIZE + extension_size;
|
||||
pcap_output_record_size_v6 = COMMON_RECORD_DATA_SIZE + PCAP_V6_BLOCK_DATA_SIZE + extension_size;
|
||||
|
||||
// now the full extension map size
|
||||
map_size += sizeof(extension_map_t);
|
||||
|
||||
// align 32 bits
|
||||
if ( ( map_size & 0x3 ) != 0 )
|
||||
map_size += 2;
|
||||
|
||||
// Create a generic pcap extension map
|
||||
pcap_extension_info.map = (extension_map_t *)malloc((size_t)map_size);
|
||||
if ( !pcap_extension_info.map ) {
|
||||
syslog(LOG_ERR, "Process_pcap: malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno));
|
||||
return 0;
|
||||
}
|
||||
pcap_extension_info.map->type = ExtensionMapType;
|
||||
pcap_extension_info.map->size = map_size;
|
||||
pcap_extension_info.map->map_id = INIT_ID;
|
||||
pcap_extension_info.map->extension_size = extension_size;
|
||||
|
||||
// see netflow_pcap.h for extension map description
|
||||
map_index = 0;
|
||||
i=0;
|
||||
while ( (id = pcap_full_map[i]) != 0 ) {
|
||||
if ( extension_descriptor[id].enabled )
|
||||
pcap_extension_info.map->ex_id[map_index++] = id;
|
||||
i++;
|
||||
}
|
||||
pcap_extension_info.map->ex_id[map_index] = 0;
|
||||
|
||||
pcap_extension_map = NULL;
|
||||
|
||||
return 1;
|
||||
|
||||
} // End of Init_pcap2nf
|
||||
|
||||
int StorePcapFlow(FlowSource_t *fs, struct FlowNode *Node) {
|
||||
common_record_t *common_record;
|
||||
uint32_t packets, bytes, pcap_output_record_size;
|
||||
uint64_t start_time, end_time;
|
||||
int j, id;
|
||||
char *string;
|
||||
void *data_ptr;
|
||||
|
||||
if ( !pcap_extension_map ) {
|
||||
pcap_extension_map = (extension_map_t *)malloc(pcap_extension_info.map->size);
|
||||
if ( !pcap_extension_map ) {
|
||||
LogError("Process_pcap: malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno));
|
||||
return 0;
|
||||
}
|
||||
memcpy((void *)pcap_extension_map, (void *)pcap_extension_info.map, pcap_extension_info.map->size);
|
||||
if ( !AddExtensionMap(fs, pcap_extension_map) ) {
|
||||
LogError("Process_pcap: Fatal: AddExtensionMap() failed in %s line %d\n", __FILE__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( Node->version == AF_INET6 ) {
|
||||
pcap_output_record_size = pcap_output_record_size_v6;
|
||||
dbg_printf("Store Flow v6 node: size: %u\n", pcap_output_record_size);
|
||||
} else if ( Node->version == AF_INET ) {
|
||||
pcap_output_record_size = pcap_output_record_size_v4;
|
||||
dbg_printf("Store Flow v4 node: size: %u\n", pcap_output_record_size);
|
||||
} else {
|
||||
LogError("Process_pcap: Unexpected version in %s line %d: %u\n", __FILE__, __LINE__, Node->version);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// output buffer size check for all expected records
|
||||
if ( !CheckBufferSpace(fs->nffile, pcap_output_record_size) ) {
|
||||
// fishy! - should never happen. maybe disk full?
|
||||
LogError("Process_pcap: output buffer size error. Abort pcap record processing");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// map output record to memory buffer
|
||||
common_record = (common_record_t *)fs->nffile->buff_ptr;
|
||||
|
||||
// header data
|
||||
common_record->flags = 0;
|
||||
common_record->type = CommonRecordType;
|
||||
common_record->exporter_sysid = 0;
|
||||
common_record->ext_map = pcap_extension_map->map_id;
|
||||
common_record->size = pcap_output_record_size;
|
||||
|
||||
// pcap common fields
|
||||
common_record->srcport = Node->src_port;
|
||||
common_record->dstport = Node->dst_port;
|
||||
common_record->tcp_flags = Node->flags;
|
||||
common_record->prot = Node->proto;
|
||||
common_record->tos = 0;
|
||||
common_record->fwd_status = 0;
|
||||
|
||||
if ( Node->version == AF_INET6 ) {
|
||||
SetFlag(common_record->flags, FLAG_IPV6_ADDR);
|
||||
pcap_v6_block_t *pcap_v6_block = (pcap_v6_block_t *)common_record->data;
|
||||
pcap_v6_block->srcaddr[0] = Node->src_addr.v6[0];
|
||||
pcap_v6_block->srcaddr[1] = Node->src_addr.v6[1];
|
||||
pcap_v6_block->dstaddr[0] = Node->dst_addr.v6[0];
|
||||
pcap_v6_block->dstaddr[1] = Node->dst_addr.v6[1];
|
||||
pcap_v6_block->dPkts = packets = Node->packets;
|
||||
pcap_v6_block->dOctets = bytes = Node->bytes;
|
||||
|
||||
data_ptr = (void *)pcap_v6_block->data;
|
||||
} else {
|
||||
pcap_v4_block_t *pcap_v4_block = (pcap_v4_block_t *)common_record->data;
|
||||
pcap_v4_block->srcaddr = Node->src_addr.v4;
|
||||
pcap_v4_block->dstaddr = Node->dst_addr.v4;
|
||||
pcap_v4_block->dPkts = packets = Node->packets;
|
||||
pcap_v4_block->dOctets = bytes = Node->bytes;
|
||||
|
||||
data_ptr = (void *)pcap_v4_block->data;
|
||||
}
|
||||
|
||||
// process optional extensions
|
||||
j = 0;
|
||||
while ( (id = pcap_extension_map->ex_id[j]) != 0 ) {
|
||||
switch (id) {
|
||||
case EX_IO_SNMP_2: { // 2 byte input/output interface index
|
||||
tpl_ext_4_t *tpl = (tpl_ext_4_t *)data_ptr;
|
||||
tpl->input = 0;
|
||||
tpl->output = 0;
|
||||
data_ptr = (void *)tpl->data;
|
||||
} break;
|
||||
default:
|
||||
// this should never happen, as pcap has no other extensions
|
||||
LogError("Process_pcap: Unexpected extension %i for pcap record. Skip extension", id);
|
||||
}
|
||||
j++;
|
||||
}
|
||||
|
||||
common_record->first = Node->t_first.tv_sec;
|
||||
common_record->msec_first = Node->t_first.tv_usec / 1000;
|
||||
|
||||
common_record->last = Node->t_last.tv_sec;
|
||||
common_record->msec_last = Node->t_last.tv_usec / 1000;
|
||||
|
||||
start_time = (1000LL * (uint64_t)common_record->first) + (uint64_t)common_record->msec_first;
|
||||
end_time = (1000LL * (uint64_t)common_record->last) + (uint64_t)common_record->msec_last;
|
||||
|
||||
// update first_seen, last_seen
|
||||
if ( start_time < fs->first_seen )
|
||||
fs->first_seen = start_time;
|
||||
if ( end_time > fs->last_seen )
|
||||
fs->last_seen = end_time;
|
||||
|
||||
|
||||
// Update stats
|
||||
switch (common_record->prot) {
|
||||
case IPPROTO_ICMP:
|
||||
case IPPROTO_ICMPV6:
|
||||
fs->nffile->stat_record->numflows_icmp++;
|
||||
fs->nffile->stat_record->numpackets_icmp += packets;
|
||||
fs->nffile->stat_record->numbytes_icmp += bytes;
|
||||
// fix odd CISCO behaviour for ICMP port/type in src port
|
||||
if ( common_record->srcport != 0 ) {
|
||||
uint8_t *s1, *s2;
|
||||
s1 = (uint8_t *)&(common_record->srcport);
|
||||
s2 = (uint8_t *)&(common_record->dstport);
|
||||
s2[0] = s1[1];
|
||||
s2[1] = s1[0];
|
||||
common_record->srcport = 0;
|
||||
}
|
||||
break;
|
||||
case IPPROTO_TCP:
|
||||
fs->nffile->stat_record->numflows_tcp++;
|
||||
fs->nffile->stat_record->numpackets_tcp += packets;
|
||||
fs->nffile->stat_record->numbytes_tcp += bytes;
|
||||
break;
|
||||
case IPPROTO_UDP:
|
||||
fs->nffile->stat_record->numflows_udp++;
|
||||
fs->nffile->stat_record->numpackets_udp += packets;
|
||||
fs->nffile->stat_record->numbytes_udp += bytes;
|
||||
break;
|
||||
default:
|
||||
fs->nffile->stat_record->numflows_other++;
|
||||
fs->nffile->stat_record->numpackets_other += packets;
|
||||
fs->nffile->stat_record->numbytes_other += bytes;
|
||||
}
|
||||
|
||||
fs->nffile->stat_record->numflows++;
|
||||
fs->nffile->stat_record->numpackets += packets;
|
||||
fs->nffile->stat_record->numbytes += bytes;
|
||||
|
||||
if ( fs->xstat ) {
|
||||
uint32_t bpp = packets ? bytes/packets : 0;
|
||||
if ( bpp > MAX_BPP )
|
||||
bpp = MAX_BPP;
|
||||
if ( common_record->prot == IPPROTO_TCP ) {
|
||||
fs->xstat->bpp_histogram->tcp.bpp[bpp]++;
|
||||
fs->xstat->bpp_histogram->tcp.count++;
|
||||
|
||||
fs->xstat->port_histogram->src_tcp.port[common_record->srcport]++;
|
||||
fs->xstat->port_histogram->dst_tcp.port[common_record->dstport]++;
|
||||
fs->xstat->port_histogram->src_tcp.count++;
|
||||
fs->xstat->port_histogram->dst_tcp.count++;
|
||||
} else if ( common_record->prot == IPPROTO_UDP ) {
|
||||
fs->xstat->bpp_histogram->udp.bpp[bpp]++;
|
||||
fs->xstat->bpp_histogram->udp.count++;
|
||||
|
||||
fs->xstat->port_histogram->src_udp.port[common_record->srcport]++;
|
||||
fs->xstat->port_histogram->dst_udp.port[common_record->dstport]++;
|
||||
fs->xstat->port_histogram->src_udp.count++;
|
||||
fs->xstat->port_histogram->dst_udp.count++;
|
||||
}
|
||||
}
|
||||
|
||||
if ( verbose ) {
|
||||
master_record_t master_record;
|
||||
ExpandRecord_v2((common_record_t *)common_record, &pcap_extension_info, NULL, &master_record);
|
||||
format_file_block_record(&master_record, &string, 0);
|
||||
printf("%s\n", string);
|
||||
}
|
||||
|
||||
// update file record size ( -> output buffer size )
|
||||
fs->nffile->block_header->NumRecords += 1;
|
||||
fs->nffile->block_header->size += pcap_output_record_size;
|
||||
fs->nffile->buff_ptr = data_ptr;
|
||||
|
||||
return 1;
|
||||
|
||||
} /* End of StorePcapFlow */
|
||||
|
42
bin/netflow_pcap.h
Normal file
42
bin/netflow_pcap.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2013, Peter Haag
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author:$
|
||||
*
|
||||
* $Id:$
|
||||
*
|
||||
* $LastChangedRevision:$
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
int Init_pcap2nf(void);
|
||||
|
||||
int StorePcapFlow(FlowSource_t *fs, struct FlowNode *Node);
|
||||
|
538
bin/netflow_v1.c
Normal file
538
bin/netflow_v1.c
Normal file
@ -0,0 +1,538 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: peter $
|
||||
*
|
||||
* $Id: netflow_v1.c 30 2011-07-18 11:19:46Z peter $
|
||||
*
|
||||
* $LastChangedRevision: 30 $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <syslog.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
#include "nffile.h"
|
||||
#include "nfx.h"
|
||||
#include "nfnet.h"
|
||||
#include "nf_common.h"
|
||||
#include "bookkeeper.h"
|
||||
#include "nfxstat.h"
|
||||
#include "collector.h"
|
||||
#include "exporter.h"
|
||||
#include "netflow_v1.h"
|
||||
|
||||
#ifndef DEVEL
|
||||
# define dbg_printf(...) /* printf(__VA_ARGS__) */
|
||||
#else
|
||||
# define dbg_printf(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
extern int verbose;
|
||||
extern extension_descriptor_t extension_descriptor[];
|
||||
|
||||
/* module limited globals */
|
||||
static extension_info_t v1_extension_info; // common for all v1 records
|
||||
static uint16_t v1_output_record_size;
|
||||
|
||||
// All required extension to save full v1 records
|
||||
static uint16_t v1_full_map[] = { EX_IO_SNMP_2, EX_NEXT_HOP_v4, EX_ROUTER_IP_v4, EX_RECEIVED, 0 };
|
||||
|
||||
typedef struct v1_block_s {
|
||||
uint32_t srcaddr;
|
||||
uint32_t dstaddr;
|
||||
uint32_t dPkts;
|
||||
uint32_t dOctets;
|
||||
uint32_t data[1]; // link to next record
|
||||
} v1_block_t;
|
||||
#define V1_BLOCK_DATA_SIZE (sizeof(v1_block_t) - sizeof(uint32_t))
|
||||
|
||||
typedef struct exporter_v1_s {
|
||||
// identical to generic_exporter_t
|
||||
struct exporter_v1_s *next;
|
||||
|
||||
// generic exporter information
|
||||
exporter_info_record_t info;
|
||||
|
||||
uint64_t packets; // number of packets sent by this exporter
|
||||
uint64_t flows; // number of flow records sent by this exporter
|
||||
uint32_t sequence_failure; // number of sequence failues
|
||||
|
||||
generic_sampler_t *sampler;
|
||||
// End of generic_exporter_t
|
||||
|
||||
// extension map
|
||||
extension_map_t *extension_map;
|
||||
|
||||
} exporter_v1_t;
|
||||
|
||||
static inline exporter_v1_t *GetExporter(FlowSource_t *fs, netflow_v1_header_t *header);
|
||||
|
||||
/* functions */
|
||||
|
||||
#include "nffile_inline.c"
|
||||
|
||||
int Init_v1(void) {
|
||||
int i, id, map_index;
|
||||
int extension_size;
|
||||
uint16_t map_size;
|
||||
|
||||
// prepare v1 extension map
|
||||
v1_extension_info.map = NULL;
|
||||
v1_extension_info.next = NULL;
|
||||
v1_extension_info.offset_cache = NULL;
|
||||
v1_extension_info.ref_count = 0;
|
||||
|
||||
extension_size = 0;
|
||||
// default map - 0 extensions
|
||||
map_size = sizeof(extension_map_t);
|
||||
i=0;
|
||||
dbg_printf("v1 map: map size start: %u\n", map_size);
|
||||
while ( (id = v1_full_map[i]) != 0 ) {
|
||||
if ( extension_descriptor[id].enabled ) {
|
||||
extension_size += extension_descriptor[id].size;
|
||||
map_size += sizeof(uint16_t);
|
||||
dbg_printf("v1 map: enabled extension %u\n", id);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
dbg_printf("v1 map: map size so far: %u\n", map_size);
|
||||
|
||||
// extension_size contains the sum of all optional extensions
|
||||
// caculate the record size
|
||||
v1_output_record_size = COMMON_RECORD_DATA_SIZE + V1_BLOCK_DATA_SIZE + extension_size;
|
||||
|
||||
// align 32 bits
|
||||
if ( ( map_size & 0x3 ) != 0 )
|
||||
map_size += 2;
|
||||
|
||||
// Create a generic netflow v1 extension map
|
||||
v1_extension_info.map = (extension_map_t *)malloc((size_t)map_size);
|
||||
if ( !v1_extension_info.map ) {
|
||||
syslog(LOG_ERR, "Process_v1: malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
v1_extension_info.map->type = ExtensionMapType;
|
||||
v1_extension_info.map->size = map_size;
|
||||
v1_extension_info.map->map_id = INIT_ID;
|
||||
v1_extension_info.map->extension_size = extension_size;
|
||||
|
||||
// see netflow_v1.h for extension map description
|
||||
map_index = 0;
|
||||
i=0;
|
||||
while ( (id = v1_full_map[i]) != 0 ) {
|
||||
if ( extension_descriptor[id].enabled )
|
||||
v1_extension_info.map->ex_id[map_index++] = id;
|
||||
i++;
|
||||
}
|
||||
v1_extension_info.map->ex_id[map_index] = 0;
|
||||
|
||||
return 1;
|
||||
} // End of Init_v1
|
||||
|
||||
/*
|
||||
* functions used for receiving netflow v1 records
|
||||
*/
|
||||
|
||||
|
||||
static inline exporter_v1_t *GetExporter(FlowSource_t *fs, netflow_v1_header_t *header) {
|
||||
exporter_v1_t **e = (exporter_v1_t **)&(fs->exporter_data);
|
||||
uint16_t version = ntohs(header->version);
|
||||
#define IP_STRING_LEN 40
|
||||
char ipstr[IP_STRING_LEN];
|
||||
|
||||
// search the appropriate exporter engine
|
||||
while ( *e ) {
|
||||
if ( (*e)->info.version == version &&
|
||||
(*e)->info.ip.v6[0] == fs->ip.v6[0] && (*e)->info.ip.v6[1] == fs->ip.v6[1])
|
||||
return *e;
|
||||
e = &((*e)->next);
|
||||
}
|
||||
|
||||
// nothing found
|
||||
*e = (exporter_v1_t *)malloc(sizeof(exporter_v1_t));
|
||||
if ( !(*e)) {
|
||||
syslog(LOG_ERR, "Process_v1: malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno));
|
||||
return NULL;
|
||||
}
|
||||
memset((void *)(*e), 0, sizeof(exporter_v1_t));
|
||||
(*e)->info.header.type = ExporterInfoRecordType;
|
||||
(*e)->info.header.size = sizeof(exporter_info_record_t);
|
||||
(*e)->info.version = version;
|
||||
(*e)->info.id = 0;
|
||||
(*e)->info.ip = fs->ip;
|
||||
(*e)->info.sa_family = fs->sa_family;
|
||||
(*e)->next = NULL;
|
||||
(*e)->packets = 0;
|
||||
(*e)->flows = 0;
|
||||
(*e)->sequence_failure = 0;
|
||||
(*e)->sampler = NULL;
|
||||
|
||||
// copy the v1 generic extension map
|
||||
(*e)->extension_map = (extension_map_t *)malloc(v1_extension_info.map->size);
|
||||
if ( !(*e)->extension_map ) {
|
||||
syslog(LOG_ERR, "Process_v1: malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno));
|
||||
free(*e);
|
||||
*e = NULL;
|
||||
return NULL;
|
||||
}
|
||||
memcpy((void *)(*e)->extension_map, (void *)v1_extension_info.map, v1_extension_info.map->size);
|
||||
|
||||
if ( !AddExtensionMap(fs, (*e)->extension_map) ) {
|
||||
// bad - we must free this map and fail - otherwise data can not be read any more
|
||||
free((*e)->extension_map);
|
||||
free(*e);
|
||||
*e = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(*e)->info.sysid = 0;
|
||||
FlushInfoExporter(fs, &((*e)->info));
|
||||
|
||||
if ( fs->sa_family == AF_INET ) {
|
||||
uint32_t _ip = htonl(fs->ip.v4);
|
||||
inet_ntop(AF_INET, &_ip, ipstr, sizeof(ipstr));
|
||||
} else if ( fs->sa_family == AF_INET6 ) {
|
||||
uint64_t _ip[2];
|
||||
_ip[0] = htonll(fs->ip.v6[0]);
|
||||
_ip[1] = htonll(fs->ip.v6[1]);
|
||||
inet_ntop(AF_INET6, &_ip, ipstr, sizeof(ipstr));
|
||||
} else {
|
||||
strncpy(ipstr, "<unknown>", IP_STRING_LEN);
|
||||
}
|
||||
|
||||
dbg_printf("New Exporter: v1 SysID: %u, Extension ID: %i, IP: %s, \n",
|
||||
(*e)->info.sysid, (*e)->extension_map->map_id, ipstr);
|
||||
syslog(LOG_INFO, "Process_v1: SysID: %u, New exporter: IP: %s\n", (*e)->info.sysid, ipstr);
|
||||
|
||||
return (*e);
|
||||
|
||||
} // End of GetExporter
|
||||
|
||||
void Process_v1(void *in_buff, ssize_t in_buff_cnt, FlowSource_t *fs) {
|
||||
netflow_v1_header_t *v1_header;
|
||||
netflow_v1_record_t *v1_record;
|
||||
exporter_v1_t *exporter;
|
||||
extension_map_t *extension_map;
|
||||
common_record_t *common_record;
|
||||
uint64_t start_time, end_time, boot_time;
|
||||
uint32_t First, Last;
|
||||
uint16_t count;
|
||||
uint8_t flags;
|
||||
int i, done, flow_record_length;
|
||||
ssize_t size_left;
|
||||
char *string;
|
||||
|
||||
// map v1 data structure to input buffer
|
||||
v1_header = (netflow_v1_header_t *)in_buff;
|
||||
|
||||
exporter = GetExporter(fs, v1_header);
|
||||
if ( !exporter ) {
|
||||
syslog(LOG_ERR,"Process_v1: Exporter NULL: Abort v1 record processing");
|
||||
return;
|
||||
}
|
||||
flags = 0;
|
||||
|
||||
exporter->packets++;
|
||||
|
||||
extension_map = exporter->extension_map;
|
||||
flow_record_length = NETFLOW_V1_RECORD_LENGTH;
|
||||
|
||||
// this many data to process
|
||||
size_left = in_buff_cnt;
|
||||
|
||||
common_record = fs->nffile->buff_ptr;
|
||||
done = 0;
|
||||
while ( !done ) {
|
||||
v1_block_t *v1_block;
|
||||
|
||||
/* Process header */
|
||||
|
||||
// count check
|
||||
count = ntohs(v1_header->count);
|
||||
if ( count > NETFLOW_V1_MAX_RECORDS ) {
|
||||
syslog(LOG_ERR,"Process_v1: Unexpected record count in header: %i. Abort v1 record processing", count);
|
||||
fs->nffile->buff_ptr = (void *)common_record;
|
||||
return;
|
||||
}
|
||||
|
||||
// input buffer size check for all expected records
|
||||
if ( size_left < ( NETFLOW_V1_HEADER_LENGTH + count * flow_record_length) ) {
|
||||
syslog(LOG_ERR,"Process_v1: Not enough data to process v1 record. Abort v1 record processing");
|
||||
fs->nffile->buff_ptr = (void *)common_record;
|
||||
return;
|
||||
}
|
||||
|
||||
// output buffer size check for all expected records
|
||||
if ( !CheckBufferSpace(fs->nffile, count * v1_output_record_size) ) {
|
||||
// fishy! - should never happen. maybe disk full?
|
||||
syslog(LOG_ERR,"Process_v1: output buffer size error. Abort v1 record processing");
|
||||
return;
|
||||
}
|
||||
|
||||
// map output record to memory buffer
|
||||
common_record = (common_record_t *)fs->nffile->buff_ptr;
|
||||
v1_block = (v1_block_t *)common_record->data;
|
||||
|
||||
v1_header->SysUptime = ntohl(v1_header->SysUptime);
|
||||
v1_header->unix_secs = ntohl(v1_header->unix_secs);
|
||||
v1_header->unix_nsecs = ntohl(v1_header->unix_nsecs);
|
||||
|
||||
/* calculate boot time in msec */
|
||||
boot_time = ((uint64_t)(v1_header->unix_secs)*1000 +
|
||||
((uint64_t)(v1_header->unix_nsecs) / 1000000) ) - (uint64_t)(v1_header->SysUptime);
|
||||
|
||||
// process all records
|
||||
v1_record = (netflow_v1_record_t *)((pointer_addr_t)v1_header + NETFLOW_V1_HEADER_LENGTH);
|
||||
|
||||
/* loop over each records associated with this header */
|
||||
for (i = 0; i < count; i++) {
|
||||
pointer_addr_t bsize;
|
||||
void *data_ptr;
|
||||
uint8_t *s1, *s2;
|
||||
int j, id;
|
||||
// header data
|
||||
common_record->flags = flags;
|
||||
common_record->type = CommonRecordType;
|
||||
common_record->exporter_sysid = exporter->info.sysid;
|
||||
common_record->ext_map = extension_map->map_id;
|
||||
common_record->size = v1_output_record_size;
|
||||
|
||||
// v1 common fields
|
||||
common_record->srcport = ntohs(v1_record->srcport);
|
||||
common_record->dstport = ntohs(v1_record->dstport);
|
||||
common_record->tcp_flags = v1_record->tcp_flags;
|
||||
common_record->prot = v1_record->prot;
|
||||
common_record->tos = v1_record->tos;
|
||||
common_record->fwd_status = 0;
|
||||
common_record->reserved = 0;
|
||||
|
||||
// v1 typed data as fixed struct v1_block
|
||||
v1_block->srcaddr = ntohl(v1_record->srcaddr);
|
||||
v1_block->dstaddr = ntohl(v1_record->dstaddr);
|
||||
v1_block->dPkts = ntohl(v1_record->dPkts);
|
||||
v1_block->dOctets = ntohl(v1_record->dOctets);
|
||||
|
||||
// process optional extensions
|
||||
data_ptr = (void *)v1_block->data;
|
||||
j = 0;
|
||||
while ( (id = extension_map->ex_id[j]) != 0 ) {
|
||||
switch (id) {
|
||||
case EX_IO_SNMP_2: { // 2 byte input/output interface index
|
||||
tpl_ext_4_t *tpl = (tpl_ext_4_t *)data_ptr;
|
||||
tpl->input = ntohs(v1_record->input);
|
||||
tpl->output = ntohs(v1_record->output);
|
||||
data_ptr = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_NEXT_HOP_v4: { // IPv4 next hop
|
||||
tpl_ext_9_t *tpl = (tpl_ext_9_t *)data_ptr;
|
||||
tpl->nexthop = ntohl(v1_record->nexthop);
|
||||
data_ptr = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_ROUTER_IP_v4: { // IPv4 router address
|
||||
tpl_ext_23_t *tpl = (tpl_ext_23_t *)data_ptr;
|
||||
tpl->router_ip = fs->ip.v4;
|
||||
data_ptr = (void *)tpl->data;
|
||||
ClearFlag(common_record->flags, FLAG_IPV6_EXP);
|
||||
} break;
|
||||
case EX_RECEIVED: {
|
||||
tpl_ext_27_t *tpl = (tpl_ext_27_t *)data_ptr;
|
||||
tpl->received = (uint64_t)((uint64_t)fs->received.tv_sec * 1000LL) + (uint64_t)((uint64_t)fs->received.tv_usec / 1000LL);
|
||||
data_ptr = (void *)tpl->data;
|
||||
} break;
|
||||
|
||||
default:
|
||||
// this should never happen, as v1 has no other extensions
|
||||
syslog(LOG_ERR,"Process_v1: Unexpected extension %i for v1 record. Skip extension", id);
|
||||
}
|
||||
j++;
|
||||
}
|
||||
|
||||
// Time issues
|
||||
First = ntohl(v1_record->First);
|
||||
Last = ntohl(v1_record->Last);
|
||||
|
||||
if ( First > Last ) {
|
||||
/* First in msec, in case of msec overflow, between start and end */
|
||||
start_time = boot_time - 0x100000000LL + (uint64_t)First;
|
||||
} else {
|
||||
start_time = boot_time + (uint64_t)First;
|
||||
}
|
||||
|
||||
/* end time in msecs */
|
||||
end_time = (uint64_t)Last + boot_time;
|
||||
|
||||
// if overflow happened after flow ended but before got exported
|
||||
if ( Last > v1_header->SysUptime ) {
|
||||
start_time -= 0x100000000LL;
|
||||
end_time -= 0x100000000LL;
|
||||
}
|
||||
|
||||
common_record->first = start_time/1000;
|
||||
common_record->msec_first = start_time - common_record->first*1000;
|
||||
|
||||
common_record->last = end_time/1000;
|
||||
common_record->msec_last = end_time - common_record->last*1000;
|
||||
|
||||
// update first_seen, last_seen
|
||||
if ( start_time < fs->first_seen )
|
||||
fs->first_seen = start_time;
|
||||
if ( end_time > fs->last_seen )
|
||||
fs->last_seen = end_time;
|
||||
|
||||
|
||||
// Update stats
|
||||
switch (common_record->prot) {
|
||||
case IPPROTO_ICMP:
|
||||
fs->nffile->stat_record->numflows_icmp++;
|
||||
fs->nffile->stat_record->numpackets_icmp += v1_block->dPkts;
|
||||
fs->nffile->stat_record->numbytes_icmp += v1_block->dOctets;
|
||||
// fix odd CISCO behaviour for ICMP port/type in src port
|
||||
if ( common_record->srcport != 0 ) {
|
||||
s1 = (uint8_t *)&(common_record->srcport);
|
||||
s2 = (uint8_t *)&(common_record->dstport);
|
||||
s2[0] = s1[1];
|
||||
s2[1] = s1[0];
|
||||
common_record->srcport = 0;
|
||||
}
|
||||
break;
|
||||
case IPPROTO_TCP:
|
||||
fs->nffile->stat_record->numflows_tcp++;
|
||||
fs->nffile->stat_record->numpackets_tcp += v1_block->dPkts;
|
||||
fs->nffile->stat_record->numbytes_tcp += v1_block->dOctets;
|
||||
break;
|
||||
case IPPROTO_UDP:
|
||||
fs->nffile->stat_record->numflows_udp++;
|
||||
fs->nffile->stat_record->numpackets_udp += v1_block->dPkts;
|
||||
fs->nffile->stat_record->numbytes_udp += v1_block->dOctets;
|
||||
break;
|
||||
default:
|
||||
fs->nffile->stat_record->numflows_other++;
|
||||
fs->nffile->stat_record->numpackets_other += v1_block->dPkts;
|
||||
fs->nffile->stat_record->numbytes_other += v1_block->dOctets;
|
||||
}
|
||||
exporter->flows++;
|
||||
fs->nffile->stat_record->numflows++;
|
||||
fs->nffile->stat_record->numpackets += v1_block->dPkts;
|
||||
fs->nffile->stat_record->numbytes += v1_block->dOctets;
|
||||
|
||||
if ( fs->xstat ) {
|
||||
uint32_t bpp = v1_block->dPkts ? v1_block->dOctets/v1_block->dPkts : 0;
|
||||
if ( bpp > MAX_BPP )
|
||||
bpp = MAX_BPP;
|
||||
if ( common_record->prot == IPPROTO_TCP ) {
|
||||
fs->xstat->bpp_histogram->tcp.bpp[bpp]++;
|
||||
fs->xstat->bpp_histogram->tcp.count++;
|
||||
|
||||
fs->xstat->port_histogram->src_tcp.port[common_record->srcport]++;
|
||||
fs->xstat->port_histogram->dst_tcp.port[common_record->dstport]++;
|
||||
fs->xstat->port_histogram->src_tcp.count++;
|
||||
fs->xstat->port_histogram->dst_tcp.count++;
|
||||
} else if ( common_record->prot == IPPROTO_UDP ) {
|
||||
fs->xstat->bpp_histogram->udp.bpp[bpp]++;
|
||||
fs->xstat->bpp_histogram->udp.count++;
|
||||
|
||||
fs->xstat->port_histogram->src_udp.port[common_record->srcport]++;
|
||||
fs->xstat->port_histogram->dst_udp.port[common_record->dstport]++;
|
||||
fs->xstat->port_histogram->src_udp.count++;
|
||||
fs->xstat->port_histogram->dst_udp.count++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( verbose ) {
|
||||
master_record_t master_record;
|
||||
ExpandRecord_v2((common_record_t *)common_record, &v1_extension_info, &(exporter->info), &master_record);
|
||||
format_file_block_record(&master_record, &string, 0);
|
||||
printf("%s\n", string);
|
||||
}
|
||||
|
||||
// advance to next input flow record
|
||||
v1_record = (netflow_v1_record_t *)((pointer_addr_t)v1_record + flow_record_length);
|
||||
|
||||
if ( ((pointer_addr_t)data_ptr - (pointer_addr_t)common_record) != v1_output_record_size ) {
|
||||
printf("Panic size check: ptr diff: %llu, record size: %u\n", (unsigned long long)((pointer_addr_t)data_ptr - (pointer_addr_t)common_record), v1_output_record_size );
|
||||
abort();
|
||||
}
|
||||
// advance to next output record
|
||||
common_record = (common_record_t *)data_ptr;
|
||||
v1_block = (v1_block_t *)common_record->data;
|
||||
|
||||
// buffer size sanity check - should never happen, but check it anyway
|
||||
bsize = (pointer_addr_t)common_record - (pointer_addr_t)fs->nffile->block_header - sizeof(data_block_header_t);
|
||||
if ( bsize > BUFFSIZE ) {
|
||||
syslog(LOG_ERR,"### Software error ###: %s line %d", __FILE__, __LINE__);
|
||||
syslog(LOG_ERR,"Process_v1: Output buffer overflow! Flush buffer and skip records.");
|
||||
syslog(LOG_ERR,"Buffer size: size: %u, bsize: %llu > %u", fs->nffile->block_header->size, (unsigned long long)bsize, BUFFSIZE);
|
||||
// reset buffer
|
||||
fs->nffile->block_header->size = 0;
|
||||
fs->nffile->block_header->NumRecords = 0;
|
||||
fs->nffile->buff_ptr = (void *)((pointer_addr_t)fs->nffile->block_header + sizeof(data_block_header_t) );
|
||||
return;
|
||||
}
|
||||
|
||||
} // End of foreach v1 record
|
||||
|
||||
// update file record size ( -> output buffer size )
|
||||
fs->nffile->block_header->NumRecords += count;
|
||||
fs->nffile->block_header->size += count * v1_output_record_size;
|
||||
fs->nffile->buff_ptr = (void *)common_record;
|
||||
|
||||
// still to go for this many input bytes
|
||||
size_left -= NETFLOW_V1_HEADER_LENGTH + count * flow_record_length;
|
||||
|
||||
// next header
|
||||
v1_header = (netflow_v1_header_t *)v1_record;
|
||||
|
||||
// should never be < 0
|
||||
done = size_left <= 0;
|
||||
|
||||
} // End of while !done
|
||||
|
||||
return;
|
||||
|
||||
} /* End of Process_v1 */
|
||||
|
97
bin/netflow_v1.h
Normal file
97
bin/netflow_v1.h
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: peter $
|
||||
*
|
||||
* $Id: netflow_v1.h 26 2011-07-05 18:51:25Z peter $
|
||||
*
|
||||
* $LastChangedRevision: 26 $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NETFLOW_V1_H
|
||||
#define _NETFLOW_V1_H 1
|
||||
|
||||
#define NETFLOW_V1_HEADER_LENGTH 16
|
||||
#define NETFLOW_V1_RECORD_LENGTH 48
|
||||
#define NETFLOW_V1_MAX_RECORDS 24
|
||||
|
||||
/* v1 structures */
|
||||
typedef struct netflow_v1_header {
|
||||
uint16_t version;
|
||||
uint16_t count;
|
||||
uint32_t SysUptime;
|
||||
uint32_t unix_secs;
|
||||
uint32_t unix_nsecs;
|
||||
} netflow_v1_header_t;
|
||||
|
||||
typedef struct netflow_v1_record {
|
||||
uint32_t srcaddr;
|
||||
uint32_t dstaddr;
|
||||
uint32_t nexthop;
|
||||
uint16_t input;
|
||||
uint16_t output;
|
||||
uint32_t dPkts;
|
||||
uint32_t dOctets;
|
||||
uint32_t First;
|
||||
uint32_t Last;
|
||||
uint16_t srcport;
|
||||
uint16_t dstport;
|
||||
uint16_t pad1;
|
||||
uint8_t prot;
|
||||
uint8_t tos;
|
||||
uint8_t tcp_flags;
|
||||
uint8_t pad2[7];
|
||||
} netflow_v1_record_t;
|
||||
|
||||
|
||||
/* prototypes */
|
||||
int Init_v1(void);
|
||||
|
||||
void Process_v1(void *in_buff, ssize_t in_buff_cnt, FlowSource_t *fs);
|
||||
|
||||
/*
|
||||
* Extension map for v1
|
||||
*
|
||||
* Required extensions:
|
||||
*
|
||||
* 4 byte byte counter
|
||||
* | 4byte packet counter
|
||||
* | | IPv4
|
||||
* | | |
|
||||
* xxxx x0 0 0
|
||||
*
|
||||
* Optional extensions:
|
||||
*
|
||||
* 4 : 2 byte input/output interface id
|
||||
* 9 : IPv4 next hop
|
||||
*/
|
||||
|
||||
#endif //_NETFLOW_V1_H
|
796
bin/netflow_v5_v7.c
Normal file
796
bin/netflow_v5_v7.c
Normal file
@ -0,0 +1,796 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: netflow_v5_v7.c 69 2010-09-09 07:17:43Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 69 $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <syslog.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
#include "nffile.h"
|
||||
#include "nfx.h"
|
||||
#include "nfnet.h"
|
||||
#include "nf_common.h"
|
||||
#include "bookkeeper.h"
|
||||
#include "nfxstat.h"
|
||||
#include "collector.h"
|
||||
#include "exporter.h"
|
||||
#include "netflow_v5_v7.h"
|
||||
|
||||
#ifndef DEVEL
|
||||
# define dbg_printf(...) /* printf(__VA_ARGS__) */
|
||||
#else
|
||||
# define dbg_printf(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
extern int verbose;
|
||||
extern extension_descriptor_t extension_descriptor[];
|
||||
extern uint32_t default_sampling;
|
||||
extern uint32_t overwrite_sampling;
|
||||
|
||||
/* module limited globals */
|
||||
static extension_info_t v5_extension_info; // common for all v5 records
|
||||
static uint16_t v5_output_record_size, v5_output_record_base_size;
|
||||
|
||||
// All required extension to save full v5 records
|
||||
static uint16_t v5_full_mapp[] = { EX_IO_SNMP_2, EX_AS_2, EX_MULIPLE, EX_NEXT_HOP_v4, EX_ROUTER_IP_v4, EX_ROUTER_ID, EX_RECEIVED, 0 };
|
||||
|
||||
// to simplify, assume blocks with 64 bit counters to check for enough buffer space
|
||||
// regardless if 32 or 64 bit packet/byte counters
|
||||
#define V5_BLOCK_DATA_SIZE (sizeof(ipv4_block_t) - sizeof(uint32_t) + 2 * sizeof(uint64_t))
|
||||
|
||||
typedef struct exporter_v5_s {
|
||||
// identical to generic_exporter_t
|
||||
struct exporter_v5_s *next;
|
||||
|
||||
// generic exporter information
|
||||
exporter_info_record_t info;
|
||||
|
||||
uint64_t packets; // number of packets sent by this exporter
|
||||
uint64_t flows; // number of flow records sent by this exporter
|
||||
uint32_t sequence_failure; // number of sequence failues
|
||||
|
||||
// generic sampler
|
||||
generic_sampler_t *sampler;
|
||||
// end of generic_exporter_t
|
||||
|
||||
// sequence vars
|
||||
int64_t last_sequence;
|
||||
int64_t sequence, distance;
|
||||
int64_t last_count;
|
||||
|
||||
int first;
|
||||
|
||||
// extension map
|
||||
extension_map_t *extension_map;
|
||||
|
||||
} exporter_v5_t;
|
||||
|
||||
// for sending netflow v5
|
||||
static netflow_v5_header_t *v5_output_header;
|
||||
static netflow_v5_record_t *v5_output_record;
|
||||
static exporter_v5_t output_engine;
|
||||
|
||||
static inline exporter_v5_t *GetExporter(FlowSource_t *fs, netflow_v5_header_t *header);
|
||||
|
||||
static inline int CheckBufferSpace(nffile_t *nffile, size_t required);
|
||||
|
||||
/* functions */
|
||||
|
||||
#include "nffile_inline.c"
|
||||
|
||||
int Init_v5_v7_input(void) {
|
||||
int i, id, map_index;
|
||||
int extension_size;
|
||||
uint16_t map_size;
|
||||
|
||||
extension_size = 0;
|
||||
// prepare v5 extension map
|
||||
v5_extension_info.map = NULL;
|
||||
v5_extension_info.next = NULL;
|
||||
v5_extension_info.offset_cache = NULL;
|
||||
v5_extension_info.ref_count = 0;
|
||||
|
||||
// default map - 0 extensions
|
||||
map_size = sizeof(extension_map_t);
|
||||
i=0;
|
||||
while ( (id = v5_full_mapp[i]) != 0 ) {
|
||||
if ( extension_descriptor[id].enabled ) {
|
||||
extension_size += extension_descriptor[id].size;
|
||||
map_size += sizeof(uint16_t);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
// extension_size contains the sum of all optional extensions
|
||||
// caculate the record size without counters!
|
||||
v5_output_record_base_size = COMMON_RECORD_DATA_SIZE + 8 + extension_size; // + 8 for 2 x IPv4 addr
|
||||
|
||||
// align 32 bits
|
||||
if ( ( map_size & 0x3 ) != 0 )
|
||||
map_size += 2;
|
||||
|
||||
// Create a generic v5 extension map
|
||||
v5_extension_info.map = (extension_map_t *)malloc((size_t)map_size);
|
||||
if ( !v5_extension_info.map ) {
|
||||
syslog(LOG_ERR, "Process_v5: malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno));
|
||||
return 0;
|
||||
}
|
||||
v5_extension_info.map->type = ExtensionMapType;
|
||||
v5_extension_info.map->size = map_size;
|
||||
v5_extension_info.map->map_id = INIT_ID;
|
||||
v5_extension_info.map->extension_size = extension_size;
|
||||
|
||||
// see netflow_v5_v7.h for extension map description
|
||||
map_index = 0;
|
||||
i=0;
|
||||
while ( (id = v5_full_mapp[i]) != 0 ) {
|
||||
if ( extension_descriptor[id].enabled )
|
||||
v5_extension_info.map->ex_id[map_index++] = id;
|
||||
i++;
|
||||
}
|
||||
v5_extension_info.map->ex_id[map_index] = 0;
|
||||
|
||||
return 1;
|
||||
} // End of Init_v5_input
|
||||
|
||||
/*
|
||||
* functions used for receiving netflow v5 records
|
||||
*/
|
||||
|
||||
|
||||
static inline exporter_v5_t *GetExporter(FlowSource_t *fs, netflow_v5_header_t *header) {
|
||||
exporter_v5_t **e = (exporter_v5_t **)&(fs->exporter_data);
|
||||
generic_sampler_t *sampler;
|
||||
uint16_t engine_tag = ntohs(header->engine_tag);
|
||||
uint16_t version = ntohs(header->version);
|
||||
#define IP_STRING_LEN 40
|
||||
char ipstr[IP_STRING_LEN];
|
||||
|
||||
// search the appropriate exporter engine
|
||||
while ( *e ) {
|
||||
if ( (*e)->info.version == version && (*e)->info.id == engine_tag &&
|
||||
(*e)->info.ip.v6[0] == fs->ip.v6[0] && (*e)->info.ip.v6[1] == fs->ip.v6[1])
|
||||
return *e;
|
||||
e = &((*e)->next);
|
||||
}
|
||||
|
||||
// nothing found
|
||||
*e = (exporter_v5_t *)malloc(sizeof(exporter_v5_t));
|
||||
if ( !(*e)) {
|
||||
syslog(LOG_ERR, "Process_v5: malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno));
|
||||
return NULL;
|
||||
}
|
||||
memset((void *)(*e), 0, sizeof(exporter_v5_t));
|
||||
(*e)->next = NULL;
|
||||
(*e)->info.header.type = ExporterInfoRecordType;
|
||||
(*e)->info.header.size = sizeof(exporter_info_record_t);
|
||||
(*e)->info.version = version;
|
||||
(*e)->info.id = engine_tag;
|
||||
(*e)->info.ip = fs->ip;
|
||||
(*e)->info.sa_family = fs->sa_family;
|
||||
(*e)->sequence_failure = 0;
|
||||
(*e)->packets = 0;
|
||||
(*e)->flows = 0;
|
||||
(*e)->first = 1;
|
||||
|
||||
sampler = (generic_sampler_t *)malloc(sizeof(generic_sampler_t));
|
||||
if ( !sampler ) {
|
||||
syslog(LOG_ERR, "Process_v5: malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno));
|
||||
return NULL;
|
||||
}
|
||||
(*e)->sampler = sampler;
|
||||
|
||||
sampler->info.header.type = SamplerInfoRecordype;
|
||||
sampler->info.header.size = sizeof(sampler_info_record_t);
|
||||
sampler->info.id = -1;
|
||||
sampler->info.mode = (0xC000 & ntohs(header->sampling_interval)) >> 14;
|
||||
sampler->info.interval = 0x3fff & ntohs(header->sampling_interval);
|
||||
sampler->next = NULL;
|
||||
|
||||
// default is global default_sampling ( user defined or unsampled => 1 )
|
||||
if ( sampler->info.interval == 0 )
|
||||
sampler->info.interval = default_sampling;
|
||||
|
||||
// copy the v5 generic extension map
|
||||
(*e)->extension_map = (extension_map_t *)malloc(v5_extension_info.map->size);
|
||||
if ( !(*e)->extension_map ) {
|
||||
syslog(LOG_ERR, "Process_v5: malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno));
|
||||
free(*e);
|
||||
*e = NULL;
|
||||
return NULL;
|
||||
}
|
||||
memcpy((void *)(*e)->extension_map, (void *)v5_extension_info.map, v5_extension_info.map->size);
|
||||
|
||||
if ( !AddExtensionMap(fs, (*e)->extension_map) ) {
|
||||
// bad - we must free this map and fail - otherwise data can not be read any more
|
||||
free((*e)->extension_map);
|
||||
free(*e);
|
||||
*e = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(*e)->info.sysid = 0;
|
||||
FlushInfoExporter(fs, &((*e)->info));
|
||||
sampler->info.exporter_sysid = (*e)->info.sysid;
|
||||
FlushInfoSampler(fs, &(sampler->info));
|
||||
|
||||
if ( fs->sa_family == AF_INET ) {
|
||||
uint32_t _ip = htonl(fs->ip.v4);
|
||||
inet_ntop(AF_INET, &_ip, ipstr, sizeof(ipstr));
|
||||
} else if ( fs->sa_family == AF_INET6 ) {
|
||||
uint64_t _ip[2];
|
||||
_ip[0] = htonll(fs->ip.v6[0]);
|
||||
_ip[1] = htonll(fs->ip.v6[1]);
|
||||
inet_ntop(AF_INET6, &_ip, ipstr, sizeof(ipstr));
|
||||
} else {
|
||||
strncpy(ipstr, "<unknown>", IP_STRING_LEN);
|
||||
}
|
||||
|
||||
|
||||
|
||||
dbg_printf("New Exporter: v5 SysID: %u, Extension ID: %i, IP: %s, Sampling Mode: %i, Sampling Interval: %u\n",
|
||||
(*e)->info.sysid, (*e)->extension_map->map_id, ipstr, sampler->info.mode ,sampler->info.interval);
|
||||
syslog(LOG_INFO, "Process_v5: New exporter: SysID: %u, engine id %u, type %u, IP: %s, Sampling Mode: %i, Sampling Interval: %u\n",
|
||||
(*e)->info.sysid, ( engine_tag & 0xFF ),( (engine_tag >> 8) & 0xFF ), ipstr, sampler->info.mode ,sampler->info.interval );
|
||||
|
||||
if ( overwrite_sampling > 0 ) {
|
||||
sampler->info.interval = overwrite_sampling;
|
||||
syslog(LOG_INFO, "Process_v5: Hard overwrite sampling rate: %u\n", sampler->info.interval);
|
||||
}
|
||||
|
||||
return (*e);
|
||||
|
||||
} // End of GetExporter
|
||||
|
||||
void Process_v5_v7(void *in_buff, ssize_t in_buff_cnt, FlowSource_t *fs) {
|
||||
netflow_v5_header_t *v5_header;
|
||||
netflow_v5_record_t *v5_record;
|
||||
exporter_v5_t *exporter;
|
||||
extension_map_t *extension_map;
|
||||
common_record_t *common_record;
|
||||
uint64_t start_time, end_time, boot_time;
|
||||
uint32_t First, Last;
|
||||
uint16_t count;
|
||||
uint8_t flags;
|
||||
int i, done, version, flow_record_length;
|
||||
ssize_t size_left;
|
||||
char *string;
|
||||
|
||||
/*
|
||||
* v7 is treated as v5. It differes only in the record length, for what we process.
|
||||
*/
|
||||
|
||||
// map v5 data structure to input buffer
|
||||
v5_header = (netflow_v5_header_t *)in_buff;
|
||||
|
||||
exporter = GetExporter(fs, v5_header);
|
||||
if ( !exporter ) {
|
||||
syslog(LOG_ERR,"Process_v5: Exporter NULL: Abort v5/v7 record processing");
|
||||
return;
|
||||
}
|
||||
exporter->packets++;
|
||||
|
||||
// calculate record size depending on counter size
|
||||
// sigh .. one day I should fix switch to 64bits
|
||||
if ( exporter->sampler->info.interval == 1 ) {
|
||||
flags = 0;
|
||||
v5_output_record_size = v5_output_record_base_size + 8; // 2 x 4 byte counters
|
||||
} else {
|
||||
flags = 0;
|
||||
SetFlag(flags, FLAG_SAMPLED);
|
||||
SetFlag(flags, FLAG_PKG_64);
|
||||
SetFlag(flags, FLAG_BYTES_64);
|
||||
v5_output_record_size = v5_output_record_base_size + 16; // 2 x 8 byte counters
|
||||
}
|
||||
|
||||
extension_map = exporter->extension_map;
|
||||
|
||||
version = ntohs(v5_header->version);
|
||||
flow_record_length = version == 5 ? NETFLOW_V5_RECORD_LENGTH : NETFLOW_V7_RECORD_LENGTH;
|
||||
|
||||
// this many data to process
|
||||
size_left = in_buff_cnt;
|
||||
|
||||
common_record = fs->nffile->buff_ptr;
|
||||
done = 0;
|
||||
while ( !done ) {
|
||||
ipv4_block_t *ipv4_block;
|
||||
|
||||
/* Process header */
|
||||
|
||||
// count check
|
||||
count = ntohs(v5_header->count);
|
||||
if ( count > NETFLOW_V5_MAX_RECORDS ) {
|
||||
syslog(LOG_ERR,"Process_v5: Unexpected record count in header: %i. Abort v5/v7 record processing", count);
|
||||
fs->nffile->buff_ptr = (void *)common_record;
|
||||
return;
|
||||
}
|
||||
|
||||
// input buffer size check for all expected records
|
||||
if ( size_left < ( NETFLOW_V5_HEADER_LENGTH + count * flow_record_length) ) {
|
||||
syslog(LOG_ERR,"Process_v5: Not enough data to process v5 record. Abort v5/v7 record processing");
|
||||
fs->nffile->buff_ptr = (void *)common_record;
|
||||
return;
|
||||
}
|
||||
|
||||
// output buffer size check for all expected records
|
||||
if ( !CheckBufferSpace(fs->nffile, count * v5_output_record_size) ) {
|
||||
// fishy! - should never happen. maybe disk full?
|
||||
syslog(LOG_ERR,"Process_v5: output buffer size error. Abort v5/v7 record processing");
|
||||
return;
|
||||
}
|
||||
|
||||
// map output record to memory buffer
|
||||
common_record = (common_record_t *)fs->nffile->buff_ptr;
|
||||
ipv4_block = (ipv4_block_t *)common_record->data;
|
||||
|
||||
// sequence check
|
||||
if ( exporter->first ) {
|
||||
exporter->last_sequence = ntohl(v5_header->flow_sequence);
|
||||
exporter->sequence = exporter->last_sequence;
|
||||
exporter->first = 0;
|
||||
} else {
|
||||
exporter->last_sequence = exporter->sequence;
|
||||
exporter->sequence = ntohl(v5_header->flow_sequence);
|
||||
exporter->distance = exporter->sequence - exporter->last_sequence;
|
||||
// handle overflow
|
||||
if (exporter->distance < 0) {
|
||||
exporter->distance = 0xffffffff + exporter->distance +1;
|
||||
}
|
||||
if (exporter->distance != exporter->last_count) {
|
||||
#define delta(a,b) ( (a)>(b) ? (a)-(b) : (b)-(a) )
|
||||
fs->nffile->stat_record->sequence_failure++;
|
||||
exporter->sequence_failure++;
|
||||
/*
|
||||
syslog(LOG_ERR,"Flow v%d sequence last:%llu now:%llu mismatch. Missing: dist:%lu flows",
|
||||
version, exporter->last_sequence, exporter->sequence, exporter->distance);
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
||||
exporter->last_count = count;
|
||||
|
||||
v5_header->SysUptime = ntohl(v5_header->SysUptime);
|
||||
v5_header->unix_secs = ntohl(v5_header->unix_secs);
|
||||
v5_header->unix_nsecs = ntohl(v5_header->unix_nsecs);
|
||||
|
||||
/* calculate boot time in msec */
|
||||
boot_time = ((uint64_t)(v5_header->unix_secs)*1000 +
|
||||
((uint64_t)(v5_header->unix_nsecs) / 1000000) ) - (uint64_t)(v5_header->SysUptime);
|
||||
|
||||
// process all records
|
||||
v5_record = (netflow_v5_record_t *)((pointer_addr_t)v5_header + NETFLOW_V5_HEADER_LENGTH);
|
||||
|
||||
/* loop over each records associated with this header */
|
||||
for (i = 0; i < count; i++) {
|
||||
pointer_addr_t bsize;
|
||||
uint64_t packets, bytes;
|
||||
void *data_ptr;
|
||||
uint8_t *s1, *s2;
|
||||
int j, id;
|
||||
// header data
|
||||
common_record->flags = flags;
|
||||
common_record->type = CommonRecordType;
|
||||
common_record->exporter_sysid = exporter->info.sysid;;
|
||||
common_record->ext_map = extension_map->map_id;
|
||||
common_record->size = v5_output_record_size;
|
||||
|
||||
// v5 common fields
|
||||
common_record->srcport = ntohs(v5_record->srcport);
|
||||
common_record->dstport = ntohs(v5_record->dstport);
|
||||
common_record->tcp_flags = v5_record->tcp_flags;
|
||||
common_record->prot = v5_record->prot;
|
||||
common_record->tos = v5_record->tos;
|
||||
common_record->fwd_status = 0;
|
||||
common_record->reserved = 0;
|
||||
|
||||
// v5 typed data as fixed struct v5_block
|
||||
ipv4_block->srcaddr = ntohl(v5_record->srcaddr);
|
||||
ipv4_block->dstaddr = ntohl(v5_record->dstaddr);
|
||||
|
||||
if ( exporter->sampler->info.interval == 1 ) {
|
||||
value32_t *v = (value32_t *)ipv4_block->data;
|
||||
|
||||
packets = (uint64_t)ntohl(v5_record->dPkts);
|
||||
bytes = (uint64_t)ntohl(v5_record->dOctets);
|
||||
|
||||
v->val = packets;
|
||||
v = (value32_t *)v->data;
|
||||
v->val = bytes;
|
||||
|
||||
data_ptr = (void *)v->data;
|
||||
} else {
|
||||
value64_t *v = (value64_t *)ipv4_block->data;
|
||||
uint32_t *ptr = (uint32_t *)&packets;
|
||||
|
||||
packets = (uint64_t)ntohl(v5_record->dPkts) * (uint64_t)exporter->sampler->info.interval;
|
||||
bytes = (uint64_t)ntohl(v5_record->dOctets) * (uint64_t)exporter->sampler->info.interval;
|
||||
|
||||
// pack packets in 32bit chunks
|
||||
v->val.val32[0] = ptr[0];
|
||||
v->val.val32[1] = ptr[1];
|
||||
|
||||
// pack bytes in 32bit chunks
|
||||
v = (value64_t *)v->data;
|
||||
ptr = (uint32_t *)&bytes;
|
||||
v->val.val32[0] = ptr[0];
|
||||
v->val.val32[1] = ptr[1];
|
||||
|
||||
data_ptr = (void *)v->data;
|
||||
}
|
||||
|
||||
// process optional extensions
|
||||
j = 0;
|
||||
while ( (id = extension_map->ex_id[j]) != 0 ) {
|
||||
switch (id) {
|
||||
case EX_IO_SNMP_2: { // 2 byte input/output interface index
|
||||
tpl_ext_4_t *tpl = (tpl_ext_4_t *)data_ptr;
|
||||
tpl->input = ntohs(v5_record->input);
|
||||
tpl->output = ntohs(v5_record->output);
|
||||
data_ptr = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_AS_2: { // 2 byte src/dst AS number
|
||||
tpl_ext_6_t *tpl = (tpl_ext_6_t *)data_ptr;
|
||||
tpl->src_as = ntohs(v5_record->src_as);
|
||||
tpl->dst_as = ntohs(v5_record->dst_as);
|
||||
data_ptr = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_MULIPLE: { // dst tos, direction, src/dst mask
|
||||
tpl_ext_8_t *tpl = (tpl_ext_8_t *)data_ptr;
|
||||
tpl->dst_tos = 0;
|
||||
tpl->dir = 0;
|
||||
tpl->src_mask = v5_record->src_mask;
|
||||
tpl->dst_mask = v5_record->dst_mask;
|
||||
data_ptr = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_NEXT_HOP_v4: { // IPv4 next hop
|
||||
tpl_ext_9_t *tpl = (tpl_ext_9_t *)data_ptr;
|
||||
tpl->nexthop = ntohl(v5_record->nexthop);
|
||||
data_ptr = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_ROUTER_IP_v4: { // IPv4 router address
|
||||
tpl_ext_23_t *tpl = (tpl_ext_23_t *)data_ptr;
|
||||
tpl->router_ip = fs->ip.v4;
|
||||
data_ptr = (void *)tpl->data;
|
||||
ClearFlag(common_record->flags, FLAG_IPV6_EXP);
|
||||
} break;
|
||||
case EX_ROUTER_ID: { // engine type, engine ID
|
||||
tpl_ext_25_t *tpl = (tpl_ext_25_t *)data_ptr;
|
||||
uint16_t engine_tag = ntohs(v5_header->engine_tag);
|
||||
tpl->engine_type = (engine_tag >> 8) & 0xFF;
|
||||
tpl->engine_id = (engine_tag & 0xFF);
|
||||
data_ptr = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_RECEIVED: {
|
||||
tpl_ext_27_t *tpl = (tpl_ext_27_t *)data_ptr;
|
||||
tpl->received = (uint64_t)((uint64_t)fs->received.tv_sec * 1000LL) + (uint64_t)((uint64_t)fs->received.tv_usec / 1000LL);
|
||||
data_ptr = (void *)tpl->data;
|
||||
} break;
|
||||
|
||||
default:
|
||||
// this should never happen, as v5 has no other extensions
|
||||
syslog(LOG_ERR,"Process_v5: Unexpected extension %i for v5 record. Skip extension", id);
|
||||
}
|
||||
j++;
|
||||
}
|
||||
|
||||
// Time issues
|
||||
First = ntohl(v5_record->First);
|
||||
Last = ntohl(v5_record->Last);
|
||||
|
||||
#ifdef FIXTIMEBUG
|
||||
/*
|
||||
* Some users report, that they see flows, which have duration time of about 40days
|
||||
* which is almost the overflow value. Investigating this, it cannot be an overflow
|
||||
* and the difference is always 15160 or 15176 msec too little for a classical
|
||||
* overflow. Therefore assume this must be an exporter bug
|
||||
*/
|
||||
if ( First > Last && ( (First - Last) < 20000) ) {
|
||||
uint32_t _t;
|
||||
syslog(LOG_ERR,"Process_v5: Unexpected time swap: First 0x%llx smaller than boot time: 0x%llx", start_time, boot_time);
|
||||
_t= First;
|
||||
First = Last;
|
||||
Last = _t;
|
||||
}
|
||||
#endif
|
||||
if ( First > Last ) {
|
||||
/* First in msec, in case of msec overflow, between start and end */
|
||||
start_time = boot_time - 0x100000000LL + (uint64_t)First;
|
||||
} else {
|
||||
start_time = boot_time + (uint64_t)First;
|
||||
}
|
||||
|
||||
/* end time in msecs */
|
||||
end_time = (uint64_t)Last + boot_time;
|
||||
|
||||
// if overflow happened after flow ended but before got exported
|
||||
// the additional check > 100000 is required due to a CISCO IOS bug
|
||||
// CSCei12353 - thanks to Bojan
|
||||
if ( Last > v5_header->SysUptime && (( Last - v5_header->SysUptime) > 100000)) {
|
||||
start_time -= 0x100000000LL;
|
||||
end_time -= 0x100000000LL;
|
||||
}
|
||||
|
||||
common_record->first = start_time/1000;
|
||||
common_record->msec_first = start_time - common_record->first*1000;
|
||||
|
||||
common_record->last = end_time/1000;
|
||||
common_record->msec_last = end_time - common_record->last*1000;
|
||||
|
||||
// update first_seen, last_seen
|
||||
if ( start_time < fs->first_seen )
|
||||
fs->first_seen = start_time;
|
||||
if ( end_time > fs->last_seen )
|
||||
fs->last_seen = end_time;
|
||||
|
||||
|
||||
// Update stats
|
||||
switch (common_record->prot) {
|
||||
case IPPROTO_ICMP:
|
||||
fs->nffile->stat_record->numflows_icmp++;
|
||||
fs->nffile->stat_record->numpackets_icmp += packets;
|
||||
fs->nffile->stat_record->numbytes_icmp += bytes;
|
||||
// fix odd CISCO behaviour for ICMP port/type in src port
|
||||
if ( common_record->srcport != 0 ) {
|
||||
s1 = (uint8_t *)&(common_record->srcport);
|
||||
s2 = (uint8_t *)&(common_record->dstport);
|
||||
s2[0] = s1[1];
|
||||
s2[1] = s1[0];
|
||||
common_record->srcport = 0;
|
||||
}
|
||||
break;
|
||||
case IPPROTO_TCP:
|
||||
fs->nffile->stat_record->numflows_tcp++;
|
||||
fs->nffile->stat_record->numpackets_tcp += packets;
|
||||
fs->nffile->stat_record->numbytes_tcp += bytes;
|
||||
break;
|
||||
case IPPROTO_UDP:
|
||||
fs->nffile->stat_record->numflows_udp++;
|
||||
fs->nffile->stat_record->numpackets_udp += packets;
|
||||
fs->nffile->stat_record->numbytes_udp += bytes;
|
||||
break;
|
||||
default:
|
||||
fs->nffile->stat_record->numflows_other++;
|
||||
fs->nffile->stat_record->numpackets_other += packets;
|
||||
fs->nffile->stat_record->numbytes_other += bytes;
|
||||
}
|
||||
exporter->flows++;
|
||||
fs->nffile->stat_record->numflows++;
|
||||
fs->nffile->stat_record->numpackets += packets;
|
||||
fs->nffile->stat_record->numbytes += bytes;
|
||||
|
||||
if ( fs->xstat ) {
|
||||
uint32_t bpp = packets ? (bytes/packets) : 0;
|
||||
if ( bpp > MAX_BPP )
|
||||
bpp = MAX_BPP;
|
||||
if ( common_record->prot == IPPROTO_TCP ) {
|
||||
fs->xstat->bpp_histogram->tcp.bpp[bpp]++;
|
||||
fs->xstat->bpp_histogram->tcp.count++;
|
||||
|
||||
fs->xstat->port_histogram->src_tcp.port[common_record->srcport]++;
|
||||
fs->xstat->port_histogram->dst_tcp.port[common_record->dstport]++;
|
||||
fs->xstat->port_histogram->src_tcp.count++;
|
||||
fs->xstat->port_histogram->dst_tcp.count++;
|
||||
} else if ( common_record->prot == IPPROTO_UDP ) {
|
||||
fs->xstat->bpp_histogram->udp.bpp[bpp]++;
|
||||
fs->xstat->bpp_histogram->udp.count++;
|
||||
|
||||
fs->xstat->port_histogram->src_udp.port[common_record->srcport]++;
|
||||
fs->xstat->port_histogram->dst_udp.port[common_record->dstport]++;
|
||||
fs->xstat->port_histogram->src_udp.count++;
|
||||
fs->xstat->port_histogram->dst_udp.count++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( verbose ) {
|
||||
master_record_t master_record;
|
||||
ExpandRecord_v2((common_record_t *)common_record, &v5_extension_info, &(exporter->info), &master_record);
|
||||
format_file_block_record(&master_record, &string, 0);
|
||||
printf("%s\n", string);
|
||||
}
|
||||
|
||||
// advance to next input flow record
|
||||
v5_record = (netflow_v5_record_t *)((pointer_addr_t)v5_record + flow_record_length);
|
||||
|
||||
if ( ((pointer_addr_t)data_ptr - (pointer_addr_t)common_record) != v5_output_record_size ) {
|
||||
printf("Panic size check: ptr diff: %llu, record size: %u\n",
|
||||
(unsigned long long)((pointer_addr_t)data_ptr - (pointer_addr_t)common_record), v5_output_record_size );
|
||||
abort();
|
||||
}
|
||||
// advance to next output record
|
||||
common_record = (common_record_t *)data_ptr;
|
||||
ipv4_block = (ipv4_block_t *)common_record->data;
|
||||
|
||||
// buffer size sanity check - should never happen, but check it anyway
|
||||
bsize = (pointer_addr_t)common_record - (pointer_addr_t)fs->nffile->block_header - sizeof(data_block_header_t);
|
||||
if ( bsize >= BUFFSIZE ) {
|
||||
syslog(LOG_ERR,"### Software error ###: %s line %d", __FILE__, __LINE__);
|
||||
syslog(LOG_ERR,"Process_v5: Output buffer overflow! Flush buffer and skip records.");
|
||||
syslog(LOG_ERR,"Buffer size: size: %u, bsize: %llu > %u", fs->nffile->block_header->size, (unsigned long long)bsize, BUFFSIZE);
|
||||
// reset buffer
|
||||
fs->nffile->block_header->size = 0;
|
||||
fs->nffile->block_header->NumRecords = 0;
|
||||
fs->nffile->buff_ptr = (void *)((pointer_addr_t)fs->nffile->block_header + sizeof(data_block_header_t) );
|
||||
return;
|
||||
}
|
||||
|
||||
} // End of foreach v5 record
|
||||
|
||||
// update file record size ( -> output buffer size )
|
||||
fs->nffile->block_header->NumRecords += count;
|
||||
fs->nffile->block_header->size += count * v5_output_record_size;
|
||||
fs->nffile->buff_ptr = (void *)common_record;
|
||||
|
||||
// still to go for this many input bytes
|
||||
size_left -= NETFLOW_V5_HEADER_LENGTH + count * flow_record_length;
|
||||
|
||||
// next header
|
||||
v5_header = (netflow_v5_header_t *)v5_record;
|
||||
|
||||
// should never be < 0
|
||||
done = size_left <= 0;
|
||||
|
||||
} // End of while !done
|
||||
|
||||
return;
|
||||
|
||||
} /* End of Process_v5 */
|
||||
|
||||
/*
|
||||
* functions used for sending netflow v5 records
|
||||
*/
|
||||
void Init_v5_v7_output(send_peer_t *peer) {
|
||||
|
||||
v5_output_header = (netflow_v5_header_t *)peer->send_buffer;
|
||||
v5_output_header->version = htons(5);
|
||||
v5_output_header->SysUptime = 0;
|
||||
v5_output_header->unix_secs = 0;
|
||||
v5_output_header->unix_nsecs = 0;
|
||||
v5_output_header->count = 0;
|
||||
output_engine.first = 1;
|
||||
|
||||
output_engine.sequence = 0;
|
||||
output_engine.last_sequence = 0;
|
||||
output_engine.last_count = 0;
|
||||
output_engine.sequence_failure = 0;
|
||||
v5_output_record = (netflow_v5_record_t *)((pointer_addr_t)v5_output_header + (pointer_addr_t)sizeof(netflow_v5_header_t));
|
||||
|
||||
} // End of Init_v5_v7_output
|
||||
|
||||
int Add_v5_output_record(master_record_t *master_record, send_peer_t *peer) {
|
||||
static uint64_t boot_time; // in msec
|
||||
static int cnt;
|
||||
extension_map_t *extension_map = master_record->map_ref;
|
||||
uint32_t i, id, t1, t2;
|
||||
|
||||
// Skip IPv6 records
|
||||
if ( (master_record->flags & FLAG_IPV6_ADDR ) != 0 )
|
||||
return 0;
|
||||
|
||||
if ( output_engine.first ) { // first time a record is added
|
||||
// boot time is set one day back - assuming that the start time of every flow does not start ealier
|
||||
boot_time = (uint64_t)(master_record->first - 86400)*1000;
|
||||
v5_output_header->unix_secs = htonl(master_record->first - 86400);
|
||||
cnt = 0;
|
||||
output_engine.first = 0;
|
||||
}
|
||||
if ( cnt == 0 ) {
|
||||
peer->buff_ptr = (void *)((pointer_addr_t)peer->send_buffer + NETFLOW_V5_HEADER_LENGTH);
|
||||
v5_output_record = (netflow_v5_record_t *)((pointer_addr_t)v5_output_header + (pointer_addr_t)sizeof(netflow_v5_header_t));
|
||||
output_engine.sequence = output_engine.last_sequence + output_engine.last_count;
|
||||
v5_output_header->flow_sequence = htonl(output_engine.sequence);
|
||||
output_engine.last_sequence = output_engine.sequence;
|
||||
}
|
||||
|
||||
t1 = (uint32_t)(1000LL * (uint64_t)master_record->first + (uint64_t)master_record->msec_first - boot_time);
|
||||
t2 = (uint32_t)(1000LL * (uint64_t)master_record->last + (uint64_t)master_record->msec_last - boot_time);
|
||||
v5_output_record->First = htonl(t1);
|
||||
v5_output_record->Last = htonl(t2);
|
||||
|
||||
v5_output_record->srcaddr = htonl(master_record->v4.srcaddr);
|
||||
v5_output_record->dstaddr = htonl(master_record->v4.dstaddr);
|
||||
|
||||
v5_output_record->srcport = htons(master_record->srcport);
|
||||
v5_output_record->dstport = htons(master_record->dstport);
|
||||
v5_output_record->tcp_flags = master_record->tcp_flags;
|
||||
v5_output_record->prot = master_record->prot;
|
||||
v5_output_record->tos = master_record->tos;
|
||||
|
||||
// the 64bit counters are cut down to 32 bits for v5
|
||||
v5_output_record->dPkts = htonl((uint32_t)master_record->dPkts);
|
||||
v5_output_record->dOctets = htonl((uint32_t)master_record->dOctets);
|
||||
|
||||
v5_output_record->input = 0;
|
||||
v5_output_record->output = 0;
|
||||
v5_output_record->src_as = 0;
|
||||
v5_output_record->dst_as = 0;
|
||||
v5_output_record->src_mask = 0;
|
||||
v5_output_record->dst_mask = 0;
|
||||
v5_output_record->pad1 = 0;
|
||||
v5_output_record->pad2 = 0;
|
||||
v5_output_record->nexthop = 0;
|
||||
|
||||
i = 0;
|
||||
while ( (id = extension_map->ex_id[i]) != 0 ) {
|
||||
switch (id) {
|
||||
case EX_IO_SNMP_2:
|
||||
v5_output_record->input = htons(master_record->input);
|
||||
v5_output_record->output = htons(master_record->output);
|
||||
break;
|
||||
case EX_AS_2:
|
||||
v5_output_record->src_as = htons(master_record->srcas);
|
||||
v5_output_record->dst_as = htons(master_record->dstas);
|
||||
break;
|
||||
case EX_MULIPLE:
|
||||
v5_output_record->src_mask = master_record->src_mask;
|
||||
v5_output_record->dst_mask = master_record->dst_mask;
|
||||
break;
|
||||
case EX_NEXT_HOP_v4:
|
||||
v5_output_record->nexthop = htonl(master_record->ip_nexthop.v4);
|
||||
break;
|
||||
// default: Other extensions can not be sent with v5
|
||||
}
|
||||
i++;
|
||||
}
|
||||
cnt++;
|
||||
|
||||
v5_output_header->count = htons(cnt);
|
||||
peer->buff_ptr = (void *)((pointer_addr_t)peer->buff_ptr + NETFLOW_V5_RECORD_LENGTH);
|
||||
v5_output_record++;
|
||||
if ( cnt == NETFLOW_V5_MAX_RECORDS ) {
|
||||
peer->flush = 1;
|
||||
output_engine.last_count = cnt;
|
||||
cnt = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
} // End of Add_v5_output_record
|
149
bin/netflow_v5_v7.h
Normal file
149
bin/netflow_v5_v7.h
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: netflow_v5_v7.h 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NETFLOW_V5_V7_H
|
||||
#define _NETFLOW_V5_V7_H 1
|
||||
|
||||
#define NETFLOW_V5_HEADER_LENGTH 24
|
||||
#define NETFLOW_V5_RECORD_LENGTH 48
|
||||
#define NETFLOW_V5_MAX_RECORDS 30
|
||||
|
||||
#define NETFLOW_V7_HEADER_LENGTH 24
|
||||
#define NETFLOW_V7_RECORD_LENGTH 52
|
||||
#define NETFLOW_V7_MAX_RECORDS 28
|
||||
|
||||
/* v5 structures */
|
||||
typedef struct netflow_v5_header {
|
||||
uint16_t version;
|
||||
uint16_t count;
|
||||
uint32_t SysUptime;
|
||||
uint32_t unix_secs;
|
||||
uint32_t unix_nsecs;
|
||||
uint32_t flow_sequence;
|
||||
uint16_t engine_tag;
|
||||
uint16_t sampling_interval;
|
||||
} netflow_v5_header_t;
|
||||
|
||||
typedef struct netflow_v5_record {
|
||||
uint32_t srcaddr;
|
||||
uint32_t dstaddr;
|
||||
uint32_t nexthop;
|
||||
uint16_t input;
|
||||
uint16_t output;
|
||||
uint32_t dPkts;
|
||||
uint32_t dOctets;
|
||||
uint32_t First;
|
||||
uint32_t Last;
|
||||
uint16_t srcport;
|
||||
uint16_t dstport;
|
||||
uint8_t pad1;
|
||||
uint8_t tcp_flags;
|
||||
uint8_t prot;
|
||||
uint8_t tos;
|
||||
uint16_t src_as;
|
||||
uint16_t dst_as;
|
||||
uint8_t src_mask;
|
||||
uint8_t dst_mask;
|
||||
uint16_t pad2;
|
||||
} netflow_v5_record_t;
|
||||
|
||||
|
||||
/* v7 structures */
|
||||
typedef struct netflow_v7_header {
|
||||
uint16_t version;
|
||||
uint16_t count;
|
||||
uint32_t SysUptime;
|
||||
uint32_t unix_secs;
|
||||
uint32_t unix_nsecs;
|
||||
uint32_t flow_sequence;
|
||||
uint32_t reserved;
|
||||
} netflow_v7_header_t;
|
||||
|
||||
typedef struct netflow_v7_record {
|
||||
uint32_t srcaddr;
|
||||
uint32_t dstaddr;
|
||||
uint32_t nexthop;
|
||||
uint16_t input;
|
||||
uint16_t output;
|
||||
uint32_t dPkts;
|
||||
uint32_t dOctets;
|
||||
uint32_t First;
|
||||
uint32_t Last;
|
||||
uint16_t srcport;
|
||||
uint16_t dstport;
|
||||
uint8_t flags;
|
||||
uint8_t tcp_flags;
|
||||
uint8_t prot;
|
||||
uint8_t tos;
|
||||
uint16_t src_as;
|
||||
uint16_t dst_as;
|
||||
uint8_t src_mask;
|
||||
uint8_t dst_mask;
|
||||
uint16_t pad;
|
||||
uint32_t router_sc;
|
||||
} netflow_v7_record_t;
|
||||
|
||||
/* prototypes */
|
||||
int Init_v5_v7_input(void);
|
||||
|
||||
void Process_v5_v7(void *in_buff, ssize_t in_buff_cnt, FlowSource_t *fs);
|
||||
|
||||
void Init_v5_v7_output(send_peer_t *peer);
|
||||
|
||||
int Add_v5_output_record(master_record_t *master_record, send_peer_t *peer);
|
||||
|
||||
/*
|
||||
* Extension map for v5/v7
|
||||
*
|
||||
* Required extensions:
|
||||
*
|
||||
* 4 byte byte counter
|
||||
* | 4byte packet counter
|
||||
* | | IPv4
|
||||
* | | |
|
||||
* xxxx x0 0 0
|
||||
*
|
||||
* Optional extensions:
|
||||
*
|
||||
* 4 : 2 byte input/output interface id
|
||||
* 6 : 2 byte src/dst as
|
||||
* 8 : srcmask/dst mask dst tos = 0, dir = 0
|
||||
* 9 : IPv4 next hop
|
||||
*/
|
||||
|
||||
#endif //_NETFLOW_V5_V7_H
|
3064
bin/netflow_v9.c
Normal file
3064
bin/netflow_v9.c
Normal file
File diff suppressed because it is too large
Load Diff
309
bin/netflow_v9.h
Normal file
309
bin/netflow_v9.h
Normal file
@ -0,0 +1,309 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: netflow_v9.h 51 2010-01-29 09:01:54Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 51 $
|
||||
*
|
||||
*/
|
||||
|
||||
/* v9 structures */
|
||||
|
||||
/* Packet Header Field Descriptions
|
||||
*
|
||||
* Version
|
||||
* Version of Flow Record format exported in this packet. The
|
||||
* value of this field is 9 for the current version.
|
||||
*
|
||||
* Count
|
||||
* The total number of records in the Export Packet, which is the
|
||||
* sum of Options FlowSet records, Template FlowSet records, and
|
||||
* Data FlowSet records.
|
||||
*
|
||||
* sysUpTime
|
||||
* Time in milliseconds since this device was first booted.
|
||||
*
|
||||
* UNIX Secs
|
||||
* Time in seconds since 0000 UTC 1970, at which the Export Packet
|
||||
* leaves the Exporter.
|
||||
*
|
||||
* Sequence Number
|
||||
* Incremental sequence counter of all Export Packets sent from
|
||||
* the current Observation Domain by the Exporter. This value
|
||||
* MUST be cumulative, and SHOULD be used by the Collector to
|
||||
* identify whether any Export Packets have been missed.
|
||||
*
|
||||
* Source ID
|
||||
* A 32-bit value that identifies the Exporter Observation Domain.
|
||||
* NetFlow Collectors SHOULD use the combination of the source IP
|
||||
* address and the Source ID field to separate different export
|
||||
* streams originating from the same Exporter.
|
||||
*/
|
||||
|
||||
#ifndef _NETFLOW_V9_H
|
||||
#define _NETFLOW_V9_H 1
|
||||
|
||||
typedef struct netflow_v9_header {
|
||||
uint16_t version;
|
||||
uint16_t count;
|
||||
uint32_t SysUptime;
|
||||
uint32_t unix_secs;
|
||||
uint32_t sequence;
|
||||
uint32_t source_id;
|
||||
} netflow_v9_header_t;
|
||||
|
||||
#define NETFLOW_V9_HEADER_LENGTH sizeof(netflow_v9_header_t)
|
||||
|
||||
/* FlowSet ID
|
||||
* FlowSet ID value of 0 is reserved for the Template FlowSet.
|
||||
* Length
|
||||
* Total length of this FlowSet. Because an individual Template
|
||||
* FlowSet MAY contain multiple Template Records, the Length value
|
||||
* MUST be used to determine the position of the next FlowSet
|
||||
* record, which could be any type of FlowSet. Length is the sum
|
||||
* of the lengths of the FlowSet ID, the Length itself, and all
|
||||
* Template Records within this FlowSet.
|
||||
*
|
||||
* Template ID
|
||||
* Each of the newly generated Template Records is given a unique
|
||||
* Template ID. This uniqueness is local to the Observation
|
||||
* Domain that generated the Template ID. Template IDs 0-255 are
|
||||
* reserved for Template FlowSets, Options FlowSets, and other
|
||||
* reserved FlowSets yet to be created. Template IDs of Data
|
||||
* FlowSets are numbered from 256 to 65535.
|
||||
*
|
||||
* Field Count
|
||||
* Number of fields in this Template Record. Because a Template
|
||||
* FlowSet usually contains multiple Template Records, this field
|
||||
* allows the Collector to determine the end of the current
|
||||
* Template Record and the start of the next.
|
||||
*
|
||||
* Field Type
|
||||
* A numeric value that represents the type of the field. Refer
|
||||
* to the "Field Type Definitions" section.
|
||||
*
|
||||
* Field Length
|
||||
* The length of the corresponding Field Type, in bytes. Refer to
|
||||
* the "Field Type Definitions" section.
|
||||
*/
|
||||
|
||||
typedef struct template_record_s {
|
||||
uint16_t template_id;
|
||||
uint16_t count;
|
||||
struct {
|
||||
uint16_t type;
|
||||
uint16_t length;
|
||||
} record[1];
|
||||
} template_record_t;
|
||||
|
||||
typedef struct template_flowset_s {
|
||||
uint16_t flowset_id;
|
||||
uint16_t length;
|
||||
template_record_t fields[1];
|
||||
} template_flowset_t;
|
||||
|
||||
typedef struct data_flowset_s {
|
||||
uint16_t flowset_id;
|
||||
uint16_t length;
|
||||
uint8_t data[4];
|
||||
} data_flowset_t;
|
||||
|
||||
typedef struct option_template_flowset_s {
|
||||
uint16_t flowset_id;
|
||||
uint16_t length;
|
||||
uint16_t template_id;
|
||||
uint16_t option_scope_length;
|
||||
uint16_t option_length;
|
||||
struct {
|
||||
uint16_t type;
|
||||
uint16_t length;
|
||||
} record[1];
|
||||
} option_template_flowset_t;
|
||||
|
||||
typedef struct common_header_s {
|
||||
uint16_t flowset_id;
|
||||
uint16_t length;
|
||||
} common_header_t;
|
||||
|
||||
#define _1byte 1
|
||||
#define _2bytes 2
|
||||
#define _3bytes 3
|
||||
#define _4bytes 4
|
||||
#define _6bytes 6
|
||||
#define _8bytes 8
|
||||
#define _12bytes 12
|
||||
#define _16bytes 16
|
||||
#define _20bytes 20
|
||||
#define _24bytes 24
|
||||
#define _65bytes 65
|
||||
#define _72bytes 72
|
||||
|
||||
#define NF9_TEMPLATE_FLOWSET_ID 0
|
||||
#define NF9_OPTIONS_FLOWSET_ID 1
|
||||
#define NF9_MIN_RECORD_FLOWSET_ID 256
|
||||
|
||||
// Flowset record types
|
||||
#define NF9_IN_BYTES 1
|
||||
#define NF9_IN_PACKETS 2
|
||||
#define NF9_FLOWS_AGGR 3
|
||||
#define NF9_IN_PROTOCOL 4
|
||||
#define NF9_SRC_TOS 5
|
||||
#define NF9_TCP_FLAGS 6
|
||||
#define NF9_L4_SRC_PORT 7
|
||||
#define NF9_IPV4_SRC_ADDR 8
|
||||
#define NF9_SRC_MASK 9
|
||||
#define NF9_INPUT_SNMP 10
|
||||
#define NF9_L4_DST_PORT 11
|
||||
#define NF9_IPV4_DST_ADDR 12
|
||||
#define NF9_DST_MASK 13
|
||||
#define NF9_OUTPUT_SNMP 14
|
||||
#define NF9_V4_NEXT_HOP 15
|
||||
#define NF9_SRC_AS 16
|
||||
#define NF9_DST_AS 17
|
||||
#define NF9_BGP_V4_NEXT_HOP 18
|
||||
|
||||
#define NF9_LAST_SWITCHED 21
|
||||
#define NF9_FIRST_SWITCHED 22
|
||||
#define NF9_OUT_BYTES 23
|
||||
#define NF9_OUT_PKTS 24
|
||||
|
||||
#define NF9_IPV6_SRC_ADDR 27
|
||||
#define NF9_IPV6_DST_ADDR 28
|
||||
#define NF9_IPV6_SRC_MASK 29
|
||||
#define NF9_IPV6_DST_MASK 30
|
||||
|
||||
#define NF9_IPV6_FLOW_LABEL 31
|
||||
#define NF9_ICMP_TYPE 32
|
||||
|
||||
#define NF9_SAMPLING_INTERVAL 34
|
||||
#define NF9_SAMPLING_ALGORITHM 35
|
||||
|
||||
#define NF9_ENGINE_TYPE 38
|
||||
#define NF9_ENGINE_ID 39
|
||||
|
||||
#define NF9_FLOW_SAMPLER_ID 48
|
||||
#define FLOW_SAMPLER_MODE 49
|
||||
#define NF9_FLOW_SAMPLER_RANDOM_INTERVAL 50
|
||||
|
||||
// #define NF9_MIN_TTL 52
|
||||
// #define NF9_MAX_TTL 53
|
||||
// #define NF9_IPV4_IDENT 54
|
||||
|
||||
#define NF9_DST_TOS 55
|
||||
#define NF9_IN_SRC_MAC 56
|
||||
#define NF9_OUT_DST_MAC 57
|
||||
#define NF9_SRC_VLAN 58
|
||||
#define NF9_DST_VLAN 59
|
||||
|
||||
#define NF9_DIRECTION 61
|
||||
#define NF9_V6_NEXT_HOP 62
|
||||
#define NF9_BPG_V6_NEXT_HOP 63
|
||||
// #define NF9_V6_OPTION_HEADERS 64
|
||||
|
||||
#define NF9_MPLS_LABEL_1 70
|
||||
#define NF9_MPLS_LABEL_2 71
|
||||
#define NF9_MPLS_LABEL_3 72
|
||||
#define NF9_MPLS_LABEL_4 73
|
||||
#define NF9_MPLS_LABEL_5 74
|
||||
#define NF9_MPLS_LABEL_6 75
|
||||
#define NF9_MPLS_LABEL_7 76
|
||||
#define NF9_MPLS_LABEL_8 77
|
||||
#define NF9_MPLS_LABEL_9 78
|
||||
#define NF9_MPLS_LABEL_10 79
|
||||
#define NF9_IN_DST_MAC 80
|
||||
#define NF9_OUT_SRC_MAC 81
|
||||
|
||||
|
||||
#define NF9_FORWARDING_STATUS 89
|
||||
|
||||
#define NF9_BGP_ADJ_NEXT_AS 128
|
||||
#define NF9_BGP_ADJ_PREV_AS 129
|
||||
|
||||
// CISCO ASA NSEL extension - Network Security Event Logging
|
||||
#define NF_F_FLOW_BYTES 85
|
||||
#define NF_F_CONN_ID 148
|
||||
#define NF_F_FLOW_CREATE_TIME_MSEC 152
|
||||
#define NF_F_FLOW_END_TIME_MSEC 153
|
||||
#define NF_F_ICMP_TYPE 176
|
||||
#define NF_F_ICMP_CODE 177
|
||||
#define NF_F_ICMP_TYPE_IPV6 178
|
||||
#define NF_F_ICMP_CODE_IPV6 179
|
||||
#define NF_F_FWD_FLOW_DELTA_BYTES 231
|
||||
#define NF_F_REV_FLOW_DELTA_BYTES 232
|
||||
#define NF_F_EVENT_TIME_MSEC 323
|
||||
#define NF_F_INGRESS_ACL_ID 33000
|
||||
#define NF_F_EGRESS_ACL_ID 33001
|
||||
#define NF_F_FW_EXT_EVENT 33002
|
||||
#define NF_F_USERNAME 40000
|
||||
|
||||
#define NF_F_XLATE_SRC_ADDR_IPV4 225
|
||||
#define NF_F_XLATE_DST_ADDR_IPV4 226
|
||||
#define NF_F_XLATE_SRC_PORT 227
|
||||
#define NF_F_XLATE_DST_PORT 228
|
||||
#define NF_F_XLATE_SRC_ADDR_IPV6 281
|
||||
#define NF_F_XLATE_DST_ADDR_IPV6 282
|
||||
#define NF_F_FW_EVENT 233
|
||||
|
||||
// ASA 8.4 compat elements
|
||||
#define NF_F_XLATE_SRC_ADDR_84 40001
|
||||
#define NF_F_XLATE_DST_ADDR_84 40002
|
||||
#define NF_F_XLATE_SRC_PORT_84 40003
|
||||
#define NF_F_XLATE_DST_PORT_84 40004
|
||||
#define NF_F_FW_EVENT_84 40005
|
||||
|
||||
// Cisco ASR 1000 series NEL extension - Nat Event Logging
|
||||
#define NF_N_NAT_EVENT 230
|
||||
#define NF_N_INGRESS_VRFID 234
|
||||
#define NF_N_EGRESS_VRFID 235
|
||||
#define NF_F_XLATE_PORT_BLOCK_START 361
|
||||
#define NF_F_XLATE_PORT_BLOCK_END 362
|
||||
#define NF_F_XLATE_PORT_BLOCK_STEP 363
|
||||
#define NF_F_XLATE_PORT_BLOCK_SIZE 364
|
||||
|
||||
// nprobe latency extensions
|
||||
#define NF9_NPROBE_CLIENT_NW_DELAY_SEC 57554
|
||||
#define NF9_NPROBE_CLIENT_NW_DELAY_USEC 57555
|
||||
#define NF9_NPROBE_SERVER_NW_DELAY_SEC 57556
|
||||
#define NF9_NPROBE_SERVER_NW_DELAY_USEC 57557
|
||||
#define NF9_NPROBE_APPL_LATENCY_SEC 57558
|
||||
#define NF9_NPROBE_APPL_LATENCY_USEC 57559
|
||||
|
||||
/* prototypes */
|
||||
int Init_v9(void);
|
||||
|
||||
void Process_v9(void *in_buff, ssize_t in_buff_cnt, FlowSource_t *fs);
|
||||
|
||||
void Init_v9_output(send_peer_t *peer);
|
||||
|
||||
int Add_v9_output_record(master_record_t *master_record, send_peer_t *peer);
|
||||
|
||||
#endif //_NETFLOW_V9_H 1
|
2887
bin/nf_common.c
Normal file
2887
bin/nf_common.c
Normal file
File diff suppressed because it is too large
Load Diff
122
bin/nf_common.h
Normal file
122
bin/nf_common.h
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: nf_common.h 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NF_COMMON_H
|
||||
#define _NF_COMMON_H 1
|
||||
|
||||
|
||||
typedef void (*printer_t)(void *, char **, int);
|
||||
|
||||
#if ( SIZEOF_VOID_P == 8 )
|
||||
typedef uint64_t pointer_addr_t;
|
||||
#else
|
||||
typedef uint32_t pointer_addr_t;
|
||||
#endif
|
||||
|
||||
typedef struct msec_time_s {
|
||||
time_t sec;
|
||||
uint16_t msec;
|
||||
} msec_time_tt;
|
||||
|
||||
/* common minimum netflow header for all versions */
|
||||
typedef struct common_flow_header {
|
||||
uint16_t version;
|
||||
uint16_t count;
|
||||
} common_flow_header_t;
|
||||
|
||||
typedef struct printmap_s {
|
||||
char *printmode; // name of the output format
|
||||
printer_t func; // name of the function, which prints the record
|
||||
char *Format; // output format definition
|
||||
} printmap_t;
|
||||
|
||||
#define NSEL_EVENT_IGNORE 0LL
|
||||
#define NSEL_EVENT_CREATE 1LL
|
||||
#define NSEL_EVENT_DELETE 2LL
|
||||
#define NSEL_EVENT_DENIED 3LL
|
||||
#define NSEL_EVENT_ALERT 4LL
|
||||
#define NSEL_EVENT_UPDATE 5LL
|
||||
|
||||
#define NEL_EVENT_INVALID 0LL
|
||||
#define NEL_EVENT_ADD 1LL
|
||||
#define NEL_EVENT_DELETE 2LL
|
||||
|
||||
/* prototypes */
|
||||
|
||||
int InitSymbols(void);
|
||||
|
||||
void Setv6Mode(int mode);
|
||||
|
||||
int Getv6Mode(void);
|
||||
|
||||
int Proto_num(char *protostr);
|
||||
|
||||
void format_file_block_header(void *header, char **s, int tag);
|
||||
|
||||
char *format_csv_header(void);
|
||||
|
||||
char *get_record_header(void);
|
||||
|
||||
void set_record_header(void);
|
||||
|
||||
void format_file_block_record(void *record, char **s, int tag);
|
||||
|
||||
void flow_record_to_pipe(void *record, char ** s, int tag);
|
||||
|
||||
void flow_record_to_csv(void *record, char ** s, int tag);
|
||||
|
||||
void flow_record_to_null(void *record, char ** s, int tag);
|
||||
|
||||
int ParseOutputFormat(char *format, int plain_numbers, printmap_t *printmap);
|
||||
|
||||
void format_special(void *record, char ** s, int tag);
|
||||
|
||||
|
||||
uint32_t Get_fwd_status_id(char *status);
|
||||
|
||||
char *Get_fwd_status_name(uint32_t id);
|
||||
|
||||
void Proto_string(uint8_t protonum, char *protostr);
|
||||
|
||||
void condense_v6(char *s);
|
||||
|
||||
#define TAG_CHAR ''
|
||||
|
||||
#endif //_NF_COMMON_H
|
||||
|
483
bin/nfanon.c
Executable file
483
bin/nfanon.c
Executable file
@ -0,0 +1,483 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id:$
|
||||
*
|
||||
* $LastChangedRevision: 48 $
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/param.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "nffile.h"
|
||||
#include "nfx.h"
|
||||
#include "util.h"
|
||||
#include "flist.h"
|
||||
#include "panonymizer.h"
|
||||
|
||||
#if ( SIZEOF_VOID_P == 8 )
|
||||
typedef uint64_t pointer_addr_t;
|
||||
#else
|
||||
typedef uint32_t pointer_addr_t;
|
||||
#endif
|
||||
|
||||
// module limited globals
|
||||
extension_map_list_t *extension_map_list;
|
||||
|
||||
/* Function Prototypes */
|
||||
static void usage(char *name);
|
||||
|
||||
static inline void AnonRecord(master_record_t *master_record);
|
||||
|
||||
static void process_data(void *wfile);
|
||||
|
||||
/* Functions */
|
||||
|
||||
#define NEED_PACKRECORD 1
|
||||
#include "nffile_inline.c"
|
||||
#undef NEED_PACKRECORD
|
||||
|
||||
static void usage(char *name) {
|
||||
printf("usage %s [options] \n"
|
||||
"-h\t\tthis text you see right here\n"
|
||||
"-K <key>\tAnonymize IP addressses using CryptoPAn with key <key>.\n"
|
||||
"-r\t\tread input from file\n"
|
||||
"-M <expr>\tRead input from multiple directories.\n"
|
||||
"-R <expr>\tRead input from sequence of files.\n"
|
||||
"-w <file>\tName of output file. Defaults to input file.\n"
|
||||
, name);
|
||||
} /* usage */
|
||||
|
||||
static inline void AnonRecord(master_record_t *master_record) {
|
||||
extension_map_t *extension_map = master_record->map_ref;
|
||||
int i;
|
||||
|
||||
// Required extension 1 - IP addresses
|
||||
if ( (master_record->flags & FLAG_IPV6_ADDR) != 0 ) { // IPv6
|
||||
// IPv6
|
||||
uint64_t anon_ip[2];
|
||||
anonymize_v6(master_record->v6.srcaddr, anon_ip);
|
||||
master_record->v6.srcaddr[0] = anon_ip[0];
|
||||
master_record->v6.srcaddr[1] = anon_ip[1];
|
||||
|
||||
anonymize_v6(master_record->v6.dstaddr, anon_ip);
|
||||
master_record->v6.dstaddr[0] = anon_ip[0];
|
||||
master_record->v6.dstaddr[1] = anon_ip[1];
|
||||
|
||||
} else {
|
||||
// IPv4
|
||||
master_record->v4.srcaddr = anonymize(master_record->v4.srcaddr);
|
||||
master_record->v4.dstaddr = anonymize(master_record->v4.dstaddr);
|
||||
}
|
||||
|
||||
// Process optional extensions
|
||||
i=0;
|
||||
while ( extension_map->ex_id[i] ) {
|
||||
switch (extension_map->ex_id[i++]) {
|
||||
case EX_AS_2: // srcas/dstas 2 byte
|
||||
master_record->srcas = 0;
|
||||
master_record->dstas = 0;
|
||||
break;
|
||||
case EX_AS_4: // srcas/dstas 4 byte
|
||||
master_record->srcas = 0;
|
||||
master_record->dstas = 0;
|
||||
break;
|
||||
case EX_NEXT_HOP_v4:
|
||||
master_record->ip_nexthop.v4 = anonymize(master_record->ip_nexthop.v4);
|
||||
break;
|
||||
case EX_NEXT_HOP_v6: {
|
||||
uint64_t anon_ip[2];
|
||||
anonymize_v6(master_record->ip_nexthop.v6, anon_ip);
|
||||
master_record->ip_nexthop.v6[0] = anon_ip[0];
|
||||
master_record->ip_nexthop.v6[1] = anon_ip[1];
|
||||
} break;
|
||||
case EX_NEXT_HOP_BGP_v4:
|
||||
master_record->bgp_nexthop.v4 = anonymize(master_record->bgp_nexthop.v4);
|
||||
break;
|
||||
case EX_NEXT_HOP_BGP_v6: {
|
||||
uint64_t anon_ip[2];
|
||||
anonymize_v6(master_record->bgp_nexthop.v6, anon_ip);
|
||||
master_record->bgp_nexthop.v6[0] = anon_ip[0];
|
||||
master_record->bgp_nexthop.v6[1] = anon_ip[1];
|
||||
} break;
|
||||
case EX_ROUTER_IP_v4:
|
||||
master_record->ip_router.v4 = anonymize(master_record->ip_router.v4);
|
||||
break;
|
||||
case EX_ROUTER_IP_v6: {
|
||||
uint64_t anon_ip[2];
|
||||
anonymize_v6(master_record->ip_router.v6, anon_ip);
|
||||
master_record->ip_router.v6[0] = anon_ip[0];
|
||||
master_record->ip_router.v6[1] = anon_ip[1];
|
||||
} break;
|
||||
#ifdef NSEL
|
||||
case EX_NSEL_XLATE_IP_v4:
|
||||
master_record->xlate_src_ip.v4 = anonymize(master_record->xlate_src_ip.v4);
|
||||
master_record->xlate_dst_ip.v4 = anonymize(master_record->xlate_dst_ip.v4);
|
||||
break;
|
||||
case EX_NSEL_XLATE_IP_v6: {
|
||||
uint64_t anon_ip[2];
|
||||
anonymize_v6(master_record->xlate_src_ip.v6, anon_ip);
|
||||
master_record->xlate_src_ip.v6[0] = anon_ip[0];
|
||||
master_record->xlate_src_ip.v6[1] = anon_ip[1];
|
||||
anonymize_v6(master_record->xlate_dst_ip.v6, anon_ip);
|
||||
master_record->xlate_dst_ip.v6[0] = anon_ip[0];
|
||||
master_record->xlate_dst_ip.v6[1] = anon_ip[1];
|
||||
} break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
} // End of AnonRecord
|
||||
|
||||
|
||||
static void process_data(void *wfile) {
|
||||
master_record_t master_record;
|
||||
common_record_t *flow_record;
|
||||
nffile_t *nffile_r;
|
||||
nffile_t *nffile_w;
|
||||
int i, done, ret, cnt, verbose;
|
||||
char outfile[MAXPATHLEN], *cfile;
|
||||
#ifdef COMPAT15
|
||||
int v1_map_done = 0;
|
||||
#endif
|
||||
|
||||
|
||||
setbuf(stderr, NULL);
|
||||
cnt = 1;
|
||||
verbose = 1;
|
||||
|
||||
// Get the first file handle
|
||||
nffile_r = GetNextFile(NULL, 0, 0);
|
||||
if ( !nffile_r ) {
|
||||
LogError("GetNextFile() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return;
|
||||
}
|
||||
if ( nffile_r == EMPTY_LIST ) {
|
||||
LogError("Empty file list. No files to process\n");
|
||||
return;
|
||||
}
|
||||
|
||||
cfile = GetCurrentFilename();
|
||||
if ( !cfile ) {
|
||||
if ( nffile_r->fd == 0 ) { // stdin
|
||||
outfile[0] = '-';
|
||||
outfile[1] = '\0';
|
||||
verbose = 0;
|
||||
} else {
|
||||
LogError("(NULL) input file name error in %s line %d\n", __FILE__, __LINE__);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// prepare output file
|
||||
snprintf(outfile,MAXPATHLEN-1, "%s-tmp", cfile);
|
||||
outfile[MAXPATHLEN-1] = '\0';
|
||||
if ( verbose )
|
||||
fprintf(stderr, " %i Processing %s\r", cnt++, cfile);
|
||||
}
|
||||
|
||||
if ( wfile )
|
||||
nffile_w = OpenNewFile(wfile, NULL, FILE_IS_COMPRESSED(nffile_r), 1, NULL);
|
||||
else
|
||||
nffile_w = OpenNewFile(outfile, NULL, FILE_IS_COMPRESSED(nffile_r), 1, NULL);
|
||||
|
||||
if ( !nffile_w ) {
|
||||
if ( nffile_r ) {
|
||||
CloseFile(nffile_r);
|
||||
DisposeFile(nffile_r);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy((void *)nffile_w->stat_record, (void *)nffile_r->stat_record, sizeof(stat_record_t));
|
||||
|
||||
done = 0;
|
||||
while ( !done ) {
|
||||
// get next data block from file
|
||||
ret = ReadBlock(nffile_r);
|
||||
|
||||
switch (ret) {
|
||||
case NF_CORRUPT:
|
||||
case NF_ERROR:
|
||||
if ( ret == NF_CORRUPT )
|
||||
LogError("Skip corrupt data file '%s'\n",GetCurrentFilename());
|
||||
else
|
||||
LogError("Read error in file '%s': %s\n",GetCurrentFilename(), strerror(errno) );
|
||||
// fall through - get next file in chain
|
||||
case NF_EOF: {
|
||||
nffile_t *next;
|
||||
if ( nffile_w->block_header->NumRecords ) {
|
||||
if ( WriteBlock(nffile_w) <= 0 ) {
|
||||
LogError("Failed to write output buffer to disk: '%s'" , strerror(errno));
|
||||
}
|
||||
}
|
||||
if ( wfile == NULL ) {
|
||||
CloseUpdateFile(nffile_w, nffile_r->file_header->ident);
|
||||
if ( rename(outfile, cfile) < 0 ) {
|
||||
LogError("\nrename() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
LogError("Abort processing.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
next = GetNextFile(nffile_r, 0, 0);
|
||||
if ( next == EMPTY_LIST ) {
|
||||
done = 1;
|
||||
continue;
|
||||
}
|
||||
if ( next == NULL ) {
|
||||
LogError("Unexpected end of file list\n");
|
||||
done = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
cfile = GetCurrentFilename();
|
||||
if ( !cfile ) {
|
||||
LogError("(NULL) input file name error in %s line %d\n", __FILE__, __LINE__);
|
||||
return;
|
||||
}
|
||||
LogError(" %i Processing %s\r", cnt++, cfile);
|
||||
|
||||
if ( wfile == NULL ) {
|
||||
snprintf(outfile,MAXPATHLEN-1, "%s-tmp", cfile);
|
||||
outfile[MAXPATHLEN-1] = '\0';
|
||||
|
||||
nffile_w = OpenNewFile(outfile, nffile_w, FILE_IS_COMPRESSED(nffile_r), 1, NULL);
|
||||
if ( !nffile_w ) {
|
||||
if ( nffile_r ) {
|
||||
CloseFile(nffile_r);
|
||||
DisposeFile(nffile_r);
|
||||
}
|
||||
return;
|
||||
}
|
||||
memcpy((void *)nffile_w->stat_record, (void *)&nffile_r->stat_record, sizeof(stat_record_t));
|
||||
} else {
|
||||
SumStatRecords(nffile_w->stat_record, nffile_r->stat_record);
|
||||
}
|
||||
|
||||
// continue with next file
|
||||
continue;
|
||||
|
||||
} break; // not really needed
|
||||
}
|
||||
|
||||
#ifdef COMPAT15
|
||||
if ( nffile_r->block_header->id == DATA_BLOCK_TYPE_1 ) {
|
||||
common_record_v1_t *v1_record = (common_record_v1_t *)nffile_r->buff_ptr;
|
||||
// create an extension map for v1 blocks
|
||||
if ( v1_map_done == 0 ) {
|
||||
extension_map_t *map = malloc(sizeof(extension_map_t) + 2 * sizeof(uint16_t) );
|
||||
if ( ! map ) {
|
||||
LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
exit(255);
|
||||
}
|
||||
map->type = ExtensionMapType;
|
||||
map->size = sizeof(extension_map_t) + 2 * sizeof(uint16_t);
|
||||
map->map_id = 0;
|
||||
map->ex_id[0] = EX_IO_SNMP_2;
|
||||
map->ex_id[1] = EX_AS_2;
|
||||
map->ex_id[2] = 0;
|
||||
|
||||
Insert_Extension_Map(extension_map_list, map);
|
||||
AppendToBuffer(nffile_w, (void *)map, map->size);
|
||||
|
||||
v1_map_done = 1;
|
||||
}
|
||||
|
||||
// convert the records to v2
|
||||
for ( i=0; i < nffile_r->block_header->NumRecords; i++ ) {
|
||||
common_record_t *v2_record = (common_record_t *)v1_record;
|
||||
Convert_v1_to_v2((void *)v1_record);
|
||||
// now we have a v2 record -> use size of v2_record->size
|
||||
v1_record = (common_record_v1_t *)((pointer_addr_t)v1_record + v2_record->size);
|
||||
}
|
||||
nffile_r->block_header->id = DATA_BLOCK_TYPE_2;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( nffile_r->block_header->id == Large_BLOCK_Type ) {
|
||||
// skip
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( nffile_r->block_header->id != DATA_BLOCK_TYPE_2 ) {
|
||||
fprintf(stderr, "Can't process block type %u. Skip block.\n", nffile_r->block_header->id);
|
||||
continue;
|
||||
}
|
||||
|
||||
flow_record = nffile_r->buff_ptr;
|
||||
for ( i=0; i < nffile_r->block_header->NumRecords; i++ ) {
|
||||
switch ( flow_record->type ) {
|
||||
case CommonRecordV0Type:
|
||||
case CommonRecordType: {
|
||||
uint32_t map_id = flow_record->ext_map;
|
||||
if ( extension_map_list->slot[map_id] == NULL ) {
|
||||
LogError("Corrupt data file! No such extension map id: %u. Skip record", flow_record->ext_map );
|
||||
} else {
|
||||
ExpandRecord_v2( flow_record, extension_map_list->slot[flow_record->ext_map], NULL, &master_record);
|
||||
|
||||
// update number of flows matching a given map
|
||||
extension_map_list->slot[map_id]->ref_count++;
|
||||
|
||||
AnonRecord(&master_record);
|
||||
PackRecord(&master_record, nffile_w);
|
||||
}
|
||||
|
||||
} break;
|
||||
case ExtensionMapType: {
|
||||
extension_map_t *map = (extension_map_t *)flow_record;
|
||||
|
||||
if ( Insert_Extension_Map(extension_map_list, map) ) {
|
||||
// flush new map
|
||||
} // else map already known and flushed
|
||||
AppendToBuffer(nffile_w, (void *)map, map->size);
|
||||
|
||||
} break;
|
||||
case ExporterRecordType:
|
||||
case SamplerRecordype:
|
||||
case ExporterInfoRecordType:
|
||||
case ExporterStatRecordType:
|
||||
case SamplerInfoRecordype:
|
||||
// Silently skip exporter/sampler records
|
||||
break;
|
||||
|
||||
default: {
|
||||
fprintf(stderr, "Skip unknown record type %i\n", flow_record->type);
|
||||
}
|
||||
}
|
||||
// Advance pointer by number of bytes for netflow record
|
||||
flow_record = (common_record_t *)((pointer_addr_t)flow_record + flow_record->size);
|
||||
|
||||
} // for all records
|
||||
|
||||
} // while
|
||||
|
||||
PackExtensionMapList(extension_map_list);
|
||||
if ( wfile != NULL )
|
||||
CloseUpdateFile(nffile_w, nffile_r->file_header->ident);
|
||||
|
||||
if ( nffile_r ) {
|
||||
CloseFile(nffile_r);
|
||||
DisposeFile(nffile_r);
|
||||
}
|
||||
|
||||
DisposeFile(nffile_w);
|
||||
|
||||
LogError("\n");
|
||||
LogError("Processed %i files.\n", --cnt);
|
||||
|
||||
} // End of process_data
|
||||
|
||||
|
||||
int main( int argc, char **argv ) {
|
||||
char *rfile, *Rfile, *wfile, *Mdirs;
|
||||
int c;
|
||||
char CryptoPAnKey[32];
|
||||
|
||||
rfile = Rfile = Mdirs = wfile = NULL;
|
||||
while ((c = getopt(argc, argv, "K:L:r:M:R:w:")) != EOF) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
exit(0);
|
||||
break;
|
||||
break;
|
||||
case 'K':
|
||||
if ( !ParseCryptoPAnKey(optarg, CryptoPAnKey) ) {
|
||||
fprintf(stderr, "Invalid key '%s' for CryptoPAn!\n", optarg);
|
||||
exit(255);
|
||||
}
|
||||
PAnonymizer_Init((uint8_t *)CryptoPAnKey);
|
||||
break;
|
||||
case 'L':
|
||||
if ( !InitLog("argv[0]", optarg) )
|
||||
exit(255);
|
||||
break;
|
||||
case 'r':
|
||||
rfile = optarg;
|
||||
if ( strcmp(rfile, "-") == 0 )
|
||||
rfile = NULL;
|
||||
break;
|
||||
case 'M':
|
||||
Mdirs = optarg;
|
||||
break;
|
||||
case 'R':
|
||||
Rfile = optarg;
|
||||
break;
|
||||
case 'w':
|
||||
wfile = optarg;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
if ( rfile && Rfile ) {
|
||||
fprintf(stderr, "-r and -R are mutually exclusive. Please specify either -r or -R\n");
|
||||
exit(255);
|
||||
}
|
||||
if ( Mdirs && !(rfile || Rfile) ) {
|
||||
fprintf(stderr, "-M needs either -r or -R to specify the file or file list. Add '-R .' for all files in the directories.\n");
|
||||
exit(255);
|
||||
}
|
||||
|
||||
extension_map_list = InitExtensionMaps(NEEDS_EXTENSION_LIST);
|
||||
|
||||
SetupInputFileSequence(Mdirs, rfile, Rfile);
|
||||
|
||||
process_data(wfile);
|
||||
|
||||
FreeExtensionMaps(extension_map_list);
|
||||
|
||||
return 0;
|
||||
}
|
1236
bin/nfcapd.c
Normal file
1236
bin/nfcapd.c
Normal file
File diff suppressed because it is too large
Load Diff
1236
bin/nfdump.c
Normal file
1236
bin/nfdump.c
Normal file
File diff suppressed because it is too large
Load Diff
85
bin/nfdump.h
Normal file
85
bin/nfdump.h
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: nfdump.h 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NFDUMP_H
|
||||
#define _NFDUMP_H 1
|
||||
|
||||
#define BuffNumRecords 1024
|
||||
|
||||
/*
|
||||
* Offset definitions for filter engine. Offsets must agree with the defined
|
||||
* flow record definition data_block_record_t in nffile.h
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
typedef struct FilterParam {
|
||||
uint16_t comp;
|
||||
uint16_t direction;
|
||||
uint32_t data;
|
||||
uint32_t inout;
|
||||
uint32_t acl;
|
||||
uint32_t self;
|
||||
} FilterParam_t;
|
||||
|
||||
/* IP tree type */
|
||||
typedef RB_HEAD(IPtree, IPListNode) IPlist_t;
|
||||
|
||||
/* Port/AS tree type */
|
||||
typedef RB_HEAD(ULongtree, ULongListNode) ULongtree_t;
|
||||
|
||||
/* parser/scanner prototypes */
|
||||
int yyparse(void);
|
||||
|
||||
int yylex(void);
|
||||
|
||||
void lex_cleanup(void);
|
||||
|
||||
void lex_init(char *buf);
|
||||
|
||||
int ScreenIPString(char *string);
|
||||
|
||||
int ScreenIdentString(char *string);
|
||||
|
||||
// Insert the RB prototypes here
|
||||
RB_PROTOTYPE(IPtree, IPListNode, entry, IPNodeCMP);
|
||||
|
||||
RB_PROTOTYPE(ULongtree, ULongListNode, entry, ULNodeCMP);
|
||||
|
||||
#endif //_NFDUMP_H
|
||||
|
188
bin/nfdump.test.diff
Normal file
188
bin/nfdump.test.diff
Normal file
@ -0,0 +1,188 @@
|
||||
3c3
|
||||
< Flags = 0x06 FLOW, Unsampled
|
||||
---
|
||||
> Flags = 0x00 FLOW, Unsampled
|
||||
5c5
|
||||
< size = 196
|
||||
---
|
||||
> size = 172
|
||||
57c57
|
||||
< Flags = 0x06 FLOW, Unsampled
|
||||
---
|
||||
> Flags = 0x00 FLOW, Unsampled
|
||||
59c59
|
||||
< size = 196
|
||||
---
|
||||
> size = 172
|
||||
111c111
|
||||
< Flags = 0x06 FLOW, Unsampled
|
||||
---
|
||||
> Flags = 0x00 FLOW, Unsampled
|
||||
113c113
|
||||
< size = 196
|
||||
---
|
||||
> size = 172
|
||||
165c165
|
||||
< Flags = 0x06 FLOW, Unsampled
|
||||
---
|
||||
> Flags = 0x00 FLOW, Unsampled
|
||||
167c167
|
||||
< size = 196
|
||||
---
|
||||
> size = 172
|
||||
219c219
|
||||
< Flags = 0x06 FLOW, Unsampled
|
||||
---
|
||||
> Flags = 0x00 FLOW, Unsampled
|
||||
221c221
|
||||
< size = 196
|
||||
---
|
||||
> size = 172
|
||||
273c273
|
||||
< Flags = 0x06 FLOW, Unsampled
|
||||
---
|
||||
> Flags = 0x00 FLOW, Unsampled
|
||||
275c275
|
||||
< size = 196
|
||||
---
|
||||
> size = 172
|
||||
327c327
|
||||
< Flags = 0x06 FLOW, Unsampled
|
||||
---
|
||||
> Flags = 0x00 FLOW, Unsampled
|
||||
329c329
|
||||
< size = 196
|
||||
---
|
||||
> size = 172
|
||||
381c381
|
||||
< Flags = 0x06 FLOW, Unsampled
|
||||
---
|
||||
> Flags = 0x00 FLOW, Unsampled
|
||||
383c383
|
||||
< size = 196
|
||||
---
|
||||
> size = 172
|
||||
435c435
|
||||
< Flags = 0x06 FLOW, Unsampled
|
||||
---
|
||||
> Flags = 0x00 FLOW, Unsampled
|
||||
437c437
|
||||
< size = 196
|
||||
---
|
||||
> size = 172
|
||||
489c489
|
||||
< Flags = 0x06 FLOW, Unsampled
|
||||
---
|
||||
> Flags = 0x00 FLOW, Unsampled
|
||||
491c491
|
||||
< size = 196
|
||||
---
|
||||
> size = 172
|
||||
543c543
|
||||
< Flags = 0x06 FLOW, Unsampled
|
||||
---
|
||||
> Flags = 0x00 FLOW, Unsampled
|
||||
545c545
|
||||
< size = 196
|
||||
---
|
||||
> size = 172
|
||||
597c597
|
||||
< Flags = 0x06 FLOW, Unsampled
|
||||
---
|
||||
> Flags = 0x00 FLOW, Unsampled
|
||||
599c599
|
||||
< size = 196
|
||||
---
|
||||
> size = 172
|
||||
651c651
|
||||
< Flags = 0x06 FLOW, Unsampled
|
||||
---
|
||||
> Flags = 0x00 FLOW, Unsampled
|
||||
653c653
|
||||
< size = 196
|
||||
---
|
||||
> size = 172
|
||||
705c705
|
||||
< Flags = 0x06 FLOW, Unsampled
|
||||
---
|
||||
> Flags = 0x00 FLOW, Unsampled
|
||||
707c707
|
||||
< size = 196
|
||||
---
|
||||
> size = 172
|
||||
758c758
|
||||
< Flags = 0x06 FLOW, Unsampled
|
||||
---
|
||||
> Flags = 0x00 FLOW, Unsampled
|
||||
760c760
|
||||
< size = 196
|
||||
---
|
||||
> size = 172
|
||||
812c812
|
||||
< Flags = 0x07 FLOW, Unsampled
|
||||
---
|
||||
> Flags = 0x01 FLOW, Unsampled
|
||||
814c814
|
||||
< size = 220
|
||||
---
|
||||
> size = 196
|
||||
866c866
|
||||
< Flags = 0x07 FLOW, Unsampled
|
||||
---
|
||||
> Flags = 0x01 FLOW, Unsampled
|
||||
868c868
|
||||
< size = 220
|
||||
---
|
||||
> size = 196
|
||||
920c920
|
||||
< Flags = 0x07 FLOW, Unsampled
|
||||
---
|
||||
> Flags = 0x05 FLOW, Unsampled
|
||||
922c922
|
||||
< size = 220
|
||||
---
|
||||
> size = 200
|
||||
974c974
|
||||
< Flags = 0x07 FLOW, Unsampled
|
||||
---
|
||||
> Flags = 0x03 FLOW, Unsampled
|
||||
976c976
|
||||
< size = 220
|
||||
---
|
||||
> size = 200
|
||||
1030c1030
|
||||
< size = 220
|
||||
---
|
||||
> size = 204
|
||||
1082c1082
|
||||
< Flags = 0x06 FLOW, Unsampled
|
||||
---
|
||||
> Flags = 0x04 FLOW, Unsampled
|
||||
1084c1084
|
||||
< size = 196
|
||||
---
|
||||
> size = 176
|
||||
1136c1136
|
||||
< Flags = 0x06 FLOW, Unsampled
|
||||
---
|
||||
> Flags = 0x02 FLOW, Unsampled
|
||||
1138c1138
|
||||
< size = 196
|
||||
---
|
||||
> size = 176
|
||||
1192c1192
|
||||
< size = 196
|
||||
---
|
||||
> size = 180
|
||||
1246c1246
|
||||
< size = 200
|
||||
---
|
||||
> size = 184
|
||||
1300c1300
|
||||
< size = 200
|
||||
---
|
||||
> size = 184
|
||||
1354c1354
|
||||
< size = 204
|
||||
---
|
||||
> size = 188
|
127
bin/nfdump_inline.c
Executable file
127
bin/nfdump_inline.c
Executable file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: nfdump_inline.c 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
// to improve readability - separate some code blocks in functions and make them inline
|
||||
// as it's called for every single flow
|
||||
static inline void UpdateStat(stat_record_t *stat_record, master_record_t *master_record);
|
||||
|
||||
static inline void UpdateXStat(xstat_t *xstat, master_record_t *master_record);
|
||||
|
||||
static inline void UpdateStat(stat_record_t *stat_record, master_record_t *master_record) {
|
||||
|
||||
switch (master_record->prot) {
|
||||
case IPPROTO_ICMP:
|
||||
case IPPROTO_ICMPV6:
|
||||
stat_record->numflows_icmp += master_record->aggr_flows ? master_record->aggr_flows : 1;
|
||||
stat_record->numpackets_icmp += master_record->dPkts;
|
||||
stat_record->numpackets_icmp += master_record->out_pkts;
|
||||
stat_record->numbytes_icmp += master_record->dOctets;
|
||||
stat_record->numbytes_icmp += master_record->out_bytes;
|
||||
break;
|
||||
case IPPROTO_TCP:
|
||||
stat_record->numflows_tcp += master_record->aggr_flows ? master_record->aggr_flows : 1;
|
||||
stat_record->numpackets_tcp += master_record->dPkts;
|
||||
stat_record->numpackets_tcp += master_record->out_pkts;
|
||||
stat_record->numbytes_tcp += master_record->dOctets;
|
||||
stat_record->numbytes_tcp += master_record->out_bytes;
|
||||
break;
|
||||
case IPPROTO_UDP:
|
||||
stat_record->numflows_udp += master_record->aggr_flows ? master_record->aggr_flows : 1;
|
||||
stat_record->numpackets_udp += master_record->dPkts;
|
||||
stat_record->numpackets_udp += master_record->out_pkts;
|
||||
stat_record->numbytes_udp += master_record->dOctets;
|
||||
stat_record->numbytes_udp += master_record->out_bytes;
|
||||
break;
|
||||
default:
|
||||
stat_record->numflows_other += master_record->aggr_flows ? master_record->aggr_flows : 1;
|
||||
stat_record->numpackets_other += master_record->dPkts;
|
||||
stat_record->numpackets_other += master_record->out_pkts;
|
||||
stat_record->numbytes_other += master_record->dOctets;
|
||||
stat_record->numbytes_other += master_record->out_bytes;
|
||||
}
|
||||
stat_record->numflows += master_record->aggr_flows ? master_record->aggr_flows : 1;
|
||||
stat_record->numpackets += master_record->dPkts;
|
||||
stat_record->numpackets += master_record->out_pkts;
|
||||
stat_record->numbytes += master_record->dOctets;
|
||||
stat_record->numbytes += master_record->out_bytes;
|
||||
|
||||
if ( master_record->first < stat_record->first_seen ) {
|
||||
stat_record->first_seen = master_record->first;
|
||||
stat_record->msec_first = master_record->msec_first;
|
||||
}
|
||||
if ( master_record->first == stat_record->first_seen &&
|
||||
master_record->msec_first < stat_record->msec_first )
|
||||
stat_record->msec_first = master_record->msec_first;
|
||||
|
||||
if ( master_record->last > stat_record->last_seen ) {
|
||||
stat_record->last_seen = master_record->last;
|
||||
stat_record->msec_last = master_record->msec_last;
|
||||
}
|
||||
if ( master_record->last == stat_record->last_seen &&
|
||||
master_record->msec_last > stat_record->msec_last )
|
||||
stat_record->msec_last = master_record->msec_last;
|
||||
|
||||
} // End of UpdateStat
|
||||
|
||||
static inline void UpdateXStat(xstat_t *xstat, master_record_t *master_record) {
|
||||
uint32_t bpp = master_record->dPkts ? master_record->dOctets/master_record->dPkts : 0;
|
||||
|
||||
if ( bpp > MAX_BPP )
|
||||
bpp = MAX_BPP;
|
||||
if ( master_record->prot == IPPROTO_TCP ) {
|
||||
xstat->bpp_histogram->tcp.bpp[bpp]++;
|
||||
xstat->bpp_histogram->tcp.count++;
|
||||
|
||||
xstat->port_histogram->src_tcp.port[master_record->srcport]++;
|
||||
xstat->port_histogram->dst_tcp.port[master_record->dstport]++;
|
||||
xstat->port_histogram->src_tcp.count++;
|
||||
xstat->port_histogram->dst_tcp.count++;
|
||||
} else if ( master_record->prot == IPPROTO_UDP ) {
|
||||
xstat->bpp_histogram->udp.bpp[bpp]++;
|
||||
xstat->bpp_histogram->udp.count++;
|
||||
|
||||
xstat->port_histogram->src_udp.port[master_record->srcport]++;
|
||||
xstat->port_histogram->dst_udp.port[master_record->dstport]++;
|
||||
xstat->port_histogram->src_udp.count++;
|
||||
xstat->port_histogram->dst_udp.count++;
|
||||
}
|
||||
|
||||
} // End of UpdateXStat
|
||||
|
544
bin/nfexpire.c
Normal file
544
bin/nfexpire.c
Normal file
@ -0,0 +1,544 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: nfexpire.c 51 2010-01-29 09:01:54Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 51 $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/param.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef HAVE_FTS_H
|
||||
# include <fts.h>
|
||||
#else
|
||||
# include "fts_compat.h"
|
||||
#define fts_children fts_children_compat
|
||||
#define fts_close fts_close_compat
|
||||
#define fts_open fts_open_compat
|
||||
#define fts_read fts_read_compat
|
||||
#define fts_set fts_set_compat
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "bookkeeper.h"
|
||||
#include "nfstatfile.h"
|
||||
#include "expire.h"
|
||||
#include "util.h"
|
||||
|
||||
static void usage(char *name);
|
||||
|
||||
void CheckDataDir( char *datadir);
|
||||
|
||||
channel_t *GetChannelList(char *datadir, int is_profile, int do_rescan);
|
||||
|
||||
static void usage(char *name) {
|
||||
printf("usage %s [options] \n"
|
||||
"-h\t\tThis text\n"
|
||||
"-l datadir\tList stat from directory\n"
|
||||
"-e datadir\tExpire data in directory\n"
|
||||
"-r datadir\tRescan data directory\n"
|
||||
"-u datadir\tUpdate expire params from collector logging at <datadir>\n"
|
||||
"-s size\t\tmax size: scales b bytes, k kilo, m mega, g giga t tera\n"
|
||||
"-t lifetime\tmaximum life time of data: scales: w week, d day, H hour, M minute\n"
|
||||
"-w watermark\tlow water mark in %% for expire.\n"
|
||||
, name);
|
||||
|
||||
} // End of usage
|
||||
|
||||
void CheckDataDir( char *datadir) {
|
||||
if ( datadir ) {
|
||||
fprintf(stderr, "Specify only one option out of -l -e -r -u or -p \n");
|
||||
exit(250);
|
||||
}
|
||||
} // End of CheckDataDir
|
||||
|
||||
static char *AbsolutePath(char *dirname) {
|
||||
char *path;
|
||||
|
||||
if ( !dirname )
|
||||
return NULL;
|
||||
|
||||
if ( dirname[0] == '/' ) // it's already absolute path
|
||||
return dirname;
|
||||
|
||||
path = (char *)malloc(MAXPATHLEN);
|
||||
if ( !path ) {
|
||||
LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return NULL;
|
||||
}
|
||||
memset((void *)path, 0, MAXPATHLEN);
|
||||
getcwd(path, MAXPATHLEN-strlen(dirname)-2); // -2: one for '/' and one for '\0'
|
||||
strncat(path, "/", 1);
|
||||
strncat(path, dirname, strlen(dirname));
|
||||
path[MAXPATHLEN-1] = '\0';
|
||||
|
||||
return path;
|
||||
|
||||
} // End of AbsolutePath
|
||||
|
||||
channel_t *GetChannelList(char *datadir, int is_profile, int do_rescan) {
|
||||
channel_t **c, *channel;
|
||||
stringlist_t dirlist;
|
||||
struct stat stat_buf;
|
||||
int i;
|
||||
|
||||
// Generate list of directories
|
||||
InitStringlist(&dirlist, 32);
|
||||
if ( is_profile ) {
|
||||
DIR *PDIR = opendir(datadir);
|
||||
struct dirent *entry;
|
||||
if ( !PDIR ) {
|
||||
fprintf(stderr, "Can't read profiledir '%s': %s\n",datadir, strerror(errno) );
|
||||
return NULL;
|
||||
}
|
||||
while ( ( entry = readdir(PDIR)) != NULL ) {
|
||||
char stringbuf[MAXPATHLEN];
|
||||
snprintf(stringbuf, MAXPATHLEN-1, "%s/%s", datadir, entry->d_name);
|
||||
stringbuf[MAXPATHLEN-1] = '\0';
|
||||
|
||||
if ( stat(stringbuf, &stat_buf) ) {
|
||||
fprintf(stderr, "Can't stat '%s': %s\n",stringbuf, strerror(errno) );
|
||||
continue;
|
||||
}
|
||||
if ( !S_ISDIR(stat_buf.st_mode) )
|
||||
continue;
|
||||
|
||||
// skip all '.' entries -> make .anything invisible to nfprofile
|
||||
if ( entry->d_name[0] == '.' )
|
||||
continue;
|
||||
|
||||
InsertString(&dirlist, stringbuf);
|
||||
}
|
||||
closedir(PDIR);
|
||||
} else {
|
||||
InsertString(&dirlist, datadir);
|
||||
}
|
||||
|
||||
channel = NULL;
|
||||
c = &channel;
|
||||
for ( i=0; i<dirlist.num_strings; i++ ) {
|
||||
int ret;
|
||||
|
||||
*c = (channel_t *)malloc(sizeof(channel_t));
|
||||
if ( !*c ) {
|
||||
LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return NULL;
|
||||
}
|
||||
memset((void *)*c, 0, sizeof(channel_t));
|
||||
(*c)->next = NULL;
|
||||
(*c)->datadir = dirlist.list[i];
|
||||
(*c)->do_rescan = do_rescan;
|
||||
|
||||
ret = ReadStatInfo((*c)->datadir, &(*c)->dirstat, CREATE_AND_LOCK);
|
||||
switch (ret) {
|
||||
case FORCE_REBUILD:
|
||||
printf("Force rebuild requested by stat record in %s\n", (*c)->datadir);
|
||||
(*c)->do_rescan = 1; // file corrupt - rescan
|
||||
break;
|
||||
case STATFILE_OK:
|
||||
break;
|
||||
case ERR_NOSTATFILE: // first rescan bevore expire, if no file exists
|
||||
if ( do_rescan == 0 ) {
|
||||
printf("Force rebuild to create stat record in %s\n", (*c)->datadir);
|
||||
(*c)->do_rescan = 1;
|
||||
} // else do_rescan is already set - do not report
|
||||
break;
|
||||
default:
|
||||
exit(250);
|
||||
}
|
||||
|
||||
(*c)->books_stat = AccessBookkeeper(&((*c)->books), (*c)->datadir);
|
||||
if ( (*c)->books_stat == ERR_FAILED ) {
|
||||
fprintf(stderr, "Failed to access bookkeeping record.\n");
|
||||
exit(250);
|
||||
}
|
||||
|
||||
c = &(*c)->next;
|
||||
}
|
||||
|
||||
return channel;
|
||||
|
||||
} // End of GetChannelList
|
||||
|
||||
int main( int argc, char **argv ) {
|
||||
struct stat fstat;
|
||||
int c, err, maxsize_set, maxlife_set;
|
||||
int do_rescan, do_expire, do_list, print_stat, do_update_param, print_books, is_profile, nfsen_format;
|
||||
char *maxsize_string, *lifetime_string, *datadir;
|
||||
uint64_t maxsize, lifetime, low_water;
|
||||
uint32_t runtime;
|
||||
channel_t *channel, *current_channel;
|
||||
|
||||
maxsize_string = lifetime_string = NULL;
|
||||
datadir = NULL;
|
||||
maxsize = lifetime = 0;
|
||||
do_rescan = 0;
|
||||
do_expire = 0;
|
||||
do_list = 0;
|
||||
do_update_param = 0;
|
||||
is_profile = 0;
|
||||
print_stat = 0;
|
||||
print_books = 0;
|
||||
maxsize_set = 0;
|
||||
maxlife_set = 0;
|
||||
low_water = 0;
|
||||
nfsen_format = 0;
|
||||
runtime = 0;
|
||||
|
||||
while ((c = getopt(argc, argv, "e:hl:L:T:Ypr:s:t:u:w:")) != EOF) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
exit(0);
|
||||
break;
|
||||
case 'l':
|
||||
CheckDataDir(datadir);
|
||||
datadir = optarg;
|
||||
do_list = 1;
|
||||
print_stat = 1;
|
||||
break;
|
||||
case 'L':
|
||||
CheckDataDir(datadir);
|
||||
datadir = optarg;
|
||||
print_stat = 1;
|
||||
print_books = 1;
|
||||
break;
|
||||
case 'p':
|
||||
is_profile = 1;
|
||||
break;
|
||||
case 'r':
|
||||
CheckDataDir(datadir);
|
||||
do_rescan = 1;
|
||||
print_stat = 1;
|
||||
datadir = optarg;
|
||||
break;
|
||||
case 'e':
|
||||
CheckDataDir(datadir);
|
||||
datadir = optarg;
|
||||
do_expire = 1;
|
||||
print_stat = 1;
|
||||
break;
|
||||
case 's':
|
||||
if ( ParseSizeDef(optarg, &maxsize ) == 0 )
|
||||
exit(250);
|
||||
maxsize_set = 1;
|
||||
break;
|
||||
case 't':
|
||||
if ( ParseTimeDef(optarg, &lifetime ) == 0 )
|
||||
exit(250);
|
||||
maxlife_set = 1;
|
||||
break;
|
||||
case 'u':
|
||||
CheckDataDir(datadir);
|
||||
datadir = optarg;
|
||||
do_update_param = 1;
|
||||
break;
|
||||
case 'w':
|
||||
low_water = strtoll(optarg, NULL, 10);
|
||||
if ( low_water > 100 ) {
|
||||
fprintf(stderr, "Water mark > 100%%\n");
|
||||
exit(250);
|
||||
}
|
||||
if ( low_water == 0 )
|
||||
low_water = 100;
|
||||
break;
|
||||
case 'T':
|
||||
runtime = strtoll(optarg, NULL, 10);
|
||||
if ( runtime > 3600 ) {
|
||||
fprintf(stderr, "Runtime > 3600 (1h)\n");
|
||||
exit(250);
|
||||
}
|
||||
break;
|
||||
case 'Y':
|
||||
nfsen_format = 1;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(250);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
datadir = AbsolutePath(datadir);
|
||||
|
||||
if ( !datadir ) {
|
||||
fprintf(stderr, "Missing data directory\n");
|
||||
usage(argv[0]);
|
||||
exit(250);
|
||||
}
|
||||
|
||||
err = stat(datadir, &fstat);
|
||||
if ( !(fstat.st_mode & S_IFDIR) ) {
|
||||
fprintf(stderr, "No such directory: %s\n", datadir);
|
||||
exit(250);
|
||||
}
|
||||
|
||||
channel = GetChannelList(datadir, is_profile, do_rescan);
|
||||
// GetChannelList(datadir, is_profile, do_rescan);
|
||||
if ( !channel ) {
|
||||
exit(250);
|
||||
}
|
||||
|
||||
// printf("Size: %llu, time: %llu\n", maxsize, lifetime);
|
||||
|
||||
// update water mark only, when not listing
|
||||
if ( !is_profile && !do_list && low_water )
|
||||
channel->dirstat->low_water = low_water;
|
||||
|
||||
/* process do_list first: if the UpdateBookStat results in a FORCE_REBUILD,
|
||||
* this will immediately done afterwards
|
||||
* do_expire will need accurate books as well, so update the books here as well
|
||||
*/
|
||||
if ( do_list || do_expire ) {
|
||||
current_channel = channel;
|
||||
while ( current_channel ) {
|
||||
if ( current_channel->books_stat == BOOKKEEPER_OK ) {
|
||||
bookkeeper_t tmp_books;
|
||||
printf("Include nfcapd bookeeping record in %s\n", current_channel->datadir);
|
||||
ClearBooks(current_channel->books, &tmp_books);
|
||||
UpdateBookStat(current_channel->dirstat, &tmp_books);
|
||||
if ( current_channel->dirstat->status == FORCE_REBUILD )
|
||||
current_channel->do_rescan = 1;
|
||||
}
|
||||
current_channel = current_channel->next;
|
||||
}
|
||||
}
|
||||
|
||||
// process do_rescan: make sure stats are up to date, if required
|
||||
current_channel = channel;
|
||||
while ( current_channel ) {
|
||||
if ( current_channel->do_rescan ) {
|
||||
int i;
|
||||
uint64_t last_sequence;
|
||||
|
||||
/* detect new files: If nfcapd adds a new file while we are rescanning the directory
|
||||
* this results in inconsistent data for the rescan. Therefore check at the begin and end
|
||||
* of the rescan for the sequence number, which reflects the accesss/change to the bookkeeping record
|
||||
* It's assumed, that such an event does not occure more than once. However, loop 3 times max
|
||||
*/
|
||||
for ( i=0; i<3; i++ ) {
|
||||
last_sequence = BookSequence(current_channel->books);
|
||||
printf("Scanning files in %s .. ", current_channel->datadir);
|
||||
RescanDir(current_channel->datadir, current_channel->dirstat);
|
||||
if ( current_channel->dirstat->numfiles == 0 ) { //nothing found
|
||||
current_channel->status = NOFILES;
|
||||
}
|
||||
if ( BookSequence(current_channel->books) == last_sequence )
|
||||
break;
|
||||
printf("Rescan again, due to file changes in directory!\n");
|
||||
}
|
||||
if ( BookSequence(current_channel->books) != last_sequence ) {
|
||||
fprintf(stderr, "Could not savely rescan the directory. Data is not consistent.\n");
|
||||
ReleaseBookkeeper(current_channel->books, DETACH_ONLY);
|
||||
if ( current_channel->status == OK )
|
||||
WriteStatInfo(current_channel->dirstat);
|
||||
exit(250);
|
||||
}
|
||||
printf("done.\n");
|
||||
if ( current_channel->books_stat == BOOKKEEPER_OK ) {
|
||||
printf("Updating nfcapd bookeeping records\n");
|
||||
ClearBooks(channel->books, NULL);
|
||||
}
|
||||
}
|
||||
current_channel = current_channel->next;
|
||||
}
|
||||
|
||||
// now process do_expire if required
|
||||
if ( do_expire ) {
|
||||
dirstat_t old_stat, current_stat;
|
||||
|
||||
if ( is_profile ) {
|
||||
current_stat.status = 0;
|
||||
current_stat.max_lifetime = lifetime;
|
||||
current_stat.max_size = maxsize;
|
||||
current_stat.low_water = low_water ? low_water : 98;
|
||||
|
||||
// sum up all channels in the profile
|
||||
current_channel = channel;
|
||||
current_stat.numfiles = current_channel->dirstat->numfiles;
|
||||
current_stat.filesize = current_channel->dirstat->filesize;
|
||||
current_stat.first = current_channel->dirstat->first;
|
||||
current_stat.last = current_channel->dirstat->last;
|
||||
current_channel = current_channel->next;
|
||||
while ( current_channel ) {
|
||||
current_stat.numfiles += current_channel->dirstat->numfiles;
|
||||
current_stat.filesize += current_channel->dirstat->filesize;
|
||||
if ( current_channel->dirstat->first && (current_channel->dirstat->first < current_stat.first) )
|
||||
current_stat.first = current_channel->dirstat->first;
|
||||
if ( current_channel->dirstat->last > current_stat.last )
|
||||
current_stat.last = current_channel->dirstat->last;
|
||||
|
||||
current_channel = current_channel->next;
|
||||
}
|
||||
old_stat = current_stat;
|
||||
ExpireProfile(channel, ¤t_stat, maxsize, lifetime, runtime);
|
||||
|
||||
} else {
|
||||
// cmd args override dirstat values
|
||||
if ( maxsize_set )
|
||||
channel->dirstat->max_size = maxsize;
|
||||
else
|
||||
maxsize = channel->dirstat->max_size;
|
||||
if ( maxlife_set )
|
||||
channel->dirstat->max_lifetime = lifetime;
|
||||
else
|
||||
lifetime = channel->dirstat->max_lifetime;
|
||||
|
||||
|
||||
old_stat = *(channel->dirstat);
|
||||
ExpireDir(channel->datadir, channel->dirstat, maxsize, lifetime, runtime);
|
||||
current_stat = *(channel->dirstat);
|
||||
|
||||
}
|
||||
// Report, what we have done
|
||||
printf("Expired files: %llu\n", (unsigned long long)(old_stat.numfiles - current_stat.numfiles));
|
||||
printf("Expired file size: %s\n", ScaleValue(old_stat.filesize - current_stat.filesize));
|
||||
printf("Expired time range: %s\n\n", ScaleTime(current_stat.first - old_stat.first));
|
||||
}
|
||||
|
||||
if ( !is_profile && do_update_param ) {
|
||||
switch (channel->books_stat) {
|
||||
case BOOKKEEPER_OK:
|
||||
if ( maxsize_set )
|
||||
channel->dirstat->max_size = maxsize;
|
||||
else
|
||||
maxsize = channel->dirstat->max_size;
|
||||
if ( maxlife_set )
|
||||
channel->dirstat->max_lifetime = lifetime;
|
||||
else
|
||||
lifetime = channel->dirstat->max_lifetime;
|
||||
printf("Update collector process running for directory: '%s'\n", datadir);
|
||||
UpdateBooksParam(channel->books, (time_t)lifetime, maxsize);
|
||||
print_stat = 1;
|
||||
break;
|
||||
case ERR_NOTEXISTS:
|
||||
if ( maxsize_set )
|
||||
channel->dirstat->max_size = maxsize;
|
||||
if ( maxlife_set )
|
||||
channel->dirstat->max_lifetime = lifetime;
|
||||
print_stat = 1;
|
||||
break;
|
||||
default:
|
||||
// should never be reached as already cought earlier
|
||||
printf("Error %i while connecting to collector\n", channel->books_stat);
|
||||
}
|
||||
if ( channel->status == OK || channel->status == NOFILES )
|
||||
WriteStatInfo(channel->dirstat);
|
||||
}
|
||||
|
||||
if ( !is_profile && print_books ) {
|
||||
switch (channel->books_stat) {
|
||||
case BOOKKEEPER_OK:
|
||||
PrintBooks(channel->books);
|
||||
break;
|
||||
case ERR_NOTEXISTS:
|
||||
printf("No collector process running for directory: '%s'\n", channel->datadir);
|
||||
break;
|
||||
default:
|
||||
// should never be reached as already cought earlier
|
||||
printf("Error %i while connecting to collector\n", channel->books_stat);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( print_stat ) {
|
||||
if ( is_profile ) {
|
||||
dirstat_t current_stat;
|
||||
|
||||
current_stat.status = 0;
|
||||
current_stat.max_lifetime = lifetime;
|
||||
current_stat.max_size = maxsize;
|
||||
current_stat.low_water = low_water ? low_water : 98;
|
||||
|
||||
// sum up all channels in the profile
|
||||
current_channel = channel;
|
||||
current_stat.numfiles = current_channel->dirstat->numfiles;
|
||||
current_stat.filesize = current_channel->dirstat->filesize;
|
||||
current_stat.first = current_channel->dirstat->first;
|
||||
current_stat.last = current_channel->dirstat->last;
|
||||
current_channel = current_channel->next;
|
||||
while ( current_channel ) {
|
||||
current_stat.numfiles += current_channel->dirstat->numfiles;
|
||||
current_stat.filesize += current_channel->dirstat->filesize;
|
||||
if ( current_channel->dirstat->first && (current_channel->dirstat->first < current_stat.first) )
|
||||
current_stat.first = current_channel->dirstat->first;
|
||||
if ( current_channel->dirstat->last > current_stat.last )
|
||||
current_stat.last = current_channel->dirstat->last;
|
||||
|
||||
current_channel = current_channel->next;
|
||||
}
|
||||
if ( nfsen_format ) {
|
||||
printf("Stat|%llu|%llu|%llu\n",
|
||||
(unsigned long long)current_stat.filesize,
|
||||
(unsigned long long)current_stat.first, (unsigned long long)current_stat.last);
|
||||
} else
|
||||
PrintDirStat(¤t_stat);
|
||||
} else
|
||||
if ( nfsen_format )
|
||||
printf("Stat|%llu|%llu|%llu\n",
|
||||
(unsigned long long)channel->dirstat->filesize,
|
||||
(unsigned long long)channel->dirstat->first, (unsigned long long)channel->dirstat->last );
|
||||
else
|
||||
PrintDirStat(channel->dirstat);
|
||||
|
||||
}
|
||||
|
||||
current_channel = channel;
|
||||
while ( current_channel ) {
|
||||
ReleaseBookkeeper(current_channel->books, DETACH_ONLY);
|
||||
if ( current_channel->status == OK )
|
||||
WriteStatInfo(current_channel->dirstat);
|
||||
|
||||
current_channel = current_channel->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
412
bin/nfexport.c
Executable file
412
bin/nfexport.c
Executable file
@ -0,0 +1,412 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: nfexport.c 54 2010-01-29 11:30:22Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 54 $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
#include "nf_common.h"
|
||||
#include "nffile.h"
|
||||
#include "nfx.h"
|
||||
#include "nfstat.h"
|
||||
#include "nfxstat.h"
|
||||
#include "nflowcache.h"
|
||||
#include "exporter.h"
|
||||
|
||||
#include "nfexport.h"
|
||||
|
||||
#include "nfdump_inline.c"
|
||||
|
||||
#define NEED_PACKRECORD 1
|
||||
#include "nffile_inline.c"
|
||||
#undef NEED_PACKRECORD
|
||||
|
||||
#include "heapsort_inline.c"
|
||||
#include "applybits_inline.c"
|
||||
|
||||
/* global vars */
|
||||
extern extension_descriptor_t extension_descriptor[];
|
||||
|
||||
/* local vars */
|
||||
enum CntIndices { FLOWS = 0, INPACKETS, INBYTES, OUTPACKETS, OUTBYTES };
|
||||
|
||||
static void ExportExtensionMaps( int aggregate, int bidir, nffile_t *nffile, extension_map_list_t *extension_map_list );
|
||||
|
||||
static void ExportExtensionMaps( int aggregate, int bidir, nffile_t *nffile, extension_map_list_t *extension_map_list ) {
|
||||
int map_id, opt_extensions, num_extensions, new_map_size, opt_align;
|
||||
extension_map_t *new_map;
|
||||
|
||||
// no extension maps to export - nothing to do
|
||||
if ( extension_map_list->max_used == 0 )
|
||||
return;
|
||||
|
||||
new_map = NULL;
|
||||
|
||||
for ( map_id = 0; map_id <= extension_map_list->max_used; map_id++ ) {
|
||||
extension_map_t *SourceMap = extension_map_list->slot[map_id]->map;
|
||||
int i, has_aggr_flows, has_out_bytes, has_out_packets, has_nat;
|
||||
// skip maps, never referenced
|
||||
|
||||
#ifdef DEVEL
|
||||
printf("Process map id: %i\n", map_id);
|
||||
printf("Ref count: %i\n", extension_map_list->slot[map_id]->ref_count);
|
||||
#endif
|
||||
|
||||
if ( extension_map_list->slot[map_id]->ref_count == 0 ) {
|
||||
#ifdef DEVEL
|
||||
printf("Ref count = 0 => Skip map\n");
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
// parse Source map if it contains all required fields:
|
||||
// for aggregation EX_AGGR_FLOWS_4 or _8 is required
|
||||
// for bidir flows EX_OUT_PKG_4 or _8 and EX_OUT_BYTES_4 or_8 are required
|
||||
has_aggr_flows = 0;
|
||||
has_out_bytes = 0;
|
||||
has_out_packets = 0;
|
||||
// parse map for older NEL nat extension
|
||||
has_nat = 0;
|
||||
|
||||
num_extensions = 0;
|
||||
i = 0;
|
||||
while ( SourceMap->ex_id[i] ) {
|
||||
switch (SourceMap->ex_id[i]) {
|
||||
case EX_AGGR_FLOWS_4:
|
||||
case EX_AGGR_FLOWS_8:
|
||||
has_aggr_flows = 1;
|
||||
break;
|
||||
case EX_OUT_BYTES_4:
|
||||
case EX_OUT_BYTES_8:
|
||||
has_out_bytes = 1;
|
||||
break;
|
||||
case EX_OUT_PKG_4:
|
||||
case EX_OUT_PKG_8:
|
||||
has_out_packets = 1;
|
||||
break;
|
||||
case EX_NEL_GLOBAL_IP_v4:
|
||||
// Map old nat extension to common NSEL extension
|
||||
SourceMap->ex_id[i] = EX_NSEL_XLATE_IP_v4;
|
||||
has_nat = 1;
|
||||
// default: nothing to do
|
||||
}
|
||||
i++;
|
||||
num_extensions++;
|
||||
}
|
||||
#ifdef DEVEL
|
||||
printf("map: num_extensions: %i, has_aggr_flows: %i, has_out_bytes: %i, has_out_packets: %i, has_nat: %i\n",
|
||||
num_extensions, has_aggr_flows, has_out_bytes, has_out_packets, has_nat);
|
||||
#endif
|
||||
|
||||
// count missing extensions
|
||||
opt_extensions = 0;
|
||||
if ( aggregate && !has_aggr_flows )
|
||||
opt_extensions++;
|
||||
|
||||
if ( bidir && !has_out_bytes )
|
||||
opt_extensions++;
|
||||
|
||||
if ( bidir && !has_out_packets )
|
||||
opt_extensions++;
|
||||
|
||||
opt_extensions += has_nat;
|
||||
// calculate new map size
|
||||
new_map_size = sizeof(extension_map_t) + ( num_extensions + opt_extensions) * sizeof(uint16_t);
|
||||
|
||||
#ifdef DEVEL
|
||||
printf("opt_extensions: %i, new_map_size: %i\n", opt_extensions,new_map_size );
|
||||
PrintExtensionMap(SourceMap);
|
||||
#endif
|
||||
if ( opt_extensions ) {
|
||||
// align 32bits
|
||||
if (( new_map_size & 0x3 ) != 0 ) {
|
||||
new_map_size += 4 - ( new_map_size & 0x3 );
|
||||
opt_align = 1;
|
||||
} else {
|
||||
opt_align = 0;
|
||||
}
|
||||
} else {
|
||||
// no missing elements in extension map - we can used the original one
|
||||
// and we are done
|
||||
|
||||
#ifdef DEVEL
|
||||
printf("New map identical => use this map:\n");
|
||||
PrintExtensionMap(SourceMap);
|
||||
#endif
|
||||
// Flush the map to disk
|
||||
AppendToBuffer(nffile, (void *)SourceMap, SourceMap->size);
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef DEVEL
|
||||
printf("Create new map:\n");
|
||||
#endif
|
||||
// new map is different - create the new map
|
||||
new_map = (extension_map_t *)malloc((ssize_t)new_map_size);
|
||||
if ( !new_map ) {
|
||||
LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
exit(255);
|
||||
}
|
||||
|
||||
// Panic check - should never happen, but we are going to copy memory
|
||||
if ( new_map_size < SourceMap->size ) {
|
||||
LogError("PANIC! new_map_size(%i) < SourceMap->size(%i) in %s line %d\n",
|
||||
new_map_size, SourceMap->size, __FILE__, __LINE__);
|
||||
exit(255);
|
||||
}
|
||||
// copy existing map
|
||||
memcpy((void *)new_map, (void *)SourceMap, SourceMap->size);
|
||||
|
||||
new_map->size = new_map_size;
|
||||
|
||||
// add the missing extensions to the output map
|
||||
// skip to end of current map
|
||||
while ( new_map->ex_id[i] )
|
||||
i++;
|
||||
|
||||
if ( has_nat ) {
|
||||
new_map->ex_id[i++] = EX_NSEL_XLATE_PORTS;
|
||||
new_map->extension_size += extension_descriptor[EX_NSEL_XLATE_PORTS].size;
|
||||
}
|
||||
// add missing map elements
|
||||
if ( aggregate && !has_aggr_flows ) {
|
||||
new_map->ex_id[i++] = EX_AGGR_FLOWS_4;
|
||||
new_map->extension_size += extension_descriptor[EX_AGGR_FLOWS_4].size;
|
||||
}
|
||||
if ( bidir && !has_out_bytes ) {
|
||||
new_map->ex_id[i++] = EX_OUT_BYTES_8;
|
||||
new_map->extension_size += extension_descriptor[EX_OUT_BYTES_8].size;
|
||||
}
|
||||
if ( bidir && !has_out_packets ) {
|
||||
new_map->ex_id[i++] = EX_OUT_PKG_8;
|
||||
new_map->extension_size += extension_descriptor[EX_OUT_PKG_8].size;
|
||||
}
|
||||
// end of map tag
|
||||
new_map->ex_id[i++] = 0;
|
||||
if ( opt_align )
|
||||
new_map->ex_id[i] = 0;
|
||||
|
||||
#ifdef DEVEL
|
||||
PrintExtensionMap(new_map);
|
||||
#endif
|
||||
|
||||
free(extension_map_list->slot[map_id]->map);
|
||||
extension_map_list->slot[map_id]->map = new_map;
|
||||
|
||||
// Flush the map to disk
|
||||
AppendToBuffer(nffile, (void *)new_map, new_map->size);
|
||||
|
||||
}
|
||||
|
||||
} // End of ExportExtensionMaps
|
||||
|
||||
int ExportFlowTable(nffile_t *nffile, int aggregate, int bidir, int date_sorted, extension_map_list_t *extension_map_list) {
|
||||
hash_FlowTable *FlowTable;
|
||||
FlowTableRecord_t *r;
|
||||
SortElement_t *SortList;
|
||||
master_record_t *aggr_record_mask;
|
||||
uint32_t i;
|
||||
uint32_t maxindex, c;
|
||||
#ifdef DEVEL
|
||||
char *string;
|
||||
#endif
|
||||
|
||||
ExportExtensionMaps(aggregate, bidir, nffile, extension_map_list);
|
||||
ExportExporterList(nffile);
|
||||
|
||||
aggr_record_mask = GetMasterAggregateMask();
|
||||
|
||||
FlowTable = GetFlowTable();
|
||||
c = 0;
|
||||
maxindex = FlowTable->NumRecords;
|
||||
if ( date_sorted ) {
|
||||
// Sort records according the date
|
||||
SortList = (SortElement_t *)calloc(maxindex, sizeof(SortElement_t));
|
||||
|
||||
if ( !SortList ) {
|
||||
LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// preset SortList table - still unsorted
|
||||
for ( i=0; i<=FlowTable->IndexMask; i++ ) {
|
||||
r = FlowTable->bucket[i];
|
||||
if ( !r )
|
||||
continue;
|
||||
|
||||
// foreach elem in this bucket
|
||||
while ( r ) {
|
||||
SortList[c].count = 1000LL * r->flowrecord.first + r->flowrecord.msec_first; // sort according the date
|
||||
SortList[c].record = (void *)r;
|
||||
c++;
|
||||
r = r->next;
|
||||
}
|
||||
}
|
||||
|
||||
if ( c != maxindex ) {
|
||||
LogError("Abort: Missmatch %s line %d: %s\n", __FILE__, __LINE__, strerror (errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( c >= 2 )
|
||||
heapSort(SortList, c, 0);
|
||||
|
||||
for ( i = 0; i < c; i++ ) {
|
||||
master_record_t *flow_record;
|
||||
common_record_t *raw_record;
|
||||
extension_info_t *extension_info;
|
||||
|
||||
r = (FlowTableRecord_t *)(SortList[i].record);
|
||||
raw_record = &(r->flowrecord);
|
||||
extension_info = r->map_info_ref;
|
||||
|
||||
flow_record = &(extension_info->master_record);
|
||||
ExpandRecord_v2( raw_record, extension_info, r->exp_ref, flow_record);
|
||||
flow_record->dPkts = r->counter[INPACKETS];
|
||||
flow_record->dOctets = r->counter[INBYTES];
|
||||
flow_record->out_pkts = r->counter[OUTPACKETS];
|
||||
flow_record->out_bytes = r->counter[OUTBYTES];
|
||||
flow_record->aggr_flows = r->counter[FLOWS];
|
||||
|
||||
// apply IP mask from aggregation, to provide a pretty output
|
||||
if ( FlowTable->has_masks ) {
|
||||
flow_record->v6.srcaddr[0] &= FlowTable->IPmask[0];
|
||||
flow_record->v6.srcaddr[1] &= FlowTable->IPmask[1];
|
||||
flow_record->v6.dstaddr[0] &= FlowTable->IPmask[2];
|
||||
flow_record->v6.dstaddr[1] &= FlowTable->IPmask[3];
|
||||
}
|
||||
|
||||
if ( FlowTable->apply_netbits )
|
||||
ApplyNetMaskBits(flow_record, FlowTable->apply_netbits);
|
||||
|
||||
if ( aggr_record_mask ) {
|
||||
ApplyAggrMask(flow_record, aggr_record_mask);
|
||||
}
|
||||
|
||||
// switch to output extension map
|
||||
flow_record->map_ref = extension_info->map;
|
||||
flow_record->ext_map = extension_info->map->map_id;
|
||||
PackRecord(flow_record, nffile);
|
||||
#ifdef DEVEL
|
||||
format_file_block_record((void *)flow_record, &string, 0);
|
||||
printf("%s\n", string);
|
||||
#endif
|
||||
// Update statistics
|
||||
UpdateStat(nffile->stat_record, flow_record);
|
||||
}
|
||||
|
||||
} else {
|
||||
// print them as they came
|
||||
for ( i=0; i<=FlowTable->IndexMask; i++ ) {
|
||||
r = FlowTable->bucket[i];
|
||||
while ( r ) {
|
||||
master_record_t *flow_record;
|
||||
common_record_t *raw_record;
|
||||
extension_info_t *extension_info;
|
||||
|
||||
raw_record = &(r->flowrecord);
|
||||
extension_info = r->map_info_ref;
|
||||
|
||||
flow_record = &(extension_info->master_record);
|
||||
ExpandRecord_v2( raw_record, extension_info, r->exp_ref, flow_record);
|
||||
flow_record->dPkts = r->counter[INPACKETS];
|
||||
flow_record->dOctets = r->counter[INBYTES];
|
||||
flow_record->out_pkts = r->counter[OUTPACKETS];
|
||||
flow_record->out_bytes = r->counter[OUTBYTES];
|
||||
flow_record->aggr_flows = r->counter[FLOWS];
|
||||
|
||||
// apply IP mask from aggregation, to provide a pretty output
|
||||
if ( FlowTable->has_masks ) {
|
||||
flow_record->v6.srcaddr[0] &= FlowTable->IPmask[0];
|
||||
flow_record->v6.srcaddr[1] &= FlowTable->IPmask[1];
|
||||
flow_record->v6.dstaddr[0] &= FlowTable->IPmask[2];
|
||||
flow_record->v6.dstaddr[1] &= FlowTable->IPmask[3];
|
||||
}
|
||||
|
||||
if ( FlowTable->apply_netbits )
|
||||
ApplyNetMaskBits(flow_record, FlowTable->apply_netbits);
|
||||
|
||||
if ( aggr_record_mask ) {
|
||||
ApplyAggrMask(flow_record, aggr_record_mask);
|
||||
}
|
||||
|
||||
// switch to output extension map
|
||||
flow_record->map_ref = extension_info->map;
|
||||
flow_record->ext_map = extension_info->map->map_id;
|
||||
PackRecord(flow_record, nffile);
|
||||
#ifdef DEVEL
|
||||
format_file_block_record((void *)flow_record, &string, 0);
|
||||
printf("%s\n", string);
|
||||
#endif
|
||||
// Update statistics
|
||||
UpdateStat(nffile->stat_record, flow_record);
|
||||
|
||||
r = r->next;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( nffile->block_header->NumRecords ) {
|
||||
if ( WriteBlock(nffile) <= 0 ) {
|
||||
LogError("Failed to write output buffer to disk: '%s'" , strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
} // End of ExportFlowTable
|
||||
|
||||
|
45
bin/nfexport.h
Executable file
45
bin/nfexport.h
Executable file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: nfexport.h 54 2010-01-29 11:30:22Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 54 $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NFEXPORT_H
|
||||
#define _NFEXPORT_H 1
|
||||
|
||||
int ExportFlowTable(nffile_t *nffile, int aggregate, int bidir, int date_sorted, extension_map_list_t *extension_map_list);
|
||||
|
||||
#endif //_NFEXPORT_H
|
||||
|
1356
bin/nffile.c
Normal file
1356
bin/nffile.c
Normal file
File diff suppressed because it is too large
Load Diff
2203
bin/nffile.h
Normal file
2203
bin/nffile.h
Normal file
File diff suppressed because it is too large
Load Diff
835
bin/nffile_inline.c
Executable file
835
bin/nffile_inline.c
Executable file
@ -0,0 +1,835 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: nffile_inline.c 40 2009-12-16 10:41:44Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 40 $
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* nffile_inline.c is needed for daemon code as well as normal stdio code
|
||||
* therefore a generic LogError is defined, which maps to the
|
||||
* approriate logging channel - either stderr or syslog
|
||||
*/
|
||||
void LogError(char *format, ...);
|
||||
|
||||
static inline int CheckBufferSpace(nffile_t *nffile, size_t required);
|
||||
|
||||
static inline void AppendToBuffer(nffile_t *nffile, void *record, size_t required);
|
||||
|
||||
static inline void CopyV6IP(uint32_t *dst, uint32_t *src);
|
||||
|
||||
static inline void ExpandRecord_v2(common_record_t *input_record, extension_info_t *extension_info, exporter_info_record_t *exporter_info, master_record_t *output_record );
|
||||
|
||||
#ifdef NEED_PACKRECORD
|
||||
static void PackRecord(master_record_t *master_record, nffile_t *nffile);
|
||||
#endif
|
||||
|
||||
static inline int CheckBufferSpace(nffile_t *nffile, size_t required) {
|
||||
|
||||
#ifdef DEVEL
|
||||
// printf("Buffer Size %u\n", nffile->block_header->size);
|
||||
#endif
|
||||
// flush current buffer to disc
|
||||
if ( (nffile->block_header->size + required ) > WRITE_BUFFSIZE ) {
|
||||
|
||||
// this should never happen, but catch it anyway
|
||||
if ( required > WRITE_BUFFSIZE ) {
|
||||
LogError("Required buffer size %zu too big for output buffer!" , required);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( WriteBlock(nffile) <= 0 ) {
|
||||
LogError("Failed to write output buffer to disk: '%s'" , strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
} // End of CheckBufferSpace
|
||||
|
||||
// Use 4 uint32_t copy cycles, as SPARC CPUs brak
|
||||
static inline void CopyV6IP(uint32_t *dst, uint32_t *src) {
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[2];
|
||||
dst[3] = src[3];
|
||||
} // End of CopyV6IP
|
||||
|
||||
/*
|
||||
* Expand file record into master record for further processing
|
||||
* LP64 CPUs need special 32bit operations as it is not guarateed, that 64bit
|
||||
* values are aligned
|
||||
*/
|
||||
static inline void ExpandRecord_v2(common_record_t *input_record, extension_info_t *extension_info, exporter_info_record_t *exporter_info, master_record_t *output_record ) {
|
||||
extension_map_t *extension_map = extension_info->map;
|
||||
uint32_t i, *u;
|
||||
void *p = (void *)input_record;
|
||||
#ifdef NSEL
|
||||
// nasty bug work around - compat issues 1.6.10 - 1.6.12 onwards
|
||||
union {
|
||||
uint16_t port[2];
|
||||
uint32_t vrf;
|
||||
} compat_nel_bug;
|
||||
compat_nel_bug.vrf = 0;
|
||||
int compat_nel = 0;
|
||||
#endif
|
||||
|
||||
// set map ref
|
||||
output_record->map_ref = extension_map;
|
||||
|
||||
if ( input_record->type == CommonRecordType ) {
|
||||
// Copy common data block
|
||||
memcpy((void *)output_record, (void *)input_record, COMMON_RECORD_DATA_SIZE);
|
||||
p = (void *)input_record->data;
|
||||
} else {
|
||||
// Compat v0 record - convert to new Common Record
|
||||
common_record_v0_t *common_record_v0 = (common_record_v0_t *)input_record;
|
||||
uint16_t flags = common_record_v0->flags;
|
||||
uint16_t exporter_sysid = common_record_v0->exporter_sysid;
|
||||
memcpy((void *)output_record, (void *)input_record, COMMON_RECORDV0_DATA_SIZE);
|
||||
output_record->flags = flags;
|
||||
output_record->exporter_sysid = exporter_sysid;
|
||||
p = (void *)common_record_v0->data;
|
||||
}
|
||||
|
||||
if ( exporter_info ) {
|
||||
uint32_t sysid = exporter_info->sysid;
|
||||
output_record->exporter_sysid = sysid;
|
||||
input_record->exporter_sysid = sysid;
|
||||
output_record->exp_ref = exporter_info;
|
||||
} else {
|
||||
output_record->exp_ref = NULL;
|
||||
}
|
||||
|
||||
// map icmp type/code in it's own vars
|
||||
output_record->icmp = output_record->dstport;
|
||||
|
||||
// Required extension 1 - IP addresses
|
||||
if ( (input_record->flags & FLAG_IPV6_ADDR) != 0 ) { // IPv6
|
||||
// IPv6
|
||||
// keep compiler happy
|
||||
// memcpy((void *)output_record->v6.srcaddr, p, 4 * sizeof(uint64_t));
|
||||
memcpy((void *)output_record->ip_union._ip_64.addr, p, 4 * sizeof(uint64_t));
|
||||
p = (void *)((pointer_addr_t)p + 4 * sizeof(uint64_t));
|
||||
} else {
|
||||
// IPv4
|
||||
u = (uint32_t *)p;
|
||||
output_record->v6.srcaddr[0] = 0;
|
||||
output_record->v6.srcaddr[1] = 0;
|
||||
output_record->v4.srcaddr = u[0];
|
||||
|
||||
output_record->v6.dstaddr[0] = 0;
|
||||
output_record->v6.dstaddr[1] = 0;
|
||||
output_record->v4.dstaddr = u[1];
|
||||
p = (void *)((pointer_addr_t)p + 2 * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
// Required extension 2 - packet counter
|
||||
if ( (input_record->flags & FLAG_PKG_64 ) != 0 ) {
|
||||
// 64bit packet counter
|
||||
value64_t l, *v = (value64_t *)p;
|
||||
l.val.val32[0] = v->val.val32[0];
|
||||
l.val.val32[1] = v->val.val32[1];
|
||||
output_record->dPkts = l.val.val64;
|
||||
p = (void *)((pointer_addr_t)p + sizeof(uint64_t));
|
||||
} else {
|
||||
// 32bit packet counter
|
||||
output_record->dPkts = *((uint32_t *)p);
|
||||
p = (void *)((pointer_addr_t)p + sizeof(uint32_t));
|
||||
}
|
||||
|
||||
// Required extension 3 - byte counter
|
||||
if ( (input_record->flags & FLAG_BYTES_64 ) != 0 ) {
|
||||
// 64bit byte counter
|
||||
value64_t l, *v = (value64_t *)p;
|
||||
l.val.val32[0] = v->val.val32[0];
|
||||
l.val.val32[1] = v->val.val32[1];
|
||||
output_record->dOctets = l.val.val64;
|
||||
p = (void *)((pointer_addr_t)p + sizeof(uint64_t));
|
||||
} else {
|
||||
// 32bit bytes counter
|
||||
output_record->dOctets = *((uint32_t *)p);
|
||||
p = (void *)((pointer_addr_t)p + sizeof(uint32_t));
|
||||
}
|
||||
|
||||
// preset one single flow
|
||||
output_record->aggr_flows = 1;
|
||||
|
||||
// Process optional extensions
|
||||
i=0;
|
||||
while ( extension_map->ex_id[i] ) {
|
||||
switch (extension_map->ex_id[i++]) {
|
||||
// 0 - 3 should never be in an extension table so - ignore it
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
break;
|
||||
case EX_IO_SNMP_2: {
|
||||
tpl_ext_4_t *tpl = (tpl_ext_4_t *)p;
|
||||
output_record->input = tpl->input;
|
||||
output_record->output = tpl->output;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_IO_SNMP_4: {
|
||||
tpl_ext_5_t *tpl = (tpl_ext_5_t *)p;
|
||||
output_record->input = tpl->input;
|
||||
output_record->output = tpl->output;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_AS_2: {
|
||||
tpl_ext_6_t *tpl = (tpl_ext_6_t *)p;
|
||||
output_record->srcas = tpl->src_as;
|
||||
output_record->dstas = tpl->dst_as;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_AS_4: {
|
||||
tpl_ext_7_t *tpl = (tpl_ext_7_t *)p;
|
||||
output_record->srcas = tpl->src_as;
|
||||
output_record->dstas = tpl->dst_as;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_MULIPLE: {
|
||||
tpl_ext_8_t *tpl = (tpl_ext_8_t *)p;
|
||||
// use a 32 bit int to copy all 4 fields
|
||||
output_record->any = tpl->any;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_NEXT_HOP_v4: {
|
||||
tpl_ext_9_t *tpl = (tpl_ext_9_t *)p;
|
||||
output_record->ip_nexthop.v6[0] = 0;
|
||||
output_record->ip_nexthop.v6[1] = 0;
|
||||
output_record->ip_nexthop.v4 = tpl->nexthop;
|
||||
p = (void *)tpl->data;
|
||||
ClearFlag(output_record->flags, FLAG_IPV6_NH);
|
||||
} break;
|
||||
case EX_NEXT_HOP_v6: {
|
||||
tpl_ext_10_t *tpl = (tpl_ext_10_t *)p;
|
||||
CopyV6IP((uint32_t *)output_record->ip_nexthop.v6, (uint32_t *)tpl->nexthop);
|
||||
p = (void *)tpl->data;
|
||||
SetFlag(output_record->flags, FLAG_IPV6_NH);
|
||||
} break;
|
||||
case EX_NEXT_HOP_BGP_v4: {
|
||||
tpl_ext_11_t *tpl = (tpl_ext_11_t *)p;
|
||||
output_record->bgp_nexthop.v6[0] = 0;
|
||||
output_record->bgp_nexthop.v6[1] = 0;
|
||||
output_record->bgp_nexthop.v4 = tpl->bgp_nexthop;
|
||||
ClearFlag(output_record->flags, FLAG_IPV6_NHB);
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_NEXT_HOP_BGP_v6: {
|
||||
tpl_ext_12_t *tpl = (tpl_ext_12_t *)p;
|
||||
CopyV6IP((uint32_t *)output_record->bgp_nexthop.v6, (uint32_t *)tpl->bgp_nexthop);
|
||||
p = (void *)tpl->data;
|
||||
SetFlag(output_record->flags, FLAG_IPV6_NHB);
|
||||
} break;
|
||||
case EX_VLAN: {
|
||||
tpl_ext_13_t *tpl = (tpl_ext_13_t *)p;
|
||||
output_record->src_vlan = tpl->src_vlan;
|
||||
output_record->dst_vlan = tpl->dst_vlan;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_OUT_PKG_4: {
|
||||
tpl_ext_14_t *tpl = (tpl_ext_14_t *)p;
|
||||
output_record->out_pkts = tpl->out_pkts;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_OUT_PKG_8: {
|
||||
tpl_ext_15_t v, *tpl = (tpl_ext_15_t *)p;
|
||||
v.v[0] = tpl->v[0];
|
||||
v.v[1] = tpl->v[1];
|
||||
output_record->out_pkts = v.out_pkts;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_OUT_BYTES_4: {
|
||||
tpl_ext_16_t *tpl = (tpl_ext_16_t *)p;
|
||||
output_record->out_bytes = tpl->out_bytes;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_OUT_BYTES_8: {
|
||||
tpl_ext_17_t v,*tpl = (tpl_ext_17_t *)p;
|
||||
v.v[0] = tpl->v[0];
|
||||
v.v[1] = tpl->v[1];
|
||||
output_record->out_bytes = v.out_bytes;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_AGGR_FLOWS_4: {
|
||||
tpl_ext_18_t *tpl = (tpl_ext_18_t *)p;
|
||||
output_record->aggr_flows = tpl->aggr_flows;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_AGGR_FLOWS_8: {
|
||||
tpl_ext_19_t v, *tpl = (tpl_ext_19_t *)p;
|
||||
v.v[0] = tpl->v[0];
|
||||
v.v[1] = tpl->v[1];
|
||||
output_record->aggr_flows = v.aggr_flows;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_MAC_1: {
|
||||
tpl_ext_20_t v, *tpl = (tpl_ext_20_t *)p;
|
||||
v.v1[0] = tpl->v1[0];
|
||||
v.v1[1] = tpl->v1[1];
|
||||
output_record->in_src_mac = v.in_src_mac;
|
||||
|
||||
v.v2[0] = tpl->v2[0];
|
||||
v.v2[1] = tpl->v2[1];
|
||||
output_record->out_dst_mac = v.out_dst_mac;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_MAC_2: {
|
||||
tpl_ext_21_t v, *tpl = (tpl_ext_21_t *)p;
|
||||
v.v1[0] = tpl->v1[0];
|
||||
v.v1[1] = tpl->v1[1];
|
||||
output_record->in_dst_mac = v.in_dst_mac;
|
||||
v.v2[0] = tpl->v2[0];
|
||||
v.v2[1] = tpl->v2[1];
|
||||
output_record->out_src_mac = v.out_src_mac;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_MPLS: {
|
||||
tpl_ext_22_t *tpl = (tpl_ext_22_t *)p;
|
||||
int j;
|
||||
for (j=0; j<10; j++ ) {
|
||||
output_record->mpls_label[j] = tpl->mpls_label[j];
|
||||
}
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_ROUTER_IP_v4: {
|
||||
tpl_ext_23_t *tpl = (tpl_ext_23_t *)p;
|
||||
output_record->ip_router.v6[0] = 0;
|
||||
output_record->ip_router.v6[1] = 0;
|
||||
output_record->ip_router.v4 = tpl->router_ip;
|
||||
p = (void *)tpl->data;
|
||||
ClearFlag(output_record->flags, FLAG_IPV6_EXP);
|
||||
} break;
|
||||
case EX_ROUTER_IP_v6: {
|
||||
tpl_ext_24_t *tpl = (tpl_ext_24_t *)p;
|
||||
CopyV6IP((uint32_t *)output_record->ip_router.v6, (uint32_t *)tpl->router_ip);
|
||||
p = (void *)tpl->data;
|
||||
SetFlag(output_record->flags, FLAG_IPV6_EXP);
|
||||
} break;
|
||||
case EX_ROUTER_ID: {
|
||||
tpl_ext_25_t *tpl = (tpl_ext_25_t *)p;
|
||||
output_record->engine_type = tpl->engine_type;
|
||||
output_record->engine_id = tpl->engine_id;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_BGPADJ: {
|
||||
tpl_ext_26_t *tpl = (tpl_ext_26_t *)p;
|
||||
output_record->bgpNextAdjacentAS = tpl->bgpNextAdjacentAS;
|
||||
output_record->bgpPrevAdjacentAS = tpl->bgpPrevAdjacentAS;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_LATENCY: {
|
||||
tpl_ext_latency_t *tpl = (tpl_ext_latency_t *)p;
|
||||
output_record->client_nw_delay_usec = tpl->client_nw_delay_usec;
|
||||
output_record->server_nw_delay_usec = tpl->server_nw_delay_usec;
|
||||
output_record->appl_latency_usec = tpl->appl_latency_usec;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_RECEIVED: {
|
||||
tpl_ext_27_t *tpl = (tpl_ext_27_t *)p;
|
||||
value64_t v;
|
||||
v.val.val32[0] = tpl->v[0];
|
||||
v.val.val32[1] = tpl->v[1];
|
||||
output_record->received = v.val.val64;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
#ifdef NSEL
|
||||
case EX_NSEL_COMMON: {
|
||||
tpl_ext_37_t *tpl = (tpl_ext_37_t *)p;
|
||||
value64_t v;
|
||||
v.val.val32[0] = tpl->v[0];
|
||||
v.val.val32[1] = tpl->v[1];
|
||||
output_record->event_time = v.val.val64;
|
||||
output_record->conn_id = tpl->conn_id;
|
||||
output_record->event = tpl->fw_event;
|
||||
output_record->event_flag = FW_EVENT;
|
||||
output_record->fw_xevent = tpl->fw_xevent;
|
||||
output_record->icmp = tpl->nsel_icmp;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_NSEL_XLATE_PORTS: {
|
||||
tpl_ext_38_t *tpl = (tpl_ext_38_t *)p;
|
||||
output_record->xlate_src_port = tpl->xlate_src_port;
|
||||
output_record->xlate_dst_port = tpl->xlate_dst_port;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_NSEL_XLATE_IP_v4: {
|
||||
tpl_ext_39_t *tpl = (tpl_ext_39_t *)p;
|
||||
output_record->xlate_src_ip.v6[0] = 0;
|
||||
output_record->xlate_src_ip.v6[1] = 0;
|
||||
output_record->xlate_src_ip.v4 = tpl->xlate_src_ip;
|
||||
output_record->xlate_dst_ip.v6[0] = 0;
|
||||
output_record->xlate_dst_ip.v6[1] = 0;
|
||||
output_record->xlate_dst_ip.v4 = tpl->xlate_dst_ip;
|
||||
p = (void *)tpl->data;
|
||||
output_record->xlate_flags = 0;
|
||||
} break;
|
||||
case EX_NSEL_XLATE_IP_v6: {
|
||||
tpl_ext_40_t *tpl = (tpl_ext_40_t *)p;
|
||||
output_record->xlate_src_ip.v6[0] = tpl->xlate_src_ip[0];
|
||||
output_record->xlate_src_ip.v6[1] = tpl->xlate_src_ip[1];
|
||||
output_record->xlate_dst_ip.v6[0] = tpl->xlate_dst_ip[0];
|
||||
output_record->xlate_dst_ip.v6[1] = tpl->xlate_dst_ip[1];
|
||||
p = (void *)tpl->data;
|
||||
output_record->xlate_flags = 1;
|
||||
} break;
|
||||
case EX_NSEL_ACL: {
|
||||
tpl_ext_41_t *tpl = (tpl_ext_41_t *)p;
|
||||
int j;
|
||||
for (j=0; j<3; j++) {
|
||||
output_record->ingress_acl_id[j] = tpl->ingress_acl_id[j];
|
||||
output_record->egress_acl_id[j] = tpl->egress_acl_id[j];
|
||||
}
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_NSEL_USER: {
|
||||
tpl_ext_42_t *tpl = (tpl_ext_42_t *)p;
|
||||
strncpy((void *)output_record->username, (void *)tpl->username, sizeof(output_record->username));
|
||||
output_record->username[sizeof(output_record->username)-1] = '\0'; // safety 0
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_NSEL_USER_MAX: {
|
||||
tpl_ext_43_t *tpl = (tpl_ext_43_t *)p;
|
||||
strncpy((void *)output_record->username, (void *)tpl->username, sizeof(output_record->username));
|
||||
output_record->username[sizeof(output_record->username)-1] = '\0'; // safety 0
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_NEL_COMMON: {
|
||||
tpl_ext_46_t *tpl = (tpl_ext_46_t *)p;
|
||||
output_record->event = tpl->nat_event;
|
||||
output_record->event_flag = FW_EVENT;
|
||||
// XXX - 3 bytes unused
|
||||
output_record->egress_vrfid = tpl->egress_vrfid;
|
||||
output_record->ingress_vrfid = tpl->ingress_vrfid;
|
||||
p = (void *)tpl->data;
|
||||
|
||||
// remember this value, if we read old 1.6.10 files
|
||||
compat_nel_bug.vrf = tpl->egress_vrfid;
|
||||
if ( compat_nel ) {
|
||||
output_record->xlate_src_port = compat_nel_bug.port[0];
|
||||
output_record->xlate_dst_port = compat_nel_bug.port[1];
|
||||
output_record->egress_vrfid = 0;
|
||||
}
|
||||
} break;
|
||||
// compat record v1.6.10
|
||||
case EX_NEL_GLOBAL_IP_v4: {
|
||||
tpl_ext_47_t *tpl = (tpl_ext_47_t *)p;
|
||||
output_record->xlate_src_ip.v6[0] = 0;
|
||||
output_record->xlate_src_ip.v6[1] = 0;
|
||||
output_record->xlate_src_ip.v4 = tpl->nat_inside;
|
||||
output_record->xlate_dst_ip.v6[0] = 0;
|
||||
output_record->xlate_dst_ip.v6[1] = 0;
|
||||
output_record->xlate_dst_ip.v4 = tpl->nat_outside;
|
||||
p = (void *)tpl->data;
|
||||
|
||||
output_record->xlate_src_port = compat_nel_bug.port[0];
|
||||
output_record->xlate_dst_port = compat_nel_bug.port[1];
|
||||
output_record->egress_vrfid = 0;
|
||||
compat_nel = 1;
|
||||
} break;
|
||||
case EX_PORT_BLOCK_ALLOC: {
|
||||
tpl_ext_48_t *tpl = (tpl_ext_48_t *)p;
|
||||
output_record->block_start = tpl->block_start;
|
||||
output_record->block_end = tpl->block_end;
|
||||
output_record->block_step = tpl->block_step;
|
||||
output_record->block_size = tpl->block_size;
|
||||
if ( output_record->block_end == 0 && output_record->block_size != 0 )
|
||||
output_record->block_end = output_record->block_start + output_record->block_size - 1;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
} // End of ExpandRecord_v2
|
||||
|
||||
#ifdef NEED_PACKRECORD
|
||||
static void PackRecord(master_record_t *master_record, nffile_t *nffile) {
|
||||
extension_map_t *extension_map = master_record->map_ref;
|
||||
common_record_t *common_record;
|
||||
uint32_t required = COMMON_RECORD_DATA_SIZE + extension_map->extension_size;
|
||||
size_t size;
|
||||
void *p;
|
||||
int i;
|
||||
|
||||
// check size of packets and bytes
|
||||
if ( master_record->dPkts > 0xffffffffLL ) {
|
||||
master_record->flags |= FLAG_PKG_64;
|
||||
required += 8;
|
||||
} else {
|
||||
master_record->flags &= ~FLAG_PKG_64;
|
||||
required += 4;
|
||||
}
|
||||
|
||||
if ( master_record->dOctets > 0xffffffffLL ) {
|
||||
master_record->flags |= FLAG_BYTES_64;
|
||||
required += 8;
|
||||
} else {
|
||||
master_record->flags &= ~FLAG_BYTES_64;
|
||||
required += 4;
|
||||
}
|
||||
if ( (master_record->flags & FLAG_IPV6_ADDR) != 0 ) // IPv6
|
||||
required += 32;
|
||||
else
|
||||
required += 8;
|
||||
|
||||
master_record->size = required;
|
||||
|
||||
// flush current buffer to disc if not enough space
|
||||
if ( !CheckBufferSpace(nffile, required) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// enough buffer space available at this point
|
||||
common_record = (common_record_t *)nffile->buff_ptr;
|
||||
|
||||
// write common record
|
||||
size = COMMON_RECORD_DATA_SIZE;
|
||||
memcpy((void *)common_record, (void *)master_record, size);
|
||||
common_record->reserved = 0;
|
||||
p = (void *)((pointer_addr_t)common_record + size);
|
||||
|
||||
// Required extension 1 - IP addresses
|
||||
if ( (master_record->flags & FLAG_IPV6_ADDR) != 0 ) { // IPv6
|
||||
// IPv6
|
||||
// keep compiler happy
|
||||
// memcpy(p, (void *)master_record->v6.srcaddr, 4 * sizeof(uint64_t));
|
||||
memcpy(p, (void *)master_record->ip_union._ip_64.addr, 4 * sizeof(uint64_t));
|
||||
p = (void *)((pointer_addr_t)p + 4 * sizeof(uint64_t));
|
||||
} else {
|
||||
// IPv4
|
||||
uint32_t *u = (uint32_t *)p;
|
||||
u[0] = master_record->v4.srcaddr;
|
||||
u[1] = master_record->v4.dstaddr;
|
||||
p = (void *)((pointer_addr_t)p + 2 * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
// Required extension 2 - packet counter
|
||||
if ( (master_record->flags & FLAG_PKG_64 ) != 0 ) {
|
||||
// 64bit packet counter
|
||||
value64_t l, *v = (value64_t *)p;
|
||||
l.val.val64 = master_record->dPkts;
|
||||
v->val.val32[0] = l.val.val32[0];
|
||||
v->val.val32[1] = l.val.val32[1];
|
||||
p = (void *)((pointer_addr_t)p + sizeof(uint64_t));
|
||||
} else {
|
||||
// 32bit packet counter
|
||||
*((uint32_t *)p) = master_record->dPkts;
|
||||
p = (void *)((pointer_addr_t)p + sizeof(uint32_t));
|
||||
}
|
||||
|
||||
// Required extension 3 - byte counter
|
||||
if ( (master_record->flags & FLAG_BYTES_64 ) != 0 ) {
|
||||
// 64bit byte counter
|
||||
value64_t l, *v = (value64_t *)p;
|
||||
l.val.val64 = master_record->dOctets;
|
||||
v->val.val32[0] = l.val.val32[0];
|
||||
v->val.val32[1] = l.val.val32[1];
|
||||
p = (void *)((pointer_addr_t)p + sizeof(uint64_t));
|
||||
} else {
|
||||
// 32bit bytes counter
|
||||
*((uint32_t *)p) = master_record->dOctets;
|
||||
p = (void *)((pointer_addr_t)p + sizeof(uint32_t));
|
||||
}
|
||||
|
||||
// Process optional extensions
|
||||
i=0;
|
||||
while ( extension_map->ex_id[i] ) {
|
||||
switch (extension_map->ex_id[i++]) {
|
||||
// 0 - 3 should never be in an extension table so - ignore it
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
break;
|
||||
case EX_IO_SNMP_2: { // input/output SNMP 2 byte
|
||||
tpl_ext_4_t *tpl = (tpl_ext_4_t *)p;
|
||||
tpl->input = master_record->input;
|
||||
tpl->output = master_record->output;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_IO_SNMP_4: { // input/output SNMP 4 byte
|
||||
tpl_ext_5_t *tpl = (tpl_ext_5_t *)p;
|
||||
tpl->input = master_record->input;
|
||||
tpl->output = master_record->output;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_AS_2: { // srcas/dstas 2 byte
|
||||
tpl_ext_6_t *tpl = (tpl_ext_6_t *)p;
|
||||
tpl->src_as = master_record->srcas;
|
||||
tpl->dst_as = master_record->dstas;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_AS_4: { // srcas/dstas 4 byte
|
||||
tpl_ext_7_t *tpl = (tpl_ext_7_t *)p;
|
||||
tpl->src_as = master_record->srcas;
|
||||
tpl->dst_as = master_record->dstas;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_MULIPLE: {
|
||||
tpl_ext_8_t *tpl = (tpl_ext_8_t *)p;
|
||||
// use a 32 bit int to copy all 4 fields
|
||||
tpl->any = master_record->any;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_NEXT_HOP_v4: {
|
||||
tpl_ext_9_t *tpl = (tpl_ext_9_t *)p;
|
||||
tpl->nexthop = master_record->ip_nexthop.v4;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_NEXT_HOP_v6: {
|
||||
tpl_ext_10_t *tpl = (tpl_ext_10_t *)p;
|
||||
tpl->nexthop[0] = master_record->ip_nexthop.v6[0];
|
||||
tpl->nexthop[1] = master_record->ip_nexthop.v6[1];
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_NEXT_HOP_BGP_v4: {
|
||||
tpl_ext_11_t *tpl = (tpl_ext_11_t *)p;
|
||||
tpl->bgp_nexthop = master_record->bgp_nexthop.v4;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_NEXT_HOP_BGP_v6: {
|
||||
tpl_ext_12_t *tpl = (tpl_ext_12_t *)p;
|
||||
tpl->bgp_nexthop[0] = master_record->bgp_nexthop.v6[0];
|
||||
tpl->bgp_nexthop[1] = master_record->bgp_nexthop.v6[1];
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_VLAN: {
|
||||
tpl_ext_13_t *tpl = (tpl_ext_13_t *)p;
|
||||
tpl->src_vlan = master_record->src_vlan;
|
||||
tpl->dst_vlan = master_record->dst_vlan;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_OUT_PKG_4: {
|
||||
tpl_ext_14_t *tpl = (tpl_ext_14_t *)p;
|
||||
tpl->out_pkts = master_record->out_pkts;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_OUT_PKG_8: {
|
||||
tpl_ext_15_t v, *tpl = (tpl_ext_15_t *)p;
|
||||
v.out_pkts = master_record->out_pkts;
|
||||
tpl->v[0] = v.v[0];
|
||||
tpl->v[1] = v.v[1];
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_OUT_BYTES_4: {
|
||||
tpl_ext_16_t *tpl = (tpl_ext_16_t *)p;
|
||||
tpl->out_bytes = master_record->out_bytes;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_OUT_BYTES_8: {
|
||||
tpl_ext_17_t v, *tpl = (tpl_ext_17_t *)p;
|
||||
v.out_bytes = master_record->out_bytes;
|
||||
tpl->v[0] = v.v[0];
|
||||
tpl->v[1] = v.v[1];
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_AGGR_FLOWS_4: {
|
||||
tpl_ext_18_t *tpl = (tpl_ext_18_t *)p;
|
||||
tpl->aggr_flows = master_record->aggr_flows;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_AGGR_FLOWS_8: {
|
||||
tpl_ext_19_t v, *tpl = (tpl_ext_19_t *)p;
|
||||
v.aggr_flows = master_record->aggr_flows;
|
||||
tpl->v[0] = v.v[0];
|
||||
tpl->v[1] = v.v[1];
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_MAC_1: {
|
||||
tpl_ext_20_t v, *tpl = (tpl_ext_20_t *)p;
|
||||
v.in_src_mac = master_record->in_src_mac;
|
||||
tpl->v1[0] = v.v1[0];
|
||||
tpl->v1[1] = v.v1[1];
|
||||
v.out_dst_mac = master_record->out_dst_mac;
|
||||
tpl->v2[0] = v.v2[0];
|
||||
tpl->v2[1] = v.v2[1];
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_MAC_2: {
|
||||
tpl_ext_21_t v, *tpl = (tpl_ext_21_t *)p;
|
||||
v.in_dst_mac = master_record->in_dst_mac;
|
||||
tpl->v1[0] = v.v1[0];
|
||||
tpl->v1[1] = v.v1[1];
|
||||
v.out_src_mac = master_record->out_src_mac;
|
||||
tpl->v2[0] = v.v2[0];
|
||||
tpl->v2[1] = v.v2[1];
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_MPLS: {
|
||||
tpl_ext_22_t *tpl = (tpl_ext_22_t *)p;
|
||||
int j;
|
||||
for (j=0; j<10; j++ ) {
|
||||
tpl->mpls_label[j] = master_record->mpls_label[j];
|
||||
}
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_ROUTER_IP_v4: {
|
||||
tpl_ext_23_t *tpl = (tpl_ext_23_t *)p;
|
||||
tpl->router_ip = master_record->ip_router.v4;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_ROUTER_IP_v6: {
|
||||
tpl_ext_24_t *tpl = (tpl_ext_24_t *)p;
|
||||
tpl->router_ip[0] = master_record->ip_router.v6[0];
|
||||
tpl->router_ip[1] = master_record->ip_router.v6[1];
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_ROUTER_ID: {
|
||||
tpl_ext_25_t *tpl = (tpl_ext_25_t *)p;
|
||||
tpl->engine_type = master_record->engine_type;
|
||||
tpl->engine_id = master_record->engine_id;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_BGPADJ: {
|
||||
tpl_ext_26_t *tpl = (tpl_ext_26_t *)p;
|
||||
tpl->bgpNextAdjacentAS = master_record->bgpNextAdjacentAS;
|
||||
tpl->bgpPrevAdjacentAS = master_record->bgpPrevAdjacentAS;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_RECEIVED: {
|
||||
tpl_ext_27_t *tpl = (tpl_ext_27_t *)p;
|
||||
tpl->received = master_record->received;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
#ifdef NSEL
|
||||
case EX_NSEL_COMMON: {
|
||||
tpl_ext_37_t *tpl = (tpl_ext_37_t *)p;
|
||||
tpl->event_time = master_record->event_time;
|
||||
tpl->conn_id = master_record->conn_id;
|
||||
tpl->fw_event = master_record->event;
|
||||
tpl->nsel_icmp = master_record->icmp;
|
||||
tpl->fill = 0;
|
||||
tpl->fill2 = 0;
|
||||
tpl->fw_xevent = master_record->fw_xevent;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_NSEL_XLATE_PORTS: {
|
||||
tpl_ext_38_t *tpl = (tpl_ext_38_t *)p;
|
||||
tpl->xlate_src_port = master_record->xlate_src_port;
|
||||
tpl->xlate_dst_port = master_record->xlate_dst_port;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_NSEL_XLATE_IP_v4: {
|
||||
tpl_ext_39_t *tpl = (tpl_ext_39_t *)p;
|
||||
tpl->xlate_src_ip = master_record->xlate_src_ip.v4;
|
||||
tpl->xlate_dst_ip = master_record->xlate_dst_ip.v4;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_NSEL_XLATE_IP_v6: {
|
||||
tpl_ext_40_t *tpl = (tpl_ext_40_t *)p;
|
||||
tpl->xlate_src_ip[0] = master_record->xlate_src_ip.v6[0];
|
||||
tpl->xlate_src_ip[1] = master_record->xlate_src_ip.v6[1];
|
||||
p = (void *)tpl->data;
|
||||
tpl->xlate_dst_ip[0] = master_record->xlate_dst_ip.v6[0];
|
||||
tpl->xlate_dst_ip[1] = master_record->xlate_dst_ip.v6[1];
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_NSEL_ACL: {
|
||||
tpl_ext_41_t *tpl = (tpl_ext_41_t *)p;
|
||||
int j;
|
||||
for (j=0; j<3; j++) {
|
||||
tpl->ingress_acl_id[j] = master_record->ingress_acl_id[j];
|
||||
tpl->egress_acl_id[j] = master_record->egress_acl_id[j];
|
||||
}
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_NSEL_USER: {
|
||||
tpl_ext_42_t *tpl = (tpl_ext_42_t *)p;
|
||||
strncpy((void *)tpl->username, (void *)master_record->username, sizeof(tpl->username));
|
||||
tpl->username[sizeof(tpl->username)-1] = '\0'; // safety 0
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_NSEL_USER_MAX: {
|
||||
tpl_ext_43_t *tpl = (tpl_ext_43_t *)p;
|
||||
strncpy((void *)tpl->username, (void *)master_record->username, sizeof(tpl->username));
|
||||
tpl->username[sizeof(tpl->username)-1] = '\0'; // safety 0
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_NEL_COMMON: {
|
||||
tpl_ext_46_t *tpl = (tpl_ext_46_t *)p;
|
||||
tpl->nat_event = master_record->event;
|
||||
tpl->fill = 0;
|
||||
tpl->flags = 0;
|
||||
tpl->egress_vrfid = master_record->egress_vrfid;
|
||||
tpl->ingress_vrfid = master_record->ingress_vrfid;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
case EX_PORT_BLOCK_ALLOC: {
|
||||
tpl_ext_48_t *tpl = (tpl_ext_48_t *)p;
|
||||
tpl->block_start = master_record->block_start;
|
||||
tpl->block_end = master_record->block_end;
|
||||
tpl->block_step = master_record->block_step;
|
||||
tpl->block_size = master_record->block_size;
|
||||
p = (void *)tpl->data;
|
||||
} break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
nffile->block_header->size += required;
|
||||
nffile->block_header->NumRecords++;
|
||||
#ifdef DEVEL
|
||||
if ( ((pointer_addr_t)p - (pointer_addr_t)nffile->buff_ptr) != required ) {
|
||||
fprintf(stderr, "Packrecord: size missmatch: required: %i, written: %li!\n",
|
||||
required, (long)((ptrdiff_t)p - (ptrdiff_t)nffile->buff_ptr));
|
||||
exit(255);
|
||||
}
|
||||
#endif
|
||||
nffile->buff_ptr = p;
|
||||
|
||||
} // End of PackRecord
|
||||
#endif
|
||||
|
||||
static inline void AppendToBuffer(nffile_t *nffile, void *record, size_t required) {
|
||||
|
||||
// flush current buffer to disc
|
||||
if ( !CheckBufferSpace(nffile, required)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// enough buffer space available at this point
|
||||
memcpy(nffile->buff_ptr, record, required);
|
||||
|
||||
// update stat
|
||||
nffile->block_header->NumRecords++;
|
||||
nffile->block_header->size += required;
|
||||
|
||||
// advance write pointer
|
||||
nffile->buff_ptr = (void *)((pointer_addr_t)nffile->buff_ptr + required);
|
||||
|
||||
} // End of AppendToBuffer
|
550
bin/nfgen.c
Normal file
550
bin/nfgen.c
Normal file
@ -0,0 +1,550 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: nfgen.c 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "nffile.h"
|
||||
#include "nfx.h"
|
||||
#include "nfnet.h"
|
||||
#include "nf_common.h"
|
||||
#include "util.h"
|
||||
#include "bookkeeper.h"
|
||||
#include "nfxstat.h"
|
||||
#include "collector.h"
|
||||
#include "exporter.h"
|
||||
#include "netflow_v5_v7.h"
|
||||
|
||||
extern extension_descriptor_t extension_descriptor[];
|
||||
|
||||
static time_t when;
|
||||
uint32_t offset = 10;
|
||||
uint32_t msecs = 10;
|
||||
|
||||
static extension_info_t extension_info;
|
||||
|
||||
#define NEED_PACKRECORD 1
|
||||
#include "nffile_inline.c"
|
||||
#undef NEED_PACKRECORD
|
||||
|
||||
void *GenRecord(int af, void *buff_ptr, char *src_ip, char *dst_ip, int src_port, int dst_port,
|
||||
int proto, int tcp_flags, int tos, uint64_t packets, uint64_t bytes, int src_as, int dst_as);
|
||||
|
||||
static void SetIPaddress(master_record_t *record, int af, char *src_ip, char *dst_ip);
|
||||
|
||||
static void SetNextIPaddress(master_record_t *record, int af, char *next_ip);
|
||||
|
||||
static void SetRouterIPaddress(master_record_t *record, int af, char *next_ip);
|
||||
|
||||
static void SetBGPNextIPaddress(master_record_t *record, int af, char *next_ip);
|
||||
|
||||
static void UpdateRecord(master_record_t *record);
|
||||
|
||||
static void SetIPaddress(master_record_t *record, int af, char *src_ip, char *dst_ip) {
|
||||
|
||||
if ( af == PF_INET6 ) {
|
||||
SetFlag(record->flags, FLAG_IPV6_ADDR);
|
||||
inet_pton(PF_INET6, src_ip, &(record->v6.srcaddr[0]));
|
||||
inet_pton(PF_INET6, dst_ip, &(record->v6.dstaddr[0]));
|
||||
record->v6.srcaddr[0] = ntohll(record->v6.srcaddr[0]);
|
||||
record->v6.srcaddr[1] = ntohll(record->v6.srcaddr[1]);
|
||||
record->v6.dstaddr[0] = ntohll(record->v6.dstaddr[0]);
|
||||
record->v6.dstaddr[1] = ntohll(record->v6.dstaddr[1]);
|
||||
} else {
|
||||
ClearFlag(record->flags, FLAG_IPV6_ADDR);
|
||||
inet_pton(PF_INET, src_ip, &record->v4.srcaddr);
|
||||
inet_pton(PF_INET, dst_ip, &record->v4.dstaddr);
|
||||
record->v4.srcaddr = ntohl(record->v4.srcaddr);
|
||||
record->v4.dstaddr = ntohl(record->v4.dstaddr);
|
||||
}
|
||||
|
||||
} // End of SetIPaddress
|
||||
|
||||
static void SetNextIPaddress(master_record_t *record, int af, char *next_ip) {
|
||||
|
||||
if ( af == PF_INET6 ) {
|
||||
SetFlag(record->flags, FLAG_IPV6_NH);
|
||||
inet_pton(PF_INET6, next_ip, &(record->ip_nexthop.v6[0]));
|
||||
record->ip_nexthop.v6[0] = ntohll(record->ip_nexthop.v6[0]);
|
||||
record->ip_nexthop.v6[1] = ntohll(record->ip_nexthop.v6[1]);
|
||||
} else {
|
||||
ClearFlag(record->flags, FLAG_IPV6_NH);
|
||||
inet_pton(PF_INET, next_ip, &record->ip_nexthop.v4);
|
||||
record->ip_nexthop.v4 = ntohl(record->ip_nexthop.v4);
|
||||
}
|
||||
|
||||
} // End of SetNextIPaddress
|
||||
|
||||
static void SetRouterIPaddress(master_record_t *record, int af, char *next_ip) {
|
||||
|
||||
if ( af == PF_INET6 ) {
|
||||
SetFlag(record->flags, FLAG_IPV6_NH);
|
||||
inet_pton(PF_INET6, next_ip, &(record->ip_router.v6[0]));
|
||||
record->ip_router.v6[0] = ntohll(record->ip_router.v6[0]);
|
||||
record->ip_router.v6[1] = ntohll(record->ip_router.v6[1]);
|
||||
} else {
|
||||
ClearFlag(record->flags, FLAG_IPV6_NH);
|
||||
inet_pton(PF_INET, next_ip, &record->ip_router.v4);
|
||||
record->ip_router.v4 = ntohl(record->ip_router.v4);
|
||||
}
|
||||
|
||||
} // End of SetRouterIPaddress
|
||||
|
||||
static void SetBGPNextIPaddress(master_record_t *record, int af, char *next_ip) {
|
||||
|
||||
if ( af == PF_INET6 ) {
|
||||
SetFlag(record->flags, FLAG_IPV6_NHB);
|
||||
inet_pton(PF_INET6, next_ip, &(record->bgp_nexthop.v6[0]));
|
||||
record->bgp_nexthop.v6[0] = ntohll(record->bgp_nexthop.v6[0]);
|
||||
record->bgp_nexthop.v6[1] = ntohll(record->bgp_nexthop.v6[1]);
|
||||
} else {
|
||||
ClearFlag(record->flags, FLAG_IPV6_NHB);
|
||||
inet_pton(PF_INET, next_ip, &record->bgp_nexthop.v4);
|
||||
record->bgp_nexthop.v4 = ntohl(record->bgp_nexthop.v4);
|
||||
}
|
||||
|
||||
} // End of SetBGPNextIPaddress
|
||||
|
||||
|
||||
static void UpdateRecord(master_record_t *record) {
|
||||
|
||||
record->first = when;
|
||||
record->last = when + offset;
|
||||
record->msec_first = msecs;
|
||||
record->msec_last = msecs + 10;
|
||||
|
||||
when += 10;
|
||||
offset += 10;
|
||||
|
||||
msecs += 100;
|
||||
if ( msecs > 1000 )
|
||||
msecs = msecs - 1000;
|
||||
|
||||
record->fwd_status++;
|
||||
|
||||
} // End of UpdateRecord
|
||||
|
||||
int main( int argc, char **argv ) {
|
||||
int i, c;
|
||||
master_record_t record;
|
||||
nffile_t *nffile;
|
||||
|
||||
when = ISO2UNIX(strdup("200407111030"));
|
||||
while ((c = getopt(argc, argv, "h")) != EOF) {
|
||||
switch(c) {
|
||||
case 'h':
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "ERROR: Unsupported option: '%c'\n", c);
|
||||
exit(255);
|
||||
}
|
||||
}
|
||||
|
||||
extension_info.map = (extension_map_t *)malloc(sizeof(extension_map_t) + 32 * sizeof(uint16_t));
|
||||
if ( !extension_info.map ) {
|
||||
fprintf(stderr, "malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno));
|
||||
exit(255);
|
||||
}
|
||||
extension_info.map->type = ExtensionMapType;
|
||||
extension_info.map->map_id = 0;
|
||||
i = 0;
|
||||
extension_info.map->ex_id[i++] = EX_IO_SNMP_2;
|
||||
extension_info.map->ex_id[i++] = EX_AS_2;
|
||||
extension_info.map->ex_id[i++] = EX_MULIPLE;
|
||||
extension_info.map->ex_id[i++] = EX_NEXT_HOP_v4;
|
||||
extension_info.map->ex_id[i++] = EX_NEXT_HOP_BGP_v4;
|
||||
extension_info.map->ex_id[i++] = EX_VLAN;
|
||||
extension_info.map->ex_id[i++] = EX_OUT_PKG_4;
|
||||
extension_info.map->ex_id[i++] = EX_OUT_BYTES_4;
|
||||
extension_info.map->ex_id[i++] = EX_AGGR_FLOWS_4;
|
||||
extension_info.map->ex_id[i++] = EX_MAC_1;
|
||||
extension_info.map->ex_id[i++] = EX_MAC_2;
|
||||
extension_info.map->ex_id[i++] = EX_MPLS;
|
||||
extension_info.map->ex_id[i++] = EX_ROUTER_IP_v4;
|
||||
extension_info.map->ex_id[i++] = EX_ROUTER_ID;
|
||||
extension_info.map->ex_id[i++] = EX_BGPADJ;
|
||||
extension_info.map->ex_id[i] = 0;
|
||||
extension_info.map->size = sizeof(extension_map_t) + i * sizeof(uint16_t);
|
||||
|
||||
// align 32bits
|
||||
if (( extension_info.map->size & 0x3 ) != 0 ) {
|
||||
extension_info.map->size += 4 - ( extension_info.map->size & 0x3 );
|
||||
}
|
||||
|
||||
extension_info.map->extension_size = 0;
|
||||
i=0;
|
||||
while (extension_info.map->ex_id[i]) {
|
||||
int id = extension_info.map->ex_id[i];
|
||||
extension_info.map->extension_size += extension_descriptor[id].size;
|
||||
i++;
|
||||
}
|
||||
memset((void *)&record, 0, sizeof(record));
|
||||
|
||||
nffile = OpenNewFile("-", NULL, 0, 0, NULL);
|
||||
if ( !nffile ) {
|
||||
exit(255);
|
||||
}
|
||||
|
||||
AppendToBuffer(nffile, (void *)extension_info.map, extension_info.map->size);
|
||||
|
||||
record.map_ref = extension_info.map;
|
||||
record.type = CommonRecordType;
|
||||
|
||||
record.flags = 0;
|
||||
record.exporter_sysid = 1;
|
||||
record.tcp_flags = 1;
|
||||
record.tos = 2;
|
||||
record.fwd_status = 0;
|
||||
record.srcport = 1024;
|
||||
record.dstport = 25;
|
||||
record.prot = IPPROTO_TCP;
|
||||
record.input = 12;
|
||||
record.output = 14;
|
||||
record.srcas = 775;
|
||||
record.dstas = 8404;
|
||||
SetIPaddress(&record, PF_INET, "172.16.1.66", "192.168.170.100");
|
||||
SetNextIPaddress(&record, PF_INET, "172.72.1.2");
|
||||
SetBGPNextIPaddress(&record, PF_INET, "172.73.2.3");
|
||||
SetRouterIPaddress(&record, PF_INET, "127.0.0.1");
|
||||
record.engine_type = 5;
|
||||
record.engine_id = 6;
|
||||
record.dPkts = 202;
|
||||
record.dOctets = 303;
|
||||
record.dst_tos = 128;
|
||||
record.dir = 1;
|
||||
record.src_mask = 16;
|
||||
record.dst_mask = 24;
|
||||
record.src_vlan = 82;
|
||||
record.dst_vlan = 93;
|
||||
record.out_pkts = 212;
|
||||
record.out_bytes = 3234;
|
||||
record.aggr_flows = 3;
|
||||
record.in_src_mac = 0x0234567890aaLL;
|
||||
record.out_dst_mac = 0xffeeddccbbaaLL;
|
||||
record.out_src_mac = 0xaa3456789002LL;
|
||||
record.in_dst_mac = 0xaaeeddccbbffLL;
|
||||
record.mpls_label[0] = 1010 << 4;
|
||||
record.mpls_label[1] = 2020 << 4;
|
||||
record.mpls_label[2] = 3030 << 4;
|
||||
record.mpls_label[3] = 4040 << 4;
|
||||
record.mpls_label[4] = 5050 << 4;
|
||||
record.mpls_label[5] = 6060 << 4;
|
||||
record.mpls_label[6] = 7070 << 4;
|
||||
record.mpls_label[7] = 8080 << 4;
|
||||
record.mpls_label[8] = 9090 << 4;
|
||||
record.mpls_label[9] = (100100 << 4) + 1;
|
||||
record.client_nw_delay_usec = 2;
|
||||
record.server_nw_delay_usec = 22;
|
||||
record.appl_latency_usec = 222;
|
||||
record.bgpNextAdjacentAS = 45804;
|
||||
record.bgpPrevAdjacentAS = 32775;
|
||||
|
||||
fprintf(stderr, "IPv4 32bit packets 32bit bytes\n");
|
||||
UpdateRecord(&record);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
SetIPaddress(&record, PF_INET, "172.16.2.66", "192.168.170.101");
|
||||
fprintf(stderr, "IPv4 32bit packets 32bit bytes\n");
|
||||
UpdateRecord(&record);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
record.dPkts = 101;
|
||||
record.dOctets = 102;
|
||||
fprintf(stderr, "IPv4 32bit packets 32bit bytes\n");
|
||||
UpdateRecord(&record);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
SetIPaddress(&record, PF_INET, "172.16.3.66", "192.168.170.102");
|
||||
fprintf(stderr, "IPv4 32bit packets 32bit bytes\n");
|
||||
UpdateRecord(&record);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
SetIPaddress(&record, PF_INET, "172.16.4.66", "192.168.170.103");
|
||||
record.srcport = 2024;
|
||||
record.prot = IPPROTO_UDP;
|
||||
record.tcp_flags = 1;
|
||||
record.tos = 1;
|
||||
record.dPkts = 1001;
|
||||
record.dOctets = 1002;
|
||||
fprintf(stderr, "IPv4 32bit packets 32bit bytes\n");
|
||||
UpdateRecord(&record);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
SetIPaddress(&record, PF_INET, "172.16.5.66", "192.168.170.104");
|
||||
record.srcport = 3024;
|
||||
record.prot = 51;
|
||||
record.tcp_flags = 2;
|
||||
record.tos = 2;
|
||||
record.dPkts = 10001;
|
||||
record.dOctets = 10002;
|
||||
fprintf(stderr, "IPv4 32bit packets 32bit bytes\n");
|
||||
UpdateRecord(&record);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
SetIPaddress(&record, PF_INET, "172.16.6.66", "192.168.170.105");
|
||||
record.srcport = 4024;
|
||||
record.prot = IPPROTO_TCP;
|
||||
record.tcp_flags = 4;
|
||||
record.tos = 3;
|
||||
record.dPkts = 100001;
|
||||
record.dOctets = 100002;
|
||||
fprintf(stderr, "IPv4 32bit packets 32bit bytes\n");
|
||||
UpdateRecord(&record);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
SetIPaddress(&record, PF_INET, "172.16.7.66", "192.168.170.106");
|
||||
record.srcport = 5024;
|
||||
record.tcp_flags = 8;
|
||||
record.tos = 4;
|
||||
record.dPkts = 1000001;
|
||||
record.dOctets = 1000002;
|
||||
fprintf(stderr, "IPv4 32bit packets 32bit bytes\n");
|
||||
UpdateRecord(&record);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
SetIPaddress(&record, PF_INET, "172.16.8.66", "192.168.170.107");
|
||||
record.tcp_flags = 1;
|
||||
record.tos = 4;
|
||||
record.dPkts = 10000001;
|
||||
record.dOctets = 1001;
|
||||
fprintf(stderr, "IPv4 32bit packets 32bit bytes\n");
|
||||
UpdateRecord(&record);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
SetIPaddress(&record, PF_INET, "172.16.9.66", "192.168.170.108");
|
||||
record.srcport = 6024;
|
||||
record.tcp_flags = 16;
|
||||
record.tos = 5;
|
||||
record.dPkts = 500;
|
||||
record.dOctets = 10000001;
|
||||
fprintf(stderr, "IPv4 32bit packets 32bit bytes\n");
|
||||
UpdateRecord(&record);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
SetIPaddress(&record, PF_INET, "172.16.10.66", "192.168.170.109");
|
||||
fprintf(stderr, "IPv4 32bit packets 32bit bytes\n");
|
||||
UpdateRecord(&record);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
SetIPaddress(&record, PF_INET, "172.16.11.66", "192.168.170.110");
|
||||
record.srcport = 7024;
|
||||
record.tcp_flags = 32;
|
||||
record.tos = 255;
|
||||
record.dPkts = 5000;
|
||||
record.dOctets = 100000001;
|
||||
fprintf(stderr, "IPv4 32bit packets 32bit bytes\n");
|
||||
UpdateRecord(&record);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
SetIPaddress(&record, PF_INET, "172.16.12.66", "192.168.170.111");
|
||||
record.srcport = 8024;
|
||||
record.tcp_flags = 63;
|
||||
record.tos = 0;
|
||||
record.dOctets = 1000000001;
|
||||
fprintf(stderr, "IPv4 32bit packets 32bit bytes\n");
|
||||
UpdateRecord(&record);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
SetIPaddress(&record, PF_INET, "172.16.13.66", "192.168.170.112");
|
||||
record.srcport = 0;
|
||||
record.dstport = 8;
|
||||
record.prot = 1;
|
||||
record.tcp_flags = 0;
|
||||
record.tos = 0;
|
||||
record.dPkts = 50002;
|
||||
record.dOctets = 50000;
|
||||
fprintf(stderr, "IPv4 32bit packets 32bit bytes\n");
|
||||
UpdateRecord(&record);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
SetIPaddress(&record, PF_INET, "172.160.160.166", "172.160.160.180");
|
||||
record.srcport = 10024;
|
||||
record.dstport = 25000;
|
||||
record.prot = IPPROTO_TCP;
|
||||
record.dPkts = 500001;
|
||||
record.dOctets = 500000;
|
||||
fprintf(stderr, "IPv4 32bit packets 32bit bytes\n");
|
||||
UpdateRecord(&record);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
SetIPaddress(&record, PF_INET6, "fe80::2110:abcd:1234:0", "fe80::2110:abcd:1235:4321");
|
||||
// SetNextIPaddress(&record, PF_INET6, "2003:234:aabb::211:24ff:fe80:d01e");
|
||||
// SetBGPNextIPaddress(&record, PF_INET6, "2004:234:aabb::211:24ff:fe80:d01e");
|
||||
record.srcport = 1024;
|
||||
record.dstport = 25;
|
||||
record.tcp_flags = 27;
|
||||
record.dPkts = 10;
|
||||
record.dOctets = 15100;
|
||||
fprintf(stderr, "IPv6 32bit packets 32bit bytes\n");
|
||||
UpdateRecord(&record);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
SetIPaddress(&record, PF_INET6, "2001:234:aabb::211:24ff:fe80:d01e", "2001:620::8:203:baff:fe52:38e5");
|
||||
record.srcport = 10240;
|
||||
record.dstport = 52345;
|
||||
record.dPkts = 10100;
|
||||
record.dOctets = 15000000;
|
||||
fprintf(stderr, "IPv6 32bit packets 32bit bytes\n");
|
||||
UpdateRecord(&record);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
record.dPkts = 10100000;
|
||||
record.dOctets = 0x100000000LL;
|
||||
fprintf(stderr, "IPv6 32bit packets 64bit bytes\n");
|
||||
UpdateRecord(&record);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
record.dPkts = 0x100000000LL;
|
||||
record.dOctets = 15000000;
|
||||
fprintf(stderr, "IPv6 64bit packets 32bit bytes\n");
|
||||
UpdateRecord(&record);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
record.dOctets = 0x200000000LL;
|
||||
fprintf(stderr, "IPv6 64bit packets 64bit bytes\n");
|
||||
UpdateRecord(&record);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
SetIPaddress(&record, PF_INET, "172.16.14.18", "192.168.170.113");
|
||||
// SetNextIPaddress(&record, PF_INET, "172.72.1.2");
|
||||
// SetBGPNextIPaddress(&record, PF_INET, "172.73.2.3");
|
||||
record.srcport = 10240;
|
||||
record.dstport = 52345;
|
||||
record.dPkts = 10100000;
|
||||
record.dOctets = 0x100000000LL;
|
||||
fprintf(stderr, "IPv4 32bit packets 64bit bytes\n");
|
||||
UpdateRecord(&record);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
SetIPaddress(&record, PF_INET, "172.16.15.18", "192.168.170.114");
|
||||
record.dPkts = 0x100000000LL;
|
||||
record.dOctets = 15000000;
|
||||
fprintf(stderr, "IPv4 64bit packets 32bit bytes\n");
|
||||
UpdateRecord(&record);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
SetIPaddress(&record, PF_INET, "172.16.16.18", "192.168.170.115");
|
||||
record.dOctets = 0x200000000LL;
|
||||
fprintf(stderr, "IPv4 64bit packets 64bit bytes\n");
|
||||
UpdateRecord(&record);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
extension_info.map->ex_id[0] = EX_IO_SNMP_4;
|
||||
|
||||
extension_info.map->extension_size = 0;
|
||||
i=0;
|
||||
while (extension_info.map->ex_id[i]) {
|
||||
int id = extension_info.map->ex_id[i];
|
||||
extension_info.map->extension_size += extension_descriptor[id].size;
|
||||
i++;
|
||||
}
|
||||
|
||||
memcpy(nffile->buff_ptr, (void *)extension_info.map, extension_info.map->size);
|
||||
nffile->buff_ptr += extension_info.map->size;
|
||||
nffile->block_header->NumRecords++;
|
||||
nffile->block_header->size += extension_info.map->size;
|
||||
|
||||
UpdateRecord(&record);
|
||||
fprintf(stderr, "4 bytes interfaces, 2 bytes AS numbers %d %d\n", record.fwd_status, nffile->block_header->NumRecords);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
extension_info.map->ex_id[0] = EX_IO_SNMP_2;
|
||||
extension_info.map->ex_id[1] = EX_AS_4;
|
||||
|
||||
extension_info.map->extension_size = 0;
|
||||
i=0;
|
||||
while (extension_info.map->ex_id[i]) {
|
||||
int id = extension_info.map->ex_id[i];
|
||||
extension_info.map->extension_size += extension_descriptor[id].size;
|
||||
i++;
|
||||
}
|
||||
|
||||
memcpy(nffile->buff_ptr, (void *)extension_info.map, extension_info.map->size);
|
||||
nffile->buff_ptr += extension_info.map->size;
|
||||
nffile->block_header->NumRecords++;
|
||||
nffile->block_header->size += extension_info.map->size;
|
||||
|
||||
UpdateRecord(&record);
|
||||
fprintf(stderr, "2 bytes interfaces, 4 bytes AS numbers %d %d\n", record.fwd_status, nffile->block_header->NumRecords);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
extension_info.map->ex_id[0] = EX_IO_SNMP_4;
|
||||
|
||||
extension_info.map->extension_size = 0;
|
||||
i=0;
|
||||
while (extension_info.map->ex_id[i]) {
|
||||
int id = extension_info.map->ex_id[i];
|
||||
extension_info.map->extension_size += extension_descriptor[id].size;
|
||||
i++;
|
||||
}
|
||||
|
||||
memcpy(nffile->buff_ptr, (void *)extension_info.map, extension_info.map->size);
|
||||
nffile->buff_ptr += extension_info.map->size;
|
||||
nffile->block_header->NumRecords++;
|
||||
nffile->block_header->size += extension_info.map->size;
|
||||
|
||||
UpdateRecord(&record);
|
||||
fprintf(stderr, "4 bytes interfaces, 4 bytes AS numbers %d %d\n", record.fwd_status, nffile->block_header->NumRecords);
|
||||
PackRecord(&record, nffile);
|
||||
|
||||
if ( nffile->block_header->NumRecords ) {
|
||||
if ( WriteBlock(nffile) <= 0 ) {
|
||||
fprintf(stderr, "Failed to write output buffer to disk: '%s'" , strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
933
bin/nflowcache.c
Executable file
933
bin/nflowcache.c
Executable file
@ -0,0 +1,933 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: nflowcache.c 40 2009-12-16 10:41:44Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 40 $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "nffile.h"
|
||||
#include "nfx.h"
|
||||
#include "nflowcache.h"
|
||||
|
||||
#ifndef DEVEL
|
||||
# define dbg_printf(...) /* printf(__VA_ARGS__) */
|
||||
#else
|
||||
# define dbg_printf(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define ALIGN_BYTES (offsetof (struct { char x; uint64_t y; }, y) - 1)
|
||||
|
||||
extern int hash_hit;
|
||||
extern int hash_miss;
|
||||
extern int hash_skip;
|
||||
|
||||
/* function prototypes */
|
||||
static void MemoryHandle_free(MemoryHandle_t *handle);
|
||||
|
||||
static int MemoryHandle_init(MemoryHandle_t *handle);
|
||||
|
||||
static inline void *MemoryHandle_get(MemoryHandle_t *handle, uint32_t size);
|
||||
|
||||
static inline FlowTableRecord_t *hash_insert_FlowTable(uint32_t index_cache, void *flowkey, common_record_t *flow_record);
|
||||
|
||||
static inline int TimeMsec_CMP(time_t t1, uint16_t offset1, time_t t2, uint16_t offset2 );
|
||||
|
||||
static inline uint32_t SuperFastHash (const char * data, int len);
|
||||
|
||||
static inline void New_Hash_Key(void *keymem, master_record_t *flow_record, int swap_flow);
|
||||
|
||||
/* locals */
|
||||
static hash_FlowTable FlowTable;
|
||||
static int initialised = 0;
|
||||
uint32_t loopcnt = 0;
|
||||
|
||||
typedef struct aggregate_param_s {
|
||||
uint32_t size; // size of parameter in bytes
|
||||
uint32_t offset; // offset in master record
|
||||
uint64_t mask; // mask for this value in master record
|
||||
uint64_t shift; // bis shift for this value in master record
|
||||
} aggregate_param_t;
|
||||
|
||||
static struct aggregate_info_s {
|
||||
char *aggregate_token; // name of aggregation parameter
|
||||
aggregate_param_t param; // the parameter array
|
||||
int merge; // apply bis mask? => -1 no, otherwise index of mask[] array
|
||||
int active; // is this parameter set?
|
||||
char *fmt; // for automatic output format generation
|
||||
} aggregate_info [] = {
|
||||
{ "srcip4", { 8, OffsetSrcIPv6a, MaskIPv6, ShiftIPv6 }, 0, 0, "%sa" },
|
||||
{ "srcip4", { 8, OffsetSrcIPv6b, MaskIPv6, ShiftIPv6 }, 1, 0, NULL },
|
||||
{ "srcip6", { 8, OffsetSrcIPv6a, MaskIPv6, ShiftIPv6 }, 0, 0, "%sa" },
|
||||
{ "srcip6", { 8, OffsetSrcIPv6b, MaskIPv6, ShiftIPv6 }, 1, 0, NULL },
|
||||
{ "srcnet", { 8, OffsetSrcIPv6a, MaskIPv6, ShiftIPv6 }, -1, 0, "%sn" },
|
||||
{ "srcnet", { 8, OffsetSrcIPv6b, MaskIPv6, ShiftIPv6 }, -1, 0, NULL },
|
||||
{ "dstnet", { 8, OffsetDstIPv6a, MaskIPv6, ShiftIPv6 }, -1, 0, "%dn" },
|
||||
{ "dstnet", { 8, OffsetDstIPv6b, MaskIPv6, ShiftIPv6 }, -1, 0, NULL },
|
||||
{ "srcip", { 8, OffsetSrcIPv6a, MaskIPv6, ShiftIPv6 }, -1, 0, "%sa" },
|
||||
{ "srcip", { 8, OffsetSrcIPv6b, MaskIPv6, ShiftIPv6 }, -1, 0, NULL },
|
||||
{ "dstip", { 8, OffsetDstIPv6a, MaskIPv6, ShiftIPv6 }, -1, 0, "%da" },
|
||||
{ "dstip", { 8, OffsetDstIPv6b, MaskIPv6, ShiftIPv6 }, -1, 0, NULL },
|
||||
{ "dstip4", { 8, OffsetDstIPv6a, MaskIPv6, ShiftIPv6 }, 0, 0, "%da" },
|
||||
{ "dstip4", { 8, OffsetDstIPv6b, MaskIPv6, ShiftIPv6 }, 1, 0, NULL },
|
||||
{ "dstip6", { 8, OffsetDstIPv6a, MaskIPv6, ShiftIPv6 }, 0, 0, "%da" },
|
||||
{ "dstip6", { 8, OffsetDstIPv6b, MaskIPv6, ShiftIPv6 }, 1, 0, NULL },
|
||||
{ "next", { 8, OffsetNexthopv6a, MaskIPv6, ShiftIPv6 }, -1, 0, "%nh" },
|
||||
{ "next", { 8, OffsetNexthopv6b, MaskIPv6, ShiftIPv6 }, -1, 0, NULL },
|
||||
{ "bgpnext", { 8, OffsetBGPNexthopv6a, MaskIPv6, ShiftIPv6 }, -1, 0, "%nhb" },
|
||||
{ "bgpnext", { 8, OffsetBGPNexthopv6b, MaskIPv6, ShiftIPv6 }, -1, 0, NULL },
|
||||
{ "router", { 8, OffsetRouterv6a, MaskIPv6, ShiftIPv6 }, -1, 0, "%ra" },
|
||||
{ "router", { 8, OffsetRouterv6b, MaskIPv6, ShiftIPv6 }, -1, 0, NULL },
|
||||
{ "insrcmac", { 8, OffsetInSrcMAC, MaskMac, ShiftIPv6 }, -1, 0, "%ismc" },
|
||||
{ "outdstmac", { 8, OffsetOutDstMAC, MaskMac, ShiftIPv6 }, -1, 0, "%odmc" },
|
||||
{ "indstmac", { 8, OffsetInDstMAC, MaskMac, ShiftIPv6 }, -1, 0, "%idmc" },
|
||||
{ "outsrcmac", { 8, OffsetOutSrcMAC, MaskMac, ShiftIPv6 }, -1, 0, "%osmc" },
|
||||
{ "srcas", { 4, OffsetAS, MaskSrcAS, ShiftSrcAS }, -1, 0, "%sas" },
|
||||
{ "dstas", { 4, OffsetAS, MaskDstAS, ShiftDstAS }, -1, 0, "%das" },
|
||||
{ "nextas", { 4, OffsetBGPadj, MaskBGPadjNext, ShiftBGPadjNext }, -1, 0, "%nas" },
|
||||
{ "prevas", { 4, OffsetBGPadj, MaskBGPadjPrev, ShiftBGPadjPrev }, -1, 0, "%pas" },
|
||||
{ "inif", { 4, OffsetInOut, MaskInput, ShiftInput }, -1, 0, "%in" },
|
||||
{ "outif", { 4, OffsetInOut, MaskOutput, ShiftOutput }, -1, 0, "%out" },
|
||||
{ "mpls1", { 4, OffsetMPLS12, MaskMPLSlabelOdd, ShiftMPLSlabelOdd }, -1, 0, "%mpls1"},
|
||||
{ "mpls2", { 4, OffsetMPLS12, MaskMPLSlabelEven, ShiftMPLSlabelEven }, -1, 0, "%mpls2"},
|
||||
{ "mpls3", { 4, OffsetMPLS34, MaskMPLSlabelOdd, ShiftMPLSlabelOdd }, -1, 0, "%mpls3"},
|
||||
{ "mpls4", { 4, OffsetMPLS34, MaskMPLSlabelEven, ShiftMPLSlabelEven }, -1, 0, "%mpls4"},
|
||||
{ "mpls5", { 4, OffsetMPLS56, MaskMPLSlabelOdd, ShiftMPLSlabelOdd }, -1, 0, "%mpls5"},
|
||||
{ "mpls6", { 4, OffsetMPLS56, MaskMPLSlabelEven, ShiftMPLSlabelEven }, -1, 0, "%mpls6"},
|
||||
{ "mpls7", { 4, OffsetMPLS78, MaskMPLSlabelOdd, ShiftMPLSlabelOdd }, -1, 0, "%mpls7"},
|
||||
{ "mpls8", { 4, OffsetMPLS78, MaskMPLSlabelEven, ShiftMPLSlabelEven }, -1, 0, "%mpls8"},
|
||||
{ "mpls9", { 4, OffsetMPLS910, MaskMPLSlabelOdd, ShiftMPLSlabelOdd }, -1, 0, "%mpls9"},
|
||||
{ "mpls10", { 4, OffsetMPLS910, MaskMPLSlabelEven, ShiftMPLSlabelEven }, -1, 0, "%mpls10"},
|
||||
{ "srcport", { 2, OffsetPort, MaskSrcPort, ShiftSrcPort }, -1, 0, "%sp" },
|
||||
{ "dstport", { 2, OffsetPort, MaskDstPort, ShiftDstPort }, -1, 0, "%dp" },
|
||||
{ "srcvlan", { 2, OffsetVlan, MaskSrcVlan, ShiftSrcVlan }, -1, 0, "%svln" },
|
||||
{ "dstvlan", { 2, OffsetVlan, MaskDstVlan, ShiftDstVlan }, -1, 0, "%dvln" },
|
||||
{ "srcmask", { 1, OffsetMask, MaskSrcMask, ShiftSrcMask }, -1, 0, "%smk" },
|
||||
{ "dstmask", { 1, OffsetMask, MaskDstMask, ShiftDstMask }, -1, 0, "%dmk" },
|
||||
{ "proto", { 1, OffsetProto, MaskProto, ShiftProto }, -1, 0, "%pr" },
|
||||
{ "tos", { 1, OffsetTos, MaskTos, ShiftTos }, -1, 0, "%tos" },
|
||||
{ "srctos", { 1, OffsetTos, MaskTos, ShiftTos }, -1, 0, "%stos" },
|
||||
{ "dsttos", { 1, OffsetDstTos, MaskDstTos, ShiftDstTos }, -1, 0, "%dtos" },
|
||||
{ NULL, { 0, 0, 0, 0}, 0, 0, NULL}
|
||||
};
|
||||
|
||||
typedef struct Default_key_s {
|
||||
uint16_t srcport;
|
||||
uint16_t dstport;
|
||||
uint64_t srcaddr[2];
|
||||
uint64_t dstaddr[2];
|
||||
uint32_t proto;
|
||||
} Default_key_t;
|
||||
|
||||
|
||||
static aggregate_param_t *aggregate_stack = NULL;
|
||||
static uint32_t aggregate_key_len = sizeof(Default_key_t);
|
||||
static uint32_t bidir_flows = 0;
|
||||
|
||||
// counter indices
|
||||
// The array size of FlowTableRecord_t array counter must match.
|
||||
enum CNT_IND { FLOWS = 0, INPACKETS, INBYTES, OUTPACKETS, OUTBYTES };
|
||||
|
||||
#include "applybits_inline.c"
|
||||
|
||||
/* Functions */
|
||||
|
||||
static inline int TimeMsec_CMP(time_t t1, uint16_t offset1, time_t t2, uint16_t offset2 ) {
|
||||
if ( t1 > t2 )
|
||||
return 1;
|
||||
if ( t2 > t1 )
|
||||
return 2;
|
||||
// else t1 == t2 - offset is now relevant
|
||||
if ( offset1 > offset2 )
|
||||
return 1;
|
||||
if ( offset2 > offset1 )
|
||||
return 2;
|
||||
else
|
||||
// both times are the same
|
||||
return 0;
|
||||
} // End of TimeMsec_CMP
|
||||
|
||||
static int MemoryHandle_init(MemoryHandle_t *handle) {
|
||||
|
||||
handle->memblock = (void **)calloc(MaxMemBlocks, sizeof(void *));
|
||||
if ( !handle->memblock ) {
|
||||
fprintf(stderr, "malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
handle->BlockSize = MemBlockSize;
|
||||
|
||||
handle->memblock[0] = malloc(MemBlockSize);
|
||||
handle->MaxBlocks = MaxMemBlocks;
|
||||
handle->NumBlocks = 1;
|
||||
handle->CurrentBlock = 0;
|
||||
handle->Allocted = 0;
|
||||
|
||||
return 1;
|
||||
|
||||
} // End of MemoryHandle_init
|
||||
|
||||
static void MemoryHandle_free(MemoryHandle_t *handle) {
|
||||
int i;
|
||||
|
||||
dbg_printf("MEM: NumBlocks: %u\n", handle->NumBlocks);
|
||||
for ( i=0; i < handle->NumBlocks; i++ ) {
|
||||
free(handle->memblock[i]);
|
||||
}
|
||||
handle->NumBlocks = 0;
|
||||
handle->CurrentBlock = 0;
|
||||
handle->Allocted = 0;
|
||||
|
||||
free((void *)handle->memblock);
|
||||
handle->memblock = NULL;
|
||||
handle->MaxBlocks = 0;
|
||||
|
||||
} // End of MemoryHandle_free
|
||||
|
||||
static inline void *MemoryHandle_get(MemoryHandle_t *handle, uint32_t size) {
|
||||
void *p;
|
||||
uint32_t aligned_size;
|
||||
|
||||
// make sure size of memory is aligned
|
||||
aligned_size = (((u_int)(size) + ALIGN_BYTES) &~ ALIGN_BYTES);
|
||||
|
||||
if ( (handle->Allocted+aligned_size) > MemBlockSize ) {
|
||||
// not enough space - allocate a new memblock
|
||||
|
||||
handle->CurrentBlock++;
|
||||
if ( handle->CurrentBlock >= handle->MaxBlocks ) {
|
||||
// we run out in memblock array - re-allocate memblock array
|
||||
handle->MaxBlocks += MaxMemBlocks;
|
||||
handle->memblock = (void **)realloc(handle->memblock, handle->MaxBlocks * sizeof(void *));
|
||||
if ( !handle->memblock ) {
|
||||
fprintf(stderr, "realloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno));
|
||||
exit(255);
|
||||
}
|
||||
}
|
||||
|
||||
// allocate new memblock
|
||||
p = malloc(MemBlockSize);
|
||||
if ( !p ) {
|
||||
fprintf(stderr, "malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno));
|
||||
exit(255);
|
||||
}
|
||||
handle->memblock[handle->CurrentBlock] = p;
|
||||
// reset counter for new memblock
|
||||
handle->Allocted = 0;
|
||||
handle->NumBlocks++;
|
||||
}
|
||||
|
||||
// enough space available in current memblock
|
||||
p = handle->memblock[handle->CurrentBlock] + handle->Allocted;
|
||||
handle->Allocted += aligned_size;
|
||||
dbg_printf("Mem Handle: Requested: %u, aligned: %u, ptr: %lu\n", size, aligned_size, (long unsigned)p);
|
||||
return p;
|
||||
|
||||
} // End of MemoryHandle_get
|
||||
|
||||
hash_FlowTable *GetFlowTable(void) {
|
||||
return &FlowTable;
|
||||
} // End of GetFlowTable
|
||||
|
||||
int Init_FlowTable(void) {
|
||||
uint32_t maxindex;
|
||||
|
||||
maxindex = (1 << HashBits);
|
||||
FlowTable.IndexMask = maxindex -1;
|
||||
FlowTable.NumBits = HashBits;
|
||||
FlowTable.NumRecords = 0;
|
||||
FlowTable.bucket = (FlowTableRecord_t **)calloc(maxindex, sizeof(FlowTableRecord_t *));
|
||||
FlowTable.bucketcache = (FlowTableRecord_t **)calloc(maxindex, sizeof(FlowTableRecord_t *));
|
||||
if ( !FlowTable.bucket || !FlowTable.bucketcache ) {
|
||||
fprintf(stderr, "malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
FlowTable.keysize = aggregate_key_len;
|
||||
|
||||
// keylen = number of uint64_t
|
||||
FlowTable.keylen = aggregate_key_len >> 3; // aggregate_key_len / 8
|
||||
if ( (aggregate_key_len & 0x7 ) != 0 )
|
||||
FlowTable.keylen++;
|
||||
|
||||
dbg_printf("FlowTable.keysize %i bytes\n", FlowTable.keysize);
|
||||
dbg_printf("FlowTable.keylen %i uint64_t\n", FlowTable.keylen);
|
||||
|
||||
if ( !MemoryHandle_init(&FlowTable.mem) )
|
||||
return 0;
|
||||
|
||||
initialised = 1;
|
||||
return 1;
|
||||
|
||||
} // End of Init_FlowTable
|
||||
|
||||
|
||||
void Dispose_FlowTable(void) {
|
||||
|
||||
if ( !initialised )
|
||||
return;
|
||||
free((void *)FlowTable.bucket);
|
||||
free((void *)FlowTable.bucketcache);
|
||||
MemoryHandle_free(&FlowTable.mem);
|
||||
FlowTable.NumRecords = 0;
|
||||
FlowTable.bucket = NULL;
|
||||
FlowTable.bucketcache = NULL;
|
||||
|
||||
} // End of Dispose_FlowTable
|
||||
|
||||
|
||||
static inline FlowTableRecord_t *hash_lookup_FlowTable(uint32_t *index_cache, void *flowkey, master_record_t *flow_record) {
|
||||
uint32_t index;
|
||||
int bsize;
|
||||
FlowTableRecord_t *record;
|
||||
|
||||
*index_cache = SuperFastHash((char *)flowkey, FlowTable.keysize);
|
||||
index = *index_cache & FlowTable.IndexMask;
|
||||
|
||||
if ( FlowTable.bucket[index] == NULL ) {
|
||||
hash_hit++;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
record = FlowTable.bucket[index];
|
||||
|
||||
// skip records with different hash value ( full 32bit )
|
||||
while ( record )
|
||||
if ( record->hash != *index_cache ) {
|
||||
hash_skip++;
|
||||
record = record->next;
|
||||
} else
|
||||
break;
|
||||
|
||||
bsize = 0;
|
||||
while ( record ) {
|
||||
uint64_t *k1 = (uint64_t *)flowkey;
|
||||
uint64_t *k2 = (uint64_t *)record->hash_key;
|
||||
int i;
|
||||
|
||||
// compare key and break as soon as keys do not match
|
||||
i = 0;
|
||||
while ( i < FlowTable.keylen ) {
|
||||
if ( k1[i] == k2[i] )
|
||||
i++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
loopcnt += i;
|
||||
|
||||
if ( i == FlowTable.keylen ) {
|
||||
// hit - record found
|
||||
|
||||
// some stats for debugging
|
||||
if ( bsize == 0 )
|
||||
hash_hit++;
|
||||
else
|
||||
hash_miss++;
|
||||
return record;
|
||||
}
|
||||
|
||||
record = record->next;
|
||||
bsize++;
|
||||
}
|
||||
return NULL;
|
||||
|
||||
} // End of hash_lookup_FlowTable
|
||||
|
||||
|
||||
inline static FlowTableRecord_t *hash_insert_FlowTable(uint32_t index_cache, void *flowkey, common_record_t *raw_record) {
|
||||
FlowTableRecord_t *record;
|
||||
uint32_t index = index_cache & FlowTable.IndexMask;
|
||||
|
||||
// allocate enough memory for the new flow including all additional information in FlowTableRecord_t
|
||||
// MemoryHandle_get always succeeds. If no memory, MemoryHandle_get already exists cleanly
|
||||
record = MemoryHandle_get(&FlowTable.mem, sizeof(FlowTableRecord_t) - sizeof(common_record_t) + raw_record->size);
|
||||
|
||||
record->next = NULL;
|
||||
record->hash = index_cache;
|
||||
record->hash_key = flowkey;
|
||||
|
||||
memcpy((void *)&record->flowrecord, (void *)raw_record, raw_record->size);
|
||||
if ( FlowTable.bucket[index] == NULL )
|
||||
FlowTable.bucket[index] = record;
|
||||
else
|
||||
FlowTable.bucketcache[index]->next = record;
|
||||
|
||||
FlowTable.bucketcache[index] = record;
|
||||
FlowTable.NumRecords++;
|
||||
|
||||
return record;
|
||||
|
||||
} // End of hash_insert_FlowTable
|
||||
|
||||
void InsertFlow(common_record_t *raw_record, master_record_t *flow_record, extension_info_t *extension_info) {
|
||||
FlowTableRecord_t *record;
|
||||
|
||||
// allocate enough memory for the new flow including all additional information in FlowTableRecord_t
|
||||
// MemoryHandle_get always succeeds. If no memory, MemoryHandle_get already exits cleanly
|
||||
record = MemoryHandle_get(&FlowTable.mem, sizeof(FlowTableRecord_t) - sizeof(common_record_t) + raw_record->size);
|
||||
|
||||
record->next = NULL;
|
||||
record->hash = 0;
|
||||
record->hash_key = NULL;
|
||||
|
||||
memcpy((void *)&record->flowrecord, (void *)raw_record, raw_record->size);
|
||||
if ( FlowTable.bucket[0] == NULL )
|
||||
FlowTable.bucket[0] = record;
|
||||
else
|
||||
FlowTable.bucketcache[0]->next = record;
|
||||
|
||||
FlowTable.bucketcache[0] = record;
|
||||
|
||||
// safe the extension map and exporter reference
|
||||
record->map_info_ref = extension_info;
|
||||
record->exp_ref = flow_record->exp_ref;
|
||||
|
||||
record->counter[INBYTES] = flow_record->dOctets;
|
||||
record->counter[INPACKETS] = flow_record->dPkts;
|
||||
record->counter[OUTBYTES] = flow_record->out_bytes;
|
||||
record->counter[OUTPACKETS] = flow_record->out_pkts;
|
||||
record->counter[FLOWS] = flow_record->aggr_flows ? flow_record->aggr_flows : 1;
|
||||
FlowTable.NumRecords++;
|
||||
|
||||
} // End of InsertFlow
|
||||
|
||||
|
||||
|
||||
void AddFlow(common_record_t *raw_record, master_record_t *flow_record, extension_info_t *extension_info ) {
|
||||
static void *keymem = NULL, *bidirkeymem = NULL;
|
||||
FlowTableRecord_t *FlowTableRecord;
|
||||
uint32_t index_cache;
|
||||
|
||||
if ( keymem == NULL ) {
|
||||
keymem = MemoryHandle_get(&FlowTable.mem ,FlowTable.keysize );
|
||||
// the last aligned word may not be fully used. set it to 0 to guarantee
|
||||
// a proper comarison
|
||||
|
||||
// for 64 bit arch int == 8 bytes otherwise 4
|
||||
((int *)keymem)[FlowTable.keylen-1] = 0;
|
||||
|
||||
}
|
||||
|
||||
New_Hash_Key(keymem, flow_record, 0);
|
||||
|
||||
// Update netflow statistics
|
||||
FlowTableRecord = hash_lookup_FlowTable(&index_cache, keymem, flow_record);
|
||||
if ( FlowTableRecord ) {
|
||||
// flow record found - best case! update all fields
|
||||
FlowTableRecord->counter[INBYTES] += flow_record->dOctets;
|
||||
FlowTableRecord->counter[INPACKETS] += flow_record->dPkts;
|
||||
FlowTableRecord->counter[OUTBYTES] += flow_record->out_bytes;
|
||||
FlowTableRecord->counter[OUTPACKETS] += flow_record->out_pkts;
|
||||
|
||||
if ( TimeMsec_CMP(flow_record->first, flow_record->msec_first,
|
||||
FlowTableRecord->flowrecord.first, FlowTableRecord->flowrecord.msec_first) == 2) {
|
||||
FlowTableRecord->flowrecord.first = flow_record->first;
|
||||
FlowTableRecord->flowrecord.msec_first = flow_record->msec_first;
|
||||
}
|
||||
if ( TimeMsec_CMP(flow_record->last, flow_record->msec_last,
|
||||
FlowTableRecord->flowrecord.last, FlowTableRecord->flowrecord.msec_last) == 1) {
|
||||
FlowTableRecord->flowrecord.last = flow_record->last;
|
||||
FlowTableRecord->flowrecord.msec_last = flow_record->msec_last;
|
||||
}
|
||||
|
||||
FlowTableRecord->counter[FLOWS] += flow_record->aggr_flows ? flow_record->aggr_flows : 1;
|
||||
FlowTableRecord->flowrecord.tcp_flags |= flow_record->tcp_flags;
|
||||
|
||||
} else if ( !bidir_flows || ( flow_record->prot != IPPROTO_TCP && flow_record->prot != IPPROTO_UDP) ) {
|
||||
// no flow record found and no TCP/UDP bidir flows. Insert flow record into hash
|
||||
FlowTableRecord = hash_insert_FlowTable(index_cache, keymem, raw_record);
|
||||
|
||||
FlowTableRecord->counter[INBYTES] = flow_record->dOctets;
|
||||
FlowTableRecord->counter[INPACKETS] = flow_record->dPkts;
|
||||
FlowTableRecord->counter[OUTBYTES] = flow_record->out_bytes;
|
||||
FlowTableRecord->counter[OUTPACKETS] = flow_record->out_pkts;
|
||||
FlowTableRecord->counter[FLOWS] = flow_record->aggr_flows ? flow_record->aggr_flows : 1;
|
||||
|
||||
FlowTableRecord->map_info_ref = extension_info;
|
||||
FlowTableRecord->exp_ref = flow_record->exp_ref;
|
||||
|
||||
// keymen got part of the cache
|
||||
keymem = NULL;
|
||||
} else {
|
||||
// for bidir flows do
|
||||
uint32_t bidir_index_cache;
|
||||
|
||||
// use tmp memory for bidir hash key to search for bidir flow
|
||||
// we need it only to lookup
|
||||
if ( bidirkeymem == NULL ) {
|
||||
bidirkeymem = MemoryHandle_get(&FlowTable.mem ,FlowTable.keysize );
|
||||
// the last aligned word may not be fully used. set it to 0 to guarantee
|
||||
// a proper comarison
|
||||
|
||||
// for 64 bit arch int == 8 bytes otherwise 4
|
||||
((int *)bidirkeymem)[FlowTable.keylen-1] = 0;
|
||||
}
|
||||
|
||||
// generate the hash key for reverse record (bidir)
|
||||
New_Hash_Key(bidirkeymem, flow_record, 1);
|
||||
FlowTableRecord = hash_lookup_FlowTable(&bidir_index_cache, bidirkeymem, flow_record);
|
||||
if ( FlowTableRecord ) {
|
||||
// we found a corresponding flow - so update all fields in reverse direction
|
||||
FlowTableRecord->counter[OUTBYTES] += flow_record->dOctets;
|
||||
FlowTableRecord->counter[OUTPACKETS] += flow_record->dPkts;
|
||||
FlowTableRecord->counter[INBYTES] += flow_record->out_bytes;
|
||||
FlowTableRecord->counter[INPACKETS] += flow_record->out_pkts;
|
||||
|
||||
if ( TimeMsec_CMP(flow_record->first, flow_record->msec_first,
|
||||
FlowTableRecord->flowrecord.first, FlowTableRecord->flowrecord.msec_first) == 2) {
|
||||
FlowTableRecord->flowrecord.first = flow_record->first;
|
||||
FlowTableRecord->flowrecord.msec_first = flow_record->msec_first;
|
||||
}
|
||||
if ( TimeMsec_CMP(flow_record->last, flow_record->msec_last,
|
||||
FlowTableRecord->flowrecord.last, FlowTableRecord->flowrecord.msec_last) == 1) {
|
||||
FlowTableRecord->flowrecord.last = flow_record->last;
|
||||
FlowTableRecord->flowrecord.msec_last = flow_record->msec_last;
|
||||
}
|
||||
|
||||
FlowTableRecord->counter[FLOWS] += flow_record->aggr_flows ? flow_record->aggr_flows : 1;
|
||||
FlowTableRecord->flowrecord.tcp_flags |= flow_record->tcp_flags;
|
||||
} else {
|
||||
// no bidir flow found
|
||||
// insert original flow into the cache
|
||||
FlowTableRecord = hash_insert_FlowTable(index_cache, keymem, raw_record);
|
||||
|
||||
FlowTableRecord->counter[INBYTES] = flow_record->dOctets;
|
||||
FlowTableRecord->counter[INPACKETS] = flow_record->dPkts;
|
||||
FlowTableRecord->counter[OUTBYTES] = flow_record->out_bytes;
|
||||
FlowTableRecord->counter[OUTPACKETS] = flow_record->out_pkts;
|
||||
FlowTableRecord->counter[FLOWS] = flow_record->aggr_flows ? flow_record->aggr_flows : 1;
|
||||
FlowTableRecord->map_info_ref = extension_info;
|
||||
FlowTableRecord->exp_ref = flow_record->exp_ref;
|
||||
|
||||
keymem = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // End of AddFlow
|
||||
|
||||
|
||||
#undef get16bits
|
||||
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
|
||||
|| defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
|
||||
#define get16bits(d) (*((const uint16_t *) (d)))
|
||||
#endif
|
||||
|
||||
#if !defined (get16bits)
|
||||
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
|
||||
+(uint32_t)(((const uint8_t *)(d))[0]) )
|
||||
#endif
|
||||
|
||||
static inline uint32_t SuperFastHash (const char * data, int len) {
|
||||
uint32_t hash = len, tmp;
|
||||
int rem;
|
||||
|
||||
if (len <= 0 || data == NULL) return 0;
|
||||
|
||||
rem = len & 3;
|
||||
len >>= 2;
|
||||
|
||||
/* Main loop */
|
||||
for (;len > 0; len--) {
|
||||
hash += get16bits (data);
|
||||
tmp = (get16bits (data+2) << 11) ^ hash;
|
||||
hash = (hash << 16) ^ tmp;
|
||||
data += 2*sizeof (uint16_t);
|
||||
hash += hash >> 11;
|
||||
}
|
||||
|
||||
/* Handle end cases */
|
||||
switch (rem) {
|
||||
case 3: hash += get16bits (data);
|
||||
hash ^= hash << 16;
|
||||
hash ^= data[sizeof (uint16_t)] << 18;
|
||||
hash += hash >> 11;
|
||||
break;
|
||||
case 2: hash += get16bits (data);
|
||||
hash ^= hash << 11;
|
||||
hash += hash >> 17;
|
||||
break;
|
||||
case 1: hash += *data;
|
||||
hash ^= hash << 10;
|
||||
hash += hash >> 1;
|
||||
}
|
||||
|
||||
/* Force "avalanching" of final 127 bits */
|
||||
hash ^= hash << 3;
|
||||
hash += hash >> 5;
|
||||
hash ^= hash << 4;
|
||||
hash += hash >> 17;
|
||||
hash ^= hash << 25;
|
||||
hash += hash >> 6;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
int SetBidirAggregation(void) {
|
||||
|
||||
if ( aggregate_stack ) {
|
||||
fprintf(stderr, "Can not set bidir mode while custom aggregation is set.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bidir_flows = 1;
|
||||
|
||||
return 1;
|
||||
|
||||
} // End of SetBidirAggregation
|
||||
|
||||
int ParseAggregateMask( char *arg, char **aggr_fmt ) {
|
||||
char *p, *q;
|
||||
uint64_t mask[2];
|
||||
uint32_t subnet, stack_count;
|
||||
int i, fmt_len, has_mask;
|
||||
struct aggregate_info_s *a;
|
||||
|
||||
|
||||
if ( bidir_flows ) {
|
||||
fprintf(stderr, "Can not set custom aggregation while bidir mode is set.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
stack_count = 0;
|
||||
subnet = 0;
|
||||
has_mask = 0;
|
||||
|
||||
aggregate_key_len = 0;
|
||||
|
||||
fmt_len = 0;
|
||||
i = 0;
|
||||
while ( aggregate_info[i].aggregate_token != NULL ) {
|
||||
if ( aggregate_info[i].active )
|
||||
stack_count++;
|
||||
if ( aggregate_info[i].fmt )
|
||||
fmt_len += ( strlen(aggregate_info[i].fmt) + 1 );
|
||||
i++;
|
||||
}
|
||||
fmt_len++; // trailing '\0'
|
||||
|
||||
if ( !*aggr_fmt ) {
|
||||
*aggr_fmt = malloc(fmt_len);
|
||||
(*aggr_fmt)[0] = '\0';
|
||||
}
|
||||
if ( !*aggr_fmt ) {
|
||||
fprintf(stderr, "malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
FlowTable.apply_netbits = 0;
|
||||
FlowTable.has_masks = 0;
|
||||
FlowTable.IPmask[0] = 0xffffffffffffffffLL;;
|
||||
FlowTable.IPmask[1] = 0xffffffffffffffffLL;;
|
||||
FlowTable.IPmask[2] = 0xffffffffffffffffLL;;
|
||||
FlowTable.IPmask[3] = 0xffffffffffffffffLL;;
|
||||
|
||||
// separate tokens
|
||||
p = strtok(arg, ",");
|
||||
while ( p ) {
|
||||
|
||||
// check for subnet bits
|
||||
q = strchr(p, '/');
|
||||
if ( q ) {
|
||||
char *n;
|
||||
|
||||
has_mask = 1;
|
||||
|
||||
*q = 0;
|
||||
subnet = atoi(q+1);
|
||||
|
||||
// get IP version
|
||||
n = &(p[strlen(p)-1]);
|
||||
if ( *n == '4' ) {
|
||||
// IPv4
|
||||
if ( subnet < 1 || subnet > 32 ) {
|
||||
fprintf(stderr, "Subnet specifier '%s' out of range for IPv4\n", q+1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mask[0] = 0xffffffffffffffffLL;
|
||||
mask[1] = 0xffffffffffffffffLL << ( 32 - subnet );
|
||||
|
||||
} else if ( *n == '6' ) {
|
||||
// IPv6
|
||||
if ( subnet < 1 || subnet > 128 ) {
|
||||
fprintf(stderr, "Subnet specifier '%s' out of range for IPv6\n", q+1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( subnet > 64 ) {
|
||||
mask[0] = 0xffffffffffffffffLL;
|
||||
mask[1] = 0xffffffffffffffffLL << ( 64 - subnet );
|
||||
} else {
|
||||
mask[0] = 0xffffffffffffffffLL << ( 64 - subnet );
|
||||
mask[1] = 0;
|
||||
}
|
||||
} else {
|
||||
// rubbish
|
||||
*q = '/';
|
||||
fprintf(stderr, "Need src4/dst4 src6/dst6 for IPv4 or IPv6 to aggregate with explicit netmask: '%s'\n", p);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
has_mask = 0;
|
||||
}
|
||||
|
||||
a = aggregate_info;
|
||||
while ( a->aggregate_token && (strcasecmp(p, a->aggregate_token ) != 0) )
|
||||
a++;
|
||||
|
||||
if ( a->active ) {
|
||||
fprintf(stderr, "Skip already given aggregation mask: %s\n", p);
|
||||
} else if ( a->aggregate_token != NULL ) {
|
||||
|
||||
if ( a->fmt != NULL ) {
|
||||
strncat(*aggr_fmt, a->fmt, fmt_len);
|
||||
fmt_len -= strlen(a->fmt);
|
||||
strncat(*aggr_fmt, " ", fmt_len);
|
||||
fmt_len -= 1;
|
||||
}
|
||||
|
||||
if ( strcasecmp(p, "srcnet" ) == 0 ) {
|
||||
FlowTable.apply_netbits |= 1;
|
||||
}
|
||||
if ( strcasecmp(p, "dstnet" ) == 0 ) {
|
||||
FlowTable.apply_netbits |= 2;
|
||||
}
|
||||
|
||||
do {
|
||||
int i = a->merge;
|
||||
if ( i != -1 ) {
|
||||
if ( has_mask ) {
|
||||
a->param.mask = mask[i];
|
||||
} else {
|
||||
fprintf(stderr, "'%s' needs subnet bits too aggregate\n", p);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if ( has_mask ) {
|
||||
fprintf(stderr, "'%s' No subnet bits allowed here!\n", p);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
a->active = 1;
|
||||
aggregate_key_len += a->param.size;
|
||||
stack_count++;
|
||||
a++;
|
||||
} while (a->aggregate_token && (strcasecmp(p, a->aggregate_token ) == 0));
|
||||
|
||||
if ( has_mask ) {
|
||||
FlowTable.has_masks = 1;
|
||||
switch (p[0]) {
|
||||
case 's':
|
||||
FlowTable.IPmask[0] = mask[0];
|
||||
FlowTable.IPmask[1] = mask[1];
|
||||
break;
|
||||
case 'd':
|
||||
FlowTable.IPmask[2] = mask[0];
|
||||
FlowTable.IPmask[3] = mask[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Unknown aggregation specifier '%s'\n", p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = strtok(NULL, ",");
|
||||
}
|
||||
|
||||
if ( stack_count == 0 ) {
|
||||
fprintf(stderr, "No aggregation specified!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
aggregate_stack = (aggregate_param_t *)malloc((stack_count+1) * sizeof(aggregate_param_t));
|
||||
|
||||
stack_count = 0;
|
||||
a = aggregate_info;
|
||||
while ( a->aggregate_token ) {
|
||||
if ( a->active ) {
|
||||
aggregate_stack[stack_count++] = a->param;
|
||||
dbg_printf("Set aggregate param: %s\n", a->aggregate_token);
|
||||
}
|
||||
a++;
|
||||
}
|
||||
// final '0' record
|
||||
aggregate_stack[stack_count] = a->param;
|
||||
|
||||
dbg_printf("Aggregate key len: %i bytes\n", aggregate_key_len);
|
||||
dbg_printf("Aggregate format string: '%s'\n", *aggr_fmt);
|
||||
|
||||
#ifdef DEVEL
|
||||
if ( aggregate_stack ) {
|
||||
aggregate_param_t *aggr_param = aggregate_stack;
|
||||
printf("Aggregate stack:\n");
|
||||
while ( aggr_param->size ) {
|
||||
printf("Offset: %u, Mask: %llx, Shift: %llu\n", aggr_param->offset,
|
||||
(long long unsigned)aggr_param->mask, (long long unsigned)aggr_param->shift);
|
||||
aggr_param++;
|
||||
} // while
|
||||
}
|
||||
printf("Has IP mask: %i %i\n", has_mask, FlowTable.has_masks);
|
||||
printf("Mask 0: 0x%llx\n", (unsigned long long)FlowTable.IPmask[0]);
|
||||
printf("Mask 1: 0x%llx\n", (unsigned long long)FlowTable.IPmask[1]);
|
||||
printf("Mask 2: 0x%llx\n", (unsigned long long)FlowTable.IPmask[2]);
|
||||
printf("Mask 3: 0x%llx\n", (unsigned long long)FlowTable.IPmask[3]);
|
||||
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
} // End of ParseAggregateMask
|
||||
|
||||
master_record_t *GetMasterAggregateMask(void) {
|
||||
master_record_t *aggr_record_mask;
|
||||
|
||||
if ( aggregate_stack ) {
|
||||
uint64_t *r;
|
||||
aggregate_param_t *aggr_param = aggregate_stack;
|
||||
|
||||
aggr_record_mask = (master_record_t *)malloc(sizeof(master_record_t));
|
||||
if ( !aggr_record_mask ) {
|
||||
fprintf(stderr, "malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = (uint64_t *)aggr_record_mask;
|
||||
memset((void *)aggr_record_mask, 0, sizeof(master_record_t));
|
||||
while ( aggr_param->size ) {
|
||||
int offset = aggr_param->offset;
|
||||
r[offset] |= aggr_param->mask;
|
||||
aggr_param++;
|
||||
}
|
||||
|
||||
// not really needed, but preset it anyway
|
||||
r[0] = 0xffffffffffffffffLL;
|
||||
r[1] = 0xffffffffffffffffLL;
|
||||
aggr_record_mask->dPkts = 0xffffffffffffffffLL;
|
||||
aggr_record_mask->dOctets = 0xffffffffffffffffLL;
|
||||
aggr_record_mask->out_pkts = 0xffffffffffffffffLL;
|
||||
aggr_record_mask->out_bytes = 0xffffffffffffffffLL;
|
||||
aggr_record_mask->aggr_flows = 0xffffffffffffffffLL;
|
||||
aggr_record_mask->last = 0xffffffff;
|
||||
|
||||
return aggr_record_mask;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // End of GetMasterAggregateMask
|
||||
|
||||
static inline void New_Hash_Key(void *keymem, master_record_t *flow_record, int swap_flow) {
|
||||
uint64_t *record = (uint64_t *)flow_record;
|
||||
Default_key_t *keyptr;
|
||||
|
||||
// apply src/dst mask bits if requested
|
||||
if ( FlowTable.apply_netbits ) {
|
||||
ApplyNetMaskBits(flow_record, FlowTable.apply_netbits);
|
||||
}
|
||||
|
||||
if ( aggregate_stack ) {
|
||||
// custom user aggregation
|
||||
aggregate_param_t *aggr_param = aggregate_stack;
|
||||
while ( aggr_param->size ) {
|
||||
uint64_t val = (record[aggr_param->offset] & aggr_param->mask) >> aggr_param->shift;
|
||||
|
||||
switch ( aggr_param->size ) {
|
||||
case 8: {
|
||||
uint64_t *_v = (uint64_t *)keymem;
|
||||
*_v = val;
|
||||
keymem += sizeof(uint64_t);
|
||||
} break;
|
||||
case 4: {
|
||||
uint32_t *_v = (uint32_t *)keymem;
|
||||
*_v = val;
|
||||
keymem += sizeof(uint32_t);
|
||||
} break;
|
||||
case 2: {
|
||||
uint16_t *_v = (uint16_t *)keymem;
|
||||
*_v = val;
|
||||
keymem += sizeof(uint16_t);
|
||||
} break;
|
||||
case 1: {
|
||||
uint8_t *_v = (uint8_t *)keymem;
|
||||
*_v = val;
|
||||
keymem += sizeof(uint8_t);
|
||||
} break;
|
||||
default:
|
||||
fprintf(stderr, "Panic: Software error in %s line %d\n", __FILE__, __LINE__);
|
||||
exit(255);
|
||||
} // switch
|
||||
aggr_param++;
|
||||
} // while
|
||||
} else if ( swap_flow ) {
|
||||
// default 5-tuple aggregation for bidirectional flows
|
||||
keyptr = (Default_key_t *)keymem;
|
||||
keyptr->srcaddr[0] = flow_record->v6.dstaddr[0];
|
||||
keyptr->srcaddr[1] = flow_record->v6.dstaddr[1];
|
||||
keyptr->dstaddr[0] = flow_record->v6.srcaddr[0];
|
||||
keyptr->dstaddr[1] = flow_record->v6.srcaddr[1];
|
||||
keyptr->srcport = flow_record->dstport;
|
||||
keyptr->dstport = flow_record->srcport;
|
||||
keyptr->proto = flow_record->prot;
|
||||
} else {
|
||||
// default 5-tuple aggregation
|
||||
keyptr = (Default_key_t *)keymem;
|
||||
keyptr->srcaddr[0] = flow_record->v6.srcaddr[0];
|
||||
keyptr->srcaddr[1] = flow_record->v6.srcaddr[1];
|
||||
keyptr->dstaddr[0] = flow_record->v6.dstaddr[0];
|
||||
keyptr->dstaddr[1] = flow_record->v6.dstaddr[1];
|
||||
keyptr->srcport = flow_record->srcport;
|
||||
keyptr->dstport = flow_record->dstport;
|
||||
keyptr->proto = flow_record->prot;
|
||||
}
|
||||
|
||||
} // End of New_Hash_Key
|
||||
|
149
bin/nflowcache.h
Executable file
149
bin/nflowcache.h
Executable file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the auhor 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: nflowcache.h 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NFLOWCACHE_H
|
||||
#define _NFLOWCACHE_H 1
|
||||
|
||||
/* Definitions */
|
||||
|
||||
/*
|
||||
* Flow Table
|
||||
* In order to aggregate flows or to generate any flow statistics, the flows passed the filter
|
||||
* are stored into an internal hash table.
|
||||
*/
|
||||
|
||||
/* Element of the Flow Table ( cache ) */
|
||||
typedef struct FlowTableRecord {
|
||||
// record chain - points to next record with same hash in case of a hash collision
|
||||
struct FlowTableRecord *next;
|
||||
|
||||
// Hash papameters
|
||||
uint32_t hash; // the full 32bit hash value
|
||||
char *hash_key; // all keys in sequence to generate the hash
|
||||
|
||||
// flow counter parameters for FLOWS, INPACKETS, INBYTES, OUTPACKETS, OUTBYTES
|
||||
uint64_t counter[5];
|
||||
|
||||
extension_info_t *map_info_ref;
|
||||
exporter_info_record_t *exp_ref;
|
||||
// flow record follows
|
||||
// flow data size may vary depending on the number of extensions
|
||||
// common_record_t already contains a pointer to more data ( extensions ) at the end
|
||||
common_record_t flowrecord;
|
||||
|
||||
// no further vars beyond this point! The flow record above has additional data.
|
||||
} FlowTableRecord_t;
|
||||
|
||||
typedef struct MemoryHandle_s {
|
||||
/*
|
||||
* to speedup aggregation/record statistics, the internal hash tables use their own memory management.
|
||||
* memory is allocated with malloc in chunks of MemBlockSize. All memory blocks are kept in the
|
||||
* memblock array. Memory blocks are allocated on request up to the number of MaxMemBlocks. If more
|
||||
* blocks are requested, the memblock array is automatically extended.
|
||||
* Memory allocated from a memblock is aligned accoording ALIGN
|
||||
*/
|
||||
|
||||
uint32_t BlockSize; /* max size of each pre-allocated memblock */
|
||||
|
||||
/* memory blocks - containing the flow records and keys */
|
||||
void **memblock; /* array holding all NumBlocks allocated memory blocks */
|
||||
uint32_t MaxBlocks; /* Size of memblock array */
|
||||
uint32_t NumBlocks; /* number of allocated flow blocks in memblock array */
|
||||
uint32_t CurrentBlock; /* Index of current memblock to allocate memory from */
|
||||
uint32_t Allocted; /* Number of bytes already allocated in memblock */
|
||||
|
||||
} MemoryHandle_t;
|
||||
|
||||
#ifdef __x86_64
|
||||
# define ALIGN_MASK 0xFFFFFFF8
|
||||
#else
|
||||
# define ALIGN_MASK 0xFFFFFFFC
|
||||
#endif
|
||||
|
||||
// number of bits for hash width for floe table
|
||||
// Size: 0 < HashBits < 32
|
||||
// typically 20 - tradeoff memory/speed
|
||||
#define HashBits 20
|
||||
|
||||
// Each pre-allocated memory block is 10M
|
||||
#define MemBlockSize 10*1024*1024
|
||||
#define MaxMemBlocks 256
|
||||
|
||||
|
||||
typedef struct hash_FlowTable {
|
||||
/* hash table data */
|
||||
uint16_t NumBits; /* width of the hash table */
|
||||
uint32_t IndexMask; /* Mask which corresponds to NumBits */
|
||||
uint32_t NumRecords; /* number of records in table */
|
||||
FlowTableRecord_t **bucket; /* Hash entry point: points to elements in the flow block */
|
||||
FlowTableRecord_t **bucketcache; /* in case of index collisions, this array points to the last element with that index */
|
||||
|
||||
uint32_t keylen; /* key length of hash key as number of 4byte ints */
|
||||
uint32_t keysize; /* size of key in bytes */
|
||||
|
||||
/* use a MemoryHandle for the table */
|
||||
MemoryHandle_t mem;
|
||||
|
||||
/* src/dst IP aggr masks - use to properly maks the IP before printing */
|
||||
uint64_t IPmask[4]; // 0-1 srcIP, 2-3 dstIP
|
||||
int has_masks;
|
||||
int apply_netbits; // bit 0: src, bit 1: dst
|
||||
|
||||
} hash_FlowTable;
|
||||
|
||||
hash_FlowTable *GetFlowTable(void);
|
||||
|
||||
int Init_FlowTable(void);
|
||||
|
||||
void Dispose_FlowTable(void);
|
||||
|
||||
char *VerifyStat(uint16_t Aggregate_Bits);
|
||||
|
||||
int SetStat(char *str, int *element_stat, int *flow_stat);
|
||||
|
||||
void InsertFlow(common_record_t *raw_record, master_record_t *flow_record, extension_info_t *extension_info);
|
||||
|
||||
void AddFlow(common_record_t *raw_record, master_record_t *flow_record, extension_info_t *extension_info );
|
||||
|
||||
int SetBidirAggregation( void );
|
||||
|
||||
int ParseAggregateMask( char *arg, char **aggr_fmt );
|
||||
|
||||
master_record_t *GetMasterAggregateMask(void);
|
||||
|
||||
#endif //_NFLOWCACHE_H
|
555
bin/nfnet.c
Normal file
555
bin/nfnet.c
Normal file
@ -0,0 +1,555 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: nfnet.c 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
#include "nfnet.h"
|
||||
|
||||
/* at least this number of byytes required, if we change the socket buffer */
|
||||
#define Min_SOCKBUFF_LEN 65536
|
||||
|
||||
const int LISTEN_QUEUE = 128;
|
||||
|
||||
/* local function prototypes */
|
||||
static int isMulticast(struct sockaddr_storage *addr);
|
||||
|
||||
static int joinGroup(int sockfd, int loopBack, int mcastTTL, struct sockaddr_storage *addr);
|
||||
|
||||
/* function definitions */
|
||||
|
||||
int Unicast_receive_socket(const char *bindhost, const char *listenport, int family, int sockbuflen ) {
|
||||
struct addrinfo hints, *res, *ressave;
|
||||
socklen_t optlen;
|
||||
int error, p, sockfd;
|
||||
|
||||
|
||||
if ( !listenport ) {
|
||||
fprintf(stderr, "listen port required!\n");
|
||||
LogError("listen port required!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if nothing specified on command line, prefer IPv4 over IPv6, for compatibility
|
||||
if ( bindhost == NULL && family == AF_UNSPEC )
|
||||
family = AF_INET;
|
||||
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
|
||||
/*
|
||||
AI_PASSIVE flag: we use the resulting address to bind
|
||||
to a socket for accepting incoming connections.
|
||||
So, when the hostname==NULL, getaddrinfo function will
|
||||
return one entry per allowed protocol family containing
|
||||
the unspecified address for that family.
|
||||
*/
|
||||
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
hints.ai_family = family;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
|
||||
error = getaddrinfo(bindhost, listenport, &hints, &res);
|
||||
if (error) {
|
||||
fprintf(stderr, "getaddrinfo error: [%s]\n", gai_strerror(error));
|
||||
LogError("getaddrinfo error: [%s]", gai_strerror(error));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
Try open socket with each address getaddrinfo returned,
|
||||
until we get a valid listening socket.
|
||||
*/
|
||||
ressave = res;
|
||||
sockfd = -1;
|
||||
while ( res ) {
|
||||
// we listen only on IPv4 or IPv6
|
||||
if ( res->ai_family != AF_INET && res->ai_family != AF_INET6 )
|
||||
continue;
|
||||
|
||||
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||
|
||||
if ( !( sockfd < 0 ) ) {
|
||||
// socket call was successfull
|
||||
|
||||
if (bind(sockfd, res->ai_addr, res->ai_addrlen) == 0) {
|
||||
if ( res->ai_family == AF_INET )
|
||||
LogInfo("Bound to IPv4 host/IP: %s, Port: %s",
|
||||
bindhost == NULL ? "any" : bindhost, listenport);
|
||||
if ( res->ai_family == AF_INET6 )
|
||||
LogInfo("Bound to IPv6 host/IP: %s, Port: %s",
|
||||
bindhost == NULL ? "any" : bindhost, listenport);
|
||||
|
||||
// we are done
|
||||
break;
|
||||
}
|
||||
|
||||
// bind was unsuccessful :(
|
||||
close(sockfd);
|
||||
sockfd = -1;
|
||||
}
|
||||
res = res->ai_next;
|
||||
}
|
||||
|
||||
if (sockfd < 0) {
|
||||
freeaddrinfo(ressave);
|
||||
fprintf(stderr, "Could not open the requested socket: %s\n", strerror (errno));
|
||||
LogError("Receive socket error: could not open the requested socket", strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
listen(sockfd, LISTEN_QUEUE);
|
||||
|
||||
freeaddrinfo(ressave);
|
||||
|
||||
if ( sockbuflen ) {
|
||||
if ( sockbuflen < Min_SOCKBUFF_LEN ) {
|
||||
sockbuflen = Min_SOCKBUFF_LEN;
|
||||
LogInfo("I want at least %i bytes as socket buffer", sockbuflen);
|
||||
}
|
||||
optlen = sizeof(p);
|
||||
getsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&p,&optlen);
|
||||
LogInfo("Standard setsockopt, SO_RCVBUF is %i Requested length is %i bytes",p, sockbuflen);
|
||||
if ((setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &sockbuflen, sizeof(sockbuflen)) != 0) ) {
|
||||
fprintf (stderr, "setsockopt(SO_RCVBUF,%d): %s\n", sockbuflen, strerror (errno));
|
||||
LogError("setsockopt(SO_RCVBUF,%d): %s", sockbuflen, strerror (errno));
|
||||
close(sockfd);
|
||||
return -1;
|
||||
} else {
|
||||
getsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&p,&optlen);
|
||||
LogInfo("System set setsockopt, SO_RCVBUF to %d bytes", p);
|
||||
}
|
||||
}
|
||||
|
||||
return sockfd;
|
||||
|
||||
} /* End of Unicast_receive_socket */
|
||||
|
||||
int Unicast_send_socket (const char *hostname, const char *sendport, int family,
|
||||
unsigned int wmem_size, struct sockaddr_storage *addr, int *addrlen) {
|
||||
struct addrinfo hints, *res, *ressave;
|
||||
int n, sockfd;
|
||||
unsigned int wmem_actual;
|
||||
socklen_t optlen;
|
||||
|
||||
if ( !hostname || !sendport ) {
|
||||
fprintf(stderr, "hostname and listen port required!\n");
|
||||
LogError("hostname and listen port required!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// create socket
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
|
||||
hints.ai_family = family;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
|
||||
n = getaddrinfo(hostname, sendport, &hints, &res);
|
||||
|
||||
if ( n < 0 ) {
|
||||
fprintf(stderr, "getaddrinfo error: [%s]\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ressave = res;
|
||||
sockfd = -1;
|
||||
while (res) {
|
||||
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||
|
||||
if ( !(sockfd < 0) ) {
|
||||
// socket call was successsful
|
||||
if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0) {
|
||||
// connect successful - we are done
|
||||
close(sockfd);
|
||||
// ok - we need now an unconnected socket
|
||||
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||
break;
|
||||
}
|
||||
// unsuccessful connect :(
|
||||
close(sockfd);
|
||||
sockfd = -1;
|
||||
}
|
||||
res=res->ai_next;
|
||||
}
|
||||
|
||||
if (sockfd < 0) {
|
||||
freeaddrinfo(ressave);
|
||||
fprintf(stderr, "Send socket error: could not open the requested socket: %s\n", strerror (errno));
|
||||
LogError("Send socket error: could not open the requested socket: %s", strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
*addrlen = res->ai_addrlen;
|
||||
memcpy(addr, res->ai_addr, res->ai_addrlen);
|
||||
freeaddrinfo(ressave);
|
||||
|
||||
// Set socket write buffer. Need to be root!
|
||||
if ( wmem_size > 0 ) {
|
||||
if ( geteuid() == 0 ) {
|
||||
setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &wmem_size, sizeof(wmem_size));
|
||||
|
||||
// check what was set (e.g. linux 2.4.20 sets twice of what was requested)
|
||||
getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &wmem_actual, &optlen);
|
||||
|
||||
if (wmem_size != wmem_actual) {
|
||||
printf("Warning: Socket write buffer size requested: %u set: %u\n",
|
||||
wmem_size, wmem_actual);
|
||||
}
|
||||
} else {
|
||||
printf("Warning: Socket buffer size can only be changed by root!\n");
|
||||
}
|
||||
}
|
||||
|
||||
return sockfd;
|
||||
|
||||
} // End of Unicast_send_socket
|
||||
|
||||
|
||||
int Multicast_receive_socket (const char *hostname, const char *listenport, int family, int sockbuflen ) {
|
||||
struct addrinfo hints, *res, *ressave;
|
||||
socklen_t optlen;
|
||||
int p, error, sockfd;
|
||||
|
||||
if ( !listenport ) {
|
||||
fprintf(stderr, "listen port required!\n");
|
||||
LogError("listen port required!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = family;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
|
||||
error = getaddrinfo(hostname, listenport, &hints, &res);
|
||||
|
||||
if ( error ) {
|
||||
fprintf(stderr, "getaddrinfo error:: [%s]\n", gai_strerror(error));
|
||||
LogError("getaddrinfo error:: [%s]", gai_strerror(error));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Try open socket with each address getaddrinfo returned,
|
||||
until we get a valid listening socket.
|
||||
*/
|
||||
|
||||
sockfd = -1;
|
||||
ressave = res;
|
||||
while (res) {
|
||||
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||
if ( sockfd < 0 ) {
|
||||
res=res->ai_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
// we found a valid socket and are done in this loop
|
||||
break;
|
||||
}
|
||||
|
||||
if ( sockfd < 0 ) {
|
||||
// nothing found - bye bye
|
||||
fprintf(stderr, "Could not create a socket for [%s:%s]\n", hostname, listenport);
|
||||
LogError("Could not create a socket for [%s:%s]", hostname, listenport);
|
||||
freeaddrinfo(ressave);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if ( isMulticast((struct sockaddr_storage *)res->ai_addr) < 0 ) {
|
||||
fprintf(stderr, "Not a multicast address [%s]\n", hostname);
|
||||
LogError("Not a multicast address [%s]", hostname);
|
||||
freeaddrinfo(ressave);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(sockfd);
|
||||
|
||||
|
||||
sockfd = socket(res->ai_family, SOCK_DGRAM, 0);
|
||||
if (bind(sockfd, res->ai_addr, res->ai_addrlen) < 0) {
|
||||
fprintf(stderr, "bind: %s\n", strerror (errno));
|
||||
LogError("bind: %s", strerror (errno));
|
||||
close(sockfd);
|
||||
freeaddrinfo(ressave);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (joinGroup(sockfd, 1 , 1, (struct sockaddr_storage *)res->ai_addr) <0) {
|
||||
close(sockfd);
|
||||
freeaddrinfo(ressave);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( res->ai_family == AF_INET )
|
||||
LogInfo("Joined IPv4 multicast group: %s Port: %s", hostname, listenport);
|
||||
if ( res->ai_family == AF_INET6 )
|
||||
LogInfo( "Joined IPv6 multicat group: %s Port: %s", hostname, listenport);
|
||||
|
||||
|
||||
freeaddrinfo(ressave);
|
||||
|
||||
if ( sockbuflen ) {
|
||||
if ( sockbuflen < Min_SOCKBUFF_LEN ) {
|
||||
sockbuflen = Min_SOCKBUFF_LEN;
|
||||
LogInfo("I want at least %i bytes as socket buffer", sockbuflen);
|
||||
}
|
||||
optlen = sizeof(p);
|
||||
getsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&p,&optlen);
|
||||
LogInfo("Standard setsockopt, SO_RCVBUF is %i Requested length is %i bytes",p, sockbuflen);
|
||||
if ((setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &sockbuflen, sizeof(sockbuflen)) != 0) ) {
|
||||
fprintf (stderr, "setsockopt(SO_RCVBUF,%d): %s\n", sockbuflen, strerror (errno));
|
||||
LogError("setsockopt(SO_RCVBUF,%d): %s", sockbuflen, strerror (errno));
|
||||
close(sockfd);
|
||||
return -1;
|
||||
} else {
|
||||
getsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&p,&optlen);
|
||||
LogInfo("System set setsockopt, SO_RCVBUF to %d bytes", p);
|
||||
}
|
||||
}
|
||||
|
||||
return sockfd;
|
||||
|
||||
} /* End of Multicast_receive_socket */
|
||||
|
||||
int Multicast_send_socket (const char *hostname, const char *listenport, int family,
|
||||
unsigned int wmem_size, struct sockaddr_storage *addr, int *addrlen) {
|
||||
struct addrinfo hints, *res, *ressave;
|
||||
int error, sockfd;
|
||||
|
||||
if ( !listenport || !hostname ) {
|
||||
fprintf(stderr, "hostname and listen port required!\n");
|
||||
LogError("hostname and listen port required!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = family;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
|
||||
error = getaddrinfo(hostname, listenport, &hints, &res);
|
||||
|
||||
if ( error ) {
|
||||
fprintf(stderr, "getaddrinfo error:: [%s]\n", gai_strerror(error));
|
||||
LogError("getaddrinfo error:: [%s]", gai_strerror(error));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Try open socket with each address getaddrinfo returned,
|
||||
until we get a valid listening socket.
|
||||
*/
|
||||
|
||||
sockfd=-1;
|
||||
ressave = res;
|
||||
while (res) {
|
||||
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||
if ( sockfd < 0 ) {
|
||||
res=res->ai_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
// we found a valid socket and are done in this loop
|
||||
break;
|
||||
}
|
||||
|
||||
if ( sockfd < 0 ) {
|
||||
// nothing found - bye bye
|
||||
fprintf(stderr, "Could not create a socket for [%s:%s]\n", hostname, listenport);
|
||||
LogError("Could not create a socket for [%s:%s]", hostname, listenport);
|
||||
freeaddrinfo(ressave);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( isMulticast((struct sockaddr_storage *)res->ai_addr) < 0 ) {
|
||||
fprintf(stderr, "Not a multicast address [%s]\n", hostname);
|
||||
LogError("Not a multicast address [%s]", hostname);
|
||||
freeaddrinfo(ressave);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(sockfd);
|
||||
sockfd = socket(res->ai_family, SOCK_DGRAM, 0);
|
||||
|
||||
*addrlen = res->ai_addrlen;
|
||||
memcpy(addr, res->ai_addr, res->ai_addrlen);
|
||||
|
||||
/*
|
||||
((struct sockaddr_in *)addr)->sin_family=AF_INET;
|
||||
addr.sin_addr.s_addr=inet_addr(HELLO_GROUP);
|
||||
addr.sin_port=htons(HELLO_PORT);
|
||||
*/
|
||||
|
||||
if (joinGroup(sockfd, 1 , 1, (struct sockaddr_storage *)res->ai_addr) <0) {
|
||||
close(sockfd);
|
||||
freeaddrinfo(ressave);
|
||||
return -1;
|
||||
}
|
||||
|
||||
freeaddrinfo(ressave);
|
||||
|
||||
/*
|
||||
message = "hello world\n";
|
||||
printf("Send %lu bytes, Message: %s\n", strlen(message)+1, message);
|
||||
while (1) {
|
||||
ret = sendto(sockfd,message,strlen(message)+1,0,(struct sockaddr *) addr, *addrlen);
|
||||
if ( ret != strlen(message)+1 ) {
|
||||
perror("sendto");
|
||||
exit(1);
|
||||
}
|
||||
printf("sleep\n");
|
||||
sleep(1);
|
||||
}
|
||||
exit(255);
|
||||
*/
|
||||
return sockfd;
|
||||
|
||||
} /* End of Multicast_send_socket */
|
||||
|
||||
static int joinGroup(int sockfd, int loopBack, int mcastTTL, struct sockaddr_storage *addr) {
|
||||
int ret, err;
|
||||
|
||||
ret=-1;
|
||||
|
||||
switch (addr->ss_family) {
|
||||
case AF_INET: {
|
||||
struct ip_mreq mreq;
|
||||
|
||||
mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
|
||||
mreq.imr_interface.s_addr = INADDR_ANY;
|
||||
|
||||
err = setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *)&mreq, sizeof(mreq));
|
||||
if ( err ) {
|
||||
fprintf(stderr, "setsockopt IP_ADD_MEMBERSHIP: %s\n", strerror (errno));
|
||||
LogError("setsockopt IP_ADD_MEMBERSHIP: %s", strerror (errno));
|
||||
break;
|
||||
}
|
||||
ret = 0;
|
||||
/*
|
||||
// These two setsockopt may fail because not implemented on every OS, but harmless
|
||||
err = setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &loopBack, sizeof(loopBack));
|
||||
if ( err ) {
|
||||
fprintf(stderr, "setsockopt IP_MULTICAST_LOOP: %s\n", strerror (errno));
|
||||
LogError("setsockopt IP_MULTICAST_LOOP: %s", strerror (errno));
|
||||
}
|
||||
|
||||
err = setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &mcastTTL, sizeof(mcastTTL));
|
||||
if ( err ) {
|
||||
fprintf(stderr, "setsockopt IP_MULTICAST_LOOP: %s\n", strerror (errno));
|
||||
LogError("setsockopt IP_MULTICAST_LOOP: %s", strerror (errno));
|
||||
}
|
||||
*/
|
||||
} break;
|
||||
|
||||
case AF_INET6: {
|
||||
struct ipv6_mreq mreq6;
|
||||
|
||||
memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
|
||||
mreq6.ipv6mr_interface= 0;
|
||||
|
||||
err = setsockopt(sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6));
|
||||
if ( err ) {
|
||||
fprintf(stderr, "setsockopt IPV6_JOIN_GROUP: %s\n", strerror (errno));
|
||||
LogError("setsockopt IPV6_JOIN_GROUP: %s", strerror (errno));
|
||||
break;
|
||||
}
|
||||
ret = 0;
|
||||
/*
|
||||
// These two setsockopt may fail because not implemented on every OS, but harmless
|
||||
err = setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loopBack, sizeof(loopBack));
|
||||
if ( err ) {
|
||||
fprintf(stderr, "setsockopt IPV6_MULTICAST_LOOP: %s\n", strerror (errno));
|
||||
LogError("setsockopt IPV6_MULTICAST_LOOP: %s", strerror (errno));
|
||||
}
|
||||
|
||||
err = setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &mcastTTL, sizeof(mcastTTL));
|
||||
if ( err ) {
|
||||
fprintf(stderr, "setsockopt IPV6_MULTICAST_HOPS: %s\n", strerror (errno));
|
||||
LogError("setsockopt IPV6_MULTICAST_HOPS: %s", strerror (errno));
|
||||
}
|
||||
*/
|
||||
} break;
|
||||
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
return ret;
|
||||
} /* joinGroup */
|
||||
|
||||
|
||||
static int isMulticast(struct sockaddr_storage *addr) {
|
||||
int ret;
|
||||
|
||||
ret = -1;
|
||||
switch (addr->ss_family) {
|
||||
case AF_INET: {
|
||||
struct sockaddr_in *addr4=(struct sockaddr_in *)addr;
|
||||
ret = IN_MULTICAST(ntohl(addr4->sin_addr.s_addr));
|
||||
}
|
||||
break;
|
||||
|
||||
case AF_INET6: {
|
||||
struct sockaddr_in6 *addr6=(struct sockaddr_in6 *)addr;
|
||||
ret = IN6_IS_ADDR_MULTICAST(&addr6->sin6_addr);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
return ret;
|
||||
} /* End of isMulticast */
|
||||
|
||||
|
72
bin/nfnet.h
Normal file
72
bin/nfnet.h
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: nfnet.h 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NFNET_H
|
||||
#define _NFNET_H 1
|
||||
|
||||
/* Definitions */
|
||||
|
||||
#define UDP_PACKET_SIZE 1472
|
||||
|
||||
typedef struct send_peer_s {
|
||||
struct sockaddr_storage addr;
|
||||
int addrlen;
|
||||
int sockfd;
|
||||
int family;
|
||||
char *port;
|
||||
char *hostname;
|
||||
int mcast;
|
||||
int flush;
|
||||
void *send_buffer;
|
||||
void *buff_ptr;
|
||||
void *endp;
|
||||
} send_peer_t;
|
||||
|
||||
/* Function prototypes */
|
||||
|
||||
int Unicast_receive_socket(const char *bindhost, const char *listenport, int family, int sockbuflen );
|
||||
|
||||
int Multicast_receive_socket (const char *hostname, const char *listenport, int family, int sockbuflen);
|
||||
|
||||
int Unicast_send_socket (const char *hostname, const char *listenport, int family,
|
||||
unsigned int wmem_size, struct sockaddr_storage *addr, int *addrlen);
|
||||
|
||||
int Multicast_send_socket (const char *hostname, const char *listenport, int family,
|
||||
unsigned int wmem_size, struct sockaddr_storage *addr, int *addrlen);
|
||||
|
||||
#endif //_NFNET_H
|
1566
bin/nfpcapd.c
Normal file
1566
bin/nfpcapd.c
Normal file
File diff suppressed because it is too large
Load Diff
134
bin/nfprof.c
Normal file
134
bin/nfprof.c
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: nfprof.c 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <strings.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include "nfprof.h"
|
||||
|
||||
/*
|
||||
* Initialize profiling.
|
||||
*
|
||||
*/
|
||||
int nfprof_start(nfprof_t *profile_data) {
|
||||
|
||||
bzero (profile_data, sizeof(nfprof_t));
|
||||
return gettimeofday(&profile_data->tstart, (struct timezone*)NULL) == 0 ? 1 : 0;
|
||||
|
||||
} // End of nfprof_start
|
||||
|
||||
/*
|
||||
* Finish profiling.
|
||||
*
|
||||
*/
|
||||
int nfprof_end(nfprof_t *profile_data, uint64_t numflows) {
|
||||
int ret;
|
||||
|
||||
if ((ret = gettimeofday(&profile_data->tend, (struct timezone*)NULL)) == -1)
|
||||
return 1;
|
||||
|
||||
if ((ret = getrusage(RUSAGE_SELF, &profile_data->used)) == -1)
|
||||
return 1;
|
||||
|
||||
profile_data->numflows = numflows;
|
||||
|
||||
return 0;
|
||||
|
||||
} // End of nfprof_end
|
||||
|
||||
/*
|
||||
* Dump nfprof contents to std
|
||||
*
|
||||
*/
|
||||
void nfprof_print(nfprof_t *profile_data, FILE *std) {
|
||||
u_long usec, sec;
|
||||
double fps, allsecs;
|
||||
|
||||
usec = profile_data->used.ru_utime.tv_usec + profile_data->used.ru_stime.tv_usec;
|
||||
sec = profile_data->used.ru_utime.tv_sec + profile_data->used.ru_stime.tv_sec;
|
||||
|
||||
if (usec > 1000000)
|
||||
usec -= 1000000, ++sec;
|
||||
|
||||
|
||||
allsecs = (double)sec + ((double)usec/1000000);
|
||||
if ( allsecs == 0.0 )
|
||||
fps = 0;
|
||||
else
|
||||
fps = (double)profile_data->numflows / ((double)sec + ((double)usec/1000000));
|
||||
|
||||
fprintf(std, "Sys: %lu.%-3.3lus flows/second: %-10.1f ", sec, usec/1000, fps);
|
||||
|
||||
if (profile_data->tend.tv_usec < profile_data->tstart.tv_usec)
|
||||
profile_data->tend.tv_usec += 1000000, --profile_data->tend.tv_sec;
|
||||
|
||||
usec = profile_data->tend.tv_usec - profile_data->tstart.tv_usec;
|
||||
sec = profile_data->tend.tv_sec - profile_data->tstart.tv_sec;
|
||||
|
||||
if ( usec == 0 && sec == 0 )
|
||||
// acctually should never happen, but catch it anyway
|
||||
fps = 0;
|
||||
else
|
||||
fps = (double)profile_data->numflows / ((double)sec + ((double)usec/1000000));
|
||||
|
||||
fprintf(std, "Wall: %lu.%-3.3lus flows/second: %-10.1f\n", sec, usec/1000, fps);
|
||||
/*
|
||||
fprintf(std, "\n");
|
||||
fprintf(std, "integral max resident set size: %u\n", profile_data->used.ru_maxrss);
|
||||
fprintf(std, "integral shared text memory size: %u\n", profile_data->used.ru_ixrss);
|
||||
fprintf(std, "integral unshared data size: %u\n", profile_data->used.ru_idrss);
|
||||
fprintf(std, "integral unshared stack size: %u\n", profile_data->used.ru_isrss);
|
||||
fprintf(std, "page reclaims: %u\n", profile_data->used.ru_minflt);
|
||||
fprintf(std, "page faults: %u\n", profile_data->used.ru_majflt);
|
||||
fprintf(std, "swaps: %u\n", profile_data->used.ru_nswap);
|
||||
fprintf(std, "block input operations: %u\n", profile_data->used.ru_inblock);
|
||||
fprintf(std, "block output operations: %u\n", profile_data->used.ru_oublock);
|
||||
*/
|
||||
|
||||
} // End of nfprof_print
|
||||
|
55
bin/nfprof.h
Normal file
55
bin/nfprof.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: nfprof.h 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NFPROF_H
|
||||
#define _NFPROF_H 1
|
||||
|
||||
typedef struct nfprof_s {
|
||||
struct timeval tstart; /* start time */
|
||||
struct timeval tend; /* end time */
|
||||
struct rusage used; /* system resources used */
|
||||
uint64_t numflows; /* total # of flows processed */
|
||||
} nfprof_t;
|
||||
|
||||
int nfprof_start(nfprof_t *profile_data);
|
||||
|
||||
int nfprof_end(nfprof_t *profile_data, uint64_t numflows);
|
||||
|
||||
void nfprof_print(nfprof_t *profile_data, FILE *std);
|
||||
|
||||
#endif //_NFPROF_H
|
694
bin/nfprofile.c
Normal file
694
bin/nfprofile.c
Normal file
@ -0,0 +1,694 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: nfprofile.c 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
#include <netinet/in.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "nf_common.h"
|
||||
#include "rbtree.h"
|
||||
#include "nftree.h"
|
||||
#include "nfdump.h"
|
||||
#include "nffile.h"
|
||||
#include "nfx.h"
|
||||
#include "nfstat.h"
|
||||
#include "nfstatfile.h"
|
||||
#include "bookkeeper.h"
|
||||
#include "nfxstat.h"
|
||||
#include "collector.h"
|
||||
#include "exporter.h"
|
||||
#include "ipconv.h"
|
||||
#include "flist.h"
|
||||
#include "util.h"
|
||||
#include "profile.h"
|
||||
|
||||
/* externals */
|
||||
extern generic_exporter_t **exporter_list;
|
||||
|
||||
#ifdef COMPAT15
|
||||
extern extension_descriptor_t extension_descriptor[];
|
||||
#endif
|
||||
|
||||
/* Local Variables */
|
||||
static const char *nfdump_version = VERSION;
|
||||
|
||||
|
||||
extension_map_list_t *extension_map_list;
|
||||
uint32_t is_anonymized;
|
||||
char Ident[IDENTLEN];
|
||||
|
||||
/* Function Prototypes */
|
||||
static void usage(char *name);
|
||||
|
||||
static profile_param_info_t *ParseParams (char *profile_datadir);
|
||||
|
||||
static void process_data(profile_channel_info_t *channels, unsigned int num_channels, time_t tslot, int do_xstat);
|
||||
|
||||
|
||||
/* Functions */
|
||||
|
||||
#include "nfdump_inline.c"
|
||||
#include "nffile_inline.c"
|
||||
|
||||
static void usage(char *name) {
|
||||
printf("usage %s [options] \n"
|
||||
"-h\t\tthis text you see right here\n"
|
||||
"-V\t\tPrint version and exit.\n"
|
||||
"-D <dns>\tUse nameserver <dns> for host lookup.\n"
|
||||
"-H Add xstat histogram data to flow file.(default 'no')\n"
|
||||
"-M <expr>\tRead input from multiple directories.\n"
|
||||
"-r\t\tread input from file\n"
|
||||
"-f\t\tfilename with filter syntaxfile\n"
|
||||
"-p\t\tprofile data dir.\n"
|
||||
"-P\t\tprofile stat dir.\n"
|
||||
"-s\t\tprofile subdir.\n"
|
||||
"-Z\t\tCheck filter syntax and exit.\n"
|
||||
"-S subdir\tSub directory format. see nfcapd(1) for format\n"
|
||||
"-z\t\tCompress flows in output file.\n"
|
||||
"-t <time>\ttime for RRD update\n", name);
|
||||
} /* usage */
|
||||
|
||||
|
||||
static void process_data(profile_channel_info_t *channels, unsigned int num_channels, time_t tslot, int do_xstat) {
|
||||
common_record_t *flow_record;
|
||||
nffile_t *nffile;
|
||||
FilterEngine_data_t *engine;
|
||||
int i, j, done, ret ;
|
||||
#ifdef COMPAT15
|
||||
int v1_map_done = 0;
|
||||
#endif
|
||||
|
||||
nffile = GetNextFile(NULL, 0, 0);
|
||||
if ( !nffile ) {
|
||||
LogError("GetNextFile() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return;
|
||||
}
|
||||
if ( nffile == EMPTY_LIST ) {
|
||||
LogError("Empty file list. No files to process\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// store infos away for later use
|
||||
// although multiple files may be processed, it is assumed that all
|
||||
// have the same settings
|
||||
is_anonymized = IP_ANONYMIZED(nffile);
|
||||
strncpy(Ident, nffile->file_header->ident, IDENTLEN);
|
||||
Ident[IDENTLEN-1] = '\0';
|
||||
|
||||
done = 0;
|
||||
while ( !done ) {
|
||||
|
||||
// get next data block from file
|
||||
ret = ReadBlock(nffile);
|
||||
|
||||
switch (ret) {
|
||||
case NF_CORRUPT:
|
||||
case NF_ERROR:
|
||||
if ( ret == NF_CORRUPT )
|
||||
LogError("Skip corrupt data file '%s'\n",GetCurrentFilename());
|
||||
else
|
||||
LogError("Read error in file '%s': %s\n",GetCurrentFilename(), strerror(errno) );
|
||||
// fall through - get next file in chain
|
||||
case NF_EOF: {
|
||||
nffile_t *next = GetNextFile(nffile, 0, 0);
|
||||
if ( next == EMPTY_LIST ) {
|
||||
done = 1;
|
||||
}
|
||||
if ( next == NULL ) {
|
||||
done = 1;
|
||||
LogError("Unexpected end of file list\n");
|
||||
}
|
||||
continue;
|
||||
|
||||
} break; // not really needed
|
||||
}
|
||||
|
||||
#ifdef COMPAT15
|
||||
if ( nffile->block_header->id == DATA_BLOCK_TYPE_1 ) {
|
||||
common_record_v1_t *v1_record = (common_record_v1_t *)nffile->buff_ptr;
|
||||
// create an extension map for v1 blocks
|
||||
if ( v1_map_done == 0 ) {
|
||||
extension_map_t *map = malloc(sizeof(extension_map_t) + 2 * sizeof(uint16_t) );
|
||||
if ( ! map ) {
|
||||
LogError("malloc() allocation error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
exit(255);
|
||||
}
|
||||
map->type = ExtensionMapType;
|
||||
map->size = sizeof(extension_map_t) + 2 * sizeof(uint16_t);
|
||||
if (( map->size & 0x3 ) != 0 ) {
|
||||
map->size += 4 - ( map->size & 0x3 );
|
||||
}
|
||||
|
||||
map->map_id = INIT_ID;
|
||||
map->ex_id[0] = EX_IO_SNMP_2;
|
||||
map->ex_id[1] = EX_AS_2;
|
||||
map->ex_id[2] = 0;
|
||||
|
||||
map->extension_size = 0;
|
||||
map->extension_size += extension_descriptor[EX_IO_SNMP_2].size;
|
||||
map->extension_size += extension_descriptor[EX_AS_2].size;
|
||||
|
||||
if ( Insert_Extension_Map(extension_map_list, map) ) {
|
||||
int j;
|
||||
for ( j=0; j < num_channels; j++ ) {
|
||||
if ( channels[j].nffile != NULL) {
|
||||
// flush new map
|
||||
AppendToBuffer(channels[j].nffile, (void *)map, map->size);
|
||||
}
|
||||
}
|
||||
} // else map already known and flushed
|
||||
|
||||
v1_map_done = 1;
|
||||
}
|
||||
|
||||
// convert the records to v2
|
||||
for ( i=0; i < nffile->block_header->NumRecords; i++ ) {
|
||||
common_record_t *v2_record = (common_record_t *)v1_record;
|
||||
Convert_v1_to_v2((void *)v1_record);
|
||||
// now we have a v2 record -> use size of v2_record->size
|
||||
v1_record = (common_record_v1_t *)((pointer_addr_t)v1_record + v2_record->size);
|
||||
}
|
||||
nffile->block_header->id = DATA_BLOCK_TYPE_2;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( nffile->block_header->id == Large_BLOCK_Type ) {
|
||||
// skip
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( nffile->block_header->id != DATA_BLOCK_TYPE_2 ) {
|
||||
LogError("Can't process block type %u. Skip block.\n", nffile->block_header->id);
|
||||
continue;
|
||||
}
|
||||
|
||||
flow_record = nffile->buff_ptr;
|
||||
for ( i=0; i < nffile->block_header->NumRecords; i++ ) {
|
||||
switch ( flow_record->type ) {
|
||||
case CommonRecordV0Type:
|
||||
case CommonRecordType: {
|
||||
generic_exporter_t *exp_info = exporter_list[flow_record->exporter_sysid];
|
||||
uint32_t map_id = flow_record->ext_map;
|
||||
master_record_t *master_record;
|
||||
|
||||
if ( extension_map_list->slot[map_id] == NULL ) {
|
||||
LogError("Corrupt data file. Missing extension map %u. Skip record.\n", flow_record->ext_map);
|
||||
flow_record = (common_record_t *)((pointer_addr_t)flow_record + flow_record->size);
|
||||
continue;
|
||||
}
|
||||
|
||||
master_record = &(extension_map_list->slot[map_id]->master_record);
|
||||
ExpandRecord_v2( flow_record, extension_map_list->slot[flow_record->ext_map],
|
||||
exp_info ? &(exp_info->info) : NULL, master_record);
|
||||
|
||||
for ( j=0; j < num_channels; j++ ) {
|
||||
int match;
|
||||
|
||||
// apply profile filter
|
||||
(channels[j].engine)->nfrecord = (uint64_t *)master_record;
|
||||
engine = channels[j].engine;
|
||||
match = (*engine->FilterEngine)(engine);
|
||||
|
||||
// if profile filter failed -> next profile
|
||||
if ( !match )
|
||||
continue;
|
||||
|
||||
// filter was successful -> continue record processing
|
||||
|
||||
// update statistics
|
||||
UpdateStat(&channels[j].stat_record, master_record);
|
||||
if ( channels[j].nffile )
|
||||
UpdateStat(channels[j].nffile->stat_record, master_record);
|
||||
|
||||
if ( channels[j].xstat )
|
||||
UpdateXStat(channels[j].xstat, master_record);
|
||||
|
||||
// do we need to write data to new file - shadow profiles do not have files.
|
||||
// check if we need to flush the output buffer
|
||||
if ( channels[j].nffile != NULL ) {
|
||||
// write record to output buffer
|
||||
AppendToBuffer(channels[j].nffile, (void *)flow_record, flow_record->size);
|
||||
}
|
||||
|
||||
} // End of for all channels
|
||||
|
||||
} break;
|
||||
case ExtensionMapType: {
|
||||
extension_map_t *map = (extension_map_t *)flow_record;
|
||||
|
||||
if ( Insert_Extension_Map(extension_map_list, map) ) {
|
||||
int j;
|
||||
for ( j=0; j < num_channels; j++ ) {
|
||||
if ( channels[j].nffile != NULL ) {
|
||||
// flush new map
|
||||
AppendToBuffer(channels[j].nffile, (void *)map, map->size);
|
||||
}
|
||||
}
|
||||
} // else map already known and flushed
|
||||
|
||||
} break;
|
||||
case ExporterInfoRecordType: {
|
||||
int ret = AddExporterInfo((exporter_info_record_t *)flow_record);
|
||||
if ( ret != 0 ) {
|
||||
int j;
|
||||
for ( j=0; j < num_channels; j++ ) {
|
||||
if ( channels[j].nffile != NULL && ret == 1) {
|
||||
// flush new exporter
|
||||
AppendToBuffer(channels[j].nffile, (void *)flow_record, flow_record->size);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LogError("Failed to add Exporter Record\n");
|
||||
}
|
||||
} break;
|
||||
case SamplerInfoRecordype: {
|
||||
int ret = AddSamplerInfo((sampler_info_record_t *)flow_record);
|
||||
if ( ret != 0 ) {
|
||||
int j;
|
||||
for ( j=0; j < num_channels; j++ ) {
|
||||
if ( channels[j].nffile != NULL && ret == 1 ) {
|
||||
// flush new map
|
||||
AppendToBuffer(channels[j].nffile, (void *)flow_record, flow_record->size);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LogError("Failed to add Sampler Record\n");
|
||||
}
|
||||
} break;
|
||||
case ExporterRecordType:
|
||||
case SamplerRecordype:
|
||||
case ExporterStatRecordType:
|
||||
// Silently skip exporter records
|
||||
break;
|
||||
default: {
|
||||
LogError("Skip unknown record type %i\n", flow_record->type);
|
||||
}
|
||||
}
|
||||
// Advance pointer by number of bytes for netflow record
|
||||
flow_record = (common_record_t *)((pointer_addr_t)flow_record + flow_record->size);
|
||||
|
||||
} // End of for all umRecords
|
||||
} // End of while !done
|
||||
|
||||
// do we need to write data to new file - shadow profiles do not have files.
|
||||
for ( j=0; j < num_channels; j++ ) {
|
||||
if ( channels[j].nffile != NULL ) {
|
||||
// flush output buffer
|
||||
if ( channels[j].nffile->block_header->NumRecords ) {
|
||||
if ( WriteBlock(channels[j].nffile) <= 0 ) {
|
||||
LogError("Failed to write output buffer to disk: '%s'" , strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CloseFile(nffile);
|
||||
DisposeFile(nffile);
|
||||
|
||||
} // End of process_data
|
||||
|
||||
static profile_param_info_t *ParseParams (char *profile_datadir) {
|
||||
struct stat stat_buf;
|
||||
char line[512], path[MAXPATHLEN], *p, *q, *s;
|
||||
profile_param_info_t *profile_list;
|
||||
profile_param_info_t **list = &profile_list;
|
||||
|
||||
profile_list = NULL;
|
||||
while ( ( fgets(line, 512, stdin) != NULL )) {
|
||||
LogInfo("Process line '%s'\n", line);
|
||||
line[511] = '\0';
|
||||
|
||||
if ( *list == NULL )
|
||||
*list = (profile_param_info_t *)malloc(sizeof(profile_param_info_t));
|
||||
// else we come from a continue statement with illegal data - overwrite
|
||||
|
||||
if ( !*list) {
|
||||
LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(*list)->next = NULL;
|
||||
(*list)->profilegroup = NULL;
|
||||
(*list)->profilename = NULL;
|
||||
(*list)->channelname = NULL;
|
||||
(*list)->channel_sourcelist = NULL;
|
||||
(*list)->profiletype = 0;
|
||||
|
||||
// delete '\n' at the end of line
|
||||
// format of stdin config line:
|
||||
// <profilegroup>#<profilename>#<profiletype>#<channelname>#<channel_sourcelist>
|
||||
p = strchr(line, '\n');
|
||||
if ( p ) *p = '\0';
|
||||
|
||||
q = line;
|
||||
p = strchr(q, '#');
|
||||
if ( p )
|
||||
*p = '\0';
|
||||
|
||||
s = line;
|
||||
|
||||
// savety check: if no separator found loop to next line
|
||||
if ( !p ) {
|
||||
LogError("Incomplete line - channel skipped.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
q = p;
|
||||
q++;
|
||||
|
||||
p = strchr(q, '#');
|
||||
if ( p )
|
||||
*p = '\0';
|
||||
|
||||
snprintf(path, MAXPATHLEN-1, "%s/%s/%s", profile_datadir, s, q);
|
||||
path[MAXPATHLEN-1] = '\0';
|
||||
if ( stat(path, &stat_buf) || !S_ISDIR(stat_buf.st_mode) ) {
|
||||
LogError("profile '%s' not found in group %s. Skipped.\n", q, s);
|
||||
continue;
|
||||
}
|
||||
|
||||
(*list)->profilegroup = strdup(s);
|
||||
(*list)->profilename = strdup(q);
|
||||
|
||||
// savety check: if no separator found loop to next line
|
||||
if ( !p ) {
|
||||
LogError("Incomplete line - channel skipped.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
q = p;
|
||||
q++;
|
||||
|
||||
p = strchr(q, '#');
|
||||
if ( p )
|
||||
*p = '\0';
|
||||
|
||||
s = q;
|
||||
while ( *s ) {
|
||||
if ( *s < '0' || *s > '9' ) {
|
||||
LogError("Not a valid number: %s\n", q);
|
||||
s = NULL;
|
||||
break;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
if ( s == NULL )
|
||||
continue;
|
||||
|
||||
(*list)->profiletype = (int)strtol(q, (char **)NULL, 10);
|
||||
|
||||
// savety check: if no separator found loop to next line
|
||||
if ( !p ) {
|
||||
LogError("Incomplete line - channel skipped.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
q = p;
|
||||
q++;
|
||||
|
||||
p = strchr(q, '#');
|
||||
if ( p )
|
||||
*p = '\0';
|
||||
|
||||
snprintf(path, MAXPATHLEN-1, "%s/%s/%s/%s", profile_datadir, (*list)->profilegroup, (*list)->profilename, q);
|
||||
path[MAXPATHLEN-1] = '\0';
|
||||
if ( stat(path, &stat_buf) || !S_ISDIR(stat_buf.st_mode) ) {
|
||||
LogError("channel '%s' in profile '%s' not found. Skipped.\n", q, (*list)->profilename);
|
||||
continue;
|
||||
}
|
||||
|
||||
(*list)->channelname = strdup(q);
|
||||
|
||||
if ( !p ) {
|
||||
LogError("Incomplete line - Skipped.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
q = p;
|
||||
q++;
|
||||
|
||||
p = strchr(q, '#');
|
||||
if ( p )
|
||||
*p = '\0';
|
||||
|
||||
// Skip leading '| chars
|
||||
while ( *q && *q == '|' ) {
|
||||
q++;
|
||||
}
|
||||
s = q;
|
||||
|
||||
// if q is already empty ( '\0' ) loop is not processed
|
||||
while ( *s ) {
|
||||
// as s[0] is not '\0' s[1] may be '\0' but still valid and in range
|
||||
if ( s[0] == '|' && s[1] == '|' ) {
|
||||
char *t = s;
|
||||
t++;
|
||||
while ( *t ) { // delete this empty channel name
|
||||
t[0] = t[1];
|
||||
t++;
|
||||
}
|
||||
} else
|
||||
s++;
|
||||
}
|
||||
// we have no doublicate '|' here any more
|
||||
// check if last char is an extra '|'
|
||||
if ( *q && (q[strlen(q)-1] == '|') )
|
||||
q[strlen(q)-1] = '\0';
|
||||
|
||||
if ( *q && (strcmp(q, "*") != 0) )
|
||||
(*list)->channel_sourcelist = strdup(q);
|
||||
|
||||
list = &((*list)->next);
|
||||
}
|
||||
|
||||
if ( *list != NULL ) {
|
||||
free(*list);
|
||||
*list = NULL;
|
||||
}
|
||||
|
||||
if ( ferror(stdin) ) {
|
||||
LogError("fgets() error: %s", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return profile_list;
|
||||
|
||||
} // End of ParseParams
|
||||
|
||||
int main( int argc, char **argv ) {
|
||||
unsigned int num_channels, compress;
|
||||
struct stat stat_buf;
|
||||
profile_param_info_t *profile_list;
|
||||
char *rfile, *ffile, *filename, *Mdirs, *tstring;
|
||||
char *profile_datadir, *profile_statdir, *nameserver;
|
||||
int c, syntax_only, subdir_index, stdin_profile_params, do_xstat;
|
||||
time_t tslot;
|
||||
|
||||
tstring = NULL;
|
||||
profile_datadir = NULL;
|
||||
profile_statdir = NULL;
|
||||
Mdirs = NULL;
|
||||
tslot = 0;
|
||||
syntax_only = 0;
|
||||
do_xstat = 0;
|
||||
compress = 0;
|
||||
subdir_index = 0;
|
||||
profile_list = NULL;
|
||||
nameserver = NULL;
|
||||
stdin_profile_params = 0;
|
||||
is_anonymized = 0;
|
||||
|
||||
strncpy(Ident, "none", IDENTLEN);
|
||||
Ident[IDENTLEN-1] = '\0';
|
||||
|
||||
// default file names
|
||||
ffile = "filter.txt";
|
||||
rfile = NULL;
|
||||
while ((c = getopt(argc, argv, "D:HIL:p:P:hf:r:n:M:S:t:VzZ")) != EOF) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
exit(0);
|
||||
break;
|
||||
case 'D':
|
||||
nameserver = optarg;
|
||||
if ( !set_nameserver(nameserver) ) {
|
||||
exit(255);
|
||||
}
|
||||
break;
|
||||
case 'I':
|
||||
stdin_profile_params = 1;
|
||||
break;
|
||||
case 'H':
|
||||
do_xstat = 1;
|
||||
break;
|
||||
case 'L':
|
||||
if ( !InitLog("nfprofile", optarg) )
|
||||
exit(255);
|
||||
break;
|
||||
case 'Z':
|
||||
syntax_only = 1;
|
||||
break;
|
||||
case 'p':
|
||||
profile_datadir = optarg;
|
||||
break;
|
||||
case 'P':
|
||||
profile_statdir = optarg;
|
||||
break;
|
||||
case 'S':
|
||||
subdir_index = atoi(optarg);
|
||||
break;
|
||||
case 'V':
|
||||
printf("%s: Version: %s\n",argv[0], nfdump_version);
|
||||
exit(0);
|
||||
break;
|
||||
case 'f':
|
||||
ffile = optarg;
|
||||
break;
|
||||
case 't':
|
||||
tslot = atoi(optarg);
|
||||
break;
|
||||
case 'M':
|
||||
Mdirs = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
rfile = optarg;
|
||||
break;
|
||||
case 'z':
|
||||
compress = 1;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
if ( subdir_index && !InitHierPath(subdir_index) ) {
|
||||
exit(255);
|
||||
}
|
||||
|
||||
if ( !profile_datadir ) {
|
||||
LogError("Profile data directory required!\n");
|
||||
exit(255);
|
||||
}
|
||||
|
||||
if ( !profile_statdir ) {
|
||||
profile_statdir = profile_datadir;
|
||||
}
|
||||
|
||||
if ( stat(profile_datadir, &stat_buf) || !S_ISDIR(stat_buf.st_mode) ) {
|
||||
LogError("'%s' not a directory\n", profile_datadir);
|
||||
exit(255);
|
||||
}
|
||||
|
||||
if ( stdin_profile_params ) {
|
||||
profile_list = ParseParams(profile_datadir);
|
||||
if ( !profile_list ) {
|
||||
exit(254);
|
||||
}
|
||||
}
|
||||
|
||||
if ( syntax_only ) {
|
||||
filename = NULL;
|
||||
rfile = NULL;
|
||||
} else {
|
||||
char *p;
|
||||
if ( rfile == NULL ) {
|
||||
LogError("-r filename required!\n");
|
||||
exit(255);
|
||||
}
|
||||
p = strrchr(rfile, '/');
|
||||
filename = p == NULL ? rfile : ++p;
|
||||
if ( strlen(filename) == 0 ) {
|
||||
LogError("Filename error: zero length filename\n");
|
||||
exit(254);
|
||||
}
|
||||
}
|
||||
|
||||
if ( chdir(profile_datadir)) {
|
||||
LogError("Error can't chdir to '%s': %s", profile_datadir, strerror(errno));
|
||||
exit(255);
|
||||
}
|
||||
|
||||
num_channels = InitChannels(profile_datadir, profile_statdir, profile_list, ffile, filename, subdir_index, syntax_only, compress, do_xstat);
|
||||
|
||||
// nothing to do
|
||||
if ( num_channels == 0 ) {
|
||||
LogInfo("No channels to process.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( syntax_only ) {
|
||||
printf("Syntax check done.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( !rfile ) {
|
||||
LogError("Input file (-r) required!\n");
|
||||
exit(255);
|
||||
}
|
||||
|
||||
extension_map_list = InitExtensionMaps(NEEDS_EXTENSION_LIST);
|
||||
if ( !InitExporterList() ) {
|
||||
exit(255);
|
||||
}
|
||||
|
||||
SetupInputFileSequence(Mdirs,rfile, NULL);
|
||||
|
||||
process_data(GetChannelInfoList(), num_channels, tslot, do_xstat);
|
||||
|
||||
CloseChannels(tslot, compress);
|
||||
|
||||
FreeExtensionMaps(extension_map_list);
|
||||
|
||||
return 0;
|
||||
}
|
387
bin/nfreader.c
Executable file
387
bin/nfreader.c
Executable file
@ -0,0 +1,387 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: nfreader.c 48 2010-01-02 08:06:27Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 48 $
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* nfreader is sample code for reading nfdump binary files.
|
||||
* It accepts the standard nfdump file select options -r, -M and -R
|
||||
* Therefore it allows you to loop over multiple files and process the netflow record.
|
||||
*
|
||||
* Insert your code in the process_data function after the call to ExpandRecord
|
||||
* To build the binary: first compile nfdump as usual.
|
||||
* Then compile nfreader:
|
||||
*
|
||||
* make nfreader
|
||||
*
|
||||
* This compiles this code and links the required nfdump files
|
||||
* If you do it by hand:
|
||||
*
|
||||
* gcc -c nfreader.c
|
||||
* gcc -o nfreader nfreader.o nffile.o flist.o util.o
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "nffile.h"
|
||||
#include "nfx.h"
|
||||
#include "bookkeeper.h"
|
||||
#include "nfxstat.h"
|
||||
#include "collector.h"
|
||||
#include "exporter.h"
|
||||
#include "util.h"
|
||||
#include "flist.h"
|
||||
|
||||
#if ( SIZEOF_VOID_P == 8 )
|
||||
typedef uint64_t pointer_addr_t;
|
||||
#else
|
||||
typedef uint32_t pointer_addr_t;
|
||||
#endif
|
||||
|
||||
// module limited globals
|
||||
extension_map_list_t *extension_map_list;
|
||||
|
||||
extern generic_exporter_t **exporter_list;
|
||||
|
||||
/* Function Prototypes */
|
||||
static void usage(char *name);
|
||||
|
||||
static void print_record(void *record, char *s );
|
||||
|
||||
static void process_data(void);
|
||||
|
||||
/* Functions */
|
||||
|
||||
#include "nffile_inline.c"
|
||||
|
||||
static void usage(char *name) {
|
||||
printf("usage %s [options] \n"
|
||||
"-h\t\tthis text you see right here\n"
|
||||
"-r\t\tread input from file\n"
|
||||
"-M <expr>\tRead input from multiple directories.\n"
|
||||
"-R <expr>\tRead input from sequence of files.\n"
|
||||
, name);
|
||||
} /* usage */
|
||||
|
||||
static void print_record(void *record, char *s ) {
|
||||
char as[40], ds[40], datestr1[64], datestr2[64];
|
||||
time_t when;
|
||||
struct tm *ts;
|
||||
master_record_t *r = (master_record_t *)record;
|
||||
|
||||
if ( (r->flags & FLAG_IPV6_ADDR ) != 0 ) { // IPv6
|
||||
r->v6.srcaddr[0] = htonll(r->v6.srcaddr[0]);
|
||||
r->v6.srcaddr[1] = htonll(r->v6.srcaddr[1]);
|
||||
r->v6.dstaddr[0] = htonll(r->v6.dstaddr[0]);
|
||||
r->v6.dstaddr[1] = htonll(r->v6.dstaddr[1]);
|
||||
inet_ntop(AF_INET6, r->v6.srcaddr, as, sizeof(as));
|
||||
inet_ntop(AF_INET6, r->v6.dstaddr, ds, sizeof(ds));
|
||||
} else { // IPv4
|
||||
r->v4.srcaddr = htonl(r->v4.srcaddr);
|
||||
r->v4.dstaddr = htonl(r->v4.dstaddr);
|
||||
inet_ntop(AF_INET, &r->v4.srcaddr, as, sizeof(as));
|
||||
inet_ntop(AF_INET, &r->v4.dstaddr, ds, sizeof(ds));
|
||||
}
|
||||
as[40-1] = 0;
|
||||
ds[40-1] = 0;
|
||||
|
||||
when = r->first;
|
||||
ts = localtime(&when);
|
||||
strftime(datestr1, 63, "%Y-%m-%d %H:%M:%S", ts);
|
||||
|
||||
when = r->last;
|
||||
ts = localtime(&when);
|
||||
strftime(datestr2, 63, "%Y-%m-%d %H:%M:%S", ts);
|
||||
|
||||
snprintf(s, 1023, "\n"
|
||||
"Flow Record: \n"
|
||||
" srcaddr = %16s\n"
|
||||
" dstaddr = %16s\n"
|
||||
" first = %10u [%s]\n"
|
||||
" last = %10u [%s]\n"
|
||||
" msec_first = %5u\n"
|
||||
" msec_last = %5u\n"
|
||||
" prot = %3u\n"
|
||||
" srcport = %5u\n"
|
||||
" dstport = %5u\n"
|
||||
" dPkts = %10llu\n"
|
||||
" dOctets = %10llu\n"
|
||||
,
|
||||
as, ds, r->first, datestr1, r->last, datestr2, r->msec_first, r->msec_last,
|
||||
r->prot, r->srcport, r->dstport,
|
||||
(unsigned long long)r->dPkts, (unsigned long long)r->dOctets);
|
||||
|
||||
s[1024-1] = 0;
|
||||
|
||||
} // End of print_record
|
||||
|
||||
|
||||
static void process_data(void) {
|
||||
master_record_t master_record;
|
||||
common_record_t *flow_record;
|
||||
nffile_t *nffile;
|
||||
int i, done, ret;
|
||||
#ifdef COMPAT15
|
||||
int v1_map_done = 0;
|
||||
#endif
|
||||
|
||||
// Get the first file handle
|
||||
nffile = GetNextFile(NULL, 0, 0);
|
||||
if ( !nffile ) {
|
||||
LogError("GetNextFile() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return;
|
||||
}
|
||||
if ( nffile == EMPTY_LIST ) {
|
||||
LogError("Empty file list. No files to process\n");
|
||||
return;
|
||||
}
|
||||
|
||||
done = 0;
|
||||
while ( !done ) {
|
||||
// get next data block from file
|
||||
ret = ReadBlock(nffile);
|
||||
|
||||
switch (ret) {
|
||||
case NF_CORRUPT:
|
||||
case NF_ERROR:
|
||||
if ( ret == NF_CORRUPT )
|
||||
fprintf(stderr, "Skip corrupt data file '%s'\n",GetCurrentFilename());
|
||||
else
|
||||
fprintf(stderr, "Read error in file '%s': %s\n",GetCurrentFilename(), strerror(errno) );
|
||||
// fall through - get next file in chain
|
||||
case NF_EOF: {
|
||||
nffile_t *next = GetNextFile(nffile, 0, 0);
|
||||
if ( next == EMPTY_LIST ) {
|
||||
done = 1;
|
||||
}
|
||||
if ( next == NULL ) {
|
||||
done = 1;
|
||||
LogError("Unexpected end of file list\n");
|
||||
}
|
||||
// else continue with next file
|
||||
continue;
|
||||
|
||||
} break; // not really needed
|
||||
}
|
||||
|
||||
#ifdef COMPAT15
|
||||
if ( nffile->block_header->id == DATA_BLOCK_TYPE_1 ) {
|
||||
common_record_v1_t *v1_record = (common_record_v1_t *)nffile->buff_ptr;
|
||||
// create an extension map for v1 blocks
|
||||
if ( v1_map_done == 0 ) {
|
||||
extension_map_t *map = malloc(sizeof(extension_map_t) + 2 * sizeof(uint16_t) );
|
||||
if ( ! map ) {
|
||||
LogError("malloc() allocation error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
exit(255);
|
||||
}
|
||||
map->type = ExtensionMapType;
|
||||
map->size = sizeof(extension_map_t) + 2 * sizeof(uint16_t);
|
||||
if (( map->size & 0x3 ) != 0 ) {
|
||||
map->size += 4 - ( map->size & 0x3 );
|
||||
}
|
||||
|
||||
map->map_id = INIT_ID;
|
||||
|
||||
map->ex_id[0] = EX_IO_SNMP_2;
|
||||
map->ex_id[1] = EX_AS_2;
|
||||
map->ex_id[2] = 0;
|
||||
|
||||
map->extension_size = 0;
|
||||
|
||||
Insert_Extension_Map(extension_map_list, map);
|
||||
|
||||
v1_map_done = 1;
|
||||
}
|
||||
|
||||
// convert the records to v2
|
||||
for ( i=0; i < nffile->block_header->NumRecords; i++ ) {
|
||||
common_record_t *v2_record = (common_record_t *)v1_record;
|
||||
Convert_v1_to_v2((void *)v1_record);
|
||||
// now we have a v2 record -> use size of v2_record->size
|
||||
v1_record = (common_record_v1_t *)((pointer_addr_t)v1_record + v2_record->size);
|
||||
}
|
||||
nffile->block_header->id = DATA_BLOCK_TYPE_2;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( nffile->block_header->id == Large_BLOCK_Type ) {
|
||||
// skip
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( nffile->block_header->id != DATA_BLOCK_TYPE_2 ) {
|
||||
fprintf(stderr, "Can't process block type %u. Skip block.\n", nffile->block_header->id);
|
||||
continue;
|
||||
}
|
||||
|
||||
flow_record = nffile->buff_ptr;
|
||||
for ( i=0; i < nffile->block_header->NumRecords; i++ ) {
|
||||
char string[1024];
|
||||
|
||||
switch ( flow_record->type ) {
|
||||
case CommonRecordType: {
|
||||
uint32_t map_id = flow_record->ext_map;
|
||||
generic_exporter_t *exp_info = exporter_list[flow_record->exporter_sysid];
|
||||
if ( extension_map_list->slot[map_id] == NULL ) {
|
||||
snprintf(string, 1024, "Corrupt data file! No such extension map id: %u. Skip record", flow_record->ext_map );
|
||||
string[1023] = '\0';
|
||||
} else {
|
||||
ExpandRecord_v2( flow_record, extension_map_list->slot[flow_record->ext_map],
|
||||
exp_info ? &(exp_info->info) : NULL, &master_record);
|
||||
|
||||
// update number of flows matching a given map
|
||||
extension_map_list->slot[map_id]->ref_count++;
|
||||
|
||||
/*
|
||||
* insert hier your calls to your processing routine
|
||||
* master_record now contains the next flow record as specified in nffile.c
|
||||
* for example you can print each record:
|
||||
*
|
||||
*/
|
||||
print_record(&master_record, string);
|
||||
printf("%s\n", string);
|
||||
}
|
||||
|
||||
} break;
|
||||
case ExtensionMapType: {
|
||||
extension_map_t *map = (extension_map_t *)flow_record;
|
||||
|
||||
if ( Insert_Extension_Map(extension_map_list, map) ) {
|
||||
// flush new map
|
||||
} // else map already known and flushed
|
||||
|
||||
} break;
|
||||
case ExporterInfoRecordType:
|
||||
case ExporterStatRecordType:
|
||||
case SamplerInfoRecordype:
|
||||
// Silently skip exporter records
|
||||
break;
|
||||
default: {
|
||||
fprintf(stderr, "Skip unknown record type %i\n", flow_record->type);
|
||||
}
|
||||
}
|
||||
|
||||
// Advance pointer by number of bytes for netflow record
|
||||
flow_record = (common_record_t *)((pointer_addr_t)flow_record + flow_record->size);
|
||||
|
||||
} // for all records
|
||||
|
||||
} // while
|
||||
|
||||
CloseFile(nffile);
|
||||
DisposeFile(nffile);
|
||||
|
||||
PackExtensionMapList(extension_map_list);
|
||||
|
||||
} // End of process_data
|
||||
|
||||
|
||||
int main( int argc, char **argv ) {
|
||||
char *rfile, *Rfile, *Mdirs;
|
||||
int c;
|
||||
|
||||
rfile = Rfile = Mdirs = NULL;
|
||||
while ((c = getopt(argc, argv, "L:r:M:R:")) != EOF) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
exit(0);
|
||||
break;
|
||||
break;
|
||||
case 'L':
|
||||
if ( !InitLog("argv[0]", optarg) )
|
||||
exit(255);
|
||||
break;
|
||||
case 'r':
|
||||
rfile = optarg;
|
||||
if ( strcmp(rfile, "-") == 0 )
|
||||
rfile = NULL;
|
||||
break;
|
||||
case 'M':
|
||||
Mdirs = optarg;
|
||||
break;
|
||||
case 'R':
|
||||
Rfile = optarg;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
if ( rfile && Rfile ) {
|
||||
fprintf(stderr, "-r and -R are mutually exclusive. Please specify either -r or -R\n");
|
||||
exit(255);
|
||||
}
|
||||
if ( Mdirs && !(rfile || Rfile) ) {
|
||||
fprintf(stderr, "-M needs either -r or -R to specify the file or file list. Add '-R .' for all files in the directories.\n");
|
||||
exit(255);
|
||||
}
|
||||
|
||||
extension_map_list = InitExtensionMaps(NEEDS_EXTENSION_LIST);
|
||||
if ( !InitExporterList() ) {
|
||||
exit(255);
|
||||
}
|
||||
|
||||
SetupInputFileSequence(Mdirs, rfile, Rfile);
|
||||
|
||||
process_data();
|
||||
|
||||
FreeExtensionMaps(extension_map_list);
|
||||
|
||||
return 0;
|
||||
}
|
625
bin/nfreplay.c
Normal file
625
bin/nfreplay.c
Normal file
@ -0,0 +1,625 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: nfreplay.c 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "nffile.h"
|
||||
#include "nfx.h"
|
||||
#include "nf_common.h"
|
||||
#include "rbtree.h"
|
||||
#include "nftree.h"
|
||||
#include "nfdump.h"
|
||||
#include "nfnet.h"
|
||||
#include "bookkeeper.h"
|
||||
#include "nfxstat.h"
|
||||
#include "collector.h"
|
||||
#include "exporter.h"
|
||||
#include "netflow_v5_v7.h"
|
||||
#include "netflow_v9.h"
|
||||
#include "nfprof.h"
|
||||
#include "flist.h"
|
||||
#include "util.h"
|
||||
#include "grammar.h"
|
||||
|
||||
#define DEFAULTCISCOPORT "9995"
|
||||
#define DEFAULTHOSTNAME "127.0.0.1"
|
||||
|
||||
#undef FPURGE
|
||||
#ifdef HAVE___FPURGE
|
||||
#define FPURGE __fpurge
|
||||
#endif
|
||||
#ifdef HAVE_FPURGE
|
||||
#define FPURGE fpurge
|
||||
#endif
|
||||
|
||||
/* Externals */
|
||||
extern int yydebug;
|
||||
|
||||
#ifdef COMPAT15
|
||||
extern extension_descriptor_t extension_descriptor[];
|
||||
#endif
|
||||
|
||||
/* Global Variables */
|
||||
FilterEngine_data_t *Engine;
|
||||
int verbose;
|
||||
|
||||
/* Local Variables */
|
||||
static const char *nfdump_version = VERSION;
|
||||
|
||||
send_peer_t peer;
|
||||
|
||||
extension_map_list_t *extension_map_list;
|
||||
|
||||
generic_exporter_t **exporter_list;
|
||||
|
||||
/* Function Prototypes */
|
||||
static void usage(char *name);
|
||||
|
||||
static void send_blast(unsigned int delay );
|
||||
|
||||
static void send_data(char *rfile, time_t twin_start, time_t twin_end, uint32_t count,
|
||||
unsigned int delay, int confirm, int netflow_version);
|
||||
|
||||
static int FlushBuffer(int confirm);
|
||||
|
||||
/* Functions */
|
||||
|
||||
#include "nffile_inline.c"
|
||||
#include "nfdump_inline.c"
|
||||
|
||||
static void usage(char *name) {
|
||||
printf("usage %s [options] [\"filter\"]\n"
|
||||
"-h\t\tthis text you see right here\n"
|
||||
"-V\t\tPrint version and exit.\n"
|
||||
"-H <Host/ip>\tTarget IP address default: 127.0.0.1\n"
|
||||
"-j <mcast>\tSend packets to multicast group\n"
|
||||
"-4\t\tForce IPv4 protocol.\n"
|
||||
"-6\t\tForce IPv6 protocol.\n"
|
||||
"-L <log>\tLog to syslog facility <log>\n"
|
||||
"-p <port>\tTarget port default 9995\n"
|
||||
"-d <usec>\tDelay in usec between packets. default 10\n"
|
||||
"-c <cnt>\tPacket count. default send all packets\n"
|
||||
"-b <bsize>\tSend buffer size.\n"
|
||||
"-r <input>\tread from file. default: stdin\n"
|
||||
"-f <filter>\tfilter syntaxfile\n"
|
||||
"-t <time>\ttime window for sending packets\n"
|
||||
"\t\tyyyy/MM/dd.hh:mm:ss[-yyyy/MM/dd.hh:mm:ss]\n"
|
||||
, name);
|
||||
} /* usage */
|
||||
|
||||
static int FlushBuffer(int confirm) {
|
||||
size_t len = (pointer_addr_t)peer.buff_ptr - (pointer_addr_t)peer.send_buffer;
|
||||
static unsigned long cnt = 1;
|
||||
|
||||
peer.flush = 0;
|
||||
peer.buff_ptr = peer.send_buffer;
|
||||
if ( confirm ) {
|
||||
FPURGE(stdin);
|
||||
printf("Press any key to send next UDP packet [%lu] ", cnt++);
|
||||
fflush(stdout);
|
||||
fgetc(stdin);
|
||||
}
|
||||
return sendto(peer.sockfd, peer.send_buffer, len, 0, (struct sockaddr *)&(peer.addr), peer.addrlen);
|
||||
} // End of FlushBuffer
|
||||
|
||||
|
||||
static void send_blast(unsigned int delay ) {
|
||||
common_flow_header_t *header;
|
||||
nfprof_t profile_data;
|
||||
int i, ret;
|
||||
u_long usec, sec;
|
||||
double fps;
|
||||
|
||||
peer.send_buffer = malloc(1400);
|
||||
if ( !peer.send_buffer ) {
|
||||
perror("Memory allocation error");
|
||||
close(peer.sockfd);
|
||||
return;
|
||||
}
|
||||
header = (common_flow_header_t *)peer.send_buffer;
|
||||
header->version = htons(255);
|
||||
nfprof_start(&profile_data);
|
||||
for ( i = 0; i < 65535; i++ ) {
|
||||
header->count = htons(i);
|
||||
ret = sendto(peer.sockfd, peer.send_buffer, 1400, 0, (struct sockaddr *)&peer.addr, peer.addrlen);
|
||||
if ( ret < 0 || ret != 1400 ) {
|
||||
perror("Error sending data");
|
||||
}
|
||||
|
||||
if ( delay ) {
|
||||
// sleep as specified
|
||||
usleep(delay);
|
||||
}
|
||||
}
|
||||
nfprof_end(&profile_data, 8*65535*1400);
|
||||
|
||||
|
||||
usec = profile_data.used.ru_utime.tv_usec + profile_data.used.ru_stime.tv_usec;
|
||||
sec = profile_data.used.ru_utime.tv_sec + profile_data.used.ru_stime.tv_sec;
|
||||
|
||||
if (usec > 1000000)
|
||||
usec -= 1000000, ++sec;
|
||||
|
||||
if (profile_data.tend.tv_usec < profile_data.tstart.tv_usec)
|
||||
profile_data.tend.tv_usec += 1000000, --profile_data.tend.tv_sec;
|
||||
|
||||
usec = profile_data.tend.tv_usec - profile_data.tstart.tv_usec;
|
||||
sec = profile_data.tend.tv_sec - profile_data.tstart.tv_sec;
|
||||
fps = (double)profile_data.numflows / ((double)sec + ((double)usec/1000000));
|
||||
|
||||
fprintf(stdout, "Wall: %lu.%-3.3lus bps: %-10.1f\n", sec, usec/1000, fps);
|
||||
|
||||
|
||||
} // End of send_blast
|
||||
|
||||
static void send_data(char *rfile, time_t twin_start,
|
||||
time_t twin_end, uint32_t count, unsigned int delay, int confirm, int netflow_version) {
|
||||
master_record_t master_record;
|
||||
common_record_t *flow_record;
|
||||
nffile_t *nffile;
|
||||
int i, done, ret, again;
|
||||
uint32_t numflows, cnt;
|
||||
|
||||
#ifdef COMPAT15
|
||||
int v1_map_done = 0;
|
||||
#endif
|
||||
|
||||
// Get the first file handle
|
||||
nffile = GetNextFile(NULL, twin_start, twin_end);
|
||||
if ( !nffile ) {
|
||||
LogError("GetNextFile() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return;
|
||||
}
|
||||
if ( nffile == EMPTY_LIST ) {
|
||||
LogError("Empty file list. No files to process\n");
|
||||
return;
|
||||
}
|
||||
|
||||
peer.send_buffer = malloc(UDP_PACKET_SIZE);
|
||||
peer.flush = 0;
|
||||
if ( !peer.send_buffer ) {
|
||||
LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
CloseFile(nffile);
|
||||
DisposeFile(nffile);
|
||||
return;
|
||||
}
|
||||
peer.buff_ptr = peer.send_buffer;
|
||||
peer.endp = (void *)((pointer_addr_t)peer.send_buffer + UDP_PACKET_SIZE - 1);
|
||||
|
||||
if ( netflow_version == 5 )
|
||||
Init_v5_v7_output(&peer);
|
||||
else
|
||||
Init_v9_output(&peer);
|
||||
|
||||
numflows = 0;
|
||||
done = 0;
|
||||
|
||||
// setup Filter Engine to point to master_record, as any record read from file
|
||||
// is expanded into this record
|
||||
Engine->nfrecord = (uint64_t *)&master_record;
|
||||
|
||||
cnt = 0;
|
||||
while ( !done ) {
|
||||
// get next data block from file
|
||||
ret = ReadBlock(nffile);
|
||||
|
||||
switch (ret) {
|
||||
case NF_CORRUPT:
|
||||
case NF_ERROR:
|
||||
if ( ret == NF_CORRUPT )
|
||||
LogError("Skip corrupt data file '%s'\n",GetCurrentFilename());
|
||||
else
|
||||
LogError("Read error in file '%s': %s\n",GetCurrentFilename(), strerror(errno) );
|
||||
// fall through - get next file in chain
|
||||
case NF_EOF: {
|
||||
nffile_t *next = GetNextFile(nffile, twin_start, twin_end);
|
||||
if ( next == EMPTY_LIST ) {
|
||||
done = 1;
|
||||
}
|
||||
if ( next == NULL ) {
|
||||
done = 1;
|
||||
LogError("Unexpected end of file list\n");
|
||||
}
|
||||
// else continue with next file
|
||||
continue;
|
||||
|
||||
} break; // not really needed
|
||||
}
|
||||
|
||||
#ifdef COMPAT15
|
||||
if ( nffile->block_header->id == DATA_BLOCK_TYPE_1 ) {
|
||||
common_record_v1_t *v1_record = (common_record_v1_t *)nffile->buff_ptr;
|
||||
// create an extension map for v1 blocks
|
||||
if ( v1_map_done == 0 ) {
|
||||
extension_map_t *map = malloc(sizeof(extension_map_t) + 2 * sizeof(uint16_t) );
|
||||
if ( ! map ) {
|
||||
perror("Memory allocation error");
|
||||
exit(255);
|
||||
}
|
||||
map->type = ExtensionMapType;
|
||||
map->size = sizeof(extension_map_t) + 2 * sizeof(uint16_t);
|
||||
if (( map->size & 0x3 ) != 0 ) {
|
||||
map->size += 4 - ( map->size & 0x3 );
|
||||
}
|
||||
map->map_id = INIT_ID;
|
||||
map->ex_id[0] = EX_IO_SNMP_2;
|
||||
map->ex_id[1] = EX_AS_2;
|
||||
map->ex_id[2] = 0;
|
||||
|
||||
map->extension_size = 0;
|
||||
map->extension_size += extension_descriptor[EX_IO_SNMP_2].size;
|
||||
map->extension_size += extension_descriptor[EX_AS_2].size;
|
||||
|
||||
Insert_Extension_Map(extension_map_list, map);
|
||||
v1_map_done = 1;
|
||||
}
|
||||
|
||||
// convert the records to v2
|
||||
for ( i=0; i < nffile->block_header->NumRecords; i++ ) {
|
||||
common_record_t *v2_record = (common_record_t *)v1_record;
|
||||
Convert_v1_to_v2((void *)v1_record);
|
||||
// now we have a v2 record -> use size of v2_record->size
|
||||
v1_record = (common_record_v1_t *)((pointer_addr_t)v1_record + v2_record->size);
|
||||
}
|
||||
nffile->block_header->id = DATA_BLOCK_TYPE_2;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( nffile->block_header->id != DATA_BLOCK_TYPE_2 ) {
|
||||
LogError("Can't process block type %u. Skip block.\n", nffile->block_header->id);
|
||||
continue;
|
||||
}
|
||||
|
||||
// cnt is the number of blocks, which survived the filter
|
||||
// and added to the output buffer
|
||||
flow_record = nffile->buff_ptr;
|
||||
|
||||
for ( i=0; i < nffile->block_header->NumRecords; i++ ) {
|
||||
int match;
|
||||
|
||||
switch ( flow_record->type ) {
|
||||
case CommonRecordV0Type:
|
||||
case CommonRecordType: {
|
||||
if ( extension_map_list->slot[flow_record->ext_map] == NULL ) {
|
||||
LogError("Corrupt data file. Missing extension map %u. Skip record.\n", flow_record->ext_map);
|
||||
flow_record = (common_record_t *)((pointer_addr_t)flow_record + flow_record->size);
|
||||
continue;
|
||||
}
|
||||
|
||||
// if no filter is given, the result is always true
|
||||
ExpandRecord_v2( flow_record, extension_map_list->slot[flow_record->ext_map], NULL, &master_record);
|
||||
|
||||
match = twin_start && (master_record.first < twin_start || master_record.last > twin_end) ? 0 : 1;
|
||||
|
||||
// filter netflow record with user supplied filter
|
||||
if ( match )
|
||||
match = (*Engine->FilterEngine)(Engine);
|
||||
|
||||
if ( match == 0 ) { // record failed to pass all filters
|
||||
// increment pointer by number of bytes for netflow record
|
||||
flow_record = (common_record_t *)((pointer_addr_t)flow_record + flow_record->size);
|
||||
// go to next record
|
||||
continue;
|
||||
}
|
||||
// Records passed filter -> continue record processing
|
||||
|
||||
if ( netflow_version == 5 )
|
||||
again = Add_v5_output_record(&master_record, &peer);
|
||||
else
|
||||
again = Add_v9_output_record(&master_record, &peer);
|
||||
|
||||
cnt++;
|
||||
numflows++;
|
||||
|
||||
if ( peer.flush ) {
|
||||
ret = FlushBuffer(confirm);
|
||||
|
||||
if ( ret < 0 ) {
|
||||
perror("Error sending data");
|
||||
CloseFile(nffile);
|
||||
DisposeFile(nffile);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( delay ) {
|
||||
// sleep as specified
|
||||
usleep(delay);
|
||||
}
|
||||
cnt = 0;
|
||||
}
|
||||
|
||||
if ( again ) {
|
||||
if ( netflow_version == 5 )
|
||||
Add_v5_output_record(&master_record, &peer);
|
||||
else
|
||||
Add_v9_output_record(&master_record, &peer);
|
||||
cnt++;
|
||||
}
|
||||
|
||||
} break;
|
||||
case ExtensionMapType: {
|
||||
extension_map_t *map = (extension_map_t *)flow_record;
|
||||
|
||||
if ( Insert_Extension_Map(extension_map_list, map) ) {
|
||||
// flush new map
|
||||
|
||||
} // else map already known and flushed
|
||||
|
||||
} break;
|
||||
case ExporterRecordType:
|
||||
case SamplerRecordype:
|
||||
case ExporterInfoRecordType:
|
||||
case ExporterStatRecordType:
|
||||
case SamplerInfoRecordype:
|
||||
// Silently skip exporter/sampler records
|
||||
break;
|
||||
default: {
|
||||
LogError("Skip unknown record type %i\n", flow_record->type);
|
||||
}
|
||||
}
|
||||
// Advance pointer by number of bytes for netflow record
|
||||
flow_record = (common_record_t *)((pointer_addr_t)flow_record + flow_record->size);
|
||||
|
||||
}
|
||||
} // while
|
||||
|
||||
// flush still remaining records
|
||||
if ( cnt ) {
|
||||
ret = FlushBuffer(confirm);
|
||||
|
||||
if ( ret < 0 ) {
|
||||
perror("Error sending data");
|
||||
}
|
||||
|
||||
} // if cnt
|
||||
|
||||
if (nffile) {
|
||||
CloseFile(nffile);
|
||||
DisposeFile(nffile);
|
||||
}
|
||||
|
||||
close(peer.sockfd);
|
||||
|
||||
return;
|
||||
|
||||
} // End of send_data
|
||||
|
||||
|
||||
int main( int argc, char **argv ) {
|
||||
struct stat stat_buff;
|
||||
char *rfile, *ffile, *filter, *tstring;
|
||||
int c, confirm, ffd, ret, blast, netflow_version;
|
||||
unsigned int delay, count, sockbuff_size;
|
||||
time_t t_start, t_end;
|
||||
|
||||
rfile = ffile = filter = tstring = NULL;
|
||||
t_start = t_end = 0;
|
||||
|
||||
peer.hostname = NULL;
|
||||
peer.port = DEFAULTCISCOPORT;
|
||||
peer.mcast = 0;
|
||||
peer.family = AF_UNSPEC;
|
||||
peer.sockfd = 0;
|
||||
|
||||
delay = 1;
|
||||
count = 0xFFFFFFFF;
|
||||
sockbuff_size = 0;
|
||||
netflow_version = 5;
|
||||
blast = 0;
|
||||
verbose = 0;
|
||||
confirm = 0;
|
||||
while ((c = getopt(argc, argv, "46BhH:i:K:L:p:d:c:b:j:r:f:t:v:VY")) != EOF) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
exit(0);
|
||||
break;
|
||||
case 'B':
|
||||
blast = 1;
|
||||
break;
|
||||
case 'V':
|
||||
printf("%s: Version: %s\n",argv[0], nfdump_version);
|
||||
exit(0);
|
||||
break;
|
||||
case 'Y':
|
||||
confirm = 1;
|
||||
break;
|
||||
case 'H':
|
||||
case 'i': // compatibility with old version
|
||||
peer.hostname = strdup(optarg);
|
||||
peer.mcast = 0;
|
||||
break;
|
||||
case 'j':
|
||||
if ( peer.hostname == NULL ) {
|
||||
peer.hostname = strdup(optarg);
|
||||
peer.mcast = 1;
|
||||
} else {
|
||||
LogError("ERROR, -H(-i) and -j are mutually exclusive!!\n");
|
||||
exit(255);
|
||||
}
|
||||
break;
|
||||
case 'K':
|
||||
LogError("*** Anonymization moved! Use nfanon to anonymize flows first!\n");
|
||||
exit(255);
|
||||
break;
|
||||
case 'L':
|
||||
if ( !InitLog(argv[0], optarg) )
|
||||
exit(255);
|
||||
break;
|
||||
case 'p':
|
||||
peer.port = strdup(optarg);
|
||||
break;
|
||||
case 'd':
|
||||
delay = atoi(optarg);
|
||||
break;
|
||||
case 'v':
|
||||
netflow_version = atoi(optarg);
|
||||
if ( netflow_version != 5 && netflow_version != 9 ) {
|
||||
LogError("Invalid netflow version: %s. Accept only 5 or 9!\n", optarg);
|
||||
exit(255);
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
count = atoi(optarg);
|
||||
break;
|
||||
case 'b':
|
||||
sockbuff_size = atoi(optarg);
|
||||
break;
|
||||
case 'f':
|
||||
ffile = optarg;
|
||||
break;
|
||||
case 't':
|
||||
tstring = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
rfile = optarg;
|
||||
break;
|
||||
case '4':
|
||||
if ( peer.family == AF_UNSPEC )
|
||||
peer.family = AF_INET;
|
||||
else {
|
||||
LogError("ERROR, Accepts only one protocol IPv4 or IPv6!\n");
|
||||
exit(255);
|
||||
}
|
||||
break;
|
||||
case '6':
|
||||
if ( peer.family == AF_UNSPEC )
|
||||
peer.family = AF_INET6;
|
||||
else {
|
||||
LogError("ERROR, Accepts only one protocol IPv4 or IPv6!\n");
|
||||
exit(255);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
if (argc - optind > 1) {
|
||||
usage(argv[0]);
|
||||
exit(255);
|
||||
} else {
|
||||
/* user specified a pcap filter */
|
||||
filter = argv[optind];
|
||||
}
|
||||
|
||||
if ( peer.hostname == NULL )
|
||||
peer.hostname = DEFAULTHOSTNAME;
|
||||
|
||||
if ( !filter && ffile ) {
|
||||
if ( stat(ffile, &stat_buff) ) {
|
||||
perror("Can't stat file");
|
||||
exit(255);
|
||||
}
|
||||
filter = (char *)malloc(stat_buff.st_size);
|
||||
if ( !filter ) {
|
||||
perror("Memory error");
|
||||
exit(255);
|
||||
}
|
||||
ffd = open(ffile, O_RDONLY);
|
||||
if ( ffd < 0 ) {
|
||||
perror("Can't open file");
|
||||
exit(255);
|
||||
}
|
||||
ret = read(ffd, (void *)filter, stat_buff.st_size);
|
||||
if ( ret < 0 ) {
|
||||
perror("Error reading file");
|
||||
close(ffd);
|
||||
exit(255);
|
||||
}
|
||||
close(ffd);
|
||||
}
|
||||
|
||||
if ( !filter )
|
||||
filter = "any";
|
||||
|
||||
Engine = CompileFilter(filter);
|
||||
if ( !Engine )
|
||||
exit(254);
|
||||
|
||||
if ( peer.mcast )
|
||||
peer.sockfd = Multicast_send_socket (peer.hostname, peer.port, peer.family, sockbuff_size,
|
||||
&peer.addr, &peer.addrlen );
|
||||
else
|
||||
peer.sockfd = Unicast_send_socket (peer.hostname, peer.port, peer.family, sockbuff_size,
|
||||
&peer.addr, &peer.addrlen );
|
||||
if ( peer.sockfd <= 0 ) {
|
||||
exit(255);
|
||||
}
|
||||
|
||||
if ( blast ) {
|
||||
send_blast(delay );
|
||||
exit(0);
|
||||
}
|
||||
|
||||
extension_map_list = InitExtensionMaps(NEEDS_EXTENSION_LIST);
|
||||
|
||||
SetupInputFileSequence(NULL,rfile, NULL);
|
||||
|
||||
if ( tstring ) {
|
||||
if ( !ScanTimeFrame(tstring, &t_start, &t_end) )
|
||||
exit(255);
|
||||
}
|
||||
|
||||
send_data(rfile, t_start, t_end, count, delay, confirm, netflow_version);
|
||||
|
||||
FreeExtensionMaps(extension_map_list);
|
||||
|
||||
return 0;
|
||||
}
|
1913
bin/nfstat.c
Normal file
1913
bin/nfstat.c
Normal file
File diff suppressed because it is too large
Load Diff
125
bin/nfstat.h
Normal file
125
bin/nfstat.h
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: nfstat.h 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NFSTAT_H
|
||||
#define _NFSTAT_H 1
|
||||
|
||||
/* Definitions */
|
||||
|
||||
|
||||
/*
|
||||
* Stat Table
|
||||
* In order to generate any flow element statistics, the flows passed the filter
|
||||
* are stored into an internal hash table.
|
||||
*/
|
||||
|
||||
typedef struct SumRecord_s {
|
||||
uint64_t flows;
|
||||
uint64_t ipkg;
|
||||
uint64_t opkg;
|
||||
uint64_t ibyte;
|
||||
uint64_t obyte;
|
||||
} SumRecord_t;
|
||||
|
||||
typedef struct StatRecord {
|
||||
// record chain
|
||||
struct StatRecord *next;
|
||||
// flow parameters
|
||||
uint64_t counter[5]; // flows ipkg ibyte opkg obyte
|
||||
uint32_t first;
|
||||
uint32_t last;
|
||||
uint16_t msec_first;
|
||||
uint16_t msec_last;
|
||||
uint8_t record_flags;
|
||||
uint8_t tcp_flags;
|
||||
uint8_t tos;
|
||||
// key
|
||||
uint8_t prot;
|
||||
uint64_t stat_key[2];
|
||||
} StatRecord_t;
|
||||
|
||||
typedef struct hash_StatTable {
|
||||
/* hash table data */
|
||||
uint16_t NumBits; /* width of the hash table */
|
||||
uint32_t IndexMask; /* Mask which corresponds to NumBits */
|
||||
StatRecord_t **bucket; /* Hash entry point: points to elements in the stat block */
|
||||
StatRecord_t **bucketcache; /* in case of index collisions, this array points to the last element with that index */
|
||||
|
||||
/* memory management */
|
||||
/* memory blocks - containing the stat records */
|
||||
StatRecord_t **memblock; /* array holding all NumBlocks allocated stat blocks */
|
||||
uint32_t MaxBlocks; /* Size of memblock array */
|
||||
/* stat blocks - containing the stat records */
|
||||
uint32_t NumBlocks; /* number of allocated stat blocks in memblock array */
|
||||
uint32_t Prealloc; /* Number of stat records in each stat block */
|
||||
uint32_t NextBlock; /* This stat block contains the next free slot for a stat recorrd */
|
||||
uint32_t NextElem; /* This element in the current stat block is the next free slot */
|
||||
} hash_StatTable;
|
||||
|
||||
typedef struct SortElement {
|
||||
void *record;
|
||||
uint64_t count;
|
||||
} SortElement_t;
|
||||
|
||||
#define MULTIPLE_LIST_ORDERS 1
|
||||
#define SINGLE_LIST_ORDER 0
|
||||
|
||||
/* Function prototypes */
|
||||
void SetLimits(int stat, char *packet_limit_string, char *byte_limit_string );
|
||||
|
||||
int Init_StatTable(uint16_t NumBits, uint32_t Prealloc);
|
||||
|
||||
void Dispose_StatTable(void);
|
||||
|
||||
int SetStat(char *str, int *element_stat, int *flow_stat);
|
||||
|
||||
int Parse_PrintOrder(char *order);
|
||||
|
||||
void AddStat(common_record_t *raw_record, master_record_t *flow_record );
|
||||
|
||||
void PrintFlowTable(printer_t print_record, uint32_t limitflows, int tag, int GuessDir, extension_map_list_t *extension_map_list);
|
||||
|
||||
void PrintFlowStat(char *record_header, printer_t print_record, int topN, int tag, int quiet, int cvs_output, extension_map_list_t *extension_map_list);
|
||||
|
||||
void PrintElementStat(stat_record_t *sum_stat, uint32_t limitflows, char *record_header, printer_t print_record, int topN, int tag, int quiet, int pipe_output, int cvs_output);
|
||||
|
||||
int ParseListOrder(char *s, int multiple_orders );
|
||||
|
||||
void PrintSortedFlows(printer_t print_record, uint32_t limitflows, int tag);
|
||||
|
||||
#endif //_NFSTAT_H
|
579
bin/nfstatfile.c
Normal file
579
bin/nfstatfile.c
Normal file
@ -0,0 +1,579 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: nfstatfile.c 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "nfstatfile.h"
|
||||
|
||||
#define stat_filename ".nfstat"
|
||||
|
||||
typedef struct config_def_s {
|
||||
char *name;
|
||||
// int type;
|
||||
uint64_t *value;
|
||||
} config_def_t;
|
||||
|
||||
static dirstat_t dirstat_tmpl;
|
||||
|
||||
static config_def_t config_def[] = {
|
||||
{ "first", &dirstat_tmpl.first},
|
||||
{ "last", &dirstat_tmpl.last },
|
||||
{ "size", &dirstat_tmpl.filesize },
|
||||
{ "maxsize", &dirstat_tmpl.max_size },
|
||||
{ "numfiles", &dirstat_tmpl.numfiles },
|
||||
{ "lifetime", &dirstat_tmpl.max_lifetime },
|
||||
{ "watermark", &dirstat_tmpl.low_water },
|
||||
{ "status", &dirstat_tmpl.status },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
|
||||
#define STACK_BLOCK_SIZE 32
|
||||
|
||||
static int stack_max_entries = 0;
|
||||
static dirstat_env_t *dirstat_stack = NULL;
|
||||
|
||||
static const double _1K = 1024.0;
|
||||
static const double _1M = 1024.0 * 1024.0;
|
||||
static const double _1G = 1024.0 * 1024.0 * 1024.0;
|
||||
static const double _1T = 1024.0 * 1024.0 * 1024.0 * 1024.0;
|
||||
|
||||
static const double _1min = 60.0;
|
||||
static const double _1hour = 3600.0;
|
||||
static const double _1day = 86400.0;
|
||||
static const double _1week = 604800.0;
|
||||
|
||||
/*
|
||||
* expire.c is needed for daemon code as well as normal stdio code
|
||||
* therefore a generic LogError is defined, which maps to the
|
||||
* approriate logging channel - either stderr or syslog
|
||||
*/
|
||||
void LogError(char *format, ...);
|
||||
|
||||
static inline uint64_t string2uint64(char *s);
|
||||
|
||||
static int ParseString(char *str, char **key, char **value);
|
||||
|
||||
static void VerifyStatInfo(dirstat_t *statinfo);
|
||||
|
||||
char *ScaleValue(uint64_t v) {
|
||||
double f = v;
|
||||
static char s[64];
|
||||
|
||||
if ( f < _1K ) { // 1 K 1024
|
||||
snprintf(s, 63, "%llu B", (unsigned long long)v);
|
||||
} else if ( f < _1M ) {
|
||||
snprintf(s, 63, "%llu = %.1f KB", (unsigned long long)v, f / _1K );
|
||||
} else if ( f < _1G ) {
|
||||
snprintf(s, 63, "%llu = %.1f MB", (unsigned long long)v, f / _1M );
|
||||
} else if ( f < _1T ) {
|
||||
snprintf(s, 63, "%llu = %.1f GB", (unsigned long long)v, f / _1G );
|
||||
} else { // everything else in T
|
||||
snprintf(s, 63, "%llu = %.1f TB", (unsigned long long)v, f / _1T );
|
||||
}
|
||||
s[63] = '\0';
|
||||
|
||||
return s;
|
||||
|
||||
} // End of ScaleValue
|
||||
|
||||
char *ScaleTime(uint64_t v) {
|
||||
double f = v;
|
||||
static char s[64];
|
||||
|
||||
if ( f < _1min ) {
|
||||
snprintf(s, 63, "%llu sec", (unsigned long long)v);
|
||||
} else if ( f < _1hour ) {
|
||||
snprintf(s, 63, "%llu = %.1f min", (unsigned long long)v, f / _1min );
|
||||
} else if ( f < _1day ) {
|
||||
snprintf(s, 63, "%llu = %.1f hours", (unsigned long long)v, f / _1hour );
|
||||
} else if ( f < _1week ) {
|
||||
snprintf(s, 63, "%llu = %.1f days", (unsigned long long)v, f / _1day );
|
||||
} else { // everything else in weeks
|
||||
snprintf(s, 63, "%llu = %.1f weeks", (unsigned long long)v, f / _1week );
|
||||
}
|
||||
s[63] = '\0';
|
||||
|
||||
return s;
|
||||
|
||||
} // End of ScaleValue
|
||||
|
||||
|
||||
static inline uint64_t string2uint64(char *s) {
|
||||
uint64_t u=0;
|
||||
char *p = s;
|
||||
|
||||
while( *p ) {
|
||||
if ( *p < '0' || *p > '9' )
|
||||
*p = '0';
|
||||
u = 10LL*u + (*p++ - 48);
|
||||
}
|
||||
return u;
|
||||
|
||||
} // End of string2uint64
|
||||
|
||||
static int SetFileLock(int fd) {
|
||||
struct flock fl;
|
||||
|
||||
fl.l_type = F_WRLCK; /* F_RDLCK, F_WRLCK, F_UNLCK */
|
||||
fl.l_whence = SEEK_SET; /* SEEK_SET, SEEK_CUR, SEEK_END */
|
||||
fl.l_start = 0; /* Offset from l_whence */
|
||||
fl.l_len = 0; /* length, 0 = to EOF */
|
||||
fl.l_pid = getpid(); /* our PID */
|
||||
|
||||
return fcntl(fd, F_SETLKW, &fl); /* F_GETLK, F_SETLK, F_SETLKW */
|
||||
|
||||
} // End of SetFileLock
|
||||
|
||||
static int ReleaseFileLock(int fd) {
|
||||
struct flock fl;
|
||||
|
||||
fl.l_type = F_UNLCK; /* F_RDLCK, F_WRLCK, F_UNLCK */
|
||||
fl.l_whence = SEEK_SET; /* SEEK_SET, SEEK_CUR, SEEK_END */
|
||||
fl.l_start = 0; /* Offset from l_whence */
|
||||
fl.l_len = 0; /* length, 0 = to EOF */
|
||||
fl.l_pid = getpid(); /* our PID */
|
||||
|
||||
return fcntl(fd, F_SETLK, &fl); /* set the region to unlocked */
|
||||
|
||||
} // End of SetFileLock
|
||||
|
||||
static int ParseString(char *str, char **key, char **value) {
|
||||
char *k, *v, *w;
|
||||
|
||||
k = str;
|
||||
v = strpbrk(str, "=");
|
||||
if ( !v ) {
|
||||
printf("Invalid config line: '%s'\n", str);
|
||||
*key = NULL;
|
||||
*value = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*v++ = '\0';
|
||||
|
||||
// strip white spaces from end of key
|
||||
w = strpbrk(k, " ");
|
||||
if ( w )
|
||||
*w = '\0';
|
||||
|
||||
// strip white spaces from start of value
|
||||
while ( *v == ' ' ) {
|
||||
v++;
|
||||
}
|
||||
|
||||
*key = k;
|
||||
*value = v;
|
||||
|
||||
return 1;
|
||||
|
||||
} // End of ParseString
|
||||
|
||||
static void VerifyStatInfo(dirstat_t *statinfo) {
|
||||
|
||||
if ( ( statinfo->first == 0 ) || ( statinfo->first > statinfo->last ||
|
||||
( statinfo->status > FORCE_REBUILD ) || ( statinfo->low_water > 100 ) ) )
|
||||
statinfo->status = FORCE_REBUILD; // -> fishy
|
||||
|
||||
} // End of VerifyStatInfo
|
||||
|
||||
/*
|
||||
* Reads the stat record from .nfstat file
|
||||
* dirname: directory to read the .nfstat file
|
||||
* dirstat_p: Assign a point of the result to this pointer
|
||||
* lock: READ_ONLY file is locked while reading, and unlocked and closed thereafter
|
||||
* CREATE_AND_LOCK if file does not exists, create it - continue as LOCK_IF_EXISTS
|
||||
* LOCK_IF_EXISTS: lock the file if it exists - file remains open
|
||||
* If file does not exists, an empty record is returned.
|
||||
*/
|
||||
int ReadStatInfo(char *dirname, dirstat_t **dirstat_p, int lock ) {
|
||||
struct stat filestat;
|
||||
char *in_buff, *s, *p, *k, *v;
|
||||
char filename[MAXPATHLEN];
|
||||
int fd, err, r_size, next_free;
|
||||
|
||||
*dirstat_p = NULL;
|
||||
|
||||
// if the dirstack does not exist, creat it
|
||||
if ( !dirstat_stack ) {
|
||||
int i;
|
||||
dirstat_stack = (dirstat_env_t *)malloc(STACK_BLOCK_SIZE * sizeof(dirstat_env_t));
|
||||
if ( !dirstat_stack ) {
|
||||
LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return ERR_FAIL;
|
||||
}
|
||||
for ( i=0; i<STACK_BLOCK_SIZE; i++ ) {
|
||||
dirstat_stack[i].dirstat = NULL;
|
||||
}
|
||||
stack_max_entries = STACK_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
// search for next free slot
|
||||
next_free = 0;
|
||||
while ( next_free < stack_max_entries && (dirstat_stack[next_free].dirstat != NULL) )
|
||||
next_free++;
|
||||
|
||||
// if too many entries exist, expand the stack
|
||||
if ( next_free >= stack_max_entries ) {
|
||||
dirstat_env_t *tmp;
|
||||
int i;
|
||||
tmp = realloc((void *)dirstat_stack, (stack_max_entries+STACK_BLOCK_SIZE) * sizeof(dirstat_env_t));
|
||||
if ( !tmp ) {
|
||||
LogError("ralloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return ERR_FAIL;
|
||||
}
|
||||
dirstat_stack = tmp;
|
||||
for ( i=stack_max_entries; i<stack_max_entries+STACK_BLOCK_SIZE; i++ ) {
|
||||
dirstat_stack[i].dirstat = NULL;
|
||||
}
|
||||
next_free = stack_max_entries;
|
||||
stack_max_entries += STACK_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
dirstat_stack[next_free].dirstat = (dirstat_t *)malloc(sizeof(dirstat_t));
|
||||
if ( !dirstat_stack[next_free].dirstat ) {
|
||||
LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return ERR_FAIL;
|
||||
}
|
||||
|
||||
// Initialize config
|
||||
snprintf(filename, MAXPATHLEN-1, "%s/%s", dirname, stat_filename);
|
||||
filename[MAXPATHLEN-1] = '\0';
|
||||
|
||||
memset((void *)dirstat_stack[next_free].dirstat, 0, sizeof(dirstat_t));
|
||||
memset((void *)&dirstat_tmpl, 0, sizeof(dirstat_t));
|
||||
dirstat_tmpl.low_water = 95; // defaults to 95%
|
||||
dirstat_tmpl.status = FORCE_REBUILD; // in case status is not set -> fishy
|
||||
*dirstat_p = dirstat_stack[next_free].dirstat;
|
||||
dirstat_stack[next_free].fd = 0;
|
||||
dirstat_stack[next_free].filename = strdup(filename);
|
||||
|
||||
|
||||
fd = open(filename, O_RDWR, 0);
|
||||
if ( fd < 0 ) {
|
||||
if ( errno == ENOENT ) {
|
||||
if ( lock == READ_ONLY || lock == LOCK_IF_EXISTS) { // no lock need
|
||||
return ERR_NOSTATFILE;
|
||||
} else { // create the file, to and lock the file
|
||||
fd = open(filename, O_RDWR|O_TRUNC|O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
if ( fd < 0 ) {
|
||||
LogError("open() error on '%s' in %s line %d: %s\n", filename, __FILE__, __LINE__, strerror(errno) );
|
||||
free(dirstat_stack[next_free].dirstat);
|
||||
dirstat_stack[next_free].dirstat = NULL;
|
||||
return ERR_FAIL;
|
||||
}
|
||||
err = SetFileLock(fd);
|
||||
if ( err != 0 ) {
|
||||
LogError("ioctl(F_WRLCK) error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
close(fd);
|
||||
free(dirstat_stack[next_free].dirstat);
|
||||
dirstat_stack[next_free].dirstat = NULL;
|
||||
return ERR_FAIL;
|
||||
}
|
||||
dirstat_stack[next_free].fd = fd;
|
||||
return ERR_NOSTATFILE;
|
||||
}
|
||||
} else {
|
||||
LogError("open() error on '%s' in %s line %d: %s\n", filename, __FILE__, __LINE__, strerror(errno) );
|
||||
free(dirstat_stack[next_free].dirstat);
|
||||
dirstat_stack[next_free].dirstat = NULL;
|
||||
return ERR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
err = SetFileLock(fd);
|
||||
if ( err != 0 ) {
|
||||
LogError("ioctl(F_WRLCK) error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
close(fd);
|
||||
free(dirstat_stack[next_free].dirstat);
|
||||
dirstat_stack[next_free].dirstat = NULL;
|
||||
return ERR_FAIL;
|
||||
}
|
||||
|
||||
fstat(fd, &filestat);
|
||||
// the file is not assumed to be larger than 1MB, otherwise it is likely corrupt
|
||||
if ( filestat.st_size > 1024*1024 ) {
|
||||
LogError("File size error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
ReleaseFileLock(fd);
|
||||
close(fd);
|
||||
free(dirstat_stack[next_free].dirstat);
|
||||
dirstat_stack[next_free].dirstat = NULL;
|
||||
return ERR_FAIL;
|
||||
}
|
||||
|
||||
in_buff = (char *)malloc(filestat.st_size+1); // +1 for trailing '\0'
|
||||
if ( !in_buff ) {
|
||||
LogError("mallow() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
ReleaseFileLock(fd);
|
||||
close(fd);
|
||||
free(dirstat_stack[next_free].dirstat);
|
||||
dirstat_stack[next_free].dirstat = NULL;
|
||||
return ERR_FAIL;
|
||||
}
|
||||
|
||||
r_size = read(fd, (void *)in_buff, filestat.st_size);
|
||||
if ( r_size < 0 ) {
|
||||
LogError("read() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
ReleaseFileLock(fd);
|
||||
close(fd);
|
||||
free(in_buff);
|
||||
free(dirstat_stack[next_free].dirstat);
|
||||
dirstat_stack[next_free].dirstat = NULL;
|
||||
return ERR_FAIL;
|
||||
}
|
||||
in_buff[filestat.st_size] = '\0';
|
||||
|
||||
if ( r_size != filestat.st_size ) {
|
||||
LogError("read() requested size error in %s line %d\n", __FILE__, __LINE__);
|
||||
ReleaseFileLock(fd);
|
||||
close(fd);
|
||||
free(in_buff);
|
||||
free(dirstat_stack[next_free].dirstat);
|
||||
dirstat_stack[next_free].dirstat = NULL;
|
||||
return ERR_FAIL;
|
||||
}
|
||||
|
||||
if ( lock == READ_ONLY ) {
|
||||
ReleaseFileLock(fd);
|
||||
close(fd);
|
||||
} else {
|
||||
dirstat_stack[next_free].fd = fd;
|
||||
}
|
||||
|
||||
p = in_buff;
|
||||
while ( p && *p ) {
|
||||
if ( *p == '#' ) { // skip comments
|
||||
s = strpbrk(p, "\n");
|
||||
if ( s ) { // "\n" found - advance p
|
||||
*s = '\0';
|
||||
printf("comment: '%s'\n",p);
|
||||
p = s+1;
|
||||
continue; // next line
|
||||
}
|
||||
}
|
||||
|
||||
// get gext key=value pair
|
||||
s = strpbrk(p, "\n");
|
||||
if ( s )
|
||||
*s = '\0';
|
||||
|
||||
if ( ParseString(p, &k, &v) ) {
|
||||
uint32_t i;
|
||||
i = 0;
|
||||
while ( config_def[i].name ) {
|
||||
if ( strcmp(config_def[i].name, k) == 0 ) {
|
||||
*(config_def[i].value) = string2uint64(v);
|
||||
// printf("key: '%s', value '%s' int: %llu\n", k,v, *(config_def[i].value));
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if ( config_def[i].name == NULL ) {
|
||||
printf("Invalid config key: '%s'\n", k);
|
||||
}
|
||||
}
|
||||
p = s;
|
||||
if ( p )
|
||||
p++;
|
||||
}
|
||||
VerifyStatInfo(&dirstat_tmpl);
|
||||
*dirstat_stack[next_free].dirstat = dirstat_tmpl;
|
||||
|
||||
free(in_buff);
|
||||
return dirstat_tmpl.status;
|
||||
|
||||
} // End of ReadStatInfo
|
||||
|
||||
int WriteStatInfo(dirstat_t *dirstat) {
|
||||
int i, index, fd, err;
|
||||
char *filename, line[256];
|
||||
|
||||
// search for entry in dirstat stack
|
||||
for (i=0; dirstat_stack[i].dirstat != dirstat && i < stack_max_entries; i++ ) {}
|
||||
|
||||
if ( i >= stack_max_entries ) {
|
||||
LogError( "WriteStatInfo(): dirstat entry not found in %s line %d\n", __FILE__, __LINE__ );
|
||||
return ERR_FAIL;
|
||||
}
|
||||
|
||||
index = i;
|
||||
|
||||
fd = dirstat_stack[index].fd;
|
||||
filename = dirstat_stack[index].filename;
|
||||
|
||||
if ( fd == 0 ) {
|
||||
fd = open(filename, O_RDWR|O_TRUNC|O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
if ( fd < 0 ) {
|
||||
LogError( "open() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return ERR_FAIL;
|
||||
}
|
||||
|
||||
err = SetFileLock(fd);
|
||||
if ( err != 0 ) {
|
||||
LogError( "ioctl(F_WRLCK) error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
close(fd);
|
||||
return ERR_FAIL;
|
||||
}
|
||||
} else {
|
||||
err = lseek(fd, SEEK_SET, 0);
|
||||
if ( err == -1 ) {
|
||||
LogError( "lseek() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
ReleaseFileLock(fd);
|
||||
close(fd);
|
||||
return ERR_FAIL;
|
||||
}
|
||||
if ( ftruncate(fd, 0) < 0 ) {
|
||||
LogError( "ftruncate() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
}
|
||||
}
|
||||
|
||||
dirstat_tmpl = *dirstat_stack[index].dirstat;
|
||||
i = 0;
|
||||
while ( config_def[i].name ) {
|
||||
size_t len;
|
||||
snprintf(line, 255, "%s=%llu\n", config_def[i].name, (unsigned long long)*(config_def[i].value));
|
||||
line[255] = '\0';
|
||||
len = strlen(line);
|
||||
if ( write(fd, line, len) < 0 ) {
|
||||
LogError( "write() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
ReleaseFileLock(fd);
|
||||
err = close(fd);
|
||||
dirstat_stack[index].fd = 0;
|
||||
if ( err == -1 ) {
|
||||
LogError( "close() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return ERR_FAIL;
|
||||
}
|
||||
|
||||
return STATFILE_OK;
|
||||
|
||||
} // End of WriteStatInfo
|
||||
|
||||
int ReleaseStatInfo(dirstat_t *dirstat) {
|
||||
int i, index;
|
||||
|
||||
// search for entry in dirstat stack
|
||||
for (i=0; dirstat_stack[i].dirstat != dirstat && i < stack_max_entries; i++ ) {}
|
||||
|
||||
if ( i >= stack_max_entries ) {
|
||||
LogError( "ReleaseStatInfo() error in %s line %d: %s\n", __FILE__, __LINE__, "dirstat entry not found" );
|
||||
return ERR_FAIL;
|
||||
}
|
||||
|
||||
index = i;
|
||||
if ( dirstat_stack[index].filename == NULL ) {
|
||||
LogError( "ReleaseStatInfo() error in %s line %d: %s\n", __FILE__, __LINE__, "Attempted to free NULL pointer" );
|
||||
return ERR_FAIL;
|
||||
}
|
||||
free(dirstat_stack[index].filename);
|
||||
|
||||
free(dirstat_stack[index].dirstat);
|
||||
dirstat_stack[index].dirstat = NULL;
|
||||
|
||||
return 0;
|
||||
|
||||
} // End of ReleaseStatInfo
|
||||
|
||||
void PrintDirStat(dirstat_t *dirstat) {
|
||||
struct tm *ts;
|
||||
time_t t;
|
||||
char string[32];
|
||||
|
||||
t = dirstat->first;
|
||||
ts = localtime(&t);
|
||||
strftime(string, 31, "%Y-%m-%d %H:%M:%S", ts);
|
||||
string[31] = '\0';
|
||||
printf("First: %s\n", string);
|
||||
|
||||
t = dirstat->last;
|
||||
ts = localtime(&t);
|
||||
strftime(string, 31, "%Y-%m-%d %H:%M:%S", ts);
|
||||
string[31] = '\0';
|
||||
printf("Last: %s\n", string);
|
||||
|
||||
printf("Lifetime: %s\n", ScaleTime(dirstat->last - dirstat->first));
|
||||
|
||||
printf("Numfiles: %llu\n", (unsigned long long)dirstat->numfiles);
|
||||
printf("Filesize: %s\n", ScaleValue(dirstat->filesize));
|
||||
|
||||
if ( dirstat->max_size )
|
||||
printf("Max Size: %s\n", ScaleValue(dirstat->max_size));
|
||||
else
|
||||
printf("Max Size: <none>\n");
|
||||
|
||||
if ( dirstat->max_lifetime )
|
||||
printf("Max Life: %s\n", ScaleTime(dirstat->max_lifetime));
|
||||
else
|
||||
printf("Max Life: <none>\n");
|
||||
|
||||
printf("Watermark: %llu%%\n", (unsigned long long)dirstat->low_water);
|
||||
|
||||
switch(dirstat->status) {
|
||||
case STATFILE_OK:
|
||||
printf("Status: OK\n");
|
||||
break;
|
||||
case FORCE_REBUILD:
|
||||
printf("Status: Force rebuild\n");
|
||||
break;
|
||||
default:
|
||||
printf("Status: Unexpected: %llu\n", (unsigned long long)dirstat->status);
|
||||
break;
|
||||
}
|
||||
} // End of PrintDirStat
|
||||
|
||||
|
80
bin/nfstatfile.h
Normal file
80
bin/nfstatfile.h
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: nfstatfile.h 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NFSTATFILE_H
|
||||
#define _NFSTATFILE_H 1
|
||||
|
||||
typedef struct dirstat_s {
|
||||
uint64_t first; // for more easy parsing and assigning, take a uint64_t also for the time_t type
|
||||
uint64_t last;
|
||||
uint64_t numfiles;
|
||||
uint64_t filesize;
|
||||
uint64_t max_size;
|
||||
uint64_t max_lifetime;
|
||||
uint64_t low_water;
|
||||
uint64_t status;
|
||||
} dirstat_t;
|
||||
|
||||
typedef struct dirstat_env_s {
|
||||
dirstat_t *dirstat;
|
||||
int fd;
|
||||
char *filename;
|
||||
int index;
|
||||
} dirstat_env_t;
|
||||
|
||||
enum { STATFILE_OK = 0, ERR_FAIL, ERR_NOSTATFILE, FORCE_REBUILD };
|
||||
|
||||
#define READ_ONLY 0
|
||||
#define CREATE_AND_LOCK 1
|
||||
#define LOCK_IF_EXISTS 2
|
||||
|
||||
#define stat_filename ".nfstat"
|
||||
|
||||
char *ScaleValue(uint64_t v);
|
||||
|
||||
char *ScaleTime(uint64_t v);
|
||||
|
||||
void PrintDirStat(dirstat_t *dirstat);
|
||||
|
||||
int ReadStatInfo(char *dirname, dirstat_t **dirstat_p, int lock );
|
||||
|
||||
int WriteStatInfo(dirstat_t *dirstat);
|
||||
|
||||
int ReleaseStatInfo(dirstat_t *dirstat);
|
||||
|
||||
#endif //_NFSTATFILE_H
|
1244
bin/nftest.c
Normal file
1244
bin/nftest.c
Normal file
File diff suppressed because it is too large
Load Diff
631
bin/nftree.c
Normal file
631
bin/nftree.c
Normal file
@ -0,0 +1,631 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: nftree.c 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "rbtree.h"
|
||||
#include "nfdump.h"
|
||||
#include "nffile.h"
|
||||
#include "nf_common.h"
|
||||
#include "ipconv.h"
|
||||
#include "nftree.h"
|
||||
|
||||
#include "grammar.h"
|
||||
|
||||
/*
|
||||
* netflow filter engine
|
||||
*
|
||||
*/
|
||||
|
||||
extern char *CurrentIdent;
|
||||
|
||||
#define MAXBLOCKS 1024
|
||||
|
||||
static FilterBlock_t *FilterTree;
|
||||
static uint32_t memblocks;
|
||||
|
||||
static uint32_t NumBlocks = 1; /* index 0 reserved */
|
||||
|
||||
#define IdentNumBlockSize 32
|
||||
static uint16_t MaxIdents;
|
||||
static uint16_t NumIdents;
|
||||
static char **IdentList;
|
||||
|
||||
static void UpdateList(uint32_t a, uint32_t b);
|
||||
|
||||
/* flow processing functions */
|
||||
static inline void pps_function(uint64_t *record_data, uint64_t *comp_values);
|
||||
static inline void bps_function(uint64_t *record_data, uint64_t *comp_values);
|
||||
static inline void bpp_function(uint64_t *record_data, uint64_t *comp_values);
|
||||
static inline void duration_function(uint64_t *record_data, uint64_t *comp_values);
|
||||
static inline void mpls_eos_function(uint64_t *record_data, uint64_t *comp_values);
|
||||
static inline void mpls_any_function(uint64_t *record_data, uint64_t *comp_values);
|
||||
static inline void pblock_function(uint64_t *record_data, uint64_t *comp_values);
|
||||
|
||||
/*
|
||||
* flow processing function table:
|
||||
* order of entries must correspond with filter functions enum in nftree.h
|
||||
*/
|
||||
static struct flow_procs_map_s {
|
||||
char *name;
|
||||
flow_proc_t function;
|
||||
} flow_procs_map[] = {
|
||||
{"none", NULL},
|
||||
{"pps", pps_function},
|
||||
{"bps", bps_function},
|
||||
{"bpp", bpp_function},
|
||||
{"duration", duration_function},
|
||||
{"mpls eos", mpls_eos_function},
|
||||
{"mpls any", mpls_any_function},
|
||||
{"pblock", pblock_function},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
uint64_t *IPstack = NULL;
|
||||
uint32_t StartNode;
|
||||
uint16_t Extended;
|
||||
|
||||
// 128bit compare for IPv6
|
||||
static int IPNodeCMP(struct IPListNode *e1, struct IPListNode *e2) {
|
||||
uint64_t ip_e1[2], ip_e2[2];
|
||||
|
||||
ip_e1[0] = e1->ip[0] & e2->mask[0];
|
||||
ip_e1[1] = e1->ip[1] & e2->mask[1];
|
||||
|
||||
ip_e2[0] = e2->ip[0] & e1->mask[0];
|
||||
ip_e2[1] = e2->ip[1] & e1->mask[1];
|
||||
|
||||
if ( ip_e1[0] == ip_e2[0] ) {
|
||||
if ( ip_e1[1] == ip_e2[1] )
|
||||
return 0;
|
||||
else
|
||||
return (ip_e1[1] < ip_e2[1] ? -1 : 1);
|
||||
} else {
|
||||
return (ip_e1[0] < ip_e2[0] ? -1 : 1);
|
||||
}
|
||||
|
||||
} // End of IPNodeCMP
|
||||
|
||||
// 64bit uint64 compare
|
||||
static int ULNodeCMP(struct ULongListNode *e1, struct ULongListNode *e2) {
|
||||
if ( e1->value == e2->value )
|
||||
return 0;
|
||||
else
|
||||
return (e1->value < e2->value ? -1 : 1);
|
||||
|
||||
} // End of ULNodeCMP
|
||||
|
||||
// Insert the IP RB tree code here
|
||||
RB_GENERATE(IPtree, IPListNode, entry, IPNodeCMP);
|
||||
|
||||
// Insert the Ulong RB tree code here
|
||||
RB_GENERATE(ULongtree, ULongListNode, entry, ULNodeCMP);
|
||||
|
||||
void InitTree(void) {
|
||||
memblocks = 1;
|
||||
FilterTree = (FilterBlock_t *)malloc(MAXBLOCKS * sizeof(FilterBlock_t));
|
||||
if ( !FilterTree ) {
|
||||
fprintf(stderr, "Memory allocation error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
exit(255);
|
||||
}
|
||||
ClearFilter();
|
||||
} // End of InitTree
|
||||
|
||||
/*
|
||||
* Clear Filter
|
||||
*/
|
||||
void ClearFilter(void) {
|
||||
|
||||
NumBlocks = 1;
|
||||
Extended = 0;
|
||||
MaxIdents = 0;
|
||||
NumIdents = 0;
|
||||
IdentList = NULL;
|
||||
memset((void *)FilterTree, 0, MAXBLOCKS * sizeof(FilterBlock_t));
|
||||
|
||||
} /* End of ClearFilter */
|
||||
|
||||
FilterEngine_data_t *CompileFilter(char *FilterSyntax) {
|
||||
FilterEngine_data_t *engine;
|
||||
int ret;
|
||||
|
||||
if ( !FilterSyntax )
|
||||
return NULL;
|
||||
|
||||
IPstack = (uint64_t *)malloc(16 * MAXHOSTS);
|
||||
if ( !IPstack ) {
|
||||
fprintf(stderr, "Memory allocation error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
exit(255);
|
||||
}
|
||||
|
||||
if ( !InitSymbols() )
|
||||
exit(255);
|
||||
InitTree();
|
||||
lex_init(FilterSyntax);
|
||||
ret = yyparse();
|
||||
if ( ret != 0 ) {
|
||||
return NULL;
|
||||
}
|
||||
lex_cleanup();
|
||||
free(IPstack);
|
||||
|
||||
engine = malloc(sizeof(FilterEngine_data_t));
|
||||
if ( !engine ) {
|
||||
fprintf(stderr, "Memory allocation error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
exit(255);
|
||||
}
|
||||
engine->nfrecord = NULL;
|
||||
engine->StartNode = StartNode;
|
||||
engine->Extended = Extended;
|
||||
engine->IdentList = IdentList;
|
||||
engine->filter = FilterTree;
|
||||
if ( Extended )
|
||||
engine->FilterEngine = RunExtendedFilter;
|
||||
else
|
||||
engine->FilterEngine = RunFilter;
|
||||
|
||||
return engine;
|
||||
|
||||
} // End of GetTree
|
||||
|
||||
/*
|
||||
* For testing purpose only
|
||||
*/
|
||||
int nblocks(void) {
|
||||
return NumBlocks - 1;
|
||||
} /* End of nblocks */
|
||||
|
||||
/*
|
||||
* Returns next free slot in blocklist
|
||||
*/
|
||||
uint32_t NewBlock(uint32_t offset, uint64_t mask, uint64_t value, uint16_t comp, uint32_t function, void *data) {
|
||||
uint32_t n = NumBlocks;
|
||||
|
||||
if ( n >= ( memblocks * MAXBLOCKS ) ) {
|
||||
memblocks++;
|
||||
FilterTree = realloc(FilterTree, memblocks * MAXBLOCKS * sizeof(FilterBlock_t));
|
||||
if ( !FilterTree ) {
|
||||
fprintf(stderr, "Memory allocation error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
exit(255);
|
||||
}
|
||||
}
|
||||
|
||||
FilterTree[n].offset = offset;
|
||||
FilterTree[n].mask = mask;
|
||||
FilterTree[n].value = value;
|
||||
FilterTree[n].invert = 0;
|
||||
FilterTree[n].OnTrue = 0;
|
||||
FilterTree[n].OnFalse = 0;
|
||||
FilterTree[n].comp = comp;
|
||||
FilterTree[n].function = flow_procs_map[function].function;
|
||||
FilterTree[n].fname = flow_procs_map[function].name;
|
||||
FilterTree[n].data = data;
|
||||
if ( comp > 0 || function > 0 )
|
||||
Extended = 1;
|
||||
|
||||
FilterTree[n].numblocks = 1;
|
||||
FilterTree[n].blocklist = (uint32_t *)malloc(sizeof(uint32_t));
|
||||
FilterTree[n].superblock = n;
|
||||
FilterTree[n].blocklist[0] = n;
|
||||
NumBlocks++;
|
||||
return n;
|
||||
|
||||
} /* End of NewBlock */
|
||||
|
||||
/*
|
||||
* Connects the two blocks b1 and b2 ( AND ) and returns index of superblock
|
||||
*/
|
||||
uint32_t Connect_AND(uint32_t b1, uint32_t b2) {
|
||||
|
||||
uint32_t a, b, i, j;
|
||||
|
||||
if ( FilterTree[b1].numblocks <= FilterTree[b2].numblocks ) {
|
||||
a = b1;
|
||||
b = b2;
|
||||
} else {
|
||||
a = b2;
|
||||
b = b1;
|
||||
}
|
||||
/* a points to block with less children and becomes the superblock
|
||||
* connect b to a
|
||||
*/
|
||||
for ( i=0; i < FilterTree[a].numblocks; i++ ) {
|
||||
j = FilterTree[a].blocklist[i];
|
||||
if ( FilterTree[j].invert ) {
|
||||
if ( FilterTree[j].OnFalse == 0 ) {
|
||||
FilterTree[j].OnFalse = b;
|
||||
}
|
||||
} else {
|
||||
if ( FilterTree[j].OnTrue == 0 ) {
|
||||
FilterTree[j].OnTrue = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
UpdateList(a,b);
|
||||
return a;
|
||||
|
||||
} /* End of Connect_AND */
|
||||
|
||||
/*
|
||||
* Connects the two blocks b1 and b2 ( OR ) and returns index of superblock
|
||||
*/
|
||||
uint32_t Connect_OR(uint32_t b1, uint32_t b2) {
|
||||
|
||||
uint32_t a, b, i, j;
|
||||
|
||||
if ( FilterTree[b1].numblocks <= FilterTree[b2].numblocks ) {
|
||||
a = b1;
|
||||
b = b2;
|
||||
} else {
|
||||
a = b2;
|
||||
b = b1;
|
||||
}
|
||||
/* a points to block with less children and becomes the superblock
|
||||
* connect b to a
|
||||
*/
|
||||
for ( i=0; i < FilterTree[a].numblocks; i++ ) {
|
||||
j = FilterTree[a].blocklist[i];
|
||||
if ( FilterTree[j].invert ) {
|
||||
if ( FilterTree[j].OnTrue == 0 ) {
|
||||
FilterTree[j].OnTrue = b;
|
||||
}
|
||||
} else {
|
||||
if ( FilterTree[j].OnFalse == 0 ) {
|
||||
FilterTree[j].OnFalse = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
UpdateList(a,b);
|
||||
return a;
|
||||
|
||||
} /* End of Connect_OR */
|
||||
|
||||
/*
|
||||
* Inverts OnTrue and OnFalse
|
||||
*/
|
||||
uint32_t Invert(uint32_t a) {
|
||||
uint32_t i, j;
|
||||
|
||||
for ( i=0; i< FilterTree[a].numblocks; i++ ) {
|
||||
j = FilterTree[a].blocklist[i];
|
||||
FilterTree[j].invert = FilterTree[j].invert ? 0 : 1 ;
|
||||
}
|
||||
return a;
|
||||
|
||||
} /* End of Invert */
|
||||
|
||||
/*
|
||||
* Update supernode infos:
|
||||
* node 'b' was connected to 'a'. update node 'a' supernode data
|
||||
*/
|
||||
static void UpdateList(uint32_t a, uint32_t b) {
|
||||
size_t s;
|
||||
uint32_t i,j;
|
||||
|
||||
/* numblocks contains the number of blocks in the superblock */
|
||||
s = FilterTree[a].numblocks + FilterTree[b].numblocks;
|
||||
FilterTree[a].blocklist = (uint32_t *)realloc(FilterTree[a].blocklist, s * sizeof(uint32_t));
|
||||
if ( !FilterTree[a].blocklist ) {
|
||||
fprintf(stderr, "Memory allocation error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
exit(250);
|
||||
}
|
||||
|
||||
/* connect list of node 'b' after list of node 'a' */
|
||||
j = FilterTree[a].numblocks;
|
||||
for ( i=0; i< FilterTree[b].numblocks; i++ ) {
|
||||
FilterTree[a].blocklist[j+i] = FilterTree[b].blocklist[i];
|
||||
}
|
||||
FilterTree[a].numblocks = s;
|
||||
|
||||
/* set superblock info of all children to new superblock */
|
||||
for ( i=0; i< FilterTree[a].numblocks; i++ ) {
|
||||
j = FilterTree[a].blocklist[i];
|
||||
FilterTree[j].superblock = a;
|
||||
}
|
||||
|
||||
/* cleanup old node 'b' */
|
||||
FilterTree[b].numblocks = 0;
|
||||
if ( FilterTree[b].blocklist )
|
||||
free(FilterTree[b].blocklist);
|
||||
|
||||
} /* End of UpdateList */
|
||||
|
||||
/*
|
||||
* Dump Filterlist
|
||||
*/
|
||||
void DumpList(FilterEngine_data_t *args) {
|
||||
uint32_t i, j;
|
||||
|
||||
for (i=1; i<NumBlocks; i++ ) {
|
||||
if ( args->filter[i].invert )
|
||||
printf("Index: %u, Offset: %u, Mask: %.16llx, Value: %.16llx, Superblock: %u, Numblocks: %u, !OnTrue: %u, !OnFalse: %u Comp: %u Function: %s\n",
|
||||
i, args->filter[i].offset, (unsigned long long)args->filter[i].mask,
|
||||
(unsigned long long)args->filter[i].value, args->filter[i].superblock,
|
||||
args->filter[i].numblocks, args->filter[i].OnTrue, args->filter[i].OnFalse, args->filter[i].comp, args->filter[i].fname);
|
||||
else
|
||||
printf("Index: %u, Offset: %u, Mask: %.16llx, Value: %.16llx, Superblock: %u, Numblocks: %u, OnTrue: %u, OnFalse: %u Comp: %u Function: %s\n",
|
||||
i, args->filter[i].offset, (unsigned long long)args->filter[i].mask,
|
||||
(unsigned long long)args->filter[i].value, args->filter[i].superblock,
|
||||
args->filter[i].numblocks, args->filter[i].OnTrue, args->filter[i].OnFalse, args->filter[i].comp, args->filter[i].fname);
|
||||
if ( args->filter[i].OnTrue > (memblocks * MAXBLOCKS) || args->filter[i].OnFalse > (memblocks * MAXBLOCKS) ) {
|
||||
fprintf(stderr, "Tree pointer out of range for index %u. *** ABORT ***\n", i);
|
||||
exit(255);
|
||||
}
|
||||
if ( args->filter[i].data ) {
|
||||
if ( args->filter[i].comp == CMP_IPLIST ) {
|
||||
struct IPListNode *node;
|
||||
RB_FOREACH(node, IPtree, args->filter[i].data) {
|
||||
printf("value: %.16llx %.16llx mask: %.16llx %.16llx\n",
|
||||
(unsigned long long)node->ip[0], (unsigned long long)node->ip[1],
|
||||
(unsigned long long)node->mask[0], (unsigned long long)node->mask[1]);
|
||||
}
|
||||
} else if ( args->filter[i].comp == CMP_ULLIST ) {
|
||||
struct ULongListNode *node;
|
||||
RB_FOREACH(node, ULongtree, args->filter[i].data) {
|
||||
printf("%.16llx \n", (unsigned long long)node->value);
|
||||
}
|
||||
} else
|
||||
printf("Error comp: %i\n", args->filter[i].comp);
|
||||
}
|
||||
printf("\tBlocks: ");
|
||||
for ( j=0; j<args->filter[i].numblocks; j++ )
|
||||
printf("%i ", args->filter[i].blocklist[j]);
|
||||
printf("\n");
|
||||
}
|
||||
printf("NumBlocks: %i\n", NumBlocks - 1);
|
||||
for ( i=0; i<NumIdents; i++ ) {
|
||||
printf("Ident %i: %s\n", i, IdentList[i]);
|
||||
}
|
||||
} /* End of DumpList */
|
||||
|
||||
/* fast filter engine */
|
||||
int RunFilter(FilterEngine_data_t *args) {
|
||||
uint32_t index, offset;
|
||||
int evaluate, invert;
|
||||
|
||||
index = args->StartNode;
|
||||
evaluate = 0;
|
||||
invert = 0;
|
||||
while ( index ) {
|
||||
offset = args->filter[index].offset;
|
||||
invert = args->filter[index].invert;
|
||||
evaluate = ( args->nfrecord[offset] & args->filter[index].mask ) == args->filter[index].value;
|
||||
index = evaluate ? args->filter[index].OnTrue : args->filter[index].OnFalse;
|
||||
}
|
||||
return invert ? !evaluate : evaluate;
|
||||
|
||||
} /* End of RunFilter */
|
||||
|
||||
/* extended filter engine */
|
||||
int RunExtendedFilter(FilterEngine_data_t *args) {
|
||||
uint32_t index, offset;
|
||||
uint64_t comp_value[2];
|
||||
int evaluate, invert;
|
||||
|
||||
index = args->StartNode;
|
||||
evaluate = 0;
|
||||
invert = 0;
|
||||
while ( index ) {
|
||||
offset = args->filter[index].offset;
|
||||
invert = args->filter[index].invert;
|
||||
|
||||
comp_value[0] = args->nfrecord[offset] & args->filter[index].mask;
|
||||
comp_value[1] = args->filter[index].value;
|
||||
|
||||
if (args->filter[index].function != NULL)
|
||||
args->filter[index].function(args->nfrecord, comp_value);
|
||||
|
||||
switch (args->filter[index].comp) {
|
||||
case CMP_EQ:
|
||||
evaluate = comp_value[0] == comp_value[1];
|
||||
break;
|
||||
case CMP_GT:
|
||||
evaluate = comp_value[0] > comp_value[1];
|
||||
break;
|
||||
case CMP_LT:
|
||||
evaluate = comp_value[0] < comp_value[1];
|
||||
break;
|
||||
case CMP_IDENT:
|
||||
evaluate = strncmp(CurrentIdent, args->IdentList[comp_value[1]], IDENTLEN) == 0 ;
|
||||
break;
|
||||
case CMP_FLAGS:
|
||||
if ( invert )
|
||||
evaluate = comp_value[0] > 0;
|
||||
else
|
||||
evaluate = comp_value[0] == comp_value[1];
|
||||
break;
|
||||
case CMP_IPLIST: {
|
||||
struct IPListNode find;
|
||||
find.ip[0] = args->nfrecord[offset];
|
||||
find.ip[1] = args->nfrecord[offset+1];
|
||||
find.mask[0] = 0xffffffffffffffffLL;
|
||||
find.mask[1] = 0xffffffffffffffffLL;
|
||||
evaluate = RB_FIND(IPtree, args->filter[index].data, &find) != NULL; }
|
||||
break;
|
||||
case CMP_ULLIST: {
|
||||
struct ULongListNode find;
|
||||
find.value = comp_value[0];
|
||||
evaluate = RB_FIND(ULongtree, args->filter[index].data, &find ) != NULL; }
|
||||
break;
|
||||
}
|
||||
|
||||
index = evaluate ? args->filter[index].OnTrue : args->filter[index].OnFalse;
|
||||
}
|
||||
return invert ? !evaluate : evaluate;
|
||||
|
||||
} /* End of RunExtendedFilter */
|
||||
|
||||
uint32_t AddIdent(char *Ident) {
|
||||
uint32_t num;
|
||||
|
||||
if ( MaxIdents == 0 ) {
|
||||
// allocate first array block
|
||||
MaxIdents = IdentNumBlockSize;
|
||||
IdentList = (char **)malloc( MaxIdents * sizeof(char *));
|
||||
if ( !IdentList ) {
|
||||
fprintf(stderr, "Memory allocation error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
exit(254);
|
||||
}
|
||||
memset((void *)IdentList, 0, MaxIdents * sizeof(char *));
|
||||
NumIdents = 0;
|
||||
} else if ( NumIdents == MaxIdents ) {
|
||||
// extend array block
|
||||
MaxIdents += IdentNumBlockSize;
|
||||
IdentList = realloc((void *)IdentList, MaxIdents * sizeof(char *));
|
||||
if ( !IdentList ) {
|
||||
fprintf(stderr, "Memory allocation error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
exit(254);
|
||||
}
|
||||
}
|
||||
|
||||
num = NumIdents++;
|
||||
IdentList[num] = strdup(Ident);
|
||||
if ( !IdentList[num] ) {
|
||||
fprintf(stderr, "Memory allocation error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
exit(254);
|
||||
}
|
||||
|
||||
return num;
|
||||
|
||||
} // End of AddIdent
|
||||
|
||||
/* record processing functions */
|
||||
|
||||
static inline void duration_function(uint64_t *record_data, uint64_t *comp_values) {
|
||||
master_record_t *record = (master_record_t *)record_data;
|
||||
|
||||
/* duration in msec */
|
||||
comp_values[0] = 1000*(record->last - record->first) + record->msec_last - record->msec_first;
|
||||
|
||||
} // End of duration_function
|
||||
|
||||
static inline void pps_function(uint64_t *record_data, uint64_t *comp_values) {
|
||||
master_record_t *record = (master_record_t *)record_data;
|
||||
uint64_t duration;
|
||||
|
||||
/* duration in msec */
|
||||
duration = 1000*(record->last - record->first) + record->msec_last - record->msec_first;
|
||||
if ( duration == 0 )
|
||||
comp_values[0] = 0;
|
||||
else
|
||||
comp_values[0] = ( 1000LL * record->dPkts ) / duration;
|
||||
|
||||
} // End of pps_function
|
||||
|
||||
static inline void bps_function(uint64_t *record_data, uint64_t *comp_values) {
|
||||
master_record_t *record = (master_record_t *)record_data;
|
||||
uint64_t duration;
|
||||
|
||||
/* duration in msec */
|
||||
duration = 1000*(record->last - record->first) + record->msec_last - record->msec_first;
|
||||
if ( duration == 0 )
|
||||
comp_values[0] = 0;
|
||||
else
|
||||
comp_values[0] = ( 8000LL * record->dOctets ) / duration; /* 8 bits per Octet - x 1000 for msec */
|
||||
|
||||
} // End of bps_function
|
||||
|
||||
static inline void bpp_function(uint64_t *record_data, uint64_t *comp_values) {
|
||||
master_record_t *record = (master_record_t *)record_data;
|
||||
|
||||
comp_values[0] = record->dPkts ? record->dOctets / record->dPkts : 0;
|
||||
|
||||
} // End of bpp_function
|
||||
|
||||
static inline void mpls_eos_function(uint64_t *record_data, uint64_t *comp_values) {
|
||||
master_record_t *record = (master_record_t *)record_data;
|
||||
int i;
|
||||
|
||||
// search for end of MPLS stack label
|
||||
for (i=0; i<10; i++ ) {
|
||||
if ( record->mpls_label[i] & 1 ) {
|
||||
// End of stack found -> mask exp and eos bits
|
||||
comp_values[0] = record->mpls_label[i] & 0x00FFFFF0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// trick filter to fail with an invalid mpls label value
|
||||
comp_values[0] = 0xFF000000;
|
||||
|
||||
} // End of mpls_eos_function
|
||||
|
||||
static inline void mpls_any_function(uint64_t *record_data, uint64_t *comp_values) {
|
||||
master_record_t *record = (master_record_t *)record_data;
|
||||
int i;
|
||||
|
||||
// search for end of MPLS stack label
|
||||
for (i=0; i<10; i++ ) {
|
||||
if ( (record->mpls_label[i] & 1) == 1 ) {
|
||||
// End of stack found -> mask exp and eos bits
|
||||
comp_values[0] = record->mpls_label[i] & 0x00FFFFF0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// trick filter to fail with an invalid mpls label value
|
||||
comp_values[0] = 0xFF000000;
|
||||
|
||||
} // End of mpls_eos_function
|
||||
|
||||
static inline void pblock_function(uint64_t *record_data, uint64_t *comp_values) {
|
||||
#ifdef NSEL
|
||||
master_record_t *record = (master_record_t *)record_data;
|
||||
comp_values[0] = comp_values[0] >> comp_values[1];
|
||||
if ( (comp_values[0] >= record->block_start) && (comp_values[0] <= record->block_end) ) {
|
||||
comp_values[1] = comp_values[0];
|
||||
} else {
|
||||
// force "not equal"
|
||||
comp_values[1] = comp_values[0] + 1;
|
||||
}
|
||||
#else
|
||||
comp_values[1] = 0;
|
||||
#endif
|
||||
|
||||
} // End of pblock_function
|
||||
|
178
bin/nftree.h
Normal file
178
bin/nftree.h
Normal file
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: nftree.h 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NFTREE_H
|
||||
#define _NFTREE_H 1
|
||||
|
||||
/*
|
||||
* type definitions for nf tree
|
||||
*/
|
||||
|
||||
typedef void (*flow_proc_t)(uint64_t *, uint64_t *);
|
||||
|
||||
typedef struct FilterBlock {
|
||||
/* Filter specific data */
|
||||
uint32_t offset;
|
||||
uint64_t mask;
|
||||
uint64_t value;
|
||||
|
||||
/* Internal block info for tree setup */
|
||||
uint32_t superblock; /* Index of superblock */
|
||||
uint32_t *blocklist; /* index array of blocks, belonging to
|
||||
this superblock */
|
||||
uint32_t numblocks; /* number of blocks in blocklist */
|
||||
uint32_t OnTrue, OnFalse; /* Jump Index for tree */
|
||||
int16_t invert; /* Invert result of test */
|
||||
uint16_t comp; /* comperator */
|
||||
flow_proc_t function; /* function for flow processing */
|
||||
char *fname; /* ascii function name */
|
||||
void *data; /* any additional data for this block */
|
||||
} FilterBlock_t;
|
||||
|
||||
typedef struct FilterEngine_data_s {
|
||||
FilterBlock_t *filter;
|
||||
uint32_t StartNode;
|
||||
uint32_t Extended;
|
||||
char **IdentList;
|
||||
uint64_t *nfrecord;
|
||||
int (*FilterEngine)(struct FilterEngine_data_s *);
|
||||
} FilterEngine_data_t;
|
||||
|
||||
|
||||
/*
|
||||
* Definitions
|
||||
*/
|
||||
enum { CMP_EQ = 0, CMP_GT, CMP_LT, CMP_IDENT, CMP_FLAGS, CMP_IPLIST, CMP_ULLIST };
|
||||
|
||||
/*
|
||||
* filter functions:
|
||||
* For some filter functions, netflow records need to be processed first in order to filter them
|
||||
* This involves all data not directly available in the netflow record, such as packets per second etc.
|
||||
* Filter speed is a bit slower due to extra netflow processsing
|
||||
* The sequence of the enum values must correspond with the entries in the flow_procs array
|
||||
*/
|
||||
|
||||
enum { FUNC_NONE = 0, /* no function - just plain filtering - just to be complete here */
|
||||
FUNC_PPS, /* function code for pps ( packet per second ) filter function */
|
||||
FUNC_BPS, /* function code for bps ( bits per second ) filter function */
|
||||
FUNC_BPP, /* function code for bpp ( bytes per packet ) filter function */
|
||||
FUNC_DURATION, /* function code for duration ( in miliseconds ) filter function */
|
||||
FUNC_MPLS_EOS, /* function code for matching End of MPLS Stack label */
|
||||
FUNC_MPLS_ANY, /* function code for matching any MPLS label */
|
||||
FUNC_PBLOCK /* function code for matching ports against pblock start */
|
||||
};
|
||||
|
||||
/*
|
||||
* Tree type defs
|
||||
*/
|
||||
|
||||
/* Definition of the IP list node */
|
||||
struct IPListNode {
|
||||
RB_ENTRY(IPListNode) entry;
|
||||
uint64_t ip[2];
|
||||
uint64_t mask[2];
|
||||
};
|
||||
|
||||
/* Definition of the port/AS list node */
|
||||
struct ULongListNode {
|
||||
RB_ENTRY(ULongListNode) entry;
|
||||
uint64_t value;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Filter Engine Functions
|
||||
*/
|
||||
int RunFilter(FilterEngine_data_t *args);
|
||||
int RunExtendedFilter(FilterEngine_data_t *args);
|
||||
/*
|
||||
* For testing purpose only
|
||||
*/
|
||||
int nblocks(void);
|
||||
|
||||
/*
|
||||
* Initialize globals
|
||||
*/
|
||||
void InitTree(void);
|
||||
|
||||
/*
|
||||
* Returns the current Filter Tree
|
||||
*/
|
||||
FilterEngine_data_t *CompileFilter(char *FilterSyntax);
|
||||
|
||||
/*
|
||||
* Clear Filter
|
||||
*/
|
||||
void ClearFilter(void);
|
||||
|
||||
/*
|
||||
* Returns next free slot in blocklist
|
||||
*/
|
||||
uint32_t NewBlock(uint32_t offset, uint64_t mask, uint64_t value, uint16_t comp, uint32_t function, void *data);
|
||||
|
||||
/*
|
||||
* Connects the to blocks b1 and b2 ( AND ) and returns index of superblock
|
||||
*/
|
||||
uint32_t Connect_AND(uint32_t b1, uint32_t b2);
|
||||
|
||||
/*
|
||||
* Connects the to blocks b1 and b2 ( OR ) and returns index of superblock
|
||||
*/
|
||||
uint32_t Connect_OR(uint32_t b1, uint32_t b2);
|
||||
|
||||
/*
|
||||
* Inverts OnTrue and OnFalse
|
||||
*/
|
||||
uint32_t Invert(uint32_t a );
|
||||
|
||||
/*
|
||||
* Add Ident to Identlist
|
||||
*/
|
||||
uint32_t AddIdent(char *Ident);
|
||||
|
||||
/*
|
||||
* Dump Filterlist
|
||||
*/
|
||||
void DumpList(FilterEngine_data_t *args);
|
||||
|
||||
/*
|
||||
* Prints info while filer is running
|
||||
*/
|
||||
int RunDebugFilter(uint32_t *block);
|
||||
|
||||
#endif //_NFTREE_H
|
635
bin/nfx.c
Executable file
635
bin/nfx.c
Executable file
@ -0,0 +1,635 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: nfx.c 58 2010-02-26 12:26:07Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 58 $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifndef DEVEL
|
||||
# define dbg_printf(...) /* printf(__VA_ARGS__) */
|
||||
#else
|
||||
# define dbg_printf(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#include "nf_common.h"
|
||||
#include "nffile.h"
|
||||
#include "util.h"
|
||||
#include "nfx.h"
|
||||
|
||||
/* global vars */
|
||||
|
||||
/*
|
||||
* see nffile.h for detailed extension description
|
||||
*/
|
||||
extension_descriptor_t extension_descriptor[] = {
|
||||
// fill indices 0 - 3
|
||||
{ COMMON_BLOCK_ID, 0, 0, 1, "Required extension: Common record"},
|
||||
{ EX_IPv4v6, 0, 0, 1, "Required extension: IPv4/IPv6 src/dst address"},
|
||||
{ EX_PACKET_4_8, 0, 0, 1, "Required extension: 4/8 byte input packets"},
|
||||
{ EX_BYTE_4_8, 0, 0, 1, "Required extension: 4/8 byte input bytes"},
|
||||
|
||||
// the optional extension
|
||||
{ EX_IO_SNMP_2, 4, 1, 1, "2 byte input/output interface index"},
|
||||
{ EX_IO_SNMP_4, 8, 1, 1, "4 byte input/output interface index"},
|
||||
{ EX_AS_2, 4, 2, 1, "2 byte src/dst AS number"},
|
||||
{ EX_AS_4, 8, 2, 1, "4 byte src/dst AS number"},
|
||||
{ EX_MULIPLE, 4, 3, 0, "dst tos, direction, src/dst mask"},
|
||||
{ EX_NEXT_HOP_v4, 4, 4, 0, "IPv4 next hop"},
|
||||
{ EX_NEXT_HOP_v6, 16, 4, 0, "IPv6 next hop"},
|
||||
{ EX_NEXT_HOP_BGP_v4, 4, 5, 0, "IPv4 BGP next IP"},
|
||||
{ EX_NEXT_HOP_BGP_v6, 16, 5, 0, "IPv6 BGP next IP"},
|
||||
{ EX_VLAN, 4, 6, 0, "src/dst vlan id"},
|
||||
{ EX_OUT_PKG_4, 4, 7, 0, "4 byte output packets"},
|
||||
{ EX_OUT_PKG_8, 8, 7, 0, "8 byte output packets"},
|
||||
{ EX_OUT_BYTES_4, 4, 8, 0, "4 byte output bytes"},
|
||||
{ EX_OUT_BYTES_8, 8, 8, 0, "8 byte output bytes"},
|
||||
{ EX_AGGR_FLOWS_4, 4, 9, 0, "4 byte aggregated flows"},
|
||||
{ EX_AGGR_FLOWS_8, 8, 9, 0, "8 byte aggregated flows"},
|
||||
{ EX_MAC_1, 16, 10, 0, "in src/out dst mac address"},
|
||||
{ EX_MAC_2, 16, 11, 0, "in dst/out src mac address"},
|
||||
{ EX_MPLS, 40, 12, 0, "MPLS Labels"},
|
||||
{ EX_ROUTER_IP_v4, 4, 13, 0, "IPv4 router IP addr"},
|
||||
{ EX_ROUTER_IP_v6, 16, 13, 0, "IPv6 router IP addr"},
|
||||
{ EX_ROUTER_ID, 4, 14, 0, "router ID"},
|
||||
|
||||
{ EX_BGPADJ, 8, 15, 0, "BGP adjacent prev/next AS"},
|
||||
{ EX_RECEIVED, 8, 16, 0, "time packet received"},
|
||||
|
||||
// reserved for more v9/IPFIX
|
||||
{ EX_RESERVED_1, 0, 0, 0, NULL},
|
||||
{ EX_RESERVED_2, 0, 0, 0, NULL},
|
||||
{ EX_RESERVED_3, 0, 0, 0, NULL},
|
||||
{ EX_RESERVED_4, 0, 0, 0, NULL},
|
||||
{ EX_RESERVED_5, 0, 0, 0, NULL},
|
||||
{ EX_RESERVED_6, 0, 0, 0, NULL},
|
||||
{ EX_RESERVED_7, 0, 0, 0, NULL},
|
||||
{ EX_RESERVED_8, 0, 0, 0, NULL},
|
||||
{ EX_RESERVED_9, 0, 0, 0, NULL},
|
||||
|
||||
// ASA - Network Security Event Logging NSEL extensions
|
||||
{ EX_NSEL_COMMON, 20, 26, 0, "NSEL Common block"},
|
||||
{ EX_NSEL_XLATE_PORTS, 4, 27, 0, "NSEL xlate ports"},
|
||||
{ EX_NSEL_XLATE_IP_v4, 8, 28, 0, "NSEL xlate IPv4 addr"},
|
||||
{ EX_NSEL_XLATE_IP_v6, 32, 28, 0, "NSEL xlate IPv6 addr"},
|
||||
{ EX_NSEL_ACL, 24, 29, 0, "NSEL ACL ingress/egress acl ID"},
|
||||
{ EX_NSEL_USER, 24, 30, 0, "NSEL username"},
|
||||
{ EX_NSEL_USER_MAX, 72, 30, 0, "NSEL max username"},
|
||||
|
||||
{ EX_NSEL_RESERVED, 0, 0, 0, NULL},
|
||||
|
||||
// nprobe extensions
|
||||
{ EX_LATENCY, 24, 64, 0, "nprobe latency"},
|
||||
|
||||
// NAT - Network Event Logging
|
||||
{ EX_NEL_COMMON, 12, 31, 0, "NEL Common block"},
|
||||
{ EX_NEL_GLOBAL_IP_v4, 0, 0, 0, "Compat NEL IPv4"},
|
||||
{ EX_PORT_BLOCK_ALLOC, 8, 32, 0, "NAT Port Block Allocation"},
|
||||
{ EX_NEL_RESERVED_1, 0, 0, 0, NULL},
|
||||
|
||||
// last entry
|
||||
{ 0, 0, 0, 0, NULL }
|
||||
};
|
||||
|
||||
uint32_t Max_num_extensions;
|
||||
|
||||
void FixExtensionMap(extension_map_t *map);
|
||||
|
||||
extension_map_list_t *InitExtensionMaps(int AllocateList) {
|
||||
extension_map_list_t *list = NULL;
|
||||
int i;
|
||||
|
||||
if ( AllocateList ) {
|
||||
list = (extension_map_list_t *)calloc(1, sizeof(extension_map_list_t));
|
||||
if ( !list ) {
|
||||
LogError("calloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
exit(255);
|
||||
}
|
||||
list->last_map = &list->map_list;
|
||||
}
|
||||
|
||||
Max_num_extensions = 0;
|
||||
i = 1;
|
||||
while ( extension_descriptor[i++].id ) {
|
||||
Max_num_extensions++;
|
||||
}
|
||||
#ifdef DEVEL
|
||||
i = 1;
|
||||
while ( extension_descriptor[i].id ) {
|
||||
if ( extension_descriptor[i].id != i ) {
|
||||
printf("*** ERROR *** Init extension_descriptors at index %i: ID: %i, %s\n",
|
||||
i, extension_descriptor[i].id, extension_descriptor[i].description);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
#endif
|
||||
|
||||
return list;
|
||||
|
||||
} // End of InitExtensionMaps
|
||||
|
||||
void FreeExtensionMaps(extension_map_list_t *extension_map_list) {
|
||||
extension_info_t *l;
|
||||
|
||||
if ( extension_map_list == NULL )
|
||||
return;
|
||||
|
||||
// free all extension infos
|
||||
l = extension_map_list->map_list;
|
||||
while ( l ) {
|
||||
extension_info_t *tmp = l;
|
||||
l = l->next;
|
||||
free(tmp->map);
|
||||
free(tmp);
|
||||
}
|
||||
free(extension_map_list);
|
||||
|
||||
} // End of FreeExtensionMaps
|
||||
|
||||
int Insert_Extension_Map(extension_map_list_t *extension_map_list, extension_map_t *map) {
|
||||
extension_info_t *l;
|
||||
uint16_t map_id;
|
||||
|
||||
map_id = map->map_id == INIT_ID ? 0 : map->map_id & EXTENSION_MAP_MASK;
|
||||
map->map_id = map_id;
|
||||
dbg_printf("Insert Extension Map:\n");
|
||||
#ifdef DEVEL
|
||||
PrintExtensionMap(map);
|
||||
#endif
|
||||
// is this slot free
|
||||
if ( extension_map_list->slot[map_id] ) {
|
||||
int i;
|
||||
dbg_printf("Extension info in slot %d already exists: 0x%llu\n", map_id, (long long unsigned)extension_map_list->slot[map_id]);
|
||||
// no - check if same map already in slot
|
||||
if ( extension_map_list->slot[map_id]->map->size == map->size ) {
|
||||
// existing map and new map have the same size
|
||||
dbg_printf("New map has same size, as existing:\n");
|
||||
|
||||
// we must compare the maps
|
||||
i = 0;
|
||||
while ( extension_map_list->slot[map_id]->map->ex_id[i] &&
|
||||
(extension_map_list->slot[map_id]->map->ex_id[i] == map->ex_id[i]) )
|
||||
i++;
|
||||
|
||||
// if last entry == 0 => last map entry => maps are the same
|
||||
if ( extension_map_list->slot[map_id]->map->ex_id[i] == 0 ) {
|
||||
dbg_printf("Same map => nothing to do\n");
|
||||
// same map
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
dbg_printf("Different map => continue\n");
|
||||
}
|
||||
#ifdef DEVEL
|
||||
else
|
||||
printf("Extension info in slot %d free\n", map_id);
|
||||
#endif
|
||||
|
||||
dbg_printf("Search if extension info exists in extension page_list\n");
|
||||
// new map is different but has same id - search for map in page list
|
||||
for ( l = extension_map_list->map_list ; l != NULL ; l = l->next) {
|
||||
int i = 0;
|
||||
dbg_printf("Check map: %u\n", l->map->map_id);
|
||||
if ( l->map->size == map->size && ( l->map->extension_size == map->extension_size ) ) {
|
||||
while ( (l->map->ex_id[i] || map->ex_id[i]) && (l->map->ex_id[i] == map->ex_id[i]) )
|
||||
i++;
|
||||
if ( l->map->ex_id[i] == 0 ) {
|
||||
dbg_printf("Map found: 0x%llu ID: %u\n", (long long unsigned)l, l->map->map_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if found l is our extension
|
||||
if ( !l ) {
|
||||
// no extension found in page_list
|
||||
dbg_printf("Map not found in extension page list\n");
|
||||
l = (extension_info_t *)malloc(sizeof(extension_info_t));
|
||||
if ( !l ) {
|
||||
fprintf(stderr, "malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
exit(255);
|
||||
}
|
||||
l->ref_count = 0;
|
||||
l->next = NULL;
|
||||
memset((void *)&l->master_record, 0, sizeof(master_record_t));
|
||||
|
||||
l->map = (extension_map_t *)malloc((ssize_t)map->size);
|
||||
if ( !l->map ) {
|
||||
fprintf(stderr, "malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
exit(255);
|
||||
}
|
||||
memcpy((void *)l->map, (void *)map, map->size);
|
||||
|
||||
// append new extension to list
|
||||
*(extension_map_list->last_map) = l;
|
||||
extension_map_list->last_map = &l->next;
|
||||
|
||||
// Sanity check
|
||||
FixExtensionMap(map);
|
||||
}
|
||||
|
||||
// l is now our valid extension
|
||||
dbg_printf("Insert extension into slot %i: 0x%llu\n\n", map_id, (long long unsigned)l);
|
||||
|
||||
// remove map from lookup list, if it exists
|
||||
if ( extension_map_list->slot[map_id] )
|
||||
extension_map_list->slot[map_id]->map->map_id = 0;
|
||||
|
||||
// place existing extension_info into lookup list
|
||||
extension_map_list->slot[map_id] = l;
|
||||
l->map->map_id = map_id;
|
||||
|
||||
if ( map_id > extension_map_list->max_used ) {
|
||||
extension_map_list->max_used = map_id;
|
||||
}
|
||||
|
||||
// extension changed
|
||||
return 1;
|
||||
|
||||
} // End of Insert_Extension_Map
|
||||
|
||||
void PackExtensionMapList(extension_map_list_t *extension_map_list) {
|
||||
extension_info_t *l;
|
||||
int i, free_slot;
|
||||
|
||||
dbg_printf("Pack extensions maps\n");
|
||||
// compact extension map list - close gaps
|
||||
|
||||
// clear current list
|
||||
for ( i=0; i <= extension_map_list->max_used; i++ ) {
|
||||
extension_map_list->slot[i] = NULL;
|
||||
}
|
||||
|
||||
// hangle though list
|
||||
free_slot = 0;
|
||||
l = extension_map_list->map_list;
|
||||
while ( l ) {
|
||||
dbg_printf("Check extension ref count: %u -> ", l->ref_count);
|
||||
if ( l->ref_count ) {
|
||||
// extension is referenced - insert into slot
|
||||
dbg_printf("slot %u\n", free_slot);
|
||||
extension_map_list->slot[free_slot] = l;
|
||||
l->map->map_id = free_slot++;
|
||||
l = l->next;
|
||||
} else {
|
||||
// extension can be removed - not referenced
|
||||
l = l->next;
|
||||
dbg_printf("Skipped\n");
|
||||
}
|
||||
if ( free_slot == MAX_EXTENSION_MAPS ) {
|
||||
fprintf(stderr, "Critical error in %s line %d: %s\n", __FILE__, __LINE__, "Out of extension slots!" );
|
||||
exit(255);
|
||||
}
|
||||
}
|
||||
|
||||
// this points to the next free slot
|
||||
extension_map_list->max_used = free_slot > 0 ? free_slot - 1 : 0;
|
||||
dbg_printf("Packed maps: %i\n", free_slot);
|
||||
|
||||
#ifdef DEVEL
|
||||
// Check maps
|
||||
i = 0;
|
||||
while ( extension_map_list->slot[i] != NULL && i < MAX_EXTENSION_MAPS ) {
|
||||
if ( extension_map_list->slot[i]->map->map_id != i )
|
||||
printf("*** Map ID missmatch in slot: %i, id: %u\n", i, extension_map_list->slot[i]->map->map_id);
|
||||
i++;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // End of PackExtensionMapList
|
||||
|
||||
void SetupExtensionDescriptors(char *options) {
|
||||
int i, *mask;
|
||||
char *p, *q, *s;
|
||||
|
||||
mask = (int *)calloc(65536, sizeof(int));
|
||||
if ( !mask ) {
|
||||
fprintf(stderr, "malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
exit(255);
|
||||
}
|
||||
|
||||
s = (char *)malloc(strlen(options)+1);
|
||||
if ( !s ) {
|
||||
fprintf(stderr, "malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
exit(255);
|
||||
}
|
||||
q = s;
|
||||
*q = '\0';
|
||||
p = options;
|
||||
while ( *p ) {
|
||||
if ( !isspace(*p) )
|
||||
*q++ = *p;
|
||||
p++;
|
||||
}
|
||||
*q = '\0';
|
||||
|
||||
p = s;
|
||||
while ( p && *p ) {
|
||||
int sign;
|
||||
q = strchr(p, ',');
|
||||
if ( q )
|
||||
*q++ = '\0';
|
||||
|
||||
// get possible sign
|
||||
sign = 1;
|
||||
if ( *p == '-' ) {
|
||||
sign = -1;
|
||||
p++;
|
||||
}
|
||||
if ( *p == '+' ) {
|
||||
sign = 1;
|
||||
p++;
|
||||
}
|
||||
|
||||
if ( strcmp(p, "all") == 0 ) {
|
||||
for (i=4; extension_descriptor[i].id; i++ )
|
||||
if ( extension_descriptor[i].description )
|
||||
extension_descriptor[i].enabled = sign == 1 ? 1 : 0;
|
||||
} else if ( strcmp(p, "nsel") == 0 ) {
|
||||
extension_descriptor[EX_IO_SNMP_2].enabled = 0;
|
||||
extension_descriptor[EX_IO_SNMP_4].enabled = 0;
|
||||
extension_descriptor[EX_OUT_BYTES_4].enabled = 1;
|
||||
extension_descriptor[EX_OUT_BYTES_8].enabled = 1;
|
||||
extension_descriptor[EX_NSEL_COMMON].enabled = 1;
|
||||
extension_descriptor[EX_NSEL_XLATE_PORTS].enabled = 1;
|
||||
extension_descriptor[EX_NSEL_XLATE_IP_v4].enabled = 1;
|
||||
extension_descriptor[EX_NSEL_XLATE_IP_v6].enabled = 1;
|
||||
extension_descriptor[EX_NSEL_ACL].enabled = 1;
|
||||
extension_descriptor[EX_NSEL_USER].enabled = 1;
|
||||
extension_descriptor[EX_NSEL_USER_MAX].enabled = 1;
|
||||
} else if ( strcmp(p, "nel") == 0 ) {
|
||||
extension_descriptor[EX_NEL_COMMON].enabled = 1;
|
||||
extension_descriptor[EX_NSEL_XLATE_PORTS].enabled = 1;
|
||||
extension_descriptor[EX_NSEL_XLATE_IP_v4].enabled = 1;
|
||||
extension_descriptor[EX_NSEL_XLATE_IP_v6].enabled = 1;
|
||||
} else {
|
||||
switch ( *p ) {
|
||||
case '\0':
|
||||
fprintf(stderr, "Extension format error: Unexpected end of format.\n");
|
||||
exit(255);
|
||||
break;
|
||||
case '*':
|
||||
for (i=4; extension_descriptor[i].id; i++ )
|
||||
if ( extension_descriptor[i].description )
|
||||
extension_descriptor[i].enabled = sign == 1 ? 1 : 0;
|
||||
break;
|
||||
default: {
|
||||
int i = strtol(p, NULL, 10);
|
||||
if ( i == 0 ) {
|
||||
fprintf(stderr, "Extension format error: Unexpected string: %s.\n", p);
|
||||
exit(255);
|
||||
}
|
||||
if ( i > 65535 ) {
|
||||
fprintf(stderr, "Extension format error: Invalid extension: %i\n", i);
|
||||
exit(255);
|
||||
}
|
||||
mask[i] = sign;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
p = q;
|
||||
}
|
||||
for (i=4; extension_descriptor[i].id; i++ ) {
|
||||
int ui = extension_descriptor[i].user_index;
|
||||
|
||||
// Skip reserved extensions
|
||||
if ( !extension_descriptor[i].description )
|
||||
continue;
|
||||
|
||||
// mask[ui] == 0 means no input from user -> default behaviour or already overwritten by '*'
|
||||
if ( mask[ui] < 0 ) {
|
||||
extension_descriptor[i].enabled = 0;
|
||||
}
|
||||
if ( mask[ui] > 0 ) {
|
||||
extension_descriptor[i].enabled = 1;
|
||||
}
|
||||
if ( extension_descriptor[i].enabled ) {
|
||||
dbg_printf("Add extension: %s\n", extension_descriptor[i].description);
|
||||
LogInfo("Add extension: %s", extension_descriptor[i].description);
|
||||
}
|
||||
}
|
||||
|
||||
free(mask);
|
||||
|
||||
} // End of SetupExtensionDescriptors
|
||||
|
||||
void PrintExtensionMap(extension_map_t *map) {
|
||||
int i;
|
||||
|
||||
printf("Extension Map:\n");
|
||||
printf(" Map ID = %u\n", map->map_id);
|
||||
printf(" Map Size = %u\n", map->size);
|
||||
printf(" Ext Size = %u\n", map->extension_size);
|
||||
i=0;
|
||||
while (map->ex_id[i]) {
|
||||
int id = map->ex_id[i++];
|
||||
printf(" ID %3i, ext %3u = %s\n", extension_descriptor[id].user_index, id, extension_descriptor[id].description );
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
} // End of PrintExtensionMap
|
||||
|
||||
int VerifyExtensionMap(extension_map_t *map) {
|
||||
int i, failed, extension_size, max_elements;
|
||||
|
||||
failed = 0;
|
||||
if (( map->size & 0x3 ) != 0 ) {
|
||||
printf("Verify map id %i: WARNING: map size %i not aligned!\n", map->map_id, map->size);
|
||||
failed = 1;
|
||||
}
|
||||
|
||||
if ( ((int)map->size - (int)sizeof(extension_map_t)) <= 0 ) {
|
||||
printf("Verify map id %i: ERROR: map size %i too small!\n", map->map_id, map->size);
|
||||
failed = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
max_elements = (map->size - sizeof(extension_map_t)) / sizeof(uint16_t);
|
||||
extension_size = 0;
|
||||
i=0;
|
||||
while (map->ex_id[i] && i <= max_elements) {
|
||||
int id = map->ex_id[i];
|
||||
if ( id > Max_num_extensions ) {
|
||||
printf("Verify map id %i: ERROR: element id %i out of range [%i]!\n", map->map_id, id, Max_num_extensions);
|
||||
failed = 1;
|
||||
}
|
||||
extension_size += extension_descriptor[id].size;
|
||||
i++;
|
||||
}
|
||||
|
||||
if ( (extension_size != map->extension_size ) ) {
|
||||
printf("Verify map id %i: ERROR extension size: Expected %i, Map reports: %i!\n", map->map_id,
|
||||
extension_size, map->extension_size);
|
||||
failed = 1;
|
||||
}
|
||||
if ( (i != max_elements ) && ((max_elements-i) != 1) ) {
|
||||
// off by 1 is the opt alignment
|
||||
printf("Verify map id %i: ERROR: Expected %i elements in map, but found %i!\n", map->map_id, max_elements, i);
|
||||
failed = 1;
|
||||
}
|
||||
|
||||
return failed;
|
||||
|
||||
} // End of VerifyExtensionMap
|
||||
|
||||
/*
|
||||
* Sanity check of map
|
||||
*/
|
||||
void FixExtensionMap(extension_map_t *map) {
|
||||
int i, extension_size, max_elements;
|
||||
|
||||
if (( map->size & 0x3 ) != 0 ) {
|
||||
printf("PANIC! - Verify map id %i: WARNING: map size %i not aligned!\n", map->map_id, map->size);
|
||||
exit(255);
|
||||
}
|
||||
|
||||
if ( ((int)map->size - (int)sizeof(extension_map_t)) <= 0 ) {
|
||||
printf("PANIC! - Verify map id %i: ERROR: map size %i too small!\n", map->map_id, map->size);
|
||||
exit(255);
|
||||
}
|
||||
|
||||
max_elements = (map->size - sizeof(extension_map_t)) / sizeof(uint16_t);
|
||||
extension_size = 0;
|
||||
i=0;
|
||||
while (map->ex_id[i] && i <= max_elements) {
|
||||
int id = map->ex_id[i];
|
||||
if ( id > Max_num_extensions ) {
|
||||
printf("PANIC! - Verify map id %i: ERROR: element id %i out of range [%i]!\n", map->map_id, id, Max_num_extensions);
|
||||
}
|
||||
extension_size += extension_descriptor[id].size;
|
||||
i++;
|
||||
}
|
||||
|
||||
// silently fix extension size bug of nfdump <= 1.6.2 ..
|
||||
if ( (extension_size != map->extension_size ) ) {
|
||||
#ifdef DEVEL
|
||||
printf("FixExtension map extension size from %i to %i\n", map->extension_size, extension_size);
|
||||
#endif
|
||||
map->extension_size = extension_size;
|
||||
}
|
||||
|
||||
if ( (i != max_elements ) && ((max_elements-i) != 1) ) {
|
||||
// off by 1 is the opt alignment
|
||||
printf("Verify map id %i: ERROR: Expected %i elements in map, but found %i!\n", map->map_id, max_elements, i);
|
||||
}
|
||||
|
||||
} // End of FixExtensionMap
|
||||
|
||||
void DumpExMaps(char *filename) {
|
||||
int done;
|
||||
nffile_t *nffile;
|
||||
common_record_t *flow_record;
|
||||
uint32_t skipped_blocks;
|
||||
uint64_t total_bytes;
|
||||
|
||||
printf("\nDump all extension maps:\n");
|
||||
printf("========================\n");
|
||||
|
||||
nffile = OpenFile(filename, NULL);
|
||||
if ( !nffile ) {
|
||||
return;
|
||||
}
|
||||
|
||||
total_bytes = 0;
|
||||
skipped_blocks = 0;
|
||||
done = 0;
|
||||
while ( !done ) {
|
||||
int i, ret;
|
||||
|
||||
// get next data block from file
|
||||
ret = ReadBlock(nffile);
|
||||
|
||||
switch (ret) {
|
||||
case NF_CORRUPT:
|
||||
case NF_ERROR:
|
||||
if ( ret == NF_CORRUPT )
|
||||
LogError("Corrupt data file '%s': '%s'\n",filename);
|
||||
else
|
||||
LogError("Read error in file '%s': %s\n",filename, strerror(errno) );
|
||||
done = 1;
|
||||
continue;
|
||||
break;
|
||||
// fall through - get next file in chain
|
||||
case NF_EOF:
|
||||
done = 1;
|
||||
continue;
|
||||
break;
|
||||
|
||||
default:
|
||||
// successfully read block
|
||||
total_bytes += ret;
|
||||
}
|
||||
|
||||
if ( nffile->block_header->id != DATA_BLOCK_TYPE_2 ) {
|
||||
skipped_blocks++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// block type = 2
|
||||
|
||||
flow_record = (common_record_t *)nffile->buff_ptr;
|
||||
for ( i=0; i < nffile->block_header->NumRecords; i++ ) {
|
||||
|
||||
if ( flow_record->type == ExtensionMapType ) {
|
||||
extension_map_t *map = (extension_map_t *)flow_record;
|
||||
VerifyExtensionMap(map);
|
||||
PrintExtensionMap(map);
|
||||
}
|
||||
|
||||
// Advance pointer by number of bytes for netflow record
|
||||
flow_record = (common_record_t *)((pointer_addr_t)flow_record + flow_record->size);
|
||||
}
|
||||
}
|
||||
|
||||
CloseFile(nffile);
|
||||
DisposeFile(nffile);
|
||||
|
||||
} // End of DumpExMaps
|
||||
|
87
bin/nfx.h
Executable file
87
bin/nfx.h
Executable file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: nfx.h 48 2010-01-02 08:06:27Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 48 $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NFX_H
|
||||
#define _NFX_H 1
|
||||
|
||||
// MAX_EXTENSION_MAPS must be a power of 2
|
||||
#define MAX_EXTENSION_MAPS 65536
|
||||
#define EXTENSION_MAP_MASK (MAX_EXTENSION_MAPS-1)
|
||||
|
||||
typedef struct extension_descriptor_s {
|
||||
uint16_t id; // id number
|
||||
uint16_t size; // number of bytes
|
||||
uint32_t user_index; // index specified by the user to enable this extension
|
||||
uint32_t enabled; // extension is enabled or not
|
||||
char *description;
|
||||
} extension_descriptor_t;
|
||||
|
||||
typedef struct extension_info_s {
|
||||
struct extension_info_s *next;
|
||||
extension_map_t *map;
|
||||
uint32_t ref_count;
|
||||
uint32_t *offset_cache;
|
||||
master_record_t master_record;
|
||||
} extension_info_t;
|
||||
|
||||
typedef struct extension_map_list_s {
|
||||
extension_info_t *slot[MAX_EXTENSION_MAPS];
|
||||
extension_info_t *map_list;
|
||||
extension_info_t **last_map;
|
||||
uint32_t max_used;
|
||||
} extension_map_list_t;
|
||||
|
||||
#define NEEDS_EXTENSION_LIST 1
|
||||
#define NO_EXTENSION_LIST 0
|
||||
extension_map_list_t *InitExtensionMaps(int AllocateList);
|
||||
|
||||
void FreeExtensionMaps(extension_map_list_t *extension_map_list);
|
||||
|
||||
void PackExtensionMapList(extension_map_list_t *extension_map_list);
|
||||
|
||||
int Insert_Extension_Map(extension_map_list_t *extension_map_list, extension_map_t *map);
|
||||
|
||||
void SetupExtensionDescriptors(char *options);
|
||||
|
||||
void PrintExtensionMap(extension_map_t *map);
|
||||
|
||||
int VerifyExtensionMap(extension_map_t *map);
|
||||
|
||||
void DumpExMaps(char *filename);
|
||||
|
||||
#endif //_NFX_H
|
112
bin/nfxstat.c
Normal file
112
bin/nfxstat.c
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2011, Peter Haag
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: peter $
|
||||
*
|
||||
* $Id: nfxstat.c 25 2011-02-26 13:22:31Z peter $
|
||||
*
|
||||
* $LastChangedRevision: 25 $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifndef DEVEL
|
||||
# define dbg_printf(...) /* printf(__VA_ARGS__) */
|
||||
#else
|
||||
# define dbg_printf(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
#include "nf_common.h"
|
||||
#include "nffile.h"
|
||||
#include "nfxstat.h"
|
||||
|
||||
|
||||
xstat_t *InitXStat(nffile_t *nffile) {
|
||||
xstat_t *xs;
|
||||
size_t block_size;
|
||||
|
||||
// extended by the record link 2*data[4], but does no harm
|
||||
block_size = sizeof(xstat_t) + sizeof(data_block_header_t) + sizeof(flow_port_histogram_t) + sizeof(flow_bpp_histogram_t);
|
||||
|
||||
xs = (xstat_t *)malloc(block_size);
|
||||
if ( !xs ) {
|
||||
LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xs->block_header = (data_block_header_t *)((pointer_addr_t)xs + sizeof(xstat_t));
|
||||
// preset the fields
|
||||
xs->block_header->NumRecords = 2; // 2 histogram records are included
|
||||
xs->block_header->size = block_size;
|
||||
xs->block_header->id = Large_BLOCK_Type;
|
||||
xs->block_header->flags = 0;
|
||||
|
||||
xs->port_histogram = (flow_port_histogram_t *)((pointer_addr_t)xs + sizeof(xstat_t) + sizeof(data_block_header_t));
|
||||
xs->bpp_histogram = (flow_bpp_histogram_t *)((pointer_addr_t)xs + sizeof(xstat_t) + sizeof(data_block_header_t) + sizeof(flow_port_histogram_t) - 4); // without link pointer data[4]
|
||||
|
||||
// XXX add catalog entry
|
||||
// SetFlag(nffile->file_header->flags, FLAG_EXTENDED_STATS);
|
||||
|
||||
ResetPortHistogram(xs->port_histogram);
|
||||
ResetBppHistogram(xs->bpp_histogram);
|
||||
|
||||
return xs;
|
||||
|
||||
} // End of InitXStat
|
||||
|
||||
void ResetPortHistogram(flow_port_histogram_t *port_histogram) {
|
||||
|
||||
memset((void *)port_histogram, 0, sizeof(flow_port_histogram_t) - 4); // without link pointer data[4]
|
||||
port_histogram->record_header.type = PortHistogramType;
|
||||
port_histogram->record_header.size = sizeof(flow_port_histogram_t) - 4;
|
||||
|
||||
} // End of ResetPortHistogram
|
||||
|
||||
void ResetBppHistogram(flow_bpp_histogram_t *bpp_histogram) {
|
||||
|
||||
memset((void *)bpp_histogram, 0, sizeof(bpp_histogram_t) - 4); // without link pointer data[4]
|
||||
bpp_histogram->record_header.type = BppHistogramType;
|
||||
bpp_histogram->record_header.size = sizeof(flow_port_histogram_t) - 4;
|
||||
|
||||
} // End of ResetBppHistogram
|
||||
|
82
bin/nfxstat.h
Normal file
82
bin/nfxstat.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2011, Peter Haag
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: peter $
|
||||
*
|
||||
* $Id: nfxstat.h 25 2011-02-26 13:22:31Z peter $
|
||||
*
|
||||
* $LastChangedRevision: 25 $
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
typedef struct port_histogram_s {
|
||||
uint32_t count;
|
||||
uint32_t port[65536];
|
||||
} port_histogram_t;
|
||||
|
||||
typedef struct bpp_histogram_s {
|
||||
uint32_t count;
|
||||
#define MAX_BPP 9000
|
||||
uint32_t bpp[MAX_BPP];
|
||||
} bpp_histogram_t;
|
||||
|
||||
typedef struct flow_port_histogram_s {
|
||||
// type = PortHistogramType
|
||||
L_record_header_t record_header;
|
||||
port_histogram_t src_tcp;
|
||||
port_histogram_t dst_tcp;
|
||||
port_histogram_t src_udp;
|
||||
port_histogram_t dst_udp;
|
||||
uint8_t data[4]; // .. more data below
|
||||
} flow_port_histogram_t;
|
||||
|
||||
typedef struct flow_bpp_histogram_s {
|
||||
// type = BppHistogramType
|
||||
L_record_header_t record_header;
|
||||
bpp_histogram_t tcp;
|
||||
bpp_histogram_t udp;
|
||||
uint8_t data[4]; // .. more data below
|
||||
} flow_bpp_histogram_t;
|
||||
|
||||
// Extended stat record
|
||||
typedef struct xstat_s {
|
||||
data_block_header_t *block_header;
|
||||
flow_port_histogram_t *port_histogram;
|
||||
flow_bpp_histogram_t *bpp_histogram;
|
||||
} xstat_t;
|
||||
|
||||
|
||||
xstat_t *InitXStat(nffile_t *nffile);
|
||||
|
||||
void ResetPortHistogram(flow_port_histogram_t *port_histogram);
|
||||
|
||||
void ResetBppHistogram(flow_bpp_histogram_t *bpp_histogram);
|
||||
|
||||
|
229
bin/panonymizer.c
Normal file
229
bin/panonymizer.c
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
*
|
||||
* $Author: haag $
|
||||
*
|
||||
* $Id: panonymizer.c 39 2009-11-25 08:11:15Z haag $
|
||||
*
|
||||
* $LastChangedRevision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
/* Original disclaimer
|
||||
* Atlanta, Georgia 30332.
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The following Software is posted on the Internet by the Georgia
|
||||
* Tech Research Corporation (GTRC). It was developed by employees
|
||||
* of the Georgia Institute of Technology in the College of Computing.
|
||||
* GTRC hereby grants to the user a non-exclusive, royalty-free
|
||||
* license to utilize such Software for the User's own purposes
|
||||
* pursuant to the following conditions.
|
||||
*
|
||||
*
|
||||
* THE SOFTWARE IS LICENSED ON AN "AS IS" BASIS. GTRC MAKES NO WARRANTY
|
||||
* THAT ALL ERRORS CAN BE OR HAVE BEEN ELIMINATED FROM THE SOFTWARE.
|
||||
* GTRC SHALL NOT BE RESPONSIBLE FOR LOSSES OF ANY KIND RESULTING FROM
|
||||
* THE USE OF THE SOFTWARE AND ITS ACCOMPANYING DOCUMENTATION, AND CAN
|
||||
* IN NO WAY PROVIDE COMPENSATION FOR ANY LOSSES SUSTAINED, INCLUDING
|
||||
* BUT NOT LIMITED TO ANY OBLIGATION, LIABILITY, RIGHT, CLAIM OR REMEDY
|
||||
* FOR TORT, OF FOR ANY ACTUAL OR ALLEGED INFRINGEMENT OF PATENTS, COPYRIGHTS,
|
||||
* TRADE SECRETS, OR SIMILAR RIGHTS OF THIRD PARTIES, NOR ANY BUSINESS
|
||||
* EXPENSE, MACHINE DOWNTIME, OR DAMAGES CAUSED LICENSEE BY ANY DEFICIENCY,
|
||||
* DEFECT OR ERROR IN THE SOFTWARE OR MALFUNCTION THEREOF, NOR ANY
|
||||
* INCIDENTAL OR CONSEQUENTIAL DAMAGES, HOWEVER CAUSED. GTRC DISCLAIMS
|
||||
* ALL WARRANTIES, BOTH EXPRESS AND IMPLIED RESPECTING THE USE AND
|
||||
* OPERATION OF THE SOFTWARE AND ANY ACCOMPANYING DOCUMENTATION,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* PARTICULAR PURPOSE AND ANY IMPLIED WARRANTY ARISING FROM COURSE
|
||||
* OF PERFORMANCE, COURSE OF DEALING OR USAGE OF TRADE. GTRC MAKES NO
|
||||
* WARRANTY THAT THE SOFTWARE IS ADEQUATELY OR COMPLETELY DESCRIBED
|
||||
* IN, OR BEHAVES IN ACCORDANCE WITH ANY OF THE ACCOMPANYING
|
||||
* DOCUMENTATION. THE USER OF THE SOFTWARE IS EXPECTED TO MAKE THE FINAL
|
||||
* EVALUATION OF THE SOFTWARE'S USEFULNESS IN USER'S OWN ENVIRONMENT.
|
||||
*
|
||||
*
|
||||
* Package: Crypto-PAn 1.0
|
||||
* File: panonymizer.cpp
|
||||
* Last Update: April 17, 2002
|
||||
* Author: Jinliang Fan
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "panonymizer.h"
|
||||
|
||||
static uint8_t m_key[16]; //128 bit secret key
|
||||
static uint8_t m_pad[16]; //128 bit secret pad
|
||||
|
||||
// Init
|
||||
void PAnonymizer_Init(uint8_t * key) {
|
||||
//initialize the 128-bit secret key.
|
||||
memcpy(m_key, key, 16);
|
||||
//initialize the Rijndael cipher.
|
||||
Rijndael_init(ECB, Encrypt, key, Key16Bytes, NULL);
|
||||
//initialize the 128-bit secret pad. The pad is encrypted before being used for padding.
|
||||
Rijndael_blockEncrypt(key + 16, 128, m_pad);
|
||||
}
|
||||
|
||||
int ParseCryptoPAnKey ( char *s, char *key ) {
|
||||
int i, j;
|
||||
char numstr[3];
|
||||
uint32_t len = strlen(s);
|
||||
|
||||
if ( len < 32 || len > 66 ) {
|
||||
fprintf(stderr, "*** CryptoPAnKey error: size: %u\n", len);
|
||||
fprintf(stderr, "*** Need either a plain 32 char string, or a 32 byte hex key starting with 0x..\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( strlen(s) == 32 ) {
|
||||
// Key is a string
|
||||
strncpy(key, s, 32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
s[1] = tolower(s[1]);
|
||||
numstr[2] = 0;
|
||||
if ( strlen(s) == 66 && s[0] == '0' && s[1] == 'x' ) {
|
||||
j = 2;
|
||||
for ( i=0; i<32; i++ ) {
|
||||
if ( !isxdigit((int)s[j]) || !isxdigit((int)s[j+1]) )
|
||||
return 0;
|
||||
numstr[0] = s[j++];
|
||||
numstr[1] = s[j++];
|
||||
key[i] = strtol(numstr, NULL, 16);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// It's an invalid key
|
||||
fprintf(stderr, "*** CryptoPAnKey error: size: %u\n", len);
|
||||
fprintf(stderr, "*** Need either a plain 32 char string, or a 32 byte hex key starting with 0x..\n");
|
||||
return 0;
|
||||
|
||||
} // End of ParseCryptoPAnKey
|
||||
|
||||
//Anonymization funtion
|
||||
uint32_t anonymize(const uint32_t orig_addr) {
|
||||
uint8_t rin_output[16];
|
||||
uint8_t rin_input[16];
|
||||
|
||||
uint32_t result = 0;
|
||||
uint32_t first4bytes_pad, first4bytes_input;
|
||||
int pos;
|
||||
|
||||
memcpy(rin_input, m_pad, 16);
|
||||
first4bytes_pad = (((uint32_t) m_pad[0]) << 24) + (((uint32_t) m_pad[1]) << 16) +
|
||||
(((uint32_t) m_pad[2]) << 8) + (uint32_t) m_pad[3];
|
||||
|
||||
// For each prefixes with length from 0 to 31, generate a bit using the Rijndael cipher,
|
||||
// which is used as a pseudorandom function here. The bits generated in every rounds
|
||||
// are combineed into a pseudorandom one-time-pad.
|
||||
for (pos = 0; pos <= 31 ; pos++) {
|
||||
|
||||
//Padding: The most significant pos bits are taken from orig_addr. The other 128-pos
|
||||
//bits are taken from m_pad. The variables first4bytes_pad and first4bytes_input are used
|
||||
//to handle the annoying byte order problem.
|
||||
if (pos==0) {
|
||||
first4bytes_input = first4bytes_pad;
|
||||
}
|
||||
else {
|
||||
first4bytes_input = ((orig_addr >> (32-pos)) << (32-pos)) | ((first4bytes_pad<<pos) >> pos);
|
||||
}
|
||||
rin_input[0] = (uint8_t) (first4bytes_input >> 24);
|
||||
rin_input[1] = (uint8_t) ((first4bytes_input << 8) >> 24);
|
||||
rin_input[2] = (uint8_t) ((first4bytes_input << 16) >> 24);
|
||||
rin_input[3] = (uint8_t) ((first4bytes_input << 24) >> 24);
|
||||
|
||||
//Encryption: The Rijndael cipher is used as pseudorandom function. During each
|
||||
//round, only the first bit of rin_output is used.
|
||||
Rijndael_blockEncrypt(rin_input, 128, rin_output);
|
||||
|
||||
//Combination: the bits are combined into a pseudorandom one-time-pad
|
||||
result |= (rin_output[0] >> 7) << (31-pos);
|
||||
}
|
||||
//XOR the orginal address with the pseudorandom one-time-pad
|
||||
return result ^ orig_addr;
|
||||
}
|
||||
|
||||
/* little endian CPU's are boring! - but give it a try
|
||||
* orig_addr is a ptr to memory, return by inet_pton for IPv6
|
||||
* anon_addr return the result in the same order
|
||||
*/
|
||||
void anonymize_v6(const uint64_t orig_addr[2], uint64_t *anon_addr) {
|
||||
uint8_t rin_output[16], *orig_bytes, *result;
|
||||
uint8_t rin_input[16];
|
||||
|
||||
int pos, i, bit_num, left_byte;
|
||||
|
||||
anon_addr[0] = anon_addr[1] = 0;
|
||||
result = (uint8_t *)anon_addr;
|
||||
orig_bytes = (uint8_t *)orig_addr;
|
||||
|
||||
// For each prefixes with length from 0 to 127, generate a bit using the Rijndael cipher,
|
||||
// which is used as a pseudorandom function here. The bits generated in every rounds
|
||||
// are combineed into a pseudorandom one-time-pad.
|
||||
for (pos = 0; pos <= 127 ; pos++) {
|
||||
bit_num = pos & 0x7;
|
||||
left_byte = (pos >> 3);
|
||||
|
||||
for ( i=0; i<left_byte; i++ ) {
|
||||
rin_input[i] = orig_bytes[i];
|
||||
}
|
||||
rin_input[left_byte] = orig_bytes[left_byte] >> (7-bit_num) << (7-bit_num) | (m_pad[left_byte]<<bit_num) >> bit_num;
|
||||
for ( i=left_byte+1; i<16; i++ ) {
|
||||
rin_input[i] = m_pad[i];
|
||||
}
|
||||
|
||||
//Encryption: The Rijndael cipher is used as pseudorandom function. During each
|
||||
//round, only the first bit of rin_output is used.
|
||||
Rijndael_blockEncrypt(rin_input, 128, rin_output);
|
||||
|
||||
//Combination: the bits are combined into a pseudorandom one-time-pad
|
||||
result[left_byte] |= (rin_output[0] >> 7) << bit_num;
|
||||
|
||||
}
|
||||
//XOR the orginal address with the pseudorandom one-time-pad
|
||||
anon_addr[0] ^= orig_addr[0];
|
||||
anon_addr[1] ^= orig_addr[1];
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user