1 /* Hosts file parser in nss_files module.
2 Copyright (C) 1996-2014 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
22 #include <arpa/nameser.h>
27 /* Get implementation for some internal functions. */
28 #include "../resolv/mapv4v6addr.h"
29 #include "../resolv/res_hconf.h"
32 #define ENTNAME hostent
33 #define DATABASE "hosts"
36 #define EXTRA_ARGS , af, flags
37 #define EXTRA_ARGS_DECL , int af, int flags
39 #define ENTDATA hostent_data
42 unsigned char host_addr
[16]; /* IPv4 or IPv6 address. */
43 char *h_addr_ptrs
[2]; /* Points to that and null terminator. */
46 #define TRAILING_LIST_MEMBER h_aliases
47 #define TRAILING_LIST_SEPARATOR_P isspace
48 #include "files-parse.c"
54 STRING_FIELD (addr
, isspace
, 1);
57 if (inet_pton (af
== AF_UNSPEC
? AF_INET
: af
, addr
, entdata
->host_addr
)
59 af
= af
== AF_UNSPEC
? AF_INET
: af
;
62 if (af
== AF_INET6
&& (flags
& AI_V4MAPPED
) != 0
63 && inet_pton (AF_INET
, addr
, entdata
->host_addr
) > 0)
64 map_v4v6_address ((char *) entdata
->host_addr
,
65 (char *) entdata
->host_addr
);
66 else if (af
== AF_INET
67 && inet_pton (AF_INET6
, addr
, entdata
->host_addr
) > 0)
69 if (IN6_IS_ADDR_V4MAPPED (entdata
->host_addr
))
70 memcpy (entdata
->host_addr
, entdata
->host_addr
+ 12, INADDRSZ
);
71 else if (IN6_IS_ADDR_LOOPBACK (entdata
->host_addr
))
73 in_addr_t localhost
= htonl (INADDR_LOOPBACK
);
74 memcpy (entdata
->host_addr
, &localhost
, sizeof (localhost
));
77 /* Illegal address: ignore line. */
80 else if (af
== AF_UNSPEC
81 && inet_pton (AF_INET6
, addr
, entdata
->host_addr
) > 0)
84 /* Illegal address: ignore line. */
88 /* We always return entries of the requested form. */
89 result
->h_addrtype
= af
;
90 result
->h_length
= af
== AF_INET
? INADDRSZ
: IN6ADDRSZ
;
92 /* Store a pointer to the address in the expected form. */
93 entdata
->h_addr_ptrs
[0] = (char *) entdata
->host_addr
;
94 entdata
->h_addr_ptrs
[1] = NULL
;
95 result
->h_addr_list
= entdata
->h_addr_ptrs
;
97 STRING_FIELD (result
->h_name
, isspace
, 1);
100 #define EXTRA_ARGS_VALUE \
101 , ((_res.options & RES_USE_INET6) ? AF_INET6 : AF_INET), \
102 ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0)
103 #include "files-XXX.c"
104 #undef EXTRA_ARGS_VALUE
106 /* We only need to consider IPv4 mapped addresses if the input to the
107 gethostbyaddr() function is an IPv6 address. */
108 #define EXTRA_ARGS_VALUE \
109 , af, (len == IN6ADDRSZ ? AI_V4MAPPED : 0)
110 DB_LOOKUP (hostbyaddr
, ,,,
112 if (result
->h_length
== (int) len
113 && ! memcmp (addr
, result
->h_addr_list
[0], len
))
115 }, const void *addr
, socklen_t len
, int af
)
116 #undef EXTRA_ARGS_VALUE
119 _nss_files_gethostbyname3_r (const char *name
, int af
, struct hostent
*result
,
120 char *buffer
, size_t buflen
, int *errnop
,
121 int *herrnop
, int32_t *ttlp
, char **canonp
)
123 uintptr_t pad
= -(uintptr_t) buffer
% __alignof__ (struct hostent_data
);
125 buflen
= buflen
> pad
? buflen
- pad
: 0;
127 __libc_lock_lock (lock
);
129 /* Reset file pointer to beginning or open file. */
130 enum nss_status status
= internal_setent (keep_stream
);
132 if (status
== NSS_STATUS_SUCCESS
)
134 /* XXX Is using _res to determine whether we want to convert IPv4
135 addresses to IPv6 addresses really the right thing to do? */
136 int flags
= ((_res
.options
& RES_USE_INET6
) ? AI_V4MAPPED
: 0);
138 /* Tell getent function that we have repositioned the file pointer. */
141 while ((status
= internal_getent (result
, buffer
, buflen
, errnop
,
143 == NSS_STATUS_SUCCESS
)
145 LOOKUP_NAME_CASE (h_name
, h_aliases
)
148 if (status
== NSS_STATUS_SUCCESS
149 && _res_hconf
.flags
& HCONF_FLAG_MULTI
)
151 /* We have to get all host entries from the file. */
152 size_t tmp_buflen
= MIN (buflen
, 4096);
153 char tmp_buffer_stack
[tmp_buflen
]
154 __attribute__ ((__aligned__ (__alignof__ (struct hostent_data
))));
155 char *tmp_buffer
= tmp_buffer_stack
;
156 struct hostent tmp_result_buf
;
160 bool tmp_buffer_malloced
= false;
162 while (result
->h_aliases
[naliases
] != NULL
)
165 bufferend
= (char *) &result
->h_aliases
[naliases
+ 1];
168 while ((status
= internal_getent (&tmp_result_buf
, tmp_buffer
,
169 tmp_buflen
, errnop
, herrnop
, af
,
171 == NSS_STATUS_SUCCESS
)
174 struct hostent
*old_result
= result
;
175 result
= &tmp_result_buf
;
176 /* The following piece is a bit clumsy but we want to use the
177 `LOOKUP_NAME_CASE' value. The optimizer should do its
181 LOOKUP_NAME_CASE (h_name
, h_aliases
)
184 while ((matches
= 0));
188 /* We could be very clever and try to recycle a few bytes
189 in the buffer instead of generating new arrays. But
190 we are not doing this here since it's more work than
191 it's worth. Simply let the user provide a bit bigger
193 char **new_h_addr_list
;
194 char **new_h_aliases
;
196 size_t newstrlen
= 0;
199 /* Count the new aliases and the length of the strings. */
200 while (tmp_result_buf
.h_aliases
[newaliases
] != NULL
)
202 char *cp
= tmp_result_buf
.h_aliases
[newaliases
];
204 newstrlen
+= strlen (cp
) + 1;
206 /* If the real name is different add it also to the
207 aliases. This means that there is a duplication
208 in the alias list but this is really the user's
210 if (strcmp (old_result
->h_name
,
211 tmp_result_buf
.h_name
) != 0)
214 newstrlen
+= strlen (tmp_result_buf
.h_name
) + 1;
217 /* Make sure bufferend is aligned. */
218 assert ((bufferend
- (char *) 0) % sizeof (char *) == 0);
220 /* Now we can check whether the buffer is large enough.
221 16 is the maximal size of the IP address. */
222 if (bufferend
+ 16 + (naddrs
+ 2) * sizeof (char *)
223 + roundup (newstrlen
, sizeof (char *))
224 + (naliases
+ newaliases
+ 1) * sizeof (char *)
228 *herrnop
= NETDB_INTERNAL
;
229 status
= NSS_STATUS_TRYAGAIN
;
235 + roundup (newstrlen
, sizeof (char *))
238 (char **) ((char *) new_h_addr_list
239 + (naddrs
+ 2) * sizeof (char *));
241 /* Copy the old data in the new arrays. */
242 for (cnt
= 0; cnt
< naddrs
; ++cnt
)
243 new_h_addr_list
[cnt
] = old_result
->h_addr_list
[cnt
];
245 for (cnt
= 0; cnt
< naliases
; ++cnt
)
246 new_h_aliases
[cnt
] = old_result
->h_aliases
[cnt
];
248 /* Store the new strings. */
250 while (tmp_result_buf
.h_aliases
[cnt
] != NULL
)
252 new_h_aliases
[naliases
++] = bufferend
;
253 bufferend
= (__stpcpy (bufferend
,
254 tmp_result_buf
.h_aliases
[cnt
])
259 if (cnt
< newaliases
)
261 new_h_aliases
[naliases
++] = bufferend
;
262 bufferend
= __stpcpy (bufferend
,
263 tmp_result_buf
.h_name
) + 1;
266 /* Final NULL pointer. */
267 new_h_aliases
[naliases
] = NULL
;
269 /* Round up the buffer end address. */
270 bufferend
+= (sizeof (char *)
271 - ((bufferend
- (char *) 0)
272 % sizeof (char *))) % sizeof (char *);
274 /* Now the new address. */
275 new_h_addr_list
[naddrs
++] =
276 memcpy (bufferend
, tmp_result_buf
.h_addr
,
277 tmp_result_buf
.h_length
);
279 /* Also here a final NULL pointer. */
280 new_h_addr_list
[naddrs
] = NULL
;
282 /* Store the new array pointers. */
283 old_result
->h_aliases
= new_h_aliases
;
284 old_result
->h_addr_list
= new_h_addr_list
;
286 /* Compute the new buffer end. */
287 bufferend
= (char *) &new_h_aliases
[naliases
+ 1];
288 assert (bufferend
<= buffer
+ buflen
);
294 if (status
== NSS_STATUS_TRYAGAIN
)
296 size_t newsize
= 2 * tmp_buflen
;
297 if (tmp_buffer_malloced
)
299 char *newp
= realloc (tmp_buffer
, newsize
);
302 assert ((((uintptr_t) newp
)
303 & (__alignof__ (struct hostent_data
) - 1))
306 tmp_buflen
= newsize
;
310 else if (!__libc_use_alloca (buflen
+ newsize
))
312 tmp_buffer
= malloc (newsize
);
313 if (tmp_buffer
!= NULL
)
315 assert ((((uintptr_t) tmp_buffer
)
316 & (__alignof__ (struct hostent_data
) - 1))
318 tmp_buffer_malloced
= true;
319 tmp_buflen
= newsize
;
326 = extend_alloca (tmp_buffer
, tmp_buflen
,
328 + __alignof__ (struct hostent_data
));
329 tmp_buffer
= (char *) (((uintptr_t) tmp_buffer
330 + __alignof__ (struct hostent_data
)
332 & ~(__alignof__ (struct hostent_data
)
338 status
= NSS_STATUS_SUCCESS
;
340 if (tmp_buffer_malloced
)
348 if (canonp
&& status
== NSS_STATUS_SUCCESS
)
349 *canonp
= result
->h_name
;
351 __libc_lock_unlock (lock
);
357 _nss_files_gethostbyname_r (const char *name
, struct hostent
*result
,
358 char *buffer
, size_t buflen
, int *errnop
,
361 int af
= ((_res
.options
& RES_USE_INET6
) ? AF_INET6
: AF_INET
);
363 return _nss_files_gethostbyname3_r (name
, af
, result
, buffer
, buflen
,
364 errnop
, herrnop
, NULL
, NULL
);
368 _nss_files_gethostbyname2_r (const char *name
, int af
, struct hostent
*result
,
369 char *buffer
, size_t buflen
, int *errnop
,
372 return _nss_files_gethostbyname3_r (name
, af
, result
, buffer
, buflen
,
373 errnop
, herrnop
, NULL
, NULL
);
377 _nss_files_gethostbyname4_r (const char *name
, struct gaih_addrtuple
**pat
,
378 char *buffer
, size_t buflen
, int *errnop
,
379 int *herrnop
, int32_t *ttlp
)
381 __libc_lock_lock (lock
);
383 /* Reset file pointer to beginning or open file. */
384 enum nss_status status
= internal_setent (keep_stream
);
386 if (status
== NSS_STATUS_SUCCESS
)
388 /* Tell getent function that we have repositioned the file pointer. */
392 bool got_canon
= false;
395 /* Align the buffer for the next record. */
396 uintptr_t pad
= (-(uintptr_t) buffer
397 % __alignof__ (struct hostent_data
));
399 buflen
= buflen
> pad
? buflen
- pad
: 0;
401 struct hostent result
;
402 status
= internal_getent (&result
, buffer
, buflen
, errnop
,
403 herrnop
, AF_UNSPEC
, 0);
404 if (status
!= NSS_STATUS_SUCCESS
)
408 if (__strcasecmp (name
, result
.h_name
) != 0)
410 for (; result
.h_aliases
[naliases
] != NULL
; ++naliases
)
411 if (! __strcasecmp (name
, result
.h_aliases
[naliases
]))
413 if (result
.h_aliases
[naliases
] == NULL
)
416 /* We know this alias exist. Count it. */
420 /* Determine how much memory has been used so far. */
421 // XXX It is not necessary to preserve the aliases array
422 while (result
.h_aliases
[naliases
] != NULL
)
424 char *bufferend
= (char *) &result
.h_aliases
[naliases
+ 1];
425 assert (buflen
>= bufferend
- buffer
);
426 buflen
-= bufferend
- buffer
;
429 /* We found something. */
432 /* Create the record the caller expects. There is only one
434 assert (result
.h_addr_list
[1] == NULL
);
437 uintptr_t pad
= (-(uintptr_t) buffer
438 % __alignof__ (struct gaih_addrtuple
));
440 buflen
= buflen
> pad
? buflen
- pad
: 0;
442 if (__builtin_expect (buflen
< sizeof (struct gaih_addrtuple
),
446 *herrnop
= NETDB_INTERNAL
;
447 status
= NSS_STATUS_TRYAGAIN
;
451 *pat
= (struct gaih_addrtuple
*) buffer
;
452 buffer
+= sizeof (struct gaih_addrtuple
);
453 buflen
-= sizeof (struct gaih_addrtuple
);
457 (*pat
)->name
= got_canon
? NULL
: result
.h_name
;
459 (*pat
)->family
= result
.h_addrtype
;
460 memcpy ((*pat
)->addr
, result
.h_addr_list
[0], result
.h_length
);
463 pat
= &((*pat
)->next
);
465 /* If we only look for the first matching entry we are done. */
466 if ((_res_hconf
.flags
& HCONF_FLAG_MULTI
) == 0)
470 /* If we have to look for multiple records and found one, this
472 if (status
== NSS_STATUS_NOTFOUND
&& any
)
474 assert ((_res_hconf
.flags
& HCONF_FLAG_MULTI
) != 0);
475 status
= NSS_STATUS_SUCCESS
;
481 else if (status
== NSS_STATUS_TRYAGAIN
)
484 *herrnop
= TRY_AGAIN
;
492 __libc_lock_unlock (lock
);