Skip to content

Instantly share code, notes, and snippets.

@definiteIymaybe
Last active January 3, 2026 03:55
Show Gist options
  • Select an option

  • Save definiteIymaybe/8c15a865b27251c08831af3a3a37c7cd to your computer and use it in GitHub Desktop.

Select an option

Save definiteIymaybe/8c15a865b27251c08831af3a3a37c7cd to your computer and use it in GitHub Desktop.
CIDR to IP Range (Notion Formula)
/**
# CIDR to IP Range (Notion Formula)
A correct, integer-based CIDR to IP range converter implemented as a Notion formula.
Handles all IPv4 CIDR prefixes (`/0–/32`), avoids octet-based hacks, and defines explicit behavior for invalid input.
## Behavior
- Empty input → empty output
- Invalid IP address → empty output
- Missing or empty prefix (`10.0.0.1`, `10.0.0.1/`) → treated as `/32`
- Fractional prefix → floored (`/31.9` → `/31`)
- Prefix < 0, > 32, or non-numeric → empty output
- `/32` collapses to a single IP
- `/31` returns two IPs (raw CIDR semantics)
## Why integer-based
Octet-level CIDR calculations break for prefixes crossing octet boundaries (e.g. `/1`, `/9`, `/17`).
This formula converts IP addresses to 32-bit integers, applies CIDR math at the integer level, and converts results back to dotted notation.
## Example
| Input | Output |
|------------------|-------------------------------------|
| `10.0.0.10` | `10.0.0.10` |
| `10.0.0.0/24` | `10.0.0.0 → 10.0.0.255` |
| `10.0.0.10/1` | `0.0.0.0 → 127.255.255.255` |
| `10.0.0.0/well` | *(empty)* |
*/
/* =========================================
CIDR → IP / Range (Integer-Correct)
Supports /0–/32, quiet on empty input
========================================= */
lets(
/* ---------- Input ---------- */
raw, replaceAll(prop("IP Range CIDR"), " ", ""),
parts, raw.split("/"),
ip,
if(raw == "", "0.0.0.0", parts.at(0)),
prefixRaw,
if(
parts.length() > 1 and parts.at(1) != "",
toNumber(parts.at(1)),
32
),
prefix,
if(
format(toNumber(prefixRaw))==format(prefixRaw),
floor(
if(prefixRaw < 0, 0,
if(prefixRaw > 32, 32,
prefixRaw))
),
32
),
/* ---------- Octets ---------- */
octets, ip.split("."),
o1, toNumber(octets.at(0)),
o2, toNumber(octets.at(1)),
o3, toNumber(octets.at(2)),
o4, toNumber(octets.at(3)),
validIp,
raw != ""
and octets.length() == 4
and [o1, o2, o3, o4].every(
current >= 0 and current <= 255
),
/* ---------- IP → Integer ---------- */
ipInt,
o1 * pow(256, 3) +
o2 * pow(256, 2) +
o3 * 256 +
o4,
/* ---------- CIDR Math ---------- */
blockSize, pow(2, 32 - prefix),
networkInt,
floor(ipInt / blockSize) * blockSize,
broadcastInt,
networkInt + blockSize - 1,
/* ---------- Integer → IP ---------- */
n1, floor(networkInt / pow(256,3)) % 256,
n2, floor(networkInt / pow(256,2)) % 256,
n3, floor(networkInt / 256) % 256,
n4, networkInt % 256,
b1, floor(broadcastInt / pow(256,3)) % 256,
b2, floor(broadcastInt / pow(256,2)) % 256,
b3, floor(broadcastInt / 256) % 256,
b4, broadcastInt % 256,
net,
format(n1) + "." + format(n2) + "." +
format(n3) + "." + format(n4),
brd,
format(b1) + "." + format(b2) + "." +
format(b3) + "." + format(b4),
/* ---------- Output ---------- */
if(
not validIp,
"",
if(
prefix == 32,
net,
net + " → " + brd
)
)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment