source: lib/protocols_l3.c @ 7baa948

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragofflibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 7baa948 was 7baa948, checked in by Shane Alcock <salcock@…>, 6 years ago

Added trace_get_fragment_offset to API

New function performs all the bit-shifting, masking,
multiplying and (in the case of IPv6) header skipping necessary to
work out the fragment offset for a packet, in bytes.

Fixed trace_get_source_port and trace_get_destination_port so
that they do not try to lookup port numbers if the packet is
not the first fragment.

IPv6 fragment offsets probably need more testing.

  • Property mode set to 100644
File size: 20.1 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        link = trace_get_layer2(packet,&linktype,remaining);
248        iphdr = trace_get_payload_from_layer2(
249                        link,
250                        linktype,
251                        ethertype,
252                        remaining);
253
254        for(;;) {
255                if (!iphdr || *remaining == 0)
256                        break;
257                switch(*ethertype) {
258                case TRACE_ETHERTYPE_8021Q: /* VLAN */
259                        iphdr=trace_get_payload_from_vlan(
260                                          iphdr,ethertype,remaining);
261                        continue;
262                case TRACE_ETHERTYPE_MPLS: /* MPLS */
263                        iphdr=trace_get_payload_from_mpls(
264                                          iphdr,ethertype,remaining);
265
266                        if (iphdr && ethertype == 0x0) {
267                                iphdr=trace_get_payload_from_ethernet(
268                                                iphdr,ethertype,remaining);
269                        }
270                        continue;
271                case TRACE_ETHERTYPE_PPP_SES: /* PPPoE */
272                        iphdr = trace_get_payload_from_pppoe(iphdr, ethertype,
273                                        remaining);
274                        continue;
275                default:
276                        break;
277                }
278
279                break;
280        }
281
282        if (!iphdr || *remaining == 0)
283                return NULL;
284
285        /* Store values in the cache for later */
286        /* Cast away constness, nasty, but this is just a cache */
287        ((libtrace_packet_t*)packet)->l3_ethertype = *ethertype;
288        ((libtrace_packet_t*)packet)->l3_header = iphdr;
289        ((libtrace_packet_t*)packet)->l3_remaining = *remaining;
290
291        return iphdr;
292}
293
294/* Parse an ip or tcp option
295 * @param[in,out] ptr   the pointer to the current option
296 * @param[in,out] len   the length of the remaining buffer
297 * @param[out] type     the type of the option
298 * @param[out] optlen   the length of the option
299 * @param[out] data     the data of the option
300 *
301 * @returns bool true if there is another option (and the fields are filled in)
302 *               or false if this was the last option.
303 *
304 * This updates ptr to point to the next option after this one, and updates
305 * len to be the number of bytes remaining in the options area.  Type is updated
306 * to be the code of this option, and data points to the data of this option,
307 * with optlen saying how many bytes there are.
308 *
309 * @note Beware of fragmented packets.
310 * @author Perry Lorier
311 */
312DLLEXPORT int trace_get_next_option(unsigned char **ptr,int *len,
313                        unsigned char *type,
314                        unsigned char *optlen,
315                        unsigned char **data)
316{
317        if (*len<=0)
318                return 0;
319        *type=**ptr;
320        switch(*type) {
321                case 0: /* End of options */
322                        return 0;
323                case 1: /* Pad */
324                        (*ptr)++;
325                        (*len)--;
326                        return 1;
327                default:
328                        *optlen = *(*ptr+1);
329                        if (*optlen<2)
330                                return 0; /* I have no idea wtf is going on
331                                           * with these packets
332                                           */
333
334                        /* Ensure that optlen is not greater than the
335                         * amount of buffer remaining */
336                        if (*optlen > *len) 
337                                return 0;
338                       
339                        (*len)-=*optlen;
340                        (*data)=(*ptr+2);
341                        (*ptr)+=*optlen;
342                        if (*len<0)
343                                return 0;
344                        return 1;
345        }
346        assert(0);
347}
348
349static char *sockaddr_to_string(struct sockaddr *addrptr, char *space,
350                int spacelen) {
351
352        assert(addrptr && space);
353        assert(spacelen > 0);
354       
355        if (addrptr->sa_family == AF_INET) {
356                struct sockaddr_in *v4 = (struct sockaddr_in *)addrptr;
357                inet_ntop(AF_INET, &(v4->sin_addr), space, spacelen);
358        }
359
360        else if (addrptr->sa_family == AF_INET6) {
361                struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addrptr;
362                inet_ntop(AF_INET6, &(v6->sin6_addr), space, spacelen);
363        }
364#ifdef HAVE_NETPACKET_PACKET_H
365        else if (addrptr->sa_family == AF_PACKET) {
366                struct sockaddr_ll *l2addr = (struct sockaddr_ll *)addrptr;
367                uint8_t *macbytes = (uint8_t *)l2addr->sll_addr;
368
369                snprintf(space, spacelen, "%02x:%02x:%02x:%02x:%02x:%02x",
370                                macbytes[0], macbytes[1], macbytes[2],
371                                macbytes[3], macbytes[4], macbytes[5]);
372
373        }
374#else
375        else if (addrptr->sa_family == AF_LINK) {
376                struct sockaddr_dl *l2addr = (struct sockaddr_dl *)addrptr;
377                uint8_t *macbytes = (uint8_t *)l2addr->sdl_data;
378
379                snprintf(space, spacelen, "%02x:%02x:%02x:%02x:%02x:%02x",
380                                macbytes[0], macbytes[1], macbytes[2],
381                                macbytes[3], macbytes[4], macbytes[5]);
382       
383        }
384#endif
385        else {
386                space[0] = '\0';
387                return NULL;
388        }
389
390        return space;
391
392}
393
394/* Extract the source mac address from a frame and bundle it up into a sockaddr */
395static struct sockaddr *get_source_ethernet_address(
396        libtrace_ether_t *ethernet, struct sockaddr *addr)
397{
398        static struct sockaddr_storage dummy;
399#ifdef HAVE_NETPACKET_PACKET_H
400/* Use linux's sockaddr_ll structure */
401        struct sockaddr_ll *l2addr;
402
403        if (addr)
404                l2addr = (struct sockaddr_ll*)addr;
405        else
406                l2addr = (struct sockaddr_ll*)&dummy;
407       
408        l2addr->sll_family = AF_PACKET;
409        l2addr->sll_protocol = ethernet->ether_type;
410        l2addr->sll_ifindex = 0; /* Irrelevant */
411        l2addr->sll_hatype = ARPHRD_ETHER; 
412        l2addr->sll_pkttype = PACKET_OTHERHOST;
413        l2addr->sll_halen = 6;
414        memcpy(l2addr->sll_addr,ethernet->ether_shost, 6);
415
416        return (struct sockaddr*)l2addr;
417#else
418/* Use BSD's sockaddr_dl structure */
419        struct sockaddr_dl *l2addr;
420
421        if (addr)
422                l2addr = (struct sockaddr_dl *)addr;
423        else
424                l2addr = (struct sockaddr_dl *)&dummy;
425       
426        l2addr->sdl_family = AF_LINK;
427#if HAVE_SDL_LEN == 1
428        l2addr->sdl_len = sizeof(struct sockaddr_dl);
429#endif
430        l2addr->sdl_index = 0; /* Unused */
431        l2addr->sdl_alen = 6; /* Address length  */
432        l2addr->sdl_nlen = 0; /* No name in here - this *should* work, right? */
433        l2addr->sdl_slen = 0;   
434        l2addr->sdl_type = 0; /* Hopefully zero is OK for this value too */
435        memcpy(l2addr->sdl_data, ethernet->ether_shost, 6);
436
437        return (struct sockaddr *)l2addr;
438#endif
439}
440
441static struct sockaddr *get_source_l2_address(
442        const libtrace_packet_t *packet, struct sockaddr *addr)
443{
444        static struct sockaddr_storage dummy;
445        void *l2;
446        libtrace_linktype_t linktype;
447        uint32_t remaining;
448
449        if (!addr)
450                addr =(struct sockaddr*)&dummy;
451
452        l2=trace_get_layer2(packet, &linktype, &remaining);
453        if (!l2) {
454                return NULL;
455        }
456
457        switch (linktype) {
458                case TRACE_TYPE_ETH:
459                        return get_source_ethernet_address((libtrace_ether_t*)l2, addr);
460                default:
461                        return NULL;
462        }
463}
464
465DLLEXPORT struct sockaddr *trace_get_source_address(
466                const libtrace_packet_t *packet, struct sockaddr *addr)
467{
468        uint16_t ethertype;
469        uint32_t remaining;
470        void *l3;
471        struct ports_t *ports;
472        static struct sockaddr_storage dummy;
473
474        if (!addr)
475                addr=(struct sockaddr*)&dummy;
476
477        l3 = trace_get_layer3(packet,&ethertype,&remaining);
478
479        if (!l3)
480                return get_source_l2_address(packet,addr);
481
482        switch (ethertype) {
483                case TRACE_ETHERTYPE_IP: /* IPv4 */
484                {
485                        struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
486                        libtrace_ip_t *ip = (libtrace_ip_t*)l3;
487                        ports = (struct ports_t*)
488                                trace_get_payload_from_ip(ip,NULL,&remaining);
489                        addr4->sin_family=AF_INET;
490                        if (ports && remaining>=sizeof(*ports))
491                                addr4->sin_port=ports->src;
492                        else
493                                addr4->sin_port=0;
494                        addr4->sin_addr=ip->ip_src;
495                        return addr;
496                }
497                case TRACE_ETHERTYPE_IPV6: /* IPv6 */
498                {
499                        struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
500                        libtrace_ip6_t *ip6 = (libtrace_ip6_t*)l3;
501                        ports = (struct ports_t*)
502                                trace_get_payload_from_ip6(ip6,NULL,&remaining);
503                        addr6->sin6_family=AF_INET6;
504                        if (ports && remaining>=sizeof(*ports))
505                                addr6->sin6_port=ports->src;
506                        else
507                                addr6->sin6_port=0;
508                        addr6->sin6_flowinfo=0;
509                        addr6->sin6_addr=ip6->ip_src;
510                        addr6->sin6_scope_id = 0;
511                        return addr;
512                }
513                default:
514                        return get_source_l2_address(packet, addr);
515        }
516}
517
518
519DLLEXPORT char *trace_get_source_address_string(
520                const libtrace_packet_t *packet, char *space, int spacelen) {
521
522        static char staticspace[INET6_ADDRSTRLEN];
523        struct sockaddr_storage addr;
524        struct sockaddr *addrptr;
525       
526
527        if (space == NULL || spacelen == 0) {
528                space = staticspace;
529                spacelen = INET6_ADDRSTRLEN;
530        }
531
532        addrptr = trace_get_source_address(packet, (struct sockaddr *)&addr);
533
534        if (addrptr == NULL)
535                return NULL;
536       
537        return sockaddr_to_string(addrptr, space, spacelen);
538}
539
540static struct sockaddr *get_destination_ethernet_address(
541        libtrace_ether_t *ethernet, struct sockaddr *addr)
542{
543        static struct sockaddr_storage dummy;
544#ifdef HAVE_NETPACKET_PACKET_H
545/* Use linux's sockaddr_ll structure */
546        struct sockaddr_ll *l2addr;
547        if (addr)
548                l2addr = (struct sockaddr_ll*)addr;
549        else
550                l2addr = (struct sockaddr_ll*)&dummy;
551       
552        l2addr->sll_family = AF_PACKET;
553        l2addr->sll_protocol = ethernet->ether_type;
554        l2addr->sll_ifindex = 0; /* Irrelevant */
555        l2addr->sll_hatype = ARPHRD_ETHER; 
556        l2addr->sll_pkttype = PACKET_OTHERHOST;
557        l2addr->sll_halen = 6;
558        memcpy(l2addr->sll_addr,ethernet->ether_dhost, 6);
559
560        return (struct sockaddr*)l2addr;
561#else
562/* Use BSD's sockaddr_dl structure */
563        struct sockaddr_dl *l2addr;
564
565        if (addr)
566                l2addr = (struct sockaddr_dl *)addr;
567        else
568                l2addr = (struct sockaddr_dl *)&dummy;
569       
570        l2addr->sdl_family = AF_LINK;
571#if HAVE_SDL_LEN == 1
572        l2addr->sdl_len = sizeof(struct sockaddr_dl);
573#endif
574        l2addr->sdl_index = 0; /* Unused */
575        l2addr->sdl_alen = 6; /* Address length  */
576        l2addr->sdl_nlen = 0; /* No name in here - this *should* work, right? */
577        l2addr->sdl_slen = 0;   
578        l2addr->sdl_type = 0; /* Hopefully zero is OK for this value too */
579        memcpy(l2addr->sdl_data, ethernet->ether_dhost, 6);
580
581        return (struct sockaddr *)l2addr;
582#endif
583}
584
585static struct sockaddr *get_destination_l2_address(
586        const libtrace_packet_t *packet, struct sockaddr *addr)
587{
588        static struct sockaddr_storage dummy;
589        void *l2;
590        libtrace_linktype_t linktype;
591        uint32_t remaining;
592        if (!addr)
593                addr =(struct sockaddr*)&dummy;
594        l2=trace_get_layer2(packet, &linktype, &remaining);
595        if (!l2)
596                return NULL;
597
598        switch (linktype) {
599                case TRACE_TYPE_ETH:
600                        return get_destination_ethernet_address((libtrace_ether_t*)l2, addr);
601                default:
602                        return NULL;
603        }
604}
605
606DLLEXPORT struct sockaddr *trace_get_destination_address(
607                const libtrace_packet_t *packet, struct sockaddr *addr)
608{
609        uint16_t ethertype;
610        uint32_t remaining;
611        void *l3;
612        struct ports_t *ports;
613        static struct sockaddr_storage dummy;
614
615        if (!addr)
616                addr=(struct sockaddr*)&dummy;
617
618        l3 = trace_get_layer3(packet,&ethertype,&remaining);
619
620        if (!l3)
621                return get_destination_l2_address(packet,addr);
622
623        switch (ethertype) {
624                case TRACE_ETHERTYPE_IP: /* IPv4 */
625                {
626                        struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
627                        libtrace_ip_t *ip = (libtrace_ip_t*)l3;
628                        ports = (struct ports_t*)
629                                trace_get_payload_from_ip(ip,NULL,&remaining);
630                        addr4->sin_family=AF_INET;
631                        if (ports && remaining>=sizeof(*ports))
632                                addr4->sin_port=ports->dst;
633                        else
634                                addr4->sin_port=0;
635                        addr4->sin_addr=ip->ip_dst;
636                        return addr;
637                }
638                case TRACE_ETHERTYPE_IPV6: /* IPv6 */
639                {
640                        struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
641                        libtrace_ip6_t *ip6 = (libtrace_ip6_t*)l3;
642                        ports = (struct ports_t*)
643                                trace_get_payload_from_ip6(ip6,NULL,&remaining);
644                        addr6->sin6_family=AF_INET6;
645                        if (ports && remaining>=sizeof(*ports))
646                                addr6->sin6_port=ports->dst;
647                        else
648                                addr6->sin6_port=0;
649                        addr6->sin6_flowinfo=0;
650                        addr6->sin6_addr=ip6->ip_dst;
651                        return addr;
652                }
653                default:
654                        return get_destination_l2_address(packet, addr);
655        }
656}
657
658DLLEXPORT char *trace_get_destination_address_string(
659                const libtrace_packet_t *packet, char *space, int spacelen) {
660
661        struct sockaddr_storage addr;
662        struct sockaddr *addrptr;
663       
664        static char staticspace[INET6_ADDRSTRLEN];
665
666        if (space == NULL || spacelen == 0) {
667                space = staticspace;
668                spacelen = INET6_ADDRSTRLEN;
669        }
670
671        addrptr = trace_get_destination_address(packet, 
672                        (struct sockaddr *)&addr);
673
674        if (addrptr == NULL)
675                return NULL;
676       
677        return sockaddr_to_string(addrptr, space, spacelen);
678}
679
680DLLEXPORT uint16_t *trace_checksum_layer3(libtrace_packet_t *packet, 
681                uint16_t *csum) {
682
683        void *l3;
684        uint16_t ethertype;
685        uint32_t remaining;
686        uint16_t *csum_ptr;
687
688        uint8_t safety[65536];
689
690        if (csum == NULL)
691                return NULL;
692       
693        l3 = trace_get_layer3(packet, &ethertype, &remaining);
694               
695        if (l3 == NULL)
696                return NULL;
697       
698        if (ethertype == TRACE_ETHERTYPE_IP) {
699                libtrace_ip_t *ip = (libtrace_ip_t *)l3;
700                if (remaining < sizeof(libtrace_ip_t))
701                        return NULL;
702
703                csum_ptr = &ip->ip_sum;
704
705                /* I hate memcpys, but this is the only truly safe way to
706                 * do this without modifying the packet. I'm trying to be
707                 * careful about not creating any more thread-safety issues
708                 * than there already are :) */
709                memcpy(safety, ip, ip->ip_hl * sizeof(uint32_t));
710               
711                /* Set the checksum to zero, so we can do the calculation */
712                ip = (libtrace_ip_t *)safety;
713                ip->ip_sum = 0;
714
715                *csum = checksum_buffer(safety, ip->ip_hl * sizeof(uint32_t));
716               
717                /* Remember to byteswap appropriately */
718                *csum = ntohs(*csum);
719               
720                return csum_ptr;
721        }
722
723        return NULL;
724}
725
726DLLEXPORT uint16_t trace_get_fragment_offset(const libtrace_packet_t *packet, 
727                uint8_t *more) {
728
729        void *l3;
730        uint16_t ethertype;
731        uint32_t remaining;
732
733        *more = 0;
734
735        l3 = trace_get_layer3(packet, &ethertype, &remaining);
736        if (l3 == NULL)
737                return 0;
738
739        if (ethertype == TRACE_ETHERTYPE_IP) {
740                libtrace_ip_t *ip = (libtrace_ip_t *)l3;
741                uint16_t offset = 0;
742
743                /* Fragment offset appears in 7th and 8th bytes */
744                if (remaining < 8)
745                        return 0;
746                 
747                offset = ntohs(ip->ip_off);
748
749                if ((offset & 0x2000) != 0)
750                        *more = 1;
751                return (offset & 0x1FFF) * 8;
752        }
753
754        if (ethertype == TRACE_ETHERTYPE_IPV6) {
755                libtrace_ip6_t *ip6 = (libtrace_ip6_t *)l3;
756                void *payload = ip6++;
757                uint8_t nxt = ip6->nxt;
758                uint16_t len;
759               
760                /* First task, find a Fragment header if present */
761                if (remaining < sizeof(libtrace_ip6_t))
762                        return 0;
763                remaining -= sizeof(libtrace_ip6_t);
764
765                /* Adapted from trace_get_payload_from_ip6 */
766                while (1) {
767                        switch (nxt) {
768                        case 0:
769                        case TRACE_IPPROTO_ROUTING:
770                        case TRACE_IPPROTO_AH:
771                        case TRACE_IPPROTO_DSTOPTS:
772                        {
773
774                                /* Length does not include the first 8 bytes */
775                                len=((libtrace_ip6_ext_t*)payload)->len * 8;
776                                len += 8;
777
778                                if (remaining < len) {
779                                        /* Snap too short */
780                                        return 0;
781                                }
782                                remaining-=len;
783
784                                nxt=((libtrace_ip6_ext_t*)payload)->nxt;
785                                continue;
786                        }
787                        case TRACE_IPPROTO_FRAGMENT:
788                        {
789                                libtrace_ip6_frag_t *frag = (libtrace_ip6_frag_t *)payload;
790                                uint16_t offset;
791                                len = sizeof(libtrace_ip6_frag_t);
792                                if (remaining < len) {
793                                        /* Snap too short */
794                                        return 0;
795                                }
796                                remaining-=len;
797
798                                offset = ntohs(frag->frag_off);
799                                if ((offset & 0x0001) != 0) 
800                                        *more = 1;
801
802                                return ((offset & 0xFFF8) >> 3) * 8;
803                         }
804                         default:
805                                return 0;
806                         }
807                }
808
809        }
810        return 0;
811}
Note: See TracBrowser for help on using the repository browser.