dns: add resolveSoa and 'SOA' rrtype
authorTuğrul Topuz <tugrultopuz@gmail.com>
Mon, 21 Oct 2013 13:47:57 +0000 (16:47 +0300)
committerTimothy J Fontaine <tjfontaine@gmail.com>
Tue, 31 Dec 2013 22:30:40 +0000 (14:30 -0800)
You can now query for SOA records by either passing 'SOA' to `resolve`
or by using the new `resolveSoa`

doc/api/dns.markdown
lib/dns.js
src/cares_wrap.cc
test/internet/test-dns.js

index 60dbfe2..b9b1502 100644 (file)
@@ -52,10 +52,19 @@ such as no available file descriptors.
 ## dns.resolve(hostname, [rrtype], callback)
 
 Resolves a hostname (e.g. `'google.com'`) into an array of the record types
-specified by rrtype. Valid rrtypes are `'A'` (IPV4 addresses, default),
-`'AAAA'` (IPV6 addresses), `'MX'` (mail exchange records), `'TXT'` (text
-records), `'SRV'` (SRV records), `'PTR'` (used for reverse IP lookups),
-`'NS'` (name server records) and `'CNAME'` (canonical name records).
+specified by rrtype.
+
+Valid rrtypes are:
+
+ * `'A'` (IPV4 addresses, default)
+ * `'AAAA'` (IPV6 addresses)
+ * `'MX'` (mail exchange records)
+ * `'TXT'` (text records)
+ * `'SRV'` (SRV records)
+ * `'PTR'` (used for reverse IP lookups)
+ * `'NS'` (name server records)
+ * `'CNAME'` (canonical name records)
+ * `'SOA'` (start of authority record)
 
 The callback has arguments `(err, addresses)`.  The type of each item
 in `addresses` is determined by the record type, and described in the
@@ -96,6 +105,25 @@ The same as `dns.resolve()`, but only for service records (`SRV` records).
 of SRV records are priority, weight, port, and name (e.g.,
 `[{'priority': 10, {'weight': 5, 'port': 21223, 'name': 'service.example.com'}, ...]`).
 
+## dns.resolveSoa(hostname, callback)
+
+The same as `dns.resolve()`, but only for start of authority record queries 
+(`SOA` record).
+
+`addresses` is an object with the following structure:
+
+```
+{
+  nsname: 'ns.example.com',
+  hostmaster: 'root.example.com',
+  serial: 2013101809,
+  refresh: 10000,
+  retry: 2400,
+  expire: 604800,
+  minttl: 3600
+}
+```
+
 ## dns.resolveNs(hostname, callback)
 
 The same as `dns.resolve()`, but only for name server records (`NS` records).
index 34545e8..cbba372 100644 (file)
@@ -176,6 +176,7 @@ exports.resolveNs = resolveMap.NS = resolver('queryNs');
 exports.resolveTxt = resolveMap.TXT = resolver('queryTxt');
 exports.resolveSrv = resolveMap.SRV = resolver('querySrv');
 exports.resolveNaptr = resolveMap.NAPTR = resolver('queryNaptr');
+exports.resolveSoa = resolveMap.SOA = resolver('querySoa');
 exports.reverse = resolveMap.PTR = resolver('getHostByAddr');
 
 
index d7669c2..ade6f13 100644 (file)
@@ -717,6 +717,59 @@ class QueryNaptrWrap: public QueryWrap {
 };
 
 
+class QuerySoaWrap: public QueryWrap {
+ public:
+  QuerySoaWrap(Environment* env, Local<Object> req_wrap_obj)
+      : QueryWrap(env, req_wrap_obj) {
+  }
+
+  int Send(const char* name) {
+    ares_query(env()->cares_channel(),
+               name,
+               ns_c_in,
+               ns_t_soa,
+               Callback,
+               GetQueryArg());
+    return 0;
+  }
+
+ protected:
+  void Parse(unsigned char* buf, int len) {
+    HandleScope handle_scope(env()->isolate());
+    Context::Scope context_scope(env()->context());
+
+    ares_soa_reply* soa_out;
+    int status = ares_parse_soa_reply(buf, len, &soa_out);
+
+    if (status != ARES_SUCCESS) {
+      ParseError(status);
+      return;
+    }
+
+    Local<Object> soa_record = Object::New();
+
+    soa_record->Set(FIXED_ONE_BYTE_STRING(node_isolate, "nsname"),
+                    OneByteString(node_isolate, soa_out->nsname));
+    soa_record->Set(FIXED_ONE_BYTE_STRING(node_isolate, "hostmaster"),
+                    OneByteString(node_isolate, soa_out->hostmaster));
+    soa_record->Set(FIXED_ONE_BYTE_STRING(node_isolate, "serial"),
+                    Integer::New(soa_out->serial, node_isolate));
+    soa_record->Set(FIXED_ONE_BYTE_STRING(node_isolate, "refresh"),
+                    Integer::New(soa_out->refresh, node_isolate));
+    soa_record->Set(FIXED_ONE_BYTE_STRING(node_isolate, "retry"),
+                    Integer::New(soa_out->retry, node_isolate));
+    soa_record->Set(FIXED_ONE_BYTE_STRING(node_isolate, "expire"),
+                    Integer::New(soa_out->expire, node_isolate));
+    soa_record->Set(FIXED_ONE_BYTE_STRING(node_isolate, "minttl"),
+                    Integer::New(soa_out->minttl, node_isolate));
+
+    ares_free_data(soa_out);
+
+    this->CallOnComplete(soa_record);
+  }
+};
+
+
 class GetHostByAddrWrap: public QueryWrap {
  public:
   explicit GetHostByAddrWrap(Environment* env, Local<Object> req_wrap_obj)
@@ -1103,6 +1156,7 @@ static void Initialize(Handle<Object> target,
   NODE_SET_METHOD(target, "queryTxt", Query<QueryTxtWrap>);
   NODE_SET_METHOD(target, "querySrv", Query<QuerySrvWrap>);
   NODE_SET_METHOD(target, "queryNaptr", Query<QueryNaptrWrap>);
+  NODE_SET_METHOD(target, "querySoa", Query<QuerySoaWrap>);
   NODE_SET_METHOD(target, "getHostByAddr", Query<GetHostByAddrWrap>);
 
   NODE_SET_METHOD(target, "getaddrinfo", GetAddrInfo);
index cc69106..bb55aec 100644 (file)
@@ -244,6 +244,40 @@ TEST(function test_resolveNaptr(done) {
   checkWrap(req);
 });
 
+TEST(function test_resolveSoa(done) {
+  var req = dns.resolveSoa('nodejs.org', function(err, result) {
+    if (err) throw err;
+    
+    assert.ok(result);
+    assert.ok(typeof result === 'object');
+    
+    assert.ok(typeof result.nsname === 'string');
+    assert.ok(result.nsname.length > 0);
+    
+    assert.ok(typeof result.hostmaster === 'string');
+    assert.ok(result.hostmaster.length > 0);
+    
+    assert.ok(typeof result.serial === 'number');
+    assert.ok((result.serial > 0) && (result.serial < 4294967295));
+    
+    assert.ok(typeof result.refresh === 'number');
+    assert.ok((result.refresh > 0) && (result.refresh < 2147483647)); 
+    
+    assert.ok(typeof result.retry === 'number');
+    assert.ok((result.retry > 0) && (result.retry < 2147483647));
+    
+    assert.ok(typeof result.expire === 'number');
+    assert.ok((result.expire > 0) && (result.expire < 2147483647));
+    
+    assert.ok(typeof result.minttl === 'number');
+    assert.ok((result.minttl >= 0) && (result.minttl < 2147483647));
+
+    done();
+  });
+  
+  checkWrap(req);
+});
+
 TEST(function test_resolveCname(done) {
   var req = dns.resolveCname('www.microsoft.com', function(err, names) {
     if (err) throw err;