/****************************************************************************
* Copyright (C) 1998 WIDE Project. All rights reserved.
* Copyright (C) 1999,2000,2001,2002 University of Tromso. All rights reserved.
* Copyright (C) 2002 Invenia Innovation AS. All rights reserved.
*
* Author: Feike W. Dillema, feico@pasta.cs.uit.no.
* based on newbie code by Yusuke DOI, Keio Univ. Murai Lab.
****************************************************************************/
/*
* <$Id: conv_trick.c,v 3.47 2002/12/11 16:39:49 dillema Exp $>
*/
#include "totd.h"
static RRset *conv_trick_rrset (RRset *, uint16_t, int);
static RRset *conv_trick_rrset (RRset *rrs_a, uint16_t qtype, int pref) {
const char *fn = "conv_trick_rrset()";
RR_List *rrl = NULL, *rrl_tmp;
RRset *rrs_new = NULL;
RR *rr_a = NULL, *rr_new = NULL;
u_char *rd, *rd_new = NULL;
syslog (LOG_DEBUG, "%s: start", fn);
/* parse A resource record set */
rrl = rr_list_of_rrset (rrs_a);
if (!rrl)
return NULL;
/* convert each RR_List data */
for (rrl_tmp = rrl; rrl_tmp->next; rrl_tmp = rrl_tmp->next) {
int rdlen;
u_char *rd_addr;
rr_a = rrl_tmp->rrp;
rrl_tmp->rrp = NULL; /* kept in rr_a */
rd = rr_rdata (rr_a);
rdlen = sizeof(struct in6_addr);
if (qtype == RT_A6)
rdlen++; /* size of prefix length */
rd_new = malloc (rdlen);
if (!rd_new)
break;
rd_addr = (qtype == RT_AAAA) ? rd_new : (rd_new + 1);
memcpy (rd_addr, T.prefix[pref], 12);
memcpy (rd_addr + 12, rd, 4);
if (qtype == RT_A6)
*rd_new = 0; /* plen is 0 */
rr_new = rr_alloc (rr_a->ttl, rdlen, rd_new);
if (!rr_new)
break;
free (rd_new);
rd_new = NULL; /* kept in rr_new */
rrl_tmp->rrp = rr_new;
rr_new = NULL; /* kept in rrl_tmp->rrp */
free (rr_a);
rr_a = NULL;
}
/* assemble A6/AAAA rrset */
rrs_new = rrset_create (qtype, rrs_a->key.info->r_class,
rrs_a->key.info->owner_len,
rrset_owner (rrs_a), rrl);
/* cleanup */
if (rr_a)
free (rr_a);
if (rr_new)
free (rr_new);
if (rrl)
rr_list_free (rrl);
if (rd_new)
free (rd_new);
return rrs_new;
}
/* target_rtype should be either RT_A6 or RT_AAAA */
void conv_trick_list (G_List *rrsl, int target_rtype, int add) {
const char *fn = "conv_trick_list()";
RRset *rrsp, *rrsp_aaaa;
u_char str[MAX_DNAME];
G_List *gl;
syslog (LOG_DEBUG, "%s: start", fn);
rrsl->list_data = NULL;
for (gl = rrsl->next; gl->list_data; gl = gl->next) {
RRset *dup;
char *name;
int len;
rrsp = (RRset *) gl->list_data;
if (rrsp->key.info->r_type != RT_A)
continue;
name = rrset_owner(rrsp);
len = rrsp->key.info->owner_len;
dup = search_name(rrsl, name, len, target_rtype);
if (dup) {
if (T.debug > 3) {
dname_decompress (str, MAX_DNAME, name, 0,0,0);
syslog (LOG_DEBUG, "%s: duplicate %s", fn, str);
}
rrset_free(dup);
continue;
}
/* convert A record into faked target_rtype record */
if (T.debug > 3) {
dname_decompress (str, MAX_DNAME, name, 0,0,0);
syslog (LOG_DEBUG, "%s: converting: %s", fn, str);
}
rrsp_aaaa = conv_trick_rrset(rrsp, target_rtype,
T.current_prefix);
if (!rrsp_aaaa) {
syslog (LOG_ERR, "%s: Can't convert A to AAAA", fn);
continue;
}
if (T.debug) {
dname_decompress (str, MAX_DNAME, name, 0,0,0);
syslog (LOG_DEBUG, "%s: %s %s", fn,
add ? "add" : "replace by", str);
}
if (add) {
list_add (rrsl, rrsp_aaaa);
} else {
rrset_free (rrsp);
gl->list_data = rrsp_aaaa;
}
}
return;
}
void conv_trick_ptr (G_List *rrsl, u_char *qname) {
const char *fn = "conv_trick_ptr()";
U_Key rk, rk_new;
G_List *gl;
syslog (LOG_DEBUG, "%s: start", fn);
if (*qname == '\0')
return;
rrsl->list_data = NULL;
for (gl = rrsl->next; gl->list_data; gl = gl->next) {
rk = ((RRset *) gl->list_data)->key;
if (rk.info->r_type == RT_PTR) {
/* convert PTR record from in-addr.arpa to ip6.int */
rk_new.p = malloc (KEYINFO_HEAD_LEN +
strlen((char *)qname) + 1);
if (rk_new.p) {
rk_new.info->r_type = RT_PTR;
rk_new.info->r_class = C_IN;
strcpy((char *)(rk_new.p + KEYINFO_HEAD_LEN),
(char *)qname);
free (rk.p);
((RRset *) gl->list_data)->key = rk_new;
} else
syslog (LOG_ERR, "Cannot allocate memory");
}
}
return;
}
void conv_trick_newptr (G_List *rrsl, u_char *qname) {
const char *fn = "conv_trick_newptr()";
G_List *gl;
U_Key rk, rk_new;
size_t qlen;
syslog (LOG_DEBUG, "%s: start", fn);
if (*qname == '\0')
return;
rrsl->list_data = NULL;
for (gl = rrsl->next; gl->list_data;
gl = gl->next) {
rk = ((RRset *) gl->list_data)->key;
if (rk.info->r_type == RT_PTR) {
/*
* convert PTR record from in-addr.arpa to
* ip6.arpa.
*/
qlen = strlen(qname) + 1;
rk_new.p = malloc (KEYINFO_HEAD_LEN + qlen);
if (rk_new.p) {
rk_new.info->r_type = RT_PTR;
rk_new.info->r_class = C_IN;
memcpy(rk_new.p+KEYINFO_HEAD_LEN, qname, qlen);
free (rk.p);
((RRset *) gl->list_data)->key = rk_new;
} else
syslog (LOG_ERR, "Out of memory");
}
}
return;
}
int conv_trick_conf (u_char *v6addr) {
const char *fn = "conv_trick_conf()";
if (T.prefixnum >= MAXPREFIXES)
syslog (LOG_ERR, "%s: max number of %d prefixes exceeded",
fn, MAXPREFIXES);
if (inet_pton (AF_INET6, (char *)v6addr,
(void *)T.prefix[T.prefixnum]) == 1) {
syslog (LOG_DEBUG, "%s: %s", fn, v6addr);
/* SUCCESS */
T.prefixnum++;
return (0);
} else
syslog (LOG_ERR, "%s: invalid IPv6 prefix: %s", fn, v6addr);
/* FAILURE */
return (-1);
}
/*
* returns 1 if netprefix of qname equals one of tot prefixes, else returns 0
*/
int conv_trick_is_tot_ptr (u_char *qname) {
struct in6_addr a6;
u_char *qname6, *q6;
u_char *p, buf[3];
unsigned int val;
int i;
const int cmpsiz = sizeof(struct in6_addr) - sizeof(struct in_addr);
if (!T.prefixnum || *qname == '\0')
return 0;
if (!(strstr((char *)qname, "INT") || strstr((char *)qname, "int")))
return 0;
qname6 = (u_char *) strstr((char *)qname, "IP6");
if (!qname6)
qname6 = (u_char *) strstr((char *)qname, "ip6");
if (!qname6)
return 0;
memset(&a6, 0, sizeof(a6));
qname6--;
if (qname6 - qname != 64)
return 0;
qname6--;
q6 = qname6;
p = &a6.s6_addr[0];
while (q6 - 4 >= qname) {
buf[0] = *q6--;
if (*q6-- != 1)
return 0;
buf[1] = *q6--;
if (*q6-- != 1)
return 0;
buf[2] = '\0';
sscanf((char *)buf, "%x", &val);
*p++ = val & 0xff;
}
for (i = 0; i < T.prefixnum; i++) {
if (memcmp(&a6, &T.prefix[i], cmpsiz) == 0)
return 1; /* got a match */
}
return 0;
}
void conv_trick_ptr_rq (u_char *qname) {
u_char *qname6, tmpaddr[8];
int len, i, tmp;
if (*qname == '\0')
return;
len = 0;
qname6 = qname;
while (len < 8) {
strncpy ((char *) tmpaddr + len, (char *) qname6 + 1, (int) *qname6);
len += (int) *qname6;
qname6 += ((int) *qname6) + 1;
}
for (i = 0; i < 8; i++) {
if (isdigit (tmpaddr[i]))
tmpaddr[i] -= '0';
else if (isalpha (tmpaddr[i]))
tmpaddr[i] -= isupper (tmpaddr[i]) ? 'A' - 10 : 'a' - 10;
}
for (qname6 = qname, i = 0; i < 8; i += 2) {
tmp = tmpaddr[i] + 16 * tmpaddr[i + 1];
len = snprintf ((char *) qname6 + 1, 4, "%d", tmp);
*qname6 = len;
qname6 += len + 1;
}
*qname6 = '\0'; /* null terminate */
strlcat ((char *) qname, "\007in-addr\004arpa", MAX_DNAME);
return;
}
/*
* Similar routines as above, but for bitstring label + ip6.arpa cases.
* We assume qname has already been validated.
*/
int conv_trick_is_tot_newptr (u_char *qname, struct in6_addr *a6p) {
const int cmpsiz = sizeof(struct in6_addr) - sizeof(struct in_addr);
int ip6len, arpalen, i;
if (!T.prefixnum || *qname == '\0')
return 0;
ip6len = strlen("IP6");
arpalen = strlen("ARPA");
/* we consider "\[x.../128\].ip6.arpa." only */
if (*qname != EDNS0_ELT_BITLABEL || *(qname + 1) != 128)
return 0;
/*
* Copy the 128 bits (16 bytes) ipv6 binary address label for
* later use by caller.
*/
memcpy(a6p, qname + 2, sizeof(*a6p));
/* check the `tail', does it end in IP6.ARPA? */
qname += (2 + sizeof(struct in6_addr)); /* ELT + bitlen + address */
if (*qname != ip6len || (strncasecmp((char *)qname + 1, "IP6", ip6len)
&& strncasecmp((char *)qname + 1, "ip6", ip6len)))
return 0;
else
qname += ip6len + 1;
if (*qname != arpalen ||
(strncasecmp((char *)qname + 1, "ARPA", arpalen) &&
strncasecmp((char *)qname + 1, "arpa", arpalen)))
return 0;
qname += arpalen + 1;
if (*qname != '\0')
return 0;
/* name is OK, now check our list of prefixes */
for (i = 0; i < T.prefixnum; i++) {
if (!memcmp(a6p, &T.prefix[i], cmpsiz))
return 1; /* got a match */
}
return 0;
}
void conv_trick_newptr_rq (u_char *qname, struct in6_addr *a6) {
int len, i;
if (*qname == '\0')
return;
/*
* we take the lower 32 bits (4 bytes) of the ipv6 address as
* ipv4 address, and construct a IPv4 PTR record from it
*/
for (i = 0; i < 4; i++) {
len = snprintf((char *)qname + 1, 4, "%d", a6->s6_addr[15 - i]);
*qname = len;
qname += len + 1;
}
strcpy ((char *)qname, "\007in-addr\004arpa\0");
return;
}
/*
* Search name record in specified record list for given NS record,
* i.e. find the address record, if any, for the given nameserver.
*/
RRset *search_name (G_List *rr_list, char *name, int len, int r_type_search) {
const char *fn = "search_name()";
u_char *tmp_domain;
G_List* gl;
RRset *rrs;
syslog (LOG_DEBUG, "%s: start", fn);
/*
* search for address record (A or AAAA) of the nameserver
* (of NS record) in AR list
*/
rr_list->list_data = NULL; /* extra termination insurance */
for (gl = rr_list->next; gl->list_data; gl = gl->next) {
rrs = (RRset*)gl->list_data;
tmp_domain = rrset_owner(rrs);
if (rrs->key.info->r_type == r_type_search &&
rrs->key.info->owner_len == len &&
!mesg_dname_cmp(NULL, tmp_domain, name))
return rrset_copy(rrs);
}
/* no record found */
return NULL;
}
syntax highlighted by Code2HTML, v. 0.9.1