from __future__ import annotations import json from typing import Any from .model import Hy2Endpoint from .policy import Policy from .version import SUPPORTED_SING_BOX_VERSION TARGET_VERSION = SUPPORTED_SING_BOX_VERSION GECKO_MIN_PACKET_SIZE = 512 GECKO_MAX_PACKET_SIZE = 1200 def render_config(policy: Policy, endpoint: Hy2Endpoint) -> dict[str, Any]: network = policy.network dns = policy.dns outbound: dict[str, Any] = { "type": "hysteria2", "tag": "hy2-out", "server": endpoint.server, "up_mbps": policy.bandwidth.up_mbps, "down_mbps": policy.bandwidth.down_mbps, "password": endpoint.password, "tls": { "enabled": True, "server_name": endpoint.sni, "insecure": endpoint.insecure, }, "disable_chrome_parrot": False, "bind_interface": network.upstream_interface, "domain_resolver": {"server": "bootstrap-dns", "strategy": dns.strategy}, } if endpoint.server_port is not None: outbound["server_port"] = endpoint.server_port else: outbound["server_ports"] = list(endpoint.server_ports) if endpoint.obfs_type is not None: obfs: dict[str, Any] = { "type": endpoint.obfs_type, "password": endpoint.obfs_password, } if endpoint.obfs_type == "gecko": obfs["min_packet_size"] = GECKO_MIN_PACKET_SIZE obfs["max_packet_size"] = GECKO_MAX_PACKET_SIZE outbound["obfs"] = obfs return { "log": {"level": "info", "timestamp": True}, "dns": { "servers": [ { "type": "udp", "tag": "bootstrap-dns", "server": dns.bootstrap_server, "server_port": dns.bootstrap_port, "bind_interface": network.upstream_interface, }, { "type": "https", "tag": "remote-dns", "server": dns.remote_server, "server_port": dns.remote_port, "path": dns.remote_path, "tls": { "enabled": True, "server_name": dns.remote_tls_server_name, }, "detour": "hy2-out", }, ], "final": "remote-dns", "strategy": dns.strategy, }, "inbounds": [ { "type": "tun", "tag": "tun-in", "interface_name": network.tun_name, "address": [network.tun_address], "mtu": network.mtu, "dns_mode": "disabled", "auto_route": True, "iproute2_table_index": network.iproute2_table_index, "iproute2_rule_index": network.iproute2_rule_index, "auto_redirect": True, "auto_redirect_input_mark": network.auto_redirect_input_mark, "auto_redirect_output_mark": network.auto_redirect_output_mark, "auto_redirect_reset_mark": network.auto_redirect_reset_mark, "auto_redirect_nfqueue": network.auto_redirect_nfqueue, "auto_redirect_iproute2_fallback_rule_index": network.auto_redirect_fallback_rule_index, "strict_route": True, "stack": "mixed", "route_exclude_address": list(network.route_exclude_address), } ], "outbounds": [outbound], "route": { "auto_detect_interface": True, "default_domain_resolver": { "server": "bootstrap-dns", "strategy": dns.strategy, }, "final": "hy2-out", "rules": [ { "network": ["tcp", "udp"], "port": 53, "action": "hijack-dns", } ], }, } def render_bytes(policy: Policy, endpoint: Hy2Endpoint) -> bytes: return ( json.dumps(render_config(policy, endpoint), ensure_ascii=False, indent=2) + "\n" ).encode("utf-8")