source: lib/protocols_l3.c @ 3c2ddf4

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 3c2ddf4 was 3c2ddf4, checked in by Shane Alcock <salcock@…>, 11 years ago
  • Added support for sockaddr_dl to the trace_get_*_ethernet_address functions - should fix the warnings about unused variables AND provide extra functionality
  • Property mode set to 100644
File size: 13.2 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.h"
36#include "protocols.h"
37#include <assert.h>
38#include <stdlib.h>
39#include "config.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        l2addr->sdl_len = sizeof(struct sockaddr_dl);
349        l2addr->sdl_index = 0; /* Unused */
350        l2addr->sdl_alen = 6; /* Address length  */
351        l2addr->sdl_nlen = 0; /* No name in here - this *should* work, right? */
352        l2addr->sdl_slen = 0;   
353        l2addr->sdl_type = 0; /* Hopefully zero is OK for this value too */
354        memcpy(l2addr->sdl_data, ethernet->ether_shost, 6);
355
356        return (struct sockaddr *)l2addr;
357#endif
358}
359
360static struct sockaddr *get_source_l2_address(
361        const libtrace_packet_t *packet, struct sockaddr *addr)
362{
363        static struct sockaddr_storage dummy;
364        void *l2;
365        libtrace_linktype_t linktype;
366        uint32_t remaining;
367
368        if (!addr)
369                addr =(struct sockaddr*)&dummy;
370
371        l2=trace_get_layer2(packet, &linktype, &remaining);
372        if (!l2) {
373                return NULL;
374        }
375
376        switch (linktype) {
377                case TRACE_TYPE_ETH:
378                        return get_source_ethernet_address((libtrace_ether_t*)l2, addr);
379                default:
380                        return NULL;
381        }
382}
383
384DLLEXPORT struct sockaddr *trace_get_source_address(
385                const libtrace_packet_t *packet, struct sockaddr *addr)
386{
387        uint16_t ethertype;
388        uint32_t remaining;
389        void *l3;
390        struct ports_t *ports;
391        static struct sockaddr_storage dummy;
392
393        if (!addr)
394                addr=(struct sockaddr*)&dummy;
395
396        l3 = trace_get_layer3(packet,&ethertype,&remaining);
397
398        if (!l3)
399                return get_source_l2_address(packet,addr);
400
401        switch (ethertype) {
402                case TRACE_ETHERTYPE_IP: /* IPv4 */
403                {
404                        struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
405                        libtrace_ip_t *ip = (libtrace_ip_t*)l3;
406                        ports = (struct ports_t*)
407                                trace_get_payload_from_ip(ip,NULL,&remaining);
408                        addr4->sin_family=AF_INET;
409                        if (ports && remaining>=sizeof(*ports))
410                                addr4->sin_port=ports->src;
411                        else
412                                addr4->sin_port=0;
413                        addr4->sin_addr=ip->ip_src;
414                        return addr;
415                }
416                case TRACE_ETHERTYPE_IPV6: /* IPv6 */
417                {
418                        struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
419                        libtrace_ip6_t *ip6 = (libtrace_ip6_t*)l3;
420                        ports = (struct ports_t*)
421                                trace_get_payload_from_ip6(ip6,NULL,&remaining);
422                        addr6->sin6_family=AF_INET6;
423                        if (ports && remaining>=sizeof(*ports))
424                                addr6->sin6_port=ports->src;
425                        else
426                                addr6->sin6_port=0;
427                        addr6->sin6_flowinfo=0;
428                        addr6->sin6_addr=ip6->ip_src;
429                        return addr;
430                }
431                default:
432                        return get_source_l2_address(packet, addr);
433        }
434}
435
436
437static struct sockaddr *get_destination_ethernet_address(
438        libtrace_ether_t *ethernet, struct sockaddr *addr)
439{
440        static struct sockaddr_storage dummy;
441#ifdef HAVE_NETPACKET_PACKET_H
442/* Use linux's sockaddr_ll structure */
443        struct sockaddr_ll *l2addr;
444        if (addr)
445                l2addr = (struct sockaddr_ll*)addr;
446        else
447                l2addr = (struct sockaddr_ll*)&dummy;
448       
449        l2addr->sll_family = AF_PACKET;
450        l2addr->sll_protocol = ethernet->ether_type;
451        l2addr->sll_ifindex = 0; /* Irrelevant */
452        l2addr->sll_hatype = ARPHRD_ETHER; 
453        l2addr->sll_pkttype = PACKET_OTHERHOST;
454        l2addr->sll_halen = 6;
455        memcpy(l2addr->sll_addr,ethernet->ether_dhost, 6);
456
457        return (struct sockaddr*)l2addr;
458#else
459/* Use BSD's sockaddr_dl structure */
460        struct sockaddr_dl *l2addr;
461
462        if (addr)
463                l2addr = (struct sockaddr_dl *)addr;
464        else
465                l2addr = (struct sockaddr_dl *)&dummy;
466       
467        l2addr->sdl_family = AF_LINK;
468        l2addr->sdl_len = sizeof(struct sockaddr_dl);
469        l2addr->sdl_index = 0; /* Unused */
470        l2addr->sdl_alen = 6; /* Address length  */
471        l2addr->sdl_nlen = 0; /* No name in here - this *should* work, right? */
472        l2addr->sdl_slen = 0;   
473        l2addr->sdl_type = 0; /* Hopefully zero is OK for this value too */
474        memcpy(l2addr->sdl_data, ethernet->ether_dhost, 6);
475
476        return (struct sockaddr *)l2addr;
477#endif
478}
479
480static struct sockaddr *get_destination_l2_address(
481        const libtrace_packet_t *packet, struct sockaddr *addr)
482{
483        static struct sockaddr_storage dummy;
484        void *l2;
485        libtrace_linktype_t linktype;
486        uint32_t remaining;
487        if (!addr)
488                addr =(struct sockaddr*)&dummy;
489        l2=trace_get_layer2(packet, &linktype, &remaining);
490        if (!l2)
491                return NULL;
492
493        switch (linktype) {
494                case TRACE_TYPE_ETH:
495                        return get_destination_ethernet_address((libtrace_ether_t*)l2, addr);
496                default:
497                        return NULL;
498        }
499}
500
501DLLEXPORT struct sockaddr *trace_get_destination_address(
502                const libtrace_packet_t *packet, struct sockaddr *addr)
503{
504        uint16_t ethertype;
505        uint32_t remaining;
506        void *l3;
507        struct ports_t *ports;
508        static struct sockaddr_storage dummy;
509
510        if (!addr)
511                addr=(struct sockaddr*)&dummy;
512
513        l3 = trace_get_layer3(packet,&ethertype,&remaining);
514
515        if (!l3)
516                return get_destination_l2_address(packet,addr);
517
518        switch (ethertype) {
519                case TRACE_ETHERTYPE_IP: /* IPv4 */
520                {
521                        struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
522                        libtrace_ip_t *ip = (libtrace_ip_t*)l3;
523                        ports = (struct ports_t*)
524                                trace_get_payload_from_ip(ip,NULL,&remaining);
525                        addr4->sin_family=AF_INET;
526                        if (ports && remaining>=sizeof(*ports))
527                                addr4->sin_port=ports->dst;
528                        else
529                                addr4->sin_port=0;
530                        addr4->sin_addr=ip->ip_dst;
531                        return addr;
532                }
533                case TRACE_ETHERTYPE_IPV6: /* IPv6 */
534                {
535                        struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
536                        libtrace_ip6_t *ip6 = (libtrace_ip6_t*)l3;
537                        ports = (struct ports_t*)
538                                trace_get_payload_from_ip6(ip6,NULL,&remaining);
539                        addr6->sin6_family=AF_INET6;
540                        if (ports && remaining>=sizeof(*ports))
541                                addr6->sin6_port=ports->dst;
542                        else
543                                addr6->sin6_port=0;
544                        addr6->sin6_flowinfo=0;
545                        addr6->sin6_addr=ip6->ip_dst;
546                        return addr;
547                }
548                default:
549                        return get_destination_l2_address(packet, addr);
550        }
551}
552
553
Note: See TracBrowser for help on using the repository browser.