Fail2ban / ha : still allowing banned IPs

Oh, I missed the whole VPN thing! Goodness.

So, your local VPN application is going to decrypt all of the VPN packets, including their original headers. This includes the source ip address from the WAN (a.b.c.d). This is the ip address home assistant is going to use in the logs. Sadly, it’s not the ip address comming into eth0 as that’s the VPN address.

But, because your VPN client is running HA, there is no way for iptables to ever see a.b.c.d. Only the applications living inside the VPN client are seeing the real packet. Thus, Home Assistant is logging a.b.c.d, and f2b is adding a.b.c.d to the iptables, but the IP stack never once got a single packet from a.b.c.d!

IPTables runs at the kernel layer. Once the packet is passed to your VPN, the packet now lives in the application layer. The only way to get this to work with iptables is to have the VPN on a different interface, then send the packets over yet another interface to Home Assistant.

EDIT: oh, I see your edit.

Hey, I didn’t even realize they had a section for ip banning built it! Good to know…

Sorry for missing the whole part about the VPN. Glad it works now!

1 Like

Yeah, thanks Jim. I wish I’d seen that banning stuff earlier.
Have to admit, I dont know what or why packets hit the application layer when on a VPN ? Are they not on the application layer when an application is interrogating? I dont really understand how all that works anyway.

BTW
I cloned the git repo for HA and came across files:

homeassistant/components/http/ban.py
homeassistant/components/http/real_ip.py

and code in real_ip.py:

root@pi:~/core# cat homeassistant/components/http/real_ip.py
"""Middleware to fetch real IP."""
from ipaddress import ip_address

from aiohttp.hdrs import X_FORWARDED_FOR
from aiohttp.web import middleware

from homeassistant.core import callback

from .const import KEY_REAL_IP

# mypy: allow-untyped-defs


@callback
def setup_real_ip(app, use_x_forwarded_for, trusted_proxies):
    """Create IP Ban middleware for the app."""

    @middleware
    async def real_ip_middleware(request, handler):
        """Real IP middleware."""
        connected_ip = ip_address(request.transport.get_extra_info("peername")[0])
        request[KEY_REAL_IP] = connected_ip

        # Only use the XFF header if enabled, present, and from a trusted proxy
        try:
            if (
                use_x_forwarded_for
                and X_FORWARDED_FOR in request.headers
                and any(
                    connected_ip in trusted_proxy for trusted_proxy in trusted_proxies
                )
            ):
                request[KEY_REAL_IP] = ip_address(
                    request.headers.get(X_FORWARDED_FOR).split(", ")[-1]
                )
        except ValueError:
            pass

        return await handler(request)

    app.middlewares.append(real_ip_middleware)

so HA is using header info in the packets and, the X-FORWARDED-FOR header in proxy forwarding cases such as mine. So that’s how HA is acquiring the correct [WAN] IP to block. I totally don’t understand HTTP stuff but is it possible to access X-FORWARDED-FOR headers in iptables? Not that it matters now, just interested because I dont understand and would like to.

Also

re your comment:

IPTables runs at the kernel layer. Once the packet is passed to your VPN, the packet now lives in the application layer. The only way to get this to work with iptables is to have the VPN on a different interface, then send the packets over yet another interface to Home Assistant

But iptables is running on the same box as HA. And there are two interfaces on this box, eth0 and wg0 [latter is the VPN]. So…
Q1. why can’t iptables see both?
Are you saying I would need 3 interfaces and if so then iptables is still running in the kernel level so
Q2. How come adding another i/f would make it work?
Finally, you mention once traffic his the VPN (I presume you mean wg0 interface) then it is in the app layer, but iptables can see wg and filter on it so
Q3. Why do you say VPN is at the application layer when iptables runs in kernel layer and can see/filter wg0 traffic?

Confused.com !

It’s possible, but again, iptables will never see that ip address in this case because of the VPN.

Packets hit the application layer when the destination and port of a packet match something that is listening for them. Looking at the 1st diagram I pasted, you can see the path to the application layer. In this case, it goes

link layer → is the packet to/from a directly connected neighbor. Usually look at the MAC address at this layer.

Network layer then looks at the src/dst ip addresses to determine where to send it (layer 3 routing). It just needs to figure out who the next hop is (it could be this very device).

Protocol layer is where the ports are checked. The packet was destined to this device, so which port? If there is something listening on that port, send it to them. Else, drop it (replies with PORT UNREACHABLE by default)

Finally, the application layer. The packet is no longer in the kernel. The application has a complete copy of the packet. In this case, the VPN application has a (probably encrypted) packet. It will remove the VPN headers from the packet (and decrypt if needed).

NOW, the VPN has to decide wtf to do with this new, unencrypted packet. You could just push it back onto the network stack and let iptables/kernel figure it out. And a lot of VPNs will do just that. But in your case, the VPN is also running the other application, so it doesn’t have to do that. It just passes it right on over.

The packets hit the VPN application because they are destined to it. When you use a VPN, you take your normal packet (from a.b.c.d to homeassistant.com), then wrap it in another layer. That packet fully exists, but you put on a new header that says (no no, send this packet to w.x.y.z instead. He’ll know what to do with it). And he does.

But iptables is running on the same box as HA. And there are two interfaces on this box, eth0 and wg0 [latter is the VPN]. So why can’t iptables see both? Are you saying I would need 3 interfaces and if so then why can iptables then “see” traffic when it’s running at the kernel level – you mentioned the traffic lives in the app layer. Confused.com !

Again, iptables exists only in the kernel. Once the kernel handed the VPN the packet, it would only ever see it again IF the vpn sent it out an external interface. If the packet went from eth0 → wg0 → eth1, it would totally see the packet between wg0 and eth1. But, because the VPN is also running the HA app, it won’t send it anywhere! Thus, the kernel will never see the packet after the VPN gets a hold of it.

Ah, so the application layer contains …

  • My VPN server in the cloud
  • My VPN client in my LAN
  • HomeAssistant
    ?

And,thats because my VPN server is also running NGINX which is reverse proxying incoming WAN traffic onto eth0 and bridging this over to wg0 then sending that down the cloud to my LAN VPN client’s wg0 interface. ?

So on my VPN client 10.19.49.2, if I were to route/bridge (whatever its called) traffic destined to port 8123 on interface wg0, over to its eth0 interface and mangle the IP to 192.168.1.127 which is the same client LAN IP, then:
Q1. Would that reach HA
Q2 . Would iptables now be able to “see” the true IPs?
Q3 Is this what they call DNAT ?
Q4. Would that not be “safe” as just leaving traffic on the VPN?

Also, just read up on VPN protocols. SoftEther operates at the network layer so iptables would have access to the packets then , unlike wireguard which Im using now?

You know, I follow these guides but never understand fully how they work. This is interesting and you clearly know a lot more than me

oh lightbulb has just gone on…there’s lots of overhead in the application layer if messing around with each packet, loads, so this is why VPNs slow your connection down. Duhhh easy once you understand - or rather its explained by you :slight_smile: