/* raw versions */
{ adns_r_a, "a" },
+ { adns_r_aaaa, "aaaa" },
{ adns_r_ns_raw, "ns-" },
{ adns_r_soa_raw, "soa-" },
{ adns_r_ptr_raw, "ptr-" },
" 11 usage problems\n"
"\n"
"Query types (see adns.h; default is addr):\n"
- " ns soa ptr mx rp srv addr - enhanced versions\n"
- " cname hinfo txt - types with only one version\n"
- " a ns- soa- ptr- mx- rp- srv- - _raw versions\n"
- " type<number> - `unknown' type, RFC3597\n"
+ " ns soa ptr mx rp srv addr - enhanced versions\n"
+ " cname hinfo txt - types with only one version\n"
+ " a aaaa ns- soa- ptr- mx- rp- srv- - _raw versions\n"
+ " type<number> - `unknown' type, RFC3597\n"
"Default is addr, or ptr for -i/--ptr queries\n",
stdout);
if (ferror(stdout)) sysfail("write usage message",errno);
--- /dev/null
+/*
+ * addrfam.c
+ * - address-family specific code
+ */
+/*
+ * This file is part of adns, which is
+ * Copyright (C) 1997-2000,2003,2006 Ian Jackson
+ * Copyright (C) 1999-2000,2003,2006 Tony Finch
+ * Copyright (C) 1991 Massachusetts Institute of Technology
+ * (See the file INSTALL for full details.)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "internal.h"
+
+/*
+ * IPv4
+ */
+
+#define SIN(sa) ((struct sockaddr_in *)(sa))
+
+static void *inet_sockaddr_to_inaddr(struct sockaddr *sa)
+ { return &SIN(sa)->sin_addr; }
+
+static void inet_prefix_mask(int len, union gen_addr *mask)
+ { mask->v4.s_addr = htonl(!len ? 0 : 0xffffffff << (32 - len)); }
+
+static int inet_guess_len(const union gen_addr *addr)
+{
+ unsigned a = (ntohl(addr->v4.s_addr) >> 24) & 0xff;
+
+ if (a < 128) return 8;
+ else if (a < 192) return 16;
+ else if (a < 224) return 24;
+ else return -1;
+}
+
+static int inet_matchp(const union gen_addr *addr,
+ const union gen_addr *base,
+ const union gen_addr *mask)
+ { return (addr->v4.s_addr & mask->v4.s_addr) == base->v4.s_addr; }
+
+const afinfo adns__inet_afinfo = {
+ AF_INET, 32, '.',
+ inet_sockaddr_to_inaddr, inet_prefix_mask, inet_guess_len, inet_matchp
+};
+
+/*
+ * IPv6
+ */
+
+#define SIN6(sa) ((struct sockaddr_in6 *)(sa))
+
+static void *inet6_sockaddr_to_inaddr(struct sockaddr *sa)
+ { return &SIN6(sa)->sin6_addr; }
+
+static void inet6_prefix_mask(int len, union gen_addr *mask)
+{
+ int i = len/8, j = len%8;
+ unsigned char *m = mask->v6.s6_addr;
+
+ assert(len < 128);
+ memset(m, 0xff, i);
+ if (j) m[i++] = (0xff << (8-j)) & 0xff;
+ memset(m + i, 0, 16-i);
+}
+
+static int inet6_guess_len(const union gen_addr *addr)
+ { return 64; }
+
+static int inet6_matchp(const union gen_addr *addr,
+ const union gen_addr *base,
+ const union gen_addr *mask)
+{
+ int i;
+ const char *a = addr->v6.s6_addr;
+ const char *b = base->v6.s6_addr;
+ const char *m = mask->v6.s6_addr;
+
+ for (i = 0; i < 16; i++)
+ if ((a[i] & m[i]) != b[i]) return 0;
+ return 1;
+}
+
+const afinfo adns__inet6_afinfo = {
+ AF_INET6, 128, ':',
+ inet6_sockaddr_to_inaddr, inet6_prefix_mask, inet6_guess_len, inet6_matchp
+};
adns_r_rp_raw= 17,
adns_r_rp= adns_r_rp_raw|adns__qtf_mail822,
+ adns_r_aaaa= 28,
+
/* For SRV records, query domain without _qf_quoteok_query must look
* as expected from SRV RFC with hostname-like Name. _With_
* _quoteok_query, any query domain is allowed. */
adns_rr_intstr *(*manyistr); /* txt (list strs ends with i=-1, str=0)*/
adns_rr_addr *addr; /* addr */
struct in_addr *inaddr; /* a */
+ struct in6_addr *in6addr; /* aaaa */
adns_rr_hostaddr *hostaddr; /* ns */
adns_rr_intstrpair *intstrpair; /* hinfo */
adns_rr_strpair *strpair; /* rp, rp_raw */
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
LIBOBJS= types.o event.o query.o reply.o general.o setup.o transmit.o \
- parse.o poll.o check.o
+ parse.o poll.o check.o addrfam.o
}
static void checkc_global(adns_state ads) {
+ const struct sortlist *sl;
int i;
assert(ads->udpsocket >= 0);
- for (i=0; i<ads->nsortlist; i++)
- assert(!(ads->sortlist[i].base.s_addr & ~ads->sortlist[i].mask.s_addr));
+ for (i=0; i<ads->nsortlist; i++) {
+ sl = &ads->sortlist[i];
+ assert(sl->ai->matchp(&sl->base, &sl->base, &sl->mask));
+ }
assert(ads->tcpserver >= 0 && ads->tcpserver < ads->nservers);
struct timeval now;
} parseinfo;
+union gen_addr {
+ struct in_addr v4;
+ struct in6_addr v6;
+};
+
+typedef struct {
+ int af;
+ int width;
+ int delim;
+ void *(*sockaddr_to_inaddr)(struct sockaddr *sa);
+ void (*prefix_mask)(int len, union gen_addr *a);
+ int (*guess_len)(const union gen_addr *a);
+ int (*matchp)(const union gen_addr *addr,
+ const union gen_addr *base, const union gen_addr *mask);
+} afinfo;
+
typedef struct typeinfo {
adns_rrtype typekey;
const char *rrtname;
struct in_addr addr;
} servers[MAXSERVERS];
struct sortlist {
- struct in_addr base, mask;
+ const afinfo *ai;
+ union gen_addr base, mask;
} sortlist[MAXSORTLIST];
char **searchlist;
unsigned short rand48xsubi[3];
};
+/* From addrfam.c: */
+
+extern const afinfo adns__inet_afinfo, adns__inet6_afinfo;
+
/* From setup.c: */
int adns__setnonblock(adns_state ads, int fd); /* => errno value */
const char *word;
char tbuf[200], *slash, *ep;
const char *maskwhat;
- struct in_addr base, mask;
+ struct sortlist *sl;
int l;
- unsigned long initial, baselocal;
+ const afinfo *ai;
+ int initial = -1;
if (!buf) return;
memcpy(tbuf,word,l); tbuf[l]= 0;
slash= strchr(tbuf,'/');
if (slash) *slash++= 0;
+
+ sl= &ads->sortlist[ads->nsortlist];
+
+ if (strchr(tbuf, ':'))
+ ai= &adns__inet6_afinfo;
+ else
+ ai= &adns__inet_afinfo;
- if (!inet_aton(tbuf,&base)) {
+ if (!inet_pton(ai->af, tbuf, &sl->base)) {
configparseerr(ads,fn,lno,"invalid address `%s' in sortlist",tbuf);
continue;
}
if (slash) {
- if (strchr(slash,'.')) {
+ if (strchr(slash,ai->delim)) {
maskwhat = "mask";
- if (!inet_aton(slash,&mask)) {
+ if (!inet_pton(ai->af,slash,&sl->mask)) {
configparseerr(ads,fn,lno,"invalid mask `%s' in sortlist",slash);
continue;
}
} else {
maskwhat = "prefix length";
initial= strtoul(slash,&ep,10);
- if (*ep || initial>32) {
+ if (*ep || initial>ai->width) {
configparseerr(ads,fn,lno,"mask length `%s' invalid",slash);
continue;
}
- mask.s_addr= htonl((0x0ffffffffUL) << (32-initial));
+ ai->prefix_mask(initial, &sl->mask);
}
} else {
- maskwhat = "implied mask";
- baselocal= ntohl(base.s_addr);
- if (!baselocal & 0x080000000UL) /* class A */
- mask.s_addr= htonl(0x0ff000000UL);
- else if ((baselocal & 0x0c0000000UL) == 0x080000000UL)
- mask.s_addr= htonl(0x0ffff0000UL); /* class B */
- else if ((baselocal & 0x0f0000000UL) == 0x0e0000000UL)
- mask.s_addr= htonl(0x0ff000000UL); /* class C */
- else {
+ maskwhat = "implied prefix length";
+ initial = ai->guess_len(&sl->base);
+ if (initial < 0) {
configparseerr(ads,fn,lno, "network address `%s'"
" in sortlist is not in classed ranges,"
" must specify mask explicitly", tbuf);
continue;
}
+ ai->prefix_mask(initial, &sl->mask);
}
- if (base.s_addr & ~mask.s_addr) {
- configparseerr(ads,fn,lno, "%s `%s' in sortlist"
- " overlaps address `%s'",maskwhat,
- slash ? slash : inet_ntoa(mask), tbuf);
+ if (!ai->matchp(&sl->base, &sl->base, &sl->mask)) {
+ if (initial >= 0) {
+ configparseerr(ads,fn,lno, "%s %d in sortlist"
+ " overlaps address `%s'",maskwhat,initial,tbuf);
+ } else {
+ configparseerr(ads,fn,lno, "%s `%s' in sortlist"
+ " overlaps address `%s'",maskwhat,slash,tbuf);
+ }
continue;
}
- ads->sortlist[ads->nsortlist].base= base;
- ads->sortlist[ads->nsortlist].mask= mask;
+ sl->ai = ai;
ads->nsortlist++;
}
}
* _intstr (mf,csp,cs)
* _manyistr (mf,cs)
* _txt (pa)
- * _inaddr (pa,dip,di)
- * _addr (pa,di,csp,cs)
+ * _inaddr (pa,cs,di, +search_sortlist, dip_genaddr)
+ * _in6addr (pa,cs,di)
+ * _addr (pa,di,csp,cs, +search_sortlist_sa, dip_sockaddr)
* _domain (pap)
* _host_raw (pa)
* _hostaddr (pap,pa,dip,di,mfp,mf,csp,cs +pap_findaddrs)
}
/*
- * _inaddr (pa,dip,di)
+ * _inaddr (pa,di,cs +search_sortlist, dip_genaddr)
*/
static adns_status pa_inaddr(const parseinfo *pai, int cbyte,
return adns_s_ok;
}
-static int search_sortlist(adns_state ads, struct in_addr ad) {
+static int search_sortlist(adns_state ads, int af, const void *ad) {
const struct sortlist *slp;
int i;
for (i=0, slp=ads->sortlist;
- i<ads->nsortlist &&
- !((ad.s_addr & slp->mask.s_addr) == slp->base.s_addr);
+ i<ads->nsortlist && (af != slp->ai->af ||
+ !slp->ai->matchp(ad, &slp->base, &slp->mask));
i++, slp++);
return i;
}
-static int dip_inaddr(adns_state ads, struct in_addr a, struct in_addr b) {
+static int dip_genaddr(adns_state ads, int af, const void *a, const void *b) {
int ai, bi;
if (!ads->nsortlist) return 0;
- ai= search_sortlist(ads,a);
- bi= search_sortlist(ads,b);
+ ai= search_sortlist(ads,af,a);
+ bi= search_sortlist(ads,af,b);
return bi<ai;
}
static int di_inaddr(adns_state ads,
const void *datap_a, const void *datap_b) {
- const struct in_addr *ap= datap_a, *bp= datap_b;
-
- return dip_inaddr(ads,*ap,*bp);
+ return dip_genaddr(ads,AF_INET,datap_a,datap_b);
}
static adns_status cs_inaddr(vbuf *vb, const void *datap) {
}
/*
- * _addr (pa,di,csp,cs)
+ * _in6addr (pa,di,cs)
+ */
+
+static adns_status pa_in6addr(const parseinfo *pai, int cbyte,
+ int max, void *datap) {
+ struct in6_addr *storeto= datap;
+
+ if (max-cbyte != 16) return adns_s_invaliddata;
+ memcpy(storeto->s6_addr, pai->dgram + cbyte, 16);
+ return adns_s_ok;
+}
+
+static int di_in6addr(adns_state ads,
+ const void *datap_a, const void *datap_b) {
+ return dip_genaddr(ads,AF_INET6,datap_a,AF_INET6,datap_b);
+}
+
+static adns_status cs_in6addr(vbuf *vb, const void *datap) {
+ char buf[INET6_ADDRSTRLEN];
+ const char *ia;
+
+ ia= inet_ntop(AF_INET6, datap, buf, sizeof(buf)); assert(ia);
+ CSP_ADDSTR(ia);
+ return adns_s_ok;
+}
+
+/*
+ * _addr (pa,di,csp,cs, +search_sortlist_sa, dip_sockaddr)
*/
static adns_status pa_addr(const parseinfo *pai, int cbyte,
return adns_s_ok;
}
+static int search_sortlist_sa(adns_state ads, const struct sockaddr *sa)
+{
+ const struct afinfo *ai = 0;
+
+ switch (sa->sa_family) {
+ case AF_INET: ai = &adns__inet_afinfo; break;
+ case AF_INET6: ai = &adns__inet6_afinfo; break;
+ }
+ assert(ai);
+
+ return search_sortlist(ads, sa->sa_family, ai->sockaddr_to_inaddr(sa));
+}
+
+static int dip_sockaddr(adns_state ads,
+ const struct sockaddr *sa,
+ const struct sockaddr *sb)
+{
+ if (!ads->sortlist) return 0;
+ return search_sortlist_sa(ads, sa) > search_sortlist_sa(ads, sb);
+}
+
static int di_addr(adns_state ads, const void *datap_a, const void *datap_b) {
const adns_rr_addr *ap= datap_a, *bp= datap_b;
- assert(ap->addr.sa.sa_family == AF_INET);
- return dip_inaddr(ads, ap->addr.inet.sin_addr, bp->addr.inet.sin_addr);
+ return dip_sockaddr(ads, &ap->addr.sa, &bp->addr.sa);
}
static int div_addr(void *context, const void *datap_a, const void *datap_b) {
if (ap->astatus != bp->astatus) return ap->astatus;
if (ap->astatus) return 0;
- assert(ap->addrs[0].addr.sa.sa_family == AF_INET);
- assert(bp->addrs[0].addr.sa.sa_family == AF_INET);
- return dip_inaddr(ads,
- ap->addrs[0].addr.inet.sin_addr,
- bp->addrs[0].addr.inet.sin_addr);
+ return dip_sockaddr(ads, &ap->addrs[0].addr.sa, &bp->addrs[0].addr.sa);
}
static int di_hostaddr(adns_state ads,
DEEP_TYPE(mx_raw, "MX", "raw",intstr, pa_mx_raw, di_mx_raw,cs_inthost ),
DEEP_TYPE(txt, "TXT", 0, manyistr,pa_txt, 0, cs_txt ),
DEEP_TYPE(rp_raw, "RP", "raw",strpair, pa_rp, 0, cs_rp ),
+FLAT_TYPE(aaaa, "AAAA", 0, in6addr, pa_in6addr, di_in6addr,cs_in6addr ),
XTRA_TYPE(srv_raw,"SRV", "raw",srvraw , pa_srvraw, di_srv, cs_srvraw,
qdpl_srv, postsort_srv),