Networking

IP Range to CIDR: Build an Exact Allowlist

An exact IP range allowlist: Three CIDR blocks cover 192.0.2.40 through 192.0.2.95 exactly: .40/29 has 8 addresses, .48/28 has 16 and .64/27 has 32. A /25 would add 72 addresses.
Count every address in the set. The exact list includes .40 and .95 and excludes .39 and .96; a shorter list may change the policy.
Three CIDR blocks cover 192.0.2.40 through 192.0.2.95 exactly: .40/29 has 8 addresses, .48/28 has 16 and .64/27 has 32. A /25 would add 72 addresses.
Count every address in the set. The exact list includes .40 and .95 and excludes .39 and .96; a shorter list may change the policy.Original Boxvirt diagram. Documentation-address example; membership arithmetic does not apply a firewall rule. View full size ↗

The inclusive IPv4 range 192.0.2.40–192.0.2.95 contains 56 addresses. Its exact CIDR representation is three blocks:

192.0.2.40/29
192.0.2.48/28
192.0.2.64/27

A single /25 would be shorter to write, but would include 72 additional addresses. For an allowlist, that changes the policy. The goal is to cover the intended set, not merely find a prefix containing its first and last address.

This worked example uses the documentation range defined in RFC 5737. It does not represent a real customer allocation or a change to a firewall.

Start with an explicit, inclusive address range

Record the first and last address and confirm that both should be included. Also record what the list is for: a source group, destination group or some other policy object. An exact conversion does not prove that the requester owns the addresses or that every address should receive the same access.

In this example:

First included address: 192.0.2.40
Last included address:  192.0.2.95
Count: 95 − 40 + 1 = 56

The count includes every address in the set. It is not a count of assignable hosts in a newly configured subnet. Keeping those questions separate avoids silently dropping boundary addresses from a firewall object.

Fit aligned CIDR blocks without crossing the end

RFC 4632 describes CIDR prefix notation and its power-of-two address blocks. A valid block must also start at the corresponding boundary.

At .40, an eight-address /29 is aligned and spans .40–.47. A /28 cannot start at .40: the containing /28 begins at .32 and would include unwanted addresses. Continue from the next uncovered address, .48:

Exact blockIncluded rangeAddresses
192.0.2.40/29192.0.2.40–478
192.0.2.48/28192.0.2.48–6316
192.0.2.64/27192.0.2.64–9532
Total192.0.2.40–9556

Shortened range endings in the table refer to the final octet. There are no gaps between the blocks, no overlaps and no entries before .40 or after .95.

CIDR coverage counts every address in a prefix, including its network and broadcast values when those terms apply to a LAN. It does not apply the IPv4 host-count subtraction of two. A /32 can represent one exact address in an allowlist; a /31 represents two address matches even when the list is not configuring a point-to-point link.

Compare an exact list with tempting shortcuts

Here are three possible descriptions of the same intended range:

Proposed listAddresses matchedAddresses outside the request
The three exact blocks above560
192.0.2.32/27 and 192.0.2.64/27648: .32–.39
192.0.2.0/2512872: .0–.39 and .96–.127

The two-block shortcut looks close, but it still permits eight addresses that were not requested. The one-block shortcut is broader again. If a rule is supposed to grant exactly the original set, neither shortcut is an equivalent replacement.

Nor does writing 192.0.2.40/26 mean “start at .40 and take 64 addresses.” That input has host bits set; its containing network is 192.0.2.0/26. It both matches unwanted earlier addresses and misses .64–.95 from the request. Check the normalized prefix whenever a tool accepts an address with a mask.

Reproduce the result in the converter

Open the IP Range to CIDR converter, choose IP range → CIDR blocks, and enter .40 and .95 as full addresses:

  • First: 192.0.2.40.
  • Last, included: 192.0.2.95.

The output should contain 56 addresses and three blocks, matching the list at the top of this guide. Reverse-convert each block if you need to inspect its complete endpoints. The tool calculates address coverage locally; it does not scan the range, determine who controls it or apply a rule.

When reviewing an existing list, keep the full normalized CIDRs in the worksheet. An application may accept ranges directly or use different object types; check what it actually stores after the change rather than assuming that every input field has the same interpretation.

Verify the exact set independently

Python’s standard-library ipaddress module can summarize the range and check its membership. This example enumerates only the small worked range; it makes no network requests:

from ipaddress import ip_address, ip_network, summarize_address_range

first = ip_address("192.0.2.40")
last = ip_address("192.0.2.95")
blocks = list(summarize_address_range(first, last))
wanted = set(range(int(first), int(last) + 1))
actual = {int(address) for block in blocks for address in block}

assert actual == wanted
assert len(actual) == 56
assert [str(block) for block in blocks] == [
    "192.0.2.40/29", "192.0.2.48/28", "192.0.2.64/27"
]
assert not any(ip_address("192.0.2.39") in block for block in blocks)
assert not any(ip_address("192.0.2.96") in block for block in blocks)
print("Exact coverage checked:", [str(block) for block in blocks])

For large ranges, use prefix arithmetic rather than expanding billions of addresses into a set. The explicit enumeration here is a convenient independent check of these 56 addresses, not the converter’s implementation strategy.

Review the surrounding rule as well as the list

An address group is a reusable object, not an access policy by itself. The OPNsense alias documentation illustrates how lists of hosts and networks are used by rules. Match the object type to the intended address set and verify the resulting entries.

Then review the rule’s direction, interfaces, source and destination, ports, action and order. A precise source list does not make a broad destination rule appropriate. A separately existing rule can also allow traffic outside this list, so testing only the positive case is insufficient.

For this example, the address-membership checks are: .40 and .95 included; .39 and .96 excluded. At implementation time, pair them with a permitted application test and a negative test through the actual policy. This article verifies the mathematical set; no live rule or reachability test is claimed.

The MikroTik address-list guide explains the distinction between membership and policy. If the task is allocating new LANs instead, use the VLSM worked example and the IPv4 subnet calculator: address allocation and exact allowlist coverage have different acceptance checks.

KEEP EXPLORING

Related guides