static int harvest_records(struct rfc1035_res *res, struct rfc1035_mxlist **list, struct rfc1035_reply *mxreply, int mxpreference, char *mxname, int q_type, int *found, int flags, int port) { struct rfc1035_reply *areply=0; int index; #if RFC1035_IPV6 struct in6_addr in; #else struct in_addr in; #endif index= -1; if (!mxreply || ( ((index=rfc1035_replysearch_all( res, mxreply, mxname, q_type, RFC1035_CLASS_IN, 0)) < 0 || mxreply->allrrs[index]->rrtype != q_type) && (flags & HARVEST_AUTOQUERY)) ) { index=rfc1035_resolve_cname(res, RFC1035_RESOLVE_RECURSIVE, mxname, q_type, RFC1035_CLASS_IN, &areply, RFC1035_X_RANDOMIZE); if (index < 0) { if (!areply) { if (index == RFC1035_ERR_CNAME_RECURSIVE) return (RFC1035_MX_BADDNS); return (RFC1035_MX_INTERNAL); } if (areply->rcode == RFC1035_RCODE_NXDOMAIN || areply->rcode == RFC1035_RCODE_NOERROR) { rfc1035_replyfree(areply); return (RFC1035_MX_OK); } rfc1035_replyfree(areply); return (RFC1035_MX_SOFTERR); } mxreply=areply; } for ( ; index >= 0 ; index=rfc1035_replysearch_all( res, mxreply, mxname, q_type, RFC1035_CLASS_IN, index+1)) { if (mxreply->allrrs[index]->rrtype != q_type) continue; #if RFC1035_IPV6 if (q_type == RFC1035_TYPE_A) { struct rfc1035_mxlist *q; /* Map it to an IPv4 address */ rfc1035_ipv4to6(&in, &mxreply->allrrs[index]->rr.inaddr); /* See if it's already here */ for (q= *list; q; q=q->next) { struct sockaddr_in6 sin6; if (q->protocol != PF_INET6) continue; memcpy(&sin6, &q->address, sizeof(sin6)); if (memcmp(&sin6.sin6_addr, &in, sizeof(in)) == 0 && q->priority == mxpreference) break; } if ((flags & HARVEST_NODUPE) && q) continue; } else in=mxreply->allrrs[index]->rr.in6addr; #else in.s_addr=mxreply->allrrs[index]->rr.inaddr.s_addr; #endif *found=1; if (addrecord(list, mxname, mxpreference, &in, port)) { if (areply) rfc1035_replyfree(areply); return (RFC1035_MX_INTERNAL); } } if (areply) rfc1035_replyfree(areply); return (RFC1035_MX_OK); }
static int domxlistcreate(struct rfc1035_res *res, const char *q_name, int opts, struct rfc1035_mxlist **list, int port) { char namebuf[RFC1035_MAXNAMESIZE+1]; struct rfc1035_reply *replyp; int index; RFC1035_ADDR in; int seen_softerr=0; int seen_good=0; *list=0; if (rfc1035_aton(q_name, &in) == 0) return (RFC1035_MX_HARDERR); /* Don't gimme an IP address */ namebuf[0]=0; strncat(namebuf, q_name, RFC1035_MAXNAMESIZE); if (namebuf[0] == '[') { char *q=strchr(namebuf, ']'); if (!q || q[1]) return (RFC1035_MX_HARDERR); /* Bad addr */ *q=0; if (rfc1035_aton(namebuf+1, &in)) return (RFC1035_MX_HARDERR); if (addrecord(list, q_name, -1, &in, port)) return (RFC1035_MX_INTERNAL); return (RFC1035_MX_OK); } index=rfc1035_resolve_cname(res, RFC1035_RESOLVE_RECURSIVE, namebuf, RFC1035_TYPE_MX, RFC1035_CLASS_IN, &replyp, RFC1035_X_RANDOMIZE); if (index < 0) { if (!replyp) { if (index == RFC1035_ERR_CNAME_RECURSIVE) return (RFC1035_MX_BADDNS); return (RFC1035_MX_INTERNAL); } if (replyp->rcode == RFC1035_RCODE_NXDOMAIN || replyp->rcode == RFC1035_RCODE_NOERROR) { rfc1035_replyfree(replyp); strcpy(namebuf, q_name); if (opts & RFC1035_MX_AFALLBACK) return (add_arecords(res, list, 0, -1, namebuf, port)); return RFC1035_MX_HARDERR; } rfc1035_replyfree(replyp); return (RFC1035_MX_SOFTERR); } for ( ; index >= 0; index=rfc1035_replysearch_all( res, replyp, namebuf, RFC1035_TYPE_MX, RFC1035_CLASS_IN, index+1)) { char mxname[RFC1035_MAXNAMESIZE+1]; if (replyp->allrrs[index]->rrtype != RFC1035_TYPE_MX) continue; if (rfc1035_replyhostname(replyp, replyp->allrrs[index]->rr.mx.mx_label, mxname) == 0) continue; switch (add_arecords(res, list, replyp, replyp->allrrs[index]->rr.mx.preference, mxname, port)) { case RFC1035_MX_SOFTERR: seen_softerr=1; continue; case RFC1035_MX_INTERNAL: rfc1035_replyfree(replyp); return (RFC1035_MX_INTERNAL); case RFC1035_MX_BADDNS: rfc1035_replyfree(replyp); return (RFC1035_MX_BADDNS); default: seen_good=1; continue; } } rfc1035_replyfree(replyp); if (seen_good && (opts & RFC1035_MX_IGNORESOFTERR)) seen_softerr=0; /* At least some A records were probably fetched */ if (seen_softerr) return (RFC1035_MX_SOFTERR); if (*list) return (RFC1035_MX_OK); return (RFC1035_MX_HARDERR); }
static char *sts_getid(const char *domain) { struct rfc1035_res res; struct rfc1035_reply *replyp; int n; char lookup_domain[RFC1035_MAXNAMESIZE]; char txtbuf[256]; char *id_str=NULL; /* Domain cannot be too long */ if (strlen(domain) >= RFC1035_MAXNAMESIZE-10) return 0; strcat(strcpy(lookup_domain, "_mta-sts."), domain); rfc1035_init_resolv(&res); (void)rfc1035_resolve_cname(&res, lookup_domain, RFC1035_TYPE_TXT, RFC1035_CLASS_IN, &replyp, 0); if (!replyp) { rfc1035_destroy_resolv(&res); return 0; } for (n=0; (n=rfc1035_replysearch_an(&res, replyp, lookup_domain, RFC1035_TYPE_TXT, RFC1035_CLASS_IN, n)) >= 0; ++n) { char *p; rfc1035_rr_gettxt(replyp->allrrs[n], 0, txtbuf); p=strtok(txtbuf, "; "); if (!p || strcmp(p, "v=STSv1")) continue; if (id_str) { /* RFC 8461 prohibits two or more. */ free(id_str); id_str=NULL; break; } id_str=sts_getid1(); if (!id_str) break; } rfc1035_replyfree(replyp); rfc1035_destroy_resolv(&res); return id_str; }