diff options
author | Dmitry Kozlov <xeb@mail.ru> | 2011-08-23 22:53:55 +0400 |
---|---|---|
committer | Dmitry Kozlov <xeb@mail.ru> | 2011-08-23 22:53:55 +0400 |
commit | 44bdbbe118396789a7eacb833f37fcee5872b1a4 (patch) | |
tree | 6559db93cd9987352d6ae94a38e95ba89ff1d908 | |
parent | 18909197b31b66b5a1445c6f070a3c9fa9ab0501 (diff) | |
download | accel-ppp-44bdbbe118396789a7eacb833f37fcee5872b1a4.tar.gz accel-ppp-44bdbbe118396789a7eacb833f37fcee5872b1a4.zip |
radius: ipv6 support
-rw-r--r-- | accel-pppd/extra/ipv6pool.c | 92 | ||||
-rw-r--r-- | accel-pppd/ppp/ipv6cp_opt_intfid.c | 53 | ||||
-rw-r--r-- | accel-pppd/radius/attr_defs.h | 6 | ||||
-rw-r--r-- | accel-pppd/radius/dict.c | 6 | ||||
-rw-r--r-- | accel-pppd/radius/dict/dictionary | 3 | ||||
-rw-r--r-- | accel-pppd/radius/dict/dictionary.rfc3162 | 13 | ||||
-rw-r--r-- | accel-pppd/radius/packet.c | 111 | ||||
-rw-r--r-- | accel-pppd/radius/radius.c | 26 | ||||
-rw-r--r-- | accel-pppd/radius/radius.h | 11 | ||||
-rw-r--r-- | accel-pppd/radius/req.c | 10 |
10 files changed, 235 insertions, 96 deletions
diff --git a/accel-pppd/extra/ipv6pool.c b/accel-pppd/extra/ipv6pool.c index 5a1a6065..4380d47d 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 abf124a3..e8681020 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 e9b617e4..779229e7 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 9704569e..146d1c1e 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 27973105..02eb7dea 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 00000000..85b381ca --- /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 892cc497..7f90a100 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 4200d621..22e4cca9 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 e580b936..dd91efa8 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 462e656b..9f41ecc6 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; } |