from __future__ import annotations from pyxray.libs.xray_config import XrayConfigSettings, generate_transparent_rules from pyxray.libs.xray_config.transparent_rules import write_transparent_rule_files def test_redirect_iptables_rules_match_v2raya_shape() -> None: settings = XrayConfigSettings() settings.transparent.mode = "proxy" settings.transparent.type = "redirect" settings.transparent.port = 52345 rules = generate_transparent_rules(settings, backend="iptables") assert rules.mode == "redirect" assert "iptables -w 2 -t nat -N TP_OUT" in rules.setup assert "iptables -w 2 -t nat -A TP_RULE -d 10.0.0.0/8 -j RETURN" in rules.setup assert "iptables -w 2 -t nat -A TP_RULE -i docker+ -j RETURN" in rules.setup assert "iptables -w 2 -t nat -A TP_RULE -p tcp -j REDIRECT --to-ports 52345" in rules.setup assert "iptables -w 2 -t nat -I PREROUTING -p tcp -j TP_PRE" in rules.setup assert "iptables -w 2 -t nat -D OUTPUT -p tcp -j TP_OUT" in rules.cleanup def test_tproxy_iptables_rules_match_v2raya_shape() -> None: settings = XrayConfigSettings() settings.transparent.mode = "proxy" settings.transparent.type = "tproxy" settings.transparent.port = 52345 settings.transparent.tproxy_white_custom_ips = ["203.0.113.88/32"] rules = generate_transparent_rules(settings, backend="iptables") assert rules.mode == "tproxy" assert "ip rule add fwmark 0x40/0xc0 table 100" in rules.setup assert "ip route add local 0.0.0.0/0 dev lo table 100" in rules.setup assert "iptables -w 2 -t mangle -N TP_MARK" in rules.setup assert "iptables -w 2 -t mangle -A TP_RULE -p udp --dport 53 -j TP_MARK" in rules.setup assert "iptables -w 2 -t mangle -A TP_RULE -d 203.0.113.88/32 -j RETURN" in rules.setup assert "iptables -w 2 -t mangle -A TP_PRE -p udp -m mark --mark 0x40/0xc0 -j TPROXY --on-port 52345 --on-ip 127.0.0.1" in rules.setup assert "iptables -w 2 -t mangle -F TP_MARK" in rules.cleanup def test_redirect_nft_rules_include_table_and_loader_command() -> None: settings = XrayConfigSettings() settings.transparent.mode = "proxy" settings.transparent.type = "redirect" rules = generate_transparent_rules(settings, backend="nft", nftables_path="/tmp/pyxray.nft") assert rules.setup == "nft -f /tmp/pyxray.nft" assert rules.cleanup == "nft delete table inet v2raya" assert "table inet v2raya" in rules.nftables assert "set whitelist" in rules.nftables assert "meta mark & 0x80 == 0x80 return" in rules.nftables assert "iifname \"docker*\" return" in rules.nftables assert "meta l4proto tcp redirect to :52345" in rules.nftables def test_close_mode_has_no_system_rules() -> None: settings = XrayConfigSettings() settings.transparent.mode = "close" rules = generate_transparent_rules(settings) assert rules.setup == "" assert rules.cleanup == "" def test_write_transparent_rule_files_outputs_auditable_scripts(tmp_path) -> None: settings = XrayConfigSettings() settings.transparent.mode = "proxy" settings.transparent.type = "redirect" files = write_transparent_rule_files(settings, tmp_path) assert files.iptables_setup.read_text(encoding="utf-8").startswith("#!/bin/sh\nset -eu\n") assert "printf '%s' 0 > /proc/sys/net/ipv4/ip_forward" in files.ip_forward.read_text(encoding="utf-8") assert "nameserver 127.2.0.17" in files.resolv_setup.read_text(encoding="utf-8") assert "REDIRECT --to-ports 52345" in files.iptables_setup.read_text(encoding="utf-8") assert "nft -f" in files.nft_setup.read_text(encoding="utf-8") assert files.nftables is not None assert "table inet v2raya" in files.nftables.read_text(encoding="utf-8") def test_ip_forward_script_follows_setting_like_v2raya(tmp_path) -> None: settings = XrayConfigSettings() settings.transparent.ipforward = True files = write_transparent_rule_files(settings, tmp_path) content = files.ip_forward.read_text(encoding="utf-8") assert "printf '%s' 1 > /proc/sys/net/ipv4/ip_forward" in content assert "printf '%s' 1 > /proc/sys/net/ipv6/conf/all/forwarding" in content def test_resolv_hijack_scripts_follow_v2raya_redirect_dns_behavior(tmp_path) -> None: settings = XrayConfigSettings() settings.transparent.mode = "proxy" settings.transparent.type = "redirect" files = write_transparent_rule_files(settings, tmp_path) assert "nameserver 127.2.0.17" in files.resolv_setup.read_text(encoding="utf-8") assert "nameserver 119.29.29.29" in files.resolv_setup.read_text(encoding="utf-8") assert "nameserver 223.6.6.6" in files.resolv_cleanup.read_text(encoding="utf-8")