摘要
Linux 平台 Netplan, NetworkManager, Systemd-networkd 等网络管理器的基本概念和使用导读。以及多个网卡连接同一个私有网络时,因为反向路由过滤 (rp_filter) 造成的网络问题填坑。
前提
本文的实验环境基于 Ubuntu 22.04.4 LTS,安装在 KVM 虚拟机中,安装模式为 Minimal Server ,内核版本为 5.15.0-107-generic。
本文主要针对无图形界面的 Linux 服务器网络配置,介绍网络管理器的选择和基本操作,具体的网络配置参数和相应的操作命令语法,不在讨论范围内。
历史和变化
ifupdown/ifconfig 是 Linux 系统上传统的的网络管理命令行工具,根据配置文件创建网络连接。
NetworkManager 是具备守护进程,可进行自动配置的网络管理器。
Systemd-networkd 是 Systemd
内置的网络管理器,出现时间最晚。缺少图形化操作界面,目前专注于有线网络参数配置,多适用于服务器环境
netplan 为前述两个管理后端生成配置参数,作为用户和网络配置间的抽线代理。
iproute2 操作网络接口和连接的网络管理命令行工具,也同样支持配置文件。
Netplan
netplan
是 Ubuntu 系统的默认网络管理器,严格来说 netplan
更像网络管理器的前端,因为他的工作主要是为 Systemd-networkd
生成配置信息。
netplan 服务程序通过读取 /etc/netplan/
目录下的配置文件为 Systemd-networkd 生成运行时网络配置。系统启动时,此目录下所有的配置文件都将被加载。一个典型的 netplan 配置文件如下:
network:
ethernets:
enp1s0:
addresses:
- 192.168.1.237/24
nameservers:
addresses: [119.29.29.29, 180.76.76.76, 223.6.6.6]
search: [vms.example.org]
routes:
- to: default
via: 192.168.1.1
- to: 192.168.1.0/24
via: 192.168.1.1
on-link: true
table: 100
routing-policy:
- priority: 100
from: 192.168.1.0/24
table: 100
- priority: 110
from: 192.168.1.0/24
table: 100
version: 2
如果熟悉 yaml 语法,这个配置称得上简洁明了,需要启用新网络参数也简单,只需敲入 netplan apply
命令,netplan 即可搞定剩下的一切。
这个配置文件为 'enp1s0' 连接配置了:
- IPv4 地址,每个连接都可以有多个;
- DNS 解析服务器,只有前三个服务器配置会生效;
- 路由,包括一个默认路由(取代了网关),和一个链路路由(直达);
- 策略路由规则,根据源和目的选择路由表;
没有配置文件 netplan 不会做任何事情。此时 Linux 服务器所有的网络管理器都不会生效。因此最简单的配置文件就派上用场了。
netplan renderer
默认情况下 netplan 采用的后端是 Systemd-networkd。指定 renderer 为 NetworkManager, Systemd-networkd 将不再管理网络连接和接口,管理权移交至前者负责。默认情况下 NetworkManager 指定所有网络接口通过 DHCP
获取 IP 地址。
指定 renderer 为 networkd 或简单忽略此行,netplan 将继续应用 networkd 后端。
network:
version: 2
renderer: NetworkManager
需要注意的是,如果配置文件中指明了特定的接口,那么需要为每一个接口在配置目录中编写配置文件。
systemd-networkd-wait-online 超时问题
Netplan renderer 指定为 NetworkManager 会产生一个隐藏的副作用:服务器每次启动,都须等待 systemd-networkd-wait-online.service
服务超时(120s),造成启动缓慢。对承载业务的服务器而言这已是无法承受的代价。
引发问题的原因是:systemd-networkd-wait-online 的任务是启动过程中后台服务的依赖检查点,确保网络参数得到正确配置以后,才能继续加载后续服务。通常这不会是个问题:
- Ubuntu 系统 netplan 的默认后端就是
Systemd-networkd
,wait-online 操作自然顺利完成; - 其他的系统要么仍然使用
ifupdown
/ifupdown2
管理工具、要么已经预置NetworkManager
为模式网络管理器;不存在 networkd online 问题。
解决这个问题的思路基本上有三种:
- 禁用
networkd-dispatcher.service
、network-online.service
、systemd-networkd.service
等三个服务; - 使用
Systemd-networkd
服务管理网络 - 按接口区分,部分由 Netplan/Sytemd-networkd 管理,部分由 NetworkManager 进行管理
由于 NetworkManager 本身已经是一个成熟且完善的网络管理机制,它本身同样提供 NetworkManager-wait-online.service, 其所处的 target 也与 networkd 的相关服务一致。故推荐使用第一种。
NetworkManager
NetworkManager 是为了使网络配置尽可能简单而开发的网络管理软件包,如果使用 DHCP,它会替换默认的路由表,目标是使网络开箱即用。
NetworkManager 由两个部分组成:
- 一个以超级用户身份运行的守护进程
- 前端管理程序,包括命令行工具
nmcli
和文本图形工具nmtui
NetworkManager.conf 配置文件位于 /etc/NetworkManager/
,自定义配置通常放置于此路径下的 Drop in 目录 conf.d
。
受管理的设备
多个网络管理服务管理同一个方案时,将会产生冲突
[keyfile]
# 指定特定接口名称设备设备非受管
unmanaged-devices=interface-name:enp1s0
# 指定特定 mac 地址设备非受管
unmanaged-devices=mac:52:54:00:74:79:56
# 指定特定设备类型非受管
unmanaged-devices=type:ethernet
# 指定多个设备选择条件,用分号(;)分隔
unmanaged-devices=interface-name:enp1s0;interface-name:enp7s0
此外,在 Debian 和 Ubuntu 发行版中,启用 ifupdown 插件,可以控制 /etc/network/interfaces
目录下配置文件所引用的网络设备是否受 NetworkManager 管理。
[main]
plugins=ifupdown,keyfile
[ifupdown]
managed=false
注意该配置仅针对传统方案配置文件存在时生效,对未纳入 NetworkManager 管理的其它网络设备而言,该配置项不产生任何影响。
修改配置文件后,需重新载入 NetworkManager 服务使之生效: systemctl reload NetworkManager
使用 nmcli
和 nmtui
配置网络
使用 nmtui
将启动一个基于字符的图形界面,可以完成基本的 IP 地址、网关、DNS 服务器地址等配置。
使用 nmcli
可以完成更多的高级功能配置,具体的 nmcli 命令参数相对复杂,这里给出一些最基本的 nmcli 示例。
# 显示所有连接
nmcli connection show
# 也可以简写为,以下采用简写模式
nmcli con show
# 显示连接的详细配置信息,需指定连接的名称
nmcli con show <con-name>
# 显示网络设备的概要信息,设备名称可选
nmcli dev show [<dev-name>]
# 设置 ipv4 的一般功能,以增加 ipv4 地址为例
nmcli con mod <con-name> +ipv4.addresses "192.168.1.0/24"
# 设置路由表,不带 + 号时将替换现有路由表,指定路由表编号可选
nmcli con mod <con-name> ipv4.routes "0.0.0.0/0 192.168.1.1 [table=<table-number>]"
# 设置策略路由,以指定接口流量按指定路由表模式为例
nmcli con mod <con-name> ipv4.touting-rules "priority 100 iif <con-name> table <table-number>"
# 在指定设备上应用更新
nmcli dev reapply <dev-name>
从 netplan 切换到 network 模式
完成切换过程的基本步骤是:修改 netplan 配置文件、禁用 networkd 相关服务、配置 新的网络参数。因为 Linux 服务器使用了 SSH 链接,修改网络管理器将不可避免的导致网络断开连接,以下脚本可以自动注册一次性服务,并重启计算机完成切换操作。
PART-I: 修改本机主机名,并配置本地地址解析
MYHOSTNAME=kavms10-h4v3
hostnamectl hostname ${MYHOSTNAME}
cat << EOF > /etc/hosts
127.0.0.1 localhost
127.0.1.1 ${MYHOSTNAME}.vms.example.org ${MYHOSTNAME}
192.168.1.231 kmvms01-h2v1.vms.example.org kmvms01-h2v1
# Other hosts ....
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
EOF
PART-II:备份 netplan 的默认配置文件,并指定 netplan 采用 NetworkManager 作为网络管理后端
{
SCNAME=yhamcit_init_ip_addr
DEFCONFIL=`ls /etc/netplan/00-* | xargs basename `
for CONFIL in `ls /etc/netplan/ | grep -v ${DEFCONFIL}`; do rm -f /etc/netplan/${CONFIL}; done
[ -f /etc/netplan//etc/netplan/${DEFCONFIL}.bak ] || mv /etc/netplan/${DEFCONFIL} /etc/netplan/${DEFCONFIL}.bak
cat << EOF > /etc/netplan/${DEFCONFIL}
# This file describes the network interfaces available on your system
# For more information, see netplan(5).
# Set and change netplan renderer to NetworkManager GUI tool
network:
version: 2
renderer: NetworkManager
EOF
}
PART-III: 禁用 networkd 服务守护进程
systemctl disable networkd-dispatcher.service network-online.service systemd-networkd.service
PART-IV:生成网络初始化配置守护进程
{
LSBSCFILE=/etc/init.d/${SCNAME}
cat << "EOF" > ${LSBSCFILE}
#! /usr/bin/bash
### BEGIN INIT INFO
# Provides: ${SCNAME}
# Required-Start: $network $NetworkManager
# Required-Stop: $network $NetworkManager
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: make ip address for networkmanager
### END INIT INFO
EOF
# 遍历当前网卡
for CONN in `ip a | sed -nr 's#^.*inet (.*) brd .*(enp[[:digit:]]s[[:digit:]])$#\2;\1#gp'`; do
IFNAME=`echo ${CONN} | awk -F\; '{print $1}'`
CIDR=`echo ${CONN} | awk -F\; '{print $2}'`
# 生成修改连接的命令,包括:修改连接名称、设置 IP、网关、路由、和路由策略
echo "CONAME=\`nmcli con show | grep ${IFNAME} | sed -En 's#^(.*) ([0-9a-f]+\-?)+ +ethernet .*\$#\1#gp'\`" >> ${LSBSCFILE}
echo "nmcli con mod \"\${CONAME}\" con-name ${IFNAME}" >> ${LSBSCFILE}
echo "nmcli con mod ${IFNAME} ipv4.addresses \"${CIDR}\"" >> ${LSBSCFILE}
echo "nmcli con mod ${IFNAME} ipv4.dns "119.29.29.29"" >> ${LSBSCFILE}
echo "nmcli con mod ${IFNAME} +ipv4.dns "180.76.76.76"" >> ${LSBSCFILE}
echo "nmcli con mod ${IFNAME} +ipv4.dns "223.6.6.6"" >> ${LSBSCFILE}
SUBN=`echo ${CIDR} | sed -En 's#^((\.?[[:digit:]]{1,3}){3}).*(\/[[:digit:]]{2})$#\1#gp'`
ADDR=`echo ${CIDR} | sed -En 's#^((\.?[[:digit:]]{1,3}){3}).*(\/[[:digit:]]{2})$#\2#gp'`
MASK=`echo ${CIDR} | sed -En 's#^((\.?[[:digit:]]{1,3}){3}).*(\/[[:digit:]]{2})$#\3#gp'`
TABLID=$(( ${ADDR:1} / 100 ))
echo "nmcli con mod ${IFNAME} ipv4.gateway ${SUBN}.254" >> ${LSBSCFILE}
echo "nmcli con mod ${IFNAME} ipv4.method manual" >> ${LSBSCFILE}
echo "nmcli con mod ${IFNAME} ipv4.routes \"0.0.0.0/0 ${SUBN}.254 table=1${TABLID}\"" >> ${LSBSCFILE}
echo "nmcli con mod ${IFNAME} +ipv4.routes \"${SUBN}.0${MASK} ${SUBN}.254 table=1${TABLID}\"" >> ${LSBSCFILE}
echo "nmcli con mod ${IFNAME} ipv4.routing-rules \"priority $(( 105 + ${TABLID} * 5)) iif ${IFNAME} table 1${TABLID}\"" >> ${LSBSCFILE}
echo "nmcli con mod ${IFNAME} +ipv4.routing-rules \"priority $(( 115 + ${TABLID} * 5)) from ${SUBN}.0${MASK} table 1${TABLID}\"" >> ${LSBSCFILE}
echo "nmcli con mod ${IFNAME} +ipv4.routing-rules \"priority $(( 125 + ${TABLID} * 5)) to ${SUBN}.0${MASK} table 1${TABLID}\"" >> ${LSBSCFILE}
# 网络参数生效
echo "nmcli dev reapply ${IFNAME}" >> ${LSBSCFILE}
done
cat << EOF >> ${LSBSCFILE}
# 守护脚本执行结束,清理自身服务
systemctl disable ${SCNAME}
update-rc.d -f ${SCNAME} remove
rm -f \`find / -name *${SCNAME}*\`
EOF
}
PART-V: 初始化服务制作完毕,注册服务
chmod +x ${LSBSCFILE}
update-rc.d ${SCNAME} defaults
reboot
以上代码 PART-IV 将在系统重启后运行,其它都会在本脚本中立刻生效。将素有内容放置在 '{}' 一次性执行整个代码块,或放置在脚本中运行。重启后会切换到 NetworkManager 管理器下,同时保留原 IP 地址。
全部完成后,再次重启将完全抹掉初始化服务的痕迹。
Systemd-networkd
networkd 作为 Systemd 的一部分,其配置文件保存于 /etc/systemd/network/
或其它 Systemd 配置文件目录的 network 子目录下,配置方式与 NetworkManager 类似。由于可采用 netplan 进行配置,故不再展开讨论。
对策略路由的支持
networkd 同样可配置基于规则的策略路由, 具体内容参考networkd man(8),ArchLinux 关于 systemd-networkd的实用手册。
命令行工具
同时 networkd 也附带了有用查询网络连接状态的命令行工具 networkctl
,但是该工具目前没有设置网络参数的功能。
多连接网络配置
在服务网络中,难以避免的需要管理/维护/控制链路和业务流量链路物理隔离。当 Linux 服务器有两个及以上的连接接入同一个私有网络,即便两个接口具有不同的 CIDR 地址段,仍然可能发生部分网段不通的问题。
假设有位于第三网段的目标地址,则同时在两个链路上存在默认路由,使目标链路多路可达。这种情况会触发反向路径过滤,导致匪夷所思的网络问题,甚至 iptables 日志和接口 tcpdump 都能看到数据发送,但数据包就是不会出现在网络中。
rp_filter
Linux 内核当中的反向路径过滤开关(rp_filter)打开时,Linux 通过反向路由查询,检查收到的数据包源IP是否可路由、是否最佳路由,如果没有通过验证,则丢弃数据包,设计的目的是防范IP地址欺骗攻击。rp_filter提供三种模式供配置:
- 0 - 不验证
- 1 - 严格模式(Strict mode):根据 RFC3704 的定义,对每个收到的数据包,查询反向路由,如果数据包入口和反向路由出口不一致,则不通过
- 2 - 松散模式(Loose mode):根据 RFC3704 的定义,对每个收到的数据包,查询反向路由,如果任何接口都不可达,则不通过
反向路由过滤功能配置文件分为全局和网卡,分别位于路径: /proc/sys/net/ipv4/conf/all/rp_filter 和 /proc/sys/net/ipv4/conf/NIC接口/rp_filter
临时禁用 rp_filter
解除 rp_filter 限制,直观的做法是禁用此功能,但是在企业级网络设备中,交换机和路由器同样会做反向路径检查,盲目的关闭此功能可能埋下更为隐蔽的缺陷。可临时禁用此功能用于检查。
# kernel default setting
sysctl -w net.ipv4.conf.default.rp_filter =1
# global setting
sysctl -w net.ipv4.conf.all.rp_filter =1
# per nic setting
sysctl -w net.ipv4.conf.enp1s0.rp_filter =1
# other nics
永久禁用 rp_filter
永久禁用此功能须慎重,修改 /etc/sysctl.conf
文件并重启,rp_filter 功能将永久关闭。
net.ipv4.conf.default.rp_filter =1
net.ipv4.conf.all.rp_filter =1
net.ipv4.conf.enp1s0.rp_filter =1
使用 nmcli 配置策略路由
配置默认路由和本地链路路由到指定路由表,包含默认路由、链路直达路由两种基本情况。
### Example of a route for the locally connected subnet
# nmcli con mod enp7s0 +ipv4.routes "192.168.0.0/24 table=10"
### Example of a route to send a remote subnet (10.0.0.0/24) via a specific gateway (192.168.0.254)
# nmcli con mod enp7s0 +ipv4.routes "10.0.0.0/24 192.168.0.254 table=10"
通过规则限制流量分流至指定路由表,包含从指定接口进入,源自/目的指定网段的流量三种规则。
### Anything which comes in this interface, send to table 10
# nmcli con mod enp7s0 ipv4.routing-rules "priority 100 iif enp7s0 table 10"
### Anything from this system's local IP, send to table 10
# nmcli con mod enp7s0 +ipv4.routing-rules "priority 110 from 192.168.0.2 table 10"
### Anything to the local subnet, send to table 10
# nmcli con mod enp7s0 +ipv4.routing-rules "priority 120 to 192.168.0.0/24 table 10"
设置完毕检查无误后启用
nmcli con show enp7s0
nmcli dev reapply enp7s0
需注意,路由规则的优先级应全局差异配置,而非对应连接差异配置
配置策略路由的说明
netplan +/ networkd 同样可以配置策略路由,通常情况下三层流量可以正常工作。但是这种方案缺少配置二层流量规则的能力,即配置从特定接口进入的流量规则。配置文件中的 from/destination 指令只能匹配 IP 地址,容易引起 TCP/UPD/IP 正常但是 PING 不通的奇怪现象。
其它内核开关
当多个连接接入同一个网络时,还应关注 proxy_arp
和 arp_filter
,这两个开关分别控制服务是否对对已知的外部 IP 地址进行 ARP 代答或内部 IP 通过不可路由接口代答。这两个开关可能导致 Linux 服务器从非预期的接口进行通信,造成网络设备设置的障碍。
- 开启 proxy_arp ,如果请求中的 IP 不是本机网卡接口的地址,该地址路由可达,则会以自己的 MAC 地址进行回复;否则不回复。
- 开启 arp_filter,请求中的 IP 是本机接口的地址,arp 客户端地址通过接收接口路由可达, 则应答此arp,否则不应答。**
参考资料
How exactly are NetworkManager, networkd, netplan, ifupdown2, and iproute2 interacting?