wip: wireguard

This commit is contained in:
Cloud
2025-09-14 03:31:14 -05:00
parent 5bd7443681
commit bb6ccfe023
8 changed files with 1468 additions and 91 deletions
+43 -1
View File
@@ -832,6 +832,44 @@ def update_peer_ip():
logger.error(f"Error updating peer IP: {e}")
return jsonify({"error": str(e)}), 500
@app.route('/api/wireguard/peers/status', methods=['POST'])
def get_peer_status():
"""Get WireGuard peer status."""
try:
data = request.get_json(silent=True)
if data is None or 'public_key' not in data:
return jsonify({"error": "Missing public key"}), 400
public_key = data['public_key']
status = wireguard_manager.get_peer_status(public_key)
return jsonify(status)
except Exception as e:
logger.error(f"Error getting peer status: {e}")
return jsonify({"error": str(e)}), 500
@app.route('/api/wireguard/network/setup', methods=['POST'])
def setup_network():
"""Setup network configuration for internet access."""
try:
success = wireguard_manager.setup_network_configuration()
if success:
return jsonify({"message": "Network configuration setup completed successfully"})
else:
return jsonify({"error": "Failed to setup network configuration"}), 500
except Exception as e:
logger.error(f"Error setting up network configuration: {e}")
return jsonify({"error": str(e)}), 500
@app.route('/api/wireguard/network/status', methods=['GET'])
def get_network_status():
"""Get network configuration status."""
try:
status = wireguard_manager.get_network_status()
return jsonify(status)
except Exception as e:
logger.error(f"Error getting network status: {e}")
return jsonify({"error": str(e)}), 500
@app.route('/api/wireguard/peers/config', methods=['POST'])
def get_peer_config():
try:
@@ -849,10 +887,14 @@ def get_peer_config():
# Get server configuration
server_config = wireguard_manager.get_server_config()
# Check if IP already has a subnet mask, if not add /32
peer_ip = peer.get('ip', '10.0.0.2')
peer_address = peer_ip if '/' in peer_ip else f"{peer_ip}/32"
# Generate client configuration using peer registry data
config = f"""[Interface]
PrivateKey = {peer.get('private_key', 'YOUR_PRIVATE_KEY_HERE')}
Address = {peer.get('ip', '10.0.0.2')}/32
Address = {peer_address}
DNS = 8.8.8.8, 1.1.1.1
[Peer]
+239 -6
View File
@@ -331,13 +331,62 @@ AllowedIPs = {allowed_ips}
raise
def _reload_wireguard_config(self):
"""Reload WireGuard configuration"""
"""Reload WireGuard configuration by updating the main config file"""
try:
# This would typically involve restarting the WireGuard service
# or reloading the configuration
logger.info("WireGuard configuration reloaded")
# Read the main server configuration
server_config_path = os.path.join(self.wg_config_dir, 'wg_confs', 'wg0.conf')
if not os.path.exists(server_config_path):
logger.error("Server configuration file not found")
return False
with open(server_config_path, 'r') as f:
server_content = f.read()
# Find the end of the [Interface] section
lines = server_content.split('\n')
interface_end = 0
for i, line in enumerate(lines):
if line.strip().startswith('[Peer]'):
interface_end = i
break
else:
interface_end = len(lines)
# Keep only the [Interface] section
interface_lines = lines[:interface_end]
# Add all peer configurations
peer_lines = []
for filename in os.listdir(self.peers_dir):
if filename.endswith('.conf') and not filename.endswith('_keys.json'):
peer_file = os.path.join(self.peers_dir, filename)
with open(peer_file, 'r') as f:
peer_content = f.read().strip()
if peer_content:
peer_lines.append('') # Empty line before peer
peer_lines.extend(peer_content.split('\n'))
# Combine interface and peer configurations
new_content = '\n'.join(interface_lines + peer_lines)
# Write the updated configuration
with open(server_config_path, 'w') as f:
f.write(new_content)
# Restart WireGuard container to apply changes
import subprocess
result = subprocess.run(['docker', 'restart', 'cell-wireguard'],
capture_output=True, text=True, timeout=30)
if result.returncode == 0:
logger.info("WireGuard configuration reloaded and container restarted")
return True
else:
logger.error(f"Failed to restart WireGuard container: {result.stderr}")
return False
except Exception as e:
logger.error(f"Failed to reload WireGuard configuration: {e}")
return False
def get_metrics(self) -> Dict[str, Any]:
"""Get WireGuard metrics"""
@@ -528,9 +577,13 @@ AllowedIPs = {allowed_ips}
# Get peer private key from peer data
peer_private_key = peer_info.get('private_key', 'YOUR_PRIVATE_KEY_HERE')
# Check if IP already has a subnet mask, if not add /32
peer_ip = peer_info.get('ip', '10.0.0.2')
peer_address = peer_ip if '/' in peer_ip else f"{peer_ip}/32"
config = f"""[Interface]
PrivateKey = {peer_private_key}
Address = {peer_info.get('ip', '10.0.0.2')}/32
Address = {peer_address}
DNS = 8.8.8.8, 1.1.1.1
[Peer]
@@ -660,4 +713,184 @@ PersistentKeepalive = {peer_info.get('persistent_keepalive', 25)}"""
return {
'public_key': 'SERVER_PUBLIC_KEY_PLACEHOLDER',
'endpoint': 'YOUR_SERVER_IP:51820'
}
}
def get_peer_status(self, public_key: str) -> Dict[str, Any]:
"""Get status for a specific peer"""
try:
# Get WireGuard interface status
result = subprocess.run(['wg', 'show'], capture_output=True, text=True, check=True)
wg_output = result.stdout
# Parse the output to find the specific peer
lines = wg_output.strip().split('\n')
peer_info = {}
in_peer = False
for line in lines:
if line.startswith('peer:') and public_key in line:
in_peer = True
peer_info['public_key'] = public_key
elif line.startswith('peer:') and public_key not in line:
in_peer = False
elif in_peer and line.startswith(' allowed ips:'):
peer_info['allowed_ips'] = line.split(':', 1)[1].strip()
elif in_peer and line.startswith(' latest handshake:'):
handshake_str = line.split(':', 1)[1].strip()
if handshake_str and handshake_str != '(none)':
peer_info['latest_handshake'] = handshake_str
peer_info['online'] = True
else:
peer_info['online'] = False
elif in_peer and line.startswith(' transfer:'):
transfer_str = line.split(':', 1)[1].strip()
if transfer_str and transfer_str != '(none)':
# Parse transfer data (e.g., "1.2 KiB received, 3.4 KiB sent")
parts = transfer_str.split(',')
if len(parts) >= 2:
rx_part = parts[0].strip()
tx_part = parts[1].strip()
# Extract numbers from strings like "1.2 KiB received"
import re
rx_match = re.search(r'([\d.]+)\s+(\w+)', rx_part)
tx_match = re.search(r'([\d.]+)\s+(\w+)', tx_part)
if rx_match and tx_match:
rx_value = float(rx_match.group(1))
rx_unit = rx_match.group(2)
tx_value = float(tx_match.group(1))
tx_unit = tx_match.group(2)
# Convert to bytes
def convert_to_bytes(value, unit):
multipliers = {'B': 1, 'KiB': 1024, 'MiB': 1024**2, 'GiB': 1024**3}
return int(value * multipliers.get(unit, 1))
peer_info['transfer_rx'] = convert_to_bytes(rx_value, rx_unit)
peer_info['transfer_tx'] = convert_to_bytes(tx_value, tx_unit)
# Set default values if not found
if 'online' not in peer_info:
peer_info['online'] = False
if 'transfer_rx' not in peer_info:
peer_info['transfer_rx'] = 0
if 'transfer_tx' not in peer_info:
peer_info['transfer_tx'] = 0
if 'latest_handshake' not in peer_info:
peer_info['latest_handshake'] = None
return peer_info
except Exception as e:
logger.error(f"Failed to get peer status for {public_key}: {e}")
return {'online': False, 'transfer_rx': 0, 'transfer_tx': 0, 'latest_handshake': None}
def setup_network_configuration(self) -> bool:
"""Setup network configuration for internet access"""
try:
logger.info("Setting up network configuration for internet access...")
# Enable IP forwarding
self._enable_ip_forwarding()
# Configure NAT and routing
self._configure_nat_routing()
logger.info("Network configuration completed successfully")
return True
except Exception as e:
logger.error(f"Failed to setup network configuration: {e}")
return False
def _enable_ip_forwarding(self):
"""Enable IP forwarding"""
try:
# Enable IP forwarding in the container
subprocess.run(['sh', '-c', 'echo 1 > /proc/sys/net/ipv4/ip_forward'], check=True)
logger.info("IP forwarding enabled")
except Exception as e:
logger.error(f"Failed to enable IP forwarding: {e}")
raise
def _configure_nat_routing(self):
"""Configure NAT and routing for internet access"""
try:
# Get the main network interface
result = subprocess.run(['ip', 'route', 'show', 'default'], capture_output=True, text=True, check=True)
main_interface = result.stdout.split()[4] # Extract interface name
# Configure iptables rules
rules = [
# Allow forwarding for WireGuard interface
f"iptables -A FORWARD -i wg0 -j ACCEPT",
f"iptables -A FORWARD -o wg0 -j ACCEPT",
# NAT rule for internet access
f"iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o {main_interface} -j MASQUERADE",
# Allow established and related connections
"iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT"
]
for rule in rules:
try:
subprocess.run(['sh', '-c', rule], check=True)
except subprocess.CalledProcessError as e:
logger.warning(f"Rule may already exist: {rule} - {e}")
logger.info(f"NAT and routing configured for interface {main_interface}")
except Exception as e:
logger.error(f"Failed to configure NAT routing: {e}")
raise
def get_network_status(self) -> Dict[str, Any]:
"""Get network configuration status"""
try:
status = {
'ip_forwarding': self._check_ip_forwarding(),
'nat_rules': self._check_nat_rules(),
'forwarding_rules': self._check_forwarding_rules(),
'interface_status': self._check_interface_status(),
'timestamp': datetime.utcnow().isoformat()
}
return status
except Exception as e:
logger.error(f"Failed to get network status: {e}")
return {'error': str(e)}
def _check_ip_forwarding(self) -> bool:
"""Check if IP forwarding is enabled"""
try:
# Check in WireGuard container
result = subprocess.run(['docker', 'exec', 'cell-wireguard', 'cat', '/proc/sys/net/ipv4/ip_forward'], capture_output=True, text=True, check=True)
return result.stdout.strip() == '1'
except:
return False
def _check_nat_rules(self) -> bool:
"""Check if NAT rules are configured"""
try:
# Check in WireGuard container
result = subprocess.run(['docker', 'exec', 'cell-wireguard', 'iptables', '-t', 'nat', '-L', 'POSTROUTING', '-n'], capture_output=True, text=True, check=True)
return 'MASQUERADE' in result.stdout
except:
return False
def _check_forwarding_rules(self) -> bool:
"""Check if forwarding rules are configured"""
try:
# Check in WireGuard container
result = subprocess.run(['docker', 'exec', 'cell-wireguard', 'iptables', '-L', 'FORWARD', '-n'], capture_output=True, text=True, check=True)
# Check for ACCEPT rules (which indicate forwarding is allowed)
return 'ACCEPT' in result.stdout and len(result.stdout.strip().split('\n')) > 2
except:
return False
def _check_interface_status(self) -> bool:
"""Check if WireGuard interface is up"""
try:
# Check in WireGuard container
result = subprocess.run(['docker', 'exec', 'cell-wireguard', 'ip', 'link', 'show', 'wg0'], capture_output=True, text=True, check=True)
return 'UP' in result.stdout
except:
return False