Add support for /dev/bpf
This commit is contained in:
parent
7b17dcc12f
commit
25f6efa8ab
@ -19,6 +19,11 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
# include <sys/socket.h>
|
||||
# define s6_addr32 __u6_addr.__u6_addr32
|
||||
#endif
|
||||
|
||||
#include "ndppd.h"
|
||||
|
||||
/*! Returns the string representation of <tt>addr</tt>.
|
||||
|
261
src/iface.c
261
src/iface.c
@ -18,12 +18,10 @@
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <linux/filter.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/icmp6.h>
|
||||
#include <netinet/in.h>
|
||||
/* Need to include netinet/in.h first on FreeBSD. */
|
||||
#include <netinet/icmp6.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
@ -31,6 +29,20 @@
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#ifdef __linux__
|
||||
# include <linux/filter.h>
|
||||
# include <linux/if_ether.h>
|
||||
# include <linux/if_packet.h>
|
||||
# include <netinet/if_ether.h>
|
||||
#else
|
||||
# include <fcntl.h>
|
||||
# include <net/bpf.h>
|
||||
# include <net/ethernet.h>
|
||||
# include <net/if_dl.h>
|
||||
# include <sys/sysctl.h>
|
||||
# define s6_addr32 __u6_addr.__u6_addr32
|
||||
#endif
|
||||
|
||||
#include "addr.h"
|
||||
#include "iface.h"
|
||||
#include "io.h"
|
||||
@ -38,6 +50,10 @@
|
||||
#include "proxy.h"
|
||||
#include "session.h"
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic ignored "-Waddress-of-packed-member"
|
||||
#endif
|
||||
|
||||
extern int nd_conf_invalid_ttl;
|
||||
extern int nd_conf_valid_ttl;
|
||||
extern int nd_conf_renew;
|
||||
@ -173,6 +189,8 @@ static __attribute__((unused)) void ndL_handle_packet(nd_iface_t *iface, uint8_t
|
||||
ndL_handle_na(iface, msg);
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
/* Called from nd_io_poll() when there are pending events on the nd_io_t. */
|
||||
static void ndL_io_handler(nd_io_t *io, __attribute__((unused)) int events)
|
||||
{
|
||||
struct sockaddr_ll lladdr;
|
||||
@ -192,14 +210,106 @@ static void ndL_io_handler(nd_io_t *io, __attribute__((unused)) int events)
|
||||
if (len < 0)
|
||||
return;
|
||||
|
||||
if ((size_t)len < sizeof(struct ether_header) + sizeof(struct ip6_hdr))
|
||||
continue;
|
||||
|
||||
struct ether_header *eh = (struct ether_header *)(buf);
|
||||
|
||||
if (eh->ether_type != ntohs(ETHERTYPE_IPV6))
|
||||
continue;
|
||||
|
||||
struct ip6_hdr *ip6_hdr = (struct ip6_hdr *)(eh + 1);
|
||||
|
||||
nd_iface_t *iface;
|
||||
|
||||
ND_LL_SEARCH(ndL_first_iface, iface, next, iface->index == (unsigned int)lladdr.sll_ifindex);
|
||||
|
||||
if (iface)
|
||||
ndL_handle_packet(iface, buf, len);
|
||||
ndL_handle_packet(iface, (uint8_t *)ip6_hdr, len - sizeof(struct ether_header));
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* Called from nd_io_poll() when there are pending events on the nd_io_t. */
|
||||
static void ndL_io_handler(nd_io_t *io, __attribute__((unused)) int events)
|
||||
{
|
||||
__attribute__((aligned(BPF_ALIGNMENT))) uint8_t buf[4096]; /* Depends on BIOCGBLEN */
|
||||
|
||||
for (;;)
|
||||
{
|
||||
ssize_t len = nd_io_read(io, buf, sizeof(buf));
|
||||
|
||||
if (len < 0)
|
||||
{
|
||||
if (errno == EAGAIN)
|
||||
return;
|
||||
|
||||
nd_log_error("%s", strerror(errno));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < (size_t)len;)
|
||||
{
|
||||
struct bpf_hdr *bpf_hdr = (struct bpf_hdr *)(buf + i);
|
||||
i += BPF_WORDALIGN(bpf_hdr->bh_hdrlen + bpf_hdr->bh_caplen);
|
||||
|
||||
if (bpf_hdr->bh_caplen < sizeof(struct ether_header) + sizeof(struct ip6_hdr))
|
||||
continue;
|
||||
|
||||
struct ether_header *eh = (struct ether_header *)((void *)bpf_hdr + bpf_hdr->bh_hdrlen);
|
||||
|
||||
if (eh->ether_type != ntohs(ETHERTYPE_IPV6))
|
||||
continue;
|
||||
|
||||
struct ip6_hdr *ip6_hdr = (struct ip6_hdr *)(eh + 1);
|
||||
|
||||
ndL_handle_packet((nd_iface_t *)io->data, (uint8_t *)ip6_hdr,
|
||||
bpf_hdr->bh_caplen - sizeof(struct ether_header));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
__attribute__((unused)) static bool ndL_configure_filter(nd_io_t *io)
|
||||
{
|
||||
#ifndef __linux__
|
||||
# define sock_filter bpf_insn
|
||||
# define sock_fprog bpf_program
|
||||
#endif
|
||||
|
||||
/* Set up filter, so we only get NS and NA messages. */
|
||||
static struct sock_filter filter[] = {
|
||||
/* Load ether_type. */
|
||||
BPF_STMT(BPF_LD | BPF_H | BPF_ABS, offsetof(struct ether_header, ether_type)),
|
||||
/* Drop packet if not ETHERTYPE_IPV6. */
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_IPV6, 0, 5),
|
||||
/* Load ip6_nxt. */
|
||||
BPF_STMT(BPF_LD | BPF_B | BPF_ABS, sizeof(struct ether_header) + offsetof(struct ip6_hdr, ip6_nxt)),
|
||||
/* Bail if it's not IPPROTO_ICMPV6. */
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 3),
|
||||
/* Load icmp6_type. */
|
||||
BPF_STMT(BPF_LD | BPF_B | BPF_ABS,
|
||||
sizeof(struct ether_header) + sizeof(struct ip6_hdr) + offsetof(struct icmp6_hdr, icmp6_type)),
|
||||
/* Keep if ND_NEIGHBOR_SOLICIT. */
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ND_NEIGHBOR_SOLICIT, 2, 0),
|
||||
/* Keep if ND_NEIGHBOR_SOLICIT. */
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ND_NEIGHBOR_ADVERT, 1, 0),
|
||||
/* Drop packet. */
|
||||
BPF_STMT(BPF_RET | BPF_K, 0),
|
||||
/* Keep packet. */
|
||||
BPF_STMT(BPF_RET | BPF_K, (u_int32_t)-1)
|
||||
};
|
||||
|
||||
static struct sock_fprog fprog = { 9, filter };
|
||||
|
||||
#ifdef __linux__
|
||||
if (setsockopt(io->fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) == -1)
|
||||
return false;
|
||||
#else
|
||||
if (ioctl(io->fd, BIOCSETF, &fprog) == -1)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nd_iface_t *nd_iface_open(const char *name, unsigned int index)
|
||||
{
|
||||
@ -235,6 +345,7 @@ nd_iface_t *nd_iface_open(const char *name, unsigned int index)
|
||||
return iface;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
/* Determine link-layer address. */
|
||||
|
||||
struct ifreq ifr;
|
||||
@ -247,7 +358,74 @@ nd_iface_t *nd_iface_open(const char *name, unsigned int index)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocate the nd_ifa_t object. */
|
||||
uint8_t *lladdr = (uint8_t *)ifr.ifr_hwaddr.sa_data;
|
||||
#else
|
||||
nd_io_t *io = NULL;
|
||||
|
||||
/* This requires a cloning bpf device, but I hope most sane systems got them. */
|
||||
if (!(io = nd_io_open("/dev/bpf", O_RDWR)))
|
||||
{
|
||||
nd_log_error("Failed to open a /dev/bpf device");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
io->handler = ndL_io_handler;
|
||||
|
||||
/* Set buffer length. */
|
||||
|
||||
unsigned int len = 4096; /* TODO: Configure */
|
||||
if (ioctl(io->fd, BIOCSBLEN, &len) < 0)
|
||||
{
|
||||
nd_log_error("BIOCSBLEN: %s", strerror(errno));
|
||||
nd_io_close(io);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Bind to interface. */
|
||||
|
||||
struct ifreq ifr;
|
||||
strcpy(ifr.ifr_name, name);
|
||||
if (ioctl(io->fd, BIOCSETIF, &ifr) < 0)
|
||||
{
|
||||
nd_log_error("Failed to bind to interface: %s", strerror(errno));
|
||||
nd_io_close(io);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Immediate */
|
||||
|
||||
uint32_t enable = 1;
|
||||
if (ioctl(io->fd, BIOCIMMEDIATE, &enable) < 0)
|
||||
{
|
||||
nd_log_error("BIOCIMMEDIATE: %s", strerror(errno));
|
||||
nd_io_close(io);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Determine link-layer address. */
|
||||
|
||||
int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, (int)index };
|
||||
uint8_t sysctl_buf[512];
|
||||
size_t sysctl_buflen = sizeof(sysctl_buf);
|
||||
|
||||
if (sysctl(mib, 6, sysctl_buf, &sysctl_buflen, NULL, 0) == -1)
|
||||
{
|
||||
nd_log_error("Failed to determine link-layer address: %s", strerror(errno));
|
||||
nd_io_close(io);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!ndL_configure_filter(io))
|
||||
{
|
||||
nd_log_error("Could not configure filter: %s", strerror(errno));
|
||||
nd_io_close(io);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t *lladdr = (uint8_t *)LLADDR((struct sockaddr_dl *)(sysctl_buf + sizeof(struct if_msghdr)));
|
||||
#endif
|
||||
|
||||
/* Allocate the nd_iface_t object. */
|
||||
|
||||
iface = ndL_first_free_iface;
|
||||
|
||||
@ -265,9 +443,15 @@ nd_iface_t *nd_iface_open(const char *name, unsigned int index)
|
||||
iface->old_allmulti = -1;
|
||||
iface->old_promisc = -1;
|
||||
strcpy(iface->name, name);
|
||||
memcpy(iface->lladdr, ifr.ifr_hwaddr.sa_data, 6);
|
||||
memcpy(iface->lladdr, lladdr, 6);
|
||||
|
||||
nd_log_info("New interface %s (%d)", iface->name, iface->index);
|
||||
#ifndef __linux__
|
||||
io->data = (uintptr_t)iface;
|
||||
iface->bpf_io = io;
|
||||
#endif
|
||||
|
||||
nd_log_info("New interface %s [%02x:%02x:%02x:%02x:%02x:%02x]", iface->name, lladdr[0], lladdr[1], lladdr[2],
|
||||
lladdr[3], lladdr[4], lladdr[5]);
|
||||
|
||||
return iface;
|
||||
}
|
||||
@ -285,6 +469,10 @@ void nd_iface_close(nd_iface_t *iface)
|
||||
nd_iface_set_allmulti(iface, iface->old_allmulti);
|
||||
}
|
||||
|
||||
#ifndef __linux__
|
||||
nd_io_close(iface->bpf_io);
|
||||
#endif
|
||||
|
||||
ND_LL_DELETE(ndL_first_iface, iface, next);
|
||||
ND_LL_PREPEND(ndL_first_free_iface, iface, next);
|
||||
}
|
||||
@ -314,14 +502,27 @@ static ssize_t ndL_send_icmp6(nd_iface_t *ifa, ndL_icmp6_msg_t *msg, size_t size
|
||||
|
||||
msg->icmp6_hdr.icmp6_cksum = ndL_calculate_icmp6_checksum(msg, size);
|
||||
|
||||
struct sockaddr_ll addr;
|
||||
memset(&addr, 0, sizeof(struct sockaddr_ll));
|
||||
addr.sll_family = AF_PACKET;
|
||||
addr.sll_protocol = htons(ETH_P_IPV6);
|
||||
addr.sll_ifindex = (int)ifa->index;
|
||||
memcpy(addr.sll_addr, hwaddr, 6);
|
||||
uint8_t buf[512];
|
||||
|
||||
return nd_io_send(ndL_io, (struct sockaddr *)&addr, sizeof(addr), msg, size);
|
||||
struct ether_header *eh = (struct ether_header *)buf;
|
||||
|
||||
eh->ether_type = htons(ETHERTYPE_IPV6);
|
||||
/* TODO: Maybe use BIOCSHDRCMPLT instead. */
|
||||
memcpy(eh->ether_shost, ifa->lladdr, ETHER_ADDR_LEN);
|
||||
memcpy(eh->ether_dhost, hwaddr, ETHER_ADDR_LEN);
|
||||
|
||||
memcpy(eh + 1, msg, size);
|
||||
|
||||
#ifdef __linux__
|
||||
struct sockaddr_ll ll;
|
||||
memset(&ll, 0, sizeof(ll));
|
||||
ll.sll_family = AF_PACKET;
|
||||
ll.sll_ifindex = (int)ifa->index;
|
||||
|
||||
return nd_io_send(ndL_io, (struct sockaddr *)&ll, sizeof(ll), buf, sizeof(struct ether_header) + size);
|
||||
#else
|
||||
return nd_io_write(ifa->bpf_io, buf, sizeof(struct ether_header) + size);
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t nd_iface_write_na(nd_iface_t *iface, nd_addr_t *dst, uint8_t *dst_ll, nd_addr_t *tgt, bool router)
|
||||
@ -397,39 +598,22 @@ ssize_t nd_iface_write_ns(nd_iface_t *ifa, nd_addr_t *tgt)
|
||||
|
||||
bool nd_iface_startup()
|
||||
{
|
||||
if (!(ndL_io = nd_io_socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6))))
|
||||
#ifdef __linux__
|
||||
if (!(ndL_io = nd_io_socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IPV6))))
|
||||
return false;
|
||||
|
||||
/* Set up filter, so we only get NS and NA messages. */
|
||||
|
||||
static struct sock_filter filter[] = {
|
||||
/* Load next header field. */
|
||||
BPF_STMT(BPF_LD | BPF_B | BPF_ABS, offsetof(struct ip6_hdr, ip6_nxt)),
|
||||
/* Bail if it's not IPPROTO_ICMPV6. */
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 3),
|
||||
/* Load the ICMPv6 type. */
|
||||
BPF_STMT(BPF_LD | BPF_B | BPF_ABS, sizeof(struct ip6_hdr) + offsetof(struct icmp6_hdr, icmp6_type)),
|
||||
/* Keep if ND_NEIGHBOR_SOLICIT. */
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ND_NEIGHBOR_SOLICIT, 2, 0),
|
||||
/* Keep if ND_NEIGHBOR_SOLICIT. */
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ND_NEIGHBOR_ADVERT, 1, 0),
|
||||
/* Drop packet. */
|
||||
BPF_STMT(BPF_RET | BPF_K, 0),
|
||||
/* Keep packet. */
|
||||
BPF_STMT(BPF_RET | BPF_K, (u_int32_t)-1)
|
||||
};
|
||||
|
||||
static struct sock_fprog fprog = { 7, filter };
|
||||
|
||||
if (setsockopt(ndL_io->fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) < 0)
|
||||
if (!ndL_configure_filter(ndL_io))
|
||||
{
|
||||
nd_io_close(ndL_io);
|
||||
ndL_io = NULL;
|
||||
nd_log_error("Failed to configure netfilter: %s", strerror(errno));
|
||||
nd_log_error("Failed to configure BPF: %s", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ndL_io->handler = ndL_io_handler;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -508,5 +692,6 @@ void nd_iface_cleanup()
|
||||
nd_iface_close(iface);
|
||||
}
|
||||
|
||||
nd_io_close(ndL_io);
|
||||
if (ndL_io)
|
||||
nd_io_close(ndL_io);
|
||||
}
|
||||
|
@ -38,6 +38,10 @@ struct nd_iface
|
||||
|
||||
nd_proxy_t *proxy;
|
||||
nd_session_t *sessions; /* All sessions expecting NA messages to arrive here. */
|
||||
|
||||
#ifndef __linux__
|
||||
nd_io_t *bpf_io;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern bool nd_iface_no_restore_flags;
|
||||
|
48
src/io.c
48
src/io.c
@ -21,9 +21,13 @@
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#if !defined(__linux__) && !defined(NDPPD_NO_USE_EPOLL)
|
||||
# define NDPPD_NO_USE_EPOLL
|
||||
#endif
|
||||
|
||||
#ifndef NDPPD_NO_USE_EPOLL
|
||||
# include <fcntl.h>
|
||||
# include <sys/epoll.h>
|
||||
#else
|
||||
# include <poll.h>
|
||||
@ -56,7 +60,7 @@ static void ndL_refresh_pollfds()
|
||||
{
|
||||
int count;
|
||||
|
||||
ND_LL_COUNT(ndL_first_sio, count, next);
|
||||
ND_LL_COUNT(ndL_first_io, count, next);
|
||||
|
||||
if (count > pollfds_size)
|
||||
{
|
||||
@ -65,14 +69,12 @@ static void ndL_refresh_pollfds()
|
||||
pollfds = (struct pollfd *)realloc(pollfds == static_pollfds ? NULL : pollfds,
|
||||
new_pollfds_size * sizeof(struct pollfd));
|
||||
|
||||
/* TODO: Validate return value */
|
||||
|
||||
pollfds_size = new_pollfds_size;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
|
||||
ND_LL_FOREACH(ndL_first_sio, sio, next)
|
||||
ND_LL_FOREACH(ndL_first_io, io, next)
|
||||
{
|
||||
pollfds[index].fd = io->fd;
|
||||
pollfds[index].revents = 0;
|
||||
@ -84,24 +86,6 @@ static void ndL_refresh_pollfds()
|
||||
}
|
||||
#endif
|
||||
|
||||
nd_io_t *nd_sio_create(int fd)
|
||||
{
|
||||
nd_io_t *io = ndL_first_free_io;
|
||||
|
||||
if (io)
|
||||
ND_LL_DELETE(ndL_first_free_io, io, next);
|
||||
else
|
||||
io = ND_ALLOC(nd_io_t);
|
||||
|
||||
ND_LL_PREPEND(ndL_first_io, io, next);
|
||||
|
||||
io->fd = fd;
|
||||
io->data = 0;
|
||||
io->handler = NULL;
|
||||
|
||||
return io;
|
||||
}
|
||||
|
||||
static nd_io_t *ndL_create(int fd)
|
||||
{
|
||||
int flags = fcntl(fd, F_GETFL, 0);
|
||||
@ -239,6 +223,19 @@ ssize_t nd_io_recv(nd_io_t *io, struct sockaddr *addr, size_t addrlen, void *msg
|
||||
return len;
|
||||
}
|
||||
|
||||
ssize_t nd_io_read(nd_io_t *io, void *buf, size_t count)
|
||||
{
|
||||
return read(io->fd, buf, count);
|
||||
}
|
||||
|
||||
ssize_t nd_io_write(nd_io_t *io, void *buf, size_t count)
|
||||
{
|
||||
ssize_t len = write(io->fd, buf, count);
|
||||
if (len < 0)
|
||||
nd_log_error("err: %s", strerror(errno));
|
||||
return len;
|
||||
}
|
||||
|
||||
bool nd_io_bind(nd_io_t *io, const struct sockaddr *addr, size_t addrlen)
|
||||
{
|
||||
return bind(io->fd, addr, addrlen) == 0;
|
||||
@ -264,7 +261,6 @@ bool nd_io_poll()
|
||||
if (io->handler)
|
||||
io->handler(io, events[i].events);
|
||||
}
|
||||
|
||||
#else
|
||||
if (ndL_dirty)
|
||||
{
|
||||
@ -285,12 +281,12 @@ bool nd_io_poll()
|
||||
if (pollfds[i].revents == 0)
|
||||
continue;
|
||||
|
||||
for (nd_sio_t *sio = ndL_first_sio; sio; sio = io->next)
|
||||
ND_LL_FOREACH(ndL_first_io, io, next)
|
||||
{
|
||||
if (io->fd == pollfds[i].fd)
|
||||
{
|
||||
if (io->handler != NULL)
|
||||
io->handler(sio, pollfds[i].revents);
|
||||
io->handler(io, pollfds[i].revents);
|
||||
|
||||
break;
|
||||
}
|
||||
|
3
src/io.h
3
src/io.h
@ -38,6 +38,9 @@ bool nd_io_bind(nd_io_t *io, const struct sockaddr *addr, size_t addrlen);
|
||||
ssize_t nd_io_send(nd_io_t *io, const struct sockaddr *addr, size_t addrlen, const void *msg, size_t msglen);
|
||||
ssize_t nd_io_recv(nd_io_t *io, struct sockaddr *addr, size_t addrlen, void *msg, size_t msglen);
|
||||
bool nd_io_poll();
|
||||
ssize_t nd_io_read(nd_io_t *io, void *buf, size_t count);
|
||||
ssize_t nd_io_write(nd_io_t *io, void *buf, size_t count);
|
||||
|
||||
void nd_io_cleanup();
|
||||
|
||||
#endif /*NDPPD_IO_H*/
|
||||
|
@ -237,10 +237,12 @@ bool nd_proxy_startup()
|
||||
|
||||
proxy->iface->proxy = proxy;
|
||||
|
||||
#ifdef __linux__
|
||||
if (proxy->promisc)
|
||||
nd_iface_set_promisc(proxy->iface, true);
|
||||
else
|
||||
nd_iface_set_allmulti(proxy->iface, true);
|
||||
#endif
|
||||
|
||||
ND_LL_FOREACH(proxy->rules, rule, next)
|
||||
{
|
||||
|
54
src/rtnl.c
54
src/rtnl.c
@ -17,25 +17,32 @@
|
||||
* along with ndppd. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#ifdef __linux__
|
||||
# include <linux/rtnetlink.h>
|
||||
#else
|
||||
# include <net/if.h>
|
||||
# include <net/if_var.h>
|
||||
# include <net/route.h>
|
||||
#endif
|
||||
|
||||
#include "addr.h"
|
||||
#include "io.h"
|
||||
#include "ndppd.h"
|
||||
#include "rtnl.h"
|
||||
|
||||
static nd_io_t *ndL_io;
|
||||
static nd_rtnl_route_t *ndL_routes, *ndL_free_routes;
|
||||
static nd_rtnl_addr_t *ndL_addrs, *ndL_free_addrs;
|
||||
__attribute__((unused)) static nd_rtnl_route_t *ndL_routes, *ndL_free_routes;
|
||||
__attribute__((unused)) static nd_rtnl_addr_t *ndL_addrs, *ndL_free_addrs;
|
||||
|
||||
long nd_rtnl_dump_timeout;
|
||||
|
||||
/*
|
||||
* This will ensure the linked list is kept sorted, so it will be easier to find a match.
|
||||
*/
|
||||
static void ndL_insert_route(nd_rtnl_route_t *route)
|
||||
__attribute__((unused)) static void ndL_insert_route(nd_rtnl_route_t *route)
|
||||
{
|
||||
nd_rtnl_route_t *prev = NULL;
|
||||
|
||||
@ -58,6 +65,7 @@ static void ndL_insert_route(nd_rtnl_route_t *route)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
static void ndL_handle_newaddr(struct ifaddrmsg *msg, int length)
|
||||
{
|
||||
nd_addr_t *addr = NULL;
|
||||
@ -227,12 +235,39 @@ static void ndL_io_handler(__attribute__((unused)) nd_io_t *unused1, __attribute
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
__attribute__((unused)) static void ndL_handle_newaddr(struct ifa_msghdr *msg, int length)
|
||||
{
|
||||
(void)msg;
|
||||
(void)length;
|
||||
|
||||
nd_log_debug("rtnl: NEWADDR");
|
||||
}
|
||||
|
||||
static void ndL_io_handler(__attribute__((unused)) nd_io_t *unused1, __attribute__((unused)) int unused2)
|
||||
{
|
||||
uint8_t buf[4096];
|
||||
|
||||
for (;;)
|
||||
{
|
||||
ssize_t len = nd_io_read(ndL_io, buf, sizeof(buf));
|
||||
|
||||
if (len < 0)
|
||||
/* Failed. */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
bool nd_rtnl_open()
|
||||
{
|
||||
if (ndL_io != NULL)
|
||||
return true;
|
||||
|
||||
#ifdef __linux__
|
||||
if (!(ndL_io = nd_io_socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)))
|
||||
{
|
||||
nd_log_error("Failed to open netlink socket: %s", strerror(errno));
|
||||
@ -251,6 +286,13 @@ bool nd_rtnl_open()
|
||||
ndL_io = NULL;
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (!(ndL_io = nd_io_socket(AF_ROUTE, SOCK_RAW, AF_INET6)))
|
||||
{
|
||||
nd_log_error("Failed to open routing socket: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
ndL_io->handler = ndL_io_handler;
|
||||
|
||||
@ -268,6 +310,7 @@ bool nd_rtnl_query_routes()
|
||||
if (nd_rtnl_dump_timeout)
|
||||
return false;
|
||||
|
||||
#ifdef __linux__
|
||||
struct
|
||||
{
|
||||
struct nlmsghdr hdr;
|
||||
@ -291,6 +334,7 @@ bool nd_rtnl_query_routes()
|
||||
nd_rtnl_dump_timeout = nd_current_time + 5000;
|
||||
|
||||
nd_io_send(ndL_io, (struct sockaddr *)&addr, sizeof(addr), &req, sizeof(req));
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -299,6 +343,7 @@ bool nd_rtnl_query_addresses()
|
||||
if (nd_rtnl_dump_timeout)
|
||||
return false;
|
||||
|
||||
#ifdef __linux__
|
||||
struct
|
||||
{
|
||||
struct nlmsghdr hdr;
|
||||
@ -321,6 +366,7 @@ bool nd_rtnl_query_addresses()
|
||||
nd_rtnl_dump_timeout = nd_current_time + 5000;
|
||||
|
||||
nd_io_send(ndL_io, (struct sockaddr *)&addr, sizeof(addr), &req, sizeof(req));
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user