source: lib/format_linux.c @ f2fae49

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since f2fae49 was f2fae49, checked in by Perry Lorier <perry@…>, 14 years ago

Add new "loss" framework

  • Property mode set to 100644
File size: 14.5 KB
Line 
1/*
2 * This file is part of libtrace
3 *
4 * Copyright (c) 2007 The University of Waikato, Hamilton, New Zealand.
5 * Authors: Daniel Lawson
6 *          Perry Lorier
7 *         
8 * All rights reserved.
9 *
10 * This code has been developed by the University of Waikato WAND
11 * research group. For further information please see http://www.wand.net.nz/
12 *
13 * libtrace is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * libtrace is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with libtrace; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 *
27 * $Id$
28 *
29 */
30
31#include "libtrace.h"
32#include "libtrace_int.h"
33#include "format_helper.h"
34#include "config.h"
35#include "stdlib.h"
36
37#ifdef HAVE_INTTYPES_H
38#  include <inttypes.h>
39#else
40# error "Can't find inttypes.h"
41#endif
42
43#include <sys/socket.h>
44#include <netpacket/packet.h>
45#include <net/ethernet.h>
46#include <net/if_arp.h>
47
48#include <string.h>
49#include <net/if.h>
50#include <sys/ioctl.h>
51#include <errno.h>
52
53#include <assert.h>
54
55struct libtrace_format_data_t {
56        int fd;
57        int snaplen;
58        int promisc;
59        libtrace_filter_t *filter;
60};
61
62struct libtrace_linuxnative_header {
63        struct timeval ts;
64        int wirelen;
65        int caplen;
66        struct sockaddr_ll hdr;
67};
68
69struct libtrace_linuxnative_format_data_t {
70        int fd;
71};
72
73#define FORMAT(x) ((struct libtrace_format_data_t*)(x))
74#define DATAOUT(x) ((struct libtrace_linuxnative_format_data_t*)((x)->format_data))
75
76static int linuxnative_init_input(libtrace_t *libtrace) 
77{
78        libtrace->format_data = (struct libtrace_format_data_t *)
79                malloc(sizeof(struct libtrace_format_data_t));
80        FORMAT(libtrace->format_data)->fd = -1;
81        FORMAT(libtrace->format_data)->promisc = -1;
82        FORMAT(libtrace->format_data)->snaplen = 65536;
83        FORMAT(libtrace->format_data)->filter = NULL;
84
85        return 0;
86}
87
88static int linuxnative_init_output(libtrace_out_t *libtrace)
89{
90        libtrace->format_data = (struct libtrace_linuxnative_format_data_t*)
91                malloc(sizeof(struct libtrace_linuxnative_format_data_t));
92        DATAOUT(libtrace)->fd = -1;
93
94        return 0;
95}
96
97static int linuxnative_start_input(libtrace_t *libtrace)
98{
99        struct sockaddr_ll addr;
100        int one = 1;
101        memset(&addr,0,sizeof(addr));
102        libtrace_filter_t *filter = FORMAT(libtrace->format_data)->filter;
103        FORMAT(libtrace->format_data)->fd = 
104                                socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
105        if (FORMAT(libtrace->format_data)->fd==-1) {
106                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Could not create raw socket");
107                free(libtrace->format_data);
108                return -1;
109        }
110        addr.sll_family = AF_PACKET;
111        addr.sll_protocol = htons(ETH_P_ALL);
112        if (strlen(libtrace->uridata)) {
113                addr.sll_ifindex = if_nametoindex(libtrace->uridata);
114                if (addr.sll_ifindex == 0) {
115                        close(FORMAT(libtrace->format_data)->fd);
116                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Failed to find interface %s", libtrace->uridata);
117                        free(libtrace->format_data);
118                        return -1;
119                }
120        }
121        else {
122                addr.sll_ifindex = 0;
123        }
124        if (bind(FORMAT(libtrace->format_data)->fd,
125                                (struct sockaddr*)&addr,
126                                (socklen_t)sizeof(addr))==-1) {
127                free(libtrace->format_data);
128                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Failed to bind to interface %s", libtrace->uridata);
129                return -1;
130        }
131
132        /* If promisc hasn't been specified, set it to "true" if we're
133         * capturing on one interface, or "false" if we're capturing on
134         * all interfaces.
135         */ 
136        if (FORMAT(libtrace->format_data)->promisc==-1) {
137                if (addr.sll_ifindex!=0)
138                        FORMAT(libtrace->format_data)->promisc=1;
139                else
140                        FORMAT(libtrace->format_data)->promisc=0;
141        }
142                               
143        if (FORMAT(libtrace->format_data)->promisc) {
144                struct packet_mreq mreq;
145                socklen_t socklen = sizeof(mreq);
146                memset(&mreq,0,sizeof(mreq));
147                mreq.mr_ifindex = addr.sll_ifindex;
148                mreq.mr_type = PACKET_MR_PROMISC;
149                setsockopt(FORMAT(libtrace->format_data)->fd,
150                                SOL_PACKET,
151                                PACKET_ADD_MEMBERSHIP,
152                                &mreq,
153                                socklen);
154        }
155
156        if (setsockopt(FORMAT(libtrace->format_data)->fd,
157                        SOL_SOCKET,
158                        SO_TIMESTAMP,
159                        &one,
160                        (socklen_t)sizeof(one))==-1) {
161                perror("setsockopt(SO_TIMESTAMP)");
162        }
163
164        /* Push BPF filter into the kernel. At this stage we can safely assume
165         * that the filterstring has been compiled, or the filter was supplied
166         * pre-compiled.
167         */
168        if (filter != NULL) {
169                assert(filter->flag == 1);
170                if (setsockopt(FORMAT(libtrace->format_data)->fd,
171                                        SOL_SOCKET,
172                                        SO_ATTACH_FILTER,
173                                        &filter->filter,
174                                        sizeof(filter->filter)) == -1) {
175                        perror("setsockopt(SO_ATTACH_FILTER)");
176                } else { 
177                        /* The socket accepted the filter, so we need to
178                         * consume any buffered packets that were received
179                         * between opening the socket and applying the filter.
180                         */
181                        void *buf = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
182                        while(recv(FORMAT(libtrace->format_data)->fd,
183                                        buf,
184                                        (size_t) LIBTRACE_PACKET_BUFSIZE,
185                                        MSG_DONTWAIT) != -1) { }
186                        free(buf);
187                }
188        }
189                                       
190        return 0;
191}
192
193static int linuxnative_start_output(libtrace_out_t *libtrace)
194{
195        FORMAT(libtrace->format_data)->fd = 
196                                socket(PF_PACKET, SOCK_RAW, 0);
197        if (FORMAT(libtrace->format_data)->fd==-1) {
198                free(libtrace->format_data);
199                return -1;
200        }
201
202        return 0;
203}
204
205static int linuxnative_pause_input(libtrace_t *libtrace)
206{
207        close(FORMAT(libtrace->format_data)->fd);
208        FORMAT(libtrace->format_data)->fd=-1;
209
210        return 0;
211}
212
213static int linuxnative_fin_input(libtrace_t *libtrace) 
214{
215        if (FORMAT(libtrace->format_data)->filter != NULL)
216                free(FORMAT(libtrace->format_data)->filter);
217        free(libtrace->format_data);
218       
219        return 0;
220}
221
222static int linuxnative_fin_output(libtrace_out_t *libtrace)
223{
224        close(DATAOUT(libtrace)->fd);
225        DATAOUT(libtrace)->fd=-1;
226        free(libtrace->format_data);
227        return 0;
228}
229
230static int linuxnative_configure_bpf(libtrace_t *libtrace, 
231                libtrace_filter_t *filter) {
232#ifdef HAVE_LIBPCAP
233        struct ifreq ifr;
234        unsigned int arphrd;
235        libtrace_dlt_t dlt;
236        libtrace_filter_t *f;
237        int sock;
238        pcap_t *pcap;
239
240        /* Take a copy of the filter object as it was passed in */
241        f = (libtrace_filter_t *) malloc(sizeof(libtrace_filter_t));
242        memcpy(f, filter, sizeof(libtrace_filter_t));
243       
244        /* If we are passed a filter with "flag" set to zero, then we must
245         * compile the filterstring before continuing. This involves
246         * determining the linktype, passing the filterstring to libpcap to
247         * compile, and saving the result for trace_start() to push into the
248         * kernel.
249         * If flag is set to one, then the filter was probably generated using
250         * trace_create_filter_from_bytecode() and so we don't need to do
251         * anything (we've just copied it above).
252         */
253        if (f->flag == 0) {
254                sock = socket(PF_INET, SOCK_STREAM, 0);
255                memset(&ifr, 0, sizeof(struct ifreq));
256                strncpy(ifr.ifr_name, libtrace->uridata, IF_NAMESIZE);
257                if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0) {
258                        perror("Can't get HWADDR for interface");
259                        return -1;
260                }
261                close(sock);
262
263                arphrd = ifr.ifr_hwaddr.sa_family;
264                dlt = libtrace_to_pcap_dlt(arphrd_type_to_libtrace(arphrd));
265
266                pcap = pcap_open_dead(dlt, 
267                                FORMAT(libtrace->format_data)->snaplen);
268
269                if (pcap_compile(pcap, &f->filter, f->filterstring, 0, 0) == -1) {
270                        perror("PCAP failed to compile the filterstring");
271                        return -1;
272                }
273
274                pcap_close(pcap);
275               
276                /* Set the "flag" to indicate that the filterstring has been
277                 * compiled
278                 */
279                f->flag = 1;
280        }
281       
282        if (FORMAT(libtrace->format_data)->filter != NULL)
283                free(FORMAT(libtrace->format_data)->filter);
284       
285        FORMAT(libtrace->format_data)->filter = f;
286       
287        return 0;
288#else
289        return -1
290#endif
291}
292static int linuxnative_config_input(libtrace_t *libtrace,
293                trace_option_t option,
294                void *data)
295{
296        switch(option) {
297                case TRACE_OPTION_SNAPLEN:
298                        FORMAT(libtrace->format_data)->snaplen=*(int*)data;
299                        return 0;
300                case TRACE_OPTION_PROMISC:
301                        FORMAT(libtrace->format_data)->promisc=*(int*)data;
302                        return 0;
303                case TRACE_OPTION_FILTER:
304                        return linuxnative_configure_bpf(libtrace, 
305                                        (libtrace_filter_t *) data);
306                case TRACE_OPTION_META_FREQ:
307                        /* No meta-data for this format */
308                        break;
309                case TRACE_OPTION_EVENT_REALTIME:
310                        break;
311                /* Avoid default: so that future options will cause a warning
312                 * here to remind us to implement it, or flag it as
313                 * unimplementable
314                 */
315        }
316       
317        /* Don't set an error - trace_config will try to deal with the
318         * option and will set an error if it fails */
319        return -1;
320}
321
322#define LIBTRACE_MIN(a,b) ((a)<(b) ? (a) : (b))
323
324/* 20 isn't enough on x86_64 */
325#define CMSG_BUF_SIZE 128
326static int linuxnative_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) 
327{
328        struct libtrace_linuxnative_header *hdr;
329        struct msghdr msghdr;
330        struct iovec iovec;
331        unsigned char controlbuf[CMSG_BUF_SIZE];
332        struct cmsghdr *cmsg;
333        socklen_t socklen;
334        int snaplen;
335
336        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
337                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
338                packet->buf_control = TRACE_CTRL_PACKET;
339        }
340
341        packet->header = packet->buffer;
342        packet->type = TRACE_RT_DATA_LINUX_NATIVE;
343        packet->payload = (char*)packet->buffer+sizeof(*hdr);
344
345        hdr=(struct libtrace_linuxnative_header*)packet->buffer;
346        socklen=sizeof(hdr->hdr);
347        snaplen=LIBTRACE_MIN(
348                        (int)LIBTRACE_PACKET_BUFSIZE-(int)sizeof(*hdr),
349                        (int)FORMAT(libtrace->format_data)->snaplen);
350
351        msghdr.msg_name = &hdr->hdr;
352        msghdr.msg_namelen = sizeof(struct sockaddr_ll);
353
354        msghdr.msg_iov = &iovec;
355        msghdr.msg_iovlen = 1;
356
357        msghdr.msg_control = &controlbuf;
358        msghdr.msg_controllen = CMSG_BUF_SIZE;
359        msghdr.msg_flags = 0;
360
361        iovec.iov_base = (void*)packet->payload;
362        iovec.iov_len = snaplen;
363
364        hdr->wirelen = recvmsg(FORMAT(libtrace->format_data)->fd, &msghdr, 0);
365
366        if (hdr->wirelen==-1) {
367                trace_set_err(libtrace,errno,"recvmsg");
368                return -1;
369        }
370
371        hdr->caplen=LIBTRACE_MIN(snaplen,hdr->wirelen);
372
373        for (cmsg = CMSG_FIRSTHDR(&msghdr);
374                        cmsg != NULL;
375                        cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
376                if (cmsg->cmsg_level == SOL_SOCKET
377                        && cmsg->cmsg_type == SO_TIMESTAMP
378                        && cmsg->cmsg_len <= CMSG_LEN(sizeof(struct timeval))) {
379                        memcpy(&hdr->ts, CMSG_DATA(cmsg),
380                                        sizeof(struct timeval));
381                        break;
382                }
383        }
384
385        if (cmsg == NULL && ioctl(FORMAT(libtrace->format_data)->fd,
386                                SIOCGSTAMP,&hdr->ts)==-1)
387                perror("ioctl(SIOCGSTAMP)");
388
389        return hdr->wirelen+sizeof(*hdr);
390}
391
392static int linuxnative_write_packet(libtrace_out_t *trace, 
393                libtrace_packet_t *packet) 
394{
395        struct sockaddr_ll hdr;
396
397        hdr.sll_family = AF_PACKET;
398        hdr.sll_protocol = 0;
399        hdr.sll_ifindex = if_nametoindex(trace->uridata);
400        hdr.sll_hatype = 0;
401        hdr.sll_pkttype = 0;
402        hdr.sll_halen = htons(6); /* FIXME */
403        memcpy(hdr.sll_addr,packet->payload,(size_t)hdr.sll_halen);
404
405        return sendto(DATAOUT(trace)->fd,
406                        packet->payload,
407                        trace_get_capture_length(packet),
408                        0,
409                        (struct sockaddr*)&hdr, (socklen_t)sizeof(hdr));
410
411}
412
413static libtrace_linktype_t linuxnative_get_link_type(const struct libtrace_packet_t *packet) {
414        int linktype=(((struct libtrace_linuxnative_header*)(packet->buffer))
415                                ->hdr.sll_hatype);
416        switch (linktype) {
417                case ARPHRD_ETHER:
418                        return TRACE_TYPE_ETH;
419                case ARPHRD_PPP:
420                        return TRACE_TYPE_NONE;
421                case ARPHRD_80211_RADIOTAP:
422                        return TRACE_TYPE_80211_RADIO;
423                case ARPHRD_IEEE80211:
424                        return TRACE_TYPE_80211;
425                case ARPHRD_SIT:
426                        return TRACE_TYPE_NONE;
427                default: /* shrug, beyond me! */
428                        printf("unknown Linux ARPHRD type 0x%04x\n",linktype);
429                        return (libtrace_linktype_t)~0U;
430        }
431}
432
433static libtrace_direction_t linuxnative_get_direction(const struct libtrace_packet_t *packet) {
434        switch (((struct libtrace_linuxnative_header*)(packet->buffer))->hdr.sll_pkttype) {
435                case PACKET_OUTGOING:
436                case PACKET_LOOPBACK:
437                        return TRACE_DIR_OUTGOING;
438                default:
439                        return TRACE_DIR_INCOMING;
440        }
441}
442
443static libtrace_direction_t linuxnative_set_direction(
444                libtrace_packet_t *packet,
445                libtrace_direction_t direction) {
446
447        switch (direction) {
448                case TRACE_DIR_OUTGOING:
449                        ((struct libtrace_linuxnative_header*)(packet->buffer))->hdr.sll_pkttype = PACKET_OUTGOING;
450                        return TRACE_DIR_OUTGOING;
451                case TRACE_DIR_INCOMING:
452                        ((struct libtrace_linuxnative_header*)(packet->buffer))->hdr.sll_pkttype = PACKET_HOST;
453                        return TRACE_DIR_INCOMING;
454                default:
455                        return -1;
456        }
457}
458
459static struct timeval linuxnative_get_timeval(const libtrace_packet_t *packet) 
460{
461        return ((struct libtrace_linuxnative_header*)(packet->buffer))->ts;
462}
463
464static int linuxnative_get_capture_length(const libtrace_packet_t *packet)
465{
466        return ((struct libtrace_linuxnative_header*)(packet->buffer))->caplen;
467}
468
469static int linuxnative_get_wire_length(const libtrace_packet_t *packet) 
470{
471        return ((struct libtrace_linuxnative_header*)(packet->buffer))->wirelen;
472}
473
474static int linuxnative_get_framing_length(UNUSED
475                const libtrace_packet_t *packet) 
476{
477        return sizeof(struct libtrace_linuxnative_header);
478}
479
480static int linuxnative_get_fd(const libtrace_t *trace) {
481        return FORMAT(trace->format_data)->fd;
482}
483
484static void linuxnative_help(void) {
485        printf("linuxnative format module: $Revision$\n");
486        printf("Supported input URIs:\n");
487        printf("\tint:\n");
488        printf("\n");
489        printf("Supported output URIs:\n");
490        printf("\tnone\n");
491        printf("\n");
492        return;
493}
494static struct libtrace_format_t linuxnative = {
495        "int",
496        "$Id$",
497        TRACE_FORMAT_LINUX_NATIVE,
498        linuxnative_init_input,         /* init_input */
499        linuxnative_config_input,       /* config_input */
500        linuxnative_start_input,        /* start_input */
501        linuxnative_pause_input,        /* pause_input */
502        linuxnative_init_output,        /* init_output */
503        NULL,                           /* config_output */
504        linuxnative_start_output,       /* start_ouput */
505        linuxnative_fin_input,          /* fin_input */
506        linuxnative_fin_output,         /* fin_output */
507        linuxnative_read_packet,        /* read_packet */
508        NULL,                           /* fin_packet */
509        linuxnative_write_packet,       /* write_packet */
510        linuxnative_get_link_type,      /* get_link_type */
511        linuxnative_get_direction,      /* get_direction */
512        linuxnative_set_direction,      /* set_direction */
513        NULL,                           /* get_erf_timestamp */
514        linuxnative_get_timeval,        /* get_timeval */
515        NULL,                           /* get_seconds */
516        NULL,                           /* seek_erf */
517        NULL,                           /* seek_timeval */
518        NULL,                           /* seek_seconds */
519        linuxnative_get_capture_length, /* get_capture_length */
520        linuxnative_get_wire_length,    /* get_wire_length */
521        linuxnative_get_framing_length, /* get_framing_length */
522        NULL,                           /* set_capture_length */
523        NULL,                           /* get_received_packets */
524        NULL,                           /* get_filtered_packets */
525        NULL,                           /* get_dropped_packets */
526        NULL,                           /* get_captured_packets */
527        linuxnative_get_fd,             /* get_fd */
528        trace_event_device,             /* trace_event */
529        linuxnative_help,               /* help */
530        NULL
531};
532
533void linuxnative_constructor(void) {
534        register_format(&linuxnative);
535}
Note: See TracBrowser for help on using the repository browser.