Practical examples demonstrating how to use the IPv4 Subnet Calculator library in real-world scenarios.
- Network Planning and IPAM
- Firewall and Security
- BGP Route Summarization
- DHCP Scope Planning
- DNS Configuration
- Network Automation
Allocate subnets to different office locations from a corporate address block.
<?php
require_once(__DIR__ . '/vendor/autoload.php');
// Corporate allocation: 10.0.0.0/16
$corporateBlock = IPv4\Subnet::fromCidr('10.0.0.0/16');
// Office requirements
$offices = [
'New York' => 500,
'London' => 300,
'Tokyo' => 250,
'Sydney' => 150,
'Branch-Small' => 50,
];
echo "Corporate IP Allocation Plan\n";
echo str_repeat('=', 80) . "\n\n";
echo "Available: {$corporateBlock->cidr()}\n";
echo "Total IPs: {$corporateBlock->addressCount()}\n\n";
$currentNetwork = '10.0.0.0';
$allocations = [];
foreach ($offices as $office => $requiredHosts) {
// Find optimal subnet size
$optimalPrefix = IPv4\SubnetParser::optimalPrefixForHosts($requiredHosts);
$subnet = IPv4\Subnet::fromCidr("{$currentNetwork}/{$optimalPrefix}");
$allocations[$office] = $subnet;
echo "{$office}:\n";
echo " Required hosts: {$requiredHosts}\n";
echo " Allocated: {$subnet->cidr()}\n";
echo " Usable hosts: {$subnet->hostCount()}\n";
echo " Range: {$subnet->minHost()} - {$subnet->maxHost()}\n";
echo " Utilization: {$subnet->utilizationFor($requiredHosts)}%\n\n";
// Move to next available network
$currentNetwork = $subnet->next()->networkAddress()->asQuads();
}
// Calculate remaining space
$allocated = array_values($allocations);
$remaining = $corporateBlock->excludeAll($allocated);
echo "Remaining unallocated space:\n";
$totalRemaining = 0;
foreach ($remaining as $block) {
echo " {$block->cidr()} ({$block->addressCount()} IPs)\n";
$totalRemaining += $block->addressCount();
}
echo "\nTotal remaining: {$totalRemaining} IP addresses\n";Build a simple IPAM system that tracks allocations and automatically manages remaining space.
<?php
class SimpleIPAM {
private $name;
private $availableBlocks;
private $allocations;
public function __construct($name, $initialBlock) {
$this->name = $name;
$this->availableBlocks = [
IPv4\Subnet::fromCidr($initialBlock)
];
$this->allocations = [];
}
public function allocate($name, $cidr) {
$allocation = IPv4\Subnet::fromCidr($cidr);
// Check if requested subnet is available
$found = false;
foreach ($this->availableBlocks as $block) {
if ($block->contains($allocation)) {
$found = true;
break;
}
}
if (!$found) {
throw new \Exception("Requested subnet {$cidr} is not available in pool");
}
// Update available blocks by excluding allocation
$newAvailable = [];
foreach ($this->availableBlocks as $block) {
if ($block->contains($allocation)) {
$remaining = $block->exclude($allocation);
$newAvailable = array_merge($newAvailable, $remaining);
} else {
$newAvailable[] = $block;
}
}
$this->availableBlocks = $newAvailable;
$this->allocations[$name] = $allocation;
return $allocation;
}
public function findAvailableSubnet($requiredHosts) {
$optimalPrefix = IPv4\SubnetParser::optimalPrefixForHosts($requiredHosts);
foreach ($this->availableBlocks as $block) {
if ($block->networkSize() <= $optimalPrefix) {
// This block is large enough
$subnet = IPv4\Subnet::fromCidr(
$block->networkAddress()->asQuads() . '/' . $optimalPrefix
);
if ($block->contains($subnet)) {
return $subnet->cidr();
}
}
}
return null;
}
public function getUtilizationReport() {
$report = "IPAM Pool: {$this->name}\n";
$report .= str_repeat('=', 80) . "\n\n";
$report .= "Allocations:\n";
$report .= str_repeat('-', 80) . "\n";
foreach ($this->allocations as $name => $subnet) {
$report .= sprintf(" %-30s %s (%d IPs)\n",
$name,
$subnet->cidr(),
$subnet->addressCount()
);
}
$report .= "\nAvailable Blocks:\n";
$report .= str_repeat('-', 80) . "\n";
$totalAvailable = 0;
foreach ($this->availableBlocks as $block) {
$report .= sprintf(" %s (%d IPs)\n",
$block->cidr(),
$block->addressCount()
);
$totalAvailable += $block->addressCount();
}
$report .= "\nTotal available: {$totalAvailable} IP addresses\n";
return $report;
}
}
// Usage example
$ipam = new SimpleIPAM('Corporate Network', '10.0.0.0/16');
// Make allocations
$ipam->allocate('Web Servers', '10.0.0.0/24');
$ipam->allocate('Database Servers', '10.0.1.0/24');
$ipam->allocate('Application Servers', '10.0.2.0/23');
// Find available space for new requirement
$suggested = $ipam->findAvailableSubnet(100);
echo "Suggested subnet for 100 hosts: {$suggested}\n\n";
// Show utilization
echo $ipam->getUtilizationReport();Validate that firewall rules don't have conflicting or overlapping entries.
<?php
class FirewallRuleValidator {
private $rules = [];
public function addRule($name, $cidr, $action = 'allow') {
$subnet = IPv4\Subnet::fromCidr($cidr);
$this->rules[] = [
'name' => $name,
'subnet' => $subnet,
'cidr' => $cidr,
'action' => $action,
];
}
public function validateRules() {
$conflicts = [];
for ($i = 0; $i < count($this->rules); $i++) {
for ($j = $i + 1; $j < count($this->rules); $j++) {
$rule1 = $this->rules[$i];
$rule2 = $this->rules[$j];
if ($rule1['subnet']->overlaps($rule2['subnet'])) {
$conflicts[] = [
'rule1' => $rule1,
'rule2' => $rule2,
'type' => $this->getConflictType($rule1, $rule2),
];
}
}
}
return $conflicts;
}
private function getConflictType($rule1, $rule2) {
if ($rule1['subnet']->contains($rule2['subnet'])) {
return 'rule1_contains_rule2';
} elseif ($rule2['subnet']->contains($rule1['subnet'])) {
return 'rule2_contains_rule1';
} else {
return 'partial_overlap';
}
}
public function printValidationReport() {
echo "Firewall Rule Validation Report\n";
echo str_repeat('=', 80) . "\n\n";
$conflicts = $this->validateRules();
if (empty($conflicts)) {
echo "✓ No conflicts detected. All rules are valid.\n";
return;
}
echo "⚠ CONFLICTS DETECTED: " . count($conflicts) . "\n\n";
foreach ($conflicts as $i => $conflict) {
echo "Conflict #" . ($i + 1) . ":\n";
echo " Rule 1: {$conflict['rule1']['name']} ({$conflict['rule1']['cidr']}) - {$conflict['rule1']['action']}\n";
echo " Rule 2: {$conflict['rule2']['name']} ({$conflict['rule2']['cidr']}) - {$conflict['rule2']['action']}\n";
echo " Type: {$conflict['type']}\n";
if ($conflict['rule1']['action'] !== $conflict['rule2']['action']) {
echo " ⚠ WARNING: Conflicting actions ({$conflict['rule1']['action']} vs {$conflict['rule2']['action']})\n";
}
echo "\n";
}
}
}
// Usage
$validator = new FirewallRuleValidator();
// Add firewall rules
$validator->addRule('Allow Internal', '10.0.0.0/8', 'allow');
$validator->addRule('Allow Office A', '10.1.0.0/16', 'allow'); // Contained in Internal
$validator->addRule('Block Office A Guest', '10.1.100.0/24', 'deny'); // Conflicts!
$validator->addRule('Allow External Partners', '203.0.113.0/24', 'allow');
$validator->addRule('Allow Public Web', '0.0.0.0/0', 'allow'); // Contains everything!
$validator->printValidationReport();Implement access control based on IP address classification.
<?php
class AccessController {
public function checkAccess($ipAddress, $resource) {
$subnet = IPv4\Subnet::fromCidr($ipAddress . '/32');
// Define access policies
$policy = $this->getAccessPolicy($resource);
// Check IP type
if ($subnet->isPrivate()) {
return in_array('private', $policy['allowed_types']);
} elseif ($subnet->isPublic()) {
return in_array('public', $policy['allowed_types']);
} elseif ($subnet->isLoopback()) {
return in_array('loopback', $policy['allowed_types']);
}
return false;
}
private function getAccessPolicy($resource) {
$policies = [
'admin-panel' => [
'allowed_types' => ['private', 'loopback'],
],
'public-api' => [
'allowed_types' => ['public', 'private'],
],
'internal-api' => [
'allowed_types' => ['private'],
],
];
return $policies[$resource] ?? ['allowed_types' => []];
}
public function generateAccessReport($ipAddress) {
$subnet = IPv4\Subnet::fromCidr($ipAddress . '/32');
echo "Access Report for {$ipAddress}\n";
echo str_repeat('=', 80) . "\n";
echo "IP Type: {$subnet->addressType()->value}\n"; // Use ->value for string
echo "Private: " . ($subnet->isPrivate() ? 'Yes' : 'No') . "\n";
echo "Public: " . ($subnet->isPublic() ? 'Yes' : 'No') . "\n";
echo "Loopback: " . ($subnet->isLoopback() ? 'Yes' : 'No') . "\n\n";
echo "Access Permissions:\n";
$resources = ['admin-panel', 'public-api', 'internal-api'];
foreach ($resources as $resource) {
$access = $this->checkAccess($ipAddress, $resource);
$status = $access ? '✓ ALLOWED' : '✗ DENIED';
echo " {$resource}: {$status}\n";
}
}
}
// Usage
$ac = new AccessController();
echo "Internal User:\n";
$ac->generateAccessReport('192.168.1.100');
echo "\n";
echo "External User:\n";
$ac->generateAccessReport('8.8.8.8');
echo "\n";
echo "Localhost:\n";
$ac->generateAccessReport('127.0.0.1');Aggregate multiple regional subnets for BGP advertisement.
<?php
class BGPRouteOptimizer {
private $regions = [];
public function addRegionalRoutes($region, array $cidrs) {
$subnets = array_map(function($cidr) {
return IPv4\Subnet::fromCidr($cidr);
}, $cidrs);
$this->regions[$region] = $subnets;
}
public function optimizeRoutes() {
$optimized = [];
foreach ($this->regions as $region => $subnets) {
$aggregated = IPv4\Subnets::aggregate($subnets);
$optimized[$region] = $aggregated;
}
return $optimized;
}
public function printOptimizationReport() {
echo "BGP Route Optimization Report\n";
echo str_repeat('=', 80) . "\n\n";
$totalOriginal = 0;
$totalOptimized = 0;
foreach ($this->regions as $region => $subnets) {
echo "Region: {$region}\n";
echo str_repeat('-', 80) . "\n";
echo "Original routes (" . \count($subnets) . "):\n";
foreach ($subnets as $subnet) {
echo " {$subnet->cidr()}\n";
}
$aggregated = IPv4\Subnets::aggregate($subnets);
echo "\nOptimized routes (" . count($aggregated) . "):\n";
foreach ($aggregated as $subnet) {
echo " {$subnet->cidr()}\n";
}
$reduction = count($subnets) - count($aggregated);
echo "\nReduction: {$reduction} routes\n\n";
$totalOriginal += count($subnets);
$totalOptimized += count($aggregated);
}
$totalReduction = $totalOriginal - $totalOptimized;
$percentReduction = round(($totalReduction / $totalOriginal) * 100, 2);
echo str_repeat('=', 80) . "\n";
echo "Total Summary:\n";
echo " Original routes: {$totalOriginal}\n";
echo " Optimized routes: {$totalOptimized}\n";
echo " Reduction: {$totalReduction} routes ({$percentReduction}%)\n";
}
}
// Usage
$bgp = new BGPRouteOptimizer();
// North America routes
$bgp->addRegionalRoutes('North America', [
'10.1.0.0/24',
'10.1.1.0/24',
'10.1.2.0/24',
'10.1.3.0/24',
]);
// Europe routes
$bgp->addRegionalRoutes('Europe', [
'10.2.0.0/24',
'10.2.1.0/24',
'10.2.4.0/24', // Gap - cannot aggregate with above
'10.2.5.0/24',
]);
// Asia routes
$bgp->addRegionalRoutes('Asia', [
'10.3.0.0/24',
'10.3.1.0/24',
]);
$bgp->printOptimizationReport();Calculate optimal DHCP scopes for different departments.
<?php
class DHCPScopePlanner {
public function planScopes($baseNetwork, array $departments) {
$baseSubnet = IPv4\Subnet::fromCidr($baseNetwork);
$scopes = [];
echo "DHCP Scope Planning Report\n";
echo str_repeat('=', 80) . "\n";
echo "Base Network: {$baseNetwork}\n";
echo "Available IPs: {$baseSubnet->addressCount()}\n\n";
$currentNetwork = $baseSubnet->networkAddress()->asQuads();
foreach ($departments as $dept => $requirements) {
$requiredHosts = $requirements['hosts'];
$optimalPrefix = IPv4\SubnetParser::optimalPrefixForHosts($requiredHosts);
$scope = IPv4\Subnet::fromCidr("{$currentNetwork}/{$optimalPrefix}");
// Verify scope fits within base network
if (!$baseSubnet->contains($scope)) {
echo "ERROR: Insufficient space for {$dept}\n";
break;
}
$usableHosts = $scope->hostCount();
$utilization = $scope->utilizationFor($requiredHosts);
// Calculate DHCP pool (reserve first 10 IPs for static, last IP for gateway)
$poolStart = $scope->minHost()->asInteger() + 10;
$poolEnd = $scope->maxHost()->asInteger() - 1;
$scopes[$dept] = [
'subnet' => $scope,
'scope_start' => long2ip($poolStart),
'scope_end' => long2ip($poolEnd),
'gateway' => $scope->maxHost(),
'dns' => $requirements['dns'] ?? $scope->minHost(),
];
echo "{$dept}:\n";
echo " Required hosts: {$requiredHosts}\n";
echo " Subnet: {$scope->cidr()}\n";
echo " Subnet mask: {$scope->mask()}\n";
echo " Usable hosts: {$usableHosts}\n";
echo " Utilization: {$utilization}%\n";
echo " DHCP Pool: {$scopes[$dept]['scope_start']} - {$scopes[$dept]['scope_end']}\n";
echo " Gateway: {$scopes[$dept]['gateway']}\n";
echo " DNS: {$scopes[$dept]['dns']}\n\n";
$currentNetwork = $scope->next()->networkAddress()->asQuads();
}
return $scopes;
}
public function exportDHCPConfig(array $scopes, $serverType = 'isc-dhcp') {
if ($serverType === 'isc-dhcp') {
return $this->exportISCDHCPConfig($scopes);
}
return '';
}
private function exportISCDHCPConfig(array $scopes) {
$config = "# ISC DHCP Server Configuration\n";
$config .= "# Generated: " . date('Y-m-d H:i:s') . "\n\n";
foreach ($scopes as $name => $scope) {
$subnet = $scope['subnet'];
$config .= "# {$name}\n";
$config .= "subnet {$subnet->networkAddress()->asQuads()} netmask {$subnet->mask()} {\n";
$config .= " range {$scope['scope_start']} {$scope['scope_end']};\n";
$config .= " option routers {$scope['gateway']};\n";
$config .= " option domain-name-servers {$scope['dns']};\n";
$config .= " option subnet-mask {$subnet->mask()};\n";
$config .= "}\n\n";
}
return $config;
}
}
// Usage
$planner = new DHCPScopePlanner();
$departments = [
'Engineering' => ['hosts' => 100, 'dns' => '10.0.0.1'],
'Sales' => ['hosts' => 50, 'dns' => '10.0.0.1'],
'Guest WiFi' => ['hosts' => 200, 'dns' => '8.8.8.8'],
];
$scopes = $planner->planScopes('10.0.0.0/22', $departments);
echo "\n" . str_repeat('=', 80) . "\n";
echo "Generated DHCP Configuration:\n";
echo str_repeat('=', 80) . "\n\n";
echo $planner->exportDHCPConfig($scopes, 'isc-dhcp');Generate reverse DNS zone configurations.
<?php
class ReverseDNSZoneGenerator {
public function generateZone($cidr, $nameservers, $hostnames = []) {
$subnet = IPv4\Subnet::fromCidr($cidr);
echo "Reverse DNS Zone Configuration\n";
echo str_repeat('=', 80) . "\n";
echo "Subnet: {$cidr}\n";
echo "Network: {$subnet->networkAddress()->asQuads()}\n";
echo "Broadcast: {$subnet->broadcastAddress()->asQuads()}\n\n";
// Generate zone file
$zone = $this->generateZoneFile($subnet, $nameservers, $hostnames);
return $zone;
}
private function generateZoneFile($subnet, $nameservers, $hostnames) {
$zone = "; Reverse DNS Zone\n";
$zone .= "; Network: {$subnet->cidr()}\n";
$zone .= "; Generated: " . date('Y-m-d H:i:s') . "\n\n";
$zone .= "\$TTL 86400\n";
$zone .= "@ IN SOA {$nameservers[0]}. hostmaster.example.com. (\n";
$zone .= " " . date('Ymd') . "01 ; Serial\n";
$zone .= " 3600 ; Refresh\n";
$zone .= " 1800 ; Retry\n";
$zone .= " 604800 ; Expire\n";
$zone .= " 86400 ) ; Minimum TTL\n\n";
// Nameservers
foreach ($nameservers as $ns) {
$zone .= " IN NS {$ns}.\n";
}
$zone .= "\n";
// PTR records
foreach ($hostnames as $ip => $hostname) {
$ipSubnet = IPv4\Subnet::fromCidr($ip . '/32');
if ($subnet->containsIP($ip)) {
$octets = $ipSubnet->ipAddress()->asArray();
$ptrRecord = $octets[3];
$zone .= "{$ptrRecord} IN PTR {$hostname}.\n";
}
}
return $zone;
}
}
// Usage
$generator = new ReverseDNSZoneGenerator();
$hostnames = [
'192.168.1.1' => 'gateway.example.com',
'192.168.1.10' => 'dns1.example.com',
'192.168.1.11' => 'dns2.example.com',
'192.168.1.20' => 'mail.example.com',
'192.168.1.100' => 'web1.example.com',
];
$zone = $generator->generateZone(
'192.168.1.0/24',
['ns1.example.com', 'ns2.example.com'],
$hostnames
);
echo $zone;Validate network configurations in infrastructure-as-code deployments.
<?php
class NetworkConfigValidator {
private $errors = [];
private $warnings = [];
public function validateConfig(array $config) {
$this->errors = [];
$this->warnings = [];
// Validate subnets
$subnets = [];
foreach ($config['subnets'] as $name => $cidr) {
try {
$subnet = IPv4\Subnet::fromCidr($cidr);
$subnets[$name] = $subnet;
// Check if subnet is properly sized
if (isset($config['requirements'][$name])) {
$required = $config['requirements'][$name];
$available = $subnet->hostCount();
if ($available < $required) {
$this->errors[] = "{$name}: Insufficient capacity. Required: {$required}, Available: {$available}";
} elseif ($available > $required * 2) {
$this->warnings[] = "{$name}: Subnet may be oversized. Required: {$required}, Available: {$available}";
}
}
} catch (\Exception $e) {
$this->errors[] = "{$name}: Invalid CIDR notation - {$e->getMessage()}";
}
}
// Check for overlaps
$subnetList = array_values($subnets);
for ($i = 0; $i < count($subnetList); $i++) {
for ($j = $i + 1; $j < count($subnetList); $j++) {
if ($subnetList[$i]->overlaps($subnetList[$j])) {
$names = array_keys($subnets);
$this->errors[] = "Overlap detected: {$names[$i]} and {$names[$j]}";
}
}
}
// Validate address types
foreach ($subnets as $name => $subnet) {
if (strpos($name, 'public') !== false && $subnet->isPrivate()) {
$this->warnings[] = "{$name}: Named 'public' but uses private address space";
}
if (strpos($name, 'private') !== false && $subnet->isPublic()) {
$this->warnings[] = "{$name}: Named 'private' but uses public address space";
}
}
return empty($this->errors);
}
public function getReport() {
$report = "Network Configuration Validation Report\n";
$report .= str_repeat('=', 80) . "\n\n";
if (!empty($this->errors)) {
$report .= "ERRORS (" . count($this->errors) . "):\n";
$report .= str_repeat('-', 80) . "\n";
foreach ($this->errors as $error) {
$report .= " ✗ {$error}\n";
}
$report .= "\n";
}
if (!empty($this->warnings)) {
$report .= "WARNINGS (" . count($this->warnings) . "):\n";
$report .= str_repeat('-', 80) . "\n";
foreach ($this->warnings as $warning) {
$report .= " ⚠ {$warning}\n";
}
$report .= "\n";
}
if (empty($this->errors) && empty($this->warnings)) {
$report .= "✓ Configuration is valid. No errors or warnings.\n";
}
return $report;
}
}
// Usage in CI/CD pipeline
$config = [
'subnets' => [
'web-tier' => '10.0.1.0/24',
'app-tier' => '10.0.2.0/24',
'data-tier' => '10.0.3.0/24',
'management' => '10.0.0.0/28',
],
'requirements' => [
'web-tier' => 50,
'app-tier' => 100,
'data-tier' => 20,
'management' => 10,
],
];
$validator = new NetworkConfigValidator();
if (!$validator->validateConfig($config)) {
echo $validator->getReport();
exit(1); // Fail CI/CD pipeline
}
echo $validator->getReport();
echo "\n✓ Validation passed. Proceeding with deployment...\n";Analyze the impact of network changes before implementation.
<?php
function analyzeNetworkChange($currentCidr, $proposedCidr) {
$current = IPv4\Subnet::fromCidr($currentCidr);
$proposed = IPv4\Subnet::fromCidr($proposedCidr);
echo "Network Change Impact Analysis\n";
echo str_repeat('=', 80) . "\n\n";
echo "Current Network: {$currentCidr}\n";
echo "Proposed Network: {$proposedCidr}\n\n";
echo "Current State:\n";
echo " Usable hosts: {$current->hostCount()}\n";
echo " Range: {$current->minHost()} - {$current->maxHost()}\n\n";
echo "Proposed State:\n";
echo " Usable hosts: {$proposed->hostCount()}\n";
echo " Range: {$proposed->minHost()} - {$proposed->maxHost()}\n\n";
echo "Impact Analysis:\n";
echo str_repeat('-', 80) . "\n";
// Capacity change
$capacityChange = $proposed->hostCount() - $current->hostCount();
if ($capacityChange > 0) {
echo " ✓ Capacity increase: +{$capacityChange} hosts\n";
} elseif ($capacityChange < 0) {
echo " ⚠ Capacity decrease: {$capacityChange} hosts\n";
} else {
echo " - No capacity change\n";
}
// Address compatibility
if ($current->overlaps($proposed)) {
if ($proposed->contains($current)) {
echo " ✓ Proposed network contains current network (expansion)\n";
echo " ✓ Existing IPs will remain valid\n";
} elseif ($current->contains($proposed)) {
echo " ⚠ Proposed network is smaller than current (contraction)\n";
echo " ⚠ Some existing IPs may become invalid\n";
} else {
echo " ⚠ Partial overlap with current network\n";
echo " ⚠ Some IPs will remain valid, others will not\n";
}
} else {
echo " ✗ No overlap with current network\n";
echo " ✗ ALL existing IPs will become invalid\n";
echo " ✗ Complete renumbering required\n";
}
echo "\nRecommendations:\n";
echo str_repeat('-', 80) . "\n";
if (!$current->overlaps($proposed)) {
echo " • Complete network renumbering required\n";
echo " • Plan maintenance window\n";
echo " • Update all static IP configurations\n";
echo " • Update firewall rules\n";
echo " • Update DNS records\n";
} elseif (!$proposed->contains($current)) {
echo " • Partial renumbering required\n";
echo " • Audit existing IP allocations\n";
echo " • Migrate hosts outside new range\n";
} else {
echo " • Low-risk change (expansion)\n";
echo " • Update DHCP scope if applicable\n";
echo " • No immediate host changes required\n";
}
}
// Usage
analyzeNetworkChange('192.168.1.0/24', '192.168.1.0/23'); // Expansion
echo "\n" . str_repeat('=', 80) . "\n\n";
analyzeNetworkChange('192.168.1.0/24', '192.168.1.0/25'); // Contraction
echo "\n" . str_repeat('=', 80) . "\n\n";
analyzeNetworkChange('192.168.1.0/24', '192.168.2.0/24'); // Complete change- Getting Started - Installation and basic usage
- Core Features - Detailed feature documentation
- Advanced Features - Advanced operations
- API Reference - Complete method documentation
- Reports - Report generation