提交 44bdbbe1 编写于 作者: D Dmitry Kozlov

radius: ipv6 support

上级 18909197
......@@ -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);
}
......
......@@ -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()
......
......@@ -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
......@@ -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;
......
......@@ -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
# -*- 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
......@@ -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)
{
......
......@@ -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);
......
......@@ -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
......@@ -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;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册