libdnsc/src/updater.c

158 lines
2.8 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/poll.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include "dns2.h"
#include "utils.h"
#include "packet.h"
#include "constants.h"
#include "glist.h"
#include "rr.h"
#include "dns2-private.h"
DNS2 *dns2_updater_new (const char *zone) {
DNS2 *updater;
updater = dns2_new ();
if (updater == NULL) {
return NULL;
}
updater->type = DNS_UPDATER;
/* Sanitizar "zona" */
updater->zone = dns_dup_trim_name (zone);
if (updater->zone == NULL) {
free (updater);
return NULL;
}
updater->packet = dns_packet_create_request (updater->zone, RR_TYPE_SOA, RR_CLASS_IN);
if (updater->packet == NULL) {
free (updater->zone);
free (updater);
return NULL;
}
updater->packet->header.opcode = OPCODE_UPDATE;
return updater;
}
int dns_updater_check_name (DNS2 *updater, const char *name) {
int len, nlen;
/* TODO: ¿Usar la zona o el question[0]->qname? */
len = strlen (updater->zone);
nlen = strlen (name);
if (nlen < len) {
return 0;
}
if (strcmp (name, updater->zone) == 0) {
return 1;
}
if (strcmp (&name[nlen - len], updater->zone) != 0) {
return 0;
}
if (name[nlen - len - 1] != '.') {
return 0;
}
return 1;
}
void dns2_updater_add (DNS2 *updater, DNSRR *rr) {
if (dns_updater_check_name (updater, rr->name) == 0) {
/* Fuera de la zona */
return;
}
if (g_list_find (updater->packet->authority, rr) == NULL) {
updater->packet->authority = g_list_append (updater->packet->authority, rr);
}
}
DNSRR * dns_updater_packet_get_tsig (DNSPacket *response) {
int g;
GList *last;
DNSRR *rr;
if (response->header.arcount == 0) {
return NULL;
}
last = g_list_last (response->additional);
while (last != NULL) {
rr = (DNSRR *) last->data;
if (rr->type == RR_TYPE_TSIG) {
return rr;
}
last = last->prev;
}
return NULL;
}
int dns_updater_packet_has_valid_tsig (DNS2 *updater, DNSPacket *response) {
DNSRR *rr, *mysig;
DNSPacket *dup;
rr = dns_updater_packet_get_tsig (response);
if (rr == NULL) {
return 0;
}
if (updater->auth_signature == NULL) {
return 0;
}
/* Eliminar temporalmente el rr de la lista */
response->additional = g_list_remove (response->additional, rr);
response->header.arcount = g_list_length (response->additional);
/* Recalcular la firma, */
mysig = dns2_rr_dup (updater->auth_signature);
if (mysig->type == RR_TYPE_TSIG /*||
mysig->tipo == RR_TYPE_SIG*/) {
dns_rr_pack_generate_signature (mysig, response);
}
/* Comparar firmas */
/* Re-anexar la firma original */
response->additional = g_list_append (response->additional, rr);
response->header.arcount = g_list_length (response->additional);
return 1;
}