Files
Cluvex f2b3064153 Dinalmask: Add exp to noise (#902)
* Finalmask: Add "tag" to noise items

* Finalmask: Rename noise "tag" to "exp"

* Finalmask: Move noise "exp" into "type"
2026-10-03 14:11:21 +08:00

27 KiB
Raw Permalink Blame History

FinalMask

FinalMask добавляет последний слой маскировки после того, как ядро уже обработало шифрование транспортного уровня, включая TLS и REALITY.

Его можно использовать для разных видов маскировки TCP- и UDP-трафика, а также для настройки параметров QUIC.

FinalMaskObject

FinalMaskObject соответствует полю finalmask в StreamSettingsObject.

{
  // пример для outbound, аналогично применимо к inbound
  "outbounds": [
    {
      // ...
      "streamSettings": {
        // [!field focus]
        "finalmask": {
          "tcp": [
            {
              "type": "",
              "settings": {}
            }
          ],
          "udp": [
            {
              "type": "",
              "settings": {}
            }
          ],
          "quicParams": {
            "congestion": "force-brutal",
            "bbrProfile": "standard",
            "debug": false,
            "brutalUp": "60 mbps",
            "brutalDown": 0,
            "udpHop": {
              "ports": "20000-50000",
              "interval": "5-10"
            },
            "initStreamReceiveWindow": 8388608,
            "maxStreamReceiveWindow": 8388608,
            "initConnectionReceiveWindow": 20971520,
            "maxConnectionReceiveWindow": 20971520,
            "maxIdleTimeout": 30,
            "keepAlivePeriod": 0,
            "disablePathMTUDiscovery": false,
            "maxIncomingStreams": 1024
          }
        }
      }
    }
  ]
}

TCPMask

Массив для маскировки TCP-трафика, исходящего из ядра. Первый элемент массива является самым внутренним слоем маскировки.

{
  "finalmask": {
    // [!field focus]
    "tcp": [
      {
        "type": "",
        "settings": {}
      }
    ]
  }
}

type: string

Тип этого слоя маскировки.

settings: object

Конкретные настройки для этого типа маскировки.

Поля каждого типа приведены ниже.

header-custom

{
  "type": "header-custom",
  // [!field focus]
  "settings": {
    "clients": [
      [
        {
          "delay": 0,
          "rand": 0,
          "randRange": "0-255",
          "type": "",
          "packet": []
        }
      ]
    ],
    "servers": [
      [
        {
          "delay": 0,
          "rand": 0,
          "randRange": "0-255",
          "type": "",
          "packet": []
        }
      ]
    ],
    "errors": [
      [
        {
          "delay": 0,
          "rand": 0,
          "randRange": "0-255",
          "type": "",
          "packet": []
        }
      ]
    ]
  }
}

clients[n][m].delay: задержка в миллисекундах. Если значение равно 0, данные отправляются слитно с предыдущим пакетом.

clients[n][m].rand: добавляет указанное количество случайных байтов. Несовместимо с packet.

clients[n][m].randRange: диапазон значений случайных байтов. По умолчанию 0-255.

clients[n][m].type: тип packet. Поддерживаются array, str, hex и base64. Значение по умолчанию - array.

clients[n][m].packet: добавляет фиксированные данные. Несовместимо с rand.

fragment

{
  "type": "fragment",
  // [!field focus]
  "settings": {
    "packets": "tlshello",
    "lengths": ["3-5", "6-8", "10-20"],
    "delays": ["10-20"],
    "maxSplit": "3-6"
  }
}

Управляет исходящей TCP-фрагментацией. В некоторых случаях это может обмануть системы цензуры, например помочь обойти SNI-блоклисты.

"length", "delay" и "maxSplit" имеют тип Int32Range.

"packets": поддерживаются два режима фрагментации. "1-3" разрезает TCP-поток и применяется к 1-й, 2-й и 3-й операциям записи клиента. "tlshello" фрагментирует пакет TLS-рукопожатия.

"lengths": длина фрагмента в байтах.

n-й элемент массива задаёт ожидаемую длину n-го фрагмента, отрезаемого от текущего обрабатываемого пакета; последний элемент продолжает применяться ко всем последующим фрагментам, отрезаемым от этого пакета. Все элементы, кроме последнего, могут быть 0 (иначе это приведёт к бесконечному холостому циклу); для нарезки TCP-потока это выражается в том, что данные не отправляются, а для tlshello — в отправке нарушающей RFC пустой TLS-записи (допускается некоторыми реализациями, но не Golang).

"delays": интервал между фрагментами в миллисекундах.

n-й элемент массива задаёт, сколько ждать после отправки n-го фрагмента, отрезаемого от текущего обрабатываемого пакета; последний элемент продолжает применяться ко всем последующим фрагментам, отрезаемым от этого пакета.

Если значение равно 0 и задано "packets": "tlshello", фрагментированный Client Hello будет отправлен в одном TCP-пакете, если его исходный размер не превышает MSS или MTU и система не фрагментирует его автоматически.

"maxSplit": максимальное количество фрагментов. Ограничивает, на сколько частей можно разделить один пакет. 0 означает без ограничений.

sudoku

{
  "type": "sudoku",
  // [!field focus]
  "settings": {
    "password": "",
    "ascii": "",

    "customTable": "", // в upstream-документации поле называется custom_table
    "customTables": [""], // в upstream-документации поле называется custom_tables

    "paddingMin": 0, // в upstream-документации поле называется padding_min
    "paddingMax": 0 // в upstream-документации поле называется padding_max
  }
}

Значение этих полей см. в upstream-документации.

UDPMask

Массив для маскировки UDP-трафика, исходящего из ядра. Первый элемент массива является самым внутренним слоем маскировки.

{
  "finalmask": {
    // [!field focus]
    "udp": [
      {
        "type": "",
        "settings": {}
      }
    ]
  }
}

type: string

Тип этого слоя маскировки.

settings: object

Конкретные настройки для этого типа маскировки.

Поля каждого типа приведены ниже.

header-custom

Всегда объединяется с заголовком пакета.

{
  "type": "header-custom",
  // [!field focus]
  "settings": {
    "client": [
      {
        "rand": 0,
        "randRange": "0-255",
        "type": "",
        "packet": []
      }
    ],
    "server": [
      {
        "rand": 0,
        "randRange": "0-255",
        "type": "",
        "packet": []
      }
    ]
  }
}

client[n].rand: добавляет указанное количество случайных байтов. Несовместимо с packet.

client[n].randRange: диапазон значений случайных байтов. По умолчанию 0-255.

client[n].type: тип packet. Поддерживаются array, str, hex и base64. Значение по умолчанию - array.

client[n].packet: добавляет фиксированные данные. Несовместимо с rand.

mkcp-legacy

{
  "type": "mkcp-legacy",
  // [!field focus]
  "settings": {
    "header": "", // dns dtls srtp utp wechat wireguard
    "value": "" // password domain
  }
}

Маскировка/обфускация заголовка пакетов в стиле старого mKCP. Значение value зависит от header. Обратите внимание: подделка - это лишь простая подделка заголовка пакета и не означает реализацию полного протокола.

Когда пусто: применяется шифрование AES-128-GCM, где value - пароль. Если value пусто, вместо этого используется простая XOR-обфускация по умолчанию.

dns: подделка под DNS-запрос. value - указанный домен; при пустом значении по умолчанию www.baidu.com.

dtls: подделка под данные приложения DTLS 1.2. value не используется.

srtp: подделка под SRTP. value не используется.

utp: подделка под uTP (BitTorrent). value не используется.

wechat: подделка под видеозвонок WeChat. value не используется.

wireguard: подделка под WireGuard. value не используется.

noise

Шум, отправляемый перед реальными данными.

{
  "type": "noise",
  // [!field focus]
  "settings": {
    "reset": "30-60",
    "noise": [
      {
        "rand": "1-8192",
        "randRange": "0-255",
        "type": "",
        "packet": [],
        "delay": "10-20"
      }
    ]
  }
}

reset: значение типа Int32Range в секундах. После отправки шума состояние сбрасывается через указанное время, и шум можно снова отправить на тот же адрес. 0 означает не сбрасывать, то есть отправить только один раз.

rand: добавляет случайные байты или случайные байты заданной длины. Несовместимо с packet.

randRange: диапазон значений случайных байтов. По умолчанию 0-255.

type: тип packet. Поддерживаются array, str, hex, base64 и exp. Значение по умолчанию - array.

packet: добавляет фиксированные данные. Несовместимо с rand.

При "type": "exp" packet - это строка-выражение, из которой собирается один пакет шума. Он генерируется заново при каждой отправке, поэтому может содержать меняющиеся данные, например метку времени. Части выражения склеиваются по порядку в один пакет:

  • <b hex>: фиксированные байты в шестнадцатеричном виде, необязательный префикс 0x игнорируется
  • <r N> или <r A-B>: N случайных байтов или случайное количество от A до B
  • <rc N> или <rc A-B>: то же, случайные буквы (a-zA-Z)
  • <rd N> или <rd A-B>: то же, случайные цифры (0-9)
  • <t>: текущее Unix-время в секундах, 4 байта big-endian
  • <c>: счётчик, 4 байта big-endian, каждый раз увеличивается на единицу
  • <n>: 8 случайных байтов

Например, {"type": "exp", "packet": "<b 0d0a0d0a><t><r 24>"} отправляет \r\n\r\n, метку времени и 24 случайных байта одним пакетом.

delay: задержка в миллисекундах. После отправки одного элемента шума Xray ждёт указанное время перед отправкой следующего.

salamander

Обфускация Salamander. Используется в Hysteria2.

{
  "type": "salamander",
  // [!field focus]
  "settings": {
    "password": "your-password",
    "packetSize": "512-1200"
  }
}

password: пароль обфускации.

gecko

packetSize: Int32Range

Если не пусто, включает обфускацию Gecko: к QUIC-пакетам с длинным заголовком применяется дополнительная обфускация с фрагментацией и заполнением (пакеты с коротким заголовком используют Salamander напрямую). packetSize задаёт размер фрагмента, а его верхняя граница не должна превышать 2048.

sudoku

{
  "type": "sudoku",
  // [!field focus]
  "settings": {
    "password": "",
    "ascii": "",

    "customTable": "",
    "customTables": [""],

    "paddingMin": 0,
    "paddingMax": 0
  }
}

Значения те же, что и в TCP-версии.

xdns

Использует DNS-запросы для передачи данных, подобно DNSTT. Для переноса полезной нагрузки выполняются стандартные DNS-запросы; поддерживаются типы TXT, A и AAAA.

Из-за технических ограничений эффективный MTU очень мал, QUIC использовать нельзя, поэтому рекомендуется сочетать этот режим с mKCP. Рекомендуемые значения MTU: на клиенте 130; на сервере 900 для TXT, который почти передаёт исходные байты, для AAAA разумно уменьшить значение примерно до половины или ниже, а для A - примерно до одной восьмой или ниже. Теоретическая эффективность кодирования различается, а реальные значения зависят от того, сколько AAAA- или A-записей промежуточные форвардеры готовы терпеть в ответах.

Поскольку выполняются стандартные запросы, они могут пересылаться через любой UDP DNS-сервер, хотя эффективность может быть очень низкой.

Чтобы использовать эту функцию, сервер должен слушать порт 53, затем прокси-протокол должен указывать на DNS-сервер, например 8.8.8.8:53, и у вас должен быть домен из domains, после чего его NS-запись нужно направить на сервер.

Например, если у вас есть example.com, задайте A-запись a.example.com, указывающую на IP сервера, затем задайте NS-запись t.example.com, указывающую на a.example.com, и используйте t.example.com. Хост, используемый в A-записи, не должен быть поддоменом хоста, используемого в NS-записи.

{
  "type": "xdns",
  // [!field focus]
  "settings": {
    "domains": [
      {
        "name": "t.example.com",
        "lenLimit": 255, // 0-255
        "labelLimit": 63, // 0-63
        "types": [1, 5, 16, 28], // 1:A 5:CNAME 16:TXT 28:AAAA
        "edns0": 1232 // 0,512-4096
      }
    ],
    "resolvers": [
      {
        "type": "udp",
        "settings": {
          "addr": "127.0.0.1:53"
        }
      }
    ]
  }
}

Совместимо только с kcp; рекомендуется значение TTI, равное 200. Настройка MTU требуется только на стороне сервера (см. раздел настроек MTU). Расчет CNAME относительно сложен; как правило, полученные значения находятся в диапазоне между значениями для записей AAAA и TXT:

  • При edns0 = 512: A 39, TXT 215, AAAA 117
  • При edns0 = 1232: A 174, TXT 932, AAAA 492

xicmp

{
  "type": "xicmp",
  // [!field focus]
  "settings": {
    "dgram": false, // optional
    "ips": [] // optional
  }
}

dgram: Более низкие права доступа, только на стороне клиента (Linux, Mac, iOS)

ips: В настоящее время CIDR не поддерживается

realm

Самодельный https://github.com/apernet/hysteria-realm-server

{
  "type": "realm",
  // [!field focus]
  "settings": {
    "url": "realm://public@xxx/your-realm-name",
    "stunServers": [
      "stun.nextcloud.com:3478",
      "global.stun.twilio.com:3478"
    ],
    "tlsConfig": {}, // optional
    "ipMode": "dual",
    "portMapping": {
      "enabled": false,
      "timeout": 10,
      "lifetime": 600
    }
  }
}

url: realm[+http]://token@host[:port]/id

stunServers: Для предсказания портов NAT используется несколько адресов IPv4/IPv6

tlsConfig: То же, что tlsSettings

ipMode: Управляйте разрешением доменных имен STUN и фильтрацией одноранговых узлов (peer) в пределах области (realm)

portMapping.enabled: Включите фиксированное сопоставление портов для улучшения доступности входящих соединений

portMapping.timeout: секунды

portMapping.lifetime: секунды

Для регистрации сбоев соединения требуется уровень отладки. К возможным факторам, способствующим возникновению проблем, относятся поставщик STUN, поставщик Realm

udphop

{
  "type": "udphop",
  // [!field focus]
  "settings": {
    "mode": "intervallocal,intervalremote", // intervallocal intervalremote perconnremote
    "interval": "5-10",
    "remoteIPs": [""],
    "remotePorts": "20000-50000,443"
  }
}

intervallocal: Поддерживает только WireGuard, Hysteria и xhttp-h3

intervalremote: Требует использования в связке с iptables или nftables

perconnremote: Требует использования в связке с iptables или nftables

mode: Список, разделенный запятыми; обычно intervallocal,intervalremote, либо только intervallocal, либо только perconnremote

interval: секунды

remoteIPs: Обязателен только в том случае, если mode включает intervalremote или perconnremote; если поле не заполнено, адрес наследуется с вышестоящего уровня. Поддерживается нотация CIDR.

remotePorts: Обязателен только в том случае, если mode включает intervalremote или perconnremote; если поле не заполнено, адрес наследуется с вышестоящего уровня

quicParams

{
  "finalmask": {
    // [!field focus]
    "quicParams": {
      "congestion": "force-brutal",
      "bbrProfile": "standard",
      "debug": false,
      "brutalUp": "60 mbps",
      "brutalDown": 0,
      "udpHop": {
        "ports": "20000-50000",
        "interval": "5-10"
      },
      "initStreamReceiveWindow": 8388608,
      "maxStreamReceiveWindow": 8388608,
      "initConnectionReceiveWindow": 20971520,
      "maxConnectionReceiveWindow": 20971520,
      "maxIdleTimeout": 30,
      "keepAlivePeriod": 0,
      "disablePathMTUDiscovery": false,
      "maxIncomingStreams": 1024
    }
  }
}

Используется для настройки параметров QUIC в XHTTP H3 и Hysteria.

congestion: reno | bbr | brutal | force-brutal

Алгоритм управления перегрузкой. В Hysteria по умолчанию используется brutal, а в XHTTP H3 - bbr.

reno и bbr - известные алгоритмы.

brutal: согласует с другой стороной фиксированную скорость отправки пакетов или откатывается к BBR.

force-brutal: то же, что и brutal, но принудительно использует для исходящего трафика фиксированную скорость отправки из brutalUp, игнорируя согласование с другой стороной.

Обратите внимание: XHTTP H3 не может использовать режим brutal, потому что у него нет механизма согласования, но поддерживает force-brutal, которому согласование не требуется.

bbrProfile: conservative | standard | aggressive

Когда для QUIC выбран алгоритм BBR, этот параметр управляет BBR-профилем. Значение по умолчанию - standard. conservative немного осторожнее, aggressive немного агрессивнее.

debug: false | true

Включает логи для управления перегрузкой bbr и brutal.

brutalUp: string

brutalDown: string

Ограничения скорости загрузки и отдачи. Значение по умолчанию - 0.

Формат удобен для пользователя и поддерживает разные распространённые записи битрейта, включая 1000000, 100kb, 20 mb, 100 mbps, 1g и 1 tbps. Регистр не важен, пробелы между значением и единицей можно ставить или не ставить, а если единица не указана, по умолчанию используется bps. Значение не может быть меньше 65535 bps.

Поведение согласования такое же, как в Hysteria Brutal:

Значение на стороне сервера ограничивает максимальную скорость режима Brutal, которую может выбрать клиент. 0 означает, что сервер не ограничивает клиента.

Если на стороне клиента указано 0, используется режим BBR. Если значение не нулевое, используется режим Brutal и он всё равно ограничивается значением на стороне сервера.

Помните, что направления относительны: исходящая скорость сервера соответствует входящей скорости клиента, а входящая скорость сервера - исходящей скорости клиента.

udpHop: {"ports": string, "interval": number}

Настройка прыжков по UDP-портам.

ports задаёт диапазон портов. Это может быть строка с одним числом, например "1234", или диапазон, например "1145-1919" для портов с 1145 по 1919. Можно использовать запятые для разбиения на сегменты, например 11,13,15-17.

interval - интервал прыжков по портам в секундах. Минимум 5, значение по умолчанию - 30 секунд.

initStreamReceiveWindow: number

maxStreamReceiveWindow: number

initConnectionReceiveWindow: number

maxConnectionReceiveWindow: number

Это четыре конкретных параметра QUIC-окон. Не меняйте их, если вы не понимаете, что делаете. Если менять всё же нужно, рекомендуется сохранять соотношение окна приёма потока и окна приёма соединения как 2:5.

maxIdleTimeout: number

Максимальный таймаут простоя в секундах. Это время, после которого сервер закроет соединение, если не получает никаких данных от клиента. Допустимый диапазон - от 4 до 120 секунд. Значение по умолчанию - 30 секунд.

keepAlivePeriod: number

Интервал QUIC KeepAlive в секундах. Допустимый диапазон - от 2 до 60 секунд. По умолчанию отключено.

disablePathMTUDiscovery: bool

Отключать ли Path MTU Discovery.

В других реализациях этот режим принудительно отключается на системах, отличных от Linux, Windows и Darwin, тогда как Xray не делает этого автоматически. Если ваша ОС не входит в linux, windows или darwin, возможно, вам придётся отключить его вручную.

maxIncomingStreams: number

Параметр стороны сервера. Если задан, он не должен быть меньше 8.