1 /* $NetBSD: lwdgnba.c,v 1.5 2014/12/10 04:37:51 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2004, 2005, 2007, 2008, 2014 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 2000-2002 Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* Id: lwdgnba.c,v 1.22 2008/01/14 23:46:56 tbox Exp */ 21 22 /*! \file */ 23 24 #include <config.h> 25 26 #include <isc/socket.h> 27 #include <isc/string.h> /* Required for HP/UX (and others?) */ 28 #include <isc/util.h> 29 30 #include <dns/adb.h> 31 #include <dns/byaddr.h> 32 #include <dns/result.h> 33 34 #include <named/types.h> 35 #include <named/lwdclient.h> 36 37 static void start_byaddr(ns_lwdclient_t *); 38 39 static void 40 byaddr_done(isc_task_t *task, isc_event_t *event) { 41 ns_lwdclient_t *client; 42 ns_lwdclientmgr_t *cm; 43 dns_byaddrevent_t *bevent; 44 int lwres; 45 lwres_buffer_t lwb; 46 dns_name_t *name; 47 isc_result_t result; 48 lwres_result_t lwresult; 49 isc_region_t r; 50 isc_buffer_t b; 51 lwres_gnbaresponse_t *gnba; 52 isc_uint16_t naliases; 53 54 UNUSED(task); 55 56 lwb.base = NULL; 57 client = event->ev_arg; 58 cm = client->clientmgr; 59 INSIST(client->byaddr == (dns_byaddr_t *)event->ev_sender); 60 61 bevent = (dns_byaddrevent_t *)event; 62 gnba = &client->gnba; 63 64 ns_lwdclient_log(50, "byaddr event result = %s", 65 isc_result_totext(bevent->result)); 66 67 result = bevent->result; 68 if (result != ISC_R_SUCCESS) { 69 dns_byaddr_destroy(&client->byaddr); 70 isc_event_free(&event); 71 bevent = NULL; 72 73 if (client->na.family != AF_INET6 || 74 (client->options & DNS_BYADDROPT_IPV6INT) != 0) { 75 if (result == DNS_R_NCACHENXDOMAIN || 76 result == DNS_R_NCACHENXRRSET || 77 result == DNS_R_NXDOMAIN || 78 result == DNS_R_NXRRSET) 79 lwresult = LWRES_R_NOTFOUND; 80 else 81 lwresult = LWRES_R_FAILURE; 82 ns_lwdclient_errorpktsend(client, lwresult); 83 return; 84 } 85 86 /* 87 * Fall back to ip6.int reverse if the default ip6.arpa 88 * fails. 89 */ 90 client->options |= DNS_BYADDROPT_IPV6INT; 91 92 start_byaddr(client); 93 return; 94 } 95 96 for (name = ISC_LIST_HEAD(bevent->names); 97 name != NULL; 98 name = ISC_LIST_NEXT(name, link)) 99 { 100 b = client->recv_buffer; 101 102 result = dns_name_totext(name, ISC_TRUE, &client->recv_buffer); 103 if (result != ISC_R_SUCCESS) 104 goto out; 105 ns_lwdclient_log(50, "found name '%.*s'", 106 (int)(client->recv_buffer.used - b.used), 107 (char *)(b.base) + b.used); 108 if (gnba->realname == NULL) { 109 gnba->realname = (char *)(b.base) + b.used; 110 gnba->realnamelen = client->recv_buffer.used - b.used; 111 } else { 112 naliases = gnba->naliases; 113 if (naliases >= LWRES_MAX_ALIASES) 114 break; 115 gnba->aliases[naliases] = (char *)(b.base) + b.used; 116 gnba->aliaslen[naliases] = 117 client->recv_buffer.used - b.used; 118 gnba->naliases++; 119 } 120 } 121 122 dns_byaddr_destroy(&client->byaddr); 123 isc_event_free(&event); 124 125 /* 126 * Render the packet. 127 */ 128 client->pkt.recvlength = LWRES_RECVLENGTH; 129 client->pkt.authtype = 0; /* XXXMLG */ 130 client->pkt.authlength = 0; 131 client->pkt.result = LWRES_R_SUCCESS; 132 133 lwres = lwres_gnbaresponse_render(cm->lwctx, 134 gnba, &client->pkt, &lwb); 135 if (lwres != LWRES_R_SUCCESS) 136 goto out; 137 138 r.base = lwb.base; 139 r.length = lwb.used; 140 client->sendbuf = r.base; 141 client->sendlength = r.length; 142 result = ns_lwdclient_sendreply(client, &r); 143 if (result != ISC_R_SUCCESS) 144 goto out; 145 146 NS_LWDCLIENT_SETSEND(client); 147 148 return; 149 150 out: 151 if (client->byaddr != NULL) 152 dns_byaddr_destroy(&client->byaddr); 153 if (lwb.base != NULL) 154 lwres_context_freemem(cm->lwctx, 155 lwb.base, lwb.length); 156 157 if (event != NULL) 158 isc_event_free(&event); 159 } 160 161 static void 162 start_byaddr(ns_lwdclient_t *client) { 163 isc_result_t result; 164 ns_lwdclientmgr_t *cm; 165 166 cm = client->clientmgr; 167 168 INSIST(client->byaddr == NULL); 169 170 result = dns_byaddr_create(cm->mctx, &client->na, cm->view, 171 client->options, cm->task, byaddr_done, 172 client, &client->byaddr); 173 if (result != ISC_R_SUCCESS) { 174 ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); 175 return; 176 } 177 } 178 179 static void 180 init_gnba(ns_lwdclient_t *client) { 181 int i; 182 183 /* 184 * Initialize the real name and alias arrays in the reply we're 185 * going to build up. 186 */ 187 for (i = 0; i < LWRES_MAX_ALIASES; i++) { 188 client->aliases[i] = NULL; 189 client->aliaslen[i] = 0; 190 } 191 for (i = 0; i < LWRES_MAX_ADDRS; i++) { 192 client->addrs[i].family = 0; 193 client->addrs[i].length = 0; 194 memset(client->addrs[i].address, 0, LWRES_ADDR_MAXLEN); 195 LWRES_LINK_INIT(&client->addrs[i], link); 196 } 197 198 client->gnba.naliases = 0; 199 client->gnba.realname = NULL; 200 client->gnba.aliases = client->aliases; 201 client->gnba.realnamelen = 0; 202 client->gnba.aliaslen = client->aliaslen; 203 client->gnba.base = NULL; 204 client->gnba.baselen = 0; 205 isc_buffer_init(&client->recv_buffer, client->buffer, LWRES_RECVLENGTH); 206 } 207 208 void 209 ns_lwdclient_processgnba(ns_lwdclient_t *client, lwres_buffer_t *b) { 210 lwres_gnbarequest_t *req; 211 isc_result_t result; 212 isc_sockaddr_t sa; 213 ns_lwdclientmgr_t *cm; 214 215 REQUIRE(NS_LWDCLIENT_ISRECVDONE(client)); 216 INSIST(client->byaddr == NULL); 217 218 cm = client->clientmgr; 219 req = NULL; 220 221 result = lwres_gnbarequest_parse(cm->lwctx, 222 b, &client->pkt, &req); 223 if (result != LWRES_R_SUCCESS) 224 goto out; 225 226 client->options = 0; 227 if (req->addr.family == LWRES_ADDRTYPE_V4) { 228 client->na.family = AF_INET; 229 if (req->addr.length != 4) 230 goto out; 231 memmove(&client->na.type.in, req->addr.address, 4); 232 } else if (req->addr.family == LWRES_ADDRTYPE_V6) { 233 client->na.family = AF_INET6; 234 if (req->addr.length != 16) 235 goto out; 236 memmove(&client->na.type.in6, req->addr.address, 16); 237 } else { 238 goto out; 239 } 240 isc_sockaddr_fromnetaddr(&sa, &client->na, 53); 241 242 ns_lwdclient_log(50, "client %p looking for addrtype %08x", 243 client, req->addr.family); 244 245 /* 246 * We no longer need to keep this around. 247 */ 248 lwres_gnbarequest_free(cm->lwctx, &req); 249 250 /* 251 * Initialize the real name and alias arrays in the reply we're 252 * going to build up. 253 */ 254 init_gnba(client); 255 client->options = 0; 256 257 /* 258 * Start the find. 259 */ 260 start_byaddr(client); 261 262 return; 263 264 /* 265 * We're screwed. Return an error packet to our caller. 266 */ 267 out: 268 if (req != NULL) 269 lwres_gnbarequest_free(cm->lwctx, &req); 270 271 ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); 272 } 273