Конфиг для выборочного обхода блокировок на базе sing-box August 5, 2024 on Savely Krasovsky's blog

Заметил, что большинство людей использует L2/L3 TAP/TUN-решения, которые в подавляющем количестве случаев являются перебором. Они часто вызывают проблемы с корпоративными VPN и заставляют постоянно переподключаться, потому что как правило роутят весь трафик через туннель. Обычно для обхода блокировок достаточно обыкновенных SOCKS/HTTP-прокси. Их умеют использовать браузеры и большинство популярных приложений и они обычно не конфликтуют с другими VPN-приложениями, например корпоративными.

Поэтому решил набросать достаточно простой конфиг для популярного прокси-движка sing-box.

Подразумевается, что:

  1. У вас уже есть настроенный сервер, например, с установленным Outline или голым Shadowsocks.
  2. Вы установили sing-box с официального сайта, GitHub или магазина приложений.
  3. Вы можете работать с консолью и в состоянии запустить команду вида sing-box run -c config.json.

Особенности конфига

  1. По умолчанию DNS-запросы уходят на ваш системный DNS-ресолвер, если не определено обратное.

    Это достигается за счёт параметров "sniff": true (позволяет сниффить SNI из запросов к прокси) и "domain_strategy": "prefer_ipv4" (позволяет ресолвить IP заранее, через правила, определенные в конфигурации, иначе ресолвинг будет происходить на удаленном сервере).

    Если для подключения к прокси-серверу, вы используете домен, то добавьте для него отдельное правило, отправляющее DNS-запрос на системный ресолвер:

    {
      "domain": "your.server.example.com",
      "server": "local-dns"
    }
    
  2. В качестве основного входящего транспорта данный конфиг использует mixed. Это SOCKS/HTTP прокси, который автоматически проставляется в настройки ОС при запуске sing-box. Это поведение можно переопределить, но тогда браузер и другие приложения придется настраивать на работу с прокси вручную, что зачастую может быть полезно.

    Этот вход может быть заменён на любой другой, например, на TUN (полезно для работы на мобильных устройствах):

    {
      "type": "tun",
      "inet4_address": "172.16.0.1/30",
      "auto_route": true,
      "strict_route": true,
      "sniff": true,
      "domain_strategy": "prefer_ipv4"
    }
    
  3. В качестве исходящих транспортов этот конфиг использует direct (прямое интернет-соединение) и shadowsocks.

    Порядок важен: если правилами не определено обратное, то sing-box пойдет по транспортам сверху вниз, то есть в нашем случае сначала он пойдет напрямую в интернет и лишь затем через Shadowsocks.

    Shadowsocks можно заменить на что угодно. Например, на XTLS-Reality:

    {
      "type": "vless",
      "tag": "vless-out",
      "server": "your.server.example.com",
      "server_port": 443,
      "uuid": "REDACTED",
      "flow": "xtls-rprx-vision",
      "tls": {
        "enabled": true,
        "server_name": "ya.ru",
        "utls": {
          "enabled": true
        },
        "reality": {
          "enabled": true,
          "public_key": "REDACTED",
          "short_id": "REDACTED"
        }
      }
    }
    

    Или WireGuard:

    {
      "type": "wireguard",
      "tag": "wireguard-out",
      "server": "REDACTED",
      "server_port": 51820,
      "system_interface": true,
      "local_address": [
        "10.252.0.1/32",
        "2600:xxxx:xxxx:cafe::1/128"
      ],
      "private_key": "REDACTED",
      "peer_public_key": "REDACTED",
      "pre_shared_key": "REDACTED"
    }
    
  4. Наконец блок с правилами. На базе правил проекта Antizapret я создал небольшую утилиту, которая генерирует sing-box-совместимые списки в формате .srs и выкладывает новые версии раз в сутки.

    С помощью этого rule_set можно добавить два правила: одно в DNS, другое в роутинг. Первое позволяет ресолвить через шифрованный DNS только заблокированные домены. Второе позволяет роутить через Shadowsocks (или другой транспорт) только заблокированные домены и IP.

    Кэш, включенный в блоке "experimental", позволяет не загружать новый .srs-файл при каждом подключении, если он не изменился.

Таким образом, в большинстве случаев вам совершенно не придется включать-выключать то, что мы называем VPN.

Полный конфиг

{
  "log": {
    "level": "info",
    "timestamp": true
  },
  "dns": {
    "servers": [
      {
        "tag": "local-dns",
        "address": "local",
        "detour": "direct-out"
      },
      {
        "tag": "cloudflare-dns",
        "address": "https://1.1.1.1/dns-query",
        "address_resolver": "local-dns",
        "detour": "shadowsocks-out"
      }
    ],
    "rules": [
      {
        "domain": "your.server.example.com",
        "server": "local-dns"
      },
      {
        "rule_set": "antizapret",
        "server": "cloudflare-dns"
      }
    ]
  },
  "inbounds": [
    {
      "type": "mixed",
      "tag": "mixed-in",
      "listen": "127.0.0.1",
      "listen_port": 1080,
      "set_system_proxy": true,
      "sniff": true,
      "domain_strategy": "prefer_ipv4"
    }
  ],
  "outbounds": [
    {
      "type": "direct",
      "tag": "direct-out"
    },
    {
      "type": "shadowsocks",
      "tag": "shadowsocks-out",
      "server": "your.server.example.com",
      "server_port": 8443,
      "method": "YOUR-METHOD",
      "password": "YOUR-PASSWORD"
    },
    {
      "type": "dns",
      "tag": "dns-out"
    }
  ],
  "route": {
    "rules": [
      {
        "rule_set": "antizapret",
        "outbound": "shadowsocks-out"
      },
      {
        "protocol": "dns",
        "outbound": "dns-out"
      }
    ],
    "rule_set": [
      {
        "tag": "antizapret",
        "type": "remote",
        "format": "binary",
        "url": "https://github.com/savely-krasovsky/antizapret-sing-box/releases/latest/download/antizapret.srs",
        "download_detour": "shadowsocks-out"
      }
    ],
    "auto_detect_interface": true
  },
  "experimental": {
    "cache_file": {
      "enabled": true
    }
  }
}

Пример конфига VLESS + Reality + сервера Youtube

Полный конфиг
{
  "log": {
    "level": "info",
    "timestamp": true
  },
  "dns": {
    "servers": [
      {
        "tag": "local-dns",
        "address": "local",
        "detour": "direct-out"
      },
      {
        "tag": "cloudflare-dns",
        "address": "https://1.1.1.1/dns-query",
        "address_resolver": "local-dns",
        "detour": "vless-out"
      }
    ],
    "rules": [
      {
        "domain": "your.server.example.com",
        "server": "local-dns"
      },
      {
        "rule_set": "antizapret",
        "server": "cloudflare-dns"
      }
    ]
  },
  "inbounds": [
    {
      "type": "tun",
      "inet4_address": "172.16.0.1/30",
      "auto_route": true,
      "strict_route": true,
      "sniff": true,
      "domain_strategy": "prefer_ipv4"
    }
  ],
  "outbounds": [
    {
      "type": "direct",
      "tag": "direct-out"
    },
    {
      "type": "vless",
      "tag": "vless-out",
      "server": "your.server.example.com",
      "server_port": 443,
      "uuid": "YOUR_UUID",
      "flow": "xtls-rprx-vision",
      "tls": {
        "enabled": true,
        "server_name": "ya.ru",
        "utls": {
          "enabled": true
        },
        "reality": {
          "enabled": true,
          "public_key": "YOUR_PUBLIC_KEY",
          "short_id": "YOUR_SHORT_ID"
        }
      }
    },
    {
      "type": "dns",
      "tag": "dns-out"
    }
  ],
  "route": {
    "rules": [
      {
        "rule_set": "antizapret",
        "outbound": "vless-out"
      },
      {
        "domain_suffix": ".youtube.com",
        "outbound": "vless-out"
      },
      {
        "domain_suffix": ".googlevideo.com",
        "outbound": "vless-out"
      },
      {
        "domain_suffix": ".nhacmp3youtube.com",
        "outbound": "vless-out"
      },
      {
        "domain_suffix": ".1e100.net",
        "outbound": "vless-out"
      },
      {
        "domain_suffix": ".ytimg.com",
        "outbound": "vless-out"
      },
      {
        "domain_suffix": ".youtu.be",
        "outbound": "vless-out"
      },
      {
        "domain_suffix": ".google.com",
        "outbound": "vless-out"
      },
      {
        "domain_suffix": ".gvt1.com",
        "outbound": "vless-out"
      },
      {
        "domain_suffix": ".googleusercontent.com",
        "outbound": "vless-out"
      },
      {
        "domain_suffix": ".googleapis.com",
        "outbound": "vless-out"
      },
      {
        "domain_suffix": ".gstatic.com",
        "outbound": "vless-out"
      },
      {
        "protocol": "dns",
        "outbound": "dns-out"
      }
    ],
    "rule_set": [
      {
        "type": "remote",
        "tag": "antizapret",
        "format": "binary",
        "url": "https://github.com/savely-krasovsky/antizapret-sing-box/releases/latest/download/antizapret.srs",
        "download_detour": "vless-out"
      }
    ],
    "auto_detect_interface": true
  },
  "experimental": {
    "cache_file": {
      "enabled": true
    }
  }
}