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 addr.addrV4.s_addr = inet_addr(txtaddr);
142 if (addr.addrV4.s_addr != INADDR_NONE)
143 {
144 /* Actual network address family and length. */
145 addr.family = AF_INET;
146 addrlen = sizeof(addr.addrV4);
147 }
148 }
149 if ((family == AF_INET6) || ((family == AF_UNSPEC) && (!addrlen)))
150 {
151 if (ares_inet_pton(AF_INET6, txtaddr, &addr.addrV6) > 0)
152 {
153 /* Actual network address family and length. */
154 addr.family = AF_INET6;
155 addrlen = sizeof(addr.addrV6);
156 }
157 }
158 if (!addrlen)
159 /* Ignore line if invalid address string for the requested family. */
160 continue;
161
162 /*
163 ** Actual address family possible values are AF_INET and AF_INET6 only.
164 */
165
166 /* Allocate memory for the hostent structure. */
167 hostent = ares_malloc(sizeof(struct hostent));
168 if (!hostent)
169 break;
170
171 /* Initialize fields for out of memory condition. */
172 hostent->h_aliases = NULL;
173 hostent->h_addr_list = NULL;
174
175 /* Copy official host name. */
176 hostent->h_name = ares_strdup(txthost);
177 if (!hostent->h_name)
178 break;
179
180 /* Copy network address. */
181 hostent->h_addr_list = ares_malloc(2 * sizeof(char *));
182 if (!hostent->h_addr_list)
183 break;
184 hostent->h_addr_list[1] = NULL;
185 hostent->h_addr_list[0] = ares_malloc(addrlen);
186 if (!hostent->h_addr_list[0])
187 break;
188 if (addr.family == AF_INET)
189 memcpy(hostent->h_addr_list[0], &addr.addrV4, sizeof(addr.addrV4));
190 else
191 memcpy(hostent->h_addr_list[0], &addr.addrV6, sizeof(addr.addrV6));
192
193 /* Copy aliases. */
194 hostent->h_aliases = ares_malloc((naliases + 1) * sizeof(char *));
195 if (!hostent->h_aliases)
196 break;
197 alias = hostent->h_aliases;
198 while (naliases)
199 *(alias + naliases--) = NULL;
200 *alias = NULL;
201 while (txtalias)
202 {
203 p = txtalias;
204 while (*p && !ISSPACE(*p))
205 p++;
206 q = p;
207 while (*q && ISSPACE(*q))
208 q++;
209 *p = '\0';
210 if ((*alias = ares_strdup(txtalias)) == NULL)
211 break;
212 alias++;
213 txtalias = *q ? q : NULL;
214 }
215 if (txtalias)
216 /* Alias memory allocation failure. */
217 break;
218
219 /* Copy actual network address family and length. */
220 hostent->h_addrtype = aresx_sitoss(addr.family);
221 hostent->h_length = aresx_uztoss(addrlen);
222
223 /* Free line buffer. */
224 ares_free(line);
225
226 /* Return hostent successfully */
227 *host = hostent;
228 return ARES_SUCCESS;
229
230 }
231
232 /* If allocated, free line buffer. */
233 if (line)
234 ares_free(line);
235
236 if (status == ARES_SUCCESS)
237 {
238 /* Memory allocation failure; clean up. */
239 if (hostent)
240 {
241 if (hostent->h_name)
242 ares_free((char *) hostent->h_name);
243 if (hostent->h_aliases)
244 {
245 for (alias = hostent->h_aliases; *alias; alias++)
246 ares_free(*alias);
247 ares_free(hostent->h_aliases);
248 }
249 if (hostent->h_addr_list)
250 {
251 if (hostent->h_addr_list[0])
252 ares_free(hostent->h_addr_list[0]);
253 ares_free(hostent->h_addr_list);
254 }
255 ares_free(hostent);
256 }
257 return ARES_ENOMEM;
258 }
259
260 return status;
261 }
262