26 #include <sys/ioctl.h>
27 #include <sys/types.h>
30 #include <net/if_dl.h>
36 #include <freeradius-devel/pcap.h>
37 #include <freeradius-devel/net.h>
38 #include <freeradius-devel/rad_assert.h>
45 static int _free_pcap(fr_pcap_t *pcap)
48 case PCAP_INTERFACE_IN:
49 case PCAP_INTERFACE_OUT:
50 case PCAP_INTERFACE_IN_OUT:
54 pcap_close(pcap->handle);
65 pcap_dump_flush(pcap->dumper);
66 pcap_dump_close(pcap->dumper);
89 int fr_pcap_if_link_layer(
char *errbuff, pcap_if_t *dev)
94 pcap = pcap_open_live(dev->name, 0, 0, 0, errbuff);
97 data_link = pcap_datalink(pcap);
110 fr_pcap_t *fr_pcap_init(TALLOC_CTX *ctx,
char const *
name, fr_pcap_type_t type)
114 if (!
fr_assert(type >= PCAP_INTERFACE_IN && type <= PCAP_INTERFACE_IN_OUT)) {
119 this = talloc_zero(ctx, fr_pcap_t);
120 if (!
this)
return NULL;
122 talloc_set_destructor(
this, _free_pcap);
125 this->link_layer = -1;
138 int fr_pcap_mac_addr(uint8_t *macaddr,
char *ifname)
140 #ifndef SIOCGIFHWADDR
141 struct ifaddrs *ifap, *ifaptr;
144 if (getifaddrs(&ifap) == 0) {
145 for (ifaptr = ifap; ifaptr != NULL; ifaptr = (ifaptr)->ifa_next) {
146 if (!strcmp((ifaptr)->ifa_name, ifname) && (((ifaptr)->ifa_addr)->sa_family == AF_LINK)) {
147 ptr = (uint8_t *)LLADDR((
struct sockaddr_dl *)(ifaptr)->ifa_addr);
153 return (ifaptr != NULL ? 0 : -1);
160 fd = socket(AF_INET, SOCK_DGRAM, 0);
166 ifr.ifr_addr.sa_family = AF_INET;
167 strncpy(ifr.ifr_name, ifname , IFNAMSIZ-1);
169 ret = ioctl(fd, SIOCGIFHWADDR, &ifr);
174 memcpy(macaddr, (uint8_t *)ifr.ifr_hwaddr.sa_data,
ETHER_ADDR_LEN);
189 int fr_pcap_open(fr_pcap_t *pcap)
191 switch (pcap->type) {
192 case PCAP_INTERFACE_OUT:
193 case PCAP_INTERFACE_IN:
194 case PCAP_INTERFACE_IN_OUT:
196 #if defined(HAVE_PCAP_CREATE) && defined(HAVE_PCAP_ACTIVATE)
197 pcap->handle = pcap_create(pcap->name, pcap->errbuf);
202 if (pcap_set_snaplen(pcap->handle, SNAPLEN) != 0) {
205 pcap_close(pcap->handle);
209 if (pcap_set_timeout(pcap->handle, PCAP_NONBLOCK_TIMEOUT) != 0) {
212 if (pcap_set_promisc(pcap->handle, pcap->promiscuous) != 0) {
216 if (pcap_set_buffer_size(pcap->handle, SNAPLEN *
217 (pcap->buffer_pkts ? pcap->buffer_pkts : PCAP_BUFFER_DEFAULT)) != 0) {
220 if (pcap_activate(pcap->handle) != 0) {
227 pcap->handle = pcap_open_live(pcap->name, SNAPLEN, pcap->promiscuous, PCAP_NONBLOCK_TIMEOUT,
238 if (fr_pcap_mac_addr((uint8_t *)&pcap->ether_addr, pcap->name) != 0) {
240 pcap_close(pcap->handle);
248 if (pcap_setnonblock(pcap->handle,
true, pcap->errbuf) != 0) {
250 pcap->errbuf : pcap_geterr(pcap->handle));
251 pcap_close(pcap->handle);
256 pcap->fd = pcap_get_selectable_fd(pcap->handle);
257 pcap->link_layer = pcap_datalink(pcap->handle);
261 if (ioctl(pcap->fd, BIOCIMMEDIATE, &value) < 0) {
270 pcap->handle = pcap_open_offline(pcap->name, pcap->errbuf);
276 pcap->fd = pcap_get_selectable_fd(pcap->handle);
277 pcap->link_layer = pcap_datalink(pcap->handle);
281 if (pcap->link_layer < 0) {
284 pcap->handle = pcap_open_dead(pcap->link_layer, SNAPLEN);
290 pcap->dumper = pcap_dump_open(pcap->handle, pcap->name);
298 #ifdef HAVE_PCAP_FOPEN_OFFLINE
300 pcap->handle = pcap_fopen_offline(stdin, pcap->errbuf);
306 pcap->fd = pcap_get_selectable_fd(pcap->handle);
307 pcap->link_layer = pcap_datalink(pcap->handle);
311 fr_strerror_printf(
"This version of libpcap does not support reading pcap data from streams");
315 #ifdef HAVE_PCAP_DUMP_FOPEN
317 pcap->handle = pcap_open_dead(
DLT_EN10MB, SNAPLEN);
318 pcap->dumper = pcap_dump_fopen(pcap->handle, stdout);
327 fr_strerror_printf(
"This version of libpcap does not support writing pcap data to streams");
350 int fr_pcap_apply_filter(fr_pcap_t *pcap,
char const *expression)
352 bpf_u_int32
mask = 0;
354 struct bpf_program fp;
365 if (pcap->link_layer == DLT_NFLOG) {
372 if (pcap->type == PCAP_INTERFACE_IN || pcap->type == PCAP_INTERFACE_IN_OUT) {
373 if (pcap_lookupnet(pcap->name, &net, &mask, pcap->errbuf) < 0) {
375 pcap->name, pcap->errbuf);
379 if (pcap_compile(pcap->handle, &fp, expression, 0, net) < 0) {
385 if (pcap_setfilter(pcap->handle, &fp) < 0) {
403 char *fr_pcap_device_names(TALLOC_CTX *ctx, fr_pcap_t *pcap,
char c)
407 size_t len = 0, left = 0, wrote;
415 pcap_p = pcap_p->next) {
416 len += talloc_array_length(pcap_p->name);
421 return talloc_zero_array(ctx,
char, 1);
425 buff = p = talloc_zero_array(ctx,
char, left);
428 pcap_p = pcap_p->next) {
429 wrote =
snprintf(p, left,
"%s%c", pcap_p->name, c);
433 buff[len - 1] =
'\0';
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
void fr_strerror_printf(char const *,...) CC_HINT(format(printf
char * talloc_typed_strdup(void const *t, char const *p)
Call talloc strdup, setting the type on the new chunk correctly.