use crate::common_types::*; use crate::errors::*; use std::net::{Ipv4Addr, Ipv6Addr}; use crate::ser::{packet::DnsPacketData, text::DnsTextData, RRData}; // unless otherwise documented, class should probably be IN (0x0001) // deriving RRData will add a unit test to make sure the type is // registered; there must be a records::types::$name `Type` constant // with the same name as the struct. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(IN)] pub struct A { pub addr: Ipv4Addr, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct NS { pub nsdname: DnsCompressedName, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct MD { pub madname: DnsCompressedName, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct MF { pub madname: DnsCompressedName, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct CNAME { pub cname: DnsCompressedName, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct SOA { pub mname: DnsCompressedName, pub rname: DnsCompressedName, pub serial: u32, pub refresh: u32, pub retry: u32, pub expire: u32, pub minimum: u32, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct MB { pub madname: DnsCompressedName, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct MG { pub mgmname: DnsCompressedName, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct MR { pub newname: DnsCompressedName, } // not allowed in zone files anyway, i.e. no text representation. // content not restricted either, just some bytes. no need to parse it, // generic representation should be just fine. // // #[RRClass(ANY)] // pub struct NULL; // text representation like: `WKS 127.0.0.1 TCP smtp http 110`. would // have to parse protocol and service names. // // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[RRClass(IN)] // pub struct WKS { // pub address: Ipv4Addr, // pub protocol: u8, // pub bitmap: ..., // remaining bytes // } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct PTR { pub ptrdname: DnsCompressedName, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct HINFO { pub cpu: ShortText, pub os: ShortText, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct MINFO { pub rmailbx: DnsCompressedName, pub emailbx: DnsCompressedName, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct MX { pub preference: u16, pub mxname: DnsCompressedName, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct TXT { pub text: LongText, } // end of RFC 1035: no DnsCompressedName below! #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct RP { pub mbox: DnsCanonicalName, pub txt: DnsCanonicalName, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct AFSDB { pub subtype: u16, pub hostname: DnsCanonicalName, } // https://tools.ietf.org/html/rfc1183#section-3.1 says "its format in // master files is a " which say nothing about the // binary encoding; later it says " is a string of decimal // digits", so it would seem that there is no length encoding or // restriction. // // wireshark and bind use though (bind also wants at // least 4 bytes in the field: probably due to "beginning with the 4 // digit DNIC"). // // #[RRClass(ANY)] // pub struct X25 { // pub psdn_address: ShortText, // } // #[RRClass(ANY)] // pub struct ISDN { // pub isdn_address: ShortText, // pub subaddress: Option, // } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct RT { pub preference: u16, pub intermediate: DnsCanonicalName, } // #[RRClass(ANY)] // pub struct NSAP; #[allow(non_camel_case_types)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRTypeName = "NSAP-PTR"] #[RRClass(ANY)] pub struct NSAP_PTR { pub owner: DnsCanonicalName, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct SIG { pub rr_type: Type, pub algorithm: DnsSecAlgorithm, pub labels: u8, // RFC says this can be omitted in text form if it is the same as // the TTL on the SIG record. not supported to be omitted here // (TODO?). pub original_ttl: OptionalTTL, pub signature_expiration: TimeStrict, pub signature_inception: TimeStrict, pub key_tag: u16, pub signers_name: DnsCanonicalName, pub signature: Base64RemainingBlob, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct KEY { pub flags: u16, pub protocol: DnskeyProtocol, pub algorithm: DnsSecAlgorithm, pub public_key: Base64RemainingBlob, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(IN)] pub struct PX { pub preference: u16, pub map822: DnsCanonicalName, pub mapx400: DnsCanonicalName, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] // not restricted in rfc 1712 pub struct GPOS { pub longitude: ShortText, pub latitude: ShortText, pub altitude: ShortText, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(IN)] pub struct AAAA { pub addr: Ipv6Addr, } pub use super::weird_structs::LOC; #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct NXT { pub next: DnsCanonicalName, pub types: NxtTypeBitmap, } // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[RRClass(?)] // pub struct EID; // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[RRClass(?)] // pub struct NIMLOC; #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(IN)] pub struct SRV { pub preference: u16, pub weight: u16, pub port: u16, pub target: DnsCanonicalName, } // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[RRClass(?)] // pub struct ATMA; #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct NAPTR { pub order: u16, pub preference: u16, pub flags: ShortText, pub service: ShortText, pub regexp: ShortText, pub replacement: DnsCanonicalName, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(IN)] pub struct KX { pub preference: u16, pub exchanger: DnsCanonicalName, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[RRClass(?)] pub struct CERT { // https://www.iana.org/assignments/cert-rr-types/cert-rr-types.xhtml pub cert_type: u16, pub key_tag: u16, pub algorithm: DnsSecAlgorithm, pub certificate: Base64RemainingBlob, } pub use super::weird_structs::A6; #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct DNAME { pub target: DnsCanonicalName, } // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[RRClass(?)] // pub struct SINK; // OPT should be decoded at "transport level", abuses ttl and class // fields too. // pub struct OPT; // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[RRClass(?)] // pub struct APL; #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct DS { pub key_tag: u16, pub algorithm: DnsSecAlgorithm, pub digest_type: DnsSecDigestAlgorithm, pub digest: HexRemainingBlob, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[RRClass(?)] pub struct SSHFP { pub algorithm: SshFpAlgorithm, pub fingerprint_type: SshFpType, // RFC 4255 doesn't specify whether whitespace is allowed. // `HexRemainingBlob` allows whitespace. pub fingerprint: HexRemainingBlob, } pub use super::weird_structs::IPSECKEY; #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct RRSIG { pub rr_type: Type, pub algorithm: DnsSecAlgorithm, pub labels: u8, pub original_ttl: u32, pub signature_expiration: Time, pub signature_inception: Time, pub key_tag: u16, pub signers_name: DnsCanonicalName, pub signature: Base64RemainingBlob, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct NSEC { pub next: DnsName, // RFC 6840 says not canonic (updates RFC 4034) pub types: NsecTypeBitmap, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct DNSKEY { pub flags: DnskeyFlags, pub protocol: DnskeyProtocol, // should always be DNSSEC (3) according to RFC 4034 pub algorithm: DnsSecAlgorithm, pub public_key: Base64RemainingBlob, } impl DNSKEY { fn alg1_tag(&self) -> u16 { let key: &[u8] = &self.public_key; if key.is_empty() { return 0; } // not enough data let pkey; if 0 == key[0] { // two-byte length encoding of exponent if key.len() < 3 { return 0; } // not enough data let explen = ((key[1] as u16) << 8) + (key[2] as u16); if explen < 256 { return 0; } // should have used shorter length encoding if key.len() < 3 + (explen as usize) { return 0; } // not enough data pkey = &key[3 + (explen as usize)..]; } else { // one-byte length encoding of exponent let explen = key[0]; if key.len() < 1 + (explen as usize) { return 0; } // not enough data pkey = &key[1 + (explen as usize)..]; } if pkey.len() < 3 { return 0; } // not enough data ((pkey[pkey.len() - 3] as u16) << 8) + (pkey[pkey.len() - 3] as u16) } /// calculate key tag pub fn tag(&self) -> u16 { if self.algorithm == DnsSecAlgorithm::RSAMD5 { return self.alg1_tag(); } let mut sum = 0u32; sum += self.flags.0 as u32; sum += (self.protocol.0 as u32) << 8; sum += self.algorithm.0 as u32; let key: &[u8] = &self.public_key; for i in 0..key.len() { let v = key[i] as u32; let v = if 0 == i & 1 { v << 8 } else { v }; sum = sum.wrapping_add(v); } sum.wrapping_add(sum >> 16) as u16 } #[cfg(feature = "crypto")] pub fn build_ds(&self, zone: &DnsName, algs: &[DnsSecDigestAlgorithmKnown]) -> Result> { if algs.is_empty() { return Ok(Vec::new()); } use crate::ser::packet::DnsPacketWriteContext; let mut ctx = DnsPacketWriteContext::new(); ctx.enable_canonical(); let mut bin = Vec::new(); zone.serialize(&mut ctx, &mut bin)?; self.serialize(&mut ctx, &mut bin)?; let key_tag = self.tag(); Ok(algs.iter().map(|alg| DS { key_tag, algorithm: self.algorithm, digest_type: (*alg).into(), digest: HexRemainingBlob::new(crate::crypto::ds_hash(*alg, &bin)), }).collect()) } } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(IN)] pub struct DHCID { pub content: Base64RemainingBlob, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct NSEC3 { pub hash_algorithm: Nsec3Algorithm, pub flags: Nsec3Flags, pub iterations: u16, pub salt: HexShortBlob, pub next_hashed: NextHashedOwnerName, pub types: NsecTypeBitmap, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct NSEC3PARAM { pub hash_algorithm: Nsec3Algorithm, pub flags: Nsec3ParamFlags, pub iterations: u16, pub salt: HexShortBlob, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct TLSA { // TODO: support acronyms from https://tools.ietf.org/html/rfc7218 pub cert_usage: u8, pub selector: u8, pub matching_type: u8, pub data: HexRemainingBlob, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct SMIMEA { // TODO: support acronyms from https://tools.ietf.org/html/rfc7218 pub cert_usage: u8, pub selector: u8, pub matching_type: u8, pub data: HexRemainingBlob, } // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[RRClass(?)] // pub struct HIP; #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct NINFO { pub text: LongText, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct RKEY { pub flags: u16, pub protocol: u8, pub algorithm: DnsSecAlgorithm, pub public_key: Base64RemainingBlob, } // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[RRClass(?)] // pub struct TALINK; #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct CDS { pub key_tag: u16, pub algorithm: DnsSecAlgorithm, pub digest_type: DnsSecDigestAlgorithm, pub digest: HexRemainingBlob, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct CDNSKEY { pub flags: DnskeyFlags, pub protocol: DnskeyProtocol, pub algorithm: DnsSecAlgorithm, pub public_key: Base64RemainingBlob, } impl CDNSKEY { pub fn tag(&self) -> u16 { DNSKEY { flags: self.flags, protocol: self.protocol, algorithm: self.algorithm, public_key: self.public_key.clone(), }.tag() } } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct OPENPGPKEY { pub public_key: Base64RemainingBlob, } // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[RRClass(?)] // pub struct CSYNC; // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[RRClass(ANY)] // pub struct ZONEMD { // pub serial: u32, // pub digest_type: u8, // pub reserved: u8, // pub digest: HexRemainingBlobNotEmpty, // } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[RRClass(?)] pub struct SPF { pub text: LongText, } // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[RRClass(?)] // pub struct UINFO; // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[RRClass(?)] // pub struct UID; // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[RRClass(?)] // pub struct GID; // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[RRClass(?)] // pub struct UNSPEC; // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[RRClass(?)] // pub struct NID; // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[RRClass(?)] // pub struct L32; // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[RRClass(?)] // pub struct L64; // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[RRClass(?)] // pub struct LP; #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct EUI48 { pub addr: EUI48Addr, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct EUI64 { pub addr: EUI64Addr } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct TKEY { pub algorithm: DnsName, pub inception: u32, pub expiration: u32, pub mode: u16, pub error: u16, pub key: Base64LongBlob, pub other: Base64LongBlob, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct TSIG { pub algorithm: DnsName, pub signed: Time48, pub fudge: u16, pub mac: Base64LongBlob, pub original_id: u16, pub error: u16, pub other: Base64LongBlob, } // QTYPEs: IXFR, AXFR, MAILB, MAILA, ANY #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct URI { pub priority: u16, pub weight: u16, pub target: UriText, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[RRClass(?)] pub struct CAA { pub flags: CaaFlags, pub tag: UnquotedShortText, pub value: RemainingText, } // pub struct AVC; // pub struct DOA; // pub struct AMTRELAY; // pub struct TA; #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct DLV { pub key_tag: u16, pub algorithm: DnsSecAlgorithm, pub digest_type: DnsSecDigestAlgorithm, pub digest: HexRemainingBlob, } // powerdns #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(IN)] // used to lookup A and AAAA - only useful in IN pub struct ALIAS { pub content: DnsName, }