diff options
author | Florian Obser <florian@cvs.openbsd.org> | 2019-11-11 05:48:47 +0000 |
---|---|---|
committer | Florian Obser <florian@cvs.openbsd.org> | 2019-11-11 05:48:47 +0000 |
commit | 9d49f18764934d775742135bf65c8505cea7f804 (patch) | |
tree | 6b6601641f2f3b8f048cb94e4d156584b1252d6b /sbin | |
parent | 83ccde157ddfd67008b61b9372bd41e6ff394f29 (diff) |
Send DNS proposals on route socket when new nameservers are learned
from router advertisements.
unwind(8) can solicit DNS proposals by sending an empty RTM_PROPOSAL
message with priority RTP_PROPOSAL_SOLICIT.
Diffstat (limited to 'sbin')
-rw-r--r-- | sbin/slaacd/engine.c | 333 | ||||
-rw-r--r-- | sbin/slaacd/frontend.c | 13 | ||||
-rw-r--r-- | sbin/slaacd/slaacd.c | 71 | ||||
-rw-r--r-- | sbin/slaacd/slaacd.h | 31 |
4 files changed, 443 insertions, 5 deletions
diff --git a/sbin/slaacd/engine.c b/sbin/slaacd/engine.c index 2fb5271aa98..a8d41e0ce25 100644 --- a/sbin/slaacd/engine.c +++ b/sbin/slaacd/engine.c @@ -1,4 +1,4 @@ -/* $OpenBSD: engine.c,v 1.43 2019/11/08 13:02:32 florian Exp $ */ +/* $OpenBSD: engine.c,v 1.44 2019/11/11 05:48:46 florian Exp $ */ /* * Copyright (c) 2017 Florian Obser <florian@openbsd.org> @@ -104,6 +104,7 @@ const char* if_state_name[] = { enum proposal_state { PROPOSAL_NOT_CONFIGURED, + PROPOSAL_SENT, PROPOSAL_CONFIGURED, PROPOSAL_NEARLY_EXPIRED, PROPOSAL_WITHDRAWN, @@ -113,6 +114,7 @@ enum proposal_state { const char* proposal_state_name[] = { "NOT_CONFIGURED", + "SENT", "CONFIGURED", "NEARLY_EXPIRED", "WITHDRAWN", @@ -206,6 +208,22 @@ struct dfr_proposal { enum rpref rpref; }; +struct rdns_proposal { + LIST_ENTRY(rdns_proposal) entries; + struct event timer; + int64_t id; + enum proposal_state state; + time_t next_timeout; + int timeout_count; + struct timespec when; + struct timespec uptime; + uint32_t if_index; + struct sockaddr_in6 from; + int rdns_count; + struct in6_addr rdns[MAX_RDNS_COUNT]; + uint32_t rdns_lifetime; +}; + struct slaacd_iface { LIST_ENTRY(slaacd_iface) entries; enum if_state state; @@ -223,6 +241,7 @@ struct slaacd_iface { LIST_HEAD(, radv) radvs; LIST_HEAD(, address_proposal) addr_proposals; LIST_HEAD(, dfr_proposal) dfr_proposals; + LIST_HEAD(, rdns_proposal) rdns_proposals; }; LIST_HEAD(, slaacd_iface) slaacd_interfaces; @@ -256,11 +275,23 @@ void gen_dfr_proposal(struct slaacd_iface *, struct void configure_dfr(struct dfr_proposal *); void free_dfr_proposal(struct dfr_proposal *); void withdraw_dfr(struct dfr_proposal *); +#ifndef SMALL +void gen_rdns_proposal(struct slaacd_iface *, struct + radv *); +void propose_rdns(struct rdns_proposal *); +void free_rdns_proposal(struct rdns_proposal *); +void withdraw_rdns(struct rdns_proposal *); +void compose_rdns_proposal(enum imsg_type, + struct rdns_proposal *); +#endif /* SMALL */ char *parse_dnssl(char *, int); void update_iface_ra(struct slaacd_iface *, struct radv *); void start_probe(struct slaacd_iface *); void address_proposal_timeout(int, short, void *); void dfr_proposal_timeout(int, short, void *); +#ifndef SMALL +void rdns_proposal_timeout(int, short, void *); +#endif /* SMALL */ void iface_timeout(int, short, void *); struct radv *find_ra(struct slaacd_iface *, struct sockaddr_in6 *); struct address_proposal *find_address_proposal_by_id(struct slaacd_iface *, @@ -271,6 +302,12 @@ struct dfr_proposal *find_dfr_proposal_by_id(struct slaacd_iface *, int64_t); struct dfr_proposal *find_dfr_proposal_by_gw(struct slaacd_iface *, struct sockaddr_in6 *); +#ifndef SMALL +struct rdns_proposal *find_rdns_proposal_by_id(struct slaacd_iface *, + int64_t); +struct rdns_proposal *find_rdns_proposal_by_gw(struct slaacd_iface *, + struct sockaddr_in6 *); +#endif /* SMALL */ struct radv_prefix *find_prefix(struct radv *, struct radv_prefix *); int engine_imsg_compose_main(int, pid_t, void *, uint16_t); uint32_t real_lifetime(struct timespec *, uint32_t); @@ -398,6 +435,9 @@ engine_dispatch_frontend(int fd, short event, void *bula) struct imsg_ra ra; struct address_proposal *addr_proposal = NULL; struct dfr_proposal *dfr_proposal = NULL; +#ifndef SMALL + struct rdns_proposal *rdns_proposal = NULL; +#endif /* SMALL */ struct imsg_del_addr del_addr; struct imsg_del_route del_route; struct imsg_dup_addr dup_addr; @@ -539,6 +579,17 @@ engine_dispatch_frontend(int fd, short event, void *bula) evtimer_add(&addr_proposal->timer, &tv); } break; +#ifndef SMALL + case IMSG_REPROPOSE_RDNS: + LIST_FOREACH (iface, &slaacd_interfaces, entries) { + LIST_FOREACH (rdns_proposal, + &iface->rdns_proposals, entries) { + compose_rdns_proposal(IMSG_PROPOSE_RDNS, + rdns_proposal); + } + } + break; +#endif /* SMALL */ default: log_debug("%s: unexpected imsg %d", __func__, imsg.hdr.type); @@ -655,6 +706,7 @@ engine_dispatch_main(int fd, short event, void *bula) iface, entries); LIST_INIT(&iface->addr_proposals); LIST_INIT(&iface->dfr_proposals); + LIST_INIT(&iface->rdns_proposals); } else { int need_refresh = 0; @@ -814,12 +866,14 @@ send_interface_info(struct slaacd_iface *iface, pid_t pid) 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 ctl_engine_info_rdns_proposal cei_rdns_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; + struct rdns_proposal *rdns_proposal; memset(&cei, 0, sizeof(cei)); cei.if_index = iface->if_index; @@ -943,6 +997,34 @@ send_interface_info(struct slaacd_iface *iface, pid_t pid) IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL, pid, &cei_dfr_proposal, sizeof(cei_dfr_proposal)); } + + if (!LIST_EMPTY(&iface->rdns_proposals)) + engine_imsg_compose_frontend( + IMSG_CTL_SHOW_INTERFACE_INFO_RDNS_PROPOSALS, pid, NULL, 0); + + LIST_FOREACH(rdns_proposal, &iface->rdns_proposals, entries) { + memset(&cei_rdns_proposal, 0, sizeof(cei_rdns_proposal)); + cei_rdns_proposal.id = rdns_proposal->id; + if(strlcpy(cei_rdns_proposal.state, + proposal_state_name[rdns_proposal->state], + sizeof(cei_rdns_proposal.state)) >= + sizeof(cei_rdns_proposal.state)) + log_warnx("truncated state name"); + cei_rdns_proposal.next_timeout = rdns_proposal->next_timeout; + cei_rdns_proposal.timeout_count = rdns_proposal->timeout_count; + cei_rdns_proposal.when = rdns_proposal->when; + cei_rdns_proposal.uptime = rdns_proposal->uptime; + memcpy(&cei_rdns_proposal.from, &rdns_proposal->from, sizeof( + cei_rdns_proposal.from)); + cei_rdns_proposal.rdns_count = rdns_proposal->rdns_count; + memcpy(&cei_rdns_proposal.rdns, + &rdns_proposal->rdns, sizeof(cei_rdns_proposal.rdns)); + cei_rdns_proposal.rdns_lifetime = + rdns_proposal->rdns_lifetime; + engine_imsg_compose_frontend( + IMSG_CTL_SHOW_INTERFACE_INFO_RDNS_PROPOSAL, pid, + &cei_rdns_proposal, sizeof(cei_rdns_proposal)); + } } void @@ -1001,6 +1083,9 @@ remove_slaacd_iface(uint32_t if_index) struct radv *ra; struct address_proposal *addr_proposal; struct dfr_proposal *dfr_proposal; +#ifndef SMALL + struct rdns_proposal *rdns_proposal; +#endif /* SMALL */ iface = get_slaacd_iface_by_id(if_index); @@ -1022,6 +1107,12 @@ remove_slaacd_iface(uint32_t if_index) dfr_proposal = LIST_FIRST(&iface->dfr_proposals); free_dfr_proposal(dfr_proposal); } +#ifndef SMALL + while(!LIST_EMPTY(&iface->rdns_proposals)) { + rdns_proposal = LIST_FIRST(&iface->rdns_proposals); + free_rdns_proposal(rdns_proposal); + } +#endif /* SMALL */ evtimer_del(&iface->timer); free(iface); } @@ -1640,6 +1731,9 @@ void update_iface_ra(struct slaacd_iface *iface, struct radv *ra) struct radv_prefix *prefix; struct address_proposal *addr_proposal; struct dfr_proposal *dfr_proposal; +#ifndef SMALL + struct rdns_proposal *rdns_proposal; +#endif /* SMALL */ uint32_t remaining_lifetime; int found, found_privacy, duplicate_found; const char *hbuf; @@ -1824,6 +1918,45 @@ void update_iface_ra(struct slaacd_iface *iface, struct radv *ra) 1); } } +#ifndef SMALL + rdns_proposal = find_rdns_proposal_by_gw(iface, &ra->from); + if (rdns_proposal) { + if (real_lifetime(&rdns_proposal->uptime, + rdns_proposal->rdns_lifetime) > + ra->rdns_lifetime) + log_warnx("ignoring router advertisement " + "lowering router lifetime"); + else { + rdns_proposal->when = ra->when; + rdns_proposal->uptime = ra->uptime; + rdns_proposal->rdns_lifetime = + ra->rdns_lifetime; + + log_debug("%s, rdns state: %s, rl: %d", + __func__, proposal_state_name[ + rdns_proposal->state], + real_lifetime(&rdns_proposal->uptime, + rdns_proposal->rdns_lifetime)); + + switch (rdns_proposal->state) { + case PROPOSAL_SENT: + case PROPOSAL_NEARLY_EXPIRED: + log_debug("updating rdns"); + propose_rdns(rdns_proposal); + break; + default: + hbuf = sin6_to_str( + &rdns_proposal->from); + log_debug("%s: iface %d: %s", + __func__, iface->if_index, + hbuf); + break; + } + } + } else + /* new proposal */ + gen_rdns_proposal(iface, ra); +#endif /* SMALL */ } } @@ -2067,6 +2200,115 @@ free_dfr_proposal(struct dfr_proposal *dfr_proposal) free(dfr_proposal); } +#ifndef SMALL +void +gen_rdns_proposal(struct slaacd_iface *iface, struct radv *ra) +{ + struct rdns_proposal *rdns_proposal; + struct radv_rdns *rdns; + const char *hbuf; + + if ((rdns_proposal = calloc(1, sizeof(*rdns_proposal))) == NULL) + fatal("calloc"); + rdns_proposal->id = ++proposal_id; + evtimer_set(&rdns_proposal->timer, rdns_proposal_timeout, + rdns_proposal); + rdns_proposal->next_timeout = 1; + rdns_proposal->timeout_count = 0; + rdns_proposal->state = PROPOSAL_NOT_CONFIGURED; + rdns_proposal->when = ra->when; + rdns_proposal->uptime = ra->uptime; + rdns_proposal->if_index = iface->if_index; + memcpy(&rdns_proposal->from, &ra->from, + sizeof(rdns_proposal->from)); + rdns_proposal->rdns_lifetime = ra->rdns_lifetime; + LIST_FOREACH(rdns, &ra->rdns_servers, entries) { + memcpy(&rdns_proposal->rdns[rdns_proposal->rdns_count++], + &rdns->rdns, sizeof(struct sockaddr_in6)); + if (rdns_proposal->rdns_count == MAX_RDNS_COUNT) + break; + } + + LIST_INSERT_HEAD(&iface->rdns_proposals, rdns_proposal, entries); + propose_rdns(rdns_proposal); + + hbuf = sin6_to_str(&rdns_proposal->from); + log_debug("%s: iface %d: %s", __func__, iface->if_index, hbuf); +} + +void +propose_rdns(struct rdns_proposal *rdns_proposal) +{ + struct timeval tv; + enum proposal_state prev_state; + + if (rdns_proposal->rdns_lifetime > MAX_RTR_SOLICITATIONS * + (RTR_SOLICITATION_INTERVAL + 1)) { + rdns_proposal->next_timeout = rdns_proposal->rdns_lifetime - + MAX_RTR_SOLICITATIONS * (RTR_SOLICITATION_INTERVAL + 1); + tv.tv_sec = rdns_proposal->next_timeout; + tv.tv_usec = arc4random_uniform(1000000); + evtimer_add(&rdns_proposal->timer, &tv); + log_debug("%s: %d, scheduling new timeout in %llds.%06ld", + __func__, rdns_proposal->if_index, tv.tv_sec, tv.tv_usec); + } else + rdns_proposal->next_timeout = 0; + + prev_state = rdns_proposal->state; + + rdns_proposal->state = PROPOSAL_SENT; + + log_debug("%s: %d", __func__, rdns_proposal->if_index); + + if (prev_state == PROPOSAL_SENT || prev_state == + PROPOSAL_NEARLY_EXPIRED) { + /* nothing to do here rDNS proposals do not expire */ + return; + } + compose_rdns_proposal(IMSG_PROPOSE_RDNS, rdns_proposal); +} + +void +withdraw_rdns(struct rdns_proposal *rdns_proposal) +{ + compose_rdns_proposal(IMSG_WITHDRAW_RDNS, rdns_proposal); +} + +void +compose_rdns_proposal(enum imsg_type type, struct rdns_proposal *rdns_proposal) +{ + struct imsg_propose_rdns rdns; + + rdns.if_index = rdns_proposal->if_index; + memcpy(&rdns.from, &rdns_proposal->from, sizeof(rdns.from)); + rdns.rdns_lifetime = rdns_proposal->rdns_lifetime; + rdns.rdns_count = rdns_proposal->rdns_count; + memcpy(&rdns.rdns, &rdns_proposal->rdns, sizeof(rdns.rdns)); + + engine_imsg_compose_main(type, 0, &rdns, sizeof(rdns)); +} + +void +free_rdns_proposal(struct rdns_proposal *rdns_proposal) +{ + if (rdns_proposal == NULL) + return; + + LIST_REMOVE(rdns_proposal, entries); + evtimer_del(&rdns_proposal->timer); + switch (rdns_proposal->state) { + case PROPOSAL_SENT: + case PROPOSAL_NEARLY_EXPIRED: + case PROPOSAL_STALE: + withdraw_rdns(rdns_proposal); + break; + default: + break; + } + free(rdns_proposal); +} +#endif /* SMALL */ + void start_probe(struct slaacd_iface *iface) { @@ -2210,6 +2452,58 @@ dfr_proposal_timeout(int fd, short events, void *arg) } } +#ifndef SMALL +void +rdns_proposal_timeout(int fd, short events, void *arg) +{ + struct rdns_proposal *rdns_proposal; + struct timeval tv; + const char *hbuf; + + rdns_proposal = (struct rdns_proposal *)arg; + + hbuf = sin6_to_str(&rdns_proposal->from); + log_debug("%s: iface %d: %s [%s]", __func__, rdns_proposal->if_index, + hbuf, proposal_state_name[rdns_proposal->state]); + + switch (rdns_proposal->state) { + case PROPOSAL_SENT: + log_debug("PROPOSAL_SENT timeout: id: %lld", + rdns_proposal->id); + + rdns_proposal->next_timeout = 1; + rdns_proposal->timeout_count = 0; + rdns_proposal->state = PROPOSAL_NEARLY_EXPIRED; + + tv.tv_sec = 0; + tv.tv_usec = 0; + evtimer_add(&rdns_proposal->timer, &tv); + + break; + case PROPOSAL_NEARLY_EXPIRED: + if (real_lifetime(&rdns_proposal->uptime, + rdns_proposal->rdns_lifetime) == 0) { + free_rdns_proposal(rdns_proposal); + log_debug("%s: removing rdns proposal", __func__); + break; + } + engine_imsg_compose_frontend(IMSG_CTL_SEND_SOLICITATION, + 0, &rdns_proposal->if_index, + sizeof(rdns_proposal->if_index)); + tv.tv_sec = rdns_proposal->next_timeout; + tv.tv_usec = arc4random_uniform(1000000); + rdns_proposal->next_timeout *= 2; + evtimer_add(&rdns_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[rdns_proposal->state]); + } +} +#endif /* SMALL */ + void iface_timeout(int fd, short events, void *arg) { @@ -2217,6 +2511,7 @@ iface_timeout(int fd, short events, void *arg) struct timeval tv; struct address_proposal *addr_proposal; struct dfr_proposal *dfr_proposal; + struct rdns_proposal *rdns_proposal; log_debug("%s[%d]: %s", __func__, iface->if_index, if_state_name[iface->state]); @@ -2249,6 +2544,14 @@ iface_timeout(int fd, short events, void *arg) dfr_proposal->state = PROPOSAL_STALE; free_dfr_proposal(dfr_proposal); } +#ifndef SMALL + while(!LIST_EMPTY(&iface->rdns_proposals)) { + rdns_proposal = + LIST_FIRST(&iface->rdns_proposals); + rdns_proposal->state = PROPOSAL_STALE; + free_rdns_proposal(rdns_proposal); + } +#endif /* SMALL */ break; case IF_DOWN: case IF_IDLE: @@ -2325,6 +2628,34 @@ find_dfr_proposal_by_gw(struct slaacd_iface *iface, struct sockaddr_in6 return (NULL); } +#ifndef SMALL +struct rdns_proposal* +find_rdns_proposal_by_id(struct slaacd_iface *iface, int64_t id) +{ + struct rdns_proposal *rdns_proposal; + + LIST_FOREACH (rdns_proposal, &iface->rdns_proposals, entries) { + if (rdns_proposal->id == id) + return (rdns_proposal); + } + + return (NULL); +} + +struct rdns_proposal* +find_rdns_proposal_by_gw(struct slaacd_iface *iface, struct sockaddr_in6 + *from) +{ + struct rdns_proposal *rdns_proposal; + + LIST_FOREACH (rdns_proposal, &iface->rdns_proposals, entries) { + if (memcmp(&rdns_proposal->from, from, sizeof(*from)) == 0) + return (rdns_proposal); + } + + return (NULL); +} +#endif /* SMALL */ struct radv_prefix * find_prefix(struct radv *ra, struct radv_prefix *prefix) diff --git a/sbin/slaacd/frontend.c b/sbin/slaacd/frontend.c index 9ff6d62ac44..8c6d48810e9 100644 --- a/sbin/slaacd/frontend.c +++ b/sbin/slaacd/frontend.c @@ -1,4 +1,4 @@ -/* $OpenBSD: frontend.c,v 1.30 2019/11/07 08:45:31 florian Exp $ */ +/* $OpenBSD: frontend.c,v 1.31 2019/11/11 05:48:46 florian Exp $ */ /* * Copyright (c) 2017 Florian Obser <florian@openbsd.org> @@ -425,6 +425,8 @@ frontend_dispatch_engine(int fd, short event, void *bula) case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSAL: case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSALS: case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL: + case IMSG_CTL_SHOW_INTERFACE_INFO_RDNS_PROPOSALS: + case IMSG_CTL_SHOW_INTERFACE_INFO_RDNS_PROPOSAL: control_imsg_relay(&imsg); break; #endif /* SMALL */ @@ -852,6 +854,15 @@ handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info) ifm->ifm_index); break; +#ifndef SMALL + case RTM_PROPOSAL: + if (rtm->rtm_priority == RTP_PROPOSAL_SOLICIT) { + log_debug("RTP_PROPOSAL_SOLICIT"); + frontend_imsg_compose_engine(IMSG_REPROPOSE_RDNS, + 0, 0, NULL, 0); + } + break; +#endif /* SMALL */ default: log_debug("unexpected RTM: %d", rtm->rtm_type); break; diff --git a/sbin/slaacd/slaacd.c b/sbin/slaacd/slaacd.c index 340424e36c0..55e26042874 100644 --- a/sbin/slaacd/slaacd.c +++ b/sbin/slaacd/slaacd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: slaacd.c,v 1.41 2019/11/07 08:45:31 florian Exp $ */ +/* $OpenBSD: slaacd.c,v 1.42 2019/11/11 05:48:46 florian Exp $ */ /* * Copyright (c) 2017 Florian Obser <florian@openbsd.org> @@ -68,6 +68,9 @@ void delete_address(struct imsg_configure_address *); void configure_gateway(struct imsg_configure_dfr *, uint8_t); void add_gateway(struct imsg_configure_dfr *); void delete_gateway(struct imsg_configure_dfr *); +#ifndef SMALL +void send_rdns_proposal(struct imsg_propose_rdns *, uint8_t); +#endif /* SMALL */ int get_soiikey(uint8_t *); static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *); @@ -267,7 +270,7 @@ main(int argc, char *argv[]) rtfilter = ROUTE_FILTER(RTM_IFINFO) | ROUTE_FILTER(RTM_NEWADDR) | ROUTE_FILTER(RTM_DELADDR) | ROUTE_FILTER(RTM_DELETE) | - ROUTE_FILTER(RTM_CHGADDRATTR); + ROUTE_FILTER(RTM_CHGADDRATTR) | ROUTE_FILTER(RTM_PROPOSAL); if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_MSGFILTER, &rtfilter, sizeof(rtfilter)) == -1) fatal("setsockopt(ROUTE_MSGFILTER)"); @@ -477,6 +480,9 @@ main_dispatch_engine(int fd, short event, void *bula) struct imsg imsg; struct imsg_configure_address address; struct imsg_configure_dfr dfr; +#ifndef SMALL + struct imsg_propose_rdns rdns; +#endif /* SMALL */ ssize_t n; int shut = 0; @@ -534,6 +540,24 @@ main_dispatch_engine(int fd, short event, void *bula) memcpy(&dfr, imsg.data, sizeof(dfr)); delete_gateway(&dfr); break; +#ifndef SMALL + case IMSG_PROPOSE_RDNS: + if (IMSG_DATA_SIZE(imsg) != sizeof(rdns)) + fatalx("%s: IMSG_PROPOSE_RDNS wrong " + "length: %lu", __func__, + IMSG_DATA_SIZE(imsg)); + memcpy(&rdns, imsg.data, sizeof(rdns)); + send_rdns_proposal(&rdns, RTF_UP); + break; + case IMSG_WITHDRAW_RDNS: + if (IMSG_DATA_SIZE(imsg) != sizeof(rdns)) + fatalx("%s: IMSG_WITHDRAW_RDNS wrong " + "length: %lu", __func__, + IMSG_DATA_SIZE(imsg)); + memcpy(&rdns, imsg.data, sizeof(rdns)); + send_rdns_proposal(&rdns, 0); + break; +#endif /* SMALL */ default: log_debug("%s: error handling imsg %d", __func__, imsg.hdr.type); @@ -809,6 +833,49 @@ delete_gateway(struct imsg_configure_dfr *dfr) } #ifndef SMALL +void +send_rdns_proposal(struct imsg_propose_rdns *rdns, uint8_t rtm_flags) +{ + struct rt_msghdr rtm; + struct sockaddr_rtdns rtdns; + struct iovec iov[3]; + long pad = 0; + int iovcnt = 0, padlen; + + memset(&rtm, 0, sizeof(rtm)); + + rtm.rtm_version = RTM_VERSION; + rtm.rtm_type = RTM_PROPOSAL; + rtm.rtm_msglen = sizeof(rtm); + rtm.rtm_tableid = 0; /* XXX imsg->rdomain; */ + rtm.rtm_index = rdns->if_index; + rtm.rtm_seq = ++rtm_seq; + rtm.rtm_priority = RTP_PROPOSAL_SLAAC; + rtm.rtm_addrs = RTA_DNS; + rtm.rtm_flags = rtm_flags; + + iov[iovcnt].iov_base = &rtm; + iov[iovcnt++].iov_len = sizeof(rtm); + + memset(&rtdns, 0, sizeof(rtdns)); + rtdns.sr_family = AF_INET6; + rtdns.sr_len = 2 + rdns->rdns_count * sizeof(struct in6_addr); + memcpy(rtdns.sr_dns, rdns->rdns, sizeof(rtdns.sr_dns)); + + iov[iovcnt].iov_base = &rtdns; + iov[iovcnt++].iov_len = sizeof(rtdns); + rtm.rtm_msglen += sizeof(rtdns); + padlen = ROUNDUP(sizeof(rtdns)) - sizeof(rtdns); + 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 route message"); +} + const char* sin6_to_str(struct sockaddr_in6 *sin6) { diff --git a/sbin/slaacd/slaacd.h b/sbin/slaacd/slaacd.h index 9f730cfa39a..3193f1a4f00 100644 --- a/sbin/slaacd/slaacd.h +++ b/sbin/slaacd/slaacd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: slaacd.h,v 1.23 2019/11/07 08:45:31 florian Exp $ */ +/* $OpenBSD: slaacd.h,v 1.24 2019/11/11 05:48:46 florian Exp $ */ /* * Copyright (c) 2017 Florian Obser <florian@openbsd.org> @@ -27,6 +27,8 @@ /* MAXDNAME from arpa/namesr.h */ #define SLAACD_MAX_DNSSL 1025 +#define MAX_RDNS_COUNT 8 /* max nameserver in a RTM_PROPOSAL */ + #define IMSG_DATA_SIZE(imsg) ((imsg).hdr.len - IMSG_HEADER_SIZE) static const char * const log_procnames[] = { @@ -55,9 +57,14 @@ enum imsg_type { IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSAL, IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSALS, IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL, + IMSG_CTL_SHOW_INTERFACE_INFO_RDNS_PROPOSALS, + IMSG_CTL_SHOW_INTERFACE_INFO_RDNS_PROPOSAL, IMSG_CTL_END, IMSG_UPDATE_ADDRESS, IMSG_UPDATE_LINK_STATE, + IMSG_PROPOSE_RDNS, + IMSG_WITHDRAW_RDNS, + IMSG_REPROPOSE_RDNS, #endif /* SMALL */ IMSG_CTL_SEND_SOLICITATION, IMSG_SOCKET_IPC, @@ -160,6 +167,19 @@ struct ctl_engine_info_dfr_proposal { char rpref[sizeof("MEDIUM")]; }; +struct ctl_engine_info_rdns_proposal { + int64_t id; + char state[sizeof("PROPOSAL_NEARLY_EXPIRED")]; + time_t next_timeout; + int timeout_count; + struct timespec when; + struct timespec uptime; + struct sockaddr_in6 from; + uint32_t rdns_lifetime; + int rdns_count; + struct in6_addr rdns[MAX_RDNS_COUNT]; +}; + struct imsg_addrinfo { uint32_t if_index; struct ether_addr hw_address; @@ -175,6 +195,15 @@ struct imsg_link_state { uint32_t if_index; int link_state; }; + +struct imsg_propose_rdns { + uint32_t if_index; + struct sockaddr_in6 from; + uint32_t rdns_lifetime; + int rdns_count; + struct sockaddr_in6 rdns[MAX_RDNS_COUNT]; +}; + #endif /* SMALL */ struct imsg_ifinfo { |