---
title: 'The Concept of the IP Address'
source: 'https://academia.sh/en/courses/how-the-internet-works/concept-of-the-ip-address'
course: 'How the Internet Works'
language: en
updated: '2026-08-17T18:07:04+00:00'
license: 'CC BY-SA 4.0'
---

# The Concept of the IP Address

The numeric structure of the address, how splitting it into network and host parts shrinks routing tables, and the distinction between public and private addresses.

The previous lesson said that autonomous systems announce **address blocks** to each
other, not individual machines. This implies that addresses are not randomly assigned
labels; if they can be spoken of in blocks, addresses must have a structure.

This lesson defines that structure. The question to ask is: what does an address look
like, and what problem was this format chosen to solve?

## An Address Is a Number

An **IP address** is a fixed-length number that identifies an interface attached to the
network. In the IPv4 scheme this number is 32 bits.

The familiar `192.0.2.10` notation is nothing more than splitting those 32 bits into four
eight-bit pieces and writing each piece in base ten. The notation is for humans; the
machine sees a single number.

```python
import ipaddress

address = ipaddress.ip_address("192.0.2.10")
print(address.version)
print(int(address))
print(format(int(address), "032b"))
```

```
4
3221225994
11000000000000000000001000001010
```

The bit string's first octet, `11000000` in binary, is 192; the second, `00000000`, is
zero; the third, `00000010`, is two; the last, `00001010`, is ten. The dot separator does
not exist in the bit string; it exists only in the written form.

Each piece being eight bits limits the values it can hold to the range 0–255. A notation
like `192.0.2.300` is invalid because 300 does not fit in eight bits.

The order in which the address's bytes are written on the network is separately agreed
upon. The byte-order lesson in the How Computers Work course covered this layout under
the name **network byte order**: multi-byte numbers in headers are written big-endian.
Machines using different byte orders can read the same address the same way because of
this agreement.

32 bits total gives $2^{32}$, roughly 4.3 billion distinct values. This number looked
plentiful when the scheme was designed; it later fell short. The IPv6 scheme removes this
limit by extending the address to 128 bits, written in hexadecimal groups like
`2001:db8::1`. The technical details between the two schemes are the subject of the
Network Models and Protocols course.

## What the Address Addresses

Note that the address identifies not a machine but **a network interface**. A machine
with multiple interfaces has multiple addresses; each leg of a router carries a separate
address.

The address works together with the port defined in the previous lesson. The address
says which interface to go to; the port says which program on that machine to deliver to.
Reaching the `example.test` server requires both.

## Hierarchy and the Scaling of Routing

Suppose addresses could be distributed arbitrarily. In that case every router would have
to know, individually, which way to go for every destination address. The table would
carry as many rows as there are addresses in use, and every new machine would have to be
announced to every network.

The solution is to split the address in two: the left-hand bits specify the **network**,
the right-hand bits the **host** within that network. Where the split falls is stated by
the **prefix length** written alongside the address.

```python
import ipaddress

network = ipaddress.ip_network("192.0.2.0/24")
print(network.network_address)
print(network.netmask)
print(network.num_addresses)
print(ipaddress.ip_address("192.0.2.10") in network)
print(ipaddress.ip_address("198.51.100.10") in network)
```

```
192.0.2.0
255.255.255.0
256
True
False
```

The `/24` notation says the left-hand 24 bits are the network part. That leaves 8 bits for
the host, and this block contains $2^8 = 256$ addresses. `192.0.2.10` is inside this
block; `198.51.100.10` is not.

The value `255.255.255.0` is the same information written as a **netmask**: bits set to
one mark the network part, bits set to zero mark the host part.

The gain is this: a router now holds a single row for 256 addresses. Every packet headed
for the `192.0.2.0/24` block goes the same way; the individual hosts inside it are
invisible from outside. The larger the block, the greater the saving in the table.

This means that, given an address, which network it belongs to can be read **from the
address itself**. An address is not only an identity but also a statement of location.
When an organization changes its address block, its machines' addresses change with it;
an address is not a portable property of the machine.

Blocks can nest, and a router can find more than one matching row. In that case the
**longest prefix** wins: the row giving the most specific information is chosen. This way
a general block can be summarized in one row while a section inside it is sent a
different way by a separate, more specific row. The detail of prefix arithmetic and
subnet design belongs to the Network Models and Protocols course.

## Public and Private Addresses

Part of the address space is set aside to never be routed on the internet. These
**private addresses** carry meaning only within a local network.

Three blocks are reserved for this purpose:

```python
import ipaddress

PRIVATE_BLOCKS = [
    ipaddress.ip_network("10.0.0.0/8"),
    ipaddress.ip_network("172.16.0.0/12"),
    ipaddress.ip_network("192.168.0.0/16"),
]

for text in ["10.0.0.5", "172.16.3.1", "192.168.1.1", "192.0.2.10"]:
    addr = ipaddress.ip_address(text)
    private = any(addr in block for block in PRIVATE_BLOCKS)
    print(f"{text:<14} in_private_block={private}")
```

```
10.0.0.5       in_private_block=True
172.16.3.1     in_private_block=True
192.168.1.1    in_private_block=True
192.0.2.10     in_private_block=False
```

The defining property of private addresses is that they are **not required to be
unique**. Countless local networks each have a machine at `192.168.1.1` at the same time,
and this is not a collision, because the address carries no meaning outside its own
network. A router does not forward a packet whose destination is a private address onto
the internet.

The direct consequence is that a machine with a private address is not directly
reachable from outside. Such a machine can still **initiate** an outbound connection: at
the network's edge, a mechanism rewrites the packet's source address to its own public
address and translates the returning response back to the correct internal machine. This
translation is detailed in the address translation lesson of the Linux Network
Administration and Troubleshooting course, and in the Network Models and Protocols
course.

This matches the client–server asymmetry established in the previous lesson: being a
client requires no reachable address, being a server does. A server's need for a public
address is the technical basis of the hosting topic.

One more block is set apart: `127.0.0.0/8` contains the **loopback** addresses that refer
to the machine itself. Packets sent to this address never reach the network interface at
all. Because the previous lesson's server listened on `127.0.0.1`, it was reachable only
from the same machine.

This course's examples use the `192.0.2.0/24` and `198.51.100.0/24` blocks. These blocks
are reserved for documentation; they do not point to a real host, which is why they are
safe to use in examples.

## Where an Address Comes From

A machine gets its address one of two ways. **Manual configuration** is a human entering
the address; it is used on machines, like servers, whose address must not change.
**Automatic assignment** is the machine requesting an address from a local service when
it joins the network; this address is leased and renewed when it expires.

The consequence of the second method is that client machines' addresses are not
permanent. The same machine gets a different address on a different network. The
server's address being stable and the client's temporary is the natural split between
these two assignment methods.

Public address blocks are not handed directly to organizations; they are allocated
within the regional registration scheme mentioned in the previous lesson and distributed
through access providers. An address block is not owned; it is allocated under specific
conditions.

## Summary

- An IP address is a fixed-length number identifying a network interface; the dotted
  notation is only a writing convenience.
- An address splits into network and host parts; the split point is stated by the
  prefix length or an equivalent netmask.
- Hierarchy lets routers table blocks instead of individual hosts; on overlapping
  blocks, the longest prefix is chosen.
- An address is a statement of location; when an organization's block changes, its
  machines' addresses change with it.
- Private addresses are not unique and are not routed to the internet; a machine with
  such an address can initiate a connection but cannot be reached from outside.
- Servers use stable, manually configured addresses; clients can work with automatically
  assigned, temporary ones.

## Next Step

It was established that the server has an address, and that the address is kept stable.
And yet you did not type a number into the address bar; you typed `example.test`. People
do not remember numbers, and an organization's server address changes when it moves,
while its name is expected to stay the same. The next topic builds this link between
names and addresses: how a name is structured, who it belongs to, and how it is
translated into an address.
