From ade100fdb870b28fed9e4838e226a148fc49d328 Mon Sep 17 00:00:00 2001 From: Kevin Kandlbinder Date: Wed, 4 May 2022 16:12:19 +0200 Subject: [PATCH] Fix edge cases in IPv4SubnettingTool --- package.json | 2 +- public/locales/de/translation.json | 12 +- public/locales/en/translation.json | 12 +- .../ipv4subnetting/IPv4SubnettingTool.tsx | 117 ++++++++++++++++-- 4 files changed, 129 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index b26bc83..50b6139 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "kevins-data-toolbox", - "version": "2.4.2", + "version": "2.4.3", "private": true, "dependencies": { "@loadable/component": "^5.15.0", diff --git a/public/locales/de/translation.json b/public/locales/de/translation.json index e251c64..769c6f1 100644 --- a/public/locales/de/translation.json +++ b/public/locales/de/translation.json @@ -59,14 +59,22 @@ "networking": { "ipv4subnetting": { "title": "IPv4-Subnetzrechner", - "description": "Der IPv4-Subnetzrechner visualisiert IPv4-Subnetze und berechnet die erste und letzte Adresse aus einem Subnetz nach CIDR-Notation." + "description": "Der IPv4-Subnetzrechner visualisiert IPv4-Subnetze und berechnet die erste und letzte Adresse aus einem Subnetz nach CIDR-Notation.", + "error": { + "isNaN": "Dies muss eine Zahl sein!", + "tooSmall": "Dies muss eine positive Zahl sein!", + "tooBig": "Diese Zahl darf nicht größer als 255 sein!", + "tooBigSubnet": "Diese Zahl darf nicht größer als 32 sein!" + } }, "common": { "ipv4addr": "IPv4-Adresse", "firstAddr": "Erste Adresse", "lastAddr": "Letzte Adresse", "subnetMask": "Subnetzmaske", - "binary": "Binär" + "binary": "Binär", + "netAddr": "Netzwerkadresse", + "broadcastAddr": "Broadcast-Adresse" } } }, diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index e98b293..71620b3 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -59,14 +59,22 @@ "networking": { "ipv4subnetting": { "title": "IPv4 Subnetter", - "description": "The IPv4 subnetter visualizes IPv4 subnets and calculates the first and last address from a CIDR-notated subnet." + "description": "The IPv4 subnetter visualizes IPv4 subnets and calculates the first and last address from a CIDR-notated subnet.", + "error": { + "isNaN": "This needs to be a valid number!", + "tooSmall": "This needs to be a positive number!", + "tooBig": "This may not be bigger than 255!", + "tooBigSubnet": "This may not be bigger than 32!" + } }, "common": { "ipv4addr": "IPv4 address", "firstAddr": "First address", "lastAddr": "Last address", "subnetMask": "Subnet mask", - "binary": "Binary" + "binary": "Binary", + "netAddr": "Network address", + "broadcastAddr": "Broadcast address" } } }, diff --git a/src/tools/networking/ipv4subnetting/IPv4SubnettingTool.tsx b/src/tools/networking/ipv4subnetting/IPv4SubnettingTool.tsx index 1de3d88..ee65fa8 100644 --- a/src/tools/networking/ipv4subnetting/IPv4SubnettingTool.tsx +++ b/src/tools/networking/ipv4subnetting/IPv4SubnettingTool.tsx @@ -34,10 +34,10 @@ const IPv4SubnettingTool = () => { let [ipBinary, setIpBinary] = useState(undefined); let [subnetNumber, setSubnetMaskNumber] = useState(undefined); - let [subnetBinary, setSubnetMaskBinaryString] = useState(undefined); let [subnetMask, setSubnetMask] = useState(undefined); let [firstAddr, setFirstAddr] = useState(undefined); let [lastAddr, setLastAddr] = useState(undefined); + let [isPeerNet, setIsPeerNet] = useState(false); useEffect(() => { let myIpPart1 = ipPart1; @@ -92,19 +92,105 @@ const IPv4SubnettingTool = () => { if(!isNaN(ipPart4Num)) setIPPart4(ipPart4Num.toString()); if(!isNaN(subnetNum)) setSubnet(subnetNum.toString()); + let invalid = false; + + [ipInput1, ipInput2, ipInput3, ipInput4].forEach((field) => { + if(!field.current) return + + const val = field.current.value; + + if (val === "") { + field.current.setCustomValidity(""); + return + } + + const valInt = parseInt(val); + + if(isNaN(valInt)) { + field.current.setCustomValidity(t("tools.networking.ipv4subnetting.error.isNaN")); + field.current.reportValidity(); + invalid = true; + return + } + + if(valInt < 0) { + field.current.setCustomValidity(t("tools.networking.ipv4subnetting.error.tooSmall")); + field.current.reportValidity(); + invalid = true; + return + } + + if(valInt > 255) { + field.current.setCustomValidity(t("tools.networking.ipv4subnetting.error.tooBig")); + field.current.reportValidity(); + invalid = true; + return + } + + field.current.setCustomValidity(""); + }); + + + + ((field: React.RefObject) => { + if(!field.current) return + + const val = field.current.value; + + if (val === "") { + field.current.setCustomValidity(""); + return + } + + const valInt = parseInt(val); + + if(isNaN(valInt)) { + field.current.setCustomValidity(t("tools.networking.ipv4subnetting.error.isNaN")); + field.current.reportValidity(); + invalid = true; + return + } + + if(valInt < 0) { + field.current.setCustomValidity(t("tools.networking.ipv4subnetting.error.tooSmall")); + field.current.reportValidity(); + invalid = true; + return + } + + if(valInt > 32) { + field.current.setCustomValidity(t("tools.networking.ipv4subnetting.error.tooBigSubnet")); + field.current.reportValidity(); + invalid = true; + return + } + + field.current.setCustomValidity(""); + })(subnetInput) + setIpBinary(undefined); setFirstAddr(undefined); setLastAddr(undefined); - setSubnetMaskBinaryString(undefined); setSubnetMaskNumber(undefined); setSubnetMask(undefined); + setIsPeerNet(false); + + if(invalid) return; if(!isNaN(ipPart1Num) && !isNaN(ipPart2Num) && !isNaN(ipPart3Num) && !isNaN(ipPart4Num)) { let ipBinary = ipPart1Num * Math.pow(2, 24) + ipPart2Num * Math.pow(2, 16) + ipPart3Num * Math.pow(2, 8) + ipPart4Num; setIpBinary(ipBinary); + if (!isNaN(subnetNum)) { setSubnetMaskNumber(subnetNum); + + let peerNet = false; + + if (subnetNum > 30) { + setIsPeerNet(true); + peerNet = true; + } let subnetMaskBinary = new Uint32Array(1); @@ -115,14 +201,21 @@ const IPv4SubnettingTool = () => { subnetMaskBinary[0] ^= 0xffffffff - setSubnetMaskBinaryString(subnetMaskBinary[0].toString(2)) + //setSubnetMaskBinaryString(subnetMaskBinary[0].toString(2)) setSubnetMask(subnetMaskBinary[0]) - setFirstAddr((ipBinary & subnetMaskBinary[0])+1) - setLastAddr((ipBinary | (subnetMaskBinary[0] ^ 0xffffffff)) - 1) + if(!peerNet) { + setFirstAddr((ipBinary & subnetMaskBinary[0])+1) + setLastAddr((ipBinary | (subnetMaskBinary[0] ^ 0xffffffff)) - 1) + } + + if(peerNet) { + setFirstAddr((ipBinary & subnetMaskBinary[0])) + setLastAddr((ipBinary | (subnetMaskBinary[0] ^ 0xffffffff))) + } } } - }, [ipPart1, ipPart2, ipPart3, ipPart4, subnet]) + }, [ipPart1, ipPart2, ipPart3, ipPart4, subnet, t]) return (
@@ -149,7 +242,7 @@ const IPv4SubnettingTool = () => { {t("tools.networking.common.subnetMask")} - {subnetMask ? intToIPv4String(subnetMask) : "???"} + {subnetMask || subnetMask === 0 ? intToIPv4String(subnetMask) : "???"} {t("tools.networking.common.firstAddr")} {firstAddr ? intToIPv4String(firstAddr) : "???"} @@ -157,16 +250,22 @@ const IPv4SubnettingTool = () => { {t("tools.networking.common.lastAddr")} {lastAddr ? intToIPv4String(lastAddr) : "???"} + {t("tools.networking.common.netAddr")} + {isPeerNet ? "n/a" : (firstAddr ? intToIPv4String(firstAddr - 1) : "???")} + + {t("tools.networking.common.broadcastAddr")} + {isPeerNet ? "n/a" : (lastAddr ? intToIPv4String(lastAddr + 1) : "???")} + {t("tools.networking.common.ipv4addr")} ({t("tools.networking.common.binary")}) - {ipBinary ? ipBinary.toString(2).padStart(32, "0").split("").map((bit, index) => { + {ipBinary || ipBinary === 0 ? ipBinary.toString(2).padStart(32, "0").split("").map((bit, index) => { return = (subnetNumber||32) ? "red" : undefined}} key={"bit"+index}>{bit} }) : "???"} {t("tools.networking.common.subnetMask")} ({t("tools.networking.common.binary")}) - {subnetBinary ? subnetBinary.padStart(32, "0").split("").map((bit, index) => { + {subnetMask || subnetMask === 0 ? subnetMask.toString(2).padStart(32, "0").split("").map((bit, index) => { return {bit} }) : "???"}