source: lib/protocols_l3.c @ 2193905

develop
Last change on this file since 2193905 was 2193905, checked in by Jacob Van Walraven <jcv9@…>, 2 years ago

Apply changes required for pull request #81

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