]>
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/>.
24 #include <sys/types.h>
31 #include <arpa/inet.h>
37 /* Ensure that glibc's assert is used. We cannot use assert from macro.h, as
38 * libnss_myhostname will be linked into arbitrary programs which will, in turn
39 * attempt to write to the journal via log_dispatch() */
42 /* We use 127.0.0.2 as IPv4 address. This has the advantage over
43 * 127.0.0.1 that it can be translated back to the local hostname. For
44 * IPv6 we use ::1 which unfortunately will not translate back to the
45 * hostname but instead something like "localhost6" or so. */
47 #define LOCALADDRESS_IPV4 (htonl(0x7F000002))
48 #define LOCALADDRESS_IPV6 &in6addr_loopback
49 #define LOOPBACK_INTERFACE "lo"
51 enum nss_status
_nss_myhostname_gethostbyname4_r(
53 struct gaih_addrtuple
**pat
,
54 char *buffer
, size_t buflen
,
55 int *errnop
, int *h_errnop
,
56 int32_t *ttlp
) _public_
;
58 enum nss_status
_nss_myhostname_gethostbyname3_r(
62 char *buffer
, size_t buflen
,
63 int *errnop
, int *h_errnop
,
65 char **canonp
) _public_
;
67 enum nss_status
_nss_myhostname_gethostbyname2_r(
71 char *buffer
, size_t buflen
,
72 int *errnop
, int *h_errnop
) _public_
;
74 enum nss_status
_nss_myhostname_gethostbyname_r(
77 char *buffer
, size_t buflen
,
78 int *errnop
, int *h_errnop
) _public_
;
80 enum nss_status
_nss_myhostname_gethostbyaddr2_r(
81 const void* addr
, socklen_t len
,
84 char *buffer
, size_t buflen
,
85 int *errnop
, int *h_errnop
,
86 int32_t *ttlp
) _public_
;
88 enum nss_status
_nss_myhostname_gethostbyaddr_r(
89 const void* addr
, socklen_t len
,
92 char *buffer
, size_t buflen
,
93 int *errnop
, int *h_errnop
) _public_
;
95 enum nss_status
_nss_myhostname_gethostbyname4_r(
97 struct gaih_addrtuple
**pat
,
98 char *buffer
, size_t buflen
,
99 int *errnop
, int *h_errnop
,
103 char hn
[HOST_NAME_MAX
+1] = {};
106 struct gaih_addrtuple
*r_tuple
, *r_tuple_prev
= NULL
;
107 struct address
*addresses
= NULL
, *a
;
108 unsigned n_addresses
= 0, n
;
110 if (gethostname(hn
, sizeof(hn
)-1) < 0) {
112 *h_errnop
= NO_RECOVERY
;
113 return NSS_STATUS_UNAVAIL
;
116 if (strcasecmp(name
, hn
) != 0) {
118 *h_errnop
= HOST_NOT_FOUND
;
119 return NSS_STATUS_NOTFOUND
;
122 /* If this fails, n_addresses is 0. Which is fine */
123 ifconf_acquire_addresses(&addresses
, &n_addresses
);
125 /* If this call fails we fill in 0 as scope. Which is fine */
126 lo_ifi
= if_nametoindex(LOOPBACK_INTERFACE
);
129 ms
= ALIGN(l
+1)+ALIGN(sizeof(struct gaih_addrtuple
))*(n_addresses
> 0 ? n_addresses
: 2);
132 *h_errnop
= NO_RECOVERY
;
134 return NSS_STATUS_TRYAGAIN
;
137 /* First, fill in hostname */
139 memcpy(r_name
, hn
, l
+1);
142 if (n_addresses
<= 0) {
143 /* Second, fill in IPv6 tuple */
144 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
145 r_tuple
->next
= r_tuple_prev
;
146 r_tuple
->name
= r_name
;
147 r_tuple
->family
= AF_INET6
;
148 memcpy(r_tuple
->addr
, LOCALADDRESS_IPV6
, 16);
149 r_tuple
->scopeid
= (uint32_t) lo_ifi
;
151 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
152 r_tuple_prev
= r_tuple
;
154 /* Third, fill in IPv4 tuple */
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
= AF_INET
;
159 *(uint32_t*) r_tuple
->addr
= LOCALADDRESS_IPV4
;
160 r_tuple
->scopeid
= (uint32_t) lo_ifi
;
162 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
163 r_tuple_prev
= r_tuple
;
166 /* Fourth, fill actual addresses in, but in backwards order */
167 for (a
= addresses
+ n_addresses
- 1, n
= 0; n
< n_addresses
; n
++, a
--) {
168 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
169 r_tuple
->next
= r_tuple_prev
;
170 r_tuple
->name
= r_name
;
171 r_tuple
->family
= a
->family
;
172 r_tuple
->scopeid
= a
->ifindex
;
173 memcpy(r_tuple
->addr
, a
->address
, 16);
175 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
176 r_tuple_prev
= r_tuple
;
179 /* Verify the size matches */
182 /* Nscd expects us to store the first record in **pat. */
184 **pat
= *r_tuple_prev
;
193 return NSS_STATUS_SUCCESS
;
196 static enum nss_status
fill_in_hostent(
199 struct hostent
*result
,
200 char *buffer
, size_t buflen
,
201 int *errnop
, int *h_errnop
,
206 char *r_addr
, *r_name
, *r_aliases
, *r_addr_list
;
208 struct address
*addresses
= NULL
, *a
;
209 unsigned n_addresses
= 0, n
, c
;
211 alen
= PROTO_ADDRESS_SIZE(af
);
213 ifconf_acquire_addresses(&addresses
, &n_addresses
);
215 for (a
= addresses
, n
= 0, c
= 0; n
< n_addresses
; a
++, n
++)
222 (c
> 0 ? c
: 1)*ALIGN(alen
)+
223 (c
> 0 ? c
+1 : 2)*sizeof(char*);
227 *h_errnop
= NO_RECOVERY
;
229 return NSS_STATUS_TRYAGAIN
;
232 /* First, fill in hostname */
234 memcpy(r_name
, hn
, l
+1);
237 /* Second, create (empty) aliases array */
238 r_aliases
= buffer
+ idx
;
239 *(char**) r_aliases
= NULL
;
240 idx
+= sizeof(char*);
242 /* Third, add addresses */
243 r_addr
= buffer
+ idx
;
247 for (a
= addresses
, n
= 0; n
< n_addresses
; a
++, n
++) {
251 memcpy(r_addr
+ i
*ALIGN(alen
), a
->address
, alen
);
256 idx
+= c
*ALIGN(alen
);
259 *(uint32_t*) r_addr
= LOCALADDRESS_IPV4
;
261 memcpy(r_addr
, LOCALADDRESS_IPV6
, 16);
266 /* Fourth, add address pointer array */
267 r_addr_list
= buffer
+ idx
;
271 for (a
= addresses
, n
= 0; n
< n_addresses
; a
++, n
++) {
275 ((char**) r_addr_list
)[i
] = (r_addr
+ i
*ALIGN(alen
));
280 ((char**) r_addr_list
)[c
] = NULL
;
281 idx
+= (c
+1)*sizeof(char*);
284 ((char**) r_addr_list
)[0] = r_addr
;
285 ((char**) r_addr_list
)[1] = NULL
;
286 idx
+= 2*sizeof(char*);
289 /* Verify the size matches */
292 result
->h_name
= r_name
;
293 result
->h_aliases
= (char**) r_aliases
;
294 result
->h_addrtype
= af
;
295 result
->h_length
= alen
;
296 result
->h_addr_list
= (char**) r_addr_list
;
306 return NSS_STATUS_SUCCESS
;
309 enum nss_status
_nss_myhostname_gethostbyname3_r(
312 struct hostent
*host
,
313 char *buffer
, size_t buflen
,
314 int *errnop
, int *h_errnop
,
318 char hn
[HOST_NAME_MAX
+1] = {};
323 if (af
!= AF_INET
&& af
!= AF_INET6
) {
324 *errnop
= EAFNOSUPPORT
;
326 return NSS_STATUS_UNAVAIL
;
329 if (gethostname(hn
, sizeof(hn
)-1) < 0) {
331 *h_errnop
= NO_RECOVERY
;
332 return NSS_STATUS_UNAVAIL
;
335 if (strcasecmp(name
, hn
) != 0) {
337 *h_errnop
= HOST_NOT_FOUND
;
338 return NSS_STATUS_NOTFOUND
;
341 return fill_in_hostent(hn
, af
, host
, buffer
, buflen
, errnop
, h_errnop
, ttlp
, canonp
);
344 enum nss_status
_nss_myhostname_gethostbyname2_r(
347 struct hostent
*host
,
348 char *buffer
, size_t buflen
,
349 int *errnop
, int *h_errnop
) {
351 return _nss_myhostname_gethostbyname3_r(
361 enum nss_status
_nss_myhostname_gethostbyname_r(
363 struct hostent
*host
,
364 char *buffer
, size_t buflen
,
365 int *errnop
, int *h_errnop
) {
367 return _nss_myhostname_gethostbyname3_r(
377 enum nss_status
_nss_myhostname_gethostbyaddr2_r(
378 const void* addr
, socklen_t len
,
380 struct hostent
*host
,
381 char *buffer
, size_t buflen
,
382 int *errnop
, int *h_errnop
,
385 char hn
[HOST_NAME_MAX
+1] = {};
386 _cleanup_free_
struct address
*addresses
= NULL
;
388 unsigned n_addresses
= 0, n
;
390 if (len
!= PROTO_ADDRESS_SIZE(af
)) {
392 *h_errnop
= NO_RECOVERY
;
393 return NSS_STATUS_UNAVAIL
;
398 if ((*(uint32_t*) addr
) == LOCALADDRESS_IPV4
)
401 } else if (af
== AF_INET6
) {
403 if (memcmp(addr
, LOCALADDRESS_IPV6
, 16) == 0)
407 *errnop
= EAFNOSUPPORT
;
409 return NSS_STATUS_UNAVAIL
;
412 ifconf_acquire_addresses(&addresses
, &n_addresses
);
414 for (a
= addresses
, n
= 0; n
< n_addresses
; n
++, a
++) {
418 if (memcmp(addr
, a
->address
, PROTO_ADDRESS_SIZE(af
)) == 0)
423 *h_errnop
= HOST_NOT_FOUND
;
425 return NSS_STATUS_NOTFOUND
;
428 if (gethostname(hn
, sizeof(hn
)-1) < 0) {
430 *h_errnop
= NO_RECOVERY
;
432 return NSS_STATUS_UNAVAIL
;
435 return fill_in_hostent(hn
, af
, host
, buffer
, buflen
, errnop
, h_errnop
, ttlp
, NULL
);
439 enum nss_status
_nss_myhostname_gethostbyaddr_r(
440 const void* addr
, socklen_t len
,
442 struct hostent
*host
,
443 char *buffer
, size_t buflen
,
444 int *errnop
, int *h_errnop
) {
446 return _nss_myhostname_gethostbyaddr2_r(