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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
|
/*
* xfrd-tcp.h - XFR (transfer) Daemon TCP system header file. Manages tcp conn.
*
* Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
*
* See LICENSE for the license.
*
*/
#ifndef XFRD_TCP_H
#define XFRD_TCP_H
#include "xfrd.h"
#ifdef HAVE_TLS_1_3
#include <openssl/ssl.h>
#endif
struct buffer;
struct xfrd_zone;
struct xfrd_soa;
struct xfrd_state;
struct region;
struct dname;
struct acl_options;
struct xfrd_tcp_pipeline;
typedef struct xfrd_tcp xfrd_tcp_type;
typedef struct xfrd_tcp_set xfrd_tcp_set_type;
/*
* A set of xfrd tcp connections.
*/
struct xfrd_tcp_set {
/* tcp connections, each has packet and read/wr state */
struct xfrd_tcp_pipeline *tcp_state[XFRD_MAX_TCP];
/* number of TCP connections in use. */
int tcp_count;
/* TCP timeout. */
int tcp_timeout;
/* rbtree with pipelines sorted by master */
rbtree_type* pipetree;
#ifdef HAVE_TLS_1_3
/* XoT: SSL context */
SSL_CTX* ssl_ctx;
#endif
/* double linked list of zones waiting for a TCP connection */
struct xfrd_zone *tcp_waiting_first, *tcp_waiting_last;
};
/*
* Structure to keep track of an open tcp connection
* The xfrd tcp connection is used to first make a request
* Then to receive the answer packet(s).
*/
struct xfrd_tcp {
/* tcp connection state */
/* state: reading or writing */
uint8_t is_reading;
/* how many bytes have been read/written - total,
incl. tcp length bytes */
uint32_t total_bytes;
/* msg len bytes */
uint16_t msglen;
/* fd of connection. -1 means unconnected */
int fd;
/* packet buffer of connection */
struct buffer* packet;
};
/* use illegal pointer value to denote skipped ID number.
* if this does not work, we can allocate with malloc */
#define TCP_NULL_SKIP ((struct xfrd_zone*)-1)
/* the number of ID values (16 bits) for a pipeline */
#define ID_PIPE_NUM 65536
/**
* The tcp pipeline key structure. By ip_len, ip, num_unused and unique by
* pointer value.
*/
struct xfrd_tcp_pipeline_key {
/* the rbtree node, sorted by IP and nr of unused queries */
rbnode_type node;
/* destination IP address */
#ifdef INET6
struct sockaddr_storage ip;
#else
struct sockaddr_in ip;
#endif /* INET6 */
socklen_t ip_len;
/* number of unused IDs. used IDs are waiting to send their query,
* or have been sent but not not all answer packets have been received.
* Sorted by num_unused, so a lookup smaller-equal for 65536 finds the
* connection to that master that has the most free IDs. */
int num_unused;
/* number of skip-set IDs (these are 'in-use') */
int num_skip;
};
/**
* Structure to keep track of a pipelined set of queries on
* an open tcp connection. The queries may be answered with
* interleaved answer packets, the ID number disambiguates.
* Sorted by the master IP address so you can use lookup with
* smaller-or-equal to find the tcp connection most suitable.
*/
struct xfrd_tcp_pipeline {
/* the key information for the tcp pipeline, in its own
* struct so it can be referenced on its own for comparison funcs */
struct xfrd_tcp_pipeline_key key;
int handler_added;
/* the event handler for this pipe (it'll disambiguate by ID) */
struct event handler;
/* the tcp connection to use for reading */
struct xfrd_tcp* tcp_r;
/* the tcp connection to use for writing, if it is done successfully,
* then the first zone from the sendlist can be removed. */
struct xfrd_tcp* tcp_w;
/* once a byte has been written, handshake complete */
int connection_established;
#ifdef HAVE_TLS_1_3
/* XoT: SSL object */
SSL *ssl;
/* XoT: if SSL handshake is not done, handshake_want indicates the
* last error. This may be SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE
* when the handshake is still in progress.
*/
int handshake_want;
/* XoT: 1 if the SSL handshake has succeeded, 0 otherwise */
int handshake_done;
#endif
/* list of queries that want to send, first to get write event,
* if NULL, no write event interest */
struct xfrd_zone* tcp_send_first, *tcp_send_last;
/* the unused and id arrays must be last in the structure */
/* per-ID number the queries that have this ID number, every
* query owns one ID numbers (until it is done). NULL: unused
* When a query is done but not all answer-packets have been
* consumed for that ID number, the rest is skipped, this
* is denoted with the pointer-value TCP_NULL_SKIP, the ids that
* are skipped are not on the unused list. They may be
* removed once the last answer packet is skipped.
* ID_PIPE_NUM-num_unused values in the id array are nonNULL (either
* a zone pointer or SKIP) */
struct xfrd_zone* id[ID_PIPE_NUM];
/* unused ID numbers; the first part of the array contains the IDs */
uint16_t unused[ID_PIPE_NUM];
};
/* create set of tcp connections */
struct xfrd_tcp_set* xfrd_tcp_set_create(struct region* region, const char *tls_cert_bundle);
/* init tcp state */
struct xfrd_tcp* xfrd_tcp_create(struct region* region, size_t bufsize);
/* obtain tcp connection for a zone (or wait) */
void xfrd_tcp_obtain(struct xfrd_tcp_set* set, struct xfrd_zone* zone);
/* release tcp connection for a zone (starts waiting) */
void xfrd_tcp_release(struct xfrd_tcp_set* set, struct xfrd_zone* zone);
/* release tcp pipe entirely (does not stop the zones inside it) */
void xfrd_tcp_pipe_release(struct xfrd_tcp_set* set,
struct xfrd_tcp_pipeline* tp, int conn);
/* use tcp connection to start xfr */
void xfrd_tcp_setup_write_packet(struct xfrd_tcp_pipeline* tp,
struct xfrd_zone* zone);
/* initialize tcp_state for a zone. Opens the connection. true on success.*/
int xfrd_tcp_open(struct xfrd_tcp_set* set, struct xfrd_tcp_pipeline* tp,
struct xfrd_zone* zone);
/* read data from tcp, maybe partial read */
void xfrd_tcp_read(struct xfrd_tcp_pipeline* tp);
/* write data to tcp, maybe a partial write */
void xfrd_tcp_write(struct xfrd_tcp_pipeline* tp, struct xfrd_zone* zone);
/* handle tcp pipe events */
void xfrd_handle_tcp_pipe(int fd, short event, void* arg);
/*
* Read from a stream connection (size16)+packet into buffer.
* returns value is
* -1 on error.
* 0 on short read, call back later.
* 1 on completed read.
* On first call, make sure total_bytes = 0, msglen=0, buffer_clear().
* and the packet and fd need to be set.
*/
int conn_read(struct xfrd_tcp* conn);
/*
* Write to a stream connection (size16)+packet.
* return value is
* -1 on error. 0 on short write, call back later. 1 completed write.
* On first call, make sure total_bytes=0, msglen=buffer_limit(),
* buffer_flipped(). packet and fd need to be set.
*/
int conn_write(struct xfrd_tcp* conn);
/* setup DNS packet for a query of this type */
void xfrd_setup_packet(struct buffer* packet,
uint16_t type, uint16_t klass, const struct dname* dname, uint16_t qid);
/* write soa in network format to the packet buffer */
void xfrd_write_soa_buffer(struct buffer* packet,
const struct dname* apex, struct xfrd_soa* soa);
/* use acl address to setup sockaddr struct, returns length of addr. */
socklen_t xfrd_acl_sockaddr_to(struct acl_options* acl,
#ifdef INET6
struct sockaddr_storage *to);
#else
struct sockaddr_in *to);
#endif /* INET6 */
socklen_t xfrd_acl_sockaddr_frm(struct acl_options* acl,
#ifdef INET6
struct sockaddr_storage *frm);
#else
struct sockaddr_in *frm);
#endif /* INET6 */
/* create pipeline tcp structure */
struct xfrd_tcp_pipeline* xfrd_tcp_pipeline_create(region_type* region);
#endif /* XFRD_TCP_H */
|