0

Some background:

There is a machine, lets call it "Machine A", (running Xubuntu 18.04) that I am hosting Minecraft on behind a firewall, that I'll call "the firewall" from here on out, (running Ubuntu Server 16.04).

Previously the Minecraft server was running on my file server, call it "Machine B", and everything was working fine except Java kept segfaulting hence why I decided to move to Machine A.

When I was using Machine B, I used the following rules for iptables on the firewall to forward all connections to the firewall on port 25565 to the Machine B on port 25565:

iptables -t nat -A PREROUTING -p tcp -d 128.xxx.xxx.xxx --destination-port 25565 -j DNAT --to 192.xxx.xxx.xxx:25565
iptables -A FORWARD -p tcp -i 'enp2s0' -o 'enp4s0' -d 192.xxx.xxx.xxx --destination-port 25565 -m state --state NEW -j ACCEPT

And this worked fine at the time with no issues. But now that I have moved to Machine A and modified the rules above accordingly, the forwarding still happens only for Machine B and not Machine A.

Here is an iptables script I use to set all of the rules on the firewall (omitted irrelevant entries):

#!/bin/bash

IPT=/sbin/iptables

INET_IFACE='enp4s0'
INET_SUB=128.xxx.xxx.xxx/28

LOCAL_IFACE='enp2s0'
LOCAL_SUB=192.xxx.xxx.xxx/24

# Flush the tables
$IPT -F INPUT
$IPT -F OUTPUT
$IPT -F FORWARD

# Define default policy to DROP packets
$IPT -P INPUT   DROP
$IPT -P OUTPUT  ACCEPT
$IPT -P FORWARD ACCEPT

$IPT -t nat -P PREROUTING ACCEPT
$IPT -t nat -P POSTROUTING ACCEPT
$IPT -t nat -P OUTPUT ACCEPT

$IPT -A INPUT -i $INET_IFACE -m state --state INVALID -j DROP

$IPT -A INPUT -s $LOCAL_SUB -i $LOCAL_IFACE -j ACCEPT

$IPT -A FORWARD -o 'enp4s0' -i 'enp2s0' -s 192.xxx.xxx.xxx/24 -m conntrack --ctstate NEW -j ACCEPT
$IPT -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

$IPT -A INPUT -m state -p tcp --dport 1024:65535 --state ESTABLISHED,RELATED -s 0/0 -j ACCEPT

$IPT -t nat -A PREROUTING -p tcp -d 128.xxx.xxx.xxx --destination-port 25565 -j DNAT --to 192.xxx.xxx.xxx:25565
$IPT -A FORWARD -p tcp -i 'enp2s0' -o 'enp4s0' -d 192.xxx.xxx.xxx --destination-port 25565 -m state --state NEW -j ACCEPT

Checking iptables -L and iptables -S shows that the forwarding rule exists for Machine A yet if I try to access the Minecraft server from outside the network, it won't connect unless the server is running Machine B leading me to believe that somewhere the updated forwarding rule is not taking affect. Outputs provided below:

user@firewall:~# iptables -L
Chain INPUT (policy DROP)
target     prot opt source               destination
ACCEPT     icmp --  anywhere             anywhere             icmp echo-reply
ACCEPT     icmp --  anywhere             anywhere             icmp echo-request
ACCEPT     icmp --  anywhere             anywhere             icmp time-exceeded
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:ssh
LOG        all  --  anywhere             anywhere             limit: avg 5/min burst 5 LOG level debug prefix "iptables denied: "
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:http
ACCEPT     all  --  anywhere             anywhere
DROP       all  --  anywhere             anywhere             state INVALID
ACCEPT     udp  --  anywhere             anywhere             udp spt:domain
ACCEPT     all  --  192.xxx.xxx.0/24     anywhere
ACCEPT     udp  --  anywhere             anywhere             udp dpts:bootps:tftp
ACCEPT     tcp  --  anywhere             anywhere             state RELATED,ESTABLISHED tcp dpts:1024:65535

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
ACCEPT     all  --  192.xxx.xxx.0/24     anywhere             ctstate NEW
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
ACCEPT     tcp  --  anywhere             192.xxx.xxx.xxx      tcp dpt:25565 state NEW
ACCEPT     tcp  --  anywhere             192.xxx.xxx.xxx      tcp dpt:http state NEW

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     icmp --  anywhere             anywhere             icmp echo-reply
ACCEPT     icmp --  anywhere             anywhere             icmp echo-request
ACCEPT     icmp --  anywhere             anywhere             icmp time-exceeded
ACCEPT     tcp  --  anywhere             anywhere             tcp spt:ssh
ACCEPT     tcp  --  anywhere             anywhere             tcp spt:http
ACCEPT     all  --  anywhere             anywhere
user@firewall:~# iptables -S
-P INPUT DROP
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 0 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 11 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -i enp4s0 -m state --state INVALID -j DROP
-A INPUT -p udp -m udp --sport 53 -j ACCEPT
-A INPUT -s 192.xxx.xxx.0/24 -i enp2s0 -j ACCEPT
-A INPUT -p udp -m udp --dport 67:69 -j ACCEPT
-A INPUT -p tcp -m state --state RELATED,ESTABLISHED -m tcp --dport 1024:65535 -j ACCEPT
-A FORWARD -s 192.xxx.xxx.0/24 -i enp2s0 -o enp4s0 -m conntrack --ctstate NEW -j ACCEPT
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -d 192.xxx.xxx.xxx/32 -i enp2s0 -o enp4s0 -p tcp -m tcp --dport 25565 -m state --state NEW -j ACCEPT
-A FORWARD -d 192.xxx.xxx.xxx/32 -i enp2s0 -o enp4s0 -p tcp -m tcp --dport 80 -m state --state NEW -j ACCEPT
-A OUTPUT -p icmp -m icmp --icmp-type 0 -j ACCEPT
-A OUTPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
-A OUTPUT -p icmp -m icmp --icmp-type 11 -j ACCEPT
-A OUTPUT -p tcp -m tcp --sport 22 -j ACCEPT
-A OUTPUT -p tcp -m tcp --sport 80 -j ACCEPT
-A OUTPUT -o lo -j ACCEPT

You might notice that I also forwarded port 8080 from the firewall to port 80 on Machine A. This was just a sanity check to make sure port forwarding worked for that machine and it does.

My question is exactly: What could cause for the forwarding rules for 25565 to still work for Machine B when it should work for Machine A?

Edit - Added output of iptables -t nat -S:

user@firewall:~# iptables -t nat -S
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-A PREROUTING -i enp4s0 -p tcp -m tcp --dport 25565 -j DNAT --to-destination 192.xxx.xxx.xxx:25565 # (Machine B)
-A PREROUTING -i enp4s0 -p tcp -m tcp --dport 25565 -j DNAT --to-destination 192.xxx.xxx.xxx # (Machine B)
-A PREROUTING -d 128.xxx.xxx.xxx/32 -p tcp -m tcp --dport 25565 -j DNAT --to-destination 192.xxx.xxx.xxx:25565 # (Machine B - Shows up 14 more times) 
-A PREROUTING -d 128.xxx.xxx.xxx/32 -p tcp -m tcp --dport 25565 -j DNAT --to-destination 192.xxx.xxx.xxx:25565 # (Machine A - Shows up 2 more times)
-A PREROUTING -d 128.xxx.xxx.xxx/32 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 192.xxx.xxx.xxx:80 # (Machine A)
-A POSTROUTING -j MASQUERADE # (Shows up 35 more times)
isema
  • 11
  • 4
  • iptables -t nat -S output would be also helpful. All forward and output rules are unnecessary as FORWARD and OUTPUT policies are accept. The interfaces in the last rule in the script seem to be swapped. – Tomek Mar 28 '20 at 16:38
  • @Tomek just added the output of iptables -t nat -S. I didn't think the interfaces in the last rule were swapped since it worked previously. As seen in the script enp2s0 is local traffic behind the firewall and enp4s0 is external traffic. – isema Mar 28 '20 at 16:59
  • They ARE swapped. But as I mentioned the rule is superfluous anyway - it worked because your DNAT-ed packets where hitting FORWARD policy which, as i mentioned, is ALLOW. Please have another look at your rules, they ARE suboptimal and possibly - opening more than you expect. I personaly prefer iptables-save output for analysis - as it shows ALL tables and ALL rules in one place. – Tomek Mar 28 '20 at 17:48

1 Answers1

1

Got it. The script I included does not flush out the nat table whenever it runs which was causing my old rules to persist causing the issue I was running into. The following article helped me solve this issue: best way to clear all iptables rules (best way to clear all iptables rules on Server Fault). I added iptables -t nat -F to the top of my script and reran the script and that fixed all the issues. After @Tomek asked me to provide the output iptables -t nat -S it got me questioning if I had to flush the nat table as well. Thanks again!

isema
  • 11
  • 4