source: tools/tracereplay/tracereplay.c @ fdf23b8

develop
Last change on this file since fdf23b8 was fdf23b8, checked in by Jacob Van Walraven <jcv9@…>, 2 years ago

Fix typo and remove spammy error message

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