1/*
2 *  OpenVPN -- An application to securely tunnel IP networks
3 *             over a single TCP/UDP port, with support for SSL/TLS-based
4 *             session authentication and key exchange,
5 *             packet encryption, packet authentication, and
6 *             packet compression.
7 *
8 *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
9 *
10 *  This program is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 2
12 *  as published by the Free Software Foundation.
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this program (see the file COPYING included with this
21 *  distribution); if not, write to the Free Software Foundation, Inc.,
22 *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#elif defined(_MSC_VER)
28#include "config-msvc.h"
29#endif
30
31#include "syshead.h"
32
33#include "pool.h"
34#include "buffer.h"
35#include "error.h"
36#include "socket.h"
37#include "otime.h"
38
39#include "memdbg.h"
40
41#if P2MP
42
43static void
44ifconfig_pool_entry_free (struct ifconfig_pool_entry *ipe, bool hard)
45{
46  ipe->in_use = false;
47  if (hard && ipe->common_name)
48    {
49      free (ipe->common_name);
50      ipe->common_name = NULL;
51    }
52  if (hard)
53    ipe->last_release = 0;
54  else
55    ipe->last_release = now;
56}
57
58static int
59ifconfig_pool_find (struct ifconfig_pool *pool, const char *common_name)
60{
61  int i;
62  time_t earliest_release = 0;
63  int previous_usage = -1;
64  int new_usage = -1;
65
66  for (i = 0; i < pool->size; ++i)
67    {
68      struct ifconfig_pool_entry *ipe = &pool->list[i];
69      if (!ipe->in_use)
70	{
71	  /*
72	   * If duplicate_cn mode, take first available IP address
73	   */
74	  if (pool->duplicate_cn)
75	    {
76	      new_usage = i;
77	      break;
78	    }
79
80	  /*
81	   * Keep track of the unused IP address entry which
82	   * was released earliest.
83	   */
84	  if ((new_usage == -1 || ipe->last_release < earliest_release) && !ipe->fixed)
85	    {
86	      earliest_release = ipe->last_release;
87	      new_usage = i;
88	    }
89
90	  /*
91	   * Keep track of a possible allocation to us
92	   * from an earlier session.
93	   */
94	  if (previous_usage < 0
95	      && common_name
96	      && ipe->common_name
97	      && !strcmp (common_name, ipe->common_name))
98	    previous_usage = i;
99
100	}
101    }
102
103  if (previous_usage >= 0)
104    return previous_usage;
105
106  if (new_usage >= 0)
107    return new_usage;
108
109  return -1;
110}
111
112/*
113 * Verify start/end range
114 */
115bool
116ifconfig_pool_verify_range (const int msglevel, const in_addr_t start, const in_addr_t end)
117{
118  struct gc_arena gc = gc_new ();
119  bool ret = true;
120
121  if (start > end)
122    {
123      msg (msglevel, "--ifconfig-pool start IP [%s] is greater than end IP [%s]",
124	   print_in_addr_t (start, 0, &gc),
125	   print_in_addr_t (end, 0, &gc));
126      ret = false;
127    }
128  if (end - start >= IFCONFIG_POOL_MAX)
129    {
130      msg (msglevel, "--ifconfig-pool address range is too large [%s -> %s].  Current maximum is %d addresses, as defined by IFCONFIG_POOL_MAX variable.",
131	   print_in_addr_t (start, 0, &gc),
132	   print_in_addr_t (end, 0, &gc),
133	   IFCONFIG_POOL_MAX);
134      ret = false;
135    }
136  gc_free (&gc);
137  return ret;
138}
139
140struct ifconfig_pool *
141ifconfig_pool_init (int type, in_addr_t start, in_addr_t end,
142		    const bool duplicate_cn,
143		    const bool ipv6_pool, const struct in6_addr ipv6_base,
144		    const int ipv6_netbits )
145{
146  struct gc_arena gc = gc_new ();
147  struct ifconfig_pool *pool = NULL;
148
149  ASSERT (start <= end && end - start < IFCONFIG_POOL_MAX);
150  ALLOC_OBJ_CLEAR (pool, struct ifconfig_pool);
151
152  pool->type = type;
153  pool->duplicate_cn = duplicate_cn;
154
155  switch (type)
156    {
157    case IFCONFIG_POOL_30NET:
158      pool->base = start & ~3;
159      pool->size = (((end | 3) + 1) - pool->base) >> 2;
160      break;
161    case IFCONFIG_POOL_INDIV:
162      pool->base = start;
163      pool->size = end - start + 1;
164      break;
165    default:
166      ASSERT (0);
167    }
168
169  /* IPv6 pools are always "INDIV" type */
170  pool->ipv6 = ipv6_pool;
171
172  if ( pool->ipv6 )
173    {
174      pool->base_ipv6 = ipv6_base;
175      pool->size_ipv6 = ipv6_netbits>96? ( 1<<(128-ipv6_netbits) )
176				       : IFCONFIG_POOL_MAX;
177
178      msg( D_IFCONFIG_POOL, "IFCONFIG POOL IPv6: (IPv4) size=%d, size_ipv6=%d, netbits=%d, base_ipv6=%s",
179			    pool->size, pool->size_ipv6, ipv6_netbits,
180			    print_in6_addr( pool->base_ipv6, 0, &gc ));
181
182      /* the current code is very simple and assumes that the IPv6
183       * pool is at least as big as the IPv4 pool, and we don't need
184       * to do separate math etc. for IPv6
185       */
186      ASSERT( pool->size < pool->size_ipv6 );
187    }
188
189  ALLOC_ARRAY_CLEAR (pool->list, struct ifconfig_pool_entry, pool->size);
190
191  msg (D_IFCONFIG_POOL, "IFCONFIG POOL: base=%s size=%d, ipv6=%d",
192       print_in_addr_t (pool->base, 0, &gc),
193       pool->size, pool->ipv6 );
194
195  gc_free (&gc);
196  return pool;
197}
198
199void
200ifconfig_pool_free (struct ifconfig_pool *pool)
201{
202  if (pool)
203    {
204      int i;
205      for (i = 0; i < pool->size; ++i)
206	ifconfig_pool_entry_free (&pool->list[i], true);
207      free (pool->list);
208      free (pool);
209    }
210}
211
212ifconfig_pool_handle
213ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, struct in6_addr *remote_ipv6, const char *common_name)
214{
215  int i;
216
217  i = ifconfig_pool_find (pool, common_name);
218  if (i >= 0)
219    {
220      struct ifconfig_pool_entry *ipe = &pool->list[i];
221      ASSERT (!ipe->in_use);
222      ifconfig_pool_entry_free (ipe, true);
223      ipe->in_use = true;
224      if (common_name)
225	ipe->common_name = string_alloc (common_name, NULL);
226
227      switch (pool->type)
228	{
229	case IFCONFIG_POOL_30NET:
230	  {
231	    in_addr_t b = pool->base + (i << 2);
232	    *local = b + 1;
233	    *remote = b + 2;
234	    break;
235	  }
236	case IFCONFIG_POOL_INDIV:
237	  {
238	    in_addr_t b = pool->base + i;
239	    *local = 0;
240	    *remote = b;
241	    break;
242	  }
243	default:
244	  ASSERT (0);
245	}
246
247      /* IPv6 pools are always INDIV (--linear) */
248      if ( pool->ipv6 && remote_ipv6 )
249	{
250	  *remote_ipv6 = add_in6_addr( pool->base_ipv6, i );
251	}
252    }
253  return i;
254}
255
256bool
257ifconfig_pool_release (struct ifconfig_pool* pool, ifconfig_pool_handle hand, const bool hard)
258{
259  bool ret = false;
260  if (pool && hand >= 0 && hand < pool->size)
261    {
262      ifconfig_pool_entry_free (&pool->list[hand], hard);
263      ret = true;
264    }
265  return ret;
266}
267
268/*
269 * private access functions
270 */
271
272static ifconfig_pool_handle
273ifconfig_pool_ip_base_to_handle (const struct ifconfig_pool* pool, const in_addr_t addr)
274{
275  ifconfig_pool_handle ret = -1;
276
277  switch (pool->type)
278    {
279    case IFCONFIG_POOL_30NET:
280      {
281	ret = (addr - pool->base) >> 2;
282	break;
283      }
284    case IFCONFIG_POOL_INDIV:
285      {
286	ret = (addr - pool->base);
287	break;
288      }
289    default:
290      ASSERT (0);
291    }
292
293  if (ret < 0 || ret >= pool->size)
294    ret = -1;
295
296  return ret;
297}
298
299static in_addr_t
300ifconfig_pool_handle_to_ip_base (const struct ifconfig_pool* pool, ifconfig_pool_handle hand)
301{
302  in_addr_t ret = 0;
303
304  if (hand >= 0 && hand < pool->size)
305    {
306      switch (pool->type)
307	{
308	case IFCONFIG_POOL_30NET:
309	  {
310	    ret = pool->base + (hand << 2);;
311	    break;
312	  }
313	case IFCONFIG_POOL_INDIV:
314	  {
315	    ret = pool->base + hand;
316	    break;
317	  }
318	default:
319	  ASSERT (0);
320	}
321    }
322
323  return ret;
324}
325
326static struct in6_addr
327ifconfig_pool_handle_to_ipv6_base (const struct ifconfig_pool* pool, ifconfig_pool_handle hand)
328{
329  struct in6_addr ret = in6addr_any;
330
331  /* IPv6 pools are always INDIV (--linear) */
332  if (hand >= 0 && hand < pool->size_ipv6 )
333    {
334      ret = add_in6_addr( pool->base_ipv6, hand );
335    }
336  return ret;
337}
338
339static void
340ifconfig_pool_set (struct ifconfig_pool* pool, const char *cn, const in_addr_t addr, const bool fixed)
341{
342  ifconfig_pool_handle h = ifconfig_pool_ip_base_to_handle (pool, addr);
343  if (h >= 0)
344    {
345      struct ifconfig_pool_entry *e = &pool->list[h];
346      ifconfig_pool_entry_free (e, true);
347      e->in_use = false;
348      e->common_name = string_alloc (cn, NULL);
349      e->last_release = now;
350      e->fixed = fixed;
351    }
352}
353
354static void
355ifconfig_pool_list (const struct ifconfig_pool* pool, struct status_output *out)
356{
357  if (pool && out)
358    {
359      struct gc_arena gc = gc_new ();
360      int i;
361
362      for (i = 0; i < pool->size; ++i)
363	{
364	  const struct ifconfig_pool_entry *e = &pool->list[i];
365	  if (e->common_name)
366	    {
367	      const in_addr_t ip = ifconfig_pool_handle_to_ip_base (pool, i);
368	      if ( pool->ipv6 )
369		{
370		  struct in6_addr ip6 = ifconfig_pool_handle_to_ipv6_base (pool, i);
371		  status_printf (out, "%s,%s,%s",
372				 e->common_name,
373				 print_in_addr_t (ip, 0, &gc),
374				 print_in6_addr (ip6, 0, &gc));
375		}
376	      else
377		{
378		  status_printf (out, "%s,%s",
379				 e->common_name,
380				 print_in_addr_t (ip, 0, &gc));
381		}
382	    }
383	}
384      gc_free (&gc);
385    }
386}
387
388static void
389ifconfig_pool_msg (const struct ifconfig_pool* pool, int msglevel)
390{
391  struct status_output *so = status_open (NULL, 0, msglevel, NULL, 0);
392  ASSERT (so);
393  status_printf (so, "IFCONFIG POOL LIST");
394  ifconfig_pool_list (pool, so);
395  status_close (so);
396}
397
398/*
399 * Deal with reading/writing the ifconfig pool database to a file
400 */
401
402struct ifconfig_pool_persist *
403ifconfig_pool_persist_init (const char *filename, int refresh_freq)
404{
405  struct ifconfig_pool_persist *ret;
406
407  ASSERT (filename);
408
409  ALLOC_OBJ_CLEAR (ret, struct ifconfig_pool_persist);
410  if (refresh_freq > 0)
411    {
412      ret->fixed = false;
413      ret->file = status_open (filename, refresh_freq, -1, NULL, STATUS_OUTPUT_READ|STATUS_OUTPUT_WRITE);
414    }
415  else
416    {
417      ret->fixed = true;
418      ret->file = status_open (filename, 0, -1, NULL, STATUS_OUTPUT_READ);
419    }
420  return ret;
421}
422
423void
424ifconfig_pool_persist_close (struct ifconfig_pool_persist *persist)
425{
426  if (persist)
427    {
428      if (persist->file)
429	status_close (persist->file);
430      free (persist);
431    }
432}
433
434bool
435ifconfig_pool_write_trigger (struct ifconfig_pool_persist *persist)
436{
437  if (persist->file)
438    return status_trigger (persist->file);
439  else
440    return false;
441}
442
443void
444ifconfig_pool_read (struct ifconfig_pool_persist *persist, struct ifconfig_pool *pool)
445{
446  const int buf_size = 128;
447
448  update_time ();
449  if (persist && persist->file && pool)
450    {
451      struct gc_arena gc = gc_new ();
452      struct buffer in = alloc_buf_gc (256, &gc);
453      char *cn_buf;
454      char *ip_buf;
455      int line = 0;
456
457      ALLOC_ARRAY_CLEAR_GC (cn_buf, char, buf_size, &gc);
458      ALLOC_ARRAY_CLEAR_GC (ip_buf, char, buf_size, &gc);
459
460      while (true)
461	{
462	  ASSERT (buf_init (&in, 0));
463	  if (!status_read (persist->file, &in))
464	    break;
465	  ++line;
466	  if (BLEN (&in))
467	    {
468	      int c = *BSTR(&in);
469	      if (c == '#' || c == ';')
470		continue;
471	      msg( M_INFO, "ifconfig_pool_read(), in='%s', TODO: IPv6",
472				BSTR(&in) );
473
474	      if (buf_parse (&in, ',', cn_buf, buf_size)
475		  && buf_parse (&in, ',', ip_buf, buf_size))
476		{
477		  bool succeeded;
478		  const in_addr_t addr = getaddr (GETADDR_HOST_ORDER, ip_buf, 0, &succeeded, NULL);
479		  if (succeeded)
480		    {
481		      msg( M_INFO, "succeeded -> ifconfig_pool_set()");
482		      ifconfig_pool_set (pool, cn_buf, addr, persist->fixed);
483		    }
484		}
485	    }
486	}
487
488      ifconfig_pool_msg (pool, D_IFCONFIG_POOL);
489
490      gc_free (&gc);
491    }
492}
493
494void
495ifconfig_pool_write (struct ifconfig_pool_persist *persist, const struct ifconfig_pool *pool)
496{
497  if (persist && persist->file && (status_rw_flags (persist->file) & STATUS_OUTPUT_WRITE) && pool)
498    {
499      status_reset (persist->file);
500      ifconfig_pool_list (pool, persist->file);
501      status_flush (persist->file);
502    }
503}
504
505/*
506 * TESTING ONLY
507 */
508
509#ifdef IFCONFIG_POOL_TEST
510
511#define DUP_CN
512
513void
514ifconfig_pool_test (in_addr_t start, in_addr_t end)
515{
516  struct gc_arena gc = gc_new ();
517  struct ifconfig_pool *p = ifconfig_pool_init (IFCONFIG_POOL_30NET, start, end);
518  /*struct ifconfig_pool *p = ifconfig_pool_init (IFCONFIG_POOL_INDIV, start, end);*/
519  ifconfig_pool_handle array[256];
520  int i;
521
522  CLEAR (array);
523
524  msg (M_INFO | M_NOPREFIX, "************ 1");
525  for (i = 0; i < (int) SIZE (array); ++i)
526    {
527      char *cn;
528      ifconfig_pool_handle h;
529      in_addr_t local, remote;
530      char buf[256];
531      openvpn_snprintf (buf, sizeof(buf), "common-name-%d", i);
532#ifdef DUP_CN
533      cn = NULL;
534#else
535      cn = buf;
536#endif
537      h = ifconfig_pool_acquire (p, &local, &remote, NULL, cn);
538      if (h < 0)
539	break;
540      msg (M_INFO | M_NOPREFIX, "IFCONFIG_POOL TEST pass 1: l=%s r=%s cn=%s",
541	   print_in_addr_t (local, 0, &gc),
542	   print_in_addr_t (remote, 0, &gc),
543	   cn);
544      array[i] = h;
545
546    }
547
548  msg (M_INFO | M_NOPREFIX, "************* 2");
549  for (i = (int) SIZE (array) / 16; i < (int) SIZE (array) / 8; ++i)
550    {
551      msg (M_INFO, "Attempt to release %d cn=%s", array[i], p->list[i].common_name);
552      if (!ifconfig_pool_release (p, array[i]))
553	break;
554      msg (M_INFO, "Succeeded");
555    }
556
557  CLEAR (array);
558
559  msg (M_INFO | M_NOPREFIX, "**************** 3");
560  for (i = 0; i < (int) SIZE (array); ++i)
561    {
562      char *cn;
563      ifconfig_pool_handle h;
564      in_addr_t local, remote;
565      char buf[256];
566      snprintf (buf, sizeof(buf), "common-name-%d", i+24);
567#ifdef DUP_CN
568      cn = NULL;
569#else
570      cn = buf;
571#endif
572      h = ifconfig_pool_acquire (p, &local, &remote, NULL, cn);
573      if (h < 0)
574	break;
575      msg (M_INFO | M_NOPREFIX, "IFCONFIG_POOL TEST pass 3: l=%s r=%s cn=%s",
576	   print_in_addr_t (local, 0, &gc),
577	   print_in_addr_t (remote, 0, &gc),
578	   cn);
579      array[i] = h;
580
581    }
582
583  ifconfig_pool_free (p);
584  gc_free (&gc);
585}
586
587#endif
588
589#endif
590