source: lib/protocols_transport.c @ 3038cd2

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