1968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
2968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold/* Copyright 2005 by Dominick Meglio
3968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold *
4968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * Permission to use, copy, modify, and distribute this
5968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * software and its documentation for any purpose and without
6968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * fee is hereby granted, provided that the above copyright
7968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * notice appear in all copies and that both that copyright
8968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * notice and this permission notice appear in supporting
9968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * documentation, and that the name of M.I.T. not be used in
10968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * advertising or publicity pertaining to distribution of the
11968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * software without specific, written prior permission.
12968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * M.I.T. makes no representations about the suitability of
13968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * this software for any purpose.  It is provided "as is"
14968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * without express or implied warranty.
15968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold */
16968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#include "ares_setup.h"
17968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
18968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_GETSERVBYPORT_R
19968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#  if !defined(GETSERVBYPORT_R_ARGS) || \
20968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold     (GETSERVBYPORT_R_ARGS < 4) || (GETSERVBYPORT_R_ARGS > 6)
21968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#    error "you MUST specifiy a valid number of arguments for getservbyport_r"
22968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#  endif
23968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
24968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
25968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_SYS_SOCKET_H
26968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#  include <sys/socket.h>
27968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
28968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_NETINET_IN_H
29968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#  include <netinet/in.h>
30968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
31968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_NETDB_H
32968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#  include <netdb.h>
33968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
34968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_ARPA_INET_H
35968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#  include <arpa/inet.h>
36968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
37968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_ARPA_NAMESER_H
38968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#  include <arpa/nameser.h>
39968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#else
40968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#  include "nameser.h"
41968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
42968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_ARPA_NAMESER_COMPAT_H
43968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#  include <arpa/nameser_compat.h>
44968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
45968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
46968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_NET_IF_H
47968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#include <net/if.h>
48968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
49968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
50968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_UNISTD_H
51968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#include <unistd.h>
52968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
53968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
54968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#include <stdio.h>
55968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#include <stdlib.h>
56968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#include <string.h>
57968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
58968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#include "ares.h"
59968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#include "ares_ipv6.h"
60968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#include "inet_ntop.h"
61968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#include "ares_nowarn.h"
62968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#include "ares_private.h"
63968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
64968bf19396ad404e89420f5d67900fce13f4186cGilad Arnoldstruct nameinfo_query {
65968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  ares_nameinfo_callback callback;
66968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  void *arg;
67968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  union {
68968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    struct sockaddr_in addr4;
69968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    struct sockaddr_in6 addr6;
70968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  } addr;
71968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  int family;
72968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  int flags;
73968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  int timeouts;
74968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold};
75968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
76968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
77968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#define IPBUFSIZ \
78968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") + IF_NAMESIZE)
79968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#else
80968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#define IPBUFSIZ \
81968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"))
82968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
83968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
84968bf19396ad404e89420f5d67900fce13f4186cGilad Arnoldstatic void nameinfo_callback(void *arg, int status, int timeouts,
85968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                              struct hostent *host);
86968bf19396ad404e89420f5d67900fce13f4186cGilad Arnoldstatic char *lookup_service(unsigned short port, int flags,
87968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                            char *buf, size_t buflen);
88968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
89968bf19396ad404e89420f5d67900fce13f4186cGilad Arnoldstatic void append_scopeid(struct sockaddr_in6 *addr6, unsigned int scopeid,
90968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                           char *buf, size_t buflen);
91968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
92968bf19396ad404e89420f5d67900fce13f4186cGilad Arnoldstatic char *ares_striendstr(const char *s1, const char *s2);
93968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
94968bf19396ad404e89420f5d67900fce13f4186cGilad Arnoldvoid ares_getnameinfo(ares_channel channel, const struct sockaddr *sa,
95968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                      ares_socklen_t salen,
96968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                      int flags, ares_nameinfo_callback callback, void *arg)
97968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold{
98968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  struct sockaddr_in *addr = NULL;
99968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  struct sockaddr_in6 *addr6 = NULL;
100968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  struct nameinfo_query *niquery;
101968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  unsigned int port = 0;
102968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
103968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  /* Validate socket address family and length */
104968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if ((sa->sa_family == AF_INET) &&
105968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      (salen == sizeof(struct sockaddr_in)))
106968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    {
107968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      addr = (struct sockaddr_in *)sa;
108968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      port = addr->sin_port;
109968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    }
110968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  else if ((sa->sa_family == AF_INET6) &&
111968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold           (salen == sizeof(struct sockaddr_in6)))
112968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    {
113968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      addr6 = (struct sockaddr_in6 *)sa;
114968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      port = addr6->sin6_port;
115968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    }
116968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  else
117968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    {
118968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      callback(arg, ARES_ENOTIMP, 0, NULL, NULL);
119968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      return;
120968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    }
121968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
122968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  /* If neither, assume they want a host */
123968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if (!(flags & ARES_NI_LOOKUPSERVICE) && !(flags & ARES_NI_LOOKUPHOST))
124968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    flags |= ARES_NI_LOOKUPHOST;
125968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
126968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  /* All they want is a service, no need for DNS */
127968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if ((flags & ARES_NI_LOOKUPSERVICE) && !(flags & ARES_NI_LOOKUPHOST))
128968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    {
129968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      char buf[33], *service;
130968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
131968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      service = lookup_service((unsigned short)(port & 0xffff),
132968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                               flags, buf, sizeof(buf));
133968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      callback(arg, ARES_SUCCESS, 0, NULL, service);
134968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      return;
135968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    }
136968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
137968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  /* They want a host lookup */
138968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if ((flags & ARES_NI_LOOKUPHOST))
139968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    {
140968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold     /* A numeric host can be handled without DNS */
141968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold     if ((flags & ARES_NI_NUMERICHOST))
142968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      {
143968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        char ipbuf[IPBUFSIZ];
144968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        char srvbuf[33];
145968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        char *service = NULL;
146968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        ipbuf[0] = 0;
147968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
148968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        /* Specifying not to lookup a host, but then saying a host
149968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold         * is required has to be illegal.
150968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold         */
151968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        if (flags & ARES_NI_NAMEREQD)
152968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          {
153968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            callback(arg, ARES_EBADFLAGS, 0, NULL, NULL);
154968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            return;
155968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          }
156968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        if (salen == sizeof(struct sockaddr_in6))
157968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          {
158968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            ares_inet_ntop(AF_INET6, &addr6->sin6_addr, ipbuf, IPBUFSIZ);
159968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            /* If the system supports scope IDs, use it */
160968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
161968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            append_scopeid(addr6, flags, ipbuf, sizeof(ipbuf));
162968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
163968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          }
164968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        else
165968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          {
166968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            ares_inet_ntop(AF_INET, &addr->sin_addr, ipbuf, IPBUFSIZ);
167968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          }
168968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        /* They also want a service */
169968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        if (flags & ARES_NI_LOOKUPSERVICE)
170968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          service = lookup_service((unsigned short)(port & 0xffff),
171968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                                   flags, srvbuf, sizeof(srvbuf));
172968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        callback(arg, ARES_SUCCESS, 0, ipbuf, service);
173968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        return;
174968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      }
175968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    /* This is where a DNS lookup becomes necessary */
176968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    else
177968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      {
178968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        niquery = malloc(sizeof(struct nameinfo_query));
179968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        if (!niquery)
180968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          {
181968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            callback(arg, ARES_ENOMEM, 0, NULL, NULL);
182968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            return;
183968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          }
184968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        niquery->callback = callback;
185968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        niquery->arg = arg;
186968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        niquery->flags = flags;
187968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        niquery->timeouts = 0;
188968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        if (sa->sa_family == AF_INET)
189968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          {
190968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            niquery->family = AF_INET;
191968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            memcpy(&niquery->addr.addr4, addr, sizeof(struct in_addr));
192968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            ares_gethostbyaddr(channel, &addr->sin_addr,
193968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                               sizeof(struct in_addr), AF_INET,
194968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                               nameinfo_callback, niquery);
195968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          }
196968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        else
197968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          {
198968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            niquery->family = AF_INET6;
199968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            memcpy(&niquery->addr.addr6, addr6, sizeof(struct ares_in6_addr));
200968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            ares_gethostbyaddr(channel, &addr6->sin6_addr,
201968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                               sizeof(struct ares_in6_addr), AF_INET6,
202968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                               nameinfo_callback, niquery);
203968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          }
204968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      }
205968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    }
206968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold}
207968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
208968bf19396ad404e89420f5d67900fce13f4186cGilad Arnoldstatic void nameinfo_callback(void *arg, int status, int timeouts,
209968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                              struct hostent *host)
210968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold{
211968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  struct nameinfo_query *niquery = (struct nameinfo_query *) arg;
212968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  char srvbuf[33];
213968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  char *service = NULL;
214968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
215968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  niquery->timeouts += timeouts;
216968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if (status == ARES_SUCCESS)
217968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    {
218968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      /* They want a service too */
219968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      if (niquery->flags & ARES_NI_LOOKUPSERVICE)
220968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        {
221968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          if (niquery->family == AF_INET)
222968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            service = lookup_service(niquery->addr.addr4.sin_port,
223968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                                     niquery->flags, srvbuf, sizeof(srvbuf));
224968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          else
225968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            service = lookup_service(niquery->addr.addr6.sin6_port,
226968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                                     niquery->flags, srvbuf, sizeof(srvbuf));
227968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        }
228968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      /* NOFQDN means we have to strip off the domain name portion.  We do
229968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold         this by determining our own domain name, then searching the string
230968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold         for this domain name and removing it.
231968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold       */
232968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_GETHOSTNAME
233968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      if (niquery->flags & ARES_NI_NOFQDN)
234968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        {
235968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold           char buf[255];
236968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold           char *domain;
237968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold           gethostname(buf, 255);
238968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold           if ((domain = strchr(buf, '.')) != NULL)
239968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold             {
240968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold               char *end = ares_striendstr(host->h_name, domain);
241968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold               if (end)
242968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                 *end = 0;
243968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold             }
244968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        }
245968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
246968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      niquery->callback(niquery->arg, ARES_SUCCESS, niquery->timeouts,
247968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                        (char *)(host->h_name),
248968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                        service);
249968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      free(niquery);
250968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      return;
251968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    }
252968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  /* We couldn't find the host, but it's OK, we can use the IP */
253968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  else if (status == ARES_ENOTFOUND && !(niquery->flags & ARES_NI_NAMEREQD))
254968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    {
255968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      char ipbuf[IPBUFSIZ];
256968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      if (niquery->family == AF_INET)
257968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        ares_inet_ntop(AF_INET, &niquery->addr.addr4.sin_addr, ipbuf,
258968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                       IPBUFSIZ);
259968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      else
260968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        {
261968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          ares_inet_ntop(AF_INET6, &niquery->addr.addr6.sin6_addr, ipbuf,
262968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                         IPBUFSIZ);
263968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
264968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          append_scopeid(&niquery->addr.addr6, niquery->flags, ipbuf,
265968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                         sizeof(ipbuf));
266968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
267968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        }
268968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      /* They want a service too */
269968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      if (niquery->flags & ARES_NI_LOOKUPSERVICE)
270968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        {
271968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          if (niquery->family == AF_INET)
272968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            service = lookup_service(niquery->addr.addr4.sin_port,
273968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                                     niquery->flags, srvbuf, sizeof(srvbuf));
274968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          else
275968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            service = lookup_service(niquery->addr.addr6.sin6_port,
276968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                                     niquery->flags, srvbuf, sizeof(srvbuf));
277968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        }
278968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      niquery->callback(niquery->arg, ARES_SUCCESS, niquery->timeouts, ipbuf,
279968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                        service);
280968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      free(niquery);
281968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      return;
282968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    }
283968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  niquery->callback(niquery->arg, status, niquery->timeouts, NULL, NULL);
284968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  free(niquery);
285968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold}
286968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
287968bf19396ad404e89420f5d67900fce13f4186cGilad Arnoldstatic char *lookup_service(unsigned short port, int flags,
288968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                            char *buf, size_t buflen)
289968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold{
290968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  const char *proto;
291968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  struct servent *sep;
292968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_GETSERVBYPORT_R
293968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  struct servent se;
294968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
295968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  char tmpbuf[4096];
296968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
297968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if (port)
298968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    {
299968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      if (flags & ARES_NI_NUMERICSERV)
300968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        sep = NULL;
301968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      else
302968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        {
303968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          if (flags & ARES_NI_UDP)
304968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            proto = "udp";
305968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          else if (flags & ARES_NI_SCTP)
306968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            proto = "sctp";
307968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          else if (flags & ARES_NI_DCCP)
308968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            proto = "dccp";
309968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          else
310968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            proto = "tcp";
311968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_GETSERVBYPORT_R
312968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          sep = &se;
313968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          memset(tmpbuf, 0, sizeof(tmpbuf));
314968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#if GETSERVBYPORT_R_ARGS == 6
315968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          if (getservbyport_r(port, proto, &se, (void *)tmpbuf,
316968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                              sizeof(tmpbuf), &sep) != 0)
317968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            sep = NULL;
318968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#elif GETSERVBYPORT_R_ARGS == 5
319968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          sep = getservbyport_r(port, proto, &se, (void *)tmpbuf,
320968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                                sizeof(tmpbuf));
321968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#elif GETSERVBYPORT_R_ARGS == 4
322968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          if (getservbyport_r(port, proto, &se, (void *)tmpbuf) != 0)
323968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            sep = NULL;
324968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#else
325968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          /* Lets just hope the OS uses TLS! */
326968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          sep = getservbyport(port, proto);
327968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
328968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#else
329968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          /* Lets just hope the OS uses TLS! */
330968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#if (defined(NETWARE) && !defined(__NOVELL_LIBC__))
331968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          sep = getservbyport(port, (char*)proto);
332968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#else
333968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          sep = getservbyport(port, proto);
334968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
335968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
336968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        }
337968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      if (sep && sep->s_name)
338968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        /* get service name */
339968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        strcpy(tmpbuf, sep->s_name);
340968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      else
341968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        /* get port as a string */
342968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        sprintf(tmpbuf, "%u", (unsigned int)ntohs(port));
343968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      if (strlen(tmpbuf) < buflen)
344968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        /* return it if buffer big enough */
345968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        strcpy(buf, tmpbuf);
346968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      else
347968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        /* avoid reusing previous one */
348968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        buf[0] = '\0';
349968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      return buf;
350968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    }
351968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  buf[0] = '\0';
352968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  return NULL;
353968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold}
354968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
355968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
356968bf19396ad404e89420f5d67900fce13f4186cGilad Arnoldstatic void append_scopeid(struct sockaddr_in6 *addr6, unsigned int flags,
357968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                           char *buf, size_t buflen)
358968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold{
359968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_IF_INDEXTONAME
360968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  int is_ll, is_mcll;
361968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
362968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  static const char fmt_u[] = "%u";
363968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  static const char fmt_lu[] = "%lu";
364968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  char tmpbuf[IF_NAMESIZE + 2];
365968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  size_t bufl;
366968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  const char *fmt = (sizeof(addr6->sin6_scope_id) > sizeof(unsigned int))?
367968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    fmt_lu:fmt_u;
368968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
369968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  tmpbuf[0] = '%';
370968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
371968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_IF_INDEXTONAME
372968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  is_ll = IN6_IS_ADDR_LINKLOCAL(&addr6->sin6_addr);
373968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  is_mcll = IN6_IS_ADDR_MC_LINKLOCAL(&addr6->sin6_addr);
374968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if ((flags & ARES_NI_NUMERICSCOPE) ||
375968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      (!is_ll && !is_mcll))
376968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    {
377968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold       sprintf(&tmpbuf[1], fmt, addr6->sin6_scope_id);
378968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    }
379968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  else
380968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    {
381968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      if (if_indextoname(addr6->sin6_scope_id, &tmpbuf[1]) == NULL)
382968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        sprintf(&tmpbuf[1], fmt, addr6->sin6_scope_id);
383968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    }
384968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#else
385968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  sprintf(&tmpbuf[1], fmt, addr6->sin6_scope_id);
386968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  (void) flags;
387968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
388968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  tmpbuf[IF_NAMESIZE + 1] = '\0';
389968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  bufl = strlen(buf);
390968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
391968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if(bufl + strlen(tmpbuf) < buflen)
392968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    /* only append the scopeid string if it fits in the target buffer */
393968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    strcpy(&buf[bufl], tmpbuf);
394968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold}
395968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
396968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
397968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold/* Determines if s1 ends with the string in s2 (case-insensitive) */
398968bf19396ad404e89420f5d67900fce13f4186cGilad Arnoldstatic char *ares_striendstr(const char *s1, const char *s2)
399968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold{
400968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  const char *c1, *c2, *c1_begin;
401968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  int lo1, lo2;
402968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  size_t s1_len = strlen(s1), s2_len = strlen(s2);
403968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
404968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  /* If the substr is longer than the full str, it can't match */
405968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if (s2_len > s1_len)
406968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    return NULL;
407968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
408968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  /* Jump to the end of s1 minus the length of s2 */
409968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  c1_begin = s1+s1_len-s2_len;
410968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  c1 = (const char *)c1_begin;
411968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  c2 = s2;
412968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  while (c2 < s2+s2_len)
413968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    {
414968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      lo1 = TOLOWER(*c1);
415968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      lo2 = TOLOWER(*c2);
416968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      if (lo1 != lo2)
417968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        return NULL;
418968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      else
419968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        {
420968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          c1++;
421968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          c2++;
422968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        }
423968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    }
424968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if (c2 == c1 && c2 == NULL)
425968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    return (char *)c1_begin;
426968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  return NULL;
427968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold}
428