]>
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 "local-addresses.h"
32 #include "hostname-util.h"
35 /* We use 127.0.0.2 as IPv4 address. This has the advantage over
36 * 127.0.0.1 that it can be translated back to the local hostname. For
37 * IPv6 we use ::1 which unfortunately will not translate back to the
38 * hostname but instead something like "localhost" or so. */
40 #define LOCALADDRESS_IPV4 (htonl(0x7F000002))
41 #define LOCALADDRESS_IPV6 &in6addr_loopback
42 #define LOOPBACK_INTERFACE "lo"
44 NSS_GETHOSTBYNAME_PROTOTYPES(myhostname
);
45 NSS_GETHOSTBYADDR_PROTOTYPES(myhostname
);
47 static bool is_gateway(const char *hostname
) {
50 return streq(hostname
, "gateway") ||
51 streq(hostname
, "gateway.");
54 enum nss_status
_nss_myhostname_gethostbyname4_r(
56 struct gaih_addrtuple
**pat
,
57 char *buffer
, size_t buflen
,
58 int *errnop
, int *h_errnop
,
61 struct gaih_addrtuple
*r_tuple
, *r_tuple_prev
= NULL
;
62 _cleanup_free_
struct local_address
*addresses
= NULL
;
63 _cleanup_free_
char *hn
= NULL
;
64 const char *canonical
= NULL
;
65 int n_addresses
= 0, lo_ifi
;
66 uint32_t local_address_ipv4
;
67 struct local_address
*a
;
78 if (is_localhost(name
)) {
79 /* We respond to 'localhost', so that /etc/hosts
82 canonical
= "localhost";
83 local_address_ipv4
= htonl(INADDR_LOOPBACK
);
85 } else if (is_gateway(name
)) {
87 n_addresses
= local_gateways(NULL
, 0, AF_UNSPEC
, &addresses
);
88 if (n_addresses
<= 0) {
90 *h_errnop
= HOST_NOT_FOUND
;
91 return NSS_STATUS_NOTFOUND
;
94 canonical
= "gateway";
97 hn
= gethostname_malloc();
100 *h_errnop
= NO_RECOVERY
;
101 return NSS_STATUS_TRYAGAIN
;
104 /* We respond to our local host name, our our hostname suffixed with a single dot. */
105 if (!streq(name
, hn
) && !streq_ptr(startswith(name
, hn
), ".")) {
107 *h_errnop
= HOST_NOT_FOUND
;
108 return NSS_STATUS_NOTFOUND
;
111 n_addresses
= local_addresses(NULL
, 0, AF_UNSPEC
, &addresses
);
116 local_address_ipv4
= LOCALADDRESS_IPV4
;
119 /* If this call fails we fill in 0 as scope. Which is fine */
120 lo_ifi
= n_addresses
<= 0 ? if_nametoindex(LOOPBACK_INTERFACE
) : 0;
122 l
= strlen(canonical
);
123 ms
= ALIGN(l
+1) + ALIGN(sizeof(struct gaih_addrtuple
)) * (n_addresses
> 0 ? n_addresses
: 2);
126 *h_errnop
= NO_RECOVERY
;
127 return NSS_STATUS_TRYAGAIN
;
130 /* First, fill in hostname */
132 memcpy(r_name
, canonical
, l
+1);
135 if (n_addresses
<= 0) {
136 /* Second, fill in IPv6 tuple */
137 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
138 r_tuple
->next
= r_tuple_prev
;
139 r_tuple
->name
= r_name
;
140 r_tuple
->family
= AF_INET6
;
141 memcpy(r_tuple
->addr
, LOCALADDRESS_IPV6
, 16);
142 r_tuple
->scopeid
= (uint32_t) lo_ifi
;
144 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
145 r_tuple_prev
= r_tuple
;
147 /* Third, fill in IPv4 tuple */
148 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
149 r_tuple
->next
= r_tuple_prev
;
150 r_tuple
->name
= r_name
;
151 r_tuple
->family
= AF_INET
;
152 *(uint32_t*) r_tuple
->addr
= local_address_ipv4
;
153 r_tuple
->scopeid
= (uint32_t) lo_ifi
;
155 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
156 r_tuple_prev
= r_tuple
;
159 /* Fourth, fill actual addresses in, but in backwards order */
160 for (a
= addresses
+ n_addresses
- 1, n
= 0; (int) n
< n_addresses
; n
++, a
--) {
161 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
162 r_tuple
->next
= r_tuple_prev
;
163 r_tuple
->name
= r_name
;
164 r_tuple
->family
= a
->family
;
165 r_tuple
->scopeid
= a
->ifindex
;
166 memcpy(r_tuple
->addr
, &a
->address
, 16);
168 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
169 r_tuple_prev
= r_tuple
;
172 /* Verify the size matches */
175 /* Nscd expects us to store the first record in **pat. */
177 **pat
= *r_tuple_prev
;
184 /* Explicitly reset all error variables */
186 *h_errnop
= NETDB_SUCCESS
;
189 return NSS_STATUS_SUCCESS
;
192 static enum nss_status
fill_in_hostent(
193 const char *canonical
, const char *additional
,
195 struct local_address
*addresses
, unsigned n_addresses
,
196 uint32_t local_address_ipv4
,
197 struct hostent
*result
,
198 char *buffer
, size_t buflen
,
199 int *errnop
, int *h_errnop
,
203 size_t l_canonical
, l_additional
, idx
, ms
, alen
;
204 char *r_addr
, *r_name
, *r_aliases
, *r_alias
= NULL
, *r_addr_list
;
205 struct local_address
*a
;
214 alen
= FAMILY_ADDRESS_SIZE(af
);
216 for (a
= addresses
, n
= 0, c
= 0; n
< n_addresses
; a
++, n
++)
220 l_canonical
= strlen(canonical
);
221 l_additional
= additional
? strlen(additional
) : 0;
222 ms
= ALIGN(l_canonical
+1)+
223 (additional
? ALIGN(l_additional
+1) : 0) +
225 (additional
? sizeof(char*) : 0) +
226 (c
> 0 ? c
: 1) * ALIGN(alen
) +
227 (c
> 0 ? c
+1 : 2) * sizeof(char*);
231 *h_errnop
= NO_RECOVERY
;
232 return NSS_STATUS_TRYAGAIN
;
235 /* First, fill in hostnames */
237 memcpy(r_name
, canonical
, l_canonical
+1);
238 idx
= ALIGN(l_canonical
+1);
241 r_alias
= buffer
+ idx
;
242 memcpy(r_alias
, additional
, l_additional
+1);
243 idx
+= ALIGN(l_additional
+1);
246 /* Second, create aliases array */
247 r_aliases
= buffer
+ idx
;
249 ((char**) r_aliases
)[0] = r_alias
;
250 ((char**) r_aliases
)[1] = NULL
;
251 idx
+= 2*sizeof(char*);
253 ((char**) r_aliases
)[0] = NULL
;
254 idx
+= sizeof(char*);
257 /* Third, add addresses */
258 r_addr
= buffer
+ idx
;
262 for (a
= addresses
, n
= 0; n
< n_addresses
; a
++, n
++) {
266 memcpy(r_addr
+ i
*ALIGN(alen
), &a
->address
, alen
);
271 idx
+= c
*ALIGN(alen
);
274 *(uint32_t*) r_addr
= local_address_ipv4
;
276 memcpy(r_addr
, LOCALADDRESS_IPV6
, 16);
281 /* Fourth, add address pointer array */
282 r_addr_list
= buffer
+ idx
;
286 for (i
= 0; i
< c
; i
++)
287 ((char**) r_addr_list
)[i
] = r_addr
+ i
*ALIGN(alen
);
289 ((char**) r_addr_list
)[i
] = NULL
;
290 idx
+= (c
+1) * sizeof(char*);
293 ((char**) r_addr_list
)[0] = r_addr
;
294 ((char**) r_addr_list
)[1] = NULL
;
295 idx
+= 2 * sizeof(char*);
298 /* Verify the size matches */
301 result
->h_name
= r_name
;
302 result
->h_aliases
= (char**) r_aliases
;
303 result
->h_addrtype
= af
;
304 result
->h_length
= alen
;
305 result
->h_addr_list
= (char**) r_addr_list
;
313 /* Explicitly reset all error variables */
315 *h_errnop
= NETDB_SUCCESS
;
318 return NSS_STATUS_SUCCESS
;
321 enum nss_status
_nss_myhostname_gethostbyname3_r(
324 struct hostent
*host
,
325 char *buffer
, size_t buflen
,
326 int *errnop
, int *h_errnop
,
330 _cleanup_free_
struct local_address
*addresses
= NULL
;
331 const char *canonical
, *additional
= NULL
;
332 _cleanup_free_
char *hn
= NULL
;
333 uint32_t local_address_ipv4
= 0;
345 if (af
!= AF_INET
&& af
!= AF_INET6
) {
346 *errnop
= EAFNOSUPPORT
;
348 return NSS_STATUS_UNAVAIL
;
351 if (is_localhost(name
)) {
352 canonical
= "localhost";
353 local_address_ipv4
= htonl(INADDR_LOOPBACK
);
355 } else if (is_gateway(name
)) {
357 n_addresses
= local_gateways(NULL
, 0, af
, &addresses
);
358 if (n_addresses
<= 0) {
360 *h_errnop
= HOST_NOT_FOUND
;
361 return NSS_STATUS_NOTFOUND
;
364 canonical
= "gateway";
367 hn
= gethostname_malloc();
370 *h_errnop
= NO_RECOVERY
;
371 return NSS_STATUS_TRYAGAIN
;
374 if (!streq(name
, hn
) && !streq_ptr(startswith(name
, hn
), ".")) {
376 *h_errnop
= HOST_NOT_FOUND
;
377 return NSS_STATUS_NOTFOUND
;
380 n_addresses
= local_addresses(NULL
, 0, af
, &addresses
);
385 additional
= n_addresses
<= 0 && af
== AF_INET6
? "localhost" : NULL
;
386 local_address_ipv4
= LOCALADDRESS_IPV4
;
389 return fill_in_hostent(
390 canonical
, additional
,
392 addresses
, n_addresses
,
401 enum nss_status
_nss_myhostname_gethostbyaddr2_r(
402 const void* addr
, socklen_t len
,
404 struct hostent
*host
,
405 char *buffer
, size_t buflen
,
406 int *errnop
, int *h_errnop
,
409 const char *canonical
= NULL
, *additional
= NULL
;
410 uint32_t local_address_ipv4
= LOCALADDRESS_IPV4
;
411 _cleanup_free_
struct local_address
*addresses
= NULL
;
412 _cleanup_free_
char *hn
= NULL
;
414 struct local_address
*a
;
415 bool additional_from_hostname
= false;
424 if (!IN_SET(af
, AF_INET
, AF_INET6
)) {
425 *errnop
= EAFNOSUPPORT
;
427 return NSS_STATUS_UNAVAIL
;
430 if (len
!= FAMILY_ADDRESS_SIZE(af
)) {
432 *h_errnop
= NO_RECOVERY
;
433 return NSS_STATUS_UNAVAIL
;
437 if ((*(uint32_t*) addr
) == LOCALADDRESS_IPV4
)
440 if ((*(uint32_t*) addr
) == htonl(INADDR_LOOPBACK
)) {
441 canonical
= "localhost";
442 local_address_ipv4
= htonl(INADDR_LOOPBACK
);
447 assert(af
== AF_INET6
);
449 if (memcmp(addr
, LOCALADDRESS_IPV6
, 16) == 0) {
450 canonical
= "localhost";
451 additional_from_hostname
= true;
456 n_addresses
= local_addresses(NULL
, 0, AF_UNSPEC
, &addresses
);
457 if (n_addresses
> 0) {
458 for (a
= addresses
, n
= 0; (int) n
< n_addresses
; n
++, a
++) {
462 if (memcmp(addr
, &a
->address
, FAMILY_ADDRESS_SIZE(af
)) == 0)
467 addresses
= mfree(addresses
);
469 n_addresses
= local_gateways(NULL
, 0, AF_UNSPEC
, &addresses
);
470 if (n_addresses
> 0) {
471 for (a
= addresses
, n
= 0; (int) n
< n_addresses
; n
++, a
++) {
475 if (memcmp(addr
, &a
->address
, FAMILY_ADDRESS_SIZE(af
)) == 0) {
476 canonical
= "gateway";
483 *h_errnop
= HOST_NOT_FOUND
;
485 return NSS_STATUS_NOTFOUND
;
488 if (!canonical
|| (!additional
&& additional_from_hostname
)) {
489 hn
= gethostname_malloc();
492 *h_errnop
= NO_RECOVERY
;
493 return NSS_STATUS_TRYAGAIN
;
499 if (!additional
&& additional_from_hostname
)
503 return fill_in_hostent(
504 canonical
, additional
,
506 addresses
, n_addresses
,
515 NSS_GETHOSTBYNAME_FALLBACKS(myhostname
);
516 NSS_GETHOSTBYADDR_FALLBACKS(myhostname
);