mirror of
https://github.com/Baim0/baim0-learn.git
synced 2026-10-19 17:57:45 +08:00
9.8 KiB
9.8 KiB
ifcfg 备份文件会被 network 服务当配置执行(机制分析 + 源码)
- 记录日期:2026-09-24
- 结论:在 CentOS/RHEL 7 系(老式 initscripts)环境下,
/etc/sysconfig/network-scripts/里面的 ifcfg 备份文件会被 network 服务枚举并真实执行,只要满足两个条件:- 文件名以
ifcfg-开头、且不以~ / .bak / .old / .orig / .rpmnew / .rpmorig / .rpmsave结尾(即ifcfg-eth0.bak0923、ifcfg-eth0.bakup0921这类"bak+日期"命名会逃过过滤); - 文件里写了
DEVICE=eth0(有它,配置就作用到真实 eth0;没有它才会被跳过)。
- 文件名以
- 影响:地址按"累加"方式生效、默认路由"后者覆盖前者",最终状态取决于文件执行顺序,行为不可预期。
1. 完整执行链条(4 步)
| 步骤 | 位置 | 行为 |
|---|---|---|
| 1. 枚举 + 过滤 | network 服务脚本 |
ls ifcfg-*,用正则剔除"忽略文件"——只匹配结尾的 .bak/.old/...,bak+日期 命名逃过过滤 |
| 2. 取 DEVICE、查 ONBOOT | network 服务脚本 |
从每个文件里 grep DEVICE=;DEVICE 为空才回退用文件名;ONBOOT=yes 则拉起 |
| 3. 执行 ifup | network 服务脚本 |
./ifup eth0.bak0923 boot |
| 4. 作用对象由文件内 DEVICE 决定 | ifup / network-functions / ifup-eth |
载入备份文件全部变量后,REALDEVICE=${DEVICE%%:*} = eth0,后续加地址/装路由全部落在 eth0 上 |
2. 源码证据(逐段)
源码取自 fedora-sysv/initscripts(main 分支,与 CentOS/RHEL 7 系 initscripts 同源,行号可能有小差异)。 本目录
initscripts-source/下有 5 个文件的完整副本,可离线核对。
2.1 枚举 ifcfg-*(etc/rc.d/init.d/network,第 42-49 行)
# find all the interfaces besides loopback.
# ignore aliases, alternative configurations, and editor backup files
interfaces=$(ls ifcfg-* | \
LC_ALL=C sed -e "$__sed_discard_ignored_files" \
-e '/\(ifcfg-lo$\|:\|ifcfg-.*-range\)/d' \
-e '{ s/^ifcfg-//g;s/[0-9]/ &/}' | \
LC_ALL=C sort -k 1,1 -k 2n | \
LC_ALL=C sed 's/ //')
注释里写明"ignore … editor backup files"——意图是忽略备份文件,但实际过滤规则有漏洞(见 2.2)。
2.2 过滤规则:只匹配"结尾"(etc/rc.d/init.d/functions,第 609-614、678-679 行)
# Copy of the function is present in usr/sbin/service
is_ignored_file() {
case "$1" in
*~ | *.bak | *.old | *.orig | *.rpmnew | *.rpmorig | *.rpmsave)
return 0
;;
esac
# A sed expression to filter out the files that is_ignored_file recognizes
__sed_discard_ignored_files='/\(~\|\.bak\|\.old\|\.orig\|\.rpmnew\|\.rpmorig\|\.rpmsave\)$/d'
正则以
$结尾锚定:
ifcfg-eth0.bak→ 结尾是.bak→ 被忽略(正确行为)ifcfg-eth0.bak0923→ 结尾是0923→ 不被忽略,进入后续流程ifcfg-eth0.bakup0921→ 结尾是0921→ 不被忽略ifcfg-ens18.bakup0921→ 同样不被忽略(但 ens18 不存在,后续会被跳过,见 2.5)
2.3 DEVICE 取自文件内容 + ONBOOT 检查 + 拉起(etc/rc.d/init.d/network,第 91-134 行,节选)
# bring up all other interfaces configured to come up at boot time
for i in $interfaces; do
unset DEVICE TYPE SLAVE NM_CONTROLLED
eval $(LANG=C grep -F "DEVICE=" ifcfg-$i)
eval $(LANG=C grep -F "TYPE=" ifcfg-$i)
eval $(LANG=C grep -F "SLAVE=" ifcfg-$i)
eval $(LANG=C grep -F "NM_CONTROLLED=" ifcfg-$i)
if [ -z "$DEVICE" ] ; then DEVICE="$i"; fi
...
if ( . ./ifcfg-"$i" ; is_false "$ONBOOT" ) ; then
# this loads the module, to preserve ordering
is_available $i
continue
fi
action $"Bringing up interface $i: " ./ifup $i boot
[ $? -ne 0 ] && rc=1
done
备份文件里
DEVICE=eth0、ONBOOT="yes"→ 走到./ifup eth0.bak0923 boot。
2.4 作用对象 = 文件里的 DEVICE(network-scripts/ifup 第 27、53、168 行;network-scripts/network-functions 第 115-120、173-175 行)
# ifup
CONFIG=${1}
...
source_config
# network-functions
source_config ()
{
CONFIG=${CONFIG##*/}
DEVNAME=${CONFIG##ifcfg-}
. /etc/sysconfig/network-scripts/$CONFIG
[ -r "keys-$DEVNAME" ] && . /etc/sysconfig/network-scripts/keys-$DEVNAME
...
[ -z "$REALDEVICE" -a -n "$PARENTDEVICE" ] && REALDEVICE=$PARENTDEVICE
[ -z "$REALDEVICE" ] && REALDEVICE=${DEVICE%%:*}
ifup eth0.bak0923载入的是ifcfg-eth0.bak0923的全部变量(DEVICE=eth0、IPADDR=…、GATEWAY=…全部生效),然后真正的操作对象REALDEVICE= eth0。
# ifup 末尾把控制权交给 ifup-eth
exec ${OTHERSCRIPT} ${CONFIG} $2
2.5 "真实执行"还是"被跳过"的分界(network-scripts/ifup-eth)
有 DEVICE=eth0 → 真实执行,操作落在 REALDEVICE 上(第 329 行起):
# set lifetime of address to forever
ip addr change ${ipaddr[$idx]}/${prefix[$idx]} dev ${REALDEVICE} valid_lft forever preferred_lft forever
没有 DEVICE= → DEVICE 回退为文件名派生的 eth0.bak0923 → 设备不存在,报错并跳过(第 132-139 行):
# now check the real state
is_available_wait ${REALDEVICE} ${DEVTIMEOUT} || {
if [ -n "$alias" ]; then
net_log $"$alias device ${DEVICE} does not seem to be present, delaying initialization."
else
net_log $"Device ${DEVICE} does not seem to be present, delaying initialization."
fi
exit 1
}
判读提醒:日志里看到
Bringing up interface eth0.bak0923:不代表它没生效,要看整行有没有以does not seem to be present, delaying initialization收尾——有这句才是"被跳过"。
2.6 为什么"执行顺序不可预期"(network-scripts/ifup-eth 第 332-340 行)
# Set a default route.
if ! is_false "${DEFROUTE}" && [ -z "${GATEWAYDEV}" -o "${GATEWAYDEV}" = "${REALDEVICE}" ]; then
# set up default gateway. replace if one already exists
if [ -n "${GATEWAY}" ] && [ "$(ipcalc --network ${GATEWAY} ${netmask[0]} 2>/dev/null)" = "NETWORK=${NETWORK}" ]; then
ip route replace default ... via ${GATEWAY} ... ||
net_log $"Error adding default gateway ${GATEWAY} for ${DEVICE}."
- 地址:
ip addr change/add→ 累加(多份文件的不同地址会都加上去); - 默认路由:
ip route replace→ 后者覆盖前者; - 多个文件按
ls字母序依次执行 → 最终状态取决于内容与顺序,不可预期。
3. 在机器上实锤的方法
# 1) 本次启动/重启实际拉起了哪些"接口名"
grep -i "Bringing up interface" /var/log/messages | tail -30
journalctl -b -u network --no-pager | tail -80
# 判读:出现 eth0.bak0923 等名字且整行无 "does not seem to be present" → 真实执行了
# 2) 文件差异对比(谁和谁不一样、哪个"赢了")
cd /etc/sysconfig/network-scripts
md5sum ifcfg-eth0 ifcfg-eth0.bak0923 ifcfg-eth0.bakup0921
grep -H -E "DEVICE|ONBOOT|IPADDR|PREFIX|GATEWAY" ifcfg-eth0*
4. 规避建议
- 备份文件不要放在
/etc/sysconfig/network-scripts/里;非要放,至少不要以ifcfg-开头(例如改成eth0_backup_0921)。 - 如果用
ifcfg-开头命名,只能靠"结尾"后缀才能被忽略:ifcfg-eth0.bak可以,ifcfg-eth0.bak0923不行。 - 已存在的备份建议统一移走:
mkdir -p /root/backup-network-scripts
mv /etc/sysconfig/network-scripts/ifcfg-*bak* /root/backup-network-scripts/
ls /etc/sysconfig/network-scripts/ifcfg-* # 预期只剩本体配置和 ifcfg-lo
文件命名规则速查表:
| 文件名 | 是否会被当设备配置执行 |
|---|---|
ifcfg-<设备名>(如 ifcfg-eth0) |
是(设备本体配置) |
ifcfg-<设备名>:<n>、ifcfg-<设备名>-range<n>、ifcfg-<设备名>.<vlan数字> |
是(别名/批量别名/VLAN,有专门逻辑) |
以 ~、.bak、.old、.orig、.rpmnew、.rpmorig、.rpmsave 结尾 |
否(被过滤规则忽略) |
*.bak0923、*.bakup0921、*.bak_日期 等"bak+后缀" |
是,会被枚举执行(本次踩坑点) |
不以 ifcfg- 开头的任意命名 |
否 |