From 9ef39cf4356d5d4cc171237b25a0461edfb93c4b Mon Sep 17 00:00:00 2001 From: tobhe Date: Wed, 1 Sep 2021 15:30:06 +0000 Subject: [PATCH] Add client side support for DNS configuration. Use RTM_PROPOSAL_STATIC route messages to propose the name server to resolvd(8). For now, iked will only propose a single name server from the first established connection. Automatic name server configuration is enabled by default for policies using the 'iface' option. discussed with deraadt@ ok for the DNS parts florian@ ok for the rest patrick@ --- sbin/iked/config.c | 3 +- sbin/iked/iked.c | 5 +- sbin/iked/iked.h | 7 +- sbin/iked/ikev2.c | 11 +- sbin/iked/ikev2_msg.c | 4 +- sbin/iked/ikev2_pld.c | 65 +++++++++-- sbin/iked/policy.c | 9 +- sbin/iked/types.h | 4 +- sbin/iked/vroute.c | 245 ++++++++++++++++++++++++++++++++++++++++-- 9 files changed, 328 insertions(+), 25 deletions(-) diff --git a/sbin/iked/config.c b/sbin/iked/config.c index 60f6443d3e2..029ee2b5813 100644 --- a/sbin/iked/config.c +++ b/sbin/iked/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.79 2021/05/13 15:20:48 tobhe Exp $ */ +/* $OpenBSD: config.c,v 1.80 2021/09/01 15:30:06 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider @@ -174,6 +174,7 @@ config_free_sa(struct iked *env, struct iked_sa *sa) free(sa->sa_cp_addr); free(sa->sa_cp_addr6); + free(sa->sa_cp_dns); free(sa->sa_tag); free(sa); diff --git a/sbin/iked/iked.c b/sbin/iked/iked.c index 777a2281498..4cd1320822d 100644 --- a/sbin/iked/iked.c +++ b/sbin/iked/iked.c @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.c,v 1.57 2021/05/13 15:20:48 tobhe Exp $ */ +/* $OpenBSD: iked.c,v 1.58 2021/09/01 15:30:06 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider @@ -459,6 +459,9 @@ parent_dispatch_ikev2(int fd, struct privsep_proc *p, struct imsg *imsg) case IMSG_IF_ADDADDR: case IMSG_IF_DELADDR: return (vroute_getaddr(env, imsg)); + case IMSG_VDNS_ADD: + case IMSG_VDNS_DEL: + return (vroute_getdns(env, imsg)); case IMSG_VROUTE_ADD: case IMSG_VROUTE_DEL: return (vroute_getroute(env, imsg)); diff --git a/sbin/iked/iked.h b/sbin/iked/iked.h index e9aa4541c31..02d23634ec1 100644 --- a/sbin/iked/iked.h +++ b/sbin/iked/iked.h @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.h,v 1.192 2021/06/23 12:11:40 tobhe Exp $ */ +/* $OpenBSD: iked.h,v 1.193 2021/09/01 15:30:06 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider @@ -429,6 +429,7 @@ struct iked_sa { int sa_cp; /* XXX */ struct iked_addr *sa_cp_addr; /* requested address */ struct iked_addr *sa_cp_addr6; /* requested address */ + struct iked_addr *sa_cp_dns; /* requested dns */ struct iked_policy *sa_policy; struct timeval sa_timecreated; @@ -611,6 +612,7 @@ struct iked_message { int msg_cp; struct iked_addr *msg_cp_addr; /* requested address */ struct iked_addr *msg_cp_addr6; /* requested address */ + struct iked_addr *msg_cp_dns; /* requested dns */ /* MOBIKE */ int msg_update_sa_addresses; @@ -752,6 +754,7 @@ struct iked { int sc_pfkey; /* ike process */ struct event sc_pfkeyev; + struct event sc_routeev; uint8_t sc_certreqtype; struct ibuf *sc_certreq; void *sc_vroute; @@ -975,6 +978,8 @@ void vroute_init(struct iked *); int vroute_setaddr(struct iked *, int, struct sockaddr *, int, unsigned int); void vroute_cleanup(struct iked *); int vroute_getaddr(struct iked *, struct imsg *); +int vroute_setdns(struct iked *, int, struct sockaddr *, unsigned int); +int vroute_getdns(struct iked *, struct imsg *); int vroute_setaddroute(struct iked *, uint8_t, struct sockaddr *, uint8_t, struct sockaddr *); int vroute_setcloneroute(struct iked *, uint8_t, struct sockaddr *, diff --git a/sbin/iked/ikev2.c b/sbin/iked/ikev2.c index c941351e9c5..5cbe1c4a935 100644 --- a/sbin/iked/ikev2.c +++ b/sbin/iked/ikev2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2.c,v 1.325 2021/06/29 15:39:20 tobhe Exp $ */ +/* $OpenBSD: ikev2.c,v 1.326 2021/09/01 15:30:06 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider @@ -998,6 +998,13 @@ ikev2_ike_auth_recv(struct iked *env, struct iked_sa *sa, log_info("%s: obtained lease: %s", SPI_SA(sa, __func__), print_host((struct sockaddr *)&sa->sa_cp_addr6->addr, NULL, 0)); } + if (msg->msg_cp_dns) { + sa->sa_cp_dns = msg->msg_cp_dns; + msg->msg_cp_dns = NULL; + log_debug("%s: DNS: %s", __func__, + print_host((struct sockaddr *)&sa->sa_cp_dns->addr, + NULL, 0)); + } sa->sa_cp = msg->msg_cp; } @@ -4508,6 +4515,8 @@ ikev2_ikesa_enable(struct iked *env, struct iked_sa *sa, struct iked_sa *nsa) sa->sa_cp_addr = NULL; nsa->sa_cp_addr6 = sa->sa_cp_addr6; sa->sa_cp_addr6 = NULL; + nsa->sa_cp_dns = sa->sa_cp_dns; + sa->sa_cp_dns = NULL; /* Transfer other attributes */ if (sa->sa_dstid_entry_valid) { sa_dstid_remove(env, sa); diff --git a/sbin/iked/ikev2_msg.c b/sbin/iked/ikev2_msg.c index ad633a7b347..32b7399de01 100644 --- a/sbin/iked/ikev2_msg.c +++ b/sbin/iked/ikev2_msg.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2_msg.c,v 1.77 2020/10/29 21:49:58 tobhe Exp $ */ +/* $OpenBSD: ikev2_msg.c,v 1.78 2021/09/01 15:30:06 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider @@ -197,6 +197,7 @@ ikev2_msg_cleanup(struct iked *env, struct iked_message *msg) free(msg->msg_eap.eam_user); free(msg->msg_cp_addr); free(msg->msg_cp_addr6); + free(msg->msg_cp_dns); msg->msg_nonce = NULL; msg->msg_ke = NULL; @@ -209,6 +210,7 @@ ikev2_msg_cleanup(struct iked *env, struct iked_message *msg) msg->msg_eap.eam_user = NULL; msg->msg_cp_addr = NULL; msg->msg_cp_addr6 = NULL; + msg->msg_cp_dns = NULL; config_free_proposals(&msg->msg_proposals, 0); while ((cr = SIMPLEQ_FIRST(&msg->msg_certreqs))) { diff --git a/sbin/iked/ikev2_pld.c b/sbin/iked/ikev2_pld.c index 026d245b172..d1a8fee33f5 100644 --- a/sbin/iked/ikev2_pld.c +++ b/sbin/iked/ikev2_pld.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2_pld.c,v 1.117 2021/02/19 21:52:53 tobhe Exp $ */ +/* $OpenBSD: ikev2_pld.c,v 1.118 2021/09/01 15:30:06 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider @@ -1842,6 +1842,7 @@ ikev2_pld_cp(struct iked *env, struct ikev2_payload *pld, uint8_t *ptr; size_t len; uint8_t buf[128]; + int cfg_type; if (ikev2_validate_cp(msg, offset, left, &cp)) return (-1); @@ -1878,8 +1879,10 @@ ikev2_pld_cp(struct iked *env, struct ikev2_payload *pld, print_hex(ptr, sizeof(*cfg), betoh16(cfg->cfg_length)); - switch (betoh16(cfg->cfg_type)) { + cfg_type = betoh16(cfg->cfg_type); + switch (cfg_type) { case IKEV2_CFG_INTERNAL_IP4_ADDRESS: + case IKEV2_CFG_INTERNAL_IP4_DNS: if (!ikev2_msg_frompeer(msg)) break; if (betoh16(cfg->cfg_length) == 0) @@ -1891,8 +1894,20 @@ ikev2_pld_cp(struct iked *env, struct ikev2_payload *pld, __func__, betoh16(cfg->cfg_length), 4); return (-1); } - if (msg->msg_parent->msg_cp_addr != NULL) { - log_debug("%s: address already set", __func__); + switch(cfg_type) { + case IKEV2_CFG_INTERNAL_IP4_ADDRESS: + if (msg->msg_parent->msg_cp_addr != NULL) { + log_debug("%s: address already set", __func__); + goto skip; + } + break; + case IKEV2_CFG_INTERNAL_IP4_DNS: + if (msg->msg_parent->msg_cp_dns != NULL) { + log_debug("%s: dns already set", __func__); + goto skip; + } + break; + default: break; } if ((addr = calloc(1, sizeof(*addr))) == NULL) { @@ -1907,22 +1922,42 @@ ikev2_pld_cp(struct iked *env, struct ikev2_payload *pld, print_host((struct sockaddr *)in4, (char *)buf, sizeof(buf)); log_debug("%s: cfg %s", __func__, buf); - msg->msg_parent->msg_cp_addr = addr; + switch(cfg_type) { + case IKEV2_CFG_INTERNAL_IP4_ADDRESS: + msg->msg_parent->msg_cp_addr = addr; + log_debug("%s: IP4_ADDRESS %s", __func__, buf); + break; + case IKEV2_CFG_INTERNAL_IP4_DNS: + msg->msg_parent->msg_cp_dns = addr; + log_debug("%s: IP4_DNS %s", __func__, buf); + break; + } break; case IKEV2_CFG_INTERNAL_IP6_ADDRESS: + case IKEV2_CFG_INTERNAL_IP6_DNS: if (!ikev2_msg_frompeer(msg)) break; if (betoh16(cfg->cfg_length) == 0) break; /* XXX multiple-valued */ - if (betoh16(cfg->cfg_length) < 16 + 1) { + if (betoh16(cfg->cfg_length) < 16) { log_debug("%s: malformed payload: too short " "for ipv6 addr w/prefixlen (%u < %u)", - __func__, betoh16(cfg->cfg_length), 16 + 1); + __func__, betoh16(cfg->cfg_length), 16); return (-1); } - if (msg->msg_parent->msg_cp_addr6 != NULL) { - log_debug("%s: address already set", __func__); + switch(cfg_type) { + case IKEV2_CFG_INTERNAL_IP6_ADDRESS: + if (msg->msg_parent->msg_cp_addr6 != NULL) { + log_debug("%s: address6 already set", __func__); + goto skip; + } + break; + case IKEV2_CFG_INTERNAL_IP6_DNS: + if (msg->msg_parent->msg_cp_dns != NULL) { + log_debug("%s: dns already set", __func__); + goto skip; + } break; } if ((addr = calloc(1, sizeof(*addr))) == NULL) { @@ -1937,10 +1972,20 @@ ikev2_pld_cp(struct iked *env, struct ikev2_payload *pld, print_host((struct sockaddr *)in6, (char *)buf, sizeof(buf)); log_debug("%s: cfg %s/%d", __func__, buf, ptr[16]); - msg->msg_parent->msg_cp_addr6 = addr; + switch(cfg_type) { + case IKEV2_CFG_INTERNAL_IP6_ADDRESS: + msg->msg_parent->msg_cp_addr6 = addr; + log_debug("%s: IP6_ADDRESS %s", __func__, buf); + break; + case IKEV2_CFG_INTERNAL_IP6_DNS: + msg->msg_parent->msg_cp_dns = addr; + log_debug("%s: IP6_DNS %s", __func__, buf); + break; + } break; } + skip: ptr += betoh16(cfg->cfg_length); len -= betoh16(cfg->cfg_length); } diff --git a/sbin/iked/policy.c b/sbin/iked/policy.c index 57077c46461..51763014923 100644 --- a/sbin/iked/policy.c +++ b/sbin/iked/policy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: policy.c,v 1.82 2021/06/23 12:11:40 tobhe Exp $ */ +/* $OpenBSD: policy.c,v 1.83 2021/09/01 15:30:06 tobhe Exp $ */ /* * Copyright (c) 2020-2021 Tobias Heider @@ -680,6 +680,13 @@ sa_configure_iface(struct iked *env, struct iked_sa *sa, int add) if (sa->sa_policy == NULL || sa->sa_policy->pol_iface == 0) return (0); + if (sa->sa_cp_dns) { + if (vroute_setdns(env, add, + (struct sockaddr *)&sa->sa_cp_dns->addr, + sa->sa_policy->pol_iface) != 0) + return (-1); + } + if (!sa->sa_cp_addr && !sa->sa_cp_addr6) return (0); diff --git a/sbin/iked/types.h b/sbin/iked/types.h index b16d04c1ab6..18f83044b82 100644 --- a/sbin/iked/types.h +++ b/sbin/iked/types.h @@ -1,4 +1,4 @@ -/* $OpenBSD: types.h,v 1.44 2021/08/03 12:46:30 tobhe Exp $ */ +/* $OpenBSD: types.h,v 1.45 2021/09/01 15:30:06 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider @@ -119,6 +119,8 @@ enum imsg_type { IMSG_VROUTE_ADD, IMSG_VROUTE_DEL, IMSG_VROUTE_CLONE, + IMSG_VDNS_ADD, + IMSG_VDNS_DEL, IMSG_OCSP_FD, IMSG_OCSP_CFG, IMSG_AUTH, diff --git a/sbin/iked/vroute.c b/sbin/iked/vroute.c index 3934cf70eb7..b893da81315 100644 --- a/sbin/iked/vroute.c +++ b/sbin/iked/vroute.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vroute.c,v 1.12 2021/06/23 12:21:23 tobhe Exp $ */ +/* $OpenBSD: vroute.c,v 1.13 2021/09/01 15:30:06 tobhe Exp $ */ /* * Copyright (c) 2021 Tobias Heider @@ -35,6 +35,7 @@ #include +#define ROUTE_SOCKET_BUF_SIZE 16384 #define IKED_VROUTE_PRIO 6 #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) @@ -44,10 +45,14 @@ int vroute_setroute(struct iked *, uint8_t, struct sockaddr *, uint8_t, int vroute_doroute(struct iked *, int, int, int, uint8_t, struct sockaddr *, struct sockaddr *, struct sockaddr *, int *); int vroute_doaddr(struct iked *, char *, struct sockaddr *, struct sockaddr *, int); +int vroute_dodns(struct iked *, struct sockaddr *, int, unsigned int); void vroute_cleanup(struct iked *); +void vroute_rtmsg_cb(int, short, void *); void vroute_insertaddr(struct iked *, int, struct sockaddr *, struct sockaddr *); void vroute_removeaddr(struct iked *, int, struct sockaddr *, struct sockaddr *); +void vroute_insertdns(struct iked *, int, struct sockaddr *); +void vroute_removedns(struct iked *, int, struct sockaddr *); void vroute_insertroute(struct iked *, int, struct sockaddr *, struct sockaddr *); void vroute_removeroute(struct iked *, int, struct sockaddr *, struct sockaddr *); @@ -68,14 +73,21 @@ struct vroute_route { }; TAILQ_HEAD(vroute_routes, vroute_route); +struct vroute_dns { + struct sockaddr_storage vd_addr; + int vd_ifidx; +}; + struct iked_vroute_sc { - struct vroute_addrs ivr_addrs; - struct vroute_routes ivr_routes; - int ivr_iosock; - int ivr_iosock6; - int ivr_rtsock; - int ivr_rtseq; - pid_t ivr_pid; + struct vroute_addrs ivr_addrs; + struct vroute_routes ivr_routes; + struct vroute_dns *ivr_dns; + struct event ivr_routeev; + int ivr_iosock; + int ivr_iosock6; + int ivr_rtsock; + int ivr_rtseq; + pid_t ivr_pid; }; struct vroute_msg { @@ -86,10 +98,58 @@ struct vroute_msg { int vroute_process(struct iked *, int msglen, struct vroute_msg *, struct sockaddr *, struct sockaddr *, struct sockaddr *, int *); +void +vroute_rtmsg_cb(int fd, short events, void *arg) +{ + struct iked *env = (struct iked *) arg; + struct iked_vroute_sc *ivr = env->sc_vroute; + static uint8_t *buf; + struct rt_msghdr *rtm; + ssize_t n; + + if (buf == NULL) { + buf = malloc(ROUTE_SOCKET_BUF_SIZE); + if (buf == NULL) + fatal("malloc"); + } + rtm = (struct rt_msghdr *)buf; + if ((n = read(fd, buf, ROUTE_SOCKET_BUF_SIZE)) == -1) { + if (errno == EAGAIN || errno == EINTR) + return; + log_warn("%s: read error", __func__); + return; + } + + if (n == 0) + fatal("routing socket closed"); + + if (n < (ssize_t)sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen) { + log_warnx("partial rtm of %zd in buffer", n); + return; + } + + if (rtm->rtm_version != RTM_VERSION) + return; + + switch(rtm->rtm_type) { + case RTM_PROPOSAL: + if (rtm->rtm_priority == RTP_PROPOSAL_SOLICIT) { + log_debug("%s: got solicit", __func__); + vroute_dodns(env, (struct sockaddr *)&ivr->ivr_dns->vd_addr, 1, + ivr->ivr_dns->vd_ifidx); + } + break; + default: + log_debug("%s: unexpected RTM: %d", __func__, rtm->rtm_type); + break; + } +} + void vroute_init(struct iked *env) { struct iked_vroute_sc *ivr; + int rtfilter; ivr = calloc(1, sizeof(*ivr)); if (ivr == NULL) @@ -104,12 +164,21 @@ vroute_init(struct iked *env) if ((ivr->ivr_rtsock = socket(AF_ROUTE, SOCK_RAW, AF_UNSPEC)) == -1) fatal("%s: failed to create routing socket", __func__); + rtfilter = ROUTE_FILTER(RTM_GET) | ROUTE_FILTER(RTM_PROPOSAL); + if (setsockopt(ivr->ivr_rtsock, AF_ROUTE, ROUTE_MSGFILTER, &rtfilter, + sizeof(rtfilter)) == -1) + fatal("%s: setsockopt(ROUTE_MSGFILTER)", __func__); + TAILQ_INIT(&ivr->ivr_addrs); TAILQ_INIT(&ivr->ivr_routes); ivr->ivr_pid = getpid(); env->sc_vroute = ivr; + + event_set(&ivr->ivr_routeev, ivr->ivr_rtsock, EV_READ | EV_PERSIST, + vroute_rtmsg_cb, env); + event_add(&ivr->ivr_routeev, NULL); } void @@ -138,6 +207,12 @@ vroute_cleanup(struct iked *env) TAILQ_REMOVE(&ivr->ivr_routes, route, vr_entry); free(route); } + + if (ivr->ivr_dns) { + vroute_dodns(env, (struct sockaddr *)&ivr->ivr_dns->vd_addr, 0, + ivr->ivr_dns->vd_ifidx); + free(ivr->ivr_dns); + } } int @@ -239,6 +314,64 @@ vroute_getaddr(struct iked *env, struct imsg *imsg) return (vroute_doaddr(env, ifname, addr, mask, add)); } +int +vroute_setdns(struct iked *env, int add, struct sockaddr *addr, + unsigned int ifidx) +{ + struct iovec iov[2]; + + iov[0].iov_base = addr; + iov[0].iov_len = addr->sa_len; + + iov[1].iov_base = &ifidx; + iov[1].iov_len = sizeof(ifidx); + + return (proc_composev(&env->sc_ps, PROC_PARENT, + add ? IMSG_VDNS_ADD: IMSG_VDNS_DEL, iov, 2)); +} + +int +vroute_getdns(struct iked *env, struct imsg *imsg) +{ + struct iked_vroute_sc *ivr = env->sc_vroute; + struct sockaddr *dns; + uint8_t *ptr; + size_t left; + int add; + unsigned int ifidx; + + ptr = imsg->data; + left = IMSG_DATA_SIZE(imsg); + + if (left < sizeof(*dns)) + fatalx("bad length imsg received"); + + dns = (struct sockaddr *) ptr; + if (left < dns->sa_len) + fatalx("bad length imsg received"); + ptr += dns->sa_len; + left -= dns->sa_len; + + if (left != sizeof(ifidx)) + fatalx("bad length imsg received"); + memcpy(&ifidx, ptr, sizeof(ifidx)); + ptr += sizeof(ifidx); + left -= sizeof(ifidx); + + add = (imsg->hdr.type == IMSG_VDNS_ADD); + if (add) { + if (ivr->ivr_dns != NULL) + return (0); + vroute_insertdns(env, ifidx, dns); + } else { + if (ivr->ivr_dns == NULL) + return (0); + vroute_removedns(env, ifidx, dns); + } + + return (vroute_dodns(env, dns, add, ifidx)); +} + void vroute_insertroute(struct iked *env, int rdomain, struct sockaddr *dest, struct sockaddr *mask) @@ -284,6 +417,35 @@ vroute_removeroute(struct iked *env, int rdomain, struct sockaddr *dest, } } +void +vroute_insertdns(struct iked *env, int ifidx, struct sockaddr *addr) +{ + struct iked_vroute_sc *ivr = env->sc_vroute; + struct vroute_dns *dns; + + dns = calloc(1, sizeof(*dns)); + if (dns == NULL) + fatalx("%s: calloc.", __func__); + + memcpy(&dns->vd_addr, addr, addr->sa_len); + dns->vd_ifidx = ifidx; + + ivr->ivr_dns = dns; +} + +void +vroute_removedns(struct iked *env, int ifidx, struct sockaddr *addr) +{ + struct iked_vroute_sc *ivr = env->sc_vroute; + + if (ifidx == ivr->ivr_dns->vd_ifidx && + sockaddr_cmp(addr, (struct sockaddr *) + &ivr->ivr_dns->vd_addr, -1) == 0) { + free(ivr->ivr_dns); + ivr->ivr_dns = NULL; + } +} + void vroute_insertaddr(struct iked *env, int ifidx, struct sockaddr *addr, struct sockaddr *mask) @@ -527,6 +689,73 @@ vroute_getcloneroute(struct iked *env, struct imsg *imsg) (struct sockaddr *)&addr, NULL)); } +int +vroute_dodns(struct iked *env, struct sockaddr *dns, int add, + unsigned int ifidx) +{ + struct vroute_msg m_rtmsg; + struct sockaddr_in *in; + struct sockaddr_in6 *in6; + struct sockaddr_rtdns rtdns; + struct iked_vroute_sc *ivr = env->sc_vroute; + struct iovec iov[3]; + int i; + long pad = 0; + int iovcnt = 0, padlen; + + bzero(&m_rtmsg, sizeof(m_rtmsg)); +#define rtm m_rtmsg.vm_rtm + rtm.rtm_version = RTM_VERSION; + rtm.rtm_type = RTM_PROPOSAL; + rtm.rtm_seq = ++ivr->ivr_rtseq; + rtm.rtm_priority = RTP_PROPOSAL_STATIC; + rtm.rtm_flags = RTF_UP; + rtm.rtm_addrs = RTA_DNS; + rtm.rtm_index = ifidx; + + iov[iovcnt].iov_base = &rtm; + iov[iovcnt].iov_len = sizeof(rtm); + iovcnt++; + + bzero(&rtdns, sizeof(rtdns)); + rtdns.sr_family = dns->sa_family; + rtdns.sr_len = 2; + if (add) { + switch(dns->sa_family) { + case AF_INET: + rtdns.sr_family = AF_INET; + rtdns.sr_len += sizeof(struct in_addr); + in = (struct sockaddr_in *)dns; + memcpy(rtdns.sr_dns, &in->sin_addr, sizeof(struct in_addr)); + break; + case AF_INET6: + rtdns.sr_family = AF_INET6; + rtdns.sr_len += sizeof(struct in6_addr); + in6 = (struct sockaddr_in6 *)dns; + memcpy(rtdns.sr_dns, &in6->sin6_addr, sizeof(struct in6_addr)); + break; + default: + return (-1); + } + } + iov[iovcnt].iov_base = &rtdns; + iov[iovcnt++].iov_len = sizeof(rtdns); + padlen = ROUNDUP(sizeof(rtdns)) - sizeof(rtdns); + if (padlen > 0) { + iov[iovcnt].iov_base = &pad; + iov[iovcnt++].iov_len = padlen; + } + + for (i = 0; i < iovcnt; i++) + rtm.rtm_msglen += iov[i].iov_len; +#undef rtm + + if (writev(ivr->ivr_rtsock, iov, iovcnt) == -1) + log_warn("failed to send route message"); + + return (0); +} + int vroute_doroute(struct iked *env, int flags, int addrs, int rdomain, uint8_t type, struct sockaddr *dest, struct sockaddr *mask, struct sockaddr *addr, int *need_gw) -- 2.20.1