source: lib/protocols.c @ 67a14d4

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

Move more types to the libtrace standard (typedef'd libtrace_*_t)
Add casts where appropriate
Remove default:'s from enum'd switch()'s

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