static int gethostnamadr_async_run(struct async *as, struct async_res *ar) { int r, type; FILE *f; char 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; ar->ar_hostent = hostent_file_match(f, as->as_type, as->as.hostnamadr.family, data, as->as.hostnamadr.addrlen); fclose(f); if (ar->ar_hostent == NULL) { if (errno) { ar->ar_errno = errno; ar->ar_h_errno = NETDB_INTERNAL; async_set_state(as, ASR_STATE_HALT); } /* otherwise not found */ break; } ar->ar_h_errno = NETDB_SUCCESS; async_set_state(as, ASR_STATE_HALT); break; #ifdef YP case ASR_DB_YP: /* IPv4 only */ if (as->as.hostnamadr.family != AF_INET) break; if (as->as_type == ASR_GETHOSTBYNAME) data = as->as.hostnamadr.dname; else data = as->as.hostnamadr.addr; ar->ar_hostent = _yp_gethostnamadr(as->as_type, data); if (ar->ar_hostent == NULL) { if (errno) { ar->ar_errno = errno; ar->ar_h_errno = NETDB_INTERNAL; async_set_state(as, ASR_STATE_HALT); } /* otherwise not found */ break; } ar->ar_h_errno = NETDB_SUCCESS; async_set_state(as, ASR_STATE_HALT); break; #endif } 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. */ ar->ar_hostent = hostent_from_packet(as->as_type, as->as.hostnamadr.family, ar->ar_data, ar->ar_datalen); free(ar->ar_data); if (ar->ar_hostent == NULL) { ar->ar_errno = errno; ar->ar_h_errno = NETDB_INTERNAL; async_set_state(as, ASR_STATE_HALT); break; } if (as->as_type == ASR_GETHOSTBYADDR) { if (hostent_add_addr(ar->ar_hostent, as->as.hostnamadr.addr, as->as.hostnamadr.addrlen) == -1) { free(ar->ar_hostent); ar->ar_errno = errno; ar->ar_h_errno = NETDB_INTERNAL; async_set_state(as, ASR_STATE_HALT); break; } } /* * No address found in the dns packet. The blocking version * reports this as an error. */ if (as->as_type == ASR_GETHOSTBYNAME && ar->ar_hostent->h_addr_list[0] == NULL) { free(ar->ar_hostent); async_set_state(as, ASR_STATE_NEXT_DB); break; } ar->ar_h_errno = NETDB_SUCCESS; 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; }
static int gethostnamadr_async_run(struct async *as, struct async_res *ar) { struct hostent_ext *h; int r, type, saved_errno; FILE *f; char name[MAXDNAME], *data, addr[16], *c; 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; } /* Name might be an IP address string */ if (as->as_type == ASR_GETHOSTBYNAME) { for (c = as->as.hostnamadr.name; *c; c++) if (!isdigit(*c) && *c != '.' && *c != ':') break; if (*c == 0 && inet_pton(as->as.hostnamadr.family, as->as.hostnamadr.name, addr) == 1) { h = hostent_from_addr(as->as.hostnamadr.family, as->as.hostnamadr.name, addr); if (h == NULL) { ar->ar_errno = errno; ar->ar_h_errno = NETDB_INTERNAL; } else { ar->ar_hostent = &h->h; ar->ar_h_errno = NETDB_SUCCESS; } async_set_state(as, ASR_STATE_HALT); break; } } async_set_state(as, ASR_STATE_NEXT_DB); break; case ASR_STATE_NEXT_DB: if (asr_iter_db(as) == -1) { 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_search_async_ctx( as->as.hostnamadr.name, C_IN, type, as->as_ctx); } else { asr_addr_as_fqdn(as->as.hostnamadr.addr, as->as.hostnamadr.family, name, sizeof(name)); as->as.hostnamadr.subq = res_query_async_ctx( name, C_IN, T_PTR, 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 = asr_hostalias(as->as_ctx, as->as.hostnamadr.name, name, sizeof(name)); if (data == NULL) data = as->as.hostnamadr.name; } else data = as->as.hostnamadr.addr; h = hostent_file_match(f, as->as_type, as->as.hostnamadr.family, data, as->as.hostnamadr.addrlen); saved_errno = errno; fclose(f); errno = saved_errno; if (h == NULL) { if (errno) { ar->ar_errno = errno; ar->ar_h_errno = NETDB_INTERNAL; async_set_state(as, ASR_STATE_HALT); } /* otherwise not found */ break; } ar->ar_hostent = &h->h; ar->ar_h_errno = NETDB_SUCCESS; async_set_state(as, ASR_STATE_HALT); break; #ifdef YP case ASR_DB_YP: /* IPv4 only */ if (as->as.hostnamadr.family != AF_INET) break; if (as->as_type == ASR_GETHOSTBYNAME) { data = asr_hostalias(as->as_ctx, as->as.hostnamadr.name, name, sizeof(name)); if (data == NULL) data = as->as.hostnamadr.name; } else data = as->as.hostnamadr.addr; h = _yp_gethostnamadr(as->as_type, data); if (h == NULL) { if (errno) { ar->ar_errno = errno; ar->ar_h_errno = NETDB_INTERNAL; async_set_state(as, ASR_STATE_HALT); } /* otherwise not found */ break; } ar->ar_hostent = &h->h; ar->ar_h_errno = NETDB_SUCCESS; async_set_state(as, ASR_STATE_HALT); break; #endif } break; case ASR_STATE_SUBQUERY: /* Run the DNS subquery. */ if ((r = asr_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); as->as.hostnamadr.subq_h_errno = ar->ar_h_errno; async_set_state(as, ASR_STATE_NEXT_DB); break; } /* Read the hostent from the packet. */ h = hostent_from_packet(as->as_type, as->as.hostnamadr.family, ar->ar_data, ar->ar_datalen); free(ar->ar_data); if (h == NULL) { ar->ar_errno = errno; ar->ar_h_errno = NETDB_INTERNAL; async_set_state(as, ASR_STATE_HALT); break; } if (as->as_type == ASR_GETHOSTBYADDR) { if (hostent_add_addr(h, as->as.hostnamadr.addr, as->as.hostnamadr.addrlen) == -1) { free(h); ar->ar_errno = errno; ar->ar_h_errno = NETDB_INTERNAL; async_set_state(as, ASR_STATE_HALT); break; } } /* * No address found in the dns packet. The blocking version * reports this as an error. */ if ((as->as_type == ASR_GETHOSTBYNAME && h->h.h_addr_list[0] == NULL) || (as->as_type == ASR_GETHOSTBYADDR && h->h.h_name == NULL)) { free(h); async_set_state(as, ASR_STATE_NEXT_DB); break; } ar->ar_hostent = &h->h; ar->ar_h_errno = NETDB_SUCCESS; async_set_state(as, ASR_STATE_HALT); break; case ASR_STATE_NOT_FOUND: ar->ar_errno = 0; if (as->as.hostnamadr.subq_h_errno) ar->ar_h_errno = as->as.hostnamadr.subq_h_errno; else 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; }