Skip to content

Sudoku — mihomo

Sudoku is a mihomo-native obfuscating proxy protocol. It carries an AEAD-encrypted record stream whose bytes are mapped onto sudoku-grid-style lookup tables, so the wire image can be biased toward printable ASCII or high-entropy noise. On top of that it offers optional HTTP(S) masking, randomized record padding, stream multiplexing, and UDP-over-TCP. mihomo ships it as both an outbound (client) and an inbound (listener).

Outbound

Entry under proxies: with type: sudoku. Embeds BasicOption (common outbound fields such as tfo, mptcp, interface-name, routing-mark, ip-version, dialer-proxy).

FieldTypeDefaultAllowed valuesDescription
namestring(required)<string>Unique proxy name.
serverstring(required)<host>Server hostname or IP.
portint(required)1-65535Server port.
keystring(required)<string>Pre-shared key. Must match the server; the AEAD seed and obfuscation tables are derived from it.
aead-methodstringchacha20-poly1305<aead cipher>AEAD cipher protecting the record layer.
padding-min*int10<int>Lower bound (bytes) of the random padding added to records.
padding-max*int30<int>Upper bound (bytes) of the random padding added to records.
table-typestringprefer_entropyprefer_ascii | prefer_entropy | up_ascii_down_entropy | up_entropy_down_asciiObfuscation byte-table orientation. The directional forms let the uplink and downlink use different tables.
enable-pure-downlink*booltruetrue | falseUse the lighter pure-downlink framing on the server-to-client direction.
http-mask*booltruetrue | falseWrap the connection in an HTTP(S) tunnel so it looks like ordinary web traffic. Enabled by default.
http-mask-modestringlegacylegacy | stream | poll | auto | wsHTTP masking transport. legacy is the classic upgrade; stream / poll / auto use real HTTP request/response tunnels; ws is a WebSocket tunnel.
http-mask-tlsboolfalsetrue | falseWrap the HTTP tunnel in TLS. Only applies to the stream / poll / auto modes.
http-mask-hoststring(unset)<domain[:port]>Host / SNI override sent on the masking tunnel.
path-rootstring(unset)<path>First-level path prefix for the HTTP tunnel endpoints.
http-mask-multiplexstringoffoff | auto | onTunnel reuse. auto reuses an h1/h2 tunnel; on opens a single multiplexed tunnel carrying multiple targets.
httpmask*SudokuHTTPMaskOptions(unset)<object>Structured HTTP-mask block; its keys override the flat http-mask-* fields above.
custom-tablestring(unset)<layout>Custom byte-layout pattern (e.g. xpxvvpvv) instead of a built-in table.
custom-tables[]string(unset)[<layout>]Rotation of custom byte-layout patterns. Overrides custom-table when non-empty.

Source: adapter/outbound/sudoku.go:30-50 · pinned at v1.19.27 (5184081)

httpmask

A structured alternative to the flat http-mask-* fields. When present, its keys take precedence.

FieldTypeDefaultAllowed valuesDescription
disableboolfalsetrue | falseDisable HTTP masking for this proxy.
modestringlegacylegacy | stream | poll | auto | wsHTTP masking transport (same values as http-mask-mode).
tlsboolfalsetrue | falseWrap the tunnel in TLS (stream / poll / auto only).
hoststring(unset)<domain[:port]>Host / SNI override.
path-rootstring(unset)<path>First-level path prefix for tunnel endpoints.
multiplexstringoffoff | auto | onTunnel reuse (same values as http-mask-multiplex).

Source: adapter/outbound/sudoku.go:52-59 · pinned at v1.19.27 (5184081)

Inbound

Entry under listeners: with type: sudoku. Embeds BaseOption (common listener fields: name, listen, port, …).

FieldTypeDefaultAllowed valuesDescription
keystring(required)<string>Pre-shared key. Clients must present the same value.
aead-methodstringchacha20-poly1305<aead cipher>AEAD cipher protecting the record layer.
padding-min*int10<int>Lower bound (bytes) of random record padding.
padding-max*int30<int>Upper bound (bytes) of random record padding.
table-typestringprefer_entropyprefer_ascii | prefer_entropy | up_ascii_down_entropy | up_entropy_down_asciiObfuscation byte-table orientation; must be compatible with the client.
handshake-timeout*int5<seconds>Maximum time allowed to complete the handshake before the connection is dropped.
enable-pure-downlink*booltruetrue | falseUse the lighter pure-downlink framing on the server-to-client direction.
custom-tablestring(unset)<layout>Custom byte-layout pattern (e.g. xpxvvpvv).
custom-tables[]string(unset)[<layout>]Rotation of custom byte-layout patterns. Overrides custom-table when non-empty.
disable-http-maskboolfalsetrue | falseTurn off the HTTP masking layer on the listener.
http-mask-modestringlegacylegacy | stream | poll | autoHTTP masking transport accepted from clients.
path-rootstring(unset)<path>First-level path prefix for the HTTP tunnel endpoints.
fallbackstring(unset)<host:port>Where to forward connections that fail the Sudoku handshake — point it at a decoy site for camouflage.
httpmask*SudokuHTTPMaskOptions(unset)<object>Structured HTTP-mask block; its keys override disable-http-mask / http-mask-mode / path-root.
mux-optionMuxOption(unset)<object>Multiplex settings (mihomo extension, not part of the standard Sudoku protocol).

Source: listener/inbound/sudoku.go:14-33 · pinned at v1.19.27 (5184081)

httpmask

FieldTypeDefaultAllowed valuesDescription
disableboolfalsetrue | falseDisable HTTP masking on the listener.
modestringlegacylegacy | stream | poll | autoHTTP masking transport (same values as http-mask-mode).
path-rootstring(unset)<path>First-level path prefix for tunnel endpoints.

Source: listener/inbound/sudoku.go:35-39 · pinned at v1.19.27 (5184081)

Examples

Minimal client outbound:

yaml
proxies:
  - name: sudoku-out
    type: sudoku
    server: example.com
    port: 443
    key: "your-pre-shared-key"

HTTP-masked over TLS, with multiplex reuse:

yaml
proxies:
  - name: sudoku-tls
    type: sudoku
    server: example.com
    port: 443
    key: "your-pre-shared-key"
    http-mask-mode: stream
    http-mask-tls: true
    http-mask-host: www.example.com
    path-root: /assets
    http-mask-multiplex: auto

Directional table with wider padding:

yaml
proxies:
  - name: sudoku-tuned
    type: sudoku
    server: 192.0.2.10
    port: 8443
    key: "your-pre-shared-key"
    table-type: up_ascii_down_entropy
    padding-min: 16
    padding-max: 64

Server-side listener with a camouflage fallback:

yaml
listeners:
  - name: sudoku-in
    type: sudoku
    listen: 0.0.0.0
    port: 443
    key: "your-pre-shared-key"
    http-mask-mode: stream
    fallback: 127.0.0.1:8080

Notes

  • key is mandatory and must be identical on both ends — both the AEAD seed and the obfuscation tables are derived from it.
  • table-type chooses how record bytes are shaped: prefer_ascii biases toward printable text, prefer_entropy (the default) toward random noise, and the up_*_down_* forms apply different tables per direction.
  • http-mask (on by default) wraps the stream so it resembles HTTP(S) traffic. http-mask-tls only matters for the stream / poll / auto modes; ws runs a WebSocket tunnel (client side only).
  • http-mask-multiplex: on carries multiple targets over a single multiplexed tunnel; auto reuses an existing h1/h2 tunnel when possible.
  • custom-table / custom-tables are advanced knobs for the byte layout; custom-tables rotates through several patterns and overrides custom-table when set.
  • Sudoku relays UDP via UDP-over-TCP, so it works for UDP-based traffic without a separate transport.
  • On the listener, fallback forwards connections that fail the Sudoku handshake to another address — typically a decoy web server, so probes see an innocuous site.

Cross-core notes

  • Sudoku is mihomo-only. Neither sing-box nor Xray-core implements it; reach for their own obfuscation transports (e.g. Shadowsocks plugins) if you need a comparable disguise there.

Source: adapter/outbound/sudoku.go:30-50 · v1.19.27 (5184081)

Source: listener/inbound/sudoku.go:14-33 · v1.19.27 (5184081)

Core Tutorial by Argsment