If your network adapter has multiple IP addresses configured, which one is used when sending packets? On Linux, you can use the iproute2 tool to force the source address by setting the src parameter:
ip route add 1.2.3.4/32 via 4.3.2.1 src 3.3.3.3
But on Windows, everything is chosen automatically by internal logic, following these principles:
With a single NIC, the best-matching IP address in the same subnet as the default gateway is chosen as the source;
With multiple NICs, the NIC containing the default gateway is chosen first as the sending NIC, and then an IP address on that NIC is chosen as the source according to the single-NIC rule.
Therefore, if your target address is 1.2.3.4, the default gateway is 4.3.2.1, and two IP addresses鈥?.3.2.2 and 3.3.3.3鈥攁re configured on the local connection, obviously 4.3.2.2 will be chosen as the source IP address. Thus when sending packets, 4.3.2.2 will serve as the source IP.
However, sometimes you may not want the system to automatically encapsulate the source IP address this way鈥攆or instance, when implementing your own policies or tricks, with OpenVPN being an obvious example.
First, let’s look at what the so-called default gateway essentially means. The default gateway is actually a more specific “next hop”鈥攊t is simply a next-hop address whose purpose is to throw packets to the next hop (stating the obvious). It only plays a supporting role; what actually matters is the MAC address resolved from it, because the MAC address is what really gets encapsulated in the Ethernet frame. The default gateway is only used to obtain this MAC address. Therefore, if you can statically specify a MAC address, the default gateway can be anything. This leads to a method:
1. Generate a fake default gateway (a fake next hop) for the route that lies in the same subnet as the desired source IP address;
2. Create a static ARP mapping for that fake gateway IP to the MAC address of the real gateway.
In this way, the source IP address selection process fully complies with Windows’ selection logic, and we bypass its restrictions from outside the kernel, enabling us to choose any address configured on the local connection as the source IP address.
To turn this manual configuration into an automated process, programming is indispensable. But I didn’t want to call those complex APIs (having to do a huge amount of prep work just for a simple function…), so I had to pin my hopes on scripting. However, the Windows command line is quite weak, which made it tricky. After asking colleagues, Baidu, Google, and trying over and over again, struggling for far too long, I finally wrote a batch script. I found that Windows XP’s scripting capabilities are actually quite powerful, not to mention PowerShell. The script is as follows (without echo off):
[plain]
set destination=%1
set mask=%2
set origw=%3
set source=%4
::Get default gateway (auto-discovery of the default gateway is possible, but too fancy and not recommended)
:::GetGW
::set origw=
::for /f "delims=: tokens=2" %%i in (‘"ipconfig | find /i "default gateway"| findstr [0-9]."’) do set origw=%%i
::Get the MAC address of the default gateway
:GetMac
set mac=
for /f "skip=3 tokens=2" %%i in (‘arp -a %origw%’) do set mac=%%i
echo %mac%|findstr –
::There’s an issue here: even if ping fails (e.g., the gateway blocks ping), it doesn’t matter, we just need its MAC address
::If even the MAC address cannot be resolved, then it shouldn’t be the default gateway. So the correct approach is to implement a counter, and consider it a failure only after two consecutive MAC retrieval failures.
if ERRORLEVEL 1 (
ping %origw% -n 1
if ERRORLEVEL 1 goto end
goto GetMac
)
set gw=
set i=
::Generate fake gateway address (a very simple algorithm: subtract 1 from the desired source IP address)
for /f "delims=. tokens=4" %%i in (‘echo %source%’) do set /a host=%%i-1
set i=
set j=
set k=
for /f "delims=. tokens=1,2,3" %%i in (‘echo %source%’) do set gw=%%i.%%j.%%k.%host%
::Set the ARP mapping for the fake gateway
arp -s %gw% %mac%
::Add the route
route add %destination% mask %mask% %gw