To install the patch, do the following:

       # cd /usr/src/usr.bin                   (or elsewhere)
       # tar xvfz .../openssh-2.1.1.tgz
       # patch -p0 < openbsd26_2.1.1.patch
       # cd ssh
       # make obj
       # make cleandir
       # make depend
       # make
       # make install
       # cp ssh_config sshd_config /etc

diff -urN ssh-old/freeaddrinfo.c ssh/freeaddrinfo.c
--- ssh-old/freeaddrinfo.c      Wed Dec 31 17:00:00 1969
+++ ssh/freeaddrinfo.c  Thu Jun  8 11:20:22 2000
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1996, 1997, 1998, 1999, Craig Metz, 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 Craig Metz and
+ *      by other contributors.
+ * 4. Neither the name of the author nor the names of 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.
+ */
+
+#include <stdlib.h>
+#include <netdb.h>
+
+void
+freeaddrinfo(ai)
+       struct addrinfo *ai;
+{
+       struct addrinfo *p;
+
+       do {
+               p = ai;
+               ai = ai->ai_next;
+               if (p->ai_canonname)
+                       free(p->ai_canonname);
+               free((void *)p);
+       } while (ai);
+}
diff -urN ssh-old/gai_strerror.c ssh/gai_strerror.c
--- ssh-old/gai_strerror.c      Wed Dec 31 17:00:00 1969
+++ ssh/gai_strerror.c  Thu Jun  8 11:20:22 2000
@@ -0,0 +1,79 @@
+/*     $OpenBSD: openbsd26_1.2.3.patch,v 1.1 2000/03/06 21:38:08 deraadt Exp $ */
+
+/*
+ * %%% copyright-cmetz-97-bsd
+ * Copyright (c) 1997-1999, Craig Metz, 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 Craig Metz and
+ *      by other contributors.
+ * 4. Neither the name of the author nor the names of 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.
+ */
+
+/* gai_strerror() v1.38 */
+
+#include <sys/types.h>
+#include <netdb.h>
+#include <errno.h>
+
+#include "kame.h"
+
+char *
+gai_strerror(int errnum)
+{
+       switch (errnum) {
+       case 0:
+               return "no error";
+       case EAI_BADFLAGS:
+               return "invalid value for ai_flags";
+       case EAI_NONAME:
+               return "name or service is not known";
+       case EAI_AGAIN:
+               return "temporary failure in name resolution";
+       case EAI_FAIL:
+               return "non-recoverable failure in name resolution";
+       case EAI_NODATA:
+               return "no address associated with name";
+       case EAI_FAMILY:
+               return "ai_family not supported";
+       case EAI_SOCKTYPE:
+               return "ai_socktype not supported";
+       case EAI_SERVICE:
+               return "service not supported for ai_socktype";
+       case EAI_ADDRFAMILY:
+               return "address family for name not supported";
+       case EAI_MEMORY:
+               return "memory allocation failure";
+       case EAI_SYSTEM:
+               return "system error";
+       case EAI_BADHINTS:
+               return "invalid value for hints";
+       case EAI_PROTOCOL:
+               return "resolved protocol is unknown";
+       default:
+               return "unknown/invalid error";
+       }
+}
diff -urN ssh-old/getaddrinfo.c ssh/getaddrinfo.c
--- ssh-old/getaddrinfo.c       Wed Dec 31 17:00:00 1969
+++ ssh/getaddrinfo.c   Thu Jun  8 11:20:22 2000
@@ -0,0 +1,1784 @@
+/*     $OpenBSD: openbsd26_1.2.3.patch,v 1.1 2000/03/06 21:38:08 deraadt Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * 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. Neither the name of the project 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 PROJECT 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 PROJECT 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.
+ */
+
+/*
+ * Issues to be discussed:
+ * - Thread safe-ness must be checked.
+ * - Return values.  There are nonstandard return values defined and used
+ *   in the source code.  This is because RFC2553 is silent about which error
+ *   code must be returned for which situation.
+ * - IPv4 classful (shortened) form.  RFC2553 is silent about it.  XNET 5.2
+ *   says to use inet_aton() to convert IPv4 numeric to binary (alows
+ *   classful form as a result).
+ *   current code - disallow classful form for IPv4 (due to use of inet_pton).
+ * - freeaddrinfo(NULL).  RFC2553 is silent about it.  XNET 5.2 says it is
+ *   invalid.
+ *   current code - SEGV on freeaddrinfo(NULL)
+ * Note:
+ * - We use getipnodebyname() just for thread-safeness.  There's no intent
+ *   to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to
+ *   getipnodebyname().
+ * - The code filters out AFs that are not supported by the kernel,
+ *   when globbing NULL hostname (to loopback, or wildcard).  Is it the right
+ *   thing to do?  What is the relationship with post-RFC2553 AI_ADDRCONFIG
+ *   in ai_flags?
+ * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague.
+ *   (1) what should we do against numeric hostname (2) what should we do
+ *   against NULL hostname (3) what is AI_ADDRCONFIG itself.  AF not ready?
+ *   non-loopback address configured?  global address configured?
+ * - To avoid search order issue, we have a big amount of code duplicate
+ *   from gethnamaddr.c and some other places.  The issues that there's no
+ *   lower layer function to lookup "IPv4 or IPv6" record.  Calling
+ *   gethostbyname2 from getaddrinfo will end up in wrong search order, as
+ *   follows:
+ *     - The code makes use of following calls when asked to resolver with
+ *       ai_family  = PF_UNSPEC:
+ *             getipnodebyname(host, AF_INET6);
+ *             getipnodebyname(host, AF_INET);
+ *       This will result in the following queries if the node is configure to
+ *       prefer /etc/hosts than DNS:
+ *             lookup /etc/hosts for IPv6 address
+ *             lookup DNS for IPv6 address
+ *             lookup /etc/hosts for IPv4 address
+ *             lookup DNS for IPv4 address
+ *       which may not meet people's requirement.
+ *       The right thing to happen is to have underlying layer which does
+ *       PF_UNSPEC lookup (lookup both) and return chain of addrinfos.
+ *       This would result in a bit of code duplicate with _dns_ghbyname() and
+ *       friends.
+ */
+
+#define INET6
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <syslog.h>
+#include <stdarg.h>
+
+#ifdef YP
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#endif
+
+#include "kame.h"
+
+#define SUCCESS 0
+#define ANY 0
+#define YES 1
+#define NO  0
+
+static const char in_addrany[] = { 0, 0, 0, 0 };
+static const char in6_addrany[] = {
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+static const char in_loopback[] = { 127, 0, 0, 1 };
+static const char in6_loopback[] = {
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
+};
+
+struct sockinet {
+       u_char  si_len;
+       u_char  si_family;
+       u_short si_port;
+       u_int32_t si_scope_id;
+};
+
+static const struct afd {
+       int a_af;
+       int a_addrlen;
+       int a_socklen;
+       int a_off;
+       const char *a_addrany;
+       const char *a_loopback;
+       int a_scoped;
+} afdl [] = {
+#ifdef INET6
+       {PF_INET6, sizeof(struct in6_addr),
+        sizeof(struct sockaddr_in6),
+        offsetof(struct sockaddr_in6, sin6_addr),
+        in6_addrany, in6_loopback, 1},
+#endif
+       {PF_INET, sizeof(struct in_addr),
+        sizeof(struct sockaddr_in),
+        offsetof(struct sockaddr_in, sin_addr),
+        in_addrany, in_loopback, 0},
+       {0, 0, 0, 0, NULL, NULL, 0},
+};
+
+struct explore {
+       int e_af;
+       int e_socktype;
+       int e_protocol;
+       const char *e_protostr;
+       int e_wild;
+#define WILD_AF(ex)            ((ex)->e_wild & 0x01)
+#define WILD_SOCKTYPE(ex)      ((ex)->e_wild & 0x02)
+#define WILD_PROTOCOL(ex)      ((ex)->e_wild & 0x04)
+};
+
+static const struct explore explore[] = {
+#if 0
+       { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
+#endif
+#ifdef INET6
+       { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
+       { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
+       { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
+#endif
+       { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
+       { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
+       { PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
+       { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
+       { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
+       { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 },
+       { -1, 0, 0, NULL, 0 },
+};
+
+#ifdef INET6
+#define PTON_MAX       16
+#else
+#define PTON_MAX       4
+#endif
+
+#if PACKETSZ > 1024
+#define MAXPACKET      PACKETSZ
+#else
+#define MAXPACKET      1024
+#endif
+
+typedef union {
+       HEADER hdr;
+       u_char buf[MAXPACKET];
+} querybuf;
+
+struct res_target {
+       struct res_target *next;
+       const char *name;       /* domain name */
+       int class, type;        /* class and type of query */
+       u_char *answer;         /* buffer to put answer */
+       int anslen;             /* size of answer buffer */
+       int n;                  /* result length */
+};
+
+static int str_isnumber __P((const char *));
+static int explore_fqdn __P((const struct addrinfo *, const char *,
+       const char *, struct addrinfo **));
+static int explore_null __P((const struct addrinfo *,
+       const char *, struct addrinfo **));
+static int explore_numeric __P((const struct addrinfo *, const char *,
+       const char *, struct addrinfo **));
+static int explore_numeric_scope __P((const struct addrinfo *, const char *,
+       const char *, struct addrinfo **));
+static int get_canonname __P((const struct addrinfo *,
+       struct addrinfo *, const char *));
+static struct addrinfo *get_ai __P((const struct addrinfo *,
+       const struct afd *, const char *));
+static int get_portmatch __P((const struct addrinfo *, const char *));
+static int get_port __P((struct addrinfo *, const char *, int));
+static const struct afd *find_afd __P((int));
+#ifdef AI_ADDRCONFIG
+static int addrconfig __P((const struct addrinfo *));
+#endif
+#ifdef INET6
+static int ip6_str2scopeid __P((char *, struct sockaddr_in6 *));
+#endif
+
+static void _sethtent __P((void));
+static void _endhtent __P((void));
+static struct addrinfo * _gethtent __P((const char *, const struct addrinfo *));
+static struct addrinfo *_files_getaddrinfo __P((const char *,
+       const struct addrinfo *));
+
+#ifdef YP
+static struct addrinfo *_yphostent __P((char *, const struct addrinfo *));
+static struct addrinfo *_yp_getaddrinfo __P((const char *,
+       const struct addrinfo *));
+#endif
+
+static struct addrinfo *getanswer __P((const querybuf *, int, const char *, int,
+       const struct addrinfo *));
+static int res_queryN __P((const char *, struct res_target *));
+static int res_searchN __P((const char *, struct res_target *));
+static int res_querydomainN __P((const char *, const char *,
+       struct res_target *));
+static struct addrinfo *_dns_getaddrinfo __P((const char *,
+       const struct addrinfo *));
+
+
+/* XXX macros that make external reference is BAD. */
+
+#define GET_AI(ai, afd, addr) \
+do { \
+       /* external reference: pai, error, and label free */ \
+       (ai) = get_ai(pai, (afd), (addr)); \
+       if ((ai) == NULL) { \
+               error = EAI_MEMORY; \
+               goto free; \
+       } \
+} while (/*CONSTCOND*/0)
+
+#define GET_PORT(ai, serv) \
+do { \
+       /* external reference: error and label free */ \
+       error = get_port((ai), (serv), 0); \
+       if (error != 0) \
+               goto free; \
+} while (/*CONSTCOND*/0)
+
+#define GET_CANONNAME(ai, str) \
+do { \
+       /* external reference: pai, error and label free */ \
+       error = get_canonname(pai, (ai), (str)); \
+       if (error != 0) \
+               goto free; \
+} while (/*CONSTCOND*/0)
+
+#define ERR(err) \
+do { \
+       /* external reference: error, and label bad */ \
+       error = (err); \
+       goto bad; \
+} while (/*CONSTCOND*/0)
+
+#define MATCH_FAMILY(x, y, w) \
+       ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
+#define MATCH(x, y, w) \
+       ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
+
+static int
+str_isnumber(p)
+       const char *p;
+{
+       const char *q = (const char *)p;
+       while (*q) {
+               if (!isdigit(*q))
+                       return NO;
+               q++;
+       }
+       return YES;
+}
+
+int
+getaddrinfo(hostname, servname, hints, res)
+       const char *hostname, *servname;
+       const struct addrinfo *hints;
+       struct addrinfo **res;
+{
+       struct addrinfo sentinel;
+       struct addrinfo *cur;
+       int error = 0;
+       struct addrinfo ai;
+       struct addrinfo ai0;
+       struct addrinfo *pai;
+       const struct explore *ex;
+
+       memset(&sentinel, 0, sizeof(sentinel));
+       cur = &sentinel;
+       pai = &ai;
+       pai->ai_flags = 0;
+       pai->ai_family = PF_UNSPEC;
+       pai->ai_socktype = ANY;
+       pai->ai_protocol = ANY;
+       pai->ai_addrlen = 0;
+       pai->ai_canonname = NULL;
+       pai->ai_addr = NULL;
+       pai->ai_next = NULL;
+
+       if (hostname == NULL && servname == NULL)
+               return EAI_NONAME;
+       if (hints) {
+               /* error check for hints */
+               if (hints->ai_addrlen || hints->ai_canonname ||
+                   hints->ai_addr || hints->ai_next)
+                       ERR(EAI_BADHINTS); /* xxx */
+               if (hints->ai_flags & ~AI_MASK)
+                       ERR(EAI_BADFLAGS);
+               switch (hints->ai_family) {
+               case PF_UNSPEC:
+               case PF_INET:
+#ifdef INET6
+               case PF_INET6:
+#endif
+                       break;
+               default:
+                       ERR(EAI_FAMILY);
+               }
+               memcpy(pai, hints, sizeof(*pai));
+
+               /*
+                * if both socktype/protocol are specified, check if they
+                * are meaningful combination.
+                */
+               if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
+                       for (ex = explore; ex->e_af >= 0; ex++) {
+                               if (pai->ai_family != ex->e_af)
+                                       continue;
+                               if (ex->e_socktype == ANY)
+                                       continue;
+                               if (ex->e_protocol == ANY)
+                                       continue;
+                               if (pai->ai_socktype == ex->e_socktype
+                                && pai->ai_protocol != ex->e_protocol) {
+                                       ERR(EAI_BADHINTS);
+                               }
+                       }
+               }
+       }
+
+       /*
+        * check for special cases.  (1) numeric servname is disallowed if
+        * socktype/protocol are left unspecified. (2) servname is disallowed
+        * for raw and other inet{,6} sockets.
+        */
+       if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
+#ifdef PF_INET6
+        || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
+#endif
+           ) {
+               ai0 = *pai;     /* backup *pai */
+
+               if (pai->ai_family == PF_UNSPEC) {
+#ifdef PF_INET6
+                       pai->ai_family = PF_INET6;
+#else
+                       pai->ai_family = PF_INET;
+#endif
+               }
+               error = get_portmatch(pai, servname);
+               if (error)
+                       ERR(error);
+
+               *pai = ai0;
+       }
+
+       ai0 = *pai;
+
+       /* NULL hostname, or numeric hostname */
+       for (ex = explore; ex->e_af >= 0; ex++) {
+               *pai = ai0;
+
+               /* PF_UNSPEC entries are prepared for DNS queries only */
+               if (ex->e_af == PF_UNSPEC)
+                       continue;
+
+               if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
+                       continue;
+               if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
+                       continue;
+               if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
+                       continue;
+
+               if (pai->ai_family == PF_UNSPEC)
+                       pai->ai_family = ex->e_af;
+               if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
+                       pai->ai_socktype = ex->e_socktype;
+               if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
+                       pai->ai_protocol = ex->e_protocol;
+
+               if (hostname == NULL)
+                       error = explore_null(pai, servname, &cur->ai_next);
+               else
+                       error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next);
+
+               if (error)
+                       goto free;
+
+               while (cur && cur->ai_next)
+                       cur = cur->ai_next;
+       }
+
+       /*
+        * XXX
+        * If numreic representation of AF1 can be interpreted as FQDN
+        * representation of AF2, we need to think again about the code below.
+        */
+       if (sentinel.ai_next)
+               goto good;
+
+       if (pai->ai_flags & AI_NUMERICHOST)
+               ERR(EAI_NONAME);
+       if (hostname == NULL)
+               ERR(EAI_NONAME);
+
+       /*
+        * hostname as alphabetical name.
+        * we would like to prefer AF_INET6 than AF_INET, so we'll make a
+        * outer loop by AFs.
+        */
+       for (ex = explore; ex->e_af >= 0; ex++) {
+               *pai = ai0;
+
+               /* require exact match for family field */
+               if (pai->ai_family != ex->e_af)
+                       continue;
+
+               if (!MATCH(pai->ai_socktype, ex->e_socktype,
+                               WILD_SOCKTYPE(ex))) {
+                       continue;
+               }
+               if (!MATCH(pai->ai_protocol, ex->e_protocol,
+                               WILD_PROTOCOL(ex))) {
+                       continue;
+               }
+
+               if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
+                       pai->ai_socktype = ex->e_socktype;
+               if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
+                       pai->ai_protocol = ex->e_protocol;
+
+               error = explore_fqdn(pai, hostname, servname,
+                       &cur->ai_next);
+
+               while (cur && cur->ai_next)
+                       cur = cur->ai_next;
+       }
+
+       /* XXX */
+       if (sentinel.ai_next)
+               error = 0;
+
+       if (error)
+               goto free;
+       if (error == 0) {
+               if (sentinel.ai_next) {
+ good:
+                       *res = sentinel.ai_next;
+                       return SUCCESS;
+               } else
+                       error = EAI_FAIL;
+       }
+ free:
+ bad:
+       if (sentinel.ai_next)
+               freeaddrinfo(sentinel.ai_next);
+       *res = NULL;
+       return error;
+}
+
+/*
+ * FQDN hostname, DNS lookup
+ */
+static int
+explore_fqdn(pai, hostname, servname, res)
+       const struct addrinfo *pai;
+       const char *hostname;
+       const char *servname;
+       struct addrinfo **res;
+{
+       struct addrinfo *result;
+       struct addrinfo *cur;
+       int error = 0;
+       char lookups[MAXDNSLUS];
+       int i;
+
+       result = NULL;
+
+#ifdef AI_ADDRCONFIG
+       /*
+        * If AI_ADDRCONFIG is specified, check if we are expected to
+        * return the address family or not.
+        */
+       if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(pai))
+               return 0;
+#endif
+
+       /*
+        * if the servname does not match socktype/protocol, ignore it.
+        */
+       if (get_portmatch(pai, servname) != 0)
+               return 0;
+
+       if ((_res.options & RES_INIT) == 0 && res_init() == -1)
+               strncpy(lookups, "f", sizeof lookups);
+       else {
+               bcopy(_res.lookups, lookups, sizeof lookups);
+               if (lookups[0] == '\0')
+                       strncpy(lookups, "bf", sizeof lookups);
+       }
+
+       for (i = 0; i < MAXDNSLUS && result == NULL && lookups[i]; i++) {
+               switch (lookups[i]) {
+#ifdef YP
+               case 'y':
+                       result = _yp_getaddrinfo(hostname, pai);
+                       break;
+#endif
+               case 'b':
+                       result = _dns_getaddrinfo(hostname, pai);
+                       break;
+               case 'f':
+                       result = _files_getaddrinfo(hostname, pai);
+                       break;
+               }
+       }
+       if (result) {
+               for (cur = result; cur; cur = cur->ai_next) {
+                       GET_PORT(cur, servname);
+                       /* canonname should be filled already */
+               }
+               *res = result;
+               return 0;
+       }
+
+free:
+       if (result)
+               freeaddrinfo(result);
+       return error;
+}
+
+/*
+ * hostname == NULL.
+ * passive socket -> anyaddr (0.0.0.0 or ::)
+ * non-passive socket -> localhost (127.0.0.1 or ::1)
+ */
+static int
+explore_null(pai, servname, res)
+       const struct addrinfo *pai;
+       const char *servname;
+       struct addrinfo **res;
+{
+       int s;
+       const struct afd *afd;
+       struct addrinfo *cur;
+       struct addrinfo sentinel;
+       int error;
+
+       *res = NULL;
+       sentinel.ai_next = NULL;
+       cur = &sentinel;
+
+       /*
+        * filter out AFs that are not supported by the kernel
+        * XXX errno?
+        */
+       s = socket(pai->ai_family, SOCK_DGRAM, 0);
+       if (s < 0) {
+               if (errno != EMFILE)
+                       return 0;
+       } else
+               close(s);
+
+       /*
+        * if the servname does not match socktype/protocol, ignore it.
+        */
+       if (get_portmatch(pai, servname) != 0)
+               return 0;
+
+       afd = find_afd(pai->ai_family);
+
+       if (pai->ai_flags & AI_PASSIVE) {
+               GET_AI(cur->ai_next, afd, afd->a_addrany);
+               /* xxx meaningless?
+                * GET_CANONNAME(cur->ai_next, "anyaddr");
+                */
+               GET_PORT(cur->ai_next, servname);
+       } else {
+               GET_AI(cur->ai_next, afd, afd->a_loopback);
+               /* xxx meaningless?
+                * GET_CANONNAME(cur->ai_next, "localhost");
+                */
+               GET_PORT(cur->ai_next, servname);
+       }
+       cur = cur->ai_next;
+
+       *res = sentinel.ai_next;
+       return 0;
+
+free:
+       if (sentinel.ai_next)
+               freeaddrinfo(sentinel.ai_next);
+       return error;
+}
+
+/*
+ * numeric hostname
+ */
+static int
+explore_numeric(pai, hostname, servname, res)
+       const struct addrinfo *pai;
+       const char *hostname;
+       const char *servname;
+       struct addrinfo **res;
+{
+       const struct afd *afd;
+       struct addrinfo *cur;
+       struct addrinfo sentinel;
+       int error;
+       char pton[PTON_MAX];
+       int flags;
+
+       *res = NULL;
+       sentinel.ai_next = NULL;
+       cur = &sentinel;
+
+       /*
+        * if the servname does not match socktype/protocol, ignore it.
+        */
+       if (get_portmatch(pai, servname) != 0)
+               return 0;
+
+       afd = find_afd(pai->ai_family);
+       flags = pai->ai_flags;
+
+       switch (afd->a_af) {
+#if 0 /*X/Open spec*/
+       case AF_INET:
+               if (inet_aton(hostname, (struct in_addr *)pton) == 1) {
+                       if (pai->ai_family == afd->a_af ||
+                           pai->ai_family == PF_UNSPEC /*?*/) {
+                               GET_AI(cur->ai_next, afd, pton);
+                               GET_PORT(cur->ai_next, servname);
+                               while (cur && cur->ai_next)
+                                       cur = cur->ai_next;
+                       } else
+                               ERR(EAI_FAMILY);        /*xxx*/
+               }
+               break;
+#endif
+       default:
+               if (inet_pton(afd->a_af, hostname, pton) == 1) {
+                       if (pai->ai_family == afd->a_af ||
+                           pai->ai_family == PF_UNSPEC /*?*/) {
+                               GET_AI(cur->ai_next, afd, pton);
+                               GET_PORT(cur->ai_next, servname);
+                               while (cur && cur->ai_next)
+                                       cur = cur->ai_next;
+                       } else
+                               ERR(EAI_FAMILY);        /*xxx*/
+               }
+               break;
+       }
+
+       *res = sentinel.ai_next;
+       return 0;
+
+free:
+bad:
+       if (sentinel.ai_next)
+               freeaddrinfo(sentinel.ai_next);
+       return error;
+}
+
+/*
+ * numeric hostname with scope
+ */
+static int
+explore_numeric_scope(pai, hostname, servname, res)
+       const struct addrinfo *pai;
+       const char *hostname;
+       const char *servname;
+       struct addrinfo **res;
+{
+#if !defined(SCOPE_DELIMITER) || !defined(INET6)
+       return explore_numeric(pai, hostname, servname, res);
+#else
+       const struct afd *afd;
+       struct addrinfo *cur;
+       int error;
+       char *cp, *hostname2 = NULL, *scope, *addr;
+       struct sockaddr_in6 *sin6;
+
+       /*
+        * if the servname does not match socktype/protocol, ignore it.
+        */
+       if (get_portmatch(pai, servname) != 0)
+               return 0;
+
+       afd = find_afd(pai->ai_family);
+       if (!afd->a_scoped)
+               return explore_numeric(pai, hostname, servname, res);
+
+       cp = strchr(hostname, SCOPE_DELIMITER);
+       if (cp == NULL)
+               return explore_numeric(pai, hostname, servname, res);
+
+#if 0
+       /*
+        * Handle special case of <scope id><delimiter><scoped_address>
+        */
+       hostname2 = strdup(hostname);
+       if (hostname2 == NULL)
+               return EAI_MEMORY;
+       /* terminate at the delimiter */
+       hostname2[cp - hostname] = '\0';
+       scope = hostname2;
+       addr = cp + 1;
+#else
+       /*
+        * Handle special case of <scoped_address><delimiter><scope id>
+        */
+       hostname2 = strdup(hostname);
+       if (hostname2 == NULL)
+               return EAI_MEMORY;
+       /* terminate at the delimiter */
+       hostname2[cp - hostname] = '\0';
+       addr = hostname2;
+       scope = cp + 1;
+#endif
+
+       error = explore_numeric(pai, addr, servname, res);
+       if (error == 0) {
+               int scopeid;
+
+               for (cur = *res; cur; cur = cur->ai_next) {
+                       if (cur->ai_family != AF_INET6)
+                               continue;
+                       sin6 = (struct sockaddr_in6 *)cur->ai_addr;
+                       if ((scopeid = ip6_str2scopeid(scope, sin6)) == -1) {
+                               free(hostname2);
+                               return(EAI_NONAME); /* XXX: is return OK? */
+                       }
+                       sin6->sin6_scope_id = scopeid;
+               }
+       }
+
+       free(hostname2);
+
+       return error;
+#endif
+}
+
+static int
+get_canonname(pai, ai, str)
+       const struct addrinfo *pai;
+       struct addrinfo *ai;
+       const char *str;
+{
+       if ((pai->ai_flags & AI_CANONNAME) != 0) {
+               ai->ai_canonname = (char *)malloc(strlen(str) + 1);
+               if (ai->ai_canonname == NULL)
+                       return EAI_MEMORY;
+               strcpy(ai->ai_canonname, str);
+       }
+       return 0;
+}
+
+static struct addrinfo *
+get_ai(pai, afd, addr)
+       const struct addrinfo *pai;
+       const struct afd *afd;
+       const char *addr;
+{
+       char *p;
+       struct addrinfo *ai;
+
+       ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
+               + (afd->a_socklen));
+       if (ai == NULL)
+               return NULL;
+
+       memcpy(ai, pai, sizeof(struct addrinfo));
+       ai->ai_addr = (struct sockaddr *)(ai + 1);
+       memset(ai->ai_addr, 0, (size_t)afd->a_socklen);
+       ai->ai_addr->sa_len = afd->a_socklen;
+       ai->ai_addrlen = afd->a_socklen;
+       ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
+       p = (char *)(ai->ai_addr);
+       memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
+       return ai;
+}
+
+static int
+get_portmatch(ai, servname)
+       const struct addrinfo *ai;
+       const char *servname;
+{
+
+       /* get_port does not touch first argument. when matchonly == 1. */
+       return get_port((struct addrinfo *)ai, servname, 1);
+}
+
+static int
+get_port(ai, servname, matchonly)
+       struct addrinfo *ai;
+       const char *servname;
+       int matchonly;
+{
+       const char *proto;
+       struct servent *sp;
+       int port;
+       int allownumeric;
+
+       if (servname == NULL)
+               return 0;
+       switch (ai->ai_family) {
+       case AF_INET:
+#ifdef AF_INET6
+       case AF_INET6:
+#endif
+               break;
+       default:
+               return 0;
+       }
+
+       switch (ai->ai_socktype) {
+       case SOCK_RAW:
+               return EAI_SERVICE;
+       case SOCK_DGRAM:
+       case SOCK_STREAM:
+               allownumeric = 1;
+               break;
+       case ANY:
+               allownumeric = 0;
+               break;
+       default:
+               return EAI_SOCKTYPE;
+       }
+
+       if (str_isnumber(servname)) {
+               if (!allownumeric)
+                       return EAI_SERVICE;
+               port = htons(atoi(servname));
+               if (port < 0 || port > 65535)
+                       return EAI_SERVICE;
+       } else {
+               switch (ai->ai_socktype) {
+               case SOCK_DGRAM:
+                       proto = "udp";
+                       break;
+               case SOCK_STREAM:
+                       proto = "tcp";
+                       break;
+               default:
+                       proto = NULL;
+                       break;
+               }
+
+               if ((sp = getservbyname(servname, proto)) == NULL)
+                       return EAI_SERVICE;
+               port = sp->s_port;
+       }
+
+       if (!matchonly) {
+               switch (ai->ai_family) {
+               case AF_INET:
+                       ((struct sockaddr_in *)ai->ai_addr)->sin_port = port;
+                       break;
+#ifdef INET6
+               case AF_INET6:
+                       ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = port;
+                       break;
+#endif
+               }
+       }
+
+       return 0;
+}
+
+static const struct afd *
+find_afd(af)
+       int af;
+{
+       const struct afd *afd;
+
+       if (af == PF_UNSPEC)
+               return NULL;
+       for (afd = afdl; afd->a_af; afd++) {
+               if (afd->a_af == af)
+                       return afd;
+       }
+       return NULL;
+}
+
+#ifdef AI_ADDRCONFIG
+/*
+ * post-2553: AI_ADDRCONFIG check.  if we use getipnodeby* as backend, backend
+ * will take care of it.
+ * the semantics of AI_ADDRCONFIG is not defined well.  we are not sure
+ * if the code is right or not.
+ */
+static int
+addrconfig(pai)
+       const struct addrinfo *pai;
+{
+       int s;
+
+       /* XXX errno */
+       s = socket(pai->ai_family, SOCK_DGRAM, 0);
+       if (s < 0)
+               return 0;
+       close(s);
+       return 1;
+}
+#endif
+
+#ifdef INET6
+/* convert a string to a scope identifier. XXX: IPv6 specific */
+static int
+ip6_str2scopeid(scope, sin6)
+       char *scope;
+       struct sockaddr_in6 *sin6;
+{
+       int scopeid;
+       struct in6_addr *a6 = &sin6->sin6_addr;
+       char *ep;
+
+       if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) {
+               /*
+                * We currently assume a one-to-one mapping between links
+                * and interfaces, so we simply use interface indices for
+                * like-local scopes.
+                */
+               scopeid = if_nametoindex(scope);
+               if (scopeid == 0)
+                       goto trynumeric;
+               return(scopeid);
+       }
+
+       /* still unclear about literal, allow numeric only - placeholder */
+       if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
+               goto trynumeric;
+       if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
+               goto trynumeric;
+       else
+               goto trynumeric;        /* global */
+
+       /* try to convert to a numeric id as a last resort */
+  trynumeric:
+       scopeid = (int)strtoul(scope, &ep, 10);
+       if (*ep == '\0')
+               return scopeid;
+       else
+               return -1;
+}
+#endif
+
+/* code duplicate with gethnamaddr.c */
+
+static const char AskedForGot[] =
+       "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
+static FILE *hostf = NULL;
+
+static struct addrinfo *
+getanswer(answer, anslen, qname, qtype, pai)
+       const querybuf *answer;
+       int anslen;
+       const char *qname;
+       int qtype;
+       const struct addrinfo *pai;
+{
+       struct addrinfo sentinel, *cur;
+       struct addrinfo ai;
+       const struct afd *afd;
+       char *canonname;
+       const HEADER *hp;
+       const u_char *cp;
+       int n;
+       const u_char *eom;
+       char *bp;
+       int type, class, buflen, ancount, qdcount;
+       int haveanswer, had_error;
+       char tbuf[MAXDNAME];
+       const char *tname;
+       int (*name_ok) __P((const char *));
+       char hostbuf[8*1024];
+
+       memset(&sentinel, 0, sizeof(sentinel));
+       cur = &sentinel;
+
+       tname = qname;
+       canonname = NULL;
+       eom = answer->buf + anslen;
+       switch (qtype) {
+       case T_A:
+       case T_AAAA:
+       case T_ANY:     /*use T_ANY only for T_A/T_AAAA lookup*/
+               name_ok = res_hnok;
+               break;
+       default:
+               return (NULL);  /* XXX should be abort(); */
+       }
+       /*
+        * find first satisfactory answer
+        */
+       hp = &answer->hdr;
+       ancount = ntohs(hp->ancount);
+       qdcount = ntohs(hp->qdcount);
+       bp = hostbuf;
+       buflen = sizeof hostbuf;
+       cp = answer->buf + HFIXEDSZ;
+       if (qdcount != 1) {
+               h_errno = NO_RECOVERY;
+               return (NULL);
+       }
+       n = dn_expand(answer->buf, eom, cp, bp, buflen);
+       if ((n < 0) || !(*name_ok)(bp)) {
+               h_errno = NO_RECOVERY;
+               return (NULL);
+       }
+       cp += n + QFIXEDSZ;
+       if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) {
+               /* res_send() has already verified that the query name is the
+                * same as the one we sent; this just gets the expanded name
+                * (i.e., with the succeeding search-domain tacked on).
+                */
+               n = strlen(bp) + 1;             /* for the \0 */
+               if (n >= MAXHOSTNAMELEN) {
+                       h_errno = NO_RECOVERY;
+                       return (NULL);
+               }
+               canonname = bp;
+               bp += n;
+               buflen -= n;
+               /* The qname can be abbreviated, but h_name is now absolute. */
+               qname = canonname;
+       }
+       haveanswer = 0;
+       had_error = 0;
+       while (ancount-- > 0 && cp < eom && !had_error) {
+               n = dn_expand(answer->buf, eom, cp, bp, buflen);
+               if ((n < 0) || !(*name_ok)(bp)) {
+                       had_error++;
+                       continue;
+               }
+               cp += n;                        /* name */
+               type = _getshort(cp);
+               cp += INT16SZ;                  /* type */
+               class = _getshort(cp);
+               cp += INT16SZ + INT32SZ;        /* class, TTL */
+               n = _getshort(cp);
+               cp += INT16SZ;                  /* len */
+               if (class != C_IN) {
+                       /* XXX - debug? syslog? */
+                       cp += n;
+                       continue;               /* XXX - had_error++ ? */
+               }
+               if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) &&
+                   type == T_CNAME) {
+                       n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
+                       if ((n < 0) || !(*name_ok)(tbuf)) {
+                               had_error++;
+                               continue;
+                       }
+                       cp += n;
+                       /* Get canonical name. */
+                       n = strlen(tbuf) + 1;   /* for the \0 */
+                       if (n > buflen || n >= MAXHOSTNAMELEN) {
+                               had_error++;
+                               continue;
+                       }
+                       strcpy(bp, tbuf);
+                       canonname = bp;
+                       bp += n;
+                       buflen -= n;
+                       continue;
+               }
+               if (qtype == T_ANY) {
+                       if (!(type == T_A || type == T_AAAA)) {
+                               cp += n;
+                               continue;
+                       }
+               } else if (type != qtype) {
+                       if (type != T_KEY && type != T_SIG)
+                               syslog(LOG_NOTICE|LOG_AUTH,
+              "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
+                                      qname, p_class(C_IN), p_type(qtype),
+                                      p_type(type));
+                       cp += n;
+                       continue;               /* XXX - had_error++ ? */
+               }
+               switch (type) {
+               case T_A:
+               case T_AAAA:
+                       if (strcasecmp(canonname, bp) != 0) {
+                               syslog(LOG_NOTICE|LOG_AUTH,
+                                      AskedForGot, canonname, bp);
+                               cp += n;
+                               continue;       /* XXX - had_error++ ? */
+                       }
+                       if (type == T_A && n != INADDRSZ) {
+                               cp += n;
+                               continue;
+                       }
+                       if (type == T_AAAA && n != IN6ADDRSZ) {
+                               cp += n;
+                               continue;
+                       }
+                       if (!haveanswer) {
+                               int nn;
+
+                               canonname = bp;
+                               nn = strlen(bp) + 1;    /* for the \0 */
+                               bp += nn;
+                               buflen -= nn;
+                       }
+
+                       /* don't overwrite pai */
+                       ai = *pai;
+                       ai.ai_family = (type == T_A) ? AF_INET : AF_INET6;
+                       afd = find_afd(ai.ai_family);
+                       if (afd == NULL) {
+                               cp += n;
+                               continue;
+                       }
+                       cur->ai_next = get_ai(&ai, afd, cp);
+                       if (cur->ai_next == NULL)
+                               had_error++;
+                       while (cur && cur->ai_next)
+                               cur = cur->ai_next;
+                       cp += n;
+                       break;
+               default:
+                       abort();
+               }
+               if (!had_error)
+                       haveanswer++;
+       }
+       if (haveanswer) {
+               if (!canonname)
+                       (void)get_canonname(pai, sentinel.ai_next, qname);
+               else
+                       (void)get_canonname(pai, sentinel.ai_next, canonname);
+               h_errno = NETDB_SUCCESS;
+               return sentinel.ai_next;
+       }
+
+       h_errno = NO_RECOVERY;
+       return NULL;
+}
+
+/*ARGSUSED*/
+static struct addrinfo *
+_dns_getaddrinfo(name, pai)
+       const char *name;
+       const struct addrinfo *pai;
+{
+       struct addrinfo *ai;
+       querybuf buf, buf2;
+       struct addrinfo sentinel, *cur;
+       struct res_target q, q2;
+       int ancount;
+
+       memset(&q, 0, sizeof(q2));
+       memset(&q2, 0, sizeof(q2));
+       memset(&sentinel, 0, sizeof(sentinel));
+       cur = &sentinel;
+
+       switch (pai->ai_family) {
+       case AF_UNSPEC:
+               /* prefer IPv6 */
+               q.class = C_IN;
+               q.type = T_AAAA;
+               q.answer = buf.buf;
+               q.anslen = sizeof(buf);
+               q.next = &q2;
+               q2.class = C_IN;
+               q2.type = T_A;
+               q2.answer = buf2.buf;
+               q2.anslen = sizeof(buf2);
+               break;
+       case AF_INET:
+               q.class = C_IN;
+               q.type = T_A;
+               q.answer = buf.buf;
+               q.anslen = sizeof(buf);
+               break;
+       case AF_INET6:
+               q.class = C_IN;
+               q.type = T_AAAA;
+               q.answer = buf.buf;
+               q.anslen = sizeof(buf);
+               break;
+       default:
+               return NULL;
+       }
+       if ((ancount = res_searchN(name, &q)) < 0)
+               return NULL;
+       ai = getanswer(&buf, q.n, q.name, q.type, pai);
+       if (ai) {
+               cur->ai_next = ai;
+               while (cur && cur->ai_next)
+                       cur = cur->ai_next;
+       }
+       if (q.next) {
+               ai = getanswer(&buf2, q2.n, q2.name, q2.type, pai);
+               if (ai)
+                       cur->ai_next = ai;
+       }
+       return sentinel.ai_next;
+}
+
+static FILE *hostf;
+
+static void
+_sethtent()
+{
+       if (!hostf)
+               hostf = fopen(_PATH_HOSTS, "r" );
+       else
+               rewind(hostf);
+}
+
+static void
+_endhtent()
+{
+       if (hostf) {
+               (void) fclose(hostf);
+               hostf = NULL;
+       }
+}
+
+static struct addrinfo *
+_gethtent(name, pai)
+       const char *name;
+       const struct addrinfo *pai;
+{
+       char *p;
+       char *cp, *tname;
+       struct addrinfo hints, *res0, *res;
+       int error;
+       const char *addr;
+       char hostbuf[8*1024];
+
+       if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" )))
+               return (NULL);
+ again:
+       if (!(p = fgets(hostbuf, sizeof hostbuf, hostf)))
+               return (NULL);
+       if (*p == '#')
+               goto again;
+       if (!(cp = strpbrk(p, "#\n")))
+               goto again;
+       *cp = '\0';
+       if (!(cp = strpbrk(p, " \t")))
+               goto again;
+       *cp++ = '\0';
+       addr = p;
+       /* if this is not something we're looking for, skip it. */
+       while (cp && *cp) {
+               if (*cp == ' ' || *cp == '\t') {
+                       cp++;
+                       continue;
+               }
+               tname = cp;
+               if ((cp = strpbrk(cp, " \t")) != NULL)
+                       *cp++ = '\0';
+               if (strcasecmp(name, tname) == 0)
+                       goto found;
+       }
+       goto again;
+
+found:
+       hints = *pai;
+       hints.ai_flags = AI_NUMERICHOST;
+       error = getaddrinfo(addr, NULL, &hints, &res0);
+       if (error)
+               goto again;
+       for (res = res0; res; res = res->ai_next) {
+               /* cover it up */
+               res->ai_flags = pai->ai_flags;
+
+               if (pai->ai_flags & AI_CANONNAME) {
+                       if (get_canonname(pai, res, name) != 0) {
+                               freeaddrinfo(res0);
+                               goto again;
+                       }
+               }
+       }
+       return res0;
+}
+
+/*ARGSUSED*/
+static struct addrinfo *
+_files_getaddrinfo(name, pai)
+       const char *name;
+       const struct addrinfo *pai;
+{
+       struct addrinfo sentinel, *cur;
+       struct addrinfo *p;
+
+       memset(&sentinel, 0, sizeof(sentinel));
+       cur = &sentinel;
+
+       _sethtent();
+       while ((p = _gethtent(name, pai)) != NULL) {
+               cur->ai_next = p;
+               while (cur && cur->ai_next)
+                       cur = cur->ai_next;
+       }
+       _endhtent();
+
+       return sentinel.ai_next;
+}
+
+#ifdef YP
+static char *__ypdomain;
+
+/*ARGSUSED*/
+static struct addrinfo *
+_yphostent(line, pai)
+       char *line;
+       const struct addrinfo *pai;
+{
+       struct addrinfo sentinel, *cur;
+       struct addrinfo hints, *res, *res0;
+       int error;
+       char *p = line;
+       const char *addr, *canonname;
+       char *nextline;
+       char *cp;
+       int more;
+
+       addr = canonname = NULL;
+
+nextline:
+       more = 0;
+
+       /* terminate line */
+       cp = strchr(p, '\n');
+       if (cp) {
+               *cp++ = '\0';
+               nextline = cp;
+       } else
+               nextline = NULL;
+
+       cp = strpbrk(p, " \t");
+       if (cp == NULL) {
+               if (canonname == NULL)
+                       return (NULL);
+               else
+                       goto done;
+       }
+       *cp++ = '\0';
+
+       addr = p;
+
+       while (cp && *cp) {
+               if (*cp == ' ' || *cp == '\t') {
+                       cp++;
+                       continue;
+               }
+               if (!canonname)
+                       canonname = cp;
+               if ((cp = strpbrk(cp, " \t")) != NULL)
+                       *cp++ = '\0';
+       }
+
+       hints = *pai;
+       hints.ai_flags = AI_NUMERICHOST;
+       error = getaddrinfo(addr, NULL, &hints, &res0);
+       if (error == 0) {
+               for (res = res0; res; res = res->ai_next) {
+                       /* cover it up */
+                       res->ai_flags = pai->ai_flags;
+
+                       if (pai->ai_flags & AI_CANONNAME)
+                               (void)get_canonname(pai, res, canonname);
+               }
+       }
+       if (res0) {
+               cur->ai_next = res0;
+               while (cur && cur->ai_next)
+                       cur = cur->ai_next;
+       }
+
+       if (nextline) {
+               p = nextline;
+               goto nextline;
+       }
+
+done:
+       return sentinel.ai_next;
+}
+
+/*ARGSUSED*/
+static struct addrinfo *
+_yp_getaddrinfo(name, pai)
+       const char *name;
+       const struct addrinfo *pai;
+{
+       struct addrinfo sentinel, *cur;
+       struct addrinfo *ai = NULL;
+       static char *__ypcurrent;
+       int __ypcurrentlen, r;
+
+       memset(&sentinel, 0, sizeof(sentinel));
+       cur = &sentinel;
+
+       if (!__ypdomain) {
+               if (_yp_check(&__ypdomain) == 0)
+                       return NULL;
+       }
+       if (__ypcurrent)
+               free(__ypcurrent);
+       __ypcurrent = NULL;
+
+       /* hosts.byname is only for IPv4 (Solaris8) */
+       if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) {
+               r = yp_match(__ypdomain, "hosts.byname", name,
+                       (int)strlen(name), &__ypcurrent, &__ypcurrentlen);
+               if (r == 0) {
+                       struct addrinfo ai4;
+
+                       ai4 = *pai;
+                       ai4.ai_family = AF_INET;
+                       ai = _yphostent(__ypcurrent, &ai4);
+                       if (ai) {
+                               cur->ai_next = ai;
+                               while (cur && cur->ai_next)
+                                       cur = cur->ai_next;
+                       }
+               }
+       }
+
+       /* ipnodes.byname can hold both IPv4/v6 */
+       r = yp_match(__ypdomain, "ipnodes.byname", name,
+               (int)strlen(name), &__ypcurrent, &__ypcurrentlen);
+       if (r == 0) {
+               ai = _yphostent(__ypcurrent, pai);
+               if (ai) {
+                       cur->ai_next = ai;
+                       while (cur && cur->ai_next)
+                               cur = cur->ai_next;
+               }
+       }
+
+       return sentinel.ai_next;
+}
+#endif
+
+
+/* resolver logic */
+
+extern const char *__hostalias __P((const char *));
+extern int h_errno;
+
+/*
+ * 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.
+ */
+static int
+res_queryN(name, target)
+       const char *name;       /* domain name */
+       struct res_target *target;
+{
+       u_char buf[MAXPACKET];
+       HEADER *hp;
+       int n;
+       struct res_target *t;
+       int rcode;
+       int ancount;
+
+       rcode = NOERROR;
+       ancount = 0;
+
+       if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+               h_errno = NETDB_INTERNAL;
+               return (-1);
+       }
+
+       for (t = target; t; t = t->next) {
+               int class, type;
+               u_char *answer;
+               int anslen;
+
+               hp = (HEADER *)(void *)t->answer;
+               hp->rcode = NOERROR;    /* default */
+
+               /* make it easier... */
+               class = t->class;
+               type = t->type;
+               answer = t->answer;
+               anslen = t->anslen;
+#ifdef DEBUG
+               if (_res.options & RES_DEBUG)
+                       printf(";; res_query(%s, %d, %d)\n", name, class, type);
+#endif
+
+               n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL,
+                   buf, sizeof(buf));
+               if (n <= 0) {
+#ifdef DEBUG
+                       if (_res.options & RES_DEBUG)
+                               printf(";; res_query: mkquery failed\n");
+#endif
+                       h_errno = NO_RECOVERY;
+                       return (n);
+               }
+               n = res_send(buf, n, answer, anslen);
+               if (n < 0) {
+#ifdef DEBUG
+                       if (_res.options & RES_DEBUG)
+                               printf(";; res_query: send error\n");
+#endif
+                       h_errno = TRY_AGAIN;
+                       return (n);
+               }
+
+               if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
+                       rcode = hp->rcode;      /* record most recent error */
+#ifdef DEBUG
+                       if (_res.options & RES_DEBUG)
+                               printf(";; rcode = %d, ancount=%d\n", hp->rcode,
+                                   ntohs(hp->ancount));
+#endif
+                       continue;
+               }
+
+               ancount += ntohs(hp->ancount);
+
+               t->n = n;
+       }
+
+       if (ancount == 0) {
+               switch (rcode) {
+               case NXDOMAIN:
+                       h_errno = HOST_NOT_FOUND;
+                       break;
+               case SERVFAIL:
+                       h_errno = TRY_AGAIN;
+                       break;
+               case NOERROR:
+                       h_errno = NO_DATA;
+                       break;
+               case FORMERR:
+               case NOTIMP:
+               case REFUSED:
+               default:
+                       h_errno = NO_RECOVERY;
+                       break;
+               }
+               return (-1);
+       }
+       return (ancount);
+}
+
+/*
+ * 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.
+ */
+static int
+res_searchN(name, target)
+       const char *name;       /* domain name */
+       struct res_target *target;
+{
+       const char *cp, * const *domain;
+       HEADER *hp = (HEADER *)(void *)target->answer;  /*XXX*/
+       u_int dots;
+       int trailing_dot, ret, saved_herrno;
+       int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
+
+       if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+               h_errno = NETDB_INTERNAL;
+               return (-1);
+       }
+
+       errno = 0;
+       h_errno = HOST_NOT_FOUND;       /* default, if we never query */
+       dots = 0;
+       for (cp = name; *cp; 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 = __hostalias(name)) != NULL)
+               return (res_queryN(cp, target));
+
+       /*
+        * If there are dots in the name already, let's just give it a try
+        * 'as is'.  The threshold can be set with the "ndots" option.
+        */
+       saved_herrno = -1;
+       if (dots >= _res.ndots) {
+               ret = res_querydomainN(name, NULL, target);
+               if (ret > 0)
+                       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 && (_res.options & RES_DEFNAMES)) ||
+           (dots && !trailing_dot && (_res.options & RES_DNSRCH))) {
+               int done = 0;
+
+               for (domain = (const char * const *)_res.dnsrch;
+                  *domain && !done;
+                  domain++) {
+
+                       ret = res_querydomainN(name, *domain, target);
+                       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 = TRY_AGAIN;
+                               return (-1);
+                       }
+
+                       switch (h_errno) {
+                       case NO_DATA:
+                               got_nodata++;
+                               /* FALLTHROUGH */
+                       case HOST_NOT_FOUND:
+                               /* keep trying */
+                               break;
+                       case TRY_AGAIN:
+                               if (hp->rcode == SERVFAIL) {
+                                       /* 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 (!(_res.options & RES_DNSRCH))
+                               done++;
+               }
+       }
+
+       /*
+        * if we have not already tried the name "as is", do that now.
+        * note that we do this regardless of how many dots were in the
+        * name or whether it ends with a dot.
+        */
+       if (!tried_as_is) {
+               ret = res_querydomainN(name, NULL, target);
+               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 = saved_herrno;
+       else if (got_nodata)
+               h_errno = NO_DATA;
+       else if (got_servfail)
+               h_errno = TRY_AGAIN;
+       return (-1);
+}
+
+/*
+ * Perform a call on res_query on the concatenation of name and domain,
+ * removing a trailing dot from name if domain is NULL.
+ */
+static int
+res_querydomainN(name, domain, target)
+       const char *name, *domain;
+       struct res_target *target;
+{
+       char nbuf[MAXDNAME];
+       const char *longname = nbuf;
+       size_t n, d;
+
+       if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+               h_errno = NETDB_INTERNAL;
+               return (-1);
+       }
+#ifdef DEBUG
+       if (_res.options & RES_DEBUG)
+               printf(";; res_querydomain(%s, %s)\n",
+                       name, domain?domain:"<Nil>");
+#endif
+       if (domain == NULL) {
+               /*
+                * Check for trailing '.';
+                * copy without '.' if present.
+                */
+               n = strlen(name);
+               if (n >= MAXDNAME) {
+                       h_errno = NO_RECOVERY;
+                       return (-1);
+               }
+               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 >= MAXDNAME) {
+                       h_errno = NO_RECOVERY;
+                       return (-1);
+               }
+               sprintf(nbuf, "%s.%s", name, domain);
+       }
+       return (res_queryN(longname, target));
+}
diff -urN ssh-old/getnameinfo.c ssh/getnameinfo.c
--- ssh-old/getnameinfo.c       Wed Dec 31 17:00:00 1969
+++ ssh/getnameinfo.c   Thu Jun  8 11:20:23 2000
@@ -0,0 +1,319 @@
+/*     $OpenBSD: openbsd26_1.2.3.patch,v 1.1 2000/03/06 21:38:08 deraadt Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * 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. Neither the name of the project 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 PROJECT 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 PROJECT 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.
+ */
+
+/*
+ * Issues to be discussed:
+ * - Thread safe-ness must be checked
+ * - Return values.  There seems to be no standard for return value (RFC2553)
+ *   but INRIA implementation returns EAI_xxx defined for getaddrinfo().
+ * - RFC2553 says that we should raise error on short buffer.  X/Open says
+ *   we need to truncate the result.  We obey RFC2553 (and X/Open should be
+ *   modified).
+ */
+
+#define INET6
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <string.h>
+#include <stddef.h>
+
+#define SUCCESS 0
+#define ANY 0
+#define YES 1
+#define NO  0
+
+static struct afd {
+       int a_af;
+       int a_addrlen;
+       int a_socklen;
+       int a_off;
+} afdl [] = {
+#ifdef INET6
+       {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
+               offsetof(struct sockaddr_in6, sin6_addr)},
+#endif
+       {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
+               offsetof(struct sockaddr_in, sin_addr)},
+       {0, 0, 0},
+};
+
+struct sockinet {
+       u_char  si_len;
+       u_char  si_family;
+       u_short si_port;
+};
+
+#ifdef INET6
+static char *ip6_sa2str __P((struct sockaddr_in6 *, char *, int));
+#endif
+
+#define ENI_NOSOCKET   0
+#define ENI_NOSERVNAME 1
+#define ENI_NOHOSTNAME 2
+#define ENI_MEMORY     3
+#define ENI_SYSTEM     4
+#define ENI_FAMILY     5
+#define ENI_SALEN      6
+
+int
+getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
+       const struct sockaddr *sa;
+       size_t salen;
+       char *host;
+       size_t hostlen;
+       char *serv;
+       size_t servlen;
+       int flags;
+{
+       struct afd *afd;
+       struct servent *sp;
+       struct hostent *hp;
+       u_short port;
+       int family, i;
+       char *addr, *p;
+       u_int32_t v4a;
+       int h_error;
+       char numserv[512];
+       char numaddr[512];
+
+       if (sa == NULL)
+               return ENI_NOSOCKET;
+
+       if (sa->sa_len != salen)
+               return ENI_SALEN;
+
+       family = sa->sa_family;
+       for (i = 0; afdl[i].a_af; i++)
+               if (afdl[i].a_af == family) {
+                       afd = &afdl[i];
+                       goto found;
+               }
+       return ENI_FAMILY;
+
+ found:
+       if (salen != afd->a_socklen)
+               return ENI_SALEN;
+
+       port = ((struct sockinet *)sa)->si_port; /* network byte order */
+       addr = (char *)sa + afd->a_off;
+
+       if (serv == NULL || servlen == 0) {
+               /*
+                * do nothing in this case.
+                * in case you are wondering if "&&" is more correct than
+                * "||" here: RFC2553 says that serv == NULL OR servlen == 0
+                * means that the caller does not want the result.
+                */
+       } else {
+               if (flags & NI_NUMERICSERV)
+                       sp = NULL;
+               else {
+                       sp = getservbyport(port,
+                               (flags & NI_DGRAM) ? "udp" : "tcp");
+               }
+               if (sp) {
+                       if (strlen(sp->s_name) > servlen)
+                               return ENI_MEMORY;
+                       strcpy(serv, sp->s_name);
+               } else {
+                       snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
+                       if (strlen(numserv) > servlen)
+                               return ENI_MEMORY;
+                       strcpy(serv, numserv);
+               }
+       }
+
+       switch (sa->sa_family) {
+       case AF_INET:
+               v4a = (u_int32_t)
+                       ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
+               if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
+                       flags |= NI_NUMERICHOST;
+               v4a >>= IN_CLASSA_NSHIFT;
+               if (v4a == 0)
+                       flags |= NI_NUMERICHOST;
+               break;
+#ifdef INET6
+       case AF_INET6:
+           {
+               struct sockaddr_in6 *sin6;
+               sin6 = (struct sockaddr_in6 *)sa;
+               switch (sin6->sin6_addr.s6_addr[0]) {
+               case 0x00:
+                       if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
+                               ;
+                       else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
+                               ;
+                       else
+                               flags |= NI_NUMERICHOST;
+                       break;
+               default:
+                       if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
+                               flags |= NI_NUMERICHOST;
+                       }
+                       else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
+                               flags |= NI_NUMERICHOST;
+                       break;
+               }
+           }
+               break;
+#endif
+       }
+       if (host == NULL || hostlen == 0) {
+               /*
+                * do nothing in this case.
+                * in case you are wondering if "&&" is more correct than
+                * "||" here: RFC2553 says that host == NULL OR hostlen == 0
+                * means that the caller does not want the result.
+                */
+       } else if (flags & NI_NUMERICHOST) {
+               int numaddrlen;
+
+               /* NUMERICHOST and NAMEREQD conflicts with each other */
+               if (flags & NI_NAMEREQD)
+                       return ENI_NOHOSTNAME;
+               if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
+                   == NULL)
+                       return ENI_SYSTEM;
+               numaddrlen = strlen(numaddr);
+               if (numaddrlen + 1 > hostlen) /* don't forget terminator */
+                       return ENI_MEMORY;
+               strcpy(host, numaddr);
+#if defined(INET6) && defined(NI_WITHSCOPEID)
+               if (afd->a_af == AF_INET6 &&
+                   (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr) ||
+                    IN6_IS_ADDR_MULTICAST((struct in6_addr *)addr)) &&
+                   ((struct sockaddr_in6 *)sa)->sin6_scope_id) {
+#ifndef ALWAYS_WITHSCOPE
+                       if (flags & NI_WITHSCOPEID)
+#endif /* !ALWAYS_WITHSCOPE */
+                       {
+                               char scopebuf[MAXHOSTNAMELEN], *s;
+                               int scopelen;
+
+                               if ((s = ip6_sa2str((struct sockaddr_in6 *)sa,
+                                                   scopebuf, 0)) == NULL)
+                                       /* XXX what should we do? */
+                                       strcpy(scopebuf, "0");
+
+                               scopelen = strlen(scopebuf);
+                               if (scopelen + 1 + numaddrlen + 1 > hostlen)
+                                       return ENI_MEMORY;
+
+#if 0
+                               /*
+                                * construct <scopeid><delim><numeric-addr>
+                                */
+                               /*
+                                * Shift the host string to allocate
+                                * space for the scope ID part.
+                                */
+                               memmove(host + scopelen + 1, host,
+                                       numaddrlen);
+                               /* copy the scope ID and the delimiter */
+                               memcpy(host, scopebuf, scopelen);
+                               host[scopelen] = SCOPE_DELIMITER;
+                               host[scopelen + 1 + numaddrlen] = '\0';
+#else
+                               /*
+                                * construct <numeric-addr><delim><scopeid>
+                                */
+                               memcpy(host + numaddrlen + 1, scopebuf,
+                                   scopelen);
+                               host[numaddrlen] = SCOPE_DELIMITER;
+                               host[numaddrlen + 1 + scopelen] = '\0';
+#endif
+                       }
+               }
+#endif /* INET6 */
+       } else {
+               hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
+               h_error = h_errno;
+
+               if (hp) {
+                       if (flags & NI_NOFQDN) {
+                               p = strchr(hp->h_name, '.');
+                               if (p) *p = '\0';
+                       }
+                       if (strlen(hp->h_name) > hostlen) {
+                               return ENI_MEMORY;
+                       }
+                       strcpy(host, hp->h_name);
+               } else {
+                       if (flags & NI_NAMEREQD)
+                               return ENI_NOHOSTNAME;
+                       if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
+                           == NULL)
+                               return ENI_NOHOSTNAME;
+                       if (strlen(numaddr) > hostlen)
+                               return ENI_MEMORY;
+                       strcpy(host, numaddr);
+               }
+       }
+       return SUCCESS;
+}
+
+#ifdef INET6
+/* ARGSUSED */
+static char *
+ip6_sa2str(sa6, buf, flags)
+       struct sockaddr_in6 *sa6;
+       char *buf;
+       int flags;
+{
+       unsigned int ifindex = (unsigned int)sa6->sin6_scope_id;
+       struct in6_addr *a6 = &sa6->sin6_addr;
+
+#ifdef notyet
+       if (flags & NI_NUMERICSCOPE) {
+               sprintf(buf, "%d", sa6->sin6_scope_id);
+               return(buf);
+       }
+#endif
+
+       if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6))
+               return(if_indextoname(ifindex, buf));
+
+       if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
+               return(NULL);   /* XXX */
+       if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
+               return(NULL);   /* XXX */
+
+       return(NULL);           /* XXX */
+}
+#endif
diff -urN ssh-old/includes.h ssh/includes.h
--- ssh-old/includes.h  Thu Jun  8 11:20:04 2000
+++ ssh/includes.h      Thu Jun  8 11:20:23 2000
@@ -55,6 +55,8 @@
#include <paths.h>
#include <dirent.h>

+#include "kame.h"
+
#include "version.h"

/* Define this to be the path of the xauth program. */
diff -urN ssh-old/kame.h ssh/kame.h
--- ssh-old/kame.h      Wed Dec 31 17:00:00 1969
+++ ssh/kame.h  Thu Jun  8 11:20:23 2000
@@ -0,0 +1,9 @@
+/* defines from OpenBSD-current */
+
+#define AI_MASK                (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST)
+#define EAI_BADHINTS   -12     /* invalid value for hints */
+#define EAI_PROTOCOL   -13     /* resolved protocol is unknown */
+
+#ifdef freeaddrinfo
+#undef freeaddrinfo
+#endif
diff -urN ssh-old/lib/Makefile ssh/lib/Makefile
--- ssh-old/lib/Makefile        Thu Jun  8 11:20:03 2000
+++ ssh/lib/Makefile    Thu Jun  8 11:20:23 2000
@@ -7,6 +7,8 @@
       rsa.c tildexpand.c ttymodes.c uidswap.c xmalloc.c atomicio.c \
       key.c dispatch.c dsa.c kex.c hmac.c uuencode.c aux.c

+SRCS+= getaddrinfo.c getnameinfo.c freeaddrinfo.c gai_strerror.c
+
NOPROFILE= yes
NOPIC= yes

diff -urN ssh-old/sshconnect.c ssh/sshconnect.c
--- ssh-old/sshconnect.c        Thu Jun  8 11:20:05 2000
+++ ssh/sshconnect.c    Thu Jun  8 11:20:23 2000
@@ -146,7 +146,9 @@
        */
       if (privileged) {
               int p = IPPORT_RESERVED - 1;
-               sock = rresvport_af(&p, family);
+               if (family != AF_INET)
+                       return -1;
+               sock = rresvport(&p);
               if (sock < 0)
                       error("rresvport: af=%d %.100s", family, strerror(errno));
               else