1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-26 00:59:24 -05:00

feat(ext/net): add support for SOA records in Deno.resolveDns() API (#14534)

This commit is contained in:
Thanapat Chotipun 2022-05-14 19:08:35 +07:00 committed by GitHub
parent f82a79ffdb
commit bd4256262a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 110 additions and 158 deletions

View file

@ -31,6 +31,7 @@ const UNSTABLE_DENO_PROPS: &[&str] = &[
"Metrics",
"OpMetrics",
"RecordType",
"SOARecord",
"SRVRecord",
"SetRawOptions",
"SignalStream",

View file

@ -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",

View file

@ -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"));

View file

@ -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));

View file

@ -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
View 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

View file

@ -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);