source: lib/protocols.c @ 84a8828

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

Avoid warnings

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