I would like to block all scanners
Then disconnect it from the internet. You cannot have it accessible on any port and still hide it from a scanner. The only way to hide it from a scanner and have it online would be to just set:
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP
And nothing else. In which case there is no point in having it online, of course. Which brings me to a point about about cascading from
ACCEPT
As a default chain policy overruled by a final catch-all:
DROP
Having a default policy and a catch-rule at the end of the chain seems pointless, but harmlessly so. This ends up as a practice because all chains have a policy, but only the built-in ones can be set; user defined ones are always RETURN, because user defined chains are only useful if at some point they can be traced back to a built-in; I believe those will default to DROP, but you can change them, and for other chains you can set a final catch all. So doing both for the same chain is sort of pointless but since there can be weird gotchas with iptables, not a bad idea. In that case, the policy should be REJECT or DROP, because it is going to apply to packets that have accidentally slipped through rules -- and since rules can be changed dynamically and nobody is perfect, being paranoid there is a good idea.
But a default policy of ACCEPT is not exactly in keeping with this paranoia. The preferred treatment in a policy/catch-all should really be just plain REJECT, or better yet:
REJECT --reject-with icmp-net-prohibited
Does this "hide the machine from scanners"? No. It makes it very clear the machine is there, and that a firewall has expressly prohibited a connection. Again, keep in mind you cannot hide the machine and still use it. You can hide ports behind firewalls in this manner, but you can't hide the firewall itself. That is not the point.
The only theoretical weakness this opens up is that in the case of a DoS attack, evaluating firewall rules is part of what overwhelms the machine. However, another point of a firewall, ideally, is that it can be used to implement the least expensive mechanism, i.e., one that requires the most resources from the attacker to create a DoS scenario. In this case, we might again, naively, assume the cheapest thing to do is DROP, but here's the problem that creates:
Simply dropping a packet in the end will "hide" the port, but since you can't hide the machine this way unless you drop on all ports (making the network "connection" useless or worse, since if someone is sure you are at a particular IP, which isn't hard to do, it can still target it and the machine still has to process the DROP), this port isn't really hidden at all. Someone scanning or attacking the machine will understand in an instant either there's something on the port that's been over whelmed or else the machine is just dropping packets there by default. To draw an analogy: This is a little kid "hiding" by closing her eyes. She can't see what's going on so she figures nobody else can either. These sorts of naive assumptions are something our minds are prone to for the same reason we can reason logically -- but that's philosophy, so anyway...
Now lets assume most of the time the machine isn't the target of a DoS attack. Which it could not be, except within the confines of a subnet. E.g., your sister has made a major investment in hardware and constantly DoS 's your pi on the house LAN. Within the context of the internet at large, widescale DoS attacks are very hard to maintain because they impact not just the target, but upstream routers as well, and those will work together to isolate attacking machines as far as possible.
But you have naively decided the stealthy thing to do is drop packets. Guess what this accomplishes under normal circumstances. More traffic. Why? Because it leads to a timeout. This implies what could be going on is there's actually a server there, but it is very busy. To establish this, during the timeout period the other machine will continue to send TCP SYN/ACK packets, which your machine still has to deal with (by "dropping" them). So although a single DROP may be less resource intensive than a single REJECT, by using DROP in this manner you won't be doing a single DROP. You'll be doing multiples of them. What's more, after the timeout, if this is the result of a mistake somewhere (which is much more likely than a DoS attack1), client software somewhere may keep trying. If it is something persistent and automated, it may do it for hours, days or forever.
You can spare yourself all that with a single:
REJECT --reject-with icmp-net-prohibited
The remote machine now knows there is no point in retrying this port. That includes scanners. If you did not read the footnote yet, read it now to understand why. This port is blocked by a firewall. Period.
Before I get into your example here's something you want as rules for INPUT and OUTPUT, preferably at the top of the list:
INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
This means that TCP connections which have been established (which first requires they are ACCEPTed by some other rule) are allowed to continue. Putting this at the top of the list means legitimate connections place a minimum of stress on the firewall they are legitimately passing through. For UDP "connections" things are a bit more complicated but these rules apply to them to them too.
So, now you have a policy or final catch-all of REJECT, and a preliminary rule set allowing legitimate connections to continue unhindered efficiently, you just need some rules to ACCEPT:
INPUT connections to servers you have running, in this case just openVPN and SSH.
OUTPUT connections from clients which may try to connect to servers on other machines.
In your example, because you have no ESTABLISHED,RELATED rules, you've used complimentary INPUT and OUTPUT rules. In general the ESTABLISHED,RELATED methodology is much better because you cannot predict what port the client will end up sending from, just where it is sending to (requiring two rules in place of one). Clients don't send from the service port -- that's for servers, which may be running on the same machine, and if they aren't, you should be REJECTing connections to that port from the firewall. The client's local port will usually be random for a number of reasons but works because an OUTPUT rule allows it. Here's the problem: without a corresponding INPUT rule, it can't hear back from the server.
So then you need a to use --sport
with INPUT. This is okay but again, not the most efficient solution. The most efficient solution is the preliminary ESTABLISHED, RELATED rules.
If you are not aware of it yet www.iptables.info is a great and very extensive source of information. This is probably a good place to start for what we are discussing here.
To Summarize:
You cannot hide your machine from scanners and use it too.
Defaulting to DROP will cause more, not less, stress on the firewall (and therefore the network link, the OS, the CPU, and the system as whole) than using REJECT. Pretending DROP hides anything is like pretending you are invisible when you close your eyes.
Use ESTABLISHED, RELATED rather than elaborate OUTPUT --dport/INPUT --sport pairs. Then you just need a single INPUT rule for servers and a single OUTPUT rule for clients.
1. Also note that scanners aren't looking for DoS targets. What is the point of trying to DoS a random target? It's expensive, and it may easily expose the attacker and is likely to have much more negative long term consequences for them than anyone else.
What scanners are looking for are legit, open ports, connected to server software with known vulnerabilities, which they will then try to exploit. Ideally, this allows them to secretly establish long term access to your machine on their own terms. A DoS is the opposite of "secretive". The purpose of establishing long term secret access is so at some latter point they can use your machine as part of a DoS on someone else -- someone that is not a random target. It's not up to the local machine's firewall to prevent this original access, it is up to the server software by not implementing vulnerabilities. E.g., don't allow password access via SSH and use "1234" as a password.
What is a major purpose of firewalls in this context is to delimit outgoing traffic to make the machine less useful as a DoS "zombie" attacker. Of course, if the vulnerability provided root access, you are screwed, because the firewall can then be disabled and other security mechanisms on the machine assessed in advance. You cannot truly guard against this, again, except by just disconnecting the machine from the internet.