source: tools/tracereplay/tracereplay.c @ 8a12a49

develop
Last change on this file since 8a12a49 was 8a12a49, checked in by Shane Alcock <salcock@…>, 2 years ago

Add proper bracing around a few simple ifs in tracereplay.

  • Property mode set to 100644
File size: 8.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
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        if (trace_get_wire_length(packet) == 0) {
102                return NULL;
103        }
104
105        pkt_buffer = trace_get_packet_buffer(packet,&linktype,&remaining);
106        remaining = 0;
107        new_packet = trace_create_packet();
108
109        wire_length = trace_get_wire_length(packet);
110
111        /* if it's ehternet we don't want to add space for the FCS that will
112           be appended. */
113        if(linktype == TRACE_TYPE_ETH || linktype == TRACE_TYPE_80211) {
114                wire_length -= FCS_SIZE;
115        }
116
117        trace_construct_packet(new_packet,linktype,pkt_buffer,wire_length);
118
119        if(broadcast) {
120                l2_header = trace_get_layer2(new_packet,&linktype,&remaining);
121                if(linktype == TRACE_TYPE_ETH){
122                        ether_header = (libtrace_ether_t *) l2_header;
123                        for(i = 0; i < 6; i++) {
124                                ether_header -> ether_dhost[i] = 0xFF;
125                        }
126                }
127
128        }
129
130        replace_ip_checksum(new_packet);
131        replace_transport_checksum(new_packet);
132
133        return new_packet;
134
135}
136
137
138
139static uint32_t event_read_packet(libtrace_t *trace, libtrace_packet_t *packet) 
140{
141        libtrace_eventobj_t obj;
142        fd_set rfds;
143        struct timeval sleep_tv;
144
145        FD_ZERO(&rfds);
146
147        for (;;) {
148                obj = trace_event(trace, packet);
149
150                switch(obj.type) {
151
152                        /* Device has no packets at present - lets wait until
153                         * it does get something */
154                        case TRACE_EVENT_IOWAIT:
155                                FD_ZERO(&rfds);
156                                FD_SET(obj.fd, &rfds);
157                                select(obj.fd + 1, &rfds, NULL, NULL, 0);
158                                continue;
159
160                                /* Replaying a trace in tracetime and the next packet
161                                 * is not due yet */
162                        case TRACE_EVENT_SLEEP:
163                                /* select offers good precision for sleeping */
164                                sleep_tv.tv_sec = (int)obj.seconds;
165                                sleep_tv.tv_usec = (int) ((obj.seconds - sleep_tv.tv_sec) * 1000000.0);
166                                select(0, NULL, NULL, NULL, &sleep_tv);
167                                continue;
168
169                                /* We've got a packet! */
170                        case TRACE_EVENT_PACKET:
171                                /* Check for error first */
172                                if (obj.size == -1) {
173                                        return -1;
174                                }
175                                return 1;
176
177                                /* End of trace has been reached */
178                        case TRACE_EVENT_TERMINATE:
179                                return -1;
180
181                                /* An event we don't know about has occured */
182                        default:
183                                fprintf(stderr, "Unknown event type occured\n");
184                                return -1;
185                }
186        }
187}
188
189static void usage(char * argv) {
190        fprintf(stderr, "usage: %s [options] inputuri outputuri...\n", argv);
191        fprintf(stderr, " --filter bpfexpr\n");
192        fprintf(stderr, " -f bpfexpr\n");
193        fprintf(stderr, "\t\tApply a bpf filter expression\n");
194        fprintf(stderr, " -s snaplength\n");
195        fprintf(stderr, " --snaplength snaplength\n");
196        fprintf(stderr, "\t\tTruncate the packets read from inputuri to <snaplength>\n");
197        fprintf(stderr, " -b\n");
198        fprintf(stderr, " --broadcast\n");
199        fprintf(stderr, "\t\tSend ethernet frames to broadcast address\n");
200        fprintf(stderr, " -X\n");
201        fprintf(stderr, " --speedup\n");
202        fprintf(stderr, "\t\tSpeed up replay by a factor of <speedup>\n");
203
204}
205
206int main(int argc, char *argv[]) {
207
208        libtrace_t *trace;
209        libtrace_out_t *output;
210        libtrace_packet_t *packet;
211        libtrace_filter_t *filter=NULL;
212        int psize = 0;
213        char *uri = 0;
214        libtrace_packet_t * new;
215        int snaplen = 0;
216        int speedup = 1;
217
218
219        while(1) {
220                int option_index;
221                struct option long_options[] = {
222                        { "filter",     1, 0, 'f'},
223                        { "help",       0, 0, 'h'},
224                        { "snaplen",    1, 0, 's'},
225                        { "broadcast",  0, 0, 'b'},
226                        { "speedup",    1, 0, 'X'},
227                        { NULL,         0, 0, 0}
228                };
229
230                int c = getopt_long(argc, argv, "bhs:f:X:",
231                                long_options, &option_index);
232
233                if(c == -1)
234                        break;
235
236                switch (c) {
237                        case 'f':
238                                filter = trace_create_filter(optarg);
239                                break;
240                        case 's':
241                                snaplen = atoi(optarg);
242                                break;
243                        case 'X':
244                                speedup = atoi(optarg);
245                                break;
246                        case 'b':
247                                broadcast = 1;
248                                break;
249
250                        case 'h':
251
252                                usage(argv[0]);
253                                return 1;
254                        default:
255                                fprintf(stderr, "Unknown option: %c\n", c);
256                }
257        }
258
259        if(optind>=argc) {
260                fprintf(stderr, "Missing input uri\n");
261                usage(argv[0]);
262                return 1;
263        }
264        if(optind+1>=argc) {
265                fprintf(stderr, "Missing output uri\n");
266                usage(argv[0]);
267                return 1;
268        }
269
270        if (speedup < 1) {
271                speedup = 1;
272        }
273
274        uri = strdup(argv[optind]);
275
276        /* Create the trace */
277        trace = trace_create(uri);
278        if (trace_is_err(trace)) {
279                trace_perror(trace, "trace_create");
280                return 1;
281        }
282
283        /*apply snaplength */
284        if(snaplen) {
285                if(trace_config(trace,TRACE_OPTION_SNAPLEN,&snaplen)) {
286                        trace_perror(trace,"error setting snaplength, proceeding anyway");
287                }
288        }
289
290        /* apply filter */
291        if(filter) {
292                if(trace_config(trace, TRACE_OPTION_FILTER, filter)) {
293                        trace_perror(trace, "ignoring: ");
294                }
295        }
296
297        if (trace_config(trace, TRACE_OPTION_REPLAY_SPEEDUP, &speedup)) {
298                trace_perror(trace, "error setting replay speedup factor");
299                return 1;
300        }
301
302        /* Starting the trace */
303        if (trace_start(trace) != 0) {
304                trace_perror(trace, "trace_start");
305                return 1;
306        }
307
308        /* Creating output trace */
309        output = trace_create_output(argv[optind+1]);
310
311        if (trace_is_err_output(output)) {
312                trace_perror_output(output, "Opening output trace: ");
313                return 1;
314        }
315        if (trace_start_output(output)) {
316                trace_perror_output(output, "Starting output trace: ");
317                trace_destroy_output(output);
318                trace_destroy(trace);
319                return 1;
320        }
321
322        packet = trace_create_packet();
323
324        for (;;) {
325                if ((psize = event_read_packet(trace, packet)) <= 0) {
326                        break;
327                }
328
329                /* Got a packet - let's do something with it */
330                new = per_packet(packet);
331
332                if (!new)
333                        continue;
334
335                if (trace_write_packet(output, new) < 0) {
336                        trace_perror_output(output, "Writing packet");
337                        trace_destroy(trace);
338                        trace_destroy_output(output);
339                        trace_destroy_packet(packet);
340                        return 1;
341                }
342                trace_destroy_packet(new);
343        }
344        if (trace_is_err(trace)) {
345                trace_perror(trace,"%s",uri);
346        }
347        free(uri);
348        trace_destroy(trace);
349        if(filter != NULL) {
350                trace_destroy_filter(filter);
351        }
352        trace_destroy_output(output);
353        trace_destroy_packet(packet);
354        return 0;
355
356}
357
Note: See TracBrowser for help on using the repository browser.