Access Control Lists Are the Most-Used Tool on a Cisco Router
Access Control Lists are the Swiss Army knife of Cisco IOS. They filter traffic at interfaces, restrict who can reach the management plane, mark packets for QoS, define interesting traffic for VPN, drive policy-based routing, and feed prefix-lists for routing protocols. Almost every operational change you make on a router touches an ACL somewhere in the chain. Knowing exactly how the five ACL types work — and which one to pick for a given task — pays back every day on the job.
This article walks through Standard, Extended, Named, Reflexive, and Time-based ACLs on Cisco IOS, with the configuration commands, the placement rules, and the gotchas that matter in production.
How an ACL Actually Processes a Packet
Every ACL is a top-down sequential list of permit and deny statements. When a packet hits an interface with an ACL applied, the router walks the list in order, and on the first match it executes that action and stops. Subsequent statements are never evaluated. If the packet falls through every statement, the implicit deny ip any any at the bottom drops it.
Two operational implications:
- Sequence matters. A more-specific permit must come before a broader deny if you want it honored. Reordering an ACL changes its behavior.
- The implicit deny is invisible. An ACL with only permits is not “allow these and let everything else through” — it’s “allow these and silently drop everything else.” Always include an explicit
permit ip any anyif that’s the intent.
For a packet traveling through the router, the order of operations relative to NAT also matters:
- Inbound: ACL is evaluated before NAT translation. Match on the original (pre-NAT) source/destination.
- Outbound: NAT translation happens before the ACL. Match on the post-NAT source/destination.
This catches people configuring outbound ACLs on a NAT router’s outside interface — you have to write the ACL against the public addresses, not the inside ones.
The Five ACL Types
1. Standard ACLs (1–99 / 1300–1999)
Standard ACLs filter on source address only. They’re fast, simple, and the right choice when you don’t need to distinguish protocols or destinations — usually for restricting management access (VTY lines) or filtering route updates.
Router(config)# access-list 10 permit 192.168.1.0 0.0.0.255
Router(config)# access-list 10 permit host 10.0.0.5
Router(config)# access-list 10 deny any log
The 0.0.0.255 is a wildcard mask, not a subnet mask. Wildcard bits set to 0 mean “match this bit exactly”; bits set to 1 mean “don’t care.” 0.0.0.255 matches any address whose first three octets are 192.168.1 — effectively the /24 subnet.
Placement rule for standard ACLs: close to the destination. Because they don’t name a destination, applying one near the source would also block legitimate traffic to other destinations.
2. Extended ACLs (100–199 / 2000–2699)
Extended ACLs filter on protocol, source, destination, and port number. They’re what you reach for to firewall traffic at an interface or define interesting traffic for VPN.
! Allow HTTPS to a specific server, deny everything else inbound:
Router(config)# access-list 110 permit tcp any host 10.0.0.5 eq 443
Router(config)# access-list 110 permit tcp any host 10.0.0.5 eq 22
Router(config)# access-list 110 deny ip any any log
Common operators after the destination port: eq (equal), gt (greater than), lt (less than), neq (not equal), range start end. The established keyword on TCP matches packets with the ACK bit set — useful for letting return traffic of an existing connection through without a fully stateful firewall.
Placement rule for extended ACLs: close to the source. They have full match information, so deny early to save downstream forwarding work.
3. Named ACLs (preferred)
Numbered ACLs are legacy. Named ACLs are the modern way — they have a meaningful name, you can edit individual lines without deleting the whole list, and they support sequence numbers explicitly.
Router(config)# ip access-list extended INBOUND-FROM-INTERNET
Router(config-ext-nacl)# permit tcp any host 203.0.113.5 eq 443
Router(config-ext-nacl)# permit tcp any host 203.0.113.5 eq 80
Router(config-ext-nacl)# deny ip any any log
To insert a line in the middle of an existing named ACL, give it a sequence number that falls between two existing ones:
Router(config)# ip access-list extended INBOUND-FROM-INTERNET
Router(config-ext-nacl)# 15 permit tcp any host 203.0.113.5 eq 22
To delete one line, prefix with no and the sequence number:
Router(config-ext-nacl)# no 15
Use named ACLs for new configurations — the diff in show running-config is also dramatically more readable than three-digit numbers.
4. Reflexive ACLs — Stateful-ish for the Pre-Firewall Era
Reflexive ACLs let return traffic of an established session through automatically — a poor man’s stateful firewall, predating Zone-Based Firewall (ZBF) and Cisco ASA. The pattern: an internal ACL reflects outbound traffic into a temporary entry in a second (external) ACL, which inbound traffic is checked against.
! Outbound: track sessions leaving the LAN
Router(config)# ip access-list extended OUTBOUND
Router(config-ext-nacl)# permit tcp any any reflect TCP-SESSIONS timeout 300
Router(config-ext-nacl)# permit udp any any reflect UDP-SESSIONS timeout 60
Router(config-ext-nacl)# permit icmp any any reflect ICMP-SESSIONS
! Inbound: only allow return traffic of tracked sessions
Router(config)# ip access-list extended INBOUND
Router(config-ext-nacl)# evaluate TCP-SESSIONS
Router(config-ext-nacl)# evaluate UDP-SESSIONS
Router(config-ext-nacl)# evaluate ICMP-SESSIONS
Router(config-ext-nacl)# deny ip any any
! Apply
Router(config)# interface GigabitEthernet0/1
Router(config-if)# ip access-group OUTBOUND out
Router(config-if)# ip access-group INBOUND in
Reflexive ACLs don’t handle protocols that use multiple connections (FTP active mode, SIP) or applications that move ports mid-session. For anything more than basic web/SSH return-traffic protection, run ZBF or a dedicated firewall.
5. Time-Based ACLs
Time-based ACLs only match during a defined schedule — useful for “allow guest WiFi to the Internet only during business hours” or “permit batch jobs only between 02:00 and 04:00.”
Router(config)# time-range BUSINESS-HOURS
Router(config-time-range)# periodic weekdays 08:00 to 18:00
Router(config)# ip access-list extended GUEST-INTERNET
Router(config-ext-nacl)# permit ip 10.99.0.0 0.0.0.255 any time-range BUSINESS-HOURS
Router(config-ext-nacl)# deny ip any any log
The periodic form recurs weekly. Use absolute start … end … for one-shot rules with explicit start/end dates.
Applying an ACL
Two surfaces commonly hold ACLs:
Interfaces
Router(config)# interface GigabitEthernet0/1
Router(config-if)# ip access-group INBOUND in
Router(config-if)# ip access-group OUTBOUND out
An interface can have one ACL per direction. in filters traffic arriving on that interface; out filters traffic leaving.
VTY Lines (management access)
Router(config)# ip access-list standard MGMT-OK
Router(config-std-nacl)# permit 192.168.10.0 0.0.0.255
Router(config)# line vty 0 4
Router(config-line)# access-class MGMT-OK in
Note access-class, not ip access-group. VTY ACLs are how you restrict who can SSH/Telnet to the device. Apply this to every router; an unrestricted VTY is one of the most common findings on a network audit.
Where to Place an ACL
| ACL Type | Placement | Why |
|---|---|---|
| Standard | Close to the destination | Source-only matching means an early drop kills traffic to other valid destinations |
| Extended | Close to the source | Full match information allows early drop and saves transit forwarding |
| VTY | On the device itself | Local-only resource — no upstream router has the context |
Verifying and Troubleshooting
The two commands you reach for:
Router# show access-lists
Router# show ip interface GigabitEthernet0/1 | include access list
show access-lists displays every ACL with hit counts per line — if a permit line has 0 hits, the traffic isn’t matching it. show ip interface | include access list tells you which ACL is currently applied in which direction.
For deep inspection, append log to a deny statement and the router will syslog every match (with the source IP, destination, protocol, port). Use sparingly — on a busy interface, log can saturate the CPU.
Common Pitfalls
- The forgotten implicit deny. An ACL with only
permitlines drops everything not explicitly permitted. Test from the LAN before applying inbound on a WAN interface. - Editing a numbered ACL.
no access-list 110wipes the entire list. To remove one line in a numbered ACL, you have to convert it to a named ACL first or delete-and-recreate the whole thing. Use named ACLs to avoid this. - Wildcard mask vs subnet mask.
0.0.0.255matches a /24, not255.255.255.0. Bits flipped. - Outbound ACL on the NAT outside interface. The router has already translated the source by the time the outbound ACL runs — write the ACL against the public address.
- VTY ACL omitted. Default is wide open. Every internet-facing router (and many internal ones) should have an
access-classon its VTY lines restricting who can manage the device. - One inbound ACL per interface. If you need multiple policies, combine them into one ACL — you cannot stack two ACLs in the same direction.
Conclusion
The five ACL types map cleanly to the jobs that need them:
- Standard for source-only rules (route filtering, VTY restrictions).
- Extended for protocol/port-aware filtering at interfaces.
- Named always preferred — readable and editable line-by-line.
- Reflexive for basic return-traffic state, where ZBF or a real firewall isn’t available.
- Time-based when the rule is itself time-sensitive.
Two habits that pay off: always write named ACLs (even for trivial cases — future-you will thank present-you), and always test the implicit deny by including an explicit deny ip any any log at the bottom so you can see what traffic is being dropped. Quiet drops are the hardest production issue to debug.