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)
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
*/