source: lib/protocols_transport.c @ 68b7f29

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 68b7f29 was c909fad, checked in by Shane Alcock <salcock@…>, 8 years ago
  • Added checksumming functions for both the IP and transport layer. The functions will calculate the correct checksum for that packet and also return a pointer to the checksum field in the appropriate header so that the caller can either evaluate whether the checksum is correct, replace the existing checksum, or do whatever they want.
  • Also managed to fix a bunch of broken Revision svn tags
  • Property mode set to 100644
File size: 12.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 "checksum.h"
38#include <assert.h>
39#include <stdlib.h>
40#include <stdio.h> // fprintf
41#include <string.h>
42
43/* This file contains all the protocol decoding functions for transport layer
44 * protocols. This includes functions for access port numbers.
45 *
46 * Supported protocols include (but are not limited to):
47 *      TCP
48 *      UDP
49 *      ICMP
50 */
51
52/* Get the size of the payload as it was in the original packet, i.e. prior
53 * to any truncation.
54 *
55 * Basically, wire length minus the packet headers.
56 *
57 * Currently only supports IP (v4 and v6) and TCP, UDP and ICMP. Will return
58 * 0 if an unsupported protocol header is encountered, or if one of the
59 * headers is truncated.
60 */
61DLLEXPORT size_t trace_get_payload_length(const libtrace_packet_t *packet) {
62
63        void *layer;
64        uint16_t ethertype;
65        uint8_t proto;
66        uint32_t rem;
67        libtrace_ip_t *ip;
68        libtrace_ip6_t *ip6;
69        libtrace_tcp_t *tcp;
70        size_t len = 0;
71
72        /* Just use the cached length if we can */
73        if (packet->payload_length != -1)
74                return packet->payload_length; 
75
76        /* Set to zero so that we can return early without having to
77         * worry about forgetting to update the cached value */
78        ((libtrace_packet_t *)packet)->payload_length = 0;
79        layer = trace_get_layer3(packet, &ethertype, &rem);
80        if (!layer)
81                return 0;
82        switch (ethertype) {
83                case TRACE_ETHERTYPE_IP:
84                        ip = (libtrace_ip_t *)layer;
85                        if (rem < sizeof(libtrace_ip_t))
86                                return 0;
87                        len = ntohs(ip->ip_len) - (4 * ip->ip_hl);
88               
89                        /* Deal with v6 within v4 */
90                        if (ip->ip_p == TRACE_IPPROTO_IPV6)
91                                len -= sizeof(libtrace_ip6_t);
92                       
93                        break;
94                case TRACE_ETHERTYPE_IPV6:
95                        ip6 = (libtrace_ip6_t *)layer;
96                        if (rem < sizeof(libtrace_ip6_t))
97                                return 0;
98                        len = ntohs(ip6->plen);
99                        break;
100                default:
101                        return 0;
102        }
103
104        layer = trace_get_transport(packet, &proto, &rem);
105        if (!layer)
106                return 0;
107       
108        switch(proto) {
109                case TRACE_IPPROTO_TCP:
110                        if (rem < sizeof(libtrace_tcp_t))
111                                return 0;
112                        tcp = (libtrace_tcp_t *)layer;
113                       
114                        if (len < (size_t)(4 * tcp->doff))
115                                return 0;
116                       
117                        len -= (4 * tcp->doff);
118                        break;
119                case TRACE_IPPROTO_UDP:
120                        if (rem < sizeof(libtrace_udp_t))
121                                return 0;
122                        if (len < sizeof(libtrace_udp_t))
123                                return 0;
124                        len -= sizeof(libtrace_udp_t);
125                        break;
126                case TRACE_IPPROTO_ICMP:
127                        if (rem < sizeof(libtrace_icmp_t))
128                                return 0;
129                        if (len < sizeof(libtrace_icmp_t))
130                                return 0;
131                        len -= sizeof(libtrace_icmp_t);
132                        break;
133                case TRACE_IPPROTO_ICMPV6:
134                        if (rem < sizeof(libtrace_icmp6_t))
135                                return 0;
136                        if (len < sizeof(libtrace_icmp6_t))
137                                return 0;
138                        len -= sizeof(libtrace_icmp6_t);
139                        break;
140                       
141                default:
142                        return 0;
143        }
144
145        ((libtrace_packet_t *)packet)->payload_length = len;
146        return len;
147
148}
149
150DLLEXPORT void *trace_get_transport(const libtrace_packet_t *packet, 
151                uint8_t *proto,
152                uint32_t *remaining
153                ) 
154{
155        uint8_t dummy_proto;
156        uint16_t ethertype;
157        uint32_t dummy_remaining;
158        void *transport;
159
160        if (!proto) proto=&dummy_proto;
161
162        if (!remaining) remaining=&dummy_remaining;
163
164        if (packet->l4_header) {
165                /*
166                void *link;
167                libtrace_linktype_t linktype;
168                link = trace_get_packet_buffer(packet, &linktype, remaining);
169                if (!link)
170                        return NULL;
171                */
172                *proto = packet->transport_proto;
173                /* *remaining -= (packet->l4_header - link); */
174                *remaining = packet->l4_remaining;
175                return packet->l4_header;
176        }
177
178        transport = trace_get_layer3(packet,&ethertype,remaining);
179
180        if (!transport || *remaining == 0)
181                return NULL;
182
183        switch (ethertype) {
184                case TRACE_ETHERTYPE_IP: /* IPv4 */
185                        transport=trace_get_payload_from_ip(
186                                (libtrace_ip_t*)transport, proto, remaining);
187                        /* IPv6 */
188                        if (transport && *proto == TRACE_IPPROTO_IPV6) {
189                                transport=trace_get_payload_from_ip6(
190                                 (libtrace_ip6_t*)transport, proto,remaining);
191                        }
192                        break;
193                case TRACE_ETHERTYPE_IPV6: /* IPv6 */
194                        transport = trace_get_payload_from_ip6(
195                                (libtrace_ip6_t*)transport, proto, remaining);
196                        break;
197                default:
198                        *proto = 0;
199                        transport = NULL;
200                        break;
201                       
202        }
203
204        ((libtrace_packet_t *)packet)->transport_proto = *proto;
205        ((libtrace_packet_t *)packet)->l4_header = transport;
206        ((libtrace_packet_t *)packet)->l4_remaining = *remaining;
207
208
209        return transport;
210}
211
212DLLEXPORT libtrace_tcp_t *trace_get_tcp(libtrace_packet_t *packet) {
213        uint8_t proto;
214        uint32_t rem = 0;
215        libtrace_tcp_t *tcp;
216
217        tcp=(libtrace_tcp_t*)trace_get_transport(packet,&proto,&rem);
218
219        if (!tcp || proto != TRACE_IPPROTO_TCP)
220                return NULL;
221
222        /* We should return NULL if there isn't a full TCP header, because the
223         * caller has no way of telling how much of a TCP header we have
224         * returned - use trace_get_transport() if you want to deal with
225         * partial headers
226         *
227         * NOTE: We're not going to insist that all the TCP options are present
228         * as well, because lots of traces are snapped after 20 bytes of TCP
229         * header and I don't really want to break libtrace programs that
230         * use this function to process those traces */
231
232        if (rem < sizeof(libtrace_tcp_t))
233                return NULL;
234
235        return (libtrace_tcp_t*)tcp;
236}
237
238DLLEXPORT libtrace_tcp_t *trace_get_tcp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
239{
240        libtrace_tcp_t *tcpptr = 0;
241
242        if (ip->ip_p == TRACE_IPPROTO_TCP)  {
243                tcpptr = (libtrace_tcp_t *)
244                        trace_get_payload_from_ip(ip, NULL, remaining);
245        }
246
247        return tcpptr;
248}
249
250DLLEXPORT libtrace_udp_t *trace_get_udp(libtrace_packet_t *packet) {
251        uint8_t proto;
252        uint32_t rem = 0;
253        libtrace_udp_t *udp;
254
255        udp=(libtrace_udp_t*)trace_get_transport(packet,&proto,&rem);
256
257        if (!udp || proto != TRACE_IPPROTO_UDP)
258                return NULL;
259
260        /* Make sure we return a full UDP header as the caller has no way of
261         * telling how much of the packet is remaining */
262        if (rem < sizeof(libtrace_udp_t))
263                return NULL;
264
265        return udp;
266}
267
268DLLEXPORT libtrace_udp_t *trace_get_udp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
269{
270        libtrace_udp_t *udpptr = 0;
271
272        if (ip->ip_p == TRACE_IPPROTO_UDP) {
273                udpptr = (libtrace_udp_t *)
274                        trace_get_payload_from_ip(ip, NULL, remaining);
275        }
276
277        return udpptr;
278}
279
280DLLEXPORT libtrace_icmp_t *trace_get_icmp(libtrace_packet_t *packet) {
281        uint8_t proto;
282        uint32_t rem = 0;
283        libtrace_icmp_t *icmp;
284
285        icmp=(libtrace_icmp_t*)trace_get_transport(packet,&proto,&rem);
286
287        if (!icmp || proto != TRACE_IPPROTO_ICMP)
288                return NULL;
289
290        /* Make sure we return a full ICMP header as the caller has no way of
291         * telling how much of the packet is remaining */
292        if (rem < sizeof(libtrace_icmp_t))
293                return NULL;
294
295        return icmp;
296}
297
298DLLEXPORT libtrace_icmp6_t *trace_get_icmp6(libtrace_packet_t *packet) {
299        uint8_t proto;
300        uint32_t rem = 0;
301        libtrace_icmp6_t *icmp;
302
303        icmp=(libtrace_icmp6_t*)trace_get_transport(packet,&proto,&rem);
304
305        if (!icmp || proto != TRACE_IPPROTO_ICMPV6)
306                return NULL;
307
308        /* Make sure we return a full ICMP header as the caller has no way of
309         * telling how much of the packet is remaining */
310        if (rem < sizeof(libtrace_icmp6_t))
311                return NULL;
312
313        return icmp;
314}
315
316DLLEXPORT libtrace_icmp_t *trace_get_icmp_from_ip(libtrace_ip_t *ip, uint32_t *remaining)
317{
318        libtrace_icmp_t *icmpptr = 0;
319
320        if (ip->ip_p == TRACE_IPPROTO_ICMP)  {
321                icmpptr = (libtrace_icmp_t *)trace_get_payload_from_ip(ip, 
322                                NULL, remaining);
323        }
324
325        return icmpptr;
326}
327
328DLLEXPORT void *trace_get_payload_from_udp(libtrace_udp_t *udp, uint32_t *remaining)
329{
330        if (remaining) {
331                if (*remaining < sizeof(libtrace_udp_t)) {
332                        *remaining = 0;
333                        return NULL;
334                }
335                *remaining-=sizeof(libtrace_udp_t);
336        }
337        return (void*)((char*)udp+sizeof(libtrace_udp_t));
338}
339
340DLLEXPORT void *trace_get_payload_from_tcp(libtrace_tcp_t *tcp, uint32_t *remaining)
341{
342        unsigned int dlen = tcp->doff*4;
343        if (remaining) {
344                if (*remaining < dlen) {
345                        *remaining = 0;
346                        return NULL;
347                }
348                *remaining-=dlen;
349        }
350        return (void *)((char *)tcp+dlen);
351}
352
353DLLEXPORT void *trace_get_payload_from_icmp(libtrace_icmp_t *icmp, uint32_t *remaining)
354{
355        if (remaining) {
356                if (*remaining < sizeof(libtrace_icmp_t)) {
357                        *remaining = 0;
358                        return NULL;
359                }
360                *remaining-=sizeof(libtrace_icmp_t);
361        }
362        return (char*)icmp+sizeof(libtrace_icmp_t);
363}
364
365DLLEXPORT void *trace_get_payload_from_icmp6(libtrace_icmp6_t *icmp, uint32_t *remaining)
366{
367        if (remaining) {
368                if (*remaining < sizeof(libtrace_icmp6_t)) {
369                        *remaining = 0;
370                        return NULL;
371                }
372                *remaining-=sizeof(libtrace_icmp6_t);
373        }
374        return (char*)icmp+sizeof(libtrace_icmp6_t);
375}
376
377/* Return the source port
378 */
379DLLEXPORT uint16_t trace_get_source_port(const libtrace_packet_t *packet)
380{
381        uint32_t remaining;
382        uint8_t proto;
383        const struct ports_t *port = 
384                (const struct ports_t*)trace_get_transport((libtrace_packet_t*)packet,
385                        &proto, &remaining);
386
387        /* Snapped too early */
388        if (remaining<2)
389                return 0;
390
391        /* ICMP *technically* doesn't have ports */
392        if (proto == TRACE_IPPROTO_ICMP)
393                return 0;
394
395        if (port)
396                return ntohs(port->src);
397        else
398                return 0;
399}
400
401/* Same as get_source_port except use the destination port */
402DLLEXPORT uint16_t trace_get_destination_port(const libtrace_packet_t *packet)
403{
404        uint32_t remaining;
405        uint8_t proto;
406        struct ports_t *port = 
407                (struct ports_t*)trace_get_transport((libtrace_packet_t*)packet,
408                        &proto, &remaining);
409        /* Snapped too early */
410        if (remaining<4)
411                return 0;
412       
413        /* ICMP *technically* doesn't have ports */
414        if (proto == TRACE_IPPROTO_ICMP)
415                return 0;
416
417        if (port)
418                return ntohs(port->dst);
419        else
420                return 0;
421}
422
423DLLEXPORT uint16_t *trace_checksum_transport(libtrace_packet_t *packet, 
424                uint16_t *csum) {
425
426        void *header = NULL;
427        uint16_t ethertype;
428        uint32_t remaining;
429        uint32_t sum = 0;
430        uint8_t proto = 0;
431        uint16_t *csum_ptr = NULL;
432        int plen = 0;
433
434        uint8_t safety[65536];
435        uint8_t *ptr = safety;
436
437        header = trace_get_layer3(packet, &ethertype, &remaining);
438
439        if (header == NULL)
440                return NULL;
441       
442        if (ethertype == TRACE_ETHERTYPE_IP) {
443                libtrace_ip_t *ip = (libtrace_ip_t *)header;
444
445                if (remaining < sizeof(libtrace_ip_t))
446                        return NULL;
447
448                sum = ipv4_pseudo_checksum(ip);
449
450        } else if (ethertype == TRACE_ETHERTYPE_IPV6) {
451                libtrace_ip6_t *ip = (libtrace_ip6_t *)header;
452               
453                if (remaining < sizeof(libtrace_ip6_t))
454                        return 0;
455
456                sum = ipv6_pseudo_checksum(ip);
457       
458        }
459
460        header = trace_get_transport(packet, &proto, &remaining);
461
462        if (proto == TRACE_IPPROTO_TCP) {
463                libtrace_tcp_t *tcp = (libtrace_tcp_t *)header;
464                header = trace_get_payload_from_tcp(tcp, &remaining);
465               
466                csum_ptr = &tcp->check;
467
468                memcpy(ptr, tcp, tcp->doff * 4);
469
470                tcp = (libtrace_tcp_t *)ptr;
471                tcp->check = 0;
472
473                ptr += (tcp->doff * 4);
474        } 
475       
476        else if (proto == TRACE_IPPROTO_UDP) {
477
478                libtrace_udp_t *udp = (libtrace_udp_t *)header;
479                header = trace_get_payload_from_udp(udp, &remaining);
480               
481                csum_ptr = &udp->check;
482                memcpy(ptr, udp, sizeof(libtrace_udp_t));
483
484                udp = (libtrace_udp_t *)ptr;
485                udp->check = 0;
486
487                ptr += sizeof(libtrace_udp_t);
488        } 
489       
490        else if (proto == TRACE_IPPROTO_ICMP) {
491                /* ICMP doesn't use the pseudo header */
492                sum = 0;
493
494                libtrace_icmp_t *icmp = (libtrace_icmp_t *)header;
495                header = trace_get_payload_from_icmp(icmp, &remaining);
496               
497                csum_ptr = &icmp->checksum;
498                memcpy(ptr, icmp, sizeof(libtrace_icmp_t));
499
500                icmp = (libtrace_icmp_t *)ptr;
501                icmp->checksum = 0;
502               
503                ptr += sizeof(libtrace_icmp_t);
504
505        } 
506        else {
507                return NULL;
508        }
509
510        sum += add_checksum(safety, (uint16_t)(ptr - safety));
511
512        plen = trace_get_payload_length(packet);
513        if (plen < 0)
514                return NULL;
515
516        if (remaining < (uint32_t)plen)
517                return NULL;
518
519        if (header == NULL)
520                return NULL;
521
522        sum += add_checksum(header, (uint16_t)plen);
523        *csum = ntohs(finish_checksum(sum));
524        //assert(0);
525       
526        return csum_ptr;
527}
Note: See TracBrowser for help on using the repository browser.