rust-dnsbox/lib/dnsbox-base/src/records/structs.rs

650 lines
17 KiB
Rust

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 <character-string>" which say nothing about the
// binary encoding; later it says "<PSDN-address> is a string of decimal
// digits", so it would seem that there is no length encoding or
// restriction.
//
// wireshark and bind use <character-string> 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<ShortText>,
// }
#[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<Vec<DS>> {
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,
}