em-udns 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/ext/em-udns.c +635 -0
- data/ext/em-udns.h +11 -0
- data/ext/extconf.rb +32 -0
- data/ext/udns-0.1.tar.gz +0 -0
- data/lib/em-udns/resolver.rb +36 -0
- data/lib/em-udns.rb +32 -0
- data/test/test-em-udns.rb +115 -0
- metadata +68 -0
data/ext/em-udns.c
ADDED
@@ -0,0 +1,635 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <ctype.h>
|
3
|
+
#include <netinet/in.h>
|
4
|
+
#include "udns.h"
|
5
|
+
#include "em-udns.h"
|
6
|
+
|
7
|
+
|
8
|
+
static VALUE mEm;
|
9
|
+
static VALUE mEmDeferrable;
|
10
|
+
static VALUE mUdns;
|
11
|
+
|
12
|
+
static VALUE cResolver;
|
13
|
+
static VALUE cQuery;
|
14
|
+
|
15
|
+
static VALUE cRR_MX;
|
16
|
+
static VALUE cRR_SRV;
|
17
|
+
static VALUE cRR_NAPTR;
|
18
|
+
|
19
|
+
static VALUE eUdnsError;
|
20
|
+
static VALUE eUdnsTempFail;
|
21
|
+
static VALUE eUdnsNoMem;
|
22
|
+
static VALUE eUdnsBadQuery;
|
23
|
+
|
24
|
+
|
25
|
+
void Resolver_free(struct dns_ctx *dns_context)
|
26
|
+
{
|
27
|
+
if(dns_context)
|
28
|
+
dns_free(dns_context);
|
29
|
+
}
|
30
|
+
|
31
|
+
|
32
|
+
VALUE Resolver_alloc(VALUE klass)
|
33
|
+
{
|
34
|
+
struct dns_ctx *dns_context;
|
35
|
+
VALUE alloc_error = Qnil;
|
36
|
+
VALUE obj;
|
37
|
+
|
38
|
+
/* First initialize the library (so the default context). */
|
39
|
+
if (dns_init(NULL, 0) < 0)
|
40
|
+
alloc_error = rb_str_new2("udns `dns_init' failed");
|
41
|
+
|
42
|
+
/* Copy the context to a new one. */
|
43
|
+
if (!(dns_context = dns_new(NULL)))
|
44
|
+
alloc_error = rb_str_new2("udns `dns_new' failed");
|
45
|
+
|
46
|
+
obj = Data_Wrap_Struct(klass, NULL, Resolver_free, dns_context);
|
47
|
+
if (TYPE(alloc_error) == T_STRING)
|
48
|
+
rb_ivar_set(obj, rb_intern("@alloc_error"), alloc_error);
|
49
|
+
|
50
|
+
return obj;
|
51
|
+
}
|
52
|
+
|
53
|
+
|
54
|
+
void timer_cb(struct dns_ctx *dns_context, int timeout, void *data)
|
55
|
+
{
|
56
|
+
VALUE resolver;
|
57
|
+
VALUE timer;
|
58
|
+
|
59
|
+
resolver = (VALUE)data;
|
60
|
+
timer = rb_ivar_get(resolver, rb_intern("@timer"));
|
61
|
+
|
62
|
+
/* Cancel the EM::Timer. */
|
63
|
+
if (TYPE(timer) != T_NIL)
|
64
|
+
rb_funcall(timer, rb_intern("cancel"), 0);
|
65
|
+
|
66
|
+
if (timeout >= 0)
|
67
|
+
rb_funcall(resolver, rb_intern("set_timer"), 1, INT2FIX(timeout));
|
68
|
+
}
|
69
|
+
|
70
|
+
|
71
|
+
VALUE Resolver_dns_open(VALUE self)
|
72
|
+
{
|
73
|
+
struct dns_ctx *dns_context = NULL;
|
74
|
+
|
75
|
+
Data_Get_Struct(self, struct dns_ctx, dns_context);
|
76
|
+
|
77
|
+
dns_set_tmcbck(dns_context, timer_cb, (void*)self);
|
78
|
+
|
79
|
+
/* Open the new context. */
|
80
|
+
if (dns_open(dns_context) < 0)
|
81
|
+
rb_raise(eUdnsError, "udns `dns_open' failed");
|
82
|
+
|
83
|
+
return Qtrue;
|
84
|
+
}
|
85
|
+
|
86
|
+
|
87
|
+
VALUE Resolver_fd(VALUE self)
|
88
|
+
{
|
89
|
+
struct dns_ctx *dns_context = NULL;
|
90
|
+
|
91
|
+
Data_Get_Struct(self, struct dns_ctx, dns_context);
|
92
|
+
return INT2FIX(dns_sock(dns_context));
|
93
|
+
}
|
94
|
+
|
95
|
+
|
96
|
+
VALUE Resolver_ioevent(VALUE self)
|
97
|
+
{
|
98
|
+
struct dns_ctx *dns_context = NULL;
|
99
|
+
|
100
|
+
Data_Get_Struct(self, struct dns_ctx, dns_context);
|
101
|
+
dns_ioevent(dns_context, 0);
|
102
|
+
return Qfalse;
|
103
|
+
}
|
104
|
+
|
105
|
+
|
106
|
+
VALUE Resolver_timeouts(VALUE self)
|
107
|
+
{
|
108
|
+
struct dns_ctx *dns_context = NULL;
|
109
|
+
|
110
|
+
Data_Get_Struct(self, struct dns_ctx, dns_context);
|
111
|
+
dns_timeouts(dns_context, -1, 0);
|
112
|
+
|
113
|
+
return Qnil;
|
114
|
+
}
|
115
|
+
|
116
|
+
|
117
|
+
VALUE Resolver_cancel(VALUE self, VALUE query)
|
118
|
+
{
|
119
|
+
VALUE queries;
|
120
|
+
VALUE value;
|
121
|
+
|
122
|
+
queries = rb_ivar_get(self, rb_intern("@queries"));
|
123
|
+
if (TYPE(rb_hash_aref(queries, query)) == T_TRUE) {
|
124
|
+
rb_hash_aset(queries, query, Qfalse);
|
125
|
+
return Qtrue;
|
126
|
+
}
|
127
|
+
else
|
128
|
+
return Qfalse;
|
129
|
+
}
|
130
|
+
|
131
|
+
|
132
|
+
VALUE Resolver_active(VALUE self)
|
133
|
+
{
|
134
|
+
struct dns_ctx *dns_context = NULL;
|
135
|
+
|
136
|
+
Data_Get_Struct(self, struct dns_ctx, dns_context);
|
137
|
+
return INT2FIX(dns_active(dns_context));
|
138
|
+
}
|
139
|
+
|
140
|
+
|
141
|
+
static void* check_query(struct dns_ctx *dns_context, void *rr, void *data)
|
142
|
+
{
|
143
|
+
VALUE resolver;
|
144
|
+
VALUE query;
|
145
|
+
VALUE query_value_in_hash;
|
146
|
+
VALUE error;
|
147
|
+
int status;
|
148
|
+
|
149
|
+
resolver = ((struct resolver_query*)data)->resolver;
|
150
|
+
query = ((struct resolver_query*)data)->query;
|
151
|
+
xfree(data);
|
152
|
+
|
153
|
+
query_value_in_hash = rb_hash_delete(rb_ivar_get(resolver, rb_intern("@queries")), query);
|
154
|
+
/* Got response belongs to a query already removed (shouldn't occur). Ignore. */
|
155
|
+
if (query_value_in_hash == Qnil) {
|
156
|
+
if (rr) free(rr);
|
157
|
+
return NULL;
|
158
|
+
}
|
159
|
+
/* Got response belongs to a cancelled query. Ignore. */
|
160
|
+
else if (query_value_in_hash == Qfalse) {
|
161
|
+
if (rr) free(rr);
|
162
|
+
return NULL;
|
163
|
+
}
|
164
|
+
|
165
|
+
if ((status = dns_status(dns_context)) < 0) {
|
166
|
+
if (rr) free(rr);
|
167
|
+
switch(status) {
|
168
|
+
case DNS_E_TEMPFAIL:
|
169
|
+
error = ID2SYM(rb_intern("dns_error_tempfail"));
|
170
|
+
break;
|
171
|
+
case DNS_E_PROTOCOL:
|
172
|
+
error = ID2SYM(rb_intern("dns_error_protocol"));
|
173
|
+
break;
|
174
|
+
case DNS_E_NXDOMAIN:
|
175
|
+
error = ID2SYM(rb_intern("dns_error_nxdomain"));
|
176
|
+
break;
|
177
|
+
case DNS_E_NODATA:
|
178
|
+
error = ID2SYM(rb_intern("dns_error_nodata"));
|
179
|
+
break;
|
180
|
+
default:
|
181
|
+
error = ID2SYM(rb_intern("dns_error_unknown"));
|
182
|
+
break;
|
183
|
+
}
|
184
|
+
rb_funcall(query, rb_intern("set_deferred_status"), 2, ID2SYM(rb_intern("failed")), error);
|
185
|
+
return NULL;
|
186
|
+
}
|
187
|
+
|
188
|
+
return (void*)query;
|
189
|
+
}
|
190
|
+
|
191
|
+
|
192
|
+
static void dns_result_A_cb(struct dns_ctx *dns_context, struct dns_rr_a4 *rr, void *data)
|
193
|
+
{
|
194
|
+
VALUE query;
|
195
|
+
VALUE array;
|
196
|
+
int i;
|
197
|
+
char ip[INET_ADDRSTRLEN];
|
198
|
+
|
199
|
+
if (!(query = (VALUE)check_query(dns_context, rr, data))) return;
|
200
|
+
|
201
|
+
array = rb_ary_new2(rr->dnsa4_nrr);
|
202
|
+
for(i = 0; i < rr->dnsa4_nrr; i++)
|
203
|
+
rb_ary_push(array, rb_str_new2((char *)dns_ntop(AF_INET, &(rr->dnsa4_addr[i].s_addr), ip, INET_ADDRSTRLEN)));
|
204
|
+
free(rr);
|
205
|
+
|
206
|
+
rb_funcall(query, rb_intern("set_deferred_status"), 2, ID2SYM(rb_intern("succeeded")), array);
|
207
|
+
}
|
208
|
+
|
209
|
+
|
210
|
+
static void dns_result_AAAA_cb(struct dns_ctx *dns_context, struct dns_rr_a6 *rr, void *data)
|
211
|
+
{
|
212
|
+
VALUE query;
|
213
|
+
VALUE array;
|
214
|
+
int i;
|
215
|
+
char ip[INET6_ADDRSTRLEN];
|
216
|
+
|
217
|
+
if (!(query = (VALUE)check_query(dns_context, rr, data))) return;
|
218
|
+
|
219
|
+
array = rb_ary_new2(rr->dnsa6_nrr);
|
220
|
+
for(i = 0; i < rr->dnsa6_nrr; i++)
|
221
|
+
rb_ary_push(array, rb_str_new2((char *)dns_ntop(AF_INET6, &(rr->dnsa6_addr[i].s6_addr), ip, INET6_ADDRSTRLEN)));
|
222
|
+
free(rr);
|
223
|
+
|
224
|
+
rb_funcall(query, rb_intern("set_deferred_status"), 2, ID2SYM(rb_intern("succeeded")), array);
|
225
|
+
}
|
226
|
+
|
227
|
+
|
228
|
+
static void dns_result_PTR_cb(struct dns_ctx *dns_context, struct dns_rr_ptr *rr, void *data)
|
229
|
+
{
|
230
|
+
VALUE query;
|
231
|
+
VALUE array;
|
232
|
+
int i;
|
233
|
+
|
234
|
+
if (!(query = (VALUE)check_query(dns_context, rr, data))) return;
|
235
|
+
|
236
|
+
array = rb_ary_new2(rr->dnsptr_nrr);
|
237
|
+
for(i = 0; i < rr->dnsptr_nrr; i++)
|
238
|
+
rb_ary_push(array, rb_str_new2(rr->dnsptr_ptr[i]));
|
239
|
+
free(rr);
|
240
|
+
|
241
|
+
rb_funcall(query, rb_intern("set_deferred_status"), 2, ID2SYM(rb_intern("succeeded")), array);
|
242
|
+
}
|
243
|
+
|
244
|
+
|
245
|
+
static void dns_result_MX_cb(struct dns_ctx *dns_context, struct dns_rr_mx *rr, void *data)
|
246
|
+
{
|
247
|
+
VALUE query;
|
248
|
+
VALUE array;
|
249
|
+
int i;
|
250
|
+
VALUE rr_mx;
|
251
|
+
|
252
|
+
if (!(query = (VALUE)check_query(dns_context, rr, data))) return;
|
253
|
+
|
254
|
+
array = rb_ary_new2(rr->dnsmx_nrr);
|
255
|
+
for(i = 0; i < rr->dnsmx_nrr; i++) {
|
256
|
+
rr_mx = rb_obj_alloc(cRR_MX);
|
257
|
+
rb_ivar_set(rr_mx, rb_intern("@domain"), rb_str_new2(rr->dnsmx_mx[i].name));
|
258
|
+
rb_ivar_set(rr_mx, rb_intern("@priority"), INT2FIX(rr->dnsmx_mx[i].priority));
|
259
|
+
rb_ary_push(array, rr_mx);
|
260
|
+
}
|
261
|
+
free(rr);
|
262
|
+
|
263
|
+
rb_funcall(query, rb_intern("set_deferred_status"), 2, ID2SYM(rb_intern("succeeded")), array);
|
264
|
+
}
|
265
|
+
|
266
|
+
|
267
|
+
static void dns_result_TXT_cb(struct dns_ctx *dns_context, struct dns_rr_txt *rr, void *data)
|
268
|
+
{
|
269
|
+
VALUE query;
|
270
|
+
VALUE array;
|
271
|
+
int i;
|
272
|
+
|
273
|
+
if (!(query = (VALUE)check_query(dns_context, rr, data))) return;
|
274
|
+
|
275
|
+
array = rb_ary_new2(rr->dnstxt_nrr);
|
276
|
+
for(i = 0; i < rr->dnstxt_nrr; i++)
|
277
|
+
rb_ary_push(array, rb_str_new(rr->dnstxt_txt[i].txt, rr->dnstxt_txt[i].len));
|
278
|
+
free(rr);
|
279
|
+
|
280
|
+
rb_funcall(query, rb_intern("set_deferred_status"), 2, ID2SYM(rb_intern("succeeded")), array);
|
281
|
+
}
|
282
|
+
|
283
|
+
|
284
|
+
static void dns_result_SRV_cb(struct dns_ctx *dns_context, struct dns_rr_srv *rr, void *data)
|
285
|
+
{
|
286
|
+
VALUE query;
|
287
|
+
VALUE array;
|
288
|
+
int i;
|
289
|
+
VALUE rr_srv;
|
290
|
+
|
291
|
+
if (!(query = (VALUE)check_query(dns_context, rr, data))) return;
|
292
|
+
|
293
|
+
array = rb_ary_new2(rr->dnssrv_nrr);
|
294
|
+
for(i = 0; i < rr->dnssrv_nrr; i++) {
|
295
|
+
rr_srv = rb_obj_alloc(cRR_SRV);
|
296
|
+
rb_ivar_set(rr_srv, rb_intern("@domain"), rb_str_new2(rr->dnssrv_srv[i].name));
|
297
|
+
rb_ivar_set(rr_srv, rb_intern("@priority"), INT2FIX(rr->dnssrv_srv[i].priority));
|
298
|
+
rb_ivar_set(rr_srv, rb_intern("@weight"), INT2FIX(rr->dnssrv_srv[i].weight));
|
299
|
+
rb_ivar_set(rr_srv, rb_intern("@port"), INT2FIX(rr->dnssrv_srv[i].port));
|
300
|
+
rb_ary_push(array, rr_srv);
|
301
|
+
}
|
302
|
+
free(rr);
|
303
|
+
|
304
|
+
rb_funcall(query, rb_intern("set_deferred_status"), 2, ID2SYM(rb_intern("succeeded")), array);
|
305
|
+
}
|
306
|
+
|
307
|
+
|
308
|
+
static void dns_result_NAPTR_cb(struct dns_ctx *dns_context, struct dns_rr_naptr *rr, void *data)
|
309
|
+
{
|
310
|
+
VALUE query;
|
311
|
+
VALUE array;
|
312
|
+
int i;
|
313
|
+
VALUE rr_naptr;
|
314
|
+
|
315
|
+
if (!(query = (VALUE)check_query(dns_context, rr, data))) return;
|
316
|
+
|
317
|
+
array = rb_ary_new2(rr->dnsnaptr_nrr);
|
318
|
+
for(i = 0; i < rr->dnsnaptr_nrr; i++) {
|
319
|
+
rr_naptr = rb_obj_alloc(cRR_NAPTR);
|
320
|
+
rb_ivar_set(rr_naptr, rb_intern("@order"), INT2FIX(rr->dnsnaptr_naptr[i].order));
|
321
|
+
rb_ivar_set(rr_naptr, rb_intern("@preference"), INT2FIX(rr->dnsnaptr_naptr[i].preference));
|
322
|
+
rb_ivar_set(rr_naptr, rb_intern("@flags"), rb_str_new2(rr->dnsnaptr_naptr[i].flags));
|
323
|
+
rb_ivar_set(rr_naptr, rb_intern("@service"), rb_str_new2(rr->dnsnaptr_naptr[i].service));
|
324
|
+
if (strlen(rr->dnsnaptr_naptr[i].regexp) > 0)
|
325
|
+
rb_ivar_set(rr_naptr, rb_intern("@regexp"), rb_str_new2(rr->dnsnaptr_naptr[i].regexp));
|
326
|
+
else
|
327
|
+
rb_ivar_set(rr_naptr, rb_intern("@regexp"), Qnil);
|
328
|
+
if (strlen(rr->dnsnaptr_naptr[i].replacement) > 0)
|
329
|
+
rb_ivar_set(rr_naptr, rb_intern("@replacement"), rb_str_new2(rr->dnsnaptr_naptr[i].replacement));
|
330
|
+
else
|
331
|
+
rb_ivar_set(rr_naptr, rb_intern("@replacement"), Qnil);
|
332
|
+
rb_ary_push(array, rr_naptr);
|
333
|
+
}
|
334
|
+
free(rr);
|
335
|
+
|
336
|
+
rb_funcall(query, rb_intern("set_deferred_status"), 2, ID2SYM(rb_intern("succeeded")), array);
|
337
|
+
}
|
338
|
+
|
339
|
+
|
340
|
+
void raise_dns_error(struct dns_ctx *dns_context)
|
341
|
+
{
|
342
|
+
switch(dns_status(dns_context)) {
|
343
|
+
case DNS_E_TEMPFAIL:
|
344
|
+
rb_raise(eUdnsTempFail, "internal error occured");
|
345
|
+
break;
|
346
|
+
case DNS_E_NOMEM:
|
347
|
+
rb_raise(eUdnsNoMem, "no memory available to allocate query structure");
|
348
|
+
break;
|
349
|
+
case DNS_E_BADQUERY:
|
350
|
+
rb_raise(eUdnsBadQuery, "name of dn is invalid");
|
351
|
+
break;
|
352
|
+
default:
|
353
|
+
rb_raise(eUdnsError, "udns `dns_status' returns unexpected error %i", dns_status(dns_context));
|
354
|
+
break;
|
355
|
+
}
|
356
|
+
}
|
357
|
+
|
358
|
+
|
359
|
+
VALUE Resolver_submit_A(VALUE self, VALUE rb_domain)
|
360
|
+
{
|
361
|
+
struct dns_ctx *dns_context;
|
362
|
+
char *domain;
|
363
|
+
VALUE query;
|
364
|
+
struct resolver_query *data;
|
365
|
+
|
366
|
+
Data_Get_Struct(self, struct dns_ctx, dns_context);
|
367
|
+
domain = StringValueCStr(rb_domain);
|
368
|
+
query = rb_obj_alloc(cQuery);
|
369
|
+
|
370
|
+
data = ALLOC(struct resolver_query);
|
371
|
+
data->resolver = self;
|
372
|
+
data->query = query;
|
373
|
+
|
374
|
+
if (!dns_submit_a4(dns_context, domain, 0, dns_result_A_cb, (void *)data)) {
|
375
|
+
xfree(data);
|
376
|
+
raise_dns_error(dns_context);
|
377
|
+
}
|
378
|
+
|
379
|
+
rb_hash_aset(rb_ivar_get(self, rb_intern("@queries")), query, Qtrue);
|
380
|
+
return query;
|
381
|
+
}
|
382
|
+
|
383
|
+
|
384
|
+
VALUE Resolver_submit_AAAA(VALUE self, VALUE rb_domain)
|
385
|
+
{
|
386
|
+
struct dns_ctx *dns_context;
|
387
|
+
char *domain;
|
388
|
+
VALUE query;
|
389
|
+
struct resolver_query *data;
|
390
|
+
|
391
|
+
Data_Get_Struct(self, struct dns_ctx, dns_context);
|
392
|
+
domain = StringValueCStr(rb_domain);
|
393
|
+
query = rb_obj_alloc(cQuery);
|
394
|
+
|
395
|
+
data = ALLOC(struct resolver_query);
|
396
|
+
data->resolver = self;
|
397
|
+
data->query = query;
|
398
|
+
|
399
|
+
if (!dns_submit_a6(dns_context, domain, 0, dns_result_AAAA_cb, (void *)data)) {
|
400
|
+
xfree(data);
|
401
|
+
raise_dns_error(dns_context);
|
402
|
+
}
|
403
|
+
|
404
|
+
rb_hash_aset(rb_ivar_get(self, rb_intern("@queries")), query, Qtrue);
|
405
|
+
return query;
|
406
|
+
}
|
407
|
+
|
408
|
+
|
409
|
+
VALUE Resolver_submit_PTR(VALUE self, VALUE rb_ip)
|
410
|
+
{
|
411
|
+
struct dns_ctx *dns_context;
|
412
|
+
char *ip;
|
413
|
+
VALUE query;
|
414
|
+
struct resolver_query *data;
|
415
|
+
struct in_addr addr;
|
416
|
+
struct in6_addr addr6;
|
417
|
+
|
418
|
+
Data_Get_Struct(self, struct dns_ctx, dns_context);
|
419
|
+
ip = StringValueCStr(rb_ip);
|
420
|
+
query = rb_obj_alloc(cQuery);
|
421
|
+
|
422
|
+
data = ALLOC(struct resolver_query);
|
423
|
+
data->resolver = self;
|
424
|
+
data->query = query;
|
425
|
+
|
426
|
+
switch(dns_pton(AF_INET, ip, &addr)) {
|
427
|
+
/* It's valid IPv4. */
|
428
|
+
case 1:
|
429
|
+
if (!dns_submit_a4ptr(dns_context, &addr, dns_result_PTR_cb, (void *)data)) {
|
430
|
+
xfree(data);
|
431
|
+
raise_dns_error(dns_context);
|
432
|
+
}
|
433
|
+
break;
|
434
|
+
/* Invalid IPv4, let's try with IPv6. */
|
435
|
+
case 0:
|
436
|
+
switch(dns_pton(AF_INET6, ip, &addr6)) {
|
437
|
+
/* It's valid IPv6. */
|
438
|
+
case 1:
|
439
|
+
if (!dns_submit_a6ptr(dns_context, &addr6, dns_result_PTR_cb, (void *)data)) {
|
440
|
+
xfree(data);
|
441
|
+
raise_dns_error(dns_context);
|
442
|
+
}
|
443
|
+
break;
|
444
|
+
/* Also an invalid IPv6 so raise an exception. */
|
445
|
+
case 0:
|
446
|
+
xfree(data);
|
447
|
+
rb_raise(rb_eArgError, "invalid IP '%s' (neither IPv4 or IPv6)", ip);
|
448
|
+
break;
|
449
|
+
}
|
450
|
+
break;
|
451
|
+
}
|
452
|
+
|
453
|
+
rb_hash_aset(rb_ivar_get(self, rb_intern("@queries")), query, Qtrue);
|
454
|
+
return query;
|
455
|
+
}
|
456
|
+
|
457
|
+
|
458
|
+
VALUE Resolver_submit_MX(VALUE self, VALUE rb_domain)
|
459
|
+
{
|
460
|
+
struct dns_ctx *dns_context;
|
461
|
+
char *domain;
|
462
|
+
VALUE query;
|
463
|
+
struct resolver_query *data;
|
464
|
+
|
465
|
+
Data_Get_Struct(self, struct dns_ctx, dns_context);
|
466
|
+
domain = StringValueCStr(rb_domain);
|
467
|
+
query = rb_obj_alloc(cQuery);
|
468
|
+
|
469
|
+
data = ALLOC(struct resolver_query);
|
470
|
+
data->resolver = self;
|
471
|
+
data->query = query;
|
472
|
+
|
473
|
+
if (!dns_submit_mx(dns_context, domain, 0, dns_result_MX_cb, (void *)data)) {
|
474
|
+
xfree(data);
|
475
|
+
raise_dns_error(dns_context);
|
476
|
+
}
|
477
|
+
|
478
|
+
rb_hash_aset(rb_ivar_get(self, rb_intern("@queries")), query, Qtrue);
|
479
|
+
return query;
|
480
|
+
}
|
481
|
+
|
482
|
+
|
483
|
+
VALUE Resolver_submit_TXT(VALUE self, VALUE rb_domain)
|
484
|
+
{
|
485
|
+
struct dns_ctx *dns_context;
|
486
|
+
char *domain;
|
487
|
+
VALUE query;
|
488
|
+
struct resolver_query *data;
|
489
|
+
|
490
|
+
Data_Get_Struct(self, struct dns_ctx, dns_context);
|
491
|
+
domain = StringValueCStr(rb_domain);
|
492
|
+
query = rb_obj_alloc(cQuery);
|
493
|
+
|
494
|
+
data = ALLOC(struct resolver_query);
|
495
|
+
data->resolver = self;
|
496
|
+
data->query = query;
|
497
|
+
|
498
|
+
if (!dns_submit_txt(dns_context, domain, DNS_C_IN, 0, dns_result_TXT_cb, (void *)data)) {
|
499
|
+
xfree(data);
|
500
|
+
raise_dns_error(dns_context);
|
501
|
+
}
|
502
|
+
|
503
|
+
rb_hash_aset(rb_ivar_get(self, rb_intern("@queries")), query, Qtrue);
|
504
|
+
return query;
|
505
|
+
}
|
506
|
+
|
507
|
+
|
508
|
+
VALUE Resolver_submit_SRV(int argc, VALUE *argv, VALUE self)
|
509
|
+
{
|
510
|
+
struct dns_ctx *dns_context;
|
511
|
+
char *domain;
|
512
|
+
char *service = NULL;
|
513
|
+
char *protocol = NULL;
|
514
|
+
VALUE query;
|
515
|
+
struct resolver_query *data;
|
516
|
+
|
517
|
+
if (argc == 1 && TYPE(argv[0]) == T_STRING);
|
518
|
+
else if (argc == 3 && TYPE(argv[0]) == T_STRING &&
|
519
|
+
TYPE(argv[1]) == T_STRING && TYPE(argv[2]) == T_STRING) {
|
520
|
+
service = StringValueCStr(argv[1]);
|
521
|
+
protocol = StringValueCStr(argv[2]);
|
522
|
+
}
|
523
|
+
else if (argc == 3 && TYPE(argv[0]) == T_STRING &&
|
524
|
+
TYPE(argv[1]) == T_NIL && TYPE(argv[2]) == T_NIL);
|
525
|
+
else
|
526
|
+
rb_raise(rb_eArgError, "arguments must be `domain' or `domain',`service',`protocol'");
|
527
|
+
|
528
|
+
Data_Get_Struct(self, struct dns_ctx, dns_context);
|
529
|
+
domain = StringValueCStr(argv[0]);
|
530
|
+
query = rb_obj_alloc(cQuery);
|
531
|
+
|
532
|
+
data = ALLOC(struct resolver_query);
|
533
|
+
data->resolver = self;
|
534
|
+
data->query = query;
|
535
|
+
|
536
|
+
if (!dns_submit_srv(dns_context, domain, service, protocol, 0, dns_result_SRV_cb, (void *)data)) {
|
537
|
+
xfree(data);
|
538
|
+
raise_dns_error(dns_context);
|
539
|
+
}
|
540
|
+
|
541
|
+
rb_hash_aset(rb_ivar_get(self, rb_intern("@queries")), query, Qtrue);
|
542
|
+
return query;
|
543
|
+
}
|
544
|
+
|
545
|
+
|
546
|
+
VALUE Resolver_submit_NAPTR(VALUE self, VALUE rb_domain)
|
547
|
+
{
|
548
|
+
struct dns_ctx *dns_context;
|
549
|
+
char *domain;
|
550
|
+
VALUE query;
|
551
|
+
struct resolver_query *data;
|
552
|
+
|
553
|
+
Data_Get_Struct(self, struct dns_ctx, dns_context);
|
554
|
+
domain = StringValueCStr(rb_domain);
|
555
|
+
query = rb_obj_alloc(cQuery);
|
556
|
+
|
557
|
+
data = ALLOC(struct resolver_query);
|
558
|
+
data->resolver = self;
|
559
|
+
data->query = query;
|
560
|
+
|
561
|
+
if (!dns_submit_naptr(dns_context, domain, 0, dns_result_NAPTR_cb, (void *)data)) {
|
562
|
+
xfree(data);
|
563
|
+
raise_dns_error(dns_context);
|
564
|
+
}
|
565
|
+
|
566
|
+
rb_hash_aset(rb_ivar_get(self, rb_intern("@queries")), query, Qtrue);
|
567
|
+
return query;
|
568
|
+
}
|
569
|
+
|
570
|
+
|
571
|
+
/* Attribute readers. */
|
572
|
+
VALUE RR_MX_domain(VALUE self) { return rv_ivar_get(self, rb_intern("@domain")); }
|
573
|
+
VALUE RR_MX_priority(VALUE self) { return rv_ivar_get(self, rb_intern("@priority")); }
|
574
|
+
|
575
|
+
VALUE RR_SRV_priority(VALUE self) { return rv_ivar_get(self, rb_intern("@priority")); }
|
576
|
+
VALUE RR_SRV_weight(VALUE self) { return rv_ivar_get(self, rb_intern("@weight")); }
|
577
|
+
VALUE RR_SRV_port(VALUE self) { return rv_ivar_get(self, rb_intern("@port")); }
|
578
|
+
VALUE RR_SRV_domain(VALUE self) { return rv_ivar_get(self, rb_intern("@domain")); }
|
579
|
+
|
580
|
+
VALUE RR_NAPTR_order(VALUE self) { return rv_ivar_get(self, rb_intern("@order")); }
|
581
|
+
VALUE RR_NAPTR_preference(VALUE self) { return rv_ivar_get(self, rb_intern("@preference")); }
|
582
|
+
VALUE RR_NAPTR_flags(VALUE self) { return rv_ivar_get(self, rb_intern("@flags")); }
|
583
|
+
VALUE RR_NAPTR_service(VALUE self) { return rv_ivar_get(self, rb_intern("@service")); }
|
584
|
+
VALUE RR_NAPTR_regexp(VALUE self) { return rv_ivar_get(self, rb_intern("@regexp")); }
|
585
|
+
VALUE RR_NAPTR_replacement(VALUE self) { return rv_ivar_get(self, rb_intern("@replacement")); }
|
586
|
+
|
587
|
+
|
588
|
+
void Init_em_udns_ext()
|
589
|
+
{
|
590
|
+
mEm = rb_define_module("EventMachine");
|
591
|
+
mEmDeferrable = rb_define_module_under(mEm, "Deferrable");
|
592
|
+
mUdns = rb_define_module_under(mEm, "Udns");
|
593
|
+
|
594
|
+
eUdnsError = rb_define_class_under(mUdns, "UdnsError", rb_eStandardError);
|
595
|
+
eUdnsTempFail = rb_define_class_under(mUdns, "UdnsTempFail", eUdnsError);
|
596
|
+
eUdnsNoMem = rb_define_class_under(mUdns, "UdnsNoMem", eUdnsError);
|
597
|
+
eUdnsBadQuery = rb_define_class_under(mUdns, "UdnsBadQuery", eUdnsError);
|
598
|
+
|
599
|
+
cResolver = rb_define_class_under(mUdns, "Resolver", rb_cObject);
|
600
|
+
rb_define_alloc_func(cResolver, Resolver_alloc);
|
601
|
+
rb_define_private_method(cResolver, "dns_open", Resolver_dns_open, 0);
|
602
|
+
rb_define_method(cResolver, "fd", Resolver_fd, 0);
|
603
|
+
rb_define_method(cResolver, "ioevent", Resolver_ioevent, 0);
|
604
|
+
rb_define_private_method(cResolver, "timeouts", Resolver_timeouts, 0);
|
605
|
+
rb_define_method(cResolver, "active", Resolver_active, 0);
|
606
|
+
rb_define_method(cResolver, "cancel", Resolver_cancel, 1);
|
607
|
+
rb_define_method(cResolver, "submit_A", Resolver_submit_A, 1);
|
608
|
+
rb_define_method(cResolver, "submit_AAAA", Resolver_submit_AAAA, 1);
|
609
|
+
rb_define_method(cResolver, "submit_PTR", Resolver_submit_PTR, 1);
|
610
|
+
rb_define_method(cResolver, "submit_MX", Resolver_submit_MX, 1);
|
611
|
+
rb_define_method(cResolver, "submit_TXT", Resolver_submit_TXT, 1);
|
612
|
+
rb_define_method(cResolver, "submit_SRV", Resolver_submit_SRV, -1);
|
613
|
+
rb_define_method(cResolver, "submit_NAPTR", Resolver_submit_NAPTR, 1);
|
614
|
+
|
615
|
+
cQuery = rb_define_class_under(mUdns, "Query", rb_cObject);
|
616
|
+
rb_include_module(cQuery, mEmDeferrable);
|
617
|
+
|
618
|
+
cRR_MX = rb_define_class_under(mUdns, "RR_MX", rb_cObject);
|
619
|
+
rb_define_method(cRR_MX, "domain", RR_MX_domain, 0);
|
620
|
+
rb_define_method(cRR_MX, "priority", RR_MX_priority, 0);
|
621
|
+
|
622
|
+
cRR_SRV = rb_define_class_under(mUdns, "RR_SRV", rb_cObject);
|
623
|
+
rb_define_method(cRR_SRV, "priority", RR_SRV_priority, 0);
|
624
|
+
rb_define_method(cRR_SRV, "weight", RR_SRV_weight, 0);
|
625
|
+
rb_define_method(cRR_SRV, "port", RR_SRV_port, 0);
|
626
|
+
rb_define_method(cRR_SRV, "domain", RR_SRV_domain, 0);
|
627
|
+
|
628
|
+
cRR_NAPTR = rb_define_class_under(mUdns, "RR_NAPTR", rb_cObject);
|
629
|
+
rb_define_method(cRR_NAPTR, "order", RR_NAPTR_order, 0);
|
630
|
+
rb_define_method(cRR_NAPTR, "preference", RR_NAPTR_preference, 0);
|
631
|
+
rb_define_method(cRR_NAPTR, "flags", RR_NAPTR_flags, 0);
|
632
|
+
rb_define_method(cRR_NAPTR, "service", RR_NAPTR_service, 0);
|
633
|
+
rb_define_method(cRR_NAPTR, "regexp", RR_NAPTR_regexp, 0);
|
634
|
+
rb_define_method(cRR_NAPTR, "replacement", RR_NAPTR_replacement, 0);
|
635
|
+
}
|
data/ext/em-udns.h
ADDED
data/ext/extconf.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require "mkmf"
|
2
|
+
require "fileutils"
|
3
|
+
|
4
|
+
|
5
|
+
here = File.expand_path(File.dirname(__FILE__))
|
6
|
+
udns_tarball = Dir.glob("#{here}/udns-*.tar.gz").first
|
7
|
+
udns_path = udns_tarball.gsub(".tar.gz", "")
|
8
|
+
|
9
|
+
Dir.chdir(here) do
|
10
|
+
puts(cmd = "tar xzf #{udns_tarball} 2>&1")
|
11
|
+
raise "'#{cmd}' failed" unless system(cmd)
|
12
|
+
|
13
|
+
Dir.chdir(udns_path) do
|
14
|
+
puts(cmd = "./configure 2>&1")
|
15
|
+
raise "'#{cmd}' failed" unless system(cmd)
|
16
|
+
|
17
|
+
puts(cmd = "make sharedlib 2>&1")
|
18
|
+
raise "'#{cmd}' failed" unless system(cmd)
|
19
|
+
|
20
|
+
puts(cmd = "ar r libudns.a *.lo 2>&1")
|
21
|
+
raise "'#{cmd}' failed" unless system(cmd)
|
22
|
+
|
23
|
+
FileUtils.mv "libudns.a", "../"
|
24
|
+
FileUtils.mv "udns.h", "../"
|
25
|
+
end
|
26
|
+
|
27
|
+
FileUtils.remove_dir(udns_path, force = true)
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
have_library("udns") # == -ludns
|
32
|
+
create_makefile("em_udns_ext")
|
data/ext/udns-0.1.tar.gz
ADDED
Binary file
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module EventMachine::Udns
|
2
|
+
|
3
|
+
class Resolver
|
4
|
+
|
5
|
+
def initialize(nameserver = nil)
|
6
|
+
raise UdnsError, @alloc_error if @alloc_error
|
7
|
+
|
8
|
+
@queries = {}
|
9
|
+
|
10
|
+
if nameserver
|
11
|
+
ENV.delete("NAMESERVERS")
|
12
|
+
ENV["NAMESERVERS"] = case nameserver
|
13
|
+
# A single nameserver.
|
14
|
+
when String
|
15
|
+
nameserver
|
16
|
+
# Multiple nameservers.
|
17
|
+
when Array
|
18
|
+
nameserver.join(" ")
|
19
|
+
else
|
20
|
+
raise Error, "`nameserver' argument must be a String or Array of addresses"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
dns_open
|
25
|
+
end
|
26
|
+
|
27
|
+
def set_timer(timeout)
|
28
|
+
@timer = EM::Timer.new(timeout) do
|
29
|
+
timeouts
|
30
|
+
end
|
31
|
+
end
|
32
|
+
private :set_timer
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
data/lib/em-udns.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require "eventmachine"
|
2
|
+
|
3
|
+
require "em_udns_ext"
|
4
|
+
require "em-udns/resolver"
|
5
|
+
|
6
|
+
|
7
|
+
module EventMachine::Udns
|
8
|
+
|
9
|
+
module Watcher
|
10
|
+
def initialize(resolver)
|
11
|
+
@resolver = resolver
|
12
|
+
end
|
13
|
+
|
14
|
+
def notify_readable
|
15
|
+
@resolver.ioevent
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.run(resolver)
|
20
|
+
raise Error, "EventMachine is not running" unless EM.reactor_running?
|
21
|
+
|
22
|
+
raise Error, "`resolver' argument must be a EM::Udns::Resolver instance" unless
|
23
|
+
resolver.is_a? EM::Udns::Resolver
|
24
|
+
|
25
|
+
EM.watch resolver.fd, Watcher, resolver do |dns_client|
|
26
|
+
dns_client.notify_readable = true
|
27
|
+
end
|
28
|
+
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "em-udns"
|
5
|
+
|
6
|
+
|
7
|
+
def show_usage
|
8
|
+
puts <<-END_USAGE
|
9
|
+
USAGE:
|
10
|
+
|
11
|
+
#{$0} A domain [times]
|
12
|
+
#{$0} AAAA domain [times]
|
13
|
+
#{$0} PTR ip [times]
|
14
|
+
#{$0} MX domain [times]
|
15
|
+
#{$0} TXT domain [times]
|
16
|
+
#{$0} SRV _service._protocol.domain [times]
|
17
|
+
#{$0} SRV domain [service] [protocol] [times]
|
18
|
+
#{$0} NAPTR domain [times]
|
19
|
+
END_USAGE
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
if ARGV.size < 2
|
24
|
+
show_usage
|
25
|
+
exit false
|
26
|
+
end
|
27
|
+
|
28
|
+
type = ARGV[0].upcase
|
29
|
+
name = ARGV[1]
|
30
|
+
case type
|
31
|
+
when "A", "AAAA", "MX", "TXT", "PTR", "NAPTR"
|
32
|
+
times = (ARGV[2].to_i > 0) ? ARGV[2].to_i : 1
|
33
|
+
when "SRV"
|
34
|
+
if ARGV[3]
|
35
|
+
service = ARGV[2]
|
36
|
+
protocol = ARGV[3]
|
37
|
+
times = (ARGV[4].to_i > 0) ? ARGV[4].to_i : 1
|
38
|
+
else
|
39
|
+
service = nil
|
40
|
+
protocol = nil
|
41
|
+
times = (ARGV[2].to_i > 0) ? ARGV[2].to_i : 1
|
42
|
+
end
|
43
|
+
else
|
44
|
+
show_usage
|
45
|
+
exit false
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def print_info(times, time_start)
|
50
|
+
puts "\n\nINFO: all the #{times} queries terminated"
|
51
|
+
printf "INFO: time elapsed: %.4f seconds (%.4f queries/second)\n", (time_elapsed = Time.now - time_start), (times / time_elapsed)
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
EM.set_max_timers 100000
|
56
|
+
EM.run do
|
57
|
+
|
58
|
+
resolver = EM::Udns::Resolver.new "127.0.0.1"
|
59
|
+
EM::Udns.run resolver
|
60
|
+
|
61
|
+
second = 0
|
62
|
+
EM.add_periodic_timer(1) { puts "[#{second += 1}] - active queries: #{resolver.active}" }
|
63
|
+
|
64
|
+
time_start = Time.now
|
65
|
+
sent = 0
|
66
|
+
recv = 0
|
67
|
+
|
68
|
+
timer = EM::PeriodicTimer.new(0) do
|
69
|
+
if sent == times
|
70
|
+
timer.cancel
|
71
|
+
else
|
72
|
+
sent += 1
|
73
|
+
end
|
74
|
+
|
75
|
+
query = case type
|
76
|
+
when "A"
|
77
|
+
resolver.submit_A name
|
78
|
+
when "AAAA"
|
79
|
+
resolver.submit_AAAA name
|
80
|
+
when "PTR"
|
81
|
+
resolver.submit_PTR name
|
82
|
+
when "MX"
|
83
|
+
resolver.submit_MX name
|
84
|
+
when "TXT"
|
85
|
+
resolver.submit_TXT name
|
86
|
+
when "SRV"
|
87
|
+
resolver.submit_SRV name, service, protocol
|
88
|
+
when "NAPTR"
|
89
|
+
resolver.submit_NAPTR name
|
90
|
+
end
|
91
|
+
|
92
|
+
query.callback do |result|
|
93
|
+
recv += 1
|
94
|
+
puts "#{Time.now} INFO: callback: result => #{result.inspect} (sent: #{sent} / recv: #{recv})"
|
95
|
+
if recv == times
|
96
|
+
print_info(times, time_start)
|
97
|
+
exit
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
query.errback do |error|
|
102
|
+
recv += 1
|
103
|
+
puts "#{Time.now} INFO: errback: error => #{error.inspect} (sent: #{sent} / recv: #{recv})"
|
104
|
+
if recv == times
|
105
|
+
print_info(times, time_start)
|
106
|
+
exit
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Uncomment to cancel the query (so no callback/errback will be called).
|
111
|
+
#resolver.cancel(query)
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: em-udns
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Iñaki Baz Castillo
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-02-14 00:00:00.000000000 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: eventmachine
|
17
|
+
requirement: &21069240 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *21069240
|
26
|
+
description: em-udns is an async DNS resolver for EventMachine based on udns C library.
|
27
|
+
Having most of the core written in C, em-udns becomes very fast. It can resolve
|
28
|
+
DNS A, AAAA, PTR, MX, TXT, SRV and NAPTR records, and can handle every kind of errors
|
29
|
+
(domain/record not found, request timeout, malformed response...).
|
30
|
+
email: ibc@aliax.net
|
31
|
+
executables: []
|
32
|
+
extensions:
|
33
|
+
- ext/extconf.rb
|
34
|
+
extra_rdoc_files: []
|
35
|
+
files:
|
36
|
+
- lib/em-udns.rb
|
37
|
+
- lib/em-udns/resolver.rb
|
38
|
+
- ext/em-udns.c
|
39
|
+
- ext/em-udns.h
|
40
|
+
- ext/extconf.rb
|
41
|
+
- ext/udns-0.1.tar.gz
|
42
|
+
- test/test-em-udns.rb
|
43
|
+
has_rdoc: true
|
44
|
+
homepage: https://github.com/ibc/em-udns
|
45
|
+
licenses: []
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options: []
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 1.8.7
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
requirements: []
|
63
|
+
rubyforge_project:
|
64
|
+
rubygems_version: 1.5.2
|
65
|
+
signing_key:
|
66
|
+
specification_version: 3
|
67
|
+
summary: Async DNS resolver for EventMachine based on udns C library
|
68
|
+
test_files: []
|