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