From: Martin Willi Date: Thu, 18 Apr 2013 16:26:49 +0000 (+0200) Subject: kernel-pfroute: implement get_nexthop() X-Git-Tag: 5.1.0dr1~153^2~18 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9bc342eae471831ca328e00a6bf65be1b2608f7a;p=thirdparty%2Fstrongswan.git kernel-pfroute: implement get_nexthop() --- diff --git a/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c b/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c index caab3150d2..face73e6b0 100644 --- a/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c +++ b/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c @@ -746,12 +746,6 @@ METHOD(kernel_net_t, get_source_addr, host_t*, return NULL; } -METHOD(kernel_net_t, get_nexthop, host_t*, - private_kernel_pfroute_net_t *this, host_t *dest, host_t *src) -{ - return NULL; -} - METHOD(kernel_net_t, add_ip, status_t, private_kernel_pfroute_net_t *this, host_t *virtual_ip, int prefix, char *iface) @@ -906,6 +900,79 @@ 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_pfroute_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; + enumerator_t *enumerator; + struct sockaddr *addr; + int type; + + msg.hdr.rtm_msglen = sizeof(struct rt_msghdr); + for (type = 0; type < RTAX_MAX; type++) + { + switch (type) + { + 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->socket, &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 (this->reply->rtm_msglen < sizeof(*this->reply) || + msg.hdr.rtm_seq != this->reply->rtm_seq) + { + continue; + } + enumerator = create_rtmsg_enumerator(this->reply, + sizeof(*this->reply)); + while (enumerator->enumerate(enumerator, &type, &addr)) + { + if (type == RTAX_GATEWAY) + { + hop = host_create_from_sockaddr(addr); + break; + } + } + enumerator->destroy(enumerator); + break; + } + } + else + { + DBG1(DBG_KNL, "PF_ROUTE lookup failed: %s", strerror(errno)); + } + this->mutex->unlock(this->mutex); + + return hop; +} + /** * Initialize a list of local addresses. */