On 2021-09-01 13:28 +02, Tobias Heider <tobias.hei...@stusta.de> wrote: > Here's an updated diff with the following changes: > > - Send the ifidx of the configured 'iface' instead of ifidx 0 to prevent > name collisions > - Cache the first received DNS server locally for cleanup/resending. > - Handle RTP_PROPOSAL_SOLICIT by resending the cached server. > - Remove the cached server from resolvd on cleanup. > > There is no easy way to support multiple DNS servers from different peers > at the moment. For now, iked will always propose the first DNS server it > receives and simply ignore the rest. There is room for improvement here, > but i would rather do this in a follow-up diff. > > ok?
the DNS bits look correct. There seem to be unrelated fixes in here? One comment inline. > > Index: config.c > =================================================================== > RCS file: /cvs/src/sbin/iked/config.c,v > retrieving revision 1.79 > diff -u -p -r1.79 config.c > --- config.c 13 May 2021 15:20:48 -0000 1.79 > +++ config.c 1 Sep 2021 11:26:51 -0000 > @@ -174,6 +174,7 @@ config_free_sa(struct iked *env, struct > > free(sa->sa_cp_addr); > free(sa->sa_cp_addr6); > + free(sa->sa_cp_dns); > > free(sa->sa_tag); > free(sa); > Index: iked.c > =================================================================== > RCS file: /cvs/src/sbin/iked/iked.c,v > retrieving revision 1.57 > diff -u -p -r1.57 iked.c > --- iked.c 13 May 2021 15:20:48 -0000 1.57 > +++ iked.c 1 Sep 2021 11:26:51 -0000 > @@ -459,6 +459,9 @@ parent_dispatch_ikev2(int fd, struct pri > 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)); > Index: iked.h > =================================================================== > RCS file: /cvs/src/sbin/iked/iked.h,v > retrieving revision 1.192 > diff -u -p -r1.192 iked.h > --- iked.h 23 Jun 2021 12:11:40 -0000 1.192 > +++ iked.h 1 Sep 2021 11:26:51 -0000 > @@ -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 *, > Index: ikev2.c > =================================================================== > RCS file: /cvs/src/sbin/iked/ikev2.c,v > retrieving revision 1.325 > diff -u -p -r1.325 ikev2.c > --- ikev2.c 29 Jun 2021 15:39:20 -0000 1.325 > +++ ikev2.c 1 Sep 2021 11:26:51 -0000 > @@ -998,6 +998,13 @@ ikev2_ike_auth_recv(struct iked *env, st > 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, str > 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); > Index: ikev2_msg.c > =================================================================== > RCS file: /cvs/src/sbin/iked/ikev2_msg.c,v > retrieving revision 1.77 > diff -u -p -r1.77 ikev2_msg.c > --- ikev2_msg.c 29 Oct 2020 21:49:58 -0000 1.77 > +++ ikev2_msg.c 1 Sep 2021 11:26:51 -0000 > @@ -197,6 +197,7 @@ ikev2_msg_cleanup(struct iked *env, stru > 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, stru > 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))) { > Index: ikev2_pld.c > =================================================================== > RCS file: /cvs/src/sbin/iked/ikev2_pld.c,v > retrieving revision 1.117 > diff -u -p -r1.117 ikev2_pld.c > --- ikev2_pld.c 19 Feb 2021 21:52:53 -0000 1.117 > +++ ikev2_pld.c 1 Sep 2021 11:26:51 -0000 > @@ -1842,6 +1842,7 @@ ikev2_pld_cp(struct iked *env, struct ik > 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 ik > > 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 ik > __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 ik > 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 ik > 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); > } > Index: policy.c > =================================================================== > RCS file: /cvs/src/sbin/iked/policy.c,v > retrieving revision 1.82 > diff -u -p -r1.82 policy.c > --- policy.c 23 Jun 2021 12:11:40 -0000 1.82 > +++ policy.c 1 Sep 2021 11:26:51 -0000 > @@ -680,6 +680,13 @@ sa_configure_iface(struct iked *env, str > 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); > > Index: types.h > =================================================================== > RCS file: /cvs/src/sbin/iked/types.h,v > retrieving revision 1.44 > diff -u -p -r1.44 types.h > --- types.h 3 Aug 2021 12:46:30 -0000 1.44 > +++ types.h 1 Sep 2021 11:26:51 -0000 > @@ -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, > Index: vroute.c > =================================================================== > RCS file: /cvs/src/sbin/iked/vroute.c,v > retrieving revision 1.12 > diff -u -p -r1.12 vroute.c > --- vroute.c 23 Jun 2021 12:21:23 -0000 1.12 > +++ vroute.c 1 Sep 2021 11:26:51 -0000 > @@ -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 > 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 ms > 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); Why are you filtering RTM_GET? I don't think you need it. > + 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 > 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 > } > > 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) > { > @@ -525,6 +687,73 @@ vroute_getcloneroute(struct iked *env, s > return (vroute_doroute(env, flags, addrs, rdomain, RTM_ADD, > (struct sockaddr *)&dest, (struct sockaddr *)&mask, > (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 > -- I'm not entirely sure you are real.