source: lib/protocols_l3.c @ 4bbe9bd

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