summaryrefslogtreecommitdiff
path: root/accel-pppd
diff options
context:
space:
mode:
Diffstat (limited to 'accel-pppd')
-rw-r--r--accel-pppd/accel-ppp.conf7
-rw-r--r--accel-pppd/accel-ppp.conf.525
-rw-r--r--accel-pppd/extra/chap-secrets.c6
-rw-r--r--accel-pppd/extra/ipv6pool.c304
-rw-r--r--accel-pppd/include/ap_session.h1
-rw-r--r--accel-pppd/radius/attr_defs.h5
-rw-r--r--accel-pppd/radius/dict.c2
-rw-r--r--accel-pppd/radius/dict/dictionary1
-rw-r--r--accel-pppd/radius/dict/dictionary.rfc691112
-rw-r--r--accel-pppd/session.c5
10 files changed, 321 insertions, 47 deletions
diff --git a/accel-pppd/accel-ppp.conf b/accel-pppd/accel-ppp.conf
index 7f341b6..acdbe4f 100644
--- a/accel-pppd/accel-ppp.conf
+++ b/accel-pppd/accel-ppp.conf
@@ -289,8 +289,15 @@ timeout=60
[ipv6-pool]
#gw-ip6-address=fc00:0:1::1
+#vendor=
+#prefix-attr=Delegated-IPv6-Prefix-Pool
+#address-attr=Stateful-IPv6-Address-Pool
fc00:0:1::/48,64
+fc00:0:2::/48,64,pool=pool1
+fc00:0:3::/48,64,pool=pool2,next=pool1
delegate=fc00:1::/36,48
+delegate=fc00:2::/36,48,pool=pool3
+delegate=fc00:3::/36,48,pool=pool4,next=pool3
[ipv6-dns]
#fc00:1::1
diff --git a/accel-pppd/accel-ppp.conf.5 b/accel-pppd/accel-ppp.conf.5
index 982bbd1..3e6312f 100644
--- a/accel-pppd/accel-ppp.conf.5
+++ b/accel-pppd/accel-ppp.conf.5
@@ -1022,27 +1022,34 @@ If attribute is vendor-specific then specify vendor name in this option.
.SH [ipv6-pool]
.br
Configuration of ipv6pool module.
+.TP
+.BI ipv6prefix/mask,prefix_len[,name=pool_name][,next=next_pool_name]
.br
-Format of each row is
-.br
-.B ipv6prefix/mask,prefix_len
-for example:
-.br
-.B fc00:0:1::/48,64
-- specifies pool of address by dividing prefix fc00:0:1::/48 to networks with 64 prefix len, e.g:
+.B fc00:0:1::/48,64 - specifies pool of address by dividing prefix fc00:0:1::/48 to networks with 64 prefix len, e.g:
.br
fc00:0:1:0::/64
.br
fc00:0:1:1::/64
.br
-...
+ ...
+.br
fc00:0:1:ffff::/64
.TP
-.BI "delegate=" ipv6prefix/mask,prefix_len
+.BI "delegate=" ipv6prefix/mask,prefix_len[,name=pool_name][,next=next_pool_name]
Specifies range of prefixes to delegate to clients through DHCPv6 prefix delegation (rfc3633).
Format is same as described above.
+.TP
.BI "gw-ip6-address=" ipv6address
Specifies gateway address (used only for /128 prefixes)
+.TP
+.BI "attr-prefix=" attribute
+Specifies which Radius attribute contains delegated prefix pool name.
+.TP
+.BI "attr-address=" attribute
+Specifies which Radius attribute contains stateful address pool name.
+.TP
+.BI "vendor=" vendor
+If attribute is vendor-specific then specify vendor name in this option.
.SH [connlimit]
.br
This module limits connection rate from single source.
diff --git a/accel-pppd/extra/chap-secrets.c b/accel-pppd/extra/chap-secrets.c
index 92cfb42..2d8593c 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 4f29a28..f00dbcf 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);
diff --git a/accel-pppd/include/ap_session.h b/accel-pppd/include/ap_session.h
index b2d0532..cf49e32 100644
--- a/accel-pppd/include/ap_session.h
+++ b/accel-pppd/include/ap_session.h
@@ -84,6 +84,7 @@ struct ap_session
struct ipv6db_prefix_t *ipv6_dp;
char *ipv4_pool_name;
char *ipv6_pool_name;
+ char *ipv6_dppool_name;
struct ap_net *net;
const struct ap_ctrl *ctrl;
diff --git a/accel-pppd/radius/attr_defs.h b/accel-pppd/radius/attr_defs.h
index eb3c5de..80ae426 100644
--- a/accel-pppd/radius/attr_defs.h
+++ b/accel-pppd/radius/attr_defs.h
@@ -292,3 +292,8 @@
#define Framed_IPv6_Route 99
#define Framed_IPv6_Pool 100
#define Delegated_IPv6_Prefix 123
+#define Framed_IPv6_Address 168
+#define DNS_Server_IPv6_Address 169
+#define Route_IPv6_Information 170
+#define Delegated_IPv6_Prefix_Pool 171
+#define Stateful_IPv6_Address_Pool 172
diff --git a/accel-pppd/radius/dict.c b/accel-pppd/radius/dict.c
index fa75dd9..cb1fb28 100644
--- a/accel-pppd/radius/dict.c
+++ b/accel-pppd/radius/dict.c
@@ -80,7 +80,7 @@ static int dict_load(const char *fname)
f = fopen(fname, "r");
if (!f) {
- log_emerg("radius: open dictioanary '%s': %s\n", fname, strerror(errno));
+ log_emerg("radius: open dictionary '%s': %s\n", fname, strerror(errno));
return -1;
}
diff --git a/accel-pppd/radius/dict/dictionary b/accel-pppd/radius/dict/dictionary
index de05680..6da511d 100644
--- a/accel-pppd/radius/dict/dictionary
+++ b/accel-pppd/radius/dict/dictionary
@@ -74,6 +74,7 @@ $INCLUDE dictionary.rfc4372
$INCLUDE dictionary.rfc4679
$INCLUDE dictionary.rfc4818
$INCLUDE dictionary.rfc5176
+$INCLUDE dictionary.rfc6911
$INCLUDE dictionary.microsoft
$INCLUDE dictionary.cisco
diff --git a/accel-pppd/radius/dict/dictionary.rfc6911 b/accel-pppd/radius/dict/dictionary.rfc6911
new file mode 100644
index 0000000..f8d5204
--- /dev/null
+++ b/accel-pppd/radius/dict/dictionary.rfc6911
@@ -0,0 +1,12 @@
+# -*- text -*-
+# Copyright (C) 2013 The FreeRADIUS Server project and contributors
+#
+# Attributes and values defined in RFC 6911
+# http://www.ietf.org/rfc/rfc6911.txt
+#
+
+ATTRIBUTE Framed-IPv6-Address 168 ipv6addr
+ATTRIBUTE DNS-Server-IPv6-Address 169 ipv6addr
+ATTRIBUTE Route-IPv6-Information 170 ipv6prefix
+ATTRIBUTE Delegated-IPv6-Prefix-Pool 171 string
+ATTRIBUTE Stateful-IPv6-Address-Pool 172 string
diff --git a/accel-pppd/session.c b/accel-pppd/session.c
index bf7d712..8326ffa 100644
--- a/accel-pppd/session.c
+++ b/accel-pppd/session.c
@@ -239,6 +239,11 @@ void __export ap_session_finished(struct ap_session *ses)
ses->ipv6_pool_name = NULL;
}
+ if (ses->ipv6_dppool_name) {
+ _free(ses->ipv6_dppool_name);
+ ses->ipv6_dppool_name = NULL;
+ }
+
if (ses->ifname_rename) {
_free(ses->ifname_rename);
ses->ifname_rename = NULL;