+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;
+ }
+ } 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]);
+ }
+
+ css->ptr.domainmap = f;
+ return adns_s_ok;
+}
+