diff options
author | 2007-05-29 17:12:04 +0000 | |
---|---|---|
committer | 2007-05-29 17:12:04 +0000 | |
commit | 4156152f0fa963fdd68c44681e8679032e5e075a (patch) | |
tree | c230749839cbad5806058abf4f0a479afb546490 | |
parent | Fix bus_dmamap_sync size argument. (diff) | |
download | wireguard-openbsd-4156152f0fa963fdd68c44681e8679032e5e075a.tar.xz wireguard-openbsd-4156152f0fa963fdd68c44681e8679032e5e075a.zip |
add a new check method which allows to run external scripts/programs
for custom evaluations.
pyr agrees to put it in now but to do some improvements of the timeout
handling later.
-rw-r--r-- | usr.sbin/hoststated/Makefile | 6 | ||||
-rw-r--r-- | usr.sbin/hoststated/check_script.c | 166 | ||||
-rw-r--r-- | usr.sbin/hoststated/hce.c | 47 | ||||
-rw-r--r-- | usr.sbin/hoststated/hoststated.c | 21 | ||||
-rw-r--r-- | usr.sbin/hoststated/hoststated.conf.5 | 17 | ||||
-rw-r--r-- | usr.sbin/hoststated/hoststated.h | 18 | ||||
-rw-r--r-- | usr.sbin/hoststated/log.c | 4 | ||||
-rw-r--r-- | usr.sbin/hoststated/parse.y | 16 | ||||
-rw-r--r-- | usr.sbin/relayd/Makefile | 6 | ||||
-rw-r--r-- | usr.sbin/relayd/check_script.c | 166 | ||||
-rw-r--r-- | usr.sbin/relayd/hce.c | 47 | ||||
-rw-r--r-- | usr.sbin/relayd/log.c | 4 | ||||
-rw-r--r-- | usr.sbin/relayd/parse.y | 16 | ||||
-rw-r--r-- | usr.sbin/relayd/relayd.c | 21 | ||||
-rw-r--r-- | usr.sbin/relayd/relayd.conf.5 | 17 | ||||
-rw-r--r-- | usr.sbin/relayd/relayd.h | 18 |
16 files changed, 532 insertions, 58 deletions
diff --git a/usr.sbin/hoststated/Makefile b/usr.sbin/hoststated/Makefile index f59567497ac..83c2467d45f 100644 --- a/usr.sbin/hoststated/Makefile +++ b/usr.sbin/hoststated/Makefile @@ -1,9 +1,9 @@ -# $OpenBSD: Makefile,v 1.11 2007/02/26 19:35:43 reyk Exp $ +# $OpenBSD: Makefile,v 1.12 2007/05/29 17:12:04 reyk Exp $ PROG= hoststated SRCS= parse.y log.c control.c buffer.c imsg.c hoststated.c \ - ssl.c pfe.c pfe_filter.c hce.c \ - check_icmp.c check_tcp.c relay.c carp.c + ssl.c pfe.c pfe_filter.c hce.c relay.c carp.c \ + check_icmp.c check_tcp.c check_script.c MAN= hoststated.8 hoststated.conf.5 LDADD= -levent -lssl -lcrypto diff --git a/usr.sbin/hoststated/check_script.c b/usr.sbin/hoststated/check_script.c new file mode 100644 index 00000000000..d347d882846 --- /dev/null +++ b/usr.sbin/hoststated/check_script.c @@ -0,0 +1,166 @@ +/* $OpenBSD: check_script.c,v 1.1 2007/05/29 17:12:04 reyk Exp $ */ + +/* + * Copyright (c) 2007 Reyk Floeter <reyk@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/socket.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include <net/if.h> + +#include <limits.h> +#include <event.h> +#include <errno.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <signal.h> +#include <pwd.h> +#include <err.h> + +#include <openssl/ssl.h> + +#include "hoststated.h" + +void script_sig_alarm(int); + +extern struct imsgbuf *ibuf_main; +pid_t child = -1; + +void +check_script(struct host *host) +{ + struct ctl_script scr; + + host->last_up = host->up; + host->flags &= ~(F_CHECK_SENT|F_CHECK_DONE); + + scr.host = host->conf.id; + imsg_compose(ibuf_main, IMSG_SCRIPT, 0, 0, &scr, sizeof(scr)); +} + +void +script_done(struct hoststated *env, struct ctl_script *scr) +{ + struct host *host; + + if ((host = host_find(env, scr->host)) == NULL) + fatalx("hce_dispatch_parent: invalid host id"); + + if (scr->retval < 0) + host->up = HOST_UNKNOWN; + else if (scr->retval == 0) + host->up = HOST_DOWN; + else + host->up = HOST_UP; + host->flags |= F_CHECK_DONE; + + hce_notify_done(host, host->up == HOST_UP ? + "script: done" : "script: failed"); +} + +void +script_sig_alarm(int sig) +{ + if (child != -1) + kill(child, SIGKILL); +} + +int +script_exec(struct hoststated *env, struct ctl_script *scr) +{ + int status = 0, ret = 0; + sig_t save_quit, save_int, save_chld; + struct itimerval it; + struct timeval *tv; + const char *file, *arg; + struct host *host; + struct table *table; + struct passwd *pw; + + if ((host = host_find(env, scr->host)) == NULL) + fatalx("script_exec: invalid host id"); + if ((table = table_find(env, host->conf.tableid)) == NULL) + fatalx("script_exec: invalid table id"); + + arg = host->conf.name; + file = table->conf.path; + tv = &table->conf.timeout; + + save_quit = signal(SIGQUIT, SIG_IGN); + save_int = signal(SIGINT, SIG_IGN); + save_chld = signal(SIGCHLD, SIG_DFL); + + switch (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(HOSTSTATED_USER)) == NULL) + fatal("script_exec: getpwnam"); + if (chdir("/") == -1) + fatal("script_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("script_exec: can't drop privileges"); + + execlp(file, file, arg, (char *)NULL); + _exit(0); + break; + default: + /* Kill the process after a timeout */ + signal(SIGALRM, script_sig_alarm); + bzero(&it, sizeof(it)); + bcopy(tv, &it.it_value, sizeof(it.it_value)); + setitimer(ITIMER_REAL, &it, NULL); + + waitpid(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); + child = -1; + + signal(SIGQUIT, save_quit); + signal(SIGINT, save_int); + signal(SIGCHLD, save_chld); + signal(SIGALRM, SIG_DFL); + + return (ret); +} diff --git a/usr.sbin/hoststated/hce.c b/usr.sbin/hoststated/hce.c index 0110dfe7d22..139ef678b05 100644 --- a/usr.sbin/hoststated/hce.c +++ b/usr.sbin/hoststated/hce.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hce.c,v 1.21 2007/05/28 22:11:33 pyr Exp $ */ +/* $OpenBSD: hce.c,v 1.22 2007/05/29 17:12:04 reyk Exp $ */ /* * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org> @@ -46,7 +46,7 @@ void hce_dispatch_imsg(int, short, void *); void hce_dispatch_parent(int, short, void *); void hce_launch_checks(int, short, void *); -static struct hoststated *env = NULL; +static struct hoststated *env = NULL; struct imsgbuf *ibuf_pfe; struct imsgbuf *ibuf_main; @@ -194,19 +194,24 @@ hce_launch_checks(int fd, short event, void *arg) TAILQ_FOREACH(host, &table->hosts, entry) { if (host->flags & F_DISABLE) continue; - if (table->conf.check == CHECK_ICMP) { + switch (table->conf.check) { + case CHECK_ICMP: schedule_icmp(env, host); - continue; + break; + case CHECK_SCRIPT: + check_script(host); + break; + default: + /* Any other TCP-style checks */ + bzero(&host->cte, sizeof(host->cte)); + host->last_up = host->up; + host->cte.host = host; + host->cte.table = table; + bcopy(&tv, &host->cte.tv_start, + sizeof(host->cte.tv_start)); + check_tcp(&host->cte); + break; } - - /* Any other TCP-style checks */ - bzero(&host->cte, sizeof(host->cte)); - host->last_up = host->up; - host->cte.host = host; - host->cte.table = table; - bcopy(&tv, &host->cte.tv_start, - sizeof(host->cte.tv_start)); - check_tcp(&host->cte); } } check_icmp(env, &tv); @@ -359,9 +364,10 @@ hce_dispatch_imsg(int fd, short event, void *ptr) void hce_dispatch_parent(int fd, short event, void * ptr) { - struct imsgbuf *ibuf; - struct imsg imsg; - ssize_t n; + struct imsgbuf *ibuf; + struct imsg imsg; + struct ctl_script scr; + ssize_t n; ibuf = ptr; switch (event) { @@ -387,6 +393,14 @@ hce_dispatch_parent(int fd, short event, void * ptr) break; switch (imsg.hdr.type) { + case IMSG_SCRIPT: + if (imsg.hdr.len - IMSG_HEADER_SIZE != + sizeof(scr)) + fatalx("hce_dispatch_parent: " + "invalid size of script request"); + bcopy(imsg.data, &scr, sizeof(scr)); + script_done(env, &scr); + break; default: log_debug("hce_dispatch_parent: unexpected imsg %d", imsg.hdr.type); @@ -394,4 +408,5 @@ hce_dispatch_parent(int fd, short event, void * ptr) } imsg_free(&imsg); } + imsg_event_add(ibuf); } diff --git a/usr.sbin/hoststated/hoststated.c b/usr.sbin/hoststated/hoststated.c index f48ba94e18c..ad04abc7f59 100644 --- a/usr.sbin/hoststated/hoststated.c +++ b/usr.sbin/hoststated/hoststated.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hoststated.c,v 1.26 2007/05/29 00:58:06 pyr Exp $ */ +/* $OpenBSD: hoststated.c,v 1.27 2007/05/29 17:12:04 reyk Exp $ */ /* * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org> @@ -54,6 +54,8 @@ int pipe_pfe2hce[2]; int pipe_parent2relay[RELAY_MAXPROC][2]; int pipe_pfe2relay[RELAY_MAXPROC][2]; +struct hoststated *hoststated_env; + struct imsgbuf *ibuf_pfe; struct imsgbuf *ibuf_hce; struct imsgbuf *ibuf_relay; @@ -68,8 +70,6 @@ main_sig_handler(int sig, short event, void *arg) struct hoststated *env = arg; int die = 0; - log_debug("signal %d", sig); - switch (sig) { case SIGTERM: case SIGINT: @@ -154,6 +154,7 @@ main(int argc, char *argv[]) if ((env = parse_config(conffile, opts)) == NULL) exit(1); + hoststated_env = env; if (env->opts & HOSTSTATED_OPT_NOACTION) { fprintf(stderr, "configuration OK\n"); @@ -485,7 +486,10 @@ main_dispatch_hce(int fd, short event, void * ptr) struct imsgbuf *ibuf; struct imsg imsg; ssize_t n; + struct ctl_script scr; + struct hoststated *env; + env = hoststated_env; ibuf = ptr; switch (event) { case EV_READ: @@ -510,6 +514,16 @@ main_dispatch_hce(int fd, short event, void * ptr) break; switch (imsg.hdr.type) { + case IMSG_SCRIPT: + if (imsg.hdr.len - IMSG_HEADER_SIZE != + sizeof(scr)) + fatalx("main_dispatch_hce: " + "invalid size of script request"); + bcopy(imsg.data, &scr, sizeof(scr)); + scr.retval = script_exec(env, &scr); + imsg_compose(ibuf_hce, IMSG_SCRIPT, + 0, 0, &scr, sizeof(scr)); + break; default: log_debug("main_dispatch_hce: unexpected imsg %d", imsg.hdr.type); @@ -517,6 +531,7 @@ main_dispatch_hce(int fd, short event, void * ptr) } imsg_free(&imsg); } + imsg_event_add(ibuf); } void diff --git a/usr.sbin/hoststated/hoststated.conf.5 b/usr.sbin/hoststated/hoststated.conf.5 index 99330d9546a..d197c824984 100644 --- a/usr.sbin/hoststated/hoststated.conf.5 +++ b/usr.sbin/hoststated/hoststated.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: hoststated.conf.5,v 1.43 2007/05/27 19:21:15 reyk Exp $ +.\" $OpenBSD: hoststated.conf.5,v 1.44 2007/05/29 17:12:04 reyk Exp $ .\" .\" Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org> .\" @@ -204,6 +204,21 @@ If the .Ic ssl keyword is present, the transaction will occur in an SSL tunnel. +.It Ic check script Ar path +Execute an external program to check the host state. +The program will be executed for each host by specifing the host name +on the command line: +.Bd -literal -offset indent +/usr/local/bin/checkload.pl front-www1.private.example.com +.Ed +.Pp +.Xr hoststated 8 +expects a positive return value on success and zero on failure. +Note that the script will be executed with the privileges of the +.Qq _hoststated +user and terminated after +.Ar timeout +milliseconds. .It Ic check ssl Perform a complete SSL handshake with each host to check their availability. .It Ic check tcp diff --git a/usr.sbin/hoststated/hoststated.h b/usr.sbin/hoststated/hoststated.h index 036ce7aec4f..ed8cde04204 100644 --- a/usr.sbin/hoststated/hoststated.h +++ b/usr.sbin/hoststated/hoststated.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hoststated.h,v 1.47 2007/05/29 00:48:04 pyr Exp $ */ +/* $OpenBSD: hoststated.h,v 1.48 2007/05/29 17:12:04 reyk Exp $ */ /* * Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@spootnik.org> @@ -125,7 +125,8 @@ enum imsg_type { IMSG_DEMOTE, IMSG_STATISTICS, IMSG_RECONF, /* reconfiguration notifies */ - IMSG_RECONF_END + IMSG_RECONF_END, + IMSG_SCRIPT }; struct imsg_hdr { @@ -154,6 +155,11 @@ struct ctl_id { char name[MAX_NAME_SIZE]; }; +struct ctl_script { + objid_t host; + int retval; +}; + struct ctl_demote { char group[IFNAMSIZ]; int level; @@ -342,7 +348,8 @@ enum table_check { CHECK_TCP = 2, CHECK_HTTP_CODE = 3, CHECK_HTTP_DIGEST = 4, - CHECK_SEND_EXPECT = 5 + CHECK_SEND_EXPECT = 5, + CHECK_SCRIPT = 6 }; struct service_config { @@ -675,6 +682,11 @@ void check_icmp(struct hoststated *, struct timeval *); /* check_tcp.c */ void check_tcp(struct ctl_tcp_event *); +/* check_script.c */ +void check_script(struct host *); +void script_done(struct hoststated *, struct ctl_script *); +int script_exec(struct hoststated *, struct ctl_script *); + /* ssl.c */ void ssl_init(struct hoststated *); void ssl_transaction(struct ctl_tcp_event *); diff --git a/usr.sbin/hoststated/log.c b/usr.sbin/hoststated/log.c index 0da3432ca88..e3ef97f502a 100644 --- a/usr.sbin/hoststated/log.c +++ b/usr.sbin/hoststated/log.c @@ -1,4 +1,4 @@ -/* $OpenBSD: log.c,v 1.4 2007/02/22 03:32:39 reyk Exp $ */ +/* $OpenBSD: log.c,v 1.5 2007/05/29 17:12:04 reyk Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -196,6 +196,8 @@ table_check(enum table_check check) return ("http digest"); case CHECK_SEND_EXPECT: return ("send expect"); + case CHECK_SCRIPT: + return ("script"); }; /* NOTREACHED */ return ("invalid"); diff --git a/usr.sbin/hoststated/parse.y b/usr.sbin/hoststated/parse.y index 88c1c1c93a1..49f89707f0d 100644 --- a/usr.sbin/hoststated/parse.y +++ b/usr.sbin/hoststated/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.44 2007/05/29 00:48:04 pyr Exp $ */ +/* $OpenBSD: parse.y,v 1.45 2007/05/29 17:12:04 reyk Exp $ */ /* * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org> @@ -108,7 +108,7 @@ typedef struct { %token SERVICE TABLE BACKUP HOST REAL %token CHECK TCP ICMP EXTERNAL REQUEST RESPONSE %token TIMEOUT CODE DIGEST PORT TAG INTERFACE -%token VIRTUAL INTERVAL DISABLE STICKYADDR BACKLOG PATH +%token VIRTUAL INTERVAL DISABLE STICKYADDR BACKLOG PATH SCRIPT %token SEND EXPECT NOTHING SSL LOADBALANCE ROUNDROBIN CIPHERS COOKIE %token RELAY LISTEN ON FORWARD TO NAT LOOKUP PREFORK NO MARK MARKED %token PROTO SESSION CACHE APPEND CHANGE REMOVE FROM FILTER HASH HEADER @@ -508,6 +508,17 @@ tableoptsl : host { } free($5); } + | CHECK SCRIPT STRING { + table->conf.check = CHECK_SCRIPT; + if (strlcpy(table->conf.path, $3, + sizeof(table->conf.path)) >= + sizeof(table->conf.path)) { + yyerror("script path truncated"); + free($3); + YYERROR; + } + free($3); + } | REAL port { table->conf.port = $2; } @@ -1167,6 +1178,7 @@ lookup(char *s) { "retry", RETRY }, { "roundrobin", ROUNDROBIN }, { "sack", SACK }, + { "script", SCRIPT }, { "send", SEND }, { "service", SERVICE }, { "session", SESSION }, diff --git a/usr.sbin/relayd/Makefile b/usr.sbin/relayd/Makefile index f59567497ac..83c2467d45f 100644 --- a/usr.sbin/relayd/Makefile +++ b/usr.sbin/relayd/Makefile @@ -1,9 +1,9 @@ -# $OpenBSD: Makefile,v 1.11 2007/02/26 19:35:43 reyk Exp $ +# $OpenBSD: Makefile,v 1.12 2007/05/29 17:12:04 reyk Exp $ PROG= hoststated SRCS= parse.y log.c control.c buffer.c imsg.c hoststated.c \ - ssl.c pfe.c pfe_filter.c hce.c \ - check_icmp.c check_tcp.c relay.c carp.c + ssl.c pfe.c pfe_filter.c hce.c relay.c carp.c \ + check_icmp.c check_tcp.c check_script.c MAN= hoststated.8 hoststated.conf.5 LDADD= -levent -lssl -lcrypto diff --git a/usr.sbin/relayd/check_script.c b/usr.sbin/relayd/check_script.c new file mode 100644 index 00000000000..d347d882846 --- /dev/null +++ b/usr.sbin/relayd/check_script.c @@ -0,0 +1,166 @@ +/* $OpenBSD: check_script.c,v 1.1 2007/05/29 17:12:04 reyk Exp $ */ + +/* + * Copyright (c) 2007 Reyk Floeter <reyk@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/socket.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include <net/if.h> + +#include <limits.h> +#include <event.h> +#include <errno.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <signal.h> +#include <pwd.h> +#include <err.h> + +#include <openssl/ssl.h> + +#include "hoststated.h" + +void script_sig_alarm(int); + +extern struct imsgbuf *ibuf_main; +pid_t child = -1; + +void +check_script(struct host *host) +{ + struct ctl_script scr; + + host->last_up = host->up; + host->flags &= ~(F_CHECK_SENT|F_CHECK_DONE); + + scr.host = host->conf.id; + imsg_compose(ibuf_main, IMSG_SCRIPT, 0, 0, &scr, sizeof(scr)); +} + +void +script_done(struct hoststated *env, struct ctl_script *scr) +{ + struct host *host; + + if ((host = host_find(env, scr->host)) == NULL) + fatalx("hce_dispatch_parent: invalid host id"); + + if (scr->retval < 0) + host->up = HOST_UNKNOWN; + else if (scr->retval == 0) + host->up = HOST_DOWN; + else + host->up = HOST_UP; + host->flags |= F_CHECK_DONE; + + hce_notify_done(host, host->up == HOST_UP ? + "script: done" : "script: failed"); +} + +void +script_sig_alarm(int sig) +{ + if (child != -1) + kill(child, SIGKILL); +} + +int +script_exec(struct hoststated *env, struct ctl_script *scr) +{ + int status = 0, ret = 0; + sig_t save_quit, save_int, save_chld; + struct itimerval it; + struct timeval *tv; + const char *file, *arg; + struct host *host; + struct table *table; + struct passwd *pw; + + if ((host = host_find(env, scr->host)) == NULL) + fatalx("script_exec: invalid host id"); + if ((table = table_find(env, host->conf.tableid)) == NULL) + fatalx("script_exec: invalid table id"); + + arg = host->conf.name; + file = table->conf.path; + tv = &table->conf.timeout; + + save_quit = signal(SIGQUIT, SIG_IGN); + save_int = signal(SIGINT, SIG_IGN); + save_chld = signal(SIGCHLD, SIG_DFL); + + switch (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(HOSTSTATED_USER)) == NULL) + fatal("script_exec: getpwnam"); + if (chdir("/") == -1) + fatal("script_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("script_exec: can't drop privileges"); + + execlp(file, file, arg, (char *)NULL); + _exit(0); + break; + default: + /* Kill the process after a timeout */ + signal(SIGALRM, script_sig_alarm); + bzero(&it, sizeof(it)); + bcopy(tv, &it.it_value, sizeof(it.it_value)); + setitimer(ITIMER_REAL, &it, NULL); + + waitpid(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); + child = -1; + + signal(SIGQUIT, save_quit); + signal(SIGINT, save_int); + signal(SIGCHLD, save_chld); + signal(SIGALRM, SIG_DFL); + + return (ret); +} diff --git a/usr.sbin/relayd/hce.c b/usr.sbin/relayd/hce.c index 0110dfe7d22..139ef678b05 100644 --- a/usr.sbin/relayd/hce.c +++ b/usr.sbin/relayd/hce.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hce.c,v 1.21 2007/05/28 22:11:33 pyr Exp $ */ +/* $OpenBSD: hce.c,v 1.22 2007/05/29 17:12:04 reyk Exp $ */ /* * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org> @@ -46,7 +46,7 @@ void hce_dispatch_imsg(int, short, void *); void hce_dispatch_parent(int, short, void *); void hce_launch_checks(int, short, void *); -static struct hoststated *env = NULL; +static struct hoststated *env = NULL; struct imsgbuf *ibuf_pfe; struct imsgbuf *ibuf_main; @@ -194,19 +194,24 @@ hce_launch_checks(int fd, short event, void *arg) TAILQ_FOREACH(host, &table->hosts, entry) { if (host->flags & F_DISABLE) continue; - if (table->conf.check == CHECK_ICMP) { + switch (table->conf.check) { + case CHECK_ICMP: schedule_icmp(env, host); - continue; + break; + case CHECK_SCRIPT: + check_script(host); + break; + default: + /* Any other TCP-style checks */ + bzero(&host->cte, sizeof(host->cte)); + host->last_up = host->up; + host->cte.host = host; + host->cte.table = table; + bcopy(&tv, &host->cte.tv_start, + sizeof(host->cte.tv_start)); + check_tcp(&host->cte); + break; } - - /* Any other TCP-style checks */ - bzero(&host->cte, sizeof(host->cte)); - host->last_up = host->up; - host->cte.host = host; - host->cte.table = table; - bcopy(&tv, &host->cte.tv_start, - sizeof(host->cte.tv_start)); - check_tcp(&host->cte); } } check_icmp(env, &tv); @@ -359,9 +364,10 @@ hce_dispatch_imsg(int fd, short event, void *ptr) void hce_dispatch_parent(int fd, short event, void * ptr) { - struct imsgbuf *ibuf; - struct imsg imsg; - ssize_t n; + struct imsgbuf *ibuf; + struct imsg imsg; + struct ctl_script scr; + ssize_t n; ibuf = ptr; switch (event) { @@ -387,6 +393,14 @@ hce_dispatch_parent(int fd, short event, void * ptr) break; switch (imsg.hdr.type) { + case IMSG_SCRIPT: + if (imsg.hdr.len - IMSG_HEADER_SIZE != + sizeof(scr)) + fatalx("hce_dispatch_parent: " + "invalid size of script request"); + bcopy(imsg.data, &scr, sizeof(scr)); + script_done(env, &scr); + break; default: log_debug("hce_dispatch_parent: unexpected imsg %d", imsg.hdr.type); @@ -394,4 +408,5 @@ hce_dispatch_parent(int fd, short event, void * ptr) } imsg_free(&imsg); } + imsg_event_add(ibuf); } diff --git a/usr.sbin/relayd/log.c b/usr.sbin/relayd/log.c index 0da3432ca88..e3ef97f502a 100644 --- a/usr.sbin/relayd/log.c +++ b/usr.sbin/relayd/log.c @@ -1,4 +1,4 @@ -/* $OpenBSD: log.c,v 1.4 2007/02/22 03:32:39 reyk Exp $ */ +/* $OpenBSD: log.c,v 1.5 2007/05/29 17:12:04 reyk Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -196,6 +196,8 @@ table_check(enum table_check check) return ("http digest"); case CHECK_SEND_EXPECT: return ("send expect"); + case CHECK_SCRIPT: + return ("script"); }; /* NOTREACHED */ return ("invalid"); diff --git a/usr.sbin/relayd/parse.y b/usr.sbin/relayd/parse.y index 88c1c1c93a1..49f89707f0d 100644 --- a/usr.sbin/relayd/parse.y +++ b/usr.sbin/relayd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.44 2007/05/29 00:48:04 pyr Exp $ */ +/* $OpenBSD: parse.y,v 1.45 2007/05/29 17:12:04 reyk Exp $ */ /* * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org> @@ -108,7 +108,7 @@ typedef struct { %token SERVICE TABLE BACKUP HOST REAL %token CHECK TCP ICMP EXTERNAL REQUEST RESPONSE %token TIMEOUT CODE DIGEST PORT TAG INTERFACE -%token VIRTUAL INTERVAL DISABLE STICKYADDR BACKLOG PATH +%token VIRTUAL INTERVAL DISABLE STICKYADDR BACKLOG PATH SCRIPT %token SEND EXPECT NOTHING SSL LOADBALANCE ROUNDROBIN CIPHERS COOKIE %token RELAY LISTEN ON FORWARD TO NAT LOOKUP PREFORK NO MARK MARKED %token PROTO SESSION CACHE APPEND CHANGE REMOVE FROM FILTER HASH HEADER @@ -508,6 +508,17 @@ tableoptsl : host { } free($5); } + | CHECK SCRIPT STRING { + table->conf.check = CHECK_SCRIPT; + if (strlcpy(table->conf.path, $3, + sizeof(table->conf.path)) >= + sizeof(table->conf.path)) { + yyerror("script path truncated"); + free($3); + YYERROR; + } + free($3); + } | REAL port { table->conf.port = $2; } @@ -1167,6 +1178,7 @@ lookup(char *s) { "retry", RETRY }, { "roundrobin", ROUNDROBIN }, { "sack", SACK }, + { "script", SCRIPT }, { "send", SEND }, { "service", SERVICE }, { "session", SESSION }, diff --git a/usr.sbin/relayd/relayd.c b/usr.sbin/relayd/relayd.c index 9f20b1a90b1..83fc992c732 100644 --- a/usr.sbin/relayd/relayd.c +++ b/usr.sbin/relayd/relayd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: relayd.c,v 1.26 2007/05/29 00:58:06 pyr Exp $ */ +/* $OpenBSD: relayd.c,v 1.27 2007/05/29 17:12:04 reyk Exp $ */ /* * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org> @@ -54,6 +54,8 @@ int pipe_pfe2hce[2]; int pipe_parent2relay[RELAY_MAXPROC][2]; int pipe_pfe2relay[RELAY_MAXPROC][2]; +struct hoststated *hoststated_env; + struct imsgbuf *ibuf_pfe; struct imsgbuf *ibuf_hce; struct imsgbuf *ibuf_relay; @@ -68,8 +70,6 @@ main_sig_handler(int sig, short event, void *arg) struct hoststated *env = arg; int die = 0; - log_debug("signal %d", sig); - switch (sig) { case SIGTERM: case SIGINT: @@ -154,6 +154,7 @@ main(int argc, char *argv[]) if ((env = parse_config(conffile, opts)) == NULL) exit(1); + hoststated_env = env; if (env->opts & HOSTSTATED_OPT_NOACTION) { fprintf(stderr, "configuration OK\n"); @@ -485,7 +486,10 @@ main_dispatch_hce(int fd, short event, void * ptr) struct imsgbuf *ibuf; struct imsg imsg; ssize_t n; + struct ctl_script scr; + struct hoststated *env; + env = hoststated_env; ibuf = ptr; switch (event) { case EV_READ: @@ -510,6 +514,16 @@ main_dispatch_hce(int fd, short event, void * ptr) break; switch (imsg.hdr.type) { + case IMSG_SCRIPT: + if (imsg.hdr.len - IMSG_HEADER_SIZE != + sizeof(scr)) + fatalx("main_dispatch_hce: " + "invalid size of script request"); + bcopy(imsg.data, &scr, sizeof(scr)); + scr.retval = script_exec(env, &scr); + imsg_compose(ibuf_hce, IMSG_SCRIPT, + 0, 0, &scr, sizeof(scr)); + break; default: log_debug("main_dispatch_hce: unexpected imsg %d", imsg.hdr.type); @@ -517,6 +531,7 @@ main_dispatch_hce(int fd, short event, void * ptr) } imsg_free(&imsg); } + imsg_event_add(ibuf); } void diff --git a/usr.sbin/relayd/relayd.conf.5 b/usr.sbin/relayd/relayd.conf.5 index 62056584def..5bf06abb520 100644 --- a/usr.sbin/relayd/relayd.conf.5 +++ b/usr.sbin/relayd/relayd.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: relayd.conf.5,v 1.43 2007/05/27 19:21:15 reyk Exp $ +.\" $OpenBSD: relayd.conf.5,v 1.44 2007/05/29 17:12:04 reyk Exp $ .\" .\" Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org> .\" @@ -204,6 +204,21 @@ If the .Ic ssl keyword is present, the transaction will occur in an SSL tunnel. +.It Ic check script Ar path +Execute an external program to check the host state. +The program will be executed for each host by specifing the host name +on the command line: +.Bd -literal -offset indent +/usr/local/bin/checkload.pl front-www1.private.example.com +.Ed +.Pp +.Xr hoststated 8 +expects a positive return value on success and zero on failure. +Note that the script will be executed with the privileges of the +.Qq _hoststated +user and terminated after +.Ar timeout +milliseconds. .It Ic check ssl Perform a complete SSL handshake with each host to check their availability. .It Ic check tcp diff --git a/usr.sbin/relayd/relayd.h b/usr.sbin/relayd/relayd.h index c92d9391560..8c66b958485 100644 --- a/usr.sbin/relayd/relayd.h +++ b/usr.sbin/relayd/relayd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: relayd.h,v 1.47 2007/05/29 00:48:04 pyr Exp $ */ +/* $OpenBSD: relayd.h,v 1.48 2007/05/29 17:12:04 reyk Exp $ */ /* * Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@spootnik.org> @@ -125,7 +125,8 @@ enum imsg_type { IMSG_DEMOTE, IMSG_STATISTICS, IMSG_RECONF, /* reconfiguration notifies */ - IMSG_RECONF_END + IMSG_RECONF_END, + IMSG_SCRIPT }; struct imsg_hdr { @@ -154,6 +155,11 @@ struct ctl_id { char name[MAX_NAME_SIZE]; }; +struct ctl_script { + objid_t host; + int retval; +}; + struct ctl_demote { char group[IFNAMSIZ]; int level; @@ -342,7 +348,8 @@ enum table_check { CHECK_TCP = 2, CHECK_HTTP_CODE = 3, CHECK_HTTP_DIGEST = 4, - CHECK_SEND_EXPECT = 5 + CHECK_SEND_EXPECT = 5, + CHECK_SCRIPT = 6 }; struct service_config { @@ -675,6 +682,11 @@ void check_icmp(struct hoststated *, struct timeval *); /* check_tcp.c */ void check_tcp(struct ctl_tcp_event *); +/* check_script.c */ +void check_script(struct host *); +void script_done(struct hoststated *, struct ctl_script *); +int script_exec(struct hoststated *, struct ctl_script *); + /* ssl.c */ void ssl_init(struct hoststated *); void ssl_transaction(struct ctl_tcp_event *); |