import { useState } from 'react' import axios from 'axios' import './App.css' const API_URL = 'http://localhost:8000' function App() { const [ipAddress, setIpAddress] = useState('') const [cidr, setCidr] = useState('24') const [subnetMask, setSubnetMask] = useState('') const [inputType, setInputType] = useState('cidr') // 'cidr' or 'mask' const [result, setResult] = useState(null) const [loading, setLoading] = useState(false) const [error, setError] = useState('') // Validate IP address format const validateIpAddress = (ip) => { if (!ip || !ip.trim()) { return 'IP address is required' } const ipPattern = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/ if (!ipPattern.test(ip)) { return 'Invalid IP format. Expected: xxx.xxx.xxx.xxx' } const octets = ip.split('.') for (let i = 0; i < octets.length; i++) { const num = parseInt(octets[i]) if (isNaN(num) || num < 0 || num > 255) { return `Invalid octet ${i + 1}: must be between 0-255` } } return null } // Validate subnet mask format const validateSubnetMask = (mask) => { if (!mask || !mask.trim()) { return 'Subnet mask is required' } const parts = mask.split('.') if (parts.length !== 4) { return 'Subnet mask must have 4 octets' } // Check each octet is 0-255 for (let part of parts) { const num = parseInt(part) if (isNaN(num) || num < 0 || num > 255) { return 'Each octet must be between 0-255' } } // Common valid subnet masks const validMasks = [ '255.255.255.255', '255.255.255.254', '255.255.255.252', '255.255.255.248', '255.255.255.240', '255.255.255.224', '255.255.255.192', '255.255.255.128', '255.255.255.0', '255.255.254.0', '255.255.252.0', '255.255.248.0', '255.255.240.0', '255.255.224.0', '255.255.192.0', '255.255.128.0', '255.255.0.0', '255.254.0.0', '255.252.0.0', '255.248.0.0', '255.240.0.0', '255.224.0.0', '255.192.0.0', '255.128.0.0', '255.0.0.0', '254.0.0.0', '252.0.0.0', '248.0.0.0', '240.0.0.0', '224.0.0.0', '192.0.0.0', '128.0.0.0', '0.0.0.0' ] if (!validMasks.includes(mask)) { return 'Invalid subnet mask (bits must be contiguous)' } return null } const calculateSubnet = async (e) => { e.preventDefault() setError('') setResult(null) // Frontend validation const ipError = validateIpAddress(ipAddress) if (ipError) { setError(ipError) return } if (inputType === 'cidr') { const cidrNum = parseInt(cidr) if (isNaN(cidrNum) || cidrNum < 0 || cidrNum > 32) { setError('CIDR must be between 0 and 32') return } } else { const maskError = validateSubnetMask(subnetMask) if (maskError) { setError(maskError) return } } setLoading(true) try { const payload = { ip_address: ipAddress, } if (inputType === 'cidr') { payload.cidr = parseInt(cidr) } else { payload.subnet_mask = subnetMask } const response = await axios.post(`${API_URL}/calculate`, payload) setResult(response.data) } catch (err) { const errorMessage = err.response?.data?.detail || err.message || 'Failed to calculate subnet' setError(errorMessage) } finally { setLoading(false) } } const InfoCard = ({ label, value, highlight }) => (
{label}
{value}
) const BinaryCard = ({ label, decimal, binary }) => (
{label}
{decimal}
{binary}
) // Calculate ALL next sequential networks based on the current network const calculateNetworkRanges = (result) => { const networkId = result.network_id const cidr = result.cidr const totalAddresses = result.total_hosts // Parse network ID to get starting IP const parts = networkId.split('.').map(Number) let networkNum = (parts[0] << 24) + (parts[1] << 16) + (parts[2] << 8) + parts[3] const networks = [] // Calculate all possible networks until end of IPv4 space // For performance, limit to 10000 networks max const maxNetworks = 10000 let count = 0 // Generate next sequential networks while (count < maxNetworks) { const currentNetworkNum = networkNum + (count * totalAddresses) // Check if we're still within valid IPv4 range const broadcastNum = currentNetworkNum + totalAddresses - 1 if (currentNetworkNum > 0xFFFFFFFF || broadcastNum > 0xFFFFFFFF) break // Convert number back to IP address const networkAddress = `${(currentNetworkNum >>> 24) & 0xFF}.${(currentNetworkNum >>> 16) & 0xFF}.${(currentNetworkNum >>> 8) & 0xFF}.${currentNetworkNum & 0xFF}` const broadcastAddress = `${(broadcastNum >>> 24) & 0xFF}.${(broadcastNum >>> 16) & 0xFF}.${(broadcastNum >>> 8) & 0xFF}.${broadcastNum & 0xFF}` // Calculate first and last usable IPs let firstUsable, lastUsable if (cidr === 32) { firstUsable = networkAddress lastUsable = networkAddress } else if (cidr === 31) { firstUsable = networkAddress lastUsable = broadcastAddress } else { const firstUsableNum = currentNetworkNum + 1 const lastUsableNum = broadcastNum - 1 firstUsable = `${(firstUsableNum >>> 24) & 0xFF}.${(firstUsableNum >>> 16) & 0xFF}.${(firstUsableNum >>> 8) & 0xFF}.${firstUsableNum & 0xFF}` lastUsable = `${(lastUsableNum >>> 24) & 0xFF}.${(lastUsableNum >>> 16) & 0xFF}.${(lastUsableNum >>> 8) & 0xFF}.${lastUsableNum & 0xFF}` } networks.push({ networkAddress: `${networkAddress}/${cidr}`, firstUsable, lastUsable, broadcastAddress, usableHosts: result.usable_hosts }) count++ } return networks } return (

🌐 IP Subnet Calculator

setIpAddress(e.target.value)} placeholder="e.g., 192.168.1.1" required />
{inputType === 'cidr' ? (
setCidr(e.target.value)} required />
) : (
setSubnetMask(e.target.value)} placeholder="e.g., 255.255.255.0" required />
)}
{error && (
⚠️ {error}
)} {result && (

Subnet Information

{/* Binary Representation Section */}

Binary Representation

{/* Main Information Section */}

Network Details

{/* Next Networks Section */}

📊 All Next Sequential Networks ({calculateNetworkRanges(result).length.toLocaleString()} networks)

#
Network
Usable Range
Broadcast
Hosts
{calculateNetworkRanges(result).map((network, index) => (
{index + 1}
{network.networkAddress}
{network.firstUsable} - {network.lastUsable}
{network.broadcastAddress}
{network.usableHosts.toLocaleString()}
))}
)}
) } export default App