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

proftpd / proftpd / 30135626854

25 Jul 2026 12:15AM UTC coverage: 93.034% (+0.6%) from 92.428%
30135626854

push

github

51363 of 55209 relevant lines covered (93.03%)

219.82 hits per line

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

90.53
/src/netacl.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 ACL routines */
25

26
#include "conf.h"
27

28
extern int ServerUseReverseDNS;
29

30
struct pr_netacl_t {
31
  pr_netacl_type_t type;
32
  const char *aclstr;
33

34
  char *pattern;
35
  int negated;
36
  const pr_netaddr_t *addr;
37
  unsigned int masklen;
38
};
39

40
static const char *trace_channel = "netacl";
41

42
pr_netacl_type_t pr_netacl_get_type(const pr_netacl_t *acl) {
43
  return acl->type;
17✔
44
}
17✔
45

46
/* Returns 1 if there was a positive match, -1 if there was a negative
47
 * match, -2 if there was an error, and zero if there was no match at all.
48
 */
49
int pr_netacl_match(const pr_netacl_t *acl, const pr_netaddr_t *addr) {
50
  pool *tmp_pool;
31✔
51
  int res = 0;
31✔
52

31✔
53
  if (acl == NULL ||
54
      addr == NULL) {
31✔
55
    errno = EINVAL;
31✔
56
    return -2;
3✔
57
  }
3✔
58

59
  tmp_pool = make_sub_pool(permanent_pool);
60

28✔
61
  switch (acl->type) {
62
    case PR_NETACL_TYPE_ALL:
28✔
63
      pr_trace_msg(trace_channel, 10, "addr '%s' matched rule 'ALL' ('%s')",
64
        pr_netaddr_get_ipstr(addr), pr_netacl_get_str(tmp_pool, acl));
1✔
65
      res = 1;
66
      break;
1✔
67

1✔
68
    case PR_NETACL_TYPE_NONE:
69
      pr_trace_msg(trace_channel, 10, "addr '%s' matched rule 'NONE'",
1✔
70
        pr_netaddr_get_ipstr(addr));
1✔
71
      res = -1;
72
      break;
1✔
73

1✔
74
    case PR_NETACL_TYPE_IPMASK:
75
      pr_trace_msg(trace_channel, 10,
3✔
76
        "checking addr '%s' against IP mask rule '%s'",
3✔
77
        pr_netaddr_get_ipstr(addr), acl->aclstr);
78

3✔
79
      if (pr_netaddr_ncmp(addr, acl->addr, acl->masklen) == 0) {
80
        pr_trace_msg(trace_channel, 10, "addr '%s' matched IP mask rule '%s'",
3✔
81
          pr_netaddr_get_ipstr(addr), acl->aclstr);
2✔
82

2✔
83
        if (acl->negated) {
84
          res = -1;
2✔
85

86
        } else {
87
          res = 1;
88
        }
1✔
89

90
      } else {
91
        pr_trace_msg(trace_channel, 10,
92
          "addr '%s' did NOT match IP mask rule '%s'",
1✔
93
          pr_netaddr_get_ipstr(addr), acl->aclstr);
94

1✔
95
        if (acl->negated) {
96
          res = 1;
1✔
97
        }
1✔
98
      }
99
      break;
100

101
    case PR_NETACL_TYPE_IPMATCH:
102
      pr_trace_msg(trace_channel, 10,
13✔
103
        "checking addr '%s' against IP address rule '%s'",
13✔
104
        pr_netaddr_get_ipstr(addr), acl->aclstr);
105

13✔
106
      if (pr_netaddr_cmp(addr, acl->addr) == 0) {
107
        pr_trace_msg(trace_channel, 10,
13✔
108
          "addr '%s' matched IP address rule '%s'",
11✔
109
          pr_netaddr_get_ipstr(addr), acl->aclstr);
110

11✔
111
        if (acl->negated) {
112
          res = -1;
11✔
113

114
        } else {
115
          res = 1;
116
        }
7✔
117

118
      } else {
119
        pr_trace_msg(trace_channel, 10,
120
          "addr '%s' did NOT match IP address rule '%s'",
2✔
121
          pr_netaddr_get_ipstr(addr), acl->aclstr);
122

2✔
123
        if (acl->negated) {
124
          res = 1;
2✔
125
        }
1✔
126
      }
127
      break;
128

129
    case PR_NETACL_TYPE_DNSMATCH:
130
      pr_trace_msg(trace_channel, 10,
3✔
131
        "checking addr '%s' against DNS name rule '%s'",
3✔
132
        pr_netaddr_get_dnsstr(addr), acl->pattern);
133

3✔
134
      if (strcmp(pr_netaddr_get_dnsstr(addr), acl->pattern) == 0) {
135
        pr_trace_msg(trace_channel, 10,
3✔
136
          "addr '%s' (%s) matched DNS name rule '%s'",
2✔
137
          pr_netaddr_get_ipstr(addr), pr_netaddr_get_dnsstr(addr),
138
          acl->aclstr);
139

2✔
140
        if (acl->negated) {
141
          res = -1;
2✔
142

143
        } else {
144
          res = 1;
145
        }
1✔
146

147
      } else {
148
        pr_trace_msg(trace_channel, 10,
149
          "addr '%s' (%s) did NOT match DNS name rule '%s'",
1✔
150
          pr_netaddr_get_ipstr(addr), pr_netaddr_get_dnsstr(addr),
151
          acl->aclstr);
152

1✔
153
        if (acl->negated) {
154
          res = 1;
1✔
155
        }
1✔
156
      }
157
      break;
158

159
    case PR_NETACL_TYPE_IPGLOB:
160
      pr_trace_msg(trace_channel, 10,
3✔
161
        "checking addr '%s' against IP glob rule '%s'",
3✔
162
        pr_netaddr_get_ipstr(addr), acl->aclstr);
163

3✔
164
      if (pr_netaddr_fnmatch(addr, acl->pattern,
165
          PR_NETADDR_MATCH_IP) == TRUE) {
3✔
166
        pr_trace_msg(trace_channel, 10,
167
          "addr '%s' matched IP glob rule '%s'",
2✔
168
          pr_netaddr_get_ipstr(addr), acl->aclstr);
169

2✔
170
        if (acl->negated) {
171
          res = -1;
2✔
172

173
        } else {
174
          res = 1;
175
        }
1✔
176

177
      } else {
178
        pr_trace_msg(trace_channel, 10,
179
          "addr '%s' did NOT match IP glob rule '%s'",
1✔
180
          pr_netaddr_get_ipstr(addr), acl->aclstr);
181

1✔
182
        if (acl->negated) {
183
          res = 1;
1✔
184
        }
1✔
185
      }
186
      break;
187

188
    case PR_NETACL_TYPE_DNSGLOB:
189
      if (ServerUseReverseDNS) {
4✔
190
        pr_trace_msg(trace_channel, 10,
4✔
191
          "checking addr '%s' against DNS glob rule '%s'",
3✔
192
          pr_netaddr_get_dnsstr(addr), acl->pattern);
193

3✔
194
        if (pr_netaddr_fnmatch(addr, acl->pattern,
195
            PR_NETADDR_MATCH_DNS) == TRUE) {
3✔
196
          pr_trace_msg(trace_channel, 10,
197
            "addr '%s' (%s) matched DNS glob rule '%s'",
2✔
198
            pr_netaddr_get_ipstr(addr), pr_netaddr_get_dnsstr(addr),
199
            acl->aclstr);
200

2✔
201
          if (acl->negated) {
202
            res = -1;
2✔
203

204
          } else {
205
            res = 1;
206
          }
1✔
207

208
        } else {
209
          pr_trace_msg(trace_channel, 10,
210
            "addr '%s' (%s) did NOT match DNS glob rule '%s'",
1✔
211
            pr_netaddr_get_ipstr(addr), pr_netaddr_get_dnsstr(addr),
212
            acl->aclstr);
213

1✔
214
          if (acl->negated) {
215
            res = 1;
1✔
216
          }
1✔
217
        }
218

219
      } else {
220
        pr_trace_msg(trace_channel, 10,
221
          "skipping comparing addr '%s' (%s) against DNS glob rule '%s' "
1✔
222
          "because UseReverseDNS is off", pr_netaddr_get_ipstr(addr),
223
          pr_netaddr_get_dnsstr(addr), acl->aclstr);
224
      }
1✔
225
      break;
226
  }
227

228
  destroy_pool(tmp_pool);
229
  return res;
28✔
230
}
28✔
231

232
pr_netacl_t *pr_netacl_create(pool *p, char *aclstr) {
233
  pr_netacl_t *acl;
101✔
234
  char *cp, *aclstr_dup;
101✔
235

101✔
236
  if (p == NULL ||
237
      aclstr == NULL) {
101✔
238
    errno = EINVAL;
101✔
239
    return NULL;
3✔
240
  }
3✔
241

242
  if (strlen(aclstr) == 0) {
243
    errno = EINVAL;
98✔
244
    return NULL;
1✔
245
  }
1✔
246

247
  /* Parse the given rule into a netacl object. */
248
  acl = pcalloc(p, sizeof(pr_netacl_t));
249

97✔
250
  aclstr_dup = pstrdup(p, aclstr);
251

97✔
252
  if (strncasecmp(aclstr, "all", 4) == 0) {
253
    aclstr_dup = pstrdup(p, "all");
97✔
254
    acl->type = PR_NETACL_TYPE_ALL;
13✔
255

13✔
256
  } else if (strncasecmp(aclstr, "none", 5) == 0) {
257
    aclstr_dup = pstrdup(p, "none");
84✔
258
    acl->type = PR_NETACL_TYPE_NONE;
4✔
259

4✔
260
  } else if ((cp = strchr(aclstr, '/')) != NULL) {
261
    char *tmp;
80✔
262

29✔
263
    acl->type = PR_NETACL_TYPE_IPMASK;
264
    *cp = '\0';
29✔
265

29✔
266
    /* Check if the given rule is negated. */
267
    if (*aclstr == '!') {
268
      acl->negated = TRUE;
29✔
269
      aclstr++;
4✔
270
    }
4✔
271

272
    /* We have some type of IP/mask, either IPv4 or IPv6.  We know that colons
273
     * will only appear in IPv6 addresses, so...
274
     */
275

276
    if (strspn(aclstr, "0123456789ABCDEFabcdef.:") != strlen(aclstr)) {
277
      errno = EINVAL;
29✔
278
      return NULL;
1✔
279
    }
7✔
280

281
    acl->addr = pr_netaddr_get_addr(p, aclstr, NULL);
282
    if (acl->addr == NULL) {
28✔
283
      return NULL;
28✔
284
    }
285

286
    /* Determine what the given bitmask is. */
287
    acl->masklen = strtol(cp + 1, &tmp, 10);
288

27✔
289
    if (tmp && *tmp) {
290
      /* Invalid bitmask syntax. */
27✔
291
      errno = EINVAL;
292
      return NULL;
1✔
293
    }
1✔
294

295
    *cp = '/';
296

26✔
297
    /* Make sure the given mask length is appropriate for the address. */
298
    switch (pr_netaddr_get_family(acl->addr)) {
299
      case AF_INET: {
26✔
300
        /* Make sure that the given number of bits is not more than supported
16✔
301
         * for IPv4 addresses (32).
302
         */
303
        if (acl->masklen > 32) {
304
          errno = EINVAL;
16✔
305
          return NULL;
2✔
306
        }
2✔
307

308
        break;
309
      }
310

311
#ifdef PR_USE_IPV6
312
      case AF_INET6: {
313
        if (pr_netaddr_use_ipv6()) {
10✔
314
          if (acl->masklen > 128) {
10✔
315
            errno = EINVAL;
10✔
316
            return NULL;
2✔
317
          }
2✔
318

319
          if (pr_netaddr_is_v4mappedv6(acl->addr) == TRUE &&
320
              acl->masklen > 32) {
8✔
321
            /* The admin may be trying to use IPv6-style masks on IPv4-mapped
3✔
322
             * IPv6 addresses, which of course will not work as expected.
323
             * If the mask is 32 bits or more, warn the admin.
324
             */
325
            pr_log_pri(PR_LOG_WARNING, "warning: possibly using IPv6-style netmask on IPv4-mapped IPv6 address, which will not work as expected");
326
            pr_trace_msg(trace_channel, 1, "possibly using IPv6-style netmask on IPv4-mapped IPv6 address (%s), which will not work as expected", aclstr);
3✔
327

3✔
328
            break;
329
          }
3✔
330
        }
331
      }
332
#endif /* PR_USE_IPV6 */
333

334
      default:
335
        break;
336
    }
337

338
#ifdef PR_USE_IPV6
339
  } else if (pr_netaddr_use_ipv6() &&
340
             strspn(aclstr, "0123456789ABCDEFabcdef.:!") != strlen(aclstr)) {
51✔
341
#else
51✔
342
  } else if (strspn(aclstr, "0123456789.!") != strlen(aclstr)) {
343
#endif /* PR_USE_IPV6 */
344

345
    /* Check if the given rule is negated. */
346
    if (*aclstr == '!') {
347
      acl->negated = TRUE;
16✔
348
      aclstr++;
6✔
349
    }
6✔
350

351
    /* If there are any glob characters (e.g. '{', '[', '*', or '?'), or if the
352
     * first character is a '.', then treat the rule as a glob.
353
     */
354
    if (strpbrk(aclstr, "{[*?")) {
355
      register unsigned int i;
16✔
356
      size_t aclstr_len = strlen(aclstr);
5✔
357
      pr_netacl_type_t netacl_type = PR_NETACL_TYPE_IPGLOB;
5✔
358

5✔
359
      /* Is this a DNS glob, or an IP address glob?  To find out, see if there
360
       * are any non-IP characters (i.e. alphabetical characters, taking IPv6
361
       * into account).
362
       */
363
      for (i = 0; i < aclstr_len; i++) {
364
        if (PR_ISALPHA(aclstr[i])) {
13✔
365
#ifdef PR_USE_IPV6
12✔
366
          if (pr_netaddr_use_ipv6()) {
367
            if (aclstr[i] == 'A' || aclstr[i] == 'a' ||
5✔
368
                aclstr[i] == 'B' || aclstr[i] == 'b' ||
5✔
369
                aclstr[i] == 'C' || aclstr[i] == 'c' ||
5✔
370
                aclstr[i] == 'D' || aclstr[i] == 'd' ||
5✔
371
                aclstr[i] == 'E' || aclstr[i] == 'e' ||
5✔
372
                aclstr[i] == 'F' || aclstr[i] == 'f') {
5✔
373
              continue;
5✔
374
            }
1✔
375

376
            netacl_type = PR_NETACL_TYPE_DNSGLOB;
377
            break;
378
          }
379

380
          netacl_type = PR_NETACL_TYPE_DNSGLOB;
381
          break;
382
#else
383
          netacl_type = PR_NETACL_TYPE_DNSGLOB;
384
          break;
385
#endif /* PR_USE_IPV6 */
386
        }
387
      }
388

389
      acl->type = netacl_type;
390
      acl->pattern = pstrdup(p, aclstr);
5✔
391

5✔
392
    } else if (*aclstr == '.') {
393
      acl->type = PR_NETACL_TYPE_DNSGLOB;
11✔
394
      acl->pattern = pstrcat(p, "*", aclstr, NULL);
3✔
395

3✔
396
    } else {
397
      acl->type = PR_NETACL_TYPE_DNSMATCH;
398
      acl->pattern = pstrdup(p, aclstr);
8✔
399
    }
8✔
400

401
  } else if (strchr(aclstr, '.') == NULL) {
402
    int use_glob = FALSE, use_dns = FALSE;
35✔
403

2✔
404
    /* Is this a DNS glob, DNS match, or an IPv6 glob/match? */
405

406
    /* Check if the given rule is negated. */
407
    if (*aclstr == '!') {
408
      acl->negated = TRUE;
2✔
409
      aclstr++;
1✔
410
    }
1✔
411

412
    /* If there are any glob characters (e.g. '{', '[', '*', or '?'), or if the
413
     * first character is a '.', then treat the rule as a glob.
414
     */
415
    if (strpbrk(aclstr, "{[*?")) {
416
      use_glob = TRUE;
2✔
417
    }
×
418

419
    /* IPv6 addresses use colons, thus if we do not see any, it's a good
420
     * bet that this is a DNS glob/match.
421
     */
422
    if (strchr(aclstr, ':') == NULL) {
423
      use_dns = TRUE;
2✔
424

425
    } else {
426
#ifdef PR_USE_IPV6
427
      if (pr_netaddr_use_ipv6() == FALSE) {
428
        pr_trace_msg(trace_channel, 1, "possibly using IPv6 %s '%s' when "
2✔
429
          "IPv6 support is disabled, which will not work as expected",
×
430
          use_glob ? "glob" : "match", aclstr);
431
        pr_log_pri(PR_LOG_WARNING, "warning: possibly using IPv6 %s '%s' when "
432
          "IPv6 support is disabled, which will not work as expected",
×
433
          use_glob ? "glob" : "match", aclstr);
434
      }
435
#else
436
      pr_trace_msg(trace_channel, 1, "possibly using IPv6 %s '%s' when "
437
        "IPv6 support is disabled, which will not work as expected",
438
        use_glob ? "glob" : "match", aclstr);
439
      pr_log_pri(PR_LOG_WARNING, "warning: possibly using IPv6 %s '%s' when "
440
        "IPv6 support is disabled, which will not work as expected",
441
        use_glob ? "glob" : "match", aclstr);
442
#endif /* PR_USE_IPV6 */
443
    }
444

445
    if (use_dns == TRUE) {
446
      acl->pattern = pstrdup(p, aclstr);
×
447
      acl->type = use_glob ? PR_NETACL_TYPE_DNSGLOB : PR_NETACL_TYPE_DNSMATCH;
×
448

×
449
    } else {
450
      acl->addr = pr_netaddr_get_addr(p, aclstr, NULL);
451
      if (acl->addr == NULL) {
2✔
452
        int xerrno = errno;
2✔
453

×
454
        pr_trace_msg(trace_channel, 3, "unable to resolve '%s': %s", aclstr,
455
          strerror(xerrno));
×
456

457
        errno = xerrno;
458
        return NULL;
×
459
      }
×
460

461
      acl->pattern = pstrdup(p, aclstr);
462
      acl->type = use_glob ? PR_NETACL_TYPE_IPGLOB : PR_NETACL_TYPE_IPMATCH;
2✔
463
    }
4✔
464

465
  } else {
466

467
    /* Check if the given rule is negated. */
468
    if (*aclstr == '!') {
469
      acl->negated = TRUE;
33✔
470
      aclstr++;
12✔
471
    }
12✔
472

473
    /* If the last character is a '.', then treat the rule as an IP glob. */
474
    if (aclstr[strlen(aclstr)-1] == '.') {
475
      acl->type = PR_NETACL_TYPE_IPGLOB;
33✔
476
      acl->pattern = pstrcat(p, aclstr, "*", NULL);
6✔
477

6✔
478
    } else {
479
      register unsigned int i;
480
      int use_glob = FALSE, use_dns = FALSE;
27✔
481
      size_t aclstr_len;
27✔
482

27✔
483
      /* Is this a DNS glob, DNS match, IP glob, or IP match?
484
       *
485
       * First, check for any glob characters.  After that, determine whether
486
       * it's a DNS or IP type ACL.
487
       */
488

489
      /* If there are any glob characters (e.g. '{', '[', '*', or '?'), or
490
       * if the first character is a '.', then treat the rule as a glob.
491
       */
492
      use_glob = (strpbrk(aclstr, "{[*?") != NULL);
493

27✔
494
      aclstr_len = strlen(aclstr);
495
      for (i = 0; i < aclstr_len; i++) {
27✔
496
        if (PR_ISALPHA(aclstr[i])) {
273✔
497
#ifdef PR_USE_IPV6
246✔
498
          if (pr_netaddr_use_ipv6()) {
499
            if (aclstr[i] == 'A' || aclstr[i] == 'a' ||
×
500
                aclstr[i] == 'B' || aclstr[i] == 'b' ||
×
501
                aclstr[i] == 'C' || aclstr[i] == 'c' ||
×
502
                aclstr[i] == 'D' || aclstr[i] == 'd' ||
×
503
                aclstr[i] == 'E' || aclstr[i] == 'e' ||
×
504
                aclstr[i] == 'F' || aclstr[i] == 'f') {
×
505
              continue;
×
506
            }
×
507

508
            use_dns = TRUE;
509
            break;
510
          }
511

512
          use_dns = TRUE;
513
          break;
514
#else
515
          use_dns = TRUE;
516
          break;
517
#endif /* PR_USE_IPV6 */
518
        }
519
      }
520

521
      if (!use_dns) {
522
        acl->type = use_glob ? PR_NETACL_TYPE_IPGLOB : PR_NETACL_TYPE_IPMATCH;
27✔
523
        acl->addr = pr_netaddr_get_addr(p, aclstr, NULL);
27✔
524
        if (acl->addr == NULL) {
27✔
525
          return NULL;
27✔
526
        }
527

528
      } else {
529
        if (use_glob) {
530
          acl->type = PR_NETACL_TYPE_DNSGLOB;
×
531
          acl->pattern = pstrdup(p, aclstr);
×
532

×
533
        } else if (*aclstr == '.') {
534
          acl->type = PR_NETACL_TYPE_DNSGLOB;
×
535
          acl->pattern = pstrcat(p, "*", aclstr, NULL);
×
536

×
537
        } else {
538
          acl->type = PR_NETACL_TYPE_DNSMATCH;
539
          acl->pattern = pstrdup(p, aclstr);
×
540
        }
×
541
      }
542
    }
543
  }
544

545
  acl->aclstr = aclstr_dup;
546
  return acl;
88✔
547
}
88✔
548

549
pr_netacl_t *pr_netacl_dup(pool *p, const pr_netacl_t *acl) {
550
  pr_netacl_t *acl2;
23✔
551

23✔
552
  if (p == NULL ||
553
      acl == NULL) {
23✔
554
    errno = EINVAL;
23✔
555
    return NULL;
3✔
556
  }
3✔
557

558
  acl2 = pcalloc(p, sizeof(pr_netacl_t));
559

20✔
560
  /* A simple memcpy(3) won't suffice; we need a deep copy. */
561
  acl2->type = acl->type;
562

20✔
563
  if (acl->pattern != NULL) {
564
    acl2->pattern = pstrdup(p, acl->pattern);
20✔
565
  }
×
566

567
  acl2->negated = acl->negated;
568

20✔
569
  if (acl->addr != NULL) {
570
    pr_netaddr_t *addr;
20✔
571

13✔
572
    addr = pr_netaddr_alloc(p);
573
    pr_netaddr_set_family(addr, pr_netaddr_get_family(acl->addr));
13✔
574
    pr_netaddr_set_sockaddr(addr, pr_netaddr_get_sockaddr(acl->addr));
13✔
575

13✔
576
    acl2->addr = addr;
577
  }
13✔
578

579
  acl2->masklen = acl->masklen;
580

20✔
581
  if (acl->aclstr != NULL) {
582
    acl2->aclstr = pstrdup(p, acl->aclstr);
20✔
583
  }
20✔
584

585
  return acl2;
586
}
587

588
int pr_netacl_get_negated(const pr_netacl_t *acl) {
589
  if (acl == NULL) {
3✔
590
    errno = EINVAL;
3✔
591
    return -1;
1✔
592
  }
1✔
593

594
  return acl->negated;
595
}
2✔
596

597
const char *pr_netacl_get_str2(pool *p, const pr_netacl_t *acl, int flags) {
598
  char *res = "";
48✔
599

48✔
600
  if (p == NULL ||
601
      acl == NULL) {
48✔
602
    errno = EINVAL;
48✔
603
    return NULL;
6✔
604
  }
6✔
605

606
  switch (acl->type) {
607
    case PR_NETACL_TYPE_ALL:
42✔
608
      res = pstrcat(p, res, acl->aclstr, NULL);
7✔
609
      if (!(flags & PR_NETACL_FL_STR_NO_DESC)) {
7✔
610
        res = pstrcat(p, res, " <all>", NULL);
7✔
611
      }
5✔
612
      return res;
613

614
    case PR_NETACL_TYPE_NONE:
615
      res = pstrcat(p, res, acl->aclstr, NULL);
2✔
616
      if (!(flags & PR_NETACL_FL_STR_NO_DESC)) {
2✔
617
        res = pstrcat(p, res, " <none>", NULL);
2✔
618
      }
1✔
619
      return res;
620

621
    case PR_NETACL_TYPE_IPMASK: {
622
      res = pstrcat(p, res, acl->aclstr, NULL);
14✔
623

14✔
624
      if (!(flags & PR_NETACL_FL_STR_NO_DESC)) {
625
        char masklenstr[64];
14✔
626

7✔
627
        memset(masklenstr, '\0', sizeof(masklenstr));
628
        pr_snprintf(masklenstr, sizeof(masklenstr)-1, "%u", acl->masklen);
7✔
629
        res = pstrcat(p, res, " <IP address mask, ", masklenstr, "-bit mask",
7✔
630
          NULL);
7✔
631
      }
632
      break;
633
    }
634

635
    case PR_NETACL_TYPE_IPMATCH:
636
      res = pstrcat(p, res, acl->aclstr, NULL);
13✔
637
      if (!(flags & PR_NETACL_FL_STR_NO_DESC)) {
13✔
638
        res = pstrcat(p, res, " <IP address match", NULL);
13✔
639
      }
11✔
640
      break;
641

642
    case PR_NETACL_TYPE_DNSMATCH:
643
      res = pstrcat(p, res, acl->aclstr, NULL);
2✔
644
      if (!(flags & PR_NETACL_FL_STR_NO_DESC)) {
2✔
645
        res = pstrcat(p, res, " <DNS hostname match", NULL);
2✔
646
      }
1✔
647
      break;
648

649
    case PR_NETACL_TYPE_IPGLOB:
650
      res = pstrcat(p, res, acl->pattern, NULL);
2✔
651
      if (!(flags & PR_NETACL_FL_STR_NO_DESC)) {
2✔
652
        res = pstrcat(p, res, " <IP address glob", NULL);
2✔
653
      }
1✔
654
      break;
655

656
    case PR_NETACL_TYPE_DNSGLOB:
657
      res = pstrcat(p, res, acl->pattern, NULL);
2✔
658
      if (!(flags & PR_NETACL_FL_STR_NO_DESC)) {
2✔
659
        res = pstrcat(p, res, " <DNS hostname glob", NULL);
2✔
660
      }
1✔
661
      break;
662
  }
663

664
  if (!(flags & PR_NETACL_FL_STR_NO_DESC)) {
665
    if (!acl->negated) {
33✔
666
      res = pstrcat(p, res, ">", NULL);
21✔
667

16✔
668
    } else {
669
      res = pstrcat(p, res, ", inverted>", NULL);
670
    }
5✔
671
  }
672

673
  return res;
674
}
675

676
const char *pr_netacl_get_str(pool *p, const pr_netacl_t *acl) {
677
  return pr_netacl_get_str2(p, acl, 0);
30✔
678
}
30✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc