The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
pcap.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2 of the
4 * License as published by the Free Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
14 */
15
16/** Wrappers around libpcap functions
17 *
18 * @file src/lib/util/pcap.c
19 *
20 * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
21 * @copyright 2013 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
22 */
23#ifdef HAVE_LIBPCAP
24
25#include <freeradius-devel/util/debug.h>
26#include <freeradius-devel/util/net.h>
27#include <freeradius-devel/util/pair.h>
28#include <freeradius-devel/util/pcap.h>
29#include <freeradius-devel/util/syserror.h>
30
31#include <net/if.h>
32#include <sys/ioctl.h>
33#include <sys/uio.h>
34
35#ifndef SIOCGIFHWADDR
36# include <ifaddrs.h>
37# ifdef HAVE_NET_IF_DL_H
38# include <net/if_dl.h>
39# endif
40#else
41# include <net/if.h>
42#endif
43
44
45/** Talloc destructor to free pcap resources associated with a handle.
46 *
47 * @param pcap to free.
48 * @return 0
49 */
50static int _free_pcap(fr_pcap_t *pcap)
51{
52 switch (pcap->type) {
53 case PCAP_INTERFACE_IN:
54 case PCAP_INTERFACE_OUT:
55 case PCAP_INTERFACE_IN_OUT:
56 case PCAP_FILE_IN:
57 case PCAP_STDIO_IN:
58 if (pcap->handle) {
59 pcap_close(pcap->handle);
60
61 if (pcap->fd > 0) {
62 close(pcap->fd);
63 }
64 }
65 break;
66
67 case PCAP_FILE_OUT:
68 case PCAP_STDIO_OUT:
69 if (pcap->dumper) {
70 pcap_dump_flush(pcap->dumper);
71 pcap_dump_close(pcap->dumper);
72 }
73 break;
74
75 case PCAP_INVALID:
76 break;
77 }
78
79 return 0;
80}
81
82/** Get data link from pcap_if_t
83 *
84 * libpcap requires an open pcap handle to get data_link type
85 * unfortunately when we're trying to find useful interfaces
86 * this is too late.
87 *
88 * @param dev to get link layer for.
89 * @return
90 * - Datalink layer.
91 * - -1 on failure.
92 */
93int fr_pcap_if_link_layer(pcap_if_t *dev)
94{
95 char errbuf[PCAP_ERRBUF_SIZE];
96 pcap_t *pcap;
97 int data_link;
98
99 pcap = pcap_open_live(dev->name, 0, 0, 0, errbuf);
100 if (!pcap) {
101 fr_strerror_printf("%s", errbuf);
102 return -1;
103 }
104
105 data_link = pcap_datalink(pcap);
106 pcap_close(pcap);
107
108 return data_link;
109}
110
111/** Initialise a pcap handle abstraction
112 *
113 * @param ctx talloc TALLOC_CTX to allocate handle in.
114 * @param name of interface or file to open.
115 * @param type of handle to initialise.
116 * @return new handle or NULL on error.
117 */
118fr_pcap_t *fr_pcap_init(TALLOC_CTX *ctx, char const *name, fr_pcap_type_t type)
119{
120 fr_pcap_t *this;
121
122 if (!fr_cond_assert(type >= PCAP_INTERFACE_IN && type <= PCAP_INTERFACE_IN_OUT)) {
123 fr_strerror_printf("Invalid PCAP type: %u", type);
124 return NULL;
125 }
126
127 this = talloc_zero(ctx, fr_pcap_t);
128 if (!this) return NULL;
129
130 talloc_set_destructor(this, _free_pcap);
131 this->name = talloc_strdup(this, name);
132 this->type = type;
133 this->link_layer = -1;
134
135 return this;
136}
137
138/** Get MAC address for given interface
139 *
140 * @param[out] macaddr to write MAC address to.
141 * @param[in] ifname to get MAC for.
142 * @return
143 * - 0 on success.
144 * - -1 on error.
145 */
146int fr_pcap_mac_addr(uint8_t *macaddr, char *ifname)
147{
148#ifndef SIOCGIFHWADDR
149 struct ifaddrs *ifap, *ifaptr;
150 unsigned char *ptr;
151
152 if (getifaddrs(&ifap) == 0) {
153 for (ifaptr = ifap; ifaptr != NULL; ifaptr = (ifaptr)->ifa_next) {
154 if (!strcmp((ifaptr)->ifa_name, ifname) && (((ifaptr)->ifa_addr)->sa_family == AF_LINK)) {
155 ptr = (uint8_t *)LLADDR((struct sockaddr_dl *)(ifaptr)->ifa_addr);
156 memcpy(macaddr, ptr, ETHER_ADDR_LEN);
157 break;
158 }
159 }
160 freeifaddrs(ifap);
161 return (ifaptr != NULL ? 0 : -1);
162 }
163 return -1;
164#else
165 int fd, ret;
166 struct ifreq ifr;
167
168 fd = socket(AF_INET, SOCK_DGRAM, 0);
169
170 if (fd < 0) {
171 return -1;
172 }
173
174 ifr.ifr_addr.sa_family = AF_INET;
175 strlcpy(ifr.ifr_name, ifname , IFNAMSIZ-1);
176
177 ret = ioctl(fd, SIOCGIFHWADDR, &ifr);
178
179 close(fd);
180
181 if (ret == 0) {
182 memcpy(macaddr, (uint8_t *)ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN);
183 return 0;
184 }
185 return -1;
186#endif
187}
188
189/** Open a PCAP handle abstraction
190 *
191 * This opens interfaces for capture or injection, or files/streams for reading/writing.
192 * @param pcap created with fr_pcap_init.
193 * @return
194 * - 0 on success.
195 * - -1 on failure.
196 */
197int fr_pcap_open(fr_pcap_t *pcap)
198{
199 switch (pcap->type) {
200 case PCAP_INTERFACE_OUT:
201 case PCAP_INTERFACE_IN:
202 case PCAP_INTERFACE_IN_OUT:
203 {
204 /*
205 * Also has the pleasant side effect of not allowing
206 * handles to be opened on "any".
207 *
208 * We do this first, as it's the most specific error.
209 */
210 pcap->ifindex = if_nametoindex(pcap->name);
211 if (!pcap->ifindex) {
212 fr_strerror_printf("Unknown interface \"%s\"", pcap->name);
213 return -1;
214 }
215
216#if defined(HAVE_PCAP_CREATE) && defined(HAVE_PCAP_ACTIVATE)
217 pcap->handle = pcap_create(pcap->name, pcap->errbuf);
218 if (!pcap->handle) {
219 fr_strerror_printf("%s", pcap->errbuf);
220 return -1;
221 }
222 if (pcap_set_snaplen(pcap->handle, SNAPLEN) != 0) {
223 create_error:
224 fr_strerror_printf("%s", pcap_geterr(pcap->handle));
225 pcap_close(pcap->handle);
226 pcap->handle = NULL;
227 return -1;
228 }
229 if (pcap_set_timeout(pcap->handle, PCAP_NONBLOCK_TIMEOUT) != 0) {
230 goto create_error;
231 }
232 if (pcap_set_promisc(pcap->handle, pcap->promiscuous) != 0) {
233 goto create_error;
234 }
235
236 if (pcap_set_buffer_size(pcap->handle, SNAPLEN *
237 (pcap->buffer_pkts ? pcap->buffer_pkts : PCAP_BUFFER_DEFAULT)) != 0) {
238 goto create_error;
239 }
240 if (pcap_activate(pcap->handle) != 0) {
241 goto create_error;
242 }
243#else
244 /*
245 * Alternative functions for libpcap < 1.0
246 */
247 pcap->handle = pcap_open_live(pcap->name, SNAPLEN, pcap->promiscuous, PCAP_NONBLOCK_TIMEOUT,
248 pcap->errbuf);
249 if (!pcap->handle) {
250 fr_strerror_printf("%s", pcap->errbuf);
251 return -1;
252 }
253#endif
254
255 /*
256 * Do this later so we get real errors from libpcap,
257 * when bad interfaces are passed in.
258 */
259 if (fr_pcap_mac_addr((uint8_t *)&pcap->ether_addr, pcap->name) != 0) {
260 fr_strerror_printf("Couldn't get MAC address for interface %s", pcap->name);
261 pcap_close(pcap->handle);
262 return -1;
263 }
264
265 /*
266 * Despite accepting an errbuff, pcap_setnonblock doesn't seem to write
267 * error message there in newer versions.
268 */
269 if (pcap_setnonblock(pcap->handle, true, pcap->errbuf) != 0) {
270 fr_strerror_printf("%s", *pcap->errbuf != '\0' ?
271 pcap->errbuf : pcap_geterr(pcap->handle));
272 pcap_close(pcap->handle);
273 pcap->handle = NULL;
274 return -1;
275 }
276
277 pcap->fd = pcap_get_selectable_fd(pcap->handle);
278 pcap->link_layer = pcap_datalink(pcap->handle);
279#ifndef __linux__
280 {
281 int value = 1;
282 if (ioctl(pcap->fd, BIOCIMMEDIATE, &value) < 0) {
283 fr_strerror_printf("Failed setting BIOCIMMEDIATE: %s", fr_syserror(errno));
284 }
285 }
286#endif
287 }
288 break;
289
290 case PCAP_FILE_IN:
291 pcap->handle = pcap_open_offline(pcap->name, pcap->errbuf);
292 if (!pcap->handle) {
293 fr_strerror_printf("%s", pcap->errbuf);
294
295 return -1;
296 }
297 pcap->fd = pcap_get_selectable_fd(pcap->handle);
298 pcap->link_layer = pcap_datalink(pcap->handle);
299 break;
300
301 case PCAP_FILE_OUT:
302 if (pcap->link_layer < 0) {
303 pcap->link_layer = DLT_EN10MB;
304 }
305 pcap->handle = pcap_open_dead(pcap->link_layer, SNAPLEN);
306 if (!pcap->handle) {
307 fr_strerror_const("Unknown error occurred opening dead PCAP handle");
308
309 return -1;
310 }
311 pcap->dumper = pcap_dump_open(pcap->handle, pcap->name);
312 if (!pcap->dumper) {
313 fr_strerror_printf("%s", pcap_geterr(pcap->handle));
314 pcap_close(pcap->handle);
315 pcap->handle = NULL;
316 return -1;
317 }
318 break;
319
320#ifdef HAVE_PCAP_FOPEN_OFFLINE
321 case PCAP_STDIO_IN:
322 pcap->handle = pcap_fopen_offline(stdin, pcap->errbuf);
323 if (!pcap->handle) {
324 fr_strerror_printf("%s", pcap->errbuf);
325
326 return -1;
327 }
328 pcap->fd = pcap_get_selectable_fd(pcap->handle);
329 pcap->link_layer = pcap_datalink(pcap->handle);
330 break;
331#else
332 case PCAP_STDIO_IN:
333 fr_strerror_const("This version of libpcap does not support reading pcap data from streams");
334
335 return -1;
336#endif
337#ifdef HAVE_PCAP_DUMP_FOPEN
338 case PCAP_STDIO_OUT:
339 pcap->handle = pcap_open_dead(DLT_EN10MB, SNAPLEN);
340 if (!pcap->handle) {
341 fr_strerror_const("Unknown error occurred opening dead PCAP handle");
342 return -1;
343 }
344 pcap->dumper = pcap_dump_fopen(pcap->handle, stdout);
345 if (!pcap->dumper) {
346 fr_strerror_printf("%s", pcap_geterr(pcap->handle));
347 pcap_close(pcap->handle);
348 pcap->handle = NULL;
349 return -1;
350 }
351 break;
352#else
353 case PCAP_STDIO_OUT:
354 fr_strerror_const("This version of libpcap does not support writing pcap data to streams");
355
356 return -1;
357#endif
358 case PCAP_INVALID:
359 default:
360 (void)fr_cond_assert(0);
361 fr_strerror_printf("Bad handle type (%u)", pcap->type);
362 return -1;
363 }
364
365 return 0;
366}
367
368/** Apply capture filter to an interface
369 *
370 * @param pcap handle to apply filter to.
371 * @param expression PCAP expression to use as a filter.
372 * @return
373 * - 0 on success.
374 * - 1 can't apply to interface.
375 * - -1 on failure.
376 */
377int fr_pcap_apply_filter(fr_pcap_t *pcap, char const *expression)
378{
379 bpf_u_int32 mask = 0; /* Our netmask */
380 bpf_u_int32 net = 0; /* Our IP */
381 struct bpf_program fp;
382
383 /*
384 * nflog devices are in the set of devices selected by default.
385 * Unfortunately there's a bug in all released version of libpcap (as of 2/1/2014)
386 * which triggers an abort if pcap_setfilter is called on an nflog interface.
387 *
388 * See here:
389 * https://github.com/the-tcpdump-group/libpcap/commit/676cf8a61ed240d0a86d471ef419f45ba35dba80
390 */
391#ifdef DLT_NFLOG
392 if (pcap->link_layer == DLT_NFLOG) {
393 fr_strerror_const("NFLOG link-layer type filtering not implemented");
394
395 return 1;
396 }
397#endif
398
399 if (pcap->type == PCAP_INTERFACE_IN || pcap->type == PCAP_INTERFACE_IN_OUT) {
400 if (pcap_lookupnet(pcap->name, &net, &mask, pcap->errbuf) < 0) {
401 fr_strerror_printf("Failed getting IP for interface \"%s\", using defaults: %s",
402 pcap->name, pcap->errbuf);
403 }
404 }
405
406 if (pcap_compile(pcap->handle, &fp, expression, 0, net) < 0) {
407 fr_strerror_printf("%s", pcap_geterr(pcap->handle));
408
409 return -1;
410 }
411
412 if (pcap_setfilter(pcap->handle, &fp) < 0) {
413 pcap_freecode(&fp);
414
415 fr_strerror_printf("%s", pcap_geterr(pcap->handle));
416 return -1;
417 }
418
419 pcap_freecode(&fp); /* Free the filter, it's not longer needed after its been applied */
420
421 return 0;
422}
423
424/** Retrieve list of interface names that will be used for capture.
425 * Only used for debugging.
426 *
427 * @param ctx talloc context for allicating string.
428 * @param pcap handle list.
429 * @param c separator to use for list.
430 * @return
431 * - string buffer.
432 */
433char *fr_pcap_device_names(TALLOC_CTX *ctx, fr_pcap_t *pcap, char c)
434{
435 fr_pcap_t *pcap_p;
436 char *buff, *p, *end;
437 size_t len = 0;
438
439 if (!pcap) {
440 null:
441 return talloc_zero_array(ctx, char, 1);
442 }
443
444 for (pcap_p = pcap;
445 pcap_p;
446 pcap_p = pcap_p->next) {
447 /*
448 * talloc_array_length includes \0 which accounts for c
449 */
450 len += talloc_array_length(pcap_p->name);
451 }
452
453 if (!len) goto null;
454
455 buff = p = talloc_zero_array(ctx, char, len);
456 end = p + len;
457
458 for (pcap_p = pcap;
459 pcap_p;
460 pcap_p = pcap_p->next) {
461 size_t name_len = talloc_strlen(pcap_p->name);
462
463 if (!fr_cond_assert(p < end)) {
465 return NULL;
466 }
467
468 memcpy(p, pcap_p->name, name_len);
469 p += name_len;
470 *p++ = c;
471 }
472 *(end - 1) = '\0'; /* Strip trailing separation char */
473
474 return buff;
475}
476
477
478/** Check whether fr_pcap_link_layer_offset can process a link_layer
479 *
480 * @param link_layer to check.
481 * @return
482 * - true if supported.
483 * - false if not supported.
484 */
485bool fr_pcap_link_layer_supported(int link_layer)
486{
487 switch (link_layer) {
488 case DLT_EN10MB:
489 case DLT_RAW:
490 case DLT_NULL:
491 case DLT_LOOP:
492#ifdef DLT_LINUX_SLL
493 case DLT_LINUX_SLL:
494#endif
495#ifdef DLT_LINUX_SLL2
496 case DLT_LINUX_SLL2:
497#endif
498 case DLT_PFLOG:
499 return true;
500
501 default:
502 return false;
503 }
504}
505
506/** Returns the length of the link layer header
507 *
508 * Libpcap does not include a decoding function to skip the L2 header, but it does
509 * at least inform us of the type.
510 *
511 * Unfortunately some headers are of variable length (like ethernet), so additional
512 * decoding logic is required.
513 *
514 * @note No header data is returned, this is only meant to be used to determine how
515 * data to consume before attempting to parse the IP header.
516 *
517 * @param data start of packet data.
518 * @param len caplen.
519 * @param link_layer value returned from pcap_linktype.
520 * @return
521 * - Length of the header.
522 * - -1 on failure.
523 */
524ssize_t fr_pcap_link_layer_offset(uint8_t const *data, size_t len, int link_layer)
525{
526 uint8_t const *p = data;
527
528 switch (link_layer) {
529 case DLT_RAW:
530 break;
531
532 case DLT_NULL:
533 case DLT_LOOP:
534 p += 4;
535 if (((size_t)(p - data)) > len) {
536 ood:
537 fr_strerror_printf("Out of data, needed %zu bytes, have %zu bytes",
538 (size_t)(p - data), len);
539 return -1;
540 }
541 break;
542
543 case DLT_EN10MB:
544 {
545 uint16_t ether_type; /* Ethernet type */
546 int i;
547
548 p += 12; /* SRC/DST Mac-Addresses */
549 if (((size_t)(p - data)) > len) {
550 goto ood;
551 }
552
553 for (i = 0; i < 3; i++) {
554 ether_type = ntohs(*((uint16_t const *) p));
555 switch (ether_type) {
556 /*
557 * There are a number of devices out there which
558 * double tag with 0x8100 *sigh*
559 */
560 case 0x8100: /* CVLAN */
561 case 0x9100: /* SVLAN */
562 case 0x9200: /* SVLAN */
563 case 0x9300: /* SVLAN */
564 p += 4;
565 if (((size_t)(p - data)) > len) {
566 goto ood;
567 }
568 break;
569
570 default:
571 p += 2;
572 if (((size_t)(p - data)) > len) {
573 goto ood;
574 }
575 goto done;
576 }
577 }
578 fr_strerror_const("Exceeded maximum level of VLAN tag nesting (2)");
579 return -1;
580 }
581
582#ifdef DLT_LINUX_SLL
583 case DLT_LINUX_SLL:
584 p += 16;
585 if (((size_t)(p - data)) > len) {
586 goto ood;
587 }
588 break;
589#endif
590
591#ifdef DLT_LINUX_SLL2
592 case DLT_LINUX_SLL2:
593 p += 20;
594 if (((size_t)(p - data)) > len) {
595 goto ood;
596 }
597 break;
598#endif
599
600 case DLT_PFLOG:
601 p += 28;
602 if (((size_t)(p - data)) > len) {
603 goto ood;
604 }
605 break;
606
607 default:
608 fr_strerror_printf("Unsupported link layer type %i", link_layer);
609 return -1;
610 }
611
612done:
613 return p - data;
614}
615#endif /* HAVE_LIBPCAP */
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:131
Test enumeration values.
Definition dict_test.h:92
talloc_free(hp)
#define AF_LINK
Definition inet.c:1622
unsigned short uint16_t
long int ssize_t
unsigned char uint8_t
#define ETHER_ADDR_LEN
Definition net.h:64
@ DLT_LOOP
Definition net.h:54
@ DLT_NULL
Definition net.h:53
@ DLT_LINUX_SLL
Definition net.h:56
@ DLT_PFLOG
Definition net.h:57
@ DLT_EN10MB
Definition net.h:55
@ DLT_RAW
Definition net.h:52
static bool done
Definition radclient.c:80
static uint32_t mask
Definition rbmonkey.c:39
static char const * name
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:37
fr_aka_sim_id_type_t type
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition strlcpy.c:34
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define talloc_strdup(_ctx, _str)
Definition talloc.h:149
static size_t talloc_strlen(char const *s)
Returns the length of a talloc array containing a string.
Definition talloc.h:143
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
static fr_slen_t data
Definition value.h:1340