From: Martin Willi Date: Wed, 17 Apr 2013 13:47:06 +0000 (+0200) Subject: kernel-utun: implement get_nexthop() lookup using PF_ROUTE X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cc3af6ae60b24b52d6f873094df3016230fd9f6a;p=thirdparty%2Fstrongswan.git kernel-utun: implement get_nexthop() lookup using PF_ROUTE --- diff --git a/src/libhydra/plugins/kernel_utun/kernel_utun_net.c b/src/libhydra/plugins/kernel_utun/kernel_utun_net.c index 3c62e3a65f..7446340aff 100644 --- a/src/libhydra/plugins/kernel_utun/kernel_utun_net.c +++ b/src/libhydra/plugins/kernel_utun/kernel_utun_net.c @@ -215,12 +215,6 @@ METHOD(kernel_net_t, get_source_addr, host_t*, return NULL; } -METHOD(kernel_net_t, get_nexthop, host_t*, - private_kernel_utun_net_t *this, host_t *dest, host_t *src) -{ - return NULL; -} - METHOD(kernel_net_t, add_ip, status_t, private_kernel_utun_net_t *this, host_t *virtual_ip, int prefix, char *iface_name) @@ -389,6 +383,87 @@ METHOD(kernel_net_t, del_route, status_t, return manage_route(this, RTM_DELETE, dst_net, prefixlen, gateway, if_name); } +METHOD(kernel_net_t, get_nexthop, host_t*, + private_kernel_utun_net_t *this, host_t *dest, host_t *src) +{ + struct { + struct rt_msghdr hdr; + char buf[sizeof(struct sockaddr_storage) * RTAX_MAX]; + } msg = { + .hdr = { + .rtm_version = RTM_VERSION, + .rtm_type = RTM_GET, + .rtm_pid = this->pid, + .rtm_seq = ++this->seq, + }, + }; + host_t *hop = NULL; + struct sockaddr *addr; + int i, remaining; + + msg.hdr.rtm_msglen = sizeof(struct rt_msghdr); + for (i = 0; i < RTAX_MAX; i++) + { + switch (i) + { + case RTAX_DST: + add_rt_addr(&msg.hdr, RTA_DST, dest); + break; + case RTAX_IFA: + add_rt_addr(&msg.hdr, RTA_IFA, src); + break; + default: + break; + } + } + this->mutex->lock(this->mutex); + + this->waiting_seq = msg.hdr.rtm_seq; + if (send(this->pfr, &msg, msg.hdr.rtm_msglen, 0) == msg.hdr.rtm_msglen) + { + while (TRUE) + { + if (this->condvar->timed_wait(this->condvar, this->mutex, 1000)) + { /* timed out? */ + break; + } + if (msg.hdr.rtm_seq != this->reply->rtm_seq) + { + continue; + } + remaining = this->reply->rtm_msglen - sizeof(*this->reply); + addr = (void*)this->reply + sizeof(*this->reply); + for (i = 0; i < RTAX_MAX; i++) + { + if ((1 << i & this->reply->rtm_addrs) && + remaining >= sizeof(addr->sa_len) && + remaining >= addr->sa_len && + remaining >= sizeof(struct sockaddr)) + { + switch (i) + { + case RTAX_GATEWAY: + hop = host_create_from_sockaddr(addr); + break; + default: + break; + } + addr = (void*)addr + addr->sa_len; + remaining -= addr->sa_len; + } + } + break; + } + } + else + { + DBG1(DBG_KNL, "PF_ROUTE lookup failed: %s", strerror(errno)); + } + this->mutex->unlock(this->mutex); + + return hop; +} + /** * Receive PF_ROUTE messages from kernel */