Hi GT!
Without spreading thoughts on the trees, let's get down to business. To provide myself with fast and uncensored Internet, I have long been using the standard scheme: OpenVPN and the simplest VPS abroad. UDP is used as a transport protocol.
ProblemAt one "wonderful" moment, I discovered that the VPN had fallen off and was no longer rising. I will not describe a long investigation of the problem - I will say the result immediately: the change in the port number helped. It did not help for a long time: after a couple of days the tunnel broke again and again was restored by changing the port.
HypothesisOn the provider's firewall, my traffic statistics look like this: 100% or a little less using a single UDP protocol, through a single port and on a single IP. Thus, if we imagine this in the form of a graph, it will be strikingly different from that of the average user, where there will be a lot of “peaks” of the graph for different protocols, ports (TCP 80, 443, 993 ...) and IP addresses.
')
It seems that the heuristic of their firewall reacts to this and blocks the connection, through which the share of traffic passes, more than a certain threshold. At the same time, such a filter, by definition, will work with some delay, since statistics is a science that loves large numbers.
TaskIt is necessary to develop a solution that will change the VPN port number with a specified interval, which is obviously smaller than the statistics conversion interval for the firewall. The port should change in an unpredictable manner to prevent the filter from running ahead of the curve. You also need to be able to start the port change manually for various force majeure cases. The change in time should work even with complete loss of server management.
AlgorithmIn general, the generation formula looks like this:
port = hash(shared_secret + round(time) + ondemand_key) % (port_max - port_min + 1) + port_min
- hash () - hash function
- shared_secret is the key that ensures the unpredictability of the next result without his knowledge. The only secret part of the system.
- round (time) - some function of deification from the current time in UTC. The degree of desensitization determines the interval for changing ports, for example, dropping seconds and minutes - an interval of 1 hour, dropping another hour and maintaining the AM / PM mark - 12 hours, and so on.
- ondemand_key is a key that is loaded from a reliable third-party server in order to be able to manually change the port by changing this key.
- port_min and port_max - the range of ports used, the minimum and maximum, respectively.
In order for the system to quickly respond to the change of ondemand-key, I run the script on the scheduler at a small interval of several minutes. In this case, it is necessary to provide for checking whether the parameters actually changed, so that if the result is negative, the script would immediately end.
Let's look at the expression above, which has already been calculated by the time of verification. If neither the hash () value nor the range limit has changed, then there has been no change. To do this, take the hash again:
cache = hash(hash(...) + port_min + port_max)
After that, we’ll read the old cache value from a special file, compare it, and if they differ, update the file and continue with the script; if the same - exit.
Next is a matter of technology: we substitute the port value into the rule template for iptables (there are two of these templates for the client and server role of the script), add the rule to the table, read the previous rule from another file and, if it exists, remove it from iptables, update the file current rule.
Theoretically, at this moment the connection should already work on the new port, but in practice for some reason it continues to use the old one until the daemon is restarted. I would be grateful if someone explained the reason for such a bug, but for now I’m just giving the command to restart from the script. Communication interruption at the same time - a few seconds and does not cause inconvenience.
System restart on demandIt’s very convenient to use a public VCS (I have GitHub) as the ondemand key repository. In principle, any free hosting would be suitable, however, VCS has an important advantage in storing the history of edits. A situation may occur when one of the ends of the tunnel has updated its key, and the second for some reason cannot reach the repository and works according to the old key in the cache. In this case, you can try to rollback the commit: if the drop in communication, which caused the admin to pull ondemand, is not caused by blocking the port, but for example by a temporary failure at the uplink, returning the key will soon raise the tunnel. In practice, such situations have happened a couple of times.
The script that pulls the key is nothing special - just wget, checking its return code and caching to the file - so there’s no point in describing it, the code will tell everything for itself.
The ondemand-key management script is a more voluminous thing, although in fact it is also simple - it is a binding to simplify operations on the repository of keys. Allows you to perform in one command operations create, delete and change keys.
ConclusionI believe that the tool for solving the set task was a success, and has been successfully operating for more than a year. Moreover, the resulting utility can be considered a universal weapon against this type of filtering, because:
- In addition to OpenVPN, scripts can be used for any network service.
- as a cryptographic device, you can use any hash function, which provides a deposit for possible future compromise of today's algorithms
- one server can serve a large number of clients with unique keys - just scatter portgen instances into individual folders
Linksgithub.com/Raegdan/portgen - the portgen program itself
github.com/Raegdan/portgen-ondemand is a program for managing ondemand keys and my keys at the same time. This was done solely for convenience. The keys ondemand are unclassified, so if someone for some reason suddenly needs a piece of my / dev / urandom, I don’t feel sorry;)
NoteThe code is for Habr! Here we have astronauts, drones and gadget reviews!In principle, I can not disagree with such an argument, and the program code is really more a Habr profile. However, first, this project is directly related to the fight against censoring the Internet - a topic that has been explicitly resettled here. Secondly, my only article so far was written before the separation and remained on Habré, which causes certain limitations for my account on the GT. Please treat with understanding.