source: lib/protocols.c @ 39e141f

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

Merge windows portability fixes

  • Property mode set to 100644
File size: 15.7 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_legacy_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                case TRACE_TYPE_LEGACY_ETH:
174                        return trace_get_payload_from_ethernet(link,type,remaining);
175                case TRACE_TYPE_NONE:
176                        return link; /* I love the simplicity */
177                case TRACE_TYPE_LINUX_SLL:
178                        return trace_get_payload_from_linux_sll(link,type,remaining);
179                case TRACE_TYPE_PFLOG:
180                        return trace_get_payload_from_pflog(link,type,remaining);
181                case TRACE_TYPE_LEGACY_POS:
182                        return trace_get_payload_from_legacy_pos(link,type,remaining);
183                case TRACE_TYPE_LEGACY_ATM:
184                case TRACE_TYPE_ATM:
185                        return trace_get_payload_from_atm(link,type,remaining);
186        }
187        fprintf(stderr,"Don't understand link layer type %i in trace_get_payload_from_link()\n",
188                linktype);
189        return NULL;
190}
191
192libtrace_ip_t *trace_get_ip(libtrace_packet_t *packet) 
193{
194        uint16_t type;
195        void *link = trace_get_link(packet);
196        void *ret;
197
198        if (!link)
199                return NULL;
200       
201        ret=trace_get_payload_from_link(
202                        link,
203                        trace_get_link_type(packet),
204                        &type, NULL);
205
206        if (!ret)
207                return NULL;
208
209        ret=trace_get_vlan_payload_from_ethernet_payload(ret,&type,NULL);
210
211        if (!ret || type!=0x0800)
212                return NULL;
213
214        return (libtrace_ip_t*)ret;
215}
216
217libtrace_ip6_t *trace_get_ip6(libtrace_packet_t *packet) 
218{
219        uint16_t type;
220        void *link=trace_get_link(packet);
221        void *ret;
222       
223        if (!link)
224                return NULL;
225
226        ret=trace_get_payload_from_link(
227                        link,
228                        trace_get_link_type(packet),
229                        &type,NULL);
230
231        if (!ret)
232                return NULL;
233
234        ret=trace_get_vlan_payload_from_ethernet_payload(ret,&type,NULL);
235
236        if (!ret || type!=0x86DD)
237                return NULL;
238
239        return (libtrace_ip6_t*)ret;
240}
241
242#define SW_IP_OFFMASK 0xff1f
243
244DLLEXPORT void *trace_get_payload_from_ip(libtrace_ip_t *ipptr, uint8_t *prot,
245                uint32_t *remaining) 
246{
247        void *trans_ptr = 0;
248
249        if ((ipptr->ip_off & SW_IP_OFFMASK) != 0)
250                return NULL;
251
252        if (remaining) {
253                if (*remaining<(ipptr->ip_hl*4U)) {
254                        return NULL;
255                }
256                *remaining-=(ipptr->ip_hl * 4);
257        }
258
259        trans_ptr = (void *)((char *)ipptr + (ipptr->ip_hl * 4));
260
261        if (prot) *prot = ipptr->ip_p;
262
263        return trans_ptr;
264}
265
266void *trace_get_payload_from_ip6(libtrace_ip6_t *ipptr, uint8_t *prot,
267                uint32_t *remaining) 
268{
269        void *payload = (char*)ipptr+sizeof(libtrace_ip6_t);
270        uint8_t nxt = ipptr->nxt;
271
272        if (remaining) {
273                if (*remaining<sizeof(libtrace_ip6_t))
274                        return NULL;
275                *remaining-=sizeof(libtrace_ip6_t);
276        }
277
278        while(1) {
279                switch (nxt) {
280                        case 0: /* hop by hop options */
281                        case 43: /* routing */
282                        case 44: /* fragment */
283                        case 50: /* ESP */
284                        case 51: /* AH */
285                        case 60: /* Destination options */
286                                {
287                                        uint16_t len=((libtrace_ip6_ext_t*)payload)->len
288                                        +sizeof(libtrace_ip6_ext_t);
289
290                                        if (remaining) {
291                                                if (*remaining < len) {
292                                                        /* Snap too short */
293                                                        return NULL;
294                                                }
295                                                *remaining-=len;
296                                        }
297
298                                        payload=(char*)payload+len;
299                                        nxt=((libtrace_ip6_ext_t*)payload)->nxt;
300                                        continue;
301                                }
302                        default:
303                                if (prot) *prot=nxt;
304                                return payload;
305                }
306        }
307}
308
309DLLEXPORT void *trace_get_transport(libtrace_packet_t *packet, 
310                uint8_t *proto,
311                uint32_t *remaining
312                ) 
313{
314        void *transport;
315        uint8_t dummy;
316        uint16_t ethertype;
317        void *link;
318
319        if (!proto) proto=&dummy;
320
321        if (remaining)
322                *remaining = trace_get_capture_length(packet);
323
324        link=trace_get_link(packet);
325
326        if (!link)
327                return NULL;
328
329        transport = trace_get_payload_from_link(
330                        link,
331                        trace_get_link_type(packet),
332                        &ethertype,
333                        remaining);
334
335        if (!transport)
336                return NULL;
337
338        transport = trace_get_vlan_payload_from_ethernet_payload(transport,
339                        &ethertype,
340                        remaining);
341
342        if (!transport)
343                return NULL;
344
345        switch (ethertype) {
346                case 0x0800: /* IPv4 */
347                        transport=trace_get_payload_from_ip(
348                                (libtrace_ip_t*)transport, proto, remaining);
349                        /* IPv6 */
350                        if (transport && *proto == 41) {
351                                transport=trace_get_payload_from_ip6(
352                                 (libtrace_ip6_t*)transport, proto,remaining);
353                        }
354                        return transport;
355                case 0x86DD: /* IPv6 */
356                        return trace_get_payload_from_ip6(
357                                (libtrace_ip6_t*)transport, proto, remaining);
358                       
359                default:
360                        return NULL;
361        }
362
363}
364
365DLLEXPORT libtrace_tcp_t *trace_get_tcp(libtrace_packet_t *packet) {
366        uint8_t proto;
367        libtrace_tcp_t *tcp;
368
369        tcp=(libtrace_tcp_t*)trace_get_transport(packet,&proto,NULL);
370
371        if (!tcp && proto != 6)
372                return NULL;
373
374        return (libtrace_tcp_t*)tcp;
375}
376
377DLLEXPORT libtrace_tcp_t *trace_get_tcp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
378{
379        struct libtrace_tcp *tcpptr = 0;
380
381        if (ip->ip_p == 6)  {
382                tcpptr = (struct libtrace_tcp *)
383                        trace_get_payload_from_ip(ip, NULL, remaining);
384        }
385
386        return tcpptr;
387}
388
389DLLEXPORT libtrace_udp_t *trace_get_udp(libtrace_packet_t *packet) {
390        uint8_t proto;
391        libtrace_udp_t *udp;
392
393        udp=(libtrace_udp_t*)trace_get_transport(packet,&proto,NULL);
394
395        if (proto != 17)
396                return NULL;
397
398        return udp;
399}
400
401DLLEXPORT libtrace_udp_t *trace_get_udp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
402{
403        struct libtrace_udp *udpptr = 0;
404
405        if (ip->ip_p == 17) {
406                udpptr = (libtrace_udp_t *)
407                        trace_get_payload_from_ip(ip, NULL, remaining);
408        }
409
410        return udpptr;
411}
412
413DLLEXPORT libtrace_icmp_t *trace_get_icmp(libtrace_packet_t *packet) {
414        uint8_t proto;
415        libtrace_icmp_t *icmp;
416
417        icmp=(libtrace_icmp_t*)trace_get_transport(packet,&proto,NULL);
418
419        if (proto != 1)
420                return NULL;
421
422        return icmp;
423}
424
425DLLEXPORT libtrace_icmp_t *trace_get_icmp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
426{
427        libtrace_icmp_t *icmpptr = 0;
428
429        if (ip->ip_p == 1)  {
430                icmpptr = (libtrace_icmp_t *)trace_get_payload_from_ip(ip, 
431                                NULL, remaining);
432        }
433
434        return icmpptr;
435}
436
437DLLEXPORT void *trace_get_payload_from_udp(libtrace_udp_t *udp, uint32_t *remaining)
438{
439        if (remaining) {
440                if (*remaining < sizeof(libtrace_udp_t))
441                        return NULL;
442                *remaining-=sizeof(libtrace_udp_t);
443        }
444        return (void*)((char*)udp+sizeof(libtrace_udp_t));
445}
446
447DLLEXPORT void *trace_get_payload_from_tcp(libtrace_tcp_t *tcp, uint32_t *remaining)
448{
449        unsigned int dlen = tcp->doff*4;
450        if (remaining) {
451                if (*remaining < dlen)
452                        return NULL;
453                *remaining-=dlen;
454        }
455        return tcp+dlen;
456}
457
458DLLEXPORT void *trace_get_payload_from_icmp(libtrace_icmp_t *icmp, uint32_t *remaining)
459{
460        if (remaining) {
461                if (*remaining < sizeof(libtrace_icmp_t))
462                        return NULL;
463                *remaining-=sizeof(libtrace_icmp_t);
464        }
465        return (char*)icmp+sizeof(libtrace_icmp_t);
466}
467
468struct ports_t {
469        uint16_t src;
470        uint16_t dst;
471};
472
473/* Return the client port
474 */
475DLLEXPORT uint16_t trace_get_source_port(const libtrace_packet_t *packet)
476{
477        struct ports_t *port = 
478                (struct ports_t*)trace_get_transport((libtrace_packet_t*)packet,
479                        NULL, NULL);
480
481        if (port)
482                return ntohs(port->src);
483        else
484                return 0;
485}
486
487/* Same as get_source_port except use the destination port */
488DLLEXPORT uint16_t trace_get_destination_port(const libtrace_packet_t *packet)
489{
490        struct ports_t *port = 
491                (struct ports_t*)trace_get_transport((libtrace_packet_t*)packet,
492                        NULL, NULL);
493
494        if (port)
495                return ntohs(port->dst);
496        else
497                return 0;
498}
499
500
501uint8_t *trace_get_source_mac(libtrace_packet_t *packet) {
502        void *link = trace_get_link(packet);
503        libtrace_80211_t *wifi;
504        libtrace_ether_t *ethptr = (libtrace_ether_t*)link;
505        if (!link)
506                return NULL;
507        switch (trace_get_link_type(packet)) {
508                case TRACE_TYPE_80211:
509                        wifi=(libtrace_80211_t*)link;
510                        return (uint8_t*)&wifi->mac2;
511                case TRACE_TYPE_80211_PRISM:
512                        wifi=(libtrace_80211_t*)((char*)link+144);
513                        return (uint8_t*)&wifi->mac2;
514                case TRACE_TYPE_LEGACY_ETH:
515                case TRACE_TYPE_ETH:
516                        return (uint8_t*)&ethptr->ether_shost;
517                case TRACE_TYPE_LEGACY:
518                case TRACE_TYPE_LEGACY_POS:
519                case TRACE_TYPE_NONE:
520                case TRACE_TYPE_ATM:
521                case TRACE_TYPE_HDLC_POS:
522                case TRACE_TYPE_LINUX_SLL:
523                case TRACE_TYPE_PFLOG:
524                case TRACE_TYPE_LEGACY_ATM:
525                        return NULL;
526        }
527        fprintf(stderr,"Not implemented\n");
528        assert(0);
529        return NULL;
530}
531
532DLLEXPORT uint8_t *trace_get_destination_mac(libtrace_packet_t *packet) {
533        void *link = trace_get_link(packet);
534        libtrace_80211_t *wifi;
535        libtrace_ether_t *ethptr = (libtrace_ether_t*)link;
536        if (!link)
537                return NULL;
538        switch (trace_get_link_type(packet)) {
539                case TRACE_TYPE_80211:
540                        wifi=(libtrace_80211_t*)link;
541                        return (uint8_t*)&wifi->mac1;
542                case TRACE_TYPE_80211_PRISM:
543                        wifi=(libtrace_80211_t*)((char*)link+144);
544                        return (uint8_t*)&wifi->mac1;
545                case TRACE_TYPE_ETH:
546                case TRACE_TYPE_LEGACY_ETH:
547                        return (uint8_t*)&ethptr->ether_dhost;
548                case TRACE_TYPE_LEGACY_ATM:
549                case TRACE_TYPE_LEGACY:
550                case TRACE_TYPE_LEGACY_POS:
551                case TRACE_TYPE_NONE:
552                case TRACE_TYPE_ATM:
553                case TRACE_TYPE_HDLC_POS:
554                case TRACE_TYPE_LINUX_SLL:
555                case TRACE_TYPE_PFLOG:
556                        /* No MAC address */
557                        return NULL;
558        }
559        fprintf(stderr,"Not implemented\n");
560        assert(0);
561        return NULL;
562}
563
564DLLEXPORT struct sockaddr *trace_get_source_address(const libtrace_packet_t *packet, 
565                struct sockaddr *addr)
566{
567        uint16_t proto;
568        uint32_t remaining;
569        void *transport;
570        static struct sockaddr_storage dummy;
571
572        if (!addr)
573                addr=(struct sockaddr*)&dummy;
574
575        remaining = trace_get_capture_length(packet);
576
577        transport = trace_get_payload_from_link(
578                        trace_get_link(packet),
579                        trace_get_link_type(packet),
580                        &proto,
581                        &remaining);
582
583        if (!transport)
584                return false;
585
586        transport = trace_get_vlan_payload_from_ethernet_payload(transport,
587                        &proto,
588                        &remaining);
589
590        if (!transport)
591                return false;
592
593        switch (proto) {
594                case 0x0800: /* IPv4 */
595                {
596                        struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
597                        libtrace_ip_t *ip = (libtrace_ip_t*)transport;
598                        addr4->sin_family=AF_INET;
599                        addr4->sin_port=0;
600                        addr4->sin_addr=ip->ip_src;
601                        return addr;
602                }
603                case 0x86DD: /* IPv6 */
604                {
605                        struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
606                        libtrace_ip6_t *ip6 = (libtrace_ip6_t*)transport;
607                        addr6->sin6_family=AF_INET6;
608                        addr6->sin6_port=0;
609                        addr6->sin6_flowinfo=0;
610                        addr6->sin6_addr=ip6->ip_src;
611                        return addr;
612                }
613                default:
614                        return NULL;
615        }
616}
617
618DLLEXPORT struct sockaddr *trace_get_destination_address(const libtrace_packet_t *packet, 
619                struct sockaddr *addr)
620{
621        uint16_t proto;
622        uint32_t remaining;
623        void *transport;
624        static struct sockaddr_storage dummy;
625
626        if (!addr)
627                addr=(struct sockaddr*)&dummy;
628
629        remaining = trace_get_capture_length(packet);
630
631        transport = trace_get_payload_from_link(
632                        trace_get_link(packet),
633                        trace_get_link_type(packet),
634                        &proto,
635                        &remaining);
636
637        if (!transport)
638                return false;
639
640        transport = trace_get_vlan_payload_from_ethernet_payload(transport,
641                        &proto,
642                        &remaining);
643
644        if (!transport)
645                return false;
646
647        switch (proto) {
648                case 0x0800: /* IPv4 */
649                {
650                        struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
651                        libtrace_ip_t *ip = (libtrace_ip_t*)transport;
652                        addr4->sin_family=AF_INET;
653                        addr4->sin_port=0;
654                        addr4->sin_addr=ip->ip_dst;
655                        return addr;
656                }
657                case 0x86DD: /* IPv6 */
658                {
659                        struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
660                        libtrace_ip6_t *ip6 = (libtrace_ip6_t*)transport;
661                        addr6->sin6_family=AF_INET6;
662                        addr6->sin6_port=0;
663                        addr6->sin6_flowinfo=0;
664                        addr6->sin6_addr=ip6->ip_dst;
665                        return addr;
666                }
667                default:
668                        return NULL;
669        }
670}
671
672/* parse an ip or tcp option
673 * @param[in,out] ptr   the pointer to the current option
674 * @param[in,out] len   the length of the remaining buffer
675 * @param[out] type     the type of the option
676 * @param[out] optlen   the length of the option
677 * @param[out] data     the data of the option
678 *
679 * @returns bool true if there is another option (and the fields are filled in)
680 *               or false if this was the last option.
681 *
682 * This updates ptr to point to the next option after this one, and updates
683 * len to be the number of bytes remaining in the options area.  Type is updated
684 * to be the code of this option, and data points to the data of this option,
685 * with optlen saying how many bytes there are.
686 *
687 * @note Beware of fragmented packets.
688 * @author Perry Lorier
689 */
690DLLEXPORT int trace_get_next_option(unsigned char **ptr,int *len,
691                        unsigned char *type,
692                        unsigned char *optlen,
693                        unsigned char **data)
694{
695        if (*len<=0)
696                return 0;
697        *type=**ptr;
698        switch(*type) {
699                case 0: /* End of options */
700                        return 0;
701                case 1: /* Pad */
702                        (*ptr)++;
703                        (*len)--;
704                        return 1;
705                default:
706                        *optlen = *(*ptr+1);
707                        if (*optlen<2)
708                                return 0; /* I have no idea wtf is going on
709                                           * with these packets
710                                           */
711                        (*len)-=*optlen;
712                        (*data)=(*ptr+2);
713                        (*ptr)+=*optlen;
714                        if (*len<0)
715                                return 0;
716                        return 1;
717        }
718        assert(0);
719}
720
721
Note: See TracBrowser for help on using the repository browser.