原文地址:http://jensd.be/343/linux/forward-a-tcp-port-to-another-ip-or-port-using-nat-with-iptables
Besides using NAT for accessing the internet with multiple machines using a single IP address, there are many other uses of NAT. One of them is to forward all traffic that is sent to a certain TCP port to another host. In practice, this technique can be used to test a service on a new host without adjusting anything on the client. The users or the clients do not need to be pointed to a new machine in order to test it. When the test would be unsuccessful, removing the NAT-rule is all it takes to switch back.
To above scenario is better known as port forwarding and it allows you to forward an incoming packet to another destination. That destination can be another port or IP-address. With the scheme under here, I will try to make things a little more visual and explain how port forwarding works:
The left part of the scheme shows the original situation: the client connects to service A, running on server A (ip: 10.1.1.1). Incoming packets come through service A on server A and the outgoing packets go back to the original source IP, client A. The goal of the NAT-setup is to forward the traffic to service A running on server B (ip:10.2.2.2) without any modifications to client A. Our new setup needs to be transparent for the client.
The right part of the scheme shows our goal: the client still connects to TCP port 9999 to the IP of server A (10.1.1.1) so nothing changed on that side. As soon as a TCP packet with destination port 9999 arrives at server A, it should be forwarded to server B (ip: 10.2.2.2). Before redirecting the TCP-packet to the other machine, the packet needs to be modified so that it get’s sent back to server A before sending back to the original host.
To completely understand this process, we need to take a deeper look into how Iptables works. When a packet passes through Iptables, it passes a set of chains. Decisions made by those chains are called rules and that’s basically how you configure Iptables.
Overview of the chains used by Iptables
For our setup to work, we need to add a DNAT and SNAT rule (Prerouting and Postrouting). The first one will make sure that the packet gets routed to the other host (ip: 10.2.2.2) and the second one will make sure that the source address of the packet is no longer the original one but the one of the machine who performed the NAT. That way, the packet will be sent back to it’s original source via the host which owns ip 10.1.1.1.
Since CentOS or RHEL 7, iptables has been “replaced” with firewalld. And while you can realize the scenario with firewalld, I will use the classic iptables. To use iptables instead of firewalld on CentOS 7 or RHEL 7, you can find more information in this post.
The next steps prepare the system and iptables for NAT. Most commands can be used on CentOS, RHEL and Debian in exactly the same way. If there are some differences, I mention them (so if nothing special is mentioned, the commands are interchangeable).
NAT uses IP forwarding and by default it’s not enabled in the kernel parameters. First we need to check if IP forwarding is enabled and if it’s not, we need to enable it.
To check if IP forwarding is enabled:
CentOS/RHEL:
Debian:
The above outputs shows that IP forwarding is not enabled.
To enable IP forwarding persistently (survives a reboot):
CentOS/RHEL:
Debian:
To activate the changes immediately:
CentOS/RHEL:
Debian:
The next thing to do is to check if Iptables is running on the system. Iptables is running as a kernel module so it can’t be seen as one of the normal processes.
CentOS/RHEL:
Debain:
If there is no output, it means that Iptables isn’t loaded.
To start Iptables:
Now that we are sure that Iptables is active on the system, we can check which rules are active.
For the INPUT, FORWARD and OUTPUT-chains:
For the NAT-related chains:
As you can see, at this moment, no rules are configured and all traffic is allowed to and from the system without doing anything NAT-related.
In case you already have some rules configured, it’s a good idea (in a testing environment) to flush the current rules:
After going trough the above steps, we’re ready to active the port forwarding. As an example, I will forward the TCP port 9999 of host 192.168.202.103 to TCP port 80 on host 192.168.202.105.
First I will check that nothing is actually listening on port 9999 of host 192.168.202.103 by doing a telnet to port 9999 on that machine:
jensd@deb:~$ telnet 192.168.202.103 9999
Trying 192.168.202.103…
telnet: Unable to connect to remote host: Connection refused
To be sure that something is listening at port 80 of host 192.168.202.105, where I want to get forwarded, I can do the same check:
As you can see, there is a webserver running on port 80 on host 192.168.202.105.
Now, to forward port 9999 on host 192.168.202.103 to port 80 on host 192.168.202.105, we need to add the following rules to the iptables configuration of host 192.168.202.103:
To test if my NAT-rule is working, I will repeat the test with telnet:
To permanently save the rules, execute iptables-save
CentOS/RHEL:
Debian:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
jensd
@deb
:
~
$
sudo
iptables
-save
|
sudo
tee
/etc
/iptables
.up
.rules
#
Generated
by
iptables
-save
v1
.4
.14
on
Thu
Nov
6
12
:07
:27
2014
*nat
:PREROUTING
ACCEPT
[1
:78
]
:INPUT
ACCEPT
[1
:78
]
:OUTPUT
ACCEPT
[3
:159
]
:POSTROUTING
ACCEPT
[3
:159
]
-A
PREROUTING
-p
tcp
-m
tcp
--dport
9999
-j
DNAT
--to
-destination
192
.168
.202
.103
:80
-A
POSTROUTING
-d
192
.168
.202
.103
/32
-p
tcp
-m
tcp
--dport
80
-j
SNAT
--to
-source
192
.168
.202
.105
COMMIT
#
Completed
on
Thu
Nov
6
12
:07
:27
2014
#
Generated
by
iptables
-save
v1
.4
.14
on
Thu
Nov
6
12
:07
:27
2014
*filter
:INPUT
ACCEPT
[4424
:3400545
]
:FORWARD
ACCEPT
[14
:5970
]
:OUTPUT
ACCEPT
[3185
:304340
]
COMMIT
#
Completed
on
Thu
Nov
6
12
:07
:27
2014
|