0bac50029a
Changelog: Profile-detail resources and include-all in custom groups
2005 lines
49 KiB
Dart
2005 lines
49 KiB
Dart
enum YamlKind { scalar, map, list }
|
|
|
|
/// Where a scalar's completions come from besides [YamlSchema.values].
|
|
enum YamlScalar {
|
|
plain,
|
|
rule,
|
|
rulePayload,
|
|
policy,
|
|
|
|
/// A policy the core looks up once the config is loaded, when GLOBAL exists.
|
|
outbound,
|
|
proxyProvider,
|
|
ruleProvider,
|
|
subRule,
|
|
}
|
|
|
|
/// The part of the mihomo configuration the editor completes against. A map
|
|
/// lists its [fields], plus [variants] keyed by the value of its `type`; a map
|
|
/// with free keys and a list both describe their members with [entry].
|
|
class YamlSchema {
|
|
final YamlKind kind;
|
|
final Map<String, YamlSchema> fields;
|
|
final Map<String, Map<String, YamlSchema>> variants;
|
|
final YamlSchema? entry;
|
|
final List<String> values;
|
|
final YamlScalar scalar;
|
|
|
|
const YamlSchema.scalar([this.values = const []])
|
|
: kind = YamlKind.scalar,
|
|
fields = const {},
|
|
variants = const {},
|
|
entry = null,
|
|
scalar = YamlScalar.plain;
|
|
|
|
const YamlSchema.of(this.scalar, [this.values = const []])
|
|
: kind = YamlKind.scalar,
|
|
fields = const {},
|
|
variants = const {},
|
|
entry = null;
|
|
|
|
const YamlSchema.map(this.fields, {this.variants = const {}})
|
|
: kind = YamlKind.map,
|
|
entry = null,
|
|
values = const [],
|
|
scalar = YamlScalar.plain;
|
|
|
|
const YamlSchema.dict(YamlSchema this.entry)
|
|
: kind = YamlKind.map,
|
|
fields = const {},
|
|
variants = const {},
|
|
values = const [],
|
|
scalar = YamlScalar.plain;
|
|
|
|
const YamlSchema.list(YamlSchema this.entry)
|
|
: kind = YamlKind.list,
|
|
fields = const {},
|
|
variants = const {},
|
|
values = const [],
|
|
scalar = YamlScalar.plain;
|
|
|
|
String get hint => switch (kind) {
|
|
YamlKind.map => '{…}',
|
|
YamlKind.list => '[…]',
|
|
YamlKind.scalar when values.length > 3 =>
|
|
'${values.take(3).join(' | ')} | …',
|
|
YamlKind.scalar => values.join(' | '),
|
|
};
|
|
|
|
/// The fields of a map whose `type` is [type], all variants when unknown.
|
|
Map<String, YamlSchema> fieldsFor(String? type) {
|
|
if (variants.isEmpty) {
|
|
return fields;
|
|
}
|
|
final variant = variants[type];
|
|
return {
|
|
...fields,
|
|
if (variant != null)
|
|
...variant
|
|
else
|
|
for (final fields in variants.values) ...fields,
|
|
};
|
|
}
|
|
}
|
|
|
|
enum EditorSchema {
|
|
config(clashConfigSchema),
|
|
dns(_dns, 'dns'),
|
|
ntp(_ntp, 'ntp'),
|
|
sniffer(_sniffer, 'sniffer'),
|
|
proxy(_proxy),
|
|
proxyGroup(_customProxyGroup, 'proxy-groups'),
|
|
rules(_rules),
|
|
shareLinks(_str),
|
|
provider(_providerFile);
|
|
|
|
final YamlSchema root;
|
|
|
|
/// The configuration key that holds this part, which a pasted fragment may
|
|
/// still carry.
|
|
final String? section;
|
|
|
|
const EditorSchema(this.root, [this.section]);
|
|
}
|
|
|
|
const _str = YamlSchema.scalar();
|
|
const _bool = YamlSchema.scalar(['true', 'false']);
|
|
const _strList = YamlSchema.list(_str);
|
|
const _policy = YamlSchema.of(YamlScalar.policy);
|
|
const _outbound = YamlSchema.of(YamlScalar.outbound);
|
|
const _headers = YamlSchema.dict(_strList);
|
|
|
|
const ruleTypes = {
|
|
'DOMAIN': 'example.com',
|
|
'DOMAIN-SUFFIX': 'example.com',
|
|
'DOMAIN-KEYWORD': 'example',
|
|
'DOMAIN-WILDCARD': '*.example.com',
|
|
'DOMAIN-REGEX': r'^.*\.example\.com$',
|
|
'GEOSITE': 'cn',
|
|
'IP-CIDR': '192.168.0.0/16',
|
|
'IP-CIDR6': 'fc00::/7',
|
|
'IP-SUFFIX': '8.8.8.8/24',
|
|
'IP-ASN': '13335',
|
|
'GEOIP': 'CN',
|
|
'SRC-GEOIP': 'CN',
|
|
'SRC-IP-ASN': '13335',
|
|
'SRC-IP-CIDR': '192.168.1.0/24',
|
|
'SRC-IP-SUFFIX': '192.168.1.1/24',
|
|
'DST-PORT': '443',
|
|
'SRC-PORT': '7777',
|
|
'IN-PORT': '7890',
|
|
'IN-TYPE': 'SOCKS/HTTP',
|
|
'IN-USER': 'user',
|
|
'IN-NAME': 'listener',
|
|
'REMATCH-NAME': 'rematch',
|
|
'PROCESS-NAME': 'curl',
|
|
'PROCESS-NAME-REGEX': '.*telegram.*',
|
|
'PROCESS-NAME-WILDCARD': '*telegram*',
|
|
'PROCESS-PATH': '/usr/bin/curl',
|
|
'PROCESS-PATH-REGEX': '.*bin/curl',
|
|
'PROCESS-PATH-WILDCARD': '/usr/bin/*',
|
|
'UID': '1001',
|
|
'NETWORK': 'udp',
|
|
'DSCP': '4',
|
|
'RULE-SET': 'provider',
|
|
'SUB-RULE': '(NETWORK,tcp)',
|
|
'AND': '((DOMAIN,…),(NETWORK,udp))',
|
|
'OR': '((DOMAIN,…),(NETWORK,udp))',
|
|
'NOT': '((DOMAIN,…))',
|
|
'MATCH': '',
|
|
};
|
|
|
|
/// Rules that take the options after their policy.
|
|
const noResolveRuleTypes = {
|
|
'IP-CIDR',
|
|
'IP-CIDR6',
|
|
'IP-SUFFIX',
|
|
'IP-ASN',
|
|
'GEOIP',
|
|
'RULE-SET',
|
|
};
|
|
|
|
const rulePayloadValues = {
|
|
'GEOSITE': [
|
|
'cn',
|
|
'geolocation-!cn',
|
|
'geolocation-cn',
|
|
'private',
|
|
'category-ads-all',
|
|
'gfw',
|
|
'google',
|
|
'youtube',
|
|
'github',
|
|
'microsoft',
|
|
'apple',
|
|
'openai',
|
|
'anthropic',
|
|
'telegram',
|
|
'twitter',
|
|
'facebook',
|
|
'netflix',
|
|
'spotify',
|
|
'steam',
|
|
'tiktok',
|
|
'bilibili',
|
|
],
|
|
'GEOIP': [
|
|
'CN',
|
|
'private',
|
|
'LAN',
|
|
'telegram',
|
|
'google',
|
|
'netflix',
|
|
'facebook',
|
|
'twitter',
|
|
'cloudflare',
|
|
],
|
|
'SRC-GEOIP': ['CN', 'private', 'LAN'],
|
|
'NETWORK': ['tcp', 'udp'],
|
|
'IN-TYPE': [
|
|
'HTTP',
|
|
'HTTPS',
|
|
'SOCKS4',
|
|
'SOCKS5',
|
|
'REDIR',
|
|
'TPROXY',
|
|
'TUN',
|
|
'INNER',
|
|
'SOCKS',
|
|
'SHADOWSOCKS',
|
|
'SNELL',
|
|
'VMESS',
|
|
'VLESS',
|
|
'TROJAN',
|
|
'TUNNEL',
|
|
'TUIC',
|
|
'HYSTERIA2',
|
|
'ANYTLS',
|
|
'MIERU',
|
|
'SUDOKU',
|
|
'TRUSTTUNNEL',
|
|
'SHADOWQUIC',
|
|
],
|
|
};
|
|
|
|
const ruleOptions = ['no-resolve', 'src'];
|
|
|
|
const _nameserver = YamlSchema.list(
|
|
YamlSchema.scalar([
|
|
'https://dns.alidns.com/dns-query',
|
|
'https://doh.pub/dns-query',
|
|
'https://dns.google/dns-query',
|
|
'https://cloudflare-dns.com/dns-query',
|
|
'tls://dns.alidns.com',
|
|
'tls://1.1.1.1',
|
|
'quic://dns.adguard-dns.com',
|
|
'223.5.5.5',
|
|
'119.29.29.29',
|
|
'8.8.8.8',
|
|
'1.1.1.1',
|
|
'system',
|
|
'dhcp://en0',
|
|
]),
|
|
);
|
|
|
|
const _clientFingerprint = YamlSchema.scalar([
|
|
'chrome',
|
|
'firefox',
|
|
'safari',
|
|
'ios',
|
|
'android',
|
|
'edge',
|
|
'360',
|
|
'qq',
|
|
'random',
|
|
'chrome120',
|
|
'firefox120',
|
|
'safari16',
|
|
'none',
|
|
]);
|
|
|
|
const _ipVersion = YamlSchema.scalar([
|
|
'dual',
|
|
'ipv4',
|
|
'ipv6',
|
|
'ipv4-prefer',
|
|
'ipv6-prefer',
|
|
]);
|
|
|
|
const _smux = YamlSchema.map({
|
|
'enabled': _bool,
|
|
'protocol': YamlSchema.scalar(['smux', 'yamux', 'h2mux']),
|
|
'max-connections': _str,
|
|
'min-streams': _str,
|
|
'max-streams': _str,
|
|
'padding': _bool,
|
|
'statistic': _bool,
|
|
'only-tcp': _bool,
|
|
'brutal-opts': YamlSchema.map({'enabled': _bool, 'up': _str, 'down': _str}),
|
|
});
|
|
|
|
const _congestionController = YamlSchema.scalar([
|
|
'bbr',
|
|
'cubic',
|
|
'new_reno',
|
|
'bbr_meta_v1',
|
|
'bbr_meta_v2',
|
|
]);
|
|
|
|
const _bbrProfile = YamlSchema.scalar([
|
|
'conservative',
|
|
'standard',
|
|
'aggressive',
|
|
]);
|
|
|
|
const _ech = YamlSchema.map({
|
|
'enable': _bool,
|
|
'config': _str,
|
|
'query-server-name': _str,
|
|
});
|
|
|
|
const _ipStack = YamlSchema.map({
|
|
'mode': YamlSchema.scalar(['auto', 'gvisor', 'mips']),
|
|
'congestion-controller': YamlSchema.scalar(['cubic', 'reno', 'bbr', 'bbr3']),
|
|
});
|
|
|
|
const _sudokuMultiplex = YamlSchema.scalar(['off', 'auto', 'on']);
|
|
|
|
const _sudokuHttpMaskMode = YamlSchema.scalar([
|
|
'legacy',
|
|
'stream',
|
|
'poll',
|
|
'auto',
|
|
'ws',
|
|
]);
|
|
|
|
const _openvpnCiphers = [
|
|
'AES-128-GCM',
|
|
'AES-192-GCM',
|
|
'AES-256-GCM',
|
|
'AES-128-CBC',
|
|
'AES-192-CBC',
|
|
'AES-256-CBC',
|
|
'CHACHA20-POLY1305',
|
|
];
|
|
|
|
const _proxyTypes = [
|
|
'ss',
|
|
'ssr',
|
|
'vmess',
|
|
'vless',
|
|
'trojan',
|
|
'anytls',
|
|
'hysteria2',
|
|
'hysteria',
|
|
'tuic',
|
|
'wireguard',
|
|
'socks5',
|
|
'http',
|
|
'snell',
|
|
'ssh',
|
|
'mieru',
|
|
'easytier',
|
|
'shadowquic',
|
|
'gost-relay',
|
|
'sudoku',
|
|
'masque',
|
|
'trusttunnel',
|
|
'openvpn',
|
|
'tailscale',
|
|
'zerotier',
|
|
'direct',
|
|
'dns',
|
|
'reject',
|
|
'rematch',
|
|
];
|
|
|
|
const _proxyCommon = {'name': _str, 'type': YamlSchema.scalar(_proxyTypes)};
|
|
|
|
const _server = {'server': _str, 'port': _str};
|
|
|
|
const _dial = {
|
|
'ip-version': _ipVersion,
|
|
'interface-name': _str,
|
|
'routing-mark': _str,
|
|
'dialer-proxy': _outbound,
|
|
};
|
|
|
|
/// Only the types that hand these to their dialer list them.
|
|
const _tcpDial = {'tfo': _bool, 'mptcp': _bool, ..._dial};
|
|
|
|
const _tls = {
|
|
'alpn': YamlSchema.list(YamlSchema.scalar(['h2', 'http/1.1', 'h3'])),
|
|
'skip-cert-verify': _bool,
|
|
'name-cert-verify': _str,
|
|
'fingerprint': _str,
|
|
'certificate': _str,
|
|
'private-key': _str,
|
|
'ech-opts': _ech,
|
|
};
|
|
|
|
/// vmess and vless switch TLS on with `tls` and name the server `servername`,
|
|
/// where the types that always use TLS call it `sni`.
|
|
const _optionalTls = {
|
|
'tls': _bool,
|
|
'servername': _str,
|
|
'client-fingerprint': _clientFingerprint,
|
|
..._tls,
|
|
};
|
|
|
|
const _sniTls = {'sni': _str, ..._tls};
|
|
|
|
const _tlsLayers = {
|
|
'shadow-tls-opts': YamlSchema.map({
|
|
'password': _str,
|
|
'version': YamlSchema.scalar(['1', '2', '3']),
|
|
}),
|
|
'restls-opts': YamlSchema.map({
|
|
'password': _str,
|
|
'version-hint': YamlSchema.scalar(['tls12', 'tls13']),
|
|
'restls-script': _str,
|
|
}),
|
|
'jls-opts': YamlSchema.map({'username': _str, 'password': _str}),
|
|
};
|
|
|
|
const _reality = {
|
|
'reality-opts': YamlSchema.map({
|
|
'public-key': _str,
|
|
'short-id': _str,
|
|
'support-x25519mlkem768': _bool,
|
|
}),
|
|
};
|
|
|
|
const _wsOpts = YamlSchema.map({
|
|
'path': _str,
|
|
'headers': YamlSchema.dict(_str),
|
|
'max-early-data': _str,
|
|
'early-data-header-name': _str,
|
|
'v2ray-http-upgrade': _bool,
|
|
'v2ray-http-upgrade-fast-open': _bool,
|
|
});
|
|
|
|
const _httpOpts = YamlSchema.map({
|
|
'method': YamlSchema.scalar(['GET', 'POST']),
|
|
'path': _strList,
|
|
'headers': _headers,
|
|
});
|
|
|
|
const _h2Opts = YamlSchema.map({'host': _strList, 'path': _str});
|
|
|
|
const _grpcOpts = YamlSchema.map({
|
|
'grpc-service-name': _str,
|
|
'grpc-user-agent': _str,
|
|
'ping-interval': _str,
|
|
'max-connections': _str,
|
|
'min-streams': _str,
|
|
'max-streams': _str,
|
|
});
|
|
|
|
const _mkcpOpts = YamlSchema.map(_mkcpFields);
|
|
|
|
const _mkcpFields = {
|
|
'mtu': _str,
|
|
'tti': _str,
|
|
'uplink-capacity': _str,
|
|
'downlink-capacity': _str,
|
|
'congestion': _bool,
|
|
'write-buffer': _str,
|
|
'read-buffer': _str,
|
|
'seed': _str,
|
|
'header': YamlSchema.scalar([
|
|
'none',
|
|
'srtp',
|
|
'utp',
|
|
'wechat-video',
|
|
'dtls',
|
|
'wireguard',
|
|
]),
|
|
};
|
|
|
|
const _vmessTransport = {
|
|
'network': YamlSchema.scalar([
|
|
'tcp',
|
|
'ws',
|
|
'http',
|
|
'h2',
|
|
'grpc',
|
|
'mekya',
|
|
'mkcp',
|
|
]),
|
|
'ws-opts': _wsOpts,
|
|
'http-opts': _httpOpts,
|
|
'h2-opts': _h2Opts,
|
|
'grpc-opts': _grpcOpts,
|
|
'mkcp-opts': _mkcpOpts,
|
|
'mekya-opts': YamlSchema.map({
|
|
'url': _str,
|
|
'h2-pool-size': _str,
|
|
'max-write-delay': _str,
|
|
'max-request-size': _str,
|
|
'polling-interval-initial': _str,
|
|
'max-write-size': _str,
|
|
'max-write-duration-ms': _str,
|
|
'max-simultaneous-write-connection': _str,
|
|
'packet-writing-buffer': _str,
|
|
'kcp': _mkcpOpts,
|
|
}),
|
|
'smux': _smux,
|
|
};
|
|
|
|
const _vlessTransport = {
|
|
'network': YamlSchema.scalar(['tcp', 'ws', 'http', 'h2', 'grpc', 'xhttp']),
|
|
'ws-opts': _wsOpts,
|
|
'http-opts': _httpOpts,
|
|
'h2-opts': _h2Opts,
|
|
'grpc-opts': _grpcOpts,
|
|
'xhttp-opts': YamlSchema.map({
|
|
'path': _str,
|
|
'host': _str,
|
|
'mode': YamlSchema.scalar(['auto', 'packet-up', 'stream-up', 'stream-one']),
|
|
'headers': YamlSchema.dict(_str),
|
|
'no-grpc-header': _bool,
|
|
'x-padding-bytes': _str,
|
|
'x-padding-obfs-mode': _bool,
|
|
'x-padding-key': _str,
|
|
'x-padding-header': _str,
|
|
'x-padding-placement': YamlSchema.scalar([
|
|
'queryInHeader',
|
|
'header',
|
|
'cookie',
|
|
'query',
|
|
]),
|
|
'x-padding-method': YamlSchema.scalar(['repeat-x', 'tokenish']),
|
|
'uplink-http-method': _str,
|
|
'session-placement': _xhttpPlacement,
|
|
'session-key': _str,
|
|
'session-table': YamlSchema.scalar([
|
|
'uuid',
|
|
'number',
|
|
'hex',
|
|
'HEX',
|
|
'alphabet',
|
|
'Alphabet',
|
|
'ALPHABET',
|
|
'base36',
|
|
'BASE36',
|
|
'Base62',
|
|
]),
|
|
'session-length': _str,
|
|
'seq-placement': _xhttpPlacement,
|
|
'seq-key': _str,
|
|
'uplink-data-placement': YamlSchema.scalar(['body', 'header', 'cookie']),
|
|
'uplink-data-key': _str,
|
|
'uplink-chunk-size': _str,
|
|
'sc-max-each-post-bytes': _str,
|
|
'sc-min-posts-interval-ms': _str,
|
|
'reuse-settings': _xhttpReuse,
|
|
'download-settings': YamlSchema.map({
|
|
..._server,
|
|
'path': _str,
|
|
'host': _str,
|
|
'headers': YamlSchema.dict(_str),
|
|
'reuse-settings': _xhttpReuse,
|
|
..._optionalTls,
|
|
..._tlsLayers,
|
|
..._reality,
|
|
}),
|
|
}),
|
|
'smux': _smux,
|
|
};
|
|
|
|
const _xhttpPlacement = YamlSchema.scalar([
|
|
'path',
|
|
'query',
|
|
'header',
|
|
'cookie',
|
|
]);
|
|
|
|
const _xhttpReuse = YamlSchema.map({
|
|
'max-concurrency': _str,
|
|
'max-connections': _str,
|
|
'c-max-reuse-times': _str,
|
|
'h-max-request-times': _str,
|
|
'h-max-reusable-secs': _str,
|
|
'h-keep-alive-period': _str,
|
|
});
|
|
|
|
const _trojanTransport = {
|
|
'network': YamlSchema.scalar(['tcp', 'ws', 'grpc']),
|
|
'ws-opts': _wsOpts,
|
|
'grpc-opts': _grpcOpts,
|
|
'smux': _smux,
|
|
};
|
|
|
|
const _aeadCiphers = [
|
|
'aes-128-gcm',
|
|
'aes-192-gcm',
|
|
'aes-256-gcm',
|
|
'chacha20-ietf-poly1305',
|
|
'xchacha20-ietf-poly1305',
|
|
];
|
|
|
|
const _ssCiphers = [
|
|
..._aeadCiphers,
|
|
'2022-blake3-aes-128-gcm',
|
|
'2022-blake3-aes-256-gcm',
|
|
'2022-blake3-chacha20-poly1305',
|
|
..._streamCiphers,
|
|
];
|
|
|
|
/// ShadowsocksR takes stream ciphers only.
|
|
const _streamCiphers = [
|
|
'aes-128-ctr',
|
|
'aes-192-ctr',
|
|
'aes-256-ctr',
|
|
'aes-128-cfb',
|
|
'aes-192-cfb',
|
|
'aes-256-cfb',
|
|
'rc4-md5',
|
|
'chacha20-ietf',
|
|
'xchacha20',
|
|
'chacha20',
|
|
'none',
|
|
];
|
|
|
|
const _kcptunFields = {
|
|
'key': _str,
|
|
'crypt': YamlSchema.scalar([
|
|
'aes',
|
|
'aes-128',
|
|
'aes-192',
|
|
'aes-128-gcm',
|
|
'salsa20',
|
|
'blowfish',
|
|
'twofish',
|
|
'cast5',
|
|
'3des',
|
|
'tea',
|
|
'xtea',
|
|
'xor',
|
|
'none',
|
|
'null',
|
|
]),
|
|
'conn': _str,
|
|
'autoexpire': _str,
|
|
'scavengettl': _str,
|
|
'mtu': _str,
|
|
'ratelimit': _str,
|
|
'sndwnd': _str,
|
|
'rcvwnd': _str,
|
|
'datashard': _str,
|
|
'parityshard': _str,
|
|
'dscp': _str,
|
|
'nocomp': _bool,
|
|
'acknodelay': _bool,
|
|
'nodelay': _str,
|
|
'interval': _str,
|
|
'resend': _str,
|
|
'nc': _str,
|
|
'sockbuf': _str,
|
|
'smuxver': YamlSchema.scalar(['1', '2']),
|
|
'smuxbuf': _str,
|
|
'framesize': _str,
|
|
'streambuf': _str,
|
|
'keepalive': _str,
|
|
};
|
|
|
|
const _pluginTls = {
|
|
'skip-cert-verify': _bool,
|
|
'name-cert-verify': _str,
|
|
'certificate': _str,
|
|
'private-key': _str,
|
|
};
|
|
|
|
const _tlsMirrorTime = YamlSchema.map({
|
|
'base-nanoseconds': _str,
|
|
'uniform-random-multiplier-nanoseconds': _str,
|
|
});
|
|
|
|
/// The ss plugins and snell obfs modes shadow-tls, restls and jls read these.
|
|
const _tlsLayerOpts = {
|
|
'username': _str,
|
|
'password': _str,
|
|
'version': YamlSchema.scalar(['1', '2', '3']),
|
|
'fingerprint': _str,
|
|
'version-hint': YamlSchema.scalar(['tls12', 'tls13']),
|
|
'restls-script': _str,
|
|
};
|
|
|
|
const _proxyVariants = <String, Map<String, YamlSchema>>{
|
|
'ss': {
|
|
..._server,
|
|
'udp': _bool,
|
|
..._tcpDial,
|
|
'cipher': YamlSchema.scalar(_ssCiphers),
|
|
'password': _str,
|
|
'udp-over-tcp': _bool,
|
|
'udp-over-tcp-version': YamlSchema.scalar(['1', '2']),
|
|
'client-fingerprint': _clientFingerprint,
|
|
'plugin': YamlSchema.scalar([
|
|
'obfs',
|
|
'v2ray-plugin',
|
|
'gost-plugin',
|
|
'shadow-tls',
|
|
'restls',
|
|
'jls',
|
|
'kcptun',
|
|
]),
|
|
'plugin-opts': YamlSchema.map({
|
|
'mode': YamlSchema.scalar([
|
|
'http',
|
|
'tls',
|
|
'websocket',
|
|
'normal',
|
|
'fast',
|
|
'fast2',
|
|
'fast3',
|
|
'manual',
|
|
]),
|
|
'host': _str,
|
|
'path': _str,
|
|
'tls': _bool,
|
|
'headers': YamlSchema.dict(_str),
|
|
'mux': _bool,
|
|
'v2ray-http-upgrade': _bool,
|
|
'v2ray-http-upgrade-fast-open': _bool,
|
|
'alpn': _strList,
|
|
'ech-opts': _ech,
|
|
..._pluginTls,
|
|
..._tlsLayerOpts,
|
|
..._kcptunFields,
|
|
}),
|
|
'smux': _smux,
|
|
},
|
|
'ssr': {
|
|
..._server,
|
|
'udp': _bool,
|
|
..._tcpDial,
|
|
'cipher': YamlSchema.scalar(_streamCiphers),
|
|
'password': _str,
|
|
'obfs': YamlSchema.scalar([
|
|
'plain',
|
|
'http_simple',
|
|
'http_post',
|
|
'random_head',
|
|
'tls1.2_ticket_auth',
|
|
'tls1.2_ticket_fastauth',
|
|
]),
|
|
'obfs-param': _str,
|
|
'protocol': YamlSchema.scalar([
|
|
'origin',
|
|
'auth_sha1_v4',
|
|
'auth_aes128_md5',
|
|
'auth_aes128_sha1',
|
|
'auth_chain_a',
|
|
'auth_chain_b',
|
|
]),
|
|
'protocol-param': _str,
|
|
},
|
|
'vmess': {
|
|
..._server,
|
|
'udp': _bool,
|
|
..._tcpDial,
|
|
'uuid': _str,
|
|
'alterId': _str,
|
|
'cipher': YamlSchema.scalar([
|
|
'auto',
|
|
'none',
|
|
'zero',
|
|
'aes-128-gcm',
|
|
'chacha20-poly1305',
|
|
'aes-128-cfb',
|
|
]),
|
|
'packet-encoding': YamlSchema.scalar(['packetaddr', 'xudp']),
|
|
'global-padding': _bool,
|
|
'authenticated-length': _bool,
|
|
..._optionalTls,
|
|
..._tlsLayers,
|
|
..._reality,
|
|
'tlsmirror-opts': YamlSchema.map({
|
|
'primary-key': _str,
|
|
'explicit-nonce-ciphersuites': _strList,
|
|
'defer-instance-derived-write-time': _tlsMirrorTime,
|
|
'transport-layer-padding': YamlSchema.map({'enabled': _bool}),
|
|
'connection-enrolment': YamlSchema.map({
|
|
'primary-ingress-outbound': _str,
|
|
'primary-egress-outbound': _str,
|
|
}),
|
|
'embedded-traffic-generator': YamlSchema.map({
|
|
'steps': YamlSchema.list(
|
|
YamlSchema.map({
|
|
'name': _str,
|
|
'host': _str,
|
|
'path': _str,
|
|
'method': _str,
|
|
'headers': YamlSchema.list(
|
|
YamlSchema.map({'name': _str, 'value': _str, 'values': _strList}),
|
|
),
|
|
'next-step': YamlSchema.list(
|
|
YamlSchema.map({'weight': _str, 'goto-location': _str}),
|
|
),
|
|
'connection-ready': _bool,
|
|
'connection-recall-exit': _bool,
|
|
'wait-time': _tlsMirrorTime,
|
|
'h2-do-not-wait-for-download-finish': _bool,
|
|
}),
|
|
),
|
|
}),
|
|
'sequence-watermarking-enabled': _bool,
|
|
}),
|
|
..._vmessTransport,
|
|
},
|
|
'vless': {
|
|
..._server,
|
|
'udp': _bool,
|
|
..._tcpDial,
|
|
'uuid': _str,
|
|
'flow': YamlSchema.scalar(['xtls-rprx-vision']),
|
|
'encryption': _str,
|
|
'packet-encoding': YamlSchema.scalar(['packetaddr', 'xudp']),
|
|
..._optionalTls,
|
|
..._tlsLayers,
|
|
..._reality,
|
|
..._vlessTransport,
|
|
},
|
|
'trojan': {
|
|
..._server,
|
|
'udp': _bool,
|
|
..._tcpDial,
|
|
'password': _str,
|
|
'ss-opts': YamlSchema.map({
|
|
'enabled': _bool,
|
|
'method': YamlSchema.scalar(_aeadCiphers),
|
|
'password': _str,
|
|
}),
|
|
'client-fingerprint': _clientFingerprint,
|
|
..._sniTls,
|
|
..._tlsLayers,
|
|
..._reality,
|
|
..._trojanTransport,
|
|
},
|
|
'anytls': {
|
|
..._server,
|
|
'udp': _bool,
|
|
..._tcpDial,
|
|
'password': _str,
|
|
'idle-session-check-interval': _str,
|
|
'idle-session-timeout': _str,
|
|
'min-idle-session': _str,
|
|
'client-metadata': _str,
|
|
'disable-reuse': _bool,
|
|
'client-fingerprint': _clientFingerprint,
|
|
..._sniTls,
|
|
..._tlsLayers,
|
|
},
|
|
'hysteria2': {
|
|
..._server,
|
|
..._dial,
|
|
'ports': _str,
|
|
'password': _str,
|
|
'up': _str,
|
|
'down': _str,
|
|
'obfs': YamlSchema.scalar(['salamander', 'gecko']),
|
|
'obfs-password': _str,
|
|
'obfs-min-packet-size': _str,
|
|
'obfs-max-packet-size': _str,
|
|
'hop-interval': _str,
|
|
'bbr-profile': _bbrProfile,
|
|
'cwnd': _str,
|
|
'udp-mtu': _str,
|
|
'handshake-timeout': _str,
|
|
'initial-stream-receive-window': _str,
|
|
'max-stream-receive-window': _str,
|
|
'initial-connection-receive-window': _str,
|
|
'max-connection-receive-window': _str,
|
|
'realm-opts': YamlSchema.map({
|
|
'enable': _bool,
|
|
'server-url': _str,
|
|
'token': _str,
|
|
'realm-id': _str,
|
|
'stun-servers': _strList,
|
|
'sni': _str,
|
|
'alpn': _strList,
|
|
'fingerprint': _str,
|
|
..._pluginTls,
|
|
}),
|
|
..._sniTls,
|
|
},
|
|
'hysteria': {
|
|
..._server,
|
|
..._dial,
|
|
'ports': _str,
|
|
'auth-str': _str,
|
|
'auth': _str,
|
|
'protocol': YamlSchema.scalar(['udp', 'wechat-video', 'faketcp']),
|
|
'obfs': _str,
|
|
'up': _str,
|
|
'down': _str,
|
|
'recv-window-conn': _str,
|
|
'recv-window': _str,
|
|
'disable-mtu-discovery': _bool,
|
|
'fast-open': _bool,
|
|
'hop-interval': _str,
|
|
..._sniTls,
|
|
},
|
|
'tuic': {
|
|
..._server,
|
|
..._dial,
|
|
'uuid': _str,
|
|
'password': _str,
|
|
'token': _str,
|
|
'ip': _str,
|
|
'heartbeat-interval': _str,
|
|
'disable-sni': _bool,
|
|
'reduce-rtt': _bool,
|
|
'request-timeout': _str,
|
|
'udp-relay-mode': YamlSchema.scalar(['native', 'quic']),
|
|
'congestion-controller': _congestionController,
|
|
'bbr-profile': _bbrProfile,
|
|
'max-udp-relay-packet-size': _str,
|
|
'fast-open': _bool,
|
|
'max-open-streams': _str,
|
|
'cwnd': _str,
|
|
'recv-window-conn': _str,
|
|
'recv-window': _str,
|
|
'disable-mtu-discovery': _bool,
|
|
'max-datagram-frame-size': _str,
|
|
'udp-over-stream': _bool,
|
|
'udp-over-stream-version': YamlSchema.scalar(['1', '2']),
|
|
..._sniTls,
|
|
},
|
|
'wireguard': {
|
|
..._server,
|
|
'udp': _bool,
|
|
..._dial,
|
|
'ip': _str,
|
|
'ipv6': _str,
|
|
'private-key': _str,
|
|
'public-key': _str,
|
|
'pre-shared-key': _str,
|
|
'reserved': _strList,
|
|
'mtu': _str,
|
|
'workers': _str,
|
|
'refresh-server-ip-interval': _str,
|
|
'ip-stack': _ipStack,
|
|
'allowed-ips': _strList,
|
|
'persistent-keepalive': _str,
|
|
'remote-dns-resolve': _bool,
|
|
'dns': _strList,
|
|
'peers': YamlSchema.list(
|
|
YamlSchema.map({
|
|
'server': _str,
|
|
'port': _str,
|
|
'public-key': _str,
|
|
'pre-shared-key': _str,
|
|
'reserved': _strList,
|
|
'allowed-ips': _strList,
|
|
}),
|
|
),
|
|
'amnezia-wg-option': YamlSchema.map({
|
|
'jc': _str,
|
|
'jmin': _str,
|
|
'jmax': _str,
|
|
's1': _str,
|
|
's2': _str,
|
|
'h1': _str,
|
|
'h2': _str,
|
|
'h3': _str,
|
|
'h4': _str,
|
|
'version': _str,
|
|
's3': _str,
|
|
's4': _str,
|
|
'i1': _str,
|
|
'i2': _str,
|
|
'i3': _str,
|
|
'i4': _str,
|
|
'i5': _str,
|
|
'header-protection-key': _str,
|
|
'content-padding-addition': _str,
|
|
'rekey-after-time': _str,
|
|
'rekey-timeout': _str,
|
|
'reject-after-time': _str,
|
|
'keepalive-timeout': _str,
|
|
'max-handshake-attempts': _str,
|
|
'random-trailers': _bool,
|
|
'disable-cookies': _bool,
|
|
}),
|
|
},
|
|
'socks5': {
|
|
..._server,
|
|
'udp': _bool,
|
|
..._tcpDial,
|
|
'username': _str,
|
|
'password': _str,
|
|
'tls': _bool,
|
|
'fingerprint': _str,
|
|
'skip-cert-verify': _bool,
|
|
'name-cert-verify': _str,
|
|
'certificate': _str,
|
|
'private-key': _str,
|
|
},
|
|
'http': {
|
|
..._server,
|
|
..._tcpDial,
|
|
'username': _str,
|
|
'password': _str,
|
|
'tls': _bool,
|
|
'sni': _str,
|
|
'fingerprint': _str,
|
|
'skip-cert-verify': _bool,
|
|
'name-cert-verify': _str,
|
|
'certificate': _str,
|
|
'private-key': _str,
|
|
'headers': YamlSchema.dict(_str),
|
|
},
|
|
'snell': {
|
|
..._server,
|
|
'udp': _bool,
|
|
..._tcpDial,
|
|
'psk': _str,
|
|
'version': YamlSchema.scalar(['1', '2', '3', '4', '5']),
|
|
'reuse': _bool,
|
|
'client-fingerprint': _clientFingerprint,
|
|
'obfs-opts': YamlSchema.map({
|
|
'mode': YamlSchema.scalar(['http', 'tls', 'shadow-tls', 'restls', 'jls']),
|
|
'host': _str,
|
|
'alpn': _strList,
|
|
..._pluginTls,
|
|
..._tlsLayerOpts,
|
|
}),
|
|
},
|
|
'ssh': {
|
|
..._server,
|
|
..._tcpDial,
|
|
'username': _str,
|
|
'password': _str,
|
|
'private-key': _str,
|
|
'private-key-passphrase': _str,
|
|
'host-key': _strList,
|
|
'host-key-algorithms': _strList,
|
|
},
|
|
'mieru': {
|
|
..._server,
|
|
'udp': _bool,
|
|
..._tcpDial,
|
|
'port-range': _str,
|
|
'transport': YamlSchema.scalar(['TCP', 'UDP']),
|
|
'username': _str,
|
|
'password': _str,
|
|
'multiplexing': YamlSchema.scalar([
|
|
'MULTIPLEXING_DEFAULT',
|
|
'MULTIPLEXING_OFF',
|
|
'MULTIPLEXING_LOW',
|
|
'MULTIPLEXING_MIDDLE',
|
|
'MULTIPLEXING_HIGH',
|
|
]),
|
|
'handshake-mode': YamlSchema.scalar([
|
|
'HANDSHAKE_DEFAULT',
|
|
'HANDSHAKE_STANDARD',
|
|
'HANDSHAKE_NO_WAIT',
|
|
]),
|
|
'traffic-pattern': _str,
|
|
},
|
|
'easytier': {
|
|
'udp': _bool,
|
|
..._dial,
|
|
'network-name': _str,
|
|
'network-secret': _str,
|
|
'hostname': _str,
|
|
'ipv4': _str,
|
|
'dhcp': _bool,
|
|
'peers': _strList,
|
|
'listeners': _strList,
|
|
'no-listener': _bool,
|
|
'mapped-listeners': _strList,
|
|
'exit-nodes': _strList,
|
|
'proxy-networks': _strList,
|
|
'instance-name': _str,
|
|
'state-dir': _str,
|
|
'accept-dns': _bool,
|
|
'enable-exit-node': _bool,
|
|
'enable-encryption': _bool,
|
|
'encryption-algorithm': _str,
|
|
'private-mode': _bool,
|
|
'latency-first': _bool,
|
|
'disable-p2p': _bool,
|
|
'enable-kcp-proxy': _bool,
|
|
'disable-kcp-input': _bool,
|
|
'enable-quic-proxy': _bool,
|
|
'disable-quic-input': _bool,
|
|
'mtu': _str,
|
|
'tld-dns-zone': _str,
|
|
'secure-mode': _bool,
|
|
'local-private-key': _str,
|
|
'local-public-key': _str,
|
|
},
|
|
'shadowquic': {
|
|
..._server,
|
|
..._dial,
|
|
'username': _str,
|
|
'password': _str,
|
|
'sni': _str,
|
|
'alpn': _strList,
|
|
'quic-versions': YamlSchema.list(YamlSchema.scalar(['v1', 'v2'])),
|
|
'udp-over-stream': _bool,
|
|
'zero-rtt': _bool,
|
|
'disable-mtu-discovery': _bool,
|
|
'congestion-controller': _congestionController,
|
|
'bbr-profile': _bbrProfile,
|
|
'cwnd': _str,
|
|
'up': _str,
|
|
'down': _str,
|
|
'keep-alive-interval': _str,
|
|
'recv-window-conn': _str,
|
|
'recv-window': _str,
|
|
'max-datagram-frame-size': _str,
|
|
'max-open-streams': _str,
|
|
},
|
|
'gost-relay': {
|
|
..._server,
|
|
'udp': _bool,
|
|
..._tcpDial,
|
|
'username': _str,
|
|
'password': _str,
|
|
'forward': _bool,
|
|
'mux': _bool,
|
|
'tls': _bool,
|
|
'sni': _str,
|
|
'skip-cert-verify': _bool,
|
|
'name-cert-verify': _str,
|
|
'fingerprint': _str,
|
|
'certificate': _str,
|
|
'private-key': _str,
|
|
'client-fingerprint': _clientFingerprint,
|
|
},
|
|
'sudoku': {
|
|
..._server,
|
|
..._tcpDial,
|
|
'key': _str,
|
|
'aead-method': YamlSchema.scalar([
|
|
'aes-128-gcm',
|
|
'chacha20-poly1305',
|
|
'none',
|
|
]),
|
|
'padding-min': _str,
|
|
'padding-max': _str,
|
|
'table-type': YamlSchema.scalar([
|
|
'prefer_ascii',
|
|
'prefer_entropy',
|
|
'up_ascii_down_entropy',
|
|
'up_entropy_down_ascii',
|
|
]),
|
|
'custom-table': _str,
|
|
'custom-tables': _strList,
|
|
'enable-pure-downlink': _bool,
|
|
'multiplex': _sudokuMultiplex,
|
|
'http-mask': _bool,
|
|
'http-mask-mode': _sudokuHttpMaskMode,
|
|
'http-mask-tls': _bool,
|
|
'http-mask-host': _str,
|
|
'path-root': _str,
|
|
'httpmask': YamlSchema.map({
|
|
'disable': _bool,
|
|
'mode': _sudokuHttpMaskMode,
|
|
'tls': _bool,
|
|
'host': _str,
|
|
'path-root': _str,
|
|
'multiplex': _sudokuMultiplex,
|
|
}),
|
|
},
|
|
'masque': {
|
|
..._server,
|
|
'udp': _bool,
|
|
..._dial,
|
|
'private-key': _str,
|
|
'public-key': _str,
|
|
'ip': _str,
|
|
'ipv6': _str,
|
|
'uri': _str,
|
|
'sni': _str,
|
|
'skip-cert-verify': _bool,
|
|
'network': YamlSchema.scalar(['h2', 'h3-l4proxy']),
|
|
'congestion-controller': _congestionController,
|
|
'bbr-profile': _bbrProfile,
|
|
'cwnd': _str,
|
|
'mtu': _str,
|
|
'handshake-timeout': _str,
|
|
'ip-stack': _ipStack,
|
|
'remote-dns-resolve': _bool,
|
|
'dns': _strList,
|
|
},
|
|
'trusttunnel': {
|
|
..._server,
|
|
'udp': _bool,
|
|
..._tcpDial,
|
|
'username': _str,
|
|
'password': _str,
|
|
'sni': _str,
|
|
'alpn': _strList,
|
|
'skip-cert-verify': _bool,
|
|
'name-cert-verify': _str,
|
|
'fingerprint': _str,
|
|
'certificate': _str,
|
|
'private-key': _str,
|
|
'client-fingerprint': _clientFingerprint,
|
|
'ech-opts': _ech,
|
|
'quic': _bool,
|
|
'congestion-controller': _congestionController,
|
|
'bbr-profile': _bbrProfile,
|
|
'cwnd': _str,
|
|
'health-check': _bool,
|
|
'max-connections': _str,
|
|
'min-streams': _str,
|
|
'max-streams': _str,
|
|
},
|
|
'openvpn': {
|
|
..._server,
|
|
'udp': _bool,
|
|
..._tcpDial,
|
|
'proto': YamlSchema.scalar(['udp', 'tcp']),
|
|
'dev': YamlSchema.scalar(['tun']),
|
|
'ca': _str,
|
|
'cert': _str,
|
|
'key': _str,
|
|
'tls-auth': _str,
|
|
'tls-crypt': _str,
|
|
'tls-crypt-v2': _str,
|
|
'key-direction': YamlSchema.scalar(['0', '1']),
|
|
'username': _str,
|
|
'password': _str,
|
|
'cipher': YamlSchema.scalar(_openvpnCiphers),
|
|
'data-ciphers': YamlSchema.list(YamlSchema.scalar(_openvpnCiphers)),
|
|
'data-ciphers-fallback': YamlSchema.scalar(_openvpnCiphers),
|
|
'auth': YamlSchema.scalar(['MD5', 'SHA1', 'SHA256', 'SHA384', 'SHA512']),
|
|
'comp-lzo': YamlSchema.scalar(['yes', 'adaptive']),
|
|
'peer-info': YamlSchema.dict(_str),
|
|
'ping': _str,
|
|
'ping-restart': _str,
|
|
'tran-window': _str,
|
|
'handshake-timeout': _str,
|
|
'mtu': _str,
|
|
'ip-stack': _ipStack,
|
|
'remote-dns-resolve': _bool,
|
|
'dns': _strList,
|
|
},
|
|
'tailscale': {
|
|
'udp': _bool,
|
|
..._dial,
|
|
'hostname': _str,
|
|
'auth-key': _str,
|
|
'control-url': _str,
|
|
'state-dir': _str,
|
|
'ephemeral': _bool,
|
|
'accept-routes': _bool,
|
|
'exit-node': _str,
|
|
'exit-node-allow-lan-access': _bool,
|
|
},
|
|
'zerotier': {
|
|
'udp': _bool,
|
|
..._dial,
|
|
'network': _str,
|
|
'state-dir': _str,
|
|
'identity-secret': _str,
|
|
'planet': _str,
|
|
'orbit': YamlSchema.list(YamlSchema.map({'world': _str, 'seed': _str})),
|
|
'mtu': _str,
|
|
'physical-mtu': _str,
|
|
'primary-port': _str,
|
|
'secondary-port': _str,
|
|
'low-bandwidth': _bool,
|
|
'encrypted-hello': _bool,
|
|
'tcp-fallback-mode': YamlSchema.scalar(['auto', 'force', 'disable']),
|
|
'tcp-fallback-relay': _str,
|
|
'remote-trace-target': _str,
|
|
'remote-trace-level': _str,
|
|
'ip-stack': _ipStack,
|
|
'remote-dns-resolve': _bool,
|
|
'dns': _strList,
|
|
},
|
|
'direct': {
|
|
'tfo': _bool,
|
|
'mptcp': _bool,
|
|
'ip-version': _ipVersion,
|
|
'interface-name': _str,
|
|
'routing-mark': _str,
|
|
},
|
|
'dns': {},
|
|
'reject': {},
|
|
'rematch': {
|
|
'target-rematch-name': _str,
|
|
'target-sub-rule': YamlSchema.of(YamlScalar.subRule),
|
|
},
|
|
};
|
|
|
|
const _proxy = YamlSchema.map(_proxyCommon, variants: _proxyVariants);
|
|
|
|
const _healthCheck = YamlSchema.map({
|
|
'enable': _bool,
|
|
'url': YamlSchema.scalar(['https://www.gstatic.com/generate_204']),
|
|
'interval': _str,
|
|
'timeout': _str,
|
|
'lazy': _bool,
|
|
'expected-status': _str,
|
|
});
|
|
|
|
const _proxyGroupFields = {
|
|
'name': _str,
|
|
'type': YamlSchema.scalar(['select', 'url-test', 'fallback', 'load-balance']),
|
|
'proxies': YamlSchema.list(_policy),
|
|
'use': YamlSchema.list(YamlSchema.of(YamlScalar.proxyProvider)),
|
|
'use-position': YamlSchema.dict(_str),
|
|
'url': YamlSchema.scalar(['https://www.gstatic.com/generate_204']),
|
|
'interval': _str,
|
|
'lazy': _bool,
|
|
'timeout': _str,
|
|
'max-failed-times': _str,
|
|
'empty-fallback': _policy,
|
|
'expected-status': _str,
|
|
'filter': _str,
|
|
'exclude-filter': _str,
|
|
'exclude-type': _str,
|
|
'disable-udp': _bool,
|
|
'hidden': _bool,
|
|
'icon': _str,
|
|
};
|
|
|
|
const _proxyGroupVariants = {
|
|
'select': {'default-selected': _policy},
|
|
'url-test': {'tolerance': _str},
|
|
'load-balance': {
|
|
'strategy': YamlSchema.scalar([
|
|
'consistent-hashing',
|
|
'round-robin',
|
|
'sticky-sessions',
|
|
]),
|
|
'hash-key': YamlSchema.scalar(['in-user']),
|
|
},
|
|
};
|
|
|
|
const _proxyGroup = YamlSchema.map({
|
|
..._proxyGroupFields,
|
|
'include-all': _bool,
|
|
'include-all-proxies': _bool,
|
|
'include-all-providers': _bool,
|
|
}, variants: _proxyGroupVariants);
|
|
|
|
const _customProxyGroup = YamlSchema.map(
|
|
_proxyGroupFields,
|
|
variants: _proxyGroupVariants,
|
|
);
|
|
|
|
const _providerType = YamlSchema.scalar(['http', 'file', 'inline']);
|
|
|
|
const _proxyProvider = YamlSchema.map({
|
|
'type': _providerType,
|
|
'url': _str,
|
|
'path': _str,
|
|
'interval': _str,
|
|
'proxy': _outbound,
|
|
'dialer-proxy': _outbound,
|
|
'size-limit': _str,
|
|
'header': _headers,
|
|
'age-secret-key': _str,
|
|
'health-check': _healthCheck,
|
|
'override': YamlSchema.map({
|
|
'tfo': _bool,
|
|
'mptcp': _bool,
|
|
'udp': _bool,
|
|
'udp-over-tcp': _bool,
|
|
'up': _str,
|
|
'down': _str,
|
|
'skip-cert-verify': _bool,
|
|
'name-cert-verify': _str,
|
|
'dialer-proxy': _outbound,
|
|
'interface-name': _str,
|
|
'routing-mark': _str,
|
|
'ip-version': _ipVersion,
|
|
'additional-prefix': _str,
|
|
'additional-suffix': _str,
|
|
'proxy-name': YamlSchema.list(
|
|
YamlSchema.map({'pattern': _str, 'target': _str}),
|
|
),
|
|
'override-expr': _strList,
|
|
}),
|
|
'filter': _str,
|
|
'exclude-filter': _str,
|
|
'exclude-type': _str,
|
|
'payload': YamlSchema.list(_proxy),
|
|
});
|
|
|
|
const _ruleProvider = YamlSchema.map({
|
|
'type': _providerType,
|
|
'behavior': YamlSchema.scalar(['domain', 'ipcidr', 'classical']),
|
|
'format': YamlSchema.scalar(['yaml', 'text', 'mrs']),
|
|
'url': _str,
|
|
'path': _str,
|
|
'interval': _str,
|
|
'proxy': _outbound,
|
|
'size-limit': _str,
|
|
'header': _headers,
|
|
'path-in-bundle': _str,
|
|
'payload': YamlSchema.list(YamlSchema.of(YamlScalar.rulePayload)),
|
|
});
|
|
|
|
const _rules = YamlSchema.list(YamlSchema.of(YamlScalar.rule));
|
|
|
|
const _dns = YamlSchema.map({
|
|
'enable': _bool,
|
|
'listen': YamlSchema.scalar(['0.0.0.0:1053']),
|
|
'listen-routing-mark': _str,
|
|
'ipv6': _bool,
|
|
'ipv6-timeout': _str,
|
|
'prefer-h3': _bool,
|
|
'cache-algorithm': YamlSchema.scalar(['lru', 'arc']),
|
|
'cache-max-size': _str,
|
|
'use-hosts': _bool,
|
|
'use-system-hosts': _bool,
|
|
'respect-rules': _bool,
|
|
'enhanced-mode': YamlSchema.scalar(['fake-ip', 'redir-host', 'normal']),
|
|
'fake-ip-range': YamlSchema.scalar(['198.18.0.1/16']),
|
|
'fake-ip-range6': _str,
|
|
'fake-ip-filter': _strList,
|
|
'fake-ip-filter-mode': YamlSchema.scalar(['blacklist', 'whitelist', 'rule']),
|
|
'fake-ip-ttl': _str,
|
|
'default-nameserver': _nameserver,
|
|
'nameserver': _nameserver,
|
|
'fallback': _nameserver,
|
|
'fallback-lazy-query': _bool,
|
|
'proxy-server-nameserver': _nameserver,
|
|
'direct-nameserver': _nameserver,
|
|
'direct-nameserver-follow-policy': _bool,
|
|
'nameserver-policy': YamlSchema.dict(_nameserver),
|
|
'proxy-server-nameserver-policy': YamlSchema.dict(_nameserver),
|
|
'fallback-filter': YamlSchema.map({
|
|
'geoip': _bool,
|
|
'geoip-code': YamlSchema.scalar(['CN']),
|
|
'geosite': _strList,
|
|
'ipcidr': _strList,
|
|
'domain': _strList,
|
|
}),
|
|
});
|
|
|
|
const _ntp = YamlSchema.map({
|
|
'enable': _bool,
|
|
'write-to-system': _bool,
|
|
'server': YamlSchema.scalar(['time.apple.com', 'ntp.aliyun.com']),
|
|
'port': _str,
|
|
'interval': _str,
|
|
'dialer-proxy': _outbound,
|
|
});
|
|
|
|
const _tun = YamlSchema.map({'enable': _bool, ..._tunFields});
|
|
|
|
const _tunFields = {
|
|
'stack': YamlSchema.scalar(['mixed', 'system', 'gvisor', 'mips']),
|
|
'device': _str,
|
|
'dns-hijack': YamlSchema.list(YamlSchema.scalar(['any:53', 'tcp://any:53'])),
|
|
'auto-route': _bool,
|
|
'auto-redirect': _bool,
|
|
'auto-detect-interface': _bool,
|
|
'strict-route': _bool,
|
|
'mtu': _str,
|
|
'gso': _bool,
|
|
'gso-max-size': _str,
|
|
'udp-timeout': _str,
|
|
'endpoint-independent-nat': _bool,
|
|
'disable-icmp-forwarding': _bool,
|
|
'iproute2-table-index': _str,
|
|
'iproute2-rule-index': _str,
|
|
'route-address': _strList,
|
|
'route-exclude-address': _strList,
|
|
'route-address-set': YamlSchema.list(YamlSchema.of(YamlScalar.ruleProvider)),
|
|
'route-exclude-address-set': YamlSchema.list(
|
|
YamlSchema.of(YamlScalar.ruleProvider),
|
|
),
|
|
'include-interface': _strList,
|
|
'exclude-interface': _strList,
|
|
'include-uid': _strList,
|
|
'include-uid-range': _strList,
|
|
'exclude-uid': _strList,
|
|
'exclude-uid-range': _strList,
|
|
'include-android-user': _strList,
|
|
'include-package': _strList,
|
|
'exclude-package': _strList,
|
|
'inet6-address': _strList,
|
|
'inet4-route-address': _strList,
|
|
'inet6-route-address': _strList,
|
|
'inet4-route-exclude-address': _strList,
|
|
'inet6-route-exclude-address': _strList,
|
|
'loopback-address': _strList,
|
|
'auto-redirect-input-mark': _str,
|
|
'auto-redirect-output-mark': _str,
|
|
'auto-redirect-iproute2-fallback-rule-index': _str,
|
|
'exclude-src-port': _strList,
|
|
'exclude-src-port-range': _strList,
|
|
'exclude-dst-port': _strList,
|
|
'exclude-dst-port-range': _strList,
|
|
'include-mac-address': _strList,
|
|
'exclude-mac-address': _strList,
|
|
'icmp-timeout': _str,
|
|
'congestion-controller': YamlSchema.scalar(['cubic', 'reno', 'bbr', 'bbr3']),
|
|
'file-descriptor': _str,
|
|
'recvmsgx': _bool,
|
|
'sendmsgx': _bool,
|
|
};
|
|
|
|
const _sniffPorts = YamlSchema.map({
|
|
'ports': _strList,
|
|
'override-destination': _bool,
|
|
});
|
|
|
|
const _sniffer = YamlSchema.map({
|
|
'enable': _bool,
|
|
'force-dns-mapping': _bool,
|
|
'parse-pure-ip': _bool,
|
|
'override-destination': _bool,
|
|
'sniff': YamlSchema.map({
|
|
'HTTP': _sniffPorts,
|
|
'TLS': _sniffPorts,
|
|
'QUIC': _sniffPorts,
|
|
}),
|
|
'force-domain': _strList,
|
|
'skip-domain': _strList,
|
|
'skip-src-address': _strList,
|
|
'skip-dst-address': _strList,
|
|
});
|
|
|
|
const _serverTls = {
|
|
'certificate': _str,
|
|
'private-key': _str,
|
|
'client-auth-type': YamlSchema.scalar([
|
|
'request',
|
|
'require-any',
|
|
'verify-if-given',
|
|
'require-and-verify',
|
|
]),
|
|
'client-auth-cert': _str,
|
|
'ech-key': _str,
|
|
};
|
|
|
|
const _listenerUsers = YamlSchema.list(
|
|
YamlSchema.map({'username': _str, 'password': _str}),
|
|
);
|
|
|
|
const _listenerUserDict = YamlSchema.dict(_str);
|
|
|
|
const _fallbackLimit = YamlSchema.map({
|
|
'after-bytes': _str,
|
|
'bytes-per-sec': _str,
|
|
'burst-bytes-per-sec': _str,
|
|
});
|
|
|
|
const _realityConfig = YamlSchema.map({
|
|
'dest': _str,
|
|
'private-key': _str,
|
|
'short-id': _strList,
|
|
'server-names': _strList,
|
|
'max-time-difference': _str,
|
|
'proxy': _outbound,
|
|
'limit-fallback-upload': _fallbackLimit,
|
|
'limit-fallback-download': _fallbackLimit,
|
|
});
|
|
|
|
const _muxOption = YamlSchema.map({
|
|
'padding': _bool,
|
|
'brutal': YamlSchema.map({'enabled': _bool, 'up': _str, 'down': _str}),
|
|
});
|
|
|
|
const _shadowTlsHandshake = YamlSchema.map({'dest': _str, 'proxy': _outbound});
|
|
|
|
const _listenerTlsLayers = {
|
|
'shadow-tls': YamlSchema.map({
|
|
'enable': _bool,
|
|
'version': YamlSchema.scalar(['1', '2', '3']),
|
|
'password': _str,
|
|
'users': YamlSchema.list(YamlSchema.map({'name': _str, 'password': _str})),
|
|
'handshake': _shadowTlsHandshake,
|
|
'handshake-for-server-name': YamlSchema.dict(_shadowTlsHandshake),
|
|
'strict-mode': _bool,
|
|
'wildcard-sni': YamlSchema.scalar(['authed', 'all', 'off']),
|
|
}),
|
|
'res-tls': YamlSchema.map({
|
|
'enable': _bool,
|
|
'dest': _str,
|
|
'password': _str,
|
|
'restls-script': _str,
|
|
'min-record-len': _str,
|
|
'rate-limit': _str,
|
|
'proxy': _outbound,
|
|
}),
|
|
'jls-config': YamlSchema.map({
|
|
'enable': _bool,
|
|
'users': _listenerUsers,
|
|
'sni': _str,
|
|
'dest': _str,
|
|
'alpn': _strList,
|
|
'proxy': _outbound,
|
|
'rate-limit': _str,
|
|
}),
|
|
};
|
|
|
|
const _v2rayListener = {
|
|
'ws-path': _str,
|
|
'grpc-service-name': _str,
|
|
..._serverTls,
|
|
..._listenerTlsLayers,
|
|
'reality-config': _realityConfig,
|
|
'mux-option': _muxOption,
|
|
};
|
|
|
|
const _mkcpConfig = YamlSchema.map({'enable': _bool, ..._mkcpFields});
|
|
|
|
const _listener = YamlSchema.map(
|
|
{
|
|
'name': _str,
|
|
'type': YamlSchema.scalar([
|
|
'mixed',
|
|
'socks',
|
|
'http',
|
|
'redir',
|
|
'tproxy',
|
|
'tun',
|
|
'tunnel',
|
|
'shadowsocks',
|
|
'vmess',
|
|
'vless',
|
|
'trojan',
|
|
'tuic',
|
|
'hysteria2',
|
|
'anytls',
|
|
'mieru',
|
|
'snell',
|
|
'hysteria2-realm',
|
|
'shadowquic',
|
|
'sudoku',
|
|
'trusttunnel',
|
|
]),
|
|
'port': _str,
|
|
'listen': _str,
|
|
'routing-mark': _str,
|
|
'rule': YamlSchema.of(YamlScalar.subRule),
|
|
'proxy': _outbound,
|
|
},
|
|
variants: {
|
|
'mixed': {
|
|
'users': _listenerUsers,
|
|
'udp': _bool,
|
|
..._serverTls,
|
|
'reality-config': _realityConfig,
|
|
},
|
|
'socks': {
|
|
'users': _listenerUsers,
|
|
'udp': _bool,
|
|
..._serverTls,
|
|
'reality-config': _realityConfig,
|
|
},
|
|
'http': {
|
|
'users': _listenerUsers,
|
|
..._serverTls,
|
|
'reality-config': _realityConfig,
|
|
},
|
|
'redir': {},
|
|
'tproxy': {'udp': _bool},
|
|
'tun': {'inet4-address': _strList, ..._tunFields},
|
|
'tunnel': {
|
|
'network': YamlSchema.list(YamlSchema.scalar(['tcp', 'udp'])),
|
|
'target': _str,
|
|
},
|
|
'shadowsocks': {
|
|
'password': _str,
|
|
'cipher': YamlSchema.scalar(_ssCiphers),
|
|
'udp': _bool,
|
|
'mux-option': _muxOption,
|
|
..._listenerTlsLayers,
|
|
'simple-obfs': YamlSchema.map({
|
|
'enable': _bool,
|
|
'mode': YamlSchema.scalar(['http', 'tls']),
|
|
}),
|
|
'kcp-tun': YamlSchema.map({
|
|
'enable': _bool,
|
|
'mode': YamlSchema.scalar(['normal', 'fast', 'fast2', 'fast3']),
|
|
..._kcptunFields,
|
|
}),
|
|
},
|
|
'snell': {
|
|
'psk': _str,
|
|
'version': YamlSchema.scalar(['1', '2', '3', '4', '5']),
|
|
'udp': _bool,
|
|
'obfs-opts': YamlSchema.map({
|
|
'mode': YamlSchema.scalar(['http', 'tls']),
|
|
'host': _str,
|
|
}),
|
|
..._listenerTlsLayers,
|
|
},
|
|
'vmess': {
|
|
'users': YamlSchema.list(
|
|
YamlSchema.map({'username': _str, 'uuid': _str, 'alterId': _str}),
|
|
),
|
|
..._v2rayListener,
|
|
'tlsmirror-config': YamlSchema.map({
|
|
'primary-key': _str,
|
|
'dest': _str,
|
|
'proxy': _outbound,
|
|
'explicit-nonce-ciphersuites': _strList,
|
|
'defer-instance-derived-write-time': _tlsMirrorTime,
|
|
'transport-layer-padding': YamlSchema.map({'enabled': _bool}),
|
|
'connection-enrolment': YamlSchema.map({
|
|
'primary-ingress-outbound': _str,
|
|
'primary-egress-outbound': _str,
|
|
}),
|
|
'sequence-watermarking-enabled': _bool,
|
|
}),
|
|
'mekya-config': YamlSchema.map({
|
|
'enable': _bool,
|
|
'url': _str,
|
|
'h2-pool-size': _str,
|
|
'max-write-delay': _str,
|
|
'max-request-size': _str,
|
|
'polling-interval-initial': _str,
|
|
'max-write-size': _str,
|
|
'max-write-duration-ms': _str,
|
|
'max-simultaneous-write-connection': _str,
|
|
'packet-writing-buffer': _str,
|
|
'kcp': _mkcpConfig,
|
|
}),
|
|
'mkcp-config': _mkcpConfig,
|
|
},
|
|
'vless': {
|
|
'users': YamlSchema.list(
|
|
YamlSchema.map({
|
|
'username': _str,
|
|
'uuid': _str,
|
|
'flow': YamlSchema.scalar(['xtls-rprx-vision']),
|
|
}),
|
|
),
|
|
'decryption': _str,
|
|
'allow-insecure': _bool,
|
|
..._v2rayListener,
|
|
'xhttp-config': YamlSchema.map({
|
|
'path': _str,
|
|
'host': _str,
|
|
'mode': YamlSchema.scalar([
|
|
'auto',
|
|
'packet-up',
|
|
'stream-up',
|
|
'stream-one',
|
|
]),
|
|
'no-sse-header': _bool,
|
|
'x-padding-bytes': _str,
|
|
'x-padding-obfs-mode': _bool,
|
|
'x-padding-key': _str,
|
|
'x-padding-header': _str,
|
|
'x-padding-placement': _str,
|
|
'x-padding-method': YamlSchema.scalar(['repeat-x', 'tokenish']),
|
|
'uplink-http-method': _str,
|
|
'session-placement': _xhttpPlacement,
|
|
'session-key': _str,
|
|
'seq-placement': _xhttpPlacement,
|
|
'seq-key': _str,
|
|
'uplink-data-placement': YamlSchema.scalar([
|
|
'body',
|
|
'header',
|
|
'cookie',
|
|
]),
|
|
'uplink-data-key': _str,
|
|
'uplink-chunk-size': _str,
|
|
'sc-stream-up-server-secs': _str,
|
|
'sc-max-buffered-posts': _str,
|
|
'sc-max-each-post-bytes': _str,
|
|
}),
|
|
},
|
|
'trojan': {
|
|
'users': _listenerUsers,
|
|
'allow-insecure': _bool,
|
|
..._v2rayListener,
|
|
'ss-option': YamlSchema.map({
|
|
'enabled': _bool,
|
|
'method': YamlSchema.scalar(_aeadCiphers),
|
|
'password': _str,
|
|
}),
|
|
},
|
|
'hysteria2': {
|
|
'users': _listenerUserDict,
|
|
'obfs': YamlSchema.scalar(['salamander', 'gecko']),
|
|
'obfs-password': _str,
|
|
'obfs-min-packet-size': _str,
|
|
'obfs-max-packet-size': _str,
|
|
..._serverTls,
|
|
'alpn': _strList,
|
|
'up': _str,
|
|
'down': _str,
|
|
'ignore-client-bandwidth': _bool,
|
|
'masquerade': _str,
|
|
'max-idle-time': _str,
|
|
'cwnd': _str,
|
|
'bbr-profile': _bbrProfile,
|
|
'udp-mtu': _str,
|
|
'mux-option': _muxOption,
|
|
'initial-stream-receive-window': _str,
|
|
'max-stream-receive-window': _str,
|
|
'initial-connection-receive-window': _str,
|
|
'max-connection-receive-window': _str,
|
|
'realm-opts': YamlSchema.map({
|
|
'enable': _bool,
|
|
'server-url': _str,
|
|
'token': _str,
|
|
'realm-id': _str,
|
|
'stun-servers': _strList,
|
|
'sni': _str,
|
|
'alpn': _strList,
|
|
'fingerprint': _str,
|
|
'proxy': _outbound,
|
|
..._pluginTls,
|
|
}),
|
|
},
|
|
'hysteria2-realm': {
|
|
'token': _str,
|
|
'max-realms': _str,
|
|
'max-realms-per-ip': _str,
|
|
'trusted-proxy-header': _str,
|
|
'realm-name-pattern': _str,
|
|
..._serverTls,
|
|
'alpn': _strList,
|
|
},
|
|
'tuic': {
|
|
'token': _strList,
|
|
'users': _listenerUserDict,
|
|
..._serverTls,
|
|
'alpn': _strList,
|
|
'congestion-controller': _congestionController,
|
|
'bbr-profile': _bbrProfile,
|
|
'cwnd': _str,
|
|
'max-idle-time': _str,
|
|
'authentication-timeout': _str,
|
|
'max-udp-relay-packet-size': _str,
|
|
'mux-option': _muxOption,
|
|
},
|
|
'shadowquic': {
|
|
'users': _listenerUsers,
|
|
'jls-upstream': YamlSchema.map({
|
|
'addr': _str,
|
|
'sni': _str,
|
|
'proxy': _outbound,
|
|
'rate-limit': _str,
|
|
}),
|
|
'alpn': _strList,
|
|
'quic-versions': YamlSchema.list(YamlSchema.scalar(['v1', 'v2'])),
|
|
'zero-rtt': _bool,
|
|
'congestion-controller': _congestionController,
|
|
'bbr-profile': _bbrProfile,
|
|
'cwnd': _str,
|
|
'up': _str,
|
|
'down': _str,
|
|
'ignore-client-bandwidth': _bool,
|
|
'max-idle-time': _str,
|
|
'max-datagram-frame-size': _str,
|
|
'recv-window-conn': _str,
|
|
'recv-window': _str,
|
|
'disable-mtu-discovery': _bool,
|
|
'mux-option': _muxOption,
|
|
},
|
|
'anytls': {
|
|
'users': _listenerUserDict,
|
|
..._serverTls,
|
|
..._listenerTlsLayers,
|
|
'allow-insecure': _bool,
|
|
'padding-scheme': _str,
|
|
},
|
|
'mieru': {
|
|
'transport': YamlSchema.scalar(['TCP', 'UDP']),
|
|
'users': _listenerUserDict,
|
|
'traffic-pattern': _str,
|
|
'user-hint-is-mandatory': _bool,
|
|
},
|
|
'sudoku': {
|
|
'key': _str,
|
|
'aead-method': YamlSchema.scalar([
|
|
'aes-128-gcm',
|
|
'chacha20-poly1305',
|
|
'none',
|
|
]),
|
|
'padding-min': _str,
|
|
'padding-max': _str,
|
|
'handshake-timeout': _str,
|
|
'table-type': YamlSchema.scalar([
|
|
'prefer_ascii',
|
|
'prefer_entropy',
|
|
'up_ascii_down_entropy',
|
|
'up_entropy_down_ascii',
|
|
]),
|
|
'custom-table': _str,
|
|
'custom-tables': _strList,
|
|
'enable-pure-downlink': _bool,
|
|
'disable-http-mask': _bool,
|
|
'http-mask-mode': _sudokuHttpMaskMode,
|
|
'path-root': _str,
|
|
'fallback': _str,
|
|
'httpmask': YamlSchema.map({
|
|
'disable': _bool,
|
|
'mode': _sudokuHttpMaskMode,
|
|
'path-root': _str,
|
|
}),
|
|
'mux-option': _muxOption,
|
|
},
|
|
'trusttunnel': {
|
|
'users': _listenerUsers,
|
|
..._serverTls,
|
|
'network': YamlSchema.list(YamlSchema.scalar(['tcp', 'udp'])),
|
|
'congestion-controller': _congestionController,
|
|
'bbr-profile': _bbrProfile,
|
|
'cwnd': _str,
|
|
},
|
|
},
|
|
);
|
|
|
|
const clashConfigSchema = YamlSchema.map({
|
|
'mixed-port': _str,
|
|
'port': _str,
|
|
'socks-port': _str,
|
|
'redir-port': _str,
|
|
'tproxy-port': _str,
|
|
'ss-config': _str,
|
|
'vmess-config': _str,
|
|
'inbound-tfo': _bool,
|
|
'inbound-mptcp': _bool,
|
|
'allow-lan': _bool,
|
|
'bind-address': YamlSchema.scalar(['*']),
|
|
'lan-allowed-ips': _strList,
|
|
'lan-disallowed-ips': _strList,
|
|
'authentication': _strList,
|
|
'skip-auth-prefixes': _strList,
|
|
'mode': YamlSchema.scalar(['rule', 'global', 'direct']),
|
|
'log-level': YamlSchema.scalar([
|
|
'info',
|
|
'warning',
|
|
'error',
|
|
'debug',
|
|
'silent',
|
|
]),
|
|
'ipv6': _bool,
|
|
'unified-delay': _bool,
|
|
'tcp-concurrent': _bool,
|
|
'find-process-mode': YamlSchema.scalar(['strict', 'always', 'off']),
|
|
'global-ua': _str,
|
|
'keep-alive-interval': _str,
|
|
'keep-alive-idle': _str,
|
|
'disable-keep-alive': _bool,
|
|
'interface-name': _str,
|
|
'routing-mark': _str,
|
|
'etag-support': _bool,
|
|
'external-controller': YamlSchema.scalar(['127.0.0.1:9090']),
|
|
'external-controller-routing-mark': _str,
|
|
'external-controller-cors': YamlSchema.map({
|
|
'allow-origins': _strList,
|
|
'allow-private-network': _bool,
|
|
}),
|
|
'secret': _str,
|
|
'external-ui': _str,
|
|
'external-ui-name': _str,
|
|
'external-ui-url': _str,
|
|
'external-doh-server': _str,
|
|
'profile': YamlSchema.map({'store-selected': _bool, 'store-fake-ip': _bool}),
|
|
'geodata-mode': _bool,
|
|
'geodata-loader': YamlSchema.scalar(['memconservative', 'standard']),
|
|
'geosite-matcher': YamlSchema.scalar(['succinct', 'mph']),
|
|
'geo-auto-update': _bool,
|
|
'geo-update-interval': _str,
|
|
'geox-url': YamlSchema.map({
|
|
'geoip': _str,
|
|
'geosite': _str,
|
|
'mmdb': _str,
|
|
'asn': _str,
|
|
}),
|
|
'hosts': YamlSchema.dict(_str),
|
|
'tls': YamlSchema.map({..._serverTls, 'custom-certifactes': _strList}),
|
|
'experimental': YamlSchema.map({
|
|
'quic-go-disable-gso': _bool,
|
|
'quic-go-disable-ecn': _bool,
|
|
'dialer-ip4p-convert': _bool,
|
|
}),
|
|
'dns': _dns,
|
|
'tun': _tun,
|
|
'sniffer': _sniffer,
|
|
'ntp': _ntp,
|
|
'listeners': YamlSchema.list(_listener),
|
|
'tunnels': YamlSchema.list(
|
|
YamlSchema.map({
|
|
'network': YamlSchema.list(YamlSchema.scalar(['tcp', 'udp'])),
|
|
'address': _str,
|
|
'target': _str,
|
|
'proxy': _outbound,
|
|
}),
|
|
),
|
|
'tuic-server': YamlSchema.map({
|
|
'enable': _bool,
|
|
'listen': _str,
|
|
'token': _strList,
|
|
'users': YamlSchema.dict(_str),
|
|
'certificate': _str,
|
|
'private-key': _str,
|
|
'alpn': _strList,
|
|
'congestion-controller': _congestionController,
|
|
'cwnd': _str,
|
|
'max-idle-time': _str,
|
|
'authentication-timeout': _str,
|
|
'max-udp-relay-packet-size': _str,
|
|
}),
|
|
'iptables': YamlSchema.map({
|
|
'enable': _bool,
|
|
'inbound-interface': _str,
|
|
'bypass': _strList,
|
|
'dns-redirect': _bool,
|
|
}),
|
|
'proxies': YamlSchema.list(_proxy),
|
|
'proxy-groups': YamlSchema.list(_proxyGroup),
|
|
'proxy-providers': YamlSchema.dict(_proxyProvider),
|
|
'rule-providers': YamlSchema.dict(_ruleProvider),
|
|
'rules': _rules,
|
|
'sub-rules': YamlSchema.dict(_rules),
|
|
});
|
|
|
|
const _providerFile = YamlSchema.map({
|
|
'proxies': YamlSchema.list(_proxy),
|
|
'payload': YamlSchema.list(YamlSchema.of(YamlScalar.rulePayload)),
|
|
});
|