Access Control Lists

Access Control Lists (ACLs) are used to prevent access to specific network resources. There are 4 types of ACLs:

• Standard Numbered ACLs

• Standard Named ACLs

• Extended Numbered ACLs

• Extended Named ACLs

Standard ACLs can only filter access by source IPs. Let’s see some examples:

Standard numbered ACL with the old syntax are configured in global config mode:

R1(config)# access-list 1 deny 172.16.0.0 0.0.0.128         /* drop connections from these subnets */
R1(config)# access-list 1 permit 172.16.0.0 0.0.255.255     /* permit connections from this superset of networks */
R1(config)# access-list 1 permit 192.168.0.5                /* when no wildcard is used /32 is assumed so it is a single host */
R1(config)# access-list 1 remark // internal net ACL //     /* we can add a remark per ACL for clarity sake */
R1(config)# int GigabitEthernet 0/0                         /* ACLs must be applied on a given interface */
R1(config-if)# ip access-group 1 in                         /* choose whether it applies to IN/OUT traffic */

Each “access-list” statement above is an ACE (Access Control Entry).

We can use the old syntax above but we are better off using the new syntax because it allows us to edit existing ACLs:

R1(config)# ip access-list standard 1 
R1(config-std-nacl)# 10 deny 172.16.0.0 0.0.0.128       /* drop connections from this subnets */
R1(config-std-nacl)# 20 permit 172.16.0.0 0.0.0.128     /* let in those from this superset of networks */
R1(config-std-nacl)# remark // internal net ACL //      /* we can add a remark per ACL for clarity sake */
R1(config-std-nacl)# int GigabitEthernet 0/0            /* ACLs must be applied on a given interface */
R1(config-if)# ip access-group 1 in                     /* choose whether it applies to IN/OUT traffic */

For named standard ACLs the syntax is the same:

R1(config)# ip access-list standard vlan350
R1(config-std-nacl)# 10 deny 172.16.0.0 0.0.0.128      /* drop connections from this subnets */
R1(config-std-nacl)# 20 permit 172.16.0.0 0.0.0.128   /* let in those from this superset of networks */
R1(config-std-nacl)# remark // internal net ACL //    /* we can add a remark per ACL for clarity sake */
R1(config-std-nacl)# int GigabitEthernet 0/0           /* ACLs must be applied on a given interface */
R1(config-if)# ip access-group vlan350 in             /* choose whether it applies to IN/OUT traffic */

The integer before the permit/deny indicates the order in which we want the ACEs executed.

A few important remarks about standard ACLs:

• For standard numbered ACLs we can use two ranges: 1-99 and 13001999. So the maximum number of standard numbered ACLs we can have in a device is 800.

• The maximum number of ACEs in an ACL varies by device model but it should not be a constraint in normal circumstances.

• We can only use two ACLs per interface: one for incoming and one for outgoing traffic.

• All ACLs have a last implicit statement of “deny any” unless we explicitly end it with “permit any“.

• Standard ACLs (numbered & named) should be applied to the interface closest to the destination (the IP/network we are protecting).

 
As said before, if we use the old syntax with standard numbered ACLs we cannot modify them. Executing this for instance…

R1(config)# no access-list 1 deny 172.16.0.0 0.0.0.128
R1(config)# do show running-config | include access-list
R1(config)#

… will not delete this specific ACE. It will delete the whole ACL and we will have to re-enter it! If we use the new syntax we can add, update and delete specific ACEs:

R1(config)# ip access-list standard BLOCK_PC1
R1(config-std-nacl)# 10 deny host 192.168.1.5
R1(config-std-nacl)# 20 deny host 192.168.1.10
R1(config-std-nacl)# 30 permit 192.168.1.0 0.0.0.255
 
R1(config-std-nacl)# do show access-list BLOCK_PC1
Standard IP access list BLOCK_PC1
    10 deny host 192.168.1.5
    20 deny host 192.168.1.10
    30 permit 192.168.1.0 0.0.0.255
    40 deny any
 
R1(config-std-nacl)# no 20
R1(config-std-nacl)# do show access-list BLOCK_PC1
Standard IP access list BLOCK_PC1
    10 deny host 192.168.1.5
    30 permit 192.168.1.0 0.0.0.255
    40 deny any
 
R1(config-std-nacl)# 20 deny host 192.168.1.11
R1(config-std-nacl)# do show access-list BLOCK_PC1
Standard IP access list BLOCK_PC1
    10 deny host 192.168.1.5
    20 deny host 192.168.1.11
    30 permit 192.168.1.0 0.0.0.255
    40 deny any
 
R1(config-std-nacl)# 20 deny host 192.168.1.15
R1(config-std-nacl)# do show access-list BLOCK_PC1
Standard IP access list BLOCK_PC1
    10 deny host 192.168.1.5
    20 deny host 192.168.1.15
    30 permit 192.168.1.0 0.0.0.255
    40 deny any
 
R1(config-std-nacl)# 25 deny host 192.168.1.18
R1(config-std-nacl)# do show access-list BLOCK_PC1
Standard IP access list BLOCK_PC1
    10 deny host 192.168.1.5
    20 deny host 192.168.1.15
    25 deny host 192.168.1.18
    30 permit 192.168.1.0 0.0.0.255
    40 deny any

There is no good reason to use the old syntax!

If we want to add a new ACE between two existing ACEs but they are consecutively numbered (e.g. 20 & 21), we can use the resequencing command:

R1(config)# do show access-list BLOCK_PC2
Standard IP access list BLOCK_PC2
    1 deny host 192.168.2.5
    2 deny host 192.168.2.15
    3 deny host 192.168.2.18
    4 permit 192.168.2.0 0.0.0.255
    5 deny any
 
R1(config)# ip access-list resequence BLOCK_PC2 10 10
R1(config)# do show access-list BLOCK_PC2
Standard IP access list BLOCK_PC2
    10 deny host 192.168.2.5
    20 deny host 192.168.2.15
    30 deny host 192.168.2.18
    40 permit 192.168.2.0 0.0.0.255
    50 deny any

The first integer after the ACL-ID (number or name) is the starting number and the 2nd one is the increment. Now we can proceed and add ACEs in-between.

Extended numbered ACLs allow us to filter by source & destination IPs, protocol and destination port. We can use the ranges 100-199 and 2000-2699.

R1(config)# access-list 110 deny tcp 172.22.5.0 0.0.252.255 172.22.0.0 0.0.240.255 eq 22
R1(config)# access-list 110 permit tcp 172.22.0.0 0.0.255.255 172.22.0.0 0.0.240.255 eq 22
R1(config)# int GigabitEthernet 0/0
R1(config-if)# ip access-group 110 in

As seen above, the ACL number determines whether it is standard or extended in the old syntax. It is recommended to use the new syntax for the reasons explained before:

R1(config)# ip access-list extended 110
R1(config-ext-nacl)# 10 deny tcp 172.22.5.0 0.0.252.255 172.22.0.0 0.0.240.255 eq 22
R1(config-ext-nacl)# 20 permit tcp 172.22.0.0 0.0.255.255 172.22.0.0 0.0.240.255 eq 22
R1(config-ext-nacl)# 30 deny ip any any log    /* log any packet that makes it here */
R1(config)# int GigabitEthernet 0/0            /* ACLs must be applied on a given interface */
R1(config-if)# ip access-group 110 in

Extended named ACL are syntactically the same:

R1(config)# ip access-list extended vlan400
R1(config-ext-nacl)# 10 deny tcp 172.22.5.0 0.0.252.255 172.22.0.0 0.0.240.255 eq 22
R1(config-ext-nacl)# 20 permit tcp 172.22.0.0 0.0.255.255 172.22.0.0 0.0.240.255 eq 22
R1(config-ext-nacl)# 30 deny ip any any log    /* log any packet that makes it here */
R1(config)# int GigabitEthernet 0/0            /* ACLs must be applied on a given interface */
R1(config-if)# ip access-group vlan400 in

Extended ACLs allow us to filter by protocol or use “ip” for any.

R1(config)# ip access-list extended BLOCK_VLAN20
R1(config-ext-nacl)# permit ?
    <0-255> An IP protocol number
    ahp Authentication Header Protocol
    eigrp Cisco’s EIGRP routing protocol
    esp Encapsulation Security Payload
    gre Cisco’s GRE tunneling
    icmp Internet Control Message Protocol
    igmp Internet Gateway Message Protocol
    ip Any Internet Protocol
    ipinip IP in IP tunneling
    nos KA9Q NOS compatible IP over IP tunneling
    object-group Service object group
    ospf OSPF routing protocol
    pcp Payload Compression Protocol
    pim Protocol Independent Multicast
    sctp Stream Control Transmission Protocol
    tcp Transmission Control Protocol
    udp User Datagram Protocol

For instance, this ACE will prevent 172.16.1.0/24 from pinging 172.16.2.0/24:

R1(config-ext-nacl)# deny icmp 172.16.1.0 0.0.0.255 172.16.2.0/24 0.0.0.255

Additionally, we can use the tcp/udp protocol for more fine-grained filtering. For example…

R1(config-ext-nacl)# deny tcp 172.16.0.0 0.0.255.255 172.16.32.0 0.0.0.255 eq 443

… would prevent the source network from accessing HTTPS in the target network. The “eq” is the most commonly used operator but we can also use:

• gt = greater than
• lt = lower than
• neq = not equal to
• range x y = from x to y

The port can be specified in either source/destination or both:

R1(config-ext-nacl)# deny tcp 172.16.0.0 0.0.255.255 gt 1023 172.16.32.0 0.0.0.255 eq 443

A final remark for extended ACLs: they should be added to the interface closest to the source. Why? Because if the packets are going to be dropped, we might as well drop them asap!

If we intend to tighten access to the router itself, it is more practical to apply the ACL to the vty lines instead of the different interfaces. See the example below:

R1(config)# ip access-list standard router_access
R1(config-std-nacl)# permit 192.168.1.0 0.0.0.255
R1(config-std-nacl)# deny any
R1(config-std-nacl)# line vty 0 15
R1(config-line# access-class router_access in

What we did is grant access the router’s Telnet/SSH lines only to 192.168.1.0/24. Pay attention to the access-class which applies only to vty lines!

To view current ACLs:

R1# show ip access-lists                /* shows only IP ACLs */
Standard IP access list 1
    10 deny 172.16.0.0 0.0.0.128
    20 permit 172.16.0.0 0.0.255.255
    30 permit 192.168.0.5
    40 deny any
 
R1# show access-lists                  /* show ACLs for all protocols */
R1# show access-list 1                 /* show ACL 1 */
R1# show access-list vlan350           /* show ACL vlan350 */
R1# show running-config | section access-list  /* show all ACLs with remarks that are otherwise hidden */
R1# show interface gi 0/0              /* show interface and its ACLs */

ACLs are processed in the order shown in “show ip access-lists” or “show access-lists” from top to bottom. As soon as an ACE is fully matched (partial matches are not matches!), its permit or deny will be executed and no further ACEs will be processed.
Cisco iOS might re-order the ACEs for the sake of efficiency from more specific to less specific and it will show it in the output of “show”.

 

Port Security <- Previous         Next -> DHCP snooping