src/usr.sbin/relayd/relayd.h
2023-06-25 21:25:02 +00:00

1486 lines
38 KiB
C

/* $OpenBSD: relayd.h,v 1.271 2023/06/25 08:07:39 op Exp $ */
/*
* Copyright (c) 2006 - 2016 Reyk Floeter <reyk@openbsd.org>
* Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF 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.
*/
#ifndef RELAYD_H
#define RELAYD_H
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/queue.h>
#include <sys/tree.h>
#include <sys/time.h>
#include <sys/un.h>
#include <net/if.h>
#include <net/pfvar.h>
#include <stdarg.h>
#include <limits.h>
#include <siphash.h>
#include <event.h>
#include <imsg.h>
#include <openssl/ssl.h>
#include <tls.h>
#ifndef nitems
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
#endif
#define CONF_FILE "/etc/relayd.conf"
#define RELAYD_SOCKET "/var/run/relayd.sock"
#define PF_SOCKET "/dev/pf"
#define RELAYD_USER "_relayd"
#define RELAYD_ANCHOR "relayd"
#define RELAYD_SERVERNAME "OpenBSD relayd"
#define CHECK_TIMEOUT 200
#define CHECK_INTERVAL 10
#define EMPTY_TABLE UINT_MAX
#define EMPTY_ID UINT_MAX
#define LABEL_NAME_SIZE 1024
#define TAG_NAME_SIZE 64
#define TABLE_NAME_SIZE 64
#define RD_TAG_NAME_SIZE 64
#define RT_LABEL_SIZE 32
#define SRV_NAME_SIZE 64
#define MAX_NAME_SIZE 64
#define SRV_MAX_VIRTS 16
#define TLS_NAME_SIZE 512
#define TLS_CERT_HASH_SIZE 128
#define RELAY_MAX_PREFETCH 256
#define RELAY_MIN_PREFETCHED 32
#define FD_RESERVE 5
#define RELAY_MAX_BACKLOG 512
#define RELAY_TIMEOUT 600
#define RELAY_CACHESIZE -1 /* use default size */
#define RELAY_NUMPROC 3
#define RELAY_MAXHOSTS 32
#define RELAY_MAXHEADERLENGTH 131072
#define RELAY_DEFHEADERLENGTH 8192
#define RELAY_STATINTERVAL 60
#define RELAY_BACKLOG 10
#define RELAY_MAXLOOKUPLEVELS 5
#define RELAY_OUTOF_FD_RETRIES 5
#define RELAY_MAX_HASH_RETRIES 5
#define RELAY_TLS_PRIV_TIMEOUT 1000 /* wait 1sec for the ca */
#define CONFIG_RELOAD 0x00
#define CONFIG_TABLES 0x01
#define CONFIG_RDRS 0x02
#define CONFIG_RELAYS 0x04
#define CONFIG_PROTOS 0x08
#define CONFIG_ROUTES 0x10
#define CONFIG_RTS 0x20
#define CONFIG_CA_ENGINE 0x40
#define CONFIG_CERTS 0x80
#define CONFIG_ALL 0xff
#define SMALL_READ_BUF_SIZE 1024
#define ICMP_BUF_SIZE 64
#define ICMP_RCVBUF_SIZE 262144
#define AGENTX_RECONNECT_TIMEOUT { 3, 0 } /* sec, usec */
#define PROC_PARENT_SOCK_FILENO 3
#define PROC_MAX_INSTANCES 32
#if DEBUG > 1
#define DPRINTF log_debug
#define DEBUG_CERT 1
#else
#define DPRINTF(x...) do {} while(0)
#endif
/* Used for DNS request ID randomization */
struct shuffle {
u_int16_t id_shuffle[65536];
int isindex;
};
typedef u_int32_t objid_t;
struct ctl_status {
objid_t id;
int up;
int retry_cnt;
u_long check_cnt;
u_int16_t he;
};
struct ctl_id {
objid_t id;
char name[MAX_NAME_SIZE];
};
struct ctl_relaytable {
objid_t id;
objid_t relayid;
int mode;
u_int32_t flags;
};
enum fd_type {
RELAY_FD_CERT = 1,
RELAY_FD_CACERT = 2,
RELAY_FD_CAFILE = 3,
RELAY_FD_KEY = 4,
RELAY_FD_OCSP = 5
};
struct ctl_relayfd {
objid_t id;
objid_t relayid;
enum fd_type type;
};
struct ctl_script {
objid_t host;
int retval;
struct timeval timeout;
char name[HOST_NAME_MAX+1];
char path[PATH_MAX];
};
struct ctl_demote {
char group[IFNAMSIZ];
int level;
};
struct ctl_icmp_event {
struct relayd *env;
int s;
int af;
int last_up;
struct event ev;
struct timeval tv_start;
};
struct ctl_tcp_event {
int s;
struct ibuf *buf;
struct host *host;
struct table *table;
struct timeval tv_start;
struct event ev;
int (*validate_read)(struct ctl_tcp_event *);
int (*validate_close)(struct ctl_tcp_event *);
struct tls *tls;
};
enum direction {
RELAY_DIR_INVALID = -1,
RELAY_DIR_ANY = 0,
RELAY_DIR_REQUEST = 1,
RELAY_DIR_RESPONSE = 2
};
enum relay_state {
STATE_INIT,
STATE_PENDING,
STATE_PRECONNECT,
STATE_CONNECTED,
STATE_CLOSED,
STATE_DONE
};
struct ctl_relay_event {
int s;
in_port_t port;
struct sockaddr_storage ss;
struct bufferevent *bev;
struct evbuffer *output;
struct ctl_relay_event *dst;
struct rsession *con;
struct tls *tls;
struct tls_config *tls_cfg;
struct tls *tls_ctx;
uint8_t *tlscert;
size_t tlscert_len;
off_t splicelen;
off_t toread;
size_t headerlen;
int line;
int done;
int timedout;
enum relay_state state;
enum direction dir;
/* protocol-specific descriptor */
void *desc;
};
enum httpchunk {
TOREAD_UNLIMITED = -1,
TOREAD_HTTP_HEADER = -2,
TOREAD_HTTP_CHUNK_LENGTH = -3,
TOREAD_HTTP_CHUNK_TRAILER = -4
};
struct ctl_natlook {
objid_t id;
int proc;
struct sockaddr_storage src;
struct sockaddr_storage dst;
struct sockaddr_storage rsrc;
struct sockaddr_storage rdst;
in_port_t rsport;
in_port_t rdport;
int in;
int proto;
};
struct ctl_bindany {
objid_t bnd_id;
int bnd_proc;
struct sockaddr_storage bnd_ss;
in_port_t bnd_port;
int bnd_proto;
};
struct ctl_keyop {
char cko_hash[TLS_CERT_HASH_SIZE];
int cko_proc;
int cko_flen;
int cko_tlen;
int cko_padding;
u_int cko_cookie;
};
struct ctl_stats {
objid_t id;
int proc;
u_int64_t interval;
u_int64_t cnt;
u_int32_t tick;
u_int32_t avg;
u_int32_t last;
u_int32_t avg_hour;
u_int32_t last_hour;
u_int32_t avg_day;
u_int32_t last_day;
};
enum key_option {
KEY_OPTION_NONE = 0,
KEY_OPTION_APPEND,
KEY_OPTION_SET,
KEY_OPTION_REMOVE,
KEY_OPTION_HASH,
KEY_OPTION_LOG,
KEY_OPTION_STRIP
};
enum key_type {
KEY_TYPE_NONE = 0,
KEY_TYPE_COOKIE,
KEY_TYPE_HEADER,
KEY_TYPE_PATH,
KEY_TYPE_QUERY,
KEY_TYPE_URL,
KEY_TYPE_MAX
};
struct ctl_kvlen {
ssize_t key;
ssize_t value;
};
struct ctl_rule {
struct ctl_kvlen kvlen[KEY_TYPE_MAX];
};
enum digest_type {
DIGEST_NONE = 0,
DIGEST_SHA1 = 1,
DIGEST_MD5 = 2
};
TAILQ_HEAD(kvlist, kv);
RB_HEAD(kvtree, kv);
struct kv {
char *kv_key;
char *kv_value;
enum key_type kv_type;
enum key_option kv_option;
enum digest_type kv_digest;
#define KV_FLAG_MACRO 0x01
#define KV_FLAG_INVALID 0x02
#define KV_FLAG_GLOBBING 0x04
u_int8_t kv_flags;
struct kvlist kv_children;
struct kv *kv_parent;
TAILQ_ENTRY(kv) kv_entry;
RB_ENTRY(kv) kv_node;
/* A few pointers used by the rule actions */
struct kv *kv_match;
struct kvtree *kv_matchtree;
TAILQ_ENTRY(kv) kv_match_entry;
TAILQ_ENTRY(kv) kv_rule_entry;
TAILQ_ENTRY(kv) kv_action_entry;
};
struct portrange {
in_port_t val[2];
u_int8_t op;
};
struct address {
objid_t rdrid;
struct sockaddr_storage ss;
int ipproto;
struct portrange port;
char ifname[IFNAMSIZ];
TAILQ_ENTRY(address) entry;
};
TAILQ_HEAD(addresslist, address);
union hashkey {
/* Simplified version of pf_poolhashkey */
u_int32_t data[4];
SIPHASH_KEY siphashkey;
};
#define F_DISABLE 0x00000001
#define F_BACKUP 0x00000002
#define F_USED 0x00000004
#define F_DOWN 0x00000008
#define F_ADD 0x00000010
#define F_DEL 0x00000020
#define F_CHANGED 0x00000040
#define F_STICKY 0x00000080
#define F_CHECK_DONE 0x00000100
#define F_ACTIVE_RULESET 0x00000200
#define F_CHECK_SENT 0x00000400
#define F_TLS 0x00000800
#define F_NATLOOK 0x00001000
#define F_DEMOTE 0x00002000
#define F_LOOKUP_PATH 0x00004000
#define F_DEMOTED 0x00008000
#define F_UDP 0x00010000
#define F_RETURN 0x00020000
#define F_AGENTX 0x00040000
#define F_NEEDPF 0x00080000
#define F_PORT 0x00100000
#define F_TLSCLIENT 0x00200000
#define F_NEEDRT 0x00400000
#define F_MATCH 0x00800000
#define F_DIVERT 0x01000000
#define F_SCRIPT 0x02000000
#define F_TLSINSPECT 0x04000000
#define F_HASHKEY 0x08000000
#define F_AGENTX_TRAPONLY 0x10000000
#define F_BITS \
"\10\01DISABLE\02BACKUP\03USED\04DOWN\05ADD\06DEL\07CHANGED" \
"\10STICKY-ADDRESS\11CHECK_DONE\12ACTIVE_RULESET\13CHECK_SENT" \
"\14TLS\15NAT_LOOKUP\16DEMOTE\17LOOKUP_PATH\20DEMOTED\21UDP" \
"\22RETURN\23TRAP\24NEEDPF\25PORT\26TLS_CLIENT\27NEEDRT" \
"\30MATCH\31DIVERT\32SCRIPT\33TLS_INSPECT\34HASHKEY" \
"\35AGENTX_TRAPONLY"
enum forwardmode {
FWD_NORMAL = 0,
FWD_ROUTE,
FWD_TRANS
};
struct host_config {
objid_t id;
objid_t parentid;
objid_t tableid;
int retry;
char name[HOST_NAME_MAX+1];
struct sockaddr_storage ss;
int ttl;
int priority;
};
struct host {
TAILQ_ENTRY(host) entry;
TAILQ_ENTRY(host) globalentry;
SLIST_ENTRY(host) child;
SLIST_HEAD(,host) children;
struct host_config conf;
u_int32_t flags;
char *tablename;
int up;
int last_up;
u_long check_cnt;
u_long up_cnt;
int retry_cnt;
int idx;
u_int16_t he;
int code;
struct ctl_tcp_event cte;
};
TAILQ_HEAD(hostlist, host);
enum host_error {
HCE_NONE = 0,
HCE_ABORT,
HCE_INTERVAL_TIMEOUT,
HCE_ICMP_OK,
HCE_ICMP_READ_TIMEOUT,
HCE_ICMP_WRITE_TIMEOUT,
HCE_TCP_SOCKET_ERROR,
HCE_TCP_SOCKET_LIMIT,
HCE_TCP_SOCKET_OPTION,
HCE_TCP_CONNECT_FAIL,
HCE_TCP_CONNECT_TIMEOUT,
HCE_TCP_CONNECT_OK,
HCE_TCP_WRITE_TIMEOUT,
HCE_TCP_WRITE_FAIL,
HCE_TCP_READ_TIMEOUT,
HCE_TCP_READ_FAIL,
HCE_SCRIPT_OK,
HCE_SCRIPT_FAIL,
HCE_TLS_CONNECT_ERROR,
HCE_TLS_CONNECT_FAIL,
HCE_TLS_CONNECT_OK,
HCE_TLS_CONNECT_TIMEOUT,
HCE_TLS_READ_TIMEOUT,
HCE_TLS_WRITE_TIMEOUT,
HCE_TLS_READ_ERROR,
HCE_TLS_WRITE_ERROR,
HCE_SEND_EXPECT_FAIL,
HCE_SEND_EXPECT_OK,
HCE_HTTP_CODE_ERROR,
HCE_HTTP_CODE_FAIL,
HCE_HTTP_CODE_OK,
HCE_HTTP_DIGEST_ERROR,
HCE_HTTP_DIGEST_FAIL,
HCE_HTTP_DIGEST_OK,
};
enum host_status {
HOST_DOWN = -1,
HOST_UNKNOWN = 0,
HOST_UP = 1
};
#define HOST_ISUP(x) (x == HOST_UP)
struct table_config {
objid_t id;
objid_t rdrid;
u_int32_t flags;
int check;
char demote_group[IFNAMSIZ];
char ifname[IFNAMSIZ];
struct timeval timeout;
in_port_t port;
int retcode;
int skip_cnt;
char name[TABLE_NAME_SIZE];
size_t name_len;
char path[PATH_MAX];
unsigned char exbinbuf[128];
char exbuf[256];
char digest[41]; /* length of sha1 digest * 2 */
u_int8_t digest_type;
enum forwardmode fwdmode;
};
struct table {
TAILQ_ENTRY(table) entry;
struct table_config conf;
int up;
int skipped;
struct hostlist hosts;
struct tls_config *tls_cfg;
struct ibuf *sendbinbuf;
char *sendbuf;
};
TAILQ_HEAD(tablelist, table);
enum table_check {
CHECK_NOCHECK = 0,
CHECK_ICMP = 1,
CHECK_TCP = 2,
CHECK_HTTP_CODE = 3,
CHECK_HTTP_DIGEST = 4,
CHECK_BINSEND_EXPECT = 5,
CHECK_SEND_EXPECT = 6,
CHECK_SCRIPT = 7
};
struct rdr_config {
objid_t id;
u_int32_t flags;
in_port_t port;
objid_t table_id;
objid_t backup_id;
int mode;
union hashkey key;
char name[SRV_NAME_SIZE];
char tag[RD_TAG_NAME_SIZE];
struct timeval timeout;
};
struct rdr {
TAILQ_ENTRY(rdr) entry;
struct rdr_config conf;
struct addresslist virts;
struct table *table;
struct table *backup; /* use this if no host up */
struct ctl_stats stats;
};
TAILQ_HEAD(rdrlist, rdr);
struct rsession {
objid_t se_id;
objid_t se_relayid;
struct sockaddr_storage se_sockname;
struct ctl_relay_event se_in;
struct ctl_relay_event se_out;
void *se_priv;
SIPHASH_CTX se_siphashctx;
struct relay_table *se_table;
struct relay_table *se_table0;
struct event se_ev;
struct timeval se_timeout;
struct timeval se_tv_start;
struct timeval se_tv_last;
struct event se_inflightevt;
int se_done;
int se_retry;
int se_retrycount;
int se_connectcount;
int se_haslog;
struct evbuffer *se_log;
struct relay *se_relay;
struct ctl_natlook *se_cnl;
int se_bnds;
u_int16_t se_tag;
u_int16_t se_label;
int se_cid;
pid_t se_pid;
SPLAY_ENTRY(rsession) se_nodes;
TAILQ_ENTRY(rsession) se_entry;
};
SPLAY_HEAD(session_tree, rsession);
TAILQ_HEAD(sessionlist, rsession);
enum prototype {
RELAY_PROTO_TCP = 0,
RELAY_PROTO_HTTP,
RELAY_PROTO_DNS
};
enum relay_result {
RES_DROP = 0,
RES_PASS = 1,
RES_FAIL = -1,
RES_BAD = -2,
RES_INTERNAL = -3
};
enum rule_action {
RULE_ACTION_MATCH = 0,
RULE_ACTION_PASS,
RULE_ACTION_BLOCK
};
struct rule_addr {
struct sockaddr_storage addr;
u_int8_t addr_mask;
int addr_port;
};
#define RELAY_ADDR_EQ(_a, _b) \
((_a)->addr_mask == (_b)->addr_mask && \
sockaddr_cmp((struct sockaddr *)&(_a)->addr, \
(struct sockaddr *)&(_b)->addr, (_a)->addr_mask) == 0)
#define RELAY_ADDR_CMP(_a, _b) \
sockaddr_cmp((struct sockaddr *)&(_a)->addr, \
(struct sockaddr *)(_b), (_a)->addr_mask)
#define RELAY_ADDR_NEQ(_a, _b) \
((_a)->addr_mask != (_b)->addr_mask || \
sockaddr_cmp((struct sockaddr *)&(_a)->addr, \
(struct sockaddr *)&(_b)->addr, (_a)->addr_mask) != 0)
#define RELAY_AF_NEQ(_a, _b) \
(((_a) != AF_UNSPEC) && ((_b) != AF_UNSPEC) && \
((_a) != (_b)))
struct relay_rule {
objid_t rule_id;
objid_t rule_protoid;
u_int rule_action;
#define RULE_SKIP_PROTO 0
#define RULE_SKIP_DIR 1
#define RULE_SKIP_AF 2
#define RULE_SKIP_SRC 3
#define RULE_SKIP_DST 4
#define RULE_SKIP_METHOD 5
#define RULE_SKIP_COUNT 6
struct relay_rule *rule_skip[RULE_SKIP_COUNT];
#define RULE_FLAG_QUICK 0x01
u_int8_t rule_flags;
int rule_label;
int rule_tag;
int rule_tagged;
enum direction rule_dir;
u_int rule_proto;
int rule_af;
struct rule_addr rule_src;
struct rule_addr rule_dst;
struct relay_table *rule_table;
u_int rule_method;
char rule_labelname[LABEL_NAME_SIZE];
char rule_tablename[TABLE_NAME_SIZE];
char rule_taggedname[TAG_NAME_SIZE];
char rule_tagname[TAG_NAME_SIZE];
struct ctl_rule rule_ctl;
struct kv rule_kv[KEY_TYPE_MAX];
struct kvlist rule_kvlist;
TAILQ_ENTRY(relay_rule) rule_entry;
};
TAILQ_HEAD(relay_rules, relay_rule);
#define TCPFLAG_NODELAY 0x01
#define TCPFLAG_NNODELAY 0x02
#define TCPFLAG_SACK 0x04
#define TCPFLAG_NSACK 0x08
#define TCPFLAG_BUFSIZ 0x10
#define TCPFLAG_IPTTL 0x20
#define TCPFLAG_IPMINTTL 0x40
#define TCPFLAG_NSPLICE 0x80
#define TCPFLAG_DEFAULT 0x00
#define TCPFLAG_BITS \
"\10\01NODELAY\02NO_NODELAY\03SACK\04NO_SACK" \
"\05SOCKET_BUFFER_SIZE\06IP_TTL\07IP_MINTTL\10NO_SPLICE"
#define TLSFLAG_SSLV3 0x01
#define TLSFLAG_TLSV1_0 0x02
#define TLSFLAG_TLSV1_1 0x04
#define TLSFLAG_TLSV1_2 0x08
#define TLSFLAG_TLSV1_3 0x10
#define TLSFLAG_TLSV1 0x1e
#define TLSFLAG_VERSION 0x1f
#define TLSFLAG_CIPHER_SERVER_PREF 0x20
#define TLSFLAG_CLIENT_RENEG 0x40
#define TLSFLAG_DEFAULT \
(TLSFLAG_TLSV1_2|TLSFLAG_TLSV1_3|TLSFLAG_CIPHER_SERVER_PREF)
#define TLSFLAG_BITS \
"\06\01sslv3\02tlsv1.0\03tlsv1.1\04tlsv1.2\05tlsv1.3" \
"\06cipher-server-preference\07client-renegotiation"
#define TLSCIPHERS_DEFAULT "HIGH:!aNULL"
#define TLSECDHECURVES_DEFAULT "default"
#define TLSDHPARAM_DEFAULT "none"
struct relay_ticket_key {
uint32_t tt_keyrev;
unsigned char tt_key[TLS_TICKET_KEY_SIZE];
};
#define TLS_SESSION_LIFETIME (2 * 3600)
#define HTTPFLAG_WEBSOCKETS 0x01
struct keyname {
TAILQ_ENTRY(keyname) entry;
char *name;
};
TAILQ_HEAD(keynamelist, keyname);
struct protocol {
objid_t id;
u_int32_t flags;
u_int8_t tcpflags;
int tcpbufsiz;
int tcpbacklog;
u_int8_t tcpipttl;
u_int8_t tcpipminttl;
size_t httpheaderlen;
int httpflags;
u_int8_t tlsflags;
char tlsciphers[768];
char tlsdhparams[128];
char tlsecdhecurves[128];
char tlsca[PATH_MAX];
char tlscacert[PATH_MAX];
char tlscakey[PATH_MAX];
char *tlscapass;
struct keynamelist tlscerts;
char name[MAX_NAME_SIZE];
int tickets;
enum prototype type;
char *style;
int (*cmp)(struct rsession *, struct rsession *);
void *(*validate)(struct rsession *, struct relay *,
struct sockaddr_storage *,
u_int8_t *, size_t);
int (*request)(struct rsession *);
void (*close)(struct rsession *);
struct relay_rules rules;
int rulecount;
TAILQ_ENTRY(protocol) entry;
};
TAILQ_HEAD(protolist, protocol);
struct relay_table {
struct table *rlt_table;
u_int32_t rlt_flags;
int rlt_mode;
u_int32_t rlt_index;
struct host *rlt_host[RELAY_MAXHOSTS];
int rlt_nhosts;
TAILQ_ENTRY(relay_table) rlt_entry;
};
TAILQ_HEAD(relaytables, relay_table);
struct ca_pkey {
char pkey_hash[TLS_CERT_HASH_SIZE];
EVP_PKEY *pkey;
TAILQ_ENTRY(ca_pkey) pkey_entry;
};
TAILQ_HEAD(ca_pkeylist, ca_pkey);
struct relay_cert {
objid_t cert_id;
objid_t cert_relayid;
int cert_fd;
int cert_key_fd;
int cert_ocsp_fd;
EVP_PKEY *cert_pkey;
TAILQ_ENTRY(relay_cert) cert_entry;
};
TAILQ_HEAD(relaycertlist, relay_cert);
struct relay_config {
objid_t id;
u_int32_t flags;
objid_t proto;
char name[HOST_NAME_MAX+1];
in_port_t port;
in_port_t dstport;
int dstretry;
struct sockaddr_storage ss;
struct sockaddr_storage dstss;
struct sockaddr_storage dstaf;
struct timeval timeout;
enum forwardmode fwdmode;
union hashkey hashkey;
off_t tls_cakey_len;
};
struct relay {
TAILQ_ENTRY(relay) rl_entry;
struct relay_config rl_conf;
int rl_up;
struct protocol *rl_proto;
int rl_s;
struct bufferevent *rl_bev;
int rl_dsts;
struct bufferevent *rl_dstbev;
struct relaytables rl_tables;
struct event rl_ev;
struct event rl_evt;
struct tls_config *rl_tls_cfg;
struct tls_config *rl_tls_client_cfg;
struct tls *rl_tls_ctx;
int rl_tls_ca_fd;
int rl_tls_cacert_fd;
EVP_PKEY *rl_tls_pkey;
X509 *rl_tls_cacertx509;
char *rl_tls_cakey;
EVP_PKEY *rl_tls_capkey;
struct ctl_stats rl_stats[PROC_MAX_INSTANCES + 1];
struct session_tree rl_sessions;
};
TAILQ_HEAD(relaylist, relay);
enum dstmode {
RELAY_DSTMODE_LOADBALANCE = 0,
RELAY_DSTMODE_ROUNDROBIN,
RELAY_DSTMODE_HASH,
RELAY_DSTMODE_SRCHASH,
RELAY_DSTMODE_LEASTSTATES,
RELAY_DSTMODE_RANDOM
};
#define RELAY_DSTMODE_DEFAULT RELAY_DSTMODE_ROUNDROBIN
struct netroute_config {
objid_t id;
struct sockaddr_storage ss;
int prefixlen;
objid_t routerid;
};
struct netroute {
struct netroute_config nr_conf;
TAILQ_ENTRY(netroute) nr_entry;
TAILQ_ENTRY(netroute) nr_route;
struct router *nr_router;
};
TAILQ_HEAD(netroutelist, netroute);
struct router_config {
objid_t id;
u_int32_t flags;
char name[HOST_NAME_MAX+1];
char label[RT_LABEL_SIZE];
int nroutes;
objid_t gwtable;
in_port_t gwport;
int rtable;
int af;
};
struct router {
struct router_config rt_conf;
struct table *rt_gwtable;
struct netroutelist rt_netroutes;
TAILQ_ENTRY(router) rt_entry;
};
TAILQ_HEAD(routerlist, router);
struct ctl_netroute {
int up;
struct host_config host;
struct netroute_config nr;
struct router_config rt;
};
/* initially control.h */
struct control_sock {
const char *cs_name;
struct event cs_ev;
struct event cs_evt;
int cs_fd;
int cs_restricted;
void *cs_env;
TAILQ_ENTRY(control_sock) cs_entry;
};
TAILQ_HEAD(control_socks, control_sock);
extern struct {
struct event ev;
int fd;
} control_state;
struct imsgev {
struct imsgbuf ibuf;
void (*handler)(int, short, void *);
struct event ev;
struct privsep_proc *proc;
void *data;
short events;
};
#define IMSG_SIZE_CHECK(imsg, p) do { \
if (IMSG_DATA_SIZE(imsg) < sizeof(*p)) \
fatalx("bad length imsg received"); \
} while (0)
#define IMSG_DATA_SIZE(imsg) ((imsg)->hdr.len - IMSG_HEADER_SIZE)
struct ctl_conn {
TAILQ_ENTRY(ctl_conn) entry;
u_int8_t flags;
u_int waiting;
#define CTL_CONN_NOTIFY 0x01
struct imsgev iev;
};
TAILQ_HEAD(ctl_connlist, ctl_conn);
enum imsg_type {
IMSG_NONE,
IMSG_CTL_OK, /* answer to relayctl requests */
IMSG_CTL_FAIL,
IMSG_CTL_VERBOSE,
IMSG_CTL_PROCFD,
IMSG_CTL_END,
IMSG_CTL_RDR,
IMSG_CTL_TABLE,
IMSG_CTL_HOST,
IMSG_CTL_RELAY,
IMSG_CTL_SESSION,
IMSG_CTL_ROUTER,
IMSG_CTL_NETROUTE,
IMSG_CTL_TABLE_CHANGED,
IMSG_CTL_PULL_RULESET,
IMSG_CTL_PUSH_RULESET,
IMSG_CTL_SHOW_SUM, /* relayctl requests */
IMSG_CTL_RDR_ENABLE,
IMSG_CTL_RDR_DISABLE,
IMSG_CTL_TABLE_ENABLE,
IMSG_CTL_TABLE_DISABLE,
IMSG_CTL_HOST_ENABLE,
IMSG_CTL_HOST_DISABLE,
IMSG_CTL_SHUTDOWN,
IMSG_CTL_START,
IMSG_CTL_RELOAD,
IMSG_CTL_RESET,
IMSG_CTL_POLL,
IMSG_CTL_NOTIFY,
IMSG_CTL_RDR_STATS,
IMSG_CTL_RELAY_STATS,
IMSG_RDR_ENABLE, /* notifies from pfe to hce */
IMSG_RDR_DISABLE,
IMSG_TABLE_ENABLE,
IMSG_TABLE_DISABLE,
IMSG_HOST_ENABLE,
IMSG_HOST_DISABLE,
IMSG_HOST_STATUS, /* notifies from hce to pfe */
IMSG_SYNC,
IMSG_NATLOOK,
IMSG_DEMOTE,
IMSG_STATISTICS,
IMSG_SCRIPT,
IMSG_AGENTXSOCK,
IMSG_BINDANY,
IMSG_RTMSG, /* from pfe to parent */
IMSG_CFG_TABLE, /* configuration from parent */
IMSG_CFG_HOST,
IMSG_CFG_RDR,
IMSG_CFG_VIRT,
IMSG_CFG_ROUTER,
IMSG_CFG_ROUTE,
IMSG_CFG_PROTO,
IMSG_CFG_RULE,
IMSG_CFG_RELAY,
IMSG_CFG_RELAY_TABLE,
IMSG_CFG_RELAY_CERT,
IMSG_CFG_RELAY_FD,
IMSG_CFG_DONE,
IMSG_CA_PRIVENC,
IMSG_CA_PRIVDEC,
IMSG_SESS_PUBLISH, /* from relay to pfe */
IMSG_SESS_UNPUBLISH,
IMSG_TLSTICKET_REKEY
};
enum privsep_procid {
PROC_ALL = -1,
PROC_PARENT = 0,
PROC_HCE,
PROC_RELAY,
PROC_PFE,
PROC_CA,
PROC_MAX
};
extern enum privsep_procid privsep_process;
/* Attach the control socket to the following process */
#define PROC_CONTROL PROC_PFE
struct privsep_pipes {
int *pp_pipes[PROC_MAX];
};
struct privsep {
struct privsep_pipes *ps_pipes[PROC_MAX];
struct privsep_pipes *ps_pp;
struct imsgev *ps_ievs[PROC_MAX];
const char *ps_title[PROC_MAX];
u_int8_t ps_what[PROC_MAX];
u_int ps_instances[PROC_MAX];
u_int ps_instance;
struct control_sock ps_csock;
struct control_socks ps_rcsocks;
/* Event and signal handlers */
struct event ps_evsigint;
struct event ps_evsigterm;
struct event ps_evsigchld;
struct event ps_evsighup;
struct event ps_evsigpipe;
struct event ps_evsigusr1;
int ps_noaction;
struct passwd *ps_pw;
struct relayd *ps_env;
};
struct privsep_proc {
const char *p_title;
enum privsep_procid p_id;
int (*p_cb)(int, struct privsep_proc *,
struct imsg *);
void (*p_init)(struct privsep *,
struct privsep_proc *);
const char *p_chroot;
struct privsep *p_ps;
void (*p_shutdown)(void);
struct passwd *p_pw;
};
struct privsep_fd {
enum privsep_procid pf_procid;
unsigned int pf_instance;
};
struct relayd_config {
char tls_sid[SSL_MAX_SID_CTX_LENGTH];
char agentx_path[sizeof(((struct sockaddr_un *)NULL)->sun_path)];
char agentx_context[32];
struct timeval interval;
struct timeval timeout;
struct timeval statinterval;
u_int16_t prefork_relay;
u_int16_t opts;
u_int32_t flags;
};
struct pfdata {
int dev;
struct pf_anchor *anchor;
struct pfioc_trans pft;
struct pfioc_trans_e pfte;
u_int8_t pfused;
};
struct relayd {
struct relayd_config sc_conf;
const char *sc_conffile;
struct pfdata *sc_pf;
int sc_rtsock;
int sc_rtseq;
int sc_tablecount;
int sc_rdrcount;
int sc_protocount;
int sc_relaycount;
int sc_routercount;
int sc_routecount;
struct table sc_empty_table;
struct protocol sc_proto_default;
struct event sc_ev;
struct tablelist *sc_tables;
struct hostlist sc_hosts;
struct rdrlist *sc_rdrs;
struct protolist *sc_protos;
struct relaylist *sc_relays;
struct routerlist *sc_rts;
struct netroutelist *sc_routes;
struct ca_pkeylist *sc_pkeys;
struct relaycertlist *sc_certs;
struct sessionlist sc_sessions;
char sc_demote_group[IFNAMSIZ];
u_int16_t sc_id;
int sc_rtable;
struct event sc_statev;
struct event sc_agentxev;
int sc_has_icmp;
int sc_has_icmp6;
struct ctl_icmp_event sc_icmp_send;
struct ctl_icmp_event sc_icmp_recv;
struct ctl_icmp_event sc_icmp6_send;
struct ctl_icmp_event sc_icmp6_recv;
struct relay_ticket_key sc_ticket;
struct privsep *sc_ps;
int sc_reload;
};
#define RELAYD_OPT_VERBOSE 0x01
#define RELAYD_OPT_NOACTION 0x04
#define RELAYD_OPT_LOGUPDATE 0x08
#define RELAYD_OPT_LOGHOSTCHECK 0x10
#define RELAYD_OPT_LOGCON 0x20
#define RELAYD_OPT_LOGCONERR 0x40
/* control.c */
int control_init(struct privsep *, struct control_sock *);
int control_listen(struct control_sock *);
void control_cleanup(struct control_sock *);
void control_dispatch_imsg(int, short, void *);
void control_imsg_forward(struct privsep *ps, struct imsg *);
struct ctl_conn *
control_connbyfd(int);
/* parse.y */
int parse_config(const char *, struct relayd *);
int load_config(const char *, struct relayd *);
int cmdline_symset(char *);
/* util.c */
const char *host_error(enum host_error);
const char *host_status(enum host_status);
const char *table_check(enum table_check);
#ifdef DEBUG
const char *relay_state(enum relay_state);
#endif
const char *print_availability(u_long, u_long);
const char *print_host(struct sockaddr_storage *, char *, size_t);
const char *print_time(struct timeval *, struct timeval *, char *, size_t);
const char *printb_flags(const u_int32_t, const char *);
void getmonotime(struct timeval *);
struct ibuf *string2binary(const char *);
void print_hex(uint8_t *, off_t, size_t);
void print_debug(const char *, ...);
/* pfe.c */
void pfe(struct privsep *, struct privsep_proc *);
void show(struct ctl_conn *);
void show_sessions(struct ctl_conn *);
int enable_rdr(struct ctl_conn *, struct ctl_id *);
int enable_table(struct ctl_conn *, struct ctl_id *);
int enable_host(struct ctl_conn *, struct ctl_id *, struct host *);
int disable_rdr(struct ctl_conn *, struct ctl_id *);
int disable_table(struct ctl_conn *, struct ctl_id *);
int disable_host(struct ctl_conn *, struct ctl_id *, struct host *);
/* pfe_filter.c */
void init_tables(struct relayd *);
void flush_table(struct relayd *, struct rdr *);
void sync_table(struct relayd *, struct rdr *, struct table *);
void sync_ruleset(struct relayd *, struct rdr *, int);
void flush_rulesets(struct relayd *);
int natlook(struct relayd *, struct ctl_natlook *);
u_int64_t
check_table(struct relayd *, struct rdr *, struct table *);
/* pfe_route.c */
void init_routes(struct relayd *);
void sync_routes(struct relayd *, struct router *);
int pfe_route(struct relayd *, struct ctl_netroute *);
/* hce.c */
void hce(struct privsep *, struct privsep_proc *);
void hce_notify_done(struct host *, enum host_error);
/* relay.c */
void relay(struct privsep *, struct privsep_proc *);
int relay_privinit(struct relay *);
void relay_notify_done(struct host *, const char *);
int relay_session_cmp(struct rsession *, struct rsession *);
void relay_close(struct rsession *, const char *, int);
int relay_reset_event(struct rsession *, struct ctl_relay_event *);
void relay_natlook(int, short, void *);
void relay_session(struct rsession *);
int relay_from_table(struct rsession *);
int relay_socket_af(struct sockaddr_storage *, in_port_t);
in_port_t
relay_socket_getport(struct sockaddr_storage *);
int relay_cmp_af(struct sockaddr_storage *,
struct sockaddr_storage *);
void relay_write(struct bufferevent *, void *);
void relay_read(struct bufferevent *, void *);
int relay_splice(struct ctl_relay_event *);
int relay_splicelen(struct ctl_relay_event *);
int relay_spliceadjust(struct ctl_relay_event *);
void relay_error(struct bufferevent *, short, void *);
int relay_preconnect(struct rsession *);
int relay_connect(struct rsession *);
void relay_connected(int, short, void *);
void relay_bindanyreq(struct rsession *, in_port_t, int);
void relay_bindany(int, short, void *);
void relay_dump(struct ctl_relay_event *, const void *, size_t);
int relay_bufferevent_add(struct event *, int);
int relay_bufferevent_print(struct ctl_relay_event *, const char *);
int relay_bufferevent_write_buffer(struct ctl_relay_event *,
struct evbuffer *);
int relay_bufferevent_write_chunk(struct ctl_relay_event *,
struct evbuffer *, size_t);
int relay_bufferevent_write(struct ctl_relay_event *,
void *, size_t);
int relay_test(struct protocol *, struct ctl_relay_event *);
void relay_calc_skip_steps(struct relay_rules *);
void relay_match(struct kvlist *, struct kv *, struct kv *,
struct kvtree *);
void relay_session_insert(struct rsession *);
void relay_session_remove(struct rsession *);
void relay_session_publish(struct rsession *);
void relay_session_unpublish(struct rsession *);
SPLAY_PROTOTYPE(session_tree, rsession, se_nodes, relay_session_cmp);
/* relay_http.c */
void relay_http(struct relayd *);
void relay_http_init(struct relay *);
void relay_abort_http(struct rsession *, u_int, const char *,
u_int16_t);
void relay_read_http(struct bufferevent *, void *);
void relay_close_http(struct rsession *);
u_int relay_httpmethod_byname(const char *);
const char
*relay_httpmethod_byid(u_int);
const char
*relay_httperror_byid(u_int);
int relay_http_priv_init(struct rsession *);
int relay_httpdesc_init(struct ctl_relay_event *);
ssize_t relay_http_time(time_t, char *, size_t);
/* relay_udp.c */
void relay_udp_privinit(struct relay *);
void relay_udp_init(struct relayd *, struct relay *);
int relay_udp_bind(struct sockaddr_storage *, in_port_t,
struct protocol *);
void relay_udp_server(int, short, void *);
/* check_icmp.c */
void icmp_init(struct relayd *);
void schedule_icmp(struct relayd *, struct host *);
void check_icmp(struct relayd *, struct timeval *);
/* check_tcp.c */
void check_tcp(struct ctl_tcp_event *);
/* check_tls.c */
void check_tls(struct ctl_tcp_event *);
/* check_script.c */
void check_script(struct relayd *, struct host *);
void script_done(struct relayd *, struct ctl_script *);
int script_exec(struct relayd *, struct ctl_script *);
/* ssl.c */
char *ssl_load_key(struct relayd *, const char *, off_t *, char *);
uint8_t *ssl_update_certificate(const uint8_t *, size_t, EVP_PKEY *,
EVP_PKEY *, X509 *, size_t *);
int ssl_load_pkey(char *, off_t, X509 **, EVP_PKEY **);
/* ca.c */
void ca(struct privsep *, struct privsep_proc *);
void ca_engine_init(struct relayd *);
void hash_x509(X509 *cert, char *hash, size_t hashlen);
/* relayd.c */
struct host *host_find(struct relayd *, objid_t);
struct table *table_find(struct relayd *, objid_t);
struct rdr *rdr_find(struct relayd *, objid_t);
struct netroute *route_find(struct relayd *, objid_t);
struct router *router_find(struct relayd *, objid_t);
struct host *host_findbyname(struct relayd *, const char *);
struct table *table_findbyname(struct relayd *, const char *);
struct table *table_findbyconf(struct relayd *, struct table *);
struct rdr *rdr_findbyname(struct relayd *, const char *);
void event_again(struct event *, int, short,
void (*)(int, short, void *),
struct timeval *, struct timeval *, void *);
struct relay *relay_find(struct relayd *, objid_t);
struct protocol *proto_find(struct relayd *, objid_t);
struct rsession *session_find(struct relayd *, objid_t);
struct relay *relay_findbyname(struct relayd *, const char *);
struct relay *relay_findbyaddr(struct relayd *, struct relay_config *);
EVP_PKEY *pkey_find(struct relayd *, char *hash);
struct ca_pkey *pkey_add(struct relayd *, EVP_PKEY *, char *hash);
struct relay_cert *cert_add(struct relayd *, objid_t);
struct relay_cert *cert_find(struct relayd *, objid_t);
char *relay_load_fd(int, off_t *);
int relay_load_certfiles(struct relayd *, struct relay *,
const char *);
int expand_string(char *, size_t, const char *, const char *);
void translate_string(char *);
void purge_key(char **, off_t);
void purge_table(struct relayd *, struct tablelist *,
struct table *);
void purge_relay(struct relayd *, struct relay *);
char *digeststr(enum digest_type, const u_int8_t *, size_t, char *);
const char *canonicalize_host(const char *, char *, size_t);
int parse_url(const char *, char **, char **, char **);
int map6to4(struct sockaddr_storage *);
int map4to6(struct sockaddr_storage *, struct sockaddr_storage *);
void imsg_event_add(struct imsgev *);
int imsg_compose_event(struct imsgev *, u_int16_t, u_int32_t,
pid_t, int, void *, u_int16_t);
void socket_rlimit(int);
char *get_string(u_int8_t *, size_t);
void *get_data(u_int8_t *, size_t);
int sockaddr_cmp(struct sockaddr *, struct sockaddr *, int);
struct in6_addr *prefixlen2mask6(u_int8_t, u_int32_t *);
u_int32_t prefixlen2mask(u_int8_t);
int accept_reserve(int, struct sockaddr *, socklen_t *, int,
volatile int *);
struct kv *kv_add(struct kvtree *, char *, char *, int);
int kv_set(struct kv *, char *, ...)
__attribute__((__format__ (printf, 2, 3)));
int kv_setkey(struct kv *, char *, ...)
__attribute__((__format__ (printf, 2, 3)));
void kv_delete(struct kvtree *, struct kv *);
struct kv *kv_extend(struct kvtree *, struct kv *, char *);
void kv_purge(struct kvtree *);
void kv_free(struct kv *);
struct kv *kv_inherit(struct kv *, struct kv *);
void relay_log(struct rsession *, char *);
int kv_log(struct rsession *, struct kv *, u_int16_t,
enum direction);
struct kv *kv_find(struct kvtree *, struct kv *);
struct kv *kv_find_value(struct kvtree *, char *, const char *,
const char *);
int kv_cmp(struct kv *, struct kv *);
int rule_add(struct protocol *, struct relay_rule *, const char
*);
void rule_delete(struct relay_rules *, struct relay_rule *);
void rule_free(struct relay_rule *);
struct relay_rule
*rule_inherit(struct relay_rule *);
void rule_settable(struct relay_rules *, struct relay_table *);
RB_PROTOTYPE(kvtree, kv, kv_node, kv_cmp);
/* carp.c */
int carp_demote_init(char *, int);
void carp_demote_shutdown(void);
int carp_demote_get(char *);
int carp_demote_set(char *, int);
int carp_demote_reset(char *, int);
/* name2id.c */
u_int16_t label_name2id(const char *);
const char *label_id2name(u_int16_t);
void label_unref(u_int16_t);
void label_ref(u_int16_t);
u_int16_t tag_name2id(const char *);
const char *tag_id2name(u_int16_t);
void tag_unref(u_int16_t);
void tag_ref(u_int16_t);
/* agentx_control.c */
void agentx_init(struct relayd *);
void agentx_setsock(struct relayd *, enum privsep_procid);
void agentx_getsock(struct imsg *);
void snmp_hosttrap(struct relayd *, struct table *, struct host *);
/* shuffle.c */
void shuffle_init(struct shuffle *);
u_int16_t shuffle_generate16(struct shuffle *);
/* log.c */
void log_init(int, int);
void log_procinit(const char *);
void log_setverbose(int);
int log_getverbose(void);
void log_warn(const char *, ...)
__attribute__((__format__ (printf, 1, 2)));
void log_warnx(const char *, ...)
__attribute__((__format__ (printf, 1, 2)));
void log_info(const char *, ...)
__attribute__((__format__ (printf, 1, 2)));
void log_debug(const char *, ...)
__attribute__((__format__ (printf, 1, 2)));
void logit(int, const char *, ...)
__attribute__((__format__ (printf, 2, 3)));
void vlog(int, const char *, va_list)
__attribute__((__format__ (printf, 2, 0)));
__dead void fatal(const char *, ...)
__attribute__((__format__ (printf, 1, 2)));
__dead void fatalx(const char *, ...)
__attribute__((__format__ (printf, 1, 2)));
/* proc.c */
enum privsep_procid
proc_getid(struct privsep_proc *, unsigned int, const char *);
int proc_flush_imsg(struct privsep *, enum privsep_procid, int);
void proc_init(struct privsep *, struct privsep_proc *, unsigned int, int,
int, char **, enum privsep_procid);
void proc_kill(struct privsep *);
void proc_connect(struct privsep *);
void proc_dispatch(int, short event, void *);
void proc_run(struct privsep *, struct privsep_proc *,
struct privsep_proc *, unsigned int,
void (*)(struct privsep *, struct privsep_proc *, void *), void *);
void proc_range(struct privsep *, enum privsep_procid, int *, int *);
int proc_compose_imsg(struct privsep *, enum privsep_procid, int,
u_int16_t, u_int32_t, int, void *, u_int16_t);
int proc_compose(struct privsep *, enum privsep_procid,
uint16_t, void *, uint16_t);
int proc_composev_imsg(struct privsep *, enum privsep_procid, int,
u_int16_t, u_int32_t, int, const struct iovec *, int);
int proc_composev(struct privsep *, enum privsep_procid,
uint16_t, const struct iovec *, int);
int proc_forward_imsg(struct privsep *, struct imsg *,
enum privsep_procid, int);
struct imsgbuf *
proc_ibuf(struct privsep *, enum privsep_procid, int);
struct imsgev *
proc_iev(struct privsep *, enum privsep_procid, int);
void imsg_event_add(struct imsgev *);
int imsg_compose_event(struct imsgev *, uint16_t, uint32_t,
pid_t, int, void *, uint16_t);
int imsg_composev_event(struct imsgev *, uint16_t, uint32_t,
pid_t, int, const struct iovec *, int);
/* config.c */
int config_init(struct relayd *);
void config_purge(struct relayd *, u_int);
int config_setreset(struct relayd *, u_int);
int config_getreset(struct relayd *, struct imsg *);
int config_getcfg(struct relayd *, struct imsg *);
int config_settable(struct relayd *, struct table *);
int config_gettable(struct relayd *, struct imsg *);
int config_gethost(struct relayd *, struct imsg *);
int config_setrdr(struct relayd *, struct rdr *);
int config_getrdr(struct relayd *, struct imsg *);
int config_getvirt(struct relayd *, struct imsg *);
int config_setrt(struct relayd *, struct router *);
int config_getrt(struct relayd *, struct imsg *);
int config_getroute(struct relayd *, struct imsg *);
int config_setproto(struct relayd *, struct protocol *);
int config_getproto(struct relayd *, struct imsg *);
int config_setrule(struct relayd *, struct protocol *);
int config_getrule(struct relayd *, struct imsg *);
int config_setrelay(struct relayd *, struct relay *);
int config_getrelay(struct relayd *, struct imsg *);
int config_getrelaytable(struct relayd *, struct imsg *);
int config_getrelayfd(struct relayd *, struct imsg *);
#endif /* RELAYD_H */