source: tools/tracesplit/tracesplit.c @ 8e11beb

cachetimestampsdevelopdpdk-ndagetsilivendag_formatrc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformance
Last change on this file since 8e11beb was 8e11beb, checked in by Shane Alcock <salcock@…>, 3 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: 14.1 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#include <libtrace.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <inttypes.h>
32#include <lt_inttypes.h>
33#include <stdbool.h>
34#include <getopt.h>
35#include <string.h>
36#include <assert.h>
37#include <signal.h>
38#include <time.h>
39
40/* Global variables */
41struct libtrace_out_t *output = NULL;
42uint64_t count=UINT64_MAX;
43uint64_t bytes=UINT64_MAX;
44uint64_t starttime=0;
45uint64_t endtime=UINT64_MAX;
46uint64_t interval=UINT64_MAX;
47double firsttime=0;
48uint64_t pktcount=0;
49uint64_t totbytes=0;
50uint64_t totbyteslast=0;
51uint64_t maxfiles = UINT64_MAX;
52uint64_t filescreated = 0;
53uint16_t snaplen = 0;
54int jump=0;
55int verbose=0;
56int compress_level=-1;
57trace_option_compresstype_t compress_type = TRACE_OPTION_COMPRESSTYPE_NONE;
58char *output_base = NULL;
59
60
61static char *strdupcat(char *str,char *app)
62{
63        str=realloc(str,strlen(str)+strlen(app)+1);
64        strncat(str,app,strlen(str) + strlen(app));
65        return str;
66}
67
68static char *strdupcati(char *str,uint64_t i)
69{
70        char buffer[64];
71        snprintf(buffer,sizeof(buffer),"%" PRIu64,i);
72        return strdupcat(str,buffer);
73}
74
75static int usage(char *argv0)
76{
77        printf("Usage:\n"
78        "%s flags inputuri [inputuri ... ] outputuri\n"
79        "-f --filter=bpf        only output packets that match filter\n"
80        "-c --count=n           split every n packets\n"
81        "-b --bytes=n           Split every n bytes received\n"
82        "-i --interval=n        Split every n seconds\n"
83        "-s --starttime=time    Start at time\n"
84        "-e --endtime=time      End at time\n"
85        "-m --maxfiles=n        Create a maximum of n trace files\n"
86        "-j --jump=n            Jump to the nth IP header\n"
87        "-H --libtrace-help     Print libtrace runtime documentation\n"
88        "-S --snaplen           Snap packets at the specified length\n"
89        "-v --verbose           Output statistics\n"
90        "-z --compress-level    Set compression level\n"
91        "-Z --compress-type     Set compression type\n"
92        ,argv0);
93        exit(1);
94}
95
96volatile int done=0;
97
98static void cleanup_signal(int sig)
99{
100        (void)sig;
101        done=1;
102        trace_interrupt();
103}
104
105
106static libtrace_packet_t *perform_jump(libtrace_packet_t *packet, int jump)
107{
108    uint16_t ethertype;
109    uint32_t remaining;
110    uint8_t ipproto;
111    void *offset = trace_get_layer3(packet, &ethertype, &remaining);
112    while(jump > 0 && offset) {
113        --jump;
114        switch (ethertype) {
115            case TRACE_ETHERTYPE_IP:
116                if (jump <= 0) {
117                    void *newpacket = trace_create_packet();
118                    trace_construct_packet(newpacket,
119                            TRACE_TYPE_NONE,
120                            offset,
121                            remaining);
122                    return newpacket;
123                }
124                offset = trace_get_payload_from_ip(offset,
125                        &ipproto,
126                        &remaining);
127                if (!offset)
128                    return NULL;
129                break;
130            case TRACE_ETHERTYPE_IPV6:
131                if (jump <= 0) {
132                    void *newpacket = trace_create_packet();
133                    trace_construct_packet(newpacket,
134                            TRACE_TYPE_NONE,
135                            offset,
136                            remaining);
137                    return newpacket;
138                }
139                offset = trace_get_payload_from_ip6(offset,
140                        &ipproto,
141                        &remaining);
142                if (!offset)
143                    return NULL;
144                break;
145            /* TODO: vlan, etc */
146            default:
147                return NULL;
148        }
149        if (!offset)
150            return false;
151        switch (ipproto) {
152            case TRACE_IPPROTO_IPV6:
153                ethertype = TRACE_ETHERTYPE_IPV6;
154                continue;
155            case TRACE_IPPROTO_IPIP:
156                ethertype = TRACE_ETHERTYPE_IP;
157                continue;
158            case TRACE_IPPROTO_GRE:
159                if (remaining < sizeof(libtrace_gre_t)) {
160                    return NULL;
161                }
162                ethertype = ((libtrace_gre_t *)offset)->ethertype;
163                offset = trace_get_payload_from_gre(offset, &remaining);
164                continue;
165            case TRACE_IPPROTO_UDP:
166                offset = trace_get_vxlan_from_udp(offset, &remaining);
167                if (!offset)
168                    return NULL;
169                offset = trace_get_payload_from_vxlan(offset, &remaining);
170                if (!offset)
171                    return NULL;
172                offset = trace_get_payload_from_layer2(offset,
173                        TRACE_TYPE_ETH,
174                        &ethertype,
175                        &remaining);
176                if (!offset)
177                    return NULL;
178                continue;
179        }
180        return NULL;
181    }
182    return NULL;
183}
184
185
186/* Return values:
187 *  1 = continue reading packets
188 *  0 = stop reading packets, cos we're done
189 *  -1 = stop reading packets, we've got an error
190 */
191static int per_packet(libtrace_packet_t **packet) {
192        if (IS_LIBTRACE_META_PACKET((*packet))) {
193                return 1;
194        }
195
196        if (trace_get_link_type(*packet) == -1) {
197                fprintf(stderr, "Halted due to being unable to determine linktype - input trace may be corrupt.\n");
198                return -1;
199        }
200
201        if (snaplen>0) {
202                trace_set_capture_length(*packet,snaplen);
203        }
204
205        if (trace_get_seconds(*packet)<starttime) {
206                return 1;
207        }
208
209        if (trace_get_seconds(*packet)>endtime) {
210                return 0;
211        }
212
213        if (firsttime==0) {
214                time_t now = trace_get_seconds(*packet);
215                if (now != 0 && starttime != 0) {
216                        firsttime=now-((now - starttime)%interval);
217                }
218                else if (now != 0) {
219                        firsttime=now;
220                }
221        }
222
223        if (output && trace_get_seconds(*packet)>firsttime+interval) {
224                trace_destroy_output(output);
225                output=NULL;
226                firsttime+=interval;
227        }
228
229        if (output && pktcount%count==0) {
230                trace_destroy_output(output);
231                output=NULL;
232        }
233
234        pktcount++;
235        totbytes+=trace_get_capture_length(*packet);
236        if (output && totbytes-totbyteslast>=bytes) {
237                trace_destroy_output(output);
238                output=NULL;
239                totbyteslast=totbytes;
240        }
241        if (!output) {
242                char *buffer;
243                bool need_ext=false;
244                if (maxfiles <= filescreated) {
245                        return 0;
246                }
247                buffer=strdup(output_base);
248                if (interval!=UINT64_MAX && maxfiles>1) {
249                        buffer=strdupcat(buffer,"-");
250                        buffer=strdupcati(buffer,(uint64_t)firsttime);
251                        need_ext=true;
252                }
253                if (count!=UINT64_MAX && maxfiles>1) {
254                        buffer=strdupcat(buffer,"-");
255                        buffer=strdupcati(buffer,(uint64_t)pktcount);
256                        need_ext=true;
257                }
258                if (bytes!=UINT64_MAX && maxfiles>1) {
259                        static int filenum=0;
260                        buffer=strdupcat(buffer,"-");
261                        buffer=strdupcati(buffer,(uint64_t)++filenum);
262                        need_ext=true;
263                }
264                if (need_ext) {
265                        if (compress_level!=0)
266                                buffer=strdupcat(buffer,".gz");
267                }
268                if (verbose>1) {
269                        fprintf(stderr,"%s:",buffer);
270                        if (count!=UINT64_MAX)
271                                fprintf(stderr," count=%" PRIu64,pktcount);
272                        if (bytes!=UINT64_MAX)
273                                fprintf(stderr," bytes=%" PRIu64,bytes);
274                        if (interval!=UINT64_MAX) {
275                                time_t filetime = firsttime;
276                                fprintf(stderr," time=%s",ctime(&filetime));
277                        }
278                        else {
279                                fprintf(stderr,"\n");
280                        }
281                }
282                output=trace_create_output(buffer);
283                if (trace_is_err_output(output)) {
284                        trace_perror_output(output,"%s",buffer);
285                        free(buffer);
286                        return -1;
287                }
288                if (compress_level!=-1) {
289                        if (trace_config_output(output,
290                                                TRACE_OPTION_OUTPUT_COMPRESS,
291                                                &compress_level)==-1) {
292                                trace_perror_output(output,"Unable to set compression level");
293                        }
294                }
295
296                if (trace_config_output(output,
297                                        TRACE_OPTION_OUTPUT_COMPRESSTYPE,
298                                        &compress_type) == -1) {
299                        trace_perror_output(output, "Unable to set compression type");
300                }
301
302                trace_start_output(output);
303                if (trace_is_err_output(output)) {
304                        trace_perror_output(output,"%s",buffer);
305                        free(buffer);
306                        return -1;
307                }
308                free(buffer);
309                filescreated ++;
310        }
311
312        /* Some traces we have are padded (usually with 0x00), so
313         * lets sort that out now and truncate them properly
314         */
315
316        if (trace_get_capture_length(*packet)
317                        > trace_get_wire_length(*packet)) {
318                trace_set_capture_length(*packet,
319                        trace_get_wire_length(*packet));
320        }
321
322        /* Support "jump"ping to the nth IP header. */
323        if (jump) {
324            /* Skip headers */
325            void *newpacket = perform_jump(*packet, jump);
326            if (newpacket) {
327                trace_destroy_packet(*packet);
328                *packet = newpacket;
329            }
330            else /* Skip packet */
331                return 1;
332        }
333
334        if (trace_write_packet(output, *packet)==-1) {
335                trace_perror_output(output,"write_packet");
336                return -1;
337        }
338
339        return 1;
340
341}
342
343int main(int argc, char *argv[])
344{
345        char *compress_type_str=NULL;
346        struct libtrace_filter_t *filter=NULL;
347        struct libtrace_t *input = NULL;
348        struct libtrace_packet_t *packet = trace_create_packet();
349        struct sigaction sigact;
350        int i;
351
352        if (argc<2) {
353                usage(argv[0]);
354                return 1;
355        }
356
357        /* Parse command line options */
358        while(1) {
359                int option_index;
360                struct option long_options[] = {
361                        { "filter",        1, 0, 'f' },
362                        { "count",         1, 0, 'c' },
363                        { "bytes",         1, 0, 'b' },
364                        { "starttime",     1, 0, 's' },
365                        { "endtime",       1, 0, 'e' },
366                        { "interval",      1, 0, 'i' },
367                        { "jump",          1, 0, 'j' },
368                        { "libtrace-help", 0, 0, 'H' },
369                        { "maxfiles",      1, 0, 'm' },
370                        { "snaplen",       1, 0, 'S' },
371                        { "verbose",       0, 0, 'v' },
372                        { "compress-level", 1, 0, 'z' },
373                        { "compress-type", 1, 0, 'Z' },
374                        { NULL,            0, 0, 0   },
375                };
376
377                int c=getopt_long(argc, argv, "j:f:c:b:s:e:i:m:S:Hvz:Z:",
378                                long_options, &option_index);
379
380                if (c==-1)
381                        break;
382
383                switch (c) {
384                        case 'f': filter=trace_create_filter(optarg);
385                                break;
386                        case 'c': count=atoi(optarg);
387                                break;
388                        case 'b': bytes=atoi(optarg);
389                                break;
390                        case 's': starttime=atoi(optarg); /* FIXME: use getdate */
391                                  break;
392                        case 'e': endtime=atoi(optarg);
393                                  break;
394                        case 'i': interval=atoi(optarg);
395                                  break;
396                        case 'j': jump=atoi(optarg);
397                                  break;
398                        case 'm': maxfiles=atoi(optarg);
399                                  break;
400                        case 'S': snaplen=atoi(optarg);
401                                  break;
402                        case 'H':
403                                  trace_help();
404                                  exit(1);
405                                  break;
406                        case 'v':
407                                  verbose++;
408                                  break;
409                        case 'z':
410                                  compress_level=atoi(optarg);
411                                  if (compress_level<0 || compress_level>9) {
412                                        usage(argv[0]);
413                                        exit(1);
414                                  }
415                                  break;
416                        case 'Z':
417                                  compress_type_str=optarg;
418                                  break;
419                        default:
420                                fprintf(stderr,"Unknown option: %c\n",c);
421                                usage(argv[0]);
422                                return 1;
423                }
424        }
425
426        if (compress_type_str == NULL && compress_level >= 0) {
427                fprintf(stderr, "Compression level set, but no compression type was defined, setting to gzip\n");
428                compress_type = TRACE_OPTION_COMPRESSTYPE_ZLIB;
429        }
430
431        else if (compress_type_str == NULL) {
432                /* If a level or type is not specified, use the "none"
433                 * compression module */
434                compress_type = TRACE_OPTION_COMPRESSTYPE_NONE;
435        }
436
437        /* I decided to be fairly generous in what I accept for the
438         * compression type string */
439        else if (strncmp(compress_type_str, "gz", 2) == 0 ||
440                        strncmp(compress_type_str, "zlib", 4) == 0) {
441                compress_type = TRACE_OPTION_COMPRESSTYPE_ZLIB;
442        } else if (strncmp(compress_type_str, "bz", 2) == 0) {
443                compress_type = TRACE_OPTION_COMPRESSTYPE_BZ2;
444        } else if (strncmp(compress_type_str, "lzo", 3) == 0) {
445                compress_type = TRACE_OPTION_COMPRESSTYPE_LZO;
446        } else if (strncmp(compress_type_str, "xz", 2) == 0) {
447                compress_type = TRACE_OPTION_COMPRESSTYPE_LZMA;
448        } else if (strncmp(compress_type_str, "no", 2) == 0) {
449                compress_type = TRACE_OPTION_COMPRESSTYPE_NONE;
450        } else {
451                fprintf(stderr, "Unknown compression type: %s\n",
452                        compress_type_str);
453                return 1;
454        }
455
456        if (optind+2>argc) {
457                fprintf(stderr,"missing inputuri or outputuri\n");
458                usage(argv[0]);
459        }
460
461        output_base = argv[argc - 1];
462
463        sigact.sa_handler = cleanup_signal;
464        sigemptyset(&sigact.sa_mask);
465        sigact.sa_flags = SA_RESTART;
466
467        sigaction(SIGINT, &sigact, NULL);
468        sigaction(SIGTERM, &sigact, NULL);
469
470        output=NULL;
471
472        signal(SIGINT,&cleanup_signal);
473        signal(SIGTERM,&cleanup_signal);
474
475        for (i = optind; i < argc - 1; i++) {
476
477
478                input = trace_create(argv[i]);
479
480                if (trace_is_err(input)) {
481                        trace_perror(input,"%s",argv[i]);
482                        return 1;
483                }
484
485                if (filter && trace_config(input, TRACE_OPTION_FILTER, filter) == 1) {
486                        trace_perror(input, "Configuring filter for %s",
487                                        argv[i]);
488                        return 1;
489                }
490
491                if (trace_start(input)==-1) {
492                        trace_perror(input,"%s",argv[i]);
493                        return 1;
494                }
495
496                while (trace_read_packet(input,packet)>0) {
497                        if (per_packet(&packet) < 1)
498                                done = 1;
499                        if (done)
500                                break;
501                }
502
503                if (trace_is_err(input)) {
504                        trace_perror(input,"Reading packets");
505                        trace_destroy(input);
506                        break;
507                }
508
509                trace_destroy(input);
510               
511                if (done)
512                        break;
513               
514        }
515
516        if (verbose) {
517                libtrace_stat_t *stat;
518               
519                stat = trace_create_statistics();
520                trace_get_statistics(input, stat);
521
522                if (stat->received_valid)
523                        fprintf(stderr,"%" PRIu64 " packets on input\n",
524                                        stat->received);
525                if (stat->filtered_valid)
526                        fprintf(stderr,"%" PRIu64 " packets filtered\n",
527                                        stat->filtered);
528                if (stat->dropped_valid)
529                        fprintf(stderr,"%" PRIu64 " packets dropped\n",
530                                        stat->dropped);
531                if (stat->accepted_valid)
532                        fprintf(stderr,"%" PRIu64 " packets accepted\n",
533                                        stat->accepted);
534                free(stat);
535        }
536       
537        if (output)
538                trace_destroy_output(output);
539
540        trace_destroy_packet(packet);
541
542        return 0;
543}
Note: See TracBrowser for help on using the repository browser.