source: tools/tracereplay/tracereplay.c @ 1ca17db

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 1ca17db was 1ca17db, checked in by Shane Alcock <salcock@…>, 9 years ago
  • Fixed tracereplay bug where we would try to update the transport checksum for packets that don't have a complete transport header
  • Property mode set to 100644
File size: 8.3 KB
Line 
1
2/*
3
4   Tracereplay is a simple utility that takes a trace and replays it to a
5   specified interface.
6   It pads packets with zeroes to reach the original length of the packet
7   and recalculates checksums in ip/tcp/udp headers.
8
9Authors: Andreas Loef and Yuwei Wang
10
11
12 */
13
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <assert.h>
18#include <sys/types.h>
19#include <unistd.h>
20#include <string.h>
21#include <libtrace.h>
22#include <getopt.h>
23#include <arpa/inet.h>
24
25#define FCS_SIZE 4
26
27int broadcast = 0;
28
29/* This function assumes that the relevant fields have been zeroed out.
30   RFC 1071 describes the method and provides a code example*/
31static uint16_t checksum(void * buffer, uint16_t length) {
32        uint32_t sum = 0;
33        uint16_t * buff = (uint16_t *) buffer;
34        uint16_t count = length;
35
36        while(count > 1 ) {
37                sum += *buff++;
38                count = count -2;
39        }
40
41        if(count > 0) {
42                sum += *buff;
43        }
44
45        while (sum>>16)
46                sum = (sum & 0xffff) + (sum >> 16);
47
48        return ~sum;
49}
50
51/*
52   This function calculates and fills in the correct checksum on
53   a transport protocol header.
54   Currently only UDP and TCP are supported.
55 */
56
57static void udp_tcp_checksum(libtrace_ip_t *ip, uint32_t length) {
58
59        uint32_t sum = 0;
60        uint16_t protocol = ip->ip_p;
61        uint16_t temp = 0;
62        uint16_t * check = NULL;
63        uint16_t tsum = 0;
64        void * transportheader = NULL;
65        uint32_t rem;
66
67        sum += (uint16_t) ~checksum(&ip->ip_src.s_addr,sizeof(uint32_t));
68        sum += (uint16_t) ~checksum(&ip->ip_dst.s_addr,sizeof(uint32_t));
69
70
71        /*this will be in host order whereas everything else is in network order*/
72        temp = htons(protocol);
73        sum += (uint16_t) ~checksum(&temp,sizeof(uint16_t));
74
75        /*this will be in host order whereas everything else is in network order*/
76        temp = htons(length);
77        sum += (uint16_t) ~checksum(&temp,sizeof(uint16_t));
78
79        transportheader = trace_get_payload_from_ip(ip,NULL,&rem);
80
81        if (transportheader == NULL)
82                return;
83
84        /* UDP */
85        if(protocol == 17 ) {
86                libtrace_udp_t * udp_header = transportheader;
87
88                if (rem < sizeof(libtrace_udp_t))
89                        return;
90                check = &udp_header -> check;
91                *check = 0;
92                tsum = checksum(transportheader, length);
93        }
94        /* TCP */
95        else if(protocol == 6) {
96                libtrace_tcp_t * tcp_header = transportheader;
97
98                if (rem < sizeof(libtrace_tcp_t))
99                        return;
100                tcp_header -> check = 0;
101                check = &tcp_header -> check;
102                *check = 0;
103                tsum = checksum(transportheader,length);
104        }
105
106        sum += (uint16_t) ~tsum;
107
108        while (sum>>16)
109                sum = (sum & 0xffff) + (sum >> 16);
110
111        if(check != NULL) {
112                *check = (uint16_t)~sum;
113        }
114
115
116
117}
118
119/*
120   Create a copy of the packet that can be written to the output URI.
121   if the packet is IPv4 the checksum will be recalculated to account for
122   cryptopan. Same for TCP and UDP. No other protocols are supported at the
123   moment.
124 */
125static libtrace_packet_t * per_packet(libtrace_packet_t *packet) {
126        uint32_t remaining = 0; 
127        libtrace_linktype_t linktype = 0;
128        libtrace_ip_t * header = NULL;
129        uint16_t sum = 0;
130        libtrace_packet_t *new_packet;
131        size_t wire_length;
132        void * pkt_buffer;
133        void * l2_header;
134        libtrace_ether_t * ether_header;
135        int i;
136
137        pkt_buffer = trace_get_packet_buffer(packet,&linktype,&remaining);
138        remaining = 0;
139        new_packet = trace_create_packet();
140
141        wire_length = trace_get_wire_length(packet);
142
143        /* if it's ehternet we don't want to add space for the FCS that will
144           be appended. */
145        if(linktype == TRACE_TYPE_ETH || linktype == TRACE_TYPE_80211) {
146                wire_length -= FCS_SIZE;
147        }
148
149        trace_construct_packet(new_packet,linktype,pkt_buffer,wire_length);
150
151
152        if(broadcast) {
153                l2_header = trace_get_layer2(new_packet,&linktype,&remaining);
154                if(linktype == TRACE_TYPE_ETH){
155                        ether_header = (libtrace_ether_t *) l2_header;
156                        for(i = 0; i < 6; i++) {
157                                ether_header -> ether_dhost[i] = 0xFF;
158                        }
159                }
160
161        }
162
163
164
165        header = trace_get_ip(new_packet);
166        if(header != NULL) {
167                /* update ip checksum */
168                wire_length -= sizeof(uint32_t)*header->ip_hl;
169                header -> ip_sum = 0;
170                sum = checksum(header,header->ip_hl*sizeof(uint32_t));
171                header -> ip_sum = sum;
172                /* update transport layer checksums */
173                udp_tcp_checksum(header,ntohs(header->ip_len)-sizeof(uint32_t)*header->ip_hl);
174        }
175
176        return new_packet;
177
178}
179
180
181
182static uint32_t event_read_packet(libtrace_t *trace, libtrace_packet_t *packet) 
183{
184        libtrace_eventobj_t obj;
185        fd_set rfds;
186        struct timeval sleep_tv;
187
188        FD_ZERO(&rfds);
189
190        for (;;) {
191                obj = trace_event(trace, packet);
192
193                switch(obj.type) {
194
195                        /* Device has no packets at present - lets wait until
196                         * it does get something */
197                        case TRACE_EVENT_IOWAIT:
198                                FD_ZERO(&rfds);
199                                FD_SET(obj.fd, &rfds);
200                                select(obj.fd + 1, &rfds, NULL, NULL, 0);
201                                continue;
202
203                                /* Replaying a trace in tracetime and the next packet
204                                 * is not due yet */
205                        case TRACE_EVENT_SLEEP:
206                                /* select offers good precision for sleeping */
207                                sleep_tv.tv_sec = (int)obj.seconds;
208                                sleep_tv.tv_usec = (int) ((obj.seconds - sleep_tv.tv_sec) * 1000000.0);
209                                select(0, NULL, NULL, NULL, &sleep_tv);
210                                continue;
211
212                                /* We've got a packet! */
213                        case TRACE_EVENT_PACKET:
214                                /* Check for error first */
215                                if (obj.size == -1)
216                                        return -1;
217                                return 1;
218
219                                /* End of trace has been reached */
220                        case TRACE_EVENT_TERMINATE:
221                                return -1;
222
223                                /* An event we don't know about has occured */
224                        default:
225                                fprintf(stderr, "Unknown event type occured\n");
226                                return -1;
227                }
228        }
229}
230
231static void usage(char * argv) {
232        fprintf(stderr, "usage: %s [options] inputuri outputuri...\n", argv);
233        fprintf(stderr, " --filter bpfexpr\n");
234        fprintf(stderr, " -f bpfexpr\n");
235        fprintf(stderr, "\t\tApply a bpf filter expression\n");
236        fprintf(stderr, " -s snaplength\n");
237        fprintf(stderr, " --snaplength snaplength\n");
238        fprintf(stderr, "\t\tTruncate the packets read from inputuri to <snaplength>\n");
239        fprintf(stderr, " -b\n");
240        fprintf(stderr, " --broadcast\n");
241        fprintf(stderr, "\t\tSend ethernet frames to broadcast address\n");
242
243}
244
245int main(int argc, char *argv[]) {
246
247        libtrace_t *trace;
248        libtrace_out_t *output;
249        libtrace_packet_t *packet;
250        libtrace_filter_t *filter=NULL;
251        int psize = 0;
252        char *uri = 0;
253        libtrace_packet_t * new;
254        int snaplen = 0;
255
256
257        while(1) {
258                int option_index;
259                struct option long_options[] = {
260                        { "filter",     1, 0, 'f'},
261                        { "help",       0, 0, 'h'},
262                        { "snaplen",    1, 0, 's'},
263                        { "broadcast",  0, 0, 'b'},
264                        { NULL,         0, 0, 0}
265                };
266
267                int c = getopt_long(argc, argv, "bhs:f:",
268                                long_options, &option_index);
269
270                if(c == -1)
271                        break;
272
273                switch (c) {
274                        case 'f':
275                                filter = trace_create_filter(optarg);
276                                break;
277                        case 's':
278                                snaplen = atoi(optarg);
279                                break;
280
281                        case 'b':
282                                broadcast = 1;
283                                break;
284
285                        case 'h':
286
287                                usage(argv[0]);
288                                return 1;
289                        default:
290                                fprintf(stderr, "Unknown option: %c\n", c);
291                }
292        }
293
294        if(optind>=argc) {
295                fprintf(stderr, "Missing input uri\n");
296                usage(argv[0]);
297                return 1;
298        }
299        if(optind+1>=argc) {
300                fprintf(stderr, "Missing output uri\n");
301                usage(argv[0]);
302                return 1;
303        }
304
305        uri = strdup(argv[optind]);
306
307        /* Create the trace */
308        trace = trace_create(uri);
309        if (trace_is_err(trace)) {
310                trace_perror(trace, "trace_create");
311                return 1;
312        }
313
314        /*apply snaplength */
315        if(snaplen) {
316                if(trace_config(trace,TRACE_OPTION_SNAPLEN,&snaplen)) {
317                        trace_perror(trace,"error setting snaplength, proceeding anyway");
318                }
319        }
320
321        /* apply filter */
322        if(filter) {
323                if(trace_config(trace, TRACE_OPTION_FILTER, filter)) {
324                        trace_perror(trace, "ignoring: ");
325                }
326        }
327
328        /* Starting the trace */
329        if (trace_start(trace) != 0) {
330                trace_perror(trace, "trace_start");
331                return 1;
332        }
333
334        /* Creating output trace */
335        output = trace_create_output(argv[optind+1]);
336
337        if (trace_is_err_output(output)) {
338                trace_perror_output(output, "Opening output trace: ");
339                return 1;
340        }
341        if (trace_start_output(output)) {
342                trace_perror_output(output, "Starting output trace: ");
343                trace_destroy_output(output);
344                trace_destroy(trace);
345                return 1;
346        }
347
348        packet = trace_create_packet();
349
350        for (;;) {
351                if ((psize = event_read_packet(trace, packet)) <= 0) {
352                        break;
353                }
354
355                /* Got a packet - let's do something with it */
356                new = per_packet(packet);
357
358                if (trace_write_packet(output, new) < 0) {
359                        trace_perror_output(output, "Writing packet");
360                        trace_destroy(trace);
361                        trace_destroy_output(output);
362                        trace_destroy_packet(packet);
363                        return 1;
364                }
365                trace_destroy_packet(new);
366        }
367        if (trace_is_err(trace)) {
368                trace_perror(trace,"%s",uri);
369        }
370        free(uri);
371        trace_destroy(trace);
372        if(filter != NULL) {
373                trace_destroy_filter(filter);
374        }
375        trace_destroy_output(output);
376        trace_destroy_packet(packet);
377        return 0;
378
379}
380
Note: See TracBrowser for help on using the repository browser.