source: lib/protocols.c @ 180f095

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 180f095 was 180f095, checked in by Scott Raynel <smr26@…>, 14 years ago
  • Deprecate the use of trace_get_link()
  • Replace trace_get_link() with trace_get_packet_buffer()
  • Introduce new API for dealing with metadata headers such as Radiotap or Linux SLL
  • Introduce trace_get_layer2() which returns the start of the layer 2 header, which is usually the start of the packet as it was seen on the wire.
  • Property mode set to 100644
File size: 25.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 <assert.h>
8#include <stdio.h>
9
10#ifndef WIN32
11#include <net/if_arp.h>
12#endif
13
14#ifndef ARPHRD_ETHER
15#define ARPHRD_ETHER    1               /* Ethernet 10/100Mbps.  */
16#endif
17
18#ifndef ARPHRD_PPP
19#define ARPHRD_PPP      512
20#endif
21
22
23static void *trace_get_payload_from_llcsnap(void *link,
24                uint16_t *type, uint32_t *remaining);
25
26/* Returns the payload from 802.3 ethernet.  Type optionally returned in
27 * "type" in host byte order.  This will return a vlan header.
28 */
29static void *trace_get_payload_from_ethernet(void *ethernet, 
30                uint16_t *type,
31                uint32_t *remaining)
32{
33        libtrace_ether_t *eth = (libtrace_ether_t*)ethernet;
34
35        if (remaining) {
36                if (*remaining < sizeof(*eth))
37                        return NULL;
38                *remaining-=sizeof(*eth);
39        }
40
41        if (type)
42                *type = ntohs(eth->ether_type);
43
44        return (void*)((char *)eth + sizeof(*eth));
45}
46
47/* skip any 802.1q headers if necessary
48 * type is input/output
49 */
50void *trace_get_vlan_payload_from_ethernet_payload(void *ethernet, uint16_t *type,
51                uint32_t *remaining)
52{
53        assert(type && "You must pass a type in!");
54
55        if (*type == 0x8100) {
56                libtrace_8021q_t *vlanhdr = (libtrace_8021q_t *)ethernet;
57
58                if (remaining) {
59                        if (*remaining < sizeof(libtrace_8021q_t))
60                                return NULL;
61
62                        *remaining=*remaining-sizeof(libtrace_8021q_t);
63                }
64
65                *type = ntohs(vlanhdr->vlan_ether_type);
66
67                return (void*)((char *)ethernet + sizeof(*vlanhdr));
68        }
69
70        return ethernet;
71}
72
73/* skip any MPLS headers if necessary, guessing what the next type is
74 * type is input/output.  If the next type is "ethernet" this will
75 * return a type of 0x0000.
76 */
77static void *trace_get_mpls_payload_from_ethernet_payload(void *ethernet,
78                uint16_t *type, uint32_t *remaining)
79{
80        assert(type && "You must pass a type in!");
81
82        if (*type == 0x8847) {
83                if ((((char*)ethernet)[2]&0x01)==0) {
84                        *type = 0x8847;
85                }
86                else {
87                        if (!remaining || *remaining>=5) {
88                                switch (((char*)ethernet)[4]&0xF0) {
89                                        case 0x40:
90                                                *type = 0x0800;
91                                                break;
92                                        case 0x60:
93                                                *type = 0x86DD;
94                                                break;
95                                        default:
96                                                /* Ethernet */
97                                                *type = 0;
98                                }
99                        }
100                }
101                ethernet=(char*)ethernet+4;
102                if (remaining) {
103                        if (*remaining<4)
104                                return NULL;
105                        else
106                                *remaining-=4;
107                }
108
109
110                return ethernet;
111        }
112        else
113                return NULL;
114}
115
116static void *trace_get_payload_from_80211(void *link, uint16_t *type, uint32_t *remaining)
117{
118        libtrace_80211_t *wifi;
119        uint16_t *eth; /* ethertype */
120        int8_t extra = 0; /* how many QoS bytes to skip */
121       
122        if (remaining && *remaining < sizeof(libtrace_80211_t))
123                return NULL;
124
125        wifi=(libtrace_80211_t*)link;
126
127        /* Data packet? */
128        if (wifi->type != 2) {
129                return NULL;
130        }
131
132        /* If FromDS and ToDS are both set then we have a four-address
133         * frame. Otherwise we have a three-address frame */
134        if (!(wifi->to_ds && wifi->from_ds)) 
135                extra -= 6; 
136       
137        /* Indicates QoS field present, see IEEE802.11e-2005 pg 21 */
138        if (wifi->subtype & 0x8) 
139                extra += 2;
140
141        if (remaining && *remaining < sizeof(*eth))
142                return NULL;
143
144        eth=(uint16_t *)((char*)wifi+sizeof(*wifi)+extra);
145       
146        if (*eth == 0xaaaa)
147                /* Payload contains an 802.2 LLC/SNAP frame */
148                return trace_get_payload_from_llcsnap((void *)eth, type, remaining);
149                       
150        /* Otherwise we assume an Ethernet II frame */
151        if (type) *type=ntohs(*eth);
152        if (remaining) *remaining = *remaining - sizeof(libtrace_80211_t) - extra - sizeof(*eth);
153       
154        return (void*)((char*)eth+sizeof(*eth));
155}
156
157/* NB: type is returned as an ARPHRD_ type for SLL*/
158void *trace_get_payload_from_linux_sll(void *link,
159                uint16_t *type, uint32_t *remaining) 
160{
161        libtrace_sll_header_t *sll;
162
163        sll = (libtrace_sll_header_t*) link;
164
165        if (remaining) {
166                if (*remaining < sizeof(*sll))
167                        return NULL;
168                *remaining-=sizeof(*sll);
169        }
170
171        /* What kind of wacked out header, has this in host order?! */
172        if (type) *type = ntohs(sll->hatype);
173
174        return (void*)((char*)sll+sizeof(*sll));
175
176}
177
178DLLEXPORT
179void *trace_get_payload_from_atm(void *link,
180                uint8_t *type, uint32_t *remaining)
181{
182        libtrace_atm_capture_cell_t *cell;
183        if (remaining && *remaining<sizeof(libtrace_atm_capture_cell_t))
184                return NULL;
185        cell=(libtrace_atm_capture_cell_t*)link;
186
187        if (type)
188                *type=cell->pt;
189
190        if (remaining)
191                *remaining-=sizeof(libtrace_atm_capture_cell_t);
192
193        return ((char*)link)+sizeof(libtrace_atm_capture_cell_t);
194}
195
196static void *trace_get_payload_from_llcsnap(void *link,
197                uint16_t *type, uint32_t *remaining)
198{
199        /* 64 byte capture. */
200        libtrace_llcsnap_t *llc = (libtrace_llcsnap_t*)link;
201
202        if (remaining) {
203                if (*remaining < sizeof(libtrace_llcsnap_t))
204                        return NULL;
205                *remaining-=(sizeof(libtrace_llcsnap_t));
206        }
207
208        llc = (libtrace_llcsnap_t*)((char *)llc);
209
210        if (type) *type = ntohs(llc->type);
211
212        return (void*)((char*)llc+sizeof(*llc));
213}
214
215static void *trace_get_payload_from_ppp(void *link, 
216                uint16_t *type, uint32_t *remaining)
217{
218        /* 64 byte capture. */
219        libtrace_ppp_t *ppp = (libtrace_ppp_t*)link;
220
221        if (remaining) {
222                if (*remaining < sizeof(libtrace_ppp_t))
223                        return NULL;
224                *remaining-=sizeof(libtrace_ppp_t);
225        }
226
227        if (type) {
228                switch(ntohs(ppp->protocol)) {
229                        case 0x0021: *type = 0x0800; break;
230                }
231        }
232
233
234        return (void*)((char *)ppp+sizeof(*ppp));
235}
236
237static void *trace_get_payload_from_pflog(void *link,
238                uint16_t *type, uint32_t *remaining)
239{
240        libtrace_pflog_header_t *pflog = (libtrace_pflog_header_t*)link;
241    if (remaining) {
242                if (*remaining<sizeof(*pflog)) 
243                        return NULL;
244                *remaining-=sizeof(*pflog);
245        }
246        if (type) {
247                switch(pflog->af) {
248                        case AF_INET6: *type=0x86DD; break;
249                        case AF_INET:  *type=0x0800; break;
250                        default:
251                                      /* Unknown */
252                                      return NULL;
253                }
254        }
255        return (void*)((char*)pflog+ sizeof(*pflog));
256}
257
258/* Returns the 'payload' of the prism header, which is the 802.11 frame */
259static void *trace_get_payload_from_prism (void *link,
260                uint16_t *type, uint32_t *remaining)
261{
262        if (remaining) {
263                if (*remaining<144) 
264                        return NULL;
265                *remaining-=144;
266        }
267
268        if (type) *type = TRACE_TYPE_80211;
269
270        return (void *) ((char*)link+144);
271}
272
273/* Returns the 'payload' of the radiotap header, which is the 802.11 frame */
274static void *trace_get_payload_from_radiotap (void *link, 
275                uint16_t *type, uint32_t *remaining)
276{
277        struct libtrace_radiotap_t *rtap = (struct libtrace_radiotap_t*)link;
278        uint16_t rtaplen = bswap_le_to_host16(rtap->it_len);
279        if (remaining) {
280                if (*remaining < rtaplen)
281                        return NULL;
282                *remaining -= rtaplen;
283        }
284
285        if (type) *type = TRACE_TYPE_80211;
286
287        return (void*) ((char*)link + rtaplen);
288}
289
290void *trace_get_payload_from_link(void *link, libtrace_linktype_t linktype, 
291                uint16_t *type, uint32_t *remaining)
292{
293        void *l = NULL;
294        uint16_t dummytype;
295       
296        switch(linktype) {
297                case TRACE_TYPE_80211_PRISM:
298                        l = trace_get_payload_from_prism(link,type,remaining);
299                        return (l ? trace_get_payload_from_link(l, TRACE_TYPE_80211, type, remaining) : NULL);
300                case TRACE_TYPE_80211_RADIO:
301                        l = trace_get_payload_from_radiotap(link,type,remaining);
302                        return (l ? trace_get_payload_from_link(l, TRACE_TYPE_80211, type, remaining) : NULL);
303                case TRACE_TYPE_80211:
304                        return trace_get_payload_from_80211(link,type,remaining);
305
306                case TRACE_TYPE_ETH:
307                        return trace_get_payload_from_ethernet(link,type,remaining);
308                case TRACE_TYPE_NONE:
309                        if ((*(char*)link&0xF0) == 0x40)
310                                *type=0x0800;
311                        else if ((*(char*)link&0xF0) == 0x60)
312                                *type=0x86DD;
313                        return link; /* I love the simplicity */
314                case TRACE_TYPE_LINUX_SLL:
315                        l = trace_get_payload_from_linux_sll(link,&dummytype,remaining);
316                        if (type) *type = dummytype;
317                        return (l ? trace_get_payload_from_link(l,
318                                                arphrd_type_to_libtrace(dummytype), type, remaining) : NULL);
319                       
320                case TRACE_TYPE_PFLOG:
321                        return trace_get_payload_from_pflog(link,type,remaining);
322                case TRACE_TYPE_PPP:
323                        return trace_get_payload_from_ppp(link,type,remaining);
324                case TRACE_TYPE_ATM:
325                        l=trace_get_payload_from_atm(link,NULL,remaining);
326                        return (l ? trace_get_payload_from_llcsnap(l,
327                                                type, remaining):NULL);
328                case TRACE_TYPE_DUCK:
329                        return NULL; /* duck packets have no payload! */
330                case TRACE_TYPE_METADATA:
331                        return NULL; /* The payload is in these packets does
332                                        not correspond to a genuine link-layer
333                                        */
334                default:
335                        break;
336        }
337        fprintf(stderr, "Don't understand link layer type %i in trace_get_payload_from_link()\n",
338                linktype);
339        return NULL;
340}
341
342libtrace_ip_t *trace_get_ip(libtrace_packet_t *packet) 
343{
344        uint16_t ethertype;
345        void *ret;
346
347        uint32_t remaining = trace_get_capture_length(packet);
348
349        ret = trace_get_layer3(packet,&ethertype,&remaining);
350
351        if (!ret || ethertype!=0x0800)
352                return NULL;
353
354        /* Not an IPv4 packet */
355        if (((libtrace_ip_t*)ret)->ip_v != 4)
356                return NULL;
357
358        return (libtrace_ip_t*)ret;
359}
360
361libtrace_ip6_t *trace_get_ip6(libtrace_packet_t *packet) 
362{
363        uint16_t ethertype;
364        void *ret;
365
366        uint32_t remaining = trace_get_capture_length(packet);
367
368        ret = trace_get_layer3(packet,&ethertype,&remaining);
369
370        if (!ret || ethertype!=0x86DD)
371                return NULL;
372
373        return (libtrace_ip6_t*)ret;
374}
375
376#define SW_IP_OFFMASK 0xff1f
377
378DLLEXPORT void *trace_get_payload_from_ip(libtrace_ip_t *ipptr, uint8_t *prot,
379                uint32_t *remaining) 
380{
381        void *trans_ptr = 0;
382
383        if ((ipptr->ip_off & SW_IP_OFFMASK) != 0) {
384                return NULL;
385        }
386
387        if (remaining) {
388                if (*remaining<(ipptr->ip_hl*4U)) {
389                        return NULL;
390                }
391                *remaining-=(ipptr->ip_hl * 4);
392        }
393
394        trans_ptr = (void *)((char *)ipptr + (ipptr->ip_hl * 4));
395
396        if (prot) *prot = ipptr->ip_p;
397
398        return trans_ptr;
399}
400
401void *trace_get_payload_from_ip6(libtrace_ip6_t *ipptr, uint8_t *prot,
402                uint32_t *remaining) 
403{
404        void *payload = (char*)ipptr+sizeof(libtrace_ip6_t);
405        uint8_t nxt = ipptr->nxt;
406
407        if (remaining) {
408                if (*remaining<sizeof(libtrace_ip6_t))
409                        return NULL;
410                *remaining-=sizeof(libtrace_ip6_t);
411        }
412
413        while(1) {
414                switch (nxt) {
415                        case 0: /* hop by hop options */
416                        case 43: /* routing */
417                        case 44: /* fragment */
418                        case 50: /* ESP */
419                        case 51: /* AH */
420                        case 60: /* Destination options */
421                                {
422                                        uint16_t len=((libtrace_ip6_ext_t*)payload)->len
423                                        +sizeof(libtrace_ip6_ext_t);
424
425                                        if (remaining) {
426                                                if (*remaining < len) {
427                                                        /* Snap too short */
428                                                        return NULL;
429                                                }
430                                                *remaining-=len;
431                                        }
432
433                                        payload=(char*)payload+len;
434                                        nxt=((libtrace_ip6_ext_t*)payload)->nxt;
435                                        continue;
436                                }
437                        default:
438                                if (prot) *prot=nxt;
439                                return payload;
440                }
441        }
442}
443
444DLLEXPORT void *trace_get_packet_meta(const libtrace_packet_t *packet, 
445                libtrace_linktype_t *linktype,
446                uint32_t *remaining)
447{
448        uint32_t dummyrem = trace_get_capture_length(packet);
449
450        assert(packet != NULL);
451        assert(linktype != NULL);
452       
453        if (remaining == NULL) 
454                remaining = &dummyrem;
455       
456        void *pktbuf = trace_get_packet_buffer(packet, linktype, remaining);
457        switch (*linktype) {
458                case TRACE_TYPE_LINUX_SLL:
459                case TRACE_TYPE_80211_RADIO:
460                case TRACE_TYPE_80211_PRISM:
461                        return pktbuf;
462                case TRACE_TYPE_HDLC_POS:
463                case TRACE_TYPE_ETH:
464                case TRACE_TYPE_ATM:
465                case TRACE_TYPE_80211:
466                case TRACE_TYPE_NONE:
467                case TRACE_TYPE_PFLOG:
468                case TRACE_TYPE_POS:
469                case TRACE_TYPE_AAL5:
470                case TRACE_TYPE_DUCK:
471                case TRACE_TYPE_LLCSNAP:
472                case TRACE_TYPE_PPP:
473                case TRACE_TYPE_METADATA:
474                        return NULL;
475        }
476}
477
478DLLEXPORT void *trace_get_payload_from_meta(const void *meta,
479                libtrace_linktype_t *linktype,
480                uint32_t *remaining)
481{
482        void *nexthdr; 
483        uint16_t arphrd;
484       
485        assert(meta != NULL);
486        assert(linktype != NULL);
487        assert(remaining != NULL);
488       
489        switch(*linktype) {
490                case TRACE_TYPE_LINUX_SLL:
491                        nexthdr = trace_get_payload_from_linux_sll(meta,
492                                        &arphrd, remaining);
493                        *linktype = arphrd_type_to_libtrace(arphrd);
494                        return nexthdr;
495                case TRACE_TYPE_80211_RADIO:
496                        nexthdr = trace_get_payload_from_radiotap(meta,
497                                        linktype, remaining);
498                        return nexthdr;
499                case TRACE_TYPE_80211_PRISM:
500                        nexthdr = trace_get_payload_from_prism(meta,
501                                        linktype, remaining);
502                        return nexthdr;
503                case TRACE_TYPE_HDLC_POS:
504                case TRACE_TYPE_ETH:
505                case TRACE_TYPE_ATM:
506                case TRACE_TYPE_80211:
507                case TRACE_TYPE_NONE:
508                case TRACE_TYPE_PFLOG:
509                case TRACE_TYPE_POS:
510                case TRACE_TYPE_AAL5:
511                case TRACE_TYPE_DUCK:
512                case TRACE_TYPE_LLCSNAP:
513                case TRACE_TYPE_PPP:
514                case TRACE_TYPE_METADATA:
515                        /* In this case, the pointer passed in does not point
516                         * to a metadata header and so we cannot get the
517                         * payload.
518                         */
519                        return NULL;
520        }
521}
522
523DLLEXPORT void *trace_get_layer2(const libtrace_packet_t *packet,
524                libtrace_linktype_t *linktype,
525                uint32_t *remaining) 
526{
527        uint32_t dummyrem;
528       
529        assert(packet != NULL);
530        assert(linktype != NULL);
531
532        if (remaining == NULL)
533                remaining = &dummyrem;
534       
535        void *meta = trace_get_packet_meta(packet, linktype, remaining);
536
537        /* If there are no meta-data headers, we just return the start of the
538         * packet buffer, along with the linktype, etc.
539         */
540        if (meta == NULL) 
541                return trace_get_packet_buffer(packet, linktype, remaining);
542       
543        /* If there are meta-data headers, we need to skip over them until we
544         * find a non-meta data header and return that.
545         */
546        for(;;) {
547                void *nexthdr = trace_get_payload_from_meta(meta, 
548                                linktype, remaining);
549                if (nexthdr == NULL)
550                        return meta;
551                meta = nexthdr;
552        }
553}
554
555DLLEXPORT void *trace_get_layer3(libtrace_packet_t *packet,
556                uint16_t *ethertype,
557                uint32_t *remaining)
558{
559        void *iphdr;
560        uint16_t dummy_ethertype;
561        void *link;
562        uint32_t dummy_remaining;
563
564        /* use l3 cache */
565        if (packet->l3_header)
566        {
567                *ethertype = packet->l3_ethertype;
568                *remaining -= (packet->l3_header - trace_get_link(packet));
569                return packet->l3_header;
570        }
571
572        if (!ethertype) ethertype=&dummy_ethertype;
573
574        if (!remaining) remaining=&dummy_remaining;
575
576        *remaining = trace_get_capture_length(packet);
577
578        link=trace_get_link(packet);
579
580        if (!link)
581                return NULL;
582
583        iphdr = trace_get_payload_from_link(
584                        link,
585                        trace_get_link_type(packet),
586                        ethertype,
587                        remaining);
588
589        if (!iphdr)
590                return NULL;
591
592        for(;;) {
593                switch(*ethertype) {
594                case 0x8100: /* VLAN */
595                        iphdr=trace_get_vlan_payload_from_ethernet_payload(
596                                          iphdr,ethertype,NULL);
597                        continue;
598                case 0x8847: /* MPLS */
599                        iphdr=trace_get_mpls_payload_from_ethernet_payload(
600                                          iphdr,ethertype,NULL);
601
602                        if (iphdr && ethertype == 0x0) {
603                                iphdr=trace_get_payload_from_ethernet(
604                                                iphdr,ethertype,NULL);
605                        }
606                        continue;
607                default:
608                        break;
609                }
610
611                break;
612        }
613
614        /* Store values in the cache for later */
615        packet->l3_ethertype = *ethertype;
616        packet->l3_header = iphdr;
617
618        return iphdr;
619}
620
621DLLEXPORT void *trace_get_transport(libtrace_packet_t *packet, 
622                uint8_t *proto,
623                uint32_t *remaining
624                ) 
625{
626        uint8_t dummy_proto;
627        uint16_t ethertype;
628        uint32_t dummy_remaining;
629        void *transport;
630
631        if (!proto) proto=&dummy_proto;
632
633        if (!remaining) remaining=&dummy_remaining;
634
635        *remaining = trace_get_capture_length(packet);
636
637        transport = trace_get_layer3(packet,&ethertype,remaining);
638
639        if (!transport)
640                return NULL;
641
642        switch (ethertype) {
643                case 0x0800: /* IPv4 */
644                        transport=trace_get_payload_from_ip(
645                                (libtrace_ip_t*)transport, proto, remaining);
646                        /* IPv6 */
647                        if (transport && *proto == 41) {
648                                transport=trace_get_payload_from_ip6(
649                                 (libtrace_ip6_t*)transport, proto,remaining);
650                        }
651                        return transport;
652                case 0x86DD: /* IPv6 */
653                        return trace_get_payload_from_ip6(
654                                (libtrace_ip6_t*)transport, proto, remaining);
655                       
656                default:
657                        *proto=0;
658                        return NULL;
659        }
660
661}
662
663DLLEXPORT libtrace_tcp_t *trace_get_tcp(libtrace_packet_t *packet) {
664        uint8_t proto;
665        libtrace_tcp_t *tcp;
666
667        tcp=(libtrace_tcp_t*)trace_get_transport(packet,&proto,NULL);
668
669        if (!tcp || proto != 6)
670                return NULL;
671
672        return (libtrace_tcp_t*)tcp;
673}
674
675DLLEXPORT libtrace_tcp_t *trace_get_tcp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
676{
677        libtrace_tcp_t *tcpptr = 0;
678
679        if (ip->ip_p == 6)  {
680                tcpptr = (libtrace_tcp_t *)
681                        trace_get_payload_from_ip(ip, NULL, remaining);
682        }
683
684        return tcpptr;
685}
686
687DLLEXPORT libtrace_udp_t *trace_get_udp(libtrace_packet_t *packet) {
688        uint8_t proto;
689        libtrace_udp_t *udp;
690
691        udp=(libtrace_udp_t*)trace_get_transport(packet,&proto,NULL);
692
693        if (!udp || proto != 17)
694                return NULL;
695
696        return udp;
697}
698
699DLLEXPORT libtrace_udp_t *trace_get_udp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
700{
701        libtrace_udp_t *udpptr = 0;
702
703        if (ip->ip_p == 17) {
704                udpptr = (libtrace_udp_t *)
705                        trace_get_payload_from_ip(ip, NULL, remaining);
706        }
707
708        return udpptr;
709}
710
711DLLEXPORT libtrace_icmp_t *trace_get_icmp(libtrace_packet_t *packet) {
712        uint8_t proto;
713        libtrace_icmp_t *icmp;
714
715        icmp=(libtrace_icmp_t*)trace_get_transport(packet,&proto,NULL);
716
717        if (!icmp || proto != 1)
718                return NULL;
719
720        return icmp;
721}
722
723DLLEXPORT libtrace_icmp_t *trace_get_icmp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
724{
725        libtrace_icmp_t *icmpptr = 0;
726
727        if (ip->ip_p == 1)  {
728                icmpptr = (libtrace_icmp_t *)trace_get_payload_from_ip(ip, 
729                                NULL, remaining);
730        }
731
732        return icmpptr;
733}
734
735DLLEXPORT void *trace_get_payload_from_udp(libtrace_udp_t *udp, uint32_t *remaining)
736{
737        if (remaining) {
738                if (*remaining < sizeof(libtrace_udp_t))
739                        return NULL;
740                *remaining-=sizeof(libtrace_udp_t);
741        }
742        return (void*)((char*)udp+sizeof(libtrace_udp_t));
743}
744
745DLLEXPORT void *trace_get_payload_from_tcp(libtrace_tcp_t *tcp, uint32_t *remaining)
746{
747        unsigned int dlen = tcp->doff*4;
748        if (remaining) {
749                if (*remaining < dlen)
750                        return NULL;
751                *remaining-=dlen;
752        }
753        return (void *)((char *)tcp+dlen);
754}
755
756DLLEXPORT void *trace_get_payload_from_icmp(libtrace_icmp_t *icmp, uint32_t *remaining)
757{
758        if (remaining) {
759                if (*remaining < sizeof(libtrace_icmp_t))
760                        return NULL;
761                *remaining-=sizeof(libtrace_icmp_t);
762        }
763        return (char*)icmp+sizeof(libtrace_icmp_t);
764}
765
766struct ports_t {
767        uint16_t src;
768        uint16_t dst;
769};
770
771/* Return the client port
772 */
773DLLEXPORT uint16_t trace_get_source_port(const libtrace_packet_t *packet)
774{
775        uint32_t remaining;
776        const struct ports_t *port = 
777                (const struct ports_t*)trace_get_transport((libtrace_packet_t*)packet,
778                        NULL, &remaining);
779
780        /* snapped too early */
781        if (remaining<2)
782                return 0;
783
784        if (port)
785                return ntohs(port->src);
786        else
787                return 0;
788}
789
790/* Same as get_source_port except use the destination port */
791DLLEXPORT uint16_t trace_get_destination_port(const libtrace_packet_t *packet)
792{
793        uint32_t remaining;
794        struct ports_t *port = 
795                (struct ports_t*)trace_get_transport((libtrace_packet_t*)packet,
796                        NULL, &remaining);
797        /* snapped to early */
798        if (remaining<4)
799                return 0;
800
801        if (port)
802                return ntohs(port->dst);
803        else
804                return 0;
805}
806
807/* Take a pointer to the start of an IEEE 802.11 MAC frame and return a pointer
808 * to the source MAC address. 
809 * If the frame does not contain a sender address, e.g. ACK frame, return NULL.
810 * If the frame is a 4-address WDS frame, return TA, i.e. addr2.
811 * NB: This function decodes the 802.11 header, so it assumes that there are no
812 * bit-errors. If there are, all bets are off.
813 */
814static
815uint8_t *get_source_mac_from_wifi(void *wifi) {
816        if (wifi == NULL) return NULL;
817        struct libtrace_80211_t *w = (struct libtrace_80211_t *) wifi;
818       
819        /* If the frame is of type CTRL */
820        if (w->type == 0x1) 
821                /* If bit 2 of the subtype field is zero, this indicates that
822                 * there is no transmitter address, i.e. the frame is either an
823                 * ACK or a CTS frame */
824                if ((w->subtype & 0x2) == 0)
825                        return NULL;
826
827        /* Always return the address of the transmitter, i.e. address 2 */
828        return (uint8_t *) &w->mac2;
829}
830
831static
832uint8_t *__trace_get_source_mac(void *link, libtrace_linktype_t *linktype, uint32_t *rem) {
833        libtrace_ether_t *ethptr = (libtrace_ether_t *) link;
834        uint16_t arphrd;
835        if (!link)
836                return NULL;
837       
838        switch (*linktype) {
839                case TRACE_TYPE_ETH:
840                        return (uint8_t *)&ethptr->ether_shost;
841                case TRACE_TYPE_80211:
842                        return get_source_mac_from_wifi(link);
843                case TRACE_TYPE_80211_RADIO:
844                        link = trace_get_payload_from_radiotap(
845                                        link, linktype, rem);
846                        return __trace_get_source_mac(link, linktype, rem);
847                case TRACE_TYPE_80211_PRISM:
848                        link = trace_get_payload_from_prism(
849                                        link, linktype, rem);
850                        return __trace_get_source_mac(link, linktype, rem);
851                case TRACE_TYPE_LINUX_SLL:
852                        link = trace_get_payload_from_linux_sll(
853                                        link, &arphrd, rem);
854                        *linktype = arphrd_type_to_libtrace(arphrd);
855                        return __trace_get_source_mac(link, linktype, rem);
856                case TRACE_TYPE_POS:
857                case TRACE_TYPE_NONE:
858                case TRACE_TYPE_HDLC_POS:
859                case TRACE_TYPE_PFLOG:
860                case TRACE_TYPE_ATM:
861                case TRACE_TYPE_DUCK:
862                case TRACE_TYPE_METADATA:
863                        return NULL;
864                default:
865                        break;
866        }
867        fprintf(stderr,"%s not implemented for linktype %i\n", __func__, *linktype);
868        assert(0);
869        return NULL;
870}
871
872DLLEXPORT uint8_t *trace_get_source_mac(libtrace_packet_t *packet) {
873        if (packet == NULL) 
874                return NULL;
875        void *link = trace_get_link(packet);
876        uint32_t len = trace_get_capture_length(packet);
877        libtrace_linktype_t lt = trace_get_link_type(packet);
878        return __trace_get_source_mac(link, &lt, &len);
879}
880
881DLLEXPORT uint8_t *trace_get_destination_mac(libtrace_packet_t *packet) {
882        void *link = trace_get_link(packet);
883        libtrace_80211_t *wifi;
884        libtrace_ether_t *ethptr = (libtrace_ether_t*)link;
885        if (!link)
886                return NULL;
887        switch (trace_get_link_type(packet)) {
888                case TRACE_TYPE_80211:
889                        wifi=(libtrace_80211_t*)link;
890                        return (uint8_t*)&wifi->mac1;
891                case TRACE_TYPE_80211_RADIO:
892                        wifi=(libtrace_80211_t*)trace_get_payload_from_radiotap(
893                                        link,NULL,NULL);
894                        return (uint8_t*)&wifi->mac1;
895                case TRACE_TYPE_80211_PRISM:
896                        wifi=(libtrace_80211_t*)((char*)link+144);
897                        return (uint8_t*)&wifi->mac1;
898                case TRACE_TYPE_ETH:
899                        return (uint8_t*)&ethptr->ether_dhost;
900                case TRACE_TYPE_POS:
901                case TRACE_TYPE_NONE:
902                case TRACE_TYPE_ATM:
903                case TRACE_TYPE_HDLC_POS:
904                case TRACE_TYPE_LINUX_SLL:
905                case TRACE_TYPE_PFLOG:
906                case TRACE_TYPE_DUCK:
907                case TRACE_TYPE_METADATA:
908                        /* No MAC address */
909                        return NULL;
910                default:
911                        break;
912        }
913        fprintf(stderr,"Not implemented\n");
914        assert(0);
915        return NULL;
916}
917
918DLLEXPORT struct sockaddr *trace_get_source_address(
919                const libtrace_packet_t *packet, struct sockaddr *addr)
920{
921        uint16_t ethertype;
922        uint32_t remaining;
923        void *l3;
924        struct ports_t *ports;
925        static struct sockaddr_storage dummy;
926
927        if (!addr)
928                addr=(struct sockaddr*)&dummy;
929
930        remaining = trace_get_capture_length(packet);
931
932        l3 = trace_get_layer3(packet,&ethertype,&remaining);
933
934        if (!l3)
935                return NULL;
936
937        switch (ethertype) {
938                case 0x0800: /* IPv4 */
939                {
940                        struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
941                        libtrace_ip_t *ip = (libtrace_ip_t*)l3;
942                        ports = (struct ports_t*)
943                                trace_get_payload_from_ip(ip,NULL,&remaining);
944                        addr4->sin_family=AF_INET;
945                        if (ports && remaining>=sizeof(*ports))
946                                addr4->sin_port=ports->src;
947                        else
948                                addr4->sin_port=0;
949                        addr4->sin_addr=ip->ip_src;
950                        return addr;
951                }
952                case 0x86DD: /* IPv6 */
953                {
954                        struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
955                        libtrace_ip6_t *ip6 = (libtrace_ip6_t*)l3;
956                        ports = (struct ports_t*)
957                                trace_get_payload_from_ip6(ip6,NULL,&remaining);
958                        addr6->sin6_family=AF_INET6;
959                        if (ports && remaining>=sizeof(*ports))
960                                addr6->sin6_port=ports->src;
961                        else
962                                addr6->sin6_port=0;
963                        addr6->sin6_flowinfo=0;
964                        addr6->sin6_addr=ip6->ip_src;
965                        return addr;
966                }
967                default:
968                        return NULL;
969        }
970}
971
972DLLEXPORT struct sockaddr *trace_get_destination_address(
973                const libtrace_packet_t *packet, struct sockaddr *addr)
974{
975        uint16_t ethertype;
976        uint32_t remaining;
977        void *l3;
978        struct ports_t *ports;
979        static struct sockaddr_storage dummy;
980
981        if (!addr)
982                addr=(struct sockaddr*)&dummy;
983
984        remaining = trace_get_capture_length(packet);
985
986        l3 = trace_get_layer3(packet,&ethertype,&remaining);
987
988        if (!l3)
989                return NULL;
990
991        switch (ethertype) {
992                case 0x0800: /* IPv4 */
993                {
994                        struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
995                        libtrace_ip_t *ip = (libtrace_ip_t*)l3;
996                        ports = (struct ports_t*)
997                                trace_get_payload_from_ip(ip,NULL,&remaining);
998                        addr4->sin_family=AF_INET;
999                        if (ports && remaining>=sizeof(*ports))
1000                                addr4->sin_port=ports->dst;
1001                        else
1002                                addr4->sin_port=0;
1003                        addr4->sin_addr=ip->ip_dst;
1004                        return addr;
1005                }
1006                case 0x86DD: /* IPv6 */
1007                {
1008                        struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
1009                        libtrace_ip6_t *ip6 = (libtrace_ip6_t*)l3;
1010                        ports = (struct ports_t*)
1011                                trace_get_payload_from_ip6(ip6,NULL,&remaining);
1012                        addr6->sin6_family=AF_INET6;
1013                        if (ports && remaining>=sizeof(*ports))
1014                                addr6->sin6_port=ports->dst;
1015                        else
1016                                addr6->sin6_port=0;
1017                        addr6->sin6_flowinfo=0;
1018                        addr6->sin6_addr=ip6->ip_dst;
1019                        return addr;
1020                }
1021                default:
1022                        return NULL;
1023        }
1024}
1025
1026/* parse an ip or tcp option
1027 * @param[in,out] ptr   the pointer to the current option
1028 * @param[in,out] len   the length of the remaining buffer
1029 * @param[out] type     the type of the option
1030 * @param[out] optlen   the length of the option
1031 * @param[out] data     the data of the option
1032 *
1033 * @returns bool true if there is another option (and the fields are filled in)
1034 *               or false if this was the last option.
1035 *
1036 * This updates ptr to point to the next option after this one, and updates
1037 * len to be the number of bytes remaining in the options area.  Type is updated
1038 * to be the code of this option, and data points to the data of this option,
1039 * with optlen saying how many bytes there are.
1040 *
1041 * @note Beware of fragmented packets.
1042 * @author Perry Lorier
1043 */
1044DLLEXPORT int trace_get_next_option(unsigned char **ptr,int *len,
1045                        unsigned char *type,
1046                        unsigned char *optlen,
1047                        unsigned char **data)
1048{
1049        if (*len<=0)
1050                return 0;
1051        *type=**ptr;
1052        switch(*type) {
1053                case 0: /* End of options */
1054                        return 0;
1055                case 1: /* Pad */
1056                        (*ptr)++;
1057                        (*len)--;
1058                        return 1;
1059                default:
1060                        *optlen = *(*ptr+1);
1061                        if (*optlen<2)
1062                                return 0; /* I have no idea wtf is going on
1063                                           * with these packets
1064                                           */
1065                        (*len)-=*optlen;
1066                        (*data)=(*ptr+2);
1067                        (*ptr)+=*optlen;
1068                        if (*len<0)
1069                                return 0;
1070                        return 1;
1071        }
1072        assert(0);
1073}
1074
1075
Note: See TracBrowser for help on using the repository browser.