source: tools/tracesplit/tracesplit.c @ 47d4f8c

cachetimestampsdeveloprc-4.0.4ringdecrementfixringperformance
Last change on this file since 47d4f8c was 47d4f8c, checked in by Shane Alcock <salcock@…>, 2 years ago

Fix various string truncation/overflow warnings

Thanks gcc 8!

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