]>
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 "alloc-util.h"
30 #include "hostname-util.h"
31 #include "local-addresses.h"
34 #include "string-util.h"
37 /* We use 127.0.0.2 as IPv4 address. This has the advantage over
38 * 127.0.0.1 that it can be translated back to the local hostname. For
39 * IPv6 we use ::1 which unfortunately will not translate back to the
40 * hostname but instead something like "localhost" or so. */
42 #define LOCALADDRESS_IPV4 (htonl(0x7F000002))
43 #define LOCALADDRESS_IPV6 &in6addr_loopback
45 NSS_GETHOSTBYNAME_PROTOTYPES(myhostname
);
46 NSS_GETHOSTBYADDR_PROTOTYPES(myhostname
);
48 enum nss_status
_nss_myhostname_gethostbyname4_r(
50 struct gaih_addrtuple
**pat
,
51 char *buffer
, size_t buflen
,
52 int *errnop
, int *h_errnop
,
55 struct gaih_addrtuple
*r_tuple
, *r_tuple_prev
= NULL
;
56 _cleanup_free_
struct local_address
*addresses
= NULL
;
57 _cleanup_free_
char *hn
= NULL
;
58 const char *canonical
= NULL
;
59 int n_addresses
= 0, lo_ifi
;
60 uint32_t local_address_ipv4
;
61 struct local_address
*a
;
72 if (is_localhost(name
)) {
73 /* We respond to 'localhost', so that /etc/hosts
76 canonical
= "localhost";
77 local_address_ipv4
= htonl(INADDR_LOOPBACK
);
79 } else if (is_gateway_hostname(name
)) {
81 n_addresses
= local_gateways(NULL
, 0, AF_UNSPEC
, &addresses
);
82 if (n_addresses
<= 0) {
84 *h_errnop
= HOST_NOT_FOUND
;
85 return NSS_STATUS_NOTFOUND
;
88 canonical
= "gateway";
91 hn
= gethostname_malloc();
94 *h_errnop
= NO_RECOVERY
;
95 return NSS_STATUS_TRYAGAIN
;
98 /* We respond to our local host name, our our hostname suffixed with a single dot. */
99 if (!streq(name
, hn
) && !streq_ptr(startswith(name
, hn
), ".")) {
101 *h_errnop
= HOST_NOT_FOUND
;
102 return NSS_STATUS_NOTFOUND
;
105 n_addresses
= local_addresses(NULL
, 0, AF_UNSPEC
, &addresses
);
110 local_address_ipv4
= LOCALADDRESS_IPV4
;
113 /* If this call fails we fill in 0 as scope. Which is fine */
114 lo_ifi
= n_addresses
<= 0 ? LOOPBACK_IFINDEX
: 0;
116 l
= strlen(canonical
);
117 ms
= ALIGN(l
+1) + ALIGN(sizeof(struct gaih_addrtuple
)) * (n_addresses
> 0 ? n_addresses
: 2);
120 *h_errnop
= NO_RECOVERY
;
121 return NSS_STATUS_TRYAGAIN
;
124 /* First, fill in hostname */
126 memcpy(r_name
, canonical
, l
+1);
129 if (n_addresses
<= 0) {
130 /* Second, fill in IPv6 tuple */
131 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
132 r_tuple
->next
= r_tuple_prev
;
133 r_tuple
->name
= r_name
;
134 r_tuple
->family
= AF_INET6
;
135 memcpy(r_tuple
->addr
, LOCALADDRESS_IPV6
, 16);
136 r_tuple
->scopeid
= (uint32_t) lo_ifi
;
138 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
139 r_tuple_prev
= r_tuple
;
141 /* Third, fill in IPv4 tuple */
142 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
143 r_tuple
->next
= r_tuple_prev
;
144 r_tuple
->name
= r_name
;
145 r_tuple
->family
= AF_INET
;
146 *(uint32_t*) r_tuple
->addr
= local_address_ipv4
;
147 r_tuple
->scopeid
= (uint32_t) lo_ifi
;
149 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
150 r_tuple_prev
= r_tuple
;
153 /* Fourth, fill actual addresses in, but in backwards order */
154 for (a
= addresses
+ n_addresses
- 1, n
= 0; (int) n
< n_addresses
; n
++, a
--) {
155 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
156 r_tuple
->next
= r_tuple_prev
;
157 r_tuple
->name
= r_name
;
158 r_tuple
->family
= a
->family
;
159 r_tuple
->scopeid
= a
->ifindex
;
160 memcpy(r_tuple
->addr
, &a
->address
, 16);
162 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
163 r_tuple_prev
= r_tuple
;
166 /* Verify the size matches */
169 /* Nscd expects us to store the first record in **pat. */
171 **pat
= *r_tuple_prev
;
178 /* Explicitly reset all error variables */
180 *h_errnop
= NETDB_SUCCESS
;
183 return NSS_STATUS_SUCCESS
;
186 static enum nss_status
fill_in_hostent(
187 const char *canonical
, const char *additional
,
189 struct local_address
*addresses
, unsigned n_addresses
,
190 uint32_t local_address_ipv4
,
191 struct hostent
*result
,
192 char *buffer
, size_t buflen
,
193 int *errnop
, int *h_errnop
,
197 size_t l_canonical
, l_additional
, idx
, ms
, alen
;
198 char *r_addr
, *r_name
, *r_aliases
, *r_alias
= NULL
, *r_addr_list
;
199 struct local_address
*a
;
208 alen
= FAMILY_ADDRESS_SIZE(af
);
210 for (a
= addresses
, n
= 0, c
= 0; n
< n_addresses
; a
++, n
++)
214 l_canonical
= strlen(canonical
);
215 l_additional
= additional
? strlen(additional
) : 0;
216 ms
= ALIGN(l_canonical
+1)+
217 (additional
? ALIGN(l_additional
+1) : 0) +
219 (additional
? sizeof(char*) : 0) +
220 (c
> 0 ? c
: 1) * ALIGN(alen
) +
221 (c
> 0 ? c
+1 : 2) * sizeof(char*);
225 *h_errnop
= NO_RECOVERY
;
226 return NSS_STATUS_TRYAGAIN
;
229 /* First, fill in hostnames */
231 memcpy(r_name
, canonical
, l_canonical
+1);
232 idx
= ALIGN(l_canonical
+1);
235 r_alias
= buffer
+ idx
;
236 memcpy(r_alias
, additional
, l_additional
+1);
237 idx
+= ALIGN(l_additional
+1);
240 /* Second, create aliases array */
241 r_aliases
= buffer
+ idx
;
243 ((char**) r_aliases
)[0] = r_alias
;
244 ((char**) r_aliases
)[1] = NULL
;
245 idx
+= 2*sizeof(char*);
247 ((char**) r_aliases
)[0] = NULL
;
248 idx
+= sizeof(char*);
251 /* Third, add addresses */
252 r_addr
= buffer
+ idx
;
256 for (a
= addresses
, n
= 0; n
< n_addresses
; a
++, n
++) {
260 memcpy(r_addr
+ i
*ALIGN(alen
), &a
->address
, alen
);
265 idx
+= c
*ALIGN(alen
);
268 *(uint32_t*) r_addr
= local_address_ipv4
;
270 memcpy(r_addr
, LOCALADDRESS_IPV6
, 16);
275 /* Fourth, add address pointer array */
276 r_addr_list
= buffer
+ idx
;
280 for (i
= 0; i
< c
; i
++)
281 ((char**) r_addr_list
)[i
] = r_addr
+ i
*ALIGN(alen
);
283 ((char**) r_addr_list
)[i
] = NULL
;
284 idx
+= (c
+1) * sizeof(char*);
287 ((char**) r_addr_list
)[0] = r_addr
;
288 ((char**) r_addr_list
)[1] = NULL
;
289 idx
+= 2 * sizeof(char*);
292 /* Verify the size matches */
295 result
->h_name
= r_name
;
296 result
->h_aliases
= (char**) r_aliases
;
297 result
->h_addrtype
= af
;
298 result
->h_length
= alen
;
299 result
->h_addr_list
= (char**) r_addr_list
;
307 /* Explicitly reset all error variables */
309 *h_errnop
= NETDB_SUCCESS
;
312 return NSS_STATUS_SUCCESS
;
315 enum nss_status
_nss_myhostname_gethostbyname3_r(
318 struct hostent
*host
,
319 char *buffer
, size_t buflen
,
320 int *errnop
, int *h_errnop
,
324 _cleanup_free_
struct local_address
*addresses
= NULL
;
325 const char *canonical
, *additional
= NULL
;
326 _cleanup_free_
char *hn
= NULL
;
327 uint32_t local_address_ipv4
= 0;
339 if (af
!= AF_INET
&& af
!= AF_INET6
) {
340 *errnop
= EAFNOSUPPORT
;
342 return NSS_STATUS_UNAVAIL
;
345 if (is_localhost(name
)) {
346 canonical
= "localhost";
347 local_address_ipv4
= htonl(INADDR_LOOPBACK
);
349 } else if (is_gateway_hostname(name
)) {
351 n_addresses
= local_gateways(NULL
, 0, af
, &addresses
);
352 if (n_addresses
<= 0) {
354 *h_errnop
= HOST_NOT_FOUND
;
355 return NSS_STATUS_NOTFOUND
;
358 canonical
= "gateway";
361 hn
= gethostname_malloc();
364 *h_errnop
= NO_RECOVERY
;
365 return NSS_STATUS_TRYAGAIN
;
368 if (!streq(name
, hn
) && !streq_ptr(startswith(name
, hn
), ".")) {
370 *h_errnop
= HOST_NOT_FOUND
;
371 return NSS_STATUS_NOTFOUND
;
374 n_addresses
= local_addresses(NULL
, 0, af
, &addresses
);
379 additional
= n_addresses
<= 0 && af
== AF_INET6
? "localhost" : NULL
;
380 local_address_ipv4
= LOCALADDRESS_IPV4
;
383 return fill_in_hostent(
384 canonical
, additional
,
386 addresses
, n_addresses
,
395 enum nss_status
_nss_myhostname_gethostbyaddr2_r(
396 const void* addr
, socklen_t len
,
398 struct hostent
*host
,
399 char *buffer
, size_t buflen
,
400 int *errnop
, int *h_errnop
,
403 const char *canonical
= NULL
, *additional
= NULL
;
404 uint32_t local_address_ipv4
= LOCALADDRESS_IPV4
;
405 _cleanup_free_
struct local_address
*addresses
= NULL
;
406 _cleanup_free_
char *hn
= NULL
;
408 struct local_address
*a
;
409 bool additional_from_hostname
= false;
418 if (!IN_SET(af
, AF_INET
, AF_INET6
)) {
419 *errnop
= EAFNOSUPPORT
;
421 return NSS_STATUS_UNAVAIL
;
424 if (len
!= FAMILY_ADDRESS_SIZE(af
)) {
426 *h_errnop
= NO_RECOVERY
;
427 return NSS_STATUS_UNAVAIL
;
431 if ((*(uint32_t*) addr
) == LOCALADDRESS_IPV4
)
434 if ((*(uint32_t*) addr
) == htonl(INADDR_LOOPBACK
)) {
435 canonical
= "localhost";
436 local_address_ipv4
= htonl(INADDR_LOOPBACK
);
441 assert(af
== AF_INET6
);
443 if (memcmp(addr
, LOCALADDRESS_IPV6
, 16) == 0) {
444 canonical
= "localhost";
445 additional_from_hostname
= true;
450 n_addresses
= local_addresses(NULL
, 0, AF_UNSPEC
, &addresses
);
451 if (n_addresses
> 0) {
452 for (a
= addresses
, n
= 0; (int) n
< n_addresses
; n
++, a
++) {
456 if (memcmp(addr
, &a
->address
, FAMILY_ADDRESS_SIZE(af
)) == 0)
461 addresses
= mfree(addresses
);
463 n_addresses
= local_gateways(NULL
, 0, AF_UNSPEC
, &addresses
);
464 if (n_addresses
> 0) {
465 for (a
= addresses
, n
= 0; (int) n
< n_addresses
; n
++, a
++) {
469 if (memcmp(addr
, &a
->address
, FAMILY_ADDRESS_SIZE(af
)) == 0) {
470 canonical
= "gateway";
477 *h_errnop
= HOST_NOT_FOUND
;
479 return NSS_STATUS_NOTFOUND
;
482 if (!canonical
|| (!additional
&& additional_from_hostname
)) {
483 hn
= gethostname_malloc();
486 *h_errnop
= NO_RECOVERY
;
487 return NSS_STATUS_TRYAGAIN
;
493 if (!additional
&& additional_from_hostname
)
497 return fill_in_hostent(
498 canonical
, additional
,
500 addresses
, n_addresses
,
509 NSS_GETHOSTBYNAME_FALLBACKS(myhostname
);
510 NSS_GETHOSTBYADDR_FALLBACKS(myhostname
);