]>
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 "signal-util.h"
35 #include "string-util.h"
38 /* We use 127.0.0.2 as IPv4 address. This has the advantage over
39 * 127.0.0.1 that it can be translated back to the local hostname. For
40 * IPv6 we use ::1 which unfortunately will not translate back to the
41 * hostname but instead something like "localhost" or so. */
43 #define LOCALADDRESS_IPV4 (htonl(0x7F000002))
44 #define LOCALADDRESS_IPV6 &in6addr_loopback
46 NSS_GETHOSTBYNAME_PROTOTYPES(myhostname
);
47 NSS_GETHOSTBYADDR_PROTOTYPES(myhostname
);
49 enum nss_status
_nss_myhostname_gethostbyname4_r(
51 struct gaih_addrtuple
**pat
,
52 char *buffer
, size_t buflen
,
53 int *errnop
, int *h_errnop
,
56 struct gaih_addrtuple
*r_tuple
, *r_tuple_prev
= NULL
;
57 _cleanup_free_
struct local_address
*addresses
= NULL
;
58 _cleanup_free_
char *hn
= NULL
;
59 const char *canonical
= NULL
;
60 int n_addresses
= 0, lo_ifi
;
61 uint32_t local_address_ipv4
;
62 struct local_address
*a
;
67 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
75 if (is_localhost(name
)) {
76 /* We respond to 'localhost', so that /etc/hosts
79 canonical
= "localhost";
80 local_address_ipv4
= htonl(INADDR_LOOPBACK
);
82 } else if (is_gateway_hostname(name
)) {
84 n_addresses
= local_gateways(NULL
, 0, AF_UNSPEC
, &addresses
);
85 if (n_addresses
<= 0) {
87 *h_errnop
= HOST_NOT_FOUND
;
88 return NSS_STATUS_NOTFOUND
;
91 canonical
= "gateway";
94 hn
= gethostname_malloc();
97 *h_errnop
= NO_RECOVERY
;
98 return NSS_STATUS_TRYAGAIN
;
101 /* We respond to our local host name, our our hostname suffixed with a single dot. */
102 if (!streq(name
, hn
) && !streq_ptr(startswith(name
, hn
), ".")) {
104 *h_errnop
= HOST_NOT_FOUND
;
105 return NSS_STATUS_NOTFOUND
;
108 n_addresses
= local_addresses(NULL
, 0, AF_UNSPEC
, &addresses
);
113 local_address_ipv4
= LOCALADDRESS_IPV4
;
116 /* If this call fails we fill in 0 as scope. Which is fine */
117 lo_ifi
= n_addresses
<= 0 ? LOOPBACK_IFINDEX
: 0;
119 l
= strlen(canonical
);
120 ms
= ALIGN(l
+1) + ALIGN(sizeof(struct gaih_addrtuple
)) * (n_addresses
> 0 ? n_addresses
: 2);
123 *h_errnop
= NO_RECOVERY
;
124 return NSS_STATUS_TRYAGAIN
;
127 /* First, fill in hostname */
129 memcpy(r_name
, canonical
, l
+1);
132 if (n_addresses
<= 0) {
133 /* Second, fill in IPv6 tuple */
134 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
135 r_tuple
->next
= r_tuple_prev
;
136 r_tuple
->name
= r_name
;
137 r_tuple
->family
= AF_INET6
;
138 memcpy(r_tuple
->addr
, LOCALADDRESS_IPV6
, 16);
139 r_tuple
->scopeid
= (uint32_t) lo_ifi
;
141 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
142 r_tuple_prev
= r_tuple
;
144 /* Third, fill in IPv4 tuple */
145 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
146 r_tuple
->next
= r_tuple_prev
;
147 r_tuple
->name
= r_name
;
148 r_tuple
->family
= AF_INET
;
149 *(uint32_t*) r_tuple
->addr
= local_address_ipv4
;
150 r_tuple
->scopeid
= (uint32_t) lo_ifi
;
152 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
153 r_tuple_prev
= r_tuple
;
156 /* Fourth, fill actual addresses in, but in backwards order */
157 for (a
= addresses
+ n_addresses
- 1, n
= 0; (int) n
< n_addresses
; n
++, a
--) {
158 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
159 r_tuple
->next
= r_tuple_prev
;
160 r_tuple
->name
= r_name
;
161 r_tuple
->family
= a
->family
;
162 r_tuple
->scopeid
= a
->ifindex
;
163 memcpy(r_tuple
->addr
, &a
->address
, 16);
165 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
166 r_tuple_prev
= r_tuple
;
169 /* Verify the size matches */
172 /* Nscd expects us to store the first record in **pat. */
174 **pat
= *r_tuple_prev
;
181 /* Explicitly reset all error variables */
183 *h_errnop
= NETDB_SUCCESS
;
186 return NSS_STATUS_SUCCESS
;
189 static enum nss_status
fill_in_hostent(
190 const char *canonical
, const char *additional
,
192 struct local_address
*addresses
, unsigned n_addresses
,
193 uint32_t local_address_ipv4
,
194 struct hostent
*result
,
195 char *buffer
, size_t buflen
,
196 int *errnop
, int *h_errnop
,
200 size_t l_canonical
, l_additional
, idx
, ms
, alen
;
201 char *r_addr
, *r_name
, *r_aliases
, *r_alias
= NULL
, *r_addr_list
;
202 struct local_address
*a
;
211 alen
= FAMILY_ADDRESS_SIZE(af
);
213 for (a
= addresses
, n
= 0, c
= 0; n
< n_addresses
; a
++, n
++)
217 l_canonical
= strlen(canonical
);
218 l_additional
= additional
? strlen(additional
) : 0;
219 ms
= ALIGN(l_canonical
+1)+
220 (additional
? ALIGN(l_additional
+1) : 0) +
222 (additional
? sizeof(char*) : 0) +
223 (c
> 0 ? c
: 1) * ALIGN(alen
) +
224 (c
> 0 ? c
+1 : 2) * sizeof(char*);
228 *h_errnop
= NO_RECOVERY
;
229 return NSS_STATUS_TRYAGAIN
;
232 /* First, fill in hostnames */
234 memcpy(r_name
, canonical
, l_canonical
+1);
235 idx
= ALIGN(l_canonical
+1);
238 r_alias
= buffer
+ idx
;
239 memcpy(r_alias
, additional
, l_additional
+1);
240 idx
+= ALIGN(l_additional
+1);
243 /* Second, create aliases array */
244 r_aliases
= buffer
+ idx
;
246 ((char**) r_aliases
)[0] = r_alias
;
247 ((char**) r_aliases
)[1] = NULL
;
248 idx
+= 2*sizeof(char*);
250 ((char**) r_aliases
)[0] = NULL
;
251 idx
+= sizeof(char*);
254 /* Third, add addresses */
255 r_addr
= buffer
+ idx
;
259 for (a
= addresses
, n
= 0; n
< n_addresses
; a
++, n
++) {
263 memcpy(r_addr
+ i
*ALIGN(alen
), &a
->address
, alen
);
268 idx
+= c
*ALIGN(alen
);
271 *(uint32_t*) r_addr
= local_address_ipv4
;
273 memcpy(r_addr
, LOCALADDRESS_IPV6
, 16);
278 /* Fourth, add address pointer array */
279 r_addr_list
= buffer
+ idx
;
283 for (i
= 0; i
< c
; i
++)
284 ((char**) r_addr_list
)[i
] = r_addr
+ i
*ALIGN(alen
);
286 ((char**) r_addr_list
)[i
] = NULL
;
287 idx
+= (c
+1) * sizeof(char*);
290 ((char**) r_addr_list
)[0] = r_addr
;
291 ((char**) r_addr_list
)[1] = NULL
;
292 idx
+= 2 * sizeof(char*);
295 /* Verify the size matches */
298 result
->h_name
= r_name
;
299 result
->h_aliases
= (char**) r_aliases
;
300 result
->h_addrtype
= af
;
301 result
->h_length
= alen
;
302 result
->h_addr_list
= (char**) r_addr_list
;
310 /* Explicitly reset all error variables */
312 *h_errnop
= NETDB_SUCCESS
;
315 return NSS_STATUS_SUCCESS
;
318 enum nss_status
_nss_myhostname_gethostbyname3_r(
321 struct hostent
*host
,
322 char *buffer
, size_t buflen
,
323 int *errnop
, int *h_errnop
,
327 _cleanup_free_
struct local_address
*addresses
= NULL
;
328 const char *canonical
, *additional
= NULL
;
329 _cleanup_free_
char *hn
= NULL
;
330 uint32_t local_address_ipv4
= 0;
333 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
344 if (af
!= AF_INET
&& af
!= AF_INET6
) {
345 *errnop
= EAFNOSUPPORT
;
347 return NSS_STATUS_UNAVAIL
;
350 if (is_localhost(name
)) {
351 canonical
= "localhost";
352 local_address_ipv4
= htonl(INADDR_LOOPBACK
);
354 } else if (is_gateway_hostname(name
)) {
356 n_addresses
= local_gateways(NULL
, 0, af
, &addresses
);
357 if (n_addresses
<= 0) {
359 *h_errnop
= HOST_NOT_FOUND
;
360 return NSS_STATUS_NOTFOUND
;
363 canonical
= "gateway";
366 hn
= gethostname_malloc();
369 *h_errnop
= NO_RECOVERY
;
370 return NSS_STATUS_TRYAGAIN
;
373 if (!streq(name
, hn
) && !streq_ptr(startswith(name
, hn
), ".")) {
375 *h_errnop
= HOST_NOT_FOUND
;
376 return NSS_STATUS_NOTFOUND
;
379 n_addresses
= local_addresses(NULL
, 0, af
, &addresses
);
384 additional
= n_addresses
<= 0 && af
== AF_INET6
? "localhost" : NULL
;
385 local_address_ipv4
= LOCALADDRESS_IPV4
;
388 return fill_in_hostent(
389 canonical
, additional
,
391 addresses
, n_addresses
,
400 enum nss_status
_nss_myhostname_gethostbyaddr2_r(
401 const void* addr
, socklen_t len
,
403 struct hostent
*host
,
404 char *buffer
, size_t buflen
,
405 int *errnop
, int *h_errnop
,
408 const char *canonical
= NULL
, *additional
= NULL
;
409 uint32_t local_address_ipv4
= LOCALADDRESS_IPV4
;
410 _cleanup_free_
struct local_address
*addresses
= NULL
;
411 _cleanup_free_
char *hn
= NULL
;
413 struct local_address
*a
;
414 bool additional_from_hostname
= false;
417 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK
);
425 if (!IN_SET(af
, AF_INET
, AF_INET6
)) {
426 *errnop
= EAFNOSUPPORT
;
428 return NSS_STATUS_UNAVAIL
;
431 if (len
!= FAMILY_ADDRESS_SIZE(af
)) {
433 *h_errnop
= NO_RECOVERY
;
434 return NSS_STATUS_UNAVAIL
;
438 if ((*(uint32_t*) addr
) == LOCALADDRESS_IPV4
)
441 if ((*(uint32_t*) addr
) == htonl(INADDR_LOOPBACK
)) {
442 canonical
= "localhost";
443 local_address_ipv4
= htonl(INADDR_LOOPBACK
);
448 assert(af
== AF_INET6
);
450 if (memcmp(addr
, LOCALADDRESS_IPV6
, 16) == 0) {
451 canonical
= "localhost";
452 additional_from_hostname
= true;
457 n_addresses
= local_addresses(NULL
, 0, AF_UNSPEC
, &addresses
);
458 if (n_addresses
> 0) {
459 for (a
= addresses
, n
= 0; (int) n
< n_addresses
; n
++, a
++) {
463 if (memcmp(addr
, &a
->address
, FAMILY_ADDRESS_SIZE(af
)) == 0)
468 addresses
= mfree(addresses
);
470 n_addresses
= local_gateways(NULL
, 0, AF_UNSPEC
, &addresses
);
471 if (n_addresses
> 0) {
472 for (a
= addresses
, n
= 0; (int) n
< n_addresses
; n
++, a
++) {
476 if (memcmp(addr
, &a
->address
, FAMILY_ADDRESS_SIZE(af
)) == 0) {
477 canonical
= "gateway";
484 *h_errnop
= HOST_NOT_FOUND
;
486 return NSS_STATUS_NOTFOUND
;
489 if (!canonical
|| (!additional
&& additional_from_hostname
)) {
490 hn
= gethostname_malloc();
493 *h_errnop
= NO_RECOVERY
;
494 return NSS_STATUS_TRYAGAIN
;
500 if (!additional
&& additional_from_hostname
)
504 return fill_in_hostent(
505 canonical
, additional
,
507 addresses
, n_addresses
,
516 NSS_GETHOSTBYNAME_FALLBACKS(myhostname
);
517 NSS_GETHOSTBYADDR_FALLBACKS(myhostname
);