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

proftpd / proftpd / 26127302613

19 May 2026 09:51PM UTC coverage: 93.024% (+0.4%) from 92.635%
26127302613

push

github

51329 of 55178 relevant lines covered (93.02%)

215.14 hits per line

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

86.97
/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;
23✔
69

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

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

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

14✔
81
      if (p) {
82
        /* If the caller provided a pool, return a copy of the array. */
14✔
83
        return copy_array_str(p, res);
84
      }
×
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) {
21✔
98
    void *v = NULL;
21✔
99
    array_header *res = NULL;
21✔
100
    int add_list = FALSE;
21✔
101

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

7✔
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;
21✔
128

21✔
129
    if (add_list == TRUE) {
130
      if (pr_table_add(netaddr_dnstab, pstrdup(netaddr_pool, ip_str), v,
21✔
131
          sizeof(array_header *)) < 0) {
7✔
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",
7✔
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) {
107✔
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",
107✔
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) {
52✔
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;
13✔
429

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

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

103✔
438
    /* Per RFC requirements, these are all that are valid from a DNS. */
439
    if (!PR_ISALNUM(*p) &&
440
        *p != '.' &&
91✔
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;
8✔
643
# if defined(EAFNOSUPPORT)
644
            } else if (res == EAI_FAMILY) {
645
              xerrno = EAFNOSUPPORT;
3✔
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
    }
698

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

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

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

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

716
    if (!(flags & PR_NETADDR_GET_ADDR_FL_EXCL_DNS)) {
717
      if (netaddr_ipcache_set(name, na) < 0) {
12✔
718
        pr_trace_msg(trace_channel, 2, "error setting '%s' in cache: %s", name,
12✔
719
          strerror(errno));
×
720
      }
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",
12✔
724
          pr_netaddr_get_ipstr(na), strerror(errno));
×
725
      }
726
    }
727

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

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

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

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

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

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

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

755
    pr_freeaddrinfo(info);
756
  }
12✔
757

758
#ifdef PR_USE_IPV6
759
  if (use_ipv6 == TRUE &&
760
      addrs != NULL) {
12✔
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
    memset(&hints, 0, sizeof(hints));
773
    hints.ai_family = AF_INET6;
3✔
774
    hints.ai_socktype = SOCK_STREAM;
3✔
775
    hints.ai_protocol = IPPROTO_TCP;
3✔
776
    info = NULL;
3✔
777

3✔
778
    pr_trace_msg(trace_channel, 7,
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

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

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

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

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

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

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

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

836
  return na;
837
}
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
842
  struct ifaddrs *ifaddr = NULL;
843
  pr_netaddr_t *na = NULL;
3✔
844
  int res, xerrno;
3✔
845

3✔
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
  res = getifaddrs(&ifaddr);
851
  if (res < 0) {
3✔
852
    xerrno = errno;
3✔
853

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

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

3✔
861
    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
862
      pr_signals_handle();
15✔
863

13✔
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
      if (ifa->ifa_addr == NULL) {
868
        continue;
13✔
869
      }
×
870

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

880
      if (strcmp(ifa->ifa_name, name) == 0) {
881
        if (found_device == FALSE) {
7✔
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);
1✔
886

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

892
          found_device = TRUE;
893

1✔
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
          if (addrs == NULL) {
899
            break;
1✔
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
    }
923

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

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

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

938
  return NULL;
939
}
2✔
940

941
const pr_netaddr_t *pr_netaddr_get_addr2(pool *p, const char *name,
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 ||
947
      name == NULL) {
141✔
948
    errno = EINVAL;
141✔
949
    return NULL;
3✔
950
  }
3✔
951

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1291
  if (pr_netaddr_get_family(na1) != pr_netaddr_get_family(na2)) {
1292

51✔
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
    if (pr_netaddr_is_v4mappedv6(na1) != TRUE &&
1299
        pr_netaddr_is_v4mappedv6(na2) != TRUE) {
7✔
1300
      errno = EINVAL;
3✔
1301
      return -1;
2✔
1302
    }
2✔
1303

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

1✔
1307
      pr_trace_msg(trace_channel, 5, "addr '%s' is an IPv4-mapped IPv6 address",
1308
        pr_netaddr_get_ipstr((pr_netaddr_t *) na1));
1✔
1309

1310
      /* This case means that na1 is an IPv4-mapped IPv6 address, and
1311
       * na2 is an IPv4 address.
1312
       */
1313
      a = pr_netaddr_v6tov4(tmp_pool, na1);
1314
      b = (pr_netaddr_t *) na2;
1✔
1315

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

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

1✔
1323
      pr_trace_msg(trace_channel, 5, "addr '%s' is an IPv4-mapped IPv6 address",
1324
        pr_netaddr_get_ipstr((pr_netaddr_t *) na2));
1✔
1325

1326
      /* This case means that na is an IPv4 address, and na2 is an
1327
       * IPv4-mapped IPv6 address.
1328
       */
1329
      a = (pr_netaddr_t *) na1;
1330
      b = pr_netaddr_v6tov4(tmp_pool, na2);
1✔
1331

1✔
1332
      pr_trace_msg(trace_channel, 6, "comparing IPv4 address '%s' against "
1333
        "IPv4-mapped IPv6 address '%s'", pr_netaddr_get_ipstr(a),
1✔
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
  }
1345

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

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

1356
      if (tmp_pool) {
1357
        destroy_pool(tmp_pool);
15✔
1358
        tmp_pool = NULL;
2✔
1359
      }
2✔
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
}
×
1391

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

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

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

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

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

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

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

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

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

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

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

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

1439
  return 0;
1440
}
1441

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

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

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

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

1464
  if (pr_netaddr_get_family(na1) != pr_netaddr_get_family(na2)) {
1465

27✔
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
    if (pr_netaddr_is_v4mappedv6(na1) != TRUE &&
1472
        pr_netaddr_is_v4mappedv6(na2) != TRUE) {
8✔
1473
      errno = EINVAL;
3✔
1474
      return -1;
2✔
1475
    }
2✔
1476

1477
    if (pr_netaddr_is_v4mappedv6(na1) == TRUE) {
1478
      tmp_pool = make_sub_pool(permanent_pool);
3✔
1479

2✔
1480
      /* This case means that na1 is an IPv4-mapped IPv6 address, and
1481
       * na2 is an IPv4 address.
1482
       */
1483
      a = pr_netaddr_v6tov4(tmp_pool, na1);
1484
      b = (pr_netaddr_t *) na2;
2✔
1485

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

1490
    } else if (pr_netaddr_is_v4mappedv6(na2) == TRUE) {
1491
      tmp_pool = make_sub_pool(permanent_pool);
1✔
1492

1✔
1493
      /* This case means that na is an IPv4 address, and na2 is an
1494
       * IPv4-mapped IPv6 address.
1495
       */
1496
      a = (pr_netaddr_t *) na1;
1497
      b = pr_netaddr_v6tov4(tmp_pool, na2);
1✔
1498

1✔
1499
      pr_trace_msg(trace_channel, 6, "comparing IPv4 address '%s' against "
1500
        "IPv4-mapped IPv6 address '%s'", pr_netaddr_get_ipstr(a),
1✔
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
  }
1512

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

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

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

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

1557
  return res;
1558
}
1559

1560
int pr_netaddr_fnmatch(const pr_netaddr_t *na, const char *pattern, int flags) {
1561

14✔
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
  int match_flags = PR_FNM_NOESCAPE|PR_FNM_CASEFOLD;
1570

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

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

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

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

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

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

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

2✔
1611
      ipstr = pr_netaddr_get_ipstr(a);
1612

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

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

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

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

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

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

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

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

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

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

1667
    return NULL;
1668
  }
9✔
1669

1670
#ifdef PR_USE_IPV6
1671
  if (use_ipv6 &&
1672
      pr_netaddr_get_family(na) == AF_INET6) {
203✔
1673
    /* The getnameinfo(3) implementation might append the zone ID to an IPv6
203✔
1674
     * name; we need to trim it off.
1675
     */
1676
    char *ptr;
1677

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

203✔
1695
  return na->na_ipstr;
1696
}
203✔
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
    const char *name) {
7✔
1840
  struct hostent *hent = NULL;
1841
  int family, ok = FALSE;
7✔
1842
  void *inaddr;
7✔
1843

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

1849
  inaddr = pr_netaddr_get_inaddr(na);
1850

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

1856
  hent = gethostbyname2(name, family);
1857

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

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

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

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

6✔
1876
              for (alias = hent->h_aliases; *alias; ++alias) {
1877
                if (hent->h_name) {
18✔
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);
12✔
1882
                }
12✔
1883
              }
1884

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

1892
# if defined(PR_USE_IPV6)
1893
      case AF_INET6:
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) {
1✔
1897
              char **alias;
1✔
1898

1✔
1899
              for (alias = hent->h_aliases; *alias; ++alias) {
1900
                if (hent->h_name) {
3✔
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);
2✔
1905
                }
2✔
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
  }
×
1921

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

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

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

28✔
1947
    return na->na_dnsstr;
1948
  }
28✔
1949

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

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

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

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

10✔
1970
    if (res == 0) {
1971
      /* Some older glibc's getaddrinfo(3) does not appear to handle IPv6
10✔
1972
       * addresses properly; we thus prefer gethostbyname2(3) on systems
1973
       * which have it, for such older systems.
1974
       */
1975
#ifdef HAVE_GETHOSTBYNAME2
1976
      res = netaddr_get_dnsstr_gethostbyname(na, dns_buf);
1977
#else
7✔
1978
      res = netaddr_get_dnsstr_getaddrinfo(na, dns_buf);
1979
#endif /* HAVE_GETHOSTBYNAME2 */
1980
      if (res == 0) {
1981
        name = dns_buf;
7✔
1982
        pr_trace_msg(trace_channel, 8,
7✔
1983
          "using DNS name '%s' for IP address '%s'", name,
7✔
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

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

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

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

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

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

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 ||
2027
      na == NULL) {
4✔
2028
    errno = EINVAL;
4✔
2029
    return NULL;
2✔
2030
  }
2✔
2031

2032
  if (!reverse_dns) {
2033
    /* If UseReverseDNS is off, then we won't have any names that we trust.
2✔
2034
     * So return an empty list.
2035
     */
2036
    return make_array(p, 0, sizeof(char *));
2037
  }
×
2038

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

2044
  return res;
2045
}
2046

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

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

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

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

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

1✔
2068
    buf[sizeof(buf)-1] = '\0';
2069

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

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

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

2122
#ifdef PR_USE_IPV6
2123
    case AF_INET6:
2124
      if (pr_netaddr_is_v4mappedv6(na) == TRUE) {
2✔
2125
        pool *tmp_pool;
2✔
2126
        pr_netaddr_t *v4na;
1✔
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

1✔
2135
        return res;
2136
      }
1✔
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
      return IN6_IS_ADDR_LOOPBACK(
2152
        ((struct in6_addr *) pr_netaddr_get_inaddr(na))->s6_addr32);
1✔
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
 */
2167

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,
2✔
2173
    (const unsigned char *) &rfc1918_addrno, 8);
2✔
2174
}
2175

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,
3✔
2181
    (const unsigned char *) &rfc1918_addrno, 12);
3✔
2182
}
2183

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,
4✔
2189
    (const unsigned char *) &rfc1918_addrno, 16);
4✔
2190
}
2191

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

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

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

2211
#ifdef PR_USE_IPV6
2212
    case AF_INET6:
2213
      if (pr_netaddr_is_v4mappedv6(na) == TRUE) {
1✔
2214
        pool *tmp_pool;
1✔
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
  }
2231

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

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

4✔
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
}
×
2271

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

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

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

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

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

2293
  return FALSE;
2294
}
2295

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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 ||
2373
      na == NULL) {
12✔
2374
    errno = EINVAL;
12✔
2375
    return NULL;
2✔
2376
  }
2✔
2377

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

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

9✔
2388
  return res;
2389
}
9✔
2390

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 ||
2395
      na == NULL) {
4✔
2396
    errno = EINVAL;
4✔
2397
    return NULL;
2✔
2398
  }
2✔
2399

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

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

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

2417
  return res;
2418
}
2419

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

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

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

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

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

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

2447
void pr_netaddr_set_sess_addrs(void) {
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));
1✔
2453
  have_sess_local_addr = TRUE;
1✔
2454

1✔
2455
  memset(&sess_remote_addr, 0, sizeof(sess_remote_addr));
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,
1✔
2459
    pr_netaddr_get_sockaddr(session.c->remote_addr));
1✔
2460

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

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

2471
  return FALSE;
2472
}
2473

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

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

9✔
2486
void pr_netaddr_clear_cache(void) {
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);
1✔
2490
    (void) pr_table_free(netaddr_iptab);
1✔
2491

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

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

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

1✔
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
}
2511

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

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

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);
2529
  netaddr_dnstab = pr_table_alloc(netaddr_pool, 0);
96✔
2530
}
96✔
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