Refactor how the AF_PACKET socket is used
This commit is contained in:
parent
be97afdf83
commit
f0e0d767f3
122
src/iface.c
122
src/iface.c
@ -33,10 +33,10 @@
|
|||||||
|
|
||||||
#include "addr.h"
|
#include "addr.h"
|
||||||
#include "iface.h"
|
#include "iface.h"
|
||||||
|
#include "io.h"
|
||||||
#include "ndppd.h"
|
#include "ndppd.h"
|
||||||
#include "proxy.h"
|
#include "proxy.h"
|
||||||
#include "session.h"
|
#include "session.h"
|
||||||
#include "sio.h"
|
|
||||||
|
|
||||||
extern int nd_conf_invalid_ttl;
|
extern int nd_conf_invalid_ttl;
|
||||||
extern int nd_conf_valid_ttl;
|
extern int nd_conf_valid_ttl;
|
||||||
@ -46,6 +46,7 @@ extern int nd_conf_retrans_time;
|
|||||||
extern bool nd_conf_keepalive;
|
extern bool nd_conf_keepalive;
|
||||||
|
|
||||||
static nd_iface_t *ndL_first_iface, *ndL_first_free_iface;
|
static nd_iface_t *ndL_first_iface, *ndL_first_free_iface;
|
||||||
|
static nd_io_t *ndL_io;
|
||||||
|
|
||||||
/* Used when daemonizing to make sure the parent process does not restore these flags upon exit. */
|
/* Used when daemonizing to make sure the parent process does not restore these flags upon exit. */
|
||||||
bool nd_iface_no_restore_flags;
|
bool nd_iface_no_restore_flags;
|
||||||
@ -150,7 +151,7 @@ static uint16_t ndL_calculate_icmp6_checksum(ndL_icmp6_msg_t *msg, size_t size)
|
|||||||
return htons(~sum);
|
return htons(~sum);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ndL_handle_packet(nd_iface_t *iface, uint8_t *buf, size_t buflen)
|
static __attribute__((unused)) void ndL_handle_packet(nd_iface_t *iface, uint8_t *buf, size_t buflen)
|
||||||
{
|
{
|
||||||
ndL_icmp6_msg_t *msg = (ndL_icmp6_msg_t *)buf;
|
ndL_icmp6_msg_t *msg = (ndL_icmp6_msg_t *)buf;
|
||||||
|
|
||||||
@ -172,21 +173,18 @@ static void ndL_handle_packet(nd_iface_t *iface, uint8_t *buf, size_t buflen)
|
|||||||
ndL_handle_na(iface, msg);
|
ndL_handle_na(iface, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ndL_sio_handler(nd_sio_t *sio, __attribute__((unused)) int events)
|
static void ndL_io_handler(nd_io_t *io, __attribute__((unused)) int events)
|
||||||
{
|
{
|
||||||
nd_iface_t *ifa = (nd_iface_t *)sio->data;
|
|
||||||
|
|
||||||
struct sockaddr_ll lladdr;
|
struct sockaddr_ll lladdr;
|
||||||
memset(&lladdr, 0, sizeof(struct sockaddr_ll));
|
memset(&lladdr, 0, sizeof(struct sockaddr_ll));
|
||||||
lladdr.sll_family = AF_PACKET;
|
lladdr.sll_family = AF_PACKET;
|
||||||
lladdr.sll_protocol = htons(ETH_P_IPV6);
|
lladdr.sll_protocol = htons(ETH_P_IPV6);
|
||||||
lladdr.sll_ifindex = (int)ifa->index;
|
|
||||||
|
|
||||||
uint8_t buf[1024];
|
uint8_t buf[1024];
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
ssize_t len = nd_sio_recv(sio, (struct sockaddr *)&lladdr, sizeof(lladdr), buf, sizeof(buf));
|
ssize_t len = nd_io_recv(io, (struct sockaddr *)&lladdr, sizeof(lladdr), buf, sizeof(buf));
|
||||||
|
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return;
|
return;
|
||||||
@ -194,7 +192,12 @@ static void ndL_sio_handler(nd_sio_t *sio, __attribute__((unused)) int events)
|
|||||||
if (len < 0)
|
if (len < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ndL_handle_packet(ifa, buf, len);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,57 +235,18 @@ nd_iface_t *nd_iface_open(const char *name, unsigned int index)
|
|||||||
return iface;
|
return iface;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No such interface. */
|
|
||||||
|
|
||||||
nd_sio_t *sio = nd_sio_open(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6));
|
|
||||||
|
|
||||||
if (!sio)
|
|
||||||
{
|
|
||||||
nd_log_error("Failed to create socket: %s", strerror(errno));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Determine link-layer address. */
|
/* Determine link-layer address. */
|
||||||
|
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
memset(&ifr, 0, sizeof(ifr));
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
strcpy(ifr.ifr_name, name);
|
strcpy(ifr.ifr_name, name);
|
||||||
|
|
||||||
if (ioctl(sio->fd, SIOCGIFHWADDR, &ifr) < 0)
|
if (ioctl(ndL_io->fd, SIOCGIFHWADDR, &ifr) < 0)
|
||||||
{
|
{
|
||||||
nd_sio_close(sio);
|
|
||||||
nd_log_error("Failed to determine link-layer address: %s", strerror(errno));
|
nd_log_error("Failed to determine link-layer address: %s", strerror(errno));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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(sio->fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) < 0)
|
|
||||||
{
|
|
||||||
nd_sio_close(sio);
|
|
||||||
nd_log_error("Failed to configure netfilter: %s", strerror(errno));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate the nd_ifa_t object. */
|
/* Allocate the nd_ifa_t object. */
|
||||||
|
|
||||||
iface = ndL_first_free_iface;
|
iface = ndL_first_free_iface;
|
||||||
@ -296,7 +260,6 @@ nd_iface_t *nd_iface_open(const char *name, unsigned int index)
|
|||||||
|
|
||||||
ND_LL_PREPEND(ndL_first_iface, iface, next);
|
ND_LL_PREPEND(ndL_first_iface, iface, next);
|
||||||
|
|
||||||
iface->sio = sio;
|
|
||||||
iface->index = index;
|
iface->index = index;
|
||||||
iface->refcount = 1;
|
iface->refcount = 1;
|
||||||
iface->old_allmulti = -1;
|
iface->old_allmulti = -1;
|
||||||
@ -304,9 +267,6 @@ nd_iface_t *nd_iface_open(const char *name, unsigned int index)
|
|||||||
strcpy(iface->name, name);
|
strcpy(iface->name, name);
|
||||||
memcpy(iface->lladdr, ifr.ifr_hwaddr.sa_data, 6);
|
memcpy(iface->lladdr, ifr.ifr_hwaddr.sa_data, 6);
|
||||||
|
|
||||||
sio->data = (intptr_t)iface;
|
|
||||||
sio->handler = ndL_sio_handler;
|
|
||||||
|
|
||||||
nd_log_info("New interface %s (%d)", iface->name, iface->index);
|
nd_log_info("New interface %s (%d)", iface->name, iface->index);
|
||||||
|
|
||||||
return iface;
|
return iface;
|
||||||
@ -325,8 +285,6 @@ void nd_iface_close(nd_iface_t *iface)
|
|||||||
nd_iface_set_allmulti(iface, iface->old_allmulti);
|
nd_iface_set_allmulti(iface, iface->old_allmulti);
|
||||||
}
|
}
|
||||||
|
|
||||||
nd_sio_close(iface->sio);
|
|
||||||
|
|
||||||
ND_LL_DELETE(ndL_first_iface, iface, next);
|
ND_LL_DELETE(ndL_first_iface, iface, next);
|
||||||
ND_LL_PREPEND(ndL_first_free_iface, iface, next);
|
ND_LL_PREPEND(ndL_first_free_iface, iface, next);
|
||||||
}
|
}
|
||||||
@ -363,7 +321,7 @@ static ssize_t ndL_send_icmp6(nd_iface_t *ifa, ndL_icmp6_msg_t *msg, size_t size
|
|||||||
addr.sll_ifindex = (int)ifa->index;
|
addr.sll_ifindex = (int)ifa->index;
|
||||||
memcpy(addr.sll_addr, hwaddr, 6);
|
memcpy(addr.sll_addr, hwaddr, 6);
|
||||||
|
|
||||||
return nd_sio_send(ifa->sio, (struct sockaddr *)&addr, sizeof(addr), msg, size);
|
return nd_io_send(ndL_io, (struct sockaddr *)&addr, sizeof(addr), msg, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t nd_iface_write_na(nd_iface_t *iface, nd_addr_t *dst, uint8_t *dst_ll, nd_addr_t *tgt, bool router)
|
ssize_t nd_iface_write_na(nd_iface_t *iface, nd_addr_t *dst, uint8_t *dst_ll, nd_addr_t *tgt, bool router)
|
||||||
@ -395,8 +353,8 @@ ssize_t nd_iface_write_na(nd_iface_t *iface, nd_addr_t *dst, uint8_t *dst_ll, nd
|
|||||||
|
|
||||||
memcpy(msg.lladdr, iface->lladdr, sizeof(msg.lladdr));
|
memcpy(msg.lladdr, iface->lladdr, sizeof(msg.lladdr));
|
||||||
|
|
||||||
nd_log_info("Write NA tgt=%s, dst=%s [%x:%x:%x:%x:%x:%x dev %s]", nd_aton(tgt), nd_aton(dst),
|
nd_log_info("Write NA tgt=%s, dst=%s [%x:%x:%x:%x:%x:%x dev %s]", nd_aton(tgt), nd_aton(dst), dst_ll[0], dst_ll[1],
|
||||||
dst_ll[0], dst_ll[1], dst_ll[2], dst_ll[3], dst_ll[4], dst_ll[5], iface->name);
|
dst_ll[2], dst_ll[3], dst_ll[4], dst_ll[5], iface->name);
|
||||||
|
|
||||||
return ndL_send_icmp6(iface, (ndL_icmp6_msg_t *)&msg, sizeof(msg), dst_ll);
|
return ndL_send_icmp6(iface, (ndL_icmp6_msg_t *)&msg, sizeof(msg), dst_ll);
|
||||||
}
|
}
|
||||||
@ -437,6 +395,45 @@ ssize_t nd_iface_write_ns(nd_iface_t *ifa, nd_addr_t *tgt)
|
|||||||
return ndL_send_icmp6(ifa, (ndL_icmp6_msg_t *)&msg, sizeof(msg), ll_mcast);
|
return ndL_send_icmp6(ifa, (ndL_icmp6_msg_t *)&msg, sizeof(msg), ll_mcast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool nd_iface_startup()
|
||||||
|
{
|
||||||
|
if (!(ndL_io = nd_io_socket(AF_PACKET, SOCK_DGRAM, 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)
|
||||||
|
{
|
||||||
|
nd_io_close(ndL_io);
|
||||||
|
ndL_io = NULL;
|
||||||
|
nd_log_error("Failed to configure netfilter: %s", strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ndL_io->handler = ndL_io_handler;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool nd_iface_set_allmulti(nd_iface_t *iface, bool on)
|
bool nd_iface_set_allmulti(nd_iface_t *iface, bool on)
|
||||||
{
|
{
|
||||||
nd_log_debug("%s all multicast mode for interface %s", on ? "Enabling" : "Disabling", iface->name);
|
nd_log_debug("%s all multicast mode for interface %s", on ? "Enabling" : "Disabling", iface->name);
|
||||||
@ -444,7 +441,7 @@ bool nd_iface_set_allmulti(nd_iface_t *iface, bool on)
|
|||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
memcpy(ifr.ifr_name, iface->name, IFNAMSIZ);
|
memcpy(ifr.ifr_name, iface->name, IFNAMSIZ);
|
||||||
|
|
||||||
if (ioctl(iface->sio->fd, SIOCGIFFLAGS, &ifr) < 0)
|
if (ioctl(ndL_io->fd, SIOCGIFFLAGS, &ifr) < 0)
|
||||||
{
|
{
|
||||||
nd_log_error("Failed to get interface flags: %s", strerror(errno));
|
nd_log_error("Failed to get interface flags: %s", strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
@ -461,7 +458,7 @@ bool nd_iface_set_allmulti(nd_iface_t *iface, bool on)
|
|||||||
else
|
else
|
||||||
ifr.ifr_flags &= ~IFF_ALLMULTI;
|
ifr.ifr_flags &= ~IFF_ALLMULTI;
|
||||||
|
|
||||||
if (ioctl(iface->sio->fd, SIOCSIFFLAGS, &ifr) < 0)
|
if (ioctl(ndL_io->fd, SIOCSIFFLAGS, &ifr) < 0)
|
||||||
{
|
{
|
||||||
nd_log_error("Failed to set interface flags: %s", strerror(errno));
|
nd_log_error("Failed to set interface flags: %s", strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
@ -477,7 +474,7 @@ bool nd_iface_set_promisc(nd_iface_t *iface, bool on)
|
|||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
memcpy(ifr.ifr_name, iface->name, IFNAMSIZ);
|
memcpy(ifr.ifr_name, iface->name, IFNAMSIZ);
|
||||||
|
|
||||||
if (ioctl(iface->sio->fd, SIOCGIFFLAGS, &ifr) < 0)
|
if (ioctl(ndL_io->fd, SIOCGIFFLAGS, &ifr) < 0)
|
||||||
{
|
{
|
||||||
nd_log_error("Failed to get interface flags: %s", strerror(errno));
|
nd_log_error("Failed to get interface flags: %s", strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
@ -494,7 +491,7 @@ bool nd_iface_set_promisc(nd_iface_t *iface, bool on)
|
|||||||
else
|
else
|
||||||
ifr.ifr_flags &= ~IFF_PROMISC;
|
ifr.ifr_flags &= ~IFF_PROMISC;
|
||||||
|
|
||||||
if (ioctl(iface->sio->fd, SIOCSIFFLAGS, &ifr) < 0)
|
if (ioctl(ndL_io->fd, SIOCSIFFLAGS, &ifr) < 0)
|
||||||
{
|
{
|
||||||
nd_log_error("Failed to set interface flags: %s", strerror(errno));
|
nd_log_error("Failed to set interface flags: %s", strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
@ -507,8 +504,9 @@ void nd_iface_cleanup()
|
|||||||
{
|
{
|
||||||
ND_LL_FOREACH_S(ndL_first_iface, iface, tmp, next)
|
ND_LL_FOREACH_S(ndL_first_iface, iface, tmp, next)
|
||||||
{
|
{
|
||||||
/* We're gonna be bad and just ignore refs here as all memory will soon be invalid anyway. */
|
|
||||||
iface->refcount = 1;
|
iface->refcount = 1;
|
||||||
nd_iface_close(iface);
|
nd_iface_close(iface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nd_io_close(ndL_io);
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#define NDPPD_IFACE_H
|
#define NDPPD_IFACE_H
|
||||||
|
|
||||||
#include "ndppd.h"
|
#include "ndppd.h"
|
||||||
|
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
|
|
||||||
struct nd_iface
|
struct nd_iface
|
||||||
@ -37,7 +38,6 @@ struct nd_iface
|
|||||||
|
|
||||||
nd_proxy_t *proxy;
|
nd_proxy_t *proxy;
|
||||||
nd_session_t *sessions; /* All sessions expecting NA messages to arrive here. */
|
nd_session_t *sessions; /* All sessions expecting NA messages to arrive here. */
|
||||||
nd_sio_t *sio;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern bool nd_iface_no_restore_flags;
|
extern bool nd_iface_no_restore_flags;
|
||||||
@ -49,6 +49,7 @@ ssize_t nd_iface_write_na(nd_iface_t *iface, nd_addr_t *dst, uint8_t *dst_ll, nd
|
|||||||
void nd_iface_get_local_addr(nd_iface_t *iface, nd_addr_t *addr);
|
void nd_iface_get_local_addr(nd_iface_t *iface, nd_addr_t *addr);
|
||||||
bool nd_iface_set_allmulti(nd_iface_t *iface, bool on);
|
bool nd_iface_set_allmulti(nd_iface_t *iface, bool on);
|
||||||
bool nd_iface_set_promisc(nd_iface_t *iface, bool on);
|
bool nd_iface_set_promisc(nd_iface_t *iface, bool on);
|
||||||
|
bool nd_iface_startup();
|
||||||
void nd_iface_cleanup();
|
void nd_iface_cleanup();
|
||||||
|
|
||||||
#endif /* NDPPD_IFACE_H */
|
#endif /* NDPPD_IFACE_H */
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#ifndef NDPPD_NO_USE_EPOLL
|
#ifndef NDPPD_NO_USE_EPOLL
|
||||||
|
# include <fcntl.h>
|
||||||
# include <sys/epoll.h>
|
# include <sys/epoll.h>
|
||||||
#else
|
#else
|
||||||
# include <poll.h>
|
# include <poll.h>
|
||||||
@ -34,16 +35,16 @@
|
|||||||
# define EPOLLIN POLLIN
|
# define EPOLLIN POLLIN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "io.h"
|
||||||
#include "ndppd.h"
|
#include "ndppd.h"
|
||||||
#include "sio.h"
|
|
||||||
|
|
||||||
static nd_sio_t *ndL_first_sio, *ndL_first_free_sio;
|
static nd_io_t *ndL_first_io, *ndL_first_free_io;
|
||||||
|
|
||||||
#ifndef NDPPD_NO_USE_EPOLL
|
#ifndef NDPPD_NO_USE_EPOLL
|
||||||
static int ndL_epoll_fd;
|
static int ndL_epoll_fd;
|
||||||
#else
|
#else
|
||||||
# ifndef NDPPD_STATIC_POLLFDS_SIZE
|
# ifndef NDPPD_STATIC_POLLFDS_SIZE
|
||||||
# define NDPPD_STATIC_POLLFDS_SIZE 32
|
# define NDPPD_STATIC_POLLFDS_SIZE 8
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
static struct pollfd static_pollfds[NDPPD_STATIC_POLLFDS_SIZE];
|
static struct pollfd static_pollfds[NDPPD_STATIC_POLLFDS_SIZE];
|
||||||
@ -74,7 +75,7 @@ static void ndL_refresh_pollfds()
|
|||||||
|
|
||||||
ND_LL_FOREACH(ndL_first_sio, sio, next)
|
ND_LL_FOREACH(ndL_first_sio, sio, next)
|
||||||
{
|
{
|
||||||
pollfds[index].fd = sio->fd;
|
pollfds[index].fd = io->fd;
|
||||||
pollfds[index].revents = 0;
|
pollfds[index].revents = 0;
|
||||||
pollfds[index].events = POLLIN;
|
pollfds[index].events = POLLIN;
|
||||||
index++;
|
index++;
|
||||||
@ -84,73 +85,113 @@ static void ndL_refresh_pollfds()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
nd_sio_t *nd_sio_open(int domain, int type, int protocol)
|
nd_io_t *nd_sio_create(int fd)
|
||||||
{
|
{
|
||||||
int fd = socket(domain, type, protocol);
|
nd_io_t *io = ndL_first_free_io;
|
||||||
|
|
||||||
if (fd < 0)
|
if (io)
|
||||||
return NULL;
|
ND_LL_DELETE(ndL_first_free_io, io, next);
|
||||||
|
else
|
||||||
|
io = ND_ALLOC(nd_io_t);
|
||||||
|
|
||||||
/* Non-blocking. */
|
ND_LL_PREPEND(ndL_first_io, io, next);
|
||||||
|
|
||||||
int on = 1;
|
io->fd = fd;
|
||||||
if (ioctl(fd, FIONBIO, (char *)&on) < 0)
|
io->data = 0;
|
||||||
|
io->handler = NULL;
|
||||||
|
|
||||||
|
return io;
|
||||||
|
}
|
||||||
|
|
||||||
|
static nd_io_t *ndL_create(int fd)
|
||||||
|
{
|
||||||
|
int flags = fcntl(fd, F_GETFL, 0);
|
||||||
|
|
||||||
|
if (flags == -1)
|
||||||
{
|
{
|
||||||
|
nd_log_error("Could not read flags: %s", strerror(errno));
|
||||||
close(fd);
|
close(fd);
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate the nd_sio_t object. */
|
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
|
||||||
|
{
|
||||||
|
nd_log_error("Could not set flags: %s", strerror(errno));
|
||||||
|
close(fd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
nd_sio_t *sio = ndL_first_free_sio;
|
nd_io_t *io = ndL_first_free_io;
|
||||||
|
|
||||||
if (sio)
|
if (io)
|
||||||
ND_LL_DELETE(ndL_first_free_sio, sio, next);
|
ND_LL_DELETE(ndL_first_free_io, io, next);
|
||||||
else
|
else
|
||||||
sio = ND_ALLOC(nd_sio_t);
|
io = ND_ALLOC(nd_io_t);
|
||||||
|
|
||||||
ND_LL_PREPEND(ndL_first_sio, sio, next);
|
ND_LL_PREPEND(ndL_first_io, io, next);
|
||||||
|
|
||||||
sio->fd = fd;
|
io->fd = fd;
|
||||||
|
io->data = 0;
|
||||||
|
io->handler = NULL;
|
||||||
|
|
||||||
#ifndef NDPPD_NO_USE_EPOLL
|
#ifndef NDPPD_NO_USE_EPOLL
|
||||||
if (ndL_epoll_fd <= 0 && (ndL_epoll_fd = epoll_create(1)) < 0)
|
if (ndL_epoll_fd <= 0 && (ndL_epoll_fd = epoll_create(1)) < 0)
|
||||||
{
|
{
|
||||||
nd_log_error("epoll_create() failed: %s", strerror(errno));
|
nd_log_error("epoll_create() failed: %s", strerror(errno));
|
||||||
nd_sio_close(sio);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct epoll_event event = { .events = EPOLLIN, .data.ptr = sio };
|
struct epoll_event event = { .events = EPOLLIN, .data.ptr = io };
|
||||||
|
|
||||||
if (epoll_ctl(ndL_epoll_fd, EPOLL_CTL_ADD, fd, &event) < 0)
|
if (epoll_ctl(ndL_epoll_fd, EPOLL_CTL_ADD, io->fd, &event) < 0)
|
||||||
{
|
{
|
||||||
nd_log_error("epoll_ctl() failed: %s", strerror(errno));
|
nd_log_error("epoll_ctl() failed: %s", strerror(errno));
|
||||||
nd_sio_close(sio);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/* Make sure our pollfd array is updated. */
|
/* Make sure our pollfd array is updated. */
|
||||||
ndL_dirty = true;
|
ndL_dirty = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return sio;
|
return io;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nd_sio_close(nd_sio_t *sio)
|
nd_io_t *nd_io_socket(int domain, int type, int protocol)
|
||||||
{
|
{
|
||||||
close(sio->fd);
|
int fd = socket(domain, type, protocol);
|
||||||
|
|
||||||
|
if (fd == -1)
|
||||||
|
{
|
||||||
|
nd_log_error("nd_io_socket(): Could not create socket: %s", strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ndL_create(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
nd_io_t *nd_io_open(const char *file, int oflag)
|
||||||
|
{
|
||||||
|
int fd = open(file, oflag);
|
||||||
|
|
||||||
|
if (fd == -1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return ndL_create(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nd_io_close(nd_io_t *io)
|
||||||
|
{
|
||||||
|
close(io->fd);
|
||||||
|
|
||||||
#ifdef NDPPD_NO_USE_EPOLL
|
#ifdef NDPPD_NO_USE_EPOLL
|
||||||
ndL_dirty = true;
|
ndL_dirty = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ND_LL_DELETE(ndL_first_sio, sio, next);
|
ND_LL_DELETE(ndL_first_io, io, next);
|
||||||
ND_LL_PREPEND(ndL_first_free_sio, sio, next);
|
ND_LL_PREPEND(ndL_first_free_io, io, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t nd_sio_send(nd_sio_t *sio, const struct sockaddr *addr, size_t addrlen, const void *msg, size_t msglen)
|
ssize_t nd_io_send(nd_io_t *io, const struct sockaddr *addr, size_t addrlen, const void *msg, size_t msglen)
|
||||||
{
|
{
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
iov.iov_len = msglen;
|
iov.iov_len = msglen;
|
||||||
@ -164,7 +205,7 @@ ssize_t nd_sio_send(nd_sio_t *sio, const struct sockaddr *addr, size_t addrlen,
|
|||||||
|
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
|
|
||||||
if ((len = sendmsg(sio->fd, &mhdr, 0)) < 0)
|
if ((len = sendmsg(io->fd, &mhdr, 0)) < 0)
|
||||||
{
|
{
|
||||||
printf("send err %s\n", strerror(errno));
|
printf("send err %s\n", strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
@ -173,7 +214,7 @@ ssize_t nd_sio_send(nd_sio_t *sio, const struct sockaddr *addr, size_t addrlen,
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t nd_sio_recv(nd_sio_t *sio, struct sockaddr *addr, size_t addrlen, 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)
|
||||||
{
|
{
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
iov.iov_len = msglen;
|
iov.iov_len = msglen;
|
||||||
@ -188,7 +229,7 @@ ssize_t nd_sio_recv(nd_sio_t *sio, struct sockaddr *addr, size_t addrlen, void *
|
|||||||
|
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
if ((len = recvmsg(sio->fd, &mhdr, 0)) < 0)
|
if ((len = recvmsg(io->fd, &mhdr, 0)) < 0)
|
||||||
{
|
{
|
||||||
if (errno != EAGAIN)
|
if (errno != EAGAIN)
|
||||||
nd_log_error("nd_sio_recv() failed: %s", strerror(errno));
|
nd_log_error("nd_sio_recv() failed: %s", strerror(errno));
|
||||||
@ -199,12 +240,12 @@ ssize_t nd_sio_recv(nd_sio_t *sio, struct sockaddr *addr, size_t addrlen, void *
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nd_sio_bind(nd_sio_t *sio, const struct sockaddr *addr, size_t addrlen)
|
bool nd_io_bind(nd_io_t *io, const struct sockaddr *addr, size_t addrlen)
|
||||||
{
|
{
|
||||||
return bind(sio->fd, addr, addrlen) == 0;
|
return bind(io->fd, addr, addrlen) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nd_sio_poll()
|
bool nd_io_poll()
|
||||||
{
|
{
|
||||||
#ifndef NDPPD_NO_USE_EPOLL
|
#ifndef NDPPD_NO_USE_EPOLL
|
||||||
struct epoll_event events[8];
|
struct epoll_event events[8];
|
||||||
@ -219,10 +260,10 @@ bool nd_sio_poll()
|
|||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
nd_sio_t *sio = (nd_sio_t *)events[i].data.ptr;
|
nd_io_t *io = (nd_io_t *)events[i].data.ptr;
|
||||||
|
|
||||||
if (sio->handler)
|
if (io->handler)
|
||||||
sio->handler(sio, events[i].events);
|
io->handler(io, events[i].events);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@ -245,12 +286,12 @@ bool nd_sio_poll()
|
|||||||
if (pollfds[i].revents == 0)
|
if (pollfds[i].revents == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (nd_sio_t *sio = ndL_first_sio; sio; sio = sio->next)
|
for (nd_sio_t *sio = ndL_first_sio; sio; sio = io->next)
|
||||||
{
|
{
|
||||||
if (sio->fd == pollfds[i].fd)
|
if (io->fd == pollfds[i].fd)
|
||||||
{
|
{
|
||||||
if (sio->handler != NULL)
|
if (io->handler != NULL)
|
||||||
sio->handler(sio, pollfds[i].revents);
|
io->handler(sio, pollfds[i].revents);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -261,16 +302,18 @@ bool nd_sio_poll()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nd_sio_cleanup()
|
void nd_io_cleanup()
|
||||||
{
|
{
|
||||||
ND_LL_FOREACH_S(ndL_first_sio, sio, tmp, next)
|
ND_LL_FOREACH_S(ndL_first_io, sio, tmp, next)
|
||||||
{
|
{
|
||||||
nd_sio_close(sio);
|
nd_io_close(sio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef NDPPD_NO_USE_EPOLL
|
||||||
if (ndL_epoll_fd > 0)
|
if (ndL_epoll_fd > 0)
|
||||||
{
|
{
|
||||||
close(ndL_epoll_fd);
|
close(ndL_epoll_fd);
|
||||||
ndL_epoll_fd = 0;
|
ndL_epoll_fd = 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
@ -16,27 +16,30 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with ndppd. If not, see <https://www.gnu.org/licenses/>.
|
* along with ndppd. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#ifndef NDPPD_SIO_H
|
#ifndef NDPPD_IO_H
|
||||||
#define NDPPD_SIO_H
|
#define NDPPD_IO_H
|
||||||
|
|
||||||
#include "ndppd.h"
|
#include "ndppd.h"
|
||||||
|
|
||||||
typedef void(nd_sio_handler_t)(nd_sio_t *sio, int events);
|
typedef void(nd_io_handler_t)(nd_io_t *io, int events);
|
||||||
|
|
||||||
struct nd_sio
|
struct nd_io
|
||||||
{
|
{
|
||||||
nd_sio_t *next;
|
nd_io_t *next;
|
||||||
int fd;
|
int fd;
|
||||||
uintptr_t data;
|
uintptr_t data;
|
||||||
nd_sio_handler_t *handler;
|
nd_io_handler_t *handler;
|
||||||
};
|
};
|
||||||
|
|
||||||
nd_sio_t *nd_sio_open(int domain, int type, int protocol);
|
nd_io_t *nd_sio_create(int fd);
|
||||||
void nd_sio_close(nd_sio_t *nio);
|
bool nd_sio_set_nonblock(nd_io_t *io, bool value);
|
||||||
bool nd_sio_bind(nd_sio_t *sio, const struct sockaddr *addr, size_t addrlen);
|
|
||||||
ssize_t nd_sio_send(nd_sio_t *sio, const struct sockaddr *addr, size_t addrlen, const void *msg, size_t msglen);
|
|
||||||
ssize_t nd_sio_recv(nd_sio_t *sio, struct sockaddr *addr, size_t addrlen, void *msg, size_t msglen);
|
|
||||||
bool nd_sio_poll();
|
|
||||||
void nd_sio_cleanup();
|
|
||||||
|
|
||||||
#endif /* NDPPD_SIO_H */
|
nd_io_t *nd_io_socket(int domain, int type, int protocol);
|
||||||
|
void nd_io_close(nd_io_t *io);
|
||||||
|
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();
|
||||||
|
void nd_io_cleanup();
|
||||||
|
|
||||||
|
#endif /*NDPPD_IO_H*/
|
10
src/ndppd.c
10
src/ndppd.c
@ -28,14 +28,12 @@
|
|||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "addr.h"
|
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "iface.h"
|
#include "iface.h"
|
||||||
|
#include "io.h"
|
||||||
#include "ndppd.h"
|
#include "ndppd.h"
|
||||||
#include "proxy.h"
|
#include "proxy.h"
|
||||||
#include "rtnl.h"
|
#include "rtnl.h"
|
||||||
#include "rule.h"
|
|
||||||
#include "sio.h"
|
|
||||||
|
|
||||||
#ifndef NDPPD_CONFIG_PATH
|
#ifndef NDPPD_CONFIG_PATH
|
||||||
# define NDPPD_CONFIG_PATH "../ndppd.conf"
|
# define NDPPD_CONFIG_PATH "../ndppd.conf"
|
||||||
@ -198,6 +196,9 @@ int main(int argc, char *argv[])
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!nd_iface_startup())
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (!nd_proxy_startup())
|
if (!nd_proxy_startup())
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -211,6 +212,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
bool query_addresses = false;
|
bool query_addresses = false;
|
||||||
|
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if (nd_current_time >= nd_rtnl_dump_timeout)
|
if (nd_current_time >= nd_rtnl_dump_timeout)
|
||||||
@ -222,7 +224,7 @@ int main(int argc, char *argv[])
|
|||||||
nd_rtnl_query_addresses();
|
nd_rtnl_query_addresses();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nd_sio_poll())
|
if (!nd_io_poll())
|
||||||
{
|
{
|
||||||
/* TODO: Error */
|
/* TODO: Error */
|
||||||
break;
|
break;
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
#define NDPPD_VERSION "1.0-beta1"
|
#define NDPPD_VERSION "1.0-beta1"
|
||||||
|
|
||||||
typedef struct nd_iface nd_iface_t;
|
typedef struct nd_iface nd_iface_t;
|
||||||
typedef struct nd_sio nd_sio_t;
|
typedef struct nd_io nd_io_t;
|
||||||
typedef struct nd_proxy nd_proxy_t;
|
typedef struct nd_proxy nd_proxy_t;
|
||||||
typedef struct nd_conf nd_conf_t;
|
typedef struct nd_conf nd_conf_t;
|
||||||
typedef struct in6_addr nd_addr_t;
|
typedef struct in6_addr nd_addr_t;
|
||||||
|
28
src/rtnl.c
28
src/rtnl.c
@ -22,11 +22,11 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#include "addr.h"
|
#include "addr.h"
|
||||||
|
#include "io.h"
|
||||||
#include "ndppd.h"
|
#include "ndppd.h"
|
||||||
#include "rtnl.h"
|
#include "rtnl.h"
|
||||||
#include "sio.h"
|
|
||||||
|
|
||||||
static nd_sio_t *ndL_sio;
|
static nd_io_t *ndL_io;
|
||||||
static nd_rtnl_route_t *ndL_routes, *ndL_free_routes;
|
static nd_rtnl_route_t *ndL_routes, *ndL_free_routes;
|
||||||
static nd_rtnl_addr_t *ndL_addrs, *ndL_free_addrs;
|
static nd_rtnl_addr_t *ndL_addrs, *ndL_free_addrs;
|
||||||
|
|
||||||
@ -189,13 +189,13 @@ static void ndL_handle_delroute(struct rtmsg *msg, int rtl)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ndL_sio_handler(__attribute__((unused)) nd_sio_t *unused1, __attribute__((unused)) int unused2)
|
static void ndL_io_handler(__attribute__((unused)) nd_io_t *unused1, __attribute__((unused)) int unused2)
|
||||||
{
|
{
|
||||||
uint8_t buf[4096];
|
uint8_t buf[4096];
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
ssize_t len = nd_sio_recv(ndL_sio, NULL, 0, buf, sizeof(buf));
|
ssize_t len = nd_io_recv(ndL_io, NULL, 0, buf, sizeof(buf));
|
||||||
|
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
/* Failed. */
|
/* Failed. */
|
||||||
@ -230,10 +230,10 @@ static void ndL_sio_handler(__attribute__((unused)) nd_sio_t *unused1, __attribu
|
|||||||
|
|
||||||
bool nd_rtnl_open()
|
bool nd_rtnl_open()
|
||||||
{
|
{
|
||||||
if (ndL_sio != NULL)
|
if (ndL_io != NULL)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!(ndL_sio = nd_sio_open(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)))
|
if (!(ndL_io = nd_io_socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)))
|
||||||
{
|
{
|
||||||
nd_log_error("Failed to open netlink socket: %s", strerror(errno));
|
nd_log_error("Failed to open netlink socket: %s", strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
@ -244,23 +244,23 @@ bool nd_rtnl_open()
|
|||||||
addr.nl_family = AF_NETLINK;
|
addr.nl_family = AF_NETLINK;
|
||||||
addr.nl_groups = (1 << (RTNLGRP_IPV6_IFADDR - 1)) | (1 << (RTNLGRP_IPV6_ROUTE - 1));
|
addr.nl_groups = (1 << (RTNLGRP_IPV6_IFADDR - 1)) | (1 << (RTNLGRP_IPV6_ROUTE - 1));
|
||||||
|
|
||||||
if (!nd_sio_bind(ndL_sio, (struct sockaddr *)&addr, sizeof(addr)))
|
if (!nd_io_bind(ndL_io, (struct sockaddr *)&addr, sizeof(addr)))
|
||||||
{
|
{
|
||||||
nd_log_error("Failed to bind netlink socket: %s", strerror(errno));
|
nd_log_error("Failed to bind netlink socket: %s", strerror(errno));
|
||||||
nd_sio_close(ndL_sio);
|
nd_io_close(ndL_io);
|
||||||
ndL_sio = NULL;
|
ndL_io = NULL;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ndL_sio->handler = ndL_sio_handler;
|
ndL_io->handler = ndL_io_handler;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nd_rtnl_cleanup()
|
void nd_rtnl_cleanup()
|
||||||
{
|
{
|
||||||
if (ndL_sio)
|
if (ndL_io)
|
||||||
nd_sio_close(ndL_sio);
|
nd_io_close(ndL_io);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nd_rtnl_query_routes()
|
bool nd_rtnl_query_routes()
|
||||||
@ -290,7 +290,7 @@ bool nd_rtnl_query_routes()
|
|||||||
|
|
||||||
nd_rtnl_dump_timeout = nd_current_time + 5000;
|
nd_rtnl_dump_timeout = nd_current_time + 5000;
|
||||||
|
|
||||||
nd_sio_send(ndL_sio, (struct sockaddr *)&addr, sizeof(addr), &req, sizeof(req));
|
nd_io_send(ndL_io, (struct sockaddr *)&addr, sizeof(addr), &req, sizeof(req));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,7 +320,7 @@ bool nd_rtnl_query_addresses()
|
|||||||
|
|
||||||
nd_rtnl_dump_timeout = nd_current_time + 5000;
|
nd_rtnl_dump_timeout = nd_current_time + 5000;
|
||||||
|
|
||||||
nd_sio_send(ndL_sio, (struct sockaddr *)&addr, sizeof(addr), &req, sizeof(req));
|
nd_io_send(ndL_io, (struct sockaddr *)&addr, sizeof(addr), &req, sizeof(req));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user