source: lib/protocols_transport.c @ cc6fcee

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since cc6fcee was cc6fcee, checked in by Shane Alcock <salcock@…>, 9 years ago
  • Added a function for parsing OSPF packets that contain LSA headers only, e.g. LS Acks, as we can't rely on the LSA length field to tell us how long the LSA in these packets is :(
  • Property mode set to 100644
File size: 15.4 KB
Line 
1/*
2 * This file is part of libtrace
3 *
4 * Copyright (c) 2007,2008,2009,2010 The University of Waikato, Hamilton,
5 * New Zealand.
6 *
7 * Authors: Daniel Lawson
8 *          Perry Lorier
9 *          Shane Alcock
10 *         
11 * All rights reserved.
12 *
13 * This code has been developed by the University of Waikato WAND
14 * research group. For further information please see http://www.wand.net.nz/
15 *
16 * libtrace is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * libtrace is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with libtrace; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29 *
30 * $Id$
31 *
32 */
33
34
35#include "libtrace.h"
36#include "protocols.h"
37#include <assert.h>
38#include <stdlib.h>
39#include <stdio.h> // fprintf
40
41/* This file contains all the protocol decoding functions for transport layer
42 * protocols. This includes functions for access port numbers.
43 *
44 * Supported protocols include (but are not limited to):
45 *      TCP
46 *      UDP
47 *      ICMP
48 */
49
50/* Get the size of the payload as it was in the original packet, i.e. prior
51 * to any truncation.
52 *
53 * Basically, wire length minus the packet headers.
54 *
55 * Currently only supports IP (v4 and v6) and TCP, UDP and ICMP. Will return
56 * 0 if an unsupported protocol header is encountered, or if one of the
57 * headers is truncated.
58 */
59DLLEXPORT size_t trace_get_payload_length(const libtrace_packet_t *packet) {
60
61        void *layer;
62        uint16_t ethertype;
63        uint8_t proto;
64        uint32_t rem;
65        libtrace_ip_t *ip;
66        libtrace_ip6_t *ip6;
67        libtrace_tcp_t *tcp;
68        size_t len = 0;
69
70        /* Just use the cached length if we can */
71        if (packet->payload_length != -1)
72                return packet->payload_length; 
73
74        /* Set to zero so that we can return early without having to
75         * worry about forgetting to update the cached value */
76        ((libtrace_packet_t *)packet)->payload_length = 0;
77        layer = trace_get_layer3(packet, &ethertype, &rem);
78        if (!layer)
79                return 0;
80        switch (ethertype) {
81                case TRACE_ETHERTYPE_IP:
82                        ip = (libtrace_ip_t *)layer;
83                        if (rem < sizeof(libtrace_ip_t))
84                                return 0;
85                        len = ntohs(ip->ip_len) - (4 * ip->ip_hl);
86               
87                        /* Deal with v6 within v4 */
88                        if (ip->ip_p == TRACE_IPPROTO_IPV6)
89                                len -= sizeof(libtrace_ip6_t);
90                       
91                        break;
92                case TRACE_ETHERTYPE_IPV6:
93                        ip6 = (libtrace_ip6_t *)layer;
94                        if (rem < sizeof(libtrace_ip6_t))
95                                return 0;
96                        len = ntohs(ip6->plen);
97                        break;
98                default:
99                        return 0;
100        }
101
102        layer = trace_get_transport(packet, &proto, &rem);
103        if (!layer)
104                return 0;
105       
106        switch(proto) {
107                case TRACE_IPPROTO_TCP:
108                        if (rem < sizeof(libtrace_tcp_t))
109                                return 0;
110                        tcp = (libtrace_tcp_t *)layer;
111                       
112                        if (len < (size_t)(4 * tcp->doff))
113                                return 0;
114                       
115                        len -= (4 * tcp->doff);
116                        break;
117                case TRACE_IPPROTO_UDP:
118                        len -= sizeof(libtrace_udp_t);
119                        break;
120                case TRACE_IPPROTO_ICMP:
121                        len -= sizeof(libtrace_icmp_t);
122                        break;
123               
124                default:
125                        return 0;
126        }
127
128
129        ((libtrace_packet_t *)packet)->payload_length = len;
130        return len;
131
132}
133
134DLLEXPORT void *trace_get_transport(const libtrace_packet_t *packet, 
135                uint8_t *proto,
136                uint32_t *remaining
137                ) 
138{
139        uint8_t dummy_proto;
140        uint16_t ethertype;
141        uint32_t dummy_remaining;
142        void *transport;
143
144        if (!proto) proto=&dummy_proto;
145
146        if (!remaining) remaining=&dummy_remaining;
147
148        if (packet->l4_header) {
149                /*
150                void *link;
151                libtrace_linktype_t linktype;
152                link = trace_get_packet_buffer(packet, &linktype, remaining);
153                if (!link)
154                        return NULL;
155                */
156                *proto = packet->transport_proto;
157                /* *remaining -= (packet->l4_header - link); */
158                *remaining = packet->l4_remaining;
159                return packet->l4_header;
160        }
161
162        transport = trace_get_layer3(packet,&ethertype,remaining);
163
164        if (!transport || *remaining == 0)
165                return NULL;
166
167        switch (ethertype) {
168                case TRACE_ETHERTYPE_IP: /* IPv4 */
169                        transport=trace_get_payload_from_ip(
170                                (libtrace_ip_t*)transport, proto, remaining);
171                        /* IPv6 */
172                        if (transport && *proto == TRACE_IPPROTO_IPV6) {
173                                transport=trace_get_payload_from_ip6(
174                                 (libtrace_ip6_t*)transport, proto,remaining);
175                        }
176                        break;
177                case TRACE_ETHERTYPE_IPV6: /* IPv6 */
178                        transport = trace_get_payload_from_ip6(
179                                (libtrace_ip6_t*)transport, proto, remaining);
180                        break;
181                default:
182                        *proto = 0;
183                        transport = NULL;
184                        break;
185                       
186        }
187
188        ((libtrace_packet_t *)packet)->transport_proto = *proto;
189        ((libtrace_packet_t *)packet)->l4_header = transport;
190        ((libtrace_packet_t *)packet)->l4_remaining = *remaining;
191
192
193        return transport;
194}
195
196DLLEXPORT void *trace_get_ospf_header(libtrace_packet_t *packet,
197                uint8_t *version, uint32_t *remaining) {
198        uint8_t proto;
199        void *ospf;
200        uint32_t dummy_rem = 0;
201
202
203        if (!remaining)
204                remaining = &dummy_rem;
205
206        assert(version != NULL && "version may not be NULL when calling trace_get_ospf_header!");
207
208        ospf = trace_get_transport(packet, &proto, remaining);
209
210        if (!ospf || proto != TRACE_IPPROTO_OSPF || *remaining == 0)
211                return NULL;
212
213        *version = *((uint8_t *)ospf);
214       
215        if (*version == 2 && *remaining < sizeof(libtrace_ospf_v2_t))
216                return NULL;
217
218        return ospf;
219}
220
221DLLEXPORT void *trace_get_ospf_contents_v2(libtrace_ospf_v2_t *header,
222                uint8_t *ospf_type, uint32_t *remaining) {
223
224        uint8_t dummy_type;
225        char *ptr;
226       
227        assert(remaining != NULL && "remaining may not be NULL when calling trace_get_ospf_contents!");
228
229        if (!ospf_type)
230                ospf_type = &dummy_type;
231
232        if (!header || *remaining < sizeof(libtrace_ospf_v2_t)) {
233                *ospf_type = 0;
234                *remaining = 0;
235                return NULL;
236        }
237       
238        *ospf_type = header->type;
239
240        ptr = ((char *)header) + sizeof(libtrace_ospf_v2_t);
241        *remaining -= sizeof(libtrace_ospf_v2_t);
242
243        return (void *)ptr;
244
245}
246
247DLLEXPORT unsigned char *trace_get_first_ospf_link_from_router_lsa_v2(
248                libtrace_ospf_router_lsa_v2_t *lsa,
249                uint32_t *remaining) {
250
251        unsigned char *link_ptr = NULL;
252        assert(remaining != NULL && "remaining may not be NULL when calling trace_get_first_link_from_router_lsa_v2!");
253
254        if (!lsa || *remaining < sizeof(libtrace_ospf_router_lsa_v2_t)) {
255                *remaining = 0;
256                return NULL;
257        }
258
259        link_ptr = ((unsigned char *)lsa) + sizeof(libtrace_ospf_router_lsa_v2_t);
260        *remaining -= sizeof(libtrace_ospf_router_lsa_v2_t);
261        return link_ptr;
262
263}
264
265DLLEXPORT unsigned char *trace_get_first_ospf_lsa_from_db_desc_v2(
266                libtrace_ospf_db_desc_v2_t *db_desc,
267                uint32_t *remaining) {
268
269        unsigned char *lsa_ptr = NULL;
270
271        assert(remaining != NULL && "remaining may not be NULL when calling trace_get_first_ospf_v2_lsa!");
272
273        if (!db_desc || *remaining < sizeof(libtrace_ospf_db_desc_v2_t)) {
274                *remaining = 0;
275                return NULL;
276        }
277       
278        lsa_ptr = ((unsigned char *)db_desc) + sizeof(libtrace_ospf_db_desc_v2_t);
279        *remaining -= sizeof(libtrace_ospf_db_desc_v2_t);
280
281        return lsa_ptr;
282}
283
284DLLEXPORT unsigned char *trace_get_first_ospf_lsa_from_update_v2(
285                libtrace_ospf_ls_update_t *ls_update,
286                uint32_t *remaining) {
287
288        unsigned char *lsa_ptr = NULL;
289
290        assert(remaining != NULL && "remaining may not be NULL when calling trace_get_first_ospf_v2_lsa!");
291
292        if (!ls_update || *remaining < sizeof(libtrace_ospf_ls_update_t)) {
293                *remaining = 0;
294                return NULL;
295        }
296       
297        lsa_ptr = ((unsigned char *)ls_update) + sizeof(libtrace_ospf_ls_update_t);
298        *remaining -= sizeof(libtrace_ospf_ls_update_t);
299
300        return lsa_ptr;
301}
302
303DLLEXPORT uint32_t trace_get_ospf_metric_from_as_external_lsa_v2(
304                libtrace_ospf_as_external_lsa_v2_t *as_lsa) {
305
306        uint32_t metric = 0;
307
308        assert(as_lsa);
309
310        metric = as_lsa->metric_a << 16;
311        metric |= (as_lsa->metric_b << 8);
312        metric |= as_lsa->metric_c;
313
314        return metric;
315}
316
317DLLEXPORT uint32_t trace_get_ospf_metric_from_summary_lsa_v2(
318                libtrace_ospf_summary_lsa_v2_t *sum_lsa) {
319
320        uint32_t metric = 0;
321
322        assert(sum_lsa);
323
324        metric = sum_lsa->metric_a << 16;
325        metric |= (sum_lsa->metric_b << 8);
326        metric |= sum_lsa->metric_c;
327
328        return metric;
329}
330
331DLLEXPORT int trace_get_next_ospf_link_v2(unsigned char **current,
332                libtrace_ospf_link_v2_t **link,
333                uint32_t *remaining,
334                uint32_t *link_len) {
335
336        if (*current == NULL || *remaining < sizeof(libtrace_ospf_link_v2_t)) {
337                *remaining = 0;
338                *link = NULL;
339                return 0;
340        }
341
342        *link = (libtrace_ospf_link_v2_t *)*current;
343
344        /* XXX The spec allows for multiple metrics for a single link. This
345         * approach won't support this, so we may need to be more intelligent
346         * about this in future */
347        *remaining -= sizeof(libtrace_ospf_link_v2_t);
348        *link_len = sizeof(libtrace_ospf_link_v2_t);
349        *current += sizeof(libtrace_ospf_link_v2_t);
350       
351        return 1; 
352
353}
354
355DLLEXPORT int trace_get_next_ospf_lsa_header_v2(unsigned char **current,
356                libtrace_ospf_lsa_v2_t **lsa_hdr,
357                uint32_t *remaining,
358                uint8_t *lsa_type,
359                uint16_t *lsa_length) {
360       
361        int valid_lsa = 0;
362
363        if (*current == NULL || *remaining < sizeof(libtrace_ospf_lsa_v2_t)) {
364                *lsa_hdr = NULL;
365                *remaining = 0;
366                return 0;
367
368        }
369
370        *lsa_hdr = (libtrace_ospf_lsa_v2_t *)(*current);
371       
372        /* Check that the LSA type is valid */
373        switch ((*lsa_hdr)->lsa_type) {
374                case TRACE_OSPF_LS_ROUTER:
375                case TRACE_OSPF_LS_NETWORK:
376                case TRACE_OSPF_LS_SUMMARY:
377                case TRACE_OSPF_LS_ASBR_SUMMARY:
378                case TRACE_OSPF_LS_EXTERNAL:
379                        valid_lsa = 1;
380                        break;
381        }
382       
383        /* This function is for reading LSA headers only, e.g. those in DB desc
384         * or LS Ack packets. As such, I'm going to set the type and length to
385         * values that should prevent anyone from trying to treat subsequent
386         * payload as an LSA body */
387        *lsa_type = 0;
388        *lsa_length = sizeof(libtrace_ospf_lsa_v2_t);
389
390        if (!valid_lsa) {
391                *remaining = 0;
392                return -1;
393        }
394       
395        *remaining -= *lsa_length;
396        *current += *lsa_length;
397
398        if (remaining == 0) {
399                /* No more LSAs */
400                return 0;
401        }
402
403        return 1;
404}
405
406DLLEXPORT int trace_get_next_ospf_lsa_v2(unsigned char **current,
407                libtrace_ospf_lsa_v2_t **lsa_hdr,
408                unsigned char **lsa_body,
409                uint32_t *remaining,
410                uint8_t *lsa_type,
411                uint16_t *lsa_length) {
412
413        int valid_lsa = 0;
414
415        if (*current == NULL || *remaining < sizeof(libtrace_ospf_lsa_v2_t)) {
416                *lsa_hdr = NULL;
417                *lsa_body = NULL;
418                *remaining = 0;
419
420                return 0;
421
422        }
423
424        *lsa_hdr = (libtrace_ospf_lsa_v2_t *)(*current);
425        *lsa_type = (*lsa_hdr)->lsa_type;
426        *lsa_length = ntohs((*lsa_hdr)->length);
427
428        /* Check that the LSA type is valid */
429        switch (*lsa_type) {
430                case TRACE_OSPF_LS_ROUTER:
431                case TRACE_OSPF_LS_NETWORK:
432                case TRACE_OSPF_LS_SUMMARY:
433                case TRACE_OSPF_LS_ASBR_SUMMARY:
434                case TRACE_OSPF_LS_EXTERNAL:
435                        valid_lsa = 1;
436                        break;
437        }
438               
439        if (*lsa_length > *remaining || !valid_lsa) {
440                /* LSA is incomplete or an invalid type.
441                 *
442                 * If this occurs, you've probably managed to read something
443                 * that is NOT a legit LSA */
444                *remaining = 0;
445                *lsa_body = NULL;
446                return -1;
447        }
448       
449        /* Some OSPF packets, e.g. LS ACKs, only contain LSA headers. If this
450         * is the case, we'll set the body pointer to NULL so the caller
451         * can't read invalid data */
452        if (*lsa_length == sizeof(libtrace_ospf_lsa_v2_t))
453                *lsa_body = NULL;
454        else
455                *lsa_body = (*current + sizeof(libtrace_ospf_lsa_v2_t));
456
457        *remaining -= *lsa_length;
458        *current += *lsa_length;
459
460        if (remaining == 0) {
461                /* No more LSAs */
462                return 0;
463        }
464
465        return 1;
466
467}
468
469DLLEXPORT libtrace_tcp_t *trace_get_tcp(libtrace_packet_t *packet) {
470        uint8_t proto;
471        uint32_t rem = 0;
472        libtrace_tcp_t *tcp;
473
474        tcp=(libtrace_tcp_t*)trace_get_transport(packet,&proto,&rem);
475
476        if (!tcp || proto != TRACE_IPPROTO_TCP)
477                return NULL;
478
479        /* We should return NULL if there isn't a full TCP header, because the
480         * caller has no way of telling how much of a TCP header we have
481         * returned - use trace_get_transport() if you want to deal with
482         * partial headers
483         *
484         * NOTE: We're not going to insist that all the TCP options are present
485         * as well, because lots of traces are snapped after 20 bytes of TCP
486         * header and I don't really want to break libtrace programs that
487         * use this function to process those traces */
488
489        if (rem < sizeof(libtrace_tcp_t))
490                return NULL;
491
492        return (libtrace_tcp_t*)tcp;
493}
494
495DLLEXPORT libtrace_tcp_t *trace_get_tcp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
496{
497        libtrace_tcp_t *tcpptr = 0;
498
499        if (ip->ip_p == TRACE_IPPROTO_TCP)  {
500                tcpptr = (libtrace_tcp_t *)
501                        trace_get_payload_from_ip(ip, NULL, remaining);
502        }
503
504        return tcpptr;
505}
506
507DLLEXPORT libtrace_udp_t *trace_get_udp(libtrace_packet_t *packet) {
508        uint8_t proto;
509        uint32_t rem = 0;
510        libtrace_udp_t *udp;
511
512        udp=(libtrace_udp_t*)trace_get_transport(packet,&proto,&rem);
513
514        if (!udp || proto != TRACE_IPPROTO_UDP)
515                return NULL;
516
517        /* Make sure we return a full UDP header as the caller has no way of
518         * telling how much of the packet is remaining */
519        if (rem < sizeof(libtrace_udp_t))
520                return NULL;
521
522        return udp;
523}
524
525DLLEXPORT libtrace_udp_t *trace_get_udp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
526{
527        libtrace_udp_t *udpptr = 0;
528
529        if (ip->ip_p == TRACE_IPPROTO_UDP) {
530                udpptr = (libtrace_udp_t *)
531                        trace_get_payload_from_ip(ip, NULL, remaining);
532        }
533
534        return udpptr;
535}
536
537DLLEXPORT libtrace_icmp_t *trace_get_icmp(libtrace_packet_t *packet) {
538        uint8_t proto;
539        uint32_t rem = 0;
540        libtrace_icmp_t *icmp;
541
542        icmp=(libtrace_icmp_t*)trace_get_transport(packet,&proto,&rem);
543
544        if (!icmp || proto != TRACE_IPPROTO_ICMP)
545                return NULL;
546
547        /* Make sure we return a full ICMP header as the caller has no way of
548         * telling how much of the packet is remaining */
549        if (rem < sizeof(libtrace_icmp_t))
550                return NULL;
551
552        return icmp;
553}
554
555DLLEXPORT libtrace_icmp_t *trace_get_icmp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
556{
557        libtrace_icmp_t *icmpptr = 0;
558
559        if (ip->ip_p == TRACE_IPPROTO_ICMP)  {
560                icmpptr = (libtrace_icmp_t *)trace_get_payload_from_ip(ip, 
561                                NULL, remaining);
562        }
563
564        return icmpptr;
565}
566
567DLLEXPORT void *trace_get_payload_from_udp(libtrace_udp_t *udp, uint32_t *remaining)
568{
569        if (remaining) {
570                if (*remaining < sizeof(libtrace_udp_t)) {
571                        *remaining = 0;
572                        return NULL;
573                }
574                *remaining-=sizeof(libtrace_udp_t);
575        }
576        return (void*)((char*)udp+sizeof(libtrace_udp_t));
577}
578
579DLLEXPORT void *trace_get_payload_from_tcp(libtrace_tcp_t *tcp, uint32_t *remaining)
580{
581        unsigned int dlen = tcp->doff*4;
582        if (remaining) {
583                if (*remaining < dlen) {
584                        *remaining = 0;
585                        return NULL;
586                }
587                *remaining-=dlen;
588        }
589        return (void *)((char *)tcp+dlen);
590}
591
592DLLEXPORT void *trace_get_payload_from_icmp(libtrace_icmp_t *icmp, uint32_t *remaining)
593{
594        if (remaining) {
595                if (*remaining < sizeof(libtrace_icmp_t)) {
596                        *remaining = 0;
597                        return NULL;
598                }
599                *remaining-=sizeof(libtrace_icmp_t);
600        }
601        return (char*)icmp+sizeof(libtrace_icmp_t);
602}
603
604/* Return the source port
605 */
606DLLEXPORT uint16_t trace_get_source_port(const libtrace_packet_t *packet)
607{
608        uint32_t remaining;
609        uint8_t proto;
610        const struct ports_t *port = 
611                (const struct ports_t*)trace_get_transport((libtrace_packet_t*)packet,
612                        &proto, &remaining);
613
614        /* Snapped too early */
615        if (remaining<2)
616                return 0;
617
618        /* ICMP *technically* doesn't have ports */
619        if (proto == TRACE_IPPROTO_ICMP)
620                return 0;
621
622        if (port)
623                return ntohs(port->src);
624        else
625                return 0;
626}
627
628/* Same as get_source_port except use the destination port */
629DLLEXPORT uint16_t trace_get_destination_port(const libtrace_packet_t *packet)
630{
631        uint32_t remaining;
632        uint8_t proto;
633        struct ports_t *port = 
634                (struct ports_t*)trace_get_transport((libtrace_packet_t*)packet,
635                        &proto, &remaining);
636        /* Snapped too early */
637        if (remaining<4)
638                return 0;
639       
640        /* ICMP *technically* doesn't have ports */
641        if (proto == TRACE_IPPROTO_ICMP)
642                return 0;
643
644        if (port)
645                return ntohs(port->dst);
646        else
647                return 0;
648}
649
650
Note: See TracBrowser for help on using the repository browser.