diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2007-11-26 09:38:26 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2007-11-26 09:38:26 +0000 |
commit | 0e9e0d402eb069d0e60ee03129dc0d7275415a92 (patch) | |
tree | 4ff0e05b17d2f6bcbb289ab1f90c55264b8b153a /usr.sbin/hoststated | |
parent | 04b4ef9c75ed734905ee1bdf681657395bf1dd08 (diff) |
allow to add labels to protocol actions, they will be printed in http
error pages and can be used to refer to additional information.
ok pyr@
Diffstat (limited to 'usr.sbin/hoststated')
-rw-r--r-- | usr.sbin/hoststated/Makefile | 4 | ||||
-rw-r--r-- | usr.sbin/hoststated/hoststated.conf.5 | 18 | ||||
-rw-r--r-- | usr.sbin/hoststated/hoststated.h | 10 | ||||
-rw-r--r-- | usr.sbin/hoststated/name2id.c | 177 | ||||
-rw-r--r-- | usr.sbin/hoststated/parse.y | 18 | ||||
-rw-r--r-- | usr.sbin/hoststated/relay.c | 57 |
6 files changed, 253 insertions, 31 deletions
diff --git a/usr.sbin/hoststated/Makefile b/usr.sbin/hoststated/Makefile index f28c57b0aad..4c2d3010aaf 100644 --- a/usr.sbin/hoststated/Makefile +++ b/usr.sbin/hoststated/Makefile @@ -1,9 +1,9 @@ -# $OpenBSD: Makefile,v 1.14 2007/09/25 08:24:26 pyr Exp $ +# $OpenBSD: Makefile,v 1.15 2007/11/26 09:38:25 reyk Exp $ PROG= hoststated SRCS= parse.y log.c control.c buffer.c imsg.c ssl.c ssl_privsep.c \ hoststated.c pfe.c pfe_filter.c hce.c relay.c relay_udp.c \ - carp.c check_icmp.c check_tcp.c check_script.c + carp.c check_icmp.c check_tcp.c check_script.c name2id.c MAN= hoststated.8 hoststated.conf.5 LDADD= -levent -lssl -lcrypto diff --git a/usr.sbin/hoststated/hoststated.conf.5 b/usr.sbin/hoststated/hoststated.conf.5 index ae3397d3f77..d82f2942121 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.68 2007/11/25 20:02:02 reyk Exp $ +.\" $OpenBSD: hoststated.conf.5,v 1.69 2007/11/26 09:38:25 reyk Exp $ .\" .\" Copyright (c) 2006, 2007 Reyk Floeter <reyk@openbsd.org> .\" Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: November 25 2007 $ +.Dd $Mdocdate: November 26 2007 $ .Dt HOSTSTATED.CONF 5 .Os .Sh NAME @@ -706,6 +706,20 @@ action does not accept the .Ic marked option (see above). .El +.It Ic label Ar string +Add a label to subsequently added actions. +The label will be printed as part of the error message if the +.Ic return error +option is set and may contain HTML tags, for example: +.Bd -literal -offset indent +label "<a href='http://example.com/advisory.pl?id=7359'>\e + Advisory provided by example.com</a>" +url filter digest 5c1e03f58f8ce0b457474ffb371fd1ef +url filter digest 80c1a7b8337462093ef8359c57b4d56a +no label +.Ed +.It Ic no label +Do not set a label for subsequently added actions, this is the default. .It Ic return error Op Ar option Return an error reponse to the client if an internal operation or the forward connection to the client failed. diff --git a/usr.sbin/hoststated/hoststated.h b/usr.sbin/hoststated/hoststated.h index 2b3cbb3c821..4198325af28 100644 --- a/usr.sbin/hoststated/hoststated.h +++ b/usr.sbin/hoststated/hoststated.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hoststated.h,v 1.85 2007/11/24 16:13:50 reyk Exp $ */ +/* $OpenBSD: hoststated.h,v 1.86 2007/11/26 09:38:25 reyk Exp $ */ /* * Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -467,6 +467,7 @@ struct protonode { u_int8_t flags; enum nodetype type; u_int16_t mark; + u_int16_t label; SIMPLEQ_HEAD(, protonode) head; SIMPLEQ_ENTRY(protonode) entry; @@ -800,3 +801,10 @@ void carp_demote_shutdown(void); int carp_demote_get(char *); int carp_demote_set(char *, int); int carp_demote_reset(char *, int); + +/* name2id.c */ +u_int16_t pn_name2id(const char *); +const char *pn_id2name(u_int16_t); +void pn_unref(u_int16_t); +void pn_ref(u_int16_t); + diff --git a/usr.sbin/hoststated/name2id.c b/usr.sbin/hoststated/name2id.c new file mode 100644 index 00000000000..8b9e4a781b9 --- /dev/null +++ b/usr.sbin/hoststated/name2id.c @@ -0,0 +1,177 @@ +/* $OpenBSD: name2id.c,v 1.1 2007/11/26 09:38:25 reyk Exp $ */ + +/* + * Copyright (c) 2004, 2005 Henning Brauer <henning@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 MIND, 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/param.h> +#include <sys/socket.h> +#include <sys/queue.h> + +#include <net/if.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <event.h> + +#include <openssl/ssl.h> + +#include "hoststated.h" + +#define IDVAL_MAX 50000 + +struct n2id_label { + TAILQ_ENTRY(n2id_label) entry; + char *name; + u_int16_t id; + int ref; +}; + +TAILQ_HEAD(n2id_labels, n2id_label); + +u_int16_t _name2id(struct n2id_labels *, const char *); +const char *_id2name(struct n2id_labels *, u_int16_t); +void _unref(struct n2id_labels *, u_int16_t); +void _ref(struct n2id_labels *, u_int16_t); + +/* for protocolnode labels */ +struct n2id_labels pn_labels = TAILQ_HEAD_INITIALIZER(pn_labels); + +u_int16_t +pn_name2id(const char *name) +{ + return (_name2id(&pn_labels, name)); +} + +const char * +pn_id2name(u_int16_t id) +{ + return (_id2name(&pn_labels, id)); +} + +void +pn_unref(u_int16_t id) +{ + _unref(&pn_labels, id); +} + +void +pn_ref(u_int16_t id) +{ + _ref(&pn_labels, id); +} + +u_int16_t +_name2id(struct n2id_labels *head, const char *name) +{ + struct n2id_label *label, *p = NULL; + u_int16_t new_id = 1; + + if (!name[0]) { + errno = EINVAL; + return (0); + } + + TAILQ_FOREACH(label, head, entry) + if (strcmp(name, label->name) == 0) { + label->ref++; + return (label->id); + } + + /* + * to avoid fragmentation, we do a linear search from the beginning + * and take the first free slot we find. if there is none or the list + * is empty, append a new entry at the end. + */ + + if (!TAILQ_EMPTY(head)) + for (p = TAILQ_FIRST(head); p != NULL && + p->id == new_id; p = TAILQ_NEXT(p, entry)) + new_id = p->id + 1; + + if (new_id > IDVAL_MAX) { + errno = ERANGE; + return (0); + } + + if ((label = calloc(1, sizeof(struct n2id_label))) == NULL) + return (0); + if ((label->name = strdup(name)) == NULL) { + free(label); + return (0); + } + label->id = new_id; + label->ref++; + + if (p != NULL) /* insert new entry before p */ + TAILQ_INSERT_BEFORE(p, label, entry); + else /* either list empty or no free slot in between */ + TAILQ_INSERT_TAIL(head, label, entry); + + return (label->id); +} + +const char * +_id2name(struct n2id_labels *head, u_int16_t id) +{ + struct n2id_label *label; + + if (id == 0) + return (""); + + TAILQ_FOREACH(label, head, entry) + if (label->id == id) + return (label->name); + + return (""); +} + +void +_unref(struct n2id_labels *head, u_int16_t id) +{ + struct n2id_label *p, *next; + + if (id == 0) + return; + + for (p = TAILQ_FIRST(head); p != NULL; p = next) { + next = TAILQ_NEXT(p, entry); + if (id == p->id) { + if (--p->ref == 0) { + TAILQ_REMOVE(head, p, entry); + free(p->name); + free(p); + } + break; + } + } +} + +void +_ref(struct n2id_labels *head, u_int16_t id) +{ + struct n2id_label *label; + + if (id == 0) + return; + + TAILQ_FOREACH(label, head, entry) + if (label->id == id) { + ++label->ref; + break; + } +} diff --git a/usr.sbin/hoststated/parse.y b/usr.sbin/hoststated/parse.y index b2a9f43d31c..dc21d748b27 100644 --- a/usr.sbin/hoststated/parse.y +++ b/usr.sbin/hoststated/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.95 2007/11/24 17:07:28 reyk Exp $ */ +/* $OpenBSD: parse.y,v 1.96 2007/11/26 09:38:25 reyk Exp $ */ /* * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -93,6 +93,7 @@ static struct table *table = NULL; static struct relay *rlay = NULL; static struct protocol *proto = NULL; static struct protonode node; +static u_int16_t label = 0; struct address *host_v4(const char *); struct address *host_v6(const char *); @@ -121,7 +122,7 @@ typedef struct { %token SERVICE TABLE BACKUP HOST REAL INCLUDE %token CHECK TCP ICMP EXTERNAL REQUEST RESPONSE -%token TIMEOUT CODE DIGEST PORT TAG INTERFACE STYLE RETURN +%token TIMEOUT CODE DIGEST PORT TAG INTERFACE STYLE RETURN LABEL %token VIRTUAL INTERVAL DISABLE STICKYADDR BACKLOG PATH SCRIPT WITH %token SEND EXPECT NOTHING SSL LOADBALANCE ROUNDROBIN CIPHERS COOKIE %token RELAY LISTEN ON FORWARD TO NAT LOOKUP PREFORK NO MARK MARKED URL @@ -689,6 +690,17 @@ protoptsl : SSL sslflags | PROTO proto_type { proto->type = $2; } | RETURN ERROR opteflags { proto->flags |= F_RETURN; } | RETURN ERROR '{' eflags_l '}' { proto->flags |= F_RETURN; } + | LABEL STRING { + label = pn_name2id($2); + free($2); + if (label == 0) { + yyerror("invalid protocol action label"); + YYERROR; + } + } + | NO LABEL { + label = 0; + } | direction protonode log { struct protonode *pn, *proot, pk; struct proto_tree *tree; @@ -704,6 +716,7 @@ protoptsl : SSL sslflags pn->key = node.key; pn->value = node.value; pn->type = node.type; + pn->label = label; SIMPLEQ_INIT(&pn->head); if ($1 == RELAY_DIR_RESPONSE) pn->id = proto->response_nodes++; @@ -1377,6 +1390,7 @@ lookup(char *s) { "interface", INTERFACE }, { "interval", INTERVAL }, { "ip", IP }, + { "label", LABEL }, { "listen", LISTEN }, { "loadbalance", LOADBALANCE }, { "log", LOG }, diff --git a/usr.sbin/hoststated/relay.c b/usr.sbin/hoststated/relay.c index 89c573d2cec..5a9234dd6ea 100644 --- a/usr.sbin/hoststated/relay.c +++ b/usr.sbin/hoststated/relay.c @@ -1,4 +1,4 @@ -/* $OpenBSD: relay.c,v 1.71 2007/11/24 17:43:47 reyk Exp $ */ +/* $OpenBSD: relay.c,v 1.72 2007/11/26 09:38:25 reyk Exp $ */ /* * Copyright (c) 2006, 2007 Reyk Floeter <reyk@openbsd.org> @@ -99,7 +99,8 @@ void relay_read_httpcontent(struct bufferevent *, void *); void relay_read_httpchunks(struct bufferevent *, void *); char *relay_expand_http(struct ctl_relay_event *, char *, char *, size_t); -void relay_close_http(struct session *, u_int, const char *); +void relay_close_http(struct session *, u_int, const char *, + u_int16_t); SSL_CTX *relay_ssl_ctx_create(struct relay *); void relay_ssl_transaction(struct session *); @@ -731,7 +732,7 @@ relay_connected(int fd, short sig, void *arg) struct bufferevent *bev; if (sig == EV_TIMEOUT) { - relay_close_http(con, 504, "connect timeout"); + relay_close_http(con, 504, "connect timeout", 0); return; } @@ -746,7 +747,7 @@ relay_connected(int fd, short sig, void *arg) if ((con->out.nodes = calloc(proto->response_nodes, sizeof(u_int8_t))) == NULL) { relay_close_http(con, 500, - "failed to allocate nodes"); + "failed to allocate nodes", 0); return; } } @@ -764,7 +765,7 @@ relay_connected(int fd, short sig, void *arg) bev = bufferevent_new(fd, outrd, outwr, relay_error, &con->out); if (bev == NULL) { relay_close_http(con, 500, - "failed to allocate output buffer event"); + "failed to allocate output buffer event", 0); return; } evbuffer_free(bev->output); @@ -920,7 +921,8 @@ relay_resolve(struct ctl_relay_event *cre, relay_bufferevent_print(cre->dst, ": ") == -1 || relay_bufferevent_print(cre->dst, ptr) == -1 || relay_bufferevent_print(cre->dst, "\r\n") == -1) { - relay_close_http(con, 500, "failed to modify header"); + relay_close_http(con, 500, + "failed to modify header", 0); return (-1); } DPRINTF("relay_resolve: add '%s: %s'", @@ -929,12 +931,12 @@ relay_resolve(struct ctl_relay_event *cre, case NODE_ACTION_EXPECT: DPRINTF("relay_resolve: missing '%s: %s'", pn->key, pn->value); - relay_close_http(con, 403, "incomplete request"); + relay_close_http(con, 403, "incomplete request", pn->label); return (-1); case NODE_ACTION_FILTER: DPRINTF("relay_resolve: filtered '%s: %s'", pn->key, pn->value); - relay_close_http(con, 403, "rejecting request"); + relay_close_http(con, 403, "rejecting request", pn->label); return (-1); default: break; @@ -1049,7 +1051,7 @@ relay_handle_http(struct ctl_relay_event *cre, struct protonode *proot, * trying to circumvent the filter. */ if (cre->nodes[proot->id] > 1) { - relay_close_http(con, 400, "repeated header line"); + relay_close_http(con, 400, "repeated header line", 0); return (PN_FAIL); } /* FALLTHROUGH */ @@ -1067,7 +1069,8 @@ relay_handle_http(struct ctl_relay_event *cre, struct protonode *proot, /* Fail instantly */ if (pn->action == NODE_ACTION_FILTER) { - relay_close_http(con, 403, "rejecting request"); + relay_close_http(con, 403, + "rejecting request", pn->label); return (PN_FAIL); } } @@ -1106,7 +1109,7 @@ relay_handle_http(struct ctl_relay_event *cre, struct protonode *proot, return (ret); fail: - relay_close_http(con, 500, strerror(errno)); + relay_close_http(con, 500, strerror(errno), 0); return (PN_FAIL); } @@ -1288,7 +1291,7 @@ relay_read_http(struct bufferevent *bev, void *arg) if (pk.value == NULL || strlen(pk.value) < 3) { if (cre->line == 1) { free(line); - relay_close_http(con, 400, "malformed"); + relay_close_http(con, 400, "malformed", 0); return; } @@ -1397,7 +1400,7 @@ relay_read_http(struct bufferevent *bev, void *arg) */ cre->toread = strtonum(pk.value, 1, INT_MAX, &errstr); if (errstr) { - relay_close_http(con, 500, errstr); + relay_close_http(con, 500, errstr, 0); goto abort; } } @@ -1506,7 +1509,7 @@ relay_read_http(struct bufferevent *bev, void *arg) if (cre->dir == RELAY_DIR_REQUEST && proto->lateconnect && cre->dst->bev == NULL && relay_connect(con) == -1) { - relay_close_http(con, 502, "session failed"); + relay_close_http(con, 502, "session failed", 0); return; } } @@ -1520,7 +1523,7 @@ relay_read_http(struct bufferevent *bev, void *arg) relay_close(con, "last http read (done)"); return; fail: - relay_close_http(con, 500, strerror(errno)); + relay_close_http(con, 500, strerror(errno), 0); return; abort: free(line); @@ -1539,7 +1542,7 @@ _relay_lookup_url(struct ctl_relay_event *cre, char *host, char *path, host, path, query == NULL ? "" : "?", query == NULL ? "" : query) == -1) { - relay_close_http(con, 500, "failed to allocate URL"); + relay_close_http(con, 500, "failed to allocate URL", 0); return (PN_FAIL); } @@ -1549,7 +1552,8 @@ _relay_lookup_url(struct ctl_relay_event *cre, char *host, char *path, case DIGEST_SHA1: case DIGEST_MD5: if ((md = digeststr(type, val, strlen(val), NULL)) == NULL) { - relay_close_http(con, 500, "failed to allocate digest"); + relay_close_http(con, 500, + "failed to allocate digest", 0); goto fail; } pkv.key = md; @@ -1602,7 +1606,7 @@ relay_lookup_url(struct ctl_relay_event *cre, const char *str, str, cre->path, cre->args == NULL ? "" : cre->args); if (canonicalize_host(str, ph, sizeof(ph)) == NULL) { - relay_close_http(con, 400, "invalid host name"); + relay_close_http(con, 400, "invalid host name", 0); return (PN_FAIL); } @@ -1618,7 +1622,7 @@ relay_lookup_url(struct ctl_relay_event *cre, const char *str, hi[dots] = ph; if ((pp = strdup(cre->path)) == NULL) { - relay_close_http(con, 500, "failed to allocate path"); + relay_close_http(con, 500, "failed to allocate path", 0); return (PN_FAIL); } for (i = (RELAY_MAXLOOKUPLEVELS - 1); i >= 0; i--) { @@ -1668,7 +1672,7 @@ relay_lookup_query(struct ctl_relay_event *cre) if (cre->path == NULL || cre->args == NULL || strlen(cre->args) < 2) return (PN_PASS); if ((val = strdup(cre->args)) == NULL) { - relay_close_http(con, 500, "failed to allocate query"); + relay_close_http(con, 500, "failed to allocate query", 0); return (PN_FAIL); } @@ -1709,7 +1713,7 @@ relay_lookup_cookie(struct ctl_relay_event *cre, const char *str) int ret; if ((val = strdup(str)) == NULL) { - relay_close_http(con, 500, "failed to allocate cookie"); + relay_close_http(con, 500, "failed to allocate cookie", 0); return (PN_FAIL); } @@ -1752,7 +1756,8 @@ relay_lookup_cookie(struct ctl_relay_event *cre, const char *str) } void -relay_close_http(struct session *con, u_int code, const char *msg) +relay_close_http(struct session *con, u_int code, const char *msg, + u_int16_t labelid) { struct relay *rlay = (struct relay *)con->relay; struct bufferevent *bev = con->in.bev; @@ -1761,7 +1766,7 @@ relay_close_http(struct session *con, u_int code, const char *msg) time_t t; struct tm *lt; char tmbuf[32], hbuf[128]; - const char *style; + const char *style, *label = NULL; /* In some cases this function may be called from generic places */ if (rlay->proto->type != RELAY_PROTO_HTTP || @@ -1787,6 +1792,8 @@ relay_close_http(struct session *con, u_int code, const char *msg) /* Do not send details of the Internal Server Error */ if (code != 500) text = msg; + if (labelid != 0) + label = pn_id2name(labelid); /* A CSS stylesheet allows minimal customization by the user */ if ((style = rlay->proto->style) == NULL) @@ -1809,12 +1816,14 @@ relay_close_http(struct session *con, u_int code, const char *msg) "</head>\n" "<body>\n" "<h1>%s</h1>\n" - "<p>%s</p>\n" + "<div id='m'>%s</div>\n" + "<div id='l'>%s</div>\n" "<hr><address>%s at %s port %d</address>\n" "</body>\n" "</html>\n", code, httperr, tmbuf, HOSTSTATED_SERVERNAME, code, httperr, style, httperr, text, + label == NULL ? "" : label, HOSTSTATED_SERVERNAME, hbuf, ntohs(rlay->conf.port)) == -1) goto done; |