1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
4 This file is part of nss-myhostname.
6 Copyright 2008 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
11 of 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, If not, see
20 <http://www.gnu.org/licenses/>.
29 #include <sys/types.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 "localhost6" or so. */
43 #define LOCALADDRESS_IPV4 (htonl(0x7F000002))
44 #define LOCALADDRESS_IPV6 &in6addr_loopback
45 #define LOOPBACK_INTERFACE "lo"
47 #define ALIGN(a) (((a+sizeof(void*)-1)/sizeof(void*))*sizeof(void*))
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,
57 char hn[HOST_NAME_MAX+1];
60 struct gaih_addrtuple *r_tuple1, *r_tuple2;
62 memset(hn, 0, sizeof(hn));
63 if (gethostname(hn, sizeof(hn)-1) < 0) {
65 *h_errnop = NO_RECOVERY;
66 return NSS_STATUS_UNAVAIL;
69 if (strcasecmp(name, hn) != 0) {
71 *h_errnop = HOST_NOT_FOUND;
72 return NSS_STATUS_NOTFOUND;
75 /* If this call fails we fill in 0 as scope. Which is fine */
76 ifi = if_nametoindex(LOOPBACK_INTERFACE);
79 ms = ALIGN(l+1)+ALIGN(sizeof(struct gaih_addrtuple))*2;
82 *h_errnop = NO_RECOVERY;
83 return NSS_STATUS_TRYAGAIN;
86 /* First, fill in hostname */
88 memcpy(r_name, hn, l+1);
91 /* Second, fill in IPv4 tuple */
92 r_tuple1 = (struct gaih_addrtuple*) (buffer + idx);
93 r_tuple1->next = NULL;
94 r_tuple1->name = r_name;
95 r_tuple1->family = AF_INET;
96 *(uint32_t*) r_tuple1->addr = LOCALADDRESS_IPV4;
97 r_tuple1->scopeid = (uint32_t) ifi;
98 idx += ALIGN(sizeof(struct gaih_addrtuple));
100 /* Third, fill in IPv6 tuple */
101 r_tuple2 = (struct gaih_addrtuple*) (buffer + idx);
102 r_tuple2->next = r_tuple1;
103 r_tuple2->name = r_name;
104 r_tuple2->family = AF_INET6;
105 memcpy(r_tuple2->addr, LOCALADDRESS_IPV6, 16);
106 r_tuple1->scopeid = (uint32_t) ifi;
107 idx += ALIGN(sizeof(struct gaih_addrtuple));
109 /* Verify the size matches */
117 return NSS_STATUS_SUCCESS;
120 static enum nss_status fill_in_hostent(
123 struct hostent *result,
124 char *buffer, size_t buflen,
125 int *errnop, int *h_errnop,
130 char *r_addr, *r_name, *r_aliases, *r_addr_list;
133 alen = af == AF_INET ? 4 : 16;
136 ms = ALIGN(l+1)+sizeof(char*)+ALIGN(alen)+sizeof(char*)*2;
139 *h_errnop = NO_RECOVERY;
140 return NSS_STATUS_TRYAGAIN;
143 /* First, fill in hostname */
145 memcpy(r_name, hn, l+1);
148 /* Second, create aliases array */
149 r_aliases = buffer + idx;
150 *(char**) r_aliases = NULL;
151 idx += sizeof(char*);
153 /* Third, add address */
154 r_addr = buffer + idx;
156 *(uint32_t*) r_addr = LOCALADDRESS_IPV4;
158 memcpy(r_addr, LOCALADDRESS_IPV6, 16);
161 /* Fourth, add address pointer array */
162 r_addr_list = buffer + idx;
163 ((char**) r_addr_list)[0] = r_addr;
164 ((char**) r_addr_list)[1] = NULL;
165 idx += sizeof(char*)*2;
167 /* Verify the size matches */
170 result->h_name = r_name;
171 result->h_aliases = (char**) r_aliases;
172 result->h_addrtype = af;
173 result->h_length = alen;
174 result->h_addr_list = (char**) r_addr_list;
182 return NSS_STATUS_SUCCESS;
185 enum nss_status _nss_myhostname_gethostbyname3_r(
188 struct hostent *host,
189 char *buffer, size_t buflen,
190 int *errnop, int *h_errnop,
194 char hn[HOST_NAME_MAX+1];
199 if (af != AF_INET && af != AF_INET6) {
200 *errnop = EAFNOSUPPORT;
202 return NSS_STATUS_UNAVAIL;
205 memset(hn, 0, sizeof(hn));
206 if (gethostname(hn, sizeof(hn)-1) < 0) {
208 *h_errnop = NO_RECOVERY;
209 return NSS_STATUS_UNAVAIL;
212 if (strcasecmp(name, hn) != 0) {
214 *h_errnop = HOST_NOT_FOUND;
215 return NSS_STATUS_NOTFOUND;
218 return fill_in_hostent(hn, af, host, buffer, buflen, errnop, h_errnop, ttlp, canonp);
221 enum nss_status _nss_myhostname_gethostbyname2_r(
224 struct hostent *host,
225 char *buffer, size_t buflen,
226 int *errnop, int *h_errnop) {
228 return _nss_myhostname_gethostbyname3_r(
238 enum nss_status _nss_myhostname_gethostbyname_r (
240 struct hostent *host,
241 char *buffer, size_t buflen,
242 int *errnop, int *h_errnop) {
244 return _nss_myhostname_gethostbyname3_r(
254 enum nss_status _nss_myhostname_gethostbyaddr2_r(
255 const void* addr, socklen_t len,
257 struct hostent *host,
258 char *buffer, size_t buflen,
259 int *errnop, int *h_errnop,
262 char hn[HOST_NAME_MAX+1];
266 (*(uint32_t*) addr) != LOCALADDRESS_IPV4)
269 } else if (af == AF_INET6) {
271 memcmp(addr, LOCALADDRESS_IPV6, 16) != 0)
274 *errnop = EAFNOSUPPORT;
276 return NSS_STATUS_UNAVAIL;
279 memset(hn, 0, sizeof(hn));
280 if (gethostname(hn, sizeof(hn)-1) < 0) {
282 *h_errnop = NO_RECOVERY;
283 return NSS_STATUS_UNAVAIL;
286 return fill_in_hostent(hn, af, host, buffer, buflen, errnop, h_errnop, ttlp, NULL);
290 *h_errnop = HOST_NOT_FOUND;
291 return NSS_STATUS_NOTFOUND;
294 enum nss_status _nss_myhostname_gethostbyaddr_r(
295 const void* addr, socklen_t len,
297 struct hostent *host,
298 char *buffer, size_t buflen,
299 int *errnop, int *h_errnop) {
301 return _nss_myhostname_gethostbyaddr2_r(