/* * 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); }
/* * Lookup the first matching entry in the hostfile, either by address or by * name depending on reqtype, and build a hostent from the line. */ static struct hostent_ext * hostent_file_match(FILE *f, int reqtype, int family, const char *data, int datalen) { char *tokens[MAXTOKEN], addr[16], buf[ASR_BUFSIZ + 1]; struct hostent_ext *h; int n, i; for (;;) { n = _asr_parse_namedb_line(f, tokens, MAXTOKEN, buf, sizeof(buf)); if (n == -1) { errno = 0; /* ignore errors reading the file */ return (NULL); } /* there must be an address and at least one name */ if (n < 2) continue; if (reqtype == ASR_GETHOSTBYNAME) { for (i = 1; i < n; i++) { if (strcasecmp(data, tokens[i])) continue; if (inet_pton(family, tokens[0], addr) == 1) goto found; } } else { if (inet_pton(family, tokens[0], addr) == 1 && memcmp(addr, data, datalen) == 0) goto found; } } found: if ((h = hostent_alloc(family)) == NULL) return (NULL); if (hostent_set_cname(h, tokens[1], 0) == -1) goto fail; for (i = 2; i < n; i ++) if (hostent_add_alias(h, tokens[i], 0) == -1) goto fail; if (hostent_add_addr(h, addr, h->h.h_length) == -1) goto fail; return (h); fail: free(h); return (NULL); }
static struct hostent * hostent_from_yp(int family, char *line) { struct hostent *h; char *next, *tokens[10], addr[IN6ADDRSZ]; int i, ntok; if ((h = hostent_alloc(family)) == NULL) return (NULL); for(next = line; line; line = next) { if ((next = strchr(line, '\n'))) { *next = '\0'; next += 1; } ntok = strsplit(line, tokens, 10); if (ntok < 2) continue; if (inet_pton(family, tokens[0], addr) == 1) hostent_add_addr(h, addr, family == AF_INET ? INADDRSZ : IN6ADDRSZ); i = 2; if (!h->h_name) hostent_set_cname(h, tokens[1], 0); else if (strcmp(h->h_name, tokens[1])) i = 1; for (; i < ntok; i++) hostent_add_alias(h, tokens[i], 0); } if (h->h_name == NULL) { free(h); return (NULL); } return (h); }
/* * 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); }
static int gethostnamadr_async_run(struct async *as, struct async_res *ar) { struct hostent *e; int i, n, r, type; FILE *f; char *toks[MAXTOKEN], addr[16], dname[MAXDNAME], *data; next: switch(as->as_state) { case ASR_STATE_INIT: if (as->as.hostnamadr.family != AF_INET && as->as.hostnamadr.family != AF_INET6) { ar->ar_h_errno = NETDB_INTERNAL; ar->ar_errno = EAFNOSUPPORT; async_set_state(as, ASR_STATE_HALT); break; } if ((as->as.hostnamadr.family == AF_INET && as->as.hostnamadr.addrlen != INADDRSZ) || (as->as.hostnamadr.family == AF_INET6 && as->as.hostnamadr.addrlen != IN6ADDRSZ)) { ar->ar_h_errno = NETDB_INTERNAL; ar->ar_errno = EINVAL; async_set_state(as, ASR_STATE_HALT); break; } if (as->as_type == ASR_GETHOSTBYNAME) async_set_state(as, ASR_STATE_NEXT_DOMAIN); else async_set_state(as, ASR_STATE_NEXT_DB); break; case ASR_STATE_NEXT_DOMAIN: r = asr_iter_domain(as, as->as.hostnamadr.name, dname, sizeof(dname)); if (r == -1) { async_set_state(as, ASR_STATE_NOT_FOUND); break; } if (as->as.hostnamadr.dname) free(as->as.hostnamadr.dname); if ((as->as.hostnamadr.dname = strdup(dname)) == NULL) { ar->ar_h_errno = NETDB_INTERNAL; ar->ar_errno = errno; async_set_state(as, ASR_STATE_HALT); } as->as_db_idx = 0; async_set_state(as, ASR_STATE_NEXT_DB); break; case ASR_STATE_NEXT_DB: if (asr_iter_db(as) == -1) { if (as->as_type == ASR_GETHOSTBYNAME) async_set_state(as, ASR_STATE_NEXT_DOMAIN); else async_set_state(as, ASR_STATE_NOT_FOUND); break; } switch(AS_DB(as)) { case ASR_DB_DNS: /* Create a subquery to do the DNS lookup */ if (as->as_type == ASR_GETHOSTBYNAME) { type = (as->as.hostnamadr.family == AF_INET) ? T_A : T_AAAA; as->as.hostnamadr.subq = res_query_async_ctx( as->as.hostnamadr.dname, C_IN, type, NULL, 0, as->as_ctx); } else { addr_as_fqdn(as->as.hostnamadr.addr, as->as.hostnamadr.family, dname, sizeof(dname)); as->as.hostnamadr.subq = res_query_async_ctx( dname, C_IN, T_PTR, NULL, 0, as->as_ctx); } if (as->as.hostnamadr.subq == NULL) { ar->ar_errno = errno; ar->ar_h_errno = NETDB_INTERNAL; async_set_state(as, ASR_STATE_HALT); break; } async_set_state(as, ASR_STATE_SUBQUERY); break; case ASR_DB_FILE: /* Try to find a match in the host file */ if ((f = fopen(as->as_ctx->ac_hostfile, "r")) == NULL) break; if (as->as_type == ASR_GETHOSTBYNAME) data = as->as.hostnamadr.dname; else data = as->as.hostnamadr.addr; if (( n = hostent_file_match(f, as->as_type, as->as.hostnamadr.family, as->as.hostnamadr.addrlen, data, addr, toks, MAXTOKEN)) == -1) { fclose(f); break; } e = hostent_alloc(as->as.hostnamadr.family); if (e == NULL) { ar->ar_errno = errno; ar->ar_h_errno = NETDB_INTERNAL; async_set_state(as, ASR_STATE_HALT); break; } hostent_set_cname(e, toks[1], 0); for (i = 2; i < n; i ++) hostent_add_alias(e, toks[i], 0); hostent_add_addr(e, addr, e->h_length); fclose(f); ar->ar_h_errno = NETDB_SUCCESS; ar->ar_hostent = e; async_set_state(as, ASR_STATE_HALT); break; } break; case ASR_STATE_SUBQUERY: /* Run the DNS subquery. */ if ((r = async_run(as->as.hostnamadr.subq, ar)) == ASYNC_COND) return (ASYNC_COND); /* Done. */ as->as.hostnamadr.subq = NULL; if (ar->ar_datalen == -1) { async_set_state(as, ASR_STATE_NEXT_DB); break; } /* If we got a packet but no anwser, use the next DB. */ if (ar->ar_count == 0) { free(ar->ar_data); async_set_state(as, ASR_STATE_NEXT_DB); break; } /* Read the hostent from the packet. */ if ((e = hostent_alloc(as->as.hostnamadr.family)) == NULL) { ar->ar_errno = errno; ar->ar_h_errno = NETDB_INTERNAL; free(ar->ar_data); async_set_state(as, ASR_STATE_HALT); break; } if (as->as_type == ASR_GETHOSTBYADDR) { e->h_addr_list[0] = malloc(as->as.hostnamadr.addrlen); if (e->h_addr_list[0]) memmove(e->h_addr_list[0], as->as.hostnamadr.addr, as->as.hostnamadr.addrlen); } hostent_from_packet(e, as->as_type, ar->ar_data, ar->ar_datalen); free(ar->ar_data); /* * No address found in the dns packet. The blocking version * reports this as an error. */ if (as->as_type == ASR_GETHOSTBYNAME && e->h_addr_list[0] == NULL) { freehostent(e); async_set_state(as, ASR_STATE_NEXT_DB); break; } ar->ar_h_errno = NETDB_SUCCESS; ar->ar_hostent = e; async_set_state(as, ASR_STATE_HALT); break; case ASR_STATE_NOT_FOUND: ar->ar_errno = 0; ar->ar_h_errno = HOST_NOT_FOUND; async_set_state(as, ASR_STATE_HALT); break; case ASR_STATE_HALT: if (ar->ar_h_errno) ar->ar_hostent = NULL; else ar->ar_errno = 0; return (ASYNC_DONE); default: ar->ar_errno = EOPNOTSUPP; ar->ar_h_errno = NETDB_INTERNAL; ar->ar_gai_errno = EAI_SYSTEM; async_set_state(as, ASR_STATE_HALT); break; } goto next; }
/* * 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); }