67

I have a service running on 127.0.0.1 with port 2222. I need to forward all requests to 192.168.2.2:2222 (outside IP) only from subnet 192.168.1.0/24 to 127.0.0.1:2222.

I'm trying to use this, but it's not working.

$ iptables -t nat -I PREROUTING -p tcp -d 192.168.1.0/24 --dport 2222 -j DNAT --to-destination 127.0.0.1:2222

How can I get this to work?

UPD: Edit address scheme.

5
  • We need some clarification. Where is the traffic coming from? Where is the traffic originally going to? Where should the traffic be going to? As I read it, you want traffic from 192.168.1.0/24 to 127.0.0.1:2222 to be redirected to 12.23.34.45:2222. But Warren's answer assumes you want traffic from 192.168.1.0/24 to 12.23.34.45:2222 to be redirected to 127.0.0.1:222
    – phemmer
    Commented Jan 29, 2014 at 13:37
  • 2
    Traffic comes from 192.168.1.0/24 subnet to 192.168.2.2:2222 and should be translated to service on 127.0.0.1:2222. I'm corrected address scheme.
    – SimWhite
    Commented Jan 29, 2014 at 14:27
  • 1
    You want a rule that allows traffic to port 2222 on the loopback interface from subnet 192.168.1.0/24? That isn't just a single rule type of setup. See here: debuntu.org/…
    – slm
    Commented Jan 29, 2014 at 14:35
  • Yes. As I understand I need to add masq rule? IP forwarding is already enabled of course.
    – SimWhite
    Commented Jan 29, 2014 at 14:47
  • Why not run it on a "real" IP, and filter out traffic comming from unwanted sources? That is what firewalls are for, essentially...
    – vonbrand
    Commented Feb 3, 2014 at 1:04

3 Answers 3

97

The iptables rule you are using will work, but there is one additional change you need to make:

sysctl -w net.ipv4.conf.eth0.route_localnet=1

(replacing eth0 with the nic 192.168.2.2 resides on)

By default this value is 0, which instructs the kernel to not route external traffic destined to 127.0.0.0/8. This is just for security as such traffic is not normal.

6
  • 19
    This info is surprisingly hard to find.
    – Wren T.
    Commented May 16, 2014 at 4:06
  • Yes, very valuable hard-to-find information! Thank you! But I don't have route_localnet. Have there been other names for it? (in linux 2.6.30) ls /proc/sys/net/ipv4/conf/lan/: accept_redirects arp_accept arp_filter arp_notify disable_policy force_igmp_version log_martians medium_id proxy_arp secure_redirects shared_media accept_source_route arp_announce arp_ignore bootp_relay disable_xfrm forwarding mc_forwarding promote_secondaries rp_filter send_redirects tag Commented Mar 31, 2015 at 22:39
  • I see, the patch for route_localnet is more recent (June 7, 2012) than my kernel ( 2.6.30-std-def-alt15 #1 SMP Mon Dec 14 08:45:48 UTC 2009). Ok, I'll simply achieve the wanted port-forwarding (from outside to inside) with a forwarding process like netcat (nc), xinetd, or the port-forwarding options of ssh (the latter is ineffective and stupid, of course, but I mention it, because, well, this possibility is there). Commented Mar 31, 2015 at 22:50
  • 4
    My 2 cents: you may enable this parameter for all interfaces with sysctl -w net.ipv4.conf.all.route_localnet=1
    – Dmitriusan
    Commented Nov 10, 2017 at 12:39
  • Like others, this info was hard to come by. Thanks, if I'd found this earlier, would have saved me a tonne of effort. Commented Feb 12, 2019 at 10:40
8

You can redirect to localhost but not to loopback (127.0.0.0/8). Loopback is a loophole. You have to redirect to one of your real interfaces. Try using REDIRECT.

iptables -t nat -A PREROUTING ..... -j REDIRECT --to-port 222

4
  • This is probably the best answer without the sysctl voodo... Commented Jun 3, 2016 at 2:30
  • 2
    Still doesn't help if port 222 is only being listened on localhost (the rule won't change destination address)
    – sanmai
    Commented Dec 20, 2016 at 4:35
  • 4
    In that case, use -j DNAT --to-destination w.x.y.z:222
    – dresende
    Commented Dec 21, 2016 at 0:58
  • 4
    Thanks @dresende, -j DNAT --to-destination 127.0.0.1:<port> works great!<br/> This is the full command I used to forward connection to a MariaDB server listening on port 1186: iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 1186 -j DNAT --to-destination 127.0.0.1:1186
    – maximus
    Commented Jul 13, 2020 at 9:14
5

What if the correct answer with route_localnet doesn't work?..

If your kernel doesn't include the patch for route_localnet, then... upgrade the kernel!

Or there are other ways to forward the traffic coming to one interface to another port on another interface (in particular, to localhost) by running a process that would listen on the external interface and forward the traffic.

netcat (nc), xinetd, and ssh (and perhaps more) are all examples of programs able to do this (although choosing ssh would be strange and ineffective).

I've written a configuration for xinetd for this. Now this service is automatically brought up:

# cat /etc/xinetd.d/z-from-outside 
# default: off
# description: Forward connections to the z port.
service z-from-outside
{
    disable         = no
    socket_type     = stream
    type        = UNLISTED
    wait            = no
    user            = nobody
    bind        = vaio.ob
    port        = 7070
    redirect    = localhost 7070
}
# 

(vaio.ob is the name of this host on the external network interface.)

After a service xinetd reload, let's check that it is listening:

# lsof -i -P | fgrep 7070
xinetd    556      root    6u  IPv4 1797906      0t0  TCP vaio.ob:7070 (LISTEN)
sshd    27438 tun_zzoom    4u  IPv4 1059100      0t0  TCP localhost.localdomain:7070 (LISTEN)
# 

And indeed, connections do go through!

You must log in to answer this question.

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