/* * Fill the hostent from the given DNS packet. */ static int hostent_from_packet(struct hostent *h, int action, char *pkt, size_t pktlen) { struct packed p; struct header hdr; struct query q; struct rr rr; int r; packed_init(&p, pkt, pktlen); unpack_header(&p, &hdr); for(; hdr.qdcount; hdr.qdcount--) unpack_query(&p, &q); for(; hdr.ancount; hdr.ancount--) { unpack_rr(&p, &rr); if (rr.rr_class != C_IN) continue; switch (rr.rr_type) { case T_CNAME: if (action == ASR_GETHOSTBYNAME) r = hostent_add_alias(h, rr.rr_dname, 1); else r = hostent_set_cname(h, rr.rr_dname, 1); break; case T_PTR: if (action != ASR_GETHOSTBYADDR) continue; r = hostent_set_cname(h, rr.rr.ptr.ptrname, 1); /* XXX See if we need MULTI_PTRS_ARE_ALIASES */ break; case T_A: if (h->h_addrtype != AF_INET) break; r = hostent_set_cname(h, rr.rr_dname, 1); r = hostent_add_addr(h, &rr.rr.in_a.addr, 4); break; case T_AAAA: if (h->h_addrtype != AF_INET6) break; r = hostent_set_cname(h, rr.rr_dname, 1); r = hostent_add_addr(h, &rr.rr.in_aaaa.addr6, 16); break; } } return (0); }
static void dns_dispatch_mx_preference(struct asr_result *ar, void *arg) { struct dns_session *s = arg; struct unpack pack; struct dns_header h; struct dns_query q; struct dns_rr rr; char buf[512]; int error; if (ar->ar_h_errno) { if (ar->ar_rcode == NXDOMAIN) error = DNS_ENONAME; else if (ar->ar_h_errno == NO_RECOVERY || ar->ar_h_errno == NO_DATA) error = DNS_EINVAL; else error = DNS_RETRY; } else { error = DNS_ENOTFOUND; unpack_init(&pack, ar->ar_data, ar->ar_datalen); if (unpack_header(&pack, &h) != -1 && unpack_query(&pack, &q) != -1) { for (; h.ancount; h.ancount--) { if (unpack_rr(&pack, &rr) == -1) break; if (rr.rr_type != T_MX) continue; print_dname(rr.rr.mx.exchange, buf, sizeof(buf)); buf[strlen(buf) - 1] = '\0'; if (!strcasecmp(s->name, buf)) { error = DNS_OK; break; } } } } free(ar->ar_data); m_create(s->p, IMSG_MTA_DNS_MX_PREFERENCE, 0, 0, -1); m_add_id(s->p, s->reqid); m_add_int(s->p, error); if (error == DNS_OK) m_add_int(s->p, rr.rr.mx.preference); m_close(s->p); free(s); }
static void dns_dispatch_mx(struct asr_result *ar, void *arg) { struct dns_session *s = arg; struct unpack pack; struct dns_header h; struct dns_query q; struct dns_rr rr; char buf[512]; size_t found; if (ar->ar_h_errno && ar->ar_h_errno != NO_DATA) { m_create(s->p, IMSG_MTA_DNS_HOST_END, 0, 0, -1); m_add_id(s->p, s->reqid); if (ar->ar_rcode == NXDOMAIN) m_add_int(s->p, DNS_ENONAME); else if (ar->ar_h_errno == NO_RECOVERY) m_add_int(s->p, DNS_EINVAL); else m_add_int(s->p, DNS_RETRY); m_close(s->p); free(s); free(ar->ar_data); return; } found = 0; unpack_init(&pack, ar->ar_data, ar->ar_datalen); if (unpack_header(&pack, &h) == -1 || unpack_query(&pack, &q) == -1) return; for (; h.ancount; h.ancount--) { if (unpack_rr(&pack, &rr) == -1) break; if (rr.rr_type != T_MX) continue; print_dname(rr.rr.mx.exchange, buf, sizeof(buf)); buf[strlen(buf) - 1] = '\0'; dns_lookup_host(s, buf, rr.rr.mx.preference); found++; } free(ar->ar_data); /* fallback to host if no MX is found. */ if (found == 0) dns_lookup_host(s, s->name, 0); }
/* * Fill the hostent from the given DNS packet. */ static struct hostent * hostent_from_packet(int reqtype, int family, char *pkt, size_t pktlen) { struct hostent *h; struct packed p; struct header hdr; struct query q; struct rr rr; if ((h = hostent_alloc(family)) == NULL) return (NULL); packed_init(&p, pkt, pktlen); unpack_header(&p, &hdr); for(; hdr.qdcount; hdr.qdcount--) unpack_query(&p, &q); for(; hdr.ancount; hdr.ancount--) { unpack_rr(&p, &rr); if (rr.rr_class != C_IN) continue; switch (rr.rr_type) { case T_CNAME: if (reqtype == ASR_GETHOSTBYNAME) { if (hostent_add_alias(h, rr.rr_dname, 1) == -1) goto fail; } else { if (hostent_set_cname(h, rr.rr_dname, 1) == -1) goto fail; } break; case T_PTR: if (reqtype != ASR_GETHOSTBYADDR) break; if (hostent_set_cname(h, rr.rr.ptr.ptrname, 1) == -1) goto fail; /* XXX See if we need MULTI_PTRS_ARE_ALIASES */ break; case T_A: if (reqtype != ASR_GETHOSTBYNAME) break; if (family != AF_INET) break; if (hostent_set_cname(h, rr.rr_dname, 1) == -1) goto fail; if (hostent_add_addr(h, &rr.rr.in_a.addr, 4) == -1) goto fail; break; case T_AAAA: if (reqtype != ASR_GETHOSTBYNAME) break; if (family != AF_INET6) break; if (hostent_set_cname(h, rr.rr_dname, 1) == -1) goto fail; if (hostent_add_addr(h, &rr.rr.in_aaaa.addr6, 16) == -1) goto fail; break; } } return (h); fail: free(h); return (NULL); }