summaryrefslogtreecommitdiff
path: root/accel-pppd/extra
diff options
context:
space:
mode:
authorVladislav Grishenko <themiron@mail.ru>2020-01-10 05:29:14 +0500
committerVladislav Grishenko <themiron@mail.ru>2020-01-10 05:42:16 +0500
commit8c9c91764069d3f6d3122c7897b05b0b93024246 (patch)
treecc6461cd7a5fcd2189d78dd33b9afae39e0146dd /accel-pppd/extra
parent385349450d42f6e1b92e08cabe97ed52cb740fab (diff)
downloadaccel-ppp-8c9c91764069d3f6d3122c7897b05b0b93024246.tar.gz
accel-ppp-8c9c91764069d3f6d3122c7897b05b0b93024246.zip
ipv6pool/radius: implement named ipv6 pools
default stateful ipv6 address & prefix radius attrs are per-rfc6911: 171 Delegated-IPv6-Prefix-Pool 172 Stateful-IPv6-Address-Pool the single pool name from chap-secret file pool is shared for ipv4/ipv6/ipv6 dp, new config syntax TBD. per-proto pool names are still for ipv4 only, new config syntax TBD.
Diffstat (limited to 'accel-pppd/extra')
-rw-r--r--accel-pppd/extra/chap-secrets.c6
-rw-r--r--accel-pppd/extra/ipv6pool.c304
2 files changed, 273 insertions, 37 deletions
diff --git a/accel-pppd/extra/chap-secrets.c b/accel-pppd/extra/chap-secrets.c
index 92cfb42f..2d8593c9 100644
--- a/accel-pppd/extra/chap-secrets.c
+++ b/accel-pppd/extra/chap-secrets.c
@@ -313,6 +313,12 @@ static struct ipv4db_item_t *get_ip(struct ap_session *ses)
if (ses->ipv4_pool_name)
_free(ses->ipv4_pool_name);
ses->ipv4_pool_name = _strdup(pd->pool);
+ if (ses->ipv6_pool_name)
+ _free(ses->ipv6_pool_name);
+ ses->ipv6_pool_name = _strdup(pd->pool);
+ if (ses->ipv6_dppool_name)
+ _free(ses->ipv6_dppool_name);
+ ses->ipv6_dppool_name = _strdup(pd->pool);
return NULL;
} else if (!pd->ip.peer_addr)
return NULL;
diff --git a/accel-pppd/extra/ipv6pool.c b/accel-pppd/extra/ipv6pool.c
index 4f29a280..f00dbcfa 100644
--- a/accel-pppd/extra/ipv6pool.c
+++ b/accel-pppd/extra/ipv6pool.c
@@ -8,31 +8,60 @@
#include <arpa/inet.h>
#include <endian.h>
+#include "events.h"
#include "ipdb.h"
#include "list.h"
#include "log.h"
#include "spinlock.h"
+#ifdef RADIUS
+#include "radius.h"
+#endif
+
#include "memdebug.h"
+enum ippool_type
+{
+ IPPOOL_ADDRESS,
+ IPPOOL_PREFIX
+};
+
+struct ippool_t
+{
+ struct list_head entry;
+ char *name;
+ struct list_head gw_list;
+ struct list_head items;
+ struct ippool_t *next;
+ spinlock_t lock;
+};
struct ippool_item_t
{
struct list_head entry;
+ struct ippool_t *pool;
struct ipv6db_item_t it;
};
struct dppool_item_t
{
struct list_head entry;
+ struct ippool_t *pool;
struct ipv6db_prefix_t it;
};
-static LIST_HEAD(ippool);
-static LIST_HEAD(dppool);
-static spinlock_t pool_lock;
+#ifdef RADIUS
+static int conf_vendor = 0;
+static int conf_dppool_attr = 171; // Delegated-IPv6-Prefix-Pool
+static int conf_ippool_attr = 172; // Stateful-IPv6-Address-Pool
+#endif
+
+static LIST_HEAD(ippool_list);
+static LIST_HEAD(dppool_list);
static struct ipdb_t ipdb;
static struct in6_addr conf_gw_addr;
+static struct ippool_t *def_ippool;
+static struct ippool_t *def_dppool;
static void in6_addr_add(struct in6_addr *res, const struct in6_addr *arg)
{
@@ -59,7 +88,40 @@ static int in6_addr_cmp(const struct in6_addr *n1, const struct in6_addr *n2)
return 0;
}
-static void generate_ippool(struct in6_addr *addr, int mask, int prefix_len)
+static struct ippool_t *create_pool(enum ippool_type type, char *name)
+{
+ struct ippool_t *pool = malloc(sizeof(*pool));
+ struct list_head *pool_list = (type == IPPOOL_PREFIX) ? &dppool_list : &ippool_list;
+
+ memset(pool, 0, sizeof(*pool));
+ pool->name = name;
+
+ INIT_LIST_HEAD(&pool->items);
+ spinlock_init(&pool->lock);
+
+ if (name)
+ list_add_tail(&pool->entry, pool_list);
+
+ return pool;
+}
+
+static struct ippool_t *find_pool(enum ippool_type type, char *name, int create)
+{
+ struct ippool_t *pool;
+ struct list_head *pool_list = (type == IPPOOL_PREFIX) ? &dppool_list : &ippool_list;
+
+ list_for_each_entry(pool, pool_list, entry) {
+ if (!strcmp(pool->name, name))
+ return pool;
+ }
+
+ if (create)
+ return create_pool(type, name);
+
+ return NULL;
+}
+
+static void generate_ippool(struct ippool_t *pool, struct in6_addr *addr, int mask, int prefix_len)
{
struct ippool_item_t *it;
struct ipv6db_addr_t *a;
@@ -84,6 +146,7 @@ static void generate_ippool(struct in6_addr *addr, int mask, int prefix_len)
while (in6_addr_cmp(&ip, &end) <= 0) {
it = malloc(sizeof(*it));
memset(it, 0, sizeof(*it));
+ it->pool = pool;
it->it.owner = &ipdb;
INIT_LIST_HEAD(&it->it.addr_list);
a = malloc(sizeof(*a));
@@ -91,12 +154,12 @@ static void generate_ippool(struct in6_addr *addr, int mask, int prefix_len)
memcpy(&a->addr, &ip, sizeof(ip));
a->prefix_len = prefix_len;
list_add_tail(&a->entry, &it->it.addr_list);
- list_add_tail(&it->entry, &ippool);
+ list_add_tail(&it->entry, &pool->items);
in6_addr_add(&ip, &step);
}
}
-static void generate_dppool(struct in6_addr *addr, int mask, int prefix_len)
+static void generate_dppool(struct ippool_t *pool, struct in6_addr *addr, int mask, int prefix_len)
{
struct dppool_item_t *it;
struct in6_addr ip, end, step;
@@ -121,6 +184,7 @@ static void generate_dppool(struct in6_addr *addr, int mask, int prefix_len)
while (in6_addr_cmp(&ip, &end) <= 0) {
it = malloc(sizeof(*it));
memset(it, 0, sizeof(*it));
+ it->pool = pool;
it->it.owner = &ipdb;
INIT_LIST_HEAD(&it->it.prefix_list);
a = malloc(sizeof(*a));
@@ -128,13 +192,12 @@ static void generate_dppool(struct in6_addr *addr, int mask, int prefix_len)
memcpy(&a->addr, &ip, sizeof(ip));
a->prefix_len = prefix_len;
list_add_tail(&a->entry, &it->it.prefix_list);
- list_add_tail(&it->entry, &dppool);
+ list_add_tail(&it->entry, &pool->items);
in6_addr_add(&ip, &step);
}
}
-
-static void add_prefix(int type, const char *_val)
+static void add_prefix(enum ippool_type type, struct ippool_t *pool, const char *_val)
{
char *val = _strdup(_val);
char *ptr1, *ptr2;
@@ -169,10 +232,10 @@ static void add_prefix(int type, const char *_val)
if (prefix_len > 128 || prefix_len < mask)
goto err;
- if (type)
- generate_dppool(&addr, mask, prefix_len);
+ if (type == IPPOOL_PREFIX)
+ generate_dppool(pool, &addr, mask, prefix_len);
else
- generate_ippool(&addr, mask, prefix_len);
+ generate_ippool(pool, &addr, mask, prefix_len);
_free(val);
return;
@@ -186,14 +249,24 @@ static struct ipv6db_item_t *get_ip(struct ap_session *ses)
{
struct ippool_item_t *it;
struct ipv6db_addr_t *a;
+ struct ippool_t *pool;
+
+ if (ses->ipv6_pool_name)
+ pool = find_pool(IPPOOL_ADDRESS, ses->ipv6_pool_name, 0);
+ else
+ pool = def_ippool;
+
+ if (!pool)
+ return NULL;
- spin_lock(&pool_lock);
- if (!list_empty(&ippool)) {
- it = list_entry(ippool.next, typeof(*it), entry);
+again:
+ spin_lock(&pool->lock);
+ if (!list_empty(&pool->items)) {
+ it = list_entry(pool->items.next, typeof(*it), entry);
list_del(&it->entry);
} else
it = NULL;
- spin_unlock(&pool_lock);
+ spin_unlock(&pool->lock);
if (it) {
a = list_entry(it->it.addr_list.next, typeof(*a), entry);
@@ -206,6 +279,9 @@ static struct ipv6db_item_t *get_ip(struct ap_session *ses)
}
return &it->it;
+ } else if (pool->next) {
+ pool = pool->next;
+ goto again;
}
return NULL;
@@ -215,33 +291,47 @@ static void put_ip(struct ap_session *ses, struct ipv6db_item_t *it)
{
struct ippool_item_t *pit = container_of(it, typeof(*pit), it);
- spin_lock(&pool_lock);
- list_add_tail(&pit->entry, &ippool);
- spin_unlock(&pool_lock);
+ spin_lock(&pit->pool->lock);
+ list_add_tail(&pit->entry, &pit->pool->items);
+ spin_unlock(&pit->pool->lock);
}
static struct ipv6db_prefix_t *get_dp(struct ap_session *ses)
{
struct dppool_item_t *it;
+ struct ippool_t *pool;
- spin_lock(&pool_lock);
- if (!list_empty(&dppool)) {
- it = list_entry(dppool.next, typeof(*it), entry);
+ if (ses->ipv6_pool_name)
+ pool = find_pool(IPPOOL_PREFIX, ses->ipv6_dppool_name, 0);
+ else
+ pool = def_dppool;
+
+again:
+ spin_lock(&pool->lock);
+ if (!list_empty(&pool->items)) {
+ it = list_entry(pool->items.next, typeof(*it), entry);
list_del(&it->entry);
} else
it = NULL;
- spin_unlock(&pool_lock);
+ spin_unlock(&pool->lock);
- return it ? &it->it : NULL;
+ if (it)
+ return &it->it;
+ else if (pool->next) {
+ pool = pool->next;
+ goto again;
+ }
+
+ return NULL;
}
static void put_dp(struct ap_session *ses, struct ipv6db_prefix_t *it)
{
struct dppool_item_t *pit = container_of(it, typeof(*pit), it);
- spin_lock(&pool_lock);
- list_add_tail(&pit->entry, &dppool);
- spin_unlock(&pool_lock);
+ spin_lock(&pit->pool->lock);
+ list_add_tail(&pit->entry, &pit->pool->items);
+ spin_unlock(&pit->pool->lock);
}
static struct ipdb_t ipdb = {
@@ -251,28 +341,168 @@ static struct ipdb_t ipdb = {
.put_ipv6_prefix = put_dp,
};
-static void ippool_init(void)
+#ifdef RADIUS
+static void ev_radius_access_accept(struct ev_radius_t *ev)
+{
+ struct rad_attr_t *attr;
+ struct ap_session *ses = ev->ses;
+
+ list_for_each_entry(attr, &ev->reply->attrs, entry) {
+ if (attr->attr->type != ATTR_TYPE_STRING)
+ continue;
+ if (attr->vendor && attr->vendor->id != conf_vendor)
+ continue;
+ if (!attr->vendor && conf_vendor)
+ continue;
+
+ if (conf_dppool_attr && conf_dppool_attr == attr->attr->id) {
+ if (ses->ipv6_dppool_name)
+ _free(ses->ipv6_dppool_name);
+ ses->ipv6_dppool_name = _strdup(attr->val.string);
+ } else
+ if (conf_ippool_attr && conf_ippool_attr == attr->attr->id) {
+ if (ses->ipv6_pool_name)
+ _free(ses->ipv6_pool_name);
+ ses->ipv6_pool_name = _strdup(attr->val.string);
+ }
+ }
+}
+
+static int parse_attr_opt(const char *opt)
+{
+ struct rad_dict_attr_t *attr;
+ struct rad_dict_vendor_t *vendor;
+
+ if (conf_vendor)
+ vendor = rad_dict_find_vendor_id(conf_vendor);
+ else
+ vendor = NULL;
+
+ if (conf_vendor) {
+ if (vendor)
+ attr = rad_dict_find_vendor_attr(vendor, opt);
+ else
+ attr = NULL;
+ } else
+ attr = rad_dict_find_attr(opt);
+
+ if (attr)
+ return attr->id;
+
+ return atoi(opt);
+}
+
+static int parse_vendor_opt(const char *opt)
+{
+ struct rad_dict_vendor_t *vendor;
+
+ vendor = rad_dict_find_vendor_name(opt);
+ if (vendor)
+ return vendor->id;
+
+ return atoi(opt);
+}
+#endif
+
+static void parse_options(enum ippool_type type, const char *opt, char **pool_name, struct ippool_t **next)
+{
+ char *ptr1, *ptr2, *tmp;
+
+ ptr1 = strstr(opt, ",name=");
+ if (ptr1) {
+ ptr1 += sizeof(",name=") - 1;
+ ptr2 = strchrnul(ptr1, ',');
+ *pool_name = _strndup(ptr1, ptr2 - ptr1);
+ }
+
+ ptr1 = strstr(opt, ",next=");
+ if (ptr1) {
+ ptr1 += sizeof(",next=") - 1;
+ ptr2 = strchrnul(ptr1, ',');
+ if (*ptr2 == ',') {
+ tmp = alloca(ptr2 - ptr1 + 1);
+ strncpy(tmp, ptr1, ptr2 - ptr1);
+ ptr1 = tmp;
+ }
+ *next = find_pool(type, ptr1, 0);
+ if (!(*next))
+ log_error("ipv6_pool: %s: next pool not found\n", opt);
+ }
+}
+
+static void ippool_init1(void)
+{
+ ipdb_register(&ipdb);
+}
+
+static void ippool_init2(void)
{
struct conf_sect_t *s = conf_get_section("ipv6-pool");
struct conf_option_t *opt;
-
- spinlock_init(&pool_lock);
+ struct ippool_t *pool, *next;
+ char *pool_name, *val;
+ enum ippool_type type;
+#ifdef RADIUS
+ int dppool_attr = 0, ippool_attr = 0;
+#endif
if (!s)
return;
+ def_ippool = create_pool(IPPOOL_ADDRESS, NULL);
+ def_dppool = create_pool(IPPOOL_PREFIX, NULL);
+
list_for_each_entry(opt, &s->items, entry) {
+#ifdef RADIUS
+ if (triton_module_loaded("radius")) {
+ if (!strcmp(opt->name, "vendor")) {
+ conf_vendor = parse_vendor_opt(opt->val);
+ continue;
+ }
+ if (!strcmp(opt->name, "attr-prefix")) {
+ dppool_attr = parse_attr_opt(opt->val);
+ continue;
+ }
+ if (!strcmp(opt->name, "attr-address")) {
+ ippool_attr = parse_attr_opt(opt->val);
+ continue;
+ }
+ }
+#endif
if (!strcmp(opt->name, "gw-ip6-address")) {
if (inet_pton(AF_INET6, opt->val, &conf_gw_addr) == 0)
log_error("ipv6_pool: failed to parse gw-ip6-address\n");
- } else if (!strcmp(opt->name, "delegate"))
- add_prefix(1, opt->val);
- else
- add_prefix(0, opt->name);
+ continue;
+ } else if (!strcmp(opt->name, "delegate")) {
+ type = IPPOOL_PREFIX;
+ val = opt->val;
+ pool = def_dppool;
+ } else {
+ type = IPPOOL_ADDRESS;
+ val = opt->name;
+ pool = def_ippool;
+ }
+
+ pool_name = NULL;
+ parse_options(type, opt->raw, &pool_name, &next);
+
+ if (pool_name)
+ pool = find_pool(type, pool_name, 1);
+ add_prefix(type, pool, val);
+
+ pool->next = next;
}
- ipdb_register(&ipdb);
+#ifdef RADIUS
+ if (triton_module_loaded("radius")) {
+ if (conf_vendor || dppool_attr)
+ conf_dppool_attr = dppool_attr;
+ if (conf_vendor || ippool_attr)
+ conf_ippool_attr = ippool_attr;
+ triton_event_register_handler(EV_RADIUS_ACCESS_ACCEPT, (triton_event_func)ev_radius_access_accept);
+ }
+#endif
}
-DEFINE_INIT(51, ippool_init);
-
+DEFINE_INIT(51, ippool_init1);
+DEFINE_INIT2(52, ippool_init2);