source: lib/protocols_transport.c @ c909fad

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