Project

General

Profile

Actions

Bug #16691

open

Title: sanitize_ipaddr() incorrectly expands bare IPv4 addresses ending in .0 to /24 subnets

Added by Ashley R. Thomas 1 day ago.

Status:
New
Priority:
Normal
Assignee:
-
Category:
pfBlockerNG
Target version:
-
Start date:
Due date:
% Done:

0%

Estimated time:
Plus Target Version:
Affected Version:
Affected Plus Version:
Affected Architecture:
All

Description

When pfBlockerNG processes an upstream IP feed containing a bare IPv4 address whose fourth octet is `0` (e.g., `N.N.N.0` with no CIDR notation), the `sanitize_ipaddr()` function automatically appends a `/24` mask. This converts a single host entry into a 256-address subnet block.

Upstream feed publishers such as CINS Army (`ci-badguys.txt`) publish lists of individual host IPv4 addresses. These lists do not document any convention where a trailing `.0` should be interpreted as a `/24` range, and an address ending in `.0` is a valid host address — particularly within larger allocations (e.g., a cloud provider's `/20` range, where `N.N.N.0` is simply a host like any other).

The result is that pfBlockerNG silently blocks an entire /24 subnet when the upstream feed intended to flag only a single host. This has caused a legitimate cloud-hosted service to become unreachable from a pfSense-protected network because a single flagged IP on the same cloud provider subnet triggered a /24 block covering the service's IP as well.

  1. Steps to Reproduce

1. Subscribe to an IP feed that contains a bare IPv4 address ending in `.0` with no CIDR mask (e.g., CINS Army `ci-badguys.txt`).
2. Allow pfBlockerNG to process and apply the feed.
3. Observe that the address is expanded to a `/24` block in `/var/db/pfblockerng/deny/<feed>_v4.txt`.
4. Any legitimate host within that /24 range is now blocked, despite only one address appearing in the upstream list.

  1. Root Cause

In `pfblockerng.inc`, function `sanitize_ipaddr()` (lines ~3605–3662):

- Line ~3621: Checks whether the fourth octet is `0` AND no CIDR mask is present.
- Line ~3622: Automatically sets `$mask = 24`.
- Line ~3659: Returns the address as `N.N.N.0/24`.

```php
if ($key 3) {
// If mask is not defined and 4th octet is '0', set mask to '24'
if ($octet 0 && empty($mask)) {
$mask = 24;
}
}
```

Reference: [pfblockerng.inc line 3622 on GitHub](https://github.com/pfsense/FreeBSD-ports/blob/f4e18ffa0e4d72d9346cbb86f85c2c8cb631c444/net/pfSense-pkg-pfBlockerNG-devel/files/usr/local/pkg/pfblockerng/pfblockerng.inc#L3622)

  1. Expected Behavior

A bare IPv4 address with no CIDR notation should be treated as a single host (`/32`), regardless of its fourth octet value. pfBlockerNG should not reinterpret upstream feed entries beyond the specification provided by the feed publisher. If no mask is present, the default should be `/32`.

  1. Illustrative Fix

In `sanitize_ipaddr()`, when no CIDR mask is provided, default to `/32` for all bare IP addresses rather than inferring `/24` from a fourth octet of `0`:

```php
if ($key == 3) {
if (empty($mask)) {
$mask = 32;
}
}
```

  1. Additional Context

- The CINS Army feed is defined in `pfblockerng_feeds.json` (lines 71–75, header `CINS_army`), materialized as the `CINS_army_v4` file prefix. ([GitHub link](https://github.com/pfsense/FreeBSD-ports/blob/f4e18ffa0e4d72d9346cbb86f85c2c8cb631c444/net/pfSense-pkg-pfBlockerNG-devel/files/usr/local/www/pfblockerng/pfblockerng_feeds.json#L71))
- This behavior applies to any feed (processed by the referenced pfBlockerNG code path) containing bare `.0` addresses, not just CINS Army.
- Cloud providers commonly allocate IPs from large CIDR blocks (e.g., /20 or larger), making `.0` addresses routine host assignments rather than subnet boundaries.

  1. Environment

- pfSense CE (current release)
- pfBlockerNG-devel (current version)

No data to display

Actions

Also available in: Atom PDF