Skip to content

Fix subnet mask computation in IpAddress::isWithinSubet - #800

Open
MarkRose wants to merge 1 commit into
sm0svx:masterfrom
MarkRose:fix-ipaddress-netmask-validation
Open

Fix subnet mask computation in IpAddress::isWithinSubet#800
MarkRose wants to merge 1 commit into
sm0svx:masterfrom
MarkRose:fix-ipaddress-netmask-validation

Conversation

@MarkRose

Copy link
Copy Markdown
Contributor

IpAddress::isWithinSubet() computed the netmask from the CIDR prefix
length using atoi() and pow(2.0, 32 - prefix), with no validation
that the prefix was a valid number in the 0-32 range:

  • A non-numeric prefix (e.g. "10.0.0.0/x") makes atoi() return 0,
    so pow(2.0, 32) overflows a uint32_t and the resulting mask
    collapses to 0.
  • An out-of-range prefix such as /33 or a negative value produces a
    negative exponent, which similarly yields a mask of 0 once cast to
    uint32_t (undefined behaviour on the out-of-range double-to-integer
    conversion).

A mask of 0 makes isWithinSubet() match every address, silently
turning an ALLOW_IP/subnet check into an "allow all" rule when the
configured prefix is malformed.

Replaced the computation with a small helper, parseNetmaskPrefix(),
that parses the prefix with strtol(), rejects anything outside 0-32
or with trailing garbage, and builds the mask with a plain integer
shift instead of floating point exponentiation. isWithinSubet() now
returns false (no match) for an invalid prefix instead of failing
open.

Co-Authored-By: Claude Opus 4.8 [email protected]


This PR also adds a unit test (IpAddressTest.cpp). It is auto-discovered and executed by the CTest suite proposed in #762 once that is merged; without that suite present the test file is inert and does not affect the build.

IpAddress::isWithinSubet() computed the netmask from the CIDR prefix
length using `atoi()` and `pow(2.0, 32 - prefix)`, with no validation
that the prefix was a valid number in the 0-32 range:

- A non-numeric prefix (e.g. "10.0.0.0/x") makes atoi() return 0,
  so pow(2.0, 32) overflows a uint32_t and the resulting mask
  collapses to 0.
- An out-of-range prefix such as /33 or a negative value produces a
  negative exponent, which similarly yields a mask of 0 once cast to
  uint32_t (undefined behaviour on the out-of-range double-to-integer
  conversion).

A mask of 0 makes isWithinSubet() match every address, silently
turning an ALLOW_IP/subnet check into an "allow all" rule when the
configured prefix is malformed.

Replaced the computation with a small helper, parseNetmaskPrefix(),
that parses the prefix with strtol(), rejects anything outside 0-32
or with trailing garbage, and builds the mask with a plain integer
shift instead of floating point exponentiation. isWithinSubet() now
returns false (no match) for an invalid prefix instead of failing
open.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
@MarkRose MarkRose closed this Jul 12, 2026
@MarkRose MarkRose reopened this Jul 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant