improve rdata deserialization support and better implemetation of get zones records
parent
1a238ea01f
commit
7155c1cc54
|
@ -710,6 +710,7 @@ dependencies = [
|
|||
name = "nomilo"
|
||||
version = "0.1.0-dev"
|
||||
dependencies = [
|
||||
"base64 0.13.0",
|
||||
"rocket",
|
||||
"rocket_contrib",
|
||||
"serde",
|
||||
|
|
|
@ -14,3 +14,4 @@ serde_json = "1.0"
|
|||
rocket = "0.4.7"
|
||||
rocket_contrib = { version = "0.4", default-features = false, features = ["json"]}
|
||||
toml = "0.5"
|
||||
base64 = "0.13.0"
|
||||
|
|
14
src/main.rs
14
src/main.rs
|
@ -19,11 +19,17 @@ fn zone_records(client: State<SyncClient<TcpClientConnection>>, zone: String) ->
|
|||
// TODO: Implement FromParam for Name
|
||||
let name = Name::from_str(&zone).unwrap();
|
||||
|
||||
// TODO: add support for all trust-dns record types
|
||||
// then use AXFR here and filter out dnssec related fields
|
||||
let response: DnsResponse = client.query(&name, DNSClass::IN, RecordType::AAAA).unwrap();
|
||||
let response: DnsResponse = client.query(&name, DNSClass::IN, RecordType::AXFR).unwrap();
|
||||
let answers: &[Record] = response.answers();
|
||||
let records: Vec<types::dns::Record> = answers.to_vec().into_iter().map(|record| record.into()).collect();
|
||||
let mut records: Vec<_> = answers.to_vec().into_iter()
|
||||
.map(|record| types::dns::Record::from(record))
|
||||
.filter(|record| match record.rdata {
|
||||
types::dns::RData::NULL { .. } | types::dns::RData::DNSSEC(_) => false,
|
||||
_ => true,
|
||||
}).collect();
|
||||
|
||||
// AXFR response ends with SOA, we remove it so it is not doubled in the response.
|
||||
records.pop();
|
||||
|
||||
Json(records)
|
||||
}
|
||||
|
|
164
src/types/dns.rs
164
src/types/dns.rs
|
@ -1,16 +1,11 @@
|
|||
use std::net::{Ipv6Addr, Ipv4Addr};
|
||||
use std::fmt;
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
use trust_dns_client::serialize::binary::BinEncoder;
|
||||
use base64;
|
||||
|
||||
pub mod trust_dns_types {
|
||||
pub use trust_dns_client::rr::rdata::{
|
||||
DNSSECRecordType, NULL,
|
||||
};
|
||||
pub use trust_dns_client::rr::{
|
||||
RecordType, RData, DNSClass, Record
|
||||
};
|
||||
pub use trust_dns_proto::rr::Name;
|
||||
}
|
||||
use super::trust_dns_types;
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub enum RecordType {
|
||||
|
@ -140,6 +135,7 @@ impl Into<trust_dns_types::RecordType> for RecordType {
|
|||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(tag = "Type")]
|
||||
#[serde(rename_all = "UPPERCASE")]
|
||||
pub enum RData {
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
A {
|
||||
|
@ -149,28 +145,61 @@ pub enum RData {
|
|||
AAAA {
|
||||
address: Ipv6Addr
|
||||
},
|
||||
ANAME(StringName),
|
||||
// CAA(CAA),
|
||||
CNAME(StringName),
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
CAA {
|
||||
issuer_critical: bool,
|
||||
value: String,
|
||||
property_tag: String,
|
||||
},
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
CNAME {
|
||||
target: String
|
||||
},
|
||||
// HINFO(HINFO),
|
||||
// HTTPS(SVCB),
|
||||
// MX(MX),
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
MX {
|
||||
preference: u16,
|
||||
mail_exchanger: String
|
||||
},
|
||||
// NAPTR(NAPTR),
|
||||
NULL(NULL),
|
||||
NS(StringName),
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
NULL {
|
||||
data: String
|
||||
},
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
NS {
|
||||
target: String
|
||||
},
|
||||
// OPENPGPKEY(OPENPGPKEY),
|
||||
// OPT(OPT),
|
||||
PTR(StringName),
|
||||
// SOA(SOA),
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
PTR {
|
||||
target: String
|
||||
},
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
SOA {
|
||||
master_server_name: String,
|
||||
maintainer_name: String,
|
||||
refresh: i32,
|
||||
retry: i32,
|
||||
expire: i32,
|
||||
minimum: u32,
|
||||
serial: u32
|
||||
},
|
||||
// SRV(SRV),
|
||||
// SSHFP(SSHFP),
|
||||
// SVCB(SVCB),
|
||||
// TLSA(TLSA),
|
||||
// TXT(TXT),
|
||||
// DNSSEC(DNSSECRData),
|
||||
|
||||
// TODO: Eventually allow deserialization of DNSSEC records
|
||||
#[serde(skip)]
|
||||
DNSSEC(trust_dns_types::DNSSECRData),
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
Unknown {
|
||||
code: u16,
|
||||
rdata: NULL,
|
||||
data: String,
|
||||
},
|
||||
// ZERO,
|
||||
}
|
||||
|
@ -180,33 +209,84 @@ impl From<trust_dns_types::RData> for RData {
|
|||
match rdata {
|
||||
trust_dns_types::RData::A(address) => RData::A { address },
|
||||
trust_dns_types::RData::AAAA(address) => RData::AAAA { address },
|
||||
_ => unimplemented!()
|
||||
// Still a draft, no iana number yet, I don't to put something that is not currently supported so that's why NULL and not unknown.
|
||||
// TODO: probably need better error here, I don't know what to do about that as this would require to change the From for something else.
|
||||
// (empty data because I'm lazy)
|
||||
trust_dns_types::RData::ANAME(_) => RData::NULL {
|
||||
data: String::new()
|
||||
},
|
||||
trust_dns_types::RData::CNAME(target) => RData::CNAME {
|
||||
target: target.to_utf8()
|
||||
},
|
||||
trust_dns_types::RData::CAA(caa) => RData::CAA {
|
||||
issuer_critical: caa.issuer_critical(),
|
||||
value: format!("{}", CAAValue(caa.value())),
|
||||
property_tag: caa.tag().as_str().to_string(),
|
||||
},
|
||||
trust_dns_types::RData::MX(mx) => RData::MX {
|
||||
preference: mx.preference(),
|
||||
mail_exchanger: mx.exchange().to_utf8()
|
||||
},
|
||||
trust_dns_types::RData::NULL(null) => RData::NULL {
|
||||
data: base64::encode(null.anything().map(|data| data.to_vec()).unwrap_or_default())
|
||||
},
|
||||
trust_dns_types::RData::NS(target) => RData::NS {
|
||||
target: target.to_utf8()
|
||||
},
|
||||
trust_dns_types::RData::PTR(target) => RData::PTR {
|
||||
target: target.to_utf8()
|
||||
},
|
||||
trust_dns_types::RData::SOA(soa) => RData::SOA {
|
||||
master_server_name: soa.mname().to_utf8(),
|
||||
maintainer_name: soa.rname().to_utf8(),
|
||||
refresh: soa.refresh(),
|
||||
retry: soa.retry(),
|
||||
expire: soa.expire(),
|
||||
minimum: soa.minimum(),
|
||||
serial: soa.serial()
|
||||
},
|
||||
trust_dns_types::RData::DNSSEC(data) => RData::DNSSEC(data),
|
||||
rdata => {
|
||||
let code = rdata.to_record_type().into();
|
||||
let mut data = Vec::new();
|
||||
let mut encoder = BinEncoder::new(&mut data);
|
||||
rdata.emit(&mut encoder).expect("could not encode data");
|
||||
|
||||
RData::Unknown {
|
||||
code,
|
||||
data: base64::encode(data),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CAAValue<'a>(&'a trust_dns_types::caa::Value);
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct StringName(String);
|
||||
// trust_dns Display implementation panics if no parameters
|
||||
// Implementation based on caa::emit_value
|
||||
// Also the quotes are strips to render in JSON
|
||||
impl<'a> fmt::Display for CAAValue<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
match self.0 {
|
||||
trust_dns_types::caa::Value::Issuer(name, parameters) => {
|
||||
|
||||
if let Some(name) = name {
|
||||
write!(f, "{}", name)?;
|
||||
}
|
||||
|
||||
impl From<trust_dns_types::Name> for StringName {
|
||||
fn from(name: trust_dns_types::Name) -> StringName {
|
||||
StringName(name.to_utf8())
|
||||
}
|
||||
}
|
||||
if name.is_none() && parameters.is_empty() {
|
||||
write!(f, ";")?;
|
||||
}
|
||||
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct NULL {
|
||||
pub anything: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl From<trust_dns_types::NULL> for NULL {
|
||||
fn from(null: trust_dns_types::NULL) -> NULL {
|
||||
NULL {
|
||||
anything: null.anything().map(|e| e.to_vec())
|
||||
for value in parameters {
|
||||
write!(f, "; {}", value)?;
|
||||
}
|
||||
}
|
||||
trust_dns_types::caa::Value::Url(url) => write!(f, "{}", url)?,
|
||||
trust_dns_types::caa::Value::Unknown(v) => write!(f, "{:?}", v)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,21 +317,21 @@ impl From<trust_dns_types::DNSClass> for DNSClass {
|
|||
#[derive(Deserialize, Serialize)]
|
||||
pub struct Record {
|
||||
#[serde(rename = "Name")]
|
||||
name: StringName,
|
||||
pub name: String,
|
||||
//#[serde(rename = "Type")]
|
||||
//rr_type: RecordType,
|
||||
#[serde(rename = "Class")]
|
||||
dns_class: DNSClass,
|
||||
pub dns_class: DNSClass,
|
||||
#[serde(rename = "TTL")]
|
||||
ttl: u32,
|
||||
pub ttl: u32,
|
||||
#[serde(flatten)]
|
||||
rdata: RData,
|
||||
pub rdata: RData,
|
||||
}
|
||||
|
||||
impl From<trust_dns_types::Record> for Record {
|
||||
fn from(record: trust_dns_types::Record) -> Record {
|
||||
Record {
|
||||
name: StringName(record.name().to_utf8()),
|
||||
name: record.name().to_utf8(),
|
||||
//rr_type: record.rr_type().into(),
|
||||
dns_class: record.dns_class().into(),
|
||||
ttl: record.ttl(),
|
||||
|
|
|
@ -1 +1,11 @@
|
|||
pub mod dns;
|
||||
|
||||
pub mod trust_dns_types {
|
||||
pub use trust_dns_client::rr::rdata::{
|
||||
DNSSECRecordType, NULL, caa, DNSSECRData
|
||||
};
|
||||
pub use trust_dns_client::rr::{
|
||||
RecordType, RData, DNSClass, Record
|
||||
};
|
||||
pub use trust_dns_proto::rr::Name;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue