diff --git a/one.cpp b/one.cpp index 46a23b1ee..8264a98a1 100644 --- a/one.cpp +++ b/one.cpp @@ -1996,6 +1996,7 @@ static void printHelp(const char *cn,FILE *out) #ifdef __UNIX_LIKE__ fprintf(out," -d - Fork and run as daemon (Unix-ish OSes)" ZT_EOL_S); + fprintf(out," -s - path to script to execute on network events" ZT_EOL_S); #endif // __UNIX_LIKE__ #ifdef __WINDOWS__ @@ -2012,13 +2013,13 @@ static void printHelp(const char *cn,FILE *out) class _OneServiceRunner { public: - _OneServiceRunner(const char *pn,const std::string &hd,unsigned int p) : progname(pn),returnValue(0),port(p),homeDir(hd) {} + _OneServiceRunner(const char *pn,const std::string &hd,unsigned int p, std::string &sp) : progname(pn),returnValue(0),port(p),homeDir(hd),scriptPath(sp) {} void threadMain() throw() { try { for(;;) { - zt1Service = OneService::newInstance(homeDir.c_str(),port); + zt1Service = OneService::newInstance(homeDir.c_str(),port,scriptPath.c_str()); switch(zt1Service->run()) { case OneService::ONE_STILL_RUNNING: // shouldn't happen, run() won't return until done case OneService::ONE_NORMAL_TERMINATION: @@ -2053,6 +2054,7 @@ public: unsigned int returnValue; unsigned int port; const std::string &homeDir; + const std::string &scriptPath; }; #ifdef __WINDOWS__ @@ -2082,6 +2084,7 @@ int main(int argc,char **argv) signal(SIGTERM,&_sighandlerQuit); signal(SIGQUIT,&_sighandlerQuit); signal(SIGINT,&_sighandlerQuit); + signal(SIGCHLD, SIG_IGN); /* Ensure that there are no inherited file descriptors open from a previous * incarnation. This is a hack to ensure that GitHub issue #61 or variants @@ -2115,7 +2118,7 @@ int main(int argc,char **argv) if ((strstr(argv[0],"zerotier-cli"))||(strstr(argv[0],"ZEROTIER-CLI"))) return cli(argc,argv); - std::string homeDir; + std::string homeDir, scriptPath; unsigned int port = ZT_DEFAULT_PORT; bool skipRootCheck = false; @@ -2135,6 +2138,11 @@ int main(int argc,char **argv) case 'd': // Run in background as daemon runAsDaemon = true; break; + case 's': // script to run on network events + if (argv[i][2]) { + scriptPath = argv[i] + 2; + } else printHelp(argv[0],stdout); + break; #endif // __UNIX_LIKE__ case 'U': @@ -2306,7 +2314,7 @@ int main(int argc,char **argv) } #endif // __UNIX_LIKE__ - _OneServiceRunner thr(argv[0],homeDir,port); + _OneServiceRunner thr(argv[0],homeDir,port,scriptPath); thr.threadMain(); //Thread::join(Thread::start(&thr)); diff --git a/osdep/OSUtils.cpp b/osdep/OSUtils.cpp index 36814523a..56ea235fc 100644 --- a/osdep/OSUtils.cpp +++ b/osdep/OSUtils.cpp @@ -11,34 +11,34 @@ */ /****/ -#include -#include -#include -#include -#include -#include - #include "../node/Constants.hpp" #include "../node/Utils.hpp" +#include +#include +#include +#include +#include + #ifdef __UNIX_LIKE__ -#include +#include #include #include -#include +#include #include #include +#include #include -#include -#include +#include +#include #endif #ifdef __WINDOWS__ -#include -#include -#include -#include #include +#include +#include +#include +#include #endif #include "OSUtils.hpp" @@ -551,6 +551,53 @@ std::string OSUtils::jsonBinFromHex(const nlohmann::json &jv) return std::string(); } +void OSUtils::_hookCmd(const char* scriptPath, const uint64_t nwid, const char *homePath, ZT_VirtualNetworkConfigOperation op) +{ + if (! scriptPath || ! strlen(scriptPath) || nwid == 0) { +#ifdef ZT_TRACE + fprintf(stderr, "no script path specified\n"); +#endif + return; + } + long p = (long)fork(); + + if (p > 0) { +#ifdef ZT_TRACE + fprintf(stderr, "Running network event hook script (%s)\n", scriptPath); +#endif + //int exitcode = -1; + //::waitpid(p, &exitcode, 0); + } + else if (p == 0) { + ::close(STDOUT_FILENO); + ::close(STDERR_FILENO); + char cmdBuf[128] = { 0 }; + OSUtils::ztsnprintf(cmdBuf, sizeof(cmdBuf), "%s", scriptPath); + char nwidStr[17] = { 0 }; + OSUtils::ztsnprintf(nwidStr, sizeof(nwidStr), "%.16llx", nwid); + std::string cmd; + switch (op) { + case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP: + cmd = std::string(cmdBuf) + " network_up " + std::string(nwidStr) + " " + std::string(homePath) + ""; + //::execl("/bin/sh", "sh", cmdBuf, "network_up", nwidStr, homePath, "&", (const char*)0); + break; + case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE: + cmd = std::string(cmdBuf) + " network_update " + std::string(nwidStr) + " " + std::string(homePath) + ""; + //::execl("/bin/sh", "sh", cmdBuf, "network_update", nwidStr, homePath, "&", (const char*)0); + break; + case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN: // Same as _DESTROY + cmd = std::string(cmdBuf) + " network_down " + std::string(nwidStr) + " " + std::string(homePath) + ""; + //::execl("/bin/sh", "sh", cmdBuf, "network_down", nwidStr, homePath, "&", (const char*)0); + break; + default: + break; + } + // Using system instead of execl, because execl blocks connections through cli + if (!cmd.empty()) ::system(cmd.c_str()); + ::_exit(-1); + } +} + #endif // OMIT_JSON_SUPPORT // Used to convert HTTP header names to ASCII lower case diff --git a/osdep/OSUtils.hpp b/osdep/OSUtils.hpp index 021b3876f..ef0e05a11 100644 --- a/osdep/OSUtils.hpp +++ b/osdep/OSUtils.hpp @@ -269,6 +269,16 @@ public: */ static std::string platformDefaultHomePath(); + /** + * Executes a system script specified by user + * + * @param scriptPath The full path to the script that should be run on each network event + * @param nwid The Network ID of the network in question + * @param homePath full patch to homepath containing connections settings and data + * @param op The operation performed up on the network + */ + static void _hookCmd(const char *scriptPath, const uint64_t nwid, const char *homePath, ZT_VirtualNetworkConfigOperation op); + #ifndef OMIT_JSON_SUPPORT static nlohmann::json jsonParse(const std::string &buf); static std::string jsonDump(const nlohmann::json &j,int indentation = 1); diff --git a/service/OneService.cpp b/service/OneService.cpp index 292f47e97..c4c089a99 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -704,8 +704,11 @@ public: // begin member variables -------------------------------------------------- const std::string _homePath; + std::string _authToken; std::string _controllerDbPath; + std::string _eventHookScriptPath; + const std::string _networksPath; const std::string _moonsPath; @@ -804,9 +807,10 @@ public: // end member variables ---------------------------------------------------- - OneServiceImpl(const char *hp,unsigned int port) : + OneServiceImpl(const char *hp,unsigned int port,const char *sp) : _homePath((hp) ? hp : ".") ,_controllerDbPath(_homePath + ZT_PATH_SEPARATOR_S "controller.d") + ,_eventHookScriptPath(sp) ,_networksPath(_homePath + ZT_PATH_SEPARATOR_S "networks.d") ,_moonsPath(_homePath + ZT_PATH_SEPARATOR_S "moons.d") ,_controller((EmbeddedNetworkController *)0) @@ -2160,6 +2164,10 @@ public: } #endif + if (_eventHookScriptPath.empty()) { + _eventHookScriptPath = std::string(OSUtils::jsonString(settings["eventHookScriptPath"],"")); + } + json &ignoreIfs = settings["interfacePrefixBlacklist"]; if (ignoreIfs.is_array()) { for(unsigned long i=0;i