source: lib/protocols_transport.c @ 8af0d01

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 8af0d01 was 10f924c, checked in by Shane Alcock <salcock@…>, 7 years ago

Fixed broken -fvisibility check in configure

  • Added a m4 script that does this properly rather than our hax gcc version check.
  • Tidied up CFLAGS in configure so we aren't adding the same sets of flags multiple times
  • Created a wandio_internal.h file for storing global variables that shouldn't be made public

Thanks to Alistair King, whose patch to try and make this work for
non-gcc systems brought my attention to just how broken this was :)

  • Property mode set to 100644
File size: 12.3 KB
Line 
1/*
2 * This file is part of libtrace
3 *
4 * Copyright (c) 2007,2008,2009,2010 The University of Waikato, Hamilton,
5 * New Zealand.
6 *
7 * Authors: Daniel Lawson
8 *          Perry Lorier
9 *          Shane Alcock
10 *         
11 * All rights reserved.
12 *
13 * This code has been developed by the University of Waikato WAND
14 * research group. For further information please see http://www.wand.net.nz/
15 *
16 * libtrace is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * libtrace is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with libtrace; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29 *
30 * $Id$
31 *
32 */
33
34
35#include "libtrace_int.h"
36#include "libtrace.h"
37#include "protocols.h"
38#include "checksum.h"
39#include <assert.h>
40#include <stdlib.h>
41#include <stdio.h> // fprintf
42#include <string.h>
43
44/* This file contains all the protocol decoding functions for transport layer
45 * protocols. This includes functions for access port numbers.
46 *
47 * Supported protocols include (but are not limited to):
48 *      TCP
49 *      UDP
50 *      ICMP
51 */
52
53/* Get the size of the payload as it was in the original packet, i.e. prior
54 * to any truncation.
55 *
56 * Basically, wire length minus the packet headers.
57 *
58 * Currently only supports IP (v4 and v6) and TCP, UDP and ICMP. Will return
59 * 0 if an unsupported protocol header is encountered, or if one of the
60 * headers is truncated.
61 */
62DLLEXPORT size_t trace_get_payload_length(const libtrace_packet_t *packet) {
63
64        void *layer;
65        uint16_t ethertype;
66        uint8_t proto;
67        uint32_t rem;
68        libtrace_ip_t *ip;
69        libtrace_ip6_t *ip6;
70        libtrace_tcp_t *tcp;
71        size_t len = 0;
72
73        /* Just use the cached length if we can */
74        if (packet->payload_length != -1)
75                return packet->payload_length; 
76
77        /* Set to zero so that we can return early without having to
78         * worry about forgetting to update the cached value */
79        ((libtrace_packet_t *)packet)->payload_length = 0;
80        layer = trace_get_layer3(packet, &ethertype, &rem);
81        if (!layer)
82                return 0;
83        switch (ethertype) {
84                case TRACE_ETHERTYPE_IP:
85                        ip = (libtrace_ip_t *)layer;
86                        if (rem < sizeof(libtrace_ip_t))
87                                return 0;
88                        len = ntohs(ip->ip_len) - (4 * ip->ip_hl);
89               
90                        /* Deal with v6 within v4 */
91                        if (ip->ip_p == TRACE_IPPROTO_IPV6)
92                                len -= sizeof(libtrace_ip6_t);
93                       
94                        break;
95                case TRACE_ETHERTYPE_IPV6:
96                        ip6 = (libtrace_ip6_t *)layer;
97                        if (rem < sizeof(libtrace_ip6_t))
98                                return 0;
99                        len = ntohs(ip6->plen);
100                        break;
101                default:
102                        return 0;
103        }
104
105        layer = trace_get_transport(packet, &proto, &rem);
106        if (!layer)
107                return 0;
108       
109        switch(proto) {
110                case TRACE_IPPROTO_TCP:
111                        if (rem < sizeof(libtrace_tcp_t))
112                                return 0;
113                        tcp = (libtrace_tcp_t *)layer;
114                       
115                        if (len < (size_t)(4 * tcp->doff))
116                                return 0;
117                       
118                        len -= (4 * tcp->doff);
119                        break;
120                case TRACE_IPPROTO_UDP:
121                        if (rem < sizeof(libtrace_udp_t))
122                                return 0;
123                        if (len < sizeof(libtrace_udp_t))
124                                return 0;
125                        len -= sizeof(libtrace_udp_t);
126                        break;
127                case TRACE_IPPROTO_ICMP:
128                        if (rem < sizeof(libtrace_icmp_t))
129                                return 0;
130                        if (len < sizeof(libtrace_icmp_t))
131                                return 0;
132                        len -= sizeof(libtrace_icmp_t);
133                        break;
134                case TRACE_IPPROTO_ICMPV6:
135                        if (rem < sizeof(libtrace_icmp6_t))
136                                return 0;
137                        if (len < sizeof(libtrace_icmp6_t))
138                                return 0;
139                        len -= sizeof(libtrace_icmp6_t);
140                        break;
141                       
142                default:
143                        return 0;
144        }
145
146        ((libtrace_packet_t *)packet)->payload_length = len;
147        return len;
148
149}
150
151DLLEXPORT void *trace_get_transport(const libtrace_packet_t *packet, 
152                uint8_t *proto,
153                uint32_t *remaining
154                ) 
155{
156        uint8_t dummy_proto;
157        uint16_t ethertype;
158        uint32_t dummy_remaining;
159        void *transport;
160
161        if (!proto) proto=&dummy_proto;
162
163        if (!remaining) remaining=&dummy_remaining;
164
165        if (packet->l4_header) {
166                /*
167                void *link;
168                libtrace_linktype_t linktype;
169                link = trace_get_packet_buffer(packet, &linktype, remaining);
170                if (!link)
171                        return NULL;
172                */
173                *proto = packet->transport_proto;
174                /* *remaining -= (packet->l4_header - link); */
175                *remaining = packet->l4_remaining;
176                return packet->l4_header;
177        }
178
179        transport = trace_get_layer3(packet,&ethertype,remaining);
180
181        if (!transport || *remaining == 0)
182                return NULL;
183
184        switch (ethertype) {
185                case TRACE_ETHERTYPE_IP: /* IPv4 */
186                        transport=trace_get_payload_from_ip(
187                                (libtrace_ip_t*)transport, proto, remaining);
188                        /* IPv6 */
189                        if (transport && *proto == TRACE_IPPROTO_IPV6) {
190                                transport=trace_get_payload_from_ip6(
191                                 (libtrace_ip6_t*)transport, proto,remaining);
192                        }
193                        break;
194                case TRACE_ETHERTYPE_IPV6: /* IPv6 */
195                        transport = trace_get_payload_from_ip6(
196                                (libtrace_ip6_t*)transport, proto, remaining);
197                        break;
198                default:
199                        *proto = 0;
200                        transport = NULL;
201                        break;
202                       
203        }
204
205        ((libtrace_packet_t *)packet)->transport_proto = *proto;
206        ((libtrace_packet_t *)packet)->l4_header = transport;
207        ((libtrace_packet_t *)packet)->l4_remaining = *remaining;
208
209
210        return transport;
211}
212
213DLLEXPORT libtrace_tcp_t *trace_get_tcp(libtrace_packet_t *packet) {
214        uint8_t proto;
215        uint32_t rem = 0;
216        libtrace_tcp_t *tcp;
217
218        tcp=(libtrace_tcp_t*)trace_get_transport(packet,&proto,&rem);
219
220        if (!tcp || proto != TRACE_IPPROTO_TCP)
221                return NULL;
222
223        /* We should return NULL if there isn't a full TCP header, because the
224         * caller has no way of telling how much of a TCP header we have
225         * returned - use trace_get_transport() if you want to deal with
226         * partial headers
227         *
228         * NOTE: We're not going to insist that all the TCP options are present
229         * as well, because lots of traces are snapped after 20 bytes of TCP
230         * header and I don't really want to break libtrace programs that
231         * use this function to process those traces */
232
233        if (rem < sizeof(libtrace_tcp_t))
234                return NULL;
235
236        return (libtrace_tcp_t*)tcp;
237}
238
239DLLEXPORT libtrace_tcp_t *trace_get_tcp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
240{
241        libtrace_tcp_t *tcpptr = 0;
242
243        if (ip->ip_p == TRACE_IPPROTO_TCP)  {
244                tcpptr = (libtrace_tcp_t *)
245                        trace_get_payload_from_ip(ip, NULL, remaining);
246        }
247
248        return tcpptr;
249}
250
251DLLEXPORT libtrace_udp_t *trace_get_udp(libtrace_packet_t *packet) {
252        uint8_t proto;
253        uint32_t rem = 0;
254        libtrace_udp_t *udp;
255
256        udp=(libtrace_udp_t*)trace_get_transport(packet,&proto,&rem);
257
258        if (!udp || proto != TRACE_IPPROTO_UDP)
259                return NULL;
260
261        /* Make sure we return a full UDP header as the caller has no way of
262         * telling how much of the packet is remaining */
263        if (rem < sizeof(libtrace_udp_t))
264                return NULL;
265
266        return udp;
267}
268
269DLLEXPORT libtrace_udp_t *trace_get_udp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
270{
271        libtrace_udp_t *udpptr = 0;
272
273        if (ip->ip_p == TRACE_IPPROTO_UDP) {
274                udpptr = (libtrace_udp_t *)
275                        trace_get_payload_from_ip(ip, NULL, remaining);
276        }
277
278        return udpptr;
279}
280
281DLLEXPORT libtrace_icmp_t *trace_get_icmp(libtrace_packet_t *packet) {
282        uint8_t proto;
283        uint32_t rem = 0;
284        libtrace_icmp_t *icmp;
285
286        icmp=(libtrace_icmp_t*)trace_get_transport(packet,&proto,&rem);
287
288        if (!icmp || proto != TRACE_IPPROTO_ICMP)
289                return NULL;
290
291        /* Make sure we return a full ICMP header as the caller has no way of
292         * telling how much of the packet is remaining */
293        if (rem < sizeof(libtrace_icmp_t))
294                return NULL;
295
296        return icmp;
297}
298
299DLLEXPORT libtrace_icmp6_t *trace_get_icmp6(libtrace_packet_t *packet) {
300        uint8_t proto;
301        uint32_t rem = 0;
302        libtrace_icmp6_t *icmp;
303
304        icmp=(libtrace_icmp6_t*)trace_get_transport(packet,&proto,&rem);
305
306        if (!icmp || proto != TRACE_IPPROTO_ICMPV6)
307                return NULL;
308
309        /* Make sure we return a full ICMP header as the caller has no way of
310         * telling how much of the packet is remaining */
311        if (rem < sizeof(libtrace_icmp6_t))
312                return NULL;
313
314        return icmp;
315}
316
317DLLEXPORT libtrace_icmp_t *trace_get_icmp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
318{
319        libtrace_icmp_t *icmpptr = 0;
320
321        if (ip->ip_p == TRACE_IPPROTO_ICMP)  {
322                icmpptr = (libtrace_icmp_t *)trace_get_payload_from_ip(ip, 
323                                NULL, remaining);
324        }
325
326        return icmpptr;
327}
328
329DLLEXPORT void *trace_get_payload_from_udp(libtrace_udp_t *udp, uint32_t *remaining)
330{
331        if (remaining) {
332                if (*remaining < sizeof(libtrace_udp_t)) {
333                        *remaining = 0;
334                        return NULL;
335                }
336                *remaining-=sizeof(libtrace_udp_t);
337        }
338        return (void*)((char*)udp+sizeof(libtrace_udp_t));
339}
340
341DLLEXPORT void *trace_get_payload_from_tcp(libtrace_tcp_t *tcp, uint32_t *remaining)
342{
343        unsigned int dlen = tcp->doff*4;
344        if (remaining) {
345                if (*remaining < dlen) {
346                        *remaining = 0;
347                        return NULL;
348                }
349                *remaining-=dlen;
350        }
351        return (void *)((char *)tcp+dlen);
352}
353
354DLLEXPORT void *trace_get_payload_from_icmp(libtrace_icmp_t *icmp, uint32_t *remaining)
355{
356        if (remaining) {
357                if (*remaining < sizeof(libtrace_icmp_t)) {
358                        *remaining = 0;
359                        return NULL;
360                }
361                *remaining-=sizeof(libtrace_icmp_t);
362        }
363        return (char*)icmp+sizeof(libtrace_icmp_t);
364}
365
366DLLEXPORT void *trace_get_payload_from_icmp6(libtrace_icmp6_t *icmp, uint32_t *remaining)
367{
368        if (remaining) {
369                if (*remaining < sizeof(libtrace_icmp6_t)) {
370                        *remaining = 0;
371                        return NULL;
372                }
373                *remaining-=sizeof(libtrace_icmp6_t);
374        }
375        return (char*)icmp+sizeof(libtrace_icmp6_t);
376}
377
378/* Return the source port
379 */
380DLLEXPORT uint16_t trace_get_source_port(const libtrace_packet_t *packet)
381{
382        uint32_t remaining;
383        uint8_t proto;
384        const struct ports_t *port = 
385                (const struct ports_t*)trace_get_transport((libtrace_packet_t*)packet,
386                        &proto, &remaining);
387
388        /* Snapped too early */
389        if (remaining<2)
390                return 0;
391
392        /* ICMP *technically* doesn't have ports */
393        if (proto == TRACE_IPPROTO_ICMP)
394                return 0;
395
396        if (port)
397                return ntohs(port->src);
398        else
399                return 0;
400}
401
402/* Same as get_source_port except use the destination port */
403DLLEXPORT uint16_t trace_get_destination_port(const libtrace_packet_t *packet)
404{
405        uint32_t remaining;
406        uint8_t proto;
407        struct ports_t *port = 
408                (struct ports_t*)trace_get_transport((libtrace_packet_t*)packet,
409                        &proto, &remaining);
410        /* Snapped too early */
411        if (remaining<4)
412                return 0;
413       
414        /* ICMP *technically* doesn't have ports */
415        if (proto == TRACE_IPPROTO_ICMP)
416                return 0;
417
418        if (port)
419                return ntohs(port->dst);
420        else
421                return 0;
422}
423
424DLLEXPORT uint16_t *trace_checksum_transport(libtrace_packet_t *packet, 
425                uint16_t *csum) {
426
427        void *header = NULL;
428        uint16_t ethertype;
429        uint32_t remaining;
430        uint32_t sum = 0;
431        uint8_t proto = 0;
432        uint16_t *csum_ptr = NULL;
433        int plen = 0;
434
435        uint8_t safety[65536];
436        uint8_t *ptr = safety;
437
438        header = trace_get_layer3(packet, &ethertype, &remaining);
439
440        if (header == NULL)
441                return NULL;
442       
443        if (ethertype == TRACE_ETHERTYPE_IP) {
444                libtrace_ip_t *ip = (libtrace_ip_t *)header;
445
446                if (remaining < sizeof(libtrace_ip_t))
447                        return NULL;
448
449                sum = ipv4_pseudo_checksum(ip);
450
451        } else if (ethertype == TRACE_ETHERTYPE_IPV6) {
452                libtrace_ip6_t *ip = (libtrace_ip6_t *)header;
453               
454                if (remaining < sizeof(libtrace_ip6_t))
455                        return 0;
456
457                sum = ipv6_pseudo_checksum(ip);
458       
459        }
460
461        header = trace_get_transport(packet, &proto, &remaining);
462
463        if (proto == TRACE_IPPROTO_TCP) {
464                libtrace_tcp_t *tcp = (libtrace_tcp_t *)header;
465                header = trace_get_payload_from_tcp(tcp, &remaining);
466               
467                csum_ptr = &tcp->check;
468
469                memcpy(ptr, tcp, tcp->doff * 4);
470
471                tcp = (libtrace_tcp_t *)ptr;
472                tcp->check = 0;
473
474                ptr += (tcp->doff * 4);
475        } 
476       
477        else if (proto == TRACE_IPPROTO_UDP) {
478
479                libtrace_udp_t *udp = (libtrace_udp_t *)header;
480                header = trace_get_payload_from_udp(udp, &remaining);
481               
482                csum_ptr = &udp->check;
483                memcpy(ptr, udp, sizeof(libtrace_udp_t));
484
485                udp = (libtrace_udp_t *)ptr;
486                udp->check = 0;
487
488                ptr += sizeof(libtrace_udp_t);
489        } 
490       
491        else if (proto == TRACE_IPPROTO_ICMP) {
492                /* ICMP doesn't use the pseudo header */
493                sum = 0;
494
495                libtrace_icmp_t *icmp = (libtrace_icmp_t *)header;
496                header = trace_get_payload_from_icmp(icmp, &remaining);
497               
498                csum_ptr = &icmp->checksum;
499                memcpy(ptr, icmp, sizeof(libtrace_icmp_t));
500
501                icmp = (libtrace_icmp_t *)ptr;
502                icmp->checksum = 0;
503               
504                ptr += sizeof(libtrace_icmp_t);
505
506        } 
507        else {
508                return NULL;
509        }
510
511        sum += add_checksum(safety, (uint16_t)(ptr - safety));
512
513        plen = trace_get_payload_length(packet);
514        if (plen < 0)
515                return NULL;
516
517        if (remaining < (uint32_t)plen)
518                return NULL;
519
520        if (header == NULL)
521                return NULL;
522
523        sum += add_checksum(header, (uint16_t)plen);
524        *csum = ntohs(finish_checksum(sum));
525        //assert(0);
526       
527        return csum_ptr;
528}
Note: See TracBrowser for help on using the repository browser.