source: lib/format_linux_int.c @ fce4572

develop
Last change on this file since fce4572 was fce4572, checked in by Shane Alcock <salcock@…>, 22 months ago

Add more failure cases to "can_write" functions for some formats.

Specifically:

  • Avoid writing metadata packets to DPDK, ring and int
  • Make sure all formats avoid writing "content invalid" packets.
  • Add comments to remind us that erf meta <-> pcapng meta conversion might be worth adding at some point.
  • Add comment to remind us that erf meta should be writable via a DAG card (I think).
  • Property mode set to 100644
File size: 17.4 KB
Line 
1/*
2 *
3 * Copyright (c) 2007-2016 The University of Waikato, Hamilton, New Zealand.
4 * All rights reserved.
5 *
6 * This file is part of libtrace.
7 *
8 * This code has been developed by the University of Waikato WAND
9 * research group. For further information please see http://www.wand.net.nz/
10 *
11 * libtrace is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * libtrace is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 *
24 *
25 */
26
27/* This format module deals with using the Linux Native capture format.
28 *
29 * Linux Native is a LIVE capture format.
30 *
31 * This format also supports writing which will write packets out to the
32 * network as a form of packet replay. This should not be confused with the
33 * RT protocol which is intended to transfer captured packet records between
34 * RT-speaking programs.
35 */
36
37#include "config.h"
38#include "libtrace.h"
39#include "libtrace_int.h"
40#include "format_helper.h"
41#include "libtrace_arphrd.h"
42#include <stdlib.h>
43#include <errno.h>
44#include <unistd.h>
45#include <string.h>
46
47#ifdef HAVE_INTTYPES_H
48#  include <inttypes.h>
49#else
50# error "Can't find inttypes.h"
51#endif
52
53#include "format_linux_common.h"
54
55
56#ifdef HAVE_NETPACKET_PACKET_H
57
58static bool linuxnative_can_write(libtrace_packet_t *packet) {
59        /* Get the linktype */
60        libtrace_linktype_t ltype = trace_get_link_type(packet);
61
62        if (ltype == TRACE_TYPE_NONDATA) {
63                return false;
64        }
65        if (ltype == TRACE_TYPE_CONTENT_INVALID) {
66                return false;
67        }
68        if (ltype == TRACE_TYPE_PCAPNG_META) {
69                return false;
70        }
71        if (ltype == TRACE_TYPE_ERF_META) {
72                return false;
73        }
74
75        return true;
76}
77
78static int linuxnative_start_input(libtrace_t *libtrace)
79{
80        int ret = linuxcommon_start_input_stream(libtrace, FORMAT_DATA_FIRST);
81        return ret;
82}
83
84#ifdef HAVE_PACKET_FANOUT
85static int linuxnative_pstart_input(libtrace_t *libtrace) {
86        return linuxcommon_pstart_input(libtrace, linuxcommon_start_input_stream);
87}
88#endif
89
90static int linuxnative_start_output(libtrace_out_t *libtrace)
91{
92        FORMAT_DATA_OUT->fd = socket(PF_PACKET, SOCK_RAW, 0);
93        if (FORMAT_DATA_OUT->fd==-1) {
94                free(FORMAT_DATA_OUT);
95                trace_set_err_out(libtrace, errno, "Failed to create raw socket");
96                return -1;
97        }
98
99        return 0;
100}
101
102static int linuxnative_fin_output(libtrace_out_t *libtrace)
103{
104        close(FORMAT_DATA_OUT->fd);
105        FORMAT_DATA_OUT->fd=-1;
106        free(libtrace->format_data);
107        return 0;
108}
109#endif /* HAVE_NETPACKET_PACKET_H */
110
111static int linuxnative_prepare_packet(libtrace_t *libtrace UNUSED, 
112                libtrace_packet_t *packet, void *buffer, 
113                libtrace_rt_types_t rt_type, uint32_t flags) {
114
115        if (packet->buffer != buffer &&
116            packet->buf_control == TRACE_CTRL_PACKET) {
117                free(packet->buffer);
118        }
119
120        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
121                packet->buf_control = TRACE_CTRL_PACKET;
122        } else
123                packet->buf_control = TRACE_CTRL_EXTERNAL;
124
125
126        packet->buffer = buffer;
127        packet->header = buffer;
128        packet->payload = (char *)buffer + 
129                sizeof(struct libtrace_linuxnative_header);
130        packet->type = rt_type;
131
132        /*
133        if (libtrace->format_data == NULL) {
134                if (linuxnative_init_input(libtrace))
135                        return -1;
136        }
137        */
138        return 0;
139       
140}
141
142#define LIBTRACE_MIN(a,b) ((a)<(b) ? (a) : (b))
143
144/* 20 isn't enough on x86_64 */
145#define CMSG_BUF_SIZE 128
146
147#ifdef HAVE_NETPACKET_PACKET_H
148inline static int linuxnative_read_stream(libtrace_t *libtrace,
149                                          libtrace_packet_t *packet,
150                                          struct linux_per_stream_t *stream,
151                                          libtrace_message_queue_t *queue)
152{
153        struct libtrace_linuxnative_header *hdr;
154        struct msghdr msghdr;
155        struct iovec iovec;
156        unsigned char controlbuf[CMSG_BUF_SIZE];
157        struct cmsghdr *cmsg;
158        int snaplen;
159
160        uint32_t flags = 0;
161        fd_set readfds;
162        struct timeval tout;
163        int ret;
164       
165        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
166                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
167                if (!packet->buffer) {
168                        perror("Cannot allocate buffer");
169                }
170        }
171
172        flags |= TRACE_PREP_OWN_BUFFER;
173       
174        packet->type = TRACE_RT_DATA_LINUX_NATIVE;
175
176        hdr=(struct libtrace_linuxnative_header*)packet->buffer;
177        snaplen=LIBTRACE_MIN(
178                        (int)LIBTRACE_PACKET_BUFSIZE-(int)sizeof(*hdr),
179                        (int)FORMAT_DATA->snaplen);
180        /* Prepare the msghdr and iovec for the kernel to write the
181         * captured packet into. The msghdr will point to the part of our
182         * buffer reserved for sll header, while the iovec will point at
183         * the buffer following the sll header. */
184
185        msghdr.msg_name = &hdr->hdr;
186        msghdr.msg_namelen = sizeof(struct sockaddr_ll);
187
188        msghdr.msg_iov = &iovec;
189        msghdr.msg_iovlen = 1;
190
191        msghdr.msg_control = &controlbuf;
192        msghdr.msg_controllen = CMSG_BUF_SIZE;
193        msghdr.msg_flags = 0;
194
195        iovec.iov_base = (void*)(packet->buffer+sizeof(*hdr));
196        iovec.iov_len = snaplen;
197
198        // Check for a packet - TODO only Linux has MSG_DONTWAIT should use fctl O_NONBLOCK
199        /* Try check ahead this should be fast if something is waiting  */
200        hdr->wirelen = recvmsg(stream->fd, &msghdr, MSG_DONTWAIT | MSG_TRUNC);
201
202        /* No data was waiting */
203        if ((int) hdr->wirelen == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
204                /* Do message queue check or select */
205                int message_fd = 0;
206                int largestfd = stream->fd;
207
208                /* Also check the message queue */
209                if (queue) {
210                        message_fd = libtrace_message_queue_get_fd(queue);
211                        if (message_fd > largestfd)
212                                largestfd = message_fd;
213                }
214                do {
215                        /* Use select to allow us to time out occasionally to check if someone
216                         * has hit Ctrl-C or otherwise wants us to stop reading and return
217                         * so they can exit their program.
218                         */
219                        tout.tv_sec = 0;
220                        tout.tv_usec = 500000;
221                        /* Make sure we reset these each loop */
222                        FD_ZERO(&readfds);
223                        FD_SET(stream->fd, &readfds);
224                        if (queue)
225                                FD_SET(message_fd, &readfds);
226
227                        ret = select(largestfd+1, &readfds, NULL, NULL, &tout);
228                        if (ret >= 1) {
229                                /* A file descriptor triggered */
230                                break;
231                        } else if (ret < 0 && errno != EINTR) {
232                                trace_set_err(libtrace, errno, "select");
233                                return -1;
234                        } else {
235                                if ((ret=is_halted(libtrace)) != -1)
236                                        return ret;
237                        }
238                }
239                while (ret <= 0);
240
241                /* Message waiting? */
242                if (queue && FD_ISSET(message_fd, &readfds))
243                        return READ_MESSAGE;
244
245                /* We must have a packet */
246                hdr->wirelen = recvmsg(stream->fd, &msghdr, MSG_TRUNC);
247        }
248
249        if (hdr->wirelen==~0U) {
250                trace_set_err(libtrace,errno,"recvmsg");
251                return -1;
252        }
253
254        hdr->caplen=LIBTRACE_MIN((unsigned int)snaplen,(unsigned int)hdr->wirelen);
255
256        /* Extract the timestamps from the msghdr and store them in our
257         * linux native encapsulation, so that we can preserve the formatting
258         * across multiple architectures */
259
260        for (cmsg = CMSG_FIRSTHDR(&msghdr);
261                        cmsg != NULL;
262                        cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
263                if (cmsg->cmsg_level == SOL_SOCKET
264                        && cmsg->cmsg_type == SO_TIMESTAMP
265                        && cmsg->cmsg_len <= CMSG_LEN(sizeof(struct timeval))) {
266                       
267                        struct timeval *tv;
268                        tv = (struct timeval *)CMSG_DATA(cmsg);
269                       
270                       
271                        hdr->tv.tv_sec = tv->tv_sec;
272                        hdr->tv.tv_usec = tv->tv_usec;
273                        hdr->timestamptype = TS_TIMEVAL;
274                        break;
275                } 
276#ifdef SO_TIMESTAMPNS
277                else if (cmsg->cmsg_level == SOL_SOCKET
278                        && cmsg->cmsg_type == SO_TIMESTAMPNS
279                        && cmsg->cmsg_len <= CMSG_LEN(sizeof(struct timespec))) {
280
281                        struct timespec *tv;
282                        tv = (struct timespec *)CMSG_DATA(cmsg);
283
284                        hdr->ts.tv_sec = tv->tv_sec;
285                        hdr->ts.tv_nsec = tv->tv_nsec;
286                        hdr->timestamptype = TS_TIMESPEC;
287                        break;
288                }
289#endif
290        }
291
292        /* Did we not get given a timestamp? Try to get one from the
293         * file descriptor directly */
294        if (cmsg == NULL) {
295                struct timeval tv;
296                if (ioctl(stream->fd, SIOCGSTAMP,&tv)==0) {
297                        hdr->tv.tv_sec = tv.tv_sec;
298                        hdr->tv.tv_usec = tv.tv_usec;
299                        hdr->timestamptype = TS_TIMEVAL;
300                }
301                else {
302                        hdr->timestamptype = TS_NONE;
303                }
304        }
305
306
307        /* Buffer contains all of our packet (including our custom header) so
308         * we just need to get prepare_packet to set all our packet pointers
309         * appropriately */
310        packet->trace = libtrace;
311        if (linuxnative_prepare_packet(libtrace, packet, packet->buffer,
312                                packet->type, flags))
313                return -1;
314       
315        if (hdr->timestamptype == TS_TIMEVAL) {
316                packet->order = (((uint64_t)hdr->tv.tv_sec) << 32)
317                            + ((((uint64_t)hdr->tv.tv_usec) << 32) /1000000);
318        } else if (hdr->timestamptype == TS_TIMESPEC) {
319                packet->order = (((uint64_t)hdr->ts.tv_sec) << 32)
320                            + ((((uint64_t)hdr->ts.tv_nsec) << 32) /1000000000);
321        } else {
322                packet->order = 0;
323        }
324
325        if (packet->order <= stream->last_timestamp) {
326                packet->order = stream->last_timestamp + 1;
327        }
328
329        stream->last_timestamp = packet->order;
330
331        return hdr->wirelen+sizeof(*hdr);
332}
333
334static int linuxnative_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) 
335{
336        return linuxnative_read_stream(libtrace, packet, FORMAT_DATA_FIRST, NULL);
337}
338
339#ifdef HAVE_PACKET_FANOUT
340static int linuxnative_pread_packets(libtrace_t *libtrace,
341                                     libtrace_thread_t *t,
342                                     libtrace_packet_t *packets[],
343                                     UNUSED size_t nb_packets) {
344        /* For now just read one packet */
345        packets[0]->error = linuxnative_read_stream(libtrace, packets[0],
346                                                       t->format_data, &t->messages);
347        if (packets[0]->error >= 1)
348                return 1;
349        else
350                return packets[0]->error;
351}
352#endif
353
354static int linuxnative_write_packet(libtrace_out_t *libtrace,
355                libtrace_packet_t *packet) 
356{
357        /* Check linuxnative can write this type of packet */
358        if (!linuxnative_can_write(packet)) {
359                return 0;
360        }
361
362        struct sockaddr_ll hdr;
363        int ret = 0;
364
365        hdr.sll_family = AF_PACKET;
366        hdr.sll_protocol = 0;
367        hdr.sll_ifindex = if_nametoindex(libtrace->uridata);
368        hdr.sll_hatype = 0;
369        hdr.sll_pkttype = 0;
370        hdr.sll_halen = htons(6); /* FIXME */
371        memcpy(hdr.sll_addr,packet->payload,(size_t)ntohs(hdr.sll_halen));
372
373        /* This is pretty easy, just send the payload using sendto() (after
374         * setting up the sll header properly, of course) */
375        ret = sendto(FORMAT_DATA_OUT->fd,
376                        packet->payload,
377                        trace_get_capture_length(packet),
378                        0,
379                        (struct sockaddr*)&hdr, (socklen_t)sizeof(hdr));
380
381        if (ret < 0) {
382                trace_set_err_out(libtrace, errno, "sendto failed");
383        }
384
385        return ret;
386}
387#endif /* HAVE_NETPACKET_PACKET_H */
388
389
390static libtrace_linktype_t linuxnative_get_link_type(const struct libtrace_packet_t *packet) {
391        uint16_t linktype=(((struct libtrace_linuxnative_header*)(packet->buffer))
392                                ->hdr.sll_hatype);
393        return linuxcommon_get_link_type(linktype);
394}
395
396static libtrace_direction_t linuxnative_get_direction(const struct libtrace_packet_t *packet) {
397        return linuxcommon_get_direction(((struct libtrace_linuxnative_header*)(packet->buffer))->hdr.sll_pkttype);
398}
399
400static libtrace_direction_t linuxnative_set_direction(
401                libtrace_packet_t *packet,
402                libtrace_direction_t direction) {
403        return linuxcommon_set_direction(&((struct libtrace_linuxnative_header*)(packet->buffer))->hdr, direction);
404}
405
406static struct timespec linuxnative_get_timespec(const libtrace_packet_t *packet) 
407{
408        struct libtrace_linuxnative_header *hdr = 
409                (struct libtrace_linuxnative_header*) packet->buffer;
410        /* We have to upconvert from timeval to timespec */
411        if (hdr->timestamptype == TS_TIMEVAL) {
412                struct timespec ts;
413                ts.tv_sec = hdr->tv.tv_sec;
414                ts.tv_nsec = hdr->tv.tv_usec*1000;
415                return ts;
416        }
417        else {
418                struct timespec ts;
419                ts.tv_sec = hdr->ts.tv_sec;
420                ts.tv_nsec = hdr->ts.tv_nsec;
421                return ts;
422        }
423}
424
425static struct timeval linuxnative_get_timeval(const libtrace_packet_t *packet) 
426{
427        struct libtrace_linuxnative_header *hdr = 
428                (struct libtrace_linuxnative_header*) packet->buffer;
429        /* We have to downconvert from timespec to timeval */
430        if (hdr->timestamptype == TS_TIMESPEC) {
431                struct timeval tv;
432                tv.tv_sec = hdr->ts.tv_sec;
433                tv.tv_usec = hdr->ts.tv_nsec/1000;
434                return tv;
435        }
436        else {
437                struct timeval tv;
438                tv.tv_sec = hdr->tv.tv_sec;
439                tv.tv_usec = hdr->tv.tv_usec;
440                return tv;
441        }
442}
443
444static int linuxnative_get_capture_length(const libtrace_packet_t *packet)
445{
446        return ((struct libtrace_linuxnative_header*)(packet->buffer))->caplen;
447}
448
449
450static int linuxnative_get_wire_length(const libtrace_packet_t *packet) 
451{
452
453        int wirelen = ((struct libtrace_linuxnative_header*)(packet->buffer))->wirelen;
454
455        /* Include the missing FCS */
456        if (trace_get_link_type(packet) == TRACE_TYPE_ETH)
457                wirelen += 4;
458
459        return wirelen;
460}
461
462
463static int linuxnative_get_framing_length(UNUSED
464                const libtrace_packet_t *packet) 
465{
466        return sizeof(struct libtrace_linuxnative_header);
467}
468
469static size_t linuxnative_set_capture_length(libtrace_packet_t *packet, 
470                size_t size) {
471
472        struct libtrace_linuxnative_header *linux_hdr = NULL;
473        if (!packet) {
474                fprintf(stderr, "NULL packet passed into linuxnative_set_capture_length()\n");
475                /* Return -1 on error? */
476                return ~0U;
477        }
478        if (size > trace_get_capture_length(packet)) {
479                /* We should avoid making a packet larger */
480                return trace_get_capture_length(packet);
481        }
482       
483        /* Reset the cached capture length */
484        packet->cached.capture_length = -1;
485
486        linux_hdr = (struct libtrace_linuxnative_header *)packet->header;
487        linux_hdr->caplen = size;
488        return trace_get_capture_length(packet);
489}
490
491#ifdef HAVE_NETPACKET_PACKET_H
492static void linuxnative_help(void) {
493        printf("linuxnative format module: $Revision: 1793 $\n");
494        printf("Supported input URIs:\n");
495        printf("\tint:eth0\n");
496        printf("\n");
497        printf("Supported output URIs:\n");
498        printf("\tint:eth0\n");
499        printf("\n");
500        return;
501}
502
503static struct libtrace_format_t linuxnative = {
504        "int",
505        "$Id$",
506        TRACE_FORMAT_LINUX_NATIVE,
507        linuxcommon_probe_filename,     /* probe filename */
508        NULL,                           /* probe magic */
509        linuxcommon_init_input,         /* init_input */
510        linuxcommon_config_input,       /* config_input */
511        linuxnative_start_input,        /* start_input */
512        linuxcommon_pause_input,        /* pause_input */
513        linuxcommon_init_output,        /* init_output */
514        NULL,                           /* config_output */
515        linuxnative_start_output,       /* start_ouput */
516        linuxcommon_fin_input,          /* fin_input */
517        linuxnative_fin_output,         /* fin_output */
518        linuxnative_read_packet,        /* read_packet */
519        linuxnative_prepare_packet,     /* prepare_packet */
520        NULL,                           /* fin_packet */
521        linuxnative_write_packet,       /* write_packet */
522        NULL,                           /* flush_output */
523        linuxnative_get_link_type,      /* get_link_type */
524        linuxnative_get_direction,      /* get_direction */
525        linuxnative_set_direction,      /* set_direction */
526        NULL,                           /* get_erf_timestamp */
527        linuxnative_get_timeval,        /* get_timeval */
528        linuxnative_get_timespec,       /* get_timespec */
529        NULL,                           /* get_seconds */
530        NULL,                           /* seek_erf */
531        NULL,                           /* seek_timeval */
532        NULL,                           /* seek_seconds */
533        linuxnative_get_capture_length, /* get_capture_length */
534        linuxnative_get_wire_length,    /* get_wire_length */
535        linuxnative_get_framing_length, /* get_framing_length */
536        linuxnative_set_capture_length, /* set_capture_length */
537        NULL,                           /* get_received_packets */
538        NULL,                           /* get_filtered_packets */
539        NULL,                           /* get_dropped_packets */
540        linuxcommon_get_statistics,     /* get_statistics */
541        linuxcommon_get_fd,             /* get_fd */
542        trace_event_device,             /* trace_event */
543        linuxnative_help,               /* help */
544        NULL,                           /* next pointer */
545#ifdef HAVE_PACKET_FANOUT
546        {true, -1},                     /* Live, no thread limit */
547        linuxnative_pstart_input,       /* pstart_input */
548        linuxnative_pread_packets,      /* pread_packets */
549        linuxcommon_pause_input,        /* ppause */
550        linuxcommon_fin_input,          /* p_fin */
551        linuxcommon_pregister_thread,   /* register thread */
552        NULL,                           /* unregister thread */
553        NULL                            /* get thread stats */
554#else
555        NON_PARALLEL(true)
556#endif
557};
558#else
559static void linuxnative_help(void) {
560        printf("linuxnative format module: $Revision: 1793 $\n");
561        printf("Not supported on this host\n");
562}
563
564static struct libtrace_format_t linuxnative = {
565        "int",
566        "$Id$",
567        TRACE_FORMAT_LINUX_NATIVE,
568        NULL,                           /* probe filename */
569        NULL,                           /* probe magic */
570        NULL,                           /* init_input */
571        NULL,                           /* config_input */
572        NULL,                           /* start_input */
573        NULL,                           /* pause_input */
574        NULL,                           /* init_output */
575        NULL,                           /* config_output */
576        NULL,                           /* start_ouput */
577        NULL,                           /* fin_input */
578        NULL,                           /* fin_output */
579        NULL,                           /* read_packet */
580        linuxnative_prepare_packet,     /* prepare_packet */
581        NULL,                           /* fin_packet */
582        NULL,                           /* write_packet */
583        NULL,                           /* flush_output */
584        linuxnative_get_link_type,      /* get_link_type */
585        linuxnative_get_direction,      /* get_direction */
586        linuxnative_set_direction,      /* set_direction */
587        NULL,                           /* get_erf_timestamp */
588        linuxnative_get_timeval,        /* get_timeval */
589        linuxnative_get_timespec,       /* get_timespec */
590        NULL,                           /* get_seconds */
591        NULL,                           /* seek_erf */
592        NULL,                           /* seek_timeval */
593        NULL,                           /* seek_seconds */
594        linuxnative_get_capture_length, /* get_capture_length */
595        linuxnative_get_wire_length,    /* get_wire_length */
596        linuxnative_get_framing_length, /* get_framing_length */
597        linuxnative_set_capture_length, /* set_capture_length */
598        NULL,                           /* get_received_packets */
599        NULL,                           /* get_filtered_packets */
600        NULL,                           /* get_dropped_packets */
601        linuxcommon_get_statistics,     /* get_statistics */
602        NULL,                           /* get_fd */
603        NULL,                           /* trace_event */
604        linuxnative_help,               /* help */
605        NULL,                   /* next pointer */
606        NON_PARALLEL(true)
607};
608#endif /* HAVE_NETPACKET_PACKET_H */
609
610void linuxnative_constructor(void) {
611        register_format(&linuxnative);
612}
Note: See TracBrowser for help on using the repository browser.