--- /dev/null
+#
+# Generated by the Apple Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = resolv
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Library
+
+HFILES = dns.h dns_private.h dns_util.h dst.h dst_internal.h\
+ nameser.h res_debug.h res_private.h res_update.h resolv.h
+
+CFILES = base64.c dns.c dns_async.c dns_util.c dst_api.c\
+ dst_hmac_link.c dst_support.c ns_date.c ns_name.c ns_netint.c\
+ ns_parse.c ns_print.c ns_samedomain.c ns_sign.c ns_ttl.c\
+ ns_verify.c res_comp.c res_data.c res_debug.c\
+ res_findzonecut.c res_init.c res_mkquery.c res_mkupdate.c\
+ res_query.c res_send.c res_sendsigned.c res_update.c
+
+OTHERSRCS = Makefile Makefile.postamble Makefile.preamble resolver.3 resolver_so.3 resolver.5
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CURRENTLY_ACTIVE_VERSION = YES
+DEPLOY_WITH_VERSION_NAME = 9
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = library.make
+NEXTSTEP_INSTALLDIR = /usr/lib
+LIBS = -ldnsinfo
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+PUBLIC_HEADERS = dns.h dns_util.h nameser.h resolv.h
+
+PROJECT_HEADERS = dns.h dns_private.h dns_util.h dst.h dst_internal.h\
+ nameser.h res_debug.h res_private.h res_update.h\
+ resolv.h
+
+
+
+WINDOWS_PUBLIC_HEADERS_DIR = LOCAL_DEVELOPER_DIR/Headers/$(NAME)
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(JDKBINDIR)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
--- /dev/null
+arpa_headers: $(DSTROOT)$(PUBLIC_HDR_INSTALLDIR)$(ARPA_HEADER_DIR_SUFFIX)
+ $(RM) -f $(foreach header, $(ARPA_SYMLINKED_HEADERS), $(DSTROOT)$(PUBLIC_HDR_INSTALLDIR)$(ARPA_HEADER_DIR_SUFFIX)/$(header))
+ $(LN) -s $(foreach header, $(ARPA_SYMLINKED_HEADERS), ../$(header)) $(DSTROOT)$(PUBLIC_HDR_INSTALLDIR)$(ARPA_HEADER_DIR_SUFFIX)
+ $(SILENT) $(FASTCP) $(ARPA_HEADERS) $(DSTROOT)$(PUBLIC_HDR_INSTALLDIR)$(ARPA_HEADER_DIR_SUFFIX)
+
+$(DSTROOT)$(PUBLIC_HDR_INSTALLDIR)$(ARPA_HEADER_DIR_SUFFIX):
+ $(MKDIRS) $@
+
+after_install: $(DSTROOT)/usr/share/man/man3 $(DSTROOT)/usr/share/man/man5
+ install -d $(DSTROOT)/usr/share/man/man3
+ install -c -m 644 resolver.3 $(DSTROOT)/usr/share/man/man3
+ install -c -m 644 resolver_so.3 $(DSTROOT)/usr/share/man/man3/dn_comp.3
+ install -c -m 644 resolver_so.3 $(DSTROOT)/usr/share/man/man3/dn_expand.3
+ install -c -m 644 resolver_so.3 $(DSTROOT)/usr/share/man/man3/dn_skipname.3
+ install -c -m 644 resolver_so.3 $(DSTROOT)/usr/share/man/man3/ns_get16.3
+ install -c -m 644 resolver_so.3 $(DSTROOT)/usr/share/man/man3/ns_get32.3
+ install -c -m 644 resolver_so.3 $(DSTROOT)/usr/share/man/man3/ns_put16.3
+ install -c -m 644 resolver_so.3 $(DSTROOT)/usr/share/man/man3/ns_put32.3
+ install -c -m 644 resolver_so.3 $(DSTROOT)/usr/share/man/man3/res_init.3
+ install -c -m 644 resolver_so.3 $(DSTROOT)/usr/share/man/man3/res_mkquery.3
+ install -c -m 644 resolver_so.3 $(DSTROOT)/usr/share/man/man3/res_query.3
+ install -c -m 644 resolver_so.3 $(DSTROOT)/usr/share/man/man3/res_search.3
+ install -c -m 644 resolver_so.3 $(DSTROOT)/usr/share/man/man3/res_send.3
+ install -d $(DSTROOT)/usr/share/man/man5
+ install -c -m 444 resolver.5 $(DSTROOT)/usr/share/man/man5
+
+$(DSTROOT)/usr/share/man/man3:
+ $(MKDIRS) $@
+
+$(DSTROOT)/usr/share/man/man5:
+ $(MKDIRS) $@
--- /dev/null
+PUBLIC_HEADER_DIR=/usr/include
+PUBLIC_HEADER_DIR_SUFFIX =
+ARPA_HEADER_DIR_SUFFIX = /arpa
+ARPA_SYMLINKED_HEADERS = nameser.h
+AFTER_INSTALLHDRS += arpa_headers
+
+PRIVATE_HEADER_DIR=/usr/local/include
+OTHER_PRIVATE_HEADERS += dns_private.h
--- /dev/null
+{
+ "CURRENTLY_ACTIVE_VERSION" = YES;
+ "DEPLOY_WITH_VERSION_NAME" = 9;
+ "DYNAMIC_CODE_GEN" = YES;
+ FILESTABLE = {
+ CLASSES = ();
+ HEADERSEARCH = ();
+ "H_FILES" = (
+ "dns.h",
+ "dns_private.h",
+ "dns_util.h",
+ "dst.h",
+ "dst_internal.h",
+ "nameser.h",
+ "res_debug.h",
+ "res_private.h",
+ "res_update.h",
+ "resolv.h"
+ );
+ "OTHER_LINKED" = (
+ "base64.c",
+ "dns.c",
+ "dns_async.c",
+ "dns_util.c",
+ "dst_api.c",
+ "dst_hmac_link.c",
+ "dst_support.c",
+ "ns_date.c",
+ "ns_name.c",
+ "ns_netint.c",
+ "ns_parse.c",
+ "ns_print.c",
+ "ns_samedomain.c",
+ "ns_sign.c",
+ "ns_ttl.c",
+ "ns_verify.c",
+ "res_comp.c",
+ "res_data.c",
+ "res_debug.c",
+ "res_findzonecut.c",
+ "res_init.c",
+ "res_mkquery.c",
+ "res_mkupdate.c",
+ "res_query.c",
+ "res_send.c",
+ "res_sendsigned.c",
+ "res_update.c"
+ );
+ "OTHER_SOURCES" = (Makefile, "Makefile.postamble", "Makefile.preamble", "resolver.5");
+ "PROJECT_HEADERS" = (
+ "dns.h",
+ "dns_private.h",
+ "dns_util.h",
+ "dst.h",
+ "dst_internal.h",
+ "nameser.h",
+ "res_debug.h",
+ "res_private.h",
+ "res_update.h",
+ "resolv.h"
+ );
+ "PUBLIC_HEADERS" = ("dns.h", "dns_util.h", "nameser.h", "resolv.h");
+ SUBPROJECTS = ();
+ };
+ LANGUAGE = English;
+ "LOCALIZABLE_FILES" = {};
+ MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles";
+ "NEXTSTEP_BUILDTOOL" = "/usr/bin/gnumake";
+ "NEXTSTEP_INSTALLDIR" = "/usr/lib";
+ "NEXTSTEP_JAVA_COMPILER" = "/usr/bin/javac";
+ "NEXTSTEP_OBJCPLUS_COMPILER" = "/usr/bin/cc";
+ "PDO_UNIX_BUILDTOOL" = "$NEXT_ROOT/Developer/bin/make";
+ "PDO_UNIX_JAVA_COMPILER" = "$(JDKBINDIR)/javac";
+ "PDO_UNIX_OBJCPLUS_COMPILER" = "$(NEXTDEV_BIN)/gcc";
+ PROJECTNAME = resolv;
+ PROJECTTYPE = Library;
+ PROJECTVERSION = "2.8";
+ "WINDOWS_BUILDTOOL" = "$NEXT_ROOT/Developer/Executables/make";
+ "WINDOWS_JAVA_COMPILER" = "$(JDKBINDIR)/javac.exe";
+ "WINDOWS_OBJCPLUS_COMPILER" = "$(DEVDIR)/gcc";
+ "WINDOWS_PUBLICHEADERSDIR" = "LOCAL_DEVELOPER_DIR/Headers/$(NAME)";
+}
--- /dev/null
+/*
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#ifndef __APPLE__
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: base64.c,v 1.1 2006/03/01 19:01:34 majka Exp $";
+#endif /* not lint */
+#endif
+
+#ifndef __APPLE__
+#include "port_before.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef __APPLE__
+#include "port_after.h"
+#endif
+
+#define Assert(Cond) if (!(Cond)) abort()
+
+static const char Base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
+ The following encoding technique is taken from RFC 1521 by Borenstein
+ and Freed. It is reproduced here in a slightly edited form for
+ convenience.
+
+ A 65-character subset of US-ASCII is used, enabling 6 bits to be
+ represented per printable character. (The extra 65th character, "=",
+ is used to signify a special processing function.)
+
+ The encoding process represents 24-bit groups of input bits as output
+ strings of 4 encoded characters. Proceeding from left to right, a
+ 24-bit input group is formed by concatenating 3 8-bit input groups.
+ These 24 bits are then treated as 4 concatenated 6-bit groups, each
+ of which is translated into a single digit in the base64 alphabet.
+
+ Each 6-bit group is used as an index into an array of 64 printable
+ characters. The character referenced by the index is placed in the
+ output string.
+
+ Table 1: The Base64 Alphabet
+
+ Value Encoding Value Encoding Value Encoding Value Encoding
+ 0 A 17 R 34 i 51 z
+ 1 B 18 S 35 j 52 0
+ 2 C 19 T 36 k 53 1
+ 3 D 20 U 37 l 54 2
+ 4 E 21 V 38 m 55 3
+ 5 F 22 W 39 n 56 4
+ 6 G 23 X 40 o 57 5
+ 7 H 24 Y 41 p 58 6
+ 8 I 25 Z 42 q 59 7
+ 9 J 26 a 43 r 60 8
+ 10 K 27 b 44 s 61 9
+ 11 L 28 c 45 t 62 +
+ 12 M 29 d 46 u 63 /
+ 13 N 30 e 47 v
+ 14 O 31 f 48 w (pad) =
+ 15 P 32 g 49 x
+ 16 Q 33 h 50 y
+
+ Special processing is performed if fewer than 24 bits are available
+ at the end of the data being encoded. A full encoding quantum is
+ always completed at the end of a quantity. When fewer than 24 input
+ bits are available in an input group, zero bits are added (on the
+ right) to form an integral number of 6-bit groups. Padding at the
+ end of the data is performed using the '=' character.
+
+ Since all base64 input is an integral number of octets, only the
+ -------------------------------------------------
+ following cases can arise:
+
+ (1) the final quantum of encoding input is an integral
+ multiple of 24 bits; here, the final unit of encoded
+ output will be an integral multiple of 4 characters
+ with no "=" padding,
+ (2) the final quantum of encoding input is exactly 8 bits;
+ here, the final unit of encoded output will be two
+ characters followed by two "=" padding characters, or
+ (3) the final quantum of encoding input is exactly 16 bits;
+ here, the final unit of encoded output will be three
+ characters followed by one "=" padding character.
+ */
+
+int
+b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) {
+ size_t datalength = 0;
+ u_char input[3];
+ u_char output[4];
+ size_t i;
+
+ while (2 < srclength) {
+ input[0] = *src++;
+ input[1] = *src++;
+ input[2] = *src++;
+ srclength -= 3;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ output[3] = input[2] & 0x3f;
+ Assert(output[0] < 64);
+ Assert(output[1] < 64);
+ Assert(output[2] < 64);
+ Assert(output[3] < 64);
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Base64[output[3]];
+ }
+
+ /* Now we worry about padding. */
+ if (0 != srclength) {
+ /* Get what's left. */
+ input[0] = input[1] = input[2] = '\0';
+ for (i = 0; i < srclength; i++)
+ input[i] = *src++;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ Assert(output[0] < 64);
+ Assert(output[1] < 64);
+ Assert(output[2] < 64);
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ if (srclength == 1)
+ target[datalength++] = Pad64;
+ else
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Pad64;
+ }
+ if (datalength >= targsize)
+ return (-1);
+ target[datalength] = '\0'; /* Returned value doesn't count \0. */
+ return (datalength);
+}
+
+/* skips all whitespace anywhere.
+ converts characters, four at a time, starting at (or after)
+ src from base - 64 numbers into three 8 bit bytes in the target area.
+ it returns the number of data bytes stored at the target, or -1 on error.
+ */
+
+int
+b64_pton(src, target, targsize)
+ char const *src;
+ u_char *target;
+ size_t targsize;
+{
+ int tarindex, state, ch;
+ char *pos;
+
+ state = 0;
+ tarindex = 0;
+
+ while ((ch = *src++) != '\0') {
+ if (isspace(ch)) /* Skip whitespace anywhere. */
+ continue;
+
+ if (ch == Pad64)
+ break;
+
+ pos = strchr(Base64, ch);
+ if (pos == 0) /* A non-base64 character. */
+ return (-1);
+
+ switch (state) {
+ case 0:
+ if (target) {
+ if ((size_t)tarindex >= targsize)
+ return (-1);
+ target[tarindex] = (pos - Base64) << 2;
+ }
+ state = 1;
+ break;
+ case 1:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 4;
+ target[tarindex+1] = ((pos - Base64) & 0x0f)
+ << 4 ;
+ }
+ tarindex++;
+ state = 2;
+ break;
+ case 2:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 2;
+ target[tarindex+1] = ((pos - Base64) & 0x03)
+ << 6;
+ }
+ tarindex++;
+ state = 3;
+ break;
+ case 3:
+ if (target) {
+ if ((size_t)tarindex >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64);
+ }
+ tarindex++;
+ state = 0;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ /*
+ * We are done decoding Base-64 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+
+ if (ch == Pad64) { /* We got a pad char. */
+ ch = *src++; /* Skip it, get next. */
+ switch (state) {
+ case 0: /* Invalid = in first position */
+ case 1: /* Invalid = in second position */
+ return (-1);
+
+ case 2: /* Valid, means one byte of info */
+ /* Skip any number of spaces. */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (!isspace(ch))
+ break;
+ /* Make sure there is another trailing = sign. */
+ if (ch != Pad64)
+ return (-1);
+ ch = *src++; /* Skip the = */
+ /* Fall through to "single trailing =" case. */
+ /* FALLTHROUGH */
+
+ case 3: /* Valid, means two bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (!isspace(ch))
+ return (-1);
+
+ /*
+ * Now make sure for cases 2 and 3 that the "extra"
+ * bits that slopped past the last full byte were
+ * zeros. If we don't check them, they become a
+ * subliminal channel.
+ */
+ if (target && target[tarindex] != 0)
+ return (-1);
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != 0)
+ return (-1);
+ }
+
+ return (tarindex);
+}
--- /dev/null
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "dns.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <sys/dir.h>
+#include <errno.h>
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <pthread.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <fcntl.h>
+#include <notify.h>
+#include <dnsinfo.h>
+#include "dns_private.h"
+#include "res_private.h"
+
+#define INET_NTOP_AF_INET_OFFSET 4
+#define INET_NTOP_AF_INET6_OFFSET 8
+
+#define SEARCH_COUNT_INIT -1
+
+#define DNS_RESOLVER_DIR "/etc/resolver"
+
+#define NOTIFY_DIR_NAME "com.apple.system.dns.resolver.dir"
+#define DNS_DELAY_NAME "com.apple.system.dns.delay"
+
+#define DNS_DELAY_INTERVAL 4
+
+#define DNS_PRIVATE_HANDLE_TYPE_SUPER 0
+#define DNS_PRIVATE_HANDLE_TYPE_PLAIN 1
+
+#define MDNS_MIN_TTL 2
+
+extern uint32_t notify_monitor_file(int token, const char *name, int flags);
+
+extern void res_client_close(res_state res);
+extern res_state res_state_new();
+extern int res_nquery_soa_min(res_state statp, const char *name, int class, int type, u_char *answer, int anslen, struct sockaddr *from, int *fromlen, int *min);
+extern int res_nsearch_2(res_state statp, const char *name, int class, int type, u_char *answer, int anslen, struct sockaddr *from, uint32_t *fromlen);
+extern int __res_nsearch_list_2(res_state statp, const char *name, int class, int type, u_char *answer, int anslen, struct sockaddr *from, uint32_t *fromlen, int nsearch, char **search);
+
+extern char *res_next_word(char **p);
+extern res_state res_build_start(res_state res);
+extern int res_build(res_state res, uint16_t port, uint32_t *nsrch, char *key, char *val);
+extern int res_build_sortlist(res_state res, struct in_addr addr, struct in_addr mask);
+
+static void
+_pdns_set_name(pdns_handle_t *pdns, const char *name)
+{
+ int n;
+
+ if (pdns == NULL) return;
+ if (name == NULL) return;
+
+ /* only set the name once */
+ if (pdns->name != NULL) return;
+
+ /* strip trailing dots */
+ n = strlen(name) - 1;
+ while ((n >= 0) && (name[n] == '.')) n--;
+
+ if (n < 0) return;
+
+ n++;
+ pdns->name = calloc(n + 1, sizeof(char));
+ if (pdns->name == NULL) return;
+ memcpy(pdns->name, name, n);
+}
+
+static pdns_handle_t *
+_pdns_build_start(char *name)
+{
+ pdns_handle_t *pdns;
+
+ pdns = (pdns_handle_t *)calloc(1, sizeof(pdns_handle_t));
+ if (pdns == NULL) return NULL;
+
+ pdns->res = res_build_start(NULL);
+ if (pdns->res == NULL)
+ {
+ free(pdns);
+ return NULL;
+ }
+
+ _pdns_set_name(pdns, name);
+ pdns->port = NS_DEFAULTPORT;
+
+ return pdns;
+}
+
+static int
+_pdns_build_finish(pdns_handle_t *pdns)
+{
+ uint32_t n;
+
+ if (pdns == NULL) return -1;
+
+ n = pdns->res->nscount;
+ if (n == 0) n = 1;
+
+ if (pdns->total_timeout == 0)
+ {
+ if (pdns->send_timeout == 0) pdns->total_timeout = RES_MAXRETRANS;
+ else pdns->total_timeout = pdns->send_timeout * pdns->res->retry * n;
+ }
+
+ if (pdns->total_timeout == 0) pdns->res->retrans = RES_MAXRETRANS;
+ else pdns->res->retrans = pdns->total_timeout;
+
+ pdns->res->options |= RES_INIT;
+
+ return 0;
+}
+
+static int
+_pdns_build_sortlist(pdns_handle_t *pdns, struct in_addr addr, struct in_addr mask)
+{
+ if (pdns == NULL) return -1;
+ return res_build_sortlist(pdns->res, addr, mask);
+}
+
+static void
+_pdns_free(pdns_handle_t *pdns)
+{
+ int i;
+
+ if (pdns == NULL) return;
+
+ if ((pdns->search_count != SEARCH_COUNT_INIT) && (pdns->search_count > 0) && (pdns->search_list != NULL))
+ {
+ for (i = 0; i < pdns->search_count; i++) free(pdns->search_list[i]);
+ free(pdns->search_list);
+ }
+
+ if (pdns->name != NULL) free(pdns->name);
+ if (pdns->res != NULL) res_client_close(pdns->res);
+
+ free(pdns);
+}
+
+static int
+_pdns_build(pdns_handle_t *pdns, char *key, char *val)
+{
+ struct in6_addr addr6;
+ int32_t status;
+ char *dupval;
+
+ if (pdns == NULL) return -1;
+
+ /*
+ * Detect IPv6 server addresses.
+ */
+ if (((pdns->flags & DNS_FLAG_HAVE_IPV6_SERVER) == 0) && (!strcmp(key, "nameserver")))
+ {
+ memset(&addr6, 0, sizeof(struct in6_addr));
+ status = inet_pton(AF_INET6, val, &addr6);
+ if (status == 1) pdns->flags |= DNS_FLAG_HAVE_IPV6_SERVER;
+ }
+
+ /*
+ * We handle some keys here.
+ * Other keys get passed on to res_build.
+ */
+ if (!strcmp(key, "default"))
+ {
+ pdns->flags |= DNS_FLAG_DEFAULT_RESOLVER;
+ return 0;
+ }
+
+ if (!strcmp(key, "port"))
+ {
+ pdns->port = atoi(val);
+ return 0;
+ }
+
+ if (!strcmp(key, "search"))
+ {
+ dupval = strdup(val);
+ if (dupval == NULL) return -1;
+
+ if (pdns->search_count == SEARCH_COUNT_INIT) pdns->search_count = 0;
+ if (pdns->search_count == 0)
+ {
+ pdns->search_list = (char **)calloc(1, sizeof(char *));
+ }
+ else
+ {
+ pdns->search_list = (char **)reallocf(pdns->search_list, (pdns->search_count + 1) * sizeof(char *));
+ }
+
+ if (pdns->search_list == NULL)
+ {
+ free(dupval);
+ _pdns_free(pdns);
+ return -1;
+ }
+
+ pdns->search_list[pdns->search_count] = dupval;
+ pdns->search_count++;
+ return 0;
+ }
+
+ if (!strcmp(key, "total_timeout"))
+ {
+ pdns->total_timeout = atoi(val);
+ return 0;
+ }
+
+ if (!strcmp(key, "timeout"))
+ {
+ pdns->send_timeout = atoi(val);
+ return 0;
+ }
+
+ if (!strcmp(key, "search_order"))
+ {
+ pdns->search_order = atoi(val);
+ return 0;
+ }
+
+ if (!strcmp(key, "pdns"))
+ {
+ pdns->flags |= DNS_FLAG_FORWARD_TO_MDNSRESPONDER;
+ return 0;
+ }
+
+ if (!strcmp(key, "mdns"))
+ {
+ pdns->flags |= DNS_FLAG_FORWARD_TO_MDNSRESPONDER;
+ return 0;
+ }
+
+ /* pass on to res_build */
+ return res_build(pdns->res, pdns->port, &(pdns->search_count), key, val);
+}
+
+static pdns_handle_t *
+_pdns_convert_sc(dns_resolver_t *r)
+{
+ pdns_handle_t *pdns;
+ char *val, *p, *x;
+ int i;
+
+ pdns = _pdns_build_start(r->domain);
+ if (r->domain == NULL) _pdns_build(pdns, "default", NULL);
+
+ p = getenv("RES_RETRY_TIMEOUT");
+ if (p != NULL) pdns->send_timeout = atoi(p);
+
+ p = getenv("RES_RETRY");
+ if (p != NULL) pdns->res->retry= atoi(p);
+
+ if (r->port != 0)
+ {
+ val = NULL;
+ asprintf(&val, "%hu", r->port);
+ if (val == NULL)
+ {
+ _pdns_free(pdns);
+ return NULL;
+ }
+
+ _pdns_build(pdns, "port", val);
+ free(val);
+ }
+
+ if (r->n_nameserver > MAXNS) r->n_nameserver = MAXNS;
+ for (i = 0; i < r->n_nameserver; i++)
+ {
+ if (r->nameserver[i]->sa_family == AF_INET)
+ {
+ val = calloc(1, 256);
+ if (val == NULL)
+ {
+ _pdns_free(pdns);
+ return NULL;
+ }
+
+ inet_ntop(AF_INET, (char *)(r->nameserver[i]) + INET_NTOP_AF_INET_OFFSET, val, 256);
+ _pdns_build(pdns, "nameserver", val);
+ free(val);
+ }
+ else if (r->nameserver[i]->sa_family == AF_INET6)
+ {
+ pdns->flags |= DNS_FLAG_HAVE_IPV6_SERVER;
+ val = calloc(1, 256);
+ if (val == NULL)
+ {
+ _pdns_free(pdns);
+ return NULL;
+ }
+
+ inet_ntop(AF_INET6, (char *)(r->nameserver[i]) + INET_NTOP_AF_INET6_OFFSET, val, 256);
+ _pdns_build(pdns, "nameserver", val);
+ free(val);
+ }
+ }
+
+ if (r->n_search > MAXDNSRCH) r->n_search = MAXDNSRCH;
+ for (i = 0; i < r->n_search; i++)
+ {
+ val = NULL;
+ asprintf(&val, "%s", r->search[i]);
+ if (val == NULL)
+ {
+ _pdns_free(pdns);
+ return NULL;
+ }
+
+ _pdns_build(pdns, "search", val);
+ free(val);
+ }
+
+ if (r->timeout > 0)
+ {
+ val = NULL;
+ asprintf(&val, "%d", r->timeout);
+ if (val == NULL)
+ {
+ _pdns_free(pdns);
+ return NULL;
+ }
+
+ _pdns_build(pdns, "total_timeout", val);
+ free(val);
+ }
+
+ val = NULL;
+ asprintf(&val, "%d", r->search_order);
+ if (val == NULL)
+ {
+ _pdns_free(pdns);
+ return NULL;
+ }
+
+ _pdns_build(pdns, "search_order", val);
+ free(val);
+
+ if (r->n_sortaddr > MAXRESOLVSORT) r->n_sortaddr = MAXRESOLVSORT;
+ for (i = 0; i < r->n_sortaddr; i++)
+ {
+ _pdns_build_sortlist(pdns, r->sortaddr[i]->address, r->sortaddr[i]->mask);
+ }
+
+ p = r->options;
+ while (NULL != (x = res_next_word(&p)))
+ {
+ /* search for and process individual options */
+ if (!strncmp(x, "ndots:", 6))
+ {
+ _pdns_build(pdns, "ndots", x+6);
+ }
+
+ else if (!strncmp(x, "nibble:", 7))
+ {
+ _pdns_build(pdns, "nibble", x+7);
+ }
+
+ else if (!strncmp(x, "nibble2:", 8))
+ {
+ _pdns_build(pdns, "nibble2", x+8);
+ }
+
+ else if (!strncmp(x, "timeout:", 8))
+ {
+ _pdns_build(pdns, "timeout", x+8);
+ }
+
+ else if (!strncmp(x, "attempts:", 9))
+ {
+ _pdns_build(pdns, "attempts", x+9);
+ }
+
+ else if (!strncmp(x, "bitstring:", 10))
+ {
+ _pdns_build(pdns, "bitstring", x+10);
+ }
+
+ else if (!strncmp(x, "v6revmode:", 10))
+ {
+ _pdns_build(pdns, "v6revmode", x+10);
+ }
+
+ else if (!strcmp(x, "debug"))
+ {
+ _pdns_build(pdns, "debug", NULL);
+ }
+
+ else if (!strcmp(x, "no_tld_query"))
+ {
+ _pdns_build(pdns, "no_tld_query", NULL);
+ }
+
+ else if (!strcmp(x, "inet6"))
+ {
+ _pdns_build(pdns, "inet6", NULL);
+ }
+
+ else if (!strcmp(x, "rotate"))
+ {
+ _pdns_build(pdns, "rotate", NULL);
+ }
+
+ else if (!strcmp(x, "no-check-names"))
+ {
+ _pdns_build(pdns, "no-check-names", NULL);
+ }
+
+#ifdef RES_USE_EDNS0
+ else if (!strcmp(x, "edns0"))
+ {
+ _pdns_build(pdns, "edns0", NULL);
+ }
+#endif
+ else if (!strcmp(x, "a6"))
+ {
+ _pdns_build(pdns, "a6", NULL);
+ }
+
+ else if (!strcmp(x, "dname"))
+ {
+ _pdns_build(pdns, "dname", NULL);
+ }
+
+ else if (!strcmp(x, "default"))
+ {
+ _pdns_build(pdns, "default", NULL);
+ }
+
+ else if (!strcmp(x, "pdns"))
+ {
+ _pdns_build(pdns, "pdns", NULL);
+ }
+
+ else if (!strcmp(x, "mdns"))
+ {
+ _pdns_build(pdns, "mdns", NULL);
+ }
+ }
+
+ _pdns_build_finish(pdns);
+ return pdns;
+}
+
+/*
+ * Open a named resolver client from the system config data.
+ */
+static pdns_handle_t *
+_pdns_sc_open(const char *name)
+{
+ pdns_handle_t *pdns;
+ int i;
+ dns_config_t *sc_dns;
+ dns_resolver_t *sc_res;
+
+ sc_dns = dns_configuration_copy();
+ if (sc_dns == NULL) return NULL;
+
+ sc_res = NULL;
+
+ if (name == NULL)
+ {
+ if (sc_dns->n_resolver != 0) sc_res = sc_dns->resolver[0];
+ }
+ else
+ {
+ for (i = 0; (sc_res == NULL) && (i < sc_dns->n_resolver); i++)
+ {
+ if (sc_dns->resolver[i] == NULL) continue;
+ if (sc_dns->resolver[i]->domain == NULL) continue;
+ if (!strcasecmp(name, sc_dns->resolver[i]->domain)) sc_res = sc_dns->resolver[i];
+ }
+ }
+
+ if (sc_res == NULL)
+ {
+ dns_configuration_free(sc_dns);
+ return NULL;
+ }
+
+ pdns = (pdns_handle_t *)calloc(1, sizeof(pdns_handle_t));
+ if (pdns == NULL)
+ {
+ dns_configuration_free(sc_dns);
+ return NULL;
+ }
+
+ pdns = _pdns_convert_sc(sc_res);
+
+ dns_configuration_free(sc_dns);
+
+ if (pdns == NULL) return NULL;
+
+ if (pdns->res == NULL)
+ {
+ free(pdns);
+ return NULL;
+ }
+
+ pdns->name = NULL;
+ if (pdns->res->defdname[0] != '\0') _pdns_set_name(pdns, pdns->res->defdname);
+ else if (name != NULL) _pdns_set_name(pdns, name);
+
+ if (name != NULL) pdns->search_count = SEARCH_COUNT_INIT;
+
+ return pdns;
+}
+
+/*
+ * Open a named resolver client from file.
+ */
+static pdns_handle_t *
+_pdns_file_open(const char *name)
+{
+ pdns_handle_t *pdns;
+ char *path, buf[1024];
+ char *p, *x, *y;
+ FILE *fp;
+
+ path = NULL;
+ if (name == NULL)
+ {
+ asprintf(&path, "%s", _PATH_RESCONF);
+ }
+ else if ((name[0] == '.') || (name[0] == '/'))
+ {
+ asprintf(&path, "%s", name);
+ }
+ else
+ {
+ asprintf(&path, "%s/%s", DNS_RESOLVER_DIR, name);
+ }
+
+ if (path == NULL) return NULL;
+
+ fp = fopen(path, "r");
+ free(path);
+ if (fp == NULL) return NULL;
+
+ pdns = _pdns_build_start(NULL);
+ if (pdns == NULL)
+ {
+ fclose(fp);
+ return NULL;
+ }
+
+ p = getenv("RES_RETRY_TIMEOUT");
+ if (p != NULL) pdns->send_timeout = atoi(p);
+
+ p = getenv("RES_RETRY");
+ if (p != NULL) pdns->res->retry= atoi(p);
+
+ while (fgets(buf, sizeof(buf), fp) != NULL)
+ {
+ /* skip comments */
+ if ((buf[0] == ';') || (buf[0] == '#')) continue;
+ p = buf;
+ x = res_next_word(&p);
+ if (x == NULL) continue;
+ if (!strcmp(x, "sortlist"))
+ {
+ while (NULL != (x = res_next_word(&p)))
+ {
+ _pdns_build(pdns, "sortlist", x);
+ }
+ }
+ else if (!strcmp(x, "timeout"))
+ {
+ x = res_next_word(&p);
+ if (x != NULL) _pdns_build(pdns, "total_timeout", x);
+ }
+ else if (!strcmp(x, "options"))
+ {
+ while (NULL != (x = res_next_word(&p)))
+ {
+ y = strchr(x, ':');
+ if (y != NULL)
+ {
+ *y = '\0';
+ y++;
+ }
+ _pdns_build(pdns, x, y);
+ }
+ }
+ else
+ {
+ y = res_next_word(&p);
+ _pdns_build(pdns, x, y);
+
+ if ((!strcmp(x, "domain")) && (pdns->name == NULL)) _pdns_set_name(pdns, y);
+ }
+ }
+
+ fclose(fp);
+
+ if (pdns->name == NULL) _pdns_set_name(pdns, name);
+
+ _pdns_build_finish(pdns);
+
+ return pdns;
+}
+
+/*
+ * If there was no search list, use domain name and parent domain components.
+ *
+ * N.B. This code deals with multiple trailing dots, but does not deal with
+ * multiple internal dots, e.g. "foo.....com".
+ */
+static void
+_pdns_check_search_list(pdns_handle_t *pdns)
+{
+ int n;
+ char *p;
+
+ if (pdns == NULL) return;
+ if (pdns->name == NULL) return;
+ if (pdns->search_count > 0) return;
+
+ /* Count dots */
+ n = 0;
+ for (p = pdns->name; *p != '\0'; p++)
+ {
+ if (*p == '.') n++;
+ }
+
+ /* Back up over any trailing dots and cut them out of the name */
+ for (p--; (p >= pdns->name) && (*p == '.'); p--)
+ {
+ *p = '\0';
+ n--;
+ }
+
+ /* This will be true if name was all dots */
+ if (p < pdns->name) return;
+
+ /* dots are separators, so number of components is one larger */
+ n++;
+
+ _pdns_build(pdns, "search", pdns->name);
+
+ /* Include parent domains with at least LOCALDOMAINPARTS components */
+ p = pdns->name;
+ while (n > LOCALDOMAINPARTS)
+ {
+ /* Find next component */
+ while ((*p != '.') && (*p != '\0')) p++;
+ if (*p == '\0') break;
+ p++;
+
+ n--;
+ _pdns_build(pdns, "search", p);
+ }
+}
+
+__private_extern__ void
+_check_cache(sdns_handle_t *sdns)
+{
+ int i, n, status, refresh, sc_dns_count;
+ DIR *dp;
+ struct direct *d;
+ pdns_handle_t *c;
+ dns_config_t *sc_dns;
+
+ if (sdns == NULL) return;
+
+ refresh = 0;
+
+ if (sdns->stattime == 0) refresh = 1;
+
+ if (refresh == 0)
+ {
+ if (sdns->notify_sys_config_token == -1) refresh = 1;
+ else
+ {
+ n = 1;
+ status = notify_check(sdns->notify_sys_config_token, &n);
+ if ((status != NOTIFY_STATUS_OK) || (n == 1)) refresh = 1;
+ }
+ }
+
+ if (refresh == 0)
+ {
+ if (sdns->notify_dir_token == -1) refresh = 1;
+ else
+ {
+ n = 1;
+ status = notify_check(sdns->notify_dir_token, &n);
+ if ((status != NOTIFY_STATUS_OK) || (n == 1)) refresh = 1;
+ }
+ }
+
+ if (refresh == 0) return;
+
+ /* Free old clients */
+ sdns->pdns_primary = NULL;
+
+ for (i = 0; i < sdns->client_count; i++)
+ {
+ _pdns_free(sdns->client[i]);
+ }
+
+ sdns->client_count = 0;
+ if (sdns->client != NULL) free(sdns->client);
+ sdns->client = NULL;
+
+ /* Fetch clients from System Configuration */
+ sc_dns = dns_configuration_copy();
+
+ /* Set up Primary resolver. It's the one we consult for a search list */
+ sc_dns_count = 0;
+ if ((sc_dns != NULL) && (sc_dns->n_resolver > 0))
+ {
+ sc_dns_count = sc_dns->n_resolver;
+ sdns->pdns_primary = _pdns_convert_sc(sc_dns->resolver[0]);
+ _pdns_check_search_list(sdns->pdns_primary);
+ }
+ else
+ {
+ sdns->pdns_primary = _pdns_file_open(_PATH_RESCONF);
+ }
+
+ if (sdns->pdns_primary != NULL)
+ {
+ if ((sdns->flags & DNS_FLAG_DEBUG) && (sdns->pdns_primary->res != NULL)) sdns->pdns_primary->res->options |= RES_DEBUG;
+ if (sdns->flags & DNS_FLAG_OK_TO_SKIP_AAAA) sdns->pdns_primary->flags |= DNS_FLAG_OK_TO_SKIP_AAAA;
+ sdns->pdns_primary->flags |= DNS_FLAG_DEFAULT_RESOLVER;
+
+ sdns->client = (pdns_handle_t **)calloc(1, sizeof(pdns_handle_t *));
+ if (sdns->client == NULL)
+ {
+ if (sc_dns != NULL) dns_configuration_free(sc_dns);
+ return;
+ }
+
+ sdns->client[sdns->client_count] = sdns->pdns_primary;
+ sdns->client_count++;
+ }
+
+ /* Convert System Configuration resolvers */
+ for (i = 1; i < sc_dns_count; i++)
+ {
+ c = _pdns_convert_sc(sc_dns->resolver[i]);
+ if (c == NULL) continue;
+
+ if (sdns->flags & DNS_FLAG_DEBUG) c->res->options |= RES_DEBUG;
+ if (sdns->flags & DNS_FLAG_OK_TO_SKIP_AAAA) c->flags |= DNS_FLAG_OK_TO_SKIP_AAAA;
+
+ if (sdns->client_count == 0)
+ {
+ sdns->client = (pdns_handle_t **)calloc(1, sizeof(pdns_handle_t *));
+ }
+ else
+ {
+ sdns->client = (pdns_handle_t **)reallocf(sdns->client, (sdns->client_count + 1) * sizeof(pdns_handle_t *));
+ }
+
+ if (sdns->client == NULL)
+ {
+ sdns->client_count = 0;
+ dns_configuration_free(sc_dns);
+ return;
+ }
+
+ sdns->client[sdns->client_count] = c;
+ sdns->client_count++;
+ }
+
+ if (sc_dns != NULL) dns_configuration_free(sc_dns);
+
+ if (sdns->flags & DNS_FLAG_CHECK_RESOLVER_DIR)
+ {
+ /* Read /etc/resolvers clients */
+ dp = opendir(DNS_RESOLVER_DIR);
+ if (dp == NULL)
+ {
+ sdns->flags &= ~DNS_FLAG_CHECK_RESOLVER_DIR;
+ }
+ else
+ {
+ while (NULL != (d = readdir(dp)))
+ {
+ if (d->d_name[0] == '.') continue;
+
+ c = _pdns_file_open(d->d_name);
+ if (c == NULL) continue;
+ if (sdns->flags & DNS_FLAG_DEBUG) c->res->options |= RES_DEBUG;
+ if (sdns->flags & DNS_FLAG_OK_TO_SKIP_AAAA) c->flags |= DNS_FLAG_OK_TO_SKIP_AAAA;
+
+ if (sdns->client_count == 0)
+ {
+ sdns->client = (pdns_handle_t **)calloc(1, sizeof(pdns_handle_t *));
+ }
+ else
+ {
+ sdns->client = (pdns_handle_t **)reallocf(sdns->client, (sdns->client_count + 1) * sizeof(pdns_handle_t *));
+ }
+
+ if (sdns->client == NULL)
+ {
+ sdns->client_count = 0;
+ return;
+ }
+
+ sdns->client[sdns->client_count] = c;
+ sdns->client_count++;
+ }
+ closedir(dp);
+ }
+ }
+
+ sdns->stattime = 1;
+}
+
+static uint32_t
+_pdns_get_default_handles(sdns_handle_t *sdns, pdns_handle_t ***pdns)
+{
+ int i, j, k, count;
+
+ if (sdns == NULL) return 0;
+ if (pdns == NULL) return 0;
+
+ count = 0;
+
+ for (i = 0; i < sdns->client_count; i++)
+ {
+ if (sdns->client[i]->flags & DNS_FLAG_DEFAULT_RESOLVER)
+ {
+ if (count == 0)
+ {
+ *pdns = (pdns_handle_t **)calloc(1, sizeof(pdns_handle_t *));
+ }
+ else
+ {
+ *pdns = (pdns_handle_t **)reallocf((*pdns), (count + 1) * sizeof(pdns_handle_t *));
+ }
+
+ if (*pdns == NULL) return 0;
+
+ /* Insert sorted by search_order */
+ for (j = 0; j < count; j++)
+ {
+ if (sdns->client[i]->search_order < (*pdns)[j]->search_order) break;
+ }
+
+ for (k = count; k > j; k--) (*pdns)[k] = (*pdns)[k-1];
+ (*pdns)[j] = sdns->client[i];
+ count++;
+ }
+ }
+
+ return count;
+}
+
+static uint32_t
+_pdns_get_handles_for_name(sdns_handle_t *sdns, const char *name, pdns_handle_t ***pdns)
+{
+ char *p, *vname;
+ int i, j, k, count;
+
+ if (sdns == NULL) return 0;
+ if (pdns == NULL) return 0;
+
+ if (name == NULL) return _pdns_get_default_handles(sdns, pdns);
+ else if (name[0] == '\0') return _pdns_get_default_handles(sdns, pdns);
+
+ count = 0;
+
+ vname = strdup(name);
+ i = strlen(vname) - 1;
+ if ((i >= 0) && (vname[i] == '.')) vname[i] = '\0';
+
+ p = vname;
+ while (p != NULL)
+ {
+ for (i = 0; i < sdns->client_count; i++)
+ {
+ if (sdns->client[i]->name == NULL) continue;
+
+ if (!strcasecmp(sdns->client[i]->name, p))
+ {
+ if (count == 0)
+ {
+ *pdns = (pdns_handle_t **)calloc(1, sizeof(pdns_handle_t *));
+ }
+ else
+ {
+ *pdns = (pdns_handle_t **)reallocf((*pdns), (count + 1) * sizeof(pdns_handle_t *));
+ }
+
+ if (*pdns == NULL) return 0;
+
+ /* Insert sorted by search_order */
+ for (j = 0; j < count; j++)
+ {
+ if (sdns->client[i]->search_order < (*pdns)[j]->search_order) break;
+ }
+
+ for (k = count; k > j; k--) (*pdns)[k] = (*pdns)[k-1];
+ (*pdns)[j] = sdns->client[i];
+ count++;
+ }
+ }
+
+ p = strchr(p, '.');
+ if (p != NULL) p++;
+ }
+
+ free(vname);
+
+ if (count != 0) return count;
+
+ return _pdns_get_default_handles(sdns, pdns);;
+}
+
+static void
+_pdns_process_res_search_list(pdns_handle_t *pdns)
+{
+ if (pdns->search_count != SEARCH_COUNT_INIT) return;
+ for (pdns->search_count = 0; (pdns->res->dnsrch[pdns->search_count] != NULL) && (pdns->res->dnsrch[pdns->search_count][0] != '\0'); pdns->search_count++);
+}
+
+static char *
+_pdns_search_list_domain(pdns_handle_t *pdns, uint32_t i)
+{
+ char *s;
+
+ if (pdns == NULL) return NULL;
+ if (pdns->search_count == SEARCH_COUNT_INIT) _pdns_process_res_search_list(pdns);
+ if (i >= pdns->search_count) return NULL;
+
+ s = pdns->search_list[i];
+ if (s == NULL) return NULL;
+ return strdup(s);
+}
+
+static void
+_dns_open_notify(sdns_handle_t *sdns)
+{
+ int status, n;
+
+ if (sdns == NULL) return;
+
+ if (sdns->notify_delay_token == -1)
+ {
+ status = notify_register_check(DNS_DELAY_NAME, &(sdns->notify_delay_token));
+ if (status != NOTIFY_STATUS_OK) sdns->notify_delay_token = -1;
+ else status = notify_check(sdns->notify_delay_token, &n);
+ }
+
+ if (sdns->notify_sys_config_token == -1)
+ {
+ status = notify_register_check(dns_configuration_notify_key(), &(sdns->notify_sys_config_token));
+ if (status != NOTIFY_STATUS_OK) sdns->notify_sys_config_token = -1;
+ }
+
+ if (sdns->notify_dir_token == -1)
+ {
+ status = notify_register_check(NOTIFY_DIR_NAME, &(sdns->notify_dir_token));
+ if (status == NOTIFY_STATUS_OK)
+ {
+ status = notify_monitor_file(sdns->notify_dir_token, "/private/etc/resolver", 0);
+ if (status != NOTIFY_STATUS_OK)
+ {
+ notify_cancel(sdns->notify_dir_token);
+ sdns->notify_dir_token = -1;
+ }
+ }
+ else
+ {
+ sdns->notify_dir_token = -1;
+ }
+ }
+}
+
+static void
+_dns_close_notify(sdns_handle_t *sdns)
+{
+ if (sdns == NULL) return;
+
+ if (sdns->notify_delay_token != -1) notify_cancel(sdns->notify_delay_token);
+ sdns->notify_delay_token = -1;
+
+ if (sdns->notify_sys_config_token != -1) notify_cancel(sdns->notify_sys_config_token);
+ sdns->notify_sys_config_token = -1;
+
+ if (sdns->notify_dir_token != -1) notify_cancel(sdns->notify_dir_token);
+ sdns->notify_dir_token = -1;
+}
+
+dns_handle_t
+dns_open(const char *name)
+{
+ dns_private_handle_t *dns;
+
+ dns = (dns_private_handle_t *)calloc(1, sizeof(dns_private_handle_t));
+ if (dns == NULL) return NULL;
+
+ if (name == NULL)
+ {
+ dns->handle_type = DNS_PRIVATE_HANDLE_TYPE_SUPER;
+ dns->sdns = (sdns_handle_t *)calloc(1, sizeof(sdns_handle_t));
+ if (dns->sdns == NULL)
+ {
+ free(dns);
+ return NULL;
+ }
+
+ dns->sdns->flags |= DNS_FLAG_CHECK_RESOLVER_DIR;
+ dns->sdns->notify_sys_config_token = -1;
+ dns->sdns->notify_dir_token = -1;
+ dns->sdns->notify_delay_token = -1;
+ _dns_open_notify(dns->sdns);
+
+ return (dns_handle_t)dns;
+ }
+
+ dns->handle_type = DNS_PRIVATE_HANDLE_TYPE_PLAIN;
+
+ /* Look for name in System Configuration first */
+ dns->pdns = _pdns_sc_open(name);
+ if (dns->pdns == NULL) dns->pdns = _pdns_file_open(name);
+
+ if (dns->pdns == NULL)
+ {
+ free(dns);
+ return NULL;
+ }
+
+ return (dns_handle_t)dns;
+}
+
+/*
+ * Release a DNS client handle
+ */
+void
+dns_free(dns_handle_t d)
+{
+ dns_private_handle_t *dns;
+ int i;
+
+ if (d == NULL) return;
+
+ dns = (dns_private_handle_t *)d;
+
+ if (dns->recvbuf != NULL) free(dns->recvbuf);
+
+ if (dns->handle_type == DNS_PRIVATE_HANDLE_TYPE_SUPER)
+ {
+ if (dns->sdns == NULL) return;
+
+ _dns_close_notify(dns->sdns);
+
+ for (i = 0; i < dns->sdns->client_count; i++)
+ {
+ _pdns_free(dns->sdns->client[i]);
+ }
+
+ dns->sdns->client_count = 0;
+ if (dns->sdns->client != NULL) free(dns->sdns->client);
+
+ free(dns->sdns);
+ }
+ else
+ {
+ _pdns_free(dns->pdns);
+ }
+
+ free(dns);
+}
+
+static void
+_pdns_debug(pdns_handle_t *pdns, uint32_t flag)
+{
+ if (pdns == NULL) return;
+
+ if (flag == 0)
+ {
+ pdns->res->options &= ~RES_DEBUG;
+ }
+ else
+ {
+ pdns->res->options |= RES_DEBUG;
+ }
+}
+
+static void
+_sdns_debug(sdns_handle_t *sdns, uint32_t flag)
+{
+ int i;
+
+ if (sdns == NULL) return;
+
+ if (flag == 0)
+ {
+ sdns->flags &= ~ DNS_FLAG_DEBUG;
+
+ for (i = 0; i < sdns->client_count; i++)
+ {
+ sdns->client[i]->res->options &= ~RES_DEBUG;
+ }
+ }
+ else
+ {
+ sdns->flags |= DNS_FLAG_DEBUG;
+
+ for (i = 0; i < sdns->client_count; i++)
+ {
+ sdns->client[i]->res->options |= RES_DEBUG;
+ }
+ }
+}
+
+/*
+ * Enable / Disable debugging
+ */
+void
+dns_set_debug(dns_handle_t d, uint32_t flag)
+{
+ dns_private_handle_t *dns;
+
+ if (d == NULL) return;
+
+ dns = (dns_private_handle_t *)d;
+
+ if (dns->handle_type == DNS_PRIVATE_HANDLE_TYPE_SUPER)
+ {
+ _sdns_debug(dns->sdns, flag);
+ }
+ else
+ {
+ _pdns_debug(dns->pdns, flag);
+ }
+}
+
+/*
+ * Returns the number of names in the search list
+ */
+uint32_t
+dns_search_list_count(dns_handle_t d)
+{
+ dns_private_handle_t *dns;
+ pdns_handle_t *pdns;
+
+ if (d == NULL) return 0;
+
+ dns = (dns_private_handle_t *)d;
+
+ if (dns->handle_type == DNS_PRIVATE_HANDLE_TYPE_SUPER)
+ {
+ _check_cache(dns->sdns);
+ pdns = dns->sdns->pdns_primary;
+ }
+ else
+ {
+ pdns = dns->pdns;
+ }
+
+ if (pdns->search_count == SEARCH_COUNT_INIT) _pdns_process_res_search_list(pdns);
+ return pdns->search_count;
+}
+
+/*
+ * Returns the domain name at index i in the search list.
+ * Returns NULL if there are no names in the search list.
+ * Caller must free the returned name.
+ */
+char *
+dns_search_list_domain(dns_handle_t d, uint32_t i)
+{
+ dns_private_handle_t *dns;
+ pdns_handle_t *pdns;
+
+ if (d == NULL) return NULL;
+
+ dns = (dns_private_handle_t *)d;
+
+ if (dns->handle_type == DNS_PRIVATE_HANDLE_TYPE_SUPER)
+ {
+ _check_cache(dns->sdns);
+ pdns = dns->sdns->pdns_primary;
+ }
+ else
+ {
+ pdns = dns->pdns;
+ }
+
+ return _pdns_search_list_domain(pdns, i);
+}
+
+static int
+_pdns_delay(sdns_handle_t *sdns)
+{
+ int status, n, snooze;
+ time_t tick;
+
+ if (sdns == NULL) return 0;
+
+ snooze = 0;
+ n = 0;
+
+ /* No delay if we are not receiving notifications */
+ if (sdns->notify_delay_token == -1) return 0;
+
+ if (sdns->dns_delay == 0)
+ {
+ status = notify_check(sdns->notify_delay_token, &n);
+ if ((status == NOTIFY_STATUS_OK) && (n == 1))
+ {
+ /*
+ * First thread to hit this condition sleeps for DNS_DELAY_INTERVAL seconds
+ */
+ sdns->dns_delay = time(NULL) + DNS_DELAY_INTERVAL;
+ snooze = DNS_DELAY_INTERVAL;
+ }
+ }
+ else
+ {
+ tick = time(NULL);
+ /*
+ * Subsequent threads sleep for the remaining duration.
+ * We add one to round up the interval since our garnularity is coarse.
+ */
+ snooze = 1 + (sdns->dns_delay - tick);
+ if (snooze < 0) snooze = 0;
+ }
+
+ if (snooze == 0) return 0;
+
+ sleep(snooze);
+
+ /* When exiting, first thread in resets the delay condition */
+ if (n == 1) sdns->dns_delay = 0;
+
+ return 0;
+}
+
+static int
+_pdns_query(sdns_handle_t *sdns, pdns_handle_t *pdns, const char *name, uint32_t class, uint32_t type, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen, int *min)
+{
+ int n;
+
+ if (name == NULL) return -1;
+ if (pdns == NULL) return -1;
+
+ if (pdns->flags & DNS_FLAG_FORWARD_TO_MDNSRESPONDER)
+ {
+ n = res_query_mDNSResponder(pdns->res, name, class, type, (u_char *)buf, len, from, fromlen);
+ if ((n < 0) && (min != NULL)) *min = MDNS_MIN_TTL;
+ return n;
+ }
+
+ if (pdns->res == NULL) return -1;
+ if (pdns->res->nscount == 0) return -1;
+
+ if ((type == ns_t_aaaa) && ((pdns->flags & DNS_FLAG_HAVE_IPV6_SERVER) == 0) && (pdns->flags & DNS_FLAG_OK_TO_SKIP_AAAA)) return -1;
+
+ _pdns_delay(sdns);
+
+ /* BIND_9 API */
+ return res_nquery_soa_min(pdns->res, name, class, type, (u_char *)buf, len, from, (int32_t *)fromlen, min);
+}
+
+__private_extern__ int
+_pdns_search(sdns_handle_t *sdns, pdns_handle_t *pdns, const char *name, uint32_t class, uint32_t type, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen)
+{
+ char *dot, *qname;
+ int append, status;
+
+ if (name == NULL) return -1;
+ if (pdns == NULL) return -1;
+ if (pdns->res == NULL) return -1;
+ if (pdns->res->nscount == 0) return -1;
+
+ if ((type == ns_t_aaaa) && ((pdns->flags & DNS_FLAG_HAVE_IPV6_SERVER) == 0) && (pdns->flags & DNS_FLAG_OK_TO_SKIP_AAAA)) return -1;
+
+ qname = NULL;
+ append = 1;
+
+ /*
+ * don't append my name if:
+ * - my name is NULL
+ * - input name is qualified (i.e. not single component)
+ * - there is a search list
+ * - there is a domain name
+ */
+
+ if (pdns->name == NULL) append = 0;
+
+ if (append == 1)
+ {
+ dot = strrchr(name, '.');
+ if (dot != NULL) append = 0;
+ }
+
+ if (append == 1)
+ {
+ if (pdns->search_count == SEARCH_COUNT_INIT) _pdns_process_res_search_list(pdns);
+ if (pdns->search_count > 0) append = 0;
+ }
+
+ if ((append == 1) && (pdns->res->defdname != NULL) && (pdns->res->defdname[0] != '\0')) append = 0;
+
+ status = -1;
+ if (append == 0)
+ {
+ /* BIND_9 API */
+ _pdns_delay(sdns);
+
+ status = __res_nsearch_list_2(pdns->res, name, class, type, (u_char *)buf, len, from, fromlen, pdns->search_count, pdns->search_list);
+ }
+ else
+ {
+ _pdns_delay(sdns);
+
+ qname = NULL;
+ asprintf(&qname, "%s.%s.", name, pdns->name);
+ if (qname == NULL) return -1;
+
+ /* BIND_9 API */
+ status = res_nsearch_2(pdns->res, qname, class, type, (u_char *)buf, len, from, fromlen);
+ free(qname);
+ }
+
+ return status;
+}
+
+static int
+_sdns_send(sdns_handle_t *sdns, const char *name, uint32_t class, uint32_t type, uint32_t fqdn, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen, int *min)
+{
+ char *qname;
+ pdns_handle_t **pdns;
+ uint32_t pdns_count;
+ int i, n, m;
+
+ pdns = NULL;
+ pdns_count = 0;
+ n = -1;
+
+ pdns_count = _pdns_get_handles_for_name(sdns, name, &pdns);
+
+ if (pdns_count == 0) return -1;
+
+ qname = NULL;
+ asprintf(&qname, "%s%s", name, (fqdn == 0) ? "." : "");
+ if (qname == NULL) return -1;
+
+ for (i = 0; i < pdns_count; i++)
+ {
+ m = -1;
+ n = _pdns_query(sdns, pdns[i], qname, class, type, buf, len, from, fromlen, &m);
+ if (min != NULL)
+ {
+ if (*min == -1) *min = m;
+ else if ((m >= 0) && (m < *min)) *min = m;
+ }
+
+ if (n > 0) break;
+ }
+
+ free(pdns);
+ free(qname);
+ return n;
+}
+
+__private_extern__ int
+_sdns_search(sdns_handle_t *sdns, const char *name, uint32_t class, uint32_t type, uint32_t fqdn, uint32_t recurse, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen, int *min)
+{
+ pdns_handle_t *primary, **pdns;
+ int i, n, ndots, status, m;
+ char *dot, *qname;
+ uint32_t pdns_count;
+
+ if (sdns == NULL) return -1;
+ if (name == NULL) return -1;
+
+ /* ndots is the threshold for trying a qualified name "as is" */
+ ndots = 1;
+ primary = sdns->pdns_primary;
+ if ((primary != NULL) && (primary->res != NULL)) ndots = primary->res->ndots;
+
+ /* count dots in input name, and keep track of the location of the last dot */
+ n = 0;
+ dot = NULL;
+
+ for (i = 0; name[i] != '\0'; i++)
+ {
+ if (name[i] == '.')
+ {
+ n++;
+ dot = (char *)(name + i);
+ }
+ }
+
+ /* the last dot is the last character, name is fully qualified */
+ if ((fqdn == 0) && (dot != NULL) && (*(dot + 1) == '\0')) fqdn = 1;
+
+ /*
+ * If n >= ndots, or it's a FQDN, or if it's a PTR query,
+ * we try a query with the name "as is".
+ */
+ if ((n >= ndots) || (fqdn == 1) || (type == ns_t_ptr))
+ {
+ status = _sdns_send(sdns, name, class, type, fqdn, buf, len, from, fromlen, min);
+ if (status > 0) return status;
+ }
+
+ /* end of the line for FQDNs or PTR queries */
+ if (fqdn == 1) return -1;
+ if (type == ns_t_ptr) return -1;
+
+ if (recurse == 0) return -1;
+ if (primary == NULL) return -1;
+
+ /* Try appending names from the search list */
+ if (primary->search_count == SEARCH_COUNT_INIT) _pdns_process_res_search_list(primary);
+ n = primary->search_count;
+ if (n > 0)
+ {
+ /* Try qualifying with each name in the search list */
+ for (i = 0; i < n ; i++)
+ {
+ qname = NULL;
+ asprintf(&qname, "%s.%s", name, primary->search_list[i]);
+ if (qname == NULL) return -1;
+
+ m = -1;
+ status = _sdns_search(sdns, qname, class, type, fqdn, 0, buf, len, from, fromlen, &m);
+ {
+ if (*min == -1) *min = m;
+ else if ((m >= 0) && (m < *min)) *min = m;
+ }
+
+ free(qname);
+ if (status > 0) return status;
+ }
+
+ return -1;
+ }
+
+ /*
+ * We get here if the name is not fully qualified (no trailing dot), and there is no search list.
+ * Try each default client, qualifying with that client's name.
+ */
+ pdns = NULL;
+ pdns_count = _pdns_get_default_handles(sdns, &pdns);
+ status = -1;
+
+ if (pdns_count == 0) return -1;
+
+ for (i = 0; i < pdns_count; i++)
+ {
+ qname = NULL;
+ if (pdns[i]->name == NULL) asprintf(&qname, "%s", name);
+ else asprintf(&qname, "%s.%s", name, pdns[i]->name);
+ if (qname == NULL) return -1;
+
+ m = -1;
+ status = _pdns_query(sdns, pdns[i], qname, class, type, buf, len, from, fromlen, min);
+ {
+ if (*min == -1) *min = m;
+ else if ((m >= 0) && (m < *min)) *min = m;
+ }
+
+ free(qname);
+ if (status > 0) break;
+ }
+
+ free(pdns);
+ return status;
+}
+
+int
+dns_query(dns_handle_t d, const char *name, uint32_t class, uint32_t type, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen)
+{
+ dns_private_handle_t *dns;
+ int status, unused;
+
+ if (d == NULL) return -1;
+ if (name == NULL) return -1;
+ dns = (dns_private_handle_t *)d;
+
+ status = -1;
+ unused = 0;
+
+ if (dns->handle_type == DNS_PRIVATE_HANDLE_TYPE_SUPER)
+ {
+ _check_cache(dns->sdns);
+ status = _sdns_search(dns->sdns, name, class, type, 1, 1, buf, len, from, fromlen, &unused);
+ }
+ else
+ {
+ status = _pdns_query(dns->sdns, dns->pdns, name, class, type, buf, len, from, fromlen, &unused);
+ }
+
+ return status;
+}
+
+
+int
+dns_search(dns_handle_t d, const char *name, uint32_t class, uint32_t type, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen)
+{
+ dns_private_handle_t *dns;
+ int status, unused;
+
+ if (d == NULL) return -1;
+ if (name == NULL) return -1;
+ dns = (dns_private_handle_t *)d;
+
+ status = -1;
+ unused = 0;
+
+ if (dns->handle_type == DNS_PRIVATE_HANDLE_TYPE_SUPER)
+ {
+ _check_cache(dns->sdns);
+ status = _sdns_search(dns->sdns, name, class, type, 0, 1, buf, len, from, fromlen, &unused);
+ }
+ else
+ {
+ status = _pdns_search(dns->sdns, dns->pdns, name, class, type, buf, len, from, fromlen);
+ }
+
+ return status;
+}
+
+/*
+ * PRIVATE
+ */
+
+uint32_t
+dns_server_list_count(dns_handle_t d)
+{
+ dns_private_handle_t *dns;
+ res_state r;
+
+ if (d == NULL) return 0;
+ dns = (dns_private_handle_t *)d;
+
+ if (dns->handle_type != DNS_PRIVATE_HANDLE_TYPE_PLAIN) return 0;
+
+ if (dns->pdns == NULL) return 0;
+
+ r = dns->pdns->res;
+ if (r == NULL) return 0;
+
+ return r->nscount;
+}
+
+struct sockaddr *
+dns_server_list_address(dns_handle_t d, uint32_t i)
+{
+ dns_private_handle_t *dns;
+ res_state r;
+ struct sockaddr_storage *s;
+ struct sockaddr *sa;
+
+ if (d == NULL) return NULL;
+ dns = (dns_private_handle_t *)d;
+
+ if (dns->handle_type != DNS_PRIVATE_HANDLE_TYPE_PLAIN) return NULL;
+
+ if (dns->pdns == NULL) return NULL;
+
+ r = dns->pdns->res;
+ if (r == NULL) return NULL;
+
+ if (i >= r->nscount) return NULL;
+ sa = get_nsaddr(r, i);
+ if (sa == NULL) return NULL;
+
+ s = (struct sockaddr_storage *)calloc(1, sizeof(struct sockaddr_storage));
+ if (s == NULL) return NULL;
+
+ memcpy(s, sa, sizeof(struct sockaddr_storage));
+ return (struct sockaddr *)s;
+}
--- /dev/null
+/*
+ * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 2003 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __DNS_H__
+#define __DNS_H__
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <stdint.h>
+#include <sys/socket.h>
+
+/*
+ * The functions described in this access layer support multiple DNS
+ * client configurations. Each DNS client has its own set of nameserver
+ * addresses and its own set of operational parameters. Each client
+ * can perform DNS queries and searches independent of other clients.
+ * Each client has a symbolic name which is of the same format as a
+ * domain name, e.g. "apple.com". A special meta-client, known as the
+ * "Super" DNS client, acts as a router for DNS queries. The Super
+ * client chooses among all available clients by finding a best match
+ * between the domain name given in a query and the names of all known
+ * clients.
+ *
+ * The configuration for a particular client may be read from a file
+ * having the same format as the traditional "/etc/resolv.conf" file.
+ * However, client configurations are not limited to being stored in
+ * files. The implementation of the library may also locate client
+ * configuratins in other data sources, such as the System Configuration
+ * Database. Users of this API should make no assumptions about the
+ * source of the configuration data.
+ */
+
+typedef const struct __dns_handle_private_struct *dns_handle_t;
+
+
+__BEGIN_DECLS
+
+/*
+ * Create a client handle for DNS access.
+ *
+ * "Super" DNS client
+ *
+ * dns_open(NULL) returns a "super" client that routes DNS queries
+ * among all DNS configurations known to the system.
+ *
+ * Queries for qualified names are sent using a client configuration that
+ * best matches the domain name given in the query. For example, if there
+ * is a client named "apple.com", a search for "foo.apple.com" would use the
+ * resolver configuration specified for that client. The matching algorithm
+ * chooses the client with the maximum number of matching domain components.
+ * For example, if there are clients named "a.b.c", and "b.c", a search for
+ * "x.a.b.c" would use the "a.b.c" resolver configuration, while a search
+ * for "x.y.b.c" would use the "b.c" client. If there are no matches, the
+ * configuration settings in the default client - generally corresponding to
+ * the /etc/resolv.conf file or to the "primary" DNS configuration on the
+ * system are used for the query.
+ *
+ * The domain search list defined in the "default" client is used to search
+ * for unqualified names, by appending each domain in the search list and
+ * then following the logic for matching qualified names described above.
+ *
+ * The DNS access APIs may be used by multiple threads. Each thread must
+ * use a separate DNS client handle created by calling dns_open().
+ *
+ * A simple DNS client handle may be obtained by providing a non-NULL value
+ * for the "name" parameter. Simple clients correspond to a single DNS
+ * configuration, derived from a resolv.conf format file or from some other
+ * source of configurations known to the system.
+ * The name parameter may be a full or relative path name (starting with '/'
+ * or '.'), in which case the client's configuration is read from the
+ * named file. If the name parameter is not a file path name, the routine
+ * will search through all known sources of DNS configuration data on the
+ * system to locate DNS configuration data corresponding to the name supplied,
+ * or NULL if none can be found.
+ *
+ * Use _PATH_RESCONF to open /etc/resolv.conf.
+ */
+extern dns_handle_t dns_open(const char *name);
+
+/*
+ * Close a client and free its resources.
+ */
+extern void dns_free(dns_handle_t dns);
+
+/*
+ * Enable / Disable debug logging.
+ */
+extern void dns_set_debug(dns_handle_t dns, uint32_t flag);
+
+/*
+ * Returns the number of names in the search list.
+ */
+extern uint32_t dns_search_list_domain_count(dns_handle_t dns);
+
+/*
+ * Returns the domain name at index i in the search list.
+ * Returns NULL if there are no names in the search list,
+ * or if i is out of range.
+ * Caller must free the returned value.
+ */
+extern char *dns_search_list_domain(dns_handle_t dns, uint32_t i);
+
+/*
+ * Resolve a name.
+ * The name is considered fully-qualified (the search list is not used).
+ * Caller must supply buffer space for the reply message and the server address.
+ */
+extern int32_t dns_query(dns_handle_t dns, const char *name, uint32_t dnsclass, uint32_t dnstype, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen);
+
+/*
+ * Search for a name.
+ * Caller must supply buffer space for the reply message and the server address.
+ */
+extern int32_t dns_search(dns_handle_t dns, const char *name, uint32_t dnsclass, uint32_t dnstype, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen);
+
+__END_DECLS
+
+#endif /* __DNS_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_headER_START@
+ *
+ * Portions Copyright (c) 2003 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.1 (the "License"). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_headER_END@
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <mach/mach.h>
+#include <pthread.h>
+#include <netdb.h>
+#include <netdb_async.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <dns.h>
+#include <dns_util.h>
+
+typedef struct
+{
+ uint32_t datalen;
+ char *databuf;
+ uint32_t _size;
+ uint32_t _dict;
+ uint32_t _key;
+ uint32_t _vlist;
+ uint32_t _val;
+} kvbuf_t;
+
+typedef struct
+{
+ uint32_t kcount;
+ const char **key;
+ uint32_t *vcount;
+ const char ***val;
+} kvdict_t;
+
+typedef struct
+{
+ uint32_t count;
+ uint32_t curr;
+ kvdict_t *dict;
+ kvbuf_t *kv;
+} kvarray_t;
+
+extern kvbuf_t *kvbuf_new(void);
+extern void kvbuf_add_dict(kvbuf_t *kv);
+extern void kvbuf_add_key(kvbuf_t *kv, const char *key);
+extern void kvbuf_add_val(kvbuf_t *kv, const char *val);
+extern void kvbuf_free(kvbuf_t *kv);
+extern void kvarray_free(kvarray_t *kva);
+extern uint32_t kvbuf_get_val_len(const char *val);
+extern kern_return_t LI_DSLookupGetProcedureNumber(const char *name, int *procno);
+extern kern_return_t LI_async_start(mach_port_t *p, uint32_t proc, kvbuf_t *query, void *callback, void *context);
+extern kern_return_t LI_async_handle_reply(void *msg, kvarray_t **reply, void **callback, void **context);
+extern kern_return_t LI_async_receive(mach_port_t p, kvarray_t **reply);
+extern void LI_async_call_cancel(mach_port_t p, void **context);
+extern uint32_t kvbuf_get_len(const char *p);
+
+static kvbuf_t *
+dns_make_query(const char *name, uint16_t dnsclass, uint16_t dnstype, uint32_t do_search)
+{
+ kvbuf_t *request;
+ char str[128];
+
+ if (name == NULL) return NULL;
+
+ request = kvbuf_new();
+ if (request == NULL) return NULL;
+
+ kvbuf_add_dict(request);
+
+ /* Encode name */
+ kvbuf_add_key(request, "domain");
+ kvbuf_add_val(request, name);
+
+ /* Encode class */
+ snprintf(str, 128, "%hu", dnsclass);
+ kvbuf_add_key(request, "class");
+ kvbuf_add_val(request, str);
+
+ /* Encode type */
+ snprintf(str, 128, "%hu", dnstype);
+ kvbuf_add_key(request, "type");
+ kvbuf_add_val(request, str);
+
+ /* Encode do_search */
+ snprintf(str, 128, "%hu", do_search);
+ kvbuf_add_key(request, "search");
+ kvbuf_add_val(request, str);
+
+ return request;
+}
+
+int32_t
+dns_async_start(mach_port_t *p, const char *name, uint16_t dnsclass, uint16_t dnstype, uint32_t do_search, dns_async_callback callback, void *context)
+{
+ int32_t status;
+ kvbuf_t *request;
+ static int proc = -1;
+
+ *p = MACH_PORT_NULL;
+
+ if (name == NULL) return NO_RECOVERY;
+
+ if (proc < 0)
+ {
+ status = LI_DSLookupGetProcedureNumber("dns_proxy", &proc);
+ if (status != KERN_SUCCESS) return NO_RECOVERY;
+ }
+
+ request = dns_make_query(name, dnsclass, dnstype, do_search);
+ if (request == NULL) return NO_RECOVERY;
+
+ status = LI_async_start(p, proc, request, (void *)callback, context);
+
+ kvbuf_free(request);
+ if (status != 0) return NO_RECOVERY;
+ return 0;
+}
+
+void
+dns_async_cancel(mach_port_t p)
+{
+ LI_async_call_cancel(p, NULL);
+}
+
+int32_t
+dns_async_send(mach_port_t *p, const char *name, uint16_t dnsclass, uint16_t dnstype, uint32_t do_search)
+{
+ return dns_async_start(p, name, dnsclass, dnstype, do_search, NULL, NULL);
+}
+
+static int
+dns_extract_data(kvarray_t *in, char **buf, uint32_t *len, struct sockaddr **from, uint32_t *fromlen)
+{
+ int32_t status;
+ struct in_addr addr4;
+ struct sockaddr_in sin4;
+ struct in6_addr addr6;
+ struct sockaddr_in6 sin6;
+ uint32_t d, k, kcount;
+
+ if (in == NULL) return -1;
+ if (buf == NULL) return -1;
+ if (len == NULL) return -1;
+ if (from == NULL) return -1;
+ if (fromlen == NULL) return -1;
+
+ *buf = NULL;
+ *len = 0;
+ *from = NULL;
+ *fromlen = 0;
+
+ d = in->curr;
+ in->curr++;
+
+ if (d >= in->count) return -1;
+
+ kcount = in->dict[d].kcount;
+
+ for (k = 0; k < kcount; k++)
+ {
+ if (!strcmp(in->dict[d].key[k], "data"))
+ {
+ if (in->dict[d].vcount[k] == 0) continue;
+ if (*buf != NULL) continue;
+
+ /*
+ * dns_proxy contains binary data, possibly with embedded nuls,
+ * so we extract the string length from the kvbuf_t reply that
+ * Libinfo got from directory services, rather than calling strlen().
+ */
+ *len = kvbuf_get_len(in->dict[d].val[k][0]);
+ if (*len == 0) continue;
+
+ *buf = malloc(*len);
+ if (*buf == NULL) return -1;
+
+ memcpy(*buf, in->dict[d].val[k][0], *len);
+ }
+ else if (!strcmp(in->dict[d].key[k], "server"))
+ {
+ if (in->dict[d].vcount[k] == 0) continue;
+ if (*from != NULL) continue;
+
+ memset(&addr4, 0, sizeof(struct in_addr));
+ memset(&sin4, 0, sizeof(struct sockaddr_in));
+
+ memset(&addr6, 0, sizeof(struct in6_addr));
+ memset(&sin6, 0, sizeof(struct sockaddr_in6));
+
+ status = inet_pton(AF_INET6, in->dict[d].val[k][0], &addr6);
+ if (status == 1)
+ {
+ sin6.sin6_addr = addr6;
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ *from = (struct sockaddr *)calloc(1, sin6.sin6_len);
+ memcpy(*from, &sin6, sin6.sin6_len);
+ *fromlen = sin6.sin6_len;
+ }
+
+ status = inet_pton(AF_INET, in->dict[d].val[k][0], &addr4);
+ if (status == 1)
+ {
+ sin4.sin_addr = addr4;
+ sin4.sin_family = AF_INET;
+ sin4.sin_len = sizeof(struct sockaddr_in);
+ *from = (struct sockaddr *)calloc(1, sin4.sin_len);
+ memcpy(*from, &sin4, sin4.sin_len);
+ *fromlen = sin4.sin_len;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int32_t
+dns_async_receive(mach_port_t p, char **buf, uint32_t *len, struct sockaddr **from, uint32_t *fromlen)
+{
+ kern_return_t status;
+ kvarray_t *reply;
+
+ reply = NULL;
+
+ status = LI_async_receive(p, &reply);
+ if (status != 0) return NO_RECOVERY;
+ if (reply == NULL) return HOST_NOT_FOUND;
+
+ status = dns_extract_data(reply, buf, len, from, fromlen);
+ kvarray_free(reply);
+ if (status != 0) return NO_RECOVERY;
+
+ if (*buf == NULL) return NO_DATA;
+
+ return 0;
+}
+
+int32_t
+dns_async_handle_reply(void *msg)
+{
+ dns_async_callback callback;
+ void *context;
+ char *buf;
+ kvarray_t *reply;
+ kern_return_t status;
+ struct sockaddr *from;
+ uint32_t len, fromlen;
+
+ callback = (dns_async_callback)NULL;
+ context = NULL;
+ reply = NULL;
+ buf = NULL;
+ len = 0;
+ from = NULL;
+ fromlen = 0;
+
+ status = LI_async_handle_reply(msg, &reply, (void **)&callback, &context);
+ if (status != KERN_SUCCESS)
+ {
+ if (status == MIG_REPLY_MISMATCH) return 0;
+ callback(NO_RECOVERY, NULL, 0, NULL, 0, context);
+ return NO_RECOVERY;
+ }
+
+ status = dns_extract_data(reply, &buf, &len, &from, &fromlen);
+ kvarray_free(reply);
+ if (status != 0)
+ {
+ callback(NO_RECOVERY, NULL, 0, NULL, 0, context);
+ return 0;
+ }
+
+ if (buf == NULL)
+ {
+ callback(NO_DATA, NULL, 0, NULL, 0, context);
+ return NO_DATA;
+ }
+
+ callback(0, buf, len, from, fromlen, context);
+
+ return 0;
+}
+
--- /dev/null
+#ifndef __DNS_PRIVATE_H__
+#define __DNS_PRIVATE_H__
+
+#include <sys/cdefs.h>
+
+#define DNS_FLAG_DEBUG 0x00000001
+#define DNS_FLAG_CHECK_RESOLVER_DIR 0x00000002
+#define DNS_FLAG_HAVE_IPV6_SERVER 0x00000004
+#define DNS_FLAG_OK_TO_SKIP_AAAA 0x00000008
+#define DNS_FLAG_DEFAULT_RESOLVER 0x00000010
+#define DNS_FLAG_FORWARD_TO_MDNSRESPONDER 0x00000020
+
+typedef struct
+{
+ res_state res;
+ char *source;
+ char *name;
+ uint32_t search_count;
+ char **search_list;
+ uint16_t port;
+ uint32_t flags;
+ uint32_t total_timeout;
+ uint32_t send_timeout;
+ uint32_t search_order;
+ uint32_t reserved1;
+ void *reserved_pointer1;
+} pdns_handle_t;
+
+typedef struct
+{
+ pdns_handle_t *pdns_primary;
+ uint32_t client_count;
+ pdns_handle_t **client;
+ uint32_t modtime;
+ uint32_t stattime;
+ uint32_t stat_latency;
+ uint32_t flags;
+ int notify_sys_config_token;
+ int notify_dir_token;
+ int notify_delay_token;
+ time_t dns_delay;
+ uint32_t reserved1;
+ void *reserved_pointer1;
+} sdns_handle_t;
+
+typedef struct __dns_handle_private_struct
+{
+ uint32_t handle_type;
+ sdns_handle_t *sdns;
+ pdns_handle_t *pdns;
+ char *recvbuf;
+ uint32_t recvsize;
+ uint32_t reserved1;
+ uint32_t reserved2;
+ void *reserved_pointer1;
+ void *reserved_pointer2;
+} dns_private_handle_t;
+
+
+__BEGIN_DECLS
+
+/*
+ * Returns the number of nameserver addresses available to the input
+ * DNS client. Returns zero if the input handle is a "Super" DNS handle.
+ */
+extern uint32_t dns_server_list_count(dns_handle_t d);
+
+/*
+ * Returns the nameserver address at the given index. Returns NULL
+ * if the index is out of range. Caller should free the returned sockaddr.
+ */
+extern struct sockaddr *dns_server_list_address(dns_handle_t d, uint32_t i);
+
+/*
+ * Returns a list of all server addresses for all clients.
+ * Caller must free each list entry, and the returned list.
+ */
+extern void dns_all_server_addrs(dns_handle_t d, struct sockaddr ***addrs, uint32_t *count);
+
+/*
+ * Returns the number of names in the search list.
+ */
+uint32_t dns_search_list_count(dns_handle_t d);
+
+__END_DECLS
+
+#endif /* __DNS_PRIVATE_H__ */
--- /dev/null
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <sys/dir.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <pthread.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include "dns.h"
+#include "dns_util.h"
+#include "dns_private.h"
+#include "res_private.h"
+
+#define DNS_RESOLVER_DIR "/etc/resolver"
+
+#define DNS_PRIVATE_HANDLE_TYPE_SUPER 0
+#define DNS_PRIVATE_HANDLE_TYPE_PLAIN 1
+#define DNS_DEFAULT_RECEIVE_SIZE 8192
+#define DNS_MAX_RECEIVE_SIZE 65536
+
+#define SDNS_DEFAULT_STAT_LATENCY 10
+
+#define DNS_FLAGS_QR_MASK 0x8000
+#define DNS_FLAGS_QR_QUERY 0x0000
+
+#define DNS_FLAGS_OPCODE_MASK 0x7800
+
+#define DNS_FLAGS_RCODE_MASK 0x000f
+
+#define DNS_FLAGS_AA 0x0400
+#define DNS_FLAGS_TC 0x0200
+#define DNS_FLAGS_RD 0x0100
+#define DNS_FLAGS_RA 0x0080
+
+#define DNS_SOCK_UDP 0
+#define DNS_SOCK_TCP_UNCONNECTED 1
+#define DNS_SOCK_TCP_CONNECTED 2
+
+#define INET_NTOP_AF_INET_OFFSET 4
+#define INET_NTOP_AF_INET6_OFFSET 8
+
+#define MAXPACKET 1024
+
+extern void res_client_close(res_state res);
+extern int __res_nquery(res_state statp, const char *name, int class, int type, u_char *answer, int anslen);
+extern int dns_res_send(res_state statp, const u_char *buf, int buflen, u_char *ans, int *anssiz, struct sockaddr *from, int *fromlen);
+extern void _check_cache(sdns_handle_t *sdns);
+extern int _sdns_search(sdns_handle_t *sdns, const char *name, uint32_t class, uint32_t type, uint32_t fqdn, uint32_t recurse, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen, int *min);
+extern int _pdns_search(sdns_handle_t *sdns, pdns_handle_t *pdns, const char *name, uint32_t class, uint32_t type, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen);
+static pthread_mutex_t _dnsPrintLock = PTHREAD_MUTEX_INITIALIZER;
+
+static void
+_dns_print_lock(void)
+{
+ pthread_mutex_lock(&_dnsPrintLock);
+}
+
+static void
+_dns_print_unlock(void)
+{
+ pthread_mutex_unlock(&_dnsPrintLock);
+}
+
+
+static uint8_t
+_dns_parse_uint8(char **p)
+{
+ uint8_t v;
+
+ v = (uint8_t)**p;
+ *p += 1;
+ return v;
+}
+
+static uint16_t
+_dns_parse_uint16(char **p)
+{
+ uint16_t *x, v;
+
+ x = (uint16_t *)*p;
+ v = ntohs(*x);
+ *p += 2;
+ return v;
+}
+
+static uint32_t
+_dns_parse_uint32(char **p)
+{
+ uint32_t *x, v;
+
+ x = (uint32_t *)*p;
+ v = ntohl(*x);
+ *p += 4;
+ return v;
+}
+
+static uint8_t
+_dns_cname_length(char *s)
+{
+ uint8_t l;
+
+ if (s == NULL) return 1;
+ l = strlen(s);
+ while ((s[l - 1] == '.') && (l > 1)) l--;
+ return l;
+}
+
+static void
+_dns_insert_cname(char *s, char *p)
+{
+ int i;
+ uint8_t len, dlen;
+
+ if (s == NULL)
+ {
+ *p = 0;
+ return;
+ }
+
+ if (!strcmp(s, "."))
+ {
+ p[0] = 1;
+ p[1] = '.';
+ p[2] = 0;
+ return;
+ }
+
+ len = _dns_cname_length(s);
+
+ p[0] = '.';
+ memmove(p + 1, s, len);
+ p[len + 1] = '.';
+
+ dlen = 0;
+
+ for (i = len + 1; i >= 0; i--)
+ {
+ if (p[i] == '.')
+ {
+ p[i] = dlen;
+ dlen = 0;
+ }
+ else dlen++;
+ }
+}
+
+static char *
+_dns_parse_string(const char *p, char **x, int32_t *remaining)
+{
+ char *str;
+ uint8_t len;
+
+ if (*remaining < 1) return NULL;
+ *remaining -= 1;
+
+ len = (uint8_t)**x;
+ *x += 1;
+
+ if (*remaining < len) return NULL;
+ *remaining -= len;
+
+ str = malloc(len + 1);
+ memmove(str, *x, len);
+ str[len] = '\0';
+ *x += len;
+
+ return str;
+}
+
+static char *
+_dns_parse_domain_name(const char *p, char **x, int32_t *remaining)
+{
+ uint8_t *v8;
+ uint16_t *v16, skip;
+ uint16_t i, j, dlen, len;
+ int more, compressed;
+ char *name, *start, *y, *z;
+
+ if (*remaining < 1) return NULL;
+
+ z = *x + *remaining;
+ start = *x;
+ compressed = 0;
+ more = 1;
+ name = malloc(1);
+ name[0] = '\0';
+ len = 1;
+ j = 0;
+ skip = 0;
+
+ while (more == 1)
+ {
+ if ((*x + 1) > z)
+ {
+ free(name);
+ return NULL;
+ }
+
+ v8 = (uint8_t *)*x;
+ dlen = *v8;
+
+ if ((dlen & 0xc0) == 0xc0)
+ {
+ if ((*x + 2) > z)
+ {
+ free(name);
+ return NULL;
+ }
+
+ v16 = (uint16_t *)*x;
+
+ y = (char *)p + (ntohs(*v16) & 0x3fff);
+ if ((*x == y) || (y > z))
+ {
+ free(name);
+ return NULL;
+ }
+
+ *x = y;
+ if (compressed == 0) skip += 2;
+ compressed = 1;
+ continue;
+ }
+
+ if ((*x + 1) > z)
+ {
+ free(name);
+ return NULL;
+ }
+
+ *x += 1;
+
+ if (dlen > 0)
+ {
+ len += dlen;
+ name = realloc(name, len);
+ }
+
+ if ((*x + dlen) > z)
+ {
+ free(name);
+ return NULL;
+ }
+
+ for (i = 0; i < dlen; i++)
+ {
+ name[j++] = **x;
+ *x += 1;
+ }
+
+ name[j] = '\0';
+ if (compressed == 0) skip += (dlen + 1);
+
+ if (dlen == 0) more = 0;
+ else
+ {
+ if ((*x + 1) > z)
+ {
+ free(name);
+ return NULL;
+ }
+
+ v8 = (uint8_t *)*x;
+ if (*v8 != 0)
+ {
+ len += 1;
+ name = realloc(name, len);
+ name[j++] = '.';
+ name[j] = '\0';
+ }
+ }
+ }
+
+ if ((start + skip) > z)
+ {
+ free(name);
+ return NULL;
+ }
+
+ *x = start + skip;
+ *remaining -= skip;
+
+ return name;
+}
+
+dns_resource_record_t *
+_dns_parse_resource_record_internal(const char *p, char **x, int32_t *remaining)
+{
+ uint32_t size, bx, mi;
+ uint16_t rdlen;
+ uint8_t byte, i;
+ dns_resource_record_t *r;
+ char *eor;
+
+ if (*remaining < 1) return NULL;
+
+ r = (dns_resource_record_t *)calloc(1, sizeof(dns_resource_record_t));
+
+ r->name = _dns_parse_domain_name(p, x, remaining);
+ if (r->name == NULL)
+ {
+ free(r);
+ return NULL;
+ }
+
+ if (*remaining < 10)
+ {
+ free(r);
+ return NULL;
+ }
+
+ r->dnstype = _dns_parse_uint16(x);
+ r->dnsclass = _dns_parse_uint16(x);
+ r->ttl = _dns_parse_uint32(x);
+ rdlen = _dns_parse_uint16(x);
+
+ *remaining -= 10;
+
+ eor = *x;
+ r->data.A = NULL;
+
+ switch (r->dnstype)
+ {
+ case ns_t_a:
+ if (*remaining < 4)
+ {
+ free(r);
+ return NULL;
+ }
+
+ *remaining -= 4;
+
+ size = sizeof(dns_address_record_t);
+ r->data.A = (dns_address_record_t *)calloc(1, size);
+ r->data.A->addr.s_addr = htonl(_dns_parse_uint32(x));
+ break;
+
+ case ns_t_aaaa:
+ if (*remaining < 16)
+ {
+ free(r);
+ return NULL;
+ }
+
+ *remaining -= 16;
+
+ size = sizeof(dns_in6_address_record_t);
+ r->data.AAAA = (dns_in6_address_record_t *)calloc(1, size);
+ r->data.AAAA->addr.__u6_addr.__u6_addr32[0] = htonl(_dns_parse_uint32(x));
+ r->data.AAAA->addr.__u6_addr.__u6_addr32[1] = htonl(_dns_parse_uint32(x));
+ r->data.AAAA->addr.__u6_addr.__u6_addr32[2] = htonl(_dns_parse_uint32(x));
+ r->data.AAAA->addr.__u6_addr.__u6_addr32[3] = htonl(_dns_parse_uint32(x));
+ break;
+
+ case ns_t_ns:
+ case ns_t_md:
+ case ns_t_mf:
+ case ns_t_cname:
+ case ns_t_mb:
+ case ns_t_mg:
+ case ns_t_mr:
+ case ns_t_ptr:
+ size = sizeof(dns_domain_name_record_t);
+ r->data.CNAME = (dns_domain_name_record_t *)calloc(1,size);
+ r->data.CNAME->name = _dns_parse_domain_name(p, x, remaining);
+ if (r->data.CNAME->name == NULL)
+ {
+ free(r->data.CNAME);
+ free(r);
+ return NULL;
+ }
+ break;
+
+ case ns_t_soa:
+ size = sizeof(dns_SOA_record_t);
+ r->data.SOA = (dns_SOA_record_t *)calloc(1, size);
+
+ r->data.SOA->mname = _dns_parse_domain_name(p, x, remaining);
+ if (r->data.SOA->mname == NULL)
+ {
+ free(r->data.SOA);
+ free(r);
+ return NULL;
+ }
+
+ r->data.SOA->rname = _dns_parse_domain_name(p, x, remaining);
+ if (r->data.SOA->rname == NULL)
+ {
+ free(r->data.SOA->mname);
+ free(r->data.SOA);
+ free(r);
+ return NULL;
+ }
+
+ if (*remaining < 20)
+ {
+ free(r->data.SOA->mname);
+ free(r->data.SOA->rname);
+ free(r->data.SOA);
+ free(r);
+ return NULL;
+ }
+
+ *remaining -= 20;
+
+ r->data.SOA->serial = _dns_parse_uint32(x);
+ r->data.SOA->refresh = _dns_parse_uint32(x);
+ r->data.SOA->retry = _dns_parse_uint32(x);
+ r->data.SOA->expire = _dns_parse_uint32(x);
+ r->data.SOA->minimum = _dns_parse_uint32(x);
+ break;
+
+ case ns_t_wks:
+ if (*remaining < 5)
+ {
+ free(r);
+ return NULL;
+ }
+
+ *remaining -= rdlen;
+
+ size = sizeof(dns_WKS_record_t);
+ r->data.WKS = (dns_WKS_record_t *)calloc(1, size);
+
+ r->data.WKS->addr.s_addr = htonl(_dns_parse_uint32(x));
+ r->data.WKS->protocol = _dns_parse_uint8(x);
+ size = rdlen - 5;
+ r->data.WKS->maplength = size * 8;
+ r->data.WKS->map = NULL;
+ if (size == 0) break;
+
+ r->data.WKS->map = (uint8_t *)calloc(1, r->data.WKS->maplength);
+ mi = 0;
+ for (bx = 0; bx < size; bx++)
+ {
+ byte = _dns_parse_uint8(x);
+ for (i = 128; i >= 1; i = i/2)
+ {
+ if (byte & i) r->data.WKS->map[mi] = 0xff;
+ else r->data.WKS->map[mi] = 0;
+ mi++;
+ }
+ }
+ break;
+
+ case ns_t_hinfo:
+ size = sizeof(dns_HINFO_record_t);
+ r->data.HINFO = (dns_HINFO_record_t *)calloc(1, size);
+
+ r->data.HINFO->cpu = _dns_parse_string(p, x, remaining);
+ if (r->data.HINFO->cpu == NULL)
+ {
+ free(r->data.HINFO);
+ free(r);
+ return NULL;
+ }
+
+ r->data.HINFO->os = _dns_parse_string(p, x, remaining);
+ if (r->data.HINFO->os == NULL)
+ {
+ free(r->data.HINFO->cpu);
+ free(r->data.HINFO);
+ free(r);
+ return NULL;
+ }
+
+ break;
+
+ case ns_t_minfo:
+ size = sizeof(dns_MINFO_record_t);
+ r->data.MINFO = (dns_MINFO_record_t *)calloc(1, size);
+
+ r->data.MINFO->rmailbx = _dns_parse_domain_name(p, x, remaining);
+ if (r->data.MINFO->rmailbx == NULL)
+ {
+ free(r->data.MINFO);
+ free(r);
+ return NULL;
+ }
+
+ r->data.MINFO->emailbx = _dns_parse_domain_name(p, x, remaining);
+ if (r->data.MINFO->emailbx == NULL)
+ {
+ free(r->data.MINFO->rmailbx);
+ free(r->data.MINFO);
+ free(r);
+ return NULL;
+ }
+
+ break;
+
+ case ns_t_mx:
+ if (*remaining < 2)
+ {
+ free(r);
+ return NULL;
+ }
+
+ *remaining -= 2;
+
+ size = sizeof(dns_MX_record_t);
+ r->data.MX = (dns_MX_record_t *)calloc(1, size);
+
+ r->data.MX->preference = _dns_parse_uint16(x);
+ r->data.MX->name = _dns_parse_domain_name(p, x, remaining);
+ if (r->data.MX->name == NULL)
+ {
+ free(r->data.MX);
+ free(r);
+ return NULL;
+ }
+
+ break;
+
+ case ns_t_txt:
+ size = sizeof(dns_TXT_record_t);
+ r->data.TXT = (dns_TXT_record_t *)malloc(size);
+ r->data.TXT->string_count = 0;
+ r->data.TXT->strings = NULL;
+
+ while (*x < (eor + rdlen))
+ {
+ if (r->data.TXT->string_count == 0)
+ {
+ r->data.TXT->strings = (char **)calloc(1, sizeof(char *));
+ }
+ else
+ {
+ r->data.TXT->strings = (char **)realloc(r->data.TXT->strings, (r->data.TXT->string_count + 1) * sizeof(char *));
+ }
+
+ r->data.TXT->strings[r->data.TXT->string_count] = _dns_parse_string(p, x, remaining);
+ if (r->data.TXT->strings[r->data.TXT->string_count] == NULL)
+ {
+ free(r->data.TXT->strings);
+ free(r->data.TXT);
+ free(r);
+ return NULL;
+ }
+ r->data.TXT->string_count++;
+ }
+
+ break;
+
+ case ns_t_rp:
+ size = sizeof(dns_RP_record_t);
+ r->data.RP = (dns_RP_record_t *)calloc(1, size);
+
+ r->data.RP->mailbox = _dns_parse_domain_name(p, x, remaining);
+ if (r->data.RP->mailbox == NULL)
+ {
+ free(r->data.RP);
+ free(r);
+ return NULL;
+ }
+
+ r->data.RP->txtdname = _dns_parse_domain_name(p, x, remaining);
+ if (r->data.RP->txtdname == NULL)
+ {
+ free(r->data.RP->mailbox);
+ free(r->data.RP);
+ free(r);
+ return NULL;
+ }
+
+ break;
+
+ case ns_t_afsdb:
+ if (*remaining < 4)
+ {
+ free(r);
+ return NULL;
+ }
+
+ *remaining -= 4;
+ size = sizeof(dns_AFSDB_record_t);
+ r->data.AFSDB = (dns_AFSDB_record_t *)calloc(1, size);
+
+ r->data.AFSDB->subtype = _dns_parse_uint32(x);
+ r->data.AFSDB->hostname = _dns_parse_domain_name(p, x, remaining);
+ if (r->data.AFSDB->hostname == NULL)
+ {
+ free(r->data.AFSDB);
+ free(r);
+ return NULL;
+ }
+
+ break;
+
+ case ns_t_x25:
+ size = sizeof(dns_X25_record_t);
+ r->data.X25 = (dns_X25_record_t *)calloc(1, size);
+
+ r->data.X25->psdn_address = _dns_parse_string(p, x, remaining);
+ if (r->data.X25->psdn_address == NULL)
+ {
+ free(r->data.X25);
+ free(r);
+ return NULL;
+ }
+
+ break;
+
+ case ns_t_isdn:
+ size = sizeof(dns_ISDN_record_t);
+ r->data.ISDN = (dns_ISDN_record_t *)calloc(1, size);
+
+ r->data.ISDN->isdn_address = _dns_parse_string(p, x, remaining);
+ if (r->data.ISDN->isdn_address == NULL)
+ {
+ free(r->data.ISDN);
+ free(r);
+ return NULL;
+ }
+
+ if (*x < (eor + rdlen))
+ {
+ r->data.ISDN->subaddress = _dns_parse_string(p, x, remaining);
+ if (r->data.ISDN->subaddress == NULL)
+ {
+ free(r->data.ISDN->isdn_address);
+ free(r->data.ISDN);
+ free(r);
+ return NULL;
+ }
+ }
+ else
+ {
+ r->data.ISDN->subaddress = NULL;
+ }
+
+ break;
+
+ case ns_t_rt:
+ if (*remaining < 2)
+ {
+ free(r);
+ return NULL;
+ }
+
+ *remaining -= 2;
+
+ size = sizeof(dns_RT_record_t);
+ r->data.RT = (dns_RT_record_t *)calloc(1, size);
+
+ r->data.RT->preference = _dns_parse_uint16(x);
+ r->data.RT->intermediate = _dns_parse_domain_name(p, x, remaining);
+ if (r->data.RT->intermediate == NULL)
+ {
+ free(r->data.RT);
+ free(r);
+ return NULL;
+ }
+
+ break;
+
+ case ns_t_loc:
+ if (*remaining < 16)
+ {
+ free(r);
+ return NULL;
+ }
+
+ *remaining -= 16;
+
+ size = sizeof(dns_LOC_record_t);
+ r->data.LOC = (dns_LOC_record_t *)calloc(1, size);
+
+ r->data.LOC->version = _dns_parse_uint8(x);
+ r->data.LOC->size = _dns_parse_uint8(x);
+ r->data.LOC->horizontal_precision = _dns_parse_uint8(x);
+ r->data.LOC->vertical_precision = _dns_parse_uint8(x);
+ r->data.LOC->latitude = _dns_parse_uint32(x);
+ r->data.LOC->longitude = _dns_parse_uint32(x);
+ r->data.LOC->altitude = _dns_parse_uint32(x);
+ break;
+
+ case ns_t_srv:
+ if (*remaining < 6)
+ {
+ free(r);
+ return NULL;
+ }
+
+ *remaining -= 6;
+
+ size = sizeof(dns_SRV_record_t);
+ r->data.SRV = (dns_SRV_record_t *)calloc(1, size);
+
+ r->data.SRV->priority = _dns_parse_uint16(x);
+ r->data.SRV->weight = _dns_parse_uint16(x);
+ r->data.SRV->port = _dns_parse_uint16(x);
+ r->data.SRV->target = _dns_parse_domain_name(p, x, remaining);
+ if (r->data.SRV->target == NULL)
+ {
+ free(r->data.SRV);
+ free(r);
+ return NULL;
+ }
+
+ break;
+
+ case ns_t_null:
+ default:
+ if (*remaining < rdlen)
+ {
+ free(r);
+ return NULL;
+ }
+
+ *remaining -= rdlen;
+
+ size = sizeof(dns_raw_resource_record_t);
+ r->data.DNSNULL = (dns_raw_resource_record_t *)calloc(1, size);
+
+ r->data.DNSNULL->length = rdlen;
+ r->data.DNSNULL->data = calloc(1, rdlen);
+ memmove(r->data.DNSNULL->data, *x, rdlen);
+ *x += rdlen;
+ break;
+ }
+
+ *x = eor + rdlen;
+ return r;
+}
+
+dns_resource_record_t *
+dns_parse_resource_record(const char *buf, uint32_t len)
+{
+ char *x;
+ int32_t remaining;
+
+ remaining = len;
+ x = (char *)buf;
+ return _dns_parse_resource_record_internal(buf, &x, &remaining);
+}
+
+dns_question_t *
+_dns_parse_question_internal(const char *p, char **x, int32_t *remaining)
+{
+ dns_question_t *q;
+
+ if (x == NULL) return NULL;
+ if (*x == NULL) return NULL;
+ if (*remaining < 1) return NULL;
+
+ q = (dns_question_t *)calloc(1, sizeof(dns_question_t));
+
+ q->name = _dns_parse_domain_name(p, x, remaining);
+ if (q->name == NULL)
+ {
+ free(q);
+ return NULL;
+ }
+
+ if (*remaining < 4)
+ {
+ free(q->name);
+ free(q);
+ return NULL;
+ }
+
+ *remaining = *remaining - 4;
+
+ q->dnstype = _dns_parse_uint16(x);
+ q->dnsclass = _dns_parse_uint16(x);
+
+ return q;
+}
+
+dns_question_t *
+dns_parse_question(const char *buf, uint32_t len)
+{
+ char *x;
+ int32_t remaining;
+
+ remaining = len;
+ x = (char *)buf;
+ return _dns_parse_question_internal(buf, &x, &remaining);
+}
+
+
+dns_reply_t *
+dns_parse_packet(const char *p, uint32_t len)
+{
+ dns_reply_t *r;
+ dns_header_t *h;
+ char *x;
+ uint32_t i, size;
+ int32_t remaining;
+
+ if (p == NULL) return NULL;
+ if (len < NS_HFIXEDSZ) return NULL;
+
+ x = (char *)p;
+
+ r = (dns_reply_t *)calloc(1, sizeof(dns_reply_t));
+
+ r->header = (dns_header_t *)calloc(1, sizeof(dns_header_t));
+ h = r->header;
+
+ h->xid = _dns_parse_uint16(&x);
+ h->flags = _dns_parse_uint16(&x);
+ h->qdcount = _dns_parse_uint16(&x);
+ h->ancount = _dns_parse_uint16(&x);
+ h->nscount = _dns_parse_uint16(&x);
+ h->arcount = _dns_parse_uint16(&x);
+
+ remaining = len - NS_HFIXEDSZ;
+
+ size = sizeof(dns_question_t *);
+ r->question = (dns_question_t **)calloc(h->qdcount, size);
+ for (i = 0; i < h->qdcount; i++)
+ {
+ r->question[i] = _dns_parse_question_internal(p, &x, &remaining);
+ if (r->question[i] ==NULL)
+ {
+ h->qdcount = 0;
+ if (i > 0) h->qdcount = i - 1;
+ h->ancount = 0;
+ h->nscount = 0;
+ h->arcount = 0;
+ dns_free_reply(r);
+ return NULL;
+ }
+ }
+
+ size = sizeof(dns_resource_record_t *);
+
+ r->answer = (dns_resource_record_t **)calloc(h->ancount, size);
+ for (i = 0; i < h->ancount; i++)
+ {
+ r->answer[i] = _dns_parse_resource_record_internal(p, &x, &remaining);
+ if (r->answer[i] == NULL)
+ {
+ h->ancount = 0;
+ if (i > 0) h->ancount = i - 1;
+ h->nscount = 0;
+ h->arcount = 0;
+ dns_free_reply(r);
+ return NULL;
+ }
+ }
+
+ r->authority = (dns_resource_record_t **)calloc(h->nscount, size);
+ for (i = 0; i < h->nscount; i++)
+ {
+ r->authority[i] = _dns_parse_resource_record_internal(p, &x, &remaining);
+ if (r->authority[i] == NULL)
+ {
+ h->nscount = 0;
+ if (i > 0) h->nscount = i - 1;
+ h->arcount = 0;
+ dns_free_reply(r);
+ return NULL;
+ }
+ }
+
+ r->additional = (dns_resource_record_t **)calloc(h->arcount, size);
+ for (i = 0; i < h->arcount; i++)
+ {
+ r->additional[i] = _dns_parse_resource_record_internal(p, &x, &remaining);
+ if (r->additional[i] == NULL)
+ {
+ h->arcount = 0;
+ if (i > 0) h->arcount = i - 1;
+ dns_free_reply(r);
+ return NULL;
+ }
+ }
+
+ return r;
+}
+
+void
+dns_free_resource_record(dns_resource_record_t *r)
+{
+ int i;
+
+ free(r->name);
+
+ switch (r->dnstype)
+ {
+ case ns_t_a:
+ free(r->data.A);
+ break;
+
+ case ns_t_aaaa:
+ free(r->data.AAAA);
+ break;
+
+ case ns_t_ns:
+ case ns_t_md:
+ case ns_t_mf:
+ case ns_t_cname:
+ case ns_t_mb:
+ case ns_t_mg:
+ case ns_t_mr:
+ case ns_t_ptr:
+ free(r->data.CNAME->name);
+ free(r->data.CNAME);
+ break;
+
+ case ns_t_soa:
+ free(r->data.SOA->mname);
+ free(r->data.SOA->rname);
+ free(r->data.SOA);
+ break;
+
+ case ns_t_wks:
+ free(r->data.WKS->map);
+ free(r->data.WKS);
+ break;
+
+ case ns_t_hinfo:
+ free(r->data.HINFO->cpu);
+ free(r->data.HINFO->os);
+ free(r->data.HINFO);
+ break;
+
+ case ns_t_minfo:
+ free(r->data.MINFO->rmailbx);
+ free(r->data.MINFO->emailbx);
+ free(r->data.MINFO);
+ break;
+
+ case ns_t_mx:
+ free(r->data.MX->name);
+ free(r->data.MX);
+ break;
+
+
+ case ns_t_txt:
+ for (i=0; i<r->data.TXT->string_count; i++)
+ {
+ free(r->data.TXT->strings[i]);
+ }
+ if (r->data.TXT->strings != NULL)
+ free(r->data.TXT->strings);
+ free(r->data.TXT);
+ break;
+
+ case ns_t_rp:
+ free(r->data.RP->mailbox);
+ free(r->data.RP->txtdname);
+ free(r->data.RP);
+ break;
+
+ case ns_t_afsdb:
+ free(r->data.AFSDB->hostname);
+ free(r->data.AFSDB);
+ break;
+
+ case ns_t_x25:
+ free(r->data.X25->psdn_address);
+ free(r->data.X25);
+ break;
+
+ case ns_t_isdn:
+ free(r->data.ISDN->isdn_address);
+ if (r->data.ISDN->subaddress != NULL)
+ free(r->data.ISDN->subaddress);
+ free(r->data.ISDN);
+ break;
+
+ case ns_t_rt:
+ free(r->data.RT->intermediate);
+ free(r->data.RT);
+ break;
+
+ case ns_t_loc:
+ free(r->data.LOC);
+ break;
+
+ case ns_t_srv:
+ free(r->data.SRV->target);
+ free(r->data.SRV);
+ break;
+
+ case ns_t_null:
+ default:
+ free(r->data.DNSNULL->data);
+ free(r->data.DNSNULL);
+ break;
+ }
+
+ free(r);
+}
+
+void
+dns_free_reply(dns_reply_t *r)
+{
+ uint32_t i;
+
+ if (r == NULL) return;
+ if (r->header != NULL)
+ {
+ for (i = 0; i < r->header->qdcount; i++)
+ {
+ free(r->question[i]->name);
+ free(r->question[i]);
+ }
+
+ for (i = 0; i < r->header->ancount; i++) dns_free_resource_record(r->answer[i]);
+ for (i = 0; i < r->header->nscount; i++) dns_free_resource_record(r->authority[i]);
+ for (i = 0; i < r->header->arcount; i++) dns_free_resource_record(r->additional[i]);
+
+ free(r->header);
+ }
+
+ if (r->question != NULL) free(r->question);
+ if (r->answer != NULL) free(r->answer);
+ if (r->authority != NULL) free(r->authority);
+ if (r->additional != NULL) free(r->additional);
+
+ if (r->server != NULL) free(r->server);
+
+ free(r);
+}
+
+static void
+_dns_append_question(dns_question_t *q, char **s, uint16_t *l)
+{
+ uint16_t len, *p;
+ char *x;
+
+ if (q == NULL) return;
+
+ len = *l + _dns_cname_length(q->name) + 2 + 4;
+ *s = realloc(*s, len);
+
+ _dns_insert_cname(q->name, (char *)*s + *l);
+ *l = len;
+
+ x = *s + (len - 4);
+
+ p = (uint16_t *)x;
+ *p = htons(q->dnstype);
+ x += 2;
+
+ p = (uint16_t *)x;
+ *p = htons(q->dnsclass);
+
+}
+
+static void
+_dns_append_resource_record(dns_resource_record_t *r, char **s, uint16_t *l)
+{
+ uint16_t clen, len, *p, extra, rdlen;
+ uint32_t *p2;
+ char *x;
+
+ if (r == NULL) return;
+
+ extra = 10;
+ switch (r->dnstype)
+ {
+ case ns_t_a:
+ extra += 4;
+ break;
+ case ns_t_ptr:
+ extra += 2;
+ clen = _dns_cname_length(r->data.PTR->name);
+ extra += clen;
+ break;
+ default: break;
+ }
+
+ len = *l + _dns_cname_length(r->name) + 2 + extra;
+ *s = realloc(*s, len);
+
+ _dns_insert_cname(r->name, (char *)*s + *l);
+ *l = len;
+
+ x = *s + (len - extra);
+
+ p = (uint16_t *)x;
+ *p = htons(r->dnstype);
+ x += 2;
+
+ p = (uint16_t *)x;
+ *p = htons(r->dnsclass);
+ x += 2;
+
+ p2 = (uint32_t *)x;
+ *p2 = htonl(r->ttl);
+ x += 4;
+
+ switch (r->dnstype)
+ {
+ case ns_t_a:
+ rdlen = 4;
+ p = (uint16_t *)x;
+ *p = htons(rdlen);
+ x += 2;
+
+ p2 = (uint32_t *)x;
+ *p2 = htons(r->data.A->addr.s_addr);
+ x += 4;
+ return;
+
+ case ns_t_ptr:
+ clen = _dns_cname_length(r->data.PTR->name) + 2;
+ p = (uint16_t *)x;
+ *p = htons(clen);
+ x += 2;
+ _dns_insert_cname(r->data.PTR->name, x);
+ x += clen;
+ return;
+
+ default: return;
+ }
+}
+
+char *
+dns_build_reply(dns_reply_t *dnsr, uint16_t *rl)
+{
+ uint16_t i, len;
+ dns_header_t *h;
+ char *s, *x;
+
+ if (dnsr == NULL) return NULL;
+
+ len = NS_HFIXEDSZ;
+
+ s = malloc(len);
+ x = s + len;
+
+ memset(s, 0, len);
+ *rl = len;
+
+ h = (dns_header_t *)s;
+
+ h->xid = htons(dnsr->header->xid);
+ h->flags = htons(dnsr->header->flags);
+ h->qdcount = htons(dnsr->header->qdcount);
+ h->ancount = htons(dnsr->header->ancount);
+ h->nscount = htons(dnsr->header->nscount);
+ h->arcount = htons(dnsr->header->arcount);
+
+ for (i = 0; i < dnsr->header->qdcount; i++)
+ {
+ _dns_append_question(dnsr->question[i], &s, rl);
+ }
+
+ for (i = 0; i < dnsr->header->ancount; i++)
+ {
+ _dns_append_resource_record(dnsr->answer[i], &s, rl);
+ }
+
+ for (i = 0; i < dnsr->header->nscount; i++)
+ {
+ _dns_append_resource_record(dnsr->authority[i], &s, rl);
+ }
+
+ for (i = 0; i < dnsr->header->arcount; i++)
+ {
+ _dns_append_resource_record(dnsr->additional[i], &s, rl);
+ }
+
+ return s;
+}
+
+void
+dns_free_question(dns_question_t *q)
+{
+ if (q == NULL) return;
+ if (q->name != NULL) free(q->name);
+ free(q);
+}
+
+void
+dns_set_buffer_size(dns_handle_t d, uint32_t len)
+{
+ dns_private_handle_t *dns;
+ if (d == NULL) return;
+
+ dns = (dns_private_handle_t *)d;
+ if (dns->recvsize == len) return;
+
+ if (dns->recvbuf != NULL)
+ {
+ free(dns->recvbuf);
+ dns->recvbuf = NULL;
+ }
+
+ dns->recvsize = len;
+ if (dns->recvsize > DNS_MAX_RECEIVE_SIZE) dns->recvsize = DNS_MAX_RECEIVE_SIZE;
+
+ if (dns->recvsize > 0) dns->recvbuf = malloc(dns->recvsize);
+}
+
+uint32_t
+dns_get_buffer_size(dns_handle_t d)
+{
+ dns_private_handle_t *dns;
+ if (d == NULL) return 0;
+
+ dns = (dns_private_handle_t *)d;
+ return dns->recvsize;
+}
+
+dns_reply_t *
+dns_lookup_soa_min(dns_handle_t d, const char *name, uint32_t class, uint32_t type, int *min)
+{
+ dns_private_handle_t *dns;
+ dns_reply_t *r;
+ int len;
+ struct sockaddr_storage *from;
+ uint32_t fromlen;
+
+ if (d == NULL) return NULL;
+ if (name == NULL) return NULL;
+
+ dns = (dns_private_handle_t *)d;
+ if (min != NULL) *min = -1;
+
+ if (dns->recvbuf == NULL)
+ {
+ if (dns->recvsize == 0) dns->recvsize = DNS_DEFAULT_RECEIVE_SIZE;
+
+ dns->recvbuf = malloc(dns->recvsize);
+ if (dns->recvbuf == NULL) return NULL;
+ }
+
+ fromlen = sizeof(struct sockaddr_storage);
+ from = (struct sockaddr_storage *)calloc(1, sizeof(struct sockaddr_storage));
+ len = -1;
+
+ if (dns->handle_type == DNS_PRIVATE_HANDLE_TYPE_SUPER)
+ {
+ _check_cache(dns->sdns);
+ len = _sdns_search(dns->sdns, name, class, type, 0, 1, dns->recvbuf, dns->recvsize, (struct sockaddr *)from, &fromlen, min);
+ }
+ else
+ {
+ /* NB. Minumium SOA TTL values are NOT provided when the caller passes a DNS_PRIVATE_HANDLE_TYPE_PLAIN handle */
+ len = _pdns_search(dns->sdns, dns->pdns, name, class, type, dns->recvbuf, dns->recvsize, (struct sockaddr *)from, &fromlen);
+ }
+
+ if (len <= 0)
+ {
+ free(from);
+ return NULL;
+ }
+
+ r = dns_parse_packet(dns->recvbuf, len);
+
+ if (r == NULL) free(from);
+ else r->server = (struct sockaddr *)from;
+
+ return r;
+}
+
+dns_reply_t *
+dns_lookup(dns_handle_t d, const char *name, uint32_t class, uint32_t type)
+{
+ int unused = 0;
+
+ return dns_lookup_soa_min(d, name, class, type, &unused);
+}
+
+/*
+ * DNS printing utilities
+ */
+
+static char *
+coord_ntoa(int32_t coord, uint32_t islat)
+{
+ int32_t deg, min, sec, secfrac;
+ static char buf[64];
+ char dir;
+
+ coord = coord - 0x80000000;
+ dir = 'N';
+
+ if ((islat == 1) && (coord < 0))
+ {
+ dir = 'S';
+ coord = -coord;
+ }
+
+ if (islat == 0)
+ {
+ dir = 'E';
+ if (coord < 0)
+ {
+ dir = 'W';
+ coord = -coord;
+ }
+ }
+
+ secfrac = coord % 1000;
+ coord = coord / 1000;
+ sec = coord % 60;
+ coord = coord / 60;
+ min = coord % 60;
+ coord = coord / 60;
+ deg = coord;
+
+ sprintf(buf, "%d %.2d %.2d.%.3d %c", deg, min, sec, secfrac, dir);
+ return buf;
+}
+
+static char *
+alt_ntoa(int32_t alt)
+{
+ int32_t ref, m, frac, sign;
+ static char buf[128];
+
+ ref = 100000 * 100;
+ sign = 1;
+
+ if (alt < ref)
+ {
+ alt = ref - alt;
+ sign = -1;
+ }
+ else
+ {
+ alt = alt - ref;
+ }
+
+ frac = alt % 100;
+ m = (alt / 100) * sign;
+
+ sprintf(buf, "%d.%.2d", m, frac);
+ return buf;
+}
+
+static unsigned int
+poweroften[10] =
+{ 1,
+ 10,
+ 100,
+ 1000,
+ 10000,
+ 100000,
+ 1000000,
+ 10000000,
+ 100000000,
+ 1000000000
+};
+
+static char *
+precsize_ntoa(uint8_t prec)
+{
+ static char buf[19];
+ unsigned long val;
+ int mantissa, exponent;
+
+ mantissa = (int)((prec >> 4) & 0x0f) % 10;
+ exponent = (int)((prec >> 0) & 0x0f) % 10;
+
+ val = mantissa * poweroften[exponent];
+
+ sprintf(buf, "%ld.%.2ld", val/100, val%100);
+ return buf;
+}
+
+const char *
+dns_type_string(uint16_t t)
+{
+ switch (t)
+ {
+ case ns_t_a: return "A ";
+ case ns_t_ns: return "NS ";
+ case ns_t_md: return "MD ";
+ case ns_t_mf: return "MF ";
+ case ns_t_cname: return "CNAME";
+ case ns_t_soa: return "SOA ";
+ case ns_t_mb: return "MB ";
+ case ns_t_mg: return "MG ";
+ case ns_t_mr: return "MR ";
+ case ns_t_null: return "NULL ";
+ case ns_t_wks: return "WKS ";
+ case ns_t_ptr: return "PTR ";
+ case ns_t_hinfo: return "HINFO";
+ case ns_t_minfo: return "MINFO";
+ case ns_t_mx: return "MX ";
+ case ns_t_txt: return "TXT ";
+ case ns_t_rp: return "PR ";
+ case ns_t_afsdb: return "AFSDB";
+ case ns_t_x25: return "X25 ";
+ case ns_t_isdn: return "ISDN ";
+ case ns_t_rt: return "RT ";
+ case ns_t_nsap: return "NSAP ";
+ case ns_t_nsap_ptr: return "NSPTR";
+ case ns_t_sig: return "SIG ";
+ case ns_t_key: return "KEY ";
+ case ns_t_px: return "PX ";
+ case ns_t_gpos: return "GPOS ";
+ case ns_t_aaaa: return "AAAA ";
+ case ns_t_loc: return "LOC ";
+ case ns_t_nxt: return "NXT ";
+ case ns_t_eid: return "EID ";
+ case ns_t_nimloc: return "NIMLC";
+ case ns_t_srv: return "SRV ";
+ case ns_t_atma: return "ATMA ";
+ case ns_t_naptr: return "NAPTR";
+ case ns_t_kx: return "KX ";
+ case ns_t_cert: return "CERT ";
+ case ns_t_a6: return "A6 ";
+ case ns_t_dname: return "DNAME";
+ case ns_t_sink: return "SINK ";
+ case ns_t_opt: return "OPT ";
+ case ns_t_tkey: return "TKEY ";
+ case ns_t_tsig: return "TSIG ";
+ case ns_t_ixfr: return "IXFR ";
+ case ns_t_axfr: return "AXFR ";
+ case ns_t_mailb: return "MAILB";
+ case ns_t_maila: return "MAILA";
+ case ns_t_any: return "ANY ";
+ case ns_t_zxfr: return "ZXFR ";
+ default: return "?????";
+ }
+
+ return "?????";
+}
+
+int32_t
+dns_type_number(const char *t, uint16_t *n)
+{
+ if (t == NULL) return -1;
+
+ if (!strcasecmp(t, "A")) { *n = ns_t_a; return 0; }
+ if (!strcasecmp(t, "NS")) { *n = ns_t_ns; return 0; }
+ if (!strcasecmp(t, "MD")) { *n = ns_t_md; return 0; }
+ if (!strcasecmp(t, "MF")) { *n = ns_t_mf; return 0; }
+ if (!strcasecmp(t, "CNAME")) { *n = ns_t_cname; return 0; }
+ if (!strcasecmp(t, "SOA")) { *n = ns_t_soa; return 0; }
+ if (!strcasecmp(t, "MB")) { *n = ns_t_mb; return 0; }
+ if (!strcasecmp(t, "MG")) { *n = ns_t_mg; return 0; }
+ if (!strcasecmp(t, "MR")) { *n = ns_t_mr; return 0; }
+ if (!strcasecmp(t, "NULL")) { *n = ns_t_null; return 0; }
+ if (!strcasecmp(t, "WKS")) { *n = ns_t_wks; return 0; }
+ if (!strcasecmp(t, "PTR")) { *n = ns_t_ptr; return 0; }
+ if (!strcasecmp(t, "HINFO")) { *n = ns_t_hinfo; return 0; }
+ if (!strcasecmp(t, "MINFO")) { *n = ns_t_minfo; return 0; }
+ if (!strcasecmp(t, "TXT")) { *n = ns_t_txt; return 0; }
+ if (!strcasecmp(t, "RP")) { *n = ns_t_rp; return 0; }
+ if (!strcasecmp(t, "AFSDB")) { *n = ns_t_afsdb; return 0; }
+ if (!strcasecmp(t, "X25")) { *n = ns_t_x25; return 0; }
+ if (!strcasecmp(t, "ISDN")) { *n = ns_t_isdn; return 0; }
+ if (!strcasecmp(t, "RT")) { *n = ns_t_rt; return 0; }
+ if (!strcasecmp(t, "NSAP")) { *n = ns_t_nsap; return 0; }
+ if (!strcasecmp(t, "NSPTR")) { *n = ns_t_nsap_ptr; return 0; }
+ if (!strcasecmp(t, "NSAP_PTR")){ *n = ns_t_nsap_ptr; return 0; }
+ if (!strcasecmp(t, "SIG")) { *n = ns_t_sig; return 0; }
+ if (!strcasecmp(t, "KEY")) { *n = ns_t_key; return 0; }
+ if (!strcasecmp(t, "PX")) { *n = ns_t_px; return 0; }
+ if (!strcasecmp(t, "GPOS")) { *n = ns_t_gpos; return 0; }
+ if (!strcasecmp(t, "AAAA")) { *n = ns_t_aaaa; return 0; }
+ if (!strcasecmp(t, "LOC")) { *n = ns_t_loc; return 0; }
+ if (!strcasecmp(t, "NXT")) { *n = ns_t_nxt; return 0; }
+ if (!strcasecmp(t, "EID")) { *n = ns_t_eid; return 0; }
+ if (!strcasecmp(t, "NIMLOC")) { *n = ns_t_nimloc; return 0; }
+ if (!strcasecmp(t, "SRV")) { *n = ns_t_srv; return 0; }
+ if (!strcasecmp(t, "ATMA")) { *n = ns_t_atma; return 0; }
+ if (!strcasecmp(t, "NAPTR")) { *n = ns_t_naptr; return 0; }
+ if (!strcasecmp(t, "KX")) { *n = ns_t_kx; return 0; }
+ if (!strcasecmp(t, "CERT")) { *n = ns_t_cert; return 0; }
+ if (!strcasecmp(t, "A6")) { *n = ns_t_a6; return 0; }
+ if (!strcasecmp(t, "DNAME")) { *n = ns_t_dname; return 0; }
+ if (!strcasecmp(t, "SINK")) { *n = ns_t_sink; return 0; }
+ if (!strcasecmp(t, "OPT")) { *n = ns_t_opt; return 0; }
+ if (!strcasecmp(t, "TKEY")) { *n = ns_t_tkey; return 0; }
+ if (!strcasecmp(t, "TSIG")) { *n = ns_t_tsig; return 0; }
+ if (!strcasecmp(t, "IXFR")) { *n = ns_t_ixfr; return 0; }
+ if (!strcasecmp(t, "AXFR")) { *n = ns_t_axfr; return 0; }
+ if (!strcasecmp(t, "MAILB")) { *n = ns_t_mailb; return 0; }
+ if (!strcasecmp(t, "MAILA")) { *n = ns_t_maila; return 0; }
+ if (!strcasecmp(t, "ANY")) { *n = ns_t_any; return 0; }
+ if (!strcasecmp(t, "ZXFR")) { *n = ns_t_zxfr; return 0; }
+
+ return -1;
+}
+
+const char *
+dns_class_string(uint16_t c)
+{
+ switch (c)
+ {
+ case ns_c_in: return "IN";
+ case ns_c_2: return "CS";
+ case ns_c_chaos: return "CH";
+ case ns_c_hs: return "HS";
+ case ns_c_none: return "NONE";
+ case ns_c_any: return "ANY";
+ default: return "??";
+ }
+
+ return "??";
+}
+
+int32_t
+dns_class_number(const char *c, uint16_t *n)
+{
+ if (c == NULL) return -1;
+
+ if (!strcasecmp(c, "IN")) { *n = ns_c_in; return 0; }
+ if (!strcasecmp(c, "CS")) { *n = ns_c_2; return 0; }
+ if (!strcasecmp(c, "CH")) { *n = ns_c_chaos; return 0; }
+ if (!strcasecmp(c, "HS")) { *n = ns_c_hs; return 0; }
+ if (!strcasecmp(c, "NONE")) { *n = ns_c_none; return 0; }
+ if (!strcasecmp(c, "ANY")) { *n = ns_c_any; return 0; }
+
+ return -1;
+}
+
+static void
+_dns_print_question_lock(const dns_question_t *q, FILE *f, int lockit)
+{
+ if (lockit != 0) _dns_print_lock();
+ fprintf(f, "%s %s %s\n", q->name, dns_class_string(q->dnsclass), dns_type_string(q->dnstype));
+ if (lockit != 0) _dns_print_unlock();
+}
+
+void
+dns_print_question(const dns_question_t *q, FILE *f)
+{
+ _dns_print_question_lock(q, f, 1);
+}
+
+static void
+_dns_print_resource_record_lock(const dns_resource_record_t *r, FILE *f, int lockit)
+{
+ struct protoent *p;
+ struct servent *s;
+ uint32_t i, len;
+ uint8_t x;
+ struct sockaddr_in6 s6;
+ char pbuf[64];
+
+ if (lockit != 0) _dns_print_lock();
+
+ fprintf(f, "%s %s %s ", r->name, dns_class_string(r->dnsclass), dns_type_string(r->dnstype));
+ fprintf(f, "%u", r->ttl);
+
+ switch (r->dnstype)
+ {
+ case ns_t_a:
+ fprintf(f, " %s", inet_ntoa(r->data.A->addr));
+ break;
+
+ case ns_t_aaaa:
+ memset(&s6, 0, sizeof(struct sockaddr_in6));
+ s6.sin6_len = sizeof(struct sockaddr_in6);
+ s6.sin6_family = AF_INET6;
+ s6.sin6_addr = r->data.AAAA->addr;
+ fprintf(f, " %s", inet_ntop(AF_INET6, (char *)(&s6) + INET_NTOP_AF_INET6_OFFSET, pbuf, 64));
+ break;
+
+ case ns_t_md:
+ case ns_t_mf:
+ case ns_t_cname:
+ case ns_t_mb:
+ case ns_t_mg:
+ case ns_t_mr:
+ case ns_t_ptr:
+ case ns_t_ns:
+ fprintf(f, " %s", r->data.CNAME->name);
+ break;
+
+ case ns_t_soa:
+ fprintf(f, " %s %s %u %u %u %u %u",
+ r->data.SOA->mname, r->data.SOA->rname,
+ r->data.SOA->serial, r->data.SOA->refresh, r->data.SOA->retry,
+ r->data.SOA->expire, r->data.SOA->minimum);
+ break;
+
+ case ns_t_wks:
+ fprintf(f, " %s", inet_ntoa(r->data.WKS->addr));
+ p = getprotobynumber(r->data.WKS->protocol);
+ if (p != NULL)
+ {
+ fprintf(f, " %s", p->p_name);
+
+ for (i = 0; i < r->data.WKS->maplength; i++)
+ {
+ if (r->data.WKS->map[i])
+ {
+ s = getservbyport(i, p->p_name);
+ if (s == NULL) fprintf(f, " %u", i);
+ else fprintf(f, " %s", s->s_name);
+ }
+ }
+ }
+ else fprintf(f, " UNKNOWN PROTOCOL %u", r->data.WKS->protocol);
+ break;
+
+ case ns_t_hinfo:
+ fprintf(f, " %s %s", r->data.HINFO->cpu, r->data.HINFO->os);
+ break;
+
+ case ns_t_minfo:
+ fprintf(f, " %s %s", r->data.MINFO->rmailbx, r->data.MINFO->emailbx);
+ break;
+
+ case ns_t_mx:
+ fprintf(f, " %u %s", r->data.MX->preference, r->data.MX->name);
+ break;
+
+ case ns_t_txt:
+ for (i = 0; i < r->data.TXT->string_count; i++)
+ {
+ fprintf(f, " \"%s\"", r->data.TXT->strings[i]);
+ }
+ break;
+
+ case ns_t_rp:
+ fprintf(f, " %s %s", r->data.RP->mailbox, r->data.RP->txtdname);
+ break;
+
+ case ns_t_afsdb:
+ fprintf(f, " %u %s", r->data.AFSDB->subtype,
+ r->data.AFSDB->hostname);
+ break;
+
+ case ns_t_x25:
+ fprintf(f, " %s", r->data.X25->psdn_address);
+ break;
+
+ case ns_t_isdn:
+ fprintf(f, " %s", r->data.ISDN->isdn_address);
+ if (r->data.ISDN->subaddress != NULL)
+ fprintf(f, " %s", r->data.ISDN->subaddress);
+ break;
+
+ case ns_t_rt:
+ fprintf(f, " %hu %s", r->data.RT->preference,
+ r->data.RT->intermediate);
+ break;
+
+ case ns_t_loc:
+ fprintf(f, " %s", coord_ntoa(r->data.LOC->latitude, 1));
+ fprintf(f, " %s", coord_ntoa(r->data.LOC->longitude, 0));
+ fprintf(f, " %sm", alt_ntoa(r->data.LOC->altitude));
+ fprintf(f, " %sm", precsize_ntoa(r->data.LOC->size));
+ fprintf(f, " %sm", precsize_ntoa(r->data.LOC->horizontal_precision));
+ fprintf(f, " %sm", precsize_ntoa(r->data.LOC->vertical_precision));
+ break;
+
+ case ns_t_srv:
+ fprintf(f, " %hu %hu %hu %s",
+ r->data.SRV->priority, r->data.SRV->weight,
+ r->data.SRV->port, r->data.SRV->target);
+ break;
+
+ case ns_t_null:
+ default:
+ len = r->data.DNSNULL->length;
+ fprintf(f, " %hu ", len);
+ for (i = 0; i < len; i++)
+ {
+ x = r->data.DNSNULL->data[i];
+ fprintf(f, "%x", x);
+ }
+
+ fprintf(f, " (");
+
+ len = r->data.DNSNULL->length;
+ for (i = 0; i < len; i++)
+ {
+ x = r->data.DNSNULL->data[i];
+ if (isascii(x)) fprintf(f, "%c", x);
+ else fprintf(f, " ");
+ }
+ fprintf(f, ")\n");
+
+ }
+
+ fprintf(f, "\n");
+
+ if (lockit != 0) _dns_print_unlock();
+}
+
+void
+dns_print_resource_record(const dns_resource_record_t *r, FILE *f)
+{
+ _dns_print_resource_record_lock(r, f, 1);
+}
+
+void
+dns_print_reply(const dns_reply_t *r, FILE *f, uint16_t mask)
+{
+ uint16_t i;
+ dns_header_t *h;
+ char scratch[1024];
+ uint32_t offset, iface;
+
+ _dns_print_lock();
+
+ if (r == NULL)
+ {
+ fprintf(f, "-nil-\n");
+ _dns_print_unlock();
+ return;
+ }
+
+ if (r->status != DNS_STATUS_OK)
+ {
+ if (r->status == DNS_STATUS_TIMEOUT)
+ fprintf(f, "Timeout\n");
+ else if (r->status == DNS_STATUS_SEND_FAILED)
+ fprintf(f, "Send failed\n");
+ else if (r->status == DNS_STATUS_RECEIVE_FAILED)
+ fprintf(f, "Receive failed\n");
+ else fprintf(f, "status %u\n", r->status);
+
+ _dns_print_unlock();
+ return;
+ }
+
+ h = r->header;
+
+ if (mask & DNS_PRINT_XID)
+ {
+ fprintf(f, "Xid: %u\n", h->xid);
+ }
+
+ if (mask & DNS_PRINT_QR)
+ {
+ if ((h->flags & DNS_FLAGS_QR_MASK) == DNS_FLAGS_QR_QUERY)
+ fprintf(f, "QR: Query\n");
+ else
+ fprintf(f, "QR: Reply\n");
+ }
+
+ if (mask & DNS_PRINT_SERVER)
+ {
+ if (r->server == NULL)
+ {
+ fprintf(f, "Server: -nil-\n");
+ }
+ else
+ {
+ offset = INET_NTOP_AF_INET_OFFSET;
+ if (r->server->sa_family == AF_INET6) offset = INET_NTOP_AF_INET6_OFFSET;
+
+ fprintf(f, "Server: %s", inet_ntop(r->server->sa_family, (char *)(r->server) + offset, scratch, 1024));
+ if (r->server->sa_family == AF_INET)
+ {
+ memcpy(&iface, (((struct sockaddr_in *)(r->server))->sin_zero), 4);
+ if (iface > 0) fprintf(f, "%%%s", if_indextoname(iface, scratch));
+ }
+ else if (r->server->sa_family == AF_INET6)
+ {
+ iface = ((struct sockaddr_in6 *)(r->server))->sin6_scope_id;
+ if (iface > 0) fprintf(f, "%%%s", if_indextoname(iface, scratch));
+ }
+ fprintf(f, "\n");
+ }
+ }
+
+ if (mask & DNS_PRINT_OPCODE)
+ {
+ fprintf(f, "Opcode: ");
+ switch (h->flags & DNS_FLAGS_OPCODE_MASK)
+ {
+ case ns_o_query: fprintf(f, "Standard\n"); break;
+ case ns_o_iquery: fprintf(f, "Inverse\n"); break;
+ case ns_o_status: fprintf(f, "Status\n"); break;
+ case ns_o_notify: fprintf(f, "Notify\n"); break;
+ case ns_o_update: fprintf(f, "Update\n"); break;
+ default:
+ fprintf(f, "Reserved (%hu)\n",
+ (h->flags & DNS_FLAGS_OPCODE_MASK) >> 11);
+ }
+ }
+
+ if (mask & DNS_PRINT_AA)
+ {
+ if (h->flags & DNS_FLAGS_AA) fprintf(f, "AA: Authoritative\n");
+ else fprintf(f, "AA: Non-Authoritative\n");
+ }
+
+ if (mask & DNS_PRINT_TC)
+ {
+ if (h->flags & DNS_FLAGS_TC) fprintf(f, "TC: Truncated\n");
+ else fprintf(f, "TC: Non-Truncated\n");
+ }
+
+ if (mask & DNS_PRINT_RD)
+ {
+ if (h->flags & DNS_FLAGS_RD) fprintf(f, "RD: Recursion desired\n");
+ else fprintf(f, "RD: No recursion desired\n");
+ }
+
+ if (mask & DNS_PRINT_RA)
+ {
+ if (h->flags & DNS_FLAGS_RA) fprintf(f, "RA: Recursion available\n");
+ else fprintf(f, "RA: No recursion available \n");
+ }
+
+ if (mask & DNS_PRINT_RCODE)
+ {
+ fprintf(f, "Rcode: ");
+ switch (h->flags & DNS_FLAGS_RCODE_MASK)
+ {
+ case ns_r_noerror:
+ fprintf(f, "No error\n");
+ break;
+ case ns_r_formerr:
+ fprintf(f, "Format error \n");
+ break;
+ case ns_r_servfail:
+ fprintf(f, "Server failure\n");
+ break;
+ case ns_r_nxdomain:
+ fprintf(f, "Name error \n");
+ break;
+ case ns_r_notimpl:
+ fprintf(f, "Not implemented\n");
+ break;
+ case ns_r_refused:
+ fprintf(f, "Refused\n");
+ break;
+ case ns_r_yxdomain:
+ fprintf(f, "Name exists\n");
+ break;
+ case ns_r_yxrrset:
+ fprintf(f, "RR Set exists\n");
+ break;
+ case ns_r_nxrrset:
+ fprintf(f, "RR Set does not exist\n");
+ break;
+ case ns_r_notauth:
+ fprintf(f, "Not authoritative\n");
+ break;
+ case ns_r_notzone:
+ fprintf(f, "Record zone does not match section zone\n");
+ break;
+ case ns_r_badvers:
+ fprintf(f, "Invalid EDNS version or TSIG signature\n");
+ break;
+ case ns_r_badkey:
+ fprintf(f, "Invalid key\n");
+ break;
+ case ns_r_badtime:
+ fprintf(f, "Invalid time\n");
+ break;
+ default:
+ fprintf(f, "Reserved (%hu)\n",h->flags & DNS_FLAGS_RCODE_MASK);
+ }
+ }
+
+ if (mask & DNS_PRINT_QUESTION)
+ {
+ fprintf(f, "Question (%hu):\n", h->qdcount);
+ for (i = 0; i < h->qdcount; i++)
+ _dns_print_question_lock(r->question[i], f, 0);
+ }
+
+ if (mask & DNS_PRINT_ANSWER)
+ {
+ fprintf(f, "Answer (%hu):\n", h->ancount);
+ for (i = 0; i < h->ancount; i++)
+ _dns_print_resource_record_lock(r->answer[i], f, 0);
+ }
+
+ if (mask & DNS_PRINT_AUTHORITY)
+ {
+ fprintf(f, "Authority (%hu):\n", h->nscount);
+ for (i = 0; i < h->nscount; i++)
+ _dns_print_resource_record_lock(r->authority[i], f, 0);
+ }
+
+ if (mask & DNS_PRINT_ADDITIONAL)
+ {
+ fprintf(f, "Additional records (%hu):\n", h->arcount);
+ for (i = 0; i < h->arcount; i++)
+ _dns_print_resource_record_lock(r->additional[i], f, 0);
+ }
+
+ _dns_print_unlock();
+}
+
+static void
+_pdns_print_handle(pdns_handle_t *pdns, FILE *f)
+{
+ uint32_t i, offset;
+ struct in_addr a;
+ char scratch[1024];
+ struct sockaddr *sa;
+ res_state r;
+
+ if (pdns == NULL)
+ {
+ fprintf(f, "-nil-\n");
+ return;
+ }
+
+ if (pdns->name == NULL) fprintf(f, "Name: -nil-\n");
+ else fprintf(f, "Name: %s\n", pdns->name);
+
+ fprintf(f, "Flags:");
+ if (pdns->flags == 0) fprintf(f, " None\n");
+ else
+ {
+ if (pdns->flags & DNS_FLAG_DEBUG) fprintf(f, " Debug");
+ if (pdns->flags & DNS_FLAG_CHECK_RESOLVER_DIR) fprintf(f, " DirCheck");
+ if (pdns->flags & DNS_FLAG_HAVE_IPV6_SERVER) fprintf(f, " IPv6");
+ if (pdns->flags & DNS_FLAG_OK_TO_SKIP_AAAA) fprintf(f, " SkipAAAA");
+ if (pdns->flags & DNS_FLAG_DEFAULT_RESOLVER) fprintf(f, " Default");
+ fprintf(f, "\n");
+ }
+
+ r = pdns->res;
+ if (r == NULL) return;
+
+ if (r->defdname[0] != '\0') fprintf(f, "Domain: %s\n", r->defdname);
+ fprintf(f, "Search Order: %d\n", pdns->search_order);
+ fprintf(f, "Total Timeout: %d\n", pdns->total_timeout);
+ fprintf(f, "Retry Timeout: %d\n", pdns->res->retrans);
+ fprintf(f, "Retry Attempts: %d\n", pdns->res->retry);
+
+ fprintf(f, "Server%s:\n", (r->nscount == 1) ? "" : "s");
+ for (i = 0; i < r->nscount; i++)
+ {
+ sa = get_nsaddr(r, i);
+ offset = INET_NTOP_AF_INET_OFFSET;
+ if (sa->sa_family == AF_INET6) offset = INET_NTOP_AF_INET6_OFFSET;
+ fprintf(f, " %u: %s", i, inet_ntop(sa->sa_family, (char *)sa + offset, scratch, 1024));
+ fprintf(f, "\n");
+ }
+
+ if (pdns->search_count > 0)
+ {
+ fprintf(f, "Search List:\n");
+ for (i = 0; i < pdns->search_count; i++)
+ fprintf(f, " %u: %s\n", i, pdns->search_list[i]);
+ }
+
+ if (r->sort_list[0].addr.s_addr != 0)
+ {
+ fprintf(f, "Sortlist:\n");
+ for (i = 0; (r->sort_list[i].addr.s_addr != 0); i++)
+ {
+ fprintf(f, " %u: ", i);
+ a.s_addr = r->sort_list[i].addr.s_addr;
+ fprintf(f, "%s/", inet_ntoa(a));
+ a.s_addr = r->sort_list[i].mask;
+ fprintf(f, "%s\n", inet_ntoa(a));
+ }
+ }
+}
+
+static void
+_sdns_print_handle(sdns_handle_t *sdns, FILE *f)
+{
+ int i;
+
+ if (sdns == NULL)
+ {
+ fprintf(f, "-nil-\n");
+ return;
+ }
+
+ for (i = 0; i < sdns->client_count; i++)
+ {
+ fprintf(f, "DNS client %d\n", i);
+ _pdns_print_handle(sdns->client[i], f);
+ fprintf(f, "\n");
+ }
+
+ fprintf(f, "resolver dir mod time = %u\n", sdns->modtime);
+ fprintf(f, "resolver dir stat time = %u\n", sdns->stattime);
+ fprintf(f, "resolver dir stat latency = %u\n", sdns->stat_latency);
+}
+
+void
+dns_print_handle(dns_handle_t d, FILE *f)
+{
+ dns_private_handle_t *dns;
+
+ _dns_print_lock();
+
+ if (d == NULL)
+ {
+ fprintf(f, "-nil-\n");
+ _dns_print_unlock();
+ return;
+ }
+
+ dns = (dns_private_handle_t *)d;
+
+ if (dns->handle_type == DNS_PRIVATE_HANDLE_TYPE_SUPER)
+ {
+ _sdns_print_handle(dns->sdns, f);
+ }
+ else
+ {
+ _pdns_print_handle(dns->pdns, f);
+ }
+
+ _dns_print_unlock();
+}
+
+void
+dns_all_server_addrs(dns_handle_t d, struct sockaddr ***addrs, uint32_t *count)
+{
+ int i, j, k, n, found;
+ dns_private_handle_t *dns;
+ pdns_handle_t *pdns;
+ struct sockaddr *sa;
+ struct sockaddr_storage **l;
+ res_state r;
+
+ *addrs = NULL;
+ *count = 0;
+ l = NULL;
+ n = 0;
+
+ if (d == NULL) return;
+
+ dns = (dns_private_handle_t *)d;
+
+ if (dns->handle_type != DNS_PRIVATE_HANDLE_TYPE_SUPER) return;
+
+ if (dns->sdns == NULL) return;
+
+ /* Just to initialize / validate clients */
+ i = dns_search_list_count(d);
+
+ for (i = 0; i < dns->sdns->client_count; i++)
+ {
+ pdns = dns->sdns->client[i];
+ if (pdns == NULL) continue;
+
+ r = pdns->res;
+ if (r == NULL) continue;
+
+ for (j = 0; j < r->nscount; j++)
+ {
+ sa = get_nsaddr(r, j);
+ found = 0;
+ for (k = 0; (found == 0) && (k < n); k++)
+ {
+ if (memcmp(l[k], sa, sa->sa_len) == 0) found = 1;
+ }
+ if (found == 1) continue;
+
+ if (n == 0)
+ {
+ l = (struct sockaddr_storage **)calloc(1, sizeof(struct sockaddr_storage *));
+ }
+ else
+ {
+ l = (struct sockaddr_storage **)reallocf(l, (n + 1) * sizeof(struct sockaddr_storage *));
+ }
+
+ if (l == NULL) return;
+
+ l[n] = (struct sockaddr_storage *)calloc(1, sizeof(struct sockaddr_storage));
+ if (l[n] == NULL) return;
+
+ memset(l[n], 0, sizeof(struct sockaddr_storage));
+ memcpy(l[n], sa, sa->sa_len);
+ n++;
+ }
+ }
+
+ *addrs = (struct sockaddr **)l;
+ *count = n;
+}
+
+int
+dns_res_once(struct sockaddr *server, struct timeval *timeout, int options, const char *name, int class, int type, u_char *res, int *reslen)
+{
+ res_state statp;
+ int n, fromlen, status;
+ struct sockaddr_storage from;
+ u_char buf[MAXPACKET];
+
+ if (server == NULL) return DNS_RES_STATUS_INVALID_ARGUMENT;
+ if (name == NULL) return DNS_RES_STATUS_INVALID_ARGUMENT;
+ if (res == NULL) return DNS_RES_STATUS_INVALID_ARGUMENT;
+ if (reslen == NULL) return DNS_RES_STATUS_INVALID_ARGUMENT;
+
+ fromlen = sizeof(struct sockaddr_storage);
+
+ statp = res_state_new();
+ statp->retry = 1;
+ statp->options = options;
+ statp->id = res_randomid();
+ if (timeout == NULL) statp->retrans = 5;
+ else statp->retrans = timeout->tv_sec;
+
+ statp->ndots = 1;
+ statp->_vcsock = -1;
+ statp->nscount = 1;
+
+ strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa");
+ strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int");
+ strcpy(statp->_u._ext.ext->bsuffix, "ip6.arpa");
+
+ if (server->sa_family == AF_INET6)
+ {
+ memcpy(&(statp->_u._ext.ext->nsaddrs[0]), server, sizeof(struct sockaddr_in6));
+ statp->nsaddr_list[0].sin_family = 0;
+ }
+ else
+ {
+ memcpy(&(statp->_u._ext.ext->nsaddrs[0]), server, sizeof(struct sockaddr_in));
+ memcpy(&(statp->nsaddr_list[0]), server, sizeof(struct sockaddr_in));
+ }
+
+ n = res_nmkquery(statp, ns_o_query, name, class, type, NULL, 0, NULL, buf, sizeof(buf));
+
+ status = dns_res_send(statp, buf, n, res, reslen, (struct sockaddr *)&from, &fromlen);
+
+ res_client_close(statp);
+
+ return status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 2003 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __DNS_UTIL_H__
+#define __DNS_UTIL_H__
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <dns.h>
+
+/*
+ * Status returned in a dns_reply_t
+ */
+#define DNS_STATUS_OK 0
+#define DNS_STATUS_BAD_HANDLE 1
+#define DNS_STATUS_MALFORMED_QUERY 2
+#define DNS_STATUS_TIMEOUT 3
+#define DNS_STATUS_SEND_FAILED 4
+#define DNS_STATUS_RECEIVE_FAILED 5
+#define DNS_STATUS_CONNECTION_FAILED 6
+#define DNS_STATUS_WRONG_SERVER 7
+#define DNS_STATUS_WRONG_XID 8
+#define DNS_STATUS_WRONG_QUESTION 9
+
+/*
+ * dns_print_reply mask
+ */
+#define DNS_PRINT_XID 0x0001
+#define DNS_PRINT_QR 0x0002
+#define DNS_PRINT_OPCODE 0x0004
+#define DNS_PRINT_AA 0x0008
+#define DNS_PRINT_TC 0x0010
+#define DNS_PRINT_RD 0x0020
+#define DNS_PRINT_RA 0x0040
+#define DNS_PRINT_PR 0x0080
+#define DNS_PRINT_RCODE 0x0100
+#define DNS_PRINT_QUESTION 0x0200
+#define DNS_PRINT_ANSWER 0x0400
+#define DNS_PRINT_AUTHORITY 0x0800
+#define DNS_PRINT_ADDITIONAL 0x1000
+#define DNS_PRINT_SERVER 0x2000
+
+/*
+ * DNS query / reply header
+ */
+typedef struct {
+ uint16_t xid;
+ uint16_t flags;
+ uint16_t qdcount;
+ uint16_t ancount;
+ uint16_t nscount;
+ uint16_t arcount;
+} dns_header_t;
+
+/*
+ * DNS query
+ */
+typedef struct
+{
+ char *name;
+ uint16_t dnstype;
+ uint16_t dnsclass;
+} dns_question_t;
+
+/*
+ * Resource Record types
+ * dns_parse_packet() creates resourse records of these types.
+ */
+typedef struct
+{
+ uint16_t length;
+ char *data;
+} dns_raw_resource_record_t;
+
+typedef struct
+{
+ struct in_addr addr;
+} dns_address_record_t;
+
+typedef struct
+{
+ struct in6_addr addr;
+} dns_in6_address_record_t;
+
+typedef struct
+{
+ char *name;
+} dns_domain_name_record_t;
+
+typedef struct
+{
+ char *mname;
+ char *rname;
+ uint32_t serial;
+ uint32_t refresh;
+ uint32_t retry;
+ uint32_t expire;
+ uint32_t minimum;
+} dns_SOA_record_t;
+
+typedef struct
+{
+ char *cpu;
+ char *os;
+} dns_HINFO_record_t;
+
+typedef struct
+{
+ char *rmailbx;
+ char *emailbx;
+} dns_MINFO_record_t;
+
+typedef struct
+{
+ uint16_t preference;
+ char *name;
+} dns_MX_record_t;
+
+typedef struct
+{
+ uint32_t string_count;
+ char **strings;
+} dns_TXT_record_t;
+
+typedef struct
+{
+ struct in_addr addr;
+ uint8_t protocol;
+ uint32_t maplength;
+ uint8_t *map;
+} dns_WKS_record_t;
+
+typedef struct
+{
+ char *mailbox;
+ char *txtdname;
+} dns_RP_record_t;
+
+typedef struct
+{
+ uint32_t subtype;
+ char *hostname;
+} dns_AFSDB_record_t;
+
+typedef struct
+{
+ char *psdn_address;
+} dns_X25_record_t;
+
+typedef struct
+{
+ char *isdn_address;
+ char *subaddress;
+} dns_ISDN_record_t;
+
+typedef struct
+{
+ uint16_t preference;
+ char * intermediate;
+} dns_RT_record_t;
+
+typedef struct
+{
+ uint8_t version;
+ uint8_t size;
+ uint8_t horizontal_precision;
+ uint8_t vertical_precision;
+ uint32_t latitude;
+ uint32_t longitude;
+ uint32_t altitude;
+} dns_LOC_record_t;
+
+typedef struct
+{
+ uint16_t priority;
+ uint16_t weight;
+ uint16_t port;
+ char *target;
+} dns_SRV_record_t;
+
+/*
+ * DNS Resource Record
+ *
+ * Data contained in unsupported or obsolete Resource Record types
+ * may be accessed via DNSNULL as a dns_raw_resource_record_t.
+ */
+typedef struct
+{
+ char *name;
+ uint16_t dnstype;
+ uint16_t dnsclass;
+ uint32_t ttl;
+ union
+ {
+ dns_address_record_t *A;
+ dns_domain_name_record_t *NS;
+ dns_domain_name_record_t *MD; /* Obsolete */
+ dns_domain_name_record_t *MF; /* Obsolete */
+ dns_domain_name_record_t *CNAME;
+ dns_SOA_record_t *SOA;
+ dns_domain_name_record_t *MB;
+ dns_domain_name_record_t *MG;
+ dns_domain_name_record_t *MR;
+ dns_raw_resource_record_t *DNSNULL;
+ dns_WKS_record_t *WKS;
+ dns_domain_name_record_t *PTR;
+ dns_HINFO_record_t *HINFO;
+ dns_MINFO_record_t *MINFO;
+ dns_MX_record_t *MX;
+ dns_TXT_record_t *TXT;
+ dns_RP_record_t *RP;
+ dns_AFSDB_record_t *AFSDB;
+ dns_X25_record_t *X25;
+ dns_ISDN_record_t *ISDN;
+ dns_RT_record_t *RT;
+ dns_in6_address_record_t *AAAA;
+ dns_LOC_record_t *LOC;
+ dns_SRV_record_t *SRV;
+ } data;
+} dns_resource_record_t;
+
+/*
+ * A parsed DNS record. Returned by dns_parse_packet() and dns_lookup().
+ * The contents may be printed using dns_print_reply().
+ */
+typedef struct
+{
+ uint32_t status;
+ struct sockaddr *server;
+ dns_header_t *header;
+ dns_question_t **question;
+ dns_resource_record_t **answer;
+ dns_resource_record_t **authority;
+ dns_resource_record_t **additional;
+} dns_reply_t;
+
+
+__BEGIN_DECLS
+
+/*
+ * High-level lookup performs a search (using dns_search), parses the
+ * reply and returns a dns_reply_t structure.
+ *
+ * The DNS handle contains an internal buffer used for fetching replies.
+ * The buffer is reused for each query, and is released with the DNS client
+ * handle when dns_free() is called. The default buffer size is 1024 bytes.
+ * The size may be changed with dns_set_buffer_size.
+ *
+ * Note that in a multithreaded application, each thread using this API must
+ * open a separate handle.
+ */
+extern dns_reply_t *dns_lookup(dns_handle_t dns, const char *name, uint32_t dnsclass, uint32_t dnstype);
+
+/*
+ * Get / Set the size of the internal receive buffer used by dns_lookup()
+ */
+extern uint32_t dns_get_buffer_size(dns_handle_t d);
+extern void dns_set_buffer_size(dns_handle_t d, uint32_t len);
+
+/*
+ * Parse a reply packet into a reply structure.
+ */
+extern dns_reply_t *dns_parse_packet(const char *buf, uint32_t len);
+
+/*
+ * Free a reply structure.
+ */
+extern void dns_free_reply(dns_reply_t *r);
+
+/*
+ * Parse a query packet into a question structure.
+ */
+extern dns_question_t *dns_parse_question(const char *buf, uint32_t len);
+
+/*
+ * Free a question structure.
+ */
+extern void dns_free_question(dns_question_t *q);
+
+/*
+ * Parse a resource record into a structure.
+ */
+extern dns_resource_record_t *dns_parse_resource_record(const char *buf, uint32_t len);
+
+/*
+ * Free a resource record structure.
+ */
+extern void dns_free_resource_record(dns_resource_record_t *rr);
+
+/*
+ * String / number representation of a DNS class
+ * dns_class_number returns 0 if the string is recognized,
+ * non-zero if the class string is unknown.
+ */
+extern const char *dns_class_string(uint16_t dnsclass);
+extern int32_t dns_class_number(const char *c, uint16_t *n);
+
+/*
+ * String / number representation of a DNS type
+ * dns_type_number returns 0 if the string is recognized,
+ * non-zero if the class string is unknown.
+ */
+extern const char *dns_type_string(uint16_t dnstype);
+extern int32_t dns_type_number(const char *t, uint16_t *n);
+
+/*
+ * Print a dns handle.
+ */
+extern void dns_print_handle(dns_handle_t d, FILE *f);
+
+/*
+ * Print the contents of a question structure.
+ */
+extern void dns_print_question(const dns_question_t *q, FILE *f);
+
+/*
+ * Print the contents of a resource record structure.
+ */
+extern void dns_print_resource_record(const dns_resource_record_t *r, FILE *f);
+
+/*
+ * Print the contents of a reply structure.
+ */
+extern void dns_print_reply(const dns_reply_t *r, FILE *f, uint16_t mask);
+
+__END_DECLS
+
+#endif /* __DNS_UTIL_H__ */
--- /dev/null
+#ifndef DST_H
+#define DST_H
+
+#ifndef HAS_DST_KEY
+#define DST_KEY RES_9_DST_KEY
+typedef struct dst_key {
+ char *dk_key_name; /* name of the key */
+ int dk_key_size; /* this is the size of the key in bits */
+ int dk_proto; /* what protocols this key can be used for */
+ int dk_alg; /* algorithm number from key record */
+ u_int32_t dk_flags; /* and the flags of the public key */
+ u_int16_t dk_id; /* identifier of the key */
+} DST_KEY;
+#endif /* HAS_DST_KEY */
+
+/*
+ * DST Crypto API defintions
+ */
+#define dst_init res_9_dst_init
+void dst_init(void);
+#ifndef __APPLE__
+int dst_check_algorithm(const int);
+#endif
+
+#define dst_sign_data res_9_dst_sign_data
+int dst_sign_data(const int mode, /* specifies INIT/UPDATE/FINAL/ALL */
+ DST_KEY *in_key, /* the key to use */
+ void **context, /* pointer to state structure */
+ const u_char *data, /* data to be signed */
+ const int len, /* length of input data */
+ u_char *signature, /* buffer to write signature to */
+ const int sig_len); /* size of output buffer */
+
+#define dst_verify_data res_9_dst_verify_data
+int dst_verify_data(const int mode, /* specifies INIT/UPDATE/FINAL/ALL */
+ DST_KEY *in_key, /* the key to use */
+ void **context, /* pointer to state structure */
+ const u_char *data, /* data to be verified */
+ const int len, /* length of input data */
+ const u_char *signature,/* buffer containing signature */
+ const int sig_len); /* length of signature */
+
+#define dst_read_key res_9_dst_read_key
+DST_KEY *dst_read_key(const char *in_name, /* name of key */
+ const u_int16_t in_id, /* key tag identifier */
+ const int in_alg, /* key algorithm */
+ const int key_type); /* Private/PublicKey wanted*/
+
+#define dst_write_key res_9_dst_write_key
+int dst_write_key(const DST_KEY *key, /* key to write out */
+ const int key_type); /* Public/Private */
+
+#define dst_dnskey_to_key res_9_dst_dnskey_to_key
+DST_KEY *dst_dnskey_to_key(const char *in_name, /* KEY record name */
+ const u_char *key, /* KEY RDATA */
+ const int len); /* size of input buffer*/
+
+#ifndef __APPLE__
+int dst_key_to_dnskey(const DST_KEY *key, /* key to translate */
+ u_char *out_storage, /* output buffer */
+ const int out_len); /* size of out_storage*/
+#endif
+
+#define dst_buffer_to_key res_9_dst_buffer_to_key
+DST_KEY *dst_buffer_to_key(const char *key_name, /* name of the key */
+ const int alg, /* algorithm */
+ const int flags, /* dns flags */
+ const int protocol, /* dns protocol */
+ const u_char *key_buf, /* key in dns wire fmt */
+ const int key_len); /* size of key */
+
+
+#define dst_key_to_buffer res_9_dst_key_to_buffer
+int dst_key_to_buffer(DST_KEY *key, u_char *out_buff, int buf_len);
+
+#define dst_generate_key res_9_dst_generate_key
+DST_KEY *dst_generate_key(const char *name, /* name of new key */
+ const int alg, /* key algorithm to generate */
+ const int bits, /* size of new key */
+ const int exp, /* alg dependent parameter*/
+ const int flags, /* key DNS flags */
+ const int protocol); /* key DNS protocol */
+
+#define dst_free_key res_9_dst_free_key
+DST_KEY *dst_free_key(DST_KEY *f_key);
+
+#define dst_compare_keys res_9_dst_compare_keys
+int dst_compare_keys(const DST_KEY *key1, const DST_KEY *key2);
+
+#define dst_sig_size res_9_dst_sig_size
+int dst_sig_size(DST_KEY *key);
+
+/* support for dns key tags/ids */
+#define dst_s_dns_key_id res_9_dst_s_dns_key_id
+u_int16_t dst_s_dns_key_id(const u_char *dns_key_rdata, const int rdata_len);
+#ifndef __APPLE__
+u_int16_t dst_s_id_calc(const u_char *key_data, const int key_len);
+#endif
+
+/* Used by callers as well as by the library. */
+#define RAW_KEY_SIZE 8192 /* large enough to store any key */
+
+/* DST_API control flags */
+/* These are used used in functions dst_sign_data and dst_verify_data */
+#define SIG_MODE_INIT 1 /* initialize digest */
+#define SIG_MODE_UPDATE 2 /* add data to digest */
+#define SIG_MODE_FINAL 4 /* generate/verify signature */
+#define SIG_MODE_ALL (SIG_MODE_INIT|SIG_MODE_UPDATE|SIG_MODE_FINAL)
+
+/* Flags for dst_read_private_key() */
+#define DST_FORCE_READ 0x1000000
+#define DST_CAN_SIGN 0x010F
+#define DST_NO_AUTHEN 0x8000
+#define DST_EXTEND_FLAG 0x1000
+#define DST_STANDARD 0
+#define DST_PRIVATE 0x2000000
+#define DST_PUBLIC 0x4000000
+#define DST_RAND_SEMI 1
+#define DST_RAND_STD 2
+#define DST_RAND_KEY 3
+#define DST_RAND_DSS 4
+
+
+/* DST algorithm codes */
+#define KEY_RSA 1
+#define KEY_DH 2
+#define KEY_DSA 3
+#define KEY_PRIVATE 254
+#define KEY_EXPAND 255
+#define KEY_HMAC_MD5 157
+#define KEY_HMAC_SHA1 158
+#define UNKNOWN_KEYALG 0
+#define DST_MAX_ALGS KEY_HMAC_SHA1
+
+/* DST constants to locations in KEY record changes in new KEY record */
+#define DST_FLAGS_SIZE 2
+#define DST_KEY_PROT 2
+#define DST_KEY_ALG 3
+#define DST_EXT_FLAG 4
+#define DST_KEY_START 4
+
+#ifndef SIGN_F_NOKEY
+#define SIGN_F_NOKEY 0xC000
+#endif
+
+/* error codes from dst routines */
+#define SIGN_INIT_FAILURE (-23)
+#define SIGN_UPDATE_FAILURE (-24)
+#define SIGN_FINAL_FAILURE (-25)
+#define VERIFY_INIT_FAILURE (-26)
+#define VERIFY_UPDATE_FAILURE (-27)
+#define VERIFY_FINAL_FAILURE (-28)
+#define MISSING_KEY_OR_SIGNATURE (-30)
+#define UNSUPPORTED_KEYALG (-31)
+
+#endif /* DST_H */
--- /dev/null
+#ifndef __APPLE__
+#ifndef LINT
+static const char rcsid[] = "$Header: /Users/Shared/libresolv_2/libresolv/dst_api.c,v 1.1 2006/03/01 19:01:36 majka Exp $";
+#endif
+#endif
+
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * Permission to use, copy modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THE SOFTWARE.
+ */
+/*
+ * This file contains the interface between the DST API and the crypto API.
+ * This is the only file that needs to be changed if the crypto system is
+ * changed. Exported functions are:
+ * void dst_init() Initialize the toolkit
+ * int dst_check_algorithm() Function to determines if alg is suppored.
+ * int dst_compare_keys() Function to compare two keys for equality.
+ * int dst_sign_data() Incremental signing routine.
+ * int dst_verify_data() Incremental verify routine.
+ * int dst_generate_key() Function to generate new KEY
+ * DST_KEY *dst_read_key() Function to retrieve private/public KEY.
+ * void dst_write_key() Function to write out a key.
+ * DST_KEY *dst_dnskey_to_key() Function to convert DNS KEY RR to a DST
+ * KEY structure.
+ * int dst_key_to_dnskey() Function to return a public key in DNS
+ * format binary
+ * DST_KEY *dst_buffer_to_key() Converst a data in buffer to KEY
+ * int *dst_key_to_buffer() Writes out DST_KEY key matterial in buffer
+ * void dst_free_key() Releases all memory referenced by key structure
+ */
+
+#ifndef __APPLE__
+#include "port_before.h"
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <memory.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include "dst_internal.h"
+#ifndef __APPLE__
+#include "port_after.h"
+#endif
+
+/* static variables */
+static int done_init = 0;
+dst_func *dst_t_func[DST_MAX_ALGS];
+const char *key_file_fmt_str = "Private-key-format: v%s\nAlgorithm: %d (%s)\n";
+const char *dst_path = "";
+
+/* internal I/O functions */
+#ifdef _UNUSED_API_
+static DST_KEY *dst_s_read_public_key(const char *in_name,
+ const u_int16_t in_id, int in_alg);
+static int dst_s_read_private_key_file(char *name, DST_KEY *pk_key,
+ u_int16_t in_id, int in_alg);
+static int dst_s_write_public_key(const DST_KEY *key);
+static int dst_s_write_private_key(const DST_KEY *key);
+#endif
+
+/* internal function to set up data structure */
+static DST_KEY *dst_s_get_key_struct(const char *name, const int alg,
+ const int flags, const int protocol,
+ const int bits);
+
+/*
+ * dst_init
+ * This function initializes the Digital Signature Toolkit.
+ * Right now, it just checks the DSTKEYPATH environment variable.
+ * Parameters
+ * none
+ * Returns
+ * none
+ */
+void
+dst_init()
+{
+ char *s;
+ int len;
+
+ if (done_init != 0)
+ return;
+ done_init = 1;
+
+ s = getenv("DSTKEYPATH");
+ len = 0;
+ if (s) {
+ struct stat statbuf;
+
+ len = strlen(s);
+ if (len > PATH_MAX) {
+ EREPORT(("%s is longer than %d characters, ignoring\n",
+ s, PATH_MAX));
+ } else if (stat(s, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) {
+ EREPORT(("%s is not a valid directory\n", s));
+ } else {
+ char *tmp;
+ tmp = (char *) malloc(len + 2);
+ memcpy(tmp, s, len + 1);
+ if (tmp[strlen(tmp) - 1] != '/') {
+ tmp[strlen(tmp) + 1] = 0;
+ tmp[strlen(tmp)] = '/';
+ }
+ dst_path = tmp;
+ }
+ }
+ memset(dst_t_func, 0, sizeof(dst_t_func));
+ /* first one is selected */
+ dst_hmac_md5_init();
+}
+
+/*
+ * dst_check_algorithm
+ * This function determines if the crypto system for the specified
+ * algorithm is present.
+ * Parameters
+ * alg 1 KEY_RSA
+ * 3 KEY_DSA
+ * 157 KEY_HMAC_MD5
+ * future algorithms TBD and registered with IANA.
+ * Returns
+ * 1 - The algorithm is available.
+ * 0 - The algorithm is not available.
+ */
+#ifdef __APPLE__
+static
+#endif
+int
+dst_check_algorithm(const int alg)
+{
+ return (dst_t_func[alg] != NULL);
+}
+
+/*
+ * dst_s_get_key_struct
+ * This function allocates key structure and fills in some of the
+ * fields of the structure.
+ * Parameters:
+ * name: the name of the key
+ * alg: the algorithm number
+ * flags: the dns flags of the key
+ * protocol: the dns protocol of the key
+ * bits: the size of the key
+ * Returns:
+ * NULL if error
+ * valid pointer otherwise
+ */
+static DST_KEY *
+dst_s_get_key_struct(const char *name, const int alg, const int flags,
+ const int protocol, const int bits)
+{
+ DST_KEY *new_key = NULL;
+
+ if (dst_check_algorithm(alg)) /* make sure alg is available */
+ new_key = (DST_KEY *) malloc(sizeof(*new_key));
+ if (new_key == NULL)
+ return (NULL);
+
+ memset(new_key, 0, sizeof(*new_key));
+ new_key->dk_key_name = strdup(name);
+ new_key->dk_alg = alg;
+ new_key->dk_flags = flags;
+ new_key->dk_proto = protocol;
+ new_key->dk_KEY_struct = NULL;
+ new_key->dk_key_size = bits;
+ new_key->dk_func = dst_t_func[alg];
+ return (new_key);
+}
+
+#ifdef _UNUSED_API_
+/*
+ * dst_compare_keys
+ * Compares two keys for equality.
+ * Parameters
+ * key1, key2 Two keys to be compared.
+ * Returns
+ * 0 The keys are equal.
+ * non-zero The keys are not equal.
+ */
+
+int
+dst_compare_keys(const DST_KEY *key1, const DST_KEY *key2)
+{
+ if (key1 == key2)
+ return (0);
+ if (key1 == NULL || key2 == NULL)
+ return (4);
+ if (key1->dk_alg != key2->dk_alg)
+ return (1);
+ if (key1->dk_key_size != key2->dk_key_size)
+ return (2);
+ if (key1->dk_id != key2->dk_id)
+ return (3);
+ return (key1->dk_func->compare(key1, key2));
+}
+#endif
+
+/*
+ * dst_sign_data
+ * An incremental signing function. Data is signed in steps.
+ * First the context must be initialized (SIG_MODE_INIT).
+ * Then data is hashed (SIG_MODE_UPDATE). Finally the signature
+ * itself is created (SIG_MODE_FINAL). This function can be called
+ * once with INIT, UPDATE and FINAL modes all set, or it can be
+ * called separately with a different mode set for each step. The
+ * UPDATE step can be repeated.
+ * Parameters
+ * mode A bit mask used to specify operation(s) to be performed.
+ * SIG_MODE_INIT 1 Initialize digest
+ * SIG_MODE_UPDATE 2 Add data to digest
+ * SIG_MODE_FINAL 4 Generate signature
+ * from signature
+ * SIG_MODE_ALL (SIG_MODE_INIT,SIG_MODE_UPDATE,SIG_MODE_FINAL
+ * data Data to be signed.
+ * len The length in bytes of data to be signed.
+ * in_key Contains a private key to sign with.
+ * KEY structures should be handled (created, converted,
+ * compared, stored, freed) by the DST.
+ * signature
+ * The location to which the signature will be written.
+ * sig_len Length of the signature field in bytes.
+ * Return
+ * 0 Successfull INIT or Update operation
+ * >0 success FINAL (sign) operation
+ * <0 failure
+ */
+
+int
+dst_sign_data(const int mode, DST_KEY *in_key, void **context,
+ const u_char *data, const int len,
+ u_char *signature, const int sig_len)
+{
+ DUMP(data, mode, len, "dst_sign_data()");
+
+ if (mode & SIG_MODE_FINAL &&
+ (in_key->dk_KEY_struct == NULL || signature == NULL))
+ return (MISSING_KEY_OR_SIGNATURE);
+
+ if (in_key->dk_func && in_key->dk_func->sign)
+ return (in_key->dk_func->sign(mode, in_key, context, data, len,
+ signature, sig_len));
+ return (UNKNOWN_KEYALG);
+}
+
+
+/*
+ * dst_verify_data
+ * An incremental verify function. Data is verified in steps.
+ * First the context must be initialized (SIG_MODE_INIT).
+ * Then data is hashed (SIG_MODE_UPDATE). Finally the signature
+ * is verified (SIG_MODE_FINAL). This function can be called
+ * once with INIT, UPDATE and FINAL modes all set, or it can be
+ * called separately with a different mode set for each step. The
+ * UPDATE step can be repeated.
+ * Parameters
+ * mode Operations to perform this time.
+ * SIG_MODE_INIT 1 Initialize digest
+ * SIG_MODE_UPDATE 2 add data to digest
+ * SIG_MODE_FINAL 4 verify signature
+ * SIG_MODE_ALL
+ * (SIG_MODE_INIT,SIG_MODE_UPDATE,SIG_MODE_FINAL)
+ * data Data to pass through the hash function.
+ * len Length of the data in bytes.
+ * in_key Key for verification.
+ * signature Location of signature.
+ * sig_len Length of the signature in bytes.
+ * Returns
+ * 0 Verify success
+ * Non-Zero Verify Failure
+ */
+
+int
+dst_verify_data(const int mode, DST_KEY *in_key, void **context,
+ const u_char *data, const int len,
+ const u_char *signature, const int sig_len)
+{
+ DUMP(data, mode, len, "dst_verify_data()");
+ if (mode & SIG_MODE_FINAL &&
+ (in_key->dk_KEY_struct == NULL || signature == NULL))
+ return (MISSING_KEY_OR_SIGNATURE);
+
+ if (in_key->dk_func == NULL || in_key->dk_func->verify == NULL)
+ return (UNSUPPORTED_KEYALG);
+ return (in_key->dk_func->verify(mode, in_key, context, data, len,
+ signature, sig_len));
+}
+
+#ifdef _UNUSED_API_
+/*
+ * dst_read_private_key
+ * Access a private key. First the list of private keys that have
+ * already been read in is searched, then the key accessed on disk.
+ * If the private key can be found, it is returned. If the key cannot
+ * be found, a null pointer is returned. The options specify required
+ * key characteristics. If the private key requested does not have
+ * these characteristics, it will not be read.
+ * Parameters
+ * in_keyname The private key name.
+ * in_id The id of the private key.
+ * options DST_FORCE_READ Read from disk - don't use a previously
+ * read key.
+ * DST_CAN_SIGN The key must be useable for signing.
+ * DST_NO_AUTHEN The key must be useable for authentication.
+ * DST_STANDARD Return any key
+ * Returns
+ * NULL If there is no key found in the current directory or
+ * this key has not been loaded before.
+ * !NULL Success - KEY structure returned.
+ */
+
+DST_KEY *
+dst_read_key(const char *in_keyname, const u_int16_t in_id,
+ const int in_alg, const int type)
+{
+ char keyname[PATH_MAX];
+ DST_KEY *dg_key = NULL, *pubkey = NULL;
+
+ if (!dst_check_algorithm(in_alg)) { /* make sure alg is available */
+ EREPORT(("dst_read_private_key(): Algorithm %d not suppored\n",
+ in_alg));
+ return (NULL);
+ }
+ if ((type & (DST_PUBLIC | DST_PRIVATE)) == 0)
+ return (NULL);
+ if (in_keyname == NULL) {
+ EREPORT(("dst_read_private_key(): Null key name passed in\n"));
+ return (NULL);
+ } else
+ strcpy(keyname, in_keyname);
+
+ /* before I read in the public key, check if it is allowed to sign */
+ if ((pubkey = dst_s_read_public_key(keyname, in_id, in_alg)) == NULL)
+ return (NULL);
+
+ if (type == DST_PUBLIC)
+ return pubkey;
+
+ if (!(dg_key = dst_s_get_key_struct(keyname, pubkey->dk_alg,
+ pubkey->dk_flags, pubkey->dk_proto,
+ 0)))
+ return (dg_key);
+ /* Fill in private key and some fields in the general key structure */
+ if (dst_s_read_private_key_file(keyname, dg_key, pubkey->dk_id,
+ pubkey->dk_alg) == 0)
+ dg_key = dst_free_key(dg_key);
+
+ pubkey = dst_free_key(pubkey);
+ return (dg_key);
+}
+#endif
+
+#ifdef _UNUSED_API_
+int
+dst_write_key(const DST_KEY *key, const int type)
+{
+ int pub = 0, priv = 0;
+
+ if (key == NULL)
+ return (0);
+ if (!dst_check_algorithm(key->dk_alg)) { /* make sure alg is available */
+ EREPORT(("dst_write_key(): Algorithm %d not suppored\n",
+ key->dk_alg));
+ return (UNSUPPORTED_KEYALG);
+ }
+ if ((type & (DST_PRIVATE|DST_PUBLIC)) == 0)
+ return (0);
+
+ if (type & DST_PUBLIC)
+ if ((pub = dst_s_write_public_key(key)) < 0)
+ return (pub);
+ if (type & DST_PRIVATE)
+ if ((priv = dst_s_write_private_key(key)) < 0)
+ return (priv);
+ return (priv+pub);
+}
+#endif
+
+#ifdef _UNUSED_API_
+/*
+ * dst_write_private_key
+ * Write a private key to disk. The filename will be of the form:
+ * K<key->dk_name>+<key->dk_alg>+<key->dk_id>.<private key suffix>.
+ * If there is already a file with this name, an error is returned.
+ *
+ * Parameters
+ * key A DST managed key structure that contains
+ * all information needed about a key.
+ * Return
+ * >= 0 Correct behavior. Returns length of encoded key value
+ * written to disk.
+ * < 0 error.
+ */
+
+static int
+dst_s_write_private_key(const DST_KEY *key)
+{
+ u_char encoded_block[RAW_KEY_SIZE];
+ char file[PATH_MAX];
+ int len;
+ FILE *fp;
+
+ /* First encode the key into the portable key format */
+ if (key == NULL)
+ return (-1);
+ if (key->dk_KEY_struct == NULL)
+ return (0); /* null key has no private key */
+
+ if (key->dk_func == NULL || key->dk_func->to_file_fmt == NULL) {
+ EREPORT(("dst_write_private_key(): Unsupported operation %d\n",
+ key->dk_alg));
+ return (-5);
+ } else if ((len = key->dk_func->to_file_fmt(key, (char *)encoded_block,
+ sizeof(encoded_block))) <= 0) {
+ EREPORT(("dst_write_private_key(): Failed encoding private RSA bsafe key %d\n", len));
+ return (-8);
+ }
+ /* Now I can create the file I want to use */
+ dst_s_build_filename(file, key->dk_key_name, key->dk_id, key->dk_alg,
+ PRIVATE_KEY, PATH_MAX);
+
+ /* Do not overwrite an existing file */
+ if ((fp = dst_s_fopen(file, "w", 0600)) != NULL) {
+ int nn;
+ if ((nn = fwrite(encoded_block, 1, len, fp)) != len) {
+ EREPORT(("dst_write_private_key(): Write failure on %s %d != %d errno=%d\n",
+ file, len, nn, errno));
+ return (-5);
+ }
+ fclose(fp);
+ } else {
+ EREPORT(("dst_write_private_key(): Can not create file %s\n"
+ ,file));
+ return (-6);
+ }
+ memset(encoded_block, 0, len);
+ return (len);
+}
+#endif
+
+#ifdef _UNUSED_API_
+/*
+*
+ * dst_read_public_key
+ * Read a public key from disk and store in a DST key structure.
+ * Parameters
+ * in_name K<in_name><in_id>.<public key suffix> is the
+ * filename of the key file to be read.
+ * Returns
+ * NULL If the key does not exist or no name is supplied.
+ * NON-NULL Initialized key structure if the key exists.
+ */
+
+static DST_KEY *
+dst_s_read_public_key(const char *in_name, const u_int16_t in_id, int in_alg)
+{
+ int flags, proto, alg, len, dlen;
+ int c;
+ char name[PATH_MAX], enckey[RAW_KEY_SIZE], *notspace;
+ u_char deckey[RAW_KEY_SIZE];
+ FILE *fp;
+
+ if (in_name == NULL) {
+ EREPORT(("dst_read_public_key(): No key name given\n"));
+ return (NULL);
+ }
+ if (dst_s_build_filename(name, in_name, in_id, in_alg, PUBLIC_KEY,
+ PATH_MAX) == -1) {
+ EREPORT(("dst_read_public_key(): Cannot make filename from %s, %d, and %s\n",
+ in_name, in_id, PUBLIC_KEY));
+ return (NULL);
+ }
+ /*
+ * Open the file and read it's formatted contents up to key
+ * File format:
+ * domain.name [ttl] [IN] KEY <flags> <protocol> <algorithm> <key>
+ * flags, proto, alg stored as decimal (or hex numbers FIXME).
+ * (FIXME: handle parentheses for line continuation.)
+ */
+ if ((fp = dst_s_fopen(name, "r", 0)) == NULL) {
+ EREPORT(("dst_read_public_key(): Public Key not found %s\n",
+ name));
+ return (NULL);
+ }
+ /* Skip domain name, which ends at first blank */
+ while ((c = getc(fp)) != EOF)
+ if (isspace(c))
+ break;
+ /* Skip blank to get to next field */
+ while ((c = getc(fp)) != EOF)
+ if (!isspace(c))
+ break;
+
+ /* Skip optional TTL -- if initial digit, skip whole word. */
+ if (isdigit(c)) {
+ while ((c = getc(fp)) != EOF)
+ if (isspace(c))
+ break;
+ while ((c = getc(fp)) != EOF)
+ if (!isspace(c))
+ break;
+ }
+ /* Skip optional "IN" */
+ if (c == 'I' || c == 'i') {
+ while ((c = getc(fp)) != EOF)
+ if (isspace(c))
+ break;
+ while ((c = getc(fp)) != EOF)
+ if (!isspace(c))
+ break;
+ }
+ /* Locate and skip "KEY" */
+ if (c != 'K' && c != 'k') {
+ EREPORT(("\"KEY\" doesn't appear in file: %s", name));
+ return NULL;
+ }
+ while ((c = getc(fp)) != EOF)
+ if (isspace(c))
+ break;
+ while ((c = getc(fp)) != EOF)
+ if (!isspace(c))
+ break;
+ ungetc(c, fp); /* return the charcter to the input field */
+ /* Handle hex!! FIXME. */
+
+ if (fscanf(fp, "%d %d %d", &flags, &proto, &alg) != 3) {
+ EREPORT(("dst_read_public_key(): Can not read flag/proto/alg field from %s\n"
+ ,name));
+ return (NULL);
+ }
+ /* read in the key string */
+ fgets(enckey, sizeof(enckey), fp);
+
+ /* If we aren't at end-of-file, something is wrong. */
+ while ((c = getc(fp)) != EOF)
+ if (!isspace(c))
+ break;
+ if (!feof(fp)) {
+ EREPORT(("Key too long in file: %s", name));
+ return NULL;
+ }
+ fclose(fp);
+
+ if ((len = strlen(enckey)) <= 0)
+ return (NULL);
+
+ /* discard \n */
+ enckey[--len] = '\0';
+
+ /* remove leading spaces */
+ for (notspace = (char *) enckey; isspace((*notspace)&0xff); len--)
+ notspace++;
+
+ dlen = b64_pton(notspace, deckey, sizeof(deckey));
+ if (dlen < 0) {
+ EREPORT(("dst_read_public_key: bad return from b64_pton = %d",
+ dlen));
+ return (NULL);
+ }
+ /* store key and info in a key structure that is returned */
+/* return dst_store_public_key(in_name, alg, proto, 666, flags, deckey,
+ dlen);*/
+ return dst_buffer_to_key(in_name, alg, flags, proto, deckey, dlen);
+}
+#endif
+
+#ifdef _UNUSED_API_
+/*
+ * dst_write_public_key
+ * Write a key to disk in DNS format.
+ * Parameters
+ * key Pointer to a DST key structure.
+ * Returns
+ * 0 Failure
+ * 1 Success
+ */
+
+static int
+dst_s_write_public_key(const DST_KEY *key)
+{
+ FILE *fp;
+ char filename[PATH_MAX];
+ u_char out_key[RAW_KEY_SIZE];
+ char enc_key[RAW_KEY_SIZE];
+ int len = 0;
+ int mode;
+
+ memset(out_key, 0, sizeof(out_key));
+ if (key == NULL) {
+ EREPORT(("dst_write_public_key(): No key specified \n"));
+ return (0);
+ } else if ((len = dst_key_to_dnskey(key, out_key, sizeof(out_key)))< 0)
+ return (0);
+
+ /* Make the filename */
+ if (dst_s_build_filename(filename, key->dk_key_name, key->dk_id,
+ key->dk_alg, PUBLIC_KEY, PATH_MAX) == -1) {
+ EREPORT(("dst_write_public_key(): Cannot make filename from %s, %d, and %s\n",
+ key->dk_key_name, key->dk_id, PUBLIC_KEY));
+ return (0);
+ }
+ /* XXX in general this should be a check for symmetric keys */
+ mode = (key->dk_alg == KEY_HMAC_MD5) ? 0600 : 0644;
+ /* create public key file */
+ if ((fp = dst_s_fopen(filename, "w+", mode)) == NULL) {
+ EREPORT(("DST_write_public_key: open of file:%s failed (errno=%d)\n",
+ filename, errno));
+ return (0);
+ }
+ /*write out key first base64 the key data */
+ if (key->dk_flags & DST_EXTEND_FLAG)
+ b64_ntop(&out_key[6], len - 6, enc_key, sizeof(enc_key));
+ else
+ b64_ntop(&out_key[4], len - 4, enc_key, sizeof(enc_key));
+ fprintf(fp, "%s IN KEY %d %d %d %s\n",
+ key->dk_key_name,
+ key->dk_flags, key->dk_proto, key->dk_alg, enc_key);
+ fclose(fp);
+ return (1);
+}
+#endif
+
+#ifdef _UNUSED_API_
+/*
+ * dst_dnskey_to_public_key
+ * This function converts the contents of a DNS KEY RR into a DST
+ * key structure.
+ * Paramters
+ * len Length of the RDATA of the KEY RR RDATA
+ * rdata A pointer to the the KEY RR RDATA.
+ * in_name Key name to be stored in key structure.
+ * Returns
+ * NULL Failure
+ * NON-NULL Success. Pointer to key structure.
+ * Caller's responsibility to free() it.
+ */
+
+DST_KEY *
+dst_dnskey_to_key(const char *in_name, const u_char *rdata, const int len)
+{
+ DST_KEY *key_st;
+ int alg ;
+ int start = DST_KEY_START;
+
+ if (rdata == NULL || len <= DST_KEY_ALG) /* no data */
+ return (NULL);
+ alg = (u_int8_t) rdata[DST_KEY_ALG];
+ if (!dst_check_algorithm(alg)) { /* make sure alg is available */
+ EREPORT(("dst_dnskey_to_key(): Algorithm %d not suppored\n",
+ alg));
+ return (NULL);
+ }
+ if ((key_st = dst_s_get_key_struct(in_name, alg, 0, 0, 0)) == NULL)
+ return (NULL);
+
+ if (in_name == NULL)
+ return (NULL);
+ key_st->dk_id = dst_s_dns_key_id(rdata, len);
+ key_st->dk_flags = dst_s_get_int16(rdata);
+ key_st->dk_proto = (u_int16_t) rdata[DST_KEY_PROT];
+ if (key_st->dk_flags & DST_EXTEND_FLAG) {
+ u_int32_t ext_flags;
+ ext_flags = (u_int32_t) dst_s_get_int16(&rdata[DST_EXT_FLAG]);
+ key_st->dk_flags = key_st->dk_flags | (ext_flags << 16);
+ start += 2;
+ }
+ /*
+ * now point to the begining of the data representing the encoding
+ * of the key
+ */
+ if (key_st->dk_func && key_st->dk_func->from_dns_key) {
+ if (key_st->dk_func->from_dns_key(key_st, &rdata[start],
+ len - start) > 0)
+ return (key_st);
+ } else
+ EREPORT(("dst_dnskey_to_public_key(): unsuppored alg %d\n",
+ alg));
+
+ SAFE_FREE(key_st);
+ return (key_st);
+}
+#endif
+
+/*
+ * dst_public_key_to_dnskey
+ * Function to encode a public key into DNS KEY wire format
+ * Parameters
+ * key Key structure to encode.
+ * out_storage Location to write the encoded key to.
+ * out_len Size of the output array.
+ * Returns
+ * <0 Failure
+ * >=0 Number of bytes written to out_storage
+ */
+
+#ifdef __APPLE__
+static
+#endif
+int
+dst_key_to_dnskey(const DST_KEY *key, u_char *out_storage,
+ const int out_len)
+{
+ u_int16_t val;
+ int loc = 0;
+ int enc_len = 0;
+ if (key == NULL)
+ return (-1);
+
+ if (!dst_check_algorithm(key->dk_alg)) { /* make sure alg is available */
+ EREPORT(("dst_key_to_dnskey(): Algorithm %d not suppored\n",
+ key->dk_alg));
+ return (UNSUPPORTED_KEYALG);
+ }
+ memset(out_storage, 0, out_len);
+ val = (u_int16_t)(key->dk_flags & 0xffff);
+ dst_s_put_int16(out_storage, val);
+ loc += 2;
+
+ out_storage[loc++] = (u_char) key->dk_proto;
+ out_storage[loc++] = (u_char) key->dk_alg;
+
+ if (key->dk_flags > 0xffff) { /* Extended flags */
+ val = (u_int16_t)((key->dk_flags >> 16) & 0xffff);
+ dst_s_put_int16(&out_storage[loc], val);
+ loc += 2;
+ }
+ if (key->dk_KEY_struct == NULL)
+ return (loc);
+ if (key->dk_func && key->dk_func->to_dns_key) {
+ enc_len = key->dk_func->to_dns_key(key,
+ (u_char *) &out_storage[loc],
+ out_len - loc);
+ if (enc_len > 0)
+ return (enc_len + loc);
+ else
+ return (-1);
+ } else
+ EREPORT(("dst_key_to_dnskey(): Unsupported ALG %d\n",
+ key->dk_alg));
+ return (-1);
+}
+
+/*
+ * dst_buffer_to_key
+ * Function to encode a string of raw data into a DST key
+ * Parameters
+ * alg The algorithm (HMAC only)
+ * key A pointer to the data
+ * keylen The length of the data
+ * Returns
+ * NULL an error occurred
+ * NON-NULL the DST key
+ */
+DST_KEY *
+dst_buffer_to_key(const char *key_name, /* name of the key */
+ const int alg, /* algorithm */
+ const int flags, /* dns flags */
+ const int protocol, /* dns protocol */
+ const u_char *key_buf, /* key in dns wire fmt */
+ const int key_len) /* size of key */
+{
+
+ DST_KEY *dkey = NULL;
+ int dnslen;
+ u_char dns[2048];
+
+ if (!dst_check_algorithm(alg)) { /* make sure alg is available */
+ EREPORT(("dst_buffer_to_key(): Algorithm %d not suppored\n", alg));
+ return (NULL);
+ }
+
+ dkey = dst_s_get_key_struct(key_name, alg, flags,
+ protocol, -1);
+
+ if (dkey == NULL)
+ return (NULL);
+ if (dkey->dk_func == NULL || dkey->dk_func->from_dns_key == NULL)
+ return NULL;
+
+ if (dkey->dk_func->from_dns_key(dkey, key_buf, key_len) < 0) {
+ EREPORT(("dst_buffer_to_key(): dst_buffer_to_hmac failed\n"));
+ return (dst_free_key(dkey));
+ }
+
+ dnslen = dst_key_to_dnskey(dkey, dns, sizeof(dns));
+ dkey->dk_id = dst_s_dns_key_id(dns, dnslen);
+ return (dkey);
+}
+
+#ifdef _UNUSED_API_
+int
+dst_key_to_buffer(DST_KEY *key, u_char *out_buff, int buf_len)
+{
+ int len;
+ /* this function will extrac the secret of HMAC into a buffer */
+ if (key == NULL)
+ return (0);
+ if (key->dk_func != NULL && key->dk_func->to_dns_key != NULL) {
+ len = key->dk_func->to_dns_key(key, out_buff, buf_len);
+ if (len < 0)
+ return (0);
+ return (len);
+ }
+ return (0);
+}
+#endif
+
+#ifdef _UNUSED_API_
+/*
+ * dst_s_read_private_key_file
+ * Function reads in private key from a file.
+ * Fills out the KEY structure.
+ * Parameters
+ * name Name of the key to be read.
+ * pk_key Structure that the key is returned in.
+ * in_id Key identifier (tag)
+ * Return
+ * 1 if everthing works
+ * 0 if there is any problem
+ */
+
+static int
+dst_s_read_private_key_file(char *name, DST_KEY *pk_key, u_int16_t in_id,
+ int in_alg)
+{
+ int cnt, alg, len, major, minor, file_major, file_minor;
+ int ret, id;
+ char filename[PATH_MAX];
+ u_char in_buff[RAW_KEY_SIZE], *p;
+ FILE *fp;
+ int dnslen;
+ u_char dns[2048];
+
+ if (name == NULL || pk_key == NULL) {
+ EREPORT(("dst_read_private_key_file(): No key name given\n"));
+ return (0);
+ }
+ /* Make the filename */
+ if (dst_s_build_filename(filename, name, in_id, in_alg, PRIVATE_KEY,
+ PATH_MAX) == -1) {
+ EREPORT(("dst_read_private_key(): Cannot make filename from %s, %d, and %s\n",
+ name, in_id, PRIVATE_KEY));
+ return (0);
+ }
+ /* first check if we can find the key file */
+ if ((fp = dst_s_fopen(filename, "r", 0)) == NULL) {
+ EREPORT(("dst_s_read_private_key_file: Could not open file %s in directory %s\n",
+ filename, dst_path[0] ? dst_path :
+ (char *) getcwd(NULL, PATH_MAX - 1)));
+ return (0);
+ }
+ /* now read the header info from the file */
+ if ((cnt = fread(in_buff, 1, sizeof(in_buff), fp)) < 5) {
+ fclose(fp);
+ EREPORT(("dst_s_read_private_key_file: error reading file %s (empty file)\n",
+ filename));
+ return (0);
+ }
+ /* decrypt key */
+ fclose(fp);
+ if (memcmp(in_buff, "Private-key-format: v", 20) != 0)
+ goto fail;
+ len = cnt;
+ p = in_buff;
+
+ if (!dst_s_verify_str((const char **) &p, "Private-key-format: v")) {
+ EREPORT(("dst_s_read_private_key_file(): Not a Key file/Decrypt failed %s\n", name));
+ goto fail;
+ }
+ /* read in file format */
+ sscanf((char *)p, "%d.%d", &file_major, &file_minor);
+ sscanf(KEY_FILE_FORMAT, "%d.%d", &major, &minor);
+ if (file_major < 1) {
+ EREPORT(("dst_s_read_private_key_file(): Unknown keyfile %d.%d version for %s\n",
+ file_major, file_minor, name));
+ goto fail;
+ } else if (file_major > major || file_minor > minor)
+ EREPORT((
+ "dst_s_read_private_key_file(): Keyfile %s version higher than mine %d.%d MAY FAIL\n",
+ name, file_major, file_minor));
+
+ while (*p++ != '\n') ; /* skip to end of line */
+
+ if (!dst_s_verify_str((const char **) &p, "Algorithm: "))
+ goto fail;
+
+ if (sscanf((char *)p, "%d", &alg) != 1)
+ goto fail;
+ while (*p++ != '\n') ; /* skip to end of line */
+
+ if (pk_key->dk_key_name && !strcmp(pk_key->dk_key_name, name))
+ SAFE_FREE2(pk_key->dk_key_name, strlen(pk_key->dk_key_name));
+ pk_key->dk_key_name = (char *) strdup(name);
+
+ /* allocate and fill in key structure */
+ if (pk_key->dk_func == NULL || pk_key->dk_func->from_file_fmt == NULL)
+ goto fail;
+
+ ret = pk_key->dk_func->from_file_fmt(pk_key, (char *)p, &in_buff[len] - p);
+ if (ret < 0)
+ goto fail;
+
+ dnslen = dst_key_to_dnskey(pk_key, dns, sizeof(dns));
+ id = dst_s_dns_key_id(dns, dnslen);
+
+ /* Make sure the actual key tag matches the input tag used in the filename
+ */
+ if (id != in_id) {
+ EREPORT(("dst_s_read_private_key_file(): actual tag of key read %d != input tag used to build filename %d.\n", id, in_id));
+ goto fail;
+ }
+ pk_key->dk_id = (u_int16_t) id;
+ pk_key->dk_alg = alg;
+ memset(in_buff, 0, cnt);
+ return (1);
+
+ fail:
+ memset(in_buff, 0, cnt);
+ return (0);
+}
+#endif
+
+#ifdef _UNUSED_API_
+/*
+ * dst_generate_key
+ * Generate and store a public/private keypair.
+ * Keys will be stored in formatted files.
+ * Parameters
+ * name Name of the new key. Used to create key files
+ * K<name>+<alg>+<id>.public and K<name>+<alg>+<id>.private.
+ * bits Size of the new key in bits.
+ * exp What exponent to use:
+ * 0 use exponent 3
+ * non-zero use Fermant4
+ * flags The default value of the DNS Key flags.
+ * The DNS Key RR Flag field is defined in RFC 2065,
+ * section 3.3. The field has 16 bits.
+ * protocol
+ * Default value of the DNS Key protocol field.
+ * The DNS Key protocol field is defined in RFC 2065,
+ * section 3.4. The field has 8 bits.
+ * alg What algorithm to use. Currently defined:
+ * KEY_RSA 1
+ * KEY_DSA 3
+ * KEY_HMAC 157
+ * out_id The key tag is returned.
+ *
+ * Return
+ * NULL Failure
+ * non-NULL the generated key pair
+ * Caller frees the result, and its dk_name pointer.
+ */
+DST_KEY *
+dst_generate_key(const char *name, const int bits, const int exp,
+ const int flags, const int protocol, const int alg)
+{
+ DST_KEY *new_key = NULL;
+ int res;
+ int dnslen;
+ u_char dns[2048];
+
+ if (name == NULL)
+ return (NULL);
+
+ if (!dst_check_algorithm(alg)) { /* make sure alg is available */
+ EREPORT(("dst_generate_key(): Algorithm %d not suppored\n", alg));
+ return (NULL);
+ }
+
+ new_key = dst_s_get_key_struct(name, alg, flags, protocol, bits);
+ if (new_key == NULL)
+ return (NULL);
+ if (bits == 0) /* null key we are done */
+ return (new_key);
+ if (new_key->dk_func == NULL || new_key->dk_func->generate == NULL) {
+ EREPORT(("dst_generate_key_pair():Unsupported algorithm %d\n",
+ alg));
+ return (dst_free_key(new_key));
+ }
+ if ((res = new_key->dk_func->generate(new_key, exp)) <= 0) {
+ EREPORT(("dst_generate_key_pair(): Key generation failure %s %d %d %d\n",
+ new_key->dk_key_name, new_key->dk_alg,
+ new_key->dk_key_size, exp));
+ return (dst_free_key(new_key));
+ }
+
+ dnslen = dst_key_to_dnskey(new_key, dns, sizeof(dns));
+ if (dnslen != UNSUPPORTED_KEYALG)
+ new_key->dk_id = dst_s_dns_key_id(dns, dnslen);
+ else
+ new_key->dk_id = 0;
+
+ return (new_key);
+}
+#endif
+
+/*
+ * dst_free_key
+ * Release all data structures pointed to by a key structure.
+ * Parameters
+ * f_key Key structure to be freed.
+ */
+
+DST_KEY *
+dst_free_key(DST_KEY *f_key)
+{
+
+ if (f_key == NULL)
+ return (f_key);
+ if (f_key->dk_func && f_key->dk_func->destroy)
+ f_key->dk_KEY_struct =
+ f_key->dk_func->destroy(f_key->dk_KEY_struct);
+ else {
+ EREPORT(("dst_free_key(): Unknown key alg %d\n",
+ f_key->dk_alg));
+ free(f_key->dk_KEY_struct); /* SHOULD NOT happen */
+ }
+ if (f_key->dk_KEY_struct) {
+ free(f_key->dk_KEY_struct);
+ f_key->dk_KEY_struct = NULL;
+ }
+ if (f_key->dk_key_name)
+ SAFE_FREE(f_key->dk_key_name);
+ SAFE_FREE(f_key);
+ return (NULL);
+}
+
+#ifdef _UNUSED_API_
+/*
+ * dst_sig_size
+ * Return the maximim size of signature from the key specified in bytes
+ * Parameters
+ * key
+ * Returns
+ * bytes
+ */
+int
+dst_sig_size(DST_KEY *key) {
+ switch (key->dk_alg) {
+ case KEY_HMAC_MD5:
+ return (16);
+ case KEY_HMAC_SHA1:
+ return (20);
+ case KEY_RSA:
+ return (key->dk_key_size + 7) / 8;
+ case KEY_DSA:
+ return (40);
+ default:
+ EREPORT(("dst_sig_size(): Unknown key alg %d\n", key->dk_alg));
+ return -1;
+ }
+}
+#endif
--- /dev/null
+#ifdef HMAC_MD5
+#ifndef __APPLE__
+#ifndef LINT
+static const char rcsid[] = "$Header: /Users/Shared/libresolv_2/libresolv/dst_hmac_link.c,v 1.1 2006/03/01 19:01:36 majka Exp $";
+#endif
+#endif
+
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * Permission to use, copy modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THE SOFTWARE.
+ */
+
+/*
+ * This file contains an implementation of the HMAC-MD5 algorithm.
+ */
+#ifndef __APPLE__
+#include "port_before.h"
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include "dst_internal.h"
+#ifdef USE_MD5
+# include "md5.h"
+# ifndef _MD5_H_
+# define _MD5_H_ 1 /* make sure we do not include rsaref md5.h file */
+# endif
+#endif
+
+#ifndef __APPLE__
+#include "port_after.h"
+#endif
+
+
+#define HMAC_LEN 64
+#define HMAC_IPAD 0x36
+#define HMAC_OPAD 0x5c
+#define MD5_LEN 16
+
+
+typedef struct hmackey {
+ u_char hk_ipad[64], hk_opad[64];
+} HMAC_Key;
+
+
+/**************************************************************************
+ * dst_hmac_md5_sign
+ * Call HMAC signing functions to sign a block of data.
+ * There are three steps to signing, INIT (initialize structures),
+ * UPDATE (hash (more) data), FINAL (generate a signature). This
+ * routine performs one or more of these steps.
+ * Parameters
+ * mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL.
+ * priv_key key to use for signing.
+ * context the context to be used in this digest
+ * data data to be signed.
+ * len length in bytes of data.
+ * signature location to store signature.
+ * sig_len size of the signature location
+ * returns
+ * N Success on SIG_MODE_FINAL = returns signature length in bytes
+ * 0 Success on SIG_MODE_INIT and UPDATE
+ * <0 Failure
+ */
+
+static int
+dst_hmac_md5_sign(const int mode, DST_KEY *d_key, void **context,
+ const u_char *data, const int len,
+ u_char *signature, const int sig_len)
+{
+ HMAC_Key *key;
+ int sign_len = 0;
+ MD5_CTX *ctx = NULL;
+
+ if (mode & SIG_MODE_INIT)
+ ctx = (MD5_CTX *) malloc(sizeof(*ctx));
+ else if (context)
+ ctx = (MD5_CTX *) *context;
+ if (ctx == NULL)
+ return (-1);
+
+ if (d_key == NULL || d_key->dk_KEY_struct == NULL)
+ return (-1);
+ key = (HMAC_Key *) d_key->dk_KEY_struct;
+
+ if (mode & SIG_MODE_INIT) {
+ MD5Init(ctx);
+ MD5Update(ctx, key->hk_ipad, HMAC_LEN);
+ }
+
+ if ((mode & SIG_MODE_UPDATE) && (data && len > 0))
+ MD5Update(ctx, data, len);
+
+ if (mode & SIG_MODE_FINAL) {
+ if (signature == NULL || sig_len < MD5_LEN)
+ return (SIGN_FINAL_FAILURE);
+ MD5Final(signature, ctx);
+
+ /* perform outer MD5 */
+ MD5Init(ctx);
+ MD5Update(ctx, key->hk_opad, HMAC_LEN);
+ MD5Update(ctx, signature, MD5_LEN);
+ MD5Final(signature, ctx);
+ sign_len = MD5_LEN;
+ SAFE_FREE(ctx);
+ }
+ else {
+ if (context == NULL)
+ return (-1);
+ *context = (void *) ctx;
+ }
+ return (sign_len);
+}
+
+
+/**************************************************************************
+ * dst_hmac_md5_verify()
+ * Calls HMAC verification routines. There are three steps to
+ * verification, INIT (initialize structures), UPDATE (hash (more) data),
+ * FINAL (generate a signature). This routine performs one or more of
+ * these steps.
+ * Parameters
+ * mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL.
+ * dkey key to use for verify.
+ * data data signed.
+ * len length in bytes of data.
+ * signature signature.
+ * sig_len length in bytes of signature.
+ * returns
+ * 0 Success
+ * <0 Failure
+ */
+
+static int
+dst_hmac_md5_verify(const int mode, DST_KEY *d_key, void **context,
+ const u_char *data, const int len,
+ const u_char *signature, const int sig_len)
+{
+ HMAC_Key *key;
+ MD5_CTX *ctx = NULL;
+
+ if (mode & SIG_MODE_INIT)
+ ctx = (MD5_CTX *) malloc(sizeof(*ctx));
+ else if (context)
+ ctx = (MD5_CTX *) *context;
+ if (ctx == NULL)
+ return (-1);
+
+ if (d_key == NULL || d_key->dk_KEY_struct == NULL)
+ return (-1);
+
+ key = (HMAC_Key *) d_key->dk_KEY_struct;
+ if (mode & SIG_MODE_INIT) {
+ MD5Init(ctx);
+ MD5Update(ctx, key->hk_ipad, HMAC_LEN);
+ }
+ if ((mode & SIG_MODE_UPDATE) && (data && len > 0))
+ MD5Update(ctx, data, len);
+
+ if (mode & SIG_MODE_FINAL) {
+ u_char digest[MD5_LEN];
+ if (signature == NULL || key == NULL || sig_len != MD5_LEN)
+ return (VERIFY_FINAL_FAILURE);
+ MD5Final(digest, ctx);
+
+ /* perform outer MD5 */
+ MD5Init(ctx);
+ MD5Update(ctx, key->hk_opad, HMAC_LEN);
+ MD5Update(ctx, digest, MD5_LEN);
+ MD5Final(digest, ctx);
+
+ SAFE_FREE(ctx);
+ if (memcmp(digest, signature, MD5_LEN) != 0)
+ return (VERIFY_FINAL_FAILURE);
+ }
+ else {
+ if (context == NULL)
+ return (-1);
+ *context = (void *) ctx;
+ }
+ return (0);
+}
+
+
+/**************************************************************************
+ * dst_buffer_to_hmac_md5
+ * Converts key from raw data to an HMAC Key
+ * This function gets in a pointer to the data
+ * Parameters
+ * hkey the HMAC key to be filled in
+ * key the key in raw format
+ * keylen the length of the key
+ * Return
+ * 0 Success
+ * <0 Failure
+ */
+static int
+dst_buffer_to_hmac_md5(DST_KEY *dkey, const u_char *key, const int keylen)
+{
+ int i;
+ HMAC_Key *hkey = NULL;
+ MD5_CTX ctx;
+ int local_keylen = keylen;
+
+ if (dkey == NULL || key == NULL || keylen < 0)
+ return (-1);
+
+ if ((hkey = (HMAC_Key *) malloc(sizeof(HMAC_Key))) == NULL)
+ return (-2);
+
+ memset(hkey->hk_ipad, 0, sizeof(hkey->hk_ipad));
+ memset(hkey->hk_opad, 0, sizeof(hkey->hk_opad));
+
+ /* if key is longer than HMAC_LEN bytes reset it to key=MD5(key) */
+ if (keylen > HMAC_LEN) {
+ u_char tk[MD5_LEN];
+ MD5Init(&ctx);
+ MD5Update(&ctx, key, keylen);
+ MD5Final(tk, &ctx);
+ memset((void *) &ctx, 0, sizeof(ctx));
+ key = tk;
+ local_keylen = MD5_LEN;
+ }
+ /* start out by storing key in pads */
+ memcpy(hkey->hk_ipad, key, local_keylen);
+ memcpy(hkey->hk_opad, key, local_keylen);
+
+ /* XOR key with hk_ipad and opad values */
+ for (i = 0; i < HMAC_LEN; i++) {
+ hkey->hk_ipad[i] ^= HMAC_IPAD;
+ hkey->hk_opad[i] ^= HMAC_OPAD;
+ }
+ dkey->dk_key_size = local_keylen;
+ dkey->dk_KEY_struct = (void *) hkey;
+ return (1);
+}
+
+
+/**************************************************************************
+ * dst_hmac_md5_key_to_file_format
+ * Encodes an HMAC Key into the portable file format.
+ * Parameters
+ * hkey HMAC KEY structure
+ * buff output buffer
+ * buff_len size of output buffer
+ * Return
+ * 0 Failure - null input hkey
+ * -1 Failure - not enough space in output area
+ * N Success - Length of data returned in buff
+ */
+
+static int
+dst_hmac_md5_key_to_file_format(const DST_KEY *dkey, char *buff,
+ const int buff_len)
+{
+ char *bp;
+ int len, b_len, i, key_len;
+ u_char key[HMAC_LEN];
+ HMAC_Key *hkey;
+
+ if (dkey == NULL || dkey->dk_KEY_struct == NULL)
+ return (0);
+ if (buff == NULL || buff_len <= (int) strlen(key_file_fmt_str))
+ return (-1); /* no OR not enough space in output area */
+
+ hkey = (HMAC_Key *) dkey->dk_KEY_struct;
+ memset(buff, 0, buff_len); /* just in case */
+ /* write file header */
+ sprintf(buff, key_file_fmt_str, KEY_FILE_FORMAT, KEY_HMAC_MD5, "HMAC");
+
+ bp = (char *) strchr(buff, '\0');
+ b_len = buff_len - (bp - buff);
+
+ memset(key, 0, HMAC_LEN);
+ for (i = 0; i < HMAC_LEN; i++)
+ key[i] = hkey->hk_ipad[i] ^ HMAC_IPAD;
+ for (i = HMAC_LEN - 1; i >= 0; i--)
+ if (key[i] != 0)
+ break;
+ key_len = i + 1;
+
+ strcat(bp, "Key: ");
+ bp += strlen("Key: ");
+ b_len = buff_len - (bp - buff);
+
+ len = b64_ntop(key, key_len, bp, b_len);
+ if (len < 0)
+ return (-1);
+ bp += len;
+ *(bp++) = '\n';
+ *bp = '\0';
+ b_len = buff_len - (bp - buff);
+
+ return (buff_len - b_len);
+}
+
+
+/**************************************************************************
+ * dst_hmac_md5_key_from_file_format
+ * Converts contents of a key file into an HMAC key.
+ * Parameters
+ * hkey structure to put key into
+ * buff buffer containing the encoded key
+ * buff_len the length of the buffer
+ * Return
+ * n >= 0 Foot print of the key converted
+ * n < 0 Error in conversion
+ */
+
+static int
+dst_hmac_md5_key_from_file_format(DST_KEY *dkey, const char *buff,
+ const int buff_len)
+{
+ const char *p = buff, *eol;
+ u_char key[HMAC_LEN+1]; /* b64_pton needs more than 64 bytes do decode
+ * it should probably be fixed rather than doing
+ * this
+ */
+ u_char *tmp;
+ int key_len, len;
+
+ if (dkey == NULL)
+ return (-2);
+ if (buff == NULL || buff_len < 0)
+ return (-1);
+
+ memset(key, 0, sizeof(key));
+
+ if (!dst_s_verify_str(&p, "Key: "))
+ return (-3);
+
+ eol = strchr(p, '\n');
+ if (eol == NULL)
+ return (-4);
+ len = eol - p;
+ tmp = malloc(len + 2);
+ memcpy(tmp, p, len);
+ *(tmp + len) = 0x0;
+ key_len = b64_pton((char *)tmp, key, HMAC_LEN+1); /* see above */
+ SAFE_FREE2(tmp, len + 2);
+
+ if (dst_buffer_to_hmac_md5(dkey, key, key_len) < 0) {
+ return (-6);
+ }
+ return (0);
+}
+
+/*
+ * dst_hmac_md5_to_dns_key()
+ * function to extract hmac key from DST_KEY structure
+ * intput:
+ * in_key: HMAC-MD5 key
+ * output:
+ * out_str: buffer to write ot
+ * out_len: size of output buffer
+ * returns:
+ * number of bytes written to output buffer
+ */
+static int
+dst_hmac_md5_to_dns_key(const DST_KEY *in_key, u_char *out_str,
+ const int out_len)
+{
+
+ HMAC_Key *hkey;
+ int i;
+
+ if (in_key == NULL || in_key->dk_KEY_struct == NULL ||
+ out_len <= in_key->dk_key_size || out_str == NULL)
+ return (-1);
+
+ hkey = (HMAC_Key *) in_key->dk_KEY_struct;
+ for (i = 0; i < in_key->dk_key_size; i++)
+ out_str[i] = hkey->hk_ipad[i] ^ HMAC_IPAD;
+ return (i);
+}
+
+/**************************************************************************
+ * dst_hmac_md5_compare_keys
+ * Compare two keys for equality.
+ * Return
+ * 0 The keys are equal
+ * NON-ZERO The keys are not equal
+ */
+
+static int
+dst_hmac_md5_compare_keys(const DST_KEY *key1, const DST_KEY *key2)
+{
+ HMAC_Key *hkey1 = (HMAC_Key *) key1->dk_KEY_struct;
+ HMAC_Key *hkey2 = (HMAC_Key *) key2->dk_KEY_struct;
+ return memcmp(hkey1->hk_ipad, hkey2->hk_ipad, HMAC_LEN);
+}
+
+/**************************************************************************
+ * dst_hmac_md5_free_key_structure
+ * Frees all (none) dynamically allocated structures in hkey
+ */
+
+static void *
+dst_hmac_md5_free_key_structure(void *key)
+{
+ HMAC_Key *hkey = key;
+ SAFE_FREE(hkey);
+ return (NULL);
+}
+
+
+/***************************************************************************
+ * dst_hmac_md5_generate_key
+ * Creates a HMAC key of size size with a maximum size of 63 bytes
+ * generating a HMAC key larger than 63 bytes makes no sense as that key
+ * is digested before use.
+ */
+
+static int
+dst_hmac_md5_generate_key(DST_KEY *key, const int nothing)
+{
+ (void)key;
+ (void)nothing;
+ return (-1);
+}
+
+/*
+ * dst_hmac_md5_init() Function to answer set up function pointers for HMAC
+ * related functions
+ */
+int
+dst_hmac_md5_init()
+{
+ if (dst_t_func[KEY_HMAC_MD5] != NULL)
+ return (1);
+ dst_t_func[KEY_HMAC_MD5] = malloc(sizeof(struct dst_func));
+ if (dst_t_func[KEY_HMAC_MD5] == NULL)
+ return (0);
+ memset(dst_t_func[KEY_HMAC_MD5], 0, sizeof(struct dst_func));
+ dst_t_func[KEY_HMAC_MD5]->sign = dst_hmac_md5_sign;
+ dst_t_func[KEY_HMAC_MD5]->verify = dst_hmac_md5_verify;
+ dst_t_func[KEY_HMAC_MD5]->compare = dst_hmac_md5_compare_keys;
+ dst_t_func[KEY_HMAC_MD5]->generate = dst_hmac_md5_generate_key;
+ dst_t_func[KEY_HMAC_MD5]->destroy = dst_hmac_md5_free_key_structure;
+ dst_t_func[KEY_HMAC_MD5]->to_dns_key = dst_hmac_md5_to_dns_key;
+ dst_t_func[KEY_HMAC_MD5]->from_dns_key = dst_buffer_to_hmac_md5;
+ dst_t_func[KEY_HMAC_MD5]->to_file_fmt = dst_hmac_md5_key_to_file_format;
+ dst_t_func[KEY_HMAC_MD5]->from_file_fmt = dst_hmac_md5_key_from_file_format;
+ return (1);
+}
+
+#else
+#define dst_hmac_md5_init res_9_dst_hmac_md5_init
+int
+dst_hmac_md5_init(){
+ return (0);
+}
+#endif
+
+
+
+
+
+
+
--- /dev/null
+#ifndef DST_INTERNAL_H
+#define DST_INTERNAL_H
+
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * Permission to use, copy modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THE SOFTWARE.
+ */
+#include <limits.h>
+#include <sys/param.h>
+#if (!defined(BSD)) || (BSD < 199306)
+# include <sys/bitypes.h>
+#else
+# include <sys/types.h>
+#endif
+
+#ifndef PATH_MAX
+# ifdef POSIX_PATH_MAX
+# define PATH_MAX POSIX_PATH_MAX
+# else
+# define PATH_MAX 255 /* this is the value of POSIX_PATH_MAX */
+# endif
+#endif
+
+#ifndef dst_func
+#define dst_func res_9_dst_func
+#endif
+#define DST_KEY res_9_DST_KEY
+typedef struct dst_key {
+ char *dk_key_name; /* name of the key */
+ int dk_key_size; /* this is the size of the key in bits */
+ int dk_proto; /* what protocols this key can be used for */
+ int dk_alg; /* algorithm number from key record */
+ u_int32_t dk_flags; /* and the flags of the public key */
+ u_int16_t dk_id; /* identifier of the key */
+ void *dk_KEY_struct; /* pointer to key in crypto pkg fmt */
+ struct dst_func *dk_func; /* point to cryptto pgk specific function table */
+} DST_KEY;
+#define HAS_DST_KEY
+
+#ifdef __APPLE__
+#include "dst.h"
+#else
+#include <isc/dst.h>
+#endif
+
+/*
+ * define what crypto systems are supported for RSA,
+ * BSAFE is prefered over RSAREF; only one can be set at any time
+ */
+#if defined(BSAFE) && defined(RSAREF)
+# error "Cannot have both BSAFE and RSAREF defined"
+#endif
+
+/* Declare dst_lib specific constants */
+#define KEY_FILE_FORMAT "1.2"
+
+/* suffixes for key file names */
+#define PRIVATE_KEY "private"
+#define PUBLIC_KEY "key"
+
+/* error handling */
+#ifdef REPORT_ERRORS
+#define EREPORT(str) printf str
+#else
+#define EREPORT(str) (void)0
+#endif
+
+/* use our own special macro to FRRE memory */
+
+#ifndef SAFE_FREE
+#define SAFE_FREE(a) \
+do{if(a != NULL){memset(a,0, sizeof(*a)); free(a); a=NULL;}} while (0)
+#define SAFE_FREE2(a,s) if (a != NULL && s > 0){memset(a,0, s);free(a); a=NULL;}
+#endif
+
+#define dst_func res_9_dst_func
+typedef struct dst_func {
+ int (*sign)(const int mode, DST_KEY *key, void **context,
+ const u_int8_t *data, const int len,
+ u_int8_t *signature, const int sig_len);
+ int (*verify)(const int mode, DST_KEY *key, void **context,
+ const u_int8_t *data, const int len,
+ const u_int8_t *signature, const int sig_len);
+ int (*compare)(const DST_KEY *key1, const DST_KEY *key2);
+ int (*generate)(DST_KEY *key, int parms);
+ void *(*destroy)(void *key);
+ /* conversion functions */
+ int (*to_dns_key)(const DST_KEY *key, u_int8_t *out,
+ const int out_len);
+ int (*from_dns_key)(DST_KEY *key, const u_int8_t *str,
+ const int str_len);
+ int (*to_file_fmt)(const DST_KEY *key, char *out,
+ const int out_len);
+ int (*from_file_fmt)(DST_KEY *key, const char *out,
+ const int out_len);
+
+} dst_func;
+
+#define dst_t_func res_9_dst_t_func
+extern dst_func *dst_t_func[DST_MAX_ALGS];
+
+#define key_file_fmt_str res_9_key_file_fmt_str
+extern const char *key_file_fmt_str;
+
+#define dst_path res_9_dst_path
+extern const char *dst_path;
+
+#ifndef DST_HASH_SIZE
+#define DST_HASH_SIZE 20 /* RIPEMD160 and SHA-1 are 20 bytes MD5 is 16 */
+#endif
+
+#define dst_bsafe_init res_9_dst_bsafe_init
+int dst_bsafe_init(void);
+
+#define dst_rsaref_init res_9_dst_rsaref_init
+int dst_rsaref_init(void);
+
+#define dst_hmac_md5_init res_9_dst_hmac_md5_init
+int dst_hmac_md5_init(void);
+
+#define dst_cylink_init res_9_dst_cylink_init
+int dst_cylink_init(void);
+
+#define dst_eay_dss_init res_9_dst_eay_dss_init
+int dst_eay_dss_init(void);
+
+/* from higher level support routines */
+#define dst_s_calculate_bits res_9_dst_s_calculate_bits
+int dst_s_calculate_bits( const u_int8_t *str, const int max_bits);
+
+#define dst_s_verify_str res_9_dst_s_verify_str
+int dst_s_verify_str( const char **buf, const char *str);
+
+
+/* conversion between dns names and key file names */
+#define dst_s_filename_length res_9_dst_s_filename_length
+size_t dst_s_filename_length( const char *name, const char *suffix);
+
+#define dst_s_build_filename res_9_dst_s_build_filename
+int dst_s_build_filename( char *filename, const char *name,
+ u_int16_t id, int alg, const char *suffix,
+ size_t filename_length);
+
+#define dst_s_fopen res_9_dst_s_fopen
+FILE *dst_s_fopen (const char *filename, const char *mode, int perm);
+
+/*
+ * read and write network byte order into u_int?_t
+ * all of these should be retired
+ */
+#define dst_s_get_int16 res_9_dst_s_get_int16
+u_int16_t dst_s_get_int16( const u_int8_t *buf);
+
+#define dst_s_put_int16 res_9_dst_s_put_int16
+void dst_s_put_int16( u_int8_t *buf, const u_int16_t val);
+
+#define dst_s_get_int32 res_9_dst_s_get_int32
+u_int32_t dst_s_get_int32( const u_int8_t *buf);
+
+#define dst_s_put_int32 res_9_dst_s_put_int32
+void dst_s_put_int32( u_int8_t *buf, const u_int32_t val);
+
+#ifdef DUMP
+# undef DUMP
+# define DUMP(a,b,c,d) dst_s_dump(a,b,c,d)
+#else
+# define DUMP(a,b,c,d)
+#endif
+#define dst_s_dump res_9_dst_s_dump
+void
+dst_s_dump(const int mode, const u_char *data, const int size,
+ const char *msg);
+
+
+
+#endif /* DST_INTERNAL_H */
--- /dev/null
+#ifndef __APPLE__
+static const char rcsid[] = "$Header: /Users/Shared/libresolv_2/libresolv/dst_support.c,v 1.1 2006/03/01 19:01:36 majka Exp $";
+#endif
+
+
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * Permission to use, copy modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THE SOFTWARE.
+ */
+
+#ifndef __APPLE__
+#include "port_before.h"
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <memory.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include "dst_internal.h"
+
+#ifndef __APPLE__
+#include "port_after.h"
+#endif
+
+/*
+ * dst_s_verify_str()
+ * Validate that the input string(*str) is at the head of the input
+ * buffer(**buf). If so, move the buffer head pointer (*buf) to
+ * the first byte of data following the string(*str).
+ * Parameters
+ * buf Input buffer.
+ * str Input string.
+ * Return
+ * 0 *str is not the head of **buff
+ * 1 *str is the head of **buff, *buf is is advanced to
+ * the tail of **buf.
+ */
+
+int
+dst_s_verify_str(const char **buf, const char *str)
+{
+ int b, s;
+ if (*buf == NULL) /* error checks */
+ return (0);
+ if (str == NULL || *str == '\0')
+ return (1);
+
+ b = strlen(*buf); /* get length of strings */
+ s = strlen(str);
+ if (s > b || strncmp(*buf, str, s)) /* check if same */
+ return (0); /* not a match */
+ (*buf) += s; /* advance pointer */
+ return (1);
+}
+
+#ifdef _UNUSED_API_
+/*
+ * dst_s_calculate_bits
+ * Given a binary number represented in a u_char[], determine
+ * the number of significant bits used.
+ * Parameters
+ * str An input character string containing a binary number.
+ * max_bits The maximum possible significant bits.
+ * Return
+ * N The number of significant bits in str.
+ */
+
+int
+dst_s_calculate_bits(const u_char *str, const int max_bits)
+{
+ const u_char *p = str;
+ u_char i, j = 0x80;
+ int bits;
+ for (bits = max_bits; *p == 0x00 && bits > 0; p++)
+ bits -= 8;
+ for (i = *p; (i & j) != j; j >>= 1)
+ bits--;
+ return (bits);
+}
+#endif
+
+/*
+ * calculates a checksum used in dst for an id.
+ * takes an array of bytes and a length.
+ * returns a 16 bit checksum.
+ */
+#ifdef __APPLE__
+static
+#endif
+u_int16_t
+dst_s_id_calc(const u_char *key, const int keysize)
+{
+ u_int32_t ac;
+ const u_char *kp = key;
+ int size = keysize;
+
+ if (!key || (keysize <= 0))
+ return (-1);
+
+ for (ac = 0; size > 1; size -= 2, kp += 2)
+ ac += ((*kp) << 8) + *(kp + 1);
+
+ if (size > 0)
+ ac += ((*kp) << 8);
+ ac += (ac >> 16) & 0xffff;
+
+ return (ac & 0xffff);
+}
+
+/*
+ * dst_s_dns_key_id() Function to calculate DNSSEC footprint from KEY record
+ * rdata
+ * Input:
+ * dns_key_rdata: the raw data in wire format
+ * rdata_len: the size of the input data
+ * Output:
+ * the key footprint/id calculated from the key data
+ */
+u_int16_t
+dst_s_dns_key_id(const u_char *dns_key_rdata, const int rdata_len)
+{
+ if (!dns_key_rdata)
+ return 0;
+
+ /* compute id */
+ if (dns_key_rdata[3] == KEY_RSA) /* Algorithm RSA */
+ return dst_s_get_int16((const u_char *)
+ &dns_key_rdata[rdata_len - 3]);
+ else if (dns_key_rdata[3] == KEY_HMAC_MD5)
+ /* compatibility */
+ return 0;
+ else
+ /* compute a checksum on the key part of the key rr */
+ return dst_s_id_calc(dns_key_rdata, rdata_len);
+}
+
+/*
+ * dst_s_get_int16
+ * This routine extracts a 16 bit integer from a two byte character
+ * string. The character string is assumed to be in network byte
+ * order and may be unaligned. The number returned is in host order.
+ * Parameter
+ * buf A two byte character string.
+ * Return
+ * The converted integer value.
+ */
+
+u_int16_t
+dst_s_get_int16(const u_char *buf)
+{
+ register u_int16_t a = 0;
+ a = ((u_int16_t)(buf[0] << 8)) | ((u_int16_t)(buf[1]));
+ return (a);
+}
+
+
+#ifdef _UNUSED_API_
+/*
+ * dst_s_get_int32
+ * This routine extracts a 32 bit integer from a four byte character
+ * string. The character string is assumed to be in network byte
+ * order and may be unaligned. The number returned is in host order.
+ * Parameter
+ * buf A four byte character string.
+ * Return
+ * The converted integer value.
+ */
+
+u_int32_t
+dst_s_get_int32(const u_char *buf)
+{
+ register u_int32_t a = 0;
+ a = ((u_int32_t)(buf[0] << 24)) | ((u_int32_t)(buf[1] << 16)) |
+ ((u_int32_t)(buf[2] << 8)) | ((u_int32_t)(buf[3]));
+ return (a);
+}
+#endif
+
+/*
+ * dst_s_put_int16
+ * Take a 16 bit integer and store the value in a two byte
+ * character string. The integer is assumed to be in network
+ * order and the string is returned in host order.
+ *
+ * Parameters
+ * buf Storage for a two byte character string.
+ * val 16 bit integer.
+ */
+
+void
+dst_s_put_int16(u_int8_t *buf, const u_int16_t val)
+{
+ buf[0] = (u_int8_t)(val >> 8);
+ buf[1] = (u_int8_t)(val);
+}
+
+#ifdef _UNUSED_API_
+/*
+ * dst_s_put_int32
+ * Take a 32 bit integer and store the value in a four byte
+ * character string. The integer is assumed to be in network
+ * order and the string is returned in host order.
+ *
+ * Parameters
+ * buf Storage for a four byte character string.
+ * val 32 bit integer.
+ */
+
+void
+dst_s_put_int32(u_int8_t *buf, const u_int32_t val)
+{
+ buf[0] = (u_int8_t)(val >> 24);
+ buf[1] = (u_int8_t)(val >> 16);
+ buf[2] = (u_int8_t)(val >> 8);
+ buf[3] = (u_int8_t)(val);
+}
+#endif
+
+
+#ifdef _UNUSED_API_
+/*
+ * dst_s_filename_length
+ *
+ * This function returns the number of bytes needed to hold the
+ * filename for a key file. '/', '\' and ':' are not allowed.
+ * form: K<keyname>+<alg>+<id>.<suffix>
+ *
+ * Returns 0 if the filename would contain either '\', '/' or ':'
+ */
+size_t
+dst_s_filename_length(const char *name, const char *suffix)
+{
+ if (name == NULL)
+ return (0);
+ if (strrchr(name, '\\'))
+ return (0);
+ if (strrchr(name, '/'))
+ return (0);
+ if (strrchr(name, ':'))
+ return (0);
+ if (suffix == NULL)
+ return (0);
+ if (strrchr(suffix, '\\'))
+ return (0);
+ if (strrchr(suffix, '/'))
+ return (0);
+ if (strrchr(suffix, ':'))
+ return (0);
+ return (1 + strlen(name) + 6 + strlen(suffix));
+}
+#endif
+
+/*
+ * dst_s_build_filename ()
+ * Builds a key filename from the key name, it's id, and a
+ * suffix. '\', '/' and ':' are not allowed. fA filename is of the
+ * form: K<keyname><id>.<suffix>
+ * form: K<keyname>+<alg>+<id>.<suffix>
+ *
+ * Returns -1 if the conversion fails:
+ * if the filename would be too long for space allotted
+ * if the filename would contain a '\', '/' or ':'
+ * Returns 0 on success
+ */
+
+int
+dst_s_build_filename(char *filename, const char *name, u_int16_t id,
+ int alg, const char *suffix, size_t filename_length)
+{
+ u_int32_t my_id;
+ if (filename == NULL)
+ return (-1);
+ memset(filename, 0, filename_length);
+ if (name == NULL)
+ return (-1);
+ if (suffix == NULL)
+ return (-1);
+ if (filename_length < 1 + strlen(name) + 4 + 6 + 1 + strlen(suffix))
+ return (-1);
+ my_id = id;
+ sprintf(filename, "K%s+%03d+%05d.%s", name, alg, my_id,
+ (const char *) suffix);
+ if (strrchr(filename, '/'))
+ return (-1);
+ if (strrchr(filename, '\\'))
+ return (-1);
+ if (strrchr(filename, ':'))
+ return (-1);
+ return (0);
+}
+
+/*
+ * dst_s_fopen ()
+ * Open a file in the dst_path directory. If perm is specified, the
+ * file is checked for existence first, and not opened if it exists.
+ * Parameters
+ * filename File to open
+ * mode Mode to open the file (passed directly to fopen)
+ * perm File permission, if creating a new file.
+ * Returns
+ * NULL Failure
+ * NON-NULL (FILE *) of opened file.
+ */
+FILE *
+dst_s_fopen(const char *filename, const char *mode, int perm)
+{
+ FILE *fp;
+ char pathname[PATH_MAX];
+ size_t plen = sizeof(pathname);
+
+ if (*dst_path != '\0') {
+ strcpy(pathname, dst_path);
+ plen -= strlen(pathname);
+ }
+ else
+ pathname[0] = '\0';
+
+ if (plen > strlen(filename))
+ strncpy(&pathname[PATH_MAX - plen], filename, plen-1);
+ else
+ return (NULL);
+
+ fp = fopen(pathname, mode);
+ if (perm)
+ chmod(pathname, perm);
+ return (fp);
+}
+
+#ifdef _UNUSED_API_
+void
+dst_s_dump(const int mode, const u_char *data, const int size,
+ const char *msg)
+{
+#ifndef __APPLE__
+ UNUSED(data);
+#endif
+
+ if (size > 0) {
+#ifdef LONG_TEST
+ static u_char scratch[1000];
+ int n ;
+ n = b64_ntop(data, scratch, size, sizeof(scratch));
+ printf("%s: %x %d %s\n", msg, mode, n, scratch);
+#else
+ printf("%s,%x %d\n", msg, mode, size);
+#endif
+ }
+}
+#endif
--- /dev/null
+/*
+ * Copyright (c) 1983, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * $Id: nameser.h,v 1.1 2006/03/01 19:01:36 majka Exp $
+ */
+
+#ifndef _NAMESER_9_H_
+#define _NAMESER_9_H_
+
+#ifdef BIND_8_COMPAT
+#include <arpa/nameser8_compat.h>
+#else
+
+#include <sys/param.h>
+#if (!defined(BSD)) || (BSD < 199306)
+# include <sys/bitypes.h>
+#else
+# include <sys/types.h>
+#endif
+#include <sys/cdefs.h>
+
+/*
+ * Revision information. This is the release date in YYYYMMDD format.
+ * It can change every day so the right thing to do with it is use it
+ * in preprocessor commands such as "#if (__NAMESER > 19931104)". Do not
+ * compare for equality; rather, use it to determine whether your libbind.a
+ * contains a new enough lib/nameser/ to support the feature you need.
+ */
+
+#define __NAMESER 19991006 /* New interface version stamp. */
+
+/*
+ * Define constants based on RFC 883, RFC 1034, RFC 1035
+ */
+#define NS_PACKETSZ 512 /* maximum packet size */
+#define NS_MAXDNAME 1025 /* maximum domain name */
+#define NS_MAXCDNAME 255 /* maximum compressed domain name */
+#define NS_MAXLABEL 63 /* maximum length of domain label */
+#define NS_HFIXEDSZ 12 /* #/bytes of fixed data in header */
+#define NS_QFIXEDSZ 4 /* #/bytes of fixed data in query */
+#define NS_RRFIXEDSZ 10 /* #/bytes of fixed data in r record */
+#define NS_INT32SZ 4 /* #/bytes of data in a u_int32_t */
+#define NS_INT16SZ 2 /* #/bytes of data in a u_int16_t */
+#define NS_INT8SZ 1 /* #/bytes of data in a u_int8_t */
+#define NS_INADDRSZ 4 /* IPv4 T_A */
+#define NS_IN6ADDRSZ 16 /* IPv6 T_AAAA */
+#define NS_CMPRSFLGS 0xc0 /* Flag bits indicating name compression. */
+#define NS_DEFAULTPORT 53 /* For both TCP and UDP. */
+
+/*
+ * These can be expanded with synonyms, just keep ns_parse.c:ns_parserecord()
+ * in synch with it.
+ */
+#define ns_sect res_9_ns_sect
+typedef enum __ns_sect {
+ ns_s_qd = 0, /* Query: Question. */
+ ns_s_zn = 0, /* Update: Zone. */
+ ns_s_an = 1, /* Query: Answer. */
+ ns_s_pr = 1, /* Update: Prerequisites. */
+ ns_s_ns = 2, /* Query: Name servers. */
+ ns_s_ud = 2, /* Update: Update. */
+ ns_s_ar = 3, /* Query|Update: Additional records. */
+ ns_s_max = 4
+} ns_sect;
+
+/*
+ * This is a message handle. It is caller allocated and has no dynamic data.
+ * This structure is intended to be opaque to all but ns_parse.c, thus the
+ * leading _'s on the member names. Use the accessor functions, not the _'s.
+ */
+#define ns_msg res_9_ns_msg
+typedef struct __ns_msg {
+ const u_char *_msg, *_eom;
+ u_int16_t _id, _flags, _counts[ns_s_max];
+ const u_char *_sections[ns_s_max];
+ ns_sect _sect;
+ int _rrnum;
+ const u_char *_msg_ptr;
+} ns_msg;
+
+/* Private data structure - do not use from outside library. */
+#define _ns_flagdata _res_9_ns_flagdata
+struct _ns_flagdata { int mask, shift; };
+extern struct _ns_flagdata _ns_flagdata[];
+
+/* Accessor macros - this is part of the public interface. */
+
+#define ns_msg_id(handle) ((handle)._id + 0)
+#define ns_msg_base(handle) ((handle)._msg + 0)
+#define ns_msg_end(handle) ((handle)._eom + 0)
+#define ns_msg_size(handle) ((handle)._eom - (handle)._msg)
+#define ns_msg_count(handle, section) ((handle)._counts[section] + 0)
+
+/*
+ * This is a parsed record. It is caller allocated and has no dynamic data.
+ */
+#define ns_rr res_9_ns_rr
+
+typedef struct __ns_rr {
+ char name[NS_MAXDNAME];
+ u_int16_t type;
+ u_int16_t rr_class;
+ u_int32_t ttl;
+ u_int16_t rdlength;
+ const u_char * rdata;
+} ns_rr;
+
+/* Accessor macros - this is part of the public interface. */
+#define ns_rr_name(rr) (((rr).name[0] != '\0') ? (rr).name : ".")
+#define ns_rr_type(rr) ((ns_type)((rr).type + 0))
+#define ns_rr_class(rr) ((ns_class)((rr).rr_class + 0))
+#define ns_rr_ttl(rr) ((rr).ttl + 0)
+#define ns_rr_rdlen(rr) ((rr).rdlength + 0)
+#define ns_rr_rdata(rr) ((rr).rdata + 0)
+
+/*
+ * These don't have to be in the same order as in the packet flags word,
+ * and they can even overlap in some cases, but they will need to be kept
+ * in synch with ns_parse.c:ns_flagdata[].
+ */
+#define ns_flag res_9_ns_flag
+typedef enum __ns_flag {
+ ns_f_qr, /* Question/Response. */
+ ns_f_opcode, /* Operation code. */
+ ns_f_aa, /* Authoritative Answer. */
+ ns_f_tc, /* Truncation occurred. */
+ ns_f_rd, /* Recursion Desired. */
+ ns_f_ra, /* Recursion Available. */
+ ns_f_z, /* MBZ. */
+ ns_f_ad, /* Authentic Data (DNSSEC). */
+ ns_f_cd, /* Checking Disabled (DNSSEC). */
+ ns_f_rcode, /* Response code. */
+ ns_f_max
+} ns_flag;
+
+/*
+ * Currently defined opcodes.
+ */
+#define ns_opcode res_9_ns_opcode
+typedef enum __ns_opcode {
+ ns_o_query = 0, /* Standard query. */
+ ns_o_iquery = 1, /* Inverse query (deprecated/unsupported). */
+ ns_o_status = 2, /* Name server status query (unsupported). */
+ /* Opcode 3 is undefined/reserved. */
+ ns_o_notify = 4, /* Zone change notification. */
+ ns_o_update = 5, /* Zone update message. */
+ ns_o_max = 6
+} ns_opcode;
+
+/*
+ * Currently defined response codes.
+ */
+#define ns_rcode res_9_ns_rcode
+typedef enum __ns_rcode {
+ ns_r_noerror = 0, /* No error occurred. */
+ ns_r_formerr = 1, /* Format error. */
+ ns_r_servfail = 2, /* Server failure. */
+ ns_r_nxdomain = 3, /* Name error. */
+ ns_r_notimpl = 4, /* Unimplemented. */
+ ns_r_refused = 5, /* Operation refused. */
+ /* these are for BIND_UPDATE */
+ ns_r_yxdomain = 6, /* Name exists */
+ ns_r_yxrrset = 7, /* RRset exists */
+ ns_r_nxrrset = 8, /* RRset does not exist */
+ ns_r_notauth = 9, /* Not authoritative for zone */
+ ns_r_notzone = 10, /* Zone of record different from zone section */
+ ns_r_max = 11,
+ /* The following are EDNS extended rcodes */
+ ns_r_badvers = 16,
+ /* The following are TSIG errors */
+ ns_r_badsig = 16,
+ ns_r_badkey = 17,
+ ns_r_badtime = 18
+} ns_rcode;
+
+/* BIND_UPDATE */
+#define ns_update_operation res_9_ns_update_operation
+typedef enum __ns_update_operation {
+ ns_uop_delete = 0,
+ ns_uop_add = 1,
+ ns_uop_max = 2
+} ns_update_operation;
+
+/*
+ * This structure is used for TSIG authenticated messages
+ */
+#define ns_tsig_key res_9_ns_tsig_key
+struct ns_tsig_key {
+ char name[NS_MAXDNAME], alg[NS_MAXDNAME];
+ unsigned char *data;
+ int len;
+};
+typedef struct ns_tsig_key ns_tsig_key;
+
+/*
+ * This structure is used for TSIG authenticated TCP messages
+ */
+#define ns_tcp_tsig_state res_9_ns_tcp_tsig_state
+struct ns_tcp_tsig_state {
+ int counter;
+ struct dst_key *key;
+ void *ctx;
+ unsigned char sig[NS_PACKETSZ];
+ int siglen;
+};
+typedef struct ns_tcp_tsig_state ns_tcp_tsig_state;
+
+#define NS_TSIG_FUDGE 300
+#define NS_TSIG_TCP_COUNT 100
+#define NS_TSIG_ALG_HMAC_MD5 "HMAC-MD5.SIG-ALG.REG.INT"
+
+#define NS_TSIG_ERROR_NO_TSIG -10
+#define NS_TSIG_ERROR_NO_SPACE -11
+#define NS_TSIG_ERROR_FORMERR -12
+
+/*
+ * Currently defined type values for resources and queries.
+ */
+#define ns_typw res_9_ns_type
+typedef enum __ns_type {
+ ns_t_invalid = 0, /* Cookie. */
+ ns_t_a = 1, /* Host address. */
+ ns_t_ns = 2, /* Authoritative server. */
+ ns_t_md = 3, /* Mail destination. */
+ ns_t_mf = 4, /* Mail forwarder. */
+ ns_t_cname = 5, /* Canonical name. */
+ ns_t_soa = 6, /* Start of authority zone. */
+ ns_t_mb = 7, /* Mailbox domain name. */
+ ns_t_mg = 8, /* Mail group member. */
+ ns_t_mr = 9, /* Mail rename name. */
+ ns_t_null = 10, /* Null resource record. */
+ ns_t_wks = 11, /* Well known service. */
+ ns_t_ptr = 12, /* Domain name pointer. */
+ ns_t_hinfo = 13, /* Host information. */
+ ns_t_minfo = 14, /* Mailbox information. */
+ ns_t_mx = 15, /* Mail routing information. */
+ ns_t_txt = 16, /* Text strings. */
+ ns_t_rp = 17, /* Responsible person. */
+ ns_t_afsdb = 18, /* AFS cell database. */
+ ns_t_x25 = 19, /* X_25 calling address. */
+ ns_t_isdn = 20, /* ISDN calling address. */
+ ns_t_rt = 21, /* Router. */
+ ns_t_nsap = 22, /* NSAP address. */
+ ns_t_nsap_ptr = 23, /* Reverse NSAP lookup (deprecated). */
+ ns_t_sig = 24, /* Security signature. */
+ ns_t_key = 25, /* Security key. */
+ ns_t_px = 26, /* X.400 mail mapping. */
+ ns_t_gpos = 27, /* Geographical position (withdrawn). */
+ ns_t_aaaa = 28, /* Ip6 Address. */
+ ns_t_loc = 29, /* Location Information. */
+ ns_t_nxt = 30, /* Next domain (security). */
+ ns_t_eid = 31, /* Endpoint identifier. */
+ ns_t_nimloc = 32, /* Nimrod Locator. */
+ ns_t_srv = 33, /* Server Selection. */
+ ns_t_atma = 34, /* ATM Address */
+ ns_t_naptr = 35, /* Naming Authority PoinTeR */
+ ns_t_kx = 36, /* Key Exchange */
+ ns_t_cert = 37, /* Certification record */
+ ns_t_a6 = 38, /* IPv6 address (deprecates AAAA) */
+ ns_t_dname = 39, /* Non-terminal DNAME (for IPv6) */
+ ns_t_sink = 40, /* Kitchen sink (experimentatl) */
+ ns_t_opt = 41, /* EDNS0 option (meta-RR) */
+ ns_t_tkey = 249, /* Transaction key */
+ ns_t_tsig = 250, /* Transaction signature. */
+ ns_t_ixfr = 251, /* Incremental zone transfer. */
+ ns_t_axfr = 252, /* Transfer zone of authority. */
+ ns_t_mailb = 253, /* Transfer mailbox records. */
+ ns_t_maila = 254, /* Transfer mail agent records. */
+ ns_t_any = 255, /* Wildcard match. */
+ ns_t_zxfr = 256, /* BIND-specific, nonstandard. */
+ ns_t_max = 65536
+} ns_type;
+
+/* Exclusively a QTYPE? (not also an RTYPE) */
+#define ns_t_qt_p(t) (ns_t_xfr_p(t) || (t) == ns_t_any || \
+ (t) == ns_t_mailb || (t) == ns_t_maila)
+/* Some kind of meta-RR? (not a QTYPE, but also not an RTYPE) */
+#define ns_t_mrr_p(t) ((t) == ns_t_tsig || (t) == ns_t_opt)
+/* Exclusively an RTYPE? (not also a QTYPE or a meta-RR) */
+#define ns_t_rr_p(t) (!ns_t_qt_p(t) && !ns_t_mrr_p(t))
+#define ns_t_udp_p(t) ((t) != ns_t_axfr && (t) != ns_t_zxfr)
+#define ns_t_xfr_p(t) ((t) == ns_t_axfr || (t) == ns_t_ixfr || \
+ (t) == ns_t_zxfr)
+
+/*
+ * Values for class field
+ */
+#define ns_class res_9_ns_class
+typedef enum __ns_class {
+ ns_c_invalid = 0, /* Cookie. */
+ ns_c_in = 1, /* Internet. */
+ ns_c_2 = 2, /* unallocated/unsupported. */
+ ns_c_chaos = 3, /* MIT Chaos-net. */
+ ns_c_hs = 4, /* MIT Hesiod. */
+ /* Query class values which do not appear in resource records */
+ ns_c_none = 254, /* for prereq. sections in update requests */
+ ns_c_any = 255, /* Wildcard match. */
+ ns_c_max = 65536
+} ns_class;
+
+/* DNSSEC constants. */
+
+#define ns_key_types res_9_ns_key_types
+typedef enum __ns_key_types {
+ ns_kt_rsa = 1, /* key type RSA/MD5 */
+ ns_kt_dh = 2, /* Diffie Hellman */
+ ns_kt_dsa = 3, /* Digital Signature Standard (MANDATORY) */
+ ns_kt_private = 254 /* Private key type starts with OID */
+} ns_key_types;
+
+#define ns_cert_types res_9_ns_cert_types
+typedef enum __ns_cert_types {
+ cert_t_pkix = 1, /* PKIX (X.509v3) */
+ cert_t_spki = 2, /* SPKI */
+ cert_t_pgp = 3, /* PGP */
+ cert_t_url = 253, /* URL private type */
+ cert_t_oid = 254 /* OID private type */
+} ns_cert_types;
+
+/* Flags field of the KEY RR rdata. */
+#define NS_KEY_TYPEMASK 0xC000 /* Mask for "type" bits */
+#define NS_KEY_TYPE_AUTH_CONF 0x0000 /* Key usable for both */
+#define NS_KEY_TYPE_CONF_ONLY 0x8000 /* Key usable for confidentiality */
+#define NS_KEY_TYPE_AUTH_ONLY 0x4000 /* Key usable for authentication */
+#define NS_KEY_TYPE_NO_KEY 0xC000 /* No key usable for either; no key */
+/* The type bits can also be interpreted independently, as single bits: */
+#define NS_KEY_NO_AUTH 0x8000 /* Key unusable for authentication */
+#define NS_KEY_NO_CONF 0x4000 /* Key unusable for confidentiality */
+#define NS_KEY_RESERVED2 0x2000 /* Security is *mandatory* if bit=0 */
+#define NS_KEY_EXTENDED_FLAGS 0x1000 /* reserved - must be zero */
+#define NS_KEY_RESERVED4 0x0800 /* reserved - must be zero */
+#define NS_KEY_RESERVED5 0x0400 /* reserved - must be zero */
+#define NS_KEY_NAME_TYPE 0x0300 /* these bits determine the type */
+#define NS_KEY_NAME_USER 0x0000 /* key is assoc. with user */
+#define NS_KEY_NAME_ENTITY 0x0200 /* key is assoc. with entity eg host */
+#define NS_KEY_NAME_ZONE 0x0100 /* key is zone key */
+#define NS_KEY_NAME_RESERVED 0x0300 /* reserved meaning */
+#define NS_KEY_RESERVED8 0x0080 /* reserved - must be zero */
+#define NS_KEY_RESERVED9 0x0040 /* reserved - must be zero */
+#define NS_KEY_RESERVED10 0x0020 /* reserved - must be zero */
+#define NS_KEY_RESERVED11 0x0010 /* reserved - must be zero */
+#define NS_KEY_SIGNATORYMASK 0x000F /* key can sign RR's of same name */
+#define NS_KEY_RESERVED_BITMASK ( NS_KEY_RESERVED2 | \
+ NS_KEY_RESERVED4 | \
+ NS_KEY_RESERVED5 | \
+ NS_KEY_RESERVED8 | \
+ NS_KEY_RESERVED9 | \
+ NS_KEY_RESERVED10 | \
+ NS_KEY_RESERVED11 )
+#define NS_KEY_RESERVED_BITMASK2 0xFFFF /* no bits defined here */
+
+/* The Algorithm field of the KEY and SIG RR's is an integer, {1..254} */
+#define NS_ALG_MD5RSA 1 /* MD5 with RSA */
+#define NS_ALG_DH 2 /* Diffie Hellman KEY */
+#define NS_ALG_DSA 3 /* DSA KEY */
+#define NS_ALG_DSS NS_ALG_DSA
+#define NS_ALG_EXPIRE_ONLY 253 /* No alg, no security */
+#define NS_ALG_PRIVATE_OID 254 /* Key begins with OID giving alg */
+
+/* Protocol values */
+/* value 0 is reserved */
+#define NS_KEY_PROT_TLS 1
+#define NS_KEY_PROT_EMAIL 2
+#define NS_KEY_PROT_DNSSEC 3
+#define NS_KEY_PROT_IPSEC 4
+#define NS_KEY_PROT_ANY 255
+
+/* Signatures */
+#define NS_MD5RSA_MIN_BITS 512 /* Size of a mod or exp in bits */
+#define NS_MD5RSA_MAX_BITS 2552
+ /* Total of binary mod and exp */
+#define NS_MD5RSA_MAX_BYTES ((NS_MD5RSA_MAX_BITS+7/8)*2+3)
+ /* Max length of text sig block */
+#define NS_MD5RSA_MAX_BASE64 (((NS_MD5RSA_MAX_BYTES+2)/3)*4)
+#define NS_MD5RSA_MIN_SIZE ((NS_MD5RSA_MIN_BITS+7)/8)
+#define NS_MD5RSA_MAX_SIZE ((NS_MD5RSA_MAX_BITS+7)/8)
+
+#define NS_DSA_SIG_SIZE 41
+#define NS_DSA_MIN_SIZE 213
+#define NS_DSA_MAX_BYTES 405
+
+/* Offsets into SIG record rdata to find various values */
+#define NS_SIG_TYPE 0 /* Type flags */
+#define NS_SIG_ALG 2 /* Algorithm */
+#define NS_SIG_LABELS 3 /* How many labels in name */
+#define NS_SIG_OTTL 4 /* Original TTL */
+#define NS_SIG_EXPIR 8 /* Expiration time */
+#define NS_SIG_SIGNED 12 /* Signature time */
+#define NS_SIG_FOOT 16 /* Key footprint */
+#define NS_SIG_SIGNER 18 /* Domain name of who signed it */
+
+/* How RR types are represented as bit-flags in NXT records */
+#define NS_NXT_BITS 8
+#define NS_NXT_BIT_SET( n,p) (p[(n)/NS_NXT_BITS] |= (0x80>>((n)%NS_NXT_BITS)))
+#define NS_NXT_BIT_CLEAR(n,p) (p[(n)/NS_NXT_BITS] &= ~(0x80>>((n)%NS_NXT_BITS)))
+#define NS_NXT_BIT_ISSET(n,p) (p[(n)/NS_NXT_BITS] & (0x80>>((n)%NS_NXT_BITS)))
+#define NS_NXT_MAX 127
+
+/*
+ * EDNS0 extended flags, host order.
+ */
+#define NS_OPT_DNSSEC_OK 0x8000U
+
+/*
+ * Inline versions of get/put short/long. Pointer is advanced.
+ */
+#define NS_GET16(s, cp) do { \
+ register const u_char *t_cp = (const u_char *)(cp); \
+ (s) = ((u_int16_t)t_cp[0] << 8) \
+ | ((u_int16_t)t_cp[1]) \
+ ; \
+ (cp) += NS_INT16SZ; \
+} while (0)
+
+#define NS_GET32(l, cp) do { \
+ register const u_char *t_cp = (const u_char *)(cp); \
+ (l) = ((u_int32_t)t_cp[0] << 24) \
+ | ((u_int32_t)t_cp[1] << 16) \
+ | ((u_int32_t)t_cp[2] << 8) \
+ | ((u_int32_t)t_cp[3]) \
+ ; \
+ (cp) += NS_INT32SZ; \
+} while (0)
+
+#define NS_PUT16(s, cp) do { \
+ register u_int16_t t_s = (u_int16_t)(s); \
+ register u_char *t_cp = (u_char *)(cp); \
+ *t_cp++ = t_s >> 8; \
+ *t_cp = t_s; \
+ (cp) += NS_INT16SZ; \
+} while (0)
+
+#define NS_PUT32(l, cp) do { \
+ register u_int32_t t_l = (u_int32_t)(l); \
+ register u_char *t_cp = (u_char *)(cp); \
+ *t_cp++ = t_l >> 24; \
+ *t_cp++ = t_l >> 16; \
+ *t_cp++ = t_l >> 8; \
+ *t_cp = t_l; \
+ (cp) += NS_INT32SZ; \
+} while (0)
+
+/*
+ * ANSI C identifier hiding for bind's lib/nameser.
+ */
+#define ns_msg_getflag res_9_ns_msg_getflag
+#define ns_get16 res_9_ns_get16
+#define ns_get32 res_9_ns_get32
+#define ns_put16 res_9_ns_put16
+#define ns_put32 res_9_ns_put32
+#define ns_initparse res_9_ns_initparse
+#define ns_skiprr res_9_ns_skiprr
+#define ns_parserr res_9_ns_parserr
+#define ns_sprintrr res_9_ns_sprintrr
+#define ns_sprintrrf res_9_ns_sprintrrf
+#define ns_format_ttl res_9_ns_format_ttl
+#define ns_parse_ttl res_9_ns_parse_ttl
+#define ns_datetosecs res_9_ns_datetosecs
+#define ns_name_ntol res_9_ns_name_ntol
+#define ns_name_ntop res_9_ns_name_ntop
+#define ns_name_pton res_9_ns_name_pton
+#define ns_name_unpack res_9_ns_name_unpack
+#define ns_name_pack res_9_ns_name_pack
+#define ns_name_compress res_9_ns_name_compress
+#define ns_name_uncompress res_9_ns_name_uncompress
+#define ns_name_skip res_9_ns_name_skip
+#define ns_name_rollback res_9_ns_name_rollback
+#define ns_sign res_9_ns_sign
+#define ns_sign2 res_9_ns_sign2
+#define ns_sign_tcp res_9_ns_sign_tcp
+#define ns_sign_tcp2 res_9_ns_sign_tcp2
+#define ns_sign_tcp_init res_9_ns_sign_tcp_init
+#define ns_find_tsig res_9_ns_find_tsig
+#define ns_verify res_9_ns_verify
+#define ns_verify_tcp res_9_ns_verify_tcp
+#define ns_verify_tcp_init res_9_ns_verify_tcp_init
+#define ns_samedomain res_9_ns_samedomain
+#define ns_subdomain res_9_ns_subdomain
+#define ns_makecanon res_9_ns_makecanon
+#define ns_samename res_9_ns_samename
+
+__BEGIN_DECLS
+int ns_msg_getflag __P((ns_msg, int));
+u_int ns_get16 __P((const u_char *));
+u_long ns_get32 __P((const u_char *));
+void ns_put16 __P((u_int, u_char *));
+void ns_put32 __P((u_long, u_char *));
+int ns_initparse __P((const u_char *, int, ns_msg *));
+int ns_skiprr __P((const u_char *, const u_char *, ns_sect, int));
+int ns_parserr __P((ns_msg *, ns_sect, int, ns_rr *));
+int ns_sprintrr __P((const ns_msg *, const ns_rr *,
+ const char *, const char *, char *, size_t));
+int ns_sprintrrf __P((const u_char *, size_t, const char *,
+ ns_class, ns_type, u_long, const u_char *,
+ size_t, const char *, const char *,
+ char *, size_t));
+int ns_format_ttl __P((u_long, char *, size_t));
+int ns_parse_ttl __P((const char *, u_long *));
+u_int32_t ns_datetosecs __P((const char *cp, int *errp));
+int ns_name_ntol __P((const u_char *, u_char *, size_t));
+int ns_name_ntop __P((const u_char *, char *, size_t));
+int ns_name_pton __P((const char *, u_char *, size_t));
+int ns_name_unpack __P((const u_char *, const u_char *,
+ const u_char *, u_char *, size_t));
+int ns_name_pack __P((const u_char *, u_char *, int,
+ const u_char **, const u_char **));
+int ns_name_uncompress __P((const u_char *, const u_char *,
+ const u_char *, char *, size_t));
+int ns_name_compress __P((const char *, u_char *, size_t,
+ const u_char **, const u_char **));
+int ns_name_skip __P((const u_char **, const u_char *));
+void ns_name_rollback __P((const u_char *, const u_char **,
+ const u_char **));
+int ns_sign __P((u_char *, int *, int, int, void *,
+ const u_char *, int, u_char *, int *, time_t));
+int ns_sign2 __P((u_char *, int *, int, int, void *,
+ const u_char *, int, u_char *, int *, time_t,
+ u_char **, u_char **));
+int ns_sign_tcp __P((u_char *, int *, int, int,
+ ns_tcp_tsig_state *, int));
+int ns_sign_tcp2 __P((u_char *, int *, int, int,
+ ns_tcp_tsig_state *, int,
+ u_char **, u_char **));
+int ns_sign_tcp_init __P((void *, const u_char *, int,
+ ns_tcp_tsig_state *));
+u_char *ns_find_tsig __P((u_char *, u_char *));
+int ns_verify __P((u_char *, int *, void *,
+ const u_char *, int, u_char *, int *,
+ time_t *, int));
+int ns_verify_tcp __P((u_char *, int *, ns_tcp_tsig_state *, int));
+int ns_verify_tcp_init __P((void *, const u_char *, int,
+ ns_tcp_tsig_state *));
+int ns_samedomain __P((const char *, const char *));
+int ns_subdomain __P((const char *, const char *));
+int ns_makecanon __P((const char *, char *, size_t));
+int ns_samename __P((const char *, const char *));
+__END_DECLS
+
+#endif /* !BIND_8_COMPAT */
+#endif /* !_NAMESER_9_H_ */
--- /dev/null
+/*
+ * Copyright (c) 1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#ifndef __APPLE__
+#ifndef lint
+static const char rcsid[] = "$Id: ns_date.c,v 1.1 2006/03/01 19:01:36 majka Exp $";
+#endif
+#endif
+
+/* Import. */
+
+#ifndef __APPLE__
+#include "port_before.h"
+#endif
+
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#ifndef __APPLE__
+#include "port_after.h"
+#endif
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/* Forward. */
+
+static int datepart(const char *, int, int, int, int *);
+
+/* Public. */
+
+/* Convert a date in ASCII into the number of seconds since
+ 1 January 1970 (GMT assumed). Format is yyyymmddhhmmss, all
+ digits required, no spaces allowed. */
+
+u_int32_t
+ns_datetosecs(const char *cp, int *errp) {
+ struct tm time;
+ u_int32_t result;
+ int mdays, i;
+ static const int days_per_month[12] =
+ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+ if (strlen(cp) != 14) {
+ *errp = 1;
+ return (0);
+ }
+ *errp = 0;
+
+ memset(&time, 0, sizeof time);
+ time.tm_year = datepart(cp + 0, 4, 1990, 9999, errp) - 1900;
+ time.tm_mon = datepart(cp + 4, 2, 01, 12, errp) - 1;
+ time.tm_mday = datepart(cp + 6, 2, 01, 31, errp);
+ time.tm_hour = datepart(cp + 8, 2, 00, 23, errp);
+ time.tm_min = datepart(cp + 10, 2, 00, 59, errp);
+ time.tm_sec = datepart(cp + 12, 2, 00, 59, errp);
+ if (*errp) /* Any parse errors? */
+ return (0);
+
+ /*
+ * OK, now because timegm() is not available in all environments,
+ * we will do it by hand. Roll up sleeves, curse the gods, begin!
+ */
+
+#define SECS_PER_DAY ((u_int32_t)24*60*60)
+#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
+
+ result = time.tm_sec; /* Seconds */
+ result += time.tm_min * 60; /* Minutes */
+ result += time.tm_hour * (60*60); /* Hours */
+ result += (time.tm_mday - 1) * SECS_PER_DAY; /* Days */
+
+ /* Months are trickier. Look without leaping, then leap */
+ mdays = 0;
+ for (i = 0; i < time.tm_mon; i++)
+ mdays += days_per_month[i];
+ result += mdays * SECS_PER_DAY; /* Months */
+ if (time.tm_mon > 1 && isleap(1900+time.tm_year))
+ result += SECS_PER_DAY; /* Add leapday for this year */
+
+ /* First figure years without leapdays, then add them in. */
+ /* The loop is slow, FIXME, but simple and accurate. */
+ result += (time.tm_year - 70) * (SECS_PER_DAY*365); /* Years */
+ for (i = 70; i < time.tm_year; i++)
+ if (isleap(1900+i))
+ result += SECS_PER_DAY; /* Add leapday for prev year */
+
+ return (result);
+}
+
+/* Private. */
+
+/*
+ * Parse part of a date. Set error flag if any error.
+ * Don't reset the flag if there is no error.
+ */
+static int
+datepart(const char *buf, int size, int min, int max, int *errp) {
+ int result = 0;
+ int i;
+
+ for (i = 0; i < size; i++) {
+ if (!isdigit((unsigned char)(buf[i])))
+ *errp = 1;
+ result = (result * 10) + buf[i] - '0';
+ }
+ if (result < min)
+ *errp = 1;
+ if (result > max)
+ *errp = 1;
+ return (result);
+}
--- /dev/null
+/*
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#ifndef __APPLE__
+#ifndef lint
+static const char rcsid[] = "$Id: ns_name.c,v 1.1 2006/03/01 19:01:36 majka Exp $";
+#endif
+#endif
+
+#ifndef __APPLE__
+#include "port_before.h"
+#endif
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#ifndef __APPLE__
+#include "port_after.h"
+#endif
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+#define NS_TYPE_ELT 0x40 /* EDNS0 extended label type */
+#define DNS_LABELTYPE_BITSTRING 0x41
+
+/* Data. */
+
+static const char digits[] = "0123456789";
+
+static const char digitvalue[256] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
+};
+
+/* Forward. */
+
+static int special(int);
+static int printable(int);
+static int dn_find(const u_char *, const u_char *,
+ const u_char * const *,
+ const u_char * const *);
+static int encode_bitsring(const char **, const char *,
+ char **, char **, const char *);
+static int labellen(const u_char *);
+static int decode_bitstring(const char **, char *, const char *);
+
+/* Public. */
+
+/*
+ * ns_name_ntop(src, dst, dstsiz)
+ * Convert an encoded domain name to printable ascii as per RFC1035.
+ * return:
+ * Number of bytes written to buffer, or -1 (with errno set)
+ * notes:
+ * The root is returned as "."
+ * All other domains are returned in non absolute form
+ */
+int
+ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
+{
+ const u_char *cp;
+ char *dn, *eom;
+ u_char c;
+ u_int n;
+ int l;
+
+ cp = src;
+ dn = dst;
+ eom = dst + dstsiz;
+
+ while ((n = *cp++) != 0) {
+ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ /* Some kind of compression pointer. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (dn != dst) {
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '.';
+ }
+ if ((l = labellen(cp - 1)) < 0) {
+ errno = EMSGSIZE; /* XXX */
+ return(-1);
+ }
+ if (dn + l >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) {
+ int m;
+
+ if (n != DNS_LABELTYPE_BITSTRING) {
+ /* XXX: labellen should reject this case */
+ errno = EINVAL;
+ return(-1);
+ }
+ if ((m = decode_bitstring((const char **)&cp, dn, eom)) < 0)
+ {
+ errno = EMSGSIZE;
+ return(-1);
+ }
+ dn += m;
+ continue;
+ }
+ for ((void)NULL; l > 0; l--) {
+ c = *cp++;
+ if (special(c)) {
+ if (dn + 1 >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '\\';
+ *dn++ = (char)c;
+ } else if (!printable(c)) {
+ if (dn + 3 >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '\\';
+ *dn++ = digits[c / 100];
+ *dn++ = digits[(c % 100) / 10];
+ *dn++ = digits[c % 10];
+ } else {
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = (char)c;
+ }
+ }
+ }
+ if (dn == dst) {
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '.';
+ }
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '\0';
+ return (dn - dst);
+}
+
+/*
+ * ns_name_pton(src, dst, dstsiz)
+ * Convert a ascii string into an encoded domain name as per RFC1035.
+ * return:
+ * -1 if it fails
+ * 1 if string was fully qualified
+ * 0 is string was not fully qualified
+ * notes:
+ * Enforces label and domain length limits.
+ */
+
+int
+ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
+{
+ u_char *label, *bp, *eom;
+ int c, n, escaped, e = 0;
+ char *cp;
+
+ escaped = 0;
+ bp = dst;
+ eom = dst + dstsiz;
+ label = bp++;
+
+ while ((c = *src++) != 0) {
+ if (escaped) {
+ if (c == '[') { /* start a bit string label */
+ if ((cp = strchr(src, ']')) == NULL) {
+ errno = EINVAL; /* ??? */
+ return(-1);
+ }
+ if ((e = encode_bitsring(&src,
+ cp + 2,
+ (char **)&label,
+ (char **)&bp,
+ (const char *)eom))
+ != 0) {
+ errno = e;
+ return(-1);
+ }
+ escaped = 0;
+ label = bp++;
+ if ((c = *src++) == 0)
+ goto done;
+ else if (c != '.') {
+ errno = EINVAL;
+ return(-1);
+ }
+ continue;
+ }
+ else if ((cp = strchr(digits, c)) != NULL) {
+ n = (cp - digits) * 100;
+ if ((c = *src++) == 0 ||
+ (cp = strchr(digits, c)) == NULL) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ n += (cp - digits) * 10;
+ if ((c = *src++) == 0 ||
+ (cp = strchr(digits, c)) == NULL) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ n += (cp - digits);
+ if (n > 255) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ c = n;
+ }
+ escaped = 0;
+ } else if (c == '\\') {
+ escaped = 1;
+ continue;
+ } else if (c == '.') {
+ c = (bp - label - 1);
+ if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (label >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *label = c;
+ /* Fully qualified ? */
+ if (*src == '\0') {
+ if (c != 0) {
+ if (bp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *bp++ = '\0';
+ }
+ if ((bp - dst) > NS_MAXCDNAME) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ return (1);
+ }
+ if (c == 0 || *src == '.') {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ label = bp++;
+ continue;
+ }
+ if (bp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *bp++ = (u_char)c;
+ }
+ c = (bp - label - 1);
+ if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ done:
+ if (label >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *label = c;
+ if (c != 0) {
+ if (bp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *bp++ = 0;
+ }
+ if ((bp - dst) > NS_MAXCDNAME) { /* src too big */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * ns_name_ntol(src, dst, dstsiz)
+ * Convert a network strings labels into all lowercase.
+ * return:
+ * Number of bytes written to buffer, or -1 (with errno set)
+ * notes:
+ * Enforces label and domain length limits.
+ */
+
+int
+ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz)
+{
+ const u_char *cp;
+ u_char *dn, *eom;
+ u_char c;
+ u_int n;
+ int l;
+
+ cp = src;
+ dn = dst;
+ eom = dst + dstsiz;
+
+ while ((n = *cp++) != 0) {
+ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ /* Some kind of compression pointer. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = n;
+ if ((l = labellen(cp - 1)) < 0) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (dn + l >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ for ((void)NULL; l > 0; l--) {
+ c = *cp++;
+ if (isupper(c))
+ *dn++ = tolower(c);
+ else
+ *dn++ = c;
+ }
+ }
+ *dn++ = '\0';
+ return (dn - dst);
+}
+
+/*
+ * ns_name_unpack(msg, eom, src, dst, dstsiz)
+ * Unpack a domain name from a message, source may be compressed.
+ * return:
+ * -1 if it fails, or consumed octets if it succeeds.
+ */
+int
+ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
+ u_char *dst, size_t dstsiz)
+{
+ const u_char *srcp, *dstlim;
+ u_char *dstp;
+ int n, len, checked, l;
+
+ len = -1;
+ checked = 0;
+ dstp = dst;
+ srcp = src;
+ dstlim = dst + dstsiz;
+ if (srcp < msg || srcp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ /* Fetch next label in domain name. */
+ while ((n = *srcp++) != 0) {
+ /* Check for indirection. */
+ switch (n & NS_CMPRSFLGS) {
+ case 0:
+ case NS_TYPE_ELT:
+ /* Limit checks. */
+ if ((l = labellen(srcp - 1)) < 0) {
+ errno = EMSGSIZE;
+ return(-1);
+ }
+ if (dstp + l + 1 >= dstlim || srcp + l >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ checked += l + 1;
+ *dstp++ = n;
+ memcpy(dstp, srcp, l);
+ dstp += l;
+ srcp += l;
+ break;
+
+ case NS_CMPRSFLGS:
+ if (srcp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (len < 0)
+ len = srcp - src + 1;
+ srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
+ if (srcp < msg || srcp >= eom) { /* Out of range. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ checked += 2;
+ /*
+ * Check for loops in the compressed name;
+ * if we've looked at the whole message,
+ * there must be a loop.
+ */
+ if (checked >= eom - msg) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ break;
+
+ default:
+ errno = EMSGSIZE;
+ return (-1); /* flag error */
+ }
+ }
+ *dstp = '\0';
+ if (len < 0)
+ len = srcp - src;
+ return (len);
+}
+
+/*
+ * ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr)
+ * Pack domain name 'domain' into 'comp_dn'.
+ * return:
+ * Size of the compressed name, or -1.
+ * notes:
+ * 'dnptrs' is an array of pointers to previous compressed names.
+ * dnptrs[0] is a pointer to the beginning of the message. The array
+ * ends with NULL.
+ * 'lastdnptr' is a pointer to the end of the array pointed to
+ * by 'dnptrs'.
+ * Side effects:
+ * The list of pointers in dnptrs is updated for labels inserted into
+ * the message as we compress the name. If 'dnptr' is NULL, we don't
+ * try to compress names. If 'lastdnptr' is NULL, we don't update the
+ * list.
+ */
+int
+ns_name_pack(const u_char *src, u_char *dst, int dstsiz,
+ const u_char **dnptrs, const u_char **lastdnptr)
+{
+ u_char *dstp;
+ const u_char **cpp, **lpp, *eob, *msg;
+ const u_char *srcp;
+ int n, l, first = 1;
+
+ srcp = src;
+ dstp = dst;
+ eob = dstp + dstsiz;
+ lpp = cpp = NULL;
+ if (dnptrs != NULL) {
+ if ((msg = *dnptrs++) != NULL) {
+ for (cpp = dnptrs; *cpp != NULL; cpp++)
+ (void)NULL;
+ lpp = cpp; /* end of list to search */
+ }
+ } else
+ msg = NULL;
+
+ /* make sure the domain we are about to add is legal */
+ l = 0;
+ do {
+ int l0;
+
+ n = *srcp;
+ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if ((l0 = labellen(srcp)) < 0) {
+ errno = EINVAL;
+ return(-1);
+ }
+ l += l0 + 1;
+ if (l > NS_MAXCDNAME) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ srcp += l0 + 1;
+ } while (n != 0);
+
+ /* from here on we need to reset compression pointer array on error */
+ srcp = src;
+ do {
+ /* Look to see if we can use pointers. */
+ n = *srcp;
+ if (n != 0 && msg != NULL) {
+ l = dn_find(srcp, msg, (const u_char * const *)dnptrs,
+ (const u_char * const *)lpp);
+ if (l >= 0) {
+ if (dstp + 1 >= eob) {
+ goto cleanup;
+ }
+ *dstp++ = (l >> 8) | NS_CMPRSFLGS;
+ *dstp++ = l % 256;
+ return (dstp - dst);
+ }
+ /* Not found, save it. */
+ if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
+ (dstp - msg) < 0x4000 && first) {
+ *cpp++ = dstp;
+ *cpp = NULL;
+ first = 0;
+ }
+ }
+ /* copy label to buffer */
+ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ /* Should not happen. */
+ goto cleanup;
+ }
+ n = labellen(srcp);
+ if (dstp + 1 + n >= eob) {
+ goto cleanup;
+ }
+ memcpy(dstp, srcp, n + 1);
+ srcp += n + 1;
+ dstp += n + 1;
+ } while (n != 0);
+
+ if (dstp > eob) {
+cleanup:
+ if (msg != NULL)
+ *lpp = NULL;
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ return (dstp - dst);
+}
+
+/*
+ * ns_name_uncompress(msg, eom, src, dst, dstsiz)
+ * Expand compressed domain name to presentation format.
+ * return:
+ * Number of bytes read out of `src', or -1 (with errno set).
+ * note:
+ * Root domain returns as "." not "".
+ */
+int
+ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src,
+ char *dst, size_t dstsiz)
+{
+ u_char tmp[NS_MAXCDNAME];
+ int n;
+
+ if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
+ return (-1);
+ if (ns_name_ntop(tmp, dst, dstsiz) == -1)
+ return (-1);
+ return (n);
+}
+
+/*
+ * ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr)
+ * Compress a domain name into wire format, using compression pointers.
+ * return:
+ * Number of bytes consumed in `dst' or -1 (with errno set).
+ * notes:
+ * 'dnptrs' is an array of pointers to previous compressed names.
+ * dnptrs[0] is a pointer to the beginning of the message.
+ * The list ends with NULL. 'lastdnptr' is a pointer to the end of the
+ * array pointed to by 'dnptrs'. Side effect is to update the list of
+ * pointers for labels inserted into the message as we compress the name.
+ * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
+ * is NULL, we don't update the list.
+ */
+int
+ns_name_compress(const char *src, u_char *dst, size_t dstsiz,
+ const u_char **dnptrs, const u_char **lastdnptr)
+{
+ u_char tmp[NS_MAXCDNAME];
+
+ if (ns_name_pton(src, tmp, sizeof tmp) == -1)
+ return (-1);
+ return (ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr));
+}
+
+/*
+ * Reset dnptrs so that there are no active references to pointers at or
+ * after src.
+ */
+void
+ns_name_rollback(const u_char *src, const u_char **dnptrs,
+ const u_char **lastdnptr)
+{
+ while (dnptrs < lastdnptr && *dnptrs != NULL) {
+ if (*dnptrs >= src) {
+ *dnptrs = NULL;
+ break;
+ }
+ dnptrs++;
+ }
+}
+
+/*
+ * ns_name_skip(ptrptr, eom)
+ * Advance *ptrptr to skip over the compressed name it points at.
+ * return:
+ * 0 on success, -1 (with errno set) on failure.
+ */
+int
+ns_name_skip(const u_char **ptrptr, const u_char *eom)
+{
+ const u_char *cp;
+ u_int n;
+ int l;
+
+ cp = *ptrptr;
+ while (cp < eom && (n = *cp++) != 0) {
+ /* Check for indirection. */
+ switch (n & NS_CMPRSFLGS) {
+ case 0: /* normal case, n == len */
+ cp += n;
+ continue;
+ case NS_TYPE_ELT: /* EDNS0 extended label */
+ if ((l = labellen(cp - 1)) < 0) {
+ errno = EMSGSIZE; /* XXX */
+ return(-1);
+ }
+ cp += l;
+ continue;
+ case NS_CMPRSFLGS: /* indirection */
+ cp++;
+ break;
+ default: /* illegal type */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ break;
+ }
+ if (cp > eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *ptrptr = cp;
+ return (0);
+}
+
+/* Private. */
+
+/*
+ * special(ch)
+ * Thinking in noninternationalized USASCII (per the DNS spec),
+ * is this characted special ("in need of quoting") ?
+ * return:
+ * boolean.
+ */
+static int
+special(int ch) {
+ switch (ch) {
+ case 0x22: /* '"' */
+ case 0x2E: /* '.' */
+ case 0x3B: /* ';' */
+ case 0x5C: /* '\\' */
+ case 0x28: /* '(' */
+ case 0x29: /* ')' */
+ /* Special modifiers in zone files. */
+ case 0x40: /* '@' */
+ case 0x24: /* '$' */
+ return (1);
+ default:
+ return (0);
+ }
+}
+
+/*
+ * printable(ch)
+ * Thinking in noninternationalized USASCII (per the DNS spec),
+ * is this character visible and not a space when printed ?
+ * return:
+ * boolean.
+ */
+static int
+printable(int ch) {
+ return (ch > 0x20 && ch < 0x7f);
+}
+
+/*
+ * Thinking in noninternationalized USASCII (per the DNS spec),
+ * convert this character to lower case if it's upper case.
+ */
+static int
+mklower(int ch) {
+ if (ch >= 0x41 && ch <= 0x5A)
+ return (ch + 0x20);
+ return (ch);
+}
+
+/*
+ * dn_find(domain, msg, dnptrs, lastdnptr)
+ * Search for the counted-label name in an array of compressed names.
+ * return:
+ * offset from msg if found, or -1.
+ * notes:
+ * dnptrs is the pointer to the first name on the list,
+ * not the pointer to the start of the message.
+ */
+static int
+dn_find(const u_char *domain, const u_char *msg,
+ const u_char * const *dnptrs,
+ const u_char * const *lastdnptr)
+{
+ const u_char *dn, *cp, *sp;
+ const u_char * const *cpp;
+ u_int n;
+
+ for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
+ sp = *cpp;
+ /*
+ * terminate search on:
+ * root label
+ * compression pointer
+ * unusable offset
+ */
+ while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
+ (sp - msg) < 0x4000) {
+ dn = domain;
+ cp = sp;
+ while ((n = *cp++) != 0) {
+ /*
+ * check for indirection
+ */
+ switch (n & NS_CMPRSFLGS) {
+ case 0: /* normal case, n == len */
+ n = labellen(cp - 1); /* XXX */
+
+ if (n != *dn++)
+ goto next;
+
+ for ((void)NULL; n > 0; n--)
+ if (mklower(*dn++) !=
+ mklower(*cp++))
+ goto next;
+ /* Is next root for both ? */
+ if (*dn == '\0' && *cp == '\0')
+ return (sp - msg);
+ if (*dn)
+ continue;
+ goto next;
+ case NS_CMPRSFLGS: /* indirection */
+ cp = msg + (((n & 0x3f) << 8) | *cp);
+ break;
+
+ default: /* illegal type */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ }
+ next: ;
+ sp += *sp + 1;
+ }
+ }
+ errno = ENOENT;
+ return (-1);
+}
+
+static int
+decode_bitstring(const char **cpp, char *dn, const char *eom)
+{
+ const char *cp = *cpp;
+ char *beg = dn, tc;
+ int b, blen, plen;
+
+ if ((blen = (*cp & 0xff)) == 0)
+ blen = 256;
+ plen = (blen + 3) / 4;
+ plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1);
+ if (dn + plen >= eom)
+ return(-1);
+
+ cp++;
+ dn += SPRINTF((dn, "\\[x"));
+ for (b = blen; b > 7; b -= 8, cp++)
+ dn += SPRINTF((dn, "%02x", *cp & 0xff));
+ if (b > 4) {
+ tc = *cp++;
+ dn += SPRINTF((dn, "%02x", tc & (0xff << (8 - b))));
+ } else if (b > 0) {
+ tc = *cp++;
+ dn += SPRINTF((dn, "%1x",
+ ((tc >> 4) & 0x0f) & (0x0f << (4 - b))));
+ }
+ dn += SPRINTF((dn, "/%d]", blen));
+
+ *cpp = cp;
+ return(dn - beg);
+}
+
+static int
+encode_bitsring(const char **bp, const char *end, char **labelp,
+ char ** dst, const char *eom)
+{
+ int afterslash = 0;
+ const char *cp = *bp;
+ char *tp, c;
+ const char *beg_blen;
+ char *end_blen = NULL;
+ int value = 0, count = 0, tbcount = 0, blen = 0;
+
+ beg_blen = end_blen = NULL;
+
+ /* a bitstring must contain at least 2 characters */
+ if (end - cp < 2)
+ return(EINVAL);
+
+ /* XXX: currently, only hex strings are supported */
+ if (*cp++ != 'x')
+ return(EINVAL);
+ if (!isxdigit((*cp) & 0xff)) /* reject '\[x/BLEN]' */
+ return(EINVAL);
+
+ for (tp = *dst + 1; cp < end && tp < eom; cp++) {
+ switch((c = *cp)) {
+ case ']': /* end of the bitstring */
+ if (afterslash) {
+ if (beg_blen == NULL)
+ return(EINVAL);
+ blen = (int)strtol(beg_blen, &end_blen, 10);
+ if (*end_blen != ']')
+ return(EINVAL);
+ }
+ if (count)
+ *tp++ = ((value << 4) & 0xff);
+ cp++; /* skip ']' */
+ goto done;
+ case '/':
+ afterslash = 1;
+ break;
+ default:
+ if (afterslash) {
+ if (!isdigit(c&0xff))
+ return(EINVAL);
+ if (beg_blen == NULL) {
+
+ if (c == '0') {
+ /* blen never begings with 0 */
+ return(EINVAL);
+ }
+ beg_blen = cp;
+ }
+ } else {
+ if (!isxdigit(c&0xff))
+ return(EINVAL);
+ value <<= 4;
+ value += digitvalue[(int)c];
+ count += 4;
+ tbcount += 4;
+ if (tbcount > 256)
+ return(EINVAL);
+ if (count == 8) {
+ *tp++ = value;
+ count = 0;
+ }
+ }
+ break;
+ }
+ }
+ done:
+ if (cp >= end || tp >= eom)
+ return(EMSGSIZE);
+
+ /*
+ * bit length validation:
+ * If a <length> is present, the number of digits in the <bit-data>
+ * MUST be just sufficient to contain the number of bits specified
+ * by the <length>. If there are insignificant bits in a final
+ * hexadecimal or octal digit, they MUST be zero.
+ * RFC 2673, Section 3.2.
+ */
+ if (blen > 0) {
+ int traillen;
+
+ if (((blen + 3) & ~3) != tbcount)
+ return(EINVAL);
+ traillen = tbcount - blen; /* between 0 and 3 */
+ if (((value << (8 - traillen)) & 0xff) != 0)
+ return(EINVAL);
+ }
+ else
+ blen = tbcount;
+ if (blen == 256)
+ blen = 0;
+
+ /* encode the type and the significant bit fields */
+ **labelp = DNS_LABELTYPE_BITSTRING;
+ **dst = blen;
+
+ *bp = cp;
+ *dst = tp;
+
+ return(0);
+}
+
+static int
+labellen(const u_char *lp)
+{
+ int bitlen;
+ u_char l = *lp;
+
+ if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ /* should be avoided by the caller */
+ return(-1);
+ }
+
+ if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
+ if (l == DNS_LABELTYPE_BITSTRING) {
+ if ((bitlen = *(lp + 1)) == 0)
+ bitlen = 256;
+ return((bitlen + 7 ) / 8 + 1);
+ }
+ return(-1); /* unknwon ELT */
+ }
+ return(l);
+}
--- /dev/null
+/*
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#ifndef __APPLE__
+#ifndef lint
+static const char rcsid[] = "$Id: ns_netint.c,v 1.1 2006/03/01 19:01:37 majka Exp $";
+#endif
+#endif
+
+/* Import. */
+
+#ifndef __APPLE__
+#include "port_before.h"
+#endif
+
+#include <arpa/nameser.h>
+
+#ifndef __APPLE__
+#include "port_after.h"
+#endif
+
+/* Public. */
+
+u_int
+ns_get16(const u_char *src) {
+ u_int dst;
+
+ NS_GET16(dst, src);
+ return (dst);
+}
+
+u_long
+ns_get32(const u_char *src) {
+ u_long dst;
+
+ NS_GET32(dst, src);
+ return (dst);
+}
+
+void
+ns_put16(u_int src, u_char *dst) {
+ NS_PUT16(src, dst);
+}
+
+void
+ns_put32(u_long src, u_char *dst) {
+ NS_PUT32(src, dst);
+}
--- /dev/null
+/*
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#ifndef __APPLE__
+#ifndef lint
+static const char rcsid[] = "$Id: ns_parse.c,v 1.1 2006/03/01 19:01:37 majka Exp $";
+#endif
+#endif
+
+/* Import. */
+
+#ifndef __APPLE__
+#include "port_before.h"
+#endif
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <string.h>
+
+#ifndef __APPLE__
+#include "port_after.h"
+#endif
+
+/* Forward. */
+
+static void setsection(ns_msg *msg, ns_sect sect);
+
+/* Macros. */
+
+#define RETERR(err) do { errno = (err); return (-1); } while (0)
+
+/* Public. */
+
+/* These need to be in the same order as the nres.h:ns_flag enum. */
+struct _ns_flagdata _ns_flagdata[16] = {
+ { 0x8000, 15 }, /* qr. */
+ { 0x7800, 11 }, /* opcode. */
+ { 0x0400, 10 }, /* aa. */
+ { 0x0200, 9 }, /* tc. */
+ { 0x0100, 8 }, /* rd. */
+ { 0x0080, 7 }, /* ra. */
+ { 0x0040, 6 }, /* z. */
+ { 0x0020, 5 }, /* ad. */
+ { 0x0010, 4 }, /* cd. */
+ { 0x000f, 0 }, /* rcode. */
+ { 0x0000, 0 }, /* expansion (1/6). */
+ { 0x0000, 0 }, /* expansion (2/6). */
+ { 0x0000, 0 }, /* expansion (3/6). */
+ { 0x0000, 0 }, /* expansion (4/6). */
+ { 0x0000, 0 }, /* expansion (5/6). */
+ { 0x0000, 0 }, /* expansion (6/6). */
+};
+
+int ns_msg_getflag(ns_msg handle, int flag) {
+ return(((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift);
+}
+
+int
+ns_skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) {
+ const u_char *optr = ptr;
+
+ for ((void)NULL; count > 0; count--) {
+ int b, rdlength;
+
+ b = dn_skipname(ptr, eom);
+ if (b < 0)
+ RETERR(EMSGSIZE);
+ ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/;
+ if (section != ns_s_qd) {
+ if (ptr + NS_INT32SZ + NS_INT16SZ > eom)
+ RETERR(EMSGSIZE);
+ ptr += NS_INT32SZ/*TTL*/;
+ NS_GET16(rdlength, ptr);
+ ptr += rdlength/*RData*/;
+ }
+ }
+ if (ptr > eom)
+ RETERR(EMSGSIZE);
+ return (ptr - optr);
+}
+
+int
+ns_initparse(const u_char *msg, int msglen, ns_msg *handle) {
+ const u_char *eom = msg + msglen;
+ int i;
+
+ memset(handle, 0x5e, sizeof *handle);
+ handle->_msg = msg;
+ handle->_eom = eom;
+ if (msg + NS_INT16SZ > eom)
+ RETERR(EMSGSIZE);
+ NS_GET16(handle->_id, msg);
+ if (msg + NS_INT16SZ > eom)
+ RETERR(EMSGSIZE);
+ NS_GET16(handle->_flags, msg);
+ for (i = 0; i < ns_s_max; i++) {
+ if (msg + NS_INT16SZ > eom)
+ RETERR(EMSGSIZE);
+ NS_GET16(handle->_counts[i], msg);
+ }
+ for (i = 0; i < ns_s_max; i++)
+ if (handle->_counts[i] == 0)
+ handle->_sections[i] = NULL;
+ else {
+ int b = ns_skiprr(msg, eom, (ns_sect)i,
+ handle->_counts[i]);
+
+ if (b < 0)
+ return (-1);
+ handle->_sections[i] = msg;
+ msg += b;
+ }
+ if (msg != eom)
+ RETERR(EMSGSIZE);
+ setsection(handle, ns_s_max);
+ return (0);
+}
+
+int
+ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) {
+ int b;
+
+ /* Make section right. */
+ if (section >= ns_s_max)
+ RETERR(ENODEV);
+ if (section != handle->_sect)
+ setsection(handle, section);
+
+ /* Make rrnum right. */
+ if (rrnum == -1)
+ rrnum = handle->_rrnum;
+ if (rrnum < 0 || rrnum >= handle->_counts[(int)section])
+ RETERR(ENODEV);
+ if (rrnum < handle->_rrnum)
+ setsection(handle, section);
+ if (rrnum > handle->_rrnum) {
+ b = ns_skiprr(handle->_msg_ptr, handle->_eom, section,
+ rrnum - handle->_rrnum);
+
+ if (b < 0)
+ return (-1);
+ handle->_msg_ptr += b;
+ handle->_rrnum = rrnum;
+ }
+
+ /* Do the parse. */
+ b = dn_expand(handle->_msg, handle->_eom,
+ handle->_msg_ptr, rr->name, NS_MAXDNAME);
+ if (b < 0)
+ return (-1);
+ handle->_msg_ptr += b;
+ if (handle->_msg_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom)
+ RETERR(EMSGSIZE);
+ NS_GET16(rr->type, handle->_msg_ptr);
+ NS_GET16(rr->rr_class, handle->_msg_ptr);
+ if (section == ns_s_qd) {
+ rr->ttl = 0;
+ rr->rdlength = 0;
+ rr->rdata = NULL;
+ } else {
+ if (handle->_msg_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom)
+ RETERR(EMSGSIZE);
+ NS_GET32(rr->ttl, handle->_msg_ptr);
+ NS_GET16(rr->rdlength, handle->_msg_ptr);
+ if (handle->_msg_ptr + rr->rdlength > handle->_eom)
+ RETERR(EMSGSIZE);
+ rr->rdata = handle->_msg_ptr;
+ handle->_msg_ptr += rr->rdlength;
+ }
+ if (++handle->_rrnum > handle->_counts[(int)section])
+ setsection(handle, (ns_sect)((int)section + 1));
+
+ /* All done. */
+ return (0);
+}
+
+/* Private. */
+
+static void
+setsection(ns_msg *msg, ns_sect sect) {
+ msg->_sect = sect;
+ if (sect == ns_s_max) {
+ msg->_rrnum = -1;
+ msg->_msg_ptr = NULL;
+ } else {
+ msg->_rrnum = 0;
+ msg->_msg_ptr = msg->_sections[(int)sect];
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#ifndef __APPLE__
+#ifndef lint
+static const char rcsid[] = "$Id: ns_print.c,v 1.1 2006/03/01 19:01:37 majka Exp $";
+#endif
+#endif
+
+/* Import. */
+
+#ifndef __APPLE__
+#include "port_before.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef __APPLE__
+#include <isc/assertions.h>
+#include "port_after.h"
+#endif
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/* Forward. */
+
+static size_t prune_origin(const char *name, const char *origin);
+static int charstr(const u_char *rdata, const u_char *edata,
+ char **buf, size_t *buflen);
+static int addname(const u_char *msg, size_t msglen,
+ const u_char **p, const char *origin,
+ char **buf, size_t *buflen);
+static void addlen(size_t len, char **buf, size_t *buflen);
+static int addstr(const char *src, size_t len,
+ char **buf, size_t *buflen);
+static int addtab(size_t len, size_t target, int spaced,
+ char **buf, size_t *buflen);
+
+/* Proto. */
+
+#ifndef dst_s_dns_key_id
+#define dst_s_dns_key_id res_9_dst_s_dns_key_id
+#endif
+u_int16_t dst_s_dns_key_id(const u_char *, const int);
+
+/* Macros. */
+
+#define T(x) \
+ do { \
+ if ((x) < 0) \
+ return (-1); \
+ } while (0)
+
+/* Public. */
+
+/*
+ * int
+ * ns_sprintrr(handle, rr, name_ctx, origin, buf, buflen)
+ * Convert an RR to presentation format.
+ * return:
+ * Number of characters written to buf, or -1 (check errno).
+ */
+int
+ns_sprintrr(const ns_msg *handle, const ns_rr *rr,
+ const char *name_ctx, const char *origin,
+ char *buf, size_t buflen)
+{
+ int n;
+
+ n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle),
+ ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr),
+ ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr),
+ name_ctx, origin, buf, buflen);
+ return (n);
+}
+
+/*
+ * int
+ * ns_sprintrrf(msg, msglen, name, class, type, ttl, rdata, rdlen,
+ * name_ctx, origin, buf, buflen)
+ * Convert the fields of an RR into presentation format.
+ * return:
+ * Number of characters written to buf, or -1 (check errno).
+ */
+int
+ns_sprintrrf(const u_char *msg, size_t msglen,
+ const char *name, ns_class class, ns_type type,
+ u_long ttl, const u_char *rdata, size_t rdlen,
+ const char *name_ctx, const char *origin,
+ char *buf, size_t buflen)
+{
+ const char *obuf = buf;
+ const u_char *edata = rdata + rdlen;
+ int spaced = 0;
+
+ const char *comment;
+ char tmp[100];
+ int len, x;
+
+ /*
+ * Owner.
+ */
+ if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) {
+ T(addstr("\t\t\t", 3, &buf, &buflen));
+ } else {
+ len = prune_origin(name, origin);
+ if (*name == '\0') {
+ goto root;
+ } else if (len == 0) {
+ T(addstr("@\t\t\t", 4, &buf, &buflen));
+ } else {
+ T(addstr(name, len, &buf, &buflen));
+ /* Origin not used or not root, and no trailing dot? */
+ if (((origin == NULL || origin[0] == '\0') ||
+ (origin[0] != '.' && origin[1] != '\0' &&
+ name[len] == '\0')) && name[len - 1] != '.') {
+ root:
+ T(addstr(".", 1, &buf, &buflen));
+ len++;
+ }
+ T(spaced = addtab(len, 24, spaced, &buf, &buflen));
+ }
+ }
+
+ /*
+ * TTL, Class, Type.
+ */
+ T(x = ns_format_ttl(ttl, buf, buflen));
+ addlen(x, &buf, &buflen);
+ len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
+ T(addstr(tmp, len, &buf, &buflen));
+ if (rdlen == 0)
+ return (buf - obuf);
+ T(spaced = addtab(x + len, 16, spaced, &buf, &buflen));
+
+ /*
+ * RData.
+ */
+ switch (type) {
+ case ns_t_a:
+ if (rdlen != NS_INADDRSZ)
+ goto formerr;
+ (void) inet_ntop(AF_INET, rdata, buf, buflen);
+ addlen(strlen(buf), &buf, &buflen);
+ break;
+
+ case ns_t_cname:
+ case ns_t_mb:
+ case ns_t_mg:
+ case ns_t_mr:
+ case ns_t_ns:
+ case ns_t_ptr:
+ case ns_t_dname:
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ break;
+
+ case ns_t_hinfo:
+ case ns_t_isdn:
+ /* First word. */
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ T(addstr(" ", 1, &buf, &buflen));
+
+
+ /* Second word, optional in ISDN records. */
+ if (type == ns_t_isdn && rdata == edata)
+ break;
+
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ break;
+
+ case ns_t_soa: {
+ u_long t;
+
+ /* Server name. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Administrator name. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ T(addstr(" (\n", 3, &buf, &buflen));
+ spaced = 0;
+
+ if ((edata - rdata) != 5*NS_INT32SZ)
+ goto formerr;
+
+ /* Serial number. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+ len = SPRINTF((tmp, "%lu", t));
+ T(addstr(tmp, len, &buf, &buflen));
+ T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+ T(addstr("; serial\n", 9, &buf, &buflen));
+ spaced = 0;
+
+ /* Refresh interval. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+ T(len = ns_format_ttl(t, buf, buflen));
+ addlen(len, &buf, &buflen);
+ T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+ T(addstr("; refresh\n", 10, &buf, &buflen));
+ spaced = 0;
+
+ /* Retry interval. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+ T(len = ns_format_ttl(t, buf, buflen));
+ addlen(len, &buf, &buflen);
+ T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+ T(addstr("; retry\n", 8, &buf, &buflen));
+ spaced = 0;
+
+ /* Expiry. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+ T(len = ns_format_ttl(t, buf, buflen));
+ addlen(len, &buf, &buflen);
+ T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+ T(addstr("; expiry\n", 9, &buf, &buflen));
+ spaced = 0;
+
+ /* Minimum TTL. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+ T(len = ns_format_ttl(t, buf, buflen));
+ addlen(len, &buf, &buflen);
+ T(addstr(" )", 2, &buf, &buflen));
+ T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+ T(addstr("; minimum\n", 10, &buf, &buflen));
+
+ break;
+ }
+
+ case ns_t_mx:
+ case ns_t_afsdb:
+ case ns_t_rt: {
+ u_int t;
+
+ if (rdlen < NS_INT16SZ)
+ goto formerr;
+
+ /* Priority. */
+ t = ns_get16(rdata);
+ rdata += NS_INT16SZ;
+ len = SPRINTF((tmp, "%u ", t));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Target. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ break;
+ }
+
+ case ns_t_px: {
+ u_int t;
+
+ if (rdlen < NS_INT16SZ)
+ goto formerr;
+
+ /* Priority. */
+ t = ns_get16(rdata);
+ rdata += NS_INT16SZ;
+ len = SPRINTF((tmp, "%u ", t));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Name1. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Name2. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ break;
+ }
+
+ case ns_t_x25:
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ break;
+
+ case ns_t_txt:
+ while (rdata < edata) {
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ if (rdata < edata)
+ T(addstr(" ", 1, &buf, &buflen));
+ }
+ break;
+
+ case ns_t_nsap: {
+ char t[2+255*3];
+
+ (void) inet_nsap_ntoa(rdlen, rdata, t);
+ T(addstr(t, strlen(t), &buf, &buflen));
+ break;
+ }
+
+ case ns_t_aaaa:
+ if (rdlen != NS_IN6ADDRSZ)
+ goto formerr;
+ (void) inet_ntop(AF_INET6, rdata, buf, buflen);
+ addlen(strlen(buf), &buf, &buflen);
+ break;
+
+ case ns_t_loc: {
+ char t[255];
+
+ /* XXX protocol format checking? */
+ (void) loc_ntoa(rdata, t);
+ T(addstr(t, strlen(t), &buf, &buflen));
+ break;
+ }
+
+ case ns_t_naptr: {
+ u_int order, preference;
+ char t[50];
+
+ if (rdlen < 2*NS_INT16SZ)
+ goto formerr;
+
+ /* Order, Precedence. */
+ order = ns_get16(rdata); rdata += NS_INT16SZ;
+ preference = ns_get16(rdata); rdata += NS_INT16SZ;
+ len = SPRINTF((t, "%u %u ", order, preference));
+ T(addstr(t, len, &buf, &buflen));
+
+ /* Flags. */
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Service. */
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Regexp. */
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len < 0)
+ return (-1);
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Server. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ break;
+ }
+
+ case ns_t_srv: {
+ u_int priority, weight, port;
+ char t[50];
+
+ if (rdlen < NS_INT16SZ*3)
+ goto formerr;
+
+ /* Priority, Weight, Port. */
+ priority = ns_get16(rdata); rdata += NS_INT16SZ;
+ weight = ns_get16(rdata); rdata += NS_INT16SZ;
+ port = ns_get16(rdata); rdata += NS_INT16SZ;
+ len = SPRINTF((t, "%u %u %u ", priority, weight, port));
+ T(addstr(t, len, &buf, &buflen));
+
+ /* Server. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ break;
+ }
+
+ case ns_t_minfo:
+ case ns_t_rp:
+ /* Name1. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Name2. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ break;
+
+ case ns_t_wks: {
+ int n, lcnt;
+
+ if (rdlen < NS_INT32SZ + 1)
+ goto formerr;
+
+ /* Address. */
+ (void) inet_ntop(AF_INET, rdata, buf, buflen);
+ addlen(strlen(buf), &buf, &buflen);
+ rdata += NS_INADDRSZ;
+
+ /* Protocol. */
+ len = SPRINTF((tmp, " %u ( ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata += NS_INT8SZ;
+
+ /* Bit map. */
+ n = 0;
+ lcnt = 0;
+ while (rdata < edata) {
+ u_int c = *rdata++;
+ do {
+ if (c & 0200) {
+ if (lcnt == 0) {
+ T(addstr("\n\t\t\t\t", 5,
+ &buf, &buflen));
+ lcnt = 10;
+ spaced = 0;
+ }
+ len = SPRINTF((tmp, "%d ", n));
+ T(addstr(tmp, len, &buf, &buflen));
+ lcnt--;
+ }
+ c <<= 1;
+ } while (++n & 07);
+ }
+ T(addstr(")", 1, &buf, &buflen));
+
+ break;
+ }
+
+ case ns_t_key: {
+ char base64_key[NS_MD5RSA_MAX_BASE64];
+ u_int keyflags, protocol, algorithm, key_id;
+ const char *leader;
+ int n;
+
+ if (rdlen < NS_INT16SZ + NS_INT8SZ + NS_INT8SZ)
+ goto formerr;
+
+ /* Key flags, Protocol, Algorithm. */
+ key_id = dst_s_dns_key_id(rdata, edata-rdata);
+ keyflags = ns_get16(rdata); rdata += NS_INT16SZ;
+ protocol = *rdata++;
+ algorithm = *rdata++;
+ len = SPRINTF((tmp, "0x%04x %u %u",
+ keyflags, protocol, algorithm));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Public key data. */
+ len = b64_ntop(rdata, edata - rdata,
+ base64_key, sizeof base64_key);
+ if (len < 0)
+ goto formerr;
+ if (len > 15) {
+ T(addstr(" (", 2, &buf, &buflen));
+ leader = "\n\t\t";
+ spaced = 0;
+ } else
+ leader = " ";
+ for (n = 0; n < len; n += 48) {
+ T(addstr(leader, strlen(leader), &buf, &buflen));
+ T(addstr(base64_key + n, MIN(len - n, 48),
+ &buf, &buflen));
+ }
+ if (len > 15)
+ T(addstr(" )", 2, &buf, &buflen));
+ n = SPRINTF((tmp, " ; key_tag= %u", key_id));
+ T(addstr(tmp, n, &buf, &buflen));
+
+ break;
+ }
+
+ case ns_t_sig: {
+ char base64_key[NS_MD5RSA_MAX_BASE64];
+ u_int type, algorithm, labels, footprint;
+ const char *leader;
+ u_long t;
+ int n;
+
+ if (rdlen < 22)
+ goto formerr;
+
+ /* Type covered, Algorithm, Label count, Original TTL. */
+ type = ns_get16(rdata); rdata += NS_INT16SZ;
+ algorithm = *rdata++;
+ labels = *rdata++;
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ len = SPRINTF((tmp, "%s %d %d %lu ",
+ p_type(type), algorithm, labels, t));
+ T(addstr(tmp, len, &buf, &buflen));
+ if (labels > (u_int)dn_count_labels(name))
+ goto formerr;
+
+ /* Signature expiry. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ len = SPRINTF((tmp, "%s ", p_secstodate(t)));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Time signed. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ len = SPRINTF((tmp, "%s ", p_secstodate(t)));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Signature Footprint. */
+ footprint = ns_get16(rdata); rdata += NS_INT16SZ;
+ len = SPRINTF((tmp, "%u ", footprint));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Signer's name. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ /* Signature. */
+ len = b64_ntop(rdata, edata - rdata,
+ base64_key, sizeof base64_key);
+ if (len > 15) {
+ T(addstr(" (", 2, &buf, &buflen));
+ leader = "\n\t\t";
+ spaced = 0;
+ } else
+ leader = " ";
+ if (len < 0)
+ goto formerr;
+ for (n = 0; n < len; n += 48) {
+ T(addstr(leader, strlen(leader), &buf, &buflen));
+ T(addstr(base64_key + n, MIN(len - n, 48),
+ &buf, &buflen));
+ }
+ if (len > 15)
+ T(addstr(" )", 2, &buf, &buflen));
+ break;
+ }
+
+ case ns_t_nxt: {
+ int n, c;
+
+ /* Next domain name. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ /* Type bit map. */
+ n = edata - rdata;
+ for (c = 0; c < n*8; c++)
+ if (NS_NXT_BIT_ISSET(c, rdata)) {
+ len = SPRINTF((tmp, " %s", p_type(c)));
+ T(addstr(tmp, len, &buf, &buflen));
+ }
+ break;
+ }
+
+ case ns_t_cert: {
+ u_int c_type, key_tag, alg;
+ int n;
+ unsigned int siz;
+ char base64_cert[8192], tmp[40];
+ const char *leader;
+
+ c_type = ns_get16(rdata); rdata += NS_INT16SZ;
+ key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
+ alg = (u_int) *rdata++;
+
+ len = SPRINTF((tmp, "%d %d %d ", c_type, key_tag, alg));
+ T(addstr(tmp, len, &buf, &buflen));
+ siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
+ if (siz > sizeof(base64_cert) * 3/4) {
+ const char *str = "record too long to print";
+ T(addstr(str, strlen(str), &buf, &buflen));
+ }
+ else {
+ len = b64_ntop(rdata, edata-rdata, base64_cert, siz);
+
+ if (len < 0)
+ goto formerr;
+ else if (len > 15) {
+ T(addstr(" (", 2, &buf, &buflen));
+ leader = "\n\t\t";
+ spaced = 0;
+ }
+ else
+ leader = " ";
+
+ for (n = 0; n < len; n += 48) {
+ T(addstr(leader, strlen(leader),
+ &buf, &buflen));
+ T(addstr(base64_cert + n, MIN(len - n, 48),
+ &buf, &buflen));
+ }
+ if (len > 15)
+ T(addstr(" )", 2, &buf, &buflen));
+ }
+ break;
+ }
+
+ case ns_t_tkey: {
+ /* KJD - need to complete this */
+ u_long t;
+ int mode, err, keysize;
+
+ /* Algorithm name. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Inception. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ len = SPRINTF((tmp, "%s ", p_secstodate(t)));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Experation. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ len = SPRINTF((tmp, "%s ", p_secstodate(t)));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Mode , Error, Key Size. */
+ /* Priority, Weight, Port. */
+ mode = ns_get16(rdata); rdata += NS_INT16SZ;
+ err = ns_get16(rdata); rdata += NS_INT16SZ;
+ keysize = ns_get16(rdata); rdata += NS_INT16SZ;
+ len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* needs to dump key, print otherdata length & other data */
+ break;
+ }
+ case ns_t_tsig: {
+ /* BEW - need to complete this */
+ int n;
+
+ T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ T(addstr(" ", 1, &buf, &buflen));
+ rdata += 8; /* time */
+ n = ns_get16(rdata); rdata += NS_INT16SZ;
+ rdata += n; /* sig */
+ n = ns_get16(rdata); rdata += NS_INT16SZ; /* original id */
+ sprintf(buf, "%d", ns_get16(rdata));
+ rdata += NS_INT16SZ;
+ addlen(strlen(buf), &buf, &buflen);
+ break;
+ }
+
+ case ns_t_a6: {
+ struct in6_addr a;
+ int pbyte, pbit;
+
+ /* prefix length */
+ if (rdlen == 0) goto formerr;
+ len = SPRINTF((tmp, "%d ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ pbit = *rdata;
+ if (pbit > 128) goto formerr;
+ pbyte = (pbit & ~7) / 8;
+ rdata++;
+
+ /* address suffix: provided only when prefix len != 128 */
+ if (pbit < 128) {
+ if (rdata + pbyte >= edata) goto formerr;
+ memset(&a, 0, sizeof(a));
+ memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
+ (void) inet_ntop(AF_INET6, &a, buf, buflen);
+ addlen(strlen(buf), &buf, &buflen);
+ rdata += sizeof(a) - pbyte;
+ }
+
+ /* prefix name: provided only when prefix len > 0 */
+ if (pbit == 0)
+ break;
+ if (rdata >= edata) goto formerr;
+ T(addstr(" ", 1, &buf, &buflen));
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ break;
+ }
+
+ case ns_t_opt: {
+ len = SPRINTF((tmp, "%u bytes", class));
+ T(addstr(tmp, len, &buf, &buflen));
+ break;
+ }
+
+ default:
+ comment = "unknown RR type";
+ goto hexify;
+ }
+ return (buf - obuf);
+ formerr:
+ comment = "RR format error";
+ hexify: {
+ int n, m;
+ char *p;
+
+ len = SPRINTF((tmp, "\\# %u (\t; %s", edata - rdata, comment));
+ T(addstr(tmp, len, &buf, &buflen));
+ while (rdata < edata) {
+ p = tmp;
+ p += SPRINTF((p, "\n\t"));
+ spaced = 0;
+ n = MIN(16, edata - rdata);
+ for (m = 0; m < n; m++)
+ p += SPRINTF((p, "%02x ", rdata[m]));
+ T(addstr(tmp, p - tmp, &buf, &buflen));
+ if (n < 16) {
+ T(addstr(")", 1, &buf, &buflen));
+ T(addtab(p - tmp + 1, 48, spaced, &buf, &buflen));
+ }
+ p = tmp;
+ p += SPRINTF((p, "; "));
+ for (m = 0; m < n; m++)
+ *p++ = (isascii(rdata[m]) && isprint(rdata[m]))
+ ? rdata[m]
+ : '.';
+ T(addstr(tmp, p - tmp, &buf, &buflen));
+ rdata += n;
+ }
+ return (buf - obuf);
+ }
+}
+
+/* Private. */
+
+/*
+ * size_t
+ * prune_origin(name, origin)
+ * Find out if the name is at or under the current origin.
+ * return:
+ * Number of characters in name before start of origin,
+ * or length of name if origin does not match.
+ * notes:
+ * This function should share code with samedomain().
+ */
+static size_t
+prune_origin(const char *name, const char *origin) {
+ const char *oname = name;
+
+ while (*name != '\0') {
+ if (origin != NULL && ns_samename(name, origin) == 1)
+ return (name - oname - (name > oname));
+ while (*name != '\0') {
+ if (*name == '\\') {
+ name++;
+ /* XXX need to handle \nnn form. */
+ if (*name == '\0')
+ break;
+ } else if (*name == '.') {
+ name++;
+ break;
+ }
+ name++;
+ }
+ }
+ return (name - oname);
+}
+
+/*
+ * int
+ * charstr(rdata, edata, buf, buflen)
+ * Format a <character-string> into the presentation buffer.
+ * return:
+ * Number of rdata octets consumed
+ * 0 for protocol format error
+ * -1 for output buffer error
+ * side effects:
+ * buffer is advanced on success.
+ */
+static int
+charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
+ const u_char *odata = rdata;
+ size_t save_buflen = *buflen;
+ char *save_buf = *buf;
+
+ if (addstr("\"", 1, buf, buflen) < 0)
+ goto enospc;
+ if (rdata < edata) {
+ int n = *rdata;
+
+ if (rdata + 1 + n <= edata) {
+ rdata++;
+ while (n-- > 0) {
+ if (strchr("\n\"\\", *rdata) != NULL)
+ if (addstr("\\", 1, buf, buflen) < 0)
+ goto enospc;
+ if (addstr((const char *)rdata, 1,
+ buf, buflen) < 0)
+ goto enospc;
+ rdata++;
+ }
+ }
+ }
+ if (addstr("\"", 1, buf, buflen) < 0)
+ goto enospc;
+ return (rdata - odata);
+ enospc:
+ errno = ENOSPC;
+ *buf = save_buf;
+ *buflen = save_buflen;
+ return (-1);
+}
+
+static int
+addname(const u_char *msg, size_t msglen,
+ const u_char **pp, const char *origin,
+ char **buf, size_t *buflen)
+{
+ size_t newlen, save_buflen = *buflen;
+ char *save_buf = *buf;
+ int n;
+
+ n = dn_expand(msg, msg + msglen, *pp, *buf, *buflen);
+ if (n < 0)
+ goto enospc; /* Guess. */
+ newlen = prune_origin(*buf, origin);
+ if (**buf == '\0') {
+ goto root;
+ } else if (newlen == 0) {
+ /* Use "@" instead of name. */
+ if (newlen + 2 > *buflen)
+ goto enospc; /* No room for "@\0". */
+ (*buf)[newlen++] = '@';
+ (*buf)[newlen] = '\0';
+ } else {
+ if (((origin == NULL || origin[0] == '\0') ||
+ (origin[0] != '.' && origin[1] != '\0' &&
+ (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') {
+ /* No trailing dot. */
+ root:
+ if (newlen + 2 > *buflen)
+ goto enospc; /* No room for ".\0". */
+ (*buf)[newlen++] = '.';
+ (*buf)[newlen] = '\0';
+ }
+ }
+ *pp += n;
+ addlen(newlen, buf, buflen);
+ **buf = '\0';
+ return (newlen);
+ enospc:
+ errno = ENOSPC;
+ *buf = save_buf;
+ *buflen = save_buflen;
+ return (-1);
+}
+
+static void
+addlen(size_t len, char **buf, size_t *buflen) {
+#ifdef __APPLE__
+ if (len > *buflen) return;
+#else
+ INSIST(len <= *buflen);
+#endif
+ *buf += len;
+ *buflen -= len;
+}
+
+static int
+addstr(const char *src, size_t len, char **buf, size_t *buflen) {
+ if (len >= *buflen) {
+ errno = ENOSPC;
+ return (-1);
+ }
+ memcpy(*buf, src, len);
+ addlen(len, buf, buflen);
+ **buf = '\0';
+ return (0);
+}
+
+static int
+addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
+ size_t save_buflen = *buflen;
+ char *save_buf = *buf;
+ int t;
+
+ if (spaced || len >= target - 1) {
+ T(addstr(" ", 2, buf, buflen));
+ spaced = 1;
+ } else {
+ for (t = (target - len - 1) / 8; t >= 0; t--)
+ if (addstr("\t", 1, buf, buflen) < 0) {
+ *buflen = save_buflen;
+ *buf = save_buf;
+ return (-1);
+ }
+ spaced = 0;
+ }
+ return (spaced);
+}
--- /dev/null
+/*
+ * Copyright (c) 1995,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#ifndef __APPLE__
+#ifndef lint
+static const char rcsid[] = "$Id: ns_samedomain.c,v 1.1 2006/03/01 19:01:37 majka Exp $";
+#endif
+#endif
+
+#ifndef __APPLE__
+#include "port_before.h"
+#endif
+
+#include <sys/types.h>
+#include <arpa/nameser.h>
+#include <errno.h>
+#include <string.h>
+
+#ifndef __APPLE__
+#include "port_after.h"
+#endif
+
+/*
+ * int
+ * ns_samedomain(a, b)
+ * Check whether a name belongs to a domain.
+ * Inputs:
+ * a - the domain whose ancestory is being verified
+ * b - the potential ancestor we're checking against
+ * Return:
+ * boolean - is a at or below b?
+ * Notes:
+ * Trailing dots are first removed from name and domain.
+ * Always compare complete subdomains, not only whether the
+ * domain name is the trailing string of the given name.
+ *
+ * "host.foobar.top" lies in "foobar.top" and in "top" and in ""
+ * but NOT in "bar.top"
+ */
+
+int
+ns_samedomain(const char *a, const char *b) {
+ size_t la, lb;
+ int diff, i, escaped;
+ const char *cp;
+
+ la = strlen(a);
+ lb = strlen(b);
+
+ /* Ignore a trailing label separator (i.e. an unescaped dot) in 'a'. */
+ if (la != 0 && a[la - 1] == '.') {
+ escaped = 0;
+ /* Note this loop doesn't get executed if la==1. */
+ for (i = la - 2; i >= 0; i--)
+ if (a[i] == '\\') {
+ if (escaped)
+ escaped = 0;
+ else
+ escaped = 1;
+ } else
+ break;
+ if (!escaped)
+ la--;
+ }
+
+ /* Ignore a trailing label separator (i.e. an unescaped dot) in 'b'. */
+ if (lb != 0 && b[lb - 1] == '.') {
+ escaped = 0;
+ /* note this loop doesn't get executed if lb==1 */
+ for (i = lb - 2; i >= 0; i--)
+ if (b[i] == '\\') {
+ if (escaped)
+ escaped = 0;
+ else
+ escaped = 1;
+ } else
+ break;
+ if (!escaped)
+ lb--;
+ }
+
+ /* lb == 0 means 'b' is the root domain, so 'a' must be in 'b'. */
+ if (lb == 0)
+ return (1);
+
+ /* 'b' longer than 'a' means 'a' can't be in 'b'. */
+ if (lb > la)
+ return (0);
+
+ /* 'a' and 'b' being equal at this point indicates sameness. */
+ if (lb == la)
+ return (strncasecmp(a, b, lb) == 0);
+
+ /* Ok, we know la > lb. */
+
+ diff = la - lb;
+
+ /*
+ * If 'a' is only 1 character longer than 'b', then it can't be
+ * a subdomain of 'b' (because of the need for the '.' label
+ * separator).
+ */
+ if (diff < 2)
+ return (0);
+
+ /*
+ * If the character before the last 'lb' characters of 'b'
+ * isn't '.', then it can't be a match (this lets us avoid
+ * having "foobar.com" match "bar.com").
+ */
+ if (a[diff - 1] != '.')
+ return (0);
+
+ /*
+ * We're not sure about that '.', however. It could be escaped
+ * and thus not a really a label separator.
+ */
+ escaped = 0;
+ for (i = diff - 2; i >= 0; i--)
+ if (a[i] == '\\') {
+ if (escaped)
+ escaped = 0;
+ else
+ escaped = 1;
+ } else
+ break;
+ if (escaped)
+ return (0);
+
+ /* Now compare aligned trailing substring. */
+ cp = a + diff;
+ return (strncasecmp(cp, b, lb) == 0);
+}
+
+/*
+ * int
+ * ns_subdomain(a, b)
+ * is "a" a subdomain of "b"?
+ */
+int
+ns_subdomain(const char *a, const char *b) {
+ return (ns_samename(a, b) != 1 && ns_samedomain(a, b));
+}
+
+/*
+ * int
+ * ns_makecanon(src, dst, dstsize)
+ * make a canonical copy of domain name "src"
+ * notes:
+ * foo -> foo.
+ * foo. -> foo.
+ * foo.. -> foo.
+ * foo\. -> foo\..
+ * foo\\. -> foo\\.
+ */
+
+int
+ns_makecanon(const char *src, char *dst, size_t dstsize) {
+ size_t n = strlen(src);
+
+ if (n + sizeof "." > dstsize) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ strcpy(dst, src);
+ while (n > 0 && dst[n - 1] == '.') /* Ends in "." */
+ if (n > 1 && dst[n - 2] == '\\' && /* Ends in "\." */
+ (n < 2 || dst[n - 3] != '\\')) /* But not "\\." */
+ break;
+ else
+ dst[--n] = '\0';
+ dst[n++] = '.';
+ dst[n] = '\0';
+ return (0);
+}
+
+/*
+ * int
+ * ns_samename(a, b)
+ * determine whether domain name "a" is the same as domain name "b"
+ * return:
+ * -1 on error
+ * 0 if names differ
+ * 1 if names are the same
+ */
+
+int
+ns_samename(const char *a, const char *b) {
+ char ta[NS_MAXDNAME], tb[NS_MAXDNAME];
+
+ if (ns_makecanon(a, ta, sizeof ta) < 0 ||
+ ns_makecanon(b, tb, sizeof tb) < 0)
+ return (-1);
+ if (strcasecmp(ta, tb) == 0)
+ return (1);
+ else
+ return (0);
+}
--- /dev/null
+/*
+ * Copyright (c) 1999 by Internet Software Consortium, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#ifndef __APPLE__
+#ifndef lint
+static const char rcsid[] = "$Id: ns_sign.c,v 1.1 2006/03/01 19:01:37 majka Exp $";
+#endif
+#endif
+
+/* Import. */
+
+#ifndef __APPLE__
+#include "port_before.h"
+#include "fd_setsize.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#ifndef __APPLE__
+#include <isc/dst.h>
+#include "port_after.h"
+#else
+#include "dst_internal.h"
+#include "res_private.h"
+#endif
+
+#define BOUNDS_CHECK(ptr, count) \
+ do { \
+ if ((ptr) + (count) > eob) { \
+ errno = EMSGSIZE; \
+ return(NS_TSIG_ERROR_NO_SPACE); \
+ } \
+ } while (0)
+
+/* ns_sign
+ * Parameters:
+ * msg message to be sent
+ * msglen input - length of message
+ * output - length of signed message
+ * msgsize length of buffer containing message
+ * error value to put in the error field
+ * key tsig key used for signing
+ * querysig (response), the signature in the query
+ * querysiglen (response), the length of the signature in the query
+ * sig a buffer to hold the generated signature
+ * siglen input - length of signature buffer
+ * output - length of signature
+ *
+ * Errors:
+ * - bad input data (-1)
+ * - bad key / sign failed (-BADKEY)
+ * - not enough space (NS_TSIG_ERROR_NO_SPACE)
+ */
+int
+ns_sign(u_char *msg, int *msglen, int msgsize, int error, void *k,
+ const u_char *querysig, int querysiglen, u_char *sig, int *siglen,
+ time_t in_timesigned)
+{
+ return(ns_sign2(msg, msglen, msgsize, error, k,
+ querysig, querysiglen, sig, siglen,
+ in_timesigned, NULL, NULL));
+}
+
+int
+ns_sign2(u_char *msg, int *msglen, int msgsize, int error, void *k,
+ const u_char *querysig, int querysiglen, u_char *sig, int *siglen,
+ time_t in_timesigned, u_char **dnptrs, u_char **lastdnptr)
+{
+ HEADER *hp = (HEADER *)msg;
+ DST_KEY *key = (DST_KEY *)k;
+ u_char *cp = msg + *msglen, *eob = msg + msgsize;
+ u_char *lenp;
+ u_char *name, *alg;
+ int n;
+ time_t timesigned;
+
+ dst_init();
+ if (msg == NULL || msglen == NULL || sig == NULL || siglen == NULL)
+ return (-1);
+
+ /* Name. */
+ if (key != NULL && error != ns_r_badsig && error != ns_r_badkey)
+ n = dn_comp(key->dk_key_name, cp, eob - cp, dnptrs, lastdnptr);
+ else
+ n = dn_comp("", cp, eob - cp, NULL, NULL);
+ if (n < 0)
+ return (NS_TSIG_ERROR_NO_SPACE);
+ name = cp;
+ cp += n;
+
+ /* Type, class, ttl, length (not filled in yet). */
+ BOUNDS_CHECK(cp, NS_INT16SZ + NS_INT16SZ + NS_INT32SZ + NS_INT16SZ);
+ NS_PUT16(ns_t_tsig, cp);
+ NS_PUT16(ns_c_any, cp);
+ NS_PUT32(0, cp); /* TTL */
+ lenp = cp;
+ cp += 2;
+
+ /* Alg. */
+ if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
+ if (key->dk_alg != KEY_HMAC_MD5)
+ return (-ns_r_badkey);
+ n = dn_comp(NS_TSIG_ALG_HMAC_MD5, cp, eob - cp, NULL, NULL);
+ }
+ else
+ n = dn_comp("", cp, eob - cp, NULL, NULL);
+ if (n < 0)
+ return (NS_TSIG_ERROR_NO_SPACE);
+ alg = cp;
+ cp += n;
+
+ /* Time. */
+ BOUNDS_CHECK(cp, NS_INT16SZ + NS_INT32SZ + NS_INT16SZ);
+ NS_PUT16(0, cp);
+ timesigned = time(NULL);
+ if (error != ns_r_badtime)
+ NS_PUT32(timesigned, cp);
+ else
+ NS_PUT32(in_timesigned, cp);
+ NS_PUT16(NS_TSIG_FUDGE, cp);
+
+ /* Compute the signature. */
+ if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
+ void *ctx;
+ u_char buf[NS_MAXDNAME], *cp2;
+ int n;
+
+ dst_sign_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0);
+
+ /* Digest the query signature, if this is a response. */
+ if (querysiglen > 0 && querysig != NULL) {
+ u_int16_t len_n = htons(querysiglen);
+ dst_sign_data(SIG_MODE_UPDATE, key, &ctx,
+ (u_char *)&len_n, NS_INT16SZ, NULL, 0);
+ dst_sign_data(SIG_MODE_UPDATE, key, &ctx,
+ querysig, querysiglen, NULL, 0);
+ }
+
+ /* Digest the message. */
+ dst_sign_data(SIG_MODE_UPDATE, key, &ctx, msg, *msglen,
+ NULL, 0);
+
+ /* Digest the key name. */
+ n = ns_name_ntol(name, buf, sizeof(buf));
+ dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
+
+ /* Digest the class and TTL. */
+ cp2 = buf;
+ NS_PUT16(ns_c_any, cp2);
+ NS_PUT32(0, cp2);
+ dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, cp2-buf,
+ NULL, 0);
+
+ /* Digest the algorithm. */
+ n = ns_name_ntol(alg, buf, sizeof(buf));
+ dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
+
+ /* Digest the time signed, fudge, error, and other data */
+ cp2 = buf;
+ NS_PUT16(0, cp2); /* Top 16 bits of time */
+ if (error != ns_r_badtime)
+ NS_PUT32(timesigned, cp2);
+ else
+ NS_PUT32(in_timesigned, cp2);
+ NS_PUT16(NS_TSIG_FUDGE, cp2);
+ NS_PUT16(error, cp2); /* Error */
+ if (error != ns_r_badtime)
+ NS_PUT16(0, cp2); /* Other data length */
+ else {
+ NS_PUT16(NS_INT16SZ+NS_INT32SZ, cp2); /* Other data length */
+ NS_PUT16(0, cp2); /* Top 16 bits of time */
+ NS_PUT32(timesigned, cp2);
+ }
+ dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, cp2-buf,
+ NULL, 0);
+
+ n = dst_sign_data(SIG_MODE_FINAL, key, &ctx, NULL, 0,
+ sig, *siglen);
+ if (n < 0)
+ return (-ns_r_badkey);
+ *siglen = n;
+ } else
+ *siglen = 0;
+
+ /* Add the signature. */
+ BOUNDS_CHECK(cp, NS_INT16SZ + (*siglen));
+ NS_PUT16(*siglen, cp);
+ memcpy(cp, sig, *siglen);
+ cp += (*siglen);
+
+ /* The original message ID & error. */
+ BOUNDS_CHECK(cp, NS_INT16SZ + NS_INT16SZ);
+ NS_PUT16(ntohs(hp->id), cp); /* already in network order */
+ NS_PUT16(error, cp);
+
+ /* Other data. */
+ BOUNDS_CHECK(cp, NS_INT16SZ);
+ if (error != ns_r_badtime)
+ NS_PUT16(0, cp); /* Other data length */
+ else {
+ NS_PUT16(NS_INT16SZ+NS_INT32SZ, cp); /* Other data length */
+ BOUNDS_CHECK(cp, NS_INT32SZ+NS_INT16SZ);
+ NS_PUT16(0, cp); /* Top 16 bits of time */
+ NS_PUT32(timesigned, cp);
+ }
+
+ /* Go back and fill in the length. */
+ NS_PUT16(cp - lenp - NS_INT16SZ, lenp);
+
+ hp->arcount = htons(ntohs(hp->arcount) + 1);
+ *msglen = (cp - msg);
+ return (0);
+}
+
+int
+ns_sign_tcp_init(void *k, const u_char *querysig, int querysiglen,
+ ns_tcp_tsig_state *state)
+{
+ dst_init();
+ if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0)
+ return (-1);
+ state->counter = -1;
+ state->key = k;
+ if (state->key->dk_alg != KEY_HMAC_MD5)
+ return (-ns_r_badkey);
+ if (querysiglen > (int)sizeof(state->sig))
+ return (-1);
+ memcpy(state->sig, querysig, querysiglen);
+ state->siglen = querysiglen;
+ return (0);
+}
+
+int
+ns_sign_tcp(u_char *msg, int *msglen, int msgsize, int error,
+ ns_tcp_tsig_state *state, int done)
+{
+ return (ns_sign_tcp2(msg, msglen, msgsize, error, state,
+ done, NULL, NULL));
+}
+
+int
+ns_sign_tcp2(u_char *msg, int *msglen, int msgsize, int error,
+ ns_tcp_tsig_state *state, int done,
+ u_char **dnptrs, u_char **lastdnptr)
+{
+ u_char *cp, *eob, *lenp;
+ u_char buf[NS_MAXDNAME], *cp2;
+ HEADER *hp = (HEADER *)msg;
+ time_t timesigned;
+ int n;
+
+ if (msg == NULL || msglen == NULL || state == NULL)
+ return (-1);
+
+ state->counter++;
+ if (state->counter == 0)
+ return (ns_sign2(msg, msglen, msgsize, error, state->key,
+ state->sig, state->siglen,
+ state->sig, &state->siglen, 0,
+ dnptrs, lastdnptr));
+
+ if (state->siglen > 0) {
+ u_int16_t siglen_n = htons(state->siglen);
+ dst_sign_data(SIG_MODE_INIT, state->key, &state->ctx,
+ NULL, 0, NULL, 0);
+ dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+ (u_char *)&siglen_n, NS_INT16SZ, NULL, 0);
+ dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+ state->sig, state->siglen, NULL, 0);
+ state->siglen = 0;
+ }
+
+ dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, msg, *msglen,
+ NULL, 0);
+
+ if (done == 0 && (state->counter % 100 != 0))
+ return (0);
+
+ cp = msg + *msglen;
+ eob = msg + msgsize;
+
+ /* Name. */
+ n = dn_comp(state->key->dk_key_name, cp, eob - cp, dnptrs, lastdnptr);
+ if (n < 0)
+ return (NS_TSIG_ERROR_NO_SPACE);
+ cp += n;
+
+ /* Type, class, ttl, length (not filled in yet). */
+ BOUNDS_CHECK(cp, NS_INT16SZ + NS_INT16SZ + NS_INT32SZ + NS_INT16SZ);
+ NS_PUT16(ns_t_tsig, cp);
+ NS_PUT16(ns_c_any, cp);
+ NS_PUT32(0, cp); /* TTL */
+ lenp = cp;
+ cp += 2;
+
+ /* Alg. */
+ n = dn_comp(NS_TSIG_ALG_HMAC_MD5, cp, eob - cp, NULL, NULL);
+ if (n < 0)
+ return (NS_TSIG_ERROR_NO_SPACE);
+ cp += n;
+
+ /* Time. */
+ BOUNDS_CHECK(cp, NS_INT16SZ + NS_INT32SZ + NS_INT16SZ);
+ NS_PUT16(0, cp);
+ timesigned = time(NULL);
+ NS_PUT32(timesigned, cp);
+ NS_PUT16(NS_TSIG_FUDGE, cp);
+
+ /*
+ * Compute the signature.
+ */
+
+ /* Digest the time signed and fudge. */
+ cp2 = buf;
+ NS_PUT16(0, cp2); /* Top 16 bits of time */
+ NS_PUT32(timesigned, cp2);
+ NS_PUT16(NS_TSIG_FUDGE, cp2);
+
+ dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+ buf, cp2 - buf, NULL, 0);
+
+ n = dst_sign_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0,
+ state->sig, sizeof(state->sig));
+ if (n < 0)
+ return (-ns_r_badkey);
+ state->siglen = n;
+
+ /* Add the signature. */
+ BOUNDS_CHECK(cp, NS_INT16SZ + state->siglen);
+ NS_PUT16(state->siglen, cp);
+ memcpy(cp, state->sig, state->siglen);
+ cp += state->siglen;
+
+ /* The original message ID & error. */
+ BOUNDS_CHECK(cp, NS_INT16SZ + NS_INT16SZ);
+ NS_PUT16(ntohs(hp->id), cp); /* already in network order */
+ NS_PUT16(error, cp);
+
+ /* Other data. */
+ BOUNDS_CHECK(cp, NS_INT16SZ);
+ NS_PUT16(0, cp);
+
+ /* Go back and fill in the length. */
+ NS_PUT16(cp - lenp - NS_INT16SZ, lenp);
+
+ hp->arcount = htons(ntohs(hp->arcount) + 1);
+ *msglen = (cp - msg);
+ return (0);
+}
--- /dev/null
+/*
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#ifndef __APPLE__
+#ifndef lint
+static const char rcsid[] = "$Id: ns_ttl.c,v 1.1 2006/03/01 19:01:37 majka Exp $";
+#endif
+#endif
+
+/* Import. */
+
+#ifndef __APPLE__
+#include "port_before.h"
+#endif
+
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifndef __APPLE__
+#include "port_after.h"
+#endif
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/* Forward. */
+
+static int fmt1(int t, char s, char **buf, size_t *buflen);
+
+/* Macros. */
+
+#define T(x) if ((x) < 0) return (-1); else (void)NULL
+
+/* Public. */
+
+int
+ns_format_ttl(u_long src, char *dst, size_t dstlen) {
+ char *odst = dst;
+ int secs, mins, hours, days, weeks, x;
+ char *p;
+
+ secs = src % 60; src /= 60;
+ mins = src % 60; src /= 60;
+ hours = src % 24; src /= 24;
+ days = src % 7; src /= 7;
+ weeks = src; src = 0;
+
+ x = 0;
+ if (weeks) {
+ T(fmt1(weeks, 'W', &dst, &dstlen));
+ x++;
+ }
+ if (days) {
+ T(fmt1(days, 'D', &dst, &dstlen));
+ x++;
+ }
+ if (hours) {
+ T(fmt1(hours, 'H', &dst, &dstlen));
+ x++;
+ }
+ if (mins) {
+ T(fmt1(mins, 'M', &dst, &dstlen));
+ x++;
+ }
+ if (secs || !(weeks || days || hours || mins)) {
+ T(fmt1(secs, 'S', &dst, &dstlen));
+ x++;
+ }
+
+ if (x > 1) {
+ int ch;
+
+ for (p = odst; (ch = *p) != '\0'; p++)
+ if (isascii(ch) && isupper(ch))
+ *p = tolower(ch);
+ }
+
+ return (dst - odst);
+}
+
+int
+ns_parse_ttl(const char *src, u_long *dst) {
+ u_long ttl, tmp;
+ int ch, digits, dirty;
+
+ ttl = 0;
+ tmp = 0;
+ digits = 0;
+ dirty = 0;
+ while ((ch = *src++) != '\0') {
+ if (!isascii(ch) || !isprint(ch))
+ goto einval;
+ if (isdigit(ch)) {
+ tmp *= 10;
+ tmp += (ch - '0');
+ digits++;
+ continue;
+ }
+ if (digits == 0)
+ goto einval;
+ if (islower(ch))
+ ch = toupper(ch);
+ switch (ch) {
+ case 'W': tmp *= 7;
+ case 'D': tmp *= 24;
+ case 'H': tmp *= 60;
+ case 'M': tmp *= 60;
+ case 'S': break;
+ default: goto einval;
+ }
+ ttl += tmp;
+ tmp = 0;
+ digits = 0;
+ dirty = 1;
+ }
+ if (digits > 0) {
+ if (dirty)
+ goto einval;
+ else
+ ttl += tmp;
+ }
+ *dst = ttl;
+ return (0);
+
+ einval:
+ errno = EINVAL;
+ return (-1);
+}
+
+/* Private. */
+
+static int
+fmt1(int t, char s, char **buf, size_t *buflen) {
+ char tmp[50];
+ size_t len;
+
+ len = SPRINTF((tmp, "%d%c", t, s));
+ if (len + 1 > *buflen)
+ return (-1);
+ strcpy(*buf, tmp);
+ *buf += len;
+ *buflen -= len;
+ return (0);
+}
--- /dev/null
+/*
+ * Copyright (c) 1999 by Internet Software Consortium, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#ifndef __APPLE__
+#ifndef lint
+static const char rcsid[] = "$Id: ns_verify.c,v 1.1 2006/03/01 19:01:37 majka Exp $";
+#endif
+#endif
+
+/* Import. */
+
+#ifndef __APPLE__
+#include "port_before.h"
+#include "fd_setsize.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#ifndef __APPLE__
+#include <isc/dst.h>
+#include "port_after.h"
+#else
+#include "dst_internal.h"
+#include "res_private.h"
+#endif
+
+/* Private. */
+
+#define BOUNDS_CHECK(ptr, count) \
+ do { \
+ if ((ptr) + (count) > eom) { \
+ return (NS_TSIG_ERROR_FORMERR); \
+ } \
+ } while (0)
+
+/* Public. */
+
+u_char *
+ns_find_tsig(u_char *msg, u_char *eom) {
+ HEADER *hp = (HEADER *)msg;
+ int n, type;
+ u_char *cp = msg, *start;
+
+ if (msg == NULL || eom == NULL || msg > eom)
+ return (NULL);
+
+ if (cp + NS_HFIXEDSZ >= eom)
+ return (NULL);
+
+ if (hp->arcount == 0)
+ return (NULL);
+
+ cp += NS_HFIXEDSZ;
+
+ n = ns_skiprr(cp, eom, ns_s_qd, ntohs(hp->qdcount));
+ if (n < 0)
+ return (NULL);
+ cp += n;
+
+ n = ns_skiprr(cp, eom, ns_s_an, ntohs(hp->ancount));
+ if (n < 0)
+ return (NULL);
+ cp += n;
+
+ n = ns_skiprr(cp, eom, ns_s_ns, ntohs(hp->nscount));
+ if (n < 0)
+ return (NULL);
+ cp += n;
+
+ n = ns_skiprr(cp, eom, ns_s_ar, ntohs(hp->arcount) - 1);
+ if (n < 0)
+ return (NULL);
+ cp += n;
+
+ start = cp;
+ n = dn_skipname(cp, eom);
+ if (n < 0)
+ return (NULL);
+ cp += n;
+ if (cp + NS_INT16SZ >= eom)
+ return (NULL);
+
+ NS_GET16(type, cp);
+ if (type != ns_t_tsig)
+ return (NULL);
+ return (start);
+}
+
+/* ns_verify
+ * Parameters:
+ * statp res stuff
+ * msg received message
+ * msglen length of message
+ * key tsig key used for verifying.
+ * querysig (response), the signature in the query
+ * querysiglen (response), the length of the signature in the query
+ * sig (query), a buffer to hold the signature
+ * siglen (query), input - length of signature buffer
+ * output - length of signature
+ *
+ * Errors:
+ * - bad input (-1)
+ * - invalid dns message (NS_TSIG_ERROR_FORMERR)
+ * - TSIG is not present (NS_TSIG_ERROR_NO_TSIG)
+ * - key doesn't match (-ns_r_badkey)
+ * - TSIG verification fails with BADKEY (-ns_r_badkey)
+ * - TSIG verification fails with BADSIG (-ns_r_badsig)
+ * - TSIG verification fails with BADTIME (-ns_r_badtime)
+ * - TSIG verification succeeds, error set to BAKEY (ns_r_badkey)
+ * - TSIG verification succeeds, error set to BADSIG (ns_r_badsig)
+ * - TSIG verification succeeds, error set to BADTIME (ns_r_badtime)
+ */
+int
+ns_verify(u_char *msg, int *msglen, void *k,
+ const u_char *querysig, int querysiglen, u_char *sig, int *siglen,
+ time_t *timesigned, int nostrip)
+{
+ HEADER *hp = (HEADER *)msg;
+ DST_KEY *key = (DST_KEY *)k;
+ u_char *cp = msg, *eom;
+ char name[NS_MAXDNAME], alg[NS_MAXDNAME];
+ u_char *recstart, *rdatastart;
+ u_char *sigstart, *otherstart;
+ int n;
+ int error;
+ u_int16_t type, length;
+ u_int16_t fudge, sigfieldlen, id, otherfieldlen;
+
+ dst_init();
+ if (msg == NULL || msglen == NULL || *msglen < 0)
+ return (-1);
+
+ eom = msg + *msglen;
+
+ recstart = ns_find_tsig(msg, eom);
+ if (recstart == NULL)
+ return (NS_TSIG_ERROR_NO_TSIG);
+
+ cp = recstart;
+
+ /* Read the key name. */
+ n = dn_expand(msg, eom, cp, name, NS_MAXDNAME);
+ if (n < 0)
+ return (NS_TSIG_ERROR_FORMERR);
+ cp += n;
+
+ /* Read the type. */
+ BOUNDS_CHECK(cp, 2*NS_INT16SZ + NS_INT32SZ + NS_INT16SZ);
+ NS_GET16(type, cp);
+ if (type != ns_t_tsig)
+ return (NS_TSIG_ERROR_NO_TSIG);
+
+ /* Skip the class and TTL, save the length. */
+ cp += NS_INT16SZ + NS_INT32SZ;
+ NS_GET16(length, cp);
+ if (eom - cp != length)
+ return (NS_TSIG_ERROR_FORMERR);
+
+ /* Read the algorithm name. */
+ rdatastart = cp;
+ n = dn_expand(msg, eom, cp, alg, NS_MAXDNAME);
+ if (n < 0)
+ return (NS_TSIG_ERROR_FORMERR);
+ if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1)
+ return (-ns_r_badkey);
+ cp += n;
+
+ /* Read the time signed and fudge. */
+ BOUNDS_CHECK(cp, NS_INT16SZ + NS_INT32SZ + NS_INT16SZ);
+ cp += NS_INT16SZ;
+ NS_GET32((*timesigned), cp);
+ NS_GET16(fudge, cp);
+
+ /* Read the signature. */
+ BOUNDS_CHECK(cp, NS_INT16SZ);
+ NS_GET16(sigfieldlen, cp);
+ BOUNDS_CHECK(cp, sigfieldlen);
+ sigstart = cp;
+ cp += sigfieldlen;
+
+ /* Read the original id and error. */
+ BOUNDS_CHECK(cp, 2*NS_INT16SZ);
+ NS_GET16(id, cp);
+ NS_GET16(error, cp);
+
+ /* Parse the other data. */
+ BOUNDS_CHECK(cp, NS_INT16SZ);
+ NS_GET16(otherfieldlen, cp);
+ BOUNDS_CHECK(cp, otherfieldlen);
+ otherstart = cp;
+ cp += otherfieldlen;
+
+ if (cp != eom)
+ return (NS_TSIG_ERROR_FORMERR);
+
+ /* Verify that the key used is OK. */
+ if (key != NULL) {
+ if (key->dk_alg != KEY_HMAC_MD5)
+ return (-ns_r_badkey);
+ if (error != ns_r_badsig && error != ns_r_badkey) {
+ if (ns_samename(key->dk_key_name, name) != 1)
+ return (-ns_r_badkey);
+ }
+ }
+
+ hp->arcount = htons(ntohs(hp->arcount) - 1);
+
+ /*
+ * Do the verification.
+ */
+
+ if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
+ void *ctx;
+ u_char buf[NS_MAXDNAME];
+ u_char buf2[NS_MAXDNAME];
+
+ /* Digest the query signature, if this is a response. */
+ dst_verify_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0);
+ if (querysiglen > 0 && querysig != NULL) {
+ u_int16_t len_n = htons(querysiglen);
+ dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
+ (u_char *)&len_n, NS_INT16SZ, NULL, 0);
+ dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
+ querysig, querysiglen, NULL, 0);
+ }
+
+ /* Digest the message. */
+ dst_verify_data(SIG_MODE_UPDATE, key, &ctx, msg, recstart - msg,
+ NULL, 0);
+
+ /* Digest the key name. */
+ n = ns_name_pton(name, buf2, sizeof(buf2));
+ if (n < 0)
+ return (-1);
+ n = ns_name_ntol(buf2, buf, sizeof(buf));
+ if (n < 0)
+ return (-1);
+ dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
+
+ /* Digest the class and TTL. */
+ dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
+ recstart + dn_skipname(recstart, eom) + NS_INT16SZ,
+ NS_INT16SZ + NS_INT32SZ, NULL, 0);
+
+ /* Digest the algorithm. */
+ n = ns_name_pton(alg, buf2, sizeof(buf2));
+ if (n < 0)
+ return (-1);
+ n = ns_name_ntol(buf2, buf, sizeof(buf));
+ if (n < 0)
+ return (-1);
+ dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
+
+ /* Digest the time signed and fudge. */
+ dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
+ rdatastart + dn_skipname(rdatastart, eom),
+ NS_INT16SZ + NS_INT32SZ + NS_INT16SZ, NULL, 0);
+
+ /* Digest the error and other data. */
+ dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
+ otherstart - NS_INT16SZ - NS_INT16SZ,
+ otherfieldlen + NS_INT16SZ + NS_INT16SZ, NULL, 0);
+
+ n = dst_verify_data(SIG_MODE_FINAL, key, &ctx, NULL, 0,
+ sigstart, sigfieldlen);
+
+ if (n < 0)
+ return (-ns_r_badsig);
+
+ if (sig != NULL && siglen != NULL) {
+ if (*siglen < sigfieldlen)
+ return (NS_TSIG_ERROR_NO_SPACE);
+ memcpy(sig, sigstart, sigfieldlen);
+ *siglen = sigfieldlen;
+ }
+ } else {
+ if (sigfieldlen > 0)
+ return (NS_TSIG_ERROR_FORMERR);
+ if (sig != NULL && siglen != NULL)
+ *siglen = 0;
+ }
+
+ /* Reset the counter, since we still need to check for badtime. */
+ hp->arcount = htons(ntohs(hp->arcount) + 1);
+
+ /* Verify the time. */
+ if (abs((*timesigned) - time(NULL)) > fudge)
+ return (-ns_r_badtime);
+
+ if (nostrip == 0) {
+ *msglen = recstart - msg;
+ hp->arcount = htons(ntohs(hp->arcount) - 1);
+ }
+
+ if (error != ns_r_noerror)
+ return (error);
+
+ return (0);
+}
+
+int
+ns_verify_tcp_init(void *k, const u_char *querysig, int querysiglen,
+ ns_tcp_tsig_state *state)
+{
+ dst_init();
+ if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0)
+ return (-1);
+ state->counter = -1;
+ state->key = k;
+ if (state->key->dk_alg != KEY_HMAC_MD5)
+ return (-ns_r_badkey);
+ if (querysiglen > (int)sizeof(state->sig))
+ return (-1);
+ memcpy(state->sig, querysig, querysiglen);
+ state->siglen = querysiglen;
+ return (0);
+}
+
+int
+ns_verify_tcp(u_char *msg, int *msglen, ns_tcp_tsig_state *state,
+ int required)
+{
+ HEADER *hp = (HEADER *)msg;
+ u_char *recstart, *rdatastart, *sigstart;
+ unsigned int sigfieldlen, otherfieldlen;
+ u_char *cp, *eom = msg + *msglen, *cp2;
+ char name[NS_MAXDNAME], alg[NS_MAXDNAME];
+ u_char buf[NS_MAXDNAME];
+ int n, type, length, fudge, id, error;
+ time_t timesigned;
+
+ if (msg == NULL || msglen == NULL || state == NULL)
+ return (-1);
+
+ state->counter++;
+ if (state->counter == 0)
+ return (ns_verify(msg, msglen, state->key,
+ state->sig, state->siglen,
+ state->sig, &state->siglen, ×igned, 0));
+
+ if (state->siglen > 0) {
+ u_int16_t siglen_n = htons(state->siglen);
+
+ dst_verify_data(SIG_MODE_INIT, state->key, &state->ctx,
+ NULL, 0, NULL, 0);
+ dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+ (u_char *)&siglen_n, NS_INT16SZ, NULL, 0);
+ dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+ state->sig, state->siglen, NULL, 0);
+ state->siglen = 0;
+ }
+
+ cp = recstart = ns_find_tsig(msg, eom);
+
+ if (recstart == NULL) {
+ if (required)
+ return (NS_TSIG_ERROR_NO_TSIG);
+ dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+ msg, *msglen, NULL, 0);
+ return (0);
+ }
+
+ hp->arcount = htons(ntohs(hp->arcount) - 1);
+ dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+ msg, recstart - msg, NULL, 0);
+
+ /* Read the key name. */
+ n = dn_expand(msg, eom, cp, name, NS_MAXDNAME);
+ if (n < 0)
+ return (NS_TSIG_ERROR_FORMERR);
+ cp += n;
+
+ /* Read the type. */
+ BOUNDS_CHECK(cp, 2*NS_INT16SZ + NS_INT32SZ + NS_INT16SZ);
+ NS_GET16(type, cp);
+ if (type != ns_t_tsig)
+ return (NS_TSIG_ERROR_NO_TSIG);
+
+ /* Skip the class and TTL, save the length. */
+ cp += NS_INT16SZ + NS_INT32SZ;
+ NS_GET16(length, cp);
+ if (eom - cp != length)
+ return (NS_TSIG_ERROR_FORMERR);
+
+ /* Read the algorithm name. */
+ rdatastart = cp;
+ n = dn_expand(msg, eom, cp, alg, NS_MAXDNAME);
+ if (n < 0)
+ return (NS_TSIG_ERROR_FORMERR);
+ if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1)
+ return (-ns_r_badkey);
+ cp += n;
+
+ /* Verify that the key used is OK. */
+ if ((ns_samename(state->key->dk_key_name, name) != 1 ||
+ state->key->dk_alg != KEY_HMAC_MD5))
+ return (-ns_r_badkey);
+
+ /* Read the time signed and fudge. */
+ BOUNDS_CHECK(cp, NS_INT16SZ + NS_INT32SZ + NS_INT16SZ);
+ cp += NS_INT16SZ;
+ NS_GET32(timesigned, cp);
+ NS_GET16(fudge, cp);
+
+ /* Read the signature. */
+ BOUNDS_CHECK(cp, NS_INT16SZ);
+ NS_GET16(sigfieldlen, cp);
+ BOUNDS_CHECK(cp, sigfieldlen);
+ sigstart = cp;
+ cp += sigfieldlen;
+
+ /* Read the original id and error. */
+ BOUNDS_CHECK(cp, 2*NS_INT16SZ);
+ NS_GET16(id, cp);
+ NS_GET16(error, cp);
+
+ /* Parse the other data. */
+ BOUNDS_CHECK(cp, NS_INT16SZ);
+ NS_GET16(otherfieldlen, cp);
+ BOUNDS_CHECK(cp, otherfieldlen);
+ cp += otherfieldlen;
+
+ if (cp != eom)
+ return (NS_TSIG_ERROR_FORMERR);
+
+ /*
+ * Do the verification.
+ */
+
+ /* Digest the time signed and fudge. */
+ cp2 = buf;
+ NS_PUT16(0, cp2); /* Top 16 bits of time. */
+ NS_PUT32(timesigned, cp2);
+ NS_PUT16(NS_TSIG_FUDGE, cp2);
+
+ dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+ buf, cp2 - buf, NULL, 0);
+
+ n = dst_verify_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0,
+ sigstart, sigfieldlen);
+ if (n < 0)
+ return (-ns_r_badsig);
+
+ if (sigfieldlen > sizeof(state->sig))
+ return (NS_TSIG_ERROR_NO_SPACE);
+
+ memcpy(state->sig, sigstart, sigfieldlen);
+ state->siglen = sigfieldlen;
+
+ /* Verify the time. */
+ if (abs(timesigned - time(NULL)) > fudge)
+ return (-ns_r_badtime);
+
+ *msglen = recstart - msg;
+
+ if (error != ns_r_noerror)
+ return (error);
+
+ return (0);
+}
--- /dev/null
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)res_comp.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_comp.c,v 1.1 2006/03/01 19:01:37 majka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#ifndef __APPLE__
+#include "port_before.h"
+#endif
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <ctype.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#ifndef __APPLE__
+#include "port_after.h"
+#endif
+
+/*
+ * Expand compressed domain name 'comp_dn' to full domain name.
+ * 'msg' is a pointer to the begining of the message,
+ * 'eomorig' points to the first location after the message,
+ * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
+ * Return size of compressed name or -1 if there was an error.
+ */
+int
+dn_expand(const u_char *msg, const u_char *eom, const u_char *src,
+ char *dst, int dstsiz)
+{
+ int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz);
+
+ if (n > 0 && dst[0] == '.')
+ dst[0] = '\0';
+ return (n);
+}
+
+/*
+ * Pack domain name 'exp_dn' in presentation form into 'comp_dn'.
+ * Return the size of the compressed name or -1.
+ * 'length' is the size of the array pointed to by 'comp_dn'.
+ */
+int
+dn_comp(const char *src, u_char *dst, int dstsiz,
+ u_char **dnptrs, u_char **lastdnptr)
+{
+ return (ns_name_compress(src, dst, (size_t)dstsiz,
+ (const u_char **)dnptrs,
+ (const u_char **)lastdnptr));
+}
+
+/*
+ * Skip over a compressed domain name. Return the size or -1.
+ */
+int
+dn_skipname(const u_char *ptr, const u_char *eom) {
+ const u_char *saveptr = ptr;
+
+ if (ns_name_skip(&ptr, eom) == -1)
+ return (-1);
+ return (ptr - saveptr);
+}
+
+/*
+ * Verify that a domain name uses an acceptable character set.
+ */
+
+/*
+ * Note the conspicuous absence of ctype macros in these definitions. On
+ * non-ASCII hosts, we can't depend on string literals or ctype macros to
+ * tell us anything about network-format data. The rest of the BIND system
+ * is not careful about this, but for some reason, we're doing it right here.
+ */
+#define PERIOD 0x2e
+#define hyphenchar(c) ((c) == 0x2d)
+#define bslashchar(c) ((c) == 0x5c)
+#define periodchar(c) ((c) == PERIOD)
+#define asterchar(c) ((c) == 0x2a)
+#define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) \
+ || ((c) >= 0x61 && (c) <= 0x7a))
+#define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
+
+#define borderchar(c) (alphachar(c) || digitchar(c))
+#define middlechar(c) (borderchar(c) || hyphenchar(c))
+#define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
+
+int
+res_hnok(const char *dn) {
+ int ppch = '\0', pch = PERIOD, ch = *dn++;
+
+ while (ch != '\0') {
+ int nch = *dn++;
+
+ if (periodchar(ch)) {
+ (void)NULL;
+ } else if (periodchar(pch)) {
+ if (!borderchar(ch))
+ return (0);
+ } else if (periodchar(nch) || nch == '\0') {
+ if (!borderchar(ch))
+ return (0);
+ } else {
+ if (!middlechar(ch))
+ return (0);
+ }
+ ppch = pch, pch = ch, ch = nch;
+ }
+ return (1);
+}
+
+/*
+ * hostname-like (A, MX, WKS) owners can have "*" as their first label
+ * but must otherwise be as a host name.
+ */
+int
+res_ownok(const char *dn) {
+ if (asterchar(dn[0])) {
+ if (periodchar(dn[1]))
+ return (res_hnok(dn+2));
+ if (dn[1] == '\0')
+ return (1);
+ }
+ return (res_hnok(dn));
+}
+
+/*
+ * SOA RNAMEs and RP RNAMEs can have any printable character in their first
+ * label, but the rest of the name has to look like a host name.
+ */
+int
+res_mailok(const char *dn) {
+ int ch, escaped = 0;
+
+ /* "." is a valid missing representation */
+ if (*dn == '\0')
+ return (1);
+
+ /* otherwise <label>.<hostname> */
+ while ((ch = *dn++) != '\0') {
+ if (!domainchar(ch))
+ return (0);
+ if (!escaped && periodchar(ch))
+ break;
+ if (escaped)
+ escaped = 0;
+ else if (bslashchar(ch))
+ escaped = 1;
+ }
+ if (periodchar(ch))
+ return (res_hnok(dn));
+ return (0);
+}
+
+/*
+ * This function is quite liberal, since RFC 1034's character sets are only
+ * recommendations.
+ */
+int
+res_dnok(const char *dn) {
+ int ch;
+
+ while ((ch = *dn++) != '\0')
+ if (!domainchar(ch))
+ return (0);
+ return (1);
+}
+
+#ifdef __APPLE__
+void putlong(u_int32_t src, u_char *dst) { ns_put32(src, dst); }
+void putshort(u_int16_t src, u_char *dst) { ns_put16(src, dst); }
+u_int32_t _getlong(const u_char *src) { return (ns_get32(src)); }
+u_int16_t _getshort(const u_char *src) { return (ns_get16(src)); }
+#else
+#ifdef BIND_4_COMPAT
+/*
+ * This module must export the following externally-visible symbols:
+ * ___putlong
+ * ___putshort
+ * __getlong
+ * __getshort
+ * Note that one _ comes from C and the others come from us.
+ */
+void putlong(u_int32_t src, u_char *dst) { ns_put32(src, dst); }
+void putshort(u_int16_t src, u_char *dst) { ns_put16(src, dst); }
+#ifndef __ultrix__
+u_int32_t _getlong(const u_char *src) { return (ns_get32(src)); }
+u_int16_t _getshort(const u_char *src) { return (ns_get16(src)); }
+#endif /*__ultrix__*/
+#endif /*BIND_4_COMPAT*/
+#endif /* __APPLE__ */
--- /dev/null
+/*
+ * Copyright (c) 1995-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: res_data.c,v 1.1 2006/03/01 19:01:37 majka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <res_update.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "res_private.h"
+
+static struct __res_state *_res_static;
+
+#ifdef USE__RES_9
+struct __res_9_state _res_9;
+#endif
+
+extern int __res_vinit(res_state, int);
+
+const char *__res_opcodes[] = {
+ "QUERY",
+ "IQUERY",
+ "CQUERYM",
+ "CQUERYU", /* experimental */
+ "NOTIFY", /* experimental */
+ "UPDATE",
+ "6",
+ "7",
+ "8",
+ "9",
+ "10",
+ "11",
+ "12",
+ "13",
+ "ZONEINIT",
+ "ZONEREF",
+};
+
+void
+__h_errno_set(struct __res_state *res, int err)
+{
+ h_errno = res->res_h_errno = err;
+}
+
+void
+res_client_close(res_state res)
+{
+ if (res == NULL) return;
+
+ if (res->_u._ext.ext != NULL) free(res->_u._ext.ext);
+ free(res);
+}
+
+res_state
+res_state_new()
+{
+ res_state x;
+
+ x = (res_state)calloc(1, sizeof(struct __res_state));
+ if (x == NULL) return NULL;
+
+ /*
+ * We use _pad (normally unused) to hold a version number.
+ * We use it provide limited compatibility between versions.
+ */
+ x->_pad = 9;
+
+ x->_u._ext.ext = (struct __res_state_ext *)calloc(1, sizeof(struct __res_state_ext));
+ if (x->_u._ext.ext == NULL)
+ {
+ free(x);
+ return NULL;
+ }
+
+ return x;
+}
+
+int
+res_init(void)
+{
+ extern int __res_vinit(res_state, int);
+ unsigned int save_retrans, save_retry, save_options, save_id;
+ struct __res_state_ext *save_ext;
+
+#ifdef USE__RES_9
+ _res_static = &_res_9;
+#else
+ _res_static = &_res;
+#endif
+
+ save_retrans = RES_TIMEOUT;
+ save_retry = RES_DFLRETRY;
+ save_options = RES_DEFAULT;
+ save_id = res_randomid();
+ save_ext = _res_static->_u._ext.ext;
+
+ if (_res_static->options & RES_INIT)
+ {
+ /* Caller wants to override default options */
+ save_options = _res_static->options;
+ if (_res_static->retrans != 0) save_retrans = _res_static->retrans;
+ if (_res_static->retry != 0) save_retry = _res_static->retry;
+ if (_res_static->id != 0) save_id = _res_static->id;
+ }
+
+ memset(_res_static, 0, sizeof(struct __res_state));
+ _res_static->_vcsock = -1;
+
+ _res_static->retrans = save_retrans;
+ _res_static->retry = save_retry;
+ _res_static->id = save_id;
+ _res_static->options = save_options;
+ _res_static->_u._ext.ext = save_ext;
+
+ _res_static->_pad = 9;
+
+ if (_res_static->_u._ext.ext == NULL) _res_static->_u._ext.ext = (struct __res_state_ext *)calloc(1, sizeof(struct __res_state_ext));
+
+ return (__res_vinit(_res_static, 1));
+}
+
+int
+res_query(const char *name, int class, int type, u_char *answer, int anslen)
+{
+#ifdef USE__RES_9
+ _res_static = &_res_9;
+#else
+ _res_static = &_res;
+#endif
+
+ if (((_res_static->options & RES_INIT) == 0) && (res_init() == -1))
+ {
+ RES_SET_H_ERRNO(_res_static, NETDB_INTERNAL);
+ return -1;
+ }
+ return (res_nquery(_res_static, name, class, type, answer, anslen));
+}
+
+void
+fp_nquery(const u_char *msg, int len, FILE *file)
+{
+#ifdef USE__RES_9
+ _res_static = &_res_9;
+#else
+ _res_static = &_res;
+#endif
+
+ if (((_res_static->options & RES_INIT) == 0) && (res_init() == -1)) return;
+
+ res_pquery(_res_static, msg, len, file);
+}
+
+void
+fp_query(const u_char *msg, FILE *file)
+{
+ fp_nquery(msg, NS_PACKETSZ, file);
+}
+
+void
+p_query(const u_char *msg)
+{
+ fp_query(msg, stdout);
+}
+
+const char *
+hostalias(const char *name)
+{
+ static char abuf[NS_MAXDNAME];
+
+#ifdef USE__RES_9
+ _res_static = &_res_9;
+#else
+ _res_static = &_res;
+#endif
+
+ return (res_hostalias(_res_static, name, abuf, sizeof abuf));
+}
+
+void
+res_close(void)
+{
+#ifdef USE__RES_9
+ _res_static = &_res_9;
+#else
+ _res_static = &_res;
+#endif
+
+ res_nclose(_res_static);
+}
+
+int
+res_isourserver(const struct sockaddr_in *inp)
+{
+#ifdef USE__RES_9
+ _res_static = &_res_9;
+#else
+ _res_static = &_res;
+#endif
+
+ return (res_ourserver_p(_res_static, (const struct sockaddr *)inp));
+}
+
+int
+res_nisourserver(const res_state res, const struct sockaddr_in *inp)
+{
+ return (res_ourserver_p(res, (const struct sockaddr *)inp));
+}
+
+int
+res_mkquery(int op, const char *dname, int class, int type, const u_char *data, int datalen, const u_char *newrr_in, u_char *buf, int buflen)
+{
+#ifdef USE__RES_9
+ _res_static = &_res_9;
+#else
+ _res_static = &_res;
+#endif
+
+ if (((_res_static->options & RES_INIT) == 0) && (res_init() == -1))
+ {
+ RES_SET_H_ERRNO(_res_static, NETDB_INTERNAL);
+ return -1;
+ }
+
+ return res_nmkquery(_res_static, op, dname, class, type, data, datalen, newrr_in, buf, buflen);
+}
+
+int
+res_querydomain(const char *name, const char *domain, int class, int type, u_char *answer, int anslen)
+{
+#ifdef USE__RES_9
+ _res_static = &_res_9;
+#else
+ _res_static = &_res;
+#endif
+
+ if (((_res_static->options & RES_INIT) == 0) && (res_init() == -1))
+ {
+ RES_SET_H_ERRNO(_res_static, NETDB_INTERNAL);
+ return -1;
+ }
+
+ return res_nquerydomain(_res_static, name, domain, class, type, answer, anslen);
+}
+
+int
+res_search(const char *name, int class, int type, u_char *answer, int anslen)
+{
+#ifdef USE__RES_9
+ _res_static = &_res_9;
+#else
+ _res_static = &_res;
+#endif
+
+ if (((_res_static->options & RES_INIT) == 0) && (res_init() == -1))
+ {
+ RES_SET_H_ERRNO(_res_static, NETDB_INTERNAL);
+ return -1;
+ }
+
+ return res_nsearch(_res_static, name, class, type, answer, anslen);
+}
+
+int
+res_send(const u_char *buf, int buflen, u_char *ans, int anssiz)
+{
+#ifdef USE__RES_9
+ _res_static = &_res_9;
+#else
+ _res_static = &_res;
+#endif
+
+ if (((_res_static->options & RES_INIT) == 0) && (res_init() == -1))
+ {
+ /* errno should have been set by res_init() in this case. */
+ return -1;
+ }
+
+ return res_nsend(_res_static, buf, buflen, ans, anssiz);
+}
+
+int
+res_sendsigned(const u_char *buf, int buflen, ns_tsig_key *key, u_char *ans, int anssiz)
+{
+#ifdef USE__RES_9
+ _res_static = &_res_9;
+#else
+ _res_static = &_res;
+#endif
+
+ if (((_res_static->options & RES_INIT) == 0) && (res_init() == -1))
+ {
+ /* errno should have been set by res_init() in this case. */
+ return -1;
+ }
+
+ return res_nsendsigned(_res_static, buf, buflen, key, ans, anssiz);
+}
--- /dev/null
+/*
+ * Copyright (c) 1985
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+/*
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)res_debug.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_debug.c,v 1.1 2006/03/01 19:01:38 majka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#ifndef __APPLE__
+#include "port_before.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <math.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifndef __APPLE__
+#include "port_after.h"
+#endif
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) sprintf x
+#endif
+
+extern const char * __res_opcodes[];
+extern const char *_res_sectioncodes[];
+
+/*
+ * Print the current options.
+ */
+void
+fp_resstat(const res_state statp, FILE *file) {
+ u_long mask;
+
+ fprintf(file, ";; res options:");
+ for (mask = 1; mask != 0; mask <<= 1)
+ if (statp->options & mask)
+ fprintf(file, " %s", p_option(mask));
+ putc('\n', file);
+}
+
+static void
+do_section(const res_state statp,
+ ns_msg *handle, ns_sect section,
+ int pflag, FILE *file)
+{
+ int n, sflag, rrnum;
+ static int buflen = 2048;
+ char *buf;
+ ns_opcode opcode;
+ ns_rr rr;
+
+ /*
+ * Print answer records.
+ */
+ sflag = (statp->pfcode & pflag);
+ if (statp->pfcode && !sflag)
+ return;
+
+ buf = malloc(buflen);
+ if (buf == NULL) {
+ fprintf(file, ";; memory allocation failure\n");
+ return;
+ }
+
+ opcode = (ns_opcode) ns_msg_getflag(*handle, ns_f_opcode);
+ rrnum = 0;
+ for (;;) {
+ if (ns_parserr(handle, section, rrnum, &rr)) {
+ if (errno != ENODEV)
+ fprintf(file, ";; ns_parserr: %s\n",
+ strerror(errno));
+ else if (rrnum > 0 && sflag != 0 &&
+ (statp->pfcode & RES_PRF_HEAD1))
+ putc('\n', file);
+ goto cleanup;
+ }
+ if (rrnum == 0 && sflag != 0 && (statp->pfcode & RES_PRF_HEAD1))
+ fprintf(file, ";; %s SECTION:\n",
+ p_section(section, opcode));
+ if (section == ns_s_qd)
+ fprintf(file, ";;\t%s, type = %s, class = %s\n",
+ ns_rr_name(rr),
+ p_type(ns_rr_type(rr)),
+ p_class(ns_rr_class(rr)));
+ else if (section == ns_s_ar && ns_rr_type(rr) == ns_t_opt) {
+ u_int32_t ttl = ns_rr_ttl(rr);
+ fprintf(file,
+ "; EDNS: version: %u, udp=%u, flags=%04x\n",
+ (ttl>>16)&0xff, ns_rr_class(rr), ttl&0xffff);
+ } else {
+ n = ns_sprintrr(handle, &rr, NULL, NULL,
+ buf, buflen);
+ if (n < 0) {
+ if (errno == ENOSPC) {
+ free(buf);
+ buf = NULL;
+ if (buflen < 131072)
+ buf = malloc(buflen += 1024);
+ if (buf == NULL) {
+ fprintf(file,
+ ";; memory allocation failure\n");
+ return;
+ }
+ continue;
+ }
+ fprintf(file, ";; ns_sprintrr: %s\n",
+ strerror(errno));
+ goto cleanup;
+ }
+ fputs(buf, file);
+ fputc('\n', file);
+ }
+ rrnum++;
+ }
+ cleanup:
+ if (buf != NULL)
+ free(buf);
+}
+
+/*
+ * Print the contents of a query.
+ * This is intended to be primarily a debugging routine.
+ */
+void
+res_pquery(const res_state statp, const u_char *msg, int len, FILE *file) {
+ ns_msg handle;
+ int qdcount, ancount, nscount, arcount;
+ u_int opcode, rcode, id;
+
+ if (ns_initparse(msg, len, &handle) < 0) {
+ fprintf(file, ";; ns_initparse: %s\n", strerror(errno));
+ return;
+ }
+ opcode = ns_msg_getflag(handle, ns_f_opcode);
+ rcode = ns_msg_getflag(handle, ns_f_rcode);
+ id = ns_msg_id(handle);
+ qdcount = ns_msg_count(handle, ns_s_qd);
+ ancount = ns_msg_count(handle, ns_s_an);
+ nscount = ns_msg_count(handle, ns_s_ns);
+ arcount = ns_msg_count(handle, ns_s_ar);
+
+ /*
+ * Print header fields.
+ */
+ if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEADX) || rcode)
+ fprintf(file,
+ ";; ->>HEADER<<- opcode: %s, status: %s, id: %d\n",
+ __res_opcodes[opcode], p_rcode(rcode), id);
+ if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEADX))
+ putc(';', file);
+ if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEAD2)) {
+ fprintf(file, "; flags:");
+ if (ns_msg_getflag(handle, ns_f_qr))
+ fprintf(file, " qr");
+ if (ns_msg_getflag(handle, ns_f_aa))
+ fprintf(file, " aa");
+ if (ns_msg_getflag(handle, ns_f_tc))
+ fprintf(file, " tc");
+ if (ns_msg_getflag(handle, ns_f_rd))
+ fprintf(file, " rd");
+ if (ns_msg_getflag(handle, ns_f_ra))
+ fprintf(file, " ra");
+ if (ns_msg_getflag(handle, ns_f_z))
+ fprintf(file, " ??");
+ if (ns_msg_getflag(handle, ns_f_ad))
+ fprintf(file, " ad");
+ if (ns_msg_getflag(handle, ns_f_cd))
+ fprintf(file, " cd");
+ }
+ if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEAD1)) {
+ fprintf(file, "; %s: %d",
+ p_section(ns_s_qd, opcode), qdcount);
+ fprintf(file, ", %s: %d",
+ p_section(ns_s_an, opcode), ancount);
+ fprintf(file, ", %s: %d",
+ p_section(ns_s_ns, opcode), nscount);
+ fprintf(file, ", %s: %d",
+ p_section(ns_s_ar, opcode), arcount);
+ }
+ if ((!statp->pfcode) || (statp->pfcode &
+ (RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) {
+ putc('\n',file);
+ }
+ /*
+ * Print the various sections.
+ */
+ do_section(statp, &handle, ns_s_qd, RES_PRF_QUES, file);
+ do_section(statp, &handle, ns_s_an, RES_PRF_ANS, file);
+ do_section(statp, &handle, ns_s_ns, RES_PRF_AUTH, file);
+ do_section(statp, &handle, ns_s_ar, RES_PRF_ADD, file);
+ if (qdcount == 0 && ancount == 0 &&
+ nscount == 0 && arcount == 0)
+ putc('\n', file);
+}
+
+const u_char *
+p_cdnname(const u_char *cp, const u_char *msg, int len, FILE *file) {
+ char name[NS_MAXDNAME];
+ int n;
+
+ if ((n = dn_expand(msg, msg + len, cp, name, sizeof name)) < 0)
+ return (NULL);
+ if (name[0] == '\0')
+ putc('.', file);
+ else
+ fputs(name, file);
+ return (cp + n);
+}
+
+const u_char *
+p_cdname(const u_char *cp, const u_char *msg, FILE *file) {
+ return (p_cdnname(cp, msg, NS_PACKETSZ, file));
+}
+
+/* Return a fully-qualified domain name from a compressed name (with
+ length supplied). */
+
+const u_char *
+p_fqnname(cp, msg, msglen, name, namelen)
+ const u_char *cp, *msg;
+ int msglen;
+ char *name;
+ int namelen;
+{
+ int n, newlen;
+
+ if ((n = dn_expand(msg, cp + msglen, cp, name, namelen)) < 0)
+ return (NULL);
+ newlen = strlen(name);
+ if (newlen == 0 || name[newlen - 1] != '.') {
+ if (newlen + 1 >= namelen) /* Lack space for final dot */
+ return (NULL);
+ else
+ strcpy(name + newlen, ".");
+ }
+ return (cp + n);
+}
+
+/* XXX: the rest of these functions need to become length-limited, too. */
+
+const u_char *
+p_fqname(const u_char *cp, const u_char *msg, FILE *file) {
+ char name[NS_MAXDNAME];
+ const u_char *n;
+
+ n = p_fqnname(cp, msg, NS_MAXCDNAME, name, sizeof name);
+ if (n == NULL)
+ return (NULL);
+ fputs(name, file);
+ return (n);
+}
+
+/*
+ * Names of RR classes and qclasses. Classes and qclasses are the same, except
+ * that ns_c_any is a qclass but not a class. (You can ask for records of class
+ * ns_c_any, but you can't have any records of that class in the database.)
+ */
+const struct res_sym __res_p_class_syms[] = {
+ {ns_c_in, "IN", (char *)0},
+ {ns_c_chaos, "CHAOS", (char *)0},
+ {ns_c_hs, "HS", (char *)0},
+ {ns_c_hs, "HESIOD", (char *)0},
+ {ns_c_any, "ANY", (char *)0},
+ {ns_c_none, "NONE", (char *)0},
+ {ns_c_in, (char *)0, (char *)0}
+};
+
+/*
+ * Names of message sections.
+ */
+#ifdef __APPLE__
+static
+#endif
+const struct res_sym __res_p_default_section_syms[] = {
+ {ns_s_qd, "QUERY", (char *)0},
+ {ns_s_an, "ANSWER", (char *)0},
+ {ns_s_ns, "AUTHORITY", (char *)0},
+ {ns_s_ar, "ADDITIONAL", (char *)0},
+ {0, (char *)0, (char *)0}
+};
+
+#ifdef __APPLE__
+static
+#endif
+const struct res_sym __res_p_update_section_syms[] = {
+ {ns_s_zn, "ZONE", (char *)0},
+ {ns_s_pr, "PREREQUISITE", (char *)0},
+ {ns_s_ud, "UPDATE", (char *)0},
+ {ns_s_ar, "ADDITIONAL", (char *)0},
+ {0, (char *)0, (char *)0}
+};
+
+const struct res_sym __res_p_key_syms[] = {
+ {NS_ALG_MD5RSA, "RSA", "RSA KEY with MD5 hash"},
+ {NS_ALG_DH, "DH", "Diffie Hellman"},
+ {NS_ALG_DSA, "DSA", "Digital Signature Algorithm"},
+ {NS_ALG_EXPIRE_ONLY, "EXPIREONLY", "No algorithm"},
+ {NS_ALG_PRIVATE_OID, "PRIVATE", "Algorithm obtained from OID"},
+ {0, NULL, NULL}
+};
+
+const struct res_sym __res_p_cert_syms[] = {
+ {cert_t_pkix, "PKIX", "PKIX (X.509v3) Certificate"},
+ {cert_t_spki, "SPKI", "SPKI certificate"},
+ {cert_t_pgp, "PGP", "PGP certificate"},
+ {cert_t_url, "URL", "URL Private"},
+ {cert_t_oid, "OID", "OID Private"},
+ {0, NULL, NULL}
+};
+
+/*
+ * Names of RR types and qtypes. Types and qtypes are the same, except
+ * that T_ANY is a qtype but not a type. (You can ask for records of type
+ * T_ANY, but you can't have any records of that type in the database.)
+ */
+const struct res_sym __p_type_syms[] = {
+ {ns_t_a, "A", "address"},
+ {ns_t_ns, "NS", "name server"},
+ {ns_t_md, "MD", "mail destination (deprecated)"},
+ {ns_t_mf, "MF", "mail forwarder (deprecated)"},
+ {ns_t_cname, "CNAME", "canonical name"},
+ {ns_t_soa, "SOA", "start of authority"},
+ {ns_t_mb, "MB", "mailbox"},
+ {ns_t_mg, "MG", "mail group member"},
+ {ns_t_mr, "MR", "mail rename"},
+ {ns_t_null, "NULL", "null"},
+ {ns_t_wks, "WKS", "well-known service (deprecated)"},
+ {ns_t_ptr, "PTR", "domain name pointer"},
+ {ns_t_hinfo, "HINFO", "host information"},
+ {ns_t_minfo, "MINFO", "mailbox information"},
+ {ns_t_mx, "MX", "mail exchanger"},
+ {ns_t_txt, "TXT", "text"},
+ {ns_t_rp, "RP", "responsible person"},
+ {ns_t_afsdb, "AFSDB", "DCE or AFS server"},
+ {ns_t_x25, "X25", "X25 address"},
+ {ns_t_isdn, "ISDN", "ISDN address"},
+ {ns_t_rt, "RT", "router"},
+ {ns_t_nsap, "NSAP", "nsap address"},
+ {ns_t_nsap_ptr, "NSAP_PTR", "domain name pointer"},
+ {ns_t_sig, "SIG", "signature"},
+ {ns_t_key, "KEY", "key"},
+ {ns_t_px, "PX", "mapping information"},
+ {ns_t_gpos, "GPOS", "geographical position (withdrawn)"},
+ {ns_t_aaaa, "AAAA", "IPv6 address"},
+ {ns_t_loc, "LOC", "location"},
+ {ns_t_nxt, "NXT", "next valid name (unimplemented)"},
+ {ns_t_eid, "EID", "endpoint identifier (unimplemented)"},
+ {ns_t_nimloc, "NIMLOC", "NIMROD locator (unimplemented)"},
+ {ns_t_srv, "SRV", "server selection"},
+ {ns_t_atma, "ATMA", "ATM address (unimplemented)"},
+ {ns_t_tkey, "TKEY", "tkey"},
+ {ns_t_tsig, "TSIG", "transaction signature"},
+ {ns_t_ixfr, "IXFR", "incremental zone transfer"},
+ {ns_t_axfr, "AXFR", "zone transfer"},
+ {ns_t_zxfr, "ZXFR", "compressed zone transfer"},
+ {ns_t_mailb, "MAILB", "mailbox-related data (deprecated)"},
+ {ns_t_maila, "MAILA", "mail agent (deprecated)"},
+ {ns_t_naptr, "NAPTR", "URN Naming Authority"},
+ {ns_t_kx, "KX", "Key Exchange"},
+ {ns_t_cert, "CERT", "Certificate"},
+ {ns_t_a6, "A6", "IPv6 Address"},
+ {ns_t_dname, "DNAME", "dname"},
+ {ns_t_sink, "SINK", "Kitchen Sink (experimental)"},
+ {ns_t_opt, "OPT", "EDNS Options"},
+ {ns_t_any, "ANY", "\"any\""},
+ {0, NULL, NULL}
+};
+
+/*
+ * Names of DNS rcodes.
+ */
+const struct res_sym __res_p_rcode_syms[] = {
+ {ns_r_noerror, "NOERROR", "no error"},
+ {ns_r_formerr, "FORMERR", "format error"},
+ {ns_r_servfail, "SERVFAIL", "server failed"},
+ {ns_r_nxdomain, "NXDOMAIN", "no such domain name"},
+ {ns_r_notimpl, "NOTIMP", "not implemented"},
+ {ns_r_refused, "REFUSED", "refused"},
+ {ns_r_yxdomain, "YXDOMAIN", "domain name exists"},
+ {ns_r_yxrrset, "YXRRSET", "rrset exists"},
+ {ns_r_nxrrset, "NXRRSET", "rrset doesn't exist"},
+ {ns_r_notauth, "NOTAUTH", "not authoritative"},
+ {ns_r_notzone, "NOTZONE", "Not in zone"},
+ {ns_r_max, "", ""},
+ {ns_r_badsig, "BADSIG", "bad signature"},
+ {ns_r_badkey, "BADKEY", "bad key"},
+ {ns_r_badtime, "BADTIME", "bad time"},
+ {0, NULL, NULL}
+};
+
+int
+sym_ston(const struct res_sym *syms, const char *name, int *success) {
+ for ((void)NULL; syms->name != 0; syms++) {
+ if (strcasecmp (name, syms->name) == 0) {
+ if (success)
+ *success = 1;
+ return (syms->number);
+ }
+ }
+ if (success)
+ *success = 0;
+ return (syms->number); /* The default value. */
+}
+
+const char *
+sym_ntos(const struct res_sym *syms, int number, int *success) {
+ static char unname[20];
+
+ for ((void)NULL; syms->name != 0; syms++) {
+ if (number == syms->number) {
+ if (success)
+ *success = 1;
+ return (syms->name);
+ }
+ }
+
+ sprintf(unname, "%d", number); /* XXX nonreentrant */
+ if (success)
+ *success = 0;
+ return (unname);
+}
+
+const char *
+sym_ntop(const struct res_sym *syms, int number, int *success) {
+ static char unname[20];
+
+ for ((void)NULL; syms->name != 0; syms++) {
+ if (number == syms->number) {
+ if (success)
+ *success = 1;
+ return (syms->humanname);
+ }
+ }
+ sprintf(unname, "%d", number); /* XXX nonreentrant */
+ if (success)
+ *success = 0;
+ return (unname);
+}
+
+/*
+ * Return a string for the type.
+ */
+const char *
+p_type(int type) {
+ int success;
+ const char *result;
+ static char typebuf[20];
+
+ result = sym_ntos(__p_type_syms, type, &success);
+ if (success)
+ return (result);
+ if (type < 0 || type > 0xfff)
+ return ("BADTYPE");
+ sprintf(typebuf, "TYPE%d", type);
+ return (typebuf);
+}
+
+/*
+ * Return a string for the type.
+ */
+const char *
+p_section(int section, int opcode) {
+ const struct res_sym *symbols;
+
+ switch (opcode) {
+ case ns_o_update:
+ symbols = __res_p_update_section_syms;
+ break;
+ default:
+ symbols = __res_p_default_section_syms;
+ break;
+ }
+ return (sym_ntos(symbols, section, (int *)0));
+}
+
+/*
+ * Return a mnemonic for class.
+ */
+const char *
+p_class(int class) {
+ int success;
+ const char *result;
+ static char classbuf[20];
+
+ result = sym_ntos(__res_p_class_syms, class, &success);
+ if (success)
+ return (result);
+ if (class < 0 || class > 0xfff)
+ return ("BADCLASS");
+ sprintf(classbuf, "CLASS%d", class);
+ return (classbuf);
+}
+
+/*
+ * Return a mnemonic for an option
+ */
+const char *
+p_option(u_long option) {
+ static char nbuf[40];
+
+ switch (option) {
+ case RES_INIT: return "init";
+ case RES_DEBUG: return "debug";
+ case RES_AAONLY: return "aaonly(unimpl)";
+ case RES_USEVC: return "usevc";
+ case RES_PRIMARY: return "primry(unimpl)";
+ case RES_IGNTC: return "igntc";
+ case RES_RECURSE: return "recurs";
+ case RES_DEFNAMES: return "defnam";
+ case RES_STAYOPEN: return "styopn";
+ case RES_DNSRCH: return "dnsrch";
+ case RES_INSECURE1: return "insecure1";
+ case RES_INSECURE2: return "insecure2";
+ case RES_NOALIASES: return "noaliases";
+ case RES_USE_INET6: return "inet6";
+#ifdef RES_USE_EDNS0 /* KAME extension */
+ case RES_USE_EDNS0: return "edns0";
+#endif
+#ifdef RES_USE_A6
+ case RES_USE_A6: return "a6";
+#endif
+#ifdef RES_USE_DNAME
+ case RES_USE_DNAME: return "dname";
+#endif
+#ifdef RES_USE_DNSSEC
+ case RES_USE_DNSSEC: return "dnssec";
+#endif
+#ifdef RES_NOTLDQUERY
+ case RES_NOTLDQUERY: return "no-tld-query";
+#endif
+
+ /* XXX nonreentrant */
+ default: sprintf(nbuf, "?0x%lx?", (u_long)option);
+ return (nbuf);
+ }
+}
+
+/*
+ * Return a mnemonic for a time to live.
+ */
+const char *
+p_time(u_int32_t value) {
+ static char nbuf[40]; /* XXX nonreentrant */
+
+ if (ns_format_ttl(value, nbuf, sizeof nbuf) < 0)
+ sprintf(nbuf, "%u", value);
+ return (nbuf);
+}
+
+/*
+ * Return a string for the rcode.
+ */
+const char *
+p_rcode(int rcode) {
+ return (sym_ntos(__res_p_rcode_syms, rcode, (int *)0));
+}
+
+/*
+ * routines to convert between on-the-wire RR format and zone file format.
+ * Does not contain conversion to/from decimal degrees; divide or multiply
+ * by 60*60*1000 for that.
+ */
+
+static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000,
+ 1000000,10000000,100000000,1000000000};
+
+/* takes an XeY precision/size value, returns a string representation. */
+static const char *
+precsize_ntoa(prec)
+ u_int8_t prec;
+{
+ static char retbuf[sizeof "90000000.00"]; /* XXX nonreentrant */
+ unsigned long val;
+ int mantissa, exponent;
+
+ mantissa = (int)((prec >> 4) & 0x0f) % 10;
+ exponent = (int)((prec >> 0) & 0x0f) % 10;
+
+ val = mantissa * poweroften[exponent];
+
+ (void) sprintf(retbuf, "%lu.%.2lu", val/100, val%100);
+ return (retbuf);
+}
+
+/* converts ascii size/precision X * 10**Y(cm) to 0xXY. moves pointer. */
+static u_int8_t
+precsize_aton(const char **strptr) {
+ unsigned int mval = 0, cmval = 0;
+ u_int8_t retval = 0;
+ const char *cp;
+ int exponent;
+ int mantissa;
+
+ cp = *strptr;
+
+ while (isdigit((unsigned char)*cp))
+ mval = mval * 10 + (*cp++ - '0');
+
+ if (*cp == '.') { /* centimeters */
+ cp++;
+ if (isdigit((unsigned char)*cp)) {
+ cmval = (*cp++ - '0') * 10;
+ if (isdigit((unsigned char)*cp)) {
+ cmval += (*cp++ - '0');
+ }
+ }
+ }
+ cmval = (mval * 100) + cmval;
+
+ for (exponent = 0; exponent < 9; exponent++)
+ if (cmval < poweroften[exponent+1])
+ break;
+
+ mantissa = cmval / poweroften[exponent];
+ if (mantissa > 9)
+ mantissa = 9;
+
+ retval = (mantissa << 4) | exponent;
+
+ *strptr = cp;
+
+ return (retval);
+}
+
+/* converts ascii lat/lon to unsigned encoded 32-bit number. moves pointer. */
+static u_int32_t
+latlon2ul(const char **latlonstrptr, int *which) {
+ const char *cp;
+ u_int32_t retval;
+ int deg = 0, min = 0, secs = 0, secsfrac = 0;
+
+ cp = *latlonstrptr;
+
+ while (isdigit((unsigned char)*cp))
+ deg = deg * 10 + (*cp++ - '0');
+
+ while (isspace((unsigned char)*cp))
+ cp++;
+
+ if (!(isdigit((unsigned char)*cp)))
+ goto fndhemi;
+
+ while (isdigit((unsigned char)*cp))
+ min = min * 10 + (*cp++ - '0');
+
+ while (isspace((unsigned char)*cp))
+ cp++;
+
+ if (!(isdigit((unsigned char)*cp)))
+ goto fndhemi;
+
+ while (isdigit((unsigned char)*cp))
+ secs = secs * 10 + (*cp++ - '0');
+
+ if (*cp == '.') { /* decimal seconds */
+ cp++;
+ if (isdigit((unsigned char)*cp)) {
+ secsfrac = (*cp++ - '0') * 100;
+ if (isdigit((unsigned char)*cp)) {
+ secsfrac += (*cp++ - '0') * 10;
+ if (isdigit((unsigned char)*cp)) {
+ secsfrac += (*cp++ - '0');
+ }
+ }
+ }
+ }
+
+ while (!isspace((unsigned char)*cp)) /* if any trailing garbage */
+ cp++;
+
+ while (isspace((unsigned char)*cp))
+ cp++;
+
+ fndhemi:
+ switch (*cp) {
+ case 'N': case 'n':
+ case 'E': case 'e':
+ retval = ((unsigned)1<<31)
+ + (((((deg * 60) + min) * 60) + secs) * 1000)
+ + secsfrac;
+ break;
+ case 'S': case 's':
+ case 'W': case 'w':
+ retval = ((unsigned)1<<31)
+ - (((((deg * 60) + min) * 60) + secs) * 1000)
+ - secsfrac;
+ break;
+ default:
+ retval = 0; /* invalid value -- indicates error */
+ break;
+ }
+
+ switch (*cp) {
+ case 'N': case 'n':
+ case 'S': case 's':
+ *which = 1; /* latitude */
+ break;
+ case 'E': case 'e':
+ case 'W': case 'w':
+ *which = 2; /* longitude */
+ break;
+ default:
+ *which = 0; /* error */
+ break;
+ }
+
+ cp++; /* skip the hemisphere */
+
+ while (!isspace((unsigned char)*cp)) /* if any trailing garbage */
+ cp++;
+
+ while (isspace((unsigned char)*cp)) /* move to next field */
+ cp++;
+
+ *latlonstrptr = cp;
+
+ return (retval);
+}
+
+/* converts a zone file representation in a string to an RDATA on-the-wire
+ * representation. */
+int
+loc_aton(ascii, binary)
+ const char *ascii;
+ u_char *binary;
+{
+ const char *cp, *maxcp;
+ u_char *bcp;
+
+ u_int32_t latit = 0, longit = 0, alt = 0;
+ u_int32_t lltemp1 = 0, lltemp2 = 0;
+ int altmeters = 0, altfrac = 0, altsign = 1;
+ u_int8_t hp = 0x16; /* default = 1e6 cm = 10000.00m = 10km */
+ u_int8_t vp = 0x13; /* default = 1e3 cm = 10.00m */
+ u_int8_t siz = 0x12; /* default = 1e2 cm = 1.00m */
+ int which1 = 0, which2 = 0;
+
+ cp = ascii;
+ maxcp = cp + strlen(ascii);
+
+ lltemp1 = latlon2ul(&cp, &which1);
+
+ lltemp2 = latlon2ul(&cp, &which2);
+
+ switch (which1 + which2) {
+ case 3: /* 1 + 2, the only valid combination */
+ if ((which1 == 1) && (which2 == 2)) { /* normal case */
+ latit = lltemp1;
+ longit = lltemp2;
+ } else if ((which1 == 2) && (which2 == 1)) { /* reversed */
+ longit = lltemp1;
+ latit = lltemp2;
+ } else { /* some kind of brokenness */
+ return (0);
+ }
+ break;
+ default: /* we didn't get one of each */
+ return (0);
+ }
+
+ /* altitude */
+ if (*cp == '-') {
+ altsign = -1;
+ cp++;
+ }
+
+ if (*cp == '+')
+ cp++;
+
+ while (isdigit((unsigned char)*cp))
+ altmeters = altmeters * 10 + (*cp++ - '0');
+
+ if (*cp == '.') { /* decimal meters */
+ cp++;
+ if (isdigit((unsigned char)*cp)) {
+ altfrac = (*cp++ - '0') * 10;
+ if (isdigit((unsigned char)*cp)) {
+ altfrac += (*cp++ - '0');
+ }
+ }
+ }
+
+ alt = (10000000 + (altsign * (altmeters * 100 + altfrac)));
+
+ while (!isspace((unsigned char)*cp) && (cp < maxcp)) /* if trailing garbage or m */
+ cp++;
+
+ while (isspace((unsigned char)*cp) && (cp < maxcp))
+ cp++;
+
+ if (cp >= maxcp)
+ goto defaults;
+
+ siz = precsize_aton(&cp);
+
+ while (!isspace((unsigned char)*cp) && (cp < maxcp)) /* if trailing garbage or m */
+ cp++;
+
+ while (isspace((unsigned char)*cp) && (cp < maxcp))
+ cp++;
+
+ if (cp >= maxcp)
+ goto defaults;
+
+ hp = precsize_aton(&cp);
+
+ while (!isspace((unsigned char)*cp) && (cp < maxcp)) /* if trailing garbage or m */
+ cp++;
+
+ while (isspace((unsigned char)*cp) && (cp < maxcp))
+ cp++;
+
+ if (cp >= maxcp)
+ goto defaults;
+
+ vp = precsize_aton(&cp);
+
+ defaults:
+
+ bcp = binary;
+ *bcp++ = (u_int8_t) 0; /* version byte */
+ *bcp++ = siz;
+ *bcp++ = hp;
+ *bcp++ = vp;
+ NS_PUT32(latit,bcp);
+ NS_PUT32(longit,bcp);
+ NS_PUT32(alt,bcp);
+
+ return (16); /* size of RR in octets */
+}
+
+/* takes an on-the-wire LOC RR and formats it in a human readable format. */
+const char *
+loc_ntoa(binary, ascii)
+ const u_char *binary;
+ char *ascii;
+{
+ static const char *error = "?";
+ static char tmpbuf[sizeof
+"1000 60 60.000 N 1000 60 60.000 W -12345678.00m 90000000.00m 90000000.00m 90000000.00m"];
+ const u_char *cp = binary;
+
+ int latdeg, latmin, latsec, latsecfrac;
+ int longdeg, longmin, longsec, longsecfrac;
+ char northsouth, eastwest;
+ const char *altsign;
+ int altmeters, altfrac;
+
+ const u_int32_t referencealt = 100000 * 100;
+
+ int32_t latval, longval, altval;
+ u_int32_t templ;
+ u_int8_t sizeval, hpval, vpval, versionval;
+
+ char *sizestr, *hpstr, *vpstr;
+
+ versionval = *cp++;
+
+ if (ascii == NULL)
+ ascii = tmpbuf;
+
+ if (versionval) {
+ (void) sprintf(ascii, "; error: unknown LOC RR version");
+ return (ascii);
+ }
+
+ sizeval = *cp++;
+
+ hpval = *cp++;
+ vpval = *cp++;
+
+ NS_GET32(templ, cp);
+ latval = (templ - ((unsigned)1<<31));
+
+ NS_GET32(templ, cp);
+ longval = (templ - ((unsigned)1<<31));
+
+ NS_GET32(templ, cp);
+ if (templ < referencealt) { /* below WGS 84 spheroid */
+ altval = referencealt - templ;
+ altsign = "-";
+ } else {
+ altval = templ - referencealt;
+ altsign = "";
+ }
+
+ if (latval < 0) {
+ northsouth = 'S';
+ latval = -latval;
+ } else
+ northsouth = 'N';
+
+ latsecfrac = latval % 1000;
+ latval = latval / 1000;
+ latsec = latval % 60;
+ latval = latval / 60;
+ latmin = latval % 60;
+ latval = latval / 60;
+ latdeg = latval;
+
+ if (longval < 0) {
+ eastwest = 'W';
+ longval = -longval;
+ } else
+ eastwest = 'E';
+
+ longsecfrac = longval % 1000;
+ longval = longval / 1000;
+ longsec = longval % 60;
+ longval = longval / 60;
+ longmin = longval % 60;
+ longval = longval / 60;
+ longdeg = longval;
+
+ altfrac = altval % 100;
+ altmeters = (altval / 100);
+
+ sizestr = strdup(precsize_ntoa(sizeval));
+ hpstr = strdup(precsize_ntoa(hpval));
+ vpstr = strdup(precsize_ntoa(vpval));
+
+ sprintf(ascii,
+ "%d %.2d %.2d.%.3d %c %d %.2d %.2d.%.3d %c %s%d.%.2dm %sm %sm %sm",
+ latdeg, latmin, latsec, latsecfrac, northsouth,
+ longdeg, longmin, longsec, longsecfrac, eastwest,
+ altsign, altmeters, altfrac,
+ (sizestr != NULL) ? sizestr : error,
+ (hpstr != NULL) ? hpstr : error,
+ (vpstr != NULL) ? vpstr : error);
+
+ if (sizestr != NULL)
+ free(sizestr);
+ if (hpstr != NULL)
+ free(hpstr);
+ if (vpstr != NULL)
+ free(vpstr);
+
+ return (ascii);
+}
+
+
+/* Return the number of DNS hierarchy levels in the name. */
+int
+dn_count_labels(const char *name) {
+ int i, len, count;
+
+ len = strlen(name);
+ for (i = 0, count = 0; i < len; i++) {
+ /* XXX need to check for \. or use named's nlabels(). */
+ if (name[i] == '.')
+ count++;
+ }
+
+ /* don't count initial wildcard */
+ if (name[0] == '*')
+ if (count)
+ count--;
+
+ /* don't count the null label for root. */
+ /* if terminating '.' not found, must adjust */
+ /* count to include last label */
+ if (len > 0 && name[len-1] != '.')
+ count++;
+ return (count);
+}
+
+
+/*
+ * Make dates expressed in seconds-since-Jan-1-1970 easy to read.
+ * SIG records are required to be printed like this, by the Secure DNS RFC.
+ */
+char *
+p_secstodate (u_long secs) {
+ /* XXX nonreentrant */
+ static char output[15]; /* YYYYMMDDHHMMSS and null */
+ time_t clock = secs;
+ struct tm *time;
+
+#ifdef HAVE_TIME_R
+ gmtime_r(&clock, &time);
+#else
+ time = gmtime(&clock);
+#endif
+ time->tm_year += 1900;
+ time->tm_mon += 1;
+ sprintf(output, "%04d%02d%02d%02d%02d%02d",
+ time->tm_year, time->tm_mon, time->tm_mday,
+ time->tm_hour, time->tm_min, time->tm_sec);
+ return (output);
+}
+
+u_int16_t
+res_nametoclass(const char *buf, int *successp) {
+ unsigned long result;
+ char *endptr;
+ int success;
+
+ result = sym_ston(__res_p_class_syms, buf, &success);
+ if (success)
+ goto done;
+
+ if (strncasecmp(buf, "CLASS", 5) != 0 ||
+ !isdigit((unsigned char)buf[5]))
+ goto done;
+ result = strtoul(buf + 5, &endptr, 10);
+ if (*endptr == '\0' && result <= 0xffff)
+ success = 1;
+ done:
+ if (successp)
+ *successp = success;
+ return (result);
+}
+
+u_int16_t
+res_nametotype(const char *buf, int *successp) {
+ unsigned long result;
+ char *endptr;
+ int success;
+
+ result = sym_ston(__p_type_syms, buf, &success);
+ if (success)
+ goto done;
+
+ if (strncasecmp(buf, "type", 4) != 0 ||
+ !isdigit((unsigned char)buf[4]))
+ goto done;
+ result = strtoul(buf + 4, &endptr, 10);
+ if (*endptr == '\0' && result <= 0xffff)
+ success = 1;
+ done:
+ if (successp)
+ *successp = success;
+ return (result);
+}
--- /dev/null
+/*
+ * Copyright (c) 1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#ifndef _RES_DEBUG_H_
+#define _RES_DEBUG_H_
+
+#ifndef DEBUG
+# define Dprint(cond, args) /*empty*/
+# define DprintQ(cond, args, query, size) /*empty*/
+# define Aerror(statp, file, string, error, address) /*empty*/
+# define Perror(statp, file, string, error) /*empty*/
+#else
+# define Dprint(cond, args) if (cond) {fprintf args;} else {}
+# define DprintQ(cond, args, query, size) if (cond) {\
+ fprintf args;\
+ res_pquery(statp, query, size, stdout);\
+ } else {}
+#endif
+
+#endif /* _RES_DEBUG_H_ */
--- /dev/null
+#ifndef __APPLE__
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: res_findzonecut.c,v 1.1 2006/03/01 19:01:38 majka Exp $";
+#endif /* not lint */
+#endif
+
+/*
+ * Copyright (c) 1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/* Import. */
+
+#ifndef __APPLE__
+#include "port_before.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef __APPLE__
+#include <isc/list.h>
+#include "port_after.h"
+#else
+#include <res_update.h>
+#endif
+
+#include <resolv.h>
+
+/* Data structures. */
+
+typedef struct rr_a {
+ LINK(struct rr_a) link;
+ union res_sockaddr_union addr;
+} rr_a;
+typedef LIST(rr_a) rrset_a;
+
+typedef struct rr_ns {
+ LINK(struct rr_ns) link;
+ const char * name;
+ int have_v4;
+ int have_v6;
+ rrset_a addrs;
+} rr_ns;
+typedef LIST(rr_ns) rrset_ns;
+
+/* Forward. */
+
+static int satisfy(res_state, const char *, rrset_ns *,
+ union res_sockaddr_union *, int);
+static int add_addrs(res_state, rr_ns *,
+ union res_sockaddr_union *, int);
+static int get_soa(res_state, const char *, ns_class, int,
+ char *, size_t, char *, size_t,
+ rrset_ns *);
+static int get_ns(res_state, const char *, ns_class, int, rrset_ns *);
+static int get_glue(res_state, ns_class, int, rrset_ns *);
+static int save_ns(res_state, ns_msg *, ns_sect,
+ const char *, ns_class, int, rrset_ns *);
+static int save_a(res_state, ns_msg *, ns_sect,
+ const char *, ns_class, int, rr_ns *);
+static void free_nsrrset(rrset_ns *);
+static void free_nsrr(rrset_ns *, rr_ns *);
+static rr_ns * find_ns(rrset_ns *, const char *);
+static int do_query(res_state, const char *, ns_class, ns_type,
+ u_char *, ns_msg *);
+#ifndef __APPLE__
+static void res_dprintf(const char *, ...) ISC_FORMAT_PRINTF(1, 2);
+#else
+static void res_dprintf(const char *, ...);
+#endif
+
+/* Macros. */
+
+#define DPRINTF(x) do {\
+ int save_errno = errno; \
+ if ((statp->options & RES_DEBUG) != 0) res_dprintf x; \
+ errno = save_errno; \
+ } while (0)
+
+/* Public. */
+
+/*
+ * int
+ * res_findzonecut(res, dname, class, zname, zsize, addrs, naddrs)
+ * find enclosing zone for a <dname,class>, and some server addresses
+ * parameters:
+ * res - resolver context to work within (is modified)
+ * dname - domain name whose enclosing zone is desired
+ * class - class of dname (and its enclosing zone)
+ * zname - found zone name
+ * zsize - allocated size of zname
+ * addrs - found server addresses
+ * naddrs - max number of addrs
+ * return values:
+ * < 0 - an error occurred (check errno)
+ * = 0 - zname is now valid, but addrs[] wasn't changed
+ * > 0 - zname is now valid, and return value is number of addrs[] found
+ * notes:
+ * this function calls res_nsend() which means it depends on correctly
+ * functioning recursive nameservers (usually defined in /etc/resolv.conf
+ * or its local equivilent).
+ *
+ * we start by asking for an SOA<dname,class>. if we get one as an
+ * answer, that just means <dname,class> is a zone top, which is fine.
+ * more than likely we'll be told to go pound sand, in the form of a
+ * negative answer.
+ *
+ * note that we are not prepared to deal with referrals since that would
+ * only come from authority servers and our correctly functioning local
+ * recursive server would have followed the referral and got us something
+ * more definite.
+ *
+ * if the authority section contains an SOA, this SOA should also be the
+ * closest enclosing zone, since any intermediary zone cuts would've been
+ * returned as referrals and dealt with by our correctly functioning local
+ * recursive name server. but an SOA in the authority section should NOT
+ * match our dname (since that would have been returned in the answer
+ * section). an authority section SOA has to be "above" our dname.
+ *
+ * however, since authority section SOA's were once optional, it's
+ * possible that we'll have to go hunting for the enclosing SOA by
+ * ripping labels off the front of our dname -- this is known as "doing
+ * it the hard way."
+ *
+ * ultimately we want some server addresses, which are ideally the ones
+ * pertaining to the SOA.MNAME, but only if there is a matching NS RR.
+ * so the second phase (after we find an SOA) is to go looking for the
+ * NS RRset for that SOA's zone.
+ *
+ * no answer section processed by this code is allowed to contain CNAME
+ * or DNAME RR's. for the SOA query this means we strip a label and
+ * keep going. for the NS and A queries this means we just give up.
+ */
+
+int
+res_findzonecut(res_state statp, const char *dname, ns_class class, int opts,
+ char *zname, size_t zsize, struct in_addr *addrs, int naddrs) {
+ int result, i;
+ union res_sockaddr_union *u;
+
+
+ opts |= RES_IPV4ONLY;
+ opts &= ~RES_IPV6ONLY;
+
+ u = calloc(naddrs, sizeof(*u));
+ if (u == NULL)
+ return(-1);
+
+ result = res_findzonecut2(statp, dname, class, opts, zname, zsize,
+ u, naddrs);
+
+ for (i = 0; i < result; i++) {
+ addrs[i] = u[i].sin.sin_addr;
+ }
+ free(u);
+ return (result);
+}
+
+int
+res_findzonecut2(res_state statp, const char *dname, ns_class class, int opts,
+ char *zname, size_t zsize, union res_sockaddr_union *addrs,
+ int naddrs)
+{
+ char mname[NS_MAXDNAME];
+ u_long save_pfcode;
+ rrset_ns nsrrs;
+ int n;
+
+ DPRINTF(("START dname='%s' class=%s, zsize=%ld, naddrs=%d",
+ dname, p_class(class), (long)zsize, naddrs));
+ save_pfcode = statp->pfcode;
+ statp->pfcode |= RES_PRF_HEAD2 | RES_PRF_HEAD1 | RES_PRF_HEADX |
+ RES_PRF_QUES | RES_PRF_ANS |
+ RES_PRF_AUTH | RES_PRF_ADD;
+ INIT_LIST(nsrrs);
+
+ DPRINTF(("get the soa, and see if it has enough glue"));
+ if ((n = get_soa(statp, dname, class, opts, zname, zsize,
+ mname, sizeof mname, &nsrrs)) < 0 ||
+ ((opts & RES_EXHAUSTIVE) == 0 &&
+ (n = satisfy(statp, mname, &nsrrs, addrs, naddrs)) > 0))
+ goto done;
+
+ DPRINTF(("get the ns rrset and see if it has enough glue"));
+ if ((n = get_ns(statp, zname, class, opts, &nsrrs)) < 0 ||
+ ((opts & RES_EXHAUSTIVE) == 0 &&
+ (n = satisfy(statp, mname, &nsrrs, addrs, naddrs)) > 0))
+ goto done;
+
+ DPRINTF(("get the missing glue and see if it's finally enough"));
+ if ((n = get_glue(statp, class, opts, &nsrrs)) >= 0)
+ n = satisfy(statp, mname, &nsrrs, addrs, naddrs);
+
+ done:
+ DPRINTF(("FINISH n=%d (%s)", n, (n < 0) ? strerror(errno) : "OK"));
+ free_nsrrset(&nsrrs);
+ statp->pfcode = save_pfcode;
+ return (n);
+}
+
+/* Private. */
+
+static int
+satisfy(res_state statp, const char *mname, rrset_ns *nsrrsp,
+ union res_sockaddr_union *addrs, int naddrs)
+{
+ rr_ns *nsrr;
+ int n, x;
+
+ n = 0;
+ nsrr = find_ns(nsrrsp, mname);
+ if (nsrr != NULL) {
+ x = add_addrs(statp, nsrr, addrs, naddrs);
+ addrs += x;
+ naddrs -= x;
+ n += x;
+ }
+ for (nsrr = HEAD(*nsrrsp);
+ nsrr != NULL && naddrs > 0;
+ nsrr = NEXT(nsrr, link))
+ if (ns_samename(nsrr->name, mname) != 1) {
+ x = add_addrs(statp, nsrr, addrs, naddrs);
+ addrs += x;
+ naddrs -= x;
+ n += x;
+ }
+ DPRINTF(("satisfy(%s): %d", mname, n));
+ return (n);
+}
+
+static int
+add_addrs(res_state statp, rr_ns *nsrr,
+ union res_sockaddr_union *addrs, int naddrs)
+{
+ rr_a *arr;
+ int n = 0;
+
+ for (arr = HEAD(nsrr->addrs); arr != NULL; arr = NEXT(arr, link)) {
+ if (naddrs <= 0)
+ return (0);
+ *addrs++ = arr->addr;
+ naddrs--;
+ n++;
+ }
+ DPRINTF(("add_addrs: %d", n));
+ return (n);
+}
+
+static int
+get_soa(res_state statp, const char *dname, ns_class class, int opts,
+ char *zname, size_t zsize, char *mname, size_t msize,
+ rrset_ns *nsrrsp)
+{
+ char tname[NS_MAXDNAME];
+ u_char resp[NS_PACKETSZ];
+ int n, i, ancount, nscount;
+ ns_sect sect;
+ ns_msg msg;
+ u_int rcode;
+
+ /*
+ * Find closest enclosing SOA, even if it's for the root zone.
+ */
+
+ /* First canonicalize dname (exactly one unescaped trailing "."). */
+ if (ns_makecanon(dname, tname, sizeof tname) < 0)
+ return (-1);
+ dname = tname;
+
+ /* Now grovel the subdomains, hunting for an SOA answer or auth. */
+ for (;;) {
+ /* Leading or inter-label '.' are skipped here. */
+ while (*dname == '.')
+ dname++;
+
+ /* Is there an SOA? */
+ n = do_query(statp, dname, class, ns_t_soa, resp, &msg);
+ if (n < 0) {
+ DPRINTF(("get_soa: do_query('%s', %s) failed (%d)",
+ dname, p_class(class), n));
+ return (-1);
+ }
+ if (n > 0) {
+ DPRINTF(("get_soa: CNAME or DNAME found"));
+ sect = ns_s_max, n = 0;
+ } else {
+ rcode = ns_msg_getflag(msg, ns_f_rcode);
+ ancount = ns_msg_count(msg, ns_s_an);
+ nscount = ns_msg_count(msg, ns_s_ns);
+ if (ancount > 0 && rcode == ns_r_noerror)
+ sect = ns_s_an, n = ancount;
+ else if (nscount > 0)
+ sect = ns_s_ns, n = nscount;
+ else
+ sect = ns_s_max, n = 0;
+ }
+ for (i = 0; i < n; i++) {
+ const char *t;
+ const u_char *rdata;
+ int rdlen;
+ ns_rr rr;
+
+ if (ns_parserr(&msg, sect, i, &rr) < 0) {
+ DPRINTF(("get_soa: ns_parserr(%s, %d) failed",
+ p_section(sect, ns_o_query), i));
+ return (-1);
+ }
+ if (ns_rr_type(rr) == ns_t_cname ||
+ ns_rr_type(rr) == ns_t_dname)
+ break;
+ if (ns_rr_type(rr) != ns_t_soa ||
+ ns_rr_class(rr) != class)
+ continue;
+ t = ns_rr_name(rr);
+ switch (sect) {
+ case ns_s_an:
+ if (ns_samedomain(dname, t) == 0) {
+ DPRINTF(("get_soa: ns_samedomain('%s', '%s') == 0",
+ dname, t));
+ errno = EPROTOTYPE;
+ return (-1);
+ }
+ break;
+ case ns_s_ns:
+ if (ns_samename(dname, t) == 1 ||
+ ns_samedomain(dname, t) == 0) {
+ DPRINTF(("get_soa: ns_samename() || !ns_samedomain('%s', '%s')",
+ dname, t));
+ errno = EPROTOTYPE;
+ return (-1);
+ }
+ break;
+ default:
+ abort();
+ }
+ if (strlen(t) + 1 > zsize) {
+ DPRINTF(("get_soa: zname(%d) too small (%d)",
+ zsize, strlen(t) + 1));
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ strcpy(zname, t);
+ rdata = ns_rr_rdata(rr);
+ rdlen = ns_rr_rdlen(rr);
+ if (ns_name_uncompress(resp, ns_msg_end(msg), rdata,
+ mname, msize) < 0) {
+ DPRINTF(("get_soa: ns_name_uncompress failed"));
+ return (-1);
+ }
+ if (save_ns(statp, &msg, ns_s_ns,
+ zname, class, opts, nsrrsp) < 0) {
+ DPRINTF(("get_soa: save_ns failed"));
+ return (-1);
+ }
+ return (0);
+ }
+
+ /* If we're out of labels, then not even "." has an SOA! */
+ if (*dname == '\0')
+ break;
+
+ /* Find label-terminating "."; top of loop will skip it. */
+ while (*dname != '.') {
+ if (*dname == '\\')
+ if (*++dname == '\0') {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ dname++;
+ }
+ }
+ DPRINTF(("get_soa: out of labels"));
+ errno = EDESTADDRREQ;
+ return (-1);
+}
+
+static int
+get_ns(res_state statp, const char *zname, ns_class class, int opts,
+ rrset_ns *nsrrsp)
+{
+ u_char resp[NS_PACKETSZ];
+ ns_msg msg;
+ int n;
+
+ /* Go and get the NS RRs for this zone. */
+ n = do_query(statp, zname, class, ns_t_ns, resp, &msg);
+ if (n != 0) {
+ DPRINTF(("get_ns: do_query('%s', %s) failed (%d)",
+ zname, p_class(class), n));
+ return (-1);
+ }
+
+ /* Remember the NS RRs and associated A RRs that came back. */
+ if (save_ns(statp, &msg, ns_s_an, zname, class, opts, nsrrsp) < 0) {
+ DPRINTF(("get_ns save_ns('%s', %s) failed",
+ zname, p_class(class)));
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+get_glue(res_state statp, ns_class class, int opts, rrset_ns *nsrrsp) {
+ rr_ns *nsrr, *nsrr_n;
+
+ /* Go and get the A RRs for each empty NS RR on our list. */
+ for (nsrr = HEAD(*nsrrsp); nsrr != NULL; nsrr = nsrr_n) {
+ u_char resp[NS_PACKETSZ];
+ ns_msg msg;
+ int n;
+
+ nsrr_n = NEXT(nsrr, link);
+
+ if (!nsrr->have_v4) {
+ n = do_query(statp, nsrr->name, class, ns_t_a,
+ resp, &msg);
+ if (n < 0) {
+ DPRINTF(("get_glue: do_query('%s', %s') failed",
+ nsrr->name, p_class(class)));
+ return (-1);
+ }
+ if (n > 0) {
+ DPRINTF((
+ "get_glue: do_query('%s', %s') CNAME or DNAME found",
+ nsrr->name, p_class(class)));
+ }
+ if (save_a(statp, &msg, ns_s_an, nsrr->name, class,
+ opts, nsrr) < 0) {
+ DPRINTF(("get_glue: save_r('%s', %s) failed",
+ nsrr->name, p_class(class)));
+ return (-1);
+ }
+ }
+
+ if (!nsrr->have_v6) {
+ n = do_query(statp, nsrr->name, class, ns_t_aaaa,
+ resp, &msg);
+ if (n < 0) {
+ DPRINTF(("get_glue: do_query('%s', %s') failed",
+ nsrr->name, p_class(class)));
+ return (-1);
+ }
+ if (n > 0) {
+ DPRINTF((
+ "get_glue: do_query('%s', %s') CNAME or DNAME found",
+ nsrr->name, p_class(class)));
+ }
+ if (save_a(statp, &msg, ns_s_an, nsrr->name, class,
+ opts, nsrr) < 0) {
+ DPRINTF(("get_glue: save_r('%s', %s) failed",
+ nsrr->name, p_class(class)));
+ return (-1);
+ }
+ }
+
+ /* If it's still empty, it's just chaff. */
+ if (EMPTY(nsrr->addrs)) {
+ DPRINTF(("get_glue: removing empty '%s' NS",
+ nsrr->name));
+ free_nsrr(nsrrsp, nsrr);
+ }
+ }
+ return (0);
+}
+
+static int
+save_ns(res_state statp, ns_msg *msg, ns_sect sect,
+ const char *owner, ns_class class, int opts,
+ rrset_ns *nsrrsp)
+{
+ int i;
+
+ for (i = 0; i < ns_msg_count(*msg, sect); i++) {
+ char tname[NS_MAXDNAME];
+ const u_char *rdata;
+ rr_ns *nsrr;
+ ns_rr rr;
+ int rdlen;
+
+ if (ns_parserr(msg, sect, i, &rr) < 0) {
+ DPRINTF(("save_ns: ns_parserr(%s, %d) failed",
+ p_section(sect, ns_o_query), i));
+ return (-1);
+ }
+ if (ns_rr_type(rr) != ns_t_ns ||
+ ns_rr_class(rr) != class ||
+ ns_samename(ns_rr_name(rr), owner) != 1)
+ continue;
+ nsrr = find_ns(nsrrsp, ns_rr_name(rr));
+ if (nsrr == NULL) {
+ nsrr = malloc(sizeof *nsrr);
+ if (nsrr == NULL) {
+ DPRINTF(("save_ns: malloc failed"));
+ return (-1);
+ }
+ rdata = ns_rr_rdata(rr);
+ rdlen = ns_rr_rdlen(rr);
+ if (ns_name_uncompress(ns_msg_base(*msg),
+ ns_msg_end(*msg), rdata,
+ tname, sizeof tname) < 0) {
+ DPRINTF(("save_ns: ns_name_uncompress failed"));
+ free(nsrr);
+ return (-1);
+ }
+ nsrr->name = strdup(tname);
+ if (nsrr->name == NULL) {
+ DPRINTF(("save_ns: strdup failed"));
+ free(nsrr);
+ return (-1);
+ }
+ INIT_LINK(nsrr, link);
+ INIT_LIST(nsrr->addrs);
+ nsrr->have_v4 = 0;
+ nsrr->have_v6 = 0;
+ APPEND(*nsrrsp, nsrr, link);
+ }
+ if (save_a(statp, msg, ns_s_ar,
+ nsrr->name, class, opts, nsrr) < 0) {
+ DPRINTF(("save_ns: save_r('%s', %s) failed",
+ nsrr->name, p_class(class)));
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+static int
+save_a(res_state statp, ns_msg *msg, ns_sect sect,
+ const char *owner, ns_class class, int opts,
+ rr_ns *nsrr)
+{
+ int i;
+
+ for (i = 0; i < ns_msg_count(*msg, sect); i++) {
+ ns_rr rr;
+ rr_a *arr;
+
+ if (ns_parserr(msg, sect, i, &rr) < 0) {
+ DPRINTF(("save_a: ns_parserr(%s, %d) failed",
+ p_section(sect, ns_o_query), i));
+ return (-1);
+ }
+ if ((ns_rr_type(rr) != ns_t_a && ns_rr_type(rr) != ns_t_aaaa) ||
+ ns_rr_class(rr) != class ||
+ ns_samename(ns_rr_name(rr), owner) != 1 ||
+ ns_rr_rdlen(rr) != NS_INADDRSZ)
+ continue;
+ if ((opts & RES_IPV6ONLY) != 0 && ns_rr_type(rr) != ns_t_aaaa)
+ continue;
+ if ((opts & RES_IPV4ONLY) != 0 && ns_rr_type(rr) != ns_t_a)
+ continue;
+ arr = malloc(sizeof *arr);
+ if (arr == NULL) {
+ DPRINTF(("save_a: malloc failed"));
+ return (-1);
+ }
+ INIT_LINK(arr, link);
+ memset(&arr->addr, 0, sizeof(arr->addr));
+ switch (ns_rr_type(rr)) {
+ case ns_t_a:
+ arr->addr.sin.sin_family = AF_INET;
+#ifdef HAVE_SA_LEN
+ arr->addr.sin.sin_len = sizeof(arr->addr.sin);
+#endif
+ memcpy(&arr->addr.sin.sin_addr, ns_rr_rdata(rr),
+ NS_INADDRSZ);
+ arr->addr.sin.sin_port = htons(NS_DEFAULTPORT);
+ nsrr->have_v4 = 1;
+ break;
+ case ns_t_aaaa:
+ arr->addr.sin6.sin6_family = AF_INET6;
+#ifdef HAVE_SA_LEN
+ arr->addr.sin6.sin6_len = sizeof(arr->addr.sin6);
+#endif
+ memcpy(&arr->addr.sin6.sin6_addr, ns_rr_rdata(rr), 16);
+ arr->addr.sin.sin_port = htons(NS_DEFAULTPORT);
+ nsrr->have_v6 = 1;
+ break;
+ default:
+ abort();
+ }
+ APPEND(nsrr->addrs, arr, link);
+ }
+ return (0);
+}
+
+static void
+free_nsrrset(rrset_ns *nsrrsp) {
+ rr_ns *nsrr;
+
+ while ((nsrr = HEAD(*nsrrsp)) != NULL)
+ free_nsrr(nsrrsp, nsrr);
+}
+
+static void
+free_nsrr(rrset_ns *nsrrsp, rr_ns *nsrr) {
+ rr_a *arr;
+ char *tmp;
+
+ while ((arr = HEAD(nsrr->addrs)) != NULL) {
+ UNLINK(nsrr->addrs, arr, link);
+ free(arr);
+ }
+#ifdef __APPLE__
+ tmp = (char *)nsrr->name;
+#else
+ DE_CONST(nsrr->name, tmp);
+#endif
+ free(tmp);
+ UNLINK(*nsrrsp, nsrr, link);
+ free(nsrr);
+}
+
+static rr_ns *
+find_ns(rrset_ns *nsrrsp, const char *dname) {
+ rr_ns *nsrr;
+
+ for (nsrr = HEAD(*nsrrsp); nsrr != NULL; nsrr = NEXT(nsrr, link))
+ if (ns_samename(nsrr->name, dname) == 1)
+ return (nsrr);
+ return (NULL);
+}
+
+static int
+do_query(res_state statp, const char *dname, ns_class class, ns_type qtype,
+ u_char *resp, ns_msg *msg)
+{
+ u_char req[NS_PACKETSZ];
+ int i, n;
+
+ n = res_nmkquery(statp, ns_o_query, dname, class, qtype,
+ NULL, 0, NULL, req, NS_PACKETSZ);
+ if (n < 0) {
+ DPRINTF(("do_query: res_nmkquery failed"));
+ return (-1);
+ }
+ n = res_nsend(statp, req, n, resp, NS_PACKETSZ);
+ if (n < 0) {
+ DPRINTF(("do_query: res_nsend failed"));
+ return (-1);
+ }
+ if (n == 0) {
+ DPRINTF(("do_query: res_nsend returned 0"));
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (ns_initparse(resp, n, msg) < 0) {
+ DPRINTF(("do_query: ns_initparse failed"));
+ return (-1);
+ }
+ n = 0;
+ for (i = 0; i < ns_msg_count(*msg, ns_s_an); i++) {
+ ns_rr rr;
+
+ if (ns_parserr(msg, ns_s_an, i, &rr) < 0) {
+ DPRINTF(("do_query: ns_parserr failed"));
+ return (-1);
+ }
+ n += (ns_rr_class(rr) == class &&
+ (ns_rr_type(rr) == ns_t_cname ||
+ ns_rr_type(rr) == ns_t_dname));
+ }
+ return (n);
+}
+
+static void
+res_dprintf(const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ fputs(";; res_findzonecut: ", stderr);
+ vfprintf(stderr, fmt, ap);
+ fputc('\n', stderr);
+ va_end(ap);
+}
--- /dev/null
+/*
+ * Copyright (c) 1985, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93";
+static const char rcsid[] = "$Id: res_init.c,v 1.1 2006/03/01 19:01:38 majka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#ifndef __APPLE__
+#include "port_before.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+#ifdef __APPLE__
+#include <fcntl.h>
+#include <dnsinfo.h>
+#endif
+
+#ifndef __APPLE__
+#include "port_after.h"
+#endif
+
+/* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */
+#include <resolv.h>
+
+#include "res_private.h"
+
+/* Options. Should all be left alone. */
+#define RESOLVSORT
+#define DEBUG
+
+static void res_setoptions __P((res_state, const char *, const char *));
+extern res_state res_state_new();
+
+#ifdef RESOLVSORT
+static const char sort_mask[] = "/&";
+#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
+static u_int32_t net_mask __P((struct in_addr));
+#endif
+
+#if !defined(isascii) /* XXX - could be a function */
+# define isascii(c) (!(c & 0200))
+#endif
+
+#define INET_NTOP_AF_INET_OFFSET 4
+#define INET_NTOP_AF_INET6_OFFSET 8
+
+/*
+ * Resolver state default settings.
+ */
+
+res_state
+res_build_start(res_state x)
+{
+ res_state res;
+ int rf;
+
+ res = NULL;
+
+ if (x == NULL)
+ {
+ res = res_state_new();
+ }
+ else
+ {
+ if ((x->options & RES_INIT) != 0) res_ndestroy(x);
+ res = x;
+ }
+
+ if (res == NULL) return NULL;
+
+ /* res_ndestroy frees _u._ext.ext so we create a new one if necessary */
+ if (res->_u._ext.ext == NULL) res->_u._ext.ext = (struct __res_state_ext *)calloc(1, sizeof(struct __res_state_ext));
+
+ /* make sure version is set */
+ res->_pad = 9;
+
+ res->retry = RES_DFLRETRY;
+ res->options = RES_DEFAULT;
+
+ rf = open("/dev/random", O_RDONLY, 0);
+ read(rf, &(res->id), 2);
+ close(rf);
+
+ res->ndots = 1;
+ res->_vcsock = -1;
+
+ if (res->_u._ext.ext != NULL)
+ {
+ strcpy(res->_u._ext.ext->nsuffix, "ip6.arpa");
+ strcpy(res->_u._ext.ext->nsuffix2, "ip6.int");
+ strcpy(res->_u._ext.ext->bsuffix, "ip6.arpa");
+ }
+
+ return res;
+}
+
+int
+res_build_finish(res_state res, uint32_t timeout, uint16_t port)
+{
+ if (res == NULL) return -1;
+
+ if (res->nscount == 0)
+ {
+#ifdef USELOOPBACK
+ res->nsaddr_list[0].sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
+#else
+ res->nsaddr_list[0].sin_addr.s_addr = INADDR_ANY;
+#endif
+
+ res->nsaddr_list[0].sin_family = AF_INET;
+ res->nsaddr_list[0].sin_port = htons(port);
+#ifdef HAVE_SA_LEN
+ res->nsaddr_list[0].sin_len = sizeof(struct sockaddr_in);
+#endif
+
+ res->nscount = 1;
+
+ /*
+ * Force loopback queries to use TCP
+ * so we don't take a timeout if named isn't running.
+ */
+ res->options |= RES_USEVC;
+ }
+
+ if (timeout == 0) res->retrans = RES_MAXRETRANS;
+ else res->retrans = timeout;
+
+ res->options |= RES_INIT;
+ return 0;
+}
+
+int
+res_build_sortlist(res_state res, struct in_addr addr, struct in_addr mask)
+{
+ uint32_t n;
+
+ if (res == NULL) return -1;
+
+ n = res->nsort;
+ if (n >= MAXRESOLVSORT) return -1;
+
+ res->sort_list[n].addr = addr;
+ res->sort_list[n].mask = mask.s_addr;
+ n++;
+ res->nsort = n;
+
+ return 0;
+}
+
+char *
+res_next_word(char **p)
+{
+ char *s, *x;
+
+ if (p == NULL) return NULL;
+ if (*p == NULL) return NULL;
+
+ s = *p;
+
+ /* Skip leading white space */
+ while ((*s == ' ') || (*s == '\t') || (*s == '\n')) s++;
+ *p = s;
+
+ if (*s == '\0') return NULL;
+
+ /* Find end of word */
+ x = s;
+ while ((*x != ' ') && (*x != '\t') && (*x != '\n') && (*x != '\0')) x++;
+ if (*x != '\0')
+ {
+ *x = '\0';
+ x++;
+ }
+
+ *p = x;
+
+ if (s == x) return NULL;
+ return s;
+}
+
+int
+res_build(res_state res, uint16_t port, uint32_t *nsrch, char *key, char *val)
+{
+ int32_t dotcount, semicount, status;
+ int32_t ival, len;
+ char *p, *lastdot;
+ uint16_t aport;
+ struct in_addr addr4, mask;
+ struct sockaddr_in sin4;
+ struct in6_addr addr6;
+ struct sockaddr_in6 sin6;
+
+ if (res == NULL) return -1;
+
+ if (!strcmp(key, "domain"))
+ {
+ strncpy(res->defdname, val, sizeof(res->defdname) - 1);
+ res->defdname[sizeof(res->defdname) - 1] = '\0';
+ return 0;
+ }
+
+ else if (!strcmp(key, "search"))
+ {
+ len = strlen(val) + 1;
+ ival = sizeof(res->defdname);
+ p = res->defdname;
+
+ if ((*nsrch) == 0)
+ {
+ memset(res->defdname, 0, sizeof(res->defdname));
+ }
+ else
+ {
+ p = res->dnsrch[*nsrch - 1];
+ for (; (ival > 0) && (*p != '\0'); ival--) p++;
+ if (*p == '\0') p++;
+ }
+
+ if (len > ival) return -1;
+
+ memcpy(p, val, len);
+ res->dnsrch[*nsrch] = p;
+ *nsrch = *nsrch + 1;
+ return 0;
+ }
+
+ else if (!strcmp(key, "nameserver"))
+ {
+ dotcount = 0;
+ semicount = 0;
+ lastdot = NULL;
+ aport = port;
+
+ for (p = val; *p != '\0'; p++)
+ {
+ if (*p == ':') semicount++;
+ else if (*p == '.')
+ {
+ dotcount++;
+ lastdot = p;
+ }
+ }
+
+ if ((dotcount == 4) || ((semicount > 0) && (lastdot != NULL)))
+ {
+ aport = atoi(lastdot + 1);
+ if (aport == 0) aport = port;
+ *lastdot = '\0';
+ }
+
+ memset(&addr4, 0, sizeof(struct in_addr));
+ memset(&sin4, 0, sizeof(struct sockaddr_in));
+
+ memset(&addr6, 0, sizeof(struct in6_addr));
+ memset(&sin6, 0, sizeof(struct sockaddr_in6));
+
+ status = inet_pton(AF_INET6, val, &addr6);
+ if (status == 1)
+ {
+ sin6.sin6_addr = addr6;
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_port = htons(aport);
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ if (res->_u._ext.ext != NULL)
+ {
+ memcpy(&(res->_u._ext.ext->nsaddrs[res->nscount]), &sin6, sizeof(struct sockaddr_in6));
+ }
+ res->nsaddr_list[res->nscount].sin_family = 0;
+ res->nscount++;
+ }
+ else
+ {
+ status = inet_pton(AF_INET, val, &addr4);
+ if (status == 1)
+ {
+ sin4.sin_addr = addr4;
+ sin4.sin_family = AF_INET;
+ sin4.sin_port = htons(aport);
+ sin4.sin_len = sizeof(struct sockaddr_in);
+ if (res->_u._ext.ext != NULL)
+ {
+ memcpy(&(res->_u._ext.ext->nsaddrs[res->nscount]), &sin4, sizeof(struct sockaddr_in));
+ }
+ memcpy(&(res->nsaddr_list[res->nscount]), &sin4, sizeof(struct sockaddr_in));
+ res->nscount++;
+ }
+ }
+
+ return 0;
+ }
+
+ else if (!strcmp(key, "sortlist"))
+ {
+ p = strchr(val, '/');
+
+ if (p != NULL)
+ {
+ *p = '\0';
+ p++;
+ }
+
+ /* we use inet_aton rather than inet_pton to be compatible with res_init() */
+ status = inet_aton(val, &addr4);
+ if (status == 0) return -1;
+
+ status = 0;
+ if (p != NULL) status = inet_aton(p, &mask);
+ if (status == 0)
+ {
+ ival = ntohl(addr4.s_addr);
+
+ if (IN_CLASSA(ival)) mask.s_addr = htonl(IN_CLASSA_NET);
+ else if (IN_CLASSB(ival)) mask.s_addr = htonl(IN_CLASSB_NET);
+ else mask.s_addr = htonl(IN_CLASSC_NET);
+ }
+
+ return res_build_sortlist(res, addr4, mask);
+ }
+
+ else if (!strcmp(key, "ndots"))
+ {
+ ival = atoi(val);
+ if (ival < 0) ival = 0;
+ if (ival > RES_MAXNDOTS) ival = RES_MAXNDOTS;
+ res->ndots = ival;
+ return 0;
+ }
+
+ else if (!strcmp(key, "nibble"))
+ {
+ if ((strlen(val) + 1) > RES_EXT_SUFFIX_LEN) return -1;
+ if (res->_u._ext.ext == NULL) return -1;
+ strcpy(res->_u._ext.ext->nsuffix, val);
+ return 0;
+ }
+
+ else if (!strcmp(key, "nibble2"))
+ {
+ if ((strlen(val) + 1) > RES_EXT_SUFFIX_LEN) return -1;
+ if (res->_u._ext.ext == NULL) return -1;
+ strcpy(res->_u._ext.ext->nsuffix2, val);
+ return 0;
+ }
+
+ else if (!strcmp(key, "bitstring"))
+ {
+ if ((strlen(val) + 1) > RES_EXT_SUFFIX_LEN) return -1;
+ if (res->_u._ext.ext == NULL) return -1;
+ strcpy(res->_u._ext.ext->bsuffix, val);
+ return 0;
+ }
+
+ else if (!strcmp(key, "attempts"))
+ {
+ ival = atoi(val);
+ if (ival < 0) ival = 0;
+ if (ival > RES_MAXRETRY) ival = RES_MAXRETRY;
+ res->retry = ival;
+ return 0;
+ }
+
+ else if (!strcmp(key, "v6revmode"))
+ {
+ if (!strcmp(val, "single")) res->options |= RES_NO_NIBBLE2;
+ else if (!strcmp(val, "both")) res->options &= ~RES_NO_NIBBLE2;
+ return 0;
+ }
+
+ else if (!strcmp(key, "debug"))
+ {
+ res->options |= RES_DEBUG;
+ return 0;
+ }
+
+ else if (!strcmp(key, "no_tld_query"))
+ {
+ res->options |= RES_NOTLDQUERY;
+ return 0;
+ }
+
+ else if (!strcmp(key, "inet6"))
+ {
+ res->options |= RES_USE_INET6;
+ return 0;
+ }
+
+ else if (!strcmp(key, "rotate"))
+ {
+ res->options |= RES_ROTATE;
+ return 0;
+ }
+
+ else if (!strcmp(key, "no-check-names"))
+ {
+ res->options |= RES_NOCHECKNAME;
+ return 0;
+ }
+
+#ifdef RES_USE_EDNS0
+ else if (!strcmp(key, "edns0"))
+ {
+ res->options |= RES_USE_EDNS0;
+ return 0;
+ }
+#endif
+
+ else if (!strcmp(key, "a6"))
+ {
+ res->options |= RES_USE_A6;
+ return 0;
+ }
+
+ else if (!strcmp(key, "dname"))
+ {
+ res->options |= RES_USE_DNAME;
+ return 0;
+ }
+
+ return -1;
+}
+
+/*
+ * Set up default settings. If the configuration file exist, the values
+ * there will have precedence. Otherwise, the server address is set to
+ * INADDR_ANY and the default domain name comes from the gethostname().
+ *
+ * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
+ * rather than INADDR_ANY ("0.0.0.0") as the default name server address
+ * since it was noted that INADDR_ANY actually meant ``the first interface
+ * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
+ * it had to be "up" in order for you to reach your own name server. It
+ * was later decided that since the recommended practice is to always
+ * install local static routes through 127.0.0.1 for all your network
+ * interfaces, that we could solve this problem without a code change.
+ *
+ * The configuration file should always be used, since it is the only way
+ * to specify a default domain. If you are running a server on your local
+ * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
+ * in the configuration file.
+ *
+ * Return 0 if completes successfully, -1 on error
+ */
+
+int
+res_vinit_from_file(res_state statp, int preinit, char *resconf_file)
+{
+ register FILE *fp;
+ register char *cp, **pp;
+ register int n;
+ char buf[BUFSIZ];
+ int nserv = 0; /* number of nameserver records read from file */
+ int haveenv = 0;
+ int havesearch = 0;
+ int isresdefault = 0;
+ unsigned short port; /* HOST BYTE ORDER */
+ unsigned int i, total_timeout;
+#ifdef RESOLVSORT
+ int nsort = 0;
+ char *net;
+#endif
+ int dots;
+
+ port = NS_DEFAULTPORT;
+ total_timeout = 0;
+
+ if (!preinit)
+ {
+ statp->retrans = RES_TIMEOUT;
+ statp->retry = RES_DFLRETRY;
+ statp->options = RES_DEFAULT;
+ statp->id = res_randomid();
+ }
+
+ if ((statp->options & RES_INIT) != 0) res_ndestroy(statp);
+
+ /* N.B. we allocate a new statp->_u._ext.ext below */
+
+ /* make sure version is set */
+ statp->_pad = 9;
+
+ statp->nscount = 0;
+
+ if ((resconf_file == NULL) || (!strcmp(resconf_file, _PATH_RESCONF)))
+ {
+ isresdefault = 1;
+
+#ifdef USELOOPBACK
+ statp->nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
+#else
+ statp->nsaddr.sin_addr.s_addr = INADDR_ANY;
+#endif
+ statp->nsaddr.sin_family = AF_INET;
+ statp->nsaddr.sin_port = htons(NS_DEFAULTPORT);
+#ifdef HAVE_SA_LEN
+ statp->nsaddr.sin_len = sizeof(struct sockaddr_in);
+#endif
+ statp->nscount = 1;
+
+ /*
+ * Force loopback queries to use TCP
+ * so we don't take a timeout if named isn't running.
+ */
+ statp->options |= RES_USEVC;
+ }
+
+ statp->ndots = 1;
+ statp->pfcode = 0;
+ statp->_vcsock = -1;
+ statp->_flags = 0;
+ statp->qhook = NULL;
+ statp->rhook = NULL;
+
+ statp->_u._ext.nscount = 0;
+ statp->_u._ext.ext = (struct __res_state_ext *)calloc(1, sizeof(struct __res_state_ext));
+
+ if (statp->_u._ext.ext != NULL)
+ {
+ memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext));
+ statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr;
+ strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa");
+ strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int");
+ strcpy(statp->_u._ext.ext->bsuffix, "ip6.arpa");
+ }
+
+#ifdef RESOLVSORT
+ statp->nsort = 0;
+#endif
+
+ /* Allow user to override the local domain definition */
+ cp = getenv("LOCALDOMAIN");
+ if ((cp != NULL) && (isresdefault != 0))
+ {
+ (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
+ statp->defdname[sizeof(statp->defdname) - 1] = '\0';
+ haveenv++;
+
+ /*
+ * Set search list to be blank-separated strings
+ * from rest of env value. Permits users of LOCALDOMAIN
+ * to still have a search list, and anyone to set the
+ * one that they want to use as an individual (even more
+ * important now that the rfc1535 stuff restricts searches)
+ */
+ cp = statp->defdname;
+ pp = statp->dnsrch;
+ *pp++ = cp;
+ for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++)
+ {
+ if (*cp == '\n') break;
+ else if (*cp == ' ' || *cp == '\t')
+ {
+ *cp = 0;
+ n = 1;
+ }
+ else if (n != 0)
+ {
+ *pp++ = cp;
+ n = 0;
+ havesearch = 1;
+ }
+ }
+
+ /* null terminate last domain if there are excess */
+ while ((*cp != '\0') && (*cp != ' ') && (*cp != '\t') && (*cp != '\n')) cp++;
+ *cp = '\0';
+ *pp++ = 0;
+ }
+
+#define MATCH(line, name) \
+ (!strncmp(line, name, sizeof(name) - 1) && \
+ (line[sizeof(name) - 1] == ' ' || \
+ line[sizeof(name) - 1] == '\t'))
+
+ if (resconf_file == NULL) resconf_file = _PATH_RESCONF;
+
+ if ((fp = fopen(resconf_file, "r")) != NULL)
+ {
+ /* look for port number */
+ while (fgets(buf, sizeof(buf), fp) != NULL)
+ {
+ /* skip comments */
+ if (*buf == ';' || *buf == '#') continue;
+
+ /* read default domain name */
+ if (MATCH(buf, "port"))
+ {
+ cp = buf + sizeof("port") - 1;
+ while (*cp == ' ' || *cp == '\t') cp++;
+ if ((*cp == '\0') || (*cp == '\n')) continue;
+ port = atoi(cp);
+ break;
+ }
+ }
+ fclose(fp);
+ }
+
+ if ((fp = fopen(resconf_file, "r")) != NULL)
+ {
+ /* read the config file */
+ while (fgets(buf, sizeof(buf), fp) != NULL)
+ {
+ /* skip comments */
+ if ((*buf == ';') || (*buf == '#')) continue;
+
+ /* read default domain name */
+ if (MATCH(buf, "domain"))
+ {
+ /* skip if have from environ */
+ if (haveenv) continue;
+
+ cp = buf + sizeof("domain") - 1;
+ while ((*cp == ' ') || (*cp == '\t')) cp++;
+ if ((*cp == '\0') || (*cp == '\n')) continue;
+
+ strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
+ statp->defdname[sizeof(statp->defdname) - 1] = '\0';
+ cp = strpbrk(statp->defdname, " \t\n");
+ if (cp != NULL) *cp = '\0';
+ havesearch = 0;
+ continue;
+ }
+
+ /* set search list */
+ if (MATCH(buf, "search"))
+ {
+ /* skip if have from environ */
+ if (haveenv) continue;
+
+ cp = buf + sizeof("search") - 1;
+ while ((*cp == ' ') || (*cp == '\t')) cp++;
+ if ((*cp == '\0') || (*cp == '\n')) continue;
+
+ strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
+ statp->defdname[sizeof(statp->defdname) - 1] = '\0';
+ cp = strchr(statp->defdname, '\n');
+ if (cp != NULL) *cp = '\0';
+
+ /*
+ * Set search list to be blank-separated strings
+ * on rest of line.
+ */
+ cp = statp->defdname;
+ pp = statp->dnsrch;
+ *pp++ = cp;
+ for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++)
+ {
+ if ((*cp == ' ') || (*cp == '\t'))
+ {
+ *cp = 0;
+ n = 1;
+ }
+ else if (n != 0)
+ {
+ *pp++ = cp;
+ n = 0;
+ }
+ }
+
+ /* null terminate last domain if there are excess */
+ while ((*cp != '\0') && (*cp != ' ') && (*cp != '\t')) cp++;
+ *cp = '\0';
+ *pp++ = 0;
+ havesearch = 1;
+ continue;
+ }
+
+ /* read nameservers to query */
+ if (MATCH(buf, "nameserver") && (nserv < MAXNS))
+ {
+#ifndef __APPLE__
+ struct addrinfo hints, *ai;
+#endif
+ int dotcount, semicount, status;
+ struct in_addr addr4;
+ struct sockaddr_in sin4;
+ struct in6_addr addr6;
+ struct sockaddr_in6 sin6;
+ unsigned short aport; /* HOST BYTE ORDER */
+ char *lastdot, *checkp;
+ char sbuf[NI_MAXSERV];
+#ifndef __APPLE__
+ const size_t minsiz = sizeof(statp->_u._ext.ext->nsaddrs[0]);
+#endif
+
+ cp = buf + sizeof("nameserver") - 1;
+ while ((*cp == ' ') || (*cp == '\t')) cp++;
+ cp[strcspn(cp, ";# \t\n")] = '\0';
+ if ((*cp != '\0') && (*cp != '\n'))
+ {
+#ifndef __APPLE__
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+ hints.ai_flags = AI_NUMERICHOST;
+#endif
+ dotcount = 0;
+ semicount = 0;
+ lastdot = NULL;
+ aport = port;
+
+ for (checkp = cp; *checkp != '\0'; checkp++)
+ {
+ if (*checkp == ':') semicount++;
+ else if (*checkp == '.')
+ {
+ dotcount++;
+ lastdot = checkp;
+ }
+ }
+
+ if ((dotcount == 4) || ((semicount > 0) && (lastdot != NULL)))
+ {
+ aport = atoi(lastdot + 1);
+ if (aport == 0) aport = port;
+ *lastdot = '\0';
+ }
+
+ sprintf(sbuf, "%u", aport);
+
+#ifdef __APPLE__
+ memset(&addr4, 0, sizeof(struct in_addr));
+ memset(&sin4, 0, sizeof(struct sockaddr_in));
+
+ memset(&addr6, 0, sizeof(struct in6_addr));
+ memset(&sin6, 0, sizeof(struct sockaddr_in6));
+
+ status = inet_pton(AF_INET6, cp, &addr6);
+ if (status == 1)
+ {
+ sin6.sin6_addr = addr6;
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_port = htons(aport);
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ if (statp->_u._ext.ext != NULL)
+ {
+ memcpy(&statp->_u._ext.ext->nsaddrs[nserv], &sin6, sizeof(struct sockaddr_in6));
+ }
+ statp->nsaddr_list[nserv].sin_family = 0;
+ nserv++;
+ }
+ else
+ {
+ status = inet_pton(AF_INET, cp, &addr4);
+ if (status == 1)
+ {
+ sin4.sin_addr = addr4;
+ sin4.sin_family = AF_INET;
+ sin4.sin_port = htons(port);
+ sin4.sin_len = sizeof(struct sockaddr_in);
+ if (statp->_u._ext.ext != NULL)
+ {
+ memcpy(&statp->_u._ext.ext->nsaddrs[nserv], &sin4, sizeof(struct sockaddr_in));
+ }
+ memcpy(&statp->nsaddr_list[nserv], &sin4, sizeof(struct sockaddr_in));
+ nserv++;
+ }
+ }
+
+
+#else
+ if (getaddrinfo(cp, sbuf, &hints, &ai) == 0 && ai->ai_addrlen <= minsiz)
+ {
+ if (statp->_u._ext.ext != NULL)
+ {
+ memcpy(&statp->_u._ext.ext->nsaddrs[nserv], ai->ai_addr, ai->ai_addrlen);
+ }
+
+ if (ai->ai_addrlen <= sizeof(statp->nsaddr_list[nserv]))
+ {
+ memcpy(&statp->nsaddr_list[nserv], ai->ai_addr, ai->ai_addrlen);
+ }
+ else
+ {
+ statp->nsaddr_list[nserv].sin_family = 0;
+ }
+
+ freeaddrinfo(ai);
+ nserv++;
+ }
+#endif
+ }
+
+ continue;
+ }
+
+#ifdef RESOLVSORT
+ if (MATCH(buf, "sortlist"))
+ {
+ struct in_addr a;
+
+ cp = buf + sizeof("sortlist") - 1;
+ while (nsort < MAXRESOLVSORT)
+ {
+ while ((*cp == ' ') || (*cp == '\t')) cp++;
+ if ((*cp == '\0') || (*cp == '\n') || (*cp == ';')) break;
+
+ net = cp;
+ while (*cp && !ISSORTMASK(*cp) && (*cp != ';') && isascii(*cp) && !isspace((unsigned char)*cp)) cp++;
+ n = *cp;
+ *cp = 0;
+ if (inet_aton(net, &a))
+ {
+ statp->sort_list[nsort].addr = a;
+ if (ISSORTMASK(n))
+ {
+ *cp++ = n;
+ net = cp;
+ while (*cp && (*cp != ';') && isascii(*cp) && !isspace((unsigned char)*cp)) cp++;
+ n = *cp;
+ *cp = 0;
+ if (inet_aton(net, &a))
+ {
+ statp->sort_list[nsort].mask = a.s_addr;
+ }
+ else
+ {
+ statp->sort_list[nsort].mask = net_mask(statp->sort_list[nsort].addr);
+ }
+ }
+ else
+ {
+ statp->sort_list[nsort].mask = net_mask(statp->sort_list[nsort].addr);
+ }
+ nsort++;
+ }
+
+ *cp = n;
+ }
+
+ continue;
+ }
+#endif
+
+ if (MATCH(buf, "options"))
+ {
+ res_setoptions(statp, buf + sizeof("options") - 1, "conf");
+ continue;
+ }
+
+ if (MATCH(buf, "timeout"))
+ {
+ cp = buf + sizeof("timeout") - 1;
+ while (*cp == ' ' || *cp == '\t') cp++;
+ if ((*cp == '\0') || (*cp == '\n')) continue;
+ i = atoi(cp);
+ if (i > RES_MAXRETRANS) i = RES_MAXRETRANS;
+ total_timeout = i;
+ continue;
+ }
+ }
+
+ if (nserv > 1) statp->nscount = nserv;
+#ifdef RESOLVSORT
+ statp->nsort = nsort;
+#endif
+ fclose(fp);
+ }
+
+ /*
+ * Last chance to get a nameserver. This should not normally
+ * be necessary
+ */
+#ifdef NO_RESOLV_CONF
+ if(nserv == 0) nserv = get_nameservers(statp);
+#endif
+
+ if (isresdefault != 0)
+ {
+ if ((statp->defdname[0] == 0) && (gethostname(buf, sizeof(statp->defdname) - 1) == 0) && ((cp = strchr(buf, '.')) != NULL))
+ {
+ strcpy(statp->defdname, cp + 1);
+ }
+ }
+
+ /* find components of local domain that might be searched */
+ if (havesearch == 0)
+ {
+ pp = statp->dnsrch;
+ *pp++ = statp->defdname;
+ *pp = NULL;
+
+ dots = 0;
+ for (cp = statp->defdname; *cp; cp++)
+ {
+ if (*cp == '.') dots++;
+ }
+
+ /* Back up over any trailing dots and cut them out of the name */
+ for (cp--; (cp >= statp->defdname) && (*cp == '.'); cp--)
+ {
+ *cp = '\0';
+ dots--;
+ }
+
+ cp = statp->defdname;
+ while (pp < statp->dnsrch + MAXDFLSRCH)
+ {
+ if (dots < LOCALDOMAINPARTS) break;
+
+ /* we know there is a dot */
+ cp = strchr(cp, '.') + 1;
+ *pp++ = cp;
+ dots--;
+ }
+
+ *pp = NULL;
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ {
+ printf(";; res_init()... default dnsrch list:\n");
+ for (pp = statp->dnsrch; *pp; pp++) printf(";;\t%s\n", *pp);
+ printf(";;\t..END..\n");
+ }
+#endif
+ }
+
+ cp = getenv("RES_OPTIONS");
+ if ((cp != NULL) && (isresdefault != 0))
+ {
+ res_setoptions(statp, cp, "env");
+ }
+
+#ifdef __APPLE__
+ /*
+ * Post processing to set the timeout value.
+ */
+ if (total_timeout != 0)
+ {
+ /* Timeout was set with a "timeout" line in the file */
+ statp->retrans = total_timeout;
+ }
+ else
+ {
+ /*
+ * Timeout is default, or was set with "options timeout:"
+ * This is a per-select timeout value. Calculate total timeout
+ * and set statp->restrans which we (Apple) use to indicate
+ * total time allowed for a query to be resolved.
+ */
+ total_timeout = statp->retrans * (statp->retry + 1) * statp->nscount;
+ statp->retrans = total_timeout;
+ }
+#endif
+
+ statp->options |= RES_INIT;
+ return (0);
+}
+
+static void
+res_setoptions(res_state statp, const char *options, const char *source)
+{
+ const char *cp = options;
+ int i;
+ struct __res_state_ext *ext = statp->_u._ext.ext;
+
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; res_setoptions(\"%s\", \"%s\")...\n",
+ options, source);
+#endif
+ while (*cp) {
+ /* skip leading and inner runs of spaces */
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ /* search for and process individual options */
+ if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
+ i = atoi(cp + sizeof("ndots:") - 1);
+ if (i <= RES_MAXNDOTS)
+ statp->ndots = i;
+ else
+ statp->ndots = RES_MAXNDOTS;
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";;\tndots=%d\n", statp->ndots);
+#endif
+ } else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) {
+ i = atoi(cp + sizeof("timeout:") - 1);
+ if (i <= RES_MAXRETRANS)
+ statp->retrans = i;
+ else
+ statp->retrans = RES_MAXRETRANS;
+ } else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){
+ i = atoi(cp + sizeof("attempts:") - 1);
+ if (i <= RES_MAXRETRY)
+ statp->retry = i;
+ else
+ statp->retry = RES_MAXRETRY;
+ } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
+#ifdef DEBUG
+ if (!(statp->options & RES_DEBUG)) {
+ printf(";; res_setoptions(\"%s\", \"%s\")..\n",
+ options, source);
+ statp->options |= RES_DEBUG;
+ }
+ printf(";;\tdebug\n");
+#endif
+ } else if (!strncmp(cp, "no_tld_query",
+ sizeof("no_tld_query") - 1) ||
+ !strncmp(cp, "no-tld-query",
+ sizeof("no-tld-query") - 1)) {
+ statp->options |= RES_NOTLDQUERY;
+ } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
+ statp->options |= RES_USE_INET6;
+ } else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) {
+ statp->options |= RES_ROTATE;
+ } else if (!strncmp(cp, "no-check-names",
+ sizeof("no-check-names") - 1)) {
+ statp->options |= RES_NOCHECKNAME;
+ }
+#ifdef RES_USE_EDNS0
+ else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) {
+ statp->options |= RES_USE_EDNS0;
+ }
+#endif
+ else if (!strncmp(cp, "a6", sizeof("a6") - 1)) {
+ statp->options |= RES_USE_A6;
+ }
+ else if (!strncmp(cp, "dname", sizeof("dname") - 1)) {
+ statp->options |= RES_USE_DNAME;
+ }
+ else if (!strncmp(cp, "nibble:", sizeof("nibble:") - 1)) {
+ if (ext == NULL)
+ goto skip;
+ cp += sizeof("nibble:") - 1;
+ i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix) - 1);
+ strncpy(ext->nsuffix, cp, i);
+ ext->nsuffix[i] = '\0';
+ }
+ else if (!strncmp(cp, "nibble2:", sizeof("nibble2:") - 1)) {
+ if (ext == NULL)
+ goto skip;
+ cp += sizeof("nibble2:") - 1;
+ i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix2) - 1);
+ strncpy(ext->nsuffix2, cp, i);
+ ext->nsuffix2[i] = '\0';
+ }
+ else if (!strncmp(cp, "bitstring:", sizeof("bitstring:") - 1)) {
+ if (ext == NULL)
+ goto skip;
+ cp += sizeof("bitstring:") - 1;
+ i = MIN(strcspn(cp, " \t"), sizeof(ext->bsuffix) - 1);
+ strncpy(ext->bsuffix, cp, i);
+ ext->bsuffix[i] = '\0';
+ }
+ else if (!strncmp(cp, "v6revmode:", sizeof("v6revmode:") - 1)) {
+ cp += sizeof("v6revmode:") - 1;
+ /* "nibble" and "bitstring" used to be valid */
+ if (!strncmp(cp, "single", sizeof("single") - 1)) {
+ statp->options |= RES_NO_NIBBLE2;
+ } else if (!strncmp(cp, "both", sizeof("both") - 1)) {
+ statp->options &=
+ ~RES_NO_NIBBLE2;
+ }
+ }
+ else {
+ /* XXX - print a warning here? */
+ }
+ skip:
+ /* skip to next run of spaces */
+ while (*cp && *cp != ' ' && *cp != '\t')
+ cp++;
+ }
+}
+
+/* This function has to be reachable by res_data.c but not publically. */
+int
+__res_vinit(res_state statp, int preinit)
+{
+ dns_config_t *sc_dns;
+ dns_resolver_t *sc_res;
+ char val[256], *p, *x;
+ int i, n;
+ uint32_t nsearch, total_timeout, send_timeout;
+ uint16_t port;
+
+ nsearch = 0;
+ send_timeout = 0;
+
+ sc_dns = dns_configuration_copy();
+ if (sc_dns == NULL) return res_vinit_from_file(statp, preinit, _PATH_RESCONF);
+
+ sc_res = sc_dns->resolver[0];
+ port = sc_res->port;
+ if (port == 0) port = NS_DEFAULTPORT;
+
+ if ((statp->options & RES_INIT) != 0) res_ndestroy(statp);
+
+ /* N.B. res_build_start will allocate statp->_u._ext.ext for us */
+ statp = res_build_start(statp);
+
+ p = getenv("RES_RETRY_TIMEOUT");
+ if (p != NULL) send_timeout = atoi(p);
+
+ p = getenv("RES_RETRY");
+ if (p != NULL) statp->retry= atoi(p);
+
+ if (sc_res->n_nameserver > MAXNS) sc_res->n_nameserver = MAXNS;
+ for (i = 0; i < sc_res->n_nameserver; i++)
+ {
+ if (sc_res->nameserver[i]->sa_family == AF_INET)
+ {
+ memset(val, 0, sizeof(val));
+ inet_ntop(AF_INET, (char *)(sc_res->nameserver[i]) + INET_NTOP_AF_INET_OFFSET, val, sizeof(val));
+ res_build(statp, port, &nsearch, "nameserver", val);
+ }
+ else if (sc_res->nameserver[i]->sa_family == AF_INET6)
+ {
+ memset(val, 0, sizeof(val));
+ inet_ntop(AF_INET6, (char *)(sc_res->nameserver[i]) + INET_NTOP_AF_INET6_OFFSET, val, sizeof(val));
+ res_build(statp, port, &nsearch, "nameserver", val);
+ }
+ }
+
+ if (sc_res->n_search > MAXDNSRCH) sc_res->n_search = MAXDNSRCH;
+ for (i = 0; i < sc_res->n_search; i++)
+ {
+ res_build(statp, port, &nsearch, "search", sc_res->search[i]);
+ }
+
+ /* If there was no search list, use "domain" */
+ if ((sc_res->n_search == 0) && (sc_res->domain != NULL))
+ {
+ /* Count dots */
+ n = 0;
+ for (p = sc_res->domain; *p != '\0'; p++)
+ {
+ if (*p == '.') n++;
+ }
+
+ /* Back up over any trailing dots and cut them out of the name */
+ for (p--; (p >= sc_res->domain) && (*p == '.'); p--)
+ {
+ *p = '\0';
+ n--;
+ }
+
+ if (p >= sc_res->domain) res_build(statp, port, &nsearch, "search", sc_res->domain);
+
+ /* dots are separators, so number of components is one larger */
+ n++;
+
+ /* Include parent domains with at least LOCALDOMAINPARTS components */
+ p = sc_res->domain;
+ while ((n > LOCALDOMAINPARTS) && (nsearch < MAXDFLSRCH))
+ {
+ /* Find next component */
+ while (*p != '.') p++;
+ if (*p == '\0') break;
+ p++;
+
+ n--;
+ res_build(statp, port, &nsearch, "search", p);
+ }
+ }
+
+ total_timeout = sc_res->timeout;
+
+ snprintf(val, sizeof(val), "%d", sc_res->search_order);
+ res_build(statp, port, &nsearch, "search_order", val);
+
+ if (sc_res->n_sortaddr > MAXRESOLVSORT) sc_res->n_sortaddr = MAXRESOLVSORT;
+ for (i = 0; i < sc_res->n_sortaddr; i++)
+ {
+ res_build_sortlist(statp, sc_res->sortaddr[i]->address, sc_res->sortaddr[i]->mask);
+ }
+
+ p = sc_res->options;
+ while (NULL != (x = res_next_word(&p)))
+ {
+ if (!strncmp(x, "ndots:", 6))
+ {
+ res_build(statp, port, &nsearch, "ndots", x+6);
+ }
+
+ else if (!strncmp(x, "nibble:", 7))
+ {
+ res_build(statp, port, &nsearch, "nibble", x+7);
+ }
+
+ else if (!strncmp(x, "nibble2:", 8))
+ {
+ res_build(statp, port, &nsearch, "nibble2", x+8);
+ }
+
+ else if (!strncmp(x, "timeout:", 8))
+ {
+ send_timeout = atoi(x+8);
+ }
+
+ else if (!strncmp(x, "attempts:", 9))
+ {
+ res_build(statp, port, &nsearch, "attempts", x+9);
+ }
+
+ else if (!strncmp(x, "bitstring:", 10))
+ {
+ res_build(statp, port, &nsearch, "bitstring", x+10);
+ }
+
+ else if (!strncmp(x, "v6revmode:", 10))
+ {
+ res_build(statp, port, &nsearch, "v6revmode", x+10);
+ }
+
+ else if (!strcmp(x, "debug"))
+ {
+ res_build(statp, port, &nsearch, "debug", NULL);
+ }
+
+ else if (!strcmp(x, "no_tld_query"))
+ {
+ res_build(statp, port, &nsearch, "no_tld_query", NULL);
+ }
+
+ else if (!strcmp(x, "inet6"))
+ {
+ res_build(statp, port, &nsearch, "inet6", NULL);
+ }
+
+ else if (!strcmp(x, "rotate"))
+ {
+ res_build(statp, port, &nsearch, "rotate", NULL);
+ }
+
+ else if (!strcmp(x, "no-check-names"))
+ {
+ res_build(statp, port, &nsearch, "no-check-names", NULL);
+ }
+
+#ifdef RES_USE_EDNS0
+ else if (!strcmp(x, "edns0"))
+ {
+ res_build(statp, port, &nsearch, "edns0", NULL);
+ }
+#endif
+ else if (!strcmp(x, "a6"))
+ {
+ res_build(statp, port, &nsearch, "a6", NULL);
+ }
+
+ else if (!strcmp(x, "dname"))
+ {
+ res_build(statp, port, &nsearch, "dname", NULL);
+ }
+ }
+
+ n = statp->nscount;
+ if (n == 0) n = 1;
+
+ if (total_timeout == 0)
+ {
+ if (send_timeout == 0) total_timeout = RES_MAXRETRANS;
+ else total_timeout = send_timeout * statp->retry * n;
+ }
+
+ dns_configuration_free(sc_dns);
+
+ res_build_finish(statp, total_timeout, port);
+
+ return 0;
+}
+
+int
+res_ninit(res_state statp)
+{
+ if (statp == NULL) return -1;
+ memset(statp, 0, sizeof(struct __res_state));
+ return __res_vinit(statp, 0);
+}
+
+#ifdef RESOLVSORT
+/* XXX - should really support CIDR which means explicit masks always. */
+static u_int32_t
+net_mask(in) /* XXX - should really use system's version of this */
+ struct in_addr in;
+{
+ register u_int32_t i = ntohl(in.s_addr);
+
+ if (IN_CLASSA(i))
+ return (htonl(IN_CLASSA_NET));
+ else if (IN_CLASSB(i))
+ return (htonl(IN_CLASSB_NET));
+ return (htonl(IN_CLASSC_NET));
+}
+#endif
+
+u_int
+res_randomid(void) {
+ struct timeval now;
+#ifdef __APPLE__
+ int rf;
+ static u_int x = 0;
+
+ if (x == 0)
+ {
+ rf = open("/dev/random", O_RDONLY, 0);
+ if (rf >= 0)
+ {
+ read(rf, &x, sizeof(u_int));
+ close(rf);
+ }
+ else
+ {
+ x = (getpid() << 10) + time(NULL);
+ }
+
+ srandom(x);
+ }
+
+ return random();
+#endif
+
+ gettimeofday(&now, NULL);
+ return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid()));
+}
+
+/*
+ * This routine is for closing the socket if a virtual circuit is used and
+ * the program wants to close it. This provides support for endhostent()
+ * which expects to close the socket.
+ *
+ * This routine is not expected to be user visible.
+ */
+void
+res_nclose(res_state statp)
+{
+ int ns;
+
+ if (statp->_vcsock >= 0)
+ {
+ close(statp->_vcsock);
+ statp->_vcsock = -1;
+ statp->_flags &= ~(RES_F_VC | RES_F_CONN);
+ }
+
+ if (statp->_pad >= 9)
+ {
+ for (ns = 0; ns < statp->_u._ext.nscount; ns++)
+ {
+ if (statp->_u._ext.nssocks[ns] != -1)
+ {
+ close(statp->_u._ext.nssocks[ns]);
+ statp->_u._ext.nssocks[ns] = -1;
+ }
+ }
+ }
+}
+
+void
+res_ndestroy(res_state statp)
+{
+ res_nclose(statp);
+ statp->options &= ~RES_INIT;
+
+ /*
+ * _pad (normally unused) is a version number.
+ * We use it to prevent BIND_9 from trashing memory
+ * if statp was created by BIND-8.
+ */
+ if (statp->_pad >= 9)
+ {
+ if (statp->_u._ext.ext != NULL) free(statp->_u._ext.ext);
+ statp->_u._ext.ext = NULL;
+ statp->_pad = 9;
+ }
+}
+
+const char *
+res_get_nibblesuffix(res_state statp) {
+ if (statp->_u._ext.ext)
+ return (statp->_u._ext.ext->nsuffix);
+ return ("ip6.arpa");
+}
+
+const char *
+res_get_nibblesuffix2(res_state statp) {
+ if (statp->_u._ext.ext)
+ return (statp->_u._ext.ext->nsuffix2);
+ return ("ip6.int");
+}
+
+const char *
+res_get_bitstringsuffix(res_state statp) {
+ if (statp->_u._ext.ext)
+ return (statp->_u._ext.ext->bsuffix);
+ return ("ip6.arpa");
+}
+
+void
+res_setservers(res_state statp, const union res_sockaddr_union *set, int cnt) {
+ int i, nserv;
+ size_t size;
+
+ /* close open servers */
+ res_nclose(statp);
+
+ /* cause rtt times to be forgotten */
+ statp->_u._ext.nscount = 0;
+
+ nserv = 0;
+ for (i = 0; i < cnt && nserv < MAXNS; i++) {
+ switch (set->sin.sin_family) {
+ case AF_INET:
+ size = sizeof(set->sin);
+ if (statp->_u._ext.ext)
+ memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
+ &set->sin, size);
+ if (size <= sizeof(statp->nsaddr_list[nserv]))
+ memcpy(&statp->nsaddr_list[nserv],
+ &set->sin, size);
+ else
+ statp->nsaddr_list[nserv].sin_family = 0;
+ nserv++;
+ break;
+
+ case AF_INET6:
+ size = sizeof(set->sin6);
+ if (statp->_u._ext.ext)
+ memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
+ &set->sin6, size);
+ if (size <= sizeof(statp->nsaddr_list[nserv]))
+ memcpy(&statp->nsaddr_list[nserv],
+ &set->sin6, size);
+ else
+ statp->nsaddr_list[nserv].sin_family = 0;
+ nserv++;
+ break;
+
+ default:
+ break;
+ }
+ set++;
+ }
+
+ statp->nscount = nserv;
+}
+
+int
+res_getservers(res_state statp, union res_sockaddr_union *set, int cnt) {
+ int i;
+ size_t size;
+ u_int16_t family;
+
+ for (i = 0; i < statp->nscount && i < cnt; i++) {
+ if (statp->_u._ext.ext)
+ family = statp->_u._ext.ext->nsaddrs[i].sin.sin_family;
+ else
+ family = statp->nsaddr_list[i].sin_family;
+
+ switch (family) {
+ case AF_INET:
+ size = sizeof(set->sin);
+ if (statp->_u._ext.ext)
+ memcpy(&set->sin,
+ &statp->_u._ext.ext->nsaddrs[i],
+ size);
+ else
+ memcpy(&set->sin, &statp->nsaddr_list[i],
+ size);
+ break;
+
+ case AF_INET6:
+ size = sizeof(set->sin6);
+ if (statp->_u._ext.ext)
+ memcpy(&set->sin6,
+ &statp->_u._ext.ext->nsaddrs[i],
+ size);
+ else
+ memcpy(&set->sin6, &statp->nsaddr_list[i],
+ size);
+ break;
+
+ default:
+ set->sin.sin_family = 0;
+ break;
+ }
+ set++;
+ }
+ return (statp->nscount);
+}
--- /dev/null
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)res_mkquery.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_mkquery.c,v 1.1 2006/03/01 19:01:38 majka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#ifndef __APPLE__
+#include "port_before.h"
+#endif
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+#include "res_private.h"
+#ifndef __APPLE__
+#include "port_after.h"
+#endif
+
+/* Options. Leave them on. */
+#define DEBUG
+
+extern const char *__res_opcodes[];
+
+/*
+ * Form all types of queries.
+ * Returns the size of the result or -1.
+ */
+int
+res_nmkquery(res_state statp,
+ int op, /* opcode of query */
+ const char *dname, /* domain name */
+ int class, int type, /* class and type of query */
+ const u_char *data, /* resource record data */
+ int datalen, /* length of data */
+ const u_char *newrr_in, /* new rr for modify or append */
+ u_char *buf, /* buffer to put query */
+ int buflen) /* size of buffer */
+{
+ register HEADER *hp;
+ register u_char *cp;
+ register int n;
+ u_char *dnptrs[20], **dpp, **lastdnptr;
+
+#ifdef __APPLE__
+ n = (int)newrr_in; n = 0;
+#else
+ UNUSED(newrr_in);
+#endif
+
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; res_nmkquery(%s, %s, %s, %s)\n",
+ __res_opcodes[op], dname, p_class(class), p_type(type));
+#endif
+ /*
+ * Initialize header fields.
+ */
+ if ((buf == NULL) || (buflen < NS_HFIXEDSZ))
+ return (-1);
+ memset(buf, 0, NS_HFIXEDSZ);
+ hp = (HEADER *) buf;
+#ifdef __APPLE__
+ hp->id = res_randomid();
+#else
+ hp->id = htons(++statp->id);
+#endif
+ hp->opcode = op;
+ hp->rd = (statp->options & RES_RECURSE) != 0;
+ hp->rcode = ns_r_noerror;
+ cp = buf + NS_HFIXEDSZ;
+ buflen -= NS_HFIXEDSZ;
+ dpp = dnptrs;
+ *dpp++ = buf;
+ *dpp++ = NULL;
+ lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
+ /*
+ * perform opcode specific processing
+ */
+ switch (op) {
+ case ns_o_query: /*FALLTHROUGH*/
+ case ns_o_update:
+ if ((buflen -= NS_QFIXEDSZ) < 0)
+ return (-1);
+ if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
+ return (-1);
+ cp += n;
+ buflen -= n;
+ putshort(type, cp);
+ cp += NS_INT16SZ;
+ putshort(class, cp);
+ cp += NS_INT16SZ;
+ hp->qdcount = htons(1);
+ if (op == ns_o_query || data == NULL)
+ break;
+ /*
+ * Make an additional record for completion domain.
+ */
+ buflen -= NS_RRFIXEDSZ;
+ n = dn_comp((const char *)data, cp, buflen, dnptrs, lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ buflen -= n;
+ putshort(ns_t_null, cp);
+ cp += NS_INT16SZ;
+ putshort(class, cp);
+ cp += NS_INT16SZ;
+ putlong(0, cp);
+ cp += NS_INT32SZ;
+ putshort(0, cp);
+ cp += NS_INT16SZ;
+ hp->arcount = htons(1);
+ break;
+
+ case ns_o_iquery:
+ /*
+ * Initialize answer section
+ */
+ if (buflen < 1 + NS_RRFIXEDSZ + datalen)
+ return (-1);
+ *cp++ = '\0'; /* no domain name */
+ putshort(type, cp);
+ cp += NS_INT16SZ;
+ putshort(class, cp);
+ cp += NS_INT16SZ;
+ putlong(0, cp);
+ cp += NS_INT32SZ;
+ putshort(datalen, cp);
+ cp += NS_INT16SZ;
+ if (datalen) {
+ memcpy(cp, data, datalen);
+ cp += datalen;
+ }
+ hp->ancount = htons(1);
+ break;
+
+ default:
+ return (-1);
+ }
+ return (cp - buf);
+}
+
+#ifdef RES_USE_EDNS0
+/* attach OPT pseudo-RR, as documented in RFC2671 (EDNS0). */
+#ifndef T_OPT
+#define T_OPT 41
+#endif
+
+int
+res_nopt(statp, n0, buf, buflen, anslen)
+ res_state statp;
+ int n0;
+ u_char *buf; /* buffer to put query */
+ int buflen; /* size of buffer */
+ int anslen; /* answer buffer length */
+{
+ register HEADER *hp;
+ register u_char *cp;
+ u_int16_t flags = 0;
+
+#ifdef DEBUG
+ if ((statp->options & RES_DEBUG) != 0)
+ printf(";; res_nopt()\n");
+#endif
+
+ hp = (HEADER *) buf;
+ cp = buf + n0;
+ buflen -= n0;
+
+ if (buflen < 1 + NS_RRFIXEDSZ)
+ return -1;
+
+ *cp++ = 0; /* "." */
+ buflen--;
+
+ putshort(T_OPT, cp); /* TYPE */
+ cp += NS_INT16SZ;
+ putshort(anslen & 0xffff, cp); /* CLASS = UDP payload size */
+ cp += NS_INT16SZ;
+ *cp++ = ns_r_noerror; /* extended RCODE */
+ *cp++ = 0; /* EDNS version */
+ if (statp->options & RES_USE_DNSSEC) {
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; res_opt()... ENDS0 DNSSEC\n");
+#endif
+ flags |= NS_OPT_DNSSEC_OK;
+ }
+ putshort(flags, cp);
+ cp += NS_INT16SZ;
+ putshort(0, cp); /* RDLEN */
+ cp += NS_INT16SZ;
+ hp->arcount = htons(ntohs(hp->arcount) + 1);
+ buflen -= NS_RRFIXEDSZ;
+
+ return cp - buf;
+}
+#endif
--- /dev/null
+/*
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Based on the Dynamic DNS reference implementation by Viraj Bais
+ * <viraj_bais@ccm.fm.intel.com>
+ */
+
+#ifndef __APPLE__
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: res_mkupdate.c,v 1.1 2006/03/01 19:01:38 majka Exp $";
+#endif /* not lint */
+#endif
+
+#ifndef __APPLE__
+#include "port_before.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <res_update.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include "res_private.h"
+
+#ifndef __APPLE__
+#include "port_after.h"
+#endif
+
+/* Options. Leave them on. */
+#define DEBUG
+#define MAXPORT 1024
+
+static int getnum_str(u_char **, u_char *);
+static int gethexnum_str(u_char **, u_char *);
+static int getword_str(char *, int, u_char **, u_char *);
+static int getstr_str(char *, int, u_char **, u_char *);
+
+#define ShrinkBuffer(x) if ((buflen -= x) < 0) return (-2);
+
+/* Forward. */
+
+#ifdef __APPLE__
+static
+#endif
+int res_protocolnumber(const char *);
+#ifdef __APPLE__
+static
+#endif
+int res_servicenumber(const char *);
+
+/*
+ * Form update packets.
+ * Returns the size of the resulting packet if no error
+ * On error,
+ * returns -1 if error in reading a word/number in rdata
+ * portion for update packets
+ * -2 if length of buffer passed is insufficient
+ * -3 if zone section is not the first section in
+ * the linked list, or section order has a problem
+ * -4 on a number overflow
+ * -5 unknown operation or no records
+ */
+int
+res_nmkupdate(res_state statp, ns_updrec *rrecp_in, u_char *buf, int buflen) {
+ ns_updrec *rrecp_start = rrecp_in;
+ HEADER *hp;
+ u_char *cp, *sp1, *sp2, *startp, *endp;
+ int n, i, soanum, multiline;
+ ns_updrec *rrecp;
+ struct in_addr ina;
+ struct in6_addr in6a;
+ char buf2[NS_MAXDNAME];
+ u_char buf3[NS_MAXDNAME];
+ int section, numrrs = 0, counts[ns_s_max];
+ u_int16_t rtype, rclass;
+ u_int32_t n1, rttl;
+ u_char *dnptrs[20], **dpp, **lastdnptr;
+ int siglen, keylen, certlen;
+
+ /*
+ * Initialize header fields.
+ */
+ if ((buf == NULL) || (buflen < NS_HFIXEDSZ))
+ return (-1);
+ memset(buf, 0, NS_HFIXEDSZ);
+ hp = (HEADER *) buf;
+#ifdef __APPLE__
+ hp->id = res_randomid();
+#else
+ hp->id = htons(++statp->id);
+#endif
+ hp->opcode = ns_o_update;
+ hp->rcode = ns_r_noerror;
+ sp1 = buf + 2*NS_INT16SZ; /* save pointer to zocount */
+ cp = buf + NS_HFIXEDSZ;
+ buflen -= NS_HFIXEDSZ;
+ dpp = dnptrs;
+ *dpp++ = buf;
+ *dpp++ = NULL;
+ lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
+
+ if (rrecp_start == NULL)
+ return (-5);
+ else if (rrecp_start->r_section != ns_s_zn)
+ return (-3);
+
+ memset(counts, 0, sizeof counts);
+ for (rrecp = rrecp_start; rrecp; rrecp = NEXT(rrecp, r_glink)) {
+ numrrs++;
+ section = rrecp->r_section;
+ if (section < 0 || section >= ns_s_max)
+ return (-1);
+ counts[section]++;
+ for (i = section + 1; i < ns_s_max; i++)
+ if (counts[i])
+ return (-3);
+ rtype = rrecp->r_type;
+ rclass = rrecp->r_class;
+ rttl = rrecp->r_ttl;
+ /* overload class and type */
+ if (section == ns_s_pr) {
+ rttl = 0;
+ switch (rrecp->r_opcode) {
+ case ns_r_yxdomain:
+ rclass = ns_c_any;
+ rtype = ns_t_any;
+ rrecp->r_size = 0;
+ break;
+ case ns_r_nxdomain:
+ rclass = ns_c_none;
+ rtype = ns_t_any;
+ rrecp->r_size = 0;
+ break;
+ case ns_r_nxrrset:
+ rclass = ns_c_none;
+ rrecp->r_size = 0;
+ break;
+ case ns_r_yxrrset:
+ if (rrecp->r_size == 0)
+ rclass = ns_c_any;
+ break;
+ default:
+ fprintf(stderr,
+ "res_mkupdate: incorrect opcode: %d\n",
+ rrecp->r_opcode);
+ fflush(stderr);
+ return (-1);
+ }
+ } else if (section == ns_s_ud) {
+ switch (rrecp->r_opcode) {
+ case ns_uop_delete:
+ rclass = rrecp->r_size == 0 ? ns_c_any : ns_c_none;
+ break;
+ case ns_uop_add:
+ break;
+ default:
+ fprintf(stderr,
+ "res_mkupdate: incorrect opcode: %d\n",
+ rrecp->r_opcode);
+ fflush(stderr);
+ return (-1);
+ }
+ }
+
+ /*
+ * XXX appending default domain to owner name is omitted,
+ * fqdn must be provided
+ */
+ if ((n = dn_comp(rrecp->r_dname, cp, buflen, dnptrs,
+ lastdnptr)) < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n + 2*NS_INT16SZ);
+ NS_PUT16(rtype, cp);
+ NS_PUT16(rclass, cp);
+ if (section == ns_s_zn) {
+ if (numrrs != 1 || rrecp->r_type != ns_t_soa)
+ return (-3);
+ continue;
+ }
+ ShrinkBuffer(NS_INT32SZ + NS_INT16SZ);
+ NS_PUT32(rttl, cp);
+ sp2 = cp; /* save pointer to length byte */
+ cp += NS_INT16SZ;
+ if (rrecp->r_size == 0) {
+ if (section == ns_s_ud && rclass != ns_c_any)
+ return (-1);
+ else {
+ NS_PUT16(0, sp2);
+ continue;
+ }
+ }
+ startp = rrecp->r_data;
+ endp = startp + rrecp->r_size - 1;
+ /* XXX this should be done centrally. */
+ switch (rrecp->r_type) {
+ case ns_t_a:
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ if (!inet_aton(buf2, &ina))
+ return (-1);
+ n1 = ntohl(ina.s_addr);
+ ShrinkBuffer(NS_INT32SZ);
+ NS_PUT32(n1, cp);
+ break;
+ case ns_t_cname:
+ case ns_t_mb:
+ case ns_t_mg:
+ case ns_t_mr:
+ case ns_t_ns:
+ case ns_t_ptr:
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ break;
+ case ns_t_minfo:
+ case ns_t_soa:
+ case ns_t_rp:
+ for (i = 0; i < 2; i++) {
+ if (!getword_str(buf2, sizeof buf2, &startp,
+ endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen,
+ dnptrs, lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ }
+ if (rrecp->r_type == ns_t_soa) {
+ ShrinkBuffer(5 * NS_INT32SZ);
+ while (isspace(*startp) || !*startp)
+ startp++;
+ if (*startp == '(') {
+ multiline = 1;
+ startp++;
+ } else
+ multiline = 0;
+ /* serial, refresh, retry, expire, minimum */
+ for (i = 0; i < 5; i++) {
+ soanum = getnum_str(&startp, endp);
+ if (soanum < 0)
+ return (-1);
+ NS_PUT32(soanum, cp);
+ }
+ if (multiline) {
+ while (isspace(*startp) || !*startp)
+ startp++;
+ if (*startp != ')')
+ return (-1);
+ }
+ }
+ break;
+ case ns_t_mx:
+ case ns_t_afsdb:
+ case ns_t_rt:
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(NS_INT16SZ);
+ NS_PUT16(n, cp);
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ break;
+ case ns_t_srv:
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(NS_INT16SZ);
+ NS_PUT16(n, cp);
+
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(NS_INT16SZ);
+ NS_PUT16(n, cp);
+
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(NS_INT16SZ);
+ NS_PUT16(n, cp);
+
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ break;
+ case ns_t_px:
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ NS_PUT16(n, cp);
+ ShrinkBuffer(NS_INT16SZ);
+ for (i = 0; i < 2; i++) {
+ if (!getword_str(buf2, sizeof buf2, &startp,
+ endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, dnptrs,
+ lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ }
+ break;
+ case ns_t_wks: {
+ char bm[MAXPORT/8];
+ unsigned int maxbm = 0;
+
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ if (!inet_aton(buf2, &ina))
+ return (-1);
+ n1 = ntohl(ina.s_addr);
+ ShrinkBuffer(NS_INT32SZ);
+ NS_PUT32(n1, cp);
+
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ if ((i = res_protocolnumber(buf2)) < 0)
+ return (-1);
+ ShrinkBuffer(1);
+ *cp++ = i & 0xff;
+
+ for (i = 0; i < MAXPORT/8 ; i++)
+ bm[i] = 0;
+
+ while (getword_str(buf2, sizeof buf2, &startp, endp)) {
+ if ((n1 = res_servicenumber(buf2)) <= 0)
+ return (-1);
+
+ if (n1 < MAXPORT) {
+ bm[n1/8] |= (0x80>>(n1%8));
+ if (n1 > maxbm)
+ maxbm = n1;
+ } else
+ return (-1);
+ }
+ maxbm = maxbm/8 + 1;
+ ShrinkBuffer(maxbm);
+ memcpy(cp, bm, maxbm);
+ cp += maxbm;
+ break;
+ }
+ case ns_t_hinfo:
+ for (i = 0; i < 2; i++) {
+ if ((n = getstr_str(buf2, sizeof buf2,
+ &startp, endp)) < 0)
+ return (-1);
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ }
+ break;
+ case ns_t_txt:
+ while (1) {
+ if ((n = getstr_str(buf2, sizeof buf2,
+ &startp, endp)) < 0) {
+ if (cp != (sp2 + NS_INT16SZ))
+ break;
+ return (-1);
+ }
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ }
+ break;
+ case ns_t_x25:
+ /* RFC 1183 */
+ if ((n = getstr_str(buf2, sizeof buf2, &startp,
+ endp)) < 0)
+ return (-1);
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ break;
+ case ns_t_isdn:
+ /* RFC 1183 */
+ if ((n = getstr_str(buf2, sizeof buf2, &startp,
+ endp)) < 0)
+ return (-1);
+ if ((n > 255) || (n == 0))
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ if ((n = getstr_str(buf2, sizeof buf2, &startp,
+ endp)) < 0)
+ n = 0;
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ break;
+ case ns_t_nsap:
+ if ((n = inet_nsap_addr((char *)startp, (u_char *)buf2, sizeof(buf2))) != 0) {
+ ShrinkBuffer(n);
+ memcpy(cp, buf2, n);
+ cp += n;
+ } else {
+ return (-1);
+ }
+ break;
+ case ns_t_loc:
+ if ((n = loc_aton((char *)startp, (u_char *)buf2)) != 0) {
+ ShrinkBuffer(n);
+ memcpy(cp, buf2, n);
+ cp += n;
+ } else
+ return (-1);
+ break;
+ case ns_t_sig:
+ {
+ int sig_type, success, dateerror;
+ u_int32_t exptime, timesigned;
+
+ /* type */
+ if ((n = getword_str(buf2, sizeof buf2,
+ &startp, endp)) < 0)
+ return (-1);
+ sig_type = sym_ston(__p_type_syms, buf2, &success);
+ if (!success || sig_type == ns_t_any)
+ return (-1);
+ ShrinkBuffer(NS_INT16SZ);
+ NS_PUT16(sig_type, cp);
+ /* alg */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(1);
+ *cp++ = n;
+ /* labels */
+ n = getnum_str(&startp, endp);
+ if (n <= 0 || n > 255)
+ return (-1);
+ ShrinkBuffer(1);
+ *cp++ = n;
+ /* ottl & expire */
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ exptime = ns_datetosecs(buf2, &dateerror);
+ if (!dateerror) {
+ ShrinkBuffer(NS_INT32SZ);
+ NS_PUT32(rttl, cp);
+ }
+ else {
+ char *ulendp;
+ u_int32_t ottl;
+
+ ottl = strtoul(buf2, &ulendp, 10);
+ if (ulendp != NULL && *ulendp != '\0')
+ return (-1);
+ ShrinkBuffer(NS_INT32SZ);
+ NS_PUT32(ottl, cp);
+ if (!getword_str(buf2, sizeof buf2, &startp,
+ endp))
+ return (-1);
+ exptime = ns_datetosecs(buf2, &dateerror);
+ if (dateerror)
+ return (-1);
+ }
+ /* expire */
+ ShrinkBuffer(NS_INT32SZ);
+ NS_PUT32(exptime, cp);
+ /* timesigned */
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ timesigned = ns_datetosecs(buf2, &dateerror);
+ if (!dateerror) {
+ ShrinkBuffer(NS_INT32SZ);
+ NS_PUT32(timesigned, cp);
+ }
+ else
+ return (-1);
+ /* footprint */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(NS_INT16SZ);
+ NS_PUT16(n, cp);
+ /* signer name */
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ /* sig */
+ if ((n = getword_str(buf2, sizeof buf2,
+ &startp, endp)) < 0)
+ return (-1);
+ siglen = b64_pton(buf2, buf3, sizeof(buf3));
+ if (siglen < 0)
+ return (-1);
+ ShrinkBuffer(siglen);
+ memcpy(cp, buf3, siglen);
+ cp += siglen;
+ break;
+ }
+ case ns_t_key:
+ /* flags */
+ n = gethexnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(NS_INT16SZ);
+ NS_PUT16(n, cp);
+ /* proto */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(1);
+ *cp++ = n;
+ /* alg */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(1);
+ *cp++ = n;
+ /* key */
+ if ((n = getword_str(buf2, sizeof buf2,
+ &startp, endp)) < 0)
+ return (-1);
+ keylen = b64_pton(buf2, buf3, sizeof(buf3));
+ if (keylen < 0)
+ return (-1);
+ ShrinkBuffer(keylen);
+ memcpy(cp, buf3, keylen);
+ cp += keylen;
+ break;
+ case ns_t_nxt:
+ {
+ int success, nxt_type;
+ u_char data[32];
+ int maxtype;
+
+ /* next name */
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ maxtype = 0;
+ memset(data, 0, sizeof data);
+ while (1) {
+ if (!getword_str(buf2, sizeof buf2, &startp,
+ endp))
+ break;
+ nxt_type = sym_ston(__p_type_syms, buf2,
+ &success);
+ if (!success || !ns_t_rr_p(nxt_type))
+ return (-1);
+ NS_NXT_BIT_SET(nxt_type, data);
+ if (nxt_type > maxtype)
+ maxtype = nxt_type;
+ }
+ n = maxtype/NS_NXT_BITS+1;
+ ShrinkBuffer(n);
+ memcpy(cp, data, n);
+ cp += n;
+ break;
+ }
+ case ns_t_cert:
+ /* type */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(NS_INT16SZ);
+ NS_PUT16(n, cp);
+ /* key tag */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(NS_INT16SZ);
+ NS_PUT16(n, cp);
+ /* alg */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(1);
+ *cp++ = n;
+ /* cert */
+ if ((n = getword_str(buf2, sizeof buf2,
+ &startp, endp)) < 0)
+ return (-1);
+ certlen = b64_pton(buf2, buf3, sizeof(buf3));
+ if (certlen < 0)
+ return (-1);
+ ShrinkBuffer(certlen);
+ memcpy(cp, buf3, certlen);
+ cp += certlen;
+ break;
+ case ns_t_aaaa:
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ if (inet_pton(AF_INET6, buf2, &in6a) <= 0)
+ return (-1);
+ ShrinkBuffer(NS_IN6ADDRSZ);
+ memcpy(cp, &in6a, NS_IN6ADDRSZ);
+ cp += NS_IN6ADDRSZ;
+ break;
+ default:
+ return (-1);
+ } /*switch*/
+ n = (u_int16_t)((cp - sp2) - NS_INT16SZ);
+ NS_PUT16(n, sp2);
+ } /*for*/
+
+ hp->qdcount = htons(counts[0]);
+ hp->ancount = htons(counts[1]);
+ hp->nscount = htons(counts[2]);
+ hp->arcount = htons(counts[3]);
+ return (cp - buf);
+}
+
+/*
+ * Get a whitespace delimited word from a string (not file)
+ * into buf. modify the start pointer to point after the
+ * word in the string.
+ */
+static int
+getword_str(char *buf, int size, u_char **startpp, u_char *endp) {
+ char *cp;
+ int c;
+
+ for (cp = buf; *startpp <= endp; ) {
+ c = **startpp;
+ if (isspace(c) || c == '\0') {
+ if (cp != buf) /* trailing whitespace */
+ break;
+ else { /* leading whitespace */
+ (*startpp)++;
+ continue;
+ }
+ }
+ (*startpp)++;
+ if (cp >= buf+size-1)
+ break;
+ *cp++ = (u_char)c;
+ }
+ *cp = '\0';
+ return (cp != buf);
+}
+
+/*
+ * get a white spae delimited string from memory. Process quoted strings
+ * and \DDD escapes. Return length or -1 on error. Returned string may
+ * contain nulls.
+ */
+static char digits[] = "0123456789";
+static int
+getstr_str(char *buf, int size, u_char **startpp, u_char *endp) {
+ char *cp;
+ int c, c1 = 0;
+ int inquote = 0;
+ int seen_quote = 0;
+ int escape = 0;
+ int dig = 0;
+
+ for (cp = buf; *startpp <= endp; ) {
+ if ((c = **startpp) == '\0')
+ break;
+ /* leading white space */
+ if ((cp == buf) && !seen_quote && isspace(c)) {
+ (*startpp)++;
+ continue;
+ }
+
+ switch (c) {
+ case '\\':
+ if (!escape) {
+ escape = 1;
+ dig = 0;
+ c1 = 0;
+ (*startpp)++;
+ continue;
+ }
+ goto do_escape;
+ case '"':
+ if (!escape) {
+ inquote = !inquote;
+ seen_quote = 1;
+ (*startpp)++;
+ continue;
+ }
+ /* fall through */
+ default:
+ do_escape:
+ if (escape) {
+ switch (c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ c1 = c1 * 10 +
+ (strchr(digits, c) - digits);
+
+ if (++dig == 3) {
+ c = c1 &0xff;
+ break;
+ }
+ (*startpp)++;
+ continue;
+ }
+ escape = 0;
+ } else if (!inquote && isspace(c))
+ goto done;
+ if (cp >= buf+size-1)
+ goto done;
+ *cp++ = (u_char)c;
+ (*startpp)++;
+ }
+ }
+ done:
+ *cp = '\0';
+ return ((cp == buf)? (seen_quote? 0: -1): (cp - buf));
+}
+/*
+ * Get a whitespace delimited base 16 number from a string (not file) into buf
+ * update the start pointer to point after the number in the string.
+ */
+static int
+gethexnum_str(u_char **startpp, u_char *endp) {
+ int c, n;
+ int seendigit = 0;
+ int m = 0;
+
+ if (*startpp + 2 >= endp || strncasecmp((char *)*startpp, "0x", 2) != 0)
+ return getnum_str(startpp, endp);
+ (*startpp)+=2;
+ for (n = 0; *startpp <= endp; ) {
+ c = **startpp;
+ if (isspace(c) || c == '\0') {
+ if (seendigit) /* trailing whitespace */
+ break;
+ else { /* leading whitespace */
+ (*startpp)++;
+ continue;
+ }
+ }
+ if (c == ';') {
+ while ((*startpp <= endp) &&
+ ((c = **startpp) != '\n'))
+ (*startpp)++;
+ if (seendigit)
+ break;
+ continue;
+ }
+ if (!isxdigit(c)) {
+ if (c == ')' && seendigit) {
+ (*startpp)--;
+ break;
+ }
+ return (-1);
+ }
+ (*startpp)++;
+ if (isdigit(c))
+ n = n * 16 + (c - '0');
+ else
+ n = n * 16 + (tolower(c) - 'a' + 10);
+ seendigit = 1;
+ }
+ return (n + m);
+}
+
+/*
+ * Get a whitespace delimited base 16 number from a string (not file) into buf
+ * update the start pointer to point after the number in the string.
+ */
+static int
+getnum_str(u_char **startpp, u_char *endp) {
+ int c, n;
+ int seendigit = 0;
+ int m = 0;
+
+ for (n = 0; *startpp <= endp; ) {
+ c = **startpp;
+ if (isspace(c) || c == '\0') {
+ if (seendigit) /* trailing whitespace */
+ break;
+ else { /* leading whitespace */
+ (*startpp)++;
+ continue;
+ }
+ }
+ if (c == ';') {
+ while ((*startpp <= endp) &&
+ ((c = **startpp) != '\n'))
+ (*startpp)++;
+ if (seendigit)
+ break;
+ continue;
+ }
+ if (!isdigit(c)) {
+ if (c == ')' && seendigit) {
+ (*startpp)--;
+ break;
+ }
+ return (-1);
+ }
+ (*startpp)++;
+ n = n * 10 + (c - '0');
+ seendigit = 1;
+ }
+ return (n + m);
+}
+
+/*
+ * Allocate a resource record buffer & save rr info.
+ */
+ns_updrec *
+res_mkupdrec(int section, const char *dname,
+ u_int class, u_int type, u_long ttl) {
+ ns_updrec *rrecp = (ns_updrec *)calloc(1, sizeof(ns_updrec));
+
+ if (!rrecp || !(rrecp->r_dname = strdup(dname))) {
+ if (rrecp)
+ free((char *)rrecp);
+ return (NULL);
+ }
+ INIT_LINK(rrecp, r_link);
+ INIT_LINK(rrecp, r_glink);
+ rrecp->r_class = class;
+ rrecp->r_type = type;
+ rrecp->r_ttl = ttl;
+ rrecp->r_section = section;
+ return (rrecp);
+}
+
+/*
+ * Free a resource record buffer created by res_mkupdrec.
+ */
+void
+res_freeupdrec(ns_updrec *rrecp) {
+ /* Note: freeing r_dp is the caller's responsibility. */
+ if (rrecp->r_dname != NULL)
+ free(rrecp->r_dname);
+ free(rrecp);
+}
+
+struct valuelist {
+ struct valuelist * next;
+ struct valuelist * prev;
+ char * name;
+ char * proto;
+ int port;
+};
+static struct valuelist *servicelist, *protolist;
+
+static void
+res_buildservicelist() {
+ struct servent *sp;
+ struct valuelist *slp;
+
+#ifdef MAYBE_HESIOD
+ setservent(0);
+#else
+ setservent(1);
+#endif
+ while ((sp = getservent()) != NULL) {
+ slp = (struct valuelist *)malloc(sizeof(struct valuelist));
+ if (!slp)
+ break;
+ slp->name = strdup(sp->s_name);
+ slp->proto = strdup(sp->s_proto);
+ if ((slp->name == NULL) || (slp->proto == NULL)) {
+ if (slp->name) free(slp->name);
+ if (slp->proto) free(slp->proto);
+ free(slp);
+ break;
+ }
+ slp->port = ntohs((u_int16_t)sp->s_port); /* host byt order */
+ slp->next = servicelist;
+ slp->prev = NULL;
+ if (servicelist)
+ servicelist->prev = slp;
+ servicelist = slp;
+ }
+ endservent();
+}
+
+void
+res_destroyservicelist() {
+ struct valuelist *slp, *slp_next;
+
+ for (slp = servicelist; slp != NULL; slp = slp_next) {
+ slp_next = slp->next;
+ free(slp->name);
+ free(slp->proto);
+ free(slp);
+ }
+ servicelist = (struct valuelist *)0;
+}
+
+void
+res_buildprotolist(void) {
+ struct protoent *pp;
+ struct valuelist *slp;
+
+#ifdef MAYBE_HESIOD
+ setprotoent(0);
+#else
+ setprotoent(1);
+#endif
+ while ((pp = getprotoent()) != NULL) {
+ slp = (struct valuelist *)malloc(sizeof(struct valuelist));
+ if (!slp)
+ break;
+ slp->name = strdup(pp->p_name);
+ if (slp->name == NULL) {
+ free(slp);
+ break;
+ }
+ slp->port = pp->p_proto; /* host byte order */
+ slp->next = protolist;
+ slp->prev = NULL;
+ if (protolist)
+ protolist->prev = slp;
+ protolist = slp;
+ }
+ endprotoent();
+}
+
+void
+res_destroyprotolist(void) {
+ struct valuelist *plp, *plp_next;
+
+ for (plp = protolist; plp != NULL; plp = plp_next) {
+ plp_next = plp->next;
+ free(plp->name);
+ free(plp);
+ }
+ protolist = (struct valuelist *)0;
+}
+
+static int
+findservice(const char *s, struct valuelist **list) {
+ struct valuelist *lp = *list;
+ int n;
+
+ for (; lp != NULL; lp = lp->next)
+ if (strcasecmp(lp->name, s) == 0) {
+ if (lp != *list) {
+ lp->prev->next = lp->next;
+ if (lp->next)
+ lp->next->prev = lp->prev;
+ (*list)->prev = lp;
+ lp->next = *list;
+ *list = lp;
+ }
+ return (lp->port); /* host byte order */
+ }
+ if (sscanf(s, "%d", &n) != 1 || n <= 0)
+ n = -1;
+ return (n);
+}
+
+/*
+ * Convert service name or (ascii) number to int.
+ */
+#ifdef __APPLE__
+static
+#endif
+int
+res_servicenumber(const char *p) {
+ if (servicelist == (struct valuelist *)0)
+ res_buildservicelist();
+ return (findservice(p, &servicelist));
+}
+
+/*
+ * Convert protocol name or (ascii) number to int.
+ */
+#ifdef __APPLE__
+static
+#endif
+int
+res_protocolnumber(const char *p) {
+ if (protolist == (struct valuelist *)0)
+ res_buildprotolist();
+ return (findservice(p, &protolist));
+}
+
+static struct servent *
+cgetservbyport(u_int16_t port, const char *proto) { /* Host byte order. */
+ struct valuelist **list = &servicelist;
+ struct valuelist *lp = *list;
+ static struct servent serv;
+
+ port = ntohs(port);
+ for (; lp != NULL; lp = lp->next) {
+ if (port != (u_int16_t)lp->port) /* Host byte order. */
+ continue;
+ if (strcasecmp(lp->proto, proto) == 0) {
+ if (lp != *list) {
+ lp->prev->next = lp->next;
+ if (lp->next)
+ lp->next->prev = lp->prev;
+ (*list)->prev = lp;
+ lp->next = *list;
+ *list = lp;
+ }
+ serv.s_name = lp->name;
+ serv.s_port = htons((u_int16_t)lp->port);
+ serv.s_proto = lp->proto;
+ return (&serv);
+ }
+ }
+ return (0);
+}
+
+static struct protoent *
+cgetprotobynumber(int proto) { /* Host byte order. */
+ struct valuelist **list = &protolist;
+ struct valuelist *lp = *list;
+ static struct protoent prot;
+
+ for (; lp != NULL; lp = lp->next)
+ if (lp->port == proto) { /* Host byte order. */
+ if (lp != *list) {
+ lp->prev->next = lp->next;
+ if (lp->next)
+ lp->next->prev = lp->prev;
+ (*list)->prev = lp;
+ lp->next = *list;
+ *list = lp;
+ }
+ prot.p_name = lp->name;
+ prot.p_proto = lp->port; /* Host byte order. */
+ return (&prot);
+ }
+ return (0);
+}
+
+const char *
+res_protocolname(int num) {
+ static char number[8];
+ struct protoent *pp;
+
+ if (protolist == (struct valuelist *)0)
+ res_buildprotolist();
+ pp = cgetprotobynumber(num);
+ if (pp == 0) {
+ (void) sprintf(number, "%d", num);
+ return (number);
+ }
+ return (pp->p_name);
+}
+
+const char *
+res_servicename(u_int16_t port, const char *proto) { /* Host byte order. */
+ static char number[8];
+ struct servent *ss;
+
+ if (servicelist == (struct valuelist *)0)
+ res_buildservicelist();
+ ss = cgetservbyport(htons(port), proto);
+ if (ss == 0) {
+ (void) sprintf(number, "%d", port);
+ return (number);
+ }
+ return (ss->s_name);
+}
--- /dev/null
+#ifndef res_9_private_h
+#define res_9_private_h
+#include <arpa/inet.h>
+#include <sys/time.h>
+#include <stdint.h>
+
+/*
+ * status codes from dns_res_xxx SPIs
+ * positive numbers are ns_rcode values.
+ */
+#define DNS_RES_STATUS_TIMEOUT -1001
+#define DNS_RES_STATUS_CANCELLED -1002
+#define DNS_RES_STATUS_INVALID_QUERY -1003
+#define DNS_RES_STATUS_INVALID_ARGUMENT -1004
+#define DNS_RES_STATUS_INVALID_RES_STATE -1005
+#define DNS_RES_STATUS_INVALID_REPLY -1006
+#define DNS_RES_STATUS_CONNECTION_REFUSED -1007
+#define DNS_RES_STATUS_SEND_FAILED -1008
+#define DNS_RES_STATUS_CONNECTION_FAILED -1009
+#define DNS_RES_STATUS_SYSTEM_ERROR -1010
+
+#define RES_EXT_SUFFIX_LEN 64
+
+typedef struct {
+ unsigned id :16; /* query identification number */
+#if BYTE_ORDER == BIG_ENDIAN
+ /* fields in third byte */
+ unsigned qr: 1; /* response flag */
+ unsigned opcode: 4; /* purpose of message */
+ unsigned aa: 1; /* authoritive answer */
+ unsigned tc: 1; /* truncated message */
+ unsigned rd: 1; /* recursion desired */
+ /* fields in fourth byte */
+ unsigned ra: 1; /* recursion available */
+ unsigned unused :3; /* unused bits (MBZ as of 4.9.3a3) */
+ unsigned rcode :4; /* response code */
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
+ /* fields in third byte */
+ unsigned rd :1; /* recursion desired */
+ unsigned tc :1; /* truncated message */
+ unsigned aa :1; /* authoritive answer */
+ unsigned opcode :4; /* purpose of message */
+ unsigned qr :1; /* response flag */
+ /* fields in fourth byte */
+ unsigned rcode :4; /* response code */
+ unsigned unused :3; /* unused bits (MBZ as of 4.9.3a3) */
+ unsigned ra :1; /* recursion available */
+#endif
+ /* remaining bytes */
+ unsigned qdcount :16; /* number of question entries */
+ unsigned ancount :16; /* number of answer entries */
+ unsigned nscount :16; /* number of authority entries */
+ unsigned arcount :16; /* number of resource entries */
+} HEADER;
+
+#ifndef __res_state_ext
+#define __res_state_ext __res_9_res_state_ext
+#endif
+
+struct __res_state_ext {
+ union res_sockaddr_union nsaddrs[MAXNS];
+ struct sort_list {
+ int af;
+ union {
+ struct in_addr ina;
+ struct in6_addr in6a;
+ } addr, mask;
+ } sort_list[MAXRESOLVSORT];
+ char nsuffix[64];
+ char bsuffix[64];
+ char nsuffix2[64];
+};
+
+#define get_nsaddr res_9_get_nsaddr
+struct sockaddr *get_nsaddr __P((res_state, size_t));
+
+#define res_nsend_2 res_9_nsend_2
+int res_nsend_2(res_state, const u_char *, int, u_char *, int, struct sockaddr *, int *);
+
+#define res_ourserver_p res_9_ourserver_p
+int res_ourserver_p(const res_state, const struct sockaddr *);
+
+res_state res_state_new();
+void res_client_close(res_state res);
+
+/*
+ * From lookupd Thread.h. We use this to signal threads to quit, since pthread_cancel() doesn't work.
+ */
+#define ThreadStateExitRequested 4
+
+/*
+ * notification SPI
+ */
+extern uint32_t notify_register_plain(const char *name, int *out_token);
+
+__private_extern__ int res_query_mDNSResponder(res_state statp, const char *name, int class, int type, u_char *answer, int anslen, struct sockaddr *from, uint32_t *fromlen);
+
+int dns_res_once(struct sockaddr *server, struct timeval *timeout, int options, const char *name, int class, int type, u_char *res, int *reslen);
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_query.c,v 1.1 2006/03/01 19:01:38 majka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#ifndef __APPLE__
+#include "port_before.h"
+#endif
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "res_private.h"
+#include <dns_sd.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+#ifndef __APPLE__
+#include "port_after.h"
+#endif
+
+/* Options. Leave them on. */
+#define DEBUG
+
+#if PACKETSZ > 1024
+#define MAXPACKET PACKETSZ
+#else
+#define MAXPACKET 1024
+#endif
+
+#define BILLION 1000000000
+
+/* length of a reverse DNS IPv6 address query name, e.g. "9.4.a.f.c.e.e.f.e.e.1.5.4.1.4.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa" */
+#define IPv6_REVERSE_LEN 72
+
+/* index of the trailing char that must be "8", "9", "A", "a", "b", or "B" */
+#define IPv6_REVERSE_LINK_LOCAL_TRAILING_CHAR 58
+
+/* index of low-order nibble of embedded scope id */
+#define IPv6_REVERSE_LINK_LOCAL_SCOPE_ID_LOW 48
+
+const static uint8_t hexval[128] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 15 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 - 31 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 32 - 47 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 48 - 63 */
+ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 64 - 79 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 95 */
+ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 96 - 111 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 112 - 127 */
+};
+
+struct res_query_context
+{
+ u_char *answer;
+ size_t anslen;
+ size_t ansmaxlen;
+ uint32_t ifnum;
+ DNSServiceFlags flags;
+ DNSServiceErrorType error;
+};
+
+static void
+res_query_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode, const char *fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *ctx)
+{
+ struct res_query_context *context;
+ int n;
+ size_t buflen;
+ u_char *dnlist[2], *cp;
+ HEADER *ans;
+ struct in6_addr a6;
+
+ context = (struct res_query_context *)ctx;
+
+ context->flags = flags;
+ context->error = errorCode;
+
+ if (errorCode != kDNSServiceErr_NoError) return;
+
+ buflen = context->ansmaxlen - context->anslen;
+ if (buflen < NS_HFIXEDSZ) return;
+
+ dnlist[0] = context->answer + NS_HFIXEDSZ;
+ dnlist[1] = NULL;
+
+ cp = context->answer + context->anslen;
+
+ n = dn_comp((char *)fullname, cp, buflen, dnlist, &dnlist[1]);
+ if (n < 0) return;
+
+ /*
+ * Check that there is enough space in the buffer for the resource name (n),
+ * the resource record data (rdlen) and the resource record header (10).
+ */
+ if (buflen < n + rdlen + 10) return;
+
+ cp += n;
+ buflen -= n;
+
+ putshort(rrtype, cp);
+ cp += sizeof(uint16_t);
+
+ putshort(rrclass, cp);
+ cp += sizeof(uint16_t);
+
+ putlong(ttl, cp);
+ cp += sizeof(uint32_t);
+
+ putshort(rdlen, cp);
+ cp += sizeof(uint16_t);
+
+ memcpy(cp, rdata, rdlen);
+ cp += rdlen;
+
+ ans = (HEADER *)context->answer;
+ ans->ancount = htons(ntohs(ans->ancount) + 1);
+
+ context->anslen = (size_t)(cp - context->answer);
+
+ /*
+ * Save the interface number for the first AAAA record for link-local addresses.
+ * It's used by getaddrinfo to set the scope id.
+ */
+ if ((context->ifnum == 0) && (rrtype == ns_t_aaaa))
+ {
+ memset(&a6, 0, sizeof(struct in6_addr));
+ memcpy(&a6, rdata, sizeof(struct in6_addr));
+ if (IN6_IS_ADDR_LINKLOCAL(&a6)) context->ifnum = ifIndex;
+ }
+}
+
+static void
+h_errno_for_dnssd_err(DNSServiceErrorType dnssd_err, int *h_errno_err)
+{
+ switch (dnssd_err)
+ {
+ case kDNSServiceErr_NoError:
+ *h_errno_err = NETDB_SUCCESS;
+ break;
+ case kDNSServiceErr_Unknown:
+ *h_errno_err = NO_RECOVERY;
+ break;
+ case kDNSServiceErr_NoSuchRecord:
+ *h_errno_err = NO_DATA;
+ break;
+ case kDNSServiceErr_NoSuchName:
+ *h_errno_err = HOST_NOT_FOUND;
+ break;
+ case kDNSServiceErr_NoMemory:
+ default:
+ *h_errno_err = NETDB_INTERNAL;
+ break;
+ }
+}
+
+static int
+_is_rev_link_local(const char *name)
+{
+ int len, i;
+
+ if (name == NULL) return 0;
+
+ len = strlen(name);
+ if (len == 0) return 0;
+
+ /* check for trailing '.' */
+ if (name[len - 1] == '.') len--;
+
+ if (len != IPv6_REVERSE_LEN) return 0;
+
+ i = IPv6_REVERSE_LINK_LOCAL_TRAILING_CHAR;
+ if ((name[i] != '8') && (name[i] != '9') && (name[i] != 'A') && (name[i] != 'a') && (name[i] != 'B') && (name[i] != 'b')) return 0;
+
+ i = IPv6_REVERSE_LINK_LOCAL_TRAILING_CHAR + 1;
+ if (strncasecmp(name + i, ".e.f.ip6.arpa", 13)) return 0;
+
+ for (i = 0; i < IPv6_REVERSE_LINK_LOCAL_TRAILING_CHAR; i += 2)
+ {
+ if (name[i] < '0') return 0;
+ if ((name[i] > '9') && (name[i] < 'A')) return 0;
+ if ((name[i] > 'F') && (name[i] < 'a')) return 0;
+ if (name[i] > 'f') return 0;
+ if (name[i + 1] != '.') return 0;
+ }
+
+ return 1;
+}
+
+__private_extern__ int
+res_query_mDNSResponder(res_state statp, const char *name, int class, int type, u_char *answer, int anslen, struct sockaddr *from, uint32_t *fromlen)
+{
+ DNSServiceRef sdRef;
+ DNSServiceErrorType result;
+ struct res_query_context context;
+ int i, kq, n, wait;
+ struct kevent kv;
+ struct timeval ctv;
+ struct timespec now, finish, timeout;
+ HEADER *ans;
+ uint32_t iface;
+ uint16_t nibble;
+ char *qname;
+ result = 0;
+ kq = -1;
+ ans = (HEADER *)answer;
+
+ ans->rcode = 0;
+
+ memset(&context, 0, sizeof(struct res_query_context));
+
+ /* Build a dummy DNS header with question for the answer */
+ context.answer = answer;
+ context.ansmaxlen = anslen;
+ context.anslen = res_nmkquery(statp, ns_o_query, name, class, type, NULL, 0, NULL, answer, anslen);
+ if (context.anslen <= 0) return 0;
+
+ /* Mark DNS packet as a response */
+ ans->qr = 1;
+ ans->qr = htons(ans->qr);
+
+ /* Pull out Scope ID in link-local reverse queries */
+ qname = (char *)name;
+ iface = 0;
+ if (_is_rev_link_local(name))
+ {
+ /* _is_rev_link_local rejects chars > 127 so it's safe to index into hexval */
+ i = IPv6_REVERSE_LINK_LOCAL_SCOPE_ID_LOW;
+ nibble = hexval[(uint32_t)name[i]];
+ iface = nibble;
+
+ i += 2;
+ nibble = hexval[(uint32_t)name[i]];
+ iface += (nibble << 4);
+
+ i += 2;
+ nibble = hexval[(uint32_t)name[i]];
+ iface += (nibble << 8);
+
+ i += 2;
+ nibble = hexval[(uint32_t)name[i]];
+ iface += (nibble << 12);
+
+ if (iface != 0)
+ {
+ qname = strdup(name);
+ if (qname == NULL)
+ {
+ h_errno = NO_RECOVERY;
+ errno = ENOMEM;
+ return -1;
+ }
+
+ i = IPv6_REVERSE_LINK_LOCAL_SCOPE_ID_LOW;
+ qname[i] = '0';
+ qname[i + 2] = '0';
+ qname[i + 4] = '0';
+ qname[i + 6] = '0';
+ }
+ }
+
+ result = DNSServiceQueryRecord(&sdRef, kDNSServiceFlagsReturnIntermediates, iface, qname, type, class, res_query_callback, &context);
+ if (iface != 0) free(qname);
+
+ if (result != 0) return 0;
+
+ /* Use a kqueue to wait for a response from mDNSResponder */
+ kq = kqueue();
+
+ /* determine the maximum time to wait for a result */
+ gettimeofday(&ctv, NULL);
+
+ /* N.B. statp->retrans is actually the total timeount in seconds */
+ timeout.tv_sec = statp->retrans;
+ timeout.tv_nsec = 0;
+
+ finish.tv_sec = ctv.tv_sec + statp->retrans;
+ finish.tv_nsec = ctv.tv_usec * 1000;
+
+ EV_SET(&kv, DNSServiceRefSockFD(sdRef), EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0);
+
+ wait = 1;
+ while (wait == 1)
+ {
+ n = kevent(kq, &kv, 1, &kv, 1, &timeout);
+
+ if (n < 0)
+ {
+ if (errno == EINTR) goto keep_waiting;
+ h_errno = NO_RECOVERY;
+ wait = 0;
+ }
+ else if ((n == 0) && (ans->ancount == 0))
+ {
+ h_errno = TRY_AGAIN;
+ wait = 0;
+ }
+ else
+ {
+ result = DNSServiceProcessResult(sdRef);
+ if ((result != 0) || (context.error != 0))
+ {
+ if (result == 0) result = context.error;
+ h_errno_for_dnssd_err(result, &h_errno);
+ wait = 0;
+ }
+
+ if ((ans->ancount > 0) && ((context.flags & kDNSServiceFlagsMoreComing) == 0)) wait = 0;
+ }
+
+ keep_waiting:
+
+ if (wait == 1)
+ {
+ /* calculate remaining timeout */
+ gettimeofday(&ctv, NULL);
+
+ now.tv_sec = ctv.tv_sec;
+ now.tv_nsec = ctv.tv_usec * 1000;
+
+ timeout.tv_sec = finish.tv_sec - now.tv_sec;
+ if (finish.tv_nsec >= now.tv_nsec)
+ {
+ timeout.tv_nsec = finish.tv_nsec - now.tv_nsec;
+ }
+ else
+ {
+ timeout.tv_nsec = BILLION - now.tv_nsec + finish.tv_nsec;
+ timeout.tv_sec--;
+ }
+ }
+ }
+
+ DNSServiceRefDeallocate(sdRef);
+ close(kq);
+
+ if (ans->ancount == 0) context.anslen = -1;
+
+ if ((from != NULL) && (fromlen != NULL) && (context.ifnum != 0))
+ {
+ ((struct sockaddr_in6 *)from)->sin6_len = sizeof(struct sockaddr_in6);
+ ((struct sockaddr_in6 *)from)->sin6_family = AF_INET6;
+ ((struct sockaddr_in6 *)from)->sin6_addr.__u6_addr.__u6_addr8[15] = 1;
+ ((struct sockaddr_in6 *)from)->sin6_scope_id = context.ifnum;
+ *fromlen = sizeof(struct sockaddr_in6);
+ }
+
+ return context.anslen;
+}
+
+static int
+res_soa_minimum(const u_char *msg, int len)
+{
+ ns_msg handle;
+ const u_char *eom;
+ uint32_t i, b;
+ int min, soa_min;
+
+ eom = msg + len;
+
+ handle._msg = msg;
+ handle._eom = eom;
+
+ if (msg + NS_INT16SZ > eom) return -1;
+ NS_GET16(handle._id, msg);
+
+ if (msg + NS_INT16SZ > eom) return -1;
+ NS_GET16(handle._flags, msg);
+
+ for (i = 0; i < ns_s_max; i++)
+ {
+ if (msg + NS_INT16SZ > eom) return -1;
+ NS_GET16(handle._counts[i], msg);
+ }
+
+ if (handle._counts[ns_s_ns] == 0) return -1;
+
+ /* Skip forward to nameserver section */
+ for (i = 0; i < ns_s_ns; i++)
+ {
+ if (handle._counts[i] == 0) handle._sections[i] = NULL;
+ else
+ {
+ b = ns_skiprr(msg, eom, (ns_sect)i, handle._counts[i]);
+ if (b < 0) return -1;
+
+ handle._sections[i] = msg;
+ msg += b;
+ }
+ }
+
+ min = -1;
+ for (i = 0; i < handle._counts[ns_s_ns]; i++)
+ {
+ b = ns_skiprr(msg, eom, ns_s_ns, 1);
+ if (b < 0) return -1;
+
+ memcpy(&soa_min, msg + b - sizeof(int32_t), sizeof(int32_t));
+ soa_min = ntohl(soa_min);
+ if ((i == 0) || (soa_min < min)) min = soa_min;
+ msg += b;
+ }
+
+ return min;
+}
+
+/*
+ * Formulate a normal query, send, and await answer.
+ * Returned answer is placed in supplied buffer "answer".
+ * Perform preliminary check of answer, returning success only
+ * if no error is indicated and the answer count is nonzero.
+ * Return the size of the response on success, -1 on error.
+ * Error number is left in H_ERRNO.
+ *
+ * Caller must parse answer and determine whether it answers the question.
+ */
+__private_extern__ int
+res_nquery_soa_min(res_state statp, const char *name, int class, int type, u_char *answer, int anslen, struct sockaddr *from, int *fromlen, int *min)
+{
+ u_char buf[MAXPACKET];
+ HEADER *hp = (HEADER *) answer;
+ int n;
+ u_int oflags;
+
+ if (min != NULL) *min = -1;
+
+ oflags = statp->_flags;
+
+again:
+ __h_errno_set(statp, 0);
+ hp->rcode = ns_r_noerror; /* default */
+
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG) printf(";; res_query(%s, %d, %d)\n", name, class, type);
+#endif
+
+ n = res_nmkquery(statp, ns_o_query, name, class, type, NULL, 0, NULL, buf, sizeof(buf));
+#ifdef RES_USE_EDNS0
+ if (n > 0 && (statp->_flags & RES_F_EDNS0ERR) == 0 && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
+ n = res_nopt(statp, n, buf, sizeof(buf), anslen);
+#endif
+ if (n <= 0)
+ {
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG) printf(";; res_query: mkquery failed\n");
+#endif
+ __h_errno_set(statp, NO_RECOVERY);
+ return (n);
+ }
+
+ n = res_nsend_2(statp, buf, n, answer, anslen, from, fromlen);
+ if (n < 0)
+ {
+#ifdef RES_USE_EDNS0
+ /* if the query choked with EDNS0, retry without EDNS0 */
+ if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0 && ((oflags ^ statp->_flags) & RES_F_EDNS0ERR) != 0)
+ {
+ statp->_flags |= RES_F_EDNS0ERR;
+ if (statp->options & RES_DEBUG) printf(";; res_nquery: retry without EDNS0\n");
+ goto again;
+ }
+#endif
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG) printf(";; res_query: send error\n");
+#endif
+ __h_errno_set(statp, TRY_AGAIN);
+ return (n);
+ }
+
+ if (hp->rcode != ns_r_noerror || ntohs(hp->ancount) == 0)
+ {
+ if (min != NULL)
+ {
+ *min = res_soa_minimum(answer, anslen);
+ if (statp->options & RES_DEBUG) printf(";; res_nquery: SOA minimum = %d\n", *min);
+ }
+
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG) printf(";; rcode = %d, ancount=%d\n", hp->rcode, ntohs(hp->ancount));
+#endif
+ switch (hp->rcode)
+ {
+ case ns_r_nxdomain:
+ __h_errno_set(statp, HOST_NOT_FOUND);
+ break;
+ case ns_r_servfail:
+ __h_errno_set(statp, TRY_AGAIN);
+ break;
+ case ns_r_noerror:
+ __h_errno_set(statp, NO_DATA);
+ break;
+ case ns_r_formerr:
+ case ns_r_notimpl:
+ case ns_r_refused:
+ default:
+ __h_errno_set(statp, NO_RECOVERY);
+ break;
+ }
+
+ return (-1);
+ }
+
+ return (n);
+}
+
+int
+res_nquery_2(res_state statp, const char *name, int class, int type, u_char *answer, int anslen, struct sockaddr *from, int *fromlen)
+{
+ int unused = 0;
+
+ return res_nquery_soa_min(statp, name, class, type, answer, anslen, from, fromlen, &unused);
+}
+
+int
+res_nquery(res_state statp, const char *name, int class, int type, u_char *answer, int anslen)
+{
+ struct sockaddr_storage f;
+ int l;
+
+ l = sizeof(struct sockaddr_storage);
+
+ return res_nquery_2(statp, name, class, type, answer, anslen, (struct sockaddr *)&f, &l);
+}
+
+/*
+ * Perform a call on res_query on the concatenation of name and domain,
+ * removing a trailing dot from name if domain is NULL.
+ */
+int
+res_nquerydomain_2(res_state statp, const char *name, const char *domain, int class, int type, u_char *answer, int anslen, struct sockaddr *from, int *fromlen)
+{
+ char nbuf[NS_MAXDNAME];
+ const char *longname = nbuf;
+ int n, d;
+
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG) printf(";; res_nquerydomain(%s, %s, %d, %d)\n", name, domain?domain:"<Nil>", class, type);
+#endif
+ if (domain == NULL)
+ {
+ /*
+ * Check for trailing '.';
+ * copy without '.' if present.
+ */
+ n = strlen(name);
+ if (n >= NS_MAXDNAME)
+ {
+ __h_errno_set(statp, NO_RECOVERY);
+ return (-1);
+ }
+
+ n--;
+ if (n >= 0 && name[n] == '.')
+ {
+ strncpy(nbuf, name, n);
+ nbuf[n] = '\0';
+ }
+ else
+ {
+ longname = name;
+ }
+ }
+ else
+ {
+ n = strlen(name);
+ d = strlen(domain);
+ if (n + d + 1 >= NS_MAXDNAME)
+ {
+ __h_errno_set(statp, NO_RECOVERY);
+ return (-1);
+ }
+
+ sprintf(nbuf, "%s.%s", name, domain);
+ }
+
+ return (res_nquery_2(statp, longname, class, type, answer, anslen, from, fromlen));
+}
+
+int
+res_nquerydomain(res_state statp, const char *name, const char *domain, int class, int type, u_char *answer, int anslen)
+{
+ struct sockaddr_storage f;
+ int l;
+
+ l = sizeof(struct sockaddr_storage);
+
+ return res_nquerydomain_2(statp, name, domain, class, type, answer, anslen, (struct sockaddr *)&f, &l);
+}
+
+/*
+ * Formulate a normal query, send, and retrieve answer in supplied buffer.
+ * Return the size of the response on success, -1 on error.
+ * If enabled, implement search rules until answer or unrecoverable failure
+ * is detected. Error code, if any, is left in H_ERRNO.
+ */
+int
+res_nsearch_2(res_state statp, const char *name, int class, int type, u_char *answer, int anslen, struct sockaddr *from, int *fromlen)
+{
+ const char *cp, * const *domain;
+ HEADER *hp = (HEADER *) answer;
+ char tmp[NS_MAXDNAME];
+ u_int dots;
+ int trailing_dot, ret, saved_herrno;
+ int got_nodata = 0, got_servfail = 0, root_on_list = 0;
+ int tried_as_is = 0;
+ int searched = 0;
+
+ errno = 0;
+ __h_errno_set(statp, HOST_NOT_FOUND); /* True if we never query. */
+
+ dots = 0;
+ for (cp = name; *cp != '\0'; cp++) dots += (*cp == '.');
+
+ trailing_dot = 0;
+ if (cp > name && *--cp == '.') trailing_dot++;
+
+ /* If there aren't any dots, it could be a user-level alias. */
+ if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL)
+ return (res_nquery(statp, cp, class, type, answer, anslen));
+
+ /*
+ * If there are enough dots in the name, let's just give it a
+ * try 'as is'. The threshold can be set with the "ndots" option.
+ * Also, query 'as is', if there is a trailing dot in the name.
+ */
+ saved_herrno = -1;
+ if (dots >= statp->ndots || trailing_dot)
+ {
+ ret = res_nquerydomain_2(statp, name, NULL, class, type, answer, anslen, from, fromlen);
+ if (ret > 0 || trailing_dot) return (ret);
+ saved_herrno = h_errno;
+ tried_as_is++;
+ }
+
+ /*
+ * We do at least one level of search if
+ * - there is no dot and RES_DEFNAME is set, or
+ * - there is at least one dot, there is no trailing dot,
+ * and RES_DNSRCH is set.
+ */
+ if ((!dots && (statp->options & RES_DEFNAMES) != 0) || (dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0))
+ {
+ int done = 0;
+
+ for (domain = (const char * const *)statp->dnsrch; *domain && !done; domain++)
+ {
+ searched = 1;
+
+ if (domain[0][0] == '\0' || (domain[0][0] == '.' && domain[0][1] == '\0')) root_on_list++;
+
+ ret = res_nquerydomain_2(statp, name, *domain, class, type, answer, anslen, from, fromlen);
+ if (ret > 0) return (ret);
+
+ /*
+ * If no server present, give up.
+ * If name isn't found in this domain,
+ * keep trying higher domains in the search list
+ * (if that's enabled).
+ * On a NO_DATA error, keep trying, otherwise
+ * a wildcard entry of another type could keep us
+ * from finding this entry higher in the domain.
+ * If we get some other error (negative answer or
+ * server failure), then stop searching up,
+ * but try the input name below in case it's
+ * fully-qualified.
+ */
+ if (errno == ECONNREFUSED)
+ {
+ __h_errno_set(statp, TRY_AGAIN);
+ return (-1);
+ }
+
+ switch (statp->res_h_errno)
+ {
+ case NO_DATA:
+ got_nodata++;
+ /* FALLTHROUGH */
+ case HOST_NOT_FOUND:
+ /* keep trying */
+ break;
+ case TRY_AGAIN:
+ if (hp->rcode == ns_r_refused)
+ {
+ /* try next search element, if any */
+ got_servfail++;
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ /* anything else implies that we're done */
+ done++;
+ }
+
+ /* if we got here for some reason other than DNSRCH,
+ * we only wanted one iteration of the loop, so stop.
+ */
+ if ((statp->options & RES_DNSRCH) == 0) done++;
+ }
+ }
+
+ /*
+ * If the query has not already been tried as is then try it
+ * unless RES_NOTLDQUERY is set and there were no dots.
+ */
+ if ((dots || !searched || (statp->options & RES_NOTLDQUERY) == 0) && !(tried_as_is || root_on_list))
+ {
+ ret = res_nquerydomain_2(statp, name, NULL, class, type, answer, anslen, from, fromlen);
+ if (ret > 0) return (ret);
+ }
+
+ /* if we got here, we didn't satisfy the search.
+ * if we did an initial full query, return that query's H_ERRNO
+ * (note that we wouldn't be here if that query had succeeded).
+ * else if we ever got a nodata, send that back as the reason.
+ * else send back meaningless H_ERRNO, that being the one from
+ * the last DNSRCH we did.
+ */
+ if (saved_herrno != -1)
+ __h_errno_set(statp, saved_herrno);
+ else if (got_nodata)
+ __h_errno_set(statp, NO_DATA);
+ else if (got_servfail)
+ __h_errno_set(statp, TRY_AGAIN);
+ return (-1);
+}
+
+int
+__res_nsearch_list_2(res_state statp, const char *name, int class, int type, u_char *answer, int anslen, struct sockaddr *from, int *fromlen, int nsearch, char **search)
+{
+ const char *cp, *domain;
+ HEADER *hp = (HEADER *) answer;
+ char tmp[NS_MAXDNAME];
+ u_int dots;
+ int trailing_dot, ret, saved_herrno, i;
+ int got_nodata = 0, got_servfail = 0, root_on_list = 0;
+ int tried_as_is = 0;
+ int searched = 0;
+
+ errno = 0;
+ __h_errno_set(statp, HOST_NOT_FOUND); /* True if we never query. */
+
+ dots = 0;
+ for (cp = name; *cp != '\0'; cp++) dots += (*cp == '.');
+
+ trailing_dot = 0;
+ if (cp > name && *--cp == '.') trailing_dot++;
+
+ /* If there aren't any dots, it could be a user-level alias. */
+ if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp)) != NULL)
+ return (res_nquery(statp, cp, class, type, answer, anslen));
+
+ /*
+ * If there are enough dots in the name, let's just give it a
+ * try 'as is'. The threshold can be set with the "ndots" option.
+ * Also, query 'as is', if there is a trailing dot in the name.
+ */
+ saved_herrno = -1;
+ if (dots >= statp->ndots || trailing_dot)
+ {
+ ret = res_nquerydomain(statp, name, NULL, class, type, answer, anslen);
+ if (ret > 0 || trailing_dot) return ret;
+ saved_herrno = h_errno;
+ tried_as_is++;
+ }
+
+ /*
+ * We do at least one level of search if
+ * - there is no dot and RES_DEFNAME is set, or
+ * - there is at least one dot, there is no trailing dot,
+ * and RES_DNSRCH is set.
+ */
+ if ((!dots && (statp->options & RES_DEFNAMES) != 0) || (dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0))
+ {
+ int done = 0;
+
+ for (i = 0; i < nsearch; i++)
+ {
+ domain = search[i];
+ searched = 1;
+
+ if (domain[0] == '\0' || (domain[0] == '.' && domain[1] == '\0')) root_on_list++;
+
+ ret = res_nquerydomain_2(statp, name, domain, class, type, answer, anslen, from, fromlen);
+ if (ret > 0) return ret;
+
+ /*
+ * If no server present, give up.
+ * If name isn't found in this domain,
+ * keep trying higher domains in the search list
+ * (if that's enabled).
+ * On a NO_DATA error, keep trying, otherwise
+ * a wildcard entry of another type could keep us
+ * from finding this entry higher in the domain.
+ * If we get some other error (negative answer or
+ * server failure), then stop searching up,
+ * but try the input name below in case it's
+ * fully-qualified.
+ */
+ if (errno == ECONNREFUSED)
+ {
+ __h_errno_set(statp, TRY_AGAIN);
+ return -1;
+ }
+
+ switch (statp->res_h_errno)
+ {
+ case NO_DATA:
+ got_nodata++;
+ /* FALLTHROUGH */
+ case HOST_NOT_FOUND:
+ /* keep trying */
+ break;
+ case TRY_AGAIN:
+ if (hp->rcode == ns_r_refused)
+ {
+ /* try next search element, if any */
+ got_servfail++;
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ /* anything else implies that we're done */
+ done++;
+ }
+
+ /*
+ * if we got here for some reason other than DNSRCH,
+ * we only wanted one iteration of the loop, so stop.
+ */
+ if ((statp->options & RES_DNSRCH) == 0) done++;
+ }
+ }
+
+ /*
+ * If the query has not already been tried as is then try it
+ * unless RES_NOTLDQUERY is set and there were no dots.
+ */
+ if ((dots || !searched || (statp->options & RES_NOTLDQUERY) == 0) && !(tried_as_is || root_on_list))
+ {
+ ret = res_nquerydomain_2(statp, name, NULL, class, type, answer, anslen, from, fromlen);
+ if (ret > 0) return ret;
+ }
+
+ /*
+ * we got here, we didn't satisfy the search.
+ * if we did an initial full query, return that query's H_ERRNO
+ * (note that we wouldn't be here if that query had succeeded).
+ * else if we ever got a nodata, send that back as the reason.
+ * else send back meaningless H_ERRNO, that being the one from
+ * the last DNSRCH we did.
+ */
+ if (saved_herrno != -1) __h_errno_set(statp, saved_herrno);
+ else if (got_nodata) __h_errno_set(statp, NO_DATA);
+ else if (got_servfail) __h_errno_set(statp, TRY_AGAIN);
+ return -1;
+}
+
+int
+res_nsearch(res_state statp, const char *name, int class, int type, u_char *answer, int anslen)
+{
+ struct sockaddr_storage f;
+ int l;
+
+ l = sizeof(struct sockaddr_storage);
+
+ return res_nsearch_2(statp, name, class, type, answer, anslen, (struct sockaddr *)&f, &l);
+}
+
+const char *
+res_hostalias(const res_state statp, const char *name, char *dst, size_t siz)
+{
+ char *file, *cp1, *cp2;
+ char buf[BUFSIZ];
+ FILE *fp;
+
+ if (statp->options & RES_NOALIASES) return (NULL);
+
+ file = getenv("HOSTALIASES");
+ if (file == NULL || (fp = fopen(file, "r")) == NULL) return (NULL);
+
+ setbuf(fp, NULL);
+ buf[sizeof(buf) - 1] = '\0';
+ while (fgets(buf, sizeof(buf), fp))
+ {
+ for (cp1 = buf; *cp1 && !isspace((unsigned char)*cp1); ++cp1) ;
+
+ if (!*cp1) break;
+ *cp1 = '\0';
+
+ if (ns_samename(buf, name) == 1)
+ {
+ while (isspace((unsigned char)*++cp1)) ;
+
+ if (!*cp1) break;
+
+ for (cp2 = cp1 + 1; *cp2 && !isspace((unsigned char)*cp2); ++cp2) ;
+
+ *cp2 = '\0';
+ strncpy(dst, cp1, siz - 1);
+ dst[siz - 1] = '\0';
+ fclose(fp);
+ return (dst);
+ }
+ }
+
+ fclose(fp);
+ return (NULL);
+}
--- /dev/null
+/*
+ * Copyright (c) 1985, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_send.c,v 1.1 2006/03/01 19:01:38 majka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Send query to name server and wait for reply.
+ */
+
+#ifndef __APPLE__
+#include "port_before.h"
+#include "fd_setsize.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <notify.h>
+#include <pthread.h>
+#include <string.h>
+#include <unistd.h>
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include "res_private.h"
+
+#ifndef __APPLE__
+#include <isc/eventlib.h>
+#include "port_after.h"
+#endif
+
+#ifdef __APPLE__
+#define ISC_SOCKLEN_T unsigned int
+#endif
+
+/* Options. Leave them on. */
+#define DEBUG
+#define CANNOT_CONNECT_DGRAM
+#ifdef __APPLE__
+#define MULTICAST
+#endif
+
+#include "res_debug.h"
+#include "res_private.h"
+
+#define EXT(res) ((res)->_u._ext)
+
+static const int highestFD = FD_SETSIZE - 1;
+
+#define MAX_HOOK_RETRIES 42
+
+/* Forward. */
+
+static int get_salen __P((const struct sockaddr *));
+static int send_vc(res_state, const u_char *, int, u_char *, int *, int *, int, struct sockaddr *, int *, int);
+static int send_dg(res_state, const u_char *, int, u_char *, int *, int *, int, int *, int *, struct sockaddr *, int *, int);
+static void Aerror(const res_state, FILE *, const char *, int, const struct sockaddr *, int);
+static void Perror(const res_state, FILE *, const char *, int);
+static int sock_eq(struct sockaddr *, struct sockaddr *);
+#ifdef NEED_PSELECT
+static int pselect(int, void *, void *, void *, struct timespec *, const sigset_t *);
+#endif
+
+static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
+
+#ifdef __APPLE__
+static struct iovec
+evConsIovec(void *buf, size_t cnt)
+{
+ struct iovec ret;
+
+ memset(&ret, 0xf5, sizeof ret);
+ ret.iov_base = buf;
+ ret.iov_len = cnt;
+ return (ret);
+}
+
+static struct timespec
+evConsTime(time_t sec, long nsec)
+{
+ struct timespec x;
+
+ x.tv_sec = sec;
+ x.tv_nsec = nsec;
+ return (x);
+}
+
+static struct timespec
+evTimeSpec(struct timeval tv)
+{
+ struct timespec ts;
+
+ ts.tv_sec = tv.tv_sec;
+ ts.tv_nsec = tv.tv_usec * 1000;
+ return (ts);
+}
+
+static struct timespec
+evNowTime()
+{
+ struct timeval now;
+
+ if (gettimeofday(&now, NULL) < 0) return (evConsTime(0, 0));
+ return (evTimeSpec(now));
+}
+
+#ifdef NEED_PSELECT
+static struct timeval
+evTimeVal(struct timespec ts)
+{
+ struct timeval tv;
+
+ tv.tv_sec = ts.tv_sec;
+ tv.tv_usec = ts.tv_nsec / 1000;
+ return (tv);
+}
+#endif
+
+#define BILLION 1000000000
+static struct timespec
+evAddTime(struct timespec addend1, struct timespec addend2)
+{
+ struct timespec x;
+
+ x.tv_sec = addend1.tv_sec + addend2.tv_sec;
+ x.tv_nsec = addend1.tv_nsec + addend2.tv_nsec;
+ if (x.tv_nsec >= BILLION)
+ {
+ x.tv_sec++;
+ x.tv_nsec -= BILLION;
+ }
+
+ return (x);
+}
+
+static struct timespec
+evSubTime(struct timespec minuend, struct timespec subtrahend)
+{
+ struct timespec x;
+
+ x.tv_sec = minuend.tv_sec - subtrahend.tv_sec;
+ if (minuend.tv_nsec >= subtrahend.tv_nsec)
+ {
+ x.tv_nsec = minuend.tv_nsec - subtrahend.tv_nsec;
+ }
+ else
+ {
+ x.tv_nsec = BILLION - subtrahend.tv_nsec + minuend.tv_nsec;
+ x.tv_sec--;
+ }
+
+ return (x);
+}
+
+static int
+evCmpTime(struct timespec a, struct timespec b)
+{
+ long x = a.tv_sec - b.tv_sec;
+
+ if (x == 0L) x = a.tv_nsec - b.tv_nsec;
+ return (x < 0L ? (-1) : x > 0L ? (1) : (0));
+}
+
+#endif /* __APPLE__ */
+
+/* Public. */
+
+/* int
+ * res_isourserver(ina)
+ * looks up "ina" in _res.ns_addr_list[]
+ * returns:
+ * 0 : not found
+ * >0 : found
+ * author:
+ * paul vixie, 29may94
+ */
+int
+res_ourserver_p(const res_state statp, const struct sockaddr *sa)
+{
+ const struct sockaddr_in *inp, *srv;
+ const struct sockaddr_in6 *in6p, *srv6;
+ int ns;
+
+ switch (sa->sa_family)
+ {
+ case AF_INET:
+ inp = (const struct sockaddr_in *)sa;
+ for (ns = 0; ns < statp->nscount; ns++)
+ {
+ srv = (struct sockaddr_in *)get_nsaddr(statp, ns);
+ if (srv->sin_family == inp->sin_family &&
+ srv->sin_port == inp->sin_port &&
+ (srv->sin_addr.s_addr == INADDR_ANY ||
+ srv->sin_addr.s_addr == inp->sin_addr.s_addr))
+ return (1);
+ }
+ break;
+ case AF_INET6:
+ if (EXT(statp).ext == NULL) break;
+ in6p = (const struct sockaddr_in6 *)sa;
+ for (ns = 0; ns < statp->nscount; ns++)
+ {
+ srv6 = (struct sockaddr_in6 *)get_nsaddr(statp, ns);
+ if (srv6->sin6_family == in6p->sin6_family &&
+ srv6->sin6_port == in6p->sin6_port &&
+ (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) ||
+ IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr)))
+ return (1);
+ }
+ break;
+ default:
+ break;
+ }
+ return (0);
+}
+
+/* int
+ * res_nameinquery(name, type, class, buf, eom)
+ * look for (name,type,class) in the query section of packet (buf,eom)
+ * requires:
+ * buf + NS_HFIXEDSZ <= eom
+ * returns:
+ * -1 : format error
+ * 0 : not found
+ * >0 : found
+ * author:
+ * paul vixie, 29may94
+ */
+int
+res_nameinquery(const char *name, int type, int class, const u_char *buf, const u_char *eom)
+{
+ const u_char *cp = buf + NS_HFIXEDSZ;
+ int qdcount = ntohs(((const HEADER*)buf)->qdcount);
+
+ while (qdcount-- > 0)
+ {
+ char tname[NS_MAXDNAME+1];
+ int n, ttype, tclass;
+
+ n = dn_expand(buf, eom, cp, tname, sizeof tname);
+ if (n < 0) return (-1);
+
+ cp += n;
+ if (cp + 2 * NS_INT16SZ > eom) return (-1);
+
+ ttype = ns_get16(cp); cp += NS_INT16SZ;
+ tclass = ns_get16(cp); cp += NS_INT16SZ;
+ if (ttype == type && tclass == class && ns_samename(tname, name) == 1) return (1);
+ }
+
+ return (0);
+}
+
+/* int
+ * res_queriesmatch(buf1, eom1, buf2, eom2)
+ * is there a 1:1 mapping of (name,type,class)
+ * in (buf1,eom1) and (buf2,eom2)?
+ * returns:
+ * -1 : format error
+ * 0 : not a 1:1 mapping
+ * >0 : is a 1:1 mapping
+ * author:
+ * paul vixie, 29may94
+ */
+int
+res_queriesmatch(const u_char *buf1, const u_char *eom1, const u_char *buf2, const u_char *eom2)
+{
+ const u_char *cp = buf1 + NS_HFIXEDSZ;
+ int qdcount = ntohs(((const HEADER*)buf1)->qdcount);
+
+ if (buf1 + NS_HFIXEDSZ > eom1 || buf2 + NS_HFIXEDSZ > eom2)
+ return (-1);
+
+ /*
+ * Only header section present in replies to
+ * dynamic update packets.
+ */
+ if ((((const HEADER *)buf1)->opcode == ns_o_update) &&
+ (((const HEADER *)buf2)->opcode == ns_o_update))
+ return (1);
+
+ if (qdcount != ntohs(((const HEADER*)buf2)->qdcount)) return (0);
+
+ while (qdcount-- > 0)
+ {
+ char tname[NS_MAXDNAME+1];
+ int n, ttype, tclass;
+
+ n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
+ if (n < 0) return (-1);
+
+ cp += n;
+ if (cp + 2 * NS_INT16SZ > eom1) return (-1);
+
+ ttype = ns_get16(cp); cp += NS_INT16SZ;
+ tclass = ns_get16(cp); cp += NS_INT16SZ;
+ if (!res_nameinquery(tname, ttype, tclass, buf2, eom2)) return (0);
+ }
+
+ return (1);
+}
+
+int
+dns_res_send(res_state statp, const u_char *buf, int buflen, u_char *ans, int *anssiz, struct sockaddr *from, int *fromlen)
+{
+ int gotsomewhere, terrno, try, v_circuit, resplen, ns;
+ char abuf[NI_MAXHOST];
+ char *notify_name;
+ int notify_token, status, send_status, reply_buf_size;
+ uint64_t exit_requested;
+
+ if (statp->nscount == 0)
+ {
+ errno = ESRCH;
+ return DNS_RES_STATUS_INVALID_RES_STATE;
+ }
+
+ reply_buf_size = *anssiz;
+ if (reply_buf_size < NS_HFIXEDSZ)
+ {
+ errno = EINVAL;
+ return DNS_RES_STATUS_INVALID_ARGUMENT;
+ }
+
+ DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY), (stdout, ";; res_send()\n"), buf, buflen);
+
+ v_circuit = (statp->options & RES_USEVC) || (buflen > NS_PACKETSZ);
+ gotsomewhere = 0;
+ send_status = 0;
+ terrno = ETIMEDOUT;
+
+ /*
+ * If the ns_addr_list in the resolver context has changed, then
+ * invalidate our cached copy and the associated timing data.
+ */
+ if (EXT(statp).nscount != 0)
+ {
+ int needclose = 0;
+ struct sockaddr_storage peer;
+ ISC_SOCKLEN_T peerlen;
+
+ if (EXT(statp).nscount != statp->nscount)
+ {
+ needclose++;
+ }
+ else
+ {
+ for (ns = 0; ns < statp->nscount; ns++)
+ {
+ if ((statp->nsaddr_list[ns].sin_family) && (EXT(statp).ext != NULL) && (!sock_eq((struct sockaddr *)&statp->nsaddr_list[ns], (struct sockaddr *)&EXT(statp).ext->nsaddrs[ns])))
+ {
+ needclose++;
+ break;
+ }
+
+ if (EXT(statp).nssocks[ns] == -1) continue;
+
+ peerlen = sizeof(peer);
+ if (getsockname(EXT(statp).nssocks[ns], (struct sockaddr *)&peer, &peerlen) < 0)
+ {
+ needclose++;
+ break;
+ }
+
+ if (!sock_eq((struct sockaddr *)&peer, get_nsaddr(statp, ns)))
+ {
+ needclose++;
+ break;
+ }
+ }
+ }
+
+ if (needclose)
+ {
+ res_nclose(statp);
+ EXT(statp).nscount = 0;
+ }
+ }
+
+ /*
+ * Maybe initialize our private copy of the ns_addr_list.
+ */
+ if (EXT(statp).nscount == 0)
+ {
+ for (ns = 0; ns < statp->nscount; ns++)
+ {
+ EXT(statp).nstimes[ns] = RES_MAXTIME;
+ EXT(statp).nssocks[ns] = -1;
+ if (!statp->nsaddr_list[ns].sin_family) continue;
+ if (EXT(statp).ext != NULL) EXT(statp).ext->nsaddrs[ns].sin = statp->nsaddr_list[ns];
+ }
+
+ EXT(statp).nscount = statp->nscount;
+ }
+
+ /*
+ * Some resolvers want to even out the load on their nameservers.
+ * Note that RES_BLAST overrides RES_ROTATE.
+ */
+ if (((statp->options & RES_ROTATE) != 0) && ((statp->options & RES_BLAST) == 0))
+ {
+ union res_sockaddr_union inu;
+ struct sockaddr_in ina;
+ int lastns = statp->nscount - 1;
+ int fd;
+ u_int16_t nstime;
+
+ if (EXT(statp).ext != NULL) inu = EXT(statp).ext->nsaddrs[0];
+ ina = statp->nsaddr_list[0];
+ fd = EXT(statp).nssocks[0];
+ nstime = EXT(statp).nstimes[0];
+
+ for (ns = 0; ns < lastns; ns++)
+ {
+ if (EXT(statp).ext != NULL)
+ {
+ EXT(statp).ext->nsaddrs[ns] =EXT(statp).ext->nsaddrs[ns + 1];
+ }
+
+ statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
+ EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1];
+ EXT(statp).nstimes[ns] = EXT(statp).nstimes[ns + 1];
+ }
+
+ if (EXT(statp).ext != NULL) EXT(statp).ext->nsaddrs[lastns] = inu;
+ statp->nsaddr_list[lastns] = ina;
+ EXT(statp).nssocks[lastns] = fd;
+ EXT(statp).nstimes[lastns] = nstime;
+ }
+
+ /*
+ * Get notification token
+ * we use a self-notification token to allow a caller
+ * to signal the thread doing this DNS query to quit.
+ */
+ notify_name = NULL;
+ notify_token = -1;
+
+ asprintf(¬ify_name, "self.thread.%lu", (unsigned long)pthread_self());
+ if (notify_name != NULL)
+ {
+ status = notify_register_plain(notify_name, ¬ify_token);
+ free(notify_name);
+ }
+
+ /*
+ * Send request, RETRY times, or until successful.
+ */
+ for (try = 0; try < statp->retry; try++)
+ {
+ for (ns = 0; ns < statp->nscount; ns++)
+ {
+ struct sockaddr *nsap;
+ int nsaplen;
+ nsap = get_nsaddr(statp, ns);
+ nsaplen = get_salen(nsap);
+
+send_same_ns:
+
+ if (statp->qhook)
+ {
+ int done = 0, loops = 0;
+
+ do
+ {
+ res_sendhookact act;
+
+ act = (*statp->qhook)(&nsap, &buf, &buflen, ans, reply_buf_size, &resplen);
+ switch (act)
+ {
+ case res_goahead:
+ done = 1;
+ break;
+ case res_nextns:
+ res_nclose(statp);
+ goto send_next_ns;
+ case res_done:
+ if (notify_token != -1) notify_cancel(notify_token);
+ return DNS_RES_STATUS_CANCELLED;
+ case res_modified:
+ /* give the hook another try */
+ if (++loops < MAX_HOOK_RETRIES) break;
+ /*FALLTHROUGH*/
+ case res_error:
+ /*FALLTHROUGH*/
+ default:
+ if (notify_token != -1) notify_cancel(notify_token);
+ return DNS_RES_STATUS_CANCELLED;
+ }
+ } while (!done);
+ }
+
+ if (notify_token != -1)
+ {
+ exit_requested = 0;
+ status = notify_get_state(notify_token, &exit_requested);
+ if (exit_requested == ThreadStateExitRequested)
+ {
+ res_nclose(statp);
+ notify_cancel(notify_token);
+ return DNS_RES_STATUS_CANCELLED;
+ }
+ }
+
+ Dprint(((statp->options & RES_DEBUG) && getnameinfo(nsap, nsaplen, abuf, sizeof(abuf), NULL, 0, niflags) == 0), (stdout, ";; Querying server (# %d) address = %s\n", ns + 1, abuf));
+
+ send_status = ns_r_noerror;
+
+ if (v_circuit != 0)
+ {
+ /* Use VC; at most one attempt per server. */
+ try = statp->retry;
+
+ *anssiz = reply_buf_size;
+ send_status = send_vc(statp, buf, buflen, ans, anssiz, &terrno, ns, from, fromlen, notify_token);
+ }
+ else
+ {
+ /* Use datagrams. */
+ send_status = send_dg(statp, buf, buflen, ans, anssiz, &terrno, ns, &v_circuit, &gotsomewhere, from, fromlen, notify_token);
+ if (v_circuit != 0) goto send_same_ns;
+ }
+
+ if ((send_status == DNS_RES_STATUS_SYSTEM_ERROR) || (send_status == DNS_RES_STATUS_CANCELLED))
+ {
+ res_nclose(statp);
+ if (notify_token != -1) notify_cancel(notify_token);
+ return send_status;
+ }
+
+ if (send_status != ns_r_noerror) goto send_next_ns;
+
+ Dprint((statp->options & RES_DEBUG) || ((statp->pfcode & RES_PRF_REPLY) && (statp->pfcode & RES_PRF_HEAD1)), (stdout, ";; got answer:\n"));
+ DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_REPLY), (stdout, "%s", ""), ans, (*anssiz > reply_buf_size) ? reply_buf_size : *anssiz);
+
+ /*
+ * If we have temporarily opened a virtual circuit,
+ * or if we haven't been asked to keep a socket open,
+ * close the socket.
+ */
+ if (((v_circuit != 0) && (statp->options & RES_USEVC) == 0) || (statp->options & RES_STAYOPEN) == 0) res_nclose(statp);
+
+ if (statp->rhook)
+ {
+ int done = 0, loops = 0;
+
+ do
+ {
+ res_sendhookact act;
+
+ act = (*statp->rhook)(nsap, buf, buflen, ans, *anssiz, &resplen);
+ switch (act)
+ {
+ case res_goahead:
+ case res_done:
+ done = 1;
+ break;
+ case res_nextns:
+ res_nclose(statp);
+ goto send_next_ns;
+ case res_modified:
+ /* give the hook another try */
+ if (++loops < MAX_HOOK_RETRIES) break;
+ /*FALLTHROUGH*/
+ case res_error:
+ /*FALLTHROUGH*/
+ default:
+ res_nclose(statp);
+ if (notify_token != -1) notify_cancel(notify_token);
+ return DNS_RES_STATUS_CANCELLED;
+ }
+ } while (!done);
+
+ }
+
+ if (notify_token != -1) notify_cancel(notify_token);
+ return ns_r_noerror;
+
+send_next_ns: ;
+ } /* foreach ns */
+ } /* foreach retry */
+
+ res_nclose(statp);
+ if (notify_token != -1) notify_cancel(notify_token);
+
+ if (v_circuit == 0)
+ {
+ /* used datagrams */
+ if (gotsomewhere != 0)
+ {
+ errno = ECONNREFUSED;
+ return DNS_RES_STATUS_CONNECTION_REFUSED;
+ }
+
+ errno = ETIMEDOUT;
+ return DNS_RES_STATUS_TIMEOUT;
+ }
+
+ /* used v_circuit */
+ errno = terrno;
+ return send_status;
+}
+
+int
+res_nsend_2(res_state statp, const u_char *buf, int buflen, u_char *ans, int anssiz, struct sockaddr *from, int *fromlen)
+{
+ int len, status;
+
+ len = anssiz;
+ status = dns_res_send(statp, buf, buflen, ans, &len, from, fromlen);
+ if (status != ns_r_noerror) len = -1;
+ return len;
+}
+
+int
+res_nsend(res_state statp, const u_char *buf, int buflen, u_char *ans, int anssiz)
+{
+ struct sockaddr_storage from;
+ int fromlen;
+
+ fromlen = sizeof(struct sockaddr_storage);
+
+ return res_nsend_2(statp, buf, buflen, ans, anssiz, (struct sockaddr *)&from, &fromlen);
+}
+
+/* Private */
+
+static int
+get_salen(const struct sockaddr *sa)
+{
+#ifdef HAVE_SA_LEN
+ /* There are people do not set sa_len. Be forgiving to them. */
+ if (sa->sa_len) return (sa->sa_len);
+#endif
+
+ if (sa->sa_family == AF_INET) return (sizeof(struct sockaddr_in));
+ else if (sa->sa_family == AF_INET6) return (sizeof(struct sockaddr_in6));
+ else return (0); /* unknown, die on connect */
+}
+
+/*
+ * pick appropriate nsaddr_list for use. see res_init() for initialization.
+ */
+struct sockaddr *
+get_nsaddr(res_state statp, size_t n)
+{
+ if ((!statp->nsaddr_list[n].sin_family) && (EXT(statp).ext != NULL))
+ {
+ /*
+ * - EXT(statp).ext->nsaddrs[n] holds an address that is larger
+ * than struct sockaddr, and
+ * - user code did not update statp->nsaddr_list[n].
+ */
+ return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n];
+ }
+ else
+ {
+ /*
+ * - user code updated statp->nsaddr_list[n], or
+ * - statp->nsaddr_list[n] has the same content as
+ * EXT(statp).ext->nsaddrs[n].
+ */
+ return (struct sockaddr *)(void *)&statp->nsaddr_list[n];
+ }
+}
+
+static int
+send_vc(res_state statp, const u_char *buf, int buflen, u_char *ans, int *anssiz, int *terrno, int ns, struct sockaddr *from, int *fromlen, int notify_token)
+{
+ const HEADER *hp = (const HEADER *) buf;
+ HEADER *anhp = (HEADER *) ans;
+ struct sockaddr *nsap;
+ int nsaplen;
+ int truncating, connreset, resplen, n;
+ struct iovec iov[2];
+ u_short len;
+ u_char *cp;
+ void *tmp;
+ int status;
+ uint64_t exit_requested;
+
+ nsap = get_nsaddr(statp, ns);
+ nsaplen = get_salen(nsap);
+
+ connreset = 0;
+
+vc_same_ns:
+
+ if (notify_token != -1)
+ {
+ exit_requested = 0;
+ status = notify_get_state(notify_token, &exit_requested);
+ if (exit_requested == ThreadStateExitRequested)
+ {
+ *terrno = EINTR;
+ return DNS_RES_STATUS_CANCELLED;
+ }
+ }
+
+ truncating = 0;
+
+ /* Are we still talking to whom we want to talk? */
+ if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0)
+ {
+ struct sockaddr_storage peer;
+ ISC_SOCKLEN_T size = sizeof peer;
+
+ if (getpeername(statp->_vcsock, (struct sockaddr *)&peer, &size) < 0 || !sock_eq((struct sockaddr *)&peer, nsap))
+ {
+ res_nclose(statp);
+ statp->_flags &= ~RES_F_VC;
+ }
+ }
+
+ if ((statp->_vcsock < 0) || ((statp->_flags & RES_F_VC) == 0))
+ {
+ if (statp->_vcsock >= 0) res_nclose(statp);
+
+ statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM, 0);
+ if (statp->_vcsock > highestFD)
+ {
+ res_nclose(statp);
+ errno = ENOTSOCK;
+ }
+
+ if (statp->_vcsock < 0)
+ {
+ *terrno = errno;
+ Perror(statp, stderr, "socket(vc)", errno);
+ return DNS_RES_STATUS_SYSTEM_ERROR;
+ }
+
+ errno = 0;
+ if (connect(statp->_vcsock, nsap, nsaplen) < 0)
+ {
+ *terrno = errno;
+ Aerror(statp, stderr, "connect(vc)", errno, nsap, nsaplen);
+ res_nclose(statp);
+ return DNS_RES_STATUS_CONNECTION_REFUSED;
+ }
+
+ statp->_flags |= RES_F_VC;
+ }
+
+ /*
+ * Send length & message
+ */
+ putshort((u_short)buflen, (u_char*)&len);
+ iov[0] = evConsIovec(&len, NS_INT16SZ);
+#ifdef __APPLE__
+ tmp = (char *)buf;
+#else
+ DE_CONST(buf, tmp);
+#endif
+ iov[1] = evConsIovec(tmp, buflen);
+ if (writev(statp->_vcsock, iov, 2) != (NS_INT16SZ + buflen))
+ {
+ *terrno = errno;
+ Perror(statp, stderr, "write failed", errno);
+ res_nclose(statp);
+ return DNS_RES_STATUS_CONNECTION_FAILED;
+ }
+
+ /*
+ * Receive length & response
+ */
+ read_len:
+
+ if (notify_token != -1)
+ {
+ exit_requested = 0;
+ status = notify_get_state(notify_token, &exit_requested);
+ if (exit_requested == ThreadStateExitRequested)
+ {
+ *terrno = EINTR;
+ return DNS_RES_STATUS_CANCELLED;
+ }
+ }
+
+ cp = ans;
+ len = NS_INT16SZ;
+ while ((n = read(statp->_vcsock, (char *)cp, (int)len)) > 0)
+ {
+ cp += n;
+ if ((len -= n) <= 0) break;
+ }
+
+ if (n <= 0)
+ {
+ *terrno = errno;
+ Perror(statp, stderr, "read failed", errno);
+ res_nclose(statp);
+
+ /*
+ * A long running process might get its TCP
+ * connection reset if the remote server was
+ * restarted. Requery the server instead of
+ * trying a new one. When there is only one
+ * server, this means that a query might work
+ * instead of failing. We only allow one reset
+ * per query to prevent looping.
+ */
+ if (*terrno == ECONNRESET && !connreset)
+ {
+ connreset = 1;
+ res_nclose(statp);
+ goto vc_same_ns;
+ }
+
+ res_nclose(statp);
+ return DNS_RES_STATUS_CONNECTION_FAILED;
+ }
+
+ resplen = ns_get16(ans);
+ if (resplen > *anssiz)
+ {
+ Dprint(statp->options & RES_DEBUG, (stdout, ";; response truncated\n"));
+ truncating = 1;
+ len = *anssiz;
+ }
+ else
+ {
+ len = resplen;
+ }
+
+ if (len < NS_HFIXEDSZ)
+ {
+ /*
+ * Undersized message.
+ */
+ Dprint(statp->options & RES_DEBUG, (stdout, ";; undersized: %d\n", len));
+ *terrno = EMSGSIZE;
+ res_nclose(statp);
+ *anssiz = 0;
+ return DNS_RES_STATUS_INVALID_REPLY;
+ }
+
+ cp = ans;
+ while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0)
+ {
+ cp += n;
+ len -= n;
+ }
+
+ if (n <= 0)
+ {
+ *terrno = errno;
+ Perror(statp, stderr, "read(vc)", errno);
+ res_nclose(statp);
+ return DNS_RES_STATUS_CONNECTION_FAILED;
+ }
+
+ if (truncating)
+ {
+ /*
+ * Flush rest of answer so connection stays in synch.
+ */
+ anhp->tc = 1;
+ len = resplen - *anssiz;
+ while (len != 0)
+ {
+ char junk[NS_PACKETSZ];
+
+ n = read(statp->_vcsock, junk, (len > sizeof junk) ? sizeof junk : len);
+ if (n > 0) len -= n;
+ else break;
+ }
+ }
+
+ /*
+ * If the calling applicating has bailed out of
+ * a previous call and failed to arrange to have
+ * the circuit closed or the server has got
+ * itself confused, then drop the packet and
+ * wait for the correct one.
+ */
+ if (hp->id != anhp->id)
+ {
+ DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_REPLY), (stdout, ";; old answer (unexpected):\n"), ans, (resplen > *anssiz) ? *anssiz : resplen);
+ goto read_len;
+ }
+
+ /*
+ * All is well, or the error is fatal. Signal that the
+ * next nameserver ought not be tried.
+ */
+
+ *fromlen = sizeof(nsap);
+ memcpy(from, &nsap, *fromlen);
+ *anssiz = resplen;
+ return ns_r_noerror;
+}
+
+static ssize_t
+internal_recvfrom(int s, void *buf, size_t len, struct sockaddr *from, int *fromlen, int *iface)
+{
+ struct sockaddr_dl *sdl;
+ struct iovec databuffers = { buf, len };
+ struct msghdr msg;
+ ssize_t n;
+ struct cmsghdr *cmp;
+ char ancillary[1024], ifname[IF_NAMESIZE];
+ struct in6_pktinfo *ip6_info;
+ struct sockaddr_in *s4;
+ struct sockaddr_in6 *s6;
+
+ memset(&msg, 0, sizeof(struct msghdr));
+ msg.msg_name = (caddr_t)from;
+ msg.msg_namelen = *fromlen;
+ msg.msg_iov = &databuffers;
+ msg.msg_iovlen = 1;
+ msg.msg_control = (caddr_t)&ancillary;
+ msg.msg_controllen = sizeof(ancillary);
+
+ /* Receive the data */
+ n = recvmsg(s, &msg, 0);
+ if ((n < 0) || (msg.msg_controllen < sizeof(struct cmsghdr)) || (msg.msg_flags & MSG_CTRUNC))
+ {
+ return n;
+ }
+
+ *fromlen = msg.msg_namelen;
+
+ s4 = (struct sockaddr_in *)from;
+ s6 = (struct sockaddr_in6 *)from;
+
+ for (cmp = CMSG_FIRSTHDR(&msg); cmp; cmp = CMSG_NXTHDR(&msg, cmp))
+ {
+ if ((cmp->cmsg_level == IPPROTO_IP) && (cmp->cmsg_type == IP_RECVIF))
+ {
+ sdl = (struct sockaddr_dl *)CMSG_DATA(cmp);
+ if (sdl->sdl_nlen < IF_NAMESIZE)
+ {
+ memcpy(ifname, sdl->sdl_data, sdl->sdl_nlen);
+ ifname[sdl->sdl_nlen] = 0;
+ *iface = if_nametoindex(ifname);
+ }
+ }
+ else if ((cmp->cmsg_level == IPPROTO_IPV6) && (cmp->cmsg_type == IPV6_PKTINFO))
+ {
+ ip6_info = (struct in6_pktinfo *)CMSG_DATA(cmp);
+ *iface = ip6_info->ipi6_ifindex;
+ }
+ }
+
+ return n;
+}
+
+static int
+send_dg(res_state statp, const u_char *buf, int buflen, u_char *ans, int *anssiz, int *terrno, int ns, int *v_circuit, int *gotsomewhere, struct sockaddr *from, int *fromlen, int notify_token)
+{
+ const HEADER *hp = (const HEADER *) buf;
+ HEADER *anhp = (HEADER *) ans;
+ const struct sockaddr *nsap;
+ int nsaplen;
+ struct timespec now, timeout, finish;
+ fd_set dsmask;
+ int iface, rif, status;
+ uint64_t exit_requested;
+#ifndef __APPLE__
+ struct sockaddr_storage from;
+ ISC_SOCKLEN_T fromlen;
+#endif
+ int resplen, seconds, ntry, n, s;
+#ifdef MULTICAST
+ int multicast;
+#endif
+
+ nsap = get_nsaddr(statp, ns);
+ nsaplen = get_salen(nsap);
+ if (EXT(statp).nssocks[ns] == -1)
+ {
+ EXT(statp).nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM, 0);
+ if (EXT(statp).nssocks[ns] > highestFD)
+ {
+ res_nclose(statp);
+ errno = ENOTSOCK;
+ }
+
+ if (EXT(statp).nssocks[ns] < 0)
+ {
+ *terrno = errno;
+ Perror(statp, stderr, "socket(dg)", errno);
+ return DNS_RES_STATUS_SYSTEM_ERROR;
+ }
+
+#ifndef CANNOT_CONNECT_DGRAM
+ /*
+ * On a 4.3BSD+ machine (client and server,
+ * actually), sending to a nameserver datagram
+ * port with no nameserver will cause an
+ * ICMP port unreachable message to be returned.
+ * If our datagram socket is "connected" to the
+ * server, we get an ECONNREFUSED error on the next
+ * socket operation, and select returns if the
+ * error message is received. We can thus detect
+ * the absence of a nameserver without timing out.
+ */
+ if (connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0)
+ {
+ Aerror(statp, stderr, "connect(dg)", errno, nsap, nsaplen);
+ res_nclose(statp);
+ return DNS_RES_STATUS_CONNECTION_REFUSED;
+ }
+
+#endif /* !CANNOT_CONNECT_DGRAM */
+ Dprint(statp->options & RES_DEBUG, (stdout, ";; new DG socket\n"))
+ }
+
+ s = EXT(statp).nssocks[ns];
+ rif = 1;
+ setsockopt(s, IPPROTO_IP, IP_RECVIF, &rif, sizeof(int));
+ setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &rif, sizeof(int));
+
+#ifdef MULTICAST
+ multicast = 0;
+
+ if ((nsap->sa_family == AF_INET) && (IN_MULTICAST(ntohl(((struct sockaddr_in *)nsap)->sin_addr.s_addr)))) multicast = AF_INET;
+ else if ((nsap->sa_family == AF_INET6) && (IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)nsap)->sin6_addr))) multicast = AF_INET6;
+
+ if (multicast != 0)
+ {
+ struct ifaddrs *ifa, *p;
+ struct sockaddr_in *sin4;
+ struct sockaddr_in6 *sin6;
+ int i, ifnum;
+
+ if (getifaddrs(&ifa) < 0)
+ {
+ Aerror(statp, stderr, "getifaddrs", errno, nsap, nsaplen);
+ res_nclose(statp);
+ return DNS_RES_STATUS_SYSTEM_ERROR;
+ }
+
+ for (p = ifa; p != NULL; p = p->ifa_next)
+ {
+ if (p->ifa_addr == NULL) continue;
+ if ((p->ifa_flags & IFF_UP) == 0) continue;
+ if (p->ifa_addr->sa_family != multicast) continue;
+ if ((p->ifa_flags & IFF_MULTICAST) == 0) continue;
+ if ((p->ifa_flags & IFF_POINTOPOINT) != 0)
+ {
+ if ((multicast == AF_INET) && (ntohl(((struct sockaddr_in *)nsap)->sin_addr.s_addr) <= INADDR_MAX_LOCAL_GROUP)) continue;
+ }
+
+ sin4 = (struct sockaddr_in *)p->ifa_addr;
+ sin6 = (struct sockaddr_in6 *)p->ifa_addr;
+ i = -1;
+ if (multicast == AF_INET) i = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &sin4->sin_addr, sizeof(sin4->sin_addr));
+ else if (multicast == AF_INET6)
+ {
+ ifnum = if_nametoindex(p->ifa_name);
+ ((struct sockaddr_in6 *)nsap)->sin6_scope_id = ifnum;
+ i = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifnum, sizeof(ifnum));
+ }
+
+ if (i < 0)
+ {
+ Aerror(statp, stderr, "setsockopt", errno, nsap, nsaplen);
+ if (multicast == AF_INET6) ((struct sockaddr_in6 *)nsap)->sin6_scope_id = 0;
+
+ continue;
+ }
+
+ if (sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen)
+ {
+ Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
+ if (multicast == AF_INET6) ((struct sockaddr_in6 *)nsap)->sin6_scope_id = 0;
+ continue;
+ }
+
+ if (multicast == AF_INET6) ((struct sockaddr_in6 *)nsap)->sin6_scope_id = 0;
+ }
+
+
+ freeifaddrs(ifa);
+ }
+ else
+ {
+#endif /* MULTICAST */
+
+#ifndef CANNOT_CONNECT_DGRAM
+ if (send(s, (const char*)buf, buflen, 0) != buflen)
+ {
+ Perror(statp, stderr, "send", errno);
+ res_nclose(statp);
+ return DNS_RES_STATUS_CONNECTION_FAILED;
+ }
+
+#else /* !CANNOT_CONNECT_DGRAM */
+ if (sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen)
+ {
+ Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
+ res_nclose(statp);
+ return DNS_RES_STATUS_CONNECTION_FAILED;
+ }
+#endif /* !CANNOT_CONNECT_DGRAM */
+
+#ifdef MULTICAST
+ }
+#endif /* MULTICAST */
+
+ /*
+ * Wait for reply.
+ */
+#ifdef __APPLE__
+ ntry = statp->nscount * statp->retry;
+ seconds = statp->retrans / ntry;
+ if (seconds <= 0) seconds = 1;
+ timeout.tv_sec = seconds;
+ timeout.tv_nsec = ((statp->retrans - (seconds * ntry)) * 1000) / ntry;
+ timeout.tv_nsec *= 1000000;
+ now = evNowTime();
+ finish = evAddTime(now, timeout);
+#else
+ seconds = (statp->retrans << ns);
+ if (ns > 0) seconds /= statp->nscount;
+ if (seconds <= 0) seconds = 1;
+ now = evNowTime();
+ timeout = evConsTime(seconds, 0);
+ finish = evAddTime(now, timeout);
+#endif /* __APPLE__ */
+ goto nonow;
+ wait:
+
+ now = evNowTime();
+
+ nonow:
+
+ if (notify_token != -1)
+ {
+ exit_requested = 0;
+ status = notify_get_state(notify_token, &exit_requested);
+ if (exit_requested == ThreadStateExitRequested) return DNS_RES_STATUS_CANCELLED;
+ }
+
+ FD_ZERO(&dsmask);
+ FD_SET(s, &dsmask);
+ if (evCmpTime(finish, now) > 0) timeout = evSubTime(finish, now);
+ else timeout = evConsTime(0, 0);
+
+ n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL);
+ if (n == 0)
+ {
+ Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
+ *gotsomewhere = 1;
+ return DNS_RES_STATUS_TIMEOUT;
+ }
+
+ if (n < 0)
+ {
+ if (errno == EINTR) goto wait;
+ Perror(statp, stderr, "select", errno);
+ res_nclose(statp);
+ return DNS_RES_STATUS_SYSTEM_ERROR;
+ }
+
+ errno = 0;
+ iface = 0;
+ resplen = internal_recvfrom(s, (char *)ans, *anssiz, from, fromlen, &iface);
+ if (resplen <= 0)
+ {
+ Perror(statp, stderr, "recvfrom", errno);
+ res_nclose(statp);
+ return DNS_RES_STATUS_CONNECTION_FAILED;
+ }
+
+ if (nsap->sa_family == AF_INET) memcpy(((struct sockaddr_in *)from)->sin_zero, &iface, 4);
+ else if (nsap->sa_family == AF_INET6) ((struct sockaddr_in6 *)from)->sin6_scope_id = iface;
+
+ *gotsomewhere = 1;
+ if (resplen < NS_HFIXEDSZ)
+ {
+ /*
+ * Undersized message.
+ */
+ Dprint(statp->options & RES_DEBUG, (stdout, ";; undersized: %d\n", resplen));
+ *terrno = EMSGSIZE;
+ res_nclose(statp);
+ return DNS_RES_STATUS_INVALID_REPLY;
+ }
+
+ if (hp->id != anhp->id)
+ {
+ /*
+ * response from old query, ignore it.
+ * XXX - potential security hazard could
+ * be detected here.
+ */
+ DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_REPLY), (stdout, ";; old answer:\n"), ans, (resplen > *anssiz) ? *anssiz : resplen);
+ goto wait;
+ }
+
+#ifdef MULTICAST
+ if (multicast == 0)
+ {
+#endif /* MULTICAST */
+
+ if (!(statp->options & RES_INSECURE1) && !res_ourserver_p(statp, from))
+ {
+ /*
+ * response from wrong server? ignore it.
+ * XXX - potential security hazard could
+ * be detected here.
+ */
+ DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_REPLY), (stdout, ";; not our server:\n"), ans, (resplen > *anssiz) ? *anssiz : resplen);
+ goto wait;
+ }
+
+#ifdef MULTICAST
+ }
+#endif /* MULTICAST */
+
+#ifdef RES_USE_EDNS0
+ if (anhp->rcode == ns_r_formerr && (statp->options & RES_USE_EDNS0) != 0)
+ {
+ /*
+ * Do not retry if the server do not understand EDNS0.
+ * The case has to be captured here, as FORMERR packet do not
+ * carry query section, hence res_queriesmatch() returns 0.
+ */
+ DprintQ(statp->options & RES_DEBUG, (stdout, "server rejected query with EDNS0:\n"), ans, (resplen > *anssiz) ? *anssiz : resplen);
+ /* record the error */
+ statp->_flags |= RES_F_EDNS0ERR;
+ res_nclose(statp);
+ return DNS_RES_STATUS_CONNECTION_REFUSED;
+ }
+#endif
+
+ if (!(statp->options & RES_INSECURE2) && !res_queriesmatch(buf, buf + buflen, ans, ans + *anssiz))
+ {
+ /*
+ * response contains wrong query? ignore it.
+ * XXX - potential security hazard could
+ * be detected here.
+ */
+ DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_REPLY), (stdout, ";; wrong query name:\n"), ans, (resplen > *anssiz) ? *anssiz : resplen);
+ res_nclose(statp);
+ return DNS_RES_STATUS_INVALID_REPLY;
+ }
+
+ if (anhp->rcode == ns_r_servfail || anhp->rcode == ns_r_notimpl || anhp->rcode == ns_r_refused)
+ {
+ DprintQ(statp->options & RES_DEBUG, (stdout, "server rejected query:\n"), ans, (resplen > *anssiz) ? *anssiz : resplen);
+ res_nclose(statp);
+ /* don't retry if called from dig */
+ if (!statp->pfcode) return anhp->rcode;
+ }
+
+ if (!(statp->options & RES_IGNTC) && anhp->tc)
+ {
+ /*
+ * To get the rest of answer,
+ * use TCP with same server.
+ */
+ Dprint(statp->options & RES_DEBUG, (stdout, ";; truncated answer\n"));
+ *v_circuit = 1;
+ res_nclose(statp);
+ return ns_r_noerror;
+ }
+
+ /*
+ * All is well, or the error is fatal. Signal that the
+ * next nameserver ought not be tried.
+ */
+ *anssiz = resplen;
+ return ns_r_noerror;
+}
+
+static void
+Aerror(const res_state statp, FILE *file, const char *string, int error, const struct sockaddr *address, int alen)
+{
+ int save = errno;
+ char hbuf[NI_MAXHOST];
+ char sbuf[NI_MAXSERV];
+
+ alen = alen;
+
+ if ((statp->options & RES_DEBUG) != 0)
+ {
+ if (getnameinfo(address, alen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), niflags))
+ {
+ strncpy(hbuf, "?", sizeof(hbuf) - 1);
+ hbuf[sizeof(hbuf) - 1] = '\0';
+ strncpy(sbuf, "?", sizeof(sbuf) - 1);
+ sbuf[sizeof(sbuf) - 1] = '\0';
+ }
+
+ fprintf(file, "res_send: %s ([%s].%s): %s\n", string, hbuf, sbuf, strerror(error));
+ }
+
+ errno = save;
+}
+
+static void
+Perror(const res_state statp, FILE *file, const char *string, int error)
+{
+ int save = errno;
+
+ if ((statp->options & RES_DEBUG) != 0) fprintf(file, "res_send: %s: %s\n", string, strerror(error));
+ errno = save;
+}
+
+static int
+sock_eq(struct sockaddr *a, struct sockaddr *b)
+{
+ struct sockaddr_in *a4, *b4;
+ struct sockaddr_in6 *a6, *b6;
+
+ if (a->sa_family != b->sa_family) return 0;
+
+ switch (a->sa_family)
+ {
+ case AF_INET:
+ a4 = (struct sockaddr_in *)a;
+ b4 = (struct sockaddr_in *)b;
+ return a4->sin_port == b4->sin_port && a4->sin_addr.s_addr == b4->sin_addr.s_addr;
+ case AF_INET6:
+ a6 = (struct sockaddr_in6 *)a;
+ b6 = (struct sockaddr_in6 *)b;
+ return a6->sin6_port == b6->sin6_port &&
+#ifdef HAVE_SIN6_SCOPE_ID
+ a6->sin6_scope_id == b6->sin6_scope_id &&
+#endif
+ IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr);
+ default:
+ return 0;
+ }
+}
+
+#ifdef NEED_PSELECT
+/* XXX needs to move to the porting library. */
+static int
+pselect(int nfds, void *rfds, void *wfds, void *efds, struct timespec *tsp, const sigset_t *sigmask)
+{
+ struct timeval tv, *tvp = NULL;
+ sigset_t sigs;
+ int n;
+
+ if (tsp)
+ {
+ tvp = &tv;
+ tv = evTimeVal(*tsp);
+ }
+
+ if (sigmask) sigprocmask(SIG_SETMASK, sigmask, &sigs);
+ n = select(nfds, rfds, wfds, efds, tvp);
+ if (sigmask) sigprocmask(SIG_SETMASK, &sigs, NULL);
+ if (tsp) *tsp = evTimeSpec(tv);
+ return n;
+}
+#endif
--- /dev/null
+#ifndef __APPLE__
+#include "port_before.h"
+#include "fd_setsize.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef __APPLE__
+#include <isc/dst.h>
+#include "port_after.h"
+#else
+#include "dst.h"
+#endif
+
+#include "res_private.h"
+
+// #define DEBUG
+#include "res_debug.h"
+
+
+/* res_nsendsigned */
+int
+res_nsendsigned(res_state statp, const u_char *msg, int msglen,
+ ns_tsig_key *key, u_char *answer, int anslen)
+{
+ res_state nstatp;
+ DST_KEY *dstkey;
+ int usingTCP = 0;
+ u_char *newmsg;
+ int newmsglen, bufsize, siglen;
+ u_char sig[64];
+ HEADER *hp;
+ time_t tsig_time;
+ int ret;
+
+ dst_init();
+
+ nstatp = (res_state) malloc(sizeof(*statp));
+ if (nstatp == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ memcpy(nstatp, statp, sizeof(*statp));
+ nstatp->_pad = 9;
+
+ bufsize = msglen + 1024;
+ newmsg = (u_char *) malloc(bufsize);
+ if (newmsg == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ memcpy(newmsg, msg, msglen);
+ newmsglen = msglen;
+
+ if (ns_samename(key->alg, NS_TSIG_ALG_HMAC_MD5) != 1)
+ dstkey = NULL;
+ else
+ dstkey = dst_buffer_to_key(key->name, KEY_HMAC_MD5,
+ NS_KEY_TYPE_AUTH_ONLY,
+ NS_KEY_PROT_ANY,
+ key->data, key->len);
+ if (dstkey == NULL) {
+ errno = EINVAL;
+ free(nstatp);
+ free(newmsg);
+ return (-1);
+ }
+
+ nstatp->nscount = 1;
+ siglen = sizeof(sig);
+ ret = ns_sign(newmsg, &newmsglen, bufsize, ns_r_noerror, dstkey, NULL, 0,
+ sig, &siglen, 0);
+ if (ret < 0) {
+ free (nstatp);
+ free (newmsg);
+ dst_free_key(dstkey);
+ if (ret == NS_TSIG_ERROR_NO_SPACE)
+ errno = EMSGSIZE;
+ else if (ret == -1)
+ errno = EINVAL;
+ return (ret);
+ }
+
+ if (newmsglen > NS_PACKETSZ || (nstatp->options & RES_IGNTC))
+ usingTCP = 1;
+ if (usingTCP == 0)
+ nstatp->options |= RES_IGNTC;
+ else
+ nstatp->options |= RES_USEVC;
+
+retry:
+
+ ret = res_nsend(nstatp, newmsg, newmsglen, answer, anslen);
+ if (ret < 0) {
+ free (nstatp);
+ free (newmsg);
+ dst_free_key(dstkey);
+ return (ret);
+ }
+
+ anslen = ret;
+ ret = ns_verify(answer, &anslen, dstkey, sig, siglen,
+ NULL, NULL, &tsig_time, nstatp->options & RES_KEEPTSIG);
+ if (ret != 0) {
+ Dprint(nstatp->pfcode & RES_PRF_REPLY,
+ (stdout, ";; TSIG invalid (%s)\n", p_rcode(ret)));
+ free (nstatp);
+ free (newmsg);
+ dst_free_key(dstkey);
+ if (ret == -1)
+ errno = EINVAL;
+ else
+ errno = ENOTTY;
+ return (-1);
+ }
+ Dprint(nstatp->pfcode & RES_PRF_REPLY, (stdout, ";; TSIG ok\n"));
+
+ hp = (HEADER *) answer;
+ if (hp->tc && usingTCP == 0) {
+ nstatp->options &= ~RES_IGNTC;
+ usingTCP = 1;
+ goto retry;
+ }
+
+ free (nstatp);
+ free (newmsg);
+ dst_free_key(dstkey);
+ return (anslen);
+}
--- /dev/null
+#ifndef __APPLE__
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: res_update.c,v 1.1 2006/03/01 19:01:39 majka Exp $";
+#endif /* not lint */
+#endif
+
+/*
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Based on the Dynamic DNS reference implementation by Viraj Bais
+ * <viraj_bais@ccm.fm.intel.com>
+ */
+
+#ifndef __APPLE__
+#include "port_before.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <res_update.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <resolv.h>
+
+#ifndef __APPLE__
+#include <isc/list.h>
+#include "port_after.h"
+#endif
+#include "res_private.h"
+
+/*
+ * Separate a linked list of records into groups so that all records
+ * in a group will belong to a single zone on the nameserver.
+ * Create a dynamic update packet for each zone and send it to the
+ * nameservers for that zone, and await answer.
+ * Abort if error occurs in updating any zone.
+ * Return the number of zones updated on success, < 0 on error.
+ *
+ * On error, caller must deal with the unsynchronized zones
+ * eg. an A record might have been successfully added to the forward
+ * zone but the corresponding PTR record would be missing if error
+ * was encountered while updating the reverse zone.
+ */
+
+struct zonegrp {
+ char z_origin[NS_MAXDNAME];
+ ns_class z_class;
+ union res_sockaddr_union z_nsaddrs[MAXNS];
+ int z_nscount;
+ int z_flags;
+ LIST(ns_updrec) z_rrlist;
+ LINK(struct zonegrp) z_link;
+};
+
+#define ZG_F_ZONESECTADDED 0x0001
+
+/* Forward. */
+
+static void res_dprintf(const char *, ...);
+
+/* Macros. */
+
+#define DPRINTF(x) do {\
+ int save_errno = errno; \
+ if ((statp->options & RES_DEBUG) != 0) res_dprintf x; \
+ errno = save_errno; \
+ } while (0)
+
+/* Public. */
+
+int
+res_nupdate(res_state statp, ns_updrec *rrecp_in, ns_tsig_key *key) {
+ ns_updrec *rrecp;
+ u_char answer[NS_PACKETSZ], packet[2*NS_PACKETSZ];
+ struct zonegrp *zptr, tgrp;
+ LIST(struct zonegrp) zgrps;
+ int nzones = 0, nscount = 0, n;
+ union res_sockaddr_union nsaddrs[MAXNS];
+
+ /* Thread all of the updates onto a list of groups. */
+ INIT_LIST(zgrps);
+ memset(&tgrp, 0, sizeof (tgrp));
+ for (rrecp = rrecp_in; rrecp;
+ rrecp = LINKED(rrecp, r_link) ? NEXT(rrecp, r_link) : NULL) {
+ int nscnt;
+ /* Find the origin for it if there is one. */
+ tgrp.z_class = rrecp->r_class;
+ nscnt = res_findzonecut2(statp, rrecp->r_dname, tgrp.z_class,
+ RES_EXHAUSTIVE, tgrp.z_origin,
+ sizeof tgrp.z_origin,
+ tgrp.z_nsaddrs, MAXNS);
+ if (nscnt <= 0) {
+ DPRINTF(("res_findzonecut failed (%d)", nscnt));
+ goto done;
+ }
+ tgrp.z_nscount = nscnt;
+ /* Find the group for it if there is one. */
+ for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link))
+ if (ns_samename(tgrp.z_origin, zptr->z_origin) == 1 &&
+ tgrp.z_class == zptr->z_class)
+ break;
+ /* Make a group for it if there isn't one. */
+ if (zptr == NULL) {
+ zptr = malloc(sizeof *zptr);
+ if (zptr == NULL) {
+ DPRINTF(("malloc failed"));
+ goto done;
+ }
+ *zptr = tgrp;
+ zptr->z_flags = 0;
+ INIT_LINK(zptr, z_link);
+ INIT_LIST(zptr->z_rrlist);
+ APPEND(zgrps, zptr, z_link);
+ }
+ /* Thread this rrecp onto the right group. */
+ APPEND(zptr->z_rrlist, rrecp, r_glink);
+ }
+
+ for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link)) {
+ /* Construct zone section and prepend it. */
+ rrecp = res_mkupdrec(ns_s_zn, zptr->z_origin,
+ zptr->z_class, ns_t_soa, 0);
+ if (rrecp == NULL) {
+ DPRINTF(("res_mkupdrec failed"));
+ goto done;
+ }
+ PREPEND(zptr->z_rrlist, rrecp, r_glink);
+ zptr->z_flags |= ZG_F_ZONESECTADDED;
+
+ /* Marshall the update message. */
+ n = res_nmkupdate(statp, HEAD(zptr->z_rrlist),
+ packet, sizeof packet);
+ DPRINTF(("res_mkupdate -> %d", n));
+ if (n < 0)
+ goto done;
+
+ /* Temporarily replace the resolver's nameserver set. */
+ nscount = res_getservers(statp, nsaddrs, MAXNS);
+ res_setservers(statp, zptr->z_nsaddrs, zptr->z_nscount);
+
+ /* Send the update and remember the result. */
+ if (key != NULL)
+ n = res_nsendsigned(statp, packet, n, key,
+ answer, sizeof answer);
+ else
+ n = res_nsend(statp, packet, n, answer, sizeof answer);
+ if (n < 0) {
+ DPRINTF(("res_nsend: send error, n=%d (%s)\n",
+ n, strerror(errno)));
+ goto done;
+ }
+ if (((HEADER *)answer)->rcode == ns_r_noerror)
+ nzones++;
+
+ /* Restore resolver's nameserver set. */
+ res_setservers(statp, nsaddrs, nscount);
+ nscount = 0;
+ }
+ done:
+ while (!EMPTY(zgrps)) {
+ zptr = HEAD(zgrps);
+ if ((zptr->z_flags & ZG_F_ZONESECTADDED) != 0)
+ res_freeupdrec(HEAD(zptr->z_rrlist));
+ UNLINK(zgrps, zptr, z_link);
+ free(zptr);
+ }
+ if (nscount != 0)
+ res_setservers(statp, nsaddrs, nscount);
+
+ return (nzones);
+}
+
+/* Private. */
+
+static void
+res_dprintf(const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ fputs(";; res_nupdate: ", stderr);
+ vfprintf(stderr, fmt, ap);
+ fputc('\n', stderr);
+ va_end(ap);
+}
--- /dev/null
+/*
+ * Copyright (c) 1999 by Internet Software Consortium, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * $Id: res_update.h,v 1.1 2006/03/01 19:01:39 majka Exp $
+ */
+
+#ifndef _RES_UPDATE_H_
+#define _RES_UPDATE_H_
+
+#include <sys/types.h>
+#include <arpa/nameser.h>
+#ifndef __APPLE__
+#include <isc/list.h>
+#else
+#define LIST(type) struct { type *head, *tail; }
+#define LINK(type) struct { type *prev, *next; }
+#define INIT_LIST(list) do { (list).head = NULL; (list).tail = NULL; } while (0)
+#define HEAD(list) ((list).head)
+#define TAIL(list) ((list).tail)
+#define EMPTY(list) ((list).head == NULL)
+#define PREV(elt, link) ((elt)->link.prev)
+#define NEXT(elt, link) ((elt)->link.next)
+#define INIT_LINK_TYPE(elt, link, type) \
+ do { \
+ (elt)->link.prev = (type *)(-1); \
+ (elt)->link.next = (type *)(-1); \
+ } while (0)
+#define INIT_LINK(elt, link) INIT_LINK_TYPE(elt, link, void)
+#define APPEND(list, elt, link) \
+ do { \
+ if ((list).tail != NULL) \
+ (list).tail->link.next = (elt); \
+ else \
+ (list).head = (elt); \
+ (elt)->link.prev = (list).tail; \
+ (elt)->link.next = NULL; \
+ (list).tail = (elt); \
+ } while (0)
+#define PREPEND(list, elt, link) \
+ do { \
+ if ((list).head != NULL) \
+ (list).head->link.prev = (elt); \
+ else \
+ (list).tail = (elt); \
+ (elt)->link.prev = NULL; \
+ (elt)->link.next = (list).head; \
+ (list).head = (elt); \
+ } while (0)
+#define UNLINK_TYPE(list, elt, link, type) \
+ do { \
+ if ((elt)->link.next != NULL) \
+ (elt)->link.next->link.prev = (elt)->link.prev; \
+ else \
+ (list).tail = (elt)->link.prev; \
+ if ((elt)->link.prev != NULL) \
+ (elt)->link.prev->link.next = (elt)->link.next; \
+ else \
+ (list).head = (elt)->link.next; \
+ INIT_LINK_TYPE(elt, link, type); \
+ } while (0)
+#define UNLINK(list, elt, link) \
+ UNLINK_TYPE(list, elt, link, void)
+#define LINKED(elt, link) ((void *)((elt)->link.prev) != (void *)(-1))
+#endif
+#include <resolv.h>
+
+/*
+ * This RR-like structure is particular to UPDATE.
+ */
+struct ns_updrec {
+ LINK(struct ns_updrec) r_link, r_glink;
+ ns_sect r_section; /* ZONE/PREREQUISITE/UPDATE */
+ char * r_dname; /* owner of the RR */
+ ns_class r_class; /* class number */
+ ns_type r_type; /* type number */
+ u_int32_t r_ttl; /* time to live */
+ u_char * r_data; /* rdata fields as text string */
+ u_int r_size; /* size of r_data field */
+ int r_opcode; /* type of operation */
+ /* following fields for private use by the resolver/server routines */
+ struct databuf *r_dp; /* databuf to process */
+ struct databuf *r_deldp; /* databuf's deleted/overwritten */
+ u_int r_zone; /* zone number on server */
+};
+typedef struct ns_updrec ns_updrec;
+typedef LIST(ns_updrec) ns_updque;
+
+#define res_mkupdate res_9_mkupdate
+#define res_update res_9_update
+#define res_mkupdrec res_9_mkupdrec
+#define res_freeupdrec res_9_freeupdrec
+#define res_nmkupdate res_9_nmkupdate
+#define res_nupdate res_9_nupdate
+
+int res_mkupdate __P((ns_updrec *, u_char *, int));
+int res_update __P((ns_updrec *));
+ns_updrec * res_mkupdrec __P((int, const char *, u_int, u_int, u_long));
+void res_freeupdrec __P((ns_updrec *));
+int res_nmkupdate __P((res_state, ns_updrec *, u_char *, int));
+int res_nupdate __P((res_state, ns_updrec *, ns_tsig_key *));
+
+#endif /*_RES_UPDATE_H_*/
--- /dev/null
+/*
+ * Copyright (c) 1983, 1987, 1989
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * @(#)resolv.h 8.1 (Berkeley) 6/2/93
+ * $Id: resolv.h,v 1.1 2006/03/01 19:01:39 majka Exp $
+ */
+
+/*
+ * Important note regarding the BIND-9 API on Mac OS
+ * -------------------------------------------------
+ *
+ * Mac OS supports a DNS query routing API (see <dns.h>) which is used by
+ * most system services to access DNS. The BIND-9 APIs described here are
+ * a lower-level that does not do query routing or search amongst multiple
+ * resolver clients. The results of DNS queries from this API may differ
+ * significantly from the results of queries sent to the <dns.h> API. We
+ * strongly encourage developers to use higher-level APIs where possible.
+ */
+
+#ifndef _RESOLV_9_H_
+#define _RESOLV_9_H_
+
+#ifdef BIND_8_COMPAT
+#include <resolv8_compat.h>
+#else
+
+#include <sys/param.h>
+#if (!defined(BSD)) || (BSD < 199306)
+# include <sys/bitypes.h>
+#else
+# include <sys/types.h>
+#endif
+#include <sys/cdefs.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <arpa/nameser.h>
+
+
+/*
+ * Revision information. This is the release date in YYYYMMDD format.
+ * It can change every day so the right thing to do with it is use it
+ * in preprocessor commands such as "#if (__RES > 19931104)". Do not
+ * compare for equality; rather, use it to determine whether your resolver
+ * is new enough to contain a certain feature.
+ */
+
+#define __RES 19991006
+
+#define __h_errno_set _res_9_h_errno_set
+#define RES_SET_H_ERRNO(r,x) __h_errno_set(r,x)
+
+#define __res_state __res_9_state
+struct __res_state; /* forward */
+
+__BEGIN_DECLS
+void __h_errno_set(struct __res_state *res, int err);
+__END_DECLS
+
+/*
+ * Resolver configuration file.
+ * Normally not present, but may contain the address of the
+ * inital name server(s) to query and the domain search list.
+ *
+ * Apple Note: The default DNS resolver client configuration
+ * is now stored in a system configuration database, not in
+ */
+
+#ifndef _PATH_RESCONF
+#define _PATH_RESCONF "/etc/resolv.conf"
+#endif
+
+#define res_goahead res_9_goahead
+#define res_nextns res_9_nextns
+#define res_modified res_9_modified
+#define res_done res_9_done
+#define res_error res_9_error
+#define res_sendhookact res_9_sendhookact
+
+typedef enum
+{
+ res_goahead,
+ res_nextns,
+ res_modified,
+ res_done,
+ res_error
+} res_sendhookact;
+
+typedef res_sendhookact (*res_send_qhook)__P((struct sockaddr * const *ns,
+ const u_char **query,
+ int *querylen,
+ u_char *ans,
+ int anssiz,
+ int *resplen));
+
+typedef res_sendhookact (*res_send_rhook)__P((const struct sockaddr *ns,
+ const u_char *query,
+ int querylen,
+ u_char *ans,
+ int anssiz,
+ int *resplen));
+
+#define res_sym res_9_sym
+
+struct res_sym
+{
+ int number; /* Identifying number, like T_MX */
+ const char * name; /* Its symbolic name, like "MX" */
+ const char * humanname; /* Its fun name, like "mail exchanger" */
+};
+
+/*
+ * Global defines and variables for resolver stub.
+ */
+#define MAXNS 3 /* max # name servers we'll track */
+#define MAXDFLSRCH 3 /* # default domain levels to try */
+#define MAXDNSRCH 6 /* max # domains in search path */
+#define LOCALDOMAINPARTS 2 /* min levels in name that is "local" */
+
+#define RES_TIMEOUT 5 /* min. seconds between retries */
+#define MAXRESOLVSORT 10 /* number of net to sort on */
+#define RES_MAXNDOTS 15 /* should reflect bit field size */
+#define RES_MAXRETRANS 30 /* only for resolv.conf/RES_OPTIONS */
+#define RES_MAXRETRY 5 /* only for resolv.conf/RES_OPTIONS */
+#define RES_DFLRETRY 2 /* Default #/tries. */
+#define RES_MAXTIME 65535 /* Infinity, in milliseconds. */
+
+#define __res_state_ext __res_9_state_ext
+struct __res_state_ext;
+
+#define __res_state __res_9_state
+struct __res_state {
+ int retrans; /* retransmition time interval */
+ int retry; /* number of times to transmit (attempts, not retries) */
+#ifdef sun
+ u_int options; /* option flags - see below. */
+#else
+ u_long options; /* option flags - see below. */
+#endif
+ int nscount; /* number of name servers */
+ struct sockaddr_in
+ nsaddr_list[MAXNS]; /* address of name server */
+#define nsaddr nsaddr_list[0] /* for backward compatibility */
+ u_short id; /* current message id */
+ char *dnsrch[MAXDNSRCH+1]; /* components of domain to search */
+ char defdname[256]; /* default domain (deprecated) */
+#ifdef sun
+ u_int pfcode; /* RES_PRF_ flags - see below. */
+#else
+ u_long pfcode; /* RES_PRF_ flags - see below. */
+#endif
+ unsigned ndots:4; /* threshold for initial abs. query */
+ unsigned nsort:4; /* number of elements in sort_list[] */
+ char unused[3];
+ struct {
+ struct in_addr addr;
+ u_int32_t mask;
+ } sort_list[MAXRESOLVSORT];
+ res_send_qhook qhook; /* query hook */
+ res_send_rhook rhook; /* response hook */
+ int res_h_errno; /* last one set for this context */
+ int _vcsock; /* PRIVATE: for res_send VC i/o */
+ u_int _flags; /* PRIVATE: see below */
+ u_int _pad; /* make _u 64 bit aligned */
+ union {
+ /* On an 32-bit arch this means 512b total. */
+ char pad[72 - 4*sizeof (int) - 2*sizeof (void *)];
+ struct {
+ u_int16_t nscount;
+ u_int16_t nstimes[MAXNS]; /* ms. */
+ int nssocks[MAXNS];
+ struct __res_state_ext *ext; /* extention for IPv6 */
+ } _ext;
+ } _u;
+};
+
+#define res_state res_9_state
+
+typedef struct __res_state *res_state;
+
+#define res_sockaddr_union res_9_sockaddr_union
+
+union res_sockaddr_union {
+ struct sockaddr_in sin;
+#ifdef IN6ADDR_ANY_INIT
+ struct sockaddr_in6 sin6;
+#endif
+#ifdef ISC_ALIGN64
+ int64_t __align64; /* 64bit alignment */
+#else
+ int32_t __align32; /* 32bit alignment */
+#endif
+ char __space[128]; /* max size */
+};
+
+/*
+ * Resolver flags (used to be discrete per-module statics ints).
+ */
+#define RES_F_VC 0x00000001 /* socket is TCP */
+#define RES_F_CONN 0x00000002 /* socket is connected */
+#define RES_F_EDNS0ERR 0x00000004 /* EDNS0 caused errors */
+
+/* res_findzonecut2() options */
+#define RES_EXHAUSTIVE 0x00000001 /* always do all queries */
+#define RES_IPV4ONLY 0x00000002 /* IPv4 only */
+#define RES_IPV6ONLY 0x00000004 /* IPv6 only */
+
+/*
+ * Resolver options (keep these in synch with res_debug.c, please)
+ */
+#define RES_INIT 0x00000001 /* address initialized */
+#define RES_DEBUG 0x00000002 /* print debug messages */
+#define RES_AAONLY 0x00000004 /* authoritative answers only (!IMPL)*/
+#define RES_USEVC 0x00000008 /* use virtual circuit */
+#define RES_PRIMARY 0x00000010 /* query primary server only (!IMPL) */
+#define RES_IGNTC 0x00000020 /* ignore trucation errors */
+#define RES_RECURSE 0x00000040 /* recursion desired */
+#define RES_DEFNAMES 0x00000080 /* use default domain name */
+#define RES_STAYOPEN 0x00000100 /* Keep TCP socket open */
+#define RES_DNSRCH 0x00000200 /* search up local domain tree */
+#define RES_INSECURE1 0x00000400 /* type 1 security disabled */
+#define RES_INSECURE2 0x00000800 /* type 2 security disabled */
+#define RES_NOALIASES 0x00001000 /* shuts off HOSTALIASES feature */
+#define RES_USE_INET6 0x00002000 /* use/map IPv6 in gethostbyname() */
+#define RES_ROTATE 0x00004000 /* rotate ns list after each query */
+#define RES_NOCHECKNAME 0x00008000 /* do not check names for sanity. */
+#define RES_KEEPTSIG 0x00010000 /* do not strip TSIG records */
+#define RES_BLAST 0x00020000 /* blast all recursive servers */
+#define RES_NO_NIBBLE 0x00040000 /* disable IPv6 nibble mode reverse */
+#define RES_NO_BITSTRING 0x00080000 /* disable IPv6 bitstring mode reverse */
+#define RES_NOTLDQUERY 0x00100000 /* don't unqualified name as a tld */
+#define RES_USE_DNSSEC 0x00200000 /* use DNSSEC using OK bit in OPT */
+/* KAME extensions: use higher bit to avoid conflict with ISC use */
+#define RES_USE_DNAME 0x10000000 /* use DNAME */
+#define RES_USE_A6 0x20000000 /* use A6 */
+#define RES_USE_EDNS0 0x40000000 /* use EDNS0 if configured */
+#define RES_NO_NIBBLE2 0x80000000 /* disable alternate nibble lookup */
+
+#define RES_DEFAULT (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH | RES_INSECURE1)
+
+/*
+ * Resolver "pfcode" values. Used by dig.
+ */
+#define RES_PRF_STATS 0x00000001
+#define RES_PRF_UPDATE 0x00000002
+#define RES_PRF_CLASS 0x00000004
+#define RES_PRF_CMD 0x00000008
+#define RES_PRF_QUES 0x00000010
+#define RES_PRF_ANS 0x00000020
+#define RES_PRF_AUTH 0x00000040
+#define RES_PRF_ADD 0x00000080
+#define RES_PRF_HEAD1 0x00000100
+#define RES_PRF_HEAD2 0x00000200
+#define RES_PRF_TTLID 0x00000400
+#define RES_PRF_HEADX 0x00000800
+#define RES_PRF_QUERY 0x00001000
+#define RES_PRF_REPLY 0x00002000
+#define RES_PRF_INIT 0x00004000
+#define RES_PRF_TRUNC 0x00008000
+/* 0x00010000 */
+
+/* Things involving an internal (static) resolver context. */
+#ifndef __BIND_NOSTATIC
+extern struct __res_state _res;
+#endif
+
+#ifndef __BIND_NOSTATIC
+#define fp_nquery res_9_fp_nquery
+#define fp_query res_9_fp_query
+#define hostalias res_9_hostalias_1
+#define p_query res_9_p_query
+#define res_close res_9_close
+#define res_init res_9_init
+#define res_isourserver res_9_isourserver
+#define res_mkquery res_9_mkquery
+#define res_query res_9_query
+#define res_querydomain res_9_querydomain
+#define res_search res_9_search
+#define res_send res_9_send
+#define res_sendsigned res_9_sendsigned
+
+__BEGIN_DECLS
+void fp_nquery __P((const u_char *, int, FILE *));
+void fp_query __P((const u_char *, FILE *));
+const char *hostalias __P((const char *));
+void p_query __P((const u_char *));
+void res_close __P((void));
+int res_init __P((void));
+int res_isourserver __P((const struct sockaddr_in *));
+int res_mkquery __P((int, const char *, int, int, const u_char *,
+ int, const u_char *, u_char *, int));
+int res_query __P((const char *, int, int, u_char *, int));
+int res_querydomain __P((const char *, const char *, int, int,
+ u_char *, int));
+int res_search __P((const char *, int, int, u_char *, int));
+int res_send __P((const u_char *, int, u_char *, int));
+int res_sendsigned __P((const u_char *, int, ns_tsig_key *,
+ u_char *, int));
+__END_DECLS
+#endif
+
+#if !defined(SHARED_LIBBIND) || defined(LIB)
+/*
+ * If libbind is a shared object (well, DLL anyway)
+ * these externs break the linker when resolv.h is
+ * included by a lib client (like named)
+ * Make them go away if a client is including this
+ *
+ */
+#define res_sym res_9_sym
+#define __p_key_syms __res_9_p_key_syms
+#define __p_cert_syms __res_9_p_cert_syms
+#define __p_class_syms __res_9_p_class_syms
+#define __p_type_syms __res_9_p_type_syms
+#define __p_rcode_syms __res_9_p_rcode_syms
+
+extern const struct res_sym __p_key_syms[];
+extern const struct res_sym __p_cert_syms[];
+extern const struct res_sym __p_class_syms[];
+extern const struct res_sym __p_type_syms[];
+extern const struct res_sym __p_rcode_syms[];
+#endif /* SHARED_LIBBIND */
+
+#define b64_ntop res_9_b64_ntop
+#define b64_pton res_9_b64_pton
+#define dn_comp res_9_dn_comp
+#define dn_count_labels res_9_dn_count_labels
+#define dn_expand res_9_dn_expand
+#define dn_skipname res_9_dn_skipname
+#define fp_resstat res_9_fp_resstat
+#define loc_aton res_9_loc_aton
+#define loc_ntoa res_9_loc_ntoa
+#define p_cdname res_9_p_cdname
+#define p_cdnname res_9_p_cdnname
+#define p_class res_9_p_class
+#define p_fqname res_9_p_fqname
+#define p_fqnname res_9_p_fqnname
+#define p_option res_9_p_option
+#define p_secstodate res_9_p_secstodate
+#define p_section res_9_p_section
+#define p_time res_9_p_time
+#define p_type res_9_p_type
+#define p_rcode res_9_p_rcode
+#define putlong res_9_putlong
+#define putshort res_9_putshort
+#define res_dnok res_9_dnok
+#define res_findzonecut res_9_findzonecut
+#define res_findzonecut2 res_9_findzonecut2
+#define res_hnok res_9_hnok
+#define res_hostalias res_9_hostalias_2
+#define res_mailok res_9_mailok
+#define res_nameinquery res_9_nameinquery
+#define res_nclose res_9_nclose
+#define res_ninit res_9_ninit
+#define res_nmkquery res_9_nmkquery
+#define res_pquery res_9_pquery
+#define res_nquery res_9_nquery
+#define res_nquerydomain res_9_nquerydomain
+#define res_nsearch res_9_nsearch
+#define res_nsend res_9_nsend
+#define res_nsendsigned res_9_nsendsigned
+#define res_nisourserver res_9_nisourserver
+#define res_ownok res_9_ownok
+#define res_queriesmatch res_9_queriesmatch
+#define res_randomid res_9_randomid
+#define sym_ntop res_9_sym_ntop
+#define sym_ntos res_9_sym_ntos
+#define sym_ston res_9_sym_ston
+#define res_nopt res_9_nopt
+#define res_ndestroy res_9_ndestroy
+#define res_nametoclass res_9_nametoclass
+#define res_nametotype res_9_nametotype
+#define res_setservers res_9_setservers
+#define res_getservers res_9_getservers
+#define _getshort res_9_getshort
+#define _getlong res_9_getlong
+#define __res_vinit res_9_vinit
+
+__BEGIN_DECLS
+int res_hnok __P((const char *));
+int res_ownok __P((const char *));
+int res_mailok __P((const char *));
+int res_dnok __P((const char *));
+int sym_ston __P((const struct res_sym *, const char *, int *));
+const char * sym_ntos __P((const struct res_sym *, int, int *));
+const char *sym_ntop __P((const struct res_sym *, int, int *));
+int b64_ntop __P((u_char const *, size_t, char *, size_t));
+int b64_pton __P((char const *, u_char *, size_t));
+int loc_aton __P((const char *ascii, u_char *binary));
+const char * loc_ntoa __P((const u_char *binary, char *ascii));
+int dn_skipname __P((const u_char *, const u_char *));
+void putlong __P((u_int32_t, u_char *));
+void putshort __P((u_int16_t, u_char *));
+#ifndef __ultrix__
+u_int16_t _getshort __P((const u_char *src));
+u_int32_t _getlong __P((const u_char *src));
+#endif
+const char * p_class __P((int));
+const char * p_time __P((u_int32_t));
+const char * p_type __P((int));
+const char * p_rcode __P((int));
+const u_char * p_cdnname __P((const u_char *, const u_char *, int, FILE *));
+const u_char * p_cdname __P((const u_char *, const u_char *, FILE *));
+const u_char * p_fqnname __P((const u_char *cp, const u_char *msg, int, char *, int));
+const u_char * p_fqname __P((const u_char *, const u_char *, FILE *));
+const char * p_option __P((u_long option));
+char * p_secstodate __P((u_long));
+int dn_count_labels __P((const char *));
+int dn_comp __P((const char *, u_char *, int, u_char **, u_char **));
+int dn_expand __P((const u_char *, const u_char *, const u_char *, char *, int));
+u_int res_randomid __P((void));
+int res_nameinquery __P((const char *, int, int, const u_char *, const u_char *));
+int res_queriesmatch __P((const u_char *, const u_char *, const u_char *, const u_char *));
+const char * p_section __P((int section, int opcode));
+
+/* Things involving a resolver context. */
+int res_ninit __P((res_state));
+int res_nisourserver __P((const res_state, const struct sockaddr_in *));
+void fp_resstat __P((const res_state, FILE *));
+void res_pquery __P((const res_state, const u_char *, int, FILE *));
+const char *res_hostalias __P((const res_state, const char *, char *, size_t));
+int res_nquery __P((res_state, const char *, int, int, u_char *, int));
+int res_nsearch __P((res_state, const char *, int, int, u_char *, int));
+int res_nquerydomain __P((res_state, const char *, const char *, int, int, u_char *, int));
+int res_nmkquery __P((res_state, int, const char *, int, int, const u_char *, int, const u_char *, u_char *, int));
+int res_nsend __P((res_state, const u_char *, int, u_char *, int));
+int res_nsendsigned __P((res_state, const u_char *, int, ns_tsig_key *, u_char *, int));
+int res_findzonecut __P((res_state, const char *, ns_class, int, char *, size_t, struct in_addr *, int));
+int res_findzonecut2 __P((res_state, const char *, ns_class, int, char *, size_t, union res_sockaddr_union *, int));
+void res_nclose __P((res_state));
+int res_nopt __P((res_state, int, u_char *, int, int));
+void res_send_setqhook __P((res_send_qhook hook));
+void res_send_setrhook __P((res_send_rhook hook));
+int __res_vinit __P((res_state, int));
+void res_destroyservicelist __P((void));
+const char * res_servicename __P((u_int16_t port, const char *proto));
+const char * res_protocolname __P((int num));
+void res_destroyprotolist __P((void));
+void res_buildprotolist __P((void));
+const char * res_get_nibblesuffix __P((res_state));
+const char * res_get_nibblesuffix2 __P((res_state));
+const char * res_get_bitstringsuffix __P((res_state));
+void res_ndestroy __P((res_state));
+u_int16_t res_nametoclass __P((const char *buf, int *success));
+u_int16_t res_nametotype __P((const char *buf, int *success));
+void res_setservers __P((res_state, const union res_sockaddr_union *, int));
+int res_getservers __P((res_state, union res_sockaddr_union *, int));
+__END_DECLS
+
+#endif /* !BIND_8_COMPAT */
+#endif /* !_RESOLV_9_H_ */
--- /dev/null
+.\" Copyright (c) 1985, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)resolver.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD: src/lib/libc/net/resolver.3,v 1.21 2001/10/01 16:08:56 ru Exp $
+.\"
+.Dd June 4, 1993
+.Dt RESOLVER 3
+.Os
+.Sh NAME
+.Nm res_query ,
+.Nm res_search ,
+.Nm res_mkquery ,
+.Nm res_send ,
+.Nm res_init ,
+.Nm dn_comp ,
+.Nm dn_expand ,
+.Nm dn_skipname ,
+.Nm ns_get16 ,
+.Nm ns_get32 ,
+.Nm ns_put16 ,
+.Nm ns_put32
+.Nd resolver routines
+.Sh LIBRARY
+.Lb libresolv
+.Sh SYNOPSIS
+.In sys/types.h
+.In netinet/in.h
+.In arpa/nameser.h
+.In resolv.h
+.Ft int
+.Fo res_query
+.Fa "const char *dname"
+.Fa "int class"
+.Fa "int type"
+.Fa "u_char *answer"
+.Fa "int anslen"
+.Fc
+.Ft int
+.Fo res_search
+.Fa "const char *dname"
+.Fa "int class"
+.Fa "int type"
+.Fa "u_char *answer"
+.Fa "int anslen"
+.Fc
+.Ft int
+.Fo res_mkquery
+.Fa "int op"
+.Fa "const char *dname"
+.Fa "int class"
+.Fa "int type"
+.Fa "const u_char *data"
+.Fa "int datalen"
+.Fa "const u_char *newrr_in"
+.Fa "u_char *buf"
+.Fa "int buflen"
+.Fc
+.Ft int
+.Fo res_send
+.Fa "const u_char *msg"
+.Fa "int msglen"
+.Fa "u_char *answer"
+.Fa "int anslen"
+.Fc
+.Ft int
+.Fn res_init
+.Ft int
+.Fo dn_comp
+.Fa "const char *exp_dn"
+.Fa "u_char *comp_dn"
+.Fa "int length"
+.Fa "u_char **dnptrs"
+.Fa "u_char **lastdnptr"
+.Fc
+.Ft int
+.Fo dn_expand
+.Fa "const u_char *msg"
+.Fa "const u_char *eomorig"
+.Fa "const u_char *comp_dn"
+.Fa "char *exp_dn"
+.Fa "int length"
+.Fc
+.Ft int
+.Fn dn_skipname "const u_char *comp_dn" "const u_char *eom"
+.Ft u_int
+.Fn ns_get16 "const u_char *src"
+.Ft u_long
+.Fn ns_get32 "const u_char *src"
+.Ft void
+.Fn ns_put16 "u_int src" "u_char *dst"
+.Ft void
+.Fn ns_put32 "u_long src" "u_char *dst"
+.Sh DESCRIPTION
+These routines are used for making, sending and interpreting
+query and reply messages with Internet domain name servers.
+.Pp
+Global configuration and state information that is used by the
+resolver routines is kept in the structure
+.Em _res .
+Most of the values have reasonable defaults and can be ignored.
+Options
+stored in
+.Em _res.options
+are defined in
+.Pa resolv.h
+and are as follows.
+Options are stored as a simple bit mask containing the bitwise ``or''
+of the options enabled.
+.Bl -tag -width RES_USE_INET6
+.It Dv RES_INIT
+True if the initial name server address and default domain name are
+initialized (i.e.,
+.Fn res_init
+has been called).
+.It Dv RES_DEBUG
+Print debugging messages.
+.It Dv RES_AAONLY
+Accept authoritative answers only.
+With this option,
+.Fn res_send
+should continue until it finds an authoritative answer or finds an error.
+Currently this is not implemented.
+.It Dv RES_USEVC
+Use
+.Tn TCP
+connections for queries instead of
+.Tn UDP
+datagrams.
+.It Dv RES_STAYOPEN
+Used with
+.Dv RES_USEVC
+to keep the
+.Tn TCP
+connection open between
+queries.
+This is useful only in programs that regularly do many queries.
+.Tn UDP
+should be the normal mode used.
+.It Dv RES_IGNTC
+Unused currently (ignore truncation errors, i.e., don't retry with
+.Tn TCP ) .
+.It Dv RES_RECURSE
+Set the recursion-desired bit in queries.
+This is the default.
+.Pf ( Fn res_send
+does not do iterative queries and expects the name server
+to handle recursion.)
+.It Dv RES_DEFNAMES
+If set,
+.Fn res_search
+will append the default domain name to single-component names
+(those that do not contain a dot).
+This option is enabled by default.
+.It Dv RES_DNSRCH
+If this option is set,
+.Fn res_search
+will search for host names in the current domain and in parent domains; see
+.Xr hostname 7 .
+This is used by the standard host lookup routine
+.Xr gethostbyname 3 .
+This option is enabled by default.
+.It Dv RES_NOALIASES
+This option turns off the user level aliasing feature controlled by the
+.Dq Ev HOSTALIASES
+environment variable. Network daemons should set this option.
+.It Dv RES_USE_INET6
+Enables support for IPv6-only applications.
+This causes IPv4 addresses to be returned as an IPv4 mapped address.
+For example,
+.Li 10.1.1.1
+will be returned as
+.Li ::ffff:10.1.1.1 .
+The option is meaningful with certain kernel configuration only.
+.It Dv RES_USE_EDNS0
+Enables support for OPT pseudo-RR for EDNS0 extension.
+With the option, resolver code will attach OPT pseudo-RR into DNS queries,
+to inform of our receive buffer size.
+The option will allow DNS servers to take advantage of non-default receive
+buffer size, and to send larger replies.
+DNS query packets with EDNS0 extension is not compatible with
+non-EDNS0 DNS servers.
+.El
+.Pp
+The
+.Fn res_init
+routine
+reads the configuration file (if any; see
+.Xr resolver 5 )
+to get the default domain name,
+search list and
+the Internet address of the local name server(s).
+If no server is configured, the host running
+the resolver is tried.
+The current domain name is defined by the hostname
+if not specified in the configuration file;
+it can be overridden by the environment variable
+.Ev LOCALDOMAIN .
+This environment variable may contain several blank-separated
+tokens if you wish to override the
+.Em "search list"
+on a per-process basis. This is similar to the
+.Em search
+command in the configuration file.
+Another environment variable
+.Dq Ev RES_OPTIONS
+can be set to
+override certain internal resolver options which are otherwise
+set by changing fields in the
+.Em _res
+structure or are inherited from the configuration file's
+.Em options
+command. The syntax of the
+.Dq Ev RES_OPTIONS
+environment variable is explained in
+.Xr resolver 5 .
+Initialization normally occurs on the first call
+to one of the following routines.
+.Pp
+The
+.Fn res_query
+function provides an interface to the server query mechanism.
+It constructs a query, sends it to the local server,
+awaits a response, and makes preliminary checks on the reply.
+The query requests information of the specified
+.Fa type
+and
+.Fa class
+for the specified fully-qualified domain name
+.Fa dname .
+The reply message is left in the
+.Fa answer
+buffer with length
+.Fa anslen
+supplied by the caller.
+.Pp
+The
+.Fn res_search
+routine makes a query and awaits a response like
+.Fn res_query ,
+but in addition, it implements the default and search rules
+controlled by the
+.Dv RES_DEFNAMES
+and
+.Dv RES_DNSRCH
+options.
+It returns the first successful reply.
+.Pp
+The remaining routines are lower-level routines used by
+.Fn res_query .
+The
+.Fn res_mkquery
+function
+constructs a standard query message and places it in
+.Fa buf .
+It returns the size of the query, or \-1 if the query is
+larger than
+.Fa buflen .
+The query type
+.Fa op
+is usually
+.Dv QUERY ,
+but can be any of the query types defined in
+.Aq Pa arpa/nameser.h .
+The domain name for the query is given by
+.Fa dname .
+.Fa Newrr
+is currently unused but is intended for making update messages.
+.Pp
+The
+.Fn res_send
+routine
+sends a pre-formatted query and returns an answer.
+It will call
+.Fn res_init
+if
+.Dv RES_INIT
+is not set, send the query to the local name server, and
+handle timeouts and retries.
+The length of the reply message is returned, or
+\-1 if there were errors.
+.Pp
+The
+.Fn dn_comp
+function
+compresses the domain name
+.Fa exp_dn
+and stores it in
+.Fa comp_dn .
+The size of the compressed name is returned or \-1 if there were errors.
+The size of the array pointed to by
+.Fa comp_dn
+is given by
+.Fa length .
+The compression uses
+an array of pointers
+.Fa dnptrs
+to previously-compressed names in the current message.
+The first pointer points to
+the beginning of the message and the list ends with
+.Dv NULL .
+The limit to the array is specified by
+.Fa lastdnptr .
+A side effect of
+.Fn dn_comp
+is to update the list of pointers for
+labels inserted into the message
+as the name is compressed.
+If
+.Em dnptr
+is
+.Dv NULL ,
+names are not compressed.
+If
+.Fa lastdnptr
+is
+.Dv NULL ,
+the list of labels is not updated.
+.Pp
+The
+.Fn dn_expand
+entry
+expands the compressed domain name
+.Fa comp_dn
+to a full domain name
+The compressed name is contained in a query or reply message;
+.Fa msg
+is a pointer to the beginning of the message.
+The uncompressed name is placed in the buffer indicated by
+.Fa exp_dn
+which is of size
+.Fa length .
+The size of compressed name is returned or \-1 if there was an error.
+.Pp
+The
+.Fn dn_skipname
+function skips over a compressed domain name, which starts at a location
+pointed to by
+.Fa comp_dn .
+The compressed name is contained in a query or reply message;
+.Fa eom
+is a pointer to the end of the message.
+The size of compressed name is returned or \-1 if there was
+an error.
+.Pp
+The
+.Fn ns_get16
+function gets a 16-bit quantity from a buffer pointed to by
+.Fa src .
+.Pp
+The
+.Fn ns_get32
+function gets a 32-bit quantity from a buffer pointed to by
+.Fa src .
+.Pp
+The
+.Fn ns_put16
+function puts a 16-bit quantity
+.Fa src
+to a buffer pointed to by
+.Fa dst .
+.Pp
+The
+.Fn ns_put32
+function puts a 32-bit quantity
+.Fa src
+to a buffer pointed to by
+.Fa dst .
+.Sh FILES
+.Bl -tag -width /etc/resolv.conf
+.It Pa /etc/resolv.conf
+The configuration file,
+see
+.Xr resolver 5 .
+.El
+.Sh SEE ALSO
+.Xr gethostbyname 3 ,
+.Xr resolver 5 ,
+.Xr hostname 7 ,
+.Xr named 8
+.Pp
+.%T RFC1032 ,
+.%T RFC1033 ,
+.%T RFC1034 ,
+.%T RFC1035 ,
+.%T RFC974
+.Rs
+.%T "Name Server Operations Guide for BIND"
+.Re
+.Sh HISTORY
+The
+.Nm
+function appeared in
+.Bx 4.3 .
--- /dev/null
+.\" $OpenBSD: resolver.5,v 1.2 1997/03/12 10:42:19 downsj Exp $
+.\" Copyright (c) 1986 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms are permitted
+.\" provided that the above copyright notice and this paragraph are
+.\" duplicated in all such forms and that any documentation,
+.\" advertising materials, and other materials related to such
+.\" distribution and use acknowledge that the software was developed
+.\" by the University of California, Berkeley. The name of the
+.\" University may not be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" Portions Copyright (c) 2003 by Apple Computer, Inc.
+.\"
+.\" @(#)resolver.5 5.9 (Berkeley) 12/14/89
+.\" $From: resolver.5,v 8.3 1995/12/06 20:34:35 vixie Exp $
+.\"
+.Dd June 6, 2003
+.Dt resolver 5
+.Os "Mac OS X"
+.Sh NAME
+.Nm resolver
+.Nd resolver configuration file format
+.Sh DESCRIPTION
+The
+.Nm
+is a set of routines in the C library
+.Xr resolv(3)
+that provide access to the Internet Domain Name System (DNS).
+A resolver configuration file contains information used to specify parameters
+for a DNS resolver client.
+The file contains a list of keywords with values that provide various types
+of resolver information.
+.Pp
+Mac OS X supports a DNS search strategy that may involve multiple
+DNS resolver clients.
+See the
+.Sx SEARCH STRATEGY
+section below for an overview of multi-client DNS
+search.
+.Pp
+Each DNS client is configured using the contents of a single configuration
+file of the format described below, or from a property list supplied from
+some other system configuration database.
+Note that the
+.Pa /etc/resolv.conf
+file, which contains configuration for the default (or "primary") DNS resolver client,
+is maintained automatically by Mac OS X and should not be edited manually.
+Changes to the DNS configuration should be made by using the Network
+Preferences panel.
+.Pp
+The different configuration options are given below.
+.Ss nameserver
+Internet address (in dot notation for IPv4 or in colon notation for IPv6)
+of a name server that the resolver should query.
+The address may optionally have a trailing dot followed by a port number.
+For example,
+.Li 10.0.0.17.55
+specifies that the nameserver at 10.0.0.17
+uses port 55.
+.Pp
+Up to
+.Va MAXNS
+(currently 3) name servers may be listed,
+one per keyword.
+If there are multiple servers,
+the resolver library queries them in the order listed.
+The algorithm used is to try a name server, and if the query times out,
+try the next, until out of name servers,
+then repeat trying all the name servers
+until a maximum number of retries are made.
+.Ss port
+IP port number to be used for this resolver.
+The default port is 53.
+The port number for an individual nameserver may be specified as
+part of the nameserver address (see
+.Sx nameserver
+above) to override the default
+or the port number specified as a value for this keyword.
+.Ss domain
+Domain name associated with this resolver configuration.
+This option is normally not required by the Mac OS X DNS search system
+when the resolver configuration is read from a file in the
+.Pa /etc/resolver
+directroy.
+In that case the file name is used as the domain name.
+However,
+.Sx domain
+must be provided when there are
+multiple resolver clients for the same domain name, since multiple
+files may not exist having the same name.
+See the
+.Sx SEARCH STRATEGY
+section for more details.
+.Ss search
+Search list for host-name lookup.
+This parameter is only used by the "Super" DNS resolver, which
+manages the DNS search strategy amongst multiple DNS resolver clients.
+Unqualified queries will be attempted using each component
+of the search list in turn until a match is found.
+Note that this process may be slow and will generate a lot of network
+traffic if the servers for the listed domains are not local,
+and that queries will time out if no server is available
+for one of the domains.
+.Pp
+The search list is currently limited to six domains
+with a total of 256 characters.
+.Ss search_order
+Only required for those clients that share a domain name with other clients.
+Queries will be sent to these clients in order by ascending
+.Sx search_order
+value.
+For example, this allows two clients for the ".local"
+domain, which is used by Apple's multicast DNS, but which may
+also be used at some sites as private DNS domain name.
+.Ss sortlist
+Sortlist allows addresses returned by gethostbyname to be sorted.
+A sortlist is specified by IP address netmask pairs. The netmask is
+optional and defaults to the natural netmask of the net. The IP address
+and optional network pairs are separated by slashes. Up to 10 pairs may
+be specified. For example:
+.Bd -literal -offset indent
+ sortlist 130.155.160.0/255.255.240.0 130.155.0.0
+.Ed
+.Ss timeout
+Specifies the total amount of time allowed for a name resolution.
+This time interval is divided by the number of nameservers and the number
+of retries allowed for each nameserver.
+.Ss options
+Options allows certain internal resolver variables to be modified.
+The syntax is:
+.Pp
+options
+.Ar option Li "..."
+.Pp
+where
+.Ar option
+is one of the following:
+.Bl -tag -width -indent
+.It Ar debug
+sets
+.Va RES_DEBUG
+in the resolver options.
+.It Ar timeout:n
+sets the per-retry timeout for resolver queries.
+The total timeout allowed for a query depends on the number of retries and the
+number of nameservers. This value is ignored if a total timeout is specified
+using the
+.Sx timeout
+keyword (see above).
+.It Ar ndots:n
+Sets a threshold for the number of dots which
+must appear in a name given to
+.Sx res_query
+(see
+.Xr resolver(3))
+before an initial absolute query will be made. The default for
+.Ar n
+is ``1'', meaning that if there are any dots in a name, the name
+will be tried first as an absolute name before any
+.Sx search
+list elements are appended to it.
+.Pp
+The keyword and value must appear on a single line,
+and the keyword must start the line.
+The value follows the keyword, separated by white space.
+.El
+.Sh SEARCH STRATEGY
+Mac OS X uses a DNS search strategy that supports multiple DNS
+client configurations.
+Each DNS client has its own set of nameserver
+addresses and its own set of operational parameters.
+Each client can perform DNS queries and searches independent of other clients.
+Each client has a symbolic name which is of the same format as a
+domain name, e.g. "apple.com".
+A special meta-client, known as the
+"Super" DNS client acts as a router for DNS queries.
+The Super client chooses among all available clients by finding a best match
+between the domain name given in a query and the names of all known clients.
+.Pp
+Queries for qualified names
+are sent using a client configuration
+that best matches the domain name given in the query.
+For example, if there is a client named "apple.com", a search for
+"www.apple.com" would use the resolver configuration specified for that client.
+The matching algorithm chooses the client with the maximum number of matching
+domain components.
+For example, if there are clients named "a.b.c", and "b.c", a search for
+"x.a.b.c" would use the "a.b.c" resolver configuration, while a search
+for "x.y.b.c" would use the "b.c" client.
+If there are no matches, the configuration settings in the default client,
+generally corresponding to the
+.Pa /etc/resolv.conf
+file or to the "primary" DNS
+configuration on the system are used for the query.
+.Pp
+If multiple clients are available for the same domain name, the clients ordered
+according to a
+.Sx search_order
+value (see above).
+Queries are sent to these resolvers in sequence by ascending value of
+search_order.
+.Pp
+The configuration for a particular client may be read from a file
+having the format described in this man page.
+These are at present located by the system in the
+.Pa /etc/resolv.conf
+file and
+in the files found in the
+.Pa /etc/resolver
+directroy.
+However, client configurations are not limited to file storage.
+The implementation of the DNS multi-client search strategy may also locate
+client configuratins in other data sources, such as the System Configuration
+Database.
+Users of the DNS system should make no assumptions about the
+source of the configuration data.
+.Sh FILES
+/etc/resolv.conf, /etc/resolver/*
+.Sh SEE ALSO
+gethostbyname(2), getaddrinfo(3), resolver(3)
--- /dev/null
+.so man3/resolver.3