Skip to content

Commit

Permalink
Merge pull request #13 from agaridata/master
Browse files Browse the repository at this point in the history
Upgrade libudns to 0.4 and add NS record lookup support.
  • Loading branch information
ibc committed Mar 1, 2017
2 parents 19f658d + 4d665b4 commit 73f15dc
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 12 deletions.
30 changes: 27 additions & 3 deletions README.markdown
Expand Up @@ -5,7 +5,7 @@

## Overview

EM-Udns is an async DNS resolver for [EventMachine](http://rubyeventmachine.com) based on [udns](http://www.corpit.ru/mjt/udns.html) C library. Having most of the code written in C, EM-Udns becomes very fast. It can resolve DNS A, AAAA, PTR, MX, TXT, SRV and NAPTR records, and can handle every kind of errors (domain/record not found, request timeout, malformed response...).
EM-Udns is an async DNS resolver for [EventMachine](http://rubyeventmachine.com) based on [udns](http://www.corpit.ru/mjt/udns.html) C library. Having most of the code written in C, EM-Udns becomes very fast. It can resolve DNS A, AAAA, PTR, MX, TXT, NS, SRV and NAPTR records, and can handle every kind of errors (domain/record not found, request timeout, malformed response...).

C udns is a stub resolver, so also EM-Udns. This means that it must rely on a recursive name server, usually co-located in local host or local network. A very good choice is [Unbound](http://unbound.net), a validating, recursive and caching DNS resolver.

Expand All @@ -21,6 +21,11 @@ C udns is a stub resolver, so also EM-Udns. This means that it must rely on a re
EM::Udns.nameservers = "127.0.0.1"
resolver = EM::Udns::Resolver.new

# alternate method of setting nameserver, including non-standard port
# resolver = EM::Udns::Resolver.new(nameserver: '127.0.0.1:5353')
# resolver = EM::Udns::Resolver.new(nameserver: ['192.168.0.1', '192.168.0.2:5353'])

EM::Udns.run resolver

query = resolver.submit_A "google.com"
Expand Down Expand Up @@ -67,8 +72,12 @@ Example 2:

Returns a `EM::Udns::Resolver` instance. If there is an error an exception `EM::Udns::UdnsError` is raised.


## Runnig a Resolver
nameserver(s) may also be passed to `new` as a hash argument:

resolver = EM::Udns::Resolver.new(nameserver: '127.0.0.1:5353')
resolver = EM::Udns::Resolver.new(nameserver: ['192.168.0.1', '192.168.0.2:5353'])

## Running a Resolver

EM::Udns.run resolver

Expand Down Expand Up @@ -194,6 +203,21 @@ Callback is called with argument:

["v=spf1 redirect=_spf.google.com"]


### NS Record

resolver.submit_NS(domain)

In case of success the callback is invoked passing as argument an array of `String` objects. Each `String` represents a nameserver entry in the NS result.

Example:

resolver.submit_NS "gmail.com"

Callback is called with argument:

["ns1.google.com", "ns3.google.com", "ns4.google.com", "ns2.google.com"]


### SRV Record

Expand Down
2 changes: 1 addition & 1 deletion em-udns.gemspec
Expand Up @@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
ext/em-udns.c
ext/em-udns.h
ext/extconf.rb
ext/udns-0.2-patched.tar.gz
ext/udns-0.4-patched.tar.gz
test/test-em-udns.rb
}
spec.require_paths = ["lib"]
Expand Down
87 changes: 83 additions & 4 deletions ext/em-udns.c
Expand Up @@ -2,6 +2,8 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "udns.h"
#include "em-udns.h"

Expand Down Expand Up @@ -141,8 +143,7 @@ VALUE Resolver_timeouts(VALUE self)
VALUE Resolver_cancel(VALUE self, VALUE query)
{
VALUE queries;
VALUE value;


queries = rb_ivar_get(self, id_queries);
if (TYPE(rb_hash_aref(queries, query)) == T_TRUE) {
rb_hash_aset(queries, query, Qfalse);
Expand Down Expand Up @@ -261,7 +262,7 @@ static void dns_result_PTR_cb(struct dns_ctx *dns_context, struct dns_rr_ptr *rr
for(i = 0; i < rr->dnsptr_nrr; i++)
rb_ary_push(array, rb_str_new2(rr->dnsptr_ptr[i]));
free(rr);

rb_funcall(query, method_do_success, 1, array);
}

Expand All @@ -287,6 +288,24 @@ static void dns_result_MX_cb(struct dns_ctx *dns_context, struct dns_rr_mx *rr,
rb_funcall(query, method_do_success, 1, array);
}

static void dns_result_NS_cb(struct dns_ctx *dns_context, struct dns_rr_ns *rr, void *data)
{
VALUE query;
VALUE array;
int i;

if (!(query = (VALUE)check_query(dns_context, rr, data))) return;

array = rb_ary_new2(rr->dnsns_nrr);
for(i = 0; i < rr->dnsns_nrr; i++) {
rb_ary_push(array, rb_str_new2(rr->dnsns_ns[i]));
}
free(rr);

rb_funcall(query, method_do_success, 1, array);
}



static void dns_result_TXT_cb(struct dns_ctx *dns_context, struct dns_rr_txt *rr, void *data)
{
Expand All @@ -298,7 +317,7 @@ static void dns_result_TXT_cb(struct dns_ctx *dns_context, struct dns_rr_txt *rr

array = rb_ary_new2(rr->dnstxt_nrr);
for(i = 0; i < rr->dnstxt_nrr; i++)
rb_ary_push(array, rb_str_new(rr->dnstxt_txt[i].txt, rr->dnstxt_txt[i].len));
rb_ary_push(array, rb_str_new((const char*)rr->dnstxt_txt[i].txt, rr->dnstxt_txt[i].len));
free(rr);

rb_funcall(query, method_do_success, 1, array);
Expand Down Expand Up @@ -524,6 +543,33 @@ VALUE Resolver_submit_MX(VALUE self, VALUE rb_domain)
return query;
}

VALUE Resolver_submit_NS(VALUE self, VALUE rb_domain)
{
struct dns_ctx *dns_context;
char *domain;
VALUE query;
VALUE error;
struct resolver_query *data;

Data_Get_Struct(self, struct dns_ctx, dns_context);
domain = StringValueCStr(rb_domain);
query = rb_obj_alloc(cQuery);

data = ALLOC(struct resolver_query);
data->resolver = self;
data-> query = query;

if (!dns_submit_ns(dns_context, domain, 0, dns_result_NS_cb, (void *)data)) {
error = get_dns_error(dns_context);
xfree(data);
rb_funcall(query, method_do_error, 1, error);
}
else {
rb_hash_aset(rb_ivar_get(self, id_queries), query, Qtrue);
}
return query;
}


VALUE Resolver_submit_TXT(VALUE self, VALUE rb_domain)
{
Expand Down Expand Up @@ -624,6 +670,36 @@ VALUE Resolver_submit_NAPTR(VALUE self, VALUE rb_domain)
return query;
}

int _add_serv_s(struct dns_ctx *dns_context, const char *ip, in_port_t port)
{
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
inet_aton(ip, &server_addr.sin_addr);
server_addr.sin_port = htons(port);
return dns_add_serv_s(dns_context, (struct sockaddr *)&server_addr);
}

VALUE Resolver_add_serv(VALUE self, VALUE ip)
{
struct dns_ctx *dns_context;
struct servent *sp;

Data_Get_Struct(self, struct dns_ctx, dns_context);

if (TYPE(ip) == T_NIL) {
return INT2FIX(dns_add_serv(dns_context, NULL));
}

sp = getservbyname("domain", "udp");
return INT2FIX(_add_serv_s(dns_context, StringValueCStr(ip), htons(sp->s_port)));
}

VALUE Resolver_add_serv_s(VALUE self, VALUE ip, VALUE port)
{
struct dns_ctx *dns_context;
Data_Get_Struct(self, struct dns_ctx, dns_context);
return INT2FIX(_add_serv_s(dns_context, StringValueCStr(ip), FIX2INT(port)));
}

/* Attribute readers. */
VALUE RR_MX_domain(VALUE self) { return rb_ivar_get(self, id_domain); }
Expand Down Expand Up @@ -663,6 +739,9 @@ void Init_em_udns_ext()
rb_define_method(cResolver, "submit_TXT", Resolver_submit_TXT, 1);
rb_define_method(cResolver, "submit_SRV", Resolver_submit_SRV, -1);
rb_define_method(cResolver, "submit_NAPTR", Resolver_submit_NAPTR, 1);
rb_define_method(cResolver, "submit_NS", Resolver_submit_NS, 1);
rb_define_method(cResolver, "add_serv", Resolver_add_serv, 1);
rb_define_method(cResolver, "add_serv_s", Resolver_add_serv_s, 2);

cQuery = rb_define_class_under(mUdns, "Query", rb_cObject);

Expand Down
Binary file removed ext/udns-0.2-patched.tar.gz
Binary file not shown.
Binary file added ext/udns-0.4-patched.tar.gz
Binary file not shown.
16 changes: 14 additions & 2 deletions lib/em-udns/resolver.rb
@@ -1,9 +1,21 @@
module EventMachine::Udns

class Resolver
def initialize
def initialize(options = {})
raise UdnsError, @alloc_error if @alloc_error
@queries = {}
nameservers = [*options[:nameserver]] + [*options[:nameservers]]
if nameservers.any?
add_serv(nil) # clear the list initialized from /etc/resolv.conf
nameservers.each do |ns|
host, port = ns.split(':')
if port
add_serv_s(host, port.to_i)
else
add_serv(host)
end
end
end
dns_open
end

Expand All @@ -15,4 +27,4 @@ def set_timer(timeout)
end
end

end
end
2 changes: 1 addition & 1 deletion lib/em-udns/version.rb
@@ -1,5 +1,5 @@
module EventMachine
module Udns
VERSION = "0.3.6"
VERSION = "0.3.6.2"
end
end
5 changes: 4 additions & 1 deletion test/test-em-udns.rb
Expand Up @@ -18,6 +18,7 @@ def show_usage
#{$0} SRV _service._protocol.domain [times]
#{$0} SRV domain [service] [protocol] [times]
#{$0} NAPTR domain [times]
#{$0} NS domain [times]
END_USAGE
end

Expand All @@ -30,7 +31,7 @@ def show_usage
type = ARGV[0].upcase
name = ARGV[1]
case type
when "A", "AAAA", "MX", "TXT", "PTR", "NAPTR"
when "A", "AAAA", "MX", "TXT", "PTR", "NAPTR", "NS"
times = (ARGV[2].to_i > 0) ? ARGV[2].to_i : 1
when "SRV"
if ARGV[3]
Expand Down Expand Up @@ -92,6 +93,8 @@ def print_info(times, time_start)
resolver.submit_SRV name, service, protocol
when "NAPTR"
resolver.submit_NAPTR name
when "NS"
resolver.submit_NS name
end

query.callback do |result|
Expand Down

0 comments on commit 73f15dc

Please sign in to comment.