summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/slaacctl/slaacctl.c31
-rw-r--r--usr.sbin/slaacd/engine.c301
-rw-r--r--usr.sbin/slaacd/engine.h8
-rw-r--r--usr.sbin/slaacd/frontend.c4
-rw-r--r--usr.sbin/slaacd/slaacd.c87
-rw-r--r--usr.sbin/slaacd/slaacd.h16
6 files changed, 432 insertions, 15 deletions
diff --git a/usr.sbin/slaacctl/slaacctl.c b/usr.sbin/slaacctl/slaacctl.c
index 5d2e8df619b..51b4e947f47 100644
--- a/usr.sbin/slaacctl/slaacctl.c
+++ b/usr.sbin/slaacctl/slaacctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: slaacctl.c,v 1.5 2017/05/27 18:37:09 florian Exp $ */
+/* $OpenBSD: slaacctl.c,v 1.6 2017/05/28 09:35:56 florian Exp $ */
/*
* Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
@@ -175,6 +175,7 @@ show_interface_msg(struct imsg *imsg)
struct ctl_engine_info_ra_rdns *cei_ra_rdns;
struct ctl_engine_info_ra_dnssl *cei_ra_dnssl;
struct ctl_engine_info_address_proposal *cei_addr_proposal;
+ struct ctl_engine_info_dfr_proposal *cei_dfr_proposal;
struct tm *t;
struct timespec now, diff;
char buf[IF_NAMESIZE], *bufp;
@@ -278,6 +279,34 @@ show_interface_msg(struct imsg *imsg)
&cei_addr_proposal->prefix, ntopbuf, INET6_ADDRSTRLEN),
cei_addr_proposal->prefix_len);
break;
+ case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSALS:
+ printf("\tDefault router proposals\n");
+ break;
+ case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL:
+ cei_dfr_proposal = imsg->data;
+
+ if (getnameinfo((struct sockaddr *)&cei_dfr_proposal->addr,
+ cei_dfr_proposal->addr.sin6_len, hbuf, sizeof(hbuf),
+ NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV))
+ err(1, "cannot get router IP");
+
+ printf("\t\tid: %4lld, state: %15s\n",
+ cei_dfr_proposal->id, cei_dfr_proposal->state);
+ printf("\t\trouter lifetime: %10u\n",
+ cei_dfr_proposal->router_lifetime);
+ printf("\t\tPreference: %s\n", cei_dfr_proposal->rpref);
+ if (clock_gettime(CLOCK_MONOTONIC, &now))
+ err(1, "clock_gettime");
+
+ timespecsub(&now, &cei_dfr_proposal->uptime, &diff);
+
+ t = localtime(&cei_dfr_proposal->when.tv_sec);
+ strftime(whenbuf, sizeof(whenbuf), "%F %T", t);
+ printf("\t\tupdated: %s.%09ld; %lld.%09lds ago\n",
+ whenbuf, cei_dfr_proposal->when.tv_nsec, diff.tv_sec,
+ diff.tv_nsec);
+
+ break;
case IMSG_CTL_END:
printf("\n");
return (1);
diff --git a/usr.sbin/slaacd/engine.c b/usr.sbin/slaacd/engine.c
index 71a79482c77..04d9e3d0262 100644
--- a/usr.sbin/slaacd/engine.c
+++ b/usr.sbin/slaacd/engine.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: engine.c,v 1.18 2017/05/27 18:37:09 florian Exp $ */
+/* $OpenBSD: engine.c,v 1.19 2017/05/28 09:35:56 florian Exp $ */
/*
* Copyright (c) 2017 Florian Obser <florian@openbsd.org>
@@ -181,6 +181,21 @@ struct address_proposal {
uint32_t pltime;
};
+struct dfr_proposal {
+ LIST_ENTRY(dfr_proposal) entries;
+ struct event timer;
+ int64_t id;
+ enum proposal_state state;
+ int next_timeout;
+ int timeout_count;
+ struct timespec when;
+ struct timespec uptime;
+ uint32_t if_index;
+ struct sockaddr_in6 addr;
+ uint32_t router_lifetime;
+ enum rpref rpref;
+};
+
struct slaacd_iface {
LIST_ENTRY(slaacd_iface) entries;
enum if_state state;
@@ -193,6 +208,7 @@ struct slaacd_iface {
struct sockaddr_in6 ll_address;
LIST_HEAD(, radv) radvs;
LIST_HEAD(, address_proposal) addr_proposals;
+ LIST_HEAD(, dfr_proposal) dfr_proposals;
};
LIST_HEAD(, slaacd_iface) slaacd_interfaces;
@@ -214,12 +230,17 @@ void gen_address_proposal(struct slaacd_iface *, struct
void configure_address(struct slaacd_iface *, struct
address_proposal *);
void in6_prefixlen2mask(struct in6_addr *, int len);
+void gen_dfr_proposal(struct slaacd_iface *, struct
+ radv *);
+void configure_dfr(struct slaacd_iface *, struct
+ dfr_proposal *);
void debug_log_ra(struct imsg_ra *);
char *parse_dnssl(char *, int);
void update_iface_ra(struct slaacd_iface *, struct radv *);
void send_proposal(struct imsg_proposal *);
void start_probe(struct slaacd_iface *);
void address_proposal_timeout(int, short, void *);
+void dfr_proposal_timeout(int, short, void *);
void ra_timeout(int, short, void *);
void iface_timeout(int, short, void *);
struct radv *find_ra(struct slaacd_iface *, struct sockaddr_in6 *);
@@ -227,6 +248,8 @@ struct address_proposal *find_address_proposal_by_id(struct slaacd_iface *,
int64_t);
struct address_proposal *find_address_proposal_by_addr(struct slaacd_iface *,
struct sockaddr_in6 *);
+struct dfr_proposal *find_dfr_proposal_by_id(struct slaacd_iface *,
+ int64_t);
void find_prefix(struct slaacd_iface *, struct
address_proposal *, struct radv **, struct
radv_prefix **);
@@ -355,7 +378,8 @@ engine_dispatch_frontend(int fd, short event, void *bula)
struct imsg_ra ra;
struct imsg_ifinfo imsg_ifinfo;
struct imsg_proposal_ack proposal_ack;
- struct address_proposal *addr_proposal;
+ struct address_proposal *addr_proposal = NULL;
+ struct dfr_proposal *dfr_proposal = NULL;
struct imsg_del_addr del_addr;
ssize_t n;
int shut = 0, verbose;
@@ -437,6 +461,7 @@ engine_dispatch_frontend(int fd, short event, void *bula)
LIST_INSERT_HEAD(&slaacd_interfaces,
iface, entries);
LIST_INIT(&iface->addr_proposals);
+ LIST_INIT(&iface->dfr_proposals);
} else {
DEBUG_IMSG("%s: updating %d", __func__,
imsg_ifinfo.if_index);
@@ -517,12 +542,18 @@ engine_dispatch_frontend(int fd, short event, void *bula)
addr_proposal = find_address_proposal_by_id(iface,
proposal_ack.id);
if (addr_proposal == NULL) {
- log_debug("IMSG_PROPOSAL_ACK: cannot find "
- "proposal, ignoring");
- break;
+ dfr_proposal = find_dfr_proposal_by_id(iface,
+ proposal_ack.id);
+ if (dfr_proposal == NULL) {
+ log_debug("IMSG_PROPOSAL_ACK: cannot "
+ "find proposal, ignoring");
+ break;
+ }
}
-
- configure_address(iface, addr_proposal);
+ if (addr_proposal != NULL)
+ configure_address(iface, addr_proposal);
+ else if (dfr_proposal != NULL)
+ configure_dfr(iface, dfr_proposal);
break;
case IMSG_DEL_ADDRESS:
@@ -656,11 +687,13 @@ send_interface_info(struct slaacd_iface *iface, pid_t pid)
struct ctl_engine_info_ra_rdns cei_ra_rdns;
struct ctl_engine_info_ra_dnssl cei_ra_dnssl;
struct ctl_engine_info_address_proposal cei_addr_proposal;
+ struct ctl_engine_info_dfr_proposal cei_dfr_proposal;
struct radv *ra;
struct radv_prefix *prefix;
struct radv_rdns *rdns;
struct radv_dnssl *dnssl;
struct address_proposal *addr_proposal;
+ struct dfr_proposal *dfr_proposal;
memset(&cei, 0, sizeof(cei));
cei.if_index = iface->if_index;
@@ -752,6 +785,36 @@ send_interface_info(struct slaacd_iface *iface, pid_t pid)
IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSAL, pid,
&cei_addr_proposal, sizeof(cei_addr_proposal));
}
+
+ if (!LIST_EMPTY(&iface->dfr_proposals))
+ engine_imsg_compose_frontend(
+ IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSALS, pid, NULL, 0);
+
+ LIST_FOREACH(dfr_proposal, &iface->dfr_proposals, entries) {
+ memset(&cei_dfr_proposal, 0, sizeof(cei_dfr_proposal));
+ cei_dfr_proposal.id = dfr_proposal->id;
+ if(strlcpy(cei_dfr_proposal.state,
+ proposal_state_name[dfr_proposal->state],
+ sizeof(cei_dfr_proposal.state)) >=
+ sizeof(cei_dfr_proposal.state))
+ log_warn("truncated state name");
+ cei_dfr_proposal.next_timeout = dfr_proposal->next_timeout;
+ cei_dfr_proposal.timeout_count = dfr_proposal->timeout_count;
+ cei_dfr_proposal.when = dfr_proposal->when;
+ cei_dfr_proposal.uptime = dfr_proposal->uptime;
+ memcpy(&cei_dfr_proposal.addr, &dfr_proposal->addr, sizeof(
+ cei_dfr_proposal.addr));
+ cei_dfr_proposal.router_lifetime =
+ dfr_proposal->router_lifetime;
+ if(strlcpy(cei_dfr_proposal.rpref,
+ rpref_name[dfr_proposal->rpref],
+ sizeof(cei_dfr_proposal.rpref)) >=
+ sizeof(cei_dfr_proposal.rpref))
+ log_warn("truncated router preference");
+ engine_imsg_compose_frontend(
+ IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL, pid,
+ &cei_dfr_proposal, sizeof(cei_dfr_proposal));
+ }
}
void
@@ -1396,6 +1459,7 @@ void update_iface_ra(struct slaacd_iface *iface, struct radv *ra)
struct radv *old_ra;
struct radv_prefix *prefix;
struct address_proposal *addr_proposal;
+ struct dfr_proposal *dfr_proposal;
int found, found_privacy;
char hbuf[NI_MAXHOST];
@@ -1408,11 +1472,73 @@ void update_iface_ra(struct slaacd_iface *iface, struct radv *ra)
if (ra->router_lifetime == 0) {
/* XXX expire default route */
} else {
+ found = 0;
+ LIST_FOREACH(dfr_proposal, &iface->dfr_proposals, entries) {
+ if (memcmp(&dfr_proposal->addr,
+ &ra->from, sizeof(struct sockaddr_in6)) ==
+ 0) {
+ found = 1;
+ if (real_lifetime(&dfr_proposal->uptime,
+ dfr_proposal->router_lifetime) >=
+ ra->router_lifetime)
+ log_warn("ignoring router advertisement"
+ " that lowers router lifetime");
+ else {
+ dfr_proposal->when = ra->when;
+ dfr_proposal->uptime = ra->uptime;
+ dfr_proposal->router_lifetime =
+ ra->router_lifetime;
+
+ log_debug("%s, dfr state: %s",
+ __func__, proposal_state_name[
+ dfr_proposal->state]);
+
+ switch (dfr_proposal->state) {
+ case PROPOSAL_CONFIGURED:
+ case PROPOSAL_NEARLY_EXPIRED:
+ log_debug("updating dfr");
+ configure_dfr(iface,
+ dfr_proposal);
+ break;
+ default:
+ if (getnameinfo((struct
+ sockaddr *)
+ &dfr_proposal->addr,
+ dfr_proposal->
+ addr.sin6_len, hbuf,
+ sizeof(hbuf), NULL, 0,
+ NI_NUMERICHOST |
+ NI_NUMERICSERV)) {
+ log_warn("cannot get "
+ "proposal IP");
+ strlcpy(hbuf, "uknown",
+ sizeof(hbuf));
+ }
+ log_debug("%s: iface %d: %s",
+ __func__, iface->if_index,
+ hbuf);
+ break;
+ }
+ }
+
+ break;
+ }
+ }
+ if (!found)
+ /* new proposal */
+ gen_dfr_proposal(iface, ra);
+
LIST_FOREACH(prefix, &ra->prefixes, entries) {
found = 0;
found_privacy = 0;
LIST_FOREACH(addr_proposal, &iface->addr_proposals,
entries) {
+ if (prefix->prefix_len ==
+ addr_proposal-> prefix_len &&
+ memcmp(&prefix->prefix,
+ &addr_proposal->prefix,
+ sizeof(struct in6_addr)) != 0)
+ continue;
if (addr_proposal->privacy) {
found_privacy = 1;
@@ -1439,7 +1565,7 @@ void update_iface_ra(struct slaacd_iface *iface, struct radv *ra)
addr_proposal->vltime = prefix->vltime;
addr_proposal->pltime = prefix->pltime;
- log_debug("%s, state: %s", __func__,
+ log_debug("%s, addr state: %s", __func__,
proposal_state_name[addr_proposal->state]);
switch (addr_proposal->state) {
@@ -1560,6 +1686,69 @@ gen_address_proposal(struct slaacd_iface *iface, struct radv *ra, struct
iface->if_index, hbuf, tv.tv_sec);
}
+void
+gen_dfr_proposal(struct slaacd_iface *iface, struct radv *ra)
+{
+ struct dfr_proposal *dfr_proposal;
+ struct timeval tv;
+ char hbuf[NI_MAXHOST];
+
+ if ((dfr_proposal = calloc(1, sizeof(*dfr_proposal))) == NULL)
+ fatal("calloc");
+ evtimer_set(&dfr_proposal->timer, dfr_proposal_timeout,
+ dfr_proposal);
+ dfr_proposal->next_timeout = 1;
+ dfr_proposal->timeout_count = 0;
+ dfr_proposal->state = PROPOSAL_NOT_CONFIGURED;
+ dfr_proposal->when = ra->when;
+ dfr_proposal->uptime = ra->uptime;
+ dfr_proposal->if_index = iface->if_index;
+ memcpy(&dfr_proposal->addr, &ra->from,
+ sizeof(dfr_proposal->addr));
+ dfr_proposal->router_lifetime = ra->router_lifetime;
+ dfr_proposal->rpref = ra->rpref;
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ evtimer_add(&dfr_proposal->timer, &tv);
+
+ LIST_INSERT_HEAD(&iface->dfr_proposals, dfr_proposal, entries);
+
+ if (getnameinfo((struct sockaddr *)&dfr_proposal->addr,
+ dfr_proposal->addr.sin6_len, hbuf, sizeof(hbuf), NULL, 0,
+ NI_NUMERICHOST | NI_NUMERICSERV)) {
+ log_warn("cannot get router IP");
+ strlcpy(hbuf, "uknown", sizeof(hbuf));
+ }
+ log_debug("%s: iface %d: %s: %lld s", __func__,
+ iface->if_index, hbuf, tv.tv_sec);
+}
+
+void
+configure_dfr(struct slaacd_iface *iface, struct dfr_proposal
+ *dfr_proposal)
+{
+ struct imsg_configure_dfr dfr;
+ struct timeval tv;
+
+ dfr_proposal->next_timeout = dfr_proposal->router_lifetime -
+ MAX_RTR_SOLICITATIONS * (RTR_SOLICITATION_INTERVAL + 1);
+
+ tv.tv_sec = dfr_proposal->next_timeout;
+ tv.tv_usec = arc4random_uniform(1000000);
+ evtimer_add(&dfr_proposal->timer, &tv);
+
+ dfr_proposal->state = PROPOSAL_CONFIGURED;
+
+ log_debug("%s: %d", __func__, iface->if_index);
+
+ dfr.if_index = iface->if_index;
+ memcpy(&dfr.addr, &dfr_proposal->addr, sizeof(dfr.addr));
+ dfr.router_lifetime = dfr_proposal->router_lifetime;
+
+ engine_imsg_compose_main(IMSG_CONFIGURE_DFR, 0, &dfr, sizeof(dfr));
+}
+
#if 0
void
update_iface_ra(struct slaacd_iface *iface, struct radv *ra)
@@ -1777,6 +1966,88 @@ address_proposal_timeout(int fd, short events, void *arg)
}
void
+dfr_proposal_timeout(int fd, short events, void *arg)
+{
+ struct dfr_proposal *dfr_proposal;
+ struct imsg_proposal proposal;
+ struct timeval tv;
+ char hbuf[NI_MAXHOST];
+
+ dfr_proposal = (struct dfr_proposal *)arg;
+
+ if (getnameinfo((struct sockaddr *)&dfr_proposal->addr,
+ dfr_proposal->addr.sin6_len, hbuf, sizeof(hbuf), NULL, 0,
+ NI_NUMERICHOST | NI_NUMERICSERV)) {
+ log_warn("cannot get router IP");
+ strlcpy(hbuf, "uknown", sizeof(hbuf));
+ }
+ log_debug("%s: iface %d: %s [%s]", __func__, dfr_proposal->if_index,
+ hbuf, proposal_state_name[dfr_proposal->state]);
+
+ switch (dfr_proposal->state) {
+ case PROPOSAL_NOT_CONFIGURED:
+ case PROPOSAL_SENT:
+ if (dfr_proposal->timeout_count++ < 6) {
+ dfr_proposal->id = ++proposal_id;
+
+ memset(&proposal, 0, sizeof(proposal));
+ proposal.if_index = dfr_proposal->if_index;
+ proposal.pid = getpid();
+ proposal.id = dfr_proposal->id;
+ memcpy(&proposal.addr, &dfr_proposal->addr,
+ sizeof(proposal.addr));
+
+ proposal.rtm_addrs = RTA_GATEWAY;
+
+ dfr_proposal->state = PROPOSAL_SENT;
+
+ send_proposal(&proposal);
+
+ tv.tv_sec = dfr_proposal->next_timeout;
+ tv.tv_usec = arc4random_uniform(1000000);
+ dfr_proposal->next_timeout *= 2;
+ evtimer_add(&dfr_proposal->timer, &tv);
+ log_debug("%s: scheduling new timeout in %llds.%06ld",
+ __func__, tv.tv_sec, tv.tv_usec);
+ } else {
+ log_debug("%s: giving up, no response to proposal",
+ __func__);
+ LIST_REMOVE(dfr_proposal, entries);
+ evtimer_del(&dfr_proposal->timer);
+ free(dfr_proposal);
+ }
+ break;
+ case PROPOSAL_CONFIGURED:
+ log_debug("PROPOSAL_CONFIGURED timeout: id: %lld",
+ dfr_proposal->id);
+
+ dfr_proposal->next_timeout = 1;
+ dfr_proposal->timeout_count = 0;
+ dfr_proposal->state = PROPOSAL_NEARLY_EXPIRED;
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ evtimer_add(&dfr_proposal->timer, &tv);
+
+ break;
+ case PROPOSAL_NEARLY_EXPIRED:
+ engine_imsg_compose_frontend(IMSG_CTL_SEND_SOLICITATION,
+ 0, &dfr_proposal->if_index,
+ sizeof(dfr_proposal->if_index));
+ tv.tv_sec = dfr_proposal->next_timeout;
+ tv.tv_usec = arc4random_uniform(1000000);
+ dfr_proposal->next_timeout *= 2;
+ evtimer_add(&dfr_proposal->timer, &tv);
+ log_debug("%s: scheduling new timeout in %llds.%06ld",
+ __func__, tv.tv_sec, tv.tv_usec);
+ break;
+ default:
+ log_debug("%s: unhandled state: %s", __func__,
+ proposal_state_name[dfr_proposal->state]);
+ }
+}
+
+void
ra_timeout(int fd, short events, void *arg)
{
struct slaacd_iface *iface = (struct slaacd_iface *)arg;
@@ -1857,6 +2128,20 @@ find_address_proposal_by_addr(struct slaacd_iface *iface, struct sockaddr_in6
return (NULL);
}
+struct dfr_proposal*
+find_dfr_proposal_by_id(struct slaacd_iface *iface, int64_t id)
+{
+ struct dfr_proposal *dfr_proposal;
+
+ LIST_FOREACH (dfr_proposal, &iface->dfr_proposals, entries) {
+ if (dfr_proposal->id == id)
+ return (dfr_proposal);
+ }
+
+ return (NULL);
+}
+
+
/* XXX currently unused */
void
find_prefix(struct slaacd_iface *iface, struct address_proposal *addr_proposal,
diff --git a/usr.sbin/slaacd/engine.h b/usr.sbin/slaacd/engine.h
index c7e6023fee6..aa579c3c5b9 100644
--- a/usr.sbin/slaacd/engine.h
+++ b/usr.sbin/slaacd/engine.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: engine.h,v 1.5 2017/05/27 10:47:23 florian Exp $ */
+/* $OpenBSD: engine.h,v 1.6 2017/05/28 09:35:56 florian Exp $ */
/*
* Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
@@ -36,5 +36,11 @@ struct imsg_configure_address {
uint32_t pltime;
};
+struct imsg_configure_dfr {
+ uint32_t if_index;
+ struct sockaddr_in6 addr;
+ uint32_t router_lifetime;
+};
+
void engine(int, int);
int engine_imsg_compose_frontend(int, pid_t, void *, uint16_t);
diff --git a/usr.sbin/slaacd/frontend.c b/usr.sbin/slaacd/frontend.c
index 8853cd1214e..fd68ec8937a 100644
--- a/usr.sbin/slaacd/frontend.c
+++ b/usr.sbin/slaacd/frontend.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: frontend.c,v 1.10 2017/05/27 16:16:49 florian Exp $ */
+/* $OpenBSD: frontend.c,v 1.11 2017/05/28 09:35:56 florian Exp $ */
/*
* Copyright (c) 2017 Florian Obser <florian@openbsd.org>
@@ -431,6 +431,8 @@ frontend_dispatch_engine(int fd, short event, void *bula)
case IMSG_CTL_SHOW_INTERFACE_INFO_RA_DNSSL:
case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSALS:
case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSAL:
+ case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSALS:
+ case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL:
control_imsg_relay(&imsg);
break;
case IMSG_CTL_SEND_SOLICITATION:
diff --git a/usr.sbin/slaacd/slaacd.c b/usr.sbin/slaacd/slaacd.c
index 9ab1fdcd4a2..cba29305e34 100644
--- a/usr.sbin/slaacd/slaacd.c
+++ b/usr.sbin/slaacd/slaacd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: slaacd.c,v 1.14 2017/05/27 16:16:49 florian Exp $ */
+/* $OpenBSD: slaacd.c,v 1.15 2017/05/28 09:35:56 florian Exp $ */
/*
* Copyright (c) 2017 Florian Obser <florian@openbsd.org>
@@ -73,6 +73,9 @@ const char* imsg_type_name[] = {
"IMSG_DEL_ADDRESS",
"IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSAL",
"IMSG_FAKE_ACK",
+ "IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSALS",
+ "IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL",
+ "IMSG_CONFIGURE_DFR",
};
__dead void usage(void);
@@ -86,6 +89,7 @@ void main_dispatch_frontend(int, short, void *);
void main_dispatch_engine(int, short, void *);
void handle_proposal(struct imsg_proposal *);
void configure_interface(struct imsg_configure_address *);
+void configure_gateway(struct imsg_configure_dfr *);
static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *);
@@ -101,6 +105,8 @@ int routesock, ioctl_sock;
char *csock;
+int rtm_seq = 0;
+
void
main_sig_handler(int sig, short event, void *arg)
{
@@ -412,6 +418,7 @@ main_dispatch_engine(int fd, short event, void *bula)
struct imsg imsg;
struct imsg_proposal proposal;
struct imsg_configure_address address;
+ struct imsg_configure_dfr dfr;
ssize_t n;
int shut = 0;
@@ -451,6 +458,13 @@ main_dispatch_engine(int fd, short event, void *bula)
memcpy(&address, imsg.data, sizeof(address));
configure_interface(&address);
break;
+ case IMSG_CONFIGURE_DFR:
+ if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(dfr))
+ fatal("%s: IMSG_CONFIGURE_DFR wrong "
+ "length: %d", __func__, imsg.hdr.len);
+ memcpy(&dfr, imsg.data, sizeof(dfr));
+ configure_gateway(&dfr);
+ break;
default:
log_debug("%s: error handling imsg %d", __func__,
imsg.hdr.type);
@@ -539,7 +553,6 @@ main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf,
void
handle_proposal(struct imsg_proposal *proposal)
{
- static int seq = 0;
struct rt_msghdr rtm;
struct sockaddr_in6 ifa, mask;
struct sockaddr_rtlabel rl;
@@ -554,7 +567,7 @@ handle_proposal(struct imsg_proposal *proposal)
rtm.rtm_msglen = sizeof(rtm);
rtm.rtm_tableid = 0; /* XXX imsg->rdomain; */
rtm.rtm_index = proposal->if_index;
- rtm.rtm_seq = ++seq;
+ rtm.rtm_seq = ++rtm_seq;
rtm.rtm_priority = RTP_PROPOSAL_SLAAC;
rtm.rtm_addrs = (proposal->rtm_addrs & (RTA_NETMASK | RTA_IFA)) |
RTA_LABEL;
@@ -660,6 +673,74 @@ configure_interface(struct imsg_configure_address *address)
fatal("SIOCAIFADDR_IN6");
}
+void
+configure_gateway(struct imsg_configure_dfr *dfr)
+{
+ struct rt_msghdr rtm;
+ struct sockaddr_in6 dst, gw, mask;
+ struct iovec iov[8];
+ long pad = 0;
+ int iovcnt = 0, padlen;
+
+ memset(&rtm, 0, sizeof(rtm));
+
+ rtm.rtm_version = RTM_VERSION;
+ rtm.rtm_type = RTM_ADD;
+ rtm.rtm_msglen = sizeof(rtm);
+ rtm.rtm_tableid = 0; /* XXX imsg->rdomain; */
+ rtm.rtm_index = dfr->if_index;
+ rtm.rtm_seq = ++rtm_seq;
+ rtm.rtm_priority = RTP_BGP;
+ rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
+ rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
+
+ iov[iovcnt].iov_base = &rtm;
+ iov[iovcnt++].iov_len = sizeof(rtm);
+
+ memset(&dst, 0, sizeof(mask));
+ dst.sin6_family = AF_INET6;
+ dst.sin6_len = sizeof(struct sockaddr_in6);
+
+ iov[iovcnt].iov_base = &dst;
+ iov[iovcnt++].iov_len = sizeof(dst);
+ rtm.rtm_msglen += sizeof(dst);
+ padlen = ROUNDUP(sizeof(dst)) - sizeof(dst);
+ if (padlen > 0) {
+ iov[iovcnt].iov_base = &pad;
+ iov[iovcnt++].iov_len = padlen;
+ rtm.rtm_msglen += padlen;
+ }
+
+ memcpy(&gw, &dfr->addr, sizeof(gw));
+ *(u_int16_t *)& gw.sin6_addr.s6_addr[2] = htons(gw.sin6_scope_id);
+ /* gw.sin6_scope_id = 0; XXX route(8) does this*/
+ iov[iovcnt].iov_base = &gw;
+ iov[iovcnt++].iov_len = sizeof(gw);
+ rtm.rtm_msglen += sizeof(gw);
+ padlen = ROUNDUP(sizeof(gw)) - sizeof(gw);
+ if (padlen > 0) {
+ iov[iovcnt].iov_base = &pad;
+ iov[iovcnt++].iov_len = padlen;
+ rtm.rtm_msglen += padlen;
+ }
+
+ memset(&mask, 0, sizeof(mask));
+ mask.sin6_family = AF_INET6;
+ mask.sin6_len = 0;//sizeof(struct sockaddr_in6);
+ iov[iovcnt].iov_base = &mask;
+ iov[iovcnt++].iov_len = sizeof(mask);
+ rtm.rtm_msglen += sizeof(mask);
+ padlen = ROUNDUP(sizeof(mask)) - sizeof(mask);
+ if (padlen > 0) {
+ iov[iovcnt].iov_base = &pad;
+ iov[iovcnt++].iov_len = padlen;
+ rtm.rtm_msglen += padlen;
+ }
+
+ if (writev(routesock, iov, iovcnt) == -1)
+ log_warn("failed to send RTM_ADD");
+}
+
#if 0
void
handle_proposal(struct imsg_proposal *proposal)
diff --git a/usr.sbin/slaacd/slaacd.h b/usr.sbin/slaacd/slaacd.h
index b952a09bc45..4d3c21a9de4 100644
--- a/usr.sbin/slaacd/slaacd.h
+++ b/usr.sbin/slaacd/slaacd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: slaacd.h,v 1.14 2017/05/27 18:38:07 florian Exp $ */
+/* $OpenBSD: slaacd.h,v 1.15 2017/05/28 09:35:56 florian Exp $ */
/*
* Copyright (c) 2017 Florian Obser <florian@openbsd.org>
@@ -70,6 +70,9 @@ enum imsg_type {
IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSALS,
IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSAL,
IMSG_FAKE_ACK,
+ IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSALS,
+ IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL,
+ IMSG_CONFIGURE_DFR,
};
extern const char* imsg_type_name[];
@@ -141,6 +144,17 @@ struct ctl_engine_info_address_proposal {
uint32_t pltime;
};
+struct ctl_engine_info_dfr_proposal {
+ int64_t id;
+ char state[sizeof("PROPOSAL_NEARLY_EXPIRED")];
+ int next_timeout;
+ int timeout_count;
+ struct timespec when;
+ struct timespec uptime;
+ struct sockaddr_in6 addr;
+ uint32_t router_lifetime;
+ char rpref[sizeof("MEDIUM")];
+};
struct imsg_ifinfo {
uint32_t if_index;