Serializing for structs

I am using the DNS Parser Dns in dns_message_parser - Rust

I have a data structure like this

struct Dnscr {
    questions: Vec<Question>,
    answers: Vec<RR>,
    authorities: Vec<RR>,
    additionals: Vec<RR>,
}

I would like to serialize and deserialize this data structure. I used serde but I get the following error

error[E0277]: the trait bound `Question: Serialize` is not satisfied
  --> src/prep-data.rs:45:5
   |
45 |     questions: Vec<Question>,
   |     ^^^^^^^^^ the trait `Serialize` is not implemented for `Question`
   |
   = note: required because of the requirements on the impl of `Serialize` for `Vec<Question>`
   = note: required by `_::_serde::ser::SerializeStruct::serialize_field`


How do I serialize this. ? Should I convert this into Bytes ? Should I use the TryInto

sounds like you're missing the

#[derive(Serialize)]

directly above that struct definition (see the docs), and you may need to enable serde's derive feature in Cargo.toml (see the same link)

That "derive" auto-generates an implementation of the Serialize trait that serde needs for structs you want to serialize.

You will need to derive Serialize and Deserialize for Question as well.

1 Like

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 :sweat_smile:):

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()))
    }
}
5 Likes

I tried the encoding / decoding approach . But now it is giving an error of not finding serde for Bytes

error[E0277]: the trait bound `bytes::Bytes: Serialize` is not satisfied
  --> src/prep-data.rs:58:29
   |
58 | struct QuestionEncodeDecode(Bytes);
   |                             ^^^^^ the trait `Serialize` is not implemented for `bytes::Bytes`
   |
   = note: required by `serialize_newtype_struct`

error[E0277]: the trait bound `bytes::Bytes: _::_serde::Deserialize<'_>` is not satisfied
   --> src/prep-data.rs:58:29
    |
58  | struct QuestionEncodeDecode(Bytes);
    |                             ^^^^^ the trait `_::_serde::Deserialize<'_>` is not implemented for `bytes::Bytes`
    | 
   ::: /home/wipro/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.130/src/de/mod.rs:539:12
    |
539 |         D: Deserializer<'de>;
    |            ----------------- required by this bound in `_::_serde::Deserialize::deserialize`

error[E0277]: the trait bound `bytes::Bytes: _::_serde::Deserialize<'_>` is not satisfied
  --> src/prep-data.rs:58:29
   |
58 | struct QuestionEncodeDecode(Bytes);
   |                             ^^^^^ the trait `_::_serde::Deserialize<'_>` is not implemented for `bytes::Bytes`
   |
   = note: required by `next_element`

error[E0277]: the trait bound `bytes::Bytes: Serialize` is not satisfied
  --> src/prep-data.rs:76:23
   |
76 | struct RREncodeDecode(Bytes);
   |                       ^^^^^ the trait `Serialize` is not implemented for `bytes::Bytes`
   |
   = note: required by `serialize_newtype_struct`

error[E0277]: the trait bound `bytes::Bytes: _::_serde::Deserialize<'_>` is not satisfied
   --> src/prep-data.rs:76:23
    |
76  | struct RREncodeDecode(Bytes);
    |                       ^^^^^ the trait `_::_serde::Deserialize<'_>` is not implemented for `bytes::Bytes`
    | 
   ::: /home/wipro/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.130/src/de/mod.rs:539:12
    |
539 |         D: Deserializer<'de>;
    |            ----------------- required by this bound in `_::_serde::Deserialize::deserialize`

error[E0277]: the trait bound `bytes::Bytes: _::_serde::Deserialize<'_>` is not satisfied
  --> src/prep-data.rs:76:23
   |
76 | struct RREncodeDecode(Bytes);
   |                       ^^^^^ the trait `_::_serde::Deserialize<'_>` is not implemented for `bytes::Bytes`
   |
   = note: required by `next_element`

error: aborting due to 6 previous errors

For more information about this error, try `rustc --explain E0277`.
error: could not compile `dnstapexperiments`

To learn more, run the command again with --verbose.

Serde is mainly for self-describing structured formats like json, yaml, msgpack etc. It doesn't play well with specific binary formats like DNS protocol. Does it make sense for you to serialize it in json? If not, the serde is not a right tool for it.

4 Likes

you need to set the serde feature of the bytes crate.

Thanks that worked.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.