1
2/* Copyright 1998, 2010 by the Massachusetts Institute of Technology.
3 *
4 * Permission to use, copy, modify, and distribute this
5 * software and its documentation for any purpose and without
6 * fee is hereby granted, provided that the above copyright
7 * notice appear in all copies and that both that copyright
8 * notice and this permission notice appear in supporting
9 * documentation, and that the name of M.I.T. not be used in
10 * advertising or publicity pertaining to distribution of the
11 * software without specific, written prior permission.
12 * M.I.T. makes no representations about the suitability of
13 * this software for any purpose.  It is provided "as is"
14 * without express or implied warranty.
15 */
16
17#include "ares_setup.h"
18
19#ifdef HAVE_SYS_SOCKET_H
20#  include <sys/socket.h>
21#endif
22#ifdef HAVE_NETINET_IN_H
23#  include <netinet/in.h>
24#endif
25#ifdef HAVE_NETDB_H
26#  include <netdb.h>
27#endif
28#ifdef HAVE_ARPA_INET_H
29#  include <arpa/inet.h>
30#endif
31
32#include "ares.h"
33#include "inet_net_pton.h"
34#include "ares_private.h"
35
36int ares__get_hostent(FILE *fp, int family, struct hostent **host)
37{
38  char *line = NULL, *p, *q, **alias;
39  char *txtaddr, *txthost, *txtalias;
40  int status;
41  size_t addrlen, linesize, naliases;
42  struct ares_addr addr;
43  struct hostent *hostent = NULL;
44
45  *host = NULL; /* Assume failure */
46
47  /* Validate family */
48  switch (family) {
49    case AF_INET:
50    case AF_INET6:
51    case AF_UNSPEC:
52      break;
53    default:
54      return ARES_EBADFAMILY;
55  }
56
57  while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
58    {
59
60      /* Trim line comment. */
61      p = line;
62      while (*p && (*p != '#'))
63        p++;
64      *p = '\0';
65
66      /* Trim trailing whitespace. */
67      q = p - 1;
68      while ((q >= line) && ISSPACE(*q))
69        q--;
70      *++q = '\0';
71
72      /* Skip leading whitespace. */
73      p = line;
74      while (*p && ISSPACE(*p))
75        p++;
76      if (!*p)
77        /* Ignore line if empty. */
78        continue;
79
80      /* Pointer to start of IPv4 or IPv6 address part. */
81      txtaddr = p;
82
83      /* Advance past address part. */
84      while (*p && !ISSPACE(*p))
85        p++;
86      if (!*p)
87        /* Ignore line if reached end of line. */
88        continue;
89
90      /* Null terminate address part. */
91      *p = '\0';
92
93      /* Advance to host name */
94      p++;
95      while (*p && ISSPACE(*p))
96        p++;
97      if (!*p)
98        /* Ignore line if reached end of line. */
99        continue;
100
101      /* Pointer to start of host name. */
102      txthost = p;
103
104      /* Advance past host name. */
105      while (*p && !ISSPACE(*p))
106        p++;
107
108      /* Pointer to start of first alias. */
109      txtalias = NULL;
110      if (*p)
111        {
112          q = p + 1;
113          while (*q && ISSPACE(*q))
114            q++;
115          if (*q)
116            txtalias = q;
117        }
118
119      /* Null terminate host name. */
120      *p = '\0';
121
122      /* find out number of aliases. */
123      naliases = 0;
124      if (txtalias)
125        {
126          p = txtalias;
127          while (*p)
128            {
129              while (*p && !ISSPACE(*p))
130                p++;
131              while (*p && ISSPACE(*p))
132                p++;
133              naliases++;
134            }
135        }
136
137      /* Convert address string to network address for the requested family. */
138      addrlen = 0;
139      addr.family = AF_UNSPEC;
140      addr.addrV4.s_addr = INADDR_NONE;
141      if ((family == AF_INET) || (family == AF_UNSPEC))
142        {
143          addr.addrV4.s_addr = inet_addr(txtaddr);
144          if (addr.addrV4.s_addr != INADDR_NONE)
145            {
146              /* Actual network address family and length. */
147              addr.family = AF_INET;
148              addrlen = sizeof(addr.addrV4);
149            }
150        }
151      if ((family == AF_INET6) || ((family == AF_UNSPEC) && (!addrlen)))
152        {
153          if (ares_inet_pton(AF_INET6, txtaddr, &addr.addrV6) > 0)
154            {
155              /* Actual network address family and length. */
156              addr.family = AF_INET6;
157              addrlen = sizeof(addr.addrV6);
158            }
159        }
160      if (!addrlen)
161        /* Ignore line if invalid address string for the requested family. */
162        continue;
163
164      /*
165      ** Actual address family possible values are AF_INET and AF_INET6 only.
166      */
167
168      /* Allocate memory for the hostent structure. */
169      hostent = malloc(sizeof(struct hostent));
170      if (!hostent)
171        break;
172
173      /* Initialize fields for out of memory condition. */
174      hostent->h_aliases = NULL;
175      hostent->h_addr_list = NULL;
176
177      /* Copy official host name. */
178      hostent->h_name = strdup(txthost);
179      if (!hostent->h_name)
180        break;
181
182      /* Copy network address. */
183      hostent->h_addr_list = malloc(2 * sizeof(char *));
184      if (!hostent->h_addr_list)
185        break;
186      hostent->h_addr_list[1] = NULL;
187      hostent->h_addr_list[0] = malloc(addrlen);
188      if (!hostent->h_addr_list[0])
189        break;
190      if (addr.family == AF_INET)
191        memcpy(hostent->h_addr_list[0], &addr.addrV4, sizeof(addr.addrV4));
192      else
193        memcpy(hostent->h_addr_list[0], &addr.addrV6, sizeof(addr.addrV6));
194
195      /* Copy aliases. */
196      hostent->h_aliases = malloc((naliases + 1) * sizeof(char *));
197      if (!hostent->h_aliases)
198        break;
199      alias = hostent->h_aliases;
200      while (naliases)
201        *(alias + naliases--) = NULL;
202      *alias = NULL;
203      while (txtalias)
204        {
205          p = txtalias;
206          while (*p && !ISSPACE(*p))
207            p++;
208          q = p;
209          while (*q && ISSPACE(*q))
210            q++;
211          *p = '\0';
212          if ((*alias = strdup(txtalias)) == NULL)
213            break;
214          alias++;
215          txtalias = *q ? q : NULL;
216        }
217      if (txtalias)
218        /* Alias memory allocation failure. */
219        break;
220
221      /* Copy actual network address family and length. */
222      hostent->h_addrtype = addr.family;
223      hostent->h_length = (int)addrlen;
224
225      /* Free line buffer. */
226      free(line);
227
228      /* Return hostent successfully */
229      *host = hostent;
230      return ARES_SUCCESS;
231
232    }
233
234  /* If allocated, free line buffer. */
235  if (line)
236    free(line);
237
238  if (status == ARES_SUCCESS)
239    {
240      /* Memory allocation failure; clean up. */
241      if (hostent)
242        {
243          if (hostent->h_name)
244            free((char *) hostent->h_name);
245          if (hostent->h_aliases)
246            {
247              for (alias = hostent->h_aliases; *alias; alias++)
248                free(*alias);
249              free(hostent->h_aliases);
250            }
251          if (hostent->h_addr_list)
252            {
253              if (hostent->h_addr_list[0])
254                free(hostent->h_addr_list[0]);
255              free(hostent->h_addr_list);
256            }
257          free(hostent);
258        }
259      return ARES_ENOMEM;
260    }
261
262  return status;
263}
264