5.2 ACLs and Control Plane Policing¶
Blueprint 5.2: Configure and verify infrastructure security features
- 5.2.a ACLs
- 5.2.b CoPP
Infrastructure security protects the network devices themselves and controls what passes through them. ACLs are the basic tool for both. CoPP reuses ACLs inside the Modular QoS CLI (MQC) to protect the route processor from being overwhelmed. Expect configuration exhibits where you must work out which host gets through, plus a lab item where you build an ACL or a CoPP policy and prove it works.
ACL types¶
| Type | Matches on | Numbers | Named form | Place it |
|---|---|---|---|---|
| Standard | Source IPv4 address only | 1 to 99, 1300 to 1999 | ip access-list standard NAME |
Close to the destination |
| Extended | Protocol, source, destination, ports, flags, DSCP and more | 100 to 199, 2000 to 2699 | ip access-list extended NAME |
Close to the source |
| IPv6 | Like extended, IPv6 only. Always named | none | ipv6 access-list NAME |
Close to the source |
Named ACLs are the better habit: the name documents the purpose, and you can insert or delete individual entries by sequence number. Numbered ACLs entered in global configuration can also be edited by sequence number in current releases, through ip access-list extended 101 for example.
Wildcard masks¶
A wildcard mask has a 0 where the bit must match and a 1 where any value is allowed. For a contiguous mask, the wildcard is 255.255.255.255 minus the subnet mask.
| Need to match | Address and wildcard | Keyword form |
|---|---|---|
| One host | 10.1.1.10 0.0.0.0 | host 10.1.1.10 |
| Everything | 0.0.0.0 255.255.255.255 | any |
| 10.1.1.0/24 | 10.1.1.0 0.0.0.255 | |
| 172.16.32.0/20 (172.16.32.0 to 172.16.47.255) | 172.16.32.0 0.0.15.255 | |
| 10.1.1.0/30 | 10.1.1.0 0.0.0.3 | |
| Odd-numbered hosts in 10.1.1.0/24 | 10.1.1.1 0.0.0.254 | (non-contiguous, valid in ACLs) |
How an ACL is processed¶
- Entries are checked from the lowest sequence number up.
- The first match decides. Nothing after it is checked.
- If nothing matches, the implicit deny at the end drops the packet. It never appears in
show access-listsand never counts matches, so add an explicitdeny ip any any logif you want to see what it drops. - One ACL per interface, per direction, per protocol (one IPv4 inbound, one IPv4 outbound, one IPv6 inbound, one IPv6 outbound).
graph TB
P["Packet arrives on Gi1"] --> Q{"Inbound ACL on Gi1?"}
Q -- "no" --> RT["Route lookup"]
Q -- "yes" --> E1{"Entry 10 matches?"}
E1 -- "yes" --> ACT1["Apply its permit or deny, stop"]
E1 -- "no" --> E2{"Entry 20 matches?"}
E2 -- "yes" --> ACT2["Apply its permit or deny, stop"]
E2 -- "no" --> IMP["Implicit deny any"]
ACT1 --> RT
RT --> O{"Outbound ACL on exit interface?"}
O -- "permit or none" --> OUT["Forward"]
O -- "deny" --> DROP["Drop"]
Exam trap
An outbound ACL does not filter packets the router generates itself (routing updates, pings sourced by the router, syslog). It filters only traffic routed through the router and out that interface. If an exhibit shows ip access-group X out and asks whether the router's own ping is blocked, the answer is no.
Exam trap
Applying an ACL name that does not exist yet (ip access-group NOT-YET in) does not block anything on IOS: an undefined IPv4 ACL on an interface permits all traffic. The moment you create the ACL with a single entry, the implicit deny takes effect. Build the ACL first, apply it second, and always end with the permit you need.
Extended ACL syntax¶
{permit | deny} protocol source source-wildcard [operator port]
destination destination-wildcard [operator port]
[established] [dscp value] [log | log-input]
| Operator | Meaning | Example |
|---|---|---|
eq |
Equal to | eq 443 or eq www |
neq |
Not equal | neq 23 |
lt / gt |
Less than / greater than | gt 1023 |
range |
Inclusive range | range 20 21 |
- The source port sits after the source address and the destination port after the destination address. Putting
eq 80after the source when you meant the destination is a classic mistake: it then matches packets from port 80, which is web replies, not requests. establishedmatches TCP segments with the ACK or RST bit set. It lets return traffic of sessions started from inside come back in, without a stateful firewall.logsends a syslog message for matches. Messages are rate-limited and summarised, so they are not a packet capture.log-inputadds the input interface and source MAC.
Building and editing a named ACL¶
ip access-list extended EDGE-IN
10 permit tcp 10.10.10.0 0.0.0.255 host 172.16.1.10 eq 443
20 permit udp 10.10.10.0 0.0.0.255 host 172.16.1.53 eq domain
30 permit icmp 10.10.10.0 0.0.0.255 any echo
40 deny ip 10.10.10.0 0.0.0.255 172.16.1.0 0.0.0.255 log
50 permit ip 10.10.10.0 0.0.0.255 any
!
interface GigabitEthernet2
ip access-group EDGE-IN in
!
! Insert a rule between 10 and 20, then remove one
ip access-list extended EDGE-IN
15 permit tcp 10.10.10.0 0.0.0.255 host 172.16.1.10 eq 22
no 30
!
ip access-list resequence EDGE-IN 10 10
ipv6 access-list V6-EDGE-IN
permit tcp 2001:db8:10::/64 host 2001:db8:172::10 eq 443
deny ipv6 2001:db8:10::/64 2001:db8:172::/64 log
permit ipv6 any any
interface GigabitEthernet2
ipv6 traffic-filter V6-EDGE-IN in
IPv6 ACLs are applied with ipv6 traffic-filter, not ip access-group. Before their implicit deny ipv6 any any, they also have implicit permits for neighbor solicitation and neighbor advertisement so that neighbor discovery keeps working. An explicit deny ipv6 any any at the end removes that protection.
Exam trap
A standard ACL that only has deny entries blocks everything, because of the implicit deny. access-list 10 deny host 10.1.1.5 applied to an interface stops all IPv4 traffic, not only 10.1.1.5. You need access-list 10 permit any after it.
Verifying ACLs¶
R1# show access-lists EDGE-IN
Extended IP access list EDGE-IN
10 permit tcp 10.10.10.0 0.0.0.255 host 172.16.1.10 eq 443 (1284 matches)
15 permit tcp 10.10.10.0 0.0.0.255 host 172.16.1.10 eq 22 (37 matches)
20 permit udp 10.10.10.0 0.0.0.255 host 172.16.1.53 eq domain (412 matches)
40 deny ip 10.10.10.0 0.0.0.255 172.16.1.0 0.0.0.255 log (9 matches)
50 permit ip 10.10.10.0 0.0.0.255 any (20311 matches)
R1# show ip interface GigabitEthernet2 | include access list
Outgoing access list is not set
Inbound access list is EDGE-IN
R1# clear ip access-list counters EDGE-IN
The match counters are your best troubleshooting tool. Generate the traffic, then see which line the counter moves on. If a line you expect never moves, an earlier line is catching the traffic or the ACL is applied in the wrong place or direction.
Control Plane Policing (CoPP)¶
A router has three planes:
| Plane | What it handles | Example traffic |
|---|---|---|
| Data (forwarding) | Transit packets, switched in hardware or CEF | User traffic passing through |
| Control | Packets addressed to or punted to the route processor | OSPF, BGP, ARP, HSRP, ICMP to the router, TTL-expired packets |
| Management | Traffic used to manage the box | SSH, SNMP, NETCONF, syslog |
The route processor CPU handles everything that is not simply forwarded. A flood of pings or SSH connection attempts aimed at the router can starve the CPU so that routing protocol hellos are missed and adjacencies drop. CoPP is a QoS policy attached to the control plane that rate-limits each kind of traffic before it reaches the CPU.
graph LR
IN["Incoming packets"] --> FW{"Destined to<br/>the router?"}
FW -- "no: transit" --> HW["Forwarded, CoPP not involved"]
FW -- "yes or punted" --> CP["control-plane<br/>service-policy input COPP"]
CP --> C1["CM-ROUTING<br/>OSPF, BGP: generous"]
CP --> C2["CM-MGMT<br/>SSH, SNMP: moderate"]
CP --> C3["CM-ICMP<br/>low rate"]
CP --> C4["CM-UNDESIRABLE<br/>drop"]
CP --> C5["class-default<br/>low rate"]
C1 & C2 & C3 & C5 --> CPU["Route processor"]
Building a CoPP policy¶
CoPP uses the same three MQC steps as QoS: classify with class-maps, act with a policy-map, attach with service-policy. The difference is where it is attached.
! 1. ACLs select traffic. permit = "belongs to this class"
ip access-list extended COPP-ROUTING
permit ospf any any
permit tcp any any eq bgp
permit tcp any eq bgp any
ip access-list extended COPP-MGMT
permit tcp 192.168.100.0 0.0.0.255 any eq 22
permit udp 192.168.100.0 0.0.0.255 any eq snmp
ip access-list extended COPP-ICMP
permit icmp any any
ip access-list extended COPP-UNDESIRABLE
permit tcp any any eq telnet
permit udp any any eq tftp
!
! 2. Class-maps
class-map match-all CM-ROUTING
match access-group name COPP-ROUTING
class-map match-all CM-MGMT
match access-group name COPP-MGMT
class-map match-all CM-ICMP
match access-group name COPP-ICMP
class-map match-all CM-UNDESIRABLE
match access-group name COPP-UNDESIRABLE
!
! 3. Policy-map. Rates are in bits per second
policy-map COPP
class CM-UNDESIRABLE
drop
class CM-ROUTING
police 1000000 conform-action transmit exceed-action transmit
class CM-MGMT
police 512000 conform-action transmit exceed-action drop
class CM-ICMP
police 32000 conform-action transmit exceed-action drop
class class-default
police 64000 conform-action transmit exceed-action drop
!
! 4. Attach to the control plane
control-plane
service-policy input COPP
Design notes:
- Routing protocol traffic is matched first and usually never dropped. Here it is policed with
exceed-action transmit, which only measures it. That way the counters show if routing traffic ever exceeds the expected rate. - Undesirable traffic is dropped outright. Put it near the top so it is caught before broader classes.
- class-default catches everything else, including ARP on many platforms unless you classify it separately. Police it, but never drop it entirely, or you will break things you forgot about.
- Start with generous rates and
exceed-action transmitto baseline what normal looks like, then tighten.
Exam trap
In a CoPP or QoS class-map, the ACL is only a classifier. A deny entry does not drop the packet; it means "not in this class", and the packet moves on to the next class. To drop traffic, match it with permit and give the class a drop or a policer whose actions drop.
Exam trap
CoPP is attached with service-policy input under control-plane, not on an interface. It only affects traffic to or punted to the route processor. If a question asks how to stop a flood of pings through the router, CoPP is the wrong tool; use an interface ACL or a QoS policer on the interface.
Catalyst 9000 switches
Catalyst 9000 switches ship with a system-defined CoPP policy (system-cpp-policy) that is attached by default. You tune the rates of its predefined classes rather than replacing it with your own policy. Routers such as the Catalyst 8000 series and ISR 4000 use the user-defined control-plane policy shown on this page. Check the configuration guide for your platform before you change CoPP.
Verifying CoPP¶
R1# show policy-map control-plane
Control Plane
Service-policy input: COPP
Class-map: CM-UNDESIRABLE (match-all)
24 packets, 1440 bytes
5 minute offered rate 0000 bps, drop rate 0000 bps
Match: access-group name COPP-UNDESIRABLE
drop
Class-map: CM-ROUTING (match-all)
5321 packets, 431002 bytes
5 minute offered rate 2000 bps, drop rate 0000 bps
Match: access-group name COPP-ROUTING
police:
cir 1000000 bps, bc 31250 bytes
conformed 5321 packets, 431002 bytes; actions:
transmit
exceeded 0 packets, 0 bytes; actions:
transmit
Class-map: CM-ICMP (match-all)
18342 packets, 25678800 bytes
5 minute offered rate 241000 bps, drop rate 209000 bps
Match: access-group name COPP-ICMP
police:
cir 32000 bps, bc 1500 bytes
conformed 2210 packets, 3094000 bytes; actions:
transmit
exceeded 16132 packets, 22584800 bytes; actions:
drop
...
Output is trimmed and the burst values depend on the platform. Read it top to bottom: packets per class, the offered rate, and the conformed and exceeded counters. A ping flood shows up as a high exceeded count in CM-ICMP while CM-ROUTING stays clean, which is exactly what CoPP is for.
| Symptom | Likely cause |
|---|---|
| Traffic you expected in a class lands in class-default | ACL entry missing, wrong direction of ports, or match-all with conditions that can not all be true |
| SSH from the NOC is slow or drops under load | Management class policed too low, or the NOC subnet is missing from the ACL so it falls to a tight class-default |
| OSPF or BGP flaps during an attack | Routing traffic not classified first and is sharing a class with the flood |
| Policy configured but counters never move | Policy not attached with service-policy input under control-plane |
Lab: an ACL and a CoPP policy on R1¶
Topology: base topology from Lab Setup. R1 (Catalyst 8000v) with Gi2 facing DIST1 and the user VLAN 10.10.10.0/24, Gi1 on the management LAN 192.168.100.0/24 with Host1 at 192.168.100.10. OSPF runs between R1 and R2.
- Save a baseline.
- Build
EDGE-INfrom this page so that users can reach 172.16.1.10 (use R2's Loopback, renumbered or added as 172.16.1.10/32) on TCP 443 and 22 only, ping anything, and reach everything outside 172.16.1.0/24. Apply it inbound on R1's user-facing interface. - From a user host, test HTTPS (or
telnet 172.16.1.10 443from an IOSv host) and SSH. Check which counters moved withshow access-lists EDGE-IN. - Move the
eq 443from after the destination to after the source on line 10. Test again: HTTPS now fails and line 40 counts. Fix it. - Build the CoPP policy from this page with CM-ICMP policed to 16 kbps. Attach it to the control plane.
- From Host1, flood R1:
sudo ping -f -s 1400 192.168.100.1(or from an IOSv host, an extended ping with repeat 10000, size 1400, timeout 0). - Watch
show policy-map control-plane class CM-ICMP. Expected: the exceeded counter climbs, most pings fail, andshow ip ospf neighborstays FULL. - Change the CoPP ACL for ICMP from
permit icmp any anytodeny icmp any any. Repeat the flood. Expected: CM-ICMP stops counting and the pings are now policed by class-default instead. That is the "deny means not this class" behaviour.
Quick check¶
Which addresses does 172.16.32.0 0.0.15.255 match?
172.16.32.0 to 172.16.47.255, a /20. The 15 in the third octet frees the low four bits, so third octet values 32 to 47 match.
A CoPP policy has no class for SNMP and class-default is policed to 8 kbps. SNMP polling from the NMS times out. Why?
SNMP falls into class-default and shares 8 kbps with everything else that is unclassified. Give SNMP from the NMS its own class with a suitable rate, matched before class-default.
Why does permit tcp any eq 80 any not match a user's web request?
eq 80 after the source matches the source port. A browser's request has destination port 80 and a high source port. The entry would match the server's replies instead.
References¶
- Cisco IOS XE Security Configuration Guide: "IP Access List Overview" and "Creating an IP Access List and Applying It to an Interface" (search on cisco.com)
- Cisco IOS XE QoS Configuration Guide: "Control Plane Policing" (search on cisco.com for your platform)
- Cisco Guide to Harden Cisco IOS Devices, section on infrastructure ACLs and CoPP (search on cisco.com)
- RFC 6192: Protecting the Router Control Plane, at rfc-editor.org
- Cisco Live On-Demand Library: search "control plane protection" and "infrastructure security"
Unlock the full question banks and cram sheets
A free account opens every question bank, the timed practice exams, the printable cram sheets, all the simulations and the lab files. Without one you see a 5-question sample of each.
No card needed. Study tips by email are optional and off unless you tick the box. Your address is never sold or shared. Privacy policy ยท Terms
Signed in as . Your account
You're on the free account, so lessons after the first module, question banks, exams and cram sheets show a sample. See Track Pass and All-Access
Also from NetManager Systems: NetManager, network monitoring for multi-vendor networks. Try the NetManager, NetDiag, PCAP Analyzer and OpsDash demos: every new account gets a free 7-day read-only login to each.