summaryrefslogtreecommitdiff
path: root/accel-pptpd/extra
diff options
context:
space:
mode:
Diffstat (limited to 'accel-pptpd/extra')
-rw-r--r--accel-pptpd/extra/CMakeLists.txt6
-rw-r--r--accel-pptpd/extra/ippool.c208
-rw-r--r--accel-pptpd/extra/pppd_compat.c10
-rw-r--r--accel-pptpd/extra/sigchld.c117
-rw-r--r--accel-pptpd/extra/sigchld.h21
5 files changed, 357 insertions, 5 deletions
diff --git a/accel-pptpd/extra/CMakeLists.txt b/accel-pptpd/extra/CMakeLists.txt
index 7b4b69b6..a14a5a3b 100644
--- a/accel-pptpd/extra/CMakeLists.txt
+++ b/accel-pptpd/extra/CMakeLists.txt
@@ -1,2 +1,8 @@
ADD_LIBRARY(pppd_compat SHARED pppd_compat.c)
+ADD_LIBRARY(ippool SHARED ippool.c)
+ADD_LIBRARY(sigchld SHARED sigchld.c)
+
+INSTALL(TARGETS pppd_compat ippool sigchld
+ LIBRARY DESTINATION usr/lib/accel-pptp
+)
diff --git a/accel-pptpd/extra/ippool.c b/accel-pptpd/extra/ippool.c
new file mode 100644
index 00000000..5f90fe8a
--- /dev/null
+++ b/accel-pptpd/extra/ippool.c
@@ -0,0 +1,208 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#include "ipdb.h"
+#include "list.h"
+#include "spinlock.h"
+
+#include "memdebug.h"
+
+struct ippool_item_t
+{
+ struct list_head entry;
+ struct ipdb_item_t it;
+};
+
+struct ipaddr_t
+{
+ struct list_head entry;
+ in_addr_t addr;
+};
+
+static LIST_HEAD(gw_list);
+static LIST_HEAD(tunnel_list);
+static LIST_HEAD(ippool);
+static spinlock_t pool_lock = SPINLOCK_INITIALIZER;
+static struct ipdb_t ipdb;
+
+static in_addr_t conf_gw_ip_address;
+static int cnt;
+
+static void parse_gw_ip_address(const char *val)
+{
+ if (!val)
+ return;
+
+ conf_gw_ip_address = inet_addr(val);
+}
+
+//parses ranges like x.x.x.x/mask
+static int parse1(const char *str, uint32_t *begin, uint32_t *end)
+{
+ int n, f1, f2, f3, f4, m, mask = 0;
+
+ n = sscanf(str, "%u.%u.%u.%u/%u",&f1, &f2, &f3, &f4, &m);
+ if (n != 5)
+ return -1;
+ if (f1 > 255)
+ return -1;
+ if (f1 > 255)
+ return -1;
+ if (f1 > 255)
+ return -1;
+ if (f1 > 255)
+ return -1;
+ if (m == 0 || m > 32)
+ return -1;
+
+ for (n = 0; n < m ; n++)
+ mask |= 1 << n;
+
+ *begin = (f4 << 24) | (f3 << 16) | (f2 << 8) | f1;
+ *end = *begin | ~mask;
+
+ return 0;
+}
+
+//parses ranges like x.x.x.x-y
+static int parse2(const char *str, uint32_t *begin, uint32_t *end)
+{
+ int n, f1, f2, f3, f4, m;
+
+ n = sscanf(str, "%u.%u.%u.%u-%u",&f1, &f2, &f3, &f4, &m);
+ if (n != 5)
+ return -1;
+ if (f1 > 255)
+ return -1;
+ if (f2 > 255)
+ return -1;
+ if (f3 > 255)
+ return -1;
+ if (f4 > 255)
+ return -1;
+ if (m < f4 || m > 255)
+ return -1;
+
+ *begin = (f4 << 24) | (f3 << 16) | (f2 << 8) | f1;
+ *end = (m << 24) | (f3 << 16) | (f2 << 8) | f1;
+
+ return 0;
+}
+
+static void add_range(struct list_head *list, const char *name)
+{
+ uint32_t i,startip, endip;
+ struct ipaddr_t *ip;
+
+ if (parse1(name, &startip, &endip))
+ if (parse2(name, &startip, &endip)) {
+ fprintf(stderr, "ippool: cann't parse '%s'\n", name);
+ _exit(EXIT_FAILURE);
+ }
+
+ for (i = ntohl(startip); i <= ntohl(endip); i++) {
+ ip = malloc(sizeof(*ip));
+ ip->addr = htonl(i);
+ list_add_tail(&ip->entry, list);
+ cnt++;
+ }
+}
+
+static void generate_pool(void)
+{
+ struct ippool_item_t *it;
+ struct ipaddr_t *addr = NULL;
+ struct ipaddr_t *peer_addr;
+
+ while (1) {
+ if (list_empty(&tunnel_list))
+ break;
+ else {
+ peer_addr = list_entry(tunnel_list.next, typeof(*peer_addr), entry);
+ list_del(&peer_addr->entry);
+ }
+
+ if (!conf_gw_ip_address) {
+ if (list_empty(&gw_list))
+ break;
+ else {
+ addr = list_entry(gw_list.next, typeof(*addr), entry);
+ list_del(&addr->entry);
+ }
+ }
+
+ it = malloc(sizeof(*it));
+ if (!it) {
+ fprintf(stderr, "ippool: out of memory\n");
+ break;
+ }
+
+ it->it.owner = &ipdb;
+ if (conf_gw_ip_address)
+ it->it.addr = conf_gw_ip_address;
+ else
+ it->it.addr = addr->addr;
+
+ it->it.peer_addr = peer_addr->addr;
+
+ list_add_tail(&it->entry, &ippool);
+ }
+}
+
+static struct ipdb_item_t *get_ip(struct ppp_t *ppp)
+{
+ struct ippool_item_t *it;
+
+ spin_lock(&pool_lock);
+ if (!list_empty(&ippool)) {
+ it = list_entry(ippool.next, typeof(*it), entry);
+ list_del(&it->entry);
+ } else
+ it = NULL;
+ spin_unlock(&pool_lock);
+
+ return it ? &it->it : NULL;
+}
+
+static void put_ip(struct ppp_t *ppp, struct ipdb_item_t *it)
+{
+ struct ippool_item_t *pit = container_of(it, typeof(*pit), it);
+
+ spin_lock(&pool_lock);
+ list_add_tail(&pit->entry, &ippool);
+ spin_unlock(&pool_lock);
+}
+
+static struct ipdb_t ipdb = {
+ .get = get_ip,
+ .put = put_ip,
+};
+
+static void __init ipool_init(void)
+{
+ struct conf_sect_t *s = conf_get_section("ip-pool");
+ struct conf_option_t *opt;
+
+ if (!s)
+ return;
+
+ list_for_each_entry(opt, &s->items, entry) {
+ if (!strcmp(opt->name, "gw-ip-address"))
+ parse_gw_ip_address(opt->val);
+ else if (!strcmp(opt->name, "gw"))
+ add_range(&gw_list, opt->val);
+ else if (!strcmp(opt->name, "tunnel"))
+ add_range(&tunnel_list, opt->val);
+ else if (!opt->val)
+ add_range(&tunnel_list, opt->name);
+ }
+
+ generate_pool();
+
+ ipdb_register(&ipdb);
+}
+
diff --git a/accel-pptpd/extra/pppd_compat.c b/accel-pptpd/extra/pppd_compat.c
index e45d609a..8dd35028 100644
--- a/accel-pptpd/extra/pppd_compat.c
+++ b/accel-pptpd/extra/pppd_compat.c
@@ -48,7 +48,7 @@ static void ip_up_handler(struct sigchld_handler_t *h, int status)
struct pppd_compat_pd_t *pd = container_of(h, typeof(*pd), ip_up_hnd);
if (conf_verbose) {
log_switch(NULL, pd->ppp);
- log_ppp_debug("pppd_compat: ip-up finished (%i)\n", status);
+ log_ppp_info("pppd_compat: ip-up finished (%i)\n", status);
}
}
@@ -57,7 +57,7 @@ static void ip_down_handler(struct sigchld_handler_t *h, int status)
struct pppd_compat_pd_t *pd = container_of(h, typeof(*pd), ip_down_hnd);
if (conf_verbose) {
log_switch(NULL, pd->ppp);
- log_ppp_debug("pppd_compat: ip-down finished (%i)\n", status);
+ log_ppp_info("pppd_compat: ip-down finished (%i)\n", status);
}
sched_yield();
triton_context_wakeup(pd->ppp->ctrl->ctx);
@@ -68,7 +68,7 @@ static void ip_change_handler(struct sigchld_handler_t *h, int status)
struct pppd_compat_pd_t *pd = container_of(h, typeof(*pd), ip_change_hnd);
if (conf_verbose) {
log_switch(NULL, pd->ppp);
- log_ppp_debug("pppd_compat: ip-change finished (%i)\n", status);
+ log_ppp_info("pppd_compat: ip-change finished (%i)\n", status);
}
sched_yield();
pd->ip_change_res = status;
@@ -113,7 +113,7 @@ static void ev_ppp_started(struct ppp_t *ppp)
pd->ip_up_hnd.pid = pid;
sigchld_register_handler(&pd->ip_up_hnd);
if (conf_verbose)
- log_ppp_debug("pppd_compat: ip-up started (pid %i)\n", pid);
+ log_ppp_info("pppd_compat: ip-up started (pid %i)\n", pid);
sigchld_unlock();
} else if (pid == 0) {
execv(conf_ip_up, argv);
@@ -156,7 +156,7 @@ static void ev_ppp_finished(struct ppp_t *ppp)
pd->ip_down_hnd.pid = pid;
sigchld_register_handler(&pd->ip_down_hnd);
if (conf_verbose)
- log_ppp_debug("pppd_compat: ip-down started (pid %i)\n", pid);
+ log_ppp_info("pppd_compat: ip-down started (pid %i)\n", pid);
sigchld_unlock();
triton_context_schedule(pd->ppp->ctrl->ctx);
pthread_mutex_lock(&pd->ip_down_hnd.lock);
diff --git a/accel-pptpd/extra/sigchld.c b/accel-pptpd/extra/sigchld.c
new file mode 100644
index 00000000..49bcfd43
--- /dev/null
+++ b/accel-pptpd/extra/sigchld.c
@@ -0,0 +1,117 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/signalfd.h>
+#include <sys/wait.h>
+
+#include "triton.h"
+#include "spinlock.h"
+#include "log.h"
+
+#include "sigchld.h"
+
+#include "memdebug.h"
+
+static LIST_HEAD(handlers);
+static int lock_refs;
+static pthread_mutex_t handlers_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t refs_cond = PTHREAD_COND_INITIALIZER;
+static pthread_t sigchld_thr;
+
+static void* sigchld_thread(void *arg)
+{
+ sigset_t set;
+ struct sigchld_handler_t *h, *h0;
+ pid_t pid;
+ int status, sig;
+
+ sigfillset(&set);
+ sigdelset(&set, SIGKILL);
+ sigdelset(&set, SIGSTOP);
+ pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGCHLD);
+ sigaddset(&set, SIGQUIT);
+
+ while (1) {
+ pid = waitpid(0, &status, 0);
+ if (pid < 0) {
+ if (errno == EINTR)
+ continue;
+ if (errno == ECHILD) {
+ sigwait(&set, &sig);
+ if (sig == SIGQUIT)
+ break;
+ continue;
+ }
+ log_error("sigchld: waitpid: %s\n", strerror(errno));
+ continue;
+ }
+
+ pthread_mutex_lock(&handlers_lock);
+ while (lock_refs)
+ pthread_cond_wait(&refs_cond, &handlers_lock);
+
+ h0 = NULL;
+ list_for_each_entry(h, &handlers, entry) {
+ if (h->pid == pid) {
+ h0 = h;
+ pthread_mutex_lock(&h0->lock);
+ break;
+ }
+ }
+ pthread_mutex_unlock(&handlers_lock);
+ if (h0) {
+ list_del(&h0->entry);
+ h0->handler(h0, WEXITSTATUS(status));
+ h0->pid = 0;
+ pthread_mutex_unlock(&h0->lock);
+ }
+ }
+
+ return NULL;
+}
+
+void __export sigchld_register_handler(struct sigchld_handler_t *h)
+{
+ pthread_mutex_init(&h->lock, NULL);
+
+ pthread_mutex_lock(&handlers_lock);
+ list_add_tail(&h->entry, &handlers);
+ pthread_mutex_unlock(&handlers_lock);
+}
+
+void __export sigchld_unregister_handler(struct sigchld_handler_t *h)
+{
+ pthread_mutex_lock(&handlers_lock);
+ pthread_mutex_lock(&h->lock);
+ if (h->pid) {
+ list_del(&h->entry);
+ h->pid = 0;
+ }
+ pthread_mutex_unlock(&h->lock);
+ pthread_mutex_unlock(&handlers_lock);
+}
+
+void __export sigchld_lock()
+{
+ pthread_mutex_lock(&handlers_lock);
+ ++lock_refs;
+ pthread_mutex_unlock(&handlers_lock);
+}
+
+void __export sigchld_unlock()
+{
+ pthread_mutex_lock(&handlers_lock);
+ if (--lock_refs == 0)
+ pthread_cond_signal(&refs_cond);
+ pthread_mutex_unlock(&handlers_lock);
+}
+
+static void __init init(void)
+{
+ if (pthread_create(&sigchld_thr, NULL, sigchld_thread, NULL))
+ log_emerg("sigchld: pthread_create: %s\n", strerror(errno));
+}
diff --git a/accel-pptpd/extra/sigchld.h b/accel-pptpd/extra/sigchld.h
new file mode 100644
index 00000000..27d1adf4
--- /dev/null
+++ b/accel-pptpd/extra/sigchld.h
@@ -0,0 +1,21 @@
+#ifndef __SIGCHLD_H
+#define __SIGCHLD_H
+
+#include <pthread.h>
+#include "list.h"
+
+struct sigchld_handler_t
+{
+ struct list_head entry;
+ pthread_mutex_t lock;
+ pid_t pid;
+ void (*handler)(struct sigchld_handler_t *, int status);
+};
+
+void sigchld_register_handler(struct sigchld_handler_t *);
+void sigchld_unregister_handler(struct sigchld_handler_t *);
+void sigchld_lock();
+void sigchld_unlock();
+
+#endif
+