1*00b67f09SDavid van Moolenbroek /* $NetBSD: lwdgabn.c,v 1.4 2014/12/10 04:37:51 christos Exp $ */
2*00b67f09SDavid van Moolenbroek
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek * Copyright (C) 2000, 2001 Internet Software Consortium.
6*00b67f09SDavid van Moolenbroek *
7*00b67f09SDavid van Moolenbroek * Permission to use, copy, modify, and/or distribute this software for any
8*00b67f09SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above
9*00b67f09SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies.
10*00b67f09SDavid van Moolenbroek *
11*00b67f09SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12*00b67f09SDavid van Moolenbroek * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13*00b67f09SDavid van Moolenbroek * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14*00b67f09SDavid van Moolenbroek * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15*00b67f09SDavid van Moolenbroek * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16*00b67f09SDavid van Moolenbroek * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*00b67f09SDavid van Moolenbroek * PERFORMANCE OF THIS SOFTWARE.
18*00b67f09SDavid van Moolenbroek */
19*00b67f09SDavid van Moolenbroek
20*00b67f09SDavid van Moolenbroek /* Id: lwdgabn.c,v 1.24 2009/09/02 23:48:01 tbox Exp */
21*00b67f09SDavid van Moolenbroek
22*00b67f09SDavid van Moolenbroek /*! \file */
23*00b67f09SDavid van Moolenbroek
24*00b67f09SDavid van Moolenbroek #include <config.h>
25*00b67f09SDavid van Moolenbroek
26*00b67f09SDavid van Moolenbroek #include <stdlib.h>
27*00b67f09SDavid van Moolenbroek
28*00b67f09SDavid van Moolenbroek #include <isc/netaddr.h>
29*00b67f09SDavid van Moolenbroek #include <isc/sockaddr.h>
30*00b67f09SDavid van Moolenbroek #include <isc/socket.h>
31*00b67f09SDavid van Moolenbroek #include <isc/string.h> /* Required for HP/UX (and others?) */
32*00b67f09SDavid van Moolenbroek #include <isc/util.h>
33*00b67f09SDavid van Moolenbroek
34*00b67f09SDavid van Moolenbroek #include <dns/adb.h>
35*00b67f09SDavid van Moolenbroek #include <dns/events.h>
36*00b67f09SDavid van Moolenbroek #include <dns/result.h>
37*00b67f09SDavid van Moolenbroek
38*00b67f09SDavid van Moolenbroek #include <named/types.h>
39*00b67f09SDavid van Moolenbroek #include <named/lwaddr.h>
40*00b67f09SDavid van Moolenbroek #include <named/lwdclient.h>
41*00b67f09SDavid van Moolenbroek #include <named/lwresd.h>
42*00b67f09SDavid van Moolenbroek #include <named/lwsearch.h>
43*00b67f09SDavid van Moolenbroek #include <named/sortlist.h>
44*00b67f09SDavid van Moolenbroek
45*00b67f09SDavid van Moolenbroek #define NEED_V4(c) ((((c)->find_wanted & LWRES_ADDRTYPE_V4) != 0) \
46*00b67f09SDavid van Moolenbroek && ((c)->v4find == NULL))
47*00b67f09SDavid van Moolenbroek #define NEED_V6(c) ((((c)->find_wanted & LWRES_ADDRTYPE_V6) != 0) \
48*00b67f09SDavid van Moolenbroek && ((c)->v6find == NULL))
49*00b67f09SDavid van Moolenbroek
50*00b67f09SDavid van Moolenbroek static isc_result_t start_find(ns_lwdclient_t *);
51*00b67f09SDavid van Moolenbroek static void restart_find(ns_lwdclient_t *);
52*00b67f09SDavid van Moolenbroek static void init_gabn(ns_lwdclient_t *);
53*00b67f09SDavid van Moolenbroek
54*00b67f09SDavid van Moolenbroek /*%
55*00b67f09SDavid van Moolenbroek * Destroy any finds. This can be used to "start over from scratch" and
56*00b67f09SDavid van Moolenbroek * should only be called when events are _not_ being generated by the finds.
57*00b67f09SDavid van Moolenbroek */
58*00b67f09SDavid van Moolenbroek static void
cleanup_gabn(ns_lwdclient_t * client)59*00b67f09SDavid van Moolenbroek cleanup_gabn(ns_lwdclient_t *client) {
60*00b67f09SDavid van Moolenbroek ns_lwdclient_log(50, "cleaning up client %p", client);
61*00b67f09SDavid van Moolenbroek
62*00b67f09SDavid van Moolenbroek if (client->v6find != NULL) {
63*00b67f09SDavid van Moolenbroek if (client->v6find == client->v4find)
64*00b67f09SDavid van Moolenbroek client->v6find = NULL;
65*00b67f09SDavid van Moolenbroek else
66*00b67f09SDavid van Moolenbroek dns_adb_destroyfind(&client->v6find);
67*00b67f09SDavid van Moolenbroek }
68*00b67f09SDavid van Moolenbroek if (client->v4find != NULL)
69*00b67f09SDavid van Moolenbroek dns_adb_destroyfind(&client->v4find);
70*00b67f09SDavid van Moolenbroek }
71*00b67f09SDavid van Moolenbroek
72*00b67f09SDavid van Moolenbroek static void
setup_addresses(ns_lwdclient_t * client,dns_adbfind_t * find,unsigned int at)73*00b67f09SDavid van Moolenbroek setup_addresses(ns_lwdclient_t *client, dns_adbfind_t *find, unsigned int at) {
74*00b67f09SDavid van Moolenbroek dns_adbaddrinfo_t *ai;
75*00b67f09SDavid van Moolenbroek lwres_addr_t *addr;
76*00b67f09SDavid van Moolenbroek int af;
77*00b67f09SDavid van Moolenbroek const struct sockaddr *sa;
78*00b67f09SDavid van Moolenbroek isc_result_t result;
79*00b67f09SDavid van Moolenbroek
80*00b67f09SDavid van Moolenbroek if (at == DNS_ADBFIND_INET)
81*00b67f09SDavid van Moolenbroek af = AF_INET;
82*00b67f09SDavid van Moolenbroek else
83*00b67f09SDavid van Moolenbroek af = AF_INET6;
84*00b67f09SDavid van Moolenbroek
85*00b67f09SDavid van Moolenbroek ai = ISC_LIST_HEAD(find->list);
86*00b67f09SDavid van Moolenbroek while (ai != NULL && client->gabn.naddrs < LWRES_MAX_ADDRS) {
87*00b67f09SDavid van Moolenbroek sa = &ai->sockaddr.type.sa;
88*00b67f09SDavid van Moolenbroek if (sa->sa_family != af)
89*00b67f09SDavid van Moolenbroek goto next;
90*00b67f09SDavid van Moolenbroek
91*00b67f09SDavid van Moolenbroek addr = &client->addrs[client->gabn.naddrs];
92*00b67f09SDavid van Moolenbroek
93*00b67f09SDavid van Moolenbroek result = lwaddr_lwresaddr_fromsockaddr(addr, &ai->sockaddr);
94*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
95*00b67f09SDavid van Moolenbroek goto next;
96*00b67f09SDavid van Moolenbroek
97*00b67f09SDavid van Moolenbroek ns_lwdclient_log(50, "adding address %p, family %d, length %d",
98*00b67f09SDavid van Moolenbroek addr->address, addr->family, addr->length);
99*00b67f09SDavid van Moolenbroek
100*00b67f09SDavid van Moolenbroek client->gabn.naddrs++;
101*00b67f09SDavid van Moolenbroek REQUIRE(!LWRES_LINK_LINKED(addr, link));
102*00b67f09SDavid van Moolenbroek LWRES_LIST_APPEND(client->gabn.addrs, addr, link);
103*00b67f09SDavid van Moolenbroek
104*00b67f09SDavid van Moolenbroek next:
105*00b67f09SDavid van Moolenbroek ai = ISC_LIST_NEXT(ai, publink);
106*00b67f09SDavid van Moolenbroek }
107*00b67f09SDavid van Moolenbroek }
108*00b67f09SDavid van Moolenbroek
109*00b67f09SDavid van Moolenbroek typedef struct {
110*00b67f09SDavid van Moolenbroek isc_netaddr_t address;
111*00b67f09SDavid van Moolenbroek int rank;
112*00b67f09SDavid van Moolenbroek } rankedaddress;
113*00b67f09SDavid van Moolenbroek
114*00b67f09SDavid van Moolenbroek static int
addr_compare(const void * av,const void * bv)115*00b67f09SDavid van Moolenbroek addr_compare(const void *av, const void *bv) {
116*00b67f09SDavid van Moolenbroek const rankedaddress *a = (const rankedaddress *) av;
117*00b67f09SDavid van Moolenbroek const rankedaddress *b = (const rankedaddress *) bv;
118*00b67f09SDavid van Moolenbroek return (a->rank - b->rank);
119*00b67f09SDavid van Moolenbroek }
120*00b67f09SDavid van Moolenbroek
121*00b67f09SDavid van Moolenbroek static void
sort_addresses(ns_lwdclient_t * client)122*00b67f09SDavid van Moolenbroek sort_addresses(ns_lwdclient_t *client) {
123*00b67f09SDavid van Moolenbroek unsigned int naddrs;
124*00b67f09SDavid van Moolenbroek rankedaddress *addrs;
125*00b67f09SDavid van Moolenbroek isc_netaddr_t remote;
126*00b67f09SDavid van Moolenbroek dns_addressorderfunc_t order;
127*00b67f09SDavid van Moolenbroek const void *arg;
128*00b67f09SDavid van Moolenbroek ns_lwresd_t *lwresd = client->clientmgr->listener->manager;
129*00b67f09SDavid van Moolenbroek unsigned int i;
130*00b67f09SDavid van Moolenbroek isc_result_t result;
131*00b67f09SDavid van Moolenbroek
132*00b67f09SDavid van Moolenbroek naddrs = client->gabn.naddrs;
133*00b67f09SDavid van Moolenbroek
134*00b67f09SDavid van Moolenbroek if (naddrs <= 1 || lwresd->view->sortlist == NULL)
135*00b67f09SDavid van Moolenbroek return;
136*00b67f09SDavid van Moolenbroek
137*00b67f09SDavid van Moolenbroek addrs = isc_mem_get(lwresd->mctx, sizeof(rankedaddress) * naddrs);
138*00b67f09SDavid van Moolenbroek if (addrs == NULL)
139*00b67f09SDavid van Moolenbroek return;
140*00b67f09SDavid van Moolenbroek
141*00b67f09SDavid van Moolenbroek isc_netaddr_fromsockaddr(&remote, &client->address);
142*00b67f09SDavid van Moolenbroek ns_sortlist_byaddrsetup(lwresd->view->sortlist,
143*00b67f09SDavid van Moolenbroek &remote, &order, &arg);
144*00b67f09SDavid van Moolenbroek if (order == NULL) {
145*00b67f09SDavid van Moolenbroek isc_mem_put(lwresd->mctx, addrs,
146*00b67f09SDavid van Moolenbroek sizeof(rankedaddress) * naddrs);
147*00b67f09SDavid van Moolenbroek return;
148*00b67f09SDavid van Moolenbroek }
149*00b67f09SDavid van Moolenbroek for (i = 0; i < naddrs; i++) {
150*00b67f09SDavid van Moolenbroek result = lwaddr_netaddr_fromlwresaddr(&addrs[i].address,
151*00b67f09SDavid van Moolenbroek &client->addrs[i]);
152*00b67f09SDavid van Moolenbroek INSIST(result == ISC_R_SUCCESS);
153*00b67f09SDavid van Moolenbroek addrs[i].rank = (*order)(&addrs[i].address, arg);
154*00b67f09SDavid van Moolenbroek }
155*00b67f09SDavid van Moolenbroek qsort(addrs, naddrs, sizeof(rankedaddress), addr_compare);
156*00b67f09SDavid van Moolenbroek for (i = 0; i < naddrs; i++) {
157*00b67f09SDavid van Moolenbroek result = lwaddr_lwresaddr_fromnetaddr(&client->addrs[i],
158*00b67f09SDavid van Moolenbroek &addrs[i].address);
159*00b67f09SDavid van Moolenbroek INSIST(result == ISC_R_SUCCESS);
160*00b67f09SDavid van Moolenbroek }
161*00b67f09SDavid van Moolenbroek
162*00b67f09SDavid van Moolenbroek isc_mem_put(lwresd->mctx, addrs, sizeof(rankedaddress) * naddrs);
163*00b67f09SDavid van Moolenbroek }
164*00b67f09SDavid van Moolenbroek
165*00b67f09SDavid van Moolenbroek static void
generate_reply(ns_lwdclient_t * client)166*00b67f09SDavid van Moolenbroek generate_reply(ns_lwdclient_t *client) {
167*00b67f09SDavid van Moolenbroek isc_result_t result;
168*00b67f09SDavid van Moolenbroek int lwres;
169*00b67f09SDavid van Moolenbroek isc_region_t r;
170*00b67f09SDavid van Moolenbroek lwres_buffer_t lwb;
171*00b67f09SDavid van Moolenbroek ns_lwdclientmgr_t *cm;
172*00b67f09SDavid van Moolenbroek
173*00b67f09SDavid van Moolenbroek cm = client->clientmgr;
174*00b67f09SDavid van Moolenbroek lwb.base = NULL;
175*00b67f09SDavid van Moolenbroek
176*00b67f09SDavid van Moolenbroek ns_lwdclient_log(50, "generating gabn reply for client %p", client);
177*00b67f09SDavid van Moolenbroek
178*00b67f09SDavid van Moolenbroek /*
179*00b67f09SDavid van Moolenbroek * We must make certain the client->find is not still active.
180*00b67f09SDavid van Moolenbroek * If it is either the v4 or v6 answer, just set it to NULL and
181*00b67f09SDavid van Moolenbroek * let the cleanup code destroy it. Otherwise, destroy it now.
182*00b67f09SDavid van Moolenbroek */
183*00b67f09SDavid van Moolenbroek if (client->find == client->v4find || client->find == client->v6find)
184*00b67f09SDavid van Moolenbroek client->find = NULL;
185*00b67f09SDavid van Moolenbroek else
186*00b67f09SDavid van Moolenbroek if (client->find != NULL)
187*00b67f09SDavid van Moolenbroek dns_adb_destroyfind(&client->find);
188*00b67f09SDavid van Moolenbroek
189*00b67f09SDavid van Moolenbroek /*
190*00b67f09SDavid van Moolenbroek * perhaps there are some here?
191*00b67f09SDavid van Moolenbroek */
192*00b67f09SDavid van Moolenbroek if (NEED_V6(client) && client->v4find != NULL)
193*00b67f09SDavid van Moolenbroek client->v6find = client->v4find;
194*00b67f09SDavid van Moolenbroek
195*00b67f09SDavid van Moolenbroek /*
196*00b67f09SDavid van Moolenbroek * Run through the finds we have and wire them up to the gabn
197*00b67f09SDavid van Moolenbroek * structure.
198*00b67f09SDavid van Moolenbroek */
199*00b67f09SDavid van Moolenbroek LWRES_LIST_INIT(client->gabn.addrs);
200*00b67f09SDavid van Moolenbroek if (client->v4find != NULL)
201*00b67f09SDavid van Moolenbroek setup_addresses(client, client->v4find, DNS_ADBFIND_INET);
202*00b67f09SDavid van Moolenbroek if (client->v6find != NULL)
203*00b67f09SDavid van Moolenbroek setup_addresses(client, client->v6find, DNS_ADBFIND_INET6);
204*00b67f09SDavid van Moolenbroek
205*00b67f09SDavid van Moolenbroek /*
206*00b67f09SDavid van Moolenbroek * If there are no addresses, try the next element in the search
207*00b67f09SDavid van Moolenbroek * path, if there are any more. Otherwise, fall through into
208*00b67f09SDavid van Moolenbroek * the error handling code below.
209*00b67f09SDavid van Moolenbroek */
210*00b67f09SDavid van Moolenbroek if (client->gabn.naddrs == 0) {
211*00b67f09SDavid van Moolenbroek do {
212*00b67f09SDavid van Moolenbroek result = ns_lwsearchctx_next(&client->searchctx);
213*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS) {
214*00b67f09SDavid van Moolenbroek cleanup_gabn(client);
215*00b67f09SDavid van Moolenbroek result = start_find(client);
216*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS)
217*00b67f09SDavid van Moolenbroek return;
218*00b67f09SDavid van Moolenbroek }
219*00b67f09SDavid van Moolenbroek } while (result == ISC_R_SUCCESS);
220*00b67f09SDavid van Moolenbroek }
221*00b67f09SDavid van Moolenbroek
222*00b67f09SDavid van Moolenbroek /*
223*00b67f09SDavid van Moolenbroek * Render the packet.
224*00b67f09SDavid van Moolenbroek */
225*00b67f09SDavid van Moolenbroek client->pkt.recvlength = LWRES_RECVLENGTH;
226*00b67f09SDavid van Moolenbroek client->pkt.authtype = 0; /* XXXMLG */
227*00b67f09SDavid van Moolenbroek client->pkt.authlength = 0;
228*00b67f09SDavid van Moolenbroek
229*00b67f09SDavid van Moolenbroek /*
230*00b67f09SDavid van Moolenbroek * If there are no addresses, return failure.
231*00b67f09SDavid van Moolenbroek */
232*00b67f09SDavid van Moolenbroek if (client->gabn.naddrs != 0)
233*00b67f09SDavid van Moolenbroek client->pkt.result = LWRES_R_SUCCESS;
234*00b67f09SDavid van Moolenbroek else
235*00b67f09SDavid van Moolenbroek client->pkt.result = LWRES_R_NOTFOUND;
236*00b67f09SDavid van Moolenbroek
237*00b67f09SDavid van Moolenbroek sort_addresses(client);
238*00b67f09SDavid van Moolenbroek
239*00b67f09SDavid van Moolenbroek lwres = lwres_gabnresponse_render(cm->lwctx, &client->gabn,
240*00b67f09SDavid van Moolenbroek &client->pkt, &lwb);
241*00b67f09SDavid van Moolenbroek if (lwres != LWRES_R_SUCCESS)
242*00b67f09SDavid van Moolenbroek goto out;
243*00b67f09SDavid van Moolenbroek
244*00b67f09SDavid van Moolenbroek r.base = lwb.base;
245*00b67f09SDavid van Moolenbroek r.length = lwb.used;
246*00b67f09SDavid van Moolenbroek client->sendbuf = r.base;
247*00b67f09SDavid van Moolenbroek client->sendlength = r.length;
248*00b67f09SDavid van Moolenbroek result = ns_lwdclient_sendreply(client, &r);
249*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
250*00b67f09SDavid van Moolenbroek goto out;
251*00b67f09SDavid van Moolenbroek
252*00b67f09SDavid van Moolenbroek NS_LWDCLIENT_SETSEND(client);
253*00b67f09SDavid van Moolenbroek
254*00b67f09SDavid van Moolenbroek /*
255*00b67f09SDavid van Moolenbroek * All done!
256*00b67f09SDavid van Moolenbroek */
257*00b67f09SDavid van Moolenbroek cleanup_gabn(client);
258*00b67f09SDavid van Moolenbroek
259*00b67f09SDavid van Moolenbroek return;
260*00b67f09SDavid van Moolenbroek
261*00b67f09SDavid van Moolenbroek out:
262*00b67f09SDavid van Moolenbroek cleanup_gabn(client);
263*00b67f09SDavid van Moolenbroek
264*00b67f09SDavid van Moolenbroek if (lwb.base != NULL)
265*00b67f09SDavid van Moolenbroek lwres_context_freemem(client->clientmgr->lwctx,
266*00b67f09SDavid van Moolenbroek lwb.base, lwb.length);
267*00b67f09SDavid van Moolenbroek
268*00b67f09SDavid van Moolenbroek ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE);
269*00b67f09SDavid van Moolenbroek }
270*00b67f09SDavid van Moolenbroek
271*00b67f09SDavid van Moolenbroek /*
272*00b67f09SDavid van Moolenbroek * Take the current real name, move it to an alias slot (if any are
273*00b67f09SDavid van Moolenbroek * open) then put this new name in as the real name for the target.
274*00b67f09SDavid van Moolenbroek *
275*00b67f09SDavid van Moolenbroek * Return success if it can be rendered, otherwise failure. Note that
276*00b67f09SDavid van Moolenbroek * not having enough alias slots open is NOT a failure.
277*00b67f09SDavid van Moolenbroek */
278*00b67f09SDavid van Moolenbroek static isc_result_t
add_alias(ns_lwdclient_t * client)279*00b67f09SDavid van Moolenbroek add_alias(ns_lwdclient_t *client) {
280*00b67f09SDavid van Moolenbroek isc_buffer_t b;
281*00b67f09SDavid van Moolenbroek isc_result_t result;
282*00b67f09SDavid van Moolenbroek isc_uint16_t naliases;
283*00b67f09SDavid van Moolenbroek
284*00b67f09SDavid van Moolenbroek b = client->recv_buffer;
285*00b67f09SDavid van Moolenbroek
286*00b67f09SDavid van Moolenbroek /*
287*00b67f09SDavid van Moolenbroek * Render the new name to the buffer.
288*00b67f09SDavid van Moolenbroek */
289*00b67f09SDavid van Moolenbroek result = dns_name_totext(dns_fixedname_name(&client->target_name),
290*00b67f09SDavid van Moolenbroek ISC_TRUE, &client->recv_buffer);
291*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
292*00b67f09SDavid van Moolenbroek return (result);
293*00b67f09SDavid van Moolenbroek
294*00b67f09SDavid van Moolenbroek /*
295*00b67f09SDavid van Moolenbroek * Are there any open slots?
296*00b67f09SDavid van Moolenbroek */
297*00b67f09SDavid van Moolenbroek naliases = client->gabn.naliases;
298*00b67f09SDavid van Moolenbroek if (naliases < LWRES_MAX_ALIASES) {
299*00b67f09SDavid van Moolenbroek client->gabn.aliases[naliases] = client->gabn.realname;
300*00b67f09SDavid van Moolenbroek client->gabn.aliaslen[naliases] = client->gabn.realnamelen;
301*00b67f09SDavid van Moolenbroek client->gabn.naliases++;
302*00b67f09SDavid van Moolenbroek }
303*00b67f09SDavid van Moolenbroek
304*00b67f09SDavid van Moolenbroek /*
305*00b67f09SDavid van Moolenbroek * Save this name away as the current real name.
306*00b67f09SDavid van Moolenbroek */
307*00b67f09SDavid van Moolenbroek client->gabn.realname = (char *)(b.base) + b.used;
308*00b67f09SDavid van Moolenbroek client->gabn.realnamelen = client->recv_buffer.used - b.used;
309*00b67f09SDavid van Moolenbroek
310*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
311*00b67f09SDavid van Moolenbroek }
312*00b67f09SDavid van Moolenbroek
313*00b67f09SDavid van Moolenbroek static isc_result_t
store_realname(ns_lwdclient_t * client)314*00b67f09SDavid van Moolenbroek store_realname(ns_lwdclient_t *client) {
315*00b67f09SDavid van Moolenbroek isc_buffer_t b;
316*00b67f09SDavid van Moolenbroek isc_result_t result;
317*00b67f09SDavid van Moolenbroek dns_name_t *tname;
318*00b67f09SDavid van Moolenbroek
319*00b67f09SDavid van Moolenbroek b = client->recv_buffer;
320*00b67f09SDavid van Moolenbroek
321*00b67f09SDavid van Moolenbroek tname = dns_fixedname_name(&client->target_name);
322*00b67f09SDavid van Moolenbroek result = ns_lwsearchctx_current(&client->searchctx, tname);
323*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
324*00b67f09SDavid van Moolenbroek return (result);
325*00b67f09SDavid van Moolenbroek
326*00b67f09SDavid van Moolenbroek /*
327*00b67f09SDavid van Moolenbroek * Render the new name to the buffer.
328*00b67f09SDavid van Moolenbroek */
329*00b67f09SDavid van Moolenbroek result = dns_name_totext(tname, ISC_TRUE, &client->recv_buffer);
330*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
331*00b67f09SDavid van Moolenbroek return (result);
332*00b67f09SDavid van Moolenbroek
333*00b67f09SDavid van Moolenbroek /*
334*00b67f09SDavid van Moolenbroek * Save this name away as the current real name.
335*00b67f09SDavid van Moolenbroek */
336*00b67f09SDavid van Moolenbroek client->gabn.realname = (char *) b.base + b.used;
337*00b67f09SDavid van Moolenbroek client->gabn.realnamelen = client->recv_buffer.used - b.used;
338*00b67f09SDavid van Moolenbroek
339*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
340*00b67f09SDavid van Moolenbroek }
341*00b67f09SDavid van Moolenbroek
342*00b67f09SDavid van Moolenbroek static void
process_gabn_finddone(isc_task_t * task,isc_event_t * ev)343*00b67f09SDavid van Moolenbroek process_gabn_finddone(isc_task_t *task, isc_event_t *ev) {
344*00b67f09SDavid van Moolenbroek ns_lwdclient_t *client = ev->ev_arg;
345*00b67f09SDavid van Moolenbroek isc_eventtype_t evtype;
346*00b67f09SDavid van Moolenbroek isc_boolean_t claimed;
347*00b67f09SDavid van Moolenbroek
348*00b67f09SDavid van Moolenbroek ns_lwdclient_log(50, "find done for task %p, client %p", task, client);
349*00b67f09SDavid van Moolenbroek
350*00b67f09SDavid van Moolenbroek evtype = ev->ev_type;
351*00b67f09SDavid van Moolenbroek isc_event_free(&ev);
352*00b67f09SDavid van Moolenbroek
353*00b67f09SDavid van Moolenbroek /*
354*00b67f09SDavid van Moolenbroek * No more info to be had? If so, we have all the good stuff
355*00b67f09SDavid van Moolenbroek * right now, so we can render things.
356*00b67f09SDavid van Moolenbroek */
357*00b67f09SDavid van Moolenbroek claimed = ISC_FALSE;
358*00b67f09SDavid van Moolenbroek if (evtype == DNS_EVENT_ADBNOMOREADDRESSES) {
359*00b67f09SDavid van Moolenbroek if (NEED_V4(client)) {
360*00b67f09SDavid van Moolenbroek client->v4find = client->find;
361*00b67f09SDavid van Moolenbroek claimed = ISC_TRUE;
362*00b67f09SDavid van Moolenbroek }
363*00b67f09SDavid van Moolenbroek if (NEED_V6(client)) {
364*00b67f09SDavid van Moolenbroek client->v6find = client->find;
365*00b67f09SDavid van Moolenbroek claimed = ISC_TRUE;
366*00b67f09SDavid van Moolenbroek }
367*00b67f09SDavid van Moolenbroek if (client->find != NULL) {
368*00b67f09SDavid van Moolenbroek if (claimed)
369*00b67f09SDavid van Moolenbroek client->find = NULL;
370*00b67f09SDavid van Moolenbroek else
371*00b67f09SDavid van Moolenbroek dns_adb_destroyfind(&client->find);
372*00b67f09SDavid van Moolenbroek
373*00b67f09SDavid van Moolenbroek }
374*00b67f09SDavid van Moolenbroek generate_reply(client);
375*00b67f09SDavid van Moolenbroek return;
376*00b67f09SDavid van Moolenbroek }
377*00b67f09SDavid van Moolenbroek
378*00b67f09SDavid van Moolenbroek /*
379*00b67f09SDavid van Moolenbroek * We probably don't need this find anymore. We're either going to
380*00b67f09SDavid van Moolenbroek * reissue it, or an error occurred. Either way, we're done with
381*00b67f09SDavid van Moolenbroek * it.
382*00b67f09SDavid van Moolenbroek */
383*00b67f09SDavid van Moolenbroek if ((client->find != client->v4find)
384*00b67f09SDavid van Moolenbroek && (client->find != client->v6find)) {
385*00b67f09SDavid van Moolenbroek dns_adb_destroyfind(&client->find);
386*00b67f09SDavid van Moolenbroek } else {
387*00b67f09SDavid van Moolenbroek client->find = NULL;
388*00b67f09SDavid van Moolenbroek }
389*00b67f09SDavid van Moolenbroek
390*00b67f09SDavid van Moolenbroek /*
391*00b67f09SDavid van Moolenbroek * We have some new information we can gather. Run off and fetch
392*00b67f09SDavid van Moolenbroek * it.
393*00b67f09SDavid van Moolenbroek */
394*00b67f09SDavid van Moolenbroek if (evtype == DNS_EVENT_ADBMOREADDRESSES) {
395*00b67f09SDavid van Moolenbroek restart_find(client);
396*00b67f09SDavid van Moolenbroek return;
397*00b67f09SDavid van Moolenbroek }
398*00b67f09SDavid van Moolenbroek
399*00b67f09SDavid van Moolenbroek /*
400*00b67f09SDavid van Moolenbroek * An error or other strangeness happened. Drop this query.
401*00b67f09SDavid van Moolenbroek */
402*00b67f09SDavid van Moolenbroek cleanup_gabn(client);
403*00b67f09SDavid van Moolenbroek ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE);
404*00b67f09SDavid van Moolenbroek }
405*00b67f09SDavid van Moolenbroek
406*00b67f09SDavid van Moolenbroek static void
restart_find(ns_lwdclient_t * client)407*00b67f09SDavid van Moolenbroek restart_find(ns_lwdclient_t *client) {
408*00b67f09SDavid van Moolenbroek unsigned int options;
409*00b67f09SDavid van Moolenbroek isc_result_t result;
410*00b67f09SDavid van Moolenbroek isc_boolean_t claimed;
411*00b67f09SDavid van Moolenbroek
412*00b67f09SDavid van Moolenbroek ns_lwdclient_log(50, "starting find for client %p", client);
413*00b67f09SDavid van Moolenbroek
414*00b67f09SDavid van Moolenbroek /*
415*00b67f09SDavid van Moolenbroek * Issue a find for the name contained in the request. We won't
416*00b67f09SDavid van Moolenbroek * set the bit that says "anything is good enough" -- we want it
417*00b67f09SDavid van Moolenbroek * all.
418*00b67f09SDavid van Moolenbroek */
419*00b67f09SDavid van Moolenbroek options = 0;
420*00b67f09SDavid van Moolenbroek options |= DNS_ADBFIND_WANTEVENT;
421*00b67f09SDavid van Moolenbroek options |= DNS_ADBFIND_RETURNLAME;
422*00b67f09SDavid van Moolenbroek
423*00b67f09SDavid van Moolenbroek /*
424*00b67f09SDavid van Moolenbroek * Set the bits up here to mark that we want this address family
425*00b67f09SDavid van Moolenbroek * and that we do not currently have a find pending. We will
426*00b67f09SDavid van Moolenbroek * set that bit again below if it turns out we will get an event.
427*00b67f09SDavid van Moolenbroek */
428*00b67f09SDavid van Moolenbroek if (NEED_V4(client))
429*00b67f09SDavid van Moolenbroek options |= DNS_ADBFIND_INET;
430*00b67f09SDavid van Moolenbroek if (NEED_V6(client))
431*00b67f09SDavid van Moolenbroek options |= DNS_ADBFIND_INET6;
432*00b67f09SDavid van Moolenbroek
433*00b67f09SDavid van Moolenbroek find_again:
434*00b67f09SDavid van Moolenbroek INSIST(client->find == NULL);
435*00b67f09SDavid van Moolenbroek result = dns_adb_createfind(client->clientmgr->view->adb,
436*00b67f09SDavid van Moolenbroek client->clientmgr->task,
437*00b67f09SDavid van Moolenbroek process_gabn_finddone, client,
438*00b67f09SDavid van Moolenbroek dns_fixedname_name(&client->target_name),
439*00b67f09SDavid van Moolenbroek dns_rootname, 0, options, 0,
440*00b67f09SDavid van Moolenbroek dns_fixedname_name(&client->target_name),
441*00b67f09SDavid van Moolenbroek client->clientmgr->view->dstport,
442*00b67f09SDavid van Moolenbroek &client->find);
443*00b67f09SDavid van Moolenbroek
444*00b67f09SDavid van Moolenbroek /*
445*00b67f09SDavid van Moolenbroek * Did we get an alias? If so, save it and re-issue the query.
446*00b67f09SDavid van Moolenbroek */
447*00b67f09SDavid van Moolenbroek if (result == DNS_R_ALIAS) {
448*00b67f09SDavid van Moolenbroek ns_lwdclient_log(50, "found alias, restarting query");
449*00b67f09SDavid van Moolenbroek dns_adb_destroyfind(&client->find);
450*00b67f09SDavid van Moolenbroek cleanup_gabn(client);
451*00b67f09SDavid van Moolenbroek result = add_alias(client);
452*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
453*00b67f09SDavid van Moolenbroek ns_lwdclient_log(50,
454*00b67f09SDavid van Moolenbroek "out of buffer space adding alias");
455*00b67f09SDavid van Moolenbroek ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE);
456*00b67f09SDavid van Moolenbroek return;
457*00b67f09SDavid van Moolenbroek }
458*00b67f09SDavid van Moolenbroek goto find_again;
459*00b67f09SDavid van Moolenbroek }
460*00b67f09SDavid van Moolenbroek
461*00b67f09SDavid van Moolenbroek ns_lwdclient_log(50, "find returned %d (%s)", result,
462*00b67f09SDavid van Moolenbroek isc_result_totext(result));
463*00b67f09SDavid van Moolenbroek
464*00b67f09SDavid van Moolenbroek /*
465*00b67f09SDavid van Moolenbroek * Did we get an error?
466*00b67f09SDavid van Moolenbroek */
467*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
468*00b67f09SDavid van Moolenbroek if (client->find != NULL)
469*00b67f09SDavid van Moolenbroek dns_adb_destroyfind(&client->find);
470*00b67f09SDavid van Moolenbroek cleanup_gabn(client);
471*00b67f09SDavid van Moolenbroek ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE);
472*00b67f09SDavid van Moolenbroek return;
473*00b67f09SDavid van Moolenbroek }
474*00b67f09SDavid van Moolenbroek
475*00b67f09SDavid van Moolenbroek claimed = ISC_FALSE;
476*00b67f09SDavid van Moolenbroek
477*00b67f09SDavid van Moolenbroek /*
478*00b67f09SDavid van Moolenbroek * Did we get our answer to V4 addresses?
479*00b67f09SDavid van Moolenbroek */
480*00b67f09SDavid van Moolenbroek if (NEED_V4(client)
481*00b67f09SDavid van Moolenbroek && ((client->find->query_pending & DNS_ADBFIND_INET) == 0)) {
482*00b67f09SDavid van Moolenbroek ns_lwdclient_log(50, "client %p ipv4 satisfied by find %p",
483*00b67f09SDavid van Moolenbroek client, client->find);
484*00b67f09SDavid van Moolenbroek claimed = ISC_TRUE;
485*00b67f09SDavid van Moolenbroek client->v4find = client->find;
486*00b67f09SDavid van Moolenbroek }
487*00b67f09SDavid van Moolenbroek
488*00b67f09SDavid van Moolenbroek /*
489*00b67f09SDavid van Moolenbroek * Did we get our answer to V6 addresses?
490*00b67f09SDavid van Moolenbroek */
491*00b67f09SDavid van Moolenbroek if (NEED_V6(client)
492*00b67f09SDavid van Moolenbroek && ((client->find->query_pending & DNS_ADBFIND_INET6) == 0)) {
493*00b67f09SDavid van Moolenbroek ns_lwdclient_log(50, "client %p ipv6 satisfied by find %p",
494*00b67f09SDavid van Moolenbroek client, client->find);
495*00b67f09SDavid van Moolenbroek claimed = ISC_TRUE;
496*00b67f09SDavid van Moolenbroek client->v6find = client->find;
497*00b67f09SDavid van Moolenbroek }
498*00b67f09SDavid van Moolenbroek
499*00b67f09SDavid van Moolenbroek /*
500*00b67f09SDavid van Moolenbroek * If we're going to get an event, set our internal pending flag
501*00b67f09SDavid van Moolenbroek * and return. When we get an event back we'll do the right
502*00b67f09SDavid van Moolenbroek * thing, basically by calling this function again, perhaps with a
503*00b67f09SDavid van Moolenbroek * new target name.
504*00b67f09SDavid van Moolenbroek *
505*00b67f09SDavid van Moolenbroek * If we have both v4 and v6, and we are still getting an event,
506*00b67f09SDavid van Moolenbroek * we have a programming error, so die hard.
507*00b67f09SDavid van Moolenbroek */
508*00b67f09SDavid van Moolenbroek if ((client->find->options & DNS_ADBFIND_WANTEVENT) != 0) {
509*00b67f09SDavid van Moolenbroek ns_lwdclient_log(50, "event will be sent");
510*00b67f09SDavid van Moolenbroek INSIST(client->v4find == NULL || client->v6find == NULL);
511*00b67f09SDavid van Moolenbroek return;
512*00b67f09SDavid van Moolenbroek }
513*00b67f09SDavid van Moolenbroek ns_lwdclient_log(50, "no event will be sent");
514*00b67f09SDavid van Moolenbroek if (claimed)
515*00b67f09SDavid van Moolenbroek client->find = NULL;
516*00b67f09SDavid van Moolenbroek else
517*00b67f09SDavid van Moolenbroek dns_adb_destroyfind(&client->find);
518*00b67f09SDavid van Moolenbroek
519*00b67f09SDavid van Moolenbroek /*
520*00b67f09SDavid van Moolenbroek * We seem to have everything we asked for, or at least we are
521*00b67f09SDavid van Moolenbroek * able to respond with things we've learned.
522*00b67f09SDavid van Moolenbroek */
523*00b67f09SDavid van Moolenbroek
524*00b67f09SDavid van Moolenbroek generate_reply(client);
525*00b67f09SDavid van Moolenbroek }
526*00b67f09SDavid van Moolenbroek
527*00b67f09SDavid van Moolenbroek static isc_result_t
start_find(ns_lwdclient_t * client)528*00b67f09SDavid van Moolenbroek start_find(ns_lwdclient_t *client) {
529*00b67f09SDavid van Moolenbroek isc_result_t result;
530*00b67f09SDavid van Moolenbroek
531*00b67f09SDavid van Moolenbroek /*
532*00b67f09SDavid van Moolenbroek * Initialize the real name and alias arrays in the reply we're
533*00b67f09SDavid van Moolenbroek * going to build up.
534*00b67f09SDavid van Moolenbroek */
535*00b67f09SDavid van Moolenbroek init_gabn(client);
536*00b67f09SDavid van Moolenbroek
537*00b67f09SDavid van Moolenbroek result = store_realname(client);
538*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
539*00b67f09SDavid van Moolenbroek return (result);
540*00b67f09SDavid van Moolenbroek restart_find(client);
541*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
542*00b67f09SDavid van Moolenbroek
543*00b67f09SDavid van Moolenbroek }
544*00b67f09SDavid van Moolenbroek
545*00b67f09SDavid van Moolenbroek static void
init_gabn(ns_lwdclient_t * client)546*00b67f09SDavid van Moolenbroek init_gabn(ns_lwdclient_t *client) {
547*00b67f09SDavid van Moolenbroek int i;
548*00b67f09SDavid van Moolenbroek
549*00b67f09SDavid van Moolenbroek /*
550*00b67f09SDavid van Moolenbroek * Initialize the real name and alias arrays in the reply we're
551*00b67f09SDavid van Moolenbroek * going to build up.
552*00b67f09SDavid van Moolenbroek */
553*00b67f09SDavid van Moolenbroek for (i = 0; i < LWRES_MAX_ALIASES; i++) {
554*00b67f09SDavid van Moolenbroek client->aliases[i] = NULL;
555*00b67f09SDavid van Moolenbroek client->aliaslen[i] = 0;
556*00b67f09SDavid van Moolenbroek }
557*00b67f09SDavid van Moolenbroek for (i = 0; i < LWRES_MAX_ADDRS; i++) {
558*00b67f09SDavid van Moolenbroek client->addrs[i].family = 0;
559*00b67f09SDavid van Moolenbroek client->addrs[i].length = 0;
560*00b67f09SDavid van Moolenbroek memset(client->addrs[i].address, 0, LWRES_ADDR_MAXLEN);
561*00b67f09SDavid van Moolenbroek LWRES_LINK_INIT(&client->addrs[i], link);
562*00b67f09SDavid van Moolenbroek }
563*00b67f09SDavid van Moolenbroek
564*00b67f09SDavid van Moolenbroek client->gabn.naliases = 0;
565*00b67f09SDavid van Moolenbroek client->gabn.naddrs = 0;
566*00b67f09SDavid van Moolenbroek client->gabn.realname = NULL;
567*00b67f09SDavid van Moolenbroek client->gabn.aliases = client->aliases;
568*00b67f09SDavid van Moolenbroek client->gabn.realnamelen = 0;
569*00b67f09SDavid van Moolenbroek client->gabn.aliaslen = client->aliaslen;
570*00b67f09SDavid van Moolenbroek LWRES_LIST_INIT(client->gabn.addrs);
571*00b67f09SDavid van Moolenbroek client->gabn.base = NULL;
572*00b67f09SDavid van Moolenbroek client->gabn.baselen = 0;
573*00b67f09SDavid van Moolenbroek
574*00b67f09SDavid van Moolenbroek /*
575*00b67f09SDavid van Moolenbroek * Set up the internal buffer to point to the receive region.
576*00b67f09SDavid van Moolenbroek */
577*00b67f09SDavid van Moolenbroek isc_buffer_init(&client->recv_buffer, client->buffer, LWRES_RECVLENGTH);
578*00b67f09SDavid van Moolenbroek }
579*00b67f09SDavid van Moolenbroek
580*00b67f09SDavid van Moolenbroek /*
581*00b67f09SDavid van Moolenbroek * When we are called, we can be assured that:
582*00b67f09SDavid van Moolenbroek *
583*00b67f09SDavid van Moolenbroek * client->sockaddr contains the address we need to reply to,
584*00b67f09SDavid van Moolenbroek *
585*00b67f09SDavid van Moolenbroek * client->pkt contains the packet header data,
586*00b67f09SDavid van Moolenbroek *
587*00b67f09SDavid van Moolenbroek * the packet "checks out" overall -- any MD5 hashes or crypto
588*00b67f09SDavid van Moolenbroek * bits have been verified,
589*00b67f09SDavid van Moolenbroek *
590*00b67f09SDavid van Moolenbroek * "b" points to the remaining data after the packet header
591*00b67f09SDavid van Moolenbroek * was parsed off.
592*00b67f09SDavid van Moolenbroek *
593*00b67f09SDavid van Moolenbroek * We are in a the RECVDONE state.
594*00b67f09SDavid van Moolenbroek *
595*00b67f09SDavid van Moolenbroek * From this state we will enter the SEND state if we happen to have
596*00b67f09SDavid van Moolenbroek * everything we need or we need to return an error packet, or to the
597*00b67f09SDavid van Moolenbroek * FINDWAIT state if we need to look things up.
598*00b67f09SDavid van Moolenbroek */
599*00b67f09SDavid van Moolenbroek void
ns_lwdclient_processgabn(ns_lwdclient_t * client,lwres_buffer_t * b)600*00b67f09SDavid van Moolenbroek ns_lwdclient_processgabn(ns_lwdclient_t *client, lwres_buffer_t *b) {
601*00b67f09SDavid van Moolenbroek isc_result_t result;
602*00b67f09SDavid van Moolenbroek lwres_gabnrequest_t *req;
603*00b67f09SDavid van Moolenbroek ns_lwdclientmgr_t *cm;
604*00b67f09SDavid van Moolenbroek isc_buffer_t namebuf;
605*00b67f09SDavid van Moolenbroek
606*00b67f09SDavid van Moolenbroek REQUIRE(NS_LWDCLIENT_ISRECVDONE(client));
607*00b67f09SDavid van Moolenbroek
608*00b67f09SDavid van Moolenbroek cm = client->clientmgr;
609*00b67f09SDavid van Moolenbroek req = NULL;
610*00b67f09SDavid van Moolenbroek
611*00b67f09SDavid van Moolenbroek result = lwres_gabnrequest_parse(client->clientmgr->lwctx,
612*00b67f09SDavid van Moolenbroek b, &client->pkt, &req);
613*00b67f09SDavid van Moolenbroek if (result != LWRES_R_SUCCESS)
614*00b67f09SDavid van Moolenbroek goto out;
615*00b67f09SDavid van Moolenbroek if (req->name == NULL)
616*00b67f09SDavid van Moolenbroek goto out;
617*00b67f09SDavid van Moolenbroek
618*00b67f09SDavid van Moolenbroek isc_buffer_init(&namebuf, req->name, req->namelen);
619*00b67f09SDavid van Moolenbroek isc_buffer_add(&namebuf, req->namelen);
620*00b67f09SDavid van Moolenbroek
621*00b67f09SDavid van Moolenbroek dns_fixedname_init(&client->target_name);
622*00b67f09SDavid van Moolenbroek dns_fixedname_init(&client->query_name);
623*00b67f09SDavid van Moolenbroek result = dns_name_fromtext(dns_fixedname_name(&client->query_name),
624*00b67f09SDavid van Moolenbroek &namebuf, NULL, 0, NULL);
625*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
626*00b67f09SDavid van Moolenbroek goto out;
627*00b67f09SDavid van Moolenbroek ns_lwsearchctx_init(&client->searchctx,
628*00b67f09SDavid van Moolenbroek cm->listener->manager->search,
629*00b67f09SDavid van Moolenbroek dns_fixedname_name(&client->query_name),
630*00b67f09SDavid van Moolenbroek cm->listener->manager->ndots);
631*00b67f09SDavid van Moolenbroek ns_lwsearchctx_first(&client->searchctx);
632*00b67f09SDavid van Moolenbroek
633*00b67f09SDavid van Moolenbroek client->find_wanted = req->addrtypes;
634*00b67f09SDavid van Moolenbroek ns_lwdclient_log(50, "client %p looking for addrtypes %08x",
635*00b67f09SDavid van Moolenbroek client, client->find_wanted);
636*00b67f09SDavid van Moolenbroek
637*00b67f09SDavid van Moolenbroek /*
638*00b67f09SDavid van Moolenbroek * We no longer need to keep this around.
639*00b67f09SDavid van Moolenbroek */
640*00b67f09SDavid van Moolenbroek lwres_gabnrequest_free(client->clientmgr->lwctx, &req);
641*00b67f09SDavid van Moolenbroek
642*00b67f09SDavid van Moolenbroek /*
643*00b67f09SDavid van Moolenbroek * Start the find.
644*00b67f09SDavid van Moolenbroek */
645*00b67f09SDavid van Moolenbroek result = start_find(client);
646*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
647*00b67f09SDavid van Moolenbroek goto out;
648*00b67f09SDavid van Moolenbroek
649*00b67f09SDavid van Moolenbroek return;
650*00b67f09SDavid van Moolenbroek
651*00b67f09SDavid van Moolenbroek /*
652*00b67f09SDavid van Moolenbroek * We're screwed. Return an error packet to our caller.
653*00b67f09SDavid van Moolenbroek */
654*00b67f09SDavid van Moolenbroek out:
655*00b67f09SDavid van Moolenbroek if (req != NULL)
656*00b67f09SDavid van Moolenbroek lwres_gabnrequest_free(client->clientmgr->lwctx, &req);
657*00b67f09SDavid van Moolenbroek
658*00b67f09SDavid van Moolenbroek ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE);
659*00b67f09SDavid van Moolenbroek }
660