Automatic blocking bypass

Description of the program for automatically bypassing blocking on the Internet, the program code is on the repository antiblock.

Around May 2022, one of the YouTube domains (yt3.ggpht.com) was blocked, through which previews and channel logos are uploaded. If before this blocking didn’t bother me much, then YouTube without pictures, for an active user, is hard. Next, several different approaches were taken to optimally bypass the blocking of this domain.

  Example of no preview

Example of no preview

Attempt number one – Your own VPN

In the spring of 2022, it became relevant to create your own VPNs based on the capacities of rental VPS. I also created my VPN WireGuard. You can read how to do it yourself, for example, in the article.

Passing all traffic from your phone or tablet through the VPN caused the battery to drain quickly. And some sites were not accessed via VPN, such as Gosuslugi or Avito. Therefore, it was decided to come up with a more flexible and adaptive method, namely routing directly on the router. But for routing on the router, you must have a router with WireGuard support, which means you need a router on which you can install OpenWrt. My previous router (RT-AC57U V3) did not have this capability, and since I wanted a powerful enough device for experimenting and setting up a network drive, the choice fell on the Beelink U59 Pro. A couple of powerful antennas and another Wi-Fi module (Mediatek MT7921K) were bought for it. I will tell you more about assembly and configuration in the following articles. Thus, I got an X86 router with the ability to compile and run code on it. And the next attempt was made.

Beelink U59 Pro with antennas

Beelink U59 Pro with antennas

Attempt number two – Routing table

The second attempt to set up blocking bypass was to add to the routing table all blocked IP addresses posted on the site antifilter.download. Listed allyouneed.lst there are about ten thousand IP addresses and subnets, which is quite easily placed in the router’s routing table. A Bash script was written to automatically enter addresses.

ip r | grep VPN | cut -d ' ' -f1 | xargs -I{} ip route del {}
curl https://antifilter.download/list/allyouneed.lst > ip.txt
cat ip.txt | xargs -I{} ip route add {} dev VPN

If you add this script to Cron autostart, then the routing table will have an up-to-date list of IP addresses and subnets.

The script worked, but its flaws were quickly discovered. The IP addresses of domains included in the CDN change very often, so they are not in the list allyouneed.lst. And the domain for which everything was started (yt3.ggpht.com) is also included in the Google CDN. Therefore, this approach had to be abandoned, but it may be useful to someone due to the simple setup and the lack of the need to compile the code for your device.

Attempt number three – BPF DPI

“To fight DPI you have to think like DPI.”

After reading earlier articles about BPF, I thought to implement a simple DPI based on BPF, which will route traffic depending on the SNI TLS Handshake. This could be done either by directly routing packets through BPF, or by setting the nf_conntrack flag, and then routing through nftables. But here again the most important domain for me (yt3.ggpht.com) played its role, communication with it is not via TLS 1.3, but via QUIC, which means that nf_conntrack will not work properly, and the packets are encrypted, albeit with a known key , and for their analysis it is necessary to detect and decipher them. For usually not productive routers, this will be a very heavy load. It was also decided to abandon this approach.

Attempt number four – Automatic anti-lock

Realizing the pros and cons of previous attempts, it was decided to route depending on the DNS packets. A DNS query proxy program was written that automatically adds the IP addresses of blocked domains to the routing table. And deletes when the IP address lifetime expires. The program is posted on repositories.

Briefly describe how the program works:

  • To quickly check if a domain is included in the list of blocked domains, you need to add blocked domains to the hash table. Having tried different hash tables for C, none of them had the desired characteristics. Was written library for a hash table, more about it will be discussed in the next article. To save memory, locked domains are stored not as an array of pointers to null-terminated strings, but as a long array of consecutive null-terminated strings. Saving memory, because malloc for each line would take overhead. And in the hash table, you can store the offset of the beginning of the string from the beginning of the array, thus the hash table consists of four-byte ints, and not eight-byte pointers. The list of blocked domains is automatically updated every 12 hours in a separate thread. The code is described in the file urls_read.c.

  • When a DNS request is received from a client, the request id is replaced with an internal one so that there is no coincidence of id numbers from different clients. The old id, IP address, port, packet arrival time and domain hash are stored in an array in the field with the new id number. When the load increases to the limit, if the responses to requests do not have time to arrive, then we can start dropping packets from the client at the stage of looking for a new internal id.

  • When a response is received from the DNS server, by the incoming id, we look at the field with this number in the array from the previous paragraph. We check if the return time of the packet has expired, check if the hash of the domain matches the saved one, and if everything is fine, then we put the incoming packet in the ring buffer for processing by another thread. The ring buffer is needed for consistency in memory usage. The request processing code is described in the file net_data.c.

  • There are many different types of DNS responses, but we are interested in two options of type “A” and type “CNAME”. The “A” type makes a direct match between a domain and an IP address. The “CNAME” type makes a match between the given domain and the new domain. If we encounter a blocked domain with an “A” type response, then we add the IP address to the routing table, and add the IP address to the hash table with the key IP address and the value of the expiration time of the IP address. If we meet a blocked domain with a response like “CNAME”, then add the domain to the list of temporarily blocked ones, and also add the domain with a hash table with the key domain, and the value of the domain expiration time. The code is described in the file dns_ans.c.

  • A separate thread checks for expired IP addresses and domains once per minute and deletes them. The code is described in the file ttl_check.c.

Testing

Testing was carried out on a separately written program, which emulates a large number of DNS queries. Tested on a million of the most popular domains by version CloudFlare. My program ran 100,000 requests per minute. Also, testing was carried out using AddressSanitizer And MemorySanitizerno problems were found.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *