summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorreyk <reyk@openbsd.org>2007-05-29 17:12:04 +0000
committerreyk <reyk@openbsd.org>2007-05-29 17:12:04 +0000
commit4156152f0fa963fdd68c44681e8679032e5e075a (patch)
treec230749839cbad5806058abf4f0a479afb546490
parentFix bus_dmamap_sync size argument. (diff)
downloadwireguard-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/Makefile6
-rw-r--r--usr.sbin/hoststated/check_script.c166
-rw-r--r--usr.sbin/hoststated/hce.c47
-rw-r--r--usr.sbin/hoststated/hoststated.c21
-rw-r--r--usr.sbin/hoststated/hoststated.conf.517
-rw-r--r--usr.sbin/hoststated/hoststated.h18
-rw-r--r--usr.sbin/hoststated/log.c4
-rw-r--r--usr.sbin/hoststated/parse.y16
-rw-r--r--usr.sbin/relayd/Makefile6
-rw-r--r--usr.sbin/relayd/check_script.c166
-rw-r--r--usr.sbin/relayd/hce.c47
-rw-r--r--usr.sbin/relayd/log.c4
-rw-r--r--usr.sbin/relayd/parse.y16
-rw-r--r--usr.sbin/relayd/relayd.c21
-rw-r--r--usr.sbin/relayd/relayd.conf.517
-rw-r--r--usr.sbin/relayd/relayd.h18
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 *);