source: lib/protocols.c @ 77285d9

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 77285d9 was 77285d9, checked in by Shane Alcock <salcock@…>, 15 years ago

OpenBSD compatibility fixes - adding in various #defines and #includes that are needed to compile under OpenBSD
Added a replacement pcap_next_ex function for systems that aren't running pcap-0.8 or better

  • Property mode set to 100644
File size: 15.9 KB
Line 
1/* This file has the various helper functions used to decode various protocols
2 *
3 * $Id$
4 */ 
5#include "libtrace.h"
6#include "libtrace_int.h"
7#include "wag.h"
8#include <assert.h>
9#include <stdio.h>
10
11#ifndef WIN32
12#include <net/if_arp.h>
13#endif
14
15#ifndef ARPHRD_ETHER
16#define ARPHRD_ETHER    1               /* Ethernet 10/100Mbps.  */
17#endif
18
19#ifndef ARPHRD_PPP
20#define ARPHRD_PPP      512
21#endif
22
23
24/* Returns the payload from 802.3 ethernet.  Type optionally returned in
25 * "type" in host byte order.  This will return a vlan header.
26 */
27static void *trace_get_payload_from_ethernet(void *ethernet, 
28                uint16_t *type,
29                uint32_t *remaining)
30{
31        libtrace_ether_t *eth = (libtrace_ether_t*)ethernet;
32
33        if (remaining) {
34                if (*remaining < sizeof(*eth))
35                        return NULL;
36                *remaining-=sizeof(*eth);
37        }
38
39        if (type)
40                *type = ntohs(eth->ether_type);
41
42        return (void*)((char *)eth + sizeof(*eth));
43}
44
45/* skip any 802.1q headers if necessary
46 * type is input/output
47 */
48static void *trace_get_vlan_payload_from_ethernet_payload(void *ethernet, uint16_t *type,
49                uint32_t *remaining)
50{
51        assert(type && "You must pass a type in!");
52
53        if (*type == 0x8100) {
54                libtrace_8021q_t *vlanhdr = (libtrace_8021q_t *)ethernet;
55
56                if (remaining) {
57                        if (*remaining < sizeof(libtrace_8021q_t))
58                                return NULL;
59
60                        *remaining=*remaining-sizeof(libtrace_8021q_t);
61                }
62
63                *type = ntohs(vlanhdr->vlan_ether_type);
64
65                return (void*)((char *)ethernet + sizeof(*vlanhdr));
66        }
67
68        return ethernet;
69}
70
71static void *trace_get_payload_from_80211(void *link, uint16_t *type, uint32_t *remaining)
72{
73        libtrace_80211_t *wifi;
74        libtrace_802_11_payload_t *eth;
75
76        if (remaining && *remaining < sizeof(libtrace_80211_t))
77                return NULL;
78
79        wifi=(libtrace_80211_t*)link;
80
81        /* Data packet? */
82        if (wifi->type != 2) {
83                return NULL;
84        }
85
86        if (remaining && *remaining < sizeof(*eth))
87                return NULL;
88
89        eth=(libtrace_802_11_payload_t *)((char*)wifi+sizeof(*eth));
90
91        if (*type) *type=eth->type;
92
93        return eth;
94}
95
96static void *trace_get_payload_from_linux_sll(void *link,
97                uint16_t *type, uint32_t *remaining) 
98{
99        libtrace_sll_header_t *sll;
100        void *ret;
101
102        sll = (libtrace_sll_header_t*) link;
103
104        if (remaining) {
105                if (*remaining < sizeof(*sll))
106                        return NULL;
107                *remaining-=sizeof(*sll);
108        }
109
110        if (*type) *type = sll->protocol;
111
112        ret=(void*)((char*)sll+sizeof(*sll));
113
114        switch(sll->hatype) {
115                case ARPHRD_PPP:
116                        break;
117                case ARPHRD_ETHER:
118                        ret=trace_get_payload_from_ethernet(ret,type,remaining);
119        }
120
121        return ret;
122}
123
124static void *trace_get_payload_from_atm(void *link,
125                uint16_t *type, uint32_t *remaining)
126{
127        /* 64 byte capture. */
128        libtrace_llcsnap_t *llc = (libtrace_llcsnap_t*)link;
129
130        if (remaining) {
131                if (*remaining < sizeof(libtrace_llcsnap_t)+4)
132                        return NULL;
133                *remaining-=(sizeof(libtrace_llcsnap_t)+4);
134        }
135
136        /* advance the llc ptr +4 into the link layer.
137         * TODO: need to check what is in these 4 bytes.
138         * don't have time!
139         */
140        llc = (libtrace_llcsnap_t*)((char *)llc + 4);
141
142        if (*type) *type = ntohs(llc->type);
143
144        return (void*)((char*)llc+sizeof(*llc));
145}
146
147static void *trace_get_payload_from_pos(void *link, 
148                uint16_t *type, uint32_t *remaining)
149{
150        /* 64 byte capture. */
151        libtrace_pos_t *pos = (libtrace_pos_t*)link;
152
153        if (remaining) {
154                if (*remaining < sizeof(libtrace_pos_t))
155                        return NULL;
156                *remaining-=sizeof(libtrace_pos_t);
157        }
158
159        if (type) *type = ntohs(pos->ether_type);
160
161        return (void*)((char *)pos+sizeof(*pos));
162}
163
164static void *trace_get_payload_from_pflog(void *link,
165                uint16_t *type, uint32_t *remaining)
166{
167        libtrace_pflog_header_t *pflog = (libtrace_pflog_header_t*)link;
168        if (remaining) {
169                if (*remaining<sizeof(*pflog)) 
170                        return NULL;
171                *remaining-=sizeof(*pflog);
172        }
173        if (type) {
174                switch(pflog->af) {
175                        case AF_INET6: *type=0x86DD; break;
176                        case AF_INET:  *type=0x0800; break;
177                        default:
178                                      /* Unknown */
179                                      return NULL;
180                }
181        }
182        return (void*)((char*)pflog+ sizeof(*pflog));
183}
184
185void *trace_get_payload_from_link(void *link, libtrace_linktype_t linktype, 
186                uint16_t *type, uint32_t *remaining)
187{
188        switch(linktype) {
189                case TRACE_TYPE_80211_PRISM:
190                        return trace_get_payload_from_80211((char*)link+144,
191                                        type,remaining);
192                case TRACE_TYPE_80211:
193                        return trace_get_payload_from_80211(link,type,remaining);
194                case TRACE_TYPE_ETH:
195                        return trace_get_payload_from_ethernet(link,type,remaining);
196                case TRACE_TYPE_NONE:
197                        if ((*(char*)link&0xF0) == 0x40)
198                                *type=0x0800;
199                        else if ((*(char*)link&0xF0) == 0x60)
200                                *type=0x86DD;
201                        return link; /* I love the simplicity */
202                case TRACE_TYPE_LINUX_SLL:
203                        return trace_get_payload_from_linux_sll(link,type,remaining);
204                case TRACE_TYPE_PFLOG:
205                        return trace_get_payload_from_pflog(link,type,remaining);
206                case TRACE_TYPE_POS:
207                        return trace_get_payload_from_pos(link,type,remaining);
208                case TRACE_TYPE_ATM:
209                        return trace_get_payload_from_atm(link,type,remaining);
210        }
211        fprintf(stderr,"Don't understand link layer type %i in trace_get_payload_from_link()\n",
212                linktype);
213        return NULL;
214}
215
216libtrace_ip_t *trace_get_ip(libtrace_packet_t *packet) 
217{
218        uint16_t type;
219        void *link = trace_get_link(packet);
220        void *ret;
221
222        if (!link)
223                return NULL;
224       
225        ret=trace_get_payload_from_link(
226                        link,
227                        trace_get_link_type(packet),
228                        &type, NULL);
229
230        if (!ret)
231                return NULL;
232
233        ret=trace_get_vlan_payload_from_ethernet_payload(ret,&type,NULL);
234
235        if (!ret || type!=0x0800)
236                return NULL;
237
238        return (libtrace_ip_t*)ret;
239}
240
241libtrace_ip6_t *trace_get_ip6(libtrace_packet_t *packet) 
242{
243        uint16_t type;
244        void *link=trace_get_link(packet);
245        void *ret;
246       
247        if (!link)
248                return NULL;
249
250        ret=trace_get_payload_from_link(
251                        link,
252                        trace_get_link_type(packet),
253                        &type,NULL);
254
255        if (!ret)
256                return NULL;
257
258        ret=trace_get_vlan_payload_from_ethernet_payload(ret,&type,NULL);
259
260        if (!ret || type!=0x86DD)
261                return NULL;
262
263        return (libtrace_ip6_t*)ret;
264}
265
266#define SW_IP_OFFMASK 0xff1f
267
268DLLEXPORT void *trace_get_payload_from_ip(libtrace_ip_t *ipptr, uint8_t *prot,
269                uint32_t *remaining) 
270{
271        void *trans_ptr = 0;
272
273        if ((ipptr->ip_off & SW_IP_OFFMASK) != 0)
274                return NULL;
275
276        if (remaining) {
277                if (*remaining<(ipptr->ip_hl*4U)) {
278                        return NULL;
279                }
280                *remaining-=(ipptr->ip_hl * 4);
281        }
282
283        trans_ptr = (void *)((char *)ipptr + (ipptr->ip_hl * 4));
284
285        if (prot) *prot = ipptr->ip_p;
286
287        return trans_ptr;
288}
289
290void *trace_get_payload_from_ip6(libtrace_ip6_t *ipptr, uint8_t *prot,
291                uint32_t *remaining) 
292{
293        void *payload = (char*)ipptr+sizeof(libtrace_ip6_t);
294        uint8_t nxt = ipptr->nxt;
295
296        if (remaining) {
297                if (*remaining<sizeof(libtrace_ip6_t))
298                        return NULL;
299                *remaining-=sizeof(libtrace_ip6_t);
300        }
301
302        while(1) {
303                switch (nxt) {
304                        case 0: /* hop by hop options */
305                        case 43: /* routing */
306                        case 44: /* fragment */
307                        case 50: /* ESP */
308                        case 51: /* AH */
309                        case 60: /* Destination options */
310                                {
311                                        uint16_t len=((libtrace_ip6_ext_t*)payload)->len
312                                        +sizeof(libtrace_ip6_ext_t);
313
314                                        if (remaining) {
315                                                if (*remaining < len) {
316                                                        /* Snap too short */
317                                                        return NULL;
318                                                }
319                                                *remaining-=len;
320                                        }
321
322                                        payload=(char*)payload+len;
323                                        nxt=((libtrace_ip6_ext_t*)payload)->nxt;
324                                        continue;
325                                }
326                        default:
327                                if (prot) *prot=nxt;
328                                return payload;
329                }
330        }
331}
332
333DLLEXPORT void *trace_get_transport(libtrace_packet_t *packet, 
334                uint8_t *proto,
335                uint32_t *remaining
336                ) 
337{
338        void *transport;
339        uint8_t dummy;
340        uint16_t ethertype;
341        void *link;
342
343        if (!proto) proto=&dummy;
344
345        if (remaining)
346                *remaining = trace_get_capture_length(packet);
347
348        link=trace_get_link(packet);
349
350        if (!link)
351                return NULL;
352
353        transport = trace_get_payload_from_link(
354                        link,
355                        trace_get_link_type(packet),
356                        &ethertype,
357                        remaining);
358
359        if (!transport)
360                return NULL;
361
362        transport = trace_get_vlan_payload_from_ethernet_payload(transport,
363                        &ethertype,
364                        remaining);
365
366        if (!transport)
367                return NULL;
368
369        switch (ethertype) {
370                case 0x0800: /* IPv4 */
371                        transport=trace_get_payload_from_ip(
372                                (libtrace_ip_t*)transport, proto, remaining);
373                        /* IPv6 */
374                        if (transport && *proto == 41) {
375                                transport=trace_get_payload_from_ip6(
376                                 (libtrace_ip6_t*)transport, proto,remaining);
377                        }
378                        return transport;
379                case 0x86DD: /* IPv6 */
380                        return trace_get_payload_from_ip6(
381                                (libtrace_ip6_t*)transport, proto, remaining);
382                       
383                default:
384                        *proto=0;
385                        return NULL;
386        }
387
388}
389
390DLLEXPORT libtrace_tcp_t *trace_get_tcp(libtrace_packet_t *packet) {
391        uint8_t proto;
392        libtrace_tcp_t *tcp;
393
394        tcp=(libtrace_tcp_t*)trace_get_transport(packet,&proto,NULL);
395
396        if (!tcp && proto != 6)
397                return NULL;
398
399        return (libtrace_tcp_t*)tcp;
400}
401
402DLLEXPORT libtrace_tcp_t *trace_get_tcp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
403{
404        libtrace_tcp_t *tcpptr = 0;
405
406        if (ip->ip_p == 6)  {
407                tcpptr = (libtrace_tcp_t *)
408                        trace_get_payload_from_ip(ip, NULL, remaining);
409        }
410
411        return tcpptr;
412}
413
414DLLEXPORT libtrace_udp_t *trace_get_udp(libtrace_packet_t *packet) {
415        uint8_t proto;
416        libtrace_udp_t *udp;
417
418        udp=(libtrace_udp_t*)trace_get_transport(packet,&proto,NULL);
419
420        if (proto != 17)
421                return NULL;
422
423        return udp;
424}
425
426DLLEXPORT libtrace_udp_t *trace_get_udp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
427{
428        libtrace_udp_t *udpptr = 0;
429
430        if (ip->ip_p == 17) {
431                udpptr = (libtrace_udp_t *)
432                        trace_get_payload_from_ip(ip, NULL, remaining);
433        }
434
435        return udpptr;
436}
437
438DLLEXPORT libtrace_icmp_t *trace_get_icmp(libtrace_packet_t *packet) {
439        uint8_t proto;
440        libtrace_icmp_t *icmp;
441
442        icmp=(libtrace_icmp_t*)trace_get_transport(packet,&proto,NULL);
443
444        if (!icmp || proto != 1)
445                return NULL;
446
447        return icmp;
448}
449
450DLLEXPORT libtrace_icmp_t *trace_get_icmp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
451{
452        libtrace_icmp_t *icmpptr = 0;
453
454        if (ip->ip_p == 1)  {
455                icmpptr = (libtrace_icmp_t *)trace_get_payload_from_ip(ip, 
456                                NULL, remaining);
457        }
458
459        return icmpptr;
460}
461
462DLLEXPORT void *trace_get_payload_from_udp(libtrace_udp_t *udp, uint32_t *remaining)
463{
464        if (remaining) {
465                if (*remaining < sizeof(libtrace_udp_t))
466                        return NULL;
467                *remaining-=sizeof(libtrace_udp_t);
468        }
469        return (void*)((char*)udp+sizeof(libtrace_udp_t));
470}
471
472DLLEXPORT void *trace_get_payload_from_tcp(libtrace_tcp_t *tcp, uint32_t *remaining)
473{
474        unsigned int dlen = tcp->doff*4;
475        if (remaining) {
476                if (*remaining < dlen)
477                        return NULL;
478                *remaining-=dlen;
479        }
480        return tcp+dlen;
481}
482
483DLLEXPORT void *trace_get_payload_from_icmp(libtrace_icmp_t *icmp, uint32_t *remaining)
484{
485        if (remaining) {
486                if (*remaining < sizeof(libtrace_icmp_t))
487                        return NULL;
488                *remaining-=sizeof(libtrace_icmp_t);
489        }
490        return (char*)icmp+sizeof(libtrace_icmp_t);
491}
492
493struct ports_t {
494        uint16_t src;
495        uint16_t dst;
496};
497
498/* Return the client port
499 */
500DLLEXPORT uint16_t trace_get_source_port(const libtrace_packet_t *packet)
501{
502        struct ports_t *port = 
503                (struct ports_t*)trace_get_transport((libtrace_packet_t*)packet,
504                        NULL, NULL);
505
506        if (port)
507                return ntohs(port->src);
508        else
509                return 0;
510}
511
512/* Same as get_source_port except use the destination port */
513DLLEXPORT uint16_t trace_get_destination_port(const libtrace_packet_t *packet)
514{
515        struct ports_t *port = 
516                (struct ports_t*)trace_get_transport((libtrace_packet_t*)packet,
517                        NULL, NULL);
518
519        if (port)
520                return ntohs(port->dst);
521        else
522                return 0;
523}
524
525
526uint8_t *trace_get_source_mac(libtrace_packet_t *packet) {
527        void *link = trace_get_link(packet);
528        libtrace_80211_t *wifi;
529        libtrace_ether_t *ethptr = (libtrace_ether_t*)link;
530        if (!link)
531                return NULL;
532        switch (trace_get_link_type(packet)) {
533                case TRACE_TYPE_80211:
534                        wifi=(libtrace_80211_t*)link;
535                        return (uint8_t*)&wifi->mac2;
536                case TRACE_TYPE_80211_PRISM:
537                        wifi=(libtrace_80211_t*)((char*)link+144);
538                        return (uint8_t*)&wifi->mac2;
539                case TRACE_TYPE_ETH:
540                        return (uint8_t*)&ethptr->ether_shost;
541                case TRACE_TYPE_POS:
542                case TRACE_TYPE_NONE:
543                case TRACE_TYPE_HDLC_POS:
544                case TRACE_TYPE_LINUX_SLL:
545                case TRACE_TYPE_PFLOG:
546                case TRACE_TYPE_ATM:
547                        return NULL;
548        }
549        fprintf(stderr,"Not implemented\n");
550        assert(0);
551        return NULL;
552}
553
554DLLEXPORT uint8_t *trace_get_destination_mac(libtrace_packet_t *packet) {
555        void *link = trace_get_link(packet);
556        libtrace_80211_t *wifi;
557        libtrace_ether_t *ethptr = (libtrace_ether_t*)link;
558        if (!link)
559                return NULL;
560        switch (trace_get_link_type(packet)) {
561                case TRACE_TYPE_80211:
562                        wifi=(libtrace_80211_t*)link;
563                        return (uint8_t*)&wifi->mac1;
564                case TRACE_TYPE_80211_PRISM:
565                        wifi=(libtrace_80211_t*)((char*)link+144);
566                        return (uint8_t*)&wifi->mac1;
567                case TRACE_TYPE_ETH:
568                        return (uint8_t*)&ethptr->ether_dhost;
569                case TRACE_TYPE_POS:
570                case TRACE_TYPE_NONE:
571                case TRACE_TYPE_ATM:
572                case TRACE_TYPE_HDLC_POS:
573                case TRACE_TYPE_LINUX_SLL:
574                case TRACE_TYPE_PFLOG:
575                        /* No MAC address */
576                        return NULL;
577        }
578        fprintf(stderr,"Not implemented\n");
579        assert(0);
580        return NULL;
581}
582
583DLLEXPORT struct sockaddr *trace_get_source_address(const libtrace_packet_t *packet, 
584                struct sockaddr *addr)
585{
586        uint16_t proto;
587        uint32_t remaining;
588        void *transport;
589        static struct sockaddr_storage dummy;
590
591        if (!addr)
592                addr=(struct sockaddr*)&dummy;
593
594        remaining = trace_get_capture_length(packet);
595
596        transport = trace_get_payload_from_link(
597                        trace_get_link(packet),
598                        trace_get_link_type(packet),
599                        &proto,
600                        &remaining);
601
602        if (!transport)
603                return false;
604
605        transport = trace_get_vlan_payload_from_ethernet_payload(transport,
606                        &proto,
607                        &remaining);
608
609        if (!transport)
610                return false;
611
612        switch (proto) {
613                case 0x0800: /* IPv4 */
614                {
615                        struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
616                        libtrace_ip_t *ip = (libtrace_ip_t*)transport;
617                        addr4->sin_family=AF_INET;
618                        addr4->sin_port=0;
619                        addr4->sin_addr=ip->ip_src;
620                        return addr;
621                }
622                case 0x86DD: /* IPv6 */
623                {
624                        struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
625                        libtrace_ip6_t *ip6 = (libtrace_ip6_t*)transport;
626                        addr6->sin6_family=AF_INET6;
627                        addr6->sin6_port=0;
628                        addr6->sin6_flowinfo=0;
629                        addr6->sin6_addr=ip6->ip_src;
630                        return addr;
631                }
632                default:
633                        return NULL;
634        }
635}
636
637DLLEXPORT struct sockaddr *trace_get_destination_address(const libtrace_packet_t *packet, 
638                struct sockaddr *addr)
639{
640        uint16_t proto;
641        uint32_t remaining;
642        void *transport;
643        static struct sockaddr_storage dummy;
644
645        if (!addr)
646                addr=(struct sockaddr*)&dummy;
647
648        remaining = trace_get_capture_length(packet);
649
650        transport = trace_get_payload_from_link(
651                        trace_get_link(packet),
652                        trace_get_link_type(packet),
653                        &proto,
654                        &remaining);
655
656        if (!transport)
657                return false;
658
659        transport = trace_get_vlan_payload_from_ethernet_payload(transport,
660                        &proto,
661                        &remaining);
662
663        if (!transport)
664                return false;
665
666        switch (proto) {
667                case 0x0800: /* IPv4 */
668                {
669                        struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
670                        libtrace_ip_t *ip = (libtrace_ip_t*)transport;
671                        addr4->sin_family=AF_INET;
672                        addr4->sin_port=0;
673                        addr4->sin_addr=ip->ip_dst;
674                        return addr;
675                }
676                case 0x86DD: /* IPv6 */
677                {
678                        struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
679                        libtrace_ip6_t *ip6 = (libtrace_ip6_t*)transport;
680                        addr6->sin6_family=AF_INET6;
681                        addr6->sin6_port=0;
682                        addr6->sin6_flowinfo=0;
683                        addr6->sin6_addr=ip6->ip_dst;
684                        return addr;
685                }
686                default:
687                        return NULL;
688        }
689}
690
691/* parse an ip or tcp option
692 * @param[in,out] ptr   the pointer to the current option
693 * @param[in,out] len   the length of the remaining buffer
694 * @param[out] type     the type of the option
695 * @param[out] optlen   the length of the option
696 * @param[out] data     the data of the option
697 *
698 * @returns bool true if there is another option (and the fields are filled in)
699 *               or false if this was the last option.
700 *
701 * This updates ptr to point to the next option after this one, and updates
702 * len to be the number of bytes remaining in the options area.  Type is updated
703 * to be the code of this option, and data points to the data of this option,
704 * with optlen saying how many bytes there are.
705 *
706 * @note Beware of fragmented packets.
707 * @author Perry Lorier
708 */
709DLLEXPORT int trace_get_next_option(unsigned char **ptr,int *len,
710                        unsigned char *type,
711                        unsigned char *optlen,
712                        unsigned char **data)
713{
714        if (*len<=0)
715                return 0;
716        *type=**ptr;
717        switch(*type) {
718                case 0: /* End of options */
719                        return 0;
720                case 1: /* Pad */
721                        (*ptr)++;
722                        (*len)--;
723                        return 1;
724                default:
725                        *optlen = *(*ptr+1);
726                        if (*optlen<2)
727                                return 0; /* I have no idea wtf is going on
728                                           * with these packets
729                                           */
730                        (*len)-=*optlen;
731                        (*data)=(*ptr+2);
732                        (*ptr)+=*optlen;
733                        if (*len<0)
734                                return 0;
735                        return 1;
736        }
737        assert(0);
738}
739
740
Note: See TracBrowser for help on using the repository browser.