It’s possible to derive Serialize
and Deserialize
for remote types. I gave this a go (10/10 wouldn’t do that again, the types ended up bigger than I initially expected ):
use std::{
collections::BTreeSet,
convert::TryFrom,
net::{Ipv4Addr, Ipv6Addr},
ops::Deref,
};
use dns_message_parser::{
question::{QClass, QType, Question},
rr::{
edns::{Cookie, CookieError, EDNSOption, Padding, ECS},
AFSDBSubtype, APItem, Address, AddressError, AlgorithmType, Class, DigestType, ISDNAddress,
PSDNAddress, SSHFPAlgorithm, SSHFPType, ServiceBinding, ServiceParameter, Tag, A, AAAA,
AFSDB, APL, CAA, CNAME, DNAME, DNSKEY, DS, EID, EUI48, EUI64, GPOS, HINFO, ISDN, KX, L32,
L64, LOC, LP, MB, MD, MF, MG, MINFO, MR, MX, NID, NIMLOC, NS, NSAP, NULL, OPT, PTR, PX, RP,
RR, RT, SA, SOA, SRV, SSHFP, TXT, URI, WKS, X25,
},
DomainName,
};
use paste::paste;
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, DeserializeAs, SerializeAs, TryFromInto};
#[serde_as]
#[derive(Serialize)]
struct Dnscr {
#[serde_as(as = "Vec<QuestionDef>")]
questions: Vec<Question>,
#[serde_as(as = "Vec<RRDef>")]
answers: Vec<RR>,
#[serde_as(as = "Vec<RRDef>")]
authorities: Vec<RR>,
#[serde_as(as = "Vec<RRDef>")]
additionals: Vec<RR>,
}
// -------------------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------------------
macro_rules! remote_serde_as {
($Type: ident, $TypeDef: ident) => {
impl SerializeAs<$Type> for $TypeDef {
fn serialize_as<S>(value: &$Type, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
$TypeDef::serialize(value, serializer)
}
}
impl<'de> DeserializeAs<'de, $Type> for $TypeDef {
fn deserialize_as<D>(deserializer: D) -> Result<$Type, D::Error>
where
D: serde::Deserializer<'de>,
{
$TypeDef::deserialize(deserializer)
}
}
};
}
remote_serde_as!(Question, QuestionDef);
remote_serde_as!(RR, RRDef);
#[derive(Serialize, Deserialize)]
#[serde(remote = "Question")]
pub struct QuestionDef {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
#[serde(with = "QClassDef")]
pub q_class: QClass,
#[serde(with = "QTypeDef")]
pub q_type: QType,
}
#[derive(Serialize, Deserialize)]
#[serde(try_from = "&str")]
#[serde(remote = "DomainName")]
pub struct DomainNameDef(#[serde(getter = "clone_from")] String);
#[derive(Serialize, Deserialize)]
#[serde(try_from = "String")]
#[serde(remote = "PSDNAddress")]
pub struct PSDNAddressDef(#[serde(getter = "deref_to_owned")] String);
#[derive(Serialize, Deserialize)]
#[serde(try_from = "String")]
#[serde(remote = "ISDNAddress")]
pub struct ISDNAddressDef(#[serde(getter = "deref_to_owned")] String);
#[derive(Serialize, Deserialize)]
#[serde(try_from = "String")]
#[serde(remote = "SA")]
pub struct SADef(#[serde(getter = "deref_to_owned")] String);
#[derive(Serialize, Deserialize)]
#[serde(try_from = "String")]
#[serde(remote = "Tag")]
pub struct TagDef(#[serde(getter = "as_ref_to_owned")] String);
fn clone_from(x: &(impl Clone + Into<String>)) -> String {
x.clone().into()
}
fn deref_to_owned(x: &impl Deref<Target = str>) -> String {
x.deref().to_owned()
}
fn as_ref_to_owned(x: &impl AsRef<str>) -> String {
x.as_ref().to_owned()
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "QClass")]
#[repr(u16)]
pub enum QClassDef {
IN = 1,
CS = 2,
CH = 3,
HS = 4,
ANY = 255,
}
#[allow(non_camel_case_types)]
#[derive(Serialize, Deserialize)]
#[serde(remote = "QType")]
#[repr(u16)]
pub enum QTypeDef {
A = 1,
NS = 2,
MD = 3,
MF = 4,
CNAME = 5,
SOA = 6,
MB = 7,
MG = 8,
MR = 9,
NULL = 10,
WKS = 11,
PTR = 12,
HINFO = 13,
MINFO = 14,
MX = 15,
TXT = 16,
RP = 17,
AFSDB = 18,
X25 = 19,
ISDN = 20,
RT = 21,
NSAP = 22,
NSAP_PTR = 23,
SIG = 24,
KEY = 25,
PX = 26,
GPOS = 27,
AAAA = 28,
LOC = 29,
NXT = 30,
EID = 31,
NIMLOC = 32,
SRV = 33,
ATMA = 34,
NAPTR = 35,
KX = 36,
CERT = 37,
A6 = 38,
DNAME = 39,
SINK = 40,
// OPT = 41,
APL = 42,
DS = 43,
SSHFP = 44,
IPSECKEY = 45,
RRSIG = 46,
NSEC = 47,
DNSKEY = 48,
DHCID = 49,
NSEC3 = 50,
NSEC3PARAM = 51,
TLSA = 52,
SMIMEA = 53,
HIP = 55,
NINFO = 56,
RKEY = 57,
TALINK = 58,
CDS = 59,
CDNSKEY = 60,
OPENPGPKEY = 61,
CSYNC = 62,
ZONEMD = 63,
/// Service Binding
SVCB = 64,
/// Service Binding specific to the https and http schemes
HTTPS = 65,
SPF = 99,
UINFO = 100,
UID = 101,
GID = 102,
UNSPEC = 103,
NID = 104,
L32 = 105,
L64 = 106,
LP = 107,
EUI48 = 108,
EUI64 = 109,
TKEY = 249,
TSIG = 250,
IXFR = 251,
// TODO QType?
URI = 256,
CAA = 257,
AVC = 258,
DOA = 259,
AMTRELAY = 260,
TA = 32768,
DLV = 32769,
AXFR = 252,
MAILB = 253,
MAILA = 254,
ALL = 255,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "RR")]
pub enum RRDef {
#[serde(with = "ADef")]
A(A),
#[serde(with = "NSDef")]
NS(NS),
#[serde(with = "MDDef")]
MD(MD),
#[serde(with = "MFDef")]
MF(MF),
#[serde(with = "CNAMEDef")]
CNAME(CNAME),
#[serde(with = "SOADef")]
SOA(SOA),
#[serde(with = "MBDef")]
MB(MB),
#[serde(with = "MGDef")]
MG(MG),
#[serde(with = "MRDef")]
MR(MR),
#[serde(with = "NULLDef")]
NULL(NULL),
#[serde(with = "WKSDef")]
WKS(WKS),
#[serde(with = "PTRDef")]
PTR(PTR),
#[serde(with = "HINFODef")]
HINFO(HINFO),
#[serde(with = "MINFODef")]
MINFO(MINFO),
#[serde(with = "MXDef")]
MX(MX),
#[serde(with = "TXTDef")]
TXT(TXT),
#[serde(with = "RPDef")]
RP(RP),
#[serde(with = "AFSDBDef")]
AFSDB(AFSDB),
#[serde(with = "X25Def")]
X25(X25),
#[serde(with = "ISDNDef")]
ISDN(ISDN),
#[serde(with = "RTDef")]
RT(RT),
#[serde(with = "NSAPDef")]
NSAP(NSAP),
#[serde(with = "PXDef")]
PX(PX),
#[serde(with = "GPOSDef")]
GPOS(GPOS),
#[serde(with = "AAAADef")]
AAAA(AAAA),
#[serde(with = "LOCDef")]
LOC(LOC),
#[serde(with = "NIMLOCDef")]
NIMLOC(NIMLOC),
#[serde(with = "SRVDef")]
SRV(SRV),
#[serde(with = "KXDef")]
KX(KX),
#[serde(with = "DNAMEDef")]
DNAME(DNAME),
#[serde(with = "OPTDef")]
OPT(OPT),
#[serde(with = "APLDef")]
APL(APL),
#[serde(with = "SSHFPDef")]
SSHFP(SSHFP),
#[serde(with = "URIDef")]
URI(URI),
#[serde(with = "EIDDef")]
EID(EID),
#[serde(with = "NIDDef")]
NID(NID),
#[serde(with = "L32Def")]
L32(L32),
#[serde(with = "L64Def")]
L64(L64),
#[serde(with = "LPDef")]
LP(LP),
#[serde(with = "EUI48Def")]
EUI48(EUI48),
#[serde(with = "EUI64Def")]
EUI64(EUI64),
#[serde(with = "DSDef")]
DS(DS),
#[serde(with = "DNSKEYDef")]
DNSKEY(DNSKEY),
#[serde(with = "CAADef")]
CAA(CAA),
#[serde(with = "ServiceBindingDef")]
SVCB(ServiceBinding),
#[serde(with = "ServiceBindingDef")]
HTTPS(ServiceBinding),
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "A")]
pub struct ADef {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
pub ipv4_addr: Ipv4Addr,
}
macro_rules! struct_domain_name_def {
($i:ident, $n:ident) => {
paste! {
#[derive(Serialize, Deserialize)]
#[serde(remote = "" $i)]
pub struct [< $i Def >] {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
#[serde(with = "ClassDef")]
pub class: Class,
#[serde(with = "DomainNameDef")]
pub $n: DomainName,
}
}
};
}
macro_rules! struct_domain_name_domain_name_def {
($i:ident, $n:ident, $m:ident) => {
paste! {
#[derive(Serialize, Deserialize)]
#[serde(remote = "" $i)]
pub struct [< $i Def >] {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
#[serde(with = "ClassDef")]
pub class: Class,
#[serde(with = "DomainNameDef")]
pub $n: DomainName,
#[serde(with = "DomainNameDef")]
pub $m: DomainName,
}
}
};
}
macro_rules! struct_u16_domain_name_def {
($i:ident, $n:ident, $m:ident) => {
paste! {
#[derive(Serialize, Deserialize)]
#[serde(remote = "" $i)]
pub struct [< $i Def >] {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
#[serde(with = "ClassDef")]
pub class: Class,
pub $n: u16,
#[serde(with = "DomainNameDef")]
pub $m: DomainName,
}
}
};
}
macro_rules! struct_u16_u64_def {
($i:ident, $n:ident, $m:ident) => {
paste! {
#[derive(Serialize, Deserialize)]
#[serde(remote = "" $i)]
pub struct [< $i Def >] {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
#[serde(with = "ClassDef")]
pub class: Class,
pub $n: u16,
pub $m: u64,
}
}
};
}
macro_rules! struct_vec_def {
($i:ident, $n:ident) => {
paste! {
#[derive(Serialize, Deserialize)]
#[serde(remote = "" $i)]
pub struct [< $i Def >] {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
#[serde(with = "ClassDef")]
pub class: Class,
pub $n: Vec<u8>,
}
}
};
}
macro_rules! struct_string_def {
($i:ident, $n:ident) => {
paste! {
#[derive(Serialize, Deserialize)]
#[serde(remote = "" $i)]
pub struct [< $i Def >] {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
#[serde(with = "ClassDef")]
pub class: Class,
pub $n: String,
}
}
};
}
struct_domain_name_def!(NS, ns_d_name);
struct_domain_name_def!(MD, mad_name);
struct_domain_name_def!(MF, mad_name);
struct_domain_name_def!(CNAME, c_name);
#[derive(Serialize, Deserialize)]
#[serde(remote = "Class")]
#[repr(u16)]
pub enum ClassDef {
/// The Internet class.
IN = 1,
/// The CSNET class. (obsolete)
CS = 2,
/// The CHAOS class.
CH = 3,
/// The Hesiod class.
HS = 4,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "SOA")]
pub struct SOADef {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
#[serde(with = "ClassDef")]
pub class: Class,
#[serde(with = "DomainNameDef")]
pub m_name: DomainName,
#[serde(with = "DomainNameDef")]
pub r_name: DomainName,
pub serial: u32,
pub refresh: u32,
pub retry: u32,
pub expire: u32,
pub min_ttl: u32,
}
struct_domain_name_def!(MB, mad_name);
struct_domain_name_def!(MG, mgm_name);
struct_domain_name_def!(MR, new_name);
struct_vec_def!(NULL, data);
#[derive(Serialize, Deserialize)]
#[serde(remote = "WKS")]
pub struct WKSDef {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
pub ipv4_addr: Ipv4Addr,
pub protocol: u8,
pub bit_map: Vec<u8>,
}
struct_domain_name_def!(PTR, ptr_d_name);
#[derive(Serialize, Deserialize)]
#[serde(remote = "HINFO")]
pub struct HINFODef {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
#[serde(with = "ClassDef")]
pub class: Class,
pub cpu: String,
pub os: String,
}
struct_domain_name_domain_name_def!(MINFO, r_mail_bx, e_mail_bx);
struct_u16_domain_name_def!(MX, preference, exchange);
struct_string_def!(TXT, string);
struct_domain_name_domain_name_def!(RP, mbox_dname, txt_dname);
#[derive(Serialize, Deserialize)]
#[serde(remote = "AFSDB")]
pub struct AFSDBDef {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
#[serde(with = "ClassDef")]
pub class: Class,
#[serde(with = "AFSDBSubtypeDef")]
pub subtype: AFSDBSubtype,
#[serde(with = "DomainNameDef")]
pub hostname: DomainName,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "AFSDBSubtype")]
#[repr(u16)]
pub enum AFSDBSubtypeDef {
VolumeLocationServer = 1,
DCEAuthenticationServer = 2,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "X25")]
pub struct X25Def {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
#[serde(with = "ClassDef")]
pub class: Class,
#[serde(with = "PSDNAddressDef")]
pub psdn_address: PSDNAddress,
}
remote_serde_as!(SA, SADef);
#[serde_as]
#[derive(Serialize, Deserialize)]
#[serde(remote = "ISDN")]
pub struct ISDNDef {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
#[serde(with = "ClassDef")]
pub class: Class,
#[serde(with = "ISDNAddressDef")]
pub isdn_address: ISDNAddress,
#[serde_as(as = "Option<SADef>")]
pub sa: Option<SA>,
}
struct_u16_domain_name_def!(RT, preference, intermediate_host);
struct_vec_def!(NSAP, data);
#[derive(Serialize, Deserialize)]
#[serde(remote = "PX")]
pub struct PXDef {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
#[serde(with = "ClassDef")]
pub class: Class,
pub preference: u16,
#[serde(with = "DomainNameDef")]
pub map822: DomainName,
#[serde(with = "DomainNameDef")]
pub mapx400: DomainName,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "GPOS")]
pub struct GPOSDef {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
#[serde(with = "ClassDef")]
pub class: Class,
pub longitude: String,
pub latitude: String,
pub altitude: String,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "AAAA")]
pub struct AAAADef {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
pub ipv6_addr: Ipv6Addr,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "LOC")]
pub struct LOCDef {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
#[serde(with = "ClassDef")]
pub class: Class,
pub version: u8,
pub size: u8,
pub horiz_pre: u8,
pub vert_pre: u8,
pub latitube: u32,
pub longitube: u32,
pub altitube: u32,
}
struct_vec_def!(NIMLOC, data);
#[derive(Serialize, Deserialize)]
#[serde(remote = "SRV")]
pub struct SRVDef {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
#[serde(with = "ClassDef")]
pub class: Class,
pub priority: u16,
pub weight: u16,
pub port: u16,
#[serde(with = "DomainNameDef")]
pub target: DomainName,
}
struct_u16_domain_name_def!(KX, preference, exchanger);
struct_domain_name_def!(DNAME, target);
#[serde_as]
#[derive(Serialize, Deserialize)]
#[serde(remote = "OPT")]
pub struct OPTDef {
pub requestor_payload_size: u16,
pub extend_rcode: u8,
pub version: u8,
pub dnssec: bool,
#[serde_as(as = "Vec<EDNSOptionDef>")]
pub edns_options: Vec<EDNSOption>,
}
remote_serde_as!(EDNSOption, EDNSOptionDef);
#[serde_as]
#[derive(Serialize, Deserialize)]
#[serde(remote = "APL")]
pub struct APLDef {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
#[serde_as(as = "Vec<APItemDef>")]
pub apitems: Vec<APItem>,
}
remote_serde_as!(APItem, APItemDef);
#[derive(Serialize, Deserialize)]
#[serde(remote = "SSHFP")]
pub struct SSHFPDef {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
#[serde(with = "ClassDef")]
pub class: Class,
#[serde(with = "SSHFPAlgorithmDef")]
pub algorithm: SSHFPAlgorithm,
#[serde(with = "SSHFPTypeDef")]
pub type_: SSHFPType,
pub fp: Vec<u8>,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "URI")]
pub struct URIDef {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
#[serde(with = "ClassDef")]
pub class: Class,
pub priority: u16,
pub weight: u16,
pub uri: String,
}
struct_vec_def!(EID, data);
struct_u16_u64_def!(NID, preference, node_id);
#[derive(Serialize, Deserialize)]
#[serde(remote = "L32")]
pub struct L32Def {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
#[serde(with = "ClassDef")]
pub class: Class,
pub preference: u16,
pub locator_32: u32,
}
struct_u16_u64_def!(L64, preference, locator_64);
struct_u16_domain_name_def!(LP, preference, fqdn);
#[derive(Serialize, Deserialize)]
#[serde(remote = "EUI48")]
pub struct EUI48Def {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
#[serde(with = "ClassDef")]
pub class: Class,
pub eui_48: [u8; 6],
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "EUI64")]
pub struct EUI64Def {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
#[serde(with = "ClassDef")]
pub class: Class,
pub eui_64: [u8; 8],
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "DS")]
pub struct DSDef {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
#[serde(with = "ClassDef")]
pub class: Class,
pub key_tag: u16,
#[serde(with = "AlgorithmTypeDef")]
pub algorithm_type: AlgorithmType,
#[serde(with = "DigestTypeDef")]
pub digest_type: DigestType,
pub digest: Vec<u8>,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "DNSKEY")]
pub struct DNSKEYDef {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
#[serde(with = "ClassDef")]
pub class: Class,
pub zone_key_flag: bool,
pub secure_entry_point_flag: bool,
#[serde(with = "AlgorithmTypeDef")]
pub algorithm_type: AlgorithmType,
pub public_key: Vec<u8>,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "CAA")]
pub struct CAADef {
#[serde(with = "DomainNameDef")]
pub domain_name: DomainName,
pub ttl: u32,
#[serde(with = "ClassDef")]
pub class: Class,
pub flags: u8,
#[serde(with = "TagDef")]
pub tag: Tag,
pub value: Vec<u8>,
}
#[serde_as]
#[derive(Serialize, Deserialize)]
#[serde(remote = "ServiceBinding")]
pub struct ServiceBindingDef {
#[serde(with = "DomainNameDef")]
pub name: DomainName,
pub ttl: u32,
pub priority: u16,
#[serde(with = "DomainNameDef")]
pub target_name: DomainName,
#[serde_as(as = "BTreeSet<ServiceParameterDef>")]
pub parameters: BTreeSet<ServiceParameter>,
pub https: bool,
}
remote_serde_as!(ServiceParameter, ServiceParameterDef);
#[serde_as]
#[derive(Serialize, Deserialize)]
#[serde(remote = "EDNSOption")]
pub enum EDNSOptionDef {
#[serde(with = "ECSDef")]
ECS(ECS),
Cookie(#[serde_as(as = "TryFromInto<CookieDef>")] Cookie),
#[serde(with = "PaddingDef")]
Padding(Padding),
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "APItem")]
#[serde(try_from = "APItemDef_")]
pub struct APItemDef {
#[serde(getter = "APItem::get_prefix")]
prefix: u8,
pub negation: bool,
#[serde(getter = "APItem::get_address")]
#[serde(with = "AddressDef")]
address: Address,
}
#[derive(Deserialize)]
#[serde(rename = "APItem")]
pub struct APItemDef_ {
prefix: u8,
pub negation: bool,
#[serde(with = "AddressDef")]
address: Address,
}
impl TryFrom<APItemDef_> for APItem {
type Error = AddressError;
fn try_from(d: APItemDef_) -> Result<Self, Self::Error> {
Self::new(d.prefix, d.negation, d.address)
}
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "SSHFPAlgorithm")]
#[repr(u8)]
pub enum SSHFPAlgorithmDef {
Reserved = 0,
RSA = 1,
DSS = 2,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "SSHFPType")]
#[repr(u8)]
pub enum SSHFPTypeDef {
Reserved = 0,
Sha1 = 1,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "AlgorithmType")]
#[repr(u8)]
pub enum AlgorithmTypeDef {
Reserved = 0x00,
RsaMd5 = 0x01,
DiffiHellman = 0x02,
DsaSha1 = 0x03,
EllipticCurve = 0x04,
RsaSha1 = 0x05,
DsaNsec3 = 0x06,
RsaSha1Nsec3Sha1 = 0x07,
RsaSha256 = 0x08,
GostR = 0x0c,
EcDsaP256 = 0x0d,
EcDsaP386 = 0x0e,
Ed25519 = 0x0f,
Ed448 = 0x10,
Indirect = 0xfc,
PrivateDns = 0xfd,
PrivateOid = 0xfe,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "DigestType")]
#[repr(u8)]
pub enum DigestTypeDef {
Reserved = 0x00,
Sha1 = 0x01,
Sha256 = 0x02,
GostR = 0x03,
Sha384 = 0x04,
}
#[allow(non_camel_case_types)]
#[derive(Serialize, Deserialize)]
#[serde(remote = "ServiceParameter")]
pub enum ServiceParameterDef {
MANDATORY { key_ids: Vec<u16> },
ALPN { alpn_ids: Vec<String> },
NO_DEFAULT_ALPN,
PORT { port: u16 },
IPV4_HINT { hints: Vec<Ipv4Addr> },
ECH { config_list: Vec<u8> },
IPV6_HINT { hints: Vec<Ipv6Addr> },
PRIVATE { number: u16, wire_data: Vec<u8> },
KEY_65535,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "ECS")]
#[serde(try_from = "ECSDef_")]
pub struct ECSDef {
#[serde(getter = "ECS::get_source_prefix_length")]
source_prefix_length: u8,
#[serde(getter = "ECS::get_scope_prefix_length")]
scope_prefix_length: u8,
#[serde(getter = "ECS::get_address")]
#[serde(with = "AddressDef")]
address: Address,
}
#[derive(Deserialize)]
#[serde(rename = "ECS")]
pub struct ECSDef_ {
source_prefix_length: u8,
scope_prefix_length: u8,
#[serde(with = "AddressDef")]
address: Address,
}
impl TryFrom<ECSDef_> for ECS {
type Error = AddressError;
fn try_from(e: ECSDef_) -> Result<Self, Self::Error> {
Self::new(e.source_prefix_length, e.scope_prefix_length, e.address)
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename = "Cookie")]
pub struct CookieDef {
pub client_cookie: [u8; 8],
server_cookie: Option<Vec<u8>>,
}
impl From<Cookie> for CookieDef {
fn from(c: Cookie) -> Self {
Self {
client_cookie: c.client_cookie,
server_cookie: c.get_server_cookie().map(<_>::to_owned),
}
}
}
impl TryFrom<CookieDef> for Cookie {
type Error = CookieError;
fn try_from(c: CookieDef) -> Result<Self, Self::Error> {
Self::new(c.client_cookie, c.server_cookie)
}
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "Address")]
pub enum AddressDef {
Ipv4(Ipv4Addr),
Ipv6(Ipv6Addr),
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "Padding")]
pub struct PaddingDef(pub u16);
A nicer approach might be to open a PR on GitHub - LinkTed/dns-message-parser: Rust libary to encode and decode DNS packets adding derives for serializing/deserialization everywhere, under an optional serde
crate feature, and hoping it gets merged.
Edit: Actually, since that’s a parsing/encoding library itself, it’s also an option to serialize/deserialize those types using their encode
/decode
methods:
use std::convert::TryFrom;
use bytes::Bytes;
use dns_message_parser::{question::Question, rr::RR, DecodeError, EncodeError};
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, TryFromInto};
#[serde_as]
#[derive(Serialize, Deserialize)]
struct Dnscr {
#[serde_as(as = "Vec<TryFromInto<QuestionEncodeDecode>>")]
questions: Vec<Question>,
#[serde_as(as = "Vec<TryFromInto<RREncodeDecode>>")]
answers: Vec<RR>,
#[serde_as(as = "Vec<TryFromInto<RREncodeDecode>>")]
authorities: Vec<RR>,
#[serde_as(as = "Vec<TryFromInto<RREncodeDecode>>")]
additionals: Vec<RR>,
}
#[derive(Serialize, Deserialize)]
#[serde(rename = "Question")]
struct QuestionEncodeDecode(Bytes);
impl TryFrom<QuestionEncodeDecode> for Question {
type Error = DecodeError;
fn try_from(value: QuestionEncodeDecode) -> Result<Self, Self::Error> {
Self::decode(value.0)
}
}
impl TryFrom<Question> for QuestionEncodeDecode {
type Error = EncodeError;
fn try_from(value: Question) -> Result<Self, Self::Error> {
Ok(Self(value.encode()?.into()))
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename = "RR")]
struct RREncodeDecode(Bytes);
impl TryFrom<RREncodeDecode> for RR {
type Error = DecodeError;
fn try_from(value: RREncodeDecode) -> Result<Self, Self::Error> {
Self::decode(value.0)
}
}
impl TryFrom<RR> for RREncodeDecode {
type Error = EncodeError;
fn try_from(value: RR) -> Result<Self, Self::Error> {
Ok(Self(value.encode()?.into()))
}
}