2024-10-28 12:56:18 -07:00
|
|
|
/* $OpenBSD: relay.c,v 1.260 2024/10/28 19:56:18 tb Exp $ */
|
2007-02-21 19:32:39 -08:00
|
|
|
|
|
|
|
/*
|
2014-04-18 06:55:26 -07:00
|
|
|
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
|
2007-02-21 19:32:39 -08:00
|
|
|
*
|
|
|
|
* 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>
|
2007-11-24 09:07:28 -08:00
|
|
|
#include <sys/queue.h>
|
2007-02-21 19:32:39 -08:00
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/tree.h>
|
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/tcp.h>
|
2015-01-22 09:42:09 -08:00
|
|
|
#include <arpa/inet.h>
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2015-01-22 09:42:09 -08:00
|
|
|
#include <limits.h>
|
2019-05-10 02:15:00 -07:00
|
|
|
#include <netdb.h>
|
2016-09-01 03:49:48 -07:00
|
|
|
#include <poll.h>
|
2015-01-22 09:42:09 -08:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2007-02-21 19:32:39 -08:00
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <event.h>
|
2015-01-22 09:42:09 -08:00
|
|
|
#include <siphash.h>
|
|
|
|
#include <imsg.h>
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
#include <tls.h>
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2007-12-07 09:17:00 -08:00
|
|
|
#include "relayd.h"
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2015-01-16 07:06:40 -08:00
|
|
|
#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
|
|
|
|
|
2007-02-21 19:32:39 -08:00
|
|
|
void relay_statistics(int, short, void *);
|
2011-05-09 05:08:46 -07:00
|
|
|
int relay_dispatch_parent(int, struct privsep_proc *,
|
|
|
|
struct imsg *);
|
|
|
|
int relay_dispatch_pfe(int, struct privsep_proc *,
|
|
|
|
struct imsg *);
|
2014-04-18 06:55:26 -07:00
|
|
|
int relay_dispatch_ca(int, struct privsep_proc *,
|
|
|
|
struct imsg *);
|
2014-11-19 02:24:39 -08:00
|
|
|
int relay_dispatch_hce(int, struct privsep_proc *,
|
|
|
|
struct imsg *);
|
2007-02-21 19:32:39 -08:00
|
|
|
void relay_shutdown(void);
|
|
|
|
|
|
|
|
void relay_protodebug(struct relay *);
|
2014-07-09 09:42:05 -07:00
|
|
|
void relay_ruledebug(struct relay_rule *);
|
2011-05-09 05:08:46 -07:00
|
|
|
void relay_init(struct privsep *, struct privsep_proc *p, void *);
|
2007-02-21 19:32:39 -08:00
|
|
|
void relay_launch(void);
|
|
|
|
int relay_socket(struct sockaddr_storage *, in_port_t,
|
2010-12-20 04:38:06 -08:00
|
|
|
struct protocol *, int, int);
|
2007-02-21 19:32:39 -08:00
|
|
|
int relay_socket_listen(struct sockaddr_storage *, in_port_t,
|
|
|
|
struct protocol *);
|
|
|
|
int relay_socket_connect(struct sockaddr_storage *, in_port_t,
|
2008-06-11 11:21:19 -07:00
|
|
|
struct protocol *, int);
|
2007-02-21 19:32:39 -08:00
|
|
|
|
|
|
|
void relay_accept(int, short, void *);
|
2009-08-07 04:21:53 -07:00
|
|
|
void relay_input(struct rsession *);
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2014-12-18 12:55:01 -08:00
|
|
|
void relay_hash_addr(SIPHASH_CTX *, struct sockaddr_storage *, int);
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
int relay_tls_ctx_create(struct relay *);
|
2014-12-12 02:05:09 -08:00
|
|
|
void relay_tls_transaction(struct rsession *,
|
2009-04-01 07:56:38 -07:00
|
|
|
struct ctl_relay_event *);
|
2017-05-27 01:33:25 -07:00
|
|
|
void relay_tls_handshake(int, short, void *);
|
2014-12-12 02:05:09 -08:00
|
|
|
void relay_tls_connected(struct ctl_relay_event *);
|
|
|
|
void relay_tls_readcb(int, short, void *);
|
|
|
|
void relay_tls_writecb(int, short, void *);
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2019-05-13 02:54:07 -07:00
|
|
|
void relay_connect_retry(int, short, void *);
|
|
|
|
void relay_connect_state(struct rsession *,
|
|
|
|
struct ctl_relay_event *, enum relay_state);
|
|
|
|
|
2007-02-21 19:32:39 -08:00
|
|
|
extern void bufferevent_read_pressure_cb(struct evbuffer *, size_t,
|
|
|
|
size_t, void *);
|
|
|
|
|
2012-09-21 02:56:27 -07:00
|
|
|
volatile int relay_sessions;
|
|
|
|
volatile int relay_inflight = 0;
|
2007-02-21 19:32:39 -08:00
|
|
|
objid_t relay_conid;
|
|
|
|
|
2007-12-07 09:17:00 -08:00
|
|
|
static struct relayd *env = NULL;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2011-05-09 05:08:46 -07:00
|
|
|
static struct privsep_proc procs[] = {
|
|
|
|
{ "parent", PROC_PARENT, relay_dispatch_parent },
|
|
|
|
{ "pfe", PROC_PFE, relay_dispatch_pfe },
|
2014-11-19 02:24:39 -08:00
|
|
|
{ "ca", PROC_CA, relay_dispatch_ca },
|
|
|
|
{ "hce", PROC_HCE, relay_dispatch_hce },
|
2011-05-09 05:08:46 -07:00
|
|
|
};
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2016-09-02 04:51:49 -07:00
|
|
|
void
|
2011-05-09 05:08:46 -07:00
|
|
|
relay(struct privsep *ps, struct privsep_proc *p)
|
2007-02-21 19:32:39 -08:00
|
|
|
{
|
2011-05-09 05:08:46 -07:00
|
|
|
env = ps->ps_env;
|
2016-09-02 04:51:49 -07:00
|
|
|
proc_run(ps, p, procs, nitems(procs), relay_init, NULL);
|
2014-07-09 09:42:05 -07:00
|
|
|
relay_http(env);
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
relay_shutdown(void)
|
|
|
|
{
|
2011-05-19 01:56:49 -07:00
|
|
|
config_purge(env, CONFIG_ALL);
|
2007-02-21 19:32:39 -08:00
|
|
|
usleep(200); /* XXX relay needs to shutdown last */
|
|
|
|
}
|
|
|
|
|
2007-11-19 06:48:19 -08:00
|
|
|
void
|
2014-07-09 09:42:05 -07:00
|
|
|
relay_ruledebug(struct relay_rule *rule)
|
2007-11-19 06:48:19 -08:00
|
|
|
{
|
2014-07-09 09:42:05 -07:00
|
|
|
struct kv *kv = NULL;
|
|
|
|
u_int i;
|
2019-05-10 02:15:00 -07:00
|
|
|
char buf[NI_MAXHOST];
|
2007-11-21 06:12:04 -08:00
|
|
|
|
2007-11-19 06:48:19 -08:00
|
|
|
fprintf(stderr, "\t\t");
|
|
|
|
|
2014-07-09 09:42:05 -07:00
|
|
|
switch (rule->rule_action) {
|
|
|
|
case RULE_ACTION_MATCH:
|
|
|
|
fprintf(stderr, "match ");
|
2007-11-19 06:48:19 -08:00
|
|
|
break;
|
2014-07-09 09:42:05 -07:00
|
|
|
case RULE_ACTION_BLOCK:
|
|
|
|
fprintf(stderr, "block ");
|
2007-11-19 06:48:19 -08:00
|
|
|
break;
|
2014-07-09 09:42:05 -07:00
|
|
|
case RULE_ACTION_PASS:
|
|
|
|
fprintf(stderr, "pass ");
|
2007-11-22 02:09:53 -08:00
|
|
|
break;
|
2007-11-19 06:48:19 -08:00
|
|
|
}
|
|
|
|
|
2014-07-09 09:42:05 -07:00
|
|
|
switch (rule->rule_dir) {
|
|
|
|
case RELAY_DIR_ANY:
|
2007-11-19 06:48:19 -08:00
|
|
|
break;
|
2014-07-09 09:42:05 -07:00
|
|
|
case RELAY_DIR_REQUEST:
|
|
|
|
fprintf(stderr, "request ");
|
2007-11-19 06:48:19 -08:00
|
|
|
break;
|
2014-07-09 09:42:05 -07:00
|
|
|
case RELAY_DIR_RESPONSE:
|
|
|
|
fprintf(stderr, "response ");
|
2007-11-23 01:39:42 -08:00
|
|
|
break;
|
2014-07-09 09:42:05 -07:00
|
|
|
default:
|
|
|
|
return;
|
|
|
|
/* NOTREACHED */
|
2007-11-19 06:48:19 -08:00
|
|
|
break;
|
|
|
|
}
|
2014-07-09 09:42:05 -07:00
|
|
|
|
|
|
|
if (rule->rule_flags & RULE_FLAG_QUICK)
|
|
|
|
fprintf(stderr, "quick ");
|
|
|
|
|
2019-05-10 02:15:00 -07:00
|
|
|
switch (rule->rule_af) {
|
|
|
|
case AF_INET:
|
|
|
|
fprintf(stderr, "inet ");
|
|
|
|
break;
|
|
|
|
case AF_INET6:
|
|
|
|
fprintf(stderr, "inet6 ");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rule->rule_src.addr.ss_family != AF_UNSPEC)
|
|
|
|
fprintf(stderr, "from %s/%d ",
|
|
|
|
print_host(&rule->rule_src.addr, buf, sizeof(buf)),
|
|
|
|
rule->rule_src.addr_mask);
|
|
|
|
|
|
|
|
if (rule->rule_dst.addr.ss_family != AF_UNSPEC)
|
|
|
|
fprintf(stderr, "to %s/%d ",
|
|
|
|
print_host(&rule->rule_dst.addr, buf, sizeof(buf)),
|
|
|
|
rule->rule_dst.addr_mask);
|
|
|
|
|
2014-07-09 09:42:05 -07:00
|
|
|
for (i = 1; i < KEY_TYPE_MAX; i++) {
|
|
|
|
kv = &rule->rule_kv[i];
|
|
|
|
if (kv->kv_type != i)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
switch (kv->kv_type) {
|
|
|
|
case KEY_TYPE_COOKIE:
|
|
|
|
fprintf(stderr, "cookie ");
|
|
|
|
break;
|
|
|
|
case KEY_TYPE_HEADER:
|
|
|
|
fprintf(stderr, "header ");
|
|
|
|
break;
|
|
|
|
case KEY_TYPE_PATH:
|
|
|
|
fprintf(stderr, "path ");
|
|
|
|
break;
|
|
|
|
case KEY_TYPE_QUERY:
|
|
|
|
fprintf(stderr, "query ");
|
|
|
|
break;
|
|
|
|
case KEY_TYPE_URL:
|
|
|
|
fprintf(stderr, "url ");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (kv->kv_option) {
|
|
|
|
case KEY_OPTION_APPEND:
|
|
|
|
fprintf(stderr, "append ");
|
|
|
|
break;
|
|
|
|
case KEY_OPTION_SET:
|
|
|
|
fprintf(stderr, "set ");
|
|
|
|
break;
|
|
|
|
case KEY_OPTION_REMOVE:
|
|
|
|
fprintf(stderr, "remove ");
|
|
|
|
break;
|
|
|
|
case KEY_OPTION_HASH:
|
|
|
|
fprintf(stderr, "hash ");
|
|
|
|
break;
|
|
|
|
case KEY_OPTION_LOG:
|
|
|
|
fprintf(stderr, "log ");
|
|
|
|
break;
|
2021-01-09 00:53:57 -08:00
|
|
|
case KEY_OPTION_STRIP:
|
|
|
|
fprintf(stderr, "strip ");
|
|
|
|
break;
|
2014-07-09 09:42:05 -07:00
|
|
|
case KEY_OPTION_NONE:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (kv->kv_digest) {
|
|
|
|
case DIGEST_SHA1:
|
|
|
|
case DIGEST_MD5:
|
|
|
|
fprintf(stderr, "digest ");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-01-09 00:53:57 -08:00
|
|
|
int kvv = (kv->kv_option == KEY_OPTION_STRIP ||
|
|
|
|
kv->kv_value == NULL);
|
2014-07-09 09:42:05 -07:00
|
|
|
fprintf(stderr, "%s%s%s%s%s%s ",
|
|
|
|
kv->kv_key == NULL ? "" : "\"",
|
|
|
|
kv->kv_key == NULL ? "" : kv->kv_key,
|
|
|
|
kv->kv_key == NULL ? "" : "\"",
|
2021-01-09 00:53:57 -08:00
|
|
|
kvv ? "" : " value \"",
|
2014-07-09 09:42:05 -07:00
|
|
|
kv->kv_value == NULL ? "" : kv->kv_value,
|
2021-01-09 00:53:57 -08:00
|
|
|
kvv ? "" : "\"");
|
2014-07-09 09:42:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (rule->rule_tablename[0])
|
|
|
|
fprintf(stderr, "forward to <%s> ", rule->rule_tablename);
|
|
|
|
|
|
|
|
if (rule->rule_tag == -1)
|
|
|
|
fprintf(stderr, "no tag ");
|
|
|
|
else if (rule->rule_tag && rule->rule_tagname[0])
|
|
|
|
fprintf(stderr, "tag \"%s\" ",
|
|
|
|
rule->rule_tagname);
|
|
|
|
|
|
|
|
if (rule->rule_tagged && rule->rule_taggedname[0])
|
|
|
|
fprintf(stderr, "tagged \"%s\" ",
|
|
|
|
rule->rule_taggedname);
|
|
|
|
|
|
|
|
if (rule->rule_label == -1)
|
|
|
|
fprintf(stderr, "no label ");
|
|
|
|
else if (rule->rule_label && rule->rule_labelname[0])
|
|
|
|
fprintf(stderr, "label \"%s\" ",
|
|
|
|
rule->rule_labelname);
|
|
|
|
|
2007-11-19 06:48:19 -08:00
|
|
|
fprintf(stderr, "\n");
|
|
|
|
}
|
|
|
|
|
2007-02-21 19:32:39 -08:00
|
|
|
void
|
|
|
|
relay_protodebug(struct relay *rlay)
|
|
|
|
{
|
2008-01-31 01:56:28 -08:00
|
|
|
struct protocol *proto = rlay->rl_proto;
|
2014-07-09 09:42:05 -07:00
|
|
|
struct relay_rule *rule = NULL;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2011-05-19 01:56:49 -07:00
|
|
|
fprintf(stderr, "protocol %d: name %s\n",
|
|
|
|
proto->id, proto->name);
|
2011-04-12 05:37:22 -07:00
|
|
|
fprintf(stderr, "\tflags: %s, relay flags: %s\n",
|
|
|
|
printb_flags(proto->flags, F_BITS),
|
|
|
|
printb_flags(rlay->rl_conf.flags, F_BITS));
|
|
|
|
if (proto->tcpflags)
|
|
|
|
fprintf(stderr, "\ttcp flags: %s\n",
|
|
|
|
printb_flags(proto->tcpflags, TCPFLAG_BITS));
|
2014-12-12 02:05:09 -08:00
|
|
|
if ((rlay->rl_conf.flags & (F_TLS|F_TLSCLIENT)) && proto->tlsflags)
|
|
|
|
fprintf(stderr, "\ttls flags: %s\n",
|
|
|
|
printb_flags(proto->tlsflags, TLSFLAG_BITS));
|
2016-09-01 03:49:48 -07:00
|
|
|
fprintf(stderr, "\ttls session tickets: %s\n",
|
2017-05-27 01:33:25 -07:00
|
|
|
(proto->tickets == 1) ? "enabled" : "disabled");
|
2007-02-21 19:32:39 -08:00
|
|
|
fprintf(stderr, "\ttype: ");
|
|
|
|
switch (proto->type) {
|
|
|
|
case RELAY_PROTO_TCP:
|
|
|
|
fprintf(stderr, "tcp\n");
|
|
|
|
break;
|
|
|
|
case RELAY_PROTO_HTTP:
|
|
|
|
fprintf(stderr, "http\n");
|
|
|
|
break;
|
2007-09-10 04:59:22 -07:00
|
|
|
case RELAY_PROTO_DNS:
|
|
|
|
fprintf(stderr, "dns\n");
|
|
|
|
break;
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
2007-02-27 05:38:58 -08:00
|
|
|
|
2014-07-09 09:42:05 -07:00
|
|
|
rule = TAILQ_FIRST(&proto->rules);
|
|
|
|
while (rule != NULL) {
|
|
|
|
relay_ruledebug(rule);
|
|
|
|
rule = TAILQ_NEXT(rule, rule_entry);
|
2007-02-27 05:38:58 -08:00
|
|
|
}
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
2011-05-19 01:56:49 -07:00
|
|
|
int
|
|
|
|
relay_privinit(struct relay *rlay)
|
2007-02-21 19:32:39 -08:00
|
|
|
{
|
2011-05-19 01:56:49 -07:00
|
|
|
log_debug("%s: adding relay %s", __func__, rlay->rl_conf.name);
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2017-01-09 06:49:21 -08:00
|
|
|
if (log_getverbose() > 1)
|
2011-05-19 01:56:49 -07:00
|
|
|
relay_protodebug(rlay);
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2011-05-19 01:56:49 -07:00
|
|
|
switch (rlay->rl_proto->type) {
|
|
|
|
case RELAY_PROTO_DNS:
|
2017-07-04 12:59:51 -07:00
|
|
|
relay_udp_privinit(rlay);
|
2011-05-19 01:56:49 -07:00
|
|
|
break;
|
|
|
|
case RELAY_PROTO_TCP:
|
2014-07-09 09:42:05 -07:00
|
|
|
break;
|
2011-05-19 01:56:49 -07:00
|
|
|
case RELAY_PROTO_HTTP:
|
|
|
|
break;
|
|
|
|
}
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2011-05-19 01:56:49 -07:00
|
|
|
if (rlay->rl_conf.flags & F_UDP)
|
|
|
|
rlay->rl_s = relay_udp_bind(&rlay->rl_conf.ss,
|
|
|
|
rlay->rl_conf.port, rlay->rl_proto);
|
|
|
|
else
|
|
|
|
rlay->rl_s = relay_socket_listen(&rlay->rl_conf.ss,
|
|
|
|
rlay->rl_conf.port, rlay->rl_proto);
|
|
|
|
if (rlay->rl_s == -1)
|
|
|
|
return (-1);
|
2007-09-10 04:59:22 -07:00
|
|
|
|
2011-05-19 01:56:49 -07:00
|
|
|
return (0);
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-05-09 05:08:46 -07:00
|
|
|
relay_init(struct privsep *ps, struct privsep_proc *p, void *arg)
|
2007-02-21 19:32:39 -08:00
|
|
|
{
|
|
|
|
struct timeval tv;
|
2010-11-30 06:38:45 -08:00
|
|
|
|
2011-05-19 01:56:49 -07:00
|
|
|
if (config_init(ps->ps_env) == -1)
|
|
|
|
fatal("failed to initialize configuration");
|
|
|
|
|
2011-05-09 05:08:46 -07:00
|
|
|
/* We use a custom shutdown callback */
|
|
|
|
p->p_shutdown = relay_shutdown;
|
|
|
|
|
2010-11-30 06:38:45 -08:00
|
|
|
/* Unlimited file descriptors (use system limits) */
|
|
|
|
socket_rlimit(-1);
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2015-12-04 07:28:55 -08:00
|
|
|
if (pledge("stdio recvfd inet", NULL) == -1)
|
|
|
|
fatal("pledge");
|
|
|
|
|
2007-02-21 19:32:39 -08:00
|
|
|
/* Schedule statistics timer */
|
2016-09-02 07:31:47 -07:00
|
|
|
evtimer_set(&env->sc_statev, relay_statistics, ps);
|
2016-09-02 07:45:51 -07:00
|
|
|
bcopy(&env->sc_conf.statinterval, &tv, sizeof(tv));
|
2008-01-31 01:33:39 -08:00
|
|
|
evtimer_add(&env->sc_statev, &tv);
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
2014-11-19 02:24:39 -08:00
|
|
|
void
|
|
|
|
relay_session_publish(struct rsession *s)
|
|
|
|
{
|
2015-12-02 05:41:27 -08:00
|
|
|
proc_compose(env->sc_ps, PROC_PFE, IMSG_SESS_PUBLISH, s, sizeof(*s));
|
2014-11-19 02:24:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
relay_session_unpublish(struct rsession *s)
|
|
|
|
{
|
2015-12-02 05:41:27 -08:00
|
|
|
proc_compose(env->sc_ps, PROC_PFE, IMSG_SESS_UNPUBLISH,
|
2014-11-19 02:24:39 -08:00
|
|
|
&s->se_id, sizeof(s->se_id));
|
|
|
|
}
|
|
|
|
|
2007-02-21 19:32:39 -08:00
|
|
|
void
|
|
|
|
relay_statistics(int fd, short events, void *arg)
|
|
|
|
{
|
2016-09-02 07:31:47 -07:00
|
|
|
struct privsep *ps = arg;
|
2007-02-21 19:32:39 -08:00
|
|
|
struct relay *rlay;
|
|
|
|
struct ctl_stats crs, *cur;
|
|
|
|
struct timeval tv, tv_now;
|
|
|
|
int resethour = 0, resetday = 0;
|
2009-08-07 04:21:53 -07:00
|
|
|
struct rsession *con, *next_con;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* This is a hack to calculate some average statistics.
|
|
|
|
* It doesn't try to be very accurate, but could be improved...
|
|
|
|
*/
|
|
|
|
|
|
|
|
timerclear(&tv);
|
2013-03-10 16:32:53 -07:00
|
|
|
getmonotime(&tv_now);
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2008-01-31 01:56:28 -08:00
|
|
|
TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
|
2007-02-21 19:32:39 -08:00
|
|
|
bzero(&crs, sizeof(crs));
|
|
|
|
resethour = resetday = 0;
|
|
|
|
|
2016-09-02 07:31:47 -07:00
|
|
|
cur = &rlay->rl_stats[ps->ps_instance];
|
2007-02-21 19:32:39 -08:00
|
|
|
cur->cnt += cur->last;
|
|
|
|
cur->tick++;
|
|
|
|
cur->avg = (cur->last + cur->avg) / 2;
|
|
|
|
cur->last_hour += cur->last;
|
2016-09-02 07:45:51 -07:00
|
|
|
if ((cur->tick %
|
|
|
|
(3600 / env->sc_conf.statinterval.tv_sec)) == 0) {
|
2007-02-21 19:32:39 -08:00
|
|
|
cur->avg_hour = (cur->last_hour + cur->avg_hour) / 2;
|
|
|
|
resethour++;
|
|
|
|
}
|
|
|
|
cur->last_day += cur->last;
|
2016-09-02 07:45:51 -07:00
|
|
|
if ((cur->tick %
|
|
|
|
(86400 / env->sc_conf.statinterval.tv_sec)) == 0) {
|
2007-02-21 19:32:39 -08:00
|
|
|
cur->avg_day = (cur->last_day + cur->avg_day) / 2;
|
|
|
|
resethour++;
|
|
|
|
}
|
|
|
|
bcopy(cur, &crs, sizeof(crs));
|
|
|
|
|
|
|
|
cur->last = 0;
|
|
|
|
if (resethour)
|
|
|
|
cur->last_hour = 0;
|
|
|
|
if (resetday)
|
|
|
|
cur->last_day = 0;
|
|
|
|
|
2008-01-31 01:56:28 -08:00
|
|
|
crs.id = rlay->rl_conf.id;
|
2016-09-02 07:31:47 -07:00
|
|
|
crs.proc = ps->ps_instance;
|
2015-12-02 05:41:27 -08:00
|
|
|
proc_compose(env->sc_ps, PROC_PFE, IMSG_STATISTICS,
|
2007-02-21 19:32:39 -08:00
|
|
|
&crs, sizeof(crs));
|
|
|
|
|
2008-01-31 01:56:28 -08:00
|
|
|
for (con = SPLAY_ROOT(&rlay->rl_sessions);
|
2007-02-21 19:32:39 -08:00
|
|
|
con != NULL; con = next_con) {
|
2007-09-05 01:48:42 -07:00
|
|
|
next_con = SPLAY_NEXT(session_tree,
|
2008-01-31 01:56:28 -08:00
|
|
|
&rlay->rl_sessions, con);
|
2008-01-31 04:12:50 -08:00
|
|
|
timersub(&tv_now, &con->se_tv_last, &tv);
|
2008-01-31 01:56:28 -08:00
|
|
|
if (timercmp(&tv, &rlay->rl_conf.timeout, >=))
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, "hard timeout", 1);
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Schedule statistics timer */
|
2016-09-02 07:31:47 -07:00
|
|
|
evtimer_set(&env->sc_statev, relay_statistics, ps);
|
2016-09-02 07:45:51 -07:00
|
|
|
bcopy(&env->sc_conf.statinterval, &tv, sizeof(tv));
|
2008-01-31 01:33:39 -08:00
|
|
|
evtimer_add(&env->sc_statev, &tv);
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
relay_launch(void)
|
|
|
|
{
|
2012-10-03 01:33:31 -07:00
|
|
|
void (*callback)(int, short, void *);
|
|
|
|
struct relay *rlay;
|
|
|
|
struct host *host;
|
|
|
|
struct relay_table *rlt;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2008-01-31 01:56:28 -08:00
|
|
|
TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
|
2014-12-12 02:05:09 -08:00
|
|
|
if ((rlay->rl_conf.flags & (F_TLS|F_TLSCLIENT)) &&
|
2017-05-27 01:33:25 -07:00
|
|
|
relay_tls_ctx_create(rlay) == -1)
|
2017-05-28 03:39:15 -07:00
|
|
|
fatalx("%s: failed to create TLS context", __func__);
|
2011-05-19 01:56:49 -07:00
|
|
|
|
2012-10-03 01:33:31 -07:00
|
|
|
TAILQ_FOREACH(rlt, &rlay->rl_tables, rlt_entry) {
|
2014-07-09 09:42:05 -07:00
|
|
|
/*
|
|
|
|
* set rule->rule_table in advance and save time
|
|
|
|
* looking up for this later on rule/connection
|
|
|
|
* evalution
|
|
|
|
*/
|
|
|
|
rule_settable(&rlay->rl_proto->rules, rlt);
|
|
|
|
|
2014-12-18 12:55:01 -08:00
|
|
|
rlt->rlt_index = 0;
|
2012-10-03 01:33:31 -07:00
|
|
|
rlt->rlt_nhosts = 0;
|
|
|
|
TAILQ_FOREACH(host, &rlt->rlt_table->hosts, entry) {
|
|
|
|
if (rlt->rlt_nhosts >= RELAY_MAXHOSTS)
|
2017-05-28 03:39:15 -07:00
|
|
|
fatal("%s: too many hosts in table",
|
|
|
|
__func__);
|
2012-10-03 01:33:31 -07:00
|
|
|
host->idx = rlt->rlt_nhosts;
|
|
|
|
rlt->rlt_host[rlt->rlt_nhosts++] = host;
|
2011-05-19 01:56:49 -07:00
|
|
|
}
|
|
|
|
log_info("adding %d hosts from table %s%s",
|
2012-10-03 01:33:31 -07:00
|
|
|
rlt->rlt_nhosts, rlt->rlt_table->conf.name,
|
|
|
|
rlt->rlt_table->conf.check ? "" : " (no check)");
|
2011-05-19 01:56:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (rlay->rl_proto->type) {
|
|
|
|
case RELAY_PROTO_DNS:
|
2017-07-04 12:59:51 -07:00
|
|
|
relay_udp_init(env, rlay);
|
2011-05-19 01:56:49 -07:00
|
|
|
break;
|
|
|
|
case RELAY_PROTO_TCP:
|
|
|
|
case RELAY_PROTO_HTTP:
|
2014-07-09 09:42:05 -07:00
|
|
|
relay_http_init(rlay);
|
2011-05-19 01:56:49 -07:00
|
|
|
/* Use defaults */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-05-05 05:01:43 -07:00
|
|
|
log_debug("%s: running relay %s", __func__,
|
|
|
|
rlay->rl_conf.name);
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2008-01-31 01:56:28 -08:00
|
|
|
rlay->rl_up = HOST_UP;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2008-01-31 01:56:28 -08:00
|
|
|
if (rlay->rl_conf.flags & F_UDP)
|
2007-09-10 04:59:22 -07:00
|
|
|
callback = relay_udp_server;
|
|
|
|
else
|
|
|
|
callback = relay_accept;
|
|
|
|
|
2012-04-11 01:25:26 -07:00
|
|
|
event_set(&rlay->rl_ev, rlay->rl_s, EV_READ,
|
2007-09-10 04:59:22 -07:00
|
|
|
callback, rlay);
|
2008-01-31 01:56:28 -08:00
|
|
|
event_add(&rlay->rl_ev, NULL);
|
2012-04-11 01:25:26 -07:00
|
|
|
evtimer_set(&rlay->rl_evt, callback, rlay);
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2007-09-10 04:59:22 -07:00
|
|
|
relay_socket_af(struct sockaddr_storage *ss, in_port_t port)
|
2007-02-21 19:32:39 -08:00
|
|
|
{
|
|
|
|
switch (ss->ss_family) {
|
|
|
|
case AF_INET:
|
|
|
|
((struct sockaddr_in *)ss)->sin_port = port;
|
|
|
|
((struct sockaddr_in *)ss)->sin_len =
|
|
|
|
sizeof(struct sockaddr_in);
|
|
|
|
break;
|
|
|
|
case AF_INET6:
|
|
|
|
((struct sockaddr_in6 *)ss)->sin6_port = port;
|
|
|
|
((struct sockaddr_in6 *)ss)->sin6_len =
|
|
|
|
sizeof(struct sockaddr_in6);
|
|
|
|
break;
|
2007-09-10 04:59:22 -07:00
|
|
|
default:
|
|
|
|
return (-1);
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
2007-09-10 04:59:22 -07:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2011-04-07 06:22:29 -07:00
|
|
|
in_port_t
|
|
|
|
relay_socket_getport(struct sockaddr_storage *ss)
|
|
|
|
{
|
|
|
|
switch (ss->ss_family) {
|
|
|
|
case AF_INET:
|
|
|
|
return (((struct sockaddr_in *)ss)->sin_port);
|
|
|
|
case AF_INET6:
|
|
|
|
return (((struct sockaddr_in6 *)ss)->sin6_port);
|
|
|
|
default:
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* NOTREACHED */
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2007-09-10 04:59:22 -07:00
|
|
|
int
|
|
|
|
relay_socket(struct sockaddr_storage *ss, in_port_t port,
|
2010-12-20 04:38:06 -08:00
|
|
|
struct protocol *proto, int fd, int reuseport)
|
2007-09-10 04:59:22 -07:00
|
|
|
{
|
2014-06-27 00:49:08 -07:00
|
|
|
struct linger lng;
|
|
|
|
int s = -1, val;
|
2007-09-10 04:59:22 -07:00
|
|
|
|
|
|
|
if (relay_socket_af(ss, port) == -1)
|
|
|
|
goto bad;
|
|
|
|
|
2015-11-28 01:52:07 -08:00
|
|
|
s = fd == -1 ? socket(ss->ss_family,
|
|
|
|
SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP) : fd;
|
2008-06-11 11:21:19 -07:00
|
|
|
if (s == -1)
|
2007-02-21 19:32:39 -08:00
|
|
|
goto bad;
|
2007-03-13 05:04:52 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Socket options
|
|
|
|
*/
|
2007-02-21 19:32:39 -08:00
|
|
|
bzero(&lng, sizeof(lng));
|
|
|
|
if (setsockopt(s, SOL_SOCKET, SO_LINGER, &lng, sizeof(lng)) == -1)
|
|
|
|
goto bad;
|
2010-12-20 04:38:06 -08:00
|
|
|
if (reuseport) {
|
|
|
|
val = 1;
|
|
|
|
if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &val,
|
|
|
|
sizeof(int)) == -1)
|
|
|
|
goto bad;
|
|
|
|
}
|
2007-03-13 05:04:52 -07:00
|
|
|
if (proto->tcpflags & TCPFLAG_BUFSIZ) {
|
|
|
|
val = proto->tcpbufsiz;
|
|
|
|
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
|
|
|
|
&val, sizeof(val)) == -1)
|
|
|
|
goto bad;
|
|
|
|
val = proto->tcpbufsiz;
|
|
|
|
if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
|
|
|
|
&val, sizeof(val)) == -1)
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* IP options
|
|
|
|
*/
|
|
|
|
if (proto->tcpflags & TCPFLAG_IPTTL) {
|
|
|
|
val = (int)proto->tcpipttl;
|
2016-11-10 05:21:58 -08:00
|
|
|
switch (ss->ss_family) {
|
|
|
|
case AF_INET:
|
|
|
|
if (setsockopt(s, IPPROTO_IP, IP_TTL,
|
|
|
|
&val, sizeof(val)) == -1)
|
|
|
|
goto bad;
|
|
|
|
break;
|
|
|
|
case AF_INET6:
|
|
|
|
if (setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
|
|
|
|
&val, sizeof(val)) == -1)
|
|
|
|
goto bad;
|
|
|
|
break;
|
|
|
|
}
|
2007-03-13 05:04:52 -07:00
|
|
|
}
|
|
|
|
if (proto->tcpflags & TCPFLAG_IPMINTTL) {
|
|
|
|
val = (int)proto->tcpipminttl;
|
2016-11-10 05:21:58 -08:00
|
|
|
switch (ss->ss_family) {
|
|
|
|
case AF_INET:
|
|
|
|
if (setsockopt(s, IPPROTO_IP, IP_MINTTL,
|
|
|
|
&val, sizeof(val)) == -1)
|
|
|
|
goto bad;
|
|
|
|
break;
|
|
|
|
case AF_INET6:
|
|
|
|
if (setsockopt(s, IPPROTO_IPV6, IPV6_MINHOPCOUNT,
|
|
|
|
&val, sizeof(val)) == -1)
|
|
|
|
goto bad;
|
|
|
|
break;
|
|
|
|
}
|
2007-03-13 05:04:52 -07:00
|
|
|
}
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2007-03-13 05:04:52 -07:00
|
|
|
/*
|
|
|
|
* TCP options
|
|
|
|
*/
|
2007-02-21 19:32:39 -08:00
|
|
|
if (proto->tcpflags & (TCPFLAG_NODELAY|TCPFLAG_NNODELAY)) {
|
|
|
|
if (proto->tcpflags & TCPFLAG_NNODELAY)
|
|
|
|
val = 0;
|
|
|
|
else
|
|
|
|
val = 1;
|
|
|
|
if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY,
|
|
|
|
&val, sizeof(val)) == -1)
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
if (proto->tcpflags & (TCPFLAG_SACK|TCPFLAG_NSACK)) {
|
|
|
|
if (proto->tcpflags & TCPFLAG_NSACK)
|
|
|
|
val = 0;
|
|
|
|
else
|
|
|
|
val = 1;
|
|
|
|
if (setsockopt(s, IPPROTO_TCP, TCP_SACK_ENABLE,
|
|
|
|
&val, sizeof(val)) == -1)
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (s);
|
|
|
|
|
|
|
|
bad:
|
|
|
|
if (s != -1)
|
|
|
|
close(s);
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
relay_socket_connect(struct sockaddr_storage *ss, in_port_t port,
|
2008-06-11 11:21:19 -07:00
|
|
|
struct protocol *proto, int fd)
|
2007-02-21 19:32:39 -08:00
|
|
|
{
|
2008-06-11 11:21:19 -07:00
|
|
|
int s;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2010-12-20 04:38:06 -08:00
|
|
|
if ((s = relay_socket(ss, port, proto, fd, 0)) == -1)
|
2007-02-21 19:32:39 -08:00
|
|
|
return (-1);
|
|
|
|
|
|
|
|
if (connect(s, (struct sockaddr *)ss, ss->ss_len) == -1) {
|
|
|
|
if (errno != EINPROGRESS)
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (s);
|
|
|
|
|
|
|
|
bad:
|
|
|
|
close(s);
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
relay_socket_listen(struct sockaddr_storage *ss, in_port_t port,
|
|
|
|
struct protocol *proto)
|
|
|
|
{
|
|
|
|
int s;
|
|
|
|
|
2010-12-20 04:38:06 -08:00
|
|
|
if ((s = relay_socket(ss, port, proto, -1, 1)) == -1)
|
2007-02-21 19:32:39 -08:00
|
|
|
return (-1);
|
|
|
|
|
|
|
|
if (bind(s, (struct sockaddr *)ss, ss->ss_len) == -1)
|
|
|
|
goto bad;
|
2007-02-23 16:22:32 -08:00
|
|
|
if (listen(s, proto->tcpbacklog) == -1)
|
2007-02-21 19:32:39 -08:00
|
|
|
goto bad;
|
|
|
|
|
|
|
|
return (s);
|
|
|
|
|
|
|
|
bad:
|
|
|
|
close(s);
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
relay_connected(int fd, short sig, void *arg)
|
|
|
|
{
|
2019-05-13 02:54:07 -07:00
|
|
|
char obuf[128];
|
2013-01-17 12:34:18 -08:00
|
|
|
struct rsession *con = arg;
|
|
|
|
struct relay *rlay = con->se_relay;
|
2015-07-18 09:01:28 -07:00
|
|
|
struct protocol *proto = rlay->rl_proto;
|
2007-02-21 19:32:39 -08:00
|
|
|
evbuffercb outrd = relay_read;
|
|
|
|
evbuffercb outwr = relay_write;
|
|
|
|
struct bufferevent *bev;
|
2009-04-01 07:56:38 -07:00
|
|
|
struct ctl_relay_event *out = &con->se_out;
|
2017-12-27 07:53:30 -08:00
|
|
|
char *msg;
|
2012-07-13 00:54:14 -07:00
|
|
|
socklen_t len;
|
|
|
|
int error;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
|
|
|
if (sig == EV_TIMEOUT) {
|
2012-09-20 05:30:20 -07:00
|
|
|
relay_abort_http(con, 504, "connect timeout", 0);
|
2007-02-21 19:32:39 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-07-13 00:54:14 -07:00
|
|
|
len = sizeof(error);
|
2017-12-27 07:53:30 -08:00
|
|
|
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) == -1) {
|
|
|
|
relay_abort_http(con, 500, "getsockopt failed", 0);
|
2012-10-04 13:53:30 -07:00
|
|
|
return;
|
2012-07-13 00:54:14 -07:00
|
|
|
}
|
2017-12-27 07:53:30 -08:00
|
|
|
if (error) {
|
|
|
|
errno = error;
|
|
|
|
if (asprintf(&msg, "socket error: %s",
|
|
|
|
strerror(error)) >= 0) {
|
|
|
|
relay_abort_http(con, 500, msg, 0);
|
|
|
|
free(msg);
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
relay_abort_http(con, 500,
|
|
|
|
"socket error and asprintf failed", 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2012-07-13 00:54:14 -07:00
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
if ((rlay->rl_conf.flags & F_TLSCLIENT) && (out->tls == NULL)) {
|
2014-12-12 02:05:09 -08:00
|
|
|
relay_tls_transaction(con, out);
|
2009-04-01 07:56:38 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-09 09:42:05 -07:00
|
|
|
DPRINTF("%s: session %d: successful", __func__, con->se_id);
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2019-05-13 02:54:07 -07:00
|
|
|
/* Log destination if it was changed in a keep-alive connection */
|
|
|
|
if ((con->se_table != con->se_table0) &&
|
|
|
|
(env->sc_conf.opts & (RELAYD_OPT_LOGCON|RELAYD_OPT_LOGCONERR))) {
|
|
|
|
con->se_table0 = con->se_table;
|
|
|
|
memset(&obuf, 0, sizeof(obuf));
|
|
|
|
(void)print_host(&con->se_out.ss, obuf, sizeof(obuf));
|
|
|
|
if (asprintf(&msg, " -> %s:%d",
|
|
|
|
obuf, ntohs(con->se_out.port)) == -1) {
|
|
|
|
relay_abort_http(con, 500,
|
|
|
|
"connection changed and asprintf failed", 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
relay_log(con, msg);
|
|
|
|
free(msg);
|
|
|
|
}
|
|
|
|
|
2008-01-31 01:56:28 -08:00
|
|
|
switch (rlay->rl_proto->type) {
|
2007-02-27 05:38:58 -08:00
|
|
|
case RELAY_PROTO_HTTP:
|
2014-07-09 09:42:05 -07:00
|
|
|
if (relay_httpdesc_init(out) == -1) {
|
|
|
|
relay_close(con,
|
2018-08-06 10:31:31 -07:00
|
|
|
"failed to allocate http descriptor", 1);
|
2014-07-09 09:42:05 -07:00
|
|
|
return;
|
2007-02-27 05:38:58 -08:00
|
|
|
}
|
2014-07-09 09:42:05 -07:00
|
|
|
con->se_out.toread = TOREAD_HTTP_HEADER;
|
|
|
|
outrd = relay_read_http;
|
2007-02-27 05:38:58 -08:00
|
|
|
break;
|
|
|
|
case RELAY_PROTO_TCP:
|
2011-09-21 11:45:40 -07:00
|
|
|
/* Use defaults */
|
2007-02-27 05:38:58 -08:00
|
|
|
break;
|
|
|
|
default:
|
2017-05-28 03:39:15 -07:00
|
|
|
fatalx("%s: unknown protocol", __func__);
|
2007-02-27 05:38:58 -08:00
|
|
|
}
|
|
|
|
|
2007-02-21 19:32:39 -08:00
|
|
|
/*
|
|
|
|
* Relay <-> Server
|
|
|
|
*/
|
2008-01-31 04:12:50 -08:00
|
|
|
bev = bufferevent_new(fd, outrd, outwr, relay_error, &con->se_out);
|
2007-02-21 19:32:39 -08:00
|
|
|
if (bev == NULL) {
|
2012-09-20 05:30:20 -07:00
|
|
|
relay_abort_http(con, 500,
|
2007-11-26 01:38:25 -08:00
|
|
|
"failed to allocate output buffer event", 0);
|
2007-02-21 19:32:39 -08:00
|
|
|
return;
|
|
|
|
}
|
2017-11-27 09:35:49 -08:00
|
|
|
/* write pending output buffer now */
|
|
|
|
if (bufferevent_write_buffer(bev, con->se_out.output)) {
|
|
|
|
relay_abort_http(con, 500, strerror(errno), 0);
|
|
|
|
return;
|
|
|
|
}
|
2008-01-31 04:12:50 -08:00
|
|
|
con->se_out.bev = bev;
|
2009-04-01 07:56:38 -07:00
|
|
|
|
2014-12-12 02:05:09 -08:00
|
|
|
/* Initialize the TLS wrapper */
|
2017-05-27 01:33:25 -07:00
|
|
|
if ((rlay->rl_conf.flags & F_TLSCLIENT) && (out->tls != NULL))
|
2014-12-12 02:05:09 -08:00
|
|
|
relay_tls_connected(out);
|
2009-04-01 07:56:38 -07:00
|
|
|
|
2007-02-21 19:32:39 -08:00
|
|
|
bufferevent_settimeout(bev,
|
2008-01-31 01:56:28 -08:00
|
|
|
rlay->rl_conf.timeout.tv_sec, rlay->rl_conf.timeout.tv_sec);
|
2015-07-18 09:01:28 -07:00
|
|
|
bufferevent_setwatermark(bev, EV_WRITE,
|
|
|
|
RELAY_MIN_PREFETCHED * proto->tcpbufsiz, 0);
|
2007-02-21 19:32:39 -08:00
|
|
|
bufferevent_enable(bev, EV_READ|EV_WRITE);
|
2015-07-18 09:01:28 -07:00
|
|
|
if (con->se_in.bev)
|
|
|
|
bufferevent_enable(con->se_in.bev, EV_READ);
|
2011-09-21 11:45:40 -07:00
|
|
|
|
|
|
|
if (relay_splice(&con->se_out) == -1)
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, strerror(errno), 1);
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-08-07 04:21:53 -07:00
|
|
|
relay_input(struct rsession *con)
|
2007-02-21 19:32:39 -08:00
|
|
|
{
|
2013-01-17 12:34:18 -08:00
|
|
|
struct relay *rlay = con->se_relay;
|
2015-07-18 09:01:28 -07:00
|
|
|
struct protocol *proto = rlay->rl_proto;
|
2007-02-21 19:32:39 -08:00
|
|
|
evbuffercb inrd = relay_read;
|
|
|
|
evbuffercb inwr = relay_write;
|
|
|
|
|
2008-01-31 01:56:28 -08:00
|
|
|
switch (rlay->rl_proto->type) {
|
2007-02-21 19:32:39 -08:00
|
|
|
case RELAY_PROTO_HTTP:
|
2021-03-24 13:59:53 -07:00
|
|
|
if (relay_http_priv_init(con) == -1) {
|
2014-07-09 09:42:05 -07:00
|
|
|
relay_close(con,
|
2018-08-06 10:31:31 -07:00
|
|
|
"failed to allocate http descriptor", 1);
|
2014-07-09 09:42:05 -07:00
|
|
|
return;
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
2014-07-09 09:42:05 -07:00
|
|
|
con->se_in.toread = TOREAD_HTTP_HEADER;
|
|
|
|
inrd = relay_read_http;
|
2007-02-21 19:32:39 -08:00
|
|
|
break;
|
|
|
|
case RELAY_PROTO_TCP:
|
|
|
|
/* Use defaults */
|
|
|
|
break;
|
|
|
|
default:
|
2017-05-28 03:39:15 -07:00
|
|
|
fatalx("%s: unknown protocol", __func__);
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Client <-> Relay
|
|
|
|
*/
|
2008-01-31 04:12:50 -08:00
|
|
|
con->se_in.bev = bufferevent_new(con->se_in.s, inrd, inwr,
|
|
|
|
relay_error, &con->se_in);
|
|
|
|
if (con->se_in.bev == NULL) {
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, "failed to allocate input buffer event", 1);
|
2007-02-21 19:32:39 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-12-12 02:05:09 -08:00
|
|
|
/* Initialize the TLS wrapper */
|
2017-05-27 01:33:25 -07:00
|
|
|
if ((rlay->rl_conf.flags & F_TLS) && con->se_in.tls != NULL)
|
2014-12-12 02:05:09 -08:00
|
|
|
relay_tls_connected(&con->se_in);
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2008-01-31 04:12:50 -08:00
|
|
|
bufferevent_settimeout(con->se_in.bev,
|
2008-01-31 01:56:28 -08:00
|
|
|
rlay->rl_conf.timeout.tv_sec, rlay->rl_conf.timeout.tv_sec);
|
2015-07-18 09:01:28 -07:00
|
|
|
bufferevent_setwatermark(con->se_in.bev, EV_WRITE,
|
|
|
|
RELAY_MIN_PREFETCHED * proto->tcpbufsiz, 0);
|
2008-01-31 04:12:50 -08:00
|
|
|
bufferevent_enable(con->se_in.bev, EV_READ|EV_WRITE);
|
2011-09-21 11:45:40 -07:00
|
|
|
|
|
|
|
if (relay_splice(&con->se_in) == -1)
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, strerror(errno), 1);
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
relay_write(struct bufferevent *bev, void *arg)
|
|
|
|
{
|
2013-01-17 12:34:18 -08:00
|
|
|
struct ctl_relay_event *cre = arg;
|
2011-04-24 03:07:43 -07:00
|
|
|
struct rsession *con = cre->con;
|
2013-03-09 06:43:06 -08:00
|
|
|
|
2013-03-10 16:32:53 -07:00
|
|
|
getmonotime(&con->se_tv_last);
|
|
|
|
|
2017-08-28 10:31:00 -07:00
|
|
|
if (con->se_done && EVBUFFER_LENGTH(EVBUFFER_OUTPUT(bev)) == 0)
|
2013-03-09 06:43:06 -08:00
|
|
|
goto done;
|
2015-07-18 09:01:28 -07:00
|
|
|
if (cre->dst->bev)
|
|
|
|
bufferevent_enable(cre->dst->bev, EV_READ);
|
2017-08-28 10:31:00 -07:00
|
|
|
if (relay_splice(cre->dst) == -1)
|
|
|
|
goto fail;
|
2015-07-18 09:01:28 -07:00
|
|
|
|
2013-03-09 06:43:06 -08:00
|
|
|
return;
|
|
|
|
done:
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, "last write (done)", 0);
|
2013-03-09 06:43:06 -08:00
|
|
|
return;
|
|
|
|
fail:
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, strerror(errno), 1);
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
2007-11-20 07:54:55 -08:00
|
|
|
void
|
|
|
|
relay_dump(struct ctl_relay_event *cre, const void *buf, size_t len)
|
|
|
|
{
|
2008-03-20 15:24:46 -07:00
|
|
|
if (!len)
|
|
|
|
return;
|
|
|
|
|
2007-11-20 07:54:55 -08:00
|
|
|
/*
|
|
|
|
* This function will dump the specified message directly
|
|
|
|
* to the underlying session, without waiting for success
|
|
|
|
* of non-blocking events etc. This is useful to print an
|
|
|
|
* error message before gracefully closing the session.
|
|
|
|
*/
|
2017-05-27 01:33:25 -07:00
|
|
|
if (cre->tls != NULL)
|
|
|
|
(void)tls_write(cre->tls, buf, len);
|
2007-11-20 07:54:55 -08:00
|
|
|
else
|
|
|
|
(void)write(cre->s, buf, len);
|
|
|
|
}
|
|
|
|
|
2007-02-21 19:32:39 -08:00
|
|
|
void
|
|
|
|
relay_read(struct bufferevent *bev, void *arg)
|
|
|
|
{
|
2013-01-17 12:34:18 -08:00
|
|
|
struct ctl_relay_event *cre = arg;
|
2011-04-24 03:07:43 -07:00
|
|
|
struct rsession *con = cre->con;
|
2015-07-18 09:01:28 -07:00
|
|
|
struct protocol *proto = con->se_relay->rl_proto;
|
2007-02-21 19:32:39 -08:00
|
|
|
struct evbuffer *src = EVBUFFER_INPUT(bev);
|
|
|
|
|
2013-03-10 16:32:53 -07:00
|
|
|
getmonotime(&con->se_tv_last);
|
2014-07-13 17:11:12 -07:00
|
|
|
cre->timedout = 0;
|
2013-03-10 16:32:53 -07:00
|
|
|
|
2007-02-21 19:32:39 -08:00
|
|
|
if (!EVBUFFER_LENGTH(src))
|
|
|
|
return;
|
2007-02-26 07:41:44 -08:00
|
|
|
if (relay_bufferevent_write_buffer(cre->dst, src) == -1)
|
|
|
|
goto fail;
|
2008-01-31 04:12:50 -08:00
|
|
|
if (con->se_done)
|
2007-02-21 19:32:39 -08:00
|
|
|
goto done;
|
2011-03-12 13:06:40 -08:00
|
|
|
if (cre->dst->bev)
|
|
|
|
bufferevent_enable(cre->dst->bev, EV_READ);
|
2015-07-18 09:01:28 -07:00
|
|
|
if (cre->dst->bev && EVBUFFER_LENGTH(EVBUFFER_OUTPUT(cre->dst->bev)) >
|
|
|
|
(size_t)RELAY_MAX_PREFETCH * proto->tcpbufsiz)
|
|
|
|
bufferevent_disable(bev, EV_READ);
|
|
|
|
|
2007-02-21 19:32:39 -08:00
|
|
|
return;
|
|
|
|
done:
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, "last read (done)", 0);
|
2007-02-26 07:41:44 -08:00
|
|
|
return;
|
|
|
|
fail:
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, strerror(errno), 1);
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
2015-05-18 09:57:20 -07:00
|
|
|
/*
|
|
|
|
* Splice sockets from cre to cre->dst if applicable. Returns:
|
|
|
|
* -1 socket splicing has failed
|
|
|
|
* 0 socket splicing is currently not possible
|
|
|
|
* 1 socket splicing was successful
|
|
|
|
*/
|
2011-09-21 11:45:40 -07:00
|
|
|
int
|
|
|
|
relay_splice(struct ctl_relay_event *cre)
|
|
|
|
{
|
|
|
|
struct rsession *con = cre->con;
|
2013-01-17 12:34:18 -08:00
|
|
|
struct relay *rlay = con->se_relay;
|
2011-09-21 11:45:40 -07:00
|
|
|
struct protocol *proto = rlay->rl_proto;
|
|
|
|
struct splice sp;
|
|
|
|
|
2014-12-12 02:05:09 -08:00
|
|
|
if ((rlay->rl_conf.flags & (F_TLS|F_TLSCLIENT)) ||
|
2011-09-21 11:45:40 -07:00
|
|
|
(proto->tcpflags & TCPFLAG_NSPLICE))
|
|
|
|
return (0);
|
|
|
|
|
2013-03-09 06:43:06 -08:00
|
|
|
if (cre->splicelen >= 0)
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
/* still not connected */
|
|
|
|
if (cre->bev == NULL || cre->dst->bev == NULL)
|
|
|
|
return (0);
|
|
|
|
|
2015-07-28 03:24:26 -07:00
|
|
|
if (!(cre->toread == TOREAD_UNLIMITED || cre->toread > 0)) {
|
2013-03-09 06:43:06 -08:00
|
|
|
DPRINTF("%s: session %d: splice dir %d, nothing to read %lld",
|
|
|
|
__func__, con->se_id, cre->dir, cre->toread);
|
2011-09-21 11:45:40 -07:00
|
|
|
return (0);
|
2013-03-09 06:43:06 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* do not splice before buffers have not been completely flushed */
|
|
|
|
if (EVBUFFER_LENGTH(cre->bev->input) ||
|
|
|
|
EVBUFFER_LENGTH(cre->dst->bev->output)) {
|
|
|
|
DPRINTF("%s: session %d: splice dir %d, dirty buffer",
|
|
|
|
__func__, con->se_id, cre->dir);
|
|
|
|
bufferevent_disable(cre->bev, EV_READ);
|
|
|
|
return (0);
|
|
|
|
}
|
2011-09-21 11:45:40 -07:00
|
|
|
|
|
|
|
bzero(&sp, sizeof(sp));
|
|
|
|
sp.sp_fd = cre->dst->s;
|
2013-03-09 06:43:06 -08:00
|
|
|
sp.sp_max = cre->toread > 0 ? cre->toread : 0;
|
2014-07-09 09:42:05 -07:00
|
|
|
bcopy(&rlay->rl_conf.timeout, &sp.sp_idle, sizeof(sp.sp_idle));
|
2011-09-21 11:45:40 -07:00
|
|
|
if (setsockopt(cre->s, SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp)) == -1) {
|
|
|
|
log_debug("%s: session %d: splice dir %d failed: %s",
|
|
|
|
__func__, con->se_id, cre->dir, strerror(errno));
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
cre->splicelen = 0;
|
2013-03-09 06:43:06 -08:00
|
|
|
bufferevent_enable(cre->bev, EV_READ);
|
|
|
|
|
|
|
|
DPRINTF("%s: session %d: splice dir %d, maximum %lld, successful",
|
|
|
|
__func__, con->se_id, cre->dir, cre->toread);
|
|
|
|
|
2015-05-18 09:57:20 -07:00
|
|
|
return (1);
|
2011-09-21 11:45:40 -07:00
|
|
|
}
|
|
|
|
|
2011-04-12 04:45:18 -07:00
|
|
|
int
|
|
|
|
relay_splicelen(struct ctl_relay_event *cre)
|
|
|
|
{
|
2011-09-21 11:45:40 -07:00
|
|
|
struct rsession *con = cre->con;
|
|
|
|
off_t len;
|
|
|
|
socklen_t optlen;
|
2011-04-12 04:45:18 -07:00
|
|
|
|
2013-03-09 06:43:06 -08:00
|
|
|
if (cre->splicelen < 0)
|
|
|
|
return (0);
|
|
|
|
|
2011-04-12 04:45:18 -07:00
|
|
|
optlen = sizeof(len);
|
|
|
|
if (getsockopt(cre->s, SOL_SOCKET, SO_SPLICE, &len, &optlen) == -1) {
|
2011-09-21 11:45:40 -07:00
|
|
|
log_debug("%s: session %d: splice dir %d get length failed: %s",
|
|
|
|
__func__, con->se_id, cre->dir, strerror(errno));
|
|
|
|
return (-1);
|
2011-04-12 04:45:18 -07:00
|
|
|
}
|
2013-03-09 06:43:06 -08:00
|
|
|
|
|
|
|
DPRINTF("%s: session %d: splice dir %d, length %lld",
|
|
|
|
__func__, con->se_id, cre->dir, len);
|
|
|
|
|
2011-04-12 04:45:18 -07:00
|
|
|
if (len > cre->splicelen) {
|
2013-03-10 16:32:53 -07:00
|
|
|
getmonotime(&con->se_tv_last);
|
|
|
|
|
2011-04-12 04:45:18 -07:00
|
|
|
cre->splicelen = len;
|
|
|
|
return (1);
|
|
|
|
}
|
2013-03-09 06:43:06 -08:00
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
relay_spliceadjust(struct ctl_relay_event *cre)
|
|
|
|
{
|
|
|
|
if (cre->splicelen < 0)
|
|
|
|
return (0);
|
|
|
|
if (relay_splicelen(cre) == -1)
|
|
|
|
return (-1);
|
|
|
|
if (cre->splicelen > 0 && cre->toread > 0)
|
|
|
|
cre->toread -= cre->splicelen;
|
|
|
|
cre->splicelen = -1;
|
|
|
|
|
2011-04-12 04:45:18 -07:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2007-02-21 19:32:39 -08:00
|
|
|
void
|
|
|
|
relay_error(struct bufferevent *bev, short error, void *arg)
|
|
|
|
{
|
2014-06-27 00:49:08 -07:00
|
|
|
struct ctl_relay_event *cre = arg;
|
|
|
|
struct rsession *con = cre->con;
|
|
|
|
struct evbuffer *dst;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2017-11-27 16:17:56 -08:00
|
|
|
DPRINTF("%s: session %d: dir %d state %d to read %lld event error %x",
|
2017-11-27 13:09:55 -08:00
|
|
|
__func__, con->se_id, cre->dir, cre->state, cre->toread, error);
|
2007-02-21 19:32:39 -08:00
|
|
|
if (error & EVBUFFER_TIMEOUT) {
|
2011-09-21 11:45:40 -07:00
|
|
|
if (cre->splicelen >= 0) {
|
|
|
|
bufferevent_enable(bev, EV_READ);
|
|
|
|
} else if (cre->dst->splicelen >= 0) {
|
|
|
|
switch (relay_splicelen(cre->dst)) {
|
|
|
|
case -1:
|
|
|
|
goto fail;
|
|
|
|
case 0:
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, "buffer event timeout", 1);
|
2011-09-21 11:45:40 -07:00
|
|
|
break;
|
|
|
|
case 1:
|
2014-07-13 17:11:12 -07:00
|
|
|
cre->timedout = 1;
|
2011-09-21 11:45:40 -07:00
|
|
|
bufferevent_enable(bev, EV_READ);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, "buffer event timeout", 1);
|
2011-09-21 11:45:40 -07:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (error & EVBUFFER_ERROR && errno == ETIMEDOUT) {
|
|
|
|
if (cre->dst->splicelen >= 0) {
|
|
|
|
switch (relay_splicelen(cre->dst)) {
|
|
|
|
case -1:
|
|
|
|
goto fail;
|
|
|
|
case 0:
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, "splice timeout", 1);
|
2011-09-21 11:45:40 -07:00
|
|
|
return;
|
|
|
|
case 1:
|
|
|
|
bufferevent_enable(bev, EV_READ);
|
|
|
|
break;
|
|
|
|
}
|
2014-07-13 17:11:12 -07:00
|
|
|
} else if (cre->dst->timedout) {
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, "splice timeout", 1);
|
2014-07-13 17:11:12 -07:00
|
|
|
return;
|
2011-09-21 11:45:40 -07:00
|
|
|
}
|
2013-03-09 06:43:06 -08:00
|
|
|
if (relay_spliceadjust(cre) == -1)
|
|
|
|
goto fail;
|
2011-09-21 11:45:40 -07:00
|
|
|
if (relay_splice(cre) == -1)
|
|
|
|
goto fail;
|
2007-02-21 19:32:39 -08:00
|
|
|
return;
|
|
|
|
}
|
2013-03-09 06:43:06 -08:00
|
|
|
if (error & EVBUFFER_ERROR && errno == EFBIG) {
|
|
|
|
if (relay_spliceadjust(cre) == -1)
|
|
|
|
goto fail;
|
|
|
|
bufferevent_enable(cre->bev, EV_READ);
|
|
|
|
return;
|
|
|
|
}
|
2007-02-21 19:32:39 -08:00
|
|
|
if (error & (EVBUFFER_READ|EVBUFFER_WRITE|EVBUFFER_EOF)) {
|
|
|
|
bufferevent_disable(bev, EV_READ|EV_WRITE);
|
|
|
|
|
2008-01-31 04:12:50 -08:00
|
|
|
con->se_done = 1;
|
2007-02-21 19:32:39 -08:00
|
|
|
if (cre->dst->bev != NULL) {
|
|
|
|
dst = EVBUFFER_OUTPUT(cre->dst->bev);
|
2007-02-26 04:09:21 -08:00
|
|
|
if (EVBUFFER_LENGTH(dst))
|
2007-02-21 19:32:39 -08:00
|
|
|
return;
|
2015-04-29 01:41:24 -07:00
|
|
|
} else if (cre->toread == TOREAD_UNLIMITED || cre->toread == 0)
|
2011-09-04 03:42:47 -07:00
|
|
|
return;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, "done", 0);
|
2007-02-21 19:32:39 -08:00
|
|
|
return;
|
|
|
|
}
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, "buffer event error", 1);
|
2011-09-21 11:45:40 -07:00
|
|
|
return;
|
|
|
|
fail:
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, strerror(errno), 1);
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-04-11 01:25:26 -07:00
|
|
|
relay_accept(int fd, short event, void *arg)
|
2007-02-21 19:32:39 -08:00
|
|
|
{
|
2016-09-02 07:31:47 -07:00
|
|
|
struct privsep *ps = env->sc_ps;
|
2014-06-27 00:49:08 -07:00
|
|
|
struct relay *rlay = arg;
|
|
|
|
struct rsession *con = NULL;
|
|
|
|
struct ctl_natlook *cnl = NULL;
|
|
|
|
socklen_t slen;
|
|
|
|
struct timeval tv;
|
|
|
|
struct sockaddr_storage ss;
|
|
|
|
int s = -1;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2012-04-11 01:25:26 -07:00
|
|
|
event_add(&rlay->rl_ev, NULL);
|
|
|
|
if ((event & EV_TIMEOUT))
|
2007-02-21 19:32:39 -08:00
|
|
|
return;
|
|
|
|
|
2012-04-11 01:25:26 -07:00
|
|
|
slen = sizeof(ss);
|
2012-09-21 02:56:27 -07:00
|
|
|
if ((s = accept_reserve(fd, (struct sockaddr *)&ss,
|
2012-11-26 21:00:28 -08:00
|
|
|
&slen, FD_RESERVE, &relay_inflight)) == -1) {
|
2012-04-11 01:25:26 -07:00
|
|
|
/*
|
|
|
|
* Pause accept if we are out of file descriptors, or
|
|
|
|
* libevent will haunt us here too.
|
|
|
|
*/
|
|
|
|
if (errno == ENFILE || errno == EMFILE) {
|
|
|
|
struct timeval evtpause = { 1, 0 };
|
|
|
|
|
|
|
|
event_del(&rlay->rl_ev);
|
|
|
|
evtimer_add(&rlay->rl_evt, &evtpause);
|
2012-11-26 21:00:28 -08:00
|
|
|
log_debug("%s: deferring connections", __func__);
|
2012-04-11 01:25:26 -07:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2018-04-18 05:10:54 -07:00
|
|
|
if (rlay->rl_conf.flags & F_DISABLE)
|
2007-02-21 19:32:39 -08:00
|
|
|
goto err;
|
|
|
|
|
2011-04-24 03:07:43 -07:00
|
|
|
if ((con = calloc(1, sizeof(*con))) == NULL)
|
2007-02-21 19:32:39 -08:00
|
|
|
goto err;
|
|
|
|
|
2015-04-23 10:03:01 -07:00
|
|
|
/* Pre-allocate log buffer */
|
|
|
|
con->se_haslog = 0;
|
|
|
|
con->se_log = evbuffer_new();
|
|
|
|
if (con->se_log == NULL)
|
|
|
|
goto err;
|
|
|
|
|
2008-01-31 04:12:50 -08:00
|
|
|
con->se_in.s = s;
|
2017-05-27 01:33:25 -07:00
|
|
|
con->se_in.tls = NULL;
|
2008-01-31 04:12:50 -08:00
|
|
|
con->se_out.s = -1;
|
2017-05-27 01:33:25 -07:00
|
|
|
con->se_out.tls = NULL;
|
2008-01-31 04:12:50 -08:00
|
|
|
con->se_in.dst = &con->se_out;
|
|
|
|
con->se_out.dst = &con->se_in;
|
|
|
|
con->se_in.con = con;
|
|
|
|
con->se_out.con = con;
|
2011-04-12 04:45:18 -07:00
|
|
|
con->se_in.splicelen = -1;
|
|
|
|
con->se_out.splicelen = -1;
|
2013-02-05 13:36:33 -08:00
|
|
|
con->se_in.toread = TOREAD_UNLIMITED;
|
|
|
|
con->se_out.toread = TOREAD_UNLIMITED;
|
2008-01-31 04:12:50 -08:00
|
|
|
con->se_relay = rlay;
|
|
|
|
con->se_id = ++relay_conid;
|
|
|
|
con->se_relayid = rlay->rl_conf.id;
|
2011-05-20 02:43:53 -07:00
|
|
|
con->se_pid = getpid();
|
2008-01-31 04:12:50 -08:00
|
|
|
con->se_in.dir = RELAY_DIR_REQUEST;
|
|
|
|
con->se_out.dir = RELAY_DIR_RESPONSE;
|
|
|
|
con->se_retry = rlay->rl_conf.dstretry;
|
2008-06-11 11:21:19 -07:00
|
|
|
con->se_bnds = -1;
|
2008-01-31 04:12:50 -08:00
|
|
|
con->se_out.port = rlay->rl_conf.dstport;
|
2007-09-07 01:20:24 -07:00
|
|
|
switch (ss.ss_family) {
|
|
|
|
case AF_INET:
|
2008-01-31 04:12:50 -08:00
|
|
|
con->se_in.port = ((struct sockaddr_in *)&ss)->sin_port;
|
2007-09-07 01:20:24 -07:00
|
|
|
break;
|
|
|
|
case AF_INET6:
|
2008-01-31 04:12:50 -08:00
|
|
|
con->se_in.port = ((struct sockaddr_in6 *)&ss)->sin6_port;
|
2007-09-07 01:20:24 -07:00
|
|
|
break;
|
|
|
|
}
|
2019-05-10 02:15:00 -07:00
|
|
|
memcpy(&con->se_in.ss, &ss, sizeof(con->se_in.ss));
|
|
|
|
|
|
|
|
slen = sizeof(con->se_sockname);
|
|
|
|
if (getsockname(s, (struct sockaddr *)&con->se_sockname, &slen) == -1) {
|
|
|
|
relay_close(con, "sockname lookup failed", 1);
|
|
|
|
return;
|
|
|
|
}
|
2013-03-10 16:32:53 -07:00
|
|
|
|
|
|
|
getmonotime(&con->se_tv_start);
|
|
|
|
bcopy(&con->se_tv_start, &con->se_tv_last, sizeof(con->se_tv_last));
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2014-12-18 12:55:01 -08:00
|
|
|
if (rlay->rl_conf.flags & F_HASHKEY) {
|
|
|
|
SipHash24_Init(&con->se_siphashctx,
|
|
|
|
&rlay->rl_conf.hashkey.siphashkey);
|
|
|
|
}
|
|
|
|
|
2007-09-04 03:58:08 -07:00
|
|
|
relay_sessions++;
|
2008-01-31 01:56:28 -08:00
|
|
|
SPLAY_INSERT(session_tree, &rlay->rl_sessions, con);
|
2014-11-19 02:24:39 -08:00
|
|
|
relay_session_publish(con);
|
2007-09-04 03:58:08 -07:00
|
|
|
|
|
|
|
/* Increment the per-relay session counter */
|
2016-09-02 07:31:47 -07:00
|
|
|
rlay->rl_stats[ps->ps_instance].last++;
|
2007-09-04 03:58:08 -07:00
|
|
|
|
2007-02-21 19:32:39 -08:00
|
|
|
/* Pre-allocate output buffer */
|
2008-01-31 04:12:50 -08:00
|
|
|
con->se_out.output = evbuffer_new();
|
|
|
|
if (con->se_out.output == NULL) {
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, "failed to allocate output buffer", 1);
|
2007-02-21 19:32:39 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-04-07 06:22:29 -07:00
|
|
|
if (rlay->rl_conf.flags & F_DIVERT) {
|
2019-05-10 02:15:00 -07:00
|
|
|
memcpy(&con->se_out.ss, &con->se_sockname,
|
|
|
|
sizeof(con->se_out.ss));
|
2011-04-07 06:22:29 -07:00
|
|
|
con->se_out.port = relay_socket_getport(&con->se_out.ss);
|
|
|
|
|
|
|
|
/* Detect loop and fall back to the alternate forward target */
|
|
|
|
if (bcmp(&rlay->rl_conf.ss, &con->se_out.ss,
|
|
|
|
sizeof(con->se_out.ss)) == 0 &&
|
|
|
|
con->se_out.port == rlay->rl_conf.port)
|
|
|
|
con->se_out.ss.ss_family = AF_UNSPEC;
|
|
|
|
} else if (rlay->rl_conf.flags & F_NATLOOK) {
|
2013-01-17 12:34:18 -08:00
|
|
|
if ((cnl = calloc(1, sizeof(*cnl))) == NULL) {
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, "failed to allocate nat lookup", 1);
|
2007-09-04 03:58:08 -07:00
|
|
|
return;
|
|
|
|
}
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2008-01-31 04:12:50 -08:00
|
|
|
con->se_cnl = cnl;
|
2007-02-21 19:32:39 -08:00
|
|
|
bzero(cnl, sizeof(*cnl));
|
|
|
|
cnl->in = -1;
|
2008-01-31 04:12:50 -08:00
|
|
|
cnl->id = con->se_id;
|
2016-09-02 07:31:47 -07:00
|
|
|
cnl->proc = ps->ps_instance;
|
2008-07-09 07:57:01 -07:00
|
|
|
cnl->proto = IPPROTO_TCP;
|
2008-07-16 07:49:44 -07:00
|
|
|
|
2019-05-10 02:15:00 -07:00
|
|
|
memcpy(&cnl->src, &con->se_in.ss, sizeof(cnl->src));
|
|
|
|
memcpy(&cnl->dst, &con->se_sockname, sizeof(cnl->dst));
|
2008-07-16 07:49:44 -07:00
|
|
|
|
2015-12-02 05:41:27 -08:00
|
|
|
proc_compose(env->sc_ps, PROC_PFE, IMSG_NATLOOK,
|
2011-09-04 13:26:58 -07:00
|
|
|
cnl, sizeof(*cnl));
|
2007-02-21 19:32:39 -08:00
|
|
|
|
|
|
|
/* Schedule timeout */
|
2008-01-31 04:12:50 -08:00
|
|
|
evtimer_set(&con->se_ev, relay_natlook, con);
|
2008-01-31 01:56:28 -08:00
|
|
|
bcopy(&rlay->rl_conf.timeout, &tv, sizeof(tv));
|
2008-01-31 04:12:50 -08:00
|
|
|
evtimer_add(&con->se_ev, &tv);
|
2007-02-21 19:32:39 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-12-12 02:05:09 -08:00
|
|
|
if (rlay->rl_conf.flags & F_TLSINSPECT) {
|
2013-05-30 13:17:12 -07:00
|
|
|
relay_preconnect(con);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-02-21 19:32:39 -08:00
|
|
|
relay_session(con);
|
|
|
|
return;
|
|
|
|
err:
|
|
|
|
if (s != -1) {
|
|
|
|
close(s);
|
2015-12-06 20:03:27 -08:00
|
|
|
free(con);
|
2012-11-28 17:01:53 -08:00
|
|
|
/*
|
2015-12-23 21:06:24 -08:00
|
|
|
* the session struct was not completely set up, but still
|
2012-09-21 02:56:27 -07:00
|
|
|
* counted as an inflight session. account for this.
|
|
|
|
*/
|
|
|
|
relay_inflight--;
|
|
|
|
log_debug("%s: inflight decremented, now %d",
|
|
|
|
__func__, relay_inflight);
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-18 12:55:01 -08:00
|
|
|
void
|
|
|
|
relay_hash_addr(SIPHASH_CTX *ctx, struct sockaddr_storage *ss, int portset)
|
2007-02-21 19:32:39 -08:00
|
|
|
{
|
|
|
|
struct sockaddr_in *sin4;
|
|
|
|
struct sockaddr_in6 *sin6;
|
2014-12-18 12:55:01 -08:00
|
|
|
in_port_t port;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
|
|
|
if (ss->ss_family == AF_INET) {
|
|
|
|
sin4 = (struct sockaddr_in *)ss;
|
2014-12-18 12:55:01 -08:00
|
|
|
SipHash24_Update(ctx, &sin4->sin_addr,
|
|
|
|
sizeof(struct in_addr));
|
2007-02-21 19:32:39 -08:00
|
|
|
} else {
|
|
|
|
sin6 = (struct sockaddr_in6 *)ss;
|
2014-12-18 12:55:01 -08:00
|
|
|
SipHash24_Update(ctx, &sin6->sin6_addr,
|
|
|
|
sizeof(struct in6_addr));
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
2014-12-18 12:55:01 -08:00
|
|
|
if (portset != -1) {
|
|
|
|
port = (in_port_t)portset;
|
|
|
|
SipHash24_Update(ctx, &port, sizeof(port));
|
|
|
|
}
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2009-08-07 04:21:53 -07:00
|
|
|
relay_from_table(struct rsession *con)
|
2007-02-21 19:32:39 -08:00
|
|
|
{
|
2013-01-17 12:34:18 -08:00
|
|
|
struct relay *rlay = con->se_relay;
|
2015-12-05 12:58:32 -08:00
|
|
|
struct host *host = NULL;
|
2012-10-03 01:33:31 -07:00
|
|
|
struct relay_table *rlt = NULL;
|
|
|
|
struct table *table = NULL;
|
2012-10-19 09:49:50 -07:00
|
|
|
int idx = -1;
|
2015-12-02 14:12:29 -08:00
|
|
|
int cnt = 0;
|
|
|
|
int maxtries;
|
2014-12-18 12:55:01 -08:00
|
|
|
u_int64_t p = 0;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2012-10-03 01:33:31 -07:00
|
|
|
/* the table is already selected */
|
|
|
|
if (con->se_table != NULL) {
|
|
|
|
rlt = con->se_table;
|
|
|
|
table = rlt->rlt_table;
|
|
|
|
if (table->conf.check && !table->up)
|
|
|
|
table = NULL;
|
|
|
|
goto gottable;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* otherwise grep the first active table */
|
|
|
|
TAILQ_FOREACH(rlt, &rlay->rl_tables, rlt_entry) {
|
|
|
|
table = rlt->rlt_table;
|
2012-10-03 01:40:40 -07:00
|
|
|
if ((rlt->rlt_flags & F_USED) == 0 ||
|
2012-10-03 01:33:31 -07:00
|
|
|
(table->conf.check && !table->up))
|
|
|
|
table = NULL;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
gottable:
|
|
|
|
if (table == NULL) {
|
|
|
|
log_debug("%s: session %d: no active hosts",
|
|
|
|
__func__, con->se_id);
|
2007-02-21 19:32:39 -08:00
|
|
|
return (-1);
|
2012-10-03 01:33:31 -07:00
|
|
|
}
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2012-10-03 01:33:31 -07:00
|
|
|
switch (rlt->rlt_mode) {
|
2007-02-21 19:32:39 -08:00
|
|
|
case RELAY_DSTMODE_ROUNDROBIN:
|
2014-12-18 12:55:01 -08:00
|
|
|
if ((int)rlt->rlt_index >= rlt->rlt_nhosts)
|
|
|
|
rlt->rlt_index = 0;
|
|
|
|
idx = (int)rlt->rlt_index;
|
2007-02-21 19:32:39 -08:00
|
|
|
break;
|
2012-10-19 09:49:50 -07:00
|
|
|
case RELAY_DSTMODE_RANDOM:
|
|
|
|
idx = (int)arc4random_uniform(rlt->rlt_nhosts);
|
|
|
|
break;
|
|
|
|
case RELAY_DSTMODE_SRCHASH:
|
2014-12-18 12:55:01 -08:00
|
|
|
/* Source IP address without port */
|
|
|
|
relay_hash_addr(&con->se_siphashctx, &con->se_in.ss, -1);
|
|
|
|
break;
|
2014-08-29 02:03:36 -07:00
|
|
|
case RELAY_DSTMODE_LOADBALANCE:
|
|
|
|
/* Source IP address without port */
|
2014-12-18 12:55:01 -08:00
|
|
|
relay_hash_addr(&con->se_siphashctx, &con->se_in.ss, -1);
|
2014-09-05 03:19:26 -07:00
|
|
|
/* FALLTHROUGH */
|
|
|
|
case RELAY_DSTMODE_HASH:
|
2012-10-19 09:49:50 -07:00
|
|
|
/* Local "destination" IP address and port */
|
2014-12-18 12:55:01 -08:00
|
|
|
relay_hash_addr(&con->se_siphashctx, &rlay->rl_conf.ss,
|
|
|
|
rlay->rl_conf.port);
|
2012-10-19 09:49:50 -07:00
|
|
|
break;
|
|
|
|
default:
|
2017-05-28 03:39:15 -07:00
|
|
|
fatalx("%s: unsupported mode", __func__);
|
2012-10-19 09:49:50 -07:00
|
|
|
/* NOTREACHED */
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
2014-12-18 12:55:01 -08:00
|
|
|
if (idx == -1) {
|
2015-12-02 14:12:29 -08:00
|
|
|
/* handle all hashing algorithms */
|
2014-12-18 12:55:01 -08:00
|
|
|
p = SipHash24_End(&con->se_siphashctx);
|
|
|
|
|
|
|
|
/* Reset hash context */
|
|
|
|
SipHash24_Init(&con->se_siphashctx,
|
|
|
|
&rlay->rl_conf.hashkey.siphashkey);
|
|
|
|
|
2015-12-02 14:12:29 -08:00
|
|
|
maxtries = (rlt->rlt_nhosts < RELAY_MAX_HASH_RETRIES ?
|
|
|
|
rlt->rlt_nhosts : RELAY_MAX_HASH_RETRIES);
|
|
|
|
for (cnt = 0; cnt < maxtries; cnt++) {
|
|
|
|
if ((idx = p % rlt->rlt_nhosts) >= RELAY_MAXHOSTS)
|
|
|
|
return (-1);
|
|
|
|
|
|
|
|
host = rlt->rlt_host[idx];
|
|
|
|
|
|
|
|
DPRINTF("%s: session %d: table %s host %s, "
|
|
|
|
"p 0x%016llx, idx %d, cnt %d, max %d",
|
|
|
|
__func__, con->se_id, table->conf.name,
|
|
|
|
host->conf.name, p, idx, cnt, maxtries);
|
|
|
|
|
|
|
|
if (!table->conf.check || host->up == HOST_UP)
|
|
|
|
goto found;
|
|
|
|
p = p >> 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* handle all non-hashing algorithms */
|
|
|
|
host = rlt->rlt_host[idx];
|
|
|
|
DPRINTF("%s: session %d: table %s host %s, p 0x%016llx, idx %d",
|
2016-09-26 09:25:16 -07:00
|
|
|
__func__, con->se_id, table->conf.name, host->conf.name,
|
|
|
|
p, idx);
|
2014-12-18 12:55:01 -08:00
|
|
|
}
|
2015-12-02 14:12:29 -08:00
|
|
|
|
2007-02-21 19:32:39 -08:00
|
|
|
while (host != NULL) {
|
2012-10-03 01:33:31 -07:00
|
|
|
DPRINTF("%s: session %d: host %s", __func__,
|
|
|
|
con->se_id, host->conf.name);
|
2007-12-08 09:07:08 -08:00
|
|
|
if (!table->conf.check || host->up == HOST_UP)
|
2007-02-21 19:32:39 -08:00
|
|
|
goto found;
|
|
|
|
host = TAILQ_NEXT(host, entry);
|
|
|
|
}
|
2007-12-08 09:07:08 -08:00
|
|
|
TAILQ_FOREACH(host, &table->hosts, entry) {
|
2014-07-09 09:42:05 -07:00
|
|
|
DPRINTF("%s: session %d: next host %s",
|
|
|
|
__func__, con->se_id, host->conf.name);
|
2007-12-08 09:07:08 -08:00
|
|
|
if (!table->conf.check || host->up == HOST_UP)
|
2007-02-21 19:32:39 -08:00
|
|
|
goto found;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Should not happen */
|
2017-05-28 03:39:15 -07:00
|
|
|
fatalx("%s: no active hosts, desynchronized", __func__);
|
2007-02-21 19:32:39 -08:00
|
|
|
|
|
|
|
found:
|
2012-10-03 01:33:31 -07:00
|
|
|
if (rlt->rlt_mode == RELAY_DSTMODE_ROUNDROBIN)
|
2014-12-18 12:55:01 -08:00
|
|
|
rlt->rlt_index = host->idx + 1;
|
2008-01-31 04:12:50 -08:00
|
|
|
con->se_retry = host->conf.retry;
|
|
|
|
con->se_out.port = table->conf.port;
|
|
|
|
bcopy(&host->conf.ss, &con->se_out.ss, sizeof(con->se_out.ss));
|
2007-02-21 19:32:39 -08:00
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
relay_natlook(int fd, short event, void *arg)
|
|
|
|
{
|
2013-01-17 12:34:18 -08:00
|
|
|
struct rsession *con = arg;
|
|
|
|
struct relay *rlay = con->se_relay;
|
2008-01-31 04:12:50 -08:00
|
|
|
struct ctl_natlook *cnl = con->se_cnl;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
|
|
|
if (cnl == NULL)
|
|
|
|
fatalx("invalid NAT lookup");
|
|
|
|
|
2008-01-31 04:12:50 -08:00
|
|
|
if (con->se_out.ss.ss_family == AF_UNSPEC && cnl->in == -1 &&
|
2008-09-29 08:12:22 -07:00
|
|
|
rlay->rl_conf.dstss.ss_family == AF_UNSPEC &&
|
2012-10-03 01:33:31 -07:00
|
|
|
TAILQ_EMPTY(&rlay->rl_tables)) {
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, "session NAT lookup failed", 1);
|
2007-02-21 19:32:39 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (cnl->in != -1) {
|
2008-01-31 04:12:50 -08:00
|
|
|
bcopy(&cnl->rdst, &con->se_out.ss, sizeof(con->se_out.ss));
|
|
|
|
con->se_out.port = cnl->rdport;
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
2008-01-31 04:12:50 -08:00
|
|
|
free(con->se_cnl);
|
|
|
|
con->se_cnl = NULL;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
|
|
|
relay_session(con);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-08-07 04:21:53 -07:00
|
|
|
relay_session(struct rsession *con)
|
2007-02-21 19:32:39 -08:00
|
|
|
{
|
2013-01-17 12:34:18 -08:00
|
|
|
struct relay *rlay = con->se_relay;
|
2008-01-31 04:12:50 -08:00
|
|
|
struct ctl_relay_event *in = &con->se_in, *out = &con->se_out;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2008-01-31 01:56:28 -08:00
|
|
|
if (bcmp(&rlay->rl_conf.ss, &out->ss, sizeof(out->ss)) == 0 &&
|
|
|
|
out->port == rlay->rl_conf.port) {
|
2011-05-05 05:01:43 -07:00
|
|
|
log_debug("%s: session %d: looping", __func__, con->se_id);
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, "session aborted", 1);
|
2007-02-21 19:32:39 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-01-31 01:56:28 -08:00
|
|
|
if (rlay->rl_conf.flags & F_UDP) {
|
2007-09-10 04:59:22 -07:00
|
|
|
/*
|
|
|
|
* Call the UDP protocol-specific handler
|
|
|
|
*/
|
2008-01-31 01:56:28 -08:00
|
|
|
if (rlay->rl_proto->request == NULL)
|
2022-12-28 13:30:15 -08:00
|
|
|
fatalx("invalid UDP session");
|
2008-01-31 01:56:28 -08:00
|
|
|
if ((*rlay->rl_proto->request)(con) == -1)
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, "session failed", 1);
|
2007-09-10 04:59:22 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
if ((rlay->rl_conf.flags & F_TLS) && (in->tls == NULL)) {
|
2014-12-12 02:05:09 -08:00
|
|
|
relay_tls_transaction(con, in);
|
2007-02-21 19:32:39 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-05-08 16:22:19 -07:00
|
|
|
if (rlay->rl_proto->type != RELAY_PROTO_HTTP) {
|
2008-06-11 11:21:19 -07:00
|
|
|
if (rlay->rl_conf.fwdmode == FWD_TRANS)
|
|
|
|
relay_bindanyreq(con, 0, IPPROTO_TCP);
|
|
|
|
else if (relay_connect(con) == -1) {
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, "session failed", 1);
|
2008-06-11 11:21:19 -07:00
|
|
|
return;
|
|
|
|
}
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
relay_input(con);
|
|
|
|
}
|
|
|
|
|
2008-06-11 11:21:19 -07:00
|
|
|
void
|
2009-08-07 04:21:53 -07:00
|
|
|
relay_bindanyreq(struct rsession *con, in_port_t port, int proto)
|
2008-06-11 11:21:19 -07:00
|
|
|
{
|
2016-09-02 07:31:47 -07:00
|
|
|
struct privsep *ps = env->sc_ps;
|
2013-01-17 12:34:18 -08:00
|
|
|
struct relay *rlay = con->se_relay;
|
2008-06-11 11:21:19 -07:00
|
|
|
struct ctl_bindany bnd;
|
|
|
|
struct timeval tv;
|
|
|
|
|
|
|
|
bzero(&bnd, sizeof(bnd));
|
|
|
|
bnd.bnd_id = con->se_id;
|
2016-09-02 07:31:47 -07:00
|
|
|
bnd.bnd_proc = ps->ps_instance;
|
2008-06-11 11:21:19 -07:00
|
|
|
bnd.bnd_port = port;
|
|
|
|
bnd.bnd_proto = proto;
|
|
|
|
bcopy(&con->se_in.ss, &bnd.bnd_ss, sizeof(bnd.bnd_ss));
|
2015-12-02 05:41:27 -08:00
|
|
|
proc_compose(env->sc_ps, PROC_PARENT, IMSG_BINDANY,
|
|
|
|
&bnd, sizeof(bnd));
|
2008-06-11 11:21:19 -07:00
|
|
|
|
|
|
|
/* Schedule timeout */
|
|
|
|
evtimer_set(&con->se_ev, relay_bindany, con);
|
|
|
|
bcopy(&rlay->rl_conf.timeout, &tv, sizeof(tv));
|
|
|
|
evtimer_add(&con->se_ev, &tv);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
relay_bindany(int fd, short event, void *arg)
|
|
|
|
{
|
2013-01-17 12:34:18 -08:00
|
|
|
struct rsession *con = arg;
|
2008-06-11 11:21:19 -07:00
|
|
|
|
|
|
|
if (con->se_bnds == -1) {
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, "bindany failed, invalid socket", 1);
|
2008-06-11 11:21:19 -07:00
|
|
|
return;
|
|
|
|
}
|
2011-04-24 03:07:43 -07:00
|
|
|
if (relay_connect(con) == -1)
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, "session failed", 1);
|
2008-06-11 11:21:19 -07:00
|
|
|
}
|
|
|
|
|
2019-05-13 02:54:07 -07:00
|
|
|
void
|
|
|
|
relay_connect_state(struct rsession *con, struct ctl_relay_event *cre,
|
|
|
|
enum relay_state new)
|
|
|
|
{
|
|
|
|
DPRINTF("%s: session %d: %s state %s -> %s",
|
|
|
|
__func__, con->se_id,
|
|
|
|
cre->dir == RELAY_DIR_REQUEST ? "accept" : "connect",
|
|
|
|
relay_state(cre->state), relay_state(new));
|
|
|
|
cre->state = new;
|
|
|
|
}
|
|
|
|
|
2012-09-21 02:56:27 -07:00
|
|
|
void
|
|
|
|
relay_connect_retry(int fd, short sig, void *arg)
|
|
|
|
{
|
|
|
|
struct timeval evtpause = { 1, 0 };
|
2013-01-17 12:34:18 -08:00
|
|
|
struct rsession *con = arg;
|
|
|
|
struct relay *rlay = con->se_relay;
|
2012-09-21 02:56:27 -07:00
|
|
|
int bnds = -1;
|
|
|
|
|
2015-06-08 08:47:51 -07:00
|
|
|
if (relay_inflight < 1) {
|
2017-05-28 03:39:15 -07:00
|
|
|
log_warnx("%s: no connection in flight", __func__);
|
2015-06-08 08:47:51 -07:00
|
|
|
relay_inflight = 1;
|
|
|
|
}
|
2012-09-21 02:56:27 -07:00
|
|
|
|
|
|
|
DPRINTF("%s: retry %d of %d, inflight: %d",__func__,
|
|
|
|
con->se_retrycount, con->se_retry, relay_inflight);
|
|
|
|
|
|
|
|
if (sig != EV_TIMEOUT)
|
2017-05-28 03:39:15 -07:00
|
|
|
fatalx("%s: called without timeout", __func__);
|
2012-09-21 02:56:27 -07:00
|
|
|
|
|
|
|
evtimer_del(&con->se_inflightevt);
|
|
|
|
|
2012-11-28 17:01:53 -08:00
|
|
|
/*
|
2012-09-21 02:56:27 -07:00
|
|
|
* XXX we might want to check if the inbound socket is still
|
|
|
|
* available: client could have closed it while we were waiting?
|
|
|
|
*/
|
|
|
|
|
|
|
|
DPRINTF("%s: got EV_TIMEOUT", __func__);
|
|
|
|
|
|
|
|
if (getdtablecount() + FD_RESERVE +
|
|
|
|
relay_inflight > getdtablesize()) {
|
|
|
|
if (con->se_retrycount < RELAY_OUTOF_FD_RETRIES) {
|
|
|
|
evtimer_add(&con->se_inflightevt, &evtpause);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* we waited for RELAY_OUTOF_FD_RETRIES seconds, give up */
|
|
|
|
event_add(&rlay->rl_ev, NULL);
|
2012-10-04 13:53:30 -07:00
|
|
|
relay_abort_http(con, 504, "connection timed out", 0);
|
2012-09-21 02:56:27 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rlay->rl_conf.fwdmode == FWD_TRANS) {
|
|
|
|
/* con->se_bnds cannot be unset */
|
|
|
|
bnds = con->se_bnds;
|
|
|
|
}
|
|
|
|
|
|
|
|
retry:
|
|
|
|
if ((con->se_out.s = relay_socket_connect(&con->se_out.ss,
|
|
|
|
con->se_out.port, rlay->rl_proto, bnds)) == -1) {
|
|
|
|
log_debug("%s: session %d: "
|
|
|
|
"forward failed: %s, %s", __func__,
|
|
|
|
con->se_id, strerror(errno),
|
|
|
|
con->se_retry ? "next retry" : "last retry");
|
|
|
|
|
|
|
|
con->se_retrycount++;
|
|
|
|
|
2012-10-04 13:53:30 -07:00
|
|
|
if ((errno == ENFILE || errno == EMFILE) &&
|
2012-09-21 02:56:27 -07:00
|
|
|
(con->se_retrycount < con->se_retry)) {
|
|
|
|
event_del(&rlay->rl_ev);
|
|
|
|
evtimer_add(&con->se_inflightevt, &evtpause);
|
|
|
|
evtimer_add(&rlay->rl_evt, &evtpause);
|
|
|
|
return;
|
|
|
|
} else if (con->se_retrycount < con->se_retry)
|
|
|
|
goto retry;
|
|
|
|
event_add(&rlay->rl_ev, NULL);
|
|
|
|
relay_abort_http(con, 504, "connect failed", 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-06-08 08:47:51 -07:00
|
|
|
if (rlay->rl_conf.flags & F_TLSINSPECT)
|
2019-05-13 02:54:07 -07:00
|
|
|
relay_connect_state(con, &con->se_out, STATE_PRECONNECT);
|
2015-06-08 08:47:51 -07:00
|
|
|
else
|
2019-05-13 02:54:07 -07:00
|
|
|
relay_connect_state(con, &con->se_out, STATE_CONNECTED);
|
2012-09-21 02:56:27 -07:00
|
|
|
relay_inflight--;
|
|
|
|
DPRINTF("%s: inflight decremented, now %d",__func__, relay_inflight);
|
|
|
|
|
|
|
|
event_add(&rlay->rl_ev, NULL);
|
|
|
|
|
|
|
|
if (errno == EINPROGRESS)
|
|
|
|
event_again(&con->se_ev, con->se_out.s, EV_WRITE|EV_TIMEOUT,
|
|
|
|
relay_connected, &con->se_tv_start, &rlay->rl_conf.timeout,
|
|
|
|
con);
|
|
|
|
else
|
|
|
|
relay_connected(con->se_out.s, EV_WRITE, con);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-05-30 13:17:12 -07:00
|
|
|
int
|
|
|
|
relay_preconnect(struct rsession *con)
|
|
|
|
{
|
2015-06-08 08:47:51 -07:00
|
|
|
int rv;
|
|
|
|
|
2013-05-30 13:17:12 -07:00
|
|
|
log_debug("%s: session %d: process %d", __func__,
|
|
|
|
con->se_id, privsep_process);
|
2015-06-08 08:47:51 -07:00
|
|
|
rv = relay_connect(con);
|
2015-06-12 07:40:55 -07:00
|
|
|
if (con->se_out.state == STATE_CONNECTED)
|
2019-05-13 02:54:07 -07:00
|
|
|
relay_connect_state(con, &con->se_out, STATE_PRECONNECT);
|
2015-06-08 08:47:51 -07:00
|
|
|
return (rv);
|
2013-05-30 13:17:12 -07:00
|
|
|
}
|
|
|
|
|
2007-02-21 19:32:39 -08:00
|
|
|
int
|
2009-08-07 04:21:53 -07:00
|
|
|
relay_connect(struct rsession *con)
|
2007-02-21 19:32:39 -08:00
|
|
|
{
|
2013-01-17 12:34:18 -08:00
|
|
|
struct relay *rlay = con->se_relay;
|
2012-09-21 02:56:27 -07:00
|
|
|
struct timeval evtpause = { 1, 0 };
|
2008-07-22 16:17:37 -07:00
|
|
|
int bnds = -1, ret;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2015-06-08 08:47:51 -07:00
|
|
|
/* relay_connect should only be called once per relay */
|
2015-06-12 07:40:55 -07:00
|
|
|
if (con->se_out.state == STATE_CONNECTED) {
|
2015-06-08 08:47:51 -07:00
|
|
|
log_debug("%s: connect already called once", __func__);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2013-05-30 13:17:12 -07:00
|
|
|
/* Connection is already established but session not active */
|
2015-06-08 08:47:51 -07:00
|
|
|
if ((rlay->rl_conf.flags & F_TLSINSPECT) &&
|
2015-06-12 07:40:55 -07:00
|
|
|
con->se_out.state == STATE_PRECONNECT) {
|
2017-05-27 01:33:25 -07:00
|
|
|
if (con->se_out.tls == NULL) {
|
2014-12-12 02:05:09 -08:00
|
|
|
log_debug("%s: tls connect failed", __func__);
|
2013-05-30 13:17:12 -07:00
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
relay_connected(con->se_out.s, EV_WRITE, con);
|
2019-05-13 02:54:07 -07:00
|
|
|
relay_connect_state(con, &con->se_out, STATE_CONNECTED);
|
2013-05-30 13:17:12 -07:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2015-06-08 08:47:51 -07:00
|
|
|
if (relay_inflight < 1) {
|
|
|
|
log_warnx("relay_connect: no connection in flight");
|
|
|
|
relay_inflight = 1;
|
|
|
|
}
|
2012-09-21 02:56:27 -07:00
|
|
|
|
2013-03-10 16:32:53 -07:00
|
|
|
getmonotime(&con->se_tv_start);
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2019-07-12 23:53:00 -07:00
|
|
|
if (con->se_out.ss.ss_family == AF_UNSPEC &&
|
|
|
|
!TAILQ_EMPTY(&rlay->rl_tables)) {
|
2007-02-21 19:32:39 -08:00
|
|
|
if (relay_from_table(con) != 0)
|
|
|
|
return (-1);
|
2008-01-31 04:12:50 -08:00
|
|
|
} else if (con->se_out.ss.ss_family == AF_UNSPEC) {
|
2008-06-11 11:21:19 -07:00
|
|
|
bcopy(&rlay->rl_conf.dstss, &con->se_out.ss,
|
|
|
|
sizeof(con->se_out.ss));
|
2008-01-31 04:12:50 -08:00
|
|
|
con->se_out.port = rlay->rl_conf.dstport;
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
2008-06-11 11:21:19 -07:00
|
|
|
if (rlay->rl_conf.fwdmode == FWD_TRANS) {
|
|
|
|
if (con->se_bnds == -1) {
|
2011-05-05 05:01:43 -07:00
|
|
|
log_debug("%s: could not bind any sock", __func__);
|
2008-06-11 11:21:19 -07:00
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
bnds = con->se_bnds;
|
|
|
|
}
|
|
|
|
|
2008-07-22 16:17:37 -07:00
|
|
|
/* Do the IPv4-to-IPv6 or IPv6-to-IPv4 translation if requested */
|
|
|
|
if (rlay->rl_conf.dstaf.ss_family != AF_UNSPEC) {
|
|
|
|
if (con->se_out.ss.ss_family == AF_INET &&
|
|
|
|
rlay->rl_conf.dstaf.ss_family == AF_INET6)
|
|
|
|
ret = map4to6(&con->se_out.ss, &rlay->rl_conf.dstaf);
|
|
|
|
else if (con->se_out.ss.ss_family == AF_INET6 &&
|
|
|
|
rlay->rl_conf.dstaf.ss_family == AF_INET)
|
|
|
|
ret = map6to4(&con->se_out.ss);
|
|
|
|
else
|
|
|
|
ret = 0;
|
|
|
|
if (ret != 0) {
|
2011-05-05 05:01:43 -07:00
|
|
|
log_debug("%s: mapped to invalid address", __func__);
|
2008-07-22 16:17:37 -07:00
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-26 03:59:48 -08:00
|
|
|
retry:
|
2008-06-11 11:21:19 -07:00
|
|
|
if ((con->se_out.s = relay_socket_connect(&con->se_out.ss,
|
|
|
|
con->se_out.port, rlay->rl_proto, bnds)) == -1) {
|
2012-09-21 02:56:27 -07:00
|
|
|
if (errno == ENFILE || errno == EMFILE) {
|
|
|
|
log_debug("%s: session %d: forward failed: %s",
|
|
|
|
__func__, con->se_id, strerror(errno));
|
|
|
|
evtimer_set(&con->se_inflightevt, relay_connect_retry,
|
|
|
|
con);
|
|
|
|
event_del(&rlay->rl_ev);
|
|
|
|
evtimer_add(&con->se_inflightevt, &evtpause);
|
|
|
|
evtimer_add(&rlay->rl_evt, &evtpause);
|
2015-06-12 07:40:55 -07:00
|
|
|
|
2015-06-08 08:47:51 -07:00
|
|
|
/* this connect is pending */
|
2019-05-13 02:54:07 -07:00
|
|
|
relay_connect_state(con, &con->se_out, STATE_PENDING);
|
2012-09-21 02:56:27 -07:00
|
|
|
return (0);
|
|
|
|
} else {
|
|
|
|
if (con->se_retry) {
|
|
|
|
con->se_retry--;
|
|
|
|
log_debug("%s: session %d: "
|
|
|
|
"forward failed: %s, %s", __func__,
|
|
|
|
con->se_id, strerror(errno),
|
2012-10-04 13:53:30 -07:00
|
|
|
con->se_retry ?
|
|
|
|
"next retry" : "last retry");
|
2012-09-21 02:56:27 -07:00
|
|
|
goto retry;
|
|
|
|
}
|
2012-10-04 13:53:30 -07:00
|
|
|
log_debug("%s: session %d: forward failed: %s",
|
|
|
|
__func__, con->se_id, strerror(errno));
|
2012-09-21 02:56:27 -07:00
|
|
|
return (-1);
|
2007-02-26 03:59:48 -08:00
|
|
|
}
|
2012-10-04 13:53:30 -07:00
|
|
|
}
|
2012-09-21 02:56:27 -07:00
|
|
|
|
2019-05-13 02:54:07 -07:00
|
|
|
relay_connect_state(con, &con->se_out, STATE_CONNECTED);
|
2012-09-21 02:56:27 -07:00
|
|
|
relay_inflight--;
|
|
|
|
DPRINTF("%s: inflight decremented, now %d",__func__,
|
|
|
|
relay_inflight);
|
2007-02-23 16:22:32 -08:00
|
|
|
|
2007-02-21 19:32:39 -08:00
|
|
|
if (errno == EINPROGRESS)
|
2008-01-31 04:12:50 -08:00
|
|
|
event_again(&con->se_ev, con->se_out.s, EV_WRITE|EV_TIMEOUT,
|
2011-09-04 02:55:10 -07:00
|
|
|
relay_connected, &con->se_tv_start, &rlay->rl_conf.timeout,
|
|
|
|
con);
|
2007-02-21 19:32:39 -08:00
|
|
|
else
|
2008-01-31 04:12:50 -08:00
|
|
|
relay_connected(con->se_out.s, EV_WRITE, con);
|
2007-02-21 19:32:39 -08:00
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(struct rsession *con, const char *msg, int err)
|
2007-02-21 19:32:39 -08:00
|
|
|
{
|
2007-02-23 16:22:32 -08:00
|
|
|
char ibuf[128], obuf[128], *ptr = NULL;
|
2013-01-17 12:34:18 -08:00
|
|
|
struct relay *rlay = con->se_relay;
|
2014-07-09 09:42:05 -07:00
|
|
|
struct protocol *proto = rlay->rl_proto;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2008-01-31 01:56:28 -08:00
|
|
|
SPLAY_REMOVE(session_tree, &rlay->rl_sessions, con);
|
2014-11-19 02:24:39 -08:00
|
|
|
relay_session_unpublish(con);
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2008-01-31 04:12:50 -08:00
|
|
|
event_del(&con->se_ev);
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2018-08-06 10:31:31 -07:00
|
|
|
if ((env->sc_conf.opts & (RELAYD_OPT_LOGCON|RELAYD_OPT_LOGCONERR)) &&
|
|
|
|
msg != NULL) {
|
2007-02-26 07:41:44 -08:00
|
|
|
bzero(&ibuf, sizeof(ibuf));
|
|
|
|
bzero(&obuf, sizeof(obuf));
|
2008-01-31 04:12:50 -08:00
|
|
|
(void)print_host(&con->se_in.ss, ibuf, sizeof(ibuf));
|
|
|
|
(void)print_host(&con->se_out.ss, obuf, sizeof(obuf));
|
|
|
|
if (EVBUFFER_LENGTH(con->se_log) &&
|
2017-09-23 04:56:57 -07:00
|
|
|
evbuffer_add_printf(con->se_log, "\r\n") != -1) {
|
|
|
|
ptr = evbuffer_readln(con->se_log, NULL,
|
|
|
|
EVBUFFER_EOL_CRLF);
|
|
|
|
}
|
2018-08-06 10:31:31 -07:00
|
|
|
if (err == 0 && (env->sc_conf.opts & RELAYD_OPT_LOGCON))
|
|
|
|
log_info("relay %s, "
|
|
|
|
"session %d (%d active), %s, %s -> %s:%d, "
|
|
|
|
"%s%s%s", rlay->rl_conf.name, con->se_id,
|
|
|
|
relay_sessions, con->se_tag != 0 ?
|
|
|
|
tag_id2name(con->se_tag) : "0", ibuf, obuf,
|
|
|
|
ntohs(con->se_out.port), msg, ptr == NULL ?
|
|
|
|
"" : ",", ptr == NULL ? "" : ptr);
|
|
|
|
if (err == 1 && (env->sc_conf.opts & RELAYD_OPT_LOGCONERR))
|
|
|
|
log_warn("relay %s, "
|
|
|
|
"session %d (%d active), %s, %s -> %s:%d, "
|
|
|
|
"%s%s%s", rlay->rl_conf.name, con->se_id,
|
|
|
|
relay_sessions, con->se_tag != 0 ?
|
|
|
|
tag_id2name(con->se_tag) : "0", ibuf, obuf,
|
|
|
|
ntohs(con->se_out.port), msg, ptr == NULL ?
|
|
|
|
"" : ",", ptr == NULL ? "" : ptr);
|
2015-12-06 20:03:27 -08:00
|
|
|
free(ptr);
|
2007-02-23 16:22:32 -08:00
|
|
|
}
|
|
|
|
|
2014-07-09 09:42:05 -07:00
|
|
|
if (proto->close != NULL)
|
|
|
|
(*proto->close)(con);
|
|
|
|
|
2015-12-06 20:03:27 -08:00
|
|
|
free(con->se_priv);
|
2017-11-27 17:51:47 -08:00
|
|
|
|
2019-05-13 02:54:07 -07:00
|
|
|
relay_connect_state(con, &con->se_in, STATE_DONE);
|
|
|
|
if (relay_reset_event(con, &con->se_in)) {
|
2012-09-21 02:56:27 -07:00
|
|
|
if (con->se_out.s == -1) {
|
2012-11-28 17:01:53 -08:00
|
|
|
/*
|
2012-09-21 02:56:27 -07:00
|
|
|
* the output was never connected,
|
|
|
|
* thus this was an inflight session.
|
|
|
|
*/
|
|
|
|
relay_inflight--;
|
|
|
|
log_debug("%s: sessions inflight decremented, now %d",
|
|
|
|
__func__, relay_inflight);
|
|
|
|
}
|
|
|
|
}
|
2017-11-27 17:51:47 -08:00
|
|
|
if (con->se_in.output != NULL)
|
|
|
|
evbuffer_free(con->se_in.output);
|
2008-01-31 04:12:50 -08:00
|
|
|
|
2019-05-13 02:54:07 -07:00
|
|
|
relay_connect_state(con, &con->se_out, STATE_DONE);
|
|
|
|
if (relay_reset_event(con, &con->se_out)) {
|
2012-04-11 01:25:26 -07:00
|
|
|
/* Some file descriptors are available again. */
|
|
|
|
if (evtimer_pending(&rlay->rl_evt, NULL)) {
|
|
|
|
evtimer_del(&rlay->rl_evt);
|
|
|
|
event_add(&rlay->rl_ev, NULL);
|
|
|
|
}
|
|
|
|
}
|
2017-11-27 17:51:47 -08:00
|
|
|
if (con->se_out.output != NULL)
|
|
|
|
evbuffer_free(con->se_out.output);
|
2012-04-11 01:25:26 -07:00
|
|
|
|
2008-01-31 04:12:50 -08:00
|
|
|
if (con->se_log != NULL)
|
|
|
|
evbuffer_free(con->se_log);
|
|
|
|
|
|
|
|
if (con->se_cnl != NULL) {
|
2007-02-21 19:32:39 -08:00
|
|
|
#if 0
|
2011-05-09 05:08:46 -07:00
|
|
|
proc_compose_imsg(env->sc_ps, PROC_PFE, -1, IMSG_KILLSTATES, -1,
|
2007-02-21 19:32:39 -08:00
|
|
|
cnl, sizeof(*cnl));
|
|
|
|
#endif
|
2008-01-31 04:12:50 -08:00
|
|
|
free(con->se_cnl);
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
free(con);
|
|
|
|
relay_sessions--;
|
|
|
|
}
|
|
|
|
|
2017-11-27 17:51:47 -08:00
|
|
|
int
|
2019-05-13 02:54:07 -07:00
|
|
|
relay_reset_event(struct rsession *con, struct ctl_relay_event *cre)
|
2017-11-27 17:51:47 -08:00
|
|
|
{
|
|
|
|
int rv = 0;
|
|
|
|
|
2019-05-13 02:54:07 -07:00
|
|
|
if (cre->state != STATE_DONE)
|
|
|
|
relay_connect_state(con, cre, STATE_CLOSED);
|
|
|
|
if (cre->bev != NULL) {
|
|
|
|
bufferevent_disable(cre->bev, EV_READ|EV_WRITE);
|
2017-11-27 17:51:47 -08:00
|
|
|
bufferevent_free(cre->bev);
|
2019-05-13 02:54:07 -07:00
|
|
|
}
|
2017-11-27 17:51:47 -08:00
|
|
|
if (cre->tls != NULL)
|
|
|
|
tls_close(cre->tls);
|
|
|
|
tls_free(cre->tls);
|
|
|
|
tls_free(cre->tls_ctx);
|
|
|
|
tls_config_free(cre->tls_cfg);
|
|
|
|
free(cre->tlscert);
|
|
|
|
if (cre->s != -1) {
|
|
|
|
close(cre->s);
|
|
|
|
rv = 1;
|
|
|
|
}
|
|
|
|
cre->bev = NULL;
|
|
|
|
cre->tls = NULL;
|
|
|
|
cre->tls_cfg = NULL;
|
|
|
|
cre->tlscert = NULL;
|
|
|
|
cre->s = -1;
|
|
|
|
|
|
|
|
return (rv);
|
|
|
|
}
|
|
|
|
|
2011-05-09 05:08:46 -07:00
|
|
|
int
|
|
|
|
relay_dispatch_pfe(int fd, struct privsep_proc *p, struct imsg *imsg)
|
2007-02-21 19:32:39 -08:00
|
|
|
{
|
2007-09-07 01:20:24 -07:00
|
|
|
struct relay *rlay;
|
2011-05-20 02:43:53 -07:00
|
|
|
struct rsession *con, se;
|
2007-02-21 19:32:39 -08:00
|
|
|
struct ctl_natlook cnl;
|
|
|
|
struct timeval tv;
|
|
|
|
struct host *host;
|
|
|
|
struct table *table;
|
|
|
|
struct ctl_status st;
|
2007-03-07 09:40:32 -08:00
|
|
|
objid_t id;
|
2011-05-20 02:43:53 -07:00
|
|
|
int cid;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2011-05-09 05:08:46 -07:00
|
|
|
switch (imsg->hdr.type) {
|
|
|
|
case IMSG_HOST_DISABLE:
|
|
|
|
memcpy(&id, imsg->data, sizeof(id));
|
|
|
|
if ((host = host_find(env, id)) == NULL)
|
2017-05-28 03:39:15 -07:00
|
|
|
fatalx("%s: desynchronized", __func__);
|
2011-05-09 05:08:46 -07:00
|
|
|
if ((table = table_find(env, host->conf.tableid)) ==
|
|
|
|
NULL)
|
2017-05-28 03:39:15 -07:00
|
|
|
fatalx("%s: invalid table id", __func__);
|
2011-05-09 05:08:46 -07:00
|
|
|
if (host->up == HOST_UP)
|
|
|
|
table->up--;
|
|
|
|
host->flags |= F_DISABLE;
|
|
|
|
host->up = HOST_UNKNOWN;
|
|
|
|
break;
|
|
|
|
case IMSG_HOST_ENABLE:
|
|
|
|
memcpy(&id, imsg->data, sizeof(id));
|
|
|
|
if ((host = host_find(env, id)) == NULL)
|
2017-05-28 03:39:15 -07:00
|
|
|
fatalx("%s: desynchronized", __func__);
|
2011-05-09 05:08:46 -07:00
|
|
|
host->flags &= ~(F_DISABLE);
|
|
|
|
host->up = HOST_UNKNOWN;
|
|
|
|
break;
|
|
|
|
case IMSG_TABLE_DISABLE:
|
|
|
|
memcpy(&id, imsg->data, sizeof(id));
|
|
|
|
if ((table = table_find(env, id)) == NULL)
|
2017-05-28 03:39:15 -07:00
|
|
|
fatalx("%s: desynchronized", __func__);
|
2011-05-09 05:08:46 -07:00
|
|
|
table->conf.flags |= F_DISABLE;
|
|
|
|
table->up = 0;
|
|
|
|
TAILQ_FOREACH(host, &table->hosts, entry)
|
2007-03-07 09:40:32 -08:00
|
|
|
host->up = HOST_UNKNOWN;
|
2011-05-09 05:08:46 -07:00
|
|
|
break;
|
|
|
|
case IMSG_TABLE_ENABLE:
|
|
|
|
memcpy(&id, imsg->data, sizeof(id));
|
|
|
|
if ((table = table_find(env, id)) == NULL)
|
2017-05-28 03:39:15 -07:00
|
|
|
fatalx("%s: desynchronized", __func__);
|
2011-05-09 05:08:46 -07:00
|
|
|
table->conf.flags &= ~(F_DISABLE);
|
|
|
|
table->up = 0;
|
|
|
|
TAILQ_FOREACH(host, &table->hosts, entry)
|
2007-03-07 09:40:32 -08:00
|
|
|
host->up = HOST_UNKNOWN;
|
2011-05-09 05:08:46 -07:00
|
|
|
break;
|
|
|
|
case IMSG_HOST_STATUS:
|
|
|
|
IMSG_SIZE_CHECK(imsg, &st);
|
|
|
|
memcpy(&st, imsg->data, sizeof(st));
|
|
|
|
if ((host = host_find(env, st.id)) == NULL)
|
2017-05-28 03:39:15 -07:00
|
|
|
fatalx("%s: invalid host id", __func__);
|
2011-05-09 05:08:46 -07:00
|
|
|
if (host->flags & F_DISABLE)
|
2007-03-07 09:40:32 -08:00
|
|
|
break;
|
2011-05-09 05:08:46 -07:00
|
|
|
if (host->up == st.up) {
|
|
|
|
log_debug("%s: host %d => %d", __func__,
|
|
|
|
host->conf.id, host->up);
|
2017-05-28 03:39:15 -07:00
|
|
|
fatalx("%s: desynchronized", __func__);
|
2011-05-09 05:08:46 -07:00
|
|
|
}
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2011-05-09 05:08:46 -07:00
|
|
|
if ((table = table_find(env, host->conf.tableid))
|
|
|
|
== NULL)
|
2017-05-28 03:39:15 -07:00
|
|
|
fatalx("%s: invalid table id", __func__);
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2011-05-09 05:08:46 -07:00
|
|
|
DPRINTF("%s: [%d] state %d for "
|
2016-09-29 15:04:28 -07:00
|
|
|
"host %u %s", __func__, p->p_ps->ps_instance, st.up,
|
2011-05-09 05:08:46 -07:00
|
|
|
host->conf.id, host->conf.name);
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2011-05-09 05:08:46 -07:00
|
|
|
if ((st.up == HOST_UNKNOWN && host->up == HOST_DOWN) ||
|
|
|
|
(st.up == HOST_DOWN && host->up == HOST_UNKNOWN)) {
|
2007-02-21 19:32:39 -08:00
|
|
|
host->up = st.up;
|
|
|
|
break;
|
2011-05-09 05:08:46 -07:00
|
|
|
}
|
|
|
|
if (st.up == HOST_UP)
|
|
|
|
table->up++;
|
|
|
|
else
|
|
|
|
table->up--;
|
|
|
|
host->up = st.up;
|
|
|
|
break;
|
|
|
|
case IMSG_NATLOOK:
|
|
|
|
bcopy(imsg->data, &cnl, sizeof(cnl));
|
|
|
|
if ((con = session_find(env, cnl.id)) == NULL ||
|
|
|
|
con->se_cnl == NULL) {
|
|
|
|
log_debug("%s: session %d: expired",
|
|
|
|
__func__, cnl.id);
|
2007-02-21 19:32:39 -08:00
|
|
|
break;
|
|
|
|
}
|
2011-05-09 05:08:46 -07:00
|
|
|
bcopy(&cnl, con->se_cnl, sizeof(*con->se_cnl));
|
|
|
|
evtimer_del(&con->se_ev);
|
|
|
|
evtimer_set(&con->se_ev, relay_natlook, con);
|
|
|
|
bzero(&tv, sizeof(tv));
|
|
|
|
evtimer_add(&con->se_ev, &tv);
|
|
|
|
break;
|
|
|
|
case IMSG_CTL_SESSION:
|
2011-05-20 02:43:53 -07:00
|
|
|
IMSG_SIZE_CHECK(imsg, &cid);
|
|
|
|
memcpy(&cid, imsg->data, sizeof(cid));
|
2011-05-09 05:08:46 -07:00
|
|
|
TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
|
|
|
|
SPLAY_FOREACH(con, session_tree,
|
|
|
|
&rlay->rl_sessions) {
|
2011-05-20 02:43:53 -07:00
|
|
|
memcpy(&se, con, sizeof(se));
|
|
|
|
se.se_cid = cid;
|
2015-12-02 05:41:27 -08:00
|
|
|
proc_compose(env->sc_ps, p->p_id,
|
|
|
|
IMSG_CTL_SESSION, &se, sizeof(se));
|
2011-05-09 05:08:46 -07:00
|
|
|
}
|
|
|
|
}
|
2015-12-02 05:41:27 -08:00
|
|
|
proc_compose(env->sc_ps, p->p_id, IMSG_CTL_END,
|
|
|
|
&cid, sizeof(cid));
|
2011-05-09 05:08:46 -07:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return (-1);
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
2011-05-09 05:08:46 -07:00
|
|
|
|
|
|
|
return (0);
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
2014-04-18 06:55:26 -07:00
|
|
|
int
|
|
|
|
relay_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg)
|
|
|
|
{
|
2018-09-19 04:28:02 -07:00
|
|
|
switch (imsg->hdr.type) {
|
|
|
|
case IMSG_CA_PRIVENC:
|
|
|
|
case IMSG_CA_PRIVDEC:
|
|
|
|
log_warnx("%s: priv%s result after timeout", __func__,
|
|
|
|
imsg->hdr.type == IMSG_CA_PRIVENC ? "enc" : "dec");
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2014-04-18 06:55:26 -07:00
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
2011-05-09 05:08:46 -07:00
|
|
|
int
|
|
|
|
relay_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
|
2007-02-21 19:32:39 -08:00
|
|
|
{
|
2017-05-27 01:33:25 -07:00
|
|
|
struct relay_ticket_key ticket;
|
|
|
|
struct relay *rlay;
|
2009-08-07 04:21:53 -07:00
|
|
|
struct rsession *con;
|
2008-06-11 11:21:19 -07:00
|
|
|
struct timeval tv;
|
|
|
|
objid_t id;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2011-05-09 05:08:46 -07:00
|
|
|
switch (imsg->hdr.type) {
|
|
|
|
case IMSG_BINDANY:
|
|
|
|
bcopy(imsg->data, &id, sizeof(id));
|
|
|
|
if ((con = session_find(env, id)) == NULL) {
|
|
|
|
log_debug("%s: session %d: expired",
|
|
|
|
__func__, id);
|
2007-02-21 19:32:39 -08:00
|
|
|
break;
|
2011-05-09 05:08:46 -07:00
|
|
|
}
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2011-05-09 05:08:46 -07:00
|
|
|
/* Will validate the result later */
|
2024-01-17 02:01:24 -08:00
|
|
|
con->se_bnds = imsg_get_fd(imsg);
|
2008-06-11 11:21:19 -07:00
|
|
|
|
2011-05-09 05:08:46 -07:00
|
|
|
evtimer_del(&con->se_ev);
|
|
|
|
evtimer_set(&con->se_ev, relay_bindany, con);
|
|
|
|
bzero(&tv, sizeof(tv));
|
|
|
|
evtimer_add(&con->se_ev, &tv);
|
|
|
|
break;
|
2011-05-19 01:56:49 -07:00
|
|
|
case IMSG_CFG_TABLE:
|
|
|
|
config_gettable(env, imsg);
|
|
|
|
break;
|
|
|
|
case IMSG_CFG_HOST:
|
|
|
|
config_gethost(env, imsg);
|
|
|
|
break;
|
|
|
|
case IMSG_CFG_PROTO:
|
|
|
|
config_getproto(env, imsg);
|
|
|
|
break;
|
2014-07-09 09:42:05 -07:00
|
|
|
case IMSG_CFG_RULE:
|
|
|
|
config_getrule(env, imsg);
|
|
|
|
break;
|
2011-05-19 01:56:49 -07:00
|
|
|
case IMSG_CFG_RELAY:
|
|
|
|
config_getrelay(env, imsg);
|
|
|
|
break;
|
2012-10-03 01:33:31 -07:00
|
|
|
case IMSG_CFG_RELAY_TABLE:
|
|
|
|
config_getrelaytable(env, imsg);
|
|
|
|
break;
|
2017-11-27 13:06:25 -08:00
|
|
|
case IMSG_CFG_RELAY_FD:
|
|
|
|
config_getrelayfd(env, imsg);
|
|
|
|
break;
|
2011-05-19 01:56:49 -07:00
|
|
|
case IMSG_CFG_DONE:
|
|
|
|
config_getcfg(env, imsg);
|
2012-01-21 05:40:48 -08:00
|
|
|
break;
|
|
|
|
case IMSG_CTL_START:
|
2011-05-19 01:56:49 -07:00
|
|
|
relay_launch();
|
|
|
|
break;
|
|
|
|
case IMSG_CTL_RESET:
|
|
|
|
config_getreset(env, imsg);
|
|
|
|
break;
|
2016-09-01 03:49:48 -07:00
|
|
|
case IMSG_TLSTICKET_REKEY:
|
2017-05-27 01:33:25 -07:00
|
|
|
IMSG_SIZE_CHECK(imsg, (&ticket));
|
|
|
|
memcpy(&env->sc_ticket, imsg->data, sizeof(env->sc_ticket));
|
|
|
|
TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
|
|
|
|
if (rlay->rl_conf.flags & F_TLS)
|
|
|
|
tls_config_add_ticket_key(rlay->rl_tls_cfg,
|
|
|
|
env->sc_ticket.tt_keyrev,
|
|
|
|
env->sc_ticket.tt_key,
|
|
|
|
sizeof(env->sc_ticket.tt_key));
|
|
|
|
}
|
2016-09-01 03:49:48 -07:00
|
|
|
break;
|
2011-05-09 05:08:46 -07:00
|
|
|
default:
|
|
|
|
return (-1);
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
2011-05-09 05:08:46 -07:00
|
|
|
|
|
|
|
return (0);
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
2014-11-19 02:24:39 -08:00
|
|
|
int
|
|
|
|
relay_dispatch_hce(int fd, struct privsep_proc *p, struct imsg *imsg)
|
|
|
|
{
|
|
|
|
switch (imsg->hdr.type) {
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
static int
|
|
|
|
relay_tls_ctx_create_proto(struct protocol *proto, struct tls_config *tls_cfg)
|
2007-02-21 19:32:39 -08:00
|
|
|
{
|
2017-05-27 01:33:25 -07:00
|
|
|
uint32_t protocols = 0;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2023-10-29 04:27:11 -07:00
|
|
|
/* Set the allowed TLS protocols */
|
2017-05-27 01:33:25 -07:00
|
|
|
if (proto->tlsflags & TLSFLAG_TLSV1_2)
|
|
|
|
protocols |= TLS_PROTOCOL_TLSv1_2;
|
2020-05-14 10:27:38 -07:00
|
|
|
if (proto->tlsflags & TLSFLAG_TLSV1_3)
|
|
|
|
protocols |= TLS_PROTOCOL_TLSv1_3;
|
2017-05-27 01:33:25 -07:00
|
|
|
if (tls_config_set_protocols(tls_cfg, protocols) == -1) {
|
|
|
|
log_warnx("could not set the TLS protocol: %s",
|
|
|
|
tls_config_error(tls_cfg));
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tls_config_set_ciphers(tls_cfg, proto->tlsciphers)) {
|
|
|
|
log_warnx("could not set the TLS cypers: %s",
|
|
|
|
tls_config_error(tls_cfg));
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((proto->tlsflags & TLSFLAG_CIPHER_SERVER_PREF) == 0)
|
|
|
|
tls_config_prefer_ciphers_client(tls_cfg);
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2016-09-01 03:49:48 -07:00
|
|
|
/*
|
2017-05-27 01:33:25 -07:00
|
|
|
* Set session ID context to a random value. It needs to be the
|
2022-12-28 13:30:15 -08:00
|
|
|
* same across all relay processes or session caching will fail.
|
2016-09-01 03:49:48 -07:00
|
|
|
*/
|
2017-05-27 01:33:25 -07:00
|
|
|
if (tls_config_set_session_id(tls_cfg, env->sc_conf.tls_sid,
|
|
|
|
sizeof(env->sc_conf.tls_sid)) == -1) {
|
|
|
|
log_warnx("could not set the TLS session ID: %s",
|
|
|
|
tls_config_error(tls_cfg));
|
|
|
|
return (-1);
|
|
|
|
}
|
2016-09-01 03:49:48 -07:00
|
|
|
|
|
|
|
/* Set callback for TLS session tickets if enabled */
|
2017-05-27 01:33:25 -07:00
|
|
|
if (proto->tickets == 1) {
|
2016-09-01 03:49:48 -07:00
|
|
|
/* set timeout to the ticket rekey time */
|
2017-05-27 01:33:25 -07:00
|
|
|
tls_config_set_session_lifetime(tls_cfg, TLS_SESSION_LIFETIME);
|
|
|
|
|
|
|
|
tls_config_add_ticket_key(tls_cfg,
|
|
|
|
env->sc_ticket.tt_keyrev, env->sc_ticket.tt_key,
|
|
|
|
sizeof(env->sc_ticket.tt_key));
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
2017-11-27 15:21:16 -08:00
|
|
|
if (tls_config_set_ecdhecurves(tls_cfg, proto->tlsecdhecurves) != 0) {
|
|
|
|
log_warnx("failed to set ecdhe curves %s: %s",
|
|
|
|
proto->tlsecdhecurves, tls_config_error(tls_cfg));
|
2017-05-27 01:33:25 -07:00
|
|
|
return (-1);
|
|
|
|
}
|
2007-02-23 16:22:32 -08:00
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
if (tls_config_set_dheparams(tls_cfg, proto->tlsdhparams) != 0) {
|
|
|
|
log_warnx("failed to set dh params %s: %s",
|
|
|
|
proto->tlsdhparams, tls_config_error(tls_cfg));
|
|
|
|
return (-1);
|
2013-09-09 10:57:44 -07:00
|
|
|
}
|
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function is not publicy exported because it is a hack until libtls
|
2017-05-28 03:39:15 -07:00
|
|
|
* has a proper privsep setup
|
2017-05-27 01:33:25 -07:00
|
|
|
*/
|
2021-01-27 12:33:05 -08:00
|
|
|
void tls_config_use_fake_private_key(struct tls_config *config);
|
2017-05-27 01:33:25 -07:00
|
|
|
|
|
|
|
int
|
|
|
|
relay_tls_ctx_create(struct relay *rlay)
|
|
|
|
{
|
|
|
|
struct tls_config *tls_cfg, *tls_client_cfg;
|
|
|
|
struct tls *tls = NULL;
|
2019-05-31 08:15:37 -07:00
|
|
|
struct relay_cert *cert;
|
2021-01-27 12:33:05 -08:00
|
|
|
int keyfound = 0;
|
2019-06-26 05:13:47 -07:00
|
|
|
char *buf = NULL, *cabuf = NULL, *ocspbuf = NULL;
|
|
|
|
off_t len = 0, calen = 0, ocsplen = 0;
|
2017-05-27 01:33:25 -07:00
|
|
|
|
|
|
|
if ((tls_cfg = tls_config_new()) == NULL) {
|
|
|
|
log_warnx("unable to allocate TLS config");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
if ((tls_client_cfg = tls_config_new()) == NULL) {
|
|
|
|
log_warnx("unable to allocate TLS config");
|
|
|
|
return (-1);
|
2014-07-11 09:59:38 -07:00
|
|
|
}
|
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
if (relay_tls_ctx_create_proto(rlay->rl_proto, tls_cfg) == -1)
|
|
|
|
goto err;
|
|
|
|
if (relay_tls_ctx_create_proto(rlay->rl_proto, tls_client_cfg) == -1)
|
2007-02-24 07:48:54 -08:00
|
|
|
goto err;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2009-04-02 07:30:51 -07:00
|
|
|
/* Verify the server certificate if we have a CA chain */
|
2017-05-27 01:33:25 -07:00
|
|
|
if (rlay->rl_conf.flags & F_TLSCLIENT) {
|
|
|
|
/*
|
|
|
|
* Currently relayd can't verify the name of certs and changing
|
|
|
|
* this is non trivial. For now just disable name verification.
|
|
|
|
*/
|
|
|
|
tls_config_insecure_noverifyname(tls_client_cfg);
|
|
|
|
|
2017-11-27 13:06:25 -08:00
|
|
|
if (rlay->rl_tls_ca_fd != -1) {
|
2024-10-28 12:56:18 -07:00
|
|
|
if ((buf = relay_load_fd(rlay->rl_tls_ca_fd, &len)) == NULL) {
|
2017-11-27 13:06:25 -08:00
|
|
|
log_warn("failed to read root certificates");
|
|
|
|
goto err;
|
|
|
|
}
|
2019-05-31 08:15:37 -07:00
|
|
|
rlay->rl_tls_ca_fd = -1;
|
2017-11-27 13:06:25 -08:00
|
|
|
|
|
|
|
if (tls_config_set_ca_mem(tls_client_cfg, buf, len) !=
|
|
|
|
0) {
|
2017-05-27 01:33:25 -07:00
|
|
|
log_warnx("failed to set root certificates: %s",
|
|
|
|
tls_config_error(tls_client_cfg));
|
|
|
|
goto err;
|
|
|
|
}
|
2017-11-27 13:06:25 -08:00
|
|
|
purge_key(&buf, len);
|
2017-05-27 01:33:25 -07:00
|
|
|
} else {
|
|
|
|
/* No root cert available so disable the checking */
|
|
|
|
tls_config_insecure_noverifycert(tls_client_cfg);
|
|
|
|
}
|
|
|
|
|
|
|
|
rlay->rl_tls_client_cfg = tls_client_cfg;
|
2009-04-02 07:30:51 -07:00
|
|
|
}
|
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
if (rlay->rl_conf.flags & F_TLS) {
|
|
|
|
log_debug("%s: loading certificate", __func__);
|
|
|
|
/*
|
|
|
|
* Use the public key as the "private" key - the secret key
|
|
|
|
* parameters are hidden in an extra process that will be
|
2023-10-29 04:27:11 -07:00
|
|
|
* contacted by the RSA engine. The TLS library needs at
|
2017-05-27 01:33:25 -07:00
|
|
|
* least the public key parameters in the current process.
|
|
|
|
*/
|
2021-01-27 12:33:05 -08:00
|
|
|
tls_config_use_fake_private_key(tls_cfg);
|
2009-04-01 07:56:38 -07:00
|
|
|
|
2019-05-31 08:15:37 -07:00
|
|
|
TAILQ_FOREACH(cert, env->sc_certs, cert_entry) {
|
|
|
|
if (cert->cert_relayid != rlay->rl_conf.id ||
|
|
|
|
cert->cert_fd == -1)
|
|
|
|
continue;
|
|
|
|
keyfound++;
|
2017-11-27 13:06:25 -08:00
|
|
|
|
2019-05-31 08:15:37 -07:00
|
|
|
if ((buf = relay_load_fd(cert->cert_fd,
|
|
|
|
&len)) == NULL) {
|
|
|
|
log_warn("failed to load tls certificate");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
cert->cert_fd = -1;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2019-06-26 05:13:47 -07:00
|
|
|
if (cert->cert_ocsp_fd != -1 &&
|
|
|
|
(ocspbuf = relay_load_fd(cert->cert_ocsp_fd,
|
|
|
|
&ocsplen)) == NULL) {
|
|
|
|
log_warn("failed to load OCSP staplefile");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
if (ocsplen == 0)
|
|
|
|
purge_key(&ocspbuf, ocsplen);
|
|
|
|
cert->cert_ocsp_fd = -1;
|
|
|
|
|
2019-05-31 08:15:37 -07:00
|
|
|
if (keyfound == 1 &&
|
|
|
|
tls_config_set_keypair_ocsp_mem(tls_cfg, buf, len,
|
2021-01-27 12:33:05 -08:00
|
|
|
NULL, 0, ocspbuf, ocsplen) != 0) {
|
2019-05-31 08:15:37 -07:00
|
|
|
log_warnx("failed to set tls certificate: %s",
|
|
|
|
tls_config_error(tls_cfg));
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* loading certificate public key */
|
|
|
|
if (keyfound == 1 &&
|
|
|
|
!ssl_load_pkey(buf, len, NULL, &rlay->rl_tls_pkey))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (tls_config_add_keypair_ocsp_mem(tls_cfg, buf, len,
|
2021-01-27 12:33:05 -08:00
|
|
|
NULL, 0, ocspbuf, ocsplen) != 0) {
|
2019-05-31 08:15:37 -07:00
|
|
|
log_warnx("failed to add tls certificate: %s",
|
|
|
|
tls_config_error(tls_cfg));
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
purge_key(&buf, len);
|
2019-06-26 05:13:47 -07:00
|
|
|
purge_key(&ocspbuf, ocsplen);
|
2019-05-31 08:15:37 -07:00
|
|
|
}
|
2017-11-27 13:06:25 -08:00
|
|
|
|
|
|
|
if (rlay->rl_tls_cacert_fd != -1) {
|
|
|
|
if ((cabuf = relay_load_fd(rlay->rl_tls_cacert_fd,
|
|
|
|
&calen)) == NULL) {
|
|
|
|
log_warn("failed to load tls CA certificate");
|
|
|
|
goto err;
|
|
|
|
}
|
2017-05-27 01:33:25 -07:00
|
|
|
log_debug("%s: loading CA certificate", __func__);
|
2017-11-27 13:06:25 -08:00
|
|
|
if (!ssl_load_pkey(cabuf, calen,
|
2017-05-27 01:33:25 -07:00
|
|
|
&rlay->rl_tls_cacertx509, &rlay->rl_tls_capkey))
|
|
|
|
goto err;
|
|
|
|
}
|
2019-05-31 08:15:37 -07:00
|
|
|
rlay->rl_tls_cacert_fd = -1;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2024-10-28 12:56:18 -07:00
|
|
|
if (rlay->rl_tls_client_ca_fd != -1) {
|
|
|
|
if ((buf = relay_load_fd(rlay->rl_tls_client_ca_fd,
|
|
|
|
&len)) == NULL) {
|
|
|
|
log_warn(
|
|
|
|
"failed to read tls client CA certificate");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tls_config_set_ca_mem(tls_cfg, buf, len) != 0) {
|
|
|
|
log_warnx(
|
|
|
|
"failed to set tls client CA cert: %s",
|
|
|
|
tls_config_error(tls_cfg));
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
purge_key(&buf, len);
|
|
|
|
|
|
|
|
tls_config_verify_client(tls_cfg);
|
|
|
|
}
|
|
|
|
rlay->rl_tls_client_ca_fd = -1;
|
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
tls = tls_server();
|
|
|
|
if (tls == NULL) {
|
|
|
|
log_warnx("unable to allocate TLS context");
|
2014-04-22 01:04:23 -07:00
|
|
|
goto err;
|
2017-05-27 01:33:25 -07:00
|
|
|
}
|
|
|
|
if (tls_configure(tls, tls_cfg) == -1) {
|
|
|
|
log_warnx("could not configure the TLS context: %s",
|
|
|
|
tls_error(tls));
|
|
|
|
tls_free(tls);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
rlay->rl_tls_cfg = tls_cfg;
|
|
|
|
rlay->rl_tls_ctx = tls;
|
2017-11-27 13:06:25 -08:00
|
|
|
|
|
|
|
purge_key(&cabuf, calen);
|
2014-04-22 01:04:23 -07:00
|
|
|
}
|
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
if (rlay->rl_tls_client_cfg == NULL)
|
|
|
|
tls_config_free(tls_client_cfg);
|
|
|
|
if (rlay->rl_tls_cfg == NULL)
|
|
|
|
tls_config_free(tls_cfg);
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
return (0);
|
2007-02-21 19:32:39 -08:00
|
|
|
err:
|
2019-06-26 05:13:47 -07:00
|
|
|
purge_key(&ocspbuf, ocsplen);
|
2017-11-27 13:06:25 -08:00
|
|
|
purge_key(&cabuf, calen);
|
|
|
|
purge_key(&buf, len);
|
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
tls_config_free(tls_client_cfg);
|
|
|
|
tls_config_free(tls_cfg);
|
|
|
|
return (-1);
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
static struct tls *
|
|
|
|
relay_tls_inspect_create(struct relay *rlay, struct ctl_relay_event *cre)
|
2007-02-21 19:32:39 -08:00
|
|
|
{
|
2017-05-27 01:33:25 -07:00
|
|
|
struct tls_config *tls_cfg;
|
2017-11-27 17:24:22 -08:00
|
|
|
struct tls *tls = NULL;
|
2017-05-27 01:33:25 -07:00
|
|
|
|
|
|
|
/* TLS inspection: use session-specific certificate */
|
|
|
|
if ((tls_cfg = tls_config_new()) == NULL) {
|
|
|
|
log_warnx("unable to allocate TLS config");
|
|
|
|
goto err;
|
|
|
|
}
|
2017-07-30 02:33:08 -07:00
|
|
|
if (relay_tls_ctx_create_proto(rlay->rl_proto, tls_cfg) == -1) {
|
|
|
|
/* error already printed */
|
2007-02-21 19:32:39 -08:00
|
|
|
goto err;
|
2009-04-01 07:56:38 -07:00
|
|
|
}
|
|
|
|
|
2021-01-27 12:33:05 -08:00
|
|
|
tls_config_use_fake_private_key(tls_cfg);
|
2017-08-09 14:29:17 -07:00
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
if (tls_config_set_keypair_ocsp_mem(tls_cfg,
|
2021-01-27 12:33:05 -08:00
|
|
|
cre->tlscert, cre->tlscert_len, NULL, 0, NULL, 0) != 0) {
|
2017-05-27 01:33:25 -07:00
|
|
|
log_warnx("failed to set tls certificate: %s",
|
|
|
|
tls_config_error(tls_cfg));
|
2007-02-21 19:32:39 -08:00
|
|
|
goto err;
|
2017-05-27 01:33:25 -07:00
|
|
|
}
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
tls = tls_server();
|
|
|
|
if (tls == NULL) {
|
|
|
|
log_warnx("unable to allocate TLS context");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
if (tls_configure(tls, tls_cfg) == -1) {
|
|
|
|
log_warnx("could not configure the TLS context: %s",
|
|
|
|
tls_error(tls));
|
|
|
|
tls_free(tls);
|
|
|
|
goto err;
|
|
|
|
}
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
cre->tls_cfg = tls_cfg;
|
2017-11-27 17:24:22 -08:00
|
|
|
cre->tls_ctx = tls;
|
2017-05-27 01:33:25 -07:00
|
|
|
return (tls);
|
2007-02-21 19:32:39 -08:00
|
|
|
err:
|
2017-05-27 01:33:25 -07:00
|
|
|
tls_config_free(tls_cfg);
|
|
|
|
return (NULL);
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-05-27 01:33:25 -07:00
|
|
|
relay_tls_transaction(struct rsession *con, struct ctl_relay_event *cre)
|
2007-02-21 19:32:39 -08:00
|
|
|
{
|
2017-05-27 01:33:25 -07:00
|
|
|
struct relay *rlay = con->se_relay;
|
|
|
|
struct tls *tls_server;
|
|
|
|
const char *errstr;
|
|
|
|
u_int flag;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
if (cre->dir == RELAY_DIR_REQUEST) {
|
|
|
|
if (cre->tlscert != NULL)
|
|
|
|
tls_server = relay_tls_inspect_create(rlay, cre);
|
|
|
|
else
|
|
|
|
tls_server = rlay->rl_tls_ctx;
|
2017-07-28 06:58:52 -07:00
|
|
|
if (tls_server == NULL) {
|
|
|
|
errstr = "no TLS server context available";
|
|
|
|
goto err;
|
|
|
|
}
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
if (tls_accept_socket(tls_server, &cre->tls, cre->s) == -1) {
|
|
|
|
errstr = "could not accept the TLS connection";
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
flag = EV_READ;
|
|
|
|
} else {
|
|
|
|
cre->tls = tls_client();
|
|
|
|
if (cre->tls == NULL ||
|
|
|
|
tls_configure(cre->tls, rlay->rl_tls_client_cfg) == -1) {
|
|
|
|
errstr = "could not configure the TLS client context";
|
|
|
|
goto err;
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
2017-05-27 01:33:25 -07:00
|
|
|
if (tls_connect_socket(cre->tls, cre->s, NULL) == -1) {
|
|
|
|
errstr = "could not connect the TLS connection";
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
flag = EV_WRITE;
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
log_debug("%s: session %d: scheduling on %s", __func__, con->se_id,
|
|
|
|
(flag == EV_READ) ? "EV_READ" : "EV_WRITE");
|
|
|
|
event_again(&con->se_ev, cre->s, EV_TIMEOUT|flag, relay_tls_handshake,
|
|
|
|
&con->se_tv_start, &rlay->rl_conf.timeout, cre);
|
2007-02-21 19:32:39 -08:00
|
|
|
return;
|
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
err:
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, errstr, 1);
|
2009-04-01 07:56:38 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-05-27 01:33:25 -07:00
|
|
|
relay_tls_handshake(int fd, short event, void *arg)
|
2009-04-01 07:56:38 -07:00
|
|
|
{
|
2017-05-27 01:33:25 -07:00
|
|
|
struct ctl_relay_event *cre = arg;
|
|
|
|
struct rsession *con = cre->con;
|
|
|
|
struct relay *rlay = con->se_relay;
|
|
|
|
int retry_flag = 0;
|
|
|
|
int ret;
|
2018-06-10 13:41:47 -07:00
|
|
|
char *msg;
|
2009-04-01 07:56:38 -07:00
|
|
|
|
|
|
|
if (event == EV_TIMEOUT) {
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, "TLS handshake timeout", 1);
|
2009-04-01 07:56:38 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
ret = tls_handshake(cre->tls);
|
|
|
|
if (ret == 0) {
|
2009-04-01 07:56:38 -07:00
|
|
|
#ifdef DEBUG
|
2017-05-27 01:33:25 -07:00
|
|
|
log_info(
|
2009-04-01 07:56:38 -07:00
|
|
|
#else
|
2017-05-27 01:33:25 -07:00
|
|
|
log_debug(
|
2009-04-01 07:56:38 -07:00
|
|
|
#endif
|
2017-05-27 01:33:25 -07:00
|
|
|
"relay %s, tls session %d %s (%d active)",
|
|
|
|
rlay->rl_conf.name, con->se_id,
|
|
|
|
cre->dir == RELAY_DIR_REQUEST ? "established" : "connected",
|
|
|
|
relay_sessions);
|
2011-05-05 05:01:43 -07:00
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
if (cre->dir == RELAY_DIR_REQUEST) {
|
2013-05-30 13:17:12 -07:00
|
|
|
relay_session(con);
|
2017-05-27 01:33:25 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rlay->rl_conf.flags & F_TLSINSPECT) {
|
|
|
|
const uint8_t *servercert;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
servercert = tls_peer_cert_chain_pem(con->se_out.tls,
|
|
|
|
&len);
|
|
|
|
if (servercert != NULL) {
|
|
|
|
con->se_in.tlscert = ssl_update_certificate(
|
|
|
|
servercert, len,
|
|
|
|
rlay->rl_tls_pkey, rlay->rl_tls_capkey,
|
|
|
|
rlay->rl_tls_cacertx509,
|
|
|
|
&con->se_in.tlscert_len);
|
|
|
|
} else
|
|
|
|
con->se_in.tlscert = NULL;
|
|
|
|
if (con->se_in.tlscert == NULL)
|
|
|
|
relay_close(con,
|
2018-08-06 10:31:31 -07:00
|
|
|
"could not create certificate", 1);
|
2017-05-27 01:33:25 -07:00
|
|
|
else
|
|
|
|
relay_session(con);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
relay_connected(fd, EV_WRITE, con);
|
|
|
|
return;
|
|
|
|
} else if (ret == TLS_WANT_POLLIN) {
|
|
|
|
retry_flag = EV_READ;
|
|
|
|
} else if (ret == TLS_WANT_POLLOUT) {
|
|
|
|
retry_flag = EV_WRITE;
|
|
|
|
} else {
|
2018-06-10 13:41:47 -07:00
|
|
|
if (asprintf(&msg, "TLS handshake error: %s",
|
|
|
|
tls_error(cre->tls)) >= 0) {
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, msg, 1);
|
2018-06-10 13:41:47 -07:00
|
|
|
free(msg);
|
|
|
|
} else {
|
2018-08-06 10:31:31 -07:00
|
|
|
relay_close(con, "TLS handshake error", 1);
|
2018-06-10 13:41:47 -07:00
|
|
|
}
|
2013-05-30 13:17:12 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-05-05 05:01:43 -07:00
|
|
|
DPRINTF("%s: session %d: scheduling on %s", __func__, con->se_id,
|
2009-04-01 07:56:38 -07:00
|
|
|
(retry_flag == EV_READ) ? "EV_READ" : "EV_WRITE");
|
2017-05-27 01:33:25 -07:00
|
|
|
event_again(&con->se_ev, fd, EV_TIMEOUT|retry_flag, relay_tls_handshake,
|
|
|
|
&con->se_tv_start, &rlay->rl_conf.timeout, cre);
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-12-12 02:05:09 -08:00
|
|
|
relay_tls_connected(struct ctl_relay_event *cre)
|
2007-02-21 19:32:39 -08:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Hack libevent - we overwrite the internal bufferevent I/O
|
2014-12-12 02:05:09 -08:00
|
|
|
* functions to handle the TLS abstraction.
|
2007-02-21 19:32:39 -08:00
|
|
|
*/
|
2017-11-26 19:40:04 -08:00
|
|
|
event_del(&cre->bev->ev_read);
|
|
|
|
event_del(&cre->bev->ev_write);
|
|
|
|
|
2007-02-21 19:32:39 -08:00
|
|
|
event_set(&cre->bev->ev_read, cre->s, EV_READ,
|
2014-12-12 02:05:09 -08:00
|
|
|
relay_tls_readcb, cre->bev);
|
2007-02-21 19:32:39 -08:00
|
|
|
event_set(&cre->bev->ev_write, cre->s, EV_WRITE,
|
2014-12-12 02:05:09 -08:00
|
|
|
relay_tls_writecb, cre->bev);
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-12-12 02:05:09 -08:00
|
|
|
relay_tls_readcb(int fd, short event, void *arg)
|
2007-02-21 19:32:39 -08:00
|
|
|
{
|
2014-06-27 00:49:08 -07:00
|
|
|
char rbuf[IBUF_READ_SIZE];
|
|
|
|
struct bufferevent *bufev = arg;
|
|
|
|
struct ctl_relay_event *cre = bufev->cbarg;
|
|
|
|
short what = EVBUFFER_READ;
|
|
|
|
int howmuch = IBUF_READ_SIZE;
|
2017-05-27 01:33:25 -07:00
|
|
|
ssize_t ret;
|
2014-06-27 00:49:08 -07:00
|
|
|
size_t len;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
|
|
|
if (event == EV_TIMEOUT) {
|
|
|
|
what |= EVBUFFER_TIMEOUT;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bufev->wm_read.high != 0)
|
2015-01-16 07:06:40 -08:00
|
|
|
howmuch = MINIMUM(sizeof(rbuf), bufev->wm_read.high);
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
ret = tls_read(cre->tls, rbuf, howmuch);
|
|
|
|
if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT) {
|
|
|
|
goto retry;
|
2019-06-28 06:32:41 -07:00
|
|
|
} else if (ret == -1) {
|
2017-05-27 01:33:25 -07:00
|
|
|
what |= EVBUFFER_ERROR;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
len = ret;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
2017-05-27 01:33:25 -07:00
|
|
|
if (len == 0) {
|
|
|
|
what |= EVBUFFER_EOF;
|
|
|
|
goto err;
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (evbuffer_add(bufev->input, rbuf, ret) == -1) {
|
|
|
|
what |= EVBUFFER_ERROR;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
relay_bufferevent_add(&bufev->ev_read, bufev->timeout_read);
|
|
|
|
|
|
|
|
len = EVBUFFER_LENGTH(bufev->input);
|
|
|
|
if (bufev->wm_read.low != 0 && len < bufev->wm_read.low)
|
|
|
|
return;
|
|
|
|
if (bufev->wm_read.high != 0 && len > bufev->wm_read.high) {
|
|
|
|
struct evbuffer *buf = bufev->input;
|
|
|
|
event_del(&bufev->ev_read);
|
|
|
|
evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bufev->readcb != NULL)
|
|
|
|
(*bufev->readcb)(bufev, bufev->cbarg);
|
|
|
|
return;
|
|
|
|
|
|
|
|
retry:
|
|
|
|
relay_bufferevent_add(&bufev->ev_read, bufev->timeout_read);
|
|
|
|
return;
|
|
|
|
|
|
|
|
err:
|
|
|
|
(*bufev->errorcb)(bufev, what, bufev->cbarg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-12-12 02:05:09 -08:00
|
|
|
relay_tls_writecb(int fd, short event, void *arg)
|
2007-02-21 19:32:39 -08:00
|
|
|
{
|
2014-06-27 00:49:08 -07:00
|
|
|
struct bufferevent *bufev = arg;
|
|
|
|
struct ctl_relay_event *cre = bufev->cbarg;
|
2017-05-27 01:33:25 -07:00
|
|
|
ssize_t ret;
|
|
|
|
size_t len;
|
2014-06-27 00:49:08 -07:00
|
|
|
short what = EVBUFFER_WRITE;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
|
|
|
if (event == EV_TIMEOUT) {
|
|
|
|
what |= EVBUFFER_TIMEOUT;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (EVBUFFER_LENGTH(bufev->output)) {
|
2017-05-27 01:33:25 -07:00
|
|
|
ret = tls_write(cre->tls, EVBUFFER_DATA(bufev->output),
|
|
|
|
EVBUFFER_LENGTH(bufev->output));
|
|
|
|
if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT) {
|
|
|
|
goto retry;
|
2019-06-28 06:32:41 -07:00
|
|
|
} else if (ret == -1) {
|
2017-05-27 01:33:25 -07:00
|
|
|
what |= EVBUFFER_ERROR;
|
|
|
|
goto err;
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
2017-05-27 01:33:25 -07:00
|
|
|
len = ret;
|
|
|
|
evbuffer_drain(bufev->output, len);
|
2007-02-21 19:32:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (EVBUFFER_LENGTH(bufev->output) != 0)
|
|
|
|
relay_bufferevent_add(&bufev->ev_write, bufev->timeout_write);
|
|
|
|
|
|
|
|
if (bufev->writecb != NULL &&
|
|
|
|
EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low)
|
|
|
|
(*bufev->writecb)(bufev, bufev->cbarg);
|
|
|
|
return;
|
|
|
|
|
|
|
|
retry:
|
2017-05-27 01:33:25 -07:00
|
|
|
relay_bufferevent_add(&bufev->ev_write, bufev->timeout_write);
|
2007-02-21 19:32:39 -08:00
|
|
|
return;
|
|
|
|
|
|
|
|
err:
|
|
|
|
(*bufev->errorcb)(bufev, what, bufev->cbarg);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
relay_bufferevent_add(struct event *ev, int timeout)
|
|
|
|
{
|
|
|
|
struct timeval tv, *ptv = NULL;
|
|
|
|
|
|
|
|
if (timeout) {
|
|
|
|
timerclear(&tv);
|
|
|
|
tv.tv_sec = timeout;
|
|
|
|
ptv = &tv;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (event_add(ev, ptv));
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef notyet
|
|
|
|
int
|
|
|
|
relay_bufferevent_printf(struct ctl_relay_event *cre, const char *fmt, ...)
|
|
|
|
{
|
2014-06-27 00:49:08 -07:00
|
|
|
int ret;
|
|
|
|
va_list ap;
|
2007-02-21 19:32:39 -08:00
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
ret = evbuffer_add_vprintf(cre->output, fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
if (cre->bev != NULL &&
|
|
|
|
ret != -1 && EVBUFFER_LENGTH(cre->output) > 0 &&
|
|
|
|
(cre->bev->enabled & EV_WRITE))
|
|
|
|
bufferevent_enable(cre->bev, EV_WRITE);
|
|
|
|
|
|
|
|
return (ret);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int
|
2014-07-09 09:42:05 -07:00
|
|
|
relay_bufferevent_print(struct ctl_relay_event *cre, const char *str)
|
2007-02-21 19:32:39 -08:00
|
|
|
{
|
|
|
|
if (cre->bev == NULL)
|
|
|
|
return (evbuffer_add(cre->output, str, strlen(str)));
|
|
|
|
return (bufferevent_write(cre->bev, str, strlen(str)));
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2007-02-26 04:11:19 -08:00
|
|
|
relay_bufferevent_write_buffer(struct ctl_relay_event *cre,
|
|
|
|
struct evbuffer *buf)
|
2007-02-21 19:32:39 -08:00
|
|
|
{
|
|
|
|
if (cre->bev == NULL)
|
|
|
|
return (evbuffer_add_buffer(cre->output, buf));
|
|
|
|
return (bufferevent_write_buffer(cre->bev, buf));
|
|
|
|
}
|
|
|
|
|
2007-02-26 04:35:43 -08:00
|
|
|
int
|
|
|
|
relay_bufferevent_write_chunk(struct ctl_relay_event *cre,
|
|
|
|
struct evbuffer *buf, size_t size)
|
|
|
|
{
|
|
|
|
int ret;
|
2023-09-03 03:22:03 -07:00
|
|
|
ret = relay_bufferevent_write(cre, EVBUFFER_DATA(buf), size);
|
2007-02-26 04:35:43 -08:00
|
|
|
if (ret != -1)
|
|
|
|
evbuffer_drain(buf, size);
|
|
|
|
return (ret);
|
|
|
|
}
|
|
|
|
|
2007-02-21 19:32:39 -08:00
|
|
|
int
|
|
|
|
relay_bufferevent_write(struct ctl_relay_event *cre, void *data, size_t size)
|
|
|
|
{
|
|
|
|
if (cre->bev == NULL)
|
|
|
|
return (evbuffer_add(cre->output, data, size));
|
|
|
|
return (bufferevent_write(cre->bev, data, size));
|
|
|
|
}
|
|
|
|
|
2007-09-10 04:59:22 -07:00
|
|
|
int
|
|
|
|
relay_cmp_af(struct sockaddr_storage *a, struct sockaddr_storage *b)
|
|
|
|
{
|
2014-06-27 00:49:08 -07:00
|
|
|
int ret = -1;
|
|
|
|
struct sockaddr_in ia, ib;
|
|
|
|
struct sockaddr_in6 ia6, ib6;
|
2007-09-10 04:59:22 -07:00
|
|
|
|
|
|
|
switch (a->ss_family) {
|
|
|
|
case AF_INET:
|
|
|
|
bcopy(a, &ia, sizeof(struct sockaddr_in));
|
|
|
|
bcopy(b, &ib, sizeof(struct sockaddr_in));
|
|
|
|
|
2008-03-03 08:41:36 -08:00
|
|
|
ret = memcmp(&ia.sin_addr, &ib.sin_addr,
|
|
|
|
sizeof(ia.sin_addr));
|
|
|
|
if (ret == 0)
|
|
|
|
ret = memcmp(&ia.sin_port, &ib.sin_port,
|
|
|
|
sizeof(ia.sin_port));
|
2007-09-10 04:59:22 -07:00
|
|
|
break;
|
|
|
|
case AF_INET6:
|
|
|
|
bcopy(a, &ia6, sizeof(struct sockaddr_in6));
|
|
|
|
bcopy(b, &ib6, sizeof(struct sockaddr_in6));
|
|
|
|
|
2008-03-03 08:41:36 -08:00
|
|
|
ret = memcmp(&ia6.sin6_addr, &ib6.sin6_addr,
|
|
|
|
sizeof(ia6.sin6_addr));
|
|
|
|
if (ret == 0)
|
|
|
|
ret = memcmp(&ia6.sin6_port, &ib6.sin6_port,
|
|
|
|
sizeof(ia6.sin6_port));
|
2007-09-10 04:59:22 -07:00
|
|
|
break;
|
|
|
|
default:
|
2008-03-03 08:41:36 -08:00
|
|
|
break;
|
2007-09-10 04:59:22 -07:00
|
|
|
}
|
2008-03-03 08:41:36 -08:00
|
|
|
|
|
|
|
return (ret);
|
2007-09-10 04:59:22 -07:00
|
|
|
}
|
|
|
|
|
2007-09-05 01:48:42 -07:00
|
|
|
int
|
2009-08-07 04:21:53 -07:00
|
|
|
relay_session_cmp(struct rsession *a, struct rsession *b)
|
2007-09-05 01:48:42 -07:00
|
|
|
{
|
2013-01-17 12:34:18 -08:00
|
|
|
struct relay *rlay = b->se_relay;
|
2008-01-31 01:56:28 -08:00
|
|
|
struct protocol *proto = rlay->rl_proto;
|
2007-09-05 01:48:42 -07:00
|
|
|
|
2007-09-05 03:25:13 -07:00
|
|
|
if (proto != NULL && proto->cmp != NULL)
|
2007-09-05 01:48:42 -07:00
|
|
|
return ((*proto->cmp)(a, b));
|
|
|
|
|
2008-01-31 04:12:50 -08:00
|
|
|
return ((int)a->se_id - b->se_id);
|
2007-09-05 01:48:42 -07:00
|
|
|
}
|
|
|
|
|
2014-07-12 17:32:08 -07:00
|
|
|
void
|
|
|
|
relay_log(struct rsession *con, char *msg)
|
|
|
|
{
|
|
|
|
if (con->se_haslog && con->se_log != NULL) {
|
|
|
|
evbuffer_add(con->se_log, msg, strlen(msg));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-07 04:21:53 -07:00
|
|
|
SPLAY_GENERATE(session_tree, rsession, se_nodes, relay_session_cmp);
|