Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Source NAT addresses are not handled properly #14

Open
86dd opened this issue Dec 17, 2024 · 1 comment
Open

Source NAT addresses are not handled properly #14

86dd opened this issue Dec 17, 2024 · 1 comment

Comments

@86dd
Copy link

86dd commented Dec 17, 2024

As seen in
kaboomserver/server#147
it is problematic that the ranges used for source NAT are not handled properly.
My proposals for solving this issue:

  • Making the NAT rules permanent until a full system reboot (which would make minecraft reset it's states), but this might cause it to be flagged as port-scanning by Hetzner anyway, now just towards a public IP...
  • Checking the conntrack on certain chains (such as outbound)
  • Completely blocking out the ranges used for source NAT when going outbound without NAT rules

I would also propose moving to nftables, as it is more modern and rulesets tend to look more clean. Most xtables binaries are linked to nftables translators nowadays anyway.

@86dd
Copy link
Author

86dd commented Dec 18, 2024

I have been working on rewriting the ruleset into nftables. Here is a demo of it now properly filtering the NAT ranges.
(Hint: I am using fd00::/8 instead of 2001:db8::/32 as it is meant for documentation purposes. 2001:db8::/32 also falls under 2000::/3 which is probably the range hetzner monitors for outgoing attacks, I don't think they care too much about traffic from reserved ranges, or else they would have complained about traffic to 192.168.0.0/16 already)
Listening for network traffic to reserved ranges that should not be publicly routed on the gateway:

root@dedi2 ~ # tcpdump -i incus0 host fd00::1337 or host 192.168.13.37
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on incus0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
14:26:48.278347 IP6 2a01:4f8:a0:3800::5359 > fd00::1337: ICMP6, echo request, id 5007, seq 1, length 64
14:26:49.288453 IP6 2a01:4f8:a0:3800::5359 > fd00::1337: ICMP6, echo request, id 5007, seq 2, length 64
14:26:50.316452 IP6 2a01:4f8:a0:3800::5359 > fd00::1337: ICMP6, echo request, id 5007, seq 3, length 64
14:26:51.336452 IP6 2a01:4f8:a0:3800::5359 > fd00::1337: ICMP6, echo request, id 5007, seq 4, length 64
14:26:56.273967 IP 10.2.3.56 > 192.168.13.37: ICMP echo request, id 5008, seq 1, length 64
14:26:57.292415 IP 10.2.3.56 > 192.168.13.37: ICMP echo request, id 5008, seq 2, length 64
14:26:58.312442 IP 10.2.3.56 > 192.168.13.37: ICMP echo request, id 5008, seq 3, length 64
14:26:59.336450 IP 10.2.3.56 > 192.168.13.37: ICMP echo request, id 5008, seq 4, length 64

This is when I ping them without the firewall in place. Now if we apply something like

#!/usr/sbin/nft -f

flush ruleset

# IPv6+IPv4 ranges to be for masquerading incoming connections
# The default values are ranges for use in private networks.
define SNATV6 = fd00::/112
define SNATV4 = 192.168.0.0/16

# Ports to which connections should be masqueraded
# TCPPORT is for Minecraft Java Edition, as it uses TCP.
# UDPPORT is for Minecraft Bedrock Edition, as it uses UDP.
define TCPPORT = 21337
define UDPPORT = 21337

table inet filter {
        chain output {
                type filter hook output priority filter;
                # Reject connections to the NAT ranges
                # Minecraft might consider a connection to be still open, even though
                # it has already expired in the NAT tables.
                # By rejecting it, it is ensured that no bogus traffic leaves the host.
                ip daddr $SNATV4 counter reject with icmpx type host-unreachable
                ip6 daddr $SNATV6 counter reject with icmpx type host-unreachable
        }
}

table inet nat {
        chain input-srcnat {
                type nat hook input priority 100;
                # Masquerade the IP addresses of incoming connections
                tcp dport $TCPPORT counter snat ip6 to $SNATV6
                tcp dport $TCPPORT counter snat ip to $SNATV4
                udp dport $UDPPORT counter snat ip6 to $SNATV6
                udp dport $UDPPORT counter snat ip to $SNATV4
        }
}

No more traffic will leave the host. If we send a packet to the reserved ranges, we get an ICMP error message back:

bomb@kaboom-test:~# ping -c 1 fd00::1337; ping -c 1 192.168.13.37
PING fd00::1337(fd00::1337) 56 data bytes
From 2a01:4f8:a0:3800::5359 icmp_seq=1 Destination unreachable: Address unreachable
ping: sendmsg: Operation not permitted

--- fd00::1337 ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms

PING 192.168.13.37 (192.168.13.37) 56(84) bytes of data.
From 10.2.3.56 icmp_seq=1 Destination Host Unreachable
ping: sendmsg: Operation not permitted

--- 192.168.13.37 ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

1 participant