source: lib/protocols_l3.c @ ee6e802

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

Updated copyright blurb on all source files

In some cases, this meant adding copyright blurbs to files that
had never had them before.

  • 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++;
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.