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
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
|
/*
* Copyright (c) 2013-2014, Vsevolod Stakhov
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef RDNS_H
#define RDNS_H
#include <sys/types.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifdef __cplusplus
extern "C" {
#endif
struct rdns_reply;
struct rdns_request;
struct rdns_io_channel;
typedef void (*dns_callback_type) (struct rdns_reply *reply, void *arg);
enum rdns_request_type {
RDNS_REQUEST_A = 1,
RDNS_REQUEST_NS = 2,
RDNS_REQUEST_SOA = 6,
RDNS_REQUEST_PTR = 12,
RDNS_REQUEST_MX = 15,
RDNS_REQUEST_TXT = 16,
RDNS_REQUEST_SRV = 33,
RDNS_REQUEST_SPF = 99,
RDNS_REQUEST_AAAA = 28,
RDNS_REQUEST_TLSA = 52,
RDNS_REQUEST_ANY = 255
};
union rdns_reply_element_un {
struct {
struct in_addr addr;
} a;
struct {
struct in6_addr addr;
} aaa;
struct {
char *name;
} ptr;
struct {
char *name;
} ns;
struct {
char *name;
uint16_t priority;
} mx;
struct {
char *data;
} txt;
struct {
uint16_t priority;
uint16_t weight;
uint16_t port;
char *target;
} srv;
struct {
char *mname;
char *admin;
uint32_t serial;
int32_t refresh;
int32_t retry;
int32_t expire;
uint32_t minimum;
} soa;
struct {
uint8_t usage;
uint8_t selector;
uint8_t match_type;
uint16_t datalen;
uint8_t *data;
} tlsa;
};
struct rdns_reply_entry {
union rdns_reply_element_un content;
uint16_t type;
int32_t ttl;
struct rdns_reply_entry *prev, *next;
};
enum dns_rcode {
RDNS_RC_NOERROR = 0,
RDNS_RC_FORMERR = 1,
RDNS_RC_SERVFAIL = 2,
RDNS_RC_NXDOMAIN = 3,
RDNS_RC_NOTIMP = 4,
RDNS_RC_REFUSED = 5,
RDNS_RC_YXDOMAIN = 6,
RDNS_RC_YXRRSET = 7,
RDNS_RC_NXRRSET = 8,
RDNS_RC_NOTAUTH = 9,
RDNS_RC_NOTZONE = 10,
RDNS_RC_TIMEOUT = 11,
RDNS_RC_NETERR = 12,
RDNS_RC_NOREC = 13
};
struct rdns_reply {
struct rdns_request *request;
struct rdns_resolver *resolver;
struct rdns_reply_entry *entries;
const char *requested_name;
enum dns_rcode code;
};
typedef void (*rdns_periodic_callback)(void *user_data);
struct rdns_async_context {
void *data;
void* (*add_read)(void *priv_data, int fd, void *user_data);
void (*del_read)(void *priv_data, void *ev_data);
void* (*add_write)(void *priv_data, int fd, void *user_data);
void (*del_write)(void *priv_data, void *ev_data);
void* (*add_timer)(void *priv_data, double after, void *user_data);
void (*repeat_timer)(void *priv_data, void *ev_data);
void (*del_timer)(void *priv_data, void *ev_data);
void* (*add_periodic)(void *priv_data, double after,
rdns_periodic_callback cb, void *user_data);
void (*del_periodic)(void *priv_data, void *ev_data);
void (*cleanup)(void *priv_data);
};
struct rdns_upstream_elt {
void *server;
void *lib_data;
};
struct rdns_upstream_context {
void *data;
struct rdns_upstream_elt* (*select)(const char *name,
size_t len, void *ups_data);
struct rdns_upstream_elt* (*select_retransmit)(const char *name,
size_t len, void *ups_data);
void (*ok)(struct rdns_upstream_elt *elt, void *ups_data);
void (*fail)(struct rdns_upstream_elt *elt, void *ups_data);
};
/**
* Type of rdns plugin
*/
enum rdns_plugin_type {
RDNS_PLUGIN_CURVE = 0
};
typedef ssize_t (*rdns_network_send_callback) (struct rdns_request *req, void *plugin_data);
typedef ssize_t (*rdns_network_recv_callback) (struct rdns_io_channel *ioc, void *buf,
size_t len, void *plugin_data, struct rdns_request **req_out);
typedef void (*rdns_network_finish_callback) (struct rdns_request *req, void *plugin_data);
typedef void (*rdns_plugin_dtor_callback) (struct rdns_resolver *resolver, void *plugin_data);
struct rdns_plugin {
enum rdns_plugin_type type;
union {
struct {
rdns_network_send_callback send_cb;
rdns_network_recv_callback recv_cb;
rdns_network_finish_callback finish_cb;
} curve_plugin;
} cb;
rdns_plugin_dtor_callback dtor;
void *data;
};
/*
* RDNS logger types
*/
/*
* These types are somehow compatible with glib
*/
enum rdns_log_level {
RDNS_LOG_ERROR = 1 << 3,
RDNS_LOG_WARNING = 1 << 4,
RDNS_LOG_INFO = 1 << 6,
RDNS_LOG_DEBUG = 1 << 7
};
typedef void (*rdns_log_function) (
void *log_data, //!< opaque data pointer
enum rdns_log_level level, //!< level of message
const char *function, //!< calling function
const char *format, //!< format
va_list args //!< set of arguments
);
struct rdns_request_name {
char *name;
enum rdns_request_type type;
unsigned int len;
};
/*
* RDNS API
*/
/**
* Create DNS resolver structure
*/
struct rdns_resolver *rdns_resolver_new (void);
/**
* Bind resolver to specified async context
* @param ctx
*/
void rdns_resolver_async_bind (struct rdns_resolver *resolver,
struct rdns_async_context *ctx);
/**
* Add new DNS server definition to the resolver
* @param resolver resolver object
* @param name name of DNS server (should be ipv4 or ipv6 address)
* @param priority priority (can be 0 for fair round-robin)
* @param io_cnt a number of sockets that are simultaneously opened to this server
* @return opaque pointer that could be used to select upstream
*/
void* rdns_resolver_add_server (struct rdns_resolver *resolver,
const char *name, unsigned int port,
int priority, unsigned int io_cnt);
/**
* Load nameservers definition from resolv.conf file
* @param resolver resolver object
* @param path path to resolv.conf file (/etc/resolv.conf typically)
* @return true if resolv.conf has been parsed
*/
bool rdns_resolver_parse_resolv_conf (struct rdns_resolver *resolver,
const char *path);
/**
* Set an external logger function to log messages from the resolver
* @param resolver resolver object
* @param logger logger callback
* @param log_data opaque data
*/
void rdns_resolver_set_logger (struct rdns_resolver *resolver,
rdns_log_function logger, void *log_data);
/**
* Set log level for an internal logger (stderr one)
* @param resolver resolver object
* @param level desired log level
*/
void rdns_resolver_set_log_level (struct rdns_resolver *resolver,
enum rdns_log_level level);
/**
* Set upstream library for selecting DNS upstreams
* @param resolver resolver object
* @param ups_ctx upstream functions
* @param ups_data opaque data
*/
void rdns_resolver_set_upstream_lib (struct rdns_resolver *resolver,
struct rdns_upstream_context *ups_ctx,
void *ups_data);
/**
* Set maximum number of dns requests to be sent to a socket to be refreshed
* @param resolver resolver object
* @param max_ioc_uses unsigned count of socket usage limit
* @param check_time specifies how often to check for sockets and refresh them
*/
void rdns_resolver_set_max_io_uses (struct rdns_resolver *resolver,
uint64_t max_ioc_uses, double check_time);
/**
* Register new plugin for rdns resolver
* @param resolver
* @param plugin
*/
void rdns_resolver_register_plugin (struct rdns_resolver *resolver,
struct rdns_plugin *plugin);
/**
* Init DNS resolver
* @param resolver
* @return
*/
bool rdns_resolver_init (struct rdns_resolver *resolver);
/**
* Decrease refcount for a resolver and free it if refcount is 0
* @param resolver
*/
void rdns_resolver_release (struct rdns_resolver *resolver);
/**
* Make a DNS request
* @param resolver resolver object
* @param cb callback to call on resolve completing
* @param ud user data for callback
* @param timeout timeout in seconds
* @param repeats how much time to retransmit query
* @param queries how much RR queries to send
* @param ... -> queries in format: <query_type>[,type_argument[,type_argument...]]
* @return opaque request object or NULL
*/
struct rdns_request* rdns_make_request_full (
struct rdns_resolver *resolver,
dns_callback_type cb,
void *cbdata,
double timeout,
unsigned int repeats,
unsigned int queries,
...
);
/**
* Get textual presentation of DNS error code
*/
const char *rdns_strerror (enum dns_rcode rcode);
/**
* Get textual presentation of DNS request type
*/
const char *rdns_strtype (enum rdns_request_type type);
/**
* Increase refcount for a request
* @param req
* @return
*/
struct rdns_request* rdns_request_retain (struct rdns_request *req);
/**
* Decrease refcount for a request and free it if refcount is 0
* @param req
*/
void rdns_request_release (struct rdns_request *req);
/**
* Check whether a request contains `type` request
* @param req request object
* @param type check for a specified type
* @return true if `type` has been requested
*/
bool rdns_request_has_type (struct rdns_request *req, enum rdns_request_type type);
/**
* Return requested name for a request
* @param req request object
* @return requested name as it was passed to `rdns_make_request`
*/
const struct rdns_request_name* rdns_request_get_name (struct rdns_request *req,
unsigned int *count);
/**
* Return PTR string for a request (ipv4 or ipv6) addresses
* @param str string representation of IP address
* @return name to resolve or NULL if `str` is not an IP address; caller must free result when it is unused
*/
char * rdns_generate_ptr_from_str (const char *str);
/*
* Private functions used by async libraries as callbacks
*/
void rdns_process_read (int fd, void *arg);
void rdns_process_timer (void *arg);
void rdns_process_retransmit (int fd, void *arg);
#ifdef __cplusplus
}
#endif
#endif
|