The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
pcap.c
Go to the documentation of this file.
1/*
2 * This program is 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_typed_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
315 return -1;
316 }
317 break;
318
319#ifdef HAVE_PCAP_FOPEN_OFFLINE
320 case PCAP_STDIO_IN:
321 pcap->handle = pcap_fopen_offline(stdin, pcap->errbuf);
322 if (!pcap->handle) {
323 fr_strerror_printf("%s", pcap->errbuf);
324
325 return -1;
326 }
327 pcap->fd = pcap_get_selectable_fd(pcap->handle);
328 pcap->link_layer = pcap_datalink(pcap->handle);
329 break;
330#else
331 case PCAP_STDIO_IN:
332 fr_strerror_const("This version of libpcap does not support reading pcap data from streams");
333
334 return -1;
335#endif
336#ifdef HAVE_PCAP_DUMP_FOPEN
337 case PCAP_STDIO_OUT:
338 pcap->handle = pcap_open_dead(DLT_EN10MB, SNAPLEN);
339 pcap->dumper = pcap_dump_fopen(pcap->handle, stdout);
340 if (!pcap->dumper) {
341 fr_strerror_printf("%s", pcap_geterr(pcap->handle));
342
343 return -1;
344 }
345 break;
346#else
347 case PCAP_STDIO_OUT:
348 fr_strerror_const("This version of libpcap does not support writing pcap data to streams");
349
350 return -1;
351#endif
352 case PCAP_INVALID:
353 default:
354 (void)fr_cond_assert(0);
355 fr_strerror_printf("Bad handle type (%u)", pcap->type);
356 return -1;
357 }
358
359 return 0;
360}
361
362/** Apply capture filter to an interface
363 *
364 * @param pcap handle to apply filter to.
365 * @param expression PCAP expression to use as a filter.
366 * @return
367 * - 0 on success.
368 * - 1 can't apply to interface.
369 * - -1 on failure.
370 */
371int fr_pcap_apply_filter(fr_pcap_t *pcap, char const *expression)
372{
373 bpf_u_int32 mask = 0; /* Our netmask */
374 bpf_u_int32 net = 0; /* Our IP */
375 struct bpf_program fp;
376
377 /*
378 * nflog devices are in the set of devices selected by default.
379 * Unfortunately there's a bug in all released version of libpcap (as of 2/1/2014)
380 * which triggers an abort if pcap_setfilter is called on an nflog interface.
381 *
382 * See here:
383 * https://github.com/the-tcpdump-group/libpcap/commit/676cf8a61ed240d0a86d471ef419f45ba35dba80
384 */
385#ifdef DLT_NFLOG
386 if (pcap->link_layer == DLT_NFLOG) {
387 fr_strerror_const("NFLOG link-layer type filtering not implemented");
388
389 return 1;
390 }
391#endif
392
393 if (pcap->type == PCAP_INTERFACE_IN || pcap->type == PCAP_INTERFACE_IN_OUT) {
394 if (pcap_lookupnet(pcap->name, &net, &mask, pcap->errbuf) < 0) {
395 fr_strerror_printf("Failed getting IP for interface \"%s\", using defaults: %s",
396 pcap->name, pcap->errbuf);
397 }
398 }
399
400 if (pcap_compile(pcap->handle, &fp, expression, 0, net) < 0) {
401 fr_strerror_printf("%s", pcap_geterr(pcap->handle));
402
403 return -1;
404 }
405
406 if (pcap_setfilter(pcap->handle, &fp) < 0) {
407 pcap_freecode(&fp);
408
409 fr_strerror_printf("%s", pcap_geterr(pcap->handle));
410 return -1;
411 }
412
413 pcap_freecode(&fp); /* Free the filter, it's not longer needed after its been applied */
414
415 return 0;
416}
417
418/** Retrieve list of interface names that will be used for capture.
419 * Only used for debugging.
420 *
421 * @param ctx talloc context for allicating string.
422 * @param pcap handle list.
423 * @param c separator to use for list.
424 * @return
425 * - string buffer.
426 */
427char *fr_pcap_device_names(TALLOC_CTX *ctx, fr_pcap_t *pcap, char c)
428{
429 fr_pcap_t *pcap_p;
430 char *buff, *p, *end;
431 size_t len = 0;
432
433 if (!pcap) {
434 null:
435 return talloc_zero_array(ctx, char, 1);
436 }
437
438 for (pcap_p = pcap;
439 pcap_p;
440 pcap_p = pcap_p->next) {
441 /*
442 * talloc_array_length includes \0 which accounts for c
443 */
444 len += talloc_array_length(pcap_p->name);
445 }
446
447 if (!len) goto null;
448
449 buff = p = talloc_zero_array(ctx, char, len);
450 end = p + len;
451
452 for (pcap_p = pcap;
453 pcap_p;
454 pcap_p = pcap_p->next) {
455 size_t name_len = talloc_array_length(pcap_p->name) - 1;
456
457 if (!fr_cond_assert(p < end)) {
459 return NULL;
460 }
461
462 memcpy(p, pcap_p->name, name_len);
463 p += name_len;
464 *p++ = c;
465 }
466 *(end - 1) = '\0'; /* Strip trailing separation char */
467
468 return buff;
469}
470
471
472/** Check whether fr_pcap_link_layer_offset can process a link_layer
473 *
474 * @param link_layer to check.
475 * @return
476 * - true if supported.
477 * - false if not supported.
478 */
479bool fr_pcap_link_layer_supported(int link_layer)
480{
481 switch (link_layer) {
482 case DLT_EN10MB:
483 case DLT_RAW:
484 case DLT_NULL:
485 case DLT_LOOP:
486#ifdef DLT_LINUX_SLL
487 case DLT_LINUX_SLL:
488#endif
489#ifdef DLT_LINUX_SLL2
490 case DLT_LINUX_SLL2:
491#endif
492 case DLT_PFLOG:
493 return true;
494
495 default:
496 return false;
497 }
498}
499
500/** Returns the length of the link layer header
501 *
502 * Libpcap does not include a decoding function to skip the L2 header, but it does
503 * at least inform us of the type.
504 *
505 * Unfortunately some headers are of variable length (like ethernet), so additional
506 * decoding logic is required.
507 *
508 * @note No header data is returned, this is only meant to be used to determine how
509 * data to consume before attempting to parse the IP header.
510 *
511 * @param data start of packet data.
512 * @param len caplen.
513 * @param link_layer value returned from pcap_linktype.
514 * @return
515 * - Length of the header.
516 * - -1 on failure.
517 */
518ssize_t fr_pcap_link_layer_offset(uint8_t const *data, size_t len, int link_layer)
519{
520 uint8_t const *p = data;
521
522 switch (link_layer) {
523 case DLT_RAW:
524 break;
525
526 case DLT_NULL:
527 case DLT_LOOP:
528 p += 4;
529 if (((size_t)(p - data)) > len) {
530 ood:
531 fr_strerror_printf("Out of data, needed %zu bytes, have %zu bytes",
532 (size_t)(p - data), len);
533 return -1;
534 }
535 break;
536
537 case DLT_EN10MB:
538 {
539 uint16_t ether_type; /* Ethernet type */
540 int i;
541
542 p += 12; /* SRC/DST Mac-Addresses */
543 if (((size_t)(p - data)) > len) {
544 goto ood;
545 }
546
547 for (i = 0; i < 3; i++) {
548 ether_type = ntohs(*((uint16_t const *) p));
549 switch (ether_type) {
550 /*
551 * There are a number of devices out there which
552 * double tag with 0x8100 *sigh*
553 */
554 case 0x8100: /* CVLAN */
555 case 0x9100: /* SVLAN */
556 case 0x9200: /* SVLAN */
557 case 0x9300: /* SVLAN */
558 p += 4;
559 if (((size_t)(p - data)) > len) {
560 goto ood;
561 }
562 break;
563
564 default:
565 p += 2;
566 if (((size_t)(p - data)) > len) {
567 goto ood;
568 }
569 goto done;
570 }
571 }
572 fr_strerror_const("Exceeded maximum level of VLAN tag nesting (2)");
573 return -1;
574 }
575
576#ifdef DLT_LINUX_SLL
577 case DLT_LINUX_SLL:
578 p += 16;
579 if (((size_t)(p - data)) > len) {
580 goto ood;
581 }
582 break;
583#endif
584
585#ifdef DLT_LINUX_SLL2
586 case DLT_LINUX_SLL2:
587 p += 20;
588 if (((size_t)(p - data)) > len) {
589 goto ood;
590 }
591 break;
592#endif
593
594 case DLT_PFLOG:
595 p += 28;
596 if (((size_t)(p - data)) > len) {
597 goto ood;
598 }
599 break;
600
601 default:
602 fr_strerror_printf("Unsupported link layer type %i", link_layer);
603 return -1;
604 }
605
606done:
607 return p - data;
608}
609#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:139
Test enumeration values.
Definition dict_test.h:92
#define AF_LINK
Definition inet.c:1615
talloc_free(reap)
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:41
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
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
Definition talloc.c:445
close(uq->fd)
#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:1265