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