> 2009.11.20 -- Version 2.1_rc22

Thanks.
For those like me who need to use routing commands with hostnames mapped
to more than a single IP, here's an updated patch.  IIUC the previous
patch should still apply, tho with some offsets.


        Stefan


Index: route.c
===================================================================
--- route.c     (révision 5180)
+++ route.c     (copie de travail)
@@ -217,34 +217,39 @@
     return false;
 }

-static bool
+struct route *
 init_route (struct route *r,
+           struct route *last_route,
            const struct route_option *ro,
            const struct route_special_addr *spec)
 {
   const in_addr_t default_netmask = ~0;
   bool status;
+  int nb = -1;
+  in_addr_t nets[MAX_IPS_PER_HOSTNAME];
+  in_addr_t netmask, gateway;
+  bool metric_defined;
+  int metric;

-  r->option = ro;
-  r->defined = false;
-
   /* network */

   if (!is_route_parm_defined (ro->network))
     {
       goto fail;
     }
-  
-  if (!get_special_addr (spec, ro->network, &r->network, &status))
+
+  if (get_special_addr (spec, ro->network, &nets[0], &status))
+    nb = 1;
+  else
     {
-      r->network = getaddr (
-                           GETADDR_RESOLVE
-                           | GETADDR_HOST_ORDER
-                           | GETADDR_WARN_ON_SIGNAL,
-                           ro->network,
-                           0,
-                           &status,
-                           NULL);
+      nb = getaddr_all (GETADDR_RESOLVE
+                       | GETADDR_HOST_ORDER
+                       | GETADDR_WARN_ON_SIGNAL,
+                       nets, MAX_IPS_PER_HOSTNAME,
+                       ro->network,
+                       0,
+                       NULL);
+      status = (nb >= 0);
     }

   if (!status)
@@ -254,33 +259,33 @@

   if (is_route_parm_defined (ro->netmask))
     {
-      r->netmask = getaddr (
-                           GETADDR_HOST_ORDER
-                           | GETADDR_WARN_ON_SIGNAL,
-                           ro->netmask,
-                           0,
-                           &status,
-                           NULL);
+      netmask = getaddr (
+                        GETADDR_HOST_ORDER
+                        | GETADDR_WARN_ON_SIGNAL,
+                        ro->netmask,
+                        0,
+                        &status,
+                        NULL);
       if (!status)
        goto fail;
     }
   else
-    r->netmask = default_netmask;
+    netmask = default_netmask;

   /* gateway */
-
+      
   if (is_route_parm_defined (ro->gateway))
     {
-      if (!get_special_addr (spec, ro->gateway, &r->gateway, &status))
+      if (!get_special_addr (spec, ro->gateway, &gateway, &status))
        {
-         r->gateway = getaddr (
-                               GETADDR_RESOLVE
-                               | GETADDR_HOST_ORDER
-                               | GETADDR_WARN_ON_SIGNAL,
-                               ro->gateway,
-                               0,
-                               &status,
-                               NULL);
+         gateway = getaddr (
+                            GETADDR_RESOLVE
+                            | GETADDR_HOST_ORDER
+                            | GETADDR_WARN_ON_SIGNAL,
+                            ro->gateway,
+                            0,
+                            &status,
+                            NULL);
        }
       if (!status)
        goto fail;
@@ -288,7 +293,7 @@
   else
     {
       if (spec->remote_endpoint_defined)
-       r->gateway = spec->remote_endpoint;
+       gateway = spec->remote_endpoint;
       else
        {
          msg (M_WARN, PACKAGE_NAME " ROUTE: " PACKAGE_NAME " needs a gateway 
parameter for a --route option and no default was specified by either 
--route-gateway or --ifconfig options");
@@ -298,35 +303,54 @@

   /* metric */

-  r->metric_defined = false;
-  r->metric = 0;
+  metric_defined = false;
+  metric = 0;
   if (is_route_parm_defined (ro->metric))
     {
-      r->metric = atoi (ro->metric);
-      if (r->metric < 0)
+      metric = atoi (ro->metric);
+      if (metric < 0)
        {
          msg (M_WARN, PACKAGE_NAME " ROUTE: route metric for network %s (%s) 
must be >= 0",
               ro->network,
               ro->metric);
          goto fail;
        }
-      r->metric_defined = true;
+      metric_defined = true;
     }
   else if (spec->default_metric_defined)
     {
-      r->metric = spec->default_metric;
-      r->metric_defined = true;
+      metric = spec->default_metric;
+      metric_defined = true;
     }

-  r->defined = true;
+  /* Now fill the corresponding route entries.  */

-  return true;
+  if (netmask != default_netmask && nb > 1)
+    /* If we add individual hosts, then every IP of that host is added,
+       but if we add a whole subnet, then only consider the first IP,
+       presuming that all the IPs are in the same subnet.  */
+    nb = 1;

+  /* Add a route for each one of the IPs found.  */
+  while (nb > 0 && r < last_route)
+    {
+      nb--;
+      r->option = ro;
+      r->network = nets[nb];
+      r->netmask = netmask;
+      r->gateway = gateway;
+      r->metric_defined = metric_defined;
+      r->metric = metric;
+      r->defined = true;
+      r++;
+    }
+
+  return r;
+
  fail:
   msg (M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve route for 
host/network: %s",
        ro->network);
-  r->defined = false;
-  return false;
+  return NULL;
 }

 void
@@ -438,22 +462,29 @@
   else
     rl->spec.remote_endpoint_defined = false;

-  if (!(opt->n >= 0 && opt->n <= rl->capacity))
-    msg (M_FATAL, PACKAGE_NAME " ROUTE: (init) number of route options (%d) is 
greater than route list capacity (%d)", opt->n, rl->capacity);
-
   /* parse the routes from opt to rl */
   {
-    int i, j = 0;
+    int i;
+    struct route *cur_route = rl->routes;
+    struct route *last_route = &rl->routes[rl->capacity];
     for (i = 0; i < opt->n; ++i)
       {
-       if (!init_route (&rl->routes[j],
-                        &opt->routes[i],
-                        &rl->spec))
-         ret = false;
+       if (cur_route >= last_route)
+         msg (M_FATAL, PACKAGE_NAME " ROUTE: (init) number of route options 
(%d) is greater than route list capacity (%d)", opt->n, rl->capacity);
        else
-         ++j;
+         {
+           struct route *next_route
+             = init_route (cur_route,
+                           last_route,
+                           &opt->routes[i],
+                           &rl->spec);
+           if (!next_route)
+             ret = false;
+           else
+             cur_route = next_route;
+         }
       }
-    rl->n = j;
+    rl->n = cur_route - rl->routes;
   }

   gc_free (&gc);
Index: socket.c
===================================================================
--- socket.c    (révision 5180)
+++ socket.c    (copie de travail)
@@ -78,22 +78,25 @@
 }

 /*
- * Translate IP addr or hostname to in_addr_t.
+ * Translate IP addr or hostname to a list of in_addr_t.
  * If resolve error, try again for
  * resolve_retry_seconds seconds.
+ * ret&size is the table in which we'll put the results.
+ * The return value is the number of IPs found.
  */
-in_addr_t
-getaddr (unsigned int flags,
-        const char *hostname,
-        int resolve_retry_seconds,
-        bool *succeeded,
-        volatile int *signal_received)
+int
+getaddr_all (unsigned int flags,
+            in_addr_t *ret, int size,
+            const char *hostname,
+            int resolve_retry_seconds,
+            volatile int *signal_received)
 {
   struct in_addr ia;
   int status;
   int sigrec = 0;
   int msglevel = (flags & GETADDR_FATAL) ? M_FATAL : D_RESOLVE_ERRORS;
   struct gc_arena gc = gc_new ();
+  int nb = -1;

   if (flags & GETADDR_RANDOMIZE)
     hostname = hostname_randomize(hostname, &gc);
@@ -101,14 +104,11 @@
   if (flags & GETADDR_MSG_VIRT_OUT)
     msglevel |= M_MSG_VIRT_OUT;

-  CLEAR (ia);
-  if (succeeded)
-    *succeeded = false;
-
   if ((flags & (GETADDR_FATAL_ON_SIGNAL|GETADDR_WARN_ON_SIGNAL))
       && !signal_received)
     signal_received = &sigrec;

+  CLEAR (ia);
   status = openvpn_inet_aton (hostname, &ia); /* parse ascii IP address */

   if (status != OIA_IP) /* parse as IP address failed? */
@@ -119,8 +119,6 @@
       const char *fmt;
       int level = 0;

-      CLEAR (ia);
-
       fmt = "RESOLVE: Cannot resolve host address: %s: %s";
       if ((flags & GETADDR_MENTION_RESOLVE_RETRY)
          && !resolve_retry_seconds)
@@ -199,37 +197,21 @@
            goto done;
        }

-      ia.s_addr = *(in_addr_t *) (h->h_addr_list[0]);
-
-      if (ia.s_addr)
+      nb = 0;
+      while (nb < size && h->h_addr_list[nb])
        {
-         if (h->h_addr_list[1]) /* more than one address returned */
-           {
-             int n = 0;
-
-             /* count address list */
-             while (h->h_addr_list[n])
-               ++n;
-             ASSERT (n >= 2);
-
-             msg (D_RESOLVE_ERRORS, "RESOLVE: NOTE: %s resolves to %d 
addresses, choosing one by random",
-                  hostname,
-                  n);
-
-             /* choose address randomly, for basic load-balancing capability */
-             ia.s_addr = *(in_addr_t *) (h->h_addr_list[get_random () % n]);
-           }
+         ret[nb] = *(in_addr_t *) (h->h_addr_list[nb]);
+         nb++;
        }
-
-      /* hostname resolve succeeded */
-      if (succeeded)
-       *succeeded = true;
     }
   else
     {
       /* IP address parse succeeded */
-      if (succeeded)
-       *succeeded = true;
+      if (size > 0)
+       {
+         ret[0] = ia.s_addr;
+         nb = 1;
+       }
     }

  done:
@@ -244,10 +226,47 @@
     }

   gc_free (&gc);
-  return (flags & GETADDR_HOST_ORDER) ? ntohl (ia.s_addr) : ia.s_addr;
+  if (flags & GETADDR_HOST_ORDER)
+    {
+      int i = 0;
+      for (; i < nb; i++)
+       ret[i] = ntohl (ret[i]);
+    }
+  return nb;
 }

 /*
+ * Translate IP addr or hostname to in_addr_t.
+ * If resolve error, try again for
+ * resolve_retry_seconds seconds.
+ */
+in_addr_t
+getaddr (unsigned int flags,
+        const char *hostname,
+        int resolve_retry_seconds,
+        bool *succeeded,
+        volatile int *signal_received)
+{
+  in_addr_t ips[MAX_IPS_PER_HOSTNAME];
+  int nb = getaddr_all (flags, ips, MAX_IPS_PER_HOSTNAME,
+                       hostname, resolve_retry_seconds, signal_received);
+  if (succeeded)
+    *succeeded = nb >= 0;
+
+  if (nb > 1)
+    {
+      msg (D_RESOLVE_ERRORS, "RESOLVE: NOTE: %s resolves to %d addresses, 
choosing one at random",
+          hostname,
+          nb);
+      return ips[get_random () % nb];
+    }
+  else if (nb >= 1)
+    return ips[0];
+  else
+    return 0;
+}
+
+/*
  * We do our own inet_aton because the glibc function
  * isn't very good about error checking.
  */
Index: socket.h
===================================================================
--- socket.h    (révision 5180)
+++ socket.h    (copie de travail)
@@ -450,6 +450,13 @@
 #define GETADDR_UPDATE_MANAGEMENT_STATE (1<<8)
 #define GETADDR_RANDOMIZE             (1<<9)

+#define MAX_IPS_PER_HOSTNAME 100
+
+int getaddr_all (unsigned int flags,
+                in_addr_t *ret, int size,
+                const char *hostname,
+                int resolve_retry_seconds,
+                volatile int *signal_received);
 in_addr_t getaddr (unsigned int flags,
                   const char *hostname,
                   int resolve_retry_seconds,


Reply via email to