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],