0

I have a machine (running openSUSE Leap 15.3) with multiple public IP addresses which serves as a gateway for a few additional hosts. I need to make one of the public IPs on the gateway act as though it belongs to one of the machines connected to it (traffic is transparently forwarded).

My iptables-save output currently is as follows (some irrelevant Docker rules are included but sensitive parts are redacted):

# Generated by iptables-save v1.8.7
*filter
:INPUT ACCEPT [9747976:4527721149]
:FORWARD ACCEPT [12638879:4423560060]
:OUTPUT ACCEPT [8913992:2531503118]
:DOCKER - [0:0]
:DOCKER-ISOLATION-STAGE-1 - [0:0]
:DOCKER-ISOLATION-STAGE-2 - [0:0]
:DOCKER-USER - [0:0]
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -j RETURN
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -j RETURN
-A DOCKER-USER -j RETURN
COMMIT
# Completed
# Generated by iptables-save v1.8.7
*nat
:PREROUTING ACCEPT [480085:188100350]
:INPUT ACCEPT [62951:4107383]
:OUTPUT ACCEPT [150:9857]
:POSTROUTING ACCEPT [0:0]
:DOCKER - [0:0]
-A PREROUTING -d <REDACTED_FORWARDING_IP>/32 -i eth0 -j DNAT --to-destination 10.125.0.2
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A POSTROUTING -j MASQUERADE
-A DOCKER -i docker0 -j RETURN
COMMIT
# Completed

The only relevant parts of that, as far as I know, are:

-A PREROUTING -d <REDACTED_FORWARDING_IP>/32 -i eth0 -j DNAT --to-destination 10.125.0.2
-A POSTROUTING -j MASQUERADE

This still has a number of issues:

  • When the internal machine initiates an outbound connection, its IP is NATed as the gateway's main address, not the address I'm trying to give it.
  • When receiving connections, they appear to be coming from the gateway's local IP, not the original IP (there should be a way around that as this is the default gateway).
  • If a service is listening on 0.0.0.0 on the gateway, connections on that port do not get redirected, they go to that service.

I tried to stitch together the answers to some other questions like:

But due to my lack of significant iptables experience, I couldn't solve my problems, or solved some only for others to pop up.

Can anyone suggest some rules to achieve this effect? Or perhaps there's a way to do this without iptables?

2
  • 1
    Please, attach a complete iptables-save output into the quesiton. All issues could have something to do with your SNAT rules set up. Also describe how you are making connections that display issues 2 and 3 (what is source address, what is inbound interface). I suspect you are SNATing too much, while DNAT rule matches could be made less restrictive. Commented Oct 2, 2021 at 14:00
  • @NikitaKipriyanov I attached the iptables-save output as requested. All connections going though the gateway display issues 2 and 3. They reach the gateway on eth0:0, the interface with the IP I'm trying to forward. In any case, my solution is likely very flawed due to my aforementioned lack of experience so it's probably best to not base answers on it. I mostly attached it to show that I have tried to do this myself.
    – user9123
    Commented Oct 2, 2021 at 14:36

1 Answer 1

1

When the internal machine initiates an outbound connection, its IP is NATed as the gateway's main address, not the address I'm trying to give it.

This should be solved with:

iptables -t nat -I POSTROUTING 1 -s 10.125.0.2 -o eth0 -j SNAT --to-source <FORWARD_IP>

It is added into the front, so it'll fire first, detect that packet is from this system and translate it into the specified IP, instead of picking an address from interface.

When receiving connections, they appear to be coming from the gateway's local IP, not the original IP (there should be a way around that as this is the default gateway).

This issue is connected to the following SNAT rule:

iptables -t nat -A POSTROUTING -j MASQUERADE

It is way too wide. You are SNATing everything in each direction, which is not efficient nor secure. It matches everything, including your DNATed packets. They are first destination-translated into private address, then their source is translated by this rule into address picked from a private interface where 10.x.x.x address is assigned.

I suspect you are trying to cover all public interfaces and all private networks with a single rule. While there are address lists in the Linux (IP sets), there is no interface lists, so it is not possible to do this correctly with just a single rule.

Filter it with at least the source address (e.g. which addresses to source-translate):

iptables -t nat -A POSTROUTING -s 10.125.0.0/24 -j MASQUERADE

If you have several private networks, add more rules of this kind.

I think it is better to create an individual rule for each public interface, so packets going out through private interface could never get source-translated whatever source address they have, e.g. iptables -t nat -A POSTROUTING -s 10.125.0.0/24 -o eth0 -j MASQUERADE and so on. This way packets from 10.x.x.x to 172.x.x.x will not get translated too, and your services in both networks will see each other's IP directly, still leaving the possibility to selectively filter them in the FORWARD filter chain.

If a service is listening on 0.0.0.0 on the gateway, connections on that port do not get redirected, they go to that service.

And, finally, I don't fully understand this point. I asked in the comment, you didn't answer. Which connections, from where, what's source IP?

The DNAT processing happens before the routing decision, that's why the chain is called "PREROUTING". It never checks if there is some local process listening on that port. The only way the local service to have chance to answer is to have the packet pass INPUT chain. For that, the routing code must decide it is destined to the local machine, so it must be ether not translated at all or be translated into some address this system has assigned.

With current rules, packets sent from private networks to the public IPs should not get translated, because they aren't coming in via eth0. So they are to be served by local services. But this doesn't depend on whether the local service is running or not; if it's not you will have the "connection refused".

If you need packets from LAN to the <FORWARD_IP> to be translated by the same DNAT rule, drop that -i eth0 match:

iptables -A PREROUTING -d <REDACTED_FORWARDING_IP>/32 -j DNAT --to-destination 10.125.0.2

However, I am against such a wide rule. In my opinion, it is better to have DNAT rules as tight as possible, so you better filter by the protos (tcp/udp) and ports of the services you are running on the 10.125.0.2. If that's a web server, only forward tcp/80 and tcp/443, like this: iptables -A PREROUTING -d <REDACTED_FORWARDING_IP>/32 -p tcp -m multiport --dports 80,443 -j DNAT --to-destination 10.125.0.2.

What's the problem? Say, you're checking something with the ping. This ping result will depend on this internal system state, it is the system you are pinging in reality. This is confusing. This is not the behaviour most sysadmins are expecting to see when they ping a router. So better leave ping to be answered by the host.

1
  • Thank you so much for the detailed answer and sorry about the delay, only just got the chance to try out your solution. I'm pleased to say that all issues are solved which makes me really happy because this has caused me significant annoyance. In regards to part 3, after clearing the firewall rules and setting them according to your answer, this seems to no longer be the case. I too was very confused about why that would be, but perhaps my exhaustion over firewall rules got the better of me and my testing was wrong. Thanks again though, you've helped massively :D
    – user9123
    Commented Oct 3, 2021 at 21:54

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .