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 
ares__get_hostent(FILE * fp,int family,struct hostent ** host)36 int 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