]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/nss-myhostname/nss-myhostname.c
tree-wide: drop license boilerplate
[thirdparty/systemd.git] / src / nss-myhostname / nss-myhostname.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
4e8c8252 2/***
cbc06dcd 3 This file is part of systemd.
4e8c8252 4
8041b5ba 5 Copyright 2008-2011 Lennart Poettering
4e8c8252 6***/
6b21f0cf 7
6b21f0cf 8#include <errno.h>
4e8c8252 9#include <net/if.h>
07630cea
LP
10#include <netdb.h>
11#include <nss.h>
8041b5ba 12#include <stdlib.h>
07630cea 13#include <string.h>
8041b5ba 14
b5efdb8a 15#include "alloc-util.h"
07630cea 16#include "hostname-util.h"
e80af1bd 17#include "local-addresses.h"
1c633045 18#include "macro.h"
c9fdc26e 19#include "nss-util.h"
0c5eb056 20#include "signal-util.h"
07630cea 21#include "string-util.h"
c9fdc26e 22#include "util.h"
4e8c8252
LP
23
24/* We use 127.0.0.2 as IPv4 address. This has the advantage over
25 * 127.0.0.1 that it can be translated back to the local hostname. For
26 * IPv6 we use ::1 which unfortunately will not translate back to the
3fdcecc8 27 * hostname but instead something like "localhost" or so. */
4e8c8252 28
8e38570e 29#define LOCALADDRESS_IPV4 (htobe32(0x7F000002))
4e8c8252 30#define LOCALADDRESS_IPV6 &in6addr_loopback
4e8c8252 31
c9fdc26e
LP
32NSS_GETHOSTBYNAME_PROTOTYPES(myhostname);
33NSS_GETHOSTBYADDR_PROTOTYPES(myhostname);
8041b5ba 34
4e8c8252
LP
35enum nss_status _nss_myhostname_gethostbyname4_r(
36 const char *name,
37 struct gaih_addrtuple **pat,
38 char *buffer, size_t buflen,
39 int *errnop, int *h_errnop,
40 int32_t *ttlp) {
41
8041b5ba 42 struct gaih_addrtuple *r_tuple, *r_tuple_prev = NULL;
e80af1bd 43 _cleanup_free_ struct local_address *addresses = NULL;
5502f0d9
LP
44 _cleanup_free_ char *hn = NULL;
45 const char *canonical = NULL;
a1077c84 46 int n_addresses = 0;
e8a7a315 47 uint32_t local_address_ipv4;
e80af1bd 48 struct local_address *a;
5502f0d9
LP
49 size_t l, idx, ms;
50 char *r_name;
e80af1bd 51 unsigned n;
4e8c8252 52
0c5eb056
LP
53 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
54
5502f0d9
LP
55 assert(name);
56 assert(pat);
57 assert(buffer);
58 assert(errnop);
59 assert(h_errnop);
60
61 if (is_localhost(name)) {
e8a7a315
LP
62 /* We respond to 'localhost', so that /etc/hosts
63 * is optional */
4e8c8252 64
e8a7a315 65 canonical = "localhost";
8e38570e 66 local_address_ipv4 = htobe32(INADDR_LOOPBACK);
e9140aff 67
46a5e0e7 68 } else if (is_gateway_hostname(name)) {
e9140aff 69
1d050e1e 70 n_addresses = local_gateways(NULL, 0, AF_UNSPEC, &addresses);
e9140aff
LP
71 if (n_addresses <= 0) {
72 *errnop = ENOENT;
73 *h_errnop = HOST_NOT_FOUND;
74 return NSS_STATUS_NOTFOUND;
75 }
76
5248e7e1 77 canonical = "_gateway";
e9140aff 78
e8a7a315 79 } else {
5502f0d9
LP
80 hn = gethostname_malloc();
81 if (!hn) {
82 *errnop = ENOMEM;
e8a7a315 83 *h_errnop = NO_RECOVERY;
5502f0d9 84 return NSS_STATUS_TRYAGAIN;
e8a7a315
LP
85 }
86
61233823 87 /* We respond to our local host name, our hostname suffixed with a single dot. */
5502f0d9 88 if (!streq(name, hn) && !streq_ptr(startswith(name, hn), ".")) {
e8a7a315
LP
89 *errnop = ENOENT;
90 *h_errnop = HOST_NOT_FOUND;
91 return NSS_STATUS_NOTFOUND;
92 }
93
1d050e1e 94 n_addresses = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
e80af1bd
LP
95 if (n_addresses < 0)
96 n_addresses = 0;
e8a7a315
LP
97
98 canonical = hn;
99 local_address_ipv4 = LOCALADDRESS_IPV4;
100 }
8041b5ba 101
e8a7a315 102 l = strlen(canonical);
5502f0d9 103 ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * (n_addresses > 0 ? n_addresses : 2);
4e8c8252 104 if (buflen < ms) {
cda458a5
LP
105 *errnop = ERANGE;
106 *h_errnop = NETDB_INTERNAL;
4e8c8252
LP
107 return NSS_STATUS_TRYAGAIN;
108 }
109
110 /* First, fill in hostname */
111 r_name = buffer;
e8a7a315 112 memcpy(r_name, canonical, l+1);
4e8c8252
LP
113 idx = ALIGN(l+1);
114
68a9c7c4
ZJS
115 assert(n_addresses >= 0);
116 if (n_addresses == 0) {
8041b5ba
LP
117 /* Second, fill in IPv6 tuple */
118 r_tuple = (struct gaih_addrtuple*) (buffer + idx);
119 r_tuple->next = r_tuple_prev;
120 r_tuple->name = r_name;
121 r_tuple->family = AF_INET6;
122 memcpy(r_tuple->addr, LOCALADDRESS_IPV6, 16);
a1077c84 123 r_tuple->scopeid = 0;
8041b5ba
LP
124
125 idx += ALIGN(sizeof(struct gaih_addrtuple));
126 r_tuple_prev = r_tuple;
127
128 /* Third, fill in IPv4 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_INET;
e8a7a315 133 *(uint32_t*) r_tuple->addr = local_address_ipv4;
a1077c84 134 r_tuple->scopeid = 0;
8041b5ba
LP
135
136 idx += ALIGN(sizeof(struct gaih_addrtuple));
137 r_tuple_prev = r_tuple;
138 }
139
140 /* Fourth, fill actual addresses in, but in backwards order */
e80af1bd 141 for (a = addresses + n_addresses - 1, n = 0; (int) n < n_addresses; n++, a--) {
8041b5ba
LP
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 = a->family;
a1077c84 146 r_tuple->scopeid = a->family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&a->address.in6) ? a->ifindex : 0;
5502f0d9 147 memcpy(r_tuple->addr, &a->address, 16);
8041b5ba
LP
148
149 idx += ALIGN(sizeof(struct gaih_addrtuple));
150 r_tuple_prev = r_tuple;
151 }
4e8c8252
LP
152
153 /* Verify the size matches */
154 assert(idx == ms);
155
d2f1f23a
ED
156 /* Nscd expects us to store the first record in **pat. */
157 if (*pat)
158 **pat = *r_tuple_prev;
159 else
160 *pat = r_tuple_prev;
4e8c8252
LP
161
162 if (ttlp)
163 *ttlp = 0;
164
e70df46b
LP
165 /* Explicitly reset all error variables */
166 *errnop = 0;
167 *h_errnop = NETDB_SUCCESS;
168 h_errno = 0;
169
4e8c8252
LP
170 return NSS_STATUS_SUCCESS;
171}
6b21f0cf
LP
172
173static enum nss_status fill_in_hostent(
e8a7a315 174 const char *canonical, const char *additional,
4e8c8252 175 int af,
e80af1bd 176 struct local_address *addresses, unsigned n_addresses,
e8a7a315 177 uint32_t local_address_ipv4,
4e8c8252
LP
178 struct hostent *result,
179 char *buffer, size_t buflen,
180 int *errnop, int *h_errnop,
181 int32_t *ttlp,
182 char **canonp) {
183
d4c9895d 184 size_t l_canonical, l_additional, idx, ms, alen;
e8a7a315 185 char *r_addr, *r_name, *r_aliases, *r_alias = NULL, *r_addr_list;
e80af1bd 186 struct local_address *a;
e8a7a315 187 unsigned n, c;
8041b5ba 188
5502f0d9
LP
189 assert(canonical);
190 assert(result);
191 assert(buffer);
192 assert(errnop);
193 assert(h_errnop);
194
9d485985 195 alen = FAMILY_ADDRESS_SIZE(af);
8041b5ba 196
8041b5ba
LP
197 for (a = addresses, n = 0, c = 0; n < n_addresses; a++, n++)
198 if (af == a->family)
199 c++;
4e8c8252 200
e8a7a315 201 l_canonical = strlen(canonical);
7bf7ce28 202 l_additional = strlen_ptr(additional);
e8a7a315
LP
203 ms = ALIGN(l_canonical+1)+
204 (additional ? ALIGN(l_additional+1) : 0) +
5502f0d9 205 sizeof(char*) +
e8a7a315 206 (additional ? sizeof(char*) : 0) +
d4c9895d 207 (c > 0 ? c : 1) * ALIGN(alen) +
5502f0d9 208 (c > 0 ? c+1 : 2) * sizeof(char*);
8041b5ba 209
4e8c8252 210 if (buflen < ms) {
cda458a5
LP
211 *errnop = ERANGE;
212 *h_errnop = NETDB_INTERNAL;
4e8c8252
LP
213 return NSS_STATUS_TRYAGAIN;
214 }
215
e8a7a315 216 /* First, fill in hostnames */
4e8c8252 217 r_name = buffer;
e8a7a315
LP
218 memcpy(r_name, canonical, l_canonical+1);
219 idx = ALIGN(l_canonical+1);
4e8c8252 220
e8a7a315
LP
221 if (additional) {
222 r_alias = buffer + idx;
223 memcpy(r_alias, additional, l_additional+1);
224 idx += ALIGN(l_additional+1);
225 }
226
227 /* Second, create aliases array */
4e8c8252 228 r_aliases = buffer + idx;
e8a7a315
LP
229 if (additional) {
230 ((char**) r_aliases)[0] = r_alias;
231 ((char**) r_aliases)[1] = NULL;
232 idx += 2*sizeof(char*);
233 } else {
234 ((char**) r_aliases)[0] = NULL;
235 idx += sizeof(char*);
236 }
4e8c8252 237
8041b5ba 238 /* Third, add addresses */
4e8c8252 239 r_addr = buffer + idx;
8041b5ba
LP
240 if (c > 0) {
241 unsigned i = 0;
242
243 for (a = addresses, n = 0; n < n_addresses; a++, n++) {
244 if (af != a->family)
245 continue;
246
5502f0d9 247 memcpy(r_addr + i*ALIGN(alen), &a->address, alen);
8041b5ba
LP
248 i++;
249 }
250
251 assert(i == c);
252 idx += c*ALIGN(alen);
253 } else {
254 if (af == AF_INET)
e8a7a315 255 *(uint32_t*) r_addr = local_address_ipv4;
8041b5ba
LP
256 else
257 memcpy(r_addr, LOCALADDRESS_IPV6, 16);
258
259 idx += ALIGN(alen);
260 }
4e8c8252
LP
261
262 /* Fourth, add address pointer array */
263 r_addr_list = buffer + idx;
8041b5ba 264 if (c > 0) {
d4c9895d 265 unsigned i;
8041b5ba 266
d4c9895d
LP
267 for (i = 0; i < c; i++)
268 ((char**) r_addr_list)[i] = r_addr + i*ALIGN(alen);
8041b5ba 269
d4c9895d
LP
270 ((char**) r_addr_list)[i] = NULL;
271 idx += (c+1) * sizeof(char*);
8041b5ba
LP
272
273 } else {
274 ((char**) r_addr_list)[0] = r_addr;
275 ((char**) r_addr_list)[1] = NULL;
d4c9895d 276 idx += 2 * sizeof(char*);
8041b5ba 277 }
4e8c8252
LP
278
279 /* Verify the size matches */
280 assert(idx == ms);
281
282 result->h_name = r_name;
283 result->h_aliases = (char**) r_aliases;
284 result->h_addrtype = af;
285 result->h_length = alen;
286 result->h_addr_list = (char**) r_addr_list;
287
288 if (ttlp)
289 *ttlp = 0;
290
291 if (canonp)
292 *canonp = r_name;
293
e70df46b
LP
294 /* Explicitly reset all error variables */
295 *errnop = 0;
296 *h_errnop = NETDB_SUCCESS;
297 h_errno = 0;
298
4e8c8252 299 return NSS_STATUS_SUCCESS;
6b21f0cf
LP
300}
301
4e8c8252
LP
302enum nss_status _nss_myhostname_gethostbyname3_r(
303 const char *name,
304 int af,
305 struct hostent *host,
306 char *buffer, size_t buflen,
307 int *errnop, int *h_errnop,
308 int32_t *ttlp,
309 char **canonp) {
6b21f0cf 310
e80af1bd 311 _cleanup_free_ struct local_address *addresses = NULL;
e8a7a315 312 const char *canonical, *additional = NULL;
5502f0d9 313 _cleanup_free_ char *hn = NULL;
e9140aff 314 uint32_t local_address_ipv4 = 0;
e80af1bd 315 int n_addresses = 0;
5502f0d9 316
0c5eb056
LP
317 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
318
5502f0d9
LP
319 assert(name);
320 assert(host);
321 assert(buffer);
322 assert(errnop);
323 assert(h_errnop);
6b21f0cf 324
4e8c8252
LP
325 if (af == AF_UNSPEC)
326 af = AF_INET;
6b21f0cf 327
ec2ce0c5 328 if (!IN_SET(af, AF_INET, AF_INET6)) {
4e8c8252
LP
329 *errnop = EAFNOSUPPORT;
330 *h_errnop = NO_DATA;
331 return NSS_STATUS_UNAVAIL;
332 }
6b21f0cf 333
5502f0d9 334 if (is_localhost(name)) {
e8a7a315 335 canonical = "localhost";
8e38570e 336 local_address_ipv4 = htobe32(INADDR_LOOPBACK);
e9140aff 337
46a5e0e7 338 } else if (is_gateway_hostname(name)) {
e9140aff 339
1d050e1e 340 n_addresses = local_gateways(NULL, 0, af, &addresses);
e9140aff
LP
341 if (n_addresses <= 0) {
342 *errnop = ENOENT;
343 *h_errnop = HOST_NOT_FOUND;
344 return NSS_STATUS_NOTFOUND;
345 }
346
5248e7e1 347 canonical = "_gateway";
e9140aff 348
e8a7a315 349 } else {
5502f0d9
LP
350 hn = gethostname_malloc();
351 if (!hn) {
352 *errnop = ENOMEM;
e8a7a315 353 *h_errnop = NO_RECOVERY;
5502f0d9 354 return NSS_STATUS_TRYAGAIN;
e8a7a315 355 }
6b21f0cf 356
5502f0d9 357 if (!streq(name, hn) && !streq_ptr(startswith(name, hn), ".")) {
e8a7a315
LP
358 *errnop = ENOENT;
359 *h_errnop = HOST_NOT_FOUND;
360 return NSS_STATUS_NOTFOUND;
361 }
362
1d050e1e 363 n_addresses = local_addresses(NULL, 0, af, &addresses);
e80af1bd
LP
364 if (n_addresses < 0)
365 n_addresses = 0;
e8a7a315
LP
366
367 canonical = hn;
368 additional = n_addresses <= 0 && af == AF_INET6 ? "localhost" : NULL;
369 local_address_ipv4 = LOCALADDRESS_IPV4;
4e8c8252 370 }
6b21f0cf 371
e8a7a315
LP
372 return fill_in_hostent(
373 canonical, additional,
374 af,
375 addresses, n_addresses,
376 local_address_ipv4,
377 host,
378 buffer, buflen,
379 errnop, h_errnop,
380 ttlp,
381 canonp);
4e8c8252 382}
6b21f0cf 383
4e8c8252
LP
384enum nss_status _nss_myhostname_gethostbyaddr2_r(
385 const void* addr, socklen_t len,
386 int af,
387 struct hostent *host,
388 char *buffer, size_t buflen,
389 int *errnop, int *h_errnop,
390 int32_t *ttlp) {
6b21f0cf 391
e8a7a315 392 const char *canonical = NULL, *additional = NULL;
5502f0d9 393 uint32_t local_address_ipv4 = LOCALADDRESS_IPV4;
e80af1bd 394 _cleanup_free_ struct local_address *addresses = NULL;
5502f0d9 395 _cleanup_free_ char *hn = NULL;
e80af1bd
LP
396 int n_addresses = 0;
397 struct local_address *a;
3fdcecc8 398 bool additional_from_hostname = false;
e80af1bd 399 unsigned n;
5502f0d9 400
0c5eb056
LP
401 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
402
5502f0d9
LP
403 assert(addr);
404 assert(host);
405 assert(buffer);
406 assert(errnop);
407 assert(h_errnop);
8041b5ba 408
555bd6e9
LP
409 if (!IN_SET(af, AF_INET, AF_INET6)) {
410 *errnop = EAFNOSUPPORT;
411 *h_errnop = NO_DATA;
412 return NSS_STATUS_UNAVAIL;
413 }
414
9d485985 415 if (len != FAMILY_ADDRESS_SIZE(af)) {
8041b5ba
LP
416 *errnop = EINVAL;
417 *h_errnop = NO_RECOVERY;
418 return NSS_STATUS_UNAVAIL;
419 }
6b21f0cf 420
4e8c8252 421 if (af == AF_INET) {
8041b5ba
LP
422 if ((*(uint32_t*) addr) == LOCALADDRESS_IPV4)
423 goto found;
6b21f0cf 424
8e38570e 425 if ((*(uint32_t*) addr) == htobe32(INADDR_LOOPBACK)) {
e8a7a315 426 canonical = "localhost";
8e38570e 427 local_address_ipv4 = htobe32(INADDR_LOOPBACK);
e8a7a315
LP
428 goto found;
429 }
430
555bd6e9
LP
431 } else {
432 assert(af == AF_INET6);
8041b5ba 433
e8a7a315 434 if (memcmp(addr, LOCALADDRESS_IPV6, 16) == 0) {
3fdcecc8
LP
435 canonical = "localhost";
436 additional_from_hostname = true;
8041b5ba 437 goto found;
e8a7a315 438 }
4e8c8252
LP
439 }
440
1d050e1e 441 n_addresses = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
68a9c7c4
ZJS
442 for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) {
443 if (af != a->family)
444 continue;
8041b5ba 445
68a9c7c4
ZJS
446 if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0)
447 goto found;
e9140aff
LP
448 }
449
97b11eed 450 addresses = mfree(addresses);
e9140aff 451
1d050e1e 452 n_addresses = local_gateways(NULL, 0, AF_UNSPEC, &addresses);
68a9c7c4
ZJS
453 for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) {
454 if (af != a->family)
455 continue;
e9140aff 456
68a9c7c4 457 if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0) {
5248e7e1 458 canonical = "_gateway";
68a9c7c4 459 goto found;
e9140aff 460 }
8041b5ba
LP
461 }
462
463 *errnop = ENOENT;
464 *h_errnop = HOST_NOT_FOUND;
8041b5ba
LP
465 return NSS_STATUS_NOTFOUND;
466
467found:
82e4c2d6 468 if (!canonical || additional_from_hostname) {
3fdcecc8
LP
469 hn = gethostname_malloc();
470 if (!hn) {
471 *errnop = ENOMEM;
472 *h_errnop = NO_RECOVERY;
473 return NSS_STATUS_TRYAGAIN;
474 }
475
476 if (!canonical)
477 canonical = hn;
82e4c2d6 478 else
3fdcecc8
LP
479 additional = hn;
480 }
4e8c8252 481
e8a7a315
LP
482 return fill_in_hostent(
483 canonical, additional,
484 af,
485 addresses, n_addresses,
486 local_address_ipv4,
487 host,
488 buffer, buflen,
489 errnop, h_errnop,
490 ttlp,
491 NULL);
4e8c8252 492}
6b21f0cf 493
c9fdc26e
LP
494NSS_GETHOSTBYNAME_FALLBACKS(myhostname);
495NSS_GETHOSTBYADDR_FALLBACKS(myhostname);