1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
5 This file is part of nss-myhostname.
7 Copyright 2008 Lennart Poettering
9 nss-myhostname is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Lesser General Public License
11 as published by the Free Software Foundation, either version 2.1
12 of the License, or (at your option) any later version.
14 nss-myhostname is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public
20 License along with nss-myhostname. If not, If not, see
21 <http://www.gnu.org/licenses/>.
26 #include <sys/types.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 "localhost6" or so. */
40 #define LOCALADDRESS_IPV4 (htonl(0x7F000002))
41 #define LOCALADDRESS_IPV6 &in6addr_loopback
42 #define LOOPBACK_INTERFACE "lo"
44 #define ALIGN(a) (((a+sizeof(void*)-1)/sizeof(void*))*sizeof(void*))
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,
54 char hn[HOST_NAME_MAX+1];
57 struct gaih_addrtuple *r_tuple1, *r_tuple2;
59 memset(hn, 0, sizeof(hn));
60 if (gethostname(hn, sizeof(hn)-1) < 0) {
62 *h_errnop = NO_RECOVERY;
63 return NSS_STATUS_UNAVAIL;
66 if (strcasecmp(name, hn) != 0) {
68 *h_errnop = HOST_NOT_FOUND;
69 return NSS_STATUS_NOTFOUND;
72 /* If this call fails we fill in 0 as scope. Which is fine */
73 ifi = if_nametoindex(LOOPBACK_INTERFACE);
76 ms = ALIGN(l+1)+ALIGN(sizeof(struct gaih_addrtuple))*2;
79 *h_errnop = NO_RECOVERY;
80 return NSS_STATUS_TRYAGAIN;
83 /* First, fill in hostname */
85 memcpy(r_name, hn, l+1);
88 /* Second, fill in IPv4 tuple */
89 r_tuple1 = (struct gaih_addrtuple*) (buffer + idx);
90 r_tuple1->next = NULL;
91 r_tuple1->name = r_name;
92 r_tuple1->family = AF_INET;
93 *(uint32_t*) r_tuple1->addr = LOCALADDRESS_IPV4;
94 r_tuple1->scopeid = (uint32_t) ifi;
95 idx += ALIGN(sizeof(struct gaih_addrtuple));
97 /* Third, fill in IPv6 tuple */
98 r_tuple2 = (struct gaih_addrtuple*) (buffer + idx);
99 r_tuple2->next = r_tuple1;
100 r_tuple2->name = r_name;
101 r_tuple2->family = AF_INET6;
102 memcpy(r_tuple2->addr, LOCALADDRESS_IPV6, 16);
103 r_tuple1->scopeid = (uint32_t) ifi;
104 idx += ALIGN(sizeof(struct gaih_addrtuple));
106 /* Verify the size matches */
114 return NSS_STATUS_SUCCESS;
117 static enum nss_status fill_in_hostent(
120 struct hostent *result,
121 char *buffer, size_t buflen,
122 int *errnop, int *h_errnop,
127 char *r_addr, *r_name, *r_aliases, *r_addr_list;
130 alen = af == AF_INET ? 4 : 16;
133 ms = ALIGN(l+1)+sizeof(char*)+ALIGN(alen)+sizeof(char*)*2;
136 *h_errnop = NO_RECOVERY;
137 return NSS_STATUS_TRYAGAIN;
140 /* First, fill in hostname */
142 memcpy(r_name, hn, l+1);
145 /* Second, create aliases array */
146 r_aliases = buffer + idx;
147 *(char**) r_aliases = NULL;
148 idx += sizeof(char*);
150 /* Third, add address */
151 r_addr = buffer + idx;
153 *(uint32_t*) r_addr = LOCALADDRESS_IPV4;
155 memcpy(r_addr, LOCALADDRESS_IPV6, 16);
158 /* Fourth, add address pointer array */
159 r_addr_list = buffer + idx;
160 ((char**) r_addr_list)[0] = r_addr;
161 ((char**) r_addr_list)[1] = NULL;
162 idx += sizeof(char*)*2;
164 /* Verify the size matches */
167 result->h_name = r_name;
168 result->h_aliases = (char**) r_aliases;
169 result->h_addrtype = af;
170 result->h_length = alen;
171 result->h_addr_list = (char**) r_addr_list;
179 return NSS_STATUS_SUCCESS;
182 enum nss_status _nss_myhostname_gethostbyname3_r(
185 struct hostent *host,
186 char *buffer, size_t buflen,
187 int *errnop, int *h_errnop,
191 char hn[HOST_NAME_MAX+1];
196 if (af != AF_INET && af != AF_INET6) {
197 *errnop = EAFNOSUPPORT;
199 return NSS_STATUS_UNAVAIL;
202 memset(hn, 0, sizeof(hn));
203 if (gethostname(hn, sizeof(hn)-1) < 0) {
205 *h_errnop = NO_RECOVERY;
206 return NSS_STATUS_UNAVAIL;
209 if (strcasecmp(name, hn) != 0) {
211 *h_errnop = HOST_NOT_FOUND;
212 return NSS_STATUS_NOTFOUND;
215 return fill_in_hostent(hn, af, host, buffer, buflen, errnop, h_errnop, ttlp, canonp);
218 enum nss_status _nss_myhostname_gethostbyname2_r(
221 struct hostent *host,
222 char *buffer, size_t buflen,
223 int *errnop, int *h_errnop) {
225 return _nss_myhostname_gethostbyname3_r(
235 enum nss_status _nss_myhostname_gethostbyname_r (
237 struct hostent *host,
238 char *buffer, size_t buflen,
239 int *errnop, int *h_errnop) {
241 return _nss_myhostname_gethostbyname3_r(
251 enum nss_status _nss_myhostname_gethostbyaddr2_r(
252 const void* addr, socklen_t len,
254 struct hostent *host,
255 char *buffer, size_t buflen,
256 int *errnop, int *h_errnop,
259 char hn[HOST_NAME_MAX+1];
263 (*(uint32_t*) addr) != LOCALADDRESS_IPV4)
266 } else if (af == AF_INET6) {
268 memcmp(addr, LOCALADDRESS_IPV6, 16) != 0)
271 *errnop = EAFNOSUPPORT;
273 return NSS_STATUS_UNAVAIL;
276 memset(hn, 0, sizeof(hn));
277 if (gethostname(hn, sizeof(hn)-1) < 0) {
279 *h_errnop = NO_RECOVERY;
280 return NSS_STATUS_UNAVAIL;
283 return fill_in_hostent(hn, af, host, buffer, buflen, errnop, h_errnop, ttlp, NULL);
287 *h_errnop = HOST_NOT_FOUND;
288 return NSS_STATUS_NOTFOUND;
291 enum nss_status _nss_myhostname_gethostbyaddr_r(
292 const void* addr, socklen_t len,
294 struct hostent *host,
295 char *buffer, size_t buflen,
296 int *errnop, int *h_errnop) {
298 return _nss_myhostname_gethostbyaddr2_r(