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