Access Control Lists (ACLs) – Part 2

In ACLs – Part 1 we learned the basics of access lists, including the facts that ACLs:

  • Are created in global config mode
  • End with an implicit “deny any” (which can be overridden)
  • Must be placed into service somewhere to have any effect

Thus, the commands:

  • Router#conf t
  • Router(config)#access-list 3 deny 172.16.1.1
  • Router(config)#access-list 3 deny 172.16.1.2
  • Router(config)#access-list 3 deny 172.16.1.3
  • Router(config)#access-list 3 permit any
  • Router(config)#interface g1/2
  • Router(config-if)#ip access-group 3 out

Will create an ACL 3 (denying traffic from hosts 172.16.1, 2 and 3, while permitting all other traffic), and place it in service on the GigEthernet1/2 interface in the outbound direction.

An ACL placed inbound on a router interface will control the traffic that’s allowed to enter the router via that interface. You would think, therefore, that an ACL placed outbound on a router interface (such as ACL 3 above) would likewise control the traffic that’s allowed to leave the router via that interface. This is also true, except for traffic that was generated by the router itself. In other words, an outbound ACL will affect only traffic attempting to transit the router, not traffic originated by the router.

Let’s look at another example. In this case, we’d like to use ACL 4 inbound on the Serial 1/1 interface to permit traffic from all hosts on the 192.168.1.0 network, and deny all other traffic. We could start as before:

  • Router#conf t
  • Router(config)#access-list 4 permit 192.168.1.1
  • Router(config)#access-list 4 permit 192.168.1.2

But wait … the Class “C” network 192.168.1.0 covers 254 hosts (192.168.1.1 through 192.168.1.254), which would require 254 lines in the ACL. Obviously listing each host address one by one is a non-scalable solution (and imagine what would happen with a Class “B” or a Class “A” network). What we need is a system to shorten the list. Such a system exists, and it makes use of a “wildcard” mask. The rules for IPv4 wildcard masks are simple:

  • Wildcard masks are thirty-two bits long (just like IPv4 addresses).
  • A “zero” bit in a WCM means match the corresponding address bit.
  • A “one” bit in a WCM means ignore the corresponding address bit.
  • WCMs are represented in dotted-decimal (just like IPv4 addresses).
  • WCMs follow addresses.

Okay, let’s use a wildcard mask to solve our example. What we want is to match the first three octets (the “192.168.1” part), and ignore the fourth octet. Thus, we could match the entire 192.168.1.0 network like this:

  • Router(config)#access-list 4 permit 192.168.1.0 0.0.0.255

How does it work? In ACL 4, you see that there is an address (192.168.1.0), followed by a wildcard mask (0.0.0.255). The first octet of the dotted-decimal wildcard mask is a zero, which represents eight binary zeros. Since a zero in a WCM means “match”, these eight zeros in the WCM mean match the first octet of the address (the “192” part).

Likewise, the second and third octets of the WCM are also zeros, meaning that the second and third octets of the address (“168” and “1”, respectively) must be matched exactly. Finally, the fourth octet of the WCM is a “255”, which is all ones in binary. Since a “1” means ignore, the ACL ignores the entire last octet of the address, meaning that it could have any value (0 through 255). Since this covers the range of legal host addresses on network 192.168.1.0, it meets the requirements stated above.

The only thing left to do is to place the ACL in service on the interface:

  • Router(config)#int serial 1/1
  • Router(config-if)#ip access-group 4 in

Those of us who are particularly geeky (!) might have noticed that the “permit” statement above not only permits the range of legal hosts, it also permits the reserved addresses of 192.168.1.0 and 192.168.1.255 (the “network” and “broadcast” addresses). Since those addresses will never be assigned to hosts, this isn’t an operational problem. And one more thing … you’ll recall that the default subnet mask for a Class “C” network is “255.255.255.0”. If we simply flip the bits of the subnet mask (zeros become ones, ones become zeros), we’d have “0.0.0.255”, which is the wildcard mask we want. More on this later!

Note that we can also represent the “permit any” at the end of ACL 3 as:

  • Router(config)#access-list 3 permit 0.0.0.0 255.255.255.255

While this is syntactically correct, if you type it into a router, IOS will display it as “permit any” (which is easier to read), so that’s the way you might as well enter it.

Now that we have a nifty method of representing large blocks of addresses, let’s write and apply an ACL that will deny packets sent from hosts with “private” addresses, and permit packets from hosts with “public” addresses. The first question, then, is what are the “private” and “public” addresses?

Per RFC 1918, the private address ranges are:

  • Class “A” – 10.0.0.0/8
  • Class “B” – 172.16.0.0/12
  • Class “C” – 192.168.0.0/16

Everything else in the Class “A”, “B” and “C” ranges is “public”. Thus, we need an ACL that denies the above listed address ranges, and permits everything else. Let’s use ACL 5, and place it on Serial 0/0.123 (a Frame Relay subinterface) outbound. We’ll take it one line at a time. First, let’s handle network 10.0.0.0, a Class “A” network. Since we’re interested in matching the network portion (the first octet), and ignoring the host portion (the last three octets), the wildcard mask should be “0.255.255.255”. Thus, the first line in ACL 5 is:

  • Router(config)#access-list 5 deny 10.0.0.0 0.255.255.255

Next, we’ll look at the second line, which involves the Class “B” address space 172.16.0.0/12. Note that the mask here is a “/12”, not the default Class “B” mask of “/16”. As you may recall from route summarization, moving four bits to the left (from 16 to 12) results in a block of 16 (two to the fourth) networks. Therefore, this address space encompasses the 172.16.0.0 through 172.31.0.0 networks. We could list these sixteen networks individually, thus:

  • Router(config)#access-list 5 deny 172.16.0.0 0.0.255.255
  • Router(config)#access-list 5 deny 172.17.0.0 0.0.255.255
  • (Twelve more lines for 18 through 29 go here)
  • Router(config)#access-list 5 deny 172.30.0.0 0.0.255.255
  • Router(config)#access-list 5 deny 172.31.0.0 0.0.255.255

Note that the wildcard mask on each line is “0.0.255.255” because we care about the first two octets (the network portion), but not about the last two (the host portion).

There is, however, a more elegant way. In fact, we can cover the Class “B” private networks in one line. Since the mask on the Class “B” address space is a “/12”, it means that we only care about the first twelve bits of the address space, and can ignore the last twenty (remember, there are a total of 32 bits in an address). Since a zero in a WCM means “match” the corresponding address bit, and a one means “ignore”, the WCM in binary would be twelve zeros, followed by twenty ones, thus:

  • 00000000.00001111.11111111.11111111

This can be represented in dotted-decimal as “0.15.255.255”, which is the format we want for a wildcard mask. Another method for determining the WCM is to note that a “/12” (the mask specified with the address space) is “255.240.0.0”, and if we simply flip the bits, we get “0.15.255.255”, which is exactly the WCM we need. An easy way to flip the bits is to just subtract each octet of a mask (255.240.0.0) from 255:

  • First octet: 255 – 255 = 0
  • Second octet: 255 – 240 = 15
  • Third octet: 255 – 0 = 255
  • Fourth octet: 255 – 0 = 255

Since the address space begins with 172.16.0.0, and the WCM is 0.15.255.255, the second line of the ACL should be:

  • Router(config)#access-list 5 deny 172.16.0.0 0.15.255.255

Next, we need to take care of the Class “C” address space. Notice that the mask specified is a “/16”. Since the default mask for a Class “C” is “/24”, and “/16” is eight bits to the left of that, this represents a block of 256 (two to the eighth) Class “C” networks (those starting with “192.168”). Similar to what we did with the Class “B” block, we can just flip the bits of the summary mask (“/16”, or 255.255.0.0) to get 0.0.255.255, which is the wildcard mask we need (match the first two octets of “192.168”, and ignore the last two). Since the address space starts with 192.168.0.0, the third line of ACL 5 should be:

  • Router(config)#access-list 5 deny 192.168.0.0 0.0.255.255

What we have at this point is an ACL that denies the private address space, but what about the public addresses? Remember that ACLs act as if they have a “deny any” at the bottom. We want to permit everything that wasn’t denied, so we need to finish the ACL with a “permit any” line:

  • Router(config)#access-list 5 permit any

Altogether then, the list is:

  • Router(config)#access-list 5 deny 10.0.0.0 0.255.255.255
  • Router(config)#access-list 5 deny 172.16.0.0 0.15.255.255
  • Router(config)#access-list 5 deny 192.168.0.0 0.0.255.255
  • Router(config)#access-list 5 permit any

Now, of course, we have to invoke it on the interface:

  • Router(config)#interface s0/0.123
  • Router(config-subif)#ip access-group 5 out

That’s it for now. Next time, we’ll do more (lots more!) with access-lists.

Author: Al Friebe

In this article

Join the Conversation