1 /* Hosts file parser in nss_files module.
2 Copyright (C) 1996-2001, 2003, 2004, 2006, 2007
3 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
24 #include <arpa/nameser.h>
29 /* Get implementation for some internal functions. */
30 #include "../resolv/mapv4v6addr.h"
31 #include "../resolv/res_hconf.h"
34 #define ENTNAME hostent
35 #define DATABASE "hosts"
38 #define EXTRA_ARGS , af, flags
39 #define EXTRA_ARGS_DECL , int af, int flags
41 #define ENTDATA hostent_data
44 unsigned char host_addr
[16]; /* IPv4 or IPv6 address. */
45 char *h_addr_ptrs
[2]; /* Points to that and null terminator. */
48 #define TRAILING_LIST_MEMBER h_aliases
49 #define TRAILING_LIST_SEPARATOR_P isspace
50 #include "files-parse.c"
56 STRING_FIELD (addr
, isspace
, 1);
59 if (inet_pton (af
, addr
, entdata
->host_addr
) <= 0)
61 if (af
== AF_INET6
&& (flags
& AI_V4MAPPED
) != 0
62 && inet_pton (AF_INET
, addr
, entdata
->host_addr
) > 0)
63 map_v4v6_address ((char *) entdata
->host_addr
,
64 (char *) entdata
->host_addr
);
65 else if (af
== AF_INET
66 && inet_pton (AF_INET6
, addr
, entdata
->host_addr
) > 0)
68 if (IN6_IS_ADDR_V4MAPPED (entdata
->host_addr
))
69 memcpy (entdata
->host_addr
, entdata
->host_addr
+ 12, INADDRSZ
);
70 else if (IN6_IS_ADDR_LOOPBACK (entdata
->host_addr
))
72 in_addr_t localhost
= htonl (INADDR_LOOPBACK
);
73 memcpy (entdata
->host_addr
, &localhost
, sizeof (localhost
));
76 /* Illegal address: ignore line. */
80 /* Illegal address: ignore line. */
84 /* We always return entries of the requested form. */
85 result
->h_addrtype
= af
;
86 result
->h_length
= af
== AF_INET
? INADDRSZ
: IN6ADDRSZ
;
88 /* Store a pointer to the address in the expected form. */
89 entdata
->h_addr_ptrs
[0] = (char *) entdata
->host_addr
;
90 entdata
->h_addr_ptrs
[1] = NULL
;
91 result
->h_addr_list
= entdata
->h_addr_ptrs
;
93 STRING_FIELD (result
->h_name
, isspace
, 1);
98 #define HOST_DB_LOOKUP(name, keysize, keypattern, break_if_match, proto...) \
100 _nss_files_get##name##_r (proto, \
101 struct STRUCTURE *result, char *buffer, \
102 size_t buflen, int *errnop H_ERRNO_PROTO) \
104 enum nss_status status; \
106 uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct hostent_data); \
108 buflen = buflen > pad ? buflen - pad : 0; \
110 __libc_lock_lock (lock); \
112 /* Reset file pointer to beginning or open file. */ \
113 status = internal_setent (keep_stream); \
115 if (status == NSS_STATUS_SUCCESS) \
117 /* Tell getent function that we have repositioned the file pointer. */ \
120 while ((status = internal_getent (result, buffer, buflen, errnop \
121 H_ERRNO_ARG EXTRA_ARGS_VALUE)) \
122 == NSS_STATUS_SUCCESS) \
125 if (status == NSS_STATUS_SUCCESS \
126 && _res_hconf.flags & HCONF_FLAG_MULTI) \
128 /* We have to get all host entries from the file. */ \
129 const size_t tmp_buflen = MIN (buflen, 4096); \
130 char tmp_buffer[tmp_buflen] \
131 __attribute__ ((__aligned__ (__alignof__ (struct hostent_data))));\
132 struct hostent tmp_result_buf; \
137 while (result->h_aliases[naliases] != NULL) \
140 bufferend = (char *) &result->h_aliases[naliases + 1]; \
142 while ((status = internal_getent (&tmp_result_buf, tmp_buffer, \
143 tmp_buflen, errnop H_ERRNO_ARG \
145 == NSS_STATUS_SUCCESS) \
148 struct hostent *old_result = result; \
149 result = &tmp_result_buf; \
150 /* The following piece is a bit clumsy but we want to use the \
151 `break_if_match' value. The optimizer should do its \
156 result = old_result; \
158 while ((matches = 0)); \
162 /* We could be very clever and try to recycle a few bytes \
163 in the buffer instead of generating new arrays. But \
164 we are not doing this here since it's more work than \
165 it's worth. Simply let the user provide a bit bigger \
167 char **new_h_addr_list; \
168 char **new_h_aliases; \
169 int newaliases = 0; \
170 size_t newstrlen = 0; \
173 /* Count the new aliases and the length of the strings. */ \
174 while (tmp_result_buf.h_aliases[newaliases] != NULL) \
176 char *cp = tmp_result_buf.h_aliases[newaliases]; \
178 newstrlen += strlen (cp) + 1; \
180 /* If the real name is different add it also to the \
181 aliases. This means that there is a duplication \
182 in the alias list but this is really the users \
184 if (strcmp (old_result->h_name, \
185 tmp_result_buf.h_name) != 0) \
188 newstrlen += strlen (tmp_result_buf.h_name) + 1; \
191 /* Make sure bufferend is aligned. */ \
192 assert ((bufferend - (char *) 0) % sizeof (char *) == 0); \
194 /* Now we can check whether the buffer is large enough. \
195 16 is the maximal size of the IP address. */ \
196 if (bufferend + 16 + (naddrs + 2) * sizeof (char *) \
197 + roundup (newstrlen, sizeof (char *)) \
198 + (naliases + newaliases + 1) * sizeof (char *) \
199 >= buffer + buflen) \
202 *herrnop = NETDB_INTERNAL; \
203 status = NSS_STATUS_TRYAGAIN; \
208 (char **) (bufferend \
209 + roundup (newstrlen, sizeof (char *)) \
212 (char **) ((char *) new_h_addr_list \
213 + (naddrs + 2) * sizeof (char *)); \
215 /* Copy the old data in the new arrays. */ \
216 for (cnt = 0; cnt < naddrs; ++cnt) \
217 new_h_addr_list[cnt] = old_result->h_addr_list[cnt]; \
219 for (cnt = 0; cnt < naliases; ++cnt) \
220 new_h_aliases[cnt] = old_result->h_aliases[cnt]; \
222 /* Store the new strings. */ \
224 while (tmp_result_buf.h_aliases[cnt] != NULL) \
226 new_h_aliases[naliases++] = bufferend; \
227 bufferend = (__stpcpy (bufferend, \
228 tmp_result_buf.h_aliases[cnt]) \
233 if (cnt < newaliases) \
235 new_h_aliases[naliases++] = bufferend; \
236 bufferend = __stpcpy (bufferend, \
237 tmp_result_buf.h_name) + 1; \
240 /* Final NULL pointer. */ \
241 new_h_aliases[naliases] = NULL; \
243 /* Round up the buffer end address. */ \
244 bufferend += (sizeof (char *) \
245 - ((bufferend - (char *) 0) \
246 % sizeof (char *))) % sizeof (char *); \
248 /* Now the new address. */ \
249 new_h_addr_list[naddrs++] = \
250 memcpy (bufferend, tmp_result_buf.h_addr, \
251 tmp_result_buf.h_length); \
253 /* Also here a final NULL pointer. */ \
254 new_h_addr_list[naddrs] = NULL; \
256 /* Store the new array pointers. */ \
257 old_result->h_aliases = new_h_aliases; \
258 old_result->h_addr_list = new_h_addr_list; \
260 /* Compute the new buffer end. */ \
261 bufferend = (char *) &new_h_aliases[naliases + 1]; \
262 assert (bufferend <= buffer + buflen); \
264 result = old_result; \
268 if (status != NSS_STATUS_TRYAGAIN) \
269 status = NSS_STATUS_SUCCESS; \
274 internal_endent (); \
277 __libc_lock_unlock (lock); \
283 #define EXTRA_ARGS_VALUE \
284 , ((_res.options & RES_USE_INET6) ? AF_INET6 : AF_INET), \
285 ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0)
286 #include "files-XXX.c"
287 HOST_DB_LOOKUP (hostbyname
, ,,
289 LOOKUP_NAME_CASE (h_name
, h_aliases
)
293 #undef EXTRA_ARGS_VALUE
294 /* XXX Is using _res to determine whether we want to convert IPv4 addresses
295 to IPv6 addresses really the right thing to do? */
296 #define EXTRA_ARGS_VALUE \
297 , af, ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0)
298 HOST_DB_LOOKUP (hostbyname2
, ,,
300 LOOKUP_NAME_CASE (h_name
, h_aliases
)
301 }, const char *name
, int af
)
303 #undef EXTRA_ARGS_VALUE
304 /* We only need to consider IPv4 mapped addresses if the input to the
305 gethostbyaddr() function is an IPv6 address. */
306 #define EXTRA_ARGS_VALUE \
307 , af, (len == IN6ADDRSZ ? AI_V4MAPPED : 0)
308 DB_LOOKUP (hostbyaddr
, ,,
310 if (result
->h_length
== (int) len
311 && ! memcmp (addr
, result
->h_addr_list
[0], len
))
313 }, const void *addr
, socklen_t len
, int af
)