1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
/* Copyright (C) CZ.NIC, z.s.p.o. <knot-resolver@labs.nic.cz>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include "daemon/tls.h"
#include "lib/generic/array.h"
#include "lib/generic/trie.h"
#include <uv.h>
#include <stdbool.h>
#include <sys/socket.h>
#ifndef AF_XDP
#define AF_XDP 44
#endif
struct engine;
struct session;
/** Ways to listen on a socket (which may exist already). */
typedef struct {
int sock_type; /**< SOCK_DGRAM or SOCK_STREAM */
bool tls; /**< only used together with .kind == NULL and SOCK_STREAM */
bool http; /**< DoH2, implies .tls (in current implementation) */
bool xdp; /**< XDP is special (not a normal socket, in particular) */
bool freebind; /**< used for binding to non-local address */
const char *kind; /**< tag for other types: "control" or module-handled kinds */
} endpoint_flags_t;
struct endpoint_key;
static inline bool endpoint_flags_eq(endpoint_flags_t f1, endpoint_flags_t f2)
{
if (f1.sock_type != f2.sock_type)
return false;
if (f1.kind && f2.kind)
return strcasecmp(f1.kind, f2.kind);
else
return f1.tls == f2.tls && f1.kind == f2.kind;
}
/** Wrapper for a single socket to listen on.
* There are two types: normal have handle, special have flags.kind (and never both).
*
* LATER: .family might be unexpected for IPv4-in-IPv6 addresses.
* ATM AF_UNIX is only supported with flags.kind != NULL
*/
struct endpoint {
/** uv_{udp,tcp,poll}_t (poll for XDP);
* NULL in case of endpoints that are to be handled by modules. */
uv_handle_t *handle;
int fd; /**< POSIX file-descriptor; always used. */
int family; /**< AF_INET or AF_INET6 or AF_UNIX or AF_XDP */
uint16_t port; /**< TCP/UDP port. Meaningless with AF_UNIX. */
int16_t nic_queue; /**< -1 or queue number of the interface for AF_XDP use. */
bool engaged; /**< to some module or internally */
endpoint_flags_t flags;
};
/** @cond internal Array of endpoints */
typedef array_t(struct endpoint) endpoint_array_t;
/* @endcond */
struct net_tcp_param {
uint64_t in_idle_timeout;
uint64_t tls_handshake_timeout;
};
/** Information about an address that is allowed to use PROXYv2. */
struct net_proxy_data {
union kr_in_addr addr;
uint8_t netmask; /**< Number of bits to be matched */
};
struct network {
uv_loop_t *loop;
/** Map: address string -> endpoint_array_t.
* \note even same address-port-flags tuples may appear. */
trie_t *endpoints;
/** Registry of callbacks for special endpoint kinds (for opening/closing).
* Map: kind (lowercased) -> lua function ID converted to void *
* The ID is the usual: raw int index in the LUA_REGISTRYINDEX table. */
trie_t *endpoint_kinds;
/** See network_engage_endpoints() */
bool missing_kind_is_error : 1;
/** True: All IPv4 addresses are allowed to use the PROXYv2 protocol */
bool proxy_all4 : 1;
/** True: All IPv6 addresses are allowed to use the PROXYv2 protocol */
bool proxy_all6 : 1;
/** IPv4 addresses and networks allowed to use the PROXYv2 protocol */
trie_t *proxy_addrs4;
/** IPv6 addresses and networks allowed to use the PROXYv2 protocol */
trie_t *proxy_addrs6;
struct tls_credentials *tls_credentials;
tls_client_params_t *tls_client_params; /**< Use tls_client_params_*() functions. */
struct tls_session_ticket_ctx *tls_session_ticket_ctx;
struct net_tcp_param tcp;
int tcp_backlog;
};
void network_init(struct network *net, uv_loop_t *loop, int tcp_backlog);
void network_deinit(struct network *net);
/** Start listening on addr#port with flags.
* \note if we did listen on that combination already,
* nothing is done and kr_error(EADDRINUSE) is returned.
* \note there's no short-hand to listen both on UDP and TCP.
* \note ownership of flags.* is taken on success. TODO: non-success?
* \param nic_queue == -1 for auto-selection or non-XDP.
* \note In XDP mode, addr may be also interface name, so kr_error(ENODEV)
* is returned if some nonsense is passed
*/
int network_listen(struct network *net, const char *addr, uint16_t port,
int16_t nic_queue, endpoint_flags_t flags);
/** Allow the specified address to send the PROXYv2 header.
* \note the address may be specified with a netmask
*/
int network_proxy_allow(struct network *net, const char* addr);
/** Reset all addresses allowed to send the PROXYv2 header. No addresses will
* be allowed to send PROXYv2 headers from the point of calling this function
* until re-allowed via network_proxy_allow again.
*/
void network_proxy_reset(struct network *net);
/** Start listening on an open file-descriptor.
* \note flags.sock_type isn't meaningful here.
* \note ownership of flags.* is taken on success. TODO: non-success?
*/
int network_listen_fd(struct network *net, int fd, endpoint_flags_t flags);
/** Stop listening on all endpoints with matching addr#port.
* port < 0 serves as a wild-card.
* \return kr_error(ENOENT) if nothing matched. */
int network_close(struct network *net, const char *addr, int port);
/** Close all endpoints immediately (no waiting for UV loop). */
void network_close_force(struct network *net);
/** Enforce that all endpoints are registered from now on.
* This only does anything with struct endpoint::flags.kind != NULL. */
int network_engage_endpoints(struct network *net);
/** Returns a string representation of the specified endpoint key.
*
* The result points into key or is on static storage like for kr_straddr() */
const char *network_endpoint_key_str(const struct endpoint_key *key);
int network_set_tls_cert(struct network *net, const char *cert);
int network_set_tls_key(struct network *net, const char *key);
void network_new_hostname(struct network *net, struct engine *engine);
int network_set_bpf(struct network *net, int bpf_fd);
void network_clear_bpf(struct network *net);
|