/* $Id: dnsproc.c,v 1.9 2017/01/24 13:32:55 jsing Exp $ */ /* * Copyright (c) 2016 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include "extern.h" #ifdef __VMS #include "wcme_config.h" #endif struct addr { int family; /* 4 for PF_INET, 6 for PF_INET6 */ char ip[INET6_ADDRSTRLEN]; }; /* * This is a modified version of host_dns in config.c of OpenBSD's ntpd. */ /* * Copyright (c) 2003, 2004 Henning Brauer * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ static ssize_t host_dns(const char *s, struct addr *vec) { struct addrinfo hints, *res0, *res; int error; ssize_t vecsz; struct sockaddr *sa; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; /* DUMMY */ /* ntpd MUST NOT use AI_ADDRCONFIG here */ error = getaddrinfo(s, NULL, &hints, &res0); if (error == EAI_AGAIN || /* FIXME */ #ifndef __FreeBSD__ error == EAI_NODATA || #endif error == EAI_NONAME) return 0; if (error) { warnx("%s: parse error: %s", s, gai_strerror(error)); return -1; } #ifdef WCME_IDIOM /* always use an IPv4 address if present */ for (int cnt = 2; cnt; cnt--) { for (vecsz = 0, res = res0; res != NULL && vecsz < MAX_SERVERS_DNS; res = res->ai_next) { if (cnt == 2 && res->ai_family != AF_INET) continue; else if (cnt == 1 && res->ai_family != AF_INET6) continue; #else for (vecsz = 0, res = res0; res != NULL && vecsz < MAX_SERVERS_DNS; res = res->ai_next) { if (res->ai_family != AF_INET && res->ai_family != AF_INET6) continue; #endif sa = res->ai_addr; if (res->ai_family == AF_INET) { vec[vecsz].family = 4; inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr), vec[vecsz].ip, INET6_ADDRSTRLEN); } else { vec[vecsz].family = 6; inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), vec[vecsz].ip, INET6_ADDRSTRLEN); } #ifdef WCME_IDIOM doddbg("%s: DNS: %s", s, vec[vecsz].ip); vecsz++; break; } if (vecsz) break; } #else dodbg("%s: DNS: %s", s, vec[vecsz].ip); vecsz++; break; } #endif freeaddrinfo(res0); return vecsz; } int dnsproc(int nfd) { char *look = NULL, *last = NULL; struct addr v[MAX_SERVERS_DNS]; int rc = 0, cc; long lval; ssize_t vsz = 0; size_t i; enum dnsop op; #ifdef WCME_DBG_DNSPROC doddbg ("(%d) %d", __LINE__, nfd); #endif if (pledge("stdio dns", NULL) == -1) { warn("pledge"); goto out; } /* * This is simple: just loop on a request operation, and each * time we write back zero or more entries. * Also do a simple trick and cache the last lookup. */ for (;;) { op = DNS__MAX; if ((lval = readop(nfd, COMM_DNS)) == 0) op = DNS_STOP; else if (lval == DNS_LOOKUP) op = lval; if (op == DNS__MAX) { warnx("unknown operation from netproc"); goto out; } else if (op == DNS_STOP) break; if ((look = readstr(nfd, COMM_DNSQ)) == NULL) goto out; /* * Check if we're asked to repeat the lookup. * If not, request it from host_dns(). */ if (last == NULL || strcmp(look, last)) { if ((vsz = host_dns(look, v)) < 0) goto out; free(last); last = look; look = NULL; } else { doddbg("%s: cached", look); free(look); look = NULL; } if ((cc = writeop(nfd, COMM_DNSLEN, vsz)) == 0) break; else if (cc < 0) goto out; for (i = 0; i < (size_t)vsz; i++) { if (writeop(nfd, COMM_DNSF, v[i].family) <= 0) goto out; if (writestr(nfd, COMM_DNSA, v[i].ip) <= 0) goto out; } } rc = 1; out: close(nfd); free(look); free(last); return rc; }