static int addrinfo_from_pkt(struct asr_query *as, char *pkt, size_t pktlen) { struct asr_unpack p; struct asr_dns_header h; struct asr_dns_query q; struct asr_dns_rr rr; int i; union { struct sockaddr sa; struct sockaddr_in sain; struct sockaddr_in6 sain6; } u; char buf[MAXDNAME], *c; _asr_unpack_init(&p, pkt, pktlen); _asr_unpack_header(&p, &h); for (; h.qdcount; h.qdcount--) _asr_unpack_query(&p, &q); for (i = 0; i < h.ancount; i++) { _asr_unpack_rr(&p, &rr); if (rr.rr_type != q.q_type || rr.rr_class != q.q_class) continue; memset(&u, 0, sizeof u); if (rr.rr_type == T_A) { #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN u.sain.sin_len = sizeof u.sain; #endif u.sain.sin_family = AF_INET; u.sain.sin_addr = rr.rr.in_a.addr; u.sain.sin_port = 0; } else if (rr.rr_type == T_AAAA) { #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN u.sain6.sin6_len = sizeof u.sain6; #endif u.sain6.sin6_family = AF_INET6; u.sain6.sin6_addr = rr.rr.in_aaaa.addr6; u.sain6.sin6_port = 0; } else continue; if (as->as.ai.hints.ai_flags & AI_CANONNAME) { _asr_strdname(rr.rr_dname, buf, sizeof buf); buf[strlen(buf) - 1] = '\0'; c = res_hnok(buf) ? buf : NULL; } else if (as->as.ai.hints.ai_flags & AI_FQDN) c = as->as.ai.fqdn; else c = NULL; if (addrinfo_add(as, &u.sa, c)) return (-1); /* errno set */ } return (0); }
/* * Fill the hostent from the given DNS packet. */ static struct hostent_ext * hostent_from_packet(int reqtype, int family, char *pkt, size_t pktlen) { struct hostent_ext *h; struct asr_unpack p; struct asr_dns_header hdr; struct asr_dns_query q; struct asr_dns_rr rr; char dname[MAXDNAME]; if ((h = hostent_alloc(family)) == NULL) return (NULL); _asr_unpack_init(&p, pkt, pktlen); _asr_unpack_header(&p, &hdr); for (; hdr.qdcount; hdr.qdcount--) _asr_unpack_query(&p, &q); strlcpy(dname, q.q_dname, sizeof(dname)); for (; hdr.ancount; hdr.ancount--) { _asr_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 (strcasecmp(rr.rr_dname, dname) == 0) strlcpy(dname, rr.rr.cname.cname, sizeof(dname)); } break; case T_PTR: if (reqtype != ASR_GETHOSTBYADDR) break; if (strcasecmp(rr.rr_dname, dname) != 0) continue; if (hostent_set_cname(h, rr.rr.ptr.ptrname, 1) == -1) hostent_add_alias(h, rr.rr.ptr.ptrname, 1); break; case T_A: if (reqtype != ASR_GETHOSTBYNAME) break; if (family != AF_INET) break; if (hostent_set_cname(h, rr.rr_dname, 1) == -1) ; 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) ; if (hostent_add_addr(h, &rr.rr.in_aaaa.addr6, 16) == -1) goto fail; break; } } return (h); fail: free(h); return (NULL); }