chiark / gitweb /
Do address-family dispatch with lots of switchy functions. wip.base.getaddrinfo
authorMark Wooding <mdw@distorted.org.uk>
Sat, 24 May 2014 13:00:03 +0000 (14:00 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sun, 25 May 2014 13:17:40 +0000 (14:17 +0100)
Instead of the previous table-of-function-pointers approach.  This seems
to have succeeded in pushing more work from call sites into addrfam,
which I think ought to be considered a win.

src/addrfam.c
src/check.c
src/event.c
src/internal.h
src/query.c
src/setup.c
src/types.c

index 3d468b04c6322d19152334e91bbced31ae31631b..af14e67e13e0ab2af8cf5e9d1408f29fee7cedad 100644 (file)
 #include "internal.h"
 
 /*
- * IPv4
+ * General address-family operations.
  */
 
 #define SIN(sa) ((struct sockaddr_in *)(sa))
 #define CSIN(sa) ((const struct sockaddr_in *)(sa))
 
-static const void *inet_sockaddr_to_inaddr(const struct sockaddr *sa)
-  { return &CSIN(sa)->sin_addr; }
+#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();
+}
 
-static int inet_sockaddr_equalp(const struct sockaddr *sa,
-                               const struct sockaddr *sb)
+int adns__af_supported_p(int af)
 {
-  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);
+  switch (af) {
+    AF_CASES(af);
+    af_inet: af_inet6: return 1;
+    default: return 0;
+  }
 }
 
-static void inet_prefix_mask(int len, union gen_addr *mask)
-  { mask->v4.s_addr = htonl(!len ? 0 : 0xffffffff << (32 - len)); }
+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 (memcmp(sin6a->sin6_addr.s6_addr,
+                    sin6b->sin6_addr.s6_addr,
+                    sizeof(sin6a->sin6_addr.s6_addr)) == 0 &&
+             sin6a->sin6_port == sin6b->sin6_port &&
+             sin6a->sin6_scope_id == sin6b->sin6_scope_id);
+    }
+    default:
+      unknown_af(sa->sa_family);
+      return -1;
+  }
+}
 
-static int inet_guess_len(const union gen_addr *addr)
+int adns__gen_pton(const char *p, int *af_r, union gen_addr *addr_r)
 {
-  unsigned a = (ntohl(addr->v4.s_addr) >> 24) & 0xff;
+  static const int aflist[] = { AF_INET6, AF_INET };
+  int i, rc;
 
-  if (a < 128) return 8;
-  else if (a < 192) return 16;
-  else if (a < 224) return 24;
-  else return -1;
+  for (i = 0; i < sizeof(aflist)/sizeof(*aflist); i++) {
+    rc = inet_pton(aflist[i], p, addr_r);
+    assert(rc >= 0);
+    if (rc) { *af_r = aflist[i]; return 1; }
+  }
+  return 0;
 }
 
-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; }
-
-static int inet_rev_parsecomp(const char *p, size_t n)
+int adns__addr_width(int af)
 {
-  int i = 0;
-  if (n > 3) return -1;
-
-  while (n--) {
-    if ('0' <= *p && *p <= '9') i = 10*i + *p++ - '0';
-    else return -1;
+  switch (af) {
+    AF_CASES(af);
+    af_inet: return 32;
+    af_inet6: return 128;
+    default: unknown_af(af); return -1;
   }
-  return i;
 }
 
-static void inet_rev_mkaddr(union gen_addr *addr, const byte *ipv)
+void adns__prefix_mask(int af, int len, union gen_addr *mask_r)
 {
-  addr->v4.s_addr = htonl((ipv[3]<<24) | (ipv[2]<<16) |
-                         (ipv[1]<<8) | (ipv[0]));
+  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;
+  }
 }
 
-static char *inet_rev_mkname(const struct sockaddr *sa, char *buf)
+int adns__guess_prefix_length(int af, const union gen_addr *addr)
 {
-  unsigned long a = ntohl(CSIN(sa)->sin_addr.s_addr);
-  int i;
+  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;
+  }
+}
 
-  for (i = 0; i < 4; i++) {
-    if (i) *buf++ = '.';
-    buf += sprintf(buf, "%d", (int)(a & 0xff));
-    a >>= 8;
+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;
   }
-  return buf;
 }
 
-const afinfo adns__inet_afinfo = {
-  AF_INET, 32, '.', 4, 3, adns_r_a,
-  inet_sockaddr_to_inaddr, inet_sockaddr_equalp,
-  inet_prefix_mask, inet_guess_len, inet_matchp,
-  inet_rev_parsecomp, inet_rev_mkaddr, inet_rev_mkname
-};
+const void *adns__sockaddr_to_inaddr(const struct sockaddr *sa)
+{
+  switch (sa->sa_family) {
+    AF_CASES(af);
+    af_inet: return &CSIN(sa)->sin_addr;
+    af_inet6: return &CSIN6(sa)->sin6_addr;
+    default: unknown_af(sa->sa_family); return 0;
+  }
+}
 
 /*
- * IPv6
+ * Reverse-domain parsing and construction.
  */
 
-#define SIN6(sa) ((struct sockaddr_in6 *)(sa))
-#define CSIN6(sa) ((const struct sockaddr_in6 *)(sa))
+int adns__make_reverse_domain(const struct sockaddr *sa,
+                             const char *zone,
+                             char **buf_io, size_t bufsz,
+                             char **buf_free_r)
+{
+  size_t req;
+  char *p;
+  unsigned c, y;
+  unsigned long aa;
+  const unsigned char *ap;
+  int i, j;
 
-static const void *inet6_sockaddr_to_inaddr(const struct sockaddr *sa)
-  { return &CSIN6(sa)->sin6_addr; }
+  switch (sa->sa_family) {
+    AF_CASES(af);
+    af_inet:
+      req = 4 * 4;
+      if (!zone) zone = "in-addr.arpa";
+      break;
+    af_inet6:
+      req = 2 * 32;
+      if (!zone) zone = "ip6.arpa";
+      break;
+    default:
+      return ENOSYS;
+  }
 
-static int inet6_sockaddr_equalp(const struct sockaddr *sa,
-                                const struct sockaddr *sb)
-{
-  const struct sockaddr_in6 *sin6a = CSIN6(sa), *sin6b = CSIN6(sb);
-  return (memcmp(sin6a->sin6_addr.s6_addr,
-                sin6b->sin6_addr.s6_addr,
-                sizeof(sin6a->sin6_addr.s6_addr)) == 0 &&
-         sin6a->sin6_port == sin6b->sin6_port &&
-         sin6a->sin6_scope_id == sin6b->sin6_scope_id);
-}
+  req += strlen(zone) + 1;
+  if (req <= bufsz)
+    p = *buf_io;
+  else {
+    p = malloc(req); if (!p) return errno;
+    *buf_free_r = p;
+  }
 
-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;
+  *buf_io = p;
+  switch (sa->sa_family) {
+    AF_CASES(bf);
+    bf_inet:
+      aa = ntohl(CSIN(sa)->sin_addr.s_addr);
+      for (i = 0; i < 4; i++) {
+       p += sprintf(p, "%d", (int)(aa & 0xff));
+       *p++ = '.';
+       aa >>= 8;
+      }
+      break;
+    bf_inet6:
+      ap = CSIN6(sa)->sin6_addr.s6_addr + 16;
+      for (i = 0; i < 16; i++) {
+       c = *--ap;
+       for (j = 0; j < 2; j++) {
+         y = c & 0xf;
+         if (y < 10) *p++ = y + '0';
+         else *p++ = y - 10 + 'a';
+         c >>= 4;
+         *p++ = '.';
+       }
+      }
+      break;
+    default:
+      unknown_af(sa->sa_family);
+  }
 
-  assert(len < 128);
-  memset(m, 0xff, i);
-  if (j) m[i++] = (0xff << (8-j)) & 0xff;
-  memset(m + i, 0, 16-i);
+  strcpy(p, zone);
+  return 0;
 }
 
-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)
+static int inet_rev_parsecomp(const char *p, size_t n)
 {
-  int i;
-  const char *a = addr->v6.s6_addr;
-  const char *b = base->v6.s6_addr;
-  const char *m = mask->v6.s6_addr;
+  int i = 0;
+  if (n > 3) return -1;
 
-  for (i = 0; i < 16; i++)
-    if ((a[i] & m[i]) != b[i]) return 0;
-  return 1;
+  while (n--) {
+    if ('0' <= *p && *p <= '9') i = 10*i + *p++ - '0';
+    else return -1;
+  }
+  return i;
+}
+
+static void inet_rev_mkaddr(union gen_addr *addr, const byte *ipv)
+{
+  addr->v4.s_addr = htonl((ipv[3]<<24) | (ipv[2]<<16) |
+                         (ipv[1]<<8) | (ipv[0]));
 }
 
 static int inet6_rev_parsecomp(const char *p, size_t n)
@@ -178,28 +304,82 @@ static void inet6_rev_mkaddr(union gen_addr *addr, const byte *ipv)
     a[i] = (ipv[31-2*i] << 4) | (ipv[30-2*i] << 0);
 }
 
-static char *inet6_rev_mkname(const struct sockaddr *sa, char *buf)
-{
-  const unsigned char *a = CSIN6(sa)->sin6_addr.s6_addr + 16;
-  unsigned c, y;
-  int i, j;
+static const struct revparse_domain {
+  int af;                              /* address family */
+  int nrevlab;                         /* n of reverse-address labels */
+  adns_rrtype rrtype;                  /* forward-lookup type */
+
+  int (*rev_parsecomp)(const char *p, size_t n);
+  /* parse a single component from a label; return the integer value, or -1
+   * if it was unintelligible.
+   */
+
+  void (*rev_mkaddr)(union gen_addr *addr, const byte *ipv);
+  /* write out the parsed address from a vector of parsed components */
+
+  const char *const tail[3];           /* tail label names */
+} revparse_domains[NREVDOMAINS] = {
+  { AF_INET, 4, adns_r_a, inet_rev_parsecomp, inet_rev_mkaddr,
+    { DNS_INADDR_ARPA, 0 } },
+  { AF_INET6, 32, adns_r_aaaa, inet6_rev_parsecomp, inet6_rev_mkaddr,
+    { DNS_IP6_ARPA, 0 } },
+};
 
-  for (i = 0; i < 16; i++) {
-    c = *--a;
-    for (j = 0; j < 2; j++) {
-      if (i || j) *buf++ = '.';
-      y = c & 0xf;
-      if (y < 10) *buf++ = y + '0';
-      else *buf++ = y - 10 + 'a';
-      c >>= 4;
+#define REVDOMAIN_MAP(rps, labnum) \
+  ((labnum) ? (rps)->map : (1 << NREVDOMAINS) - 1)
+
+int adns__revparse_label(struct revparse_state *rps, int labnum,
+                        const char *label, int lablen)
+{
+  unsigned f = REVDOMAIN_MAP(rps, labnum);
+  const struct revparse_domain *rpd;
+  const char *tp;
+  unsigned d;
+  int i, ac;
+
+  for (rpd=revparse_domains, i=0, d=1; i<NREVDOMAINS; rpd++, i++, d <<= 1) {
+    if (!(f & d)) continue;
+    if (labnum >= rpd->nrevlab) {
+      tp = rpd->tail[labnum - rpd->nrevlab];
+      if (!tp || strncmp(label, tp, lablen) != 0 || tp[lablen])
+       goto mismatch;
+    } else {
+      ac = rpd->rev_parsecomp(label, lablen);
+      if (ac < 0) goto mismatch;
+      assert(labnum < sizeof(rps->ipv[i]));
+      rps->ipv[i][labnum] = ac;
     }
+    continue;
+
+  mismatch:
+    f &= ~d;
+    if (!f) return -1;
   }
-  return buf;
+
+  rps->map = f;
+  return 0;
 }
 
-const afinfo adns__inet6_afinfo = {
-  AF_INET6, 128, ':', 32, 1, adns_r_aaaa,
-  inet6_sockaddr_to_inaddr, inet6_sockaddr_equalp,
-  inet6_prefix_mask, inet6_guess_len, inet6_matchp,
-  inet6_rev_parsecomp, inet6_rev_mkaddr, inet6_rev_mkname
-};
+int adns__revparse_done(struct revparse_state *rps, int nlabels,
+                       adns_rrtype *rrtype_r, struct af_addr *addr_r)
+{
+  unsigned f = REVDOMAIN_MAP(rps, nlabels);
+  const struct revparse_domain *rpd;
+  unsigned d;
+  int i, found = -1;
+
+  for (rpd=revparse_domains, i=0, d=1; i<NREVDOMAINS; rpd++, i++, d <<= 1) {
+    if (!(f & d)) continue;
+    if (nlabels >= rpd->nrevlab && !rpd->tail[nlabels - rpd->nrevlab])
+      { found = i; continue; }
+    f &= ~d;
+    if (!f) return -1;
+  }
+  assert(found >= 0); assert(f == (1 << found));
+
+  rpd = &revparse_domains[found];
+  *rrtype_r = rpd->rrtype;
+  addr_r->af = rpd->af;
+  rpd->rev_mkaddr(&addr_r->addr, rps->ipv[found]);
+  return 0;
+}
index 6a02ee89987bdd0fbf70547ccb4ed5f4d6f2be9f..eeb7ecdb0d238a52a19a36f4d3ee2455de09537b 100644 (file)
@@ -82,7 +82,7 @@ static void checkc_global(adns_state ads) {
 
   for (i=0; i<ads->nsortlist; i++) {
     sl = &ads->sortlist[i];
-    assert(sl->ai->matchp(&sl->base, &sl->base, &sl->mask));
+    assert(adns__addr_match_p(sl->af,&sl->base, sl->af,&sl->base, &sl->mask));
   }
 
   assert(ads->tcpserver >= 0 && ads->tcpserver < ads->nservers);
index 43b9637c47d7ec0e63d31defdacbd8d23c65402d..e083b896c9119c2fcf1428a47358a38f4a860b69 100644 (file)
@@ -409,9 +409,8 @@ int adns_processreadable(adns_state ads, int fd, const struct timeval *now) {
        }
        for (serv= 0;
             serv < ads->nservers &&
-              !(udpaddr.sa.sa_family == ads->servers[serv].addr.sa.sa_family &&
-                udp->ai->sockaddr_equalp(&udpaddr.sa,
-                                         &ads->servers[serv].addr.sa));
+              !adns__sockaddr_equal_p(&udpaddr.sa,
+                                      &ads->servers[serv].addr.sa);
             serv++);
        if (serv >= ads->nservers) {
          adns__warn(ads,-1,0,"datagram received from unknown nameserver %s",
index bc5f542bb132f7b71ba9213959c561527f008a6e..98f492f06559e65131fa2b49eb6bb77aade42032 100644 (file)
@@ -129,34 +129,17 @@ union gen_addr {
   struct in6_addr v6;
 };
 
+#define NREVDOMAINS 2                  /* keep in sync with addrfam! */
+struct revparse_state {
+  unsigned map;                                /* which domains are still live */
+  byte ipv[NREVDOMAINS][32];           /* address components so far */
+};
+
 union checklabel_state {
-  struct {
-#define PTR_NDOMAIN 2
-    unsigned domainmap;                        /* which domains are still live */
-    byte ipv[PTR_NDOMAIN][32];         /* address components so far */
-  } ptr;
+  struct revparse_state ptr;
 };
 
-typedef struct {
-  int af;
-  int width;
-  int delim;
-  int nrevcomp;
-  int revcompwd;
-  adns_rrtype rrtype;
-  const void *(*sockaddr_to_inaddr)(const struct sockaddr *sa);
-  int (*sockaddr_equalp)(const struct sockaddr *sa,
-                        const struct sockaddr *sb);
-  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);
-  int (*rev_parsecomp)(const char *p, size_t n);
-  void (*rev_mkaddr)(union gen_addr *addr, const byte *ipv);
-  char *(*rev_mkname)(const struct sockaddr *sa, char *buf);
-} afinfo;
-
-struct afinfo_addr { const afinfo *ai; union gen_addr addr; };
+struct af_addr { int af; union gen_addr addr; };
 
 typedef struct {
   void *ext;
@@ -168,7 +151,8 @@ typedef struct {
 
   union {
     struct {
-      struct afinfo_addr addr;
+      adns_rrtype rev_rrtype;
+      struct af_addr addr;
     } ptr;
     struct {
       unsigned want, have;
@@ -385,7 +369,7 @@ struct adns__state {
   struct query_queue udpw, tcpw, childw, output;
   adns_query forallnext;
   int nextid, tcpsocket;
-  struct udpsocket { const afinfo *ai; int fd; } udpsocket[MAXUDP];
+  struct udpsocket { int af; int fd; } udpsocket[MAXUDP];
   int nudp;
   vbuf tcpsend, tcprecv;
   int nservers, nsortlist, nsearchlist, searchndots, tcpserver, tcprecv_skip;
@@ -404,7 +388,7 @@ struct adns__state {
   struct pollfd pollfds_buf[MAX_POLLFDS];
   adns_rr_addr servers[MAXSERVERS];
   struct sortlist {
-    const afinfo *ai;
+    int af;
     union gen_addr base, mask;
   } sortlist[MAXSORTLIST];
   char **searchlist;
@@ -413,7 +397,87 @@ struct adns__state {
 
 /* From addrfam.c: */
 
-extern const afinfo adns__inet_afinfo, adns__inet6_afinfo;
+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__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__gen_pton(const char *p, int *af_r, union gen_addr *addr_r);
+/* Parse an address at p, deciding which address family it belongs to.  On
+ * success, returns 1 (like inet_aton) having stashed the address family in
+ * *af_r and the parsed address in *addr_r.  If the address string is
+ * invalid, returns 0.
+ */
+
+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.
+ */
+
+const void *adns__sockaddr_to_inaddr(const struct sockaddr *sa);
+/* Given a socket address, return a pointer to the actual network address
+ * within it.
+ */
+
+extern int adns__make_reverse_domain(const struct sockaddr *sa,
+                                    const char *zone,
+                                    char **buf_io, size_t bufsz,
+                                    char **buf_free_r);
+/* Construct a reverse domain string, given a socket address and a parent
+ * zone.  If zone is null, then use the standard reverse-lookup zone for the
+ * address family.  If the length of the resulting string is no larger than
+ * bufsz, then the result is stored starting at *buf_io; otherwise a new
+ * buffer is allocated is used, and a pointer to it is stored in both *buf_io
+ * and *buf_free_r (the latter of which should be null on entry).  If
+ * something goes wrong, then an errno value is returned: ENOSYS if the
+ * address family of sa isn't recognized, or ENOMEM if the attempt to
+ * allocate an output buffer failed.
+ */
+
+extern int adns__revparse_label(struct revparse_state *rps, int labnum,
+                               const char *label, int lablen);
+/* Parse a label in a reverse-domain name, given its index labnum (starting
+ * from zero), a pointer to its contents (which need not be null-terminated),
+ * and its length.  The state in *rps is initialized implicitly when labnum
+ * is zero.
+ *
+ * Returns zero if the parse was successful, nonzero if the domain name is
+ * definitely invalid and the parse must be abandoned.
+ */
+
+extern int adns__revparse_done(struct revparse_state *rps, int nlabels,
+                              adns_rrtype *rrtype_r, struct af_addr *addr_r);
+/* Finishes parsing a reverse-domain name, given the total number of labels
+ * in the name.  On success, fills in the address in *addr_r, and the forward
+ * query type in *rrtype_r (because that turns out to be useful).  Returns
+ * nonzero if the parse must be abandoned.
+ */
 
 /* From setup.c: */
 
index 708120faf1855d1ee3c745e1c8f1395fad1c7390..cd04944abdae9728690aac543fd3daff17b69588 100644 (file)
@@ -332,40 +332,15 @@ int adns_submit_reverse_any(adns_state ads,
                            adns_queryflags flags,
                            void *context,
                            adns_query *query_r) {
-  char *buf, *buf_free, *p;
+  char *buf, *buf_free = 0;
   char shortbuf[100];
-  const afinfo *ai;
-  int r, lreq;
+  int r;
 
   flags &= ~adns_qf_search;
 
-  switch (addr->sa_family) {
-    case AF_INET:
-      ai = &adns__inet_afinfo;
-      if (!zone) zone = "in-addr.arpa";
-      break;
-    case AF_INET6:
-      ai = &adns__inet6_afinfo;
-      if (!zone) zone = "ip6.arpa";
-      break;
-    default:
-      return ENOSYS;
-  }
-
-  lreq= strlen(zone) + ai->nrevcomp*(ai->revcompwd + 1) + 1;
-  if (lreq > sizeof(shortbuf)) {
-    buf= malloc(lreq);
-    if (!buf) return errno;
-    buf_free= buf;
-  } else {
-    buf= shortbuf;
-    buf_free= 0;
-  }
-
-  p = ai->rev_mkname(addr, buf);
-  *p++ = '.';
-  strcpy(p, zone);
-
+  buf = shortbuf;
+  r= adns__make_reverse_domain(addr,zone, &buf,sizeof(shortbuf),&buf_free);
+  if (r) return r;
   r= adns_submit(ads,buf,type,flags,context,query_r);
   free(buf_free);
   return r;
index fdbc6d08e23425d276acbf974d00d4dcf12f88d0..6dd8fee9eae1726579cdc2ba9de943d11de1ef58 100644 (file)
 
 static void readconfig(adns_state ads, const char *filename, int warnmissing);
 
-static const afinfo *const transport_aftab[] = {
-  &adns__inet_afinfo,
-  &adns__inet6_afinfo,
-  0
-};
-
-static const afinfo *find_afinfo(int af)
-{
-  int i;
-
-  for (i = 0; transport_aftab[i]; i++)
-    if (transport_aftab[i]->af == af) return transport_aftab[i];
-  return 0;
-}
-
 static void addserver(adns_state ads, struct sockaddr *sa, int n) {
   int i;
   adns_rr_addr *ss;
-  const afinfo *ai;
   char buf[MAX_ADDRSTRLEN];
 
-  ai = find_afinfo(sa->sa_family);
-  if (!ai) {
+  if (!adns__af_supported_p(sa->sa_family)) {
     adns__diag(ads,-1,0,
               "nameserver %s for unknown address family %d ignored",
               adns__sockaddr_ntoa(sa, n, buf), sa->sa_family);
   }
   
   for (i=0; i<ads->nservers; i++) {
-    if (ads->servers[i].addr.sa.sa_family == sa->sa_family &&
-       ai->sockaddr_equalp(sa, &ads->servers[i].addr.sa)) {
+    if (adns__sockaddr_equal_p(sa, &ads->servers[i].addr.sa)) {
       adns__debug(ads,-1,0,"duplicate nameserver %s ignored",
                  adns__sockaddr_ntoa(sa, n, buf));
       return;
@@ -195,7 +177,7 @@ static void ccf_sortlist(adns_state ads, const char *fn,
   const char *maskwhat;
   struct sortlist *sl;
   int l;
-  const afinfo *ai;
+  int af;
   int initial = -1;
 
   if (!buf) return;
@@ -219,45 +201,40 @@ static void ccf_sortlist(adns_state ads, const char *fn,
 
     sl= &ads->sortlist[ads->nsortlist];
 
-    if (strchr(tbuf, ':'))
-      ai= &adns__inet6_afinfo;
-    else
-      ai= &adns__inet_afinfo;
-    
-    if (!inet_pton(ai->af, tbuf, &sl->base)) {
+    if (!adns__gen_pton(tbuf, &af, &sl->base)) {
       configparseerr(ads,fn,lno,"invalid address `%s' in sortlist",tbuf);
       continue;
     }
 
     if (slash) {
-      if (strchr(slash,ai->delim)) {
+      if (slash[strspn(slash, "0123456789")]) {
        maskwhat = "mask";
-       if (!inet_pton(ai->af,slash,&sl->mask)) {
+       if (!inet_pton(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>ai->width) {
+       if (*ep || initial>adns__addr_width(af)) {
          configparseerr(ads,fn,lno,"mask length `%s' invalid",slash);
          continue;
        }
-       ai->prefix_mask(initial, &sl->mask);
+       adns__prefix_mask(af, initial, &sl->mask);
       }
     } else {
       maskwhat = "implied prefix length";
-      initial = ai->guess_len(&sl->base);
+      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;
       }
-      ai->prefix_mask(initial, &sl->mask);
+      adns__prefix_mask(af, initial, &sl->mask);
     }
 
-    if (!ai->matchp(&sl->base, &sl->base, &sl->mask)) {
+    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);
@@ -268,7 +245,7 @@ static void ccf_sortlist(adns_state ads, const char *fn,
       continue;
     }
 
-    sl->ai = ai;
+    sl->af = af;
     ads->nsortlist++;
   }
 }
@@ -631,9 +608,8 @@ static int init_finish(adns_state ads) {
       continue;
     assert(ads->nudp < MAXUDP);
     udp = &ads->udpsocket[ads->nudp];
-    udp->ai = find_afinfo(ads->servers[i].addr.sa.sa_family);
-    assert(udp->ai);
-    udp->fd = socket(udp->ai->af,SOCK_DGRAM,proto->p_proto);
+    udp->af = ads->servers[i].addr.sa.sa_family;
+    udp->fd = socket(udp->af,SOCK_DGRAM,proto->p_proto);
     if (udp->fd < 0) { r= errno; goto x_free; }
     r= adns__setnonblock(ads,udp->fd);
     if (r) { r= errno; goto x_closeudp; }
index ff3691b5c103250eb5ec5c5ea835d6ceedc36024..18cf15939737f1dd49db2e72ff32cc3ab0409a14 100644 (file)
@@ -275,10 +275,9 @@ static int search_sortlist(adns_state ads, int af, const void *ad) {
 
   for (i=0, slp=ads->sortlist;
        i<ads->nsortlist &&
-       !(af == slp->ai->af &&
-        slp->ai->matchp(ad, &slp->base, &slp->mask)) &&
-       !(v6mappedp && slp->ai->af == AF_INET &&
-        slp->ai->matchp(&a, &slp->base, &slp->mask));
+        !adns__addr_match_p(af,ad, slp->af,&slp->base,&slp->mask) &&
+        !(v6mappedp &&
+          adns__addr_match_p(AF_INET,&a, slp->af,&slp->base,&slp->mask));
        i++, slp++);
   return i;
 }
@@ -449,15 +448,7 @@ static adns_status pa_addr(const parseinfo *pai, int cbyte,
 
 static int search_sortlist_sa(adns_state ads, const struct sockaddr *sa)
 {
-  const 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));
+  return search_sortlist(ads, sa->sa_family, adns__sockaddr_to_inaddr(sa));
 }
 
 static int dip_sockaddr(adns_state ads,
@@ -1165,66 +1156,19 @@ static void icb_ptr(adns_query parent, adns_query child) {
   adns__query_fail(parent,adns_s_inconsistent);
 }
 
-static const struct ptr_expectdomain {
-  const afinfo *ai;
-  const char *const tail[3];
-} ptr_expectdomain[PTR_NDOMAIN] = {
-  { &adns__inet_afinfo, { DNS_INADDR_ARPA, 0 } },
-  { &adns__inet6_afinfo, { DNS_IP6_ARPA, 0 } }
-};
-
 static adns_status ckl_ptr(adns_state ads, adns_queryflags flags,
                           union checklabel_state *css, qcontext *ctx,
                           int labnum, const char *label, int lablen)
 {
-  int i, found, ac;
-  unsigned f = labnum ? css->ptr.domainmap : (1 << PTR_NDOMAIN) - 1;
-  unsigned d;
-  const char *tp;
-  const struct ptr_expectdomain *ed;
-  struct afinfo_addr *ap;
-
   if (lablen) {
-    for (ed = ptr_expectdomain, i = 0, d = 1;
-        i < PTR_NDOMAIN;
-        ed++, i++, d <<= 1) {
-      if (!(f & d)) continue;
-      if (labnum < ed->ai->nrevcomp) {
-       ac = ed->ai->rev_parsecomp(label, lablen);
-       if (ac < 0) goto mismatch;
-       assert(labnum < sizeof(css->ptr.ipv[i]));
-       css->ptr.ipv[i][labnum] = ac;
-      } else {
-       tp = ed->tail[labnum - ed->ai->nrevcomp];
-       if (!tp || strncmp(label, tp, lablen) != 0 || tp[lablen])
-         goto mismatch;
-      }
-      continue;
-
-    mismatch:
-      f &= ~d;
-      if (!f) return adns_s_querydomainwrong;
-    }
+    if (adns__revparse_label(&css->ptr, labnum, label,lablen))
+      return adns_s_querydomainwrong;
   } else {
-    found = -1;
-    for (ed = ptr_expectdomain, i = 0, d = 1;
-        i < PTR_NDOMAIN;
-        ed++, i++, d <<= 1) {
-      if (!(f & d)) continue;
-      if (labnum >= ed->ai->nrevcomp && !ed->tail[labnum - ed->ai->nrevcomp])
-       { found = i; continue; }
-      f &= ~d;
-      if (!f) return adns_s_querydomainwrong;
-    }
-    assert(found >= 0 && f == (1 << found));
-
-    ed = &ptr_expectdomain[found];
-    ap = &ctx->tinfo.ptr.addr;
-    ap->ai = ed->ai;
-    ed->ai->rev_mkaddr(&ap->addr, css->ptr.ipv[found]);
+    if (adns__revparse_done(&css->ptr, labnum,
+                           &ctx->tinfo.ptr.rev_rrtype,
+                           &ctx->tinfo.ptr.addr))
+      return adns_s_querydomainwrong;
   }
-
-  css->ptr.domainmap = f;
   return adns_s_ok;
 }
 
@@ -1232,7 +1176,7 @@ static adns_status pa_ptr(const parseinfo *pai, int dmstart,
                          int max, void *datap) {
   char **rrp= datap;
   adns_status st;
-  struct afinfo_addr *ap;
+  adns_rrtype rrtype = pai->qu->ctx.tinfo.ptr.rev_rrtype;
   int cbyte, id;
   adns_query nqu;
   qcontext ctx;
@@ -1243,20 +1187,17 @@ static adns_status pa_ptr(const parseinfo *pai, int dmstart,
   if (st) return st;
   if (cbyte != max) return adns_s_invaliddata;
 
-  ap= &pai->qu->ctx.tinfo.ptr.addr;
-  assert(ap->ai);
-
   st= adns__mkquery_frdgram(pai->ads, &pai->qu->vb, &id,
                            pai->dgram, pai->dglen, dmstart,
-                           ap->ai->rrtype, adns_qf_quoteok_query);
+                           rrtype, adns_qf_quoteok_query);
   if (st) return st;
 
   ctx.ext= 0;
   ctx.callback= icb_ptr;
   memset(&ctx.pinfo,0,sizeof(ctx.pinfo));
   memset(&ctx.tinfo,0,sizeof(ctx.tinfo));
-  st= adns__internal_submit(pai->ads, &nqu, adns__findtype(ap->ai->rrtype),
-                           ap->ai->rrtype, &pai->qu->vb, id,
+  st= adns__internal_submit(pai->ads, &nqu, adns__findtype(rrtype),
+                           rrtype, &pai->qu->vb, id,
                            adns_qf_quoteok_query, pai->now, &ctx);
   if (st) return st;