~ubuntu-branches/ubuntu/natty/ntop/natty

« back to all changes in this revision

Viewing changes to plugins/sflowPlugin.c

  • Committer: Bazaar Package Importer
  • Author(s): Ola Lundqvist
  • Date: 2005-01-30 21:59:13 UTC
  • mfrom: (2.1.1 warty)
  • Revision ID: james.westby@ubuntu.com-20050130215913-xc3ke963bw49b3k4
Tags: 2:3.0-5
* Updated README.Debian file so users will understand what to do at
  install, closes: #291794, #287802.
* Updated ntop init script to give better output.
* Also changed log directory from /var/lib/ntop to /var/log/ntop,
  closes: #252352.
* Quoted the interface list to allow whitespace, closes: #267248.
* Added a couple of logcheck ignores, closes: #269321, #269319.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Copyright (C) 2002-04 Luca Deri <deri@ntop.org>
 
3
 *
 
4
 *                     http://www.ntop.org/
 
5
 *
 
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.
 
10
 *
 
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.
 
15
 *
 
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.
 
19
 */
 
20
 
 
21
/* This plugin works only with threads */
 
22
 
 
23
/* ******************************************************************
 
24
 
 
25
  -----------------------------------------------------------------------
 
26
         Copyright (c) 2001 InMon Corp.  All rights reserved.
 
27
  -----------------------------------------------------------------------
 
28
 
 
29
  Redistribution and use in source and binary forms, with or without
 
30
  modification, are permitted provided that the following conditions
 
31
  are met:
 
32
 
 
33
  1. Redistributions of source code must retain the above copyright
 
34
     notice, this list of conditions and the following disclaimer.
 
35
 
 
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.
 
40
 
 
41
  3. Redistributions of any form whatsoever must retain the following
 
42
     acknowledgment:
 
43
      "This product includes sFlow(TM), freely available from
 
44
       http://www.inmon.com/".
 
45
 
 
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/".
 
50
 
 
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.
 
60
 
 
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.
 
66
 
 
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.
 
70
 
 
71
 
 
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.
 
84
 
 
85
  --------------------------------------------------------------------
 
86
 
 
87
  This software consists of voluntary contributions made by many
 
88
  individuals on behalf of InMon Corp.
 
89
 
 
90
  InMon Corp. can be contacted via Email at info@inmon.com.
 
91
 
 
92
  For more information on InMon Corp. and sFlow,
 
93
  please see http://www.inmon.com/.
 
94
 
 
95
  InMon Public License Version 1.0 written May 31, 2001
 
96
 
 
97
******************************************************************* */
 
98
 
 
99
#include "ntop.h"
 
100
#include "globals-report.h"
 
101
 
 
102
static int debug = 0;
 
103
static ProbeInfo probeList[MAX_NUM_PROBES];
 
104
 
 
105
#ifdef CFG_MULTITHREADED
 
106
pthread_t sFlowThread;
 
107
static int threadActive;
 
108
#endif
 
109
 
 
110
static void initSflowInSocket(void); /* forward */
 
111
static void setPluginStatus(char * status); /* forward */
 
112
 
 
113
/* ****************************** */
 
114
 
 
115
/* define my own IP header struct - to ease portability */
 
116
struct myiphdr
 
117
{
 
118
  u_int8_t version_and_headerLen;
 
119
  u_int8_t tos;
 
120
  u_int16_t tot_len;
 
121
  u_int16_t id;
 
122
  u_int16_t frag_off;
 
123
  u_int8_t ttl;
 
124
  u_int8_t protocol;
 
125
  u_int16_t check;
 
126
  u_int32_t saddr;
 
127
  u_int32_t daddr;
 
128
};
 
129
 
 
130
/* same for tcp */
 
131
struct mytcphdr
 
132
{
 
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;
 
138
  u_int8_t th_flags;
 
139
  u_int16_t th_win;             /* window */
 
140
  u_int16_t th_sum;             /* checksum */
 
141
  u_int16_t th_urp;             /* urgent pointer */
 
142
};
 
143
 
 
144
/* and UDP */
 
145
struct myudphdr {
 
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 */
 
150
};
 
151
 
 
152
/* and ICMP */
 
153
struct myicmphdr
 
154
{
 
155
  u_int8_t type;                /* message type */
 
156
  u_int8_t code;                /* type sub-code */
 
157
  /* ignore the rest */
 
158
};
 
159
 
 
160
 
 
161
#if (!defined(HAVE_IN6_ADDR)) && (!defined(WIN32))  && (!defined(DARWIN))
 
162
struct in6_addr
 
163
{
 
164
  union
 
165
  {
 
166
    u_int8_t u6_addr8[16];
 
167
    u_int16_t u6_addr16[8];
 
168
    u_int32_t u6_addr32[4];
 
169
  } in6_u;
 
170
};
 
171
#endif /* HAVE_IN6_ADDR */
 
172
 
 
173
enum INMAddress_type {
 
174
  INMADDRESSTYPE_IP_V4 = 1,
 
175
  INMADDRESSTYPE_IP_V6 = 2
 
176
};
 
177
 
 
178
typedef union _INMAddress_value {
 
179
  struct in_addr ip_v4;
 
180
  struct in6_addr ip_v6;
 
181
} INMAddress_value;
 
182
 
 
183
typedef struct _INMAddress {
 
184
  u_int32_t type;           /* enum INMAddress_type */
 
185
  INMAddress_value address;
 
186
} INMAddress;
 
187
 
 
188
/* Packet header data */
 
189
 
 
190
#define INM_MAX_HEADER_SIZE         256   /* The maximum sampled header size. */
 
191
 
 
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,
 
197
  INMHEADER_FDDI                 = 4,
 
198
  INMHEADER_FRAME_RELAY          = 5,
 
199
  INMHEADER_X25                  = 6,
 
200
  INMHEADER_PPP                  = 7,
 
201
  INMHEADER_SMDS                 = 8,
 
202
  INMHEADER_AAL5                 = 9,
 
203
  INMHEADER_AAL5_IP              = 10, /* e.g. Cisco AAL5 mux */
 
204
  INMHEADER_IPv4                 = 11,
 
205
  INMHEADER_IPv6                 = 12
 
206
};
 
207
 
 
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 */
 
213
} INMSampled_header;
 
214
 
 
215
/* Packet IP version 4 data */
 
216
 
 
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 */
 
227
} INMSampled_ipv4;
 
228
 
 
229
/* Packet IP version 6 data */
 
230
 
 
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 */
 
241
} INMSampled_ipv6;
 
242
 
 
243
 
 
244
/* Packet data */
 
245
 
 
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 */
 
250
};
 
251
 
 
252
typedef union _INMPacket_data_type {
 
253
  INMSampled_header header;
 
254
  INMSampled_ipv4 ipv4;
 
255
  INMSampled_ipv6 ipv6;
 
256
} INMPacket_data_type;
 
257
 
 
258
/* Extended data types */
 
259
 
 
260
/* Extended switch data */
 
261
 
 
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;
 
268
 
 
269
/* Extended router data */
 
270
 
 
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;
 
276
 
 
277
/* Extended gateway data */
 
278
 
 
279
typedef struct _INMExtended_gateway {
 
280
  u_int32_t as;              /* AS number for this gateway */
 
281
  u_int32_t src_as;
 
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;
 
286
 
 
287
/* Extended user data */
 
288
typedef struct _INMExtended_user {
 
289
  u_int32_t src_user_len;
 
290
  char *src_user;
 
291
  u_int32_t dst_user_len;
 
292
  char *dst_user;
 
293
} INMExtended_user;
 
294
 
 
295
/* Extended data */
 
296
 
 
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 */
 
302
};
 
303
 
 
304
/* Format of a single sample */
 
305
 
 
306
typedef struct _INMFlow_sample {
 
307
  u_int32_t sequence_number;      /* Incremented with each flow sample
 
308
                                     generated */
 
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
 
315
                                     lack of resources */
 
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.
 
325
                                     Examples:
 
326
                                     0x00000002  indicates ifIndex = 2
 
327
                                     0x00000000  ifIndex unknown.
 
328
                                     0x80000007  indicates a packet sent
 
329
                                     to 7 interfaces.
 
330
                                     0x80000000  indicates a packet sent to
 
331
                                     an unknown number of
 
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 */
 
335
 
 
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 */
 
340
  int gotSwitch;
 
341
  INMExtended_switch switchDevice;
 
342
  int gotRouter;
 
343
  INMExtended_router router;
 
344
  int gotGateway;
 
345
  INMExtended_gateway gateway;
 
346
  int gotUser;
 
347
  INMExtended_user user;
 
348
} INMFlow_sample;
 
349
 
 
350
/* Counter types */
 
351
 
 
352
/* Generic interface counters - see RFC 1573, 2233 */
 
353
 
 
354
typedef struct _INMIf_counters {
 
355
  u_int32_t ifIndex;
 
356
  u_int32_t ifType;
 
357
  u_int64_t ifSpeed;
 
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;
 
378
} INMIf_counters;
 
379
 
 
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;
 
396
 
 
397
typedef struct _INMEthernet_counters {
 
398
  INMIf_counters generic;
 
399
  INMEthernet_specific_counters ethernet;
 
400
} INMEthernet_counters;
 
401
 
 
402
/* FDDI interface counters - see RFC 1512 */
 
403
typedef struct _INMFddi_counters {
 
404
  INMIf_counters generic;
 
405
} INMFddi_counters;
 
406
 
 
407
/* Token ring counters - see RFC 1748 */
 
408
 
 
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;
 
429
 
 
430
typedef struct _INMTokenring_counters {
 
431
  INMIf_counters generic;
 
432
  INMTokenring_specific_counters tokenring;
 
433
} INMTokenring_counters;
 
434
 
 
435
/* 100 BaseVG interface counters - see RFC 2020 */
 
436
 
 
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;
 
453
 
 
454
typedef struct _INMVg_counters {
 
455
  INMIf_counters generic;
 
456
  INMVg_specific_counters vg;
 
457
} INMVg_counters;
 
458
 
 
459
/* WAN counters */
 
460
 
 
461
typedef struct _INMWan_counters {
 
462
  INMIf_counters generic;
 
463
} INMWan_counters;
 
464
 
 
465
typedef struct _INMVlan_counters {
 
466
  u_int32_t vlan_id;
 
467
  u_int64_t octets;
 
468
  u_int32_t ucastPkts;
 
469
  u_int32_t multicastPkts;
 
470
  u_int32_t broadcastPkts;
 
471
  u_int32_t discards;
 
472
} INMVlan_counters;
 
473
 
 
474
/* Counters data */
 
475
 
 
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
 
484
};
 
485
 
 
486
typedef union _INMCounters_type {
 
487
  INMIf_counters generic;
 
488
  INMEthernet_counters ethernet;
 
489
  INMTokenring_counters tokenring;
 
490
  INMFddi_counters fddi;
 
491
  INMVg_counters vg;
 
492
  INMWan_counters wan;
 
493
  INMVlan_counters vlan;
 
494
} INMCounters_type;
 
495
 
 
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;
 
502
 
 
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;
 
508
 
 
509
enum INMSample_types {
 
510
  FLOWSAMPLE  = 1,
 
511
  COUNTERSSAMPLE = 2
 
512
};
 
513
 
 
514
typedef union _INMSample_type {
 
515
  INMFlow_sample flowsample;
 
516
  INMCounters_sample counterssample;
 
517
} INMSample_type;
 
518
 
 
519
/* Format of a sample datagram */
 
520
 
 
521
enum INMDatagram_version {
 
522
  INMDATAGRAM_VERSION2 = 2,
 
523
};
 
524
 
 
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
 
529
                                      generated */
 
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;
 
535
 
 
536
typedef struct _SFSample {
 
537
  struct in_addr sourceIP;
 
538
  struct in_addr agent_addr;
 
539
 
 
540
  /* the raw pdu */
 
541
  u_char *rawSample;
 
542
  u_int rawSampleLen;
 
543
 
 
544
  u_int sampleType;
 
545
  u_int samplerId;
 
546
 
 
547
  /* interface info */
 
548
  u_long ifIndex;
 
549
  u_long networkType;
 
550
  u_int64_t ifSpeed;
 
551
  u_long ifDirection;
 
552
  u_long ifStatus;
 
553
 
 
554
  /* sample stream info */
 
555
  u_long sysUpTime;
 
556
  u_long sequenceNo;
 
557
  u_long sampledPacketSize;
 
558
  u_long samplesGenerated;
 
559
  u_long meanSkipCount;
 
560
  u_long samplePool;
 
561
  u_long dropEvents;
 
562
 
 
563
  /* the sampled header */
 
564
  u_long packet_data_tag;
 
565
  u_long headerProtocol;
 
566
  u_char *header;
 
567
  int headerLen;
 
568
 
 
569
  /* header decode */
 
570
  int offsetToIPV4;
 
571
  struct in_addr dcd_srcIP;
 
572
  struct in_addr dcd_dstIP;
 
573
  u_int dcd_ipProtocol;
 
574
  u_int dcd_ipTos;
 
575
  u_int dcd_ipTTL;
 
576
  u_int dcd_sport;
 
577
  u_int dcd_dport;
 
578
  u_int dcd_tcpFlags;
 
579
 
 
580
  /* ports */
 
581
  u_long inputPort;
 
582
  u_long outputPort;
 
583
 
 
584
  /* vlan */
 
585
  u_long in_vlan;
 
586
  u_long in_priority;
 
587
  u_long internalPriority;
 
588
  u_long out_vlan;
 
589
  u_long out_priority;
 
590
 
 
591
  /* extended data fields */
 
592
  u_long num_extended;
 
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
 
598
 
 
599
  /* IP forwarding info */
 
600
  struct in_addr nextHop;
 
601
  u_long srcMask;
 
602
  u_long dstMask;
 
603
  u_long my_as;
 
604
  u_long src_as;
 
605
  u_long src_peer_as;
 
606
  u_long dst_as_path_len;
 
607
  u_long *dst_as_path;
 
608
 
 
609
  /* user id */
 
610
#define SA_MAX_EXTENDED_USER_LEN 200
 
611
  u_int src_user_len;
 
612
  char src_user[SA_MAX_EXTENDED_USER_LEN+1];
 
613
  u_int dst_user_len;
 
614
  char dst_user[SA_MAX_EXTENDED_USER_LEN+1];
 
615
 
 
616
  /* counter blocks */
 
617
  u_long statsSamplingInterval;
 
618
  u_long counterBlockVersion;
 
619
} SFSample;
 
620
 
 
621
 
 
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; \
 
629
  } while(0)
 
630
 
 
631
 
 
632
static u_long *readExtendedSwitch(SFSample *sample, u_long *datap, u_char *endPtr)
 
633
{
 
634
  GETDATA32(sample->in_vlan, datap);
 
635
  GETDATA32(sample->in_priority, datap);
 
636
  GETDATA32(sample->out_vlan, datap);
 
637
  GETDATA32(sample->out_priority, datap);
 
638
 
 
639
  sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_SWITCH;
 
640
 
 
641
  if(debug) {
 
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);
 
646
  }
 
647
 
 
648
  return datap;
 
649
}
 
650
 
 
651
static char *IP_to_a(u_long ipaddr, char *buf)
 
652
{
 
653
  u_char *ip = (u_char *)&ipaddr;
 
654
  sprintf(buf, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
 
655
  return buf;
 
656
}
 
657
 
 
658
/*_________________---------------------------__________________
 
659
  _________________        printHex           __________________
 
660
  -----------------___________________________------------------
 
661
*/
 
662
 
 
663
static u_char bin2hex(int nib) { return (nib < 10) ? ('0' + nib) : ('A' - 10 + nib); }
 
664
 
 
665
static int printHex(const u_char *a, int len, u_char *buf,
 
666
             int bufLen, int marker, int bytesPerOutputLine)
 
667
{
 
668
  int b = 0, i = 0;
 
669
 
 
670
  for(; i < len; i++) {
 
671
    u_char byte;
 
672
    if(b > (bufLen - 10)) break;
 
673
    if(marker > 0 && i == marker) {
 
674
      buf[b++] = '<';
 
675
      buf[b++] = '*';
 
676
      buf[b++] = '>';
 
677
      buf[b++] = '-';
 
678
    }
 
679
    byte = a[i];
 
680
    buf[b++] = bin2hex(byte >> 4);
 
681
    buf[b++] = bin2hex(byte & 0x0f);
 
682
    if(i > 0 && (i % bytesPerOutputLine) == 0) buf[b++] = '\n';
 
683
    else {
 
684
      // separate the bytes with a dash
 
685
      if (i < (len - 1)) buf[b++] = '-';
 
686
    }
 
687
  }
 
688
  buf[b] = '\0';
 
689
  return b;
 
690
}
 
691
 
 
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.
 
697
*/
 
698
 
 
699
#define NFT_ETHHDR_SIZ 14
 
700
#define NFT_8022_SIZ 3
 
701
#define NFT_MAX_8023_LEN 1500
 
702
 
 
703
#define NFT_MIN_SIZ (NFT_ETHHDR_SIZ + sizeof(struct myiphdr))
 
704
 
 
705
static void decodeLinkLayer(SFSample *sample)
 
706
{
 
707
  u_char *start = (u_char *)sample->header;
 
708
  u_char *end = start + sample->headerLen;
 
709
  u_char *ptr = start;
 
710
  u_int16_t type_len;
 
711
 
 
712
  /* assume not found */
 
713
  sample->offsetToIPV4 = -1;
 
714
 
 
715
  if(sample->headerLen < NFT_ETHHDR_SIZ) return; /* not enough for an Ethernet header */
 
716
 
 
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]);
 
719
  ptr += 6;
 
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]);
 
722
  ptr += 6;
 
723
  type_len = (ptr[0] << 8) + ptr[1];
 
724
  ptr += 2;
 
725
 
 
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] */
 
735
    if(debug) {
 
736
              traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: decodedVLAN %lu", vlan);
 
737
              traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: decodedPriority %lu", priority);
 
738
    }
 
739
    /* now get the type_len again (next two bytes) */
 
740
    type_len = (ptr[0] << 8) + ptr[1];
 
741
  }
 
742
 
 
743
  /* now we're just looking for IP */
 
744
  if(sample->headerLen < NFT_MIN_SIZ) return; /* not enough for an IPv4 header */
 
745
 
 
746
  /* peek for IPX */
 
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];
 
752
    if(ipxChecksum &&
 
753
       ipxLen >= IPX_HDR_LEN &&
 
754
       ipxLen <= (IPX_HDR_LEN + IPX_MAX_DATA))
 
755
      /* we don't do anything with IPX here */
 
756
      return;
 
757
  }
 
758
 
 
759
  if(type_len <= NFT_MAX_8023_LEN) {
 
760
    /* assume 802.3+802.2 header */
 
761
    /* check for SNAP */
 
762
    if(ptr[0] == 0xAA &&
 
763
       ptr[1] == 0xAA &&
 
764
       ptr[2] == 0x03) {
 
765
      type_len = (ptr[3] << 8) + ptr[4];
 
766
      ptr += 5;
 
767
    }
 
768
    else {
 
769
      if (ptr[0] == 0x06 &&
 
770
          ptr[1] == 0x06 &&
 
771
          (ptr[2] & 0x01)) {
 
772
        /* IP over 8022 */
 
773
        ptr += 3;
 
774
        /* force the type_len to be IP so we can inline the IP decode below */
 
775
        type_len = 0x0800;
 
776
      }
 
777
      else return;
 
778
    }
 
779
  }
 
780
 
 
781
  /* assume type_len is an ethernet-type now */
 
782
 
 
783
  if(type_len == 0x0800) {
 
784
    /* IPV4 */
 
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);
 
794
  }
 
795
}
 
796
 
 
797
 
 
798
/*_________________---------------------------__________________
 
799
  _________________     decodeIPV4            __________________
 
800
  -----------------___________________________------------------
 
801
*/
 
802
 
 
803
static void decodeIPV4(SFSample *sample)
 
804
{
 
805
  if(sample->offsetToIPV4 > 0) {
 
806
    char buf[51];
 
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. */
 
812
    struct myiphdr ip;
 
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 */
 
821
    if(debug) {
 
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);
 
827
    }
 
828
    /* advance the pointer to the next protocol layer */
 
829
    ptr += sizeof(struct myiphdr);
 
830
 
 
831
    switch(ip.protocol) {
 
832
    case 1: /* ICMP */
 
833
      {
 
834
        struct myicmphdr icmp;
 
835
        memcpy(&icmp, ptr, sizeof(icmp));
 
836
        if(debug) {
 
837
                  traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: ICMPType %u", icmp.type);
 
838
                  traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: ICMPCode %u", icmp.code);
 
839
        }
 
840
      }
 
841
      break;
 
842
    case 6: /* TCP */
 
843
      {
 
844
        struct mytcphdr tcp;
 
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;
 
849
        if(debug) {
 
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);
 
853
        }
 
854
      }
 
855
      break;
 
856
    case 17: /* UDP */
 
857
      {
 
858
        struct myudphdr udp;
 
859
        memcpy(&udp, ptr, sizeof(udp));
 
860
        sample->dcd_sport = ntohs(udp.uh_sport);
 
861
        sample->dcd_dport = ntohs(udp.uh_dport);
 
862
        if(debug) {
 
863
                  traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: UDPSrcPort %u", sample->dcd_sport);
 
864
                  traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: UDPDstPort %u", sample->dcd_dport);
 
865
        }
 
866
      }
 
867
      break;
 
868
    default: /* some other protcol */
 
869
      break;
 
870
    }
 
871
  }
 
872
}
 
873
 
 
874
/*_________________---------------------------__________________
 
875
  _________________   writePcapHeader         __________________
 
876
  -----------------___________________________------------------
 
877
*/
 
878
 
 
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;
 
885
  hdr.thiszone = 0;
 
886
  hdr.snaplen = 128;
 
887
  hdr.sigfigs = 0;
 
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));
 
891
    exit(-1);
 
892
  }
 
893
  fflush(stdout);
 
894
}
 
895
 
 
896
/*_________________---------------------------__________________
 
897
  _________________   writePcapPacket         __________________
 
898
  -----------------___________________________------------------
 
899
*/
 
900
 
 
901
static void writePcapPacket(SFSample *sample) {
 
902
  struct pcap_pkthdr hdr;
 
903
  int i;
 
904
 
 
905
  hdr.ts.tv_sec  = time(NULL);
 
906
  hdr.ts.tv_usec = 0;
 
907
  hdr.caplen     = sample->headerLen;
 
908
  hdr.len        = sample->sampledPacketSize;
 
909
 
 
910
  if(myGlobals.sflowInSocket == 0)
 
911
    myGlobals.initialPool = sample->samplePool;
 
912
 
 
913
  myGlobals.numSamplesReceived++;
 
914
  myGlobals.lastSample = sample->samplePool;
 
915
 
 
916
  NTOHL(sample->sourceIP.s_addr);
 
917
 
 
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;
 
922
      break;
 
923
    } else if(probeList[i].probeAddr.s_addr == sample->sourceIP.s_addr) {
 
924
      probeList[i].pkts++;
 
925
      break;
 
926
    }
 
927
  }
 
928
 
 
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...
 
934
   */
 
935
  /*
 
936
    Fix below courtesy of
 
937
    Neil McKee <neil_mckee@inmon.com>
 
938
  */
 
939
  if(sample->headerProtocol == INMHEADER_ETHERNET_ISO8023)
 
940
    queuePacket((u_char*)myGlobals.sflowDeviceId,
 
941
                &hdr, sample->header); /* Pass the packet to ntop */
 
942
#endif
 
943
 
 
944
}
 
945
 
 
946
/*_________________---------------------------__________________
 
947
  _________________    receiveError           __________________
 
948
  -----------------___________________________------------------
 
949
*/
 
950
 
 
951
static void receiveError(SFSample *sample, char *errm, int hexdump, u_char *currentMark)
 
952
{
 
953
  char ipbuf[51];
 
954
  u_char scratch[6000];
 
955
  char *msg = "";
 
956
  char *hex = "";
 
957
  u_long markOffset = 0;
 
958
  if(currentMark != NULL) markOffset = currentMark - sample->rawSample;
 
959
  if(errm) msg = errm;
 
960
 
 
961
  if(hexdump) {
 
962
    printHex(sample->rawSample, sample->rawSampleLen, scratch, 6000, markOffset, 16);
 
963
    hex = scratch;
 
964
  }
 
965
 
 
966
  traceEvent(CONST_TRACE_WARNING, "SFLOW: %s (source IP = %s) %s", msg, IP_to_a(sample->sourceIP.s_addr, ipbuf), hex);
 
967
}
 
968
 
 
969
/*_________________---------------------------__________________
 
970
  _________________    readExtendedRouter     __________________
 
971
  -----------------___________________________------------------
 
972
*/
 
973
 
 
974
static u_long *readExtendedRouter(SFSample *sample, u_long *datap, u_char *endPtr)
 
975
{
 
976
  u_int32_t addrType;
 
977
  char buf[51];
 
978
  GETDATA32(addrType, datap);
 
979
  if(addrType == INMADDRESSTYPE_IP_V4) GETDATA32_NOBSWAP(sample->nextHop.s_addr, datap);
 
980
  else {
 
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;
 
984
  }
 
985
  GETDATA32(sample->srcMask, datap);
 
986
  GETDATA32(sample->dstMask, datap);
 
987
 
 
988
  sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_ROUTER;
 
989
 
 
990
  if(debug) {
 
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);
 
994
  }
 
995
 
 
996
  return datap;
 
997
}
 
998
 
 
999
/*_________________---------------------------__________________
 
1000
  _________________  readExtendedGateway      __________________
 
1001
  -----------------___________________________------------------
 
1002
*/
 
1003
 
 
1004
static u_long *readExtendedGateway(SFSample *sample, u_long *datap, u_char *endPtr)
 
1005
{
 
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);
 
1016
    return NULL;
 
1017
  }
 
1018
 
 
1019
  sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_GATEWAY;
 
1020
 
 
1021
  if(debug) {
 
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);
 
1026
  }
 
1027
  if(sample->dst_as_path_len > 0) {
 
1028
    u_int i = 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]));
 
1033
    }
 
1034
    if(debug) traceEvent(CONST_TRACE_INFO, "");
 
1035
  }
 
1036
  return datap;
 
1037
}
 
1038
 
 
1039
/*_________________---------------------------__________________
 
1040
  _________________    readExtendedUser       __________________
 
1041
  -----------------___________________________------------------
 
1042
*/
 
1043
 
 
1044
static u_long *readExtendedUser(SFSample *sample, u_long *datap, u_char *endPtr)
 
1045
{
 
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);
 
1050
      return NULL;
 
1051
    }
 
1052
    memcpy(datap, sample->src_user, sample->src_user_len);
 
1053
    datap += (sample->src_user_len + 3 / 4);  /* string is padded to quad boundary */
 
1054
  }
 
1055
  sample->src_user[sample->src_user_len] = '\0';
 
1056
 
 
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);
 
1063
      return NULL;
 
1064
    }
 
1065
    memcpy(datap, sample->dst_user, sample->dst_user_len);
 
1066
    datap += (sample->dst_user_len + 3 / 4);  /* string is padded to quad boundary */
 
1067
  }
 
1068
  sample->dst_user[sample->dst_user_len] = '\0';
 
1069
 
 
1070
  sample->extended_data_tag |= SASAMPLE_EXTENDED_DATA_USER;
 
1071
 
 
1072
  if(debug) {
 
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);
 
1075
  }
 
1076
 
 
1077
  return datap;
 
1078
}
 
1079
 
 
1080
/* ************************* */
 
1081
 
 
1082
static void receiveSflowSample(SFSample *sample)
 
1083
{
 
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;
 
1089
  struct timeval now;
 
1090
  u_long *datap = (u_long *)sample->rawSample;
 
1091
 
 
1092
  now.tv_sec = time(NULL);
 
1093
  now.tv_usec = 0;
 
1094
  if(debug) {
 
1095
    char buf[51];
 
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);
 
1100
  }
 
1101
 
 
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);
 
1107
    return;
 
1108
  }
 
1109
 
 
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);
 
1115
    return;
 
1116
  }
 
1117
  GETDATA32_NOBSWAP(agentIP.s_addr, datap);
 
1118
 
 
1119
  GETDATA32(sample->sequenceNo, datap);  /* this is the packet sequence number */
 
1120
  GETDATA32(sample->sysUpTime, datap);
 
1121
  GETDATA32(samplesInPacket, datap);
 
1122
 
 
1123
  if(debug) {
 
1124
    char buf[51];
 
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);
 
1129
  }
 
1130
 
 
1131
  { /* now iterate and pull out the flows and counters samples */
 
1132
    u_int32_t samp = 0;
 
1133
    u_char *endPtr = (u_char *)sample->rawSample + sample->rawSampleLen;
 
1134
 
 
1135
    for(; samp < samplesInPacket; samp++) {
 
1136
      u_char *startOfSample = (u_char *)datap;
 
1137
 
 
1138
      if((u_char *)datap >= endPtr) {
 
1139
        receiveError(sample, "datap >= endp", TRUE, (u_char *)datap);
 
1140
        return;
 
1141
      }
 
1142
 
 
1143
      GETDATA32(sample->sampleType, datap);
 
1144
      GETDATA32(sample->samplesGenerated, datap);
 
1145
      GETDATA32(sample->samplerId, datap);
 
1146
      if(debug) {
 
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);
 
1151
      }
 
1152
 
 
1153
      switch(sample->sampleType) {
 
1154
      case FLOWSAMPLE:
 
1155
        {
 
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);
 
1162
          if(debug) {
 
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);
 
1168
          }
 
1169
 
 
1170
          GETDATA32(sample->packet_data_tag, datap);
 
1171
 
 
1172
          switch(sample->packet_data_tag) {
 
1173
 
 
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);
 
1179
            if(debug) {
 
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);
 
1183
            }
 
1184
 
 
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);
 
1189
              return;
 
1190
            }
 
1191
            {
 
1192
              char scratch[2000];
 
1193
              printHex(sample->header, sample->headerLen, scratch, 2000, 0, 2000);
 
1194
              if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: headerBytes %s", scratch);
 
1195
            }
 
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);
 
1200
              decodeIPV4(sample);
 
1201
            }
 
1202
 
 
1203
            break;
 
1204
 
 
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 */
 
1210
            {
 
1211
              char buf[51];
 
1212
              INMSampled_ipv4 nfKey;
 
1213
              memcpy(&nfKey, sample->header, sizeof(nfKey));
 
1214
              sample->sampledPacketSize = ntohl(nfKey.length);
 
1215
              if(debug) {
 
1216
                        traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: sampledPacketSize %lu", sample->sampledPacketSize);
 
1217
                        traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: IPSize %d",  sample->sampledPacketSize);
 
1218
              }
 
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);
 
1223
              if(debug) {
 
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);
 
1228
              }
 
1229
              sample->dcd_sport = ntohl(nfKey.src_port);
 
1230
              sample->dcd_dport = ntohl(nfKey.dst_port);
 
1231
              switch(sample->dcd_ipProtocol) {
 
1232
              case 1: /* ICMP */
 
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 */
 
1236
                break;
 
1237
              case 6: /* TCP */
 
1238
                if(debug) {
 
1239
                          traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: TCPSrcPort %u", sample->dcd_sport);
 
1240
                          traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: TCPDstPort %u", sample->dcd_dport);
 
1241
                }
 
1242
                sample->dcd_tcpFlags = ntohl(nfKey.tcp_flags);
 
1243
                if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: TCPFlags %u", sample->dcd_tcpFlags);
 
1244
                break;
 
1245
              case 17: /* UDP */
 
1246
                if(debug) {
 
1247
                          traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: UDPSrcPort %u", sample->dcd_sport);
 
1248
                          traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: UDPDstPort %u", sample->dcd_dport);
 
1249
                }
 
1250
                break;
 
1251
              default: /* some other protcol */
 
1252
                break;
 
1253
              }
 
1254
            }
 
1255
            break;
 
1256
          case INMPACKETTYPE_IPV6:
 
1257
            if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: packetDataTag INMPACKETTYPE_IPV6");
 
1258
 
 
1259
            sample->header = (u_char *)datap; /* just point at the header */
 
1260
            datap += (sample->headerLen + 3) / 4; /* quad-alignment is required by XDR */
 
1261
            {
 
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);
 
1266
            }
 
1267
            /* bug: more decode to do here */
 
1268
            break;
 
1269
 
 
1270
          default:
 
1271
            receiveError(sample, "unexpected packet_data_tag", TRUE, (u_char *)datap);
 
1272
            return;
 
1273
            break;
 
1274
          }
 
1275
 
 
1276
          /* assume no extended data */
 
1277
          sample->extended_data_tag = 0;
 
1278
          {
 
1279
            u_int x;
 
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;
 
1288
                break;
 
1289
              case INMEXTENDED_ROUTER:
 
1290
                if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: extendedType ROUTER");
 
1291
                if((datap = readExtendedRouter(sample, datap, endPtr)) == NULL) return;
 
1292
                break;
 
1293
              case INMEXTENDED_GATEWAY:
 
1294
                if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: extendedType GATEWAY");
 
1295
                if((datap = readExtendedGateway(sample, datap, endPtr)) == NULL) return;
 
1296
                break;
 
1297
              case INMEXTENDED_USER:
 
1298
                if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: extendedType USER");
 
1299
                if((datap = readExtendedUser(sample, datap, endPtr)) == NULL) return;
 
1300
                break;
 
1301
              default:
 
1302
                receiveError(sample, "unrecognized extended data tag", TRUE, (u_char *)datap);
 
1303
                return;
 
1304
              }
 
1305
            }
 
1306
          }
 
1307
 
 
1308
          writePcapPacket(sample);
 
1309
        }
 
1310
        break;
 
1311
 
 
1312
      case COUNTERSSAMPLE:
 
1313
        {
 
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);
 
1320
 
 
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:
 
1329
            {
 
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);
 
1337
              if(debug) {
 
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);
 
1343
              }
 
1344
 
 
1345
              /* the generic counters always come first */
 
1346
              if(debug) {
 
1347
                u_int64_t cntr64;
 
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);
 
1376
              }
 
1377
            }
 
1378
            break;
 
1379
 
 
1380
          case INMCOUNTERSVERSION_VLAN:
 
1381
            break;
 
1382
 
 
1383
          default:
 
1384
            receiveError(sample, "unknown stats version", TRUE, (u_char *)datap);
 
1385
            return;
 
1386
            break;
 
1387
          }
 
1388
 
 
1389
          /* now see if there are any specific counter blocks to add */
 
1390
          switch(sample->counterBlockVersion) {
 
1391
          case INMCOUNTERSVERSION_GENERIC:
 
1392
            /* nothing more */
 
1393
            break;
 
1394
          case INMCOUNTERSVERSION_ETHERNET:
 
1395
            if(debug) {
 
1396
              u_int32_t cntr32;
 
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);
 
1423
            }
 
1424
            break;
 
1425
          case INMCOUNTERSVERSION_TOKENRING:
 
1426
                      {
 
1427
              u_int32_t cntr32;
 
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);
 
1464
            }
 
1465
            break;
 
1466
          case INMCOUNTERSVERSION_FDDI:
 
1467
            /* nothing more (for the moment) $$$ */
 
1468
            break;
 
1469
          case INMCOUNTERSVERSION_VG:
 
1470
            if(debug) {
 
1471
              u_int64_t cntr64;
 
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);
 
1500
            }
 
1501
            break;
 
1502
          case INMCOUNTERSVERSION_WAN:
 
1503
            /* nothing more for the moment $$$ */
 
1504
            break;
 
1505
          case INMCOUNTERSVERSION_VLAN:
 
1506
            if(debug) {
 
1507
              u_int64_t cntr64;
 
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);
 
1520
            }
 
1521
            break;
 
1522
          default:
 
1523
            return;
 
1524
            break;
 
1525
          }
 
1526
        }
 
1527
        break;
 
1528
      default:
 
1529
        return;
 
1530
        break;
 
1531
      }
 
1532
      /*
 
1533
        report the size in bytes that this flowSample or
 
1534
        counterSample took up in the datagram
 
1535
      */
 
1536
      if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: %s %d",
 
1537
                 (sample->sampleType == FLOWSAMPLE ?
 
1538
                  "flowSampleSize" : "countersSampleSize"),
 
1539
                 (u_char *)datap - startOfSample);
 
1540
    }
 
1541
  }
 
1542
}
 
1543
 
 
1544
/* ****************************** */
 
1545
 
 
1546
static void freeSflowMatrixMemory(void) {
 
1547
  /*
 
1548
    NOTE: we need to lock something here (TBD)
 
1549
  */
 
1550
 
 
1551
  if((!myGlobals.device[myGlobals.sflowDeviceId].activeDevice) || (myGlobals.sflowDeviceId == -1)) return;
 
1552
 
 
1553
  if(myGlobals.device[myGlobals.sflowDeviceId].ipTrafficMatrix != NULL) {
 
1554
    int j;
 
1555
 
 
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]);
 
1560
 
 
1561
    free(myGlobals.device[myGlobals.sflowDeviceId].ipTrafficMatrix);
 
1562
  }
 
1563
 
 
1564
  if(myGlobals.device[myGlobals.sflowDeviceId].ipTrafficMatrixHosts != NULL)
 
1565
    free(myGlobals.device[myGlobals.sflowDeviceId].ipTrafficMatrixHosts);
 
1566
}
 
1567
 
 
1568
/* ************************************************** */
 
1569
 
 
1570
static void setSflowInterfaceMatrix() {
 
1571
  if((!myGlobals.device[myGlobals.sflowDeviceId].activeDevice) || (myGlobals.sflowDeviceId == -1)) return;
 
1572
 
 
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));
 
1581
  }
 
1582
 
 
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);
 
1588
}
 
1589
 
 
1590
/* ************************************** */
 
1591
 
 
1592
static void setSflowInSocket() {
 
1593
  struct sockaddr_in sockIn;
 
1594
  int sockopt = 1;
 
1595
 
 
1596
  if(myGlobals.sflowInSocket > 0) {
 
1597
    traceEvent(CONST_TRACE_ALWAYSDISPLAY, "SFLOW: Collector terminated");
 
1598
    closeNwSocket(&myGlobals.sflowInSocket);
 
1599
  }
 
1600
 
 
1601
  if(myGlobals.sflowInPort > 0) {
 
1602
    myGlobals.sflowInSocket = socket(AF_INET, SOCK_DGRAM, 0);
 
1603
 
 
1604
    setsockopt(myGlobals.sflowInSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&sockopt, sizeof(sockopt));
 
1605
 
 
1606
    sockIn.sin_family            = AF_INET;
 
1607
    sockIn.sin_port              = (int)htons(myGlobals.sflowInPort);
 
1608
    sockIn.sin_addr.s_addr       = INADDR_ANY;
 
1609
 
 
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;
 
1615
      return;
 
1616
    }
 
1617
 
 
1618
    traceEvent(CONST_TRACE_ALWAYSDISPLAY, "SFLOW: Collector listening on port %d",
 
1619
               myGlobals.sflowInPort);
 
1620
  }
 
1621
 
 
1622
  if((myGlobals.sflowInPort > 0) && (myGlobals.sflowDeviceId == -1)) {
 
1623
    myGlobals.sflowDeviceId = createDummyInterface(SFLOW_DEVICE_NAME);
 
1624
    setSflowInterfaceMatrix();
 
1625
    myGlobals.device[myGlobals.sflowDeviceId].activeDevice = 1;
 
1626
  }
 
1627
 
 
1628
  myGlobals.mergeInterfaces = 0; /* Use different devices */
 
1629
}
 
1630
 
 
1631
/* ****************************** */
 
1632
 
 
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;
 
1637
  int i;
 
1638
 
 
1639
  sendHTTPHeader(FLAG_HTTP_TYPE_HTML, 0, 1);
 
1640
  printHTMLheader("sFlow Statistics", NULL, 0);
 
1641
 
 
1642
  sendString("<CENTER>\n<HR>\n");
 
1643
 
 
1644
  if(url != NULL) {
 
1645
    char *key, *value;
 
1646
 
 
1647
    key = strtok(url, "=");
 
1648
    if(key != NULL) value = strtok(NULL, "="); else value = NULL;
 
1649
 
 
1650
    if(value && key) {
 
1651
      if(strcmp(key, "port") == 0) {
 
1652
        if(myGlobals.sflowInPort != atoi(value)) {
 
1653
          myGlobals.sflowInPort = atoi(value);
 
1654
          storePrefsValue("sflow.sflowInPort", value);
 
1655
          initSflowInSocket();
 
1656
        }
 
1657
      } else if(strcmp(key, "ifNetMask") == 0) {
 
1658
        int a, b, c, d, a1, b1, c1, d1;
 
1659
 
 
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();
 
1666
        } else
 
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);
 
1674
      }
 
1675
    }
 
1676
  }
 
1677
 
 
1678
  /* *************************************** */
 
1679
 
 
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=");
 
1685
 
 
1686
  if(snprintf(buf, sizeof(buf), "%d", myGlobals.sflowInPort) < 0)
 
1687
    BufferTooShort();
 
1688
  sendString(buf);
 
1689
 
 
1690
  sendString("><br>[default port is "DEFAULT_SFLOW_COLLECTOR_PORT_STR"]"
 
1691
             "</td><td><INPUT TYPE=submit VALUE=Set></form></td></tr>\n<br>");
 
1692
 
 
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=\"");
 
1696
 
 
1697
    if(snprintf(buf, sizeof(buf), "%s/%s",
 
1698
                _intoa(myGlobals.sflowIfAddress, buf1, sizeof(buf1)),
 
1699
                _intoa(myGlobals.sflowIfMask, buf2, sizeof(buf2))) < 0)
 
1700
      BufferTooShort();
 
1701
    sendString(buf);
 
1702
 
 
1703
    sendString("\"><br>Format: digit.digit.digit.digit/digit.digit.digit.digit</td><td><INPUT TYPE=submit VALUE=Set></form></td></tr>\n");
 
1704
  }
 
1705
 
 
1706
  /* *************************************** */
 
1707
 
 
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=");
 
1711
 
 
1712
  theDest.s_addr = ntohl(myGlobals.sflowDest.sin_addr.s_addr);
 
1713
  sendString(_intoa(theDest, buf, sizeof(buf)));
 
1714
 
 
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");
 
1717
 
 
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>");
 
1720
  if(debug) {
 
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");
 
1724
  } else {
 
1725
    sendString("<INPUT TYPE=radio NAME=debug VALUE=1>On");
 
1726
    sendString("<INPUT TYPE=radio NAME=debug VALUE=0 CHECKED>Off");
 
1727
  }
 
1728
 
 
1729
  sendString("</TD><td><INPUT TYPE=submit VALUE=Set></form></td></TR>\n");
 
1730
  sendString("</table></tr>\n");
 
1731
 
 
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");
 
1741
 
 
1742
  /* *************************************** */
 
1743
 
 
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> ]&nbsp;</p>\n");
 
1748
    printHTMLtrailer();
 
1749
    return;
 
1750
  }
 
1751
 
 
1752
 
 
1753
  percentage = (myGlobals.lastSample-myGlobals.initialPool)/myGlobals.numSamplesReceived;
 
1754
  err = 196 * sqrt((float)(1/(float)myGlobals.numSamplesReceived));
 
1755
 
 
1756
  if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: [%.2f %%][Error <= %.2f%%]", percentage, err);
 
1757
 
 
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");
 
1760
 
 
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)
 
1764
    BufferTooShort();
 
1765
  sendString(buf);
 
1766
 
 
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",
 
1769
              percentage) < 0)
 
1770
    BufferTooShort();
 
1771
  sendString(buf);
 
1772
 
 
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",
 
1775
              err) < 0)
 
1776
    BufferTooShort();
 
1777
  sendString(buf);
 
1778
 
 
1779
  sendString("<TR "TR_ON"><TH "TH_BG" ALIGN=LEFT "DARK_BG">Flow Senders</TH><TD "TD_BG" ALIGN=LEFT>");
 
1780
 
 
1781
  for(i=0; i<MAX_NUM_PROBES; i++) {
 
1782
    if(probeList[i].probeAddr.s_addr == 0) break;
 
1783
 
 
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)
 
1787
      BufferTooShort();
 
1788
    sendString(buf);
 
1789
  }
 
1790
 
 
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> ]&nbsp;</p>\n");
 
1794
 
 
1795
  printHTMLtrailer();
 
1796
}
 
1797
 
 
1798
/* ****************************** */
 
1799
 
 
1800
static void* sFlowMainLoop(void* notUsed _UNUSED_) {
 
1801
  fd_set sFlowMask;
 
1802
  int rc, len;
 
1803
  u_char buffer[2048];
 
1804
  SFSample sample;
 
1805
  struct sockaddr_in fromHost;
 
1806
 
 
1807
  if(!(myGlobals.sflowInSocket > 0)) return(NULL);
 
1808
 
 
1809
#ifdef CFG_MULTITHREADED
 
1810
  threadActive = 1;
 
1811
#endif
 
1812
 
 
1813
#ifdef DEBUG
 
1814
  traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: sFlowMainLoop()");
 
1815
#endif
 
1816
 
 
1817
#ifdef CFG_MULTITHREADED
 
1818
  traceEvent(CONST_TRACE_INFO, "THREADMGMT: sFlow thread (%ld) started...", sFlowThread);
 
1819
#endif
 
1820
 
 
1821
  for(;myGlobals.capturePackets == FLAG_NTOPSTATE_RUN;) {
 
1822
    FD_ZERO(&sFlowMask);
 
1823
    FD_SET(myGlobals.sflowInSocket, &sFlowMask);
 
1824
 
 
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);
 
1829
 
 
1830
#ifdef DEBUG
 
1831
      traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: select() = %d", rc);
 
1832
#endif
 
1833
      if(rc > 0) {
 
1834
        memset(&sample, 0, sizeof(sample));
 
1835
        sample.rawSample    = buffer;
 
1836
        sample.rawSampleLen = rc;
 
1837
        sample.sourceIP     = fromHost.sin_addr;
 
1838
 
 
1839
        receiveSflowSample(&sample);
 
1840
 
 
1841
        if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: rawSampleLen: %d", sample.rawSampleLen);
 
1842
      } else {
 
1843
        if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: rawSampleLen: rc=%d", rc);
 
1844
      }
 
1845
    } else {
 
1846
      traceEvent(CONST_TRACE_INFO, "SFLOW: select() failed (%d, %s), terminating",
 
1847
                 errno,
 
1848
                 (errno == EBADF ? "EBADF" :
 
1849
                    errno == EINTR ? "EINTR" :
 
1850
                    errno == EINVAL ? "EINVAL" :
 
1851
                    errno == ENOMEM ? "ENOMEM" : "other"));
 
1852
      break;
 
1853
    }
 
1854
  }
 
1855
 
 
1856
#ifdef CFG_MULTITHREADED
 
1857
  threadActive = 0;
 
1858
  traceEvent(CONST_TRACE_INFO, "THREADMGMT: sFlow thread (%ld) terminated...", sFlowThread);
 
1859
#endif
 
1860
  return(0);
 
1861
}
 
1862
 
 
1863
/* ****************************** */
 
1864
 
 
1865
static void initSflowInSocket(void) {
 
1866
  struct sockaddr_in sockIn;
 
1867
  int sockopt = 1;
 
1868
 
 
1869
  if(myGlobals.sflowInSocket != 0) {
 
1870
    if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: sFlow collector terminated");
 
1871
    closeNwSocket(&myGlobals.sflowInSocket);
 
1872
  }
 
1873
 
 
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));
 
1878
 
 
1879
    sockIn.sin_family            = AF_INET;
 
1880
    sockIn.sin_port              = (int)htons(myGlobals.sflowInPort);
 
1881
    sockIn.sin_addr.s_addr       = INADDR_ANY;
 
1882
 
 
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;
 
1888
      return;
 
1889
    }
 
1890
 
 
1891
    traceEvent(CONST_TRACE_INFO, "SFLOW: Collector listening on port %d",
 
1892
               myGlobals.sflowInPort);
 
1893
  }
 
1894
 
 
1895
  if((myGlobals.sflowInSocket > 0) && (myGlobals.sflowDeviceId == -1)) {
 
1896
    myGlobals.sflowDeviceId = createDummyInterface(SFLOW_DEVICE_NAME);
 
1897
    setSflowInterfaceMatrix();
 
1898
    myGlobals.device[myGlobals.sflowDeviceId].activeDevice = 1;
 
1899
  }
 
1900
 
 
1901
  myGlobals.mergeInterfaces = 0; /* Use different devices */
 
1902
 
 
1903
  if(myGlobals.sflowOutSocket == 0) {
 
1904
    char value[32];
 
1905
 
 
1906
    myGlobals.sflowOutSocket = socket(AF_INET, SOCK_DGRAM, 0);
 
1907
    setsockopt(myGlobals.sflowOutSocket, SOL_SOCKET, SO_REUSEADDR,
 
1908
               (char *)&sockopt, sizeof(sockopt));
 
1909
 
 
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);
 
1913
 
 
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);
 
1918
 
 
1919
    myGlobals.numSamplesToGo = atoi(DEFAULT_SFLOW_SAMPLING_RATE);
 
1920
  }
 
1921
 
 
1922
#ifdef CFG_MULTITHREADED
 
1923
  if((!threadActive) && (myGlobals.sflowInSocket > 0))
 
1924
    createThread(&sFlowThread, sFlowMainLoop, NULL);
 
1925
#endif
 
1926
}
 
1927
 
 
1928
/* ****************************** */
 
1929
 
 
1930
static void setSflowOutSocket() {
 
1931
  struct sockaddr_in sockIn;
 
1932
  int sockopt = 1;
 
1933
 
 
1934
  if(myGlobals.sflowOutSocket != 0) {
 
1935
    traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: sFlow collector terminated");
 
1936
    closeNwSocket(&myGlobals.sflowOutSocket);
 
1937
  }
 
1938
 
 
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));
 
1943
 
 
1944
    sockIn.sin_family            = AF_INET;
 
1945
    sockIn.sin_port              = (int)htons(myGlobals.sflowInPort);
 
1946
    sockIn.sin_addr.s_addr       = INADDR_ANY;
 
1947
 
 
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;
 
1953
      return;
 
1954
    }
 
1955
 
 
1956
    traceEvent(CONST_TRACE_INFO, "SFLOW: Collector listening on port %d",
 
1957
               myGlobals.sflowInPort);
 
1958
  }
 
1959
 
 
1960
  if((myGlobals.sflowOutSocket != 0) && (myGlobals.sflowDeviceId == 1)) {
 
1961
    myGlobals.sflowDeviceId = createDummyInterface(SFLOW_DEVICE_NAME);
 
1962
    setSflowInterfaceMatrix();
 
1963
    myGlobals.device[myGlobals.sflowDeviceId].activeDevice = 1;
 
1964
  }
 
1965
 
 
1966
  myGlobals.mergeInterfaces = 0; /* Use different devices */
 
1967
}
 
1968
 
 
1969
/* ****************************** */
 
1970
 
 
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;
 
1992
} SflowSample;
 
1993
 
 
1994
/* **************************************** */
 
1995
 
 
1996
static void handleSflowPacket(u_char *_deviceId,
 
1997
                              const struct pcap_pkthdr *h,
 
1998
                              const u_char *p) {
 
1999
  SflowSample mySample;
 
2000
  int sampledPacketSize;
 
2001
  int deviceId, rc;
 
2002
 
 
2003
  if(myGlobals.rFileName != NULL) {
 
2004
    /* ntop is reading packets from a file */
 
2005
 
 
2006
    struct ether_header ehdr;
 
2007
    u_int caplen = h->caplen;
 
2008
    u_int length = h->len;
 
2009
    unsigned short eth_type;
 
2010
    u_int8_t flags = 0;
 
2011
    struct ip ip;
 
2012
    struct udphdr up;
 
2013
 
 
2014
    if(caplen >= sizeof(struct ether_header)) {
 
2015
      memcpy(&ehdr, p, sizeof(struct ether_header));
 
2016
      eth_type = ntohs(ehdr.ether_type);
 
2017
 
 
2018
      if(eth_type == ETHERTYPE_IP) {
 
2019
        u_int plen, hlen;
 
2020
        u_short sport, dport;
 
2021
 
 
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);
 
2025
 
 
2026
        plen = length-sizeof(struct ether_header);
 
2027
 
 
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);
 
2032
 
 
2033
            if(dport == myGlobals.sflowInPort) {
 
2034
              /* This is an sflow packet */
 
2035
              SFSample sample;
 
2036
 
 
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;
 
2041
 
 
2042
              receiveSflowSample(&sample);
 
2043
            }
 
2044
          }
 
2045
        }
 
2046
      }
 
2047
    }
 
2048
  }
 
2049
 
 
2050
  if(myGlobals.numSamplesToGo-- > 0) return;
 
2051
 
 
2052
#ifdef WIN32
 
2053
  deviceId = 0;
 
2054
#else
 
2055
  deviceId = *_deviceId;
 
2056
#endif
 
2057
 
 
2058
  sampledPacketSize = h->caplen < DEFAULT_SNAPLEN ? h->caplen : DEFAULT_SNAPLEN;
 
2059
 
 
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.
 
2078
                                         */
 
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 */
 
2090
 
 
2091
  myGlobals.flowSampleSeqNo++;
 
2092
 
 
2093
#if 1
 
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));
 
2097
 
 
2098
    if(rc == 0)
 
2099
      if(debug) traceEvent(CONST_TRACE_INFO, "SFLOW_DEBUG: sendto returned %d [errno=%d][sflowOutSocket=%d]",
 
2100
                 rc, errno, myGlobals.sflowOutSocket);
 
2101
  }
 
2102
#else
 
2103
  if(myGlobals.sflowDest.sin_addr.s_addr != 0) {
 
2104
    debug = 1;
 
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);
 
2110
  }
 
2111
#endif
 
2112
 
 
2113
  myGlobals.numSamplesToGo = atoi(DEFAULT_SFLOW_SAMPLING_RATE); /* reset value */
 
2114
}
 
2115
 
 
2116
/* ****************************** */
 
2117
 
 
2118
static int initsFlowFunct(void) {
 
2119
  char value[32];
 
2120
  int a, b, c, d, a1, b1, c1, d1;
 
2121
 
 
2122
  setPluginStatus(NULL);
 
2123
 
 
2124
#ifdef CFG_MULTITHREADED
 
2125
  threadActive = 0;
 
2126
#else
 
2127
  setPluginStatus("Disabled - requires POSIX thread support.");
 
2128
  return(-1);
 
2129
#endif
 
2130
 
 
2131
  myGlobals.sflowInSocket = 0, debug = 0;
 
2132
  myGlobals.numSamplesReceived = 0,
 
2133
    myGlobals.initialPool = 0,
 
2134
    myGlobals.lastSample = 0;
 
2135
 
 
2136
  memset(probeList, 0, sizeof(probeList));
 
2137
 
 
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;
 
2143
  } else {
 
2144
    myGlobals.sflowIfAddress.s_addr = (a << 24) + (b << 16) + (c << 8) + d;
 
2145
    myGlobals.sflowIfMask.s_addr    = (a1 << 24) + (b1 << 16) + (c1 << 8) + d1;
 
2146
  }
 
2147
 
 
2148
  if(fetchPrefsValue("sflow.sflowInPort", value, sizeof(value)) == -1)
 
2149
    storePrefsValue("sflow.sflowInPort", "0");
 
2150
  else
 
2151
    myGlobals.sflowInPort = atoi(value);
 
2152
 
 
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;
 
2156
  } else
 
2157
    myGlobals.sflowDest.sin_addr.s_addr = inet_addr(value);
 
2158
 
 
2159
  if(fetchPrefsValue("sflow.debug", value, sizeof(value)) == -1)
 
2160
    storePrefsValue("sflow.debug", "0");
 
2161
  else
 
2162
    debug = atoi(value);
 
2163
 
 
2164
  initSflowInSocket();
 
2165
 
 
2166
  /* http://www.inmon.com/ */
 
2167
 
 
2168
    if(myGlobals.sflowInPort > 0)
 
2169
      traceEvent(CONST_TRACE_INFO, "SFLOW: Welcome to sFlow: listening on UDP port %d",
 
2170
                 myGlobals.sflowInPort);
 
2171
 
 
2172
  if(myGlobals.sflowDeviceId != -1)
 
2173
    myGlobals.device[myGlobals.sflowDeviceId].activeDevice = 1;
 
2174
 
 
2175
  fflush(stdout);
 
2176
  return(0);
 
2177
}
 
2178
 
 
2179
/* ****************************** */
 
2180
 
 
2181
static void termsFlowFunct(void) {
 
2182
 
 
2183
  traceEvent(CONST_TRACE_INFO, "SFLOW: Thanks for using sFlow");
 
2184
 
 
2185
#ifdef CFG_MULTITHREADED
 
2186
  if(threadActive) killThread(&sFlowThread);
 
2187
#endif
 
2188
 
 
2189
  if(myGlobals.sflowInSocket > 0)  closeNwSocket(&myGlobals.sflowInSocket);
 
2190
  if(myGlobals.sflowOutSocket > 0) closeNwSocket(&myGlobals.sflowOutSocket);
 
2191
 
 
2192
  if(myGlobals.sflowDeviceId != -1)
 
2193
    myGlobals.device[myGlobals.sflowDeviceId].activeDevice = 0;
 
2194
 
 
2195
  traceEvent(CONST_TRACE_ALWAYSDISPLAY, "SFLOW: Done");
 
2196
  fflush(stdout);
 
2197
}
 
2198
 
 
2199
/* ****************************** */
 
2200
 
 
2201
static PluginInfo sFlowPluginInfo[] = {
 
2202
  { 
 
2203
    VERSION, /* current ntop version */
 
2204
    "sFlowPlugin",
 
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 */
 
2222
  }
 
2223
};
 
2224
 
 
2225
/* ***************************************** */
 
2226
 
 
2227
/* Plugin entry fctn */
 
2228
#ifdef MAKE_STATIC_PLUGIN
 
2229
PluginInfo* sflowPluginEntryFctn(void)
 
2230
#else
 
2231
     PluginInfo* PluginEntryFctn(void)
 
2232
#endif
 
2233
{
 
2234
  traceEvent(CONST_TRACE_ALWAYSDISPLAY, "SFLOW: Welcome to %s. (C) 2002-04 by Luca Deri",
 
2235
             sFlowPluginInfo->pluginName);
 
2236
 
 
2237
  return(sFlowPluginInfo);
 
2238
}
 
2239
 
 
2240
/* This must be here so it can access the struct PluginInfo, above */
 
2241
static void setPluginStatus(char * status)
 
2242
   {
 
2243
       if (sFlowPluginInfo->pluginStatusMessage != NULL)
 
2244
           free(sFlowPluginInfo->pluginStatusMessage);
 
2245
       if (status == NULL) {
 
2246
           sFlowPluginInfo->pluginStatusMessage = NULL;
 
2247
       } else {
 
2248
           sFlowPluginInfo->pluginStatusMessage = strdup(status);
 
2249
       }
 
2250
   }