source: lib/format_linux.c @ 394706e

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

Support for in-kernel BPF processing for the linux native capture format.
Requires libpcap to compile the filterstring.

  • Property mode set to 100644
File size: 13.8 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
54struct libtrace_format_data_t {
55        int fd;
56        int snaplen;
57        int promisc;
58        libtrace_filter_t *filter;
59};
60
61struct libtrace_linuxnative_header {
62        struct timeval ts;
63        int wirelen;
64        int caplen;
65        struct sockaddr_ll hdr;
66};
67
68struct libtrace_linuxnative_format_data_t {
69        int fd;
70};
71
72#define FORMAT(x) ((struct libtrace_format_data_t*)(x))
73#define DATAOUT(x) ((struct libtrace_linuxnative_format_data_t*)((x)->format_data))
74
75static int linuxnative_init_input(libtrace_t *libtrace) 
76{
77        libtrace->format_data = (struct libtrace_format_data_t *)
78                malloc(sizeof(struct libtrace_format_data_t));
79        FORMAT(libtrace->format_data)->fd = -1;
80        FORMAT(libtrace->format_data)->promisc = -1;
81        FORMAT(libtrace->format_data)->snaplen = 65536;
82        FORMAT(libtrace->format_data)->filter = NULL;
83
84        return 0;
85}
86
87static int linuxnative_init_output(libtrace_out_t *libtrace)
88{
89        libtrace->format_data = (struct libtrace_linuxnative_format_data_t*)
90                malloc(sizeof(struct libtrace_linuxnative_format_data_t));
91        DATAOUT(libtrace)->fd = -1;
92
93        return 0;
94}
95
96static int linuxnative_start_input(libtrace_t *libtrace)
97{
98        struct sockaddr_ll addr;
99        int one = 1;
100        memset(&addr,0,sizeof(addr));
101        libtrace_filter_t *filter = FORMAT(libtrace->format_data)->filter;
102        FORMAT(libtrace->format_data)->fd = 
103                                socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
104        if (FORMAT(libtrace->format_data)->fd==-1) {
105                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Could not create raw socket");
106                free(libtrace->format_data);
107                return -1;
108        }
109        addr.sll_family = AF_PACKET;
110        addr.sll_protocol = htons(ETH_P_ALL);
111        if (strlen(libtrace->uridata)) {
112                addr.sll_ifindex = if_nametoindex(libtrace->uridata);
113                if (addr.sll_ifindex == 0) {
114                        close(FORMAT(libtrace->format_data)->fd);
115                        trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Failed to find interface %s", libtrace->uridata);
116                        free(libtrace->format_data);
117                        return -1;
118                }
119        }
120        else {
121                addr.sll_ifindex = 0;
122        }
123        if (bind(FORMAT(libtrace->format_data)->fd,
124                                (struct sockaddr*)&addr,
125                                (socklen_t)sizeof(addr))==-1) {
126                free(libtrace->format_data);
127                trace_set_err(libtrace, TRACE_ERR_INIT_FAILED, "Failed to bind to interface %s", libtrace->uridata);
128                return -1;
129        }
130
131        /* If promisc hasn't been specified, set it to "true" if we're
132         * capturing on one interface, or "false" if we're capturing on
133         * all interfaces.
134         */ 
135        if (FORMAT(libtrace->format_data)->promisc==-1) {
136                if (addr.sll_ifindex!=0)
137                        FORMAT(libtrace->format_data)->promisc=1;
138                else
139                        FORMAT(libtrace->format_data)->promisc=0;
140        }
141                               
142        if (FORMAT(libtrace->format_data)->promisc) {
143                struct packet_mreq mreq;
144                socklen_t socklen = sizeof(mreq);
145                memset(&mreq,0,sizeof(mreq));
146                mreq.mr_ifindex = addr.sll_ifindex;
147                mreq.mr_type = PACKET_MR_PROMISC;
148                setsockopt(FORMAT(libtrace->format_data)->fd,
149                                SOL_PACKET,
150                                PACKET_ADD_MEMBERSHIP,
151                                &mreq,
152                                socklen);
153        }
154
155        if (setsockopt(FORMAT(libtrace->format_data)->fd,
156                        SOL_SOCKET,
157                        SO_TIMESTAMP,
158                        &one,
159                        (socklen_t)sizeof(one))==-1) {
160                perror("setsockopt(SO_TIMESTAMP)");
161        }
162
163        /* Push BPF filter into the kernel.
164         */
165        if (filter != NULL) {
166                if (setsockopt(FORMAT(libtrace->format_data)->fd,
167                                        SOL_SOCKET,
168                                        SO_ATTACH_FILTER,
169                                        &filter->filter,
170                                        sizeof(filter->filter)) == -1) {
171                        perror("setsockopt(SO_ATTACH_FILTER)");
172                } else { 
173                        /* The socket accepted the filter, so we need to
174                         * consume any buffered packets that were received
175                         * between opening the socket and applying the filter.
176                         */
177                        void *buf = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
178                        while(recv(FORMAT(libtrace->format_data)->fd,
179                                        buf,
180                                        (size_t) LIBTRACE_PACKET_BUFSIZE,
181                                        MSG_DONTWAIT) != -1) { }
182                        free(buf);
183                }
184        }
185                                       
186        return 0;
187}
188
189static int linuxnative_start_output(libtrace_out_t *libtrace)
190{
191        FORMAT(libtrace->format_data)->fd = 
192                                socket(PF_PACKET, SOCK_RAW, 0);
193        if (FORMAT(libtrace->format_data)->fd==-1) {
194                free(libtrace->format_data);
195                return -1;
196        }
197
198        return 0;
199}
200
201static int linuxnative_pause_input(libtrace_t *libtrace)
202{
203        close(FORMAT(libtrace->format_data)->fd);
204        FORMAT(libtrace->format_data)->fd=-1;
205
206        return 0;
207}
208
209static int linuxnative_fin_input(libtrace_t *libtrace) 
210{
211        if (FORMAT(libtrace->format_data)->filter != NULL)
212                free(FORMAT(libtrace->format_data)->filter);
213        free(libtrace->format_data);
214       
215        return 0;
216}
217
218static int linuxnative_fin_output(libtrace_out_t *libtrace)
219{
220        close(DATAOUT(libtrace)->fd);
221        DATAOUT(libtrace)->fd=-1;
222        free(libtrace->format_data);
223        return 0;
224}
225
226static int linuxnative_configure_bpf(libtrace_t *libtrace, 
227                libtrace_filter_t *filter) {
228#ifdef HAVE_LIBPCAP
229        struct ifreq ifr;
230        unsigned int arphrd;
231        libtrace_dlt_t dlt;
232        libtrace_filter_t *f;
233        int sock;
234        pcap_t *pcap;
235
236        /* We've been passed a filter, which hasn't been compiled yet. We need
237         * to figure out the linktype of the socket, compile the filter, check
238         * to make sure it's sane, then save it for trace_start() to push down
239         * into the kernel.
240         */
241        sock = socket(PF_INET, SOCK_STREAM, 0);
242        memset(&ifr, 0, sizeof(struct ifreq));
243        strncpy(ifr.ifr_name, libtrace->uridata, IF_NAMESIZE);
244        if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0) {
245                perror("Can't get HWADDR for interface");
246                return -1;
247        }
248        close(socket);
249
250        arphrd = ifr.ifr_hwaddr.sa_family;
251        dlt = libtrace_to_pcap_dlt(arphrd_type_to_libtrace(arphrd));
252
253        f = (libtrace_filter_t *) malloc(sizeof(libtrace_filter_t));
254        memcpy(f, filter, sizeof(libtrace_filter_t));
255
256        pcap = pcap_open_dead(dlt, FORMAT(libtrace->format_data)->snaplen);
257       
258        if (pcap_compile(pcap, &f->filter, f->filterstring, 0, 0) == -1) {
259                perror("PCAP failed to compile the filterstring");
260                return -1;
261        }
262
263        pcap_close(pcap);
264
265        if (FORMAT(libtrace->format_data)->filter != NULL)
266                free(FORMAT(libtrace->format_data)->filter);
267       
268        FORMAT(libtrace->format_data)->filter = f;
269        return 0;
270#else
271        return -1
272#endif
273}
274static int linuxnative_config_input(libtrace_t *libtrace,
275                trace_option_t option,
276                void *data)
277{
278        switch(option) {
279                case TRACE_OPTION_SNAPLEN:
280                        FORMAT(libtrace->format_data)->snaplen=*(int*)data;
281                        return 0;
282                case TRACE_OPTION_PROMISC:
283                        FORMAT(libtrace->format_data)->promisc=*(int*)data;
284                        return 0;
285                case TRACE_OPTION_FILTER:
286                        return linuxnative_configure_bpf(libtrace, 
287                                        (libtrace_filter_t *) data);
288                case TRACE_OPTION_META_FREQ:
289                        /* No meta-data for this format */
290                        break;
291                case TRACE_OPTION_EVENT_REALTIME:
292                        break;
293                /* Avoid default: so that future options will cause a warning
294                 * here to remind us to implement it, or flag it as
295                 * unimplementable
296                 */
297        }
298       
299        /* Don't set an error - trace_config will try to deal with the
300         * option and will set an error if it fails */
301        return -1;
302}
303
304#define LIBTRACE_MIN(a,b) ((a)<(b) ? (a) : (b))
305
306/* 20 isn't enough on x86_64 */
307#define CMSG_BUF_SIZE 128
308static int linuxnative_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) 
309{
310        struct libtrace_linuxnative_header *hdr;
311        struct msghdr msghdr;
312        struct iovec iovec;
313        unsigned char controlbuf[CMSG_BUF_SIZE];
314        struct cmsghdr *cmsg;
315        socklen_t socklen;
316        int snaplen;
317
318        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
319                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
320                packet->buf_control = TRACE_CTRL_PACKET;
321        }
322
323        packet->header = packet->buffer;
324        packet->type = TRACE_RT_DATA_LINUX_NATIVE;
325        packet->payload = (char*)packet->buffer+sizeof(*hdr);
326
327        hdr=(struct libtrace_linuxnative_header*)packet->buffer;
328        socklen=sizeof(hdr->hdr);
329        snaplen=LIBTRACE_MIN(
330                        (int)LIBTRACE_PACKET_BUFSIZE-(int)sizeof(*hdr),
331                        (int)FORMAT(libtrace->format_data)->snaplen);
332
333        msghdr.msg_name = &hdr->hdr;
334        msghdr.msg_namelen = sizeof(struct sockaddr_ll);
335
336        msghdr.msg_iov = &iovec;
337        msghdr.msg_iovlen = 1;
338
339        msghdr.msg_control = &controlbuf;
340        msghdr.msg_controllen = CMSG_BUF_SIZE;
341        msghdr.msg_flags = 0;
342
343        iovec.iov_base = (void*)packet->payload;
344        iovec.iov_len = snaplen;
345
346        hdr->wirelen = recvmsg(FORMAT(libtrace->format_data)->fd, &msghdr, 0);
347
348        if (hdr->wirelen==-1) {
349                trace_set_err(libtrace,errno,"recvmsg");
350                return -1;
351        }
352
353        hdr->caplen=LIBTRACE_MIN(snaplen,hdr->wirelen);
354
355        for (cmsg = CMSG_FIRSTHDR(&msghdr);
356                        cmsg != NULL;
357                        cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
358                if (cmsg->cmsg_level == SOL_SOCKET
359                        && cmsg->cmsg_type == SO_TIMESTAMP
360                        && cmsg->cmsg_len <= CMSG_LEN(sizeof(struct timeval))) {
361                        memcpy(&hdr->ts, CMSG_DATA(cmsg),
362                                        sizeof(struct timeval));
363                        break;
364                }
365        }
366
367        if (cmsg == NULL && ioctl(FORMAT(libtrace->format_data)->fd,
368                                SIOCGSTAMP,&hdr->ts)==-1)
369                perror("ioctl(SIOCGSTAMP)");
370
371        return hdr->wirelen+sizeof(*hdr);
372}
373
374static int linuxnative_write_packet(libtrace_out_t *trace, 
375                libtrace_packet_t *packet) 
376{
377        struct sockaddr_ll hdr;
378
379        hdr.sll_family = AF_PACKET;
380        hdr.sll_protocol = 0;
381        hdr.sll_ifindex = if_nametoindex(trace->uridata);
382        hdr.sll_hatype = 0;
383        hdr.sll_pkttype = 0;
384        hdr.sll_halen = htons(6); /* FIXME */
385        memcpy(hdr.sll_addr,packet->payload,(size_t)hdr.sll_halen);
386
387        return sendto(DATAOUT(trace)->fd,
388                        packet->payload,
389                        trace_get_capture_length(packet),
390                        0,
391                        (struct sockaddr*)&hdr, (socklen_t)sizeof(hdr));
392
393}
394
395static libtrace_linktype_t linuxnative_get_link_type(const struct libtrace_packet_t *packet) {
396        int linktype=(((struct libtrace_linuxnative_header*)(packet->buffer))
397                                ->hdr.sll_hatype);
398        switch (linktype) {
399                case ARPHRD_ETHER:
400                        return TRACE_TYPE_ETH;
401                case ARPHRD_PPP:
402                        return TRACE_TYPE_NONE;
403                case ARPHRD_80211_RADIOTAP:
404                        return TRACE_TYPE_80211_RADIO;
405                case ARPHRD_IEEE80211:
406                        return TRACE_TYPE_80211;
407                case ARPHRD_SIT:
408                        return TRACE_TYPE_NONE;
409                default: /* shrug, beyond me! */
410                        printf("unknown Linux ARPHRD type 0x%04x\n",linktype);
411                        return (libtrace_linktype_t)~0U;
412        }
413}
414
415static libtrace_direction_t linuxnative_get_direction(const struct libtrace_packet_t *packet) {
416        switch (((struct libtrace_linuxnative_header*)(packet->buffer))->hdr.sll_pkttype) {
417                case PACKET_OUTGOING:
418                case PACKET_LOOPBACK:
419                        return TRACE_DIR_OUTGOING;
420                default:
421                        return TRACE_DIR_INCOMING;
422        }
423}
424
425static libtrace_direction_t linuxnative_set_direction(
426                const libtrace_packet_t *packet,
427                libtrace_direction_t direction) {
428
429        switch (direction) {
430                case TRACE_DIR_OUTGOING:
431                        ((struct libtrace_linuxnative_header*)(packet->buffer))->hdr.sll_pkttype = PACKET_OUTGOING;
432                        return TRACE_DIR_OUTGOING;
433                case TRACE_DIR_INCOMING:
434                        ((struct libtrace_linuxnative_header*)(packet->buffer))->hdr.sll_pkttype = PACKET_HOST;
435                        return TRACE_DIR_INCOMING;
436                default:
437                        return -1;
438        }
439}
440
441static struct timeval linuxnative_get_timeval(const libtrace_packet_t *packet) 
442{
443        return ((struct libtrace_linuxnative_header*)(packet->buffer))->ts;
444}
445
446static int linuxnative_get_capture_length(const libtrace_packet_t *packet)
447{
448        return ((struct libtrace_linuxnative_header*)(packet->buffer))->caplen;
449}
450
451static int linuxnative_get_wire_length(const libtrace_packet_t *packet) 
452{
453        return ((struct libtrace_linuxnative_header*)(packet->buffer))->wirelen;
454}
455
456static int linuxnative_get_framing_length(UNUSED
457                const libtrace_packet_t *packet) 
458{
459        return sizeof(struct libtrace_linuxnative_header);
460}
461
462static int linuxnative_get_fd(const libtrace_t *trace) {
463        return FORMAT(trace->format_data)->fd;
464}
465
466static void linuxnative_help(void) {
467        printf("linuxnative format module: $Revision$\n");
468        printf("Supported input URIs:\n");
469        printf("\tint:\n");
470        printf("\n");
471        printf("Supported output URIs:\n");
472        printf("\tnone\n");
473        printf("\n");
474        return;
475}
476static struct libtrace_format_t linuxnative = {
477        "int",
478        "$Id$",
479        TRACE_FORMAT_LINUX_NATIVE,
480        linuxnative_init_input,         /* init_input */
481        linuxnative_config_input,       /* config_input */
482        linuxnative_start_input,        /* start_input */
483        linuxnative_pause_input,        /* pause_input */
484        linuxnative_init_output,        /* init_output */
485        NULL,                           /* config_output */
486        linuxnative_start_output,       /* start_ouput */
487        linuxnative_fin_input,          /* fin_input */
488        linuxnative_fin_output,         /* fin_output */
489        linuxnative_read_packet,        /* read_packet */
490        NULL,                           /* fin_packet */
491        linuxnative_write_packet,       /* write_packet */
492        linuxnative_get_link_type,      /* get_link_type */
493        linuxnative_get_direction,      /* get_direction */
494        linuxnative_set_direction,      /* set_direction */
495        NULL,                           /* get_erf_timestamp */
496        linuxnative_get_timeval,        /* get_timeval */
497        NULL,                           /* get_seconds */
498        NULL,                           /* seek_erf */
499        NULL,                           /* seek_timeval */
500        NULL,                           /* seek_seconds */
501        linuxnative_get_capture_length, /* get_capture_length */
502        linuxnative_get_wire_length,    /* get_wire_length */
503        linuxnative_get_framing_length, /* get_framing_length */
504        NULL,                           /* set_capture_length */
505        linuxnative_get_fd,             /* get_fd */
506        trace_event_device,             /* trace_event */
507        linuxnative_help,               /* help */
508        NULL
509};
510
511void linuxnative_constructor(void) {
512        register_format(&linuxnative);
513}
Note: See TracBrowser for help on using the repository browser.