diff options
Diffstat (limited to 'accel-pppd')
-rw-r--r-- | accel-pppd/accel-ppp.conf | 7 | ||||
-rw-r--r-- | accel-pppd/accel-ppp.conf.5 | 25 | ||||
-rw-r--r-- | accel-pppd/extra/chap-secrets.c | 6 | ||||
-rw-r--r-- | accel-pppd/extra/ipv6pool.c | 304 | ||||
-rw-r--r-- | accel-pppd/include/ap_session.h | 1 | ||||
-rw-r--r-- | accel-pppd/radius/attr_defs.h | 5 | ||||
-rw-r--r-- | accel-pppd/radius/dict.c | 2 | ||||
-rw-r--r-- | accel-pppd/radius/dict/dictionary | 1 | ||||
-rw-r--r-- | accel-pppd/radius/dict/dictionary.rfc6911 | 12 | ||||
-rw-r--r-- | accel-pppd/session.c | 5 |
10 files changed, 321 insertions, 47 deletions
diff --git a/accel-pppd/accel-ppp.conf b/accel-pppd/accel-ppp.conf index 7f341b62..acdbe4f2 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 982bbd10..3e6312f8 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 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); diff --git a/accel-pppd/include/ap_session.h b/accel-pppd/include/ap_session.h index b2d05327..cf49e32b 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 eb3c5de8..80ae426b 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 fa75dd9c..cb1fb28b 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 de056801..6da511d2 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 00000000..f8d52049 --- /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 bf7d712a..8326ffa7 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; |