From 391a5d87f15e175a1705d79a2d3c0b93a195d2fd Mon Sep 17 00:00:00 2001 From: Anne Stellingwerf Date: Tue, 13 Jul 2021 15:43:13 +0200 Subject: [PATCH 1/3] fix: demskie#6 --- src/shared.ts | 27 +++++++++++++++++++++++---- src/tests/index.test.ts | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/shared.ts b/src/shared.ts index 6a810fe..1738d0e 100644 --- a/src/shared.ts +++ b/src/shared.ts @@ -19,7 +19,13 @@ export function sortNetworks(networks: Network[]) { sort.nativeSort(networks); } -export function summarizeSortedNetworks(sorted: Network[]) { +function increaseSizeByOneBit(network: Network): Network { + const wider = network.setCIDR(network.cidr() - 1); + wider.addr.applySubnetMask(wider.cidr()); + return wider; +} + +export function summarizeSortedNetworks(sorted: Network[]): Network[] { const summarized = [] as Network[]; for (let idx = 0; idx < sorted.length; idx++) { summarized.push(sorted[idx]); @@ -31,13 +37,26 @@ export function summarizeSortedNetworks(sorted: Network[]) { } if (sorted[idx].cidr() === sorted[i].cidr()) { if (sorted[idx].adjacent(sorted[i])) { - sorted[idx].setCIDR(sorted[idx].cidr() - 1); - skipped++; - continue; + const wider = increaseSizeByOneBit(sorted[idx].duplicate()); + if (wider.contains(sorted[i])) { + increaseSizeByOneBit(sorted[idx]); + skipped++; + continue; + } } } break; } + while (summarized.length >= 2) { + const a = summarized[summarized.length - 2]; + const b = summarized[summarized.length - 1]; + if (a.cidr() != b.cidr() || !a.addr.isBaseAddress(a.cidr() - 1) || !a.adjacent(b)) { + break; + } + increaseSizeByOneBit(a); + summarized.pop(); + } + idx += skipped; } return summarized; diff --git a/src/tests/index.test.ts b/src/tests/index.test.ts index 2a7d8c4..06c6f54 100644 --- a/src/tests/index.test.ts +++ b/src/tests/index.test.ts @@ -1,5 +1,18 @@ import * as index from "../index"; +expect.extend({ + toContainAddresses(received, addresses) { + const notFound = addresses.filter((i: string) => { + return undefined === received.find((value: string) => index.networkContainsAddress(value, i)); + }); + if (notFound.length > 0) { + return { message: () => `expected to find ${notFound} in ${received}`, pass: false }; + } else { + return { message: () => `expected not to find ${addresses} in ${received}`, pass: true }; + } + } +}); + test("sanity check baseAddress #1", () => { const output = index.baseAddress("192.168.200.113/24", true); expect(output).toEqual("192.168.200.0"); @@ -397,7 +410,7 @@ test("sanity check summarize #2", () => { test("sanity check summarize #3", () => { const output = index.summarize(["192.168.0.0", "192.168.0.2/31", "192.168.0.3", "192.168.0.4/31"], true); - expect(output).toEqual(["192.168.0.0/32", "192.168.0.2/30"]); + expect(output).toEqual(["192.168.0.0/32", "192.168.0.2/31", "192.168.0.4/31"]); }); test("sanity check summarize #4", () => { @@ -405,6 +418,29 @@ test("sanity check summarize #4", () => { expect(output).toEqual(["192.168.0.0/30", "192.168.0.5/32"]); }); +test("sanity check summarize #5", () => { + const input = [ + "10.9.201.68", + "10.9.201.71", + "10.9.201.70", + "10.9.201.65", + "10.9.201.72", + "10.9.201.67", + "10.9.201.66", + "10.9.201.69" + ]; // Shuffled, but effectively ranging from 10.9.201.65 to 10.9.201.72 + + const output = index.summarize(input, true); + expect(output).toBeDefined(); + expect(output).not.toContainAddresses(["192.168.0.0"]); + expect(output).not.toContainAddresses(["10.9.201.64"]); + expect(output).not.toContainAddresses(["10.9.201.73"]); + expect(output).toContainAddresses(input); + + const expectedOutput = ["10.9.201.65/32", "10.9.201.66/31", "10.9.201.68/30", "10.9.201.72/32"]; + expect(output).toEqual(expectedOutput); +}); + // https://tools.ietf.org/html/rfc5952#section-4 test("sanity check IPv6 parsing #1", () => { From df547af7045a801ecb591f92ae79fe52caf03a5e Mon Sep 17 00:00:00 2001 From: Anne Stellingwerf Date: Tue, 13 Jul 2021 18:30:51 +0200 Subject: [PATCH 2/3] Simplify the logic further --- src/shared.ts | 27 +++++---------------------- src/tests/index.test.ts | 11 +++++++---- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/src/shared.ts b/src/shared.ts index 1738d0e..8b84bf1 100644 --- a/src/shared.ts +++ b/src/shared.ts @@ -26,27 +26,12 @@ function increaseSizeByOneBit(network: Network): Network { } export function summarizeSortedNetworks(sorted: Network[]): Network[] { - const summarized = [] as Network[]; - for (let idx = 0; idx < sorted.length; idx++) { - summarized.push(sorted[idx]); - let skipped = 0; - for (let i = idx + 1; i < sorted.length; i++) { - if (sorted[idx].contains(sorted[i])) { - skipped++; - continue; - } - if (sorted[idx].cidr() === sorted[i].cidr()) { - if (sorted[idx].adjacent(sorted[i])) { - const wider = increaseSizeByOneBit(sorted[idx].duplicate()); - if (wider.contains(sorted[i])) { - increaseSizeByOneBit(sorted[idx]); - skipped++; - continue; - } - } - } - break; + const summarized: Network[] = [sorted[0]]; + for (let idx = 1; idx < sorted.length; idx++) { + if (summarized[summarized.length - 1].contains(sorted[idx])) { + continue; } + summarized.push(sorted[idx]); while (summarized.length >= 2) { const a = summarized[summarized.length - 2]; const b = summarized[summarized.length - 1]; @@ -56,8 +41,6 @@ export function summarizeSortedNetworks(sorted: Network[]): Network[] { increaseSizeByOneBit(a); summarized.pop(); } - - idx += skipped; } return summarized; } diff --git a/src/tests/index.test.ts b/src/tests/index.test.ts index 06c6f54..de39024 100644 --- a/src/tests/index.test.ts +++ b/src/tests/index.test.ts @@ -1,7 +1,7 @@ import * as index from "../index"; expect.extend({ - toContainAddresses(received, addresses) { + toContainAddresses(received: string[], addresses: string[]) { const notFound = addresses.filter((i: string) => { return undefined === received.find((value: string) => index.networkContainsAddress(value, i)); }); @@ -425,19 +425,22 @@ test("sanity check summarize #5", () => { "10.9.201.70", "10.9.201.65", "10.9.201.72", + "10.9.201.75", "10.9.201.67", "10.9.201.66", - "10.9.201.69" - ]; // Shuffled, but effectively ranging from 10.9.201.65 to 10.9.201.72 + "10.9.201.69", + "10.9.201.74" + ]; // Shuffled, but effectively ranging from 10.9.201.65 to 10.9.201.72 + 10.9.201.74 const output = index.summarize(input, true); expect(output).toBeDefined(); expect(output).not.toContainAddresses(["192.168.0.0"]); expect(output).not.toContainAddresses(["10.9.201.64"]); expect(output).not.toContainAddresses(["10.9.201.73"]); + expect(output).not.toContainAddresses(["10.9.201.76"]); expect(output).toContainAddresses(input); - const expectedOutput = ["10.9.201.65/32", "10.9.201.66/31", "10.9.201.68/30", "10.9.201.72/32"]; + const expectedOutput = ["10.9.201.65/32", "10.9.201.66/31", "10.9.201.68/30", "10.9.201.72/32", "10.9.201.74/31"]; expect(output).toEqual(expectedOutput); }); From b479f7982528c4c1ce7b31af5fb36b5929eb36a0 Mon Sep 17 00:00:00 2001 From: Anne Stellingwerf Date: Tue, 13 Jul 2021 18:32:04 +0200 Subject: [PATCH 3/3] Simplify the logic further --- src/tests/index.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/index.test.ts b/src/tests/index.test.ts index de39024..087205c 100644 --- a/src/tests/index.test.ts +++ b/src/tests/index.test.ts @@ -430,7 +430,7 @@ test("sanity check summarize #5", () => { "10.9.201.66", "10.9.201.69", "10.9.201.74" - ]; // Shuffled, but effectively ranging from 10.9.201.65 to 10.9.201.72 + 10.9.201.74 + ]; // Shuffled, but effectively ranging from 10.9.201.65 to 10.9.201.72 + 10.9.201.74 + 10.9.201.75 const output = index.summarize(input, true); expect(output).toBeDefined();