6fbf66fa |
struct ifconfig_pool *
ifconfig_pool_init (int type, in_addr_t start, in_addr_t end, const bool duplicate_cn)
{
struct gc_arena gc = gc_new ();
struct ifconfig_pool *pool = NULL;
ASSERT (start <= end && end - start < IFCONFIG_POOL_MAX);
ALLOC_OBJ_CLEAR (pool, struct ifconfig_pool);
pool->type = type;
pool->duplicate_cn = duplicate_cn;
switch (type)
{
case IFCONFIG_POOL_30NET:
pool->base = start & ~3;
pool->size = (((end | 3) + 1) - pool->base) >> 2;
break;
case IFCONFIG_POOL_INDIV:
pool->base = start;
pool->size = end - start + 1;
break;
default:
ASSERT (0);
}
ALLOC_ARRAY_CLEAR (pool->list, struct ifconfig_pool_entry, pool->size);
msg (D_IFCONFIG_POOL, "IFCONFIG POOL: base=%s size=%d",
print_in_addr_t (pool->base, 0, &gc),
pool->size);
gc_free (&gc);
return pool;
}
void
ifconfig_pool_free (struct ifconfig_pool *pool)
{
if (pool)
{
int i;
for (i = 0; i < pool->size; ++i)
ifconfig_pool_entry_free (&pool->list[i], true);
free (pool->list);
free (pool);
}
}
ifconfig_pool_handle
ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, const char *common_name)
{
int i;
i = ifconfig_pool_find (pool, common_name);
if (i >= 0)
{
struct ifconfig_pool_entry *ipe = &pool->list[i];
ASSERT (!ipe->in_use);
ifconfig_pool_entry_free (ipe, true);
ipe->in_use = true;
if (common_name)
ipe->common_name = string_alloc (common_name, NULL);
switch (pool->type)
{
case IFCONFIG_POOL_30NET:
{
in_addr_t b = pool->base + (i << 2);
*local = b + 1;
*remote = b + 2;
break;
}
case IFCONFIG_POOL_INDIV:
{
in_addr_t b = pool->base + i;
*local = 0;
*remote = b;
break;
}
default:
ASSERT (0);
}
}
return i;
}
bool
ifconfig_pool_release (struct ifconfig_pool* pool, ifconfig_pool_handle hand, const bool hard)
{
bool ret = false;
if (pool && hand >= 0 && hand < pool->size)
{
ifconfig_pool_entry_free (&pool->list[hand], hard);
ret = true;
}
return ret;
}
/*
* private access functions
*/
static ifconfig_pool_handle
ifconfig_pool_ip_base_to_handle (const struct ifconfig_pool* pool, const in_addr_t addr)
{
ifconfig_pool_handle ret = -1;
switch (pool->type)
{
case IFCONFIG_POOL_30NET:
{
ret = (addr - pool->base) >> 2;
break;
}
case IFCONFIG_POOL_INDIV:
{
ret = (addr - pool->base);
break;
}
default:
ASSERT (0);
}
if (ret < 0 || ret >= pool->size)
ret = -1;
return ret;
}
static in_addr_t
ifconfig_pool_handle_to_ip_base (const struct ifconfig_pool* pool, ifconfig_pool_handle hand)
{
in_addr_t ret = 0;
if (hand >= 0 && hand < pool->size)
{
switch (pool->type)
{
case IFCONFIG_POOL_30NET:
{
ret = pool->base + (hand << 2);;
break;
}
case IFCONFIG_POOL_INDIV:
{
ret = pool->base + hand;
break;
}
default:
ASSERT (0);
}
}
return ret;
}
static void
ifconfig_pool_set (struct ifconfig_pool* pool, const char *cn, const in_addr_t addr, const bool fixed)
{
ifconfig_pool_handle h = ifconfig_pool_ip_base_to_handle (pool, addr);
if (h >= 0)
{
struct ifconfig_pool_entry *e = &pool->list[h];
ifconfig_pool_entry_free (e, true);
e->in_use = false;
e->common_name = string_alloc (cn, NULL);
e->last_release = now;
e->fixed = fixed;
}
}
static void
ifconfig_pool_list (const struct ifconfig_pool* pool, struct status_output *out)
{
if (pool && out)
{
struct gc_arena gc = gc_new ();
int i;
for (i = 0; i < pool->size; ++i)
{
const struct ifconfig_pool_entry *e = &pool->list[i];
if (e->common_name)
{
const in_addr_t ip = ifconfig_pool_handle_to_ip_base (pool, i);
status_printf (out, "%s,%s",
e->common_name,
print_in_addr_t (ip, 0, &gc));
}
}
gc_free (&gc);
}
}
static void
ifconfig_pool_msg (const struct ifconfig_pool* pool, int msglevel)
{
struct status_output *so = status_open (NULL, 0, msglevel, NULL, 0);
ASSERT (so);
status_printf (so, "IFCONFIG POOL LIST");
ifconfig_pool_list (pool, so);
status_close (so);
}
/*
* Deal with reading/writing the ifconfig pool database to a file
*/
struct ifconfig_pool_persist *
ifconfig_pool_persist_init (const char *filename, int refresh_freq)
{
struct ifconfig_pool_persist *ret;
ASSERT (filename);
ALLOC_OBJ_CLEAR (ret, struct ifconfig_pool_persist);
if (refresh_freq > 0)
{
ret->fixed = false;
ret->file = status_open (filename, refresh_freq, -1, NULL, STATUS_OUTPUT_READ|STATUS_OUTPUT_WRITE);
}
else
{
ret->fixed = true;
ret->file = status_open (filename, 0, -1, NULL, STATUS_OUTPUT_READ);
}
return ret;
}
void
ifconfig_pool_persist_close (struct ifconfig_pool_persist *persist)
{
if (persist)
{
if (persist->file)
status_close (persist->file);
free (persist);
}
}
bool
ifconfig_pool_write_trigger (struct ifconfig_pool_persist *persist)
{
if (persist->file)
return status_trigger (persist->file);
else
return false;
}
void
ifconfig_pool_read (struct ifconfig_pool_persist *persist, struct ifconfig_pool *pool)
{
const int buf_size = 128;
update_time ();
if (persist && persist->file && pool)
{
struct gc_arena gc = gc_new ();
struct buffer in = alloc_buf_gc (256, &gc);
char *cn_buf;
char *ip_buf;
int line = 0;
ALLOC_ARRAY_CLEAR_GC (cn_buf, char, buf_size, &gc);
ALLOC_ARRAY_CLEAR_GC (ip_buf, char, buf_size, &gc);
while (true)
{
ASSERT (buf_init (&in, 0));
if (!status_read (persist->file, &in))
break;
++line;
if (BLEN (&in))
{
int c = *BSTR(&in);
if (c == '#' || c == ';')
continue;
if (buf_parse (&in, ',', cn_buf, buf_size)
&& buf_parse (&in, ',', ip_buf, buf_size))
{
bool succeeded;
const in_addr_t addr = getaddr (GETADDR_HOST_ORDER, ip_buf, 0, &succeeded, NULL);
if (succeeded)
{
ifconfig_pool_set (pool, cn_buf, addr, persist->fixed);
}
}
}
}
ifconfig_pool_msg (pool, D_IFCONFIG_POOL);
gc_free (&gc);
}
}
void
ifconfig_pool_write (struct ifconfig_pool_persist *persist, const struct ifconfig_pool *pool)
{
if (persist && persist->file && (status_rw_flags (persist->file) & STATUS_OUTPUT_WRITE) && pool)
{
status_reset (persist->file);
ifconfig_pool_list (pool, persist->file);
status_flush (persist->file);
}
}
/*
* TESTING ONLY
*/
#ifdef IFCONFIG_POOL_TEST
#define DUP_CN
void
ifconfig_pool_test (in_addr_t start, in_addr_t end)
{
struct gc_arena gc = gc_new ();
struct ifconfig_pool *p = ifconfig_pool_init (IFCONFIG_POOL_30NET, start, end);
/*struct ifconfig_pool *p = ifconfig_pool_init (IFCONFIG_POOL_INDIV, start, end);*/
ifconfig_pool_handle array[256];
int i;
CLEAR (array);
msg (M_INFO | M_NOPREFIX, "************ 1");
for (i = 0; i < (int) SIZE (array); ++i)
{
char *cn;
ifconfig_pool_handle h;
in_addr_t local, remote;
char buf[256];
openvpn_snprintf (buf, sizeof(buf), "common-name-%d", i);
#ifdef DUP_CN
cn = NULL;
#else
cn = buf;
#endif
h = ifconfig_pool_acquire (p, &local, &remote, cn);
if (h < 0)
break;
msg (M_INFO | M_NOPREFIX, "IFCONFIG_POOL TEST pass 1: l=%s r=%s cn=%s",
print_in_addr_t (local, 0, &gc),
print_in_addr_t (remote, 0, &gc),
cn);
array[i] = h;
}
msg (M_INFO | M_NOPREFIX, "************* 2");
for (i = (int) SIZE (array) / 16; i < (int) SIZE (array) / 8; ++i)
{
msg (M_INFO, "Attempt to release %d cn=%s", array[i], p->list[i].common_name);
if (!ifconfig_pool_release (p, array[i]))
break;
msg (M_INFO, "Succeeded");
}
CLEAR (array);
msg (M_INFO | M_NOPREFIX, "**************** 3");
for (i = 0; i < (int) SIZE (array); ++i)
{
char *cn;
ifconfig_pool_handle h;
in_addr_t local, remote;
char buf[256];
snprintf (buf, sizeof(buf), "common-name-%d", i+24);
#ifdef DUP_CN
cn = NULL;
#else
cn = buf;
#endif
h = ifconfig_pool_acquire (p, &local, &remote, cn);
if (h < 0)
break;
msg (M_INFO | M_NOPREFIX, "IFCONFIG_POOL TEST pass 3: l=%s r=%s cn=%s",
print_in_addr_t (local, 0, &gc),
print_in_addr_t (remote, 0, &gc),
cn);
array[i] = h;
}
ifconfig_pool_free (p);
gc_free (&gc);
}
#endif
#endif |