#!/bin/bash # Nym QUIC Bridge Deployment Helper Script # This script provides network configuration and troubleshooting tools for Nym QUIC bridges network_device=$(ip route show default | awk '/default/ {print $5}') wg_tunnel_interface="nymwg" BRIDGE_CONFIG_DIR="/opt/nym-bridge" BRIDGE_KEYS_DIR="$BRIDGE_CONFIG_DIR/keys" BRIDGE_CONFIG="$BRIDGE_CONFIG_DIR/bridges.toml" CLIENT_PARAMS="$BRIDGE_CONFIG_DIR/client_bridge_params.json" BRIDGE_BINARY="/usr/local/bin/nym-bridge" if ! dpkg -s iptables-persistent >/dev/null 2>&1; then echo "Installing iptables-persistent..." sudo apt-get update sudo apt-get install -y iptables-persistent else echo "iptables-persistent is already installed." 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 } fetch_wg_ipv6_address() { ipv6_global_address=$(ip -6 addr show "$wg_tunnel_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 $wg_tunnel_interface. Please configure IPv6 or check your network settings." exit 1 else echo "Using IPv6 address: $ipv6_global_address" 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 echo "IP forwarding enabled for IPv4 and IPv6." } apply_bridge_iptables_rules() { echo "Applying iptables rules for QUIC bridge ($wg_tunnel_interface)..." sleep 1 # INPUT rules - allow incoming connections TO the bridge from WireGuard clients # CRITICAL: This allows mobile clients to reach the bandwidth controller at 10.1.0.1:51830 sudo iptables -I INPUT -i "$wg_tunnel_interface" -j ACCEPT sudo ip6tables -I INPUT -i "$wg_tunnel_interface" -j ACCEPT # NAT rules - for outbound traffic masquerading sudo iptables -t nat -A POSTROUTING -o "$network_device" -j MASQUERADE sudo ip6tables -t nat -A POSTROUTING -o "$network_device" -j MASQUERADE # FORWARD rules - allow traffic through the bridge sudo iptables -A FORWARD -i "$wg_tunnel_interface" -o "$network_device" -j ACCEPT sudo iptables -A FORWARD -i "$network_device" -o "$wg_tunnel_interface" -m state --state RELATED,ESTABLISHED -j ACCEPT sudo ip6tables -A FORWARD -i "$wg_tunnel_interface" -o "$network_device" -j ACCEPT sudo ip6tables -A FORWARD -i "$network_device" -o "$wg_tunnel_interface" -m state --state RELATED,ESTABLISHED -j ACCEPT # Save rules sudo iptables-save | sudo tee /etc/iptables/rules.v4 sudo ip6tables-save | sudo tee /etc/iptables/rules.v6 echo "Iptables rules applied successfully for QUIC bridge (including INPUT rules for bandwidth controller)." } check_bridge_iptables() { echo "Inspecting iptables rules for QUIC bridge ($wg_tunnel_interface)..." echo "---------------------------------------" echo "IPv4 INPUT rules (for bandwidth controller):" iptables -L INPUT -v -n | grep -E "$wg_tunnel_interface|Chain INPUT" | head -20 echo "---------------------------------------" echo "IPv4 FORWARD rules:" iptables -L FORWARD -v -n | awk -v dev="$wg_tunnel_interface" '/^Chain FORWARD/ || $0 ~ dev || $0 ~ "ufw-reject-forward"' echo "---------------------------------------" echo "IPv6 INPUT rules (for bandwidth controller):" ip6tables -L INPUT -v -n | grep -E "$wg_tunnel_interface|Chain INPUT" | head -20 echo "---------------------------------------" echo "IPv6 FORWARD rules:" ip6tables -L FORWARD -v -n | awk -v dev="$wg_tunnel_interface" '/^Chain FORWARD/ || $0 ~ dev || $0 ~ "ufw6-reject-forward"' } remove_duplicate_bridge_rules() { local script_name=$(basename "$0") echo "Removing duplicate iptables rules for $wg_tunnel_interface..." iptables-save | grep "$wg_tunnel_interface" | while read -r line; do sudo iptables -D ${line#-A } 2>/dev/null || echo "Failed to delete rule: $line" done ip6tables-save | grep "$wg_tunnel_interface" | while read -r line; do sudo ip6tables -D ${line#-A } 2>/dev/null || echo "Failed to delete rule: $line" done echo "Duplicates removed for $wg_tunnel_interface." echo "!!IMPORTANT!! You need to now reapply the iptables rules." echo "Run: ./$script_name apply_bridge_iptables_rules" } configure_dns_and_icmp() { 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 sudo ip6tables -A INPUT -p ipv6-icmp -j ACCEPT sudo ip6tables -A OUTPUT -p ipv6-icmp -j ACCEPT echo "Allowing DNS over UDP (port 53)..." sudo iptables -A INPUT -p udp --dport 53 -j ACCEPT sudo ip6tables -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 sudo ip6tables -A INPUT -p tcp --dport 53 -j ACCEPT echo "Saving iptables rules..." sudo iptables-save | sudo tee /etc/iptables/rules.v4 sudo ip6tables-save | sudo tee /etc/iptables/rules.v6 echo "DNS and ICMP configuration completed." } 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 -4 -c 4 google.com echo "---------------------------------------" echo "Performing IPv6 ping to google.com..." ping6 -c 4 google.com } test_bridge_connectivity() { 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}Testing QUIC bridge connectivity on $wg_tunnel_interface...${reset}" echo -e "${yellow}If these tests succeed, it confirms the bridge can reach the outside world via IPv4 and IPv6.${reset}" echo -e "${yellow}However, external clients may experience different connectivity to your bridge.${reset}" ipv4_address=$(ip addr show "$wg_tunnel_interface" | awk '/inet / {print $2}' | cut -d'/' -f1) ipv6_address=$(ip addr show "$wg_tunnel_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 $wg_tunnel_interface. Unable to test connectivity.${reset}" echo -e "${red}Please verify your bridge 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 -4 -c 1 -I "$ipv4_address" google.com >/dev/null 2>&1; then echo -e "${green}IPv4 connectivity is working. Fetching test data...${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 test joke: $joke${reset}" || echo -e "${red}Failed to fetch test data via IPv4.${reset}" else echo -e "${red}IPv4 connectivity is not working for $wg_tunnel_interface. Verify your routing and NAT settings.${reset}" fi else echo -e "${yellow}No IPv4 address found on $wg_tunnel_interface. Skipping IPv4 test.${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 test data...${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 test joke: $joke${reset}" || echo -e "${red}Failed to fetch test data via IPv6.${reset}" else echo -e "${red}IPv6 connectivity is not working for $wg_tunnel_interface. Verify your routing and NAT settings.${reset}" fi else echo -e "${yellow}No IPv6 address found on $wg_tunnel_interface. Skipping IPv6 test.${reset}" fi echo -e "${green}Connectivity testing completed for $wg_tunnel_interface.${reset}" echo -e "------------------------------------" sleep 2 echo echo echo -e "${yellow}### Bridge Connectivity Testing Recommendations ###${reset}" echo -e "${yellow}- Test UDP connectivity on port 51822 (used for Nym QUIC/WireGuard)${reset}" echo -e "${yellow} From another machine: echo 'test message' | nc -u 51822${reset}" echo -e "${yellow}- Test bandwidth controller access on port 51830:${reset}" echo -e "${yellow} From inside the WireGuard tunnel: curl http://10.1.0.1:51830${reset}" echo -e "${yellow}- If connectivity issues persist, check port forwarding and firewall rules${reset}" echo } check_bridge_service_status() { echo "Checking nym-bridge service status..." systemctl status nym-bridge.service --no-pager echo "---------------------------------------" echo "Checking nym-node service status..." systemctl status nym-node.service --no-pager } show_bridge_logs() { local lines=${1:-50} echo "Showing last $lines lines of nym-bridge logs..." journalctl -u nym-bridge.service -n "$lines" --no-pager } check_bridge_installation() { local green="\033[0;32m" local reset="\033[0m" local red="\033[0;31m" local yellow="\033[0;33m" echo -e "${yellow}=== Nym QUIC Bridge Installation Status ===${reset}" echo "" # Check binary if [[ -f "$BRIDGE_BINARY" ]]; then echo -e "${green}✓ Bridge binary found: $BRIDGE_BINARY${reset}" bridge_version=$($BRIDGE_BINARY --version 2>/dev/null | head -1 || echo "Unable to determine version") echo " Version: $bridge_version" else echo -e "${red}✗ Bridge binary not found at $BRIDGE_BINARY${reset}" fi echo "" # Check configuration directory if [[ -d "$BRIDGE_CONFIG_DIR" ]]; then echo -e "${green}✓ Configuration directory exists: $BRIDGE_CONFIG_DIR${reset}" else echo -e "${red}✗ Configuration directory not found: $BRIDGE_CONFIG_DIR${reset}" fi echo "" # Check keys directory if [[ -d "$BRIDGE_KEYS_DIR" ]]; then echo -e "${green}✓ Keys directory exists: $BRIDGE_KEYS_DIR${reset}" key_count=$(sudo bash -c "ls -1 \"$BRIDGE_KEYS_DIR\"/*.pem" 2>/dev/null | wc -l) echo " Keys found: $key_count" else echo -e "${red}✗ Keys directory not found: $BRIDGE_KEYS_DIR${reset}" fi echo "" # Check configuration files if [[ -f "$BRIDGE_CONFIG" ]]; then echo -e "${green}✓ Bridge config found: $BRIDGE_CONFIG${reset}" else echo -e "${red}✗ Bridge config not found: $BRIDGE_CONFIG${reset}" fi if [[ -f "$CLIENT_PARAMS" ]]; then echo -e "${green}✓ Client params found: $CLIENT_PARAMS${reset}" else echo -e "${red}✗ Client params not found: $CLIENT_PARAMS${reset}" fi echo "" # Check services echo -e "${yellow}Service Status:${reset}" if systemctl is-active --quiet nym-bridge.service; then echo -e "${green}✓ nym-bridge service is running${reset}" else echo -e "${red}✗ nym-bridge service is not running${reset}" fi if systemctl is-active --quiet nym-node.service; then echo -e "${green}✓ nym-node service is running${reset}" else echo -e "${red}✗ nym-node service is not running${reset}" fi echo "" } show_bridge_config() { echo "=== Bridge Configuration ===" echo "" if [[ -f "$BRIDGE_CONFIG" ]]; then echo "Bridge config ($BRIDGE_CONFIG):" echo "---------------------------------------" cat "$BRIDGE_CONFIG" echo "" else echo "Bridge config not found at $BRIDGE_CONFIG" fi if [[ -f "$CLIENT_PARAMS" ]]; then echo "Client parameters ($CLIENT_PARAMS):" echo "---------------------------------------" cat "$CLIENT_PARAMS" echo "" else echo "Client parameters not found at $CLIENT_PARAMS" fi } show_bridge_keys() { local green="\033[0;32m" local reset="\033[0m" local red="\033[0;31m" local yellow="\033[0;33m" echo -e "${yellow}=== Bridge Keys Information ===${reset}" echo "" if [[ ! -d "$BRIDGE_KEYS_DIR" ]]; then echo -e "${red}Keys directory not found: $BRIDGE_KEYS_DIR${reset}" return 1 fi echo "Keys directory: $BRIDGE_KEYS_DIR" echo "---------------------------------------" # List all key files if ls -1 "$BRIDGE_KEYS_DIR"/*.pem >/dev/null 2>&1; then for key_file in "$BRIDGE_KEYS_DIR"/*.pem; do key_name=$(basename "$key_file") echo -e "${green}Key file: $key_name${reset}" # If it's a public key, show the content if [[ "$key_name" == *"_bridge_identity.pem" ]]; then echo " Type: ED25519 Bridge Identity (Private)" echo " Path: $key_file" # Extract and show public key if command -v openssl >/dev/null 2>&1; then echo -e "${yellow} Public key (base64):${reset}" openssl pkey -in "$key_file" -pubout 2>/dev/null | grep -v "\---" | base64 -d | tail -c 32 | base64 fi fi echo "" done else echo -e "${red}No key files found in $BRIDGE_KEYS_DIR${reset}" fi } show_bridge_info() { local green="\033[0;32m" local reset="\033[0m" local yellow="\033[0;33m" echo -e "${yellow}=== Nym QUIC Bridge Information ===${reset}" echo "" # Network interfaces echo -e "${yellow}Network Configuration:${reset}" echo "Primary network device: $network_device" echo "WireGuard interface: $wg_tunnel_interface" # Show IP addresses echo "" echo "IPv4 addresses:" ip -4 addr show | grep inet | awk '{print " " $2 " on " $NF}' echo "" echo "IPv6 addresses:" ip -6 addr show scope global | grep inet6 | awk '{print " " $2 " on " $NF}' echo "" echo -e "${yellow}Bridge Paths:${reset}" echo "Configuration: $BRIDGE_CONFIG_DIR" echo "Keys: $BRIDGE_KEYS_DIR" echo "Binary: $BRIDGE_BINARY" echo "" echo -e "${yellow}Important Commands:${reset}" echo " Check bridge status: systemctl status nym-bridge" echo " Check nym-node status: systemctl status nym-node" echo " View bridge logs: journalctl -u nym-bridge -f" echo " View nym-node logs: journalctl -u nym-node -f" echo "" } verify_bridge_prerequisites() { local green="\033[0;32m" local reset="\033[0m" local red="\033[0;31m" local yellow="\033[0;33m" echo -e "${yellow}=== Verifying Bridge Prerequisites ===${reset}" echo "" local all_good=true # Check IP forwarding ipv4_forward=$(cat /proc/sys/net/ipv4/ip_forward) ipv6_forward=$(cat /proc/sys/net/ipv6/conf/all/forwarding) if [[ "$ipv4_forward" == "1" ]]; then echo -e "${green}✓ IPv4 forwarding enabled${reset}" else echo -e "${red}✗ IPv4 forwarding disabled${reset}" echo " Fix: Run 'nym-bridge-helper adjust_ip_forwarding'" all_good=false fi if [[ "$ipv6_forward" == "1" ]]; then echo -e "${green}✓ IPv6 forwarding enabled${reset}" else echo -e "${red}✗ IPv6 forwarding disabled${reset}" echo " Fix: Run 'nym-bridge-helper adjust_ip_forwarding'" all_good=false fi # Check iptables-persistent if dpkg -s iptables-persistent >/dev/null 2>&1; then echo -e "${green}✓ iptables-persistent installed${reset}" else echo -e "${red}✗ iptables-persistent not installed${reset}" echo " Fix: This script will auto-install on first run" all_good=false fi # Check required packages for pkg in openssl jq curl wg; do if command -v "$pkg" >/dev/null 2>&1; then echo -e "${green}✓ $pkg installed${reset}" else echo -e "${red}✗ $pkg not installed${reset}" if [[ "$pkg" == "wg" ]]; then echo " Install: sudo apt install wireguard-tools" fi all_good=false fi done echo "" if [[ "$all_good" == true ]]; then echo -e "${green}All prerequisites satisfied!${reset}" else echo -e "${yellow}Some prerequisites need attention. See above for fixes.${reset}" fi echo "" } generate_bridge_keys() { local green="\033[0;32m" local reset="\033[0m" local red="\033[0;31m" local yellow="\033[0;33m" echo -e "${yellow}=== Generating Bridge Keys ===${reset}" echo "" # Create directories sudo mkdir -p "$BRIDGE_CONFIG_DIR" sudo mkdir -p "$BRIDGE_KEYS_DIR" sudo chmod 700 "$BRIDGE_KEYS_DIR" # Generate ED25519 private key local key_file="$BRIDGE_KEYS_DIR/ed25519_bridge_identity.pem" if sudo test -f "$key_file"; then echo -e "${yellow}Warning: Key file already exists at $key_file${reset}" read -p "Overwrite existing key? (yes/no): " confirm if [[ "$confirm" != "yes" ]]; then echo "Aborted. Keeping existing key." return 1 fi fi echo "Generating ED25519 key..." sudo openssl genpkey -algorithm ED25519 -out "$key_file" sudo chmod 600 "$key_file" echo -e "${green}✓ Bridge key generated at $key_file${reset}" # Extract and display public key echo "" echo "Extracting public key..." pubkey=$(sudo openssl pkey -in "$key_file" -pubout 2>/dev/null | grep -v "\---" | base64 -d | tail -c 32 | base64) echo -e "${green}Public key (base64): $pubkey${reset}" echo "" echo -e "${yellow}Next steps:${reset}" echo "1. Run 'nym-bridge-helper create_client_params' to generate client parameters" echo "2. Run 'nym-bridge-helper create_bridge_config' to create bridge configuration" } create_client_params() { local green="\033[0;32m" local reset="\033[0m" local red="\033[0;31m" local yellow="\033[0;33m" echo -e "${yellow}=== Creating Client Bridge Parameters ===${reset}" echo "" # Check if key exists local key_file="$BRIDGE_KEYS_DIR/ed25519_bridge_identity.pem" if ! sudo test -f "$key_file"; then echo -e "${red}Error: Bridge key not found at $key_file${reset}" echo "Run 'nym-bridge-helper generate_bridge_keys' first" return 1 fi # Get forward address read -p "Enter forward address (e.g., :51822, can be found by running 'curl -4 https://ifconfig.co/ip'): " forward_addr if [[ -z "$forward_addr" ]]; then echo -e "${red}Error: Forward address is required${reset}" return 1 fi # Extract public key echo "Extracting public key..." pubkey=$(sudo openssl pkey -in "$key_file" -pubout 2>/dev/null | grep -v "\---" | base64 -d | tail -c 32 | base64) # Create client params JSON echo "Creating client parameters file..." sudo tee "$CLIENT_PARAMS" > /dev/null < /dev/null < /dev/null fi sudo tee -a "$BRIDGE_CONFIG" > /dev/null < /dev/null <