# CIDR

## Vad det är

CIDR, en förkortning av Classless Inter-Domain Routing, är sättet att beskriva
ett block av IP-adresser med en startadress och det antal inledande bitar som
alla adresser i blocket har gemensamt. Nedskrivet är det det välbekanta
snedstrecket. 198.51.100.0/24 betyder alla adresser vars första 24 bitar är
desamma som i 198.51.100.0, alltså 256 adresser från 198.51.100.0 till
198.51.100.255. Talet efter snedstrecket kallas prefixlängden, och själva
blocket kallas ett prefix.

Ordet classless, klasslös, pekar på det som fanns före. Den ursprungliga
IPv4-planen från RFC 791 hade tre storlekar av nätverk, och RFC 4632, den
gällande beskrivningen av CIDR, förklarar varför det inte höll: Klass C, med
högst 254 värdadresser, var för litet för en medelstor organisation, och klass
B, med upp till 65 534, alldeles för stort, men ändå det bästa som fanns. När
nätet kommersialiserades i slutet av 1980-talet växte efterfrågan på klass B i
vad som såg ut som exponentiell takt.

IETF:s ROAD-grupp (Routing and Addressing) möttes i januari 1992 och pekade ut
tre problem: att adressrymden i klass B höll på att ta slut, att
routningstabellerna växte bortom vad routrar och de som drev dem kunde hantera,
och att IPv4 självt en dag skulle få slut på adresser. De två första väntades
bli kritiska någon gång mellan 1993 och 1995. CIDR var svaret på dem, först
föreslaget i RFC 1338 i juni 1992 och sedan i RFC 1519 i september 1993, som RFC
4632 ersatte i augusti 2006. Det tredje problemet försökte CIDR aldrig lösa; det
skulle bara köpa tid.

I CIDR-notation skriver RFC 4632 ett prefix som den vanliga adressen i fyra
delar, ett snedstreck och ett tal från 0 till 32 som anger de signifikanta
bitarna. Den äldre nätmasken säger samma sak med de bitarna satta till ett och
resten till noll, så /24 är 255.255.255.0. Den enda begränsning RFC:n håller
fast vid är att masken måste vara sammanhängande, och inom den kan ett prefix
beskriva varje block vars storlek är en potens av två. Tabellen i RFC:n går från
/32, en värdrutt med en adress, via /31 för en punkt-till-punkt-länk med två,
/24 med 256 och /16 med 65 536, ned till 0.0.0.0/0 med alla 4 294 967 296
adresser, som används som standardrutt.

Notationen har överlevt adressfamiljen den byggdes för: RFC 4291, som
fastställer hur IPv6-adresser är uppbyggda, skriver IPv6-prefix på samma sätt,
så 2001:db8::/32 läses precis som sina IPv4-kusiner.

## Varför det spelar roll

CIDR löste sina ursprungliga problem genom aggregering. RFC 4632 kallar
aggregering av information den enda allmänt förstådda metoden för att minska
routningstillståndet i ett paketförmedlande nätverk. En leverantör som har ett
stort block och numrerar sina kunder ur små bitar av det kan annonsera en enda
rutt för hela blocket, och resten av internet behöver inget mer för att nå varje
kund i det. RFC 4632 tillägger att själva tilldelningen av adresser måste läggas
om för att göra det möjligt, och att den del av den gamla klass C-rymden som
inte går att aggregera, på engelska kallad the swamp, träsket, år 2006
uppskattades till omkring 15 000 poster i routningstabellen.

Aggregering fungerar tack vare en enda regel som alla routrar följer. Med RFC
4632:s ord: ”Vidarebefordran på internet sker efter principen om längsta
matchning.” När flera prefix täcker samma destination vinner det mest specifika.
Så förblir en organisation som byter leverantör utan att numrera om nåbar: Den
nya leverantören annonserar organisationens eget lilla prefix, vilket RFC:n
beskriver som att slå hål i den gamla leverantörens aggregat, och det föredras
framför aggregatet eftersom det är den längre matchningen. CIDR var tänkt att
räcka i tre till fem år men var enligt RFC:n grundligt infört 2005.

Få ingenjörer sätter upp routning mellan domäner, men nästan alla skriver
prefix: i en brandväggsregel som släpper in ett kontorsnät, i en routningstabell
på en Linux-server och i WireGuard, där AllowedIPs-listan med prefix för varje
motpart avgör både vilka källadresser som godtas från den motparten och vart
trafik till den skickas. På alla tre ställena kan en enda felaktig siffra efter
snedstrecket i tysthet släppa in eller stänga ute tusentals värdar.

## Så ser det ut i praktiken

Pythons standardmodul `ipaddress` förstår notationen och är ett snabbt sätt att
kontrollera räkningen innan den hamnar i en regel. Sessionen nedan är den här
artikelns illustration, körd på Python 3.15 med adresser från
dokumentationsblocket 198.51.100.0/24:

```text
>>> import ipaddress
>>> net = ipaddress.ip_network("198.51.100.0/24")
>>> net.netmask, net.num_addresses
(IPv4Address('255.255.255.0'), 256)
>>> for sub in net.subnets(new_prefix=26):
...     print(sub)
...
198.51.100.0/26
198.51.100.64/26
198.51.100.128/26
198.51.100.192/26
>>> ipaddress.ip_network("198.51.100.70/26")
Traceback (most recent call last):
  ...
ValueError: 198.51.100.70/26 has host bits set
>>> ipaddress.ip_network("198.51.100.70/26", strict=False)
IPv4Network('198.51.100.64/26')
>>> half = ipaddress.ip_network("198.51.100.128/25")
>>> ipaddress.ip_address("198.51.100.200") in half
True
>>> half.subnet_of(net)
True
```

Ett /24 delar sig i fyra /26-block med 64 adresser i varje, och vart och ett
börjar på en multipel av 64. Försöket med 198.51.100.70/26 misslyckas eftersom
blocket som innehåller .70 börjar på .64 och bitarna efter den 26:e inte är
noll; med `strict=False` nollställer modulen dem och returnerar det block som
.70 hör till. De två sista raderna är de frågor man bör ställa om varje par av
prefix när man granskar regler: Ligger adressen inom blocket, och ligger det ena
blocket helt inuti det andra?

Den andra frågan betyder mest i ett paketfilter, eftersom det inte använder
längsta matchning. Det läser sina regler i ordning och stannar vid den första
som avgör saken. Manualen nft(8) säger att `accept` och `drop` avslutar
utvärderingen av kedjan, och att `add` lägger en regel sist i en kedja medan
`insert` lägger den först. I den här artikelns andra illustration är målet att
låta ett /24 nå SSH men hålla dess övre halva ute:

```text
add table inet filter
add chain inet filter input { type filter hook input priority filter; }
add rule inet filter input ip saddr 198.51.100.0/24 tcp dport 22 accept
add rule inet filter input ip saddr 198.51.100.128/25 tcp dport 22 drop
```

Båda reglerna ser riktiga ut, och en listning visar båda. Men varje adress i
/25-blocket ligger också i /24-blocket, så den första regeln godtar trafiken
därifrån, och drop-regeln under den nås aldrig. I routning skulle det mer
specifika prefixet vinna oavsett var det stod; i ett filter vinner det bara om
det kommer först. Byt plats på de två raderna, eller lägg till den smala regeln
med `insert`, så får du det avsedda resultatet. `nft -a list ruleset` skriver ut
varje regel med dess handle, och både `add` och `insert` tar emot ett handle, så
att en ny regel kan placeras intill en befintlig.

Portföljposten
[Verifierade brandväggsregler efter position](/sv/portfolio/verified-firewall-rules-by-position/)
från augusti 2026 beskriver samma fälla från driftsidan. En värd gick i ett år
med en hastighetsbegränsning som inget paket någonsin nådde fram till, eftersom
den låg under en bredare regel som matchade först, och varje inblandat verktyg
hade skrivit ut begränsningen korrekt hela tiden. Kontrollerna läser nu den
numrerade regellistan och den levande filterkedjan och verifierar mot ordningen.
Sidan säger inte hur den bredare regeln var skriven eller om adressprefix
spelade in, så raderna ovan illustrerar principen och inte den värdens regler.

## Var det går fel

**Värdbitar i adressen.** 198.51.100.70/26 är en adress med en mask, inte ett
block. Python avvisar den som standard, men med `strict=False` avrundar modulen
den nedåt till 198.51.100.64/26, vilket kanske inte är de värdar som författaren
menade. Skriv blockets nätverksadress, och tolka strikt så att slarvfelet syns
som ett felmeddelande.

**En ensam adress där ett block var tänkt.** Pythons dokumentation säger att ett
nätverk utan mask tolkas som /32, så en kontorsadress skriven utan prefix
släpper in en enda värd. Skriv alltid prefixlängden, även /32, så att en läsare
kan skilja en avsiktlig värdrutt från ett glömt snedstreck.

**Ett brett prefix ovanför ett smalt.** Som illustrationen visar låter ett
filter med första träff den tidigare regeln skugga varje senare regel vars
prefix den innehåller. Lägg de mest specifika reglerna först, och när reglerna
genereras, testa varje par med en kontroll av innehållande som `subnet_of` eller
`overlaps`, och låt bygget misslyckas om en senare regel inte kan nås.

**En prefixlängd som är några bitar för kort.** Varje bit som tas bort
fördubblar blocket, så ett /16 skrivet i stället för ett /24 släpper in 256
gånger så många adresser, och /0 släpper in alla adresser som finns. RFC 4632
noterar att operatörsfel och andra händelser tidigare har gjort att /1- och
/2-rutter dykt upp i vissa nätverk. Behandla varje regel som är kortare än
blocket du själv har som en granskningspunkt, och reservera 0.0.0.0/0 och ::/0
för regler som ska matcha allt.

**Värdar räknade som adresser.** Ett /24 har 256 adresser, men på ett vanligt
nätverk är den första nätverksadressen och den sista broadcastadressen, så
`hosts()` i Python returnerar 254 av dem. På punkt-till-punkt-länkar blir
spillet stort: RFC 3021 påpekar att ett /30 lägger fyra adresser på två värdar,
och låter sådana länkar använda ett /31 i stället, vilket sparar 1 000 adresser
på 500 länkar. Dimensionera ett block efter de värdar det ska rymma plus de
reserverade adresserna, och använd /31 bara på utrustning som stöder RFC 3021.

**Ett aggregat utan discard-rutt.** En router som annonserar ett sammanfattande
block men har tappat ett av de mindre prefixen inuti det kan skicka trafik för
den saknade biten tillbaka längs en mindre specifik rutt, till exempel
standardrutten, och på så vis skapa en routningsloop. RFC 4632 kräver att den
router som skapar aggregatet kastar paket som matchar det men ingen mer specifik
rutt, och i praktiken betyder det en discard- eller null-rutt för varje aggregat
den annonserar.

**Tillåtelselistor som bara täcker IPv4.** I nftables läser `ip saddr`
IPv4-huvudet och `ip6 saddr` IPv6-huvudet, och i Python ger det ett `TypeError`
att slå ihop en blandad lista, eftersom de två versionerna inte kan kombineras.
En lista med IPv4-prefix säger ingenting om IPv6-klienter, som då faller igenom
till det som kommer efteråt. Håll IPv4- och IPv6-prefix sida vid sida i varje
regel, och kontrollera båda när du testar.

## Läs mer

- [RFC 4632: Classless Inter-domain Routing (CIDR): The Internet Address Assignment and Aggregation Plan](https://www.rfc-editor.org/rfc/rfc4632.html)
  — den gällande beskrivningen av CIDR, med historiken, prefixtabellen och
  reglerna för aggregering.
- [RFC 3021: Using 31-Bit Prefixes on IPv4 Point-to-Point Links](https://www.rfc-editor.org/rfc/rfc3021.html)
  — varför ett /30 lägger hälften av sina adresser på en punkt-till-punkt-länk
  och hur ett /31 undviker det.
- [RFC 4291: IP Version 6 Addressing Architecture](https://www.rfc-editor.org/rfc/rfc4291.html)
  — reglerna för IPv6-adresser, också prefix skrivna med samma
  snedstrecksnotation.
- [ipaddress: IPv4/IPv6 manipulation library](https://docs.python.org/3/library/ipaddress.html)
  — Pythons dokumentation för att tolka, dela upp, jämföra och slå ihop prefix.
- [nft(8): nftables manual](https://www.netfilter.org/projects/nftables/manpage.html)
  — referensen för nftables, bland annat om hur regler ordnas och vilka beslut
  som avslutar en kedja.
- [wg(8): set and retrieve configuration of WireGuard interfaces](https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8)
  — WireGuard-manualen, där AllowedIPs definieras som en lista med adresser med
  CIDR-masker.

<https://engineer.company/sv/glossary/cidr/>
