Comment by phire

18 days ago

The firewall on your typical IPv4 router does basically nothing. It just drops all packets that aren’t a response to an active NAT session.

If the firewall somehow didn’t exist (not really possible, because NAT and the firewall are implemented by the same code) incoming packets wouldn’t be dropped, but they wouldn’t make it through to any of the NATed machines. From the prospective any machine behind the router, nothing changes, they get the same level of protection they always got.

So for those machines, the NAT is inherently acting as a firewall.

The only difference is the incoming packets would reach the router itself (which really shouldn’t have any ports open on the external IP) reach a closed port, and the kernel responds with a NAK. Sure, dropping is slightly more secure, but bouncing off a closed port really isn’t that problematic.

NAT gateways that utilize connection tracking are effectively stateful firewalls. Whether a separate set of ‘firewall’ rules does much good because most SNAT implementations by necessity duplicate this functionality is a bit ignorant, IMO.

Meanwhile, an IPv6 network behind your average Linux-based home router is 2-3 nftables rules to lock down in a similar fashion.

  • It's also trivial to roll your own version of dropbox. With IPv6 it's possible to fail to configure those nftables rules. The firewall could be turned off.

    In theory you could turn off IPv4 NAT as well but in practice most ISPs will only give you a single address. That makes it functionally impossible to misconfigure. I inadvertently plugged the WAN cable directly into my LAN one time and my ISP's DHCP server promptly banned my ONT entirely.

    • > In theory you could turn off IPv4 NAT as well but in practice most ISPs will only give you a single address

      So, I randomly discovered the other day that my ISP has given me a full /28.

      But I have no idea how to actually configure my router to forward those extra IP addresses inside my network. In practice, modern routers just aren't expecting to handle this, there is no easy "turn of NAT" button.

      It's possible (at least on my EdgeRouterX), but I have to configure all the routing manually, and there doesn't seem to be much documentation.

      6 replies →

    • > With IPv6 it's possible to fail to configure those nftables rules. The firewall could be turned off.

      So what? It's not like you get SNAT without a couple netfilter rules either.

      This argument doesn't pass muster, sorry. Consumer and SOHO gear should come with a safe configuration out of the box, it's not rocket science.

      3 replies →

  • The difference is that with IPv4 you know that you have that security because there is no other way for the system to work while with the IPv6 router you need to be a network expert to make that conclusion.

    • Except, you don't.

      Assume eth0 is WAN, eth1 is LAN

      Look at this nftables setup for a standard IPv4 masquerade setup

          table ip global {
              chain inbound-wan {
                  # Add rules here if external devices need to access services on the router
              }
              chain inbound-lan {
                  # Add rules here to allow local devices to access DNS, DHCP, etc, that are running on the router
              }
              chain input {
                  type filter hook input priority 0; policy drop
                  ct state vmap { established : accept, related : accept, invalid : drop };
                  iifname vmap { lo : accept, eth0 : jump inbound-wan, eth1 : jump inbound-lan };
              }
              chain forward {
                  type filter hook forward priority 0; policy drop;
                  iifname eth1 accept;
                  ct state vmap { established : accept, related : accept, invalid : drop };
              }
              chain inbound-nat {
                  type nat hook prerouting priority -100;
                  # DNAT port 80 and 443 to our internal web server
                  iifname eth0 tcp dport { 80, 443 } dnat to 192.168.100.10;
              }
              chain outbound-nat {
                  type nat hook postrouting priority 100;
                  ip saddr 192.168.0.0/16 oiname eth0 masquerade;
              }
          }
      

      Note, we have explicit rules in the forward chain that only forward packets that either:

      * Were sent to the LAN-side interface, meaning traffic from within our network that wants to go somewhere else

      * Are part of an established packet flow that is tracked, that means return packets from the internet in this simple setup

      Everything else is dropped. Without this rule, if I was on the same physical network segment as the WAN interface of your router, I could simply send packets to it destined to hosts on your internal network, and they would happily be forwarded on to it!

      NAT itself is not providing the security here. Yes, the attack surface here is limited, because I need to be able to address this box at layer 2 (just ignore ARP, send the TCP packet with the internal dst_ip address I want addressed to the ethernet MAC of your router), but if I compromised routers from other customers on your ISP I could start fishing around quite easily.

      Now, what's it look like to secure IPv6, as well?

          # The vast majority of this is the same. We're using the inet table type here
          # so there's only one set of rules for both IPv4 and IPv6.
          table inet global {
              chain inbound-wan {
                  # Add rules here if external devices need to access services on the router
              }
              chain inbound-lan {
                  # Add rules here to allow local devices to access DNS, DHCP, etc, that are running on the router
              }
              chain inbound-nat {
                  type nat hook prerouting priority -100;
                  # DNAT port 80 and 443 to our internal web server
                  # Note, we now only apply this rule to IPv4 traffic
                  meta nfproto ipv4 iifname eth0 tcp dport { 80, 443 } dnat to 192.168.100.10;
              }
              chain outbound-nat {
                  type nat hook postrouting priority 100;
                  # Note, we now only apply this rule to IPv4 traffic
                  meta nfproto ipv4 ip saddr 192.168.0.0/16 oiname eth0 masquerade;
              }
              chain input {
                  type filter hook input priority 0; policy drop
                  ct state vmap { established : accept, related : accept, invalid : drop };
                  # A new rule here to allow ICMPv6 traffic, because it's not required for IPv6 to function correctly
                  icmpv6 type { echo-request, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept;
                  iifname vmap { lo : accept, eth0 : jump inbound-wan, eth1 : jump inbound-lan };
              }
              chain forward {
                  type filter hook forward priority 0; policy drop;
                  iifname eth1 accept;
                  # A new rule here to allow ICMPv6 traffic, because it's not required for IPv6 to function correctly
                  icmpv6 type { echo-request, echo-reply, destination-unreachable, packet-too-big, time-exceeded } accept;
                  # We will allow access to our internal web server via IP6 even if the traffic is coming from an
                  # external interface
                  ip6 daddr 2602:dead:beef::1 tcp dport { 80, 443 } accept;
                  ct state vmap { established : accept, related : accept, invalid : drop };
              }
          }
      

      Note, there's only three new rules added here, the other changes are just so we can use a dual-stack table so there's no duplication of the shared rules in separate ip and ip6 tables.

      * 1 & 2: We allow ICMPv6 traffic in the forward and input chains. This is technically more permissive than needs to be, we could block echo-request traffic coming from outside our network if desired. destination-unreachable, packet-too-big, and time-exceeded are mandatory for IPv6 to work correctly.

      * 3: Since we don't need NAT, we just add a rule to the forward chain that allows access to our web server (2602:dead:beef::1) on port 80 and 443 regardless of what interface the traffic came in on.

      None of this requires being a "network expert", the only functional difference in an actually secure IPv4 SNAT configuration and a secure IPv6 firewall is...not needing a masquerade rule to handle SNAT, and you add traffic you want to let in to forwarding rules instead of DNAT rules.

      Consumers would never need to see the guts like this. This is basic shit that modern consumer routers should do for you, so all you need to think about is what you want to expose (if anything) to the public internet.