]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
kernel-utun: implement get_nexthop() lookup using PF_ROUTE
authorMartin Willi <martin@revosec.ch>
Wed, 17 Apr 2013 13:47:06 +0000 (15:47 +0200)
committerMartin Willi <martin@revosec.ch>
Thu, 18 Apr 2013 12:43:56 +0000 (14:43 +0200)
src/libhydra/plugins/kernel_utun/kernel_utun_net.c

index 3c62e3a65f2c0e14d2b1f0f5ca54279ab3601373..7446340affe0f002781e1cc78e86afc6008b0161 100644 (file)
@@ -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
  */