$OpenBSD: patch-src_openvpn_route_c,v 1.2 2013/10/21 09:15:07 bluhm Exp $
--- src/openvpn/route.c.orig	Thu Mar 28 10:31:03 2013
+++ src/openvpn/route.c	Sat Oct 19 16:00:06 2013
@@ -49,7 +49,7 @@
 #define METRIC_NOT_USED ((DWORD)-1)
 #endif
 
-static void delete_route (struct route *r, const struct tuntap *tt, unsigned int flags, const struct route_gateway_info *rgi, const struct env_set *es);
+static void delete_route (struct route_base *r, const struct tuntap *tt, unsigned int flags, const struct route_gateway_info *rgi, const struct env_set *es);
 
 static void get_bypass_addresses (struct route_bypass *rb, const unsigned int flags);
 
@@ -150,7 +150,7 @@ struct route_list *
 new_route_list (const int max_routes, struct gc_arena *a)
 {
   struct route_list *ret;
-  ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_list, struct route, max_routes, a);
+  ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_list, struct route_base, max_routes, a);
   ret->capacity = max_routes;
   return ret;
 }
@@ -165,7 +165,7 @@ new_route_ipv6_list (const int max_routes, struct gc_a
 }
 
 static const char *
-route_string (const struct route *r, struct gc_arena *gc)
+route_string (const struct route_base *r, struct gc_arena *gc)
 {
   struct buffer out = alloc_buf_gc (256, gc);
   buf_printf (&out, "ROUTE network %s netmask %s gateway %s",
@@ -267,7 +267,7 @@ is_special_addr (const char *addr_str)
 }
 
 static bool
-init_route (struct route *r,
+init_route (struct route_base *r,
 	    struct addrinfo **network_list,
 	    const struct route_option *ro,
 	    const struct route_list *rl)
@@ -484,7 +484,7 @@ void
 clear_route_list (struct route_list *rl)
 {
   const int capacity = rl->capacity;
-  const size_t rl_size = array_mult_safe (sizeof(struct route), capacity, sizeof(struct route_list));
+  const size_t rl_size = array_mult_safe (sizeof(struct route_base), capacity, sizeof(struct route_list));
   memset(rl, 0, rl_size);
   rl->capacity = capacity;
 }
@@ -518,7 +518,7 @@ add_block_local_item (struct route_list *rl,
       && rl->rgi.gateway.netmask < 0xFFFFFFFF
       && (rl->n)+2 <= rl->capacity)
     {
-      struct route r;
+      struct route_base r;
       unsigned int l2;
 
       /* split a route into two smaller blocking routes, and direct them to target */
@@ -648,7 +648,7 @@ init_route_list (struct route_list *rl,
     for (i = 0; i < opt->n; ++i)
       {
         struct addrinfo* netlist;
-	struct route r;
+	struct route_base r;
 
 	if (!init_route (&r,
 			 &netlist,
@@ -759,7 +759,7 @@ add_route3 (in_addr_t network,
 	    const struct route_gateway_info *rgi,
 	    const struct env_set *es)
 {
-  struct route r;
+  struct route_base r;
   CLEAR (r);
   r.flags = RT_DEFINED;
   r.network = network;
@@ -777,7 +777,7 @@ del_route3 (in_addr_t network,
 	    const struct route_gateway_info *rgi,
 	    const struct env_set *es)
 {
-  struct route r;
+  struct route_base r;
   CLEAR (r);
   r.flags = RT_DEFINED|RT_ADDED;
   r.network = network;
@@ -1027,7 +1027,7 @@ add_routes (struct route_list *rl, struct route_ipv6_l
       
       for (i = 0; i < rl->n; ++i)
 	{
-	  struct route *r = &rl->routes[i];
+	  struct route_base *r = &rl->routes[i];
 	  check_subnet_conflict (r->network, r->netmask, "route");
 	  if (flags & ROUTE_DELETE_FIRST)
 	    delete_route (r, tt, flags, &rl->rgi, es);
@@ -1059,7 +1059,7 @@ delete_routes (struct route_list *rl, struct route_ipv
       int i;
       for (i = rl->n - 1; i >= 0; --i)
 	{
-	  struct route * r = &rl->routes[i];
+	  struct route_base * r = &rl->routes[i];
 	  delete_route (r, tt, flags, &rl->rgi, es);
 	}
       rl->iflags &= ~RL_ROUTES_ADDED;
@@ -1153,7 +1153,7 @@ print_default_gateway(const int msglevel, const struct
 #endif
 
 static void
-print_route (const struct route *r, int level)
+print_route (const struct route_base *r, int level)
 {
   struct gc_arena gc = gc_new ();
   if (r->flags & RT_DEFINED)
@@ -1170,7 +1170,7 @@ print_routes (const struct route_list *rl, int level)
 }
 
 static void
-setenv_route (struct env_set *es, const struct route *r, int i)
+setenv_route (struct env_set *es, const struct route_base *r, int i)
 {
   struct gc_arena gc = gc_new ();
   if (r->flags & RT_DEFINED)
@@ -1287,7 +1287,7 @@ is_on_link (const int is_local_route, const unsigned i
 }
 
 void
-add_route (struct route *r,
+add_route (struct route_base *r,
 	   const struct tuntap *tt,
 	   unsigned int flags,
 	   const struct route_gateway_info *rgi, /* may be NULL */
@@ -1727,7 +1727,7 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tu
 }
 
 static void
-delete_route (struct route *r,
+delete_route (struct route_base *r,
 	      const struct tuntap *tt,
 	      unsigned int flags,
 	      const struct route_gateway_info *rgi,
@@ -2231,7 +2231,7 @@ get_default_gateway (struct route_gateway_info *rgi)
 }
 
 static DWORD
-windows_route_find_if_index (const struct route *r, const struct tuntap *tt)
+windows_route_find_if_index (const struct route_base *r, const struct tuntap *tt)
 {
   struct gc_arena gc = gc_new ();
   DWORD ret = TUN_ADAPTER_INDEX_INVALID;
@@ -2276,7 +2276,7 @@ windows_route_find_if_index (const struct route *r, co
 }
 
 bool
-add_route_ipapi (const struct route *r, const struct tuntap *tt, DWORD adapter_index)
+add_route_ipapi (const struct route_base *r, const struct tuntap *tt, DWORD adapter_index)
 {
   struct gc_arena gc = gc_new ();
   bool ret = false;
@@ -2350,7 +2350,7 @@ add_route_ipapi (const struct route *r, const struct t
 }
 
 bool
-del_route_ipapi (const struct route *r, const struct tuntap *tt)
+del_route_ipapi (const struct route_base *r, const struct tuntap *tt)
 {
   struct gc_arena gc = gc_new ();
   bool ret = false;
@@ -2957,7 +2957,7 @@ get_default_gateway (struct route_gateway_info *rgi)
 
 #undef max
 
-#elif defined(TARGET_OPENBSD) || defined(TARGET_NETBSD)
+#elif defined(TARGET_NETBSD)
 
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -3008,6 +3008,119 @@ struct rt_msghdr {
 	u_long	rtm_inits;	/* which metrics we are initializing */
 	struct	rt_metrics rtm_rmx; /* metrics themselves */
 };
+
+struct {
+  struct rt_msghdr m_rtm;
+  char       m_space[512];
+} m_rtmsg;
+
+#define ROUNDUP(a) \
+        ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+
+/*
+ * FIXME -- add support for netmask, hwaddr, and iface
+ */
+void
+get_default_gateway (struct route_gateway_info *rgi)
+{
+  struct gc_arena gc = gc_new ();
+  int s, seq, l, rtm_addrs, i;
+  pid_t pid;
+  struct sockaddr so_dst, so_mask;
+  char *cp = m_rtmsg.m_space; 
+  struct sockaddr *gate = NULL, *sa;
+  struct  rt_msghdr *rtm_aux;
+
+#define NEXTADDR(w, u) \
+        if (rtm_addrs & (w)) {\
+            l = ROUNDUP(u.sa_len); memmove(cp, &(u), l); cp += l;\
+        }
+
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+#define rtm m_rtmsg.m_rtm
+
+  CLEAR(*rgi);
+
+  pid = getpid();
+  seq = 0;
+  rtm_addrs = RTA_DST | RTA_NETMASK;
+
+  bzero(&so_dst, sizeof(so_dst));
+  bzero(&so_mask, sizeof(so_mask));
+  bzero(&rtm, sizeof(struct rt_msghdr));
+
+  rtm.rtm_type = RTM_GET;
+  rtm.rtm_flags = RTF_UP | RTF_GATEWAY;
+  rtm.rtm_version = RTM_VERSION;
+  rtm.rtm_seq = ++seq;
+  rtm.rtm_addrs = rtm_addrs; 
+
+  so_dst.sa_family = AF_INET;
+  so_dst.sa_len = sizeof(struct sockaddr_in);
+  so_mask.sa_family = AF_INET;
+  so_mask.sa_len = sizeof(struct sockaddr_in);
+
+  NEXTADDR(RTA_DST, so_dst);
+  NEXTADDR(RTA_NETMASK, so_mask);
+
+  rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
+
+  s = socket(PF_ROUTE, SOCK_RAW, 0);
+
+  if (write(s, (char *)&m_rtmsg, l) < 0)
+    {
+      msg(M_WARN|M_ERRNO, "Could not retrieve default gateway from route socket:");
+      gc_free (&gc);
+      close(s);
+      return;
+    }
+
+  do {
+    l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
+  } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
+                        
+  close(s);
+
+  rtm_aux = &rtm;
+
+  cp = ((char *)(rtm_aux + 1));
+  if (rtm_aux->rtm_addrs) {
+    for (i = 1; i; i <<= 1)
+      if (i & rtm_aux->rtm_addrs) {
+	sa = (struct sockaddr *)cp;
+	if (i == RTA_GATEWAY )
+	  gate = sa;
+	ADVANCE(cp, sa);
+      }
+  }
+  else
+    {
+      gc_free (&gc);
+      return;
+    }
+
+
+  if (gate != NULL )
+    {
+      rgi->gateway.addr = ntohl(((struct sockaddr_in *)gate)->sin_addr.s_addr);
+      rgi->flags |= RGI_ADDR_DEFINED;
+
+      gc_free (&gc);
+    }
+  else
+    {
+      gc_free (&gc);
+    }
+}
+
+#elif defined(TARGET_OPENBSD)
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <net/route.h>
 
 struct {
   struct rt_msghdr m_rtm;
