动态多点 VPN (DMVPN)
https://alpinelinux.cn/about 在 Why the Name Alpine? 中提到
Cisco DMVPN 的第一个开源实现 OpenNHRP 是为 Alpine Linux 编写的。[1]
因此,本文档的目的是成为 Linux DMVPN 设置的参考,包含客户端使用 DMVPN 所需的所有网络服务(DNS、防火墙等)。 小型办公室服务 提供额外的服务,例如客户端的 DHCP、HTTP 代理和基本的 SIP 电话系统。
术语
- NBMA
- 非广播多路访问 网络,如 RFC 2332 中所述
- Hub
- 执行 NBMA 云内下一跳解析协议服务的下一跳服务器 (NHS)。
- Spoke
- 下一跳解析协议客户端 (NHC),它发起各种类型的 NHRP 请求,以便获得对 NHRP 服务的访问权限。
硬件
如果您需要千兆位吞吐量,则应选择具有 AES-NI 和 SHA 扩展 的处理器。
提取证书
我们将使用证书用于 DMVPN 和 OpenVPN(RoadWarrior 客户端)。如果您需要生成自己的证书,请参阅 Generating_SSL_certs_with_ACF。您应该为此目的使用单独的机器。如果您在 Windows 机器上下载了证书,则可以使用 WinSCP 将它们复制到 DMVPN 设备上。
以下是从 pfx 文件中提取证书的通用说明
openssl pkcs12 -in cert.pfx -cacerts -nokeys -out cacert.pem openssl pkcs12 -in cert.pfx -nocerts -nodes -out serverkey.pem openssl pkcs12 -in cert.pfx -nokeys -clcerts -out cert.pem
为您的证书文件设置适当的权限
chmod 600 *.pem *.pfx
Spoke 节点
本地 Spoke 节点网络支持多个 ISP 连接,以及冗余的第 2 层交换机。至少需要一个支持 802.1q 的交换机,第二个是可选的,用于冗余目的。典型的 Spoke 节点网络如下所示
启动 Alpine USB
按照 Create_a_Bootable_USB 上的说明,了解如何创建可启动的 USB。
Alpine 设置
我们将按如下方式设置网络接口
接口 | 描述 | 子网 |
---|---|---|
bond0.3 | 管理 | 10.1.0.129/26 |
bond0.101 | LAN | 10.1.0.0/25 |
bond0.256 | 来自 ISP1 的互联网 | 从 ISP 分配 |
bond0.257 | 来自 ISP2 的互联网 | 从 ISP 分配 |
bond0.620 | wifi 代理和 dmvpn spoke 节点之间的传输 | 10.1.0.252/30 |
bond0.701 | WiFi 客户端(无法访问 DMVPN 网络) | 172.17.48.0/24 |
bond0.1101 | 语音 | 10.2.0.0/24 |
setup-alpine
您将被提示类似以下内容... | 关于您可以输入的内容的建议... |
---|---|
选择键盘布局 [none]
|
输入适合您的布局 |
选择变体
|
输入适合您的布局(如果提示) |
输入系统主机名(短格式,例如“foo”)[localhost]
|
输入主机名,例如 vpnc |
可用接口为:eth0
|
输入 bond0.101 |
可用的链路聚合从属设备为:eth0 eth1
|
eth0 eth1 |
bond0 的 IP 地址?(或“dhcp”、“none”、“?”)[none]
|
按 Enter 键确认“none” |
bond0.101 的 IP 地址?(或“dhcp”、“none”、“?”)[dhcp]
|
输入您的 LAN 接口的 IP 地址,例如 10.1.0.1 |
子网掩码?[255.255.255.0]
|
按 Enter 键确认“255.255.255.0”或键入另一个合适的子网掩码 |
网关?(或“none”)[none]
|
按 Enter 键确认“none” |
您要进行任何手动网络配置吗?[no]
|
yes |
为 bond0.620、bond0.701、bond0.1101、bond0.256 和 bond0.257(可选)接口复制 bond0.101 配置。 设置多个网关时,不要忘记为 ISP 接口添加网关和指标值。 保存并关闭文件 (:wq) | |
DNS 域名?(例如“bar.com”)[]
|
输入您的内联网域名,例如, example.net |
DNS 名称服务器?[]
|
8.8.8.8 8.8.4.4 (稍后我们将更改它们) |
正在更改 root 密码
|
为控制台输入安全密码 |
重新输入密码
|
重新输入上述密码 |
您所在的时区?(“?”表示列表)[UTC]
|
按 Enter 键确认“UTC” |
HTTP/FTP 代理 URL?(例如“http://proxy:8080”或“none”)[none]
|
按 Enter 键确认“none” |
输入镜像编号 (1-9) 或要添加的 URL(或 r/f/e/done)[f]
|
选择离您较近的镜像并按 Enter 键 |
哪个 SSH 服务器?(“openssh”、“dropbear”或“none”)[openssh]
|
按 Enter 键确认“openssh” |
要运行哪个 NTP 客户端?(“openntpd”、“chrony”或“none”)[chrony]
|
按 Enter 键确认“chrony” |
您想使用哪些磁盘?(或“?”表示帮助或“none”)[none]
|
按 Enter 键确认“none”或根据需要键入“none” |
输入存储配置的位置(“floppy”、“usb”或“none”)[usb]
|
按 Enter 键确认“usb” |
输入 apk 缓存目录(或“?”或“none”)[/media/usb/cache]
|
按 Enter 键确认“/media/usb/cache” |
网络配置
更新网络配置。
使用您喜欢的编辑器打开 /etc/network/interfaces
并添加接口
内容 /etc/network/interfaces
链路聚合
更新链路聚合配置。
使用您喜欢的编辑器打开 /etc/network/interfaces
并将 bond-mode
、bond-miimon
和 bond-updelay
参数添加到 bond0
节
内容 /etc/network/interfaces
启动新的链路聚合设置
ifdown bond0 ifup bond0
物理安装
此时,如果您尚未连接 VPN Spoke 节点到网络,则可以连接了。请设置一个支持 802.1q 的交换机,其中包含 AlpineSetup 部分中列出的 VLAN。完成后,在一个端口上标记所有 VLAN。将该端口连接到 eth0
。然后,将您的第一个 ISP 的 CPE 连接到具有 VLAN 256 未标记的交换机端口。
SSH
删除密码身份验证和 DNS 反向查找
sed -i "s/.PasswordAuthentication yes/PasswordAuthentication no/" /etc/ssh/sshd_config sed -i "s/.UseDNS yes/UseDNS no/" /etc/ssh/sshd_config
重启 ssh
rc-service sshd restart
NTP 服务器
为了让连接的设备再次与此主机同步时间,我们需要对 chrony 配置进行一些修改。
将 'allow all
' 添加到 '/etc/chrony/chrony.conf
' 的末尾,以便文件看起来像这样
内容 /etc/chrony/chrony.conf
重启 chronyd 以使更改生效
rc-service chronyd restart
递归 DNS
安装软件包
apk add -U unbound
使用您喜欢的编辑器打开 /etc/unbound/unbound.conf
并添加以下配置。如果您有要 unbound 解析但仅在您的网络内部的域名,则存在 stub-zone 节
内容 /etc/unbound/unbound.conf
启动 unbound 并在此主机上开始使用 unbound
rc-service unbound start rc-update add unbound echo nameserver 10.1.0.1 > /etc/resolv.conf
GRE 隧道
使用您喜欢的编辑器打开 /etc/network/interfaces
并添加以下内容
内容 /etc/network/interfaces
启动新的 gre1
接口
ifup gre1
IPSEC
安装软件包
apk add ipsec-tools
使用您喜欢的编辑器创建 /etc/ipsec.conf
并将内容设置为以下内容
内容 /etc/ipsec.conf
创建缺失的目录
mkdir /etc/racoon/
将您的 pfx 提取到 /etc/racoon
,使用文件名 ca.pem
、cert.pem
和 key.pem
(请参阅 上面的说明)。
使用您喜欢的编辑器创建 /etc/racoon/racoon.conf
并将内容设置为以下内容
内容 /etc/racoon/racoon.conf
编辑 /etc/conf.d/racoon
并取消设置 RACOON_PSK_FILE
内容 /etc/conf.d/racoon
启动服务
rc-service racoon start rc-update add racoon
下一跳解析协议 (NHRP)
安装软件包
apk add opennhrp
使用您喜欢的编辑器打开 /etc/opennhrp/opennhrp.conf
并将内容更改为以下内容
内容 /etc/opennhrp/opennhrp.conf
您必须为每个 hub 节点 IP 地址设置 DNS A 记录 hub.example.com
。
使用您喜欢的编辑器打开 /etc/opennhrp/opennhrp-script
并将内容更改为以下内容
内容 /etc/opennhrp/opennhrp-script
使其可执行并启动服务
chmod +x /etc/opennhrp/opennhrp-script rc-service opennhrp start rc-update add opennhrp
BGP
安装软件包
apk add quagga touch /etc/quagga/zebra.conf
使用您喜欢的编辑器打开 /etc/quagga/bgpd.conf
并将内容更改为以下内容(将 strongpassword
替换为您选择的密码,并将 %HUB_GRE_IP%
替换为 Hub 节点 GRE IP 地址)
- 为您在 NBMA 云中拥有的每个 Hub 主机添加行
neighbor %HUB_GRE_IP% remote-as 65000
。
内容 /etc/quagga/bgpd.conf
启动服务
rc-service bgpd start rc-update add bgpd
OpenVPN
安装软件包
echo tun >> /etc/modules modprobe tun apk add openvpn openssl openssl dhparam -out /etc/openvpn/dh1024.pem 1024
配置 openvpn
内容 /etc/openvpn/openvpn.conf
启动服务
rc-service openvpn start rc-update add openvpn
防火墙
安装软件包
apk add awall
启用 IP 转发
sysctl -w net.ipv4.ip_forward=1 sed -i 's/.*net\.ipv4\.ip_forward.*$/net.ipv4.ip_forward = 1/g' /etc/sysctl.conf
使用您喜欢的编辑器,编辑以下文件并将其内容设置为如下所示
内容 /etc/awall/optional/params.json
内容 /etc/awall/optional/internet-host.json
内容 /etc/awall/optional/openvpn.json
内容 /etc/awall/optional/clampmss.json
内容 /etc/awall/optional/mark.json
内容 /etc/awall/optional/dmvpn.json
内容 /etc/awall/optional/vpnc.json
激活防火墙
modprobe ip_tables modprobe iptable_nat awall enable clampmss awall enable openvpn awall enable vpnc awall activate -f rc-update add iptables
ISP 故障转移
安装软件包
apk add pingu echo -e "1\tisp1">> /etc/iproute2/rt_tables echo -e "2\tisp2">> /etc/iproute2/rt_tables
配置 pingu 以监视 bond0.256
和 bond0.257
接口在 /etc/pingu/pingu.conf
中。将要监视的主机添加到 /etc/pingu/pingu.conf
以进行 ISP 故障转移,并绑定到主 ISP。我们还将 ping 超时设置为 4 秒。
内容 /etc/pingu/pingu.conf
确保我们可以从 LAN 访问公共 IP,方法是为我们的专用网络添加静态路由规则。编辑 /etc/pingu/route-rules
内容 /etc/pingu/route-rules
启动服务
rc-service pingu start rc-update add pingu
现在,如果两个主机都停止响应 ping,则 ISP-1 将被视为关闭,并且所有通过 bond0.256 的网关将从主路由表中删除。请注意,网关不会从路由表“1”中删除。这样做是为了我们可以继续尝试通过 bond0.256
进行 ping,以便我们可以检测到 ISP 重新在线。当 ISP 再次开始工作时,网关将再次添加回主路由表。
提交配置
提交配置
lbu ci
Hub 节点
我们将仅记录与 Spoke 节点设置不同的更改。
路由表
echo -e "42\tnhrp_shortcut\n43\tnhrp_mtu\n44\tquagga\n>> /etc/iproute2/rt_tables
添加以下“up”命令
内容 /etc/network/interfaces
NHRP
在 Hub 2 上使用您喜欢的编辑器打开 /etc/opennhrp/opennhrp.conf
并将内容设置为如下所示
内容 /etc/opennhrp/opennhrp.conf
在 Hub 1 上执行相同的操作,添加与 Hub 2 相关的数据。
使用您喜欢的编辑器打开 /etc/opennhrp/opennhrp-script
并将内容设置为如下所示
#!/bin/sh case $1 in interface-up) ip route flush proto 42 dev $NHRP_INTERFACE ip neigh flush dev $NHRP_INTERFACE ;; peer-register) CERT=`racoonctl get-cert inet $NHRP_SRCNBMA $NHRP_DESTNBMA | openssl x509 -inform der -text -noout | egrep -o "/OU=[^/]*(/[0-9]+)?" | cut -b 5-` if [ -z "`echo "$CERT" | grep "^GRE=$NHRP_DESTADDR"`" ]; then logger -t opennhrp-script -p auth.err "GRE registration of $NHRP_DESTADDR to $NHRP_DESTNBMA DENIED" exit 1 fi logger -t opennhrp-script -p auth.info "GRE registration of $NHRP_DESTADDR to $NHRP_DESTNBMA authenticated" ( flock -x 200 AS=`echo "$CERT" | grep "^AS=" | cut -b 4-` vtysh -d bgpd -c "configure terminal" \ -c "router bgp 65000" \ -c "neighbor $NHRP_DESTADDR remote-as $AS" \ -c "neighbor $NHRP_DESTADDR peer-group leaf" \ -c "neighbor $NHRP_DESTADDR prefix-list net-$AS-in in" SEQ=5 (echo "$CERT" | grep "^NET=" | cut -b 5-) | while read NET; do vtysh -d bgpd -c "configure terminal" \ -c "ip prefix-list net-$AS-in seq $SEQ permit $NET le 26" SEQ=$(($SEQ+5)) done ) 200>/var/lock/opennhrp-script.lock ;; peer-up) echo "Create link from $NHRP_SRCADDR ($NHRP_SRCNBMA) to $NHRP_DESTADDR ($NHRP_DESTNBMA)" racoonctl establish-sa -w isakmp inet $NHRP_SRCNBMA $NHRP_DESTNBMA || exit 1 racoonctl establish-sa -w esp inet $NHRP_SRCNBMA $NHRP_DESTNBMA gre || exit 1 CERT=`racoonctl get-cert inet $NHRP_SRCNBMA $NHRP_DESTNBMA | openssl x509 -inform der -text -noout | egrep -o "/OU=[^/]*(/[0-9]+)?" | cut -b 5-` if [ -z "`echo "$CERT" | grep "^GRE=$NHRP_DESTADDR"`" ]; then logger -p daemon.err "GRE mapping of $NHRP_DESTADDR to $NHRP_DESTNBMA DENIED" exit 1 fi if [ -n "$NHRP_DESTMTU" ]; then ARGS=`ip route get $NHRP_DESTNBMA from $NHRP_SRCNBMA | head -1` ip route add $ARGS proto 42 mtu $NHRP_DESTMTU table nhrp_mtu fi ;; peer-down) echo "Delete link from $NHRP_SRCADDR ($NHRP_SRCNBMA) to $NHRP_DESTADDR ($NHRP_DESTNBMA)" if [ "$NHRP_PEER_DOWN_REASON" != "lower-down" ]; then racoonctl delete-sa isakmp inet $NHRP_SRCNBMA $NHRP_DESTNBMA fi ip route del $NHRP_DESTNBMA src $NHRP_SRCNBMA proto 42 table nhrp_mtu ;; route-up) echo "Route $NHRP_DESTADDR/$NHRP_DESTPREFIX is up" ip route replace $NHRP_DESTADDR/$NHRP_DESTPREFIX proto 42 via $NHRP_NEXTHOP dev $NHRP_INTERFACE table nhrp_shortcut ip route flush cache ;; route-down) echo "Route $NHRP_DESTADDR/$NHRP_DESTPREFIX is down" ip route del $NHRP_DESTADDR/$NHRP_DESTPREFIX proto 42 table nhrp_shortcut ip route flush cache ;; esac exit 0
BGP
在 Hub 2 上使用您喜欢的编辑器打开 /etc/quagga/bgpd.conf
并将内容设置为如下所示
内容 /etc/quagga/bgpd.conf
为您拥有的每个 spoke 节点添加行 neighbor %Spoke1_GRE_IP%...
。在 Hub 1 上执行相同的操作,更改 Hub 2 的相关数据。
DMVPN 故障排除
路径 MTU 发现 (PMTUD) 故障
害怕 ICMP 的 ISP(这在某种程度上是合理的)通常只是盲目地在其路由器接口中添加 no ip unreachables
,从而有效地创建 黑洞路由器,从而破坏 PMTUD,因为 ICMP 类型 3 代码 4 数据包(需要分片)被丢弃。ISAKMP 需要 PMTUD,它在 UDP 上运行(TCP 工作是因为它使用 CLAMPMSS)。
有关技术详细信息,请参阅 https://packetlife.net/blog/2008/oct/9/disabling-unreachables-breaks-pmtud/
PMTUD 也可能因 DSL 调制解调器/路由器配置错误或固件错误而损坏。关闭调制解调器本身上的防火墙或任何 VPN 直通功能可能会有所帮助。
您可以通过 ping DF 位集和标准 MTU 大小的数据包,以及 traceroute 到目的地的每个跃点,轻松检测到哪个主机是黑洞路由器
ping -M do -s 1472 %IP%
iputils
软件包中如果您没有收到响应(Echo-Response 或 Fragmentation-Needed),则表示防火墙正在丢弃 ICMP 数据包。如果它响应正常的 ping 数据包(DF 位清除),则很可能您遇到了黑洞路由器。
内核和 NHRP 路由缓存问题
