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

Reply via email to