source: lib/protocols_transport.c @ 05f2718

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 05f2718 was 05f2718, checked in by Shane Alcock <salcock@…>, 8 years ago
  • Added API functions for getting the ICMPv6 header and the subsequent payload
  • Property mode set to 100644
File size: 10.1 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                        if (rem < sizeof(libtrace_udp_t))
119                                return 0;
120                        if (len < sizeof(libtrace_udp_t))
121                                return 0;
122                        len -= sizeof(libtrace_udp_t);
123                        break;
124                case TRACE_IPPROTO_ICMP:
125                        if (rem < sizeof(libtrace_icmp_t))
126                                return 0;
127                        if (len < sizeof(libtrace_icmp_t))
128                                return 0;
129                        len -= sizeof(libtrace_icmp_t);
130                        break;
131                case TRACE_IPPROTO_ICMPV6:
132                        if (rem < sizeof(libtrace_icmp6_t))
133                                return 0;
134                        if (len < sizeof(libtrace_icmp6_t))
135                                return 0;
136                        len -= sizeof(libtrace_icmp6_t);
137                        break;
138                       
139                default:
140                        return 0;
141        }
142
143        ((libtrace_packet_t *)packet)->payload_length = len;
144        return len;
145
146}
147
148DLLEXPORT void *trace_get_transport(const libtrace_packet_t *packet, 
149                uint8_t *proto,
150                uint32_t *remaining
151                ) 
152{
153        uint8_t dummy_proto;
154        uint16_t ethertype;
155        uint32_t dummy_remaining;
156        void *transport;
157
158        if (!proto) proto=&dummy_proto;
159
160        if (!remaining) remaining=&dummy_remaining;
161
162        if (packet->l4_header) {
163                /*
164                void *link;
165                libtrace_linktype_t linktype;
166                link = trace_get_packet_buffer(packet, &linktype, remaining);
167                if (!link)
168                        return NULL;
169                */
170                *proto = packet->transport_proto;
171                /* *remaining -= (packet->l4_header - link); */
172                *remaining = packet->l4_remaining;
173                return packet->l4_header;
174        }
175
176        transport = trace_get_layer3(packet,&ethertype,remaining);
177
178        if (!transport || *remaining == 0)
179                return NULL;
180
181        switch (ethertype) {
182                case TRACE_ETHERTYPE_IP: /* IPv4 */
183                        transport=trace_get_payload_from_ip(
184                                (libtrace_ip_t*)transport, proto, remaining);
185                        /* IPv6 */
186                        if (transport && *proto == TRACE_IPPROTO_IPV6) {
187                                transport=trace_get_payload_from_ip6(
188                                 (libtrace_ip6_t*)transport, proto,remaining);
189                        }
190                        break;
191                case TRACE_ETHERTYPE_IPV6: /* IPv6 */
192                        transport = trace_get_payload_from_ip6(
193                                (libtrace_ip6_t*)transport, proto, remaining);
194                        break;
195                default:
196                        *proto = 0;
197                        transport = NULL;
198                        break;
199                       
200        }
201
202        ((libtrace_packet_t *)packet)->transport_proto = *proto;
203        ((libtrace_packet_t *)packet)->l4_header = transport;
204        ((libtrace_packet_t *)packet)->l4_remaining = *remaining;
205
206
207        return transport;
208}
209
210DLLEXPORT libtrace_tcp_t *trace_get_tcp(libtrace_packet_t *packet) {
211        uint8_t proto;
212        uint32_t rem = 0;
213        libtrace_tcp_t *tcp;
214
215        tcp=(libtrace_tcp_t*)trace_get_transport(packet,&proto,&rem);
216
217        if (!tcp || proto != TRACE_IPPROTO_TCP)
218                return NULL;
219
220        /* We should return NULL if there isn't a full TCP header, because the
221         * caller has no way of telling how much of a TCP header we have
222         * returned - use trace_get_transport() if you want to deal with
223         * partial headers
224         *
225         * NOTE: We're not going to insist that all the TCP options are present
226         * as well, because lots of traces are snapped after 20 bytes of TCP
227         * header and I don't really want to break libtrace programs that
228         * use this function to process those traces */
229
230        if (rem < sizeof(libtrace_tcp_t))
231                return NULL;
232
233        return (libtrace_tcp_t*)tcp;
234}
235
236DLLEXPORT libtrace_tcp_t *trace_get_tcp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
237{
238        libtrace_tcp_t *tcpptr = 0;
239
240        if (ip->ip_p == TRACE_IPPROTO_TCP)  {
241                tcpptr = (libtrace_tcp_t *)
242                        trace_get_payload_from_ip(ip, NULL, remaining);
243        }
244
245        return tcpptr;
246}
247
248DLLEXPORT libtrace_udp_t *trace_get_udp(libtrace_packet_t *packet) {
249        uint8_t proto;
250        uint32_t rem = 0;
251        libtrace_udp_t *udp;
252
253        udp=(libtrace_udp_t*)trace_get_transport(packet,&proto,&rem);
254
255        if (!udp || proto != TRACE_IPPROTO_UDP)
256                return NULL;
257
258        /* Make sure we return a full UDP header as the caller has no way of
259         * telling how much of the packet is remaining */
260        if (rem < sizeof(libtrace_udp_t))
261                return NULL;
262
263        return udp;
264}
265
266DLLEXPORT libtrace_udp_t *trace_get_udp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
267{
268        libtrace_udp_t *udpptr = 0;
269
270        if (ip->ip_p == TRACE_IPPROTO_UDP) {
271                udpptr = (libtrace_udp_t *)
272                        trace_get_payload_from_ip(ip, NULL, remaining);
273        }
274
275        return udpptr;
276}
277
278DLLEXPORT libtrace_icmp_t *trace_get_icmp(libtrace_packet_t *packet) {
279        uint8_t proto;
280        uint32_t rem = 0;
281        libtrace_icmp_t *icmp;
282
283        icmp=(libtrace_icmp_t*)trace_get_transport(packet,&proto,&rem);
284
285        if (!icmp || proto != TRACE_IPPROTO_ICMP)
286                return NULL;
287
288        /* Make sure we return a full ICMP header as the caller has no way of
289         * telling how much of the packet is remaining */
290        if (rem < sizeof(libtrace_icmp_t))
291                return NULL;
292
293        return icmp;
294}
295
296DLLEXPORT libtrace_icmp6_t *trace_get_icmp6(libtrace_packet_t *packet) {
297        uint8_t proto;
298        uint32_t rem = 0;
299        libtrace_icmp6_t *icmp;
300
301        icmp=(libtrace_icmp6_t*)trace_get_transport(packet,&proto,&rem);
302
303        if (!icmp || proto != TRACE_IPPROTO_ICMPV6)
304                return NULL;
305
306        /* Make sure we return a full ICMP header as the caller has no way of
307         * telling how much of the packet is remaining */
308        if (rem < sizeof(libtrace_icmp6_t))
309                return NULL;
310
311        return icmp;
312}
313
314DLLEXPORT libtrace_icmp_t *trace_get_icmp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
315{
316        libtrace_icmp_t *icmpptr = 0;
317
318        if (ip->ip_p == TRACE_IPPROTO_ICMP)  {
319                icmpptr = (libtrace_icmp_t *)trace_get_payload_from_ip(ip, 
320                                NULL, remaining);
321        }
322
323        return icmpptr;
324}
325
326DLLEXPORT void *trace_get_payload_from_udp(libtrace_udp_t *udp, uint32_t *remaining)
327{
328        if (remaining) {
329                if (*remaining < sizeof(libtrace_udp_t)) {
330                        *remaining = 0;
331                        return NULL;
332                }
333                *remaining-=sizeof(libtrace_udp_t);
334        }
335        return (void*)((char*)udp+sizeof(libtrace_udp_t));
336}
337
338DLLEXPORT void *trace_get_payload_from_tcp(libtrace_tcp_t *tcp, uint32_t *remaining)
339{
340        unsigned int dlen = tcp->doff*4;
341        if (remaining) {
342                if (*remaining < dlen) {
343                        *remaining = 0;
344                        return NULL;
345                }
346                *remaining-=dlen;
347        }
348        return (void *)((char *)tcp+dlen);
349}
350
351DLLEXPORT void *trace_get_payload_from_icmp(libtrace_icmp_t *icmp, uint32_t *remaining)
352{
353        if (remaining) {
354                if (*remaining < sizeof(libtrace_icmp_t)) {
355                        *remaining = 0;
356                        return NULL;
357                }
358                *remaining-=sizeof(libtrace_icmp_t);
359        }
360        return (char*)icmp+sizeof(libtrace_icmp_t);
361}
362
363DLLEXPORT void *trace_get_payload_from_icmp6(libtrace_icmp6_t *icmp, uint32_t *remaining)
364{
365        if (remaining) {
366                if (*remaining < sizeof(libtrace_icmp6_t)) {
367                        *remaining = 0;
368                        return NULL;
369                }
370                *remaining-=sizeof(libtrace_icmp6_t);
371        }
372        return (char*)icmp+sizeof(libtrace_icmp6_t);
373}
374
375/* Return the source port
376 */
377DLLEXPORT uint16_t trace_get_source_port(const libtrace_packet_t *packet)
378{
379        uint32_t remaining;
380        uint8_t proto;
381        const struct ports_t *port = 
382                (const struct ports_t*)trace_get_transport((libtrace_packet_t*)packet,
383                        &proto, &remaining);
384
385        /* Snapped too early */
386        if (remaining<2)
387                return 0;
388
389        /* ICMP *technically* doesn't have ports */
390        if (proto == TRACE_IPPROTO_ICMP)
391                return 0;
392
393        if (port)
394                return ntohs(port->src);
395        else
396                return 0;
397}
398
399/* Same as get_source_port except use the destination port */
400DLLEXPORT uint16_t trace_get_destination_port(const libtrace_packet_t *packet)
401{
402        uint32_t remaining;
403        uint8_t proto;
404        struct ports_t *port = 
405                (struct ports_t*)trace_get_transport((libtrace_packet_t*)packet,
406                        &proto, &remaining);
407        /* Snapped too early */
408        if (remaining<4)
409                return 0;
410       
411        /* ICMP *technically* doesn't have ports */
412        if (proto == TRACE_IPPROTO_ICMP)
413                return 0;
414
415        if (port)
416                return ntohs(port->dst);
417        else
418                return 0;
419}
420
421
Note: See TracBrowser for help on using the repository browser.