mirror of
https://github.com/denoland/deno.git
synced 2024-11-24 15:19:26 -05:00
feat(ext/net): add support for SOA records in Deno.resolveDns() API (#14534)
This commit is contained in:
parent
f82a79ffdb
commit
bd4256262a
7 changed files with 110 additions and 158 deletions
|
@ -31,6 +31,7 @@ const UNSTABLE_DENO_PROPS: &[&str] = &[
|
|||
"Metrics",
|
||||
"OpMetrics",
|
||||
"RecordType",
|
||||
"SOARecord",
|
||||
"SRVRecord",
|
||||
"SetRawOptions",
|
||||
"SignalStream",
|
||||
|
|
13
cli/dts/lib.deno.ns.d.ts
vendored
13
cli/dts/lib.deno.ns.d.ts
vendored
|
@ -2957,6 +2957,7 @@ declare namespace Deno {
|
|||
| "MX"
|
||||
| "NS"
|
||||
| "PTR"
|
||||
| "SOA"
|
||||
| "SRV"
|
||||
| "TXT";
|
||||
|
||||
|
@ -2978,6 +2979,12 @@ declare namespace Deno {
|
|||
exchange: string;
|
||||
}
|
||||
|
||||
/** If `resolveDns` is called with "SOA" record type specified, it will return an array of this interface. */
|
||||
export interface SOARecord {
|
||||
mname: string;
|
||||
rname: string;
|
||||
}
|
||||
|
||||
/** If `resolveDns` is called with "SRV" record type specified, it will return an array of this interface. */
|
||||
export interface SRVRecord {
|
||||
priority: number;
|
||||
|
@ -2998,6 +3005,12 @@ declare namespace Deno {
|
|||
options?: ResolveDnsOptions,
|
||||
): Promise<MXRecord[]>;
|
||||
|
||||
export function resolveDns(
|
||||
query: string,
|
||||
recordType: "SOA",
|
||||
options?: ResolveDnsOptions,
|
||||
): Promise<SOARecord[]>;
|
||||
|
||||
export function resolveDns(
|
||||
query: string,
|
||||
recordType: "SRV",
|
||||
|
|
|
@ -15,6 +15,8 @@ use std::sync::Arc;
|
|||
use test_util as util;
|
||||
use test_util::TempDir;
|
||||
use tokio::task::LocalSet;
|
||||
use trust_dns_client::serialize::txt::Lexer;
|
||||
use trust_dns_client::serialize::txt::Parser;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! itest(
|
||||
|
@ -811,9 +813,6 @@ fn set_raw_should_not_panic_on_no_tty() {
|
|||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_resolve_dns() {
|
||||
use std::collections::BTreeMap;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::net::Ipv6Addr;
|
||||
use std::net::SocketAddr;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
@ -821,19 +820,9 @@ async fn test_resolve_dns() {
|
|||
use tokio::net::TcpListener;
|
||||
use tokio::net::UdpSocket;
|
||||
use tokio::sync::oneshot;
|
||||
use trust_dns_client::rr::LowerName;
|
||||
use trust_dns_client::rr::RecordType;
|
||||
use trust_dns_client::rr::RrKey;
|
||||
use trust_dns_server::authority::Catalog;
|
||||
use trust_dns_server::authority::ZoneType;
|
||||
use trust_dns_server::proto::rr::rdata::mx::MX;
|
||||
use trust_dns_server::proto::rr::rdata::soa::SOA;
|
||||
use trust_dns_server::proto::rr::rdata::srv::SRV;
|
||||
use trust_dns_server::proto::rr::rdata::txt::TXT;
|
||||
use trust_dns_server::proto::rr::record_data::RData;
|
||||
use trust_dns_server::proto::rr::resource::Record;
|
||||
use trust_dns_server::proto::rr::Name;
|
||||
use trust_dns_server::proto::rr::RecordSet;
|
||||
use trust_dns_server::store::in_memory::InMemoryAuthority;
|
||||
use trust_dns_server::ServerFuture;
|
||||
|
||||
|
@ -841,137 +830,25 @@ async fn test_resolve_dns() {
|
|||
|
||||
// Setup DNS server for testing
|
||||
async fn run_dns_server(tx: oneshot::Sender<()>) {
|
||||
let catalog = {
|
||||
let records = {
|
||||
let mut map = BTreeMap::new();
|
||||
let lookup_name = "www.example.com".parse::<Name>().unwrap();
|
||||
let lookup_name_lower = LowerName::new(&lookup_name);
|
||||
|
||||
// Inserts SOA record
|
||||
let soa = SOA::new(
|
||||
Name::from_str("net").unwrap(),
|
||||
Name::from_str("example").unwrap(),
|
||||
0,
|
||||
i32::MAX,
|
||||
i32::MAX,
|
||||
i32::MAX,
|
||||
0,
|
||||
);
|
||||
let rdata = RData::SOA(soa);
|
||||
let record = Record::from_rdata(Name::new(), u32::MAX, rdata);
|
||||
let record_set = RecordSet::from(record);
|
||||
map
|
||||
.insert(RrKey::new(Name::root().into(), RecordType::SOA), record_set);
|
||||
|
||||
// Inserts A record
|
||||
let rdata = RData::A(Ipv4Addr::new(1, 2, 3, 4));
|
||||
let record = Record::from_rdata(lookup_name.clone(), u32::MAX, rdata);
|
||||
let record_set = RecordSet::from(record);
|
||||
map.insert(
|
||||
RrKey::new(lookup_name_lower.clone(), RecordType::A),
|
||||
record_set,
|
||||
);
|
||||
|
||||
// Inserts AAAA record
|
||||
let rdata = RData::AAAA(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8));
|
||||
let record = Record::from_rdata(lookup_name.clone(), u32::MAX, rdata);
|
||||
let record_set = RecordSet::from(record);
|
||||
map.insert(
|
||||
RrKey::new(lookup_name_lower.clone(), RecordType::AAAA),
|
||||
record_set,
|
||||
);
|
||||
|
||||
// Inserts ANAME record
|
||||
let rdata = RData::ANAME(Name::from_str("aname.com").unwrap());
|
||||
let record = Record::from_rdata(lookup_name.clone(), u32::MAX, rdata);
|
||||
let record_set = RecordSet::from(record);
|
||||
map.insert(
|
||||
RrKey::new(lookup_name_lower.clone(), RecordType::ANAME),
|
||||
record_set,
|
||||
);
|
||||
|
||||
// Inserts CNAME record
|
||||
let rdata = RData::CNAME(Name::from_str("cname.com").unwrap());
|
||||
let record =
|
||||
Record::from_rdata(Name::from_str("foo").unwrap(), u32::MAX, rdata);
|
||||
let record_set = RecordSet::from(record);
|
||||
map.insert(
|
||||
RrKey::new(lookup_name_lower.clone(), RecordType::CNAME),
|
||||
record_set,
|
||||
);
|
||||
|
||||
// Inserts MX record
|
||||
let rdata = RData::MX(MX::new(0, Name::from_str("mx.com").unwrap()));
|
||||
let record = Record::from_rdata(lookup_name.clone(), u32::MAX, rdata);
|
||||
let record_set = RecordSet::from(record);
|
||||
map.insert(
|
||||
RrKey::new(lookup_name_lower.clone(), RecordType::MX),
|
||||
record_set,
|
||||
);
|
||||
|
||||
// Inserts NS record
|
||||
let rdata = RData::NS(Name::from_str("ns1.ns.com").unwrap());
|
||||
let record = Record::from_rdata(lookup_name.clone(), u32::MAX, rdata);
|
||||
let record_set = RecordSet::from(record);
|
||||
map.insert(
|
||||
RrKey::new(lookup_name_lower.clone(), RecordType::NS),
|
||||
record_set,
|
||||
);
|
||||
|
||||
// Inserts PTR record
|
||||
let rdata = RData::PTR(Name::from_str("ptr.com").unwrap());
|
||||
let record = Record::from_rdata(
|
||||
Name::from_str("5.6.7.8").unwrap(),
|
||||
u32::MAX,
|
||||
rdata,
|
||||
);
|
||||
let record_set = RecordSet::from(record);
|
||||
map.insert(
|
||||
RrKey::new("5.6.7.8".parse().unwrap(), RecordType::PTR),
|
||||
record_set,
|
||||
);
|
||||
|
||||
// Inserts SRV record
|
||||
let rdata = RData::SRV(SRV::new(
|
||||
0,
|
||||
100,
|
||||
1234,
|
||||
Name::from_str("srv.com").unwrap(),
|
||||
));
|
||||
let record = Record::from_rdata(
|
||||
Name::from_str("_Service._TCP.example.com").unwrap(),
|
||||
u32::MAX,
|
||||
rdata,
|
||||
);
|
||||
let record_set = RecordSet::from(record);
|
||||
map.insert(
|
||||
RrKey::new(lookup_name_lower.clone(), RecordType::SRV),
|
||||
record_set,
|
||||
);
|
||||
|
||||
// Inserts TXT record
|
||||
let rdata =
|
||||
RData::TXT(TXT::new(vec!["foo".to_string(), "bar".to_string()]));
|
||||
let record = Record::from_rdata(lookup_name, u32::MAX, rdata);
|
||||
let record_set = RecordSet::from(record);
|
||||
map.insert(RrKey::new(lookup_name_lower, RecordType::TXT), record_set);
|
||||
|
||||
map
|
||||
};
|
||||
|
||||
let authority = Box::new(Arc::new(
|
||||
InMemoryAuthority::new(
|
||||
Name::from_str("com").unwrap(),
|
||||
records,
|
||||
ZoneType::Primary,
|
||||
false,
|
||||
)
|
||||
let zone_file =
|
||||
fs::read_to_string(util::testdata_path().join("resolve_dns.zone.in"))
|
||||
.unwrap();
|
||||
let lexer = Lexer::new(&zone_file);
|
||||
let records = Parser::new().parse(
|
||||
lexer,
|
||||
Some(Name::from_str("example.com").unwrap()),
|
||||
None,
|
||||
);
|
||||
if records.is_err() {
|
||||
panic!("failed to parse: {:?}", records.err())
|
||||
}
|
||||
let (origin, records) = records.unwrap();
|
||||
let authority = Box::new(Arc::new(
|
||||
InMemoryAuthority::new(origin, records, ZoneType::Primary, false)
|
||||
.unwrap(),
|
||||
));
|
||||
let mut c = Catalog::new();
|
||||
c.upsert(Name::root().into(), authority);
|
||||
c
|
||||
};
|
||||
));
|
||||
let mut catalog: Catalog = Catalog::new();
|
||||
catalog.upsert(Name::root().into(), authority);
|
||||
|
||||
let mut server_fut = ServerFuture::new(catalog);
|
||||
let socket_addr = SocketAddr::from(([127, 0, 0, 1], DNS_PORT));
|
||||
|
@ -1011,6 +888,7 @@ async fn test_resolve_dns() {
|
|||
.unwrap();
|
||||
let err = String::from_utf8_lossy(&output.stderr);
|
||||
let out = String::from_utf8_lossy(&output.stdout);
|
||||
println!("{}", err);
|
||||
assert!(output.status.success());
|
||||
assert!(err.starts_with("Check file"));
|
||||
|
||||
|
|
18
cli/tests/testdata/resolve_dns.ts
vendored
18
cli/tests/testdata/resolve_dns.ts
vendored
|
@ -1,15 +1,16 @@
|
|||
const nameServer = { nameServer: { ipAddr: "127.0.0.1", port: 4553 } };
|
||||
|
||||
const [a, aaaa, aname, cname, mx, ns, ptr, srv, txt] = await Promise.all([
|
||||
const [a, aaaa, aname, cname, mx, ns, ptr, soa, srv, txt] = await Promise.all([
|
||||
Deno.resolveDns("www.example.com", "A", nameServer),
|
||||
Deno.resolveDns("www.example.com", "AAAA", nameServer),
|
||||
Deno.resolveDns("www.example.com", "ANAME", nameServer),
|
||||
Deno.resolveDns("foo", "CNAME", nameServer),
|
||||
Deno.resolveDns("www.example.com", "MX", nameServer),
|
||||
Deno.resolveDns("www.example.com", "NS", nameServer),
|
||||
Deno.resolveDns("5.6.7.8", "PTR", nameServer),
|
||||
Deno.resolveDns("_Service._TCP.example.com", "SRV", nameServer),
|
||||
Deno.resolveDns("www.example.com", "TXT", nameServer),
|
||||
Deno.resolveDns("alias.example.com", "CNAME", nameServer),
|
||||
Deno.resolveDns("example.com", "MX", nameServer),
|
||||
Deno.resolveDns("example.com", "NS", nameServer),
|
||||
Deno.resolveDns("1.2.3.4.IN-ADDR.ARPA.", "PTR", nameServer),
|
||||
Deno.resolveDns("example.com", "SOA", nameServer),
|
||||
Deno.resolveDns("_service._tcp.example.com", "SRV", nameServer),
|
||||
Deno.resolveDns("example.com", "TXT", nameServer),
|
||||
]);
|
||||
|
||||
console.log("A");
|
||||
|
@ -33,6 +34,9 @@ console.log(JSON.stringify(ns));
|
|||
console.log("PTR");
|
||||
console.log(JSON.stringify(ptr));
|
||||
|
||||
console.log("SOA");
|
||||
console.log(JSON.stringify(soa));
|
||||
|
||||
console.log("SRV");
|
||||
console.log(JSON.stringify(srv));
|
||||
|
||||
|
|
18
cli/tests/testdata/resolve_dns.ts.out
vendored
18
cli/tests/testdata/resolve_dns.ts.out
vendored
|
@ -1,19 +1,21 @@
|
|||
A
|
||||
["1.2.3.4"]
|
||||
["1.2.3.4","5.6.7.8"]
|
||||
AAAA
|
||||
["1:2:3:4:5:6:7:8"]
|
||||
ANAME
|
||||
["aname.com."]
|
||||
["aname.example.com."]
|
||||
CNAME
|
||||
["cname.com."]
|
||||
["cname.example.com."]
|
||||
MX
|
||||
[{"preference":0,"exchange":"mx.com."}]
|
||||
[{"preference":10,"exchange":"mx1.com."},{"preference":20,"exchange":"mx2.com."}]
|
||||
NS
|
||||
["ns1.ns.com."]
|
||||
["ns1.ns.com.","ns2.ns.com.","ns3.ns.com."]
|
||||
PTR
|
||||
["ptr.com."]
|
||||
["www.example.com.","alias.example.com."]
|
||||
SOA
|
||||
[{"mname":"net.example.com.","rname":"admin\\.domain.example.com."}]
|
||||
SRV
|
||||
[{"priority":0,"weight":100,"port":1234,"target":"srv.com."}]
|
||||
[{"priority":0,"weight":100,"port":1234,"target":"srv.example.com."}]
|
||||
TXT
|
||||
[["foo","bar"]]
|
||||
[["I","am","a","txt","record"],["I","am","another","txt","record"],["I am a different","txt record"],["key=val"]]
|
||||
Error NotFound thrown for not-found-example.com
|
||||
|
|
24
cli/tests/testdata/resolve_dns.zone.in
vendored
Normal file
24
cli/tests/testdata/resolve_dns.zone.in
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
@ IN SOA net admin\.domain (
|
||||
20 ; SERIAL
|
||||
7200 ; REFRESH
|
||||
600 ; RETRY
|
||||
3600000; EXPIRE
|
||||
60) ; MINIMUM
|
||||
NS ns1.ns.com.
|
||||
NS ns2.ns.com.
|
||||
NS ns3.ns.com.
|
||||
MX 10 mx1.com.
|
||||
MX 20 mx2.com.
|
||||
TXT I am a txt record
|
||||
TXT I am another txt record
|
||||
TXT "I am a different" "txt record"
|
||||
TXT key=val
|
||||
www A 1.2.3.4
|
||||
A 5.6.7.8
|
||||
ANAME aname
|
||||
www AAAA 1:2:3:4:5:6:7:8
|
||||
alias CNAME cname
|
||||
|
||||
1.2.3.4.IN-ADDR.ARPA. PTR www
|
||||
PTR alias
|
||||
_service._tcp SRV 0 100 1234 srv
|
|
@ -581,6 +581,10 @@ pub enum DnsReturnRecord {
|
|||
},
|
||||
Ns(String),
|
||||
Ptr(String),
|
||||
Soa {
|
||||
mname: String,
|
||||
rname: String,
|
||||
},
|
||||
Srv {
|
||||
priority: u16,
|
||||
weight: u16,
|
||||
|
@ -736,6 +740,10 @@ fn rdata_to_return_record(
|
|||
.as_ptr()
|
||||
.map(ToString::to_string)
|
||||
.map(DnsReturnRecord::Ptr),
|
||||
SOA => r.as_soa().map(|soa| DnsReturnRecord::Soa {
|
||||
mname: soa.mname().to_string(),
|
||||
rname: soa.rname().to_string(),
|
||||
}),
|
||||
SRV => r.as_srv().map(|srv| DnsReturnRecord::Srv {
|
||||
priority: srv.priority(),
|
||||
weight: srv.weight(),
|
||||
|
@ -772,6 +780,7 @@ mod tests {
|
|||
use trust_dns_proto::rr::rdata::mx::MX;
|
||||
use trust_dns_proto::rr::rdata::srv::SRV;
|
||||
use trust_dns_proto::rr::rdata::txt::TXT;
|
||||
use trust_dns_proto::rr::rdata::SOA;
|
||||
use trust_dns_proto::rr::record_data::RData;
|
||||
use trust_dns_proto::rr::Name;
|
||||
|
||||
|
@ -833,6 +842,27 @@ mod tests {
|
|||
assert_eq!(func(&rdata), Some(DnsReturnRecord::Ptr("".to_string())));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rdata_to_return_record_soa() {
|
||||
let func = rdata_to_return_record(RecordType::SOA);
|
||||
let rdata = RData::SOA(SOA::new(
|
||||
Name::new(),
|
||||
Name::new(),
|
||||
0,
|
||||
i32::MAX,
|
||||
i32::MAX,
|
||||
i32::MAX,
|
||||
0,
|
||||
));
|
||||
assert_eq!(
|
||||
func(&rdata),
|
||||
Some(DnsReturnRecord::Soa {
|
||||
mname: "".to_string(),
|
||||
rname: "".to_string()
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rdata_to_return_record_srv() {
|
||||
let func = rdata_to_return_record(RecordType::SRV);
|
||||
|
|
Loading…
Reference in a new issue