Across the Great Wall we can reach very corner in the world.

The first email sent in China, sending from Beijing to German, at 21:07, September 14th, 1987.

1987年9月14日21时07分 中国第一封电子邮件 从北京发往德国 “越过长城,走向世界”

– 摘自 QQ 邮箱首页

How the Great Firewall of China (GFW) works

  • HTTP sniffing
  • DNS spoofing
  • IP blacklist
  • Ports blocking (mostly for VPNs)
  • Interrupt encrypted protocol

HTTP sniffing

Mostly used in the early days, for instance, around 2008.

If your HTTP URL or content contains sensitive keywords, your connection will be reset. The firewall will set TCP RESET signal to both ends of the connection. What you observe in Chrome will be TCP_CONNECTION_RESET.

The reset status will keep sending in the following several minutes, even if you do not contains sensitive keywords.

HTTP sniffing (solution)

  • It’s said that if both ends ignore this reset signal, the connection can continue.


  • It’s also said that, if your HTTP heads contains extra prepended blank lines, GFW will ignore that package


  • Encrypt the data being transferred

    base64 is enough, for instance, a PHP web proxy


DNS spoofing

You will get random IP as A result when you query for a blocked domain, i.e.,

And as you know, DNS query is layer by layer, so the DNS in the whole country will always return the polluted result.

$ dig @

DNS spoofing (solution)

  • query DNS via TCP (but now you got TCP reset for blocked domains)
    $ dig @ -p 53 +vc
  • hosts file: Smart Hosts
  • via the other UDP ports (only works for Open DNS)

    $ dig @ -p 5353 +vc

IP blacklist

Some of the services have been blocked as IP blacklist, that means, no connection will be allowed.

Examples include Google, twitter, facebook, etc,

IP blacklist (solution)

  • Proxy
    • Socks5, HTTP
    • GoAgent
    • SSH dynamic forward
    • Shadowsocks
  • VPN
    • sshuttle
    • PPTP
    • L2TP (IPSec-PSK)
    • SSTP

Ports blocking

Some of the ports are being blocked or interrupted in China, for instance:

  • L2TP: IPsec 500 / 4500, or 1701 (UDP), or 1723 (TCP)
  • SSH: 22
  • SSTP: blocked the GRE protocol

Ports blocking (solution)

  • L2TP: usually blocked in the IPsec handshake, you may try to connect via 4G and then connect to WiFi (data is being transferred as UDP after handshake).
  • SSH: try to change your port
  • PPTP is insecure

Or, use:

  • SSTP (it’s not likely they will block all HTTPS traffic)
  • Shadowsocks

Interrupt encrypted protocol

GFW may interrupt encrypted protocal, VPN, SSL.

It’s said that the CA of CNNIC, had signed some certificates of Google / Facebook for decrypt the SSL traffic.

You may also think about what’s the certificate of looks like.

General Solutions

Socks5, HTTP

  • Search for free or paid service
  • build your own server

insecure, not recommended

BTW: HTTPS traffic send via HTTP proxy is using CONNECT tunnel, which sends as TCP.

GoAgent or GappProxy

Running in Google Application Engine, started in around 2008

  • First OSS for GFW
  • Free 1GB / node / day, 10 nodes free node
  • Fast (use Google’s Beijing Data Center, died recent years)
  • Not support HTTPS (self-signed)

SSH dynamic forward

ssh -D will open a port on local machine act as Socks5 proxy.

$ ssh -D 7777 # or DynamicForward in config


Shadowsocks (SS)

aiming to implement a proxy protocol without signature, so that it can hardly being detected and blocked

  • server side: $ sudo apt install shadowsocks-libev (after 16.04)

  • client side: Windows / iOS / Android / MacOS … including routers (miwifi), use iptable to forward TCP traffic to socks5 (similar project: RedSocks)

Also read SS vs SSr:

Rule-based proxying

You won’t want to send all your traffic via proxy, it’s slow for domestic destinations!

PAC (Proxy Auto-Config) script

function FindProxyForURL(url, host) {
  // our local URLs from the domains below don't need a proxy:
  if (shExpMatch(url,"**")) {
      return "DIRECT";
  if (shExpMatch(url, "**/*")) {
      return "DIRECT";

  // URLs within this network are accessed through
  // port 8080 on
  if (isInNet(host, "",  ""))    {
      return "PROXY";

  // All other requests go through port 8080 of
  // should that fail to respond, go directly to the WWW:
  return "PROXY; DIRECT";

I don’t think you want to do it yourself all the time.

Chrome Plugin

Proxy SwitchyOmega


GFW list

I seldom enable this plugin, but I export the rules as a .pac file, and set that file as global config. And what’s more, the Windows / Mac version of ss will do things like this for you.

Application layer is not enough

for instances, in the terminal, or other applications that not working or working well with HTTP / SOCKS proxy


sshuttle is perfect solution if you just want TCP traffic cross the GFW, it works when you have a ssh server.

  • no server side installation (only python is requried, server side code is send by client)
  • support remote DNS by --dns
  • stable: SSH is comparing not likely to be blocked


if you need UDP, ICMP, or other stuffs, you still need VPNs

  • PPTP is insecure.
  • L2TP looks good
  • SSTP is recommanded

VPN server

  • Windows Server
  • SoftEther This is a full solution for
    • Open VPN
    • L2TP (IPsec-PSK or RAW)
    • SSTP

      It also implemented VPN as virtual devices (ether, hub) in Windows (or Linux?), which is great. Open source project, but be aware: according to privacy rules, it’s restricted by Japanese goverment.

  • Open VPN

Enable Google BBR in Linux Kernal 4.9

Routing on top of VPN

  • Windows: route add <IP> mask <MASK,> <GATEWAY> metric 25 (script)
  • Mac: /sbin/route add -net 111.222.0/16 -interface $1 or add to /etc/ppp/ip-up

CN IP arrangement:

Anonymous notes

  • Proxy is usually not anonymous if it strictly follow HTTP (RFC 2616)
  • IP address is static
  • Screen resolution / cookies / User Agent / Not modified header … may indidates your identity

The only valid solution: Tor

Thank you!