]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/nss-myhostname/nss-myhostname.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2008-2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
29 #include "hostname-util.h"
30 #include "local-addresses.h"
33 #include "string-util.h"
36 /* We use 127.0.0.2 as IPv4 address. This has the advantage over
37 * 127.0.0.1 that it can be translated back to the local hostname. For
38 * IPv6 we use ::1 which unfortunately will not translate back to the
39 * hostname but instead something like "localhost" or so. */
41 #define LOCALADDRESS_IPV4 (htonl(0x7F000002))
42 #define LOCALADDRESS_IPV6 &in6addr_loopback
44 NSS_GETHOSTBYNAME_PROTOTYPES(myhostname
);
45 NSS_GETHOSTBYADDR_PROTOTYPES(myhostname
);
47 enum nss_status
_nss_myhostname_gethostbyname4_r(
49 struct gaih_addrtuple
**pat
,
50 char *buffer
, size_t buflen
,
51 int *errnop
, int *h_errnop
,
54 struct gaih_addrtuple
*r_tuple
, *r_tuple_prev
= NULL
;
55 _cleanup_free_
struct local_address
*addresses
= NULL
;
56 _cleanup_free_
char *hn
= NULL
;
57 const char *canonical
= NULL
;
58 int n_addresses
= 0, lo_ifi
;
59 uint32_t local_address_ipv4
;
60 struct local_address
*a
;
71 if (is_localhost(name
)) {
72 /* We respond to 'localhost', so that /etc/hosts
75 canonical
= "localhost";
76 local_address_ipv4
= htonl(INADDR_LOOPBACK
);
78 } else if (is_gateway_hostname(name
)) {
80 n_addresses
= local_gateways(NULL
, 0, AF_UNSPEC
, &addresses
);
81 if (n_addresses
<= 0) {
83 *h_errnop
= HOST_NOT_FOUND
;
84 return NSS_STATUS_NOTFOUND
;
87 canonical
= "gateway";
90 hn
= gethostname_malloc();
93 *h_errnop
= NO_RECOVERY
;
94 return NSS_STATUS_TRYAGAIN
;
97 /* We respond to our local host name, our our hostname suffixed with a single dot. */
98 if (!streq(name
, hn
) && !streq_ptr(startswith(name
, hn
), ".")) {
100 *h_errnop
= HOST_NOT_FOUND
;
101 return NSS_STATUS_NOTFOUND
;
104 n_addresses
= local_addresses(NULL
, 0, AF_UNSPEC
, &addresses
);
109 local_address_ipv4
= LOCALADDRESS_IPV4
;
112 /* If this call fails we fill in 0 as scope. Which is fine */
113 lo_ifi
= n_addresses
<= 0 ? LOOPBACK_IFINDEX
: 0;
115 l
= strlen(canonical
);
116 ms
= ALIGN(l
+1) + ALIGN(sizeof(struct gaih_addrtuple
)) * (n_addresses
> 0 ? n_addresses
: 2);
119 *h_errnop
= NO_RECOVERY
;
120 return NSS_STATUS_TRYAGAIN
;
123 /* First, fill in hostname */
125 memcpy(r_name
, canonical
, l
+1);
128 if (n_addresses
<= 0) {
129 /* Second, fill in IPv6 tuple */
130 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
131 r_tuple
->next
= r_tuple_prev
;
132 r_tuple
->name
= r_name
;
133 r_tuple
->family
= AF_INET6
;
134 memcpy(r_tuple
->addr
, LOCALADDRESS_IPV6
, 16);
135 r_tuple
->scopeid
= (uint32_t) lo_ifi
;
137 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
138 r_tuple_prev
= r_tuple
;
140 /* Third, fill in IPv4 tuple */
141 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
142 r_tuple
->next
= r_tuple_prev
;
143 r_tuple
->name
= r_name
;
144 r_tuple
->family
= AF_INET
;
145 *(uint32_t*) r_tuple
->addr
= local_address_ipv4
;
146 r_tuple
->scopeid
= (uint32_t) lo_ifi
;
148 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
149 r_tuple_prev
= r_tuple
;
152 /* Fourth, fill actual addresses in, but in backwards order */
153 for (a
= addresses
+ n_addresses
- 1, n
= 0; (int) n
< n_addresses
; n
++, a
--) {
154 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
155 r_tuple
->next
= r_tuple_prev
;
156 r_tuple
->name
= r_name
;
157 r_tuple
->family
= a
->family
;
158 r_tuple
->scopeid
= a
->ifindex
;
159 memcpy(r_tuple
->addr
, &a
->address
, 16);
161 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
162 r_tuple_prev
= r_tuple
;
165 /* Verify the size matches */
168 /* Nscd expects us to store the first record in **pat. */
170 **pat
= *r_tuple_prev
;
177 /* Explicitly reset all error variables */
179 *h_errnop
= NETDB_SUCCESS
;
182 return NSS_STATUS_SUCCESS
;
185 static enum nss_status
fill_in_hostent(
186 const char *canonical
, const char *additional
,
188 struct local_address
*addresses
, unsigned n_addresses
,
189 uint32_t local_address_ipv4
,
190 struct hostent
*result
,
191 char *buffer
, size_t buflen
,
192 int *errnop
, int *h_errnop
,
196 size_t l_canonical
, l_additional
, idx
, ms
, alen
;
197 char *r_addr
, *r_name
, *r_aliases
, *r_alias
= NULL
, *r_addr_list
;
198 struct local_address
*a
;
207 alen
= FAMILY_ADDRESS_SIZE(af
);
209 for (a
= addresses
, n
= 0, c
= 0; n
< n_addresses
; a
++, n
++)
213 l_canonical
= strlen(canonical
);
214 l_additional
= additional
? strlen(additional
) : 0;
215 ms
= ALIGN(l_canonical
+1)+
216 (additional
? ALIGN(l_additional
+1) : 0) +
218 (additional
? sizeof(char*) : 0) +
219 (c
> 0 ? c
: 1) * ALIGN(alen
) +
220 (c
> 0 ? c
+1 : 2) * sizeof(char*);
224 *h_errnop
= NO_RECOVERY
;
225 return NSS_STATUS_TRYAGAIN
;
228 /* First, fill in hostnames */
230 memcpy(r_name
, canonical
, l_canonical
+1);
231 idx
= ALIGN(l_canonical
+1);
234 r_alias
= buffer
+ idx
;
235 memcpy(r_alias
, additional
, l_additional
+1);
236 idx
+= ALIGN(l_additional
+1);
239 /* Second, create aliases array */
240 r_aliases
= buffer
+ idx
;
242 ((char**) r_aliases
)[0] = r_alias
;
243 ((char**) r_aliases
)[1] = NULL
;
244 idx
+= 2*sizeof(char*);
246 ((char**) r_aliases
)[0] = NULL
;
247 idx
+= sizeof(char*);
250 /* Third, add addresses */
251 r_addr
= buffer
+ idx
;
255 for (a
= addresses
, n
= 0; n
< n_addresses
; a
++, n
++) {
259 memcpy(r_addr
+ i
*ALIGN(alen
), &a
->address
, alen
);
264 idx
+= c
*ALIGN(alen
);
267 *(uint32_t*) r_addr
= local_address_ipv4
;
269 memcpy(r_addr
, LOCALADDRESS_IPV6
, 16);
274 /* Fourth, add address pointer array */
275 r_addr_list
= buffer
+ idx
;
279 for (i
= 0; i
< c
; i
++)
280 ((char**) r_addr_list
)[i
] = r_addr
+ i
*ALIGN(alen
);
282 ((char**) r_addr_list
)[i
] = NULL
;
283 idx
+= (c
+1) * sizeof(char*);
286 ((char**) r_addr_list
)[0] = r_addr
;
287 ((char**) r_addr_list
)[1] = NULL
;
288 idx
+= 2 * sizeof(char*);
291 /* Verify the size matches */
294 result
->h_name
= r_name
;
295 result
->h_aliases
= (char**) r_aliases
;
296 result
->h_addrtype
= af
;
297 result
->h_length
= alen
;
298 result
->h_addr_list
= (char**) r_addr_list
;
306 /* Explicitly reset all error variables */
308 *h_errnop
= NETDB_SUCCESS
;
311 return NSS_STATUS_SUCCESS
;
314 enum nss_status
_nss_myhostname_gethostbyname3_r(
317 struct hostent
*host
,
318 char *buffer
, size_t buflen
,
319 int *errnop
, int *h_errnop
,
323 _cleanup_free_
struct local_address
*addresses
= NULL
;
324 const char *canonical
, *additional
= NULL
;
325 _cleanup_free_
char *hn
= NULL
;
326 uint32_t local_address_ipv4
= 0;
338 if (af
!= AF_INET
&& af
!= AF_INET6
) {
339 *errnop
= EAFNOSUPPORT
;
341 return NSS_STATUS_UNAVAIL
;
344 if (is_localhost(name
)) {
345 canonical
= "localhost";
346 local_address_ipv4
= htonl(INADDR_LOOPBACK
);
348 } else if (is_gateway_hostname(name
)) {
350 n_addresses
= local_gateways(NULL
, 0, af
, &addresses
);
351 if (n_addresses
<= 0) {
353 *h_errnop
= HOST_NOT_FOUND
;
354 return NSS_STATUS_NOTFOUND
;
357 canonical
= "gateway";
360 hn
= gethostname_malloc();
363 *h_errnop
= NO_RECOVERY
;
364 return NSS_STATUS_TRYAGAIN
;
367 if (!streq(name
, hn
) && !streq_ptr(startswith(name
, hn
), ".")) {
369 *h_errnop
= HOST_NOT_FOUND
;
370 return NSS_STATUS_NOTFOUND
;
373 n_addresses
= local_addresses(NULL
, 0, af
, &addresses
);
378 additional
= n_addresses
<= 0 && af
== AF_INET6
? "localhost" : NULL
;
379 local_address_ipv4
= LOCALADDRESS_IPV4
;
382 return fill_in_hostent(
383 canonical
, additional
,
385 addresses
, n_addresses
,
394 enum nss_status
_nss_myhostname_gethostbyaddr2_r(
395 const void* addr
, socklen_t len
,
397 struct hostent
*host
,
398 char *buffer
, size_t buflen
,
399 int *errnop
, int *h_errnop
,
402 const char *canonical
= NULL
, *additional
= NULL
;
403 uint32_t local_address_ipv4
= LOCALADDRESS_IPV4
;
404 _cleanup_free_
struct local_address
*addresses
= NULL
;
405 _cleanup_free_
char *hn
= NULL
;
407 struct local_address
*a
;
408 bool additional_from_hostname
= false;
417 if (!IN_SET(af
, AF_INET
, AF_INET6
)) {
418 *errnop
= EAFNOSUPPORT
;
420 return NSS_STATUS_UNAVAIL
;
423 if (len
!= FAMILY_ADDRESS_SIZE(af
)) {
425 *h_errnop
= NO_RECOVERY
;
426 return NSS_STATUS_UNAVAIL
;
430 if ((*(uint32_t*) addr
) == LOCALADDRESS_IPV4
)
433 if ((*(uint32_t*) addr
) == htonl(INADDR_LOOPBACK
)) {
434 canonical
= "localhost";
435 local_address_ipv4
= htonl(INADDR_LOOPBACK
);
440 assert(af
== AF_INET6
);
442 if (memcmp(addr
, LOCALADDRESS_IPV6
, 16) == 0) {
443 canonical
= "localhost";
444 additional_from_hostname
= true;
449 n_addresses
= local_addresses(NULL
, 0, AF_UNSPEC
, &addresses
);
450 if (n_addresses
> 0) {
451 for (a
= addresses
, n
= 0; (int) n
< n_addresses
; n
++, a
++) {
455 if (memcmp(addr
, &a
->address
, FAMILY_ADDRESS_SIZE(af
)) == 0)
460 addresses
= mfree(addresses
);
462 n_addresses
= local_gateways(NULL
, 0, AF_UNSPEC
, &addresses
);
463 if (n_addresses
> 0) {
464 for (a
= addresses
, n
= 0; (int) n
< n_addresses
; n
++, a
++) {
468 if (memcmp(addr
, &a
->address
, FAMILY_ADDRESS_SIZE(af
)) == 0) {
469 canonical
= "gateway";
476 *h_errnop
= HOST_NOT_FOUND
;
478 return NSS_STATUS_NOTFOUND
;
481 if (!canonical
|| (!additional
&& additional_from_hostname
)) {
482 hn
= gethostname_malloc();
485 *h_errnop
= NO_RECOVERY
;
486 return NSS_STATUS_TRYAGAIN
;
492 if (!additional
&& additional_from_hostname
)
496 return fill_in_hostent(
497 canonical
, additional
,
499 addresses
, n_addresses
,
508 NSS_GETHOSTBYNAME_FALLBACKS(myhostname
);
509 NSS_GETHOSTBYADDR_FALLBACKS(myhostname
);