source: lib/protocols.c @ 873558d

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

Fix latent bugs with protocol decodes

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