root/usr.sbin/relayd/relayd.h
/*      $OpenBSD: relayd.h,v 1.278 2026/03/02 19:28:01 rsadowski 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 RT_LABEL_SIZE           32
#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,
        RELAY_FD_CLIENTCACERT   = 6
};

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_PFLOG                 0x20000000
#define F_PROXYV1               0x40000000
#define F_PROXYV2               0x80000000

#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[PF_TABLE_NAME_SIZE];
        char                     tag[PF_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;
        char                     tlsclientca[PATH_MAX];
        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;
        int                      rl_tls_client_ca_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);

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 *);
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_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 *);

/* 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 *);

/* proxy_protocol.c */
int     proxy_protocol_v1(struct rsession *, struct evbuffer *);
int     proxy_protocol_v2(struct rsession *, struct evbuffer *);

#endif /* RELAYD_H */