source: lib/protocols_l3.c @ d5a42c2

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since d5a42c2 was f6730d8, checked in by Shane Alcock <salcock@…>, 12 years ago
  • Updated licensing and documentation for the protocol decoders
  • Moved trace_get_source_mac and trace_get_destination_mac into protocols_l2.c which is much more appropriate
  • Re-wrote trace_get_destination_mac to match the behaviour of trace_get_source_mac, especially with regard to ignoring link types that match meta-data headers
  • Added TRACE_TYPE_NONDATA handlers to several switch statements
  • Property mode set to 100644
File size: 12.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#endif
48
49/* This file contains all the protocol decoding functions for layer 3
50 * (the IP layer) protocols. This includes functions for accessing IP
51 * addresses.
52 *
53 * Supported protocols include:
54 *      IPv4
55 *      IPv6
56 */
57
58/* Gets an IPv4 header */
59libtrace_ip_t *trace_get_ip(libtrace_packet_t *packet) 
60{
61        uint16_t ethertype;
62        void *ret;
63
64        uint32_t remaining = trace_get_capture_length(packet);
65
66        ret = trace_get_layer3(packet,&ethertype,&remaining);
67
68        if (!ret || ethertype!=TRACE_ETHERTYPE_IP)
69                return NULL;
70
71        /* Make sure we have at least a base IPv4 header */
72        if (remaining < sizeof(libtrace_ip_t)) 
73                return NULL;
74       
75        /* Not an IPv4 packet */
76        if (((libtrace_ip_t*)ret)->ip_v != 4)
77                return NULL;
78
79        return (libtrace_ip_t*)ret;
80}
81
82libtrace_ip6_t *trace_get_ip6(libtrace_packet_t *packet) 
83{
84        uint16_t ethertype;
85        void *ret;
86
87        uint32_t remaining = trace_get_capture_length(packet);
88
89        ret = trace_get_layer3(packet,&ethertype,&remaining);
90
91        if (!ret || ethertype!=TRACE_ETHERTYPE_IPV6)
92                return NULL;
93
94        /* Make sure we have at least the base IPv6 header */
95        if (remaining < sizeof(libtrace_ip6_t))
96                return NULL;
97
98        return (libtrace_ip6_t*)ret;
99}
100
101#define SW_IP_OFFMASK 0x1fff
102
103DLLEXPORT void *trace_get_payload_from_ip(libtrace_ip_t *ipptr, uint8_t *prot,
104                uint32_t *remaining) 
105{
106        void *trans_ptr = 0;
107
108        assert(ipptr != NULL);
109       
110        /* Er? IPv5? */
111        if (ipptr->ip_v != 4)
112                return NULL;
113
114        if ((ntohs(ipptr->ip_off) & SW_IP_OFFMASK) != 0) {
115                if (remaining)
116                        *remaining = 0;         
117                return NULL;
118        }
119
120        if (remaining) {
121                if (*remaining<(ipptr->ip_hl*4U)) {
122                        *remaining = 0;
123                        return NULL;
124                }
125                *remaining-=(ipptr->ip_hl * 4);
126        }
127
128        trans_ptr = (void *)((char *)ipptr + (ipptr->ip_hl * 4));
129
130        if (prot) *prot = ipptr->ip_p;
131
132        return trans_ptr;
133}
134
135void *trace_get_payload_from_ip6(libtrace_ip6_t *ipptr, uint8_t *prot,
136                uint32_t *remaining) 
137{
138        void *payload = (char*)ipptr+sizeof(libtrace_ip6_t);
139        uint8_t nxt;
140
141        assert (ipptr != NULL);
142        nxt = ipptr->nxt;       
143        if (remaining) {
144                if (*remaining<sizeof(libtrace_ip6_t)) {
145                        *remaining = 0;
146                        return NULL;
147                }
148                *remaining-=sizeof(libtrace_ip6_t);
149        }
150
151        while(1) {
152                switch (nxt) {
153                        case 0: /* hop by hop options */
154                        case TRACE_IPPROTO_ROUTING:
155                        case TRACE_IPPROTO_FRAGMENT:
156                        case TRACE_IPPROTO_ESP:
157                        case TRACE_IPPROTO_AH:
158                        case TRACE_IPPROTO_DSTOPTS:
159                                {
160                                        uint16_t len=((libtrace_ip6_ext_t*)payload)->len
161                                        +sizeof(libtrace_ip6_ext_t);
162
163                                        if (remaining) {
164                                                if (*remaining < len) {
165                                                        /* Snap too short */
166                                                        *remaining = 0;
167                                                        return NULL;
168                                                }
169                                                *remaining-=len;
170                                        }
171
172                                        payload=(char*)payload+len;
173                                        nxt=((libtrace_ip6_ext_t*)payload)->nxt;
174                                        continue;
175                                }
176                        default:
177                                if (prot) *prot=nxt;
178                                return payload;
179                }
180        }
181}
182
183DLLEXPORT void *trace_get_layer3(const libtrace_packet_t *packet,
184                uint16_t *ethertype,
185                uint32_t *remaining)
186{
187        void *iphdr;
188        uint16_t dummy_ethertype;
189        void *link;
190        uint32_t dummy_remaining;
191        libtrace_linktype_t linktype;
192
193        if (!ethertype) ethertype=&dummy_ethertype;
194
195        if (!remaining) remaining=&dummy_remaining;
196
197        /* use l3 cache */
198        if (packet->l3_header)
199        {
200                link = trace_get_packet_buffer(packet,&linktype,remaining);
201
202                if (!link)
203                        return NULL;
204
205                *ethertype = packet->l3_ethertype;
206                *remaining -= (packet->l3_header - link);
207
208                return packet->l3_header;
209        }
210
211        link = trace_get_layer2(packet,&linktype,remaining);
212        iphdr = trace_get_payload_from_layer2(
213                        link,
214                        linktype,
215                        ethertype,
216                        remaining);
217
218        for(;;) {
219                if (!iphdr || *remaining == 0)
220                        break;
221                switch(*ethertype) {
222                case TRACE_ETHERTYPE_8021Q: /* VLAN */
223                        iphdr=trace_get_payload_from_vlan(
224                                          iphdr,ethertype,remaining);
225                        continue;
226                case TRACE_ETHERTYPE_MPLS: /* MPLS */
227                        iphdr=trace_get_payload_from_mpls(
228                                          iphdr,ethertype,remaining);
229
230                        if (iphdr && ethertype == 0x0) {
231                                iphdr=trace_get_payload_from_ethernet(
232                                                iphdr,ethertype,remaining);
233                        }
234                        continue;
235                case TRACE_ETHERTYPE_PPP_SES: /* PPPoE */
236                        iphdr = trace_get_payload_from_pppoe(iphdr, ethertype,
237                                        remaining);
238                        continue;
239                default:
240                        break;
241                }
242
243                break;
244        }
245
246        if (!iphdr || *remaining == 0)
247                return NULL;
248
249        /* Store values in the cache for later */
250        /* Cast away constness, nasty, but this is just a cache */
251        ((libtrace_packet_t*)packet)->l3_ethertype = *ethertype;
252        ((libtrace_packet_t*)packet)->l3_header = iphdr;
253
254        return iphdr;
255}
256
257/* Parse an ip or tcp option
258 * @param[in,out] ptr   the pointer to the current option
259 * @param[in,out] len   the length of the remaining buffer
260 * @param[out] type     the type of the option
261 * @param[out] optlen   the length of the option
262 * @param[out] data     the data of the option
263 *
264 * @returns bool true if there is another option (and the fields are filled in)
265 *               or false if this was the last option.
266 *
267 * This updates ptr to point to the next option after this one, and updates
268 * len to be the number of bytes remaining in the options area.  Type is updated
269 * to be the code of this option, and data points to the data of this option,
270 * with optlen saying how many bytes there are.
271 *
272 * @note Beware of fragmented packets.
273 * @author Perry Lorier
274 */
275DLLEXPORT int trace_get_next_option(unsigned char **ptr,int *len,
276                        unsigned char *type,
277                        unsigned char *optlen,
278                        unsigned char **data)
279{
280        if (*len<=0)
281                return 0;
282        *type=**ptr;
283        switch(*type) {
284                case 0: /* End of options */
285                        return 0;
286                case 1: /* Pad */
287                        (*ptr)++;
288                        (*len)--;
289                        return 1;
290                default:
291                        *optlen = *(*ptr+1);
292                        if (*optlen<2)
293                                return 0; /* I have no idea wtf is going on
294                                           * with these packets
295                                           */
296
297                        /* Ensure that optlen is not greater than the
298                         * amount of buffer remaining */
299                        if (*optlen > *len) 
300                                return 0;
301                       
302                        (*len)-=*optlen;
303                        (*data)=(*ptr+2);
304                        (*ptr)+=*optlen;
305                        if (*len<0)
306                                return 0;
307                        return 1;
308        }
309        assert(0);
310}
311
312/* Extract the source mac address from a frame and bundle it up into a sockaddr */
313static struct sockaddr *get_source_ethernet_address(
314        libtrace_ether_t *ethernet, struct sockaddr *addr)
315{
316#ifdef HAVE_NETPACKET_PACKET_H
317/* Use linux's sockaddr_ll structure */
318        static struct sockaddr_storage dummy;
319        struct sockaddr_ll *l2addr;
320
321        if (addr)
322                l2addr = (struct sockaddr_ll*)addr;
323        else
324                l2addr = (struct sockaddr_ll*)&dummy;
325       
326        l2addr->sll_family = AF_PACKET;
327        l2addr->sll_protocol = ethernet->ether_type;
328        l2addr->sll_ifindex = 0; /* Irrelevant */
329        l2addr->sll_hatype = ARPHRD_ETHER; 
330        l2addr->sll_pkttype = PACKET_OTHERHOST;
331        l2addr->sll_halen = 6;
332        memcpy(l2addr->sll_addr,ethernet->ether_shost, 6);
333
334        return (struct sockaddr*)l2addr;
335#else
336/* TODO: implement BSD's sockaddr_dl structure, sigh. */
337        return NULL;
338#endif
339}
340
341static struct sockaddr *get_source_l2_address(
342        const libtrace_packet_t *packet, struct sockaddr *addr)
343{
344        static struct sockaddr_storage dummy;
345        void *l2;
346        libtrace_linktype_t linktype;
347        uint32_t remaining;
348
349        if (!addr)
350                addr =(struct sockaddr*)&dummy;
351
352        l2=trace_get_layer2(packet, &linktype, &remaining);
353        if (!l2) {
354                return NULL;
355        }
356
357        switch (linktype) {
358                case TRACE_TYPE_ETH:
359                        return get_source_ethernet_address((libtrace_ether_t*)l2, addr);
360                default:
361                        return NULL;
362        }
363}
364
365DLLEXPORT struct sockaddr *trace_get_source_address(
366                const libtrace_packet_t *packet, struct sockaddr *addr)
367{
368        uint16_t ethertype;
369        uint32_t remaining;
370        void *l3;
371        struct ports_t *ports;
372        static struct sockaddr_storage dummy;
373
374        if (!addr)
375                addr=(struct sockaddr*)&dummy;
376
377        l3 = trace_get_layer3(packet,&ethertype,&remaining);
378
379        if (!l3)
380                return get_source_l2_address(packet,addr);
381
382        switch (ethertype) {
383                case TRACE_ETHERTYPE_IP: /* IPv4 */
384                {
385                        struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
386                        libtrace_ip_t *ip = (libtrace_ip_t*)l3;
387                        ports = (struct ports_t*)
388                                trace_get_payload_from_ip(ip,NULL,&remaining);
389                        addr4->sin_family=AF_INET;
390                        if (ports && remaining>=sizeof(*ports))
391                                addr4->sin_port=ports->src;
392                        else
393                                addr4->sin_port=0;
394                        addr4->sin_addr=ip->ip_src;
395                        return addr;
396                }
397                case TRACE_ETHERTYPE_IPV6: /* IPv6 */
398                {
399                        struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
400                        libtrace_ip6_t *ip6 = (libtrace_ip6_t*)l3;
401                        ports = (struct ports_t*)
402                                trace_get_payload_from_ip6(ip6,NULL,&remaining);
403                        addr6->sin6_family=AF_INET6;
404                        if (ports && remaining>=sizeof(*ports))
405                                addr6->sin6_port=ports->src;
406                        else
407                                addr6->sin6_port=0;
408                        addr6->sin6_flowinfo=0;
409                        addr6->sin6_addr=ip6->ip_src;
410                        return addr;
411                }
412                default:
413                        return get_source_l2_address(packet, addr);
414        }
415}
416
417
418static struct sockaddr *get_destination_ethernet_address(
419        libtrace_ether_t *ethernet, struct sockaddr *addr)
420{
421#ifdef HAVE_NETPACKET_PACKET_H
422/* Use linux's sockaddr_ll structure */
423        static struct sockaddr_storage dummy;
424        struct sockaddr_ll *l2addr;
425        if (addr)
426                l2addr = (struct sockaddr_ll*)addr;
427        else
428                l2addr = (struct sockaddr_ll*)&dummy;
429       
430        l2addr->sll_family = AF_PACKET;
431        l2addr->sll_protocol = ethernet->ether_type;
432        l2addr->sll_ifindex = 0; /* Irrelevant */
433        l2addr->sll_hatype = ARPHRD_ETHER; 
434        l2addr->sll_pkttype = PACKET_OTHERHOST;
435        l2addr->sll_halen = 6;
436        memcpy(l2addr->sll_addr,ethernet->ether_dhost, 6);
437
438        return (struct sockaddr*)l2addr;
439#else
440/* TODO: implement BSD's sockaddr_dl structure, sigh. */
441        return NULL;
442#endif
443}
444
445static struct sockaddr *get_destination_l2_address(
446        const libtrace_packet_t *packet, struct sockaddr *addr)
447{
448        static struct sockaddr_storage dummy;
449        void *l2;
450        libtrace_linktype_t linktype;
451        uint32_t remaining;
452        if (!addr)
453                addr =(struct sockaddr*)&dummy;
454        l2=trace_get_layer2(packet, &linktype, &remaining);
455        if (!l2)
456                return NULL;
457
458        switch (linktype) {
459                case TRACE_TYPE_ETH:
460                        return get_destination_ethernet_address((libtrace_ether_t*)l2, addr);
461                default:
462                        return NULL;
463        }
464}
465
466DLLEXPORT struct sockaddr *trace_get_destination_address(
467                const libtrace_packet_t *packet, struct sockaddr *addr)
468{
469        uint16_t ethertype;
470        uint32_t remaining;
471        void *l3;
472        struct ports_t *ports;
473        static struct sockaddr_storage dummy;
474
475        if (!addr)
476                addr=(struct sockaddr*)&dummy;
477
478        l3 = trace_get_layer3(packet,&ethertype,&remaining);
479
480        if (!l3)
481                return get_destination_l2_address(packet,addr);
482
483        switch (ethertype) {
484                case TRACE_ETHERTYPE_IP: /* IPv4 */
485                {
486                        struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
487                        libtrace_ip_t *ip = (libtrace_ip_t*)l3;
488                        ports = (struct ports_t*)
489                                trace_get_payload_from_ip(ip,NULL,&remaining);
490                        addr4->sin_family=AF_INET;
491                        if (ports && remaining>=sizeof(*ports))
492                                addr4->sin_port=ports->dst;
493                        else
494                                addr4->sin_port=0;
495                        addr4->sin_addr=ip->ip_dst;
496                        return addr;
497                }
498                case TRACE_ETHERTYPE_IPV6: /* IPv6 */
499                {
500                        struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
501                        libtrace_ip6_t *ip6 = (libtrace_ip6_t*)l3;
502                        ports = (struct ports_t*)
503                                trace_get_payload_from_ip6(ip6,NULL,&remaining);
504                        addr6->sin6_family=AF_INET6;
505                        if (ports && remaining>=sizeof(*ports))
506                                addr6->sin6_port=ports->dst;
507                        else
508                                addr6->sin6_port=0;
509                        addr6->sin6_flowinfo=0;
510                        addr6->sin6_addr=ip6->ip_dst;
511                        return addr;
512                }
513                default:
514                        return get_destination_l2_address(packet, addr);
515        }
516}
517
518
Note: See TracBrowser for help on using the repository browser.