1. 为什么要用ACL:没有访问控制的网络,就像不设门禁的机房
先讲一个我早年间带新人时常说的场景:某公司内网里,财务部服务器存放着全公司的薪资数据和报表。网络拓扑很简单,所有部门在一个网段,大家互相能通。某个实习生心血来潮,在自己的工位上Ping了一下财务服务器的IP,通了,又随手试了一下445端口的共享文件夹,结果真的弹出了文件列表。那一刻他有点慌了,赶紧关掉窗口,但这件事要是被别人用同样的方式做了呢?网管根本不知道,因为交换机不喊不叫,默认放行一切流量。
这就是ACL存在的根本理由:在网络设备上定义一套规则,告诉设备“哪些流量能过,哪些流量必须丢”。思科官方对ACL(Access Control List)的定义并不复杂——一系列允许或拒绝语句的集合,但很多人学ACL时只学会了敲命令,没学会怎么用它解决实际问题。本文就用Cisco Packet Tracer这个模拟器,把标准访问控制列表从原理到配置、从踩坑到验证完整过一遍。看完之后,你不仅能在一台路由器上写出能用的ACL,还能明白什么时候该用标准ACL、什么时候该换扩展ACL、为什么规则顺序写错了会造成全网故障。
学这篇内容适合哪些人?正在备考CCNA的人,上课听得懂但一碰设备就懵的在校生,以及刚入职需要配置公司网络设备但不敢乱动生产环境的实习网工。Packet Tracer最大的价值就是让你随便折腾,命令敲错了重启设备就能恢复,这种试错成本在真实设备上是没有的。
关于思科模拟器里的ACL实操,市面上教程很多,但大多数只告诉你“先access-list然后ip access-group”,没有讲通配符掩码究竟在匹配什么、为什么标准ACL只能基于源地址、为什么ACL一定要在接口方向选对之后才生效。这些细节才是真正让人从“会敲命令”变成“会排错”的关键。下面直接从标准ACL的原理开始拆。
2. 标准ACL的工作机制:规则顺序、通配符掩码与隐含拒绝
2.1 标准ACL到底匹配什么
标准ACL(编号范围1到99,扩展编号1300到1999)最核心的特征是:只匹配源IP地址。它不关心你要去访问哪个服务器、用的是HTTP还是Telnet、源端口是几千还是几万——只要报文的源地址落在ACL规则指定的范围内,这条规则就生效。这就是它和扩展ACL的本质区别。
这个特性决定了标准ACL的使用位置:尽量部署在靠近目标的那一侧。为什么?举例来说,公司有三个网段:研发部192.168.10.0/24、市场部192.168.20.0/24、核心服务器区192.168.100.0/24。你希望禁止研发部访问服务器区的某些服务,但又不影响市场部。如果ACL只匹配源地址,那么把它放在研发部网关的出口和放在服务器区网关的入口,效果会有很大差别:放在研发部出口,规则会影响研发部访问外面所有网段的流量;放在服务器区网关入口,规则只影响进入服务器区的流量。所以标准ACL不适合靠近源端部署,否则容易误伤。这就是为什么你经常看到标准ACL被挂在离目标最近的接口上,哪怕这样会让不需要经过该接口的流量白白穿越整个网络。这是一个典型的“用正确的位置弥补工具功能单一”的工程思路。
2.2 通配符掩码:不是子网掩码
通配符掩码(Wildcard Mask)是ACL配置里最容易让人糊涂的概念。它和子网掩码写法长得像,但规则完全相反:子网掩码里,1代表必须匹配,0代表可以不匹配;通配符掩码里,0代表必须匹配,1代表随意。翻译成人话:通配符掩码中的0表示IP地址对应的那一位必须精确一样,1表示这一位不用管,0和1都能通过。
主机192.168.1.1的通配符掩码:0.0.0.0 等价写法:host 192.168.1.1 整个192.168.1.0/24网段的通配符掩码:0.0.0.255 等价写法:192.168.1.0 0.0.0.255 所有IP地址的通配符掩码:255.255.255.255 等价写法:any计算方法是:子网掩码按位取反。255.255.255.0取反就是0.0.0.255,所以192.168.1.0 0.0.0.255就匹配192.168.1.0到192.168.1.255这个范围。这个规则不需要死记,理解取反逻辑后自然就记住了。
但是有几个不连续网段的场景会让人掉头发。比如要匹配192.168.1.0/24和192.168.3.0/24两个网段,但不匹配192.168.2.0/24。用标准ACL的源地址匹配来做,通配符掩码会变得很诡异。有些资料会给出192.168.1.0 0.0.2.255这种写法,但实际工程中没人这么干——遇到不连续网段的需求,首选方案是写多条ACL语句,或者换用扩展ACL。标准ACL本身就不是为这种精细匹配设计的,强行用通配符去凑不连续地址,只会给自己留下排错隐患。
2.3 隐含拒绝规则:ACL的最后一句话
ACL最坑人的特性在于它的结尾有一条看不见的规则:deny any。也就是说,配置ACL时只写了允许谁谁谁,最后没写deny any,系统也会自动把所有不在规则列表里的流量全部丢掉。很多人配置完ACL后网络不通,排查了半天,最后发现是因为只写了放行语句,忘了还有一个隐含拒绝在悄悄工作。
理解隐含拒绝,需要先理解ACL的匹配顺序:数据包到达接口后,从ACL列表的第一行开始逐行比对,一旦匹配到某条规则,就立即执行该规则的允许或拒绝操作,后面所有规则不再检查;如果所有规则都不匹配,最终落到隐含拒绝,丢弃。
比如说我定义了这样两条规则:
access-list 1 permit 192.168.10.0 0.0.0.255 access-list 1 deny 192.168.20.0 0.0.0.255实际效果是192.168.10.0/24的流量放行,192.168.20.0/24的流量丢弃,其他任何地址的流量同样丢弃。这个“其他任何地址”就是隐含拒绝。很多教程把ACL前三行写完就结束了,真实配置中,我会习惯性地在末尾显式写一条deny any或者deny ip any any。虽然不写系统也会执行同样的效果,但显式写出来有两个好处:一是排除ACL的人能一眼看到这条规则确实存在,不会产生歧义;二是后期修改ACL时,向表里插入新规则时不会误以为列表就到此为止。
2.4 入方向和出方向:ACL生效的两个角度
接口上的ACL有两个绑定方向。in方向处理的是从该接口接收进入设备的流量,out方向处理的是从该接口发送出去的流量。这个方向选择如果搞错了,ACL配置得再正确也不会产生预期效果。
一个常见错误场景:我在路由器Router0的Gig0/0接口上写了一个ACL,打算阻止来自192.168.1.0/24网段的流量访问Router0后面的服务器。但我把ACL绑定到了Gig0/0的out方向,而这个接口上出去的流量其实是从本路由器发往192.168.1.0/24网段的,方向刚好反了,流量照样畅通无阻。检查的时候一定要用show access-lists看计数器有没有增加——如果流量经过但没有命中规则,命令不会报错,但行为就是不对。这就是方向选错最典型的表现。
3. 在Cisco Packet Tracer里从零配置标准ACL
3.1 先搭一个能复现问题的拓扑
纸上谈兵没有意义,Packet Tracer的价值就在于把配置落到设备上。新建一个工作区,拖入三台路由器、两台交换机、三台PC,规划如下拓扑思路:
- Router0作为总出口网关,连接两个内部网段
- 左侧PC0和PC1代表研发部,IP地址为192.168.10.10和192.168.10.11,属于192.168.10.0/24网段
- 右侧PC2代表服务器区,IP地址为192.168.100.10,属于192.168.100.0/24网段
- Router0与左侧交换机相连的接口是Gig0/0,IP为192.168.10.1;与右侧交换机相连的接口是Gig0/1,IP为192.168.100.1
各PC的默认网关指向各自网段的路由器接口IP。这是最简单的一种拓扑,但足够演示ACL的核心场景了。
在配置ACL之前,先确保全网能互相Ping通。这一步很多人会跳过,结果ACL一挂上去,网络不通了,分不清是ACL的问题还是链路的问题。先把基础连通性验证清楚了再动ACL,后面排查会轻松很多。
3.2 写第一条标准ACL并绑定到接口
现在需求来了:允许PC0(192.168.10.10)访问服务器区的任何服务,拒绝PC1(192.168.10.11)访问服务器区。注意是“拒绝访问服务器区”,不是“拒绝所有流量”。
按标准ACL的设计思路,它只匹配源地址,所以应该把ACL部署在靠近目标的Router0的Gig0/1接口上,方向选择in。这样进入服务器区方向的流量才会被检查。
在Router0上执行如下配置:
Router>enable Router#configure terminal Router(config)#access-list 1 permit host 192.168.10.10 Router(config)#interface gigabitEthernet 0/1 Router(config-if)#ip access-group 1 in Router(config-if)#end Router#write此时ACL 1只有一行permit主机192.168.10.10,加上隐含拒绝,实际效果就是:只有来自192.168.10.10的流量能进入服务器区,其他所有流量全部丢弃。PC1 Ping服务器区不通,服务器区反Ping PC1也不通。
如果你想验证这个配置确实生效,去PC0上Ping服务器IP,然后回到Router0上执行:
Router#show access-lists 1可以看到匹配计数在增长,说明放行规则确实命中了。这就是ACL配置验证的基础操作,比只在PC上按“Ping通了吗”要靠谱得多。
3.3 多条规则的顺序:先精确后宽泛
继续延伸需求:现在允许192.168.10.0/24整个网段访问服务器区,但要单独拒绝其中一个用户192.168.10.50。
很多初学者会这样写:
access-list 1 deny host 192.168.10.50 access-list 1 permit 192.168.10.0 0.0.0.255第一眼看上去没问题,但ACL是逐行匹配的,第一行deny host先比对,只有源地址正好是192.168.10.50时才命中,其他源地址继续向下匹配,最终落到permit网段这行。这种顺序下,deny和permit各自只作用于自己的范围,看起来是对的。
但如果把两条顺序调换一下:
access-list 1 permit 192.168.10.0 0.0.0.255 access-list 1 deny host 192.168.10.50问题就来了:192.168.10.50这个主机地址也在192.168.10.0/24网段范围内,数据包从第一行permit就已经被放行了,后面的deny根本不会被检查到。这就是为什么配置ACL有一条铁律:先写更精确的匹配规则,再写宽泛的匹配规则。
正确写法是把deny放前面。这并不难理解,但实际排错时十次里有八次都是这种顺序问题。尤其在一个ACL列表持续增删改之后,规则顺序很容易乱。Packet Tracer里可以在全局配置模式下用ip access-list standard 1进入命名式配置,然后手动用编号插入规则,比一条条敲access-list命令更可控。
3.4 命名式标准ACL:推荐给所有新手的写法
上面用的是编号式标准ACL,即access-list 1这种格式。还有一种写法是命名式标准ACL,命令结构如下:
Router(config)#ip access-list standard BLOCK_RND Router(config-std-nacl)#permit host 192.168.10.10 Router(config-std-nacl)#deny 192.168.10.0 0.0.0.255 Router(config-std-nacl)#exit Router(config)#interface gigabitEthernet 0/1 Router(config-if)#ip access-group BLOCK_RND in命名式ACL的最大优势是名称一眼能看出用途。一个名为BLOCK_RND的ACL比一个名为5的ACL在半年之后更容易回忆起来。生产环境里我倾向于给每一个ACL起一个可读性强的名字,比如ALLOW_MGMT_ONLY、BLOCK_VENDOR_SUBNET。Packet Tracer对这种命名式ACL支持得很好,而且完全可以在命名式ACL里同时写permit和deny语句。
有一个细节需要留意:命名式ACL里规则是有默认序号的(比如10、20、30),如果想在现有规则中间插入新规则,需要指定新的序号,或者用no 10删除现有规则再重新添加。Packet Tracer的界面操作也可以编辑这些序号,但命令行方式更直观,也更接近真实设备操作习惯。
4. 标准ACL实战中最容易踩的坑:我踩过的和你们即将踩的
4.1 只写permit忘了隐含拒绝导致路由器与服务器彻底失联
这是我排障生涯中遇到频率最高的一个“低级错误”,但它造成的后果一点都不低级。
场景回放:某台路由器上有一个标准ACL,管理员只想放行192.168.1.0/24访问后面的一台服务器,于是写了一条:
access-list 10 permit 192.168.1.0 0.0.0.255然后把它绑到了服务器的网关接口的in方向。结果不仅是其他网段访问不了服务器,连路由器自己管理用的Telnet、SSH也一并断了。原因就是隐含拒绝把设备的控制面流量也拦住了。
很多教材会强调ACL影响数据面的转发流量,但不要忽略控制面流量同样会经过接口ACL检查。管理地址如果不在放行清单里,远程管理会话就会被ACL无情拒绝。这就是为什么在很多老网工的规范配置里,ACL列表的最后会加上一条permit host <管理站IP>,并且一定放在deny之前(虽然隐含拒绝必然兜底,但显式放行管理IP能防止因为调整其他规则顺序导致自己把自己锁在门外)。
处理方法是:要么在ACL里放行管理IP,要么把管理接口和业务接口分开。生产环境中更建议后者——带外管理或者专用管理VLAN。Packet Tracer的模拟环境没有那么高要求,但习惯要从实验阶段养成,等真到了生产环境再去改习惯,代价就太大了。
4.2 通配符掩码把网段和主机搞混
再举一个通配符掩码的典型错误:有人想匹配192.168.1.0到192.168.1.255的整个网段,写成了192.168.1.0 0.0.0.0。从命令角度说这并不报错,它匹配的只是192.168.1.0这一个主机地址,实际网络里根本没这个主机在发流量。ACL一绑定接口,看起来好像有效果,但又好像没效果——因为其他主机照样能访问目标,只有真正的192.168.1.0地址(几乎不会作为源地址出现)才会被匹配。这种问题特别坑,因为命令毫无报错,show run也看不出逻辑问题,只能靠show access-lists里的计数器观察命中情况。
这个坑的规避方法其实很简单:写ACL之前,先在草稿纸上把要匹配的网段、子网掩码、通配符掩码三个值列出来,取反计算一遍再敲进设备。宁可在这一步多花两分钟,也不要等ACL上线后在半夜被电话叫醒。
4.3 标准ACL绑错方向:服务不可达但命令不报错
接前面方向问题的例子,展开说一个更隐蔽的情况。假设网络拓扑是三层结构:核心路由器连接两个楼层,二楼有一个服务器群,三楼是办公区。我接到需求“不让三楼的某个网段访问二楼服务器”,然后在核心路由器连接二楼服务器的接口上写了一个ACL,绑定out方向,里面的规则是deny三楼的源地址。但实际上二楼服务器接口的out方向流量是核心路由器发往二楼服务器的,源地址是核心路由器自己的接口地址,根本不会匹配三楼源地址。于是ACL就像一道设错了位置的门禁卡机器,完全没起到作用。
方向结合标准ACL的特性,有一个简单的判断方法:站在接口的角度问自己——我想拦的是从这个接口进来的流量,还是从这个接口出去的流量?如果是“进入服务器区的流量”,那就在服务器区接口的in方向拦;如果是“从路由器发往某个网段的流量”,那才考虑out方向。刚开始做实验的时候,每次绑定前都把这个逻辑过一遍,比事后排错效率高得多。
4.4 远程管理会话被ACL锁死:恢复手段必须留一手
现实中,远程维护设备时误绑ACL导致自己和设备断连,是非常经典的“自锁”事故。原因五花八门:ACL里忘了放行自己的管理IP、ACL顺序调整后自己掉到deny规则后面、接口方向选错然后一不小心把管理流量也拦了。
Packet Tracer里遇到这种情况还好,可以直接重启设备或关掉电源再开,模拟器的“重新加载”功能相当于物理重启。但真实生产环境这么做代价极高,可能造成业务中断。
所以我的建议是两条:第一,实验阶段就养成习惯,任何ACL绑定到接口之前,先用show access-lists确认管理IP在放行规则里、且放行规则在匹配顺序上不会被前面的deny抢了先;第二,登录设备时保留一个备用入口——比如串口console,或者带外管理网络。真被锁了,至少还能稳住心态去恢复配置。这也是为什么我在给团队培训时反复强调:ACL是一个把双刃剑,它限制别人的同时,如果不小心也会限制你自己。
5. 验证ACL是否生效:计数器、调试与常见排错链路
5.1 show命令族:把ACL的内部状态翻出来看
配置完ACL,一定不要急着宣布“搞定”。必须验证、验证、再验证。思科设备上最常用的三条验证命令:
Router#show access-lists Router#show ip access-lists Router#show ip interface gigabitEthernet 0/1show access-lists会显示每条规则被匹配的次数。当你在PC上发起Ping或访问流量时,对应规则后面的计数会增加。如果流量确实在走这个接口,而一个规则始终是0次命中,说明这个规则可能没被触发,原因可能是方向错了、通配符掩码写错了、或者是ACL根本就没被绑定到接口上。这条命令几乎可以定位ACL配置问题80%的原因。
show ip interface则能看到接口上具体绑定了哪个方向的哪个ACL,用于确认配置确实下发到了接口上。有些时候ACL在全局配置里写好了,但忘了绑定到接口,流量自然就不会受控。
5.2 用扩展Ping和抓包确认流量走向
如果show命令显示ACL有命中,但业务依然不通,就需要用更底层的手段验证。在Packet Tracer里有一个非常好用的工具:右下角的模拟模式(Simulation Mode)。激活之后,数据包逐跳传输,每一步都能看到设备的处理动作,包括ACL是允许还是拒绝。这对于学习ACL来说简直是外挂级功能,强烈建议初学的同学一定要亲手在模拟模式下发一个Ping包,观察它经过路由器的接口时ACL的匹配路径。
模拟模式看的是图形化流程,真实生产环境没有这种条件。退一步的做法是使用扩展Ping指定源地址测试不同网段的连通性。比如在PC1上执行Ping,源是PC1的IP,目标服务器IP,看到超时;再到PC0上执行相同目标的Ping,通了。这种对比就能确定ACL确实只拦了PC1。扩展Ping的用法是进入特权模式后直接敲ping,然后按提示填写源接口或源地址、目标地址、重复次数等参数。
5.3 完整排错链路:从“Ping不通”到“ACL计数异常”
整理一个排错思路供参考,按照这个链路走,大部分ACL问题都能在十分钟内定位:
- 确认物理链路和IP配置没问题(接口up/up,网关正确)。
- 在不绑ACL的情况下,确认直连网段的连通性正常。
- 绑定ACL后,再测一遍,确认确实是从“通”变成了“不通”,锁定是ACL引起的。
- 用
show ip interface确认ACL绑定方向和接口无误。 - 用
show access-lists查看计数是否增长。计数增长说明ACL匹配到了流量,接下来逐个排除规则顺序及匹配逻辑;计数不增长,大概率方向或接口绑错了。 - 用Packet Tracer模拟模式逐跳观察,定位具体哪一条规则允许或拒绝了数据包。
- 修正ACL规则、保存配置,再验证。
这套链路看起来很简单,但实际排错中很多人会跳过第1步,直接在ACL上反复试,最后发现根本是网段划分错了或者接口忘了配IP。据我观察,至少三成“ACL问题”最终发现根本与ACL无关。
6. 从标准ACL走向扩展ACL:什么时候应换方案
6.1 标准ACL的选型边界
标准ACL简单、执行效率高、占用设备CPU资源少,但它的局限性也很明显:只匹配源地址。很多实际需求并不是“不让某个网段的所有流量进来”,而是“不让某个网段访问我的Web服务,但允许它访问我的数据库端口”。这种需求标准ACL完全无能为力。
举一个明确的场景:公司里有一个数据服务器,研发部需要访问它上面的MySQL服务(TCP 3306),但不需要访问它的HTTP服务(TCP 80)。如果用标准ACL,你在靠近数据服务器的接口上只能控制源地址,无法区分端口。服务器为了业务需要同时开着80和3306,结果研发部既能访问MySQL也能访问Web页面。这时候就需要扩展ACL。
扩展ACL的编号范围是100到199(扩展编号2000到2699),它可以同时匹配源地址、目标地址、协议类型、源端口、目标端口等多个维度,配置语法也更长:
Router(config)#access-list 100 permit tcp host 192.168.10.10 host 192.168.100.10 eq 3306 Router(config)#access-list 100 deny ip any any Router(config)#interface gigabitEthernet 0/1 Router(config-if)#ip access-group 100 in这条规则的效果是:只允许192.168.10.10访问192.168.100.10上的TCP 3306端口,其余所有流量全部丢弃。
6.2 标准ACL的典型应用场景
这不是说标准ACL可以被淘汰,事实上它在一些场景下依然是最合适的方案:
- 基于来源网段的访问隔离:比如禁止某个办公区网段访问服务器区,不区分具体服务。这种情况下标准ACL一条permit或deny就解决问题,没必要上扩展ACL增加配置复杂度。
- 用于路由过滤:OSPF、RIP等动态路由协议做路由信息过滤时,标准ACL是常用的匹配工具。
- 其他命令中引用ACL做身份识别:比如NAT、route-map里可以用ACL作为匹配工具,标准ACL的简单性在这里反而成了优点。
理解这个边界之后,就能明白为什么网络工程师招聘要求里总是同时出现“标准ACL”和“扩展ACL”——它们像螺丝刀和扳手一样,各有各的适用场景,不存在谁完全替代谁。
7. 一段来自排障一线的经验补充
最后讲一个我从Packet Tracer一路学到真实设备上一直适用的心得。每次配完ACL,我习惯性地做三件事:
第一,write或者copy running-config startup-config保存配置。模拟器关机后配置可能丢失,生产设备意外断电后如果没有保存,所有ACL策略都会回到上一次保存的状态,这种事故我听说过不止一次。
第二,把ACL的规则逐条读一遍,特别关注deny和permit的顺序。有的设备上会自动生成“序号”,查看时一目了然;有的则显示配置顺序,逐个核对是否符合预期:先精确后宽泛、管理放行在前、隐含拒绝永远是兜底。
第三,在模拟器里特意制造一次“破坏性测试”。比如故意把一个放行的规则删掉,确认设备会拒绝预期流量,再重新加回去。这听起来多此一举,但这种对“什么时候会断、什么时候会通”的敏感度,恰恰是排错能力最核心的部分。ACL的配置命令就那几条,但能把ACL用得收放自如,靠的就是对规则匹配顺序和方向选择的反复体感训练。
如果你现在还在Packet Tracer阶段,建议把文中的拓扑、配置命令和排错链路亲手敲一遍,不要复制粘贴。等你自己敲通了第一条ACL,再回头来看这些注意事项,你会发现它们全都变成了肌肉记忆的一部分。