summaryrefslogtreecommitdiff
path: root/accel-pppd/radius
diff options
context:
space:
mode:
authorKozlov Dmitry <xeb@mail.ru>2012-07-10 18:58:53 +0400
committerKozlov Dmitry <xeb@mail.ru>2012-07-10 18:58:53 +0400
commit80c32d237e01b1c05663ccfa34003d2f49aa7eee (patch)
treea49da21b5219e4bc89d9794918f054f3620cb140 /accel-pppd/radius
parent64b5b693764c4f36870fd988ccbb53bcb188e74d (diff)
downloadaccel-ppp-80c32d237e01b1c05663ccfa34003d2f49aa7eee.tar.gz
accel-ppp-80c32d237e01b1c05663ccfa34003d2f49aa7eee.zip
initial session backup implementation
Diffstat (limited to 'accel-pppd/radius')
-rw-r--r--accel-pppd/radius/CMakeLists.txt4
-rw-r--r--accel-pppd/radius/acct.c112
-rw-r--r--accel-pppd/radius/backup.c163
-rw-r--r--accel-pppd/radius/radius.c17
-rw-r--r--accel-pppd/radius/radius_p.h5
-rw-r--r--accel-pppd/radius/req.c29
-rw-r--r--accel-pppd/radius/serv.c26
7 files changed, 293 insertions, 63 deletions
diff --git a/accel-pppd/radius/CMakeLists.txt b/accel-pppd/radius/CMakeLists.txt
index 0c1789ef..d139fe1f 100644
--- a/accel-pppd/radius/CMakeLists.txt
+++ b/accel-pppd/radius/CMakeLists.txt
@@ -10,6 +10,10 @@ SET(sources
radius.c
)
+IF (BACKUP)
+ SET(sources ${sources} backup.c)
+ENDIF (BACKUP)
+
ADD_DEFINITIONS(-DDICTIONARY="${CMAKE_INSTALL_PREFIX}/share/accel-ppp/radius/dictionary")
ADD_LIBRARY(radius SHARED ${sources})
diff --git a/accel-pppd/radius/acct.c b/accel-pppd/radius/acct.c
index dfc982d4..b5f7ff76 100644
--- a/accel-pppd/radius/acct.c
+++ b/accel-pppd/radius/acct.c
@@ -10,6 +10,8 @@
#include "crypto.h"
#include "log.h"
+#include "backup.h"
+#include "ap_session_backup.h"
#include "radius_p.h"
#include "memdebug.h"
@@ -235,7 +237,9 @@ int rad_acct_start(struct radius_pd_t *rpd)
if (!conf_accounting)
return 0;
- rpd->acct_req = rad_req_alloc(rpd, CODE_ACCOUNTING_REQUEST, rpd->ses->username);
+ if (!rpd->acct_req)
+ rpd->acct_req = rad_req_alloc(rpd, CODE_ACCOUNTING_REQUEST, rpd->ses->username);
+
if (!rpd->acct_req)
return -1;
@@ -259,71 +263,77 @@ int rad_acct_start(struct radius_pd_t *rpd)
if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret))
goto out_err;
- while (1) {
-
- if (rad_server_req_enter(rpd->acct_req)) {
- if (rad_server_realloc(rpd->acct_req)) {
- log_ppp_warn("radius:acct_start: no servers available\n");
- goto out_err;
- }
- if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret))
- goto out_err;
- continue;
- }
+#ifdef USE_BACKUP
+ if (rpd->ses->state != AP_STATE_RESTORE || !rpd->ses->backup->internal) {
+#endif
+ while (1) {
- 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 (rad_server_req_enter(rpd->acct_req)) {
+ if (rad_server_realloc(rpd->acct_req)) {
+ log_ppp_warn("radius:acct_start: no servers available\n");
+ goto out_err;
+ }
if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret))
goto out_err;
+ continue;
}
- if (rad_req_send(rpd->acct_req, conf_verbose))
- 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, rpd->acct_req->serv->secret))
+ goto out_err;
+ }
- __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_sent, 1);
+ if (rad_req_send(rpd->acct_req, conf_verbose))
+ goto out_err;
+
+ __sync_add_and_fetch(&rpd->acct_req->serv->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(&rpd->acct_req->serv->stat_acct_lost, 1);
+ stat_accm_add(rpd->acct_req->serv->stat_acct_lost_1m, 1);
+ stat_accm_add(rpd->acct_req->serv->stat_acct_lost_5m, 1);
+ continue;
+ }
- rad_req_wait(rpd->acct_req, conf_timeout);
+ dt = (rpd->acct_req->reply->tv.tv_sec - rpd->acct_req->pack->tv.tv_sec) * 1000 +
+ (rpd->acct_req->reply->tv.tv_nsec - rpd->acct_req->pack->tv.tv_nsec) / 1000000;
+ stat_accm_add(rpd->acct_req->serv->stat_acct_query_1m, dt);
+ stat_accm_add(rpd->acct_req->serv->stat_acct_query_5m, dt);
- if (!rpd->acct_req->reply) {
- if (conf_acct_delay_time)
+ 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(&rpd->acct_req->serv->stat_acct_lost, 1);
- stat_accm_add(rpd->acct_req->serv->stat_acct_lost_1m, 1);
- stat_accm_add(rpd->acct_req->serv->stat_acct_lost_5m, 1);
- continue;
+ __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_lost, 1);
+ stat_accm_add(rpd->acct_req->serv->stat_acct_lost_1m, 1);
+ stat_accm_add(rpd->acct_req->serv->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_nsec - rpd->acct_req->pack->tv.tv_nsec) / 1000000;
- stat_accm_add(rpd->acct_req->serv->stat_acct_query_1m, dt);
- stat_accm_add(rpd->acct_req->serv->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(&rpd->acct_req->serv->stat_acct_lost, 1);
- stat_accm_add(rpd->acct_req->serv->stat_acct_lost_1m, 1);
- stat_accm_add(rpd->acct_req->serv->stat_acct_lost_5m, 1);
- } else
- break;
- }
-
- rad_server_req_exit(rpd->acct_req);
+ rad_server_req_exit(rpd->acct_req);
- if (rpd->acct_req->reply)
- break;
+ if (rpd->acct_req->reply)
+ break;
- rad_server_fail(rpd->acct_req->serv);
- if (rad_server_realloc(rpd->acct_req)) {
- log_ppp_warn("radius:acct_start: no servers available\n");
- goto out_err;
+ rad_server_fail(rpd->acct_req->serv);
+ if (rad_server_realloc(rpd->acct_req)) {
+ log_ppp_warn("radius:acct_start: no servers available\n");
+ goto out_err;
+ }
+ if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret))
+ goto out_err;
}
- if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret))
- goto out_err;
+#ifdef USE_BACKUP
}
+#endif
rpd->acct_req->hnd.read = rad_acct_read;
diff --git a/accel-pppd/radius/backup.c b/accel-pppd/radius/backup.c
new file mode 100644
index 00000000..4c40ec61
--- /dev/null
+++ b/accel-pppd/radius/backup.c
@@ -0,0 +1,163 @@
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <net/ethernet.h>
+
+#include "log.h"
+#include "memdebug.h"
+
+#include "backup.h"
+#include "ap_session_backup.h"
+#include "radius_p.h"
+
+#define RAD_TAG_INTERIM_INTERVAL 1
+#define RAD_TAG_SESSION_TIMEOUT 2
+#define RAD_TAG_IPV4_ADDR 3
+#define RAD_TAG_IPV6_ADDR 4
+#define RAD_TAG_IPV6_DP 5
+#define RAD_TAG_ATTR_CLASS 6
+#define RAD_TAG_ATTR_STATE 7
+#define RAD_TAG_TERMINATION_ACTION 8
+#define RAD_TAG_ACCT_SERVER_ADDR 9
+#define RAD_TAG_ACCT_SERVER_PORT 10
+
+
+#define add_tag(id, data, size) if (!backup_add_tag(m, id, 0, data, size)) return -1;
+#define add_tag_int(id, data, size) if (!backup_add_tag(m, id, 1, data, size)) return -1;
+
+static int session_save(struct ap_session *ses, struct backup_mod *m)
+{
+ struct radius_pd_t *rpd = find_pd(ses);
+ uint64_t session_timeout = ses->start_time + rpd->session_timeout.expire_tv.tv_sec;
+
+ if (!rpd)
+ return 0;
+
+ if (!rpd->authenticated)
+ return -2;
+
+ add_tag(RAD_TAG_INTERIM_INTERVAL, &rpd->acct_interim_interval, 4);
+
+ if (rpd->session_timeout.tpd)
+ add_tag(RAD_TAG_SESSION_TIMEOUT, &session_timeout, 8);
+
+ if (ses->ipv4 == &rpd->ipv4_addr)
+ add_tag(RAD_TAG_IPV4_ADDR, NULL, 0);
+
+ if (ses->ipv6 == &rpd->ipv6_addr)
+ add_tag(RAD_TAG_IPV6_ADDR, NULL, 0);
+
+ /*if (rpd->ipv6_pd_assigned) {
+
+ }*/
+
+ if (rpd->attr_class)
+ add_tag(RAD_TAG_ATTR_CLASS, rpd->attr_class, rpd->attr_class_len);
+
+ if (rpd->attr_state)
+ add_tag(RAD_TAG_ATTR_CLASS, rpd->attr_state, rpd->attr_state_len);
+
+ add_tag(RAD_TAG_TERMINATION_ACTION, &rpd->termination_action, 4);
+
+ if (rpd->acct_req) {
+ add_tag(RAD_TAG_ACCT_SERVER_ADDR, &rpd->acct_req->server_addr, 4);
+ add_tag(RAD_TAG_ACCT_SERVER_PORT, &rpd->acct_req->server_port, 2);
+ }
+
+ return 0;
+}
+
+static int session_restore(struct ap_session *ses, struct backup_mod *m)
+{
+ return 0;
+}
+
+static void restore_ipv4_addr(struct ap_session *ses)
+{
+ struct backup_mod *m = backup_find_mod(ses->backup, MODID_COMMON);
+ struct backup_tag *tag;
+
+ list_for_each_entry(tag, &m->tag_list, entry) {
+ switch (tag->id) {
+ case SES_TAG_IPV4_ADDR:
+ ses->ipv4->addr = *(in_addr_t *)tag->data;
+ break;
+ case SES_TAG_IPV4_PEER_ADDR:
+ ses->ipv4->peer_addr = *(in_addr_t *)tag->data;
+ break;
+ }
+ }
+}
+
+static void restore_ipv6_addr(struct ap_session *ses)
+{
+
+}
+
+void radius_restore_session(struct ap_session *ses, struct radius_pd_t *rpd)
+{
+ struct backup_mod *m = backup_find_mod(ses->backup, MODID_RADIUS);
+ struct backup_tag *tag;
+ in_addr_t acct_addr = 0;
+ int acct_port;
+
+ if (!m)
+ return;
+
+ list_for_each_entry(tag, &m->tag_list, entry) {
+ switch (tag->id) {
+ case RAD_TAG_INTERIM_INTERVAL:
+ rpd->acct_interim_interval = *(uint32_t *)tag->data;
+ break;
+ case RAD_TAG_SESSION_TIMEOUT:
+ rpd->session_timeout.expire_tv.tv_sec = *(uint64_t *)tag->data - ses->start_time;
+ break;
+ case RAD_TAG_IPV4_ADDR:
+ ses->ipv4 = &rpd->ipv4_addr;
+ restore_ipv4_addr(ses);
+ break;
+ case RAD_TAG_IPV6_ADDR:
+ restore_ipv6_addr(ses);
+ break;
+ case RAD_TAG_ATTR_CLASS:
+ rpd->attr_class = _malloc(tag->size);
+ memcpy(rpd->attr_class, tag->data, tag->size);
+ rpd->attr_class_len = tag->size;
+ break;
+ case RAD_TAG_ATTR_STATE:
+ rpd->attr_state = _malloc(tag->size);
+ memcpy(rpd->attr_state, tag->data, tag->size);
+ rpd->attr_state_len = tag->size;
+ break;
+ case RAD_TAG_TERMINATION_ACTION:
+ rpd->termination_action = *(uint32_t *)tag->data;
+ break;
+ case RAD_TAG_ACCT_SERVER_ADDR:
+ acct_addr = *(in_addr_t *)tag->data;
+ break;
+ case RAD_TAG_ACCT_SERVER_PORT:
+ acct_port = *(uint16_t *)tag->data;
+ break;
+ }
+ }
+
+ if (acct_addr)
+ rpd->acct_req = rad_req_alloc2(rpd, CODE_ACCOUNTING_REQUEST, rpd->ses->username, acct_addr, acct_port);
+
+ rpd->authenticated = 1;
+}
+
+static struct backup_module mod = {
+ .id = MODID_RADIUS,
+ .save = session_save,
+ .restore = session_restore,
+};
+
+static void init(void)
+{
+ backup_register_module(&mod);
+}
+
+DEFINE_INIT(100, init);
+
diff --git a/accel-pppd/radius/radius.c b/accel-pppd/radius/radius.c
index d880ad01..82ac979d 100644
--- a/accel-pppd/radius/radius.c
+++ b/accel-pppd/radius/radius.c
@@ -84,7 +84,6 @@ int rad_proc_attrs(struct rad_req_t *req)
if (!conf_gw_ip_address)
log_ppp_warn("radius: gw-ip-address not specified, cann't assign IP address...\n");
else {
- req->rpd->ipv4_addr.owner = &ipdb;
req->rpd->ipv4_addr.peer_addr = attr->val.ipaddr;
req->rpd->ipv4_addr.addr = conf_gw_ip_address;
}
@@ -190,7 +189,6 @@ static struct ipv6db_item_t *get_ipv6(struct ap_session *ses)
{
struct radius_pd_t *rpd = find_pd(ses);
- rpd->ipv6_addr.owner = &ipdb;
rpd->ipv6_addr.intf_id = 0;
if (!list_empty(&rpd->ipv6_addr.addr_list))
@@ -203,10 +201,10 @@ static struct ipv6db_prefix_t *get_ipv6_prefix(struct ap_session *ses)
{
struct radius_pd_t *rpd = find_pd(ses);
- rpd->ipv6_dp.owner = &ipdb;
-
- if (!list_empty(&rpd->ipv6_dp.prefix_list))
+ if (!list_empty(&rpd->ipv6_dp.prefix_list)) {
+ rpd->ipv6_dp_assigned = 1;
return &rpd->ipv6_dp;
+ }
return NULL;
}
@@ -240,12 +238,21 @@ static void ses_starting(struct ap_session *ses)
INIT_LIST_HEAD(&rpd->plugin_list);
INIT_LIST_HEAD(&rpd->ipv6_addr.addr_list);
INIT_LIST_HEAD(&rpd->ipv6_dp.prefix_list);
+
+ rpd->ipv4_addr.owner = &ipdb;
+ rpd->ipv6_addr.owner = &ipdb;
+ rpd->ipv6_dp.owner = &ipdb;
list_add_tail(&rpd->pd.entry, &ses->pd_list);
pthread_rwlock_wrlock(&sessions_lock);
list_add_tail(&rpd->entry, &sessions);
pthread_rwlock_unlock(&sessions_lock);
+
+#ifdef USE_BACKUP
+ if (ses->state == AP_STATE_RESTORE && ses->backup)
+ radius_restore_session(ses, rpd);
+#endif
}
static void ses_acct_start(struct ap_session *ses)
diff --git a/accel-pppd/radius/radius_p.h b/accel-pppd/radius/radius_p.h
index f8adb465..07093517 100644
--- a/accel-pppd/radius/radius_p.h
+++ b/accel-pppd/radius/radius_p.h
@@ -19,6 +19,7 @@ struct radius_pd_t
struct ap_session *ses;
pthread_mutex_t lock;
int authenticated:1;
+ int ipv6_dp_assigned:1;
struct rad_req_t *auth_req;
struct rad_req_t *acct_req;
@@ -142,6 +143,7 @@ int rad_dict_load(const char *fname);
void rad_dict_free(struct rad_dict_t *dict);
struct rad_req_t *rad_req_alloc(struct radius_pd_t *rpd, int code, const char *username);
+struct rad_req_t *rad_req_alloc2(struct radius_pd_t *rpd, int code, const char *username, in_addr_t addr, int port);
int rad_req_acct_fill(struct rad_req_t *);
void rad_req_free(struct rad_req_t *);
int rad_req_send(struct rad_req_t *, int verbose);
@@ -169,6 +171,7 @@ 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);
+struct rad_server_t *rad_server_get2(int, in_addr_t, int);
void rad_server_put(struct rad_server_t *, int);
int rad_server_req_enter(struct rad_req_t *);
void rad_server_req_exit(struct rad_req_t *);
@@ -176,6 +179,8 @@ int rad_server_realloc(struct rad_req_t *);
void rad_server_fail(struct rad_server_t *);
void rad_server_timeout(struct rad_server_t *);
void rad_server_reply(struct rad_server_t *);
+
+void radius_restore_session(struct ap_session *ses, struct radius_pd_t *rpd);
struct stat_accm_t;
struct stat_accm_t *stat_accm_create(unsigned int time);
diff --git a/accel-pppd/radius/req.c b/accel-pppd/radius/req.c
index f452c425..cd9a170b 100644
--- a/accel-pppd/radius/req.c
+++ b/accel-pppd/radius/req.c
@@ -16,8 +16,9 @@
static int rad_req_read(struct triton_md_handler_t *h);
static void rad_req_timeout(struct triton_timer_t *t);
+static int make_socket(struct rad_req_t *req);
-struct rad_req_t *rad_req_alloc(struct radius_pd_t *rpd, int code, const char *username)
+static struct rad_req_t *__rad_req_alloc(struct radius_pd_t *rpd, int code, const char *username, in_addr_t addr, int port)
{
struct rad_plugin_t *plugin;
struct ppp_t *ppp = NULL;
@@ -38,7 +39,11 @@ struct rad_req_t *rad_req_alloc(struct radius_pd_t *rpd, int code, const char *u
req->type = code == CODE_ACCESS_REQUEST ? RAD_SERV_AUTH : RAD_SERV_ACCT;
- req->serv = rad_server_get(req->type);
+ if (addr)
+ req->serv = rad_server_get2(req->type, addr, port);
+ else
+ req->serv = rad_server_get(req->type);
+
if (!req->serv)
goto out_err;
@@ -120,6 +125,26 @@ out_err:
return NULL;
}
+struct rad_req_t *rad_req_alloc(struct radius_pd_t *rpd, int code, const char *username)
+{
+ return __rad_req_alloc(rpd, code, username, 0, 0);
+}
+
+struct rad_req_t *rad_req_alloc2(struct radius_pd_t *rpd, int code, const char *username, in_addr_t addr, int port)
+{
+ struct rad_req_t *req = __rad_req_alloc(rpd, code, username, addr, port);
+
+ if (!req)
+ return NULL;
+
+ if (code == CODE_ACCOUNTING_REQUEST)
+ req->server_port = req->serv->acct_port;
+
+ make_socket(req);
+
+ return req;
+}
+
int rad_req_acct_fill(struct rad_req_t *req)
{
struct ipv6db_addr_t *a;
diff --git a/accel-pppd/radius/serv.c b/accel-pppd/radius/serv.c
index 4de6ad1e..aae37190 100644
--- a/accel-pppd/radius/serv.c
+++ b/accel-pppd/radius/serv.c
@@ -24,9 +24,9 @@ static LIST_HEAD(serv_list);
static void __free_server(struct rad_server_t *);
-static struct rad_server_t *__rad_server_get(int type, struct rad_server_t *exclude)
+static struct rad_server_t *__rad_server_get(int type, struct rad_server_t *exclude, in_addr_t addr, int port)
{
- struct rad_server_t *s, *s0 = NULL;
+ struct rad_server_t *s, *s0 = NULL, *s1 = NULL;
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
@@ -43,6 +43,15 @@ static struct rad_server_t *__rad_server_get(int type, struct rad_server_t *excl
else if (type == RAD_SERV_ACCT && !s->acct_port)
continue;
+ if (s->addr == addr) {
+ if (type == RAD_SERV_AUTH && port == s->auth_port)
+ s1 = s;
+ else if (type == RAD_SERV_ACCT && port == s->acct_port)
+ s1 = s;
+ else if (!s1)
+ s1 = s;
+ }
+
if (!s0) {
s0 = s;
continue;
@@ -52,7 +61,9 @@ static struct rad_server_t *__rad_server_get(int type, struct rad_server_t *excl
s0 = s;
}
- if (!s0)
+ if (s1)
+ s0 = s1;
+ else if (!s0)
return NULL;
__sync_add_and_fetch(&s0->client_cnt[type], 1);
@@ -62,7 +73,12 @@ static struct rad_server_t *__rad_server_get(int type, struct rad_server_t *excl
struct rad_server_t *rad_server_get(int type)
{
- return __rad_server_get(type, NULL);
+ return __rad_server_get(type, NULL, 0, 0);
+}
+
+struct rad_server_t *rad_server_get2(int type, in_addr_t addr, int port)
+{
+ return __rad_server_get(type, NULL, addr, port);
}
void rad_server_put(struct rad_server_t *s, int type)
@@ -137,7 +153,7 @@ void rad_server_req_exit(struct rad_req_t *req)
int rad_server_realloc(struct rad_req_t *req)
{
- struct rad_server_t *s = __rad_server_get(req->type, req->serv);
+ struct rad_server_t *s = __rad_server_get(req->type, req->serv, 0, 0);
if (!s)
return -1;