static void handle_icmpv6(void *addr, void *data, size_t len,
struct interface *iface, void *dest);
static void trigger_router_advert(struct uloop_timeout *event);
-static void sigusr1_refresh(int signal);
+static void router_netevent_cb(unsigned long event, struct netevent_handler_info *info);
static struct odhcpd_event router_event = {.uloop = {.fd = -1}, .handle_dgram = handle_icmpv6, };
+static struct netevent_handler router_netevent_handler = { .cb = router_netevent_cb, };
static FILE *fp_route = NULL;
+
#define TIME_LEFT(t1, now) ((t1) != UINT32_MAX ? (t1) - (now) : UINT32_MAX)
-int init_router(void)
+int router_init(void)
{
// Open ICMPv6 socket
int sock = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_ICMPV6);
if (sock < 0 && errno != EAFNOSUPPORT) {
- syslog(LOG_ERR, "Failed to open RAW-socket: %s", strerror(errno));
+ syslog(LOG_ERR, "Failed to open RAW-socket: %m");
return -1;
}
odhcpd_register(&router_event);
if (!(fp_route = fopen("/proc/net/ipv6_route", "r")))
- syslog(LOG_ERR, "Failed to open routing table: %s",
- strerror(errno));
+ syslog(LOG_ERR, "Failed to open routing table: %m");
+
+ netlink_add_netevent_handler(&router_netevent_handler);
- signal(SIGUSR1, sigusr1_refresh);
return 0;
}
-int setup_router_interface(struct interface *iface, bool enable)
+int router_setup_interface(struct interface *iface, bool enable)
{
if (!fp_route || router_event.uloop.fd < 0)
return -1;
} else {
void *mreq = &all_routers;
- if (iface->ra == RELAYD_RELAY && iface->master) {
+ if (iface->ra == MODE_RELAY && iface->master) {
mreq = &all_nodes;
forward_router_solicitation(iface);
- } else if (iface->ra == RELAYD_SERVER && !iface->master) {
+ } else if (iface->ra == MODE_SERVER && !iface->master) {
iface->timer_rs.cb = trigger_router_advert;
uloop_timeout_set(&iface->timer_rs, 1000);
}
- if (iface->ra == RELAYD_RELAY || (iface->ra == RELAYD_SERVER && !iface->master))
+ if (iface->ra == MODE_RELAY || (iface->ra == MODE_SERVER && !iface->master))
setsockopt(router_event.uloop.fd, IPPROTO_IPV6,
IPV6_ADD_MEMBERSHIP, mreq, sizeof(all_nodes));
}
}
-// Signal handler to resend all RDs
-static void sigusr1_refresh(_unused int signal)
+static void router_netevent_cb(unsigned long event, struct netevent_handler_info *info)
{
struct interface *iface;
- list_for_each_entry(iface, &interfaces, head)
- if (iface->ra == RELAYD_SERVER && !iface->master)
+
+ switch (event) {
+ case NETEV_ROUTE6_ADD:
+ case NETEV_ROUTE6_DEL:
+ if (info->rt.dst_len)
+ break;
+
+ list_for_each_entry(iface, &interfaces, head) {
+ if (iface->ra == MODE_SERVER && !iface->master)
+ uloop_timeout_set(&iface->timer_rs, 1000);
+ }
+ break;
+ case NETEV_ADDR6LIST_CHANGE:
+ iface = info->iface;
+ if (iface && iface->ra == MODE_SERVER && !iface->master)
uloop_timeout_set(&iface->timer_rs, 1000);
+ break;
+ default:
+ break;
+ }
}
+
static bool router_icmpv6_valid(struct sockaddr_in6 *source, uint8_t *data, size_t len)
{
struct icmp6_hdr *hdr = (struct icmp6_hdr *)data;
if (hlim > 0)
adv.h.nd_ra_curhoplimit = hlim;
- if (iface->dhcpv6)
+ if (iface->dhcpv6) {
adv.h.nd_ra_flags_reserved = ND_RA_FLAG_OTHER;
- if (iface->managed >= RELAYD_MANAGED_MFLAG)
- adv.h.nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED;
+ if (iface->ra_managed >= RA_MANAGED_MFLAG)
+ adv.h.nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED;
+ }
if (iface->route_preference < 0)
adv.h.nd_ra_flags_reserved |= ND_RA_PREF_LOW;
// If not shutdown
if (iface->timer_rs.cb) {
- size_t size = sizeof(*addrs) * iface->ia_addr_len;
+ size_t size = sizeof(*addrs) * iface->addr6_len;
addrs = alloca(size);
- memcpy(addrs, iface->ia_addr, size);
+ memcpy(addrs, iface->addr6, size);
- ipcnt = iface->ia_addr_len;
+ ipcnt = iface->addr6_len;
// Check default route
if (iface->default_router) {
continue;
}
+ if (odhcpd_bmemcmp(&addr->addr, &iface->pio_filter_addr,
+ iface->pio_filter_length) != 0 ||
+ addr->prefix < iface->pio_filter_length)
+ continue; // PIO filtered out of this RA
+
struct nd_opt_prefix_info *p = NULL;
for (size_t i = 0; i < pfxs_cnt; ++i) {
if (addr->prefix == pfxs[i].nd_opt_pi_prefix_len &&
p->nd_opt_pi_flags_reserved = 0;
if (!iface->ra_not_onlink)
p->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK;
- if (iface->managed < RELAYD_MANAGED_NO_AFLAG && addr->prefix <= 64)
+ if (iface->ra_managed < RA_MANAGED_NO_AFLAG && addr->prefix <= 64)
p->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO;
if (iface->ra_advrouter)
p->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_RADDR;
for (ssize_t i = 0; i < ipcnt; ++i) {
struct odhcpd_ipaddr *addr = &addrs[i];
- if (addr->dprefix > 64 || addr->dprefix == 0 || addr->valid <= (uint32_t)now ||
- (addr->dprefix == 64 && addr->prefix == 64)) {
+ if (addr->dprefix > 64 || addr->dprefix == 0 || addr->valid <= (uint32_t)now)
continue; // Address not suitable
- } else if (addr->dprefix > 32) {
+
+ if (addr->dprefix > 32) {
addr->addr.in6.s6_addr32[1] &= htonl(~((1U << (64 - addr->dprefix)) - 1));
} else if (addr->dprefix <= 32) {
addr->addr.in6.s6_addr32[0] &= htonl(~((1U << (32 - addr->dprefix)) - 1));
if (!router_icmpv6_valid(addr, data, len))
return;
- if ((iface->ra == RELAYD_SERVER && !iface->master)) { // Server mode
+ if ((iface->ra == MODE_SERVER && !iface->master)) { // Server mode
if (hdr->icmp6_type == ND_ROUTER_SOLICIT)
send_router_advert(iface, &from->sin6_addr);
- } else if (iface->ra == RELAYD_RELAY) { // Relay mode
+ } else if (iface->ra == MODE_RELAY) { // Relay mode
if (hdr->icmp6_type == ND_ROUTER_ADVERT && iface->master)
forward_router_advertisement(data, len);
else if (hdr->icmp6_type == ND_ROUTER_SOLICIT && !iface->master)
struct interface *iface;
list_for_each_entry(iface, &interfaces, head) {
- if (iface->ra != RELAYD_RELAY || iface->master)
+ if (iface->ra != MODE_RELAY || iface->master)
continue;
// Fixup source hardware address option