/* ** Copyright 1998 - 2019 Double Precision, Inc. ** See COPYING for distribution information. */ #include "rfc1035.h" #include #include #include #include #include /* Convenient function to do forward IP lookup */ #if RFC1035_IPV6 static int rfc1035_a_ipv4(struct rfc1035_res *res, const char *name, struct in_addr **iaptr, unsigned *iasize) #else static int rfc1035_unicode(struct rfc1035_res *res, const char *name, RFC1035_ADDR **iaptr, unsigned *iasize) #endif { struct rfc1035_reply *reply; int n, o; char namebuf[RFC1035_MAXNAMESIZE+1]; namebuf[0]=0; strncat(namebuf, name, RFC1035_MAXNAMESIZE); *iasize=0; if (rfc1035_resolve_cname(res, namebuf, RFC1035_TYPE_A, RFC1035_CLASS_IN, &reply, 0) < 0 || reply == 0 || (n=rfc1035_replysearch_an( res, reply, namebuf, RFC1035_TYPE_A, RFC1035_CLASS_IN, 0)) < 0) { if (reply && reply->rcode != RFC1035_RCODE_NXDOMAIN && reply->rcode != RFC1035_RCODE_NOERROR) { errno=EAGAIN; rfc1035_replyfree(reply); return (1); /* soft error */ } if (reply) rfc1035_replyfree(reply); errno=ENOENT; return (-1); /* hard error */ } for (o=n; o >= 0; o=rfc1035_replysearch_an(res, reply, namebuf, RFC1035_TYPE_A, RFC1035_CLASS_IN, o+1)) ++*iasize; if ( *iasize == 0 ) { errno=EAGAIN; rfc1035_replyfree(reply); return (-1); } if ( (*iaptr=(struct in_addr *)malloc(sizeof(**iaptr)* *iasize)) == 0) { rfc1035_replyfree(reply); return (-1); } for (*iasize=0; n >= 0; n=rfc1035_replysearch_an(res, reply, namebuf, RFC1035_TYPE_A, RFC1035_CLASS_IN, n+1)) { (*iaptr)[*iasize]= reply->allrrs[n]->rr.inaddr; ++*iasize; } rfc1035_replyfree(reply); return (0); } #if RFC1035_IPV6 /* ** The IPv6 version issues two queries - for both A and AAAA records, ** then maps any A record to IPv6. ** ** If we get back both an AAAA for the IPv4-mapped address, and the ** A record itself, ignore the dupe. */ static int we_have_that_ipv4(struct in6_addr in6, const struct in_addr *ia4ptr, unsigned ia4len) { char buf[INET6_ADDRSTRLEN]; const char *p; struct in_addr in4; unsigned i; if (!IN6_IS_ADDR_V4MAPPED((&in6))) return (0); /* Not an IPv4 addy */ if (inet_ntop(AF_INET6, &in6, buf, sizeof(buf)) == 0) return (0); /* WTF??? */ if ((p=strrchr(buf, ':')) != 0) ++p; else p=buf; rfc1035_aton_ipv4(p, &in4); for (i=0; i 0) return (n); if (n < 0) { if (errno != ENOENT) return (n); ia4len=0; ia4ptr=0; enotfound=1; } namebuf[0]=0; strncat(namebuf, name, RFC1035_MAXNAMESIZE); *iasize=ia4len; reply=0; /* ** Resist the temptation to stick in "ia4len > 0 &&", below. Why? ** A) We get a connection from an IPv6 address. ** B) Spam check: the IP address must resolve backwards and forwards. ** C) There are IPv4 records for the same hostname as well. ** D) This sux. */ if (rfc1035_resolve_cname(res, namebuf, RFC1035_TYPE_AAAA, RFC1035_CLASS_IN, &reply, 0) < 0 || reply == 0 || (n=rfc1035_replysearch_an( res, reply, namebuf, RFC1035_TYPE_AAAA, RFC1035_CLASS_IN, 0)) < 0) { if (reply && reply->rcode != RFC1035_RCODE_NXDOMAIN && reply->rcode != RFC1035_RCODE_NOERROR && *iasize == 0) /* Unfortunately this is necessary. Some swervers ** return a TEMPFAIL for AAAA queries. */ { errno=EAGAIN; rfc1035_replyfree(reply); if (ia4len) free(ia4ptr); return (1); /* soft error */ } if (reply) rfc1035_replyfree(reply); if (enotfound) return (-1); enotfound=1; reply=0; n= -1; } else { for (o=n; o >= 0; o=rfc1035_replysearch_an(res, reply, namebuf, RFC1035_TYPE_AAAA, RFC1035_CLASS_IN, o+1)) { if (we_have_that_ipv4(reply->allrrs[n]->rr.in6addr, ia4ptr, ia4len)) continue; ++*iasize; } } if ( *iasize == 0 && enotfound) { if (ia4len) free(ia4ptr); errno=ENOENT; return (-1); } if ( *iasize == 0 ) { errno=EAGAIN; rfc1035_replyfree(reply); return (-1); } if ( (*iaptr=(struct in6_addr *)malloc(sizeof(**iaptr)* *iasize)) == 0) { rfc1035_replyfree(reply); return (-1); } for (*iasize=0; n >= 0; n=rfc1035_replysearch_an(res, reply, namebuf, RFC1035_TYPE_AAAA, RFC1035_CLASS_IN, n+1)) { if (we_have_that_ipv4(reply->allrrs[n]->rr.in6addr, ia4ptr, ia4len)) continue; (*iaptr)[*iasize]= reply->allrrs[n]->rr.in6addr; ++*iasize; } for (k=0; k