summaryrefslogtreecommitdiff
path: root/accel-pptpd
diff options
context:
space:
mode:
authorKozlov Dmitry <dima@server>2010-09-14 15:56:31 +0400
committerKozlov Dmitry <dima@server>2010-09-14 16:05:10 +0400
commitd860a4beaf5f99d5045d03b931b4829426a2f7b0 (patch)
tree377f0cf851020786f5e40f70644a3dafbc63ce14 /accel-pptpd
parenta670641cc3c420bfd9026d3711501663aef88287 (diff)
downloadaccel-ppp-d860a4beaf5f99d5045d03b931b4829426a2f7b0.tar.gz
accel-ppp-d860a4beaf5f99d5045d03b931b4829426a2f7b0.zip
extra: implemented module 'pppd_compat' which starts pppd compatible scripts ip-up, ip-down,
and newly introduced - ip-change, when radius CoA request received, also this module manages pppd compatible radattr.pppX files core: implemented module 'sigchld' which handles SIGCHLD signal, waits child processes to terminate and manages pid terminate handlers
Diffstat (limited to 'accel-pptpd')
-rw-r--r--accel-pptpd/CMakeLists.txt6
-rw-r--r--accel-pptpd/accel-pptpd.conf8
-rw-r--r--accel-pptpd/extra/CMakeLists.txt2
-rw-r--r--accel-pptpd/extra/pppd_compat.c375
-rw-r--r--accel-pptpd/include/events.h12
l---------accel-pptpd/include/radius.h1
l---------accel-pptpd/include/sigchld.h1
l---------accel-pptpd/include/utils.h1
-rw-r--r--accel-pptpd/log.c2
-rw-r--r--accel-pptpd/ppp/ipcp_opt_ipaddr.c3
-rw-r--r--accel-pptpd/ppp/ppp.h3
-rw-r--r--accel-pptpd/radius/acct.c2
-rw-r--r--accel-pptpd/radius/auth.c40
-rw-r--r--accel-pptpd/radius/dict.c16
-rw-r--r--accel-pptpd/radius/dm_coa.c27
-rw-r--r--accel-pptpd/radius/packet.c21
-rw-r--r--accel-pptpd/radius/radius.c2
-rw-r--r--accel-pptpd/radius/radius.h81
-rw-r--r--accel-pptpd/radius/radius_p.h90
-rw-r--r--accel-pptpd/radius/req.c2
-rw-r--r--accel-pptpd/sigchld.c134
-rw-r--r--accel-pptpd/sigchld.h21
-rw-r--r--accel-pptpd/triton/triton.c11
-rw-r--r--accel-pptpd/triton/triton.h7
-rw-r--r--accel-pptpd/utils.c10
-rw-r--r--accel-pptpd/utils.h8
26 files changed, 775 insertions, 111 deletions
diff --git a/accel-pptpd/CMakeLists.txt b/accel-pptpd/CMakeLists.txt
index 1621e35a..b27302ca 100644
--- a/accel-pptpd/CMakeLists.txt
+++ b/accel-pptpd/CMakeLists.txt
@@ -10,6 +10,7 @@ ADD_SUBDIRECTORY(ctrl)
ADD_SUBDIRECTORY(auth)
ADD_SUBDIRECTORY(radius)
ADD_SUBDIRECTORY(logs)
+ADD_SUBDIRECTORY(extra)
ADD_EXECUTABLE(pptpd
ppp/ppp.c
@@ -30,7 +31,10 @@ ADD_EXECUTABLE(pptpd
iprange.c
ippool.c
-
+
+ utils.c
+ sigchld.c
+
log.c
main.c
)
diff --git a/accel-pptpd/accel-pptpd.conf b/accel-pptpd/accel-pptpd.conf
index eaa4dafe..5ebff71c 100644
--- a/accel-pptpd/accel-pptpd.conf
+++ b/accel-pptpd/accel-pptpd.conf
@@ -7,6 +7,7 @@
./libauth_mschap_v1.so
./libauth_mschap_v2.so
./libradius.so
+./libpppd_compat.so
[core]
log-error=/dev/stderr
@@ -52,3 +53,10 @@ log-emerg=/dev/stderr
[log-pgsql]
conninfo=user=log
log-table=log
+
+[pppd-compat]
+ip-up=./ip-up.sh
+ip-down=./ip-down.sh
+ip-change=./ip-change.sh
+radattr-prefix=./radattr
+verbose=1
diff --git a/accel-pptpd/extra/CMakeLists.txt b/accel-pptpd/extra/CMakeLists.txt
new file mode 100644
index 00000000..7b4b69b6
--- /dev/null
+++ b/accel-pptpd/extra/CMakeLists.txt
@@ -0,0 +1,2 @@
+ADD_LIBRARY(pppd_compat SHARED pppd_compat.c)
+
diff --git a/accel-pptpd/extra/pppd_compat.c b/accel-pptpd/extra/pppd_compat.c
new file mode 100644
index 00000000..1cf67413
--- /dev/null
+++ b/accel-pptpd/extra/pppd_compat.c
@@ -0,0 +1,375 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sched.h>
+#include <limits.h>
+
+#include "triton.h"
+
+#include "events.h"
+#include "ppp.h"
+#include "log.h"
+#include "radius.h"
+#include "utils.h"
+#include "sigchld.h"
+
+static char *conf_ip_up = "/etc/ppp/ip-up";
+static char *conf_ip_down = "/etc/ppp/ip-down";
+static char *conf_ip_change = "/etc/ppp/ip-change";
+static char *conf_radattr_prefix = "/var/run/radattr.";
+static int conf_verbose = 0;
+
+static void *pd_key;
+
+struct pppd_compat_pd_t
+{
+ struct ppp_pd_t pd;
+ struct ppp_t *ppp;
+ struct sigchld_handler_t ip_up_hnd;
+ struct sigchld_handler_t ip_change_hnd;
+ struct sigchld_handler_t ip_down_hnd;
+ int radattr_saved:1;
+ int started:1;
+ int ip_change_res;
+};
+
+static void remove_radattr(struct ppp_t *ppp);
+static struct pppd_compat_pd_t *find_pd(struct ppp_t *ppp);
+static void fill_argv(char **argv, struct ppp_t *ppp, char *path);
+static void write_radattr(struct ppp_t *ppp, struct rad_packet_t *pack, int save_old);
+
+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);
+ }
+}
+
+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);
+ }
+ sched_yield();
+ triton_context_wakeup(pd->ppp->ctrl->ctx);
+}
+
+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);
+ }
+ sched_yield();
+ pd->ip_change_res = status;
+ triton_context_wakeup(pd->ppp->ctrl->ctx);
+}
+
+static void ev_ppp_starting(struct ppp_t *ppp)
+{
+ struct pppd_compat_pd_t *pd = malloc(sizeof(*pd));
+
+ if (!pd) {
+ log_emerg("pppd_compat: out of memory\n");
+ return;
+ }
+
+ memset(pd, 0, sizeof(*pd));
+ pd->pd.key = &pd_key;
+ pd->ppp = ppp;
+ pd->ip_up_hnd.handler = ip_up_handler;
+ pd->ip_down_hnd.handler = ip_down_handler;
+ pd->ip_change_hnd.handler = ip_change_handler;
+ list_add_tail(&pd->pd.entry, &ppp->pd_list);
+}
+static void ev_ppp_started(struct ppp_t *ppp)
+{
+ pid_t pid;
+ char *argv[8];
+ char ipaddr[16];
+ char peer_ipaddr[16];
+ struct pppd_compat_pd_t *pd = find_pd(ppp);
+
+ if (!pd)
+ return;
+
+ argv[4] = ipaddr;
+ argv[5] = peer_ipaddr;
+ fill_argv(argv, ppp, conf_ip_up);
+
+ sigchld_lock();
+ pid = fork();
+ if (pid > 0) {
+ 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);
+ sigchld_unlock();
+ } else if (pid == 0) {
+ execv(conf_ip_up, argv);
+ log_error("pppd_compat: exec '%s': %s\n", conf_ip_up, strerror(errno));
+ _exit(EXIT_FAILURE);
+ } else
+ log_error("pppd_compat: fork: %s\n", strerror(errno));
+
+ pd->started = 1;
+}
+
+static void ev_ppp_finished(struct ppp_t *ppp)
+{
+ pid_t pid;
+ char *argv[8];
+ char ipaddr[16];
+ char peer_ipaddr[16];
+ struct pppd_compat_pd_t *pd = find_pd(ppp);
+
+ if (!pd)
+ return;
+
+ if (pd->started) {
+ pthread_mutex_lock(&pd->ip_up_hnd.lock);
+ if (pd->ip_up_hnd.pid) {
+ log_ppp_warn("pppd_compat: ip-up is not yet finished, terminating it ...\n");
+ kill(pd->ip_up_hnd.pid, SIGTERM);
+ pthread_mutex_unlock(&pd->ip_up_hnd.lock);
+ }
+ }
+
+ argv[4] = ipaddr;
+ argv[5] = peer_ipaddr;
+ fill_argv(argv, pd->ppp, conf_ip_down);
+
+ sigchld_lock();
+ pid = fork();
+ if (pid > 0) {
+ 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);
+ sigchld_unlock();
+ triton_context_schedule(pd->ppp->ctrl->ctx);
+ } else if (pid == 0) {
+ execv(conf_ip_down, argv);
+ log_error("pppd_compat: exec '%s': %s\n", conf_ip_change, strerror(errno));
+ _exit(EXIT_FAILURE);
+ } else
+ log_error("pppd_compat: fork: %s\n", strerror(errno));
+
+ if (pd->started) {
+ pthread_mutex_lock(&pd->ip_up_hnd.lock);
+ if (pd->ip_up_hnd.pid) {
+ log_ppp_warn("pppd_compat: ip-up is not yet finished, killing it ...\n");
+ kill(pd->ip_up_hnd.pid, SIGKILL);
+ pthread_mutex_unlock(&pd->ip_up_hnd.lock);
+ sigchld_unregister_handler(&pd->ip_up_hnd);
+ } else
+ pthread_mutex_unlock(&pd->ip_up_hnd.lock);
+ }
+
+ if (pd->radattr_saved)
+ remove_radattr(ppp);
+
+ list_del(&pd->pd.entry);
+ free(pd);
+}
+
+static void ev_radius_access_accept(struct ev_radius_t *ev)
+{
+ struct pppd_compat_pd_t *pd = find_pd(ev->ppp);
+
+ write_radattr(ev->ppp, ev->reply, 0);
+
+ pd->radattr_saved = 1;
+}
+
+static void ev_radius_coa(struct ev_radius_t *ev)
+{
+ pid_t pid;
+ char *argv[8];
+ char ipaddr[16];
+ char peer_ipaddr[16];
+ struct pppd_compat_pd_t *pd = find_pd(ev->ppp);
+
+ if (!pd)
+ return;
+
+ write_radattr(ev->ppp, ev->request, 1);
+
+ argv[4] = ipaddr;
+ argv[5] = peer_ipaddr;
+ fill_argv(argv, pd->ppp, conf_ip_change);
+
+ sigchld_lock();
+ pid = fork();
+ if (pid > 0) {
+ pd->ip_change_hnd.pid = pid;
+ sigchld_register_handler(&pd->ip_change_hnd);
+ sigchld_unlock();
+ if (conf_verbose)
+ log_ppp_debug("pppd_compat: ip-change started (pid %i)\n", pid);
+ triton_context_schedule(pd->ppp->ctrl->ctx);
+ if (!ev->res)
+ ev->res = pd->ip_change_res;
+ } else if (pid == 0) {
+ execv(conf_ip_change, argv);
+ log_error("pppd_compat: exec '%s': %s\n", conf_ip_change, strerror(errno));
+ _exit(EXIT_FAILURE);
+ } else
+ log_error("pppd_compat: fork: %s\n", strerror(errno));
+}
+
+static void remove_radattr(struct ppp_t *ppp)
+{
+ char *fname;
+
+ fname = malloc(PATH_MAX);
+ if (!fname) {
+ log_emerg("pppd_compat: out of memory\n");
+ return;
+ }
+
+ sprintf(fname, "%s.%s", conf_radattr_prefix, ppp->ifname);
+ if (unlink(fname)) {
+ log_ppp_warn("pppd_compat: failed to remove '%s': %s\n", fname, strerror(errno));
+ }
+ sprintf(fname, "%s_old.%s", conf_radattr_prefix, ppp->ifname);
+ unlink(fname);
+
+ free(fname);
+}
+
+static void write_radattr(struct ppp_t *ppp, struct rad_packet_t *pack, int save_old)
+{
+ struct rad_attr_t *attr;
+ struct rad_dict_value_t *val;
+ FILE *f;
+ char *fname1, *fname2;
+ int i;
+
+ fname1 = malloc(PATH_MAX);
+ if (!fname1) {
+ log_emerg("pppd_compat: out of memory\n");
+ return;
+ }
+
+ if (save_old) {
+ fname2 = malloc(PATH_MAX);
+ if (!fname2) {
+ log_emerg("pppd_compat: out of memory\n");
+ free(fname1);
+ return;
+ }
+ }
+
+ sprintf(fname1, "%s.%s", conf_radattr_prefix, ppp->ifname);
+ if (save_old) {
+ sprintf(fname2, "%s_old.%s", conf_radattr_prefix, ppp->ifname);
+ if (rename(fname1, fname2)) {
+ log_ppp_warn("pppd_compat: rename: %s\n", strerror(errno));
+ }
+ }
+
+ f = fopen(fname1, "w");
+ if (f) {
+ list_for_each_entry(attr, &pack->attrs, entry) {
+ fprintf(f, "%s ", attr->attr->name);
+ switch (attr->attr->type) {
+ case ATTR_TYPE_INTEGER:
+ val = rad_dict_find_val(attr->attr, attr->val);
+ if (val)
+ fprintf(f, "%s\n", val->name);
+ else
+ fprintf(f, "%i\n", attr->val.integer);
+ break;
+ case ATTR_TYPE_STRING:
+ fprintf(f, "%s\n", attr->val.string);
+ break;
+ case ATTR_TYPE_OCTETS:
+ for (i = 0; i < attr->len; i++)
+ fprintf(f, "%02X", attr->val.octets[i]);
+ fprintf(f, "\n");
+ break;
+ case ATTR_TYPE_IPADDR:
+ fprintf(f, "%i.%i.%i.%i\n", attr->val.ipaddr & 0xff, (attr->val.ipaddr >> 8) & 0xff, (attr->val.ipaddr >> 16) & 0xff, (attr->val.ipaddr >> 24) & 0xff);
+ break;
+ case ATTR_TYPE_DATE:
+ fprintf(f, "%lu\n", attr->val.date);
+ break;
+ }
+ }
+ fclose(f);
+ } else
+ log_ppp_warn("pppd_compat: failed to create '%s': %s\n", fname1, strerror(errno));
+
+ free(fname1);
+ if (save_old)
+ free(fname2);
+}
+
+static struct pppd_compat_pd_t *find_pd(struct ppp_t *ppp)
+{
+ struct ppp_pd_t *pd;
+ struct pppd_compat_pd_t *cpd;
+
+ list_for_each_entry(pd, &ppp->pd_list, entry) {
+ if (pd->key == &pd_key) {
+ cpd = container_of(pd, typeof(*cpd), pd);
+ return cpd;
+ }
+ }
+
+ log_ppp_warn("pppd_compat: pd not found\n");
+ return NULL;
+}
+
+static void fill_argv(char **argv, struct ppp_t *ppp, char *path)
+{
+ argv[0] = path;
+ argv[1] = ppp->ifname;
+ argv[2] = "none";
+ argv[3] = "0";
+ u_inet_ntoa(ppp->ipaddr, argv[4]);
+ u_inet_ntoa(ppp->peer_ipaddr, argv[5]);
+ argv[6] = "none";
+ argv[7] = NULL;
+}
+
+static void __init init(void)
+{
+ char *opt;
+
+ opt = conf_get_opt("pppd-compat", "ip-up");
+ if (opt)
+ conf_ip_up = opt;
+
+ opt = conf_get_opt("pppd-compat", "ip-down");
+ if (opt)
+ conf_ip_down = opt;
+
+ opt = conf_get_opt("pppd-compat", "ip-change");
+ if (opt)
+ conf_ip_change = opt;
+
+ opt = conf_get_opt("pppd-compat", "radattr-prefix");
+ if (opt)
+ conf_radattr_prefix = opt;
+
+ opt = conf_get_opt("pppd-compat", "verbose");
+ if (opt && atoi(opt) > 0)
+ conf_verbose = 1;
+
+ triton_event_register_handler(EV_PPP_STARTING, (triton_event_func)ev_ppp_starting);
+ triton_event_register_handler(EV_PPP_STARTED, (triton_event_func)ev_ppp_started);
+ triton_event_register_handler(EV_PPP_FINISHED, (triton_event_func)ev_ppp_finished);
+ triton_event_register_handler(EV_RADIUS_ACCESS_ACCEPT, (triton_event_func)ev_radius_access_accept);
+ triton_event_register_handler(EV_RADIUS_COA, (triton_event_func)ev_radius_coa);
+}
+
diff --git a/accel-pptpd/include/events.h b/accel-pptpd/include/events.h
index 332b4e31..0b37d0fd 100644
--- a/accel-pptpd/include/events.h
+++ b/accel-pptpd/include/events.h
@@ -11,6 +11,18 @@
#define EV_CTRL_FINISHED 8
#define EV_IP_CHANGED 100
#define EV_SHAPE_CHANGED 101
+#define EV_RADIUS_ACCESS_ACCEPT 200
+#define EV_RADIUS_COA 201
+
+struct ppp_t;
+struct rad_packet_t;
+struct ev_radius_t
+{
+ struct ppp_t *ppp;
+ struct rad_packet_t *request;
+ struct rad_packet_t *reply;
+ int res;
+};
#endif
diff --git a/accel-pptpd/include/radius.h b/accel-pptpd/include/radius.h
new file mode 120000
index 00000000..e1465f19
--- /dev/null
+++ b/accel-pptpd/include/radius.h
@@ -0,0 +1 @@
+../radius/radius.h \ No newline at end of file
diff --git a/accel-pptpd/include/sigchld.h b/accel-pptpd/include/sigchld.h
new file mode 120000
index 00000000..166c77e6
--- /dev/null
+++ b/accel-pptpd/include/sigchld.h
@@ -0,0 +1 @@
+../sigchld.h \ No newline at end of file
diff --git a/accel-pptpd/include/utils.h b/accel-pptpd/include/utils.h
new file mode 120000
index 00000000..6cd5d4fd
--- /dev/null
+++ b/accel-pptpd/include/utils.h
@@ -0,0 +1 @@
+../utils.h \ No newline at end of file
diff --git a/accel-pptpd/log.c b/accel-pptpd/log.c
index 5012cba3..fbd50674 100644
--- a/accel-pptpd/log.c
+++ b/accel-pptpd/log.c
@@ -300,8 +300,6 @@ static struct log_pd_t *find_pd(struct ppp_t *ppp)
return lpd;
}
}
- list_for_each_entry(pd, &ppp->pd_list, entry)
- printf("%p %p\n", pd->key, &pd_key);
log_emerg("log:BUG: pd not found\n");
abort();
}
diff --git a/accel-pptpd/ppp/ipcp_opt_ipaddr.c b/accel-pptpd/ppp/ipcp_opt_ipaddr.c
index b7f86365..1f9af3e7 100644
--- a/accel-pptpd/ppp/ipcp_opt_ipaddr.c
+++ b/accel-pptpd/ppp/ipcp_opt_ipaddr.c
@@ -113,6 +113,9 @@ static int ipaddr_recv_conf_req(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *o
return IPCP_OPT_NAK;
ack:
+ ipcp->ppp->ipaddr = ipaddr_opt->ip->addr;
+ ipcp->ppp->peer_ipaddr = ipaddr_opt->ip->peer_addr;
+
memset(&ifr, 0, sizeof(ifr));
memset(&addr, 0, sizeof(addr));
diff --git a/accel-pptpd/ppp/ppp.h b/accel-pptpd/ppp/ppp.h
index 76b379f4..641a74ba 100644
--- a/accel-pptpd/ppp/ppp.h
+++ b/accel-pptpd/ppp/ppp.h
@@ -3,6 +3,7 @@
#include <sys/types.h>
#include <time.h>
+#include <netinet/in.h>
#include "triton.h"
#include "list.h"
@@ -76,6 +77,8 @@ struct ppp_t
char sessionid[PPP_SESSIONID_LEN+1];
time_t start_time;
char *username;
+ in_addr_t ipaddr;
+ in_addr_t peer_ipaddr;
struct ppp_ctrl_t *ctrl;
diff --git a/accel-pptpd/radius/acct.c b/accel-pptpd/radius/acct.c
index 785eab3a..72e6df34 100644
--- a/accel-pptpd/radius/acct.c
+++ b/accel-pptpd/radius/acct.c
@@ -8,7 +8,7 @@
#include <openssl/md5.h>
#include "log.h"
-#include "radius.h"
+#include "radius_p.h"
static int req_set_RA(struct rad_req_t *req, const char *secret)
{
diff --git a/accel-pptpd/radius/auth.c b/accel-pptpd/radius/auth.c
index 29c6efd3..92406b34 100644
--- a/accel-pptpd/radius/auth.c
+++ b/accel-pptpd/radius/auth.c
@@ -2,10 +2,12 @@
#include <string.h>
#include <openssl/md5.h>
+#include "triton.h"
+#include "events.h"
#include "log.h"
#include "pwdb.h"
-#include "radius.h"
+#include "radius_p.h"
static uint8_t* encrypt_password(const char *passwd, const char *secret, const uint8_t *RA, int *epasswd_len)
@@ -97,7 +99,15 @@ int rad_auth_pap(struct radius_pd_t *rpd, const char *username, va_list args)
free(epasswd);
- rad_auth_send(req);
+ r = rad_auth_send(req);
+ if (r == PWDB_SUCCESS) {
+ struct ev_radius_t ev = {
+ .ppp = rpd->ppp,
+ .request = req->pack,
+ .reply = req->reply,
+ };
+ triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev);
+ }
out:
rad_req_free(req);
@@ -134,6 +144,14 @@ int rad_auth_chap_md5(struct radius_pd_t *rpd, const char *username, va_list arg
goto out;
r = rad_auth_send(req);
+ if (r == PWDB_SUCCESS) {
+ struct ev_radius_t ev = {
+ .ppp = rpd->ppp,
+ .request = req->pack,
+ .reply = req->reply,
+ };
+ triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev);
+ }
out:
rad_req_free(req);
@@ -154,7 +172,7 @@ int rad_auth_mschap_v1(struct radius_pd_t *rpd, const char *username, va_list ar
const uint8_t *nt_response = va_arg(args, const uint8_t *);
int flags = va_arg(args, int);
- req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username);
+ req = rad_req_alloc(rpd, CODE_ACCESS_ACCEPT, username);
if (!req)
return PWDB_DENIED;
@@ -170,6 +188,14 @@ int rad_auth_mschap_v1(struct radius_pd_t *rpd, const char *username, va_list ar
goto out;
r = rad_auth_send(req);
+ if (r == PWDB_SUCCESS) {
+ struct ev_radius_t ev = {
+ .ppp = rpd->ppp,
+ .request = req->pack,
+ .reply = req->reply,
+ };
+ triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev);
+ }
out:
rad_req_free(req);
@@ -217,6 +243,14 @@ int rad_auth_mschap_v2(struct radius_pd_t *rpd, const char *username, va_list ar
} else
memcpy(authenticator, ra->val.octets + 3, 40);
}
+ if (r == PWDB_SUCCESS) {
+ struct ev_radius_t ev = {
+ .ppp = rpd->ppp,
+ .request = req->pack,
+ .reply = req->reply,
+ };
+ triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev);
+ }
out:
rad_req_free(req);
diff --git a/accel-pptpd/radius/dict.c b/accel-pptpd/radius/dict.c
index 6db77813..bd7a4ef3 100644
--- a/accel-pptpd/radius/dict.c
+++ b/accel-pptpd/radius/dict.c
@@ -5,7 +5,7 @@
#include <limits.h>
#include "list.h"
-#include "radius.h"
+#include "radius_p.h"
#include "log.h"
static struct rad_dict_t *dict;
@@ -281,12 +281,12 @@ static struct rad_dict_attr_t *dict_find_attr(struct list_head *items, const cha
return NULL;
}
-struct rad_dict_attr_t *rad_dict_find_attr(const char *name)
+__export struct rad_dict_attr_t *rad_dict_find_attr(const char *name)
{
return dict_find_attr(&dict->items, name);
}
-struct rad_dict_attr_t *rad_dict_find_attr_id(struct rad_dict_vendor_t *vendor, int id)
+__export struct rad_dict_attr_t *rad_dict_find_attr_id(struct rad_dict_vendor_t *vendor, int id)
{
struct rad_dict_attr_t *attr;
struct list_head *items = vendor ? &vendor->items : &dict->items;
@@ -298,7 +298,7 @@ struct rad_dict_attr_t *rad_dict_find_attr_id(struct rad_dict_vendor_t *vendor,
return NULL;
}
-struct rad_dict_value_t *rad_dict_find_val_name(struct rad_dict_attr_t *attr, const char *name)
+__export struct rad_dict_value_t *rad_dict_find_val_name(struct rad_dict_attr_t *attr, const char *name)
{
struct rad_dict_value_t *val;
@@ -309,7 +309,7 @@ struct rad_dict_value_t *rad_dict_find_val_name(struct rad_dict_attr_t *attr, co
return NULL;
}
-struct rad_dict_value_t *rad_dict_find_val(struct rad_dict_attr_t *attr, rad_value_t v)
+__export struct rad_dict_value_t *rad_dict_find_val(struct rad_dict_attr_t *attr, rad_value_t v)
{
struct rad_dict_value_t *val;
@@ -323,7 +323,7 @@ struct rad_dict_value_t *rad_dict_find_val(struct rad_dict_attr_t *attr, rad_val
return NULL;
}
-struct rad_dict_vendor_t *rad_dict_find_vendor_name(const char *name)
+__export struct rad_dict_vendor_t *rad_dict_find_vendor_name(const char *name)
{
struct rad_dict_vendor_t *vendor;
@@ -335,7 +335,7 @@ struct rad_dict_vendor_t *rad_dict_find_vendor_name(const char *name)
return NULL;
}
-struct rad_dict_vendor_t *rad_dict_find_vendor_id(int id)
+__export struct rad_dict_vendor_t *rad_dict_find_vendor_id(int id)
{
struct rad_dict_vendor_t *vendor;
@@ -347,7 +347,7 @@ struct rad_dict_vendor_t *rad_dict_find_vendor_id(int id)
return NULL;
}
-struct rad_dict_attr_t *rad_dict_find_vendor_attr(struct rad_dict_vendor_t *vendor, const char *name)
+__export struct rad_dict_attr_t *rad_dict_find_vendor_attr(struct rad_dict_vendor_t *vendor, const char *name)
{
return dict_find_attr(&vendor->items, name);
}
diff --git a/accel-pptpd/radius/dm_coa.c b/accel-pptpd/radius/dm_coa.c
index 784ad826..f515f873 100644
--- a/accel-pptpd/radius/dm_coa.c
+++ b/accel-pptpd/radius/dm_coa.c
@@ -12,9 +12,10 @@
#include <openssl/md5.h>
#include "triton.h"
+#include "events.h"
#include "log.h"
-#include "radius.h"
+#include "radius_p.h"
#define PD_COA_PORT 3799
@@ -98,7 +99,8 @@ static int dm_coa_send_nak(int fd, struct rad_packet_t *req, struct sockaddr_in
reply->id = req->id;
- rad_packet_add_int(reply, "Error-Cause", err_code);
+ if (err_code)
+ rad_packet_add_int(reply, "Error-Cause", err_code);
if (rad_packet_build(reply, RA)) {
rad_packet_free(reply);
@@ -137,14 +139,28 @@ static void disconnect_request(struct radius_pd_t *rpd)
static void coa_request(struct radius_pd_t *rpd)
{
+ struct ev_radius_t ev = {
+ .ppp = rpd->ppp,
+ .request = rpd->dm_coa_req,
+ };
+
if (conf_verbose) {
log_ppp_debug("recv ");
rad_packet_print(rpd->dm_coa_req, log_ppp_debug);
}
-/// TODO: CoA handling
+
+ triton_event_fire(EV_RADIUS_COA, &ev);
+
+ if (ev.res)
+ dm_coa_send_nak(serv.hnd.fd, rpd->dm_coa_req, &rpd->dm_coa_addr, 0);
+ else
+ dm_coa_send_ack(serv.hnd.fd, rpd->dm_coa_req, &rpd->dm_coa_addr);
rad_packet_free(rpd->dm_coa_req);
+
+ pthread_mutex_lock(&rpd->lock);
rpd->dm_coa_req = NULL;
+ pthread_mutex_unlock(&rpd->lock);
}
static int dm_coa_read(struct triton_md_handler_t *h)
@@ -187,6 +203,11 @@ static int dm_coa_read(struct triton_md_handler_t *h)
goto out_err;
}
+ if (rpd->dm_coa_req) {
+ pthread_mutex_unlock(&rpd->lock);
+ goto out_err_no_reply;
+ }
+
rpd->dm_coa_req = pack;
memcpy(&rpd->dm_coa_addr, &addr, sizeof(addr));
diff --git a/accel-pptpd/radius/packet.c b/accel-pptpd/radius/packet.c
index 0aeafa54..9e7df01d 100644
--- a/accel-pptpd/radius/packet.c
+++ b/accel-pptpd/radius/packet.c
@@ -8,7 +8,7 @@
#include "log.h"
-#include "radius.h"
+#include "radius_p.h"
struct rad_packet_t *rad_packet_alloc(int code)
{
@@ -165,7 +165,8 @@ struct rad_packet_t *rad_packet_recv(int fd, struct sockaddr_in *addr)
n -= 2 + len;
} else
log_ppp_warn("radius:packet: vendor %s not found\n", id);
- }
+ } else
+ vendor = NULL;
da = rad_dict_find_attr_id(vendor, id);
if (da) {
attr = malloc(sizeof(*attr));
@@ -257,28 +258,28 @@ void rad_packet_print(struct rad_packet_t *pack, void (*print)(const char *fmt,
print("Access-Reject");
break;
case CODE_ACCOUNTING_REQUEST:
- printf("Accounting-Request");
+ print("Accounting-Request");
break;
case CODE_ACCOUNTING_RESPONSE:
- printf("Accounting-Response");
+ print("Accounting-Response");
break;
case CODE_DISCONNECT_REQUEST:
- printf("Disconnect-Request");
+ print("Disconnect-Request");
break;
case CODE_DISCONNECT_ACK:
- printf("Disconnect-ACK");
+ print("Disconnect-ACK");
break;
case CODE_DISCONNECT_NAK:
- printf("Disconnect-NAK");
+ print("Disconnect-NAK");
break;
case CODE_COA_REQUEST:
- printf("CoA-Request");
+ print("CoA-Request");
break;
case CODE_COA_ACK:
- printf("CoA-ACK");
+ print("CoA-ACK");
break;
case CODE_COA_NAK:
- printf("CoA-NAK");
+ print("CoA-NAK");
break;
default:
print("Unknown (%i)", pack->code);
diff --git a/accel-pptpd/radius/radius.c b/accel-pptpd/radius/radius.c
index 133ed29c..04e41332 100644
--- a/accel-pptpd/radius/radius.c
+++ b/accel-pptpd/radius/radius.c
@@ -11,7 +11,7 @@
#include "pwdb.h"
#include "ipdb.h"
-#include "radius.h"
+#include "radius_p.h"
#define CHAP_MD5 5
#define MSCHAP_V1 0x80
diff --git a/accel-pptpd/radius/radius.h b/accel-pptpd/radius/radius.h
index 8403b339..dca93d4f 100644
--- a/accel-pptpd/radius/radius.h
+++ b/accel-pptpd/radius/radius.h
@@ -2,12 +2,6 @@
#define __RADIUS_H
#include <stdint.h>
-#include <netinet/in.h>
-#include <pthread.h>
-
-#include "triton.h"
-#include "ppp.h"
-#include "ipdb.h"
#define REQ_LENGTH_MAX 4096
@@ -32,23 +26,6 @@
#define CODE_COA_ACK 44
#define CODE_COA_NAK 45
-struct radius_pd_t
-{
- struct list_head entry;
- struct ppp_pd_t pd;
- struct ppp_t *ppp;
- pthread_mutex_t lock;
-
- struct rad_req_t *acct_req;
- struct triton_timer_t acct_interim_timer;
-
- struct rad_packet_t *dm_coa_req;
- struct sockaddr_in dm_coa_addr;
-
- struct ipdb_item_t ipaddr;
- int acct_interim_interval;
-};
-
typedef union
{
int integer;
@@ -106,41 +83,7 @@ struct rad_packet_t
struct list_head attrs;
void *buf;
};
-struct rad_req_t
-{
- struct triton_context_t ctx;
- struct triton_md_handler_t hnd;
- struct triton_timer_t timeout;
- uint8_t RA[16];
- struct rad_packet_t *pack;
- struct rad_packet_t *reply;
- const char *server_name;
- int server_port;
-
- struct radius_pd_t *rpd;
-};
-
-extern int conf_max_try;
-extern int conf_timeout;
-extern int conf_verbose;
-extern char *conf_nas_identifier;
-extern char *conf_nas_ip_address;
-extern char *conf_gw_ip_address;
-extern char *conf_auth_server;
-extern char *conf_auth_secret;
-extern int conf_auth_server_port;
-extern char *conf_acct_server;
-extern char *conf_acct_secret;
-extern int conf_acct_server_port;
-extern char *conf_dm_coa_secret;
-
-int rad_check_nas_pack(struct rad_packet_t *pack);
-struct radius_pd_t *rad_find_session(const char *sessionid, const char *username, int port_id, in_addr_t ipaddr);
-struct radius_pd_t *rad_find_session_pack(struct rad_packet_t *pack);
-
-int rad_dict_load(const char *fname);
-void rad_dict_free(struct rad_dict_t *dict);
struct rad_dict_attr_t *rad_dict_find_attr(const char *name);
struct rad_dict_attr_t *rad_dict_find_attr_id(struct rad_dict_vendor_t *vendor, int type);
struct rad_dict_value_t *rad_dict_find_val_name(struct rad_dict_attr_t *, const char *name);
@@ -149,12 +92,6 @@ struct rad_dict_vendor_t *rad_dict_find_vendor_name(const char *name);
struct rad_dict_vendor_t *rad_dict_find_vendor_id(int id);
struct rad_dict_attr_t *rad_dict_find_vendor_attr(struct rad_dict_vendor_t *vendor, const char *name);
-struct rad_req_t *rad_req_alloc(struct radius_pd_t *rpd, int code, const char *username);
-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 rad_req_wait(struct rad_req_t *, int);
-
struct rad_attr_t *rad_packet_find_attr(struct rad_packet_t *pack, const char *name);
int rad_packet_add_int(struct rad_packet_t *pack, const char *name, int val);
int rad_packet_add_val(struct rad_packet_t *pack, const char *name, const char *val);
@@ -165,23 +102,5 @@ int rad_packet_change_val(struct rad_packet_t *pack, const char *name, const cha
int rad_packet_add_vendor_octets(struct rad_packet_t *pack, const char *vendor_name, const char *name, const uint8_t *val, int len);
struct rad_attr_t *rad_packet_find_vendor_attr(struct rad_packet_t *pack, const char *vendor_name, const char *name);
-struct rad_packet_t *rad_packet_alloc(int code);
-int rad_packet_build(struct rad_packet_t *pack, uint8_t *RA);
-struct rad_packet_t *rad_packet_recv(int fd, struct sockaddr_in *addr);
-void rad_packet_free(struct rad_packet_t *);
-void rad_packet_print(struct rad_packet_t *pack, void (*print)(const char *fmt, ...));
-int rad_packet_send(struct rad_packet_t *pck, int fd, struct sockaddr_in *addr);
-
-struct radius_pd_t *find_pd(struct ppp_t *ppp);
-void rad_proc_attrs(struct rad_req_t *req);
-
-int rad_auth_pap(struct radius_pd_t *rpd, const char *username, va_list args);
-int rad_auth_chap_md5(struct radius_pd_t *rpd, const char *username, va_list args);
-int rad_auth_mschap_v1(struct radius_pd_t *rpd, const char *username, va_list args);
-int rad_auth_mschap_v2(struct radius_pd_t *rpd, const char *username, va_list args);
-
-int rad_acct_start(struct radius_pd_t *rpd);
-void rad_acct_stop(struct radius_pd_t *rpd);
-
#endif
diff --git a/accel-pptpd/radius/radius_p.h b/accel-pptpd/radius/radius_p.h
new file mode 100644
index 00000000..3aa54064
--- /dev/null
+++ b/accel-pptpd/radius/radius_p.h
@@ -0,0 +1,90 @@
+#ifndef __RADIUS_P_H
+#define __RADIUS_P_H
+
+#include <netinet/in.h>
+#include <pthread.h>
+
+#include "triton.h"
+#include "radius.h"
+#include "ppp.h"
+#include "ipdb.h"
+
+struct radius_pd_t
+{
+ struct list_head entry;
+ struct ppp_pd_t pd;
+ struct ppp_t *ppp;
+ pthread_mutex_t lock;
+
+ struct rad_req_t *acct_req;
+ struct triton_timer_t acct_interim_timer;
+
+ struct rad_packet_t *dm_coa_req;
+ struct sockaddr_in dm_coa_addr;
+
+ struct ipdb_item_t ipaddr;
+ int acct_interim_interval;
+};
+
+struct rad_req_t
+{
+ struct triton_context_t ctx;
+ struct triton_md_handler_t hnd;
+ struct triton_timer_t timeout;
+ uint8_t RA[16];
+ struct rad_packet_t *pack;
+ struct rad_packet_t *reply;
+ const char *server_name;
+ int server_port;
+
+ struct radius_pd_t *rpd;
+};
+
+extern int conf_max_try;
+extern int conf_timeout;
+extern int conf_verbose;
+extern char *conf_nas_identifier;
+extern char *conf_nas_ip_address;
+extern char *conf_gw_ip_address;
+extern char *conf_auth_server;
+extern char *conf_auth_secret;
+extern int conf_auth_server_port;
+extern char *conf_acct_server;
+extern char *conf_acct_secret;
+extern int conf_acct_server_port;
+extern char *conf_dm_coa_secret;
+
+int rad_check_nas_pack(struct rad_packet_t *pack);
+struct radius_pd_t *rad_find_session(const char *sessionid, const char *username, int port_id, in_addr_t ipaddr);
+struct radius_pd_t *rad_find_session_pack(struct rad_packet_t *pack);
+
+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);
+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 rad_req_wait(struct rad_req_t *, int);
+
+struct radius_pd_t *find_pd(struct ppp_t *ppp);
+void rad_proc_attrs(struct rad_req_t *req);
+
+int rad_auth_pap(struct radius_pd_t *rpd, const char *username, va_list args);
+int rad_auth_chap_md5(struct radius_pd_t *rpd, const char *username, va_list args);
+int rad_auth_mschap_v1(struct radius_pd_t *rpd, const char *username, va_list args);
+int rad_auth_mschap_v2(struct radius_pd_t *rpd, const char *username, va_list args);
+
+int rad_acct_start(struct radius_pd_t *rpd);
+void rad_acct_stop(struct radius_pd_t *rpd);
+
+struct rad_packet_t *rad_packet_alloc(int code);
+int rad_packet_build(struct rad_packet_t *pack, uint8_t *RA);
+struct rad_packet_t *rad_packet_recv(int fd, struct sockaddr_in *addr);
+void rad_packet_free(struct rad_packet_t *);
+void rad_packet_print(struct rad_packet_t *pack, void (*print)(const char *fmt, ...));
+int rad_packet_send(struct rad_packet_t *pck, int fd, struct sockaddr_in *addr);
+
+
+#endif
+
diff --git a/accel-pptpd/radius/req.c b/accel-pptpd/radius/req.c
index e6f29c53..a9192bb4 100644
--- a/accel-pptpd/radius/req.c
+++ b/accel-pptpd/radius/req.c
@@ -9,7 +9,7 @@
#include <arpa/inet.h>
#include "log.h"
-#include "radius.h"
+#include "radius_p.h"
static int urandom_fd;
diff --git a/accel-pptpd/sigchld.c b/accel-pptpd/sigchld.c
new file mode 100644
index 00000000..478f44c7
--- /dev/null
+++ b/accel-pptpd/sigchld.c
@@ -0,0 +1,134 @@
+#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"
+
+static LIST_HEAD(handlers);
+static int refs;
+static int sleeping = 1;
+static pthread_mutex_t handlers_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t refs_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static struct triton_context_t sigchld_ctx;
+
+static void sigchld_handler(void *arg)
+{
+ struct sigchld_handler_t *h, *h0;
+ pid_t pid;
+ int status;
+
+ while (1) {
+ pid = waitpid(0, &status, WNOHANG);
+ pthread_mutex_lock(&handlers_lock);
+ if (pid == 0 || (pid == -1 && errno == ECHILD)) {
+ sleeping = 1;
+ pthread_mutex_unlock(&handlers_lock);
+ return;
+ } else if (pid < 0) {
+ pthread_mutex_unlock(&handlers_lock);
+ log_error("sigchld: waitpid: %s\n", strerror(errno));
+ return;
+ }
+ 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) {
+ h0->handler(h0, WEXITSTATUS(status));
+ list_del(&h0->entry);
+ h0->pid = 0;
+ pthread_mutex_unlock(&h0->lock);
+ }
+ }
+}
+
+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()
+{
+ sigset_t set;
+
+ pthread_mutex_lock(&refs_lock);
+ if (refs == 0) {
+ sigemptyset(&set);
+ sigaddset(&set, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &set, NULL);
+ }
+ ++refs;
+ pthread_mutex_unlock(&refs_lock);
+}
+
+void __export sigchld_unlock()
+{
+ sigset_t set;
+
+ pthread_mutex_lock(&refs_lock);
+ if (refs == 1) {
+ sigemptyset(&set);
+ sigaddset(&set, SIGCHLD);
+ sigprocmask(SIG_UNBLOCK, &set, NULL);
+ }
+ --refs;
+ pthread_mutex_unlock(&refs_lock);
+
+}
+
+static void sigchld(int num)
+{
+ int s;
+
+ pthread_mutex_lock(&handlers_lock);
+ s = sleeping;
+ sleeping = 0;
+ pthread_mutex_unlock(&handlers_lock);
+
+ if (s)
+ triton_context_call(&sigchld_ctx, sigchld_handler, NULL);
+}
+
+static void __init init(void)
+{
+ struct sigaction sa_sigchld = {
+ .sa_handler = sigchld,
+ .sa_flags = SA_NOCLDSTOP,
+ };
+
+ if (sigaction(SIGCHLD, &sa_sigchld, NULL)) {
+ fprintf(stderr, "sigchld: sigaction: %s\n", strerror(errno));
+ return;
+ }
+
+ triton_context_register(&sigchld_ctx, NULL);
+}
diff --git a/accel-pptpd/sigchld.h b/accel-pptpd/sigchld.h
new file mode 100644
index 00000000..27d1adf4
--- /dev/null
+++ b/accel-pptpd/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
+
diff --git a/accel-pptpd/triton/triton.c b/accel-pptpd/triton/triton.c
index b0aedbc7..9b9fd753 100644
--- a/accel-pptpd/triton/triton.c
+++ b/accel-pptpd/triton/triton.c
@@ -35,6 +35,17 @@ static void* triton_thread(struct _triton_thread_t *thread)
sigset_t set;
int sig;
+ sigfillset(&set);
+ pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+ sigdelset(&set, SIGUSR1);
+ sigdelset(&set, SIGQUIT);
+ sigdelset(&set, SIGSEGV);
+ sigdelset(&set, SIGFPE);
+ sigdelset(&set, SIGILL);
+ sigdelset(&set, SIGBUS);
+ pthread_sigmask(SIG_UNBLOCK, &set, NULL);
+
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGQUIT);
diff --git a/accel-pptpd/triton/triton.h b/accel-pptpd/triton/triton.h
index b1df4971..8510a512 100644
--- a/accel-pptpd/triton/triton.h
+++ b/accel-pptpd/triton/triton.h
@@ -29,6 +29,13 @@ struct triton_timer_t
void (*expire)(struct triton_timer_t *);
};
+struct triton_sigchld_handler_t
+{
+ void *tpd;
+ int pid;
+ void (*handler)(struct triton_sigchld_handler_t *h, int status);
+};
+
struct conf_option_t
{
struct list_head entry;
diff --git a/accel-pptpd/utils.c b/accel-pptpd/utils.c
new file mode 100644
index 00000000..fd59b005
--- /dev/null
+++ b/accel-pptpd/utils.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+#include "triton.h"
+#include "utils.h"
+
+
+void __export u_inet_ntoa(in_addr_t addr, char *str)
+{
+ sprintf(str, "%i.%i.%i.%i", addr & 0xff, (addr >> 8) & 0xff, (addr >> 16) & 0xff, (addr >> 24) & 0xff);
+}
diff --git a/accel-pptpd/utils.h b/accel-pptpd/utils.h
new file mode 100644
index 00000000..27d4d058
--- /dev/null
+++ b/accel-pptpd/utils.h
@@ -0,0 +1,8 @@
+#ifndef __UTILS_H
+#define __UTILS_H
+
+#include <netinet/in.h>
+
+void u_inet_ntoa(in_addr_t, char *str);
+
+#endif