source: tools/tracereplay/tracereplay.c @ d74ca03

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

Add check in tracereplay for unknown linktype

  • 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        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                fprintf(stderr, "Encountered packet with unknown linktype, Skipping it\n");
107                return NULL;
108        }
109
110        remaining = 0;
111        new_packet = trace_create_packet();
112
113        wire_length = trace_get_wire_length(packet);
114
115        /* if it's ehternet we don't want to add space for the FCS that will
116           be appended. */
117        if(linktype == TRACE_TYPE_ETH || linktype == TRACE_TYPE_80211) {
118                wire_length -= FCS_SIZE;
119        }
120
121        trace_construct_packet(new_packet,linktype,pkt_buffer,wire_length);
122
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                                return 1;
180
181                                /* End of trace has been reached */
182                        case TRACE_EVENT_TERMINATE:
183                                return -1;
184
185                                /* An event we don't know about has occured */
186                        default:
187                                fprintf(stderr, "Unknown event type occured\n");
188                                return -1;
189                }
190        }
191}
192
193static void usage(char * argv) {
194        fprintf(stderr, "usage: %s [options] inputuri outputuri...\n", argv);
195        fprintf(stderr, " --filter bpfexpr\n");
196        fprintf(stderr, " -f bpfexpr\n");
197        fprintf(stderr, "\t\tApply a bpf filter expression\n");
198        fprintf(stderr, " -s snaplength\n");
199        fprintf(stderr, " --snaplength snaplength\n");
200        fprintf(stderr, "\t\tTruncate the packets read from inputuri to <snaplength>\n");
201        fprintf(stderr, " -b\n");
202        fprintf(stderr, " --broadcast\n");
203        fprintf(stderr, "\t\tSend ethernet frames to broadcast address\n");
204        fprintf(stderr, " -X\n");
205        fprintf(stderr, " --speedup\n");
206        fprintf(stderr, "\t\tSpeed up replay by a factor of <speedup>\n");
207
208}
209
210int main(int argc, char *argv[]) {
211
212        libtrace_t *trace;
213        libtrace_out_t *output;
214        libtrace_packet_t *packet;
215        libtrace_filter_t *filter=NULL;
216        int psize = 0;
217        char *uri = 0;
218        libtrace_packet_t * new;
219        int snaplen = 0;
220        int speedup = 1;
221
222
223        while(1) {
224                int option_index;
225                struct option long_options[] = {
226                        { "filter",     1, 0, 'f'},
227                        { "help",       0, 0, 'h'},
228                        { "snaplen",    1, 0, 's'},
229                        { "broadcast",  0, 0, 'b'},
230                        { "speedup",    1, 0, 'X'},
231                        { NULL,         0, 0, 0}
232                };
233
234                int c = getopt_long(argc, argv, "bhs:f:X:",
235                                long_options, &option_index);
236
237                if(c == -1)
238                        break;
239
240                switch (c) {
241                        case 'f':
242                                filter = trace_create_filter(optarg);
243                                break;
244                        case 's':
245                                snaplen = atoi(optarg);
246                                break;
247                        case 'X':
248                                speedup = atoi(optarg);
249                                break;
250                        case 'b':
251                                broadcast = 1;
252                                break;
253
254                        case 'h':
255
256                                usage(argv[0]);
257                                return 1;
258                        default:
259                                fprintf(stderr, "Unknown option: %c\n", c);
260                }
261        }
262
263        if(optind>=argc) {
264                fprintf(stderr, "Missing input uri\n");
265                usage(argv[0]);
266                return 1;
267        }
268        if(optind+1>=argc) {
269                fprintf(stderr, "Missing output uri\n");
270                usage(argv[0]);
271                return 1;
272        }
273
274        if (speedup < 1) {
275                speedup = 1;
276        }
277
278        uri = strdup(argv[optind]);
279
280        /* Create the trace */
281        trace = trace_create(uri);
282        if (trace_is_err(trace)) {
283                trace_perror(trace, "trace_create");
284                return 1;
285        }
286
287        /*apply snaplength */
288        if(snaplen) {
289                if(trace_config(trace,TRACE_OPTION_SNAPLEN,&snaplen)) {
290                        trace_perror(trace,"error setting snaplength, proceeding anyway");
291                }
292        }
293
294        /* apply filter */
295        if(filter) {
296                if(trace_config(trace, TRACE_OPTION_FILTER, filter)) {
297                        trace_perror(trace, "ignoring: ");
298                }
299        }
300
301        if (trace_config(trace, TRACE_OPTION_REPLAY_SPEEDUP, &speedup)) {
302                trace_perror(trace, "error setting replay speedup factor");
303                return 1;
304        }
305
306        /* Starting the trace */
307        if (trace_start(trace) != 0) {
308                trace_perror(trace, "trace_start");
309                return 1;
310        }
311
312        /* Creating output trace */
313        output = trace_create_output(argv[optind+1]);
314
315        if (trace_is_err_output(output)) {
316                trace_perror_output(output, "Opening output trace: ");
317                return 1;
318        }
319        if (trace_start_output(output)) {
320                trace_perror_output(output, "Starting output trace: ");
321                trace_destroy_output(output);
322                trace_destroy(trace);
323                return 1;
324        }
325
326        packet = trace_create_packet();
327
328        for (;;) {
329                if ((psize = event_read_packet(trace, packet)) <= 0) {
330                        break;
331                }
332
333                /* Got a packet - let's do something with it */
334                new = per_packet(packet);
335
336                if (!new)
337                        continue;
338
339                if (trace_write_packet(output, new) < 0) {
340                        trace_perror_output(output, "Writing packet");
341                        trace_destroy(trace);
342                        trace_destroy_output(output);
343                        trace_destroy_packet(packet);
344                        return 1;
345                }
346                trace_destroy_packet(new);
347        }
348        if (trace_is_err(trace)) {
349                trace_perror(trace,"%s",uri);
350        }
351        free(uri);
352        trace_destroy(trace);
353        if(filter != NULL) {
354                trace_destroy_filter(filter);
355        }
356        trace_destroy_output(output);
357        trace_destroy_packet(packet);
358        return 0;
359
360}
361
Note: See TracBrowser for help on using the repository browser.