source: tools/tracereplay/tracereplay.c @ d7d3267

develop
Last change on this file since d7d3267 was d7d3267, checked in by Shane Alcock <salcock@…>, 23 months ago

Merge branch 'master' of git://github.com/jacobvw/libtrace into jacobvw-master

Conflicts:

lib/format_linux_ring.c

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