source: lib/protocols.c @ 95747c3

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 95747c3 was 95747c3, checked in by Matt Brown <mattb@…>, 15 years ago

Added the required ARP_HRD types that Windows doesn't supply.

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