I have a server with two IP addresses attached to a single interface:
2: enp27s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 30:9c:23:83:64:f6 brd ff:ff:ff:ff:ff:ff
inet [IP_1]/32 scope global noprefixroute enp27s0
valid_lft forever preferred_lft forever
inet [IP_2]/32 scope global enp27s0
valid_lft forever preferred_lft forever
inet6 [IP6_1]/64 scope link
valid_lft forever preferred_lft forever
And I have a few virtual machines running on it and whenever they communicate with the outside world, their packets get IP_1
as the source IP. I also have a specific VM which I'd like to "route" through IP_2
instead. I don't want to attach it entirely to that IP address, I'd still prefer for it to stay inside the virtual network, but I want all of the packets coming out of it have IP_2
as their source IP.
I tried to apply a SNAT translation to achieve that, but it didn't really work:
iptables -t nat -A POSTROUTING -s [VM_IP] -o enp27s0 -j SNAT --to-source [IP_2]
I assume that's because by the time packets finish routing they already have IP_1
as source IP and the -s [VM_IP]
part of rule doesn't match. Changing that to -s [IP_1]
or just setting IP_2
as the primary IP could work probably, but I kinda need other VMs to have their outgoing traffic be routed through IP_1
.
Are there any ways to achieve that? I'm pretty sure a question like that has been asked here before, but unfortunately my inexperience prevents me from coming up with keywords to put in the search bar to find it :(
Update: here's my POSTROUTING table rules (excluding that one SNAT rule):
# iptables -t nat -S POSTROUTING
-P POSTROUTING ACCEPT
-A POSTROUTING -j LIBVIRT_PRT
# iptables -t nat -S LIBVIRT_PRT
-N LIBVIRT_PRT
-A LIBVIRT_PRT -s 192.168.122.0/24 -d 224.0.0.0/24 -j RETURN
-A LIBVIRT_PRT -s 192.168.122.0/24 -d 255.255.255.255/32 -j RETURN
-A LIBVIRT_PRT -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p tcp -j MASQUERADE --to-ports 1024-65535
-A LIBVIRT_PRT -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p udp -j MASQUERADE --to-ports 1024-65535
-A LIBVIRT_PRT -s 192.168.122.0/24 ! -d 192.168.122.0/24 -j MASQUERADE
Given your existing ruleset, when you run...
...it gets appended at the end of the
POSTROUTING
chain, so you end up with:That's too late; at this point, the packet has already traversed the
MASQUERADE
rules and will no longer match-s [VM_IP]
. This rule will probably do what you want if you move it in front of the-J LIBVIRT_PRT
rule:Using
-I
(without an explicit index) inserts the rule at the top of the chain.