]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
The maximum number of "route" directives (specified in the config
authorjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Thu, 17 Sep 2009 23:43:37 +0000 (23:43 +0000)
committerjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Thu, 17 Sep 2009 23:43:37 +0000 (23:43 +0000)
file or pulled from a server) can now be configured via the new
"max-routes" directive.

Previously, the limit was set to 100 and fixed by a compile-time
constant.  Now the limit is dynamic and can be modified by the
"max-routes" directive.  If max-routes is not specified, the default
limit is 100.

Note that this change does not address the maximum size of the
pushed options string sent from server to client, which is still
controlled by the TLS_CHANNEL_BUF_SIZE compile-time constant.

git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@4967 e7ae566f-a301-0410-adde-c780ea21d3b5

buffer.c
buffer.h
init.c
openvpn.8
options.c
options.h
route.c
route.h

index 15ab7764013cde0996dd9bb29ef00763199d48dd..d448e5d7544dbee9c0f2185456448e07cfbbda9f 100644 (file)
--- a/buffer.c
+++ b/buffer.c
 #include "memdbg.h"
 
 size_t
-array_mult_safe (const size_t m1, const size_t m2)
+array_mult_safe (const size_t m1, const size_t m2, const size_t extra)
 {
   const size_t limit = 0xFFFFFFFF;
-  unsigned long long res = (unsigned long long)m1 * (unsigned long long)m2;
-  if (unlikely(m1 > limit) || unlikely(m2 > limit) || unlikely(res > (unsigned long long)limit))
+  unsigned long long res = (unsigned long long)m1 * (unsigned long long)m2 + (unsigned long long)extra;
+  if (unlikely(m1 > limit) || unlikely(m2 > limit) || unlikely(extra > limit) || unlikely(res > (unsigned long long)limit))
     msg (M_FATAL, "attemped allocation of excessively large array");
   return (size_t) res;
 }
index 91b3cc6aad5aed59a99419bdb9cd0a3730e516e8..b046a5cf571f2102a9cc57df6dc387c3bd78f544 100644 (file)
--- a/buffer.h
+++ b/buffer.h
@@ -88,7 +88,7 @@ bool buf_assign (struct buffer *dest, const struct buffer *src);
 void string_clear (char *str);
 int string_array_len (const char **array);
 
-size_t array_mult_safe (const size_t m1, const size_t m2);
+size_t array_mult_safe (const size_t m1, const size_t m2, const size_t extra);
 
 #define PA_BRACKET (1<<0)
 char *print_argv (const char **p, struct gc_arena *gc, const unsigned int flags);
@@ -776,23 +776,28 @@ void out_of_memory (void);
 
 #define ALLOC_ARRAY(dptr, type, n) \
 { \
-  check_malloc_return ((dptr) = (type *) malloc (array_mult_safe (sizeof (type), (n)))); \
+  check_malloc_return ((dptr) = (type *) malloc (array_mult_safe (sizeof (type), (n), 0))); \
 }
 
 #define ALLOC_ARRAY_GC(dptr, type, n, gc) \
 { \
-  (dptr) = (type *) gc_malloc (array_mult_safe (sizeof (type), (n)), false, (gc)); \
+  (dptr) = (type *) gc_malloc (array_mult_safe (sizeof (type), (n), 0), false, (gc)); \
 }
 
 #define ALLOC_ARRAY_CLEAR(dptr, type, n) \
 { \
   ALLOC_ARRAY (dptr, type, n); \
-  memset ((dptr), 0, (array_mult_safe (sizeof(type), (n)))); \
+  memset ((dptr), 0, (array_mult_safe (sizeof(type), (n), 0)));        \
 }
 
 #define ALLOC_ARRAY_CLEAR_GC(dptr, type, n, gc) \
 { \
-  (dptr) = (type *) gc_malloc (array_mult_safe (sizeof (type), (n)), true, (gc)); \
+  (dptr) = (type *) gc_malloc (array_mult_safe (sizeof (type), (n), 0), true, (gc)); \
+}
+
+#define ALLOC_VAR_ARRAY_CLEAR_GC(dptr, type, atype, n, gc)     \
+{ \
+  (dptr) = (type *) gc_malloc (array_mult_safe (sizeof (atype), (n), sizeof (type)), true, (gc)); \
 }
 
 #define ALLOC_OBJ_GC(dptr, type, gc) \
diff --git a/init.c b/init.c
index 80b284977a0767b4dfe70bd7e6edbc0f77dc340e..a2821b9d9bf989bb755cd39cfcb39b087760e340 100644 (file)
--- a/init.c
+++ b/init.c
@@ -847,7 +847,7 @@ static void
 do_alloc_route_list (struct context *c)
 {
   if (c->options.routes && !c->c1.route_list)
-    c->c1.route_list = new_route_list (&c->gc);
+    c->c1.route_list = new_route_list (c->options.max_routes, &c->gc);
 }
 
 
index 6e2541a0476f590e59e5ec87fcf2381202da2acd..e9bc113b1c0192cb6e1342c12ca2a866249f9f2d 100644 (file)
--- a/openvpn.8
+++ b/openvpn.8
@@ -946,6 +946,13 @@ table (not supported on all OSes).
 address if OpenVPN is being run in client mode, and is undefined in server mode.
 .\"*********************************************************
 .TP
+.B --max-routes n
+Allow a maximum number of n
+.B --route
+options to be specified, either in the local configuration file,
+or pulled from an OpenVPN server.  By default, n=100.
+.\"*********************************************************
+.TP
 .B --route-gateway gw|'dhcp'
 Specify a default gateway
 .B gw
index a7cab8074859c7e6758ed956b0a80a5308ed9446..c1692e7b639c6b1b18bacc7ba0ff9df1b9560950 100644 (file)
--- a/options.c
+++ b/options.c
@@ -170,6 +170,8 @@ static const char usage_message[] =
   "                  netmask default: 255.255.255.255\n"
   "                  gateway default: taken from --route-gateway or --ifconfig\n"
   "                  Specify default by leaving blank or setting to \"nil\".\n"
+  "--max-routes n :  Specify the maximum number of routes that may be defined\n"
+  "                  or pulled from a server.\n"
   "--route-gateway gw|'dhcp' : Specify a default gateway for use with --route.\n"
   "--route-metric m : Specify a default metric for use with --route.\n"
   "--route-delay n [w] : Delay n seconds after connection initiation before\n"
@@ -680,6 +682,7 @@ init_options (struct options *o, const bool init_gc)
   o->mtu_discover_type = -1;
   o->mssfix = MSSFIX_DEFAULT;
   o->route_delay_window = 30;
+  o->max_routes = MAX_ROUTES_DEFAULT;
   o->resolve_retry_seconds = RESOLV_RETRY_INFINITE;
 #ifdef ENABLE_OCC
   o->occ = true;
@@ -1075,7 +1078,7 @@ void
 rol_check_alloc (struct options *options)
 {
   if (!options->routes)
-    options->routes = new_route_option_list (&options->gc);
+    options->routes = new_route_option_list (options->max_routes, &options->gc);
 }
 
 #ifdef ENABLE_DEBUG
@@ -1264,6 +1267,7 @@ show_settings (const struct options *o)
   SHOW_BOOL (route_delay_defined);
   SHOW_BOOL (route_nopull);
   SHOW_BOOL (route_gateway_via_dhcp);
+  SHOW_INT (max_routes);
   SHOW_BOOL (allow_pull_fqdn);
   if (o->routes)
     print_route_options (o->routes, D_SHOW_PARMS);
@@ -2160,7 +2164,7 @@ pre_pull_save (struct options *o)
       o->pre_pull->foreign_option_index = o->foreign_option_index;
       if (o->routes)
        {
-         o->pre_pull->routes = *o->routes;
+         o->pre_pull->routes = clone_route_option_list(o->routes, &o->gc);
          o->pre_pull->routes_defined = true;
        }
     }
@@ -2179,7 +2183,7 @@ pre_pull_restore (struct options *o)
       if (pp->routes_defined)
        {
          rol_check_alloc (o);
-         *o->routes = pp->routes;
+         copy_route_option_list (o->routes, pp->routes);
        }
       else
        o->routes = NULL;
@@ -4343,6 +4347,19 @@ add_option (struct options *options,
        }
       add_route_to_option_list (options->routes, p[1], p[2], p[3], p[4]);
     }
+  else if (streq (p[0], "max-routes") && p[1])
+    {
+      int max_routes;
+
+      VERIFY_PERMISSION (OPT_P_GENERAL);
+      max_routes = atoi (p[1]);
+      if (max_routes < 0 || max_routes > 100000000)
+       {
+         msg (msglevel, "--max-routes parameter is out of range");
+         goto err;
+       }
+      options->max_routes = max_routes;
+    }
   else if (streq (p[0], "route-gateway") && p[1])
     {
       VERIFY_PERMISSION (OPT_P_ROUTE_EXTRAS);
index 8cabf09873091c46a3b7517d081c47d58527d855..9210aca860e0b86d55c08cdae15ceb43ef9ffdb5 100644 (file)
--- a/options.h
+++ b/options.h
@@ -75,7 +75,7 @@ struct options_pre_pull
   struct tuntap_options tuntap_options;
 
   bool routes_defined;
-  struct route_option_list routes;
+  struct route_option_list *routes;
 
   int foreign_option_index;
 };
@@ -306,6 +306,7 @@ struct options
   int route_delay;
   int route_delay_window;
   bool route_delay_defined;
+  int max_routes;
   struct route_option_list *routes;
   bool route_nopull;
   bool route_gateway_via_dhcp;
diff --git a/route.c b/route.c
index 3809c821c9151a19166bcf5908b05535f08ac25a..988c7ab46ed686bcae208f001932fb00d251d925 100644 (file)
--- a/route.c
+++ b/route.c
@@ -80,18 +80,38 @@ add_bypass_address (struct route_bypass *rb, const in_addr_t a)
 }
 
 struct route_option_list *
-new_route_option_list (struct gc_arena *a)
+new_route_option_list (const int max_routes, struct gc_arena *a)
 {
   struct route_option_list *ret;
-  ALLOC_OBJ_CLEAR_GC (ret, struct route_option_list, a);
+  ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_option_list, struct route_option, max_routes, a);
+  ret->capacity = max_routes;
   return ret;
 }
 
+struct route_option_list *
+clone_route_option_list (const struct route_option_list *src, struct gc_arena *a)
+{
+  const size_t rl_size = array_mult_safe (sizeof(struct route_option), src->capacity, sizeof(struct route_option_list));
+  struct route_option_list *ret = gc_malloc (rl_size, false, a);
+  memcpy (ret, src, rl_size);
+  return ret;
+}
+
+void
+copy_route_option_list (struct route_option_list *dest, const struct route_option_list *src)
+{
+  const size_t src_size = array_mult_safe (sizeof(struct route_option), src->capacity, sizeof(struct route_option_list));
+  if (src->n > dest->capacity)
+    msg (M_FATAL, PACKAGE_NAME " ROUTE: (copy) number of route options in src (%d) is greater than route list capacity in dest (%d)", src->n, dest->capacity);
+  memcpy (dest, src, src_size);
+}
+
 struct route_list *
-new_route_list (struct gc_arena *a)
+new_route_list (const int max_routes, struct gc_arena *a)
 {
   struct route_list *ret;
-  ALLOC_OBJ_CLEAR_GC (ret, struct route_list, a);
+  ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_list, struct route, max_routes, a);
+  ret->capacity = max_routes;
   return ret;
 }
 
@@ -317,9 +337,9 @@ add_route_to_option_list (struct route_option_list *l,
                          const char *metric)
 {
   struct route_option *ro;
-  if (l->n >= MAX_ROUTES)
-    msg (M_FATAL, PACKAGE_NAME " ROUTE: cannot add more than %d routes",
-        MAX_ROUTES);
+  if (l->n >= l->capacity)
+    msg (M_FATAL, PACKAGE_NAME " ROUTE: cannot add more than %d routes -- please increase the max-routes option in the client configuration file",
+        l->capacity);
   ro = &l->routes[l->n];
   ro->network = network;
   ro->netmask = netmask;
@@ -331,7 +351,10 @@ add_route_to_option_list (struct route_option_list *l,
 void
 clear_route_list (struct route_list *rl)
 {
-  CLEAR (*rl);
+  const int capacity = rl->capacity;
+  const size_t rl_size = array_mult_safe (sizeof(struct route), capacity, sizeof(struct route_list));
+  memset(rl, 0, rl_size);
+  rl->capacity = capacity;
 }
 
 void
@@ -415,7 +438,8 @@ init_route_list (struct route_list *rl,
   else
     rl->spec.remote_endpoint_defined = false;
 
-  ASSERT (opt->n >= 0 && opt->n < MAX_ROUTES);
+  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 */
   {
diff --git a/route.h b/route.h
index d8278012b02a07a1e78f037ab1bb868ceeb0ef43..6f713ca8f29c334111816224e069c0f888bcc90b 100644 (file)
--- a/route.h
+++ b/route.h
@@ -32,7 +32,7 @@
 #include "tun.h"
 #include "misc.h"
 
-#define MAX_ROUTES 100
+#define MAX_ROUTES_DEFAULT 100
 
 #ifdef WIN32
 /*
@@ -86,9 +86,10 @@ struct route_option {
 #define RG_AUTO_LOCAL     (1<<6)
 
 struct route_option_list {
-  int n;
   unsigned int flags;
-  struct route_option routes[MAX_ROUTES];
+  int capacity;
+  int n;
+  struct route_option routes[EMPTY_ARRAY_SIZE];
 };
 
 struct route {
@@ -107,8 +108,9 @@ struct route_list {
   unsigned int flags;
   bool did_redirect_default_gateway;
   bool did_local;
+  int capacity;
   int n;
-  struct route routes[MAX_ROUTES];
+  struct route routes[EMPTY_ARRAY_SIZE];
 };
 
 #if P2MP
@@ -120,9 +122,11 @@ struct iroute {
 };
 #endif
 
-struct route_option_list *new_route_option_list (struct gc_arena *a);
+struct route_option_list *new_route_option_list (const int max_routes, struct gc_arena *a);
+struct route_option_list *clone_route_option_list (const struct route_option_list *src, struct gc_arena *a);
+void copy_route_option_list (struct route_option_list *dest, const struct route_option_list *src);
 
-struct route_list *new_route_list (struct gc_arena *a);
+struct route_list *new_route_list (const int max_routes, struct gc_arena *a);
 
 void add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es);
 
@@ -132,8 +136,6 @@ void add_route_to_option_list (struct route_option_list *l,
                               const char *gateway,
                               const char *metric);
 
-void clear_route_list (struct route_list *rl);
-
 bool init_route_list (struct route_list *rl,
                      const struct route_option_list *opt,
                      const char *remote_endpoint,