Thuta Learning
BasicDevOps & Toolsbeginner

IP Addresses and Subnets

What you'll walk away with

  • Explain the core ideas behind IP Addresses and Subnets
  • Read the diagram and trace how data actually moves through it
  • Run the sample code and verify its output

Build the mental model

An IPv4 address is a 32-bit number — nothing more. 3232238117 is a perfectly valid IPv4 address, and it is the same address as 192.168.10.37. Dotted-quad notation is purely a human convenience: split the 32 bits into four 8-bit chunks, write each as a decimal 0-255, join with dots. Every octet you see is just eight bits of one integer, which is why 192.168.10.256 is meaningless, and why comparing addresses as strings gives nonsense while comparing them as integers works.

The important structure is that those 32 bits are split into two parts. A leading run of bits identifies the network; the remaining bits identify a host within that network. Crucially, the address alone does not tell you where the split falls — you need a subnet mask, a second 32-bit value whose bits are all 1s across the network portion and all 0s across the host portion. AND the address with the mask and you get the network address; AND it with the inverted mask and you get the host number.

Because a mask is always a solid run of 1s followed by a solid run of 0s, writing out all 32 bits is redundant — you only need the count. That is CIDR notation: /24 means twenty-four 1s, which is 255.255.255.0. This matters constantly in practice, because a host uses exactly this test to decide what to do with every outbound packet. If the destination's network part matches its own, it delivers directly on the local link; if not, it hands the packet to its default gateway. Change the mask and you change that decision.

text
192.168.10.37/24 AS 32 BITS
---------------------------
  192        168         10         37    <- dotted quad (for humans)
11000000   10101000   00001010   00100101 <- the real 32-bit integer
[---- network: 24 bits ------]   [ host ]
11111111   11111111   11111111   00000000 <- /24 mask = 255.255.255.0
   all 1s: keep this part          all 0s: this part varies per host

address AND  mask -> 11000000 10101000 00001010 00000000
                     = 192.168.10.0     (the network address)

address AND ~mask -> 00000000 00000000 00000000 00100101
                     = 37               (host number in that net)

Same 32 bits, different mask, different meaning:

  192.168.10.37/24  -> network 192.168.10.0    (8 host bits)
  192.168.10.37/16  -> network 192.168.0.0    (16 host bits)
  192.168.10.37/28  -> network 192.168.10.32   (4 host bits)

Connect it to a real scenario

Here is a concrete failure you will eventually meet. Someone sets a machine's address to 192.168.10.37 with mask 255.255.0.0, while everything else on the LAN uses 255.255.255.0. Pinging neighbours in 192.168.10.x still works, so things look fine — but 192.168.11.5, which is a different network to everyone else, now looks local to this one machine. Instead of sending that traffic to the gateway, it ARPs for a host that is not on the wire, and the connection silently hangs. The reported symptom is "some hosts work, some time out", and the cause is one wrong mask.

The reasoning to apply is always the same three steps. Take your own address and your own mask and AND them to get your network address. Take the destination address and apply your mask to it, getting its network address. If the two match, the destination is on your link and you deliver directly; if not, send it to the default gateway. That comparison happens for every single outbound packet, which is why the mask is not a cosmetic setting.

The code below runs exactly that computation for 192.168.10.37/24 — printing the address as an integer, then as 32 bits, then the mask, and finally the two AND results that separate the network part from the host part.

Try the working example

python
import ipaddress

iface = ipaddress.IPv4Interface("192.168.10.37/24")
addr = iface.ip
net = iface.network

print("address       :", addr)
print("as one integer:", int(addr))
print("as 32 bits    :", format(int(addr), "032b"))
print()

print("prefix length :", net.prefixlen, "network bits /",
      32 - net.prefixlen, "host bits")
print("netmask       :", net.netmask)
print("mask in bits  :", format(int(net.netmask), "032b"))
print("hostmask      :", net.hostmask)
print()

print("network addr  :", net.network_address)
print("network part  :", format(int(addr) & int(net.netmask), "032b"))
print("host part     :", format(int(addr) & int(net.hostmask), "032b"))
print("host number   :", int(addr) & int(net.hostmask))
print()

# Two addresses are "local" to each other only if the network parts match.
for other in ("192.168.10.200", "192.168.11.200"):
    same = ipaddress.IPv4Address(other) in net
    print("%-15s same network as %s ? %s" % (other, addr, same))
You should see
address       : 192.168.10.37
as one integer: 3232238117
as 32 bits    : 11000000101010000000101000100101

prefix length : 24 network bits / 8 host bits
netmask       : 255.255.255.0
mask in bits  : 11111111111111111111111100000000
hostmask      : 0.0.0.255

network addr  : 192.168.10.0
network part  : 11000000101010000000101000000000
host part     : 00000000000000000000000000100101
host number   : 37

192.168.10.200  same network as 192.168.10.37 ? True
192.168.11.200  same network as 192.168.10.37 ? False

5-minute try-it

Re-run the code with "192.168.10.37/16" and then "192.168.10.37/28". The 32 address bits are identical every time — explain why the network address, the host number, and the answer to "is 192.168.11.200 on the same network?" all change anyway.

One important caution

Comparing or sorting IP addresses as strings — string order says "192.168.10.9" is greater than "192.168.10.10"; convert to ipaddress objects or ints first

Guessing the network from the address alone — 10.1.2.3 could be a /8, /24, or /30, and only the mask tells you which, so always check the configured mask

RFC 4632 — Classless Inter-domain Routing (CIDR)Computer Networking

Easy traps

  • Comparing or sorting IP addresses as strings — string order says "192.168.10.9" is greater than "192.168.10.10"; convert to ipaddress objects or ints first
  • Guessing the network from the address alone — 10.1.2.3 could be a /8, /24, or /30, and only the mask tells you which, so always check the configured mask
  • Validate sample code in a local or test environment before applying it to a production network.

Exercise

Re-run the code with "192.168.10.37/16" and then "192.168.10.37/28". The 32 address bits are identical every time — explain why the network address, the host number, and the answer to "is 192.168.11.200 on the same network?" all change anyway.

You'll know it worked when: address : 192.168.10.37 as one integer: 3232238117 as 32 bits : 11000000101010000000101000100101 prefix length : 24 network bits / 8 host bits netmask : 255.255.255.0 mask in bits : 11111111111111111111111100000000 hostmask : 0.0.0.255 network addr : 192.168.10.0 network part : 11000000101010000000101000000000 host part : 00000000000000000000000000100101 host number : 37 192.168.10.200 same network as 192.168.10.37 ? True 192.168.11.200 same network as 192.168.10.37 ? False

IP Addresses and Subnets | Thuta Learning