import { useState, useEffect } from 'react'; import { Plus, Trash2, Wifi, Shield, Activity, Settings } from 'lucide-react'; import { routingAPI } from '../services/api'; function Routing() { const [routingStatus, setRoutingStatus] = useState(null); const [isLoading, setIsLoading] = useState(true); const [activeTab, setActiveTab] = useState('overview'); // NAT management state const [natRules, setNatRules] = useState([]); const [natLoading, setNatLoading] = useState(false); const [natError, setNatError] = useState(null); const [showNatForm, setShowNatForm] = useState(false); const [newNat, setNewNat] = useState({ source_network: '', target_interface: '', masquerade: true, nat_type: 'MASQUERADE', protocol: 'ALL', external_port: '', internal_ip: '', internal_port: '' }); const [natSubmitting, setNatSubmitting] = useState(false); // Peer Routes management state const [peerRoutes, setPeerRoutes] = useState([]); const [peersLoading, setPeersLoading] = useState(false); const [peersError, setPeersError] = useState(null); const [showPeerForm, setShowPeerForm] = useState(false); const [newPeerRoute, setNewPeerRoute] = useState({ peer_name: '', peer_ip: '', allowed_networks: '', route_type: 'lan' }); const [peerSubmitting, setPeerSubmitting] = useState(false); // Firewall Rules management state const [firewallRules, setFirewallRules] = useState([]); const [fwLoading, setFwLoading] = useState(false); const [fwError, setFwError] = useState(null); const [showFwForm, setShowFwForm] = useState(false); const [newFwRule, setNewFwRule] = useState({ rule_type: 'INPUT', source: '', destination: '', action: 'ACCEPT', protocol: 'ALL', port_range: '' }); const [fwSubmitting, setFwSubmitting] = useState(false); // Network Configuration state const [networkStatus, setNetworkStatus] = useState(null); const [networkLoading, setNetworkLoading] = useState(false); const [networkError, setNetworkError] = useState(null); const [isSettingUp, setIsSettingUp] = useState(false); useEffect(() => { fetchRoutingStatus(); fetchNatRules(); fetchPeerRoutes(); fetchFirewallRules(); fetchNetworkStatus(); }, []); const fetchRoutingStatus = async () => { try { const response = await routingAPI.getStatus(); setRoutingStatus(response.data); } catch (error) { console.error('Failed to fetch routing status:', error); } finally { setIsLoading(false); } }; const fetchNatRules = async () => { setNatLoading(true); setNatError(null); try { const response = await routingAPI.getNatRules(); setNatRules(response.data.nat_rules || []); } catch (error) { setNatError('Failed to load NAT rules'); } finally { setNatLoading(false); } }; const fetchPeerRoutes = async () => { setPeersLoading(true); setPeersError(null); try { const response = await routingAPI.getPeerRoutes(); setPeerRoutes(response.data.peer_routes || []); } catch (error) { setPeersError('Failed to load peer routes'); } finally { setPeersLoading(false); } }; const fetchFirewallRules = async () => { setFwLoading(true); setFwError(null); try { const response = await routingAPI.getFirewallRules(); setFirewallRules(response.data.firewall_rules || []); } catch (error) { setFwError('Failed to load firewall rules'); } finally { setFwLoading(false); } }; const fetchNetworkStatus = async () => { setNetworkLoading(true); setNetworkError(null); try { const response = await fetch('http://localhost:3000/api/wireguard/network/status'); if (response.ok) { const data = await response.json(); setNetworkStatus(data); } else { throw new Error('Failed to fetch network status'); } } catch (error) { console.error('Failed to fetch network status:', error); setNetworkError('Failed to fetch network status'); } finally { setNetworkLoading(false); } }; const setupNetworkConfiguration = async () => { setIsSettingUp(true); setNetworkError(null); try { const response = await fetch('http://localhost:3000/api/wireguard/network/setup', { method: 'POST', headers: { 'Content-Type': 'application/json', }, }); if (response.ok) { const data = await response.json(); console.log('Network setup successful:', data); // Refresh network status await fetchNetworkStatus(); } else { const errorData = await response.json(); throw new Error(errorData.error || 'Failed to setup network configuration'); } } catch (error) { console.error('Failed to setup network configuration:', error); setNetworkError(error.message); } finally { setIsSettingUp(false); } }; const handleNatInputChange = (e) => { const { name, value, type, checked } = e.target; setNewNat((prev) => ({ ...prev, [name]: type === 'checkbox' ? checked : value, })); }; const handleAddNatRule = async (e) => { e.preventDefault(); setNatSubmitting(true); setNatError(null); try { await routingAPI.addNatRule(newNat); setShowNatForm(false); setNewNat({ source_network: '', target_interface: '', masquerade: true, nat_type: 'MASQUERADE', protocol: 'ALL', external_port: '', internal_ip: '', internal_port: '' }); fetchNatRules(); fetchRoutingStatus(); } catch (error) { setNatError('Failed to add NAT rule'); } finally { setNatSubmitting(false); } }; const handleDeleteNatRule = async (ruleId) => { if (!window.confirm('Delete this NAT rule?')) return; setNatLoading(true); setNatError(null); try { await routingAPI.deleteNatRule(ruleId); fetchNatRules(); fetchRoutingStatus(); } catch (error) { setNatError('Failed to delete NAT rule'); } finally { setNatLoading(false); } }; const handlePeerInputChange = (e) => { const { name, value } = e.target; setNewPeerRoute((prev) => ({ ...prev, [name]: value })); }; const handleAddPeerRoute = async (e) => { e.preventDefault(); setPeerSubmitting(true); setPeersError(null); try { // allowed_networks: comma-separated string to array const payload = { ...newPeerRoute, allowed_networks: newPeerRoute.allowed_networks.split(',').map((s) => s.trim()).filter(Boolean), }; await routingAPI.addPeerRoute(payload); setShowPeerForm(false); setNewPeerRoute({ peer_name: '', peer_ip: '', allowed_networks: '', route_type: 'lan' }); fetchPeerRoutes(); fetchRoutingStatus(); } catch (error) { setPeersError('Failed to add peer route'); } finally { setPeerSubmitting(false); } }; const handleDeletePeerRoute = async (peerName) => { if (!window.confirm('Delete this peer route?')) return; setPeersLoading(true); setPeersError(null); try { await routingAPI.deletePeerRoute(peerName); fetchPeerRoutes(); fetchRoutingStatus(); } catch (error) { setPeersError('Failed to delete peer route'); } finally { setPeersLoading(false); } }; const handleFwInputChange = (e) => { const { name, value } = e.target; setNewFwRule((prev) => ({ ...prev, [name]: value })); }; const handleAddFwRule = async (e) => { e.preventDefault(); setFwSubmitting(true); setFwError(null); try { const payload = { ...newFwRule }; if (!payload.port) delete payload.port; await routingAPI.addFirewallRule(payload); setShowFwForm(false); setNewFwRule({ rule_type: 'INPUT', source: '', destination: '', action: 'ACCEPT', protocol: 'ALL', port_range: '' }); fetchFirewallRules(); fetchRoutingStatus(); } catch (error) { setFwError('Failed to add firewall rule'); } finally { setFwSubmitting(false); } }; const handleDeleteFwRule = async (ruleId) => { if (!window.confirm('Delete this firewall rule?')) return; setFwLoading(true); setFwError(null); try { await routingAPI.deleteFirewallRule(ruleId); fetchFirewallRules(); fetchRoutingStatus(); } catch (error) { setFwError('Failed to delete firewall rule'); } finally { setFwLoading(false); } }; if (isLoading) { return (
Manage VPN gateway, NAT rules, and routing configuration
NAT Rules
{routingStatus.nat_rules_count || 0}
Peer Routes
{routingStatus.peer_routes_count || 0}
Firewall Rules
{routingStatus.firewall_rules_count || 0}
Exit Nodes
{routingStatus.exit_nodes_count || 0}
No routing table entries available.
)}{networkError}
IP Forwarding
{networkStatus.ip_forwarding ? 'Enabled' : 'Disabled'}
WireGuard Interface
{networkStatus.interface_status ? 'Up' : 'Down'}
NAT Rules
{networkStatus.nat_rules ? 'Configured' : 'Missing'}
Forwarding Rules
{networkStatus.forwarding_rules ? 'Configured' : 'Missing'}
Failed to load network status
| Source Network | Target Interface | Masquerade | Type | Protocol | Ext Port | Int IP | Int Port | |
|---|---|---|---|---|---|---|---|---|
| {rule.source_network} | {rule.target_interface} | {rule.masquerade ? 'Yes' : 'No'} | {rule.nat_type || 'MASQUERADE'} | {rule.protocol || 'ALL'} | {rule.external_port || '-'} | {rule.internal_ip || '-'} | {rule.internal_port || '-'} |
| Peer Name | Peer IP | Allowed Networks | Route Type | |
|---|---|---|---|---|
| {route.peer_name} | {route.peer_ip} | {Array.isArray(route.allowed_networks) ? route.allowed_networks.join(', ') : route.allowed_networks} | {route.route_type} |
| Rule Type | Source | Destination | Protocol | Port/Range | Action | |
|---|---|---|---|---|---|---|
| {rule.rule_type} | {rule.source} | {rule.destination} | {rule.protocol || 'ALL'} | {rule.port_range || '-'} | {rule.action} |