summaryrefslogtreecommitdiff
path: root/accel-pppd/radius
diff options
context:
space:
mode:
authorKozlov Dmitry <dima@server>2011-08-16 17:46:36 +0400
committerKozlov Dmitry <dima@server>2011-08-16 17:46:36 +0400
commit3b04c12e021c35d71d8b690b54b7f96ce6a24576 (patch)
tree71d4fbe11c30e6ab54224cb38b98a7562a4b30a3 /accel-pppd/radius
parent8a948ec1a1697601282a20f3c0f09d912c24c923 (diff)
parentdc7cbe120d8794d8520e6d9d35c121474453d807 (diff)
downloadaccel-ppp-3b04c12e021c35d71d8b690b54b7f96ce6a24576.tar.gz
accel-ppp-3b04c12e021c35d71d8b690b54b7f96ce6a24576.zip
Merge branch 'radius'
Diffstat (limited to 'accel-pppd/radius')
-rw-r--r--accel-pppd/radius/CMakeLists.txt1
-rw-r--r--accel-pppd/radius/acct.c220
-rw-r--r--accel-pppd/radius/auth.c91
-rw-r--r--accel-pppd/radius/radius.c36
-rw-r--r--accel-pppd/radius/radius_p.h39
-rw-r--r--accel-pppd/radius/req.c14
-rw-r--r--accel-pppd/radius/serv.c322
7 files changed, 582 insertions, 141 deletions
diff --git a/accel-pppd/radius/CMakeLists.txt b/accel-pppd/radius/CMakeLists.txt
index d85d60c8..0c1789ef 100644
--- a/accel-pppd/radius/CMakeLists.txt
+++ b/accel-pppd/radius/CMakeLists.txt
@@ -5,6 +5,7 @@ SET(sources
packet.c
auth.c
acct.c
+ serv.c
dm_coa.c
radius.c
)
diff --git a/accel-pppd/radius/acct.c b/accel-pppd/radius/acct.c
index 31ab298f..66dcbb4e 100644
--- a/accel-pppd/radius/acct.c
+++ b/accel-pppd/radius/acct.c
@@ -116,6 +116,30 @@ static int rad_acct_read(struct triton_md_handler_t *h)
return 0;
}
+static void __rad_req_send(struct rad_req_t *req)
+{
+ while (1) {
+
+ if (rad_server_req_enter(req)) {
+ if (rad_server_realloc(req, 1)) {
+ log_ppp_warn("radius:acct: no servers available, terminating session...\n");
+ if (conf_acct_timeout) {
+ ppp_terminate(req->rpd->ppp, TERM_NAS_ERROR, 0);
+ return;
+ }
+ break;
+ }
+ continue;
+ }
+
+ rad_req_send(req, conf_interim_verbose);
+
+ rad_server_req_exit(req);
+
+ break;
+ }
+}
+
static void rad_acct_timeout(struct triton_timer_t *t)
{
struct rad_req_t *req = container_of(t, typeof(*req), timeout);
@@ -130,9 +154,13 @@ static void rad_acct_timeout(struct triton_timer_t *t)
dt = ts - req->rpd->acct_timestamp;
if (dt > conf_acct_timeout) {
- log_ppp_warn("radius:acct: no response, terminating session...\n");
- ppp_terminate(req->rpd->ppp, TERM_NAS_ERROR, 0);
- return;
+ rad_server_fail(req->serv);
+ if (rad_server_realloc(req, 1)) {
+ log_ppp_warn("radius:acct: no servers available, terminating session...\n");
+ ppp_terminate(req->rpd->ppp, TERM_NAS_ERROR, 0);
+ return;
+ }
+ time(&req->rpd->acct_timestamp);
}
if (dt > conf_acct_timeout / 2) {
req->timeout.period += 1000;
@@ -147,10 +175,11 @@ static void rad_acct_timeout(struct triton_timer_t *t)
if (conf_acct_delay_time) {
req->pack->id++;
rad_packet_change_int(req->pack, NULL, "Acct-Delay-Time", dt);
- req_set_RA(req, conf_acct_secret);
+ req_set_RA(req, req->serv->acct_secret);
}
- rad_req_send(req, conf_interim_verbose);
+ __rad_req_send(req);
+
__sync_add_and_fetch(&stat_interim_sent, 1);
}
@@ -175,8 +204,10 @@ static void rad_acct_interim_update(struct triton_timer_t *t)
rad_packet_change_val(rpd->acct_req->pack, NULL, "Acct-Status-Type", "Interim-Update");
if (conf_acct_delay_time)
rad_packet_change_int(rpd->acct_req->pack, NULL, "Acct-Delay-Time", 0);
- req_set_RA(rpd->acct_req, conf_acct_secret);
- rad_req_send(rpd->acct_req, conf_interim_verbose);
+ req_set_RA(rpd->acct_req, rpd->acct_req->serv->acct_secret);
+
+ __rad_req_send(rpd->acct_req);
+
__sync_add_and_fetch(&stat_interim_sent, 1);
if (conf_acct_timeout) {
rpd->acct_req->timeout.period = conf_timeout * 1000;
@@ -189,8 +220,8 @@ int rad_acct_start(struct radius_pd_t *rpd)
int i;
time_t ts;
unsigned int dt;
-
- if (!conf_acct_secret)
+
+ if (!conf_accounting)
return 0;
rpd->acct_req = rad_req_alloc(rpd, CODE_ACCOUNTING_REQUEST, rpd->ppp->username);
@@ -216,50 +247,75 @@ int rad_acct_start(struct radius_pd_t *rpd)
time(&rpd->acct_timestamp);
- if (req_set_RA(rpd->acct_req, conf_acct_secret))
+ if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->acct_secret))
goto out_err;
- for (i = 0; i < conf_max_try; i++) {
- if (conf_acct_delay_time) {
- time(&ts);
- rad_packet_change_int(rpd->acct_req->pack, NULL, "Acct-Delay-Time", ts - rpd->acct_timestamp);
- if (req_set_RA(rpd->acct_req, conf_acct_secret))
+ while (1) {
+
+ if (rad_server_req_enter(rpd->acct_req)) {
+ if (rad_server_realloc(rpd->acct_req, 1)) {
+ log_ppp_warn("radius:acct_start: no servers available\n");
goto out_err;
+ }
+ if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->acct_secret))
+ goto out_err;
+ continue;
}
- if (rad_req_send(rpd->acct_req, conf_verbose))
- goto out_err;
- __sync_add_and_fetch(&stat_acct_sent, 1);
- rad_req_wait(rpd->acct_req, conf_timeout);
- if (!rpd->acct_req->reply) {
- if (conf_acct_delay_time)
+
+ for (i = 0; i < conf_max_try; i++) {
+ if (conf_acct_delay_time) {
+ time(&ts);
+ rad_packet_change_int(rpd->acct_req->pack, NULL, "Acct-Delay-Time", ts - rpd->acct_timestamp);
+ if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->acct_secret))
+ goto out_err;
+ }
+
+ if (rad_req_send(rpd->acct_req, conf_verbose))
+ goto out_err;
+
+ __sync_add_and_fetch(&stat_acct_sent, 1);
+
+ rad_req_wait(rpd->acct_req, conf_timeout);
+
+ if (!rpd->acct_req->reply) {
+ if (conf_acct_delay_time)
+ rpd->acct_req->pack->id++;
+ __sync_add_and_fetch(&stat_acct_lost, 1);
+ stat_accm_add(stat_acct_lost_1m, 1);
+ stat_accm_add(stat_acct_lost_5m, 1);
+ continue;
+ }
+
+ dt = (rpd->acct_req->reply->tv.tv_sec - rpd->acct_req->pack->tv.tv_sec) * 1000 +
+ (rpd->acct_req->reply->tv.tv_usec - rpd->acct_req->pack->tv.tv_usec) / 1000;
+ stat_accm_add(stat_acct_query_1m, dt);
+ stat_accm_add(stat_acct_query_5m, dt);
+
+ if (rpd->acct_req->reply->id != rpd->acct_req->pack->id || rpd->acct_req->reply->code != CODE_ACCOUNTING_RESPONSE) {
+ rad_packet_free(rpd->acct_req->reply);
+ rpd->acct_req->reply = NULL;
rpd->acct_req->pack->id++;
- __sync_add_and_fetch(&stat_acct_lost, 1);
- stat_accm_add(stat_acct_lost_1m, 1);
- stat_accm_add(stat_acct_lost_5m, 1);
- continue;
+ __sync_add_and_fetch(&stat_acct_lost, 1);
+ stat_accm_add(stat_acct_lost_1m, 1);
+ stat_accm_add(stat_acct_lost_5m, 1);
+ } else
+ break;
}
- dt = (rpd->acct_req->reply->tv.tv_sec - rpd->acct_req->pack->tv.tv_sec) * 1000 +
- (rpd->acct_req->reply->tv.tv_usec - rpd->acct_req->pack->tv.tv_usec) / 1000;
- stat_accm_add(stat_acct_query_1m, dt);
- stat_accm_add(stat_acct_query_5m, dt);
+ rad_server_req_exit(rpd->acct_req);
- if (rpd->acct_req->reply->id != rpd->acct_req->pack->id || rpd->acct_req->reply->code != CODE_ACCOUNTING_RESPONSE) {
- rad_packet_free(rpd->acct_req->reply);
- rpd->acct_req->reply = NULL;
- rpd->acct_req->pack->id++;
- __sync_add_and_fetch(&stat_acct_lost, 1);
- stat_accm_add(stat_acct_lost_1m, 1);
- stat_accm_add(stat_acct_lost_5m, 1);
+ if (!rpd->acct_req->reply) {
+ rad_server_fail(rpd->acct_req->serv);
+ if (rad_server_realloc(rpd->acct_req, 1)) {
+ log_ppp_warn("radius:acct_start: no servers available\n");
+ goto out_err;
+ }
+ if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->acct_secret))
+ goto out_err;
} else
break;
}
- if (!rpd->acct_req->reply) {
- log_ppp_warn("radius:acct_start: no response\n");
- goto out_err;
- }
-
rpd->acct_req->hnd.read = rad_acct_read;
triton_md_register_handler(rpd->ppp->ctrl->ctx, &rpd->acct_req->hnd);
@@ -290,7 +346,7 @@ void rad_acct_stop(struct radius_pd_t *rpd)
time_t ts;
unsigned int dt;
- if (!conf_acct_secret)
+ if (!rpd->acct_req || !rpd->acct_req->serv)
return;
if (rpd->acct_interim_timer.tpd)
@@ -330,7 +386,7 @@ void rad_acct_stop(struct radius_pd_t *rpd)
}
rad_packet_change_val(rpd->acct_req->pack, NULL, "Acct-Status-Type", "Stop");
req_set_stat(rpd->acct_req, rpd->ppp);
- req_set_RA(rpd->acct_req, conf_acct_secret);
+ req_set_RA(rpd->acct_req, rpd->acct_req->serv->acct_secret);
/// !!! rad_req_add_val(rpd->acct_req, "Acct-Terminate-Cause", "");
if (rpd->acct_req->reply) {
@@ -340,41 +396,63 @@ void rad_acct_stop(struct radius_pd_t *rpd)
time(&rpd->acct_timestamp);
- for(i = 0; i < conf_max_try; i++) {
- if (conf_acct_delay_time) {
- time(&ts);
- rad_packet_change_int(rpd->acct_req->pack, NULL, "Acct-Delay-Time", ts - rpd->acct_timestamp);
- rpd->acct_req->pack->id++;
- if (req_set_RA(rpd->acct_req, conf_acct_secret))
+ while (1) {
+
+ if (rad_server_req_enter(rpd->acct_req)) {
+ if (rad_server_realloc(rpd->acct_req, 1)) {
+ log_ppp_warn("radius:acct_stop: no servers available\n");
break;
- }
- if (rad_req_send(rpd->acct_req, conf_verbose))
- break;
- __sync_add_and_fetch(&stat_acct_sent, 1);
- rad_req_wait(rpd->acct_req, conf_timeout);
- if (!rpd->acct_req->reply) {
- __sync_add_and_fetch(&stat_acct_lost, 1);
- stat_accm_add(stat_acct_lost_1m, 1);
- stat_accm_add(stat_acct_lost_5m, 1);
+ }
+ req_set_RA(rpd->acct_req, rpd->acct_req->serv->acct_secret);
continue;
}
- dt = (rpd->acct_req->reply->tv.tv_sec - rpd->acct_req->pack->tv.tv_sec) * 1000 +
- (rpd->acct_req->reply->tv.tv_usec - rpd->acct_req->pack->tv.tv_usec) / 1000;
- stat_accm_add(stat_acct_query_1m, dt);
- stat_accm_add(stat_acct_query_5m, dt);
+ for(i = 0; i < conf_max_try; i++) {
+ if (conf_acct_delay_time) {
+ time(&ts);
+ rad_packet_change_int(rpd->acct_req->pack, NULL, "Acct-Delay-Time", ts - rpd->acct_timestamp);
+ rpd->acct_req->pack->id++;
+ if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->acct_secret))
+ break;
+ }
+ if (rad_req_send(rpd->acct_req, conf_verbose))
+ break;
+ __sync_add_and_fetch(&stat_acct_sent, 1);
+ rad_req_wait(rpd->acct_req, conf_timeout);
+ if (!rpd->acct_req->reply) {
+ __sync_add_and_fetch(&stat_acct_lost, 1);
+ stat_accm_add(stat_acct_lost_1m, 1);
+ stat_accm_add(stat_acct_lost_5m, 1);
+ continue;
+ }
+
+ dt = (rpd->acct_req->reply->tv.tv_sec - rpd->acct_req->pack->tv.tv_sec) * 1000 +
+ (rpd->acct_req->reply->tv.tv_usec - rpd->acct_req->pack->tv.tv_usec) / 1000;
+ stat_accm_add(stat_acct_query_1m, dt);
+ stat_accm_add(stat_acct_query_5m, dt);
+
+ if (rpd->acct_req->reply->id != rpd->acct_req->pack->id || rpd->acct_req->reply->code != CODE_ACCOUNTING_RESPONSE) {
+ rad_packet_free(rpd->acct_req->reply);
+ rpd->acct_req->reply = NULL;
+ __sync_add_and_fetch(&stat_acct_lost, 1);
+ stat_accm_add(stat_acct_lost_1m, 1);
+ stat_accm_add(stat_acct_lost_5m, 1);
+ } else
+ break;
+ }
- if (rpd->acct_req->reply->id != rpd->acct_req->pack->id || rpd->acct_req->reply->code != CODE_ACCOUNTING_RESPONSE) {
- rad_packet_free(rpd->acct_req->reply);
- rpd->acct_req->reply = NULL;
- __sync_add_and_fetch(&stat_acct_lost, 1);
- stat_accm_add(stat_acct_lost_1m, 1);
- stat_accm_add(stat_acct_lost_5m, 1);
- } else
+ rad_server_req_exit(rpd->acct_req);
+
+ if (rpd->acct_req->reply)
break;
+
+ rad_server_fail(rpd->acct_req->serv);
+ if (rad_server_realloc(rpd->acct_req, 1)) {
+ log_ppp_warn("radius:acct_stop: no servers available\n");
+ break;
+ }
+ req_set_RA(rpd->acct_req, rpd->acct_req->serv->acct_secret);
}
- if (!rpd->acct_req->reply)
- log_ppp_warn("radius:acct_stop: no response\n");
rad_req_free(rpd->acct_req);
rpd->acct_req = NULL;
diff --git a/accel-pppd/radius/auth.c b/accel-pppd/radius/auth.c
index a37da0b6..e4810fa6 100644
--- a/accel-pppd/radius/auth.c
+++ b/accel-pppd/radius/auth.c
@@ -30,7 +30,7 @@ static int decrypt_chap_mppe_keys(struct rad_req_t *req, struct rad_attr_t *attr
memcpy(plain, attr->val.octets, 32);
MD5_Init(&md5_ctx);
- MD5_Update(&md5_ctx, conf_auth_secret, strlen(conf_auth_secret));
+ MD5_Update(&md5_ctx, req->serv->auth_secret, strlen(req->serv->auth_secret));
MD5_Update(&md5_ctx, req->pack->buf + 4, 16);
MD5_Final(md5, &md5_ctx);
@@ -38,7 +38,7 @@ static int decrypt_chap_mppe_keys(struct rad_req_t *req, struct rad_attr_t *attr
plain[i] ^= md5[i];
MD5_Init(&md5_ctx);
- MD5_Update(&md5_ctx, conf_auth_secret, strlen(conf_auth_secret));
+ MD5_Update(&md5_ctx, req->serv->auth_secret, strlen(req->serv->auth_secret));
MD5_Update(&md5_ctx, attr->val.octets, 16);
MD5_Final(md5, &md5_ctx);
@@ -74,7 +74,7 @@ static int decrypt_mppe_key(struct rad_req_t *req, struct rad_attr_t *attr, uint
}
MD5_Init(&md5_ctx);
- MD5_Update(&md5_ctx, conf_auth_secret, strlen(conf_auth_secret));
+ MD5_Update(&md5_ctx, req->serv->auth_secret, strlen(req->serv->auth_secret));
MD5_Update(&md5_ctx, req->pack->buf + 4, 16);
MD5_Update(&md5_ctx, attr->val.octets, 2);
MD5_Final(md5, &md5_ctx);
@@ -90,7 +90,7 @@ static int decrypt_mppe_key(struct rad_req_t *req, struct rad_attr_t *attr, uint
}
MD5_Init(&md5_ctx);
- MD5_Update(&md5_ctx, conf_auth_secret, strlen(conf_auth_secret));
+ MD5_Update(&md5_ctx, req->serv->auth_secret, strlen(req->serv->auth_secret));
MD5_Update(&md5_ctx, attr->val.octets + 2, 16);
MD5_Final(md5, &md5_ctx);
@@ -145,42 +145,71 @@ static uint8_t* encrypt_password(const char *passwd, const char *secret, const u
static int rad_auth_send(struct rad_req_t *req)
{
int i;
- struct timeval tv;
+ struct timeval tv, tv2;
unsigned int dt;
+ int timeout;
- for(i = 0; i < conf_max_try; i++) {
- __sync_add_and_fetch(&stat_auth_sent, 1);
- gettimeofday(&tv, NULL);
- if (rad_req_send(req, conf_verbose))
- goto out;
+ while (1) {
+ if (rad_server_req_enter(req)) {
+ if (rad_server_realloc(req, 0)) {
+ log_ppp_warn("radius: no available servers\n");
+ break;
+ }
+ continue;
+ }
- rad_req_wait(req, conf_timeout);
+ for(i = 0; i < conf_max_try; i++) {
+ __sync_add_and_fetch(&stat_auth_sent, 1);
+ gettimeofday(&tv, NULL);
+ if (rad_req_send(req, conf_verbose))
+ goto out;
- if (req->reply) {
- if (req->reply->id != req->pack->id) {
- __sync_add_and_fetch(&stat_auth_lost, 1);
- stat_accm_add(stat_auth_lost_1m, 1);
- stat_accm_add(stat_auth_lost_5m, 1);
- rad_packet_free(req->reply);
- req->reply = NULL;
- } else {
+ timeout = conf_timeout;
+
+ while (timeout > 0) {
+
+ rad_req_wait(req, timeout);
+
+ if (req->reply) {
+ if (req->reply->id != req->pack->id) {
+ rad_packet_free(req->reply);
+ req->reply = NULL;
+ gettimeofday(&tv2, NULL);
+ timeout = conf_timeout - ((tv2.tv_sec - tv.tv_sec) * 1000 + (tv2.tv_usec - tv.tv_usec) / 1000);
+ } else
+ break;
+ } else
+ break;
+ }
+
+ if (req->reply) {
dt = (req->reply->tv.tv_sec - tv.tv_sec) * 1000 + (req->reply->tv.tv_usec - tv.tv_usec) / 1000;
stat_accm_add(stat_auth_query_1m, dt);
stat_accm_add(stat_auth_query_5m, dt);
break;
+ } else {
+ __sync_add_and_fetch(&stat_auth_lost, 1);
+ stat_accm_add(stat_auth_lost_1m, 1);
+ stat_accm_add(stat_auth_lost_5m, 1);
}
- } else
- __sync_add_and_fetch(&stat_auth_lost, 1);
- stat_accm_add(stat_auth_lost_1m, 1);
- stat_accm_add(stat_auth_lost_5m, 1);
- }
+ }
+
+ rad_server_req_exit(req);
- if (!req->reply)
- log_ppp_warn("radius:auth: no response\n");
- else if (req->reply->code == CODE_ACCESS_ACCEPT) {
- if (rad_proc_attrs(req))
- return PWDB_DENIED;
- return PWDB_SUCCESS;
+ if (!req->reply) {
+ rad_server_fail(req->serv);
+ if (rad_server_realloc(req, 0)) {
+ log_ppp_warn("radius: no available servers\n");
+ break;
+ }
+ } else {
+ if (req->reply->code == CODE_ACCESS_ACCEPT) {
+ if (rad_proc_attrs(req))
+ return PWDB_DENIED;
+ return PWDB_SUCCESS;
+ } else
+ break;
+ }
}
out:
@@ -200,7 +229,7 @@ int rad_auth_pap(struct radius_pd_t *rpd, const char *username, va_list args)
if (!req)
return PWDB_DENIED;
- epasswd = encrypt_password(passwd, conf_auth_secret, req->RA, &epasswd_len);
+ epasswd = encrypt_password(passwd, req->serv->auth_secret, req->RA, &epasswd_len);
if (!epasswd)
goto out;
diff --git a/accel-pppd/radius/radius.c b/accel-pppd/radius/radius.c
index 5663af99..0fc42cd1 100644
--- a/accel-pppd/radius/radius.c
+++ b/accel-pppd/radius/radius.c
@@ -34,14 +34,6 @@ in_addr_t conf_bind;
int conf_verbose;
int conf_interim_verbose;
-in_addr_t conf_auth_server;
-int conf_auth_server_port = 1812;
-char *conf_auth_secret;
-
-in_addr_t conf_acct_server;
-int conf_acct_server_port = 1813;
-char *conf_acct_secret;
-
in_addr_t conf_dm_coa_server;
int conf_dm_coa_port = 3799;
char *conf_dm_coa_secret;
@@ -50,6 +42,9 @@ int conf_sid_in_auth;
int conf_require_nas_ident;
int conf_acct_interim_interval;
+int conf_accounting;
+int conf_fail_time = 60;
+
unsigned long stat_auth_sent;
unsigned long stat_auth_lost;
unsigned long stat_acct_sent;
@@ -494,27 +489,6 @@ static int load_config(void)
else if (conf_nas_ip_address)
conf_bind = conf_nas_ip_address;
- opt = conf_get_opt("radius", "auth-server");
- if (!opt)
- opt = conf_get_opt("radius", "auth_server");
- if (!opt) {
- log_emerg("radius: auth-server not specified\n");
- return -1;
- } else if (parse_server(opt, &conf_auth_server, &conf_auth_server_port, &conf_auth_secret)) {
- log_emerg("radius: failed to parse auth_server\n");
- return -1;
- }
-
- opt = conf_get_opt("radius", "acct-server");
- if (!opt)
- opt = conf_get_opt("radius", "acct_server");
- if (!opt)
- log_emerg("radius: acct-server not specified\n");
- if (opt && parse_server(opt, &conf_acct_server, &conf_acct_server_port, &conf_acct_secret)) {
- log_emerg("radius: failed to parse acct_server\n");
- return -1;
- }
-
opt = conf_get_opt("radius", "dae-server");
if (opt && parse_server(opt, &conf_dm_coa_server, &conf_dm_coa_port, &conf_dm_coa_secret)) {
log_emerg("radius: failed to parse dae-server\n");
@@ -537,6 +511,10 @@ static int load_config(void)
if (opt)
conf_acct_delay_time = atoi(opt);
+ opt = conf_get_opt("radius", "fail-time");
+ if (opt)
+ conf_fail_time = atoi(opt);
+
return 0;
}
diff --git a/accel-pppd/radius/radius_p.h b/accel-pppd/radius/radius_p.h
index 929fe8e6..8c3a10d5 100644
--- a/accel-pppd/radius/radius_p.h
+++ b/accel-pppd/radius/radius_p.h
@@ -10,6 +10,8 @@
#include "ppp.h"
#include "ipdb.h"
+struct rad_server_t;
+
struct radius_pd_t
{
struct list_head entry;
@@ -46,16 +48,37 @@ struct radius_pd_t
struct rad_req_t
{
+ struct list_head entry;
struct triton_context_t ctx;
struct triton_md_handler_t hnd;
struct triton_timer_t timeout;
uint8_t RA[16];
struct rad_packet_t *pack;
struct rad_packet_t *reply;
+
+ struct radius_pd_t *rpd;
+ struct rad_server_t *serv;
+
in_addr_t server_addr;
int server_port;
+};
- struct radius_pd_t *rpd;
+struct rad_server_t
+{
+ struct list_head entry;
+ in_addr_t auth_addr;
+ int auth_port;
+ char *auth_secret;
+ in_addr_t acct_addr;
+ int acct_port;
+ char *acct_secret;
+ int max_req_cnt;
+ int req_cnt;
+ struct list_head req_queue;
+ int client_cnt;
+ time_t fail_time;
+ int conf_fail_time;
+ pthread_mutex_t lock;
};
@@ -70,17 +93,14 @@ extern in_addr_t conf_nas_ip_address;
extern in_addr_t conf_bind;
extern in_addr_t conf_gw_ip_address;
extern in_addr_t conf_auth_server;
-extern char *conf_auth_secret;
-extern int conf_auth_server_port;
-extern in_addr_t conf_acct_server;
-extern char *conf_acct_secret;
-extern int conf_acct_server_port;
extern char *conf_dm_coa_secret;
extern int conf_sid_in_auth;
extern int conf_require_nas_ident;
extern in_addr_t conf_dm_coa_server;
extern int conf_dm_coa_port;
extern int conf_acct_interim_interval;
+extern int conf_accounting;
+extern int conf_fail_time;
extern unsigned long stat_auth_sent;
extern unsigned long stat_auth_lost;
@@ -122,6 +142,13 @@ int rad_packet_send(struct rad_packet_t *pck, int fd, struct sockaddr_in *addr);
void dm_coa_cancel(struct radius_pd_t *pd);
+struct rad_server_t *rad_server_get(int);
+void rad_server_put(struct rad_server_t *);
+int rad_server_req_enter(struct rad_req_t *);
+void rad_server_req_exit(struct rad_req_t *);
+int rad_server_realloc(struct rad_req_t *, int);
+void rad_server_fail(struct rad_server_t *);
+
struct stat_accm_t;
struct stat_accm_t *stat_accm_create(unsigned int time);
void stat_accm_add(struct stat_accm_t *, unsigned int);
diff --git a/accel-pppd/radius/req.c b/accel-pppd/radius/req.c
index 7b865038..f3d72f83 100644
--- a/accel-pppd/radius/req.c
+++ b/accel-pppd/radius/req.c
@@ -32,8 +32,12 @@ struct rad_req_t *rad_req_alloc(struct radius_pd_t *rpd, int code, const char *u
req->hnd.fd = -1;
req->ctx.before_switch = log_switch;
- req->server_addr = conf_auth_server;
- req->server_port = conf_auth_server_port;
+ req->serv = rad_server_get(code == CODE_ACCOUNTING_REQUEST);
+ if (!req->serv)
+ goto out_err;
+
+ req->server_addr = req->serv->auth_addr;
+ req->server_port = req->serv->auth_port;
while (1) {
if (read(urandom_fd, req->RA, 16) != 16) {
@@ -97,8 +101,8 @@ out_err:
int rad_req_acct_fill(struct rad_req_t *req)
{
- req->server_addr = conf_acct_server;
- req->server_port = conf_acct_server_port;
+ req->server_addr = req->serv->acct_addr;
+ req->server_port = req->serv->acct_port;
memset(req->RA, 0, sizeof(req->RA));
@@ -132,6 +136,8 @@ int rad_req_acct_fill(struct rad_req_t *req)
void rad_req_free(struct rad_req_t *req)
{
+ if (req->serv)
+ rad_server_put(req->serv);
if (req->hnd.fd >= 0 )
close(req->hnd.fd);
if (req->pack)
diff --git a/accel-pppd/radius/serv.c b/accel-pppd/radius/serv.c
new file mode 100644
index 00000000..0d9eb260
--- /dev/null
+++ b/accel-pppd/radius/serv.c
@@ -0,0 +1,322 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sched.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "log.h"
+#include "triton.h"
+#include "radius_p.h"
+
+#include "memdebug.h"
+
+static LIST_HEAD(serv_list);
+
+struct rad_server_t *rad_server_get(int type)
+{
+ struct rad_server_t *s, *s0 = NULL;
+
+ list_for_each_entry(s, &serv_list, entry) {
+ if (s->fail_time && time(NULL) < s->fail_time)
+ continue;
+
+ if (type == 0 && !s->auth_addr)
+ continue;
+ else if (type == 1 && !s->acct_addr)
+ continue;
+
+ if (!s0) {
+ s0 = s;
+ continue;
+ }
+
+ if (s->client_cnt < s0->client_cnt)
+ s0 = s;
+ }
+
+ if (!s0)
+ return NULL;
+
+ __sync_add_and_fetch(&s0->client_cnt, 1);
+
+ return s0;
+}
+
+void rad_server_put(struct rad_server_t *s)
+{
+ __sync_sub_and_fetch(&s->client_cnt, 1);
+}
+
+int rad_server_req_enter(struct rad_req_t *req)
+{
+ if (!req->serv->max_req_cnt)
+ return 0;
+
+ pthread_mutex_lock(&req->serv->lock);
+
+ if (time(NULL) < req->serv->fail_time) {
+ pthread_mutex_unlock(&req->serv->lock);
+ return -1;
+ }
+
+ if (req->serv->req_cnt >= req->serv->max_req_cnt) {
+ list_add_tail(&req->entry, &req->serv->req_queue);
+ pthread_mutex_unlock(&req->serv->lock);
+ triton_context_schedule();
+ pthread_mutex_lock(&req->serv->lock);
+
+ if (time(NULL) < req->serv->fail_time) {
+ pthread_mutex_unlock(&req->serv->lock);
+ return -1;
+ }
+ }
+
+ req->serv->req_cnt++;
+ pthread_mutex_unlock(&req->serv->lock);
+
+ return 0;
+}
+
+void rad_server_req_exit(struct rad_req_t *req)
+{
+ struct rad_req_t *r = NULL;
+
+ if (!req->serv->max_req_cnt)
+ return;
+
+ pthread_mutex_lock(&req->serv->lock);
+ req->serv->req_cnt--;
+ if (req->serv->req_cnt < req->serv->max_req_cnt && !list_empty(&req->serv->req_queue)) {
+ r = list_entry(req->serv->req_queue.next, typeof(*r), entry);
+ list_del(&r->entry);
+ }
+ pthread_mutex_unlock(&req->serv->lock);
+
+ if (r)
+ triton_context_wakeup(r->rpd->ppp->ctrl->ctx);
+}
+
+int rad_server_realloc(struct rad_req_t *req, int type)
+{
+ if (req->hnd.fd != -1) {
+ close(req->hnd.fd);
+ req->hnd.fd = -1;
+ }
+
+ if (req->serv)
+ rad_server_put(req->serv);
+
+ req->serv = rad_server_get(type);
+
+ if (!req->serv)
+ return -1;
+
+ if (type) {
+ req->server_addr = req->serv->acct_addr;
+ req->server_port = req->serv->acct_port;
+ } else {
+ req->server_addr = req->serv->auth_addr;
+ req->server_port = req->serv->auth_port;
+ }
+
+ return 0;
+}
+
+void rad_server_fail(struct rad_server_t *s)
+{
+ struct rad_req_t *r;
+ time_t t;
+
+ pthread_mutex_lock(&s->lock);
+ t = time(NULL);
+
+ if (t > s->fail_time) {
+ s->fail_time = t + s->conf_fail_time;
+ log_ppp_warn("radius: server not responding\n");
+ log_warn("radius: server noy responding\n");
+ }
+
+ while (!list_empty(&s->req_queue)) {
+ r = list_entry(s->req_queue.next, typeof(*r), entry);
+ list_del(&r->entry);
+ triton_context_wakeup(r->rpd->ppp->ctrl->ctx);
+ }
+ pthread_mutex_unlock(&s->lock);
+}
+
+static void __add_server(struct rad_server_t *s)
+{
+ INIT_LIST_HEAD(&s->req_queue);
+ pthread_mutex_init(&s->lock, NULL);
+ s->conf_fail_time = conf_fail_time;
+ list_add_tail(&s->entry, &serv_list);
+}
+
+static int parse_server_old(const char *opt, in_addr_t *addr, int *port, char **secret)
+{
+ char *str = _strdup(opt);
+ char *p1, *p2;
+
+ p1 = strstr(str, ":");
+ p2 = strstr(str, ",");
+
+ if (p1)
+ *p1 = 0;
+ if (p2)
+ *p2 = 0;
+ else
+ return -1;
+
+ *addr = inet_addr(str);
+
+ if (p1) {
+ *port = atoi(p1 + 1);
+ if (*port <=0 )
+ return -1;
+ }
+
+ p1 = _strdup(p2 + 1);
+ p2 = *secret;
+ *secret = p1;
+ if (p2)
+ _free(p2);
+
+ _free(str);
+
+ return 0;
+}
+
+static void add_server_old(void)
+{
+ const char *opt;
+ struct rad_server_t *s = _malloc(sizeof(*s));
+
+ memset(s, 0, sizeof(*s));
+
+ opt = conf_get_opt("radius", "auth-server");
+ if (opt) {
+ if (parse_server_old(opt, &s->auth_addr, &s->auth_port, &s->auth_secret)) {
+ log_emerg("radius: failed to parse 'auth-server'\n");
+ goto out;
+ }
+ }
+
+ opt = conf_get_opt("radius", "acct-server");
+ if (opt) {
+ if (parse_server_old(opt, &s->acct_addr, &s->acct_port, &s->acct_secret)) {
+ log_emerg("radius: failed to parse 'acct-server'\n");
+ goto out;
+ }
+ conf_accounting = 1;
+ }
+
+ if (s->auth_addr || s->acct_addr) {
+ __add_server(s);
+ return;
+ }
+
+out:
+ _free(s);
+}
+
+static int parse_server(const char *_opt, struct rad_server_t *s)
+{
+ char *opt = _strdup(_opt);
+ char *ptr1, *ptr2, *ptr3, *endptr;
+
+ ptr1 = strchr(opt, ',');
+ if (!ptr1)
+ goto out;
+
+ ptr2 = strchr(ptr1 + 1, ',');
+
+ if (ptr2)
+ ptr3 = strchr(ptr2 + 1, ',');
+ else
+ ptr3 = NULL;
+
+ *ptr1 = 0;
+ if (ptr2)
+ *ptr2 = 0;
+ if (ptr3)
+ *ptr3 = 0;
+
+ s->auth_addr = s->acct_addr = inet_addr(opt);
+
+ if (ptr2) {
+ if (ptr2[1]) {
+ s->auth_port = strtol(ptr2 + 1, &endptr, 10);
+ if (*endptr)
+ goto out;
+ }
+ if (!s->auth_port)
+ s->auth_addr = 0;
+ } else
+ s->auth_port = 1812;
+
+ if (ptr3) {
+ if (ptr3[1]) {
+ s->acct_port = strtol(ptr3 + 1, &endptr, 10);
+ if (*endptr)
+ goto out;
+ }
+ if (!s->acct_port)
+ s->acct_addr = 0;
+ } else
+ s->acct_port = 1813;
+
+ if (!s->auth_addr && !s->acct_addr)
+ goto out;
+
+ if (s->auth_addr)
+ s->auth_secret = _strdup(ptr1 + 1);
+
+ if (s->acct_addr) {
+ s->acct_secret = _strdup(ptr1 + 1);
+ conf_accounting = 1;
+ }
+
+ return 0;
+
+out:
+ _free(opt);
+
+ return -1;
+}
+
+static void add_server(const char *opt)
+{
+ struct rad_server_t *s = _malloc(sizeof(*s));
+
+ memset(s, 0, sizeof(*s));
+
+ if (parse_server(opt, s)) {
+ log_emerg("radius: failed to parse '%s'\n", opt);
+ _free(s);
+ return;
+ }
+
+ __add_server(s);
+}
+
+static void init(void)
+{
+ struct conf_sect_t *s = conf_get_section("radius");
+ struct conf_option_t *opt;
+
+ add_server_old();
+
+
+ list_for_each_entry(opt, &s->items, entry) {
+ if (strcmp(opt->name, "server"))
+ continue;
+ add_server(opt->val);
+ }
+}
+
+DEFINE_INIT(21, init);