source: lib/protocols_l3.c @ 0277ab8

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivelibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 0277ab8 was 0277ab8, checked in by Shane Alcock <salcock@…>, 5 years ago

Completed improvement of trace_strip_packet()

  • Removed the trace_copy_packet() if the packet is not totally owned by libtrace. I think we can get away without it and we really don't want the performance hit when dealing with live captures.
  • Replaced call to trace_get_layer3 with the old header parsing code from the previous version of trace_strip_packet(). The overhead of calling trace_get_layer3 was outweighing the performance gain from the change in memmove strategy.
  • Removed ability to selectively strip VLAN or MPLS headers only -- this was not that useful and supporting it would make the code much more complex.
  • Updated trace_get_layer3 to use the cached layer 2 header if available rather than making a call to trace_get_layer2 and getting it from there. This saves us a bit of function call overhead.
  • Make sure we reset the layer 2 cached info if we shift the Ethernet header.
  • Strip PPPoE in addition to MPLS and VLAN.
  • Property mode set to 100644
File size: 20.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 <arpa/inet.h>
42
43#ifdef HAVE_NETPACKET_PACKET_H
44#include <sys/socket.h>
45#include <netpacket/packet.h>
46#include <net/ethernet.h>
47#include <net/if_arp.h>
48#include <string.h>
49#else
50#include <net/if_dl.h>
51#include <string.h>
52#endif
53
54/* This file contains all the protocol decoding functions for layer 3
55 * (the IP layer) protocols. This includes functions for accessing IP
56 * addresses.
57 *
58 * Supported protocols include:
59 *      IPv4
60 *      IPv6
61 */
62
63/* Gets an IPv4 header */
64libtrace_ip_t *trace_get_ip(libtrace_packet_t *packet) 
65{
66        uint16_t ethertype;
67        void *ret;
68
69        uint32_t remaining = trace_get_capture_length(packet);
70
71        ret = trace_get_layer3(packet,&ethertype,&remaining);
72
73        if (!ret || ethertype!=TRACE_ETHERTYPE_IP)
74                return NULL;
75
76        /* Make sure we have at least a base IPv4 header */
77        if (remaining < sizeof(libtrace_ip_t)) 
78                return NULL;
79       
80        /* Not an IPv4 packet */
81        if (((libtrace_ip_t*)ret)->ip_v != 4)
82                return NULL;
83
84        return (libtrace_ip_t*)ret;
85}
86
87libtrace_ip6_t *trace_get_ip6(libtrace_packet_t *packet) 
88{
89        uint16_t ethertype;
90        void *ret;
91
92        uint32_t remaining = trace_get_capture_length(packet);
93
94        ret = trace_get_layer3(packet,&ethertype,&remaining);
95
96        if (!ret || ethertype!=TRACE_ETHERTYPE_IPV6)
97                return NULL;
98
99        /* Make sure we have at least the base IPv6 header */
100        if (remaining < sizeof(libtrace_ip6_t))
101                return NULL;
102
103        return (libtrace_ip6_t*)ret;
104}
105
106#define SW_IP_OFFMASK 0x1fff
107
108DLLEXPORT void *trace_get_payload_from_ip(libtrace_ip_t *ipptr, uint8_t *prot,
109                uint32_t *remaining) 
110{
111        void *trans_ptr = 0;
112
113        assert(ipptr != NULL);
114       
115        /* Er? IPv5? */
116        if (ipptr->ip_v != 4)
117                return NULL;
118
119        if ((ntohs(ipptr->ip_off) & SW_IP_OFFMASK) != 0) {
120                if (remaining)
121                        *remaining = 0;         
122                return NULL;
123        }
124
125        if (remaining) {
126                if (*remaining<(ipptr->ip_hl*4U)) {
127                        *remaining = 0;
128                        return NULL;
129                }
130                /* If the packet features extra "padding", we probably
131                 * don't want that counting as possible payload, e.g. for
132                 * payload length calculations */
133                //if (*remaining > ntohs(ipptr->ip_len))
134                //      *remaining = ntohs(ipptr->ip_len);
135
136                *remaining-=(ipptr->ip_hl * 4);
137        }
138
139        trans_ptr = (void *)((char *)ipptr + (ipptr->ip_hl * 4));
140
141        if (prot) *prot = ipptr->ip_p;
142
143        return trans_ptr;
144}
145
146void *trace_get_payload_from_ip6(libtrace_ip6_t *ipptr, uint8_t *prot,
147                uint32_t *remaining) 
148{
149        void *payload = (char*)ipptr+sizeof(libtrace_ip6_t);
150        uint8_t nxt;
151        uint16_t len;
152
153        assert (ipptr != NULL);
154        nxt = ipptr->nxt;       
155        if (remaining) {
156                if (*remaining<sizeof(libtrace_ip6_t)) {
157                        *remaining = 0;
158                        return NULL;
159                }
160                *remaining-=sizeof(libtrace_ip6_t);
161        }
162
163        while(1) {
164                switch (nxt) {
165                        case 0: /* hop by hop options */
166                        case TRACE_IPPROTO_ROUTING:
167                        case TRACE_IPPROTO_AH:
168                        case TRACE_IPPROTO_DSTOPTS:
169                        {
170                                /* Length does not include the first 8 bytes */
171                                len=((libtrace_ip6_ext_t*)payload)->len * 8;
172                                len += 8;
173
174
175                                if (remaining) {
176                                        if (*remaining < len) {
177                                                /* Snap too short */
178                                                *remaining = 0;
179                                                return NULL;
180                                        }
181                                        *remaining-=len;
182                                }
183
184                                nxt=((libtrace_ip6_ext_t*)payload)->nxt;
185                                payload=(char*)payload+len;
186                                continue;
187                        }
188                        case TRACE_IPPROTO_ESP:
189                        {
190                                if (prot) *prot=TRACE_IPPROTO_ESP;
191                                return payload;
192                        }
193                        case TRACE_IPPROTO_FRAGMENT:
194                                {
195                                        len = sizeof(libtrace_ip6_frag_t);
196                                        if (remaining) {
197                                                if (*remaining < len) {
198                                                        /* Snap too short */
199                                                        *remaining = 0;
200                                                        return NULL;
201                                                }
202                                                *remaining-=len;
203                                        }
204                                        nxt=((libtrace_ip6_frag_t*)payload)->nxt;
205                                        payload=(char*)payload+len;
206                                        continue;
207                                }
208
209                        default:
210                                if (prot) *prot=nxt;
211                                return payload;
212                }
213        }
214}
215
216DLLEXPORT void *trace_get_layer3(const libtrace_packet_t *packet,
217                uint16_t *ethertype,
218                uint32_t *remaining)
219{
220        void *iphdr;
221        uint16_t dummy_ethertype;
222        void *link;
223        uint32_t dummy_remaining;
224        libtrace_linktype_t linktype;
225
226        if (!ethertype) ethertype=&dummy_ethertype;
227
228        if (!remaining) remaining=&dummy_remaining;
229
230        /* use l3 cache */
231        if (packet->l3_header)
232        {
233                /*
234                link = trace_get_packet_buffer(packet,&linktype,remaining);
235
236                if (!link)
237                        return NULL;
238                */
239
240                *ethertype = packet->l3_ethertype;
241                /* *remaining -= (packet->l3_header - link); */
242                *remaining = packet->l3_remaining;
243
244                return packet->l3_header;
245        }
246
247        if (packet->l2_header) {
248                link = packet->l2_header;
249                linktype = packet->link_type;
250                *remaining = packet->l2_remaining;
251        } else {
252                link = trace_get_layer2(packet,&linktype,remaining);
253        }
254        iphdr = trace_get_payload_from_layer2(
255                        link,
256                        linktype,
257                        ethertype,
258                        remaining);
259
260        for(;;) {
261                if (!iphdr || *remaining == 0)
262                        break;
263                switch(*ethertype) {
264                case TRACE_ETHERTYPE_8021Q: /* VLAN */
265                        iphdr=trace_get_payload_from_vlan(
266                                          iphdr,ethertype,remaining);
267                        continue;
268                case TRACE_ETHERTYPE_MPLS: /* MPLS */
269                        iphdr=trace_get_payload_from_mpls(
270                                          iphdr,ethertype,remaining);
271
272                        if (iphdr && ethertype == 0x0) {
273                                iphdr=trace_get_payload_from_ethernet(
274                                                iphdr,ethertype,remaining);
275                        }
276                        continue;
277                case TRACE_ETHERTYPE_PPP_SES: /* PPPoE */
278                        iphdr = trace_get_payload_from_pppoe(iphdr, ethertype,
279                                        remaining);
280                        continue;
281                default:
282                        break;
283                }
284
285                break;
286        }
287
288        if (!iphdr || *remaining == 0)
289                return NULL;
290
291        /* Store values in the cache for later */
292        /* Cast away constness, nasty, but this is just a cache */
293        ((libtrace_packet_t*)packet)->l3_ethertype = *ethertype;
294        ((libtrace_packet_t*)packet)->l3_header = iphdr;
295        ((libtrace_packet_t*)packet)->l3_remaining = *remaining;
296
297        return iphdr;
298}
299
300/* Parse an ip or tcp option
301 * @param[in,out] ptr   the pointer to the current option
302 * @param[in,out] len   the length of the remaining buffer
303 * @param[out] type     the type of the option
304 * @param[out] optlen   the length of the option
305 * @param[out] data     the data of the option
306 *
307 * @returns bool true if there is another option (and the fields are filled in)
308 *               or false if this was the last option.
309 *
310 * This updates ptr to point to the next option after this one, and updates
311 * len to be the number of bytes remaining in the options area.  Type is updated
312 * to be the code of this option, and data points to the data of this option,
313 * with optlen saying how many bytes there are.
314 *
315 * @note Beware of fragmented packets.
316 * @author Perry Lorier
317 */
318DLLEXPORT int trace_get_next_option(unsigned char **ptr,int *len,
319                        unsigned char *type,
320                        unsigned char *optlen,
321                        unsigned char **data)
322{
323        if (*len<=0)
324                return 0;
325        *type=**ptr;
326        switch(*type) {
327                case 0: /* End of options */
328                        return 0;
329                case 1: /* Pad */
330                        (*ptr)++;
331                        (*len)--;
332                        return 1;
333                default:
334                        *optlen = *(*ptr+1);
335                        if (*optlen<2)
336                                return 0; /* I have no idea wtf is going on
337                                           * with these packets
338                                           */
339
340                        /* Ensure that optlen is not greater than the
341                         * amount of buffer remaining */
342                        if (*optlen > *len) 
343                                return 0;
344                       
345                        (*len)-=*optlen;
346                        (*data)=(*ptr+2);
347                        (*ptr)+=*optlen;
348                        if (*len<0)
349                                return 0;
350                        return 1;
351        }
352        assert(0);
353}
354
355static char *sockaddr_to_string(struct sockaddr *addrptr, char *space,
356                int spacelen) {
357
358        assert(addrptr && space);
359        assert(spacelen > 0);
360       
361        if (addrptr->sa_family == AF_INET) {
362                struct sockaddr_in *v4 = (struct sockaddr_in *)addrptr;
363                inet_ntop(AF_INET, &(v4->sin_addr), space, spacelen);
364        }
365
366        else if (addrptr->sa_family == AF_INET6) {
367                struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addrptr;
368                inet_ntop(AF_INET6, &(v6->sin6_addr), space, spacelen);
369        }
370#ifdef HAVE_NETPACKET_PACKET_H
371        else if (addrptr->sa_family == AF_PACKET) {
372                struct sockaddr_ll *l2addr = (struct sockaddr_ll *)addrptr;
373                uint8_t *macbytes = (uint8_t *)l2addr->sll_addr;
374
375                snprintf(space, spacelen, "%02x:%02x:%02x:%02x:%02x:%02x",
376                                macbytes[0], macbytes[1], macbytes[2],
377                                macbytes[3], macbytes[4], macbytes[5]);
378
379        }
380#else
381        else if (addrptr->sa_family == AF_LINK) {
382                struct sockaddr_dl *l2addr = (struct sockaddr_dl *)addrptr;
383                uint8_t *macbytes = (uint8_t *)l2addr->sdl_data;
384
385                snprintf(space, spacelen, "%02x:%02x:%02x:%02x:%02x:%02x",
386                                macbytes[0], macbytes[1], macbytes[2],
387                                macbytes[3], macbytes[4], macbytes[5]);
388       
389        }
390#endif
391        else {
392                space[0] = '\0';
393                return NULL;
394        }
395
396        return space;
397
398}
399
400/* Extract the source mac address from a frame and bundle it up into a sockaddr */
401static struct sockaddr *get_source_ethernet_address(
402        libtrace_ether_t *ethernet, struct sockaddr *addr)
403{
404        static struct sockaddr_storage dummy;
405#ifdef HAVE_NETPACKET_PACKET_H
406/* Use linux's sockaddr_ll structure */
407        struct sockaddr_ll *l2addr;
408
409        if (addr)
410                l2addr = (struct sockaddr_ll*)addr;
411        else
412                l2addr = (struct sockaddr_ll*)&dummy;
413       
414        l2addr->sll_family = AF_PACKET;
415        l2addr->sll_protocol = ethernet->ether_type;
416        l2addr->sll_ifindex = 0; /* Irrelevant */
417        l2addr->sll_hatype = ARPHRD_ETHER; 
418        l2addr->sll_pkttype = PACKET_OTHERHOST;
419        l2addr->sll_halen = 6;
420        memcpy(l2addr->sll_addr,ethernet->ether_shost, 6);
421
422        return (struct sockaddr*)l2addr;
423#else
424/* Use BSD's sockaddr_dl structure */
425        struct sockaddr_dl *l2addr;
426
427        if (addr)
428                l2addr = (struct sockaddr_dl *)addr;
429        else
430                l2addr = (struct sockaddr_dl *)&dummy;
431       
432        l2addr->sdl_family = AF_LINK;
433#if HAVE_SDL_LEN == 1
434        l2addr->sdl_len = sizeof(struct sockaddr_dl);
435#endif
436        l2addr->sdl_index = 0; /* Unused */
437        l2addr->sdl_alen = 6; /* Address length  */
438        l2addr->sdl_nlen = 0; /* No name in here - this *should* work, right? */
439        l2addr->sdl_slen = 0;   
440        l2addr->sdl_type = 0; /* Hopefully zero is OK for this value too */
441        memcpy(l2addr->sdl_data, ethernet->ether_shost, 6);
442
443        return (struct sockaddr *)l2addr;
444#endif
445}
446
447static struct sockaddr *get_source_l2_address(
448        const libtrace_packet_t *packet, struct sockaddr *addr)
449{
450        static struct sockaddr_storage dummy;
451        void *l2;
452        libtrace_linktype_t linktype;
453        uint32_t remaining;
454
455        if (!addr)
456                addr =(struct sockaddr*)&dummy;
457
458        l2=trace_get_layer2(packet, &linktype, &remaining);
459        if (!l2) {
460                return NULL;
461        }
462
463        switch (linktype) {
464                case TRACE_TYPE_ETH:
465                        return get_source_ethernet_address((libtrace_ether_t*)l2, addr);
466                default:
467                        return NULL;
468        }
469}
470
471DLLEXPORT struct sockaddr *trace_get_source_address(
472                const libtrace_packet_t *packet, struct sockaddr *addr)
473{
474        uint16_t ethertype;
475        uint32_t remaining;
476        void *l3;
477        struct ports_t *ports;
478        static struct sockaddr_storage dummy;
479
480        if (!addr)
481                addr=(struct sockaddr*)&dummy;
482
483        l3 = trace_get_layer3(packet,&ethertype,&remaining);
484
485        if (!l3)
486                return get_source_l2_address(packet,addr);
487
488        switch (ethertype) {
489                case TRACE_ETHERTYPE_IP: /* IPv4 */
490                {
491                        struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
492                        libtrace_ip_t *ip = (libtrace_ip_t*)l3;
493                        ports = (struct ports_t*)
494                                trace_get_payload_from_ip(ip,NULL,&remaining);
495                        addr4->sin_family=AF_INET;
496                        if (ports && remaining>=sizeof(*ports))
497                                addr4->sin_port=ports->src;
498                        else
499                                addr4->sin_port=0;
500                        addr4->sin_addr=ip->ip_src;
501                        return addr;
502                }
503                case TRACE_ETHERTYPE_IPV6: /* IPv6 */
504                {
505                        struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
506                        libtrace_ip6_t *ip6 = (libtrace_ip6_t*)l3;
507                        ports = (struct ports_t*)
508                                trace_get_payload_from_ip6(ip6,NULL,&remaining);
509                        addr6->sin6_family=AF_INET6;
510                        if (ports && remaining>=sizeof(*ports))
511                                addr6->sin6_port=ports->src;
512                        else
513                                addr6->sin6_port=0;
514                        addr6->sin6_flowinfo=0;
515                        addr6->sin6_addr=ip6->ip_src;
516                        addr6->sin6_scope_id = 0;
517                        return addr;
518                }
519                default:
520                        return get_source_l2_address(packet, addr);
521        }
522}
523
524
525DLLEXPORT char *trace_get_source_address_string(
526                const libtrace_packet_t *packet, char *space, int spacelen) {
527
528        static char staticspace[INET6_ADDRSTRLEN];
529        struct sockaddr_storage addr;
530        struct sockaddr *addrptr;
531       
532
533        if (space == NULL || spacelen == 0) {
534                space = staticspace;
535                spacelen = INET6_ADDRSTRLEN;
536        }
537
538        addrptr = trace_get_source_address(packet, (struct sockaddr *)&addr);
539
540        if (addrptr == NULL)
541                return NULL;
542       
543        return sockaddr_to_string(addrptr, space, spacelen);
544}
545
546static struct sockaddr *get_destination_ethernet_address(
547        libtrace_ether_t *ethernet, struct sockaddr *addr)
548{
549        static struct sockaddr_storage dummy;
550#ifdef HAVE_NETPACKET_PACKET_H
551/* Use linux's sockaddr_ll structure */
552        struct sockaddr_ll *l2addr;
553        if (addr)
554                l2addr = (struct sockaddr_ll*)addr;
555        else
556                l2addr = (struct sockaddr_ll*)&dummy;
557       
558        l2addr->sll_family = AF_PACKET;
559        l2addr->sll_protocol = ethernet->ether_type;
560        l2addr->sll_ifindex = 0; /* Irrelevant */
561        l2addr->sll_hatype = ARPHRD_ETHER; 
562        l2addr->sll_pkttype = PACKET_OTHERHOST;
563        l2addr->sll_halen = 6;
564        memcpy(l2addr->sll_addr,ethernet->ether_dhost, 6);
565
566        return (struct sockaddr*)l2addr;
567#else
568/* Use BSD's sockaddr_dl structure */
569        struct sockaddr_dl *l2addr;
570
571        if (addr)
572                l2addr = (struct sockaddr_dl *)addr;
573        else
574                l2addr = (struct sockaddr_dl *)&dummy;
575       
576        l2addr->sdl_family = AF_LINK;
577#if HAVE_SDL_LEN == 1
578        l2addr->sdl_len = sizeof(struct sockaddr_dl);
579#endif
580        l2addr->sdl_index = 0; /* Unused */
581        l2addr->sdl_alen = 6; /* Address length  */
582        l2addr->sdl_nlen = 0; /* No name in here - this *should* work, right? */
583        l2addr->sdl_slen = 0;   
584        l2addr->sdl_type = 0; /* Hopefully zero is OK for this value too */
585        memcpy(l2addr->sdl_data, ethernet->ether_dhost, 6);
586
587        return (struct sockaddr *)l2addr;
588#endif
589}
590
591static struct sockaddr *get_destination_l2_address(
592        const libtrace_packet_t *packet, struct sockaddr *addr)
593{
594        static struct sockaddr_storage dummy;
595        void *l2;
596        libtrace_linktype_t linktype;
597        uint32_t remaining;
598        if (!addr)
599                addr =(struct sockaddr*)&dummy;
600        l2=trace_get_layer2(packet, &linktype, &remaining);
601        if (!l2)
602                return NULL;
603
604        switch (linktype) {
605                case TRACE_TYPE_ETH:
606                        return get_destination_ethernet_address((libtrace_ether_t*)l2, addr);
607                default:
608                        return NULL;
609        }
610}
611
612DLLEXPORT struct sockaddr *trace_get_destination_address(
613                const libtrace_packet_t *packet, struct sockaddr *addr)
614{
615        uint16_t ethertype;
616        uint32_t remaining;
617        void *l3;
618        struct ports_t *ports;
619        static struct sockaddr_storage dummy;
620
621        if (!addr)
622                addr=(struct sockaddr*)&dummy;
623
624        l3 = trace_get_layer3(packet,&ethertype,&remaining);
625
626        if (!l3)
627                return get_destination_l2_address(packet,addr);
628
629        switch (ethertype) {
630                case TRACE_ETHERTYPE_IP: /* IPv4 */
631                {
632                        struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
633                        libtrace_ip_t *ip = (libtrace_ip_t*)l3;
634                        ports = (struct ports_t*)
635                                trace_get_payload_from_ip(ip,NULL,&remaining);
636                        addr4->sin_family=AF_INET;
637                        if (ports && remaining>=sizeof(*ports))
638                                addr4->sin_port=ports->dst;
639                        else
640                                addr4->sin_port=0;
641                        addr4->sin_addr=ip->ip_dst;
642                        return addr;
643                }
644                case TRACE_ETHERTYPE_IPV6: /* IPv6 */
645                {
646                        struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
647                        libtrace_ip6_t *ip6 = (libtrace_ip6_t*)l3;
648                        ports = (struct ports_t*)
649                                trace_get_payload_from_ip6(ip6,NULL,&remaining);
650                        addr6->sin6_family=AF_INET6;
651                        if (ports && remaining>=sizeof(*ports))
652                                addr6->sin6_port=ports->dst;
653                        else
654                                addr6->sin6_port=0;
655                        addr6->sin6_flowinfo=0;
656                        addr6->sin6_addr=ip6->ip_dst;
657                        return addr;
658                }
659                default:
660                        return get_destination_l2_address(packet, addr);
661        }
662}
663
664DLLEXPORT char *trace_get_destination_address_string(
665                const libtrace_packet_t *packet, char *space, int spacelen) {
666
667        struct sockaddr_storage addr;
668        struct sockaddr *addrptr;
669       
670        static char staticspace[INET6_ADDRSTRLEN];
671
672        if (space == NULL || spacelen == 0) {
673                space = staticspace;
674                spacelen = INET6_ADDRSTRLEN;
675        }
676
677        addrptr = trace_get_destination_address(packet, 
678                        (struct sockaddr *)&addr);
679
680        if (addrptr == NULL)
681                return NULL;
682       
683        return sockaddr_to_string(addrptr, space, spacelen);
684}
685
686DLLEXPORT uint16_t *trace_checksum_layer3(libtrace_packet_t *packet, 
687                uint16_t *csum) {
688
689        void *l3;
690        uint16_t ethertype;
691        uint32_t remaining;
692        uint16_t *csum_ptr;
693
694        uint8_t safety[65536];
695
696        if (csum == NULL)
697                return NULL;
698       
699        l3 = trace_get_layer3(packet, &ethertype, &remaining);
700               
701        if (l3 == NULL)
702                return NULL;
703       
704        if (ethertype == TRACE_ETHERTYPE_IP) {
705                libtrace_ip_t *ip = (libtrace_ip_t *)l3;
706                if (remaining < sizeof(libtrace_ip_t))
707                        return NULL;
708
709                csum_ptr = &ip->ip_sum;
710
711                /* I hate memcpys, but this is the only truly safe way to
712                 * do this without modifying the packet. I'm trying to be
713                 * careful about not creating any more thread-safety issues
714                 * than there already are :) */
715                memcpy(safety, ip, ip->ip_hl * sizeof(uint32_t));
716               
717                /* Set the checksum to zero, so we can do the calculation */
718                ip = (libtrace_ip_t *)safety;
719                ip->ip_sum = 0;
720
721                *csum = checksum_buffer(safety, ip->ip_hl * sizeof(uint32_t));
722               
723                /* Remember to byteswap appropriately */
724                *csum = ntohs(*csum);
725               
726                return csum_ptr;
727        }
728
729        return NULL;
730}
731
732DLLEXPORT uint16_t trace_get_fragment_offset(const libtrace_packet_t *packet, 
733                uint8_t *more) {
734
735        void *l3;
736        uint16_t ethertype;
737        uint32_t remaining;
738
739        *more = 0;
740
741        l3 = trace_get_layer3(packet, &ethertype, &remaining);
742        if (l3 == NULL)
743                return 0;
744
745        if (ethertype == TRACE_ETHERTYPE_IP) {
746                libtrace_ip_t *ip = (libtrace_ip_t *)l3;
747                uint16_t offset = 0;
748
749                /* Fragment offset appears in 7th and 8th bytes */
750                if (remaining < 8)
751                        return 0;
752                 
753                offset = ntohs(ip->ip_off);
754
755                if ((offset & 0x2000) != 0)
756                        *more = 1;
757                return (offset & 0x1FFF) * 8;
758        }
759
760        if (ethertype == TRACE_ETHERTYPE_IPV6) {
761                libtrace_ip6_t *ip6 = (libtrace_ip6_t *)l3;
762                void *payload = ip6++;
763                uint8_t nxt = ip6->nxt;
764                uint16_t len;
765               
766                /* First task, find a Fragment header if present */
767                if (remaining < sizeof(libtrace_ip6_t))
768                        return 0;
769                remaining -= sizeof(libtrace_ip6_t);
770
771                /* Adapted from trace_get_payload_from_ip6 */
772                while (1) {
773                        switch (nxt) {
774                        case 0:
775                        case TRACE_IPPROTO_ROUTING:
776                        case TRACE_IPPROTO_AH:
777                        case TRACE_IPPROTO_DSTOPTS:
778                        {
779
780                                /* Length does not include the first 8 bytes */
781                                len=((libtrace_ip6_ext_t*)payload)->len * 8;
782                                len += 8;
783
784                                if (remaining < len) {
785                                        /* Snap too short */
786                                        return 0;
787                                }
788                                remaining-=len;
789
790                                nxt=((libtrace_ip6_ext_t*)payload)->nxt;
791                                continue;
792                        }
793                        case TRACE_IPPROTO_FRAGMENT:
794                        {
795                                libtrace_ip6_frag_t *frag = (libtrace_ip6_frag_t *)payload;
796                                uint16_t offset;
797                                len = sizeof(libtrace_ip6_frag_t);
798                                if (remaining < len) {
799                                        /* Snap too short */
800                                        return 0;
801                                }
802                                remaining-=len;
803
804                                offset = ntohs(frag->frag_off);
805                                if ((offset & 0x0001) != 0) 
806                                        *more = 1;
807
808                                return ((offset & 0xFFF8) >> 3) * 8;
809                         }
810                         default:
811                                return 0;
812                         }
813                }
814
815        }
816        return 0;
817}
Note: See TracBrowser for help on using the repository browser.