source: lib/protocols.c @ 9bc4689

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

Move everything over to using the newer API's

  • Property mode set to 100644
File size: 26.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 <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(const 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 (const void *link,
260                libtrace_linktype_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 (const void *link, 
275                libtrace_linktype_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,&linktype,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,&linktype,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;
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        /* Shouldn't get here */
478        return NULL;
479}
480
481DLLEXPORT void *trace_get_payload_from_meta(const void *meta,
482                libtrace_linktype_t *linktype,
483                uint32_t *remaining)
484{
485        void *nexthdr; 
486        uint16_t arphrd;
487       
488        assert(meta != NULL);
489        assert(linktype != NULL);
490        assert(remaining != NULL);
491       
492        switch(*linktype) {
493                case TRACE_TYPE_LINUX_SLL:
494                        nexthdr = trace_get_payload_from_linux_sll(meta,
495                                        &arphrd, remaining);
496                        *linktype = arphrd_type_to_libtrace(arphrd);
497                        return nexthdr;
498                case TRACE_TYPE_80211_RADIO:
499                        nexthdr = trace_get_payload_from_radiotap(meta,
500                                        linktype, remaining);
501                        return nexthdr;
502                case TRACE_TYPE_80211_PRISM:
503                        nexthdr = trace_get_payload_from_prism(meta,
504                                        linktype, remaining);
505                        return nexthdr;
506                case TRACE_TYPE_HDLC_POS:
507                case TRACE_TYPE_ETH:
508                case TRACE_TYPE_ATM:
509                case TRACE_TYPE_80211:
510                case TRACE_TYPE_NONE:
511                case TRACE_TYPE_PFLOG:
512                case TRACE_TYPE_POS:
513                case TRACE_TYPE_AAL5:
514                case TRACE_TYPE_DUCK:
515                case TRACE_TYPE_LLCSNAP:
516                case TRACE_TYPE_PPP:
517                case TRACE_TYPE_METADATA:
518                        /* In this case, the pointer passed in does not point
519                         * to a metadata header and so we cannot get the
520                         * payload.
521                         */
522                        return NULL;
523        }
524        /* Shouldn't get here */
525        return NULL;
526}
527
528DLLEXPORT void *trace_get_layer2(const libtrace_packet_t *packet,
529                libtrace_linktype_t *linktype,
530                uint32_t *remaining) 
531{
532        uint32_t dummyrem;
533       
534        assert(packet != NULL);
535        assert(linktype != NULL);
536
537        if (remaining == NULL)
538                remaining = &dummyrem;
539       
540        void *meta = trace_get_packet_meta(packet, linktype, remaining);
541
542        /* If there are no meta-data headers, we just return the start of the
543         * packet buffer, along with the linktype, etc.
544         */
545        if (meta == NULL) 
546                return trace_get_packet_buffer(packet, linktype, remaining);
547       
548        /* If there are meta-data headers, we need to skip over them until we
549         * find a non-meta data header and return that.
550         */
551        for(;;) {
552                void *nexthdr = trace_get_payload_from_meta(meta, 
553                                linktype, remaining);
554                if (nexthdr == NULL)
555                        return meta;
556                meta = nexthdr;
557        }
558}
559
560DLLEXPORT void *trace_get_payload_from_layer2(void *link,
561                libtrace_linktype_t linktype,
562                uint16_t *ethertype,
563                uint32_t *remaining)
564{
565        void *l;
566        switch(linktype) {
567                /* Packet Metadata headers, not layer2 headers */
568                case TRACE_TYPE_80211_PRISM:
569                case TRACE_TYPE_80211_RADIO:
570                case TRACE_TYPE_LINUX_SLL:
571                        return NULL;
572
573                /* duck packets have no payload! */
574                case TRACE_TYPE_DUCK:
575                        return NULL;
576
577                /* The payload is in these packets does
578                   not correspond to a genuine link-layer
579                   */
580                case TRACE_TYPE_METADATA:
581                        return NULL;
582
583                case TRACE_TYPE_80211:
584                        return trace_get_payload_from_80211(link,ethertype,remaining);
585                case TRACE_TYPE_ETH:
586                        return trace_get_payload_from_ethernet(link,ethertype,remaining);
587                case TRACE_TYPE_NONE:
588                        if ((*(char*)link&0xF0) == 0x40)
589                                *ethertype=0x0800;
590                        else if ((*(char*)link&0xF0) == 0x60)
591                                *ethertype=0x86DD;
592                        return link; /* I love the simplicity */
593                case TRACE_TYPE_PFLOG:
594                        return trace_get_payload_from_pflog(link,ethertype,remaining);
595                case TRACE_TYPE_PPP:
596                        return trace_get_payload_from_ppp(link,ethertype,remaining);
597                case TRACE_TYPE_ATM:
598                        l=trace_get_payload_from_atm(link,NULL,remaining);
599                        /* FIXME: We shouldn't skip llcsnap here, we should return
600                         * an ethertype for it (somehow)
601                         */
602                        return (l ? trace_get_payload_from_llcsnap(l,
603                                                ethertype, remaining):NULL);
604                case TRACE_TYPE_LLCSNAP:
605                        return trace_get_payload_from_llcsnap(link,ethertype,remaining);
606
607                /* TODO: Unsupported */
608                case TRACE_TYPE_HDLC_POS:
609                case TRACE_TYPE_POS:
610                case TRACE_TYPE_AAL5:
611                        return NULL;
612        }
613        return NULL;
614
615}
616
617DLLEXPORT void *trace_get_layer3(const libtrace_packet_t *packet,
618                uint16_t *ethertype,
619                uint32_t *remaining)
620{
621        void *iphdr;
622        uint16_t dummy_ethertype;
623        void *link;
624        uint32_t dummy_remaining;
625        libtrace_linktype_t linktype;
626
627        if (!ethertype) ethertype=&dummy_ethertype;
628
629        if (!remaining) remaining=&dummy_remaining;
630
631        /* use l3 cache */
632        if (packet->l3_header)
633        {
634                link = trace_get_packet_buffer(packet,&linktype,remaining);
635
636                if (!link)
637                        return NULL;
638
639                *ethertype = packet->l3_ethertype;
640                *remaining -= (packet->l3_header - link);
641
642                return packet->l3_header;
643        }
644
645        link = trace_get_layer2(packet,&linktype,remaining);
646
647        iphdr = trace_get_payload_from_layer2(
648                        link,
649                        linktype,
650                        ethertype,
651                        remaining);
652
653        if (!iphdr)
654                return NULL;
655
656        for(;;) {
657                switch(*ethertype) {
658                case 0x8100: /* VLAN */
659                        iphdr=trace_get_vlan_payload_from_ethernet_payload(
660                                          iphdr,ethertype,NULL);
661                        continue;
662                case 0x8847: /* MPLS */
663                        iphdr=trace_get_mpls_payload_from_ethernet_payload(
664                                          iphdr,ethertype,NULL);
665
666                        if (iphdr && ethertype == 0x0) {
667                                iphdr=trace_get_payload_from_ethernet(
668                                                iphdr,ethertype,NULL);
669                        }
670                        continue;
671                default:
672                        break;
673                }
674
675                break;
676        }
677
678        /* Store values in the cache for later */
679        /* Cast away constness, nasty, but this is just a cache */
680        ((libtrace_packet_t*)packet)->l3_ethertype = *ethertype;
681        ((libtrace_packet_t*)packet)->l3_header = iphdr;
682
683        return iphdr;
684}
685
686DLLEXPORT void *trace_get_transport(const libtrace_packet_t *packet, 
687                uint8_t *proto,
688                uint32_t *remaining
689                ) 
690{
691        uint8_t dummy_proto;
692        uint16_t ethertype;
693        uint32_t dummy_remaining;
694        void *transport;
695
696        if (!proto) proto=&dummy_proto;
697
698        if (!remaining) remaining=&dummy_remaining;
699
700        transport = trace_get_layer3(packet,&ethertype,remaining);
701
702        if (!transport)
703                return NULL;
704
705        switch (ethertype) {
706                case 0x0800: /* IPv4 */
707                        transport=trace_get_payload_from_ip(
708                                (libtrace_ip_t*)transport, proto, remaining);
709                        /* IPv6 */
710                        if (transport && *proto == 41) {
711                                transport=trace_get_payload_from_ip6(
712                                 (libtrace_ip6_t*)transport, proto,remaining);
713                        }
714                        return transport;
715                case 0x86DD: /* IPv6 */
716                        return trace_get_payload_from_ip6(
717                                (libtrace_ip6_t*)transport, proto, remaining);
718                       
719                default:
720                        *proto=0;
721                        return NULL;
722        }
723
724}
725
726DLLEXPORT libtrace_tcp_t *trace_get_tcp(libtrace_packet_t *packet) {
727        uint8_t proto;
728        libtrace_tcp_t *tcp;
729
730        tcp=(libtrace_tcp_t*)trace_get_transport(packet,&proto,NULL);
731
732        if (!tcp || proto != 6)
733                return NULL;
734
735        return (libtrace_tcp_t*)tcp;
736}
737
738DLLEXPORT libtrace_tcp_t *trace_get_tcp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
739{
740        libtrace_tcp_t *tcpptr = 0;
741
742        if (ip->ip_p == 6)  {
743                tcpptr = (libtrace_tcp_t *)
744                        trace_get_payload_from_ip(ip, NULL, remaining);
745        }
746
747        return tcpptr;
748}
749
750DLLEXPORT libtrace_udp_t *trace_get_udp(libtrace_packet_t *packet) {
751        uint8_t proto;
752        libtrace_udp_t *udp;
753
754        udp=(libtrace_udp_t*)trace_get_transport(packet,&proto,NULL);
755
756        if (!udp || proto != 17)
757                return NULL;
758
759        return udp;
760}
761
762DLLEXPORT libtrace_udp_t *trace_get_udp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
763{
764        libtrace_udp_t *udpptr = 0;
765
766        if (ip->ip_p == 17) {
767                udpptr = (libtrace_udp_t *)
768                        trace_get_payload_from_ip(ip, NULL, remaining);
769        }
770
771        return udpptr;
772}
773
774DLLEXPORT libtrace_icmp_t *trace_get_icmp(libtrace_packet_t *packet) {
775        uint8_t proto;
776        libtrace_icmp_t *icmp;
777
778        icmp=(libtrace_icmp_t*)trace_get_transport(packet,&proto,NULL);
779
780        if (!icmp || proto != 1)
781                return NULL;
782
783        return icmp;
784}
785
786DLLEXPORT libtrace_icmp_t *trace_get_icmp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
787{
788        libtrace_icmp_t *icmpptr = 0;
789
790        if (ip->ip_p == 1)  {
791                icmpptr = (libtrace_icmp_t *)trace_get_payload_from_ip(ip, 
792                                NULL, remaining);
793        }
794
795        return icmpptr;
796}
797
798DLLEXPORT void *trace_get_payload_from_udp(libtrace_udp_t *udp, uint32_t *remaining)
799{
800        if (remaining) {
801                if (*remaining < sizeof(libtrace_udp_t))
802                        return NULL;
803                *remaining-=sizeof(libtrace_udp_t);
804        }
805        return (void*)((char*)udp+sizeof(libtrace_udp_t));
806}
807
808DLLEXPORT void *trace_get_payload_from_tcp(libtrace_tcp_t *tcp, uint32_t *remaining)
809{
810        unsigned int dlen = tcp->doff*4;
811        if (remaining) {
812                if (*remaining < dlen)
813                        return NULL;
814                *remaining-=dlen;
815        }
816        return (void *)((char *)tcp+dlen);
817}
818
819DLLEXPORT void *trace_get_payload_from_icmp(libtrace_icmp_t *icmp, uint32_t *remaining)
820{
821        if (remaining) {
822                if (*remaining < sizeof(libtrace_icmp_t))
823                        return NULL;
824                *remaining-=sizeof(libtrace_icmp_t);
825        }
826        return (char*)icmp+sizeof(libtrace_icmp_t);
827}
828
829struct ports_t {
830        uint16_t src;
831        uint16_t dst;
832};
833
834/* Return the client port
835 */
836DLLEXPORT uint16_t trace_get_source_port(const libtrace_packet_t *packet)
837{
838        uint32_t remaining;
839        const struct ports_t *port = 
840                (const struct ports_t*)trace_get_transport((libtrace_packet_t*)packet,
841                        NULL, &remaining);
842
843        /* snapped too early */
844        if (remaining<2)
845                return 0;
846
847        if (port)
848                return ntohs(port->src);
849        else
850                return 0;
851}
852
853/* Same as get_source_port except use the destination port */
854DLLEXPORT uint16_t trace_get_destination_port(const libtrace_packet_t *packet)
855{
856        uint32_t remaining;
857        struct ports_t *port = 
858                (struct ports_t*)trace_get_transport((libtrace_packet_t*)packet,
859                        NULL, &remaining);
860        /* snapped to early */
861        if (remaining<4)
862                return 0;
863
864        if (port)
865                return ntohs(port->dst);
866        else
867                return 0;
868}
869
870/* Take a pointer to the start of an IEEE 802.11 MAC frame and return a pointer
871 * to the source MAC address. 
872 * If the frame does not contain a sender address, e.g. ACK frame, return NULL.
873 * If the frame is a 4-address WDS frame, return TA, i.e. addr2.
874 * NB: This function decodes the 802.11 header, so it assumes that there are no
875 * bit-errors. If there are, all bets are off.
876 */
877static
878uint8_t *get_source_mac_from_wifi(void *wifi) {
879        if (wifi == NULL) return NULL;
880        struct libtrace_80211_t *w = (struct libtrace_80211_t *) wifi;
881       
882        /* If the frame is of type CTRL */
883        if (w->type == 0x1) 
884                /* If bit 2 of the subtype field is zero, this indicates that
885                 * there is no transmitter address, i.e. the frame is either an
886                 * ACK or a CTS frame */
887                if ((w->subtype & 0x2) == 0)
888                        return NULL;
889
890        /* Always return the address of the transmitter, i.e. address 2 */
891        return (uint8_t *) &w->mac2;
892}
893
894DLLEXPORT uint8_t *trace_get_source_mac(libtrace_packet_t *packet) {
895        void *link;
896        uint32_t remaining;
897        libtrace_linktype_t linktype;
898        assert(packet);
899        link = trace_get_layer2(packet,&linktype,&remaining);
900
901        if (!link)
902                return NULL;
903       
904        switch (linktype) {
905                case TRACE_TYPE_ETH:
906                        return (uint8_t *)&(((libtrace_ether_t*)link)->ether_shost);
907                case TRACE_TYPE_80211:
908                        return get_source_mac_from_wifi(link);
909                /* These packets don't have MAC addresses */
910                case TRACE_TYPE_POS:
911                case TRACE_TYPE_NONE:
912                case TRACE_TYPE_HDLC_POS:
913                case TRACE_TYPE_PFLOG:
914                case TRACE_TYPE_ATM:
915                case TRACE_TYPE_DUCK:
916                case TRACE_TYPE_METADATA:
917                case TRACE_TYPE_AAL5:
918                case TRACE_TYPE_LLCSNAP:
919                case TRACE_TYPE_PPP:
920                        return NULL;
921
922                /* Metadata headers should already be skipped */
923                case TRACE_TYPE_LINUX_SLL:
924                case TRACE_TYPE_80211_PRISM:
925                case TRACE_TYPE_80211_RADIO:
926                        assert(!"Metadata headers should already be skipped");
927                        break;
928        }
929        fprintf(stderr,"%s not implemented for linktype %i\n", __func__, linktype);
930        assert(0);
931        return NULL;
932}
933
934DLLEXPORT uint8_t *trace_get_destination_mac(libtrace_packet_t *packet) 
935{
936        void *link;
937        libtrace_linktype_t linktype;
938        uint32_t remaining;
939
940        link = trace_get_layer2(packet,&linktype,&remaining);
941
942        libtrace_80211_t *wifi;
943        libtrace_ether_t *ethptr = (libtrace_ether_t*)link;
944
945
946        if (!link)
947                return NULL;
948
949        switch (linktype) {
950                case TRACE_TYPE_80211:
951                        wifi=(libtrace_80211_t*)link;
952                        return (uint8_t*)&wifi->mac1;
953                case TRACE_TYPE_80211_RADIO:
954                        wifi=(libtrace_80211_t*)trace_get_payload_from_radiotap(
955                                        link,NULL,NULL);
956                        return (uint8_t*)&wifi->mac1;
957                case TRACE_TYPE_80211_PRISM:
958                        wifi=(libtrace_80211_t*)((char*)link+144);
959                        return (uint8_t*)&wifi->mac1;
960                case TRACE_TYPE_ETH:
961                        return (uint8_t*)&ethptr->ether_dhost;
962                case TRACE_TYPE_POS:
963                case TRACE_TYPE_NONE:
964                case TRACE_TYPE_ATM:
965                case TRACE_TYPE_HDLC_POS:
966                case TRACE_TYPE_LINUX_SLL:
967                case TRACE_TYPE_PFLOG:
968                case TRACE_TYPE_DUCK:
969                case TRACE_TYPE_METADATA:
970                        /* No MAC address */
971                        return NULL;
972                default:
973                        break;
974        }
975        fprintf(stderr,"Not implemented\n");
976        assert(0);
977        return NULL;
978}
979
980DLLEXPORT struct sockaddr *trace_get_source_address(
981                const libtrace_packet_t *packet, struct sockaddr *addr)
982{
983        uint16_t ethertype;
984        uint32_t remaining;
985        void *l3;
986        struct ports_t *ports;
987        static struct sockaddr_storage dummy;
988
989        if (!addr)
990                addr=(struct sockaddr*)&dummy;
991
992        l3 = trace_get_layer3(packet,&ethertype,&remaining);
993
994        if (!l3)
995                return NULL;
996
997        switch (ethertype) {
998                case 0x0800: /* IPv4 */
999                {
1000                        struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
1001                        libtrace_ip_t *ip = (libtrace_ip_t*)l3;
1002                        ports = (struct ports_t*)
1003                                trace_get_payload_from_ip(ip,NULL,&remaining);
1004                        addr4->sin_family=AF_INET;
1005                        if (ports && remaining>=sizeof(*ports))
1006                                addr4->sin_port=ports->src;
1007                        else
1008                                addr4->sin_port=0;
1009                        addr4->sin_addr=ip->ip_src;
1010                        return addr;
1011                }
1012                case 0x86DD: /* IPv6 */
1013                {
1014                        struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
1015                        libtrace_ip6_t *ip6 = (libtrace_ip6_t*)l3;
1016                        ports = (struct ports_t*)
1017                                trace_get_payload_from_ip6(ip6,NULL,&remaining);
1018                        addr6->sin6_family=AF_INET6;
1019                        if (ports && remaining>=sizeof(*ports))
1020                                addr6->sin6_port=ports->src;
1021                        else
1022                                addr6->sin6_port=0;
1023                        addr6->sin6_flowinfo=0;
1024                        addr6->sin6_addr=ip6->ip_src;
1025                        return addr;
1026                }
1027                default:
1028                        return NULL;
1029        }
1030}
1031
1032DLLEXPORT struct sockaddr *trace_get_destination_address(
1033                const libtrace_packet_t *packet, struct sockaddr *addr)
1034{
1035        uint16_t ethertype;
1036        uint32_t remaining;
1037        void *l3;
1038        struct ports_t *ports;
1039        static struct sockaddr_storage dummy;
1040
1041        if (!addr)
1042                addr=(struct sockaddr*)&dummy;
1043
1044        l3 = trace_get_layer3(packet,&ethertype,&remaining);
1045
1046        if (!l3)
1047                return NULL;
1048
1049        switch (ethertype) {
1050                case 0x0800: /* IPv4 */
1051                {
1052                        struct sockaddr_in *addr4=(struct sockaddr_in*)addr;
1053                        libtrace_ip_t *ip = (libtrace_ip_t*)l3;
1054                        ports = (struct ports_t*)
1055                                trace_get_payload_from_ip(ip,NULL,&remaining);
1056                        addr4->sin_family=AF_INET;
1057                        if (ports && remaining>=sizeof(*ports))
1058                                addr4->sin_port=ports->dst;
1059                        else
1060                                addr4->sin_port=0;
1061                        addr4->sin_addr=ip->ip_dst;
1062                        return addr;
1063                }
1064                case 0x86DD: /* IPv6 */
1065                {
1066                        struct sockaddr_in6 *addr6=(struct sockaddr_in6*)addr;
1067                        libtrace_ip6_t *ip6 = (libtrace_ip6_t*)l3;
1068                        ports = (struct ports_t*)
1069                                trace_get_payload_from_ip6(ip6,NULL,&remaining);
1070                        addr6->sin6_family=AF_INET6;
1071                        if (ports && remaining>=sizeof(*ports))
1072                                addr6->sin6_port=ports->dst;
1073                        else
1074                                addr6->sin6_port=0;
1075                        addr6->sin6_flowinfo=0;
1076                        addr6->sin6_addr=ip6->ip_dst;
1077                        return addr;
1078                }
1079                default:
1080                        return NULL;
1081        }
1082}
1083
1084/* parse an ip or tcp option
1085 * @param[in,out] ptr   the pointer to the current option
1086 * @param[in,out] len   the length of the remaining buffer
1087 * @param[out] type     the type of the option
1088 * @param[out] optlen   the length of the option
1089 * @param[out] data     the data of the option
1090 *
1091 * @returns bool true if there is another option (and the fields are filled in)
1092 *               or false if this was the last option.
1093 *
1094 * This updates ptr to point to the next option after this one, and updates
1095 * len to be the number of bytes remaining in the options area.  Type is updated
1096 * to be the code of this option, and data points to the data of this option,
1097 * with optlen saying how many bytes there are.
1098 *
1099 * @note Beware of fragmented packets.
1100 * @author Perry Lorier
1101 */
1102DLLEXPORT int trace_get_next_option(unsigned char **ptr,int *len,
1103                        unsigned char *type,
1104                        unsigned char *optlen,
1105                        unsigned char **data)
1106{
1107        if (*len<=0)
1108                return 0;
1109        *type=**ptr;
1110        switch(*type) {
1111                case 0: /* End of options */
1112                        return 0;
1113                case 1: /* Pad */
1114                        (*ptr)++;
1115                        (*len)--;
1116                        return 1;
1117                default:
1118                        *optlen = *(*ptr+1);
1119                        if (*optlen<2)
1120                                return 0; /* I have no idea wtf is going on
1121                                           * with these packets
1122                                           */
1123                        (*len)-=*optlen;
1124                        (*data)=(*ptr+2);
1125                        (*ptr)+=*optlen;
1126                        if (*len<0)
1127                                return 0;
1128                        return 1;
1129        }
1130        assert(0);
1131}
1132
1133
Note: See TracBrowser for help on using the repository browser.