source: lib/protocols_l3.c @ d247823

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since d247823 was d247823, checked in by Shane Alcock <salcock@…>, 10 years ago
  • Fixed bug in trace_get_payload_from_ip6 where we were incorrectly calculating the length of any extension headers that were present - for some silly reason, the first 8 bytes are not included in the length field. Thanks to Rong Zheng for reporting this bug (#314).
  • Property mode set to 100644
File size: 13.7 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 <assert.h>
39#include <stdlib.h>
40
41#ifdef HAVE_NETPACKET_PACKET_H
42#include <sys/socket.h>
43#include <netpacket/packet.h>
44#include <net/ethernet.h>
45#include <net/if_arp.h>
46#include <string.h>
47#else
48#include <net/if_dl.h>
49#include <string.h>
50#endif
51
52/* This file contains all the protocol decoding functions for layer 3
53 * (the IP layer) protocols. This includes functions for accessing IP
54 * addresses.
55 *
56 * Supported protocols include:
57 *      IPv4
58 *      IPv6
59 */
60
61/* Gets an IPv4 header */
62libtrace_ip_t *trace_get_ip(libtrace_packet_t *packet) 
63{
64        uint16_t ethertype;
65        void *ret;
66
67        uint32_t remaining = trace_get_capture_length(packet);
68
69        ret = trace_get_layer3(packet,&ethertype,&remaining);
70
71        if (!ret || ethertype!=TRACE_ETHERTYPE_IP)
72                return NULL;
73
74        /* Make sure we have at least a base IPv4 header */
75        if (remaining < sizeof(libtrace_ip_t)) 
76                return NULL;
77       
78        /* Not an IPv4 packet */
79        if (((libtrace_ip_t*)ret)->ip_v != 4)
80                return NULL;
81
82        return (libtrace_ip_t*)ret;
83}
84
85libtrace_ip6_t *trace_get_ip6(libtrace_packet_t *packet) 
86{
87        uint16_t ethertype;
88        void *ret;
89
90        uint32_t remaining = trace_get_capture_length(packet);
91
92        ret = trace_get_layer3(packet,&ethertype,&remaining);
93
94        if (!ret || ethertype!=TRACE_ETHERTYPE_IPV6)
95                return NULL;
96
97        /* Make sure we have at least the base IPv6 header */
98        if (remaining < sizeof(libtrace_ip6_t))
99                return NULL;
100
101        return (libtrace_ip6_t*)ret;
102}
103
104#define SW_IP_OFFMASK 0x1fff
105
106DLLEXPORT void *trace_get_payload_from_ip(libtrace_ip_t *ipptr, uint8_t *prot,
107                uint32_t *remaining) 
108{
109        void *trans_ptr = 0;
110
111        assert(ipptr != NULL);
112       
113        /* Er? IPv5? */
114        if (ipptr->ip_v != 4)
115                return NULL;
116
117        if ((ntohs(ipptr->ip_off) & SW_IP_OFFMASK) != 0) {
118                if (remaining)
119                        *remaining = 0;         
120                return NULL;
121        }
122
123        if (remaining) {
124                if (*remaining<(ipptr->ip_hl*4U)) {
125                        *remaining = 0;
126                        return NULL;
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                link = trace_get_packet_buffer(packet,&linktype,remaining);
226
227                if (!link)
228                        return NULL;
229
230                *ethertype = packet->l3_ethertype;
231                *remaining -= (packet->l3_header - link);
232
233                return packet->l3_header;
234        }
235
236        link = trace_get_layer2(packet,&linktype,remaining);
237        iphdr = trace_get_payload_from_layer2(
238                        link,
239                        linktype,
240                        ethertype,
241                        remaining);
242
243        for(;;) {
244                if (!iphdr || *remaining == 0)
245                        break;
246                switch(*ethertype) {
247                case TRACE_ETHERTYPE_8021Q: /* VLAN */
248                        iphdr=trace_get_payload_from_vlan(
249                                          iphdr,ethertype,remaining);
250                        continue;
251                case TRACE_ETHERTYPE_MPLS: /* MPLS */
252                        iphdr=trace_get_payload_from_mpls(
253                                          iphdr,ethertype,remaining);
254
255                        if (iphdr && ethertype == 0x0) {
256                                iphdr=trace_get_payload_from_ethernet(
257                                                iphdr,ethertype,remaining);
258                        }
259                        continue;
260                case TRACE_ETHERTYPE_PPP_SES: /* PPPoE */
261                        iphdr = trace_get_payload_from_pppoe(iphdr, ethertype,
262                                        remaining);
263                        continue;
264                default:
265                        break;
266                }
267
268                break;
269        }
270
271        if (!iphdr || *remaining == 0)
272                return NULL;
273
274        /* Store values in the cache for later */
275        /* Cast away constness, nasty, but this is just a cache */
276        ((libtrace_packet_t*)packet)->l3_ethertype = *ethertype;
277        ((libtrace_packet_t*)packet)->l3_header = iphdr;
278
279        return iphdr;
280}
281
282/* Parse an ip or tcp option
283 * @param[in,out] ptr   the pointer to the current option
284 * @param[in,out] len   the length of the remaining buffer
285 * @param[out] type     the type of the option
286 * @param[out] optlen   the length of the option
287 * @param[out] data     the data of the option
288 *
289 * @returns bool true if there is another option (and the fields are filled in)
290 *               or false if this was the last option.
291 *
292 * This updates ptr to point to the next option after this one, and updates
293 * len to be the number of bytes remaining in the options area.  Type is updated
294 * to be the code of this option, and data points to the data of this option,
295 * with optlen saying how many bytes there are.
296 *
297 * @note Beware of fragmented packets.
298 * @author Perry Lorier
299 */
300DLLEXPORT int trace_get_next_option(unsigned char **ptr,int *len,
301                        unsigned char *type,
302                        unsigned char *optlen,
303                        unsigned char **data)
304{
305        if (*len<=0)
306                return 0;
307        *type=**ptr;
308        switch(*type) {
309                case 0: /* End of options */
310                        return 0;
311                case 1: /* Pad */
312                        (*ptr)++;
313                        (*len)--;
314                        return 1;
315                default:
316                        *optlen = *(*ptr+1);
317                        if (*optlen<2)
318                                return 0; /* I have no idea wtf is going on
319                                           * with these packets
320                                           */
321
322                        /* Ensure that optlen is not greater than the
323                         * amount of buffer remaining */
324                        if (*optlen > *len) 
325                                return 0;
326                       
327                        (*len)-=*optlen;
328                        (*data)=(*ptr+2);
329                        (*ptr)+=*optlen;
330                        if (*len<0)
331                                return 0;
332                        return 1;
333        }
334        assert(0);
335}
336
337/* Extract the source mac address from a frame and bundle it up into a sockaddr */
338static struct sockaddr *get_source_ethernet_address(
339        libtrace_ether_t *ethernet, struct sockaddr *addr)
340{
341        static struct sockaddr_storage dummy;
342#ifdef HAVE_NETPACKET_PACKET_H
343/* Use linux's sockaddr_ll structure */
344        struct sockaddr_ll *l2addr;
345
346        if (addr)
347                l2addr = (struct sockaddr_ll*)addr;
348        else
349                l2addr = (struct sockaddr_ll*)&dummy;
350       
351        l2addr->sll_family = AF_PACKET;
352        l2addr->sll_protocol = ethernet->ether_type;
353        l2addr->sll_ifindex = 0; /* Irrelevant */
354        l2addr->sll_hatype = ARPHRD_ETHER; 
355        l2addr->sll_pkttype = PACKET_OTHERHOST;
356        l2addr->sll_halen = 6;
357        memcpy(l2addr->sll_addr,ethernet->ether_shost, 6);
358
359        return (struct sockaddr*)l2addr;
360#else
361/* Use BSD's sockaddr_dl structure */
362        struct sockaddr_dl *l2addr;
363
364        if (addr)
365                l2addr = (struct sockaddr_dl *)addr;
366        else
367                l2addr = (struct sockaddr_dl *)&dummy;
368       
369        l2addr->sdl_family = AF_LINK;
370#if HAVE_SDL_LEN == 1
371        l2addr->sdl_len = sizeof(struct sockaddr_dl);
372#endif
373        l2addr->sdl_index = 0; /* Unused */
374        l2addr->sdl_alen = 6; /* Address length  */
375        l2addr->sdl_nlen = 0; /* No name in here - this *should* work, right? */
376        l2addr->sdl_slen = 0;   
377        l2addr->sdl_type = 0; /* Hopefully zero is OK for this value too */
378        memcpy(l2addr->sdl_data, ethernet->ether_shost, 6);
379
380        return (struct sockaddr *)l2addr;
381#endif
382}
383
384static struct sockaddr *get_source_l2_address(
385        const libtrace_packet_t *packet, struct sockaddr *addr)
386{
387        static struct sockaddr_storage dummy;
388        void *l2;
389        libtrace_linktype_t linktype;
390        uint32_t remaining;
391
392        if (!addr)
393                addr =(struct sockaddr*)&dummy;
394
395        l2=trace_get_layer2(packet, &linktype, &remaining);
396        if (!l2) {
397                return NULL;
398        }
399
400        switch (linktype) {
401                case TRACE_TYPE_ETH:
402                        return get_source_ethernet_address((libtrace_ether_t*)l2, addr);
403                default:
404                        return NULL;
405        }
406}
407
408DLLEXPORT struct sockaddr *trace_get_source_address(
409                const libtrace_packet_t *packet, struct sockaddr *addr)
410{
411        uint16_t ethertype;
412        uint32_t remaining;
413        void *l3;
414        struct ports_t *ports;
415        static struct sockaddr_storage dummy;
416
417        if (!addr)
418                addr=(struct sockaddr*)&dummy;
419
420        l3 = trace_get_layer3(packet,&ethertype,&remaining);
421
422        if (!l3)
423                return get_source_l2_address(packet,addr);
424
425        switch (ethertype) {
426                case TRACE_ETHERTYPE_IP: /* IPv4 */
427                {
428                        struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
429                        libtrace_ip_t *ip = (libtrace_ip_t*)l3;
430                        ports = (struct ports_t*)
431                                trace_get_payload_from_ip(ip,NULL,&remaining);
432                        addr4->sin_family=AF_INET;
433                        if (ports && remaining>=sizeof(*ports))
434                                addr4->sin_port=ports->src;
435                        else
436                                addr4->sin_port=0;
437                        addr4->sin_addr=ip->ip_src;
438                        return addr;
439                }
440                case TRACE_ETHERTYPE_IPV6: /* IPv6 */
441                {
442                        struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
443                        libtrace_ip6_t *ip6 = (libtrace_ip6_t*)l3;
444                        ports = (struct ports_t*)
445                                trace_get_payload_from_ip6(ip6,NULL,&remaining);
446                        addr6->sin6_family=AF_INET6;
447                        if (ports && remaining>=sizeof(*ports))
448                                addr6->sin6_port=ports->src;
449                        else
450                                addr6->sin6_port=0;
451                        addr6->sin6_flowinfo=0;
452                        addr6->sin6_addr=ip6->ip_src;
453                        return addr;
454                }
455                default:
456                        return get_source_l2_address(packet, addr);
457        }
458}
459
460
461static struct sockaddr *get_destination_ethernet_address(
462        libtrace_ether_t *ethernet, struct sockaddr *addr)
463{
464        static struct sockaddr_storage dummy;
465#ifdef HAVE_NETPACKET_PACKET_H
466/* Use linux's sockaddr_ll structure */
467        struct sockaddr_ll *l2addr;
468        if (addr)
469                l2addr = (struct sockaddr_ll*)addr;
470        else
471                l2addr = (struct sockaddr_ll*)&dummy;
472       
473        l2addr->sll_family = AF_PACKET;
474        l2addr->sll_protocol = ethernet->ether_type;
475        l2addr->sll_ifindex = 0; /* Irrelevant */
476        l2addr->sll_hatype = ARPHRD_ETHER; 
477        l2addr->sll_pkttype = PACKET_OTHERHOST;
478        l2addr->sll_halen = 6;
479        memcpy(l2addr->sll_addr,ethernet->ether_dhost, 6);
480
481        return (struct sockaddr*)l2addr;
482#else
483/* Use BSD's sockaddr_dl structure */
484        struct sockaddr_dl *l2addr;
485
486        if (addr)
487                l2addr = (struct sockaddr_dl *)addr;
488        else
489                l2addr = (struct sockaddr_dl *)&dummy;
490       
491        l2addr->sdl_family = AF_LINK;
492#if HAVE_SDL_LEN == 1
493        l2addr->sdl_len = sizeof(struct sockaddr_dl);
494#endif
495        l2addr->sdl_index = 0; /* Unused */
496        l2addr->sdl_alen = 6; /* Address length  */
497        l2addr->sdl_nlen = 0; /* No name in here - this *should* work, right? */
498        l2addr->sdl_slen = 0;   
499        l2addr->sdl_type = 0; /* Hopefully zero is OK for this value too */
500        memcpy(l2addr->sdl_data, ethernet->ether_dhost, 6);
501
502        return (struct sockaddr *)l2addr;
503#endif
504}
505
506static struct sockaddr *get_destination_l2_address(
507        const libtrace_packet_t *packet, struct sockaddr *addr)
508{
509        static struct sockaddr_storage dummy;
510        void *l2;
511        libtrace_linktype_t linktype;
512        uint32_t remaining;
513        if (!addr)
514                addr =(struct sockaddr*)&dummy;
515        l2=trace_get_layer2(packet, &linktype, &remaining);
516        if (!l2)
517                return NULL;
518
519        switch (linktype) {
520                case TRACE_TYPE_ETH:
521                        return get_destination_ethernet_address((libtrace_ether_t*)l2, addr);
522                default:
523                        return NULL;
524        }
525}
526
527DLLEXPORT struct sockaddr *trace_get_destination_address(
528                const libtrace_packet_t *packet, struct sockaddr *addr)
529{
530        uint16_t ethertype;
531        uint32_t remaining;
532        void *l3;
533        struct ports_t *ports;
534        static struct sockaddr_storage dummy;
535
536        if (!addr)
537                addr=(struct sockaddr*)&dummy;
538
539        l3 = trace_get_layer3(packet,&ethertype,&remaining);
540
541        if (!l3)
542                return get_destination_l2_address(packet,addr);
543
544        switch (ethertype) {
545                case TRACE_ETHERTYPE_IP: /* IPv4 */
546                {
547                        struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
548                        libtrace_ip_t *ip = (libtrace_ip_t*)l3;
549                        ports = (struct ports_t*)
550                                trace_get_payload_from_ip(ip,NULL,&remaining);
551                        addr4->sin_family=AF_INET;
552                        if (ports && remaining>=sizeof(*ports))
553                                addr4->sin_port=ports->dst;
554                        else
555                                addr4->sin_port=0;
556                        addr4->sin_addr=ip->ip_dst;
557                        return addr;
558                }
559                case TRACE_ETHERTYPE_IPV6: /* IPv6 */
560                {
561                        struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
562                        libtrace_ip6_t *ip6 = (libtrace_ip6_t*)l3;
563                        ports = (struct ports_t*)
564                                trace_get_payload_from_ip6(ip6,NULL,&remaining);
565                        addr6->sin6_family=AF_INET6;
566                        if (ports && remaining>=sizeof(*ports))
567                                addr6->sin6_port=ports->dst;
568                        else
569                                addr6->sin6_port=0;
570                        addr6->sin6_flowinfo=0;
571                        addr6->sin6_addr=ip6->ip_dst;
572                        return addr;
573                }
574                default:
575                        return get_destination_l2_address(packet, addr);
576        }
577}
578
579
Note: See TracBrowser for help on using the repository browser.