source: tools/traceends/traceends.cc @ 264f286c

cachetimestampsdevelopdpdk-ndagetsilivendag_formatrc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformance
Last change on this file since 264f286c was 8e11beb, checked in by Shane Alcock <salcock@…>, 4 years ago

Update tools to properly ignore meta records and missing timestamps

pcapng introduces a lot of meta records that we should preserve as
long as possible. Since we aren't automatically discarding them,
we need to make sure that our tools do not try to treat them as
"real" packets, i.e. try to get a timestamp or capture length from
them.

Similarly, simple pcapng packet records do not have a timestamp
so we need to make sure the tools do the right thing when
trace_get_seconds() returns a timestamp of zero on a packet. For
starters, we don't want to set our "first" packet time to zero
in that case!

  • Property mode set to 100644
File size: 11.2 KB
Line 
1/*
2 *
3 * Copyright (c) 2007-2016 The University of Waikato, Hamilton, New Zealand.
4 * All rights reserved.
5 *
6 * This file is part of libtrace.
7 *
8 * This code has been developed by the University of Waikato WAND
9 * research group. For further information please see http://www.wand.net.nz/
10 *
11 * libtrace is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * libtrace is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 *
24 *
25 */
26
27
28#define __STDC_FORMAT_MACROS
29
30#include <libtrace.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <inttypes.h>
34#include <lt_inttypes.h>
35#include <getopt.h>
36#include <string.h>
37#include <assert.h>
38#include <signal.h>
39#include <time.h>
40#include <sys/socket.h>
41#include <netinet/in.h>
42#include <arpa/inet.h>
43#include <time.h>
44
45#include <map>
46
47typedef struct end_counter {
48        uint64_t src_bytes;
49        uint64_t src_pbytes;
50        uint64_t src_pkts;
51        uint64_t dst_pkts;
52        uint64_t dst_bytes;
53        uint64_t dst_pbytes;
54
55        double last_active;
56
57} end_counter_t;
58
59typedef struct mac_addr {
60        uint8_t addr[6];
61} mac_addr_t;
62
63struct v6comp {
64        bool operator() (const struct in6_addr &a, const struct in6_addr &b) const {
65                if (memcmp(&a, &b, sizeof(struct in6_addr)) < 0)
66                        return true;
67                return false;
68        }
69};
70       
71struct maccomp {
72        bool operator() (const mac_addr_t &a, const mac_addr_t &b) const {
73                if (memcmp(&a, &b, sizeof(mac_addr_t)) < 0)
74                        return true;
75                return false;
76        }
77};
78
79typedef std::map<uint32_t, end_counter_t *> IP4EndMap;
80typedef std::map<struct in6_addr, end_counter_t *, v6comp> IP6EndMap;
81typedef std::map<mac_addr_t, end_counter_t *, maccomp> MacEndMap;
82
83enum {
84        MODE_MAC,
85        MODE_IPV4,
86        MODE_IPV6
87};
88
89int mode = MODE_IPV4;
90
91IP4EndMap ipv4;
92IP6EndMap ipv6;
93MacEndMap mac;
94
95static int usage(char *argv0)
96{
97        printf("Usage:\n"
98        "%s flags inputuri [inputuri ... ] \n"
99        "-f --filter=bpf        Only output packets that match filter\n"
100        "-H --help              Print this message\n"
101        "-A --address=addr      Specifies which address type to match (mac, v4, v6)\n"
102        ,argv0);
103        exit(1);
104}
105
106volatile int done=0;
107
108static void cleanup_signal(int sig)
109{
110        (void)sig;
111        done=1;
112        trace_interrupt();
113}
114
115static end_counter_t *create_counter() {
116        end_counter_t *c = (end_counter_t *)malloc(sizeof(end_counter_t));
117
118        c->src_bytes = 0;
119        c->src_pbytes = 0;
120        c->src_pkts = 0;
121        c->dst_pkts = 0;
122        c->dst_bytes = 0;
123        c->dst_pbytes = 0;
124
125        c->last_active = 0.0;
126        return c;
127}
128
129static char *mac_string(mac_addr_t m, char *str) {
130       
131       
132        snprintf(str, 80, "%02x:%02x:%02x:%02x:%02x:%02x", 
133                m.addr[0], m.addr[1], m.addr[2], m.addr[3], m.addr[4],
134                m.addr[5]);
135        return str;
136}
137
138static void dump_mac_map() {
139        MacEndMap::iterator it;
140        char str[80];
141        char timestr[80];
142        struct tm *tm;
143        time_t t;
144       
145        for (it = mac.begin(); it != mac.end(); it++) {
146                t = (time_t)(it->second->last_active);
147                tm = localtime(&t);
148                strftime(timestr, 80, "%d/%m,%H:%M:%S", tm);
149                printf("%18s %16s %16" PRIu64 " %16" PRIu64 " %16" PRIu64 " %16" PRIu64 " %16" PRIu64 " %16" PRIu64 "\n", 
150                                mac_string(it->first, str),
151                                timestr,
152                                it->second->src_pkts,
153                                it->second->src_bytes,
154                                it->second->src_pbytes,
155                                it->second->dst_pkts,
156                                it->second->dst_bytes,
157                                it->second->dst_pbytes);
158        }
159}
160
161static void dump_ipv4_map() {
162        IP4EndMap::iterator it;
163        struct in_addr in;
164        char timestr[80];
165        struct tm *tm;
166        time_t t;
167        for (it = ipv4.begin(); it != ipv4.end(); it++) {
168                in.s_addr = it->first;
169                t = (time_t)(it->second->last_active);
170                tm = localtime(&t);
171                strftime(timestr, 80, "%d/%m,%H:%M:%S", tm);
172                printf("%16s %16s %16" PRIu64 " %16" PRIu64 " %16" PRIu64 " %16" PRIu64 " %16" PRIu64 " %16" PRIu64 "\n", 
173                                inet_ntoa(in),
174                                timestr,
175                                it->second->src_pkts,
176                                it->second->src_bytes,
177                                it->second->src_pbytes,
178                                it->second->dst_pkts,
179                                it->second->dst_bytes,
180                                it->second->dst_pbytes);
181        }
182}
183
184static void dump_ipv6_map() {
185        IP6EndMap::iterator it;
186        struct in6_addr in;
187        char ip6_addr[128];
188        char timestr[80];
189        struct tm *tm;
190        time_t t;
191
192        for (it = ipv6.begin(); it != ipv6.end(); it++) {
193                in = it->first;
194                t = (time_t)(it->second->last_active);
195                tm = localtime(&t);
196                strftime(timestr, 80, "%d/%m,%H:%M:%S", tm);
197                printf("%40s %16s %16" PRIu64 " %16" PRIu64 " %16" PRIu64 " %16" PRIu64 " %16" PRIu64 " %16" PRIu64 "\n", 
198                                inet_ntop(AF_INET6, &in, ip6_addr, 128),
199                                timestr,
200                                it->second->src_pkts,
201                                it->second->src_bytes,
202                                it->second->src_pbytes,
203                                it->second->dst_pkts,
204                                it->second->dst_bytes,
205                                it->second->dst_pbytes);
206        }
207}
208
209static void update_ipv6(libtrace_ip6_t *ip, uint16_t ip_len, uint32_t rem, 
210                uint32_t plen,  double ts) {
211
212        struct in6_addr key;
213        IP6EndMap::iterator it;
214        end_counter_t *c = NULL;
215
216        if (rem < sizeof(libtrace_ip6_t))
217                return;
218       
219        key = ip->ip_src;
220       
221        it = ipv6.find(key);
222        if (it == ipv6.end()) {
223                c = create_counter();
224                ipv6[key] = c;
225        } else {
226                c = it->second;
227        }
228
229        c->src_pkts ++;
230        c->src_pbytes += plen;
231        c->src_bytes += ip_len;
232        c->last_active = ts;
233       
234        key = ip->ip_dst;
235       
236        it = ipv6.find(key);
237        if (it == ipv6.end()) {
238                c = create_counter();
239                ipv6[key] = c;
240        } else {
241                c = it->second;
242        }
243
244        c->dst_pkts ++;
245        c->dst_pbytes += plen;
246        c->dst_bytes += ip_len;
247        c->last_active = ts;
248}
249
250static void update_mac(uint8_t *src, uint8_t *dst, uint16_t ip_len,
251                uint32_t plen, double ts) {
252
253        mac_addr_t key;
254        end_counter_t *c = NULL;
255        MacEndMap::iterator it;
256
257        memcpy(&(key.addr), src, sizeof(key.addr));
258        it = mac.find(key);
259       
260        if (it == mac.end()) {
261                c = create_counter();
262                mac[key] = c;
263        } else {
264                c = it->second;
265        }
266
267        c->src_pkts ++;
268        c->src_pbytes += plen;
269        c->src_bytes += ip_len;
270        c->last_active = ts;
271
272        memcpy(&key.addr, dst, sizeof(key.addr));
273        it = mac.find(key);
274       
275        if (it == mac.end()) {
276                c = create_counter();
277                mac[key] = c;
278        } else {
279                c = it->second;
280        }
281
282        c->dst_pkts ++;
283        c->dst_pbytes += plen;
284        c->dst_bytes += ip_len;
285        c->last_active = ts;
286}
287
288static void update_ipv4(libtrace_ip_t *ip, uint16_t ip_len, uint32_t rem, 
289                uint32_t plen,  double ts) {
290
291        uint32_t key;
292        IP4EndMap::iterator it;
293        end_counter_t *c = NULL;
294
295        if (rem < sizeof(libtrace_ip_t))
296                return;
297       
298        key = ip->ip_src.s_addr;
299       
300        it = ipv4.find(key);
301        if (it == ipv4.end()) {
302                c = create_counter();
303                ipv4[key] = c;
304        } else {
305                c = it->second;
306        }
307
308        c->src_pkts ++;
309        c->src_pbytes += plen;
310        c->src_bytes += ip->ip_len;
311        if (ts != 0)
312                c->last_active = ts;
313       
314        key = ip->ip_dst.s_addr;
315       
316        it = ipv4.find(key);
317        if (it == ipv4.end()) {
318                c = create_counter();
319                ipv4[key] = c;
320        } else {
321                c = it->second;
322        }
323
324        c->dst_pkts ++;
325        c->dst_pbytes += plen;
326        c->dst_bytes += ip_len;
327        if (ts != 0)
328                c->last_active = ts;
329}
330
331static int per_packet(libtrace_packet_t *packet) {
332
333        void *header;
334        uint16_t ethertype;
335        uint32_t rem;
336        uint16_t ip_len = 0;
337        uint32_t plen = trace_get_payload_length(packet);
338        double ts = trace_get_seconds(packet);
339        libtrace_ip_t *ip = NULL;
340        libtrace_ip6_t *ip6 = NULL;
341        uint8_t *src_mac, *dst_mac;
342
343        header = trace_get_layer3(packet, &ethertype, &rem);
344
345        if (header == NULL || rem == 0)
346                return 1;
347       
348        if (ethertype == TRACE_ETHERTYPE_IP) {
349                ip = (libtrace_ip_t *)header;
350                if (rem < sizeof(libtrace_ip_t))
351                        return 1;
352                ip_len = ntohs(ip->ip_len);
353                if (mode == MODE_IPV4 && ip) {
354                        update_ipv4(ip, ip_len, rem, plen, ts);
355                        return 1;
356                }
357        }
358
359        if (ethertype == TRACE_ETHERTYPE_IPV6) {
360                ip6 = (libtrace_ip6_t *)header;
361                if (rem < sizeof(libtrace_ip6_t))
362                        return 1;
363                ip_len = ntohs(ip6->plen) + sizeof(libtrace_ip6_t);
364                if (mode == MODE_IPV6 && ip6) {
365                        update_ipv6(ip6, ip_len, rem, plen, ts);
366                        return 1;
367                }
368        }
369
370        if (mode == MODE_MAC) {
371                src_mac = trace_get_source_mac(packet);
372                dst_mac = trace_get_destination_mac(packet);
373
374                if (src_mac == NULL || dst_mac == NULL)
375                        return 1;
376                update_mac(src_mac, dst_mac, ip_len, plen, ts);
377        }
378
379        return 1;
380}
381
382int main(int argc, char *argv[]) {
383
384        int i;
385        struct sigaction sigact;
386        struct libtrace_filter_t *filter=NULL;
387        struct libtrace_t *input = NULL;
388        struct libtrace_packet_t *packet = trace_create_packet();
389
390        while(1) {
391                int option_index;
392                struct option long_options[] = {
393                        { "filter",        1, 0, 'f' },
394                        { "help",          0, 0, 'H' },
395                        { "addresses",     1, 0, 'A' }, 
396                        { NULL,            0, 0, 0   },
397                };
398
399                int c=getopt_long(argc, argv, "A:f:H",
400                                long_options, &option_index);
401
402                if (c==-1)
403                        break;
404                switch (c) {
405                        case 'A':
406                                if (strncmp(optarg, "mac", 3) == 0)
407                                        mode = MODE_MAC;
408                                else if (strncmp(optarg, "v4", 2) == 0)
409                                        mode = MODE_IPV4;
410                                else if (strncmp(optarg, "v6", 2) == 0)
411                                        mode = MODE_IPV6;
412                                else {
413                                        fprintf(stderr, "Invalid address type, must be either mac, v4 or v6\n");
414                                        return 1;
415                                }
416                                break;
417
418                        case 'f': filter=trace_create_filter(optarg);
419                                break;
420                        case 'H':
421                                usage(argv[0]);
422                                break;
423                        default:
424                                fprintf(stderr,"Unknown option: %c\n",c);
425                                usage(argv[0]);
426                                return 1;
427                }
428
429        }
430        sigact.sa_handler = cleanup_signal;
431        sigemptyset(&sigact.sa_mask);
432        sigact.sa_flags = SA_RESTART;
433
434        sigaction(SIGINT, &sigact, NULL);
435        sigaction(SIGTERM, &sigact, NULL);
436        sigaction(SIGPIPE, &sigact, NULL);
437        sigaction(SIGHUP, &sigact, NULL);
438
439        for (i = optind; i < argc; i++) {
440                input = trace_create(argv[i]);
441
442                if (trace_is_err(input)) {
443                        trace_perror(input,"%s",argv[i]);
444                        return 1;
445                }
446
447                if (filter && trace_config(input, TRACE_OPTION_FILTER, filter) == 1) {
448                        trace_perror(input, "Configuring filter for %s",
449                                        argv[i]);
450                        return 1;
451                }
452
453                if (trace_start(input)==-1) {
454                        trace_perror(input,"%s",argv[i]);
455                        return 1;
456                }
457
458                while (trace_read_packet(input,packet)>0) {
459                        if (IS_LIBTRACE_META_PACKET(packet))
460                                continue;
461                        if (per_packet(packet) < 1)
462                                done = 1;
463                        if (done)
464                                break;
465                }
466
467                if (done)
468                        break;
469
470                if (trace_is_err(input)) {
471                        trace_perror(input,"Reading packets");
472                        trace_destroy(input);
473                        break;
474                }
475
476                trace_destroy(input);
477        }
478
479        /* Dump results */
480        if (mode == MODE_IPV4)
481                dump_ipv4_map();
482        if (mode == MODE_IPV6)
483                dump_ipv6_map();
484        if (mode == MODE_MAC)
485                dump_mac_map();
486        return 0;
487}
Note: See TracBrowser for help on using the repository browser.