Theory
How it works
What your provider sees in your traffic, why that is enough to block you, and how a few altered bytes take the block away.
You do not have to read this page to use the program. But once you understand what is going on, two things stop being surprising: why there are nine strategies rather than one, and why sometimes "diagnostics is all green but the site will not open".
How the blocking works
When a browser opens an https:// connection, the first thing it sends is a TLS
ClientHello packet. Among other things it carries the SNI field (Server Name Indication): the
name of the site you are connecting to. It exists so that a server hosting thousands of domains knows
whose certificate to present.
The key detail: the connection is not encrypted yet, and the site name travels in plain text. Anyone watching the channel can see it, including the provider's equipment. Operators call this DPI (Deep Packet Inspection); in Russia it is more often TSPU, a "technical countermeasure device" installed on the operator's network.
The rest is simple. The box reads the name, compares it against a list and, if it matches, interferes. There are three ways to interfere, and the symptom usually tells you which one was used:
| What the DPI does | What it looks like |
|---|---|
| Reset (a forged TCP RST) | The connection drops instantly. The browser says the site closed the connection. The classic Russian signature. |
| Silent drop | The packet carrying the site name is discarded without a word. There is no reply, and the page hangs loading until it times out. |
| Substitution | Instead of the site you get a stub page or a redirect. Less common these days. |
There is a fourth mechanism built differently: not blocking but a volume limit. The connection is established, the first few dozen kilobytes get through, and after roughly sixteen or twenty packets in each direction the stream stalls. That is the "the site opens but video buffers and media will not load" case. To check whether this is being applied to you, use the "DPI check" button on the Diagnostics tab.
Why it can be bypassed
The bypass exists thanks to one asymmetry: the DPI is not the recipient of your traffic. It sits to the side, sees a copy of the stream, and has to decide within milliseconds, for millions of connections at once. The real server receives the whole stream and reassembles it by all the rules of TCP, in no hurry at all.
From which the main point follows: the picture of the stream can differ between the DPI and the server. If you can make the box see one thing while the server assembles another, the block does not fire and the site still opens normally. Every bypass strategy does exactly this, and it is called desynchronisation (desync).
It is important to understand the boundary: the bypass does not break into the provider, does not encrypt your traffic and does not hide your address. All it does is stop the automation from recognising the site name in the first packet. The rest of the connection runs as usual, directly.
Three families of techniques
The engine has a couple of dozen specific techniques, but they all boil down to three ideas.
Split the packet
The site name is cut by a TCP segment boundary. The browser sends not one ClientHello but several
pieces: for example, so that you goes in one segment and tube.com in the
next. The server reassembles them in the right order and sees the whole name, while the DPI, which
analyses packets individually and keeps no state for every connection, never sees the whole name.
Verbs: multisplit (just cut), multidisorder (cut and send the pieces in
reverse order, to make reassembly even harder). Where exactly to place the cut is set by
position markers such as midsld, meaning "the
middle of the second-level domain".
Forge a packet
Before the real ClientHello a fake one is sent, with an innocent name inside: for example a
ready-made ClientHello from www.google.com or vk.com. The DPI sees that one
first, considers the connection allowed and loses interest. The real packet follows behind it without
inspection.
This is where the central difficulty of the whole bypass appears. The fake is only meant for the provider's box. If it reaches the server, the server receives two ClientHellos in a row and tears the handshake down. So the fake must die somewhere in the middle: after the DPI but before the server. How that is achieved is covered below.
Verbs: fake (insert a fake only), fakedsplit and
fakeddisorder (fake plus splitting), hostfakesplit (a cut exactly on the
name marker with a false name of the same length substituted in).
Squeeze the window
The third approach works not on your request but on the server's reply. The client advertises a very small TCP window, and the server is forced to deliver its reply in small portions. The signature the DPI looks for in the reply never assembles. This technique is slower than the others, but sometimes it gets through where nothing else did.
Verbs: wssize, wsize.
How the fake dies on the way
The techniques that make an intermediate packet fail to reach the server are called fooling. The idea is always the same: craft a packet so that the DPI reads and counts it, while the network or the server itself throws it away.
| Technique | How it kills the fake | Caveats |
|---|---|---|
ip_autottl |
Lowers the TTL so the packet expires a few hops past the provider's DPI and never reaches the server. | Depends on the route. When the network changes, the value that was picked may stop fitting. |
badsum |
Corrupts the checksum. The server discards the packet as damaged. | Often useless at home: the home router behind NAT drops such a packet before it even reaches the provider, so the DPI never sees it either. |
tcp_md5 |
Adds a TCP MD5 signature option. An ordinary server does not accept such a packet. | Safe behind NAT. The working replacement for badsum on a home network. |
tcp_seq |
Shifts the sequence number outside the window. The server treats the packet as out-of-order junk. | Reliable, but some DPIs also check sequence numbers and stop believing the fake. |
tcp_ts |
Gives the fake an older timestamp. The PAWS mechanism in the server's kernel discards the "stale" packet. | Only works with TCP timestamps enabled and only with a negative value. See the warning below. |
The tcp_ts trap. The value must be negative (tcp_ts=-1000). PAWS
discards the packet with the smaller timestamp, that is, the older one. Set a positive value
and everything inverts: the fake survives and PAWS discards the real packet instead. The
connection then breaks silently, with no error, and looks like "the bypass is on but nothing
works".
One more subtlety that makes ts techniques silently do nothing: by default Windows keeps TCP
timestamps in the allowed state, which does not guarantee they are present in outgoing
packets. Zapret2UI switches them to enabled for the duration of the session and restores
the previous value on stop, so there is nothing to configure by hand.
Fooling is not applied to every verb the same way. With fake and the
faked* family it affects the fake packets only, so you can put anything there. With
multisplit and multidisorder it affects all segments, including the
real ones, so destructive fooling there breaks the connection. More in the
reference.
Why there is no single strategy for everyone
Operators use different equipment: different vendors, different firmware versions, different inspection depth settings. One DPI looks only at the first packet of a connection, another assembles the first few. One believes any ClientHello, another checks sequence numbers. One cuts QUIC entirely, another ignores it.
So a technique that punches straight through at one provider gives nothing at another. The only honest way to find a working variant is to try. That is what two of the program's features do:
- Selection works through the ready-made strategies, checks the target sites under each and keeps the one with the fewest failures. Faster and more predictable, so start there.
- Generation assembles a strategy from scratch: it tests individual techniques, optimises Discord and YouTube separately, then joins what it found into one command and checks it as a whole. Slower, but the result is fitted to your network.
What it finds is tied to a fingerprint of the current network (your router's address) and turns on by itself when you return to that network. The data is stored locally; nothing goes to the internet.
This is zapret2, not the ordinary zapret
Confusion here is constant, so let us be thorough. There are two different engines, both made by the same author, bol-van.
- zapret, also called "the first" or "the ordinary" one. Its Windows engine is called
winws.exe. That is the project most ready-made builds, guides and YouTube videos grew around. - zapret2. The
winws2.exeengine. The next generation, reworked from the inside. That is what Zapret2UI drives, hence the digit in the program's name.
This is not a fork or a competitor: the second continues the first. But there is no compatibility between them: different argument names, a different strategy format, and each has its own driver.
What changed in the second one
The main change is not in the set of techniques but in where their logic lives. In the first
zapret every technique was baked into the executable: adding a new one, or peeking at what exactly it
does to a packet, was impossible without rebuilding. In the second, the logic is moved out into Lua
scripts that sit next to the engine in the lua\ folder and are open to read.
Everything else follows from that.
| zapret (the first) | zapret2 | |
|---|---|---|
| Engine | winws.exe |
winws2.exe |
| Techniques are set with | --dpi-desync= |
--lua-desync= |
| Where a technique's logic lives | Baked into the executable. | Lua scripts next to the engine. You can read them and add your own. |
| Fake packets | Separate flags for each type, such as --dpi-desync-fake-tls. |
Named blobs: a file is declared once with --blob=name:path and used by name
afterwards. |
| Several techniques in a row | A limited set of pre-baked combinations. | As many --lua-desync entries per profile as you like, executed in order. |
| Control on the fly | None. | There are orchestrators (circular and others): they switch techniques
themselves when they catch a reset from the DPI, without restarting the engine. |
| Driver | Its own. | Its own, a different one. Which is why the two versions should not be run at the same time. |
How to tell which engine a guide is for
Two things in any config or command you find are enough.
| What you see in the text | What it means |
|---|---|
winws.exe, --dpi-desync=, --dpi-desync-ttl |
The first zapret. Does not apply here. |
winws2.exe, --lua-desync=, --blob= |
zapret2. Most likely applicable, but check the blob names. |
A word about the name "Zapret 2 GUI". There are popular builds with the digit 2 in their name that run the first zapret inside, with hand-written Lua scripts bolted on. The digit there is the version of the build, not the generation of the engine. Their strategies are fine as a source of ideas, but you cannot carry lines over directly: some of those verbs and blob names simply do not exist in stock zapret2.
What this means in practice. Configs found in guides for the first zapret will not run
here: the engine stops with an "invalid parameter" error. That is not a bug in the program but an
incompatibility of formats. If you want to bring someone else's strategy over, check every verb
against the list of supported ones and replace any blob names
such as tls5 with ones that exist here.
How this differs from a VPN
The bypass and a VPN solve different problems and affect speed differently.
| DPI bypass | VPN | |
|---|---|---|
| Where the traffic goes | Straight to the site | Through somebody else's server |
| Speed | Unchanged: the route is the same | Limited by the channel and the server's distance |
| Hides your address | No | Yes |
| Adds extra encryption | No | Yes |
| Against blocking by site name | Works | Works |
| Against blocking by IP address | Powerless | Works |
What the bypass cannot do
An honest list of limits. All of them follow from the fact that the bypass only touches how the site name in the first packet is recognised.
- Blocking by IP address. If the provider has closed the service's addresses themselves, changing the name in the packet is pointless: the packet is going nowhere. Only a VPN helps here. For Telegram, which is blocked exactly this way, the program has a built-in proxy.
- ECH. When the browser encrypts the SNI field itself (Encrypted Client Hello), the provider may cut such connections wholesale without inspecting them. Then the low-level check shows green while the site will not open in the browser.
- A volume limit. A TLS bypass does not always lift a limit on the number of packets, because that limit has nothing to do with the site name.
- Throttling on the service's own side. If the service itself is slow rather than the channel to it, there is nothing to be done.
Three details that decide everything
QUIC and HTTP/3
Modern YouTube and Discord happily use QUIC over UDP instead of the familiar TCP. That is a separate protocol and has to be bypassed separately, with its own profiles. If your provider is cutting or throttling QUIC specifically, the quickest way out is to disable it in Settings. The browser silently falls back to TCP, which the bypass handles better. Hence the classic recipe for "video loads forever".
Discord voice
Voice traffic does not run over port 443 but over UDP on high ports, up to 65535, using the STUN
protocol. A profile that only catches 443 never reaches voice at all. That is why every built-in
strategy has a separate voice profile covering the
19294-19344, 50000-65535 range. Hence also the classic symptom "text works but the voice
channel is stuck connecting".
Bypass scope
By default the program only touches domains from the lists (Discord, YouTube plus your own targets), not all traffic. That is deliberate: bypassing everything means interfering with connections from games, banking apps and everything else, which may well break as a result. An "all sites" mode exists, but turn it on deliberately.