summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--accel-pppd/extra/ipv6pool.c92
-rw-r--r--accel-pppd/ppp/ipv6cp_opt_intfid.c53
-rw-r--r--accel-pppd/radius/attr_defs.h6
-rw-r--r--accel-pppd/radius/dict.c6
-rw-r--r--accel-pppd/radius/dict/dictionary3
-rw-r--r--accel-pppd/radius/dict/dictionary.rfc316213
-rw-r--r--accel-pppd/radius/packet.c111
-rw-r--r--accel-pppd/radius/radius.c26
-rw-r--r--accel-pppd/radius/radius.h11
-rw-r--r--accel-pppd/radius/req.c10
10 files changed, 235 insertions, 96 deletions
diff --git a/accel-pppd/extra/ipv6pool.c b/accel-pppd/extra/ipv6pool.c
index 5a1a606..4380d47 100644
--- a/accel-pppd/extra/ipv6pool.c
+++ b/accel-pppd/extra/ipv6pool.c
@@ -16,14 +16,6 @@
#include "memdebug.h"
-#define INTF_ID_FIXED 0
-#define INTF_ID_RANDOM 1
-#define INTF_ID_CSID 2
-#define INTF_ID_IPV4 3
-
-static int conf_intf_id = INTF_ID_FIXED;
-static uint64_t conf_intf_id_val = 2;
-
struct ippool_item_t
{
struct list_head entry;
@@ -33,7 +25,6 @@ struct ippool_item_t
static LIST_HEAD(ippool);
static spinlock_t pool_lock = SPINLOCK_INITIALIZER;
static struct ipdb_t ipdb;
-static int urandom_fd;
static void generate_pool(struct in6_addr *addr, int mask, int prefix_len)
{
@@ -103,38 +94,6 @@ err:
_free(val);
}
-static uint64_t generate_intf_id(struct ppp_t *ppp)
-{
- char str[4];
- int i, n;
- union {
- uint64_t intf_id;
- uint16_t addr16[4];
- } u;
-
- switch (conf_intf_id) {
- case INTF_ID_FIXED:
- return conf_intf_id_val;
- break;
- case INTF_ID_RANDOM:
- read(urandom_fd, &u, sizeof(u));
- break;
- case INTF_ID_CSID:
- break;
- case INTF_ID_IPV4:
- if (ppp->ipv4) {
- for (i = 0; i < 4; i++) {
- sprintf(str, "%i", (ppp->ipv4->peer_addr >> (i*8)) & 0xff);
- sscanf(str, "%x", &n);
- u.addr16[i] = htons(n);
- }
- } else
- read(urandom_fd, &u, sizeof(u));
- }
-
- return u.intf_id;
-}
-
static struct ipv6db_item_t *get_ip(struct ppp_t *ppp)
{
struct ippool_item_t *it;
@@ -146,9 +105,8 @@ static struct ipv6db_item_t *get_ip(struct ppp_t *ppp)
} else
it = NULL;
spin_unlock(&pool_lock);
-
- if (it)
- it->it.intf_id = generate_intf_id(ppp);
+
+ it->it.intf_id = 0;
return it ? &it->it : NULL;
}
@@ -167,33 +125,6 @@ static struct ipdb_t ipdb = {
.put_ipv6 = put_ip,
};
-static uint64_t parse_intfid(const char *opt)
-{
- union {
- uint64_t u64;
- uint16_t u16[4];
- } u;
-
- int n[4];
- int i;
-
- if (sscanf(opt, "%x:%x:%x:%x", &n[0], &n[1], &n[2], &n[3]) != 4)
- goto err;
-
- for (i = 0; i < 4; i++) {
- if (n[i] < 0 || n[i] > 0xffff)
- goto err;
- u.u16[i] = htons(n[i]);
- }
-
- return u.u64;
-
-err:
- log_error("ipv6pool: failed to parse intf-id\n");
- conf_intf_id = INTF_ID_RANDOM;
- return 0;
-}
-
static void ippool_init(void)
{
struct conf_sect_t *s = conf_get_section("ipv6-pool");
@@ -202,25 +133,8 @@ static void ippool_init(void)
if (!s)
return;
- list_for_each_entry(opt, &s->items, entry) {
- if (!strcmp(opt->name, "intf-id")) {
- if (!strcmp(opt->val, "random"))
- conf_intf_id = INTF_ID_RANDOM;
- else if (!strcmp(opt->val, "calling-sid"))
- conf_intf_id = INTF_ID_CSID;
- else if (!strcmp(opt->val, "ipv4"))
- conf_intf_id = INTF_ID_IPV4;
- else {
- conf_intf_id = INTF_ID_FIXED;
- conf_intf_id_val = parse_intfid(opt->val);
- }
- }
- if (opt->val)
- continue;
+ list_for_each_entry(opt, &s->items, entry)
add_prefix(opt->name);
- }
-
- urandom_fd = open("/dev/urandom", O_RDONLY);
ipdb_register(&ipdb);
}
diff --git a/accel-pppd/ppp/ipv6cp_opt_intfid.c b/accel-pppd/ppp/ipv6cp_opt_intfid.c
index abf124a..e868102 100644
--- a/accel-pppd/ppp/ipv6cp_opt_intfid.c
+++ b/accel-pppd/ppp/ipv6cp_opt_intfid.c
@@ -18,10 +18,14 @@
#define INTF_ID_FIXED 0
#define INTF_ID_RANDOM 1
+#define INTF_ID_CSID 2
+#define INTF_ID_IPV4 3
static int conf_check_exists;
static int conf_intf_id = INTF_ID_FIXED;
static uint64_t conf_intf_id_val = 1;
+static int conf_peer_intf_id = INTF_ID_FIXED;
+static uint64_t conf_peer_intf_id_val = 2;
// from /usr/include/linux/ipv6.h
struct in6_ifreq {
@@ -118,6 +122,38 @@ out:
return r;
}
+static uint64_t generate_peer_intf_id(struct ppp_t *ppp)
+{
+ char str[4];
+ int i, n;
+ union {
+ uint64_t intf_id;
+ uint16_t addr16[4];
+ } u;
+
+ switch (conf_peer_intf_id) {
+ case INTF_ID_FIXED:
+ return conf_peer_intf_id_val;
+ break;
+ case INTF_ID_RANDOM:
+ read(urandom_fd, &u, sizeof(u));
+ break;
+ case INTF_ID_CSID:
+ break;
+ case INTF_ID_IPV4:
+ if (ppp->ipv4) {
+ for (i = 0; i < 4; i++) {
+ sprintf(str, "%i", (ppp->ipv4->peer_addr >> (i*8)) & 0xff);
+ sscanf(str, "%x", &n);
+ u.addr16[i] = htons(n);
+ }
+ } else
+ read(urandom_fd, &u, sizeof(u));
+ }
+
+ return u.intf_id;
+}
+
static int ipaddr_send_conf_req(struct ppp_ipv6cp_t *ipv6cp, struct ipv6cp_option_t *opt, uint8_t *ptr)
{
struct ipaddr_option_t *ipaddr_opt = container_of(opt, typeof(*ipaddr_opt), opt);
@@ -130,6 +166,9 @@ static int ipaddr_send_conf_req(struct ppp_ipv6cp_t *ipv6cp, struct ipv6cp_optio
return -1;
}
}
+
+ if (!ipv6cp->ppp->ipv6->intf_id)
+ ipv6cp->ppp->ipv6->intf_id = generate_peer_intf_id(ipv6cp->ppp);
if (conf_check_exists && check_exists(ipv6cp->ppp))
return -1;
@@ -268,6 +307,20 @@ static void load_config(void)
conf_intf_id_val = parse_intfid(opt);
}
}
+
+ opt = conf_get_opt("ppp", "ipv6-peer-intf-id");
+ if (opt) {
+ if (!strcmp(opt, "random"))
+ conf_peer_intf_id = INTF_ID_RANDOM;
+ else if (!strcmp(opt, "calling-sid"))
+ conf_peer_intf_id = INTF_ID_CSID;
+ else if (!strcmp(opt, "ipv4"))
+ conf_peer_intf_id = INTF_ID_IPV4;
+ else {
+ conf_peer_intf_id = INTF_ID_FIXED;
+ conf_peer_intf_id_val = parse_intfid(opt);
+ }
+ }
}
static void init()
diff --git a/accel-pppd/radius/attr_defs.h b/accel-pppd/radius/attr_defs.h
index e9b617e..779229e 100644
--- a/accel-pppd/radius/attr_defs.h
+++ b/accel-pppd/radius/attr_defs.h
@@ -285,3 +285,9 @@
#define MS_Acct_EAP_Type_Generic_Token_Card 6
#define MS_Acct_EAP_Type_TLS 13
#define Traffic_Shape_in 231
+#define NAS_IPv6_Address 95
+#define Framed_Interface_Id 96
+#define Framed_IPv6_Prefix 97
+#define Login_IPv6_Host 98
+#define Framed_IPv6_Route 99
+#define Framed_IPv6_Pool 100
diff --git a/accel-pppd/radius/dict.c b/accel-pppd/radius/dict.c
index 9704569..146d1c1 100644
--- a/accel-pppd/radius/dict.c
+++ b/accel-pppd/radius/dict.c
@@ -155,6 +155,12 @@ static int dict_load(const char *fname)
attr->type = ATTR_TYPE_IPADDR;
else if (!strcmp(ptr[2], "octets"))
attr->type = ATTR_TYPE_OCTETS;
+ else if (!strcmp(ptr[2], "ifid"))
+ attr->type = ATTR_TYPE_IFID;
+ else if (!strcmp(ptr[2], "ipv6addr"))
+ attr->type = ATTR_TYPE_IPV6ADDR;
+ else if (!strcmp(ptr[2], "ipv6prefix"))
+ attr->type = ATTR_TYPE_IPV6PREFIX;
else {
log_emerg("radius:%s:%i: unknown attribute type\n", fname, n);
goto out_err;
diff --git a/accel-pppd/radius/dict/dictionary b/accel-pppd/radius/dict/dictionary
index 2797310..02eb7de 100644
--- a/accel-pppd/radius/dict/dictionary
+++ b/accel-pppd/radius/dict/dictionary
@@ -66,6 +66,7 @@ $INCLUDE dictionary.rfc2866
$INCLUDE dictionary.rfc2867
$INCLUDE dictionary.rfc2868
$INCLUDE dictionary.rfc2869
+$INCLUDE dictionary.rfc3162
$INCLUDE dictionary.rfc3576
$INCLUDE dictionary.rfc3580
$INCLUDE dictionary.rfc4072
@@ -75,5 +76,3 @@ $INCLUDE dictionary.rfc5176
$INCLUDE dictionary.microsoft
$INCLUDE dictionary.cisco
-
-ATTRIBUTE Traffic-Shape-in 231 integer
diff --git a/accel-pppd/radius/dict/dictionary.rfc3162 b/accel-pppd/radius/dict/dictionary.rfc3162
new file mode 100644
index 0000000..85b381c
--- /dev/null
+++ b/accel-pppd/radius/dict/dictionary.rfc3162
@@ -0,0 +1,13 @@
+# -*- text -*-
+#
+# Attributes and values defined in RFC 3162.
+# http://www.ietf.org/rfc/rfc3162.txt
+#
+# $Id: dictionary.rfc3162,v 1.2 2005/08/08 22:23:39 aland Exp $
+#
+ATTRIBUTE NAS-IPv6-Address 95 ipv6addr
+ATTRIBUTE Framed-Interface-Id 96 ifid
+ATTRIBUTE Framed-IPv6-Prefix 97 ipv6prefix
+ATTRIBUTE Login-IPv6-Host 98 ipv6addr
+ATTRIBUTE Framed-IPv6-Route 99 string
+ATTRIBUTE Framed-IPv6-Pool 100 string
diff --git a/accel-pppd/radius/packet.c b/accel-pppd/radius/packet.c
index 892cc49..7f90a10 100644
--- a/accel-pppd/radius/packet.c
+++ b/accel-pppd/radius/packet.c
@@ -7,6 +7,7 @@
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/mman.h>
+#include <arpa/inet.h>
#include "log.h"
#include "mempool.h"
@@ -87,11 +88,18 @@ int rad_packet_build(struct rad_packet_t *pack, uint8_t *RA)
memcpy(ptr, attr->val.string, attr->len);
break;
case ATTR_TYPE_IPADDR:
- *(in_addr_t*)ptr = attr->val.ipaddr;
+ case ATTR_TYPE_IFID:
+ case ATTR_TYPE_IPV6ADDR:
+ memcpy(ptr, &attr->val, attr->len);
break;
case ATTR_TYPE_DATE:
*(uint32_t*)ptr = htonl(attr->val.date);
break;
+ case ATTR_TYPE_IPV6PREFIX:
+ ptr[0] = 0;
+ ptr[1] = attr->val.ipv6prefix.len;
+ memcpy(ptr + 2, &attr->val.ipv6prefix.prefix, sizeof(attr->val.ipv6prefix.prefix));
+ break;
default:
log_emerg("radius:packet:BUG: unknown attribute type\n");
abort();
@@ -222,7 +230,14 @@ int rad_packet_recv(int fd, struct rad_packet_t **p, struct sockaddr_in *addr)
attr->val.integer = ntohl(*(uint32_t*)ptr);
break;
case ATTR_TYPE_IPADDR:
- attr->val.integer = *(uint32_t*)ptr;
+ case ATTR_TYPE_IFID:
+ case ATTR_TYPE_IPV6ADDR:
+ memcpy(&attr->val.integer, ptr, len);
+ break;
+ case ATTR_TYPE_IPV6PREFIX:
+ attr->val.ipv6prefix.len = ptr[1];
+ memset(&attr->val.ipv6prefix.prefix, 0, sizeof(attr->val.ipv6prefix.prefix));
+ memcpy(&attr->val.ipv6prefix.prefix, ptr + 2, len - 2);
break;
}
list_add_tail(&attr->entry, &pack->attrs);
@@ -264,6 +279,11 @@ void rad_packet_print(struct rad_packet_t *pack, void (*print)(const char *fmt,
{
struct rad_attr_t *attr;
struct rad_dict_value_t *val;
+ char ip_str[50];
+ union {
+ uint64_t ifid;
+ uint16_t u16[4];
+ } ifid_u;
print("[RADIUS ");
switch(pack->code) {
@@ -327,6 +347,18 @@ void rad_packet_print(struct rad_packet_t *pack, void (*print)(const char *fmt,
case ATTR_TYPE_IPADDR:
print("%i.%i.%i.%i", attr->val.ipaddr & 0xff, (attr->val.ipaddr >> 8) & 0xff, (attr->val.ipaddr >> 16) & 0xff, (attr->val.ipaddr >> 24) & 0xff);
break;
+ case ATTR_TYPE_IFID:
+ ifid_u.ifid = attr->val.ifid;
+ print("%x:%x:%x:%x", ntohs(ifid_u.u16[0]), ntohs(ifid_u.u16[1]), ntohs(ifid_u.u16[2]), ntohs(ifid_u.u16[3]));
+ break;
+ case ATTR_TYPE_IPV6ADDR:
+ inet_ntop(AF_INET6, &attr->val.ipv6addr, ip_str, sizeof(ip_str));
+ print("%s", ip_str);
+ break;
+ case ATTR_TYPE_IPV6PREFIX:
+ inet_ntop(AF_INET6, &attr->val.ipv6prefix.prefix, ip_str, sizeof(ip_str));
+ print("%s/%i", ip_str, attr->val.ipv6prefix.len);
+ break;
}
print(">");
}
@@ -596,6 +628,81 @@ int __export rad_packet_add_ipaddr(struct rad_packet_t *pack, const char *vendor
return rad_packet_add_int(pack, vendor_name, name, ipaddr);
}
+int rad_packet_add_ifid(struct rad_packet_t *pack, const char *vendor_name, const char *name, uint64_t ifid)
+{
+ struct rad_attr_t *ra;
+ struct rad_dict_attr_t *attr;
+ struct rad_dict_vendor_t *vendor;
+
+ if (pack->len + (vendor_name ? 8 : 2) + 8 >= REQ_LENGTH_MAX)
+ return -1;
+
+ if (vendor_name) {
+ vendor = rad_dict_find_vendor_name(vendor_name);
+ if (!vendor)
+ return -1;
+ attr = rad_dict_find_vendor_attr(vendor, name);
+ } else {
+ vendor = NULL;
+ attr = rad_dict_find_attr(name);
+ }
+
+ if (!attr)
+ return -1;
+
+ ra = mempool_alloc(attr_pool);
+ if (!ra)
+ return -1;
+
+ memset(ra, 0, sizeof(*ra));
+ ra->vendor = vendor;
+ ra->attr = attr;
+ ra->len = 8;
+ ra->val.ifid = ifid;
+ list_add_tail(&ra->entry, &pack->attrs);
+ pack->len += (vendor_name ? 8 : 2) + 8;
+
+ return 0;
+}
+
+int rad_packet_add_ipv6prefix(struct rad_packet_t *pack, const char *vendor_name, const char *name, struct in6_addr *prefix, int len)
+{
+ struct rad_attr_t *ra;
+ struct rad_dict_attr_t *attr;
+ struct rad_dict_vendor_t *vendor;
+
+ if (pack->len + (vendor_name ? 8 : 2) + 18 >= REQ_LENGTH_MAX)
+ return -1;
+
+ if (vendor_name) {
+ vendor = rad_dict_find_vendor_name(vendor_name);
+ if (!vendor)
+ return -1;
+ attr = rad_dict_find_vendor_attr(vendor, name);
+ } else {
+ vendor = NULL;
+ attr = rad_dict_find_attr(name);
+ }
+
+ if (!attr)
+ return -1;
+
+ ra = mempool_alloc(attr_pool);
+ if (!ra)
+ return -1;
+
+ memset(ra, 0, sizeof(*ra));
+ ra->vendor = vendor;
+ ra->attr = attr;
+ ra->len = 18;
+ ra->val.ipv6prefix.len = len;
+ ra->val.ipv6prefix.prefix = *prefix;
+ list_add_tail(&ra->entry, &pack->attrs);
+ pack->len += (vendor_name ? 8 : 2) + 18;
+
+ return 0;
+}
+
struct rad_attr_t __export *rad_packet_find_attr(struct rad_packet_t *pack, const char *vendor_name, const char *name)
{
diff --git a/accel-pppd/radius/radius.c b/accel-pppd/radius/radius.c
index 4200d62..22e4cca 100644
--- a/accel-pppd/radius/radius.c
+++ b/accel-pppd/radius/radius.c
@@ -78,6 +78,7 @@ static mempool_t rpd_pool;
int rad_proc_attrs(struct rad_req_t *req)
{
struct rad_attr_t *attr;
+ struct ipv6db_addr_t *a;
int res = 0;
req->rpd->acct_interim_interval = conf_acct_interim_interval;
@@ -120,6 +121,15 @@ int rad_proc_attrs(struct rad_req_t *req)
case Termination_Action:
req->rpd->termination_action = attr->val.integer;
break;
+ case Framed_Interface_Id:
+ req->rpd->ipv6_addr.intf_id = attr->val.ifid;
+ break;
+ case Framed_IPv6_Prefix:
+ a = _malloc(sizeof(*a));
+ a->prefix_len = attr->val.ipv6prefix.len;
+ a->addr = attr->val.ipv6prefix.prefix;
+ list_add_tail(&a->entry, &req->rpd->ipv6_addr.addr_list);
+ break;
}
}
@@ -174,10 +184,11 @@ static struct ipv4db_item_t *get_ipv4(struct ppp_t *ppp)
static struct ipv6db_item_t *get_ipv6(struct ppp_t *ppp)
{
- //struct radius_pd_t *rpd = find_pd(ppp);
+ struct radius_pd_t *rpd = find_pd(ppp);
- //if (memcmp(&rpd->ipv6_addr.peer_addr, &in6addr_any, sizeof(in6addr_any)))
- // return &rpd->ipv6_addr;
+ if (!list_empty(&rpd->ipv6_addr.addr_list))
+ return &rpd->ipv6_addr;
+
return NULL;
}
@@ -206,6 +217,8 @@ static void ppp_starting(struct ppp_t *ppp)
rpd->ppp = ppp;
pthread_mutex_init(&rpd->lock, NULL);
INIT_LIST_HEAD(&rpd->plugin_list);
+ INIT_LIST_HEAD(&rpd->ipv6_addr.addr_list);
+ INIT_LIST_HEAD(&rpd->ipv6_addr.route_list);
list_add_tail(&rpd->pd.entry, &ppp->pd_list);
pthread_rwlock_wrlock(&sessions_lock);
@@ -242,6 +255,7 @@ static void ppp_finishing(struct ppp_t *ppp)
static void ppp_finished(struct ppp_t *ppp)
{
struct radius_pd_t *rpd = find_pd(ppp);
+ struct ipv6db_addr_t *a;
pthread_rwlock_wrlock(&sessions_lock);
pthread_mutex_lock(&rpd->lock);
@@ -267,6 +281,12 @@ static void ppp_finished(struct ppp_t *ppp)
if (rpd->attr_state)
_free(rpd->attr_state);
+ while (!list_empty(&rpd->ipv6_addr.addr_list)) {
+ a = list_entry(rpd->ipv6_addr.addr_list.next, typeof(*a), entry);
+ list_del(&a->entry);
+ _free(a);
+ }
+
list_del(&rpd->pd.entry);
mempool_free(rpd);
diff --git a/accel-pppd/radius/radius.h b/accel-pppd/radius/radius.h
index e580b93..dd91efa 100644
--- a/accel-pppd/radius/radius.h
+++ b/accel-pppd/radius/radius.h
@@ -11,6 +11,9 @@
#define ATTR_TYPE_OCTETS 2
#define ATTR_TYPE_DATE 3
#define ATTR_TYPE_IPADDR 4
+#define ATTR_TYPE_IFID 5
+#define ATTR_TYPE_IPV6ADDR 6
+#define ATTR_TYPE_IPV6PREFIX 7
#define CODE_ACCESS_REQUEST 1
#define CODE_ACCESS_ACCEPT 2
@@ -34,6 +37,12 @@ typedef union
uint8_t *octets;
time_t date;
in_addr_t ipaddr;
+ uint64_t ifid;
+ struct in6_addr ipv6addr;
+ struct {
+ struct in6_addr prefix;
+ uint8_t len;
+ } ipv6prefix;
} rad_value_t;
struct rad_dict_t
@@ -114,6 +123,8 @@ int rad_packet_change_int(struct rad_packet_t *pack, const char *vendor, const c
int rad_packet_change_val(struct rad_packet_t *pack, const char *vendor, const char *name, const char *val);
int rad_packet_change_octets(struct rad_packet_t *pack, const char *vendor, const char *name, const uint8_t *val, int len);
int rad_packet_add_ipaddr(struct rad_packet_t *pack, const char *vendor, const char *name, in_addr_t ipaddr);
+int rad_packet_add_ifid(struct rad_packet_t *pack, const char *vendor, const char *name, uint64_t ifid);
+int rad_packet_add_ipv6prefix(struct rad_packet_t *pack, const char *vendor, const char *name, struct in6_addr *prefix, int len);
#endif
diff --git a/accel-pppd/radius/req.c b/accel-pppd/radius/req.c
index 462e656..9f41ecc 100644
--- a/accel-pppd/radius/req.c
+++ b/accel-pppd/radius/req.c
@@ -101,6 +101,8 @@ out_err:
int rad_req_acct_fill(struct rad_req_t *req)
{
+ struct ipv6db_addr_t *a;
+
req->server_addr = req->serv->acct_addr;
req->server_port = req->serv->acct_port;
@@ -134,6 +136,14 @@ int rad_req_acct_fill(struct rad_req_t *req)
if (rad_packet_add_ipaddr(req->pack, NULL, "Framed-IP-Address", req->rpd->ppp->ipv4->peer_addr))
return -1;
}
+ if (req->rpd->ppp->ipv6) {
+ if (rad_packet_add_ifid(req->pack, NULL, "Framed-Interface-Id", req->rpd->ppp->ipv6->intf_id))
+ return -1;
+ list_for_each_entry(a, &req->rpd->ppp->ipv6->addr_list, entry) {
+ if (rad_packet_add_ipv6prefix(req->pack, NULL, "Framed-IPv6-Prefix", &a->addr, a->prefix_len))
+ return -1;
+ }
+ }
return 0;
}