727 lines
16 KiB
C
727 lines
16 KiB
C
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include <stdint.h>
|
||
|
|
||
|
#include <time.h>
|
||
|
|
||
|
#include <openssl/hmac.h>
|
||
|
|
||
|
#include "rr.h"
|
||
|
#include "utils.h"
|
||
|
#include "constants.h"
|
||
|
#include "packet.h"
|
||
|
|
||
|
/* ----- Creadores ----- */
|
||
|
|
||
|
DNSRR *dns2_rr_create_a (const char *name, int klass, int ttl, struct in_addr address) {
|
||
|
DNSRR *rr;
|
||
|
|
||
|
rr = (DNSRR *) malloc (sizeof (DNSRR));
|
||
|
|
||
|
if (rr == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
strncpy (rr->name, name, sizeof (rr->name));
|
||
|
dns2_trim_name (rr->name);
|
||
|
|
||
|
if (rr->name[0] == 0) {
|
||
|
free (rr);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
rr->type = RR_TYPE_A;
|
||
|
rr->klass = klass;
|
||
|
rr->ttl = ttl;
|
||
|
|
||
|
/* Copiar la IP */
|
||
|
memcpy (&rr->a.address, &address, sizeof (rr->a.address));
|
||
|
|
||
|
return rr;
|
||
|
}
|
||
|
|
||
|
DNSRR *dns2_rr_create_tsig (const char *name, const char *signature, const char *algorithm) {
|
||
|
DNSRR *rr;
|
||
|
|
||
|
if (strcmp (algorithm, RR_TSIG_HMAC_MD5) != 0 &&
|
||
|
strcmp (algorithm, RR_TSIG_HMAC_SHA1) != 0 &&
|
||
|
strcmp (algorithm, RR_TSIG_HMAC_SHA224) != 0 &&
|
||
|
strcmp (algorithm, RR_TSIG_HMAC_SHA256) != 0 &&
|
||
|
strcmp (algorithm, RR_TSIG_HMAC_SHA384) != 0 &&
|
||
|
strcmp (algorithm, RR_TSIG_HMAC_SHA512) != 0) {
|
||
|
/* Algoritmo no soportado */
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
rr = (DNSRR *) malloc (sizeof (DNSRR));
|
||
|
|
||
|
if (rr == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
strncpy (rr->name, name, sizeof (rr->name));
|
||
|
dns2_trim_name (rr->name);
|
||
|
|
||
|
if (rr->name[0] == 0) {
|
||
|
free (rr);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
rr->type = RR_TYPE_TSIG;
|
||
|
rr->klass = RR_CLASS_ANY;
|
||
|
rr->ttl = 0;
|
||
|
|
||
|
strncpy (rr->tsig.algorithm, algorithm, sizeof (rr->tsig.algorithm));
|
||
|
rr->tsig.key = strdup (signature);
|
||
|
|
||
|
if (rr->tsig.key == NULL) {
|
||
|
free (rr->name);
|
||
|
free (rr);
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// El tiempo tiene que ser UTC
|
||
|
// El tiempo son 6 bytes.
|
||
|
rr->tsig.time_signed = time (NULL);
|
||
|
//exit (1);
|
||
|
//rr->tsig.time_signed = 1602910230u;
|
||
|
//printf ("Time: %i\n", ((unsigned int) rr->tsig.time_signed));
|
||
|
rr->tsig.fudge = 300;
|
||
|
rr->tsig.mac_size = 0;
|
||
|
rr->tsig.original_id = 0;
|
||
|
|
||
|
rr->tsig.error = 0;
|
||
|
rr->tsig.other_length = 0;
|
||
|
|
||
|
return rr;
|
||
|
}
|
||
|
|
||
|
DNSRR *dns2_rr_create_aaaa (const char *name, int klass, int ttl, struct in6_addr address) {
|
||
|
DNSRR *rr;
|
||
|
|
||
|
rr = (DNSRR *) malloc (sizeof (DNSRR));
|
||
|
|
||
|
if (rr == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
strncpy (rr->name, name, sizeof (rr->name));
|
||
|
dns2_trim_name (rr->name);
|
||
|
|
||
|
if (rr->name[0] == 0) {
|
||
|
free (rr);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
rr->type = RR_TYPE_AAAA;
|
||
|
rr->klass = klass;
|
||
|
rr->ttl = ttl;
|
||
|
|
||
|
/* Copiar la IP */
|
||
|
memcpy (&rr->aaaa.address, &address, sizeof (rr->aaaa.address));
|
||
|
|
||
|
return rr;
|
||
|
}
|
||
|
|
||
|
DNSRR *dns2_rr_create_ns (const char *name, int klass, int ttl, const char *nsname) {
|
||
|
DNSRR *rr;
|
||
|
|
||
|
rr = (DNSRR *) malloc (sizeof (DNSRR));
|
||
|
|
||
|
if (rr == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
strncpy (rr->name, name, sizeof (rr->name));
|
||
|
dns2_trim_name (rr->name);
|
||
|
|
||
|
if (rr->name[0] == 0) {
|
||
|
free (rr);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
rr->type = RR_TYPE_NS;
|
||
|
rr->klass = klass;
|
||
|
rr->ttl = ttl;
|
||
|
|
||
|
/* Copiar el nombre */
|
||
|
memcpy (&rr->ns.name, &nsname, strlen (nsname) + 1);
|
||
|
dns2_trim_name (rr->ns.name);
|
||
|
|
||
|
return rr;
|
||
|
}
|
||
|
|
||
|
/* ----- Empaquetadores ----- */
|
||
|
void dns_rr_pack_a_data (DNSRR *rr, DNSPacket *packet) {
|
||
|
char *buf;
|
||
|
uint16_t t16;
|
||
|
|
||
|
buf = &packet->rdata[packet->rdlength];
|
||
|
|
||
|
t16 = htons (4);
|
||
|
memcpy (buf, &t16, 2);
|
||
|
|
||
|
memcpy (&buf[2], &rr->a.address, 4);
|
||
|
packet->rdlength += 4 + 2;
|
||
|
}
|
||
|
|
||
|
void dns_rr_pack_aaaa_data (DNSRR *rr, DNSPacket *packet) {
|
||
|
char *buf;
|
||
|
uint16_t t16;
|
||
|
|
||
|
buf = &packet->rdata[packet->rdlength];
|
||
|
|
||
|
t16 = htons (16);
|
||
|
memcpy (buf, &t16, 2);
|
||
|
|
||
|
memcpy (&buf[2], &rr->aaaa.address, 16);
|
||
|
packet->rdlength += 16 + 2;
|
||
|
}
|
||
|
|
||
|
int dns_rr_sign_hmac (void *data, int data_len, const char *key, const char *algorithm, void *mac) {
|
||
|
HMAC_CTX *ctx;
|
||
|
const EVP_MD *md_algo;
|
||
|
char *decoded_key;
|
||
|
size_t key_length;
|
||
|
int total_len;
|
||
|
int g;
|
||
|
|
||
|
printf ("About to sign, data is:\n");
|
||
|
for (g = 0; g < data_len; g++) {
|
||
|
printf ("%02x", (unsigned int) (((unsigned char *) data)[g]));
|
||
|
}
|
||
|
printf ("\nEnd data sig\n");
|
||
|
|
||
|
if (strcmp (algorithm, RR_TSIG_HMAC_MD5) == 0) {
|
||
|
md_algo = EVP_md5 ();
|
||
|
} else if (strcmp (algorithm, RR_TSIG_HMAC_SHA1) == 0) {
|
||
|
md_algo = EVP_sha1 ();
|
||
|
} else if (strcmp (algorithm, RR_TSIG_HMAC_SHA224) == 0) {
|
||
|
md_algo = EVP_sha224 ();
|
||
|
} else if (strcmp (algorithm, RR_TSIG_HMAC_SHA256) == 0) {
|
||
|
md_algo = EVP_sha256 ();
|
||
|
} else if (strcmp (algorithm, RR_TSIG_HMAC_SHA384) == 0) {
|
||
|
md_algo = EVP_sha384 ();
|
||
|
} else if (strcmp (algorithm, RR_TSIG_HMAC_SHA512) == 0) {
|
||
|
md_algo = EVP_sha512 ();
|
||
|
} else {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
ctx = HMAC_CTX_new ();
|
||
|
|
||
|
if (ctx == NULL) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (base64_decode (key, (unsigned char **)&decoded_key, &key_length) != 0) {
|
||
|
HMAC_CTX_free (ctx);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
HMAC_Init_ex (ctx, decoded_key, key_length, md_algo, NULL);
|
||
|
|
||
|
/* Enviar el mensaje a firmar */
|
||
|
HMAC_Update (ctx, data, data_len);
|
||
|
|
||
|
HMAC_Final (ctx, mac, &total_len);
|
||
|
|
||
|
HMAC_CTX_free (ctx);
|
||
|
|
||
|
free (decoded_key);
|
||
|
|
||
|
return total_len;
|
||
|
}
|
||
|
|
||
|
void dns_rr_pack_tsig_data (DNSRR *rr, DNSPacket *packet) {
|
||
|
uint16_t offset_rdlength, t16;
|
||
|
uint32_t t32;
|
||
|
|
||
|
/* Tomar la posición actual para el rdlength */
|
||
|
offset_rdlength = packet->rdlength;
|
||
|
packet->rdlength += 2;
|
||
|
|
||
|
/* Agregar el algoritmo sin compresión */
|
||
|
dns_packet_pack_name (packet, rr->tsig.algorithm);
|
||
|
|
||
|
/* Empaquetar el tiempo, fudge y mac_size */
|
||
|
t16 = 0;
|
||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||
|
packet->rdlength += 2;
|
||
|
|
||
|
t32 = htonl ((intmax_t) rr->tsig.time_signed);
|
||
|
memcpy (&packet->rdata[packet->rdlength], &t32, 4);
|
||
|
packet->rdlength += 4;
|
||
|
|
||
|
/* El fudge */
|
||
|
t16 = htons (rr->tsig.fudge);
|
||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||
|
packet->rdlength += 2;
|
||
|
|
||
|
t16 = htons (rr->tsig.mac_size);
|
||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||
|
packet->rdlength += 2;
|
||
|
|
||
|
/* Agregar el MAC */
|
||
|
memcpy (&packet->rdata[packet->rdlength], rr->tsig.mac, rr->tsig.mac_size);
|
||
|
packet->rdlength += rr->tsig.mac_size;
|
||
|
|
||
|
/* Copiar el packet id */
|
||
|
t16 = htons (packet->header.id);
|
||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||
|
packet->rdlength += 2;
|
||
|
|
||
|
/* Error y other length */
|
||
|
t16 = htons (rr->tsig.error);
|
||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||
|
packet->rdlength += 2;
|
||
|
|
||
|
t16 = htons (rr->tsig.other_length);
|
||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||
|
packet->rdlength += 2;
|
||
|
|
||
|
/* Agregar el other_data si other_length > 0 */
|
||
|
if (rr->tsig.other_length > 0) {
|
||
|
memcpy (&packet->rdata[packet->rdlength], rr->tsig.other_data, rr->tsig.other_length);
|
||
|
packet->rdlength += rr->tsig.other_length;
|
||
|
}
|
||
|
|
||
|
/* Regresar a la posición del rdlength y escribir el valor correcto */
|
||
|
t16 = htons (packet->rdlength - offset_rdlength - 2);
|
||
|
memcpy (&packet->rdata[offset_rdlength], &t16, 2);
|
||
|
}
|
||
|
|
||
|
void dns_rr_pack_generate_signature (DNSRR *signature, DNSPacket *packet) {
|
||
|
void *data;
|
||
|
int data_count;
|
||
|
uint16_t t16;
|
||
|
uint32_t t32;
|
||
|
|
||
|
/* Reempaquetar todo el paquete para generar los bytes de la firma */
|
||
|
dns_packet_reset (packet);
|
||
|
dns_packet_pack_data (packet);
|
||
|
|
||
|
/* Agregar el nombre del tsig sin compresión */
|
||
|
dns_packet_pack_name (packet, signature->name);
|
||
|
|
||
|
t16 = htons (signature->klass);
|
||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||
|
packet->rdlength += 2;
|
||
|
|
||
|
t32 = htonl (signature->ttl);
|
||
|
memcpy (&packet->rdata[packet->rdlength], &t32, 4);
|
||
|
packet->rdlength += 4;
|
||
|
|
||
|
/* Agregar el algoritmo sin compresión */
|
||
|
dns_packet_pack_name (packet, signature->tsig.algorithm);
|
||
|
|
||
|
/* Agregar la hora */
|
||
|
t16 = 0;
|
||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||
|
packet->rdlength += 2;
|
||
|
|
||
|
t32 = htonl ((intmax_t) signature->tsig.time_signed);
|
||
|
memcpy (&packet->rdata[packet->rdlength], &t32, 4);
|
||
|
packet->rdlength += 4;
|
||
|
|
||
|
/* El fudge */
|
||
|
t16 = htons (signature->tsig.fudge);
|
||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||
|
packet->rdlength += 2;
|
||
|
|
||
|
/* Error y other length */
|
||
|
t16 = htons (signature->tsig.error);
|
||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||
|
packet->rdlength += 2;
|
||
|
t16 = htons (signature->tsig.other_length);
|
||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||
|
packet->rdlength += 2;
|
||
|
|
||
|
/* Agregar el other_data si other_length > 0 */
|
||
|
if (signature->tsig.other_length > 0) {
|
||
|
memcpy (&packet->rdata[packet->rdlength], signature->tsig.other_data, signature->tsig.other_length);
|
||
|
packet->rdlength += signature->tsig.other_length;
|
||
|
}
|
||
|
|
||
|
/* Recuperar la data */
|
||
|
data_count = dns_packet_get_data (packet, (unsigned char **)&data);
|
||
|
|
||
|
/* Realmente firmar la data */
|
||
|
signature->tsig.mac_size = dns_rr_sign_hmac (data, data_count, signature->tsig.key, signature->tsig.algorithm, signature->tsig.mac);
|
||
|
|
||
|
/* Pedir reempaquetar la data, otra vez */
|
||
|
dns_packet_reset (packet);
|
||
|
}
|
||
|
|
||
|
void dns_rr_pack_data (DNSRR *rr, DNSPacket *packet) {
|
||
|
uint16_t t16;
|
||
|
uint32_t t32;
|
||
|
char *buf;
|
||
|
|
||
|
dns_packet_compress_name (packet, rr->name);
|
||
|
|
||
|
buf = &packet->rdata[packet->rdlength];
|
||
|
|
||
|
/*if (rr->type == OPT) {
|
||
|
|
||
|
} else { */
|
||
|
t16 = htons (rr->type);
|
||
|
memcpy (&buf[0], &t16, 2);
|
||
|
|
||
|
t16 = htons (rr->klass);
|
||
|
memcpy (&buf[2], &t16, 2);
|
||
|
|
||
|
t32 = htonl (rr->ttl);
|
||
|
memcpy (&buf[4], &t32, 4);
|
||
|
/* } */
|
||
|
|
||
|
packet->rdlength += 8;
|
||
|
|
||
|
/* Data por tipo */
|
||
|
switch (rr->type) {
|
||
|
case RR_TYPE_A:
|
||
|
dns_rr_pack_a_data (rr, packet);
|
||
|
break;
|
||
|
case RR_TYPE_AAAA:
|
||
|
dns_rr_pack_aaaa_data (rr, packet);
|
||
|
break;
|
||
|
case RR_TYPE_TSIG:
|
||
|
dns_rr_pack_tsig_data (rr, packet);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* ----- Desempaquetadores ----- */
|
||
|
int dns_rr_unpack_a_data (DNSRR *rr, unsigned char *buf, int rd_length) {
|
||
|
if (rd_length < 4) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
memcpy (&rr->a.address, buf, 4);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int dns_rr_unpack_aaaa_data (DNSRR *rr, unsigned char *buf, int rd_length) {
|
||
|
if (rd_length < 16) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
memcpy (&rr->aaaa.address, buf, 16);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int dns_rr_unpack_ns_data (DNSRR *rr, unsigned char *buf, int rd_length, DNSPacket *packet) {
|
||
|
/* No hacemos validaciones sobre la longitud porque los nombres son variables */
|
||
|
int save;
|
||
|
save = buf - packet->rdata;
|
||
|
|
||
|
if (dns_packet_expand_name (rr->ns.name, packet, &save) < 0) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int dns_rr_unpack_cname_data (DNSRR *rr, unsigned char *buf, int rd_length, DNSPacket *packet) {
|
||
|
/* No hacemos validaciones sobre la longitud porque los nombres son variables */
|
||
|
int save;
|
||
|
save = buf - packet->rdata;
|
||
|
|
||
|
if (dns_packet_expand_name (rr->cname.name, packet, &save) < 0) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int dns_rr_unpack_soa_data (DNSRR *rr, unsigned char *buf, int rd_length, DNSPacket *packet) {
|
||
|
int save, start;
|
||
|
int tot;
|
||
|
uint32_t u32;
|
||
|
|
||
|
if (rd_length < 20) { /* Al menos 5 enteros de 32 bits cada uno */
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
start = save = buf - packet->rdata;
|
||
|
if (dns_packet_expand_name (rr->soa.mname, packet, &save) < 0) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (dns_packet_expand_name (rr->soa.rname, packet, &save) < 0) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
tot = save - start;
|
||
|
if (rd_length - tot < 20) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
/* Leer el serial */
|
||
|
memcpy (&u32, &buf[tot], 4);
|
||
|
rr->soa.serial = ntohl (u32);
|
||
|
|
||
|
/* Leer el refresh */
|
||
|
memcpy (&u32, &buf[tot + 4], 4);
|
||
|
rr->soa.refresh = ntohl (u32);
|
||
|
|
||
|
/* Leer el retry */
|
||
|
memcpy (&u32, &buf[tot + 8], 4);
|
||
|
rr->soa.retry = ntohl (u32);
|
||
|
|
||
|
/* El expire */
|
||
|
memcpy (&u32, &buf[tot + 12], 4);
|
||
|
rr->soa.expire = ntohl (u32);
|
||
|
|
||
|
/* El minimum */
|
||
|
memcpy (&u32, &buf[tot + 16], 4);
|
||
|
rr->soa.minimum = ntohl (u32);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int dns_rr_unpack_ptr_data (DNSRR *rr, unsigned char *buf, int rd_length, DNSPacket *packet) {
|
||
|
int save;
|
||
|
save = buf - packet->rdata;
|
||
|
|
||
|
if (dns_packet_expand_name (rr->ptr.name, packet, &save) < 0) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int dns_rr_unpack_mx_data (DNSRR *rr, unsigned char *buf, int rd_length, DNSPacket *packet) {
|
||
|
int save;
|
||
|
uint16_t u16;
|
||
|
|
||
|
if (rd_length < 2) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
memcpy (&u16, buf, 2);
|
||
|
rr->mx.preference = ntohs (u16);
|
||
|
|
||
|
save = &buf[2] - packet->rdata;
|
||
|
|
||
|
if (dns_packet_expand_name (rr->mx.name, packet, &save) < 0) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int dns_rr_unpack_txt_data (DNSRR *rr, unsigned char *buf, int rd_length) {
|
||
|
/* En la teoría, un TXT puede contener muchas cadenas,
|
||
|
* En la práctica, no creo que ocurra.
|
||
|
* Tomar solo la primer cadena */
|
||
|
uint8_t txt_len;
|
||
|
|
||
|
txt_len = buf[0];
|
||
|
|
||
|
if (txt_len > rd_length - 1) {
|
||
|
return -1;
|
||
|
}
|
||
|
memcpy (rr->txt.txt, &buf[1], txt_len);
|
||
|
|
||
|
rr->txt.txt[txt_len] = 0;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int dns_rr_unpack_tsig_data (DNSRR *rr, unsigned char *buf, int rd_length) {
|
||
|
uint32_t t32;
|
||
|
uint16_t t16;
|
||
|
uint8_t t8;
|
||
|
|
||
|
int offset;
|
||
|
|
||
|
offset = 0;
|
||
|
t8 = dns_packet_expand_name_simple (rr->tsig.algorithm, buf, rd_length);
|
||
|
|
||
|
if (t8 < 0) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
offset += t8;
|
||
|
|
||
|
/* Revisar el time, fudge y mac_size */
|
||
|
if (offset + 10 > rd_length) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
/* ¿Ignorar los primeros dos bytes del tiempo? */
|
||
|
memcpy (&t16, &buf[offset], 2);
|
||
|
|
||
|
memcpy (&t32, &buf[offset + 2], 4);
|
||
|
rr->tsig.time_signed = ntohl (t32);
|
||
|
|
||
|
memcpy (&t16, &buf[offset + 6], 2);
|
||
|
rr->tsig.fudge = ntohs (t16);
|
||
|
|
||
|
memcpy (&t16, &buf[offset + 8], 2);
|
||
|
rr->tsig.mac_size = ntohs (t16);
|
||
|
|
||
|
offset += 10;
|
||
|
|
||
|
/* Copiar el MAC */
|
||
|
if (offset + rr->tsig.mac_size > rd_length) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
memcpy (&rr->tsig.mac, &buf[offset], rr->tsig.mac_size);
|
||
|
offset += rr->tsig.mac_size;
|
||
|
|
||
|
/* Revisar el packet id, error y other_len */
|
||
|
if (offset + 6 > rd_length) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
/* Copiar el packet id original */
|
||
|
memcpy (&t16, &buf[offset], 2);
|
||
|
rr->tsig.original_id = ntohs (t16);
|
||
|
|
||
|
memcpy (&t16, &buf[offset + 2], 2);
|
||
|
rr->tsig.error = ntohs (t16);
|
||
|
|
||
|
memcpy (&t16, &buf[offset + 4], 2);
|
||
|
rr->tsig.other_length = ntohs (t16);
|
||
|
|
||
|
offset += 6;
|
||
|
if (rr->tsig.other_length > 0) {
|
||
|
if (offset + rr->tsig.other_length < rd_length) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
memcpy (&rr->tsig.other_data, &buf[offset], rr->tsig.other_length);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
DNSRR * dns_rr_unpack_data (DNSPacket *packet) {
|
||
|
DNSRR *rr;
|
||
|
uint16_t t16;
|
||
|
uint32_t t32;
|
||
|
unsigned char *buf;
|
||
|
int rd_length;
|
||
|
int res;
|
||
|
|
||
|
rr = (DNSRR *) malloc (sizeof (DNSRR));
|
||
|
|
||
|
if (rr == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
memset (rr, 0, sizeof (DNSRR));
|
||
|
|
||
|
if (dns_packet_expand_name (rr->name, packet, &packet->rdread) < 0) {
|
||
|
dns2_rr_free (rr);
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/* Asegurar al menos 10 bytes */
|
||
|
if (packet->rdlength < packet->rdread + 10) {
|
||
|
dns2_rr_free (rr);
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
buf = &packet->rdata[packet->rdread];
|
||
|
packet->rdread += 10;
|
||
|
|
||
|
memcpy (&t16, &buf[0], sizeof (t16));
|
||
|
rr->type = ntohs (t16);
|
||
|
|
||
|
memcpy (&t16, &buf[2], sizeof (t16));
|
||
|
rr->klass = ntohs (t16);
|
||
|
|
||
|
memcpy (&t32, &buf[4], sizeof (t32));
|
||
|
rr->ttl = ntohl (t32);
|
||
|
|
||
|
memcpy (&t16, &buf[8], sizeof (t16));
|
||
|
rd_length = ntohs (t16);
|
||
|
|
||
|
if (packet->rdlength < packet->rdread + rd_length) {
|
||
|
dns2_rr_free (rr);
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
buf = &packet->rdata[packet->rdread];
|
||
|
packet->rdread += rd_length;
|
||
|
|
||
|
res = 0;
|
||
|
switch (rr->type) {
|
||
|
case RR_TYPE_A:
|
||
|
res = dns_rr_unpack_a_data (rr, buf, rd_length);
|
||
|
break;
|
||
|
case RR_TYPE_AAAA:
|
||
|
res = dns_rr_unpack_aaaa_data (rr, buf, rd_length);
|
||
|
break;
|
||
|
case RR_TYPE_NS:
|
||
|
res = dns_rr_unpack_ns_data (rr, buf, rd_length, packet);
|
||
|
break;
|
||
|
case RR_TYPE_CNAME:
|
||
|
res = dns_rr_unpack_cname_data (rr, buf, rd_length, packet);
|
||
|
break;
|
||
|
case RR_TYPE_SOA:
|
||
|
res = dns_rr_unpack_soa_data (rr, buf, rd_length, packet);
|
||
|
break;
|
||
|
case RR_TYPE_PTR:
|
||
|
res = dns_rr_unpack_ptr_data (rr, buf, rd_length, packet);
|
||
|
break;
|
||
|
case RR_TYPE_MX:
|
||
|
res = dns_rr_unpack_mx_data (rr, buf, rd_length, packet);
|
||
|
break;
|
||
|
case RR_TYPE_TXT:
|
||
|
res = dns_rr_unpack_txt_data (rr, buf, rd_length);
|
||
|
break;
|
||
|
case RR_TYPE_TSIG:
|
||
|
res = dns_rr_unpack_tsig_data (rr, buf, rd_length);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (res < 0) {
|
||
|
dns2_rr_free (rr);
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return rr;
|
||
|
}
|
||
|
|
||
|
DNSRR *dns2_rr_dup (const DNSRR *rr) {
|
||
|
DNSRR *new;
|
||
|
|
||
|
new = (DNSRR *) malloc (sizeof (DNSRR));
|
||
|
if (new == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
memcpy (new, rr, sizeof (DNSRR));
|
||
|
|
||
|
if (rr->type == RR_TYPE_TSIG) {
|
||
|
new->tsig.key = strdup (rr->tsig.key);
|
||
|
}
|
||
|
|
||
|
return new;
|
||
|
}
|
||
|
|
||
|
void dns2_rr_free (DNSRR *rr) {
|
||
|
if (rr->type == RR_TYPE_TSIG) {
|
||
|
/* La llave se duplicó, liberarla */
|
||
|
free (rr->tsig.key);
|
||
|
}
|
||
|
|
||
|
free (rr);
|
||
|
}
|
||
|
|