Back to blog

Cisco / IOS  ·  Tutorial  ·  July 2026

Cisco IOS
Access Control Lists

The router's traffic filter. Standard vs extended ACLs, the wildcard masks that trip everyone, named ACLs you can actually edit, where in the network each type belongs — and the one ACL every device needs: the lock on its own VTY lines.

Cisco IOS ACL Access-List Filtering Security Wildcard Mask CCNA

packet ACL — checked TOP DOWN, first match wins 10 permit 192.168.10.0 0.0.0.255 20 deny 192.168.20.0 0.0.0.255 30 permit any (implicit) deny any — always there, invisible forwarded dropped A packet walks the list from the top; the first matching line decides. Match nothing and the hidden deny drops it.

An access control list is an ordered list of permit/deny rules. A packet is compared against the lines from the top; the first line that matches decides its fate and evaluation stops. If nothing matches, an invisible deny any at the bottom drops it. That's the whole engine — everything else is syntax.

ACLs are the closest thing an IOS router has to a firewall, but they're also the general-purpose "match this traffic" tool: NAT used one in the DHCP & NAT post to define who gets translated, and QoS, route-maps, and VPNs all borrow the same syntax. Learn them once for filtering and you've learned the matching language of all of IOS. We'll build standard and extended ACLs, demystify wildcard masks, edit named ACLs surgically with sequence numbers, and lock down the management plane — the ACL that protects the router itself.

Prerequisites

01

Standard vs Extended — Pick the Right Tool

Standard ACLs match only the SOURCE address — a blunt instrument. Extended ACLs match source, destination, protocol, and port — a scalpel. The number range tells IOS which one you mean.

TypeMatches
Standard (1–99, 1300–1999)Source IP only. "Traffic from these hosts."
Extended (100–199, 2000–2699)Source + destination + protocol (ip/tcp/udp/icmp) + ports. "SSH from mgmt to servers."
Named (standard or extended)Same engines, but with a name and editable line numbers. Use these for anything you'll keep.

Because a standard ACL can only see the source, where you place it matters: put it near the destination, or it blocks that source from reaching everything. An extended ACL is precise, so place it near the source and kill unwanted traffic before it crosses the network. That's the classic placement rule, and it falls straight out of what each type can see.

02

Wildcard Masks — The Inverted Mask

ACLs don't use subnet masks. They use wildcard masks — the bitwise inverse. 0 means "must match", 1 means "don't care". Once you see it as inverse-of-the-subnet-mask, it's mechanical.

Wildcard mask logic — 0 = match exactly, 1 = anything goes
# Subnet mask 255.255.255.0  →  wildcard 0.0.0.255   (a /24)
192.168.10.0  0.0.0.255   → matches 192.168.10.0 – 192.168.10.255

# One single host — every bit must match:
192.168.10.5  0.0.0.0     → exactly 192.168.10.5 (shortcut: host 192.168.10.5)

# Everything — no bit has to match:
0.0.0.0  255.255.255.255  → any address (shortcut: any)

# The mental shortcut for common masks: 255 minus each octet
/24 → 0.0.0.255      /16 → 0.0.255.255      /30 → 0.0.0.3
/25 → 0.0.0.127      /28 → 0.0.0.15         /32 → 0.0.0.0
⚠ Gotcha — Typing a Subnet Mask Where a Wildcard Belongs

Writing permit 192.168.10.0 255.255.255.0 in an ACL doesn't error — IOS accepts it and matches almost nothing you intended (it reads those 255s as "don't care" octets). This is the number-one silent ACL bug. If an ACL "isn't matching anything" (show access-lists shows zero matches), check the mask first: in ACL-land it's always the wildcard, the inverse of the subnet mask. (NAT's access-list, from the previous post, uses wildcards too.)

03

A Standard ACL — Build and Apply

The two-step ritual for every ACL: build the list in global config, then apply it to an interface with a direction. An ACL that isn't applied filters nothing.

IOS — standard ACL: guests may not reach the server VLAN
# 1. Build the list (numbered standard, 1-99)
R1(config)# access-list 10 deny 192.168.20.0 0.0.0.255
R1(config)# access-list 10 permit any
# Without "permit any", the implicit deny would block EVERYONE.

# 2. Apply it OUTBOUND on the interface facing the servers
#    (standard ACL → near the destination)
R1(config)# interface GigabitEthernet0/2
R1(config-if)# ip access-group 10 out
R1(config-if)# end

# Verify: rules + hit counters (safe)
R1# show access-lists 10
Standard IP access list 10
    10 deny   192.168.20.0, wildcard bits 0.0.0.255 (43 matches)
    20 permit any (1287 matches)

Direction is from the router's point of view. in = packets arriving at this interface from the wire; out = packets the router is about to send out of it. Getting this backwards is the second-most-common ACL bug after wildcard masks.

04

Extended ACLs — Match Precisely

Protocol, source, destination, port. Extended ACLs express real policy: "guests get web and DNS, and nothing else toward the LAN."

IOS — extended ACL, applied near the source (guest VLAN in)
# Named extended ACL — use names for anything permanent
R1(config)# ip access-list extended GUEST-IN

# Allow DNS and web to the internet, block everything toward the LAN
R1(config-ext-nacl)# permit udp 192.168.20.0 0.0.0.255 any eq 53
R1(config-ext-nacl)# permit tcp 192.168.20.0 0.0.0.255 any eq 443
R1(config-ext-nacl)# permit tcp 192.168.20.0 0.0.0.255 any eq 80
R1(config-ext-nacl)# deny   ip  192.168.20.0 0.0.0.255 192.168.10.0 0.0.0.255
R1(config-ext-nacl)# deny   ip  192.168.20.0 0.0.0.255 192.168.99.0 0.0.0.255
R1(config-ext-nacl)# permit ip  192.168.20.0 0.0.0.255 any
R1(config-ext-nacl)# exit

# Apply INBOUND on the guest-facing interface (extended → near the source)
R1(config)# interface GigabitEthernet0/1.20
R1(config-subif)# ip access-group GUEST-IN in
R1(config-subif)# end
⚠ Gotcha — Order Is Policy: Permits Before the Deny They'd Hit

First match wins, so a rule's position is part of the policy. In GUEST-IN, the web/DNS permits sit above the LAN denies — swap them and guests lose DNS if your DNS server lives in the LAN range. When an ACL misbehaves, read it top-down as the packet would: show access-lists shows per-line match counters, and the line soaking up the hits is where your traffic is actually landing — often not the line you thought.

💡 Pro Tip — established, and Logging the Denies

Two keywords worth knowing early. permit tcp any any established matches only TCP packets that belong to already-started conversations (ACK/RST set) — the classic "replies may come back, but outsiders can't initiate" line on an inbound WAN ACL. And appending log to a deny (deny ip any any log as your explicit last line) makes the invisible visible: you get a syslog entry for every drop, which turns "the app doesn't work" into "the ACL is dropping TCP/8443 from .20.14, add a permit." An explicit final deny with log costs nothing and replaces guessing with evidence.

05

Editing ACLs — Sequence Numbers

The old pain: numbered ACLs couldn't be edited — you deleted and retyped the whole list. Named ACL config mode fixes this with sequence numbers. This is why you use named ACLs.

IOS — insert, delete, and renumber lines surgically
# The lines are numbered 10, 20, 30... — gaps are for insertions
R1# show access-lists GUEST-IN
Extended IP access list GUEST-IN
    10 permit udp 192.168.20.0 0.0.0.255 any eq domain
    20 permit tcp 192.168.20.0 0.0.0.255 any eq 443
    30 permit tcp 192.168.20.0 0.0.0.255 any eq www
    40 deny ip 192.168.20.0 0.0.0.255 192.168.10.0 0.0.0.255

# Insert a new rule BETWEEN 10 and 20 — give it sequence 15
R1(config)# ip access-list extended GUEST-IN
R1(config-ext-nacl)# 15 permit udp 192.168.20.0 0.0.0.255 any eq 123   # NTP

# Delete one line by its sequence number — the rest stay untouched
R1(config-ext-nacl)# no 30
R1(config-ext-nacl)# exit

# Out of gaps? Renumber: start at 10, step by 10
R1(config)# ip access-list resequence GUEST-IN 10 10
⚠ Gotcha — "no access-list 110" Deletes the WHOLE Numbered List

On a classic numbered ACL, typing no access-list 110 deny … intending to remove one line removes the entire ACL 110 — and an interface with ip access-group 110 in now filters nothing (an applied-but-nonexistent ACL permits everything). If that ACL was your WAN filter, you just opened the router. Edit numbered ACLs only by rewriting them offline and pasting; better, use named ACLs and sequence numbers and never face the problem.

06

Protecting the Router Itself — VTY Access-Class

The most important ACL on any device is the one that decides who may even attempt to SSH in. An interface ACL filters transit traffic; access-class on the VTY lines guards the management plane from every direction at once.

IOS — SSH management locked to the admin subnet
# Standard ACL is enough here — we only care about WHO (source)
R1(config)# ip access-list standard MGMT-ONLY
R1(config-std-nacl)# permit 192.168.99.0 0.0.0.255
R1(config-std-nacl)# deny any log
R1(config-std-nacl)# exit

# Apply with access-class on the VTY lines — not ip access-group
R1(config)# line vty 0 4
R1(config-line)# access-class MGMT-ONLY in
R1(config-line)# end

# Now SSH attempts from anywhere outside 192.168.99.0/24 are refused
# at the line — regardless of which interface they arrived on.
💡 Why access-class Beats Interface ACLs for Management

You could add "deny SSH to the router" lines on every interface ACL — and forget one, which is exactly what attackers count on. access-class sits on the VTY lines themselves, so it covers every current and future interface in one place. This pairs with the SSH setup from First Contact: transport input ssh decides how you may connect, access-class decides from where. On gear we hand over, both are non-negotiable.

07

Verify & Troubleshoot Safe to Run

Three questions solve most ACL tickets: what do the rules actually say, which line is the traffic hitting, and is the ACL applied where you think it is.

CommandAnswers
show access-listsEvery ACL with per-line match counters — the ground truth.
show access-lists GUEST-INOne ACL's lines and counters.
show ip interface gi0/1Which ACL is applied on this interface, and in which direction.
show run | section access-listThe ACLs as configured, including remarks.
show run | section line vtyConfirms the access-class guarding management.
clear access-list countersZero the match counters before a test, so hits are unambiguous.
IOS — the counter-based debugging ritual
# 1. Zero the counters
R1# clear access-list counters GUEST-IN

# 2. Reproduce the problem (have the user retry / send the traffic)

# 3. Read which line moved
R1# show access-lists GUEST-IN
    ...
    40 deny ip 192.168.20.0 0.0.0.255 192.168.10.0 0.0.0.255 (17 matches)
# 17 new matches on line 40 — the traffic is being eaten by the LAN deny.
# Decision is now informed: insert a permit above 40, or confirm it's policy.

08

MikroTik ↔ Cisco — Filter Philosophy

RouterOS firewall rules and IOS ACLs solve the same problem with different engines — one is stateful by default, the other is a stateless list you make smarter.

MikroTik / RouterOSCisco IOS
/ip firewall filter ruleAn ACL line (permit/deny)
chain=forwardACL applied to a transit interface (in/out)
chain=input (to the router)access-class on VTY + control-plane policies
connection-state=established,relatedpermit tcp any any established (TCP-only, cruder)
src-address=192.168.10.0/24192.168.10.0 0.0.0.255 (wildcard, not CIDR)
log=yeslog keyword on the ACL line
Rules evaluated top-down, first matchSame — and both end in an implicit drop/deny
💡 The Real Difference — State

RouterOS filter is a stateful firewall: connection tracking is built in, and established,related handles return traffic for every protocol. Classic IOS ACLs are stateless — each packet is judged alone, and established only approximates state for TCP. That's fine for segmentation and management-plane control, which is what ACLs are for. When a site needs a real stateful edge on Cisco, that's Zone-Based Firewall (or a dedicated firewall appliance) — a different tool, and a topic for later in this series.

Takeaways

  1. Top-down, first match, invisible deny at the end. That single sentence is the whole ACL engine. Every confusing behaviour traces back to one of its three clauses.
  2. Wildcard masks are inverted subnet masks. 0 = must match, 1 = don't care; /24 → 0.0.0.255. Typing a subnet mask by habit doesn't error — it just silently matches the wrong thing.
  3. Standard near the destination, extended near the source. The placement rule falls out of what each type can see. And remember direction is the router's view: in arriving, out leaving.
  4. Use named ACLs with sequence numbers. Insert with 15 permit …, delete with no 30, tidy with resequence. Numbered ACLs delete wholesale — no access-list 110 removes the entire list and fails open.
  5. An ACL that isn't applied filters nothing. Build, then ip access-group … in|out — and verify with show ip interface, not memory.
  6. The management plane gets its own ACL. access-class on the VTY lines restricts who may even attempt SSH, on every interface at once. It's the highest-value five lines of security on the box.
  7. Debug with counters, not theories. clear access-list counters, reproduce, show access-lists — the line that moved is the line responsible. Add log to explicit denies and drops stop being mysteries.

Need real segmentation for an office, hotel, or SMB in Crete?

NOCTIS designs and audits filtering policies on Cisco and MikroTik — guest isolation, management-plane lockdown, and rules your team can read. We document every ACL line with its reason, so the policy survives staff changes.

Book a Discovery Call →