Hi, i am using relayd in "router" mode for a cable-modem link that sometimes does not work.
I need to run a programm to load/unload pf-rules and to restart a proxy with a different config whenever this happens. Here is a patch that adds an "exec" option to the router section like this: router "uplinks" { route 0.0.0.0/0 forward to <gateways> check icmp exec "/usr/local/sbin/relayd_test" timeout 10 } The code that does the exec is taken from check_script.c. One thing i'm not quite sure about: is the timeout useful or should relayd just start the program and forget about it? /Benno Index: parse.y =================================================================== RCS file: /cvs/src/usr.sbin/relayd/parse.y,v retrieving revision 1.149 diff -u -r1.149 parse.y --- parse.y 26 Oct 2010 15:04:37 -0000 1.149 +++ parse.y 2 Dec 2010 20:53:54 -0000 @@ -141,7 +141,7 @@ %} %token ALL APPEND BACKLOG BACKUP BUFFER CA CACHE CHANGE CHECK -%token CIPHERS CODE COOKIE DEMOTE DIGEST DISABLE ERROR EXPECT +%token CIPHERS CODE COOKIE DEMOTE DIGEST DISABLE ERROR EXEC EXPECT %token EXTERNAL FILENAME FILTER FORWARD FROM HASH HEADER HOST ICMP %token INCLUDE INET INET6 INTERFACE INTERVAL IP LABEL LISTEN %token LOADBALANCE LOG LOOKUP MARK MARKED MODE NAT NO @@ -1523,6 +1523,18 @@ } free($2); } + | EXEC STRING TIMEOUT timeout { + bcopy(&$4, &table->conf.timeout, + sizeof(struct timeval)); + if (strlcpy(router->rt_conf.exec, $2, + sizeof(router->rt_conf.exec)) >= + sizeof(router->rt_conf.exec)) { + yyerror("exec command truncated"); + free($2); + YYERROR; + } + free($2); + } | DISABLE { rlay->rl_conf.flags |= F_DISABLE; } | include ; @@ -1719,6 +1731,7 @@ { "digest", DIGEST }, { "disable", DISABLE }, { "error", ERROR }, + { "exec", EXEC }, { "expect", EXPECT }, { "external", EXTERNAL }, { "file", FILENAME }, Index: pfe_route.c =================================================================== RCS file: /cvs/src/usr.sbin/relayd/pfe_route.c,v retrieving revision 1.1 diff -u -r1.1 pfe_route.c --- pfe_route.c 13 Aug 2009 13:51:21 -0000 1.1 +++ pfe_route.c 2 Dec 2010 20:53:54 -0000 @@ -32,6 +32,10 @@ #include <string.h> #include <errno.h> +#include <sys/wait.h> +#include <signal.h> +#include <pwd.h> + #include <openssl/ssl.h> #include "relayd.h" @@ -56,6 +60,9 @@ } rm_u; }; +pid_t route_exec_child = -1; +void pfe_route_exec_sig_alarm(int); + void init_routes(struct relayd *env) { @@ -237,4 +244,115 @@ errno, strerror(errno)); return (-1); +} + +/* code from check_script.c */ + +void +pfe_route_exec_sig_alarm(int sig) +{ + int save_errno = errno; + + if (route_exec_child != -1) + kill(route_exec_child, SIGKILL); + errno = save_errno; +} + +int +pfe_route_exec(struct relayd *env, struct ctl_netroute *crt) +{ + struct netroute *nr; + + int status = 0, ret = 0; + sig_t save_quit, save_int, save_chld; + struct itimerval it; + struct timeval *tv; + const char *file, *arg_host, *arg_action; + struct host *host; + struct passwd *pw; + + if ((nr = route_find(env, crt->id)) == NULL || + (host = host_find(env, crt->hostid)) == NULL) { + log_debug("pfe_route: invalid host or route id"); + return (-1); + } + + arg_host = host->conf.name; + arg_action = HOST_ISUP(crt->up) ? "added" : "deleted"; + file = nr->nr_router->rt_conf.exec; + tv = &nr->nr_router->rt_conf.exec_timeout; + + log_info("pfe_route_exec: %s %s %s", + file, + arg_host, + arg_action); + + save_quit = signal(SIGQUIT, SIG_IGN); + save_int = signal(SIGINT, SIG_IGN); + save_chld = signal(SIGCHLD, SIG_DFL); + + switch (route_exec_child = fork()) { + case -1: + ret = -1; + goto done; + case 0: + signal(SIGQUIT, SIG_DFL); + signal(SIGINT, SIG_DFL); + signal(SIGCHLD, SIG_DFL); + + if ((pw = getpwnam(RELAYD_USER)) == NULL) + fatal("pfe_route_exec: getpwnam"); + if (chdir("/") == -1) + fatal("pfe_route_exec: chdir(\"/\")"); + if (setgroups(1, &pw->pw_gid) || + setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || + setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) + fatal("pfe_route_exec: can't drop privileges"); + + /* + * close fds before executing an external program, to + * prevent access to internal fds, eg. IMSG connections + * of internal processes. + */ + closefrom(STDERR_FILENO + 1); + + execlp(file, file, arg_host, arg_action, (char *)NULL); + _exit(0); + break; + default: + /* Kill the process after a timeout */ + signal(SIGALRM, pfe_route_exec_sig_alarm); + bzero(&it, sizeof(it)); + bcopy(tv, &it.it_value, sizeof(it.it_value)); + setitimer(ITIMER_REAL, &it, NULL); + + waitpid(route_exec_child, &status, 0); + break; + } + + switch (ret) { + case -1: + ret = -1; + break; + default: + if (WIFEXITED(status)) + ret = WEXITSTATUS(status); + else + ret = -1; + } + + done: + /* Disable the process timeout timer */ + bzero(&it, sizeof(it)); + setitimer(ITIMER_REAL, &it, NULL); + route_exec_child = -1; + + signal(SIGQUIT, save_quit); + signal(SIGINT, save_int); + signal(SIGCHLD, save_chld); + signal(SIGALRM, SIG_DFL); + + log_info("pfe_route_exec ret=%i",ret); + + return (ret); } Index: relayd.c =================================================================== RCS file: /cvs/src/usr.sbin/relayd/relayd.c,v retrieving revision 1.98 diff -u -r1.98 relayd.c --- relayd.c 2 Sep 2010 14:03:22 -0000 1.98 +++ relayd.c 2 Dec 2010 20:54:27 -0000 @@ -664,6 +664,7 @@ "invalid size of rtmsg request"); memcpy(&crt, imsg.data, sizeof(crt)); pfe_route(env, &crt); + pfe_route_exec(env, &crt); break; case IMSG_CTL_RELOAD: /* Index: relayd.conf.5 =================================================================== RCS file: /cvs/src/usr.sbin/relayd/relayd.conf.5,v retrieving revision 1.116 diff -u -r1.116 relayd.conf.5 --- relayd.conf.5 26 Oct 2010 15:26:58 -0000 1.116 +++ relayd.conf.5 2 Dec 2010 20:54:29 -0000 @@ -1113,7 +1113,18 @@ .It Ic rtlabel Ar label Add the routes with the specified .Ar label -to the kernel routing table. +to the kernel routing table XXXX. +.It Xo +.Ic exec +.Ar path +.Ic timeout Ar number +.Xc +The program +.Ar path +will be run (with the two arguments gateway and "added" or "deleted") +when a route is added or deleted. The program is killed after +.Ar number +seconds. .El .Sh FILES .Bl -tag -width "/etc/ssl/private/address.keyXX" -compact Index: relayd.h =================================================================== RCS file: /cvs/src/usr.sbin/relayd/relayd.h,v retrieving revision 1.138 diff -u -r1.138 relayd.h --- relayd.h 26 Oct 2010 15:04:37 -0000 1.138 +++ relayd.h 2 Dec 2010 20:54:31 -0000 @@ -613,6 +613,8 @@ objid_t gwtable; in_port_t gwport; int rtable; + char exec[MAXPATHLEN]; + struct timeval exec_timeout; }; struct router { @@ -828,6 +830,7 @@ void init_routes(struct relayd *); void sync_routes(struct relayd *, struct router *); int pfe_route(struct relayd *, struct ctl_netroute *); +int pfe_route_exec(struct relayd *, struct ctl_netroute *); /* hce.c */ pid_t hce(struct relayd *, int [2], int [2], int [RELAY_MAXPROC][2],