]>
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
43 NSS_GETHOSTBYNAME_PROTOTYPES(myhostname
);
44 NSS_GETHOSTBYADDR_PROTOTYPES(myhostname
);
46 enum nss_status
_nss_myhostname_gethostbyname4_r(
48 struct gaih_addrtuple
**pat
,
49 char *buffer
, size_t buflen
,
50 int *errnop
, int *h_errnop
,
53 struct gaih_addrtuple
*r_tuple
, *r_tuple_prev
= NULL
;
54 _cleanup_free_
struct local_address
*addresses
= NULL
;
55 _cleanup_free_
char *hn
= NULL
;
56 const char *canonical
= NULL
;
57 int n_addresses
= 0, lo_ifi
;
58 uint32_t local_address_ipv4
;
59 struct local_address
*a
;
70 if (is_localhost(name
)) {
71 /* We respond to 'localhost', so that /etc/hosts
74 canonical
= "localhost";
75 local_address_ipv4
= htonl(INADDR_LOOPBACK
);
77 } else if (is_gateway_hostname(name
)) {
79 n_addresses
= local_gateways(NULL
, 0, AF_UNSPEC
, &addresses
);
80 if (n_addresses
<= 0) {
82 *h_errnop
= HOST_NOT_FOUND
;
83 return NSS_STATUS_NOTFOUND
;
86 canonical
= "gateway";
89 hn
= gethostname_malloc();
92 *h_errnop
= NO_RECOVERY
;
93 return NSS_STATUS_TRYAGAIN
;
96 /* We respond to our local host name, our our hostname suffixed with a single dot. */
97 if (!streq(name
, hn
) && !streq_ptr(startswith(name
, hn
), ".")) {
99 *h_errnop
= HOST_NOT_FOUND
;
100 return NSS_STATUS_NOTFOUND
;
103 n_addresses
= local_addresses(NULL
, 0, AF_UNSPEC
, &addresses
);
108 local_address_ipv4
= LOCALADDRESS_IPV4
;
111 /* If this call fails we fill in 0 as scope. Which is fine */
112 lo_ifi
= n_addresses
<= 0 ? LOOPBACK_IFINDEX
: 0;
114 l
= strlen(canonical
);
115 ms
= ALIGN(l
+1) + ALIGN(sizeof(struct gaih_addrtuple
)) * (n_addresses
> 0 ? n_addresses
: 2);
118 *h_errnop
= NO_RECOVERY
;
119 return NSS_STATUS_TRYAGAIN
;
122 /* First, fill in hostname */
124 memcpy(r_name
, canonical
, l
+1);
127 if (n_addresses
<= 0) {
128 /* Second, fill in IPv6 tuple */
129 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
130 r_tuple
->next
= r_tuple_prev
;
131 r_tuple
->name
= r_name
;
132 r_tuple
->family
= AF_INET6
;
133 memcpy(r_tuple
->addr
, LOCALADDRESS_IPV6
, 16);
134 r_tuple
->scopeid
= (uint32_t) lo_ifi
;
136 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
137 r_tuple_prev
= r_tuple
;
139 /* Third, fill in IPv4 tuple */
140 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
141 r_tuple
->next
= r_tuple_prev
;
142 r_tuple
->name
= r_name
;
143 r_tuple
->family
= AF_INET
;
144 *(uint32_t*) r_tuple
->addr
= local_address_ipv4
;
145 r_tuple
->scopeid
= (uint32_t) lo_ifi
;
147 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
148 r_tuple_prev
= r_tuple
;
151 /* Fourth, fill actual addresses in, but in backwards order */
152 for (a
= addresses
+ n_addresses
- 1, n
= 0; (int) n
< n_addresses
; n
++, a
--) {
153 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
154 r_tuple
->next
= r_tuple_prev
;
155 r_tuple
->name
= r_name
;
156 r_tuple
->family
= a
->family
;
157 r_tuple
->scopeid
= a
->ifindex
;
158 memcpy(r_tuple
->addr
, &a
->address
, 16);
160 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
161 r_tuple_prev
= r_tuple
;
164 /* Verify the size matches */
167 /* Nscd expects us to store the first record in **pat. */
169 **pat
= *r_tuple_prev
;
176 /* Explicitly reset all error variables */
178 *h_errnop
= NETDB_SUCCESS
;
181 return NSS_STATUS_SUCCESS
;
184 static enum nss_status
fill_in_hostent(
185 const char *canonical
, const char *additional
,
187 struct local_address
*addresses
, unsigned n_addresses
,
188 uint32_t local_address_ipv4
,
189 struct hostent
*result
,
190 char *buffer
, size_t buflen
,
191 int *errnop
, int *h_errnop
,
195 size_t l_canonical
, l_additional
, idx
, ms
, alen
;
196 char *r_addr
, *r_name
, *r_aliases
, *r_alias
= NULL
, *r_addr_list
;
197 struct local_address
*a
;
206 alen
= FAMILY_ADDRESS_SIZE(af
);
208 for (a
= addresses
, n
= 0, c
= 0; n
< n_addresses
; a
++, n
++)
212 l_canonical
= strlen(canonical
);
213 l_additional
= additional
? strlen(additional
) : 0;
214 ms
= ALIGN(l_canonical
+1)+
215 (additional
? ALIGN(l_additional
+1) : 0) +
217 (additional
? sizeof(char*) : 0) +
218 (c
> 0 ? c
: 1) * ALIGN(alen
) +
219 (c
> 0 ? c
+1 : 2) * sizeof(char*);
223 *h_errnop
= NO_RECOVERY
;
224 return NSS_STATUS_TRYAGAIN
;
227 /* First, fill in hostnames */
229 memcpy(r_name
, canonical
, l_canonical
+1);
230 idx
= ALIGN(l_canonical
+1);
233 r_alias
= buffer
+ idx
;
234 memcpy(r_alias
, additional
, l_additional
+1);
235 idx
+= ALIGN(l_additional
+1);
238 /* Second, create aliases array */
239 r_aliases
= buffer
+ idx
;
241 ((char**) r_aliases
)[0] = r_alias
;
242 ((char**) r_aliases
)[1] = NULL
;
243 idx
+= 2*sizeof(char*);
245 ((char**) r_aliases
)[0] = NULL
;
246 idx
+= sizeof(char*);
249 /* Third, add addresses */
250 r_addr
= buffer
+ idx
;
254 for (a
= addresses
, n
= 0; n
< n_addresses
; a
++, n
++) {
258 memcpy(r_addr
+ i
*ALIGN(alen
), &a
->address
, alen
);
263 idx
+= c
*ALIGN(alen
);
266 *(uint32_t*) r_addr
= local_address_ipv4
;
268 memcpy(r_addr
, LOCALADDRESS_IPV6
, 16);
273 /* Fourth, add address pointer array */
274 r_addr_list
= buffer
+ idx
;
278 for (i
= 0; i
< c
; i
++)
279 ((char**) r_addr_list
)[i
] = r_addr
+ i
*ALIGN(alen
);
281 ((char**) r_addr_list
)[i
] = NULL
;
282 idx
+= (c
+1) * sizeof(char*);
285 ((char**) r_addr_list
)[0] = r_addr
;
286 ((char**) r_addr_list
)[1] = NULL
;
287 idx
+= 2 * sizeof(char*);
290 /* Verify the size matches */
293 result
->h_name
= r_name
;
294 result
->h_aliases
= (char**) r_aliases
;
295 result
->h_addrtype
= af
;
296 result
->h_length
= alen
;
297 result
->h_addr_list
= (char**) r_addr_list
;
305 /* Explicitly reset all error variables */
307 *h_errnop
= NETDB_SUCCESS
;
310 return NSS_STATUS_SUCCESS
;
313 enum nss_status
_nss_myhostname_gethostbyname3_r(
316 struct hostent
*host
,
317 char *buffer
, size_t buflen
,
318 int *errnop
, int *h_errnop
,
322 _cleanup_free_
struct local_address
*addresses
= NULL
;
323 const char *canonical
, *additional
= NULL
;
324 _cleanup_free_
char *hn
= NULL
;
325 uint32_t local_address_ipv4
= 0;
337 if (af
!= AF_INET
&& af
!= AF_INET6
) {
338 *errnop
= EAFNOSUPPORT
;
340 return NSS_STATUS_UNAVAIL
;
343 if (is_localhost(name
)) {
344 canonical
= "localhost";
345 local_address_ipv4
= htonl(INADDR_LOOPBACK
);
347 } else if (is_gateway_hostname(name
)) {
349 n_addresses
= local_gateways(NULL
, 0, af
, &addresses
);
350 if (n_addresses
<= 0) {
352 *h_errnop
= HOST_NOT_FOUND
;
353 return NSS_STATUS_NOTFOUND
;
356 canonical
= "gateway";
359 hn
= gethostname_malloc();
362 *h_errnop
= NO_RECOVERY
;
363 return NSS_STATUS_TRYAGAIN
;
366 if (!streq(name
, hn
) && !streq_ptr(startswith(name
, hn
), ".")) {
368 *h_errnop
= HOST_NOT_FOUND
;
369 return NSS_STATUS_NOTFOUND
;
372 n_addresses
= local_addresses(NULL
, 0, af
, &addresses
);
377 additional
= n_addresses
<= 0 && af
== AF_INET6
? "localhost" : NULL
;
378 local_address_ipv4
= LOCALADDRESS_IPV4
;
381 return fill_in_hostent(
382 canonical
, additional
,
384 addresses
, n_addresses
,
393 enum nss_status
_nss_myhostname_gethostbyaddr2_r(
394 const void* addr
, socklen_t len
,
396 struct hostent
*host
,
397 char *buffer
, size_t buflen
,
398 int *errnop
, int *h_errnop
,
401 const char *canonical
= NULL
, *additional
= NULL
;
402 uint32_t local_address_ipv4
= LOCALADDRESS_IPV4
;
403 _cleanup_free_
struct local_address
*addresses
= NULL
;
404 _cleanup_free_
char *hn
= NULL
;
406 struct local_address
*a
;
407 bool additional_from_hostname
= false;
416 if (!IN_SET(af
, AF_INET
, AF_INET6
)) {
417 *errnop
= EAFNOSUPPORT
;
419 return NSS_STATUS_UNAVAIL
;
422 if (len
!= FAMILY_ADDRESS_SIZE(af
)) {
424 *h_errnop
= NO_RECOVERY
;
425 return NSS_STATUS_UNAVAIL
;
429 if ((*(uint32_t*) addr
) == LOCALADDRESS_IPV4
)
432 if ((*(uint32_t*) addr
) == htonl(INADDR_LOOPBACK
)) {
433 canonical
= "localhost";
434 local_address_ipv4
= htonl(INADDR_LOOPBACK
);
439 assert(af
== AF_INET6
);
441 if (memcmp(addr
, LOCALADDRESS_IPV6
, 16) == 0) {
442 canonical
= "localhost";
443 additional_from_hostname
= true;
448 n_addresses
= local_addresses(NULL
, 0, AF_UNSPEC
, &addresses
);
449 if (n_addresses
> 0) {
450 for (a
= addresses
, n
= 0; (int) n
< n_addresses
; n
++, a
++) {
454 if (memcmp(addr
, &a
->address
, FAMILY_ADDRESS_SIZE(af
)) == 0)
459 addresses
= mfree(addresses
);
461 n_addresses
= local_gateways(NULL
, 0, AF_UNSPEC
, &addresses
);
462 if (n_addresses
> 0) {
463 for (a
= addresses
, n
= 0; (int) n
< n_addresses
; n
++, a
++) {
467 if (memcmp(addr
, &a
->address
, FAMILY_ADDRESS_SIZE(af
)) == 0) {
468 canonical
= "gateway";
475 *h_errnop
= HOST_NOT_FOUND
;
477 return NSS_STATUS_NOTFOUND
;
480 if (!canonical
|| (!additional
&& additional_from_hostname
)) {
481 hn
= gethostname_malloc();
484 *h_errnop
= NO_RECOVERY
;
485 return NSS_STATUS_TRYAGAIN
;
491 if (!additional
&& additional_from_hostname
)
495 return fill_in_hostent(
496 canonical
, additional
,
498 addresses
, n_addresses
,
507 NSS_GETHOSTBYNAME_FALLBACKS(myhostname
);
508 NSS_GETHOSTBYADDR_FALLBACKS(myhostname
);