/src/proftpd/src/netaddr.c
Line | Count | Source |
1 | | /* |
2 | | * ProFTPD - FTP server daemon |
3 | | * Copyright (c) 2003-2026 The ProFTPD Project team |
4 | | * |
5 | | * This program is free software; you can redistribute it and/or modify |
6 | | * it under the terms of the GNU General Public License as published by |
7 | | * the Free Software Foundation; either version 2 of the License, or |
8 | | * (at your option) any later version. |
9 | | * |
10 | | * This program is distributed in the hope that it will be useful, |
11 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | | * GNU General Public License for more details. |
14 | | * |
15 | | * You should have received a copy of the GNU General Public License |
16 | | * along with this program; if not, see <https://www.gnu.org/licenses/>. |
17 | | * |
18 | | * As a special exemption, The ProFTPD Project team and other respective |
19 | | * copyright holders give permission to link this program with OpenSSL, and |
20 | | * distribute the resulting executable, without including the source code for |
21 | | * OpenSSL in the source distribution. |
22 | | */ |
23 | | |
24 | | /* Network address routines */ |
25 | | |
26 | | #include "conf.h" |
27 | | |
28 | | #if HAVE_NET_IF_H |
29 | | # include <net/if.h> |
30 | | #endif |
31 | | #if HAVE_IFADDRS_H |
32 | | # include <ifaddrs.h> |
33 | | #endif |
34 | | |
35 | | /* Define an IPv4 equivalent of the IN6_IS_ADDR_LOOPBACK macro. */ |
36 | | #undef IN_IS_ADDR_LOOPBACK |
37 | | #define IN_IS_ADDR_LOOPBACK(a) \ |
38 | 0 | ((((unsigned long int) ntohl((a)->s_addr)) & 0xff000000) == 0x7f000000) |
39 | | |
40 | | static pr_netaddr_t sess_local_addr; |
41 | | static int have_sess_local_addr = FALSE; |
42 | | |
43 | | static pr_netaddr_t sess_remote_addr; |
44 | | static char sess_remote_name[PR_TUNABLE_BUFFER_SIZE]; |
45 | | static int have_sess_remote_addr = FALSE; |
46 | | |
47 | | /* Do reverse DNS lookups? */ |
48 | | static int reverse_dns = 1; |
49 | | |
50 | | /* Use IPv6? */ |
51 | | #ifdef PR_USE_IPV6 |
52 | | static int use_ipv6 = TRUE; |
53 | | #else |
54 | | static int use_ipv6 = FALSE; |
55 | | #endif /* PR_USE_IPV6 */ |
56 | | |
57 | | static char localaddr_str[PR_TUNABLE_BUFFER_SIZE]; |
58 | | static int have_localaddr_str = FALSE; |
59 | | |
60 | | static pool *netaddr_pool = NULL; |
61 | | static pr_table_t *netaddr_iptab = NULL; |
62 | | static pr_table_t *netaddr_dnstab = NULL; |
63 | | |
64 | | static const char *trace_channel = "dns"; |
65 | | |
66 | | /* Netaddr cache management */ |
67 | 0 | static array_header *netaddr_dnscache_get(pool *p, const char *ip_str) { |
68 | 0 | array_header *res = NULL; |
69 | |
|
70 | 0 | if (netaddr_dnstab != NULL) { |
71 | 0 | const void *v; |
72 | |
|
73 | 0 | v = pr_table_get(netaddr_dnstab, ip_str, NULL); |
74 | 0 | if (v != NULL) { |
75 | 0 | res = (array_header *) v; |
76 | |
|
77 | 0 | pr_trace_msg(trace_channel, 4, |
78 | 0 | "using %d DNS %s from netaddr DNS cache for IP address '%s'", |
79 | 0 | res->nelts, res->nelts != 1 ? "names" : "name", ip_str); |
80 | |
|
81 | 0 | if (p) { |
82 | | /* If the caller provided a pool, return a copy of the array. */ |
83 | 0 | return copy_array_str(p, res); |
84 | 0 | } |
85 | | |
86 | 0 | return res; |
87 | 0 | } |
88 | 0 | } |
89 | | |
90 | 0 | pr_trace_msg(trace_channel, 12, |
91 | 0 | "no DNS names found in netaddr DNS cache for IP address '%s'", ip_str); |
92 | 0 | errno = ENOENT; |
93 | 0 | return NULL; |
94 | 0 | } |
95 | | |
96 | 0 | static void netaddr_dnscache_set(const char *ip_str, const char *dns_name) { |
97 | 0 | if (netaddr_dnstab != NULL) { |
98 | 0 | void *v = NULL; |
99 | 0 | array_header *res = NULL; |
100 | 0 | int add_list = FALSE; |
101 | |
|
102 | 0 | res = netaddr_dnscache_get(NULL, ip_str); |
103 | 0 | if (res == NULL) { |
104 | | /* No existing entries for this IP address yet. */ |
105 | 0 | res = make_array(netaddr_pool, 1, sizeof(char *)); |
106 | 0 | add_list = TRUE; |
107 | |
|
108 | 0 | } else { |
109 | 0 | register unsigned int i; |
110 | 0 | char **names; |
111 | | |
112 | | /* Check for duplicates. */ |
113 | 0 | names = res->elts; |
114 | 0 | for (i = 0; i < res->nelts; i++) { |
115 | 0 | if (names[i] != NULL) { |
116 | 0 | if (strcmp(names[i], dns_name) == 0) { |
117 | 0 | pr_trace_msg(trace_channel, 5, |
118 | 0 | "DNS name '%s' for IP address '%s' already stashed in the " |
119 | 0 | "netaddr DNS cache", dns_name, ip_str); |
120 | 0 | return; |
121 | 0 | } |
122 | 0 | } |
123 | 0 | } |
124 | 0 | } |
125 | | |
126 | 0 | *((char **) push_array(res)) = pstrdup(netaddr_pool, dns_name); |
127 | 0 | v = res; |
128 | |
|
129 | 0 | if (add_list == TRUE) { |
130 | 0 | if (pr_table_add(netaddr_dnstab, pstrdup(netaddr_pool, ip_str), v, |
131 | 0 | sizeof(array_header *)) < 0) { |
132 | 0 | pr_trace_msg(trace_channel, 3, |
133 | 0 | "error adding DNS name '%s' for IP address '%s' to the netaddr " |
134 | 0 | "DNS cache: %s", dns_name, ip_str, strerror(errno)); |
135 | |
|
136 | 0 | } else { |
137 | 0 | pr_trace_msg(trace_channel, 5, |
138 | 0 | "stashed DNS name '%s' for IP address '%s' in the netaddr DNS cache", |
139 | 0 | dns_name, ip_str); |
140 | 0 | } |
141 | |
|
142 | 0 | } else { |
143 | 0 | pr_trace_msg(trace_channel, 5, |
144 | 0 | "stashed DNS name '%s' for IP address '%s' in the netaddr DNS cache", |
145 | 0 | dns_name, ip_str); |
146 | 0 | } |
147 | 0 | } |
148 | 0 | } |
149 | | |
150 | 0 | static pr_netaddr_t *netaddr_ipcache_get(pool *p, const char *name) { |
151 | 0 | pr_netaddr_t *res = NULL; |
152 | |
|
153 | 0 | if (netaddr_iptab != NULL) { |
154 | 0 | const void *v; |
155 | |
|
156 | 0 | v = pr_table_get(netaddr_iptab, name, NULL); |
157 | 0 | if (v != NULL) { |
158 | 0 | res = (pr_netaddr_t *) v; |
159 | 0 | pr_trace_msg(trace_channel, 4, |
160 | 0 | "using IP address '%s' from netaddr IP cache for name '%s'", |
161 | 0 | pr_netaddr_get_ipstr(res), name); |
162 | | |
163 | | /* We return a copy of the cache's netaddr_t, if the caller provided |
164 | | * a pool for duplication. |
165 | | */ |
166 | 0 | if (p != NULL) { |
167 | 0 | pr_netaddr_t *dup_res = NULL; |
168 | |
|
169 | 0 | dup_res = pr_netaddr_dup(p, res); |
170 | 0 | if (dup_res == NULL) { |
171 | 0 | pr_log_debug(DEBUG0, "error duplicating address for name '%s' " |
172 | 0 | "from cache: %s", name, strerror(errno)); |
173 | 0 | } |
174 | |
|
175 | 0 | return dup_res; |
176 | 0 | } |
177 | | |
178 | 0 | return res; |
179 | 0 | } |
180 | 0 | } |
181 | | |
182 | 0 | pr_trace_msg(trace_channel, 2, |
183 | 0 | "no IP address found in netaddr IP cache for name '%s'", name); |
184 | 0 | errno = ENOENT; |
185 | 0 | return NULL; |
186 | 0 | } |
187 | | |
188 | 0 | static int netaddr_ipcache_set(const char *name, const pr_netaddr_t *na) { |
189 | 0 | if (netaddr_iptab != NULL) { |
190 | 0 | int count = 0; |
191 | 0 | void *v = NULL; |
192 | | |
193 | | /* We store an internal copy of the netaddr_t in the cache. */ |
194 | 0 | v = pr_netaddr_dup(netaddr_pool, na); |
195 | 0 | if (v == NULL) { |
196 | 0 | return -1; |
197 | 0 | } |
198 | | |
199 | 0 | count = pr_table_exists(netaddr_iptab, name); |
200 | 0 | if (count <= 0) { |
201 | 0 | if (pr_table_add(netaddr_iptab, pstrdup(netaddr_pool, name), v, |
202 | 0 | sizeof(pr_netaddr_t *)) < 0) { |
203 | 0 | pr_trace_msg(trace_channel, 3, |
204 | 0 | "error adding IP address '%s' for name '%s' to the netaddr " |
205 | 0 | "IP cache: %s", pr_netaddr_get_ipstr(na), name, |
206 | 0 | strerror(errno)); |
207 | |
|
208 | 0 | } else { |
209 | 0 | pr_trace_msg(trace_channel, 5, |
210 | 0 | "stashed IP address '%s' for name '%s' in the netaddr IP cache", |
211 | 0 | pr_netaddr_get_ipstr(v), name); |
212 | 0 | } |
213 | |
|
214 | 0 | } else { |
215 | 0 | if (pr_table_set(netaddr_iptab, pstrdup(netaddr_pool, name), v, |
216 | 0 | sizeof(pr_netaddr_t *)) < 0) { |
217 | 0 | pr_trace_msg(trace_channel, 3, |
218 | 0 | "error setting IP address '%s' for name '%s' in the netaddr " |
219 | 0 | "IP cache: %s", pr_netaddr_get_ipstr(na), name, strerror(errno)); |
220 | 0 | } |
221 | 0 | } |
222 | 0 | } |
223 | | |
224 | 0 | return 0; |
225 | 0 | } |
226 | | |
227 | | /* Provide replacements for needed functions. */ |
228 | | |
229 | | #if !defined(HAVE_GETNAMEINFO) || defined(PR_USE_GETNAMEINFO) |
230 | | int pr_getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, |
231 | | size_t hostlen, char *serv, size_t servlen, int flags) { |
232 | | |
233 | | struct sockaddr_in *sai = (struct sockaddr_in *) sa; |
234 | | |
235 | | if (!sai || sai->sin_family != AF_INET) |
236 | | return EAI_FAMILY; |
237 | | |
238 | | if (serv != NULL && servlen > (size_t) 1) |
239 | | pr_snprintf(serv, servlen, "%lu", (unsigned long) ntohs(sai->sin_port)); |
240 | | |
241 | | if (host != NULL && hostlen > (size_t) 1) { |
242 | | struct hostent *he = NULL; |
243 | | |
244 | | if ((flags & NI_NUMERICHOST) == 0 && |
245 | | (he = gethostbyaddr((const char *) &(sai->sin_addr), |
246 | | sizeof(sai->sin_addr), AF_INET)) != NULL && |
247 | | he->h_name != NULL && |
248 | | *he->h_name != 0) { |
249 | | |
250 | | if (strlen(he->h_name) >= hostlen) |
251 | | goto handle_numeric_ip; |
252 | | sstrncpy(host, he->h_name, hostlen); |
253 | | |
254 | | } else { |
255 | | char *ipstr = NULL; |
256 | | |
257 | | handle_numeric_ip: |
258 | | ipstr = inet_ntoa(sai->sin_addr); |
259 | | if (ipstr == NULL) |
260 | | return EAI_SYSTEM; |
261 | | |
262 | | if (strlen(ipstr) >= hostlen) |
263 | | return EAI_FAIL; |
264 | | |
265 | | sstrncpy(host, ipstr, hostlen); |
266 | | } |
267 | | } |
268 | | |
269 | | return 0; |
270 | | } |
271 | | #endif /* HAVE_GETNAMEINFO or PR_USE_GETNAMEINFO */ |
272 | | |
273 | | #if !defined(HAVE_GETADDRINFO) || defined(PR_USE_GETADDRINFO) |
274 | | int pr_getaddrinfo(const char *node, const char *service, |
275 | | const struct addrinfo *hints, struct addrinfo **res) { |
276 | | struct addrinfo *ans = NULL; |
277 | | struct sockaddr_in *saddr = NULL; |
278 | | const char *proto_name = "tcp"; |
279 | | int socktype = SOCK_STREAM; |
280 | | unsigned short port = 0; |
281 | | |
282 | | if (res == NULL) { |
283 | | return EAI_FAIL; |
284 | | } |
285 | | |
286 | | *res = NULL; |
287 | | |
288 | | ans = malloc(sizeof(struct addrinfo)); |
289 | | if (ans == NULL) { |
290 | | return EAI_MEMORY; |
291 | | } |
292 | | |
293 | | saddr = malloc(sizeof(struct sockaddr_in)); |
294 | | if (saddr == NULL) { |
295 | | free(ans); |
296 | | return EAI_MEMORY; |
297 | | } |
298 | | |
299 | | ans->ai_family = AF_INET; |
300 | | ans->ai_addrlen = sizeof *saddr; |
301 | | ans->ai_addr = (struct sockaddr *) saddr; |
302 | | ans->ai_next = NULL; |
303 | | memset(saddr, 0, sizeof(*saddr)); |
304 | | saddr->sin_family = AF_INET; |
305 | | |
306 | | if (hints != NULL) { |
307 | | struct protoent *pe = NULL; |
308 | | |
309 | | if ((pe = getprotobynumber(hints->ai_protocol)) != NULL && |
310 | | pe->p_name != NULL && |
311 | | *pe->p_name != 0) |
312 | | proto_name = pe->p_name; |
313 | | |
314 | | if (hints->ai_socktype != 0) { |
315 | | socktype = hints->ai_socktype; |
316 | | |
317 | | } else if (strncasecmp(proto_name, "udp", 4) == 0) { |
318 | | socktype = SOCK_DGRAM; |
319 | | } |
320 | | } |
321 | | |
322 | | if (service != NULL) { |
323 | | struct servent *se = NULL; |
324 | | |
325 | | if ((se = getservbyname(service, proto_name)) != NULL && |
326 | | se->s_port > 0) { |
327 | | port = se->s_port; |
328 | | |
329 | | } else if ((port = (unsigned short) strtoul(service, NULL, 0)) <= 0 || |
330 | | port > 65535) { |
331 | | port = 0; |
332 | | } |
333 | | } |
334 | | |
335 | | if (hints != NULL && |
336 | | (hints->ai_flags & AI_PASSIVE) != 0) |
337 | | saddr->sin_addr.s_addr = htonl(INADDR_ANY); |
338 | | |
339 | | if (node != NULL) { |
340 | | struct hostent *he = NULL; |
341 | | |
342 | | if ((he = gethostbyname(node)) != NULL && |
343 | | he->h_addr_list != NULL && |
344 | | he->h_addr_list[0] != NULL && |
345 | | he->h_length > 0 && |
346 | | he->h_length <= (int) sizeof(saddr->sin_addr)) |
347 | | memcpy(&saddr->sin_addr, he->h_addr_list[0], he->h_length); |
348 | | } |
349 | | |
350 | | ans->ai_socktype = socktype; |
351 | | saddr->sin_port = htons(port); |
352 | | *res = ans; |
353 | | |
354 | | return 0; |
355 | | } |
356 | | |
357 | | void pr_freeaddrinfo(struct addrinfo *ai) { |
358 | | if (ai == NULL) { |
359 | | return; |
360 | | } |
361 | | |
362 | | if (ai->ai_addr != NULL) { |
363 | | free(ai->ai_addr); |
364 | | ai->ai_addr = NULL; |
365 | | } |
366 | | |
367 | | free(ai); |
368 | | } |
369 | | #endif /* HAVE_GETADDRINFO or PR_USE_GETADDRINFO */ |
370 | | |
371 | | #if !defined(HAVE_INET_NTOP) |
372 | | const char *pr_inet_ntop(int af, const void *src, char *dst, size_t len) { |
373 | | char *res; |
374 | | |
375 | | if (af != AF_INET) { |
376 | | errno = EAFNOSUPPORT; |
377 | | return NULL; |
378 | | } |
379 | | |
380 | | res = inet_ntoa(*((struct in_addr *) src)); |
381 | | if (res == NULL) |
382 | | return NULL; |
383 | | |
384 | | memcpy(dst, res, len); |
385 | | return dst; |
386 | | } |
387 | | #endif /* !HAVE_INET_NTOP */ |
388 | | |
389 | | #if !defined(HAVE_INET_PTON) |
390 | | int pr_inet_pton(int af, const char *src, void *dst) { |
391 | | unsigned long res; |
392 | | |
393 | | if (af != AF_INET) { |
394 | | errno = EAFNOSUPPORT; |
395 | | return -1; |
396 | | } |
397 | | |
398 | | /* inet_aton(3) would be better. However, it is not ubiquitous. */ |
399 | | res = inet_addr(src); |
400 | | if (res == INADDR_NONE || |
401 | | res == 0) |
402 | | return 0; |
403 | | |
404 | | memcpy(dst, &res, sizeof(res)); |
405 | | return 1; |
406 | | } |
407 | | #endif /* !HAVE_INET_PTON */ |
408 | | |
409 | 0 | static void *get_v4inaddr(const pr_netaddr_t *na) { |
410 | | |
411 | | /* This function is specifically for IPv4 clients (when gethostbyname2(2) is |
412 | | * present) that have an IPv4-mapped IPv6 address, when performing reverse |
413 | | * DNS checks. This function is called iff the given netaddr object is |
414 | | * indeed an IPv4-mapped IPv6 address. IPv6 address have 128 bits in their |
415 | | * sin6_addr field. For IPv4-mapped IPv6 addresses, the relevant 32 bits |
416 | | * are the last of those 128 bits (or, alternatively, the last 4 bytes of |
417 | | * those 16 bytes); hence the read of 12 bytes after the start of the |
418 | | * sin6_addr pointer. |
419 | | */ |
420 | |
|
421 | 0 | return (((char *) pr_netaddr_get_inaddr(na)) + 12); |
422 | 0 | } |
423 | | |
424 | | /* Validate anything returned from the 'outside', since it's untrusted |
425 | | * information. |
426 | | */ |
427 | 0 | char *pr_netaddr_validate_dns_str(char *buf) { |
428 | 0 | char *p; |
429 | |
|
430 | 0 | if (buf == NULL) { |
431 | 0 | errno = EINVAL; |
432 | 0 | return NULL; |
433 | 0 | } |
434 | | |
435 | | /* Validate anything returned from a DNS. */ |
436 | 0 | for (p = buf; p && *p; p++) { |
437 | | |
438 | | /* Per RFC requirements, these are all that are valid from a DNS. */ |
439 | 0 | if (!PR_ISALNUM(*p) && |
440 | 0 | *p != '.' && |
441 | 0 | *p != '-' |
442 | 0 | #ifdef PR_USE_IPV6 |
443 | 0 | && *p != ':' |
444 | 0 | #endif /* PR_USE_IPV6 */ |
445 | 0 | ) { |
446 | | |
447 | | /* We set it to _ because we know that's an invalid, yet safe, option |
448 | | * for a DNS entry. |
449 | | */ |
450 | 0 | *p = '_'; |
451 | 0 | } |
452 | 0 | } |
453 | |
|
454 | 0 | return buf; |
455 | 0 | } |
456 | | |
457 | 0 | int pr_netaddr_set_reverse_dns(int enable) { |
458 | 0 | int old_enable = reverse_dns; |
459 | 0 | reverse_dns = enable; |
460 | 0 | return old_enable; |
461 | 0 | } |
462 | | |
463 | 0 | pr_netaddr_t *pr_netaddr_alloc(pool *p) { |
464 | 0 | if (p == NULL) { |
465 | 0 | errno = EINVAL; |
466 | 0 | return NULL; |
467 | 0 | } |
468 | | |
469 | 0 | return pcalloc(p, sizeof(pr_netaddr_t)); |
470 | 0 | } |
471 | | |
472 | 0 | void pr_netaddr_clear(pr_netaddr_t *na) { |
473 | 0 | if (na == NULL) { |
474 | 0 | return; |
475 | 0 | } |
476 | | |
477 | 0 | memset(na, 0, sizeof(pr_netaddr_t)); |
478 | 0 | } |
479 | | |
480 | 0 | pr_netaddr_t *pr_netaddr_dup(pool *p, const pr_netaddr_t *na) { |
481 | 0 | pr_netaddr_t *dup_na; |
482 | |
|
483 | 0 | if (p == NULL || |
484 | 0 | na == NULL) { |
485 | 0 | errno = EINVAL; |
486 | 0 | return NULL; |
487 | 0 | } |
488 | | |
489 | 0 | dup_na = pr_netaddr_alloc(p); |
490 | |
|
491 | 0 | if (pr_netaddr_set_family(dup_na, pr_netaddr_get_family(na)) < 0) { |
492 | 0 | return NULL; |
493 | 0 | } |
494 | | |
495 | 0 | pr_netaddr_set_sockaddr(dup_na, pr_netaddr_get_sockaddr(na)); |
496 | |
|
497 | 0 | if (na->na_have_ipstr) { |
498 | 0 | sstrncpy(dup_na->na_ipstr, na->na_ipstr, sizeof(dup_na->na_ipstr)); |
499 | 0 | dup_na->na_have_ipstr = 1; |
500 | 0 | } |
501 | |
|
502 | 0 | if (na->na_have_dnsstr) { |
503 | 0 | sstrncpy(dup_na->na_dnsstr, na->na_dnsstr, sizeof(dup_na->na_dnsstr)); |
504 | 0 | dup_na->na_have_dnsstr = 1; |
505 | 0 | } |
506 | |
|
507 | 0 | return dup_na; |
508 | 0 | } |
509 | | |
510 | | static pr_netaddr_t *get_addr_by_ip(pool *p, const char *name, |
511 | 0 | array_header **addrs, unsigned int flags) { |
512 | 0 | struct sockaddr_in v4; |
513 | 0 | pr_netaddr_t *na = NULL; |
514 | 0 | int res; |
515 | |
|
516 | 0 | #ifdef PR_USE_IPV6 |
517 | 0 | if (use_ipv6 == TRUE) { |
518 | 0 | struct sockaddr_in6 v6; |
519 | 0 | memset(&v6, 0, sizeof(v6)); |
520 | 0 | v6.sin6_family = AF_INET6; |
521 | |
|
522 | | # ifdef SIN6_LEN |
523 | | v6.sin6_len = sizeof(struct sockaddr_in6); |
524 | | # endif /* SIN6_LEN */ |
525 | |
|
526 | 0 | res = pr_inet_pton(AF_INET6, name, &v6.sin6_addr); |
527 | 0 | if (res > 0) { |
528 | 0 | na = (pr_netaddr_t *) pcalloc(p, sizeof(pr_netaddr_t)); |
529 | 0 | pr_netaddr_set_family(na, AF_INET6); |
530 | 0 | pr_netaddr_set_sockaddr(na, (struct sockaddr *) &v6); |
531 | 0 | if (addrs != NULL) { |
532 | 0 | *addrs = NULL; |
533 | 0 | } |
534 | |
|
535 | 0 | pr_trace_msg(trace_channel, 7, "'%s' resolved to IPv6 address %s", name, |
536 | 0 | pr_netaddr_get_ipstr(na)); |
537 | |
|
538 | 0 | if (!(flags & PR_NETADDR_GET_ADDR_FL_EXCL_CACHE)) { |
539 | 0 | if (netaddr_ipcache_set(name, na) < 0) { |
540 | 0 | pr_trace_msg(trace_channel, 2, "error setting '%s' in cache: %s", |
541 | 0 | name, strerror(errno)); |
542 | 0 | } |
543 | |
|
544 | 0 | if (netaddr_ipcache_set(pr_netaddr_get_ipstr(na), na) < 0) { |
545 | 0 | pr_trace_msg(trace_channel, 2, "error setting '%s' in cache: %s", |
546 | 0 | pr_netaddr_get_ipstr(na), strerror(errno)); |
547 | 0 | } |
548 | 0 | } |
549 | |
|
550 | 0 | return na; |
551 | 0 | } |
552 | 0 | } |
553 | 0 | #endif /* PR_USE_IPV6 */ |
554 | | |
555 | 0 | memset(&v4, 0, sizeof(v4)); |
556 | 0 | v4.sin_family = AF_INET; |
557 | |
|
558 | | # ifdef SIN_LEN |
559 | | v4.sin_len = sizeof(struct sockaddr_in); |
560 | | # endif /* SIN_LEN */ |
561 | |
|
562 | 0 | res = pr_inet_pton(AF_INET, name, &v4.sin_addr); |
563 | 0 | if (res > 0) { |
564 | 0 | na = (pr_netaddr_t *) pcalloc(p, sizeof(pr_netaddr_t)); |
565 | 0 | pr_netaddr_set_family(na, AF_INET); |
566 | 0 | pr_netaddr_set_sockaddr(na, (struct sockaddr *) &v4); |
567 | 0 | if (addrs != NULL) { |
568 | 0 | *addrs = NULL; |
569 | 0 | } |
570 | |
|
571 | 0 | pr_trace_msg(trace_channel, 7, "'%s' resolved to IPv4 address %s", name, |
572 | 0 | pr_netaddr_get_ipstr(na)); |
573 | |
|
574 | 0 | if (!(flags & PR_NETADDR_GET_ADDR_FL_EXCL_DNS)) { |
575 | 0 | if (netaddr_ipcache_set(name, na) < 0) { |
576 | 0 | pr_trace_msg(trace_channel, 2, "error setting '%s' in cache: %s", name, |
577 | 0 | strerror(errno)); |
578 | 0 | } |
579 | | |
580 | | /* Avoid duplicates. */ |
581 | 0 | if (strcmp(name, pr_netaddr_get_ipstr(na)) != 0) { |
582 | 0 | if (netaddr_ipcache_set(pr_netaddr_get_ipstr(na), na) < 0) { |
583 | 0 | pr_trace_msg(trace_channel, 2, "error setting '%s' in cache: %s", |
584 | 0 | pr_netaddr_get_ipstr(na), strerror(errno)); |
585 | 0 | } |
586 | 0 | } |
587 | 0 | } |
588 | |
|
589 | 0 | return na; |
590 | 0 | } |
591 | | |
592 | 0 | return NULL; |
593 | 0 | } |
594 | | |
595 | | static pr_netaddr_t *get_addr_by_name(pool *p, const char *name, |
596 | 0 | array_header **addrs, unsigned int flags) { |
597 | 0 | pr_netaddr_t *na = NULL; |
598 | 0 | int res, xerrno; |
599 | 0 | struct addrinfo hints, *info = NULL; |
600 | |
|
601 | 0 | memset(&hints, 0, sizeof(hints)); |
602 | 0 | hints.ai_family = AF_INET; |
603 | 0 | hints.ai_socktype = SOCK_STREAM; |
604 | 0 | hints.ai_protocol = IPPROTO_TCP; |
605 | 0 | info = NULL; |
606 | |
|
607 | 0 | xerrno = errno; |
608 | 0 | pr_trace_msg(trace_channel, 7, |
609 | 0 | "attempting to resolve '%s' to IPv4 address via DNS", name); |
610 | 0 | errno = xerrno; |
611 | 0 | res = pr_getaddrinfo(name, NULL, &hints, &info); |
612 | 0 | if (res != 0) { |
613 | 0 | xerrno = errno; |
614 | |
|
615 | 0 | if (res != EAI_SYSTEM) { |
616 | 0 | #ifdef PR_USE_IPV6 |
617 | 0 | if (use_ipv6 == TRUE) { |
618 | 0 | pr_trace_msg(trace_channel, 7, |
619 | 0 | "unable to resolve '%s' to an IPv4 address: %s", name, |
620 | 0 | pr_gai_strerror(res)); |
621 | |
|
622 | 0 | memset(&hints, 0, sizeof(hints)); |
623 | 0 | hints.ai_family = AF_INET6; |
624 | 0 | hints.ai_socktype = SOCK_STREAM; |
625 | 0 | hints.ai_protocol = IPPROTO_TCP; |
626 | 0 | info = NULL; |
627 | |
|
628 | 0 | pr_trace_msg(trace_channel, 7, |
629 | 0 | "attempting to resolve '%s' to IPv6 address via DNS", name); |
630 | 0 | errno = xerrno; |
631 | 0 | res = pr_getaddrinfo(name, NULL, &hints, &info); |
632 | 0 | xerrno = errno; |
633 | |
|
634 | 0 | if (res != 0) { |
635 | 0 | if (res != EAI_SYSTEM) { |
636 | 0 | pr_trace_msg(trace_channel, 5, |
637 | 0 | "unable to resolve '%s' to an IPv6 address: %s", name, |
638 | 0 | pr_gai_strerror(res)); |
639 | |
|
640 | 0 | if (res == EAI_NODATA || |
641 | 0 | res == EAI_NONAME) { |
642 | 0 | xerrno = ENOENT; |
643 | 0 | # if defined(EAFNOSUPPORT) |
644 | 0 | } else if (res == EAI_FAMILY) { |
645 | 0 | xerrno = EAFNOSUPPORT; |
646 | 0 | # endif /* EAFNOSUPPORT */ |
647 | 0 | } |
648 | |
|
649 | 0 | } else { |
650 | 0 | pr_trace_msg(trace_channel, 1, |
651 | 0 | "IPv6 getaddrinfo '%s' system error: [%d] %s", name, |
652 | 0 | xerrno, strerror(xerrno)); |
653 | 0 | } |
654 | 0 | } |
655 | |
|
656 | 0 | } else { |
657 | 0 | const char *errstr; |
658 | |
|
659 | 0 | errstr = pr_gai_strerror(res); |
660 | 0 | pr_trace_msg(trace_channel, 1, "IPv4 getaddrinfo '%s' error: %s", |
661 | 0 | name, errstr); |
662 | |
|
663 | 0 | if (res == EAI_NODATA || |
664 | 0 | res == EAI_NONAME) { |
665 | 0 | xerrno = ENOENT; |
666 | 0 | # if defined(EAFNOSUPPORT) |
667 | 0 | } else if (res == EAI_FAMILY) { |
668 | 0 | xerrno = EAFNOSUPPORT; |
669 | 0 | # endif /* EAFNOSUPPORT */ |
670 | 0 | } else { |
671 | | /* Note that this is a hack, to deal with GNU/Linux custom |
672 | | * gai_strerror(3) values which are not exported in the <netdb.h> |
673 | | * header by default. |
674 | | */ |
675 | 0 | if (strcmp(errstr, "Address family for hostname not supported") == 0) { |
676 | 0 | xerrno = EAFNOSUPPORT; |
677 | 0 | } |
678 | 0 | } |
679 | 0 | } |
680 | | #else |
681 | | pr_trace_msg(trace_channel, 1, "IPv4 getaddrinfo '%s' error: %s", |
682 | | name, pr_gai_strerror(res)); |
683 | | if (res == EAI_NODATA || |
684 | | res == EAI_NONAME) { |
685 | | xerrno = ENOENT; |
686 | | # if defined(EAFNOSUPPORT) |
687 | | } else if (res == EAI_FAMILY) { |
688 | | xerrno = EAFNOSUPPORT; |
689 | | # endif /* EAFNOSUPPORT */ |
690 | | } |
691 | | #endif /* PR_USE_IPV6 */ |
692 | |
|
693 | 0 | } else { |
694 | 0 | pr_trace_msg(trace_channel, 1, |
695 | 0 | "IPv4 getaddrinfo '%s' system error: [%d] %s", name, |
696 | 0 | xerrno, strerror(xerrno)); |
697 | 0 | } |
698 | |
|
699 | 0 | if (res != 0) { |
700 | 0 | errno = xerrno; |
701 | 0 | return NULL; |
702 | 0 | } |
703 | 0 | } |
704 | | |
705 | 0 | if (info != NULL) { |
706 | 0 | na = (pr_netaddr_t *) pcalloc(p, sizeof(pr_netaddr_t)); |
707 | | |
708 | | /* Copy the first returned addr into na, as the return value. */ |
709 | 0 | pr_netaddr_set_family(na, info->ai_family); |
710 | 0 | pr_netaddr_set_sockaddr(na, info->ai_addr); |
711 | |
|
712 | 0 | pr_trace_msg(trace_channel, 7, "resolved '%s' to %s address %s", name, |
713 | 0 | info->ai_family == AF_INET ? "IPv4" : "IPv6", |
714 | 0 | pr_netaddr_get_ipstr(na)); |
715 | |
|
716 | 0 | if (!(flags & PR_NETADDR_GET_ADDR_FL_EXCL_DNS)) { |
717 | 0 | if (netaddr_ipcache_set(name, na) < 0) { |
718 | 0 | pr_trace_msg(trace_channel, 2, "error setting '%s' in cache: %s", name, |
719 | 0 | strerror(errno)); |
720 | 0 | } |
721 | |
|
722 | 0 | if (netaddr_ipcache_set(pr_netaddr_get_ipstr(na), na) < 0) { |
723 | 0 | pr_trace_msg(trace_channel, 2, "error setting '%s' in cache: %s", |
724 | 0 | pr_netaddr_get_ipstr(na), strerror(errno)); |
725 | 0 | } |
726 | 0 | } |
727 | |
|
728 | 0 | if (addrs != NULL) { |
729 | 0 | struct addrinfo *next_info = NULL; |
730 | | |
731 | | /* Copy any other addrs into the list. */ |
732 | 0 | if (*addrs == NULL) { |
733 | 0 | *addrs = make_array(p, 0, sizeof(pr_netaddr_t *)); |
734 | 0 | } |
735 | |
|
736 | 0 | next_info = info->ai_next; |
737 | 0 | while (next_info != NULL) { |
738 | 0 | pr_netaddr_t **elt; |
739 | |
|
740 | 0 | pr_signals_handle(); |
741 | 0 | elt = push_array(*addrs); |
742 | |
|
743 | 0 | *elt = pcalloc(p, sizeof(pr_netaddr_t)); |
744 | 0 | pr_netaddr_set_family(*elt, next_info->ai_family); |
745 | 0 | pr_netaddr_set_sockaddr(*elt, next_info->ai_addr); |
746 | |
|
747 | 0 | pr_trace_msg(trace_channel, 7, "resolved '%s' to %s address %s", name, |
748 | 0 | next_info->ai_family == AF_INET ? "IPv4" : "IPv6", |
749 | 0 | pr_netaddr_get_ipstr(*elt)); |
750 | |
|
751 | 0 | next_info = next_info->ai_next; |
752 | 0 | } |
753 | 0 | } |
754 | |
|
755 | 0 | pr_freeaddrinfo(info); |
756 | 0 | } |
757 | |
|
758 | 0 | #ifdef PR_USE_IPV6 |
759 | 0 | if (use_ipv6 == TRUE && |
760 | 0 | addrs != NULL) { |
761 | | /* Do the call again, this time for IPv6 addresses. |
762 | | * |
763 | | * We make two separate getaddrinfo(3) calls, rather than one |
764 | | * with a hint of AF_UNSPEC, because of certain bugs where the use |
765 | | * of AF_UNSPEC does not function as advertised. (I suspect this |
766 | | * bug was caused by proftpd's calling pattern, but as I could |
767 | | * not track it down, and as there are reports of AF_UNSPEC not |
768 | | * being as fast as AF_INET/AF_INET6, it just seemed easier to |
769 | | * do it this way.) |
770 | | */ |
771 | |
|
772 | 0 | memset(&hints, 0, sizeof(hints)); |
773 | 0 | hints.ai_family = AF_INET6; |
774 | 0 | hints.ai_socktype = SOCK_STREAM; |
775 | 0 | hints.ai_protocol = IPPROTO_TCP; |
776 | 0 | info = NULL; |
777 | |
|
778 | 0 | pr_trace_msg(trace_channel, 7, |
779 | 0 | "attempting to resolve '%s' to IPv6 address via DNS", name); |
780 | 0 | res = pr_getaddrinfo(name, NULL, &hints, &info); |
781 | 0 | xerrno = errno; |
782 | |
|
783 | 0 | if (res != 0) { |
784 | 0 | if (res != EAI_SYSTEM) { |
785 | 0 | pr_trace_msg(trace_channel, 1, "IPv6 getaddrinfo '%s' error: %s", |
786 | 0 | name, pr_gai_strerror(res)); |
787 | |
|
788 | 0 | } else { |
789 | 0 | pr_trace_msg(trace_channel, 1, |
790 | 0 | "IPv6 getaddrinfo '%s' system error: [%d] %s", name, |
791 | 0 | xerrno, strerror(xerrno)); |
792 | 0 | } |
793 | |
|
794 | 0 | } else { |
795 | | /* We may have already looked up an IPv6 address as the first |
796 | | * address; we don't want to have duplicate addresses in the |
797 | | * returned list of additional addresses. |
798 | | */ |
799 | 0 | if (info != NULL) { |
800 | 0 | struct addrinfo *next_info = NULL; |
801 | | |
802 | | /* Copy any other addrs into the list. */ |
803 | 0 | if (*addrs == NULL) { |
804 | 0 | *addrs = make_array(p, 0, sizeof(pr_netaddr_t *)); |
805 | 0 | } |
806 | | |
807 | | /* Note that for this subsequent IPv6 lookup, we need to treat the |
808 | | * first struct addrinfo as an "additional" record, unlike our handling |
809 | | * of IPv4 results. Failure to do so means we might miss some IPv6 |
810 | | * addresses; see Bug#4428. |
811 | | */ |
812 | 0 | next_info = info; |
813 | 0 | while (next_info != NULL) { |
814 | 0 | pr_netaddr_t **elt; |
815 | |
|
816 | 0 | pr_signals_handle(); |
817 | 0 | elt = push_array(*addrs); |
818 | |
|
819 | 0 | *elt = pcalloc(p, sizeof(pr_netaddr_t)); |
820 | 0 | pr_netaddr_set_family(*elt, next_info->ai_family); |
821 | 0 | pr_netaddr_set_sockaddr(*elt, next_info->ai_addr); |
822 | |
|
823 | 0 | pr_trace_msg(trace_channel, 7, "resolved '%s' to %s address %s", name, |
824 | 0 | next_info->ai_family == AF_INET ? "IPv4" : "IPv6", |
825 | 0 | pr_netaddr_get_ipstr(*elt)); |
826 | |
|
827 | 0 | next_info = next_info->ai_next; |
828 | 0 | } |
829 | |
|
830 | 0 | pr_freeaddrinfo(info); |
831 | 0 | } |
832 | 0 | } |
833 | 0 | } |
834 | 0 | #endif /* PR_USE_IPV6 */ |
835 | |
|
836 | 0 | return na; |
837 | 0 | } |
838 | | |
839 | | static pr_netaddr_t *get_addr_by_device(pool *p, const char *name, |
840 | 0 | array_header **addrs, unsigned int flags) { |
841 | 0 | #ifdef HAVE_GETIFADDRS |
842 | 0 | struct ifaddrs *ifaddr = NULL; |
843 | 0 | pr_netaddr_t *na = NULL; |
844 | 0 | int res, xerrno; |
845 | | |
846 | | /* Try to use the given name as a device/interface name, and see if we |
847 | | * can suss out the IP address(es) to use based on that. |
848 | | */ |
849 | |
|
850 | 0 | res = getifaddrs(&ifaddr); |
851 | 0 | if (res < 0) { |
852 | 0 | xerrno = errno; |
853 | |
|
854 | 0 | pr_trace_msg(trace_channel, 1, |
855 | 0 | "error retrieving interfaces via getifaddrs(3): %s", strerror(xerrno)); |
856 | |
|
857 | 0 | } else { |
858 | 0 | struct ifaddrs *ifa; |
859 | 0 | int found_device = FALSE; |
860 | |
|
861 | 0 | for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { |
862 | 0 | pr_signals_handle(); |
863 | | |
864 | | /* Watch out for null ifa_addr, as when a device does not have |
865 | | * an associated address (e.g. due to not be initialized). |
866 | | */ |
867 | 0 | if (ifa->ifa_addr == NULL) { |
868 | 0 | continue; |
869 | 0 | } |
870 | | |
871 | | /* We're only looking for addresses, not stats. */ |
872 | 0 | if (ifa->ifa_addr->sa_family != AF_INET |
873 | 0 | #ifdef PR_USE_IPV6 |
874 | 0 | && ifa->ifa_addr->sa_family != AF_INET6 |
875 | 0 | #endif /* PR_USE_IPV6 */ |
876 | 0 | ) { |
877 | 0 | continue; |
878 | 0 | } |
879 | | |
880 | 0 | if (strcmp(ifa->ifa_name, name) == 0) { |
881 | 0 | if (found_device == FALSE) { |
882 | 0 | na = (pr_netaddr_t *) pcalloc(p, sizeof(pr_netaddr_t)); |
883 | |
|
884 | 0 | pr_netaddr_set_family(na, ifa->ifa_addr->sa_family); |
885 | 0 | pr_netaddr_set_sockaddr(na, ifa->ifa_addr); |
886 | |
|
887 | 0 | pr_trace_msg(trace_channel, 7, |
888 | 0 | "resolved '%s' to interface with %s address %s", name, |
889 | 0 | ifa->ifa_addr->sa_family == AF_INET ? "IPv4" : "IPv6", |
890 | 0 | pr_netaddr_get_ipstr(na)); |
891 | |
|
892 | 0 | found_device = TRUE; |
893 | | |
894 | | /* If the caller did not request additional addresses, then |
895 | | * return now. Otherwise, we keep looking for the other |
896 | | * addresses bound to this interface. |
897 | | */ |
898 | 0 | if (addrs == NULL) { |
899 | 0 | break; |
900 | 0 | } |
901 | |
|
902 | 0 | } else { |
903 | 0 | pr_netaddr_t **elt; |
904 | | |
905 | | /* We've already found the first match; this block happens |
906 | | * if the caller wants all of the addresses for this interface. |
907 | | */ |
908 | |
|
909 | 0 | *addrs = make_array(p, 0, sizeof(pr_netaddr_t *)); |
910 | 0 | elt = push_array(*addrs); |
911 | |
|
912 | 0 | *elt = pcalloc(p, sizeof(pr_netaddr_t)); |
913 | 0 | pr_netaddr_set_family(*elt, ifa->ifa_addr->sa_family); |
914 | 0 | pr_netaddr_set_sockaddr(*elt, ifa->ifa_addr); |
915 | |
|
916 | 0 | pr_trace_msg(trace_channel, 7, |
917 | 0 | "resolved '%s' to interface with %s address %s", name, |
918 | 0 | ifa->ifa_addr->sa_family == AF_INET ? "IPv4" : "IPv6", |
919 | 0 | pr_netaddr_get_ipstr(*elt)); |
920 | 0 | } |
921 | 0 | } |
922 | 0 | } |
923 | |
|
924 | 0 | if (ifaddr != NULL) { |
925 | 0 | freeifaddrs(ifaddr); |
926 | 0 | } |
927 | |
|
928 | 0 | if (found_device) { |
929 | 0 | return na; |
930 | 0 | } |
931 | 0 | } |
932 | | |
933 | 0 | errno = ENOENT; |
934 | | #else |
935 | | errno = ENOSYS; |
936 | | #endif /* HAVE_GETIFADDRS */ |
937 | |
|
938 | 0 | return NULL; |
939 | 0 | } |
940 | | |
941 | | const pr_netaddr_t *pr_netaddr_get_addr2(pool *p, const char *name, |
942 | 0 | array_header **addrs, unsigned int flags) { |
943 | 0 | pr_netaddr_t *na = NULL; |
944 | 0 | int xerrno = ENOENT; |
945 | |
|
946 | 0 | if (p == NULL || |
947 | 0 | name == NULL) { |
948 | 0 | errno = EINVAL; |
949 | 0 | return NULL; |
950 | 0 | } |
951 | | |
952 | 0 | pr_trace_msg(trace_channel, 10, "resolving name '%s' to IP address", |
953 | 0 | name); |
954 | | |
955 | | /* First, check our cache to see if this name has already been |
956 | | * resolved. We only want to use the cache, though, if the caller did not |
957 | | * provide the `addrs' pointer, indicating that the caller wants to know |
958 | | * about any additional addresses for the given name. The netaddr cache |
959 | | * is a simple cache, hidden from callers, and thus is unable to populate |
960 | | * that `addrs' pointer if the name is in the cache. |
961 | | */ |
962 | 0 | if (addrs == NULL) { |
963 | 0 | na = netaddr_ipcache_get(p, name); |
964 | 0 | if (na != NULL) { |
965 | 0 | return na; |
966 | 0 | } |
967 | 0 | } |
968 | | |
969 | | /* Attempt to translate the given name into a pr_netaddr_t using |
970 | | * pr_inet_pton() first. |
971 | | * |
972 | | * First, if IPv6 support is enabled, we try to translate the name using |
973 | | * pr_inet_pton(AF_INET6) on the hopes that the given string is a valid |
974 | | * representation of an IPv6 address. If that fails, or if IPv6 support |
975 | | * is not enabled, we try with pr_inet_pton(AF_INET). If that fails, we |
976 | | * assume that the given name is a DNS name, and we call pr_getaddrinfo(). |
977 | | */ |
978 | | |
979 | 0 | na = get_addr_by_ip(p, name, addrs, flags); |
980 | 0 | xerrno = errno; |
981 | |
|
982 | 0 | if (na != NULL) { |
983 | 0 | return na; |
984 | 0 | } |
985 | | |
986 | | /* If get_addr_by_ip() returns NULL, it means that name does not represent a |
987 | | * valid network address in the specified address family. Usually, |
988 | | * this means that name is actually a DNS name, not an IP address |
989 | | * string. So we treat it as a DNS name, and use getaddrinfo(3) to |
990 | | * resolve that name to its IP address(es) -- unless the EXCL_DNS flag |
991 | | * has been used, indicating that the caller does not want us resolving |
992 | | * DNS names. |
993 | | */ |
994 | | |
995 | 0 | if (!(flags & PR_NETADDR_GET_ADDR_FL_EXCL_DNS)) { |
996 | 0 | na = get_addr_by_name(p, name, addrs, flags); |
997 | 0 | xerrno = errno; |
998 | |
|
999 | 0 | if (na != NULL) { |
1000 | 0 | return na; |
1001 | 0 | } |
1002 | 0 | } |
1003 | | |
1004 | 0 | if (flags & PR_NETADDR_GET_ADDR_FL_INCL_DEVICE) { |
1005 | 0 | na = get_addr_by_device(p, name, addrs, flags); |
1006 | 0 | xerrno = errno; |
1007 | |
|
1008 | 0 | if (na != NULL) { |
1009 | 0 | return na; |
1010 | 0 | } |
1011 | 0 | } |
1012 | | |
1013 | 0 | pr_trace_msg(trace_channel, 8, "failed to resolve '%s' to an IP address", |
1014 | 0 | name); |
1015 | 0 | errno = xerrno; |
1016 | 0 | return NULL; |
1017 | 0 | } |
1018 | | |
1019 | | const pr_netaddr_t *pr_netaddr_get_addr(pool *p, const char *name, |
1020 | 0 | array_header **addrs) { |
1021 | 0 | return pr_netaddr_get_addr2(p, name, addrs, 0); |
1022 | 0 | } |
1023 | | |
1024 | 0 | int pr_netaddr_get_family(const pr_netaddr_t *na) { |
1025 | 0 | if (na == NULL) { |
1026 | 0 | errno = EINVAL; |
1027 | 0 | return -1; |
1028 | 0 | } |
1029 | | |
1030 | 0 | return na->na_family; |
1031 | 0 | } |
1032 | | |
1033 | 0 | int pr_netaddr_set_family(pr_netaddr_t *na, int family) { |
1034 | 0 | if (!na) { |
1035 | 0 | errno = EINVAL; |
1036 | 0 | return -1; |
1037 | 0 | } |
1038 | | |
1039 | | /* Set the family member of the appropriate sockaddr struct. */ |
1040 | 0 | switch (family) { |
1041 | 0 | case AF_INET: |
1042 | 0 | na->na_addr.v4.sin_family = AF_INET; |
1043 | 0 | break; |
1044 | | |
1045 | 0 | #ifdef PR_USE_IPV6 |
1046 | 0 | case AF_INET6: |
1047 | 0 | if (use_ipv6 == TRUE) { |
1048 | 0 | na->na_addr.v6.sin6_family = AF_INET6; |
1049 | 0 | break; |
1050 | 0 | } |
1051 | 0 | #endif /* PR_USE_IPV6 */ |
1052 | | |
1053 | 0 | default: |
1054 | 0 | #ifdef EAFNOSUPPORT |
1055 | 0 | errno = EAFNOSUPPORT; |
1056 | | #else |
1057 | | errno = EINVAL; |
1058 | | #endif |
1059 | 0 | return -1; |
1060 | 0 | } |
1061 | | |
1062 | 0 | na->na_family = family; |
1063 | 0 | return 0; |
1064 | 0 | } |
1065 | | |
1066 | 0 | size_t pr_netaddr_get_sockaddr_len(const pr_netaddr_t *na) { |
1067 | 0 | if (na == NULL) { |
1068 | 0 | errno = EINVAL; |
1069 | 0 | return -1; |
1070 | 0 | } |
1071 | | |
1072 | 0 | switch (pr_netaddr_get_family(na)) { |
1073 | 0 | case AF_INET: |
1074 | 0 | return sizeof(struct sockaddr_in); |
1075 | | |
1076 | 0 | #if defined(PR_USE_IPV6) |
1077 | 0 | case AF_INET6: |
1078 | 0 | if (use_ipv6 == TRUE) { |
1079 | 0 | return sizeof(struct sockaddr_in6); |
1080 | 0 | } |
1081 | 0 | #endif /* PR_USE_IPV6 */ |
1082 | 0 | } |
1083 | | |
1084 | 0 | errno = EPERM; |
1085 | 0 | return -1; |
1086 | 0 | } |
1087 | | |
1088 | 0 | size_t pr_netaddr_get_inaddr_len(const pr_netaddr_t *na) { |
1089 | 0 | if (na == NULL) { |
1090 | 0 | errno = EINVAL; |
1091 | 0 | return -1; |
1092 | 0 | } |
1093 | | |
1094 | 0 | switch (pr_netaddr_get_family(na)) { |
1095 | 0 | case AF_INET: |
1096 | 0 | return sizeof(struct in_addr); |
1097 | | |
1098 | 0 | #ifdef PR_USE_IPV6 |
1099 | 0 | case AF_INET6: |
1100 | 0 | return sizeof(struct in6_addr); |
1101 | 0 | #endif /* PR_USE_IPV6 */ |
1102 | 0 | } |
1103 | | |
1104 | 0 | errno = EPERM; |
1105 | 0 | return -1; |
1106 | 0 | } |
1107 | | |
1108 | 0 | struct sockaddr *pr_netaddr_get_sockaddr(const pr_netaddr_t *na) { |
1109 | 0 | if (na == NULL) { |
1110 | 0 | errno = EINVAL; |
1111 | 0 | return NULL; |
1112 | 0 | } |
1113 | | |
1114 | 0 | switch (pr_netaddr_get_family(na)) { |
1115 | 0 | case AF_INET: |
1116 | 0 | return (struct sockaddr *) &na->na_addr.v4; |
1117 | | |
1118 | 0 | #if defined(PR_USE_IPV6) |
1119 | 0 | case AF_INET6: |
1120 | 0 | if (use_ipv6 == TRUE) { |
1121 | 0 | return (struct sockaddr *) &na->na_addr.v6; |
1122 | 0 | } |
1123 | 0 | #endif /* PR_USE_IPV6 */ |
1124 | 0 | } |
1125 | | |
1126 | 0 | errno = EPERM; |
1127 | 0 | return NULL; |
1128 | 0 | } |
1129 | | |
1130 | 0 | int pr_netaddr_set_sockaddr(pr_netaddr_t *na, struct sockaddr *addr) { |
1131 | 0 | if (na == NULL || |
1132 | 0 | addr == NULL) { |
1133 | 0 | errno = EINVAL; |
1134 | 0 | return -1; |
1135 | 0 | } |
1136 | | |
1137 | 0 | memset(&na->na_addr, 0, sizeof(na->na_addr)); |
1138 | 0 | switch (na->na_family) { |
1139 | 0 | case AF_INET: |
1140 | 0 | memcpy(&(na->na_addr.v4), addr, sizeof(struct sockaddr_in)); |
1141 | 0 | return 0; |
1142 | | |
1143 | 0 | #if defined(PR_USE_IPV6) |
1144 | 0 | case AF_INET6: |
1145 | 0 | if (use_ipv6 == TRUE) { |
1146 | 0 | memcpy(&(na->na_addr.v6), addr, sizeof(struct sockaddr_in6)); |
1147 | 0 | return 0; |
1148 | 0 | } |
1149 | 0 | #endif /* PR_USE_IPV6 */ |
1150 | 0 | } |
1151 | | |
1152 | 0 | errno = EPERM; |
1153 | 0 | return -1; |
1154 | 0 | } |
1155 | | |
1156 | 0 | int pr_netaddr_set_sockaddr_any(pr_netaddr_t *na) { |
1157 | 0 | if (na == NULL) { |
1158 | 0 | errno = EINVAL; |
1159 | 0 | return -1; |
1160 | 0 | } |
1161 | | |
1162 | 0 | switch (pr_netaddr_get_family(na)) { |
1163 | 0 | case AF_INET: { |
1164 | 0 | struct in_addr in4addr_any; |
1165 | 0 | in4addr_any.s_addr = htonl(INADDR_ANY); |
1166 | 0 | na->na_addr.v4.sin_family = AF_INET; |
1167 | | #ifdef SIN_LEN |
1168 | | na->na_addr.v4.sin_len = sizeof(struct sockaddr_in); |
1169 | | #endif /* SIN_LEN */ |
1170 | 0 | memcpy(&na->na_addr.v4.sin_addr, &in4addr_any, sizeof(struct in_addr)); |
1171 | 0 | if (na->na_have_ipstr) { |
1172 | 0 | memset(na->na_ipstr, '\0', sizeof(na->na_ipstr)); |
1173 | 0 | sstrncpy(na->na_ipstr, "0.0.0.0", sizeof(na->na_ipstr)); |
1174 | 0 | } |
1175 | 0 | return 0; |
1176 | 0 | } |
1177 | | |
1178 | 0 | #ifdef PR_USE_IPV6 |
1179 | 0 | case AF_INET6: |
1180 | 0 | if (use_ipv6 == TRUE) { |
1181 | 0 | na->na_addr.v6.sin6_family = AF_INET6; |
1182 | | #ifdef SIN6_LEN |
1183 | | na->na_addr.v6.sin6_len = sizeof(struct sockaddr_in6); |
1184 | | #endif /* SIN6_LEN */ |
1185 | 0 | memcpy(&na->na_addr.v6.sin6_addr, &in6addr_any, sizeof(struct in6_addr)); |
1186 | 0 | if (na->na_have_ipstr) { |
1187 | 0 | memset(na->na_ipstr, '\0', sizeof(na->na_ipstr)); |
1188 | 0 | sstrncpy(na->na_ipstr, "::", sizeof(na->na_ipstr)); |
1189 | 0 | } |
1190 | 0 | return 0; |
1191 | 0 | } |
1192 | 0 | #endif /* PR_USE_IPV6 */ |
1193 | 0 | } |
1194 | | |
1195 | 0 | errno = EPERM; |
1196 | 0 | return -1; |
1197 | 0 | } |
1198 | | |
1199 | 0 | void *pr_netaddr_get_inaddr(const pr_netaddr_t *na) { |
1200 | 0 | if (na == NULL) { |
1201 | 0 | errno = EINVAL; |
1202 | 0 | return NULL; |
1203 | 0 | } |
1204 | | |
1205 | 0 | switch (pr_netaddr_get_family(na)) { |
1206 | 0 | case AF_INET: |
1207 | 0 | return (void *) &na->na_addr.v4.sin_addr; |
1208 | | |
1209 | 0 | #ifdef PR_USE_IPV6 |
1210 | 0 | case AF_INET6: |
1211 | 0 | if (use_ipv6 == TRUE) { |
1212 | 0 | return (void *) &na->na_addr.v6.sin6_addr; |
1213 | 0 | } |
1214 | 0 | #endif /* PR_USE_IPV6 */ |
1215 | 0 | } |
1216 | | |
1217 | 0 | errno = EPERM; |
1218 | 0 | return NULL; |
1219 | 0 | } |
1220 | | |
1221 | 0 | unsigned int pr_netaddr_get_port(const pr_netaddr_t *na) { |
1222 | 0 | if (na == NULL) { |
1223 | 0 | errno = EINVAL; |
1224 | 0 | return 0; |
1225 | 0 | } |
1226 | | |
1227 | 0 | switch (pr_netaddr_get_family(na)) { |
1228 | 0 | case AF_INET: |
1229 | 0 | return na->na_addr.v4.sin_port; |
1230 | | |
1231 | 0 | #ifdef PR_USE_IPV6 |
1232 | 0 | case AF_INET6: |
1233 | 0 | if (use_ipv6 == TRUE) { |
1234 | 0 | return na->na_addr.v6.sin6_port; |
1235 | 0 | } |
1236 | 0 | #endif /* PR_USE_IPV6 */ |
1237 | 0 | } |
1238 | | |
1239 | 0 | errno = EPERM; |
1240 | 0 | return 0; |
1241 | 0 | } |
1242 | | |
1243 | 0 | int pr_netaddr_set_port(pr_netaddr_t *na, unsigned int port) { |
1244 | 0 | if (!na) { |
1245 | 0 | errno = EINVAL; |
1246 | 0 | return -1; |
1247 | 0 | } |
1248 | | |
1249 | 0 | switch (pr_netaddr_get_family(na)) { |
1250 | 0 | case AF_INET: |
1251 | 0 | na->na_addr.v4.sin_port = port; |
1252 | 0 | return 0; |
1253 | | |
1254 | 0 | #ifdef PR_USE_IPV6 |
1255 | 0 | case AF_INET6: |
1256 | 0 | if (use_ipv6) { |
1257 | 0 | na->na_addr.v6.sin6_port = port; |
1258 | 0 | return 0; |
1259 | 0 | } |
1260 | 0 | #endif /* PR_USE_IPV6 */ |
1261 | 0 | } |
1262 | | |
1263 | 0 | errno = EPERM; |
1264 | 0 | return -1; |
1265 | 0 | } |
1266 | | |
1267 | 0 | int pr_netaddr_set_port2(pr_netaddr_t *na, unsigned int port) { |
1268 | 0 | return pr_netaddr_set_port(na, htons(port)); |
1269 | 0 | } |
1270 | | |
1271 | 0 | int pr_netaddr_cmp(const pr_netaddr_t *na1, const pr_netaddr_t *na2) { |
1272 | 0 | pool *tmp_pool = NULL; |
1273 | 0 | pr_netaddr_t *a, *b; |
1274 | 0 | int res; |
1275 | |
|
1276 | 0 | if (na1 != NULL && |
1277 | 0 | na2 == NULL) { |
1278 | 0 | return 1; |
1279 | 0 | } |
1280 | | |
1281 | 0 | if (na1 == NULL && |
1282 | 0 | na2 != NULL) { |
1283 | 0 | return -1; |
1284 | 0 | } |
1285 | | |
1286 | 0 | if (na1 == NULL && |
1287 | 0 | na2 == NULL) { |
1288 | 0 | return 0; |
1289 | 0 | } |
1290 | | |
1291 | 0 | if (pr_netaddr_get_family(na1) != pr_netaddr_get_family(na2)) { |
1292 | | |
1293 | | /* Cannot compare addresses from different families, unless one |
1294 | | * of the netaddrs has an AF_INET family, and the other has an |
1295 | | * AF_INET6 family AND is an IPv4-mapped IPv6 address. |
1296 | | */ |
1297 | |
|
1298 | 0 | if (pr_netaddr_is_v4mappedv6(na1) != TRUE && |
1299 | 0 | pr_netaddr_is_v4mappedv6(na2) != TRUE) { |
1300 | 0 | errno = EINVAL; |
1301 | 0 | return -1; |
1302 | 0 | } |
1303 | | |
1304 | 0 | if (pr_netaddr_is_v4mappedv6(na1) == TRUE) { |
1305 | 0 | tmp_pool = make_sub_pool(permanent_pool); |
1306 | |
|
1307 | 0 | pr_trace_msg(trace_channel, 5, "addr '%s' is an IPv4-mapped IPv6 address", |
1308 | 0 | pr_netaddr_get_ipstr((pr_netaddr_t *) na1)); |
1309 | | |
1310 | | /* This case means that na1 is an IPv4-mapped IPv6 address, and |
1311 | | * na2 is an IPv4 address. |
1312 | | */ |
1313 | 0 | a = pr_netaddr_v6tov4(tmp_pool, na1); |
1314 | 0 | b = (pr_netaddr_t *) na2; |
1315 | |
|
1316 | 0 | pr_trace_msg(trace_channel, 6, "comparing IPv4 address '%s' against " |
1317 | 0 | "IPv4-mapped IPv6 address '%s'", pr_netaddr_get_ipstr(b), |
1318 | 0 | pr_netaddr_get_ipstr(a)); |
1319 | |
|
1320 | 0 | } else if (pr_netaddr_is_v4mappedv6(na2) == TRUE) { |
1321 | 0 | tmp_pool = make_sub_pool(permanent_pool); |
1322 | |
|
1323 | 0 | pr_trace_msg(trace_channel, 5, "addr '%s' is an IPv4-mapped IPv6 address", |
1324 | 0 | pr_netaddr_get_ipstr((pr_netaddr_t *) na2)); |
1325 | | |
1326 | | /* This case means that na is an IPv4 address, and na2 is an |
1327 | | * IPv4-mapped IPv6 address. |
1328 | | */ |
1329 | 0 | a = (pr_netaddr_t *) na1; |
1330 | 0 | b = pr_netaddr_v6tov4(tmp_pool, na2); |
1331 | |
|
1332 | 0 | pr_trace_msg(trace_channel, 6, "comparing IPv4 address '%s' against " |
1333 | 0 | "IPv4-mapped IPv6 address '%s'", pr_netaddr_get_ipstr(a), |
1334 | 0 | pr_netaddr_get_ipstr(b)); |
1335 | |
|
1336 | 0 | } else { |
1337 | 0 | a = (pr_netaddr_t *) na1; |
1338 | 0 | b = (pr_netaddr_t *) na2; |
1339 | 0 | } |
1340 | |
|
1341 | 0 | } else { |
1342 | 0 | a = (pr_netaddr_t *) na1; |
1343 | 0 | b = (pr_netaddr_t *) na2; |
1344 | 0 | } |
1345 | | |
1346 | 0 | switch (pr_netaddr_get_family(a)) { |
1347 | 0 | case AF_INET: |
1348 | 0 | res = memcmp(&a->na_addr.v4.sin_addr, &b->na_addr.v4.sin_addr, |
1349 | 0 | sizeof(struct in_addr)); |
1350 | |
|
1351 | 0 | if (res != 0) { |
1352 | 0 | pr_trace_msg(trace_channel, 4, "addr %s does not match addr %s", |
1353 | 0 | pr_netaddr_get_ipstr(a), pr_netaddr_get_ipstr(b)); |
1354 | 0 | } |
1355 | |
|
1356 | 0 | if (tmp_pool) { |
1357 | 0 | destroy_pool(tmp_pool); |
1358 | 0 | tmp_pool = NULL; |
1359 | 0 | } |
1360 | |
|
1361 | 0 | return res; |
1362 | | |
1363 | 0 | #ifdef PR_USE_IPV6 |
1364 | 0 | case AF_INET6: |
1365 | 0 | if (use_ipv6) { |
1366 | 0 | res = memcmp(&a->na_addr.v6.sin6_addr, &b->na_addr.v6.sin6_addr, |
1367 | 0 | sizeof(struct in6_addr)); |
1368 | |
|
1369 | 0 | if (res != 0) { |
1370 | 0 | pr_trace_msg(trace_channel, 4, "addr %s does not match addr %s", |
1371 | 0 | pr_netaddr_get_ipstr(a), pr_netaddr_get_ipstr(b)); |
1372 | 0 | } |
1373 | |
|
1374 | 0 | if (tmp_pool != NULL) { |
1375 | 0 | destroy_pool(tmp_pool); |
1376 | 0 | tmp_pool = NULL; |
1377 | 0 | } |
1378 | |
|
1379 | 0 | return res; |
1380 | 0 | } |
1381 | 0 | #endif /* PR_USE_IPV6 */ |
1382 | 0 | } |
1383 | | |
1384 | 0 | if (tmp_pool != NULL) { |
1385 | 0 | destroy_pool(tmp_pool); |
1386 | 0 | } |
1387 | |
|
1388 | 0 | errno = EPERM; |
1389 | 0 | return -1; |
1390 | 0 | } |
1391 | | |
1392 | | static int addr_ncmp(const unsigned char *aptr, const unsigned char *bptr, |
1393 | 0 | unsigned int masklen) { |
1394 | 0 | unsigned char nbits, nbytes; |
1395 | 0 | int res; |
1396 | | |
1397 | | /* These null checks are unlikely to happen. But be prepared, eh? */ |
1398 | |
|
1399 | 0 | if (aptr != NULL && |
1400 | 0 | bptr == NULL) { |
1401 | 0 | return 1; |
1402 | 0 | } |
1403 | | |
1404 | 0 | if (aptr == NULL && |
1405 | 0 | bptr != NULL) { |
1406 | 0 | return -1; |
1407 | 0 | } |
1408 | | |
1409 | 0 | if (aptr == NULL && |
1410 | 0 | bptr == NULL) { |
1411 | 0 | return 0; |
1412 | 0 | } |
1413 | | |
1414 | 0 | nbytes = masklen / 8; |
1415 | 0 | nbits = masklen % 8; |
1416 | |
|
1417 | 0 | res = memcmp(aptr, bptr, nbytes); |
1418 | 0 | if (res != 0) { |
1419 | 0 | return -1; |
1420 | 0 | } |
1421 | | |
1422 | 0 | if (nbits > 0) { |
1423 | 0 | unsigned char abyte, bbyte, mask; |
1424 | |
|
1425 | 0 | abyte = aptr[nbytes]; |
1426 | 0 | bbyte = bptr[nbytes]; |
1427 | |
|
1428 | 0 | mask = (0xff << (8 - nbits)) & 0xff; |
1429 | |
|
1430 | 0 | if ((abyte & mask) > (bbyte & mask)) { |
1431 | 0 | return 1; |
1432 | 0 | } |
1433 | | |
1434 | 0 | if ((abyte & mask) < (bbyte & mask)) { |
1435 | 0 | return -1; |
1436 | 0 | } |
1437 | 0 | } |
1438 | | |
1439 | 0 | return 0; |
1440 | 0 | } |
1441 | | |
1442 | | int pr_netaddr_ncmp(const pr_netaddr_t *na1, const pr_netaddr_t *na2, |
1443 | 0 | unsigned int bitlen) { |
1444 | 0 | pool *tmp_pool = NULL; |
1445 | 0 | pr_netaddr_t *a, *b; |
1446 | 0 | const unsigned char *in1, *in2; |
1447 | 0 | int res; |
1448 | |
|
1449 | 0 | if (na1 != NULL && |
1450 | 0 | na2 == NULL) { |
1451 | 0 | return 1; |
1452 | 0 | } |
1453 | | |
1454 | 0 | if (na1 == NULL && |
1455 | 0 | na2 != NULL) { |
1456 | 0 | return -1; |
1457 | 0 | } |
1458 | | |
1459 | 0 | if (na1 == NULL && |
1460 | 0 | na2 == NULL) { |
1461 | 0 | return 0; |
1462 | 0 | } |
1463 | | |
1464 | 0 | if (pr_netaddr_get_family(na1) != pr_netaddr_get_family(na2)) { |
1465 | | |
1466 | | /* Cannot compare addresses from different families, unless one |
1467 | | * of the netaddrs has an AF_INET family, and the other has an |
1468 | | * AF_INET6 family AND is an IPv4-mapped IPv6 address. |
1469 | | */ |
1470 | |
|
1471 | 0 | if (pr_netaddr_is_v4mappedv6(na1) != TRUE && |
1472 | 0 | pr_netaddr_is_v4mappedv6(na2) != TRUE) { |
1473 | 0 | errno = EINVAL; |
1474 | 0 | return -1; |
1475 | 0 | } |
1476 | | |
1477 | 0 | if (pr_netaddr_is_v4mappedv6(na1) == TRUE) { |
1478 | 0 | tmp_pool = make_sub_pool(permanent_pool); |
1479 | | |
1480 | | /* This case means that na1 is an IPv4-mapped IPv6 address, and |
1481 | | * na2 is an IPv4 address. |
1482 | | */ |
1483 | 0 | a = pr_netaddr_v6tov4(tmp_pool, na1); |
1484 | 0 | b = (pr_netaddr_t *) na2; |
1485 | |
|
1486 | 0 | pr_trace_msg(trace_channel, 6, "comparing IPv4 address '%s' against " |
1487 | 0 | "IPv4-mapped IPv6 address '%s'", pr_netaddr_get_ipstr(b), |
1488 | 0 | pr_netaddr_get_ipstr(a)); |
1489 | |
|
1490 | 0 | } else if (pr_netaddr_is_v4mappedv6(na2) == TRUE) { |
1491 | 0 | tmp_pool = make_sub_pool(permanent_pool); |
1492 | | |
1493 | | /* This case means that na is an IPv4 address, and na2 is an |
1494 | | * IPv4-mapped IPv6 address. |
1495 | | */ |
1496 | 0 | a = (pr_netaddr_t *) na1; |
1497 | 0 | b = pr_netaddr_v6tov4(tmp_pool, na2); |
1498 | |
|
1499 | 0 | pr_trace_msg(trace_channel, 6, "comparing IPv4 address '%s' against " |
1500 | 0 | "IPv4-mapped IPv6 address '%s'", pr_netaddr_get_ipstr(a), |
1501 | 0 | pr_netaddr_get_ipstr(b)); |
1502 | |
|
1503 | 0 | } else { |
1504 | 0 | a = (pr_netaddr_t *) na1; |
1505 | 0 | b = (pr_netaddr_t *) na2; |
1506 | 0 | } |
1507 | |
|
1508 | 0 | } else { |
1509 | 0 | a = (pr_netaddr_t *) na1; |
1510 | 0 | b = (pr_netaddr_t *) na2; |
1511 | 0 | } |
1512 | | |
1513 | 0 | switch (pr_netaddr_get_family(a)) { |
1514 | 0 | case AF_INET: { |
1515 | | /* Make sure that the given number of bits is not more than supported |
1516 | | * for IPv4 addresses (32). |
1517 | | */ |
1518 | 0 | if (bitlen > 32) { |
1519 | 0 | errno = EINVAL; |
1520 | 0 | return -1; |
1521 | 0 | } |
1522 | | |
1523 | 0 | break; |
1524 | 0 | } |
1525 | | |
1526 | 0 | #ifdef PR_USE_IPV6 |
1527 | 0 | case AF_INET6: { |
1528 | 0 | if (use_ipv6) { |
1529 | | /* Make sure that the given number of bits is not more than supported |
1530 | | * for IPv6 addresses (128). |
1531 | | */ |
1532 | 0 | if (bitlen > 128) { |
1533 | 0 | errno = EINVAL; |
1534 | 0 | return -1; |
1535 | 0 | } |
1536 | | |
1537 | 0 | break; |
1538 | 0 | } |
1539 | 0 | } |
1540 | 0 | #endif /* PR_USE_IPV6 */ |
1541 | | |
1542 | 0 | default: |
1543 | 0 | errno = EPERM; |
1544 | 0 | return -1; |
1545 | 0 | } |
1546 | | |
1547 | | /* Retrieve pointers to the contained in_addrs. */ |
1548 | 0 | in1 = (const unsigned char *) pr_netaddr_get_inaddr(a); |
1549 | 0 | in2 = (const unsigned char *) pr_netaddr_get_inaddr(b); |
1550 | |
|
1551 | 0 | res = addr_ncmp(in1, in2, bitlen); |
1552 | |
|
1553 | 0 | if (tmp_pool) { |
1554 | 0 | destroy_pool(tmp_pool); |
1555 | 0 | } |
1556 | |
|
1557 | 0 | return res; |
1558 | 0 | } |
1559 | | |
1560 | 0 | int pr_netaddr_fnmatch(const pr_netaddr_t *na, const char *pattern, int flags) { |
1561 | | |
1562 | | /* Note: I'm still not sure why proftpd bundles an fnmatch(3) |
1563 | | * implementation rather than using the system library's implementation. |
1564 | | * Needs looking into. |
1565 | | * |
1566 | | * The FNM_CASEFOLD flag is a GNU extension; perhaps the bundled |
1567 | | * implementation was added to make that flag available on other platforms. |
1568 | | */ |
1569 | 0 | int match_flags = PR_FNM_NOESCAPE|PR_FNM_CASEFOLD; |
1570 | |
|
1571 | 0 | if (na == NULL || |
1572 | 0 | pattern == NULL) { |
1573 | 0 | errno = EINVAL; |
1574 | 0 | return -1; |
1575 | 0 | } |
1576 | | |
1577 | 0 | if (flags & PR_NETADDR_MATCH_DNS) { |
1578 | 0 | const char *dnsstr; |
1579 | |
|
1580 | 0 | dnsstr = pr_netaddr_get_dnsstr(na); |
1581 | 0 | if (pr_fnmatch(pattern, dnsstr, match_flags) == 0) { |
1582 | 0 | pr_trace_msg(trace_channel, 6, "DNS name '%s' matches pattern '%s'", |
1583 | 0 | dnsstr, pattern); |
1584 | 0 | return TRUE; |
1585 | 0 | } |
1586 | 0 | } |
1587 | | |
1588 | 0 | if (flags & PR_NETADDR_MATCH_IP) { |
1589 | 0 | const char *ipstr; |
1590 | |
|
1591 | 0 | ipstr = pr_netaddr_get_ipstr(na); |
1592 | 0 | if (pr_fnmatch(pattern, ipstr, match_flags) == 0) { |
1593 | 0 | pr_trace_msg(trace_channel, 6, "IP address '%s' matches pattern '%s'", |
1594 | 0 | ipstr, pattern); |
1595 | 0 | return TRUE; |
1596 | 0 | } |
1597 | | |
1598 | | /* If the address is an IPv4-mapped IPv6 address, get the IPv4 address |
1599 | | * and try to match that against the configured glob pattern. |
1600 | | */ |
1601 | 0 | if (pr_netaddr_is_v4mappedv6(na) == TRUE) { |
1602 | 0 | pool *tmp_pool; |
1603 | 0 | pr_netaddr_t *a; |
1604 | |
|
1605 | 0 | pr_trace_msg(trace_channel, 5, "addr '%s' is an IPv4-mapped IPv6 address", |
1606 | 0 | ipstr); |
1607 | |
|
1608 | 0 | tmp_pool = make_sub_pool(permanent_pool); |
1609 | 0 | a = pr_netaddr_v6tov4(tmp_pool, na); |
1610 | |
|
1611 | 0 | ipstr = pr_netaddr_get_ipstr(a); |
1612 | |
|
1613 | 0 | if (pr_fnmatch(pattern, ipstr, match_flags) == 0) { |
1614 | 0 | pr_trace_msg(trace_channel, 6, "IP address '%s' matches pattern '%s'", |
1615 | 0 | ipstr, pattern); |
1616 | |
|
1617 | 0 | destroy_pool(tmp_pool); |
1618 | 0 | return TRUE; |
1619 | 0 | } |
1620 | | |
1621 | 0 | destroy_pool(tmp_pool); |
1622 | 0 | } |
1623 | 0 | } |
1624 | | |
1625 | 0 | pr_trace_msg(trace_channel, 4, "addr %s does not match pattern '%s'", |
1626 | 0 | pr_netaddr_get_ipstr(na), pattern); |
1627 | 0 | return FALSE; |
1628 | 0 | } |
1629 | | |
1630 | 0 | const char *pr_netaddr_get_ipstr(const pr_netaddr_t *na) { |
1631 | 0 | #if defined(PR_USE_IPV6) |
1632 | 0 | char buf[INET6_ADDRSTRLEN]; |
1633 | | #else |
1634 | | char buf[INET_ADDRSTRLEN]; |
1635 | | #endif /* PR_USE_IPV6 */ |
1636 | 0 | int res = 0, xerrno; |
1637 | 0 | pr_netaddr_t *addr; |
1638 | |
|
1639 | 0 | if (na == NULL) { |
1640 | 0 | errno = EINVAL; |
1641 | 0 | return NULL; |
1642 | 0 | } |
1643 | | |
1644 | | /* If this pr_netaddr_t has already been resolved to an IP string, return the |
1645 | | * cached string. |
1646 | | */ |
1647 | 0 | if (na->na_have_ipstr) { |
1648 | 0 | return na->na_ipstr; |
1649 | 0 | } |
1650 | | |
1651 | 0 | memset(buf, '\0', sizeof(buf)); |
1652 | 0 | res = pr_getnameinfo(pr_netaddr_get_sockaddr(na), |
1653 | 0 | pr_netaddr_get_sockaddr_len(na), buf, sizeof(buf), NULL, 0, NI_NUMERICHOST); |
1654 | 0 | xerrno = errno; |
1655 | |
|
1656 | 0 | if (res != 0) { |
1657 | 0 | if (res != EAI_SYSTEM) { |
1658 | 0 | pr_log_pri(PR_LOG_WARNING, "getnameinfo error: %s", pr_gai_strerror(res)); |
1659 | 0 | errno = EIO; |
1660 | |
|
1661 | 0 | } else { |
1662 | 0 | pr_log_pri(PR_LOG_WARNING, "getnameinfo system error: [%d] %s", |
1663 | 0 | xerrno, strerror(xerrno)); |
1664 | 0 | errno = xerrno; |
1665 | 0 | } |
1666 | |
|
1667 | 0 | return NULL; |
1668 | 0 | } |
1669 | | |
1670 | 0 | #ifdef PR_USE_IPV6 |
1671 | 0 | if (use_ipv6 && |
1672 | 0 | pr_netaddr_get_family(na) == AF_INET6) { |
1673 | | /* The getnameinfo(3) implementation might append the zone ID to an IPv6 |
1674 | | * name; we need to trim it off. |
1675 | | */ |
1676 | 0 | char *ptr; |
1677 | |
|
1678 | 0 | ptr = strrchr(buf, '%'); |
1679 | 0 | if (ptr != NULL) { |
1680 | 0 | *ptr = '\0'; |
1681 | 0 | } |
1682 | 0 | } |
1683 | 0 | #endif /* PR_USE_IPV6 */ |
1684 | | |
1685 | | /* Copy the string into the pr_netaddr_t cache as well, so we only |
1686 | | * have to do this once for this pr_netaddr_t. But to do this, we need |
1687 | | * let the compiler know that the pr_netaddr_t is not really const at this |
1688 | | * point. |
1689 | | */ |
1690 | 0 | addr = (pr_netaddr_t *) na; |
1691 | 0 | memset(addr->na_ipstr, '\0', sizeof(addr->na_ipstr)); |
1692 | 0 | sstrncpy(addr->na_ipstr, buf, sizeof(addr->na_ipstr)); |
1693 | 0 | addr->na_have_ipstr = TRUE; |
1694 | |
|
1695 | 0 | return na->na_ipstr; |
1696 | 0 | } |
1697 | | |
1698 | | #if defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME2) |
1699 | | static int netaddr_get_dnsstr_getaddrinfo(const pr_netaddr_t *na, |
1700 | | const char *name) { |
1701 | | struct addrinfo hints, *info = NULL; |
1702 | | int family, flags = 0, res = 0, ok = FALSE; |
1703 | | void *inaddr = pr_netaddr_get_inaddr(na); |
1704 | | |
1705 | | family = pr_netaddr_get_family(na); |
1706 | | if (pr_netaddr_is_v4mappedv6(na) == TRUE) { |
1707 | | family = AF_INET; |
1708 | | inaddr = get_v4inaddr(na); |
1709 | | } |
1710 | | |
1711 | | #ifdef AI_CANONNAME |
1712 | | flags |= AI_CANONNAME; |
1713 | | #endif |
1714 | | |
1715 | | #ifdef AI_ALL |
1716 | | flags |= AI_ALL; |
1717 | | #endif |
1718 | | |
1719 | | #ifdef AI_V4MAPPED |
1720 | | flags |= AI_V4MAPPED; |
1721 | | #endif |
1722 | | |
1723 | | memset(&hints, 0, sizeof(hints)); |
1724 | | |
1725 | | hints.ai_family = family; |
1726 | | hints.ai_socktype = SOCK_STREAM; |
1727 | | hints.ai_protocol = IPPROTO_TCP; |
1728 | | hints.ai_flags = flags; |
1729 | | |
1730 | | res = pr_getaddrinfo(name, NULL, &hints, &info); |
1731 | | if (res != 0) { |
1732 | | int xerrno = errno; |
1733 | | |
1734 | | if (res != EAI_SYSTEM) { |
1735 | | pr_trace_msg(trace_channel, 1, "%s getaddrinfo '%s' error: %s", |
1736 | | hints.ai_family == AF_INET ? "IPv4" : "IPv6", name, |
1737 | | pr_gai_strerror(res)); |
1738 | | |
1739 | | } else { |
1740 | | pr_trace_msg(trace_channel, 1, |
1741 | | "%s getaddrinfo '%s' system error: [%d] %s", |
1742 | | hints.ai_family == AF_INET ? "IPv4" : "IPv6", name, xerrno, |
1743 | | strerror(xerrno)); |
1744 | | } |
1745 | | |
1746 | | errno = xerrno; |
1747 | | return -1; |
1748 | | } |
1749 | | |
1750 | | if (info != NULL) { |
1751 | | #ifdef PR_USE_IPV6 |
1752 | | char buf[INET6_ADDRSTRLEN]; |
1753 | | #else |
1754 | | char buf[INET_ADDRSTRLEN]; |
1755 | | #endif /* PR_USE_IPV6 */ |
1756 | | struct addrinfo *ai; |
1757 | | int xerrno; |
1758 | | |
1759 | | memset(buf, '\0', sizeof(buf)); |
1760 | | res = pr_getnameinfo(info->ai_addr, info->ai_addrlen, buf, sizeof(buf), |
1761 | | NULL, 0, NI_NAMEREQD); |
1762 | | xerrno = errno; |
1763 | | |
1764 | | if (res != 0) { |
1765 | | if (res != EAI_SYSTEM) { |
1766 | | pr_trace_msg(trace_channel, 1, "%s getnameinfo error: %s", |
1767 | | hints.ai_family == AF_INET ? "IPv4" : "IPv6", pr_gai_strerror(res)); |
1768 | | |
1769 | | } else { |
1770 | | pr_trace_msg(trace_channel, 1, |
1771 | | "%s getnameinfo system error: [%d] %s", |
1772 | | hints.ai_family == AF_INET ? "IPv4" : "IPv6", xerrno, |
1773 | | strerror(xerrno)); |
1774 | | } |
1775 | | |
1776 | | errno = xerrno; |
1777 | | return -1; |
1778 | | } |
1779 | | |
1780 | | netaddr_dnscache_set(pr_netaddr_get_ipstr(na), buf); |
1781 | | ok = TRUE; |
1782 | | |
1783 | | pr_trace_msg(trace_channel, 10, |
1784 | | "checking addresses associated with host '%s'", buf); |
1785 | | |
1786 | | for (ai = info->ai_next; ai; ai = ai->ai_next) { |
1787 | | #ifdef PR_USE_IPV6 |
1788 | | char alias[INET6_ADDRSTRLEN]; |
1789 | | #else |
1790 | | char alias[INET_ADDRSTRLEN]; |
1791 | | #endif /* PR_USE_IPV6 */ |
1792 | | |
1793 | | switch (ai->ai_family) { |
1794 | | case AF_INET: |
1795 | | if (family == AF_INET) { |
1796 | | if (memcmp(ai->ai_addr, inaddr, ai->ai_addrlen) == 0) { |
1797 | | memset(alias, '\0', sizeof(alias)); |
1798 | | res = pr_getnameinfo(ai->ai_addr, ai->ai_addrlen, alias, |
1799 | | sizeof(alias), NULL, 0, NI_NAMEREQD); |
1800 | | if (res == 0) { |
1801 | | pr_trace_msg(trace_channel, 10, |
1802 | | "host '%s' has alias '%s'", buf, alias); |
1803 | | netaddr_ipcache_set(alias, na); |
1804 | | netaddr_dnscache_set(pr_netaddr_get_ipstr(na), alias); |
1805 | | } |
1806 | | } |
1807 | | } |
1808 | | break; |
1809 | | |
1810 | | #ifdef PR_USE_IPV6 |
1811 | | case AF_INET6: |
1812 | | if (use_ipv6 && family == AF_INET6) { |
1813 | | if (memcmp(ai->ai_addr, inaddr, ai->ai_addrlen) == 0) { |
1814 | | memset(alias, '\0', sizeof(alias)); |
1815 | | res = pr_getnameinfo(ai->ai_addr, ai->ai_addrlen, alias, |
1816 | | sizeof(alias), NULL, 0, NI_NAMEREQD); |
1817 | | if (res == 0) { |
1818 | | pr_trace_msg(trace_channel, 10, |
1819 | | "host '%s' has alias '%s'", buf, alias); |
1820 | | netaddr_ipcache_set(alias, na); |
1821 | | netaddr_dnscache_set(pr_netaddr_get_ipstr(na), alias); |
1822 | | } |
1823 | | } |
1824 | | } |
1825 | | break; |
1826 | | #endif /* PR_USE_IPV6 */ |
1827 | | } |
1828 | | } |
1829 | | |
1830 | | pr_freeaddrinfo(info); |
1831 | | } |
1832 | | |
1833 | | return (ok ? 0 : -1); |
1834 | | } |
1835 | | #endif /* HAVE_GETADDRINFO and not HAVE_GETHOSTBYNAME2 */ |
1836 | | |
1837 | | #ifdef HAVE_GETHOSTBYNAME2 |
1838 | | static int netaddr_get_dnsstr_gethostbyname(const pr_netaddr_t *na, |
1839 | 0 | const char *name) { |
1840 | 0 | struct hostent *hent = NULL; |
1841 | 0 | int family, ok = FALSE; |
1842 | 0 | void *inaddr; |
1843 | |
|
1844 | 0 | family = pr_netaddr_get_family(na); |
1845 | 0 | if (family < 0) { |
1846 | 0 | return -1; |
1847 | 0 | } |
1848 | | |
1849 | 0 | inaddr = pr_netaddr_get_inaddr(na); |
1850 | |
|
1851 | 0 | if (pr_netaddr_is_v4mappedv6(na) == TRUE) { |
1852 | 0 | family = AF_INET; |
1853 | 0 | inaddr = get_v4inaddr(na); |
1854 | 0 | } |
1855 | |
|
1856 | 0 | hent = gethostbyname2(name, family); |
1857 | |
|
1858 | 0 | if (hent != NULL) { |
1859 | 0 | char **checkaddr; |
1860 | |
|
1861 | 0 | if (hent->h_name != NULL) { |
1862 | 0 | netaddr_dnscache_set(pr_netaddr_get_ipstr(na), hent->h_name); |
1863 | 0 | } |
1864 | |
|
1865 | 0 | pr_trace_msg(trace_channel, 10, |
1866 | 0 | "checking addresses associated with host '%s'", |
1867 | 0 | hent->h_name ? hent->h_name : "(null)"); |
1868 | |
|
1869 | 0 | switch (hent->h_addrtype) { |
1870 | 0 | case AF_INET: |
1871 | 0 | if (family == AF_INET) { |
1872 | 0 | for (checkaddr = hent->h_addr_list; *checkaddr; ++checkaddr) { |
1873 | 0 | if (memcmp(*checkaddr, inaddr, hent->h_length) == 0) { |
1874 | 0 | char **alias; |
1875 | |
|
1876 | 0 | for (alias = hent->h_aliases; *alias; ++alias) { |
1877 | 0 | if (hent->h_name) { |
1878 | 0 | pr_trace_msg(trace_channel, 10, |
1879 | 0 | "host '%s' has alias '%s'", hent->h_name, *alias); |
1880 | 0 | netaddr_ipcache_set(*alias, na); |
1881 | 0 | netaddr_dnscache_set(pr_netaddr_get_ipstr(na), *alias); |
1882 | 0 | } |
1883 | 0 | } |
1884 | |
|
1885 | 0 | ok = TRUE; |
1886 | 0 | break; |
1887 | 0 | } |
1888 | 0 | } |
1889 | 0 | } |
1890 | 0 | break; |
1891 | | |
1892 | 0 | # if defined(PR_USE_IPV6) |
1893 | 0 | case AF_INET6: |
1894 | 0 | if (use_ipv6 && family == AF_INET6) { |
1895 | 0 | for (checkaddr = hent->h_addr_list; *checkaddr; ++checkaddr) { |
1896 | 0 | if (memcmp(*checkaddr, inaddr, hent->h_length) == 0) { |
1897 | 0 | char **alias; |
1898 | |
|
1899 | 0 | for (alias = hent->h_aliases; *alias; ++alias) { |
1900 | 0 | if (hent->h_name) { |
1901 | 0 | pr_trace_msg(trace_channel, 10, |
1902 | 0 | "host '%s' has alias '%s'", hent->h_name, *alias); |
1903 | 0 | netaddr_ipcache_set(*alias, na); |
1904 | 0 | netaddr_dnscache_set(pr_netaddr_get_ipstr(na), *alias); |
1905 | 0 | } |
1906 | 0 | } |
1907 | |
|
1908 | 0 | ok = TRUE; |
1909 | 0 | break; |
1910 | 0 | } |
1911 | 0 | } |
1912 | 0 | } |
1913 | 0 | break; |
1914 | 0 | # endif /* PR_USE_IPV6 */ |
1915 | 0 | } |
1916 | |
|
1917 | 0 | } else { |
1918 | 0 | pr_log_debug(DEBUG1, "notice: unable to resolve '%s' as %s address: %s", |
1919 | 0 | name, family != AF_INET ? "IPv6" : "IPv4", hstrerror(h_errno)); |
1920 | 0 | } |
1921 | | |
1922 | 0 | return (ok ? 0 : -1); |
1923 | 0 | } |
1924 | | #endif /* HAVE_GETHOSTBYNAME2 */ |
1925 | | |
1926 | | /* This differs from pr_netaddr_get_ipstr() in that pr_netaddr_get_ipstr() |
1927 | | * returns a string of the numeric form of the given network address, whereas |
1928 | | * this function returns a string of the DNS name (if present). |
1929 | | */ |
1930 | 0 | const char *pr_netaddr_get_dnsstr(const pr_netaddr_t *na) { |
1931 | 0 | char dns_buf[1024], *name = NULL; |
1932 | 0 | pr_netaddr_t *addr = NULL, *cache = NULL; |
1933 | |
|
1934 | 0 | if (na == NULL) { |
1935 | 0 | errno = EINVAL; |
1936 | 0 | return NULL; |
1937 | 0 | } |
1938 | | |
1939 | 0 | cache = netaddr_ipcache_get(NULL, pr_netaddr_get_ipstr(na)); |
1940 | 0 | if (cache && |
1941 | 0 | cache->na_have_dnsstr) { |
1942 | 0 | addr = (pr_netaddr_t *) na; |
1943 | 0 | memset(addr->na_dnsstr, '\0', sizeof(addr->na_dnsstr)); |
1944 | 0 | sstrncpy(addr->na_dnsstr, cache->na_dnsstr, sizeof(addr->na_dnsstr)); |
1945 | 0 | addr->na_have_dnsstr = TRUE; |
1946 | |
|
1947 | 0 | return na->na_dnsstr; |
1948 | 0 | } |
1949 | | |
1950 | | /* If this pr_netaddr_t has already been resolved to an DNS string, return the |
1951 | | * cached string. |
1952 | | */ |
1953 | 0 | if (na->na_have_dnsstr) { |
1954 | 0 | return na->na_dnsstr; |
1955 | 0 | } |
1956 | | |
1957 | 0 | if (reverse_dns) { |
1958 | 0 | int res = 0; |
1959 | |
|
1960 | 0 | pr_trace_msg(trace_channel, 3, |
1961 | 0 | "verifying DNS name for IP address %s via reverse DNS lookup", |
1962 | 0 | pr_netaddr_get_ipstr(na)); |
1963 | |
|
1964 | 0 | memset(dns_buf, '\0', sizeof(dns_buf)); |
1965 | 0 | res = pr_getnameinfo(pr_netaddr_get_sockaddr(na), |
1966 | 0 | pr_netaddr_get_sockaddr_len(na), dns_buf, sizeof(dns_buf), NULL, 0, |
1967 | 0 | NI_NAMEREQD); |
1968 | 0 | dns_buf[sizeof(dns_buf)-1] = '\0'; |
1969 | |
|
1970 | 0 | if (res == 0) { |
1971 | | /* Some older glibc's getaddrinfo(3) does not appear to handle IPv6 |
1972 | | * addresses properly; we thus prefer gethostbyname2(3) on systems |
1973 | | * which have it, for such older systems. |
1974 | | */ |
1975 | 0 | #ifdef HAVE_GETHOSTBYNAME2 |
1976 | 0 | res = netaddr_get_dnsstr_gethostbyname(na, dns_buf); |
1977 | | #else |
1978 | | res = netaddr_get_dnsstr_getaddrinfo(na, dns_buf); |
1979 | | #endif /* HAVE_GETHOSTBYNAME2 */ |
1980 | 0 | if (res == 0) { |
1981 | 0 | name = dns_buf; |
1982 | 0 | pr_trace_msg(trace_channel, 8, |
1983 | 0 | "using DNS name '%s' for IP address '%s'", name, |
1984 | 0 | pr_netaddr_get_ipstr(na)); |
1985 | |
|
1986 | 0 | } else { |
1987 | 0 | name = NULL; |
1988 | 0 | pr_trace_msg(trace_channel, 8, |
1989 | 0 | "unable to verify any DNS names for IP address '%s'", |
1990 | 0 | pr_netaddr_get_ipstr(na)); |
1991 | 0 | } |
1992 | 0 | } |
1993 | |
|
1994 | 0 | } else { |
1995 | 0 | pr_log_debug(DEBUG10, |
1996 | 0 | "UseReverseDNS off, returning IP address instead of DNS name"); |
1997 | 0 | } |
1998 | |
|
1999 | 0 | if (name) { |
2000 | 0 | name = pr_netaddr_validate_dns_str(name); |
2001 | |
|
2002 | 0 | } else { |
2003 | 0 | name = (char *) pr_netaddr_get_ipstr(na); |
2004 | 0 | } |
2005 | | |
2006 | | /* Copy the string into the pr_netaddr_t cache as well, so we only |
2007 | | * have to do this once for this pr_netaddr_t. But to do this, we need |
2008 | | * let the compiler know that the pr_netaddr_t is not really const at this |
2009 | | * point. |
2010 | | */ |
2011 | 0 | addr = (pr_netaddr_t *) na; |
2012 | 0 | memset(addr->na_dnsstr, '\0', sizeof(addr->na_dnsstr)); |
2013 | 0 | sstrncpy(addr->na_dnsstr, name, sizeof(addr->na_dnsstr)); |
2014 | 0 | addr->na_have_dnsstr = TRUE; |
2015 | | |
2016 | | /* Update the netaddr object in the cache with the resolved DNS names. */ |
2017 | 0 | netaddr_ipcache_set(name, na); |
2018 | 0 | netaddr_ipcache_set(pr_netaddr_get_ipstr(na), na); |
2019 | |
|
2020 | 0 | return na->na_dnsstr; |
2021 | 0 | } |
2022 | | |
2023 | 0 | array_header *pr_netaddr_get_dnsstr_list(pool *p, const pr_netaddr_t *na) { |
2024 | 0 | array_header *res; |
2025 | |
|
2026 | 0 | if (p == NULL || |
2027 | 0 | na == NULL) { |
2028 | 0 | errno = EINVAL; |
2029 | 0 | return NULL; |
2030 | 0 | } |
2031 | | |
2032 | 0 | if (!reverse_dns) { |
2033 | | /* If UseReverseDNS is off, then we won't have any names that we trust. |
2034 | | * So return an empty list. |
2035 | | */ |
2036 | 0 | return make_array(p, 0, sizeof(char *)); |
2037 | 0 | } |
2038 | | |
2039 | 0 | res = netaddr_dnscache_get(p, pr_netaddr_get_ipstr(na)); |
2040 | 0 | if (res == NULL) { |
2041 | 0 | res = make_array(p, 0, sizeof(char *)); |
2042 | 0 | } |
2043 | |
|
2044 | 0 | return res; |
2045 | 0 | } |
2046 | | |
2047 | | /* Return the hostname (wrapper for gethostname(2), except returns FQDN). */ |
2048 | 0 | const char *pr_netaddr_get_localaddr_str(pool *p) { |
2049 | 0 | char buf[256]; |
2050 | 0 | int res, xerrno; |
2051 | |
|
2052 | 0 | if (p == NULL) { |
2053 | 0 | errno = EINVAL; |
2054 | 0 | return NULL; |
2055 | 0 | } |
2056 | | |
2057 | 0 | if (have_localaddr_str) { |
2058 | 0 | return pr_netaddr_validate_dns_str(pstrdup(p, localaddr_str)); |
2059 | 0 | } |
2060 | | |
2061 | 0 | memset(buf, '\0', sizeof(buf)); |
2062 | 0 | res = gethostname(buf, sizeof(buf)-1); |
2063 | 0 | xerrno = errno; |
2064 | |
|
2065 | 0 | if (res >= 0) { |
2066 | 0 | struct hostent *host; |
2067 | |
|
2068 | 0 | buf[sizeof(buf)-1] = '\0'; |
2069 | | |
2070 | | /* Note: this may need to be gethostbyname2() on systems that provide |
2071 | | * that function, for it is possible that the configured hostname for |
2072 | | * a machine only resolves to an IPv6 address. |
2073 | | */ |
2074 | 0 | #ifdef HAVE_GETHOSTBYNAME2 |
2075 | 0 | host = gethostbyname2(buf, AF_INET); |
2076 | 0 | if (host == NULL && |
2077 | 0 | h_errno == HOST_NOT_FOUND) { |
2078 | 0 | # ifdef AF_INET6 |
2079 | 0 | host = gethostbyname2(buf, AF_INET6); |
2080 | 0 | # endif /* AF_INET6 */ |
2081 | 0 | } |
2082 | | #else |
2083 | | host = gethostbyname(buf); |
2084 | | #endif |
2085 | 0 | if (host != NULL) { |
2086 | 0 | return pr_netaddr_validate_dns_str(pstrdup(p, host->h_name)); |
2087 | 0 | } |
2088 | | |
2089 | 0 | pr_trace_msg(trace_channel, 14, |
2090 | 0 | "gethostbyname() failed for '%s': %s", buf, hstrerror(h_errno)); |
2091 | 0 | return pr_netaddr_validate_dns_str(pstrdup(p, buf)); |
2092 | 0 | } |
2093 | | |
2094 | 0 | pr_trace_msg(trace_channel, 1, "gethostname(2) error: %s", strerror(xerrno)); |
2095 | 0 | errno = xerrno; |
2096 | 0 | return NULL; |
2097 | 0 | } |
2098 | | |
2099 | 0 | int pr_netaddr_set_localaddr_str(const char *addr_str) { |
2100 | 0 | if (addr_str == NULL) { |
2101 | 0 | errno = EINVAL; |
2102 | 0 | return -1; |
2103 | 0 | } |
2104 | | |
2105 | 0 | memset(localaddr_str, '\0', sizeof(localaddr_str)); |
2106 | 0 | sstrncpy(localaddr_str, addr_str, sizeof(localaddr_str)); |
2107 | 0 | have_localaddr_str = TRUE; |
2108 | 0 | return 0; |
2109 | 0 | } |
2110 | | |
2111 | 0 | int pr_netaddr_is_loopback(const pr_netaddr_t *na) { |
2112 | 0 | if (na == NULL) { |
2113 | 0 | errno = EINVAL; |
2114 | 0 | return -1; |
2115 | 0 | } |
2116 | | |
2117 | 0 | switch (pr_netaddr_get_family(na)) { |
2118 | 0 | case AF_INET: |
2119 | 0 | return IN_IS_ADDR_LOOPBACK( |
2120 | 0 | (struct in_addr *) pr_netaddr_get_inaddr(na)); |
2121 | | |
2122 | 0 | #ifdef PR_USE_IPV6 |
2123 | 0 | case AF_INET6: |
2124 | 0 | if (pr_netaddr_is_v4mappedv6(na) == TRUE) { |
2125 | 0 | pool *tmp_pool; |
2126 | 0 | pr_netaddr_t *v4na; |
2127 | 0 | int res; |
2128 | |
|
2129 | 0 | tmp_pool = make_sub_pool(permanent_pool); |
2130 | 0 | v4na = pr_netaddr_v6tov4(tmp_pool, na); |
2131 | |
|
2132 | 0 | res = pr_netaddr_is_loopback(v4na); |
2133 | 0 | destroy_pool(tmp_pool); |
2134 | |
|
2135 | 0 | return res; |
2136 | 0 | } |
2137 | | |
2138 | | /* XXX *sigh* Different platforms implement the IN6_IS_ADDR macros |
2139 | | * differently. For example, on Linux, those macros expect to operate |
2140 | | * on s6_addr32, while on Solaris, the macros operate on struct in6_addr. |
2141 | | * Certain Drafts define the macros to work on struct in6_addr *, as |
2142 | | * Solaris does, so Linux may have it wrong. Tentative research on |
2143 | | * Google shows some BSD netinet6/in6.h headers that define these |
2144 | | * macros in terms of struct in6_addr *, so I'll go with that for now. |
2145 | | * Joy. =P |
2146 | | */ |
2147 | | # ifndef LINUX |
2148 | | return IN6_IS_ADDR_LOOPBACK( |
2149 | | (struct in6_addr *) pr_netaddr_get_inaddr(na)); |
2150 | | # else |
2151 | 0 | return IN6_IS_ADDR_LOOPBACK( |
2152 | 0 | ((struct in6_addr *) pr_netaddr_get_inaddr(na))->s6_addr32); |
2153 | 0 | # endif |
2154 | 0 | #endif /* PR_USE_IPV6 */ |
2155 | 0 | } |
2156 | | |
2157 | 0 | return FALSE; |
2158 | 0 | } |
2159 | | |
2160 | | /* RFC 1918 addresses: |
2161 | | * |
2162 | | * 10.0.0.0 - 10.255.255.255 (10.0.0.0/8, 24-bit block) |
2163 | | * 172.16.0.0 - 172.31.255.255 (172.16.0.0/12, 20-bit block) |
2164 | | * 192.168.0.0 - 192.168.255.255 (192.168.0.0/16, 16-bit block) |
2165 | | * |
2166 | | */ |
2167 | | |
2168 | 0 | static int is_10_xxx_addr(uint32_t addrno) { |
2169 | 0 | uint32_t rfc1918_addrno; |
2170 | |
|
2171 | 0 | rfc1918_addrno = htonl(0x0a000000); |
2172 | 0 | return addr_ncmp((const unsigned char *) &addrno, |
2173 | 0 | (const unsigned char *) &rfc1918_addrno, 8); |
2174 | 0 | } |
2175 | | |
2176 | 0 | static int is_172_16_xx_addr(uint32_t addrno) { |
2177 | 0 | uint32_t rfc1918_addrno; |
2178 | |
|
2179 | 0 | rfc1918_addrno = htonl(0xac100000); |
2180 | 0 | return addr_ncmp((const unsigned char *) &addrno, |
2181 | 0 | (const unsigned char *) &rfc1918_addrno, 12); |
2182 | 0 | } |
2183 | | |
2184 | 0 | static int is_192_168_xx_addr(uint32_t addrno) { |
2185 | 0 | uint32_t rfc1918_addrno; |
2186 | |
|
2187 | 0 | rfc1918_addrno = htonl(0xc0a80000); |
2188 | 0 | return addr_ncmp((const unsigned char *) &addrno, |
2189 | 0 | (const unsigned char *) &rfc1918_addrno, 16); |
2190 | 0 | } |
2191 | | |
2192 | 0 | int pr_netaddr_is_rfc1918(const pr_netaddr_t *na) { |
2193 | 0 | if (na == NULL) { |
2194 | 0 | errno = EINVAL; |
2195 | 0 | return -1; |
2196 | 0 | } |
2197 | | |
2198 | 0 | switch (pr_netaddr_get_family(na)) { |
2199 | 0 | case AF_INET: { |
2200 | 0 | uint32_t addrno; |
2201 | |
|
2202 | 0 | addrno = pr_netaddr_get_addrno(na); |
2203 | 0 | if (is_192_168_xx_addr(addrno) == 0 || |
2204 | 0 | is_172_16_xx_addr(addrno) == 0 || |
2205 | 0 | is_10_xxx_addr(addrno) == 0) { |
2206 | 0 | return TRUE; |
2207 | 0 | } |
2208 | 0 | break; |
2209 | 0 | } |
2210 | | |
2211 | 0 | #ifdef PR_USE_IPV6 |
2212 | 0 | case AF_INET6: |
2213 | 0 | if (pr_netaddr_is_v4mappedv6(na) == TRUE) { |
2214 | 0 | pool *tmp_pool; |
2215 | 0 | pr_netaddr_t *v4na; |
2216 | 0 | int res; |
2217 | |
|
2218 | 0 | tmp_pool = make_sub_pool(permanent_pool); |
2219 | 0 | v4na = pr_netaddr_v6tov4(tmp_pool, na); |
2220 | |
|
2221 | 0 | res = pr_netaddr_is_rfc1918(v4na); |
2222 | 0 | destroy_pool(tmp_pool); |
2223 | |
|
2224 | 0 | return res; |
2225 | 0 | } |
2226 | | |
2227 | | /* By definition, an IPv6 address is not an RFC1918-defined address. */ |
2228 | 0 | return FALSE; |
2229 | 0 | #endif /* PR_USE_IPV6 */ |
2230 | 0 | } |
2231 | | |
2232 | 0 | errno = EINVAL; |
2233 | 0 | return FALSE; |
2234 | 0 | } |
2235 | | |
2236 | | /* A slightly naughty function that should go away. It relies too much on |
2237 | | * knowledge of the internal structures of struct in_addr, struct in6_addr. |
2238 | | */ |
2239 | 0 | uint32_t pr_netaddr_get_addrno(const pr_netaddr_t *na) { |
2240 | 0 | if (na == NULL) { |
2241 | 0 | errno = EINVAL; |
2242 | 0 | return 0; |
2243 | 0 | } |
2244 | | |
2245 | 0 | switch (pr_netaddr_get_family(na)) { |
2246 | 0 | case AF_INET: |
2247 | 0 | return (uint32_t) na->na_addr.v4.sin_addr.s_addr; |
2248 | | |
2249 | 0 | #ifdef PR_USE_IPV6 |
2250 | 0 | case AF_INET6: { |
2251 | | |
2252 | | /* Linux defines s6_addr32 in its netinet/in.h header. |
2253 | | * FreeBSD defines s6_addr32 in KAME's netinet6/in6.h header. |
2254 | | * Solaris defines s6_addr32 in its netinet/in.h header, but only |
2255 | | * for kernel builds. |
2256 | | */ |
2257 | | #if 0 |
2258 | | int *addrs = ((struct sockaddr_in6 *) pr_netaddr_get_inaddr(na))->s6_addr32; |
2259 | | return addrs[0]; |
2260 | | #else |
2261 | 0 | errno = ENOENT; |
2262 | 0 | return 0; |
2263 | 0 | #endif |
2264 | 0 | } |
2265 | 0 | #endif /* PR_USE_IPV6 */ |
2266 | 0 | } |
2267 | | |
2268 | 0 | errno = EPERM; |
2269 | 0 | return 0; |
2270 | 0 | } |
2271 | | |
2272 | 0 | int pr_netaddr_is_v4(const char *name) { |
2273 | 0 | int res; |
2274 | 0 | struct sockaddr_in v4; |
2275 | |
|
2276 | 0 | if (name == NULL) { |
2277 | 0 | errno = EINVAL; |
2278 | 0 | return -1; |
2279 | 0 | } |
2280 | | |
2281 | 0 | memset(&v4, 0, sizeof(v4)); |
2282 | 0 | v4.sin_family = AF_INET; |
2283 | |
|
2284 | | # ifdef SIN_LEN |
2285 | | v4.sin_len = sizeof(struct sockaddr_in); |
2286 | | # endif /* SIN_LEN */ |
2287 | |
|
2288 | 0 | res = pr_inet_pton(AF_INET, name, &v4.sin_addr); |
2289 | 0 | if (res > 0) { |
2290 | 0 | return TRUE; |
2291 | 0 | } |
2292 | | |
2293 | 0 | return FALSE; |
2294 | 0 | } |
2295 | | |
2296 | 0 | int pr_netaddr_is_v6(const char *name) { |
2297 | 0 | if (name == NULL) { |
2298 | 0 | errno = EINVAL; |
2299 | 0 | return -1; |
2300 | 0 | } |
2301 | | |
2302 | 0 | #ifdef PR_USE_IPV6 |
2303 | 0 | if (use_ipv6) { |
2304 | 0 | int res; |
2305 | 0 | struct sockaddr_in6 v6; |
2306 | |
|
2307 | 0 | memset(&v6, 0, sizeof(v6)); |
2308 | 0 | v6.sin6_family = AF_INET6; |
2309 | |
|
2310 | | # ifdef SIN6_LEN |
2311 | | v6.sin6_len = sizeof(struct sockaddr_in6); |
2312 | | # endif /* SIN6_LEN */ |
2313 | |
|
2314 | 0 | res = pr_inet_pton(AF_INET6, name, &v6.sin6_addr); |
2315 | 0 | if (res > 0) { |
2316 | 0 | return TRUE; |
2317 | 0 | } |
2318 | 0 | } |
2319 | | |
2320 | 0 | return FALSE; |
2321 | | #else |
2322 | | return FALSE; |
2323 | | #endif /* !PR_USE_IPV6 */ |
2324 | 0 | } |
2325 | | |
2326 | 0 | int pr_netaddr_is_v4mappedv6(const pr_netaddr_t *na) { |
2327 | 0 | if (!na) { |
2328 | 0 | errno = EINVAL; |
2329 | 0 | return -1; |
2330 | 0 | } |
2331 | | |
2332 | 0 | switch (pr_netaddr_get_family(na)) { |
2333 | 0 | case AF_INET: |
2334 | | |
2335 | | /* This function tests only IPv6 addresses, not IPv4 addresses. */ |
2336 | 0 | errno = EINVAL; |
2337 | 0 | return -1; |
2338 | | |
2339 | 0 | #ifdef PR_USE_IPV6 |
2340 | 0 | case AF_INET6: { |
2341 | 0 | int res; |
2342 | |
|
2343 | 0 | if (!use_ipv6) { |
2344 | 0 | errno = EINVAL; |
2345 | 0 | return -1; |
2346 | 0 | } |
2347 | | |
2348 | | # ifndef LINUX |
2349 | | res = IN6_IS_ADDR_V4MAPPED( |
2350 | | (struct in6_addr *) pr_netaddr_get_inaddr(na)); |
2351 | | # else |
2352 | 0 | res = IN6_IS_ADDR_V4MAPPED( |
2353 | 0 | ((struct in6_addr *) pr_netaddr_get_inaddr(na))->s6_addr32); |
2354 | 0 | # endif |
2355 | |
|
2356 | 0 | if (res != TRUE) { |
2357 | 0 | errno = EINVAL; |
2358 | 0 | } |
2359 | |
|
2360 | 0 | return res; |
2361 | 0 | } |
2362 | 0 | #endif /* PR_USE_IPV6 */ |
2363 | 0 | } |
2364 | | |
2365 | 0 | errno = EPERM; |
2366 | 0 | return -1; |
2367 | 0 | } |
2368 | | |
2369 | 0 | pr_netaddr_t *pr_netaddr_v6tov4(pool *p, const pr_netaddr_t *na) { |
2370 | 0 | pr_netaddr_t *res; |
2371 | |
|
2372 | 0 | if (p == NULL || |
2373 | 0 | na == NULL) { |
2374 | 0 | errno = EINVAL; |
2375 | 0 | return NULL; |
2376 | 0 | } |
2377 | | |
2378 | 0 | if (pr_netaddr_is_v4mappedv6(na) != TRUE) { |
2379 | 0 | errno = EPERM; |
2380 | 0 | return NULL; |
2381 | 0 | } |
2382 | | |
2383 | 0 | res = pr_netaddr_alloc(p); |
2384 | 0 | pr_netaddr_set_family(res, AF_INET); |
2385 | 0 | pr_netaddr_set_port(res, pr_netaddr_get_port(na)); |
2386 | 0 | memcpy(&res->na_addr.v4.sin_addr, get_v4inaddr(na), sizeof(struct in_addr)); |
2387 | |
|
2388 | 0 | return res; |
2389 | 0 | } |
2390 | | |
2391 | 0 | pr_netaddr_t *pr_netaddr_v4tov6(pool *p, const pr_netaddr_t *na) { |
2392 | 0 | pr_netaddr_t *res; |
2393 | |
|
2394 | 0 | if (p == NULL || |
2395 | 0 | na == NULL) { |
2396 | 0 | errno = EINVAL; |
2397 | 0 | return NULL; |
2398 | 0 | } |
2399 | | |
2400 | 0 | if (pr_netaddr_get_family(na) != AF_INET) { |
2401 | 0 | errno = EPERM; |
2402 | 0 | return NULL; |
2403 | 0 | } |
2404 | | |
2405 | 0 | #ifdef PR_USE_IPV6 |
2406 | 0 | res = (pr_netaddr_t *) pr_netaddr_get_addr(p, |
2407 | 0 | pstrcat(p, "::ffff:", pr_netaddr_get_ipstr(na), NULL), NULL); |
2408 | 0 | if (res != NULL) { |
2409 | 0 | pr_netaddr_set_port(res, pr_netaddr_get_port(na)); |
2410 | 0 | } |
2411 | |
|
2412 | | #else |
2413 | | errno = EPERM; |
2414 | | res = NULL; |
2415 | | #endif /* PR_USE_IPV6 */ |
2416 | |
|
2417 | 0 | return res; |
2418 | 0 | } |
2419 | | |
2420 | 0 | const pr_netaddr_t *pr_netaddr_get_sess_local_addr(void) { |
2421 | 0 | if (have_sess_local_addr) { |
2422 | 0 | return &sess_local_addr; |
2423 | 0 | } |
2424 | | |
2425 | 0 | errno = ENOENT; |
2426 | 0 | return NULL; |
2427 | 0 | } |
2428 | | |
2429 | 0 | const pr_netaddr_t *pr_netaddr_get_sess_remote_addr(void) { |
2430 | 0 | if (have_sess_remote_addr) { |
2431 | 0 | return &sess_remote_addr; |
2432 | 0 | } |
2433 | | |
2434 | 0 | errno = ENOENT; |
2435 | 0 | return NULL; |
2436 | 0 | } |
2437 | | |
2438 | 0 | const char *pr_netaddr_get_sess_remote_name(void) { |
2439 | 0 | if (have_sess_remote_addr) { |
2440 | 0 | return sess_remote_name; |
2441 | 0 | } |
2442 | | |
2443 | 0 | errno = ENOENT; |
2444 | 0 | return NULL; |
2445 | 0 | } |
2446 | | |
2447 | 0 | void pr_netaddr_set_sess_addrs(void) { |
2448 | 0 | memset(&sess_local_addr, 0, sizeof(sess_local_addr)); |
2449 | 0 | pr_netaddr_set_family(&sess_local_addr, |
2450 | 0 | pr_netaddr_get_family(session.c->local_addr)); |
2451 | 0 | pr_netaddr_set_sockaddr(&sess_local_addr, |
2452 | 0 | pr_netaddr_get_sockaddr(session.c->local_addr)); |
2453 | 0 | have_sess_local_addr = TRUE; |
2454 | |
|
2455 | 0 | memset(&sess_remote_addr, 0, sizeof(sess_remote_addr)); |
2456 | 0 | pr_netaddr_set_family(&sess_remote_addr, |
2457 | 0 | pr_netaddr_get_family(session.c->remote_addr)); |
2458 | 0 | pr_netaddr_set_sockaddr(&sess_remote_addr, |
2459 | 0 | pr_netaddr_get_sockaddr(session.c->remote_addr)); |
2460 | |
|
2461 | 0 | memset(sess_remote_name, '\0', sizeof(sess_remote_name)); |
2462 | 0 | sstrncpy(sess_remote_name, session.c->remote_name, sizeof(sess_remote_name)); |
2463 | 0 | have_sess_remote_addr = TRUE; |
2464 | 0 | } |
2465 | | |
2466 | 0 | unsigned char pr_netaddr_use_ipv6(void) { |
2467 | 0 | if (use_ipv6 == TRUE) { |
2468 | 0 | return TRUE; |
2469 | 0 | } |
2470 | | |
2471 | 0 | return FALSE; |
2472 | 0 | } |
2473 | | |
2474 | 0 | void pr_netaddr_disable_ipv6(void) { |
2475 | 0 | #if defined(PR_USE_IPV6) |
2476 | 0 | use_ipv6 = FALSE; |
2477 | 0 | #endif /* PR_USE_IPV6 */ |
2478 | 0 | } |
2479 | | |
2480 | 0 | void pr_netaddr_enable_ipv6(void) { |
2481 | 0 | #if defined(PR_USE_IPV6) |
2482 | 0 | use_ipv6 = TRUE; |
2483 | 0 | #endif /* PR_USE_IPV6 */ |
2484 | 0 | } |
2485 | | |
2486 | 0 | void pr_netaddr_clear_cache(void) { |
2487 | 0 | if (netaddr_iptab != NULL) { |
2488 | 0 | pr_trace_msg(trace_channel, 5, "emptying netaddr IP cache"); |
2489 | 0 | (void) pr_table_empty(netaddr_iptab); |
2490 | 0 | (void) pr_table_free(netaddr_iptab); |
2491 | | |
2492 | | /* Allocate a fresh table. */ |
2493 | 0 | netaddr_iptab = pr_table_alloc(netaddr_pool, 0); |
2494 | 0 | } |
2495 | |
|
2496 | 0 | if (netaddr_dnstab != NULL) { |
2497 | 0 | pr_trace_msg(trace_channel, 5, "emptying netaddr DNS cache"); |
2498 | 0 | (void) pr_table_empty(netaddr_dnstab); |
2499 | 0 | (void) pr_table_free(netaddr_dnstab); |
2500 | | |
2501 | | /* Allocate a fresh table. */ |
2502 | 0 | netaddr_dnstab = pr_table_alloc(netaddr_pool, 0); |
2503 | 0 | } |
2504 | 0 | } |
2505 | | |
2506 | 0 | void pr_netaddr_clear_dnscache(const char *ip_str) { |
2507 | 0 | if (netaddr_dnstab != NULL) { |
2508 | 0 | (void) pr_table_remove(netaddr_dnstab, ip_str, NULL); |
2509 | 0 | } |
2510 | 0 | } |
2511 | | |
2512 | 0 | void pr_netaddr_clear_ipcache(const char *name) { |
2513 | 0 | if (netaddr_iptab != NULL) { |
2514 | 0 | (void) pr_table_remove(netaddr_iptab, name, NULL); |
2515 | 0 | } |
2516 | 0 | } |
2517 | | |
2518 | 0 | void init_netaddr(void) { |
2519 | 0 | if (netaddr_pool != NULL) { |
2520 | 0 | pr_netaddr_clear_cache(); |
2521 | 0 | destroy_pool(netaddr_pool); |
2522 | 0 | netaddr_pool = NULL; |
2523 | 0 | } |
2524 | |
|
2525 | 0 | netaddr_pool = make_sub_pool(permanent_pool); |
2526 | 0 | pr_pool_tag(netaddr_pool, "Netaddr API"); |
2527 | |
|
2528 | 0 | netaddr_iptab = pr_table_alloc(netaddr_pool, 0); |
2529 | 0 | netaddr_dnstab = pr_table_alloc(netaddr_pool, 0); |
2530 | 0 | } |