source: lib/format_linux.c @ a81d2fc

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since a81d2fc was 3a14f3b, checked in by Scott Raynel <smr26@…>, 14 years ago

Allow libtrace applications to create filters based on pre-compiled BPF
bytecode as well as filterstrings. See trace_create_filter_from_bytecode()

  • Property mode set to 100644
File size: 14.4 KB
RevLine 
[97e39a7]1/*
2 * This file is part of libtrace
3 *
[d5a27e8]4 * Copyright (c) 2007 The University of Waikato, Hamilton, New Zealand.
[97e39a7]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 *
[293999b]27 * $Id$
[97e39a7]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
[edb18ce]48#include <string.h>
49#include <net/if.h>
50#include <sys/ioctl.h>
[d0fd73c]51#include <errno.h>
[edb18ce]52
[3a14f3b]53#include <assert.h>
[c4cf162]54
[97e39a7]55struct libtrace_format_data_t {
56        int fd;
[411f3c7]57        int snaplen;
58        int promisc;
[394706e]59        libtrace_filter_t *filter;
[97e39a7]60};
61
62struct libtrace_linuxnative_header {
63        struct timeval ts;
64        int wirelen;
[411f3c7]65        int caplen;
[97e39a7]66        struct sockaddr_ll hdr;
67};
68
[e4e95499]69struct libtrace_linuxnative_format_data_t {
70        int fd;
71};
72
[97e39a7]73#define FORMAT(x) ((struct libtrace_format_data_t*)(x))
[e4e95499]74#define DATAOUT(x) ((struct libtrace_linuxnative_format_data_t*)((x)->format_data))
[97e39a7]75
[411f3c7]76static int linuxnative_init_input(libtrace_t *libtrace) 
77{
[97e39a7]78        libtrace->format_data = (struct libtrace_format_data_t *)
79                malloc(sizeof(struct libtrace_format_data_t));
[411f3c7]80        FORMAT(libtrace->format_data)->fd = -1;
[3ed9a80]81        FORMAT(libtrace->format_data)->promisc = -1;
[411f3c7]82        FORMAT(libtrace->format_data)->snaplen = 65536;
[394706e]83        FORMAT(libtrace->format_data)->filter = NULL;
[411f3c7]84
85        return 0;
86}
87
[e4e95499]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
[411f3c7]97static int linuxnative_start_input(libtrace_t *libtrace)
98{
99        struct sockaddr_ll addr;
[d0fd73c]100        int one = 1;
[9a5b234]101        memset(&addr,0,sizeof(addr));
[394706e]102        libtrace_filter_t *filter = FORMAT(libtrace->format_data)->filter;
[97e39a7]103        FORMAT(libtrace->format_data)->fd = 
104                                socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
105        if (FORMAT(libtrace->format_data)->fd==-1) {
[205809b]106                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Could not create raw socket");
[97e39a7]107                free(libtrace->format_data);
[566e404]108                return -1;
[97e39a7]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);
[205809b]116                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Failed to find interface %s", libtrace->uridata);
[97e39a7]117                        free(libtrace->format_data);
[566e404]118                        return -1;
[97e39a7]119                }
120        }
121        else {
122                addr.sll_ifindex = 0;
123        }
124        if (bind(FORMAT(libtrace->format_data)->fd,
125                                (struct sockaddr*)&addr,
[4bd8a5b]126                                (socklen_t)sizeof(addr))==-1) {
[97e39a7]127                free(libtrace->format_data);
[205809b]128                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Failed to bind to interface %s", libtrace->uridata);
[566e404]129                return -1;
[97e39a7]130        }
[3ed9a80]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) {
[97e39a7]144                struct packet_mreq mreq;
145                socklen_t socklen = sizeof(mreq);
[9a5b234]146                memset(&mreq,0,sizeof(mreq));
[97e39a7]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
[3b10b9f]156        if (setsockopt(FORMAT(libtrace->format_data)->fd,
[d0fd73c]157                        SOL_SOCKET,
158                        SO_TIMESTAMP,
159                        &one,
[4bd8a5b]160                        (socklen_t)sizeof(one))==-1) {
[3b10b9f]161                perror("setsockopt(SO_TIMESTAMP)");
162        }
[d0fd73c]163
[3a14f3b]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.
[394706e]167         */
168        if (filter != NULL) {
[3a14f3b]169                assert(filter->flag == 1);
[394706e]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                                       
[566e404]190        return 0;
[97e39a7]191}
192
[e4e95499]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
[411f3c7]205static int linuxnative_pause_input(libtrace_t *libtrace)
206{
[97e39a7]207        close(FORMAT(libtrace->format_data)->fd);
[411f3c7]208        FORMAT(libtrace->format_data)->fd=-1;
209
210        return 0;
211}
212
213static int linuxnative_fin_input(libtrace_t *libtrace) 
214{
[394706e]215        if (FORMAT(libtrace->format_data)->filter != NULL)
216                free(FORMAT(libtrace->format_data)->filter);
[97e39a7]217        free(libtrace->format_data);
[394706e]218       
[97e39a7]219        return 0;
220}
221
[e4e95499]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
[394706e]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
[3a14f3b]240        /* Take a copy of the filter object as it was passed in */
[394706e]241        f = (libtrace_filter_t *) malloc(sizeof(libtrace_filter_t));
242        memcpy(f, filter, sizeof(libtrace_filter_t));
243       
[3a14f3b]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(socket);
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);
[394706e]268
[3a14f3b]269                if (pcap_compile(pcap, &f->filter, f->filterstring, 0, 0) == -1) {
270                        perror("PCAP failed to compile the filterstring");
271                        return -1;
272                }
[394706e]273
[3a14f3b]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       
[394706e]282        if (FORMAT(libtrace->format_data)->filter != NULL)
283                free(FORMAT(libtrace->format_data)->filter);
284       
285        FORMAT(libtrace->format_data)->filter = f;
[3a14f3b]286       
[394706e]287        return 0;
288#else
289        return -1
290#endif
291}
[411f3c7]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:
[394706e]304                        return linuxnative_configure_bpf(libtrace, 
305                                        (libtrace_filter_t *) data);
[646aca1]306                case TRACE_OPTION_META_FREQ:
[cd7eec7]307                        /* No meta-data for this format */
308                        break;
[646aca1]309                case TRACE_OPTION_EVENT_REALTIME:
310                        break;
[411f3c7]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        }
[205809b]316       
[708f9ae]317        /* Don't set an error - trace_config will try to deal with the
318         * option and will set an error if it fails */
[411f3c7]319        return -1;
320}
321
322#define LIBTRACE_MIN(a,b) ((a)<(b) ? (a) : (b))
323
[3b10b9f]324/* 20 isn't enough on x86_64 */
325#define CMSG_BUF_SIZE 128
[e4e95499]326static int linuxnative_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) 
327{
[566e404]328        struct libtrace_linuxnative_header *hdr;
[d0fd73c]329        struct msghdr msghdr;
330        struct iovec iovec;
331        unsigned char controlbuf[CMSG_BUF_SIZE];
332        struct cmsghdr *cmsg;
[edb18ce]333        socklen_t socklen;
[411f3c7]334        int snaplen;
[d0fd73c]335
[566e404]336        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
[4bd8a5b]337                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
[566e404]338                packet->buf_control = TRACE_CTRL_PACKET;
339        }
340
341        packet->header = packet->buffer;
[cab58c5]342        packet->type = TRACE_RT_DATA_LINUX_NATIVE;
[edb18ce]343        packet->payload = (char*)packet->buffer+sizeof(*hdr);
[566e404]344
[85a79b0]345        hdr=(struct libtrace_linuxnative_header*)packet->buffer;
[edb18ce]346        socklen=sizeof(hdr->hdr);
[411f3c7]347        snaplen=LIBTRACE_MIN(
348                        (int)LIBTRACE_PACKET_BUFSIZE-(int)sizeof(*hdr),
349                        (int)FORMAT(libtrace->format_data)->snaplen);
[d0fd73c]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");
[97e39a7]368                return -1;
[d0fd73c]369        }
[97e39a7]370
[411f3c7]371        hdr->caplen=LIBTRACE_MIN(snaplen,hdr->wirelen);
372
[d0fd73c]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
[3b10b9f]378                        && cmsg->cmsg_len <= CMSG_LEN(sizeof(struct timeval))) {
[d0fd73c]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)
[97e39a7]387                perror("ioctl(SIOCGSTAMP)");
388
389        return hdr->wirelen+sizeof(*hdr);
390}
391
[e4e95499]392static int linuxnative_write_packet(libtrace_out_t *trace, 
[85a79b0]393                libtrace_packet_t *packet) 
[e4e95499]394{
395        struct sockaddr_ll hdr;
396
397        hdr.sll_family = AF_PACKET;
398        hdr.sll_protocol = 0;
[030aa3f]399        hdr.sll_ifindex = if_nametoindex(trace->uridata);
[e4e95499]400        hdr.sll_hatype = 0;
401        hdr.sll_pkttype = 0;
[99ff3d9]402        hdr.sll_halen = htons(6); /* FIXME */
[4bd8a5b]403        memcpy(hdr.sll_addr,packet->payload,(size_t)hdr.sll_halen);
[e4e95499]404
405        return sendto(DATAOUT(trace)->fd,
406                        packet->payload,
407                        trace_get_capture_length(packet),
408                        0,
[4bd8a5b]409                        (struct sockaddr*)&hdr, (socklen_t)sizeof(hdr));
[e4e95499]410
411}
412
[97e39a7]413static libtrace_linktype_t linuxnative_get_link_type(const struct libtrace_packet_t *packet) {
[c042b5c]414        int linktype=(((struct libtrace_linuxnative_header*)(packet->buffer))
415                                ->hdr.sll_hatype);
[fc2e63f]416        switch (linktype) {
[51c83a4]417                case ARPHRD_ETHER:
[97e39a7]418                        return TRACE_TYPE_ETH;
[8c747709]419                case ARPHRD_PPP:
420                        return TRACE_TYPE_NONE;
[ef3660cb]421                case ARPHRD_80211_RADIOTAP:
422                        return TRACE_TYPE_80211_RADIO;
423                case ARPHRD_IEEE80211:
424                        return TRACE_TYPE_80211;
[496b8e5]425                case ARPHRD_SIT:
426                        return TRACE_TYPE_NONE;
[97e39a7]427                default: /* shrug, beyond me! */
[9cad9c9]428                        printf("unknown Linux ARPHRD type 0x%04x\n",linktype);
[85a79b0]429                        return (libtrace_linktype_t)~0U;
[97e39a7]430        }
431}
432
[431548c5]433static libtrace_direction_t linuxnative_get_direction(const struct libtrace_packet_t *packet) {
[97e39a7]434        switch (((struct libtrace_linuxnative_header*)(packet->buffer))->hdr.sll_pkttype) {
435                case PACKET_OUTGOING:
[27bd348]436                case PACKET_LOOPBACK:
[431548c5]437                        return TRACE_DIR_OUTGOING;
[97e39a7]438                default:
[431548c5]439                        return TRACE_DIR_INCOMING;
[97e39a7]440        }
441}
442
[1008250]443static libtrace_direction_t linuxnative_set_direction(
444                const 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:
[27bd348]452                        ((struct libtrace_linuxnative_header*)(packet->buffer))->hdr.sll_pkttype = PACKET_HOST;
[1008250]453                        return TRACE_DIR_INCOMING;
454                default:
455                        return -1;
456        }
457}
458
[411f3c7]459static struct timeval linuxnative_get_timeval(const libtrace_packet_t *packet) 
460{
[97e39a7]461        return ((struct libtrace_linuxnative_header*)(packet->buffer))->ts;
462}
463
[411f3c7]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{
[97e39a7]471        return ((struct libtrace_linuxnative_header*)(packet->buffer))->wirelen;
472}
473
[85a79b0]474static int linuxnative_get_framing_length(UNUSED
475                const libtrace_packet_t *packet) 
[411f3c7]476{
[97e39a7]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
[33d83d4]484static void linuxnative_help(void) {
[97e39a7]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",
[293999b]496        "$Id$",
[97e39a7]497        TRACE_FORMAT_LINUX_NATIVE,
498        linuxnative_init_input,         /* init_input */
[411f3c7]499        linuxnative_config_input,       /* config_input */
500        linuxnative_start_input,        /* start_input */
501        linuxnative_pause_input,        /* pause_input */
[e4e95499]502        linuxnative_init_output,        /* init_output */
[97e39a7]503        NULL,                           /* config_output */
[e4e95499]504        linuxnative_start_output,       /* start_ouput */
[97e39a7]505        linuxnative_fin_input,          /* fin_input */
[e4e95499]506        linuxnative_fin_output,         /* fin_output */
[97e39a7]507        linuxnative_read_packet,        /* read_packet */
508        NULL,                           /* fin_packet */
[e4e95499]509        linuxnative_write_packet,       /* write_packet */
[97e39a7]510        linuxnative_get_link_type,      /* get_link_type */
511        linuxnative_get_direction,      /* get_direction */
[1008250]512        linuxnative_set_direction,      /* set_direction */
[97e39a7]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 */
[411f3c7]519        linuxnative_get_capture_length, /* get_capture_length */
[97e39a7]520        linuxnative_get_wire_length,    /* get_wire_length */
521        linuxnative_get_framing_length, /* get_framing_length */
522        NULL,                           /* set_capture_length */
523        linuxnative_get_fd,             /* get_fd */
[411f3c7]524        trace_event_device,             /* trace_event */
[97e39a7]525        linuxnative_help,               /* help */
526        NULL
527};
528
[33d83d4]529void linuxnative_constructor(void) {
[97e39a7]530        register_format(&linuxnative);
531}
Note: See TracBrowser for help on using the repository browser.