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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
|
/*
* query.h -- manipulation with the queries
*
* Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
*
* See LICENSE for the license.
*
*/
#ifndef QUERY_H
#define QUERY_H
#include <assert.h>
#include <string.h>
#include "namedb.h"
#include "nsd.h"
#include "packet.h"
#include "tsig.h"
struct ixfr_data;
enum query_state {
QUERY_PROCESSED,
QUERY_DISCARDED,
QUERY_IN_AXFR,
QUERY_IN_IXFR
};
typedef enum query_state query_state_type;
/* Query as we pass it around */
typedef struct query query_type;
struct query {
/*
* Memory region freed whenever the query is reset.
*/
region_type *region;
/*
* The address the query was received from.
*/
#ifdef INET6
struct sockaddr_storage remote_addr;
#else
struct sockaddr_in remote_addr;
#endif
socklen_t remote_addrlen;
/* if set, the request came through a proxy */
int is_proxied;
/* the client address
* the same as remote_addr if not proxied */
#ifdef INET6
struct sockaddr_storage client_addr;
#else
struct sockaddr_in client_addr;
#endif
socklen_t client_addrlen;
/*
* Maximum supported query size.
*/
size_t maxlen;
/*
* Space reserved for optional records like EDNS.
*/
size_t reserved_space;
/* EDNS information provided by the client. */
edns_record_type edns;
/* TSIG record information and running hash for query-response */
tsig_record_type tsig;
/* tsig actions can be overridden, for axfr transfer. */
int tsig_prepare_it, tsig_update_it, tsig_sign_it;
int tcp;
uint16_t tcplen;
buffer_type *packet;
/* Normalized query domain name. */
const dname_type *qname;
/* Query type and class in host byte order. */
uint16_t qtype;
uint16_t qclass;
/* The zone used to answer the query. */
zone_type *zone;
/* The delegation domain, if any. */
domain_type *delegation_domain;
/* The delegation NS rrset, if any. */
rrset_type *delegation_rrset;
/* Original opcode. */
uint8_t opcode;
/*
* The number of CNAMES followed. After a CNAME is followed
* we no longer clear AA for a delegation and do not REFUSE
* or SERVFAIL if the destination zone of the CNAME does not exist,
* or is configured but not present.
* Also includes number of DNAMES followed.
*/
int cname_count;
/* Used for dname compression. */
uint16_t compressed_dname_count;
domain_type **compressed_dnames;
/*
* Indexed by domain->number, index 0 is reserved for the
* query name when generated from a wildcard record.
*/
uint16_t *compressed_dname_offsets;
size_t compressed_dname_offsets_size;
/* number of temporary domains used for the query */
size_t number_temporary_domains;
/*
* Used for AXFR processing.
*/
int axfr_is_done;
zone_type *axfr_zone;
domain_type *axfr_current_domain;
rrset_type *axfr_current_rrset;
uint16_t axfr_current_rr;
/* Used for IXFR processing,
* indicates if the zone transfer is done, connection can close. */
int ixfr_is_done;
/* the ixfr data that is processed */
struct ixfr_data* ixfr_data;
/* the ixfr data that is the last segment */
struct ixfr_data* ixfr_end_data;
/* ixfr count of newsoa bytes added, 0 none, len means done */
size_t ixfr_count_newsoa;
/* ixfr count of oldsoa bytes added, 0 none, len means done */
size_t ixfr_count_oldsoa;
/* ixfr count of del bytes added, 0 none, len means done */
size_t ixfr_count_del;
/* ixfr count of add bytes added, 0 none, len means done */
size_t ixfr_count_add;
/* position for the end of SOA record, for UDP truncation */
size_t ixfr_pos_of_newsoa;
#ifdef RATELIMIT
/* if we encountered a wildcard, its domain */
domain_type *wildcard_domain;
#endif
};
/* Check if the last write resulted in an overflow. */
static inline int query_overflow(struct query *q);
/*
* Store the offset of the specified domain in the dname compression
* table.
*/
void query_put_dname_offset(struct query *query,
domain_type *domain,
uint16_t offset);
/*
* Lookup the offset of the specified domain in the dname compression
* table. Offset 0 is used to indicate the domain is not yet in the
* compression table.
*/
static inline
uint16_t query_get_dname_offset(struct query *query, domain_type *domain)
{
return query->compressed_dname_offsets[domain->number];
}
/*
* Remove all compressed dnames that have an offset that points beyond
* the end of the current answer. This must be done after some RRs
* are truncated and before adding new RRs. Otherwise dnames may be
* compressed using truncated data!
*/
void query_clear_dname_offsets(struct query *query, size_t max_offset);
/*
* Clear the compression tables.
*/
void query_clear_compression_tables(struct query *query);
/*
* Enter the specified domain into the compression table starting at
* the specified offset.
*/
void query_add_compression_domain(struct query *query,
domain_type *domain,
uint16_t offset);
/*
* Create a new query structure.
*/
query_type *query_create(region_type *region,
uint16_t *compressed_dname_offsets,
size_t compressed_dname_size,
domain_type **compressed_dnames);
/*
* Reset a query structure so it is ready for receiving and processing
* a new query.
*/
void query_reset(query_type *query, size_t maxlen, int is_tcp);
/*
* Process a query and write the response in the query I/O buffer.
*/
query_state_type query_process(query_type *q, nsd_type *nsd, uint32_t *now_p);
/*
* Prepare the query structure for writing the response. The packet
* data up-to the current packet limit is preserved. This usually
* includes the packet header and question section. Space is reserved
* for the optional EDNS record, if required.
*/
void query_prepare_response(query_type *q);
/*
* Add EDNS0 information to the response if required.
*/
void query_add_optional(query_type *q, nsd_type *nsd, uint32_t *now_p);
/*
* Write an error response into the query structure with the indicated
* RCODE.
*/
query_state_type query_error(query_type *q, nsd_rc_type rcode);
static inline int
query_overflow(query_type *q)
{
return buffer_position(q->packet) > (q->maxlen - q->reserved_space);
}
#endif /* QUERY_H */
|