Recently I answered a question on StackOverflow regarding IP addressing. Basically the question was

"How can I specify subnets containing the range 154.100.0.0 - 154.109.255.255 in the smallest way possible?"

### Quick answer

Play with a subnetting calculator such as http://www.subnet-calculator.com/ and http://jodies.de/ipcalc to break it up into three subnets

```
154.100.0.0/14 (154.100.0.0 - 154.103.255.255)
154.104.0.0/14 (154.104.0.0 - 154.107.255.255)
154.108.0.0/15 (154.108.0.0 - 154.109.255.255)
```

### Long answer

CIDR slash notation indicates the number of 1's in the subnet mask. For the purposes of routing a subnet mask is N number of 1's immediately followed by M number of 0's with N+M=32.

```
/1 is 10000000 00000000 00000000 00000000 or 128.0.0.0
/8 is 11111111 00000000 00000000 00000000 or 255.0.0.0
/16 is 11111111 11111111 00000000 00000000 or 255.255.0.0
/24 is 11111111 11111111 11111111 00000000 or 255.255.255.0
/32 is 11111111 11111111 11111111 11111111 or 255.255.255.255
```

(Notice I grouped each octet into 8 bytes, hence the term "octet")

Note that you can not have a 1 following a 0 for CIDR notation. There may be applications that allow such subnet masks (some ACLs in firewalls do), but at least for the purposes of routing this is not allowed as far as I know.

The subnet bits are matched up with the IP address bits. If the subnet bit is a 0 then anything in the IP address for that bit position is allowed (it's a wildcard for that bit).

So back to your question, if we have 154.10*.*.* then we are looking for IPs in this range:

```
154.100.0.0 - 154.109.255.255
```

Which in binary is represented as:

```
154 100 0 0
10011010 01100100 00000000 00000000
```

to

```
154 109 255 255
10011010 01101101 11111111 11111111
```

So now focus on the binary for the ranges where the bits match them together (if both bytes are the same, then output a 1; if they are different, output a 0; basically an inverted XOR also known as an XNOR)

```
BINARY DECIMAL
10011010 01100100 00000000 00000000 154.100. 0. 0
XNOR 10011010 01101101 11111111 11111111 XNOR 154.109.255.255
---------------------------------------- --------------------
11111111 11110110 00000000 00000000 255.246. 0. 0
```

But there is a problem here: this is not a standard CIDR subnet. As I mentioned above most systems / applications will not accept this, and it cannot be converted to slash notation. If you are writing your own application you certainly could support this type of value to filter for complex IP address blocks. If 255.246.0.0 is supported by your system/application, then you are done!

If you want to get the closest standard CIDR subnet simply count the number of 1's bits from the left until you hit a zero, and truncate the rest:

```
/12 is 11111111 11110000 00000000 00000000 or 255.240.0.0
```

Now to find out where this mask would start you would AND them together (if both bits are 1 output a 1, otherwise output a 0):

```
10011010 01100100 00000000 00000000 154.100.0.0
AND 11111111 11110000 00000000 00000000 AND 255.240.0.0
--------------------------------------- -------------------
10011010 01100000 00000000 00000000 154. 96.0.0
```

To determine the end of the range you would invert the subnet and OR them together (if either the IP bit or the subnet bit is 1, output a 1):

```
10011010 01100100 00000000 00000000 154.100. 0. 0
OR 00000000 00001111 11111111 11111111 OR 0. 15.255.255
-------------------------------------- ------------------
10011010 01101111 11111111 11111111 154.111.255.255
```

So 154.96.0.0/12 is the closest standard CIDR subnet that will cover your required range. Unfortunately it also covers some ranges outside of your desired target (154.96.0.0 - 154.111.255.255)

If you absolutely must lock it down to just 154.100.0.0 - 154.109.255.255 you will have to create multiple subnet blocks.

What you want is build a series of subnets to match every value in between:

```
10011010 01100100 00000000 00000000 154.100.0.0
10011010 01100101 00000000 00000000 154.101.0.0
10011010 01100110 00000000 00000000 154.102.0.0
10011010 01100111 00000000 00000000 154.103.0.0
^^^^^^^^ ^^^^^^ <- 14 bits match
```

Above the first 14 bits match each time, so we can break this into

```
10011010 01100100 00000000 00000000 154.100.0.0/14
```

Now continuing...

```
10011010 01101000 00000000 00000000 154.104.0.0
10011010 01101001 00000000 00000000 154.105.0.0
10011010 01101010 00000000 00000000 154.106.0.0
10011010 01101011 00000000 00000000 154.107.0.0
^^^^^^^^ ^^^^^^ <- 14 bits match
```

We have another match of 14 bits, so lets get it

```
10011010 01101000 00000000 00000000 154.104.0.0/14
```

And finally...

```
10011010 01101100 00000000 00000000 154.108.0.0
10011010 01101101 00000000 00000000 154.109.0.0
^^^^^^^^ ^^^^^^^ <- 15 bits match
```

We have 15 matching bits this time:

```
10011010 01101100 00000000 00000000 154.108.0.0/15
```

So we broke up the range 154.100.0.0 - 154.109.255.255 into three valid subnets:

```
154.100.0.0/14 (154.100.0.0 - 154.103.255.255)
154.104.0.0/14 (154.104.0.0 - 154.107.255.255)
154.108.0.0/15 (154.108.0.0 - 154,109.255.255)
```