BGP路由过滤:前缀列表、AS路径过滤、Bogon拒绝与GTSM

5 分钟阅读·Matthieu·bgpbird2frrroute-filteringnetwork-securityrpkimanrs|

面向Linux BGP会话加固的实用参考。涵盖前缀列表、bogon拒绝、AS路径过滤、最大前缀限制和GTSM,同时提供BIRD2与FRR语法及验证步骤。

RPKI验证AS是否有权发起某个前缀的通告。它无法防护路由泄露、bogon注入、配置错误对端导致的路由表爆炸,也无法防护来自非直连主机的伪造BGP数据包。本文涵盖RPKI未覆盖的其他过滤手段。

每项过滤器均以BIRD2和FRR两种语法展示,包含IPv4和IPv6示例。每节先说明该过滤器能防止什么,再给出配置,最后说明如何验证其有效性。

如果尚未完成RPKI源验证,请先完成该步骤。参见RPKI ROA Setup for BGP

基础BGP会话配置请参见BIRD2 BGP Configuration on Linux(BIRD2)或FRR BGP Configuration on Linux(FRR)。本文假设你已有一个正常运行的BGP会话,现在需要对其进行加固。

为什么BGP路由过滤需要在RPKI之外做更多?

BGP路由过滤是基于前缀、AS路径或源属性来接受或拒绝BGP通告的做法。它防止路由泄露、前缀劫持、bogon注入和路由表爆炸。RPKI只覆盖源验证。没有额外过滤器,你的路由器会暴露于其他所有类别的BGP安全事件。

各层过滤器的防护目标如下:

过滤器类型 阻断的威胁 不使用的后果
Bogon前缀拒绝 DFZ中的私有/保留地址空间 路由器将流量转发到RFC 1918地址,形成黑洞。
小前缀拒绝 更精确的劫持路由(/25+,/49+) 攻击者通告覆盖你接受的/24中一部分的/32路由,以最长匹配方式赢得竞争。
AS路径bogon过滤 路径中包含私有/保留ASN AS 65535或AS 4200000000的路由泄漏进你的路由表,转发基于无效路径。
AS路径长度限制 路径膨胀攻击、路由表臃肿 对端发送超过50个AS跳的路由,占满内存。
最大前缀限制 路由泄露、会话过载 对端将完整路由表(100万+前缀)泄漏进你的会话,路由器内存耗尽。
GTSM(TTL安全) 来自远程主机的伪造BGP数据包 多跳之外的攻击者向你的会话注入BGP OPEN或UPDATE数据包。
RPKI源验证 源劫持 他人从其AS发起你的前缀通告。已在RPKI ROA Setup for BGP中覆盖。

真实事件说明了每层防护的重要性。2008年,巴基斯坦电信(Pakistan Telecom)为执行国内审查令,通告了YouTube前缀的更精确路由。这些路由泄漏到国际传输提供商,导致YouTube在全球范围内黑洞化数小时。传输提供商处的bogon或小前缀过滤器本可丢弃这些通告。2019年6月,宾夕法尼亚州一家小型ISP(AS396531)意外将Cloudflare、Amazon和Linode的路由泄露给Verizon,并扩散至全球。最大前缀限制本可在泄露扩散前拆除该会话。

如何在BIRD2和FRR中过滤bogon前缀?

Bogon前缀是绝对不应出现在全球路由表中的地址范围。包括RFC 1918私有地址空间、链路本地地址、文档用地址段和保留块。接受这些前缀意味着路由器会尝试将流量转发到没有合法全局目的地的地址,形成黑洞。

IPv4 bogon前缀

前缀 参考标准 用途
0.0.0.0/8 RFC 1122 "本"网络
10.0.0.0/8 RFC 1918 私有地址空间
100.64.0.0/10 RFC 6598 运营商级NAT
127.0.0.0/8 RFC 1122 回环地址
169.254.0.0/16 RFC 3927 链路本地
172.16.0.0/12 RFC 1918 私有地址空间
192.0.2.0/24 RFC 5737 TEST-NET-1
192.88.99.0/24 RFC 7526 已废弃的6to4中继
192.168.0.0/16 RFC 1918 私有地址空间
198.18.0.0/15 RFC 2544 基准测试
198.51.100.0/24 RFC 5737 TEST-NET-2
203.0.113.0/24 RFC 5737 TEST-NET-3
224.0.0.0/4 RFC 5771 组播
240.0.0.0/4 RFC 1112 保留供未来使用

IPv6 bogon前缀

前缀 参考标准 用途
::/8 各类标准 IPv4兼容、回环、映射地址
100::/64 RFC 6666 仅丢弃
2001:2::/48 RFC 5180 BMWG基准测试
2001:10::/28 RFC 4843 ORCHID
2001:db8::/32 RFC 3849 文档用
3fff::/20 RFC 9637 文档用
2002::/16 RFC 7526 已废弃的6to4
3ffe::/16 RFC 3701 原6bone
5f00::/16 RFC 9602 SRv6 SIDs
fc00::/7 RFC 4193 唯一本地单播
fe80::/10 RFC 4291 链路本地单播
fec0::/10 RFC 3879 已废弃的站点本地
ff00::/8 RFC 4291 组播

当IANA分配新块或废弃旧块时,这些列表会发生变化。Team Cymru bogon参考提供自动更新的fullbogons(未分配+保留空间)BGP Feed。静态列表请定期检查NLNOG BGP过滤指南。

BIRD2 bogon过滤器

# /etc/bird/bogons.conf - include this from your main bird.conf

define BOGON_PREFIXES_V4 = [
    0.0.0.0/8+,
    10.0.0.0/8+,
    100.64.0.0/10+,
    127.0.0.0/8+,
    169.254.0.0/16+,
    172.16.0.0/12+,
    192.0.2.0/24+,
    192.88.99.0/24+,
    192.168.0.0/16+,
    198.18.0.0/15+,
    198.51.100.0/24+,
    203.0.113.0/24+,
    224.0.0.0/4+,
    240.0.0.0/4+
];

define BOGON_PREFIXES_V6 = [
    ::/8+,
    0100::/64+,
    2001:2::/48+,
    2001:10::/28+,
    2001:db8::/32+,
    3fff::/20+,
    2002::/16+,
    3ffe::/16+,
    5f00::/16+,
    fc00::/7+,
    fe80::/10+,
    fec0::/10+,
    ff00::/8+
];

function reject_bogon_prefixes_v4() {
    if (net ~ BOGON_PREFIXES_V4) then {
        print "REJECTED bogon prefix: ", net, " path: ", bgp_path;
        reject;
    }
}

function reject_bogon_prefixes_v6() {
    if (net ~ BOGON_PREFIXES_V6) then {
        print "REJECTED bogon prefix: ", net, " path: ", bgp_path;
        reject;
    }
}

每个前缀后的+表示"此前缀及所有更精确子网"。10.0.0.0/8+匹配10.0.0.0/8、10.0.0.0/9、10.1.0.0/16等。这样可以拦截攻击者通告RFC 1918空间内某个/24的情况。

在导入过滤器中调用这些函数:

filter import_from_upstream_v4 {
    reject_bogon_prefixes_v4();
    # ... other filters ...
    accept;
}

protocol bgp upstream_v4 {
    local as 64500;
    neighbor 198.51.100.1 as 64501;
    ipv4 {
        import filter import_from_upstream_v4;
        export none;
    };
}

FRR bogon过滤器

! IPv4 bogon prefix-list
ip prefix-list BOGONS_v4 seq 10 deny 0.0.0.0/8 le 32
ip prefix-list BOGONS_v4 seq 20 deny 10.0.0.0/8 le 32
ip prefix-list BOGONS_v4 seq 30 deny 100.64.0.0/10 le 32
ip prefix-list BOGONS_v4 seq 40 deny 127.0.0.0/8 le 32
ip prefix-list BOGONS_v4 seq 50 deny 169.254.0.0/16 le 32
ip prefix-list BOGONS_v4 seq 60 deny 172.16.0.0/12 le 32
ip prefix-list BOGONS_v4 seq 70 deny 192.0.2.0/24 le 32
ip prefix-list BOGONS_v4 seq 80 deny 192.88.99.0/24 le 32
ip prefix-list BOGONS_v4 seq 90 deny 192.168.0.0/16 le 32
ip prefix-list BOGONS_v4 seq 100 deny 198.18.0.0/15 le 32
ip prefix-list BOGONS_v4 seq 110 deny 198.51.100.0/24 le 32
ip prefix-list BOGONS_v4 seq 120 deny 203.0.113.0/24 le 32
ip prefix-list BOGONS_v4 seq 130 deny 224.0.0.0/4 le 32
ip prefix-list BOGONS_v4 seq 140 deny 240.0.0.0/4 le 32
ip prefix-list BOGONS_v4 seq 999 permit 0.0.0.0/0 le 32

! IPv6 bogon prefix-list
ipv6 prefix-list BOGONS_v6 seq 10 deny ::/8 le 128
ipv6 prefix-list BOGONS_v6 seq 20 deny 100::/64 le 128
ipv6 prefix-list BOGONS_v6 seq 30 deny 2001:2::/48 le 128
ipv6 prefix-list BOGONS_v6 seq 40 deny 2001:10::/28 le 128
ipv6 prefix-list BOGONS_v6 seq 50 deny 2001:db8::/32 le 128
ipv6 prefix-list BOGONS_v6 seq 60 deny 3fff::/20 le 128
ipv6 prefix-list BOGONS_v6 seq 70 deny 2002::/16 le 128
ipv6 prefix-list BOGONS_v6 seq 80 deny 3ffe::/16 le 128
ipv6 prefix-list BOGONS_v6 seq 90 deny 5f00::/16 le 128
ipv6 prefix-list BOGONS_v6 seq 100 deny fc00::/7 le 128
ipv6 prefix-list BOGONS_v6 seq 110 deny fe80::/10 le 128
ipv6 prefix-list BOGONS_v6 seq 120 deny fec0::/10 le 128
ipv6 prefix-list BOGONS_v6 seq 130 deny ff00::/8 le 128
ipv6 prefix-list BOGONS_v6 seq 999 permit ::/0 le 128

le 32(IPv4)和le 128(IPv6)子句与前缀及所有更精确子网匹配,与BIRD2中的+运算符相同。最后seq 999处的permit条目允许所有未被拒绝的路由通过。

将前缀列表应用到邻居:

router bgp 64500
 neighbor 198.51.100.1 remote-as 64501
 address-family ipv4 unicast
  neighbor 198.51.100.1 prefix-list BOGONS_v4 in
 address-family ipv6 unicast
  neighbor 2001:db8::1 prefix-list BOGONS_v6 in

注意:2001:db8::/32条目在bogon列表中。生产环境不要使用文档地址。将上面的邻居地址替换为实际的对端IP。

拒绝过小的前缀

小于/24(IPv4)或/48(IPv6)的路由在全球DFZ中无法可靠传播。更重要的是,接受这些路由会使你暴露于更精确前缀劫持攻击。在入站方向过滤。

BIRD2:

function reject_small_prefixes_v4() {
    if (net.len > 24) then {
        print "REJECTED too-small prefix: ", net, " path: ", bgp_path;
        reject;
    }
}

function reject_small_prefixes_v6() {
    if (net.len > 48) then {
        print "REJECTED too-small prefix: ", net, " path: ", bgp_path;
        reject;
    }
}

FRR:

! Add to the same prefix-lists, before the final permit
ip prefix-list BOGONS_v4 seq 150 deny 0.0.0.0/0 ge 25 le 32
ipv6 prefix-list BOGONS_v6 seq 140 deny ::/0 ge 49 le 128

这会拦截所有比/24(IPv4)或/48(IPv6)更精确的前缀。将这些条目放在seq 999 permit条目之前。

AS路径过滤器如何防止路由泄露?

AS路径过滤器检查路由所经过的自治系统序列。它能发现三类问题:不应出现在路径中的bogon ASN、表明泄露或操纵的过长路径,以及通告前未被剥离的私有ASN。

过滤bogon ASN

Bogon ASN是在公共互联网的BGP路径中不应出现的保留编号:

ASN范围 参考标准 用途
0 RFC 7607 保留
23456 RFC 4893 AS_TRANS(4字节AS过渡)
64496-64511 RFC 5398 文档/示例
64512-65534 RFC 6996 私有使用(16位)
65535 RFC 7300 最后一个16位ASN
65536-65551 RFC 5398 文档/示例(32位)
65552-131071 IANA 保留
4200000000-4294967294 RFC 6996 私有使用(32位)
4294967295 RFC 7300 最后一个32位ASN

BIRD2:

define BOGON_ASNS = [
    0,
    23456,
    64496..64511,
    64512..65534,
    65535,
    65536..65551,
    65552..131071,
    4200000000..4294967294,
    4294967295
];

function reject_bogon_asns()
int set bogon_asns;
{
    bogon_asns = BOGON_ASNS;
    if (bgp_path ~ bogon_asns) then {
        print "REJECTED bogon ASN in path: ", net, " path: ", bgp_path;
        reject;
    }
}

bgp_path ~ bogon_asns运算符检查路径中是否有任何ASN属于该集合。路径中任意位置出现一个bogon ASN即触发拒绝。

FRR:

bgp as-path access-list BOGON_ASNS deny _0_
bgp as-path access-list BOGON_ASNS deny _23456_
bgp as-path access-list BOGON_ASNS deny _6449[6-9]_
bgp as-path access-list BOGON_ASNS deny _6450[0-9]_
bgp as-path access-list BOGON_ASNS deny _6451[01]_
bgp as-path access-list BOGON_ASNS deny _64[5-9][1-9][2-9]_
bgp as-path access-list BOGON_ASNS deny _6[5-9][0-9][0-9][0-9]_
bgp as-path access-list BOGON_ASNS deny _[1-9][0-9][0-9][0-9][0-9]_
bgp as-path access-list BOGON_ASNS deny _[1-3][0-9][0-9][0-9][0-9][0-9]_
bgp as-path access-list BOGON_ASNS permit .*

FRR对AS路径字符串使用正则匹配。下划线_匹配AS路径分隔符(空格、开始、结束)。这种正则方式不如BIRD2的整数集合匹配精确。使用route-map配合as-path access-list:

route-map IMPORT_FILTER deny 10
 match as-path BOGON_ASNS
route-map IMPORT_FILTER permit 100

router bgp 64500
 address-family ipv4 unicast
  neighbor 198.51.100.1 route-map IMPORT_FILTER in

注意:上述正则模式已经过简化。用正则完整匹配32位私有ASN范围(4200000000-4294967294)容易出错。生产部署建议使用bgpq4从IRR数据生成前缀列表和AS路径过滤器,这样更准确且可自动化。

限制AS路径长度

合法的BGP路径很少超过10-15个ASN。超过这个长度通常表明存在路由泄露、路径操纵或错误的路径预置。设置一个硬限制。

BIRD2:

function reject_long_paths() {
    if (bgp_path.len > 25) then {
        print "REJECTED long AS-path (", bgp_path.len, "): ", net, " path: ", bgp_path;
        reject;
    }
}

FRR:

bgp as-path access-list LONG_PATHS deny ^([0-9]+_){25,}
bgp as-path access-list LONG_PATHS permit .*

route-map IMPORT_FILTER deny 20
 match as-path LONG_PATHS

25的限制是保守值。大多数合法路由的路径在10以下。如果你接收完整路由表,在确定阈值前先检查RIB中最长的路径:

# BIRD2
birdc 'show route where bgp_path.len > 15' | head -20

# FRR
vtysh -c "show ip bgp regexp ^([0-9]+_){15,}"

在出站方向剥离私有ASN

如果你在内部使用私有ASN运行iBGP,确保它们不会泄漏到上游。

BIRD2:

filter export_to_upstream_v4 {
    # Strip private ASNs before advertising
    bgp_path.delete([64512..65534, 4200000000..4294967294]);
    # ... your export policy ...
    accept;
}

FRR:

router bgp 64500
 address-family ipv4 unicast
  neighbor 198.51.100.1 remove-private-AS all

all关键字即使在路径中存在公共ASN时也会移除所有私有ASN。不加all,FRR仅在整个路径全部为私有ASN时才剥离。

BGP会话的最大前缀限制应如何设置?

最大前缀限制是一个安全阀,当对端通告的前缀数超过配置阈值时拆除BGP会话。它能防止对端意外泄露完整路由表或被劫持时导致路由表爆炸。没有这个限制,单个配置错误的对端就可能耗尽路由器内存。

根据对每个对端的预期来设置限制:

对端类型 预期前缀数(IPv4) 建议限制 建议限制(IPv6)
完整路由表上游 ~1,200,000(2026年3月) 1,500,000 300,000
部分路由表 / IXP对端 不固定 当前数量的1.5倍 当前数量的1.5倍
单宿客户 1-10 50 50
多宿客户 10-100 200 200

设置上游限制前请在bgp.potaroo.net检查当前完整路由表大小。将限制设置为预期数量的约1.2倍,以吸收正常增长而不触发误报。

BIRD2:

protocol bgp upstream_v4 {
    local as 64500;
    neighbor 198.51.100.1 as 64501;
    ipv4 {
        import limit 1500000 action restart;
        import filter import_from_upstream_v4;
        export none;
    };
}

protocol bgp customer_v4 {
    local as 64500;
    neighbor 203.0.113.10 as 64502;
    ipv4 {
        import limit 50 action disable;
        import filter import_from_customer_v4;
        export filter export_to_customer_v4;
    };
}

BIRD2在达到限制时提供三种动作:

  • action restart - 拆除会话并在延迟后重启。适合上游对端。
  • action disable - 拆除并禁用协议。需要手动执行birdc enable恢复。适合客户对端,触发限制意味着出现严重问题。
  • action block - 停止导入新路由但保持会话。适合在调查期间保留现有路由。

FRR:

router bgp 64500
 neighbor 198.51.100.1 remote-as 64501
 address-family ipv4 unicast
  neighbor 198.51.100.1 maximum-prefix 1500000 90 restart 5

 neighbor 203.0.113.10 remote-as 64502
 address-family ipv4 unicast
  neighbor 203.0.113.10 maximum-prefix 50 80

FRR中,maximum-prefix 1500000 90 restart 5的含义:在90%时(1,350,000个前缀)警告,达到1,500,000时拆除,5分钟后重启会话。不加restart关键字,FRR会拆除会话并需要手动执行clear bgp neighbor才能恢复。

验证最大前缀配置

# BIRD2 - check current prefix count and limit
birdc show protocols all upstream_v4 | grep -E "Routes|Limit"

# FRR - check prefix count per neighbor
vtysh -c "show ip bgp summary"

输出会在配置限制旁显示当前前缀数。如果数量接近限制,在触发之前增大阈值。

GTSM如何保护BGP会话免受伪造数据包攻击?

GTSM(通用TTL安全机制,Generalized TTL Security Mechanism,RFC 5082)通过检查TTL/Hop Limit字段,将接受的BGP数据包限制为直连对端。启用后,BGP数据包以TTL 255发送。接收方丢弃所有TTL低于254的BGP数据包(对于直连对端)。由于路由器在每跳都会递减TTL,多跳之外的攻击者无法发送到达时TTL为255的数据包。

这可阻断远程TCP RST注入、针对BGP 179端口的SYN洪泛,以及来自非直连攻击者的伪造BGP OPEN/UPDATE数据包。GTSM与同一会话上的eBGP multihop互斥。双方都必须启用。

BIRD2:

protocol bgp upstream_v4 {
    local as 64500;
    neighbor 198.51.100.1 as 64501;
    ttl security yes;
    ipv4 {
        import limit 1500000 action restart;
        import filter import_from_upstream_v4;
        export none;
    };
}

FRR:

router bgp 64500
 neighbor 198.51.100.1 remote-as 64501
 neighbor 198.51.100.1 ttl-security hops 1

hops 1表示对端必须恰好距离1跳(直连)。根据实际跳数设置此值。对于IXP交换结构上的eBGP对端,hops 1是正确的。对于多跳会话(如BGP over GRE隧道),无法使用GTSM。改用MD5认证:

BIRD2 MD5替代方案:

protocol bgp multihop_peer {
    local as 64500;
    neighbor 198.51.100.5 as 64503;
    multihop 2;
    password "your-md5-secret";
    # ...
}

FRR MD5替代方案:

router bgp 64500
 neighbor 198.51.100.5 remote-as 64503
 neighbor 198.51.100.5 ebgp-multihop 2
 neighbor 198.51.100.5 password your-md5-secret

将MD5密码存储在受限文件(chmod 600)中,而不是主配置文件里。对于FRR,在/etc/frr/frr.conf中引用,该文件应已设置为640并由frr:frr拥有。对于BIRD2,保持/etc/bird/bird.conf640并由bird:bird拥有。

MANRS要求哪些BGP过滤器?

MANRS(路由安全的共识规范,Mutually Agreed Norms for Routing Security)定义了网络运营商的基准行动。行动1、3和4是成为MANRS参与者的必要条件。本文中的过滤器与MANRS行动的对应关系如下。

行动1:防止传播不正确的路由信息。

这是核心过滤行动。要求对客户连接实施明确的前缀级过滤,并推荐使用AS路径过滤器防止路由泄露。

本文中的过滤器 MANRS行动1覆盖
前缀列表过滤(bogons) 防止通告/接受保留地址空间
小前缀拒绝 阻断表明劫持的更精确路由
AS路径bogon过滤 拒绝包含私有/保留ASN的路由
最大前缀限制 阻止泄露的完整路由表传播
客户前缀过滤器 本文未涵盖。使用bgpq4从IRR数据为每个客户构建。

行动2(推荐):防止带有伪造源地址的流量。

不属于BGP过滤器。这是BCP 38/84源地址验证(uRPF)。超出本文范围,但同样重要。

行动3:促进全球运营通信。

在PeeringDB和RIR数据库中保持联系方式最新。不是过滤器,但运行正确过滤器的运营商通常也会维护联系信息。

行动4:在全球范围内促进路由信息共享。

使用RPSL对象在IRR(RIPE、RADB)中发布路由策略。为RPKI创建ROA。这使得对端能够为你的通告构建准确的前缀过滤器。

bogon过滤(前缀+ASN)+ 小前缀拒绝 + 最大前缀限制 + 客户前缀列表的组合覆盖MANRS行动1。添加RPKI(RPKI ROA Setup for BGP)和IRR注册可覆盖行动4。

综合应用:完整的导入过滤器

下面是综合使用上述所有技术的完整导入过滤器。

BIRD2完整导入过滤器

# /etc/bird/filters.conf

include "/etc/bird/bogons.conf";  # BOGON_PREFIXES_V4, BOGON_PREFIXES_V6, BOGON_ASNS

function import_checks_v4() {
    # 1. Reject bogon prefixes
    if (net ~ BOGON_PREFIXES_V4) then {
        print "REJECT bogon prefix: ", net, " ", bgp_path;
        reject;
    }

    # 2. Reject too-small prefixes
    if (net.len > 24) then {
        print "REJECT small prefix: ", net, " ", bgp_path;
        reject;
    }

    # 3. Reject bogon ASNs in path
    if (bgp_path ~ [0, 23456, 64496..64511, 64512..65534, 65535,
                     65536..65551, 65552..131071,
                     4200000000..4294967294, 4294967295]) then {
        print "REJECT bogon ASN: ", net, " ", bgp_path;
        reject;
    }

    # 4. Reject excessively long paths
    if (bgp_path.len > 25) then {
        print "REJECT long path: ", net, " ", bgp_path;
        reject;
    }

    # 5. Reject RPKI invalid (if RPKI is configured)
    if (roa_check(rpki4, net, bgp_path.last) = ROA_INVALID) then {
        print "REJECT RPKI invalid: ", net, " ", bgp_path;
        reject;
    }
}

filter import_upstream_v4 {
    import_checks_v4();
    accept;
}

protocol bgp upstream_v4 {
    local as 64500;
    neighbor 198.51.100.1 as 64501;
    ttl security yes;
    ipv4 {
        import limit 1500000 action restart;
        import filter import_upstream_v4;
        export none;
    };
}

FRR完整导入过滤器

! /etc/frr/frr.conf

! --- Prefix lists (bogons + small prefix rejection) ---
ip prefix-list IMPORT_V4 seq 10 deny 0.0.0.0/8 le 32
ip prefix-list IMPORT_V4 seq 20 deny 10.0.0.0/8 le 32
ip prefix-list IMPORT_V4 seq 30 deny 100.64.0.0/10 le 32
ip prefix-list IMPORT_V4 seq 40 deny 127.0.0.0/8 le 32
ip prefix-list IMPORT_V4 seq 50 deny 169.254.0.0/16 le 32
ip prefix-list IMPORT_V4 seq 60 deny 172.16.0.0/12 le 32
ip prefix-list IMPORT_V4 seq 70 deny 192.0.2.0/24 le 32
ip prefix-list IMPORT_V4 seq 80 deny 192.88.99.0/24 le 32
ip prefix-list IMPORT_V4 seq 90 deny 192.168.0.0/16 le 32
ip prefix-list IMPORT_V4 seq 100 deny 198.18.0.0/15 le 32
ip prefix-list IMPORT_V4 seq 110 deny 198.51.100.0/24 le 32
ip prefix-list IMPORT_V4 seq 120 deny 203.0.113.0/24 le 32
ip prefix-list IMPORT_V4 seq 130 deny 224.0.0.0/4 le 32
ip prefix-list IMPORT_V4 seq 140 deny 240.0.0.0/4 le 32
ip prefix-list IMPORT_V4 seq 150 deny 0.0.0.0/0 ge 25 le 32
ip prefix-list IMPORT_V4 seq 999 permit 0.0.0.0/0 le 32

! --- AS-path filters (bogon ASNs + path length) ---
bgp as-path access-list BOGON_ASNS deny _0_
bgp as-path access-list BOGON_ASNS deny _23456_
bgp as-path access-list BOGON_ASNS deny _6449[6-9]_
bgp as-path access-list BOGON_ASNS deny _6450[0-9]_
bgp as-path access-list BOGON_ASNS deny _6451[01]_
bgp as-path access-list BOGON_ASNS permit .*

bgp as-path access-list LONG_PATHS deny ^([0-9]+_){25,}
bgp as-path access-list LONG_PATHS permit .*

! --- Route-map combining all checks ---
route-map IMPORT_UPSTREAM deny 10
 match as-path BOGON_ASNS
route-map IMPORT_UPSTREAM deny 20
 match as-path LONG_PATHS
route-map IMPORT_UPSTREAM permit 100

! --- BGP neighbor configuration ---
router bgp 64500
 neighbor 198.51.100.1 remote-as 64501
 neighbor 198.51.100.1 ttl-security hops 1
 address-family ipv4 unicast
  neighbor 198.51.100.1 prefix-list IMPORT_V4 in
  neighbor 198.51.100.1 route-map IMPORT_UPSTREAM in
  neighbor 198.51.100.1 maximum-prefix 1500000 90 restart 5

FRR中,前缀列表和route-map都会被评估。前缀列表先运行,丢弃bogon前缀和小前缀。通过前缀列表的路由再经过route-map检查AS路径过滤器。两者都必须允许路由才能被接受。

如何验证BGP路由过滤器有效?

过滤器只有在真正拒绝应拒绝的内容时才有用。每次变更后都要验证。

BIRD2验证

# Check what routes were rejected (requires print statements in filters)
grep "REJECT" /var/log/bird.log | tail -20

# Show the routing table with filter details
birdc show route filtered

# Show routes from a specific protocol
birdc show route protocol upstream_v4

# Count accepted routes per protocol
birdc show protocols all upstream_v4 | grep "Routes:"

# Test a specific prefix against your import filter
birdc show route for 10.0.0.0/8 all

show route filtered命令显示已收到但被导入过滤器拒绝的路由。如果bogon过滤器正常工作,接受的路由表中应该看不到bogon前缀,所有收到的bogon路由应出现在filtered表中。

FRR验证

# Show accepted routes from a neighbor
vtysh -c "show ip bgp neighbors 198.51.100.1 received-routes"

# Show routes filtered by inbound policy
vtysh -c "show ip bgp neighbors 198.51.100.1 filtered-routes"

# Check the prefix count per neighbor
vtysh -c "show ip bgp summary"

# Test if a specific prefix is accepted
vtysh -c "show ip bgp 10.0.0.0/8"

# Check max-prefix status
vtysh -c "show ip bgp neighbors 198.51.100.1" | grep -A2 "Maximum prefix"

要使received-routesfiltered-routes生效,必须在邻居上启用软重配入站:

router bgp 64500
 address-family ipv4 unicast
  neighbor 198.51.100.1 soft-reconfiguration inbound

这会使用额外内存(存储过滤前的所有已收路由)。对于完整路由表会话,大约是RIB内存的2倍。在RAM有限的生产路由器上,选择性使用。

外部验证

你的过滤器保护自己的RIB。要验证你向外界通告了什么,使用外部looking glass:

  • bgp.tools - 搜索你的ASN,查看全球范围内你通告的前缀
  • RIPE RIS - BGP路由信息服务,显示跨收集器的路由可见性
  • Hurricane Electric BGP Toolkit - 前缀和ASN查询

过滤器变更后检查这些工具,确认你没有意外过滤掉合法路由,也没有泄漏不应通告的路由。

如需自动化监控,参见 。

BIRD2与FRR语法对照

两种路由守护进程之间的快速参考:

过滤器类型 BIRD2 FRR
Bogon前缀 if (net ~ BOGON_PREFIXES) then reject ip prefix-list BOGONS deny 10.0.0.0/8 le 32
小前缀 if (net.len > 24) then reject ip prefix-list X deny 0.0.0.0/0 ge 25 le 32
Bogon ASN if (bgp_path ~ [64512..65534]) then reject bgp as-path access-list X deny _64[5-9][1-9][2-9]_
路径长度 if (bgp_path.len > 25) then reject bgp as-path access-list X deny ^([0-9]+_){25,}
最大前缀 import limit 50 action disable neighbor X maximum-prefix 50
GTSM ttl security yes neighbor X ttl-security hops 1
MD5认证 password "secret" neighbor X password secret
剥离私有AS bgp_path.delete([64512..65534]) neighbor X remove-private-AS all
应用过滤器 import filter name neighbor X prefix-list/route-map name in

BIRD2使用单一过滤器函数组合所有检查。FRR将检查分散在前缀列表(前缀匹配)、as-path access-list(路径匹配)和route-map(组合多个匹配条件)之间。两种方法都可用。BIRD2的方式在处理复杂策略时更易读。FRR的方式对Cisco运维人员更熟悉。

出现问题了?

max-prefix触发会话拆除: 检查journalctl -u birdjournalctl -u frr中的限制触发消息。如果对端确实增长则增大限制,否则调查是否为泄漏。BIRD2中用birdc enable upstream_v4重新启用。FRR中用vtysh -c "clear bgp 198.51.100.1"清除。

合法路由被过滤: 检查birdc show route filteredvtysh -c "show ip bgp neighbors X filtered-routes"查看被丢弃的内容。常见原因:bogon列表过于激进,或小前缀阈值拒绝了来自客户的合法/25路由。调整过滤器并重新加载:birdc configurevtysh -c "write memory"后执行systemctl reload frr

GTSM拒绝有效对端: 双方都必须启用GTSM。如果一方启用另一方未启用,数据包到达时TTL为1,被启用GTSM的一方丢弃。用tcpdump -i eth0 port 179 -v检查TTL值。

变更后过滤器未生效: BIRD2中运行birdc configure重新加载。FRR中,如果更改了前缀列表或route-map,触发软重置:vtysh -c "clear bgp 198.51.100.1 in"。不执行此操作,RIB中的现有路由不会对新过滤器重新评估。

日志: 两个守护进程默认通过systemd journal记录日志。

# BIRD2
journalctl -u bird -f

# FRR
journalctl -u frr -f

BIRD2过滤器函数中的print语句写入bird日志。FRR中,在vtysh中使用debug bgp updates启用调试日志进行临时排查。排查完成后禁用,因为它会产生大量日志输出。


本文是BGP Bring Your Own IP on a VPS系列的一部分。


Copyright 2026 Virtua.Cloud. All rights reserved.

准备好亲自尝试了吗?

几秒内部署您自己的服务器。支持 Linux、Windows 或 FreeBSD。

查看 VPS 方案