sing-box Integration
Relevant source files
The following files were used as context for generating this wiki page:The sing-box integration provides an automated mechanism to convert the project's existing Clash rule lists into a format compatible with the sing-box proxy client. This is achieved through the update_sing_box.py script, which processes .list files, transforms them into sing-box JSON rule-sets, and compiles them into the binary .srs format. This ensures that the curated rule definitions maintained for Clash can be seamlessly used with sing-box.
The entire toolchain starts from .yaml provider files, which are first converted to .list files by update_providers.py, and then subsequently processed for sing-box.
Conversion Process Overview
The system uses a multi-step process to convert human-readable YAML rule definitions into compiled sing-box rule-sets. The update_sing_box.py script is the central component for the final stage of this conversion.
The following diagram illustrates the complete data flow from the source YAML files to the final compiled sing-box rule-sets.
Core Conversion Script: update_sing_box.py
This script is responsible for finding Clash .list files and converting them into compiled sing-box .srs files.
Data Structures
The script defines two primary dataclasses, HeadlessRule and Rule, to model the structure of a sing-box JSON rule-set.
Sources: update_sing_box.py:14-55
The HeadlessRule class represents a collection of matchers for a single rule entry, while the Rule class is the top-level container for the rule-set file, which includes a version number and a list of HeadlessRule objects.
Sources: update_sing_box.py:14-59
File Discovery and Processing
The script traverses the Clash/ directory to find all files ending with the .list extension. It explicitly ignores the Clash/config and Clash/Providers directories during its search.
For each .list file found, it performs the following actions:
- Reads the content of the
.listfile line by line. - Parses each line to identify the rule type and its value.
- Appends the value to the corresponding attribute in a
HeadlessRuleinstance. - Creates a
Ruleobject containing the populatedHeadlessRule. - Serializes the
Ruleobject into a JSON string. - Writes the JSON to a temporary file in the
sing-box/directory. - Invokes the
sing-box rule-set compilecommand on the temporary JSON file to create a compiled.srsfile. - Deletes the temporary JSON file.
This sequence is illustrated in the diagram below.
Sources: update_sing_box.py:65-127
Rule Type Mapping
The script maps rule types from the Clash .list format to the fields of the HeadlessRule object. Comments and empty lines are ignored.
| Clash Rule Type | HeadlessRule Attribute | Description |
|---|---|---|
DOMAIN | domain | Matches a full domain name. |
DOMAIN-SUFFIX | domain_suffix | Matches a domain and all its subdomains. |
DOMAIN-KEYWORD | domain_keyword | Matches if a keyword is in the domain. |
DOMAIN-REGEX | domain_regex | Matches a domain against a regex pattern. |
IP-CIDR | ip_cidr | Matches a destination IP address/range. |
IP-CIDR6 | ip_cidr | Matches a destination IPv6 address/range. |
SOURCE-IP-CIDR | source_ip_cidr | Matches a source IP address/range. |
SRC-PORT | source_port/source_port_range | Matches a source port or port range. |
DST-PORT|port/port_range| Matches a destination port or port range. |
|PROCESS-NAME|process_name| Matches the process name. |
|PROCESS-PATH|process_path| Matches the full process path. |
Sources: update_sing_box.py:89-119
The port rules (SRC-PORT, DST-PORT) are further parsed to distinguish between single ports and ranges (e.g., 80 vs 80-90).
# Example of port parsing
elif line.split(",")[0] == "SRC-PORT":
items = line.split(",")[1].split("/")
for item in items:
if "-" in item:
headless_rule.append("source_port_range", ":".join(item.split("-")))
else:
headless_rule.append("source_port", item)
Sources: update_sing_box.py:103-109
Source and Output Formats
Source .list and .yaml Format
The conversion process originates from .yaml files located in Clash/Providers/. These files contain a payload section with a list of rules.
Example: Clash/Providers/Ruleset/Wikipedia.yaml
payload:
# 内容:Wikipedia 维基相关域名
# 数量:12条
- DOMAIN-SUFFIX,mediawiki.org
- DOMAIN-SUFFIX,wikibooks.org
- DOMAIN-SUFFIX,wikidata.org
Sources: Clash/Providers/Ruleset/Wikipedia.yaml:1-6
The update_providers.py script processes these YAML files into intermediate .list files, which are then used by update_sing_box.py. Other rule lists like ProxyGFWlist.yaml also follow this payload structure.
Sources: update_providers.py:14-20, Clash/Providers/ProxyGFWlist.yaml:1-5
Generated sing-box JSON Format
Before compilation, the script generates a JSON file that adheres to the sing-box rule-set format. Based on the Rule and HeadlessRule classes, a typical output for a simple rule list would look like this:
{
"version": 2,
"rules": [
{
"domain_suffix": [
"mediawiki.org",
"wikibooks.org",
"wikidata.org",
"wikileaks.org",
"wikimedia.org",
"wikinews.org",
"wikipedia.org",
"wikiquote.org",
"wikisource.org",
"wikiversity.org",
"wikivoyage.org",
"wiktionary.org"
]
}
]
}
This JSON structure is then passed to the sing-box command-line tool for compilation into the final .srs binary format.
Sources: update_sing_box.py:57-59, update_sing_box.py:121-123, Clash/Providers/Ruleset/Wikipedia.yaml