One client on your OpenVPN server has to lose LAN access while every other tunnel stays up. Search for that, and the top answer usually says the daemon cannot do it, which is only half true: OpenVPN has no per-client firewall, but the host that terminates the tunnel already filters packets. The two decisions that matter are the identity you block and the position of the rule. Get those right and the change becomes one line you can test and remove.

Pin the client before you write the rule

OpenVPN leases tunnel addresses from a pool, so 10.8.0.6 is a seat rather than a person. When the session ends the lease returns and can be handed to the next connection, which means a rule written against that address follows the seat, not the user. So decide first what you are actually blocking: an address for a short experiment, or a certificate for someone you want to keep out.

To bind the address to the certificate, create a file in the directory named by client-config-dir and give the file exactly the certificate's common name. Put one directive in it, ifconfig-push 10.8.0.6 255.255.255.0, and that client keeps the same tunnel address across reconnects. Two settings have to exist for this to take effect: client-config-dir must be declared in the server configuration, and the pushed address has to sit in a subnet the server can route. Miss either one and the file is ignored without an error, which makes the next firewall test misleading.

A temporary block can use a pool address, as long as the ticket records which session held it at the time.

Order decides whether the drop runs

On a Linux gateway that forwards between the tunnel and the LAN, packets cross the FORWARD chain. Read the command below as a sentence: insert at the head of FORWARD, match traffic entering from tun0, from that single host, addressed to the LAN subnet, and drop it.

iptables -I FORWARD -i tun0 -s 10.8.0.6/32 -d 192.168.1.0/24 -j DROP

The -I is what makes the rule run. Appended with -A, it lands below any broad accept for the tunnel subnet and never sees a packet. Verify the position with iptables -vnL FORWARD --line-numbers, and read the counters as well: a drop at the top that counts nothing means the traffic is arriving by another path.

The gateway's own LAN address is a different path. Packets sent to the box itself go to INPUT, not FORWARD, so a client can lose a LAN host and still open the router's admin page. Add the matching INPUT rule when that matters.

What the filter cannot see

Filtering happens when a packet is evaluated, so an established TCP session can continue until it closes or is reset. If the block must bite immediately, clear the tracked flows for that source with conntrack -D -s 10.8.0.6 after the rule goes in. If a few seconds of overlap are acceptable, record that choice instead of leaving it implicit. Either way, the next person needs to know whether the rule stops live traffic or only new connections.

Peer traffic never touches the host firewall. With client-to-client enabled, OpenVPN forwards those packets inside the daemon, so neither FORWARD nor INPUT sees them. The only fixes are turning client-to-client off or accepting that peers can reach each other; an iptables rule will not see that traffic.

IPv6, firmware and reboot survival

An IPv4 rule says nothing about IPv6. If the tunnel and the LAN carry both families, the equivalent rule has to exist in ip6tables, or in the nftables ruleset that owns policy on that host. Router firmware often hides netfilter behind its own abstraction, so syntax and table names copied from a forum may not apply.

On OpenWrt, the documented path is a firewall configuration entry rather than a hand-written iptables line, and a hand-written line can disappear when the firewall reloads. Other distributions restore rules through netfilter-persistent, a boot unit or a vendor store, and those mechanisms are not interchangeable. Prove whichever one you chose with a reboot, because a reload exercises a different path.

Verify by path, then roll back cleanly

Test each path separately, because one successful check hides the others. A blocked client should still reach the internet through the tunnel while failing against a LAN host, a second client should reach that same host, and the gateway address and the peer path each need their own observation. Write the results next to the rule so the next change has a baseline. The table below is the set worth keeping in the ticket.

PathExpected with the ruleWhen it fails
Blocked client to a LAN hostNo answerRule sits below an accept, or the source does not match
Blocked client to the internetWorks through tun0Rule is too broad, with no destination match
Second client to the same LAN hostWorksRule matched more than the intended host
Blocked client to the gateway LAN addressBlocked only with the matching INPUT ruleINPUT rule missing
Blocked client to a peer tunnel addressStill worksclient-to-client is enabled and outside firewall scope

Rollback is a delete by specification, not a flush: iptables -D FORWARD -i tun0 -s 10.8.0.6/32 -d 192.168.1.0/24 -j DROP removes exactly that entry and leaves the rest of the chain intact. Remove the same line from whichever file restores the rules at boot, reload it, and confirm the client reaches the LAN host again. Flushing FORWARD would also undo rules you did not write, which turns a rollback into a second incident.

Before you close the ticket, confirm three things: the pinned address matches the certificate, the rule sits above the accepts with a non-zero counter, and the persistence file contains the same rule you tested. If any of those is missing, the block is a shell-session illusion.

Pennadoù liammet