]>
git.ipfire.org Git - thirdparty/systemd.git/blob - nss-myhostname.c
83180ad80532713dc6bb9ca2c23e21629568b026
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of nss-myhostname.
6 Copyright 2008-2011 Lennart Poettering
8 nss-myhostname is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public License
10 as published by the Free Software Foundation; either version 2.1 of
11 the License, or (at your option) any later version.
13 nss-myhostname is distributed in the hope that it will be useful,
14 but 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
19 License along with nss-myhostname; If not, see
20 <http://www.gnu.org/licenses/>.
25 #include <sys/types.h>
33 #include <arpa/inet.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 "localhost6" or so. */
42 #define LOCALADDRESS_IPV4 (htonl(0x7F000002))
43 #define LOCALADDRESS_IPV6 &in6addr_loopback
44 #define LOOPBACK_INTERFACE "lo"
46 #define ALIGN(a) (((a+sizeof(void*)-1)/sizeof(void*))*sizeof(void*))
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
,
53 int32_t *ttlp
) _public_
;
55 enum nss_status
_nss_myhostname_gethostbyname3_r(
59 char *buffer
, size_t buflen
,
60 int *errnop
, int *h_errnop
,
62 char **canonp
) _public_
;
64 enum nss_status
_nss_myhostname_gethostbyname2_r(
68 char *buffer
, size_t buflen
,
69 int *errnop
, int *h_errnop
) _public_
;
71 enum nss_status
_nss_myhostname_gethostbyname_r(
74 char *buffer
, size_t buflen
,
75 int *errnop
, int *h_errnop
) _public_
;
77 enum nss_status
_nss_myhostname_gethostbyaddr2_r(
78 const void* addr
, socklen_t len
,
81 char *buffer
, size_t buflen
,
82 int *errnop
, int *h_errnop
,
83 int32_t *ttlp
) _public_
;
85 enum nss_status
_nss_myhostname_gethostbyaddr_r(
86 const void* addr
, socklen_t len
,
89 char *buffer
, size_t buflen
,
90 int *errnop
, int *h_errnop
) _public_
;
92 enum nss_status
_nss_myhostname_gethostbyname4_r(
94 struct gaih_addrtuple
**pat
,
95 char *buffer
, size_t buflen
,
96 int *errnop
, int *h_errnop
,
100 char hn
[HOST_NAME_MAX
+1];
103 struct gaih_addrtuple
*r_tuple
, *r_tuple_prev
= NULL
;
104 struct address
*addresses
= NULL
, *a
;
105 unsigned n_addresses
= 0, n
;
107 memset(hn
, 0, sizeof(hn
));
108 if (gethostname(hn
, sizeof(hn
)-1) < 0) {
110 *h_errnop
= NO_RECOVERY
;
111 return NSS_STATUS_UNAVAIL
;
114 if (strcasecmp(name
, hn
) != 0) {
116 *h_errnop
= HOST_NOT_FOUND
;
117 return NSS_STATUS_NOTFOUND
;
120 /* If this fails, n_addresses is 0. Which is fine */
121 ifconf_acquire_addresses(&addresses
, &n_addresses
);
123 /* If this call fails we fill in 0 as scope. Which is fine */
124 lo_ifi
= if_nametoindex(LOOPBACK_INTERFACE
);
127 ms
= ALIGN(l
+1)+ALIGN(sizeof(struct gaih_addrtuple
))*(n_addresses
> 0 ? n_addresses
: 2);
130 *h_errnop
= NO_RECOVERY
;
132 return NSS_STATUS_TRYAGAIN
;
135 /* First, fill in hostname */
137 memcpy(r_name
, hn
, l
+1);
140 if (n_addresses
<= 0) {
141 /* Second, fill in IPv6 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_INET6
;
146 memcpy(r_tuple
->addr
, LOCALADDRESS_IPV6
, 16);
147 r_tuple
->scopeid
= (uint32_t) lo_ifi
;
149 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
150 r_tuple_prev
= r_tuple
;
152 /* Third, fill in IPv4 tuple */
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
= AF_INET
;
157 *(uint32_t*) r_tuple
->addr
= LOCALADDRESS_IPV4
;
158 r_tuple
->scopeid
= (uint32_t) lo_ifi
;
160 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
161 r_tuple_prev
= r_tuple
;
164 /* Fourth, fill actual addresses in, but in backwards order */
165 for (a
= addresses
+ n_addresses
- 1, n
= 0; n
< n_addresses
; n
++, a
--) {
166 r_tuple
= (struct gaih_addrtuple
*) (buffer
+ idx
);
167 r_tuple
->next
= r_tuple_prev
;
168 r_tuple
->name
= r_name
;
169 r_tuple
->family
= a
->family
;
170 r_tuple
->scopeid
= a
->ifindex
;
171 memcpy(r_tuple
->addr
, a
->address
, 16);
173 idx
+= ALIGN(sizeof(struct gaih_addrtuple
));
174 r_tuple_prev
= r_tuple
;
177 /* Verify the size matches */
187 return NSS_STATUS_SUCCESS
;
190 static enum nss_status
fill_in_hostent(
193 struct hostent
*result
,
194 char *buffer
, size_t buflen
,
195 int *errnop
, int *h_errnop
,
200 char *r_addr
, *r_name
, *r_aliases
, *r_addr_list
;
202 struct address
*addresses
= NULL
, *a
;
203 unsigned n_addresses
= 0, n
, c
;
205 alen
= PROTO_ADDRESS_SIZE(af
);
207 ifconf_acquire_addresses(&addresses
, &n_addresses
);
209 for (a
= addresses
, n
= 0, c
= 0; n
< n_addresses
; a
++, n
++)
216 (c
> 0 ? c
: 1)*ALIGN(alen
)+
217 (c
> 0 ? c
+1 : 2)*sizeof(char*);
221 *h_errnop
= NO_RECOVERY
;
223 return NSS_STATUS_TRYAGAIN
;
226 /* First, fill in hostname */
228 memcpy(r_name
, hn
, l
+1);
231 /* Second, create (empty) aliases array */
232 r_aliases
= buffer
+ idx
;
233 *(char**) r_aliases
= NULL
;
234 idx
+= sizeof(char*);
236 /* Third, add addresses */
237 r_addr
= buffer
+ idx
;
241 for (a
= addresses
, n
= 0; n
< n_addresses
; a
++, n
++) {
245 memcpy(r_addr
+ i
*ALIGN(alen
), a
->address
, alen
);
250 idx
+= c
*ALIGN(alen
);
253 *(uint32_t*) r_addr
= LOCALADDRESS_IPV4
;
255 memcpy(r_addr
, LOCALADDRESS_IPV6
, 16);
260 /* Fourth, add address pointer array */
261 r_addr_list
= buffer
+ idx
;
265 for (a
= addresses
, n
= 0; n
< n_addresses
; a
++, n
++) {
269 ((char**) r_addr_list
)[i
] = (r_addr
+ i
*ALIGN(alen
));
274 ((char**) r_addr_list
)[c
] = NULL
;
275 idx
+= (c
+1)*sizeof(char*);
278 ((char**) r_addr_list
)[0] = r_addr
;
279 ((char**) r_addr_list
)[1] = NULL
;
280 idx
+= 2*sizeof(char*);
283 /* Verify the size matches */
286 result
->h_name
= r_name
;
287 result
->h_aliases
= (char**) r_aliases
;
288 result
->h_addrtype
= af
;
289 result
->h_length
= alen
;
290 result
->h_addr_list
= (char**) r_addr_list
;
300 return NSS_STATUS_SUCCESS
;
303 enum nss_status
_nss_myhostname_gethostbyname3_r(
306 struct hostent
*host
,
307 char *buffer
, size_t buflen
,
308 int *errnop
, int *h_errnop
,
312 char hn
[HOST_NAME_MAX
+1];
317 if (af
!= AF_INET
&& af
!= AF_INET6
) {
318 *errnop
= EAFNOSUPPORT
;
320 return NSS_STATUS_UNAVAIL
;
323 memset(hn
, 0, sizeof(hn
));
324 if (gethostname(hn
, sizeof(hn
)-1) < 0) {
326 *h_errnop
= NO_RECOVERY
;
327 return NSS_STATUS_UNAVAIL
;
330 if (strcasecmp(name
, hn
) != 0) {
332 *h_errnop
= HOST_NOT_FOUND
;
333 return NSS_STATUS_NOTFOUND
;
336 return fill_in_hostent(hn
, af
, host
, buffer
, buflen
, errnop
, h_errnop
, ttlp
, canonp
);
339 enum nss_status
_nss_myhostname_gethostbyname2_r(
342 struct hostent
*host
,
343 char *buffer
, size_t buflen
,
344 int *errnop
, int *h_errnop
) {
346 return _nss_myhostname_gethostbyname3_r(
356 enum nss_status
_nss_myhostname_gethostbyname_r(
358 struct hostent
*host
,
359 char *buffer
, size_t buflen
,
360 int *errnop
, int *h_errnop
) {
362 return _nss_myhostname_gethostbyname3_r(
372 enum nss_status
_nss_myhostname_gethostbyaddr2_r(
373 const void* addr
, socklen_t len
,
375 struct hostent
*host
,
376 char *buffer
, size_t buflen
,
377 int *errnop
, int *h_errnop
,
380 char hn
[HOST_NAME_MAX
+1];
381 struct address
*addresses
= NULL
, *a
;
382 unsigned n_addresses
= 0, n
;
384 if (len
!= PROTO_ADDRESS_SIZE(af
)) {
386 *h_errnop
= NO_RECOVERY
;
387 return NSS_STATUS_UNAVAIL
;
392 if ((*(uint32_t*) addr
) == LOCALADDRESS_IPV4
)
395 } else if (af
== AF_INET6
) {
397 if (memcmp(addr
, LOCALADDRESS_IPV6
, 16) == 0)
401 *errnop
= EAFNOSUPPORT
;
403 return NSS_STATUS_UNAVAIL
;
406 ifconf_acquire_addresses(&addresses
, &n_addresses
);
408 for (a
= addresses
, n
= 0; n
< n_addresses
; n
++, a
++) {
412 if (memcmp(addr
, a
->address
, PROTO_ADDRESS_SIZE(af
)) == 0)
417 *h_errnop
= HOST_NOT_FOUND
;
420 return NSS_STATUS_NOTFOUND
;
425 memset(hn
, 0, sizeof(hn
));
426 if (gethostname(hn
, sizeof(hn
)-1) < 0) {
428 *h_errnop
= NO_RECOVERY
;
430 return NSS_STATUS_UNAVAIL
;
433 return fill_in_hostent(hn
, af
, host
, buffer
, buflen
, errnop
, h_errnop
, ttlp
, NULL
);
437 enum nss_status
_nss_myhostname_gethostbyaddr_r(
438 const void* addr
, socklen_t len
,
440 struct hostent
*host
,
441 char *buffer
, size_t buflen
,
442 int *errnop
, int *h_errnop
) {
444 return _nss_myhostname_gethostbyaddr2_r(