Compare commits

...

3 Commits

Author SHA1 Message Date
benedettadavico 2e7f1ed0f3 fix order 2025-11-17 16:27:17 +01:00
benedettadavico c2f588857f dns and icmp rules go to the top 2025-11-17 16:21:49 +01:00
benedettadavico 45598ce250 testing 2025-11-17 11:42:25 +01:00
4 changed files with 779 additions and 11 deletions
@@ -507,17 +507,17 @@ 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
}
@@ -525,26 +525,26 @@ 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
iptables -I "$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
iptables -I "$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
ip6tables -I "$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
ip6tables -I "$NYM_CHAIN" -p tcp --dport 53 -j ACCEPT
fi
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
iptables -I "$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
iptables -I "$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
ip6tables -I "$NYM_CHAIN" -p ipv6-icmp -j ACCEPT
fi
}
@@ -0,0 +1,43 @@
#!/bin/bash
# Fix the FORWARD chain order so NYM-EXIT comes before ACCEPT
WG_INTERFACE="nymwg"
NETWORK_DEVICE=$(ip route show default | awk '/default/ {print $5}')
NYM_CHAIN="NYM-EXIT"
echo "Fixing FORWARD chain order..."
# Remove ALL ACCEPT rules for nymwg → network_device (there might be duplicates)
while iptables -D FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT 2>/dev/null; do
echo "Removed ACCEPT rule"
done
# Remove NYM-EXIT hook if it exists (we'll re-add it)
iptables -D FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null || true
# Insert NYM-EXIT at position 1
iptables -I FORWARD 1 -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN"
echo "Added NYM-EXIT hook at position 1"
# Insert ACCEPT right after NYM-EXIT (position 2)
iptables -I FORWARD 2 -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT
echo "Added ACCEPT rule at position 2 (after NYM-EXIT)"
# Same for IPv6
while ip6tables -D FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT 2>/dev/null; do
echo "Removed IPv6 ACCEPT rule"
done
ip6tables -D FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null || true
ip6tables -I FORWARD 1 -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN"
ip6tables -I FORWARD 2 -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j ACCEPT
echo "Fixed IPv6 rules"
echo ""
echo "=== New FORWARD chain order ==="
iptables -L FORWARD -n --line-numbers | head -10
echo ""
echo "=== Verify NYM-EXIT is before ACCEPT ==="
iptables -L FORWARD -n --line-numbers | grep -E "$WG_INTERFACE|$NYM_CHAIN" | head -5
@@ -0,0 +1,26 @@
#!/bin/bash
# Remove exit policy rules (use this if accidentally applied to entry gateway)
WG_INTERFACE="nymwg"
NETWORK_DEVICE=$(ip route show default | awk '/default/ {print $5}')
NYM_CHAIN="NYM-EXIT"
echo "Removing exit policy rules..."
# Remove NYM-EXIT hooks from FORWARD chain
iptables -D FORWARD -i "$WG_INTERFACE" -o "$NETWORK_DEVICE" -j "$NYM_CHAIN" 2>/dev/null || true
iptables -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
ip6tables -D FORWARD -o "$WG_INTERFACE" -j "$NYM_CHAIN" 2>/dev/null || true
# Flush and delete NYM-EXIT chains
iptables -F "$NYM_CHAIN" 2>/dev/null || true
iptables -X "$NYM_CHAIN" 2>/dev/null || true
ip6tables -F "$NYM_CHAIN" 2>/dev/null || true
ip6tables -X "$NYM_CHAIN" 2>/dev/null || true
echo "✓ Exit policy rules removed"
echo ""
echo "=== Current FORWARD chain (first 10 rules) ==="
iptables -L FORWARD -n --line-numbers | head -10
@@ -0,0 +1,699 @@
#!/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 -I "$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 -I "$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" <<EOF
ExitPolicy reject 5.188.10.0/23:*
ExitPolicy reject 31.132.36.0/22:*
ExitPolicy reject 37.9.42.0/24:*
ExitPolicy reject 45.43.128.0/18:*
ExitPolicy reject *:*
EOF
fi
# Count and process rules
total_rules=$(grep -c "^ExitPolicy reject" "$POLICY_FILE" | grep -v "\*:\*")
echo -e "${YELLOW}Processing $total_rules blocklist rules...${NC}"
# Extract and apply IP block rules
grep "^ExitPolicy reject" "$POLICY_FILE" | grep -v "\*:\*" |
while read -r line; do
# Extract IP range
ip_range=$(echo "$line" | sed -E 's/ExitPolicy reject ([^:]+):.*/\1/')
# Apply rule if it's a valid IP range
if [[ -n "$ip_range" ]]; then
# Skip if the rule already exists
if ! iptables -C "$NYM_CHAIN" -d "$ip_range" -j REJECT 2>/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 <interface>${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 <<EOF
#!/bin/sh
iptables-restore < /etc/iptables.rules
ip6tables-restore < /etc/ip6tables.rules
EOF
chmod +x /etc/network/if-pre-up.d/iptables
echo -e "${GREEN}Created pre-up script to load rules at boot${NC}"
fi
fi
}
show_status() {
echo -e "${YELLOW}Nym Exit Policy Status:${NC}"
echo -e "${YELLOW}----------------------${NC}"
# Network information
echo -e "${GREEN}Network Device:${NC} $NETWORK_DEVICE"
echo -e "${GREEN}Wireguard Interface:${NC} $WG_INTERFACE"
# Interface check
if ! ip link show "$WG_INTERFACE" &>/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 <interface> 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 "$@"