mirror of
https://github.com/nodejs/node.git
synced 2025-04-28 13:40:37 +00:00
dns: add TLSA record query and parsing
PR-URL: https://github.com/nodejs/node/pull/52983 Refs: https://github.com/nodejs/node/issues/39569 Reviewed-By: Paolo Insogna <paolo@cowtech.it> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
This commit is contained in:
parent
ea2004a2ac
commit
ef91595e2f
@ -129,6 +129,7 @@ The following methods from the `node:dns` module are available:
|
|||||||
* [`resolver.resolvePtr()`][`dns.resolvePtr()`]
|
* [`resolver.resolvePtr()`][`dns.resolvePtr()`]
|
||||||
* [`resolver.resolveSoa()`][`dns.resolveSoa()`]
|
* [`resolver.resolveSoa()`][`dns.resolveSoa()`]
|
||||||
* [`resolver.resolveSrv()`][`dns.resolveSrv()`]
|
* [`resolver.resolveSrv()`][`dns.resolveSrv()`]
|
||||||
|
* [`resolver.resolveTlsa()`][`dns.resolveTlsa()`]
|
||||||
* [`resolver.resolveTxt()`][`dns.resolveTxt()`]
|
* [`resolver.resolveTxt()`][`dns.resolveTxt()`]
|
||||||
* [`resolver.reverse()`][`dns.reverse()`]
|
* [`resolver.reverse()`][`dns.reverse()`]
|
||||||
* [`resolver.setServers()`][`dns.setServers()`]
|
* [`resolver.setServers()`][`dns.setServers()`]
|
||||||
@ -444,6 +445,7 @@ records. The type and structure of individual results varies based on `rrtype`:
|
|||||||
| `'PTR'` | pointer records | {string} | [`dns.resolvePtr()`][] |
|
| `'PTR'` | pointer records | {string} | [`dns.resolvePtr()`][] |
|
||||||
| `'SOA'` | start of authority records | {Object} | [`dns.resolveSoa()`][] |
|
| `'SOA'` | start of authority records | {Object} | [`dns.resolveSoa()`][] |
|
||||||
| `'SRV'` | service records | {Object} | [`dns.resolveSrv()`][] |
|
| `'SRV'` | service records | {Object} | [`dns.resolveSrv()`][] |
|
||||||
|
| `'TLSA'` | certificate associations | {Object} | [`dns.resolveTlsa()`][] |
|
||||||
| `'TXT'` | text records | {string\[]} | [`dns.resolveTxt()`][] |
|
| `'TXT'` | text records | {string\[]} | [`dns.resolveTxt()`][] |
|
||||||
|
|
||||||
On error, `err` is an [`Error`][] object, where `err.code` is one of the
|
On error, `err` is an [`Error`][] object, where `err.code` is one of the
|
||||||
@ -543,6 +545,7 @@ will be present on the object:
|
|||||||
| `'PTR'` | `value` |
|
| `'PTR'` | `value` |
|
||||||
| `'SOA'` | Refer to [`dns.resolveSoa()`][] |
|
| `'SOA'` | Refer to [`dns.resolveSoa()`][] |
|
||||||
| `'SRV'` | Refer to [`dns.resolveSrv()`][] |
|
| `'SRV'` | Refer to [`dns.resolveSrv()`][] |
|
||||||
|
| `'TLSA'` | Refer to [`dns.resolveTlsa()`][] |
|
||||||
| `'TXT'` | This type of record contains an array property called `entries` which refers to [`dns.resolveTxt()`][], e.g. `{ entries: ['...'], type: 'TXT' }` |
|
| `'TXT'` | This type of record contains an array property called `entries` which refers to [`dns.resolveTxt()`][], e.g. `{ entries: ['...'], type: 'TXT' }` |
|
||||||
|
|
||||||
Here is an example of the `ret` object passed to the callback:
|
Here is an example of the `ret` object passed to the callback:
|
||||||
@ -802,6 +805,41 @@ be an array of objects with the following properties:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## `dns.resolveTlsa(hostname, callback)`
|
||||||
|
|
||||||
|
<!-- YAML
|
||||||
|
added: REPLACEME
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!--lint disable no-undefined-references list-item-bullet-indent-->
|
||||||
|
|
||||||
|
* `hostname` {string}
|
||||||
|
* `callback` {Function}
|
||||||
|
* `err` {Error}
|
||||||
|
* `records` {Object\[]}
|
||||||
|
|
||||||
|
<!--lint enable no-undefined-references list-item-bullet-indent-->
|
||||||
|
|
||||||
|
Uses the DNS protocol to resolve certificate associations (`TLSA` records) for
|
||||||
|
the `hostname`. The `records` argument passed to the `callback` function is an
|
||||||
|
array of objects with these properties:
|
||||||
|
|
||||||
|
* `certUsage`
|
||||||
|
* `selector`
|
||||||
|
* `match`
|
||||||
|
* `data`
|
||||||
|
|
||||||
|
<!-- eslint-skip -->
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
certUsage: 3,
|
||||||
|
selector: 1,
|
||||||
|
match: 1,
|
||||||
|
data: [ArrayBuffer]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## `dns.resolveTxt(hostname, callback)`
|
## `dns.resolveTxt(hostname, callback)`
|
||||||
|
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
@ -1008,6 +1046,7 @@ The following methods from the `dnsPromises` API are available:
|
|||||||
* [`resolver.resolvePtr()`][`dnsPromises.resolvePtr()`]
|
* [`resolver.resolvePtr()`][`dnsPromises.resolvePtr()`]
|
||||||
* [`resolver.resolveSoa()`][`dnsPromises.resolveSoa()`]
|
* [`resolver.resolveSoa()`][`dnsPromises.resolveSoa()`]
|
||||||
* [`resolver.resolveSrv()`][`dnsPromises.resolveSrv()`]
|
* [`resolver.resolveSrv()`][`dnsPromises.resolveSrv()`]
|
||||||
|
* [`resolver.resolveTlsa()`][`dnsPromises.resolveTlsa()`]
|
||||||
* [`resolver.resolveTxt()`][`dnsPromises.resolveTxt()`]
|
* [`resolver.resolveTxt()`][`dnsPromises.resolveTxt()`]
|
||||||
* [`resolver.reverse()`][`dnsPromises.reverse()`]
|
* [`resolver.reverse()`][`dnsPromises.reverse()`]
|
||||||
* [`resolver.setServers()`][`dnsPromises.setServers()`]
|
* [`resolver.setServers()`][`dnsPromises.setServers()`]
|
||||||
@ -1212,6 +1251,7 @@ based on `rrtype`:
|
|||||||
| `'PTR'` | pointer records | {string} | [`dnsPromises.resolvePtr()`][] |
|
| `'PTR'` | pointer records | {string} | [`dnsPromises.resolvePtr()`][] |
|
||||||
| `'SOA'` | start of authority records | {Object} | [`dnsPromises.resolveSoa()`][] |
|
| `'SOA'` | start of authority records | {Object} | [`dnsPromises.resolveSoa()`][] |
|
||||||
| `'SRV'` | service records | {Object} | [`dnsPromises.resolveSrv()`][] |
|
| `'SRV'` | service records | {Object} | [`dnsPromises.resolveSrv()`][] |
|
||||||
|
| `'TLSA'` | certificate associations | {Object} | [`dnsPromises.resolveTlsa()`][] |
|
||||||
| `'TXT'` | text records | {string\[]} | [`dnsPromises.resolveTxt()`][] |
|
| `'TXT'` | text records | {string\[]} | [`dnsPromises.resolveTxt()`][] |
|
||||||
|
|
||||||
On error, the `Promise` is rejected with an [`Error`][] object, where `err.code`
|
On error, the `Promise` is rejected with an [`Error`][] object, where `err.code`
|
||||||
@ -1276,6 +1316,7 @@ present on the object:
|
|||||||
| `'PTR'` | `value` |
|
| `'PTR'` | `value` |
|
||||||
| `'SOA'` | Refer to [`dnsPromises.resolveSoa()`][] |
|
| `'SOA'` | Refer to [`dnsPromises.resolveSoa()`][] |
|
||||||
| `'SRV'` | Refer to [`dnsPromises.resolveSrv()`][] |
|
| `'SRV'` | Refer to [`dnsPromises.resolveSrv()`][] |
|
||||||
|
| `'TLSA'` | Refer to [`dnsPromises.resolveTlsa()`][] |
|
||||||
| `'TXT'` | This type of record contains an array property called `entries` which refers to [`dnsPromises.resolveTxt()`][], e.g. `{ entries: ['...'], type: 'TXT' }` |
|
| `'TXT'` | This type of record contains an array property called `entries` which refers to [`dnsPromises.resolveTxt()`][], e.g. `{ entries: ['...'], type: 'TXT' }` |
|
||||||
|
|
||||||
Here is an example of the result object:
|
Here is an example of the result object:
|
||||||
@ -1458,6 +1499,34 @@ the following properties:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `dnsPromises.resolveTlsa(hostname)`
|
||||||
|
|
||||||
|
<!-- YAML
|
||||||
|
added: REPLACEME
|
||||||
|
-->
|
||||||
|
|
||||||
|
* `hostname` {string}
|
||||||
|
|
||||||
|
Uses the DNS protocol to resolve certificate associations (`TLSA` records) for
|
||||||
|
the `hostname`. On success, the `Promise` is resolved with an array of objects
|
||||||
|
with these properties:
|
||||||
|
|
||||||
|
* `certUsage`
|
||||||
|
* `selector`
|
||||||
|
* `match`
|
||||||
|
* `data`
|
||||||
|
|
||||||
|
<!-- eslint-skip -->
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
certUsage: 3,
|
||||||
|
selector: 1,
|
||||||
|
match: 1,
|
||||||
|
data: [ArrayBuffer]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### `dnsPromises.resolveTxt(hostname)`
|
### `dnsPromises.resolveTxt(hostname)`
|
||||||
|
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
@ -1658,6 +1727,7 @@ uses. For instance, they do not use the configuration from `/etc/hosts`.
|
|||||||
[`dns.resolvePtr()`]: #dnsresolveptrhostname-callback
|
[`dns.resolvePtr()`]: #dnsresolveptrhostname-callback
|
||||||
[`dns.resolveSoa()`]: #dnsresolvesoahostname-callback
|
[`dns.resolveSoa()`]: #dnsresolvesoahostname-callback
|
||||||
[`dns.resolveSrv()`]: #dnsresolvesrvhostname-callback
|
[`dns.resolveSrv()`]: #dnsresolvesrvhostname-callback
|
||||||
|
[`dns.resolveTlsa()`]: #dnsresolvetlsahostname-callback
|
||||||
[`dns.resolveTxt()`]: #dnsresolvetxthostname-callback
|
[`dns.resolveTxt()`]: #dnsresolvetxthostname-callback
|
||||||
[`dns.reverse()`]: #dnsreverseip-callback
|
[`dns.reverse()`]: #dnsreverseip-callback
|
||||||
[`dns.setDefaultResultOrder()`]: #dnssetdefaultresultorderorder
|
[`dns.setDefaultResultOrder()`]: #dnssetdefaultresultorderorder
|
||||||
@ -1676,6 +1746,7 @@ uses. For instance, they do not use the configuration from `/etc/hosts`.
|
|||||||
[`dnsPromises.resolvePtr()`]: #dnspromisesresolveptrhostname
|
[`dnsPromises.resolvePtr()`]: #dnspromisesresolveptrhostname
|
||||||
[`dnsPromises.resolveSoa()`]: #dnspromisesresolvesoahostname
|
[`dnsPromises.resolveSoa()`]: #dnspromisesresolvesoahostname
|
||||||
[`dnsPromises.resolveSrv()`]: #dnspromisesresolvesrvhostname
|
[`dnsPromises.resolveSrv()`]: #dnspromisesresolvesrvhostname
|
||||||
|
[`dnsPromises.resolveTlsa()`]: #dnspromisesresolvetlsahostname
|
||||||
[`dnsPromises.resolveTxt()`]: #dnspromisesresolvetxthostname
|
[`dnsPromises.resolveTxt()`]: #dnspromisesresolvetxthostname
|
||||||
[`dnsPromises.reverse()`]: #dnspromisesreverseip
|
[`dnsPromises.reverse()`]: #dnspromisesreverseip
|
||||||
[`dnsPromises.setDefaultResultOrder()`]: #dnspromisessetdefaultresultorderorder
|
[`dnsPromises.setDefaultResultOrder()`]: #dnspromisessetdefaultresultorderorder
|
||||||
|
@ -235,6 +235,7 @@ const resolverKeys = [
|
|||||||
'resolvePtr',
|
'resolvePtr',
|
||||||
'resolveSoa',
|
'resolveSoa',
|
||||||
'resolveSrv',
|
'resolveSrv',
|
||||||
|
'resolveTlsa',
|
||||||
'resolveTxt',
|
'resolveTxt',
|
||||||
'reverse',
|
'reverse',
|
||||||
];
|
];
|
||||||
@ -300,6 +301,7 @@ function createResolverClass(resolver) {
|
|||||||
Resolver.prototype.resolveCname = resolveMap.CNAME = resolver('queryCname');
|
Resolver.prototype.resolveCname = resolveMap.CNAME = resolver('queryCname');
|
||||||
Resolver.prototype.resolveMx = resolveMap.MX = resolver('queryMx');
|
Resolver.prototype.resolveMx = resolveMap.MX = resolver('queryMx');
|
||||||
Resolver.prototype.resolveNs = resolveMap.NS = resolver('queryNs');
|
Resolver.prototype.resolveNs = resolveMap.NS = resolver('queryNs');
|
||||||
|
Resolver.prototype.resolveTlsa = resolveMap.TLSA = resolver('queryTlsa');
|
||||||
Resolver.prototype.resolveTxt = resolveMap.TXT = resolver('queryTxt');
|
Resolver.prototype.resolveTxt = resolveMap.TXT = resolver('queryTxt');
|
||||||
Resolver.prototype.resolveSrv = resolveMap.SRV = resolver('querySrv');
|
Resolver.prototype.resolveSrv = resolveMap.SRV = resolver('querySrv');
|
||||||
Resolver.prototype.resolvePtr = resolveMap.PTR = resolver('queryPtr');
|
Resolver.prototype.resolvePtr = resolveMap.PTR = resolver('queryPtr');
|
||||||
|
@ -40,6 +40,10 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
|
#ifndef T_TLSA
|
||||||
|
#define T_TLSA 52 /* TLSA certificate association */
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef T_CAA
|
#ifndef T_CAA
|
||||||
# define T_CAA 257 /* Certification Authority Authorization */
|
# define T_CAA 257 /* Certification Authority Authorization */
|
||||||
#endif
|
#endif
|
||||||
@ -57,6 +61,7 @@ namespace node {
|
|||||||
namespace cares_wrap {
|
namespace cares_wrap {
|
||||||
|
|
||||||
using v8::Array;
|
using v8::Array;
|
||||||
|
using v8::ArrayBuffer;
|
||||||
using v8::Context;
|
using v8::Context;
|
||||||
using v8::EscapableHandleScope;
|
using v8::EscapableHandleScope;
|
||||||
using v8::Exception;
|
using v8::Exception;
|
||||||
@ -352,6 +357,65 @@ int ParseCaaReply(
|
|||||||
return ARES_SUCCESS;
|
return ARES_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ParseTlsaReply(Environment* env,
|
||||||
|
unsigned char* buf,
|
||||||
|
int len,
|
||||||
|
Local<Array> ret) {
|
||||||
|
EscapableHandleScope handle_scope(env->isolate());
|
||||||
|
|
||||||
|
ares_dns_record_t* dnsrec = nullptr;
|
||||||
|
|
||||||
|
int status = ares_dns_parse(buf, len, 0, &dnsrec);
|
||||||
|
if (status != ARES_SUCCESS) {
|
||||||
|
ares_dns_record_destroy(dnsrec);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t offset = ret->Length();
|
||||||
|
size_t rr_count = ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < rr_count; i++) {
|
||||||
|
const ares_dns_rr_t* rr =
|
||||||
|
ares_dns_record_rr_get(dnsrec, ARES_SECTION_ANSWER, i);
|
||||||
|
|
||||||
|
if (ares_dns_rr_get_type(rr) != ARES_REC_TYPE_TLSA) continue;
|
||||||
|
|
||||||
|
unsigned char certusage = ares_dns_rr_get_u8(rr, ARES_RR_TLSA_CERT_USAGE);
|
||||||
|
unsigned char selector = ares_dns_rr_get_u8(rr, ARES_RR_TLSA_SELECTOR);
|
||||||
|
unsigned char match = ares_dns_rr_get_u8(rr, ARES_RR_TLSA_MATCH);
|
||||||
|
size_t data_len;
|
||||||
|
const unsigned char* data =
|
||||||
|
ares_dns_rr_get_bin(rr, ARES_RR_TLSA_DATA, &data_len);
|
||||||
|
if (!data || data_len == 0) continue;
|
||||||
|
|
||||||
|
Local<ArrayBuffer> data_ab = ArrayBuffer::New(env->isolate(), data_len);
|
||||||
|
memcpy(data_ab->Data(), data, data_len);
|
||||||
|
|
||||||
|
Local<Object> tlsa_rec = Object::New(env->isolate());
|
||||||
|
tlsa_rec
|
||||||
|
->Set(env->context(),
|
||||||
|
env->cert_usage_string(),
|
||||||
|
Integer::NewFromUnsigned(env->isolate(), certusage))
|
||||||
|
.Check();
|
||||||
|
tlsa_rec
|
||||||
|
->Set(env->context(),
|
||||||
|
env->selector_string(),
|
||||||
|
Integer::NewFromUnsigned(env->isolate(), selector))
|
||||||
|
.Check();
|
||||||
|
tlsa_rec
|
||||||
|
->Set(env->context(),
|
||||||
|
env->match_string(),
|
||||||
|
Integer::NewFromUnsigned(env->isolate(), match))
|
||||||
|
.Check();
|
||||||
|
tlsa_rec->Set(env->context(), env->data_string(), data_ab).Check();
|
||||||
|
|
||||||
|
ret->Set(env->context(), offset + i, tlsa_rec).Check();
|
||||||
|
}
|
||||||
|
|
||||||
|
ares_dns_record_destroy(dnsrec);
|
||||||
|
return ARES_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
int ParseTxtReply(
|
int ParseTxtReply(
|
||||||
Environment* env,
|
Environment* env,
|
||||||
const unsigned char* buf,
|
const unsigned char* buf,
|
||||||
@ -861,6 +925,11 @@ int NsTraits::Send(QueryWrap<NsTraits>* wrap, const char* name) {
|
|||||||
return ARES_SUCCESS;
|
return ARES_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int TlsaTraits::Send(QueryWrap<TlsaTraits>* wrap, const char* name) {
|
||||||
|
wrap->AresQuery(name, ARES_CLASS_IN, ARES_REC_TYPE_TLSA);
|
||||||
|
return ARES_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
int TxtTraits::Send(QueryWrap<TxtTraits>* wrap, const char* name) {
|
int TxtTraits::Send(QueryWrap<TxtTraits>* wrap, const char* name) {
|
||||||
wrap->AresQuery(name, ARES_CLASS_IN, ARES_REC_TYPE_TXT);
|
wrap->AresQuery(name, ARES_CLASS_IN, ARES_REC_TYPE_TXT);
|
||||||
return ARES_SUCCESS;
|
return ARES_SUCCESS;
|
||||||
@ -1045,6 +1114,10 @@ int AnyTraits::Parse(
|
|||||||
if (!soa_record.IsEmpty())
|
if (!soa_record.IsEmpty())
|
||||||
ret->Set(env->context(), ret->Length(), soa_record).Check();
|
ret->Set(env->context(), ret->Length(), soa_record).Check();
|
||||||
|
|
||||||
|
/* Parse TLSA records */
|
||||||
|
status = ParseTlsaReply(env, buf, len, ret);
|
||||||
|
if (status != ARES_SUCCESS && status != ARES_ENODATA) return status;
|
||||||
|
|
||||||
/* Parse CAA records */
|
/* Parse CAA records */
|
||||||
status = ParseCaaReply(env, buf, len, ret, true);
|
status = ParseCaaReply(env, buf, len, ret, true);
|
||||||
if (status != ARES_SUCCESS && status != ARES_ENODATA)
|
if (status != ARES_SUCCESS && status != ARES_ENODATA)
|
||||||
@ -1219,6 +1292,27 @@ int NsTraits::Parse(
|
|||||||
return ARES_SUCCESS;
|
return ARES_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int TlsaTraits::Parse(QueryTlsaWrap* wrap,
|
||||||
|
const std::unique_ptr<ResponseData>& response) {
|
||||||
|
if (response->is_host) [[unlikely]] {
|
||||||
|
return ARES_EBADRESP;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char* buf = response->buf.data;
|
||||||
|
int len = response->buf.size;
|
||||||
|
|
||||||
|
Environment* env = wrap->env();
|
||||||
|
HandleScope handle_scope(env->isolate());
|
||||||
|
Context::Scope context_scope(env->context());
|
||||||
|
|
||||||
|
Local<Array> tlsa_records = Array::New(env->isolate());
|
||||||
|
int status = ParseTlsaReply(env, buf, len, tlsa_records);
|
||||||
|
if (status != ARES_SUCCESS) return status;
|
||||||
|
|
||||||
|
wrap->CallOnComplete(tlsa_records);
|
||||||
|
return ARES_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
int TxtTraits::Parse(
|
int TxtTraits::Parse(
|
||||||
QueryTxtWrap* wrap,
|
QueryTxtWrap* wrap,
|
||||||
const std::unique_ptr<ResponseData>& response) {
|
const std::unique_ptr<ResponseData>& response) {
|
||||||
@ -1998,6 +2092,7 @@ void Initialize(Local<Object> target,
|
|||||||
SetProtoMethod(isolate, channel_wrap, "queryCname", Query<QueryCnameWrap>);
|
SetProtoMethod(isolate, channel_wrap, "queryCname", Query<QueryCnameWrap>);
|
||||||
SetProtoMethod(isolate, channel_wrap, "queryMx", Query<QueryMxWrap>);
|
SetProtoMethod(isolate, channel_wrap, "queryMx", Query<QueryMxWrap>);
|
||||||
SetProtoMethod(isolate, channel_wrap, "queryNs", Query<QueryNsWrap>);
|
SetProtoMethod(isolate, channel_wrap, "queryNs", Query<QueryNsWrap>);
|
||||||
|
SetProtoMethod(isolate, channel_wrap, "queryTlsa", Query<QueryTlsaWrap>);
|
||||||
SetProtoMethod(isolate, channel_wrap, "queryTxt", Query<QueryTxtWrap>);
|
SetProtoMethod(isolate, channel_wrap, "queryTxt", Query<QueryTxtWrap>);
|
||||||
SetProtoMethod(isolate, channel_wrap, "querySrv", Query<QuerySrvWrap>);
|
SetProtoMethod(isolate, channel_wrap, "querySrv", Query<QuerySrvWrap>);
|
||||||
SetProtoMethod(isolate, channel_wrap, "queryPtr", Query<QueryPtrWrap>);
|
SetProtoMethod(isolate, channel_wrap, "queryPtr", Query<QueryPtrWrap>);
|
||||||
@ -2029,6 +2124,7 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
|
|||||||
registry->Register(Query<QueryCnameWrap>);
|
registry->Register(Query<QueryCnameWrap>);
|
||||||
registry->Register(Query<QueryMxWrap>);
|
registry->Register(Query<QueryMxWrap>);
|
||||||
registry->Register(Query<QueryNsWrap>);
|
registry->Register(Query<QueryNsWrap>);
|
||||||
|
registry->Register(Query<QueryTlsaWrap>);
|
||||||
registry->Register(Query<QueryTxtWrap>);
|
registry->Register(Query<QueryTxtWrap>);
|
||||||
registry->Register(Query<QuerySrvWrap>);
|
registry->Register(Query<QuerySrvWrap>);
|
||||||
registry->Register(Query<QueryPtrWrap>);
|
registry->Register(Query<QueryPtrWrap>);
|
||||||
|
@ -460,6 +460,13 @@ struct NsTraits final {
|
|||||||
const std::unique_ptr<ResponseData>& response);
|
const std::unique_ptr<ResponseData>& response);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TlsaTraits final {
|
||||||
|
static constexpr const char* name = "resolveTlsa";
|
||||||
|
static int Send(QueryWrap<TlsaTraits>* wrap, const char* name);
|
||||||
|
static int Parse(QueryWrap<TlsaTraits>* wrap,
|
||||||
|
const std::unique_ptr<ResponseData>& response);
|
||||||
|
};
|
||||||
|
|
||||||
struct TxtTraits final {
|
struct TxtTraits final {
|
||||||
static constexpr const char* name = "resolveTxt";
|
static constexpr const char* name = "resolveTxt";
|
||||||
static int Send(QueryWrap<TxtTraits>* wrap, const char* name);
|
static int Send(QueryWrap<TxtTraits>* wrap, const char* name);
|
||||||
@ -515,6 +522,7 @@ using QueryCaaWrap = QueryWrap<CaaTraits>;
|
|||||||
using QueryCnameWrap = QueryWrap<CnameTraits>;
|
using QueryCnameWrap = QueryWrap<CnameTraits>;
|
||||||
using QueryMxWrap = QueryWrap<MxTraits>;
|
using QueryMxWrap = QueryWrap<MxTraits>;
|
||||||
using QueryNsWrap = QueryWrap<NsTraits>;
|
using QueryNsWrap = QueryWrap<NsTraits>;
|
||||||
|
using QueryTlsaWrap = QueryWrap<TlsaTraits>;
|
||||||
using QueryTxtWrap = QueryWrap<TxtTraits>;
|
using QueryTxtWrap = QueryWrap<TxtTraits>;
|
||||||
using QuerySrvWrap = QueryWrap<SrvTraits>;
|
using QuerySrvWrap = QueryWrap<SrvTraits>;
|
||||||
using QueryPtrWrap = QueryWrap<PtrTraits>;
|
using QueryPtrWrap = QueryWrap<PtrTraits>;
|
||||||
|
@ -91,6 +91,7 @@
|
|||||||
V(cached_data_rejected_string, "cachedDataRejected") \
|
V(cached_data_rejected_string, "cachedDataRejected") \
|
||||||
V(cached_data_string, "cachedData") \
|
V(cached_data_string, "cachedData") \
|
||||||
V(cache_key_string, "cacheKey") \
|
V(cache_key_string, "cacheKey") \
|
||||||
|
V(cert_usage_string, "certUsage") \
|
||||||
V(change_string, "change") \
|
V(change_string, "change") \
|
||||||
V(changes_string, "changes") \
|
V(changes_string, "changes") \
|
||||||
V(channel_string, "channel") \
|
V(channel_string, "channel") \
|
||||||
@ -135,6 +136,7 @@
|
|||||||
V(dns_ptr_string, "PTR") \
|
V(dns_ptr_string, "PTR") \
|
||||||
V(dns_soa_string, "SOA") \
|
V(dns_soa_string, "SOA") \
|
||||||
V(dns_srv_string, "SRV") \
|
V(dns_srv_string, "SRV") \
|
||||||
|
V(dns_tlsa_string, "TLSA") \
|
||||||
V(dns_txt_string, "TXT") \
|
V(dns_txt_string, "TXT") \
|
||||||
V(done_string, "done") \
|
V(done_string, "done") \
|
||||||
V(duration_string, "duration") \
|
V(duration_string, "duration") \
|
||||||
@ -237,6 +239,7 @@
|
|||||||
V(line_number_string, "lineNumber") \
|
V(line_number_string, "lineNumber") \
|
||||||
V(loop_count, "loopCount") \
|
V(loop_count, "loopCount") \
|
||||||
V(mac_string, "mac") \
|
V(mac_string, "mac") \
|
||||||
|
V(match_string, "match") \
|
||||||
V(max_buffer_string, "maxBuffer") \
|
V(max_buffer_string, "maxBuffer") \
|
||||||
V(max_concurrent_streams_string, "maxConcurrentStreams") \
|
V(max_concurrent_streams_string, "maxConcurrentStreams") \
|
||||||
V(message_port_constructor_string, "MessagePort") \
|
V(message_port_constructor_string, "MessagePort") \
|
||||||
@ -336,6 +339,7 @@
|
|||||||
V(script_id_string, "scriptId") \
|
V(script_id_string, "scriptId") \
|
||||||
V(script_name_string, "scriptName") \
|
V(script_name_string, "scriptName") \
|
||||||
V(search_string, "search") \
|
V(search_string, "search") \
|
||||||
|
V(selector_string, "selector") \
|
||||||
V(serial_number_string, "serialNumber") \
|
V(serial_number_string, "serialNumber") \
|
||||||
V(serial_string, "serial") \
|
V(serial_string, "serial") \
|
||||||
V(servername_string, "servername") \
|
V(servername_string, "servername") \
|
||||||
|
@ -38,6 +38,8 @@ const addresses = {
|
|||||||
CNAME_HOST: 'blog.nodejs.org',
|
CNAME_HOST: 'blog.nodejs.org',
|
||||||
// A host with NS records registered
|
// A host with NS records registered
|
||||||
NS_HOST: 'nodejs.org',
|
NS_HOST: 'nodejs.org',
|
||||||
|
// A host with TLSA records registered
|
||||||
|
TLSA_HOST: '_443._tcp.fedoraproject.org',
|
||||||
// A host with TXT records registered
|
// A host with TXT records registered
|
||||||
TXT_HOST: 'nodejs.org',
|
TXT_HOST: 'nodejs.org',
|
||||||
// An accessible IPv4 DNS server
|
// An accessible IPv4 DNS server
|
||||||
|
@ -11,6 +11,7 @@ const methods = [
|
|||||||
'resolveCname',
|
'resolveCname',
|
||||||
'resolveMx',
|
'resolveMx',
|
||||||
'resolveNs',
|
'resolveNs',
|
||||||
|
'resolveTlsa',
|
||||||
'resolveTxt',
|
'resolveTxt',
|
||||||
'resolveSrv',
|
'resolveSrv',
|
||||||
'resolvePtr',
|
'resolvePtr',
|
||||||
|
@ -479,6 +479,47 @@ TEST(function test_resolveCname_failure(done) {
|
|||||||
checkWrap(req);
|
checkWrap(req);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
TEST(async function test_resolveTlsa(done) {
|
||||||
|
function validateResult(result) {
|
||||||
|
assert.ok(Array.isArray(result));
|
||||||
|
assert.ok(result.length >= 1);
|
||||||
|
for (const record of result) {
|
||||||
|
assert.strictEqual(typeof record.certUsage, 'number');
|
||||||
|
assert.strictEqual(typeof record.selector, 'number');
|
||||||
|
assert.strictEqual(typeof record.match, 'number');
|
||||||
|
assert.ok(record.data instanceof ArrayBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validateResult(await dnsPromises.resolveTlsa(addresses.TLSA_HOST));
|
||||||
|
|
||||||
|
const req = dns.resolveTlsa(addresses.TLSA_HOST, function(err, records) {
|
||||||
|
assert.ifError(err);
|
||||||
|
validateResult(records);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
checkWrap(req);
|
||||||
|
});
|
||||||
|
|
||||||
|
TEST(function test_resolveTlsa_failure(done) {
|
||||||
|
dnsPromises.resolveTlsa(addresses.NOT_FOUND)
|
||||||
|
.then(common.mustNotCall())
|
||||||
|
.catch(common.mustCall((err) => {
|
||||||
|
assert.strictEqual(err.code, 'ENOTFOUND');
|
||||||
|
}));
|
||||||
|
|
||||||
|
const req = dns.resolveTlsa(addresses.NOT_FOUND, function(err, result) {
|
||||||
|
assert.ok(err instanceof Error);
|
||||||
|
assert.strictEqual(err.code, 'ENOTFOUND');
|
||||||
|
|
||||||
|
assert.strictEqual(result, undefined);
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
checkWrap(req);
|
||||||
|
});
|
||||||
|
|
||||||
TEST(async function test_resolveTxt(done) {
|
TEST(async function test_resolveTxt(done) {
|
||||||
function validateResult(result) {
|
function validateResult(result) {
|
||||||
|
@ -34,6 +34,7 @@ const tests = {
|
|||||||
'resolveCname': 'dns.resolveCname("example.com", (err, res) => {});',
|
'resolveCname': 'dns.resolveCname("example.com", (err, res) => {});',
|
||||||
'resolveMx': 'dns.resolveMx("example.com", (err, res) => {});',
|
'resolveMx': 'dns.resolveMx("example.com", (err, res) => {});',
|
||||||
'resolveNs': 'dns.resolveNs("example.com", (err, res) => {});',
|
'resolveNs': 'dns.resolveNs("example.com", (err, res) => {});',
|
||||||
|
'resolveTlsa': 'dns.resolveTlsa("example.com", (err, res) => {});',
|
||||||
'resolveTxt': 'dns.resolveTxt("example.com", (err, res) => {});',
|
'resolveTxt': 'dns.resolveTxt("example.com", (err, res) => {});',
|
||||||
'resolveSrv': 'dns.resolveSrv("example.com", (err, res) => {});',
|
'resolveSrv': 'dns.resolveSrv("example.com", (err, res) => {});',
|
||||||
'resolvePtr': 'dns.resolvePtr("example.com", (err, res) => {});',
|
'resolvePtr': 'dns.resolvePtr("example.com", (err, res) => {});',
|
||||||
|
Loading…
Reference in New Issue
Block a user