2
* Copyright (C) 2002-04 Luca Deri <deri@ntop.org>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
/* This plugin works only with threads */
23
/* ******************************************************************
25
-----------------------------------------------------------------------
26
Copyright (c) 2001 InMon Corp. All rights reserved.
27
-----------------------------------------------------------------------
29
Redistribution and use in source and binary forms, with or without
30
modification, are permitted provided that the following conditions
33
1. Redistributions of source code must retain the above copyright
34
notice, this list of conditions and the following disclaimer.
36
2. Redistributions in binary form must reproduce the above
37
copyright notice, this list of conditions and the following
38
disclaimer in the documentation and/or other materials provided
39
with the distribution.
41
3. Redistributions of any form whatsoever must retain the following
43
"This product includes sFlow(TM), freely available from
44
http://www.inmon.com/".
46
4. All advertising materials mentioning features or use of this
47
software must display the following acknowledgment:
48
"This product includes sFlow(TM), freely available from
49
http://www.inmon.com/".
51
5. InMon Corp. may publish revised and/or new versions
52
of the license from time to time. Each version will be given a
53
distinguishing version number. Once covered code has been
54
published under a particular version of the license, you may
55
always continue to use it under the terms of that version. You
56
may also choose to use such covered code under the terms of any
57
subsequent version of the license published by InMon Corp.
58
No one other than the InMon Corp. has the right to modify the terms
59
applicable to covered code created under this License.
61
6. The name "sFlow" must not be used to endorse or promote products
62
derived from this software without prior written permission
63
from InMon Corp. This does not apply to add-on libraries or tools
64
that work in conjunction with sFlow. In such a case the sFlow name
65
may be used to indicate that the product supports sFlow.
67
7. Products derived from this software may not be called "sFlow",
68
nor may "sFlow" appear in their name, without prior written
69
permission of InMon Corp.
72
THIS SOFTWARE IS PROVIDED BY INMON CORP. ``AS IS'' AND
73
ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
74
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
75
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
76
INMON CORP. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
77
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
78
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
79
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
80
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
81
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
82
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
83
OF THE POSSIBILITY OF SUCH DAMAGE.
85
--------------------------------------------------------------------
87
This software consists of voluntary contributions made by many
88
individuals on behalf of InMon Corp.
90
InMon Corp. can be contacted via Email at info@inmon.com.
92
For more information on InMon Corp. and sFlow,
93
please see http://www.inmon.com/.
95
InMon Public License Version 1.0 written May 31, 2001
97
******************************************************************* */
100
#include "globals-report.h"
102
static int debug = 0;
103
static ProbeInfo probeList[MAX_NUM_PROBES];
105
#ifdef CFG_MULTITHREADED
106
pthread_t sFlowThread;
107
static int threadActive;
110
static void initSflowInSocket(void); /* forward */
111
static void setPluginStatus(char * status); /* forward */
113
/* ****************************** */
115
/* define my own IP header struct - to ease portability */
118
u_int8_t version_and_headerLen;
133
u_int16_t th_sport; /* source port */
134
u_int16_t th_dport; /* destination port */
135
u_int32_t th_seq; /* sequence number */
136
u_int32_t th_ack; /* acknowledgement number */
137
u_int8_t th_off_and_unused;
139
u_int16_t th_win; /* window */
140
u_int16_t th_sum; /* checksum */
141
u_int16_t th_urp; /* urgent pointer */
146
u_int16_t uh_sport; /* source port */
147
u_int16_t uh_dport; /* destination port */
148
u_int16_t uh_ulen; /* udp length */
149
u_int16_t uh_sum; /* udp checksum */
155
u_int8_t type; /* message type */
156
u_int8_t code; /* type sub-code */
157
/* ignore the rest */
161
#if (!defined(HAVE_IN6_ADDR)) && (!defined(WIN32)) && (!defined(DARWIN))
166
u_int8_t u6_addr8[16];
167
u_int16_t u6_addr16[8];
168
u_int32_t u6_addr32[4];
171
#endif /* HAVE_IN6_ADDR */
173
enum INMAddress_type {
174
INMADDRESSTYPE_IP_V4 = 1,
175
INMADDRESSTYPE_IP_V6 = 2
178
typedef union _INMAddress_value {
179
struct in_addr ip_v4;
180
struct in6_addr ip_v6;
183
typedef struct _INMAddress {
184
u_int32_t type; /* enum INMAddress_type */
185
INMAddress_value address;
188
/* Packet header data */
190
#define INM_MAX_HEADER_SIZE 256 /* The maximum sampled header size. */
192
/* The header protocol describes the format of the sampled header */
193
enum INMHeader_protocol {
194
INMHEADER_ETHERNET_ISO8023 = 1,
195
INMHEADER_ISO88024_TOKENBUS = 2,
196
INMHEADER_ISO88025_TOKENRING = 3,
198
INMHEADER_FRAME_RELAY = 5,
203
INMHEADER_AAL5_IP = 10, /* e.g. Cisco AAL5 mux */
208
typedef struct _INMSampled_header {
209
u_int32_t header_protocol; /* (enum INMHeader_protocol) */
210
u_int32_t frame_length; /* Original length of packet before sampling */
211
u_int32_t header_length; /* length of sampled header bytes to follow */
212
u_int8_t header[INM_MAX_HEADER_SIZE]; /* Header bytes */
215
/* Packet IP version 4 data */
217
typedef struct _INMSampled_ipv4 {
218
u_int32_t length; /* The length of the IP packet
219
excluding lower layer encapsulations */
220
u_int32_t protocol; /* IP Protocol type (for example, TCP = 6, UDP = 17) */
221
struct in_addr src_ip; /* Source IP Address */
222
struct in_addr dst_ip; /* Destination IP Address */
223
u_int32_t src_port; /* TCP/UDP source port number or equivalent */
224
u_int32_t dst_port; /* TCP/UDP destination port number or equivalent */
225
u_int32_t tcp_flags; /* TCP flags */
226
u_int32_t tos; /* IP type of service */
229
/* Packet IP version 6 data */
231
typedef struct _INMSampled_ipv6 {
232
u_int32_t length; /* The length of the IP packet
233
excluding lower layer encapsulations */
234
u_int32_t protocol; /* IP Protocol type (for example, TCP = 6, UDP = 17) */
235
struct in6_addr src_ip; /* Source IP Address */
236
struct in6_addr dst_ip; /* Destination IP Address */
237
u_int32_t src_port; /* TCP/UDP source port number or equivalent */
238
u_int32_t dst_port; /* TCP/UDP destination port number or equivalent */
239
u_int32_t tcp_flags; /* TCP flags */
240
u_int32_t tos; /* IP type of service */
246
enum INMPacket_information_type {
247
INMPACKETTYPE_HEADER = 1, /* Packet headers are sampled */
248
INMPACKETTYPE_IPV4 = 2, /* IP version 4 data */
249
INMPACKETTYPE_IPV6 = 3 /* IP version 4 data */
252
typedef union _INMPacket_data_type {
253
INMSampled_header header;
254
INMSampled_ipv4 ipv4;
255
INMSampled_ipv6 ipv6;
256
} INMPacket_data_type;
258
/* Extended data types */
260
/* Extended switch data */
262
typedef struct _INMExtended_switch {
263
u_int32_t src_vlan; /* The 802.1Q VLAN id of incomming frame */
264
u_int32_t src_priority; /* The 802.1p priority */
265
u_int32_t dst_vlan; /* The 802.1Q VLAN id of outgoing frame */
266
u_int32_t dst_priority; /* The 802.1p priority */
267
} INMExtended_switch;
269
/* Extended router data */
271
typedef struct _INMExtended_router {
272
INMAddress nexthop; /* IP address of next hop router */
273
u_int32_t src_mask; /* Source address prefix mask bits */
274
u_int32_t dst_mask; /* Destination address prefix mask bits */
275
} INMExtended_router;
277
/* Extended gateway data */
279
typedef struct _INMExtended_gateway {
280
u_int32_t as; /* AS number for this gateway */
282
u_int32_t src_peer_as;
283
u_int32_t dst_as_path_length;
284
u_int32_t *dst_as_path;
285
} INMExtended_gateway;
287
/* Extended user data */
288
typedef struct _INMExtended_user {
289
u_int32_t src_user_len;
291
u_int32_t dst_user_len;
297
enum INMExtended_information_type {
298
INMEXTENDED_SWITCH = 1, /* Extended switch information */
299
INMEXTENDED_ROUTER = 2, /* Extended router information */
300
INMEXTENDED_GATEWAY = 3, /* Extended gateway router information */
301
INMEXTENDED_USER = 4 /* Extended TACAS/RADIUS user information */
304
/* Format of a single sample */
306
typedef struct _INMFlow_sample {
307
u_int32_t sequence_number; /* Incremented with each flow sample
309
u_int32_t source_id; /* fsSourceId */
310
u_int32_t sampling_rate; /* fsPacketSamplingRate */
311
u_int32_t sample_pool; /* Total number of packets that could have been
312
sampled (i.e. packets skipped by sampling
313
process + total number of samples) */
314
u_int32_t drops; /* Number of times a packet was dropped due to
316
u_int32_t input; /* SNMP ifIndex of input interface.
317
0 if interface is not known. */
318
u_int32_t output; /* SNMP ifIndex of output interface,
319
0 if interface is not known.
320
Set most significant bit to indicate
321
multiple destination interfaces
322
(i.e. in case of broadcast or multicast)
323
and set lower order bits to indicate
324
number of destination interfaces.
326
0x00000002 indicates ifIndex = 2
327
0x00000000 ifIndex unknown.
328
0x80000007 indicates a packet sent
330
0x80000000 indicates a packet sent to
332
interfaces greater than 1.*/
333
u_int32_t packet_data_tag; /* enum INMPacket_information_type */
334
INMPacket_data_type packet_data; /* Information about sampled packet */
336
/* in the sFlow packet spec the next field is the number of extended objects
337
followed by the data for each one (tagged with the type). Here we just
338
provide space for each one, and flags to enable them. The correct format
339
is then put together by the serialization code */
341
INMExtended_switch switchDevice;
343
INMExtended_router router;
345
INMExtended_gateway gateway;
347
INMExtended_user user;
352
/* Generic interface counters - see RFC 1573, 2233 */
354
typedef struct _INMIf_counters {
358
u_int32_t ifDirection; /* Derived from MAU MIB (RFC 2239)
359
0 = unknown, 1 = full-duplex,
360
2 = half-duplex, 3 = in, 4 = out */
361
u_int32_t ifStatus; /* bit field with the following bits assigned:
362
bit 0 = ifAdminStatus (0 = down, 1 = up)
363
bit 1 = ifOperStatus (0 = down, 1 = up) */
364
u_int64_t ifInOctets;
365
u_int32_t ifInUcastPkts;
366
u_int32_t ifInMulticastPkts;
367
u_int32_t ifInBroadcastPkts;
368
u_int32_t ifInDiscards;
369
u_int32_t ifInErrors;
370
u_int32_t ifInUnknownProtos;
371
u_int64_t ifOutOctets;
372
u_int32_t ifOutUcastPkts;
373
u_int32_t ifOutMulticastPkts;
374
u_int32_t ifOutBroadcastPkts;
375
u_int32_t ifOutDiscards;
376
u_int32_t ifOutErrors;
377
u_int32_t ifPromiscuousMode;
380
/* Ethernet interface counters - see RFC 2358 */
381
typedef struct _INMEthernet_specific_counters {
382
u_int32_t dot3StatsAlignmentErrors;
383
u_int32_t dot3StatsFCSErrors;
384
u_int32_t dot3StatsSingleCollisionFrames;
385
u_int32_t dot3StatsMultipleCollisionFrames;
386
u_int32_t dot3StatsSQETestErrors;
387
u_int32_t dot3StatsDeferredTransmissions;
388
u_int32_t dot3StatsLateCollisions;
389
u_int32_t dot3StatsExcessiveCollisions;
390
u_int32_t dot3StatsInternalMacTransmitErrors;
391
u_int32_t dot3StatsCarrierSenseErrors;
392
u_int32_t dot3StatsFrameTooLongs;
393
u_int32_t dot3StatsInternalMacReceiveErrors;
394
u_int32_t dot3StatsSymbolErrors;
395
} INMEthernet_specific_counters;
397
typedef struct _INMEthernet_counters {
398
INMIf_counters generic;
399
INMEthernet_specific_counters ethernet;
400
} INMEthernet_counters;
402
/* FDDI interface counters - see RFC 1512 */
403
typedef struct _INMFddi_counters {
404
INMIf_counters generic;
407
/* Token ring counters - see RFC 1748 */
409
typedef struct _INMTokenring_specific_counters {
410
u_int32_t dot5StatsLineErrors;
411
u_int32_t dot5StatsBurstErrors;
412
u_int32_t dot5StatsACErrors;
413
u_int32_t dot5StatsAbortTransErrors;
414
u_int32_t dot5StatsInternalErrors;
415
u_int32_t dot5StatsLostFrameErrors;
416
u_int32_t dot5StatsReceiveCongestions;
417
u_int32_t dot5StatsFrameCopiedErrors;
418
u_int32_t dot5StatsTokenErrors;
419
u_int32_t dot5StatsSoftErrors;
420
u_int32_t dot5StatsHardErrors;
421
u_int32_t dot5StatsSignalLoss;
422
u_int32_t dot5StatsTransmitBeacons;
423
u_int32_t dot5StatsRecoverys;
424
u_int32_t dot5StatsLobeWires;
425
u_int32_t dot5StatsRemoves;
426
u_int32_t dot5StatsSingles;
427
u_int32_t dot5StatsFreqErrors;
428
} INMTokenring_specific_counters;
430
typedef struct _INMTokenring_counters {
431
INMIf_counters generic;
432
INMTokenring_specific_counters tokenring;
433
} INMTokenring_counters;
435
/* 100 BaseVG interface counters - see RFC 2020 */
437
typedef struct _INMVg_specific_counters {
438
u_int32_t dot12InHighPriorityFrames;
439
u_int64_t dot12InHighPriorityOctets;
440
u_int32_t dot12InNormPriorityFrames;
441
u_int64_t dot12InNormPriorityOctets;
442
u_int32_t dot12InIPMErrors;
443
u_int32_t dot12InOversizeFrameErrors;
444
u_int32_t dot12InDataErrors;
445
u_int32_t dot12InNullAddressedFrames;
446
u_int32_t dot12OutHighPriorityFrames;
447
u_int64_t dot12OutHighPriorityOctets;
448
u_int32_t dot12TransitionIntoTrainings;
449
u_int64_t dot12HCInHighPriorityOctets;
450
u_int64_t dot12HCInNormPriorityOctets;
451
u_int64_t dot12HCOutHighPriorityOctets;
452
} INMVg_specific_counters;
454
typedef struct _INMVg_counters {
455
INMIf_counters generic;
456
INMVg_specific_counters vg;
461
typedef struct _INMWan_counters {
462
INMIf_counters generic;
465
typedef struct _INMVlan_counters {
469
u_int32_t multicastPkts;
470
u_int32_t broadcastPkts;
476
enum INMCounters_version {
477
INMCOUNTERSVERSION_GENERIC = 1,
478
INMCOUNTERSVERSION_ETHERNET = 2,
479
INMCOUNTERSVERSION_TOKENRING = 3,
480
INMCOUNTERSVERSION_FDDI = 4,
481
INMCOUNTERSVERSION_VG = 5,
482
INMCOUNTERSVERSION_WAN = 6,
483
INMCOUNTERSVERSION_VLAN = 7
486
typedef union _INMCounters_type {
487
INMIf_counters generic;
488
INMEthernet_counters ethernet;
489
INMTokenring_counters tokenring;
490
INMFddi_counters fddi;
493
INMVlan_counters vlan;
496
typedef struct _INMCounters_sample_hdr {
497
u_int32_t sequence_number; /* Incremented with each counters sample
498
generated by this source_id */
499
u_int32_t source_id; /* fsSourceId */
500
u_int32_t sampling_interval; /* fsCounterSamplingInterval */
501
} INMCounters_sample_hdr;
503
typedef struct _INMCounters_sample {
504
INMCounters_sample_hdr hdr;
505
u_int32_t counters_type_tag; /* Enum INMCounters_version */
506
INMCounters_type counters; /* Counter set for this interface type */
507
} INMCounters_sample;
509
enum INMSample_types {
514
typedef union _INMSample_type {
515
INMFlow_sample flowsample;
516
INMCounters_sample counterssample;
519
/* Format of a sample datagram */
521
enum INMDatagram_version {
522
INMDATAGRAM_VERSION2 = 2,
525
typedef struct _INMSample_datagram_hdr {
526
u_int32_t datagram_version; /* (enum INMDatagram_version) = VERSION2 */
527
INMAddress agent_address; /* IP address of sampling agent */
528
u_int32_t sequence_number; /* Incremented with each sample datagram
530
u_int32_t uptime; /* Current time (in milliseconds since device
531
last booted). Should be set as close to
532
datagram transmission time as possible.*/
533
u_int32_t num_samples; /* Number of flow and counters samples to follow */
534
} INMSample_datagram_hdr;
536
typedef struct _SFSample {
537
struct in_addr sourceIP;
538
struct in_addr agent_addr;
554
/* sample stream info */
557
u_long sampledPacketSize;
558
u_long samplesGenerated;
559
u_long meanSkipCount;
563
/* the sampled header */
564
u_long packet_data_tag;
565
u_long headerProtocol;
571
struct in_addr dcd_srcIP;
572
struct in_addr dcd_dstIP;
573
u_int dcd_ipProtocol;
587
u_long internalPriority;
591
/* extended data fields */
593
u_long extended_data_tag;
594
#define SASAMPLE_EXTENDED_DATA_SWITCH 1
595
#define SASAMPLE_EXTENDED_DATA_ROUTER 4
596
#define SASAMPLE_EXTENDED_DATA_GATEWAY 8
597
#define SASAMPLE_EXTENDED_DATA_USER 16
599
/* IP forwarding info */
600
struct in_addr nextHop;
606
u_long dst_as_path_len;
610
#define SA_MAX_EXTENDED_USER_LEN 200
612
char src_user[SA_MAX_EXTENDED_USER_LEN+1];
614
char dst_user[SA_MAX_EXTENDED_USER_LEN+1];
617
u_long statsSamplingInterval;
618
u_long counterBlockVersion;
622
#define GETDATA32(target, datap) (target) = ntohl(*(datap)++)
623
#define GETDATA32_NOBSWAP(target, datap) (target) = *(datap)++
624
#define GETDATA64(target, datap) \
625
do { u_int64_t tmpLo, tmpHi; \
626
GETDATA32(tmpHi, (datap)); \
627
GETDATA32(tmpLo, (datap)); \
628
(target) = (tmpHi << 32) + tmpLo; \
632
static u_long *readExtendedSwitch(SFSample *sample, u_long *datap, u_char *endPtr)
634
GETDATA32(sample->in_vlan, datap);
635
GETDATA32(sample->in_priority, datap);
636
GETDATA32(sample->out_vlan, datap);
637
GETDATA32(sample->out_priority, datap);
639
sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_SWITCH;
642
traceEvent(CONST_TRACE_INFO, "in_vlan %lu", sample->in_vlan);
643
traceEvent(CONST_TRACE_INFO, "in_priority %lu", sample->in_priority);
644
traceEvent(CONST_TRACE_INFO, "out_vlan %lu", sample->out_vlan);
645
traceEvent(CONST_TRACE_INFO, "out_priority %lu", sample->out_priority);
651
static char *IP_to_a(u_long ipaddr, char *buf)
653
u_char *ip = (u_char *)&ipaddr;
654
sprintf(buf, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
658
/*_________________---------------------------__________________
659
_________________ printHex __________________
660
-----------------___________________________------------------
663
static u_char bin2hex(int nib) { return (nib < 10) ? ('0' + nib) : ('A' - 10 + nib); }
665
static int printHex(const u_char *a, int len, u_char *buf,
666
int bufLen, int marker, int bytesPerOutputLine)
670
for(; i < len; i++) {
672
if(b > (bufLen - 10)) break;
673
if(marker > 0 && i == marker) {
680
buf[b++] = bin2hex(byte >> 4);
681
buf[b++] = bin2hex(byte & 0x0f);
682
if(i > 0 && (i % bytesPerOutputLine) == 0) buf[b++] = '\n';
684
// separate the bytes with a dash
685
if (i < (len - 1)) buf[b++] = '-';
692
/*_________________---------------------------__________________
693
_________________ decodeLinkLayer __________________
694
-----------------___________________________------------------
695
store the offset to the start of the ipv4 header in the sequence_number field
696
or -1 if not found. Decode the 802.1d if it's there.
699
#define NFT_ETHHDR_SIZ 14
700
#define NFT_8022_SIZ 3
701
#define NFT_MAX_8023_LEN 1500
703
#define NFT_MIN_SIZ (NFT_ETHHDR_SIZ + sizeof(struct myiphdr))
705
static void decodeLinkLayer(SFSample *sample)
707
u_char *start = (u_char *)sample->header;
708
u_char *end = start + sample->headerLen;
712
/* assume not found */
713
sample->offsetToIPV4 = -1;
715
if(sample->headerLen < NFT_ETHHDR_SIZ) return; /* not enough for an Ethernet header */
717
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dstMAC %02x%02x%02x%02x%02x%02x",
718
ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]);
720
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: srcMAC %02x%02x%02x%02x%02x%02x",
721
ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]);
723
type_len = (ptr[0] << 8) + ptr[1];
726
if(type_len == 0x8100) {
727
/* VLAN - next two bytes */
728
u_int32_t vlanData = (ptr[0] << 8) + ptr[1];
729
u_int32_t vlan = vlanData & 0x0fff;
730
u_int32_t priority = vlanData >> 13;
731
/* _____________________________________ */
732
/* | pri | c | vlan-id | */
733
/* ------------------------------------- */
734
/* [priority = 3bits] [Canonical Format Flag = 1bit] [vlan-id = 12 bits] */
736
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: decodedVLAN %lu", vlan);
737
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: decodedPriority %lu", priority);
739
/* now get the type_len again (next two bytes) */
740
type_len = (ptr[0] << 8) + ptr[1];
743
/* now we're just looking for IP */
744
if(sample->headerLen < NFT_MIN_SIZ) return; /* not enough for an IPv4 header */
747
if(type_len == 0x0200 || type_len == 0x0201 || type_len == 0x0600) {
748
#define IPX_HDR_LEN 30
749
#define IPX_MAX_DATA 546
750
int ipxChecksum = (ptr[0] == 0xff && ptr[1] == 0xff);
751
int ipxLen = (ptr[2] << 8) + ptr[3];
753
ipxLen >= IPX_HDR_LEN &&
754
ipxLen <= (IPX_HDR_LEN + IPX_MAX_DATA))
755
/* we don't do anything with IPX here */
759
if(type_len <= NFT_MAX_8023_LEN) {
760
/* assume 802.3+802.2 header */
765
type_len = (ptr[3] << 8) + ptr[4];
769
if (ptr[0] == 0x06 &&
774
/* force the type_len to be IP so we can inline the IP decode below */
781
/* assume type_len is an ethernet-type now */
783
if(type_len == 0x0800) {
785
if((end - ptr) < sizeof(struct myiphdr)) return;
786
/* look at first byte of header.... */
787
/* ___________________________ */
788
/* | version | hdrlen | */
789
/* --------------------------- */
790
if((*ptr >> 4) != 4) return; /* not version 4 */
791
if((*ptr & 15) < 5) return; /* not IP (hdr len must be 5 quads or more) */
792
/* survived all the tests - store the offset to the start of the ip header */
793
sample->offsetToIPV4 = (ptr - start);
798
/*_________________---------------------------__________________
799
_________________ decodeIPV4 __________________
800
-----------------___________________________------------------
803
static void decodeIPV4(SFSample *sample)
805
if(sample->offsetToIPV4 > 0) {
807
u_char *ptr = sample->header + sample->offsetToIPV4;
808
/* Create a local copy of the IP header (cannot overlay
809
structure in case it is not quad-aligned...some
810
platforms would core-dump if we tried that). It's
811
OK coz this probably performs just as well anyway. */
813
memcpy(&ip, ptr, sizeof(ip));
814
/* Value copy all ip elements into sample */
815
sample->dcd_srcIP.s_addr = ip.saddr;
816
sample->dcd_dstIP.s_addr = ip.daddr;
817
sample->dcd_ipProtocol = ip.protocol;
818
sample->dcd_ipTos = ip.tos;
819
sample->dcd_ipTTL = ip.ttl;
820
/* Log out the decoded IP fields */
822
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: srcIP %s", IP_to_a(sample->dcd_srcIP.s_addr, buf));
823
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dstIP %s", IP_to_a(sample->dcd_dstIP.s_addr, buf));
824
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: IPProtocol %u", sample->dcd_ipProtocol);
825
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: IPTOS %u", sample->dcd_ipTos);
826
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: IPTTL %u", sample->dcd_ipTTL);
828
/* advance the pointer to the next protocol layer */
829
ptr += sizeof(struct myiphdr);
831
switch(ip.protocol) {
834
struct myicmphdr icmp;
835
memcpy(&icmp, ptr, sizeof(icmp));
837
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: ICMPType %u", icmp.type);
838
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: ICMPCode %u", icmp.code);
845
memcpy(&tcp, ptr, sizeof(tcp));
846
sample->dcd_sport = ntohs(tcp.th_sport);
847
sample->dcd_dport = ntohs(tcp.th_dport);
848
sample->dcd_tcpFlags = tcp.th_flags;
850
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: TCPSrcPort %u", sample->dcd_sport);
851
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: TCPDstPort %u",sample->dcd_dport);
852
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: TCPFlags %u", sample->dcd_tcpFlags);
859
memcpy(&udp, ptr, sizeof(udp));
860
sample->dcd_sport = ntohs(udp.uh_sport);
861
sample->dcd_dport = ntohs(udp.uh_dport);
863
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: UDPSrcPort %u", sample->dcd_sport);
864
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: UDPDstPort %u", sample->dcd_dport);
868
default: /* some other protcol */
874
/*_________________---------------------------__________________
875
_________________ writePcapHeader __________________
876
-----------------___________________________------------------
879
static void writePcapHeader() {
880
struct pcap_file_header hdr;
881
memset(&hdr, 0, sizeof(hdr));
882
hdr.magic = CONST_SFLOW_TCPDUMP_MAGIC;
883
hdr.version_major = CONST_SFLOW_PCAP_VERSION_MAJOR;
884
hdr.version_minor = CONST_SFLOW_PCAP_VERSION_MINOR;
888
hdr.linktype = DLT_EN10MB;
889
if (fwrite((char *)&hdr, sizeof(hdr), 1, stdout) != 1) {
890
printf("failed to write tcpdump header: %s\n", strerror(errno));
896
/*_________________---------------------------__________________
897
_________________ writePcapPacket __________________
898
-----------------___________________________------------------
901
static void writePcapPacket(SFSample *sample) {
902
struct pcap_pkthdr hdr;
905
hdr.ts.tv_sec = time(NULL);
907
hdr.caplen = sample->headerLen;
908
hdr.len = sample->sampledPacketSize;
910
if(myGlobals.sflowInSocket == 0)
911
myGlobals.initialPool = sample->samplePool;
913
myGlobals.numSamplesReceived++;
914
myGlobals.lastSample = sample->samplePool;
916
NTOHL(sample->sourceIP.s_addr);
918
for(i=0; i<MAX_NUM_PROBES; i++) {
919
if(probeList[i].probeAddr.s_addr == 0) {
920
probeList[i].probeAddr.s_addr = sample->sourceIP.s_addr;
921
probeList[i].pkts = 1;
923
} else if(probeList[i].probeAddr.s_addr == sample->sourceIP.s_addr) {
929
#ifdef CFG_MULTITHREADED
930
/* Obviously, sflow won't work without multiple threads.
931
* We said so up front!
932
* this ifdef is just here so that we don't die when loading
933
* the plugin so we can warn you...
936
Fix below courtesy of
937
Neil McKee <neil_mckee@inmon.com>
939
if(sample->headerProtocol == INMHEADER_ETHERNET_ISO8023)
940
queuePacket((u_char*)myGlobals.sflowDeviceId,
941
&hdr, sample->header); /* Pass the packet to ntop */
946
/*_________________---------------------------__________________
947
_________________ receiveError __________________
948
-----------------___________________________------------------
951
static void receiveError(SFSample *sample, char *errm, int hexdump, u_char *currentMark)
954
u_char scratch[6000];
957
u_long markOffset = 0;
958
if(currentMark != NULL) markOffset = currentMark - sample->rawSample;
962
printHex(sample->rawSample, sample->rawSampleLen, scratch, 6000, markOffset, 16);
966
traceEvent(CONST_TRACE_WARNING, "SFLOW: %s (source IP = %s) %s", msg, IP_to_a(sample->sourceIP.s_addr, ipbuf), hex);
969
/*_________________---------------------------__________________
970
_________________ readExtendedRouter __________________
971
-----------------___________________________------------------
974
static u_long *readExtendedRouter(SFSample *sample, u_long *datap, u_char *endPtr)
978
GETDATA32(addrType, datap);
979
if(addrType == INMADDRESSTYPE_IP_V4) GETDATA32_NOBSWAP(sample->nextHop.s_addr, datap);
981
printf("nextHop addrType = %d - currently only IPV4 nexthop supported\n", addrType);
982
datap += 4; /* skip over the IPV6 address */
983
sample->nextHop.s_addr = 0;
985
GETDATA32(sample->srcMask, datap);
986
GETDATA32(sample->dstMask, datap);
988
sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_ROUTER;
991
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: nextHop %s", IP_to_a(sample->nextHop.s_addr, buf));
992
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: srcSubnetMask %lu", sample->srcMask);
993
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dstSubnetMask %lu", sample->dstMask);
999
/*_________________---------------------------__________________
1000
_________________ readExtendedGateway __________________
1001
-----------------___________________________------------------
1004
static u_long *readExtendedGateway(SFSample *sample, u_long *datap, u_char *endPtr)
1006
GETDATA32(sample->my_as, datap); /* shake yo' ass */
1007
GETDATA32(sample->src_as, datap);
1008
GETDATA32(sample->src_peer_as, datap);
1009
GETDATA32(sample->dst_as_path_len, datap);
1010
/* just point at the dst_as_path array */
1011
if(sample->dst_as_path_len > 0) sample->dst_as_path = datap;
1012
/* and skip over it in the input */
1013
datap += sample->dst_as_path_len;
1014
if((u_char *)datap > (endPtr + 1)) {
1015
receiveError(sample, "datap >= (endp + 1)\n", TRUE, (u_char *)datap);
1019
sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_GATEWAY;
1022
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: my_as %lu", sample->my_as);
1023
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: src_as %lu", sample->src_as);
1024
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: src_peer_as %lu", sample->src_peer_as);
1025
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dst_as_path_len %lu", sample->dst_as_path_len);
1027
if(sample->dst_as_path_len > 0) {
1029
for(; i < sample->dst_as_path_len; i++) {
1030
if(i == 0) if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dst_as_path ");
1031
else if(debug) traceEvent(CONST_TRACE_INFO, "-");
1032
if(debug) traceEvent(CONST_TRACE_INFO, "%lu", ntohl(sample->dst_as_path[i]));
1034
if(debug) traceEvent(CONST_TRACE_INFO, "");
1039
/*_________________---------------------------__________________
1040
_________________ readExtendedUser __________________
1041
-----------------___________________________------------------
1044
static u_long *readExtendedUser(SFSample *sample, u_long *datap, u_char *endPtr)
1046
GETDATA32(sample->src_user_len, datap);
1047
if(sample->src_user_len) {
1048
if(sample->src_user_len > SA_MAX_EXTENDED_USER_LEN) {
1049
receiveError(sample, "extended_data: src_user_len > MAX\n", TRUE, (u_char *)datap);
1052
memcpy(datap, sample->src_user, sample->src_user_len);
1053
datap += (sample->src_user_len + 3 / 4); /* string is padded to quad boundary */
1055
sample->src_user[sample->src_user_len] = '\0';
1057
/* repeat for dest */
1058
GETDATA32(sample->dst_user_len, datap);
1059
if(sample->dst_user_len) {
1060
if(sample->dst_user_len > SA_MAX_EXTENDED_USER_LEN) {
1061
receiveError(sample, "extended_data: sample->dst_user_len > MAX\n",
1062
TRUE, (u_char *)datap);
1065
memcpy(datap, sample->dst_user, sample->dst_user_len);
1066
datap += (sample->dst_user_len + 3 / 4); /* string is padded to quad boundary */
1068
sample->dst_user[sample->dst_user_len] = '\0';
1070
sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_USER;
1073
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: src_user %s", sample->src_user);
1074
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dst_user %s", sample->dst_user);
1080
/* ************************* */
1082
static void receiveSflowSample(SFSample *sample)
1084
u_int numFlowSamples = 0;
1085
u_int32_t datagramVersion;
1086
u_int32_t addressType;
1087
struct in_addr agentIP;
1088
u_int32_t samplesInPacket;
1090
u_long *datap = (u_long *)sample->rawSample;
1092
now.tv_sec = time(NULL);
1096
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: startDatagram =================================");
1097
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: datagramSourceIP %s", IP_to_a(sample->sourceIP.s_addr, buf));
1098
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: datagramSize %lu", sample->rawSampleLen);
1099
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: unixSecondsUTC %lu", now.tv_sec);
1102
/* check the version */
1103
GETDATA32(datagramVersion, datap);
1104
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: datagramVersion %d", datagramVersion);
1105
if(datagramVersion != 2) {
1106
receiveError(sample, "unexpected datagram version number: %d\n", TRUE, (u_char *)datap);
1110
/* get the agent address */
1111
GETDATA32(addressType, datap);
1112
if(addressType != INMADDRESSTYPE_IP_V4) {
1113
receiveError(sample, "currently only support INMADDRESSTYPE_IP_V4 "
1114
"as the agent IP address type", TRUE, (u_char *)datap);
1117
GETDATA32_NOBSWAP(agentIP.s_addr, datap);
1119
GETDATA32(sample->sequenceNo, datap); /* this is the packet sequence number */
1120
GETDATA32(sample->sysUpTime, datap);
1121
GETDATA32(samplesInPacket, datap);
1125
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: agent %s", IP_to_a(agentIP.s_addr, buf));
1126
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: sysUpTime %lu", sample->sysUpTime);
1127
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: packetSequenceNo %lu", sample->sequenceNo);
1128
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: samplesInPacket %lu", samplesInPacket);
1131
{ /* now iterate and pull out the flows and counters samples */
1133
u_char *endPtr = (u_char *)sample->rawSample + sample->rawSampleLen;
1135
for(; samp < samplesInPacket; samp++) {
1136
u_char *startOfSample = (u_char *)datap;
1138
if((u_char *)datap >= endPtr) {
1139
receiveError(sample, "datap >= endp", TRUE, (u_char *)datap);
1143
GETDATA32(sample->sampleType, datap);
1144
GETDATA32(sample->samplesGenerated, datap);
1145
GETDATA32(sample->samplerId, datap);
1147
u_int32_t ds_class = sample->samplerId >> 24;
1148
u_int32_t ds_index = sample->samplerId & 0x00ffffff;
1149
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: sampleSequenceNo %lu", sample->samplesGenerated);
1150
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: sourceId %lu:%lu", ds_class, ds_index);
1153
switch(sample->sampleType) {
1156
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: sampleType FLOWSAMPLE");
1157
GETDATA32(sample->meanSkipCount, datap);
1158
GETDATA32(sample->samplePool, datap);
1159
GETDATA32(sample->dropEvents, datap);
1160
GETDATA32(sample->inputPort, datap);
1161
GETDATA32(sample->outputPort, datap);
1163
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: meanSkipCount %lu", sample->meanSkipCount);
1164
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: samplePool %lu", sample->samplePool);
1165
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dropEvents %lu", sample->dropEvents);
1166
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: inputPort %lu", sample->inputPort);
1167
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: outputPort %lu", sample->outputPort);
1170
GETDATA32(sample->packet_data_tag, datap);
1172
switch(sample->packet_data_tag) {
1174
case INMPACKETTYPE_HEADER:
1175
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: packetDataTag INMPACKETTYPE_HEADER");
1176
GETDATA32(sample->headerProtocol, datap);
1177
GETDATA32(sample->sampledPacketSize, datap);
1178
GETDATA32(sample->headerLen, datap);
1180
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: headerProtocol %lu", sample->headerProtocol);
1181
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: sampledPacketSize %lu", sample->sampledPacketSize);
1182
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: headerLen %lu", sample->headerLen);
1185
sample->header = (u_char *)datap; /* just point at the header */
1186
datap += ((sample->headerLen + 3) / 4); /* quad-alignment is required by XDR */
1187
if((u_char *)datap >= endPtr) {
1188
receiveError(sample, "datap >= endp (headerLen)", TRUE, (u_char *)datap);
1193
printHex(sample->header, sample->headerLen, scratch, 2000, 0, 2000);
1194
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: headerBytes %s", scratch);
1196
decodeLinkLayer(sample);
1197
if(sample->offsetToIPV4 > 0) {
1198
// report the size of the original IPPdu (including the IP header)
1199
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: IPSize %d", sample->sampledPacketSize - sample->offsetToIPV4);
1205
case INMPACKETTYPE_IPV4:
1206
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: packetDataTag INMPACKETTYPE_IPV4");
1207
sample->headerLen = sizeof(INMSampled_ipv4);
1208
sample->header = (u_char *)datap; /* just point at the header */
1209
datap += (sample->headerLen + 3) / 4; /* quad-alignment is required by XDR */
1212
INMSampled_ipv4 nfKey;
1213
memcpy(&nfKey, sample->header, sizeof(nfKey));
1214
sample->sampledPacketSize = ntohl(nfKey.length);
1216
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: sampledPacketSize %lu", sample->sampledPacketSize);
1217
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: IPSize %d", sample->sampledPacketSize);
1219
sample->dcd_srcIP = nfKey.src_ip;
1220
sample->dcd_dstIP = nfKey.dst_ip;
1221
sample->dcd_ipProtocol = ntohl(nfKey.protocol);
1222
sample->dcd_ipTos = ntohl(nfKey.tos);
1224
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: srcIP %s", IP_to_a(sample->dcd_srcIP.s_addr, buf));
1225
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dstIP %s", IP_to_a(sample->dcd_dstIP.s_addr, buf));
1226
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: IPProtocol %u", sample->dcd_ipProtocol);
1227
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: IPTOS %u", sample->dcd_ipTos);
1229
sample->dcd_sport = ntohl(nfKey.src_port);
1230
sample->dcd_dport = ntohl(nfKey.dst_port);
1231
switch(sample->dcd_ipProtocol) {
1233
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: ICMPType %u", sample->dcd_sport);
1234
/* not sure about the dest port being icmp code
1235
- might just be a repeat of the type */
1239
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: TCPSrcPort %u", sample->dcd_sport);
1240
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: TCPDstPort %u", sample->dcd_dport);
1242
sample->dcd_tcpFlags = ntohl(nfKey.tcp_flags);
1243
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: TCPFlags %u", sample->dcd_tcpFlags);
1247
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: UDPSrcPort %u", sample->dcd_sport);
1248
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: UDPDstPort %u", sample->dcd_dport);
1251
default: /* some other protcol */
1256
case INMPACKETTYPE_IPV6:
1257
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: packetDataTag INMPACKETTYPE_IPV6");
1259
sample->header = (u_char *)datap; /* just point at the header */
1260
datap += (sample->headerLen + 3) / 4; /* quad-alignment is required by XDR */
1262
INMSampled_ipv6 nfKey6;
1263
memcpy(&nfKey6, sample->header, sizeof(nfKey6));
1264
sample->sampledPacketSize = ntohl(nfKey6.length);
1265
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: sampledPacketSize %lu", sample->sampledPacketSize);
1267
/* bug: more decode to do here */
1271
receiveError(sample, "unexpected packet_data_tag", TRUE, (u_char *)datap);
1276
/* assume no extended data */
1277
sample->extended_data_tag = 0;
1280
GETDATA32(sample->num_extended, datap);
1281
for(x = 0; x < sample->num_extended; x++) {
1282
u_int32_t extended_tag;
1283
GETDATA32(extended_tag, datap);
1284
switch(extended_tag) {
1285
case INMEXTENDED_SWITCH:
1286
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: extendedType SWITCH");
1287
if((datap = readExtendedSwitch(sample, datap, endPtr)) == NULL) return;
1289
case INMEXTENDED_ROUTER:
1290
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: extendedType ROUTER");
1291
if((datap = readExtendedRouter(sample, datap, endPtr)) == NULL) return;
1293
case INMEXTENDED_GATEWAY:
1294
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: extendedType GATEWAY");
1295
if((datap = readExtendedGateway(sample, datap, endPtr)) == NULL) return;
1297
case INMEXTENDED_USER:
1298
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: extendedType USER");
1299
if((datap = readExtendedUser(sample, datap, endPtr)) == NULL) return;
1302
receiveError(sample, "unrecognized extended data tag", TRUE, (u_char *)datap);
1308
writePcapPacket(sample);
1312
case COUNTERSSAMPLE:
1314
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: sampleType COUNTERSSAMPLE");
1315
GETDATA32(sample->statsSamplingInterval, datap);
1316
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: statsSamplingInterval %lu", sample->statsSamplingInterval);
1317
/* now find out what sort of counter blocks we have here... */
1318
GETDATA32(sample->counterBlockVersion, datap);
1319
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: counterBlockVersion %lu", sample->counterBlockVersion);
1321
/* first see if we should read the generic stats */
1322
switch(sample->counterBlockVersion) {
1323
case INMCOUNTERSVERSION_GENERIC:
1324
case INMCOUNTERSVERSION_ETHERNET:
1325
case INMCOUNTERSVERSION_TOKENRING:
1326
case INMCOUNTERSVERSION_FDDI:
1327
case INMCOUNTERSVERSION_VG:
1328
case INMCOUNTERSVERSION_WAN:
1330
/* the first part of the generic counters block is really just
1331
more info about the interface. */
1332
GETDATA32(sample->ifIndex, datap);
1333
GETDATA32(sample->networkType, datap);
1334
GETDATA64(sample->ifSpeed, datap);
1335
GETDATA32(sample->ifDirection, datap);
1336
GETDATA32(sample->ifStatus, datap);
1338
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: ifIndex %lu", sample->ifIndex);
1339
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: networkType %lu", sample->networkType);
1340
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: ifSpeed %lu", sample->ifSpeed);
1341
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: ifDirection %lu", sample->ifDirection);
1342
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: ifStatus %lu", sample->ifStatus);
1345
/* the generic counters always come first */
1348
GETDATA64(cntr64, datap);
1349
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: ifInOctets %Lu", cntr64);
1350
GETDATA32(cntr64, datap);
1351
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: ifInUcastPkts %Lu", cntr64);
1352
GETDATA32(cntr64, datap);
1353
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: ifInMulticastPkts %Lu", cntr64);
1354
GETDATA32(cntr64, datap);
1355
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: ifInBroadcastPkts %Lu", cntr64);
1356
GETDATA32(cntr64, datap);
1357
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: ifInDiscards %Lu", cntr64);
1358
GETDATA32(cntr64, datap);
1359
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: ifInErrors %Lu", cntr64);
1360
GETDATA32(cntr64, datap);
1361
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: ifInUnknownProtos %Lu", cntr64);
1362
GETDATA64(cntr64, datap);
1363
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: ifOutOctets %Lu", cntr64);
1364
GETDATA32(cntr64, datap);
1365
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: ifOutUcastPkts %Lu", cntr64);
1366
GETDATA32(cntr64, datap);
1367
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: ifOutMulticastPkts %Lu", cntr64);
1368
GETDATA32(cntr64, datap);
1369
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: ifOutBroadcastPkts %Lu", cntr64);
1370
GETDATA32(cntr64, datap);
1371
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: ifOutDiscards %Lu", cntr64);
1372
GETDATA32(cntr64, datap);
1373
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: ifOutErrors %Lu", cntr64);
1374
GETDATA32(cntr64, datap);
1375
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: ifPromiscuousMode %Lu", cntr64);
1380
case INMCOUNTERSVERSION_VLAN:
1384
receiveError(sample, "unknown stats version", TRUE, (u_char *)datap);
1389
/* now see if there are any specific counter blocks to add */
1390
switch(sample->counterBlockVersion) {
1391
case INMCOUNTERSVERSION_GENERIC:
1394
case INMCOUNTERSVERSION_ETHERNET:
1397
GETDATA32(cntr32, datap);
1398
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot3StatsAlignmentErrors %lu", cntr32);
1399
GETDATA32(cntr32, datap);
1400
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot3StatsFCSErrors %lu", cntr32);
1401
GETDATA32(cntr32, datap);
1402
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot3StatsSingleCollisionFrames %lu", cntr32);
1403
GETDATA32(cntr32, datap);
1404
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot3StatsMultipleCollisionFrames %lu", cntr32);
1405
GETDATA32(cntr32, datap);
1406
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot3StatsSQETestErrors %lu", cntr32);
1407
GETDATA32(cntr32, datap);
1408
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot3StatsDeferredTransmissions %lu", cntr32);
1409
GETDATA32(cntr32, datap);
1410
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot3StatsLateCollisions %lu", cntr32);
1411
GETDATA32(cntr32, datap);
1412
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot3StatsExcessiveCollisions %lu", cntr32);
1413
GETDATA32(cntr32, datap);
1414
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot3StatsInternalMacTransmitErrors %lu", cntr32);
1415
GETDATA32(cntr32, datap);
1416
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot3StatsCarrierSenseErrors %lu", cntr32);
1417
GETDATA32(cntr32, datap);
1418
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot3StatsFrameTooLongs %lu", cntr32);
1419
GETDATA32(cntr32, datap);
1420
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot3StatsInternalMacReceiveErrors %lu", cntr32);
1421
GETDATA32(cntr32, datap);
1422
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot3StatsSymbolErrors %lu", cntr32);
1425
case INMCOUNTERSVERSION_TOKENRING:
1428
GETDATA32(cntr32, datap);
1429
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot5StatsLineErrors %lu", cntr32);
1430
GETDATA32(cntr32, datap);
1431
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot5StatsBurstErrors %lu", cntr32);
1432
GETDATA32(cntr32, datap);
1433
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot5StatsACErrors %lu", cntr32);
1434
GETDATA32(cntr32, datap);
1435
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot5StatsAbortTransErrors %lu", cntr32);
1436
GETDATA32(cntr32, datap);
1437
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot5StatsInternalErrors %lu", cntr32);
1438
GETDATA32(cntr32, datap);
1439
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot5StatsLostFrameErrors %lu", cntr32);
1440
GETDATA32(cntr32, datap);
1441
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot5StatsReceiveCongestions %lu", cntr32);
1442
GETDATA32(cntr32, datap);
1443
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot5StatsFrameCopiedErrors %lu", cntr32);
1444
GETDATA32(cntr32, datap);
1445
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot5StatsTokenErrors %lu", cntr32);
1446
GETDATA32(cntr32, datap);
1447
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot5StatsSoftErrors %lu", cntr32);
1448
GETDATA32(cntr32, datap);
1449
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot5StatsHardErrors %lu", cntr32);
1450
GETDATA32(cntr32, datap);
1451
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot5StatsSignalLoss %lu", cntr32);
1452
GETDATA32(cntr32, datap);
1453
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot5StatsTransmitBeacons %lu", cntr32);
1454
GETDATA32(cntr32, datap);
1455
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot5StatsRecoverys %lu", cntr32);
1456
GETDATA32(cntr32, datap);
1457
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot5StatsLobeWires %lu", cntr32);
1458
GETDATA32(cntr32, datap);
1459
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot5StatsRemoves %lu", cntr32);
1460
GETDATA32(cntr32, datap);
1461
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot5StatsSingles %lu", cntr32);
1462
GETDATA32(cntr32, datap);
1463
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot5StatsFreqErrors %lu", cntr32);
1466
case INMCOUNTERSVERSION_FDDI:
1467
/* nothing more (for the moment) $$$ */
1469
case INMCOUNTERSVERSION_VG:
1472
GETDATA32(cntr64, datap);
1473
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot12InHighPriorityFrames %Lu", cntr64);
1474
GETDATA64(cntr64, datap);
1475
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot12InHighPriorityOctets %Lu", cntr64);
1476
GETDATA32(cntr64, datap);
1477
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot12InNormPriorityFrames %Lu", cntr64);
1478
GETDATA64(cntr64, datap);
1479
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot12InNormPriorityOctets %Lu", cntr64);
1480
GETDATA32(cntr64, datap);
1481
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot12InIPMErrors %Lu", cntr64);
1482
GETDATA32(cntr64, datap);
1483
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot12InOversizeFrameErrors %Lu", cntr64);
1484
GETDATA32(cntr64, datap);
1485
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot12InDataErrors %Lu", cntr64);
1486
GETDATA32(cntr64, datap);
1487
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot12InNullAddressedFrames %Lu", cntr64);
1488
GETDATA32(cntr64, datap);
1489
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot12OutHighPriorityFrames %Lu", cntr64);
1490
GETDATA64(cntr64, datap);
1491
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot12OutHighPriorityOctets %Lu", cntr64);
1492
GETDATA32(cntr64, datap);
1493
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot12TransitionIntoTrainings %Lu", cntr64);
1494
GETDATA64(cntr64, datap);
1495
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot12HCInHighPriorityOctets %Lu", cntr64);
1496
GETDATA64(cntr64, datap);
1497
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot12HCInNormPriorityOctets %Lu", cntr64);
1498
GETDATA64(cntr64, datap);
1499
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: dot12HCOutHighPriorityOctets %Lu", cntr64);
1502
case INMCOUNTERSVERSION_WAN:
1503
/* nothing more for the moment $$$ */
1505
case INMCOUNTERSVERSION_VLAN:
1508
GETDATA32(sample->in_vlan, datap);
1509
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: in_vlan %lu", sample->in_vlan);
1510
GETDATA64(cntr64, datap);
1511
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: octets %Lu", cntr64);
1512
GETDATA32(cntr64, datap);
1513
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: ucastPkts %Lu", cntr64);
1514
GETDATA64(cntr64, datap);
1515
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: multicastPkts %Lu", cntr64);
1516
GETDATA32(cntr64, datap);
1517
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: broadcastPkts %Lu", cntr64);
1518
GETDATA32(cntr64, datap);
1519
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: discards %Lu", cntr64);
1533
report the size in bytes that this flowSample or
1534
counterSample took up in the datagram
1536
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: %s %d",
1537
(sample->sampleType == FLOWSAMPLE ?
1538
"flowSampleSize" : "countersSampleSize"),
1539
(u_char *)datap - startOfSample);
1544
/* ****************************** */
1546
static void freeSflowMatrixMemory(void) {
1548
NOTE: we need to lock something here (TBD)
1551
if((!myGlobals.device[myGlobals.sflowDeviceId].activeDevice) || (myGlobals.sflowDeviceId == -1)) return;
1553
if(myGlobals.device[myGlobals.sflowDeviceId].ipTrafficMatrix != NULL) {
1556
/* Courtesy of Wies-Software <wies@wiessoft.de> */
1557
for(j=0; j<(myGlobals.device[myGlobals.sflowDeviceId].numHosts*myGlobals.device[myGlobals.sflowDeviceId].numHosts); j++)
1558
if(myGlobals.device[myGlobals.sflowDeviceId].ipTrafficMatrix[j] != NULL)
1559
free(myGlobals.device[myGlobals.sflowDeviceId].ipTrafficMatrix[j]);
1561
free(myGlobals.device[myGlobals.sflowDeviceId].ipTrafficMatrix);
1564
if(myGlobals.device[myGlobals.sflowDeviceId].ipTrafficMatrixHosts != NULL)
1565
free(myGlobals.device[myGlobals.sflowDeviceId].ipTrafficMatrixHosts);
1568
/* ************************************************** */
1570
static void setSflowInterfaceMatrix() {
1571
if((!myGlobals.device[myGlobals.sflowDeviceId].activeDevice) || (myGlobals.sflowDeviceId == -1)) return;
1573
myGlobals.device[myGlobals.sflowDeviceId].numHosts = 0xFFFFFFFF - myGlobals.sflowIfMask.s_addr+1;
1574
myGlobals.device[myGlobals.sflowDeviceId].network.s_addr = myGlobals.sflowIfAddress.s_addr;
1575
myGlobals.device[myGlobals.sflowDeviceId].netmask.s_addr = myGlobals.sflowIfMask.s_addr;
1576
if(myGlobals.device[myGlobals.sflowDeviceId].numHosts > MAX_SUBNET_HOSTS) {
1577
myGlobals.device[myGlobals.sflowDeviceId].numHosts = MAX_SUBNET_HOSTS;
1578
traceEvent(CONST_TRACE_WARNING, "SFLOW: Truncated network size (device %s) to %d hosts (real netmask %s)",
1579
myGlobals.device[myGlobals.sflowDeviceId].name, myGlobals.device[myGlobals.sflowDeviceId].numHosts,
1580
intoa(myGlobals.device[myGlobals.sflowDeviceId].netmask));
1583
myGlobals.device[myGlobals.sflowDeviceId].ipTrafficMatrix = (TrafficEntry**)calloc(myGlobals.device[myGlobals.sflowDeviceId].numHosts*
1584
myGlobals.device[myGlobals.sflowDeviceId].numHosts,
1585
sizeof(TrafficEntry*));
1586
myGlobals.device[myGlobals.sflowDeviceId].ipTrafficMatrixHosts = (struct hostTraffic**)calloc(sizeof(struct hostTraffic*),
1587
myGlobals.device[myGlobals.sflowDeviceId].numHosts);
1590
/* ************************************** */
1592
static void setSflowInSocket() {
1593
struct sockaddr_in sockIn;
1596
if(myGlobals.sflowInSocket > 0) {
1597
traceEvent(CONST_TRACE_ALWAYSDISPLAY, "SFLOW: Collector terminated");
1598
closeNwSocket(&myGlobals.sflowInSocket);
1601
if(myGlobals.sflowInPort > 0) {
1602
myGlobals.sflowInSocket = socket(AF_INET, SOCK_DGRAM, 0);
1604
setsockopt(myGlobals.sflowInSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&sockopt, sizeof(sockopt));
1606
sockIn.sin_family = AF_INET;
1607
sockIn.sin_port = (int)htons(myGlobals.sflowInPort);
1608
sockIn.sin_addr.s_addr = INADDR_ANY;
1610
if(bind(myGlobals.sflowInSocket, (struct sockaddr *)&sockIn, sizeof(sockIn)) < 0) {
1611
traceEvent(CONST_TRACE_ERROR, "SFLOW: Collector, port %d already in use - import disabled",
1612
myGlobals.sflowInPort);
1613
closeNwSocket(&myGlobals.sflowInSocket);
1614
myGlobals.sflowInSocket = 0;
1618
traceEvent(CONST_TRACE_ALWAYSDISPLAY, "SFLOW: Collector listening on port %d",
1619
myGlobals.sflowInPort);
1622
if((myGlobals.sflowInPort > 0) && (myGlobals.sflowDeviceId == -1)) {
1623
myGlobals.sflowDeviceId = createDummyInterface(SFLOW_DEVICE_NAME);
1624
setSflowInterfaceMatrix();
1625
myGlobals.device[myGlobals.sflowDeviceId].activeDevice = 1;
1628
myGlobals.mergeInterfaces = 0; /* Use different devices */
1631
/* ****************************** */
1633
static void handlesFlowHTTPrequest(char* url) {
1634
char buf[1024], buf1[32], buf2[32], formatBuf[32];
1635
float percentage, err;
1636
struct in_addr theDest;
1639
sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1);
1640
printHTMLheader("sFlow Statistics", NULL, 0);
1642
sendString("<CENTER>\n<HR>\n");
1647
key = strtok(url, "=");
1648
if(key != NULL) value = strtok(NULL, "="); else value = NULL;
1651
if(strcmp(key, "port") == 0) {
1652
if(myGlobals.sflowInPort != atoi(value)) {
1653
myGlobals.sflowInPort = atoi(value);
1654
storePrefsValue("sflow.sflowInPort", value);
1655
initSflowInSocket();
1657
} else if(strcmp(key, "ifNetMask") == 0) {
1658
int a, b, c, d, a1, b1, c1, d1;
1660
if(sscanf(value, "%d.%d.%d.%d/%d.%d.%d.%d",
1661
&a, &b, &c, &d, &a1, &b1, &c1, &d1) == 8) {
1662
myGlobals.sflowIfAddress.s_addr = (a << 24) + (b << 16) + (c << 8) + d;
1663
myGlobals.sflowIfMask.s_addr = (a1 << 24) + (b1 << 16) + (c1 << 8) + d1;
1664
storePrefsValue("sflow.ifNetMask", value);
1665
freeSflowMatrixMemory(); setSflowInterfaceMatrix();
1667
traceEvent(CONST_TRACE_WARNING, "SFLOW: Parse Error (%s)", value);
1668
} else if(strcmp(key, "sflowDest") == 0) {
1669
myGlobals.sflowDest.sin_addr.s_addr = inet_addr(value);
1670
storePrefsValue("sflow.sflowDest", value);
1671
} else if(strcmp(key, "debug") == 0) {
1672
debug = atoi(value);
1673
storePrefsValue("sflow.debug", value);
1678
/* *************************************** */
1680
sendString("<table border=0 "TABLE_DEFAULTS">\n<tr><td><table border=1 "TABLE_DEFAULTS">");
1681
sendString("<TR><TH "DARK_BG" COLSPAN=4>sFlow Preferences</TH></TR>\n");
1682
sendString("<TR "TR_ON"><TH "TH_BG" "DARK_BG" ALIGN=LEFT>Incoming Flows</TH><TD "TD_BG"><FORM ACTION=/plugins/sFlow METHOD=GET>"
1683
"Local UDP Port</td> "
1684
"<td "TD_BG"><INPUT NAME=port SIZE=5 VALUE=");
1686
if(snprintf(buf, sizeof(buf), "%d", myGlobals.sflowInPort) < 0)
1690
sendString("><br>[default port is "DEFAULT_SFLOW_COLLECTOR_PORT_STR"]"
1691
"</td><td><INPUT TYPE=submit VALUE=Set></form></td></tr>\n<br>");
1693
if(myGlobals.sflowInPort > 0) {
1694
sendString("<TR "TR_ON"><TH "TH_BG" ALIGN=LEFT "DARK_BG">Virtual sFlow Interface</TH><TD "TD_BG"><FORM ACTION=/plugins/sFlow METHOD=GET>"
1695
"Local Network IP Address/Mask:</td><td "TD_BG"><INPUT NAME=ifNetMask SIZE=32 VALUE=\"");
1697
if(snprintf(buf, sizeof(buf), "%s/%s",
1698
_intoa(myGlobals.sflowIfAddress, buf1, sizeof(buf1)),
1699
_intoa(myGlobals.sflowIfMask, buf2, sizeof(buf2))) < 0)
1703
sendString("\"><br>Format: digit.digit.digit.digit/digit.digit.digit.digit</td><td><INPUT TYPE=submit VALUE=Set></form></td></tr>\n");
1706
/* *************************************** */
1708
sendString("<TR "TR_ON"><TH "TH_BG" "DARK_BG" ALIGN=LEFT>Outgoing Flows</TH><TD "TD_BG"><FORM ACTION=/plugins/sFlow METHOD=GET>"
1709
"Remote Collector IP Address</td> "
1710
"<td "TD_BG"><INPUT NAME=sflowDest SIZE=15 VALUE=");
1712
theDest.s_addr = ntohl(myGlobals.sflowDest.sin_addr.s_addr);
1713
sendString(_intoa(theDest, buf, sizeof(buf)));
1715
sendString(">:6343<br>[default sampling rate is "DEFAULT_SFLOW_SAMPLING_RATE" packets]</td>"
1716
"<td><INPUT TYPE=submit VALUE=Set></form></td></tr>\n");
1718
sendString("<TR "TR_ON"><TH "TH_BG" "DARK_BG" ALIGN=LEFT>Debug</TH><TD "TD_BG" align=left COLSPAN=2>"
1719
"<FORM ACTION=/plugins/sFlow METHOD=GET>");
1721
sendString("<INPUT TYPE=radio NAME=debug VALUE=1 CHECKED>On");
1722
sendString("<INPUT TYPE=radio NAME=debug VALUE=0>Off");
1723
sendString("<p>NOTE: sFlow packets are dumped on the ntop log");
1725
sendString("<INPUT TYPE=radio NAME=debug VALUE=1>On");
1726
sendString("<INPUT TYPE=radio NAME=debug VALUE=0 CHECKED>Off");
1729
sendString("</TD><td><INPUT TYPE=submit VALUE=Set></form></td></TR>\n");
1730
sendString("</table></tr>\n");
1732
sendString("<tr><td>"
1733
"<p><b>NOTE</b>:<ol>"
1734
"<li>Use 0 as port, and 0.0.0.0 as IP address to disable export/collection."
1735
"<li>sFlow packets are associated with a virtual device and not mixed to captured packets."
1736
"<li>sFlow activation may require ntop restart"
1737
"<li>A virtual sFlow device is activated only when incoming flow capture is enabled."
1738
"<li>You can switch devices using this <A HREF=/" CONST_SWITCH_NIC_HTML ">link</A>."
1739
"</ol></td></tr>\n");
1740
sendString("</table></center><p>\n");
1742
/* *************************************** */
1744
if((myGlobals.sflowInSocket == 0)
1745
|| (myGlobals.numSamplesReceived == 0)) {
1746
sendString("<p><H5>sFlow is a trademark of <A HREF=http://www.inmon.com/>InMon Corp.</A></H5>\n");
1747
sendString("<p align=right>[ Back to <a href=\"../" CONST_SHOW_PLUGINS_HTML "\">plugins</a> ] </p>\n");
1753
percentage = (myGlobals.lastSample-myGlobals.initialPool)/myGlobals.numSamplesReceived;
1754
err = 196 * sqrt((float)(1/(float)myGlobals.numSamplesReceived));
1756
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: [%.2f %%][Error <= %.2f%%]", percentage, err);
1758
sendString("<CENTER>\n<TABLE BORDER>\n");
1759
sendString("<TR "TR_ON" "DARK_BG"><TH "TH_BG" ALIGN=CENTER COLSPAN=2>Flow Statistics</TH></TR>\n");
1761
if(snprintf(buf, sizeof(buf),
1762
"<TR "TR_ON"><TH "TH_BG" ALIGN=LEFT "DARK_BG"># Samples</TH><TD "TD_BG" ALIGN=RIGHT>%s</TD></TR>\n",
1763
formatPkts((Counter)myGlobals.numSamplesReceived, formatBuf, sizeof(formatBuf))) < 0)
1767
if(snprintf(buf, sizeof(buf),
1768
"<TR "TR_ON"><TH "TH_BG" ALIGN=LEFT "DARK_BG">Data Scale</TH><TD "TD_BG" ALIGN=RIGHT>%.2f %%</TD></TR>\n",
1773
if(snprintf(buf, sizeof(buf),
1774
"<TR "TR_ON"><TH "TH_BG" ALIGN=LEFT "DARK_BG">Estimated Error</TH><TD "TD_BG" ALIGN=RIGHT>%.2f %%</TD></TR>\n",
1779
sendString("<TR "TR_ON"><TH "TH_BG" ALIGN=LEFT "DARK_BG">Flow Senders</TH><TD "TD_BG" ALIGN=LEFT>");
1781
for(i=0; i<MAX_NUM_PROBES; i++) {
1782
if(probeList[i].probeAddr.s_addr == 0) break;
1784
if(snprintf(buf, sizeof(buf), "%s [%s pkts]\n",
1785
_intoa(probeList[i].probeAddr, buf, sizeof(buf)),
1786
formatPkts(probeList[i].pkts, formatBuf, sizeof(formatBuf))) < 0)
1791
sendString("</TD></TR>\n</TABLE>\n</CENTER>\n");
1792
sendString("<p><H5>sFlow is a trademark of <A HREF=http://www.inmon.com/>InMon Corp.</A></H5>\n");
1793
sendString("<p align=right>[ Back to <a href=\"../" CONST_SHOW_PLUGINS_HTML "\">plugins</a> ] </p>\n");
1798
/* ****************************** */
1800
static void* sFlowMainLoop(void* notUsed _UNUSED_) {
1803
u_char buffer[2048];
1805
struct sockaddr_in fromHost;
1807
if(!(myGlobals.sflowInSocket > 0)) return(NULL);
1809
#ifdef CFG_MULTITHREADED
1814
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: sFlowMainLoop()");
1817
#ifdef CFG_MULTITHREADED
1818
traceEvent(CONST_TRACE_INFO, "THREADMGMT: sFlow thread (%ld) started...", sFlowThread);
1821
for(;myGlobals.capturePackets == FLAG_NTOPSTATE_RUN;) {
1822
FD_ZERO(&sFlowMask);
1823
FD_SET(myGlobals.sflowInSocket, &sFlowMask);
1825
if((rc = select(myGlobals.sflowInSocket+1, &sFlowMask, NULL, NULL, NULL)) > 0) {
1826
len = sizeof(fromHost);
1827
rc = recvfrom(myGlobals.sflowInSocket, (char*)&buffer, sizeof(buffer),
1828
0, (struct sockaddr*)&fromHost, &len);
1831
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: select() = %d", rc);
1834
memset(&sample, 0, sizeof(sample));
1835
sample.rawSample = buffer;
1836
sample.rawSampleLen = rc;
1837
sample.sourceIP = fromHost.sin_addr;
1839
receiveSflowSample(&sample);
1841
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: rawSampleLen: %d", sample.rawSampleLen);
1843
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: rawSampleLen: rc=%d", rc);
1846
traceEvent(CONST_TRACE_INFO, "SFLOW: select() failed (%d, %s), terminating",
1848
(errno == EBADF ? "EBADF" :
1849
errno == EINTR ? "EINTR" :
1850
errno == EINVAL ? "EINVAL" :
1851
errno == ENOMEM ? "ENOMEM" : "other"));
1856
#ifdef CFG_MULTITHREADED
1858
traceEvent(CONST_TRACE_INFO, "THREADMGMT: sFlow thread (%ld) terminated...", sFlowThread);
1863
/* ****************************** */
1865
static void initSflowInSocket(void) {
1866
struct sockaddr_in sockIn;
1869
if(myGlobals.sflowInSocket != 0) {
1870
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: sFlow collector terminated");
1871
closeNwSocket(&myGlobals.sflowInSocket);
1874
if(myGlobals.sflowInPort > 0) {
1875
myGlobals.sflowInSocket = socket(AF_INET, SOCK_DGRAM, 0);
1876
setsockopt(myGlobals.sflowInSocket, SOL_SOCKET, SO_REUSEADDR,
1877
(char *)&sockopt, sizeof(sockopt));
1879
sockIn.sin_family = AF_INET;
1880
sockIn.sin_port = (int)htons(myGlobals.sflowInPort);
1881
sockIn.sin_addr.s_addr = INADDR_ANY;
1883
if(bind(myGlobals.sflowInSocket, (struct sockaddr *)&sockIn, sizeof(sockIn)) < 0) {
1884
traceEvent(CONST_TRACE_ERROR, "SFLOW: Collector: port %d already in use - collector disabled",
1885
myGlobals.sflowInPort);
1886
closeNwSocket(&myGlobals.sflowInSocket);
1887
myGlobals.sflowInSocket = 0;
1891
traceEvent(CONST_TRACE_INFO, "SFLOW: Collector listening on port %d",
1892
myGlobals.sflowInPort);
1895
if((myGlobals.sflowInSocket > 0) && (myGlobals.sflowDeviceId == -1)) {
1896
myGlobals.sflowDeviceId = createDummyInterface(SFLOW_DEVICE_NAME);
1897
setSflowInterfaceMatrix();
1898
myGlobals.device[myGlobals.sflowDeviceId].activeDevice = 1;
1901
myGlobals.mergeInterfaces = 0; /* Use different devices */
1903
if(myGlobals.sflowOutSocket == 0) {
1906
myGlobals.sflowOutSocket = socket(AF_INET, SOCK_DGRAM, 0);
1907
setsockopt(myGlobals.sflowOutSocket, SOL_SOCKET, SO_REUSEADDR,
1908
(char *)&sockopt, sizeof(sockopt));
1910
myGlobals.sflowDest.sin_addr.s_addr = 0;
1911
myGlobals.sflowDest.sin_family = AF_INET;
1912
myGlobals.sflowDest.sin_port = (int)htons(DEFAULT_SFLOW_COLLECTOR_PORT);
1914
if(fetchPrefsValue("sflow.sflowDest", value, sizeof(value)) == -1)
1915
storePrefsValue("sflow.sflowDest", "");
1916
else if(value[0] != '\0')
1917
myGlobals.sflowDest.sin_addr.s_addr = inet_addr(value);
1919
myGlobals.numSamplesToGo = atoi(DEFAULT_SFLOW_SAMPLING_RATE);
1922
#ifdef CFG_MULTITHREADED
1923
if((!threadActive) && (myGlobals.sflowInSocket > 0))
1924
createThread(&sFlowThread, sFlowMainLoop, NULL);
1928
/* ****************************** */
1930
static void setSflowOutSocket() {
1931
struct sockaddr_in sockIn;
1934
if(myGlobals.sflowOutSocket != 0) {
1935
traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: sFlow collector terminated");
1936
closeNwSocket(&myGlobals.sflowOutSocket);
1939
if(myGlobals.sflowInPort != 0) {
1940
myGlobals.sflowOutSocket = socket(AF_INET, SOCK_DGRAM, 0);
1941
setsockopt(myGlobals.sflowOutSocket, SOL_SOCKET, SO_REUSEADDR,
1942
(char *)&sockopt, sizeof(sockopt));
1944
sockIn.sin_family = AF_INET;
1945
sockIn.sin_port = (int)htons(myGlobals.sflowInPort);
1946
sockIn.sin_addr.s_addr = INADDR_ANY;
1948
if(bind(myGlobals.sflowOutSocket, (struct sockaddr *)&sockIn, sizeof(sockIn)) < 0) {
1949
traceEvent(CONST_TRACE_WARNING, "SFLOW: Collector: port %d already in use",
1950
myGlobals.sflowInPort);
1951
closeNwSocket(&myGlobals.sflowOutSocket);
1952
myGlobals.sflowOutSocket = 0;
1956
traceEvent(CONST_TRACE_INFO, "SFLOW: Collector listening on port %d",
1957
myGlobals.sflowInPort);
1960
if((myGlobals.sflowOutSocket != 0) && (myGlobals.sflowDeviceId == 1)) {
1961
myGlobals.sflowDeviceId = createDummyInterface(SFLOW_DEVICE_NAME);
1962
setSflowInterfaceMatrix();
1963
myGlobals.device[myGlobals.sflowDeviceId].activeDevice = 1;
1966
myGlobals.mergeInterfaces = 0; /* Use different devices */
1969
/* ****************************** */
1971
typedef struct sflowSample {
1972
u_int32_t datagramVersion;
1973
u_int32_t addressType;
1974
u_int32_t agentAddress;
1975
u_int32_t sequenceNo;
1976
u_int32_t sysUpTime;
1977
u_int32_t samplesInPacket;
1978
u_int32_t sampleType;
1979
u_int32_t sampleSequenceNo;
1980
u_int32_t samplerId;
1981
u_int32_t meanSkipCount;
1982
u_int32_t samplePool;
1983
u_int32_t dropEvents;
1984
u_int32_t inputPort;
1985
u_int32_t outputPort;
1986
u_int32_t packet_data_tag;
1987
u_int32_t headerProtocol;
1988
u_int32_t sampledPacketSize;
1989
u_int32_t headerLen;
1990
u_char packetData[DEFAULT_SNAPLEN];
1991
u_int32_t extended_data_tag;
1994
/* **************************************** */
1996
static void handleSflowPacket(u_char *_deviceId,
1997
const struct pcap_pkthdr *h,
1999
SflowSample mySample;
2000
int sampledPacketSize;
2003
if(myGlobals.rFileName != NULL) {
2004
/* ntop is reading packets from a file */
2006
struct ether_header ehdr;
2007
u_int caplen = h->caplen;
2008
u_int length = h->len;
2009
unsigned short eth_type;
2014
if(caplen >= sizeof(struct ether_header)) {
2015
memcpy(&ehdr, p, sizeof(struct ether_header));
2016
eth_type = ntohs(ehdr.ether_type);
2018
if(eth_type == ETHERTYPE_IP) {
2020
u_short sport, dport;
2022
memcpy(&ip, p+sizeof(struct ether_header), sizeof(struct ip));
2023
hlen = (u_int)ip.ip_hl * 4;
2024
NTOHL(ip.ip_dst.s_addr); NTOHL(ip.ip_src.s_addr);
2026
plen = length-sizeof(struct ether_header);
2028
if(ip.ip_p == IPPROTO_UDP) {
2029
if(plen > (hlen+sizeof(struct udphdr))) {
2030
memcpy(&up, p+sizeof(struct ether_header)+hlen, sizeof(struct udphdr));
2031
sport = ntohs(up.uh_sport), dport = ntohs(up.uh_dport);
2033
if(dport == myGlobals.sflowInPort) {
2034
/* This is an sflow packet */
2037
memset(&sample, 0, sizeof(sample));
2038
sample.rawSample = (void*)(p+sizeof(struct ether_header)+hlen+sizeof(struct udphdr));
2039
sample.rawSampleLen = h->caplen-(sizeof(struct ether_header)+hlen+sizeof(struct udphdr));
2040
sample.sourceIP = ip.ip_src;
2042
receiveSflowSample(&sample);
2050
if(myGlobals.numSamplesToGo-- > 0) return;
2055
deviceId = *_deviceId;
2058
sampledPacketSize = h->caplen < DEFAULT_SNAPLEN ? h->caplen : DEFAULT_SNAPLEN;
2060
memset(&mySample, 0, sizeof(SflowSample));
2061
mySample.datagramVersion = htonl(INMDATAGRAM_VERSION2);
2062
mySample.addressType = htonl(INMADDRESSTYPE_IP_V4);
2063
mySample.agentAddress = htonl(myGlobals.device[deviceId].ifAddr.s_addr);
2064
mySample.sequenceNo = htonl(myGlobals.flowSampleSeqNo);
2065
mySample.sysUpTime = htonl(myGlobals.actTime);
2066
mySample.samplesInPacket = htonl(1);
2067
mySample.sampleType = htonl(FLOWSAMPLE);
2068
mySample.sampleSequenceNo = htonl(myGlobals.flowSampleSeqNo);
2069
mySample.samplerId = htonl(0); /*
2070
sFlowDataSource encoded as follows:
2071
The most significant byte of the
2072
source_id is used to indicate the
2073
type of sFlowDataSource
2074
(0 = ifIndex, 1 = smonVlanDataSource,
2075
2 = entPhysicalEntry) and the
2076
lower three bytes contain the
2077
relevant index value.
2079
mySample.meanSkipCount = htonl(atoi(DEFAULT_SFLOW_SAMPLING_RATE));
2080
mySample.samplePool = htonl(myGlobals.device[deviceId].ethernetPkts.value);
2081
mySample.dropEvents = htonl(0);
2082
mySample.inputPort = htonl(0);
2083
mySample.outputPort = htonl(0);
2084
mySample.packet_data_tag = htonl(INMPACKETTYPE_HEADER);
2085
mySample.headerProtocol = htonl(1);
2086
mySample.sampledPacketSize = htonl(sampledPacketSize);
2087
mySample.headerLen = htonl(sampledPacketSize);
2088
memcpy(mySample.packetData, p, sampledPacketSize);
2089
mySample.extended_data_tag = htonl(0); /* No extended data */
2091
myGlobals.flowSampleSeqNo++;
2094
if(myGlobals.sflowDest.sin_addr.s_addr != 0) {
2095
rc = sendto(myGlobals.sflowOutSocket, (const char*)&mySample, sizeof(mySample)+sampledPacketSize, 0,
2096
(struct sockaddr *)&myGlobals.sflowDest, sizeof(myGlobals.sflowDest));
2099
if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: sendto returned %d [errno=%d][sflowOutSocket=%d]",
2100
rc, errno, myGlobals.sflowOutSocket);
2103
if(myGlobals.sflowDest.sin_addr.s_addr != 0) {
2105
memset(&sample, 0, sizeof(sample));
2106
sample.rawSample = &mySample;
2107
sample.rawSampleLen = sizeof(mySample)+sampledPacketSize;
2108
sample.sourceIP.s_addr = 0;
2109
receiveSflowSample(&sample);
2113
myGlobals.numSamplesToGo = atoi(DEFAULT_SFLOW_SAMPLING_RATE); /* reset value */
2116
/* ****************************** */
2118
static int initsFlowFunct(void) {
2120
int a, b, c, d, a1, b1, c1, d1;
2122
setPluginStatus(NULL);
2124
#ifdef CFG_MULTITHREADED
2127
setPluginStatus("Disabled - requires POSIX thread support.");
2131
myGlobals.sflowInSocket = 0, debug = 0;
2132
myGlobals.numSamplesReceived = 0,
2133
myGlobals.initialPool = 0,
2134
myGlobals.lastSample = 0;
2136
memset(probeList, 0, sizeof(probeList));
2138
if((fetchPrefsValue("sflow.ifNetMask", value, sizeof(value)) == -1)
2139
|| (sscanf(value, "%d.%d.%d.%d/%d.%d.%d.%d", &a, &b, &c, &d, &a1, &b1, &c1, &d1) != 8)) {
2140
storePrefsValue("sflow.ifNetMask", "192.168.0.0/255.255.255.0");
2141
myGlobals.sflowIfAddress.s_addr = 0xC0A80000;
2142
myGlobals.sflowIfMask.s_addr = 0xFFFFFF00;
2144
myGlobals.sflowIfAddress.s_addr = (a << 24) + (b << 16) + (c << 8) + d;
2145
myGlobals.sflowIfMask.s_addr = (a1 << 24) + (b1 << 16) + (c1 << 8) + d1;
2148
if(fetchPrefsValue("sflow.sflowInPort", value, sizeof(value)) == -1)
2149
storePrefsValue("sflow.sflowInPort", "0");
2151
myGlobals.sflowInPort = atoi(value);
2153
if(fetchPrefsValue("sflow.sflowDest", value, sizeof(value)) == -1) {
2154
storePrefsValue("sflow.sflowDest", "0.0.0.0");
2155
myGlobals.sflowDest.sin_addr.s_addr = 0;
2157
myGlobals.sflowDest.sin_addr.s_addr = inet_addr(value);
2159
if(fetchPrefsValue("sflow.debug", value, sizeof(value)) == -1)
2160
storePrefsValue("sflow.debug", "0");
2162
debug = atoi(value);
2164
initSflowInSocket();
2166
/* http://www.inmon.com/ */
2168
if(myGlobals.sflowInPort > 0)
2169
traceEvent(CONST_TRACE_INFO, "SFLOW: Welcome to sFlow: listening on UDP port %d",
2170
myGlobals.sflowInPort);
2172
if(myGlobals.sflowDeviceId != -1)
2173
myGlobals.device[myGlobals.sflowDeviceId].activeDevice = 1;
2179
/* ****************************** */
2181
static void termsFlowFunct(void) {
2183
traceEvent(CONST_TRACE_INFO, "SFLOW: Thanks for using sFlow");
2185
#ifdef CFG_MULTITHREADED
2186
if(threadActive) killThread(&sFlowThread);
2189
if(myGlobals.sflowInSocket > 0) closeNwSocket(&myGlobals.sflowInSocket);
2190
if(myGlobals.sflowOutSocket > 0) closeNwSocket(&myGlobals.sflowOutSocket);
2192
if(myGlobals.sflowDeviceId != -1)
2193
myGlobals.device[myGlobals.sflowDeviceId].activeDevice = 0;
2195
traceEvent(CONST_TRACE_ALWAYSDISPLAY, "SFLOW: Done");
2199
/* ****************************** */
2201
static PluginInfo sFlowPluginInfo[] = {
2203
VERSION, /* current ntop version */
2205
"This plugin is used to setup, activate and deactivate ntop's sFlow support.<br>"
2206
"<b>ntop</b> can both collect and receive sFlow data. For more information about "
2207
"sFlow, search for RFC 3176, 'InMon Corporation's sFlow: A Method for Monitoring "
2208
"Traffic in Switched and Routed Networks'.<br>"
2209
"<i>Received flow data is reported as a separate 'NIC' in the regular <b>ntop</b> "
2210
"reports - <em>Remember to switch the reporting NIC via Admin | Switch NIC</em>.",
2211
"2.2", /* version */
2212
"<A HREF=\"http://luca.ntop.org/\" alt=\"Luca's home page\">L.Deri</A>",
2213
"sFlow", /* http://<host>:<port>/plugins/sFlowWatch */
2214
0, /* Active by default */
2215
1, /* Inactive setup */
2216
initsFlowFunct, /* InitFunc */
2217
termsFlowFunct, /* TermFunc */
2218
handleSflowPacket, /* PluginFunc */
2219
handlesFlowHTTPrequest,
2220
"ip", /* no capture */
2221
NULL /* no status */
2225
/* ***************************************** */
2227
/* Plugin entry fctn */
2228
#ifdef MAKE_STATIC_PLUGIN
2229
PluginInfo* sflowPluginEntryFctn(void)
2231
PluginInfo* PluginEntryFctn(void)
2234
traceEvent(CONST_TRACE_ALWAYSDISPLAY, "SFLOW: Welcome to %s. (C) 2002-04 by Luca Deri",
2235
sFlowPluginInfo->pluginName);
2237
return(sFlowPluginInfo);
2240
/* This must be here so it can access the struct PluginInfo, above */
2241
static void setPluginStatus(char * status)
2243
if (sFlowPluginInfo->pluginStatusMessage != NULL)
2244
free(sFlowPluginInfo->pluginStatusMessage);
2245
if (status == NULL) {
2246
sFlowPluginInfo->pluginStatusMessage = NULL;
2248
sFlowPluginInfo->pluginStatusMessage = strdup(status);