source: tools/tracereplay/tracereplay.c @ 044d8bc

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

Don't replay packets with no contents, e.g. meta-records

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