1 /* $Id: dnsproc.c,v 1.12 2021/12/13 13:30:39 jca 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 hints.ai_flags = AI_ADDRCONFIG; 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 } 106 107 freeaddrinfo(res0); 108 return vecsz; 109 } 110 111 int 112 dnsproc(int nfd) 113 { 114 char *look = NULL, *last = NULL; 115 struct addr v[MAX_SERVERS_DNS]; 116 int rc = 0, cc; 117 long lval; 118 ssize_t vsz = 0; 119 size_t i; 120 enum dnsop op; 121 122 if (pledge("stdio dns", NULL) == -1) { 123 warn("pledge"); 124 goto out; 125 } 126 127 /* 128 * This is simple: just loop on a request operation, and each 129 * time we write back zero or more entries. 130 * Also do a simple trick and cache the last lookup. 131 */ 132 133 for (;;) { 134 op = DNS__MAX; 135 if ((lval = readop(nfd, COMM_DNS)) == 0) 136 op = DNS_STOP; 137 else if (lval == DNS_LOOKUP) 138 op = lval; 139 140 if (op == DNS__MAX) { 141 warnx("unknown operation from netproc"); 142 goto out; 143 } else if (op == DNS_STOP) 144 break; 145 146 if ((look = readstr(nfd, COMM_DNSQ)) == NULL) 147 goto out; 148 149 /* 150 * Check if we're asked to repeat the lookup. 151 * If not, request it from host_dns(). 152 */ 153 154 if (last == NULL || strcmp(look, last)) { 155 if ((vsz = host_dns(look, v)) < 0) 156 goto out; 157 158 free(last); 159 last = look; 160 look = NULL; 161 } else { 162 free(look); 163 look = NULL; 164 } 165 166 if ((cc = writeop(nfd, COMM_DNSLEN, vsz)) == 0) 167 break; 168 else if (cc < 0) 169 goto out; 170 for (i = 0; i < (size_t)vsz; i++) { 171 if (writeop(nfd, COMM_DNSF, v[i].family) <= 0) 172 goto out; 173 if (writestr(nfd, COMM_DNSA, v[i].ip) <= 0) 174 goto out; 175 } 176 } 177 178 rc = 1; 179 out: 180 close(nfd); 181 free(look); 182 free(last); 183 return rc; 184 } 185