Browse code

grow route lists dynamically

This removes the need for the --max-routes option. Instead of
allocating a fixed size array for the route(-option)s they are
managed in linked lists instead.

Signed-off-by: Heiko Hund <heiko.hund@sophos.com>
Acked-by: Arne Schwabe <arne@rfc2549.org>
Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <1392746395-19246-1-git-send-email-heiko.hund@sophos.com>
URL: http://article.gmane.org/gmane.network.openvpn.devel/8295
Signed-off-by: Gert Doering <gert@greenie.muc.de>

Heiko Hund authored on 2014/02/19 02:59:55
Showing 6 changed files
... ...
@@ -1167,9 +1167,9 @@ static void
1167 1167
 do_alloc_route_list (struct context *c)
1168 1168
 {
1169 1169
   if (!c->c1.route_list)
1170
-    c->c1.route_list = new_route_list (c->options.max_routes, &c->gc);
1170
+    ALLOC_OBJ_CLEAR_GC (c->c1.route_list, struct route_list, &c->gc);
1171 1171
   if (c->options.routes_ipv6 && !c->c1.route_ipv6_list)
1172
-    c->c1.route_ipv6_list = new_route_ipv6_list (c->options.max_routes, &c->gc);
1172
+    ALLOC_OBJ_CLEAR_GC (c->c1.route_ipv6_list, struct route_ipv6_list, &c->gc);
1173 1173
 }
1174 1174
 
1175 1175
 
... ...
@@ -218,8 +218,6 @@ static const char usage_message[] =
218 218
   "                  Add IPv6 route to routing table after connection\n"
219 219
   "                  is established.  Multiple routes can be specified.\n"
220 220
   "                  gateway default: taken from 'remote' in --ifconfig-ipv6\n"
221
-  "--max-routes n :  Specify the maximum number of routes that may be defined\n"
222
-  "                  or pulled from a server.\n"
223 221
   "--route-gateway gw|'dhcp' : Specify a default gateway for use with --route.\n"
224 222
   "--route-metric m : Specify a default metric for use with --route.\n"
225 223
   "--route-delay n [w] : Delay n seconds after connection initiation before\n"
... ...
@@ -796,7 +794,6 @@ init_options (struct options *o, const bool init_gc)
796 796
   o->ce.mtu_discover_type = -1;
797 797
   o->ce.mssfix = MSSFIX_DEFAULT;
798 798
   o->route_delay_window = 30;
799
-  o->max_routes = MAX_ROUTES_DEFAULT;
800 799
   o->resolve_retry_seconds = RESOLV_RETRY_INFINITE;
801 800
   o->proto_force = -1;
802 801
 #ifdef ENABLE_OCC
... ...
@@ -1340,14 +1337,14 @@ void
1340 1340
 rol_check_alloc (struct options *options)
1341 1341
 {
1342 1342
   if (!options->routes)
1343
-    options->routes = new_route_option_list (options->max_routes, &options->gc);
1343
+    options->routes = new_route_option_list (&options->gc);
1344 1344
 }
1345 1345
 
1346 1346
 void
1347 1347
 rol6_check_alloc (struct options *options)
1348 1348
 {
1349 1349
   if (!options->routes_ipv6)
1350
-    options->routes_ipv6 = new_route_ipv6_option_list (options->max_routes, &options->gc);
1350
+    options->routes_ipv6 = new_route_ipv6_option_list (&options->gc);
1351 1351
 }
1352 1352
 
1353 1353
 #ifdef ENABLE_CLIENT_NAT
... ...
@@ -1550,7 +1547,6 @@ show_settings (const struct options *o)
1550 1550
   SHOW_BOOL (route_delay_defined);
1551 1551
   SHOW_BOOL (route_nopull);
1552 1552
   SHOW_BOOL (route_gateway_via_dhcp);
1553
-  SHOW_INT (max_routes);
1554 1553
   SHOW_BOOL (allow_pull_fqdn);
1555 1554
   if (o->routes)
1556 1555
     print_route_options (o->routes, D_SHOW_PARMS);
... ...
@@ -2829,7 +2825,7 @@ pre_pull_save (struct options *o)
2829 2829
 }
2830 2830
 
2831 2831
 void
2832
-pre_pull_restore (struct options *o)
2832
+pre_pull_restore (struct options *o, struct gc_arena *gc)
2833 2833
 {
2834 2834
   const struct options_pre_pull *pp = o->pre_pull;
2835 2835
   if (pp)
... ...
@@ -2841,7 +2837,7 @@ pre_pull_restore (struct options *o)
2841 2841
       if (pp->routes_defined)
2842 2842
 	{
2843 2843
 	  rol_check_alloc (o);
2844
-	  copy_route_option_list (o->routes, pp->routes);
2844
+	  copy_route_option_list (o->routes, pp->routes, gc);
2845 2845
 	}
2846 2846
       else
2847 2847
 	o->routes = NULL;
... ...
@@ -2849,7 +2845,7 @@ pre_pull_restore (struct options *o)
2849 2849
       if (pp->routes_ipv6_defined)
2850 2850
 	{
2851 2851
 	  rol6_check_alloc (o);
2852
-	  copy_route_ipv6_option_list (o->routes_ipv6, pp->routes_ipv6);
2852
+	  copy_route_ipv6_option_list (o->routes_ipv6, pp->routes_ipv6, gc);
2853 2853
 	}
2854 2854
       else
2855 2855
 	o->routes_ipv6 = NULL;
... ...
@@ -5227,23 +5223,10 @@ add_option (struct options *options,
5227 5227
 	}
5228 5228
       add_route_ipv6_to_option_list (options->routes_ipv6, p[1], p[2], p[3]);
5229 5229
     }
5230
-  else if (streq (p[0], "max-routes") && p[1])
5230
+  else if (streq (p[0], "max-routes"))
5231 5231
     {
5232
-      int max_routes;
5233
-
5234
-      VERIFY_PERMISSION (OPT_P_GENERAL);
5235
-      max_routes = atoi (p[1]);
5236
-      if (max_routes < 0 || max_routes > 100000000)
5237
-	{
5238
-	  msg (msglevel, "--max-routes parameter is out of range");
5239
-	  goto err;
5240
-	}
5241
-      if (options->routes || options->routes_ipv6)
5242
-        {
5243
-          msg (msglevel, "--max-routes must to be specifed before any route/route-ipv6/redirect-gateway option");
5244
-          goto err;
5245
-        }
5246
-      options->max_routes = max_routes;
5232
+      msg (msglevel, "--max-routes option ignored. The number of routes is unlimited as of version 2.4. "
5233
+           "This option will be removed in a future version, please remove it from your configuration.");
5247 5234
     }
5248 5235
   else if (streq (p[0], "route-gateway") && p[1])
5249 5236
     {
... ...
@@ -343,7 +343,6 @@ struct options
343 343
   int route_delay;
344 344
   int route_delay_window;
345 345
   bool route_delay_defined;
346
-  int max_routes;
347 346
   struct route_option_list *routes;
348 347
   struct route_ipv6_option_list *routes_ipv6;			/* IPv6 */
349 348
   bool route_nopull;
... ...
@@ -715,7 +714,7 @@ void options_warning (char *actual, const char *expected);
715 715
 void options_postprocess (struct options *options);
716 716
 
717 717
 void pre_pull_save (struct options *o);
718
-void pre_pull_restore (struct options *o);
718
+void pre_pull_restore (struct options *o, struct gc_arena *gc);
719 719
 
720 720
 bool apply_push_options (struct options *options,
721 721
 			 struct buffer *buf,
... ...
@@ -456,7 +456,7 @@ process_incoming_push_msg (struct context *c,
456 456
 	    }
457 457
 	  if (!c->c2.did_pre_pull_restore)
458 458
 	    {
459
-	      pre_pull_restore (&c->options);
459
+	      pre_pull_restore (&c->options, &c->c2.gc);
460 460
 	      c->c2.did_pre_pull_restore = true;
461 461
 	    }
462 462
 	  if (apply_push_options (&c->options,
... ...
@@ -92,76 +92,62 @@ add_bypass_address (struct route_bypass *rb, const in_addr_t a)
92 92
 }
93 93
 
94 94
 struct route_option_list *
95
-new_route_option_list (const int max_routes, struct gc_arena *a)
95
+new_route_option_list (struct gc_arena *a)
96 96
 {
97 97
   struct route_option_list *ret;
98
-  ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_option_list, struct route_option, max_routes, a);
99
-  ret->capacity = max_routes;
98
+  ALLOC_OBJ_CLEAR_GC (ret, struct route_option_list, a);
99
+  ret->gc = a;
100 100
   return ret;
101 101
 }
102 102
 
103 103
 struct route_ipv6_option_list *
104
-new_route_ipv6_option_list (const int max_routes, struct gc_arena *a)
104
+new_route_ipv6_option_list (struct gc_arena *a)
105 105
 {
106 106
   struct route_ipv6_option_list *ret;
107
-  ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_ipv6_option_list, struct route_ipv6_option, max_routes, a);
108
-  ret->capacity = max_routes;
107
+  ALLOC_OBJ_CLEAR_GC (ret, struct route_ipv6_option_list, a);
108
+  ret->gc = a;
109 109
   return ret;
110 110
 }
111 111
 
112
+/*
113
+ * NOTE: structs are cloned/copied shallow by design.
114
+ * The routes list from src will stay intact since it is allocated using
115
+ * the options->gc. The cloned/copied lists will share this common tail
116
+ * to avoid copying the data around between pulls. Pulled routes use
117
+ * the c2->gc so they get freed immediately after a reconnect.
118
+ */
112 119
 struct route_option_list *
113 120
 clone_route_option_list (const struct route_option_list *src, struct gc_arena *a)
114 121
 {
115
-  const size_t rl_size = array_mult_safe (sizeof(struct route_option), src->capacity, sizeof(struct route_option_list));
116
-  struct route_option_list *ret = gc_malloc (rl_size, false, a);
117
-  memcpy (ret, src, rl_size);
122
+  struct route_option_list *ret;
123
+  ALLOC_OBJ_GC (ret, struct route_option_list, a);
124
+  *ret = *src;
118 125
   return ret;
119 126
 }
120 127
 
121 128
 struct route_ipv6_option_list *
122 129
 clone_route_ipv6_option_list (const struct route_ipv6_option_list *src, struct gc_arena *a)
123 130
 {
124
-  const size_t rl_size = array_mult_safe (sizeof(struct route_ipv6_option), src->capacity, sizeof(struct route_ipv6_option_list));
125
-  struct route_ipv6_option_list *ret = gc_malloc (rl_size, false, a);
126
-  memcpy (ret, src, rl_size);
131
+  struct route_ipv6_option_list *ret;
132
+  ALLOC_OBJ_GC (ret, struct route_ipv6_option_list, a);
133
+  *ret = *src;
127 134
   return ret;
128 135
 }
129 136
 
130 137
 void
131
-copy_route_option_list (struct route_option_list *dest, const struct route_option_list *src)
138
+copy_route_option_list (struct route_option_list *dest, const struct route_option_list *src, struct gc_arena *a)
132 139
 {
133
-  const size_t src_size = array_mult_safe (sizeof(struct route_option), src->capacity, sizeof(struct route_option_list));
134
-  if (src->capacity > dest->capacity)
135
-    msg (M_FATAL, PACKAGE_NAME " ROUTE: (copy) number of route options in src (%d) is greater than route list capacity in dest (%d)", src->capacity, dest->capacity);
136
-  memcpy (dest, src, src_size);
140
+  *dest = *src;
141
+  dest->gc = a;
137 142
 }
138 143
 
139 144
 void
140 145
 copy_route_ipv6_option_list (struct route_ipv6_option_list *dest,
141
-			     const struct route_ipv6_option_list *src)
146
+                             const struct route_ipv6_option_list *src,
147
+                             struct gc_arena *a)
142 148
 {
143
-  const size_t src_size = array_mult_safe (sizeof(struct route_ipv6_option), src->capacity, sizeof(struct route_ipv6_option_list));
144
-  if (src->capacity > dest->capacity)
145
-    msg (M_FATAL, PACKAGE_NAME " ROUTE: (copy) number of route options in src (%d) is greater than route list capacity in dest (%d)", src->capacity, dest->capacity);
146
-  memcpy (dest, src, src_size);
147
-}
148
-
149
-struct route_list *
150
-new_route_list (const int max_routes, struct gc_arena *a)
151
-{
152
-  struct route_list *ret;
153
-  ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_list, struct route_ipv4, max_routes, a);
154
-  ret->capacity = max_routes;
155
-  return ret;
156
-}
157
-
158
-struct route_ipv6_list *
159
-new_route_ipv6_list (const int max_routes, struct gc_arena *a)
160
-{
161
-  struct route_ipv6_list *ret;
162
-  ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_ipv6_list, struct route_ipv6, max_routes, a);
163
-  ret->capacity = max_routes;
164
-  return ret;
149
+  *dest = *src;
150
+  dest->gc = a;
165 151
 }
166 152
 
167 153
 static const char *
... ...
@@ -452,15 +438,14 @@ add_route_to_option_list (struct route_option_list *l,
452 452
 			  const char *metric)
453 453
 {
454 454
   struct route_option *ro;
455
-  if (l->n >= l->capacity)
456
-    msg (M_FATAL, PACKAGE_NAME " ROUTE: cannot add more than %d routes -- please increase the max-routes option in the client configuration file",
457
-	 l->capacity);
458
-  ro = &l->routes[l->n];
455
+  ALLOC_OBJ_GC (ro, struct route_option, l->gc);
459 456
   ro->network = network;
460 457
   ro->netmask = netmask;
461 458
   ro->gateway = gateway;
462 459
   ro->metric = metric;
463
-  ++l->n;
460
+  ro->next = l->routes;
461
+  l->routes = ro;
462
+
464 463
 }
465 464
 
466 465
 void
... ...
@@ -470,32 +455,26 @@ add_route_ipv6_to_option_list (struct route_ipv6_option_list *l,
470 470
 			  const char *metric)
471 471
 {
472 472
   struct route_ipv6_option *ro;
473
-  if (l->n >= l->capacity)
474
-    msg (M_FATAL, PACKAGE_NAME " ROUTE: cannot add more than %d IPv6 routes -- please increase the max-routes option in the client configuration file",
475
-	 l->capacity);
476
-  ro = &l->routes_ipv6[l->n];
473
+  ALLOC_OBJ_GC (ro, struct route_ipv6_option, l->gc);
477 474
   ro->prefix = prefix;
478 475
   ro->gateway = gateway;
479 476
   ro->metric = metric;
480
-  ++l->n;
477
+  ro->next = l->routes_ipv6;
478
+  l->routes_ipv6 = ro;
481 479
 }
482 480
 
483 481
 void
484 482
 clear_route_list (struct route_list *rl)
485 483
 {
486
-  const int capacity = rl->capacity;
487
-  const size_t rl_size = array_mult_safe (sizeof(struct route_ipv4), capacity, sizeof(struct route_list));
488
-  memset(rl, 0, rl_size);
489
-  rl->capacity = capacity;
484
+  gc_free (&rl->gc);
485
+  CLEAR (*rl);
490 486
 }
491 487
 
492 488
 void
493 489
 clear_route_ipv6_list (struct route_ipv6_list *rl6)
494 490
 {
495
-  const int capacity = rl6->capacity;
496
-  const size_t rl6_size = array_mult_safe (sizeof(struct route_ipv6), capacity, sizeof(struct route_ipv6_list));
497
-  memset(rl6, 0, rl6_size);
498
-  rl6->capacity = capacity;
491
+  gc_free (&rl6->gc);
492
+  CLEAR (*rl6);
499 493
 }
500 494
 
501 495
 void
... ...
@@ -516,22 +495,27 @@ add_block_local_item (struct route_list *rl,
516 516
 {
517 517
   const int rgi_needed = (RGI_ADDR_DEFINED|RGI_NETMASK_DEFINED);
518 518
   if ((rl->rgi.flags & rgi_needed) == rgi_needed
519
-      && rl->rgi.gateway.netmask < 0xFFFFFFFF
520
-      && (rl->n)+2 <= rl->capacity)
519
+      && rl->rgi.gateway.netmask < 0xFFFFFFFF)
521 520
     {
522
-      struct route_ipv4 r;
521
+      struct route_ipv4 *r1, *r2;
523 522
       unsigned int l2;
524 523
 
524
+      ALLOC_OBJ_GC (r1, struct route_ipv4, &rl->gc);
525
+      ALLOC_OBJ_GC (r2, struct route_ipv4, &rl->gc);
526
+
525 527
       /* split a route into two smaller blocking routes, and direct them to target */
526
-      CLEAR(r);
527
-      r.flags = RT_DEFINED;
528
-      r.gateway = target;
529
-      r.network = gateway->addr & gateway->netmask;
530 528
       l2 = ((~gateway->netmask)+1)>>1;
531
-      r.netmask = ~(l2-1);
532
-      rl->routes[rl->n++] = r;
533
-      r.network += l2;
534
-      rl->routes[rl->n++] = r;
529
+      r1->flags = RT_DEFINED;
530
+      r1->gateway = target;
531
+      r1->network = gateway->addr & gateway->netmask;
532
+      r1->netmask = ~(l2-1);
533
+      r1->next = rl->routes;
534
+      rl->routes = r1;
535
+
536
+      *r2 = *r1;
537
+      r2->network += l2;
538
+      r2->next = rl->routes;
539
+      rl->routes = r2;
535 540
     }
536 541
 }
537 542
 
... ...
@@ -643,42 +627,29 @@ init_route_list (struct route_list *rl,
643 643
 
644 644
   /* parse the routes from opt to rl */
645 645
   {
646
-    int i = 0;
647
-    int j = rl->n;
648
-    bool warned = false;
649
-    for (i = 0; i < opt->n; ++i)
646
+    struct route_option *ro;
647
+    for (ro = opt->routes; ro; ro = ro->next)
650 648
       {
651 649
         struct addrinfo* netlist;
652 650
 	struct route_ipv4 r;
653 651
 
654
-	if (!init_route (&r,
655
-			 &netlist,
656
-			 &opt->routes[i],
657
-			 rl))
652
+	if (!init_route (&r, &netlist, ro, rl))
658 653
 	  ret = false;
659 654
 	else
660 655
 	  {
661 656
             struct addrinfo* curele;
662 657
             for (curele	= netlist; curele; curele = curele->ai_next)
663 658
 	      {
664
-		if (j < rl->capacity)
665
-		  {
666
-                    r.network = ntohl(((struct sockaddr_in*)(curele)->ai_addr)->sin_addr.s_addr);
667
-		    rl->routes[j++] = r;
668
-		  }
669
-		else
670
-		  {
671
-		    if (!warned)
672
-		      {
673
-			msg (M_WARN, PACKAGE_NAME " ROUTE: routes dropped because number of expanded routes is greater than route list capacity (%d)", rl->capacity);
674
-			warned = true;
675
-		      }
676
-		  }
659
+                struct route_ipv4 *new;
660
+                ALLOC_OBJ_GC (new, struct route_ipv4, &rl->gc);
661
+                *new = r;
662
+                new->network = ntohl (((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr);
663
+                new->next = rl->routes;
664
+                rl->routes = new;
677 665
 	      }
678 666
             freeaddrinfo(netlist);
679 667
 	  }
680 668
       }
681
-    rl->n = j;
682 669
   }
683 670
 
684 671
   gc_free (&gc);
... ...
@@ -729,22 +700,21 @@ init_route_ipv6_list (struct route_ipv6_list *rl6,
729 729
     rl6->remote_endpoint_defined = false;
730 730
 
731 731
 
732
-  if (!(opt6->n >= 0 && opt6->n <= rl6->capacity))
733
-    msg (M_FATAL, PACKAGE_NAME " ROUTE6: (init) number of route options (%d) is greater than route list capacity (%d)", opt6->n, rl6->capacity);
734
-
735
-  /* parse the routes from opt to rl6 */
732
+  /* parse the routes from opt6 to rl6 */
736 733
   {
737
-    int i, j = 0;
738
-    for (i = 0; i < opt6->n; ++i)
734
+    struct route_ipv6_option *ro6;
735
+    for (ro6 = opt6->routes_ipv6; ro6; ro6 = ro6->next)
739 736
       {
740
-	if (!init_route_ipv6 (&rl6->routes_ipv6[j],
741
-			      &opt6->routes_ipv6[i],
742
-			      rl6 ))
737
+        struct route_ipv6 *r6;
738
+        ALLOC_OBJ_GC (r6, struct route_ipv6, &rl6->gc);
739
+        if (!init_route_ipv6 (r6, ro6, rl6))
743 740
 	  ret = false;
744 741
 	else
745
-	  ++j;
742
+          {
743
+            r6->next = rl6->routes_ipv6;
744
+            rl6->routes_ipv6 = r6;
745
+          }
746 746
       }
747
-    rl6->n = j;
748 747
   }
749 748
 
750 749
   gc_free (&gc);
... ...
@@ -1013,10 +983,10 @@ add_routes (struct route_list *rl, struct route_ipv6_list *rl6, const struct tun
1013 1013
   redirect_default_route_to_vpn (rl, tt, flags, es);
1014 1014
   if ( rl && !(rl->iflags & RL_ROUTES_ADDED) )
1015 1015
     {
1016
-      int i;
1016
+      struct route_ipv4 *r;
1017 1017
 
1018 1018
 #ifdef ENABLE_MANAGEMENT
1019
-      if (management && rl->n)
1019
+      if (management && rl->routes)
1020 1020
 	{
1021 1021
 	  management_set_state (management,
1022 1022
 				OPENVPN_STATE_ADD_ROUTES,
... ...
@@ -1025,10 +995,9 @@ add_routes (struct route_list *rl, struct route_ipv6_list *rl6, const struct tun
1025 1025
 				0);
1026 1026
 	}
1027 1027
 #endif
1028
-      
1029
-      for (i = 0; i < rl->n; ++i)
1028
+
1029
+      for (r = rl->routes; r; r = r->next)
1030 1030
 	{
1031
-	  struct route_ipv4 *r = &rl->routes[i];
1032 1031
 	  check_subnet_conflict (r->network, r->netmask, "route");
1033 1032
 	  if (flags & ROUTE_DELETE_FIRST)
1034 1033
 	    delete_route (r, tt, flags, &rl->rgi, es);
... ...
@@ -1038,11 +1007,9 @@ add_routes (struct route_list *rl, struct route_ipv6_list *rl6, const struct tun
1038 1038
     }
1039 1039
   if (rl6 && !rl6->routes_added)
1040 1040
     {
1041
-      int i;
1042
-
1043
-      for (i = 0; i < rl6->n; ++i)
1041
+      struct route_ipv6 *r;
1042
+      for (r = rl6->routes_ipv6; r; r = r->next)
1044 1043
 	{
1045
-	  struct route_ipv6 *r = &rl6->routes_ipv6[i];
1046 1044
 	  if (flags & ROUTE_DELETE_FIRST)
1047 1045
 	    delete_route_ipv6 (r, tt, flags, es);
1048 1046
 	  add_route_ipv6 (r, tt, flags, es);
... ...
@@ -1057,10 +1024,9 @@ delete_routes (struct route_list *rl, struct route_ipv6_list *rl6,
1057 1057
 {
1058 1058
   if ( rl && rl->iflags & RL_ROUTES_ADDED )
1059 1059
     {
1060
-      int i;
1061
-      for (i = rl->n - 1; i >= 0; --i)
1060
+      struct route_ipv4 *r;
1061
+      for (r = rl->routes; r; r = r->next)
1062 1062
 	{
1063
-	  struct route_ipv4 * r = &rl->routes[i];
1064 1063
 	  delete_route (r, tt, flags, &rl->rgi, es);
1065 1064
 	}
1066 1065
       rl->iflags &= ~RL_ROUTES_ADDED;
... ...
@@ -1075,10 +1041,9 @@ delete_routes (struct route_list *rl, struct route_ipv6_list *rl6,
1075 1075
 
1076 1076
   if ( rl6 && rl6->routes_added )
1077 1077
     {
1078
-      int i;
1079
-      for (i = rl6->n - 1; i >= 0; --i)
1078
+      struct route_ipv6 *r6;
1079
+      for (r6 = rl6->routes_ipv6; r6; r6 = r6->next)
1080 1080
 	{
1081
-	  const struct route_ipv6 *r6 = &rl6->routes_ipv6[i];
1082 1081
 	  delete_route_ipv6 (r6, tt, flags, es);
1083 1082
 	}
1084 1083
       rl6->routes_added = false;
... ...
@@ -1115,12 +1080,12 @@ void
1115 1115
 print_route_options (const struct route_option_list *rol,
1116 1116
 		     int level)
1117 1117
 {
1118
-  int i;
1118
+  struct route_option *ro;
1119 1119
   if (rol->flags & RG_ENABLE)
1120 1120
     msg (level, "  [redirect_default_gateway local=%d]",
1121 1121
 	 (rol->flags & RG_LOCAL) != 0);
1122
-  for (i = 0; i < rol->n; ++i)
1123
-    print_route_option (&rol->routes[i], level);
1122
+  for (ro = rol->routes; ro; ro = ro->next)
1123
+    print_route_option (ro, level);
1124 1124
 }
1125 1125
 
1126 1126
 void
... ...
@@ -1165,9 +1130,9 @@ print_route (const struct route_ipv4 *r, int level)
1165 1165
 void
1166 1166
 print_routes (const struct route_list *rl, int level)
1167 1167
 {
1168
-  int i;
1169
-  for (i = 0; i < rl->n; ++i)
1170
-    print_route (&rl->routes[i], level);
1168
+  struct route_ipv4 *r;
1169
+  for (r = rl->routes; r; r = r->next)
1170
+    print_route (r, level);
1171 1171
 }
1172 1172
 
1173 1173
 static void
... ...
@@ -1193,9 +1158,10 @@ setenv_route (struct env_set *es, const struct route_ipv4 *r, int i)
1193 1193
 void
1194 1194
 setenv_routes (struct env_set *es, const struct route_list *rl)
1195 1195
 {
1196
-  int i;
1197
-  for (i = 0; i < rl->n; ++i)
1198
-    setenv_route (es, &rl->routes[i], i + 1);
1196
+  int i = 1;
1197
+  struct route_ipv4 *r;
1198
+  for (r = rl->routes; r; r = r->next)
1199
+    setenv_route (es, r, i++);
1199 1200
 }
1200 1201
 
1201 1202
 static void
... ...
@@ -1221,9 +1187,10 @@ setenv_route_ipv6 (struct env_set *es, const struct route_ipv6 *r6, int i)
1221 1221
 void
1222 1222
 setenv_routes_ipv6 (struct env_set *es, const struct route_ipv6_list *rl6)
1223 1223
 {
1224
-  int i;
1225
-  for (i = 0; i < rl6->n; ++i)
1226
-    setenv_route_ipv6 (es, &rl6->routes_ipv6[i], i + 1);
1224
+  int i = 1;
1225
+  struct route_ipv6 *r6;
1226
+  for (r6 = rl6->routes_ipv6; r6; r6 = r6->next)
1227
+    setenv_route_ipv6 (es, r6, i++);
1227 1228
 }
1228 1229
 
1229 1230
 /*
... ...
@@ -2137,6 +2104,7 @@ test_routes (const struct route_list *rl, const struct tuntap *tt)
2137 2137
   int count = 0;
2138 2138
   int good = 0;
2139 2139
   int ambig = 0;
2140
+  int len = -1;
2140 2141
   bool adapter_up = false;
2141 2142
 
2142 2143
   if (is_adapter_up (tt, adapters))
... ...
@@ -2146,9 +2114,9 @@ test_routes (const struct route_list *rl, const struct tuntap *tt)
2146 2146
 
2147 2147
       if (rl)
2148 2148
 	{
2149
-	  int i;
2150
-	  for (i = 0; i < rl->n; ++i)
2151
-	    test_route_helper (&ret, &count, &good, &ambig, adapters, rl->routes[i].gateway);
2149
+	  struct route *r;
2150
+	  for (r = rl->routes, len = 0; r; r = r->next, ++len)
2151
+	    test_route_helper (&ret, &count, &good, &ambig, adapters, r->gateway);
2152 2152
 
2153 2153
 	  if ((rl->flags & RG_ENABLE) && (rl->spec.flags & RTSA_REMOTE_ENDPOINT))
2154 2154
 	    test_route_helper (&ret, &count, &good, &ambig, adapters, rl->spec.remote_endpoint);
... ...
@@ -2158,7 +2126,7 @@ test_routes (const struct route_list *rl, const struct tuntap *tt)
2158 2158
   msg (D_ROUTE, "TEST ROUTES: %d/%d succeeded len=%d ret=%d a=%d u/d=%s",
2159 2159
        good,
2160 2160
        count,
2161
-       rl ? rl->n : -1,
2161
+       len,
2162 2162
        (int)ret,
2163 2163
        ambig,
2164 2164
        adapter_up ? "up" : "down");
... ...
@@ -33,8 +33,6 @@
33 33
 #include "tun.h"
34 34
 #include "misc.h"
35 35
 
36
-#define MAX_ROUTES_DEFAULT 100
37
-
38 36
 #ifdef WIN32
39 37
 /*
40 38
  * Windows route methods
... ...
@@ -74,6 +72,7 @@ struct route_special_addr
74 74
 };
75 75
 
76 76
 struct route_option {
77
+  struct route_option *next;
77 78
   const char *network;
78 79
   const char *netmask;
79 80
   const char *gateway;
... ...
@@ -92,12 +91,12 @@ struct route_option {
92 92
 
93 93
 struct route_option_list {
94 94
   unsigned int flags;  /* RG_x flags */
95
-  int capacity;
96
-  int n;
97
-  struct route_option routes[EMPTY_ARRAY_SIZE];
95
+  struct route_option *routes;
96
+  struct gc_arena *gc;
98 97
 };
99 98
 
100 99
 struct route_ipv6_option {
100
+  struct route_ipv6_option *next;
101 101
   const char *prefix;		/* e.g. "2001:db8:1::/64" */
102 102
   const char *gateway;		/* e.g. "2001:db8:0::2" */
103 103
   const char *metric;		/* e.g. "5" */
... ...
@@ -105,15 +104,15 @@ struct route_ipv6_option {
105 105
 
106 106
 struct route_ipv6_option_list {
107 107
   unsigned int flags;
108
-  int capacity;
109
-  int n;
110
-  struct route_ipv6_option routes_ipv6[EMPTY_ARRAY_SIZE];
108
+  struct route_ipv6_option *routes_ipv6;
109
+  struct gc_arena *gc;
111 110
 };
112 111
 
113 112
 struct route_ipv4 {
114 113
 # define RT_DEFINED        (1<<0)
115 114
 # define RT_ADDED          (1<<1)
116 115
 # define RT_METRIC_DEFINED (1<<2)
116
+  struct route_ipv4 *next;
117 117
   unsigned int flags;
118 118
   const struct route_option *option;
119 119
   in_addr_t network;
... ...
@@ -123,6 +122,7 @@ struct route_ipv4 {
123 123
 };
124 124
 
125 125
 struct route_ipv6 {
126
+  struct route_ipv6 *next;
126 127
   bool defined;
127 128
   struct in6_addr network;
128 129
   unsigned int netbits;
... ...
@@ -140,9 +140,8 @@ struct route_ipv6_list {
140 140
   bool remote_endpoint_defined;
141 141
   bool did_redirect_default_gateway;			/* TODO (?) */
142 142
   bool did_local;					/* TODO (?) */
143
-  int capacity;
144
-  int n;
145
-  struct route_ipv6 routes_ipv6[EMPTY_ARRAY_SIZE];
143
+  struct route_ipv6 *routes_ipv6;
144
+  struct gc_arena gc;
146 145
 };
147 146
 
148 147
 
... ...
@@ -188,9 +187,8 @@ struct route_list {
188 188
   struct route_special_addr spec;
189 189
   struct route_gateway_info rgi;
190 190
   unsigned int flags;     /* RG_x flags */
191
-  int capacity;
192
-  int n;
193
-  struct route_ipv4 routes[EMPTY_ARRAY_SIZE];
191
+  struct route_ipv4 *routes;
192
+  struct gc_arena gc;
194 193
 };
195 194
 
196 195
 #if P2MP
... ...
@@ -208,17 +206,15 @@ struct iroute_ipv6 {
208 208
 };
209 209
 #endif
210 210
 
211
-struct route_option_list *new_route_option_list (const int max_routes, struct gc_arena *a);
212
-struct route_ipv6_option_list *new_route_ipv6_option_list (const int max_routes, struct gc_arena *a);
211
+struct route_option_list *new_route_option_list (struct gc_arena *a);
212
+struct route_ipv6_option_list *new_route_ipv6_option_list (struct gc_arena *a);
213 213
 
214 214
 struct route_option_list *clone_route_option_list (const struct route_option_list *src, struct gc_arena *a);
215 215
 struct route_ipv6_option_list *clone_route_ipv6_option_list (const struct route_ipv6_option_list *src, struct gc_arena *a);
216
-void copy_route_option_list (struct route_option_list *dest, const struct route_option_list *src);
216
+void copy_route_option_list (struct route_option_list *dest, const struct route_option_list *src, struct gc_arena *a);
217 217
 void copy_route_ipv6_option_list (struct route_ipv6_option_list *dest,
218
-				  const struct route_ipv6_option_list *src);
219
-
220
-struct route_list *new_route_list (const int max_routes, struct gc_arena *a);
221
-struct route_ipv6_list *new_route_ipv6_list (const int max_routes, struct gc_arena *a);
218
+                                  const struct route_ipv6_option_list *src,
219
+                                  struct gc_arena *a);
222 220
 
223 221
 void add_route_ipv6 (struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es);
224 222
 void delete_route_ipv6 (const struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es);