1 /* $Id: dnsproc.c,v 1.9 2017/01/24 13:32:55 jsing Exp $ */ 2 /* 3 * Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/socket.h> 19 #include <arpa/inet.h> 20 21 #include <err.h> 22 #include <netdb.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <unistd.h> 27 28 #include "extern.h" 29 30 struct addr { 31 int family; /* 4 for PF_INET, 6 for PF_INET6 */ 32 char ip[INET6_ADDRSTRLEN]; 33 }; 34 35 /* 36 * This is a modified version of host_dns in config.c of OpenBSD's ntpd. 37 */ 38 /* 39 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 40 * 41 * Permission to use, copy, modify, and distribute this software for any 42 * purpose with or without fee is hereby granted, provided that the above 43 * copyright notice and this permission notice appear in all copies. 44 * 45 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 46 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 47 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 48 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 49 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 50 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 51 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 52 */ 53 static ssize_t 54 host_dns(const char *s, struct addr *vec) 55 { 56 struct addrinfo hints, *res0, *res; 57 int error; 58 ssize_t vecsz; 59 struct sockaddr *sa; 60 61 memset(&hints, 0, sizeof(hints)); 62 hints.ai_family = PF_UNSPEC; 63 hints.ai_socktype = SOCK_DGRAM; /* DUMMY */ 64 /* ntpd MUST NOT use AI_ADDRCONFIG here */ 65 66 error = getaddrinfo(s, NULL, &hints, &res0); 67 68 if (error == EAI_AGAIN || 69 /* FIXME */ 70 #ifndef __FreeBSD__ 71 error == EAI_NODATA || 72 #endif 73 error == EAI_NONAME) 74 return 0; 75 76 if (error) { 77 warnx("%s: parse error: %s", 78 s, gai_strerror(error)); 79 return -1; 80 } 81 82 for (vecsz = 0, res = res0; 83 res != NULL && vecsz < MAX_SERVERS_DNS; 84 res = res->ai_next) { 85 if (res->ai_family != AF_INET && 86 res->ai_family != AF_INET6) 87 continue; 88 89 sa = res->ai_addr; 90 91 if (res->ai_family == AF_INET) { 92 vec[vecsz].family = 4; 93 inet_ntop(AF_INET, 94 &(((struct sockaddr_in *)sa)->sin_addr), 95 vec[vecsz].ip, INET6_ADDRSTRLEN); 96 } else { 97 vec[vecsz].family = 6; 98 inet_ntop(AF_INET6, 99 &(((struct sockaddr_in6 *)sa)->sin6_addr), 100 vec[vecsz].ip, INET6_ADDRSTRLEN); 101 } 102 103 dodbg("%s: DNS: %s", s, vec[vecsz].ip); 104 vecsz++; 105 break; 106 } 107 108 freeaddrinfo(res0); 109 return vecsz; 110 } 111 112 int 113 dnsproc(int nfd) 114 { 115 char *look = NULL, *last = NULL; 116 struct addr v[MAX_SERVERS_DNS]; 117 int rc = 0, cc; 118 long lval; 119 ssize_t vsz = 0; 120 size_t i; 121 enum dnsop op; 122 123 if (pledge("stdio dns", NULL) == -1) { 124 warn("pledge"); 125 goto out; 126 } 127 128 /* 129 * This is simple: just loop on a request operation, and each 130 * time we write back zero or more entries. 131 * Also do a simple trick and cache the last lookup. 132 */ 133 134 for (;;) { 135 op = DNS__MAX; 136 if ((lval = readop(nfd, COMM_DNS)) == 0) 137 op = DNS_STOP; 138 else if (lval == DNS_LOOKUP) 139 op = lval; 140 141 if (op == DNS__MAX) { 142 warnx("unknown operation from netproc"); 143 goto out; 144 } else if (op == DNS_STOP) 145 break; 146 147 if ((look = readstr(nfd, COMM_DNSQ)) == NULL) 148 goto out; 149 150 /* 151 * Check if we're asked to repeat the lookup. 152 * If not, request it from host_dns(). 153 */ 154 155 if (last == NULL || strcmp(look, last)) { 156 if ((vsz = host_dns(look, v)) < 0) 157 goto out; 158 159 free(last); 160 last = look; 161 look = NULL; 162 } else { 163 doddbg("%s: cached", look); 164 free(look); 165 look = NULL; 166 } 167 168 if ((cc = writeop(nfd, COMM_DNSLEN, vsz)) == 0) 169 break; 170 else if (cc < 0) 171 goto out; 172 for (i = 0; i < (size_t)vsz; i++) { 173 if (writeop(nfd, COMM_DNSF, v[i].family) <= 0) 174 goto out; 175 if (writestr(nfd, COMM_DNSA, v[i].ip) <= 0) 176 goto out; 177 } 178 } 179 180 rc = 1; 181 out: 182 close(nfd); 183 free(look); 184 free(last); 185 return rc; 186 } 187