# Subnet Calculator

> Free online CIDR calculator with full IPv6 support: network, broadcast, host range and counts, netmask in dotted, hex or wildcard form, plus a subnet splitter.

- URL: https://bytescope.dev/en/subnet-calculator/
- Locale: en · Also: [ja](https://bytescope.dev/ja/subnet-calculator.md) · [zh-Hant](https://bytescope.dev/zh-Hant/subnet-calculator.md)
- Runs: Everything runs locally in your browser — nothing is uploaded.
- Requires: Any modern browser (Chrome, Edge, Firefox, Safari), desktop and mobile.
- Updated: 2026-09-08

## What it does

Type anything that looks like a network and this calculator works out the rest: `192.168.1.0/24`, a bare address, `10.0.0.1/255.255.255.0`, `10.0.0.1 255.255.255.0`, a hex mask like `/0xffffff00`, or an IPv6 prefix in any of its legal spellings. You get the network address, the broadcast address, the first and last usable host, the total address count and the usable host count, the netmask in every notation, and what the address actually is — private, loopback, link-local, multicast, documentation, CGNAT — checked against the 32 special-purpose ranges the RFCs define rather than the old class A/B/C story.

IPv6 is a first-class citizen here, not a bolted-on afterthought: most subnet calculators still stop at IPv4. Prefixes are normalised to RFC 5952 form (lowercase hex, a single `::` at the longest run of zeros), `::ffff:192.0.2.1` renders in mixed notation, and every count is an exact big integer — a /48 really is 1,208,925,819,614,629,174,706,176 addresses, not `1.2e24`. That makes the questions you actually ask while planning answerable: how many /64s a /56 or a /48 gives you, whether a prefix is ULA (`fc00::/7`) or globally routable, where a link-local `fe80::/10` address sits.

The subnet splitter carves a parent prefix into equal children — a /24 into four /26s, a /48 into 256 /56s — and lists each child's network, range and broadcast. It pages instead of materialising rows, so asking for a /8 in /30s answers instantly: the total (4,194,304) comes from arithmetic and only the page you are looking at gets built. Masks convert both directions: hand it a prefix length and get dotted, hex and wildcard forms back; hand it `255.255.254.0` or the wildcard `0.0.1.255` and get the prefix length. Non-contiguous masks like `255.0.255.0` are refused with a reason, because they are not valid CIDR.

Everything is computed in your browser — the page is a static file and there is no API behind it. That matters more than the usual privacy boilerplate: your internal addressing plan is reconnaissance material, and pasting `10.42.7.0/23 — payment gateways` into a form that posts to someone's server hands a stranger a map of your network. Bad input never breaks the page either; it names the problem instead — a leading zero in `192.168.01.1`, two `::` in one IPv6 address, a host bit set inside something you called a network — so you can fix the input rather than guess.

## Limits

Does not look up who owns an address or scan a network; it does IPv4/IPv6 CIDR arithmetic.

## Machine output

Copy JSON copies an envelope `{ tool, url, generatedAt, userAgentHint, result }`. `tool` is `"subnet-calculator"`; `result` is the on-screen CIDR analysis below. Split-children tables are omitted. `totalAddresses` and `usableHosts` are decimal digit strings, not JSON numbers, because IPv6 counts can exceed Number.MAX_SAFE_INTEGER.

- `version` (number | null) — `4` or `6`. `null` = not analysed.
- `input` (string | null) — Trimmed text the user typed. `null` = not analysed.
- `address` (string | null) — Canonical address as typed (host bits kept). `null` = not analysed.
- `mixedNotation` (string | null) — RFC 5952 mixed form for IPv4-mapped addresses (e.g. `::ffff:192.0.2.1`). `null` = not IPv4-mapped or not analysed.
- `cidr` (string | null) — Canonical `network/prefix`. `null` = not analysed.
- `network` (string | null) — Network address (host bits cleared). `null` = not analysed.
- `firstHost` (string | null) — First assignable host. `null` = not analysed.
- `lastHost` (string | null) — Last assignable host. `null` = not analysed.
- `broadcast` (string | null) — IPv4 directed broadcast. `null` = IPv6 (IPv6 has no broadcast) or not analysed.
- `totalAddresses` (string | null) — Address count as a decimal digit string. `null` = not analysed.
- `usableHosts` (string | null) — Usable host count as a decimal digit string. `null` = not analysed.
- `hostBitsSet` (boolean | null) — Typed address had host bits set. `null` = not analysed.
- `isPointToPoint` (boolean | null) — `/31` or `/127`. `null` = not analysed.
- `isSingleAddress` (boolean | null) — `/32` or `/128`. `null` = not analysed.
- `prefixLength` (number | null) — Prefix length. `null` = not analysed.
- `netmaskDotted` (string | null) — IPv4 dotted netmask. `null` = IPv6 or not analysed.
- `netmaskHex` (string | null) — `0x`-prefixed hex mask. `null` = not analysed.
- `wildcard` (string | null) — Wildcard / host mask, same-family text. `null` = not analysed.
- `classificationName` (string | null) — Special-use range label (e.g. `"Private-Use"`). `null` = no matching range (ordinary / unassigned) or not analysed.
- `classificationRfc` (string | null) — Defining RFC (e.g. `"RFC 1918"`). `null` = no matching range or not analysed.

## FAQ

### What is the broadcast address of an IPv6 subnet?

There isn't one. RFC 4291 removed broadcast from IPv6 entirely and replaced it with the all-nodes multicast group `ff02::1`; the last address on a link is just another usable interface address. This calculator leaves the broadcast field empty for every IPv6 prefix. If another tool shows you an IPv6 "broadcast address", it is showing you the last address in the range under a name that does not exist.

### Why does a /31 have 2 usable hosts and a /32 have 1?

Because RFC 3021 says so for the /31, and because a /32 is a single host route. A /31 on a point-to-point link needs neither a network nor a broadcast address — the two ends simply use the two addresses — which is why it is the standard way to number router-to-router links and saves two addresses per link over a /30. Below that, a /32 is one address: a loopback, a VIP, or a firewall rule matching exactly one host. The textbook `2^host bits − 2` formula returns 0 for both, so the tool special-cases them instead of printing a meaningless number.

### Why does an IPv6 /64 lose only one address instead of two?

The one it loses is the Subnet-Router anycast address — the all-zeros interface id, so `2001:db8::` in `2001:db8::/64` — which RFC 4291 reserves for the routers on the link. There is no broadcast address to reserve at the other end, so nothing is subtracted there. In practice the count is academic: a /64 has 18,446,744,073,709,551,615 usable addresses, and you should hand out a /64 per link anyway because SLAAC requires it.

### Can I split a /8 into /30s without hanging my browser?

Yes. The splitter derives the total count arithmetically — 4,194,304 subnets — and builds only the rows you are looking at, 256 at a time by default, so you can page through the list or jump straight to an offset. Nothing is materialised in memory, which makes the absurd requests exactly as fast as the sensible ones.

### What is 100.64.0.0/10, and why can't I forward a port to it?

That range is CGNAT space (RFC 6598): carrier-grade NAT, the addresses an ISP hands out once it no longer has a public IPv4 address per subscriber. If your router's WAN address sits in `100.64.0.0/10`, it is behind your ISP's NAT as well as your own, so inbound port forwarding cannot work — there is no public address that reaches you. The tool labels those addresses CGNAT rather than "public", which is usually the line that makes the situation click. The ways out are a real public IPv4 address from your ISP, IPv6 (CGNAT deployments usually offer it), or an outbound tunnel.

### Why is `fe80::1%eth0` rejected?

Because of the `%eth0`. That is a zone id, and it identifies an interface on one particular machine rather than anything about the address itself: `fe80::1%eth0` and `fe80::1%wlan0` are different destinations on your laptop and mean nothing at all on mine, so a calculator cannot say anything true about the zone part. Drop it and paste `fe80::1` — or `fe80::/10` for the prefix — and everything else works normally.
