summaryrefslogtreecommitdiff
path: root/accel-pppd/radius
diff options
context:
space:
mode:
authorDmitry Kozlov <xeb@mail.ru>2016-01-03 23:12:12 +0300
committerDmitry Kozlov <xeb@mail.ru>2016-01-03 23:12:16 +0300
commit683fcf64fa9b90efd009d47a7ca500459adf419d (patch)
treec1abc26f6dfbea8e70429b31dfdbe3b0cfb22b30 /accel-pppd/radius
parent0ba262d4bf906b8fd6b724264c69933309bedd74 (diff)
downloadaccel-ppp-683fcf64fa9b90efd009d47a7ca500459adf419d.tar.gz
accel-ppp-683fcf64fa9b90efd009d47a7ca500459adf419d.zip
radius: implemented handling of Framed-Route attribute
Framed-Route has following syntax: Framed-Route=address[/mask] [gateway] If gateway is not specified then route would be attached to session interface.
Diffstat (limited to 'accel-pppd/radius')
-rw-r--r--accel-pppd/radius/radius.c106
-rw-r--r--accel-pppd/radius/radius_p.h9
2 files changed, 115 insertions, 0 deletions
diff --git a/accel-pppd/radius/radius.c b/accel-pppd/radius/radius.c
index 64c85df0..24ca20a3 100644
--- a/accel-pppd/radius/radius.c
+++ b/accel-pppd/radius/radius.c
@@ -13,6 +13,8 @@
#include "pwdb.h"
#include "ipdb.h"
#include "ppp_auth.h"
+#include "iputils.h"
+#include "utils.h"
#include "radius_p.h"
#include "attr_defs.h"
@@ -56,6 +58,84 @@ static struct ipdb_t ipdb;
static mempool_t rpd_pool;
static mempool_t auth_ctx_pool;
+static void parse_framed_route(struct radius_pd_t *rpd, const char *attr)
+{
+ char str[32];
+ char *ptr;
+ in_addr_t dst;
+ in_addr_t gw;
+ int mask;
+ struct framed_route *fr;
+
+ ptr = strchr(attr, '/');
+ if (ptr && ptr - attr > 16)
+ goto out_err;
+
+ if (ptr) {
+ memcpy(str, attr, ptr - attr);
+ str[ptr - attr] = 0;
+ } else {
+ ptr = strchr(attr, ' ');
+ if (ptr) {
+ memcpy(str, attr, ptr - attr);
+ str[ptr - attr] = 0;
+ } else
+ strcpy(str, attr);
+ }
+
+ dst = inet_addr(str);
+ if (dst == INADDR_NONE)
+ goto out_err;
+
+ if (ptr) {
+ if (*ptr == '/') {
+ char *ptr2;
+ for (ptr2 = ++ptr; *ptr2 && *ptr2 != '.' && *ptr2 != ' '; ptr2++);
+ if (*ptr2 == '.' && ptr2 - ptr <= 16) {
+ in_addr_t a;
+ memcpy(str, ptr, ptr2 - ptr);
+ str[ptr2 - ptr] = 0;
+ a = ntohl(inet_addr(str));
+ if (a == INADDR_NONE)
+ goto out_err;
+ mask = 33 - htonl(inet_addr(str));
+ if (~((1<<(32 - mask)) - 1) != a)
+ goto out_err;
+ } else if (*ptr2 == ' ' || *ptr2 == 0) {
+ char *ptr3;
+ mask = strtol(ptr, &ptr3, 10);
+ if (mask < 0 || mask > 32 || ptr3 != ptr2)
+ goto out_err;
+ } else
+ goto out_err;
+ } else
+ mask = 32;
+
+ for (++ptr; *ptr && *ptr != ' '; ptr++);
+ if (*ptr == ' ')
+ gw = inet_addr(ptr + 1);
+ else if (*ptr == 0)
+ gw = 0;
+ else
+ goto out_err;
+ } else {
+ mask = 32;
+ gw = 0;
+ }
+
+ fr = _malloc(sizeof (*fr));
+ fr->dst = dst;
+ fr->mask = mask;
+ fr->gw = gw;
+ fr->next = rpd->fr;
+ rpd->fr = fr;
+
+ return;
+
+out_err:
+ log_ppp_warn("radius: failed to parse Framed-Route=%s\n", attr);
+}
+
int rad_proc_attrs(struct rad_req_t *req)
{
struct rad_attr_t *attr;
@@ -152,6 +232,9 @@ int rad_proc_attrs(struct rad_req_t *req)
case NAS_Port_Id:
ap_session_rename(rpd->ses, attr->val.string, attr->len);
break;
+ case Framed_Route:
+ parse_framed_route(rpd, attr->val.string);
+ break;
}
}
@@ -336,16 +419,27 @@ static void ses_acct_start(struct ap_session *ses)
static void ses_started(struct ap_session *ses)
{
struct radius_pd_t *rpd = find_pd(ses);
+ struct framed_route *fr;
if (rpd->session_timeout.expire_tv.tv_sec) {
rpd->session_timeout.expire = session_timeout;
triton_timer_add(ses->ctrl->ctx, &rpd->session_timeout, 0);
}
+
+ for (fr = rpd->fr; fr; fr = fr->next) {
+ if (iproute_add(fr->gw ? 0 : rpd->ses->ifindex, 0, fr->dst, fr->gw, 3, fr->mask)) {
+ char dst[17], gw[17];
+ u_inet_ntoa(fr->dst, dst);
+ u_inet_ntoa(fr->gw, gw);
+ log_ppp_warn("radius: failed to add route %s/%i%s\n", dst, fr->mask, gw);
+ }
+ }
}
static void ses_finishing(struct ap_session *ses)
{
struct radius_pd_t *rpd = find_pd(ses);
+ struct framed_route *fr;
if (rpd->auth_ctx) {
rad_server_req_cancel(rpd->auth_ctx->req, 1);
@@ -354,6 +448,11 @@ static void ses_finishing(struct ap_session *ses)
rpd->auth_ctx = NULL;
}
+ for (fr = rpd->fr; fr; fr = fr->next) {
+ if (fr->gw)
+ iproute_del(0, fr->dst, 3, fr->mask);
+ }
+
if (rpd->acct_started || rpd->acct_req)
rad_acct_stop(rpd);
}
@@ -362,6 +461,7 @@ static void ses_finished(struct ap_session *ses)
{
struct radius_pd_t *rpd = find_pd(ses);
struct ipv6db_addr_t *a;
+ struct framed_route *fr = rpd->fr;
pthread_rwlock_wrlock(&sessions_lock);
pthread_mutex_lock(&rpd->lock);
@@ -409,6 +509,12 @@ static void ses_finished(struct ap_session *ses)
_free(a);
}
+ while (fr) {
+ struct framed_route *next = fr->next;
+ _free(fr);
+ fr = next;
+ }
+
list_del(&rpd->pd.entry);
release_pd(rpd);
diff --git a/accel-pppd/radius/radius_p.h b/accel-pppd/radius/radius_p.h
index cf7cbc84..0e1789fd 100644
--- a/accel-pppd/radius/radius_p.h
+++ b/accel-pppd/radius/radius_p.h
@@ -25,6 +25,13 @@ struct radius_auth_ctx {
char **reply_msg;
};
+struct framed_route {
+ in_addr_t dst;
+ int mask;
+ in_addr_t gw;
+ struct framed_route *next;
+};
+
struct radius_pd_t {
struct list_head entry;
struct ap_private pd;
@@ -54,6 +61,8 @@ struct radius_pd_t {
int attr_state_len;
int termination_action;
+ struct framed_route *fr;
+
struct radius_auth_ctx *auth_ctx;
struct list_head plugin_list;