source: lib/protocols.c @ e6d963c

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

Style fixes, get rid of unnecessary "struct"'s

  • 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                        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                        return NULL;
363        }
364
365}
366
367DLLEXPORT libtrace_tcp_t *trace_get_tcp(libtrace_packet_t *packet) {
368        uint8_t proto;
369        libtrace_tcp_t *tcp;
370
371        tcp=(libtrace_tcp_t*)trace_get_transport(packet,&proto,NULL);
372
373        if (!tcp && proto != 6)
374                return NULL;
375
376        return (libtrace_tcp_t*)tcp;
377}
378
379DLLEXPORT libtrace_tcp_t *trace_get_tcp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
380{
381        libtrace_tcp_t *tcpptr = 0;
382
383        if (ip->ip_p == 6)  {
384                tcpptr = (libtrace_tcp_t *)
385                        trace_get_payload_from_ip(ip, NULL, remaining);
386        }
387
388        return tcpptr;
389}
390
391DLLEXPORT libtrace_udp_t *trace_get_udp(libtrace_packet_t *packet) {
392        uint8_t proto;
393        libtrace_udp_t *udp;
394
395        udp=(libtrace_udp_t*)trace_get_transport(packet,&proto,NULL);
396
397        if (proto != 17)
398                return NULL;
399
400        return udp;
401}
402
403DLLEXPORT libtrace_udp_t *trace_get_udp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
404{
405        libtrace_udp_t *udpptr = 0;
406
407        if (ip->ip_p == 17) {
408                udpptr = (libtrace_udp_t *)
409                        trace_get_payload_from_ip(ip, NULL, remaining);
410        }
411
412        return udpptr;
413}
414
415DLLEXPORT libtrace_icmp_t *trace_get_icmp(libtrace_packet_t *packet) {
416        uint8_t proto;
417        libtrace_icmp_t *icmp;
418
419        icmp=(libtrace_icmp_t*)trace_get_transport(packet,&proto,NULL);
420
421        if (proto != 1)
422                return NULL;
423
424        return icmp;
425}
426
427DLLEXPORT libtrace_icmp_t *trace_get_icmp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
428{
429        libtrace_icmp_t *icmpptr = 0;
430
431        if (ip->ip_p == 1)  {
432                icmpptr = (libtrace_icmp_t *)trace_get_payload_from_ip(ip, 
433                                NULL, remaining);
434        }
435
436        return icmpptr;
437}
438
439DLLEXPORT void *trace_get_payload_from_udp(libtrace_udp_t *udp, uint32_t *remaining)
440{
441        if (remaining) {
442                if (*remaining < sizeof(libtrace_udp_t))
443                        return NULL;
444                *remaining-=sizeof(libtrace_udp_t);
445        }
446        return (void*)((char*)udp+sizeof(libtrace_udp_t));
447}
448
449DLLEXPORT void *trace_get_payload_from_tcp(libtrace_tcp_t *tcp, uint32_t *remaining)
450{
451        unsigned int dlen = tcp->doff*4;
452        if (remaining) {
453                if (*remaining < dlen)
454                        return NULL;
455                *remaining-=dlen;
456        }
457        return tcp+dlen;
458}
459
460DLLEXPORT void *trace_get_payload_from_icmp(libtrace_icmp_t *icmp, uint32_t *remaining)
461{
462        if (remaining) {
463                if (*remaining < sizeof(libtrace_icmp_t))
464                        return NULL;
465                *remaining-=sizeof(libtrace_icmp_t);
466        }
467        return (char*)icmp+sizeof(libtrace_icmp_t);
468}
469
470struct ports_t {
471        uint16_t src;
472        uint16_t dst;
473};
474
475/* Return the client port
476 */
477DLLEXPORT uint16_t trace_get_source_port(const libtrace_packet_t *packet)
478{
479        struct ports_t *port = 
480                (struct ports_t*)trace_get_transport((libtrace_packet_t*)packet,
481                        NULL, NULL);
482
483        if (port)
484                return ntohs(port->src);
485        else
486                return 0;
487}
488
489/* Same as get_source_port except use the destination port */
490DLLEXPORT uint16_t trace_get_destination_port(const libtrace_packet_t *packet)
491{
492        struct ports_t *port = 
493                (struct ports_t*)trace_get_transport((libtrace_packet_t*)packet,
494                        NULL, NULL);
495
496        if (port)
497                return ntohs(port->dst);
498        else
499                return 0;
500}
501
502
503uint8_t *trace_get_source_mac(libtrace_packet_t *packet) {
504        void *link = trace_get_link(packet);
505        libtrace_80211_t *wifi;
506        libtrace_ether_t *ethptr = (libtrace_ether_t*)link;
507        if (!link)
508                return NULL;
509        switch (trace_get_link_type(packet)) {
510                case TRACE_TYPE_80211:
511                        wifi=(libtrace_80211_t*)link;
512                        return (uint8_t*)&wifi->mac2;
513                case TRACE_TYPE_80211_PRISM:
514                        wifi=(libtrace_80211_t*)((char*)link+144);
515                        return (uint8_t*)&wifi->mac2;
516                case TRACE_TYPE_ETH:
517                        return (uint8_t*)&ethptr->ether_shost;
518                case TRACE_TYPE_POS:
519                case TRACE_TYPE_NONE:
520                case TRACE_TYPE_HDLC_POS:
521                case TRACE_TYPE_LINUX_SLL:
522                case TRACE_TYPE_PFLOG:
523                case TRACE_TYPE_ATM:
524                        return NULL;
525        }
526        fprintf(stderr,"Not implemented\n");
527        assert(0);
528        return NULL;
529}
530
531DLLEXPORT uint8_t *trace_get_destination_mac(libtrace_packet_t *packet) {
532        void *link = trace_get_link(packet);
533        libtrace_80211_t *wifi;
534        libtrace_ether_t *ethptr = (libtrace_ether_t*)link;
535        if (!link)
536                return NULL;
537        switch (trace_get_link_type(packet)) {
538                case TRACE_TYPE_80211:
539                        wifi=(libtrace_80211_t*)link;
540                        return (uint8_t*)&wifi->mac1;
541                case TRACE_TYPE_80211_PRISM:
542                        wifi=(libtrace_80211_t*)((char*)link+144);
543                        return (uint8_t*)&wifi->mac1;
544                case TRACE_TYPE_ETH:
545                        return (uint8_t*)&ethptr->ether_dhost;
546                case TRACE_TYPE_POS:
547                case TRACE_TYPE_NONE:
548                case TRACE_TYPE_ATM:
549                case TRACE_TYPE_HDLC_POS:
550                case TRACE_TYPE_LINUX_SLL:
551                case TRACE_TYPE_PFLOG:
552                        /* No MAC address */
553                        return NULL;
554        }
555        fprintf(stderr,"Not implemented\n");
556        assert(0);
557        return NULL;
558}
559
560DLLEXPORT struct sockaddr *trace_get_source_address(const libtrace_packet_t *packet, 
561                struct sockaddr *addr)
562{
563        uint16_t proto;
564        uint32_t remaining;
565        void *transport;
566        static struct sockaddr_storage dummy;
567
568        if (!addr)
569                addr=(struct sockaddr*)&dummy;
570
571        remaining = trace_get_capture_length(packet);
572
573        transport = trace_get_payload_from_link(
574                        trace_get_link(packet),
575                        trace_get_link_type(packet),
576                        &proto,
577                        &remaining);
578
579        if (!transport)
580                return false;
581
582        transport = trace_get_vlan_payload_from_ethernet_payload(transport,
583                        &proto,
584                        &remaining);
585
586        if (!transport)
587                return false;
588
589        switch (proto) {
590                case 0x0800: /* IPv4 */
591                {
592                        struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
593                        libtrace_ip_t *ip = (libtrace_ip_t*)transport;
594                        addr4->sin_family=AF_INET;
595                        addr4->sin_port=0;
596                        addr4->sin_addr=ip->ip_src;
597                        return addr;
598                }
599                case 0x86DD: /* IPv6 */
600                {
601                        struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
602                        libtrace_ip6_t *ip6 = (libtrace_ip6_t*)transport;
603                        addr6->sin6_family=AF_INET6;
604                        addr6->sin6_port=0;
605                        addr6->sin6_flowinfo=0;
606                        addr6->sin6_addr=ip6->ip_src;
607                        return addr;
608                }
609                default:
610                        return NULL;
611        }
612}
613
614DLLEXPORT struct sockaddr *trace_get_destination_address(const libtrace_packet_t *packet, 
615                struct sockaddr *addr)
616{
617        uint16_t proto;
618        uint32_t remaining;
619        void *transport;
620        static struct sockaddr_storage dummy;
621
622        if (!addr)
623                addr=(struct sockaddr*)&dummy;
624
625        remaining = trace_get_capture_length(packet);
626
627        transport = trace_get_payload_from_link(
628                        trace_get_link(packet),
629                        trace_get_link_type(packet),
630                        &proto,
631                        &remaining);
632
633        if (!transport)
634                return false;
635
636        transport = trace_get_vlan_payload_from_ethernet_payload(transport,
637                        &proto,
638                        &remaining);
639
640        if (!transport)
641                return false;
642
643        switch (proto) {
644                case 0x0800: /* IPv4 */
645                {
646                        struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
647                        libtrace_ip_t *ip = (libtrace_ip_t*)transport;
648                        addr4->sin_family=AF_INET;
649                        addr4->sin_port=0;
650                        addr4->sin_addr=ip->ip_dst;
651                        return addr;
652                }
653                case 0x86DD: /* IPv6 */
654                {
655                        struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
656                        libtrace_ip6_t *ip6 = (libtrace_ip6_t*)transport;
657                        addr6->sin6_family=AF_INET6;
658                        addr6->sin6_port=0;
659                        addr6->sin6_flowinfo=0;
660                        addr6->sin6_addr=ip6->ip_dst;
661                        return addr;
662                }
663                default:
664                        return NULL;
665        }
666}
667
668/* parse an ip or tcp option
669 * @param[in,out] ptr   the pointer to the current option
670 * @param[in,out] len   the length of the remaining buffer
671 * @param[out] type     the type of the option
672 * @param[out] optlen   the length of the option
673 * @param[out] data     the data of the option
674 *
675 * @returns bool true if there is another option (and the fields are filled in)
676 *               or false if this was the last option.
677 *
678 * This updates ptr to point to the next option after this one, and updates
679 * len to be the number of bytes remaining in the options area.  Type is updated
680 * to be the code of this option, and data points to the data of this option,
681 * with optlen saying how many bytes there are.
682 *
683 * @note Beware of fragmented packets.
684 * @author Perry Lorier
685 */
686DLLEXPORT int trace_get_next_option(unsigned char **ptr,int *len,
687                        unsigned char *type,
688                        unsigned char *optlen,
689                        unsigned char **data)
690{
691        if (*len<=0)
692                return 0;
693        *type=**ptr;
694        switch(*type) {
695                case 0: /* End of options */
696                        return 0;
697                case 1: /* Pad */
698                        (*ptr)++;
699                        (*len)--;
700                        return 1;
701                default:
702                        *optlen = *(*ptr+1);
703                        if (*optlen<2)
704                                return 0; /* I have no idea wtf is going on
705                                           * with these packets
706                                           */
707                        (*len)-=*optlen;
708                        (*data)=(*ptr+2);
709                        (*ptr)+=*optlen;
710                        if (*len<0)
711                                return 0;
712                        return 1;
713        }
714        assert(0);
715}
716
717
Note: See TracBrowser for help on using the repository browser.