241 lines
		
	
	
	
		
			7.4 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			241 lines
		
	
	
	
		
			7.4 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable file
		
	
	
	
	
| #!/bin/bash
 | |
| 
 | |
| #############################################################
 | |
| #                    scripts/killswitch.sh                 #
 | |
| #############################################################
 | |
| 
 | |
| cat > scripts/killswitch.sh << 'EOFKILLSWITCH'
 | |
| #!/bin/bash
 | |
| 
 | |
| # VPN Gateway Killswitch Script
 | |
| # CRITICAL: This script ensures NO traffic leaks without VPN
 | |
| # Version: 1.0.0
 | |
| 
 | |
| set -e
 | |
| 
 | |
| # Colors for output
 | |
| RED='\033[0;31m'
 | |
| GREEN='\033[0;32m'
 | |
| YELLOW='\033[1;33m'
 | |
| NC='\033[0m'
 | |
| 
 | |
| # Get network configuration from install
 | |
| if [ -f /opt/vpn-gateway/network.conf ]; then
 | |
|     source /opt/vpn-gateway/network.conf
 | |
| else
 | |
|     # Fallback to auto-detection
 | |
|     LAN_IF=$(ip route | grep default | awk '{print $5}' | head -n1)
 | |
|     LAN_NET=$(ip route | grep "$LAN_IF" | grep -v default | awk '{print $1}' | head -n1)
 | |
| fi
 | |
| 
 | |
| # Logging
 | |
| log() {
 | |
|     echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> /var/log/vpn-killswitch.log
 | |
|     echo -e "${GREEN}[+]${NC} $1"
 | |
| }
 | |
| 
 | |
| error() {
 | |
|     echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: $1" >> /var/log/vpn-killswitch.log
 | |
|     echo -e "${RED}[!]${NC} $1"
 | |
| }
 | |
| 
 | |
| warning() {
 | |
|     echo "[$(date '+%Y-%m-%d %H:%M:%S')] WARNING: $1" >> /var/log/vpn-killswitch.log
 | |
|     echo -e "${YELLOW}[*]${NC} $1"
 | |
| }
 | |
| 
 | |
| enable_killswitch() {
 | |
|     log "ENABLING PERMANENT KILLSWITCH - NO INTERNET WITHOUT VPN"
 | |
|     
 | |
|     # Backup current rules (just in case)
 | |
|     iptables-save > /tmp/iptables.backup.$(date +%s) 2>/dev/null || true
 | |
|     
 | |
|     # Reset all rules
 | |
|     iptables -F
 | |
|     iptables -X
 | |
|     iptables -t nat -F
 | |
|     iptables -t nat -X
 | |
|     iptables -t mangle -F
 | |
|     iptables -t mangle -X
 | |
|     iptables -t raw -F
 | |
|     iptables -t raw -X
 | |
|     
 | |
|     # DEFAULT POLICIES: DROP EVERYTHING
 | |
|     iptables -P INPUT DROP
 | |
|     iptables -P FORWARD DROP
 | |
|     iptables -P OUTPUT DROP
 | |
|     
 | |
|     log "Default policies set to DROP"
 | |
|     
 | |
|     # CRITICAL: Allow loopback (required for system operation)
 | |
|     iptables -A INPUT -i lo -j ACCEPT
 | |
|     iptables -A OUTPUT -o lo -j ACCEPT
 | |
|     
 | |
|     # Allow LAN communication (for WebUI and local clients)
 | |
|     if [ -n "$LAN_IF" ] && [ -n "$LAN_NET" ]; then
 | |
|         iptables -A INPUT -i $LAN_IF -s $LAN_NET -j ACCEPT
 | |
|         iptables -A OUTPUT -o $LAN_IF -d $LAN_NET -j ACCEPT
 | |
|         log "LAN communication allowed: $LAN_IF ($LAN_NET)"
 | |
|     fi
 | |
|     
 | |
|     # Allow DNS for initial VPN connection (root only, limited)
 | |
|     iptables -A OUTPUT -p udp --dport 53 -m owner --uid-owner root -m limit --limit 10/min -j ACCEPT
 | |
|     iptables -A OUTPUT -p tcp --dport 53 -m owner --uid-owner root -m limit --limit 10/min -j ACCEPT
 | |
|     
 | |
|     # Allow DHCP client (if needed)
 | |
|     iptables -A OUTPUT -p udp --sport 68 --dport 67 -j ACCEPT
 | |
|     iptables -A INPUT -p udp --sport 67 --dport 68 -j ACCEPT
 | |
|     
 | |
|     # Allow established/related connections
 | |
|     iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
 | |
|     iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
 | |
|     iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
 | |
|     
 | |
|     # Allow forwarding from LAN (will only work when VPN is up)
 | |
|     if [ -n "$LAN_IF" ] && [ -n "$LAN_NET" ]; then
 | |
|         iptables -A FORWARD -i $LAN_IF -s $LAN_NET -j ACCEPT
 | |
|     fi
 | |
|     
 | |
|     # Log dropped packets (optional, can be verbose)
 | |
|     # iptables -A INPUT -j LOG --log-prefix "INPUT-DROP: " --log-level 4
 | |
|     # iptables -A OUTPUT -j LOG --log-prefix "OUTPUT-DROP: " --log-level 4
 | |
|     
 | |
|     # IPv6: Complete blocking (unless you use IPv6 VPN)
 | |
|     ip6tables -P INPUT DROP
 | |
|     ip6tables -P FORWARD DROP
 | |
|     ip6tables -P OUTPUT DROP
 | |
|     ip6tables -A INPUT -i lo -j ACCEPT
 | |
|     ip6tables -A OUTPUT -o lo -j ACCEPT
 | |
|     
 | |
|     # Save rules for persistence
 | |
|     mkdir -p /etc/iptables
 | |
|     iptables-save > /etc/iptables/rules.v4
 | |
|     ip6tables-save > /etc/iptables/rules.v6
 | |
|     
 | |
|     # Ensure persistence across reboots
 | |
|     if ! systemctl is-enabled netfilter-persistent >/dev/null 2>&1; then
 | |
|         systemctl enable netfilter-persistent 2>/dev/null || true
 | |
|     fi
 | |
|     
 | |
|     log "KILLSWITCH ACTIVE - System is now protected"
 | |
|     log "Rules saved to /etc/iptables/"
 | |
|     
 | |
|     # Verify killswitch is working
 | |
|     verify_killswitch
 | |
| }
 | |
| 
 | |
| disable_killswitch() {
 | |
|     error "KILLSWITCH CANNOT BE DISABLED FOR SECURITY REASONS!"
 | |
|     warning "This is a security feature. The killswitch must remain active."
 | |
|     warning "If you really need to disable it, you must manually flush iptables rules."
 | |
|     warning "This would leave your system vulnerable to leaks!"
 | |
|     
 | |
|     # Re-enable killswitch immediately
 | |
|     enable_killswitch
 | |
|     
 | |
|     return 1
 | |
| }
 | |
| 
 | |
| verify_killswitch() {
 | |
|     log "Verifying killswitch status..."
 | |
|     
 | |
|     # Check DROP policies
 | |
|     if iptables -L -n | grep -q "Chain INPUT (policy DROP)" && \
 | |
|        iptables -L -n | grep -q "Chain OUTPUT (policy DROP)" && \
 | |
|        iptables -L -n | grep -q "Chain FORWARD (policy DROP)"; then
 | |
|         log "✓ Killswitch policies verified: DROP"
 | |
|     else
 | |
|         error "✗ Killswitch policies NOT active!"
 | |
|         enable_killswitch
 | |
|         return 1
 | |
|     fi
 | |
|     
 | |
|     # Test that we cannot reach internet directly
 | |
|     if ping -c 1 -W 1 8.8.8.8 >/dev/null 2>&1; then
 | |
|         if wg show wg0 >/dev/null 2>&1; then
 | |
|             log "✓ Internet accessible (VPN is connected)"
 | |
|         else
 | |
|             error "✗ LEAK DETECTED: Internet accessible without VPN!"
 | |
|             enable_killswitch
 | |
|             return 1
 | |
|         fi
 | |
|     else
 | |
|         if wg show wg0 >/dev/null 2>&1; then
 | |
|             warning "VPN appears connected but internet not reachable"
 | |
|         else
 | |
|             log "✓ Internet blocked (VPN not connected)"
 | |
|         fi
 | |
|     fi
 | |
|     
 | |
|     log "Killswitch verification complete"
 | |
| }
 | |
| 
 | |
| status_killswitch() {
 | |
|     echo -e "${GREEN}=== VPN Killswitch Status ===${NC}"
 | |
|     echo ""
 | |
|     
 | |
|     # Check policies
 | |
|     echo "Firewall Policies:"
 | |
|     iptables -L -n | grep "Chain.*policy" | while read line; do
 | |
|         if echo "$line" | grep -q "DROP"; then
 | |
|             echo -e "  ${GREEN}✓${NC} $line"
 | |
|         else
 | |
|             echo -e "  ${RED}✗${NC} $line"
 | |
|         fi
 | |
|     done
 | |
|     
 | |
|     echo ""
 | |
|     echo "Active Rules Summary:"
 | |
|     echo "  INPUT:   $(iptables -L INPUT -n | grep -c ACCEPT) ACCEPT rules"
 | |
|     echo "  OUTPUT:  $(iptables -L OUTPUT -n | grep -c ACCEPT) ACCEPT rules"
 | |
|     echo "  FORWARD: $(iptables -L FORWARD -n | grep -c ACCEPT) ACCEPT rules"
 | |
|     
 | |
|     echo ""
 | |
|     echo "VPN Status:"
 | |
|     if wg show wg0 >/dev/null 2>&1; then
 | |
|         echo -e "  ${GREEN}✓${NC} WireGuard interface active"
 | |
|         echo "  Endpoint: $(wg show wg0 endpoints | awk '{print $2}')"
 | |
|     else
 | |
|         echo -e "  ${YELLOW}⚠${NC} WireGuard interface not active"
 | |
|     fi
 | |
|     
 | |
|     echo ""
 | |
|     echo "Leak Test:"
 | |
|     if ping -c 1 -W 1 8.8.8.8 >/dev/null 2>&1; then
 | |
|         if wg show wg0 >/dev/null 2>&1; then
 | |
|             echo -e "  ${GREEN}✓${NC} Internet accessible via VPN"
 | |
|         else
 | |
|             echo -e "  ${RED}✗ LEAK: Internet accessible without VPN!${NC}"
 | |
|         fi
 | |
|     else
 | |
|         echo -e "  ${GREEN}✓${NC} Internet blocked (killswitch working)"
 | |
|     fi
 | |
| }
 | |
| 
 | |
| # Main logic
 | |
| case "${1:-enable}" in
 | |
|     enable|start)
 | |
|         enable_killswitch
 | |
|         ;;
 | |
|     disable|stop)
 | |
|         disable_killswitch
 | |
|         ;;
 | |
|     verify|check)
 | |
|         verify_killswitch
 | |
|         ;;
 | |
|     status)
 | |
|         status_killswitch
 | |
|         ;;
 | |
|     restart|reload)
 | |
|         enable_killswitch
 | |
|         ;;
 | |
|     *)
 | |
|         echo "Usage: $0 {enable|disable|verify|status|restart}"
 | |
|         echo "  enable  - Enable killswitch (default)"
 | |
|         echo "  disable - Disable killswitch (blocked for security)"
 | |
|         echo "  verify  - Verify killswitch is working"
 | |
|         echo "  status  - Show detailed status"
 | |
|         echo "  restart - Restart killswitch"
 | |
|         exit 1
 | |
|         ;;
 | |
| esac
 |