How Packets Match a List Entry
A standard access list is composed of a series of rules. These rules are processed in order and describe which packets should be allowed or denied based on their source addresses. The syntax of an entry in a standard access list is:
access-list number action source
The parameters are:
number
A number between 1 and 99, identifying the list for future reference
action
The keyword permit or deny, indicating whether to allow or block the packet
source
The packet's source address
Table 7-1 shows three ways to write the source and destination addresses. In most cases, you'll use address/mask pairs to specify blocks of addresses: if we had to write access lists based on individual IP addresses, they wouldn't be very interesting.
Syntax |
Example |
Explanation |
---|---|---|
address mask |
192.168.2.0 0.0.0.255 |
Describes a block of IP addresses. The mask is used as a wildcard; a one (1) in the mask indicates that we "don't care" about the corresponding bit in the address. A zero (0) in the mask means that the corresponding bit must match exactly. This example specifies addresses from 192.168.2.0 to 192.168.2.255. That is, the wildcard mask says that we ignore the last byte of the address when figuring out whether an address matches. |
host address |
host 192.168.2.1 |
The given address must be matched exactly. |
any |
any |
Any IP address will match. |
7.1.1. Address/Mask Pairs (Wildcards)
Nearly every user starting out with access lists has a problem understanding wildcard masks . The problem is that wildcard masks look like subnet masks, but they aren't; a wildcard is actually the complement of the corresponding subnet mask. For example, to permit any IP traffic to the 192.168.2.0/24 network (i.e., 192.168.2.0 with a subnet mask of 255.255.255.0), we write an access list entry like this:
access-list 10 permit 192.168.2.0 0.0.0.255
Now, let's say that a packet comes along with a destination address of 192.168.2.1. How do we tell if a match occurs? The wildcard mask is bitwise ORed with both the actual destination address and the address given in the access list rule. If the two results are equal, a match occurs and the packet is either permitted or denied. To see how this works, let's look at the bits. Table 7-2 shows the relevant addresses and masks in binary.
Decimal form |
Binary |
|
---|---|---|
Wildcard mask |
0.0.0.255 |
00000000.00000000.00000000.11111111 |
Access list address |
192.168.2.0 |
11000000.10101000.00000010.00000000 |
Destination IP |
192.168.2.1 |
11000000.10101000.00000010.00000001 |
Here is the computation:
WildCard Mask = 00000000.00000000.00000000.11111111 Access List = 11000000.10101000.00000010.00000000 Result One = 11000000.10101000.00000010.11111111 WildCard Mask = 00000000.00000000.00000000.11111111 Destination IP = 11000000.10101000.00000010.00000001 Result Two = 11000000.10101000.00000010.11111111 Result One = Result Two
Because the two results match, the destination address 192.168.2.1 matches the access list. In short, the mask value of 0.0.0.255 means that the last byte of the incoming address can have any value; we don't care about its value. In this case, we match all IP addresses from 192.168.2.0 through 192.168.2.255. Furthermore, since the mask states that we will match any value in the last byte of the incoming address, the last byte of the address in the access list can have any value. That sounds confusing, but all it really means is that 192.168.2.0 0.0.0.255 is the same as 192.168.2.139 0.0.0.255; both address/mask pairs match the same group of addresses (192.168.2.0 through 192.168.2.255).
7.1.2. Computing a Wildcard for a Given Subnet Mask
Because the wildcard mask is the complement of the subnet mask, there's a simple formula for computing the correct wildcard mask for any subnet mask. For each byte of the subnet mask, calculate the corresponding byte of the wildcard mask using the formula:
Wildcard = 255 - Subnet
The wildcard mask that corresponds to a subnet mask of 255.255.255.224 (30 hosts per subnet) is 0.0.0.31 (255 - 224 = 31). Here are two access list entries using this wildcard mask:
! For a network of 192.168.2.64 255.255.255.224 access-list 10 permit 192.168.2.64 0.0.0.31 ! ! For a network of 192.168.2.96 255.255.225.224 access-list 10 permit 192.168.2.96 0.0.0.31
7.1.3. Access List Processing
Most of the access lists we have seen so far have consisted of a single rule. But access lists frequently contain many rules. In this case, rules are processed sequentially. The source address of each packet is tested against each rule in the list, starting with the first and ending when a match occurs. Let's take the example in the beginning of this chapter, which permitted everything except traffic from two particular subnets. Here is what the list looked like:
access-list 1 deny 10.10.1.0 0.0.0.255 access-list 1 deny 10.10.2.0 0.0.0.255 access-list 1 permit any
The router processes each line in order until it finds a match. Therefore, if a packet arrives from 10.10.2.13, it matches the second rule in the list and so is denied. What happens if we change the list, placing the last line first?
access-list 1 permit any access-list 1 deny 10.10.1.0 0.0.0.255 access-list 1 deny 10.10.2.0 0.0.0.255
Now all traffic would be permitted through this list. The first line permits all traffic because all incoming packets match it. The second and third lines are never used because processing stops when a match is found, and the first line matches all IP addresses. For this reason, access lists must be ordered carefully.
7.1.4. Implicit Deny
Every time you create an access list, the router adds a line to the end stating, "If nothing matched this list, deny it." If we could see it, this line would look like this:
access-list 1 deny any
All traffic that makes it to the end of an access list is blocked by the implicit deny . This helps us write more efficient access lists. It would be a pain to write access lists that listed every host (and, for extended lists, every port) you want to permit and every host (and port) you want to deny. Furthermore, the router overhead for processing such large lists would be prohibitive. However, you can take advantage of the implicit deny to write lists that itemize only the traffic you want to permit. Don't bother to list traffic you want to denyit will be handled by the implicit deny. (But do be careful not to inadvertently permit traffic you want to deny.) A good rule of thumb for designing access lists is to use lots of permit rules and relatively few deny rules.
7.1.5. Access Lists Are Additive
Access lists cannot be freely edited once they have been entered in the router's configuration. If you want to change a single entry in the list, the entire list must be deleted and then re-entered. For example, consider this list:
access-list 1 deny host 10.10.1.5 access-list 1 deny host 10.10.1.7
After typing this list, you realize there is a mistake: in the first line, the IP address 10.10.1.5 should be 10.10.1.17. Your first attempt to fix the problem is to add another rule by typing:
access-list 1 deny host 10.10.1.17
This new rule is simply added to access list 1. The result is that you're now denying access by 10.10.1.17but you are also denying access by 10.10.1.5, which wasn't your original intent. Can you fix this problem by adding a fourth rule that explicitly permits access from 10.10.1.5? No. Because rules are processed in order, the first line (denying access) will always be processed before the additional line permitting access. So, can you delete the first line? Trying to do so, you type:
no access-list 1 deny host 10.10.1.5
This doesn't work either, because instead of deleting just one line, the router sees no access-list 1 and removes the entire list. It is a common mistake to think that a single rule can be deleted from an access list. If you make a mistake in an access list, or want to change it for some reason, your best approach is to delete the entire list and build it again from scratch. Modifying an existing list usually isn't a good idea. In this case, to fix your list you would enter:
no access-list 1 access-list 1 deny host 10.10.1.17 access-list 1 deny host 10.10.1.7
The best way to edit access lists is to keep an editor open with the access list in it. After you have modified your list, simply paste it into the router. That way, if you make a mistake, you can easily change it within your editor and paste it again.
7.1.6. Outbound Access Lists Are More Efficient Than Inbound
It is much more efficient to filter outgoing packets than to filter incoming packets. This is counterintuitive; at first glance, it seems that filtering incoming packets would save the router from processing all the blocked packets and routing them through to an outbound port. The difference is that an outgoing packet has already been routed (i.e., an outbound interface has been selected for it) before the access list processes it. Incoming packets must be processed by the access list before they arrive, and that's where the problem lies. Processing the access list first means that the router can't use its fast-switching paths and must process-switch the packet. What does this mean? Normally, the router has a cache of routes, which allows it to look up a known route quickly. With an inbound access list, the router can't use this cache and is forced to select the route another way.
In addition, an outbound access list is often smaller than the corresponding incoming list. For example, if a packet is coming in one interface, you have to write an inbound access list that considers all the possible routes the packet might take. On an outbound list, you already have a lot of information about the packet's destination (e.g., which interface it's going through), which allows you to write shorter, more efficient access lists.
This isn't to say that inbound access lists shouldn't be used. There are plenty of times when you need to use an inbound access list; I'll cover some of these in the next few sections.