aboutgitcodebugslistschat
diff options
context:
space:
mode:
-rw-r--r--ip.h9
-rw-r--r--ndp.c54
-rw-r--r--ndp.h3
-rw-r--r--passt.c3
4 files changed, 69 insertions, 0 deletions
diff --git a/ip.h b/ip.h
index b8d4a5b..0742612 100644
--- a/ip.h
+++ b/ip.h
@@ -92,4 +92,13 @@ struct ipv6_opt_hdr {
char *ipv6_l4hdr(const struct pool *p, int idx, size_t offset, uint8_t *proto,
size_t *dlen);
+
+/* IPv6 link-local all-nodes multicast adddress, ff02::1 */
+static const struct in6_addr in6addr_ll_all_nodes = {
+ .s6_addr = {
+ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ },
+};
+
#endif /* IP_H */
diff --git a/ndp.c b/ndp.c
index 09df8d6..7ee44b2 100644
--- a/ndp.c
+++ b/ndp.c
@@ -372,3 +372,57 @@ int ndp(const struct ctx *c, const struct icmp6hdr *ih,
return 1;
}
+
+/* Default interval between unsolicited RAs (seconds) */
+#define DEFAULT_MAX_RTR_ADV_INTERVAL 600 /* RFC 4861, 6.2.1 */
+
+/* Minimum required interval between RAs (seconds) */
+#define MIN_DELAY_BETWEEN_RAS 3 /* RFC 4861, 10 */
+
+static time_t next_ra;
+
+/**
+ * ndp_timer() - Send unsolicited NDP messages if necessary
+ * @c: Execution context
+ * @now: Current (monotonic) time
+ */
+void ndp_timer(const struct ctx *c, const struct timespec *now)
+{
+ time_t max_rtr_adv_interval = DEFAULT_MAX_RTR_ADV_INTERVAL;
+ time_t min_rtr_adv_interval, interval;
+
+ if (c->no_ra || now->tv_sec < next_ra)
+ return;
+
+ /* We must advertise before the route's lifetime expires */
+ max_rtr_adv_interval = MIN(max_rtr_adv_interval, RT_LIFETIME - 1);
+
+ /* But we must not go smaller than the minimum delay */
+ max_rtr_adv_interval = MAX(max_rtr_adv_interval, MIN_DELAY_BETWEEN_RAS);
+
+ /* RFC 4861, 6.2.1 */
+ min_rtr_adv_interval = MAX(max_rtr_adv_interval / 3,
+ MIN_DELAY_BETWEEN_RAS);
+
+ /* As required by RFC 4861, we randomise the interval between
+ * unsolicited RAs. This is to prevent multiple routers on a link
+ * getting synchronised (e.g. after booting a bunch of routers at once)
+ * and causing flurries of RAs at the same time.
+ *
+ * This random doesn't need to be cryptographically strong, so random(3)
+ * is fine. Other routers on the link also want to avoid
+ * synchronisation, and anything malicious has much easier ways to cause
+ * trouble.
+ *
+ * The modulus also makes this not strictly a uniform distribution, but,
+ * again, it's close enough for our purposes.
+ */
+ interval = min_rtr_adv_interval +
+ random() % (max_rtr_adv_interval - min_rtr_adv_interval);
+
+ info("NDP: sending unsolicited RA, next in %llds", (long long)interval);
+
+ ndp_ra(c, &in6addr_ll_all_nodes);
+
+ next_ra = now->tv_sec + interval;
+}
diff --git a/ndp.h b/ndp.h
index abe6d02..41c2000 100644
--- a/ndp.h
+++ b/ndp.h
@@ -6,7 +6,10 @@
#ifndef NDP_H
#define NDP_H
+struct icmp6hdr;
+
int ndp(const struct ctx *c, const struct icmp6hdr *ih,
const struct in6_addr *saddr, const struct pool *p);
+void ndp_timer(const struct ctx *c, const struct timespec *now);
#endif /* NDP_H */
diff --git a/passt.c b/passt.c
index 83b26c5..a51a4e1 100644
--- a/passt.c
+++ b/passt.c
@@ -49,6 +49,7 @@
#include "arch.h"
#include "log.h"
#include "tcp_splice.h"
+#include "ndp.h"
#define EPOLL_EVENTS 8
@@ -107,6 +108,8 @@ static void post_handler(struct ctx *c, const struct timespec *now)
flow_defer_handler(c, now);
#undef CALL_PROTO_HANDLER
+
+ ndp_timer(c, now);
}
/**