2N/A * The contents of this file are subject to the terms of the 2N/A * Common Development and Distribution License (the "License"). 2N/A * You may not use this file except in compliance with the License. 2N/A * See the License for the specific language governing permissions 2N/A * and limitations under the License. 2N/A * When distributing Covered Code, include this CDDL HEADER in each 2N/A * If applicable, add the following below this CDDL HEADER, with the 2N/A * fields enclosed by brackets "[]" replaced with your own identifying 2N/A * information: Portions Copyright [yyyy] [name of copyright owner] 2N/A * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 2N/A * Use is subject to license terms. 2N/A#
pragma ident "%Z%%M% %I% %E% SMI" 2N/A#
define LEASEMIN 3600 /* minimum lease time allowed by RFC 1531 */ 2N/A * The parent (calling) thread and the child thread it spawns to do an 2N/A * update use this structure to rendezvous. The child thread sets the 2N/A * ``done'' variable to B_TRUE when it's completed its work. The nusers 2N/A * variable lets us arbitrate to see who has to clean up (via the 2N/A * provided childstat_cleanup() function) the dynamically-allocated 2N/A * structure - last one to wake up loses, and has to do the work. 2N/A * The given environment variable, if present, will contain the name 2N/A * of a file (or the distinguished values "stdout" and "stderr") into 2N/A * which we should place the debugging output from this shared object. 2N/A * The debugging output is basically free-form but uses the dprint() 2N/A * function to ensure that each message is tagged with its thread ID, 2N/A * so we have some hope of sorting out later what actually happened. 2N/A * This is the shared object startup function, called once when we 2N/A * Use res_ninit(3RESOLV) to see whether DNS has been configured 2N/A * on the host running this code. In practice, life must be very 2N/A * bad for res_ninit() to fail. 2N/A dprint(
"res_ninit() failed - dns_config_ok FALSE\n");
2N/A * This is the interface exported to the outside world. Control over 2N/A * the hostent structure is assumed to pass to dns_puthostent(); it will 2N/A * free the associated space when done. 2N/A * Check the consistency of the hostent structure: 2N/A * both the name and address fields should be valid, 2N/A * h_addrtype must be AF_INET, and h_length must be 2N/A * sizeof (struct in_addr); 2N/A dprint(
"h_addr_list is zero-length - return -1\n");
2N/A dprint(
"h_addrtype (%d) != AF_INET - return -1\n",
2N/A dprint(
"h_length (%d) != sizeof (struct in_addr) - return -1\n",
2N/A dprint(
"malloc (sizeof struct childstat) failed\n");
2N/A * From this point on, both hp and sp are cleaned up and freed via 2N/A * childstat_cleanup(), with bookkeeping done to see whether the 2N/A * parent thread or the child one should be the one in charge of 2N/A if (!
sp->
done) {
/* we might already have finished */ 2N/A /* if asynchronous, and child still working, just return; */ 2N/A /* otherwise, wait for child to finish or time to expire */ 2N/A * Child thread did not return before the 2N/A * timeout. One might think we could 2N/A * assert(sp->nusers > 1); 2N/A * here, but we can't: we must protect 2N/A * against this sequence of events: 2N/A * cond_timedwait() times out 2N/A * child finishes, grabs mutex, 2N/A * decrements nusers, sets done, 2N/A * cond_timedwait() reacquires the 2N/A * mutex and returns ETIME 2N/A * If this happens, nusers will now be 1, 2N/A * even though cond_timedwait() returned 2N/A /* child must have also set done */ 2N/A /* child thread has not returned */ 2N/A * This worker thread, spawned by dns_puthostent(), is responsible for 2N/A * seeing that the update work gets done and cleaning up afterward 2N/A * Paranoia: if nusers was 0 and we were asked to do a 2N/A * synchronous update, our parent must have incremented 2N/A * it, called cond_timedwait(), timed out, and decremented it, 2N/A * all before we got this far. In this case, we do nothing 2N/A * except clean up and exit. 2N/A * h_name should be full-qualified; find the name servers for 2N/A /* ... and send the update to one of them. */ 2N/A /* parent timed out and abandoned us - our turn to clean up */ 2N/A * Find a name server for the supplied domain and return its IP address. 2N/A * Sadly, in order to do this we have to parse the actual DNS reply 2N/A * packet - no functions are provided for doing this work for us. 2N/A dprint(
"getNS: found cached IP address for domain %s\n",
2N/A * Look for indicators from libresolv:res_nsend() 2N/A * that we should retry a request. 2N/A dprint(
"getNS retry: errno %d, h_errno %d\n",
2N/A dprint(
"getNS(\"%s\"): res_nquery failed " "(h_errno %d)\n",
2N/A data = (
unsigned char *)&
hp[
1];
/* a DNS paradigm - actually abuf.buf */ 2N/A dprint(
"getNS: fell through res_nquery results - no A records\n");
2N/A * The reply contained NS records, but no A records. Use 2N/A * res_gethostbyname() to get the name server's address 2N/A dprint(
"getNS: reply contained no NS records\n");
2N/A * Cache the <domain, IP address> tuple (which is assumed to not already 2N/A * be cached) for ttl seconds. 2N/A dprint(
"cacheNS: ttl 0 - nothing to cache\n");
2N/A * See whether the <domain, IP address> tuple has been cached. 2N/A * Do the work of updating DNS to have the <hp->h_name <-> hp->h_addr> 2N/A /* If debugging output desired, then ask resolver to do it, too */ 2N/A /* Construct the fully-qualified name for PTR record updates */ 2N/A /* LINTED - alignment */ 2N/A "%u.%u.%u.%u.in-addr.ARPA",
2N/A * The steps in doing an update: 2N/A * - delete any A records 2N/A * - delete any PTR records 2N/A * - add a PTR record 2N/A/* delete A records for this fully-qualified name */ 2N/A dprint(
"res_nupdate (del A) failed - errno %d, h_errno %d\n",
2N/A/* delete PTR records for this address */ 2N/A dprint(
"res_nupdate (del PTR) failed - errno %d, h_errno %d\n",
2N/A/* add an A record for this fqdn <-> addr pair */ 2N/A dprint(
"res_mkupdrec (add A PREREQ) failed\n");
2N/A dprint(
"res_mkupdrec (add A UPDATE) failed\n");
2N/A dprint(
"res_nupdate (ADD A) failed - errno %d, h_errno %d\n",
2N/A/* add a PTR record for this fqdn <-> address pair */ 2N/A dprint(
"res_mkupdrec (add PTR DELETE) failed\n");
2N/A dprint(
"res_mkupdrec (add PTR ADD) failed\n");
2N/A dprint(
"res_nupdate (ADD PTR) failed - errno %d, h_errno %d\n",
2N/A/* retry an update request when appropriate */ 2N/A * Look for indicators from libresolv:res_nsend() 2N/A * that we should retry a request. 2N/A dprint(
"retry_update - errno %d, h_errno %d\n",
2N/A * Parse a 16-bit quantity from a DNS reply packet. 2N/Astatic unsigned short 2N/A * Parse a 32-bit quantity from a DNS reply packet. 2N/A * Clean up a childstat structure's synchronization variables and free 2N/A * the allocated memory. 2N/A * Format and print a debug message, prepending the thread ID of the 2N/A * thread logging the message.