--- a/pppd/chap-new.c +++ b/pppd/chap-new.c @@ -37,6 +37,8 @@ #include "chap-new.h" #include "chap-md5.h" +#include "syncppp.h" + #ifdef CHAPMS #include "chap_ms.h" #define MDTYPE_ALL (MDTYPE_MICROSOFT_V2 | MDTYPE_MICROSOFT | MDTYPE_MD5) @@ -523,6 +525,18 @@ chap_respond(struct chap_client_state *cs, int id, p[2] = len >> 8; p[3] = len; + if (npppd > 1) { + if (syncppp(npppd) < 0) { + error("syncppp sync fail"); + sem_unlink(SEM_COUNT_NAME); + sem_unlink(SEM_BLOCK_NAME); + } else { + info("syncppp sync succeeded"); + } + } else { + info("syncppp not active"); + } + output(0, response, PPP_HDRLEN + len); } --- a/pppd/Makefile.linux +++ b/pppd/Makefile.linux @@ -17,16 +17,16 @@ TARGETS = pppd PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap-new.c md5.c ccp.c \ ecp.c ipxcp.c auth.c options.c sys-linux.c md4.c chap_ms.c \ - demand.c utils.c tty.c eap.c chap-md5.c session.c + demand.c utils.c tty.c eap.c chap-md5.c session.c syncppp.c HEADERS = ccp.h session.h chap-new.h ecp.h fsm.h ipcp.h \ ipxcp.h lcp.h magic.h md5.h patchlevel.h pathnames.h pppd.h \ - upap.h eap.h + upap.h eap.h syncppp.h MANPAGES = pppd.8 PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap-new.o md5.o ccp.o \ ecp.o auth.o options.o demand.o utils.o sys-linux.o ipxcp.o tty.o \ - eap.o chap-md5.o session.o + eap.o chap-md5.o session.o syncppp.o # # include dependencies if present @@ -34,7 +34,7 @@ ifeq (.depend,$(wildcard .depend)) include .depend endif -LIBS = -lrt +LIBS = -lpthread # Uncomment the next line to include support for Microsoft's # MS-CHAP authentication protocol. Also, edit plugins/radius/Makefile.linux. --- a/pppd/options.c +++ b/pppd/options.c @@ -127,6 +127,7 @@ bool dump_options; /* print out option values */ bool dryrun; /* print out option values and exit */ char *domain; /* domain name set by domain option */ int child_wait = 5; /* # seconds to wait for children at exit */ +int npppd = 0; /* synchronize between multiple pppd */ struct userenv *userenv_list; /* user environment variables */ int dfl_route_metric = -1; /* metric of the default route to set over the PPP link */ @@ -323,6 +324,9 @@ option_t general_options[] = { "Unset user environment variable", OPT_A2PRINTER | OPT_NOPRINT, (void *)user_unsetprint }, + { "syncppp", o_int, &npppd, + "sync among multiple pppd when sending chap/pap respond", OPT_PRIO }, + { "defaultroute-metric", o_int, &dfl_route_metric, "Metric to use for the default route (Linux only; -1 for default behavior)", OPT_PRIV|OPT_LLIMIT|OPT_INITONLY, NULL, 0, -1 }, --- a/pppd/pppd.h +++ b/pppd/pppd.h @@ -335,6 +335,7 @@ extern char *bundle_name; /* bundle name for multilink */ extern bool dump_options; /* print out option values */ extern bool dryrun; /* check everything, print options, exit */ extern int child_wait; /* # seconds to wait for children at end */ +extern int npppd; /* synchronize between multiple pppd */ #ifdef USE_EAPTLS extern char *crl_dir; --- /dev/null +++ b/pppd/syncppp.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include +#include +#include "pppd.h" +#include "syncppp.h" + +int syncppp(int nproc) +{ + int flags; + int value; + sem_t *block; + sem_t *count; + struct timespec ts; + + if (nproc <= 1) { + error("syncppp: number of pppd should be larger than 1"); + return -1; + } + + if (clock_gettime(CLOCK_REALTIME, &ts) == -1) { + error("clock_gettime error"); + return -1; + } + ts.tv_sec += SYNCPPP_TIMEOUT; + + + flags = O_RDWR | O_CREAT; + block = sem_open(SEM_BLOCK_NAME, flags, 0644, 0); + count = sem_open(SEM_COUNT_NAME, flags, 0644, 0); + if (block == SEM_FAILED || count == SEM_FAILED) { + error("syncppp: sem_open failed"); + return -1; + } + + if (sem_post(count) < 0) { + error("syncppp: sem_post failed"); + return -1; + } + if (sem_getvalue(count, &value) < 0) { + error("syncppp: sem_getvalue failed"); + return -1; + } + info("%d pppd have arrived, waiting for the left %d", value, nproc-value); + if (value >= nproc) { + while (nproc-1 > 0) { + if (sem_post(block) < 0) { + error("syncppp: sem_post failed"); + return -1; + } + nproc--; + } + } else { + if (sem_timedwait(block, &ts) < 0) { + if (errno == ETIMEDOUT) { + error("syncppp: sem_timewait time out"); + } else { + error("syncppp: sem_timewait error"); + } + return -1; + } + + } + + sem_close(count); + sem_close(block); + + sem_unlink(SEM_COUNT_NAME); + sem_unlink(SEM_BLOCK_NAME); + + return 0; +} + --- /dev/null +++ b/pppd/syncppp.h @@ -0,0 +1,3 @@ +#define SEM_BLOCK_NAME "block" +#define SEM_COUNT_NAME "count" +#define SYNCPPP_TIMEOUT 5 --- a/pppd/upap.c +++ b/pppd/upap.c @@ -50,6 +50,7 @@ #include "pppd.h" #include "upap.h" +#include "syncppp.h" static bool hide_password = 1; @@ -540,6 +541,18 @@ upap_sauthreq(upap_state *u) PUTCHAR(u->us_passwdlen, outp); BCOPY(u->us_passwd, outp, u->us_passwdlen); + if (npppd > 1) { + if (syncppp(npppd) < 0) { + error("syncppp sync fail"); + sem_unlink(SEM_COUNT_NAME); + sem_unlink(SEM_BLOCK_NAME); + } else { + info("syncppp sync succeeded"); + } + } else { + info("syncppp not active"); + } + output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN); TIMEOUT(upap_timeout, u, u->us_timeouttime);