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 | |
parent | 64b5b693764c4f36870fd988ccbb53bcb188e74d (diff) | |
download | accel-ppp-80c32d237e01b1c05663ccfa34003d2f49aa7eee.tar.gz accel-ppp-80c32d237e01b1c05663ccfa34003d2f49aa7eee.zip |
initial session backup implementation
Diffstat (limited to 'accel-pppd')
25 files changed, 1770 insertions, 161 deletions
diff --git a/accel-pppd/CMakeLists.txt b/accel-pppd/CMakeLists.txt index c50dc58..777d7e5 100644 --- a/accel-pppd/CMakeLists.txt +++ b/accel-pppd/CMakeLists.txt @@ -24,6 +24,11 @@ IF (MEMDEBUG) ENDIF (VALGRIND) ENDIF (MEMDEBUG) +IF (BACKUP) + ADD_DEFINITIONS(-DUSE_BACKUP) + ADD_SUBDIRECTORY(backup) +ENDIF (BACKUP) + IF (NOT DEFINED RADIUS) SET(RADIUS TRUE) ENDIF (NOT DEFINED RADIUS) @@ -43,8 +48,11 @@ ADD_SUBDIRECTORY(shaper) ADD_EXECUTABLE(accel-pppd session.c + session_backup.c ifcfg.c + backup/backup.c + ppp/ppp.c ppp/ppp_fsm.c ppp/ppp_lcp.c diff --git a/accel-pppd/backup/CMakeLists.txt b/accel-pppd/backup/CMakeLists.txt new file mode 100644 index 0000000..77fefab --- /dev/null +++ b/accel-pppd/backup/CMakeLists.txt @@ -0,0 +1,4 @@ +ADD_LIBRARY(backup_file SHARED backup_file.c) + +INSTALL(TARGETS backup_file LIBRARY DESTINATION lib/accel-ppp) + diff --git a/accel-pppd/backup/backup.c b/accel-pppd/backup/backup.c new file mode 100644 index 0000000..d045f0c --- /dev/null +++ b/accel-pppd/backup/backup.c @@ -0,0 +1,245 @@ +#include <stdlib.h> +#include <string.h> + +#include "triton.h" +#include "events.h" +#include "ap_session.h" +#include "backup.h" + +#ifdef USE_BACKUP + +static LIST_HEAD(storage_list); +static LIST_HEAD(module_list); + +struct backup_tag __export *backup_add_tag(struct backup_mod *m, uint8_t id, int internal, const void *data, size_t size) +{ + struct backup_tag *t; + + t = m->data->storage->alloc_tag(m->data, size); + if (!t) + return NULL; + + t->id = id; + t->internal = internal; + t->size = size; + memcpy(t->data, data, size); + + list_add_tail(&t->entry, &m->tag_list); + + return t; +} + +void backup_add_fd(struct backup_mod *m, int fd) +{ + if (m->data->storage->add_fd) + m->data->storage->add_fd(m->data, fd); +} + +struct backup_mod __export *backup_find_mod(struct backup_data *d, uint8_t mod_id) +{ + struct backup_mod *m; + + list_for_each_entry(m, &d->mod_list, entry) { + if (m->id == mod_id) + return m; + } + + return NULL; +} + +struct backup_tag __export *backup_find_tag(struct backup_data *d, uint8_t mod_id, uint8_t tag_id, int internal) +{ + struct backup_mod *m = backup_find_mod(d, mod_id); + struct backup_tag *t; + + if (!m) + return NULL; + + list_for_each_entry(t, &m->tag_list, entry) { + if (t->id == tag_id && t->internal == internal) + return t; + } + + return NULL; +} + +void __export backup_free(struct backup_data *data) +{ + struct backup_mod *m; + struct backup_tag *t; + + while (!list_empty(&data->mod_list)) { + m = list_entry(data->mod_list.next, typeof(*m), entry); + while (!list_empty(&m->tag_list)) { + t = list_entry(m->tag_list.next, typeof(*t), entry); + list_del(&t->entry); + data->storage->free_tag(data, t); + } + list_del(&m->entry); + data->storage->free_mod(m); + } + data->storage->free(data); +} + +int __export backup_save_session(struct ap_session *ses) +{ + struct backup_storage *storage; + struct backup_module *module; + struct backup_data *d; + struct backup_mod *m; + int r, f1 = 0, f2; + + list_for_each_entry(storage, &storage_list, entry) { + d = storage->create(ses); + if (!d) + continue; + + //d->ses = ses; + + f2 = 0; + + list_for_each_entry(module, &module_list, entry) { + if (!module->save) + continue; + + m = storage->alloc_mod(d); + if (!m) { + f2 = 1; + break; + } + + m->data = d; + m->id = module->id; + r = module->save(ses, m); + if (r == -2) { + storage->free_mod(m); + continue; + } + + list_add_tail(&m->entry, &d->mod_list); + + if (r == -1) { + f2 = 1; + break; + } + } + + if (f2) + backup_free(d); + else { + f1 = 1; + if (storage->commit) + storage->commit(d); + ses->backup = d; + } + } + + return !f1; +} + +/*int backup_restore_internal(void) +{ + struct backup_storage *storage; + + list_for_each_entry(storage, &storage_list, entry) { + if (storage->restore_internal) { + if (storage->check_integrity()) + continue; + storage->restore_internal(); + return 0; + } + } + + return -1; +} + +void backup_restore_external(void) +{ + struct backup_storage *storage; + + list_for_each_entry(storage, &storage_list, entry) { + if (storage->restore_external) { + if (storage->check_integrity()) + continue; + storage->restore_external(); + return; + } + } +}*/ + +static void __restore_session(struct ap_session *ses) +{ + struct backup_module *module; + struct backup_mod *m; + struct backup_module *ctrl = NULL; + + list_for_each_entry(module, &module_list, entry) { + if (module->ctrl_start) + ctrl = module; + if (module->restore) { + m = backup_find_mod(ses->backup, module->id); + if (!m) + continue; + module->restore(ses, m); + } + } + + if (ctrl) + ctrl->ctrl_start(ses); + else { + triton_event_fire(EV_CTRL_STARTING, ses); + triton_event_fire(EV_CTRL_STARTED, ses); + + ap_session_starting(ses); + ap_session_activate(ses); + } +} + +void __export backup_restore_session(struct backup_data *d) +{ + struct backup_module *module; + struct backup_mod *m; + struct ap_session *ses; + + list_for_each_entry(module, &module_list, entry) { + if (module->ctrl_restore) { + m = backup_find_mod(d, module->id); + if (!m) + continue; + ses = module->ctrl_restore(m); + ses->backup = d; + d->ses = ses; + ses->state = AP_STATE_RESTORE; + triton_context_call(ses->ctrl->ctx, (triton_event_func)__restore_session, ses); + break; + } + } +} + + +void __export backup_register_module(struct backup_module *m) +{ + list_add_tail(&m->entry, &module_list); +} + +void __export backup_register_storage(struct backup_storage *s) +{ + list_add_tail(&s->entry, &storage_list); +} + +void backup_restore_fd() +{ + +} + +void backup_restore(int internal) +{ + struct backup_storage *storage; + + list_for_each_entry(storage, &storage_list, entry) { + if (storage->restore) + storage->restore(internal); + } +} + +#endif diff --git a/accel-pppd/backup/backup.h b/accel-pppd/backup/backup.h new file mode 100644 index 0000000..39c4ed7 --- /dev/null +++ b/accel-pppd/backup/backup.h @@ -0,0 +1,94 @@ +#ifndef __BACKUP_H +#define __BACKUP_H + +#include <stdint.h> +#include "list.h" + +#define MODID_COMMON 1 +#define MODID_RADIUS 2 +#define MODID_PPPOE 3 +#define MODID_IPOE 4 +#define MODID_PPTP 5 +#define MODID_L2TP 6 +#define MODID_IPPOOL 7 + + +struct ap_session; +struct backup_storage; +struct backup_data; + +struct backup_tag +{ + struct list_head entry; + uint16_t internal:1; + uint8_t id; + uint16_t size; + uint8_t *data; +}; + +struct backup_mod +{ + struct backup_data *data; + struct list_head entry; + int id; + struct list_head tag_list; +}; + +struct backup_data +{ + struct ap_session *ses; + struct backup_storage *storage; + struct list_head mod_list; + int internal:1; +}; + +struct backup_module +{ + struct list_head entry; + int id; + + int (*save)(struct ap_session *, struct backup_mod *); + int (*restore)(struct ap_session *, struct backup_mod *); + + struct ap_session *(*ctrl_restore)(struct backup_mod *); + void (*ctrl_start)(struct ap_session *ses); +}; + +struct backup_storage +{ + struct list_head entry; + + /*int (*check_integrity)(void); + int (*restore)(int internal);*/ + + void (*restore)(int internal); + + struct backup_data *(*create)(struct ap_session *); + int (*commit)(struct backup_data *); + void (*free)(struct backup_data *); + + struct backup_mod *(*alloc_mod)(struct backup_data *); + void (*free_mod)(struct backup_mod *); + + void (*add_fd)(struct backup_data *, int fd); + + struct backup_tag *(*alloc_tag)(struct backup_data *, int size); + void (*free_tag)(struct backup_data *, struct backup_tag *); +}; + +void backup_register_module(struct backup_module *); +void backup_register_storage(struct backup_storage *); + +int backup_save_session(struct ap_session *ses); +void backup_restore_session(struct backup_data *d); + +struct backup_mod *backup_find_mod(struct backup_data *d, uint8_t mod_id); +struct backup_tag *backup_find_tag(struct backup_data *d, uint8_t mod_id, uint8_t tag_id, int internal); +struct backup_tag *backup_add_tag(struct backup_mod *m, uint8_t id, int internal, const void *data, size_t size); +void backup_add_fd(struct backup_mod *m, int fd); + +void backup_restore(int internal); +void backup_restore_fd(); + +#endif + diff --git a/accel-pppd/backup/backup_file.c b/accel-pppd/backup/backup_file.c new file mode 100644 index 0000000..b9d2646 --- /dev/null +++ b/accel-pppd/backup/backup_file.c @@ -0,0 +1,351 @@ +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <dirent.h> +#include <sys/stat.h> +#include <sys/uio.h> +#include <sys/mman.h> + +#include "triton.h" +#include "log.h" +#include "ap_session.h" +#include "backup.h" +#include "crypto.h" +#include "memdebug.h" + +#define VERSION 1 + +struct fs_backup_data +{ + struct list_head fd_list; + int fd; + void *map_addr; + int map_len; + char sessionid[AP_SESSIONID_LEN]; + struct backup_data data; +}; + +static char *conf_path; + +static struct backup_storage file_storage; + +static struct backup_data *fs_create(struct ap_session *ses) +{ + struct fs_backup_data *d = _malloc(sizeof(*d)); + + if (!d) + return NULL; + + memset(d, 0, sizeof(*d)); + d->fd = -1; + INIT_LIST_HEAD(&d->fd_list); + INIT_LIST_HEAD(&d->data.mod_list); + d->data.ses = ses; + d->data.storage = &file_storage; + + return &d->data; +} + +static int fs_commit(struct backup_data *d) +{ + char fname[PATH_MAX]; + int fd; + struct backup_mod *mod; + struct backup_tag *tag; + struct iovec iov[IOV_MAX]; + int i, len, n; + MD5_CTX md5; + unsigned char md5_buf[16]; + uint8_t end[4] = {0, 0, 0, 0}; + uint8_t version = VERSION; + uint8_t *ptr; + + if (!conf_path) + return -1; + + sprintf(fname, "%s/%s", conf_path, d->ses->sessionid); + + fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE); + + if (fd < 0) { + log_error("backup: can not create file '%s': %s\n", fname, strerror(errno)); + return -1; + } + + MD5_Init(&md5); + MD5_Update(&md5, &version, 1); + + iov[0].iov_base = &version; + iov[0].iov_len = 1; + i = 1; + len = 1; + + list_for_each_entry(mod, &d->mod_list, entry) { + MD5_Update(&md5, &mod->id, 1); + iov[i].iov_base = &mod->id; + iov[i].iov_len = 1; + i++; + len++; + + list_for_each_entry(tag, &mod->tag_list, entry) { + ptr = (uint8_t *)(tag + 1); + *ptr = tag->id; ptr++; + *ptr = tag->internal ? 1 : 0; ptr++; + *(uint16_t *)ptr = tag->size; + MD5_Update(&md5, tag + 1, 4 + tag->size); + iov[i].iov_base = tag + 1; + iov[i].iov_len = 4 + tag->size; + i++; + len += 4 + tag->size; + if (i == IOV_MAX - 2) { + n = writev(fd, iov, i); + if (n < len) { + log_error("backup: short write %i/%i\n", n, len); + goto out_err; + } + i = 0; + len = 0; + } + } + + MD5_Update(&md5, end, 4); + iov[i].iov_base = end; + iov[i].iov_len = 4; + i++; + len += 4; + } + + MD5_Final(md5_buf, &md5); + + iov[i].iov_base = md5_buf; + iov[i].iov_len = 16; + len += 16; + + n = writev(fd, iov, i + 1); + if (n < len) { + log_error("backup: short write %i/%i\n", n, len); + goto out_err; + } + + close(fd); + + while (!list_empty(&d->mod_list)) { + mod = list_entry(d->mod_list.next, typeof(*mod), entry); + list_del(&mod->entry); + while (!list_empty(&mod->tag_list)) { + tag = list_entry(mod->tag_list.next, typeof(*tag), entry); + list_del(&tag->entry); + _free(tag); + } + _free(mod); + } + + return 0; + +out_err: + close(fd); + unlink(fname); + return -1; +} + +static void fs_free(struct backup_data *d) +{ + struct fs_backup_data *fsd = container_of(d, typeof(*fsd), data); + char fname[PATH_MAX]; + + if (fsd->map_addr) + munmap(fsd->map_addr, fsd->map_len); + + if (fsd->fd != -1) + close(fsd->fd); + + sprintf(fname, "%s/%s", conf_path, d->ses->sessionid); + unlink(fname); + + _free(fsd); +} + +static struct backup_mod *fs_alloc_mod(struct backup_data *d) +{ + struct backup_mod *m = _malloc(sizeof(struct backup_mod)); + + if (!m) + return NULL; + + memset(m, 0, sizeof(*m)); + INIT_LIST_HEAD(&m->tag_list); + + return m; +} + +static void fs_free_mod(struct backup_mod *mod) +{ + _free(mod); +} + +static struct backup_tag *fs_alloc_tag(struct backup_data *d, int size) +{ + struct backup_tag *t = _malloc(sizeof(struct backup_tag) + 4 + size); + + if (!t) + return NULL; + + memset(t, 0, sizeof(*t)); + + t->data = (uint8_t *)(t + 1) + 4; + + return t; +} + +static void fs_free_tag(struct backup_data *d, struct backup_tag *tag) +{ + _free(tag); +} + +static void fs_add_fd(struct backup_data *d, int fd) +{ + +} + +static void restore_session(const char *fn, int internal) +{ + char fname[PATH_MAX]; + int fd; + struct stat st; + uint8_t *ptr, *endptr; + MD5_CTX md5; + unsigned char md5_buf[16]; + struct backup_data *d; + struct fs_backup_data *fsd; + struct backup_mod *mod; + struct backup_tag *tag; + + sprintf(fname, "%s/%s", conf_path, fn); + + fd = open(fname, O_RDONLY); + if (fd < 0) { + log_emerg("backup_file: open '%s': %s\n", fname, strerror(errno)); + return; + } + + fstat(fd, &st); + + ptr = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) { + log_emerg("backup_file: mmap '%s': %s\n", fname, strerror(errno)); + close(fd); + return; + } + + if (*ptr != VERSION) + goto out; + + MD5_Init(&md5); + MD5_Update(&md5, ptr, st.st_size - 16); + MD5_Final(md5_buf, &md5); + + if (memcmp(md5_buf, ptr + st.st_size - 16, 16)) + goto out; + + d = fs_create(NULL); + if (!d) + goto out; + + d->internal = internal; + + fsd = container_of(d, typeof(*fsd), data); + fsd->fd = fd; + fsd->map_addr = ptr; + fsd->map_len = st.st_size; + + endptr = ptr + st.st_size - 16; + ptr++; + + while (ptr < endptr) { + mod = fs_alloc_mod(d); + list_add_tail(&mod->entry, &d->mod_list); + mod->data = d; + mod->id = *ptr; ptr++; + while (ptr < endptr) { + if (*(uint8_t *)ptr == 0) { + ptr += 4; + break; + } + + if (!internal && ptr[1]) { + ptr += 4 + *(uint16_t *)(ptr + 2); + continue; + } + + tag = fs_alloc_tag(d, 0); + tag->id = *ptr; ptr++; + tag->internal = (*ptr & 0x01) ? 1 : 0; ptr ++; + tag->size = *(uint16_t *)ptr; ptr += 2; + tag->data = ptr; ptr += tag->size; + + list_add_tail(&tag->entry, &mod->tag_list); + } + } + + backup_restore_session(d); + + return; + +out: + munmap(ptr, st.st_size); + close(fd); +} + +static void fs_restore(int internal) +{ + DIR *dirp; + struct dirent ent, *res; + + if (!conf_path) + return; + + dirp = opendir(conf_path); + if (!dirp) { + log_emerg("backup_file: opendir: %s\n", strerror(errno)); + return; + } + + while (1) { + if (readdir_r(dirp, &ent, &res)) { + log_emerg("backup_file: readdir: %s\n", strerror(errno)); + break; + } + if (!res) + break; + if (strcmp(ent.d_name, ".") == 0 || strcmp(ent.d_name, "..") == 0) + continue; + restore_session(ent.d_name, internal); + } + + closedir(dirp); +} + +static struct backup_storage file_storage = { + .create = fs_create, + .commit = fs_commit, + .free = fs_free, + .alloc_mod = fs_alloc_mod, + .free_mod = fs_free_mod, + .add_fd = fs_add_fd, + .alloc_tag = fs_alloc_tag, + .free_tag = fs_free_tag, + .restore = fs_restore, +}; + +static void init(void) +{ + conf_path = conf_get_opt("backup", "path"); + + backup_register_storage(&file_storage); +} + +DEFINE_INIT(1000, init); diff --git a/accel-pppd/ctrl/ipoe/CMakeLists.txt b/accel-pppd/ctrl/ipoe/CMakeLists.txt index 297d81b..7be18cc 100644 --- a/accel-pppd/ctrl/ipoe/CMakeLists.txt +++ b/accel-pppd/ctrl/ipoe/CMakeLists.txt @@ -17,6 +17,10 @@ IF (LUA) SET(sources ${sources} lua.c lua_lpack.c) ENDIF (LUA) +IF (BACKUP) + SET(sources ${sources} backup.c) +ENDIF (BACKUP) + ADD_LIBRARY(ipoe SHARED ${sources}) IF (LUA) TARGET_LINK_LIBRARIES(ipoe ${LUA_LIBRARIES}) diff --git a/accel-pppd/ctrl/ipoe/backup.c b/accel-pppd/ctrl/ipoe/backup.c new file mode 100644 index 0000000..b2d0c0c --- /dev/null +++ b/accel-pppd/ctrl/ipoe/backup.c @@ -0,0 +1,168 @@ +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <netinet/in.h> +#include <net/ethernet.h> + +#include "log.h" +#include "memdebug.h" + +#include "ipoe.h" +#include "backup.h" +#include "ap_session_backup.h" + +#define IPOE_TAG_HWADDR 1 +#define IPOE_TAG_CLIENT_ID 2 +#define IPOE_TAG_AGENT_CIRCUIT_ID 3 +#define IPOE_TAG_AGENT_REMOTE_ID 4 +#define IPOE_TAG_XID 5 +#define IPOE_TAG_GIADDR 6 +#define IPOE_TAG_CALLING_SID 7 +#define IPOE_TAG_CALLED_SID 8 +#define IPOE_TAG_IFNAME 9 + +#define IPOE_TAG_IFINDEX 100 + + +#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 ipoe_session *conn = container_of(ses, typeof(*conn), ses); + + add_tag(IPOE_TAG_HWADDR, conn->hwaddr, 6); + add_tag(IPOE_TAG_CALLING_SID, ses->ctrl->calling_station_id, strlen(ses->ctrl->calling_station_id)); + add_tag(IPOE_TAG_CALLED_SID, ses->ctrl->called_station_id, strlen(ses->ctrl->called_station_id)); + add_tag(IPOE_TAG_XID, &conn->xid, 4); + add_tag(IPOE_TAG_GIADDR, &conn->giaddr, 4); + + if (conn->client_id) + add_tag(IPOE_TAG_CLIENT_ID, conn->client_id->data, conn->client_id->len); + if (conn->agent_circuit_id) + add_tag(IPOE_TAG_AGENT_CIRCUIT_ID, conn->agent_circuit_id->data, conn->agent_circuit_id->len); + if (conn->agent_circuit_id) + add_tag(IPOE_TAG_AGENT_REMOTE_ID, conn->agent_remote_id->data, conn->agent_remote_id->len); + + //add_tag_int(IPOE_TAG_IFNAME, conn->serv->ifname, strlen(conn->serv->ifname) + 1); + add_tag(IPOE_TAG_IFNAME, conn->serv->ifname, strlen(conn->serv->ifname) + 1); + + return 0; +} + +static int session_restore(struct ap_session *ses, struct backup_mod *m) +{ + struct ipoe_session *conn = container_of(ses, typeof(*conn), ses); + + + return 0; +} + +static void set_dhcpv4_opt(struct dhcp_opt **opt, struct backup_tag *t, uint8_t **ptr) +{ + *opt = (struct dhcp_opt *)(*ptr); + (*opt)->len = t->size; + memcpy((*opt)->data, t->data, t->size); + (*ptr) += sizeof(**opt) + t->size; +} + +static struct ap_session *ctrl_restore(struct backup_mod *m) +{ + struct backup_tag *t; + struct ipoe_session *ses; + struct ipoe_serv *serv; + struct backup_tag *ifname = NULL; + int dlen = 0; + uint8_t *ptr; + + //if (!m->data->internal) + // return NULL; + + list_for_each_entry(t, &m->tag_list, entry) { + switch(t->id) { + case IPOE_TAG_CLIENT_ID: + case IPOE_TAG_AGENT_CIRCUIT_ID: + case IPOE_TAG_AGENT_REMOTE_ID: + dlen += sizeof(struct dhcp_opt) + t->size; + break; + case IPOE_TAG_IFNAME: + ifname = t; + break; + } + } + + if (!ifname) + return NULL; + + serv = ipoe_find_serv((char *)ifname->data); + if (!serv) + return NULL; + + ses = ipoe_session_alloc(); + if (!ses) + return NULL; + + if (dlen) + ses->data = _malloc(dlen); + + ptr = ses->data; + + list_for_each_entry(t, &m->tag_list, entry) { + switch(t->id) { + case IPOE_TAG_HWADDR: + memcpy(ses->hwaddr, t->data, 6); + break; + case IPOE_TAG_CALLING_SID: + ses->ctrl.calling_station_id = _malloc(t->size + 1); + memcpy(ses->ctrl.calling_station_id, t->data, t->size); + ses->ctrl.calling_station_id[t->size] = 0; + break; + case IPOE_TAG_CALLED_SID: + ses->ctrl.called_station_id = _malloc(t->size + 1); + memcpy(ses->ctrl.called_station_id, t->data, t->size); + ses->ctrl.called_station_id[t->size] = 0; + break; + case IPOE_TAG_XID: + ses->xid = *(uint32_t *)t->data; + break; + case IPOE_TAG_GIADDR: + ses->giaddr = *(uint32_t *)t->data; + break; + case IPOE_TAG_CLIENT_ID: + set_dhcpv4_opt(&ses->client_id, t, &ptr); + break; + case IPOE_TAG_AGENT_CIRCUIT_ID: + set_dhcpv4_opt(&ses->agent_circuit_id, t, &ptr); + break; + case IPOE_TAG_AGENT_REMOTE_ID: + set_dhcpv4_opt(&ses->agent_remote_id, t, &ptr); + break; + } + } + + ses->serv = serv; + + triton_context_register(&ses->ctx, &ses->ses); + triton_context_wakeup(&ses->ctx); + + pthread_mutex_lock(&serv->lock); + list_add_tail(&ses->entry, &serv->sessions); + pthread_mutex_unlock(&serv->lock); + + return &ses->ses; +} + +static struct backup_module mod = { + .id = MODID_IPOE, + .save = session_save, + .restore = session_restore, + .ctrl_restore = ctrl_restore, +}; + +static void init(void) +{ + backup_register_module(&mod); +} + +DEFINE_INIT(100, init); + diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c index 5878b0c..fea61a8 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.c +++ b/accel-pppd/ctrl/ipoe/ipoe.c @@ -73,6 +73,7 @@ struct iplink_arg static void ipoe_session_finished(struct ap_session *s); static void ipoe_drop_sessions(struct ipoe_serv *serv, struct ipoe_session *skip); +static void ipoe_serv_close(struct triton_context_t *ctx); static struct ipoe_session *ipoe_session_lookup(struct ipoe_serv *serv, struct dhcpv4_packet *pack) { @@ -321,13 +322,18 @@ static void ipoe_session_free(struct ipoe_session *ses) static void ipoe_session_finished(struct ap_session *s) { struct ipoe_session *ses = container_of(s, typeof(*ses), ses); + int serv_close; log_ppp_debug("ipoe: session finished\n"); pthread_mutex_lock(&ses->serv->lock); list_del(&ses->entry); + serv_close = ses->serv->need_close && list_empty(&ses->serv->sessions); pthread_mutex_unlock(&ses->serv->lock); + if (serv_close) + ipoe_serv_close(&ses->serv->ctx); + triton_context_call(&ses->ctx, (triton_event_func)ipoe_session_free, ses); } @@ -590,6 +596,37 @@ static struct ipoe_session *ipoe_session_create_up(struct ipoe_serv *serv, struc return ses; } +struct ipoe_session *ipoe_session_alloc(void) +{ + struct ipoe_session *ses; + + ses = mempool_alloc(ses_pool); + if (!ses) { + log_emerg("out of memery\n"); + return NULL; + } + + memset(ses, 0, sizeof(*ses)); + + ap_session_init(&ses->ses); + + ses->ifindex = -1; + + ses->ctx.before_switch = log_switch; + ses->ctx.close = ipoe_session_close; + ses->ctrl.ctx = &ses->ctx; + ses->ctrl.started = ipoe_session_started; + ses->ctrl.finished = ipoe_session_finished; + ses->ctrl.terminate = ipoe_session_terminate; + ses->ctrl.type = CTRL_TYPE_IPOE; + ses->ctrl.name = "ipoe"; + + ses->ses.ctrl = &ses->ctrl; + ses->ses.chan_name = ses->ctrl.calling_station_id; + + return ses; +} + void ipoe_recv_up(int ifindex, struct ethhdr *eth, struct iphdr *iph) { struct ipoe_serv *serv; @@ -619,6 +656,14 @@ static void ipoe_serv_close(struct triton_context_t *ctx) { struct ipoe_serv *serv = container_of(ctx, typeof(*serv), ctx); + pthread_mutex_lock(&serv->lock); + if (!list_empty(&serv->sessions)) { + serv->need_close = 1; + pthread_mutex_unlock(&serv->lock); + return; + } + pthread_mutex_unlock(&serv->lock); + if (serv->dhcpv4) dhcpv4_free(serv->dhcpv4); @@ -663,6 +708,18 @@ static void ipoe_drop_sessions(struct ipoe_serv *serv, struct ipoe_session *skip } } +struct ipoe_serv *ipoe_find_serv(const char *ifname) +{ + struct ipoe_serv *serv; + + list_for_each_entry(serv, &serv_list, entry) { + if (strcmp(serv->ifname, ifname) == 0) + return serv; + } + + return NULL; +} + static void add_interface(const char *ifname, int ifindex, const char *opt) { char *str0, *str, *ptr1, *ptr2; @@ -758,6 +815,7 @@ static void add_interface(const char *ifname, int ifindex, const char *opt) serv = _malloc(sizeof(*serv)); memset(serv, 0, sizeof(*serv)); + serv->ctx.close = ipoe_serv_close; serv->ifname = _strdup(ifname); serv->ifindex = ifindex; serv->opt_shared = opt_shared; @@ -873,6 +931,7 @@ static void load_interfaces(struct conf_sect_t *sect) list_for_each_safe(pos, n, &serv_list) { serv = list_entry(pos, typeof(*serv), entry); if (!serv->active) { + ipoe_drop_sessions(serv, NULL); list_del(&serv->entry); triton_context_call(&serv->ctx, (triton_event_func)ipoe_serv_close, &serv->ctx); } diff --git a/accel-pppd/ctrl/ipoe/ipoe.h b/accel-pppd/ctrl/ipoe/ipoe.h index 97b13e6..a2efd37 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.h +++ b/accel-pppd/ctrl/ipoe/ipoe.h @@ -22,6 +22,7 @@ struct ipoe_serv int opt_shared:1; int opt_dhcpv4:1; int opt_up:1; + int need_close:1; }; struct dhcp_opt @@ -57,6 +58,9 @@ struct iphdr; struct ethhdr; void ipoe_recv_up(int ifindex, struct ethhdr *eth, struct iphdr *iph); +struct ipoe_session *ipoe_session_alloc(void); + +struct ipoe_serv *ipoe_find_serv(const char *ifname); void ipoe_nl_add_net(uint32_t addr, int mask); void ipoe_nl_delete_nets(void); diff --git a/accel-pppd/ctrl/ipoe/ipoe_netlink.c b/accel-pppd/ctrl/ipoe/ipoe_netlink.c index ec603d5..525dc0b 100644 --- a/accel-pppd/ctrl/ipoe/ipoe_netlink.c +++ b/accel-pppd/ctrl/ipoe/ipoe_netlink.c @@ -364,7 +364,6 @@ static int ipoe_up_read(struct triton_md_handler_t *h) static void ipoe_up_close(struct triton_context_t *ctx) { - rtnl_close(&rth); triton_md_unregister_handler(&up_hnd); triton_context_unregister(ctx); } diff --git a/accel-pppd/extra/ippool.c b/accel-pppd/extra/ippool.c index ab2dfb2..ccb3b2a 100644 --- a/accel-pppd/extra/ippool.c +++ b/accel-pppd/extra/ippool.c @@ -9,6 +9,8 @@ #include "ipdb.h" #include "list.h" #include "spinlock.h" +#include "backup.h" +#include "ap_session_backup.h" #ifdef RADIUS #include "radius.h" @@ -23,6 +25,8 @@ struct ippool_t struct list_head gw_list; struct list_head tunnel_list; struct list_head items; + uint32_t startip; + uint32_t endip; spinlock_t lock; }; @@ -143,7 +147,7 @@ static int parse2(const char *str, uint32_t *begin, uint32_t *end) return 0; } -static void add_range(struct list_head *list, const char *name) +static void add_range(struct ippool_t *p, struct list_head *list, const char *name) { uint32_t i,startip, endip; struct ipaddr_t *ip; @@ -161,6 +165,9 @@ static void add_range(struct list_head *list, const char *name) list_add_tail(&ip->entry, list); cnt++; } + + p->startip = startip; + p->endip = endip; } static void generate_pool(struct ippool_t *p) @@ -243,6 +250,89 @@ static struct ipdb_t ipdb = { .put_ipv4 = put_ip, }; +#ifdef USE_BACKUP +static void put_ip_b(struct ap_session *ses, struct ipv4db_item_t *it) +{ + _free(it); +} + +static struct ipdb_t ipdb_b = { + .put_ipv4 = put_ip_b, +}; + +static int session_save(struct ap_session *ses, struct backup_mod *m) +{ + if (!ses->ipv4 || ses->ipv4->owner != &ipdb) + return -2; + + return 0; +} + +static int session_restore(struct ap_session *ses, struct backup_mod *m) +{ + struct backup_tag *tag; + in_addr_t addr = 0, peer_addr; + struct ippool_t *p; + struct ippool_item_t *it, *it0 = NULL; + + m = backup_find_mod(m->data, MODID_COMMON); + + list_for_each_entry(tag, &m->tag_list, entry) { + switch (tag->id) { + case SES_TAG_IPV4_ADDR: + addr = *(in_addr_t *)tag->data; + break; + case SES_TAG_IPV4_PEER_ADDR: + peer_addr = *(in_addr_t *)tag->data; + break; + } + } + + spin_lock(&def_pool->lock); + list_for_each_entry(it, &def_pool->items, entry) { + if (peer_addr == it->it.peer_addr && addr == it->it.addr) { + list_del(&it->entry); + it0 = it; + break; + } + } + spin_unlock(&def_pool->lock); + + if (!it0) { + list_for_each_entry(p, &pool_list, entry) { + spin_lock(&p->lock); + list_for_each_entry(it, &p->items, entry) { + if (peer_addr == it->it.peer_addr && addr == it->it.addr) { + list_del(&it->entry); + it0 = it; + break; + } + } + spin_unlock(&p->lock); + if (it0) + break; + } + } + + if (it0) + ses->ipv4 = &it0->it; + else { + ses->ipv4 = _malloc(sizeof(*ses->ipv4)); + ses->ipv4->addr = addr; + ses->ipv4->peer_addr = peer_addr; + ses->ipv4->owner = &ipdb_b; + } + + return 0; +} + +static struct backup_module backup_mod = { + .id = MODID_IPPOOL, + .save = session_save, + .restore = session_restore, +}; +#endif + #ifdef RADIUS static int parse_attr(struct ap_session *ses, struct rad_attr_t *attr) { @@ -348,11 +438,11 @@ static void ippool_init(void) p = pool_name ? find_pool(pool_name + 1, 1) : def_pool; if (!strcmp(opt->name, "gw")) - add_range(&p->gw_list, opt->val); + add_range(p, &p->gw_list, opt->val); else if (!strcmp(opt->name, "tunnel")) - add_range(&p->tunnel_list, opt->val); + add_range(p, &p->tunnel_list, opt->val); else if (!opt->val) - add_range(&p->tunnel_list, opt->name); + add_range(p, &p->tunnel_list, opt->name); } } @@ -363,6 +453,10 @@ static void ippool_init(void) ipdb_register(&ipdb); +#ifdef USE_BACKUP + backup_register_module(&backup_mod); +#endif + #ifdef RADIUS if (triton_module_loaded("radius")) triton_event_register_handler(EV_RADIUS_ACCESS_ACCEPT, (triton_event_func)ev_radius_access_accept); diff --git a/accel-pppd/ifcfg.c b/accel-pppd/ifcfg.c index 134edfb..7399a60 100644 --- a/accel-pppd/ifcfg.c +++ b/accel-pppd/ifcfg.c @@ -17,6 +17,7 @@ #include "ppp.h" #include "ipdb.h" #include "log.h" +#include "backup.h" // from /usr/include/linux/ipv6.h struct in6_ifreq { @@ -56,7 +57,7 @@ void ap_session_ifup(struct ap_session *ses) { struct ipv6db_addr_t *a; struct ifreq ifr; - struct rtentry rt; + //struct rtentry rt; struct in6_ifreq ifr6; struct npioctl np; struct sockaddr_in addr; @@ -72,96 +73,102 @@ void ap_session_ifup(struct ap_session *ses) memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, ses->ifname); - - if (ses->ipv4) { - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = ses->ipv4->addr; - memcpy(&ifr.ifr_addr, &addr, sizeof(addr)); - - if (ioctl(sock_fd, SIOCSIFADDR, &ifr)) - log_ppp_error("failed to set IPv4 address: %s\n", strerror(errno)); - - /*if (ses->ctrl->type == CTRL_TYPE_IPOE) { - addr.sin_addr.s_addr = 0xffffffff; - memcpy(&ifr.ifr_netmask, &addr, sizeof(addr)); - if (ioctl(sock_fd, SIOCSIFNETMASK, &ifr)) - log_ppp_error("failed to set IPv4 nask: %s\n", strerror(errno)); - }*/ + +#ifdef USE_BACKUP + if (!ses->backup || !ses->backup->internal) { +#endif + if (ses->ipv4) { + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = ses->ipv4->addr; + memcpy(&ifr.ifr_addr, &addr, sizeof(addr)); + + if (ioctl(sock_fd, SIOCSIFADDR, &ifr)) + log_ppp_error("failed to set IPv4 address: %s\n", strerror(errno)); - addr.sin_addr.s_addr = ses->ipv4->peer_addr; - - /*if (ses->ctrl->type == CTRL_TYPE_IPOE) { - memset(&rt, 0, sizeof(rt)); - memcpy(&rt.rt_dst, &addr, sizeof(addr)); - rt.rt_flags = RTF_HOST | RTF_UP; - rt.rt_metric = 1; - rt.rt_dev = ifr.ifr_name; - if (ioctl(sock_fd, SIOCADDRT, &rt, sizeof(rt))) - log_ppp_error("failed to add route: %s\n", strerror(errno)); - } else*/ { - memcpy(&ifr.ifr_dstaddr, &addr, sizeof(addr)); + /*if (ses->ctrl->type == CTRL_TYPE_IPOE) { + addr.sin_addr.s_addr = 0xffffffff; + memcpy(&ifr.ifr_netmask, &addr, sizeof(addr)); + if (ioctl(sock_fd, SIOCSIFNETMASK, &ifr)) + log_ppp_error("failed to set IPv4 nask: %s\n", strerror(errno)); + }*/ - if (ioctl(sock_fd, SIOCSIFDSTADDR, &ifr)) - log_ppp_error("failed to set peer IPv4 address: %s\n", strerror(errno)); + addr.sin_addr.s_addr = ses->ipv4->peer_addr; + + /*if (ses->ctrl->type == CTRL_TYPE_IPOE) { + memset(&rt, 0, sizeof(rt)); + memcpy(&rt.rt_dst, &addr, sizeof(addr)); + rt.rt_flags = RTF_HOST | RTF_UP; + rt.rt_metric = 1; + rt.rt_dev = ifr.ifr_name; + if (ioctl(sock_fd, SIOCADDRT, &rt, sizeof(rt))) + log_ppp_error("failed to add route: %s\n", strerror(errno)); + } else*/ { + memcpy(&ifr.ifr_dstaddr, &addr, sizeof(addr)); + + if (ioctl(sock_fd, SIOCSIFDSTADDR, &ifr)) + log_ppp_error("failed to set peer IPv4 address: %s\n", strerror(errno)); + } } - } - - if (ses->ipv6) { - devconf(ses, "accept_ra", "0"); - devconf(ses, "autoconf", "0"); - devconf(ses, "forwarding", "1"); - memset(&ifr6, 0, sizeof(ifr6)); - - if (ses->ctrl->type != CTRL_TYPE_IPOE) { - ifr6.ifr6_addr.s6_addr32[0] = htons(0xfe80); - *(uint64_t *)(ifr6.ifr6_addr.s6_addr + 8) = ses->ipv6->intf_id; - ifr6.ifr6_prefixlen = 64; - ifr6.ifr6_ifindex = ses->ifindex; + if (ses->ipv6) { + devconf(ses, "accept_ra", "0"); + devconf(ses, "autoconf", "0"); + devconf(ses, "forwarding", "1"); - if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6)) - log_ppp_error("faild to set LL IPv6 address: %s\n", strerror(errno)); - } - - list_for_each_entry(a, &ses->ipv6->addr_list, entry) { - if (a->prefix_len == 128) - continue; + memset(&ifr6, 0, sizeof(ifr6)); + + if (ses->ctrl->type != CTRL_TYPE_IPOE) { + ifr6.ifr6_addr.s6_addr32[0] = htons(0xfe80); + *(uint64_t *)(ifr6.ifr6_addr.s6_addr + 8) = ses->ipv6->intf_id; + ifr6.ifr6_prefixlen = 64; + ifr6.ifr6_ifindex = ses->ifindex; + + if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6)) + log_ppp_error("faild to set LL IPv6 address: %s\n", strerror(errno)); + } + + list_for_each_entry(a, &ses->ipv6->addr_list, entry) { + if (a->prefix_len == 128) + continue; - build_addr(a, ses->ipv6->intf_id, &ifr6.ifr6_addr); - ifr6.ifr6_prefixlen = a->prefix_len; + build_addr(a, ses->ipv6->intf_id, &ifr6.ifr6_addr); + ifr6.ifr6_prefixlen = a->prefix_len; - if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6)) - log_ppp_error("failed to add IPv6 address: %s\n", strerror(errno)); + if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6)) + log_ppp_error("failed to add IPv6 address: %s\n", strerror(errno)); + } } - } - - if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr)) - log_ppp_error("failed to get interface flags: %s\n", strerror(errno)); - ifr.ifr_flags |= IFF_UP; + if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr)) + log_ppp_error("failed to get interface flags: %s\n", strerror(errno)); - if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr)) - log_ppp_error("failed to set interface flags: %s\n", strerror(errno)); + ifr.ifr_flags |= IFF_UP; - if (ses->ctrl->type != CTRL_TYPE_IPOE) { - ppp = container_of(ses, typeof(*ppp), ses); - if (ses->ipv4) { - np.protocol = PPP_IP; - np.mode = NPMODE_PASS; + if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr)) + log_ppp_error("failed to set interface flags: %s\n", strerror(errno)); - if (ioctl(ppp->unit_fd, PPPIOCSNPMODE, &np)) - log_ppp_error("failed to set NP (IPv4) mode: %s\n", strerror(errno)); - } - - if (ses->ipv6) { - np.protocol = PPP_IPV6; - np.mode = NPMODE_PASS; + if (ses->ctrl->type != CTRL_TYPE_IPOE) { + ppp = container_of(ses, typeof(*ppp), ses); + if (ses->ipv4) { + np.protocol = PPP_IP; + np.mode = NPMODE_PASS; + + if (ioctl(ppp->unit_fd, PPPIOCSNPMODE, &np)) + log_ppp_error("failed to set NP (IPv4) mode: %s\n", strerror(errno)); + } + + if (ses->ipv6) { + np.protocol = PPP_IPV6; + np.mode = NPMODE_PASS; - if (ioctl(ppp->unit_fd, PPPIOCSNPMODE, &np)) - log_ppp_error("failed to set NP (IPv6) mode: %s\n", strerror(errno)); + if (ioctl(ppp->unit_fd, PPPIOCSNPMODE, &np)) + log_ppp_error("failed to set NP (IPv6) mode: %s\n", strerror(errno)); + } } +#ifdef USE_BACKUP } +#endif ses->ctrl->started(ses); diff --git a/accel-pppd/include/ap_session.h b/accel-pppd/include/ap_session.h index b964c80..075058c 100644 --- a/accel-pppd/include/ap_session.h +++ b/accel-pppd/include/ap_session.h @@ -7,6 +7,7 @@ #define AP_STATE_STARTING 1 #define AP_STATE_ACTIVE 2 #define AP_STATE_FINISHING 3 +#define AP_STATE_RESTORE 4 #define TERM_USER_REQUEST 1 #define TERM_SESSION_TIMEOUT 2 @@ -30,6 +31,7 @@ #define MPPE_REQUIRE 2 struct ap_session; +struct backup_data; struct ap_ctrl { @@ -71,6 +73,10 @@ struct ap_session struct ap_ctrl *ctrl; +#ifdef USE_BACKUP + struct backup_data *backup; +#endif + int terminating:1; int terminated:1; int terminate_cause; diff --git a/accel-pppd/include/ap_session_backup.h b/accel-pppd/include/ap_session_backup.h new file mode 100644 index 0000000..e6382ff --- /dev/null +++ b/accel-pppd/include/ap_session_backup.h @@ -0,0 +1,23 @@ +#ifndef __AP_SESSION_BACKUP_H +#define __AP_SESSION_BACKUP_H + +#define SES_TAG_USERNAME 1 +#define SES_TAG_SESSIONID 2 +#define SES_TAG_START_TIME 3 +#define SES_TAG_IPV4_ADDR 4 +#define SES_TAG_IPV4_PEER_ADDR 5 +#define SES_TAG_IPV6_INTFID 6 +#define SES_TAG_IPV6_PEER_INTFID 7 +#define SES_TAG_IPV6_ADDR 8 +#define SES_TAG_IFINDEX 9 +#define SES_TAG_IFNAME 10 + + +struct ses_tag_ipv6 +{ + struct in6_addr addr; + uint8_t prefix_len; +} __attribute__((packed)); + +#endif + diff --git a/accel-pppd/include/backup.h b/accel-pppd/include/backup.h new file mode 120000 index 0000000..0271d05 --- /dev/null +++ b/accel-pppd/include/backup.h @@ -0,0 +1 @@ +../backup/backup.h
\ No newline at end of file diff --git a/accel-pppd/main.c b/accel-pppd/main.c index e153caf..9e51556 100644 --- a/accel-pppd/main.c +++ b/accel-pppd/main.c @@ -4,6 +4,11 @@ #include <stdlib.h> #include <stdio.h> #include <errno.h> +#include <fcntl.h> +#include <time.h> +#include <limits.h> +#include <malloc.h> +#include <dirent.h> #include <sys/stat.h> #include <sys/mman.h> #include <sys/resource.h> @@ -13,9 +18,16 @@ #include "memdebug.h" #include "log.h" #include "events.h" +#include "backup.h" + +#ifndef ARG_MAX +#define ARG_MAX 128*1024 +#endif static char *pid_file; static char *conf_file; +static char *conf_dump; +static char *exec_file; static void change_limits(void) { @@ -50,19 +62,138 @@ static void config_reload_notify(int r) if (!r) triton_event_fire(EV_CONFIG_RELOAD, NULL); } + static void config_reload(int num) { triton_conf_reload(config_reload_notify); } +static void close_all_fd(void) +{ + DIR *dirp; + struct dirent ent, *res; + char path[128]; + + sprintf(path, "/proc/%u/fd", getpid()); + + dirp = opendir(path); + if (!dirp) + return; + + while (1) { + if (readdir_r(dirp, &ent, &res)) + return; + if (!res) + break; + close((unsigned long)atol(ent.d_name)); + } + + closedir(dirp); +} + +void core_restart(int soft) +{ + char fname[128]; + int fd, n; + char cmdline[ARG_MAX]; + char *args[16]; + char *ptr = cmdline, *endptr; + sigset_t set; + + if (fork()) { + close_all_fd(); + return; + } + + sigfillset(&set); + pthread_sigmask(SIG_SETMASK, &set, NULL); + + sprintf(fname, "/proc/%i/cmdline", getpid()); + + fd = open(fname, O_RDONLY); + n = read(fd, cmdline, ARG_MAX); + + endptr = ptr + n; + + n = 0; + while (ptr < endptr) { + args[n++] = ptr; + while (ptr < endptr && *ptr++); + } + + args[n++] = NULL; + +#ifdef USE_BACKUP + if (soft) + backup_restore_fd(); + else +#endif + if (fork()) { + close_all_fd(); + _exit(0); + } + + + while (1) { + sleep(3); + execv(args[0], args); + } +} + +static void sigsegv(int num) +{ + char cmd[PATH_MAX]; + char fname[PATH_MAX]; + struct rlimit lim; + +#ifdef USE_BACKUP + core_restart(1); +#else + core_restart(0); +#endif + + if (conf_dump) { + FILE *f; + unsigned int t = time(NULL); + sprintf(fname, "%s/cmd-%u", conf_dump, t); + f = fopen(fname, "w"); + if (!f) + goto out; + fprintf(f, "thread apply all bt full\ndetach\nquit\n"); + fclose(f); + + sprintf(cmd, "gdb -x %s %s %d > %s/dump-%u", fname, exec_file, getpid(), conf_dump, t); + system(cmd); + unlink(fname); + + lim.rlim_cur = RLIM_INFINITY; + lim.rlim_max = RLIM_INFINITY; + + setrlimit(RLIMIT_CORE, &lim); + + chdir(conf_dump); + } + +out: + abort(); +} + int main(int argc, char **argv) { sigset_t set; - int i, sig, goto_daemon = 0; + int i, sig, goto_daemon = 0, len; + pid_t pid = 0; + struct sigaction sa; + int pagesize = sysconf(_SC_PAGE_SIZE); +#ifdef USE_BACKUP + int internal = 0; +#endif if (argc < 2) goto usage; + exec_file = argv[0]; + for(i = 1; i < argc; i++) { if (!strcmp(argv[i], "-d")) goto_daemon = 1; @@ -74,16 +205,38 @@ int main(int argc, char **argv) if (i == argc - 1) goto usage; conf_file = argv[++i]; + } else if (!strcmp(argv[i], "--dump")) { + if (i == argc - 1) + goto usage; + len = (strlen(argv[i + 1]) / pagesize + 1) * pagesize; + conf_dump = memalign(pagesize, len); + strcpy(conf_dump, argv[++i]); + mprotect(conf_dump, len, PROT_READ); } } if (!conf_file) goto usage; + + if (pid_file) { + FILE *f = fopen(pid_file, "r"); + if (f) { + fscanf(f, "%u", &pid); + fclose(f); + } +#ifdef USE_BACKUP + internal = pid == getppid(); +#endif + /*if (pid) { + printf("%i %i %i\n", pid, getppid(), getpid()); + return 0; + }*/ + } if (triton_init(conf_file)) _exit(EXIT_FAILURE); - if (goto_daemon) { + if (goto_daemon && pid != getpid()) { /*pid_t pid = fork(); if (pid > 0) _exit(EXIT_SUCCESS); @@ -121,15 +274,19 @@ int main(int argc, char **argv) triton_run(); - sigfillset(&set); - struct sigaction sa = { - .sa_handler = config_reload, - .sa_mask = set, - }; + sigfillset(&set); + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = config_reload; + sa.sa_mask = set; sigaction(SIGUSR1, &sa, NULL); + + sa.sa_handler = sigsegv; + sa.sa_mask = set; + sigaction(SIGSEGV, &sa, NULL); + sigdelset(&set, SIGKILL); sigdelset(&set, SIGSTOP); sigdelset(&set, SIGSEGV); @@ -151,7 +308,11 @@ int main(int argc, char **argv) sigaddset(&set, SIGILL); sigaddset(&set, SIGFPE); sigaddset(&set, SIGBUS); - + +#ifdef USE_BACKUP + backup_restore(internal); +#endif + sigwait(&set, &sig); log_info1("terminate, sig = %i\n", sig); diff --git a/accel-pppd/radius/CMakeLists.txt b/accel-pppd/radius/CMakeLists.txt index 0c1789e..d139fe1 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 dfc982d..b5f7ff7 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 0000000..4c40ec6 --- /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 d880ad0..82ac979 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 f8adb46..0709351 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 f452c42..cd9a170 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 4de6ad1..aae3719 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; diff --git a/accel-pppd/session.c b/accel-pppd/session.c index 886aa40..d24dcd7 100644 --- a/accel-pppd/session.c +++ b/accel-pppd/session.c @@ -17,6 +17,7 @@ #include "log.h" #include "events.h" #include "ap_session.h" +#include "backup.h" #include "spinlock.h" #include "mempool.h" #include "memdebug.h" @@ -51,8 +52,6 @@ int __export ap_session_starting(struct ap_session *ses) { struct ifreq ifr; - ses->start_time = time(NULL); - if (ses->ifindex == -1) { memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, ses->ifname); @@ -63,10 +62,14 @@ int __export ap_session_starting(struct ap_session *ses) } ses->ifindex = ifr.ifr_ifindex; } - - generate_sessionid(ses); - ses->state = AP_STATE_STARTING; + if (ses->state != AP_STATE_RESTORE) { + ses->start_time = time(NULL); + generate_sessionid(ses); + + ses->state = AP_STATE_STARTING; + } + __sync_add_and_fetch(&ap_session_stat.starting, 1); pthread_rwlock_wrlock(&ses_lock); @@ -80,10 +83,16 @@ int __export ap_session_starting(struct ap_session *ses) void __export ap_session_activate(struct ap_session *ses) { + ap_session_ifup(ses); + ses->state = AP_STATE_ACTIVE; __sync_sub_and_fetch(&ap_session_stat.starting, 1); __sync_add_and_fetch(&ap_session_stat.active, 1); - ap_session_ifup(ses); + +#ifdef USE_BACKUP + if (!ses->backup) + backup_save_session(ses); +#endif } void __export ap_session_finished(struct ap_session *ses) @@ -98,6 +107,7 @@ void __export ap_session_finished(struct ap_session *ses) case AP_STATE_ACTIVE: __sync_sub_and_fetch(&ap_session_stat.active, 1); break; + case AP_STATE_RESTORE: case AP_STATE_STARTING: __sync_sub_and_fetch(&ap_session_stat.starting, 1); break; @@ -123,6 +133,11 @@ void __export ap_session_finished(struct ap_session *ses) _free(ses->ipv6_pool_name); ses->ipv6_pool_name = NULL; } + +#ifdef USE_BACKUP + if (ses->backup) + ses->backup->storage->free(ses->backup); +#endif if (ap_shutdown && !ap_session_stat.starting && !ap_session_stat.active && !ap_session_stat.finishing) kill(getpid(), SIGTERM); @@ -145,14 +160,14 @@ void __export ap_session_terminate(struct ap_session *ses, int cause, int hard) return; } - ses->terminating = 1; - ses->state = AP_STATE_FINISHING; - if (ses->state == AP_STATE_ACTIVE) __sync_sub_and_fetch(&ap_session_stat.active, 1); else __sync_sub_and_fetch(&ap_session_stat.starting, 1); + __sync_add_and_fetch(&ap_session_stat.finishing, 1); + ses->terminating = 1; + ses->state = AP_STATE_FINISHING; log_ppp_debug("terminate\n"); diff --git a/accel-pppd/session_backup.c b/accel-pppd/session_backup.c new file mode 100644 index 0000000..8607362 --- /dev/null +++ b/accel-pppd/session_backup.c @@ -0,0 +1,136 @@ +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <netinet/in.h> + +#include "events.h" +#include "triton.h" +#include "log.h" +#include "ap_session.h" +#include "backup.h" +#include "ap_session_backup.h" +#include "ipdb.h" + +#include "memdebug.h" + +#ifdef USE_BACKUP + +#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 ipv6db_addr_t *a; + struct ses_tag_ipv6 ipv6; + + add_tag(SES_TAG_USERNAME, ses->username, strlen(ses->username)); + add_tag(SES_TAG_SESSIONID, ses->sessionid, AP_SESSIONID_LEN); + add_tag(SES_TAG_START_TIME, &ses->start_time, sizeof(time_t)); + add_tag(SES_TAG_IFNAME, ses->ifname, strlen(ses->ifname)); + add_tag_int(SES_TAG_IFINDEX, &ses->ifindex, 4); + + if (ses->ipv4) { + add_tag(SES_TAG_IPV4_ADDR, &ses->ipv4->addr, 4); + add_tag(SES_TAG_IPV4_PEER_ADDR, &ses->ipv4->peer_addr, 4); + } + + if (ses->ipv6) { + add_tag(SES_TAG_IPV6_INTFID, &ses->ipv6->intf_id, 8); + add_tag(SES_TAG_IPV6_PEER_INTFID, &ses->ipv6->peer_intf_id, 8); + list_for_each_entry(a, &ses->ipv6->addr_list, entry) { + ipv6.addr = a->addr; + ipv6.prefix_len = a->prefix_len; + add_tag(SES_TAG_IPV6_ADDR, &ipv6, sizeof(ipv6)); + } + } + + //add_tag_int(PPP_TAG_FD, &ses->fd, sizeof(ses->fd)); + //add_tag_int(PPP_TAG_CHAN_FD, &ses->chan_fd, sizeof(ses->chan_fd)); + //add_tag_int(PPP_TAG_UNIT_FD, &ses->unit_fd, sizeof(ses->unit_fd)); + //add_tag_int(PPP_TAG_UNIT, &ses->unit_idx, sizeof(ses->unit_idx)); + + //triton_event_fire(EV_PPP_SESSION_SAVE, &ev); + + return 0; +} + +static int session_restore(struct ap_session *ses, struct backup_mod *m) +{ + struct backup_tag *t; + + list_for_each_entry(t, &m->tag_list, entry) { + switch(t->id) { + case SES_TAG_USERNAME: + ses->username = _malloc(t->size + 1); + if (!ses->username) { + log_emerg("out of memory"); + return -1; + } + memcpy(ses->username, t->data, t->size); + ses->username[t->size] = 0; + break; + case SES_TAG_SESSIONID: + memcpy(ses->sessionid, t->data, AP_SESSIONID_LEN); + break; + case SES_TAG_IFNAME: + memcpy(ses->ifname, t->data, t->size); + ses->ifname[t->size] = 0; + break; + case SES_TAG_START_TIME: + ses->start_time = *(time_t *)t->data; + break; + case SES_TAG_IFINDEX: + if (ses->backup->internal) + ses->ifindex = *(uint32_t *)t->data; + break; + /*case PPP_TAG_FD: + ses->fd = *(int *)t->data; + break; + case PPP_TAG_CHAN_FD: + ses->chan_fd = *(int *)t->data; + break; + case PPP_TAG_UNIT_FD: + ses->chan_fd = *(int *)t->data; + break; + case PPP_TAG_UNIT: + ses->unit_idx = *(int *)t->data; + break; + case PPP_TAG_IPV4_ADDR: + if (!ses->ipv4) { + ses->ipv4 = _malloc(sizeof(*ses->ipv4)); + memset(ses->ipv4, 0, sizeof(*ses->ipv4)); + ses->ipv4->owner = &ipdb; + } + ses->ipv4->addr = *(in_addr_t *)t->data; + break; + case PPP_TAG_IPV4_PEER_ADDR: + if (!ses->ipv4) { + ses->ipv4 = _malloc(sizeof(*ses->ipv4)); + memset(ses->ipv4, 0, sizeof(*ses->ipv4)); + ses->ipv4->owner = &ipdb; + } + ses->ipv4->peer_addr = *(in_addr_t *)t->data; + break;*/ + } + } + + return 0; + //return establish_ses(ses); +} + +static struct backup_module mod = { + .id = MODID_COMMON, + .save = session_save, + .restore = session_restore, +}; + +static void init(void) +{ + backup_register_module(&mod); +} + +DEFINE_INIT(101, init); + +#endif |