在多个DHCP服务器的网络环境中选择使用指定的DHCP服务

问题

学校有两个网络,我电脑网线插在同一个交换机的同一个接口上,有时候获取的是172.27开头的IP,有时候获取的是192.168开头的IP。
通常第一次开机获取的是172.27的IP,插拔网线或重启网络接口后会变为192.168的IP。
两个网络各有作用但是并不互通,非常影响正常使用网络,因此我使用以下方式使得电脑固定通过DHCP获取172.27开头的ip。

原因解析

这种现象表明电脑连接的是一个同时存在两个网络环境(两个不同的DHCP服务器)的局域网 ,并且这两个网络在同一个物理交换机上共存。

这个交换机可能连接着两个不同的路由器或三层设备 ,分别运行着两个DHCP服务。

  • 一个是提供 172.27.x.x 段的DHCP服务器,DHCP服务器和网关都是172.27.1.1
  • 一个是提供 192.168.x.x 段的DHCP服务器,DHCP服务器和网关都是192.168.1.1

当电脑发送DHCP请求时,两个DHCP服务器都可能收到请求,并响应DHCP Offer,客户端通常选择第一个收到的DHCP Offer 作为自己的配置来源;

解决方案

排除清单

  • ✔️如果允许手动设置IP地址,那很简单,直接手动设置IP为所需网段的IP地址即可。
  • ❌系统自带的防火墙一般无法过滤DHCP数据包

因此,在无法手动设置IP地址,没有权限操作上层交换机的情况下,只能通过技术手段,设法使得设备仅接收特定DHCP服务器的DHCP Offer。

Linux系统

Windows系统处理方案见下一节

输入以下命令监听eth0接口的DHCP报文

sudo tcpdump -i eth0 port 67 or port 68

方案

我电脑是Ubuntu 24.04,网络配置使用的是 netplan + systemd-networkd 的方案,但 systemd-networkd 的 DHCP 客户端并不支持对 DHCP Offer 进行筛选,因此我需要使用 dhclient 来替代DHCP的这个功能。

配置dhclient作为DHCP客户端

Ubuntu自带dhclient,默认没有启用。若没有则需要安装。

sudo apt install isc-dhcp-client

修改 dhclient 配置文件,将模板从 /etc/dhcp/dhclient.conf 复制到 /etc/dhcp/dhclient.eth0.confeth0修改为你的网络接口名称。添加一行reject 192.168.1.1;,使其拒绝来自192.168.1.1的内容,这样就可以只响应和接受172.27.1.1的DHCP服务了。

# /etc/dhcp/dhclient.eth0.conf
reject 192.168.1.1;

禁用原DHCP功能

修改 netplan 配置文件,设置将dhcp4: no,使 networkd 不处理 dhcp,交由 dhclient 完成。

# /etc/netplan/01-netcfg.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    enp6s0:
      dhcp4: no
      dhcp6: no

设置dhclient开机启动

配置 dhclient 服务以使其开机启动,创建以下文件:

参考:https://github.com/egberts/systemd-dhclient

# /etc/systemd/system/dhclient@.service
[Unit]
Description=dhclient on %I
Documentation=man:dhclient(8)

# dhclient wants network.target afterward
# dhclient will stay up regardlessof network.target failure
Wants=network.target

#
Before=network.target

# Binds to a specific device based on %i
BindsTo=sys-subsystem-net-devices-%i.device
After=sys-subsystem-net-devices-%i.device

[Service]
# Reads /etc/dhcp/dhclient.conf, by default
# Invokes /sbin/dhclient-script, by default, upon receiving a lease IP
# Force dhclient to run in foreground and let systemd handle all Unix FDs (0,1, and 2)
ExecStart=/sbin/dhclient -4 -d -v -cf /etc/dhcp/dhclient.%I.conf -pf /var/run/dhclient.%I.pid -lf /var/lib/dhcp/dhclient.%I.leases %I
Type=simple
PIDFile=/run/dhclient.%I.pid

# DHCLIENT should never exit, ever.
# DHCLIENT should not use '-1' option nor handle exit code 2 in a special way
Restart=always
##### TBD ExecStop=/sbin/dhclient -x
##### TBD ExecReload=/sbin/dhclient -r
#StandardInput=null
#StandardOutput=journal
#StandardError=journal

# Environment variables used by dhclient
#  Could define those envname in /etc/default/dhclient.%I
# PATH_DHCLIENT_CONF The dhclient.conf configuration file.
# PATH_DHCLIENT_DB The dhclient.leases database.
# PATH_DHCLIENT_PID The dhclient PID file.
# PATH_DHCLIENT_SCRIPT The dhclient-script file.
# environment filespec is prefaced with '-' as to ignore if unreadable or nonexisting
EnvironmentFile=-/etc/default/dhclient
EnvironmentFile=-/etc/default/dhclient.%I

[Install]
WantedBy=multi-user.target

设置开机启动,其中eth0修改为你的网络接口名称,下同:

sudo systemctl enable dhclient@eth0.service

这是重启应该就能成功了,如果你不想重启,执行以下代码应用该设置:

sudo netplan apply && sudo systemctl start dhclient@eth0.service

连带问题

系统中还存在一个systemd-networkd-wait-online.service服务,其目的是在完成计算机启动前等待网络连接,但我使用了 dhclient 替代了一部分 networkd 的功能,使其 无法再感知 IP 是否已配置成功,这会导致开机时卡在该步骤直至超时,影响启动体验。

建议直接禁用 systemd-networkd-wait-online.service

sudo systemctl disable systemd-networkd-wait-online.service
sudo systemctl mask systemd-networkd-wait-online.service

Windows系统

下载WinDivert

Windows Packet Divert(WinDivert)允许用户模式应用程序捕获/修改/丢弃发送到/来自 Windows 网络堆栈的网络数据包。

因此我们使用 WinDivert 过滤DHCP数据包。

下载WinDivert二进制包后解压到任意位置。

设置WinDivert过滤

管理员模式开启命令行,执行netfilter工具,设置为抛弃来自192.168.x.x网段的DHCP数据包:

Path\To\WinDivert-2.2.2-A\x64\netfilter.exe "inbound and udp.SrcPort == 67 and udp.DstPort == 68 and ip.SrcAddr >= 192.168.0.0 and ip.SrcAddr <= 192.168.255.255"

打开另外一个命令行窗口,输入以下命令重新获取IP地址:

ipconfig /release 
ipconfig /renew 

此时可以看到netfilter阻止了来自192.168.1.1的DHCP数据,并且能够获取172.27.x.x的ip地址

BLOCK ip.SrcAddr=192.168.1.1 ip.DstAddr=192.168.1.19 udp.SrcPort=67 udp.DstPort=68
BLOCK ip.SrcAddr=192.168.1.1  ip.DstAddr=192.168.1.19 udp.SrcPort=67 udp.DstPort=68
BLOCK ip.SrcAddr=192.168.1.1 ip.DstAddr=255.255.255.255 udp.SrcPort=67 udp.DstPort=68
BLOCK ip.SrcAddr=192.168.1.1 ip.DstAddr=255.255.255.255 udp.SrcPort=67 udp.DstPort=68

开机启动脚本

过滤特定DHCP服务.sh

# 设置 WinDivert netfilter.exe 所在目录
$scriptDir = "D:\Program Files\WinDivert-2.2.2-A\x64"
Set-Location $scriptDir

# 指定适配器名称
$adapterName = "Ethernet"

# 启动 netfilter,拦截来自 192.168.x.x 的 DHCP 响应(后台运行,隐藏窗口)
Start-Process -FilePath "$scriptDir\netfilter.exe" `
    -ArgumentList '"inbound and udp.SrcPort == 67 and udp.DstPort == 68 and ip.SrcAddr >= 192.168.0.0 and ip.SrcAddr <= 192.168.255.255"' `
    -WindowStyle Hidden

# 等待 netfilter 启动
Start-Sleep -Seconds 3

# 执行 DHCP 释放与续租
Write-Output "Releasing IP for adapter: $adapterName"
ipconfig /release "$adapterName" *> $null
Start-Sleep -Seconds 1
Write-Output "Renewing IP for adapter: $adapterName"
ipconfig /renew "$adapterName"

该脚本需要管理员权限,启动WinDivertnetfilter,并且重新获取一次IP地址。scriptDiradapterName变量以及IP地址按照实际情况修改。

脚本结束后netfilter会常驻在后台,可以使用以下命令停止:

Stop-Process -Name netfilter

将脚本放入启动目录或添加到计划任务程序(推荐)即可实现开机启动。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值