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