/***************************************************************************//**
  @file lip_dns_defs.h @ingroup lip_mdns
  @brief Файл содержит общие определения DNS, которые могут быть так же
         использованы для реализации протоколов @ref lip_mdns и LLMNR
  @author Borisov Alexey <borisov@lcard.ru>
 ******************************************************************************/

#ifndef LIP_DNS_DEFS_H_
#define LIP_DNS_DEFS_H_

#include "lip/lip_defs.h"
#include "lcspec.h"

/** Коды классов для записей DNS */
typedef enum {
    LIP_DNS_CLASS_IN    = 0x0001,  /**< Internet (IN)           [RFC1035]  */
    LIP_DNS_CLASS_CH    = 0x0003,  /**< Chaos (CH)              [Moon1981] */
    LIP_DNS_CLASS_HS    = 0x0004,  /**< Hesiod (HS)             [Dyer1987] */
    LIP_DNS_CLASS_NONE  = 0x00FD,  /**< QCLASS NONE             [RFC2136]  */
    LIP_DNS_CLASS_ANY   = 0x00FF   /**< QCLASS * (ANY)          [RFC1035]  */
} t_lip_dns_rr_classes;

/** Коды типов записей DNS - RR Types */
typedef enum {
    LIP_DNS_RRTYPE_A          = 1,  /**< a host address                           [RFC1035] */
    LIP_DNS_RRTYPE_NS         = 2,  /**< an authoritative name server             [RFC1035] */
    LIP_DNS_RRTYPE_MD         = 3,  /**< a mail destination (Obsolete - use MX)   [RFC1035] */
    LIP_DNS_RRTYPE_MF         = 4,  /**< a mail forwarder (Obsolete - use MX)     [RFC1035] */
    LIP_DNS_RRTYPE_CNAME      = 5,  /**< the canonical name for an alias          [RFC1035] */
    LIP_DNS_RRTYPE_SOA        = 6,  /**< marks the start of a zone of authority   [RFC1035] */
    LIP_DNS_RRTYPE_MB         = 7,  /**< a mailbox domain name (EXPERIMENTAL)     [RFC1035] */
    LIP_DNS_RRTYPE_MG         = 8,  /**< a mail group member (EXPERIMENTAL)       [RFC1035] */
    LIP_DNS_RRTYPE_MR         = 9,  /**< a mail rename domain name (EXPERIMENTAL) [RFC1035] */
    LIP_DNS_RRTYPE_NULL       = 10, /**< a null RR (EXPERIMENTAL)                 [RFC1035] */
    LIP_DNS_RRTYPE_WKS        = 11, /**< a well known service description         [RFC1035] */
    LIP_DNS_RRTYPE_PTR        = 12, /**< a domain name pointer                    [RFC1035] */
    LIP_DNS_RRTYPE_HINFO      = 13, /**< host information                         [RFC1035] */
    LIP_DNS_RRTYPE_MINFO      = 14, /**< mailbox or mail list information         [RFC1035] */
    LIP_DNS_RRTYPE_MX         = 15, /**< mail exchange                            [RFC1035] */
    LIP_DNS_RRTYPE_TXT        = 16, /**< text strings                             [RFC1035] */
    LIP_DNS_RRTYPE_RP         = 17, /**< for Responsible Person                   [RFC1183] */
    LIP_DNS_RRTYPE_AFSDB      = 18, /**< for AFS Data Base location               [RFC1183][RFC5864] */
    LIP_DNS_RRTYPE_X25        = 19, /**< for X.25 PSDN address                    [RFC1183] */
    LIP_DNS_RRTYPE_ISDN       = 20, /**< for ISDN address                         [RFC1183] */
    LIP_DNS_RRTYPE_RT         = 21, /**< for Route Through                        [RFC1183] */
    LIP_DNS_RRTYPE_NSAP       = 22, /**< for NSAP address, NSAP style A record    [RFC1706] */
    LIP_DNS_RRTYPE_NSAP_PTR   = 23, /**< for domain name pointer, NSAP style      [RFC1348] */
    LIP_DNS_RRTYPE_SIG        = 24, /**< for security signature                   [RFC4034][RFC3755][RFC2535] */
    LIP_DNS_RRTYPE_KEY        = 25, /**< for security key                         [RFC4034][RFC3755][RFC2535] */
    LIP_DNS_RRTYPE_PX         = 26, /**< X.400 mail mapping information           [RFC2163] */
    LIP_DNS_RRTYPE_GPOS       = 27, /**< Geographical Position                    [RFC1712] */
    LIP_DNS_RRTYPE_AAAA       = 28, /**< IP6 Address                              [RFC3596] */
    LIP_DNS_RRTYPE_LOC        = 29, /**< Location Information                     [RFC1876] */
    LIP_DNS_RRTYPE_NXT        = 30, /**< Next Domain - OBSOLETE                   [RFC3755][RFC2535] */
    LIP_DNS_RRTYPE_EID        = 31, /**< Endpoint Identifier                      [Patton] */
    LIP_DNS_RRTYPE_NIMLOC     = 32, /**< Nimrod Locator                           [Patton] */
    LIP_DNS_RRTYPE_SRV        = 33, /**< Server Selection                         [RFC2782] */
    LIP_DNS_RRTYPE_ATMA       = 34, /**< ATM Address                              [ATMDOC] */
    LIP_DNS_RRTYPE_NAPTR      = 35, /**< Naming Authority Pointer                 [RFC2915][RFC2168][RFC3403] */
    LIP_DNS_RRTYPE_KX         = 36, /**< Key Exchanger                            [RFC2230] */
    LIP_DNS_RRTYPE_CERT       = 37, /**< CERT                                     [RFC4398] */
    LIP_DNS_RRTYPE_A6         = 38, /**< A6 (Experimental)                        [RFC3226][RFC2874] */
    LIP_DNS_RRTYPE_DNAME      = 39, /**< DNAME                                    [RFC2672] */
    LIP_DNS_RRTYPE_SINK       = 40, /**< SINK                                     [Eastlake] */
    LIP_DNS_RRTYPE_OPT        = 41, /**< OPT                                      [RFC2671] */
    LIP_DNS_RRTYPE_APL        = 42, /**< APL                                      [RFC3123] */
    LIP_DNS_RRTYPE_DS         = 43, /**< Delegation Signer                        [RFC4034][RFC3658] */
    LIP_DNS_RRTYPE_SSHFP      = 44, /**< SSH Key Fingerprint                      [RFC4255] */
    LIP_DNS_RRTYPE_IPSECKEY   = 45, /**< IPSECKEY                                 [RFC4025] */
    LIP_DNS_RRTYPE_RRSIG      = 46, /**< RRSIG                                    [RFC4034][RFC3755] */
    LIP_DNS_RRTYPE_NSEC       = 47, /**< NSEC                                     [RFC4034][RFC3755] */
    LIP_DNS_RRTYPE_DNSKEY     = 48, /**< DNSKEY                                   [RFC4034][RFC3755] */
    LIP_DNS_RRTYPE_DHCID      = 49, /**< DHCID                                    [RFC4701] */
    LIP_DNS_RRTYPE_NSEC3      = 50, /**< NSEC3                                    [RFC5155] */
    LIP_DNS_RRTYPE_NSEC3PARAM = 51, /**< NSEC3PARAM                               [RFC5155] */
    LIP_DNS_RRTYPE_HIP        = 55, /**< Host Identity Protocol                   [RFC5205] */
    LIP_DNS_RRTYPE_NINFO      = 56, /**< NINFO                                    [Reid] */
    LIP_DNS_RRTYPE_RKEY       = 57, /**< RKEY                                     [Reid] */
    LIP_DNS_RRTYPE_TALINK     = 58, /**< Trust Anchor LINK                        [Wijngaards] */
    LIP_DNS_RRTYPE_CDS        = 59, /**< Child DS                                 [Barwood] */
    LIP_DNS_RRTYPE_SPF        = 99, /**<                                          [RFC4408] */
    LIP_DNS_RRTYPE_UINFO      = 100,/**<                                          [IANA-Reserved] */
    LIP_DNS_RRTYPE_UID        = 101,/**<                                          [IANA-Reserved] */
    LIP_DNS_RRTYPE_GID        = 102,/**<                                          [IANA-Reserved] */
    LIP_DNS_RRTYPE_UNSPEC     = 103,/**<                                          [IANA-Reserved] */
    LIP_DNS_RRTYPE_TKEY       = 249,/**< Transaction Key                          [RFC2930] */
    LIP_DNS_RRTYPE_TSIG       = 250,/**< Transaction Signature                    [RFC2845] */
    LIP_DNS_RRTYPE_IXFR       = 251,/**< incremental transfer                     [RFC1995] */
    LIP_DNS_RRTYPE_AXFR       = 252,/**< transfer of an entire zone               [RFC1035][RFC5936] */
    LIP_DNS_RRTYPE_MAILB      = 253,/**< mailbox-related RRs (MB, MG or MR)       [RFC1035] */
    LIP_DNS_RRTYPE_MAILA      = 254,/**< mail agent RRs (Obsolete - see MX)       [RFC1035] */
    LIP_DNS_RRTYPE_ANY        = 255,/**< A request for all records                [RFC1035] */
    LIP_DNS_RRTYPE_URI        = 256,/**< URI                                      [Faltstrom] */
    LIP_DNS_RRTYPE_CAA        = 257,/**< Certification Authority Authorization    [Hallam-Baker] */
    LIP_DNS_RRTYPE_TA         = 32768,/**<  DNSSEC Trust Authorities              [Weiler] */
    LIP_DNS_RRTYPE_DLV        = 32769 /**<  DNSSEC Lookaside Validation           [RFC4431] */
} t_lip_dns_rr_types;

/** DNS OpCodes */
typedef enum {
    LIP_DNS_OPCODE_QUERY      = 0, /**< [RFC1035] */
    LIP_DNS_OPCODE_IQUERY     = 1, /**< (Inverse Query, Obsolete)  [RFC3425] */
    LIP_DNS_OPCODE_STATUS     = 2, /**< [RFC1035] */
    LIP_DNS_OPCODE_NOTIFY     = 4, /**< [RFC1996] */
    LIP_DNS_OPCODE_UPDATE     = 5  /**< [RFC2136] */
} t_lip_dns_opcodes;


/** DNS RCODEs  */
typedef enum {
    LIP_DNS_RCODE_NOERROR    =  0, /**< No Error                             [RFC1035] */
    LIP_DNS_RCODE_FORMERR    =  1, /**< Format Error                         [RFC1035] */
    LIP_DNS_RCODE_SERVFAIL   =  2, /**< Server Failure                       [RFC1035] */
    LIP_DNS_RCODE_NXDOMAIN   =  3, /**< Non-Existent Domain                  [RFC1035] */
    LIP_DNS_RCODE_NOTIMP     =  4, /**< Not Implemented                      [RFC1035] */
    LIP_DNS_RCODE_REFUSED    =  5, /**< Query Refused                        [RFC1035] */
    LIP_DNS_RCODE_YXDOMAIN   =  6, /**< Name Exists when it should not       [RFC2136] */
    LIP_DNS_RCODE_YXRRSET    =  7, /**< RR Set Exists when it should not     [RFC2136] */
    LIP_DNS_RCODE_NXRRSET    =  8, /**< RR Set that should exist does not    [RFC2136] */
    LIP_DNS_RCODE_NOTAUTH    =  9, /**< Server Not Authoritative for zone    [RFC2136] */
    LIP_DNS_RCODE_NOTZONE    = 10, /**< Name not contained in zone           [RFC2136] */
    LIP_DNS_RCODE_BADVERS    = 16, /**< Bad OPT Version                      [RFC2671] */
    LIP_DNS_RCODE_BADSIG     = 16, /**< TSIG Signature Failure               [RFC2845] */
    LIP_DNS_RCODE_BADKEY     = 17, /**< Key not recognized                   [RFC2845] */
    LIP_DNS_RCODE_BADTIME    = 18, /**< Signature out of time window         [RFC2845] */
    LIP_DNS_RCODE_BADMODE    = 19, /**< Bad TKEY Mode                        [RFC2930] */
    LIP_DNS_RCODE_BADNAME    = 20, /**< Duplicate key name                   [RFC2930] */
    LIP_DNS_RCODE_BADALG     = 21, /**< Algorithm not supported              [RFC2930] */
    LIP_DNS_RCODE_BADTRUNC   = 22  /**< Bad Truncation                       [RFC4635] */
} t_lip_dns_rcodes;


/** DNS Label types  */
typedef enum {
    LIP_DNS_LABEL_TYPE_NORMAL     = 0x00, /**< Normal label lower 6 bits is the length of the label */
    LIP_DNS_LABEL_TYPE_COMPRESSED = 0xC0, /**< Compressed label the lower 6 bits and the 8 bits
                                                from next octet form a pointer to the compression target */
    LIP_DNS_LABEL_TYPE_EXTENDED   = 0x40  /**< Extended label type the lower 6 bits of this type
                                               (section 3) indicate the type of label in use */
} t_lip_dns_label_types;
#define LIP_DNS_LABEL_TYPE_MSK        (0xC0)

/** DNS EDNS0 Options  */
typedef enum {
    LIP_DNS_OPT_LLQ   = 1, /**< On-hold [http://files.dns-sd.org/draft-sekar-dns-llq.txt] */
    LIP_DNS_OPT_UL    = 2, /**< On-hold [http://files.dns-sd.org/draft-sekar-dns-ul.txt] */
    LIP_DNS_OPT_NSID  = 3 /**< [RFC5001] */
} t_lip_dns_ends0_opts;

/** Флаги из заголовка DNS-сообщения */
typedef enum {
    LIP_DNS_FLAG_QR          = 0x8000, /**< Query(0)/Response(1)   [RFC1035] */
    LIP_DNS_FLAG_AA          = 0x0400, /**< Authoritative Answer   [RFC1035] */
    LIP_DNS_FLAG_TC          = 0x0200, /**< Truncated Response     [RFC1035] */
    LIP_DNS_FLAG_RD          = 0x0100, /**< Recursion Desired      [RFC1035] */
    LIP_DNS_FLAG_RA          = 0x0080, /**< Recursion Allowed      [RFC1035] */
    LIP_DNS_FLAG_AD          = 0x0040, /**< Authentic Data         [RFC4035] */
    LIP_DNS_FLAG_CD          = 0x0020  /**< Checking Disabled      [RFC4035] */
} t_lip_dns_hdr_flags;

/** EDNS Header Flags (16 bits) */
typedef enum {
    LIP_DNS_EDNS_FLAGS_DO    = 0x0001 /**< DNSSEC answer OK   [RFC4035][RFC3225] */
} t_lip_dns_ends_flags;

/** Маска для выделения OPCODE из поля флагов пакета DNS */
#define LIP_DNS_OPCODE_MSK    (0xFUL << 11)
/** Маска для выделения RCODE из поля флагов пакета DNS */
#define LIP_DNS_RCODE_MSK     (0xFUL << 0)

/** Максимальная длина строки в DNS сообщении (например в записи TXT) */
#define LIP_DNS_STR_LEN_MAX   255

/** Максимальная длина метки в DNS-имени */
#define LIP_DNS_LABEL_LEN_MAX   63

#include "lcspec_pack_start.h"

/** Структура, описывающая RR (Resource Record) без имени узла */
typedef struct st_lip_dns_rr {
    uint16_t type; /**< Тип записи из #t_lip_dns_rr_types */
    uint16_t rclass; /**< Класс записи из #t_lip_dns_rr_classes */
    uint32_t ttl;   /**< Время жизни записи в кеше в секундах */
    uint16_t rdlength; /**< Длина переменной части (данных) */
    uint8_t rdata[0]; /**< Данные переменной длины */
} LATTRIBUTE_PACKED t_lip_dns_rr;

/** Размер постоянной части записи DNS */
#define LIP_DNS_RR_CONST_SIZE  offsetof(t_lip_dns_rr, rdata)

/** Структура, описывающая запрос без имени узла */
typedef struct st_lp_dns_query {
    uint16_t qtype; /**< Запрашиваемый тип записи из #t_lip_dns_rr_types */
    uint16_t qclass; /**< Запрашиваемый класс записи из #t_lip_dns_rr_classes */
} LATTRIBUTE_PACKED t_lip_dns_query;
/** Размер постоянной части запроса DNS */
#define LIP_DNS_QUERY_CONST_SIZE sizeof(t_lip_dns_query)

/** Заголовок сообщения DNS */
struct st_lip_dns_hdr {
    uint16_t id; /**< id запроса */
    uint16_t flags; /**< Поле содержит в себе флаги из #t_lip_dns_hdr_flags,
                         код операции (#t_lip_dns_opcodes) и код результата (#t_lip_dns_rcodes) */
    uint16_t qdcount; /**< Количество записей в секции вопросов (question) */
    uint16_t ancount; /**< Количество записей в секции ответов (answers) */
    uint16_t nscount; /**< Количество записей в секции authority */
    uint16_t arcount; /**< Количество записей в доп. секции (additional) */
    uint8_t  data[0]; /**< Остальные секции DNS сообщения */
} LATTRIBUTE_PACKED;
typedef struct st_lip_dns_hdr t_lip_dns_hdr;

#include "lcspec_pack_restore.h"


struct st_lip_dns_name;
/** Cтруктура, служащая для представления полного доменного имени (FQDN).
    Представляет собой имя узла (может содержать как одну метку, так и несколько
    разделенных точками (точки в именах не поддерживаются!) и опционально ссылку
    на домен верхнего уровня */
typedef struct st_lip_dns_name {
    const char *name; /**< Укзатель на строку с именем узла */
    const struct st_lip_dns_name *parent; /**< Указатель на домен верхнего уровня или  NULL */
} t_lip_dns_name;


/** Стркутура для представления информации из записи HINFO */
typedef struct {
    const char *cpu; /**< Укзатель на строку с названием процессора */
    const char *os; /**< Указатель на строку с названием ОС */
} t_lip_dns_rdata_hinfo;

/** Структура для представления информации из записи SRV */
typedef struct {
    uint16_t priority; /**< Приоритет сервера (выбирается сервер с минимальным
                             значением приоритета) */
    uint16_t weight; /**< Вес сервера (из серверов с одинаковым приритетом
                           сервер выбирается случайно, но вероятность каждого
                           определяется весом) */
    uint16_t port;  /**< Порт, используемый сервисом */
    const t_lip_dns_name *target; /**< Доменное имя сервера, предоставляющего сервис */
} t_lip_dns_rdata_srv;


/** Форматы для внутреннего хранения текстовых данных для записи типа #LIP_DNS_RRTYPE_TXT */
typedef enum {
    /** Формат записи txt, когда строки просто сохраняются как они есть */
    LIP_DNS_TXT_FORMAT_LIST     = 0x0,
    /** Формат записи txt, когда строки сохраняются попарно в виде ключ=значение,
        где первая строка представляет собой ключ, а вторая --- значение
        (используется в DNS-SD). Если вторая строка --- нулевой указатель,
        то результирующая строка будет состоять в виде только ключа (для бинарных
        ключей, которые либо присутствуют, либо отсутствуют), если строка нулевой
        длины, то в результате получается "ключ=", что означает пустое значение
        для ключа, у которого может быть значение. Для представления строк
        ключ-значение можно также использовать тип #t_lip_dns_txt_keyval */
    LIP_DNS_TXT_FORMAT_KEYS     = 0x1
} t_lip_dns_txt_rr_formats;


/** Стркутура для представления информации из записи TXT */
typedef struct {
    uint16_t format; /** Формат из #t_lip_dns_txt_rr_formats --- определяет, как
                         интерпретировать строки в поле #str */
    uint16_t str_cnt; /** Количество строк в массиве #str */
    const char** str; /** Указатели на массив строк (значение зависит от формата) */
} t_lip_dns_rdata_txt;

/** Структура для сохранения пар ключ-значения из записи TXT формата #LIP_DNS_TXT_FORMAT_KEYS */
typedef struct {
    const char *key; /**< Указатель на строку с названием ключа */
    const char *value; /**< Указатель на строку со значением ключа (если NULL -
                            то используется только ключ без значения) */
} t_lip_dns_txt_keyval;

#endif /* LIP_DNS_DEFS_H_ */
