source: tools/tracereplay/tracereplay.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: 7.5 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
29/*
30
31   Tracereplay is a simple utility that takes a trace and replays it to a
32   specified interface.
33   It pads packets with zeroes to reach the original length of the packet
34   and recalculates checksums in ip/tcp/udp headers.
35
36Authors: Andreas Loef and Yuwei Wang
37
38
39 */
40
41
42#include <stdio.h>
43#include <stdlib.h>
44#include <assert.h>
45#include <sys/types.h>
46#include <unistd.h>
47#include <string.h>
48#include <libtrace.h>
49#include <getopt.h>
50#include <arpa/inet.h>
51
52#define FCS_SIZE 4
53
54int broadcast = 0;
55
56static void replace_ip_checksum(libtrace_packet_t *packet) {
57
58        uint16_t *ip_csm_ptr = NULL;
59        uint16_t calc_csum;
60
61        ip_csm_ptr = trace_checksum_layer3(packet, &calc_csum);
62
63        if (ip_csm_ptr == NULL)
64                return;
65        *ip_csm_ptr = htons(calc_csum);
66
67}
68
69static void replace_transport_checksum(libtrace_packet_t *packet) {
70
71        uint16_t *csm_ptr = NULL;
72        uint16_t calc_csum;
73       
74        csm_ptr = trace_checksum_transport(packet, &calc_csum);
75
76        if (csm_ptr == NULL)
77                return;
78        *csm_ptr = htons(calc_csum);
79
80}
81
82/*
83   Create a copy of the packet that can be written to the output URI.
84   if the packet is IPv4 the checksum will be recalculated to account for
85   cryptopan. Same for TCP and UDP. No other protocols are supported at the
86   moment.
87 */
88static libtrace_packet_t * per_packet(libtrace_packet_t *packet) {
89        uint32_t remaining = 0; 
90        libtrace_linktype_t linktype = 0;
91        libtrace_packet_t *new_packet;
92        size_t wire_length;
93        void * pkt_buffer;
94        void * l2_header;
95        libtrace_ether_t * ether_header;
96        int i;
97
98        if (IS_LIBTRACE_META_PACKET(packet))
99                return NULL;
100
101        pkt_buffer = trace_get_packet_buffer(packet,&linktype,&remaining);
102        remaining = 0;
103        new_packet = trace_create_packet();
104
105        wire_length = trace_get_wire_length(packet);
106
107        /* if it's ehternet we don't want to add space for the FCS that will
108           be appended. */
109        if(linktype == TRACE_TYPE_ETH || linktype == TRACE_TYPE_80211) {
110                wire_length -= FCS_SIZE;
111        }
112
113        trace_construct_packet(new_packet,linktype,pkt_buffer,wire_length);
114
115
116        if(broadcast) {
117                l2_header = trace_get_layer2(new_packet,&linktype,&remaining);
118                if(linktype == TRACE_TYPE_ETH){
119                        ether_header = (libtrace_ether_t *) l2_header;
120                        for(i = 0; i < 6; i++) {
121                                ether_header -> ether_dhost[i] = 0xFF;
122                        }
123                }
124
125        }
126
127        replace_ip_checksum(new_packet);
128        replace_transport_checksum(new_packet);
129
130        return new_packet;
131
132}
133
134
135
136static uint32_t event_read_packet(libtrace_t *trace, libtrace_packet_t *packet) 
137{
138        libtrace_eventobj_t obj;
139        fd_set rfds;
140        struct timeval sleep_tv;
141
142        FD_ZERO(&rfds);
143
144        for (;;) {
145                obj = trace_event(trace, packet);
146
147                switch(obj.type) {
148
149                        /* Device has no packets at present - lets wait until
150                         * it does get something */
151                        case TRACE_EVENT_IOWAIT:
152                                FD_ZERO(&rfds);
153                                FD_SET(obj.fd, &rfds);
154                                select(obj.fd + 1, &rfds, NULL, NULL, 0);
155                                continue;
156
157                                /* Replaying a trace in tracetime and the next packet
158                                 * is not due yet */
159                        case TRACE_EVENT_SLEEP:
160                                /* select offers good precision for sleeping */
161                                sleep_tv.tv_sec = (int)obj.seconds;
162                                sleep_tv.tv_usec = (int) ((obj.seconds - sleep_tv.tv_sec) * 1000000.0);
163                                select(0, NULL, NULL, NULL, &sleep_tv);
164                                continue;
165
166                                /* We've got a packet! */
167                        case TRACE_EVENT_PACKET:
168                                /* Check for error first */
169                                if (obj.size == -1)
170                                        return -1;
171                                return 1;
172
173                                /* End of trace has been reached */
174                        case TRACE_EVENT_TERMINATE:
175                                return -1;
176
177                                /* An event we don't know about has occured */
178                        default:
179                                fprintf(stderr, "Unknown event type occured\n");
180                                return -1;
181                }
182        }
183}
184
185static void usage(char * argv) {
186        fprintf(stderr, "usage: %s [options] inputuri outputuri...\n", argv);
187        fprintf(stderr, " --filter bpfexpr\n");
188        fprintf(stderr, " -f bpfexpr\n");
189        fprintf(stderr, "\t\tApply a bpf filter expression\n");
190        fprintf(stderr, " -s snaplength\n");
191        fprintf(stderr, " --snaplength snaplength\n");
192        fprintf(stderr, "\t\tTruncate the packets read from inputuri to <snaplength>\n");
193        fprintf(stderr, " -b\n");
194        fprintf(stderr, " --broadcast\n");
195        fprintf(stderr, "\t\tSend ethernet frames to broadcast address\n");
196
197}
198
199int main(int argc, char *argv[]) {
200
201        libtrace_t *trace;
202        libtrace_out_t *output;
203        libtrace_packet_t *packet;
204        libtrace_filter_t *filter=NULL;
205        int psize = 0;
206        char *uri = 0;
207        libtrace_packet_t * new;
208        int snaplen = 0;
209
210
211        while(1) {
212                int option_index;
213                struct option long_options[] = {
214                        { "filter",     1, 0, 'f'},
215                        { "help",       0, 0, 'h'},
216                        { "snaplen",    1, 0, 's'},
217                        { "broadcast",  0, 0, 'b'},
218                        { NULL,         0, 0, 0}
219                };
220
221                int c = getopt_long(argc, argv, "bhs:f:",
222                                long_options, &option_index);
223
224                if(c == -1)
225                        break;
226
227                switch (c) {
228                        case 'f':
229                                filter = trace_create_filter(optarg);
230                                break;
231                        case 's':
232                                snaplen = atoi(optarg);
233                                break;
234
235                        case 'b':
236                                broadcast = 1;
237                                break;
238
239                        case 'h':
240
241                                usage(argv[0]);
242                                return 1;
243                        default:
244                                fprintf(stderr, "Unknown option: %c\n", c);
245                }
246        }
247
248        if(optind>=argc) {
249                fprintf(stderr, "Missing input uri\n");
250                usage(argv[0]);
251                return 1;
252        }
253        if(optind+1>=argc) {
254                fprintf(stderr, "Missing output uri\n");
255                usage(argv[0]);
256                return 1;
257        }
258
259        uri = strdup(argv[optind]);
260
261        /* Create the trace */
262        trace = trace_create(uri);
263        if (trace_is_err(trace)) {
264                trace_perror(trace, "trace_create");
265                return 1;
266        }
267
268        /*apply snaplength */
269        if(snaplen) {
270                if(trace_config(trace,TRACE_OPTION_SNAPLEN,&snaplen)) {
271                        trace_perror(trace,"error setting snaplength, proceeding anyway");
272                }
273        }
274
275        /* apply filter */
276        if(filter) {
277                if(trace_config(trace, TRACE_OPTION_FILTER, filter)) {
278                        trace_perror(trace, "ignoring: ");
279                }
280        }
281
282        /* Starting the trace */
283        if (trace_start(trace) != 0) {
284                trace_perror(trace, "trace_start");
285                return 1;
286        }
287
288        /* Creating output trace */
289        output = trace_create_output(argv[optind+1]);
290
291        if (trace_is_err_output(output)) {
292                trace_perror_output(output, "Opening output trace: ");
293                return 1;
294        }
295        if (trace_start_output(output)) {
296                trace_perror_output(output, "Starting output trace: ");
297                trace_destroy_output(output);
298                trace_destroy(trace);
299                return 1;
300        }
301
302        packet = trace_create_packet();
303
304        for (;;) {
305                if ((psize = event_read_packet(trace, packet)) <= 0) {
306                        break;
307                }
308
309                /* Got a packet - let's do something with it */
310                new = per_packet(packet);
311
312                if (!new)
313                        continue;
314
315                if (trace_write_packet(output, new) < 0) {
316                        trace_perror_output(output, "Writing packet");
317                        trace_destroy(trace);
318                        trace_destroy_output(output);
319                        trace_destroy_packet(packet);
320                        return 1;
321                }
322                trace_destroy_packet(new);
323        }
324        if (trace_is_err(trace)) {
325                trace_perror(trace,"%s",uri);
326        }
327        free(uri);
328        trace_destroy(trace);
329        if(filter != NULL) {
330                trace_destroy_filter(filter);
331        }
332        trace_destroy_output(output);
333        trace_destroy_packet(packet);
334        return 0;
335
336}
337
Note: See TracBrowser for help on using the repository browser.