--- /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 <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "internal.h"
+
+/*
+ * General address-family operations.
+ */
+
+#define SIN(sa) ((struct sockaddr_in *)(sa))
+#define CSIN(sa) ((const struct sockaddr_in *)(sa))
+
+#define SIN6(sa) ((struct sockaddr_in6 *)(sa))
+#define CSIN6(sa) ((const struct sockaddr_in6 *)(sa))
+
+/* This gadget (thanks, Richard Kettlewell) makes sure that we handle the
+ * same set of address families in each switch. */
+#define AF_CASES(pre) \
+ case AF_INET: goto pre##_inet; \
+ case AF_INET6: goto pre##_inet6
+
+static void unknown_af(int af) {
+ fprintf(stderr, "ADNS INTERNAL: unknown address family %d\n", af);
+ abort();
+}
+
+#define IN6_ADDR_EQUALP(a, b) \
+ (!memcmp((a).s6_addr, (b).s6_addr, sizeof((a).s6_addr)))
+
+int adns__genaddr_equal_p(int af, const union gen_addr *a,
+ int bf, const void *b) {
+ const union gen_addr *bb= b;
+ if (af != bf) return 0;
+ switch (af) {
+ AF_CASES(af);
+ af_inet: return a->v4.s_addr == bb->v4.s_addr;
+ af_inet6: return IN6_ADDR_EQUALP(a->v6, bb->v6);
+ default: unknown_af(af); return -1;
+ }
+}
+
+int adns__sockaddr_equal_p(const struct sockaddr *sa,
+ const struct sockaddr *sb) {
+ if (sa->sa_family != sb->sa_family) return 0;
+ switch (sa->sa_family) {
+ AF_CASES(af);
+ af_inet: {
+ const struct sockaddr_in *sina= CSIN(sa), *sinb= CSIN(sb);
+ return (sina->sin_addr.s_addr == sinb->sin_addr.s_addr &&
+ sina->sin_port == sinb->sin_port);
+ }
+ af_inet6: {
+ /* Don't check the flowlabel. That's apparently useful for routing
+ * performance, but doesn't affect the address in any important
+ * respect. */
+ const struct sockaddr_in6 *sin6a= CSIN6(sa), *sin6b= CSIN6(sb);
+ return (IN6_ADDR_EQUALP(sin6a->sin6_addr, sin6b->sin6_addr) &&
+ sin6a->sin6_port == sin6b->sin6_port &&
+ sin6a->sin6_scope_id == sin6b->sin6_scope_id);
+ }
+ default:
+ unknown_af(sa->sa_family);
+ return -1;
+ }
+}
+
+int adns__addr_width(int af) {
+ switch (af) {
+ AF_CASES(af);
+ af_inet: return 32;
+ af_inet6: return 128;
+ default: unknown_af(af); return -1;
+ }
+}
+
+void adns__prefix_mask(int af, int len, union gen_addr *mask_r) {
+ switch (af) {
+ AF_CASES(af);
+ af_inet:
+ assert(len <= 32);
+ mask_r->v4.s_addr= htonl(!len ? 0 : 0xffffffff << (32-len));
+ break;
+ af_inet6: {
+ int i= len/8, j= len%8;
+ unsigned char *m= mask_r->v6.s6_addr;
+ assert(len <= 128);
+ memset(m, 0xff, i);
+ if (j) m[i++]= (0xff << (8-j)) & 0xff;
+ memset(m+i, 0, 16-i);
+ } break;
+ default:
+ unknown_af(af);
+ break;
+ }
+}
+
+int adns__guess_prefix_length(int af, const union gen_addr *addr) {
+ switch (af) {
+ AF_CASES(af);
+ af_inet: {
+ 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;
+ } break;
+ af_inet6:
+ return 64;
+ default:
+ unknown_af(af);
+ return -1;
+ }
+}
+
+int adns__addr_match_p(int addraf, const union gen_addr *addr,
+ int netaf, const union gen_addr *base,
+ const union gen_addr *mask)
+{
+ if (addraf != netaf) return 0;
+ switch (addraf) {
+ AF_CASES(af);
+ af_inet:
+ return (addr->v4.s_addr & mask->v4.s_addr) == base->v4.s_addr;
+ af_inet6: {
+ 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;
+ } break;
+ default:
+ unknown_af(addraf);
+ return -1;
+ }
+}
+
+void adns__sockaddr_extract(const struct sockaddr *sa,
+ union gen_addr *a_r, int *port_r) {
+ switch (sa->sa_family) {
+ AF_CASES(af);
+ af_inet: {
+ const struct sockaddr_in *sin = CSIN(sa);
+ if (port_r) *port_r= ntohs(sin->sin_port);
+ if (a_r) a_r->v4= sin->sin_addr;
+ break;
+ }
+ af_inet6: {
+ const struct sockaddr_in6 *sin6 = CSIN6(sa);
+ if (port_r) *port_r= ntohs(sin6->sin6_port);
+ if (a_r) a_r->v6= sin6->sin6_addr;
+ break;
+ }
+ default:
+ unknown_af(sa->sa_family);
+ }
+}
+
+void adns__sockaddr_inject(const union gen_addr *a, int port,
+ struct sockaddr *sa) {
+ switch (sa->sa_family) {
+ AF_CASES(af);
+ af_inet: {
+ struct sockaddr_in *sin = SIN(sa);
+ if (port != -1) sin->sin_port= htons(port);
+ if (a) sin->sin_addr= a->v4;
+ break;
+ }
+ af_inet6: {
+ struct sockaddr_in6 *sin6 = SIN6(sa);
+ if (port != -1) sin6->sin6_port= htons(port);
+ if (a) sin6->sin6_addr= a->v6;
+ break;
+ }
+ default:
+ unknown_af(sa->sa_family);
+ }
+}
# 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
assert(ads->udpsocket >= 0);
for (i=0; i<ads->nsortlist; i++) {
- assert(ads->sortlist[i].af==AF_INET);
- assert(!(ads->sortlist[i].base.v4.s_addr &
- ~ads->sortlist[i].mask.v4.s_addr));
sl= &ads->sortlist[i];
- assert(sl->af==AF_INET);
- assert(!(sl->base.v4.s_addr & ~sl->mask.v4.s_addr));
+ assert(adns__addr_match_p(sl->af,&sl->base, sl->af,&sl->base,&sl->mask));
}
assert(ads->tcpserver >= 0 && ads->tcpserver < ads->nservers);
}
for (serv= 0;
serv < ads->nservers &&
- (assert(ads->servers[serv].addr.sa.sa_family==AF_INET),
- ads->servers[serv].addr.inet.sin_addr.s_addr !=
- udpaddr.sin_addr.s_addr);
+ !adns__sockaddr_equal_p(&ads->servers[serv].addr.sa,
+ (const struct sockaddr *)&udpaddr);
serv++);
if (serv >= ads->nservers) {
adns__warn(ads,-1,0,"datagram received from unknown nameserver %s",
unsigned short rand48xsubi[3];
};
+/* From addrfam.c: */
+
+extern int adns__af_supported_p(int af);
+/* Return nonzero if the address family af known to the library and supported
+ * by the other addrfam operations. Note that the other operations will
+ * abort on an unrecognized address family rather than returning an error
+ * code.
+ */
+
+extern int adns__genaddr_equal_p(int af, const union gen_addr *a,
+ int bf, const void *b);
+/* b should point to a `struct in_addr' or equivalent for the address family
+ * bf. Returns nonzero if the two addresses are equal.
+ */
+
+extern int adns__sockaddr_equal_p(const struct sockaddr *sa,
+ const struct sockaddr *sb);
+/* Return nonzero if the two socket addresses are equal (in all significant
+ * respects).
+ */
+
+extern int adns__addr_width(int af);
+/* Return the width of addresses of family af, in bits. */
+
+extern void adns__prefix_mask(int af, int len, union gen_addr *mask_r);
+/* Store in mask_r an address mask for address family af, whose first len
+ * bits are set and the remainder are clear. This is what you want for
+ * converting a prefix length into a netmask.
+ */
+
+extern int adns__guess_prefix_length(int af, const union gen_addr *addr);
+/* Given a network base address, guess the appropriate prefix length based on
+ * the appropriate rules for the address family (e.g., for IPv4, this uses
+ * the old address classes).
+ */
+
+extern int adns__addr_match_p(int addraf, const union gen_addr *addr,
+ int netaf, const union gen_addr *base,
+ const union gen_addr *mask);
+/* Given an address af (with family addraf) and a network (with family netaf,
+ * base address base, and netmask mask), return nonzero if the address lies
+ * within the network.
+ */
+
+extern void adns__sockaddr_extract(const struct sockaddr *sa,
+ union gen_addr *a_r, int *port_r);
+/* Extract fields from the socket address, filling in *a_r and *port_r with
+ * the address and (integer, host byte-order) port number, respectively.
+ * Either (or, pointlessly, both) of a_r and port_r may be null to mean
+ * `don't care'.
+ */
+
+extern void adns__sockaddr_inject(const union gen_addr *a, int port,
+ struct sockaddr *sa);
+/* Inject fields into the socket adress sa. If a is not null, copy the
+ * address in; if port is not -1, then copy the port (converting from host
+ * byte-order). Assumes that sa->sa_family is already set correctly.
+ */
+
/* From setup.c: */
int adns__setnonblock(adns_state ads, int fd); /* => errno value */
adns_rr_addr *ss;
const struct sockaddr_in *sin;
- assert(sa->sa_family==AF_INET); assert(n>=sizeof(*sin));
+ assert(sa->sa_family==AF_INET); /* for inet_ntoa */
sin= (const void *)sa;
for (i=0; i<ads->nservers; i++) {
- assert(ads->servers[i].addr.sa.sa_family==AF_INET);
- if (ads->servers[i].addr.inet.sin_addr.s_addr == sin->sin_addr.s_addr) {
+ if (adns__sockaddr_equal_p(sa, &ads->servers[i].addr.sa)) {
adns__debug(ads,-1,0,"duplicate nameserver %s ignored",
inet_ntoa(sin->sin_addr));
return;
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;
+ int af= AF_UNSPEC;
+ int initial= -1;
if (!buf) return;
memcpy(tbuf,word,l); tbuf[l]= 0;
slash= strchr(tbuf,'/');
if (slash) *slash++= 0;
-
- if (!inet_aton(tbuf,&base)) {
+
+ sl= &ads->sortlist[ads->nsortlist];
+ if (!inet_aton(tbuf, &sl->base.v4)) {
configparseerr(ads,fn,lno,"invalid address `%s' in sortlist",tbuf);
continue;
}
+ af= AF_INET;
if (slash) {
- if (strchr(slash,'.')) {
+ if (slash[strspn(slash, "0123456789")]) {
maskwhat = "mask";
- if (!inet_aton(slash,&mask)) {
+ if (!inet_aton(slash, &sl->mask.v4)) {
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>adns__addr_width(af)) {
configparseerr(ads,fn,lno,"mask length `%s' invalid",slash);
continue;
}
- mask.s_addr= htonl((0x0ffffffffUL) << (32-initial));
+ adns__prefix_mask(af, 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= adns__guess_prefix_length(af, &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;
}
+ adns__prefix_mask(af, 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 (!adns__addr_match_p(af,&sl->base, af,&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].af= AF_INET;
- ads->sortlist[ads->nsortlist].base.v4= base;
- ads->sortlist[ads->nsortlist].mask.v4= mask;
+ sl->af= af;
ads->nsortlist++;
}
}
static int search_sortlist(adns_state ads, int af, const void *ad) {
const struct sortlist *slp;
- const struct in_addr *a4;
int i;
- assert(af==AF_INET);
- a4= ad;
for (i=0, slp=ads->sortlist;
i<ads->nsortlist &&
- (assert(slp->af==AF_INET),
- !((a4->s_addr & slp->mask.v4.s_addr) == slp->base.v4.s_addr));
+ !adns__addr_match_p(af,ad, slp->af,&slp->base,&slp->mask);
i++, slp++);
return i;
}
}
static int search_sortlist_sa(adns_state ads, const struct sockaddr *sa) {
- assert(sa->sa_family == AF_INET);
- return search_sortlist(ads, sa->sa_family,
- &((const struct sockaddr_in *)sa)->sin_addr);
+ union gen_addr a;
+ adns__sockaddr_extract(sa, &a, 0);
+ return search_sortlist(ads, sa->sa_family, &a);
}
+
static int dip_sockaddr(adns_state ads,
const struct sockaddr *sa,
const struct sockaddr *sb) {
}
queried= &parent->ctx.tinfo.ptr.addr;
- assert(queried->af == AF_INET);
assert(cans->type == adns_r_a);
for (i=0, found=cans->rrs.bytes; i<cans->nrrs; i++, found+=cans->rrsz) {
- if (queried->addr.v4.s_addr == ((const struct in_addr *)found)->s_addr) {
+ if (adns__genaddr_equal_p(queried->af,&queried->addr, AF_INET,found)) {
if (!parent->children.head) {
adns__query_done(parent);
return;