summaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
authorTobias Heider <tobhe@cvs.openbsd.org>2021-09-01 15:30:07 +0000
committerTobias Heider <tobhe@cvs.openbsd.org>2021-09-01 15:30:07 +0000
commit6f1cf91bc43eb666cda40d8b10a29ad5593b6420 (patch)
tree1cf3abef881111744388754718ef067264c98dfb /sbin
parent1c09d776bff82d707544477525b40f900a258c6d (diff)
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@
Diffstat (limited to 'sbin')
-rw-r--r--sbin/iked/config.c3
-rw-r--r--sbin/iked/iked.c5
-rw-r--r--sbin/iked/iked.h7
-rw-r--r--sbin/iked/ikev2.c11
-rw-r--r--sbin/iked/ikev2_msg.c4
-rw-r--r--sbin/iked/ikev2_pld.c65
-rw-r--r--sbin/iked/policy.c9
-rw-r--r--sbin/iked/types.h4
-rw-r--r--sbin/iked/vroute.c245
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 <tobias.heider@stusta.de>
@@ -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 <tobias.heider@stusta.de>
@@ -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 <tobias.heider@stusta.de>
@@ -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 <tobias.heider@stusta.de>
@@ -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 <tobias.heider@stusta.de>
@@ -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 <tobias.heider@stusta.de>
@@ -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 <tobhe@openbsd.org>
@@ -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 <tobias.heider@stusta.de>
@@ -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 <tobhe@openbsd.org>
@@ -35,6 +35,7 @@
#include <iked.h>
+#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 {
@@ -87,9 +99,57 @@ 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)
@@ -285,6 +418,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)
{
@@ -528,6 +690,73 @@ vroute_getcloneroute(struct iked *env, struct imsg *imsg)
}
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)
{