
class DnsQueryResponse : public IDnsQueryResult {
    bool error;

    std::vector<class IDnsQueryEntry *> answers;
    std::vector<class IDnsQueryEntry *> authorities;
    std::vector<class IDnsQueryEntry *> additionals;

    const byte * ParseQuestion(const byte * msg, const byte * start, const byte * end, char * name, char * nameEnd, word * queryType, word * queryClass);
    const byte * ParseName(const byte * msg, const byte * start, const byte * end, char * name, char * nameEnd);
    const byte * ParseSection(const byte * msg, const byte * start, const byte * end, word count, std::vector<class IDnsQueryEntry *> * list);

    class IDnsQueryEntry * ParseA(const byte * msg, const byte * start, const byte * end, const char * name, dword ttl);
    class IDnsQueryEntry * ParseAAAA(const byte * msg, const byte * start, const byte * end, const char * name, dword ttl);
    class IDnsQueryEntry * ParseCNAME(const byte * msg, const byte * start, const byte * end, const char * name, dword ttl);
    class IDnsQueryEntry * ParseMX(const byte * msg, const byte * start, const byte * end, const char * name, dword ttl);
    class IDnsQueryEntry * ParseNS(const byte * msg, const byte * start, const byte * end, const char * name, dword ttl);
    class IDnsQueryEntry * ParseSRV(const byte * msg, const byte * start, const byte * end, const char * name, dword ttl);
    class IDnsQueryEntry * ParseTXT(const byte * msg, const byte * start, const byte * end, word rdLength, const char * name, dword ttl);
    class IDnsQueryEntry * ParseSOA(const byte * msg, const byte * start, const byte * end, const char * name, dword ttl);
    class IDnsQueryEntry * ParsePTR(const byte * msg, const byte * start, const byte * end, const char * name, dword ttl);
    class IDnsQueryEntry * ParseNAPTR(const byte * msg, const byte * start, const byte * end, const char * name, dword ttl);

public:
    DnsQueryResponse(const byte * answer, unsigned length);
    ~DnsQueryResponse();

    bool GetError() { return this->error; }

    size_t GetAnswerCount() override { return this->answers.size(); }
    size_t GetAuthorityCount() override { return this->authorities.size(); }
    size_t GetAdditionalCount() override { return this->additionals.size(); }
    class IDnsQueryEntry * GetAnswer(size_t index) override { return this->answers.size() > index ? this->answers[index] : nullptr; }
    class IDnsQueryEntry * GetAuthority(size_t index) override { return this->authorities.size() > index ? this->authorities[index] : nullptr; }
    class IDnsQueryEntry * GetAdditional(size_t index) override { return this->additionals.size() > index ? this->additionals[index] : nullptr; }
};

class DnsQueryEntry : public virtual IDnsQueryEntry {
    char * name;
    dns_query_type_sdk type;
    dword ttl;

public:
    DnsQueryEntry(const char * name, dns_query_type_sdk type, dword ttl);
    ~DnsQueryEntry();

    const char * GetName() override { return this->name; }
    dns_query_type_sdk GetType() override { return this->type; }
    dword GetTTL() override { return this->ttl; }
};

class DnsQueryEntryA : public DnsQueryEntry, public IDnsQueryEntryA {
    char * address;

public:
    DnsQueryEntryA(const char * name, dword ttl, const char * address);
    ~DnsQueryEntryA();

    const char * GetAddress() override { return this->address; }
};

class DnsQueryEntryAAAA : public DnsQueryEntry, public IDnsQueryEntryAAAA {
    char * address;

public:
    DnsQueryEntryAAAA(const char * name, dword ttl, const char * address);
    ~DnsQueryEntryAAAA();

    const char * GetAddress() override { return this->address; }
};

class DnsQueryEntryCNAME : public DnsQueryEntry, public IDnsQueryEntryCNAME {
    char * canonicalName;

public:
    DnsQueryEntryCNAME(const char * name, dword ttl, const char * canonicalName);
    ~DnsQueryEntryCNAME();

    const char * GetCanonicalName() { return this->canonicalName; }
};

class DnsQueryEntryMX : public DnsQueryEntry, public IDnsQueryEntryMX {
    word preference;
    char * mailServer;

public:
    DnsQueryEntryMX(const char * name, dword ttl, word preference, const char * mailServer);
    ~DnsQueryEntryMX();

    word GetPreference() override { return this->preference; }
    const char * GetMailServer() override { return this->mailServer; }
};

class DnsQueryEntryNS : public DnsQueryEntry, public IDnsQueryEntryNS {
    char * nameServer;

public:
    DnsQueryEntryNS(const char * name, dword ttl, const char * nameServer);
    ~DnsQueryEntryNS();

    const char * GetNameServer() override { return this->nameServer; }
};

class DnsQueryEntrySRV : public DnsQueryEntry, public IDnsQueryEntrySRV {
    word priority;
    word weight;
    word port;
    char * target;

public:
    DnsQueryEntrySRV(const char * name, dword ttl, word priority, word weight, word port, const char * target);
    ~DnsQueryEntrySRV();

    word GetPriority() override { return this->priority; }
    word GetWeight() override { return this->weight; }
    word GetPort() override { return this->port; }
    const char * GetTarget() override { return this->target; }
};

class DnsQueryEntryTXT : public DnsQueryEntry, public IDnsQueryEntryTXT {
    std::vector<char *> texts;

public:
    DnsQueryEntryTXT(const char * name, dword ttl);
    ~DnsQueryEntryTXT();

    void AddText(byte length, const byte * start);

    size_t GetTextCount() override { return this->texts.size(); }
    const char * GetTxt(size_t index) override { return this->texts.size() > index ? this->texts[index] : nullptr; }
};

class DnsQueryEntrySOA : public DnsQueryEntry, public IDnsQueryEntrySOA {
    char * primaryNS;
    char * responsibleMailbox;
    dword serialNumber;
    dword refreshInterval;
    dword retryInterval;
    dword expireLimit;
    dword minimumTTL;

public:
    DnsQueryEntrySOA(const char * name, dword ttl, char * primaryNS, char * responsibleMailbox, dword serialNumber, dword refreshInterval, dword retryInterval, dword expireLimit, dword minimumTTL);
    ~DnsQueryEntrySOA();

    const char * GetPrimaryNS() override { return this->primaryNS; }
    const char * GetResponsibleMailbox() override { return this->responsibleMailbox; }
    dword GetSerialNumber() override { return this->serialNumber; }
    dword GetRefreshInterval() override { return this->refreshInterval; }
    dword GetRetryInterval() override { return this->retryInterval; }
    dword GetExpireLimit() override { return this->expireLimit; }
    dword GetMinimumTTL() override { return this->minimumTTL; }
};

class DnsQueryEntryPTR : public DnsQueryEntry, public IDnsQueryEntryPTR {
    char * domainName;

public:
    DnsQueryEntryPTR(const char * name, dword ttl, const char * domainName);
    ~DnsQueryEntryPTR();

    const char * GetDomainName() override { return this->domainName; }
};

class DnsQueryEntryNAPTR : public DnsQueryEntry, public IDnsQueryEntryNAPTR {
    word order;
    word preference;
    char * flags;
    char * services;
    char * regex;
    char * replacement;

public:
    DnsQueryEntryNAPTR(const char * name, dword ttl, word order, word preference, const char * flags, const char * services, const char * regex, const char * replacement);
    ~DnsQueryEntryNAPTR();

    word GetOrder() override { return this->order; }
    word GetPreference() override { return this->preference; }
    const char * GetFlags() override { return this->flags; }
    const char * GetServices() override { return this->services; }
    const char * GetRegexp() override { return this->regex; }
    const char * GetReplacement() override { return this->replacement; }
};