From fc5d31093531dc64299cc766397de705fe1deb7e Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Tue, 11 Nov 2025 15:04:09 +0100 Subject: [PATCH 001/134] add QUIC setup script to nym-node-cli --- scripts/nym-node-setup/nym-node-cli.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/scripts/nym-node-setup/nym-node-cli.py b/scripts/nym-node-setup/nym-node-cli.py index ebae150523..6b001df8d2 100755 --- a/scripts/nym-node-setup/nym-node-cli.py +++ b/scripts/nym-node-setup/nym-node-cli.py @@ -33,6 +33,7 @@ class NodeSetupCLI: self.tunnel_manager_sh = self._check_gwx_mode() and self.fetch_script("network_tunnel_manager.sh") self.wg_ip_tables_manager_sh = self._check_gwx_mode() and self.fetch_script("wireguard-exit-policy-manager.sh") self.wg_ip_tables_test_sh = self._check_gwx_mode() and self.fetch_script("exit-policy-tests.sh") + self.wg_ip_tables_test_sh = self._check_gwx_mode() and self.fetch_script("quic_bridge_deployment.sh") def print_welcome_message(self): """Welcome user, warns for needed pre-reqs and asks for confimation""" @@ -128,7 +129,9 @@ class NodeSetupCLI: "network_tunnel_manager.sh": f"https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/network_tunnel_manager.sh", "wireguard-exit-policy-manager.sh": f"https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh", "exit-policy-tests.sh": f"https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/wireguard-exit-policy/exit-policy-tests.sh", + "quic_bridge_deployment.sh": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/quic_bridge_deployment.sh" } + return scripts_urls[script_init_name] def run_script( @@ -320,6 +323,10 @@ class NodeSetupCLI: self.run_script(self.wg_ip_tables_manager_sh, args=["status"]) self.run_script(self.wg_ip_tables_test_sh) + def quic_bridge_deploy(self): + """Setup QUIC bridge and configuration using external script""" + self.run_script(self.quic_bridge_deployment_sh, args=["full_bridge_setup"], env=run_env) + return def run_nym_node_as_service(self): """Starts /etc/systemd/system/nym-node.service based on prompt using external script""" @@ -521,7 +528,7 @@ class NodeSetupCLI: self.run_tunnel_manager_setup() if self.check_wg_enabled(): self.setup_test_wg_ip_tables() - self.setup_test_wg_ip_tables() + self.quic_bridge_deploy() From dea8a287e6d2ca000447957405bb2e947890b848 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Tue, 11 Nov 2025 19:42:03 +0100 Subject: [PATCH 002/134] add arguments for env vars --- scripts/nym-node-setup/nym-node-cli.py | 219 ++++++++++++++++++------- 1 file changed, 157 insertions(+), 62 deletions(-) diff --git a/scripts/nym-node-setup/nym-node-cli.py b/scripts/nym-node-setup/nym-node-cli.py index 6b001df8d2..b7c59dfc16 100755 --- a/scripts/nym-node-setup/nym-node-cli.py +++ b/scripts/nym-node-setup/nym-node-cli.py @@ -22,18 +22,28 @@ class NodeSetupCLI: def __init__(self, args): self.branch = args.dev self.welcome_message = self.print_welcome_message() - self.mode = self.prompt_mode() + self.mode = self._get_or_prompt_mode(args) self.prereqs_install_sh = self.fetch_script("nym-node-prereqs-install.sh") - self.env_vars_install_sh = self.fetch_script("setup-env-vars.sh") + #self.env_vars_install_sh = self.fetch_script("setup-env-vars.sh") self.node_install_sh = self.fetch_script("nym-node-install.sh") self.service_config_sh = self.fetch_script("setup-systemd-service-file.sh") self.start_node_systemd_service_sh = self.fetch_script("start-node-systemd-service.sh") - self.landing_page_html = self._check_gwx_mode() and self.fetch_script("landing-page.html") - self.nginx_proxy_wss_sh = self._check_gwx_mode() and self.fetch_script("nginx_proxy_wss_sh") - self.tunnel_manager_sh = self._check_gwx_mode() and self.fetch_script("network_tunnel_manager.sh") - self.wg_ip_tables_manager_sh = self._check_gwx_mode() and self.fetch_script("wireguard-exit-policy-manager.sh") - self.wg_ip_tables_test_sh = self._check_gwx_mode() and self.fetch_script("exit-policy-tests.sh") - self.wg_ip_tables_test_sh = self._check_gwx_mode() and self.fetch_script("quic_bridge_deployment.sh") + self.is_gwx = self.mode == "exit-gateway" + if self.is_gwx: + self.landing_page_html = self.fetch_script("landing-page.html") + self.nginx_proxy_wss_sh = self.fetch_script("nginx_proxy_wss_sh") + self.tunnel_manager_sh = self.fetch_script("network_tunnel_manager.sh") + self.wg_ip_tables_manager_sh = self.fetch_script("wireguard-exit-policy-manager.sh") + self.wg_ip_tables_test_sh = self.fetch_script("exit-policy-tests.sh") + self.quic_bridge_deployment_sh = self.fetch_script("quic_bridge_deployment.sh") + else: + self.landing_page_html = None + self.nginx_proxy_wss_sh = None + self.tunnel_manager_sh = None + self.wg_ip_tables_manager_sh = None + self.wg_ip_tables_test_sh = None + self.quic_bridge_deployment_sh = None + def print_welcome_message(self): """Welcome user, warns for needed pre-reqs and asks for confimation""" @@ -46,7 +56,7 @@ class NodeSetupCLI: self.print_character("=", 41) msg = \ "Before you begin, make sure that:\n"\ - "1. You run this setup on Debian based Linux (ie Ubuntu)\n"\ + "1. You run this setup on Debian based Linux (ie Ubuntu 22.04 LTS)\n"\ "2. You run this installation program from a root shell\n"\ "3. You meet minimal requirements: https://nym.com/docs/operators/nodes\n"\ "4. You accept Operators Terms & Conditions: https://nym.com/operators-validators-terms\n"\ @@ -60,43 +70,99 @@ class NodeSetupCLI: else: print("Without confirming the points above, we cannot continue.") exit(1) + + def ensure_env_values(self, args): + """Collect env vars from args or prompt interactively, then save to env.sh.""" + env_file = Path("env.sh") + fields = [ + ("hostname", "HOSTNAME", "Enter hostname (if you don't use a DNS, press enter): "), + ("location", "LOCATION", "Enter node location (country code or name): "), + ("email", "EMAIL", "Enter your email: "), + ("moniker", "MONIKER", "Enter node public moniker (visible in explorer & NymVPN app): "), + ("description", "DESCRIPTION", "Enter short node public description: "), + ] - def prompt_mode(self): - """Ask user to insert node functionality and save it in python and bash envs""" + existing = self._read_env_file(env_file) + updated = {} + + for arg_name, key, prompt in fields: + cli_val = getattr(args, arg_name, None) + value = cli_val.strip() if cli_val else existing.get(key) or input(prompt).strip() + updated[key] = value + os.environ[key] = value + + # autodetect PUBLIC_IP if not already set + if not os.environ.get("PUBLIC_IP"): + try: + ip = subprocess.run(["curl", "-fsS4", "https://ifconfig.me"], + capture_output=True, text=True, timeout=5) + if ip.returncode == 0 and ip.stdout.strip(): + updated["PUBLIC_IP"] = ip.stdout.strip() + os.environ["PUBLIC_IP"] = ip.stdout.strip() + except Exception: + pass + + # write all collected variables to env.sh in one go + self._upsert_env_vars(updated, env_file) + + print(f"[OK] Updated env.sh with {len(updated)} entries.") + + + + + def _upsert_env_vars(self, updates: dict, env_file: Path = Path("env.sh")): + existing = self._read_env_file(env_file) + existing.update(updates) + with env_file.open("w") as f: + for k, v in existing.items(): + f.write(f'export {k}="{v}"\n') + os.environ.update(updates) + + def _read_env_file(self, env_file: Path) -> dict: + env = {} + if env_file.exists(): + for line in env_file.read_text().splitlines(): + if line.startswith("export ") and "=" in line: + k, v = line.replace("export ", "", 1).split("=", 1) + env[k.strip()] = v.strip().strip('"') + return env + + def _get_or_prompt_mode(self, args): + """Resolve MODE from --mode, env.sh, os.environ, or prompt; persist to env.sh.""" + + env_file = Path("env.sh") + + # CLI arg + mode = getattr(args, "mode", None) + if mode: + mode = mode.strip().lower() + self._upsert_env_var("MODE", mode) + print(f"Mode set to '{mode}' from CLI argument.") + return mode + + # env.sh (replaces manual read) + existing = self._read_env_file(env_file) + mode = existing.get("MODE") + if mode: + os.environ["MODE"] = mode + return mode + + # process env + if os.environ.get("MODE"): + return os.environ["MODE"] + + # prompt mode = input( - "\nEnter the mode you want to run nym-node in: " - "\n1. mixnode " - "\n2. entry-gateway " - "\n3. exit-gateway (works as entry-gateway as well) " - "\nPress 1, 2 or 3 and enter:\n" - ).strip() - - if mode in ("1", "mixnode"): - mode = "mixnode" - elif mode in ("2", "entry-gateway"): - mode = "entry-gateway" - elif mode in ("3", "exit-gateway"): - mode = "exit-gateway" - else: - print("Only numbers 1, 2 or 3 are accepted.") + "\nEnter node mode (mixnode / entry-gateway / exit-gateway): " + ).strip().lower() + if mode not in ("mixnode", "entry-gateway", "exit-gateway"): + print("Invalid mode. Must be one of: mixnode, entry-gateway, exit-gateway.") raise SystemExit(1) - # save mode for this Python instance - self.mode = mode - os.environ["MODE"] = mode - - # persist to env.sh so other scripts can source it - env_file = Path("env.sh") - with env_file.open("a") as f: - f.write(f'export MODE="{mode}"\n') - - # source env.sh so future bash subprocesses see it immediately - subprocess.run("source ./env.sh", shell=True, executable="/bin/bash") - + self._upsert_env_var("MODE", mode) print(f"Mode set to '{mode}' — stored in env.sh and sourced for immediate use.") return mode - def fetch_script(self, script_name): """Fetches needed scripts according to a defined mode""" # print header only the first time @@ -120,7 +186,7 @@ class NodeSetupCLI: github_raw_nymtech_nym_scripts_url = f"https://raw.githubusercontent.com/nymtech/nym/refs/heads/{self.branch}/scripts/" scripts_urls = { "nym-node-prereqs-install.sh": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/nym-node-prereqs-install.sh", - "setup-env-vars.sh": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/setup-env-vars.sh", + #"setup-env-vars.sh": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/setup-env-vars.sh", "nym-node-install.sh": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/nym-node-install.sh", "setup-systemd-service-file.sh": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/setup-systemd-service-file.sh", "start-node-systemd-service.sh": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/start-node-systemd-service.sh", @@ -208,27 +274,30 @@ class NodeSetupCLI: else: return False - def check_wg_enabled(self): - """Checks if Wireguard is enabled and if not, prompts user if they want to enable it, stores it to env.sh""" + def check_wg_enabled(self, args=None): + """Determine if WireGuard is enabled; precedence: CLI > env > env.sh > prompt. Persist normalized value.""" + env_file = os.path.join(os.getcwd(), "env.sh") - env_file = os.path.abspath(os.path.join(os.getcwd(), "env.sh")) + def norm(v): + return "true" if str(v).strip().lower() in ("true") else "false" - def norm(v): # -> "true" or "false" - return "true" if str(v).strip().lower() in ("1", "true", "yes", "y") else "false" + val = None - # precedence: process env → env.sh → prompt - val = os.environ.get("WIREGUARD") + # CLI argument + if args and getattr(args, "wireguard", None) is not None: + val = norm(getattr(args, "wireguard")) + print(f"[INFO] WireGuard mode provided via CLI: {val}") - if val is None and os.path.isfile(env_file): - try: - with open(env_file, "r", encoding="utf-8") as f: - m = re.search(r'^\s*export\s+WIREGUARD\s*=\s*"?([^"\n]+)"?', f.read(), re.M) - if m: - val = m.group(1) - except Exception: - pass + # Environment variable + val = val or os.environ.get("WIREGUARD") + # env.sh file + if val is None: + envs = self._read_env_file(Path(env_file)) + val = envs.get("WIREGUARD") + + # Prompt if val is None: ans = input( "\nWireGuard is not configured.\n" @@ -240,25 +309,24 @@ class NodeSetupCLI: val = norm(val) os.environ["WIREGUARD"] = val - # persist to env.sh (replace or append) + # Persist to env.sh try: text = "" if os.path.isfile(env_file): - with open(env_file, "r", encoding="utf-8") as f: + with open(env_file, encoding="utf-8") as f: text = f.read() if re.search(r'^\s*export\s+WIREGUARD\s*=.*$', text, re.M): text = re.sub(r'^\s*export\s+WIREGUARD\s*=.*$', f'export WIREGUARD="{val}"', text, flags=re.M) else: - if text and not text.endswith("\n"): - text += "\n" - text += f'export WIREGUARD="{val}"\n' + text = (text.rstrip("\n") + "\n" if text else "") + f'export WIREGUARD="{val}"\n' with open(env_file, "w", encoding="utf-8") as f: f.write(text) print(f'WIREGUARD={val} saved to {env_file}') - except Exception as e: + except OSError as e: print(f"Warning: could not write {env_file}: {e}") - return (val == "true") + return val == "true" + def run_bash_command(self, command, args=None, *, env=None, cwd=None, check=True): """ @@ -517,6 +585,7 @@ class NodeSetupCLI: def run_node_installation(self,args): """Main function called by argparser command install running full node install flow""" + self.ensure_env_values(args) self.run_script(self.prereqs_install_sh) self.run_script(self.env_vars_install_sh) self.run_script(self.node_install_sh) @@ -565,6 +634,32 @@ class ArgParser: help="Starts nym-node installation setup CLI", aliases=["i", "I"], add_help=True ) + install_parser.add_argument( + "--mode", + choices=["mixnode", "entry-gateway", "exit-gateway"], + help="Node mode: 'mixnode', 'entry-gateway', or 'exit-gateway'", + ) + install_parser.add_argument( + "--wireguard", + choices=["true", "false"], + help="WireGuard functionality switch: true / false" + ) + install_parser.add_argument("--hostname", help="Node domain / hostname") + install_parser.add_argument("--location", help="Node location (country code or name)") + install_parser.add_argument("--email", help="Contact email for the node operator") + install_parser.add_argument("--moniker", help="Public moniker displayed in explorer & NymVPN app") + install_parser.add_argument("--description", help="Short public description of the node") + install_parser.add_argument("--public-ip", help="External IPv4 address (autodetected if omitted)") + install_parser.add_argument("--nym-node-binary", help="URL for nym-node binary (autodetected if omitted)") + + # generic fallback + install_parser.add_argument( + "--env", + action="append", + metavar="KEY=VALUE", + help="(Optional) Extra ENV VARS, e.g. --env CUSTOM_KEY=value", + ) + args = parser.parse_args() From cc74d218fcdb8817238f4fa5f5cde0a253bdc741 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Tue, 11 Nov 2025 21:56:15 +0100 Subject: [PATCH 003/134] rm redundant fn --- scripts/nym-node-setup/setup-env-vars.sh | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/scripts/nym-node-setup/setup-env-vars.sh b/scripts/nym-node-setup/setup-env-vars.sh index 3eafd93ba5..e119a61fd6 100644 --- a/scripts/nym-node-setup/setup-env-vars.sh +++ b/scripts/nym-node-setup/setup-env-vars.sh @@ -39,16 +39,6 @@ while true; do esac done -# try to get the latest binary URL (non-fatal if missing) -LATEST_BINARY=$( - curl -fsSL https://github.com/nymtech/nym/releases/latest \ - | grep -Eo 'href="/nymtech/nym/releases/download/[^"]+/nym-node"' \ - | head -n1 \ - | cut -d'"' -f2 -) -if [[ -z "${LATEST_BINARY:-}" ]]; then - echo "WARNING: Could not determine latest nym-node binary URL right now. The installer will resolve it later." -fi PUBLIC_IP=$(curl -fsS -4 https://ifconfig.me || true) PUBLIC_IP=${PUBLIC_IP:-""} From 9eca9efd823662b15d1769c76fa3425a5a8b5d1e Mon Sep 17 00:00:00 2001 From: benedettadavico Date: Wed, 12 Nov 2025 13:45:33 +0100 Subject: [PATCH 004/134] fix direction and add test --- .../exit-policy-tests.sh | 68 ++++++++++++++++++- .../wireguard-exit-policy-manager.sh | 13 ++-- 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/scripts/wireguard-exit-policy/exit-policy-tests.sh b/scripts/wireguard-exit-policy/exit-policy-tests.sh index 5ae10b177c..e0f86e5969 100644 --- a/scripts/wireguard-exit-policy/exit-policy-tests.sh +++ b/scripts/wireguard-exit-policy/exit-policy-tests.sh @@ -47,7 +47,7 @@ test_port_range_rules() { "8087-8088:tcp:Simplify Media" "8232-8233:tcp:Zcash" "8332-8333:tcp:Bitcoin" - "18080-18081:tcp:Monero" + "18080-18081:tcp:Monero" ) local total_failures=0 @@ -146,6 +146,71 @@ test_critical_services() { return $failures } +# Test that the exit policy chain is correctly wired up to FORWARD chain +test_forward_chain_hook() { + echo -e "${YELLOW}Testing FORWARD Chain Hook...${NC}" + + local failures=0 + NETWORK_DEVICE=$(ip route show default | awk '/default/ {print $5}') + + if [[ -z "$NETWORK_DEVICE" ]]; then + echo -e "${RED}✗ Could not determine network device${NC}" + return 1 + fi + + # (incoming from nymwg, outgoing to network device) + if iptables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null; then + echo -e "${GREEN}✓ IPv4 FORWARD hook exists with correct direction: -i $WG_INTERFACE -o $NETWORK_DEVICE${NC}" + else + echo -e "${RED}✗ IPv4 FORWARD hook missing or has wrong direction${NC}" + echo -e "${YELLOW} Expected: -i $WG_INTERFACE -o $NETWORK_DEVICE -j $NYM_CHAIN${NC}" + + # Check if wrong direction exists + if iptables -C FORWARD -o "$WG_INTERFACE" -j "$NYM_CHAIN" 2>/dev/null; then + echo -e "${RED}✗ WRONG DIRECTION FOUND: -o $WG_INTERFACE (this matches return traffic, not client egress!)${NC}" + fi + + # Show what actually exists - specifically look for jump rules to NYM-EXIT + echo -e "${YELLOW} Current FORWARD rules that jump to $NYM_CHAIN:${NC}" + iptables -L FORWARD -n -v --line-numbers | grep -E "$NYM_CHAIN" || echo " (none found - exit policy chain is not hooked to FORWARD!)" + echo -e "${YELLOW} All FORWARD rules with $WG_INTERFACE (for reference):${NC}" + iptables -L FORWARD -n -v --line-numbers | grep -E "$WG_INTERFACE" | head -5 || echo " (none found)" + ((failures++)) + fi + + # Check IPv6 + if ip6tables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null; then + echo -e "${GREEN}✓ IPv6 FORWARD hook exists with correct direction: -i $WG_INTERFACE -o $NETWORK_DEVICE${NC}" + else + echo -e "${RED}✗ IPv6 FORWARD hook missing or has wrong direction${NC}" + echo -e "${YELLOW} Expected: -i $WG_INTERFACE -o $NETWORK_DEVICE -j $NYM_CHAIN${NC}" + + # Check if wrong direction exists + if ip6tables -C FORWARD -o "$WG_INTERFACE" -j "$NYM_CHAIN" 2>/dev/null; then + echo -e "${RED}✗ WRONG DIRECTION FOUND: -o $WG_INTERFACE (this matches return traffic, not client egress!)${NC}" + fi + + # Show what actually exists - specifically look for jump rules to NYM-EXIT + echo -e "${YELLOW} Current IPv6 FORWARD rules that jump to $NYM_CHAIN:${NC}" + ip6tables -L FORWARD -n -v --line-numbers | grep -E "$NYM_CHAIN" || echo " (none found - exit policy chain is not hooked to FORWARD!)" + echo -e "${YELLOW} All IPv6 FORWARD rules with $WG_INTERFACE (for reference):${NC}" + ip6tables -L FORWARD -n -v --line-numbers | grep -E "$WG_INTERFACE" | head -5 || echo " (none found)" + ((failures++)) + fi + + # Check rule position (should be before UFW rules) + local rule_num=$(iptables -L FORWARD -n --line-numbers | grep -E "$NYM_CHAIN.*$WG_INTERFACE.*$NETWORK_DEVICE" | awk '{print $1}' | head -1) + if [[ -n "$rule_num" ]]; then + if [[ $rule_num -le 5 ]]; then + echo -e "${GREEN}✓ Rule is early in FORWARD chain (position #$rule_num) - good for UFW compatibility${NC}" + else + echo -e "${YELLOW}⚠ Rule is later in FORWARD chain (position #$rule_num) - may conflict with UFW${NC}" + fi + fi + + return $failures +} + # Verify default reject rule exists test_default_reject_rule() { echo -e "${YELLOW}This test takes some time, do not quit the process${NC}" @@ -197,6 +262,7 @@ run_all_tests() { done local test_functions=( + "test_forward_chain_hook" "test_port_range_rules" "test_critical_services" ) diff --git a/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh b/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh index bce3d09711..b803cd65a3 100644 --- a/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh +++ b/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh @@ -11,7 +11,7 @@ # - Groups rules logically for easier management # - Integrates with existing Nym node configuration # -# Usage: ./nym-exit-policy.sh [command] +# Usage: ./wireguard-exit-policy-manager.sh [command] set -e @@ -117,15 +117,15 @@ create_nym_chain() { fi # Link it to the FORWARD chain if not already linked - if ! iptables -C FORWARD -o "$WG_INTERFACE" -j "$NYM_CHAIN" 2>/dev/null; then + if ! iptables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null; then echo -e "${YELLOW}Linking $NYM_CHAIN to FORWARD chain...${NC}" - iptables -A FORWARD -o "$WG_INTERFACE" -j "$NYM_CHAIN" + iptables -I FORWARD 1 -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" fi # Link IPv6 chain - if ! ip6tables -C FORWARD -o "$WG_INTERFACE" -j "$NYM_CHAIN" 2>/dev/null; then + if ! ip6tables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null; then echo -e "${YELLOW}Linking $NYM_CHAIN to IPv6 FORWARD chain...${NC}" - ip6tables -A FORWARD -o "$WG_INTERFACE" -j "$NYM_CHAIN" + ip6tables -I FORWARD 1 -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" fi } @@ -313,6 +313,7 @@ apply_port_allowlist() { ["IMAPOverTLS"]="993" ["POP3OverTLS"]="995" ["OpenVPN"]="1194" + ["WireGuardPeer"]="51820-51822" ["QTServerAdmin"]="1220" ["PKTKRB"]="1293" ["MSSQL"]="1433" @@ -418,7 +419,9 @@ clear_rules() { # Remove the chain from FORWARD if it exists iptables -D FORWARD -o "$WG_INTERFACE" -j "$NYM_CHAIN" 2>/dev/null || true + iptables -D FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null || true ip6tables -D FORWARD -o "$WG_INTERFACE" -j "$NYM_CHAIN" 2>/dev/null || true + ip6tables -D FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null || true # Delete the chains iptables -X "$NYM_CHAIN" 2>/dev/null || true From bdacc7200378e49eb04236aedf8e749cda4085b4 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Wed, 12 Nov 2025 15:22:26 +0100 Subject: [PATCH 005/134] rm redundant --- scripts/nym-node-setup/nym-node-cli.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/nym-node-setup/nym-node-cli.py b/scripts/nym-node-setup/nym-node-cli.py index b7c59dfc16..06b8ef7d5f 100755 --- a/scripts/nym-node-setup/nym-node-cli.py +++ b/scripts/nym-node-setup/nym-node-cli.py @@ -24,7 +24,6 @@ class NodeSetupCLI: self.welcome_message = self.print_welcome_message() self.mode = self._get_or_prompt_mode(args) self.prereqs_install_sh = self.fetch_script("nym-node-prereqs-install.sh") - #self.env_vars_install_sh = self.fetch_script("setup-env-vars.sh") self.node_install_sh = self.fetch_script("nym-node-install.sh") self.service_config_sh = self.fetch_script("setup-systemd-service-file.sh") self.start_node_systemd_service_sh = self.fetch_script("start-node-systemd-service.sh") @@ -186,7 +185,6 @@ class NodeSetupCLI: github_raw_nymtech_nym_scripts_url = f"https://raw.githubusercontent.com/nymtech/nym/refs/heads/{self.branch}/scripts/" scripts_urls = { "nym-node-prereqs-install.sh": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/nym-node-prereqs-install.sh", - #"setup-env-vars.sh": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/setup-env-vars.sh", "nym-node-install.sh": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/nym-node-install.sh", "setup-systemd-service-file.sh": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/setup-systemd-service-file.sh", "start-node-systemd-service.sh": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/start-node-systemd-service.sh", From b56d9505e6c954446f8e7eeb5295bb60b8895e37 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Wed, 12 Nov 2025 15:31:08 +0100 Subject: [PATCH 006/134] address comments --- scripts/nym-node-setup/nym-node-cli.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/scripts/nym-node-setup/nym-node-cli.py b/scripts/nym-node-setup/nym-node-cli.py index 06b8ef7d5f..6bbe7bd5e4 100755 --- a/scripts/nym-node-setup/nym-node-cli.py +++ b/scripts/nym-node-setup/nym-node-cli.py @@ -135,7 +135,7 @@ class NodeSetupCLI: mode = getattr(args, "mode", None) if mode: mode = mode.strip().lower() - self._upsert_env_var("MODE", mode) + self._upsert_env_vars("MODE", mode) print(f"Mode set to '{mode}' from CLI argument.") return mode @@ -158,7 +158,7 @@ class NodeSetupCLI: print("Invalid mode. Must be one of: mixnode, entry-gateway, exit-gateway.") raise SystemExit(1) - self._upsert_env_var("MODE", mode) + self._upsert_env_vars("MODE", mode) print(f"Mode set to '{mode}' — stored in env.sh and sourced for immediate use.") return mode @@ -278,7 +278,7 @@ class NodeSetupCLI: env_file = os.path.join(os.getcwd(), "env.sh") def norm(v): - return "true" if str(v).strip().lower() in ("true") else "false" + return "true" if str(v).strip().lower() == ("true") else "false" val = None @@ -391,8 +391,7 @@ class NodeSetupCLI: def quic_bridge_deploy(self): """Setup QUIC bridge and configuration using external script""" - self.run_script(self.quic_bridge_deployment_sh, args=["full_bridge_setup"], env=run_env) - return + self.run_script(self.quic_bridge_deployment_sh, args=["full_bridge_setup"]) def run_nym_node_as_service(self): """Starts /etc/systemd/system/nym-node.service based on prompt using external script""" From 0453345d65e60f828b1fa09af04a99b75f6142c8 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Wed, 12 Nov 2025 15:32:41 +0100 Subject: [PATCH 007/134] address comments --- scripts/nym-node-setup/nym-node-cli.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/nym-node-setup/nym-node-cli.py b/scripts/nym-node-setup/nym-node-cli.py index 6bbe7bd5e4..c4ef41ca95 100755 --- a/scripts/nym-node-setup/nym-node-cli.py +++ b/scripts/nym-node-setup/nym-node-cli.py @@ -584,7 +584,6 @@ class NodeSetupCLI: """Main function called by argparser command install running full node install flow""" self.ensure_env_values(args) self.run_script(self.prereqs_install_sh) - self.run_script(self.env_vars_install_sh) self.run_script(self.node_install_sh) self.run_script(self.service_config_sh) self._check_gwx_mode() and self.run_script(self.nginx_proxy_wss_sh) From a8086675d9268207202f3281c9c036275aba7c49 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Wed, 12 Nov 2025 15:34:00 +0100 Subject: [PATCH 008/134] metadata port inside nymwg --- scripts/nym-node-setup/nym-node-prereqs-install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/nym-node-setup/nym-node-prereqs-install.sh b/scripts/nym-node-setup/nym-node-prereqs-install.sh index 63f3264ff0..58b04ecc65 100644 --- a/scripts/nym-node-setup/nym-node-prereqs-install.sh +++ b/scripts/nym-node-setup/nym-node-prereqs-install.sh @@ -24,6 +24,7 @@ ufw allow 8080/tcp # Nym specific - nym-node-api ufw allow 9000/tcp # Nym Specific - clients port ufw allow 9001/tcp # Nym specific - wss port ufw allow 51822/udp # WireGuard +ufw allow in on nymwg to any port 51830 proto tcp # bandwidth queries/topup - inside the tunnel ufw allow 'Nginx Full' && \ ufw reload && \ ufw status From 73a34935aef7b6acc3ce8dc4ba80a14fae371076 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Wed, 12 Nov 2025 16:29:52 +0100 Subject: [PATCH 009/134] trims --- scripts/nym-node-setup/nym-node-cli.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/scripts/nym-node-setup/nym-node-cli.py b/scripts/nym-node-setup/nym-node-cli.py index c4ef41ca95..a56d46e84c 100755 --- a/scripts/nym-node-setup/nym-node-cli.py +++ b/scripts/nym-node-setup/nym-node-cli.py @@ -267,10 +267,7 @@ class NodeSetupCLI: def _check_gwx_mode(self): """Helper: Several fns run only for GWx - this fn checks this condition""" - if self.mode == "exit-gateway": - return True - else: - return False + return self.mode == "exit-gateway" def check_wg_enabled(self, args=None): """Determine if WireGuard is enabled; precedence: CLI > env > env.sh > prompt. Persist normalized value.""" @@ -609,7 +606,7 @@ class ArgParser: version=f"nym-node-cli {__version__}" ) parent.add_argument("-d", "--dev", metavar="BRANCH", - help="Define github branch", + help="Define github branch (default: develop)", type=str, default=argparse.SUPPRESS) parent.add_argument("-v", "--verbose", action="store_true", @@ -625,7 +622,7 @@ class ArgParser: subparsers = parser.add_subparsers(dest="command", help="subcommands") subparsers.required = True - p_install = subparsers.add_parser( + install_parser = subparsers.add_parser( "install", parents=[parent], help="Starts nym-node installation setup CLI", aliases=["i", "I"], add_help=True @@ -636,7 +633,7 @@ class ArgParser: help="Node mode: 'mixnode', 'entry-gateway', or 'exit-gateway'", ) install_parser.add_argument( - "--wireguard", + "--wireguard-enabled", choices=["true", "false"], help="WireGuard functionality switch: true / false" ) From 5a26fa262e0f39b9d9fd2e9e3822822bff970554 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Wed, 12 Nov 2025 16:58:10 +0100 Subject: [PATCH 010/134] add uplink override arg --- scripts/nym-node-setup/nym-node-cli.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/nym-node-setup/nym-node-cli.py b/scripts/nym-node-setup/nym-node-cli.py index a56d46e84c..2732f36756 100755 --- a/scripts/nym-node-setup/nym-node-cli.py +++ b/scripts/nym-node-setup/nym-node-cli.py @@ -644,6 +644,7 @@ class ArgParser: install_parser.add_argument("--description", help="Short public description of the node") install_parser.add_argument("--public-ip", help="External IPv4 address (autodetected if omitted)") install_parser.add_argument("--nym-node-binary", help="URL for nym-node binary (autodetected if omitted)") + install_parser.add_argument("--uplink-dev", help="Override uplink interface used for NAT/FORWARD (e.g., 'eth0'; autodetected if omitted)") # generic fallback install_parser.add_argument( From 66797efa805b0260901d02ccea0c651638c5e0db Mon Sep 17 00:00:00 2001 From: benedettadavico Date: Wed, 12 Nov 2025 17:18:59 +0100 Subject: [PATCH 011/134] test new order of events.. --- .../wireguard-exit-policy-manager.sh | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh b/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh index b803cd65a3..5a31d8ed54 100644 --- a/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh +++ b/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh @@ -282,6 +282,16 @@ add_default_reject_rule() { apply_port_allowlist() { echo -e "${YELLOW}Applying allowed ports...${NC}" + # Insert DNS rules at the very beginning of NYM-EXIT chain, this ensures DNS queries are never blocked by REJECT rules + echo -e "${YELLOW}Ensuring DNS is at the beginning of $NYM_CHAIN...${NC}" + + iptables -I "$NYM_CHAIN" 1 -p udp --dport 53 -j ACCEPT + iptables -I "$NYM_CHAIN" 2 -p tcp --dport 53 -j ACCEPT + ip6tables -I "$NYM_CHAIN" 1 -p udp --dport 53 -j ACCEPT + ip6tables -I "$NYM_CHAIN" 2 -p tcp --dport 53 -j ACCEPT + + echo -e "${GREEN}✓ DNS rules inserted at beginning of $NYM_CHAIN${NC}" + # Dictionary of services and their ports declare -A PORT_MAPPINGS=( ["FTP"]="20-21" @@ -383,8 +393,6 @@ apply_port_allowlist() { add_port_rules ip6tables "$port" "udp" done - add_default_reject_rule - echo -e "${GREEN}Port allowlist applied successfully.${NC}" } @@ -643,8 +651,11 @@ main() { create_nym_chain setup_nat_rules configure_dns_and_icmp - apply_spamhaus_blocklist + # Apply allowlist first (so DNS and other allowed ports are not blocked) apply_port_allowlist + # Then apply blocklist (aka the REJECT rules) + apply_spamhaus_blocklist + add_default_reject_rule save_rules echo -e "${GREEN}Nym exit policy installed successfully.${NC}" ;; From 58083df0b092f96fce83a58b77917e676feed3da Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Wed, 12 Nov 2025 17:22:43 +0100 Subject: [PATCH 012/134] fix QUIC helper script --- .../nym-node-setup/quic_bridge_deployment.sh | 50 +++++++++++++++++-- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/scripts/nym-node-setup/quic_bridge_deployment.sh b/scripts/nym-node-setup/quic_bridge_deployment.sh index f7dc60e0f9..1d40958578 100644 --- a/scripts/nym-node-setup/quic_bridge_deployment.sh +++ b/scripts/nym-node-setup/quic_bridge_deployment.sh @@ -32,6 +32,7 @@ log() { # simple redirection that keeps function scope intact add_log_redirection() { + exec 3>&1 4>&2 exec > >(tee -a "$LOG_FILE") 2>&1 } add_log_redirection @@ -47,7 +48,17 @@ NYM_ETC_BRIDGES="$NYM_ETC_DIR/bridges.toml" NYM_ETC_CLIENT_PARAMS_DEFAULT="$NYM_ETC_DIR/client_bridge_params.json" SERVICE_FILE="/etc/systemd/system/nym-bridge.service" -NET_DEV="$(ip route show default 2>/dev/null | awk '/default/ {print $5}' || true)" +NET_DEV="${UPLINK_DEV:-}" +if [[ -z "$NET_DEV" ]]; then + NET_DEV="$(ip -o route show default 2>/dev/null | awk '{print $5}' | head -n1)" + [[ -z "$NET_DEV" ]] && NET_DEV="$(ip -o route show default table all 2>/dev/null | awk '{print $5}' | head -n1)" +fi +if [[ -z "$NET_DEV" ]]; then + echo -e "${RED}Cannot determine uplink interface. Set UPLINK_DEV.${RESET}" | tee -a "$LOG_FILE" + exit 1 +fi +info "Using uplink device: $NET_DEV" + WG_IFACE="nymwg" # Root check @@ -65,6 +76,11 @@ err() { echo -e "${RED}$1${RESET}"; } info() { echo -e "${CYAN}$1${RESET}"; } press_enter() { read -r -p "$1"; } +# Disable pauses for noninteractive mode +if [[ "${NONINTERACTIVE:-0}" == "1" ]]; then + press_enter() { :; } +fi + # Helper: detect dpkg dependency failure for libc6>=2.34 deb_depends_libc_too_old() { local v @@ -377,6 +393,11 @@ User=root ExecStart=$BRIDGE_BIN --config $NYM_ETC_BRIDGES Restart=on-failure RestartSec=5 +LimitNOFILE=65535 +ProtectSystem=full +ProtectHome=yes +PrivateTmp=yes + [Install] WantedBy=multi-user.target @@ -391,12 +412,26 @@ EOF # IPTABLES & helpers apply_bridge_iptables_rules() { title "Applying iptables rules" - iptables -I INPUT -i "$WG_IFACE" -j ACCEPT || true - ip6tables -I INPUT -i "$WG_IFACE" -j ACCEPT || true - iptables -t nat -A POSTROUTING -o "$NET_DEV" -j MASQUERADE || true - ip6tables -t nat -A POSTROUTING -o "$NET_DEV" -j MASQUERADE || true + + # Ensure stateful rules exist + iptables -C FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || \ + iptables -I FORWARD 1 -m state --state RELATED,ESTABLISHED -j ACCEPT + ip6tables -C FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || \ + ip6tables -I FORWARD 1 -m state --state RELATED,ESTABLISHED -j ACCEPT + + # Allow WG interface input + iptables -C INPUT -i "$WG_IFACE" -j ACCEPT 2>/dev/null || iptables -I INPUT -i "$WG_IFACE" -j ACCEPT + ip6tables -C INPUT -i "$WG_IFACE" -j ACCEPT 2>/dev/null || ip6tables -I INPUT -i "$WG_IFACE" -j ACCEPT + + # NAT (idempotent) + iptables -t nat -C POSTROUTING -o "$NET_DEV" -j MASQUERADE 2>/dev/null || \ + iptables -t nat -I POSTROUTING 1 -o "$NET_DEV" -j MASQUERADE + ip6tables -t nat -C POSTROUTING -o "$NET_DEV" -j MASQUERADE 2>/dev/null || \ + ip6tables -t nat -I POSTROUTING 1 -o "$NET_DEV" -j MASQUERADE + iptables-save > /etc/iptables/rules.v4 ip6tables-save > /etc/iptables/rules.v6 + ok "iptables rules applied." } @@ -404,6 +439,9 @@ configure_dns_and_icmp() { title "Allow ICMP and DNS" iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT || true ip6tables -A INPUT -p ipv6-icmp -j ACCEPT || true + iptables -C INPUT -p udp --dport 53 -j ACCEPT 2>/dev/null || iptables -I INPUT -p udp --dport 53 -j ACCEPT + ip6tables -C INPUT -p udp --dport 53 -j ACCEPT 2>/dev/null || ip6tables -I INPUT -p udp --dport 53 -j ACCEPT + ok "ICMP and DNS rules applied." } @@ -429,6 +467,8 @@ full_bridge_setup() { echo "" echo "Step 2/6: Installing bridge binary..." install_bridge_binary + echo "[Bridge Install] $(date '+%F %T') $( $BRIDGE_BIN --version 2>/dev/null || echo 'nym-bridge (unknown)')" \ + >> /var/log/nym-bridge-version.log press_enter "Press Enter to continue..." echo "" From 781afd35226f3f3d83bf306530687e9537a0fb65 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Wed, 12 Nov 2025 17:29:47 +0100 Subject: [PATCH 013/134] add arg --- scripts/nym-node-setup/nym-node-cli.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/nym-node-setup/nym-node-cli.py b/scripts/nym-node-setup/nym-node-cli.py index 2732f36756..0fe9fa64e0 100755 --- a/scripts/nym-node-setup/nym-node-cli.py +++ b/scripts/nym-node-setup/nym-node-cli.py @@ -580,6 +580,9 @@ class NodeSetupCLI: def run_node_installation(self,args): """Main function called by argparser command install running full node install flow""" self.ensure_env_values(args) + # Pass uplink override to all helper scripts if provided + if getattr(args, "uplink_dev", None): + os.environ["UPLINK_DEV"] = args.uplink_dev self.run_script(self.prereqs_install_sh) self.run_script(self.node_install_sh) self.run_script(self.service_config_sh) From c503a5f0e8b0dce88fe0fb84e02b783542be4b73 Mon Sep 17 00:00:00 2001 From: benedettadavico Date: Thu, 13 Nov 2025 10:21:37 +0100 Subject: [PATCH 014/134] few more tweaks --- .../wireguard-exit-policy-manager.sh | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh b/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh index 5a31d8ed54..f3288b6204 100644 --- a/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh +++ b/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh @@ -290,7 +290,12 @@ apply_port_allowlist() { ip6tables -I "$NYM_CHAIN" 1 -p udp --dport 53 -j ACCEPT ip6tables -I "$NYM_CHAIN" 2 -p tcp --dport 53 -j ACCEPT - echo -e "${GREEN}✓ DNS rules inserted at beginning of $NYM_CHAIN${NC}" + # ICMP is needed because the probe tests DNS by pinging hostnames + iptables -I "$NYM_CHAIN" 3 -p icmp --icmp-type echo-request -j ACCEPT + iptables -I "$NYM_CHAIN" 4 -p icmp --icmp-type echo-reply -j ACCEPT + ip6tables -I "$NYM_CHAIN" 3 -p ipv6-icmp -j ACCEPT + + echo -e "${GREEN}✓ DNS and ICMP rules inserted at beginning of $NYM_CHAIN${NC}" # Dictionary of services and their ports declare -A PORT_MAPPINGS=( @@ -368,17 +373,18 @@ apply_port_allowlist() { ["Lightning"]="9735" ["NDMP"]="10000" ["OpenPGP"]="11371" - ["Monero"]="18080-18081" - ["MoneroRPC"]="18089" + ["Monero"]="18080-18081" + ["MoneroRPC"]="18089" ["GoogleVoice"]="19294" ["EnsimControlPanel"]="19638" - ["DarkFiTor"]="25551" + ["DarkFiTor"]="25551" ["Minecraft"]="25565" - ["DarkFi"]="26661" + ["DarkFi"]="26661" ["Steam"]="27000-27050" ["ElectrumSSL"]="50002" ["MOSH"]="60000-61000" ["Mumble"]="64738" + ["Metadata"]="51830" ) # Add TCP and UDP rules for each allowed port From 010b013094749db6fb3cbe04c5955b84ca9ffbf4 Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 10:17:04 +0000 Subject: [PATCH 015/134] comment fix Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/nym-node-cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nym-node-setup/nym-node-cli.py b/scripts/nym-node-setup/nym-node-cli.py index 0fe9fa64e0..590717ab2c 100755 --- a/scripts/nym-node-setup/nym-node-cli.py +++ b/scripts/nym-node-setup/nym-node-cli.py @@ -275,7 +275,7 @@ class NodeSetupCLI: env_file = os.path.join(os.getcwd(), "env.sh") def norm(v): - return "true" if str(v).strip().lower() == ("true") else "false" + return "true" if str(v).strip().lower() == "true" else "false" val = None From ef52f25564500fe449dea2954c523009585694f2 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 11:20:13 +0100 Subject: [PATCH 016/134] address comment --- scripts/nym-node-setup/nym-node-cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nym-node-setup/nym-node-cli.py b/scripts/nym-node-setup/nym-node-cli.py index 590717ab2c..6a3f84540a 100755 --- a/scripts/nym-node-setup/nym-node-cli.py +++ b/scripts/nym-node-setup/nym-node-cli.py @@ -158,7 +158,7 @@ class NodeSetupCLI: print("Invalid mode. Must be one of: mixnode, entry-gateway, exit-gateway.") raise SystemExit(1) - self._upsert_env_vars("MODE", mode) + self._upsert_env_vars({"MODE": mode}) print(f"Mode set to '{mode}' — stored in env.sh and sourced for immediate use.") return mode From 34a500d0a28c9013fe77b4a8175c3badf6224938 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 14:26:49 +0100 Subject: [PATCH 017/134] refactor completely --- scripts/network_tunnel_manager.sh | 290 -------- .../nym-node-setup/network-tunnel-manager.sh | 0 .../exit-policy-tests.sh | 306 -------- .../validate-exit-blocking-test.sh | 40 - .../wireguard-exit-policy-manager.sh | 699 ------------------ 5 files changed, 1335 deletions(-) delete mode 100644 scripts/network_tunnel_manager.sh create mode 100644 scripts/nym-node-setup/network-tunnel-manager.sh delete mode 100644 scripts/wireguard-exit-policy/exit-policy-tests.sh delete mode 100644 scripts/wireguard-exit-policy/validate-exit-blocking-test.sh delete mode 100644 scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh diff --git a/scripts/network_tunnel_manager.sh b/scripts/network_tunnel_manager.sh deleted file mode 100644 index 58eff34565..0000000000 --- a/scripts/network_tunnel_manager.sh +++ /dev/null @@ -1,290 +0,0 @@ -#!/bin/bash - -network_device=$(ip route show default | awk '/default/ {print $5}') -tunnel_interface="nymtun0" -wg_tunnel_interface="nymwg" - -if ! dpkg -s iptables-persistent >/dev/null 2>&1; then - sudo apt-get update - sudo apt-get install -y iptables-persistent -else - echo "iptables-persistent is already installed." -fi - -fetch_ipv6_address() { - local interface=$1 - ipv6_global_address=$(ip -6 addr show "$interface" scope global | grep inet6 | awk '{print $2}' | head -n 1) - - if [[ -z "$ipv6_global_address" ]]; then - echo "no globally routable IPv6 address found on $interface. Please configure IPv6 or check your network settings." - exit 1 - else - echo "using IPv6 address: $ipv6_global_address" - fi -} - -fetch_and_display_ipv6() { - ipv6_address=$(ip -6 addr show "$network_device" scope global | grep inet6 | awk '{print $2}') - if [[ -z "$ipv6_address" ]]; then - echo "no global IPv6 address found on $network_device." - else - echo "IPv6 address on $network_device: $ipv6_address" - fi -} - -remove_duplicate_rules() { - local interface=$1 - local script_name=$(basename "$0") - - if [[ -z "$interface" ]]; then - echo "error: no interface specified. please enter the interface (nymwg or nymtun0):" - read -r interface - fi - - if [[ "$interface" != "nymwg" && "$interface" != "nymtun0" ]]; then - echo "error: invalid interface '$interface'. allowed values are 'nymwg' or 'nymtun0'." >&2 - exit 1 - fi - - echo "removing duplicate rules for $interface..." - - iptables-save | grep "$interface" | while read -r line; do - sudo iptables -D ${line#-A } || echo "Failed to delete rule: $line" - done - - ip6tables-save | grep "$interface" | while read -r line; do - sudo ip6tables -D ${line#-A } || echo "Failed to delete rule: $line" - done - - echo "duplicates removed for $interface." - echo "!!-important-!! you need to now reapply the iptables rules for $interface." - if [ "$interface" == "nymwg" ]; then - echo "run: ./$script_name apply_iptables_rules_wg" - else - echo "run: ./$script_name apply_iptables_rules" - fi -} - -adjust_ip_forwarding() { - ipv6_forwarding_setting="net.ipv6.conf.all.forwarding=1" - ipv4_forwarding_setting="net.ipv4.ip_forward=1" - - # remove duplicate entries for these settings from the file - sudo sed -i "/^net.ipv6.conf.all.forwarding=/d" /etc/sysctl.conf - sudo sed -i "/^net.ipv4.ip_forward=/d" /etc/sysctl.conf - - echo "$ipv6_forwarding_setting" | sudo tee -a /etc/sysctl.conf - echo "$ipv4_forwarding_setting" | sudo tee -a /etc/sysctl.conf - - sudo sysctl -p /etc/sysctl.conf - -} - -apply_iptables_rules() { - local interface=$1 - echo "applying IPtables rules for $interface..." - sleep 2 - - sudo iptables -t nat -A POSTROUTING -o "$network_device" -j MASQUERADE - sudo iptables -A FORWARD -i "$interface" -o "$network_device" -j ACCEPT - sudo iptables -A FORWARD -i "$network_device" -o "$interface" -m state --state RELATED,ESTABLISHED -j ACCEPT - - sudo ip6tables -t nat -A POSTROUTING -o "$network_device" -j MASQUERADE - sudo ip6tables -A FORWARD -i "$interface" -o "$network_device" -j ACCEPT - sudo ip6tables -A FORWARD -i "$network_device" -o "$interface" -m state --state RELATED,ESTABLISHED -j ACCEPT - - sudo iptables-save | sudo tee /etc/iptables/rules.v4 - sudo ip6tables-save | sudo tee /etc/iptables/rules.v6 -} - -check_tunnel_iptables() { - local interface=$1 - echo "inspecting IPtables rules for $interface..." - echo "---------------------------------------" - echo "IPv4 rules:" - iptables -L FORWARD -v -n | awk -v dev="$interface" '/^Chain FORWARD/ || $0 ~ dev || $0 ~ "ufw-reject-forward"' - echo "---------------------------------------" - echo "IPv6 rules:" - ip6tables -L FORWARD -v -n | awk -v dev="$interface" '/^Chain FORWARD/ || $0 ~ dev || $0 ~ "ufw6-reject-forward"' -} - -check_ipv6_ipv4_forwarding() { - result_ipv4=$(cat /proc/sys/net/ipv4/ip_forward) - result_ipv6=$(cat /proc/sys/net/ipv6/conf/all/forwarding) - echo "IPv4 forwarding is $([ "$result_ipv4" == "1" ] && echo "enabled" || echo "not enabled")." - echo "IPv6 forwarding is $([ "$result_ipv6" == "1" ] && echo "enabled" || echo "not enabled")." -} - -check_ip_routing() { - echo "IPv4 routing table:" - ip route - echo "---------------------------------------" - echo "IPv6 routing table:" - ip -6 route -} - -perform_pings() { - echo "performing IPv4 ping to google.com..." - ping -c 4 google.com - echo "---------------------------------------" - echo "performing IPv6 ping to google.com..." - ping6 -c 4 google.com -} - -joke_through_tunnel() { - local interface=$1 - local green="\033[0;32m" - local reset="\033[0m" - local red="\033[0;31m" - local yellow="\033[0;33m" - - sleep 1 - echo - echo -e "${yellow}checking tunnel connectivity and fetching a joke for $interface...${reset}" - echo -e "${yellow}if these test succeeds, it confirms your machine can reach the outside world via IPv4 and IPv6.${reset}" - echo -e "${yellow}however, probes and external clients may experience different connectivity to your nym-node.${reset}" - - ipv4_address=$(ip addr show "$interface" | awk '/inet / {print $2}' | cut -d'/' -f1) - ipv6_address=$(ip addr show "$interface" | awk '/inet6 / && $2 !~ /^fe80/ {print $2}' | cut -d'/' -f1) - - if [[ -z "$ipv4_address" && -z "$ipv6_address" ]]; then - echo -e "${red}no IP address found on $interface. unable to fetch a joke.${reset}" - echo -e "${red}please verify your tunnel configuration and ensure the interface is up.${reset}" - return 1 - fi - - if [[ -n "$ipv4_address" ]]; then - echo - echo -e "------------------------------------" - echo -e "detected IPv4 address: $ipv4_address" - echo -e "testing IPv4 connectivity..." - echo - - if ping -c 1 -I "$ipv4_address" google.com >/dev/null 2>&1; then - echo -e "${green}IPv4 connectivity is working. fetching a joke...${reset}" - joke=$(curl -s -H "Accept: application/json" --interface "$ipv4_address" https://icanhazdadjoke.com/ | jq -r .joke) - [[ -n "$joke" && "$joke" != "null" ]] && echo -e "${green}IPv4 joke: $joke${reset}" || echo -e "failed to fetch a joke via IPv4." - else - echo -e "${red}IPv4 connectivity is not working for $interface. verify your routing and NAT settings.${reset}" - fi - else - echo -e "${red}no IPv4 address found on $interface. unable to fetch a joke via IPv4.${reset}" - fi - - if [[ -n "$ipv6_address" ]]; then - echo - echo -e "------------------------------------" - echo -e "detected IPv6 address: $ipv6_address" - echo -e "testing IPv6 connectivity..." - echo - - if ping6 -c 1 -I "$ipv6_address" google.com >/dev/null 2>&1; then - echo -e "${green}IPv6 connectivity is working. fetching a joke...${reset}" - joke=$(curl -s -H "Accept: application/json" --interface "$ipv6_address" https://icanhazdadjoke.com/ | jq -r .joke) - [[ -n "$joke" && "$joke" != "null" ]] && echo -e "${green}IPv6 joke: $joke${reset}" || echo -e "${red}failed to fetch a joke via IPv6.${reset}" - else - echo -e "${red}IPv6 connectivity is not working for $interface. verify your routing and NAT settings.${reset}" - fi - else - echo -e "${red}no IPv6 address found on $interface. unable to fetch a joke via IPv6.${reset}" - fi - - echo -e "${green}joke fetching processes completed for $interface.${reset}" - echo -e "------------------------------------" - - sleep 3 - echo - echo - echo -e "${yellow}### connectivity testing recommendations ###${reset}" - echo -e "${yellow}- use the following command to test WebSocket connectivity from an external client:${reset}" - echo -e "${yellow} wscat -c wss://:9001 ${reset}" - echo -e "${yellow}- test UDP connectivity on port 51822 (commonly used for nym wireguard) ${reset}" - echo -e "${yellow} from another machine, use tools like nc or socat to send UDP packets ${reset}" - echo -e "${yellow} echo 'test message' | nc -u 51822 ${reset}" - echo -e "${yellow}if connectivity issues persist, ensure port forwarding and firewall rules are correctly configured ${reset}" - echo -} - - -configure_dns_and_icmp_wg() { - echo "allowing icmp (ping)..." - sudo iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT - sudo iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT - - echo "allowing dns over udp (port 53)..." - sudo iptables -A INPUT -p udp --dport 53 -j ACCEPT - - echo "allowing dns over tcp (port 53)..." - sudo iptables -A INPUT -p tcp --dport 53 -j ACCEPT - - echo "saving iptables rules..." - sudo iptables-save >/etc/iptables/rules.v4 - - echo "dns and icmp configuration completed." -} - -case "$1" in -fetch_ipv6_address_nym_tun) - fetch_ipv6_address "$tunnel_interface" - ;; -fetch_and_display_ipv6) - fetch_and_display_ipv6 - ;; -apply_iptables_rules) - apply_iptables_rules "$tunnel_interface" - ;; -apply_iptables_rules_wg) - apply_iptables_rules "$wg_tunnel_interface" - ;; -check_nymtun_iptables) - check_tunnel_iptables "$tunnel_interface" - ;; -check_nym_wg_tun) - check_tunnel_iptables "$wg_tunnel_interface" - ;; -check_ipv6_ipv4_forwarding) - check_ipv6_ipv4_forwarding - ;; -check_ip_routing) - check_ip_routing - ;; -perform_pings) - perform_pings - ;; -joke_through_the_mixnet) - joke_through_tunnel "$tunnel_interface" - ;; -joke_through_wg_tunnel) - joke_through_tunnel "$wg_tunnel_interface" - ;; -configure_dns_and_icmp_wg) - configure_dns_and_icmp_wg - ;; -adjust_ip_forwarding) - adjust_ip_forwarding - ;; -remove_duplicate_rules) - remove_duplicate_rules "$2" - ;; -*) - echo "Usage: $0 [command]" - echo "Commands:" - echo " fetch_ipv6_address_nym_tun - Fetch IPv6 for nymtun0." - echo " fetch_and_display_ipv6 - Show IPv6 on default device." - echo " apply_iptables_rules - Apply IPtables rules for nymtun0." - echo " apply_iptables_rules_wg - Apply IPtables rules for nymwg." - echo " check_nymtun_iptables - Check IPtables for nymtun0." - echo " check_nym_wg_tun - Check IPtables for nymwg." - echo " check_ipv6_ipv4_forwarding - Check IPv4 and IPv6 forwarding." - echo " check_ip_routing - Display IP routing tables." - echo " perform_pings - Test IPv4 and IPv6 connectivity." - echo " joke_through_the_mixnet - Fetch a joke via nymtun0." - echo " joke_through_wg_tunnel - Fetch a joke via nymwg." - echo " configure_dns_and_icmp_wg - Allows icmp ping tests for probes alongside configuring dns" - echo " adjust_ip_forwarding - Enable IPV6 and IPV4 forwarding" - echo " remove_duplicate_rules - Remove duplicate iptables rules. Valid interfaces: nymwg, nymtun0" - exit 1 - ;; -esac - -echo "operation $1 completed successfully." diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh new file mode 100644 index 0000000000..e69de29bb2 diff --git a/scripts/wireguard-exit-policy/exit-policy-tests.sh b/scripts/wireguard-exit-policy/exit-policy-tests.sh deleted file mode 100644 index e0f86e5969..0000000000 --- a/scripts/wireguard-exit-policy/exit-policy-tests.sh +++ /dev/null @@ -1,306 +0,0 @@ -#!/bin/bash -# Nym Exit Policy Verification Unit Tests - -GREEN='\033[0;32m' -RED='\033[0;31m' -YELLOW='\033[0;33m' -NC='\033[0m' - -NYM_CHAIN="NYM-EXIT" -WG_INTERFACE="nymwg" - -check_port_range_rules() { - local port_range="$1" - local protocol="${2:-tcp}" - local chain="${3:-$NYM_CHAIN}" - - # Extract start and end ports - local start_port=$(echo "$port_range" | cut -d'-' -f1) - local end_port=$(echo "$port_range" | cut -d'-' -f2) - - if iptables -t filter -C "$chain" -p "$protocol" --dport "$start_port:$end_port" -j ACCEPT 2>/dev/null; then - echo -e "${GREEN}✓ Rule exists: $chain $protocol port range $start_port:$end_port${NC}" - return 0 - else - echo -e "${RED}✗ Rule missing: $chain $protocol port range $start_port:$end_port${NC}" - - echo -e "${YELLOW}Dumping all rules in $chain:${NC}" - iptables -L "$chain" -n | grep "$protocol" - - return 1 - fi -} - -# Test port range rules -test_port_range_rules() { - echo -e "${YELLOW}Testing Port Range Rules...${NC}" - - # Select the essential port ranges for testing - local port_ranges=( - "20-21:tcp:FTP" - "80-81:tcp:HTTP" - "2082-2083:tcp:CPanel" - "5222-5223:tcp:XMPP" - "27000-27050:tcp:Steam (sampling)" - "989-990:tcp:FTP over TLS" - "5000-5005:tcp:RTP/VoIP" - "8087-8088:tcp:Simplify Media" - "8232-8233:tcp:Zcash" - "8332-8333:tcp:Bitcoin" - "18080-18081:tcp:Monero" - ) - - local total_failures=0 - - for range in "${port_ranges[@]}"; do - IFS=':' read -r port_range protocol service <<< "$range" - - # Extract start and end ports - local start_port=$(echo "$port_range" | cut -d'-' -f1) - local end_port=$(echo "$port_range" | cut -d'-' -f2) - - echo -e "${YELLOW}Testing $service $protocol port range $port_range${NC}" - - if iptables -t filter -C "$NYM_CHAIN" -p "$protocol" --dport "$start_port:$end_port" -j ACCEPT 2>/dev/null; then - echo -e "${GREEN}✓ Rule exists: $NYM_CHAIN $protocol port range $start_port:$end_port${NC}" - else - echo -e "${RED}✗ Rule missing: $NYM_CHAIN $protocol port range $start_port:$end_port${NC}" - ((total_failures++)) - - echo -e "${YELLOW}Existing rules for protocol $protocol:${NC}" - iptables -L "$NYM_CHAIN" -n | grep "$protocol" - fi - done - - if [ $total_failures -eq 0 ]; then - return 0 - else - return 1 - fi -} - -test_critical_services() { - echo -e "${YELLOW}Testing Critical Service Rules...${NC}" - - local tcp_services=( - 22 # SSH - 53 # DNS - 443 # HTTPS - 853 # DNS over TLS - 1194 # OpenVPN - ) - - local udp_services=( - 53 # DNS - 123 # NTP - 1194 # OpenVPN - ) - - local failures=0 - - # Test TCP services - for port in "${tcp_services[@]}"; do - local rule_found=false - - # First check for exact match - if iptables -t filter -C "$NYM_CHAIN" -p tcp --dport "$port" -j ACCEPT 2>/dev/null; then - echo -e "${GREEN}✓ Rule exists: NYM-EXIT tcp port $port${NC}" - rule_found=true - else - # If not found as exact port, search for it in port ranges - # This checks if the port is covered by any range rule - if iptables-save | grep -E "^-A $NYM_CHAIN.*tcp.*dpts:" | grep -qP "dpts:(\d+:)?$port(:|\d+)" || \ - iptables-save | grep -E "^-A $NYM_CHAIN.*tcp.*dpts:" | grep -qP "dpts:$port:"; then - echo -e "${GREEN}✓ Rule exists: NYM-EXIT tcp port $port (covered by a range rule)${NC}" - rule_found=true - else - echo -e "${RED}✗ Rule missing: NYM-EXIT tcp port $port${NC}" - ((failures++)) - fi - fi - done - - # Test UDP services - similar approach - for port in "${udp_services[@]}"; do - local rule_found=false - - if iptables -t filter -C "$NYM_CHAIN" -p udp --dport "$port" -j ACCEPT 2>/dev/null; then - echo -e "${GREEN}✓ Rule exists: NYM-EXIT udp port $port${NC}" - rule_found=true - else - # If not found as exact port, search for it in port ranges - if iptables-save | grep -E "^-A $NYM_CHAIN.*udp.*dpts:" | grep -qP "dpts:(\d+:)?$port(:|\d+)" || \ - iptables-save | grep -E "^-A $NYM_CHAIN.*udp.*dpts:" | grep -qP "dpts:$port:"; then - echo -e "${GREEN}✓ Rule exists: NYM-EXIT udp port $port (covered by a range rule)${NC}" - rule_found=true - else - echo -e "${RED}✗ Rule missing: NYM-EXIT udp port $port${NC}" - ((failures++)) - fi - fi - done - - echo -e "${YELLOW}Relevant existing rules for HTTP (port 80):${NC}" - iptables-save | grep -E "$NYM_CHAIN.*tcp" | grep -E "(dpt|dpts):.*80" - - return $failures -} - -# Test that the exit policy chain is correctly wired up to FORWARD chain -test_forward_chain_hook() { - echo -e "${YELLOW}Testing FORWARD Chain Hook...${NC}" - - local failures=0 - NETWORK_DEVICE=$(ip route show default | awk '/default/ {print $5}') - - if [[ -z "$NETWORK_DEVICE" ]]; then - echo -e "${RED}✗ Could not determine network device${NC}" - return 1 - fi - - # (incoming from nymwg, outgoing to network device) - if iptables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null; then - echo -e "${GREEN}✓ IPv4 FORWARD hook exists with correct direction: -i $WG_INTERFACE -o $NETWORK_DEVICE${NC}" - else - echo -e "${RED}✗ IPv4 FORWARD hook missing or has wrong direction${NC}" - echo -e "${YELLOW} Expected: -i $WG_INTERFACE -o $NETWORK_DEVICE -j $NYM_CHAIN${NC}" - - # Check if wrong direction exists - if iptables -C FORWARD -o "$WG_INTERFACE" -j "$NYM_CHAIN" 2>/dev/null; then - echo -e "${RED}✗ WRONG DIRECTION FOUND: -o $WG_INTERFACE (this matches return traffic, not client egress!)${NC}" - fi - - # Show what actually exists - specifically look for jump rules to NYM-EXIT - echo -e "${YELLOW} Current FORWARD rules that jump to $NYM_CHAIN:${NC}" - iptables -L FORWARD -n -v --line-numbers | grep -E "$NYM_CHAIN" || echo " (none found - exit policy chain is not hooked to FORWARD!)" - echo -e "${YELLOW} All FORWARD rules with $WG_INTERFACE (for reference):${NC}" - iptables -L FORWARD -n -v --line-numbers | grep -E "$WG_INTERFACE" | head -5 || echo " (none found)" - ((failures++)) - fi - - # Check IPv6 - if ip6tables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null; then - echo -e "${GREEN}✓ IPv6 FORWARD hook exists with correct direction: -i $WG_INTERFACE -o $NETWORK_DEVICE${NC}" - else - echo -e "${RED}✗ IPv6 FORWARD hook missing or has wrong direction${NC}" - echo -e "${YELLOW} Expected: -i $WG_INTERFACE -o $NETWORK_DEVICE -j $NYM_CHAIN${NC}" - - # Check if wrong direction exists - if ip6tables -C FORWARD -o "$WG_INTERFACE" -j "$NYM_CHAIN" 2>/dev/null; then - echo -e "${RED}✗ WRONG DIRECTION FOUND: -o $WG_INTERFACE (this matches return traffic, not client egress!)${NC}" - fi - - # Show what actually exists - specifically look for jump rules to NYM-EXIT - echo -e "${YELLOW} Current IPv6 FORWARD rules that jump to $NYM_CHAIN:${NC}" - ip6tables -L FORWARD -n -v --line-numbers | grep -E "$NYM_CHAIN" || echo " (none found - exit policy chain is not hooked to FORWARD!)" - echo -e "${YELLOW} All IPv6 FORWARD rules with $WG_INTERFACE (for reference):${NC}" - ip6tables -L FORWARD -n -v --line-numbers | grep -E "$WG_INTERFACE" | head -5 || echo " (none found)" - ((failures++)) - fi - - # Check rule position (should be before UFW rules) - local rule_num=$(iptables -L FORWARD -n --line-numbers | grep -E "$NYM_CHAIN.*$WG_INTERFACE.*$NETWORK_DEVICE" | awk '{print $1}' | head -1) - if [[ -n "$rule_num" ]]; then - if [[ $rule_num -le 5 ]]; then - echo -e "${GREEN}✓ Rule is early in FORWARD chain (position #$rule_num) - good for UFW compatibility${NC}" - else - echo -e "${YELLOW}⚠ Rule is later in FORWARD chain (position #$rule_num) - may conflict with UFW${NC}" - fi - fi - - return $failures -} - -# Verify default reject rule exists -test_default_reject_rule() { - echo -e "${YELLOW}This test takes some time, do not quit the process${NC}" - echo - echo -e "${YELLOW}Testing Default Reject Rule...${NC}" - - # Try different patterns to detect the reject rule - if iptables -L "$NYM_CHAIN" | grep -q "REJECT.*all.*anywhere.*anywhere.*reject-with"; then - echo -e "${GREEN}✓ Default REJECT rule exists${NC}" - return 0 - elif iptables -L "$NYM_CHAIN" | grep -q "REJECT.*all -- .*everywhere.*everywhere"; then - echo -e "${GREEN}✓ Default REJECT rule exists${NC}" - return 0 - elif iptables -L "$NYM_CHAIN" | grep -q "REJECT.*all.*0.0.0.0/0.*0.0.0.0/0"; then - echo -e "${GREEN}✓ Default REJECT rule exists${NC}" - return 0 - elif iptables -n -L "$NYM_CHAIN" | grep -qE "REJECT.*all.*0.0.0.0/0.*0.0.0.0/0"; then - echo -e "${GREEN}✓ Default REJECT rule exists${NC}" - return 0 - elif iptables -L "$NYM_CHAIN" | tail -1 | grep -q "REJECT"; then - echo -e "${GREEN}✓ Default REJECT rule exists at the end of chain${NC}" - return 0 - else - echo -e "${RED}✗ Default REJECT rule missing${NC}" - # Display the last 3 rules in the chain for debugging - echo -e "${YELLOW}Last 3 rules in the chain:${NC}" - iptables -L "$NYM_CHAIN" | tail -3 - return 1 - fi -} - -run_all_tests() { - local total_failures=0 - local total_tests=0 - local skip_default_reject=false - - # Parse arguments - while [[ $# -gt 0 ]]; do - case "$1" in - --skip-default-reject) - skip_default_reject=true - shift - ;; - *) - echo -e "${RED}Unknown argument: $1${NC}" - exit 1 - ;; - esac - done - - local test_functions=( - "test_forward_chain_hook" - "test_port_range_rules" - "test_critical_services" - ) - - if [ "$skip_default_reject" = false ]; then - test_functions+=("test_default_reject_rule") - fi - - echo -e "${YELLOW}Running Nym Exit Policy Verification Tests...${NC}" - - for test_func in "${test_functions[@]}"; do - ((total_tests++)) - $test_func - if [ $? -ne 0 ]; then - ((total_failures++)) - echo -e "${RED}Test $test_func FAILED${NC}" - else - echo -e "${GREEN}Test $test_func PASSED${NC}" - fi - done - - echo -e "\n${YELLOW}Test Summary:${NC}" - echo -e "Total Tests: $total_tests" - echo -e "Failures: $total_failures" - - if [ $total_failures -eq 0 ]; then - echo -e "${GREEN}All Tests Passed Successfully!${NC}" - exit 0 - else - echo -e "${RED}Some Tests Failed. Please review the iptables configuration.${NC}" - exit 1 - fi -} - -if [[ $EUID -ne 0 ]]; then - echo -e "${RED}This script must be run as root${NC}" - exit 1 -fi - -# Run the tests -run_all_tests "$@" diff --git a/scripts/wireguard-exit-policy/validate-exit-blocking-test.sh b/scripts/wireguard-exit-policy/validate-exit-blocking-test.sh deleted file mode 100644 index e93d28a24f..0000000000 --- a/scripts/wireguard-exit-policy/validate-exit-blocking-test.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash - -validate_exit_policy() { - echo "=== Nym Exit Policy Blocking Validation ===" - - # Check iptables rules - echo "Checking iptables NYM-EXIT chain:" - sudo iptables -L NYM-EXIT -v -n - - # Test IP ranges and individual IPs - test_ips=( - "5.188.10.0/24" # Blocked network range - "31.132.36.50" # Specific blocked IP - "37.9.42.100" # Another blocked IP - ) - - for target in "${test_ips[@]}"; do - echo -e "\n\e[33mTesting blocking for $target\e[0m" - - # Multiple connection test methods - methods=( - "ping -c 4 -W 2" - "curl -m 5 http://$target" - "nc -z -w 5 $target 80" - "telnet $target 80" - ) - - for method in "${methods[@]}"; do - echo -n "Testing with $method: " - if sudo timeout 5 $method >/dev/null 2>&1; then - echo -e "\e[31mFAILED: Connection succeeded (Blocking ineffective)\e[0m" - else - echo -e "\e[32mBLOCKED\e[0m" - fi - done - done -} - -# Run the test -validate_exit_policy \ No newline at end of file diff --git a/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh b/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh deleted file mode 100644 index f3288b6204..0000000000 --- a/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh +++ /dev/null @@ -1,699 +0,0 @@ -#!/bin/bash -# -# Nym Wireguard Exit Policy Manager -# Version: 1.0.0 -# -# This script manages iptables rules for Nym Wireguard exit policies -# Features: -# - Implements the Nym exit policy from official documentation -# - Makes rules persistent across reboots -# - Provides commands to inspect and manage rules -# - Groups rules logically for easier management -# - Integrates with existing Nym node configuration -# -# Usage: ./wireguard-exit-policy-manager.sh [command] - -set -e - -NETWORK_DEVICE=$(ip route show default | awk '/default/ {print $5}') -WG_INTERFACE="nymwg" -NYM_CHAIN="NYM-EXIT" -POLICY_FILE="/etc/nym/exit-policy.txt" -EXIT_POLICY_LOCATION="https://nymtech.net/.wellknown/network-requester/exit-policy.txt" - -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[0;33m' -NC='\033[0m' - -add_port_rules() { - local chain="$1" - local port="$2" - local protocol="${3:-tcp}" - - # Check if the port contains a range - if [[ "$port" == *"-"* ]]; then - # Port range handling - add as a single rule with a range - local start_port=$(echo "$port" | cut -d'-' -f1) - local end_port=$(echo "$port" | cut -d'-' -f2) - - if ! $chain -C "$NYM_CHAIN" -p "$protocol" --dport "$start_port:$end_port" -j ACCEPT 2>/dev/null; then - $chain -A "$NYM_CHAIN" -p "$protocol" --dport "$start_port:$end_port" -j ACCEPT - echo -e " ${GREEN}Added: $NYM_CHAIN $protocol port range $start_port:$end_port${NC}" - fi - else - # Single port handling - if ! $chain -C "$NYM_CHAIN" -p "$protocol" --dport "$port" -j ACCEPT 2>/dev/null; then - $chain -A "$NYM_CHAIN" -p "$protocol" --dport "$port" -j ACCEPT - echo -e " ${GREEN}Added: $NYM_CHAIN $protocol port $port${NC}" - fi - fi -} - -install_dependencies() { - if ! dpkg -s iptables-persistent >/dev/null 2>&1; then - echo -e "${YELLOW}Installing iptables-persistent...${NC}" - apt-get update - DEBIAN_FRONTEND=noninteractive apt-get install -y iptables-persistent - echo -e "${GREEN}iptables-persistent installed.${NC}" - else - echo -e "${GREEN}iptables-persistent is already installed.${NC}" - fi - - # Check for other required dependencies - for cmd in iptables ip6tables ip grep sed awk wget curl; do - if ! command -v "$cmd" &>/dev/null; then - echo -e "${YELLOW}Installing $cmd...${NC}" - apt-get install -y "$cmd" - fi - done -} - -configure_ip_forwarding() { - echo -e "${YELLOW}Configuring IP forwarding...${NC}" - - # Remove any existing forwarding settings to avoid duplicates - sed -i "/^net.ipv6.conf.all.forwarding=/d" /etc/sysctl.conf - sed -i "/^net.ipv4.ip_forward=/d" /etc/sysctl.conf - - # Add forwarding settings - echo "net.ipv6.conf.all.forwarding=1" | tee -a /etc/sysctl.conf - echo "net.ipv4.ip_forward=1" | tee -a /etc/sysctl.conf - - # Apply changes - sysctl -p /etc/sysctl.conf - - # Verify settings - ipv4_forwarding=$(cat /proc/sys/net/ipv4/ip_forward) - ipv6_forwarding=$(cat /proc/sys/net/ipv6/conf/all/forwarding) - - if [ "$ipv4_forwarding" == "1" ] && [ "$ipv6_forwarding" == "1" ]; then - echo -e "${GREEN}IP forwarding configured successfully.${NC}" - else - echo -e "${RED}Failed to configure IP forwarding.${NC}" - exit 1 - fi -} - -create_nym_chain() { - echo -e "${YELLOW}Creating Nym exit policy chain...${NC}" - - # Check if the chain already exists - if iptables -L "$NYM_CHAIN" &>/dev/null; then - echo -e "${YELLOW}Chain $NYM_CHAIN already exists. Flushing it...${NC}" - iptables -F "$NYM_CHAIN" - else - echo -e "${YELLOW}Creating chain $NYM_CHAIN...${NC}" - iptables -N "$NYM_CHAIN" - fi - - # Do the same for IPv6 - if ip6tables -L "$NYM_CHAIN" &>/dev/null; then - echo -e "${YELLOW}Chain $NYM_CHAIN already exists in ip6tables. Flushing it...${NC}" - ip6tables -F "$NYM_CHAIN" - else - echo -e "${YELLOW}Creating chain $NYM_CHAIN in ip6tables...${NC}" - ip6tables -N "$NYM_CHAIN" - fi - - # Link it to the FORWARD chain if not already linked - if ! iptables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null; then - echo -e "${YELLOW}Linking $NYM_CHAIN to FORWARD chain...${NC}" - iptables -I FORWARD 1 -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" - fi - - # Link IPv6 chain - if ! ip6tables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null; then - echo -e "${YELLOW}Linking $NYM_CHAIN to IPv6 FORWARD chain...${NC}" - ip6tables -I FORWARD 1 -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" - fi -} - -setup_nat_rules() { - echo -e "${YELLOW}Setting up NAT rules...${NC}" - - # Check if NAT rule for IPv4 exists - if ! iptables -t nat -C POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE 2>/dev/null; then - iptables -t nat -A POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE - echo -e "${GREEN}Added IPv4 NAT rule.${NC}" - else - echo -e "${GREEN}IPv4 NAT rule already exists.${NC}" - fi - - # Check if NAT rule for IPv6 exists - if ! ip6tables -t nat -C POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE 2>/dev/null; then - ip6tables -t nat -A POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE - echo -e "${GREEN}Added IPv6 NAT rule.${NC}" - else - echo -e "${GREEN}IPv6 NAT rule already exists.${NC}" - fi - - # Setup forwarding rules for Wireguard interface - if ! iptables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT 2>/dev/null; then - iptables -A FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT - echo -e "${GREEN}Added IPv4 forwarding rule (WG → Internet).${NC}" - fi - - if ! iptables -C FORWARD -i "$NETWORK_DEVICE" -o "$WG_INTERFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null; then - iptables -A FORWARD -i "$NETWORK_DEVICE" -o "$WG_INTERFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT - echo -e "${GREEN}Added IPv4 forwarding rule (Internet → WG for established connections).${NC}" - fi - - # IPv6 forwarding rules - if ! ip6tables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT 2>/dev/null; then - ip6tables -A FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT - echo -e "${GREEN}Added IPv6 forwarding rule (WG → Internet).${NC}" - fi - - if ! ip6tables -C FORWARD -i "$NETWORK_DEVICE" -o "$WG_INTERFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null; then - ip6tables -A FORWARD -i "$NETWORK_DEVICE" -o "$WG_INTERFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT - echo -e "${GREEN}Added IPv6 forwarding rule (Internet → WG for established connections).${NC}" - fi -} - -configure_dns_and_icmp() { - echo -e "${YELLOW}Configuring DNS and ICMP rules...${NC}" - - # ICMP rules for ping - if ! iptables -C INPUT -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null; then - iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT - echo -e "${GREEN}Added IPv4 ICMP rule (allow ping requests).${NC}" - fi - - if ! iptables -C OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null; then - iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT - echo -e "${GREEN}Added IPv4 ICMP rule (allow ping replies).${NC}" - fi - - # ICMPv6 rules for ping6 - if ! ip6tables -C INPUT -p ipv6-icmp -j ACCEPT 2>/dev/null; then - ip6tables -A INPUT -p ipv6-icmp -j ACCEPT - echo -e "${GREEN}Added IPv6 ICMP rule (allow ping6).${NC}" - fi - - # DNS rules - if ! iptables -C INPUT -p udp --dport 53 -j ACCEPT 2>/dev/null; then - iptables -A INPUT -p udp --dport 53 -j ACCEPT - echo -e "${GREEN}Added IPv4 DNS rule (UDP).${NC}" - fi - - if ! iptables -C INPUT -p tcp --dport 53 -j ACCEPT 2>/dev/null; then - iptables -A INPUT -p tcp --dport 53 -j ACCEPT - echo -e "${GREEN}Added IPv4 DNS rule (TCP).${NC}" - fi - - # IPv6 DNS rules - if ! ip6tables -C INPUT -p udp --dport 53 -j ACCEPT 2>/dev/null; then - ip6tables -A INPUT -p udp --dport 53 -j ACCEPT - echo -e "${GREEN}Added IPv6 DNS rule (UDP).${NC}" - fi - - if ! ip6tables -C INPUT -p tcp --dport 53 -j ACCEPT 2>/dev/null; then - ip6tables -A INPUT -p tcp --dport 53 -j ACCEPT - echo -e "${GREEN}Added IPv6 DNS rule (TCP).${NC}" - fi -} - -# Apply Spamhaus blocklist from the Nym exit policy -apply_spamhaus_blocklist() { - echo -e "${YELLOW}Applying Spamhaus blocklist...${NC}" - - # Create directory if not exists - mkdir -p "$(dirname "$POLICY_FILE")" - - # Try to download the policy file - echo -e "${YELLOW}Downloading exit policy from $EXIT_POLICY_LOCATION${NC}" - if ! wget -q "$EXIT_POLICY_LOCATION" -O "$POLICY_FILE" 2>/dev/null; then - echo -e "${RED}Failed to download exit policy. Using minimal blocklist.${NC}" - - # Create a minimal policy file with a few entries - cat >"$POLICY_FILE" </dev/null; then - iptables -A "$NYM_CHAIN" -d "$ip_range" -j REJECT - fi - - # Apply IPv6 rules for IPv6 addresses - if [[ "$ip_range" == *":"* ]] && ! ip6tables -C "$NYM_CHAIN" -d "$ip_range" -j REJECT 2>/dev/null; then - ip6tables -A "$NYM_CHAIN" -d "$ip_range" -j REJECT - fi - fi - done - - echo -e "${GREEN}Blocklist applied successfully.${NC}" -} - -add_default_reject_rule() { - echo -e "${YELLOW}Adding default reject rule...${NC}" - - # First remove any existing plain reject rules (without specific destinations) - iptables -D "$NYM_CHAIN" -j REJECT 2>/dev/null || true - iptables -D "$NYM_CHAIN" -j REJECT --reject-with icmp-port-unreachable 2>/dev/null || true - ip6tables -D "$NYM_CHAIN" -j REJECT 2>/dev/null || true - ip6tables -D "$NYM_CHAIN" -j REJECT --reject-with icmp6-port-unreachable 2>/dev/null || true - - # Add the default catch-all reject rule (must be the last rule in the chain) - iptables -A "$NYM_CHAIN" -j REJECT --reject-with icmp-port-unreachable - ip6tables -A "$NYM_CHAIN" -j REJECT --reject-with icmp6-port-unreachable - - echo -e "${GREEN}Default reject rule added successfully.${NC}" -} - -apply_port_allowlist() { - echo -e "${YELLOW}Applying allowed ports...${NC}" - - # Insert DNS rules at the very beginning of NYM-EXIT chain, this ensures DNS queries are never blocked by REJECT rules - echo -e "${YELLOW}Ensuring DNS is at the beginning of $NYM_CHAIN...${NC}" - - iptables -I "$NYM_CHAIN" 1 -p udp --dport 53 -j ACCEPT - iptables -I "$NYM_CHAIN" 2 -p tcp --dport 53 -j ACCEPT - ip6tables -I "$NYM_CHAIN" 1 -p udp --dport 53 -j ACCEPT - ip6tables -I "$NYM_CHAIN" 2 -p tcp --dport 53 -j ACCEPT - - # ICMP is needed because the probe tests DNS by pinging hostnames - iptables -I "$NYM_CHAIN" 3 -p icmp --icmp-type echo-request -j ACCEPT - iptables -I "$NYM_CHAIN" 4 -p icmp --icmp-type echo-reply -j ACCEPT - ip6tables -I "$NYM_CHAIN" 3 -p ipv6-icmp -j ACCEPT - - echo -e "${GREEN}✓ DNS and ICMP rules inserted at beginning of $NYM_CHAIN${NC}" - - # Dictionary of services and their ports - declare -A PORT_MAPPINGS=( - ["FTP"]="20-21" - ["SSH"]="22" - ["WHOIS"]="43" - ["DNS"]="53" - ["Finger"]="79" - ["HTTP"]="80-81" - ["Kerberos"]="88" - ["POP3"]="110" - ["NTP"]="123" - ["IMAP"]="143" - ["IMAP3"]="220" - ["LDAP"]="389" - ["HTTPS"]="443" - ["SMBWindowsFileShare"]="445" - ["Kpasswd"]="464" - ["RTSP"]="554" - ["LDAPS"]="636" - ["SILC"]="706" - ["KerberosAdmin"]="749" - ["DNSOverTLS"]="853" - ["Rsync"]="873" - ["VMware"]="902-904" - ["RemoteHTTPS"]="981" - ["FTPOverTLS"]="989-990" - ["NetnewsAdmin"]="991" - ["TelnetOverTLS"]="992" - ["IMAPOverTLS"]="993" - ["POP3OverTLS"]="995" - ["OpenVPN"]="1194" - ["WireGuardPeer"]="51820-51822" - ["QTServerAdmin"]="1220" - ["PKTKRB"]="1293" - ["MSSQL"]="1433" - ["VLSILicenseManager"]="1500" - ["OracleDB"]="1521" - ["Sametime"]="1533" - ["GroupWise"]="1677" - ["PPTP"]="1723" - ["RTSPAlt"]="1755" - ["MSNP"]="1863" - ["NFS"]="2049" - ["CPanel"]="2082-2083" - ["GNUnet"]="2086-2087" - ["NBX"]="2095-2096" - ["Zephyr"]="2102-2104" - ["XboxLive"]="3074" - ["MySQL"]="3306" - ["SVN"]="3690" - ["RWHOIS"]="4321" - ["Virtuozzo"]="4643" - ["RTPVOIP"]="5000-5005" - ["MMCC"]="5050" - ["ICQ"]="5190" - ["XMPP"]="5222-5223" - ["AndroidMarket"]="5228" - ["PostgreSQL"]="5432" - ["MongoDBDefault"]="27017" - ["Electrum"]="8082" - ["SimplifyMedia"]="8087-8088" - ["Zcash"]="8232-8233" - ["Bitcoin"]="8332-8333" - ["HTTPSALT"]="8443" - ["TeamSpeak"]="8767" - ["MQTTS"]="8883" - ["HTTPProxy"]="8888" - ["TorORPort"]="9001" - ["TorDirPort"]="9030" - ["Tari"]="9053" - ["Gaming"]="9339" - ["Git"]="9418" - ["HTTPSALT2"]="9443" - ["Lightning"]="9735" - ["NDMP"]="10000" - ["OpenPGP"]="11371" - ["Monero"]="18080-18081" - ["MoneroRPC"]="18089" - ["GoogleVoice"]="19294" - ["EnsimControlPanel"]="19638" - ["DarkFiTor"]="25551" - ["Minecraft"]="25565" - ["DarkFi"]="26661" - ["Steam"]="27000-27050" - ["ElectrumSSL"]="50002" - ["MOSH"]="60000-61000" - ["Mumble"]="64738" - ["Metadata"]="51830" - ) - - # Add TCP and UDP rules for each allowed port - for service in "${!PORT_MAPPINGS[@]}"; do - port="${PORT_MAPPINGS[$service]}" - echo -e "${YELLOW}Adding rules for $service (Port: $port)${NC}" - - # Add both TCP and UDP rules for all services - add_port_rules iptables "$port" "tcp" - add_port_rules ip6tables "$port" "tcp" - add_port_rules iptables "$port" "udp" - add_port_rules ip6tables "$port" "udp" - done - - echo -e "${GREEN}Port allowlist applied successfully.${NC}" -} - -safe_iptables_rule_remove() { - local chain="$1" - local table="${2:-filter}" - local interface="$3" - - # Remove rule if it exists - if iptables -t "$table" -C "$chain" -o "$interface" -j "$NYM_CHAIN" 2>/dev/null; then - iptables -t "$table" -D "$chain" -o "$interface" -j "$NYM_CHAIN" - fi -} - -safe_ip6tables_rule_remove() { - local chain="$1" - local table="${2:-filter}" - local interface="$3" - - # Remove rule if it exists - if ip6tables -t "$table" -C "$chain" -o "$interface" -j "$NYM_CHAIN" 2>/dev/null; then - ip6tables -t "$table" -D "$chain" -o "$interface" -j "$NYM_CHAIN" - fi -} - -clear_rules() { - echo -e "${YELLOW}Clearing Nym exit policy rules...${NC}" - - # Flush all rules in the NYM-EXIT chain - iptables -F "$NYM_CHAIN" 2>/dev/null || true - ip6tables -F "$NYM_CHAIN" 2>/dev/null || true - - # Remove the chain from FORWARD if it exists - iptables -D FORWARD -o "$WG_INTERFACE" -j "$NYM_CHAIN" 2>/dev/null || true - iptables -D FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null || true - ip6tables -D FORWARD -o "$WG_INTERFACE" -j "$NYM_CHAIN" 2>/dev/null || true - ip6tables -D FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null || true - - # Delete the chains - iptables -X "$NYM_CHAIN" 2>/dev/null || true - ip6tables -X "$NYM_CHAIN" 2>/dev/null || true - - echo -e "${GREEN}Nym exit policy rules cleared successfully.${NC}" -} - -remove_duplicate_rules() { - local interface="$1" - - if [[ -z "$interface" ]]; then - echo -e "${RED}Error: No interface specified. Usage: $0 remove-duplicates ${NC}" >&2 - exit 1 - fi - - echo -e "${YELLOW}Detecting and removing duplicate rules for $interface...${NC}" - - # Verbose duplicate rule detection for IPv4 - echo -e "${YELLOW}Checking IPv4 duplicate rules:${NC}" - iptables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep "$interface" | sort | uniq -d && { - echo -e "${RED}Duplicate IPv4 rules found! Removing...${NC}" - # Remove duplicates by saving unique rules - iptables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep "$interface" | sort | uniq | while read -r rule; do - # Carefully remove duplicates - full_rule=$(echo "$rule" | sed 's/^-A/iptables -D/') - eval "$full_rule" 2>/dev/null - done - } || echo -e "${GREEN}No duplicate IPv4 rules found.${NC}" - - # Verbose duplicate rule detection for IPv6 - echo -e "${YELLOW}Checking IPv6 duplicate rules:${NC}" - ip6tables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep "$interface" | sort | uniq -d && { - echo -e "${RED}Duplicate IPv6 rules found! Removing...${NC}" - # Remove duplicates by saving unique rules - ip6tables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep "$interface" | sort | uniq | while read -r rule; do - # Carefully remove duplicates - full_rule=$(echo "$rule" | sed 's/^-A/ip6tables -D/') - eval "$full_rule" 2>/dev/null - done - } || echo -e "${GREEN}No duplicate IPv6 rules found.${NC}" - - # Additional verification - echo -e "\n${YELLOW}Rule verification:${NC}" - echo "IPv4 Rules:" - iptables -L FORWARD -v -n | grep "$interface" - echo "IPv6 Rules:" - ip6tables -L FORWARD -v -n | grep "$interface" - - echo -e "${GREEN}Duplicate rule removal process completed.${NC}" -} - -save_rules() { - echo -e "${YELLOW}Saving iptables rules to make them persistent...${NC}" - - if [ -d "/etc/iptables" ]; then - # For Debian/Ubuntu with iptables-persistent - iptables-save >/etc/iptables/rules.v4 - ip6tables-save >/etc/iptables/rules.v6 - echo -e "${GREEN}Rules saved to /etc/iptables/rules.v4 and /etc/iptables/rules.v6${NC}" - else - # Fallback method - iptables-save >/etc/iptables.rules - ip6tables-save >/etc/ip6tables.rules - echo -e "${GREEN}Rules saved to /etc/iptables.rules and /etc/ip6tables.rules${NC}" - - # Add loading script to rc.local if it doesn't exist - if [ ! -f "/etc/network/if-pre-up.d/iptables" ]; then - cat >/etc/network/if-pre-up.d/iptables </dev/null; then - echo -e "${RED}WARNING: Wireguard interface $WG_INTERFACE not found!${NC}" - return 1 - fi - - # Interface details - echo -e "\n${YELLOW}Interface Details:${NC}" - ip link show "$WG_INTERFACE" - - # IP Addresses - echo -e "\n${YELLOW}IP Addresses:${NC}" - ip -4 addr show dev "$WG_INTERFACE" - ip -6 addr show dev "$WG_INTERFACE" - - # Iptables Chain Status - echo -e "\n${YELLOW}Iptables Chains:${NC}" - { - echo "IPv4 Chain:" - iptables -L "$NYM_CHAIN" -n -v - echo -e "\nIPv6 Chain:" - ip6tables -L "$NYM_CHAIN" -n -v - } || echo "One or both chains not found" - - # Forwarding Status - echo -e "\n${YELLOW}IP Forwarding:${NC}" - echo "IPv4: $(cat /proc/sys/net/ipv4/ip_forward)" - echo "IPv6: $(cat /proc/sys/net/ipv6/conf/all/forwarding)" -} - -test_connectivity() { - echo -e "${YELLOW}Testing connectivity through $WG_INTERFACE...${NC}" - - # More comprehensive interface check - interface_info=$(ip link show "$WG_INTERFACE" 2>/dev/null) - - if [ -z "$interface_info" ]; then - echo -e "${RED}Interface $WG_INTERFACE not found!${NC}" - return 1 - fi - - # Check for multiple possible interface states - if ! echo "$interface_info" | grep -qE "state (UP|UNKNOWN|DORMANT)"; then - echo -e "${RED}Interface $WG_INTERFACE is not in an active state!${NC}" - echo "$interface_info" - return 1 - fi - - # Detailed interface information - echo -e "${GREEN}Interface Details:${NC}" - echo "$interface_info" - - # Get IP addresses with more robust method - ipv4_address=$(ip -4 addr show dev "$WG_INTERFACE" | grep -oP '(?<=inet\s)\d+\.\d+\.\d+\.\d+/\d+' | cut -d'/' -f1 | head -n1) - ipv6_address=$(ip -6 addr show dev "$WG_INTERFACE" scope global | grep -oP '(?<=inet6\s)[0-9a-f:]+/\d+' | cut -d'/' -f1 | head -n1) - - echo -e "${GREEN}IPv4 Address:${NC} ${ipv4_address:-Not found}" - echo -e "${GREEN}IPv6 Address:${NC} ${ipv6_address:-Not found}" - - # Connectivity tests - if [[ -n "$ipv4_address" ]]; then - echo -e "${YELLOW}Testing IPv4 connectivity from $ipv4_address...${NC}" - - # Ping test - if timeout 5 ping -c 3 -I "$ipv4_address" 8.8.8.8 >/dev/null 2>&1; then - echo -e "${GREEN}IPv4 connectivity to 8.8.8.8: Success${NC}" - else - echo -e "${RED}IPv4 connectivity to 8.8.8.8: Failed${NC}" - fi - - # DNS resolution test - if timeout 5 ping -c 3 -I "$ipv4_address" google.com >/dev/null 2>&1; then - echo -e "${GREEN}IPv4 DNS resolution: Success${NC}" - else - echo -e "${RED}IPv4 DNS resolution: Failed${NC}" - fi - - # HTTP(S) connectivity test - if command -v curl &>/dev/null; then - if timeout 5 curl -s --interface "$ipv4_address" -o /dev/null -w "%{http_code}" https://www.google.com | grep -q "200"; then - echo -e "${GREEN}IPv4 HTTPS connectivity: Success${NC}" - else - echo -e "${RED}IPv4 HTTPS connectivity: Failed${NC}" - fi - fi - else - echo -e "${RED}No IPv4 address configured on $WG_INTERFACE${NC}" - fi - - # Similar tests for IPv6 if available - if [[ -n "$ipv6_address" ]]; then - echo -e "${YELLOW}Testing IPv6 connectivity from $ipv6_address...${NC}" - - if timeout 5 ping6 -c 3 -I "$ipv6_address" 2001:4860:4860::8888 >/dev/null 2>&1; then - echo -e "${GREEN}IPv6 connectivity to Google DNS: Success${NC}" - else - echo -e "${RED}IPv6 connectivity to Google DNS: Failed${NC}" - fi - - if timeout 5 ping6 -c 3 -I "$ipv6_address" google.com >/dev/null 2>&1; then - echo -e "${GREEN}IPv6 DNS resolution: Success${NC}" - else - echo -e "${RED}IPv6 DNS resolution: Failed${NC}" - fi - - if command -v curl &>/dev/null; then - if timeout 5 curl -s --interface "$ipv6_address" -o /dev/null -w "%{http_code}" https://www.google.com | grep -q "200"; then - echo -e "${GREEN}IPv6 HTTPS connectivity: Success${NC}" - else - echo -e "${RED}IPv6 HTTPS connectivity: Failed${NC}" - fi - fi - else - echo -e "${YELLOW}No IPv6 address configured on $WG_INTERFACE${NC}" - fi - - echo -e "${GREEN}Connectivity tests completed.${NC}" -} - -main() { - # Check for root privileges - if [ "$(id -u)" -ne 0 ]; then - echo -e "${RED}This script must be run as root${NC}" >&2 - exit 1 - fi - - # Parse command-line arguments - case "$1" in - install) - install_dependencies - configure_ip_forwarding - create_nym_chain - setup_nat_rules - configure_dns_and_icmp - # Apply allowlist first (so DNS and other allowed ports are not blocked) - apply_port_allowlist - # Then apply blocklist (aka the REJECT rules) - apply_spamhaus_blocklist - add_default_reject_rule - save_rules - echo -e "${GREEN}Nym exit policy installed successfully.${NC}" - ;; - status) - show_status - ;; - test) - test_connectivity - ;; - clear) - clear_rules - echo -e "${GREEN}Nym exit policy rules cleared.${NC}" - ;; - remove-duplicates) - remove_duplicate_rules "$2" - ;; - help | --help | -h) - echo "Usage: $0 [command]" - echo "" - echo "Commands:" - echo " install Install and configure Nym exit policy" - echo " status Show current Nym exit policy status" - echo " test Test connectivity through Wireguard interface" - echo " clear Remove all Nym exit policy rules" - echo " remove-duplicates Remove duplicate iptables rules for an interface" - echo " help Show this help message" - ;; - *) - echo -e "${RED}Invalid command. Use '$0 help' for usage information.${NC}" >&2 - exit 1 - ;; - esac -} - -main "$@" From f402da8e6091b33750cde1e619d07cd29e042604 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 14:28:38 +0100 Subject: [PATCH 018/134] add new top manager tool --- .../nym-node-setup/network-tunnel-manager.sh | 965 ++++++++++++++++++ 1 file changed, 965 insertions(+) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index e69de29bb2..1c869a297a 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -0,0 +1,965 @@ +#!/bin/bash +# nym tunnel and wireguard exit policy manager +# run this script as root + +set -euo pipefail + +############################################################################### +# safety: must run as root +############################################################################### +if [ "$(id -u)" -ne 0 ]; then + echo "this script must be run as root" + exit 1 +fi + +############################################################################### +# basic config +############################################################################### + +TUNNEL_INTERFACE="${TUNNEL_INTERFACE:-nymtun0}" +WG_INTERFACE="${WG_INTERFACE:-nymwg}" + +# uplink device detection, can be overridden +NETWORK_DEVICE="${NETWORK_DEVICE:-}" +if [[ -z "$NETWORK_DEVICE" ]]; then + NETWORK_DEVICE="$(ip -o route show default 2>/dev/null | awk '{print $5}' | head -n1 || true)" +fi +if [[ -z "$NETWORK_DEVICE" ]]; then + NETWORK_DEVICE="$(ip -o route show default table all 2>/dev/null | awk '{print $5}' | head -n1 || true)" +fi +if [[ -z "$NETWORK_DEVICE" ]]; then + echo "cannot determine uplink interface. set NETWORK_DEVICE or UPLINK_DEV" + exit 1 +fi + +NYM_CHAIN="NYM-EXIT" +POLICY_FILE="/etc/nym/exit-policy.txt" +EXIT_POLICY_LOCATION="https://nymtech.net/.wellknown/network-requester/exit-policy.txt" + +# colors (no emojis) +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[0;33m' +NC='\033[0m' + +############################################################################### +# shared helpers +############################################################################### + +install_iptables_persistent() { + if ! dpkg -s iptables-persistent >/dev/null 2>&1; then + echo -e "${YELLOW}installing iptables-persistent${NC}" + apt-get update -y + DEBIAN_FRONTEND=noninteractive apt-get install -y iptables-persistent + else + echo -e "${GREEN}iptables-persistent is already installed${NC}" + fi +} + +adjust_ip_forwarding() { + echo -e "${YELLOW}configuring ip forwarding via /etc/sysctl.d/99-nym-forwarding.conf${NC}" + install -m 0644 /dev/null /etc/sysctl.d/99-nym-forwarding.conf + cat > /etc/sysctl.d/99-nym-forwarding.conf </dev/null || echo 0) + v6=$(cat /proc/sys/net/ipv6/conf/all/forwarding 2>/dev/null || echo 0) + + if [[ "$v4" == "1" && "$v6" == "1" ]]; then + echo -e "${GREEN}ipv4 and ipv6 forwarding enabled${NC}" + else + echo -e "${RED}warning: ip forwarding not fully enabled (ipv4=$v4 ipv6=$v6)${NC}" + fi +} + +save_iptables_rules() { + echo -e "${YELLOW}saving iptables rules to /etc/iptables${NC}" + mkdir -p /etc/iptables + iptables-save > /etc/iptables/rules.v4 + ip6tables-save > /etc/iptables/rules.v6 + echo -e "${GREEN}iptables rules saved${NC}" +} + +############################################################################### +# part 1: network tunnel manager (nymtun0 + nymwg base nat/forwarding) +############################################################################### + +fetch_ipv6_address() { + local interface=$1 + local ipv6_global_address + ipv6_global_address=$(ip -6 addr show "$interface" scope global | awk '/inet6/ {print $2}' | head -n 1) + + if [[ -z "$ipv6_global_address" ]]; then + echo "no globally routable ipv6 address found on $interface. please configure ipv6 or check your network settings" + exit 1 + else + echo "using ipv6 address: $ipv6_global_address" + fi +} + +fetch_and_display_ipv6() { + local ipv6_address + ipv6_address=$(ip -6 addr show "$NETWORK_DEVICE" scope global | awk '/inet6/ {print $2}') + if [[ -z "$ipv6_address" ]]; then + echo "no global ipv6 address found on $NETWORK_DEVICE" + else + echo "ipv6 address on $NETWORK_DEVICE: $ipv6_address" + fi +} + +# dedupe / clean-up rules for an interface in FORWARD and NYM-EXIT +# keeps a single copy of each rule +remove_duplicate_rules() { + local interface="$1" + + if [[ -z "$interface" ]]; then + echo "error: no interface specified. usage: $0 remove_duplicate_rules " + exit 1 + fi + + echo -e "${YELLOW}detecting and removing duplicate rules for $interface in FORWARD and ${NYM_CHAIN}${NC}" + + # ipv4 + local rules_v4 + rules_v4=$(iptables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep "$interface" || true) + if [[ -n "$rules_v4" ]]; then + echo -e "${YELLOW}processing ipv4 rules${NC}" + echo "$rules_v4" | sort | uniq -d | while read -r dup; do + echo "removing duplicate ipv4 rule: $dup" + while iptables -t filter -C ${dup#-A } 2>/dev/null; do + iptables -t filter -D ${dup#-A } || break + done + done + else + echo -e "${GREEN}no ipv4 rules found for $interface to deduplicate${NC}" + fi + + # ipv6 + local rules_v6 + rules_v6=$(ip6tables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep "$interface" || true) + if [[ -n "$rules_v6" ]]; then + echo -e "${YELLOW}processing ipv6 rules${NC}" + echo "$rules_v6" | sort | uniq -d | while read -r dup; do + echo "removing duplicate ipv6 rule: $dup" + while ip6tables -t filter -C ${dup#-A } 2>/dev/null; do + ip6tables -t filter -D ${dup#-A } || break + done + done + else + echo -e "${GREEN}no ipv6 rules found for $interface to deduplicate${NC}" + fi + + echo -e "${GREEN}duplicate rule scan completed for $interface${NC}" +} + +apply_iptables_rules() { + local interface=$1 + echo "applying iptables rules for $interface using uplink $NETWORK_DEVICE" + sleep 1 + + # ipv4 nat and forwarding + iptables -t nat -C POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE 2>/dev/null || \ + iptables -t nat -A POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE + + iptables -C FORWARD -i "$interface" -o "$NETWORK_DEVICE" -j ACCEPT 2>/dev/null || \ + iptables -A FORWARD -i "$interface" -o "$NETWORK_DEVICE" -j ACCEPT + + iptables -C FORWARD -i "$NETWORK_DEVICE" -o "$interface" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || \ + iptables -A FORWARD -i "$NETWORK_DEVICE" -o "$interface" -m state --state RELATED,ESTABLISHED -j ACCEPT + + # ipv6 nat and forwarding + ip6tables -t nat -C POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE 2>/dev/null || \ + ip6tables -t nat -A POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE + + ip6tables -C FORWARD -i "$interface" -o "$NETWORK_DEVICE" -j ACCEPT 2>/dev/null || \ + ip6tables -A FORWARD -i "$interface" -o "$NETWORK_DEVICE" -j ACCEPT + + ip6tables -C FORWARD -i "$NETWORK_DEVICE" -o "$interface" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || \ + ip6tables -A FORWARD -i "$NETWORK_DEVICE" -o "$interface" -m state --state RELATED,ESTABLISHED -j ACCEPT + + save_iptables_rules +} + +check_tunnel_iptables() { + local interface=$1 + echo "inspecting iptables rules for $interface" + echo "ipv4 forward chain:" + iptables -L FORWARD -v -n | awk -v dev="$interface" '/^Chain FORWARD/ || $0 ~ dev || $0 ~ "ufw-reject-forward"' + echo + echo "ipv6 forward chain:" + ip6tables -L FORWARD -v -n | awk -v dev="$interface" '/^Chain FORWARD/ || $0 ~ dev || $0 ~ "ufw6-reject-forward"' +} + +check_ipv6_ipv4_forwarding() { + local result_ipv4 result_ipv6 + result_ipv4=$(cat /proc/sys/net/ipv4/ip_forward) + result_ipv6=$(cat /proc/sys/net/ipv6/conf/all/forwarding) + echo "ipv4 forwarding is $([ "$result_ipv4" == "1" ] && echo enabled || echo not enabled)" + echo "ipv6 forwarding is $([ "$result_ipv6" == "1" ] && echo enabled || echo not enabled)" +} + +check_ip_routing() { + echo "ipv4 routing table:" + ip route + echo "---------------------------" + echo "ipv6 routing table:" + ip -6 route +} + +perform_pings() { + echo "performing ipv4 ping to google.com" + ping -c 4 google.com || echo "ipv4 ping failed" + echo "---------------------------" + echo "performing ipv6 ping to google.com" + ping6 -c 4 google.com || echo "ipv6 ping failed" +} + +joke_through_tunnel() { + local interface=$1 + local green="\033[0;32m" + local reset="\033[0m" + local red="\033[0;31m" + local yellow="\033[0;33m" + + sleep 1 + echo + echo -e "${yellow}checking tunnel connectivity and fetching a joke for $interface${reset}" + echo -e "${yellow}if this test succeeds, it confirms your machine can reach the outside world via ipv4 and ipv6${reset}" + echo -e "${yellow}probes and external clients may still see different connectivity to your nym node${reset}" + + local ipv4_address ipv6_address joke + ipv4_address=$(ip addr show "$interface" | awk '/inet / {print $2}' | cut -d'/' -f1) + ipv6_address=$(ip addr show "$interface" | awk '/inet6 / && $2 !~ /^fe80/ {print $2}' | cut -d'/' -f1) + + if [[ -z "$ipv4_address" && -z "$ipv6_address" ]]; then + echo -e "${red}no ip address found on $interface. unable to fetch a joke${reset}" + echo -e "${red}please verify your tunnel configuration and ensure the interface is up${reset}" + return 1 + fi + + if [[ -n "$ipv4_address" ]]; then + echo + echo "------------------------------------" + echo "detected ipv4 address: $ipv4_address" + echo "testing ipv4 connectivity" + echo + + if ping -c 1 -I "$ipv4_address" google.com >/dev/null 2>&1; then + echo -e "${green}ipv4 connectivity is working. fetching a joke${reset}" + joke=$(curl -s -H "Accept: application/json" --interface "$ipv4_address" https://icanhazdadjoke.com/ | jq -r .joke || true) + [[ -n "$joke" && "$joke" != "null" ]] && echo -e "${green}ipv4 joke: $joke${reset}" || echo "failed to fetch a joke via ipv4" + else + echo -e "${red}ipv4 connectivity is not working for $interface. verify your routing and nat settings${reset}" + fi + else + echo -e "${red}no ipv4 address found on $interface. unable to fetch a joke via ipv4${reset}" + fi + + if [[ -n "$ipv6_address" ]]; then + echo + echo "------------------------------------" + echo "detected ipv6 address: $ipv6_address" + echo "testing ipv6 connectivity" + echo + + if ping6 -c 1 -I "$ipv6_address" google.com >/dev/null 2>&1; then + echo -e "${green}ipv6 connectivity is working. fetching a joke${reset}" + joke=$(curl -s -H "Accept: application/json" --interface "$ipv6_address" https://icanhazdadjoke.com/ | jq -r .joke || true) + [[ -n "$joke" && "$joke" != "null" ]] && echo -e "${green}ipv6 joke: $joke${reset}" || echo -e "${red}failed to fetch a joke via ipv6${reset}" + else + echo -e "${red}ipv6 connectivity is not working for $interface. verify your routing and nat settings${reset}" + fi + else + echo -e "${red}no ipv6 address found on $interface. unable to fetch a joke via ipv6${reset}" + fi + + echo -e "${green}joke fetching processes completed for $interface${reset}" + echo "------------------------------------" + + sleep 3 + echo + echo + echo -e "${yellow}connectivity testing recommendations${reset}" + echo -e "${yellow}- from another machine use wscat to test websocket connectivity on 9001${reset}" + echo -e "${yellow}- test udp connectivity on port 51822 (wireguard)${reset}" + echo -e "${yellow}- example: echo 'test' | nc -u 51822${reset}" +} + +configure_dns_and_icmp_wg() { + echo "allowing ping (icmp) and dns on this host" + iptables -C INPUT -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null || \ + iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT + iptables -C OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null || \ + iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT + + iptables -C INPUT -p udp --dport 53 -j ACCEPT 2>/dev/null || \ + iptables -A INPUT -p udp --dport 53 -j ACCEPT + iptables -C INPUT -p tcp --dport 53 -j ACCEPT 2>/dev/null || \ + iptables -A INPUT -p tcp --dport 53 -j ACCEPT + + save_iptables_rules + echo "dns and icmp configuration completed" +} + +############################################################################### +# part 2: wireguard exit policy manager +############################################################################### + +add_port_rules() { + local cmd="$1" # iptables or ip6tables + local port="$2" + local protocol="${3:-tcp}" + + if [[ "$port" == *"-"* ]]; then + local start_port end_port + start_port=$(echo "$port" | cut -d'-' -f1) + end_port=$(echo "$port" | cut -d'-' -f2) + + if ! $cmd -C "$NYM_CHAIN" -p "$protocol" --dport "$start_port:$end_port" -j ACCEPT 2>/dev/null; then + $cmd -A "$NYM_CHAIN" -p "$protocol" --dport "$start_port:$end_port" -j ACCEPT + echo "added $cmd $NYM_CHAIN $protocol port range $start_port:$end_port" + fi + else + if ! $cmd -C "$NYM_CHAIN" -p "$protocol" --dport "$port" -j ACCEPT 2>/dev/null; then + $cmd -A "$NYM_CHAIN" -p "$protocol" --dport "$port" -j ACCEPT + echo "added $cmd $NYM_CHAIN $protocol port $port" + fi + fi +} + +exit_policy_install_deps() { + install_iptables_persistent + + for cmd in iptables ip6tables ip grep sed awk wget curl; do + if ! command -v "$cmd" >/dev/null 2>&1; then + echo "installing dependency: $cmd" + apt-get install -y "$cmd" + fi + done +} + +create_nym_chain() { + echo "creating nym exit policy chain $NYM_CHAIN" + + if iptables -L "$NYM_CHAIN" >/dev/null 2>&1; then + iptables -F "$NYM_CHAIN" + else + iptables -N "$NYM_CHAIN" + fi + + if ip6tables -L "$NYM_CHAIN" >/dev/null 2>&1; then + ip6tables -F "$NYM_CHAIN" + else + ip6tables -N "$NYM_CHAIN" + fi + + if ! iptables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null; then + iptables -I FORWARD 1 -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" + fi + + if ! ip6tables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null; then + ip6tables -I FORWARD 1 -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" + fi +} + +setup_nat_rules() { + echo "setting up nat and forwarding rules for $WG_INTERFACE via $NETWORK_DEVICE" + + if ! iptables -t nat -C POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE 2>/dev/null; then + iptables -t nat -A POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE + fi + if ! ip6tables -t nat -C POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE 2>/dev/null; then + ip6tables -t nat -A POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE + fi + + if ! iptables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT 2>/dev/null; then + iptables -A FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT + fi + if ! iptables -C FORWARD -i "$NETWORK_DEVICE" -o "$WG_INTERFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null; then + iptables -A FORWARD -i "$NETWORK_DEVICE" -o "$WG_INTERFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT + fi + + if ! ip6tables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT 2>/dev/null; then + ip6tables -A FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT + fi + if ! ip6tables -C FORWARD -i "$NETWORK_DEVICE" -o "$WG_INTERFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null; then + ip6tables -A FORWARD -i "$NETWORK_DEVICE" -o "$WG_INTERFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT + fi +} + +configure_exit_dns_and_icmp() { + echo "ensuring dns and icmp are allowed inside nym exit chain" + + iptables -I "$NYM_CHAIN" 1 -p udp --dport 53 -j ACCEPT + iptables -I "$NYM_CHAIN" 2 -p tcp --dport 53 -j ACCEPT + ip6tables -I "$NYM_CHAIN" 1 -p udp --dport 53 -j ACCEPT + ip6tables -I "$NYM_CHAIN" 2 -p tcp --dport 53 -j ACCEPT + + iptables -I "$NYM_CHAIN" 3 -p icmp --icmp-type echo-request -j ACCEPT + iptables -I "$NYM_CHAIN" 4 -p icmp --icmp-type echo-reply -j ACCEPT + ip6tables -I "$NYM_CHAIN" 3 -p ipv6-icmp -j ACCEPT +} + +apply_port_allowlist() { + echo "applying allowed port list into ${NYM_CHAIN}" + + configure_exit_dns_and_icmp + + declare -A PORT_MAPPINGS=( + ["FTP"]="20-21" + ["SSH"]="22" + ["WHOIS"]="43" + ["DNS"]="53" + ["Finger"]="79" + ["HTTP"]="80-81" + ["Kerberos"]="88" + ["POP3"]="110" + ["NTP"]="123" + ["IMAP"]="143" + ["IMAP3"]="220" + ["LDAP"]="389" + ["HTTPS"]="443" + ["SMBWindowsFileShare"]="445" + ["Kpasswd"]="464" + ["RTSP"]="554" + ["LDAPS"]="636" + ["SILC"]="706" + ["KerberosAdmin"]="749" + ["DNSOverTLS"]="853" + ["Rsync"]="873" + ["VMware"]="902-904" + ["RemoteHTTPS"]="981" + ["FTPOverTLS"]="989-990" + ["NetnewsAdmin"]="991" + ["TelnetOverTLS"]="992" + ["IMAPOverTLS"]="993" + ["POP3OverTLS"]="995" + ["OpenVPN"]="1194" + ["WireGuardPeer"]="51820-51822" + ["QTServerAdmin"]="1220" + ["PKTKRB"]="1293" + ["MSSQL"]="1433" + ["VLSILicenseManager"]="1500" + ["OracleDB"]="1521" + ["Sametime"]="1533" + ["GroupWise"]="1677" + ["PPTP"]="1723" + ["RTSPAlt"]="1755" + ["MSNP"]="1863" + ["NFS"]="2049" + ["CPanel"]="2082-2083" + ["GNUnet"]="2086-2087" + ["NBX"]="2095-2096" + ["Zephyr"]="2102-2104" + ["XboxLive"]="3074" + ["MySQL"]="3306" + ["SVN"]="3690" + ["RWHOIS"]="4321" + ["Virtuozzo"]="4643" + ["RTPVOIP"]="5000-5005" + ["MMCC"]="5050" + ["ICQ"]="5190" + ["XMPP"]="5222-5223" + ["AndroidMarket"]="5228" + ["PostgreSQL"]="5432" + ["MongoDBDefault"]="27017" + ["Electrum"]="8082" + ["SimplifyMedia"]="8087-8088" + ["Zcash"]="8232-8233" + ["Bitcoin"]="8332-8333" + ["HTTPSALT"]="8443" + ["TeamSpeak"]="8767" + ["MQTTS"]="8883" + ["HTTPProxy"]="8888" + ["TorORPort"]="9001" + ["TorDirPort"]="9030" + ["Tari"]="9053" + ["Gaming"]="9339" + ["Git"]="9418" + ["HTTPSALT2"]="9443" + ["Lightning"]="9735" + ["NDMP"]="10000" + ["OpenPGP"]="11371" + ["Monero"]="18080-18081" + ["MoneroRPC"]="18089" + ["GoogleVoice"]="19294" + ["EnsimControlPanel"]="19638" + ["DarkFiTor"]="25551" + ["Minecraft"]="25565" + ["DarkFi"]="26661" + ["Steam"]="27000-27050" + ["ElectrumSSL"]="50002" + ["MOSH"]="60000-61000" + ["Mumble"]="64738" + ["Metadata"]="51830" + ) + + for service in "${!PORT_MAPPINGS[@]}"; do + local port="${PORT_MAPPINGS[$service]}" + echo "adding rules for $service (ports $port)" + add_port_rules iptables "$port" "tcp" + add_port_rules ip6tables "$port" "tcp" + add_port_rules iptables "$port" "udp" + add_port_rules ip6tables "$port" "udp" + done +} + +apply_spamhaus_blocklist() { + echo "applying spamhaus-like blocklist from $EXIT_POLICY_LOCATION" + + mkdir -p "$(dirname "$POLICY_FILE")" + + if ! wget -q "$EXIT_POLICY_LOCATION" -O "$POLICY_FILE" 2>/dev/null; then + echo "failed to download exit policy, using minimal blocklist" + cat >"$POLICY_FILE" </dev/null; then + iptables -A "$NYM_CHAIN" -d "$ip_range" -j REJECT + fi + if [[ "$ip_range" == *":"* ]] && ! ip6tables -C "$NYM_CHAIN" -d "$ip_range" -j REJECT 2>/dev/null; then + ip6tables -A "$NYM_CHAIN" -d "$ip_range" -j REJECT + fi + fi + done +} + +add_default_reject_rule() { + echo "ensuring default reject rule at end of ${NYM_CHAIN}" + + iptables -D "$NYM_CHAIN" -j REJECT 2>/dev/null || true + iptables -D "$NYM_CHAIN" -j REJECT --reject-with icmp-port-unreachable 2>/dev/null || true + ip6tables -D "$NYM_CHAIN" -j REJECT 2>/dev/null || true + ip6tables -D "$NYM_CHAIN" -j REJECT --reject-with icmp6-port-unreachable 2>/dev/null || true + + iptables -A "$NYM_CHAIN" -j REJECT --reject-with icmp-port-unreachable + ip6tables -A "$NYM_CHAIN" -j REJECT --reject-with icmp6-port-unreachable +} + +clear_exit_policy_rules() { + echo "clearing nym exit policy rules" + + iptables -F "$NYM_CHAIN" 2>/dev/null || true + ip6tables -F "$NYM_CHAIN" 2>/dev/null || true + + iptables -D FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null || true + ip6tables -D FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null || true + + iptables -X "$NYM_CHAIN" 2>/dev/null || true + ip6tables -X "$NYM_CHAIN" 2>/dev/null || true +} + +show_exit_policy_status() { + echo "nym exit policy status" + echo "network device: $NETWORK_DEVICE" + echo "wireguard interface: $WG_INTERFACE" + echo + + if ! ip link show "$WG_INTERFACE" >/dev/null 2>&1; then + echo "warning: wireguard interface $WG_INTERFACE not found" + else + echo "interface details:" + ip link show "$WG_INTERFACE" + echo + echo "ipv4 addresses:" + ip -4 addr show dev "$WG_INTERFACE" + echo + echo "ipv6 addresses:" + ip -6 addr show dev "$WG_INTERFACE" + fi + + echo + echo "iptables chains for ${NYM_CHAIN}:" + iptables -L "$NYM_CHAIN" -n -v 2>/dev/null || echo "ipv4 chain not found" + echo + ip6tables -L "$NYM_CHAIN" -n -v 2>/dev/null || echo "ipv6 chain not found" + echo + echo "ip forwarding:" + echo "ipv4: $(cat /proc/sys/net/ipv4/ip_forward 2>/dev/null || echo 0)" + echo "ipv6: $(cat /proc/sys/net/ipv6/conf/all/forwarding 2>/dev/null || echo 0)" +} + +test_exit_policy_connectivity() { + echo "testing connectivity through $WG_INTERFACE" + + local iface_info + iface_info=$(ip link show "$WG_INTERFACE" 2>/dev/null || true) + if [[ -z "$iface_info" ]]; then + echo "interface $WG_INTERFACE not found" + return 1 + fi + + echo "interface:" + echo "$iface_info" + + local ipv4_address ipv6_address + ipv4_address=$(ip -4 addr show dev "$WG_INTERFACE" | awk '/inet / {print $2}' | cut -d'/' -f1 | head -n1) + ipv6_address=$(ip -6 addr show dev "$WG_INTERFACE" scope global | awk '/inet6/ {print $2}' | cut -d'/' -f1 | head -n1) + + echo "ipv4 address: ${ipv4_address:-none}" + echo "ipv6 address: ${ipv6_address:-none}" + + if [[ -n "$ipv4_address" ]]; then + echo "testing ipv4 ping to 8.8.8.8" + timeout 5 ping -c 3 -I "$ipv4_address" 8.8.8.8 >/dev/null 2>&1 && \ + echo "ipv4 ping ok" || echo "ipv4 ping failed" + + echo "testing ipv4 dns resolution" + timeout 5 ping -c 3 -I "$ipv4_address" google.com >/dev/null 2>&1 && \ + echo "ipv4 dns ok" || echo "ipv4 dns failed" + fi + + if [[ -n "$ipv6_address" ]]; then + echo "testing ipv6 ping to google dns" + timeout 5 ping6 -c 3 -I "$ipv6_address" 2001:4860:4860::8888 >/dev/null 2>&1 && \ + echo "ipv6 ping ok" || echo "ipv6 ping failed" + + echo "testing ipv6 dns resolution" + timeout 5 ping6 -c 3 -I "$ipv6_address" google.com >/dev/null 2>&1 && \ + echo "ipv6 dns ok" || echo "ipv6 dns failed" + fi + + echo "connectivity tests finished" +} + +############################################################################### +# part 3: exit policy verification tests +############################################################################### + +test_port_range_rules() { + echo "testing port range rules in ${NYM_CHAIN}" + + local port_ranges=( + "20-21:tcp:ftp" + "80-81:tcp:http" + "2082-2083:tcp:cpanel" + "5222-5223:tcp:xmpp" + "27000-27050:tcp:steam-sample" + "989-990:tcp:ftp-tls" + "5000-5005:tcp:rtp-voip" + "8087-8088:tcp:simplify-media" + "8232-8233:tcp:zcash" + "8332-8333:tcp:bitcoin" + "18080-18081:tcp:monero" + ) + + local failures=0 + for entry in "${port_ranges[@]}"; do + IFS=':' read -r range proto name <<<"$entry" + local start end + start=$(echo "$range" | cut -d'-' -f1) + end=$(echo "$range" | cut -d'-' -f2) + + if iptables -t filter -C "$NYM_CHAIN" -p "$proto" --dport "$start:$end" -j ACCEPT 2>/dev/null; then + echo "rule ok: $name $proto $range" + else + echo "missing rule: $name $proto $range" + ((failures++)) + fi + done + + return "$failures" +} + +test_critical_services() { + echo "testing critical service rules in ${NYM_CHAIN}" + + local tcp_ports=(22 53 443 853 1194) + local udp_ports=(53 123 1194) + local failures=0 + + for port in "${tcp_ports[@]}"; do + if iptables -t filter -C "$NYM_CHAIN" -p tcp --dport "$port" -j ACCEPT 2>/dev/null; then + echo "tcp port $port allowed" + else + if iptables-save | grep -E "^-A $NYM_CHAIN.*tcp.*dpts:" | grep -q "$port"; then + echo "tcp port $port allowed by range" + else + echo "tcp port $port missing" + ((failures++)) + fi + fi + done + + for port in "${udp_ports[@]}"; do + if iptables -t filter -C "$NYM_CHAIN" -p udp --dport "$port" -j ACCEPT 2>/dev/null; then + echo "udp port $port allowed" + else + if iptables-save | grep -E "^-A $NYM_CHAIN.*udp.*dpts:" | grep -q "$port"; then + echo "udp port $port allowed by range" + else + echo "udp port $port missing" + ((failures++)) + fi + fi + done + + return "$failures" +} + +test_forward_chain_hook() { + echo "testing forward chain hook direction for ${NYM_CHAIN}" + + local failures=0 + + if iptables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null; then + echo "ipv4 forward hook ok: -i $WG_INTERFACE -o $NETWORK_DEVICE -> $NYM_CHAIN" + else + echo "ipv4 forward hook missing or wrong" + ((failures++)) + fi + + if ip6tables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null; then + echo "ipv6 forward hook ok: -i $WG_INTERFACE -o $NETWORK_DEVICE -> $NYM_CHAIN" + else + echo "ipv6 forward hook missing or wrong" + ((failures++)) + fi + + return "$failures" +} + +test_default_reject_rule() { + echo "testing default reject rule at end of ${NYM_CHAIN}" + + if iptables -L "$NYM_CHAIN" | grep -q "REJECT"; then + echo "default reject present in ipv4 chain" + else + echo "default reject missing in ipv4 chain" + return 1 + fi +} + +exit_policy_run_tests() { + local skip_default=0 + while [[ $# -gt 0 ]]; do + case "$1" in + --skip-default-reject) skip_default=1; shift ;; + *) echo "unknown test option: $1"; return 1 ;; + esac + done + + local total=0 + local failed=0 + + test_forward_chain_hook || ((failed++)) + ((total++)) + + test_port_range_rules || ((failed++)) + ((total++)) + + test_critical_services || ((failed++)) + ((total++)) + + if [[ $skip_default -eq 0 ]]; then + test_default_reject_rule || ((failed++)) + ((total++)) + fi + + echo "tests run: $total, failures: $failed" + if [[ $failed -eq 0 ]]; then + echo "all exit policy tests passed" + else + echo "some exit policy tests failed" + fi + + return "$failed" +} + +############################################################################### +# part 4: high level workflows +############################################################################### + +full_tunnel_setup() { + # this mirrors your previous chain of calls but inside one script + echo "running full tunnel setup for ${TUNNEL_INTERFACE} and ${WG_INTERFACE}" + + check_tunnel_iptables "$TUNNEL_INTERFACE" + remove_duplicate_rules "$TUNNEL_INTERFACE" + remove_duplicate_rules "$WG_INTERFACE" + check_tunnel_iptables "$TUNNEL_INTERFACE" + + adjust_ip_forwarding + + apply_iptables_rules "$TUNNEL_INTERFACE" + check_tunnel_iptables "$TUNNEL_INTERFACE" + + apply_iptables_rules "$WG_INTERFACE" + + configure_dns_and_icmp_wg + adjust_ip_forwarding + check_ipv6_ipv4_forwarding + + joke_through_tunnel "$TUNNEL_INTERFACE" + joke_through_tunnel "$WG_INTERFACE" + + echo "full tunnel setup completed" +} + +exit_policy_install() { + echo "installing nym wireguard exit policy for ${WG_INTERFACE} via ${NETWORK_DEVICE}" + exit_policy_install_deps + adjust_ip_forwarding + create_nym_chain + setup_nat_rules + apply_port_allowlist + apply_spamhaus_blocklist + add_default_reject_rule + save_iptables_rules + echo "nym exit policy installed" +} + +complete_networking_configuration() { + echo "starting complete networking configuration: tunnels + exit policy" + + full_tunnel_setup + exit_policy_install + exit_policy_run_tests || echo "exit policy tests reported problems, please review output" + + echo "complete networking configuration finished" +} + +############################################################################### +# cli +############################################################################### + +cmd="${1:-help}" + +case "$cmd" in + # high level workflows + full_tunnel_setup) + full_tunnel_setup + ;; + exit_policy_install) + exit_policy_install + ;; + complete_networking_configuration) + complete_networking_configuration + ;; + + # tunnel manager cmds + fetch_ipv6_address_nym_tun) + fetch_ipv6_address "$TUNNEL_INTERFACE" + ;; + fetch_and_display_ipv6) + fetch_and_display_ipv6 + ;; + apply_iptables_rules) + apply_iptables_rules "$TUNNEL_INTERFACE" + ;; + apply_iptables_rules_wg) + apply_iptables_rules "$WG_INTERFACE" + ;; + check_nymtun_iptables) + check_tunnel_iptables "$TUNNEL_INTERFACE" + ;; + check_nym_wg_tun) + check_tunnel_iptables "$WG_INTERFACE" + ;; + check_ipv6_ipv4_forwarding) + check_ipv6_ipv4_forwarding + ;; + check_ip_routing) + check_ip_routing + ;; + perform_pings) + perform_pings + ;; + joke_through_the_mixnet) + joke_through_tunnel "$TUNNEL_INTERFACE" + ;; + joke_through_wg_tunnel) + joke_through_tunnel "$WG_INTERFACE" + ;; + configure_dns_and_icmp_wg) + configure_dns_and_icmp_wg + ;; + adjust_ip_forwarding) + adjust_ip_forwarding + ;; + remove_duplicate_rules) + remove_duplicate_rules "${2:-}" + ;; + + # exit policy manager cmds + exit_policy_status) + show_exit_policy_status + ;; + exit_policy_test_connectivity) + test_exit_policy_connectivity + ;; + exit_policy_clear) + clear_exit_policy_rules + ;; + exit_policy_tests) + shift + exit_policy_run_tests "$@" + ;; + + help|--help|-h) + cat < [args] + +high level workflows: + full_tunnel_setup run tunnel iptables and checks for nymtun0 and nymwg + exit_policy_install install and configure wireguard exit policy + complete_networking_configuration run tunnel setup, exit policy install and tests + +tunnel and nat helpers: + fetch_ipv6_address_nym_tun show global ipv6 address on ${TUNNEL_INTERFACE} + fetch_and_display_ipv6 show ipv6 on uplink ${NETWORK_DEVICE} + apply_iptables_rules apply nat/forward rules for ${TUNNEL_INTERFACE} + apply_iptables_rules_wg apply nat/forward rules for ${WG_INTERFACE} + check_nymtun_iptables inspect forward chain for ${TUNNEL_INTERFACE} + check_nym_wg_tun inspect forward chain for ${WG_INTERFACE} + check_ipv6_ipv4_forwarding show ipv4/ipv6 forwarding flags + check_ip_routing show ipv4 and ipv6 routes + perform_pings test ipv4 and ipv6 pings + joke_through_the_mixnet test via ${TUNNEL_INTERFACE} with joke + joke_through_wg_tunnel test via ${WG_INTERFACE} with joke + configure_dns_and_icmp_wg allow ping and dns on this host + adjust_ip_forwarding enable ipv4/ipv6 forwarding via sysctl.d + remove_duplicate_rules deduplicate rules for interface in FORWARD and ${NYM_CHAIN} + +exit policy manager: + exit_policy_install install exit policy (iptables rules and blocklist) + exit_policy_status show status of exit policy and forwarding + exit_policy_test_connectivity test connectivity via ${WG_INTERFACE} + exit_policy_clear remove ${NYM_CHAIN} chains and hooks + exit_policy_tests [--skip-default-reject] + run verification tests on exit policy + +environment overrides: + TUNNEL_INTERFACE default nymtun0 + WG_INTERFACE default nymwg + NETWORK_DEVICE uplink device, auto-detected if not set + +EOF + ;; + *) + echo "unknown command: $cmd" + echo "run with 'help' for usage" + exit 1 + ;; +esac + +echo "operation ${cmd} completed" From e815f08505762542b82b8b2eea8e3ce58168773b Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 13:38:15 +0000 Subject: [PATCH 019/134] address comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/network-tunnel-manager.sh | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 1c869a297a..29ed4c802e 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -143,11 +143,17 @@ remove_duplicate_rules() { rules_v6=$(ip6tables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep "$interface" || true) if [[ -n "$rules_v6" ]]; then echo -e "${YELLOW}processing ipv6 rules${NC}" - echo "$rules_v6" | sort | uniq -d | while read -r dup; do - echo "removing duplicate ipv6 rule: $dup" - while ip6tables -t filter -C ${dup#-A } 2>/dev/null; do - ip6tables -t filter -D ${dup#-A } || break - done + # For each unique rule, count occurrences and remove all but one + echo "$rules_v6" | sort | uniq | while read -r rule; do + count=$(echo "$rules_v6" | grep -Fx "$rule" | wc -l) + if [[ "$count" -gt 1 ]]; then + echo "removing $((count - 1)) duplicate(s) of ipv6 rule: $rule" + for ((i=1; i/dev/null; then + ip6tables -t filter -D ${rule#-A } || break + fi + done + fi done else echo -e "${GREEN}no ipv6 rules found for $interface to deduplicate${NC}" From 694135c81bfebcc9f1c743dd49af7d733647f2f2 Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 13:38:45 +0000 Subject: [PATCH 020/134] address comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/network-tunnel-manager.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 29ed4c802e..b6babd8c65 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -531,7 +531,7 @@ EOF fi local total_rules - total_rules=$(grep -c "^ExitPolicy reject" "$POLICY_FILE" | grep -v "\*:\*" || true) + total_rules=$(grep "^ExitPolicy reject" "$POLICY_FILE" | grep -v "\*:\*" | wc -l || true) echo "processing $total_rules blocklist rules" grep "^ExitPolicy reject" "$POLICY_FILE" | grep -v "\*:\*" | while read -r line; do From 1f8144eb119a53b590d8ae4375e450fbd5d56614 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 14:47:02 +0100 Subject: [PATCH 021/134] add a safeguard --- .../nym-node-setup/network-tunnel-manager.sh | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index b6babd8c65..e50b4f8d5d 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -5,13 +5,31 @@ set -euo pipefail ############################################################################### -# safety: must run as root +# safety: must run as root, jq ############################################################################### if [ "$(id -u)" -ne 0 ]; then echo "this script must be run as root" exit 1 fi +echo "checking for jq..." + +if command -v jq >/dev/null 2>&1; then + echo "jq is already installed" + return 0 +fi + +echo "jq not found, installing..." +apt-get update -y +DEBIAN_FRONTEND=noninteractive apt-get install -y jq + +if command -v jq >/dev/null 2>&1; then + echo "jq installed successfully" +else + echo "failed to install jq" + return 1 +fi + ############################################################################### # basic config ############################################################################### @@ -966,6 +984,6 @@ EOF echo "run with 'help' for usage" exit 1 ;; + echo "operation ${cmd} completed" + ;; esac - -echo "operation ${cmd} completed" From c617bbb240d4fd16f9f7a32fd5d6e6d05be7a8ab Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 14:59:36 +0100 Subject: [PATCH 022/134] fix jq --- scripts/nym-node-setup/network-tunnel-manager.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index e50b4f8d5d..0083286aa2 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -16,7 +16,7 @@ echo "checking for jq..." if command -v jq >/dev/null 2>&1; then echo "jq is already installed" - return 0 + exit 0 fi echo "jq not found, installing..." @@ -27,7 +27,7 @@ if command -v jq >/dev/null 2>&1; then echo "jq installed successfully" else echo "failed to install jq" - return 1 + exit 1 fi ############################################################################### From aba6c9d4acc34ac824c77c97b6b65365705dcac2 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:04:17 +0100 Subject: [PATCH 023/134] fix exit message --- .../nym-node-setup/network-tunnel-manager.sh | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 0083286aa2..0a2a4c6f89 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -869,74 +869,94 @@ complete_networking_configuration() { cmd="${1:-help}" case "$cmd" in - # high level workflows full_tunnel_setup) full_tunnel_setup + status=$? ;; exit_policy_install) exit_policy_install + status=$? ;; complete_networking_configuration) complete_networking_configuration + status=$? ;; # tunnel manager cmds fetch_ipv6_address_nym_tun) fetch_ipv6_address "$TUNNEL_INTERFACE" + status=$? ;; fetch_and_display_ipv6) fetch_and_display_ipv6 + status=$? ;; apply_iptables_rules) apply_iptables_rules "$TUNNEL_INTERFACE" + status=$? ;; apply_iptables_rules_wg) apply_iptables_rules "$WG_INTERFACE" + status=$? ;; check_nymtun_iptables) check_tunnel_iptables "$TUNNEL_INTERFACE" + status=$? ;; check_nym_wg_tun) check_tunnel_iptables "$WG_INTERFACE" + status=$? ;; check_ipv6_ipv4_forwarding) check_ipv6_ipv4_forwarding + status=$? ;; check_ip_routing) check_ip_routing + status=$? ;; perform_pings) perform_pings + status=$? ;; joke_through_the_mixnet) joke_through_tunnel "$TUNNEL_INTERFACE" + status=$? ;; joke_through_wg_tunnel) joke_through_tunnel "$WG_INTERFACE" + status=$? ;; configure_dns_and_icmp_wg) configure_dns_and_icmp_wg + status=$? ;; adjust_ip_forwarding) adjust_ip_forwarding + status=$? ;; remove_duplicate_rules) remove_duplicate_rules "${2:-}" + status=$? ;; # exit policy manager cmds exit_policy_status) show_exit_policy_status + status=$? ;; exit_policy_test_connectivity) test_exit_policy_connectivity + status=$? ;; exit_policy_clear) clear_exit_policy_rules + status=$? ;; exit_policy_tests) shift exit_policy_run_tests "$@" + status=$? ;; help|--help|-h) @@ -978,12 +998,17 @@ environment overrides: NETWORK_DEVICE uplink device, auto-detected if not set EOF + status=0 ;; + *) echo "unknown command: $cmd" echo "run with 'help' for usage" exit 1 ;; - echo "operation ${cmd} completed" - ;; esac + +# Only print when operation succeeded +if [ "$status" -eq 0 ]; then + echo "operation ${cmd} completed" +fi \ No newline at end of file From 71301ee0cc0f2fcfa0c2a281065fb82f042c6f91 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:08:34 +0100 Subject: [PATCH 024/134] sync ipv4 w ipv6 --- .../nym-node-setup/network-tunnel-manager.sh | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 0a2a4c6f89..241fc1137d 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -131,6 +131,7 @@ fetch_and_display_ipv6() { # dedupe / clean-up rules for an interface in FORWARD and NYM-EXIT # keeps a single copy of each rule + remove_duplicate_rules() { local interface="$1" @@ -139,29 +140,35 @@ remove_duplicate_rules() { exit 1 fi - echo -e "${YELLOW}detecting and removing duplicate rules for $interface in FORWARD and ${NYM_CHAIN}${NC}" + echo "detecting and removing duplicate rules for $interface in FORWARD and ${NYM_CHAIN}" # ipv4 local rules_v4 rules_v4=$(iptables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep "$interface" || true) + if [[ -n "$rules_v4" ]]; then - echo -e "${YELLOW}processing ipv4 rules${NC}" - echo "$rules_v4" | sort | uniq -d | while read -r dup; do - echo "removing duplicate ipv4 rule: $dup" - while iptables -t filter -C ${dup#-A } 2>/dev/null; do - iptables -t filter -D ${dup#-A } || break - done + echo "processing ipv4 rules" + echo "$rules_v4" | sort | uniq | while read -r rule; do + count=$(echo "$rules_v4" | grep -Fx "$rule" | wc -l) + if [[ "$count" -gt 1 ]]; then + echo "removing $((count - 1)) duplicate(s) of ipv4 rule: $rule" + for ((i=1; i/dev/null; then + iptables -t filter -D ${rule#-A } || break + fi + done + fi done else - echo -e "${GREEN}no ipv4 rules found for $interface to deduplicate${NC}" + echo "no ipv4 rules found for $interface to deduplicate" fi # ipv6 local rules_v6 rules_v6=$(ip6tables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep "$interface" || true) + if [[ -n "$rules_v6" ]]; then - echo -e "${YELLOW}processing ipv6 rules${NC}" - # For each unique rule, count occurrences and remove all but one + echo "processing ipv6 rules" echo "$rules_v6" | sort | uniq | while read -r rule; do count=$(echo "$rules_v6" | grep -Fx "$rule" | wc -l) if [[ "$count" -gt 1 ]]; then @@ -174,12 +181,13 @@ remove_duplicate_rules() { fi done else - echo -e "${GREEN}no ipv6 rules found for $interface to deduplicate${NC}" + echo "no ipv6 rules found for $interface to deduplicate" fi - echo -e "${GREEN}duplicate rule scan completed for $interface${NC}" + echo "duplicate rule scan completed for $interface" } + apply_iptables_rules() { local interface=$1 echo "applying iptables rules for $interface using uplink $NETWORK_DEVICE" From e2fe3a60a692b6e95489a4309b212609c4bab279 Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:01:23 +0000 Subject: [PATCH 025/134] address comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/wireguard-exit-policy/exit-policy-tests.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/wireguard-exit-policy/exit-policy-tests.sh b/scripts/wireguard-exit-policy/exit-policy-tests.sh index e0f86e5969..0734f19318 100644 --- a/scripts/wireguard-exit-policy/exit-policy-tests.sh +++ b/scripts/wireguard-exit-policy/exit-policy-tests.sh @@ -199,7 +199,9 @@ test_forward_chain_hook() { fi # Check rule position (should be before UFW rules) - local rule_num=$(iptables -L FORWARD -n --line-numbers | grep -E "$NYM_CHAIN.*$WG_INTERFACE.*$NETWORK_DEVICE" | awk '{print $1}' | head -1) + local rule_num=$(iptables -L FORWARD -n --line-numbers -v | awk -v chain="$NYM_CHAIN" -v in="$WG_INTERFACE" -v out="$NETWORK_DEVICE" ' + $0 ~ chain && $0 ~ in && $0 ~ out {print $1; exit} + ') if [[ -n "$rule_num" ]]; then if [[ $rule_num -le 5 ]]; then echo -e "${GREEN}✓ Rule is early in FORWARD chain (position #$rule_num) - good for UFW compatibility${NC}" From 70a119ac587f6cb3aea1d6004221519471e93baa Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:09:38 +0000 Subject: [PATCH 026/134] address comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/network-tunnel-manager.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 241fc1137d..021b8cd818 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -16,7 +16,7 @@ echo "checking for jq..." if command -v jq >/dev/null 2>&1; then echo "jq is already installed" - exit 0 + # continue script execution fi echo "jq not found, installing..." From d04b61a88bbd86bd9da45cccabeb7e9bc5c584e8 Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:10:01 +0000 Subject: [PATCH 027/134] spacing Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/network-tunnel-manager.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 021b8cd818..729dec9767 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -517,7 +517,7 @@ apply_port_allowlist() { ["NDMP"]="10000" ["OpenPGP"]="11371" ["Monero"]="18080-18081" - ["MoneroRPC"]="18089" + ["MoneroRPC"]="18089" ["GoogleVoice"]="19294" ["EnsimControlPanel"]="19638" ["DarkFiTor"]="25551" From c6a0256b0386137fbcd2c73894d491a01c9c3b51 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 16:12:52 +0100 Subject: [PATCH 028/134] remove wrong stdout --- scripts/nym-node-setup/network-tunnel-manager.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 729dec9767..6d8626078e 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -142,6 +142,7 @@ remove_duplicate_rules() { echo "detecting and removing duplicate rules for $interface in FORWARD and ${NYM_CHAIN}" + # ipv4 local rules_v4 rules_v4=$(iptables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep "$interface" || true) @@ -282,7 +283,7 @@ joke_through_tunnel() { if ping -c 1 -I "$ipv4_address" google.com >/dev/null 2>&1; then echo -e "${green}ipv4 connectivity is working. fetching a joke${reset}" - joke=$(curl -s -H "Accept: application/json" --interface "$ipv4_address" https://icanhazdadjoke.com/ | jq -r .joke || true) + joke=$(curl -s -H "Accept: application/json" --interface "$ipv4_address" https://icanhazdadjoke.com/ | jq -r .joke) [[ -n "$joke" && "$joke" != "null" ]] && echo -e "${green}ipv4 joke: $joke${reset}" || echo "failed to fetch a joke via ipv4" else echo -e "${red}ipv4 connectivity is not working for $interface. verify your routing and nat settings${reset}" @@ -300,7 +301,7 @@ joke_through_tunnel() { if ping6 -c 1 -I "$ipv6_address" google.com >/dev/null 2>&1; then echo -e "${green}ipv6 connectivity is working. fetching a joke${reset}" - joke=$(curl -s -H "Accept: application/json" --interface "$ipv6_address" https://icanhazdadjoke.com/ | jq -r .joke || true) + joke=$(curl -s -H "Accept: application/json" --interface "$ipv6_address" https://icanhazdadjoke.com/ | jq -r .joke) [[ -n "$joke" && "$joke" != "null" ]] && echo -e "${green}ipv6 joke: $joke${reset}" || echo -e "${red}failed to fetch a joke via ipv6${reset}" else echo -e "${red}ipv6 connectivity is not working for $interface. verify your routing and nat settings${reset}" From 06dd74ba349410362d642fe6feb6482ad6c2e81f Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:18:38 +0000 Subject: [PATCH 029/134] address comments Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../nym-node-setup/network-tunnel-manager.sh | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 6d8626078e..daf3ed17bd 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -17,17 +17,17 @@ echo "checking for jq..." if command -v jq >/dev/null 2>&1; then echo "jq is already installed" # continue script execution -fi - -echo "jq not found, installing..." -apt-get update -y -DEBIAN_FRONTEND=noninteractive apt-get install -y jq - -if command -v jq >/dev/null 2>&1; then - echo "jq installed successfully" else - echo "failed to install jq" - exit 1 + echo "jq not found, installing..." + apt-get update -y + DEBIAN_FRONTEND=noninteractive apt-get install -y jq + + if command -v jq >/dev/null 2>&1; then + echo "jq installed successfully" + else + echo "failed to install jq" + exit 1 + fi fi ############################################################################### From c5971d0e9d0bb5dc3d8166f18022423cb966f91d Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:18:54 +0000 Subject: [PATCH 030/134] align space Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/network-tunnel-manager.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index daf3ed17bd..2251614470 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -518,7 +518,7 @@ apply_port_allowlist() { ["NDMP"]="10000" ["OpenPGP"]="11371" ["Monero"]="18080-18081" - ["MoneroRPC"]="18089" + ["MoneroRPC"]="18089" ["GoogleVoice"]="19294" ["EnsimControlPanel"]="19638" ["DarkFiTor"]="25551" From a6fe1b1de7713594b65750de42dda0d51a6045bb Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 16:32:40 +0100 Subject: [PATCH 031/134] fix logic to ensure to more robust --- .../nym-node-setup/network-tunnel-manager.sh | 79 +++++++++++++++++-- 1 file changed, 71 insertions(+), 8 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 2251614470..93229176c2 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -142,45 +142,109 @@ remove_duplicate_rules() { echo "detecting and removing duplicate rules for $interface in FORWARD and ${NYM_CHAIN}" - + # # ipv4 + # local rules_v4 rules_v4=$(iptables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep "$interface" || true) if [[ -n "$rules_v4" ]]; then echo "processing ipv4 rules" + echo "$rules_v4" | sort | uniq | while read -r rule; do + local count count=$(echo "$rules_v4" | grep -Fx "$rule" | wc -l) + if [[ "$count" -gt 1 ]]; then echo "removing $((count - 1)) duplicate(s) of ipv4 rule: $rule" + for ((i=1; i/dev/null; then - iptables -t filter -D ${rule#-A } || break + local cleaned="${rule#-A }" + + # try exact match delete first + if iptables -t filter -C $cleaned 2>/dev/null; then + iptables -t filter -D $cleaned && continue + fi + + # fallback: locate rule in iptables -S + local match + match=$(iptables -S | grep -F -- "$cleaned" | head -n1 || true) + + if [[ -n "$match" ]]; then + # match looks like: -A FORWARD ...full rule... + local chain + chain=$(echo "$match" | awk '{print $2}') + + # find the rule index from iptables -L --line-numbers + local index + index=$(iptables -L "$chain" --line-numbers | grep -F "$interface" | awk 'NR==1{print $1}') + + if [[ -n "$index" ]]; then + iptables -D "$chain" "$index" 2>/dev/null || \ + echo "warning: failed to delete ipv4 duplicate via index ($chain $index)" + else + echo "warning: unable to locate ipv4 duplicate index for: $rule" + fi + else + echo "warning: could not match ipv4 duplicate rule reliably: $rule" fi done fi done + else echo "no ipv4 rules found for $interface to deduplicate" fi + # # ipv6 + # local rules_v6 rules_v6=$(ip6tables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep "$interface" || true) if [[ -n "$rules_v6" ]]; then echo "processing ipv6 rules" + echo "$rules_v6" | sort | uniq | while read -r rule; do + local count count=$(echo "$rules_v6" | grep -Fx "$rule" | wc -l) + if [[ "$count" -gt 1 ]]; then echo "removing $((count - 1)) duplicate(s) of ipv6 rule: $rule" + for ((i=1; i/dev/null; then - ip6tables -t filter -D ${rule#-A } || break + local cleaned="${rule#-A }" + + # try exact delete first + if ip6tables -t filter -C $cleaned 2>/dev/null; then + ip6tables -t filter -D $cleaned && continue fi + + # fallback: find matching rule in ip6tables -S + local match + match=$(ip6tables -S | grep -F -- "$cleaned" | head -n1 || true) + + if [[ -n "$match" ]]; then + local chain + chain=$(echo "$match" | awk '{print $2}') + + local index + index=$(ip6tables -L "$chain" --line-numbers | grep -F "$interface" | awk 'NR==1{print $1}') + + if [[ -n "$index" ]]; then + ip6tables -D "$chain" "$index" 2>/dev/null || \ + echo "warning: failed to delete ipv6 duplicate via index ($chain $index)" + else + echo "warning: unable to locate ipv6 duplicate index for: $rule" + fi + else + echo "warning: could not match ipv6 duplicate rule reliably: $rule" + fi + done fi done + else echo "no ipv6 rules found for $interface to deduplicate" fi @@ -1017,7 +1081,6 @@ EOF ;; esac -# Only print when operation succeeded -if [ "$status" -eq 0 ]; then +if [ "${status:-1}" -eq 0 ]; then echo "operation ${cmd} completed" -fi \ No newline at end of file +fi From 04be5624fae8a8fea8b03c9acf9e07a5fd58f35c Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 16:41:42 +0100 Subject: [PATCH 032/134] ensure cars passing in a shell --- scripts/nym-node-setup/network-tunnel-manager.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 93229176c2..2f3d9b2424 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -151,7 +151,9 @@ remove_duplicate_rules() { if [[ -n "$rules_v4" ]]; then echo "processing ipv4 rules" - echo "$rules_v4" | sort | uniq | while read -r rule; do + while read -r rule; do + [[ -z "$rule" ]] && continue + local count count=$(echo "$rules_v4" | grep -Fx "$rule" | wc -l) @@ -171,11 +173,9 @@ remove_duplicate_rules() { match=$(iptables -S | grep -F -- "$cleaned" | head -n1 || true) if [[ -n "$match" ]]; then - # match looks like: -A FORWARD ...full rule... local chain chain=$(echo "$match" | awk '{print $2}') - # find the rule index from iptables -L --line-numbers local index index=$(iptables -L "$chain" --line-numbers | grep -F "$interface" | awk 'NR==1{print $1}') @@ -190,7 +190,7 @@ remove_duplicate_rules() { fi done fi - done + done < <(echo "$rules_v4" | sort | uniq) else echo "no ipv4 rules found for $interface to deduplicate" From 4e1228fff0ba7e7db54ec1e148557f50b0263f31 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 16:43:39 +0100 Subject: [PATCH 033/134] ensure cars passing in a shell --- .../nym-node-setup/network-tunnel-manager.sh | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 2f3d9b2424..eac8a4112a 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -625,21 +625,36 @@ EOF total_rules=$(grep "^ExitPolicy reject" "$POLICY_FILE" | grep -v "\*:\*" | wc -l || true) echo "processing $total_rules blocklist rules" - grep "^ExitPolicy reject" "$POLICY_FILE" | grep -v "\*:\*" | while read -r line; do + # + # main loop — no subshell, safe variable handling + # + while read -r line; do + [[ -z "$line" ]] && continue + local ip_range ip_range=$(echo "$line" | sed -E 's/ExitPolicy reject ([^:]+):.*/\1/') if [[ -n "$ip_range" ]]; then + + # ipv4 reject if ! iptables -C "$NYM_CHAIN" -d "$ip_range" -j REJECT 2>/dev/null; then - iptables -A "$NYM_CHAIN" -d "$ip_range" -j REJECT + iptables -A "$NYM_CHAIN" -d "$ip_range" -j REJECT || \ + echo "warning: failed adding ipv4 reject for $ip_range" fi - if [[ "$ip_range" == *":"* ]] && ! ip6tables -C "$NYM_CHAIN" -d "$ip_range" -j REJECT 2>/dev/null; then - ip6tables -A "$NYM_CHAIN" -d "$ip_range" -j REJECT + + # ipv6 reject + if [[ "$ip_range" == *":"* ]]; then + if ! ip6tables -C "$NYM_CHAIN" -d "$ip_range" -j REJECT 2>/dev/null; then + ip6tables -A "$NYM_CHAIN" -d "$ip_range" -j REJECT || \ + echo "warning: failed adding ipv6 reject for $ip_range" + fi fi fi - done + + done < <(grep "^ExitPolicy reject" "$POLICY_FILE" | grep -v "\*:\*") } + add_default_reject_rule() { echo "ensuring default reject rule at end of ${NYM_CHAIN}" From 5627ada57e003123f89048f8535502156a71426c Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:49:02 +0000 Subject: [PATCH 034/134] address comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/network-tunnel-manager.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index eac8a4112a..312b7e0913 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -41,9 +41,17 @@ WG_INTERFACE="${WG_INTERFACE:-nymwg}" NETWORK_DEVICE="${NETWORK_DEVICE:-}" if [[ -z "$NETWORK_DEVICE" ]]; then NETWORK_DEVICE="$(ip -o route show default 2>/dev/null | awk '{print $5}' | head -n1 || true)" + # Validate that NETWORK_DEVICE is non-empty and looks like a network interface + if [[ -z "$NETWORK_DEVICE" || ! "$NETWORK_DEVICE" =~ ^[a-zA-Z0-9_-]+$ ]]; then + NETWORK_DEVICE="" + fi fi if [[ -z "$NETWORK_DEVICE" ]]; then NETWORK_DEVICE="$(ip -o route show default table all 2>/dev/null | awk '{print $5}' | head -n1 || true)" + # Validate that NETWORK_DEVICE is non-empty and looks like a network interface + if [[ -z "$NETWORK_DEVICE" || ! "$NETWORK_DEVICE" =~ ^[a-zA-Z0-9_-]+$ ]]; then + NETWORK_DEVICE="" + fi fi if [[ -z "$NETWORK_DEVICE" ]]; then echo "cannot determine uplink interface. set NETWORK_DEVICE or UPLINK_DEV" From 99b28b2b6f5ce146673a8ce21225936a4dad5eaa Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:49:32 +0000 Subject: [PATCH 035/134] address comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/network-tunnel-manager.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 312b7e0913..b4b21d6531 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -172,8 +172,8 @@ remove_duplicate_rules() { local cleaned="${rule#-A }" # try exact match delete first - if iptables -t filter -C $cleaned 2>/dev/null; then - iptables -t filter -D $cleaned && continue + if iptables -t filter -C "$cleaned" 2>/dev/null; then + iptables -t filter -D "$cleaned" && continue fi # fallback: locate rule in iptables -S From 91d0b7bdad7f8481b0fde4cb672783c44e2c0f41 Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:49:49 +0000 Subject: [PATCH 036/134] address comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/network-tunnel-manager.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index b4b21d6531..529788599c 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -224,8 +224,8 @@ remove_duplicate_rules() { local cleaned="${rule#-A }" # try exact delete first - if ip6tables -t filter -C $cleaned 2>/dev/null; then - ip6tables -t filter -D $cleaned && continue + if ip6tables -t filter -C "$cleaned" 2>/dev/null; then + ip6tables -t filter -D "$cleaned" && continue fi # fallback: find matching rule in ip6tables -S From 239c6c701b83a6bac0cfb295ec8513ba21d07e3e Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:50:19 +0000 Subject: [PATCH 037/134] address comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/network-tunnel-manager.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 529788599c..79e97dd619 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -636,10 +636,9 @@ EOF # # main loop — no subshell, safe variable handling # + local ip_range while read -r line; do [[ -z "$line" ]] && continue - - local ip_range ip_range=$(echo "$line" | sed -E 's/ExitPolicy reject ([^:]+):.*/\1/') if [[ -n "$ip_range" ]]; then From 71e0c025c6d95641ab44247920f897c4dfdd26ca Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:50:42 +0000 Subject: [PATCH 038/134] address comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/network-tunnel-manager.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 79e97dd619..4609a29545 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -603,8 +603,9 @@ apply_port_allowlist() { ["Metadata"]="51830" ) + local port for service in "${!PORT_MAPPINGS[@]}"; do - local port="${PORT_MAPPINGS[$service]}" + port="${PORT_MAPPINGS[$service]}" echo "adding rules for $service (ports $port)" add_port_rules iptables "$port" "tcp" add_port_rules ip6tables "$port" "tcp" From 943b5fa8bc5d4ea9cf70e08f7c406bb707b07c36 Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:51:01 +0000 Subject: [PATCH 039/134] address comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/network-tunnel-manager.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 4609a29545..b4f5c6eb26 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -783,9 +783,9 @@ test_port_range_rules() { ) local failures=0 + local start end for entry in "${port_ranges[@]}"; do IFS=':' read -r range proto name <<<"$entry" - local start end start=$(echo "$range" | cut -d'-' -f1) end=$(echo "$range" | cut -d'-' -f2) From 1525aed657cd318482eae5a4617490753ccaf1de Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:56:18 +0000 Subject: [PATCH 040/134] expand pattern to common naming conventions Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/network-tunnel-manager.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index b4f5c6eb26..e2a8b3d5d1 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -42,14 +42,14 @@ NETWORK_DEVICE="${NETWORK_DEVICE:-}" if [[ -z "$NETWORK_DEVICE" ]]; then NETWORK_DEVICE="$(ip -o route show default 2>/dev/null | awk '{print $5}' | head -n1 || true)" # Validate that NETWORK_DEVICE is non-empty and looks like a network interface - if [[ -z "$NETWORK_DEVICE" || ! "$NETWORK_DEVICE" =~ ^[a-zA-Z0-9_-]+$ ]]; then + if [[ -z "$NETWORK_DEVICE" || ! "$NETWORK_DEVICE" =~ ^[a-zA-Z0-9._-]+$ ]]; then NETWORK_DEVICE="" fi fi if [[ -z "$NETWORK_DEVICE" ]]; then NETWORK_DEVICE="$(ip -o route show default table all 2>/dev/null | awk '{print $5}' | head -n1 || true)" # Validate that NETWORK_DEVICE is non-empty and looks like a network interface - if [[ -z "$NETWORK_DEVICE" || ! "$NETWORK_DEVICE" =~ ^[a-zA-Z0-9_-]+$ ]]; then + if [[ -z "$NETWORK_DEVICE" || ! "$NETWORK_DEVICE" =~ ^[a-zA-Z0-9._-]+$ ]]; then NETWORK_DEVICE="" fi fi From aea74425258ea271a12c9a4b258a493d9257e587 Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:56:52 +0000 Subject: [PATCH 041/134] add status Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/network-tunnel-manager.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index e2a8b3d5d1..0563510fc2 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -1107,3 +1107,4 @@ esac if [ "${status:-1}" -eq 0 ]; then echo "operation ${cmd} completed" fi +exit $status From 219f3af9675d4a6798a9dcceaea2013a50a5c83c Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 16:57:34 +0100 Subject: [PATCH 042/134] remove subshell --- .../nym-node-setup/network-tunnel-manager.sh | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 0563510fc2..e31051d825 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -635,34 +635,43 @@ EOF echo "processing $total_rules blocklist rules" # - # main loop — no subshell, safe variable handling + # SAFE non-subshell loop using a temp file # - local ip_range - while read -r line; do + local tmpfile + tmpfile=$(mktemp) + + grep "^ExitPolicy reject" "$POLICY_FILE" | grep -v "\*:\*" > "$tmpfile" + + local line ip_range + while IFS= read -r line; do [[ -z "$line" ]] && continue + ip_range=$(echo "$line" | sed -E 's/ExitPolicy reject ([^:]+):.*/\1/') if [[ -n "$ip_range" ]]; then # ipv4 reject if ! iptables -C "$NYM_CHAIN" -d "$ip_range" -j REJECT 2>/dev/null; then - iptables -A "$NYM_CHAIN" -d "$ip_range" -j REJECT || \ - echo "warning: failed adding ipv4 reject for $ip_range" + iptables -A "$NYM_CHAIN" -d "$ip_range" -j REJECT \ + || echo "warning: failed adding ipv4 reject for $ip_range" fi # ipv6 reject if [[ "$ip_range" == *":"* ]]; then if ! ip6tables -C "$NYM_CHAIN" -d "$ip_range" -j REJECT 2>/dev/null; then - ip6tables -A "$NYM_CHAIN" -d "$ip_range" -j REJECT || \ - echo "warning: failed adding ipv6 reject for $ip_range" + ip6tables -A "$NYM_CHAIN" -d "$ip_range" -j REJECT \ + || echo "warning: failed adding ipv6 reject for $ip_range" fi fi - fi - done < <(grep "^ExitPolicy reject" "$POLICY_FILE" | grep -v "\*:\*") + fi + done < "$tmpfile" + + rm -f "$tmpfile" } + add_default_reject_rule() { echo "ensuring default reject rule at end of ${NYM_CHAIN}" From 81fd37e5c039abce13d945e50bd26356df808d00 Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 16:02:56 +0000 Subject: [PATCH 043/134] address comments Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/network-tunnel-manager.sh | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index e31051d825..6e0a0e4bff 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -630,18 +630,14 @@ ExitPolicy reject *:* EOF fi - local total_rules - total_rules=$(grep "^ExitPolicy reject" "$POLICY_FILE" | grep -v "\*:\*" | wc -l || true) - echo "processing $total_rules blocklist rules" - - # - # SAFE non-subshell loop using a temp file - # local tmpfile tmpfile=$(mktemp) grep "^ExitPolicy reject" "$POLICY_FILE" | grep -v "\*:\*" > "$tmpfile" + local total_rules + total_rules=$(wc -l < "$tmpfile") + echo "processing $total_rules blocklist rules" local line ip_range while IFS= read -r line; do [[ -z "$line" ]] && continue From de4fb6291c6d317deed3255db6fcd0696ce79266 Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 16:03:50 +0000 Subject: [PATCH 044/134] address comments Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/network-tunnel-manager.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 6e0a0e4bff..a2c160a587 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -170,10 +170,13 @@ remove_duplicate_rules() { for ((i=1; i/dev/null; then - iptables -t filter -D "$cleaned" && continue + if iptables -t filter -C "$chain" $rest 2>/dev/null; then + iptables -t filter -D "$chain" $rest && continue fi # fallback: locate rule in iptables -S From 8c799b29760c59a3c9d1055116beb009359ad5a7 Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 16:04:34 +0000 Subject: [PATCH 045/134] address comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/network-tunnel-manager.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index a2c160a587..25e8ca69d7 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -225,10 +225,12 @@ remove_duplicate_rules() { for ((i=1; i/dev/null; then - ip6tables -t filter -D "$cleaned" && continue + if ip6tables -t filter -C "$chain" $rule_spec 2>/dev/null; then + ip6tables -t filter -D "$chain" $rule_spec && continue fi # fallback: find matching rule in ip6tables -S From ba0182058648e4aa577afb3d28b72649d27fd6db Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 16:05:10 +0000 Subject: [PATCH 046/134] address comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/network-tunnel-manager.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 25e8ca69d7..c09ce4cacf 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -653,7 +653,7 @@ EOF # ipv4 reject if ! iptables -C "$NYM_CHAIN" -d "$ip_range" -j REJECT 2>/dev/null; then - iptables -A "$NYM_CHAIN" -d "$ip_range" -j REJECT \ + iptables -A "$NYM_CHAIN" -d "$ip_range" -j REJECT --reject-with icmp-port-unreachable \ || echo "warning: failed adding ipv4 reject for $ip_range" fi From cf8a399089bb1d09ef2f450a34ede3ccd10a84cb Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 17:07:20 +0100 Subject: [PATCH 047/134] remove subshell --- .../nym-node-setup/network-tunnel-manager.sh | 66 +++++++++++-------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index c09ce4cacf..72c891e791 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -159,54 +159,60 @@ remove_duplicate_rules() { if [[ -n "$rules_v4" ]]; then echo "processing ipv4 rules" - while read -r rule; do + # temp file to avoid subshell loops + local tmp4 + tmp4=$(mktemp) + + printf "%s\n" "$rules_v4" | sort | uniq > "$tmp4" + + local rule count cleaned chain rest match index + + while IFS= read -r rule; do [[ -z "$rule" ]] && continue - local count - count=$(echo "$rules_v4" | grep -Fx "$rule" | wc -l) + count=$(printf "%s\n" "$rules_v4" | grep -Fx "$rule" | wc -l) if [[ "$count" -gt 1 ]]; then echo "removing $((count - 1)) duplicate(s) of ipv4 rule: $rule" for ((i=1; i/dev/null; then iptables -t filter -D "$chain" $rest && continue fi - # fallback: locate rule in iptables -S - local match + # fallback: find exact match textually in iptables -S match=$(iptables -S | grep -F -- "$cleaned" | head -n1 || true) if [[ -n "$match" ]]; then - local chain chain=$(echo "$match" | awk '{print $2}') - local index index=$(iptables -L "$chain" --line-numbers | grep -F "$interface" | awk 'NR==1{print $1}') if [[ -n "$index" ]]; then iptables -D "$chain" "$index" 2>/dev/null || \ - echo "warning: failed to delete ipv4 duplicate via index ($chain $index)" + echo "warning: failed deleting ipv4 duplicate via index ($chain $index)" else echo "warning: unable to locate ipv4 duplicate index for: $rule" fi else - echo "warning: could not match ipv4 duplicate rule reliably: $rule" + echo "warning: could not reliably match ipv4 duplicate rule: $rule" fi done fi - done < <(echo "$rules_v4" | sort | uniq) + done < "$tmp4" + + rm -f "$tmp4" else echo "no ipv4 rules found for $interface to deduplicate" fi + # # ipv6 # @@ -216,47 +222,54 @@ remove_duplicate_rules() { if [[ -n "$rules_v6" ]]; then echo "processing ipv6 rules" - echo "$rules_v6" | sort | uniq | while read -r rule; do - local count - count=$(echo "$rules_v6" | grep -Fx "$rule" | wc -l) + local tmp6 + tmp6=$(mktemp) + + printf "%s\n" "$rules_v6" | sort | uniq > "$tmp6" + + local rule count cleaned chain rule_spec match index + + while IFS= read -r rule; do + [[ -z "$rule" ]] && continue + + count=$(printf "%s\n" "$rules_v6" | grep -Fx "$rule" | wc -l) if [[ "$count" -gt 1 ]]; then echo "removing $((count - 1)) duplicate(s) of ipv6 rule: $rule" for ((i=1; i/dev/null; then ip6tables -t filter -D "$chain" $rule_spec && continue fi - # fallback: find matching rule in ip6tables -S - local match + # fallback lookup in ip6tables -S match=$(ip6tables -S | grep -F -- "$cleaned" | head -n1 || true) if [[ -n "$match" ]]; then - local chain chain=$(echo "$match" | awk '{print $2}') - local index index=$(ip6tables -L "$chain" --line-numbers | grep -F "$interface" | awk 'NR==1{print $1}') if [[ -n "$index" ]]; then ip6tables -D "$chain" "$index" 2>/dev/null || \ - echo "warning: failed to delete ipv6 duplicate via index ($chain $index)" + echo "warning: failed deleting ipv6 duplicate via index ($chain $index)" else echo "warning: unable to locate ipv6 duplicate index for: $rule" fi else echo "warning: could not match ipv6 duplicate rule reliably: $rule" fi - done fi - done + + done < "$tmp6" + + rm -f "$tmp6" else echo "no ipv6 rules found for $interface to deduplicate" @@ -266,6 +279,7 @@ remove_duplicate_rules() { } + apply_iptables_rules() { local interface=$1 echo "applying iptables rules for $interface using uplink $NETWORK_DEVICE" From a38917cb9bb94c70c56e2996ecb10f3f33cfd5ef Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 16:22:34 +0000 Subject: [PATCH 048/134] address comments Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/network-tunnel-manager.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 72c891e791..0e1cf0062c 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -181,8 +181,8 @@ remove_duplicate_rules() { rest=$(echo "$cleaned" | cut -d' ' -f2-) # try exact delete first - if iptables -t filter -C "$chain" $rest 2>/dev/null; then - iptables -t filter -D "$chain" $rest && continue + if iptables -t filter -C "$chain" "$rest" 2>/dev/null; then + iptables -t filter -D "$chain" "$rest" && continue fi # fallback: find exact match textually in iptables -S From 45e14a7fb1cf00c0452d404c1993d4c9e3bfc34e Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 16:22:57 +0000 Subject: [PATCH 049/134] address comments Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/network-tunnel-manager.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 0e1cf0062c..b262cf4d86 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -243,8 +243,8 @@ remove_duplicate_rules() { rule_spec="${cleaned#"$chain" }" # try exact delete first - if ip6tables -t filter -C "$chain" $rule_spec 2>/dev/null; then - ip6tables -t filter -D "$chain" $rule_spec && continue + if ip6tables -t filter -C "$chain" "$rule_spec" 2>/dev/null; then + ip6tables -t filter -D "$chain" "$rule_spec" && continue fi # fallback lookup in ip6tables -S From 8ca6af7c867003a94137eb1bb111c5a8fe30fff5 Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 16:23:18 +0000 Subject: [PATCH 050/134] syntax fix Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/network-tunnel-manager.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index b262cf4d86..07ec842fda 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -144,7 +144,7 @@ remove_duplicate_rules() { local interface="$1" if [[ -z "$interface" ]]; then - echo "error: no interface specified. usage: $0 remove_duplicate_rules " + echo "Error: No interface specified. Usage: $0 remove_duplicate_rules " exit 1 fi From 76fc9f4a90ff6a71b5c370353f8816f4e237a9c7 Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 16:23:38 +0000 Subject: [PATCH 051/134] syntax fix Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/network-tunnel-manager.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 07ec842fda..f0a100c7e7 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -8,7 +8,7 @@ set -euo pipefail # safety: must run as root, jq ############################################################################### if [ "$(id -u)" -ne 0 ]; then - echo "this script must be run as root" + echo "This script must be run as root" exit 1 fi From 5ba181b11815a13cc8c66d03d099c4acd11fca6d Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 17:47:58 +0100 Subject: [PATCH 052/134] break into args --- .../nym-node-setup/network-tunnel-manager.sh | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index f0a100c7e7..fa32cf1cdd 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -159,10 +159,8 @@ remove_duplicate_rules() { if [[ -n "$rules_v4" ]]; then echo "processing ipv4 rules" - # temp file to avoid subshell loops local tmp4 tmp4=$(mktemp) - printf "%s\n" "$rules_v4" | sort | uniq > "$tmp4" local rule count cleaned chain rest match index @@ -180,17 +178,19 @@ remove_duplicate_rules() { chain=$(echo "$cleaned" | awk '{print $1}') rest=$(echo "$cleaned" | cut -d' ' -f2-) + # split "rest" into correct argv tokens + read -ra RULE_ARR <<<"$rest" + # try exact delete first - if iptables -t filter -C "$chain" "$rest" 2>/dev/null; then - iptables -t filter -D "$chain" "$rest" && continue + if iptables -t filter -C "$chain" "${RULE_ARR[@]}" 2>/dev/null; then + iptables -t filter -D "$chain" "${RULE_ARR[@]}" && continue fi - # fallback: find exact match textually in iptables -S + # fallback: find textual rule in iptables -S match=$(iptables -S | grep -F -- "$cleaned" | head -n1 || true) if [[ -n "$match" ]]; then chain=$(echo "$match" | awk '{print $2}') - index=$(iptables -L "$chain" --line-numbers | grep -F "$interface" | awk 'NR==1{print $1}') if [[ -n "$index" ]]; then @@ -202,6 +202,7 @@ remove_duplicate_rules() { else echo "warning: could not reliably match ipv4 duplicate rule: $rule" fi + done fi done < "$tmp4" @@ -224,7 +225,6 @@ remove_duplicate_rules() { local tmp6 tmp6=$(mktemp) - printf "%s\n" "$rules_v6" | sort | uniq > "$tmp6" local rule count cleaned chain rule_spec match index @@ -242,17 +242,19 @@ remove_duplicate_rules() { chain="${cleaned%% *}" rule_spec="${cleaned#"$chain" }" - # try exact delete first - if ip6tables -t filter -C "$chain" "$rule_spec" 2>/dev/null; then - ip6tables -t filter -D "$chain" "$rule_spec" && continue + # split rule_spec safely + read -ra RULE6_ARR <<<"$rule_spec" + + # try exact match delete + if ip6tables -t filter -C "$chain" "${RULE6_ARR[@]}" 2>/dev/null; then + ip6tables -t filter -D "$chain" "${RULE6_ARR[@]}" && continue fi - # fallback lookup in ip6tables -S + # fallback: lookup exact text in ip6tables -S match=$(ip6tables -S | grep -F -- "$cleaned" | head -n1 || true) if [[ -n "$match" ]]; then chain=$(echo "$match" | awk '{print $2}') - index=$(ip6tables -L "$chain" --line-numbers | grep -F "$interface" | awk 'NR==1{print $1}') if [[ -n "$index" ]]; then @@ -264,6 +266,7 @@ remove_duplicate_rules() { else echo "warning: could not match ipv6 duplicate rule reliably: $rule" fi + done fi @@ -280,6 +283,7 @@ remove_duplicate_rules() { + apply_iptables_rules() { local interface=$1 echo "applying iptables rules for $interface using uplink $NETWORK_DEVICE" From 766024be277b3bec62dc9b310c1fc297dee2995b Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 17:51:39 +0100 Subject: [PATCH 053/134] break into args --- .../nym-node-setup/network-tunnel-manager.sh | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index fa32cf1cdd..66180d67d3 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -164,11 +164,11 @@ remove_duplicate_rules() { printf "%s\n" "$rules_v4" | sort | uniq > "$tmp4" local rule count cleaned chain rest match index - while IFS= read -r rule; do [[ -z "$rule" ]] && continue - count=$(printf "%s\n" "$rules_v4" | grep -Fx "$rule" | wc -l) + # FIX: protect grep from rule content becoming flags + count=$(printf "%s\n" "$rules_v4" | grep -F -- "$rule" | wc -l) if [[ "$count" -gt 1 ]]; then echo "removing $((count - 1)) duplicate(s) of ipv4 rule: $rule" @@ -178,15 +178,12 @@ remove_duplicate_rules() { chain=$(echo "$cleaned" | awk '{print $1}') rest=$(echo "$cleaned" | cut -d' ' -f2-) - # split "rest" into correct argv tokens read -ra RULE_ARR <<<"$rest" - # try exact delete first if iptables -t filter -C "$chain" "${RULE_ARR[@]}" 2>/dev/null; then iptables -t filter -D "$chain" "${RULE_ARR[@]}" && continue fi - # fallback: find textual rule in iptables -S match=$(iptables -S | grep -F -- "$cleaned" | head -n1 || true) if [[ -n "$match" ]]; then @@ -202,9 +199,9 @@ remove_duplicate_rules() { else echo "warning: could not reliably match ipv4 duplicate rule: $rule" fi - done fi + done < "$tmp4" rm -f "$tmp4" @@ -214,6 +211,7 @@ remove_duplicate_rules() { fi + # # ipv6 # @@ -228,11 +226,11 @@ remove_duplicate_rules() { printf "%s\n" "$rules_v6" | sort | uniq > "$tmp6" local rule count cleaned chain rule_spec match index - while IFS= read -r rule; do [[ -z "$rule" ]] && continue - count=$(printf "%s\n" "$rules_v6" | grep -Fx "$rule" | wc -l) + # FIX: protect grep from interpreting rule as flags + count=$(printf "%s\n" "$rules_v6" | grep -F -- "$rule" | wc -l) if [[ "$count" -gt 1 ]]; then echo "removing $((count - 1)) duplicate(s) of ipv6 rule: $rule" @@ -242,19 +240,17 @@ remove_duplicate_rules() { chain="${cleaned%% *}" rule_spec="${cleaned#"$chain" }" - # split rule_spec safely read -ra RULE6_ARR <<<"$rule_spec" - # try exact match delete if ip6tables -t filter -C "$chain" "${RULE6_ARR[@]}" 2>/dev/null; then ip6tables -t filter -D "$chain" "${RULE6_ARR[@]}" && continue fi - # fallback: lookup exact text in ip6tables -S match=$(ip6tables -S | grep -F -- "$cleaned" | head -n1 || true) if [[ -n "$match" ]]; then chain=$(echo "$match" | awk '{print $2}') + index=$(ip6tables -L "$chain" --line-numbers | grep -F "$interface" | awk 'NR==1{print $1}') if [[ -n "$index" ]]; then @@ -266,7 +262,6 @@ remove_duplicate_rules() { else echo "warning: could not match ipv6 duplicate rule reliably: $rule" fi - done fi From 1559f6a9126d7e25a9ca7101da99f2d503754290 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 17:55:57 +0100 Subject: [PATCH 054/134] bugfix --- scripts/nym-node-setup/network-tunnel-manager.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 66180d67d3..66e412d629 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -154,7 +154,7 @@ remove_duplicate_rules() { # ipv4 # local rules_v4 - rules_v4=$(iptables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep "$interface" || true) + rules_v4=$(iptables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep -F -- "$interface" || true) if [[ -n "$rules_v4" ]]; then echo "processing ipv4 rules" @@ -216,7 +216,7 @@ remove_duplicate_rules() { # ipv6 # local rules_v6 - rules_v6=$(ip6tables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep "$interface" || true) + rules_v6=$(ip6tables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep -F -- "$interface" || true) if [[ -n "$rules_v6" ]]; then echo "processing ipv6 rules" From 4e5d88f64c702c04b127b4f3b45f4a4d249d059a Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 17:26:20 +0000 Subject: [PATCH 055/134] deleting to resolve merge confilict --- .../wireguard-exit-policy-manager.sh | 699 ------------------ 1 file changed, 699 deletions(-) delete mode 100644 scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh diff --git a/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh b/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh deleted file mode 100644 index f3288b6204..0000000000 --- a/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh +++ /dev/null @@ -1,699 +0,0 @@ -#!/bin/bash -# -# Nym Wireguard Exit Policy Manager -# Version: 1.0.0 -# -# This script manages iptables rules for Nym Wireguard exit policies -# Features: -# - Implements the Nym exit policy from official documentation -# - Makes rules persistent across reboots -# - Provides commands to inspect and manage rules -# - Groups rules logically for easier management -# - Integrates with existing Nym node configuration -# -# Usage: ./wireguard-exit-policy-manager.sh [command] - -set -e - -NETWORK_DEVICE=$(ip route show default | awk '/default/ {print $5}') -WG_INTERFACE="nymwg" -NYM_CHAIN="NYM-EXIT" -POLICY_FILE="/etc/nym/exit-policy.txt" -EXIT_POLICY_LOCATION="https://nymtech.net/.wellknown/network-requester/exit-policy.txt" - -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[0;33m' -NC='\033[0m' - -add_port_rules() { - local chain="$1" - local port="$2" - local protocol="${3:-tcp}" - - # Check if the port contains a range - if [[ "$port" == *"-"* ]]; then - # Port range handling - add as a single rule with a range - local start_port=$(echo "$port" | cut -d'-' -f1) - local end_port=$(echo "$port" | cut -d'-' -f2) - - if ! $chain -C "$NYM_CHAIN" -p "$protocol" --dport "$start_port:$end_port" -j ACCEPT 2>/dev/null; then - $chain -A "$NYM_CHAIN" -p "$protocol" --dport "$start_port:$end_port" -j ACCEPT - echo -e " ${GREEN}Added: $NYM_CHAIN $protocol port range $start_port:$end_port${NC}" - fi - else - # Single port handling - if ! $chain -C "$NYM_CHAIN" -p "$protocol" --dport "$port" -j ACCEPT 2>/dev/null; then - $chain -A "$NYM_CHAIN" -p "$protocol" --dport "$port" -j ACCEPT - echo -e " ${GREEN}Added: $NYM_CHAIN $protocol port $port${NC}" - fi - fi -} - -install_dependencies() { - if ! dpkg -s iptables-persistent >/dev/null 2>&1; then - echo -e "${YELLOW}Installing iptables-persistent...${NC}" - apt-get update - DEBIAN_FRONTEND=noninteractive apt-get install -y iptables-persistent - echo -e "${GREEN}iptables-persistent installed.${NC}" - else - echo -e "${GREEN}iptables-persistent is already installed.${NC}" - fi - - # Check for other required dependencies - for cmd in iptables ip6tables ip grep sed awk wget curl; do - if ! command -v "$cmd" &>/dev/null; then - echo -e "${YELLOW}Installing $cmd...${NC}" - apt-get install -y "$cmd" - fi - done -} - -configure_ip_forwarding() { - echo -e "${YELLOW}Configuring IP forwarding...${NC}" - - # Remove any existing forwarding settings to avoid duplicates - sed -i "/^net.ipv6.conf.all.forwarding=/d" /etc/sysctl.conf - sed -i "/^net.ipv4.ip_forward=/d" /etc/sysctl.conf - - # Add forwarding settings - echo "net.ipv6.conf.all.forwarding=1" | tee -a /etc/sysctl.conf - echo "net.ipv4.ip_forward=1" | tee -a /etc/sysctl.conf - - # Apply changes - sysctl -p /etc/sysctl.conf - - # Verify settings - ipv4_forwarding=$(cat /proc/sys/net/ipv4/ip_forward) - ipv6_forwarding=$(cat /proc/sys/net/ipv6/conf/all/forwarding) - - if [ "$ipv4_forwarding" == "1" ] && [ "$ipv6_forwarding" == "1" ]; then - echo -e "${GREEN}IP forwarding configured successfully.${NC}" - else - echo -e "${RED}Failed to configure IP forwarding.${NC}" - exit 1 - fi -} - -create_nym_chain() { - echo -e "${YELLOW}Creating Nym exit policy chain...${NC}" - - # Check if the chain already exists - if iptables -L "$NYM_CHAIN" &>/dev/null; then - echo -e "${YELLOW}Chain $NYM_CHAIN already exists. Flushing it...${NC}" - iptables -F "$NYM_CHAIN" - else - echo -e "${YELLOW}Creating chain $NYM_CHAIN...${NC}" - iptables -N "$NYM_CHAIN" - fi - - # Do the same for IPv6 - if ip6tables -L "$NYM_CHAIN" &>/dev/null; then - echo -e "${YELLOW}Chain $NYM_CHAIN already exists in ip6tables. Flushing it...${NC}" - ip6tables -F "$NYM_CHAIN" - else - echo -e "${YELLOW}Creating chain $NYM_CHAIN in ip6tables...${NC}" - ip6tables -N "$NYM_CHAIN" - fi - - # Link it to the FORWARD chain if not already linked - if ! iptables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null; then - echo -e "${YELLOW}Linking $NYM_CHAIN to FORWARD chain...${NC}" - iptables -I FORWARD 1 -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" - fi - - # Link IPv6 chain - if ! ip6tables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null; then - echo -e "${YELLOW}Linking $NYM_CHAIN to IPv6 FORWARD chain...${NC}" - ip6tables -I FORWARD 1 -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" - fi -} - -setup_nat_rules() { - echo -e "${YELLOW}Setting up NAT rules...${NC}" - - # Check if NAT rule for IPv4 exists - if ! iptables -t nat -C POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE 2>/dev/null; then - iptables -t nat -A POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE - echo -e "${GREEN}Added IPv4 NAT rule.${NC}" - else - echo -e "${GREEN}IPv4 NAT rule already exists.${NC}" - fi - - # Check if NAT rule for IPv6 exists - if ! ip6tables -t nat -C POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE 2>/dev/null; then - ip6tables -t nat -A POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE - echo -e "${GREEN}Added IPv6 NAT rule.${NC}" - else - echo -e "${GREEN}IPv6 NAT rule already exists.${NC}" - fi - - # Setup forwarding rules for Wireguard interface - if ! iptables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT 2>/dev/null; then - iptables -A FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT - echo -e "${GREEN}Added IPv4 forwarding rule (WG → Internet).${NC}" - fi - - if ! iptables -C FORWARD -i "$NETWORK_DEVICE" -o "$WG_INTERFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null; then - iptables -A FORWARD -i "$NETWORK_DEVICE" -o "$WG_INTERFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT - echo -e "${GREEN}Added IPv4 forwarding rule (Internet → WG for established connections).${NC}" - fi - - # IPv6 forwarding rules - if ! ip6tables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT 2>/dev/null; then - ip6tables -A FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT - echo -e "${GREEN}Added IPv6 forwarding rule (WG → Internet).${NC}" - fi - - if ! ip6tables -C FORWARD -i "$NETWORK_DEVICE" -o "$WG_INTERFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null; then - ip6tables -A FORWARD -i "$NETWORK_DEVICE" -o "$WG_INTERFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT - echo -e "${GREEN}Added IPv6 forwarding rule (Internet → WG for established connections).${NC}" - fi -} - -configure_dns_and_icmp() { - echo -e "${YELLOW}Configuring DNS and ICMP rules...${NC}" - - # ICMP rules for ping - if ! iptables -C INPUT -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null; then - iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT - echo -e "${GREEN}Added IPv4 ICMP rule (allow ping requests).${NC}" - fi - - if ! iptables -C OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null; then - iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT - echo -e "${GREEN}Added IPv4 ICMP rule (allow ping replies).${NC}" - fi - - # ICMPv6 rules for ping6 - if ! ip6tables -C INPUT -p ipv6-icmp -j ACCEPT 2>/dev/null; then - ip6tables -A INPUT -p ipv6-icmp -j ACCEPT - echo -e "${GREEN}Added IPv6 ICMP rule (allow ping6).${NC}" - fi - - # DNS rules - if ! iptables -C INPUT -p udp --dport 53 -j ACCEPT 2>/dev/null; then - iptables -A INPUT -p udp --dport 53 -j ACCEPT - echo -e "${GREEN}Added IPv4 DNS rule (UDP).${NC}" - fi - - if ! iptables -C INPUT -p tcp --dport 53 -j ACCEPT 2>/dev/null; then - iptables -A INPUT -p tcp --dport 53 -j ACCEPT - echo -e "${GREEN}Added IPv4 DNS rule (TCP).${NC}" - fi - - # IPv6 DNS rules - if ! ip6tables -C INPUT -p udp --dport 53 -j ACCEPT 2>/dev/null; then - ip6tables -A INPUT -p udp --dport 53 -j ACCEPT - echo -e "${GREEN}Added IPv6 DNS rule (UDP).${NC}" - fi - - if ! ip6tables -C INPUT -p tcp --dport 53 -j ACCEPT 2>/dev/null; then - ip6tables -A INPUT -p tcp --dport 53 -j ACCEPT - echo -e "${GREEN}Added IPv6 DNS rule (TCP).${NC}" - fi -} - -# Apply Spamhaus blocklist from the Nym exit policy -apply_spamhaus_blocklist() { - echo -e "${YELLOW}Applying Spamhaus blocklist...${NC}" - - # Create directory if not exists - mkdir -p "$(dirname "$POLICY_FILE")" - - # Try to download the policy file - echo -e "${YELLOW}Downloading exit policy from $EXIT_POLICY_LOCATION${NC}" - if ! wget -q "$EXIT_POLICY_LOCATION" -O "$POLICY_FILE" 2>/dev/null; then - echo -e "${RED}Failed to download exit policy. Using minimal blocklist.${NC}" - - # Create a minimal policy file with a few entries - cat >"$POLICY_FILE" </dev/null; then - iptables -A "$NYM_CHAIN" -d "$ip_range" -j REJECT - fi - - # Apply IPv6 rules for IPv6 addresses - if [[ "$ip_range" == *":"* ]] && ! ip6tables -C "$NYM_CHAIN" -d "$ip_range" -j REJECT 2>/dev/null; then - ip6tables -A "$NYM_CHAIN" -d "$ip_range" -j REJECT - fi - fi - done - - echo -e "${GREEN}Blocklist applied successfully.${NC}" -} - -add_default_reject_rule() { - echo -e "${YELLOW}Adding default reject rule...${NC}" - - # First remove any existing plain reject rules (without specific destinations) - iptables -D "$NYM_CHAIN" -j REJECT 2>/dev/null || true - iptables -D "$NYM_CHAIN" -j REJECT --reject-with icmp-port-unreachable 2>/dev/null || true - ip6tables -D "$NYM_CHAIN" -j REJECT 2>/dev/null || true - ip6tables -D "$NYM_CHAIN" -j REJECT --reject-with icmp6-port-unreachable 2>/dev/null || true - - # Add the default catch-all reject rule (must be the last rule in the chain) - iptables -A "$NYM_CHAIN" -j REJECT --reject-with icmp-port-unreachable - ip6tables -A "$NYM_CHAIN" -j REJECT --reject-with icmp6-port-unreachable - - echo -e "${GREEN}Default reject rule added successfully.${NC}" -} - -apply_port_allowlist() { - echo -e "${YELLOW}Applying allowed ports...${NC}" - - # Insert DNS rules at the very beginning of NYM-EXIT chain, this ensures DNS queries are never blocked by REJECT rules - echo -e "${YELLOW}Ensuring DNS is at the beginning of $NYM_CHAIN...${NC}" - - iptables -I "$NYM_CHAIN" 1 -p udp --dport 53 -j ACCEPT - iptables -I "$NYM_CHAIN" 2 -p tcp --dport 53 -j ACCEPT - ip6tables -I "$NYM_CHAIN" 1 -p udp --dport 53 -j ACCEPT - ip6tables -I "$NYM_CHAIN" 2 -p tcp --dport 53 -j ACCEPT - - # ICMP is needed because the probe tests DNS by pinging hostnames - iptables -I "$NYM_CHAIN" 3 -p icmp --icmp-type echo-request -j ACCEPT - iptables -I "$NYM_CHAIN" 4 -p icmp --icmp-type echo-reply -j ACCEPT - ip6tables -I "$NYM_CHAIN" 3 -p ipv6-icmp -j ACCEPT - - echo -e "${GREEN}✓ DNS and ICMP rules inserted at beginning of $NYM_CHAIN${NC}" - - # Dictionary of services and their ports - declare -A PORT_MAPPINGS=( - ["FTP"]="20-21" - ["SSH"]="22" - ["WHOIS"]="43" - ["DNS"]="53" - ["Finger"]="79" - ["HTTP"]="80-81" - ["Kerberos"]="88" - ["POP3"]="110" - ["NTP"]="123" - ["IMAP"]="143" - ["IMAP3"]="220" - ["LDAP"]="389" - ["HTTPS"]="443" - ["SMBWindowsFileShare"]="445" - ["Kpasswd"]="464" - ["RTSP"]="554" - ["LDAPS"]="636" - ["SILC"]="706" - ["KerberosAdmin"]="749" - ["DNSOverTLS"]="853" - ["Rsync"]="873" - ["VMware"]="902-904" - ["RemoteHTTPS"]="981" - ["FTPOverTLS"]="989-990" - ["NetnewsAdmin"]="991" - ["TelnetOverTLS"]="992" - ["IMAPOverTLS"]="993" - ["POP3OverTLS"]="995" - ["OpenVPN"]="1194" - ["WireGuardPeer"]="51820-51822" - ["QTServerAdmin"]="1220" - ["PKTKRB"]="1293" - ["MSSQL"]="1433" - ["VLSILicenseManager"]="1500" - ["OracleDB"]="1521" - ["Sametime"]="1533" - ["GroupWise"]="1677" - ["PPTP"]="1723" - ["RTSPAlt"]="1755" - ["MSNP"]="1863" - ["NFS"]="2049" - ["CPanel"]="2082-2083" - ["GNUnet"]="2086-2087" - ["NBX"]="2095-2096" - ["Zephyr"]="2102-2104" - ["XboxLive"]="3074" - ["MySQL"]="3306" - ["SVN"]="3690" - ["RWHOIS"]="4321" - ["Virtuozzo"]="4643" - ["RTPVOIP"]="5000-5005" - ["MMCC"]="5050" - ["ICQ"]="5190" - ["XMPP"]="5222-5223" - ["AndroidMarket"]="5228" - ["PostgreSQL"]="5432" - ["MongoDBDefault"]="27017" - ["Electrum"]="8082" - ["SimplifyMedia"]="8087-8088" - ["Zcash"]="8232-8233" - ["Bitcoin"]="8332-8333" - ["HTTPSALT"]="8443" - ["TeamSpeak"]="8767" - ["MQTTS"]="8883" - ["HTTPProxy"]="8888" - ["TorORPort"]="9001" - ["TorDirPort"]="9030" - ["Tari"]="9053" - ["Gaming"]="9339" - ["Git"]="9418" - ["HTTPSALT2"]="9443" - ["Lightning"]="9735" - ["NDMP"]="10000" - ["OpenPGP"]="11371" - ["Monero"]="18080-18081" - ["MoneroRPC"]="18089" - ["GoogleVoice"]="19294" - ["EnsimControlPanel"]="19638" - ["DarkFiTor"]="25551" - ["Minecraft"]="25565" - ["DarkFi"]="26661" - ["Steam"]="27000-27050" - ["ElectrumSSL"]="50002" - ["MOSH"]="60000-61000" - ["Mumble"]="64738" - ["Metadata"]="51830" - ) - - # Add TCP and UDP rules for each allowed port - for service in "${!PORT_MAPPINGS[@]}"; do - port="${PORT_MAPPINGS[$service]}" - echo -e "${YELLOW}Adding rules for $service (Port: $port)${NC}" - - # Add both TCP and UDP rules for all services - add_port_rules iptables "$port" "tcp" - add_port_rules ip6tables "$port" "tcp" - add_port_rules iptables "$port" "udp" - add_port_rules ip6tables "$port" "udp" - done - - echo -e "${GREEN}Port allowlist applied successfully.${NC}" -} - -safe_iptables_rule_remove() { - local chain="$1" - local table="${2:-filter}" - local interface="$3" - - # Remove rule if it exists - if iptables -t "$table" -C "$chain" -o "$interface" -j "$NYM_CHAIN" 2>/dev/null; then - iptables -t "$table" -D "$chain" -o "$interface" -j "$NYM_CHAIN" - fi -} - -safe_ip6tables_rule_remove() { - local chain="$1" - local table="${2:-filter}" - local interface="$3" - - # Remove rule if it exists - if ip6tables -t "$table" -C "$chain" -o "$interface" -j "$NYM_CHAIN" 2>/dev/null; then - ip6tables -t "$table" -D "$chain" -o "$interface" -j "$NYM_CHAIN" - fi -} - -clear_rules() { - echo -e "${YELLOW}Clearing Nym exit policy rules...${NC}" - - # Flush all rules in the NYM-EXIT chain - iptables -F "$NYM_CHAIN" 2>/dev/null || true - ip6tables -F "$NYM_CHAIN" 2>/dev/null || true - - # Remove the chain from FORWARD if it exists - iptables -D FORWARD -o "$WG_INTERFACE" -j "$NYM_CHAIN" 2>/dev/null || true - iptables -D FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null || true - ip6tables -D FORWARD -o "$WG_INTERFACE" -j "$NYM_CHAIN" 2>/dev/null || true - ip6tables -D FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null || true - - # Delete the chains - iptables -X "$NYM_CHAIN" 2>/dev/null || true - ip6tables -X "$NYM_CHAIN" 2>/dev/null || true - - echo -e "${GREEN}Nym exit policy rules cleared successfully.${NC}" -} - -remove_duplicate_rules() { - local interface="$1" - - if [[ -z "$interface" ]]; then - echo -e "${RED}Error: No interface specified. Usage: $0 remove-duplicates ${NC}" >&2 - exit 1 - fi - - echo -e "${YELLOW}Detecting and removing duplicate rules for $interface...${NC}" - - # Verbose duplicate rule detection for IPv4 - echo -e "${YELLOW}Checking IPv4 duplicate rules:${NC}" - iptables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep "$interface" | sort | uniq -d && { - echo -e "${RED}Duplicate IPv4 rules found! Removing...${NC}" - # Remove duplicates by saving unique rules - iptables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep "$interface" | sort | uniq | while read -r rule; do - # Carefully remove duplicates - full_rule=$(echo "$rule" | sed 's/^-A/iptables -D/') - eval "$full_rule" 2>/dev/null - done - } || echo -e "${GREEN}No duplicate IPv4 rules found.${NC}" - - # Verbose duplicate rule detection for IPv6 - echo -e "${YELLOW}Checking IPv6 duplicate rules:${NC}" - ip6tables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep "$interface" | sort | uniq -d && { - echo -e "${RED}Duplicate IPv6 rules found! Removing...${NC}" - # Remove duplicates by saving unique rules - ip6tables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep "$interface" | sort | uniq | while read -r rule; do - # Carefully remove duplicates - full_rule=$(echo "$rule" | sed 's/^-A/ip6tables -D/') - eval "$full_rule" 2>/dev/null - done - } || echo -e "${GREEN}No duplicate IPv6 rules found.${NC}" - - # Additional verification - echo -e "\n${YELLOW}Rule verification:${NC}" - echo "IPv4 Rules:" - iptables -L FORWARD -v -n | grep "$interface" - echo "IPv6 Rules:" - ip6tables -L FORWARD -v -n | grep "$interface" - - echo -e "${GREEN}Duplicate rule removal process completed.${NC}" -} - -save_rules() { - echo -e "${YELLOW}Saving iptables rules to make them persistent...${NC}" - - if [ -d "/etc/iptables" ]; then - # For Debian/Ubuntu with iptables-persistent - iptables-save >/etc/iptables/rules.v4 - ip6tables-save >/etc/iptables/rules.v6 - echo -e "${GREEN}Rules saved to /etc/iptables/rules.v4 and /etc/iptables/rules.v6${NC}" - else - # Fallback method - iptables-save >/etc/iptables.rules - ip6tables-save >/etc/ip6tables.rules - echo -e "${GREEN}Rules saved to /etc/iptables.rules and /etc/ip6tables.rules${NC}" - - # Add loading script to rc.local if it doesn't exist - if [ ! -f "/etc/network/if-pre-up.d/iptables" ]; then - cat >/etc/network/if-pre-up.d/iptables </dev/null; then - echo -e "${RED}WARNING: Wireguard interface $WG_INTERFACE not found!${NC}" - return 1 - fi - - # Interface details - echo -e "\n${YELLOW}Interface Details:${NC}" - ip link show "$WG_INTERFACE" - - # IP Addresses - echo -e "\n${YELLOW}IP Addresses:${NC}" - ip -4 addr show dev "$WG_INTERFACE" - ip -6 addr show dev "$WG_INTERFACE" - - # Iptables Chain Status - echo -e "\n${YELLOW}Iptables Chains:${NC}" - { - echo "IPv4 Chain:" - iptables -L "$NYM_CHAIN" -n -v - echo -e "\nIPv6 Chain:" - ip6tables -L "$NYM_CHAIN" -n -v - } || echo "One or both chains not found" - - # Forwarding Status - echo -e "\n${YELLOW}IP Forwarding:${NC}" - echo "IPv4: $(cat /proc/sys/net/ipv4/ip_forward)" - echo "IPv6: $(cat /proc/sys/net/ipv6/conf/all/forwarding)" -} - -test_connectivity() { - echo -e "${YELLOW}Testing connectivity through $WG_INTERFACE...${NC}" - - # More comprehensive interface check - interface_info=$(ip link show "$WG_INTERFACE" 2>/dev/null) - - if [ -z "$interface_info" ]; then - echo -e "${RED}Interface $WG_INTERFACE not found!${NC}" - return 1 - fi - - # Check for multiple possible interface states - if ! echo "$interface_info" | grep -qE "state (UP|UNKNOWN|DORMANT)"; then - echo -e "${RED}Interface $WG_INTERFACE is not in an active state!${NC}" - echo "$interface_info" - return 1 - fi - - # Detailed interface information - echo -e "${GREEN}Interface Details:${NC}" - echo "$interface_info" - - # Get IP addresses with more robust method - ipv4_address=$(ip -4 addr show dev "$WG_INTERFACE" | grep -oP '(?<=inet\s)\d+\.\d+\.\d+\.\d+/\d+' | cut -d'/' -f1 | head -n1) - ipv6_address=$(ip -6 addr show dev "$WG_INTERFACE" scope global | grep -oP '(?<=inet6\s)[0-9a-f:]+/\d+' | cut -d'/' -f1 | head -n1) - - echo -e "${GREEN}IPv4 Address:${NC} ${ipv4_address:-Not found}" - echo -e "${GREEN}IPv6 Address:${NC} ${ipv6_address:-Not found}" - - # Connectivity tests - if [[ -n "$ipv4_address" ]]; then - echo -e "${YELLOW}Testing IPv4 connectivity from $ipv4_address...${NC}" - - # Ping test - if timeout 5 ping -c 3 -I "$ipv4_address" 8.8.8.8 >/dev/null 2>&1; then - echo -e "${GREEN}IPv4 connectivity to 8.8.8.8: Success${NC}" - else - echo -e "${RED}IPv4 connectivity to 8.8.8.8: Failed${NC}" - fi - - # DNS resolution test - if timeout 5 ping -c 3 -I "$ipv4_address" google.com >/dev/null 2>&1; then - echo -e "${GREEN}IPv4 DNS resolution: Success${NC}" - else - echo -e "${RED}IPv4 DNS resolution: Failed${NC}" - fi - - # HTTP(S) connectivity test - if command -v curl &>/dev/null; then - if timeout 5 curl -s --interface "$ipv4_address" -o /dev/null -w "%{http_code}" https://www.google.com | grep -q "200"; then - echo -e "${GREEN}IPv4 HTTPS connectivity: Success${NC}" - else - echo -e "${RED}IPv4 HTTPS connectivity: Failed${NC}" - fi - fi - else - echo -e "${RED}No IPv4 address configured on $WG_INTERFACE${NC}" - fi - - # Similar tests for IPv6 if available - if [[ -n "$ipv6_address" ]]; then - echo -e "${YELLOW}Testing IPv6 connectivity from $ipv6_address...${NC}" - - if timeout 5 ping6 -c 3 -I "$ipv6_address" 2001:4860:4860::8888 >/dev/null 2>&1; then - echo -e "${GREEN}IPv6 connectivity to Google DNS: Success${NC}" - else - echo -e "${RED}IPv6 connectivity to Google DNS: Failed${NC}" - fi - - if timeout 5 ping6 -c 3 -I "$ipv6_address" google.com >/dev/null 2>&1; then - echo -e "${GREEN}IPv6 DNS resolution: Success${NC}" - else - echo -e "${RED}IPv6 DNS resolution: Failed${NC}" - fi - - if command -v curl &>/dev/null; then - if timeout 5 curl -s --interface "$ipv6_address" -o /dev/null -w "%{http_code}" https://www.google.com | grep -q "200"; then - echo -e "${GREEN}IPv6 HTTPS connectivity: Success${NC}" - else - echo -e "${RED}IPv6 HTTPS connectivity: Failed${NC}" - fi - fi - else - echo -e "${YELLOW}No IPv6 address configured on $WG_INTERFACE${NC}" - fi - - echo -e "${GREEN}Connectivity tests completed.${NC}" -} - -main() { - # Check for root privileges - if [ "$(id -u)" -ne 0 ]; then - echo -e "${RED}This script must be run as root${NC}" >&2 - exit 1 - fi - - # Parse command-line arguments - case "$1" in - install) - install_dependencies - configure_ip_forwarding - create_nym_chain - setup_nat_rules - configure_dns_and_icmp - # Apply allowlist first (so DNS and other allowed ports are not blocked) - apply_port_allowlist - # Then apply blocklist (aka the REJECT rules) - apply_spamhaus_blocklist - add_default_reject_rule - save_rules - echo -e "${GREEN}Nym exit policy installed successfully.${NC}" - ;; - status) - show_status - ;; - test) - test_connectivity - ;; - clear) - clear_rules - echo -e "${GREEN}Nym exit policy rules cleared.${NC}" - ;; - remove-duplicates) - remove_duplicate_rules "$2" - ;; - help | --help | -h) - echo "Usage: $0 [command]" - echo "" - echo "Commands:" - echo " install Install and configure Nym exit policy" - echo " status Show current Nym exit policy status" - echo " test Test connectivity through Wireguard interface" - echo " clear Remove all Nym exit policy rules" - echo " remove-duplicates Remove duplicate iptables rules for an interface" - echo " help Show this help message" - ;; - *) - echo -e "${RED}Invalid command. Use '$0 help' for usage information.${NC}" >&2 - exit 1 - ;; - esac -} - -main "$@" From 0fe863c8895eb40af855bcc63f123a1233a6530b Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 17:27:04 +0000 Subject: [PATCH 056/134] delete to resolve merge conflict --- .../exit-policy-tests.sh | 308 ------------------ 1 file changed, 308 deletions(-) delete mode 100644 scripts/wireguard-exit-policy/exit-policy-tests.sh diff --git a/scripts/wireguard-exit-policy/exit-policy-tests.sh b/scripts/wireguard-exit-policy/exit-policy-tests.sh deleted file mode 100644 index 0734f19318..0000000000 --- a/scripts/wireguard-exit-policy/exit-policy-tests.sh +++ /dev/null @@ -1,308 +0,0 @@ -#!/bin/bash -# Nym Exit Policy Verification Unit Tests - -GREEN='\033[0;32m' -RED='\033[0;31m' -YELLOW='\033[0;33m' -NC='\033[0m' - -NYM_CHAIN="NYM-EXIT" -WG_INTERFACE="nymwg" - -check_port_range_rules() { - local port_range="$1" - local protocol="${2:-tcp}" - local chain="${3:-$NYM_CHAIN}" - - # Extract start and end ports - local start_port=$(echo "$port_range" | cut -d'-' -f1) - local end_port=$(echo "$port_range" | cut -d'-' -f2) - - if iptables -t filter -C "$chain" -p "$protocol" --dport "$start_port:$end_port" -j ACCEPT 2>/dev/null; then - echo -e "${GREEN}✓ Rule exists: $chain $protocol port range $start_port:$end_port${NC}" - return 0 - else - echo -e "${RED}✗ Rule missing: $chain $protocol port range $start_port:$end_port${NC}" - - echo -e "${YELLOW}Dumping all rules in $chain:${NC}" - iptables -L "$chain" -n | grep "$protocol" - - return 1 - fi -} - -# Test port range rules -test_port_range_rules() { - echo -e "${YELLOW}Testing Port Range Rules...${NC}" - - # Select the essential port ranges for testing - local port_ranges=( - "20-21:tcp:FTP" - "80-81:tcp:HTTP" - "2082-2083:tcp:CPanel" - "5222-5223:tcp:XMPP" - "27000-27050:tcp:Steam (sampling)" - "989-990:tcp:FTP over TLS" - "5000-5005:tcp:RTP/VoIP" - "8087-8088:tcp:Simplify Media" - "8232-8233:tcp:Zcash" - "8332-8333:tcp:Bitcoin" - "18080-18081:tcp:Monero" - ) - - local total_failures=0 - - for range in "${port_ranges[@]}"; do - IFS=':' read -r port_range protocol service <<< "$range" - - # Extract start and end ports - local start_port=$(echo "$port_range" | cut -d'-' -f1) - local end_port=$(echo "$port_range" | cut -d'-' -f2) - - echo -e "${YELLOW}Testing $service $protocol port range $port_range${NC}" - - if iptables -t filter -C "$NYM_CHAIN" -p "$protocol" --dport "$start_port:$end_port" -j ACCEPT 2>/dev/null; then - echo -e "${GREEN}✓ Rule exists: $NYM_CHAIN $protocol port range $start_port:$end_port${NC}" - else - echo -e "${RED}✗ Rule missing: $NYM_CHAIN $protocol port range $start_port:$end_port${NC}" - ((total_failures++)) - - echo -e "${YELLOW}Existing rules for protocol $protocol:${NC}" - iptables -L "$NYM_CHAIN" -n | grep "$protocol" - fi - done - - if [ $total_failures -eq 0 ]; then - return 0 - else - return 1 - fi -} - -test_critical_services() { - echo -e "${YELLOW}Testing Critical Service Rules...${NC}" - - local tcp_services=( - 22 # SSH - 53 # DNS - 443 # HTTPS - 853 # DNS over TLS - 1194 # OpenVPN - ) - - local udp_services=( - 53 # DNS - 123 # NTP - 1194 # OpenVPN - ) - - local failures=0 - - # Test TCP services - for port in "${tcp_services[@]}"; do - local rule_found=false - - # First check for exact match - if iptables -t filter -C "$NYM_CHAIN" -p tcp --dport "$port" -j ACCEPT 2>/dev/null; then - echo -e "${GREEN}✓ Rule exists: NYM-EXIT tcp port $port${NC}" - rule_found=true - else - # If not found as exact port, search for it in port ranges - # This checks if the port is covered by any range rule - if iptables-save | grep -E "^-A $NYM_CHAIN.*tcp.*dpts:" | grep -qP "dpts:(\d+:)?$port(:|\d+)" || \ - iptables-save | grep -E "^-A $NYM_CHAIN.*tcp.*dpts:" | grep -qP "dpts:$port:"; then - echo -e "${GREEN}✓ Rule exists: NYM-EXIT tcp port $port (covered by a range rule)${NC}" - rule_found=true - else - echo -e "${RED}✗ Rule missing: NYM-EXIT tcp port $port${NC}" - ((failures++)) - fi - fi - done - - # Test UDP services - similar approach - for port in "${udp_services[@]}"; do - local rule_found=false - - if iptables -t filter -C "$NYM_CHAIN" -p udp --dport "$port" -j ACCEPT 2>/dev/null; then - echo -e "${GREEN}✓ Rule exists: NYM-EXIT udp port $port${NC}" - rule_found=true - else - # If not found as exact port, search for it in port ranges - if iptables-save | grep -E "^-A $NYM_CHAIN.*udp.*dpts:" | grep -qP "dpts:(\d+:)?$port(:|\d+)" || \ - iptables-save | grep -E "^-A $NYM_CHAIN.*udp.*dpts:" | grep -qP "dpts:$port:"; then - echo -e "${GREEN}✓ Rule exists: NYM-EXIT udp port $port (covered by a range rule)${NC}" - rule_found=true - else - echo -e "${RED}✗ Rule missing: NYM-EXIT udp port $port${NC}" - ((failures++)) - fi - fi - done - - echo -e "${YELLOW}Relevant existing rules for HTTP (port 80):${NC}" - iptables-save | grep -E "$NYM_CHAIN.*tcp" | grep -E "(dpt|dpts):.*80" - - return $failures -} - -# Test that the exit policy chain is correctly wired up to FORWARD chain -test_forward_chain_hook() { - echo -e "${YELLOW}Testing FORWARD Chain Hook...${NC}" - - local failures=0 - NETWORK_DEVICE=$(ip route show default | awk '/default/ {print $5}') - - if [[ -z "$NETWORK_DEVICE" ]]; then - echo -e "${RED}✗ Could not determine network device${NC}" - return 1 - fi - - # (incoming from nymwg, outgoing to network device) - if iptables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null; then - echo -e "${GREEN}✓ IPv4 FORWARD hook exists with correct direction: -i $WG_INTERFACE -o $NETWORK_DEVICE${NC}" - else - echo -e "${RED}✗ IPv4 FORWARD hook missing or has wrong direction${NC}" - echo -e "${YELLOW} Expected: -i $WG_INTERFACE -o $NETWORK_DEVICE -j $NYM_CHAIN${NC}" - - # Check if wrong direction exists - if iptables -C FORWARD -o "$WG_INTERFACE" -j "$NYM_CHAIN" 2>/dev/null; then - echo -e "${RED}✗ WRONG DIRECTION FOUND: -o $WG_INTERFACE (this matches return traffic, not client egress!)${NC}" - fi - - # Show what actually exists - specifically look for jump rules to NYM-EXIT - echo -e "${YELLOW} Current FORWARD rules that jump to $NYM_CHAIN:${NC}" - iptables -L FORWARD -n -v --line-numbers | grep -E "$NYM_CHAIN" || echo " (none found - exit policy chain is not hooked to FORWARD!)" - echo -e "${YELLOW} All FORWARD rules with $WG_INTERFACE (for reference):${NC}" - iptables -L FORWARD -n -v --line-numbers | grep -E "$WG_INTERFACE" | head -5 || echo " (none found)" - ((failures++)) - fi - - # Check IPv6 - if ip6tables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null; then - echo -e "${GREEN}✓ IPv6 FORWARD hook exists with correct direction: -i $WG_INTERFACE -o $NETWORK_DEVICE${NC}" - else - echo -e "${RED}✗ IPv6 FORWARD hook missing or has wrong direction${NC}" - echo -e "${YELLOW} Expected: -i $WG_INTERFACE -o $NETWORK_DEVICE -j $NYM_CHAIN${NC}" - - # Check if wrong direction exists - if ip6tables -C FORWARD -o "$WG_INTERFACE" -j "$NYM_CHAIN" 2>/dev/null; then - echo -e "${RED}✗ WRONG DIRECTION FOUND: -o $WG_INTERFACE (this matches return traffic, not client egress!)${NC}" - fi - - # Show what actually exists - specifically look for jump rules to NYM-EXIT - echo -e "${YELLOW} Current IPv6 FORWARD rules that jump to $NYM_CHAIN:${NC}" - ip6tables -L FORWARD -n -v --line-numbers | grep -E "$NYM_CHAIN" || echo " (none found - exit policy chain is not hooked to FORWARD!)" - echo -e "${YELLOW} All IPv6 FORWARD rules with $WG_INTERFACE (for reference):${NC}" - ip6tables -L FORWARD -n -v --line-numbers | grep -E "$WG_INTERFACE" | head -5 || echo " (none found)" - ((failures++)) - fi - - # Check rule position (should be before UFW rules) - local rule_num=$(iptables -L FORWARD -n --line-numbers -v | awk -v chain="$NYM_CHAIN" -v in="$WG_INTERFACE" -v out="$NETWORK_DEVICE" ' - $0 ~ chain && $0 ~ in && $0 ~ out {print $1; exit} - ') - if [[ -n "$rule_num" ]]; then - if [[ $rule_num -le 5 ]]; then - echo -e "${GREEN}✓ Rule is early in FORWARD chain (position #$rule_num) - good for UFW compatibility${NC}" - else - echo -e "${YELLOW}⚠ Rule is later in FORWARD chain (position #$rule_num) - may conflict with UFW${NC}" - fi - fi - - return $failures -} - -# Verify default reject rule exists -test_default_reject_rule() { - echo -e "${YELLOW}This test takes some time, do not quit the process${NC}" - echo - echo -e "${YELLOW}Testing Default Reject Rule...${NC}" - - # Try different patterns to detect the reject rule - if iptables -L "$NYM_CHAIN" | grep -q "REJECT.*all.*anywhere.*anywhere.*reject-with"; then - echo -e "${GREEN}✓ Default REJECT rule exists${NC}" - return 0 - elif iptables -L "$NYM_CHAIN" | grep -q "REJECT.*all -- .*everywhere.*everywhere"; then - echo -e "${GREEN}✓ Default REJECT rule exists${NC}" - return 0 - elif iptables -L "$NYM_CHAIN" | grep -q "REJECT.*all.*0.0.0.0/0.*0.0.0.0/0"; then - echo -e "${GREEN}✓ Default REJECT rule exists${NC}" - return 0 - elif iptables -n -L "$NYM_CHAIN" | grep -qE "REJECT.*all.*0.0.0.0/0.*0.0.0.0/0"; then - echo -e "${GREEN}✓ Default REJECT rule exists${NC}" - return 0 - elif iptables -L "$NYM_CHAIN" | tail -1 | grep -q "REJECT"; then - echo -e "${GREEN}✓ Default REJECT rule exists at the end of chain${NC}" - return 0 - else - echo -e "${RED}✗ Default REJECT rule missing${NC}" - # Display the last 3 rules in the chain for debugging - echo -e "${YELLOW}Last 3 rules in the chain:${NC}" - iptables -L "$NYM_CHAIN" | tail -3 - return 1 - fi -} - -run_all_tests() { - local total_failures=0 - local total_tests=0 - local skip_default_reject=false - - # Parse arguments - while [[ $# -gt 0 ]]; do - case "$1" in - --skip-default-reject) - skip_default_reject=true - shift - ;; - *) - echo -e "${RED}Unknown argument: $1${NC}" - exit 1 - ;; - esac - done - - local test_functions=( - "test_forward_chain_hook" - "test_port_range_rules" - "test_critical_services" - ) - - if [ "$skip_default_reject" = false ]; then - test_functions+=("test_default_reject_rule") - fi - - echo -e "${YELLOW}Running Nym Exit Policy Verification Tests...${NC}" - - for test_func in "${test_functions[@]}"; do - ((total_tests++)) - $test_func - if [ $? -ne 0 ]; then - ((total_failures++)) - echo -e "${RED}Test $test_func FAILED${NC}" - else - echo -e "${GREEN}Test $test_func PASSED${NC}" - fi - done - - echo -e "\n${YELLOW}Test Summary:${NC}" - echo -e "Total Tests: $total_tests" - echo -e "Failures: $total_failures" - - if [ $total_failures -eq 0 ]; then - echo -e "${GREEN}All Tests Passed Successfully!${NC}" - exit 0 - else - echo -e "${RED}Some Tests Failed. Please review the iptables configuration.${NC}" - exit 1 - fi -} - -if [[ $EUID -ne 0 ]]; then - echo -e "${RED}This script must be run as root${NC}" - exit 1 -fi - -# Run the tests -run_all_tests "$@" From 21d52244cb077b5db9e5a7a11038647894aafd5f Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 18:49:53 +0100 Subject: [PATCH 057/134] sync up with new tunnel manager --- scripts/nym-node-setup/nym-node-cli.py | 28 ++++++++++++-------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/scripts/nym-node-setup/nym-node-cli.py b/scripts/nym-node-setup/nym-node-cli.py index 6a3f84540a..2df9657e3f 100755 --- a/scripts/nym-node-setup/nym-node-cli.py +++ b/scripts/nym-node-setup/nym-node-cli.py @@ -32,8 +32,6 @@ class NodeSetupCLI: self.landing_page_html = self.fetch_script("landing-page.html") self.nginx_proxy_wss_sh = self.fetch_script("nginx_proxy_wss_sh") self.tunnel_manager_sh = self.fetch_script("network_tunnel_manager.sh") - self.wg_ip_tables_manager_sh = self.fetch_script("wireguard-exit-policy-manager.sh") - self.wg_ip_tables_test_sh = self.fetch_script("exit-policy-tests.sh") self.quic_bridge_deployment_sh = self.fetch_script("quic_bridge_deployment.sh") else: self.landing_page_html = None @@ -190,9 +188,7 @@ class NodeSetupCLI: "start-node-systemd-service.sh": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/start-node-systemd-service.sh", "nginx_proxy_wss_sh": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/setup-nginx-proxy-wss.sh", "landing-page.html": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/landing-page.html", - "network_tunnel_manager.sh": f"https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/network_tunnel_manager.sh", - "wireguard-exit-policy-manager.sh": f"https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh", - "exit-policy-tests.sh": f"https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/wireguard-exit-policy/exit-policy-tests.sh", + "network_tunnel_manager.sh": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/network-tunnel-manager.sh", "quic_bridge_deployment.sh": f"{github_raw_nymtech_nym_scripts_url}nym-node-setup/quic_bridge_deployment.sh" } @@ -297,9 +293,9 @@ class NodeSetupCLI: ans = input( "\nWireGuard is not configured.\n" "Nodes routing WireGuard can be listed as both entry and exit in the app.\n" - "Enable WireGuard support? (y/n): " + "Enable WireGuard support? (Y/n): " ).strip().lower() - val = "true" if ans in ("y", "yes") else "false" + val = "true" if ans in ("", "y", "yes") else "false" val = norm(val) os.environ["WIREGUARD"] = val @@ -382,13 +378,15 @@ class NodeSetupCLI: "Setting up Wireguard IP tables to match Nym exit policy for mixnet, stored at: https://nymtech.net/.wellknown/network-requester/exit-policy.txt" "\nThis may take a while, follow the steps below and don't kill the process..." ) - self.run_script(self.wg_ip_tables_manager_sh, args=["install"]) - self.run_script(self.wg_ip_tables_manager_sh, args=["status"]) - self.run_script(self.wg_ip_tables_test_sh) + self.run_script(self.tunnel_manager_sh, args=["exit_policy_install"]) def quic_bridge_deploy(self): """Setup QUIC bridge and configuration using external script""" - self.run_script(self.quic_bridge_deployment_sh, args=["full_bridge_setup"]) + print("\n* * * Installing and configuring QUIC bridges * * *") + answer = input("\nDo you want to install, setup and run QUIC bridge? (Y/n) ").strip().lower() + + if answer in ("", "y", "yes"): + self.run_script(self.quic_bridge_deployment_sh, args=["full_bridge_setup"]) def run_nym_node_as_service(self): """Starts /etc/systemd/system/nym-node.service based on prompt using external script""" @@ -416,8 +414,8 @@ class NodeSetupCLI: if is_active: while True: - ans = input(f"{service} is already running. Restart it now? (y/n):\n").strip().lower() - if ans == "y": + ans = input(f"{service} is already running. Restart it now? (Y/n):\n").strip().lower() + if ans in ("", "Y", "y"): self.run_script(self.start_node_systemd_service_sh, args=["restart-poll"], env=run_env) return elif ans == "n": @@ -427,8 +425,8 @@ class NodeSetupCLI: print("Invalid input. Please press 'y' or 'n' and press enter.") else: while True: - ans = input(f"{service} is not running. Start it now? (y/n):\n").strip().lower() - if ans == "y": + ans = input(f"{service} is not running. Start it now? (Y/n):\n").strip().lower() + if ans in ("", "Y", "y"): self.run_script(self.start_node_systemd_service_sh, args=["start-poll"], env=run_env) return elif ans == "n": From fe7470ea44fd7539bae5a4946a4cdc6061326fe0 Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 17:54:17 +0000 Subject: [PATCH 058/134] address comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/quic_bridge_deployment.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/nym-node-setup/quic_bridge_deployment.sh b/scripts/nym-node-setup/quic_bridge_deployment.sh index 1d40958578..4aaa7d72df 100644 --- a/scripts/nym-node-setup/quic_bridge_deployment.sh +++ b/scripts/nym-node-setup/quic_bridge_deployment.sh @@ -32,6 +32,8 @@ log() { # simple redirection that keeps function scope intact add_log_redirection() { + # Preserve original stdout (fd 1) and stderr (fd 2) in file descriptors 3 and 4 + # before redirection, to support potential future use cases where the original streams are needed. exec 3>&1 4>&2 exec > >(tee -a "$LOG_FILE") 2>&1 } From e8ca490db121c1059dff723be62e85b73d55d841 Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 17:54:42 +0000 Subject: [PATCH 059/134] style Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/quic_bridge_deployment.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/nym-node-setup/quic_bridge_deployment.sh b/scripts/nym-node-setup/quic_bridge_deployment.sh index 4aaa7d72df..f0a3de83df 100644 --- a/scripts/nym-node-setup/quic_bridge_deployment.sh +++ b/scripts/nym-node-setup/quic_bridge_deployment.sh @@ -433,7 +433,6 @@ apply_bridge_iptables_rules() { iptables-save > /etc/iptables/rules.v4 ip6tables-save > /etc/iptables/rules.v6 - ok "iptables rules applied." } From 94151965bbebb3559bee101d850beeb242188f89 Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 17:55:09 +0000 Subject: [PATCH 060/134] string to dict fix Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/nym-node-cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nym-node-setup/nym-node-cli.py b/scripts/nym-node-setup/nym-node-cli.py index 2df9657e3f..21eacbac48 100755 --- a/scripts/nym-node-setup/nym-node-cli.py +++ b/scripts/nym-node-setup/nym-node-cli.py @@ -133,7 +133,7 @@ class NodeSetupCLI: mode = getattr(args, "mode", None) if mode: mode = mode.strip().lower() - self._upsert_env_vars("MODE", mode) + self._upsert_env_vars({"MODE": mode}) print(f"Mode set to '{mode}' from CLI argument.") return mode From 6b8a6283a428e0677f4753889e3e166181754d3c Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 20:27:43 +0100 Subject: [PATCH 061/134] fix nginx script --- .../nym-node-setup/setup-nginx-proxy-wss.sh | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/scripts/nym-node-setup/setup-nginx-proxy-wss.sh b/scripts/nym-node-setup/setup-nginx-proxy-wss.sh index eae4d7165e..f3a8aa46c0 100644 --- a/scripts/nym-node-setup/setup-nginx-proxy-wss.sh +++ b/scripts/nym-node-setup/setup-nginx-proxy-wss.sh @@ -64,16 +64,16 @@ cert_ok() { } fetch_landing_html() { - local url="https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/nym-node-setup/landing-page.html" + local url="https://raw.githubusercontent.com/nymtech/nym/develop/scripts/nym-node-setup/landing-page.html" + mkdir -p "${WEBROOT}" - if command -v curl >/dev/null 2>&1; then - curl -fsSL "$url" -o "${WEBROOT}/index.html" || true - else - wget -qO "${WEBROOT}/index.html" "$url" || true - fi + curl -fsSL "$url" -o "${WEBROOT}/index.html" || \ + wget -qO "${WEBROOT}/index.html" "$url" || true + # fallback HTML if [[ ! -s "${WEBROOT}/index.html" ]]; then + echo "landing page not found upstream, using fallback template" cat > "${WEBROOT}/index.html" <<'HTML' @@ -158,23 +158,36 @@ echo "Landing page at ${WEBROOT}/index.html" # disable default and stale SSL configs [[ -L "${SITES_EN}/default" ]] && unlink "${SITES_EN}/default" || true + +# hard-clean: dangling SSL symlink for this hostname +if [[ -L "${SITES_EN}/${HOSTNAME}-ssl" && ! -f "${SITES_AVAIL}/${HOSTNAME}-ssl" ]]; then + echo "Removing stale SSL symlink for ${HOSTNAME}" + unlink "${SITES_EN}/${HOSTNAME}-ssl" +fi + +# remove SSL vhosts referencing localhost certs for f in "${SITES_EN}"/*; do [[ -L "$f" ]] || continue if grep -q "/etc/letsencrypt/live/localhost" "$f"; then - echo "Disabling vhost referencing localhost cert: $f"; unlink "$f" + echo "Disabling vhost with localhost cert: $f" + unlink "$f" fi done + +# remove SSL vhosts with missing certs for f in "${SITES_EN}"/*; do [[ -L "$f" ]] || continue if grep -qE 'listen\s+.*443' "$f"; then cert=$(awk '/ssl_certificate[ \t]+/ {print $2}' "$f" | tr -d ';' | head -n1) - key=$(awk '/ssl_certificate_key[ \t]+/ {print $2}' "$f" | tr -d ';' | head -n1) - if [[ -n "${cert:-}" && ! -s "$cert" ]] || [[ -n "${key:-}" && ! -s "$key" ]]; then - echo "Disabling SSL vhost with missing cert/key: $f"; unlink "$f" + key=$(awk '/ssl_certificate_key[ \t]+/ {print $2}' "$f" | tr -d ';') + if [[ ! -s "$cert" || ! -s "$key" ]]; then + echo "Disabling SSL vhost with missing cert/key: $f" + unlink "$f" fi fi done + # HTTP :80 vhost (ACME-safe, proxy to :8080) neat_backup "${BASE_HTTP}" cat > "${BASE_HTTP}" < Date: Thu, 13 Nov 2025 20:37:35 +0100 Subject: [PATCH 062/134] flush nginx script anew --- .../nym-node-setup/setup-nginx-proxy-wss.sh | 368 +++++------------- 1 file changed, 100 insertions(+), 268 deletions(-) diff --git a/scripts/nym-node-setup/setup-nginx-proxy-wss.sh b/scripts/nym-node-setup/setup-nginx-proxy-wss.sh index f3a8aa46c0..ed3d3e59fb 100644 --- a/scripts/nym-node-setup/setup-nginx-proxy-wss.sh +++ b/scripts/nym-node-setup/setup-nginx-proxy-wss.sh @@ -1,365 +1,197 @@ #!/usr/bin/env bash set -euo pipefail -# load env (prefer absolute ENV_FILE injected by Python CLI; fallback to ./env.sh) +# load env if [[ -n "${ENV_FILE:-}" && -f "${ENV_FILE}" ]]; then set -a; . "${ENV_FILE}"; set +a elif [[ -f "./env.sh" ]]; then set -a; . ./env.sh; set +a fi -: "${HOSTNAME:?HOSTNAME not set in env.sh}" -: "${EMAIL:?EMAIL not set in env.sh}" +: "${HOSTNAME:?HOSTNAME not set}" +: "${EMAIL:?EMAIL not set}" -export SYSTEMD_PAGER="" -export SYSTEMD_COLORS="0" -DEBIAN_FRONTEND=noninteractive - -# sanity check -if [[ "${HOSTNAME}" == "localhost" || "${HOSTNAME}" == "127.0.0.1" || "${HOSTNAME}" == "ubuntu" ]]; then - echo "ERROR: HOSTNAME cannot be 'localhost'. Use a public FQDN." >&2 - exit 1 -fi - -echo -e "\n* * * Starting nginx configuration for landing page, reverse proxy and WSS * * *" - -# set paths & ports vars +export DEBIAN_FRONTEND=noninteractive WEBROOT="/var/www/${HOSTNAME}" -LE_ACME_DIR="/var/www/letsencrypt" SITES_AVAIL="/etc/nginx/sites-available" SITES_EN="/etc/nginx/sites-enabled" -BASE_HTTP="${SITES_AVAIL}/${HOSTNAME}" # :80 vhost -BASE_HTTPS="${SITES_AVAIL}/${HOSTNAME}-ssl" # :443 vhost (we’ll write it ourselves) -WSS_AVAIL="${SITES_AVAIL}/wss-config-nym" -BACKUP_DIR="/etc/nginx/sites-backups" -NYM_PORT_HTTP="${NYM_PORT_HTTP:-8080}" -NYM_PORT_WSS="${NYM_PORT_WSS:-9000}" -WSS_LISTEN_PORT="${WSS_LISTEN_PORT:-9001}" +HTTP_CONF="${SITES_AVAIL}/${HOSTNAME}" +HTTPS_CONF="${SITES_AVAIL}/${HOSTNAME}-ssl" +WSS_CONF="${SITES_AVAIL}/wss-config-nym" -mkdir -p "${WEBROOT}" "${LE_ACME_DIR}" "${BACKUP_DIR}" "${SITES_AVAIL}" "${SITES_EN}" +echo +echo "* * * starting clean nginx configuration for landing page, reverse proxy and wss * * *" -# helpers -neat_backup() { - local file="$1"; [[ -f "$file" ]] || return 0 - local sha_now; sha_now="$(sha256sum "$file" | awk '{print $1}')" || return 0 - local tag; tag="$(basename "$file")" - local latest="${BACKUP_DIR}/${tag}.latest" - if [[ -f "$latest" ]]; then - local sha_prev; sha_prev="$(awk '{print $1}' "$latest")" - [[ "$sha_now" == "$sha_prev" ]] && return 0 - fi - cp -a "$file" "${BACKUP_DIR}/${tag}.bak.$(date +%s)" - echo "$sha_now ${tag}" > "$latest" - ls -1t "${BACKUP_DIR}/${tag}.bak."* 2>/dev/null | tail -n +6 | xargs -r rm -f -} +############################################################################### +# step 1: clean old configs +############################################################################### -ensure_enabled() { - local src="$1"; local name; name="$(basename "$src")" - ln -sf "$src" "${SITES_EN}/${name}" -} +echo "cleaning existing nginx configuration" -cert_ok() { - [[ -s "/etc/letsencrypt/live/${HOSTNAME}/fullchain.pem" && -s "/etc/letsencrypt/live/${HOSTNAME}/privkey.pem" ]] -} +# remove old default symlink +[[ -L ${SITES_EN}/default ]] && unlink ${SITES_EN}/default || true -fetch_landing_html() { - local url="https://raw.githubusercontent.com/nymtech/nym/develop/scripts/nym-node-setup/landing-page.html" +# remove old vhosts for this domain (symlink + config) +rm -f "${SITES_EN}/${HOSTNAME}" || true +rm -f "${SITES_EN}/${HOSTNAME}-ssl" || true +rm -f "${SITES_EN}/wss-config-nym" || true - mkdir -p "${WEBROOT}" +rm -f "${HTTP_CONF}" || true +rm -f "${HTTPS_CONF}" || true +rm -f "${WSS_CONF}" || true - curl -fsSL "$url" -o "${WEBROOT}/index.html" || \ - wget -qO "${WEBROOT}/index.html" "$url" || true +############################################################################### +# step 2: create landing page +############################################################################### - # fallback HTML - if [[ ! -s "${WEBROOT}/index.html" ]]; then - echo "landing page not found upstream, using fallback template" - cat > "${WEBROOT}/index.html" <<'HTML' +mkdir -p "${WEBROOT}" +if ! curl -fsSL \ + https://raw.githubusercontent.com/nymtech/nym/develop/scripts/nym-node-setup/landing-page.html \ + -o "${WEBROOT}/index.html"; then + + cat > "${WEBROOT}/index.html" <<'EOF' - - - - - Nym Exit Gateway - - - -

Nym Exit Gateway

-

This is a Nym Exit Gateway. The operator of this router has no access to any of the data routing through that due to encryption design.

+ +nym node + +

nym exit gateway

+

this is a nym exit gateway.

-HTML - fi -} +EOF -inject_email() { - local file="${WEBROOT}/index.html" - [[ -n "${EMAIL:-}" && -s "$file" ]] || return 0 - - # Escape characters that would break sed replacement - local esc_email - esc_email="$(printf '%s' "$EMAIL" | sed -e 's/[&/\]/\\&/g')" - - # try to update existing meta (case-insensitive on the name attr) - if grep -qiE ']+name=["'"'"']contact:email["'"'"']' "$file"; then - sed -i -E \ - "s|(]+name=[\"']contact:email[\"'][^>]*content=\")[^\"]*(\"[^>]*>)|\1${esc_email}\2|I" \ - "$file" || true - return 0 - fi - - # insert before if present (case-insensitive) - if grep -qi '' "$file"; then - awk -v email="$EMAIL" ' - BEGIN{IGNORECASE=1} - /<\/head>/ && !done { - print " " - done=1 - } - { print } - ' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file" - return 0 - fi - - # fallback: append at end - printf '\n\n' "$EMAIL" >> "$file" || true -} - -fetch_logo() { - local logo_url="https://raw.githubusercontent.com/nymtech/websites/refs/heads/main/www/nym.com/public/images/Nym_meta_Image.png?token=GHSAT0AAAAAACEERII7URYRTFACZ4F2OWZ42GMCPBQ" - mkdir -p "${WEBROOT}/images" - if [[ ! -s "${WEBROOT}/images/nym_logo.png" ]]; then - if command -v curl >/dev/null 2>&1; then - curl -fsSL "$logo_url" -o "${WEBROOT}/images/nym_logo.png" || true - else - wget -qO "${WEBROOT}/images/nym_logo.png" "$logo_url" || true - fi - fi -} - -reload_nginx() { nginx -t && systemctl reload nginx; } - -# landing page (idempotent) -fetch_landing_html -inject_email -fetch_logo -echo "Landing page at ${WEBROOT}/index.html" - -# disable default and stale SSL configs -[[ -L "${SITES_EN}/default" ]] && unlink "${SITES_EN}/default" || true - -# hard-clean: dangling SSL symlink for this hostname -if [[ -L "${SITES_EN}/${HOSTNAME}-ssl" && ! -f "${SITES_AVAIL}/${HOSTNAME}-ssl" ]]; then - echo "Removing stale SSL symlink for ${HOSTNAME}" - unlink "${SITES_EN}/${HOSTNAME}-ssl" fi -# remove SSL vhosts referencing localhost certs -for f in "${SITES_EN}"/*; do - [[ -L "$f" ]] || continue - if grep -q "/etc/letsencrypt/live/localhost" "$f"; then - echo "Disabling vhost with localhost cert: $f" - unlink "$f" - fi -done +echo "landing page at ${WEBROOT}/index.html" -# remove SSL vhosts with missing certs -for f in "${SITES_EN}"/*; do - [[ -L "$f" ]] || continue - if grep -qE 'listen\s+.*443' "$f"; then - cert=$(awk '/ssl_certificate[ \t]+/ {print $2}' "$f" | tr -d ';' | head -n1) - key=$(awk '/ssl_certificate_key[ \t]+/ {print $2}' "$f" | tr -d ';') - if [[ ! -s "$cert" || ! -s "$key" ]]; then - echo "Disabling SSL vhost with missing cert/key: $f" - unlink "$f" - fi - fi -done +############################################################################### +# step 3: create basic http config (80) +############################################################################### - -# HTTP :80 vhost (ACME-safe, proxy to :8080) -neat_backup "${BASE_HTTP}" -cat > "${BASE_HTTP}" < "${HTTP_CONF}" </dev/null; then - echo "WARNING: Can't reach Let's Encrypt directory. We'll still keep HTTP up." >&2 -fi -THIS_IP="$(curl -fsS -4 https://ifconfig.me || true)" -DNS_IP="$(getent ahostsv4 "${HOSTNAME}" 2>/dev/null | awk '{print $1; exit}')" -echo "Public IPv4: ${THIS_IP:-unknown} DNS A(${HOSTNAME}): ${DNS_IP:-unresolved}" -if [[ -n "${THIS_IP:-}" && -n "${DNS_IP:-}" && "${THIS_IP}" != "${DNS_IP}" ]]; then - echo "WARNING: DNS for ${HOSTNAME} does not match this server's public IPv4." -fi -timedatectl show -p NTPSynchronized --value 2>/dev/null | grep -qi yes || timedatectl set-ntp true || true +ln -sf "${HTTP_CONF}" "${SITES_EN}/${HOSTNAME}" -# install certbot if missing -if ! command -v certbot >/dev/null 2>&1; then - if command -v snap >/dev/null 2>&1; then - snap install core || true; snap refresh core || true - snap install --classic certbot; ln -sf /snap/bin/certbot /usr/bin/certbot - else - apt-get update -y >/dev/null 2>&1 || true - apt-get install -y certbot >/dev/null 2>&1 || true - fi -fi +nginx -t +systemctl reload nginx -# issue/renew via WEBROOT (no nginx auto-edit), non-fatal if it fails -STAGING_FLAG=""; [[ "${CERTBOT_STAGING:-0}" == "1" ]] && STAGING_FLAG="--staging" && echo "Using Let's Encrypt STAGING." -if ! cert_ok; then - certbot certonly --non-interactive --agree-tos -m "${EMAIL}" -d "${HOSTNAME}" \ - --webroot -w "${LE_ACME_DIR}" ${STAGING_FLAG} || true -fi +############################################################################### +# step 4: get certificate using certbot --nginx +############################################################################### -# create own 443 vhost (only if certs exist) -if cert_ok; then - neat_backup "${BASE_HTTPS}" - cat > "${BASE_HTTPS}" </dev/null 2>&1 || true +apt-get install -y certbot python3-certbot-nginx >/dev/null 2>&1 || true + +echo "requesting let's encrypt certificate for ${HOSTNAME}" + +certbot --nginx --non-interactive --agree-tos \ + -m "${EMAIL}" -d "${HOSTNAME}" --redirect || true + +############################################################################### +# step 5: if cert OK, build https and wss configs +############################################################################### + +if [[ -s "/etc/letsencrypt/live/${HOSTNAME}/fullchain.pem" ]]; then + echo "certificate detected, creating https and wss configs" + + cat > "${HTTPS_CONF}" <HTTPS (keeps ACME path in HTTP too via separate small server) - neat_backup "${BASE_HTTP}" - cat > "${BASE_HTTP}" < "${WSS_CONF}" < "${WSS_AVAIL}" < Date: Thu, 13 Nov 2025 20:46:33 +0100 Subject: [PATCH 063/134] replace y to Y and '' --- scripts/nym-node-setup/nym-node-install.sh | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/scripts/nym-node-setup/nym-node-install.sh b/scripts/nym-node-setup/nym-node-install.sh index 3ea25687f5..3a88577ad9 100644 --- a/scripts/nym-node-setup/nym-node-install.sh +++ b/scripts/nym-node-setup/nym-node-install.sh @@ -34,8 +34,9 @@ check_existing_config() { if [[ "${resp}" =~ ^([Rr][Ee][Ss][Ee][Tt])$ ]]; then echo - read -r -p "We are going to remove the existing node with configuration $NODE_CONFIG_DIR and replace it with a fresh one, do you want to back up the old one first? (y/n) " backup_ans - if [[ "${backup_ans}" =~ ^[Yy]$ ]]; then + echo "We are going to remove the existing node with configuration $NODE_CONFIG_DIR and replace it with a fresh one." + read -r -p "back up the old one first? (Y/n) " backup_ans + if [[ -z "${backup_ans}" || "${backup_ans}" =~ ^[Yy]$ ]]; then ts="$(date +%Y%m%d-%H%M%S)" backup_dir="$HOME/.nym/backup/$(basename "$NODE_CONFIG_DIR")-$ts" echo "Backing up to: $backup_dir" @@ -185,14 +186,14 @@ NYM_NODE="$HOME/nym-binaries/nym-node" if [[ -e "${NYM_NODE}" ]]; then echo echo -e "\n* * * A nym-node binary already exists at: ${NYM_NODE}" - read -r -p "Overwrite with the latest release? (y/n): " ow_ans - if [[ "${ow_ans}" =~ ^[Yy]$ ]]; then - echo "Removing existing binary to avoid 'text file busy'..." + read -r -p "Overwrite with the latest release? (Y/n): " ow_ans + if [[ -z "${ow_ans}" || "${ow_ans}" =~ ^[Yy]$ ]]; then + echo "Removing existing binary..." rm -f "${NYM_NODE}" + download_nym_node "$LATEST_TAG_URL" "$NYM_NODE" else - echo "Keeping existing binary." + echo "Keeping existing binary. Skipping download." fi -fi download_nym_node "$LATEST_TAG_URL" "$NYM_NODE" @@ -229,13 +230,12 @@ if [[ ( "$MODE" == "entry-gateway" || "$MODE" == "exit-gateway" ) && ( -n "${ASK # show current default in the prompt if present def_hint="" [[ -n "${WIREGUARD}" ]] && def_hint=" [current: ${WIREGUARD}]" - read -r -p "Enable WireGuard support? (y/n)${def_hint}: " answer || true - case "${answer:-}" in - [Yy]* ) WIREGUARD="true" ;; - [Nn]* ) WIREGUARD="false" ;; - * ) : ;; # keep existing value if user just pressed enter - esac -fi + read -r -p "Enable WireGuard support? (Y/n)${def_hint}: " answer || true + if [[ -z "${answer}" || "${answer}" =~ ^[Yy]$ ]]; then + WIREGUARD="true" + elif [[ "${answer}" =~ ^[Nn]$ ]]; then + WIREGUARD="false" + fi # final default only if still empty WIREGUARD="${WIREGUARD:-false}" From 58c0e289c25d67ba72a868629e7624a38b680087 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 13 Nov 2025 20:56:04 +0100 Subject: [PATCH 064/134] syntax fix --- scripts/nym-node-setup/nym-node-install.sh | 15 ++-- .../nym-node-setup/setup-nginx-proxy-wss.sh | 70 +++++++++++-------- 2 files changed, 49 insertions(+), 36 deletions(-) diff --git a/scripts/nym-node-setup/nym-node-install.sh b/scripts/nym-node-setup/nym-node-install.sh index 3a88577ad9..af36c92017 100644 --- a/scripts/nym-node-setup/nym-node-install.sh +++ b/scripts/nym-node-setup/nym-node-install.sh @@ -182,11 +182,12 @@ fi NYM_NODE="$HOME/nym-binaries/nym-node" -# if binary already exists, ask to overwrite; if yes, remove first +# if binary already exists, ask to overwrite; if yes, remove first; if no, skip download if [[ -e "${NYM_NODE}" ]]; then echo echo -e "\n* * * A nym-node binary already exists at: ${NYM_NODE}" read -r -p "Overwrite with the latest release? (Y/n): " ow_ans + if [[ -z "${ow_ans}" || "${ow_ans}" =~ ^[Yy]$ ]]; then echo "Removing existing binary..." rm -f "${NYM_NODE}" @@ -195,11 +196,13 @@ if [[ -e "${NYM_NODE}" ]]; then echo "Keeping existing binary. Skipping download." fi -download_nym_node "$LATEST_TAG_URL" "$NYM_NODE" +else + # binary does not exist → must download + download_nym_node "$LATEST_TAG_URL" "$NYM_NODE" +fi echo -e "\n * * * Making binary executable * * *" chmod +x "${NYM_NODE}" - echo "---------------------------------------------------" echo "Nym node binary downloaded:" "${NYM_NODE}" --version || true @@ -226,16 +229,18 @@ WIREGUARD="${WIREGUARD:-}" if [[ ( "$MODE" == "entry-gateway" || "$MODE" == "exit-gateway" ) && ( -n "${ASK_WG:-}" || -z "$WIREGUARD" ) ]]; then echo echo "Gateways can also route WireGuard in NymVPN." - echo "Enabling it means your node may be listed as both entry and exit in the app." - # show current default in the prompt if present def_hint="" [[ -n "${WIREGUARD}" ]] && def_hint=" [current: ${WIREGUARD}]" + read -r -p "Enable WireGuard support? (Y/n)${def_hint}: " answer || true + if [[ -z "${answer}" || "${answer}" =~ ^[Yy]$ ]]; then WIREGUARD="true" elif [[ "${answer}" =~ ^[Nn]$ ]]; then WIREGUARD="false" fi +fi + # final default only if still empty WIREGUARD="${WIREGUARD:-false}" diff --git a/scripts/nym-node-setup/setup-nginx-proxy-wss.sh b/scripts/nym-node-setup/setup-nginx-proxy-wss.sh index ed3d3e59fb..312ea8bf11 100644 --- a/scripts/nym-node-setup/setup-nginx-proxy-wss.sh +++ b/scripts/nym-node-setup/setup-nginx-proxy-wss.sh @@ -12,6 +12,7 @@ fi : "${EMAIL:?EMAIL not set}" export DEBIAN_FRONTEND=noninteractive + WEBROOT="/var/www/${HOSTNAME}" SITES_AVAIL="/etc/nginx/sites-available" SITES_EN="/etc/nginx/sites-enabled" @@ -23,29 +24,31 @@ WSS_CONF="${SITES_AVAIL}/wss-config-nym" echo echo "* * * starting clean nginx configuration for landing page, reverse proxy and wss * * *" -############################################################################### -# step 1: clean old configs -############################################################################### +################################################################################ +# step 1: clean all previous configs +################################################################################ echo "cleaning existing nginx configuration" -# remove old default symlink -[[ -L ${SITES_EN}/default ]] && unlink ${SITES_EN}/default || true +# remove default nginx config +[[ -L "${SITES_EN}/default" ]] && unlink "${SITES_EN}/default" || true -# remove old vhosts for this domain (symlink + config) -rm -f "${SITES_EN}/${HOSTNAME}" || true -rm -f "${SITES_EN}/${HOSTNAME}-ssl" || true -rm -f "${SITES_EN}/wss-config-nym" || true +# remove domain symlinks +rm -f "${SITES_EN}/${HOSTNAME}" || true +rm -f "${SITES_EN}/${HOSTNAME}-ssl" || true +rm -f "${SITES_EN}/wss-config-nym" || true -rm -f "${HTTP_CONF}" || true -rm -f "${HTTPS_CONF}" || true -rm -f "${WSS_CONF}" || true +# remove old configs +rm -f "${HTTP_CONF}" || true +rm -f "${HTTPS_CONF}" || true +rm -f "${WSS_CONF}" || true -############################################################################### -# step 2: create landing page -############################################################################### +################################################################################ +# step 2: landing page +################################################################################ mkdir -p "${WEBROOT}" + if ! curl -fsSL \ https://raw.githubusercontent.com/nymtech/nym/develop/scripts/nym-node-setup/landing-page.html \ -o "${WEBROOT}/index.html"; then @@ -65,9 +68,9 @@ fi echo "landing page at ${WEBROOT}/index.html" -############################################################################### -# step 3: create basic http config (80) -############################################################################### +################################################################################ +# step 3: HTTP :80 config +################################################################################ cat > "${HTTP_CONF}" </dev/null 2>&1 || true apt-get install -y certbot python3-certbot-nginx >/dev/null 2>&1 || true @@ -108,15 +113,17 @@ apt-get install -y certbot python3-certbot-nginx >/dev/null 2>&1 || true echo "requesting let's encrypt certificate for ${HOSTNAME}" certbot --nginx --non-interactive --agree-tos \ + --reuse-key \ -m "${EMAIL}" -d "${HOSTNAME}" --redirect || true -############################################################################### -# step 5: if cert OK, build https and wss configs -############################################################################### +################################################################################ +# step 5: HTTPS and WSS configs +################################################################################ if [[ -s "/etc/letsencrypt/live/${HOSTNAME}/fullchain.pem" ]]; then echo "certificate detected, creating https and wss configs" + # HTTPS 443 cat > "${HTTPS_CONF}" < "${WSS_CONF}" < Date: Fri, 14 Nov 2025 10:31:26 +0000 Subject: [PATCH 065/134] remove redundant detect interface Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../nym-node-setup/network-tunnel-manager.sh | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 66e412d629..400a75971f 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -37,21 +37,25 @@ fi TUNNEL_INTERFACE="${TUNNEL_INTERFACE:-nymtun0}" WG_INTERFACE="${WG_INTERFACE:-nymwg}" +# Function to detect and validate uplink interface +detect_uplink_interface() { + local cmd="$1" + local dev + dev="$(eval "$cmd" 2>/dev/null | awk '{print \$5}' | head -n1 || true)" + if [[ -n "$dev" && "$dev" =~ ^[a-zA-Z0-9._-]+$ ]]; then + echo "$dev" + else + echo "" + fi +} + # uplink device detection, can be overridden NETWORK_DEVICE="${NETWORK_DEVICE:-}" if [[ -z "$NETWORK_DEVICE" ]]; then - NETWORK_DEVICE="$(ip -o route show default 2>/dev/null | awk '{print $5}' | head -n1 || true)" - # Validate that NETWORK_DEVICE is non-empty and looks like a network interface - if [[ -z "$NETWORK_DEVICE" || ! "$NETWORK_DEVICE" =~ ^[a-zA-Z0-9._-]+$ ]]; then - NETWORK_DEVICE="" - fi + NETWORK_DEVICE="$(detect_uplink_interface "ip -o route show default")" fi if [[ -z "$NETWORK_DEVICE" ]]; then - NETWORK_DEVICE="$(ip -o route show default table all 2>/dev/null | awk '{print $5}' | head -n1 || true)" - # Validate that NETWORK_DEVICE is non-empty and looks like a network interface - if [[ -z "$NETWORK_DEVICE" || ! "$NETWORK_DEVICE" =~ ^[a-zA-Z0-9._-]+$ ]]; then - NETWORK_DEVICE="" - fi + NETWORK_DEVICE="$(detect_uplink_interface "ip -o route show default table all")" fi if [[ -z "$NETWORK_DEVICE" ]]; then echo "cannot determine uplink interface. set NETWORK_DEVICE or UPLINK_DEV" From f62dbbdae0b81b8e920501164fd61e34c6230a6d Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Fri, 14 Nov 2025 10:33:23 +0000 Subject: [PATCH 066/134] ensure idempotency for the iptable rules Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../nym-node-setup/network-tunnel-manager.sh | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 400a75971f..668b6c55f1 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -521,14 +521,28 @@ setup_nat_rules() { configure_exit_dns_and_icmp() { echo "ensuring dns and icmp are allowed inside nym exit chain" - iptables -I "$NYM_CHAIN" 1 -p udp --dport 53 -j ACCEPT - iptables -I "$NYM_CHAIN" 2 -p tcp --dport 53 -j ACCEPT - ip6tables -I "$NYM_CHAIN" 1 -p udp --dport 53 -j ACCEPT - ip6tables -I "$NYM_CHAIN" 2 -p tcp --dport 53 -j ACCEPT + if ! iptables -C "$NYM_CHAIN" -p udp --dport 53 -j ACCEPT 2>/dev/null; then + iptables -A "$NYM_CHAIN" -p udp --dport 53 -j ACCEPT + fi + if ! iptables -C "$NYM_CHAIN" -p tcp --dport 53 -j ACCEPT 2>/dev/null; then + iptables -A "$NYM_CHAIN" -p tcp --dport 53 -j ACCEPT + fi + if ! ip6tables -C "$NYM_CHAIN" -p udp --dport 53 -j ACCEPT 2>/dev/null; then + ip6tables -A "$NYM_CHAIN" -p udp --dport 53 -j ACCEPT + fi + if ! ip6tables -C "$NYM_CHAIN" -p tcp --dport 53 -j ACCEPT 2>/dev/null; then + ip6tables -A "$NYM_CHAIN" -p tcp --dport 53 -j ACCEPT + fi - iptables -I "$NYM_CHAIN" 3 -p icmp --icmp-type echo-request -j ACCEPT - iptables -I "$NYM_CHAIN" 4 -p icmp --icmp-type echo-reply -j ACCEPT - ip6tables -I "$NYM_CHAIN" 3 -p ipv6-icmp -j ACCEPT + if ! iptables -C "$NYM_CHAIN" -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null; then + iptables -A "$NYM_CHAIN" -p icmp --icmp-type echo-request -j ACCEPT + fi + if ! iptables -C "$NYM_CHAIN" -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null; then + iptables -A "$NYM_CHAIN" -p icmp --icmp-type echo-reply -j ACCEPT + fi + if ! ip6tables -C "$NYM_CHAIN" -p ipv6-icmp -j ACCEPT 2>/dev/null; then + ip6tables -A "$NYM_CHAIN" -p ipv6-icmp -j ACCEPT + fi } apply_port_allowlist() { From 3f560180b7713428979732fb705151340131aaed Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Fri, 14 Nov 2025 10:35:42 +0000 Subject: [PATCH 067/134] remove redundant Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/quic_bridge_deployment.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/scripts/nym-node-setup/quic_bridge_deployment.sh b/scripts/nym-node-setup/quic_bridge_deployment.sh index f0a3de83df..d6fb15cb2e 100644 --- a/scripts/nym-node-setup/quic_bridge_deployment.sh +++ b/scripts/nym-node-setup/quic_bridge_deployment.sh @@ -32,9 +32,6 @@ log() { # simple redirection that keeps function scope intact add_log_redirection() { - # Preserve original stdout (fd 1) and stderr (fd 2) in file descriptors 3 and 4 - # before redirection, to support potential future use cases where the original streams are needed. - exec 3>&1 4>&2 exec > >(tee -a "$LOG_FILE") 2>&1 } add_log_redirection From 054715a600d503e823dd76324e0ecbde8b19b439 Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Fri, 14 Nov 2025 10:36:23 +0000 Subject: [PATCH 068/134] robust error handling Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/nym-node-cli.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/nym-node-setup/nym-node-cli.py b/scripts/nym-node-setup/nym-node-cli.py index 21eacbac48..b6e4bd55a1 100755 --- a/scripts/nym-node-setup/nym-node-cli.py +++ b/scripts/nym-node-setup/nym-node-cli.py @@ -96,8 +96,12 @@ class NodeSetupCLI: if ip.returncode == 0 and ip.stdout.strip(): updated["PUBLIC_IP"] = ip.stdout.strip() os.environ["PUBLIC_IP"] = ip.stdout.strip() - except Exception: - pass + except subprocess.TimeoutExpired: + print("[WARN] Timeout expired while trying to fetch public IP with curl.") + except FileNotFoundError: + print("[WARN] 'curl' command not found. Please install curl or set PUBLIC_IP manually.") + except subprocess.CalledProcessError as e: + print(f"[WARN] Error while running curl to fetch public IP: {e}") # write all collected variables to env.sh in one go self._upsert_env_vars(updated, env_file) From d820131d2cc539d9eb14bcad966154a7c9b2ecf0 Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Fri, 14 Nov 2025 10:36:45 +0000 Subject: [PATCH 069/134] arg consistency Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/nym-node-setup/nym-node-cli.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/nym-node-setup/nym-node-cli.py b/scripts/nym-node-setup/nym-node-cli.py index b6e4bd55a1..0e9130c1bc 100755 --- a/scripts/nym-node-setup/nym-node-cli.py +++ b/scripts/nym-node-setup/nym-node-cli.py @@ -585,6 +585,7 @@ class NodeSetupCLI: # Pass uplink override to all helper scripts if provided if getattr(args, "uplink_dev", None): os.environ["UPLINK_DEV"] = args.uplink_dev + os.environ["NETWORK_DEVICE"] = args.uplink_dev self.run_script(self.prereqs_install_sh) self.run_script(self.node_install_sh) self.run_script(self.service_config_sh) From 228ef8b158b7772106062ce30d6a6c87bbb36b29 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Fri, 14 Nov 2025 12:40:14 +0100 Subject: [PATCH 070/134] add else --- scripts/nym-node-setup/nym-node-cli.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/nym-node-setup/nym-node-cli.py b/scripts/nym-node-setup/nym-node-cli.py index 0e9130c1bc..179ab0e767 100755 --- a/scripts/nym-node-setup/nym-node-cli.py +++ b/scripts/nym-node-setup/nym-node-cli.py @@ -391,6 +391,8 @@ class NodeSetupCLI: if answer in ("", "y", "yes"): self.run_script(self.quic_bridge_deployment_sh, args=["full_bridge_setup"]) + else: + print("Skipping QUIC bridge setup.") def run_nym_node_as_service(self): """Starts /etc/systemd/system/nym-node.service based on prompt using external script""" From 9bdd2af14c24bd05ae152718cbb2b01f4fa02570 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Fri, 14 Nov 2025 12:42:05 +0100 Subject: [PATCH 071/134] enforce root --- scripts/nym-node-setup/nym-node-prereqs-install.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/scripts/nym-node-setup/nym-node-prereqs-install.sh b/scripts/nym-node-setup/nym-node-prereqs-install.sh index 58b04ecc65..f359aceb67 100644 --- a/scripts/nym-node-setup/nym-node-prereqs-install.sh +++ b/scripts/nym-node-setup/nym-node-prereqs-install.sh @@ -1,6 +1,11 @@ #!/bin/bash -# update, upgrade & install dependencies +if [[ "$(id -u)" -ne 0 ]]; then + echo "This script must be run as root." + exit 1 +fi + +# update, upgrade and install dependencies echo -e "\n* * * Installing needed prerequisities * * *" apt update -y && apt --fix-broken install @@ -8,11 +13,9 @@ apt upgrade apt install apt ca-certificates jq curl wget ufw jq tmux pkg-config build-essential libssl-dev git ntp ntpdate neovim tree tmux tig nginx -y apt install ufw --fix-missing - - # enable & setup firewall echo -e "\n* * * Setting up firewall using ufw * * * " -echo "Please enable the firewall in the next prompt for node proper routing!" +echo "Please enable the firewall in the next prompt for node proper routing." echo ufw enable ufw allow 22/tcp # SSH - you're in control of these ports From 10707fd2c5be2c354e2340c436c6014c022b7a0a Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Fri, 14 Nov 2025 12:43:54 +0100 Subject: [PATCH 072/134] convention Y/n --- scripts/nym-node-setup/setup-systemd-service-file.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/nym-node-setup/setup-systemd-service-file.sh b/scripts/nym-node-setup/setup-systemd-service-file.sh index 4f8d586492..fca48f7a2f 100644 --- a/scripts/nym-node-setup/setup-systemd-service-file.sh +++ b/scripts/nym-node-setup/setup-systemd-service-file.sh @@ -83,8 +83,8 @@ fi # interactive path (manual runs) ensure_mode -read -rp "Service file not found. Create it now? (y/n): " create_ans -if [[ "${create_ans:-}" =~ ^[Yy]$ ]]; then +read -rp "Service file not found. Create it now? (Y/n): " create_ans +if [[ -z "${create_ans}" || "${create_ans}" =~ ^[Yy]$ ]]; then create_service_file else echo "Not creating the service file." From e0ff09f323c1fdb8b9873872cb11a932eae171fa Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Fri, 14 Nov 2025 12:44:57 +0100 Subject: [PATCH 073/134] enforce root --- scripts/nym-node-setup/setup-nginx-proxy-wss.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/nym-node-setup/setup-nginx-proxy-wss.sh b/scripts/nym-node-setup/setup-nginx-proxy-wss.sh index 312ea8bf11..7acb56f120 100644 --- a/scripts/nym-node-setup/setup-nginx-proxy-wss.sh +++ b/scripts/nym-node-setup/setup-nginx-proxy-wss.sh @@ -1,6 +1,11 @@ #!/usr/bin/env bash set -euo pipefail +if [[ "$(id -u)" -ne 0 ]]; then + echo "This script must be run as root." + exit 1 +fi + # load env if [[ -n "${ENV_FILE:-}" && -f "${ENV_FILE}" ]]; then set -a; . "${ENV_FILE}"; set +a From ae47d53f0ce2d9dd7f766884eeb9f2ac8ce9c1d2 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Fri, 14 Nov 2025 12:49:10 +0100 Subject: [PATCH 074/134] enforce root --- scripts/nym-node-setup/setup-nginx-proxy-wss.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nym-node-setup/setup-nginx-proxy-wss.sh b/scripts/nym-node-setup/setup-nginx-proxy-wss.sh index 7acb56f120..aa74b9a775 100644 --- a/scripts/nym-node-setup/setup-nginx-proxy-wss.sh +++ b/scripts/nym-node-setup/setup-nginx-proxy-wss.sh @@ -27,7 +27,7 @@ HTTPS_CONF="${SITES_AVAIL}/${HOSTNAME}-ssl" WSS_CONF="${SITES_AVAIL}/wss-config-nym" echo -echo "* * * starting clean nginx configuration for landing page, reverse proxy and wss * * *" +echo "* * * Starting clean nginx configuration for landing page, reverse proxy and wss * * *" ################################################################################ # step 1: clean all previous configs From cc04a09ed7463d9362aea30a15a11c0a253b5806 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Fri, 14 Nov 2025 12:58:03 +0100 Subject: [PATCH 075/134] remove redundant work --- .../nym-node-setup/quic_bridge_deployment.sh | 87 ++++++++++++------- 1 file changed, 54 insertions(+), 33 deletions(-) diff --git a/scripts/nym-node-setup/quic_bridge_deployment.sh b/scripts/nym-node-setup/quic_bridge_deployment.sh index d6fb15cb2e..2d6b151feb 100644 --- a/scripts/nym-node-setup/quic_bridge_deployment.sh +++ b/scripts/nym-node-setup/quic_bridge_deployment.sh @@ -56,7 +56,7 @@ if [[ -z "$NET_DEV" ]]; then echo -e "${RED}Cannot determine uplink interface. Set UPLINK_DEV.${RESET}" | tee -a "$LOG_FILE" exit 1 fi -info "Using uplink device: $NET_DEV" +echo "Using uplink device: $NET_DEV" WG_IFACE="nymwg" @@ -191,13 +191,31 @@ verify_bridge_prerequisites() { } adjust_ip_forwarding() { - title "Adjusting IP Forwarding" - sed -i '/^net\.ipv4\.ip_forward=/d' /etc/sysctl.conf - sed -i '/^net\.ipv6\.conf\.all\.forwarding=/d' /etc/sysctl.conf - echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf - echo "net.ipv6.conf.all.forwarding=1" >> /etc/sysctl.conf - sysctl -p /etc/sysctl.conf - ok "IPv4/IPv6 forwarding enabled." + title "Checking IP forwarding" + local v4 v6 + v4="$(cat /proc/sys/net/ipv4/ip_forward 2>/dev/null || echo 0)" + v6="$(cat /proc/sys/net/ipv6/conf/all/forwarding 2>/dev/null || echo 0)" + + if [[ "$v4" == "1" ]]; then + ok "IPv4 forwarding is enabled." + else + warn "IPv4 forwarding is not enabled." + fi + + if [[ "$v6" == "1" ]]; then + ok "IPv6 forwarding is enabled." + else + warn "IPv6 forwarding is not enabled." + fi + + if [[ "$v4" != "1" || "$v6" != "1" ]]; then + echo + echo "To enable forwarding and routing consistently, run the network tunnel manager script as root." + echo "For example:" + echo " ./network-tunnel-manager.sh complete_networking_configuration" + echo "or:" + echo " ./network-tunnel-manager.sh adjust_ip_forwarding" + fi } # Install nym-bridge @@ -410,37 +428,40 @@ EOF # IPTABLES & helpers apply_bridge_iptables_rules() { - title "Applying iptables rules" + title "Checking iptables rules for bridge routing" - # Ensure stateful rules exist - iptables -C FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || \ - iptables -I FORWARD 1 -m state --state RELATED,ESTABLISHED -j ACCEPT - ip6tables -C FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || \ - ip6tables -I FORWARD 1 -m state --state RELATED,ESTABLISHED -j ACCEPT + echo "Inspecting current iptables state for interface ${WG_IFACE} and uplink ${NET_DEV}." + echo - # Allow WG interface input - iptables -C INPUT -i "$WG_IFACE" -j ACCEPT 2>/dev/null || iptables -I INPUT -i "$WG_IFACE" -j ACCEPT - ip6tables -C INPUT -i "$WG_IFACE" -j ACCEPT 2>/dev/null || ip6tables -I INPUT -i "$WG_IFACE" -j ACCEPT + echo "IPv4 FORWARD:" + iptables -L FORWARD -n -v 2>/dev/null | sed -n '1,20p' || echo "iptables not available." + echo + echo "IPv4 NAT POSTROUTING:" + iptables -t nat -L POSTROUTING -n -v 2>/dev/null | sed -n '1,20p' || true + echo + echo "IPv6 FORWARD:" + ip6tables -L FORWARD -n -v 2>/dev/null | sed -n '1,20p' || true + echo + echo "IPv6 NAT POSTROUTING:" + ip6tables -t nat -L POSTROUTING -n -v 2>/dev/null | sed -n '1,20p' || true - # NAT (idempotent) - iptables -t nat -C POSTROUTING -o "$NET_DEV" -j MASQUERADE 2>/dev/null || \ - iptables -t nat -I POSTROUTING 1 -o "$NET_DEV" -j MASQUERADE - ip6tables -t nat -C POSTROUTING -o "$NET_DEV" -j MASQUERADE 2>/dev/null || \ - ip6tables -t nat -I POSTROUTING 1 -o "$NET_DEV" -j MASQUERADE - - iptables-save > /etc/iptables/rules.v4 - ip6tables-save > /etc/iptables/rules.v6 - ok "iptables rules applied." + echo + echo "This script no longer changes iptables. To configure routing and NAT for nym, use the network tunnel manager script." + echo "For example (run as root):" + echo " ./network-tunnel-manager.sh complete_networking_configuration" } configure_dns_and_icmp() { - title "Allow ICMP and DNS" - iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT || true - ip6tables -A INPUT -p ipv6-icmp -j ACCEPT || true - iptables -C INPUT -p udp --dport 53 -j ACCEPT 2>/dev/null || iptables -I INPUT -p udp --dport 53 -j ACCEPT - ip6tables -C INPUT -p udp --dport 53 -j ACCEPT 2>/dev/null || ip6tables -I INPUT -p udp --dport 53 -j ACCEPT + title "Checking ICMP and DNS firewall rules" - ok "ICMP and DNS rules applied." + echo "IPv4 INPUT rules related to ICMP and DNS:" + iptables -L INPUT -n -v 2>/dev/null | grep -E 'icmp|dpt:53' || echo "no matching IPv4 rules shown." + echo + echo "IPv6 INPUT rules related to ICMP and DNS:" + ip6tables -L INPUT -n -v 2>/dev/null | grep -E 'icmp|dpt:53' || echo "no matching IPv6 rules shown." + + echo + echo "If ping or DNS are blocked for bridge traffic, adjust your firewall using the network tunnel manager script or your chosen firewall tool." } # Full interactive setup @@ -485,7 +506,7 @@ full_bridge_setup() { press_enter "Press Enter to continue..." echo "" - echo "Step 6/6: Configuring network rules (optional but recommended)..." + echo "Step 6/6: Checking network rules and forwarding status..." adjust_ip_forwarding apply_bridge_iptables_rules configure_dns_and_icmp From cc95358385ba60fe7137b0b954cd03228b1fbc5a Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Fri, 14 Nov 2025 13:08:05 +0100 Subject: [PATCH 076/134] add email to a fallback --- scripts/nym-node-setup/setup-nginx-proxy-wss.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/nym-node-setup/setup-nginx-proxy-wss.sh b/scripts/nym-node-setup/setup-nginx-proxy-wss.sh index aa74b9a775..4b0fae6bda 100644 --- a/scripts/nym-node-setup/setup-nginx-proxy-wss.sh +++ b/scripts/nym-node-setup/setup-nginx-proxy-wss.sh @@ -65,6 +65,7 @@ if ! curl -fsSL \

nym exit gateway

this is a nym exit gateway.

+

Operator contact: ${EMAIL}

EOF From ce261059860ff560e7958092624374e0026f354c Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Fri, 14 Nov 2025 13:24:05 +0100 Subject: [PATCH 077/134] typo --- .../docs/pages/operators/nodes/nym-node/configuration.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/pages/operators/nodes/nym-node/configuration.mdx b/documentation/docs/pages/operators/nodes/nym-node/configuration.mdx index 69afc1e41d..dbe24c5072 100644 --- a/documentation/docs/pages/operators/nodes/nym-node/configuration.mdx +++ b/documentation/docs/pages/operators/nodes/nym-node/configuration.mdx @@ -375,7 +375,7 @@ operation check_nymtun_iptables completed successfully. ###### 5. Remove old and apply new rules for wireguad routing ```sh -/network_tunnel_manager.sh remove_duplicate_rules nymwg +./network_tunnel_manager.sh remove_duplicate_rules nymwg ./network_tunnel_manager.sh apply_iptables_rules_wg ``` From 842ce93a60a075ee246783d02b965820e3876a54 Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Fri, 14 Nov 2025 13:24:20 +0100 Subject: [PATCH 078/134] remove duplicate ufw rule --- scripts/nym-node-setup/nym-node-prereqs-install.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/nym-node-setup/nym-node-prereqs-install.sh b/scripts/nym-node-setup/nym-node-prereqs-install.sh index f359aceb67..e462ecb5c9 100644 --- a/scripts/nym-node-setup/nym-node-prereqs-install.sh +++ b/scripts/nym-node-setup/nym-node-prereqs-install.sh @@ -28,6 +28,5 @@ ufw allow 9000/tcp # Nym Specific - clients port ufw allow 9001/tcp # Nym specific - wss port ufw allow 51822/udp # WireGuard ufw allow in on nymwg to any port 51830 proto tcp # bandwidth queries/topup - inside the tunnel -ufw allow 'Nginx Full' && \ ufw reload && \ ufw status From e09066858c2dcd1c9e8b980f6906942802b80d8f Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Fri, 14 Nov 2025 14:21:50 +0100 Subject: [PATCH 079/134] bump up version --- scripts/nym-node-setup/nym-node-cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nym-node-setup/nym-node-cli.py b/scripts/nym-node-setup/nym-node-cli.py index 179ab0e767..def82b1d17 100755 --- a/scripts/nym-node-setup/nym-node-cli.py +++ b/scripts/nym-node-setup/nym-node-cli.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -__version__ = "1.1.0" +__version__ = "1.2.0" __default_branch__ = "develop" import os From ab6e08dd13175fda82fdd1b2c49b2ff2ffa24282 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Fri, 14 Nov 2025 14:27:38 +0100 Subject: [PATCH 080/134] fix logic of landing-page lookup --- .../nym-node-setup/setup-nginx-proxy-wss.sh | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/scripts/nym-node-setup/setup-nginx-proxy-wss.sh b/scripts/nym-node-setup/setup-nginx-proxy-wss.sh index 4b0fae6bda..b72cf6ed24 100644 --- a/scripts/nym-node-setup/setup-nginx-proxy-wss.sh +++ b/scripts/nym-node-setup/setup-nginx-proxy-wss.sh @@ -48,17 +48,25 @@ rm -f "${HTTP_CONF}" || true rm -f "${HTTPS_CONF}" || true rm -f "${WSS_CONF}" || true -################################################################################ -# step 2: landing page -################################################################################ +############################################################################### +# step 2: create landing page +############################################################################### mkdir -p "${WEBROOT}" -if ! curl -fsSL \ - https://raw.githubusercontent.com/nymtech/nym/develop/scripts/nym-node-setup/landing-page.html \ - -o "${WEBROOT}/index.html"; then +# script directory where Python CLI stores fetched scripts +SCRIPT_DIR="$(dirname "${ENV_FILE:-./env.sh}")" +LOCAL_FETCHED_PAGE="${SCRIPT_DIR}/landing-page.html" - cat > "${WEBROOT}/index.html" <<'EOF' +if [[ -s "${LOCAL_FETCHED_PAGE}" ]]; then + cp "${LOCAL_FETCHED_PAGE}" "${WEBROOT}/index.html" +else + if curl -fsSL \ + https://raw.githubusercontent.com/nymtech/nym/develop/scripts/nym-node-setup/landing-page.html \ + -o "${WEBROOT}/index.html"; then + : + else + cat > "${WEBROOT}/index.html" < nym node @@ -69,11 +77,13 @@ if ! curl -fsSL \ EOF - + fi fi echo "landing page at ${WEBROOT}/index.html" +echo "landing page at ${WEBROOT}/index.html" + ################################################################################ # step 3: HTTP :80 config ################################################################################ From 6acc54d2bcff46fc3f8f070f17a5ab373d2cd51a Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Fri, 14 Nov 2025 15:03:36 +0100 Subject: [PATCH 081/134] syntax fix --- scripts/nym-node-setup/network-tunnel-manager.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 668b6c55f1..acd0186366 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -41,7 +41,9 @@ WG_INTERFACE="${WG_INTERFACE:-nymwg}" detect_uplink_interface() { local cmd="$1" local dev - dev="$(eval "$cmd" 2>/dev/null | awk '{print \$5}' | head -n1 || true)" + + dev="$(eval "$cmd" 2>/dev/null | awk '{print $5}' | head -n1 || true)" + if [[ -n "$dev" && "$dev" =~ ^[a-zA-Z0-9._-]+$ ]]; then echo "$dev" else @@ -49,6 +51,7 @@ detect_uplink_interface() { fi } + # uplink device detection, can be overridden NETWORK_DEVICE="${NETWORK_DEVICE:-}" if [[ -z "$NETWORK_DEVICE" ]]; then From e5aef76256a9fd42957392977a9719464726190d Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Fri, 14 Nov 2025 15:27:44 +0100 Subject: [PATCH 082/134] non-interactive --- scripts/nym-node-setup/quic_bridge_deployment.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/nym-node-setup/quic_bridge_deployment.sh b/scripts/nym-node-setup/quic_bridge_deployment.sh index 2d6b151feb..db14127016 100644 --- a/scripts/nym-node-setup/quic_bridge_deployment.sh +++ b/scripts/nym-node-setup/quic_bridge_deployment.sh @@ -75,9 +75,15 @@ err() { echo -e "${RED}$1${RESET}"; } info() { echo -e "${CYAN}$1${RESET}"; } press_enter() { read -r -p "$1"; } -# Disable pauses for noninteractive mode +# Disable pauses and interactive prompts for noninteractive mode if [[ "${NONINTERACTIVE:-0}" == "1" ]]; then + # all pauses become no-ops press_enter() { :; } + + # silence any "enter path:" prompts + echo_prompt() { :; } +else + echo_prompt() { echo -n "$1"; } fi # Helper: detect dpkg dependency failure for libc6>=2.34 From 4f991061dde3a87078b3da6868369f583ed59193 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Fri, 14 Nov 2025 16:22:58 +0100 Subject: [PATCH 083/134] fix nginx errors --- .../nym-node-setup/setup-nginx-proxy-wss.sh | 164 +++++++----------- 1 file changed, 65 insertions(+), 99 deletions(-) diff --git a/scripts/nym-node-setup/setup-nginx-proxy-wss.sh b/scripts/nym-node-setup/setup-nginx-proxy-wss.sh index b72cf6ed24..cf1378f5b6 100644 --- a/scripts/nym-node-setup/setup-nginx-proxy-wss.sh +++ b/scripts/nym-node-setup/setup-nginx-proxy-wss.sh @@ -23,50 +23,28 @@ SITES_AVAIL="/etc/nginx/sites-available" SITES_EN="/etc/nginx/sites-enabled" HTTP_CONF="${SITES_AVAIL}/${HOSTNAME}" -HTTPS_CONF="${SITES_AVAIL}/${HOSTNAME}-ssl" WSS_CONF="${SITES_AVAIL}/wss-config-nym" echo -echo "* * * Starting clean nginx configuration for landing page, reverse proxy and wss * * *" - -################################################################################ -# step 1: clean all previous configs -################################################################################ - -echo "cleaning existing nginx configuration" - -# remove default nginx config -[[ -L "${SITES_EN}/default" ]] && unlink "${SITES_EN}/default" || true - -# remove domain symlinks -rm -f "${SITES_EN}/${HOSTNAME}" || true -rm -f "${SITES_EN}/${HOSTNAME}-ssl" || true -rm -f "${SITES_EN}/wss-config-nym" || true - -# remove old configs -rm -f "${HTTP_CONF}" || true -rm -f "${HTTPS_CONF}" || true -rm -f "${WSS_CONF}" || true +echo "* * * Starting nginx configuration for landing page, reverse proxy and WSS * * *" ############################################################################### -# step 2: create landing page +# step 1: ensure landing page exists (local fetch -> github -> template) ############################################################################### mkdir -p "${WEBROOT}" -# script directory where Python CLI stores fetched scripts SCRIPT_DIR="$(dirname "${ENV_FILE:-./env.sh}")" LOCAL_FETCHED_PAGE="${SCRIPT_DIR}/landing-page.html" if [[ -s "${LOCAL_FETCHED_PAGE}" ]]; then cp "${LOCAL_FETCHED_PAGE}" "${WEBROOT}/index.html" +elif curl -fsSL \ + https://raw.githubusercontent.com/nymtech/nym/develop/scripts/nym-node-setup/landing-page.html \ + -o "${WEBROOT}/index.html"; then + : else - if curl -fsSL \ - https://raw.githubusercontent.com/nymtech/nym/develop/scripts/nym-node-setup/landing-page.html \ - -o "${WEBROOT}/index.html"; then - : - else - cat > "${WEBROOT}/index.html" < "${WEBROOT}/index.html" < nym node @@ -77,16 +55,35 @@ else EOF - fi fi -echo "landing page at ${WEBROOT}/index.html" +echo "Landing page at ${WEBROOT}/index.html" -echo "landing page at ${WEBROOT}/index.html" +############################################################################### +# step 2: remove default site and old configs, restart nginx +############################################################################### -################################################################################ -# step 3: HTTP :80 config -################################################################################ +echo "Cleaning existing nginx configuration" + +# remove default nginx site +[[ -L "${SITES_EN}/default" ]] && unlink "${SITES_EN}/default" || true + +# optional: remove default available config if present +rm -f /etc/nginx/sites-available/default || true + +# remove old vhosts for this domain +rm -f "${SITES_EN}/${HOSTNAME}" || true +rm -f "${SITES_EN}/${HOSTNAME}-ssl" || true +rm -f "${SITES_EN}/wss-config-nym" || true + +rm -f "${HTTP_CONF}" || true +rm -f "${WSS_CONF}" || true + +systemctl restart nginx || systemctl start nginx + +############################################################################### +# step 3: create basic HTTP config like manual flow (80 -> 8080) +############################################################################### cat > "${HTTP_CONF}" </dev/null 2>&1 || true apt-get install -y certbot python3-certbot-nginx >/dev/null 2>&1 || true -echo "requesting let's encrypt certificate for ${HOSTNAME}" +echo "Requesting Let's Encrypt certificate for ${HOSTNAME}" -certbot --nginx --non-interactive --agree-tos \ - --reuse-key \ - -m "${EMAIL}" -d "${HOSTNAME}" --redirect || true +certbot --nginx --non-interactive --agree-tos --redirect --reuse-key \ + -m "${EMAIL}" -d "${HOSTNAME}" || true -################################################################################ -# step 5: HTTPS and WSS configs -################################################################################ +############################################################################### +# step 5: create WSS 9001 config using certbot-generated certs +############################################################################### if [[ -s "/etc/letsencrypt/live/${HOSTNAME}/fullchain.pem" ]]; then - echo "certificate detected, creating https and wss configs" + echo "Certificate detected, creating WSS config" - # HTTPS 443 - cat > "${HTTPS_CONF}" < "${WSS_CONF}" < Date: Mon, 17 Nov 2025 17:05:34 +0100 Subject: [PATCH 084/134] fix --- .../nym-node-setup/network-tunnel-manager.sh | 53 +++++++++---------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index acd0186366..71e31e5c9f 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -296,20 +296,20 @@ apply_iptables_rules() { iptables -t nat -A POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE iptables -C FORWARD -i "$interface" -o "$NETWORK_DEVICE" -j ACCEPT 2>/dev/null || \ - iptables -A FORWARD -i "$interface" -o "$NETWORK_DEVICE" -j ACCEPT + iptables -I FORWARD 1 -i "$interface" -o "$NETWORK_DEVICE" -j ACCEPT iptables -C FORWARD -i "$NETWORK_DEVICE" -o "$interface" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || \ - iptables -A FORWARD -i "$NETWORK_DEVICE" -o "$interface" -m state --state RELATED,ESTABLISHED -j ACCEPT + iptables -I FORWARD 2 -i "$NETWORK_DEVICE" -o "$interface" -m state --state RELATED,ESTABLISHED -j ACCEPT # ipv6 nat and forwarding ip6tables -t nat -C POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE 2>/dev/null || \ ip6tables -t nat -A POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE ip6tables -C FORWARD -i "$interface" -o "$NETWORK_DEVICE" -j ACCEPT 2>/dev/null || \ - ip6tables -A FORWARD -i "$interface" -o "$NETWORK_DEVICE" -j ACCEPT + ip6tables -I FORWARD 1 -i "$interface" -o "$NETWORK_DEVICE" -j ACCEPT ip6tables -C FORWARD -i "$NETWORK_DEVICE" -o "$interface" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || \ - ip6tables -A FORWARD -i "$NETWORK_DEVICE" -o "$interface" -m state --state RELATED,ESTABLISHED -j ACCEPT + ip6tables -I FORWARD 2 -i "$NETWORK_DEVICE" -o "$interface" -m state --state RELATED,ESTABLISHED -j ACCEPT save_iptables_rules } @@ -507,45 +507,40 @@ setup_nat_rules() { fi if ! iptables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT 2>/dev/null; then - iptables -A FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT + iptables -I FORWARD 1 -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT fi if ! iptables -C FORWARD -i "$NETWORK_DEVICE" -o "$WG_INTERFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null; then - iptables -A FORWARD -i "$NETWORK_DEVICE" -o "$WG_INTERFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT + iptables -I FORWARD 2 -i "$NETWORK_DEVICE" -o "$WG_INTERFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT fi if ! ip6tables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT 2>/dev/null; then - ip6tables -A FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT + ip6tables -I FORWARD 1 -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT fi if ! ip6tables -C FORWARD -i "$NETWORK_DEVICE" -o "$WG_INTERFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null; then - ip6tables -A FORWARD -i "$NETWORK_DEVICE" -o "$WG_INTERFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT + ip6tables -I FORWARD 2 -i "$NETWORK_DEVICE" -o "$WG_INTERFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT fi } configure_exit_dns_and_icmp() { echo "ensuring dns and icmp are allowed inside nym exit chain" - if ! iptables -C "$NYM_CHAIN" -p udp --dport 53 -j ACCEPT 2>/dev/null; then - iptables -A "$NYM_CHAIN" -p udp --dport 53 -j ACCEPT - fi - if ! iptables -C "$NYM_CHAIN" -p tcp --dport 53 -j ACCEPT 2>/dev/null; then - iptables -A "$NYM_CHAIN" -p tcp --dport 53 -j ACCEPT - fi - if ! ip6tables -C "$NYM_CHAIN" -p udp --dport 53 -j ACCEPT 2>/dev/null; then - ip6tables -A "$NYM_CHAIN" -p udp --dport 53 -j ACCEPT - fi - if ! ip6tables -C "$NYM_CHAIN" -p tcp --dport 53 -j ACCEPT 2>/dev/null; then - ip6tables -A "$NYM_CHAIN" -p tcp --dport 53 -j ACCEPT - fi + # Remove any existing DNS/ICMP rules first to avoid duplicates + iptables -D "$NYM_CHAIN" -p udp --dport 53 -j ACCEPT 2>/dev/null || true + iptables -D "$NYM_CHAIN" -p tcp --dport 53 -j ACCEPT 2>/dev/null || true + iptables -D "$NYM_CHAIN" -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null || true + iptables -D "$NYM_CHAIN" -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null || true + ip6tables -D "$NYM_CHAIN" -p udp --dport 53 -j ACCEPT 2>/dev/null || true + ip6tables -D "$NYM_CHAIN" -p tcp --dport 53 -j ACCEPT 2>/dev/null || true + ip6tables -D "$NYM_CHAIN" -p ipv6-icmp -j ACCEPT 2>/dev/null || true - if ! iptables -C "$NYM_CHAIN" -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null; then - iptables -A "$NYM_CHAIN" -p icmp --icmp-type echo-request -j ACCEPT - fi - if ! iptables -C "$NYM_CHAIN" -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null; then - iptables -A "$NYM_CHAIN" -p icmp --icmp-type echo-reply -j ACCEPT - fi - if ! ip6tables -C "$NYM_CHAIN" -p ipv6-icmp -j ACCEPT 2>/dev/null; then - ip6tables -A "$NYM_CHAIN" -p ipv6-icmp -j ACCEPT - fi + # Insert rules at the beginning in correct order: DNS first, then ICMP + iptables -I "$NYM_CHAIN" 1 -p udp --dport 53 -j ACCEPT + iptables -I "$NYM_CHAIN" 2 -p tcp --dport 53 -j ACCEPT + iptables -I "$NYM_CHAIN" 3 -p icmp --icmp-type echo-request -j ACCEPT + iptables -I "$NYM_CHAIN" 4 -p icmp --icmp-type echo-reply -j ACCEPT + ip6tables -I "$NYM_CHAIN" 1 -p udp --dport 53 -j ACCEPT + ip6tables -I "$NYM_CHAIN" 2 -p tcp --dport 53 -j ACCEPT + ip6tables -I "$NYM_CHAIN" 3 -p ipv6-icmp -j ACCEPT } apply_port_allowlist() { From 82a9563ca0cbe7c7441abf8699f44750f9b14322 Mon Sep 17 00:00:00 2001 From: benedettadavico Date: Tue, 18 Nov 2025 13:12:35 +0100 Subject: [PATCH 085/134] add a checker script --- .../nym-node-setup/check-firewall-setup.sh | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 scripts/nym-node-setup/check-firewall-setup.sh diff --git a/scripts/nym-node-setup/check-firewall-setup.sh b/scripts/nym-node-setup/check-firewall-setup.sh new file mode 100644 index 0000000000..713750b65e --- /dev/null +++ b/scripts/nym-node-setup/check-firewall-setup.sh @@ -0,0 +1,99 @@ +#!/bin/bash +# helper script to verify firewall ordering +set -euo pipefail + +bold() { printf '\033[1m%s\033[0m\n' "$*"; } +warn() { printf '\033[31m⚠ %s\033[0m\n' "$*"; } +ok() { printf '\033[32m✓ %s\033[0m\n' "$*"; } + +RULE_OFFSET=2 # this is because thefirst rule appears on line 3 + +get_rule_line() { + local chain=$1 + local rule_idx=$2 + iptables -L "$chain" -n --line-numbers | sed -n "$((rule_idx + RULE_OFFSET))p" +} + +check_forward_chain() { + local output + output=$(iptables -L FORWARD -n --line-numbers) + + if echo "$output" | grep -q "^1[[:space:]]\+NYM-EXIT"; then + ok "FORWARD rule 1 jumps to NYM-EXIT" + else + warn "FORWARD rule 1 is not NYM-EXIT; re-run network-tunnel-manager.sh exit_policy_install" + return 1 + fi + + if echo "$output" | grep -q "ACCEPT.*state RELATED,ESTABLISHED"; then + ok "FORWARD chain contains RELATED,ESTABLISHED accepts (WG return path)" + else + warn "FORWARD chain missing RELATED,ESTABLISHED accepts; re-run network-tunnel-manager.sh apply_iptables_rules_wg" + return 1 + fi + + return 0 +} + +check_nym_exit_chain() { + local errors=0 + local patterns=( + "udp.*dpt:53" + "tcp.*dpt:53" + "icmp.*type 8" + "icmp.*type 0" + ) + + for idx in "${!patterns[@]}"; do + local rule_no=$((idx + 1)) + local line + line=$(get_rule_line "NYM-EXIT" "$rule_no") + if [[ "$line" =~ ${patterns[$idx]} ]]; then + ok "NYM-EXIT rule $rule_no matches ${patterns[$idx]}" + else + warn "NYM-EXIT rule $rule_no is not ${patterns[$idx]}; re-run network-tunnel-manager.sh exit_policy_install" + errors=1 + fi + done + + local last_rule + last_rule=$(iptables -L NYM-EXIT -n --line-numbers | awk 'NR>2 {line=$0} END {print line}') + if [[ -z "${last_rule:-}" ]]; then + warn "NYM-EXIT chain is empty; re-run network-tunnel-manager.sh exit_policy_install" + errors=1 + elif [[ "$last_rule" =~ REJECT ]] && [[ "$last_rule" =~ 0\.0\.0\.0/0 ]]; then + ok "NYM-EXIT ends with REJECT all" + else + warn "NYM-EXIT final rule is not a REJECT all (got: $last_rule)" + errors=1 + fi + + return $errors +} + +main() { + bold "Checking IPv4 firewall ordering…" + local errors=0 + check_forward_chain || errors=1 + check_nym_exit_chain || errors=1 + + if command -v ip6tables >/dev/null 2>&1; then + bold "Checking IPv6 firewall ordering…" + if ip6tables -L NYM-EXIT -n --line-numbers >/dev/null 2>&1; then + if ! ip6tables -L NYM-EXIT -n --line-numbers | sed -n '3p' | grep -q "udp.*dpt:53"; then + warn "ip6tables NYM-EXIT rule 1 is not UDP 53" + errors=1 + fi + fi + fi + + if [[ $errors -ne 0 ]]; then + warn "There may be some problems, it's recommended to re-run network-tunnel-manager.sh exit_policy_install after configuring UFW." + exit 1 + else + ok "It's looking good!" + fi +} + +main "$@" + From b742ace7e0f7278f538598fa667841f0dcd3f464 Mon Sep 17 00:00:00 2001 From: benedettadavico Date: Tue, 18 Nov 2025 14:24:19 +0100 Subject: [PATCH 086/134] add firewall check to the main script --- .../nym-node-setup/check-firewall-setup.sh | 99 ------------------- .../nym-node-setup/network-tunnel-manager.sh | 97 +++++++++++++++++- 2 files changed, 95 insertions(+), 101 deletions(-) delete mode 100644 scripts/nym-node-setup/check-firewall-setup.sh diff --git a/scripts/nym-node-setup/check-firewall-setup.sh b/scripts/nym-node-setup/check-firewall-setup.sh deleted file mode 100644 index 713750b65e..0000000000 --- a/scripts/nym-node-setup/check-firewall-setup.sh +++ /dev/null @@ -1,99 +0,0 @@ -#!/bin/bash -# helper script to verify firewall ordering -set -euo pipefail - -bold() { printf '\033[1m%s\033[0m\n' "$*"; } -warn() { printf '\033[31m⚠ %s\033[0m\n' "$*"; } -ok() { printf '\033[32m✓ %s\033[0m\n' "$*"; } - -RULE_OFFSET=2 # this is because thefirst rule appears on line 3 - -get_rule_line() { - local chain=$1 - local rule_idx=$2 - iptables -L "$chain" -n --line-numbers | sed -n "$((rule_idx + RULE_OFFSET))p" -} - -check_forward_chain() { - local output - output=$(iptables -L FORWARD -n --line-numbers) - - if echo "$output" | grep -q "^1[[:space:]]\+NYM-EXIT"; then - ok "FORWARD rule 1 jumps to NYM-EXIT" - else - warn "FORWARD rule 1 is not NYM-EXIT; re-run network-tunnel-manager.sh exit_policy_install" - return 1 - fi - - if echo "$output" | grep -q "ACCEPT.*state RELATED,ESTABLISHED"; then - ok "FORWARD chain contains RELATED,ESTABLISHED accepts (WG return path)" - else - warn "FORWARD chain missing RELATED,ESTABLISHED accepts; re-run network-tunnel-manager.sh apply_iptables_rules_wg" - return 1 - fi - - return 0 -} - -check_nym_exit_chain() { - local errors=0 - local patterns=( - "udp.*dpt:53" - "tcp.*dpt:53" - "icmp.*type 8" - "icmp.*type 0" - ) - - for idx in "${!patterns[@]}"; do - local rule_no=$((idx + 1)) - local line - line=$(get_rule_line "NYM-EXIT" "$rule_no") - if [[ "$line" =~ ${patterns[$idx]} ]]; then - ok "NYM-EXIT rule $rule_no matches ${patterns[$idx]}" - else - warn "NYM-EXIT rule $rule_no is not ${patterns[$idx]}; re-run network-tunnel-manager.sh exit_policy_install" - errors=1 - fi - done - - local last_rule - last_rule=$(iptables -L NYM-EXIT -n --line-numbers | awk 'NR>2 {line=$0} END {print line}') - if [[ -z "${last_rule:-}" ]]; then - warn "NYM-EXIT chain is empty; re-run network-tunnel-manager.sh exit_policy_install" - errors=1 - elif [[ "$last_rule" =~ REJECT ]] && [[ "$last_rule" =~ 0\.0\.0\.0/0 ]]; then - ok "NYM-EXIT ends with REJECT all" - else - warn "NYM-EXIT final rule is not a REJECT all (got: $last_rule)" - errors=1 - fi - - return $errors -} - -main() { - bold "Checking IPv4 firewall ordering…" - local errors=0 - check_forward_chain || errors=1 - check_nym_exit_chain || errors=1 - - if command -v ip6tables >/dev/null 2>&1; then - bold "Checking IPv6 firewall ordering…" - if ip6tables -L NYM-EXIT -n --line-numbers >/dev/null 2>&1; then - if ! ip6tables -L NYM-EXIT -n --line-numbers | sed -n '3p' | grep -q "udp.*dpt:53"; then - warn "ip6tables NYM-EXIT rule 1 is not UDP 53" - errors=1 - fi - fi - fi - - if [[ $errors -ne 0 ]]; then - warn "There may be some problems, it's recommended to re-run network-tunnel-manager.sh exit_policy_install after configuring UFW." - exit 1 - else - ok "It's looking good!" - fi -} - -main "$@" - diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 71e31e5c9f..883c068f4b 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -800,8 +800,95 @@ test_exit_policy_connectivity() { echo "connectivity tests finished" } + ############################################################################### -# part 3: exit policy verification tests +# part 3: check the firewall setup +############################################################################### + +firewall_rule_line() { + local chain=$1 + local rule_idx=$2 + # this is because thefirst rule appears on line 3 + iptables -L "$chain" -n --line-numbers | sed -n "$((rule_idx + 2))p" +} + +check_forward_chain() { + local output + output=$(iptables -L FORWARD -n --line-numbers) + + if ! echo "$output" | grep -q "^1[[:space:]]\+$NYM_CHAIN"; then + echo "FORWARD rule 1 is not ${NYM_CHAIN}; re-run network-tunnel-manager.sh exit_policy_install" + return 1 + fi + + if ! echo "$output" | grep -q "ACCEPT.*state RELATED,ESTABLISHED"; then + echo "FORWARD chain missing RELATED,ESTABLISHED accepts; re-run network-tunnel-manager.sh apply_iptables_rules_wg" + return 1 + fi + + echo "FORWARD chain ordering looks good" + return 0 +} + +check_nym_exit_chain() { + local errors=0 + local patterns=("udp.*dpt:53" "tcp.*dpt:53" "icmp.*type 8" "icmp.*type 0") + + for idx in "${!patterns[@]}"; do + local line + line=$(firewall_rule_line "$NYM_CHAIN" $((idx + 1))) + if [[ "$line" =~ ${patterns[$idx]} ]]; then + echo "${NYM_CHAIN} rule $((idx + 1)) ok (${patterns[$idx]})" + else + echo "${NYM_CHAIN} rule $((idx + 1)) is not ${patterns[$idx]}; re-run network-tunnel-manager.sh exit_policy_install" + errors=1 + fi + done + + local last_rule + last_rule=$(iptables -L "$NYM_CHAIN" -n --line-numbers | awk 'NR>2 {line=$0} END {print line}') + if [[ -z "${last_rule:-}" ]]; then + echo "${NYM_CHAIN} chain is empty; re-run network-tunnel-manager.sh exit_policy_install" + errors=1 + elif [[ "$last_rule" =~ REJECT ]] && [[ "$last_rule" =~ 0\.0\.0\.0/0 ]]; then + echo "${NYM_CHAIN} ends with the catch-all REJECT" + else + echo "${NYM_CHAIN} final rule is not the catch-all REJECT (got: $last_rule)" + errors=1 + fi + + return $errors +} + +check_firewall_setup() { + echo "checking ipv4 firewall ordering…" + local errors=0 + + check_forward_chain || errors=1 + check_nym_exit_chain || errors=1 + + if command -v ip6tables >/dev/null 2>&1; then + echo "checking ipv6 firewall ordering…" + if ip6tables -L "$NYM_CHAIN" -n --line-numbers >/dev/null 2>&1; then + if ! ip6tables -L "$NYM_CHAIN" -n --line-numbers | sed -n '3p' | grep -q "udp.*dpt:53"; then + echo "ip6tables ${NYM_CHAIN} rule 1 is not UDP 53" + errors=1 + fi + fi + fi + + if [[ $errors -ne 0 ]]; then + echo "There may be some ordering issues, it is recommended to re-run network-tunnel-manager.sh exit_policy_install after configuring UFW." + return 1 + fi + + echo "It's looking good!" + return 0 +} + + +############################################################################### +# part 4: full exit policy verification tests ############################################################################### test_port_range_rules() { @@ -945,7 +1032,7 @@ exit_policy_run_tests() { } ############################################################################### -# part 4: high level workflows +# part 5: high level workflows ############################################################################### full_tunnel_setup() { @@ -992,6 +1079,7 @@ complete_networking_configuration() { full_tunnel_setup exit_policy_install + check_firewall_setup || echo "firewall order checks reported problems, please review output" exit_policy_run_tests || echo "exit policy tests reported problems, please review output" echo "complete networking configuration finished" @@ -1080,6 +1168,10 @@ case "$cmd" in show_exit_policy_status status=$? ;; + check_firewall_setup) + check_firewall_setup + status=$? + ;; exit_policy_test_connectivity) test_exit_policy_connectivity status=$? @@ -1121,6 +1213,7 @@ tunnel and nat helpers: exit policy manager: exit_policy_install install exit policy (iptables rules and blocklist) + check_firewall_setup run ordering sanity check (dns/icmp + FORWARD jump) exit_policy_status show status of exit policy and forwarding exit_policy_test_connectivity test connectivity via ${WG_INTERFACE} exit_policy_clear remove ${NYM_CHAIN} chains and hooks From bdc0f5022d0cbf8553be30a55c76c4eadafc3efa Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Tue, 18 Nov 2025 16:38:01 +0100 Subject: [PATCH 087/134] / move ensure_jq where needed --- .../nym-node-setup/network-tunnel-manager.sh | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index acd0186366..7017adbd4d 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -12,24 +12,6 @@ if [ "$(id -u)" -ne 0 ]; then exit 1 fi -echo "checking for jq..." - -if command -v jq >/dev/null 2>&1; then - echo "jq is already installed" - # continue script execution -else - echo "jq not found, installing..." - apt-get update -y - DEBIAN_FRONTEND=noninteractive apt-get install -y jq - - if command -v jq >/dev/null 2>&1; then - echo "jq installed successfully" - else - echo "failed to install jq" - exit 1 - fi -fi - ############################################################################### # basic config ############################################################################### @@ -51,7 +33,6 @@ detect_uplink_interface() { fi } - # uplink device detection, can be overridden NETWORK_DEVICE="${NETWORK_DEVICE:-}" if [[ -z "$NETWORK_DEVICE" ]]; then @@ -79,6 +60,25 @@ NC='\033[0m' # shared helpers ############################################################################### +ensure_jq() { + echo "checking for jq..." + + if command -v jq >/dev/null 2>&1; then + echo "jq is already installed" + else + echo "jq not found, installing..." + apt-get update -y + DEBIAN_FRONTEND=noninteractive apt-get install -y jq + + if command -v jq >/dev/null 2>&1; then + echo "jq installed successfully" + else + echo "failed to install jq" + exit 1 + fi + fi +} + install_iptables_persistent() { if ! dpkg -s iptables-persistent >/dev/null 2>&1; then echo -e "${YELLOW}installing iptables-persistent${NC}" @@ -283,9 +283,6 @@ remove_duplicate_rules() { echo "duplicate rule scan completed for $interface" } - - - apply_iptables_rules() { local interface=$1 echo "applying iptables rules for $interface using uplink $NETWORK_DEVICE" @@ -349,6 +346,7 @@ perform_pings() { } joke_through_tunnel() { + ensure_jq local interface=$1 local green="\033[0;32m" local reset="\033[0m" @@ -905,6 +903,7 @@ test_forward_chain_hook() { test_default_reject_rule() { echo "testing default reject rule at end of ${NYM_CHAIN}" + # not sure this will really check that it is on end if iptables -L "$NYM_CHAIN" | grep -q "REJECT"; then echo "default reject present in ipv4 chain" else From 06c0c36c671bc4b5225204cdabdc23e5c9715914 Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Tue, 18 Nov 2025 17:04:24 +0100 Subject: [PATCH 088/134] + add output for no rules were deduplicated --- scripts/nym-node-setup/network-tunnel-manager.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 7017adbd4d..e7a291bb29 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -207,6 +207,8 @@ remove_duplicate_rules() { echo "warning: could not reliably match ipv4 duplicate rule: $rule" fi done + else + echo "no ipv4 rules were deduplicated" fi done < "$tmp4" @@ -270,6 +272,8 @@ remove_duplicate_rules() { echo "warning: could not match ipv6 duplicate rule reliably: $rule" fi done + else + echo "no ipv6 rules were deduplicated" fi done < "$tmp6" From 2e059865a14d0b0309980f2b2994efdf28ca1cc3 Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Tue, 18 Nov 2025 17:08:12 +0100 Subject: [PATCH 089/134] Revert "/ move ensure_jq where needed" This reverts commit bdc0f5022d0cbf8553be30a55c76c4eadafc3efa. --- .../nym-node-setup/network-tunnel-manager.sh | 43 ++++++++++--------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index e7a291bb29..01d73705a8 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -12,6 +12,24 @@ if [ "$(id -u)" -ne 0 ]; then exit 1 fi +echo "checking for jq..." + +if command -v jq >/dev/null 2>&1; then + echo "jq is already installed" + # continue script execution +else + echo "jq not found, installing..." + apt-get update -y + DEBIAN_FRONTEND=noninteractive apt-get install -y jq + + if command -v jq >/dev/null 2>&1; then + echo "jq installed successfully" + else + echo "failed to install jq" + exit 1 + fi +fi + ############################################################################### # basic config ############################################################################### @@ -33,6 +51,7 @@ detect_uplink_interface() { fi } + # uplink device detection, can be overridden NETWORK_DEVICE="${NETWORK_DEVICE:-}" if [[ -z "$NETWORK_DEVICE" ]]; then @@ -60,25 +79,6 @@ NC='\033[0m' # shared helpers ############################################################################### -ensure_jq() { - echo "checking for jq..." - - if command -v jq >/dev/null 2>&1; then - echo "jq is already installed" - else - echo "jq not found, installing..." - apt-get update -y - DEBIAN_FRONTEND=noninteractive apt-get install -y jq - - if command -v jq >/dev/null 2>&1; then - echo "jq installed successfully" - else - echo "failed to install jq" - exit 1 - fi - fi -} - install_iptables_persistent() { if ! dpkg -s iptables-persistent >/dev/null 2>&1; then echo -e "${YELLOW}installing iptables-persistent${NC}" @@ -287,6 +287,9 @@ remove_duplicate_rules() { echo "duplicate rule scan completed for $interface" } + + + apply_iptables_rules() { local interface=$1 echo "applying iptables rules for $interface using uplink $NETWORK_DEVICE" @@ -350,7 +353,6 @@ perform_pings() { } joke_through_tunnel() { - ensure_jq local interface=$1 local green="\033[0;32m" local reset="\033[0m" @@ -907,7 +909,6 @@ test_forward_chain_hook() { test_default_reject_rule() { echo "testing default reject rule at end of ${NYM_CHAIN}" - # not sure this will really check that it is on end if iptables -L "$NYM_CHAIN" | grep -q "REJECT"; then echo "default reject present in ipv4 chain" else From 2933732225b71c5c56e83888ba82043e2c0caf7d Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Tue, 18 Nov 2025 17:08:51 +0100 Subject: [PATCH 090/134] Revert "+ add output for no rules were deduplicated" This reverts commit 06c0c36c671bc4b5225204cdabdc23e5c9715914. --- scripts/nym-node-setup/network-tunnel-manager.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 01d73705a8..acd0186366 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -207,8 +207,6 @@ remove_duplicate_rules() { echo "warning: could not reliably match ipv4 duplicate rule: $rule" fi done - else - echo "no ipv4 rules were deduplicated" fi done < "$tmp4" @@ -272,8 +270,6 @@ remove_duplicate_rules() { echo "warning: could not match ipv6 duplicate rule reliably: $rule" fi done - else - echo "no ipv6 rules were deduplicated" fi done < "$tmp6" From bfcb4c79bb0ee6cd03efca62d570cc3cbd0ae599 Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Wed, 19 Nov 2025 13:07:08 +0100 Subject: [PATCH 091/134] / fix test_default_reject_rule --- .../nym-node-setup/network-tunnel-manager.sh | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index acd0186366..266ed03679 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -903,14 +903,23 @@ test_forward_chain_hook() { } test_default_reject_rule() { - echo "testing default reject rule at end of ${NYM_CHAIN}" + echo "testing default reject rule position in ${NYM_CHAIN}" - if iptables -L "$NYM_CHAIN" | grep -q "REJECT"; then - echo "default reject present in ipv4 chain" - else - echo "default reject missing in ipv4 chain" + local last_rule_v4 + last_rule_v4=$(iptables -S "$NYM_CHAIN" | awk '/^-A /{rule=$0} END{print rule}') + if [[ "$last_rule_v4" != "-A $NYM_CHAIN -j REJECT --reject-with icmp-port-unreachable" ]]; then + echo "default reject missing or not last in ipv4 chain" return 1 fi + + local last_rule_v6 + last_rule_v6=$(ip6tables -S "$NYM_CHAIN" | awk '/^-A /{rule=$0} END{print rule}') + if [[ "$last_rule_v6" != "-A $NYM_CHAIN -j REJECT --reject-with icmp6-port-unreachable" ]]; then + echo "default reject missing or not last in ipv6 chain" + return 1 + fi + + echo "default reject confirmed at end of ${NYM_CHAIN}" } exit_policy_run_tests() { From c23e139eaab8c68ed700a95b20bfed0f6b998cc0 Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Wed, 19 Nov 2025 13:11:05 +0100 Subject: [PATCH 092/134] + COLORS test_default_reject_rule --- scripts/nym-node-setup/network-tunnel-manager.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 266ed03679..ade9c1836e 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -903,23 +903,23 @@ test_forward_chain_hook() { } test_default_reject_rule() { - echo "testing default reject rule position in ${NYM_CHAIN}" + echo -e "${YELLOW}testing default reject rule position in ${NYM_CHAIN}${NC}" local last_rule_v4 last_rule_v4=$(iptables -S "$NYM_CHAIN" | awk '/^-A /{rule=$0} END{print rule}') if [[ "$last_rule_v4" != "-A $NYM_CHAIN -j REJECT --reject-with icmp-port-unreachable" ]]; then - echo "default reject missing or not last in ipv4 chain" + echo -e "${RED}default reject missing or not last in ipv4 chain${NC}" return 1 fi local last_rule_v6 last_rule_v6=$(ip6tables -S "$NYM_CHAIN" | awk '/^-A /{rule=$0} END{print rule}') if [[ "$last_rule_v6" != "-A $NYM_CHAIN -j REJECT --reject-with icmp6-port-unreachable" ]]; then - echo "default reject missing or not last in ipv6 chain" + echo -e "${RED}default reject missing or not last in ipv6 chain${NC}" return 1 fi - echo "default reject confirmed at end of ${NYM_CHAIN}" + echo -e "${GREEN}default reject confirmed at end of ${NYM_CHAIN}${NC}" } exit_policy_run_tests() { From 4736f1eb527a618b3c7dae95f7d49e85ab1acc6a Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Wed, 19 Nov 2025 13:26:14 +0100 Subject: [PATCH 093/134] / fix login in exit_policy_run_tests --- scripts/nym-node-setup/network-tunnel-manager.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index ade9c1836e..b1c637e51c 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -934,17 +934,17 @@ exit_policy_run_tests() { local total=0 local failed=0 - test_forward_chain_hook || ((failed++)) + test_forward_chain_hook || ((failed += 1)) ((total++)) - test_port_range_rules || ((failed++)) + test_port_range_rules || ((failed += 1)) ((total++)) - test_critical_services || ((failed++)) + test_critical_services || ((failed += 1)) ((total++)) if [[ $skip_default -eq 0 ]]; then - test_default_reject_rule || ((failed++)) + test_default_reject_rule || ((failed += 1)) ((total++)) fi From 95ee3a7c7d3ea78bd1b9dec1bd8dc7ee895621e2 Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Wed, 19 Nov 2025 13:34:35 +0100 Subject: [PATCH 094/134] + colors test_forward_chain_hook & complete_networking_configuration --- scripts/nym-node-setup/network-tunnel-manager.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index b1c637e51c..e08aac84cc 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -881,21 +881,21 @@ test_critical_services() { } test_forward_chain_hook() { - echo "testing forward chain hook direction for ${NYM_CHAIN}" + echo -e "${YELLOW}testing forward chain hook direction for ${NYM_CHAIN}${NC}" local failures=0 if iptables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null; then - echo "ipv4 forward hook ok: -i $WG_INTERFACE -o $NETWORK_DEVICE -> $NYM_CHAIN" + echo echo -e "${GREEN}ipv4 forward hook ok: -i $WG_INTERFACE -o $NETWORK_DEVICE -> $NYM_CHAIN${NC}" else - echo "ipv4 forward hook missing or wrong" + echo -e "${RED}ipv4 forward hook missing or wrong${NC}" ((failures++)) fi if ip6tables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null; then - echo "ipv6 forward hook ok: -i $WG_INTERFACE -o $NETWORK_DEVICE -> $NYM_CHAIN" + echo echo -e "${GREEN}ipv6 forward hook ok: -i $WG_INTERFACE -o $NETWORK_DEVICE -> $NYM_CHAIN${NC}" else - echo "ipv6 forward hook missing or wrong" + echo -e "${RED}ipv6 forward hook missing or wrong${NC}" ((failures++)) fi @@ -1002,11 +1002,11 @@ exit_policy_install() { } complete_networking_configuration() { - echo "starting complete networking configuration: tunnels + exit policy" + echo -e "${YELLOW}starting complete networking configuration: tunnels + exit policy${NC}" full_tunnel_setup exit_policy_install - exit_policy_run_tests || echo "exit policy tests reported problems, please review output" + exit_policy_run_tests || echo -e "${RED}exit policy tests reported problems, please review output${NC}" echo "complete networking configuration finished" } From 40a7a87c615a2412f3b7058d646e9c92f968af01 Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Wed, 19 Nov 2025 13:36:41 +0100 Subject: [PATCH 095/134] + colorl jq install --- scripts/nym-node-setup/network-tunnel-manager.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index e08aac84cc..8413af1742 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -15,17 +15,17 @@ fi echo "checking for jq..." if command -v jq >/dev/null 2>&1; then - echo "jq is already installed" + echo -e "${GREEN}jq is already installed${NC}" # continue script execution else - echo "jq not found, installing..." + echo -e "${YELLOW}jq not found, installing...${NC}" apt-get update -y DEBIAN_FRONTEND=noninteractive apt-get install -y jq if command -v jq >/dev/null 2>&1; then - echo "jq installed successfully" + echo -e "${GREEN}jq installed successfully${NC}" else - echo "failed to install jq" + echo -e "${RED}failed to install jq${NC}" exit 1 fi fi From 8de37eb6c91fa548ef2c0c463f9d626ed05a9949 Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Wed, 19 Nov 2025 13:43:24 +0100 Subject: [PATCH 096/134] / move ensure_jq where needed --- .../nym-node-setup/network-tunnel-manager.sh | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 8413af1742..799ee4f6d2 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -12,24 +12,6 @@ if [ "$(id -u)" -ne 0 ]; then exit 1 fi -echo "checking for jq..." - -if command -v jq >/dev/null 2>&1; then - echo -e "${GREEN}jq is already installed${NC}" - # continue script execution -else - echo -e "${YELLOW}jq not found, installing...${NC}" - apt-get update -y - DEBIAN_FRONTEND=noninteractive apt-get install -y jq - - if command -v jq >/dev/null 2>&1; then - echo -e "${GREEN}jq installed successfully${NC}" - else - echo -e "${RED}failed to install jq${NC}" - exit 1 - fi -fi - ############################################################################### # basic config ############################################################################### @@ -51,7 +33,6 @@ detect_uplink_interface() { fi } - # uplink device detection, can be overridden NETWORK_DEVICE="${NETWORK_DEVICE:-}" if [[ -z "$NETWORK_DEVICE" ]]; then @@ -79,6 +60,25 @@ NC='\033[0m' # shared helpers ############################################################################### +ensure_jq() { + echo "checking for jq..." + + if command -v jq >/dev/null 2>&1; then + echo "jq is already installed" + else + echo "jq not found, installing..." + apt-get update -y + DEBIAN_FRONTEND=noninteractive apt-get install -y jq + + if command -v jq >/dev/null 2>&1; then + echo "jq installed successfully" + else + echo "failed to install jq" + exit 1 + fi + fi +} + install_iptables_persistent() { if ! dpkg -s iptables-persistent >/dev/null 2>&1; then echo -e "${YELLOW}installing iptables-persistent${NC}" @@ -283,9 +283,6 @@ remove_duplicate_rules() { echo "duplicate rule scan completed for $interface" } - - - apply_iptables_rules() { local interface=$1 echo "applying iptables rules for $interface using uplink $NETWORK_DEVICE" @@ -349,6 +346,7 @@ perform_pings() { } joke_through_tunnel() { + ensure_jq local interface=$1 local green="\033[0;32m" local reset="\033[0m" @@ -905,6 +903,11 @@ test_forward_chain_hook() { test_default_reject_rule() { echo -e "${YELLOW}testing default reject rule position in ${NYM_CHAIN}${NC}" + # not sure this will really check that it is on end + if iptables -L "$NYM_CHAIN" | grep -q "REJECT"; then + echo "default reject present in ipv4 chain" + else + echo "default reject missing in ipv4 chain" local last_rule_v4 last_rule_v4=$(iptables -S "$NYM_CHAIN" | awk '/^-A /{rule=$0} END{print rule}') if [[ "$last_rule_v4" != "-A $NYM_CHAIN -j REJECT --reject-with icmp-port-unreachable" ]]; then From 5496cce5c967acc211474f9db41e26098cdd774f Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Wed, 19 Nov 2025 13:48:36 +0100 Subject: [PATCH 097/134] / move color definition --- .../nym-node-setup/network-tunnel-manager.sh | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 799ee4f6d2..fbba8cd5f2 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -4,11 +4,19 @@ set -euo pipefail +############################################################################### +# colors (no emojis) +############################################################################### +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[0;33m' +NC='\033[0m' + ############################################################################### # safety: must run as root, jq ############################################################################### if [ "$(id -u)" -ne 0 ]; then - echo "This script must be run as root" + echo -e "${RED}This script must be run as root${NC}" exit 1 fi @@ -16,6 +24,10 @@ fi # basic config ############################################################################### +NYM_CHAIN="NYM-EXIT" +POLICY_FILE="/etc/nym/exit-policy.txt" +EXIT_POLICY_LOCATION="https://nymtech.net/.wellknown/network-requester/exit-policy.txt" + TUNNEL_INTERFACE="${TUNNEL_INTERFACE:-nymtun0}" WG_INTERFACE="${WG_INTERFACE:-nymwg}" @@ -46,16 +58,6 @@ if [[ -z "$NETWORK_DEVICE" ]]; then exit 1 fi -NYM_CHAIN="NYM-EXIT" -POLICY_FILE="/etc/nym/exit-policy.txt" -EXIT_POLICY_LOCATION="https://nymtech.net/.wellknown/network-requester/exit-policy.txt" - -# colors (no emojis) -GREEN='\033[0;32m' -RED='\033[0;31m' -YELLOW='\033[0;33m' -NC='\033[0m' - ############################################################################### # shared helpers ############################################################################### From 22db132c0909693fcf2071f17577accdeae0c61e Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Wed, 19 Nov 2025 14:14:19 +0100 Subject: [PATCH 098/134] @ merge fix test_default_reject_rule --- scripts/nym-node-setup/network-tunnel-manager.sh | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index fbba8cd5f2..6982e74baa 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -886,14 +886,14 @@ test_forward_chain_hook() { local failures=0 if iptables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null; then - echo echo -e "${GREEN}ipv4 forward hook ok: -i $WG_INTERFACE -o $NETWORK_DEVICE -> $NYM_CHAIN${NC}" + echo -e "${GREEN}ipv4 forward hook ok: -i $WG_INTERFACE -o $NETWORK_DEVICE -> $NYM_CHAIN${NC}" else echo -e "${RED}ipv4 forward hook missing or wrong${NC}" ((failures++)) fi if ip6tables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null; then - echo echo -e "${GREEN}ipv6 forward hook ok: -i $WG_INTERFACE -o $NETWORK_DEVICE -> $NYM_CHAIN${NC}" + echo -e "${GREEN}ipv6 forward hook ok: -i $WG_INTERFACE -o $NETWORK_DEVICE -> $NYM_CHAIN${NC}" else echo -e "${RED}ipv6 forward hook missing or wrong${NC}" ((failures++)) @@ -905,11 +905,6 @@ test_forward_chain_hook() { test_default_reject_rule() { echo -e "${YELLOW}testing default reject rule position in ${NYM_CHAIN}${NC}" - # not sure this will really check that it is on end - if iptables -L "$NYM_CHAIN" | grep -q "REJECT"; then - echo "default reject present in ipv4 chain" - else - echo "default reject missing in ipv4 chain" local last_rule_v4 last_rule_v4=$(iptables -S "$NYM_CHAIN" | awk '/^-A /{rule=$0} END{print rule}') if [[ "$last_rule_v4" != "-A $NYM_CHAIN -j REJECT --reject-with icmp-port-unreachable" ]]; then From 9c5847dc6764b9437128478c692333b2ce7a57bd Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Wed, 19 Nov 2025 14:26:16 +0100 Subject: [PATCH 099/134] @ fix failing exit_policy_run_tests --- scripts/nym-node-setup/network-tunnel-manager.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 6982e74baa..0cc57d5fb7 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -935,17 +935,17 @@ exit_policy_run_tests() { local failed=0 test_forward_chain_hook || ((failed += 1)) - ((total++)) + ((total += 1)) test_port_range_rules || ((failed += 1)) - ((total++)) + ((total += 1)) test_critical_services || ((failed += 1)) - ((total++)) + ((total += 1)) if [[ $skip_default -eq 0 ]]; then test_default_reject_rule || ((failed += 1)) - ((total++)) + ((total += 1)) fi echo "tests run: $total, failures: $failed" From 568268d39b6460e70c5b4518a8bc02fa45cab45a Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Wed, 19 Nov 2025 14:32:33 +0100 Subject: [PATCH 100/134] + color exit_policy_run_tests --- scripts/nym-node-setup/network-tunnel-manager.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 0cc57d5fb7..67f22af298 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -927,7 +927,7 @@ exit_policy_run_tests() { while [[ $# -gt 0 ]]; do case "$1" in --skip-default-reject) skip_default=1; shift ;; - *) echo "unknown test option: $1"; return 1 ;; + *) echo -e "${RED}unknown test option: $1${NC}"; return 1 ;; esac done @@ -948,11 +948,11 @@ exit_policy_run_tests() { ((total += 1)) fi - echo "tests run: $total, failures: $failed" + echo -e "${YELLOW}tests run: ${GREEN}$total${YELLOW}, failures: ${RED}$failed${NC}" if [[ $failed -eq 0 ]]; then - echo "all exit policy tests passed" + echo -e "${GREEN}all exit policy tests passed${NC}" else - echo "some exit policy tests failed" + echo -e "${RED}some exit policy tests failed${NC}" fi return "$failed" From 7a339d4c4d325b560c4d9f961f564d32c4396d0f Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Wed, 19 Nov 2025 16:35:40 +0100 Subject: [PATCH 101/134] + color everywhere --- .../nym-node-setup/network-tunnel-manager.sh | 86 +++++++++++-------- 1 file changed, 49 insertions(+), 37 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 67f22af298..c03ada3a08 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -12,11 +12,23 @@ RED='\033[0;31m' YELLOW='\033[0;33m' NC='\033[0m' +info() { + printf "%b\n" "${YELLOW}[INFO] $*${NC}" +} + +ok() { + printf "%b\n" "${GREEN}[OK] $*${NC}" +} + +error() { + printf "%b\n" "${RED}[ERROR] $*${NC}" +} + ############################################################################### # safety: must run as root, jq ############################################################################### if [ "$(id -u)" -ne 0 ]; then - echo -e "${RED}This script must be run as root${NC}" + error "This script must be run as root" exit 1 fi @@ -54,7 +66,7 @@ if [[ -z "$NETWORK_DEVICE" ]]; then NETWORK_DEVICE="$(detect_uplink_interface "ip -o route show default table all")" fi if [[ -z "$NETWORK_DEVICE" ]]; then - echo "cannot determine uplink interface. set NETWORK_DEVICE or UPLINK_DEV" + error "cannot determine uplink interface. set NETWORK_DEVICE or UPLINK_DEV" exit 1 fi @@ -63,19 +75,19 @@ fi ############################################################################### ensure_jq() { - echo "checking for jq..." + info "checking for jq..." if command -v jq >/dev/null 2>&1; then - echo "jq is already installed" + ok "jq is already installed" else - echo "jq not found, installing..." + info "jq not found, installing..." apt-get update -y DEBIAN_FRONTEND=noninteractive apt-get install -y jq if command -v jq >/dev/null 2>&1; then - echo "jq installed successfully" + ok "jq installed successfully" else - echo "failed to install jq" + error "failed to install jq" exit 1 fi fi @@ -810,7 +822,7 @@ test_exit_policy_connectivity() { ############################################################################### test_port_range_rules() { - echo "testing port range rules in ${NYM_CHAIN}" + info "testing port range rules in ${NYM_CHAIN}" local port_ranges=( "20-21:tcp:ftp" @@ -834,9 +846,9 @@ test_port_range_rules() { end=$(echo "$range" | cut -d'-' -f2) if iptables -t filter -C "$NYM_CHAIN" -p "$proto" --dport "$start:$end" -j ACCEPT 2>/dev/null; then - echo "rule ok: $name $proto $range" + ok "rule ok: $name $proto $range" else - echo "missing rule: $name $proto $range" + error "missing rule: $name $proto $range" ((failures++)) fi done @@ -845,7 +857,7 @@ test_port_range_rules() { } test_critical_services() { - echo "testing critical service rules in ${NYM_CHAIN}" + info "testing critical service rules in ${NYM_CHAIN}" local tcp_ports=(22 53 443 853 1194) local udp_ports=(53 123 1194) @@ -853,12 +865,12 @@ test_critical_services() { for port in "${tcp_ports[@]}"; do if iptables -t filter -C "$NYM_CHAIN" -p tcp --dport "$port" -j ACCEPT 2>/dev/null; then - echo "tcp port $port allowed" + ok "tcp port $port allowed" else if iptables-save | grep -E "^-A $NYM_CHAIN.*tcp.*dpts:" | grep -q "$port"; then - echo "tcp port $port allowed by range" + ok "tcp port $port allowed by range" else - echo "tcp port $port missing" + error "tcp port $port missing" ((failures++)) fi fi @@ -866,12 +878,12 @@ test_critical_services() { for port in "${udp_ports[@]}"; do if iptables -t filter -C "$NYM_CHAIN" -p udp --dport "$port" -j ACCEPT 2>/dev/null; then - echo "udp port $port allowed" + ok "udp port $port allowed" else if iptables-save | grep -E "^-A $NYM_CHAIN.*udp.*dpts:" | grep -q "$port"; then - echo "udp port $port allowed by range" + ok "udp port $port allowed by range" else - echo "udp port $port missing" + error "udp port $port missing" ((failures++)) fi fi @@ -881,21 +893,21 @@ test_critical_services() { } test_forward_chain_hook() { - echo -e "${YELLOW}testing forward chain hook direction for ${NYM_CHAIN}${NC}" + info "testing forward chain hook direction for ${NYM_CHAIN}" local failures=0 if iptables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null; then - echo -e "${GREEN}ipv4 forward hook ok: -i $WG_INTERFACE -o $NETWORK_DEVICE -> $NYM_CHAIN${NC}" + ok "ipv4 forward hook ok: -i $WG_INTERFACE -o $NETWORK_DEVICE -> $NYM_CHAIN" else - echo -e "${RED}ipv4 forward hook missing or wrong${NC}" + error "ipv4 forward hook missing or wrong" ((failures++)) fi if ip6tables -C FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null; then - echo -e "${GREEN}ipv6 forward hook ok: -i $WG_INTERFACE -o $NETWORK_DEVICE -> $NYM_CHAIN${NC}" + ok "ipv6 forward hook ok: -i $WG_INTERFACE -o $NETWORK_DEVICE -> $NYM_CHAIN" else - echo -e "${RED}ipv6 forward hook missing or wrong${NC}" + error "ipv6 forward hook missing or wrong" ((failures++)) fi @@ -903,23 +915,23 @@ test_forward_chain_hook() { } test_default_reject_rule() { - echo -e "${YELLOW}testing default reject rule position in ${NYM_CHAIN}${NC}" + info "testing default reject rule position in ${NYM_CHAIN}" local last_rule_v4 last_rule_v4=$(iptables -S "$NYM_CHAIN" | awk '/^-A /{rule=$0} END{print rule}') if [[ "$last_rule_v4" != "-A $NYM_CHAIN -j REJECT --reject-with icmp-port-unreachable" ]]; then - echo -e "${RED}default reject missing or not last in ipv4 chain${NC}" + error "default reject missing or not last in ipv4 chain" return 1 fi local last_rule_v6 last_rule_v6=$(ip6tables -S "$NYM_CHAIN" | awk '/^-A /{rule=$0} END{print rule}') if [[ "$last_rule_v6" != "-A $NYM_CHAIN -j REJECT --reject-with icmp6-port-unreachable" ]]; then - echo -e "${RED}default reject missing or not last in ipv6 chain${NC}" + error "default reject missing or not last in ipv6 chain" return 1 fi - echo -e "${GREEN}default reject confirmed at end of ${NYM_CHAIN}${NC}" + ok "default reject confirmed at end of ${NYM_CHAIN}" } exit_policy_run_tests() { @@ -927,7 +939,7 @@ exit_policy_run_tests() { while [[ $# -gt 0 ]]; do case "$1" in --skip-default-reject) skip_default=1; shift ;; - *) echo -e "${RED}unknown test option: $1${NC}"; return 1 ;; + *) error "unknown test option: $1"; return 1 ;; esac done @@ -948,11 +960,11 @@ exit_policy_run_tests() { ((total += 1)) fi - echo -e "${YELLOW}tests run: ${GREEN}$total${YELLOW}, failures: ${RED}$failed${NC}" + info "tests run: $total, failures: $failed" if [[ $failed -eq 0 ]]; then - echo -e "${GREEN}all exit policy tests passed${NC}" + ok "all exit policy tests passed" else - echo -e "${RED}some exit policy tests failed${NC}" + error "some exit policy tests failed" fi return "$failed" @@ -964,7 +976,7 @@ exit_policy_run_tests() { full_tunnel_setup() { # this mirrors your previous chain of calls but inside one script - echo "running full tunnel setup for ${TUNNEL_INTERFACE} and ${WG_INTERFACE}" + info "running full tunnel setup for ${TUNNEL_INTERFACE} and ${WG_INTERFACE}" check_tunnel_iptables "$TUNNEL_INTERFACE" remove_duplicate_rules "$TUNNEL_INTERFACE" @@ -985,11 +997,11 @@ full_tunnel_setup() { joke_through_tunnel "$TUNNEL_INTERFACE" joke_through_tunnel "$WG_INTERFACE" - echo "full tunnel setup completed" + ok "full tunnel setup completed" } exit_policy_install() { - echo "installing nym wireguard exit policy for ${WG_INTERFACE} via ${NETWORK_DEVICE}" + info "installing nym wireguard exit policy for ${WG_INTERFACE} via ${NETWORK_DEVICE}" exit_policy_install_deps adjust_ip_forwarding create_nym_chain @@ -998,17 +1010,17 @@ exit_policy_install() { apply_spamhaus_blocklist add_default_reject_rule save_iptables_rules - echo "nym exit policy installed" + ok "nym exit policy installed" } complete_networking_configuration() { - echo -e "${YELLOW}starting complete networking configuration: tunnels + exit policy${NC}" + info "starting complete networking configuration: tunnels + exit policy" full_tunnel_setup exit_policy_install - exit_policy_run_tests || echo -e "${RED}exit policy tests reported problems, please review output${NC}" + exit_policy_run_tests || error "exit policy tests reported problems, please review output" - echo "complete networking configuration finished" + ok "complete networking configuration finished" } ############################################################################### From 1b9af19e2082df7fb96ab1a9b153750f0b0da5c1 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Wed, 19 Nov 2025 17:14:44 +0100 Subject: [PATCH 102/134] update routing configuration steps and make components --- .../operators/snippets/routing-conf.mdx | 247 ++++++++++++++++ .../snippets/wg-exit-policy-conf.mdx | 0 .../snippets/wg-exit-policy-test.mdx | 0 .../nodes/nym-node/configuration.mdx | 264 +----------------- 4 files changed, 254 insertions(+), 257 deletions(-) create mode 100644 documentation/docs/components/operators/snippets/routing-conf.mdx create mode 100644 documentation/docs/components/operators/snippets/wg-exit-policy-conf.mdx create mode 100644 documentation/docs/components/operators/snippets/wg-exit-policy-test.mdx diff --git a/documentation/docs/components/operators/snippets/routing-conf.mdx b/documentation/docs/components/operators/snippets/routing-conf.mdx new file mode 100644 index 0000000000..acb73b084d --- /dev/null +++ b/documentation/docs/components/operators/snippets/routing-conf.mdx @@ -0,0 +1,247 @@ +import { Callout } from 'nextra/components'; +import { Tabs } from 'nextra/components'; +import { VarInfo } from 'components/variable-info.tsx'; +import { Steps } from 'nextra/components'; +import { AccordionTemplate } from 'components/accordion-template.tsx'; + + +We're working on Rust implementation agregating all routing settings into a binary, to solve all connectivity configuration requirements. In the meantime node operators need to use the [`network_tunnel_manager.sh`](https://github.com/nymtech/nym/blob/develop/scripts/network_tunnel_manager.sh) as a handy support to configure their servers. + + + +Networking configuration across different ISPs and various operation systems does not have a generic solution. If the provided configuration setup doesn't solve your problem check out [IPv6 troubleshooting](/operators/troubleshooting/vps-isp.mdx#ipv6-troubleshooting) page. Be aware that you may have to do more research, customised adjustments or contact your ISP to change settings for your VPS. + + +**Network Tunnel Manager ([`network-tunnel-manager.sh`](https://github.com/nymtech/nym/blob/develop/scripts/network_tunnel_manager.sh), NTM) is currently the one tool hadling the configuration of `nym-node` hosting server, according to the required design (node's [functionality](/operators/nodes/nym-node/setup#functionality-mode), WireGuard setup etc).** + +**NTM cand administrate these areas:** + +* IPv4 and IPv6 routing to the internet + +* The `nymtun0` interface (Mixnet / 5-hop): dynamically managed by the `exit-gateway` service. When the service is stopped, `nymtun0` disappears, and when started, `nymtun0` is recreated. + +* The `nymwg` interface (WG / 2-hop): used for creating a secure wireguard tunnel as part of the Nym Network configuration. + +* `iptables` rules specific to `nymwg` to ensure proper routing and forwarding through the wireguard tunnel. The `nymwg` interface needs to be correctly configured and active for the related commands to function properly. This includes applying or removing iptables rules and running connectivity tests through the `nymwg` tunnel. + +* WireGuard exit policy: Mixnet uses a common [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt), to apply the same for WG, the operators need to set that one up on their server using `iptables` rules. + +* Testing and validating all above + +The script should be used in a context where `nym-node` is running to fully utilise its capabilities, particularly for fetching IPv6 addresses or applying network rules that depend on the `nymtun0` and `nymwg` interfaces and to establish a WireGuard tunnel. + +**Before starting with the following configuration, make sure you have the [latest `nym-node` binary](https://github.com/nymtech/nym/releases) installed and your [VPS setup](../preliminary-steps/vps-setup.mdx) finished properly!** + + +**Run the following steps as root!** + + +|**Choose configuration command according your setup** + +
+ New nym-node Full Configuration, + Existing nym-node Full Configuration + Step-by-step or Partial Configuration + ]} defaultIndex={0}> + +This design is meant for operators setting up a new node on a fresh machine and it will result with a complete server readiness for routing as Entry Gateway and Exit Gateway in both Mixnet and WireGuard mode. + + +###### 1. Download `network-tunnel-manager.sh`, make executable and run with `--help` command: + +```sh +curl -L https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/nym-node-setup/network-tunnel-manager.sh -o network-tunnel-manager.sh && \ +chmod +x network-tunnel-manager.sh && \ +./network-tunnel-manager.sh --help +``` + +###### 2. Make sure your `nym-node` service is up and running and bonded + +- **If you setting up a new node and not upgrading an existing one, keep it running and [bond](/operators/nodes/nym-node/bonding.mdx) your node now! Then come back here and follow the rest of the configuration.** + +###### 3. Execute complete network configuration: +```sh +./network-tunnel-manager.sh complete_networking_setup +``` + + + + +This is meant for operators configuring an existing and bonded node and it will result with a complete server readiness for routing as Entry Gateway and Exit Gateway in both Mixnet and WireGuard mode. + + +###### 1. Download `network-tunnel-manager.sh`, make executable and run with `--help` command: + +```sh +curl -L https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/nym-node-setup/network-tunnel-manager.sh -o network-tunnel-manager.sh && \ +chmod +x network-tunnel-manager.sh && \ +./network-tunnel-manager.sh --help +``` + +###### 2. Execute complete network configuration: +```sh +./network-tunnel-manager.sh complete_networking_setup +``` + + + + +This design is meant for operators who want to do their server configuration step by step or choose only some parts of the setup. + +###### 1. Download `network-tunnel-manager.sh`, make executable and run with `--help` command: + +```sh +curl -L https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/nym-node-setup/network-tunnel-manager.sh -o network-tunnel-manager.sh && \ +chmod +x network-tunnel-manager.sh && \ +./network-tunnel-manager.sh --help +``` + +###### 2. Make sure your `nym-node` service is up and running and bonded + +- **If you setting up a new node and not upgrading an existing one, keep it running and [bond](/operators/nodes/nym-node/bonding.mdx) your node now! Then come back here and follow the rest of the configuration.** + +###### 3. Choose steps according your need + +> You should be certain in your selection when configuring only various parts of the server. + +###### Setup IP tables rules + +- Delete IP tables rules for IPv4 and IPv6 and apply new ones: +```sh +./network-tunnel-manager.sh remove_duplicate_rules nymtun0 + +./network-tunnel-manager.sh apply_iptables_rules +``` + +- The process may prompt you if you want to save current IPv4 and IPv6 rules, choose yes. + +![](/images/operators/ip_table_prompt.png) + +- At this point you should see a `global ipv6` address. +```sh +./network-tunnel-manager.sh fetch_and_display_ipv6 +``` +
+}> +```sh +iptables-persistent is already installed. +Using IPv6 address: 2001:db8:a160::1/112 #the address will be different for you +operation fetch_ipv6_address_nym_tun completed successfully. +``` + + +###### Check Nymtun IP tables: + +```sh +./network-tunnel-manager.sh check_nymtun_iptables +``` + +- If there's no process running it wouldn't return anything. +- In case you see `nymtun0` but not active, this is probably because you are setting up a new (never bonded) node and not upgrading an existing one. + +
+}> +```sh +iptables-persistent is already installed. +network Device: eth0 +--------------------------------------- + +inspecting IPv4 firewall rules... +Chain FORWARD (policy DROP 0 packets, 0 bytes) + 0 0 ufw-reject-forward all -- * * 0.0.0.0/0 0.0.0.0/0 + 0 0 ACCEPT all -- nymtun0 eth0 0.0.0.0/0 0.0.0.0/0 + 0 0 ACCEPT all -- eth0 nymtun0 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED + 0 0 ACCEPT all -- nymtun0 eth0 0.0.0.0/0 0.0.0.0/0 + 0 0 ACCEPT all -- eth0 nymtun0 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED + 0 0 ACCEPT all -- nymtun0 eth0 0.0.0.0/0 0.0.0.0/0 + 0 0 ACCEPT all -- eth0 nymtun0 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED +--------------------------------------- + +inspecting IPv6 firewall rules... +Chain FORWARD (policy DROP 0 packets, 0 bytes) + 0 0 ufw6-reject-forward all * * ::/0 ::/0 + 0 0 ACCEPT all eth0 nymtun0 ::/0 ::/0 state RELATED,ESTABLISHED + 0 0 ACCEPT all nymtun0 eth0 ::/0 ::/0 + 0 0 ACCEPT all eth0 nymtun0 ::/0 ::/0 state RELATED,ESTABLISHED + 0 0 ACCEPT all nymtun0 eth0 ::/0 ::/0 + 0 0 ACCEPT all eth0 nymtun0 ::/0 ::/0 state RELATED,ESTABLISHED + 0 0 ACCEPT all nymtun0 eth0 ::/0 ::/0 +operation check_nymtun_iptables completed successfully. +``` + + +###### Remove old and apply new rules for wireguad routing + +```sh +../network-tunnel-manager.sh remove_duplicate_rules nymwg + +./network-tunnel-manager.sh apply_iptables_rules_wg +``` + +###### Apply rules to configure DNS routing and allow ICMP piung test for node probing (network testing) + +```sh +./network-tunnel-manager.sh configure_dns_and_icmp_wg +``` +###### Adjust and validate IP forwarding + +```sh +./network-tunnel-manager.sh adjust_ip_forwarding + +./network-tunnel-manager.sh check_ipv6_ipv4_forwarding +``` + +###### Check `nymtun0` interface and test routing configuration + +```sh +ip addr show nymtun0 +``` + +
+}> +```sh +# your addresses will be different +8: nymtun0: mtu 1420 qdisc fq_codel state UNKNOWN group default qlen 500 + link/none + inet 10.0.0.1/16 scope global nymtun0 + valid_lft forever preferred_lft forever + inet6 fc00::1/112 scope global + valid_lft forever preferred_lft forever + inet6 fe80::ad08:d167:5700:8c7c/64 scope link stable-privacy + valid_lft forever preferred_lft forever` +``` + + +- Validate your IPv6 and IPv4 networking by running a joke test via Mixnet: +```sh +./network-tunnel-manager.sh joke_through_the_mixnet +``` + +- Validate your tunneling by running a joke test via WG: +```sh +../network-tunnel-manager.sh joke_through_wg_tunnel +``` + +###### Enable wireguard + +Now you can run your node with the `--wireguard-enabled true` flag or add it to your [systemd service config](#systemd). Restart your `nym-node` or [systemd](#2-following-steps-for-nym-nodes-running-as-systemd-service) service (recommended): + +```sh +systemctl daemon-reload && service nym-node restart +``` +- Optionally, you can check if the node is running correctly by monitoring the service logs: + +```sh +journalctl -u nym-node.service -f -n 100 +``` + +
+
+
+ + +Note that the functionality the node runs in is decided by [arguments on the node itself / in node's `config.toml`](/operators/nodes/nym-node/setup#functionality-mode), this tool only prepares the server. + + +Make sure that you get the validation of all connectivity. If there are still any problems, please refer to [troubleshooting section](/operators/troubleshooting/vps-isp.mdx#incorrect-gateway-network-check). diff --git a/documentation/docs/components/operators/snippets/wg-exit-policy-conf.mdx b/documentation/docs/components/operators/snippets/wg-exit-policy-conf.mdx new file mode 100644 index 0000000000..e69de29bb2 diff --git a/documentation/docs/components/operators/snippets/wg-exit-policy-test.mdx b/documentation/docs/components/operators/snippets/wg-exit-policy-test.mdx new file mode 100644 index 0000000000..e69de29bb2 diff --git a/documentation/docs/pages/operators/nodes/nym-node/configuration.mdx b/documentation/docs/pages/operators/nodes/nym-node/configuration.mdx index dbe24c5072..f1ab9af05e 100644 --- a/documentation/docs/pages/operators/nodes/nym-node/configuration.mdx +++ b/documentation/docs/pages/operators/nodes/nym-node/configuration.mdx @@ -6,12 +6,12 @@ import { AccordionTemplate } from 'components/accordion-template.tsx'; import ExitPolicyInstallOutput from 'components/operators/snippets/wg-exit-policy-install-output.mdx'; import ExitPolicyStatusOutput from 'components/operators/snippets/wg-exit-policy-status-output.mdx'; import ExitPolicyTestOutput from 'components/operators/snippets/wg-exit-policy-test-output.mdx'; -import ExitPolicyTestServer from 'components/operators/snippets/wg-exit-policy-testing-from-server.mdx'; -import ExitPolicyTestOutside from 'components/operators/snippets/wg-exit-policy-testing-from-outside.mdx'; +import WGExitPolicyConf from 'components/operators/snippets/wg-exit-policy-conf.mdx'; +import WGExitPolicyTest from 'components/operators/snippets/wg-exit-policy-test.mdx'; +import RoutingConf from 'components/operators/snippets/routing-conf.mdx'; import QuicDeploymentSteps from 'components/operators/snippets/quic-bridge-deployment-script-setup.mdx'; - -export const ManagerIPOutput = () => ( +Export const ManagerIPOutput = () => (
Correct ./network_tunnel_manager.sh fetch_and_display_ipv6 output
@@ -275,265 +275,15 @@ Make sure to keep your IPv4 address enabled while setting up IPv6, as the majori ### Routing Configuration -While we're working on Rust implementation to have these settings as a part of the binary build, to solve these connectivity requirements in the meantime we wrote a script [`network_tunnel_manager.sh`](https://github.com/nymtech/nym/blob/develop/scripts/network_tunnel_manager.sh) to support operators to configure their servers and address all the connectivity requirements. - -Networking configuration across different ISPs and various operation systems does not have a generic solution. If the provided configuration setup doesn't solve your problem check out [IPv6 troubleshooting](../../troubleshooting/vps-isp.mdx#ipv6-troubleshooting) page. Be aware that you may have to do more research, customised adjustments or contact your ISP to change settings for your VPS. - -The `nymtun0` interface is dynamically managed by the `exit-gateway` service. When the service is stopped, `nymtun0` disappears, and when started, `nymtun0` is recreated. - -The `nymwg` interface is used for creating a secure wireguard tunnel as part of the Nym Network configuration. Similar to `nymtun0`, the script manages iptables rules specific to `nymwg` to ensure proper routing and forwarding through the wireguard tunnel. The `nymwg` interface needs to be correctly configured and active for the related commands to function properly. This includes applying or removing iptables rules and running connectivity tests through the `nymwg` tunnel. - -The script should be used in a context where `nym-node` is running to fully utilise its capabilities, particularly for fetching IPv6 addresses or applying network rules that depend on the `nymtun0` and `nymwg` interfaces and to establish a WireGuard tunnel. - -**Before starting with the following configuration, make sure you have the [latest `nym-node` binary](https://github.com/nymtech/nym/releases) installed and your [VPS setup](../preliminary-steps/vps-setup.mdx) finished properly!** - - - -###### 1. Download `network_tunnel_manager.sh`, make executable and run: - -```sh -curl -L https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/network_tunnel_manager.sh -o network_tunnel_manager.sh && \ -chmod +x network_tunnel_manager.sh && \ -./network_tunnel_manager.sh -``` - -###### 2. Make sure your `nym-node` service is up and running and bond - -- **If you setting up a new node and not upgrading an existing one, keep it running and [bond](bonding.mdx) your node now**. Then come back here and follow the rest of the configuration. - - -**Run the following steps as root or with `sudo` prefix!** - - - -###### 3. Setup IP tables rules - -- Delete IP tables rules for IPv4 and IPv6 and apply new ones: -```sh -./network_tunnel_manager.sh remove_duplicate_rules nymtun0 - -./network_tunnel_manager.sh apply_iptables_rules -``` - -- The process may prompt you if you want to save current IPv4 and IPv6 rules, choose yes. - -![](/images/operators/ip_table_prompt.png) - -- At this point you should see a `global ipv6` address. -```sh -./network_tunnel_manager.sh fetch_and_display_ipv6 -``` -
-}> -```sh -iptables-persistent is already installed. -Using IPv6 address: 2001:db8:a160::1/112 #the address will be different for you -operation fetch_ipv6_address_nym_tun completed successfully. -``` - - -###### 4. Check Nymtun IP tables: - -```sh -./network_tunnel_manager.sh check_nymtun_iptables -``` - -- If there's no process running it wouldn't return anything. -- In case you see `nymtun0` but not active, this is probably because you are setting up a new (never bonded) node and not upgrading an existing one. - -
-}> -```sh -iptables-persistent is already installed. -network Device: eth0 ---------------------------------------- - -inspecting IPv4 firewall rules... -Chain FORWARD (policy DROP 0 packets, 0 bytes) - 0 0 ufw-reject-forward all -- * * 0.0.0.0/0 0.0.0.0/0 - 0 0 ACCEPT all -- nymtun0 eth0 0.0.0.0/0 0.0.0.0/0 - 0 0 ACCEPT all -- eth0 nymtun0 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED - 0 0 ACCEPT all -- nymtun0 eth0 0.0.0.0/0 0.0.0.0/0 - 0 0 ACCEPT all -- eth0 nymtun0 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED - 0 0 ACCEPT all -- nymtun0 eth0 0.0.0.0/0 0.0.0.0/0 - 0 0 ACCEPT all -- eth0 nymtun0 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED ---------------------------------------- - -inspecting IPv6 firewall rules... -Chain FORWARD (policy DROP 0 packets, 0 bytes) - 0 0 ufw6-reject-forward all * * ::/0 ::/0 - 0 0 ACCEPT all eth0 nymtun0 ::/0 ::/0 state RELATED,ESTABLISHED - 0 0 ACCEPT all nymtun0 eth0 ::/0 ::/0 - 0 0 ACCEPT all eth0 nymtun0 ::/0 ::/0 state RELATED,ESTABLISHED - 0 0 ACCEPT all nymtun0 eth0 ::/0 ::/0 - 0 0 ACCEPT all eth0 nymtun0 ::/0 ::/0 state RELATED,ESTABLISHED - 0 0 ACCEPT all nymtun0 eth0 ::/0 ::/0 -operation check_nymtun_iptables completed successfully. -``` - - -###### 5. Remove old and apply new rules for wireguad routing - -```sh -./network_tunnel_manager.sh remove_duplicate_rules nymwg - -./network_tunnel_manager.sh apply_iptables_rules_wg -``` - -###### 6. Apply rules to configure DNS routing and allow ICMP piung test for node probing (network testing) - -```sh -./network_tunnel_manager.sh configure_dns_and_icmp_wg -``` -###### 7. Adjust and validate IP forwarding - -```sh -./network_tunnel_manager.sh adjust_ip_forwarding - -./network_tunnel_manager.sh check_ipv6_ipv4_forwarding -``` - -###### 8. Check `nymtun0` interface and test routing configuration - -```sh -ip addr show nymtun0 -``` - -
-}> -```sh -# your addresses will be different -8: nymtun0: mtu 1420 qdisc fq_codel state UNKNOWN group default qlen 500 - link/none - inet 10.0.0.1/16 scope global nymtun0 - valid_lft forever preferred_lft forever - inet6 fc00::1/112 scope global - valid_lft forever preferred_lft forever - inet6 fe80::ad08:d167:5700:8c7c/64 scope link stable-privacy - valid_lft forever preferred_lft forever` -``` - - -- Validate your IPv6 and IPv4 networking by running a joke test via Mixnet: -```sh -./network_tunnel_manager.sh joke_through_the_mixnet -``` - -- Validate your tunneling by running a joke test via WG: -```sh -./network_tunnel_manager.sh joke_through_wg_tunnel -``` - -- **Note:** WireGuard will return only IPv4 joke, not IPv6. WG IPv6 is under development. Running IPR joke through the mixnet with `./network_tunnel_manager.sh joke_through_the_mixnet` should work with both IPv4 and IPv6! - - -###### 9. Enable wireguard - -Now you can run your node with the `--wireguard-enabled true` flag or add it to your [systemd service config](#systemd). Restart your `nym-node` or [systemd](#2-following-steps-for-nym-nodes-running-as-systemd-service) service (recommended): - -```sh -systemctl daemon-reload && service nym-node restart -``` -- Optionally, you can check if the node is running correctly by monitoring the service logs: - -```sh -journalctl -u nym-node.service -f -n 100 -``` -
- -Make sure that you get the validation of all connectivity. If there are still any problems, please refer to [troubleshooting section](../../troubleshooting/vps-isp.mdx#incorrect-gateway-network-check). + ## Wireguard Exit Policy Configuration -Nym Node running as Exit Gateway has contains multiple modules, one of them is Nym Network Requester(NR), routing TCP traffic to the internet. To make sure that the node is not just an open proxy, NR checks agains [Nym exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) following these conditions (in this exact order): - -1. Do we explicitly block those IP addresses regardless of ports? -2. Do we allow those specific ports regardless of IPs? -3. Do block EVERYTHING else! - -The exit policy is same for all NRs, the content is shaped by an offchain governance of Nym Node operators on our [forum](https://forum.nym.com/t/poll-a-new-nym-exit-policy-for-exit-gateways-and-the-nym-mixnet-is-inbound/464). - -There is a caveat though. NR is only routing TCP streams and therefore any other type of routing is *not* filtered thorugh the exit policy. To ensure that Nym Nodes follow the same exit policy when routing IP packets through wireguard and don't act as open proxies, the operators have to set up these rules via IP tables rules. - -**Follow these steps, using a [setup script](https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh) and [testing scripts](https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/wireguard-exit-policy/exit-policy-tests.sh) written by Nym quality assurance team, to setup exit policy for wireguard:** - - - -###### 1. Download the scripts and make executable - -- SSH to your node -- Create a folder `~/nym-binaries` and navigate there -```sh -mkdir $HOME/nym-binaries -cd $HOME/nym-binaries -``` -- Download the scripts -```sh -wget https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh - -wget https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/wireguard-exit-policy/exit-policy-tests.sh -``` -- Make executable -```sh -chmod +x wireguard-exit-policy-manager.sh exit-policy-tests.sh -``` - -###### 2. Install `wireguard-exit-policy-manager.sh` -```sh -./wireguard-exit-policy-manager.sh install -``` -- The output should look like this: - - - - - -###### 3. Run `wireguard-exit-policy-manager.sh` -```sh -./wireguard-exit-policy-manager.sh status -``` - -- The output should look like this: - - - - -###### 4. Test with `exit-policy-tests.sh` - -```sh -./exit-policy-tests.sh -``` - -- The output should look like this: - - - - -###### 5. In case of problems, you can clear the exit policy rule -```sh -./wireguard-exit-policy-manager.sh clear - -./wireguard-exit-policy-manager.sh status -``` - - -Now your wireguart routing should have same rotuing permissions like [Nym exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) used on 5-hop (Mixnet) mode of NymVPN. + ### Testing Wireguard Exit Policy -You can validate the application of the IP tables routes on your `nym-node` by checking it from the server side as well as from the outside. - -
- From the server, - From the outside - using NymVPN - ]} defaultIndex={0}> - - - -
- -Your node has successfully implemented wireguard exit policy with the same routing permissions like [Nym exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) used on 5-hop (Mixnet). + ## QUIC Transport Bridge Deployment From 45a1074377edd7f93af1c57ce76e7135cb71d051 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Wed, 19 Nov 2025 17:35:33 +0100 Subject: [PATCH 103/134] remove redundant --- .../operators/snippets/routing-conf.mdx | 30 ++++++++++++++----- .../nyx-outputs/nyx-percent-stake.md | 2 +- .../nyx-outputs/nyx-total-stake.md | 2 +- .../outputs/api-scraping-outputs/time-now.md | 2 +- .../nodes/nym-node/configuration.mdx | 16 ---------- 5 files changed, 25 insertions(+), 27 deletions(-) diff --git a/documentation/docs/components/operators/snippets/routing-conf.mdx b/documentation/docs/components/operators/snippets/routing-conf.mdx index acb73b084d..9910043512 100644 --- a/documentation/docs/components/operators/snippets/routing-conf.mdx +++ b/documentation/docs/components/operators/snippets/routing-conf.mdx @@ -1,9 +1,26 @@ import { Callout } from 'nextra/components'; import { Tabs } from 'nextra/components'; -import { VarInfo } from 'components/variable-info.tsx'; import { Steps } from 'nextra/components'; import { AccordionTemplate } from 'components/accordion-template.tsx'; +export const ManagerIPOutput = () => ( +
+ Correct ./network-tunnel-manager.sh fetch_and_display_ipv6 output +
+); + +export const ManagerTablesOutput = () => ( +
+ Correct ./network-tunnel-manager.sh check_nymtun_iptables output +
+); + +export const ShowTun = () => ( +
+ Correct ip addr show nymtun0 output +
+); + We're working on Rust implementation agregating all routing settings into a binary, to solve all connectivity configuration requirements. In the meantime node operators need to use the [`network_tunnel_manager.sh`](https://github.com/nymtech/nym/blob/develop/scripts/network_tunnel_manager.sh) as a handy support to configure their servers. @@ -28,20 +45,18 @@ Networking configuration across different ISPs and various operation systems doe * Testing and validating all above -The script should be used in a context where `nym-node` is running to fully utilise its capabilities, particularly for fetching IPv6 addresses or applying network rules that depend on the `nymtun0` and `nymwg` interfaces and to establish a WireGuard tunnel. - **Before starting with the following configuration, make sure you have the [latest `nym-node` binary](https://github.com/nymtech/nym/releases) installed and your [VPS setup](../preliminary-steps/vps-setup.mdx) finished properly!** **Run the following steps as root!** - + -|**Choose configuration command according your setup** +**Choose configuration command according your setup**
New nym-node Full Configuration, - Existing nym-node Full Configuration + New nym-node Full Configuration, + Existing nym-node Full Configuration, Step-by-step or Partial Configuration ]} defaultIndex={0}> @@ -67,7 +82,6 @@ chmod +x network-tunnel-manager.sh && \ - This is meant for operators configuring an existing and bonded node and it will result with a complete server readiness for routing as Entry Gateway and Exit Gateway in both Mixnet and WireGuard mode. diff --git a/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/nyx-percent-stake.md b/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/nyx-percent-stake.md index 069e6eb141..858227b92a 100644 --- a/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/nyx-percent-stake.md +++ b/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/nyx-percent-stake.md @@ -1 +1 @@ -0.77% +0.79% diff --git a/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/nyx-total-stake.md b/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/nyx-total-stake.md index 486924e832..6c69256b94 100644 --- a/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/nyx-total-stake.md +++ b/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/nyx-total-stake.md @@ -1 +1 @@ -37.305 +36.446 diff --git a/documentation/docs/components/outputs/api-scraping-outputs/time-now.md b/documentation/docs/components/outputs/api-scraping-outputs/time-now.md index 3351fa154b..8e492903cb 100644 --- a/documentation/docs/components/outputs/api-scraping-outputs/time-now.md +++ b/documentation/docs/components/outputs/api-scraping-outputs/time-now.md @@ -1 +1 @@ -Monday, November 10th 2025, 13:30:27 UTC +Wednesday, November 19th 2025, 16:17:05 UTC diff --git a/documentation/docs/pages/operators/nodes/nym-node/configuration.mdx b/documentation/docs/pages/operators/nodes/nym-node/configuration.mdx index f1ab9af05e..e8a824d287 100644 --- a/documentation/docs/pages/operators/nodes/nym-node/configuration.mdx +++ b/documentation/docs/pages/operators/nodes/nym-node/configuration.mdx @@ -11,23 +11,7 @@ import WGExitPolicyTest from 'components/operators/snippets/wg-exit-policy-test. import RoutingConf from 'components/operators/snippets/routing-conf.mdx'; import QuicDeploymentSteps from 'components/operators/snippets/quic-bridge-deployment-script-setup.mdx'; -Export const ManagerIPOutput = () => ( -
- Correct ./network_tunnel_manager.sh fetch_and_display_ipv6 output -
-); -export const ManagerTablesOutput = () => ( -
- Correct ./network_tunnel_manager.sh check_nymtun_iptables output -
-); - -export const ShowTun = () => ( -
- Correct ip addr show nymtun0 output -
-); From 37e3a101b177de071be05a0506084b3fd406d96c Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Wed, 19 Nov 2025 17:41:35 +0100 Subject: [PATCH 104/134] fix routing test --- .../operators/snippets/routing-conf.mdx | 9 +++++++ .../nodes/nym-node/configuration.mdx | 25 +++++-------------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/documentation/docs/components/operators/snippets/routing-conf.mdx b/documentation/docs/components/operators/snippets/routing-conf.mdx index 9910043512..12549970f6 100644 --- a/documentation/docs/components/operators/snippets/routing-conf.mdx +++ b/documentation/docs/components/operators/snippets/routing-conf.mdx @@ -21,6 +21,15 @@ export const ShowTun = () => (
); + + +We recommend operators to configure their `nym-node` with the full routing configuration. + +However, most of the time the packets sent through the Mixnet are IPv4 based. The IPv6 packets are still pretty rare and therefore it's not mandatory from operational point of view to have this configuration implemented if you running only `mixnode` mode. + +If you preparing to run a `nym-node` with all modes enabled in the future, this setup is required. + + We're working on Rust implementation agregating all routing settings into a binary, to solve all connectivity configuration requirements. In the meantime node operators need to use the [`network_tunnel_manager.sh`](https://github.com/nymtech/nym/blob/develop/scripts/network_tunnel_manager.sh) as a handy support to configure their servers. diff --git a/documentation/docs/pages/operators/nodes/nym-node/configuration.mdx b/documentation/docs/pages/operators/nodes/nym-node/configuration.mdx index e8a824d287..af8bfdf590 100644 --- a/documentation/docs/pages/operators/nodes/nym-node/configuration.mdx +++ b/documentation/docs/pages/operators/nodes/nym-node/configuration.mdx @@ -206,9 +206,13 @@ This lets your operating system know it's ok to reload the service configuration
-## Connectivity Test and Configuration +## Routing Configuration -During our ongoing testing events we found out, that after introducing IP Packet Router (IPR) and [Nym exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) on embedded Network Requester (NR) by default, only a fragment of Gateways routes correctly through IPv4 and IPv6. We built a useful monitor to check out your Gateway (`nym-node --mode exit-gateway`) at [harbourmaster.nymtech.net](https://harbourmaster.nymtech.net/). + + +## Routing Validation & Test + +### Quick IPv6 Check IPv6 routing is not only a case for gateways. Imagine a rare occasion when you run a `mixnode` without IPv6 enabled and a client will sent IPv6 packets through the Mixnet through such route: ```ascii @@ -216,19 +220,6 @@ IPv6 routing is not only a case for gateways. Imagine a rare occasion when you r ``` In this (unusual) case your `mixnode` will not be able to route the packets. The node will drop the packets and its performance would go down. For that reason it's beneficial to have IPv6 enabled when running a `mixnode` functionality. - -We recommend operators to configure their `nym-node` with the full routing configuration. - -However, most of the time the packets sent through the Mixnet are IPv4 based. The IPv6 packets are still pretty rare and therefore it's not mandatory from operational point of view to have this configuration implemented if you running only `mixnode` mode. - -If you preparing to run a `nym-node` with all modes enabled in the future, this setup is required. - - - -For everyone participating in Delegation Program or Service Grant program, this setup is a requirement! - - -### Quick IPv6 Check You can always check IPv6 address and connectivity by using some of these methods:
@@ -257,10 +248,6 @@ telnet -6 ipv6.telnetmyip.com Make sure to keep your IPv4 address enabled while setting up IPv6, as the majority of routing goes through that one!
-### Routing Configuration - - - ## Wireguard Exit Policy Configuration From b4544c2b48916d8be44d401ee05e2644abd7bafc Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 20 Nov 2025 13:17:40 +0100 Subject: [PATCH 105/134] wg exit policy setup --- .../snippets/wg-exit-policy-conf.mdx | 69 +++++++++++++++++++ .../nodes/nym-node/configuration.mdx | 7 -- 2 files changed, 69 insertions(+), 7 deletions(-) diff --git a/documentation/docs/components/operators/snippets/wg-exit-policy-conf.mdx b/documentation/docs/components/operators/snippets/wg-exit-policy-conf.mdx index e69de29bb2..1c99f69e6d 100644 --- a/documentation/docs/components/operators/snippets/wg-exit-policy-conf.mdx +++ b/documentation/docs/components/operators/snippets/wg-exit-policy-conf.mdx @@ -0,0 +1,69 @@ +import { Callout } from 'nextra/components'; +import { Tabs } from 'nextra/components'; +import { Steps } from 'nextra/components'; +import { AccordionTemplate } from 'components/accordion-template.tsx'; +import ExitPolicyInstallOutput from 'components/operators/snippets/wg-exit-policy-install-output.mdx'; +import ExitPolicyStatusOutput from 'components/operators/snippets/wg-exit-policy-status-output.mdx'; + + +**In case you had used `network-tunnel-manager.sh` with the command `complete_networking_setup`, your WireGuard exit policy is already setup. You can test it in the next chapter.** + + +Nym Node running as Exit Gateway has contains multiple modules, one of them is Nym Network Requester(NR), routing TCP traffic to the internet. To make sure that the node is not just an open proxy, NR checks agains [Nym exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) following these conditions (in this exact order): + +1. Do we explicitly block those IP addresses regardless of ports? +2. Do we allow those specific ports regardless of IPs? +3. Do block EVERYTHING else! + +The exit policy is same for all NRs, the content is shaped by an offchain governance of Nym Node operators on our [forum](https://forum.nym.com/t/poll-a-new-nym-exit-policy-for-exit-gateways-and-the-nym-mixnet-is-inbound/464). + +There is a caveat though. NR is only routing TCP streams and therefore any other type of routing than Mixnet is *not* filtered thorugh the exit policy. To ensure that Nym Nodes follow the same exit policy when routing IP packets through WireGuard and don't act as open proxies, the operators have to set up these rules via IP tables rules. + +**For all routing configuration we provide one tool [`network-tunnel-manager.sh` (NTM)](https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh). This tool manages WireGuard exit policy as well.** + +In case you haven't run `network-tunnel-manager.sh` with the command `complete_networking_setup` you need to use NTM for WireGuard exit policy configuration. + +**Folow these steps** + + +**Run the following steps as root!** + + + + +###### 1. Download `network-tunnel-manager.sh`, make executable and run with `--help` command: + +```sh +curl -L https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/nym-node-setup/network-tunnel-manager.sh -o network-tunnel-manager.sh && \ +chmod +x network-tunnel-manager.sh && \ +./network-tunnel-manager.sh --help +``` + +###### 2. Install exit policy + +- Clear old rules and configure new ones: +```sh +./network-tunnel-manager.sh exit_policy_clear +./network-tunnel-manager.sh exit_policy_install +``` +- The output should look like this: + + + + + +###### 3. Check status of your configuration +```sh +./network-tunnel-manager.sh exit_policy_status +``` + +- The output should look like this: + + + +``` + + +Now your WireGuard routing (2-hop) should have same rotuing permissions like [Nym exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) used on 5-hop (Mixnet) mode of NymVPN. + + diff --git a/documentation/docs/pages/operators/nodes/nym-node/configuration.mdx b/documentation/docs/pages/operators/nodes/nym-node/configuration.mdx index af8bfdf590..bd5e1319b3 100644 --- a/documentation/docs/pages/operators/nodes/nym-node/configuration.mdx +++ b/documentation/docs/pages/operators/nodes/nym-node/configuration.mdx @@ -3,18 +3,11 @@ import { Tabs } from 'nextra/components'; import { VarInfo } from 'components/variable-info.tsx'; import { Steps } from 'nextra/components'; import { AccordionTemplate } from 'components/accordion-template.tsx'; -import ExitPolicyInstallOutput from 'components/operators/snippets/wg-exit-policy-install-output.mdx'; -import ExitPolicyStatusOutput from 'components/operators/snippets/wg-exit-policy-status-output.mdx'; -import ExitPolicyTestOutput from 'components/operators/snippets/wg-exit-policy-test-output.mdx'; import WGExitPolicyConf from 'components/operators/snippets/wg-exit-policy-conf.mdx'; import WGExitPolicyTest from 'components/operators/snippets/wg-exit-policy-test.mdx'; import RoutingConf from 'components/operators/snippets/routing-conf.mdx'; import QuicDeploymentSteps from 'components/operators/snippets/quic-bridge-deployment-script-setup.mdx'; - - - - # Nym Node Configuration From 78fb7790102ca485ab22a4dd0b81d146c505db7a Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 20 Nov 2025 13:33:06 +0100 Subject: [PATCH 106/134] write wg exit policy testing steps --- .../snippets/wg-exit-policy-test.mdx | 39 +++++++++++++++++++ .../wg-exit-policy-testing-from-outside.mdx | 24 +++++++++++- .../wg-exit-policy-testing-from-server.mdx | 34 ++++++++++++++-- 3 files changed, 92 insertions(+), 5 deletions(-) diff --git a/documentation/docs/components/operators/snippets/wg-exit-policy-test.mdx b/documentation/docs/components/operators/snippets/wg-exit-policy-test.mdx index e69de29bb2..f8a25006f3 100644 --- a/documentation/docs/components/operators/snippets/wg-exit-policy-test.mdx +++ b/documentation/docs/components/operators/snippets/wg-exit-policy-test.mdx @@ -0,0 +1,39 @@ +import { Tabs } from 'nextra/components'; +import { Steps } from 'nextra/components'; + +import ExitPolicyTestServer from 'components/operators/snippets/wg-exit-policy-testing-from-server.mdx'; +import ExitPolicyTestOutside from 'components/operators/snippets/wg-exit-policy-testing-from-outside.mdx'; + +**For all routing configuration we provide one tool [`network-tunnel-manager.sh` (NTM)](https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/wireguard-exit-policy/wireguard-exit-policy-manager.sh). This tool manages WireGuard tests all configurations, including WireGuard exit policy as well.** + + +You can use NTM to validate the application of the IP tables routes on your `nym-node` by checking it from the server side as well as from the outside. + +
+ From the server, + From the outside - using NymVPN + ]} defaultIndex={0}> + + + +
+ + +If all works , your node has successfully implemented WireGuard exit policy with the same routing permissions like [Nym exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) used on 5-hop (Mixnet) for TCP routing. + + + + + + + + + + + + + + + + diff --git a/documentation/docs/components/operators/snippets/wg-exit-policy-testing-from-outside.mdx b/documentation/docs/components/operators/snippets/wg-exit-policy-testing-from-outside.mdx index ebc11c315c..35b61745db 100644 --- a/documentation/docs/components/operators/snippets/wg-exit-policy-testing-from-outside.mdx +++ b/documentation/docs/components/operators/snippets/wg-exit-policy-testing-from-outside.mdx @@ -1,9 +1,29 @@ +import { Steps } from 'nextra/components'; + +Here are a few ways you can ensre your WireGuard exit policy is working correctly from the outside. + + + +###### 1. Using NymVPN + +- Connect to NymVPN and use your node as an Exit Gateway in dVPN (2-hop) mode + +- While connected to NymVPN, navigate to [`portquiz.net:12345`](http://portquiz.net:12345) and see if you can load the page + +- It shouldn't load, but if you navigate to some of the accepted ports, like[`portquiz.net:443`](http://portquiz.net:443) it should all work + +###### 2. Test it from your local terminal + - Install these dependencies on your local machine: ```shell sudo apt install tcpdump sudo tcpdump -i nymwg -n ``` -- Connect to [NymVPN](https://nym.com) and select your node as an Exit Gateway (after running the exit policy [manager script](#wireguard-exit-policy-configuration)) +- Connect to [NymVPN](https://nym.com) and select your node as an Exit Gateway + - Run the `tcpdump` command before registering -- Have the output of the `echo $BLOCKED_IP` from your node and try to go into your browser or a registered client and try to connect - It will not resolve. + +- Have the output of the `echo $BLOCKED_IP` from your node and try to go into your browser or a registered client and try to connect - It should not resolve + + \ No newline at end of file diff --git a/documentation/docs/components/operators/snippets/wg-exit-policy-testing-from-server.mdx b/documentation/docs/components/operators/snippets/wg-exit-policy-testing-from-server.mdx index 02fe54adfa..501dcc3876 100644 --- a/documentation/docs/components/operators/snippets/wg-exit-policy-testing-from-server.mdx +++ b/documentation/docs/components/operators/snippets/wg-exit-policy-testing-from-server.mdx @@ -1,11 +1,39 @@ -Run this command to define variable `BLOCKED_IP` and try to `ping` it: +import { Steps } from 'nextra/components'; +import { AccordionTemplate } from 'components/accordion-template.tsx'; +import ExitPolicyTestOutput from 'components/operators/snippets/wg-exit-policy-test-output.mdx'; + + + + +###### 1. Make sure to have the latest NTM: +```sh +curl -L https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/nym-node-setup/network-tunnel-manager.sh -o network-tunnel-manager.sh && \ +chmod +x network-tunnel-manager.sh && \ +./network-tunnel-manager.sh --help +``` + +###### 2. Run tests with NTM +```sh +./network-tunnel-manager.sh exit_policy_test_connectivity +./network-tunnel-manager.sh exit_policy_tests +``` + +- The output should look like this: + + + + +###### 3. Optionally you can do some manual sanity checks +- Run this command to define variable `BLOCKED_IP` and try to `ping` it: ```shell BLOCKED_IP=$(grep "ExitPolicy reject" /etc/nym/exit-policy.txt | head -1 | sed -E 's/ExitPolicy reject ([^:]+):.*/\1/' | sed 's/\/.*$//') ping -c 3 $BLOCKED_IP ``` -You should see `100% packet loss` as an outcome. +- You should see `100% packet loss` as an outcome. ```shell telnet $BLOCKED_IP 80 ``` -You should see `telnet: Unable to connect to remote host: Connection timed out`. +- You should see `telnet: Unable to connect to remote host: Connection timed out`. + + \ No newline at end of file From dcfd0f77ad39b353e7dfe6a00f91775e7e65ebd4 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 20 Nov 2025 13:39:11 +0100 Subject: [PATCH 107/134] debug trace ticks --- .../docs/components/operators/snippets/wg-exit-policy-conf.mdx | 1 - .../docs/components/outputs/api-scraping-outputs/time-now.md | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/documentation/docs/components/operators/snippets/wg-exit-policy-conf.mdx b/documentation/docs/components/operators/snippets/wg-exit-policy-conf.mdx index 1c99f69e6d..7d5ebf3de7 100644 --- a/documentation/docs/components/operators/snippets/wg-exit-policy-conf.mdx +++ b/documentation/docs/components/operators/snippets/wg-exit-policy-conf.mdx @@ -61,7 +61,6 @@ chmod +x network-tunnel-manager.sh && \ -``` Now your WireGuard routing (2-hop) should have same rotuing permissions like [Nym exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) used on 5-hop (Mixnet) mode of NymVPN. diff --git a/documentation/docs/components/outputs/api-scraping-outputs/time-now.md b/documentation/docs/components/outputs/api-scraping-outputs/time-now.md index 8e492903cb..bfd8731655 100644 --- a/documentation/docs/components/outputs/api-scraping-outputs/time-now.md +++ b/documentation/docs/components/outputs/api-scraping-outputs/time-now.md @@ -1 +1 @@ -Wednesday, November 19th 2025, 16:17:05 UTC +Thursday, November 20th 2025, 12:33:19 UTC From 47c6006bb7ac4285bdf262076585e14c367807c0 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 20 Nov 2025 13:52:41 +0100 Subject: [PATCH 108/134] ready to merge back --- .../components/operators/snippets/routing-conf.mdx | 10 +++------- .../snippets/wg-exit-policy-testing-from-outside.mdx | 2 +- .../pages/operators/nodes/nym-node/configuration.mdx | 2 -- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/documentation/docs/components/operators/snippets/routing-conf.mdx b/documentation/docs/components/operators/snippets/routing-conf.mdx index 12549970f6..ebb33e5ba9 100644 --- a/documentation/docs/components/operators/snippets/routing-conf.mdx +++ b/documentation/docs/components/operators/snippets/routing-conf.mdx @@ -30,10 +30,6 @@ However, most of the time the packets sent through the Mixnet are IPv4 based. Th If you preparing to run a `nym-node` with all modes enabled in the future, this setup is required.
- -We're working on Rust implementation agregating all routing settings into a binary, to solve all connectivity configuration requirements. In the meantime node operators need to use the [`network_tunnel_manager.sh`](https://github.com/nymtech/nym/blob/develop/scripts/network_tunnel_manager.sh) as a handy support to configure their servers. - - Networking configuration across different ISPs and various operation systems does not have a generic solution. If the provided configuration setup doesn't solve your problem check out [IPv6 troubleshooting](/operators/troubleshooting/vps-isp.mdx#ipv6-troubleshooting) page. Be aware that you may have to do more research, customised adjustments or contact your ISP to change settings for your VPS. @@ -64,9 +60,9 @@ Networking configuration across different ISPs and various operation systems doe
New nym-node Full Configuration, - Existing nym-node Full Configuration, - Step-by-step or Partial Configuration + New nym-node full configuration, + Existing nym-node full configuration, + Step-by-step or Pprtial configuration ]} defaultIndex={0}> This design is meant for operators setting up a new node on a fresh machine and it will result with a complete server readiness for routing as Entry Gateway and Exit Gateway in both Mixnet and WireGuard mode. diff --git a/documentation/docs/components/operators/snippets/wg-exit-policy-testing-from-outside.mdx b/documentation/docs/components/operators/snippets/wg-exit-policy-testing-from-outside.mdx index 35b61745db..349a7cd2de 100644 --- a/documentation/docs/components/operators/snippets/wg-exit-policy-testing-from-outside.mdx +++ b/documentation/docs/components/operators/snippets/wg-exit-policy-testing-from-outside.mdx @@ -12,7 +12,7 @@ Here are a few ways you can ensre your WireGuard exit policy is working correctl - It shouldn't load, but if you navigate to some of the accepted ports, like[`portquiz.net:443`](http://portquiz.net:443) it should all work -###### 2. Test it from your local terminal +###### 2. Testing from your local terminal - Install these dependencies on your local machine: ```shell diff --git a/documentation/docs/pages/operators/nodes/nym-node/configuration.mdx b/documentation/docs/pages/operators/nodes/nym-node/configuration.mdx index bd5e1319b3..d791e7f946 100644 --- a/documentation/docs/pages/operators/nodes/nym-node/configuration.mdx +++ b/documentation/docs/pages/operators/nodes/nym-node/configuration.mdx @@ -203,8 +203,6 @@ This lets your operating system know it's ok to reload the service configuration -## Routing Validation & Test - ### Quick IPv6 Check IPv6 routing is not only a case for gateways. Imagine a rare occasion when you run a `mixnode` without IPv6 enabled and a client will sent IPv6 packets through the Mixnet through such route: From 4e7b4715b08f0afd1bf37986ec61d6d380a47a38 Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Thu, 20 Nov 2025 14:37:46 +0100 Subject: [PATCH 109/134] / test failed echo text --- scripts/nym-node-setup/network-tunnel-manager.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index c03ada3a08..66db28a570 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -960,7 +960,7 @@ exit_policy_run_tests() { ((total += 1)) fi - info "tests run: $total, failures: $failed" + echo "tests run: $total, test failed: $failed" if [[ $failed -eq 0 ]]; then ok "all exit policy tests passed" else From 752c7915b3acccbaf139dd9cc8e53688544422cf Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Thu, 20 Nov 2025 14:47:41 +0100 Subject: [PATCH 110/134] + colors for check the firewall setup --- .../nym-node-setup/network-tunnel-manager.sh | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index ee1e3a7555..b4e6fdfb35 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -829,16 +829,16 @@ check_forward_chain() { output=$(iptables -L FORWARD -n --line-numbers) if ! echo "$output" | grep -q "^1[[:space:]]\+$NYM_CHAIN"; then - echo "FORWARD rule 1 is not ${NYM_CHAIN}; re-run network-tunnel-manager.sh exit_policy_install" + error "FORWARD rule 1 is not ${NYM_CHAIN}; re-run network-tunnel-manager.sh exit_policy_install" return 1 fi if ! echo "$output" | grep -q "ACCEPT.*state RELATED,ESTABLISHED"; then - echo "FORWARD chain missing RELATED,ESTABLISHED accepts; re-run network-tunnel-manager.sh apply_iptables_rules_wg" + error "FORWARD chain missing RELATED,ESTABLISHED accepts; re-run network-tunnel-manager.sh apply_iptables_rules_wg" return 1 fi - echo "FORWARD chain ordering looks good" + ok "FORWARD chain ordering looks good" return 0 } @@ -850,9 +850,9 @@ check_nym_exit_chain() { local line line=$(firewall_rule_line "$NYM_CHAIN" $((idx + 1))) if [[ "$line" =~ ${patterns[$idx]} ]]; then - echo "${NYM_CHAIN} rule $((idx + 1)) ok (${patterns[$idx]})" + ok "${NYM_CHAIN} rule $((idx + 1)) ok (${patterns[$idx]})" else - echo "${NYM_CHAIN} rule $((idx + 1)) is not ${patterns[$idx]}; re-run network-tunnel-manager.sh exit_policy_install" + error "${NYM_CHAIN} rule $((idx + 1)) is not ${patterns[$idx]}; re-run network-tunnel-manager.sh exit_policy_install" errors=1 fi done @@ -860,12 +860,12 @@ check_nym_exit_chain() { local last_rule last_rule=$(iptables -L "$NYM_CHAIN" -n --line-numbers | awk 'NR>2 {line=$0} END {print line}') if [[ -z "${last_rule:-}" ]]; then - echo "${NYM_CHAIN} chain is empty; re-run network-tunnel-manager.sh exit_policy_install" + error "${NYM_CHAIN} chain is empty; re-run network-tunnel-manager.sh exit_policy_install" errors=1 elif [[ "$last_rule" =~ REJECT ]] && [[ "$last_rule" =~ 0\.0\.0\.0/0 ]]; then - echo "${NYM_CHAIN} ends with the catch-all REJECT" + ok "${NYM_CHAIN} ends with the catch-all REJECT" else - echo "${NYM_CHAIN} final rule is not the catch-all REJECT (got: $last_rule)" + error "${NYM_CHAIN} final rule is not the catch-all REJECT (got: $last_rule)" errors=1 fi @@ -873,28 +873,28 @@ check_nym_exit_chain() { } check_firewall_setup() { - echo "checking ipv4 firewall ordering…" + info "checking ipv4 firewall ordering…" local errors=0 check_forward_chain || errors=1 check_nym_exit_chain || errors=1 if command -v ip6tables >/dev/null 2>&1; then - echo "checking ipv6 firewall ordering…" + info "checking ipv6 firewall ordering…" if ip6tables -L "$NYM_CHAIN" -n --line-numbers >/dev/null 2>&1; then if ! ip6tables -L "$NYM_CHAIN" -n --line-numbers | sed -n '3p' | grep -q "udp.*dpt:53"; then - echo "ip6tables ${NYM_CHAIN} rule 1 is not UDP 53" + error "ip6tables ${NYM_CHAIN} rule 1 is not UDP 53" errors=1 fi fi fi if [[ $errors -ne 0 ]]; then - echo "There may be some ordering issues, it is recommended to re-run network-tunnel-manager.sh exit_policy_install after configuring UFW." + error "There may be some ordering issues, it is recommended to re-run network-tunnel-manager.sh exit_policy_install after configuring UFW." return 1 fi - echo "It's looking good!" + ok "It's looking good!" return 0 } From 18d271f4811a7536055cfcc9774a95164275cc99 Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Thu, 20 Nov 2025 15:47:59 +0100 Subject: [PATCH 111/134] + colors test_exit_policy_connectivity --- .../nym-node-setup/network-tunnel-manager.sh | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index b4e6fdfb35..08a70dccbb 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -770,46 +770,46 @@ show_exit_policy_status() { } test_exit_policy_connectivity() { - echo "testing connectivity through $WG_INTERFACE" + info "testing connectivity through $WG_INTERFACE" local iface_info iface_info=$(ip link show "$WG_INTERFACE" 2>/dev/null || true) if [[ -z "$iface_info" ]]; then - echo "interface $WG_INTERFACE not found" + error "interface $WG_INTERFACE not found" return 1 fi - echo "interface:" - echo "$iface_info" + ok "interface:" + ok "$iface_info" local ipv4_address ipv6_address ipv4_address=$(ip -4 addr show dev "$WG_INTERFACE" | awk '/inet / {print $2}' | cut -d'/' -f1 | head -n1) ipv6_address=$(ip -6 addr show dev "$WG_INTERFACE" scope global | awk '/inet6/ {print $2}' | cut -d'/' -f1 | head -n1) - echo "ipv4 address: ${ipv4_address:-none}" - echo "ipv6 address: ${ipv6_address:-none}" + ok "ipv4 address: ${ipv4_address:-none}" + ok "ipv6 address: ${ipv6_address:-none}" if [[ -n "$ipv4_address" ]]; then - echo "testing ipv4 ping to 8.8.8.8" + info "testing ipv4 ping to 8.8.8.8" timeout 5 ping -c 3 -I "$ipv4_address" 8.8.8.8 >/dev/null 2>&1 && \ - echo "ipv4 ping ok" || echo "ipv4 ping failed" + ok "ipv4 ping ok" || error "ipv4 ping failed" - echo "testing ipv4 dns resolution" + info "testing ipv4 dns resolution" timeout 5 ping -c 3 -I "$ipv4_address" google.com >/dev/null 2>&1 && \ - echo "ipv4 dns ok" || echo "ipv4 dns failed" + ok "ipv4 dns ok" || error "ipv4 dns failed" fi if [[ -n "$ipv6_address" ]]; then - echo "testing ipv6 ping to google dns" + info "testing ipv6 ping to google dns" timeout 5 ping6 -c 3 -I "$ipv6_address" 2001:4860:4860::8888 >/dev/null 2>&1 && \ - echo "ipv6 ping ok" || echo "ipv6 ping failed" + ok "ipv6 ping ok" || error "ipv6 ping failed" - echo "testing ipv6 dns resolution" + info "testing ipv6 dns resolution" timeout 5 ping6 -c 3 -I "$ipv6_address" google.com >/dev/null 2>&1 && \ - echo "ipv6 dns ok" || echo "ipv6 dns failed" + ok "ipv6 dns ok" || error "ipv6 dns failed" fi - echo "connectivity tests finished" + info "connectivity tests finished" } From 7b96adf7a81121a60b28ce3ec63800fff305bd1a Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Thu, 20 Nov 2025 16:04:22 +0100 Subject: [PATCH 112/134] / refactor help section --- .../nym-node-setup/network-tunnel-manager.sh | 53 +++++++++---------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 08a70dccbb..abe0c1a804 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -1212,42 +1212,41 @@ case "$cmd" in usage: $0 [args] high level workflows: - full_tunnel_setup run tunnel iptables and checks for nymtun0 and nymwg - exit_policy_install install and configure wireguard exit policy - complete_networking_configuration run tunnel setup, exit policy install and tests + complete_networking_configuration Run tunnel setup, exit policy install and tests + exit_policy_install Install and configure wireguard exit policy + full_tunnel_setup Run tunnel iptables and checks for nymtun0 and nymwg tunnel and nat helpers: - fetch_ipv6_address_nym_tun show global ipv6 address on ${TUNNEL_INTERFACE} - fetch_and_display_ipv6 show ipv6 on uplink ${NETWORK_DEVICE} - apply_iptables_rules apply nat/forward rules for ${TUNNEL_INTERFACE} - apply_iptables_rules_wg apply nat/forward rules for ${WG_INTERFACE} - check_nymtun_iptables inspect forward chain for ${TUNNEL_INTERFACE} - check_nym_wg_tun inspect forward chain for ${WG_INTERFACE} - check_ipv6_ipv4_forwarding show ipv4/ipv6 forwarding flags - check_ip_routing show ipv4 and ipv6 routes - perform_pings test ipv4 and ipv6 pings - joke_through_the_mixnet test via ${TUNNEL_INTERFACE} with joke - joke_through_wg_tunnel test via ${WG_INTERFACE} with joke - configure_dns_and_icmp_wg allow ping and dns on this host - adjust_ip_forwarding enable ipv4/ipv6 forwarding via sysctl.d - remove_duplicate_rules deduplicate rules for interface in FORWARD and ${NYM_CHAIN} + adjust_ip_forwarding Enable ipv4/ipv6 forwarding via sysctl.d + apply_iptables_rules Apply nat/forward rules for ${TUNNEL_INTERFACE} + apply_iptables_rules_wg Apply nat/forward rules for ${WG_INTERFACE} + check_ip_routing Show ipv4 and ipv6 routes + check_ipv6_ipv4_forwarding Show ipv4/ipv6 forwarding flags + check_nym_wg_tun Inspect forward chain for ${WG_INTERFACE} + check_nymtun_iptables Inspect forward chain for ${TUNNEL_INTERFACE} + configure_dns_and_icmp_wg Allow ping and dns ports on this host + fetch_and_display_ipv6 Show ipv6 on uplink ${NETWORK_DEVICE} + fetch_ipv6_address_nym_tun Show global ipv6 address on ${TUNNEL_INTERFACE} + joke_through_the_mixnet Test via ${TUNNEL_INTERFACE} with joke + joke_through_wg_tunnel Test via ${WG_INTERFACE} with joke + perform_pings Test ipv4 and ipv6 pings + remove_duplicate_rules Deduplicate FORWARD and ${NYM_CHAIN} rules for (required). exit policy manager: - exit_policy_install install exit policy (iptables rules and blocklist) - check_firewall_setup run ordering sanity check (dns/icmp + FORWARD jump) - exit_policy_status show status of exit policy and forwarding - exit_policy_test_connectivity test connectivity via ${WG_INTERFACE} - exit_policy_clear remove ${NYM_CHAIN} chains and hooks + check_firewall_setup Run ordering sanity check (dns/icmp + FORWARD jump) + exit_policy_clear Remove ${NYM_CHAIN} chains and hooks + exit_policy_install Install exit policy (iptables rules and blocklist) + exit_policy_status Show status of exit policy and forwarding + exit_policy_test_connectivity Test connectivity via ${WG_INTERFACE} exit_policy_tests [--skip-default-reject] - run verification tests on exit policy + Run verification tests on exit policy (options: --skip-default-reject). environment overrides: - TUNNEL_INTERFACE default nymtun0 - WG_INTERFACE default nymwg - NETWORK_DEVICE uplink device, auto-detected if not set + NETWORK_DEVICE Auto-detected uplink (e.g., eth0). Set manually if detection fails. + TUNNEL_INTERFACE Default: nymtun0. Requires root privileges (sudo) to manage. + WG_INTERFACE Default: nymwg - Must match your WireGuard interface name. EOF - status=0 ;; *) From 9b076197b1c7604b381a1e4f0ebb619ad63ecae7 Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Thu, 20 Nov 2025 16:04:22 +0100 Subject: [PATCH 113/134] / refactor help section --- .../nym-node-setup/network-tunnel-manager.sh | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 7017adbd4d..2096fd836b 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -1103,41 +1103,41 @@ case "$cmd" in usage: $0 [args] high level workflows: - full_tunnel_setup run tunnel iptables and checks for nymtun0 and nymwg - exit_policy_install install and configure wireguard exit policy - complete_networking_configuration run tunnel setup, exit policy install and tests + complete_networking_configuration Run tunnel setup, exit policy install and tests + exit_policy_install Install and configure wireguard exit policy + full_tunnel_setup Run tunnel iptables and checks for nymtun0 and nymwg tunnel and nat helpers: - fetch_ipv6_address_nym_tun show global ipv6 address on ${TUNNEL_INTERFACE} - fetch_and_display_ipv6 show ipv6 on uplink ${NETWORK_DEVICE} - apply_iptables_rules apply nat/forward rules for ${TUNNEL_INTERFACE} - apply_iptables_rules_wg apply nat/forward rules for ${WG_INTERFACE} - check_nymtun_iptables inspect forward chain for ${TUNNEL_INTERFACE} - check_nym_wg_tun inspect forward chain for ${WG_INTERFACE} - check_ipv6_ipv4_forwarding show ipv4/ipv6 forwarding flags - check_ip_routing show ipv4 and ipv6 routes - perform_pings test ipv4 and ipv6 pings - joke_through_the_mixnet test via ${TUNNEL_INTERFACE} with joke - joke_through_wg_tunnel test via ${WG_INTERFACE} with joke - configure_dns_and_icmp_wg allow ping and dns on this host - adjust_ip_forwarding enable ipv4/ipv6 forwarding via sysctl.d - remove_duplicate_rules deduplicate rules for interface in FORWARD and ${NYM_CHAIN} + adjust_ip_forwarding Enable ipv4/ipv6 forwarding via sysctl.d + apply_iptables_rules Apply nat/forward rules for ${TUNNEL_INTERFACE} + apply_iptables_rules_wg Apply nat/forward rules for ${WG_INTERFACE} + check_ip_routing Show ipv4 and ipv6 routes + check_ipv6_ipv4_forwarding Show ipv4/ipv6 forwarding flags + check_nym_wg_tun Inspect forward chain for ${WG_INTERFACE} + check_nymtun_iptables Inspect forward chain for ${TUNNEL_INTERFACE} + configure_dns_and_icmp_wg Allow ping and dns ports on this host + fetch_and_display_ipv6 Show ipv6 on uplink ${NETWORK_DEVICE} + fetch_ipv6_address_nym_tun Show global ipv6 address on ${TUNNEL_INTERFACE} + joke_through_the_mixnet Test via ${TUNNEL_INTERFACE} with joke + joke_through_wg_tunnel Test via ${WG_INTERFACE} with joke + perform_pings Test ipv4 and ipv6 pings + remove_duplicate_rules Deduplicate FORWARD and ${NYM_CHAIN} rules for (required). exit policy manager: - exit_policy_install install exit policy (iptables rules and blocklist) - exit_policy_status show status of exit policy and forwarding - exit_policy_test_connectivity test connectivity via ${WG_INTERFACE} - exit_policy_clear remove ${NYM_CHAIN} chains and hooks + check_firewall_setup Run ordering sanity check (dns/icmp + FORWARD jump) + exit_policy_clear Remove ${NYM_CHAIN} chains and hooks + exit_policy_install Install exit policy (iptables rules and blocklist) + exit_policy_status Show status of exit policy and forwarding + exit_policy_test_connectivity Test connectivity via ${WG_INTERFACE} exit_policy_tests [--skip-default-reject] - run verification tests on exit policy + Run verification tests on exit policy (options: --skip-default-reject). environment overrides: - TUNNEL_INTERFACE default nymtun0 - WG_INTERFACE default nymwg - NETWORK_DEVICE uplink device, auto-detected if not set + NETWORK_DEVICE Auto-detected uplink (e.g., eth0). Set manually if detection fails. + TUNNEL_INTERFACE Default: nymtun0. Requires root privileges (sudo) to manage. + WG_INTERFACE Default: nymwg - Must match your WireGuard interface name. EOF - status=0 ;; *) From 50d768976fba54a80f078a5e9dea6eb67c014d73 Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Thu, 20 Nov 2025 16:20:15 +0100 Subject: [PATCH 114/134] end status of help --- scripts/nym-node-setup/network-tunnel-manager.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index abe0c1a804..38215258c6 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -1247,6 +1247,7 @@ environment overrides: WG_INTERFACE Default: nymwg - Must match your WireGuard interface name. EOF + status=0 ;; *) @@ -1256,7 +1257,7 @@ EOF ;; esac -if [ "${status:-1}" -eq 0 ]; then +if [[ "$cmd" != help && "$cmd" != "--help" && "$cmd" != "-h" && ${status:-1} -eq 0 ]]; then echo "operation ${cmd} completed" fi exit $status From f9e2311574630d5b3eb6e5abdf5c9bf498784157 Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Thu, 20 Nov 2025 16:20:15 +0100 Subject: [PATCH 115/134] end status of help --- scripts/nym-node-setup/network-tunnel-manager.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 2096fd836b..bd97153db1 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -1138,6 +1138,7 @@ environment overrides: WG_INTERFACE Default: nymwg - Must match your WireGuard interface name. EOF + status=0 ;; *) @@ -1147,7 +1148,7 @@ EOF ;; esac -if [ "${status:-1}" -eq 0 ]; then +if [[ "$cmd" != help && "$cmd" != "--help" && "$cmd" != "-h" && ${status:-1} -eq 0 ]]; then echo "operation ${cmd} completed" fi exit $status From bb5b43492a34f82ed7428a4b404b73d42771a13b Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Thu, 20 Nov 2025 16:28:05 +0100 Subject: [PATCH 116/134] + colors show_exit_policy_status --- .../nym-node-setup/network-tunnel-manager.sh | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 38215258c6..72cbf927c7 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -740,31 +740,31 @@ clear_exit_policy_rules() { } show_exit_policy_status() { - echo "nym exit policy status" - echo "network device: $NETWORK_DEVICE" - echo "wireguard interface: $WG_INTERFACE" + info "nym exit policy status" + info "network device: ${NC}$NETWORK_DEVICE" + info "wireguard interface: ${NC}$WG_INTERFACE" echo if ! ip link show "$WG_INTERFACE" >/dev/null 2>&1; then - echo "warning: wireguard interface $WG_INTERFACE not found" + error "warning: wireguard interface $WG_INTERFACE not found" else - echo "interface details:" + info "interface details:" ip link show "$WG_INTERFACE" echo - echo "ipv4 addresses:" + info "ipv4 addresses:" ip -4 addr show dev "$WG_INTERFACE" echo - echo "ipv6 addresses:" + info "ipv6 addresses:" ip -6 addr show dev "$WG_INTERFACE" fi echo - echo "iptables chains for ${NYM_CHAIN}:" + info "iptables chains for ${NYM_CHAIN}:" iptables -L "$NYM_CHAIN" -n -v 2>/dev/null || echo "ipv4 chain not found" echo ip6tables -L "$NYM_CHAIN" -n -v 2>/dev/null || echo "ipv6 chain not found" echo - echo "ip forwarding:" + info "ip forwarding:" echo "ipv4: $(cat /proc/sys/net/ipv4/ip_forward 2>/dev/null || echo 0)" echo "ipv6: $(cat /proc/sys/net/ipv6/conf/all/forwarding 2>/dev/null || echo 0)" } @@ -1251,13 +1251,13 @@ EOF ;; *) - echo "unknown command: $cmd" - echo "run with 'help' for usage" + error "unknown command: $cmd" + info "run with 'help' for usage" exit 1 ;; esac if [[ "$cmd" != help && "$cmd" != "--help" && "$cmd" != "-h" && ${status:-1} -eq 0 ]]; then - echo "operation ${cmd} completed" + ok "operation ${cmd} completed" fi exit $status From a488a1b4899316f9af6a6868ce8da4f6b9a4f510 Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Thu, 20 Nov 2025 16:50:05 +0100 Subject: [PATCH 117/134] / color fixes --- .../nym-node-setup/network-tunnel-manager.sh | 158 +++++++++--------- 1 file changed, 77 insertions(+), 81 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 72cbf927c7..3d047b7601 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -95,16 +95,16 @@ ensure_jq() { install_iptables_persistent() { if ! dpkg -s iptables-persistent >/dev/null 2>&1; then - echo -e "${YELLOW}installing iptables-persistent${NC}" + info "installing iptables-persistent" apt-get update -y DEBIAN_FRONTEND=noninteractive apt-get install -y iptables-persistent else - echo -e "${GREEN}iptables-persistent is already installed${NC}" + ok "iptables-persistent is already installed" fi } adjust_ip_forwarding() { - echo -e "${YELLOW}configuring ip forwarding via /etc/sysctl.d/99-nym-forwarding.conf${NC}" + info "configuring ip forwarding via /etc/sysctl.d/99-nym-forwarding.conf" install -m 0644 /dev/null /etc/sysctl.d/99-nym-forwarding.conf cat > /etc/sysctl.d/99-nym-forwarding.conf </dev/null || echo 0) if [[ "$v4" == "1" && "$v6" == "1" ]]; then - echo -e "${GREEN}ipv4 and ipv6 forwarding enabled${NC}" + ok "ipv4 and ipv6 forwarding enabled" else - echo -e "${RED}warning: ip forwarding not fully enabled (ipv4=$v4 ipv6=$v6)${NC}" + error "warning: ip forwarding not fully enabled (ipv4=$v4 ipv6=$v6)" fi } save_iptables_rules() { - echo -e "${YELLOW}saving iptables rules to /etc/iptables${NC}" + info "saving iptables rules to /etc/iptables$" mkdir -p /etc/iptables iptables-save > /etc/iptables/rules.v4 ip6tables-save > /etc/iptables/rules.v6 - echo -e "${GREEN}iptables rules saved${NC}" + ok "iptables rules saved" } ############################################################################### @@ -141,10 +141,10 @@ fetch_ipv6_address() { ipv6_global_address=$(ip -6 addr show "$interface" scope global | awk '/inet6/ {print $2}' | head -n 1) if [[ -z "$ipv6_global_address" ]]; then - echo "no globally routable ipv6 address found on $interface. please configure ipv6 or check your network settings" + error "no globally routable ipv6 address found on $interface. please configure ipv6 or check your network settings" exit 1 else - echo "using ipv6 address: $ipv6_global_address" + info "using ipv6 address: $ipv6_global_address" fi } @@ -152,9 +152,9 @@ fetch_and_display_ipv6() { local ipv6_address ipv6_address=$(ip -6 addr show "$NETWORK_DEVICE" scope global | awk '/inet6/ {print $2}') if [[ -z "$ipv6_address" ]]; then - echo "no global ipv6 address found on $NETWORK_DEVICE" + error "no global ipv6 address found on $NETWORK_DEVICE" else - echo "ipv6 address on $NETWORK_DEVICE: $ipv6_address" + ok "ipv6 address on $NETWORK_DEVICE: $ipv6_address" fi } @@ -165,11 +165,11 @@ remove_duplicate_rules() { local interface="$1" if [[ -z "$interface" ]]; then - echo "Error: No interface specified. Usage: $0 remove_duplicate_rules " + error "Error: No interface specified. Usage: $0 remove_duplicate_rules " exit 1 fi - echo "detecting and removing duplicate rules for $interface in FORWARD and ${NYM_CHAIN}" + info "detecting and removing duplicate rules for $interface in FORWARD and ${NYM_CHAIN}" # # ipv4 @@ -178,7 +178,7 @@ remove_duplicate_rules() { rules_v4=$(iptables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep -F -- "$interface" || true) if [[ -n "$rules_v4" ]]; then - echo "processing ipv4 rules" + info "processing ipv4 rules" local tmp4 tmp4=$(mktemp) @@ -192,7 +192,7 @@ remove_duplicate_rules() { count=$(printf "%s\n" "$rules_v4" | grep -F -- "$rule" | wc -l) if [[ "$count" -gt 1 ]]; then - echo "removing $((count - 1)) duplicate(s) of ipv4 rule: $rule" + info "removing $((count - 1)) duplicate(s) of ipv4 rule: $rule" for ((i=1; i/dev/null || \ - echo "warning: failed deleting ipv4 duplicate via index ($chain $index)" + error "warning: failed deleting ipv4 duplicate via index ($chain $index)" else - echo "warning: unable to locate ipv4 duplicate index for: $rule" + error "warning: unable to locate ipv4 duplicate index for: $rule" fi else - echo "warning: could not reliably match ipv4 duplicate rule: $rule" + error "warning: could not reliably match ipv4 duplicate rule: $rule" fi done fi @@ -228,7 +228,7 @@ remove_duplicate_rules() { rm -f "$tmp4" else - echo "no ipv4 rules found for $interface to deduplicate" + ok "no ipv4 rules found for $interface to deduplicate" fi @@ -240,7 +240,7 @@ remove_duplicate_rules() { rules_v6=$(ip6tables-save | grep -E "(-A FORWARD|-A $NYM_CHAIN)" | grep -F -- "$interface" || true) if [[ -n "$rules_v6" ]]; then - echo "processing ipv6 rules" + info "processing ipv6 rules" local tmp6 tmp6=$(mktemp) @@ -254,7 +254,7 @@ remove_duplicate_rules() { count=$(printf "%s\n" "$rules_v6" | grep -F -- "$rule" | wc -l) if [[ "$count" -gt 1 ]]; then - echo "removing $((count - 1)) duplicate(s) of ipv6 rule: $rule" + info "removing $((count - 1)) duplicate(s) of ipv6 rule: $rule" for ((i=1; i/dev/null || \ - echo "warning: failed deleting ipv6 duplicate via index ($chain $index)" + error "warning: failed deleting ipv6 duplicate via index ($chain $index)" else - echo "warning: unable to locate ipv6 duplicate index for: $rule" + error "warning: unable to locate ipv6 duplicate index for: $rule" fi else - echo "warning: could not match ipv6 duplicate rule reliably: $rule" + error "warning: could not match ipv6 duplicate rule reliably: $rule" fi done fi @@ -291,15 +291,15 @@ remove_duplicate_rules() { rm -f "$tmp6" else - echo "no ipv6 rules found for $interface to deduplicate" + error "no ipv6 rules found for $interface to deduplicate" fi - echo "duplicate rule scan completed for $interface" + ok "duplicate rule scan completed for $interface" } apply_iptables_rules() { local interface=$1 - echo "applying iptables rules for $interface using uplink $NETWORK_DEVICE" + info "applying iptables rules for $interface using uplink $NETWORK_DEVICE" sleep 1 # ipv4 nat and forwarding @@ -327,11 +327,11 @@ apply_iptables_rules() { check_tunnel_iptables() { local interface=$1 - echo "inspecting iptables rules for $interface" - echo "ipv4 forward chain:" + info "inspecting iptables rules for $interface" + info "ipv4 forward chain:" iptables -L FORWARD -v -n | awk -v dev="$interface" '/^Chain FORWARD/ || $0 ~ dev || $0 ~ "ufw-reject-forward"' echo - echo "ipv6 forward chain:" + info "ipv6 forward chain:" ip6tables -L FORWARD -v -n | awk -v dev="$interface" '/^Chain FORWARD/ || $0 ~ dev || $0 ~ "ufw6-reject-forward"' } @@ -339,100 +339,96 @@ check_ipv6_ipv4_forwarding() { local result_ipv4 result_ipv6 result_ipv4=$(cat /proc/sys/net/ipv4/ip_forward) result_ipv6=$(cat /proc/sys/net/ipv6/conf/all/forwarding) - echo "ipv4 forwarding is $([ "$result_ipv4" == "1" ] && echo enabled || echo not enabled)" - echo "ipv6 forwarding is $([ "$result_ipv6" == "1" ] && echo enabled || echo not enabled)" + ok "ipv4 forwarding is $([ "$result_ipv4" == "1" ] && ok enabled || error not enabled)" + ok "ipv6 forwarding is $([ "$result_ipv6" == "1" ] && ok enabled || error not enabled)" } check_ip_routing() { - echo "ipv4 routing table:" + info "ipv4 routing table:" ip route - echo "---------------------------" - echo "ipv6 routing table:" + info "---------------------------" + info "ipv6 routing table:" ip -6 route } perform_pings() { - echo "performing ipv4 ping to google.com" - ping -c 4 google.com || echo "ipv4 ping failed" + info "performing ipv4 ping to google.com" + ping -c 4 google.com || error "ipv4 ping failed" echo "---------------------------" - echo "performing ipv6 ping to google.com" - ping6 -c 4 google.com || echo "ipv6 ping failed" + info "performing ipv6 ping to google.com" + ping6 -c 4 google.com || error "ipv6 ping failed" } joke_through_tunnel() { ensure_jq local interface=$1 - local green="\033[0;32m" - local reset="\033[0m" - local red="\033[0;31m" - local yellow="\033[0;33m" sleep 1 echo - echo -e "${yellow}checking tunnel connectivity and fetching a joke for $interface${reset}" - echo -e "${yellow}if this test succeeds, it confirms your machine can reach the outside world via ipv4 and ipv6${reset}" - echo -e "${yellow}probes and external clients may still see different connectivity to your nym node${reset}" + info "checking tunnel connectivity and fetching a joke for $interface" + info "if this test succeeds, it confirms your machine can reach the outside world via ipv4 and ipv6" + info "probes and external clients may still see different connectivity to your nym node" local ipv4_address ipv6_address joke ipv4_address=$(ip addr show "$interface" | awk '/inet / {print $2}' | cut -d'/' -f1) ipv6_address=$(ip addr show "$interface" | awk '/inet6 / && $2 !~ /^fe80/ {print $2}' | cut -d'/' -f1) if [[ -z "$ipv4_address" && -z "$ipv6_address" ]]; then - echo -e "${red}no ip address found on $interface. unable to fetch a joke${reset}" - echo -e "${red}please verify your tunnel configuration and ensure the interface is up${reset}" + error "no ip address found on $interface. unable to fetch a joke" + error "please verify your tunnel configuration and ensure the interface is up" return 1 fi if [[ -n "$ipv4_address" ]]; then echo echo "------------------------------------" - echo "detected ipv4 address: $ipv4_address" - echo "testing ipv4 connectivity" + info "detected ipv4 address: $ipv4_address" + info "testing ipv4 connectivity" echo if ping -c 1 -I "$ipv4_address" google.com >/dev/null 2>&1; then - echo -e "${green}ipv4 connectivity is working. fetching a joke${reset}" + ok "ipv4 connectivity is working. fetching a joke" joke=$(curl -s -H "Accept: application/json" --interface "$ipv4_address" https://icanhazdadjoke.com/ | jq -r .joke) - [[ -n "$joke" && "$joke" != "null" ]] && echo -e "${green}ipv4 joke: $joke${reset}" || echo "failed to fetch a joke via ipv4" + [[ -n "$joke" && "$joke" != "null" ]] && ok "ipv4 joke: $joke" || echo "failed to fetch a joke via ipv4" else - echo -e "${red}ipv4 connectivity is not working for $interface. verify your routing and nat settings${reset}" + error "ipv4 connectivity is not working for $interface. verify your routing and nat settings" fi else - echo -e "${red}no ipv4 address found on $interface. unable to fetch a joke via ipv4${reset}" + error "no ipv4 address found on $interface. unable to fetch a joke via ipv4" fi if [[ -n "$ipv6_address" ]]; then echo echo "------------------------------------" - echo "detected ipv6 address: $ipv6_address" - echo "testing ipv6 connectivity" + info "detected ipv6 address: $ipv6_address" + info "testing ipv6 connectivity" echo if ping6 -c 1 -I "$ipv6_address" google.com >/dev/null 2>&1; then - echo -e "${green}ipv6 connectivity is working. fetching a joke${reset}" + ok "ipv6 connectivity is working. fetching a joke" joke=$(curl -s -H "Accept: application/json" --interface "$ipv6_address" https://icanhazdadjoke.com/ | jq -r .joke) - [[ -n "$joke" && "$joke" != "null" ]] && echo -e "${green}ipv6 joke: $joke${reset}" || echo -e "${red}failed to fetch a joke via ipv6${reset}" + [[ -n "$joke" && "$joke" != "null" ]] && ok "ipv6 joke: $joke" || error "failed to fetch a joke via ipv6" else - echo -e "${red}ipv6 connectivity is not working for $interface. verify your routing and nat settings${reset}" + error "ipv6 connectivity is not working for $interface. verify your routing and nat settings" fi else - echo -e "${red}no ipv6 address found on $interface. unable to fetch a joke via ipv6${reset}" + error "no ipv6 address found on $interface. unable to fetch a joke via ipv6" fi - echo -e "${green}joke fetching processes completed for $interface${reset}" + ok "joke fetching processes completed for $interface" echo "------------------------------------" sleep 3 echo echo - echo -e "${yellow}connectivity testing recommendations${reset}" - echo -e "${yellow}- from another machine use wscat to test websocket connectivity on 9001${reset}" - echo -e "${yellow}- test udp connectivity on port 51822 (wireguard)${reset}" - echo -e "${yellow}- example: echo 'test' | nc -u 51822${reset}" + info "connectivity testing recommendations" + info "- from another machine use wscat to test websocket connectivity on 9001" + info "- test udp connectivity on port 51822 (wireguard)" + info "- example: echo 'test' | nc -u 51822" } configure_dns_and_icmp_wg() { - echo "allowing ping (icmp) and dns on this host" + info "allowing ping (icmp) and dns on this host" iptables -C INPUT -p icmp --icmp-type echo-request -j ACCEPT 2>/dev/null || \ iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -C OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 2>/dev/null || \ @@ -444,7 +440,7 @@ configure_dns_and_icmp_wg() { iptables -A INPUT -p tcp --dport 53 -j ACCEPT save_iptables_rules - echo "dns and icmp configuration completed" + ok "dns and icmp configuration completed" } ############################################################################### @@ -463,12 +459,12 @@ add_port_rules() { if ! $cmd -C "$NYM_CHAIN" -p "$protocol" --dport "$start_port:$end_port" -j ACCEPT 2>/dev/null; then $cmd -A "$NYM_CHAIN" -p "$protocol" --dport "$start_port:$end_port" -j ACCEPT - echo "added $cmd $NYM_CHAIN $protocol port range $start_port:$end_port" + ok "added $cmd $NYM_CHAIN $protocol port range $start_port:$end_port" fi else if ! $cmd -C "$NYM_CHAIN" -p "$protocol" --dport "$port" -j ACCEPT 2>/dev/null; then $cmd -A "$NYM_CHAIN" -p "$protocol" --dport "$port" -j ACCEPT - echo "added $cmd $NYM_CHAIN $protocol port $port" + ok "added $cmd $NYM_CHAIN $protocol port $port" fi fi } @@ -478,14 +474,14 @@ exit_policy_install_deps() { for cmd in iptables ip6tables ip grep sed awk wget curl; do if ! command -v "$cmd" >/dev/null 2>&1; then - echo "installing dependency: $cmd" + info "installing dependency: $cmd" apt-get install -y "$cmd" fi done } create_nym_chain() { - echo "creating nym exit policy chain $NYM_CHAIN" + info "creating nym exit policy chain $NYM_CHAIN" if iptables -L "$NYM_CHAIN" >/dev/null 2>&1; then iptables -F "$NYM_CHAIN" @@ -509,7 +505,7 @@ create_nym_chain() { } setup_nat_rules() { - echo "setting up nat and forwarding rules for $WG_INTERFACE via $NETWORK_DEVICE" + info "setting up nat and forwarding rules for $WG_INTERFACE via $NETWORK_DEVICE" if ! iptables -t nat -C POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE 2>/dev/null; then iptables -t nat -A POSTROUTING -o "$NETWORK_DEVICE" -j MASQUERADE @@ -534,7 +530,7 @@ setup_nat_rules() { } configure_exit_dns_and_icmp() { - echo "ensuring dns and icmp are allowed inside nym exit chain" + info "ensuring dns and icmp are allowed inside nym exit chain" # Remove any existing DNS/ICMP rules first to avoid duplicates iptables -D "$NYM_CHAIN" -p udp --dport 53 -j ACCEPT 2>/dev/null || true @@ -727,7 +723,7 @@ add_default_reject_rule() { } clear_exit_policy_rules() { - echo "clearing nym exit policy rules" + info "clearing nym exit policy rules ..." iptables -F "$NYM_CHAIN" 2>/dev/null || true ip6tables -F "$NYM_CHAIN" 2>/dev/null || true @@ -741,8 +737,8 @@ clear_exit_policy_rules() { show_exit_policy_status() { info "nym exit policy status" - info "network device: ${NC}$NETWORK_DEVICE" - info "wireguard interface: ${NC}$WG_INTERFACE" + info "network device: $NETWORK_DEVICE" + info "wireguard interface: $WG_INTERFACE" echo if ! ip link show "$WG_INTERFACE" >/dev/null 2>&1; then @@ -790,26 +786,26 @@ test_exit_policy_connectivity() { ok "ipv6 address: ${ipv6_address:-none}" if [[ -n "$ipv4_address" ]]; then - info "testing ipv4 ping to 8.8.8.8" + echo -e "${NC}testing ipv4 ping to 8.8.8.8 ..." timeout 5 ping -c 3 -I "$ipv4_address" 8.8.8.8 >/dev/null 2>&1 && \ ok "ipv4 ping ok" || error "ipv4 ping failed" - info "testing ipv4 dns resolution" + echo -e "${NC}testing ipv4 dns resolution ..." timeout 5 ping -c 3 -I "$ipv4_address" google.com >/dev/null 2>&1 && \ ok "ipv4 dns ok" || error "ipv4 dns failed" fi if [[ -n "$ipv6_address" ]]; then - info "testing ipv6 ping to google dns" + echo -e "${NC}testing ipv6 ping to google dns ..." timeout 5 ping6 -c 3 -I "$ipv6_address" 2001:4860:4860::8888 >/dev/null 2>&1 && \ ok "ipv6 ping ok" || error "ipv6 ping failed" - info "testing ipv6 dns resolution" + echo -e "${NC}testing ipv6 dns resolution ..." timeout 5 ping6 -c 3 -I "$ipv6_address" google.com >/dev/null 2>&1 && \ ok "ipv6 dns ok" || error "ipv6 dns failed" fi - info "connectivity tests finished" + ok "connectivity tests finished" } From ef7974fde97927bc26cafc4d8765d57b88c915c4 Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Thu, 20 Nov 2025 17:29:42 +0100 Subject: [PATCH 118/134] / otpimize create_nym_chain --- scripts/nym-node-setup/network-tunnel-manager.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 3d047b7601..41b9c3c7f2 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -483,13 +483,13 @@ exit_policy_install_deps() { create_nym_chain() { info "creating nym exit policy chain $NYM_CHAIN" - if iptables -L "$NYM_CHAIN" >/dev/null 2>&1; then + if iptables -S "$NYM_CHAIN" >/dev/null 2>&1; then iptables -F "$NYM_CHAIN" else iptables -N "$NYM_CHAIN" fi - if ip6tables -L "$NYM_CHAIN" >/dev/null 2>&1; then + if ip6tables -S "$NYM_CHAIN" >/dev/null 2>&1; then ip6tables -F "$NYM_CHAIN" else ip6tables -N "$NYM_CHAIN" From 76993a9b940405237c930cb3e767d016ee2ea8d8 Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Thu, 20 Nov 2025 17:36:27 +0100 Subject: [PATCH 119/134] / colors --- scripts/nym-node-setup/network-tunnel-manager.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 41b9c3c7f2..ca68f1593c 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -657,12 +657,12 @@ apply_port_allowlist() { } apply_spamhaus_blocklist() { - echo "applying spamhaus-like blocklist from $EXIT_POLICY_LOCATION" + info "applying spamhaus-like blocklist from $EXIT_POLICY_LOCATION" mkdir -p "$(dirname "$POLICY_FILE")" if ! wget -q "$EXIT_POLICY_LOCATION" -O "$POLICY_FILE" 2>/dev/null; then - echo "failed to download exit policy, using minimal blocklist" + arror "failed to download exit policy, using minimal blocklist" cat >"$POLICY_FILE" </dev/null; then iptables -A "$NYM_CHAIN" -d "$ip_range" -j REJECT --reject-with icmp-port-unreachable \ - || echo "warning: failed adding ipv4 reject for $ip_range" + || error "warning: failed adding ipv4 reject for $ip_range" fi # ipv6 reject if [[ "$ip_range" == *":"* ]]; then if ! ip6tables -C "$NYM_CHAIN" -d "$ip_range" -j REJECT 2>/dev/null; then ip6tables -A "$NYM_CHAIN" -d "$ip_range" -j REJECT \ - || echo "warning: failed adding ipv6 reject for $ip_range" + || error "warning: failed adding ipv6 reject for $ip_range" fi fi @@ -711,7 +711,7 @@ EOF add_default_reject_rule() { - echo "ensuring default reject rule at end of ${NYM_CHAIN}" + info "ensuring default reject rule at end of ${NYM_CHAIN}" iptables -D "$NYM_CHAIN" -j REJECT 2>/dev/null || true iptables -D "$NYM_CHAIN" -j REJECT --reject-with icmp-port-unreachable 2>/dev/null || true @@ -1038,7 +1038,7 @@ exit_policy_run_tests() { ((total += 1)) fi - echo "tests run: $total, test failed: $failed" + info "tests run: ${GREEN}$total${YELLOW}, test failed: ${RED}$failed${NC}" if [[ $failed -eq 0 ]]; then ok "all exit policy tests passed" else From 6170ca2a1413c58b570bef66e1e8f508570040cd Mon Sep 17 00:00:00 2001 From: import this <97586125+serinko@users.noreply.github.com> Date: Fri, 21 Nov 2025 11:04:48 +0000 Subject: [PATCH 120/134] Update time-now.md From 6d63ba1f4cafff42ec7e60b0af3e43680a40f454 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Fri, 21 Nov 2025 12:17:50 +0100 Subject: [PATCH 121/134] menu fix --- scripts/nym-node-setup/network-tunnel-manager.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index ca68f1593c..3072110181 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -1208,9 +1208,9 @@ case "$cmd" in usage: $0 [args] high level workflows: - complete_networking_configuration Run tunnel setup, exit policy install and tests + complete_networking_configuration Install tunnel interfaces, setup networking, iptables & wg exit policy exit_policy_install Install and configure wireguard exit policy - full_tunnel_setup Run tunnel iptables and checks for nymtun0 and nymwg + full_tunnel_setup Install tunnel interfaces & setup networking tunnel and nat helpers: adjust_ip_forwarding Enable ipv4/ipv6 forwarding via sysctl.d From 52f98de73b571748054f4b4013f1f0e5bbb337c8 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Fri, 21 Nov 2025 12:40:24 +0100 Subject: [PATCH 122/134] simplify --- scripts/nym-node-setup/network-tunnel-manager.sh | 2 +- scripts/nym-node-setup/nym-node-cli.py | 16 ++-------------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 3072110181..3d60cc5bfb 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -1208,7 +1208,7 @@ case "$cmd" in usage: $0 [args] high level workflows: - complete_networking_configuration Install tunnel interfaces, setup networking, iptables & wg exit policy + complete_networking_configuration Install tunnel interfaces, setup networking, iptables, wg exit policy & tests exit_policy_install Install and configure wireguard exit policy full_tunnel_setup Install tunnel interfaces & setup networking diff --git a/scripts/nym-node-setup/nym-node-cli.py b/scripts/nym-node-setup/nym-node-cli.py index def82b1d17..9d99fc4ad0 100755 --- a/scripts/nym-node-setup/nym-node-cli.py +++ b/scripts/nym-node-setup/nym-node-cli.py @@ -345,25 +345,13 @@ class NodeSetupCLI: """A standalone fn to pass full cmd list needed for correct setup and test network tunneling, using an external script""" print( "\n* * * Setting up network configuration for mixnet IP router and Wireguard tunneling * * *" - "\nMore info: https://nym.com/docs/operators/nodes/nym-node/configuration#1-download-network_tunnel_managersh-make-executable-and-run" + "\nMore info: https://nym.com/docs/operators/nodes/nym-node/configuration#routing-configuration" "\nThis may take a while; follow the steps below and don't kill the process..." ) # each entry is the exact argv to pass to the script steps = [ - ["check_nymtun_iptables"], - ["remove_duplicate_rules", "nymtun0"], - ["remove_duplicate_rules", "nymwg"], - ["check_nymtun_iptables"], - ["adjust_ip_forwarding"], - ["apply_iptables_rules"], - ["check_nymtun_iptables"], - ["apply_iptables_rules_wg"], - ["configure_dns_and_icmp_wg"], - ["adjust_ip_forwarding"], - ["check_ipv6_ipv4_forwarding"], - ["joke_through_the_mixnet"], - ["joke_through_wg_tunnel"], + ["complete_networking_configuration"] ] for argv in steps: From 28dc7cae4db58570900609a349f3336e88c99f57 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 24 Nov 2025 11:40:22 +0100 Subject: [PATCH 123/134] add logging and logfile --- .../nym-node-setup/network-tunnel-manager.sh | 50 ++++++++++++++++- .../nym-node-setup/quic_bridge_deployment.sh | 55 ++++++++++++------- 2 files changed, 83 insertions(+), 22 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 3d60cc5bfb..af14f62912 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -3,6 +3,8 @@ # run this script as root set -euo pipefail +set +o errtrace + ############################################################################### # colors (no emojis) @@ -11,6 +13,8 @@ GREEN='\033[0;32m' RED='\033[0;31m' YELLOW='\033[0;33m' NC='\033[0m' +CYAN='\033[0;36m' +RESET='\033[0m' info() { printf "%b\n" "${YELLOW}[INFO] $*${NC}" @@ -32,6 +36,44 @@ if [ "$(id -u)" -ne 0 ]; then exit 1 fi +############################################################################### +# Logging +############################################################################### +LOG_FILE="/var/log/nym/network_tunnel_manager.log" +mkdir -p "$(dirname "$LOG_FILE")" +touch "$LOG_FILE" +chmod 640 "$LOG_FILE" + +# rotate log if >10MB +if [[ -f "$LOG_FILE" && $(stat -c%s "$LOG_FILE") -gt 10485760 ]]; then + mv "$LOG_FILE" "${LOG_FILE}.1" + touch "$LOG_FILE" + chmod 640 "$LOG_FILE" +fi + +echo "----- $(date '+%Y-%m-%d %H:%M:%S') START network-tunnel-manager -----" | tee -a "$LOG_FILE" +echo -e "${CYAN}Logs are being saved locally to:${RESET} $LOG_FILE" +echo -e "${CYAN}These logs never leave your machine.${RESET}" +echo "" | tee -a "$LOG_FILE" + +# safe logger +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE" +} + +# simple redirection that keeps function scope intact +add_log_redirection() { + exec > >(sed -u 's/\x1b\[[0-9;]*m//g' | tee -a "$LOG_FILE") 2>&1 +} +add_log_redirection + +trap 'log "ERROR: exit=$? line=$LINENO cmd=$(printf "%q" "$BASH_COMMAND")"' ERR + + + + +START_TIME=$(date +%s) + ############################################################################### # basic config ############################################################################### @@ -662,7 +704,7 @@ apply_spamhaus_blocklist() { mkdir -p "$(dirname "$POLICY_FILE")" if ! wget -q "$EXIT_POLICY_LOCATION" -O "$POLICY_FILE" 2>/dev/null; then - arror "failed to download exit policy, using minimal blocklist" + error "failed to download exit policy, using minimal blocklist" cat >"$POLICY_FILE" <> "$LOG_FILE" exit $status diff --git a/scripts/nym-node-setup/quic_bridge_deployment.sh b/scripts/nym-node-setup/quic_bridge_deployment.sh index db14127016..585261bbef 100644 --- a/scripts/nym-node-setup/quic_bridge_deployment.sh +++ b/scripts/nym-node-setup/quic_bridge_deployment.sh @@ -7,6 +7,7 @@ # RUN AS ROOT set -euo pipefail +set +o errtrace # Colors RED="\033[0;31m" @@ -17,25 +18,39 @@ BOLD="\033[1m" RESET="\033[0m" # Logging -LOG_FILE="/var/log/nym-bridge-helper.log" +LOG_FILE="/var/log/nym/quic_bridge_deployment.log" mkdir -p "$(dirname "$LOG_FILE")" + +# rotate log if >10MB BEFORE writing START header +if [[ -f "$LOG_FILE" && $(stat -c%s "$LOG_FILE") -gt 10485760 ]]; then + mv "$LOG_FILE" "${LOG_FILE}.1" +fi + touch "$LOG_FILE" chmod 640 "$LOG_FILE" + +echo "----- $(date '+%Y-%m-%d %H:%M:%S') START quic-bridge-manager -----" | tee -a "$LOG_FILE" echo -e "${CYAN}Logs are being saved locally to:${RESET} $LOG_FILE" echo -e "${CYAN}These logs never leave your machine.${RESET}" echo "" | tee -a "$LOG_FILE" -# safe logger +# safe logger function log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE" } -# simple redirection that keeps function scope intact +# global redirection, strip ANSI before writing to log add_log_redirection() { - exec > >(tee -a "$LOG_FILE") 2>&1 + exec > >(sed -u 's/\x1b\[[0-9;]*m//g' | tee -a "$LOG_FILE") 2>&1 } add_log_redirection +# trap errors with full visibility +trap 'log "ERROR: exit=$? line=$LINENO cmd=\"$BASH_COMMAND\""' ERR + +START_TIME=$(date +%s) + + # Constants / Paths REQUIRED_CMDS=(ip jq curl openssl dpkg) BRIDGE_BIN="/usr/local/bin/nym-bridge" @@ -493,7 +508,7 @@ full_bridge_setup() { echo "Step 2/6: Installing bridge binary..." install_bridge_binary echo "[Bridge Install] $(date '+%F %T') $( $BRIDGE_BIN --version 2>/dev/null || echo 'nym-bridge (unknown)')" \ - >> /var/log/nym-bridge-version.log + >> /var/log/nym/nym-bridge-version.log press_enter "Press Enter to continue..." echo "" @@ -533,10 +548,6 @@ full_bridge_setup() { echo -e "${YELLOW}------------------------------------------${RESET}" echo -e "All done! You can safely close this session." echo -e "${YELLOW}------------------------------------------${RESET}" - echo "" - echo "Logs saved locally at: $LOG_FILE" - echo "Operation 'full_bridge_setup' completed." - echo "" hr echo -e "${CYAN}Next steps and verification:${RESET}" @@ -574,22 +585,26 @@ full_bridge_setup() { graceful_exit() { local exit_code=$? - echo "" - echo -e "${YELLOW}------------------------------------------${RESET}" + END_TIME=$(date +%s) + ELAPSED=$((END_TIME - START_TIME)) + + # Only print success message when there were NO errors if [[ $exit_code -eq 0 ]]; then - echo -e "${GREEN}Setup completed successfully. Exiting cleanly.${RESET}" - else - echo -e "${RED}Script exited with errors (code: $exit_code).${RESET}" - echo "Check the log at: $LOG_FILE" + echo "Operation '${COMMAND}' completed." fi - echo -e "${YELLOW}------------------------------------------${RESET}" - echo "" - exec >&- 2>&- + + # END footer always logged + echo "----- $(date '+%Y-%m-%d %H:%M:%S') END operation ${COMMAND} (status $exit_code, duration ${ELAPSED}s) -----" >> "$LOG_FILE" + exit $exit_code } -trap graceful_exit EXIT # Command menu +COMMAND="${1:-help}" +trap 'log "ERROR: exit=$? line=$LINENO cmd=$(printf "%q" "$BASH_COMMAND")"' ERR + +trap graceful_exit EXIT + case "${1:-}" in full_bridge_setup) full_bridge_setup ;; install_bridge_binary) install_bridge_binary ;; @@ -615,5 +630,3 @@ case "${1:-}" in ;; esac -echo "Operation '${1:-help}' completed." - From 68eae18b8b45beb935d9d21f0c2275c1c10a622e Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 24 Nov 2025 12:21:03 +0100 Subject: [PATCH 124/134] fix coloring and trap --- .../nym-node-setup/quic_bridge_deployment.sh | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/scripts/nym-node-setup/quic_bridge_deployment.sh b/scripts/nym-node-setup/quic_bridge_deployment.sh index 585261bbef..a1fe29ff3a 100644 --- a/scripts/nym-node-setup/quic_bridge_deployment.sh +++ b/scripts/nym-node-setup/quic_bridge_deployment.sh @@ -41,13 +41,11 @@ log() { # global redirection, strip ANSI before writing to log add_log_redirection() { - exec > >(sed -u 's/\x1b\[[0-9;]*m//g' | tee -a "$LOG_FILE") 2>&1 + exec > >(tee >(sed -u 's/\x1b\[[0-9;]*m//g' >> "$LOG_FILE")) + exec 2> >(tee >(sed -u 's/\x1b\[[0-9;]*m//g' >> "$LOG_FILE") >&2) } add_log_redirection -# trap errors with full visibility -trap 'log "ERROR: exit=$? line=$LINENO cmd=\"$BASH_COMMAND\""' ERR - START_TIME=$(date +%s) @@ -82,23 +80,28 @@ if [[ "$(id -u)" -ne 0 ]]; then fi # UI helpers -hr() { echo -e "${YELLOW}----------------------------------------${RESET}"; } +hr() { echo -e "${YELLOW}----------------------------------------${RESET}" ; } title() { echo -e "\n${YELLOW}==========================================${RESET}\n${YELLOW} $1${RESET}\n${YELLOW}==========================================${RESET}\n"; } ok() { echo -e "${GREEN}$1${RESET}"; } warn() { echo -e "${YELLOW}$1${RESET}"; } err() { echo -e "${RED}$1${RESET}"; } info() { echo -e "${CYAN}$1${RESET}"; } -press_enter() { read -r -p "$1"; } +press_enter() { + echo -n "$1" > /dev/tty + read -r _ < /dev/tty +} + # Disable pauses and interactive prompts for noninteractive mode if [[ "${NONINTERACTIVE:-0}" == "1" ]]; then - # all pauses become no-ops - press_enter() { :; } - - # silence any "enter path:" prompts - echo_prompt() { :; } + press_enter() { :; } + echo_prompt() { :; } else - echo_prompt() { echo -n "$1"; } + press_enter() { + echo -n "$1" > /dev/tty + read -r _ < /dev/tty + } + echo_prompt() { echo -n "$1"; } fi # Helper: detect dpkg dependency failure for libc6>=2.34 From c13b4aa745719a5060e80cddd1940c3a55f322b6 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 24 Nov 2025 12:25:59 +0100 Subject: [PATCH 125/134] fix coloring and trap --- scripts/nym-node-setup/network-tunnel-manager.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index af14f62912..c5f6bbbf86 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -61,12 +61,14 @@ log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE" } -# simple redirection that keeps function scope intact +# global redirection, strip ANSI before writing to log add_log_redirection() { - exec > >(sed -u 's/\x1b\[[0-9;]*m//g' | tee -a "$LOG_FILE") 2>&1 + exec > >(tee >(sed -u 's/\x1b\[[0-9;]*m//g' >> "$LOG_FILE")) + exec 2> >(tee >(sed -u 's/\x1b\[[0-9;]*m//g' >> "$LOG_FILE") >&2) } add_log_redirection + trap 'log "ERROR: exit=$? line=$LINENO cmd=$(printf "%q" "$BASH_COMMAND")"' ERR @@ -333,7 +335,7 @@ remove_duplicate_rules() { rm -f "$tmp6" else - error "no ipv6 rules found for $interface to deduplicate" + ok "no ipv6 rules found for $interface to deduplicate" fi ok "duplicate rule scan completed for $interface" From f1be6ae788ced8f8e5ccd315cc64eb73c247f55d Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Mon, 24 Nov 2025 12:38:25 +0100 Subject: [PATCH 126/134] @ rename $cmd -> item in exit_policy_install_deps --- scripts/nym-node-setup/network-tunnel-manager.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index c5f6bbbf86..3a464dd9fa 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -516,10 +516,10 @@ add_port_rules() { exit_policy_install_deps() { install_iptables_persistent - for cmd in iptables ip6tables ip grep sed awk wget curl; do - if ! command -v "$cmd" >/dev/null 2>&1; then - info "installing dependency: $cmd" - apt-get install -y "$cmd" + for item in iptables ip6tables ip grep sed awk wget curl; do + if ! command -v "$item" >/dev/null 2>&1; then + info "installing dependency: $item" + apt-get install -y "$item" fi done } From 2d37c33a3d8c8244c9417a0e175debbc7492c56d Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 24 Nov 2025 12:42:38 +0100 Subject: [PATCH 127/134] tweak docs commands --- .../operators/snippets/routing-conf.mdx | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/documentation/docs/components/operators/snippets/routing-conf.mdx b/documentation/docs/components/operators/snippets/routing-conf.mdx index ebb33e5ba9..44036091f4 100644 --- a/documentation/docs/components/operators/snippets/routing-conf.mdx +++ b/documentation/docs/components/operators/snippets/routing-conf.mdx @@ -62,7 +62,7 @@ Networking configuration across different ISPs and various operation systems doe New nym-node full configuration, Existing nym-node full configuration, - Step-by-step or Pprtial configuration + Step-by-step or Partial configuration ]} defaultIndex={0}> This design is meant for operators setting up a new node on a fresh machine and it will result with a complete server readiness for routing as Entry Gateway and Exit Gateway in both Mixnet and WireGuard mode. @@ -80,9 +80,14 @@ chmod +x network-tunnel-manager.sh && \ - **If you setting up a new node and not upgrading an existing one, keep it running and [bond](/operators/nodes/nym-node/bonding.mdx) your node now! Then come back here and follow the rest of the configuration.** -###### 3. Execute complete network configuration: +###### 3. Run command for configuration: +- For nodes with WireGuard enabled: ```sh -./network-tunnel-manager.sh complete_networking_setup +./network-tunnel-manager.sh complete_networking_configuration +``` +- For nodes with WireGuard disabled: +```sh +./network-tunnel-manager.sh full_tunnel_setup ``` @@ -98,9 +103,14 @@ chmod +x network-tunnel-manager.sh && \ ./network-tunnel-manager.sh --help ``` -###### 2. Execute complete network configuration: +###### 2. Run command for configuration: +- For nodes with WireGuard enabled: ```sh -./network-tunnel-manager.sh complete_networking_setup +./network-tunnel-manager.sh complete_networking_configuration +``` +- For nodes with WireGuard disabled: +```sh +./network-tunnel-manager.sh full_tunnel_setup ``` From 26f4dd8f39001ba8f7e8a8b06e842aeaa21b6206 Mon Sep 17 00:00:00 2001 From: benedettadavico Date: Mon, 24 Nov 2025 13:41:03 +0100 Subject: [PATCH 128/134] add another test --- .../nym-node-setup/network-tunnel-manager.sh | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 3a464dd9fa..9b3318c836 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -912,10 +912,43 @@ check_nym_exit_chain() { return $errors } +check_iptables_default_policies() { + info "checking base iptables default policies (INPUT/FORWARD)" + + local issues=0 + local input_policy forward_policy + + input_policy=$(iptables -S INPUT 2>/dev/null | awk 'NR==1 && $1=="-P" {print $3}') + forward_policy=$(iptables -S FORWARD 2>/dev/null | awk 'NR==1 && $1=="-P" {print $3}') + + if [[ -z "${input_policy:-}" ]]; then + error "unable to read INPUT default policy (iptables -S INPUT failed?)" + issues=1 + elif [[ "${input_policy^^}" != "DROP" ]]; then + error "INPUT default policy is ${input_policy^^}; expected DROP so traffic is only allowed by explicit rules." + issues=1 + else + ok "INPUT default policy is DROP" + fi + + if [[ -z "${forward_policy:-}" ]]; then + error "unable to read FORWARD default policy (iptables -S FORWARD failed?)" + issues=1 + elif [[ "${forward_policy^^}" != "DROP" ]]; then + error "FORWARD default policy is ${forward_policy^^}; expected DROP to ensure traffic only flows via NYM-EXIT rules." + issues=1 + else + ok "FORWARD default policy is DROP" + fi + + return $issues +} + check_firewall_setup() { info "checking ipv4 firewall ordering…" local errors=0 + check_iptables_default_policies || errors=1 check_forward_chain || errors=1 check_nym_exit_chain || errors=1 From 42c051dfa3e6165759f62fbaa0ddcf2505c108bc Mon Sep 17 00:00:00 2001 From: benedettadavico Date: Mon, 24 Nov 2025 13:44:28 +0100 Subject: [PATCH 129/134] add default output test --- scripts/nym-node-setup/network-tunnel-manager.sh | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 9b3318c836..852079ac09 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -916,10 +916,11 @@ check_iptables_default_policies() { info "checking base iptables default policies (INPUT/FORWARD)" local issues=0 - local input_policy forward_policy + local input_policy forward_policy output_policy input_policy=$(iptables -S INPUT 2>/dev/null | awk 'NR==1 && $1=="-P" {print $3}') forward_policy=$(iptables -S FORWARD 2>/dev/null | awk 'NR==1 && $1=="-P" {print $3}') + output_policy=$(iptables -S OUTPUT 2>/dev/null | awk 'NR==1 && $1=="-P" {print $3}') if [[ -z "${input_policy:-}" ]]; then error "unable to read INPUT default policy (iptables -S INPUT failed?)" @@ -941,6 +942,16 @@ check_iptables_default_policies() { ok "FORWARD default policy is DROP" fi + if [[ -z "${output_policy:-}" ]]; then + error "unable to read OUTPUT default policy (iptables -S OUTPUT failed?)" + issues=1 + elif [[ "${output_policy^^}" != "ACCEPT" ]]; then + error "OUTPUT default policy is ${output_policy^^}; expected ACCEPT" + issues=1 + else + ok "OUTPUT default policy is ACCEPT" + fi + return $issues } From de0ae687efae364a0a41b46ae1666e352236bf47 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 24 Nov 2025 14:24:04 +0100 Subject: [PATCH 130/134] docs: specify command desc --- .../docs/components/operators/snippets/routing-conf.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/documentation/docs/components/operators/snippets/routing-conf.mdx b/documentation/docs/components/operators/snippets/routing-conf.mdx index 44036091f4..f39379f7ab 100644 --- a/documentation/docs/components/operators/snippets/routing-conf.mdx +++ b/documentation/docs/components/operators/snippets/routing-conf.mdx @@ -81,11 +81,11 @@ chmod +x network-tunnel-manager.sh && \ - **If you setting up a new node and not upgrading an existing one, keep it running and [bond](/operators/nodes/nym-node/bonding.mdx) your node now! Then come back here and follow the rest of the configuration.** ###### 3. Run command for configuration: -- For nodes with WireGuard enabled: +- Nodes with **WireGuard enabled**: Configures interfaces (`nymtun0` and `nymwg`), IPv4 and IPv6 routing, WireGuard exit policy and does validation tests ```sh ./network-tunnel-manager.sh complete_networking_configuration ``` -- For nodes with WireGuard disabled: +- Nodes with **WireGuard disabled**: Does everything like the command above *without WireGuard exit policy* ```sh ./network-tunnel-manager.sh full_tunnel_setup ``` @@ -104,11 +104,11 @@ chmod +x network-tunnel-manager.sh && \ ``` ###### 2. Run command for configuration: -- For nodes with WireGuard enabled: +- Nodes with **WireGuard enabled**: Configures interfaces (`nymtun0` and `nymwg`), IPv4 and IPv6 routing, WireGuard exit policy and does validation tests ```sh ./network-tunnel-manager.sh complete_networking_configuration ``` -- For nodes with WireGuard disabled: +- Nodes with **WireGuard disabled**: Does everything like the command above *without WireGuard exit policy* ```sh ./network-tunnel-manager.sh full_tunnel_setup ``` From 00d0ae0b5bb3b7da3cb51b76a8f00e4bf05df4cf Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 24 Nov 2025 14:35:00 +0100 Subject: [PATCH 131/134] docs: add noninteractive mode for quic setup --- .../snippets/quic-bridge-deployment-script-setup.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/documentation/docs/components/operators/snippets/quic-bridge-deployment-script-setup.mdx b/documentation/docs/components/operators/snippets/quic-bridge-deployment-script-setup.mdx index 592269d728..0fd62d033f 100644 --- a/documentation/docs/components/operators/snippets/quic-bridge-deployment-script-setup.mdx +++ b/documentation/docs/components/operators/snippets/quic-bridge-deployment-script-setup.mdx @@ -32,6 +32,10 @@ chmod +x quic_bridge_deployment.sh ```sh ./quic_bridge_deployment.sh full_bridge_setup ``` +- If you prefer a non-interactive mode, run the command with this variable (and skip next step): +```sh +NONINTERACTIVE=1 quick_bridge_deployment.sh full_bridge_setup +``` ###### 3. Follow the interactive prompts - Make sure you don't just press enter to insert default values if your setup is different, for example in case of path to the config file From 8c3a7977507dc5b6873e388ff7578f4ad65f9f6e Mon Sep 17 00:00:00 2001 From: RadekSabacky Date: Mon, 24 Nov 2025 15:11:01 +0100 Subject: [PATCH 132/134] @ fix perform_pings --- scripts/nym-node-setup/network-tunnel-manager.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 3a464dd9fa..82630438d1 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -397,10 +397,10 @@ check_ip_routing() { perform_pings() { info "performing ipv4 ping to google.com" - ping -c 4 google.com || error "ipv4 ping failed" + ping -4 -c 4 google.com || error "ipv4 ping failed" echo "---------------------------" info "performing ipv6 ping to google.com" - ping6 -c 4 google.com || error "ipv6 ping failed" + ping6 -6 -c 4 google.com || error "ipv6 ping failed" } joke_through_tunnel() { From a293d6da7d2407d68513c4affe3eb116efb264d4 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 24 Nov 2025 15:20:45 +0100 Subject: [PATCH 133/134] full_tunnel_setup to nym_tunnel_setup --- .../components/operators/snippets/routing-conf.mdx | 4 ++-- scripts/nym-node-setup/network-tunnel-manager.sh | 13 ++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/documentation/docs/components/operators/snippets/routing-conf.mdx b/documentation/docs/components/operators/snippets/routing-conf.mdx index f39379f7ab..31c7148454 100644 --- a/documentation/docs/components/operators/snippets/routing-conf.mdx +++ b/documentation/docs/components/operators/snippets/routing-conf.mdx @@ -87,7 +87,7 @@ chmod +x network-tunnel-manager.sh && \ ``` - Nodes with **WireGuard disabled**: Does everything like the command above *without WireGuard exit policy* ```sh -./network-tunnel-manager.sh full_tunnel_setup +./network-tunnel-manager.sh nym_tunnel_setup ``` @@ -110,7 +110,7 @@ chmod +x network-tunnel-manager.sh && \ ``` - Nodes with **WireGuard disabled**: Does everything like the command above *without WireGuard exit policy* ```sh -./network-tunnel-manager.sh full_tunnel_setup +./network-tunnel-manager.sh nym_tunnel_setup ``` diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 71aa676822..75ea0cf080 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -1140,7 +1140,7 @@ exit_policy_run_tests() { # part 5: high level workflows ############################################################################### -full_tunnel_setup() { +nym_tunnel_setup() { # this mirrors your previous chain of calls but inside one script info "running full tunnel setup for ${TUNNEL_INTERFACE} and ${WG_INTERFACE}" @@ -1182,7 +1182,7 @@ exit_policy_install() { complete_networking_configuration() { info "starting complete networking configuration: tunnels + exit policy" - full_tunnel_setup + nym_tunnel_setup exit_policy_install check_firewall_setup || error "firewall order checks reported problems, please review output" exit_policy_run_tests || error "exit policy tests reported problems, please review output" @@ -1198,8 +1198,8 @@ cmd="${1:-help}" log "COMMAND: $cmd ARGS: $*" case "$cmd" in - full_tunnel_setup) - full_tunnel_setup + nym_tunnel_setup) + nym_tunnel_setup status=$? ;; exit_policy_install) @@ -1298,9 +1298,8 @@ usage: $0 [args] high level workflows: complete_networking_configuration Install tunnel interfaces, setup networking, iptables, wg exit policy & tests - exit_policy_install Install and configure wireguard exit policy - full_tunnel_setup Install tunnel interfaces & setup networking - + nym_tunnel_setup Install tunnel interfaces & setup networking + exit_policy_install Install and configure wireguard exit policy tunnel and nat helpers: adjust_ip_forwarding Enable ipv4/ipv6 forwarding via sysctl.d apply_iptables_rules Apply nat/forward rules for ${TUNNEL_INTERFACE} From e0c74c5eb0c442e0fc3a000cf05f2543b2b76f70 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 24 Nov 2025 15:33:51 +0100 Subject: [PATCH 134/134] formatting fix ... LFG --- scripts/nym-node-setup/network-tunnel-manager.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/nym-node-setup/network-tunnel-manager.sh b/scripts/nym-node-setup/network-tunnel-manager.sh index 75ea0cf080..ab941e89b5 100644 --- a/scripts/nym-node-setup/network-tunnel-manager.sh +++ b/scripts/nym-node-setup/network-tunnel-manager.sh @@ -1298,8 +1298,8 @@ usage: $0 [args] high level workflows: complete_networking_configuration Install tunnel interfaces, setup networking, iptables, wg exit policy & tests - nym_tunnel_setup Install tunnel interfaces & setup networking - exit_policy_install Install and configure wireguard exit policy + nym_tunnel_setup Install tunnel interfaces & setup networking + exit_policy_install Install and configure wireguard exit policy tunnel and nat helpers: adjust_ip_forwarding Enable ipv4/ipv6 forwarding via sysctl.d apply_iptables_rules Apply nat/forward rules for ${TUNNEL_INTERFACE}