source: lib/protocols_l3.c @ 5732e9b

cachetimestampsdevelopdpdk-ndagetsiliverc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformance
Last change on this file since 5732e9b was 5732e9b, checked in by Shane Alcock <salcock@…>, 4 years ago

Fix bad IPv6 fragment offset calculation.

This has been horribly broken the whole time, but we generally got
lucky and fell through to the default "no fragmentation" case.
Since nobody uses IPv6 fragmentation, this seemed to be giving the
correct result.

Of course, on the odd occasion we'd accidentally treat a packet as
a fragment incorrectly and therefore trace_get_source_port() etc
would fail -- this was a bit more problematic :)

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