source: lib/protocols_transport.c @ 29532e3

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 29532e3 was 29532e3, checked in by Shane Alcock <salcock@…>, 9 years ago

Added support for parsing OSPFv2 headers, based on Simon Wadsworth's 591 project.

A few comments on the implementation thus far:

  • This code has only been tested with Hello, LS Update and LS Acknowledge packets. DB Desc and LS Request is completely untested, mainly due to a lack of traces containing those packets.
  • This release supports not only accessing the basic OSPF headers but also parsing the interesting LSAs and Link Ids in LSA Update packets.
  • OSPF is not a nice protocol - there's lots of dynamic length stuff for starters. I've tried to design the API so that is as nice as possible for the end user who may not be overly knowledgeable about OSPF. In particular, I've tried to minimise the amount of pointer arithmetic needed to get at the LSAs and Link Ids. More documentation and an example program will come in a later commit.
  • Also, whoever came up with 24-bit metric values should be shot. To make life easier for users, I've included functions to return the correct value for the metric from a given header. I hope you all appreciate the extra effort :)
  • Property mode set to 100644
File size: 14.2 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_v2(unsigned char **current,
356                libtrace_ospf_lsa_v2_t **lsa_hdr,
357                unsigned char **lsa_body,
358                uint32_t *remaining,
359                uint8_t *lsa_type,
360                uint16_t *lsa_length) {
361
362        int valid_lsa = 0;
363
364        if (*current == NULL || *remaining < sizeof(libtrace_ospf_lsa_v2_t)) {
365                *lsa_hdr = NULL;
366                *lsa_body = NULL;
367                *remaining = 0;
368
369                return 0;
370
371        }
372
373        *lsa_hdr = (libtrace_ospf_lsa_v2_t *)(*current);
374        *lsa_type = (*lsa_hdr)->lsa_type;
375        *lsa_length = ntohs((*lsa_hdr)->length);
376
377        /* Check that the LSA type is valid */
378        switch (*lsa_type) {
379                case TRACE_OSPF_LS_ROUTER:
380                case TRACE_OSPF_LS_NETWORK:
381                case TRACE_OSPF_LS_SUMMARY:
382                case TRACE_OSPF_LS_ASBR_SUMMARY:
383                case TRACE_OSPF_LS_EXTERNAL:
384                        valid_lsa = 1;
385                        break;
386        }
387               
388        if (*lsa_length > *remaining || !valid_lsa) {
389                /* LSA is incomplete or an invalid type.
390                 *
391                 * If this occurs, you've probably managed to read something
392                 * that is NOT a legit LSA */
393                *remaining = 0;
394                return -1;
395        }
396       
397        /* Some OSPF packets, e.g. LS ACKs, only contain LSA headers. If this
398         * is the case, we'll set the body pointer to NULL so the caller
399         * can't read invalid data */
400        if (*lsa_length == sizeof(libtrace_ospf_lsa_v2_t))
401                *lsa_body = NULL;
402        else
403                *lsa_body = (*current + sizeof(libtrace_ospf_lsa_v2_t));
404
405        *remaining -= *lsa_length;
406        *current += *lsa_length;
407
408        if (remaining == 0) {
409                /* No more LSAs */
410                return 0;
411        }
412
413        return 1;
414
415}
416
417DLLEXPORT libtrace_tcp_t *trace_get_tcp(libtrace_packet_t *packet) {
418        uint8_t proto;
419        uint32_t rem = 0;
420        libtrace_tcp_t *tcp;
421
422        tcp=(libtrace_tcp_t*)trace_get_transport(packet,&proto,&rem);
423
424        if (!tcp || proto != TRACE_IPPROTO_TCP)
425                return NULL;
426
427        /* We should return NULL if there isn't a full TCP header, because the
428         * caller has no way of telling how much of a TCP header we have
429         * returned - use trace_get_transport() if you want to deal with
430         * partial headers
431         *
432         * NOTE: We're not going to insist that all the TCP options are present
433         * as well, because lots of traces are snapped after 20 bytes of TCP
434         * header and I don't really want to break libtrace programs that
435         * use this function to process those traces */
436
437        if (rem < sizeof(libtrace_tcp_t))
438                return NULL;
439
440        return (libtrace_tcp_t*)tcp;
441}
442
443DLLEXPORT libtrace_tcp_t *trace_get_tcp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
444{
445        libtrace_tcp_t *tcpptr = 0;
446
447        if (ip->ip_p == TRACE_IPPROTO_TCP)  {
448                tcpptr = (libtrace_tcp_t *)
449                        trace_get_payload_from_ip(ip, NULL, remaining);
450        }
451
452        return tcpptr;
453}
454
455DLLEXPORT libtrace_udp_t *trace_get_udp(libtrace_packet_t *packet) {
456        uint8_t proto;
457        uint32_t rem = 0;
458        libtrace_udp_t *udp;
459
460        udp=(libtrace_udp_t*)trace_get_transport(packet,&proto,&rem);
461
462        if (!udp || proto != TRACE_IPPROTO_UDP)
463                return NULL;
464
465        /* Make sure we return a full UDP header as the caller has no way of
466         * telling how much of the packet is remaining */
467        if (rem < sizeof(libtrace_udp_t))
468                return NULL;
469
470        return udp;
471}
472
473DLLEXPORT libtrace_udp_t *trace_get_udp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
474{
475        libtrace_udp_t *udpptr = 0;
476
477        if (ip->ip_p == TRACE_IPPROTO_UDP) {
478                udpptr = (libtrace_udp_t *)
479                        trace_get_payload_from_ip(ip, NULL, remaining);
480        }
481
482        return udpptr;
483}
484
485DLLEXPORT libtrace_icmp_t *trace_get_icmp(libtrace_packet_t *packet) {
486        uint8_t proto;
487        uint32_t rem = 0;
488        libtrace_icmp_t *icmp;
489
490        icmp=(libtrace_icmp_t*)trace_get_transport(packet,&proto,&rem);
491
492        if (!icmp || proto != TRACE_IPPROTO_ICMP)
493                return NULL;
494
495        /* Make sure we return a full ICMP header as the caller has no way of
496         * telling how much of the packet is remaining */
497        if (rem < sizeof(libtrace_icmp_t))
498                return NULL;
499
500        return icmp;
501}
502
503DLLEXPORT libtrace_icmp_t *trace_get_icmp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
504{
505        libtrace_icmp_t *icmpptr = 0;
506
507        if (ip->ip_p == TRACE_IPPROTO_ICMP)  {
508                icmpptr = (libtrace_icmp_t *)trace_get_payload_from_ip(ip, 
509                                NULL, remaining);
510        }
511
512        return icmpptr;
513}
514
515DLLEXPORT void *trace_get_payload_from_udp(libtrace_udp_t *udp, uint32_t *remaining)
516{
517        if (remaining) {
518                if (*remaining < sizeof(libtrace_udp_t)) {
519                        *remaining = 0;
520                        return NULL;
521                }
522                *remaining-=sizeof(libtrace_udp_t);
523        }
524        return (void*)((char*)udp+sizeof(libtrace_udp_t));
525}
526
527DLLEXPORT void *trace_get_payload_from_tcp(libtrace_tcp_t *tcp, uint32_t *remaining)
528{
529        unsigned int dlen = tcp->doff*4;
530        if (remaining) {
531                if (*remaining < dlen) {
532                        *remaining = 0;
533                        return NULL;
534                }
535                *remaining-=dlen;
536        }
537        return (void *)((char *)tcp+dlen);
538}
539
540DLLEXPORT void *trace_get_payload_from_icmp(libtrace_icmp_t *icmp, uint32_t *remaining)
541{
542        if (remaining) {
543                if (*remaining < sizeof(libtrace_icmp_t)) {
544                        *remaining = 0;
545                        return NULL;
546                }
547                *remaining-=sizeof(libtrace_icmp_t);
548        }
549        return (char*)icmp+sizeof(libtrace_icmp_t);
550}
551
552/* Return the source port
553 */
554DLLEXPORT uint16_t trace_get_source_port(const libtrace_packet_t *packet)
555{
556        uint32_t remaining;
557        uint8_t proto;
558        const struct ports_t *port = 
559                (const struct ports_t*)trace_get_transport((libtrace_packet_t*)packet,
560                        &proto, &remaining);
561
562        /* Snapped too early */
563        if (remaining<2)
564                return 0;
565
566        /* ICMP *technically* doesn't have ports */
567        if (proto == TRACE_IPPROTO_ICMP)
568                return 0;
569
570        if (port)
571                return ntohs(port->src);
572        else
573                return 0;
574}
575
576/* Same as get_source_port except use the destination port */
577DLLEXPORT uint16_t trace_get_destination_port(const libtrace_packet_t *packet)
578{
579        uint32_t remaining;
580        uint8_t proto;
581        struct ports_t *port = 
582                (struct ports_t*)trace_get_transport((libtrace_packet_t*)packet,
583                        &proto, &remaining);
584        /* Snapped too early */
585        if (remaining<4)
586                return 0;
587       
588        /* ICMP *technically* doesn't have ports */
589        if (proto == TRACE_IPPROTO_ICMP)
590                return 0;
591
592        if (port)
593                return ntohs(port->dst);
594        else
595                return 0;
596}
597
598
Note: See TracBrowser for help on using the repository browser.