diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2007-02-22 03:32:41 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2007-02-22 03:32:41 +0000 |
commit | b8b5308cae709adc7b92263ac61594c76949364e (patch) | |
tree | 2bac390064e9007c688d03c0520127876862c33e /usr.sbin/relayd/relayd.c | |
parent | 28be4aaf667d9ad44c93bdc68b15a111e28fe396 (diff) |
Add layer 7 functionality to hoststated used for layer 7
loadbalancing, SSL acceleration, general-purpose TCP relaying, and
transparent proxying.
see hoststated.conf(5) and my upcoming article on undeadly.org for
details.
ok to commit deraadt@ pyr@
Diffstat (limited to 'usr.sbin/relayd/relayd.c')
-rw-r--r-- | usr.sbin/relayd/relayd.c | 190 |
1 files changed, 178 insertions, 12 deletions
diff --git a/usr.sbin/relayd/relayd.c b/usr.sbin/relayd/relayd.c index 976029c0e43..093b35fb849 100644 --- a/usr.sbin/relayd/relayd.c +++ b/usr.sbin/relayd/relayd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: relayd.c,v 1.16 2007/02/08 13:32:24 reyk Exp $ */ +/* $OpenBSD: relayd.c,v 1.17 2007/02/22 03:32:39 reyk Exp $ */ /* * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org> @@ -40,25 +40,33 @@ __dead void usage(void); void main_sig_handler(int, short, void *); -void main_shutdown(void); +void main_shutdown(struct hoststated *); void main_dispatch_pfe(int, short, void *); void main_dispatch_hce(int, short, void *); +void main_dispatch_relay(int, short, void *); int check_child(pid_t, const char *); int pipe_parent2pfe[2]; int pipe_parent2hce[2]; +int pipe_parent2relay[2]; int pipe_pfe2hce[2]; +int pipe_pfe2relay[RELAY_MAXPROC][2]; struct imsgbuf *ibuf_pfe; struct imsgbuf *ibuf_hce; +struct imsgbuf *ibuf_relay; pid_t pfe_pid = 0; pid_t hce_pid = 0; +pid_t relay_pid = 0; void main_sig_handler(int sig, short event, void *arg) { - int die = 0; + struct hoststated *env = arg; + int die = 0; + + log_debug("signal %d", sig); switch (sig) { case SIGTERM: @@ -73,8 +81,12 @@ main_sig_handler(int sig, short event, void *arg) hce_pid = 0; die = 1; } + if (check_child(relay_pid, "socket relay engine")) { + relay_pid = 0; + die = 1; + } if (die) - main_shutdown(); + main_shutdown(env); break; case SIGHUP: /* reconfigure */ @@ -145,6 +157,8 @@ main(int argc, char *argv[]) fprintf(stderr, "configuration OK\n"); exit(0); } + if (debug) + env.opts |= HOSTSTATED_OPT_LOGUPDATE; if (geteuid()) errx(1, "need root privileges"); @@ -163,27 +177,42 @@ main(int argc, char *argv[]) fatal("socketpair"); if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2hce) == -1) fatal("socketpair"); + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2relay) == -1) + fatal("socketpair"); if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_pfe2hce) == -1) fatal("socketpair"); + for (c = 0; c < env.prefork_relay; c++) { + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, + pipe_pfe2relay[c]) == -1) + fatal("socketpair"); + session_socket_blockmode(pipe_pfe2relay[c][0], BM_NONBLOCK); + session_socket_blockmode(pipe_pfe2relay[c][1], BM_NONBLOCK); + } session_socket_blockmode(pipe_parent2pfe[0], BM_NONBLOCK); session_socket_blockmode(pipe_parent2pfe[1], BM_NONBLOCK); session_socket_blockmode(pipe_parent2hce[0], BM_NONBLOCK); session_socket_blockmode(pipe_parent2hce[1], BM_NONBLOCK); + session_socket_blockmode(pipe_parent2relay[0], BM_NONBLOCK); + session_socket_blockmode(pipe_parent2relay[1], BM_NONBLOCK); session_socket_blockmode(pipe_pfe2hce[0], BM_NONBLOCK); session_socket_blockmode(pipe_pfe2hce[1], BM_NONBLOCK); - pfe_pid = pfe(&env, pipe_parent2pfe, pipe_parent2hce, pipe_pfe2hce); - hce_pid = hce(&env, pipe_parent2pfe, pipe_parent2hce, pipe_pfe2hce); + pfe_pid = pfe(&env, pipe_parent2pfe, pipe_parent2hce, + pipe_parent2relay, pipe_pfe2hce, pipe_pfe2relay); + hce_pid = hce(&env, pipe_parent2pfe, pipe_parent2hce, + pipe_parent2relay, pipe_pfe2hce, pipe_pfe2relay); + relay_pid = relay(&env, pipe_parent2pfe, pipe_parent2hce, + pipe_parent2relay, pipe_pfe2hce, pipe_pfe2relay); setproctitle("parent"); event_init(); - signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL); - signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL); - signal_set(&ev_sigchld, SIGCHLD, main_sig_handler, NULL); - signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL); + signal_set(&ev_sigint, SIGINT, main_sig_handler, &env); + signal_set(&ev_sigterm, SIGTERM, main_sig_handler, &env); + signal_set(&ev_sigchld, SIGCHLD, main_sig_handler, &env); + signal_set(&ev_sighup, SIGHUP, main_sig_handler, &env); signal_add(&ev_sigint, NULL); signal_add(&ev_sigterm, NULL); signal_add(&ev_sigchld, NULL); @@ -192,15 +221,22 @@ main(int argc, char *argv[]) close(pipe_parent2pfe[1]); close(pipe_parent2hce[1]); + close(pipe_parent2relay[1]); close(pipe_pfe2hce[0]); close(pipe_pfe2hce[1]); + for (c = 0; c < env.prefork_relay; c++) { + close(pipe_pfe2relay[c][0]); + close(pipe_pfe2relay[c][1]); + } if ((ibuf_pfe = calloc(1, sizeof(struct imsgbuf))) == NULL || - (ibuf_hce = calloc(1, sizeof(struct imsgbuf))) == NULL) + (ibuf_hce = calloc(1, sizeof(struct imsgbuf))) == NULL || + (ibuf_relay = calloc(1, sizeof(struct imsgbuf))) == NULL) fatal(NULL); imsg_init(ibuf_pfe, pipe_parent2pfe[0], main_dispatch_pfe); imsg_init(ibuf_hce, pipe_parent2hce[0], main_dispatch_hce); + imsg_init(ibuf_relay, pipe_parent2relay[0], main_dispatch_relay); ibuf_pfe->events = EV_READ; event_set(&ibuf_pfe->ev, ibuf_pfe->fd, ibuf_pfe->events, @@ -212,13 +248,21 @@ main(int argc, char *argv[]) ibuf_hce->handler, ibuf_hce); event_add(&ibuf_hce->ev, NULL); + ibuf_relay->events = EV_READ; + event_set(&ibuf_relay->ev, ibuf_relay->fd, ibuf_relay->events, + ibuf_relay->handler, ibuf_relay); + event_add(&ibuf_relay->ev, NULL); + + if (env.flags & F_DEMOTE) + carp_demote_reset(env.demote_group, 0); + event_dispatch(); return (0); } void -main_shutdown(void) +main_shutdown(struct hoststated *env) { pid_t pid; @@ -226,6 +270,8 @@ main_shutdown(void) kill(pfe_pid, SIGTERM); if (hce_pid) kill(hce_pid, SIGTERM); + if (relay_pid) + kill(relay_pid, SIGTERM); do { if ((pid = wait(NULL)) == -1 && @@ -234,6 +280,9 @@ main_shutdown(void) } while (pid != -1 || (pid == -1 && errno == EINTR)); control_cleanup(); + carp_demote_shutdown(); + if (env->flags & F_DEMOTE) + carp_demote_reset(env->demote_group, 128); log_info("terminating"); exit(0); } @@ -276,6 +325,7 @@ main_dispatch_pfe(int fd, short event, void *ptr) struct imsgbuf *ibuf; struct imsg imsg; ssize_t n; + struct ctl_demote demote; ibuf = ptr; switch (event) { @@ -301,6 +351,14 @@ main_dispatch_pfe(int fd, short event, void *ptr) break; switch (imsg.hdr.type) { + case IMSG_DEMOTE: + if (imsg.hdr.len - IMSG_HEADER_SIZE != + sizeof(demote)) + fatalx("main_dispatch_pfe: " + "invalid size of demote request"); + memcpy(&demote, imsg.data, sizeof(demote)); + carp_demote_set(demote.group, demote.level); + break; default: log_debug("main_dispatch_pfe: unexpected imsg %d", imsg.hdr.type); @@ -351,6 +409,46 @@ main_dispatch_hce(int fd, short event, void * ptr) } } +void +main_dispatch_relay(int fd, short event, void * ptr) +{ + struct imsgbuf *ibuf; + struct imsg imsg; + ssize_t n; + + ibuf = ptr; + switch (event) { + case EV_READ: + if ((n = imsg_read(ibuf)) == -1) + fatal("imsg_read error"); + if (n == 0) + fatalx("main_dispatch_relay: pipe closed"); + break; + case EV_WRITE: + if (msgbuf_write(&ibuf->w) == -1) + fatal("msgbuf_write"); + imsg_event_add(ibuf); + return; + default: + fatalx("unknown event"); + } + + for (;;) { + if ((n = imsg_get(ibuf, &imsg)) == -1) + fatal("main_dispatch_relay: imsg_read error"); + if (n == 0) + break; + + switch (imsg.hdr.type) { + default: + log_debug("main_dispatch_relay: unexpected imsg %d", + imsg.hdr.type); + break; + } + imsg_free(&imsg); + } +} + struct host * host_find(struct hoststated *env, objid_t id) { @@ -386,6 +484,32 @@ service_find(struct hoststated *env, objid_t id) return (NULL); } +struct relay * +relay_find(struct hoststated *env, objid_t id) +{ + struct relay *rlay; + + TAILQ_FOREACH(rlay, &env->relays, entry) + if (rlay->id == id) + return (rlay); + return (NULL); +} + +struct session * +session_find(struct hoststated *env, objid_t id) +{ + struct relay *rlay; + struct session *con; + + TAILQ_FOREACH(rlay, &env->relays, entry) + TAILQ_FOREACH(con, &rlay->sessions, entry) { + log_debug("session_find: %d : %d", id, con->id); + if (con->id == id) + return (con); + } + return (NULL); +} + struct host * host_findbyname(struct hoststated *env, const char *name) { @@ -421,6 +545,17 @@ service_findbyname(struct hoststated *env, const char *name) return (NULL); } +struct relay * +relay_findbyname(struct hoststated *env, const char *name) +{ + struct relay *rlay; + + TAILQ_FOREACH(rlay, &env->relays, entry) + if (strcmp(rlay->name, name) == 0) + return (rlay); + return (NULL); +} + void event_again(struct event *ev, int fd, short event, void (*fn)(int, short, void *), @@ -442,3 +577,34 @@ event_again(struct event *ev, int fd, short event, event_set(ev, fd, event, fn, arg); event_add(ev, &tv); } + +int +expand_string(char *label, size_t len, const char *srch, const char *repl) +{ + char *tmp; + char *p, *q; + + if ((tmp = calloc(1, len)) == NULL) { + log_debug("expand_string: calloc"); + return (-1); + } + p = q = label; + while ((q = strstr(p, srch)) != NULL) { + *q = '\0'; + if ((strlcat(tmp, p, len) >= len) || + (strlcat(tmp, repl, len) >= len)) { + log_debug("expand_string: string too long"); + return (-1); + } + q += strlen(srch); + p = q; + } + if (strlcat(tmp, p, len) >= len) { + log_debug("expand_string: string too long"); + return (-1); + } + strlcpy(label, tmp, len); /* always fits */ + free(tmp); + + return (0); +} |