source: lib/protocols_l3.c @ 08c56ac

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 08c56ac was 08c56ac, checked in by Shane Alcock <salcock@…>, 10 years ago
  • Fixed bug where we were moving to the next header before noting what the next header type is
  • Property mode set to 100644
File size: 13.6 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_ESP:
160                        case TRACE_IPPROTO_AH:
161                        case TRACE_IPPROTO_DSTOPTS:
162                                {
163                                        len=((libtrace_ip6_ext_t*)payload)->len
164                                        +sizeof(libtrace_ip6_ext_t);
165
166                                        if (remaining) {
167                                                if (*remaining < len) {
168                                                        /* Snap too short */
169                                                        *remaining = 0;
170                                                        return NULL;
171                                                }
172                                                *remaining-=len;
173                                        }
174
175                                        nxt=((libtrace_ip6_ext_t*)payload)->nxt;
176                                        payload=(char*)payload+len;
177                                        continue;
178                                }
179                        case TRACE_IPPROTO_FRAGMENT:
180                                {
181                                        len = sizeof(libtrace_ip6_frag_t);
182                                        if (remaining) {
183                                                if (*remaining < len) {
184                                                        /* Snap too short */
185                                                        *remaining = 0;
186                                                        return NULL;
187                                                }
188                                                *remaining-=len;
189                                        }
190                                        nxt=((libtrace_ip6_frag_t*)payload)->nxt;
191                                        payload=(char*)payload+len;
192                                        continue;
193                                }
194
195                        default:
196                                if (prot) *prot=nxt;
197                                return payload;
198                }
199        }
200}
201
202DLLEXPORT void *trace_get_layer3(const libtrace_packet_t *packet,
203                uint16_t *ethertype,
204                uint32_t *remaining)
205{
206        void *iphdr;
207        uint16_t dummy_ethertype;
208        void *link;
209        uint32_t dummy_remaining;
210        libtrace_linktype_t linktype;
211
212        if (!ethertype) ethertype=&dummy_ethertype;
213
214        if (!remaining) remaining=&dummy_remaining;
215
216        /* use l3 cache */
217        if (packet->l3_header)
218        {
219                link = trace_get_packet_buffer(packet,&linktype,remaining);
220
221                if (!link)
222                        return NULL;
223
224                *ethertype = packet->l3_ethertype;
225                *remaining -= (packet->l3_header - link);
226
227                return packet->l3_header;
228        }
229
230        link = trace_get_layer2(packet,&linktype,remaining);
231        iphdr = trace_get_payload_from_layer2(
232                        link,
233                        linktype,
234                        ethertype,
235                        remaining);
236
237        for(;;) {
238                if (!iphdr || *remaining == 0)
239                        break;
240                switch(*ethertype) {
241                case TRACE_ETHERTYPE_8021Q: /* VLAN */
242                        iphdr=trace_get_payload_from_vlan(
243                                          iphdr,ethertype,remaining);
244                        continue;
245                case TRACE_ETHERTYPE_MPLS: /* MPLS */
246                        iphdr=trace_get_payload_from_mpls(
247                                          iphdr,ethertype,remaining);
248
249                        if (iphdr && ethertype == 0x0) {
250                                iphdr=trace_get_payload_from_ethernet(
251                                                iphdr,ethertype,remaining);
252                        }
253                        continue;
254                case TRACE_ETHERTYPE_PPP_SES: /* PPPoE */
255                        iphdr = trace_get_payload_from_pppoe(iphdr, ethertype,
256                                        remaining);
257                        continue;
258                default:
259                        break;
260                }
261
262                break;
263        }
264
265        if (!iphdr || *remaining == 0)
266                return NULL;
267
268        /* Store values in the cache for later */
269        /* Cast away constness, nasty, but this is just a cache */
270        ((libtrace_packet_t*)packet)->l3_ethertype = *ethertype;
271        ((libtrace_packet_t*)packet)->l3_header = iphdr;
272
273        return iphdr;
274}
275
276/* Parse an ip or tcp option
277 * @param[in,out] ptr   the pointer to the current option
278 * @param[in,out] len   the length of the remaining buffer
279 * @param[out] type     the type of the option
280 * @param[out] optlen   the length of the option
281 * @param[out] data     the data of the option
282 *
283 * @returns bool true if there is another option (and the fields are filled in)
284 *               or false if this was the last option.
285 *
286 * This updates ptr to point to the next option after this one, and updates
287 * len to be the number of bytes remaining in the options area.  Type is updated
288 * to be the code of this option, and data points to the data of this option,
289 * with optlen saying how many bytes there are.
290 *
291 * @note Beware of fragmented packets.
292 * @author Perry Lorier
293 */
294DLLEXPORT int trace_get_next_option(unsigned char **ptr,int *len,
295                        unsigned char *type,
296                        unsigned char *optlen,
297                        unsigned char **data)
298{
299        if (*len<=0)
300                return 0;
301        *type=**ptr;
302        switch(*type) {
303                case 0: /* End of options */
304                        return 0;
305                case 1: /* Pad */
306                        (*ptr)++;
307                        (*len)--;
308                        return 1;
309                default:
310                        *optlen = *(*ptr+1);
311                        if (*optlen<2)
312                                return 0; /* I have no idea wtf is going on
313                                           * with these packets
314                                           */
315
316                        /* Ensure that optlen is not greater than the
317                         * amount of buffer remaining */
318                        if (*optlen > *len) 
319                                return 0;
320                       
321                        (*len)-=*optlen;
322                        (*data)=(*ptr+2);
323                        (*ptr)+=*optlen;
324                        if (*len<0)
325                                return 0;
326                        return 1;
327        }
328        assert(0);
329}
330
331/* Extract the source mac address from a frame and bundle it up into a sockaddr */
332static struct sockaddr *get_source_ethernet_address(
333        libtrace_ether_t *ethernet, struct sockaddr *addr)
334{
335        static struct sockaddr_storage dummy;
336#ifdef HAVE_NETPACKET_PACKET_H
337/* Use linux's sockaddr_ll structure */
338        struct sockaddr_ll *l2addr;
339
340        if (addr)
341                l2addr = (struct sockaddr_ll*)addr;
342        else
343                l2addr = (struct sockaddr_ll*)&dummy;
344       
345        l2addr->sll_family = AF_PACKET;
346        l2addr->sll_protocol = ethernet->ether_type;
347        l2addr->sll_ifindex = 0; /* Irrelevant */
348        l2addr->sll_hatype = ARPHRD_ETHER; 
349        l2addr->sll_pkttype = PACKET_OTHERHOST;
350        l2addr->sll_halen = 6;
351        memcpy(l2addr->sll_addr,ethernet->ether_shost, 6);
352
353        return (struct sockaddr*)l2addr;
354#else
355/* Use BSD's sockaddr_dl structure */
356        struct sockaddr_dl *l2addr;
357
358        if (addr)
359                l2addr = (struct sockaddr_dl *)addr;
360        else
361                l2addr = (struct sockaddr_dl *)&dummy;
362       
363        l2addr->sdl_family = AF_LINK;
364#if HAVE_SDL_LEN == 1
365        l2addr->sdl_len = sizeof(struct sockaddr_dl);
366#endif
367        l2addr->sdl_index = 0; /* Unused */
368        l2addr->sdl_alen = 6; /* Address length  */
369        l2addr->sdl_nlen = 0; /* No name in here - this *should* work, right? */
370        l2addr->sdl_slen = 0;   
371        l2addr->sdl_type = 0; /* Hopefully zero is OK for this value too */
372        memcpy(l2addr->sdl_data, ethernet->ether_shost, 6);
373
374        return (struct sockaddr *)l2addr;
375#endif
376}
377
378static struct sockaddr *get_source_l2_address(
379        const libtrace_packet_t *packet, struct sockaddr *addr)
380{
381        static struct sockaddr_storage dummy;
382        void *l2;
383        libtrace_linktype_t linktype;
384        uint32_t remaining;
385
386        if (!addr)
387                addr =(struct sockaddr*)&dummy;
388
389        l2=trace_get_layer2(packet, &linktype, &remaining);
390        if (!l2) {
391                return NULL;
392        }
393
394        switch (linktype) {
395                case TRACE_TYPE_ETH:
396                        return get_source_ethernet_address((libtrace_ether_t*)l2, addr);
397                default:
398                        return NULL;
399        }
400}
401
402DLLEXPORT struct sockaddr *trace_get_source_address(
403                const libtrace_packet_t *packet, struct sockaddr *addr)
404{
405        uint16_t ethertype;
406        uint32_t remaining;
407        void *l3;
408        struct ports_t *ports;
409        static struct sockaddr_storage dummy;
410
411        if (!addr)
412                addr=(struct sockaddr*)&dummy;
413
414        l3 = trace_get_layer3(packet,&ethertype,&remaining);
415
416        if (!l3)
417                return get_source_l2_address(packet,addr);
418
419        switch (ethertype) {
420                case TRACE_ETHERTYPE_IP: /* IPv4 */
421                {
422                        struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
423                        libtrace_ip_t *ip = (libtrace_ip_t*)l3;
424                        ports = (struct ports_t*)
425                                trace_get_payload_from_ip(ip,NULL,&remaining);
426                        addr4->sin_family=AF_INET;
427                        if (ports && remaining>=sizeof(*ports))
428                                addr4->sin_port=ports->src;
429                        else
430                                addr4->sin_port=0;
431                        addr4->sin_addr=ip->ip_src;
432                        return addr;
433                }
434                case TRACE_ETHERTYPE_IPV6: /* IPv6 */
435                {
436                        struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
437                        libtrace_ip6_t *ip6 = (libtrace_ip6_t*)l3;
438                        ports = (struct ports_t*)
439                                trace_get_payload_from_ip6(ip6,NULL,&remaining);
440                        addr6->sin6_family=AF_INET6;
441                        if (ports && remaining>=sizeof(*ports))
442                                addr6->sin6_port=ports->src;
443                        else
444                                addr6->sin6_port=0;
445                        addr6->sin6_flowinfo=0;
446                        addr6->sin6_addr=ip6->ip_src;
447                        return addr;
448                }
449                default:
450                        return get_source_l2_address(packet, addr);
451        }
452}
453
454
455static struct sockaddr *get_destination_ethernet_address(
456        libtrace_ether_t *ethernet, struct sockaddr *addr)
457{
458        static struct sockaddr_storage dummy;
459#ifdef HAVE_NETPACKET_PACKET_H
460/* Use linux's sockaddr_ll structure */
461        struct sockaddr_ll *l2addr;
462        if (addr)
463                l2addr = (struct sockaddr_ll*)addr;
464        else
465                l2addr = (struct sockaddr_ll*)&dummy;
466       
467        l2addr->sll_family = AF_PACKET;
468        l2addr->sll_protocol = ethernet->ether_type;
469        l2addr->sll_ifindex = 0; /* Irrelevant */
470        l2addr->sll_hatype = ARPHRD_ETHER; 
471        l2addr->sll_pkttype = PACKET_OTHERHOST;
472        l2addr->sll_halen = 6;
473        memcpy(l2addr->sll_addr,ethernet->ether_dhost, 6);
474
475        return (struct sockaddr*)l2addr;
476#else
477/* Use BSD's sockaddr_dl structure */
478        struct sockaddr_dl *l2addr;
479
480        if (addr)
481                l2addr = (struct sockaddr_dl *)addr;
482        else
483                l2addr = (struct sockaddr_dl *)&dummy;
484       
485        l2addr->sdl_family = AF_LINK;
486#if HAVE_SDL_LEN == 1
487        l2addr->sdl_len = sizeof(struct sockaddr_dl);
488#endif
489        l2addr->sdl_index = 0; /* Unused */
490        l2addr->sdl_alen = 6; /* Address length  */
491        l2addr->sdl_nlen = 0; /* No name in here - this *should* work, right? */
492        l2addr->sdl_slen = 0;   
493        l2addr->sdl_type = 0; /* Hopefully zero is OK for this value too */
494        memcpy(l2addr->sdl_data, ethernet->ether_dhost, 6);
495
496        return (struct sockaddr *)l2addr;
497#endif
498}
499
500static struct sockaddr *get_destination_l2_address(
501        const libtrace_packet_t *packet, struct sockaddr *addr)
502{
503        static struct sockaddr_storage dummy;
504        void *l2;
505        libtrace_linktype_t linktype;
506        uint32_t remaining;
507        if (!addr)
508                addr =(struct sockaddr*)&dummy;
509        l2=trace_get_layer2(packet, &linktype, &remaining);
510        if (!l2)
511                return NULL;
512
513        switch (linktype) {
514                case TRACE_TYPE_ETH:
515                        return get_destination_ethernet_address((libtrace_ether_t*)l2, addr);
516                default:
517                        return NULL;
518        }
519}
520
521DLLEXPORT struct sockaddr *trace_get_destination_address(
522                const libtrace_packet_t *packet, struct sockaddr *addr)
523{
524        uint16_t ethertype;
525        uint32_t remaining;
526        void *l3;
527        struct ports_t *ports;
528        static struct sockaddr_storage dummy;
529
530        if (!addr)
531                addr=(struct sockaddr*)&dummy;
532
533        l3 = trace_get_layer3(packet,&ethertype,&remaining);
534
535        if (!l3)
536                return get_destination_l2_address(packet,addr);
537
538        switch (ethertype) {
539                case TRACE_ETHERTYPE_IP: /* IPv4 */
540                {
541                        struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
542                        libtrace_ip_t *ip = (libtrace_ip_t*)l3;
543                        ports = (struct ports_t*)
544                                trace_get_payload_from_ip(ip,NULL,&remaining);
545                        addr4->sin_family=AF_INET;
546                        if (ports && remaining>=sizeof(*ports))
547                                addr4->sin_port=ports->dst;
548                        else
549                                addr4->sin_port=0;
550                        addr4->sin_addr=ip->ip_dst;
551                        return addr;
552                }
553                case TRACE_ETHERTYPE_IPV6: /* IPv6 */
554                {
555                        struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
556                        libtrace_ip6_t *ip6 = (libtrace_ip6_t*)l3;
557                        ports = (struct ports_t*)
558                                trace_get_payload_from_ip6(ip6,NULL,&remaining);
559                        addr6->sin6_family=AF_INET6;
560                        if (ports && remaining>=sizeof(*ports))
561                                addr6->sin6_port=ports->dst;
562                        else
563                                addr6->sin6_port=0;
564                        addr6->sin6_flowinfo=0;
565                        addr6->sin6_addr=ip6->ip_dst;
566                        return addr;
567                }
568                default:
569                        return get_destination_l2_address(packet, addr);
570        }
571}
572
573
Note: See TracBrowser for help on using the repository browser.