/* ** Copyright 1998 - 2011 Double Precision, Inc. ** See COPYING for distribution information. */ #include "rfc1035.h" #include #include static int found(const struct rfc1035_reply *r, const struct rfc1035_rr *rrp, const char *h, unsigned qclass, unsigned qtype) { char namebuf[RFC1035_MAXNAMESIZE+1]; if ((rrp->rrtype != qtype && rrp->rrtype != RFC1035_TYPE_CNAME) || rrp->rrclass != qclass) return (0); if (rfc1035_replyhostname(r, rrp->rrname, namebuf) == 0) return (0); if (rfc1035_hostnamecmp(namebuf, h) == 0) return (1); return (0); } int rfc1035_replysearch_an(const struct rfc1035_res *res, const struct rfc1035_reply *r, const char *h, unsigned qtype, unsigned qclass, int pos) { if (res->rfc1035_defaultdomain && strchr(h, '.') == NULL) { char *buf; int rc; /* Append default domain */ if ((buf=malloc(strlen(h)+ strlen(res->rfc1035_defaultdomain)+2)) == 0) return (-1); strcat(strcat(strcpy(buf, h), "."), res->rfc1035_defaultdomain); rc=rfc1035_replysearch_an(res, r, buf, qtype, qclass, pos); free(buf); return (rc); } for ( ; pos >= 0 && pos < r->ancount; pos++) if (found(r, r->anptr+pos, h, qclass, qtype)) return (pos); return (-1); } int rfc1035_replysearch_ns(const struct rfc1035_res *res, const struct rfc1035_reply *r, const char *h, unsigned qtype, unsigned qclass, int pos) { if (res->rfc1035_defaultdomain && strchr(h, '.') == NULL) { char *buf; int rc; /* Append default domain */ if ((buf=malloc(strlen(h)+ strlen(res->rfc1035_defaultdomain)+2)) == 0) return (-1); strcat(strcat(strcpy(buf, h), "."), res->rfc1035_defaultdomain); rc=rfc1035_replysearch_ns(res, r, buf, qtype, qclass, pos); free(buf); return (rc); } for ( ; pos >= 0 && pos < r->nscount; pos++) if (found(r, r->nsptr+pos, h, qclass, qtype)) return (pos); return (-1); } int rfc1035_replysearch_ar(const struct rfc1035_res *res, const struct rfc1035_reply *r, const char *h, unsigned qtype, unsigned qclass, int pos) { if (res->rfc1035_defaultdomain && strchr(h, '.') == NULL) { char *buf; int rc; /* Append default domain */ if ((buf=malloc(strlen(h)+ strlen(res->rfc1035_defaultdomain)+2)) == 0) return (-1); strcat(strcat(strcpy(buf, h), "."), res->rfc1035_defaultdomain); rc=rfc1035_replysearch_ar(res, r, buf, qtype, qclass, pos); free(buf); return (rc); } for ( ; pos >= 0 && pos < r->arcount; pos++) if (found(r, r->arptr+pos, h, qclass, qtype)) return (pos); return (-1); } int rfc1035_replysearch_all(const struct rfc1035_res *res, const struct rfc1035_reply *r, const char *h, unsigned qtype, unsigned qclass, int pos) { unsigned s; if (res->rfc1035_defaultdomain && strchr(h, '.') == NULL) { char *buf; int rc; /* Append default domain */ if ((buf=malloc(strlen(h)+ strlen(res->rfc1035_defaultdomain)+2)) == 0) return (-1); strcat(strcat(strcpy(buf, h), "."), res->rfc1035_defaultdomain); rc=rfc1035_replysearch_all(res, r, buf, qtype, qclass, pos); free(buf); return (rc); } s=r->ancount+r->nscount+r->arcount; for ( ; pos >= 0 && pos < s; pos++) if (found(r, r->allrrs[pos], h, qclass, qtype)) return (pos); return (-1); } int rfc1035_resolve_cname(struct rfc1035_res *res, char *namebuf, unsigned qtype, unsigned qclass, struct rfc1035_reply **ptr, int x_flags) { int n; int recursion_count=10; if ( (*ptr=rfc1035_resolve(res, RFC1035_OPCODE_QUERY, namebuf, qtype, qclass)) == 0) return (-1); if ((x_flags & RFC1035_X_RANDOMIZE) && (*ptr)->rcode == RFC1035_RCODE_NOERROR) rfc1035_rr_rand(*ptr); if ( (*ptr)->rcode != RFC1035_RCODE_NOERROR || (n=rfc1035_replysearch_an( res, *ptr, namebuf, qtype, qclass, 0))<0) return (-1); if ( (*ptr)->anptr[n].rrtype == qtype) return (n); /* Must've gotten back a CNAME when we were looking for something else */ for (;;) { if (rfc1035_replyhostname( *ptr, (*ptr)->anptr[n].rr.domainname, namebuf) == 0) { rfc1035_replyfree( *ptr ); *ptr=0; return (-1); } /* Let's see if we already have the answer for the canonical name */ if ( (n=rfc1035_replysearch_all( res, *ptr, namebuf, qtype, qclass, 0)) >= 0) { if ( (*ptr)->anptr[n].rrtype == qtype) return (n); if ( --recursion_count > 0) continue; rfc1035_replyfree( *ptr ); /* Recursive CNAME */ *ptr=0; return (RFC1035_ERR_CNAME_RECURSIVE); } rfc1035_replyfree( *ptr ); if ( (*ptr=rfc1035_resolve(res, RFC1035_OPCODE_QUERY, namebuf, qtype, qclass)) == 0) return (-1); if ( (*ptr)->rcode == RFC1035_RCODE_NOERROR && (n=rfc1035_replysearch_an( res, *ptr, namebuf, qtype, qclass, 0)) >= 0) { if ( (*ptr)->anptr[n].rrtype == qtype) return (n); if ( --recursion_count > 0) continue; rfc1035_replyfree( *ptr ); /* Recursive CNAME */ *ptr=0; return (RFC1035_ERR_CNAME_RECURSIVE); } return (-1); } }