#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;
}
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);
#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) \
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);
}
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
" 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"
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;
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
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);
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;
}
}
if (pp->routes_defined)
{
rol_check_alloc (o);
- *o->routes = pp->routes;
+ copy_route_option_list (o->routes, pp->routes);
}
else
o->routes = NULL;
}
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);
struct tuntap_options tuntap_options;
bool routes_defined;
- struct route_option_list routes;
+ struct route_option_list *routes;
int foreign_option_index;
};
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;
}
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;
}
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;
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
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 */
{
#include "tun.h"
#include "misc.h"
-#define MAX_ROUTES 100
+#define MAX_ROUTES_DEFAULT 100
#ifdef WIN32
/*
#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 {
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
};
#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);
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,