ACLs – Access Control Lists Overview
1. What Is an ACL and Why Does It Matter?
An Access Control List (ACL) is an ordered set of rules — called Access Control Entries (ACEs) — that a Cisco router or multilayer switch uses to filter IP packets. Each ACE contains a permit or deny action followed by match criteria. When a packet is evaluated against an ACL, each ACE is checked in sequence from top to bottom. The first ACE that matches the packet determines what happens to it — the remaining ACEs are ignored. A packet that matches no ACE hits the implicit deny all at the end of every ACL.
ACLs are used for three primary purposes:
| Purpose | Example |
|---|---|
| Security filtering | Block traffic from untrusted networks, deny specific hosts from reaching servers, restrict management access to authorised IPs only |
| Traffic classification | Identify traffic for QoS marking, NAT translation, Policy-Based Routing, or route map matching |
| VPN and route control | Define interesting traffic for IPsec VPN crypto maps, control route redistribution between routing protocols |
Related pages: Standard ACLs | Named ACLs | Applying ACLs to Interfaces | Wildcard Masks | Extended ACLs | Policy-Based Routing | NAT Overview | Standard ACL Lab | Extended ACL Lab
2. How ACL Processing Works — Top-Down Order
Understanding the top-down processing model is the single most important ACL concept. Every matching decision follows this logic exactly.
ACL processing flow for an incoming packet:
Packet arrives at interface
│
▼
ACE 1: Does the packet match? ──► YES → apply permit/deny action → DONE (stop)
│ NO
▼
ACE 2: Does the packet match? ──► YES → apply permit/deny action → DONE (stop)
│ NO
▼
ACE 3: Does the packet match? ──► YES → apply permit/deny action → DONE (stop)
│ NO
▼
(no more ACEs)
│
▼
Implicit deny all → packet DROPPED (no log generated by default)
Key rules:
1. Evaluation is TOP-DOWN — first match wins, remaining ACEs are skipped
2. Once a match is found, the action (permit/deny) is applied immediately
3. If NO ACE matches → implicit deny all drops the packet silently
4. Order of ACEs matters enormously — more specific entries must come BEFORE
less specific ones (a broad permit before a specific deny = the deny never fires)
Order Matters — A Common Mistake
WRONG ORDER — the deny for 10.1.1.1 can never be reached: ACE 1: permit 10.1.1.0 0.0.0.255 ← permits the entire /24 subnet ACE 2: deny 10.1.1.1 0.0.0.0 ← intended to block .1 specifically Packet from 10.1.1.1 arrives: → ACE 1: source 10.1.1.1 matches 10.1.1.0/24 → PERMIT → stop → .1 is allowed! ACE 2 is NEVER reached. CORRECT ORDER — specific before general: ACE 1: deny 10.1.1.1 0.0.0.0 ← block .1 specifically (most specific first) ACE 2: permit 10.1.1.0 0.0.0.255 ← allow the rest of the /24 ACE 3: (implicit deny all) Packet from 10.1.1.1: ACE 1 matches → DENY ✓ Packet from 10.1.1.5: ACE 1 no match → ACE 2 matches → PERMIT ✓
3. The Implicit Deny All
Every ACL on a Cisco device ends with an implicit deny all —
an invisible ACE that denies any packet not matched by an explicit ACE
above it. It is not shown in the running-configuration or in
show access-lists output, but it is always present and
always active.
What you configure: What the router actually processes:
────────────────────────────── ──────────────────────────────────────
permit 192.168.1.0 0.0.0.255 permit 192.168.1.0 0.0.0.255
permit 10.0.0.0 0.255.255.255 permit 10.0.0.0 0.255.255.255
deny any any ← IMPLICIT (invisible)
A packet from 172.16.5.5:
→ ACE 1: no match (not in 192.168.1.0/24)
→ ACE 2: no match (not in 10.0.0.0/8)
→ Implicit deny: packet DROPPED — silently, no log entry
permit any if you want non-matched traffic to pass,
or verify your intent matches what the implicit deny provides.
Making the Implicit Deny Visible with Logging
! Add an explicit deny any with log to see what is being dropped: Router(config)# ip access-list extended FILTER_INBOUND Router(config-ext-nacl)# permit tcp 192.168.1.0 0.0.0.255 any eq 80 Router(config-ext-nacl)# permit tcp 192.168.1.0 0.0.0.255 any eq 443 Router(config-ext-nacl)# deny ip any any log ← makes drops visible in syslog ! Without "log", the implicit deny drops silently. ! "log" generates a syslog message for every denied packet — use carefully ! on high-traffic interfaces as it consumes CPU resources.
See show logging to review the syslog messages generated by the log keyword and
Syslog for forwarding them to a central server.
4. Wildcard Masks
ACLs use wildcard masks instead of subnet masks to define which bits of an IP address must match. The logic is inverted from a subnet mask: a 0 bit in the wildcard means "must match this bit exactly" and a 1 bit means "this bit can be anything (ignore it)."
Subnet mask vs Wildcard mask logic:
Subnet mask: 255.255.255.0 → 1 bits = network, 0 bits = host
Wildcard mask: 0. 0. 0.255 → 0 bits = must match, 1 bits = ignore
Relationship: wildcard mask = 255.255.255.255 − subnet mask
Example: subnet /24 = 255.255.255.0 → wildcard = 0.0.0.255
ACL example — permit the 192.168.10.0/24 subnet:
permit 192.168.10.0 0.0.0.255
─────────── ─────────
Base address Wildcard (match first 24 bits, ignore last 8)
This matches: 192.168.10.0 through 192.168.10.255
Common wildcard masks:
┌──────────────────┬──────────────────┬─────────────────────────────────────┐
│ Subnet Mask │ Wildcard Mask │ Matches │
├──────────────────┼──────────────────┼─────────────────────────────────────┤
│ 255.255.255.255 │ 0.0.0.0 │ Single host (exact match) │
│ 255.255.255.0 │ 0.0.0.255 │ /24 subnet (256 addresses) │
│ 255.255.0.0 │ 0.0.255.255 │ /16 range (65,536 addresses) │
│ 255.0.0.0 │ 0.255.255.255 │ /8 range (16.7M addresses) │
│ 0.0.0.0 │ 255.255.255.255 │ All addresses (any) │
└──────────────────┴──────────────────┴─────────────────────────────────────┘
Wildcard Mask Shortcuts — host and any
Cisco IOS provides two keywords to avoid typing common wildcard masks: "host" keyword — matches a single IP address exactly: deny host 192.168.1.5 ≡ deny 192.168.1.5 0.0.0.0 (identical — wildcard 0.0.0.0 = match all bits) "any" keyword — matches any IP address: permit any ≡ permit 0.0.0.0 255.255.255.255 (identical — wildcard all bits = any address) Examples in an ACL: deny host 10.1.1.1 ! deny exactly 10.1.1.1 permit 10.1.1.0 0.0.0.255 ! permit the rest of the /24 permit any ! permit everything else
See full guide: Wildcard Masks
5. Standard ACLs
Standard ACLs filter traffic based solely on the source IP address. They cannot examine the destination address, protocol, or port number. Because they only look at the source, they must be placed as close to the destination as possible — placing them near the source would block that source from reaching all destinations, not just the intended one.
| Feature | Standard ACL |
|---|---|
| Match criteria | Source IP address only |
| Numbered range | 1–99 and 1300–1999 |
| Named | Yes — ip access-list standard <name> |
| Placement rule | Place close to the destination to avoid over-blocking traffic to other networks |
| Common uses | Restricting VTY (SSH/Telnet) access, controlling route redistribution, basic source-based filtering |
Standard ACL syntax: Numbered: Router(config)# access-list 10 deny host 192.168.1.5 Router(config)# access-list 10 permit 192.168.1.0 0.0.0.255 Router(config)# access-list 10 deny any Named: Router(config)# ip access-list standard BLOCK_HOST Router(config-std-nacl)# deny host 192.168.1.5 Router(config-std-nacl)# permit 192.168.1.0 0.0.0.255 Router(config-std-nacl)# deny any Applying to VTY lines (restricting management access): Router(config)# line vty 0 4 Router(config-line)# access-class BLOCK_HOST in
Standard ACL Placement — Why Close to Destination?
Topology:
[Host A: 10.1.1.1] ── [R1] ── [R2] ── [Server 172.16.1.10]
└──── [Server 172.16.2.10]
Goal: Block Host A from reaching Server 172.16.1.10 only.
WRONG — ACL on R1 (close to source):
ACL: deny host 10.1.1.1
Applied inbound on R1's LAN interface.
Result: Host A cannot reach EITHER 172.16.1.10 OR 172.16.2.10
Standard ACL can only match source — it blocks the host from everything.
CORRECT — ACL on R2 (close to destination):
ACL: deny host 10.1.1.1
Applied outbound on R2's interface toward 172.16.1.10.
Result: Host A cannot reach 172.16.1.10 ✓
Host A CAN still reach 172.16.2.10 ✓
See full guide: Standard ACLs | Standard ACL Lab
6. Extended ACLs
Extended ACLs can match on multiple criteria simultaneously: source IP, destination IP, Layer 4 protocol (TCP, UDP, ICMP, etc.), source port, and destination port. This makes them far more precise and flexible than standard ACLs. Because they can match the destination, extended ACLs should be placed as close to the source as possible — this stops unwanted traffic early and avoids wasting bandwidth on traffic that will eventually be blocked.
| Feature | Extended ACL |
|---|---|
| Match criteria | Source IP, destination IP, protocol (IP, TCP, UDP, ICMP, OSPF, EIGRP, etc.), source port, destination port, TCP flags (established), DSCP, ToS |
| Numbered range | 100–199 and 2000–2699 |
| Named | Yes — ip access-list extended <name> |
| Placement rule | Place close to the source to drop traffic early and conserve bandwidth |
| Common uses | Firewall-style filtering, permitting specific applications (HTTP, SSH, DNS), blocking specific protocols, NAT interesting traffic, VPN crypto maps, PBR matching, and complementing DHCP Snooping / 802.1X access control |
Extended ACL syntax:
access-list <number> {permit|deny} <protocol> <src> <src-wildcard> <dst> <dst-wildcard> [operator port]
Protocol keywords: ip, tcp, udp, icmp, ospf, eigrp, esp, ahp, gre, …
Port operators: eq (equal), neq (not equal), lt (less than),
gt (greater than), range (range of ports)
Examples:
! Permit HTTP from any source to the web server 172.16.1.10:
access-list 110 permit tcp any host 172.16.1.10 eq 80
! Permit HTTPS from the 10.1.0.0/16 network to any destination:
access-list 110 permit tcp 10.1.0.0 0.0.255.255 any eq 443
! Deny all ICMP from 192.168.5.0/24 to any destination:
access-list 110 deny icmp 192.168.5.0 0.0.0.255 any
! Permit DNS (UDP port 53) from internal to DNS server:
access-list 110 permit udp 10.0.0.0 0.255.255.255 host 8.8.8.8 eq 53
! Permit established TCP sessions (return traffic):
access-list 110 permit tcp any 10.0.0.0 0.255.255.255 established
! Deny everything else (explicit — good practice alongside implicit):
access-list 110 deny ip any any log
The "established" Keyword
The "established" keyword matches TCP packets that have the ACK or RST flag set — indicating the packet is part of an ALREADY established session (return traffic), not a new connection initiation (SYN). Use case: Allow internal hosts to browse the Internet (outbound permitted), and allow only return traffic back in (inbound established only). Inbound ACL on Internet-facing interface: permit tcp any 10.0.0.0 0.255.255.255 established ← allow return TCP permit udp any 10.0.0.0 0.255.255.255 ← allow return UDP (stateless) deny ip any any log ← block everything else Note: "established" only works with TCP — UDP is stateless and has no flags. For stateful inspection of UDP and other protocols, use a proper firewall (Zone-Based Firewall or ASA). See: <a href="zone-based-firewall.html">Zone-Based Firewall</a>
See full guide: Extended ACL Lab
7. Numbered vs Named ACLs
Cisco IOS supports two ACL identification methods: numbered (identified by a number) and named (identified by a descriptive string). Both can be standard or extended. Named ACLs were introduced to address the limitations of numbered ACLs.
| Feature | Numbered ACL | Named ACL |
|---|---|---|
| Identifier | A number (1–99, 100–199, 1300–1999, 2000–2699) | A descriptive name (e.g., BLOCK_TELNET, PERMIT_WEB) |
| Edit individual ACEs | Cannot delete individual lines — must delete the entire ACL and re-enter | Can delete or insert individual ACEs by sequence number |
| Sequence numbers | Not visible (added in modern IOS but limited) | Explicitly shown and editable — insert entries between existing ones |
| Readability | Low — number 110 gives no clue about purpose | High — PERMIT_HTTP_TO_SERVER is self-documenting |
| Recommended for | Simple/temporary filters, legacy environments | Production networks — best practice in all modern designs |
Named ACL Sequence Numbers — Editing Without Rewriting
Named ACL with sequence numbers:
Router(config)# ip access-list extended CORP_FILTER
Router(config-ext-nacl)# 10 permit tcp 10.1.0.0 0.0.255.255 any eq 80
Router(config-ext-nacl)# 20 permit tcp 10.1.0.0 0.0.255.255 any eq 443
Router(config-ext-nacl)# 30 permit tcp 10.1.0.0 0.0.255.255 any eq 22
Router(config-ext-nacl)# 40 deny ip any any log
! Need to insert a new rule between seq 20 and seq 30?
! Use sequence number 25:
Router(config-ext-nacl)# 25 permit tcp 10.1.0.0 0.0.255.255 any eq 53
! Need to delete only seq 30?
Router(config-ext-nacl)# no 30
! With NUMBERED ACLs you cannot do this — you must:
! 1. Remove the entire ACL from the interface
! 2. Delete the entire ACL (no access-list 110)
! 3. Re-enter every ACE from scratch
Verify ACL with sequence numbers:
Router# show ip access-lists CORP_FILTER
Extended IP access list CORP_FILTER
10 permit tcp 10.1.0.0 0.0.255.255 any eq www (142 matches)
20 permit tcp 10.1.0.0 0.0.255.255 any eq 443 (87 matches)
25 permit tcp 10.1.0.0 0.0.255.255 any eq domain
30 permit tcp 10.1.0.0 0.0.255.255 any eq 22
40 deny ip any any log (3 matches)
See full guide: Named ACLs
8. ACL Number Ranges — Reference
| ACL Type | Number Range | Match Criteria |
|---|---|---|
| Standard IP | 1 – 99 | Source IP address only |
| Extended IP | 100 – 199 | Source IP, destination IP, protocol, source/destination port |
| Standard IP (expanded) | 1300 – 1999 | Source IP address only (additional range) |
| Extended IP (expanded) | 2000 – 2699 | Source IP, destination IP, protocol, source/destination port (additional range) |
| Standard IPX | 800 – 899 | Legacy IPX — not relevant to CCNA |
| Extended IPX | 900 – 999 | Legacy IPX — not relevant to CCNA |
9. Inbound vs Outbound ACL Placement
An ACL is applied to a router interface in a specific direction — either inbound (filtering packets as they arrive on the interface) or outbound (filtering packets as they leave the interface). The direction determines which traffic the ACL sees and critically affects what other router processes (such as routing table lookup) have already occurred.
Inbound ACL
Inbound ACL — applied on the interface where packets ARRIVE:
[External network] ──► Gi0/0 (inbound ACL here) ──► routing table ──► Gi0/1
Processing order:
1. Packet arrives on Gi0/0
2. Inbound ACL is evaluated BEFORE the routing table lookup
3. If permit → routing table lookup → forwarded
4. If deny → packet dropped immediately — routing never consulted
Advantage: Drops unwanted traffic early — before the CPU cost of routing
Advantage: Protects the router itself from inbound attacks
Use case: Filter traffic entering the network from an untrusted source
(e.g., inbound on WAN interface from the Internet)
Outbound ACL
Outbound ACL — applied on the interface where packets LEAVE:
[LAN] ──► Gi0/0 ──► routing table ──► Gi0/1 (outbound ACL here) ──► [Server]
Processing order:
1. Packet arrives on Gi0/0
2. Routing table lookup determines exit interface (Gi0/1)
3. Outbound ACL on Gi0/1 is evaluated BEFORE the packet leaves
4. If permit → packet transmitted out Gi0/1
5. If deny → packet dropped at this point
Advantage: Can filter based on egress interface — useful when traffic from
multiple sources converges on one exit point
Use case: Restrict what leaves a specific interface toward a destination
(e.g., permit only HTTP/HTTPS out the WAN interface)
Inbound vs Outbound — Key Differences
| Feature | Inbound ACL | Outbound ACL |
|---|---|---|
| When evaluated | Before routing table lookup | After routing table lookup, before transmission |
| Affects router-originated traffic | No — packets generated by the router bypass inbound ACLs | Yes — packets generated by the router are subject to outbound ACLs |
| CPU efficiency | More efficient — drops packets before routing lookup | Less efficient — routing lookup already done when drop occurs |
| Typical use | Filter ingress traffic (from untrusted networks, WAN) | Restrict egress traffic (to specific destinations or servers) |
| ACLs per interface per direction | Maximum one ACL per interface per direction (one inbound + one outbound allowed simultaneously on the same interface) | |
Applying an ACL to an Interface
! Apply ACL to an interface: Router(config)# interface gigabitEthernet 0/0 Router(config-if)# ip access-group CORP_FILTER in ! inbound Router(config-if)# ip access-group OUTBOUND_FILTER out ! outbound ! A different ACL can be applied inbound and outbound on the SAME interface. ! But only ONE ACL per direction per interface. ! Apply a standard ACL to VTY lines (restrict SSH/Telnet management access): Router(config)# line vty 0 4 Router(config-line)# access-class MGMT_ALLOW in ! Remove an ACL from an interface: Router(config-if)# no ip access-group CORP_FILTER in
See full guide: Applying ACLs to Interfaces
10. ACL Placement Rules — Standard vs Extended Summary
The placement rule for each ACL type exists because of what each type can and cannot match. Understanding why the rules exist makes them impossible to forget.
| ACL Type | Place Close To | Why |
|---|---|---|
| Standard ACL | Destination | Standard ACLs can only match source IP. Placing near the source would block that source from ALL destinations — not just the intended one. Placing near the destination ensures the block is specific to the path toward that destination. |
| Extended ACL | Source | Extended ACLs can match destination IP and port, so they can be precise about what is blocked. Placing near the source drops traffic early — before it wastes bandwidth traversing multiple router hops only to be blocked at the far end. |
Topology:
[Finance: 10.10.1.0/24] ── [R1] ── [R2] ── [Server farm: 172.16.0.0/24]
[HR: 10.20.1.0/24] ──┘
Goal: Block Finance from accessing the HR file server (172.16.0.5 port 445)
but allow Finance to access all other servers.
Standard ACL approach — must go near destination (R2):
deny host 10.10.1.0 0.0.0.255 ← blocks Finance from ALL of R2's networks
This is too broad — Finance also cannot reach web/mail servers behind R2.
Extended ACL approach — place near source (R1, inbound on Finance interface):
deny tcp 10.10.1.0 0.0.0.255 host 172.16.0.5 eq 445 ← precise block
permit ip any any
Result: Finance blocked only from 172.16.0.5:445; can reach everything else ✓
Traffic is dropped at R1 — does not waste the R1→R2 link bandwidth.
11. ACL Best Practices
| Best Practice | Reason |
|---|---|
| Use named ACLs in production | Self-documenting names, editable individual ACEs by sequence number — avoid the numbered ACL limitation of full rewrite on edit |
| Most specific ACEs first | Prevents broad rules from shadowing specific ones — ensure host-specific rules precede subnet rules |
Add explicit deny ip any any log at the end |
Makes the implicit deny visible in syslog for troubleshooting and security monitoring |
| Use remarks for documentation | remark lines explain purpose; visible in running-config
and show access-lists |
| Test ACLs in a lab before production | An incorrectly placed ACL can cut off legitimate traffic — including your own management access |
| Always have a permit before applying an ACL to an interface | An ACL with only deny statements plus the implicit deny will block everything — verify at least one permit exists for legitimate traffic |
| One ACL per interface per direction | IOS only accepts one ACL inbound and one outbound per interface — consolidate rules into one ACL rather than applying multiple |
| Remove ACL from interface before deleting it | Deleting an ACL while it is applied to an interface removes the
filter but may leave a reference — always remove with
no ip access-group first |
Using remarks for documentation: Router(config)# ip access-list extended EDGE_FILTER Router(config-ext-nacl)# remark === Permit web traffic from internal LAN === Router(config-ext-nacl)# 10 permit tcp 10.0.0.0 0.255.255.255 any eq 80 Router(config-ext-nacl)# 20 permit tcp 10.0.0.0 0.255.255.255 any eq 443 Router(config-ext-nacl)# remark === Block all other traffic and log === Router(config-ext-nacl)# 30 deny ip any any log
12. Verification Commands
! Show all ACLs and their match counters: Router# show ip access-lists ! Show a specific named or numbered ACL: Router# show ip access-lists CORP_FILTER Router# show ip access-lists 110 ! Show which ACLs are applied to which interfaces and in which direction: Router# show ip interface gigabitEthernet 0/0 ... Inbound access list is CORP_FILTER Outbound access list is not set ! Show running-config section for a specific ACL: Router# show running-config | section ip access-list ! Clear ACL hit counters (match statistics) without removing the ACL: Router# clear ip access-list counters CORP_FILTER Router# clear ip access-list counters ! clears all ACL counters
Interpreting show ip access-lists Output
Router# show ip access-lists CORP_FILTER
Extended IP access list CORP_FILTER
10 permit tcp 10.1.0.0 0.0.255.255 any eq www (2341 matches)
20 permit tcp 10.1.0.0 0.0.255.255 any eq 443 (1876 matches)
30 deny ip any any log (47 matches)
Key fields:
- Sequence number (10, 20, 30): order of evaluation
- permit / deny: action applied on match
- Match criteria: protocol, source, destination, port
- (X matches): number of packets that matched this ACE since last counter clear
- A count of 0 on a permit ACE may indicate misconfigured criteria
- A high count on a deny ACE indicates traffic being blocked — investigate source
13. ACL Summary — Key Facts
| Topic | Key Fact |
|---|---|
| Processing order | Top-down — first match wins; remaining ACEs are not evaluated |
| Implicit deny | Every ACL ends with an invisible deny any any —
unmatched traffic is always dropped |
| Standard ACL numbers | 1–99 and 1300–1999 — matches source IP only |
| Extended ACL numbers | 100–199 and 2000–2699 — matches source, destination, protocol, port |
| Standard ACL placement | Close to the destination — avoids over-blocking |
| Extended ACL placement | Close to the source — drops traffic early, saves bandwidth |
| Wildcard 0.0.0.0 | Matches single host — equivalent to host keyword |
| Wildcard 255.255.255.255 | Matches any address — equivalent to any keyword |
| Max ACLs per interface | One inbound + one outbound — only two ACLs per interface |
| Named vs numbered | Named ACLs allow individual ACE editing by sequence number; numbered ACLs require full rewrite to change one entry |
| Interface apply command | ip access-group <name/number> in|out |
| VTY apply command | access-class <name/number> in — restricts
SSH/Telnet management access |