source: lib/protocols_transport.c @ 7e8a25a

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