• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

proftpd / proftpd / 20113771060

10 Dec 2025 09:30PM UTC coverage: 93.027% (+0.4%) from 92.636%
20113771060

push

github

51324 of 55171 relevant lines covered (93.03%)

233.26 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.16
/src/netaddr.c
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
  ((((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
static array_header *netaddr_dnscache_get(pool *p, const char *ip_str) {
68
  array_header *res = NULL;
24✔
69

24✔
70
  if (netaddr_dnstab != NULL) {
71
    const void *v;
24✔
72

24✔
73
    v = pr_table_get(netaddr_dnstab, ip_str, NULL);
74
    if (v != NULL) {
24✔
75
      res = (array_header *) v;
24✔
76

15✔
77
      pr_trace_msg(trace_channel, 4,
78
        "using %d DNS %s from netaddr DNS cache for IP address '%s'",
15✔
79
        res->nelts, res->nelts != 1 ? "names" : "name", ip_str);
80

15✔
81
      if (p) {
82
        /* If the caller provided a pool, return a copy of the array. */
15✔
83
        return copy_array_str(p, res);
84
      }
1✔
85

86
      return res;
87
    }
88
  }
89

90
  pr_trace_msg(trace_channel, 12,
91
    "no DNS names found in netaddr DNS cache for IP address '%s'", ip_str);
9✔
92
  errno = ENOENT;
93
  return NULL;
9✔
94
}
9✔
95

96
static void netaddr_dnscache_set(const char *ip_str, const char *dns_name) {
97
  if (netaddr_dnstab != NULL) {
22✔
98
    void *v = NULL;
22✔
99
    array_header *res = NULL;
22✔
100
    int add_list = FALSE;
22✔
101

22✔
102
    res = netaddr_dnscache_get(NULL, ip_str);
103
    if (res == NULL) {
22✔
104
      /* No existing entries for this IP address yet. */
22✔
105
      res = make_array(netaddr_pool, 1, sizeof(char *));
106
      add_list = TRUE;
8✔
107

8✔
108
    } else {
109
      register unsigned int i;
110
      char **names;
14✔
111

14✔
112
      /* Check for duplicates. */
113
      names = res->elts;
114
      for (i = 0; i < res->nelts; i++) {
14✔
115
        if (names[i] != NULL) {
35✔
116
          if (strcmp(names[i], dns_name) == 0) {
21✔
117
            pr_trace_msg(trace_channel, 5,
21✔
118
              "DNS name '%s' for IP address '%s' already stashed in the "
×
119
              "netaddr DNS cache", dns_name, ip_str);
120
            return;
121
          }
×
122
        }
123
      }
124
    }
125

126
    *((char **) push_array(res)) = pstrdup(netaddr_pool, dns_name);
127
    v = res;
22✔
128

22✔
129
    if (add_list == TRUE) {
130
      if (pr_table_add(netaddr_dnstab, pstrdup(netaddr_pool, ip_str), v,
22✔
131
          sizeof(array_header *)) < 0) {
8✔
132
        pr_trace_msg(trace_channel, 3,
133
          "error adding DNS name '%s' for IP address '%s' to the netaddr "
×
134
          "DNS cache: %s", dns_name, ip_str, strerror(errno));
135

×
136
      } else {
137
        pr_trace_msg(trace_channel, 5,
138
          "stashed DNS name '%s' for IP address '%s' in the netaddr DNS cache",
8✔
139
          dns_name, ip_str);
140
      }
141

142
    } else {
143
      pr_trace_msg(trace_channel, 5,
144
        "stashed DNS name '%s' for IP address '%s' in the netaddr DNS cache",
14✔
145
        dns_name, ip_str);
146
    }
147
  }
148
}
149

150
static pr_netaddr_t *netaddr_ipcache_get(pool *p, const char *name) {
151
  pr_netaddr_t *res = NULL;
173✔
152

173✔
153
  if (netaddr_iptab != NULL) {
154
    const void *v;
173✔
155

167✔
156
    v = pr_table_get(netaddr_iptab, name, NULL);
157
    if (v != NULL) {
167✔
158
      res = (pr_netaddr_t *) v;
167✔
159
      pr_trace_msg(trace_channel, 4,
78✔
160
        "using IP address '%s' from netaddr IP cache for name '%s'",
78✔
161
        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
      if (p != NULL) {
167
        pr_netaddr_t *dup_res = NULL;
78✔
168

40✔
169
        dup_res = pr_netaddr_dup(p, res);
170
        if (dup_res == NULL) {
40✔
171
          pr_log_debug(DEBUG0, "error duplicating address for name '%s' "
40✔
172
            "from cache: %s", name, strerror(errno));
×
173
        }
×
174

175
        return dup_res;
176
      }
40✔
177

178
      return res;
179
    }
180
  }
181

182
  pr_trace_msg(trace_channel, 2,
183
    "no IP address found in netaddr IP cache for name '%s'", name);
95✔
184
  errno = ENOENT;
185
  return NULL;
95✔
186
}
95✔
187

188
static int netaddr_ipcache_set(const char *name, const pr_netaddr_t *na) {
189
  if (netaddr_iptab != NULL) {
169✔
190
    int count = 0;
169✔
191
    void *v = NULL;
163✔
192

163✔
193
    /* We store an internal copy of the netaddr_t in the cache. */
194
    v = pr_netaddr_dup(netaddr_pool, na);
195
    if (v == NULL) {
163✔
196
      return -1;
163✔
197
    }
198

199
    count = pr_table_exists(netaddr_iptab, name);
200
    if (count <= 0) {
159✔
201
      if (pr_table_add(netaddr_iptab, pstrdup(netaddr_pool, name), v,
159✔
202
          sizeof(pr_netaddr_t *)) < 0) {
108✔
203
        pr_trace_msg(trace_channel, 3,
204
          "error adding IP address '%s' for name '%s' to the netaddr "
×
205
          "IP cache: %s", pr_netaddr_get_ipstr(na), name,
206
          strerror(errno));
207

×
208
      } else {
209
        pr_trace_msg(trace_channel, 5,
210
          "stashed IP address '%s' for name '%s' in the netaddr IP cache",
108✔
211
          pr_netaddr_get_ipstr(v), name);
212
      }
213

214
    } else {
215
      if (pr_table_set(netaddr_iptab, pstrdup(netaddr_pool, name), v,
216
          sizeof(pr_netaddr_t *)) < 0) {
51✔
217
        pr_trace_msg(trace_channel, 3,
218
          "error setting IP address '%s' for name '%s' in the netaddr "
×
219
          "IP cache: %s", pr_netaddr_get_ipstr(na), name, strerror(errno));
220
      }
×
221
    }
222
  }
223

224
  return 0;
225
}
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
static void *get_v4inaddr(const pr_netaddr_t *na) {
410

9✔
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
  return (((char *) pr_netaddr_get_inaddr(na)) + 12);
422
}
18✔
423

424
/* Validate anything returned from the 'outside', since it's untrusted
425
 * information.
426
 */
427
char *pr_netaddr_validate_dns_str(char *buf) {
428
  char *p;
14✔
429

14✔
430
  if (buf == NULL) {
431
    errno = EINVAL;
14✔
432
    return NULL;
1✔
433
  }
1✔
434

435
  /* Validate anything returned from a DNS. */
436
  for (p = buf; p && *p; p++) {
437

124✔
438
    /* Per RFC requirements, these are all that are valid from a DNS. */
439
    if (!PR_ISALNUM(*p) &&
440
        *p != '.' &&
111✔
441
        *p != '-'
442
#ifdef PR_USE_IPV6
443
        && *p != ':'
444
#endif /* PR_USE_IPV6 */
445
        ) {
446

447
      /* We set it to _ because we know that's an invalid, yet safe, option
448
       * for a DNS entry.
449
       */
450
      *p = '_';
451
    }
2✔
452
  }
453

454
  return buf;
455
}
456

457
int pr_netaddr_set_reverse_dns(int enable) {
458
  int old_enable = reverse_dns;
20✔
459
  reverse_dns = enable;
20✔
460
  return old_enable;
20✔
461
}
20✔
462

463
pr_netaddr_t *pr_netaddr_alloc(pool *p) {
464
  if (p == NULL) {
306✔
465
    errno = EINVAL;
306✔
466
    return NULL;
1✔
467
  }
1✔
468

469
  return pcalloc(p, sizeof(pr_netaddr_t));
470
}
305✔
471

472
void pr_netaddr_clear(pr_netaddr_t *na) {
473
  if (na == NULL) {
82✔
474
    return;
82✔
475
  }
476

477
  memset(na, 0, sizeof(pr_netaddr_t));
478
}
81✔
479

480
pr_netaddr_t *pr_netaddr_dup(pool *p, const pr_netaddr_t *na) {
481
  pr_netaddr_t *dup_na;
209✔
482

209✔
483
  if (p == NULL ||
484
      na == NULL) {
209✔
485
    errno = EINVAL;
209✔
486
    return NULL;
3✔
487
  }
3✔
488

489
  dup_na = pr_netaddr_alloc(p);
490

206✔
491
  if (pr_netaddr_set_family(dup_na, pr_netaddr_get_family(na)) < 0) {
492
    return NULL;
206✔
493
  }
494

495
  pr_netaddr_set_sockaddr(dup_na, pr_netaddr_get_sockaddr(na));
496

202✔
497
  if (na->na_have_ipstr) {
498
    sstrncpy(dup_na->na_ipstr, na->na_ipstr, sizeof(dup_na->na_ipstr));
202✔
499
    dup_na->na_have_ipstr = 1;
201✔
500
  }
201✔
501

502
  if (na->na_have_dnsstr) {
503
    sstrncpy(dup_na->na_dnsstr, na->na_dnsstr, sizeof(dup_na->na_dnsstr));
202✔
504
    dup_na->na_have_dnsstr = 1;
30✔
505
  }
30✔
506

507
  return dup_na;
508
}
509

510
static pr_netaddr_t *get_addr_by_ip(pool *p, const char *name,
511
    array_header **addrs, unsigned int flags) {
98✔
512
  struct sockaddr_in v4;
513
  pr_netaddr_t *na = NULL;
98✔
514
  int res;
98✔
515

98✔
516
#ifdef PR_USE_IPV6
517
  if (use_ipv6 == TRUE) {
518
    struct sockaddr_in6 v6;
98✔
519
    memset(&v6, 0, sizeof(v6));
98✔
520
    v6.sin6_family = AF_INET6;
98✔
521

98✔
522
# ifdef SIN6_LEN
523
    v6.sin6_len = sizeof(struct sockaddr_in6);
524
# endif /* SIN6_LEN */
525

526
    res = pr_inet_pton(AF_INET6, name, &v6.sin6_addr);
527
    if (res > 0) {
98✔
528
      na = (pr_netaddr_t *) pcalloc(p, sizeof(pr_netaddr_t));
98✔
529
      pr_netaddr_set_family(na, AF_INET6);
30✔
530
      pr_netaddr_set_sockaddr(na, (struct sockaddr *) &v6);
30✔
531
      if (addrs != NULL) {
30✔
532
        *addrs = NULL;
30✔
533
      }
1✔
534

535
      pr_trace_msg(trace_channel, 7, "'%s' resolved to IPv6 address %s", name,
536
        pr_netaddr_get_ipstr(na));
30✔
537

538
      if (!(flags & PR_NETADDR_GET_ADDR_FL_EXCL_CACHE)) {
539
        if (netaddr_ipcache_set(name, na) < 0) {
30✔
540
          pr_trace_msg(trace_channel, 2, "error setting '%s' in cache: %s",
30✔
541
            name, strerror(errno));
×
542
        }
×
543

544
        if (netaddr_ipcache_set(pr_netaddr_get_ipstr(na), na) < 0) {
545
          pr_trace_msg(trace_channel, 2, "error setting '%s' in cache: %s",
30✔
546
            pr_netaddr_get_ipstr(na), strerror(errno));
×
547
        }
×
548
      }
549

550
      return na;
551
    }
30✔
552
  }
553
#endif /* PR_USE_IPV6 */
554

555
  memset(&v4, 0, sizeof(v4));
556
  v4.sin_family = AF_INET;
68✔
557

68✔
558
# ifdef SIN_LEN
559
  v4.sin_len = sizeof(struct sockaddr_in);
560
# endif /* SIN_LEN */
561

562
  res = pr_inet_pton(AF_INET, name, &v4.sin_addr);
563
  if (res > 0) {
68✔
564
    na = (pr_netaddr_t *) pcalloc(p, sizeof(pr_netaddr_t));
68✔
565
    pr_netaddr_set_family(na, AF_INET);
47✔
566
    pr_netaddr_set_sockaddr(na, (struct sockaddr *) &v4);
47✔
567
    if (addrs != NULL) {
47✔
568
      *addrs = NULL;
47✔
569
    }
1✔
570

571
    pr_trace_msg(trace_channel, 7, "'%s' resolved to IPv4 address %s", name,
572
      pr_netaddr_get_ipstr(na));
47✔
573

574
    if (!(flags & PR_NETADDR_GET_ADDR_FL_EXCL_DNS)) {
575
      if (netaddr_ipcache_set(name, na) < 0) {
47✔
576
        pr_trace_msg(trace_channel, 2, "error setting '%s' in cache: %s", name,
47✔
577
          strerror(errno));
×
578
      }
×
579

580
      /* Avoid duplicates. */
581
      if (strcmp(name, pr_netaddr_get_ipstr(na)) != 0) {
582
        if (netaddr_ipcache_set(pr_netaddr_get_ipstr(na), na) < 0) {
47✔
583
          pr_trace_msg(trace_channel, 2, "error setting '%s' in cache: %s",
×
584
            pr_netaddr_get_ipstr(na), strerror(errno));
×
585
        }
×
586
      }
587
    }
588

589
    return na;
590
  }
47✔
591

592
  return NULL;
593
}
594

595
static pr_netaddr_t *get_addr_by_name(pool *p, const char *name,
596
    array_header **addrs, unsigned int flags) {
20✔
597
  pr_netaddr_t *na = NULL;
598
  int res, xerrno;
20✔
599
  struct addrinfo hints, *info = NULL;
20✔
600

20✔
601
  memset(&hints, 0, sizeof(hints));
602
  hints.ai_family = AF_INET;
20✔
603
  hints.ai_socktype = SOCK_STREAM;
20✔
604
  hints.ai_protocol = IPPROTO_TCP;
20✔
605
  info = NULL;
20✔
606

20✔
607
  xerrno = errno;
608
  pr_trace_msg(trace_channel, 7,
20✔
609
    "attempting to resolve '%s' to IPv4 address via DNS", name);
20✔
610
  errno = xerrno;
611
  res = pr_getaddrinfo(name, NULL, &hints, &info);
20✔
612
  if (res != 0) {
20✔
613
    xerrno = errno;
20✔
614

8✔
615
    if (res != EAI_SYSTEM) {
616
#ifdef PR_USE_IPV6
8✔
617
      if (use_ipv6 == TRUE) {
618
        pr_trace_msg(trace_channel, 7,
8✔
619
          "unable to resolve '%s' to an IPv4 address: %s", name,
8✔
620
          pr_gai_strerror(res));
621

622
        memset(&hints, 0, sizeof(hints));
623
        hints.ai_family = AF_INET6;
8✔
624
        hints.ai_socktype = SOCK_STREAM;
8✔
625
        hints.ai_protocol = IPPROTO_TCP;
8✔
626
        info = NULL;
8✔
627

8✔
628
        pr_trace_msg(trace_channel, 7,
629
          "attempting to resolve '%s' to IPv6 address via DNS", name);
8✔
630
        errno = xerrno;
631
        res = pr_getaddrinfo(name, NULL, &hints, &info);
8✔
632
        xerrno = errno;
8✔
633

8✔
634
        if (res != 0) {
635
          if (res != EAI_SYSTEM) {
8✔
636
            pr_trace_msg(trace_channel, 5,
8✔
637
              "unable to resolve '%s' to an IPv6 address: %s", name,
8✔
638
              pr_gai_strerror(res));
639

640
            if (res == EAI_NODATA ||
641
                res == EAI_NONAME) {
8✔
642
              xerrno = ENOENT;
643
# if defined(EAFNOSUPPORT)
644
            } else if (res == EAI_FAMILY) {
3✔
645
              xerrno = EAFNOSUPPORT;
×
646
# endif /* EAFNOSUPPORT */
647
            }
648

649
          } else {
650
            pr_trace_msg(trace_channel, 1,
×
651
              "IPv6 getaddrinfo '%s' system error: [%d] %s", name,
652
              xerrno, strerror(xerrno));
653
          }
654
        }
655

656
      } else {
657
        const char *errstr;
×
658

659
        errstr = pr_gai_strerror(res);
×
660
        pr_trace_msg(trace_channel, 1, "IPv4 getaddrinfo '%s' error: %s",
×
661
          name, errstr);
662

663
        if (res == EAI_NODATA ||
×
664
            res == EAI_NONAME) {
665
          xerrno = ENOENT;
666
# if defined(EAFNOSUPPORT)
×
667
        } else if (res == EAI_FAMILY) {
668
          xerrno = EAFNOSUPPORT;
669
# endif /* EAFNOSUPPORT */
670
        } 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
          if (strcmp(errstr, "Address family for hostname not supported") == 0) {
×
676
            xerrno = EAFNOSUPPORT;
677
          }
678
        }
679
      }
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
    } else {
694
      pr_trace_msg(trace_channel, 1,
695
        "IPv4 getaddrinfo '%s' system error: [%d] %s", name,
696
        xerrno, strerror(xerrno));
697
    }
8✔
698

8✔
699
    if (res != 0) {
8✔
700
      errno = xerrno;
701
      return NULL;
702
    }
703
  }
12✔
704

12✔
705
  if (info != NULL) {
706
    na = (pr_netaddr_t *) pcalloc(p, sizeof(pr_netaddr_t));
707

12✔
708
    /* Copy the first returned addr into na, as the return value. */
12✔
709
    pr_netaddr_set_family(na, info->ai_family);
710
    pr_netaddr_set_sockaddr(na, info->ai_addr);
24✔
711

12✔
712
    pr_trace_msg(trace_channel, 7, "resolved '%s' to %s address %s", name,
713
      info->ai_family == AF_INET ? "IPv4" : "IPv6",
714
      pr_netaddr_get_ipstr(na));
12✔
715

12✔
716
    if (!(flags & PR_NETADDR_GET_ADDR_FL_EXCL_DNS)) {
×
717
      if (netaddr_ipcache_set(name, na) < 0) {
718
        pr_trace_msg(trace_channel, 2, "error setting '%s' in cache: %s", name,
719
          strerror(errno));
720
      }
12✔
721

×
722
      if (netaddr_ipcache_set(pr_netaddr_get_ipstr(na), na) < 0) {
723
        pr_trace_msg(trace_channel, 2, "error setting '%s' in cache: %s",
724
          pr_netaddr_get_ipstr(na), strerror(errno));
725
      }
726
    }
12✔
727

3✔
728
    if (addrs != NULL) {
729
      struct addrinfo *next_info = NULL;
730

3✔
731
      /* Copy any other addrs into the list. */
2✔
732
      if (*addrs == NULL) {
733
        *addrs = make_array(p, 0, sizeof(pr_netaddr_t *));
734
      }
3✔
735

14✔
736
      next_info = info->ai_next;
11✔
737
      while (next_info != NULL) {
738
        pr_netaddr_t **elt;
11✔
739

11✔
740
        pr_signals_handle();
741
        elt = push_array(*addrs);
11✔
742

11✔
743
        *elt = pcalloc(p, sizeof(pr_netaddr_t));
11✔
744
        pr_netaddr_set_family(*elt, next_info->ai_family);
745
        pr_netaddr_set_sockaddr(*elt, next_info->ai_addr);
22✔
746

11✔
747
        pr_trace_msg(trace_channel, 7, "resolved '%s' to %s address %s", name,
748
          next_info->ai_family == AF_INET ? "IPv4" : "IPv6",
749
          pr_netaddr_get_ipstr(*elt));
11✔
750

751
        next_info = next_info->ai_next;
752
      }
753
    }
12✔
754

755
    pr_freeaddrinfo(info);
756
  }
757

12✔
758
#ifdef PR_USE_IPV6
759
  if (use_ipv6 == TRUE &&
760
      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
     */
3✔
771

3✔
772
    memset(&hints, 0, sizeof(hints));
3✔
773
    hints.ai_family = AF_INET6;
3✔
774
    hints.ai_socktype = SOCK_STREAM;
3✔
775
    hints.ai_protocol = IPPROTO_TCP;
776
    info = NULL;
3✔
777

778
    pr_trace_msg(trace_channel, 7,
3✔
779
      "attempting to resolve '%s' to IPv6 address via DNS", name);
3✔
780
    res = pr_getaddrinfo(name, NULL, &hints, &info);
781
    xerrno = errno;
3✔
782

×
783
    if (res != 0) {
×
784
      if (res != EAI_SYSTEM) {
785
        pr_trace_msg(trace_channel, 1, "IPv6 getaddrinfo '%s' error: %s",
786
          name, pr_gai_strerror(res));
787

×
788
      } else {
789
        pr_trace_msg(trace_channel, 1,
790
          "IPv6 getaddrinfo '%s' system error: [%d] %s", name,
791
          xerrno, strerror(xerrno));
792
      }
793

794
    } 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.
3✔
798
       */
3✔
799
      if (info != NULL) {
800
        struct addrinfo *next_info = NULL;
801

3✔
802
        /* Copy any other addrs into the list. */
×
803
        if (*addrs == NULL) {
804
          *addrs = make_array(p, 0, sizeof(pr_netaddr_t *));
805
        }
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.
3✔
811
         */
12✔
812
        next_info = info;
9✔
813
        while (next_info != NULL) {
814
          pr_netaddr_t **elt;
9✔
815

9✔
816
          pr_signals_handle();
817
          elt = push_array(*addrs);
9✔
818

9✔
819
          *elt = pcalloc(p, sizeof(pr_netaddr_t));
9✔
820
          pr_netaddr_set_family(*elt, next_info->ai_family);
821
          pr_netaddr_set_sockaddr(*elt, next_info->ai_addr);
18✔
822

9✔
823
          pr_trace_msg(trace_channel, 7, "resolved '%s' to %s address %s", name,
824
            next_info->ai_family == AF_INET ? "IPv4" : "IPv6",
825
            pr_netaddr_get_ipstr(*elt));
9✔
826

827
          next_info = next_info->ai_next;
828
        }
3✔
829

830
        pr_freeaddrinfo(info);
831
      }
832
    }
833
  }
834
#endif /* PR_USE_IPV6 */
835

836
  return na;
837
}
3✔
838

839
static pr_netaddr_t *get_addr_by_device(pool *p, const char *name,
840
    array_header **addrs, unsigned int flags) {
3✔
841
#ifdef HAVE_GETIFADDRS
3✔
842
  struct ifaddrs *ifaddr = NULL;
3✔
843
  pr_netaddr_t *na = NULL;
844
  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
   */
3✔
849

3✔
850
  res = getifaddrs(&ifaddr);
×
851
  if (res < 0) {
852
    xerrno = errno;
×
853

854
    pr_trace_msg(trace_channel, 1,
855
      "error retrieving interfaces via getifaddrs(3): %s", strerror(xerrno));
856

3✔
857
  } else {
3✔
858
    struct ifaddrs *ifa;
859
    int found_device = FALSE;
15✔
860

13✔
861
    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
862
      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).
13✔
866
       */
×
867
      if (ifa->ifa_addr == NULL) {
868
        continue;
869
      }
870

19✔
871
      /* We're only looking for addresses, not stats. */
872
      if (ifa->ifa_addr->sa_family != AF_INET
13✔
873
#ifdef PR_USE_IPV6
874
          && ifa->ifa_addr->sa_family != AF_INET6
875
#endif /* PR_USE_IPV6 */
6✔
876
         ) {
877
        continue;
878
      }
7✔
879

1✔
880
      if (strcmp(ifa->ifa_name, name) == 0) {
1✔
881
        if (found_device == FALSE) {
882
          na = (pr_netaddr_t *) pcalloc(p, sizeof(pr_netaddr_t));
1✔
883

1✔
884
          pr_netaddr_set_family(na, ifa->ifa_addr->sa_family);
885
          pr_netaddr_set_sockaddr(na, ifa->ifa_addr);
2✔
886

887
          pr_trace_msg(trace_channel, 7,
1✔
888
            "resolved '%s' to interface with %s address %s", name,
889
            ifa->ifa_addr->sa_family == AF_INET ? "IPv4" : "IPv6",
890
            pr_netaddr_get_ipstr(na));
1✔
891

892
          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.
1✔
897
           */
898
          if (addrs == NULL) {
899
            break;
900
          }
901

×
902
        } else {
903
          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
          *addrs = make_array(p, 0, sizeof(pr_netaddr_t *));
910
          elt = push_array(*addrs);
×
911

×
912
          *elt = pcalloc(p, sizeof(pr_netaddr_t));
×
913
          pr_netaddr_set_family(*elt, ifa->ifa_addr->sa_family);
914
          pr_netaddr_set_sockaddr(*elt, ifa->ifa_addr);
×
915

916
          pr_trace_msg(trace_channel, 7,
×
917
            "resolved '%s' to interface with %s address %s", name,
918
            ifa->ifa_addr->sa_family == AF_INET ? "IPv4" : "IPv6",
919
            pr_netaddr_get_ipstr(*elt));
920
        }
921
      }
922
    }
3✔
923

3✔
924
    if (ifaddr != NULL) {
925
      freeifaddrs(ifaddr);
926
    }
3✔
927

928
    if (found_device) {
929
      return na;
930
    }
931
  }
2✔
932

933
  errno = ENOENT;
934
#else
935
  errno = ENOSYS;
936
#endif /* HAVE_GETIFADDRS */
2✔
937

938
  return NULL;
939
}
141✔
940

941
const pr_netaddr_t *pr_netaddr_get_addr2(pool *p, const char *name,
141✔
942
    array_header **addrs, unsigned int flags) {
141✔
943
  pr_netaddr_t *na = NULL;
944
  int xerrno = ENOENT;
141✔
945

141✔
946
  if (p == NULL ||
3✔
947
      name == NULL) {
3✔
948
    errno = EINVAL;
949
    return NULL;
950
  }
138✔
951

952
  pr_trace_msg(trace_channel, 10, "resolving name '%s' to IP address",
953
    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.
138✔
961
   */
133✔
962
  if (addrs == NULL) {
133✔
963
    na = netaddr_ipcache_get(p, name);
964
    if (na != NULL) {
965
      return na;
966
    }
967
  }
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
   */
98✔
978

98✔
979
  na = get_addr_by_ip(p, name, addrs, flags);
980
  xerrno = errno;
98✔
981

982
  if (na != NULL) {
983
    return na;
984
  }
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
   */
21✔
994

20✔
995
  if (!(flags & PR_NETADDR_GET_ADDR_FL_EXCL_DNS)) {
20✔
996
    na = get_addr_by_name(p, name, addrs, flags);
997
    xerrno = errno;
20✔
998

999
    if (na != NULL) {
1000
      return na;
1001
    }
1002
  }
9✔
1003

3✔
1004
  if (flags & PR_NETADDR_GET_ADDR_FL_INCL_DEVICE) {
3✔
1005
    na = get_addr_by_device(p, name, addrs, flags);
1006
    xerrno = errno;
3✔
1007

1008
    if (na != NULL) {
1009
      return na;
1010
    }
1011
  }
8✔
1012

1013
  pr_trace_msg(trace_channel, 8, "failed to resolve '%s' to an IP address",
8✔
1014
    name);
8✔
1015
  errno = xerrno;
1016
  return NULL;
1017
}
136✔
1018

1019
const pr_netaddr_t *pr_netaddr_get_addr(pool *p, const char *name,
135✔
1020
    array_header **addrs) {
1021
  return pr_netaddr_get_addr2(p, name, addrs, 0);
1022
}
2,111✔
1023

185✔
1024
int pr_netaddr_get_family(const pr_netaddr_t *na) {
2✔
1025
  if (na == NULL) {
2✔
1026
    errno = EINVAL;
1027
    return -1;
1028
  }
443✔
1029

1030
  return na->na_family;
1031
}
501✔
1032

501✔
1033
int pr_netaddr_set_family(pr_netaddr_t *na, int family) {
1✔
1034
  if (!na) {
1✔
1035
    errno = EINVAL;
1036
    return -1;
1037
  }
1038

500✔
1039
  /* Set the family member of the appropriate sockaddr struct. */
295✔
1040
  switch (family) {
295✔
1041
    case AF_INET:
295✔
1042
      na->na_addr.v4.sin_family = AF_INET;
1043
      break;
1044

199✔
1045
#ifdef PR_USE_IPV6
199✔
1046
    case AF_INET6:
199✔
1047
      if (use_ipv6 == TRUE) {
199✔
1048
        na->na_addr.v6.sin6_family = AF_INET6;
1049
        break;
1050
      }
1051
#endif /* PR_USE_IPV6 */
1052

1053
    default:
6✔
1054
#ifdef EAFNOSUPPORT
1055
      errno = EAFNOSUPPORT;
1056
#else
1057
      errno = EINVAL;
6✔
1058
#endif
1059
      return -1;
1060
  }
494✔
1061

494✔
1062
  na->na_family = family;
1063
  return 0;
1064
}
370✔
1065

370✔
1066
size_t pr_netaddr_get_sockaddr_len(const pr_netaddr_t *na) {
1✔
1067
  if (na == NULL) {
1✔
1068
    errno = EINVAL;
1069
    return -1;
1070
  }
369✔
1071

1072
  switch (pr_netaddr_get_family(na)) {
1073
    case AF_INET:
1074
      return sizeof(struct sockaddr_in);
1075

170✔
1076
#if defined(PR_USE_IPV6)
170✔
1077
    case AF_INET6:
1078
      if (use_ipv6 == TRUE) {
1079
        return sizeof(struct sockaddr_in6);
1080
      }
1081
#endif /* PR_USE_IPV6 */
1082
  }
14✔
1083

14✔
1084
  errno = EPERM;
1085
  return -1;
1086
}
4✔
1087

4✔
1088
size_t pr_netaddr_get_inaddr_len(const pr_netaddr_t *na) {
1✔
1089
  if (na == NULL) {
1✔
1090
    errno = EINVAL;
1091
    return -1;
1092
  }
3✔
1093

1094
  switch (pr_netaddr_get_family(na)) {
1095
    case AF_INET:
1096
      return sizeof(struct in_addr);
1097

1✔
1098
#ifdef PR_USE_IPV6
1✔
1099
    case AF_INET6:
1100
      return sizeof(struct in6_addr);
1101
#endif /* PR_USE_IPV6 */
1102
  }
1✔
1103

1✔
1104
  errno = EPERM;
1105
  return -1;
1106
}
675✔
1107

675✔
1108
struct sockaddr *pr_netaddr_get_sockaddr(const pr_netaddr_t *na) {
1✔
1109
  if (na == NULL) {
1✔
1110
    errno = EINVAL;
1111
    return NULL;
1112
  }
674✔
1113

371✔
1114
  switch (pr_netaddr_get_family(na)) {
371✔
1115
    case AF_INET:
1116
      return (struct sockaddr *) &na->na_addr.v4;
1117

290✔
1118
#if defined(PR_USE_IPV6)
290✔
1119
    case AF_INET6:
289✔
1120
      if (use_ipv6 == TRUE) {
1121
        return (struct sockaddr *) &na->na_addr.v6;
1122
      }
1123
#endif /* PR_USE_IPV6 */
1124
  }
14✔
1125

14✔
1126
  errno = EPERM;
1127
  return NULL;
1128
}
417✔
1129

417✔
1130
int pr_netaddr_set_sockaddr(pr_netaddr_t *na, struct sockaddr *addr) {
417✔
1131
  if (na == NULL ||
2✔
1132
      addr == NULL) {
2✔
1133
    errno = EINVAL;
1134
    return -1;
1135
  }
415✔
1136

415✔
1137
  memset(&na->na_addr, 0, sizeof(na->na_addr));
261✔
1138
  switch (na->na_family) {
261✔
1139
    case AF_INET:
261✔
1140
      memcpy(&(na->na_addr.v4), addr, sizeof(struct sockaddr_in));
1141
      return 0;
1142

153✔
1143
#if defined(PR_USE_IPV6)
153✔
1144
    case AF_INET6:
152✔
1145
      if (use_ipv6 == TRUE) {
152✔
1146
        memcpy(&(na->na_addr.v6), addr, sizeof(struct sockaddr_in6));
1147
        return 0;
1148
      }
1149
#endif /* PR_USE_IPV6 */
1150
  }
2✔
1151

2✔
1152
  errno = EPERM;
1153
  return -1;
1154
}
64✔
1155

64✔
1156
int pr_netaddr_set_sockaddr_any(pr_netaddr_t *na) {
1✔
1157
  if (na == NULL) {
1✔
1158
    errno = EINVAL;
1159
    return -1;
1160
  }
63✔
1161

1162
  switch (pr_netaddr_get_family(na)) {
22✔
1163
    case AF_INET: {
22✔
1164
      struct in_addr in4addr_any;
22✔
1165
      in4addr_any.s_addr = htonl(INADDR_ANY);
1166
      na->na_addr.v4.sin_family = AF_INET;
1167
#ifdef SIN_LEN
1168
      na->na_addr.v4.sin_len = sizeof(struct sockaddr_in);
22✔
1169
#endif /* SIN_LEN */
22✔
1170
      memcpy(&na->na_addr.v4.sin_addr, &in4addr_any, sizeof(struct in_addr));
1✔
1171
      if (na->na_have_ipstr) {
1✔
1172
        memset(na->na_ipstr, '\0', sizeof(na->na_ipstr));
1173
        sstrncpy(na->na_ipstr, "0.0.0.0", sizeof(na->na_ipstr));
22✔
1174
      }
1175
      return 0;
1176
    }
1177

40✔
1178
#ifdef PR_USE_IPV6
40✔
1179
    case AF_INET6:
39✔
1180
      if (use_ipv6 == TRUE) {
1181
        na->na_addr.v6.sin6_family = AF_INET6;
1182
#ifdef SIN6_LEN
1183
        na->na_addr.v6.sin6_len = sizeof(struct sockaddr_in6);
39✔
1184
#endif /* SIN6_LEN */
39✔
1185
        memcpy(&na->na_addr.v6.sin6_addr, &in6addr_any, sizeof(struct in6_addr));
1✔
1186
        if (na->na_have_ipstr) {
1✔
1187
          memset(na->na_ipstr, '\0', sizeof(na->na_ipstr));
1188
          sstrncpy(na->na_ipstr, "::", sizeof(na->na_ipstr));
39✔
1189
        }
1190
        return 0;
1191
      }
1192
#endif /* PR_USE_IPV6 */
1193
  }
2✔
1194

2✔
1195
  errno = EPERM;
1196
  return -1;
1197
}
79✔
1198

79✔
1199
void *pr_netaddr_get_inaddr(const pr_netaddr_t *na) {
1✔
1200
  if (na == NULL) {
1✔
1201
    errno = EINVAL;
1202
    return NULL;
1203
  }
78✔
1204

23✔
1205
  switch (pr_netaddr_get_family(na)) {
23✔
1206
    case AF_INET:
1207
      return (void *) &na->na_addr.v4.sin_addr;
1208

54✔
1209
#ifdef PR_USE_IPV6
54✔
1210
    case AF_INET6:
53✔
1211
      if (use_ipv6 == TRUE) {
1212
        return (void *) &na->na_addr.v6.sin6_addr;
1213
      }
1214
#endif /* PR_USE_IPV6 */
1215
  }
2✔
1216

2✔
1217
  errno = EPERM;
1218
  return NULL;
1219
}
87✔
1220

87✔
1221
unsigned int pr_netaddr_get_port(const pr_netaddr_t *na) {
1✔
1222
  if (na == NULL) {
1✔
1223
    errno = EINVAL;
1224
    return 0;
1225
  }
86✔
1226

34✔
1227
  switch (pr_netaddr_get_family(na)) {
34✔
1228
    case AF_INET:
1229
      return na->na_addr.v4.sin_port;
1230

51✔
1231
#ifdef PR_USE_IPV6
51✔
1232
    case AF_INET6:
51✔
1233
      if (use_ipv6 == TRUE) {
1234
        return na->na_addr.v6.sin6_port;
1235
      }
1236
#endif /* PR_USE_IPV6 */
1237
  }
1✔
1238

1✔
1239
  errno = EPERM;
1240
  return 0;
1241
}
97✔
1242

97✔
1243
int pr_netaddr_set_port(pr_netaddr_t *na, unsigned int port) {
1✔
1244
  if (!na) {
1✔
1245
    errno = EINVAL;
1246
    return -1;
1247
  }
96✔
1248

52✔
1249
  switch (pr_netaddr_get_family(na)) {
52✔
1250
    case AF_INET:
52✔
1251
      na->na_addr.v4.sin_port = port;
1252
      return 0;
1253

43✔
1254
#ifdef PR_USE_IPV6
43✔
1255
    case AF_INET6:
43✔
1256
      if (use_ipv6) {
43✔
1257
        na->na_addr.v6.sin6_port = port;
1258
        return 0;
1259
      }
1260
#endif /* PR_USE_IPV6 */
1261
  }
1✔
1262

1✔
1263
  errno = EPERM;
1264
  return -1;
1265
}
3✔
1266

3✔
1267
int pr_netaddr_set_port2(pr_netaddr_t *na, unsigned int port) {
1268
  return pr_netaddr_set_port(na, htons(port));
1269
}
20✔
1270

20✔
1271
int pr_netaddr_cmp(const pr_netaddr_t *na1, const pr_netaddr_t *na2) {
20✔
1272
  pool *tmp_pool = NULL;
20✔
1273
  pr_netaddr_t *a, *b;
1274
  int res;
20✔
1275

20✔
1276
  if (na1 != NULL &&
1277
      na2 == NULL) {
1278
    return 1;
1279
  }
19✔
1280

19✔
1281
  if (na1 == NULL &&
1282
      na2 != NULL) {
1283
    return -1;
1284
  }
18✔
1285

1286
  if (na1 == NULL &&
1287
      na2 == NULL) {
1288
    return 0;
1289
  }
51✔
1290

1291
  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
     */
7✔
1297

3✔
1298
    if (pr_netaddr_is_v4mappedv6(na1) != TRUE &&
2✔
1299
        pr_netaddr_is_v4mappedv6(na2) != TRUE) {
2✔
1300
      errno = EINVAL;
1301
      return -1;
1302
    }
2✔
1303

1✔
1304
    if (pr_netaddr_is_v4mappedv6(na1) == TRUE) {
1305
      tmp_pool = make_sub_pool(permanent_pool);
1✔
1306

1307
      pr_trace_msg(trace_channel, 5, "addr '%s' is an IPv4-mapped IPv6 address",
1308
        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.
1✔
1312
       */
1✔
1313
      a = pr_netaddr_v6tov4(tmp_pool, na1);
1314
      b = (pr_netaddr_t *) na2;
1✔
1315

1316
      pr_trace_msg(trace_channel, 6, "comparing IPv4 address '%s' against "
1317
        "IPv4-mapped IPv6 address '%s'", pr_netaddr_get_ipstr(b),
1318
        pr_netaddr_get_ipstr(a));
1✔
1319

1✔
1320
    } else if (pr_netaddr_is_v4mappedv6(na2) == TRUE) {
1321
      tmp_pool = make_sub_pool(permanent_pool);
1✔
1322

1323
      pr_trace_msg(trace_channel, 5, "addr '%s' is an IPv4-mapped IPv6 address",
1324
        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.
1✔
1328
       */
1✔
1329
      a = (pr_netaddr_t *) na1;
1330
      b = pr_netaddr_v6tov4(tmp_pool, na2);
1✔
1331

1332
      pr_trace_msg(trace_channel, 6, "comparing IPv4 address '%s' against "
1333
        "IPv4-mapped IPv6 address '%s'", pr_netaddr_get_ipstr(a),
1334
        pr_netaddr_get_ipstr(b));
1335

1336
    } else {
1337
      a = (pr_netaddr_t *) na1;
1338
      b = (pr_netaddr_t *) na2;
1339
    }
1340

1341
  } else {
1342
    a = (pr_netaddr_t *) na1;
1343
    b = (pr_netaddr_t *) na2;
1344
  }
15✔
1345

15✔
1346
  switch (pr_netaddr_get_family(a)) {
15✔
1347
    case AF_INET:
1348
      res = memcmp(&a->na_addr.v4.sin_addr, &b->na_addr.v4.sin_addr,
1349
        sizeof(struct in_addr));
15✔
1350

2✔
1351
      if (res != 0) {
1352
        pr_trace_msg(trace_channel, 4, "addr %s does not match addr %s",
1353
          pr_netaddr_get_ipstr(a), pr_netaddr_get_ipstr(b));
1354
      }
15✔
1355

2✔
1356
      if (tmp_pool) {
2✔
1357
        destroy_pool(tmp_pool);
1358
        tmp_pool = NULL;
1359
      }
1360

1361
      return res;
1362

×
1363
#ifdef PR_USE_IPV6
×
1364
    case AF_INET6:
×
1365
      if (use_ipv6) {
1366
        res = memcmp(&a->na_addr.v6.sin6_addr, &b->na_addr.v6.sin6_addr,
1367
          sizeof(struct in6_addr));
×
1368

×
1369
        if (res != 0) {
1370
          pr_trace_msg(trace_channel, 4, "addr %s does not match addr %s",
1371
            pr_netaddr_get_ipstr(a), pr_netaddr_get_ipstr(b));
1372
        }
×
1373

×
1374
        if (tmp_pool != NULL) {
×
1375
          destroy_pool(tmp_pool);
1376
          tmp_pool = NULL;
1377
        }
×
1378

1379
        return res;
1380
      }
1381
#endif /* PR_USE_IPV6 */
1382
  }
×
1383

×
1384
  if (tmp_pool != NULL) {
1385
    destroy_pool(tmp_pool);
1386
  }
×
1387

×
1388
  errno = EPERM;
1389
  return -1;
1390
}
15✔
1391

1392
static int addr_ncmp(const unsigned char *aptr, const unsigned char *bptr,
15✔
1393
    unsigned int masklen) {
15✔
1394
  unsigned char nbits, nbytes;
1395
  int res;
1396

1397
  /* These null checks are unlikely to happen.  But be prepared, eh? */
15✔
1398

9✔
1399
  if (aptr != NULL &&
1400
      bptr == NULL) {
1401
    return 1;
1402
  }
15✔
1403

9✔
1404
  if (aptr == NULL &&
1405
      bptr != NULL) {
1406
    return -1;
1407
  }
9✔
1408

1409
  if (aptr == NULL &&
1410
      bptr == NULL) {
1411
    return 0;
1412
  }
15✔
1413

15✔
1414
  nbytes = masklen / 8;
1415
  nbits = masklen % 8;
15✔
1416

9✔
1417
  res = memcmp(aptr, bptr, nbytes);
1418
  if (res != 0) {
1419
    return -1;
1420
  }
7✔
1421

1✔
1422
  if (nbits > 0) {
1423
    unsigned char abyte, bbyte, mask;
1✔
1424

1✔
1425
    abyte = aptr[nbytes];
1426
    bbyte = bptr[nbytes];
1✔
1427

1428
    mask = (0xff << (8 - nbits)) & 0xff;
1✔
1429

1430
    if ((abyte & mask) > (bbyte & mask)) {
1431
      return 1;
1432
    }
1✔
1433

×
1434
    if ((abyte & mask) < (bbyte & mask)) {
1435
      return -1;
1436
    }
1437
  }
1438

1439
  return 0;
1440
}
13✔
1441

1442
int pr_netaddr_ncmp(const pr_netaddr_t *na1, const pr_netaddr_t *na2,
13✔
1443
    unsigned int bitlen) {
13✔
1444
  pool *tmp_pool = NULL;
13✔
1445
  pr_netaddr_t *a, *b;
13✔
1446
  const unsigned char *in1, *in2;
1447
  int res;
13✔
1448

13✔
1449
  if (na1 != NULL &&
1450
      na2 == NULL) {
1451
    return 1;
1452
  }
12✔
1453

12✔
1454
  if (na1 == NULL &&
1455
      na2 != NULL) {
1456
    return -1;
1457
  }
10✔
1458

1459
  if (na1 == NULL &&
1460
      na2 == NULL) {
1461
    return 0;
1462
  }
27✔
1463

1464
  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
     */
8✔
1470

3✔
1471
    if (pr_netaddr_is_v4mappedv6(na1) != TRUE &&
2✔
1472
        pr_netaddr_is_v4mappedv6(na2) != TRUE) {
2✔
1473
      errno = EINVAL;
1474
      return -1;
1475
    }
3✔
1476

2✔
1477
    if (pr_netaddr_is_v4mappedv6(na1) == TRUE) {
1478
      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.
2✔
1482
       */
2✔
1483
      a = pr_netaddr_v6tov4(tmp_pool, na1);
1484
      b = (pr_netaddr_t *) na2;
2✔
1485

1486
      pr_trace_msg(trace_channel, 6, "comparing IPv4 address '%s' against "
1487
        "IPv4-mapped IPv6 address '%s'", pr_netaddr_get_ipstr(b),
1488
        pr_netaddr_get_ipstr(a));
1✔
1489

1✔
1490
    } else if (pr_netaddr_is_v4mappedv6(na2) == TRUE) {
1491
      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.
1✔
1495
       */
1✔
1496
      a = (pr_netaddr_t *) na1;
1497
      b = pr_netaddr_v6tov4(tmp_pool, na2);
1✔
1498

1499
      pr_trace_msg(trace_channel, 6, "comparing IPv4 address '%s' against "
1500
        "IPv4-mapped IPv6 address '%s'", pr_netaddr_get_ipstr(a),
1501
        pr_netaddr_get_ipstr(b));
1502

1503
    } else {
1504
      a = (pr_netaddr_t *) na1;
1505
      b = (pr_netaddr_t *) na2;
1506
    }
1507

1508
  } else {
1509
    a = (pr_netaddr_t *) na1;
1510
    b = (pr_netaddr_t *) na2;
1511
  }
7✔
1512

7✔
1513
  switch (pr_netaddr_get_family(a)) {
1514
    case AF_INET: {
1515
      /* Make sure that the given number of bits is not more than supported
1516
       * for IPv4 addresses (32).
7✔
1517
       */
1✔
1518
      if (bitlen > 32) {
1✔
1519
        errno = EINVAL;
1520
        return -1;
1521
      }
1522

1523
      break;
1524
    }
1525

×
1526
#ifdef PR_USE_IPV6
×
1527
    case AF_INET6: {
1528
      if (use_ipv6) {
1529
        /* Make sure that the given number of bits is not more than supported
1530
         * for IPv6 addresses (128).
×
1531
         */
×
1532
        if (bitlen > 128) {
×
1533
          errno = EINVAL;
1534
          return -1;
1535
        }
1536

1537
        break;
1538
      }
1539
    }
1540
#endif /* PR_USE_IPV6 */
1541

×
1542
    default:
×
1543
      errno = EPERM;
1544
      return -1;
1545
  }
1546

6✔
1547
  /* Retrieve pointers to the contained in_addrs. */
6✔
1548
  in1 = (const unsigned char *) pr_netaddr_get_inaddr(a);
1549
  in2 = (const unsigned char *) pr_netaddr_get_inaddr(b);
6✔
1550

1551
  res = addr_ncmp(in1, in2, bitlen);
6✔
1552

3✔
1553
  if (tmp_pool) {
1554
    destroy_pool(tmp_pool);
1555
  }
1556

1557
  return res;
1558
}
14✔
1559

1560
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.
14✔
1568
   */
1569
  int match_flags = PR_FNM_NOESCAPE|PR_FNM_CASEFOLD;
14✔
1570

14✔
1571
  if (na == NULL ||
2✔
1572
      pattern == NULL) {
2✔
1573
    errno = EINVAL;
1574
    return -1;
1575
  }
12✔
1576

5✔
1577
  if (flags & PR_NETADDR_MATCH_DNS) {
1578
    const char *dnsstr;
5✔
1579

5✔
1580
    dnsstr = pr_netaddr_get_dnsstr(na);
3✔
1581
    if (pr_fnmatch(pattern, dnsstr, match_flags) == 0) {
1582
      pr_trace_msg(trace_channel, 6, "DNS name '%s' matches pattern '%s'",
3✔
1583
        dnsstr, pattern);
1584
      return TRUE;
1585
    }
1586
  }
9✔
1587

7✔
1588
  if (flags & PR_NETADDR_MATCH_IP) {
1589
    const char *ipstr;
7✔
1590

7✔
1591
    ipstr = pr_netaddr_get_ipstr(na);
3✔
1592
    if (pr_fnmatch(pattern, ipstr, match_flags) == 0) {
1593
      pr_trace_msg(trace_channel, 6, "IP address '%s' matches pattern '%s'",
3✔
1594
        ipstr, pattern);
1595
      return TRUE;
1596
    }
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.
4✔
1600
     */
2✔
1601
    if (pr_netaddr_is_v4mappedv6(na) == TRUE) {
2✔
1602
      pool *tmp_pool;
1603
      pr_netaddr_t *a;
2✔
1604

1605
      pr_trace_msg(trace_channel, 5, "addr '%s' is an IPv4-mapped IPv6 address",
1606
        ipstr);
2✔
1607

2✔
1608
      tmp_pool = make_sub_pool(permanent_pool);
1609
      a = pr_netaddr_v6tov4(tmp_pool, na);
2✔
1610

1611
      ipstr = pr_netaddr_get_ipstr(a);
2✔
1612

1✔
1613
      if (pr_fnmatch(pattern, ipstr, match_flags) == 0) {
1614
        pr_trace_msg(trace_channel, 6, "IP address '%s' matches pattern '%s'",
1615
          ipstr, pattern);
1✔
1616

1✔
1617
        destroy_pool(tmp_pool);
1618
        return TRUE;
1619
      }
1✔
1620

1621
      destroy_pool(tmp_pool);
1622
    }
1623
  }
5✔
1624

1625
  pr_trace_msg(trace_channel, 4, "addr %s does not match pattern '%s'",
5✔
1626
    pr_netaddr_get_ipstr(na), pattern);
1627
  return FALSE;
1628
}
665✔
1629

1630
const char *pr_netaddr_get_ipstr(const pr_netaddr_t *na) {
665✔
1631
#if defined(PR_USE_IPV6)
1632
  char buf[INET6_ADDRSTRLEN];
1633
#else
1634
  char buf[INET_ADDRSTRLEN];
665✔
1635
#endif /* PR_USE_IPV6 */
665✔
1636
  int res = 0, xerrno;
1637
  pr_netaddr_t *addr;
665✔
1638

6✔
1639
  if (na == NULL) {
6✔
1640
    errno = EINVAL;
1641
    return NULL;
1642
  }
1643

1644
  /* If this pr_netaddr_t has already been resolved to an IP string, return the
1645
   * cached string.
659✔
1646
   */
459✔
1647
  if (na->na_have_ipstr) {
1648
    return na->na_ipstr;
1649
  }
200✔
1650

200✔
1651
  memset(buf, '\0', sizeof(buf));
200✔
1652
  res = pr_getnameinfo(pr_netaddr_get_sockaddr(na),
200✔
1653
    pr_netaddr_get_sockaddr_len(na), buf, sizeof(buf), NULL, 0, NI_NUMERICHOST);
1654
  xerrno = errno;
200✔
1655

9✔
1656
  if (res != 0) {
9✔
1657
    if (res != EAI_SYSTEM) {
9✔
1658
      pr_log_pri(PR_LOG_WARNING, "getnameinfo error: %s", pr_gai_strerror(res));
1659
      errno = EIO;
1660

×
1661
    } else {
1662
      pr_log_pri(PR_LOG_WARNING, "getnameinfo system error: [%d] %s",
×
1663
        xerrno, strerror(xerrno));
1664
      errno = xerrno;
1665
    }
9✔
1666

1667
    return NULL;
1668
  }
1669

191✔
1670
#ifdef PR_USE_IPV6
191✔
1671
  if (use_ipv6 &&
1672
      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.
81✔
1675
     */
1676
    char *ptr;
81✔
1677

81✔
1678
    ptr = strrchr(buf, '%');
×
1679
    if (ptr != NULL) {
1680
      *ptr = '\0';
1681
    }
1682
  }
1683
#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.
191✔
1689
   */
191✔
1690
  addr = (pr_netaddr_t *) na;
191✔
1691
  memset(addr->na_ipstr, '\0', sizeof(addr->na_ipstr));
191✔
1692
  sstrncpy(addr->na_ipstr, buf, sizeof(addr->na_ipstr));
1693
  addr->na_have_ipstr = TRUE;
191✔
1694

1695
  return na->na_ipstr;
1696
}
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

8✔
1837
#ifdef HAVE_GETHOSTBYNAME2
1838
static int netaddr_get_dnsstr_gethostbyname(const pr_netaddr_t *na,
8✔
1839
    const char *name) {
8✔
1840
  struct hostent *hent = NULL;
8✔
1841
  int family, ok = FALSE;
1842
  void *inaddr;
8✔
1843

8✔
1844
  family = pr_netaddr_get_family(na);
×
1845
  if (family < 0) {
1846
    return -1;
1847
  }
8✔
1848

1849
  inaddr = pr_netaddr_get_inaddr(na);
8✔
1850

×
1851
  if (pr_netaddr_is_v4mappedv6(na) == TRUE) {
×
1852
    family = AF_INET;
1853
    inaddr = get_v4inaddr(na);
1854
  }
8✔
1855

1856
  hent = gethostbyname2(name, family);
8✔
1857

8✔
1858
  if (hent != NULL) {
1859
    char **checkaddr;
8✔
1860

8✔
1861
    if (hent->h_name != NULL) {
1862
      netaddr_dnscache_set(pr_netaddr_get_ipstr(na), hent->h_name);
1863
    }
8✔
1864

1865
    pr_trace_msg(trace_channel, 10,
8✔
1866
      "checking addresses associated with host '%s'",
1867
      hent->h_name ? hent->h_name : "(null)");
8✔
1868

7✔
1869
    switch (hent->h_addrtype) {
7✔
1870
      case AF_INET:
7✔
1871
        if (family == AF_INET) {
7✔
1872
          for (checkaddr = hent->h_addr_list; *checkaddr; ++checkaddr) {
7✔
1873
            if (memcmp(*checkaddr, inaddr, hent->h_length) == 0) {
1874
              char **alias;
19✔
1875

12✔
1876
              for (alias = hent->h_aliases; *alias; ++alias) {
12✔
1877
                if (hent->h_name) {
1878
                  pr_trace_msg(trace_channel, 10,
12✔
1879
                    "host '%s' has alias '%s'", hent->h_name, *alias);
12✔
1880
                  netaddr_ipcache_set(*alias, na);
1881
                  netaddr_dnscache_set(pr_netaddr_get_ipstr(na), *alias);
1882
                }
1883
              }
1884

1885
              ok = TRUE;
1886
              break;
1887
            }
1888
          }
1889
        }
1890
        break;
1891

1✔
1892
# if defined(PR_USE_IPV6)
1✔
1893
      case AF_INET6:
1✔
1894
        if (use_ipv6 && family == AF_INET6) {
1✔
1895
          for (checkaddr = hent->h_addr_list; *checkaddr; ++checkaddr) {
1✔
1896
            if (memcmp(*checkaddr, inaddr, hent->h_length) == 0) {
1897
              char **alias;
3✔
1898

2✔
1899
              for (alias = hent->h_aliases; *alias; ++alias) {
2✔
1900
                if (hent->h_name) {
1901
                  pr_trace_msg(trace_channel, 10,
2✔
1902
                    "host '%s' has alias '%s'", hent->h_name, *alias);
2✔
1903
                  netaddr_ipcache_set(*alias, na);
1904
                  netaddr_dnscache_set(pr_netaddr_get_ipstr(na), *alias);
1905
                }
1906
              }
1907

1908
              ok = TRUE;
1909
              break;
1910
            }
1911
          }
1912
        }
1913
        break;
1914
# endif /* PR_USE_IPV6 */
1915
    }
1916

×
1917
  } else {
×
1918
    pr_log_debug(DEBUG1, "notice: unable to resolve '%s' as %s address: %s",
1919
      name, family != AF_INET ? "IPv6" : "IPv4", hstrerror(h_errno));
1920
  }
8✔
1921

1922
  return (ok ? 0 : -1);
1923
}
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).
44✔
1929
 */
44✔
1930
const char *pr_netaddr_get_dnsstr(const pr_netaddr_t *na) {
44✔
1931
  char dns_buf[1024], *name = NULL;
1932
  pr_netaddr_t *addr = NULL, *cache = NULL;
44✔
1933

4✔
1934
  if (na == NULL) {
4✔
1935
    errno = EINVAL;
1936
    return NULL;
1937
  }
40✔
1938

40✔
1939
  cache = netaddr_ipcache_get(NULL, pr_netaddr_get_ipstr(na));
38✔
1940
  if (cache &&
28✔
1941
      cache->na_have_dnsstr) {
28✔
1942
    addr = (pr_netaddr_t *) na;
28✔
1943
    memset(addr->na_dnsstr, '\0', sizeof(addr->na_dnsstr));
28✔
1944
    sstrncpy(addr->na_dnsstr, cache->na_dnsstr, sizeof(addr->na_dnsstr));
1945
    addr->na_have_dnsstr = TRUE;
28✔
1946

1947
    return na->na_dnsstr;
1948
  }
1949

1950
  /* If this pr_netaddr_t has already been resolved to an DNS string, return the
1951
   * cached string.
12✔
1952
   */
×
1953
  if (na->na_have_dnsstr) {
1954
    return na->na_dnsstr;
1955
  }
12✔
1956

10✔
1957
  if (reverse_dns) {
1958
    int res = 0;
10✔
1959

1960
    pr_trace_msg(trace_channel, 3,
1961
      "verifying DNS name for IP address %s via reverse DNS lookup",
1962
      pr_netaddr_get_ipstr(na));
10✔
1963

10✔
1964
    memset(dns_buf, '\0', sizeof(dns_buf));
10✔
1965
    res = pr_getnameinfo(pr_netaddr_get_sockaddr(na),
1966
      pr_netaddr_get_sockaddr_len(na), dns_buf, sizeof(dns_buf), NULL, 0,
10✔
1967
      NI_NAMEREQD);
1968
    dns_buf[sizeof(dns_buf)-1] = '\0';
10✔
1969

1970
    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
       */
8✔
1975
#ifdef HAVE_GETHOSTBYNAME2
1976
      res = netaddr_get_dnsstr_gethostbyname(na, dns_buf);
1977
#else
1978
      res = netaddr_get_dnsstr_getaddrinfo(na, dns_buf);
8✔
1979
#endif /* HAVE_GETHOSTBYNAME2 */
8✔
1980
      if (res == 0) {
8✔
1981
        name = dns_buf;
1982
        pr_trace_msg(trace_channel, 8,
1983
          "using DNS name '%s' for IP address '%s'", name,
1984
          pr_netaddr_get_ipstr(na));
1985

×
1986
      } else {
×
1987
        name = NULL;
1988
        pr_trace_msg(trace_channel, 8,
1989
          "unable to verify any DNS names for IP address '%s'",
1990
          pr_netaddr_get_ipstr(na));
1991
      }
1992
    }
1993

2✔
1994
  } else {
1995
    pr_log_debug(DEBUG10,
1996
      "UseReverseDNS off, returning IP address instead of DNS name");
1997
  }
2✔
1998

8✔
1999
  if (name) {
2000
    name = pr_netaddr_validate_dns_str(name);
2001

4✔
2002
  } else {
2003
    name = (char *) pr_netaddr_get_ipstr(na);
2004
  }
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.
12✔
2010
   */
12✔
2011
  addr = (pr_netaddr_t *) na;
12✔
2012
  memset(addr->na_dnsstr, '\0', sizeof(addr->na_dnsstr));
12✔
2013
  sstrncpy(addr->na_dnsstr, name, sizeof(addr->na_dnsstr));
2014
  addr->na_have_dnsstr = TRUE;
2015

12✔
2016
  /* Update the netaddr object in the cache with the resolved DNS names. */
12✔
2017
  netaddr_ipcache_set(name, na);
2018
  netaddr_ipcache_set(pr_netaddr_get_ipstr(na), na);
12✔
2019

2020
  return na->na_dnsstr;
2021
}
4✔
2022

4✔
2023
array_header *pr_netaddr_get_dnsstr_list(pool *p, const pr_netaddr_t *na) {
2024
  array_header *res;
4✔
2025

4✔
2026
  if (p == NULL ||
2✔
2027
      na == NULL) {
2✔
2028
    errno = EINVAL;
2029
    return NULL;
2030
  }
2✔
2031

2032
  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
    return make_array(p, 0, sizeof(char *));
2037
  }
2✔
2038

2✔
2039
  res = netaddr_dnscache_get(p, pr_netaddr_get_ipstr(na));
1✔
2040
  if (res == NULL) {
2041
    res = make_array(p, 0, sizeof(char *));
2042
  }
2043

2044
  return res;
2045
}
2046

2✔
2047
/* Return the hostname (wrapper for gethostname(2), except returns FQDN). */
2✔
2048
const char *pr_netaddr_get_localaddr_str(pool *p) {
2✔
2049
  char buf[256];
2050
  int res, xerrno;
2✔
2051

1✔
2052
  if (p == NULL) {
1✔
2053
    errno = EINVAL;
2054
    return NULL;
2055
  }
1✔
2056

×
2057
  if (have_localaddr_str) {
2058
    return pr_netaddr_validate_dns_str(pstrdup(p, localaddr_str));
2059
  }
1✔
2060

1✔
2061
  memset(buf, '\0', sizeof(buf));
1✔
2062
  res = gethostname(buf, sizeof(buf)-1);
2063
  xerrno = errno;
1✔
2064

1✔
2065
  if (res >= 0) {
2066
    struct hostent *host;
1✔
2067

2068
    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
     */
1✔
2074
#ifdef HAVE_GETHOSTBYNAME2
1✔
2075
    host = gethostbyname2(buf, AF_INET);
×
2076
    if (host == NULL &&
2077
        h_errno == HOST_NOT_FOUND) {
×
2078
# ifdef AF_INET6
2079
      host = gethostbyname2(buf, AF_INET6);
2080
# endif /* AF_INET6 */
2081
    }
2082
#else
2083
    host = gethostbyname(buf);
1✔
2084
#endif
1✔
2085
    if (host != NULL) {
2086
      return pr_netaddr_validate_dns_str(pstrdup(p, host->h_name));
2087
    }
×
2088

×
2089
    pr_trace_msg(trace_channel, 14,
×
2090
      "gethostbyname() failed for '%s': %s", buf, hstrerror(h_errno));
2091
    return pr_netaddr_validate_dns_str(pstrdup(p, buf));
2092
  }
×
2093

×
2094
  pr_trace_msg(trace_channel, 1, "gethostname(2) error: %s", strerror(xerrno));
×
2095
  errno = xerrno;
2096
  return NULL;
2097
}
×
2098

×
2099
int pr_netaddr_set_localaddr_str(const char *addr_str) {
×
2100
  if (addr_str == NULL) {
×
2101
    errno = EINVAL;
2102
    return -1;
2103
  }
×
2104

×
2105
  memset(localaddr_str, '\0', sizeof(localaddr_str));
×
2106
  sstrncpy(localaddr_str, addr_str, sizeof(localaddr_str));
×
2107
  have_localaddr_str = TRUE;
2108
  return 0;
2109
}
6✔
2110

6✔
2111
int pr_netaddr_is_loopback(const pr_netaddr_t *na) {
1✔
2112
  if (na == NULL) {
1✔
2113
    errno = EINVAL;
2114
    return -1;
2115
  }
5✔
2116

3✔
2117
  switch (pr_netaddr_get_family(na)) {
3✔
2118
    case AF_INET:
2119
      return IN_IS_ADDR_LOOPBACK(
2120
        (struct in_addr *) pr_netaddr_get_inaddr(na));
2121

2✔
2122
#ifdef PR_USE_IPV6
2✔
2123
    case AF_INET6:
1✔
2124
      if (pr_netaddr_is_v4mappedv6(na) == TRUE) {
1✔
2125
        pool *tmp_pool;
1✔
2126
        pr_netaddr_t *v4na;
2127
        int res;
1✔
2128

1✔
2129
        tmp_pool = make_sub_pool(permanent_pool);
2130
        v4na = pr_netaddr_v6tov4(tmp_pool, na);
1✔
2131

1✔
2132
        res = pr_netaddr_is_loopback(v4na);
2133
        destroy_pool(tmp_pool);
1✔
2134

2135
        return res;
2136
      }
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));
1✔
2150
# else
2151
      return IN6_IS_ADDR_LOOPBACK(
2152
        ((struct in6_addr *) pr_netaddr_get_inaddr(na))->s6_addr32);
2153
# endif
2154
#endif /* PR_USE_IPV6 */
2155
  }
2156

2157
  return FALSE;
2158
}
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
 */
2✔
2167

2✔
2168
static int is_10_xxx_addr(uint32_t addrno) {
2169
  uint32_t rfc1918_addrno;
2✔
2170

2✔
2171
  rfc1918_addrno = htonl(0x0a000000);
2172
  return addr_ncmp((const unsigned char *) &addrno,
2173
    (const unsigned char *) &rfc1918_addrno, 8);
2174
}
3✔
2175

3✔
2176
static int is_172_16_xx_addr(uint32_t addrno) {
2177
  uint32_t rfc1918_addrno;
3✔
2178

3✔
2179
  rfc1918_addrno = htonl(0xac100000);
2180
  return addr_ncmp((const unsigned char *) &addrno,
2181
    (const unsigned char *) &rfc1918_addrno, 12);
2182
}
4✔
2183

4✔
2184
static int is_192_168_xx_addr(uint32_t addrno) {
2185
  uint32_t rfc1918_addrno;
4✔
2186

4✔
2187
  rfc1918_addrno = htonl(0xc0a80000);
2188
  return addr_ncmp((const unsigned char *) &addrno,
2189
    (const unsigned char *) &rfc1918_addrno, 16);
2190
}
6✔
2191

6✔
2192
int pr_netaddr_is_rfc1918(const pr_netaddr_t *na) {
1✔
2193
  if (na == NULL) {
1✔
2194
    errno = EINVAL;
2195
    return -1;
2196
  }
5✔
2197

4✔
2198
  switch (pr_netaddr_get_family(na)) {
4✔
2199
    case AF_INET: {
2200
      uint32_t addrno;
4✔
2201

4✔
2202
      addrno = pr_netaddr_get_addrno(na);
3✔
2203
      if (is_192_168_xx_addr(addrno) == 0 ||
4✔
2204
          is_172_16_xx_addr(addrno) == 0 ||
3✔
2205
          is_10_xxx_addr(addrno) == 0) {
2206
          return TRUE;
2207
      }
2208
      break;
2209
    }
2210

1✔
2211
#ifdef PR_USE_IPV6
1✔
2212
    case AF_INET6:
×
2213
      if (pr_netaddr_is_v4mappedv6(na) == TRUE) {
×
2214
        pool *tmp_pool;
×
2215
        pr_netaddr_t *v4na;
2216
        int res;
×
2217

×
2218
        tmp_pool = make_sub_pool(permanent_pool);
2219
        v4na = pr_netaddr_v6tov4(tmp_pool, na);
×
2220

×
2221
        res = pr_netaddr_is_rfc1918(v4na);
2222
        destroy_pool(tmp_pool);
×
2223

2224
        return res;
2225
      }
2226

2227
      /* By definition, an IPv6 address is not an RFC1918-defined address. */
2228
      return FALSE;
2229
#endif /* PR_USE_IPV6 */
2230
  }
1✔
2231

1✔
2232
  errno = EINVAL;
2233
  return FALSE;
2234
}
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.
4✔
2238
 */
4✔
2239
uint32_t pr_netaddr_get_addrno(const pr_netaddr_t *na) {
×
2240
  if (na == NULL) {
×
2241
    errno = EINVAL;
2242
    return 0;
2243
  }
4✔
2244

4✔
2245
  switch (pr_netaddr_get_family(na)) {
4✔
2246
    case AF_INET:
2247
      return (uint32_t) na->na_addr.v4.sin_addr.s_addr;
2248

×
2249
#ifdef PR_USE_IPV6
2250
    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
      errno = ENOENT;
2262
      return 0;
2263
#endif
2264
    }
2265
#endif /* PR_USE_IPV6 */
2266
  }
×
2267

×
2268
  errno = EPERM;
2269
  return 0;
2270
}
4✔
2271

4✔
2272
int pr_netaddr_is_v4(const char *name) {
4✔
2273
  int res;
2274
  struct sockaddr_in v4;
4✔
2275

1✔
2276
  if (name == NULL) {
1✔
2277
    errno = EINVAL;
2278
    return -1;
2279
  }
3✔
2280

3✔
2281
  memset(&v4, 0, sizeof(v4));
2282
  v4.sin_family = AF_INET;
2283

2284
# ifdef SIN_LEN
2285
  v4.sin_len = sizeof(struct sockaddr_in);
2286
# endif /* SIN_LEN */
3✔
2287

3✔
2288
  res = pr_inet_pton(AF_INET, name, &v4.sin_addr);
1✔
2289
  if (res > 0) {
2290
    return TRUE;
2291
  }
2292

2293
  return FALSE;
2294
}
4✔
2295

4✔
2296
int pr_netaddr_is_v6(const char *name) {
1✔
2297
  if (name == NULL) {
1✔
2298
    errno = EINVAL;
2299
    return -1;
2300
  }
2301

3✔
2302
#ifdef PR_USE_IPV6
3✔
2303
  if (use_ipv6) {
3✔
2304
    int res;
2305
    struct sockaddr_in6 v6;
3✔
2306

3✔
2307
    memset(&v6, 0, sizeof(v6));
2308
    v6.sin6_family = AF_INET6;
2309

2310
# ifdef SIN6_LEN
2311
    v6.sin6_len = sizeof(struct sockaddr_in6);
2312
# endif /* SIN6_LEN */
3✔
2313

3✔
2314
    res = pr_inet_pton(AF_INET6, name, &v6.sin6_addr);
1✔
2315
    if (res > 0) {
2316
      return TRUE;
2317
    }
2318
  }
2319

2320
  return FALSE;
2321
#else
2322
  return FALSE;
2323
#endif /* !PR_USE_IPV6 */
2324
}
61✔
2325

61✔
2326
int pr_netaddr_is_v4mappedv6(const pr_netaddr_t *na) {
1✔
2327
  if (!na) {
1✔
2328
    errno = EINVAL;
2329
    return -1;
2330
  }
60✔
2331

19✔
2332
  switch (pr_netaddr_get_family(na)) {
2333
    case AF_INET:
2334

19✔
2335
      /* This function tests only IPv6 addresses, not IPv4 addresses. */
19✔
2336
      errno = EINVAL;
2337
      return -1;
2338

41✔
2339
#ifdef PR_USE_IPV6
41✔
2340
    case AF_INET6: {
2341
      int res;
41✔
2342

×
2343
      if (!use_ipv6) {
×
2344
        errno = EINVAL;
2345
        return -1;
2346
      }
2347

2348
# ifndef LINUX
2349
      res = IN6_IS_ADDR_V4MAPPED(
2350
        (struct in6_addr *) pr_netaddr_get_inaddr(na));
41✔
2351
# else
2352
      res = IN6_IS_ADDR_V4MAPPED(
2353
        ((struct in6_addr *) pr_netaddr_get_inaddr(na))->s6_addr32);
2354
# endif
15✔
2355

15✔
2356
      if (res != TRUE) {
2357
        errno = EINVAL;
2358
      }
2359

2360
      return res;
2361
    }
2362
#endif /* PR_USE_IPV6 */
2363
  }
×
2364

×
2365
  errno = EPERM;
2366
  return -1;
2367
}
12✔
2368

12✔
2369
pr_netaddr_t *pr_netaddr_v6tov4(pool *p, const pr_netaddr_t *na) {
2370
  pr_netaddr_t *res;
12✔
2371

12✔
2372
  if (p == NULL ||
2✔
2373
      na == NULL) {
2✔
2374
    errno = EINVAL;
2375
    return NULL;
2376
  }
10✔
2377

1✔
2378
  if (pr_netaddr_is_v4mappedv6(na) != TRUE) {
1✔
2379
    errno = EPERM;
2380
    return NULL;
2381
  }
9✔
2382

9✔
2383
  res = pr_netaddr_alloc(p);
9✔
2384
  pr_netaddr_set_family(res, AF_INET);
9✔
2385
  pr_netaddr_set_port(res, pr_netaddr_get_port(na));
2386
  memcpy(&res->na_addr.v4.sin_addr, get_v4inaddr(na), sizeof(struct in_addr));
9✔
2387

2388
  return res;
2389
}
4✔
2390

4✔
2391
pr_netaddr_t *pr_netaddr_v4tov6(pool *p, const pr_netaddr_t *na) {
2392
  pr_netaddr_t *res;
4✔
2393

4✔
2394
  if (p == NULL ||
2✔
2395
      na == NULL) {
2✔
2396
    errno = EINVAL;
2397
    return NULL;
2398
  }
2✔
2399

1✔
2400
  if (pr_netaddr_get_family(na) != AF_INET) {
1✔
2401
    errno = EPERM;
2402
    return NULL;
2403
  }
2404

2✔
2405
#ifdef PR_USE_IPV6
1✔
2406
  res = (pr_netaddr_t *) pr_netaddr_get_addr(p,
1✔
2407
    pstrcat(p, "::ffff:", pr_netaddr_get_ipstr(na), NULL), NULL);
1✔
2408
  if (res != NULL) {
2409
    pr_netaddr_set_port(res, pr_netaddr_get_port(na));
2410
  }
2411

2412
#else
2413
  errno = EPERM;
2414
  res = NULL;
2415
#endif /* PR_USE_IPV6 */
2416

2417
  return res;
2418
}
4✔
2419

4✔
2420
const pr_netaddr_t *pr_netaddr_get_sess_local_addr(void) {
2421
  if (have_sess_local_addr) {
2422
    return &sess_local_addr;
2423
  }
4✔
2424

4✔
2425
  errno = ENOENT;
2426
  return NULL;
2427
}
6✔
2428

6✔
2429
const pr_netaddr_t *pr_netaddr_get_sess_remote_addr(void) {
2430
  if (have_sess_remote_addr) {
2431
    return &sess_remote_addr;
2432
  }
5✔
2433

5✔
2434
  errno = ENOENT;
2435
  return NULL;
2436
}
2✔
2437

2✔
2438
const char *pr_netaddr_get_sess_remote_name(void) {
2439
  if (have_sess_remote_addr) {
2440
    return sess_remote_name;
2441
  }
2✔
2442

2✔
2443
  errno = ENOENT;
2444
  return NULL;
2445
}
1✔
2446

1✔
2447
void pr_netaddr_set_sess_addrs(void) {
1✔
2448
  memset(&sess_local_addr, 0, sizeof(sess_local_addr));
1✔
2449
  pr_netaddr_set_family(&sess_local_addr,
1✔
2450
    pr_netaddr_get_family(session.c->local_addr));
1✔
2451
  pr_netaddr_set_sockaddr(&sess_local_addr,
1✔
2452
    pr_netaddr_get_sockaddr(session.c->local_addr));
2453
  have_sess_local_addr = TRUE;
1✔
2454

1✔
2455
  memset(&sess_remote_addr, 0, sizeof(sess_remote_addr));
1✔
2456
  pr_netaddr_set_family(&sess_remote_addr,
1✔
2457
    pr_netaddr_get_family(session.c->remote_addr));
1✔
2458
  pr_netaddr_set_sockaddr(&sess_remote_addr,
2459
    pr_netaddr_get_sockaddr(session.c->remote_addr));
1✔
2460

1✔
2461
  memset(sess_remote_name, '\0', sizeof(sess_remote_name));
1✔
2462
  sstrncpy(sess_remote_name, session.c->remote_name, sizeof(sess_remote_name));
1✔
2463
  have_sess_remote_addr = TRUE;
2464
}
201✔
2465

201✔
2466
unsigned char pr_netaddr_use_ipv6(void) {
200✔
2467
  if (use_ipv6 == TRUE) {
2468
    return TRUE;
2469
  }
2470

2471
  return FALSE;
2472
}
6✔
2473

2474
void pr_netaddr_disable_ipv6(void) {
6✔
2475
#if defined(PR_USE_IPV6)
2476
  use_ipv6 = FALSE;
6✔
2477
#endif /* PR_USE_IPV6 */
2478
}
9✔
2479

2480
void pr_netaddr_enable_ipv6(void) {
9✔
2481
#if defined(PR_USE_IPV6)
2482
  use_ipv6 = TRUE;
9✔
2483
#endif /* PR_USE_IPV6 */
2484
}
1✔
2485

1✔
2486
void pr_netaddr_clear_cache(void) {
1✔
2487
  if (netaddr_iptab != NULL) {
1✔
2488
    pr_trace_msg(trace_channel, 5, "emptying netaddr IP cache");
1✔
2489
    (void) pr_table_empty(netaddr_iptab);
2490
    (void) pr_table_free(netaddr_iptab);
2491

1✔
2492
    /* Allocate a fresh table. */
2493
    netaddr_iptab = pr_table_alloc(netaddr_pool, 0);
2494
  }
1✔
2495

1✔
2496
  if (netaddr_dnstab != NULL) {
1✔
2497
    pr_trace_msg(trace_channel, 5, "emptying netaddr DNS cache");
1✔
2498
    (void) pr_table_empty(netaddr_dnstab);
2499
    (void) pr_table_free(netaddr_dnstab);
2500

1✔
2501
    /* Allocate a fresh table. */
2502
    netaddr_dnstab = pr_table_alloc(netaddr_pool, 0);
1✔
2503
  }
2504
}
×
2505

×
2506
void pr_netaddr_clear_dnscache(const char *ip_str) {
×
2507
  if (netaddr_dnstab != NULL) {
2508
    (void) pr_table_remove(netaddr_dnstab, ip_str, NULL);
×
2509
  }
2510
}
2✔
2511

2✔
2512
void pr_netaddr_clear_ipcache(const char *name) {
2✔
2513
  if (netaddr_iptab != NULL) {
2514
    (void) pr_table_remove(netaddr_iptab, name, NULL);
2✔
2515
  }
2516
}
96✔
2517

96✔
2518
void init_netaddr(void) {
×
2519
  if (netaddr_pool != NULL) {
×
2520
    pr_netaddr_clear_cache();
×
2521
    destroy_pool(netaddr_pool);
2522
    netaddr_pool = NULL;
2523
  }
96✔
2524

96✔
2525
  netaddr_pool = make_sub_pool(permanent_pool);
2526
  pr_pool_tag(netaddr_pool, "Netaddr API");
96✔
2527

96✔
2528
  netaddr_iptab = pr_table_alloc(netaddr_pool, 0);
96✔
2529
  netaddr_dnstab = pr_table_alloc(netaddr_pool, 0);
2530
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc