/****************************************************************************
* Copyright (C) 1998 WIDE Project. All rights reserved.
* Copyright (C) 1999,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_scoped.c,v 1.31 2003/01/27 16:22:46 dillema Exp $>
*/
#include "totd.h"
#ifdef SCOPED_REWRITE
static RRset *conv_scoped_rrset (RRset *);
int conv_scoped_query(Context *context) {
struct sockaddr_in6 *me;
struct sockaddr_in6 *peer;
static int warned = 0;
Nia *ni;
syslog(LOG_DEBUG, "conv_scoped_query(): start");
ni = context->netifaddr;
if (!ni || !ni->sa_p)
return 0;
me =(struct sockaddr_in6 *)ni->sa_p;
if (me->sin6_family != AF_INET6)
return 0;
if (IN6_ARE_ADDR_EQUAL(&me->sin6_addr, &in6addr_any)) {
/* me is wildcard, so lookup our address */
if (!warned)
syslog(LOG_WARNING, "Scoped rewriting not \
implemented for wildcard sockets");
warned = 1;
return 0;
}
peer = (struct sockaddr_in6 *)context->peer;
if (peer->sin6_family != AF_INET6)
return 0;
if (IN6_IS_ADDR_LINKLOCAL(&me->sin6_addr) &&
IN6_IS_ADDR_LINKLOCAL(&peer->sin6_addr)) {
#ifdef HAVE_SIN6_SCOPE_ID
if (me->sin6_scope_id == peer->sin6_scope_id)
return 1; /* good */
if (me->sin6_scope_id)
return 0;
/*
* XXX this is horrible hack to handle case where
* scope_id is in sockaddr, and not in sin6_scope_id
* due to problem with SIOCGIFCONF ioctl. I have this
* problem on my test machine, so I added this code
* to be able to test it all. XXX This code should
* be removed again in the future.
*/
if (!warned)
syslog(LOG_WARNING, "Need hack around your \
sin6_scope_id for SIOCGIFCONF!");
warned = 1;
if ((&me->sin6_addr)->s6_addr[3] == peer->sin6_scope_id)
return 1; /* good */
return 0;
#endif
/* when we don not know, do rewrite */
return 1;
}
if (IN6_IS_ADDR_SITELOCAL(&me->sin6_addr) &&
IN6_IS_ADDR_SITELOCAL(&peer->sin6_addr)) {
#ifdef HAVE_SIN6_SCOPE_ID
if (me->sin6_scope_id == peer->sin6_scope_id)
return 1; /* good */
if (me->sin6_scope_id)
return 0;
/*
* XXX this is horrible hack to handle case where
* scope_id is in sockaddr, and not in sin6_scope_id
* due to problem with SIOCGIFCONF ioctl. I have this
* problem on my test machine, so I added this code
* to be able to test it all. XXX This code should
* be removed again in the future.
*/
if (!warned)
syslog(LOG_WARNING, "Need hack around your \
sin6_scope_id for SIOCGIFCONF!");
warned = 1;
if ((&me->sin6_addr)->s6_addr[3] == peer->sin6_scope_id)
return 1; /* good */
return 0;
#endif
/* when we don not know, do rewrite */
return 1;
}
return 0;
}
static RRset *conv_scoped_rrset(RRset *rrs_old) {
RR_List *rrl = NULL, *rrl_tmp = NULL;
RRset *ret_val = NULL, *rrs_new = NULL;
u_char *rd = NULL, *rd_new = NULL;
RR_List sentinel, *cur;
int i;
syslog(LOG_DEBUG, "conv_scoped_rrset: start");
if (!T.scoped_prefixes) {
ret_val = NULL;
goto finish;
}
memset(&sentinel, 0, sizeof(sentinel));
cur = &sentinel;
if (rrs_old->key.info->r_type != RT_AAAA) {
ret_val = NULL;
goto finish;
}
/* parse A rrset */
rrl = rr_list_of_rrset(rrs_old);
if (!rrl) {
ret_val = NULL;
goto finish;
}
/* convert each RR_List data */
for (rrl_tmp = rrl; rrl_tmp->next; rrl_tmp = rrl_tmp->next) {
rd = rr_rdata(rrl_tmp->rrp);
for (i = 0; i < T.scoped_prefixes; i++) {
if (!memcmp(rd, &T.scoped_from[i], T.scoped_plen[i]/8))
break;
}
if (i >= T.scoped_prefixes)
continue;
/* make a duplicate */
cur->next = rr_list_alloc();
*(cur->next) = *rrl_tmp;
cur->next->rrp = NULL;
cur->next->next = NULL;
rd_new = malloc(sizeof(struct in6_addr));
if (!rd_new) {
rr_list_free(cur->next);
cur->next = NULL;
continue;
}
memcpy(rd_new, &T.scoped_to[i], T.scoped_plen[i] / 8);
memcpy(rd_new + T.scoped_plen[i] / 8, rd + T.scoped_plen[i] / 8,
sizeof(struct in6_addr) - T.scoped_plen[i] / 8);
cur->next->rrp = rr_alloc(rrl_tmp->rrp->ttl,
sizeof(struct in6_addr), rd_new);
if (rd_new)
free (rd_new);
rd_new = NULL;
if (!cur->next->rrp) {
rr_list_free(cur->next);
cur->next = NULL;
continue;
}
while (cur && cur->next)
cur = cur->next;
}
cur->next = rrl;
/* why do we need to count like this? */
i = 0;
for (cur = sentinel.next; cur; cur = cur->next)
i++;
i -= 2;
for (cur = sentinel.next; cur; cur = cur->next)
cur->cnt = i--;
/* assemble AAAA rrset */
rrs_new = rrset_create(RT_AAAA, rrs_old->key.info->r_class,
rrs_old->key.info->owner_len,
rrset_owner(rrs_old), sentinel.next);
if (!rrs_new) {
ret_val = NULL;
goto finish;
}
/* set return value */
ret_val = rrs_new;
rrs_new = NULL;
finish:
if (rrs_new)
rrset_free(rrs_new);
if (sentinel.next)
rr_list_free(sentinel.next);
if (rd_new)
free(rd_new);
syslog(LOG_DEBUG, "conv_scoped_rrset: return");
return ret_val;
}
void conv_scoped_list(G_List *rrsl) {
const char *fn = "conv_scoped_list()";
RRset *rrsp, *rrsp_new;
G_List *gl_tmp;
syslog(LOG_DEBUG, "%s: start", fn);
rrsl->list_data = NULL;
for (gl_tmp = rrsl->next; gl_tmp->list_data; gl_tmp = gl_tmp->next) {
rrsp =(RRset *)gl_tmp->list_data;
if (rrsp->key.info->r_type != RT_AAAA)
continue;
/* add scoped address if necessary */
rrsp_new = conv_scoped_rrset(rrsp);
if (!rrsp_new) {
syslog(LOG_ERR, "Can't add scoped address");
} else {
rrset_free(rrsp);
gl_tmp->list_data = rrsp_new;
rrsp_new = NULL;
}
}
syslog(LOG_DEBUG, "%s: return", fn);
return;
}
int conv_scoped_conf(const char *from, const char *to, int plen) {
const char *fn = "conv_scoped_conf()";
const int max = sizeof(T.scoped_from)/sizeof(T.scoped_from[0]);
if (T.scoped_prefixes >= max) {
syslog(LOG_ERR, "%s: max number of %d prefixes exceeded",
fn, max);
return(-1);
}
if (plen % 8) {
syslog(LOG_ERR, "%s: plen needs to be multiple of 8", fn);
return(-1);
}
if (inet_pton(AF_INET6, from, &T.scoped_from[T.scoped_prefixes]) != 1) {
syslog(LOG_ERR, "invalid format: from %s", from);
return(-1);
}
if (inet_pton(AF_INET6, to, &T.scoped_to[T.scoped_prefixes]) != 1) {
syslog(LOG_ERR, "invalid format: to %s", to);
return(-1);
}
T.scoped_plen[T.scoped_prefixes] = plen;
syslog(LOG_DEBUG, "%s: %s %s", fn, from, to);
T.scoped_prefixes++;
return(0);
}
void conv_scoped_ptr(G_List *rrsl, u_char *qname) {
G_List *gl_tmp;
U_Key rk;
int idx;
u_char *p, *q;
int off;
syslog(LOG_DEBUG, "conv_scoped_ptr: start.");
if (!T.scoped_prefixes) {
syslog (LOG_ERR, "No scoped prefix configured!");
return;
}
idx = conv_is_scoped_ptr(qname, 1);
if (idx == -1)
return;
rrsl->list_data = NULL;
for (gl_tmp = rrsl->next; gl_tmp->list_data; gl_tmp = gl_tmp->next) {
rk = ((RRset *) gl_tmp->list_data)->key;
if (rk.info->r_type != RT_PTR)
continue;
/* convert PTR record from in-addr.arpa to ip6.int */
p = rk.p + KEYINFO_HEAD_LEN;
q = &T.scoped_to[idx].s6_addr[0];
for (off = 0; off < T.scoped_plen[idx] / 8; off++) {
p[64 - 4 - off * 4 + 3] = hex[(q[off] >> 4) & 0x0f];
p[64 - 4 - off * 4 + 1] = hex[q[off] & 0x0f];
}
}
syslog (LOG_DEBUG, "conv_scoped_ptr: return");
return;
}
/*
* returns index of scoped rewrite, if netprefix of qname equals one of scoped
* prefixes. returns -1 if not.
*
* to argument: 0: from 1: to
*/
int conv_is_scoped_ptr(u_char *qname, int to) {
u_char *qname6, *q6;
struct in6_addr a6;
u_char *p;
unsigned int val;
char buf[3];
int i;
if (!T.scoped_prefixes || *qname == '\0')
return -1;
if (!(strstr((char *)qname, "INT") || strstr((char *)qname, "int")))
return -1;
qname6 = (u_char *)strstr((char *)qname, "IP6");
if (!qname6)
qname6 = (u_char *)strstr((char *)qname, "ip6");
if (!qname6)
return -1;
memset(&a6, 0, sizeof(a6));
qname6--;
if (qname6 - qname != 64)
return -1;
qname6--;
q6 = qname6;
p = &a6.s6_addr[0];
while (q6 - 3 >= qname) {
buf[0] = *q6--;
if (*q6-- != 1)
return -1;
buf[1] = *q6--;
if (*q6-- != 1)
return -1;
buf[2] = '\0';
sscanf(buf, "%x", &val);
*p = val & 0xff;
p++;
}
for (i = 0; i < T.scoped_prefixes; i++) {
if (!memcmp(&a6, to ? &T.scoped_to[i] : &T.scoped_from[i],
T.scoped_plen[i] / 8))
return i;
}
return -1;
}
void conv_scoped_ptr_rq(u_char *qname) {
u_char *p, *q;
int off, idx;
idx = conv_is_scoped_ptr(qname, 1);
if (idx == -1)
return;
/* convert PTR record from in-addr.arpa to ip6.int */
p = qname;
q = &T.scoped_from[idx].s6_addr[0];
for (off = 0; off < T.scoped_plen[idx] / 8; off++) {
p[64 - 4 - off * 4 + 3] = hex[(q[off] >> 4) & 0x0f];
p[64 - 4 - off * 4 + 1] = hex[q[off] & 0x0f];
}
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1