@@ -22,7 +22,7 @@ endif(${EXT_CER_ID})
set(SOURCES src/odhcp6c.c src/dhcpv6.c src/ra.c src/script.c)
-set(LIBRARIES resolv)
+set(LIBRARIES resolv rt)
if(USE_LIBUBOX)
add_definitions(-DUSE_LIBUBOX)
@@ -1350,7 +1350,7 @@ static unsigned int dhcpv6_parse_ia(void *opt, void *end)
// Update address IA
dhcpv6_for_each_option(&ia_hdr[1], end, otype, olen, odata) {
- struct odhcp6c_entry entry = {IN6ADDR_ANY_INIT, 0, 0,
+ struct odhcp6c_entry entry = {0, IN6ADDR_ANY_INIT, 0, 0,
IN6ADDR_ANY_INIT, 0, 0, 0, 0, 0, 0};
entry.iaid = ia_hdr->iaid;
@@ -59,6 +59,10 @@ static volatile bool signal_io = false;
static volatile bool signal_usr1 = false;
static volatile bool signal_usr2 = false;
static volatile bool signal_term = false;
+static volatile bool signal_timer = false;
+
+static struct sigaction sa;
+static struct sigevent se;
static int urandom_fd = -1, allow_slaac_only = 0;
static bool bound = false, release = true, ra = false;
@@ -163,6 +167,77 @@ static struct odhcp6c_opt opts[] = {
{ .code = 0, .flags = 0, .str = NULL },
};
+static void timer_handler()
+{
+ syslog(LOG_DEBUG, "timer fired.\n");
+ signal_timer = true;
+}
+
+static int timer_init()
+{
+ int signo = SIGRTMIN;
+
+ sa.sa_flags = SA_SIGINFO;
+ sa.sa_sigaction = timer_handler;
+
+ syslog(LOG_DEBUG, "in timer_init.\n");
+
+ sigemptyset(&sa.sa_mask);
+ if (sigaction(signo, &sa, NULL) == -1)
+ {
+ perror("sigaction install failed");
+ return -1;
+ }
+
+ /* Set and enable alarm */
+ se.sigev_notify = SIGEV_SIGNAL;
+ se.sigev_signo = signo;
+ return 0;
+}
+
+static int timer_set(timer_t timer, int count)
+{
+ struct itimerspec its;
+ its.it_interval.tv_sec = 0;
+ its.it_interval.tv_nsec = 0;
+ its.it_value.tv_sec = count;
+ its.it_value.tv_nsec = 0;
+
+ syslog(LOG_DEBUG, "in timer_set, count = %d.\n", count);
+
+ if (timer_settime(timer, 0, &its, NULL) == -1)
+ {
+ perror("timer settime failed");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int timer_add(timer_t *timer, int count)
+{
+ syslog(LOG_DEBUG, "in timer_add.\n");
+
+ if (timer_create(CLOCK_REALTIME, &se, timer) == -1)
+ {
+ perror("timer create failed");
+ return -1;
+ }
+
+ return timer_set(*timer, count);
+}
+
+static int timer_del(timer_t *timer)
+{
+ int rc = 0;
+
+ syslog(LOG_DEBUG, "in timer_del.\n");
+
+ rc = timer_delete(*timer);
+ *timer = 0;
+ return rc;
+}
+
int main(_unused int argc, char* const argv[])
{
static struct in6_addr ifid = IN6ADDR_ANY_INIT;
@@ -404,6 +479,8 @@ int main(_unused int argc, char* const argv[])
if (help || !ifname)
return usage();
+ timer_init();
+
signal(SIGIO, sighandler);
signal(SIGHUP, sighandler);
signal(SIGINT, sighandler);
@@ -666,6 +743,16 @@ static uint8_t* odhcp6c_resize_state(enum odhcp6c_state state, ssize_t len)
bool odhcp6c_signal_process(void)
{
+ /* To apply the RFC 8106, DNS RA options could have a lower lifetime
+ * than MaxRtrAdvInterval. So the options could be expired between
+ * two RA messages, and need to be processed here. */
+ if (signal_timer) {
+ signal_timer = false;
+ syslog(LOG_DEBUG, "timer arrived, expire invalid options...\n");
+ odhcp6c_expire();
+ script_call("ra-updated", 0, false);
+ }
+
while (signal_io) {
signal_io = false;
@@ -775,6 +862,9 @@ bool odhcp6c_update_entry(enum odhcp6c_state state, struct odhcp6c_entry *new,
struct odhcp6c_entry *x = odhcp6c_find_entry(state, new);
uint8_t *start = odhcp6c_get_state(state, &len);
+ syslog(LOG_ERR, "odhcp6c_update_entry state %d, valid %d, preferred %d",
+ state, new->valid, new->preferred);
+
if (x && x->valid > new->valid && new->valid < safe)
new->valid = safe;
@@ -793,10 +883,21 @@ bool odhcp6c_update_entry(enum odhcp6c_state state, struct odhcp6c_entry *new,
x->t1 = new->t1;
x->t2 = new->t2;
x->iaid = new->iaid;
- } else if (odhcp6c_add_state(state, new, odhcp6c_entry_size(new)))
- return false;
- } else if (x)
+
+ if (state == STATE_RA_DNS || state == STATE_RA_SEARCH)
+ timer_set(x->timer, new->valid);
+ } else {
+ if (state == STATE_RA_DNS || state == STATE_RA_SEARCH)
+ timer_add(&new->timer, new->valid);
+
+ if (odhcp6c_add_state(state, new, odhcp6c_entry_size(new)))
+ return false;
+ }
+ } else if (x) {
+ if (state == STATE_RA_DNS || state == STATE_RA_SEARCH)
+ timer_del(&x->timer);
odhcp6c_remove_state(state, ((uint8_t*)x) - start, odhcp6c_entry_size(x));
+ }
return true;
}
@@ -831,6 +932,9 @@ static void odhcp6c_expire_list(enum odhcp6c_state state, uint32_t elapsed)
c->valid -= elapsed;
if (!c->valid) {
+ syslog(LOG_DEBUG, "in odhcp6c_expire_list expire state %d", state);
+ if (state == STATE_RA_DNS || state == STATE_RA_SEARCH)
+ timer_del(&c->timer);
odhcp6c_remove_state(state, ((uint8_t*)c) - start, odhcp6c_entry_size(c));
start = odhcp6c_get_state(state, &len);
} else
@@ -15,6 +15,7 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
+#include <time.h>
#include <netinet/in.h>
#define _unused __attribute__((unused))
@@ -345,6 +346,7 @@ enum odhcp6c_ia_mode {
struct odhcp6c_entry {
+ timer_t timer;
struct in6_addr router;
uint8_t auxlen;
uint8_t length;
The sender domain has a DMARC Reject/Quarantine policy which disallows sending mailing list messages using the original "From" header. To mitigate this problem, the original message has been wrapped automatically by the mailing list software. To support RFC 8106 DNS RA option lifetime, add timers for RA DNS and RA SEARCH options, when timer fires, expire invalid options in list. Signed-off-by: Asura Liu <asuliu@cisco.com> --- CMakeLists.txt | 2 +- src/dhcpv6.c | 2 +- src/odhcp6c.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++-- src/odhcp6c.h | 2 + 4 files changed, 111 insertions(+), 5 deletions(-) -- 2.27.0