source: lib/protocols.c @ 1b95fd0

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

Don't wander off the end of the packet when the packet was prematurely snapped
when looking at packets that were snapped before the end of the IPv6 header
when looking for the source/dest port.

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