# CIDR Aggregator: Merge IPs and Ranges into CIDR Blocks

Merge IP addresses, ranges and CIDR blocks (any mix of IPv4 and IPv6, one per line, up to about 4,000 lines) into the smallest exact set of CIDR blocks: duplicates and contained blocks vanish, neighbours join. Exact mode never adds an address that was not listed; cover mode returns at most N blocks and reports exactly how many extra addresses they include. An optional exclude list removes ranges first. Returns the blocks with the entries that fed each one, counts in and out, lines that could not be read with the reason, and an export in plain list, nginx, iptables and ipset, nftables, AWS WAF IP set, Cloudflare list, Terraform or CSV form. No network lookups.

**Not for:** Looking up who owns an address (use ip_whois), or checking whether an address is inside a block (use cidr_contains).

- Tool id: `cidr-aggregate`
- Category: ip
- Execution: pure
- MCP tool `cidr_aggregate` at https://lookupowl.com/mcp
- REST `GET https://lookupowl.com/api/v1/tools/cidr-aggregate` (or POST a JSON body)
- OpenAPI: https://lookupowl.com/api/openapi.json

## Input

| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `entries` | string | yes |  | IPs, ranges or CIDRs, one per line, up to about 48,000 characters (roughly 4,000 lines; the web page takes far more in your browser, because the work runs there). Mix them freely: single addresses, CIDR blocks, ranges like 10.0.0.1-10.0.0.9, address plus netmask. IPv4 and IPv6 together are fine. Defanged text such as 10[.]0[.]0[.]1 is read too. max length 48000 |
| `exclude` | string | no | `""` | Ranges to remove from the result, one per line, in the same notations. max length 12000 |
| `mode` | "exact" \| "cover" | no | `"exact"` | exact: the smallest set of blocks that covers exactly the addresses you gave. cover: at most maxBlocks blocks, which may include addresses you did not list (the answer says how many). |
| `maxBlocks` | integer | no | `16` | cover mode only: the most blocks to return. min 1, max 1000 |
| `exportAs` | "list" \| "nginx" \| "iptables" \| "nftables" \| "aws-waf" \| "cloudflare" \| "terraform" \| "csv" | no | `"list"` | How to write the export: a plain list, nginx allow lines, iptables and ipset, an nftables set, an AWS WAF IP set (JSON), a Cloudflare list, a Terraform list or CSV. |

## Output

Results are wrapped in an envelope: `tool`, `version`, `requestId`, `data`, `summary`, `meta` (cache status, timing), `permalink`. `data` has these fields:

| Field | Type | Description |
|---|---|---|
| `mode` | "exact" \| "cover" |  |
| `in` | object |  |
| `out` | object |  |
| `overCoverage` | integer | Addresses in the output that were not in the input (capped at 2^53 - 1). Always 0 in exact mode. min -9007199254740991, max 9007199254740991 |
| `overCoverageDetail` | object | The same, split by family, with the IPv6 count as text. |
| `blocks` | object[] |  |
| `ignored` | object[] |  |
| `excluded` | object |  |
| `notes` | string[] | Plain-English notes about the result, for example when exclusions stopped cover mode from reaching the limit. |
| `unchanged` | boolean | True when the list was already the smallest exact set: nothing merged, dropped or cut. |
| `export` | object |  |

## Examples

### A mixed firewall list

```json
{"entries":"10.0.0.0/24\n10.0.1.0/24\n10.0.2.0/25\n10.0.2.128/25\n10.0.3.7\n10.0.3.0-10.0.3.255\n192.168.1.0/24\n192.168.1.64/26\n203.0.113.10\n203.0.113.11\n203.0.113.12\n203.0.113.13\n2001:db8::/33\n2001:db8:8000::/33\n198.51.100.0 255.255.255.0","exclude":"","mode":"exact","maxBlocks":16,"exportAs":"list"}
```

```bash
curl 'https://lookupowl.com/api/v1/tools/cidr-aggregate?entries=10.0.0.0%2F24%0A10.0.1.0%2F24%0A10.0.2.0%2F25%0A10.0.2.128%2F25%0A10.0.3.7%0A10.0.3.0-10.0.3.255%0A192.168.1.0%2F24%0A192.168.1.64%2F26%0A203.0.113.10%0A203.0.113.11%0A203.0.113.12%0A203.0.113.13%0A2001%3Adb8%3A%3A%2F33%0A2001%3Adb8%3A8000%3A%3A%2F33%0A198.51.100.0+255.255.255.0&exclude=&exportAs=list&maxBlocks=16&mode=exact'
```

Web page: https://lookupowl.com/cidr-aggregator?q=10.0.0.0%2F24%0A10.0.1.0%2F24%0A10.0.2.0%2F25%0A10.0.2.128%2F25%0A10.0.3.7%0A10.0.3.0-10.0.3.255%0A192.168.1.0%2F24%0A192.168.1.64%2F26%0A203.0.113.10%0A203.0.113.11%0A203.0.113.12%0A203.0.113.13%0A2001%3Adb8%3A%3A%2F33%0A2001%3Adb8%3A8000%3A%3A%2F33%0A198.51.100.0+255.255.255.0

### A block with a hole cut out of it

```json
{"entries":"10.0.0.0/22","exclude":"10.0.1.128/25","mode":"exact","maxBlocks":16,"exportAs":"nginx"}
```

```bash
curl 'https://lookupowl.com/api/v1/tools/cidr-aggregate?entries=10.0.0.0%2F22&exclude=10.0.1.128%2F25&exportAs=nginx&maxBlocks=16&mode=exact'
```

Web page: https://lookupowl.com/cidr-aggregator?q=10.0.0.0%2F22&exclude=10.0.1.128%2F25&exportAs=nginx

### Cover with at most three blocks

```json
{"entries":"10.0.0.0/24\n10.0.2.0/24\n10.1.0.0/24\n172.16.5.0/24","exclude":"","mode":"cover","maxBlocks":3,"exportAs":"list"}
```

```bash
curl 'https://lookupowl.com/api/v1/tools/cidr-aggregate?entries=10.0.0.0%2F24%0A10.0.2.0%2F24%0A10.1.0.0%2F24%0A172.16.5.0%2F24&exclude=&exportAs=list&maxBlocks=3&mode=cover'
```

Web page: https://lookupowl.com/cidr-aggregator?q=10.0.0.0%2F24%0A10.0.2.0%2F24%0A10.1.0.0%2F24%0A172.16.5.0%2F24&maxBlocks=3&mode=cover

## Web pages

- https://lookupowl.com/cidr-aggregator

## Limits and caching

- Cost: from 1 unit up, depending on the input (a registry lookup counts every upstream request); 1 unit for a cached result. Budgets are per network and published in the `RateLimit` response headers.
- Cache: results are kept for 86400 s.
- Timeout: 5 s.

## Related tools

- [IP in CIDR: Is This Address in That Block?](https://lookupowl.com/tools/cidr-contains.md): Check which IP addresses fall inside which CIDR blocks, and whether two lists of blocks overlap.
- [VLSM Subnet Planner: Split a Network into Subnets](https://lookupowl.com/tools/subnet-plan.md): Split a network into equal subnets or right-sized VLSM subnets for named host counts, and see what is left.
- [IP Subnet Calculator](https://lookupowl.com/tools/subnet-calculator.md): Network, broadcast, usable range, masks and exact host counts for any IPv4 or IPv6 subnet.
- [CIDR / IP Range Converter](https://lookupowl.com/tools/ip-range-convert.md): Turn CIDR blocks into first/last addresses, and IP ranges into the minimal list of CIDR blocks.
- [IP Address Converter](https://lookupowl.com/tools/ip-convert.md): Convert IP addresses to decimal, hex and binary, IPv4 to IPv6 forms, and pull the IPv4 out of an IPv6 address.

## Guide: CIDR aggregator

Paste a list of addresses, ranges and blocks and get the fewest CIDR blocks that cover exactly the same addresses.

### What the aggregator does

Firewall allow-lists, block-lists and route tables grow by copy and paste. Over a few years one list ends up with duplicates, a /24 next to the /25 that is already inside it, single addresses that could be one block, and ranges nobody wrote in CIDR form. This tool reads the whole mess and gives back the smallest set of CIDR blocks that covers the same addresses.

It reads one entry per line in any mix of notations: a single address such as `203.0.113.10`, a block such as `10.0.0.0/24`, a range such as `10.0.3.0-10.0.3.255`, an address with a netmask such as `198.51.100.0 255.255.255.0`, and IPv6 such as `2001:db8::/33`. Text that was defanged for safe sharing, like `10[.]0[.]0[.]1`, is read as the plain address.

Next to each result block you see how many entries fed it, and next to each entry you see the block it ended up in, so you can check the merge instead of trusting it.

### Exact merge never adds addresses

In exact mode the result covers the same addresses as your list, no more and no fewer. Overlapping and touching entries join, and a block is only ever replaced by blocks that hold exactly its addresses. That matters for a firewall: a merge that quietly lets in addresses you never listed is a security change, not a tidy-up.

> **Some tools get this wrong** Joining `192.168.1.0/24` and `192.168.2.0/24` into `192.168.0.0/23` is wrong, because a /23 starts at `192.168.0.0` and also holds `192.168.0.0/24`. The two blocks are neighbours but not siblings, so the exact answer stays two blocks.

| You paste | Exact result | Why |
|---|---|---|
| `10.0.0.0/25` and `10.0.0.128/25` | `10.0.0.0/24` | Two siblings join into their parent |
| `10.0.0.0/24` and `10.0.0.77` | `10.0.0.0/24` | The single address is already inside |
| `10.0.1.0/24` and `10.0.2.0/24` | Both stay | They touch, but no single block holds exactly them |
| `203.0.113.10` to `203.0.113.13` | `203.0.113.10/31`, `203.0.113.12/31` | Four addresses that do not line up on a /30 boundary |

### Exclusions and cover mode

The exclusion box removes ranges from the result. Allow `10.0.0.0/22` except `10.0.1.128/25` and you get `10.0.0.0/24`, `10.0.1.0/25` and `10.0.2.0/23`: the hole is cut out and the rest is written as the fewest blocks.

Cover mode is for when a short list matters more than precision. You choose the most blocks you can live with, and the tool joins the neighbours that add the fewest extra addresses until it is within your limit. It then says exactly how many addresses the list covers that you did not list. It never joins blocks across an address you excluded, and it treats IPv4 and IPv6 separately.

Read the extra-address count before you paste a cover result into a firewall. Four extra addresses in a /29 may be fine. Four million may not be.

### Ready for your platform

Under More options, pick the format of the export: a plain list, nginx `allow` lines, `ipset` and `iptables` commands, an `nftables` set, an AWS WAF IP set as JSON, a Cloudflare list, a Terraform list or CSV. The export holds only the merged blocks, written the way that platform expects them. Check the limits of your own platform before you load a long list, because they differ by product and plan.

### Where your list goes

With JavaScript on, the list is merged in your browser and nothing you paste is sent to us. Without JavaScript, the form sends the list to our server in the page address, which limits how long a list can be, and the server merges it. The API and the no-JavaScript form take about 4,000 lines (a 64 KB request). The browser takes up to 100,000. Our [privacy policy](https://lookupowl.com/privacy) has the details.

### Frequently asked questions

**What is CIDR aggregation?**

It is replacing a list of addresses and blocks with fewer blocks that cover the same addresses. It is also called route summarisation or supernetting when it is done for routing. The aim is a shorter list that is easier to read, cheaper to load and faster to match.

**Why did two neighbouring blocks not merge?**

Two blocks only join when they are siblings: the same size, next to each other, and together exactly one larger block. `10.0.1.0/24` and `10.0.2.0/24` are neighbours, but the /23 around the first one starts at `10.0.0.0`, so joining them would add `10.0.0.0/24`.

**What is the difference between exact and cover mode?**

Exact mode gives the smallest list that covers precisely your addresses. Cover mode gives at most the number of blocks you choose and may include addresses you did not list. It always tells you how many.

**Can I mix IPv4 and IPv6 in one list?**

Yes. The two families are merged separately and the result lists IPv4 first. The counts show each family on its own.

**What happens to lines that are not addresses?**

They are skipped, and the page lists each one with its line number and the reason, so you can fix it and merge again. The rest of the list is still merged.

**Is there a limit on the list?**

The browser merges up to 100,000 lines. REST and MCP calls take about 4,000 lines and answer with at most 5,000 blocks. Over the limit, split the list, merge each part and then merge the results again.
