source: lib/protocols_transport.c @ 15749d5

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

Added a trace_get_payload_length() function which returns the original payload length for a packet - got sick of re-implementing this function everytime I wanted to know the size of the application payload.

This function currently works for TCP, UDP and ICMP packets. All other protocols
will return 0.

  • Property mode set to 100644
File size: 7.9 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        layer = trace_get_layer3(packet, &ethertype, &rem);
71
72        if (!layer)
73                return 0;
74        switch (ethertype) {
75                case TRACE_ETHERTYPE_IP:
76                        ip = (libtrace_ip_t *)layer;
77                        if (rem < sizeof(libtrace_ip_t))
78                                return 0;
79                        len = ntohs(ip->ip_len) - (4 * ip->ip_hl);
80                        break;
81                case TRACE_ETHERTYPE_IPV6:
82                        ip6 = (libtrace_ip6_t *)layer;
83                        if (rem < sizeof(libtrace_ip6_t))
84                                return 0;
85                        len = ntohs(ip6->plen);
86                        break;
87                default:
88                        return 0;
89        }
90
91        layer = trace_get_transport(packet, &proto, &rem);
92        if (!layer)
93                return 0;
94       
95        switch(proto) {
96                case TRACE_IPPROTO_TCP:
97                        tcp = (libtrace_tcp_t *)layer;
98                        len -= (4 * tcp->doff);
99                        break;
100                case TRACE_IPPROTO_UDP:
101                        len -= sizeof(libtrace_udp_t);
102                        break;
103                case TRACE_IPPROTO_ICMP:
104                        len -= sizeof(libtrace_icmp_t);
105                        break;
106                default:
107                        return 0;
108        }
109
110        return len;
111
112}
113
114DLLEXPORT void *trace_get_transport(const libtrace_packet_t *packet, 
115                uint8_t *proto,
116                uint32_t *remaining
117                ) 
118{
119        uint8_t dummy_proto;
120        uint16_t ethertype;
121        uint32_t dummy_remaining;
122        void *transport;
123
124        if (!proto) proto=&dummy_proto;
125
126        if (!remaining) remaining=&dummy_remaining;
127
128        transport = trace_get_layer3(packet,&ethertype,remaining);
129
130        if (!transport || *remaining == 0)
131                return NULL;
132
133        switch (ethertype) {
134                case TRACE_ETHERTYPE_IP: /* IPv4 */
135                        transport=trace_get_payload_from_ip(
136                                (libtrace_ip_t*)transport, proto, remaining);
137                        /* IPv6 */
138                        if (transport && *proto == TRACE_IPPROTO_IPV6) {
139                                transport=trace_get_payload_from_ip6(
140                                 (libtrace_ip6_t*)transport, proto,remaining);
141                        }
142                        return transport;
143                case TRACE_ETHERTYPE_IPV6: /* IPv6 */
144                        return trace_get_payload_from_ip6(
145                                (libtrace_ip6_t*)transport, proto, remaining);
146                       
147        }
148
149        *proto=0;
150        return NULL;
151}
152
153DLLEXPORT libtrace_tcp_t *trace_get_tcp(libtrace_packet_t *packet) {
154        uint8_t proto;
155        uint32_t rem = 0;
156        libtrace_tcp_t *tcp;
157
158        tcp=(libtrace_tcp_t*)trace_get_transport(packet,&proto,&rem);
159
160        if (!tcp || proto != TRACE_IPPROTO_TCP)
161                return NULL;
162
163        /* We should return NULL if there isn't a full TCP header, because the
164         * caller has no way of telling how much of a TCP header we have
165         * returned - use trace_get_transport() if you want to deal with
166         * partial headers
167         *
168         * NOTE: We're not going to insist that all the TCP options are present
169         * as well, because lots of traces are snapped after 20 bytes of TCP
170         * header and I don't really want to break libtrace programs that
171         * use this function to process those traces */
172
173        if (rem < sizeof(libtrace_tcp_t))
174                return NULL;
175
176        return (libtrace_tcp_t*)tcp;
177}
178
179DLLEXPORT libtrace_tcp_t *trace_get_tcp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
180{
181        libtrace_tcp_t *tcpptr = 0;
182
183        if (ip->ip_p == TRACE_IPPROTO_TCP)  {
184                tcpptr = (libtrace_tcp_t *)
185                        trace_get_payload_from_ip(ip, NULL, remaining);
186        }
187
188        return tcpptr;
189}
190
191DLLEXPORT libtrace_udp_t *trace_get_udp(libtrace_packet_t *packet) {
192        uint8_t proto;
193        uint32_t rem = 0;
194        libtrace_udp_t *udp;
195
196        udp=(libtrace_udp_t*)trace_get_transport(packet,&proto,&rem);
197
198        if (!udp || proto != TRACE_IPPROTO_UDP)
199                return NULL;
200
201        /* Make sure we return a full UDP header as the caller has no way of
202         * telling how much of the packet is remaining */
203        if (rem < sizeof(libtrace_udp_t))
204                return NULL;
205
206        return udp;
207}
208
209DLLEXPORT libtrace_udp_t *trace_get_udp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
210{
211        libtrace_udp_t *udpptr = 0;
212
213        if (ip->ip_p == TRACE_IPPROTO_UDP) {
214                udpptr = (libtrace_udp_t *)
215                        trace_get_payload_from_ip(ip, NULL, remaining);
216        }
217
218        return udpptr;
219}
220
221DLLEXPORT libtrace_icmp_t *trace_get_icmp(libtrace_packet_t *packet) {
222        uint8_t proto;
223        uint32_t rem = 0;
224        libtrace_icmp_t *icmp;
225
226        icmp=(libtrace_icmp_t*)trace_get_transport(packet,&proto,&rem);
227
228        if (!icmp || proto != TRACE_IPPROTO_ICMP)
229                return NULL;
230
231        /* Make sure we return a full ICMP header as the caller has no way of
232         * telling how much of the packet is remaining */
233        if (rem < sizeof(libtrace_icmp_t))
234                return NULL;
235
236        return icmp;
237}
238
239DLLEXPORT libtrace_icmp_t *trace_get_icmp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
240{
241        libtrace_icmp_t *icmpptr = 0;
242
243        if (ip->ip_p == TRACE_IPPROTO_ICMP)  {
244                icmpptr = (libtrace_icmp_t *)trace_get_payload_from_ip(ip, 
245                                NULL, remaining);
246        }
247
248        return icmpptr;
249}
250
251DLLEXPORT void *trace_get_payload_from_udp(libtrace_udp_t *udp, uint32_t *remaining)
252{
253        if (remaining) {
254                if (*remaining < sizeof(libtrace_udp_t)) {
255                        *remaining = 0;
256                        return NULL;
257                }
258                *remaining-=sizeof(libtrace_udp_t);
259        }
260        return (void*)((char*)udp+sizeof(libtrace_udp_t));
261}
262
263DLLEXPORT void *trace_get_payload_from_tcp(libtrace_tcp_t *tcp, uint32_t *remaining)
264{
265        unsigned int dlen = tcp->doff*4;
266        if (remaining) {
267                if (*remaining < dlen) {
268                        *remaining = 0;
269                        return NULL;
270                }
271                *remaining-=dlen;
272        }
273        return (void *)((char *)tcp+dlen);
274}
275
276DLLEXPORT void *trace_get_payload_from_icmp(libtrace_icmp_t *icmp, uint32_t *remaining)
277{
278        if (remaining) {
279                if (*remaining < sizeof(libtrace_icmp_t)) {
280                        *remaining = 0;
281                        return NULL;
282                }
283                *remaining-=sizeof(libtrace_icmp_t);
284        }
285        return (char*)icmp+sizeof(libtrace_icmp_t);
286}
287
288/* Return the source port
289 */
290DLLEXPORT uint16_t trace_get_source_port(const libtrace_packet_t *packet)
291{
292        uint32_t remaining;
293        uint8_t proto;
294        const struct ports_t *port = 
295                (const struct ports_t*)trace_get_transport((libtrace_packet_t*)packet,
296                        &proto, &remaining);
297
298        /* Snapped too early */
299        if (remaining<2)
300                return 0;
301
302        /* ICMP *technically* doesn't have ports */
303        if (proto == TRACE_IPPROTO_ICMP)
304                return 0;
305
306        if (port)
307                return ntohs(port->src);
308        else
309                return 0;
310}
311
312/* Same as get_source_port except use the destination port */
313DLLEXPORT uint16_t trace_get_destination_port(const libtrace_packet_t *packet)
314{
315        uint32_t remaining;
316        uint8_t proto;
317        struct ports_t *port = 
318                (struct ports_t*)trace_get_transport((libtrace_packet_t*)packet,
319                        &proto, &remaining);
320        /* Snapped too early */
321        if (remaining<4)
322                return 0;
323       
324        /* ICMP *technically* doesn't have ports */
325        if (proto == TRACE_IPPROTO_ICMP)
326                return 0;
327
328        if (port)
329                return ntohs(port->dst);
330        else
331                return 0;
332}
333
334
Note: See TracBrowser for help on using the repository browser.