1250 lines
32 KiB
C++
1250 lines
32 KiB
C++
// git version 5effe725
|
||
|
||
#include <stdio.h>
|
||
#include <arpa/inet.h>
|
||
#include <assert.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
|
||
#include "dns.h"
|
||
|
||
#define DNS_ERROR_LOG(msg) printf("%s, %s:%d", msg, __FILE__, __LINE__)
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////
|
||
// compress/decompress API
|
||
/////////////////////////////////////////////////////////////////////////////////
|
||
|
||
static int dns_compress_rr_str(u_char *domain, int domain_len, u_char *result)
|
||
{
|
||
int section_len = 0;
|
||
int result_pos = 1;
|
||
int domain_pos = 0;
|
||
|
||
if (domain_len < 0 || domain_len > DNS_MAX_NAME + 1 || '.' == domain[0] || '.' == domain[domain_len - 1])
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
while ((domain[domain_pos] != '\n') || (domain[domain_pos] != '\0'))
|
||
{
|
||
section_len = 0;
|
||
while ((domain[domain_pos] != '.') && (domain[domain_pos] != '\n') && (domain[domain_pos] != '\0'))
|
||
{
|
||
result[result_pos] = domain[domain_pos];
|
||
result_pos++;
|
||
domain_pos++;
|
||
section_len++;
|
||
}
|
||
result[result_pos - section_len - 1] = section_len;
|
||
|
||
if ((domain[domain_pos] == '\n') || (domain[domain_pos] == '\0'))
|
||
break;
|
||
result_pos++;
|
||
domain_pos++;
|
||
}
|
||
|
||
result[result_pos] = '\0';
|
||
|
||
if (result_pos >= domain_len)
|
||
{
|
||
return result_pos + 1;
|
||
}
|
||
else
|
||
{
|
||
return result_pos;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int dns_name_compress(u_char *name, int name_len, char *payload)
|
||
{
|
||
int used_len = 0;
|
||
u_int16_t compress_len = 0;
|
||
u_char compress_name[DNS_MAX_NAME + 1] = {0};
|
||
|
||
if (name_len)
|
||
{
|
||
compress_len = dns_compress_rr_str(name, name_len, compress_name);
|
||
if (compress_len <= 0)
|
||
{
|
||
DNS_ERROR_LOG("dns_compress_rr_str()");
|
||
return -1;
|
||
}
|
||
NS_SETLEN(compress_name, compress_len, payload, used_len);
|
||
}
|
||
else
|
||
{
|
||
NS_SET8(0, payload, used_len);
|
||
}
|
||
|
||
return used_len;
|
||
}
|
||
|
||
static int dns_name_decompress(char *msg, u_char **ptr, u_char *buf, int buflen, char *end)
|
||
{
|
||
u_char *p = NULL;
|
||
int index = 0, len = 0;
|
||
int np = 0, tot_len = 0;
|
||
|
||
p = *ptr;
|
||
*ptr = NULL;
|
||
index = 0;
|
||
np = 0;
|
||
while (1)
|
||
{
|
||
if (0 == p[0])
|
||
{
|
||
break;
|
||
}
|
||
|
||
if (0x0c0 == (p[0] & 0x0c0))
|
||
{
|
||
if (p + 2 > (u_char *)end)
|
||
return -1;
|
||
|
||
len = ((p[0] & 0x03f) << 8) + p[1];
|
||
|
||
if (NULL == *ptr)
|
||
{
|
||
tot_len += 2;
|
||
*ptr = p + 2;
|
||
}
|
||
|
||
p = (u_char *)msg + len;
|
||
if (p > (u_char *)end)
|
||
return -1;
|
||
|
||
/* too many pointers. */
|
||
if (np++ > 16)
|
||
return -1;
|
||
|
||
continue;
|
||
}
|
||
|
||
len = p[0];
|
||
p++;
|
||
tot_len++;
|
||
|
||
if (p + len > (u_char *)end)
|
||
return -1;
|
||
|
||
if (index + len >= buflen - 1)
|
||
return -1;
|
||
|
||
memcpy(buf + index, p, len);
|
||
index += len;
|
||
buf[index++] = '.';
|
||
p += len;
|
||
tot_len += len;
|
||
}
|
||
|
||
if (NULL == *ptr)
|
||
{
|
||
*ptr = p + 1;
|
||
tot_len++;
|
||
}
|
||
/*
|
||
* omit last '.'
|
||
*/
|
||
if (index > 0)
|
||
{
|
||
buf[index - 1] = '\0';
|
||
}
|
||
else
|
||
{
|
||
buf[0] = '\0';
|
||
}
|
||
|
||
return tot_len;
|
||
}
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////
|
||
// get API
|
||
/////////////////////////////////////////////////////////////////////////////////
|
||
|
||
static void get_dns_hdr_info(dns_hdr_t *dns_hdr, char *payload)
|
||
{
|
||
dns_hdr_t *tmp = ((dns_hdr_t *)payload);
|
||
memset(dns_hdr, 0, sizeof(dns_hdr_t));
|
||
|
||
dns_hdr->qr = tmp->qr;
|
||
dns_hdr->opcode = tmp->opcode;
|
||
dns_hdr->aa = tmp->aa;
|
||
dns_hdr->tc = tmp->tc;
|
||
dns_hdr->rd = tmp->rd;
|
||
dns_hdr->ra = tmp->ra;
|
||
dns_hdr->z = tmp->z;
|
||
dns_hdr->rcode = tmp->rcode;
|
||
|
||
dns_hdr->id = ntohs(tmp->id);
|
||
dns_hdr->qdcount = ntohs(tmp->qdcount);
|
||
dns_hdr->ancount = ntohs(tmp->ancount);
|
||
dns_hdr->aucount = ntohs(tmp->aucount);
|
||
dns_hdr->adcount = ntohs(tmp->adcount);
|
||
}
|
||
|
||
static void get_rr_type_nsec3(char **ptr, nsec3_t *nsec3, char *end)
|
||
{
|
||
NS_GET8(nsec3->hash_algo, *ptr);
|
||
NS_GET8(nsec3->flags, *ptr);
|
||
NS_GET16(nsec3->iteration, *ptr);
|
||
NS_GET8(nsec3->salt_len, *ptr);
|
||
nsec3->salt_value = *(u_char **)ptr;
|
||
*ptr += nsec3->salt_len; /* jump salt_value */
|
||
|
||
NS_GET8(nsec3->hash_len, *ptr);
|
||
nsec3->next_hash_owner = *(u_char **)ptr;
|
||
*ptr += nsec3->hash_len; /* jump next_hash_owner */
|
||
}
|
||
|
||
// unused
|
||
__attribute__((unused))static int get_rr_signer(u_char **ptr, u_char *buf, int buflen, char *end)
|
||
{
|
||
u_char *p = NULL;
|
||
int len = 0, i = 0;
|
||
|
||
p = *ptr;
|
||
if (0 == p[0])
|
||
{
|
||
len = strlen("Root");
|
||
memcpy(buf, "Root", len);
|
||
buf[len] = '\0';
|
||
*ptr += 1;
|
||
return 1;
|
||
}
|
||
|
||
p = *ptr;
|
||
*ptr = NULL;
|
||
len = 0;
|
||
|
||
while (1)
|
||
{
|
||
len++;
|
||
if (0x03 == p[0])
|
||
{
|
||
p += 1;
|
||
continue;
|
||
}
|
||
|
||
buf[i++] = p[0];
|
||
p += 1;
|
||
|
||
if (0 == p[0])
|
||
{
|
||
len++;
|
||
p += 1;
|
||
break;
|
||
}
|
||
}
|
||
|
||
*ptr = p;
|
||
buf[i] = '\0';
|
||
|
||
return len;
|
||
}
|
||
|
||
static void get_rr_type_rrsig(char **ptr, rrsig_t *rrsig, char *end)
|
||
{
|
||
NS_GET16(rrsig->type_covered, *ptr);
|
||
NS_GET8(rrsig->algo, *ptr);
|
||
NS_GET8(rrsig->labels, *ptr);
|
||
NS_GET32(rrsig->original_ttl, *ptr);
|
||
NS_GET32(rrsig->sig_expiration, *ptr);
|
||
NS_GET32(rrsig->sig_inception, *ptr);
|
||
NS_GET16(rrsig->key_tag, *ptr);
|
||
}
|
||
|
||
static int get_rr_type_wks(char **ptr, wks_t *wks, char *end)
|
||
{
|
||
if (*ptr + 4 > end)
|
||
return -1;
|
||
NS_GET32(wks->addr, *ptr);
|
||
if (*ptr + 1 > end)
|
||
return -1;
|
||
NS_GET8(wks->protocol, *ptr);
|
||
wks->bitmap = *(u_char **)ptr;
|
||
|
||
return 0;
|
||
}
|
||
|
||
static void get_rr_type_info(char **ptr, hinfo_t *hinfo, char *end)
|
||
{
|
||
int len = 0;
|
||
|
||
NS_GET8(hinfo->cpu_len, *ptr);
|
||
len = MIN(hinfo->cpu_len, sizeof(DNS_HINFO_MAX_CPU - 1));
|
||
memcpy((char *)hinfo->cpu, *ptr, len);
|
||
hinfo->cpu[len] = '\0';
|
||
*ptr += hinfo->cpu_len;
|
||
hinfo->cpu_len = len;
|
||
|
||
NS_GET8(hinfo->os_len, *ptr);
|
||
len = MIN(hinfo->os_len, sizeof(DNS_HINFO_MAX_OS - 1));
|
||
memcpy((char *)hinfo->os, *ptr, len);
|
||
hinfo->os[len] = '\0';
|
||
*ptr += hinfo->os_len;
|
||
hinfo->os_len = len;
|
||
}
|
||
|
||
static int get_rr_type_soa(char *msg, char **ptr, soa_t *soa, char *end)
|
||
{
|
||
if (0 >= dns_name_decompress(msg, (u_char **)ptr, soa->mname, sizeof(soa->mname), end))
|
||
return -1;
|
||
if (0 >= dns_name_decompress(msg, (u_char **)ptr, soa->rname, sizeof(soa->rname), end))
|
||
return -1;
|
||
|
||
if (*ptr + 4 > end)
|
||
return -1;
|
||
NS_GET32(soa->serial, *ptr);
|
||
if (*ptr + 4 > end)
|
||
return -1;
|
||
NS_GET32(soa->refresh, *ptr);
|
||
if (*ptr + 4 > end)
|
||
return -1;
|
||
NS_GET32(soa->retry, *ptr);
|
||
if (*ptr + 4 > end)
|
||
return -1;
|
||
NS_GET32(soa->expire, *ptr);
|
||
if (*ptr + 4 > end)
|
||
return -1;
|
||
NS_GET32(soa->minimum, *ptr);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int get_rr_common_field(char *msg, char **ptr, dns_rr_t *rr, char *end)
|
||
{
|
||
char *p = NULL;
|
||
if (*ptr == NULL)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
dns_name_decompress(msg, (u_char **)ptr, rr->name, DNS_MAX_NAME + 1, end);
|
||
#if 0
|
||
if(0 >= dns_name_decompress(msg, (u_char**)ptr, rr->name, DNS_MAX_NAME+1, end))
|
||
{
|
||
return -1;
|
||
}
|
||
#endif
|
||
if (*ptr == NULL || *ptr + 2 > end)
|
||
{
|
||
return -1;
|
||
}
|
||
NS_GET16(rr->type, *ptr);
|
||
|
||
if (*ptr == NULL || *ptr + 2 > end)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
NS_GET16(rr->rr_class, *ptr);
|
||
|
||
if (DNS_CLASS_UNKNOWN == rr->rr_class)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
if (*ptr == NULL || *ptr + 4 > end)
|
||
{
|
||
return -1;
|
||
}
|
||
NS_GET32(rr->ttl, *ptr);
|
||
if (*ptr == NULL || *ptr + 2 > end)
|
||
{
|
||
return -1;
|
||
}
|
||
NS_GET16(rr->rdlength, *ptr);
|
||
p = *ptr + rr->rdlength;
|
||
if (*ptr == NULL || p > end)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int get_dns_query_question(char *msg, char **ptr, dns_query_question_t *q, char *end)
|
||
{
|
||
int used_len = 0;
|
||
if (0 >= dns_name_decompress(msg, (u_char **)ptr, q->qname, DNS_MAX_NAME + 1, end))
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
used_len = strlen((char *)q->qname);
|
||
if (q->qname[used_len - 1] == '.')
|
||
return -2;
|
||
|
||
if (*ptr + 2 > end)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
NS_GET16(q->qtype, *ptr);
|
||
|
||
if (*ptr + 2 > end)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
NS_GET16(q->qclass, *ptr);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int get_one_resource_record(char *msg, char **ptr, dns_rr_t *rr, char *end)
|
||
{
|
||
u_int32_t len = 0, byte = 0;
|
||
u_char *original_ptr = NULL;
|
||
|
||
switch (rr->type)
|
||
{
|
||
case DNS_TYPE_CNAME:
|
||
original_ptr = (u_char *)*ptr;
|
||
if (0 >= dns_name_decompress(msg, (u_char **)ptr, rr->rdata.cname, DNS_MAX_NAME + 1, end))
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
break;
|
||
case DNS_TYPE_HINFO:
|
||
get_rr_type_info(ptr, &(rr->rdata.hinfo), end);
|
||
break;
|
||
case DNS_TYPE_MB:
|
||
if (0 >= dns_name_decompress(msg, (u_char **)ptr, rr->rdata.mb, DNS_MAX_NAME + 1, end))
|
||
return 0;
|
||
break;
|
||
case DNS_TYPE_MD:
|
||
if (0 >= dns_name_decompress(msg, (u_char **)ptr, rr->rdata.md, DNS_MAX_NAME + 1, end))
|
||
return 0;
|
||
break;
|
||
case DNS_TYPE_MF:
|
||
if (0 >= dns_name_decompress(msg, (u_char **)ptr, rr->rdata.mf, DNS_MAX_NAME + 1, end))
|
||
return 0;
|
||
break;
|
||
case DNS_TYPE_MG:
|
||
if (0 >= dns_name_decompress(msg, (u_char **)ptr, rr->rdata.mg, DNS_MAX_NAME + 1, end))
|
||
return 0;
|
||
break;
|
||
case DNS_TYPE_MINFO:
|
||
if (0 >= dns_name_decompress(msg, (u_char **)ptr, rr->rdata.minfo.rmailbx, DNS_MAX_NAME + 1, end))
|
||
return 0;
|
||
if (0 >= dns_name_decompress(msg, (u_char **)ptr, rr->rdata.minfo.emailbx, DNS_MAX_NAME + 1, end))
|
||
return 0;
|
||
break;
|
||
case DNS_TYPE_MR:
|
||
if (0 >= dns_name_decompress(msg, (u_char **)ptr, rr->rdata.mr, DNS_MAX_NAME + 1, end))
|
||
return 0;
|
||
break;
|
||
case DNS_TYPE_MX:
|
||
if (*ptr + 2 > end)
|
||
return 0;
|
||
NS_GET16(rr->rdata.mx.preference, *ptr);
|
||
if (rr->rdlength - 2 < ((u_char *)*ptr)[0])
|
||
{
|
||
if (rr->rdlength < 2)
|
||
{
|
||
*ptr += rr->rdlength;
|
||
break;
|
||
}
|
||
len = MIN(DNS_MAX_NAME - 1, rr->rdlength - 2); /* size=1byte */
|
||
memcpy(rr->rdata.mx.exchange, *ptr, len); /* error labels */
|
||
rr->rdata.mx.exchange[len] = '\0';
|
||
*ptr += rr->rdlength - 2;
|
||
}
|
||
else
|
||
{
|
||
if (0 >= dns_name_decompress(msg, (u_char **)ptr, rr->rdata.mx.exchange, DNS_MAX_NAME + 1, end))
|
||
return 0;
|
||
}
|
||
break;
|
||
case DNS_TYPE_NS:
|
||
if (0 >= dns_name_decompress(msg, (u_char **)ptr, rr->rdata.ns, DNS_MAX_NAME + 1, end))
|
||
return 0;
|
||
break;
|
||
case DNS_TYPE_PTR:
|
||
if (0 >= dns_name_decompress(msg, (u_char **)ptr, rr->rdata.ptr, DNS_MAX_NAME + 1, end))
|
||
return 0;
|
||
break;
|
||
case DNS_TYPE_SOA:
|
||
original_ptr = (u_char *)*ptr;
|
||
if (0 != get_rr_type_soa(msg, ptr, &(rr->rdata.soa), end))
|
||
return 0;
|
||
if ((char *)original_ptr + rr->rdlength != *ptr)
|
||
{
|
||
*ptr = (char *)original_ptr + rr->rdlength;
|
||
}
|
||
break;
|
||
case DNS_TYPE_A:
|
||
if (*ptr + 4 > end)
|
||
return 0;
|
||
memcpy(rr->rdata.a, *ptr, NS_INT32SZ);
|
||
(*ptr) += NS_INT32SZ;
|
||
break;
|
||
case DNS_TYPE_AAAA:
|
||
if (*ptr + 16 > end)
|
||
return -1;
|
||
memcpy(rr->rdata.aaaa, *ptr, 16);
|
||
(*ptr) += 16;
|
||
break;
|
||
case DNS_TYPE_DNAME:
|
||
if (0 >= dns_name_decompress(msg, (u_char **)ptr, rr->rdata.dname, DNS_MAX_NAME + 1, end))
|
||
return 0;
|
||
break;
|
||
case DNS_TYPE_ISDN:
|
||
memcpy(rr->rdata.isdn, *ptr, sizeof(u_char));
|
||
(*ptr) += 1;
|
||
break;
|
||
case DNS_TYPE_TXT:
|
||
len = MIN(DNS_MAX_NAME - 1, rr->rdlength - 1); /* size=1byte */
|
||
memcpy(rr->rdata.txt.txt, *ptr + 1, len);
|
||
rr->rdata.txt.size = len;
|
||
*ptr += rr->rdlength;
|
||
break;
|
||
case DNS_TYPE_RP:
|
||
if (0 >= dns_name_decompress(msg, (u_char **)ptr, rr->rdata.rp.mailbox, DNS_MAX_NAME + 1, end))
|
||
return 0;
|
||
if (0 >= dns_name_decompress(msg, (u_char **)ptr, rr->rdata.rp.txt_rr, DNS_MAX_NAME + 1, end))
|
||
return 0;
|
||
break;
|
||
case DNS_TYPE_NULL:
|
||
len = MIN(DNS_MAX_NAME - 1, rr->rdlength - 1); /* size=1byte */
|
||
memcpy(rr->rdata.null.null, *ptr + 1, len);
|
||
rr->rdata.null.size = len;
|
||
*ptr += rr->rdlength;
|
||
break;
|
||
case DNS_TYPE_WKS:
|
||
if (0 != get_rr_type_wks(ptr, &(rr->rdata.wks), end))
|
||
return 0;
|
||
rr->rdata.wks.size = rr->rdlength - 5;
|
||
*ptr += rr->rdlength - 5;
|
||
case DNS_TYPE_SRV:
|
||
NS_GET16(rr->rdata.srv.priority, *ptr);
|
||
NS_GET16(rr->rdata.srv.weight, *ptr);
|
||
NS_GET16(rr->rdata.srv.port, *ptr);
|
||
if (0 >= dns_name_decompress(msg, (u_char **)ptr, rr->rdata.srv.target, DNS_MAX_TARGET, end))
|
||
return 0;
|
||
break;
|
||
case DNS_TYPE_DS:
|
||
case DNS_TYPE_DLV:
|
||
if (*ptr + 4 > end)
|
||
return 0;
|
||
NS_GET16(rr->rdata.ds.key_tag, *ptr);
|
||
NS_GET8(rr->rdata.ds.algo, *ptr);
|
||
NS_GET8(rr->rdata.ds.digest_type, *ptr);
|
||
rr->rdata.ds.digest = *(u_char **)ptr;
|
||
rr->rdata.ds.digest_len = rr->rdlength - 4;
|
||
*ptr += rr->rdlength - 4;
|
||
break;
|
||
case DNS_TYPE_RRSIG:
|
||
if (*ptr + 18 > end)
|
||
return 0;
|
||
get_rr_type_rrsig(ptr, &(rr->rdata.rrsig), end);
|
||
len = dns_name_decompress(msg, (u_char **)ptr, rr->rdata.rrsig.signer_name, DNS_MAX_SIGNER_NAME, end);
|
||
if (len <= 0)
|
||
{
|
||
return -1;
|
||
}
|
||
rr->rdata.rrsig.signature = *(u_char **)ptr;
|
||
rr->rdata.rrsig.signature_len = rr->rdlength - 18 - len;
|
||
*ptr += rr->rdlength - 18 - len;
|
||
break;
|
||
case DNS_TYPE_NSEC:
|
||
original_ptr = (u_char *)*ptr;
|
||
len = dns_name_decompress(msg, (u_char **)ptr, rr->rdata.nsec.next_domain, DNS_MAX_OWNER, end);
|
||
if (len <= 0)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
if ((original_ptr + rr->rdlength != (u_char *)*ptr) && (*ptr != NULL))
|
||
{
|
||
NS_GET16(len, *ptr);
|
||
byte = MIN(DNS_MAX_MAPS - 1, len);
|
||
memcpy(rr->rdata.nsec.type_bit_maps, *ptr, byte);
|
||
rr->rdata.nsec.type_bit_maps[byte] = '\0';
|
||
*ptr += len;
|
||
rr->rdata.nsec.maps_temp_len = len;
|
||
rr->rdata.nsec.maps_len = len;
|
||
len = byte;
|
||
|
||
byte = ((u_char *)ptr)[0];
|
||
if ((byte & 0xFF) == 0xFF || byte == 128)
|
||
{
|
||
*ptr += 1; /* jump 0xFF */
|
||
byte = ((u_char *)ptr)[0];
|
||
*ptr += 1; /* jump 1 byte of len */
|
||
len = MIN(DNS_MAX_MAPS - 1 - len, byte);
|
||
memcpy(rr->rdata.nsec.type_bit_maps + rr->rdata.nsec.maps_len, *ptr, len);
|
||
(rr->rdata.nsec.type_bit_maps + rr->rdata.nsec.maps_len)[len] = '\0';
|
||
*ptr += byte; /* jump byte */
|
||
rr->rdata.nsec.maps_len += len;
|
||
}
|
||
}
|
||
break;
|
||
case DNS_TYPE_DNSKEY:
|
||
if (*ptr + 4 > end)
|
||
return 0;
|
||
NS_GET16(rr->rdata.dnskey.flags, *ptr);
|
||
NS_GET8(rr->rdata.dnskey.protocol, *ptr);
|
||
NS_GET8(rr->rdata.dnskey.algo, *ptr);
|
||
rr->rdata.dnskey.public_key = *(u_char **)ptr;
|
||
rr->rdata.dnskey.public_key_len = rr->rdlength - 4; /* sizeof(flags)+sizeof(protocol)+sizeof(algo) */
|
||
*ptr += rr->rdlength - 4; /* todo add log */
|
||
break;
|
||
case DNS_TYPE_NSEC3:
|
||
if (*ptr + 5 > end)
|
||
return 0;
|
||
original_ptr = (u_char *)*ptr;
|
||
get_rr_type_nsec3(ptr, &(rr->rdata.nsec3), end);
|
||
|
||
if ((original_ptr + rr->rdlength != (u_char *)*ptr) && (*ptr != NULL))
|
||
{
|
||
NS_GET16(len, *ptr);
|
||
byte = MIN(DNS_MAX_MAPS - 1, len);
|
||
memcpy(rr->rdata.nsec3.type_bit_maps, *ptr, byte);
|
||
rr->rdata.nsec3.type_bit_maps[byte] = '\0';
|
||
*ptr += len;
|
||
rr->rdata.nsec3.maps_temp_len = byte;
|
||
rr->rdata.nsec3.maps_len = byte;
|
||
len = byte;
|
||
|
||
byte = ((u_char *)*ptr)[0];
|
||
if ((byte & 0xFF) == 0xFF || byte == 128)
|
||
{
|
||
*ptr += 1; /* jump 0xFF */
|
||
byte = ((u_char *)*ptr)[0];
|
||
*ptr += 1; /* jump 1 byte of len */
|
||
len = MIN(DNS_MAX_MAPS - 1 - len, byte);
|
||
memcpy(rr->rdata.nsec3.type_bit_maps + rr->rdata.nsec3.maps_len, *ptr, len);
|
||
(rr->rdata.nsec3.type_bit_maps + rr->rdata.nsec3.maps_len)[len] = '\0';
|
||
*ptr += byte; /* jump byte */
|
||
rr->rdata.nsec3.maps_len += len;
|
||
}
|
||
}
|
||
break;
|
||
case DNS_TYPE_NSEC3PARAM:
|
||
NS_GET8(rr->rdata.nsec3param.hash_algo, *ptr);
|
||
NS_GET8(rr->rdata.nsec3param.flags, *ptr);
|
||
NS_GET16(rr->rdata.nsec3param.iteration, *ptr);
|
||
rr->rdata.nsec3param.salt_len = rr->rdlength - 4 - 1;
|
||
*ptr += 1;
|
||
rr->rdata.nsec3param.salt_value = *(u_char **)ptr;
|
||
*ptr += rr->rdlength - 5;
|
||
break;
|
||
case DNS_TYPE_OPT:
|
||
/* fail through */
|
||
case DNS_TYPE_UNKNOWN:
|
||
/* fail through */
|
||
default:
|
||
memcpy(rr->rdata.unknown_data, *ptr, rr->rdlength);
|
||
rr->rdata.unknown_data[rr->rdlength] = '\0';
|
||
(*ptr) += rr->rdlength;
|
||
// printf("No support respone type, type: %d", rr->type);
|
||
break;
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
static int parse_resource_record(dns_info_t *dns_info, char *payload, int payload_len, char **cur_pos)
|
||
{
|
||
int i = 0;
|
||
|
||
dns_info->rr_count = dns_info->hdr_info.ancount + dns_info->hdr_info.adcount + dns_info->hdr_info.aucount;
|
||
if (dns_info->rr_count == 0)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
dns_info->rr_count = MIN(dns_info->rr_count, MAX_RR_NUM);
|
||
for (i = 0; i < dns_info->rr_count; i++)
|
||
{
|
||
if ((u_char *)*cur_pos >= (u_char *)payload + payload_len || (u_char *)*cur_pos < (u_char *)payload)
|
||
{
|
||
DNS_ERROR_LOG("parse_resource_record()");
|
||
return -1;
|
||
}
|
||
|
||
if (0 != get_rr_common_field(payload, cur_pos, &dns_info->rr[i], payload + payload_len))
|
||
{
|
||
if (dns_info->rr[i].rr_class == DNS_CLASS_UNKNOWN)
|
||
{
|
||
DNS_ERROR_LOG("get_rr_common_field()");
|
||
return -1; /* error packet */
|
||
}
|
||
else
|
||
{
|
||
DNS_ERROR_LOG("get_rr_common_field()");
|
||
dns_info->rr_count -= 1;
|
||
i -= 1;
|
||
continue;
|
||
}
|
||
}
|
||
|
||
if (dns_info->rr[i].rdlength == 0)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
if (get_one_resource_record(payload, cur_pos, &dns_info->rr[i], payload + payload_len) != 1)
|
||
{
|
||
DNS_ERROR_LOG("get_one_resource_record()");
|
||
dns_info->rr_count -= 1;
|
||
i -= 1;
|
||
}
|
||
}
|
||
|
||
assert(i == dns_info->rr_count);
|
||
return 0;
|
||
}
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////
|
||
// set API
|
||
/////////////////////////////////////////////////////////////////////////////////
|
||
|
||
static void set_dns_hdr_info(dns_hdr_t *src, char *payload)
|
||
{
|
||
dns_hdr_t *dst = ((dns_hdr_t *)payload);
|
||
memset(dst, 0, sizeof(dns_hdr_t));
|
||
|
||
dst->qr = src->qr;
|
||
dst->opcode = src->opcode;
|
||
dst->aa = src->aa;
|
||
dst->tc = src->tc;
|
||
dst->rd = src->rd;
|
||
dst->ra = src->ra;
|
||
dst->z = src->z;
|
||
dst->rcode = src->rcode;
|
||
|
||
dst->id = htons(src->id);
|
||
dst->qdcount = htons(src->qdcount); // 16bits: QDCOUNT: number of questions
|
||
dst->ancount = htons(src->ancount); // 16bits: ANCOUNT: number of answer resource records
|
||
dst->aucount = htons(src->aucount); // 16bits: NSCOUNT: number of authority resource records
|
||
dst->adcount = htons(src->adcount); // 16bits: ARCOUNT: number of additional resource records
|
||
}
|
||
|
||
static int set_dns_pkt_rr_header(char *payload, int payload_len, dns_rr_t *rr, int rdlength, char **rr_header_length_ptr)
|
||
{
|
||
int ret;
|
||
int used_len = 0;
|
||
|
||
if (rr->name)
|
||
{
|
||
ret = dns_name_compress(rr->name, strlen((char *)rr->name), payload);
|
||
if (ret == -1)
|
||
{
|
||
return -1;
|
||
}
|
||
used_len += ret;
|
||
}
|
||
else
|
||
{
|
||
NS_SET16(0xc00c, payload, used_len);
|
||
}
|
||
|
||
NS_SET16(rr->type, payload, used_len);
|
||
NS_SET16(rr->rr_class, payload, used_len);
|
||
NS_SET32(rr->ttl, payload, used_len);
|
||
*rr_header_length_ptr = payload + used_len;
|
||
NS_SET16(rr->rdlength, payload, used_len);
|
||
|
||
return used_len;
|
||
}
|
||
|
||
static void reset_rr_header_length(char **rr_length_ptr, int rdlength)
|
||
{
|
||
u_int16_t seg_16 = 0;
|
||
seg_16 = htons(rdlength);
|
||
memset(*rr_length_ptr, 0, sizeof(seg_16));
|
||
memcpy(*rr_length_ptr, &seg_16, sizeof(seg_16));
|
||
}
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////
|
||
// cheat API
|
||
/////////////////////////////////////////////////////////////////////////////////
|
||
|
||
static void set_cheat_pkt_header(dns_hdr_t *dns_hdr)
|
||
{
|
||
dns_hdr->qr = 1; // 1bit: Response
|
||
dns_hdr->opcode = 0; // 4bits: Query
|
||
dns_hdr->aa = 0; // 1bit: authoritative answer
|
||
dns_hdr->tc = 0; // 1bit: Not truncated
|
||
dns_hdr->rd = 1; // 1bit: Recursion Desired
|
||
dns_hdr->ra = 1; // 1bit: Recursion Available
|
||
dns_hdr->z = 0; // 3bits: Reserved for future use: Must be zero in all queries and responses
|
||
dns_hdr->rcode = 0; // 4bits: 0: No error condition
|
||
|
||
dns_hdr->id = htons(dns_hdr->id);
|
||
dns_hdr->qdcount = htons(dns_hdr->qdcount); // 16bits: QDCOUNT: number of questions
|
||
dns_hdr->ancount = htons(dns_hdr->ancount); // 16bits: ANCOUNT: number of answer resource records
|
||
dns_hdr->aucount = htons(dns_hdr->aucount); // 16bits: NSCOUNT: number of authority resource records
|
||
dns_hdr->adcount = htons(dns_hdr->adcount); // 16bits: ARCOUNT: number of additional resource records
|
||
}
|
||
|
||
static int set_cheat_pkt_question(char *payload, dns_query_question_t *query, int query_num)
|
||
{
|
||
int ret;
|
||
int used_len = 0;
|
||
|
||
/* ֻ<><D6BB><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||
ret = dns_name_compress(query->qname, strlen((char *)query->qname), payload);
|
||
if (ret == -1)
|
||
{
|
||
return -1;
|
||
}
|
||
used_len += ret;
|
||
|
||
NS_SET16(query->qtype, payload, used_len);
|
||
NS_SET16(query->qclass, payload, used_len);
|
||
|
||
return used_len;
|
||
}
|
||
|
||
// NOTE <20><><EFBFBD><EFBFBD>ֵ TODO
|
||
static int set_cheat_pkt_rr_pdata_type_str(char *payload, cheat_pkt_opt_t *cheat_opt)
|
||
{
|
||
int used_len = 0;
|
||
u_int16_t q_class = 1;
|
||
u_int16_t compress_len = 0;
|
||
u_char compress_name[DNS_MAX_NAME + 1] = {0};
|
||
|
||
NS_SET16(0xc00c, payload, used_len);
|
||
NS_SET16(cheat_opt->res_type, payload, used_len);
|
||
NS_SET16(q_class, payload, used_len);
|
||
NS_SET32(cheat_opt->ttl, payload, used_len);
|
||
|
||
compress_len = dns_compress_rr_str(cheat_opt->res_info, cheat_opt->res_len, compress_name);
|
||
if (compress_len <= 0)
|
||
{
|
||
DNS_ERROR_LOG("dns_compress_rr_str()");
|
||
}
|
||
|
||
NS_SET16(compress_len, payload, used_len);
|
||
NS_SETLEN(compress_name, compress_len, payload, used_len);
|
||
|
||
return used_len;
|
||
}
|
||
|
||
static int set_cheat_pkt_rr_pdata_type_ip(char *payload, cheat_pkt_opt_t *cheat_opt)
|
||
{
|
||
int used_len = 0;
|
||
u_int16_t q_class = 1;
|
||
|
||
NS_SET16(0xc00c, payload, used_len);
|
||
NS_SET16(cheat_opt->res_type, payload, used_len);
|
||
NS_SET16(q_class, payload, used_len);
|
||
NS_SET32(cheat_opt->ttl, payload, used_len);
|
||
NS_SET16(cheat_opt->res_len, payload, used_len);
|
||
NS_SETLEN((char *)cheat_opt->res_info, cheat_opt->res_len, payload, used_len);
|
||
|
||
return used_len;
|
||
}
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////
|
||
// public API
|
||
/////////////////////////////////////////////////////////////////////////////////
|
||
|
||
dns_info_t *dns_new(void)
|
||
{
|
||
dns_info_t *dns_info = (dns_info_t *)calloc(sizeof(dns_info_t), 1);
|
||
return dns_info;
|
||
}
|
||
|
||
void dns_free(dns_info_t *dns_info)
|
||
{
|
||
if (dns_info)
|
||
{
|
||
free(dns_info);
|
||
dns_info = NULL;
|
||
}
|
||
}
|
||
|
||
int dns_parser(dns_info_t *dns_info, char *in_buff, int buff_len)
|
||
{
|
||
char *cur_pos = NULL;
|
||
|
||
get_dns_hdr_info(&dns_info->hdr_info, in_buff);
|
||
cur_pos = in_buff + sizeof(dns_hdr_t);
|
||
|
||
if (0 == dns_info->hdr_info.qdcount || dns_info->hdr_info.qdcount > 1)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
if (0 != get_dns_query_question(in_buff, &cur_pos, &(dns_info->query_question), in_buff + buff_len))
|
||
{
|
||
DNS_ERROR_LOG("get_dns_query_question()");
|
||
return -1;
|
||
}
|
||
|
||
if (parse_resource_record(dns_info, in_buff, buff_len, &cur_pos) != 0)
|
||
{
|
||
DNS_ERROR_LOG("parse_resource_record()");
|
||
return -1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
int dns_package(dns_info_t *dns_info, char *out_buff, int buff_size)
|
||
{
|
||
char *rr_header_length_ptr = NULL;
|
||
int i = 0;
|
||
int rr_count = 0;
|
||
dns_hdr_t *dns_hdr = &dns_info->hdr_info;
|
||
int ret = 0;
|
||
int used_len = 0;
|
||
dns_rr_t *rr;
|
||
|
||
set_dns_hdr_info(dns_hdr, out_buff);
|
||
used_len += sizeof(dns_hdr_t);
|
||
ret = set_cheat_pkt_question(out_buff + used_len, &dns_info->query_question, dns_hdr->qdcount);
|
||
if (ret < 0)
|
||
{
|
||
return -1;
|
||
}
|
||
used_len += ret;
|
||
|
||
rr_count = dns_hdr->adcount + dns_hdr->ancount + dns_hdr->aucount;
|
||
for (i = 0; i < rr_count; i++)
|
||
{
|
||
rr = &dns_info->rr[i];
|
||
ret = set_dns_pkt_rr_header(out_buff + used_len, buff_size, rr, 0, &rr_header_length_ptr);
|
||
if (ret == -1)
|
||
{
|
||
return -1;
|
||
}
|
||
used_len += ret;
|
||
|
||
if (rr->rdlength == 0)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
int rr_header_used_len = used_len;
|
||
switch (rr->type)
|
||
{
|
||
case DNS_TYPE_A:
|
||
NS_SETLEN(rr->rdata.a, strlen((char *)rr->rdata.a), out_buff, used_len);
|
||
break;
|
||
case DNS_TYPE_AAAA:
|
||
NS_SETLEN(rr->rdata.aaaa, 16, out_buff, used_len);
|
||
break;
|
||
case DNS_TYPE_CNAME:
|
||
ret = dns_name_compress(rr->rdata.cname, strlen((char *)rr->rdata.cname), out_buff + used_len);
|
||
if (ret == -1)
|
||
{
|
||
return -1;
|
||
}
|
||
used_len += ret;
|
||
break;
|
||
case DNS_TYPE_MB:
|
||
ret = dns_name_compress(rr->rdata.mb, strlen((char *)rr->rdata.mb), out_buff + used_len);
|
||
if (ret == -1)
|
||
{
|
||
return -1;
|
||
}
|
||
used_len += ret;
|
||
break;
|
||
case DNS_TYPE_MD:
|
||
ret = dns_name_compress(rr->rdata.md, strlen((char *)rr->rdata.md), out_buff + used_len);
|
||
if (ret == -1)
|
||
{
|
||
return -1;
|
||
}
|
||
used_len += ret;
|
||
break;
|
||
case DNS_TYPE_MF:
|
||
ret = dns_name_compress(rr->rdata.mf, strlen((char *)rr->rdata.mf), out_buff + used_len);
|
||
if (ret == -1)
|
||
{
|
||
return -1;
|
||
}
|
||
used_len += ret;
|
||
break;
|
||
case DNS_TYPE_MG:
|
||
ret = dns_name_compress(rr->rdata.mg, strlen((char *)rr->rdata.mg), out_buff + used_len);
|
||
if (ret == -1)
|
||
{
|
||
return -1;
|
||
}
|
||
used_len += ret;
|
||
break;
|
||
case DNS_TYPE_MINFO:
|
||
ret = dns_name_compress(rr->rdata.minfo.rmailbx, strlen((char *)rr->rdata.minfo.rmailbx), out_buff + used_len);
|
||
if (ret == -1)
|
||
{
|
||
return -1;
|
||
}
|
||
used_len += ret;
|
||
|
||
ret = dns_name_compress(rr->rdata.minfo.emailbx, strlen((char *)rr->rdata.minfo.emailbx), out_buff + used_len);
|
||
if (ret == -1)
|
||
{
|
||
return -1;
|
||
}
|
||
used_len += ret;
|
||
break;
|
||
case DNS_TYPE_MR:
|
||
ret = dns_name_compress(rr->rdata.mr, strlen((char *)rr->rdata.mr), out_buff + used_len);
|
||
if (ret == -1)
|
||
{
|
||
return -1;
|
||
}
|
||
used_len += ret;
|
||
break;
|
||
case DNS_TYPE_MX:
|
||
NS_SET16(rr->rdata.mx.preference, out_buff, used_len);
|
||
|
||
ret = dns_name_compress(rr->rdata.mx.exchange, strlen((char *)rr->rdata.mx.exchange), out_buff + used_len);
|
||
if (ret == -1)
|
||
{
|
||
return -1;
|
||
}
|
||
used_len += ret;
|
||
break;
|
||
case DNS_TYPE_NS:
|
||
ret = dns_name_compress(rr->rdata.ns, strlen((char *)rr->rdata.ns), out_buff + used_len);
|
||
if (ret == -1)
|
||
{
|
||
return -1;
|
||
}
|
||
used_len += ret;
|
||
break;
|
||
case DNS_TYPE_PTR:
|
||
ret = dns_name_compress(rr->rdata.ptr, strlen((char *)rr->rdata.ptr), out_buff + used_len);
|
||
if (ret == -1)
|
||
{
|
||
return -1;
|
||
}
|
||
used_len += ret;
|
||
break;
|
||
case DNS_TYPE_SOA:
|
||
ret = dns_name_compress(rr->rdata.soa.mname, strlen((char *)rr->rdata.soa.mname), out_buff + used_len);
|
||
if (ret == -1)
|
||
{
|
||
return -1;
|
||
}
|
||
used_len += ret;
|
||
|
||
ret = dns_name_compress(rr->rdata.soa.rname, strlen((char *)rr->rdata.soa.rname), out_buff + used_len);
|
||
if (ret == -1)
|
||
{
|
||
return -1;
|
||
}
|
||
used_len += ret;
|
||
|
||
NS_SET32(rr->rdata.soa.serial, out_buff, used_len);
|
||
NS_SET32(rr->rdata.soa.refresh, out_buff, used_len);
|
||
NS_SET32(rr->rdata.soa.retry, out_buff, used_len);
|
||
NS_SET32(rr->rdata.soa.expire, out_buff, used_len);
|
||
NS_SET32(rr->rdata.soa.minimum, out_buff, used_len);
|
||
break;
|
||
case DNS_TYPE_DNAME:
|
||
ret = dns_name_compress(rr->rdata.dname, strlen((char *)rr->rdata.dname), out_buff + used_len);
|
||
if (ret == -1)
|
||
{
|
||
return -1;
|
||
}
|
||
used_len += ret;
|
||
break;
|
||
case DNS_TYPE_ISDN:
|
||
NS_SETLEN(rr->rdata.isdn, strlen((char *)rr->rdata.isdn), out_buff, used_len);
|
||
break;
|
||
case DNS_TYPE_RP:
|
||
ret = dns_name_compress(rr->rdata.rp.mailbox, strlen((char *)rr->rdata.rp.mailbox), out_buff + used_len);
|
||
if (ret == -1)
|
||
{
|
||
return -1;
|
||
}
|
||
used_len += ret;
|
||
|
||
ret = dns_name_compress(rr->rdata.rp.txt_rr, strlen((char *)rr->rdata.rp.txt_rr), out_buff + used_len);
|
||
if (ret == -1)
|
||
{
|
||
return -1;
|
||
}
|
||
used_len += ret;
|
||
break;
|
||
case DNS_TYPE_SRV:
|
||
NS_SET16(rr->rdata.srv.priority, out_buff, used_len);
|
||
NS_SET16(rr->rdata.srv.weight, out_buff, used_len);
|
||
NS_SET16(rr->rdata.srv.port, out_buff, used_len);
|
||
|
||
ret = dns_name_compress(rr->rdata.srv.target, strlen((char *)rr->rdata.srv.target), out_buff + used_len);
|
||
if (ret == -1)
|
||
{
|
||
return -1;
|
||
}
|
||
used_len += ret;
|
||
break;
|
||
case DNS_TYPE_RRSIG:
|
||
NS_SET16(rr->rdata.rrsig.type_covered, out_buff, used_len);
|
||
NS_SET8(rr->rdata.rrsig.algo, out_buff, used_len);
|
||
NS_SET8(rr->rdata.rrsig.labels, out_buff, used_len);
|
||
NS_SET32(rr->rdata.rrsig.original_ttl, out_buff, used_len);
|
||
NS_SET32(rr->rdata.rrsig.sig_expiration, out_buff, used_len);
|
||
NS_SET32(rr->rdata.rrsig.sig_inception, out_buff, used_len);
|
||
NS_SET16(rr->rdata.rrsig.key_tag, out_buff, used_len);
|
||
|
||
ret = dns_name_compress(rr->rdata.rrsig.signer_name, strlen((char *)rr->rdata.rrsig.signer_name), out_buff + used_len);
|
||
if (ret == -1)
|
||
{
|
||
return -1;
|
||
}
|
||
used_len += ret;
|
||
NS_SETLEN(rr->rdata.rrsig.signature, rr->rdata.rrsig.signature_len, out_buff, used_len);
|
||
break;
|
||
case DNS_TYPE_DNSKEY:
|
||
NS_SET16(rr->rdata.dnskey.flags, out_buff, used_len);
|
||
NS_SET8(rr->rdata.dnskey.protocol, out_buff, used_len);
|
||
NS_SET8(rr->rdata.dnskey.algo, out_buff, used_len);
|
||
NS_SETLEN(rr->rdata.dnskey.public_key, rr->rdata.dnskey.public_key_len, out_buff, used_len);
|
||
break;
|
||
case DNS_TYPE_NSEC3PARAM:
|
||
NS_SET8(rr->rdata.nsec3param.hash_algo, out_buff, used_len);
|
||
NS_SET8(rr->rdata.nsec3param.flags, out_buff, used_len);
|
||
NS_SET16(rr->rdata.nsec3param.iteration, out_buff, used_len);
|
||
NS_SET8(rr->rdata.nsec3param.salt_len, out_buff, used_len);
|
||
NS_SETLEN(rr->rdata.nsec3param.salt_value, rr->rdata.nsec3param.salt_len, out_buff, used_len);
|
||
break;
|
||
case DNS_TYPE_DS:
|
||
/* fail through */
|
||
case DNS_TYPE_DLV:
|
||
NS_SET16(rr->rdata.ds.key_tag, out_buff, used_len);
|
||
NS_SET8(rr->rdata.ds.algo, out_buff, used_len);
|
||
NS_SET8(rr->rdata.ds.digest_type, out_buff, used_len);
|
||
NS_SETLEN(rr->rdata.ds.digest, rr->rdata.ds.digest_len, out_buff, used_len);
|
||
break;
|
||
case DNS_TYPE_TXT:
|
||
NS_SET8(rr->rdata.txt.size, out_buff, used_len);
|
||
NS_SETLEN(rr->rdata.txt.txt, rr->rdata.txt.size, out_buff, used_len);
|
||
break;
|
||
case DNS_TYPE_NULL:
|
||
NS_SET8(rr->rdata.null.size, out_buff, used_len);
|
||
NS_SETLEN(rr->rdata.null.null, rr->rdata.null.size, out_buff, used_len);
|
||
break;
|
||
case DNS_TYPE_WKS:
|
||
NS_SET32(rr->rdata.wks.addr, out_buff, used_len);
|
||
NS_SET8(rr->rdata.wks.protocol, out_buff, used_len);
|
||
NS_SETLEN(rr->rdata.wks.bitmap, rr->rdata.wks.size, out_buff, used_len);
|
||
break;
|
||
case DNS_TYPE_HINFO:
|
||
NS_SET8(rr->rdata.hinfo.cpu_len, out_buff, used_len);
|
||
NS_SETLEN(rr->rdata.hinfo.cpu, rr->rdata.hinfo.cpu_len, out_buff, used_len);
|
||
NS_SET8(rr->rdata.hinfo.os_len, out_buff, used_len);
|
||
NS_SETLEN(rr->rdata.hinfo.os, rr->rdata.hinfo.os_len, out_buff, used_len);
|
||
break;
|
||
case DNS_TYPE_NSEC:
|
||
ret = dns_name_compress(rr->rdata.nsec.next_domain, strlen((char *)rr->rdata.nsec.next_domain), out_buff + used_len);
|
||
if (ret == -1)
|
||
{
|
||
return -1;
|
||
}
|
||
used_len += ret;
|
||
|
||
if (rr->rdata.nsec.maps_len)
|
||
{
|
||
NS_SET16(rr->rdata.nsec.maps_temp_len, out_buff, used_len);
|
||
NS_SETLEN(rr->rdata.nsec.type_bit_maps, rr->rdata.nsec.maps_temp_len, out_buff, used_len);
|
||
|
||
if (rr->rdata.nsec.maps_len > rr->rdata.nsec.maps_temp_len)
|
||
{
|
||
NS_SET8(0xFF, out_buff, used_len);
|
||
NS_SET8(rr->rdata.nsec.maps_len - rr->rdata.nsec.maps_temp_len, out_buff, used_len);
|
||
NS_SETLEN(rr->rdata.nsec.type_bit_maps + rr->rdata.nsec.maps_temp_len, rr->rdata.nsec.maps_len - rr->rdata.nsec.maps_temp_len, out_buff, used_len);
|
||
}
|
||
}
|
||
break;
|
||
case DNS_TYPE_NSEC3:
|
||
NS_SET8(rr->rdata.nsec3.hash_algo, out_buff, used_len);
|
||
NS_SET8(rr->rdata.nsec3.flags, out_buff, used_len);
|
||
NS_SET16(rr->rdata.nsec3.iteration, out_buff, used_len);
|
||
NS_SET8(rr->rdata.nsec3.salt_len, out_buff, used_len);
|
||
NS_SETLEN(rr->rdata.nsec3.salt_value, rr->rdata.nsec3.salt_len, out_buff, used_len);
|
||
NS_SET8(rr->rdata.nsec3.hash_len, out_buff, used_len);
|
||
NS_SETLEN(rr->rdata.nsec3.next_hash_owner, rr->rdata.nsec3.hash_len, out_buff, used_len);
|
||
|
||
if (rr->rdata.nsec3.maps_len)
|
||
{
|
||
NS_SET16(rr->rdata.nsec3.maps_temp_len, out_buff, used_len);
|
||
NS_SETLEN(rr->rdata.nsec3.type_bit_maps, rr->rdata.nsec3.maps_temp_len, out_buff, used_len);
|
||
|
||
if (rr->rdata.nsec3.maps_len > rr->rdata.nsec3.maps_temp_len)
|
||
{
|
||
NS_SET8(0xFF, out_buff, used_len);
|
||
NS_SET8(rr->rdata.nsec3.maps_len - rr->rdata.nsec3.maps_temp_len, out_buff, used_len);
|
||
NS_SETLEN(rr->rdata.nsec3.type_bit_maps + rr->rdata.nsec3.maps_temp_len, rr->rdata.nsec3.maps_len - rr->rdata.nsec3.maps_temp_len, out_buff, used_len);
|
||
}
|
||
}
|
||
break;
|
||
case DNS_TYPE_OPT:
|
||
/* fail through */
|
||
case DNS_TYPE_UNKNOWN:
|
||
/* fail through */
|
||
default:
|
||
NS_SETLEN(rr->rdata.unknown_data, rr->rdlength, out_buff, used_len);
|
||
break;
|
||
}
|
||
|
||
if (used_len - rr_header_used_len != rr->rdlength)
|
||
{
|
||
reset_rr_header_length(&rr_header_length_ptr, used_len - rr_header_used_len);
|
||
}
|
||
if (used_len > buff_size)
|
||
{
|
||
// printf("dns_package buff to short, %s, %d\n", __FILE__, __LINE__);
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
return used_len;
|
||
}
|
||
|
||
int dns_cheat_response(dns_info_t *dns_info, cheat_pkt_opt_t *cheat_opt, int cheat_opt_num, char *out_buff, int buff_size)
|
||
{
|
||
int i = 0;
|
||
dns_hdr_t *dns_hdr = NULL;
|
||
int ret = 0, used_len = 0;
|
||
|
||
memset(out_buff, 0, buff_size);
|
||
dns_hdr = (dns_hdr_t *)out_buff;
|
||
dns_hdr->id = dns_info->hdr_info.id;
|
||
dns_hdr->qdcount = 1;
|
||
dns_hdr->ancount = cheat_opt_num;
|
||
used_len += sizeof(dns_hdr_t);
|
||
|
||
ret = set_cheat_pkt_question(out_buff + used_len, &dns_info->query_question, dns_hdr->qdcount);
|
||
if (ret < 0)
|
||
{
|
||
return -1;
|
||
}
|
||
used_len += ret;
|
||
|
||
for (i = 0; i < cheat_opt_num; i++)
|
||
{
|
||
switch (cheat_opt[i].res_type)
|
||
{
|
||
case DNS_TYPE_A:
|
||
case DNS_TYPE_AAAA:
|
||
used_len += set_cheat_pkt_rr_pdata_type_ip(out_buff + used_len, &cheat_opt[i]);
|
||
break;
|
||
case DNS_TYPE_CNAME:
|
||
case DNS_TYPE_NS:
|
||
used_len += set_cheat_pkt_rr_pdata_type_str(out_buff + used_len, &cheat_opt[i]);
|
||
break;
|
||
}
|
||
|
||
if (used_len > buff_size)
|
||
{
|
||
return -2;
|
||
}
|
||
}
|
||
|
||
set_cheat_pkt_header(dns_hdr);
|
||
|
||
return used_len;
|
||
} |