无论如何,你得先找一个支持 BGP 的上游,它可能能支持自助开通 BGP 服务,或者通过 Ticket 让你提交 LOA。政策上的事情不在这个文章中讨论。

本文以 Debian11 和 Bird2 为例。

配置一个虚拟网卡

直接改 /etc/network/interfaces 的配置,可以 ifup ifdown 控制。

虚拟 IP 写 /128 或者 /32,否则会出现问题。

1
2
3
4
5
6
7
8
9
10
11
auto dummy0
iface dummy0 inet6 static
address IPv6/128
pre-up ip link add $IFACE type dummy
post-down ip link delete $IFACE type dummy

auto dummy1
iface dummy1 inet static
address IPv4/32
pre-up ip link add $IFACE type dummy
post-down ip link delete $IFACE type dummy

拉起虚拟网卡。

1
2
ifdown dummy0
ifup dummy0

配置 Bird

修改 Bird 配置,这里是一个示例的配置,可以按这个来,这里不做配置解释,想了解配置的意思可以看一下 Bird 的文档。

1
vim /etc/bird/bird.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# 下面是配置文件
log "/var/log/bird.log" { debug, trace, info, remote, warning, error, auth, fatal, bug };

define ROUTER_ID = 你机器的公网v4地址; # 例如 6.6.6.6
define LOCAL_ASN = 你的AS号; # 例如 114514
define LOCAL_ASN_IPV6_PREFIX_SET = [你要宣告的IPv6地址段]; # 多段用,隔开,例如 xxxxxx::/48,yyyyyy::/48

define BOGON_ASNS = [
0, # RFC 7607
23456, # RFC 4893 AS_TRANS
64496..64511, # RFC 5398 and documentation/example ASNs
64512..65534, # RFC 6996 Private ASNs
65535, # RFC 7300 Last 16 bit ASN
65536..65551, # RFC 5398 and documentation/example ASNs
65552..131071, # RFC IANA reserved ASNs
4200000000..4294967294, # RFC 6996 Private ASNs
4294967295 # RFC 7300 Last 32 bit ASN
];

define BOGON_PREFIXES_V4 = [
0.0.0.0/8+, # RFC 1122 'this' network
10.0.0.0/8+, # RFC 1918 private space
100.64.0.0/10+, # RFC 6598 Carrier grade nat space
127.0.0.0/8+, # RFC 1122 localhost
169.254.0.0/16+, # RFC 3927 link local
172.16.0.0/12+, # RFC 1918 private space
192.0.2.0/24+, # RFC 5737 TEST-NET-1
192.88.99.0/24+, # RFC 7526 deprecated 6to4 relay anycast. If you wish to allow this, change `24+` to `24{25,32}`(no more specific)
192.168.0.0/16+, # RFC 1918 private space
198.18.0.0/15+, # RFC 2544 benchmarking
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+, # multicast
240.0.0.0/4+ # reserved
];

define BOGON_PREFIXES_V6 = [
::/8+, # RFC 4291 IPv4-compatible, loopback, et al
0064:ff9b::/96+, # RFC 6052 IPv4/IPv6 Translation
0064:ff9b:1::/48+, # RFC 8215 Local-Use IPv4/IPv6 Translation
0100::/64+, # RFC 6666 Discard-Only
2001::/32{33,128}, # RFC 4380 Teredo, no more specific
2001:2::/48+, # RFC 5180 BMWG
2001:10::/28+, # RFC 4843 ORCHID
2001:db8::/32+, # RFC 3849 documentation
2002::/16+, # RFC 7526 deprecated 6to4 relay anycast. If you wish to allow this, change `16+` to `16{17,128}`(no more specific)
3ffe::/16+, 5f00::/8+, # RFC 3701 old 6bone
fc00::/7+, # RFC 4193 unique local unicast
fe80::/10+, # RFC 4291 link local unicast
fec0::/10+, # RFC 3879 old site local unicast
ff00::/8+ # RFC 4291 multicast
];

router id ROUTER_ID;

function is_bogon_prefix() {
case net.type {
NET_IP4: return net ~ BOGON_PREFIXES_V4;
NET_IP6: return net ~ BOGON_PREFIXES_V6;
else: print "is_bogon_prefix: unexpected net.type ", net.type, " ", net; return false;
}
}

function is_bogon_asn() {
if bgp_path ~ BOGON_ASNS then return true;
return false;
}

# 公网上约定俗成的最小前缀长度是 24(IPv4)和 48(IPv6),所以要在导出的时候过滤
function net_len_too_long(){
case net.type {
NET_IP4: return net.len > 24; # IPv4 CIDR 大于 /24 为太长
NET_IP6: return net.len > 48; # IPv6 CIDR 大于 /48 为太长
else: print "net_len_too_long: unexpected net.type ", net.type, " ", net; return false;
}
}

function bgp_export() {
if net_len_too_long() then return false;
if source != RTS_STATIC then return false;
if net !~ LOCAL_ASN_IPV6_PREFIX_SET then return false;
return true;
}


template bgp bgp_tpl {
graceful restart;
local as LOCAL_ASN;
ipv6 {
import filter {
if net_len_too_long() then reject;
if is_bogon_prefix() then reject;
if is_bogon_asn() then reject;
if proto = "noAnnounce" then reject;
accept;
};
export where bgp_export();
};
}

protocol device {
scan time 5;
}

protocol kernel {
ipv6 {
export all;
};
}

protocol static noAnnounce {
ipv6;
route 宣告的地址段 via 本机网卡的IPv6地址; # 例如 route yyyyyy::/48 via xxxxx::1;
}

protocol static Announce {
ipv6;
route 宣告的地址段 reject; # 例如 xxxxx::/48
}


protocol bgp OOOOH from bgp_tpl {
source address 本机网卡的IPv6地址;
multihop 2; # 跳数
neighbor 邻居地址 as 邻居AS号; # 你的上游会告诉你的
#password "密码"; # Peer 密码,有就写没有就注释掉好了
ipv6 {
export limit 15;
};
}

创建 log 文件并授权,省的 Bird 因为权限问题起不来了。

1
2
touch /var/log/bird.log
chown bird:bird /var/log/bird.log

重启 Bird,或重载配置文件。

1
systemctl restart bird # 或者 birdc configure

验证

先看一下你的邻居建立起来没有。

1
2
3
4
birdc show protocol all

OOOOH BGP --- up 2023-08-03 Established
BGP state: Established

Established 了,说明你俩是 OK 的。

等你的上游放通你,最后以达到全球路由表有你的记录,你就可以在任意地方访问到你的 IP 了。