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

Reply via email to