source: lib/protocols.c @ 088533a

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 088533a was 088533a, checked in by Perry Lorier <perry@…>, 15 years ago

Cleanup old legacy link types

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