diff options
author | Kozlov Dmitry <xeb@mail.ru> | 2012-07-10 18:58:53 +0400 |
---|---|---|
committer | Kozlov Dmitry <xeb@mail.ru> | 2012-07-10 18:58:53 +0400 |
commit | 80c32d237e01b1c05663ccfa34003d2f49aa7eee (patch) | |
tree | a49da21b5219e4bc89d9794918f054f3620cb140 /accel-pppd/radius | |
parent | 64b5b693764c4f36870fd988ccbb53bcb188e74d (diff) | |
download | accel-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.txt | 4 | ||||
-rw-r--r-- | accel-pppd/radius/acct.c | 112 | ||||
-rw-r--r-- | accel-pppd/radius/backup.c | 163 | ||||
-rw-r--r-- | accel-pppd/radius/radius.c | 17 | ||||
-rw-r--r-- | accel-pppd/radius/radius_p.h | 5 | ||||
-rw-r--r-- | accel-pppd/radius/req.c | 29 | ||||
-rw-r--r-- | accel-pppd/radius/serv.c | 26 |
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; |