Hi, On Mon, Dec 27, 2010 at 11:24:20PM +0100, Sebastian Benoit wrote: > 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. >
I remember you were explaining the problem at EuroBSDCon ;-). And now you have a diff - cool, thanks! > Here is a patch that adds an "exec" option to the router section like this: > I would prefer to call it "run" (it is a full word and similar to the same keyword in ifstated.conf). > 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? > Yes, it makes sense. But we can give it a fairly high default value. I like your diff and what it does. Please give me some time to look at it in detail, maybe not before next year... reyk > /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],