aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--buffer.c6
-rw-r--r--buffer.h15
-rw-r--r--init.c2
-rw-r--r--openvpn.87
-rw-r--r--options.c23
-rw-r--r--options.h3
-rw-r--r--route.c42
-rw-r--r--route.h18
8 files changed, 86 insertions, 30 deletions
diff --git a/buffer.c b/buffer.c
index 15ab776..d448e5d 100644
--- a/buffer.c
+++ b/buffer.c
@@ -33,11 +33,11 @@
#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;
}
diff --git a/buffer.h b/buffer.h
index 91b3cc6..b046a5c 100644
--- 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 80b2849..a2821b9 100644
--- 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);
}
diff --git a/openvpn.8 b/openvpn.8
index 6e2541a..e9bc113 100644
--- 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
diff --git a/options.c b/options.c
index a7cab80..c1692e7 100644
--- 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);
diff --git a/options.h b/options.h
index 8cabf09..9210aca 100644
--- 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 3809c82..988c7ab 100644
--- 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 d827801..6f713ca 100644
--- 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,