-/* $OpenBSD: engine.c,v 1.19 2021/05/13 11:22:15 florian Exp $ */
+/* $OpenBSD: engine.c,v 1.20 2022/03/23 15:26:08 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/syslog.h>
+#include <sys/time.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include <errno.h>
#include <event.h>
#include <imsg.h>
+#include <pwd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
-#include <pwd.h>
+#include <time.h>
#include <unistd.h>
#include "log.h"
struct engine_iface {
TAILQ_ENTRY(engine_iface) entry;
struct event timer;
+ struct timespec last_ra;
uint32_t if_index;
+ int ras_delayed;
};
TAILQ_HEAD(, engine_iface) engine_interfaces;
parse_rs(struct imsg_ra_rs *rs)
{
struct nd_router_solicit *nd_rs;
- struct imsg_send_ra send_ra;
+ struct engine_iface *engine_iface;
ssize_t len;
+ int unicast_ra = 0;
const char *hbuf;
char ifnamebuf[IFNAMSIZ];
uint8_t *p;
hbuf = sin6_to_str(&rs->from);
- send_ra.if_index = rs->if_index;
- memcpy(&send_ra.to, &all_nodes, sizeof(send_ra.to));
-
log_debug("got RS from %s on %s", hbuf, if_indextoname(rs->if_index,
ifnamebuf));
+ if ((engine_iface = find_engine_iface_by_id(rs->if_index)) == NULL)
+ return;
+
len = rs->len;
if (!(IN6_IS_ADDR_LINKLOCAL(&rs->from.sin6_addr) ||
switch (nd_opt_hdr->nd_opt_type) {
case ND_OPT_SOURCE_LINKADDR:
log_debug("got RS with source linkaddr option");
- memcpy(&send_ra.to, &rs->from, sizeof(send_ra.to));
+ unicast_ra = 1;
break;
default:
log_debug("\t\tUNKNOWN: %d", nd_opt_hdr->nd_opt_type);
len -= nd_opt_hdr->nd_opt_len * 8 - 2;
p += nd_opt_hdr->nd_opt_len * 8 - 2;
}
- engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra,
- sizeof(send_ra));
+
+ if (unicast_ra) {
+ struct imsg_send_ra send_ra;
+
+ send_ra.if_index = rs->if_index;
+ memcpy(&send_ra.to, &rs->from, sizeof(send_ra.to));
+ engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra,
+ sizeof(send_ra));
+ } else {
+ struct timespec now, diff, ra_delay = {MIN_DELAY_BETWEEN_RAS, 0};
+ struct timeval tv = {0, 0};
+
+ /* a multicast RA is already scheduled within the next 3 seconds */
+ if (engine_iface->ras_delayed)
+ return;
+
+ engine_iface->ras_delayed = 1;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ timespecsub(&now, &engine_iface->last_ra, &diff);
+
+ if (timespeccmp(&diff, &ra_delay, <)) {
+ timespecsub(&ra_delay, &diff, &ra_delay);
+ TIMESPEC_TO_TIMEVAL(&tv, &ra_delay);
+ }
+
+ tv.tv_usec = arc4random_uniform(MAX_RA_DELAY_TIME * 1000);
+ evtimer_add(&engine_iface->timer, &tv);
+ }
}
struct engine_iface*
memcpy(&send_ra.to, &all_nodes, sizeof(send_ra.to));
engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra,
sizeof(send_ra));
+ clock_gettime(CLOCK_MONOTONIC, &engine_iface->last_ra);
+ engine_iface->ras_delayed = 0;
}
-/* $OpenBSD: rad.h,v 1.21 2021/02/27 10:35:20 florian Exp $ */
+/* $OpenBSD: rad.h,v 1.22 2022/03/23 15:26:08 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
#define MIN_RTR_ADV_INTERVAL 200
#define ADV_DEFAULT_LIFETIME 3 * MAX_RTR_ADV_INTERVAL
#define ADV_PREFERRED_LIFETIME 604800 /* 7 days */
-#define ADV_VALID_LIFETIME 2592000 /* 30 days */
+#define ADV_VALID_LIFETIME 2592000 /* 30 days */
+#define MAX_RA_DELAY_TIME 500 /* 500 milliseconds */
+#define MIN_DELAY_BETWEEN_RAS 3 /* 3 seconds */
#define MAX_SEARCH 1025 /* MAXDNAME in arpa/nameser.h */
#define DEFAULT_RDNS_LIFETIME 600 * 1.5