//
//  File:   hzDNS.h
//
//  Legal Notice: This file is part of the HadronZoo C++ Class Library.
//
//  Copyright 2025 HadronZoo Project (http://www.hadronzoo.com)
//
//  The HadronZoo C++ Class Library is free software: You can redistribute it, and/or modify it under the terms of the GNU Lesser General Public License, as published by the Free
//  Software Foundation, either version 3 of the License, or any later version.
//
//  The HadronZoo C++ Class Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
//  A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public License along with the HadronZoo C++ Class Library. If not, see http://www.gnu.org/licenses.
//
//
//  The primary purpose for the hzDNS class is too facilitate DNS lookup
//
#ifndef hzDNS_h
#define hzDNS_h
#include "hzChain.h"
#include "hzTmplList.h"
#include "hzIpaddr.h"
enum    DnsType
{
    //  Category:   Internet
    //
    //  Main types (from RFC 1035)
    DNSTYPE_A           = 1,        //  a host address
    DNSTYPE_NS          = 2,        //  an authoritative name server
    DNSTYPE_MD          = 3,        //  a mail destination (Obsolete - use MX)
    DNSTYPE_MF          = 4,        //  a mail forwarder (Obsolete - use MX)
    DNSTYPE_CNAME       = 5,        //  the canonical name for an alias
    DNSTYPE_SOA         = 6,        //  marks the start of a zone of authority
    DNSTYPE_MB          = 7,        //  a mailbox domain name (EXPERIMENTAL)
    DNSTYPE_MG          = 8,        //  a mail group member (EXPERIMENTAL)
    DNSTYPE_MR          = 9,        //  a mail rename domain name (EXPERIMENTAL)
    DNSTYPE_NULL        = 10,       //  a null RR (EXPERIMENTAL)
    DNSTYPE_WKS         = 11,       //  a well known service description
    DNSTYPE_PTR         = 12,       //  a domain name pointer
    DNSTYPE_HINFO       = 13,       //  host information
    DNSTYPE_MINFO       = 14,       //  mailbox or mail list information
    DNSTYPE_MX          = 15,       //  mail exchange
    DNSTYPE_TXT         = 16,       //  text strings
    //  From RFC 1183
    DNSTYPE_RP          = 17,       //  for Responsible Person
    DNSTYPE_AFSDB       = 18,       //  for AFS Data Base location
    DNSTYPE_X25         = 19,       //  for X.25 PSDN address
    DNSTYPE_ISDN        = 20,       //  for ISDN address
    DNSTYPE_RT          = 21,       //  for Route Through
    //  Others
    DNSTYPE_NSAP        = 22,       //  for NSAP address, NSAP style A record   (RFC1706)
    DNSTYPE_NSAP_PTR    = 23,       //  Not sure!
    DNSTYPE_SIG         = 24,       //  for security signature                  (RFC2535, RFC3755, RFC4034)
    DNSTYPE_KEY         = 25,       //  for security key                        (RFC2535, RFC3755, RFC4034)
    DNSTYPE_PX          = 26,       //  X.400 mail mapping information          (RFC2163)
    DNSTYPE_GPOS        = 27,       //  Geographical Position                   (RFC1712)
    DNSTYPE_AAAA        = 28,       //  IP6 Address                             (RFC3596)
    DNSTYPE_LOC         = 29,       //  Location Information                    (RFC1876)
    DNSTYPE_NXT         = 30,       //  Next Domain - OBSOLETE                  (RFC2535, RFC3755)
    DNSTYPE_EID         = 31,       //  Endpoint Identifier                     (Patton)
    DNSTYPE_NIMLOC      = 32,       //  Nimrod Locator                          (Patton)
    DNSTYPE_SRV         = 33,       //  Server Selection                        (RFC2782)
    DNSTYPE_ATMA        = 34,       //  ATM Address                             (Dobrowski)
    DNSTYPE_NAPTR       = 35,       //  Naming Authority Pointer                (RFC2168, RFC2915)
    DNSTYPE_KX          = 36,       //  Key Exchanger                           (RFC2230)
    DNSTYPE_CERT        = 37,       //  CERT                                    (RFC2538)
    DNSTYPE_A6          = 38,       //  IPV6                                    (RFC2874, RFC3226)
    DNSTYPE_DNAME       = 39,       //  DNAME                                   (RFC2672)
    DNSTYPE_SINK        = 40,       //  SINK                                    (Eastlake)
    DNSTYPE_OPT         = 41,       //  OPT                                     (RFC2671)
    DNSTYPE_APL         = 42,       //  APL                                     (RFC3123)
    DNSTYPE_DS          = 43,       //  Delegation Signer                       (RFC3658)
    DNSTYPE_SSHFP       = 44,       //  SSH Key Fingerprint                     (RFC4255)
    DNSTYPE_IPSECKEY    = 45,       //  IPSECKEY                                (RFC4025)
    DNSTYPE_RRSIG       = 46,       //  RRSIG                                   (RFC3755)
    DNSTYPE_NSEC        = 47,       //  NSEC                                    (RFC3755)
    DNSTYPE_DNSKEY      = 48,       //  DNSKEY                                  (RFC3755)
    DNSTYPE_DHCID       = 49,       //  DHCID                                   (RFC4701)
    DNSTYPE_HIP         = 55,       //  Host Identity Protocol                  (RFC-ietf-hip-dns-09.txt)
    DNSTYPE_SPF         = 99,       //  Oh no, not these!                       (RFC4408)
    DNSTYPE_UINFO       = 100,      //  IANA-Reserved
    DNSTYPE_UID         = 101,      //  IANA-Reserved
    DNSTYPE_GID         = 102,      //  IANA-Reserved
    DNSTYPE_UNSPEC      = 103,      //  IANA-Reserved
    DNSTYPE_TKEY        = 249,      //  Transaction Key                         (RFC2930)
    DNSTYPE_TSIG        = 250,      //  Transaction Signature                   (RFC2845)
    DNSTYPE_IXFR        = 251,      //  incremental transfer                    (RFC1995)
    DNSTYPE_AXFR        = 252,      //  transfer of an entire zone              (RFC1035)
    DNSTYPE_MAILB       = 253,      //  mailbox-related RRs (MB, MG or MR)      (RFC1035)
    DNSTYPE_MAILA       = 254,      //  mail agent RRs (Obsolete - see MX)      (RFC1035)
    DNSTYPE_GLOBAL      = 255,      //  A request for all records               (RFC1035)
    DNSTYPE_TA          = 32768,    //  DNSSEC Trust Authorities                (Weiler)
    DNSTYPE_DLV         = 32769,    //  DNSSEC Lookaside Validation             (RFC4431)
} ;
/*
**  DNS Header
*/
struct  DnsHdr
{
    //  Category:   Internet
    //
    //  Used in the interpretation of a DNS query
    uint16_t    m_nQueryID ;            //  Useful only if set of records require more than one UDP packet. We send this with next request.
    uint16_t    m_nDNACode ;            //  Flags for interpretation - currently ignored
    uint16_t    m_nNoQuestions ;        //  Question count
    uint16_t    m_nNoAnswers ;          //  Answer count
    uint16_t    m_nNoAuth ;             //  Name server record count
    uint16_t    m_nNoAdditional ;       //  Name server record count
    void    _clear  (void)
    {
        m_nQueryID = 0 ;
        m_nDNACode = 0 ;
        m_nNoQuestions = 0 ;
        m_nNoAnswers = 0 ;
        m_nNoAuth = 0 ;
        m_nNoAdditional = 0 ;
    }
    bool        QueryResponse   (void)  { return m_nDNACode & 0x8000 ? true : false ; }
    uint32_t    OpCode          (void)  { return (m_nDNACode & 0x7800) >> 11 ; }
    bool        Authoritative   (void)  { return m_nDNACode & 0x0400 ? true : false ; }
    bool        Truncation      (void)  { return m_nDNACode & 0x0200 ? true : false ; }
    bool        RecursionDesire (void)  { return m_nDNACode & 0x0100 ? true : false ; }
    bool        RecursionAvail  (void)  { return m_nDNACode & 0x0080 ? true : false ; }
    uint32_t    ResponseCode    (void)  { return m_nDNACode & 0x000F ; }
} ;
/*
**  DNS Record
*/
struct  DnsRec
{
    //  Category:   Internet
    //
    //  DNS Record - Used in the interpretation of a DNS query
    hzString    m_Domain ;          //  Domain name
    hzString    m_Server ;          //  Server name
    hzIpaddr    m_Ipa ;             //  IP address (V4)
    uint32_t    m_anorakA ;         //  Part of IVP6
    uint32_t    m_anorakB ;         //  Part of IVP6
    uint32_t    m_anorakC ;         //  Part of IVP6
    uint32_t    m_anorakD ;         //  Part of IVP6
    uint32_t    m_nTTL ;            //  Time to live
    uint16_t    m_nType ;           //  Type of record, eg IN
    uint16_t    m_nClass ;          //  Class of record, eg MX
    uint16_t    m_nLen ;            //  Record length
    uint16_t    m_nValue ;          //  Eg MX value
    DnsRec  (void)
    {
        Clear() ;
    }
    ~DnsRec (void)
    {
    }
    void    Clear   (void)
    {
        m_Ipa.Clear() ;
        m_anorakA = m_anorakB = m_anorakC = m_anorakD = 0 ;
        m_nTTL = 0 ;
        m_nType = 0 ;
        m_nClass = 0 ;
        m_nLen = 0 ;
        m_nValue = 0 ;
    }
} ;
struct  hzResServer
{
    //  Category:   Internet
    //
    //  Cut-down version of a DNS record as used by applications
    hzString    m_Servername ;      //  Name of server being queried
    hzIpaddr    m_Ipa ;             //  IP address (V4)
    uint32_t    m_nTTL ;            //  Time to live
    uint16_t    m_nValue ;          //  MX records only
    uint16_t    m_nMisc ;           //  Reserved
    hzResServer (void)
    {
        m_nTTL = 0 ;
        m_nValue = 0 ;
        m_nMisc = 0 ;
    }
} ;
class   hzDNS
{
    //  Category:   Internet
    //
    //  The DnsQuery class
    uchar*      m_cpDns ;       //  Buffer for DNS output
    uint16_t    m_qID ;         //  So we can check this against ID of query
    uint16_t    m_DNA ;         //  Exactly
    uint32_t    m_Resv ;        //  Reserved
    hzString    _procraw    (uchar** cpPtr) ;
    void        _clear      (void) ;
public:
    hzList<DnsRec>  m_arQus ;   //  Question section
    hzList<DnsRec>  m_arAns ;   //  Answer section
    hzList<DnsRec>  m_arAut ;   //  Authorative section
    hzList<DnsRec>  m_arAdd ;   //  Additional section
    hzChain         m_Error ;   //  For error reporting
    hzDNS   (void)
    {
        m_cpDns = 0 ;
    }
    ~hzDNS  (void)
    {
        m_arQus.Clear() ;
        m_arAns.Clear() ;
        m_arAut.Clear() ;
        m_arAdd.Clear() ;
        delete [] m_cpDns ;
    }
    hzEcode     Query       (const char* dom, DnsType eType) ;
    hzEcode     SelectMX    (hzList<hzResServer>& ServersMX, const char* dom) ;
    hzEcode     QueryA      (const char* dom)   { return Query(dom, DNSTYPE_A) ; }
    hzEcode     QueryPTR    (const char* dom)   { return Query(dom, DNSTYPE_PTR) ; }
    hzEcode     QueryTXT    (const char* dom)   { return Query(dom, DNSTYPE_TXT) ; }
    hzEcode     QuerySPF    (const char* dom)   { return Query(dom, DNSTYPE_SPF) ; }
    hzEcode     QueryMX     (const char* dom)   { return Query(dom, DNSTYPE_MX) ; }
    void        Show            (hzChain& Result) const ;
    uint32_t    NoAnswers       (void) const    { return m_arAns.Count() ; }
    uint32_t    NoAuth          (void) const    { return m_arAut.Count() ; }
    uint32_t    NoAdditional    (void) const    { return m_arAdd.Count() ; }
} ;
/*
**  Prototypes
*/
hzEcode GetHostByAddr   (hzString& Host, const char* cpIPAddr) ;
#endif  //  hzDNS_h