Skip to content

Commit 1903456

Browse files
committed
Refactos IPv4 /31,32 fix and improves logic
1 parent 92f46e0 commit 1903456

File tree

3 files changed

+40
-67
lines changed

3 files changed

+40
-67
lines changed

src/lib/components/tools/NetworkVisualizer.svelte

Lines changed: 34 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -14,55 +14,44 @@
1414
* Generates visual representation of network range
1515
*/
1616
function generateNetworkBlocks() {
17-
const totalHosts = subnetInfo.hostCount;
18-
const _usableHosts = subnetInfo.usableHosts;
19-
const cidr = subnetInfo.cidr;
20-
21-
// For visualization, we'll show up to 256 blocks max
17+
const { hostCount, cidr } = subnetInfo;
2218
const maxBlocks = 256;
23-
const blocksToShow = Math.min(totalHosts, maxBlocks);
24-
const blockSize = totalHosts > maxBlocks ? Math.ceil(totalHosts / maxBlocks) : 1;
25-
26-
const blocks = [];
27-
28-
// RFC 3021: /31 networks have no network/broadcast addresses
29-
const is31Subnet = cidr === 31;
30-
const is32Subnet = cidr === 32;
31-
32-
for (let i = 0; i < blocksToShow; i++) {
33-
let type: 'network' | 'broadcast' | 'usable';
34-
let tooltip: string;
35-
36-
if (is31Subnet) {
37-
// /31: Both IPs are usable hosts (point-to-point)
38-
type = 'usable';
39-
tooltip = i === 0 ? 'Usable Host 1 (P2P)' : 'Usable Host 2 (P2P)';
40-
} else if (is32Subnet) {
41-
// /32: Single host
42-
type = 'usable';
43-
tooltip = 'Single Host';
44-
} else {
45-
// Normal subnet: first is network, last is broadcast, rest are usable
46-
const isNetwork = i === 0;
47-
const isBroadcast = i === blocksToShow - 1 && totalHosts > 2;
48-
49-
type = isNetwork ? 'network' : isBroadcast ? 'broadcast' : 'usable';
50-
tooltip = isNetwork
51-
? 'Network Address'
52-
: isBroadcast
53-
? 'Broadcast Address'
54-
: `Usable Host${blockSize > 1 ? 's' : ''}`;
19+
const blocksToShow = Math.min(hostCount, maxBlocks);
20+
const blockSize = hostCount > maxBlocks ? Math.ceil(hostCount / maxBlocks) : 1;
21+
22+
return Array.from({ length: blocksToShow }, (_, i) => {
23+
const isFirst = i === 0;
24+
const isLast = i === blocksToShow - 1;
25+
26+
// RFC 3021: /31 and /32 have all IPs usable
27+
if (cidr === 31) {
28+
return {
29+
id: i,
30+
type: 'usable' as const,
31+
represents: blockSize,
32+
tooltip: isFirst ? 'Usable Host 1 (P2P)' : 'Usable Host 2 (P2P)',
33+
};
5534
}
5635
57-
blocks.push({
58-
id: i,
59-
type,
60-
represents: blockSize,
61-
tooltip,
62-
});
63-
}
36+
if (cidr === 32) {
37+
return {
38+
id: i,
39+
type: 'usable' as const,
40+
represents: blockSize,
41+
tooltip: 'Single Host',
42+
};
43+
}
44+
45+
// Normal subnets have network/broadcast reserved
46+
const type = isFirst ? 'network' : isLast && hostCount > 2 ? 'broadcast' : 'usable';
47+
const tooltip = isFirst
48+
? 'Network Address'
49+
: isLast && hostCount > 2
50+
? 'Broadcast Address'
51+
: `Usable Host${blockSize > 1 ? 's' : ''}`;
6452
65-
return blocks;
53+
return { id: i, type, represents: blockSize, tooltip };
54+
});
6655
}
6756
6857
let networkBlocks = $derived(generateNetworkBlocks());

src/lib/utils/ip-calculations.ts

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -74,33 +74,17 @@ export function calculateSubnet(ip: string, cidr: number): SubnetInfo {
7474
const hostBits = 32 - cidr;
7575
const hostCount = Math.pow(2, hostBits);
7676

77-
// Calculate usable hosts based on CIDR
78-
// RFC 3021: /31 has 2 usable hosts (point-to-point, no network/broadcast)
79-
// /32 has 1 usable host (single host route)
80-
// All others: total - 2 (excluding network and broadcast)
81-
let usableHosts: number;
82-
if (cidr === 32) {
83-
usableHosts = 1;
84-
} else if (cidr === 31) {
85-
usableHosts = 2; // Both IPs are usable for point-to-point links
86-
} else {
87-
usableHosts = hostCount - 2;
88-
}
77+
// RFC 3021: /31 point-to-point has both IPs usable, /32 is single host
78+
const usableHosts = cidr === 32 ? 1 : cidr === 31 ? 2 : hostCount - 2;
8979

90-
// Calculate first and last host based on CIDR
80+
// For /31 and /32, all IPs are usable (no reserved network/broadcast)
9181
let firstHost: IPAddress;
9282
let lastHost: IPAddress;
9383

94-
if (cidr === 32) {
95-
// Host route - first and last are the same
96-
firstHost = network;
97-
lastHost = network;
98-
} else if (cidr === 31) {
99-
// Point-to-point - use network and broadcast as hosts (RFC 3021)
84+
if (cidr >= 31) {
10085
firstHost = network;
101-
lastHost = broadcast;
86+
lastHost = cidr === 32 ? network : broadcast;
10287
} else {
103-
// Normal subnet - exclude network and broadcast
10488
firstHost = numberToIP(ipToNumber(network.octets.join('.')) + 1);
10589
lastHost = numberToIP(ipToNumber(broadcast.octets.join('.')) - 1);
10690
}

tests/unit/utils/ip-calculations.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,4 +245,4 @@ describe('IP calculations core logic', () => {
245245
expect(subnet.usableHosts).toBe(2);
246246
});
247247
});
248-
});
248+
});

0 commit comments

Comments
 (0)