+ if (af != base->sa.sa_family) return 0;
+ SOCKADDR_IN_IN6_PAIR(const, &base->sa, sbase, &mask->sa, smask, {
+ const struct in_addr *v4 = addr;
+ return (v4->s_addr & smask->sin_addr.s_addr)
+ == sbase->sin_addr.s_addr;
+ }, {
+ int i;
+ const char *a= addr;
+ const char *b= sbase6->sin6_addr.s6_addr;
+ const char *m= smask6->sin6_addr.s6_addr;
+ for (i = 0; i < 16; i++)
+ if ((a[i] & m[i]) != b[i]) return 0;
+ return 1;
+ });
+}
+
+const void *adns__sockaddr_addr(const struct sockaddr *sa) {
+ SOCKADDR_IN_IN6(const, sa, sin, {
+ return &sin->sin_addr;
+ }, {
+ return &sin6->sin6_addr;
+ });
+}
+
+void adns__addr_inject(const void *a, adns_sockaddr *sa) {
+ SOCKADDR_IN_IN6( , &sa->sa, sin, {
+ memcpy(&sin->sin_addr, a, sizeof(sin->sin_addr));
+ }, {
+ memcpy(&sin6->sin6_addr, a, sizeof(sin6->sin6_addr));
+ });
+}
+
+/*
+ * addr2text and text2addr
+ */
+
+#define ADDRFAM_DEBUG
+#ifdef ADDRFAM_DEBUG
+static void af_debug_func(const char *fmt, ...) {
+ int esave= errno;
+ va_list al;
+ va_start(al,fmt);
+ vfprintf(stderr,fmt,al);
+ va_end(al);
+ errno= esave;
+}
+# define af_debug(fmt,...) \
+ (af_debug_func("%s: " fmt "\n", __func__, __VA_ARGS__))
+#else
+# define af_debug(fmt,...) ((void)("" fmt "", __VA_ARGS__))
+#endif
+
+static bool addrtext_our_errno(int e) {
+ return
+ e==EAFNOSUPPORT ||
+ e==EINVAL ||
+ e==ENOSPC ||
+ e==ENOSYS;
+}
+
+static bool addrtext_scope_use_ifname(const struct sockaddr *sa) {
+ const struct in6_addr *in6= &SIN6(const,sa)->sin6_addr;
+ return
+ IN6_IS_ADDR_LINKLOCAL(in6) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(in6);
+}
+
+static int textaddr_check_qf(adns_queryflags flags) {
+ if (flags & ~(adns_queryflags)(adns_qf_addrlit_scope_forbid|
+ adns_qf_addrlit_scope_numeric|
+ adns_qf_addrlit_ipv4_quadonly|
+ 0x40000000))
+ return ENOSYS;
+ return 0;
+}
+
+int adns_text2addr(const char *text, uint16_t port, adns_queryflags flags,
+ struct sockaddr *sa, socklen_t *salen_io) {
+ int r, af;
+ char copybuf[INET6_ADDRSTRLEN];
+ const char *parse=text;
+ const char *scopestr=0;
+ socklen_t needlen;
+ void *dst;
+ uint16_t *portp;
+
+ r= textaddr_check_qf(flags); if (r) return r;
+
+#define INVAL(how) do{ \
+ af_debug("invalid: %s: `%s'", how, text); \
+ return EINVAL; \
+}while(0)
+
+#define AFCORE(INETx,SINx,sinx) \
+ af= AF_##INETx; \
+ dst = &SINx(,sa)->sinx##_addr; \
+ portp = &SINx(,sa)->sinx##_port; \
+ needlen= sizeof(*SINx(,sa));
+
+ if (!strchr(text, ':')) { /* INET */
+
+ AFCORE(INET,SIN,sin);
+
+ } else { /* INET6 */
+
+ AFCORE(INET6,SIN6,sin6);
+
+ const char *percent= strchr(text, '%');
+ if (percent) {
+ ptrdiff_t lhslen = percent - text;
+ if (lhslen >= INET6_ADDRSTRLEN) INVAL("scoped addr lhs too long");
+ memcpy(copybuf, text, lhslen);
+ copybuf[lhslen]= 0;
+
+ parse= copybuf;
+ scopestr= percent+1;
+
+ af_debug("will parse scoped addr `%s' %% `%s'", parse, scopestr);
+ }
+