2、ACL工作原理:匹配顺序、隐式拒绝与路由器交互

ACL这东西,说白了就是一张规则表。但规则怎么查、查到以后怎么办、路由器内部到底干了啥——这些才是真正容易出坑的地方。我带过不少新人,配置ACL时语法全对,结果流量就是不通,十有八九是没搞懂工作原理。

2.1 ACL匹配顺序:从上到下,命中即停

ACL的匹配规则很简单:从上往下逐条检查,一旦匹配就立即执行动作,不再继续往下看。这个机制叫"顺序匹配,首次命中"。

举个例子,你写了这么几条规则:

access-list 100 permit ip 192.168.1.0 0.0.0.255 any
access-list 100 deny ip 10.0.0.0 0.255.255.255 any
access-list 100 permit ip any any

当一个来自192.168.1.10的包到达时,路由器先看第一条——匹配了,直接放行,后面两条根本不会检查。但如果来的是10.1.1.1,第一条不匹配,接着看第二条——匹配了,直接丢弃,第三条permit any any也救不了它。

核心要点:ACL的规则顺序就是执行顺序。把最精确、最常用的规则放在前面,把范围大的规则放在后面。我见过有人把deny any any放在第一条,结果所有流量都被干掉,排查了半天才发现是顺序问题。

这里有个容易忽略的细节:标准ACL只能检查源IP,扩展ACL可以检查源IP、目的IP、端口、协议等。但匹配顺序的逻辑是一样的——逐条匹配,命中即停。

2.2 隐式拒绝规则:看不见的"最后一道墙"

每条ACL的末尾,都藏着一条看不见的规则:deny any any(标准ACL)或deny ip any any(扩展ACL)。这就是所谓的"隐式拒绝"。

为什么会这样?你想想看,如果ACL匹配完所有规则都没命中,路由器该怎么办?总得有个默认动作吧。思科的设计哲学是"默认拒绝一切",这样更安全。

注意:隐式拒绝规则是自动添加的,你看不到也删不掉。这意味着:

  • 如果你只写了permit规则,没写deny规则,没匹配到的流量照样会被拒绝
  • 如果你想让所有流量都通过,必须在末尾显式加上permit ip any any
  • 隐式拒绝会记录日志吗?默认不会。但你可以用log关键字让显式规则记录日志

我在项目中遇到过这么个事:某公司新上了一台路由器,运维配了ACL只允许内网访问服务器,结果外网用户全连不上。查了半天,发现ACL里只写了permit tcp 10.0.0.0 0.255.255.255 host 192.168.1.100 eq 80,没写deny any any——但隐式拒绝已经帮他们干了这件事。他们以为没写deny就是允许,其实正好相反。

避坑指南:我曾经在配置远程管理ACL时,只允许了特定管理IP的SSH流量,忘了加permit ip any any,结果把自己也锁在外面了。后来我养成了一个习惯:在ACL末尾显式写一条deny ip any any log,这样既能明确拒绝动作,又能记录被拒绝的流量,方便排障。

2.3 ACL与路由器的交互:数据包处理流程

ACL不是独立工作的,它和路由器的转发流程紧密耦合。搞清楚这个流程,你才能知道ACL该放在哪个接口、哪个方向。

路由器处理一个数据包时,大致走这么几步:

  1. 接收数据包:从入接口收到帧,检查CRC,解封装
  2. 入方向ACL检查:如果入接口配置了入方向ACL,先匹配。拒绝就直接丢弃
  3. 路由查找:查路由表,决定出接口和下一跳
  4. 出方向ACL检查:如果出接口配置了出方向ACL,再匹配。拒绝就丢弃
  5. 封装转发:重新封装帧,从出接口发出去

你看,ACL可以在两个位置介入:入接口(inbound)和出接口(outbound)。方向搞错了,ACL就不起作用。

经验之谈:我个人习惯把ACL尽量放在入方向。原因很简单——流量一进来就过滤掉,省得路由器白费力气查路由表。特别是拒绝大量非法流量时,入方向ACL能显著降低CPU负载。

但也不是所有场景都适合入方向。比如你想控制从内网访问外网的流量,但内网有多个网段,入方向ACL要写很多条。这时候放在出方向可能更清晰。

下面这张图展示了ACL在路由器转发流程中的位置:

ACL与路由器转发流程 入接口接收 入方向ACL检查 路由查找 出方向ACL检查 封装转发 丢弃数据包 说明:入方向ACL在路由查找前执行,出方向ACL在路由查找后执行。拒绝动作都会直接丢弃数据包。

2.4 方向选择实战:入方向 vs 出方向

很多新手搞不清ACL该放哪个方向。我总结了一个简单判断方法:

场景 推荐方向 理由
过滤外部非法访问 入方向 流量一进来就拒绝,省路由查找
控制内网访问外网 出方向 可以基于目的IP/端口精确控制
限制特定用户访问服务器 入方向(服务器接口) 在服务器接口入方向过滤,不影响其他流量
记录被拒绝的流量 入方向 拒绝发生在早期,日志更完整

一个小技巧:配置ACL时,先想清楚"我要控制谁访问谁"。如果控制的是"谁进来",用入方向;如果控制的是"谁出去",用出方向。记住这个口诀:入控进,出控出。

2.5 常见误区与排障思路

最后分享几个我踩过的坑,你遇到了可以直接对照排查:

  • ACL没应用到接口:配置了ACL但忘了ip access-group,等于没配。用show running-config interface检查
  • 方向搞反了:入方向写成出方向,流量照常通过。用show ip access-list查看匹配计数,如果一直是0,大概率方向错了
  • 隐式拒绝导致意外断网:只写了permit没写deny,以为其他流量能过。记住:ACL默认拒绝一切
  • 规则顺序不对:精确规则放在后面,被前面的宽泛规则覆盖了。检查顺序,把最具体的规则放前面
  • ACL没考虑回程流量:只配了入方向ACL允许流量进来,但出方向没配允许回包,导致单向通信。双向ACL都要考虑