Skip to content

Commit 49e624f

Browse files
HBSPSmarco-ippolito
authored andcommitted
os: fix netmask format check condition in getCIDR function
Modified to check the format of the netmask instead of just checking that each part of the netmask is even PR-URL: #57324 Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 275ea8e commit 49e624f

File tree

3 files changed

+81
-55
lines changed

3 files changed

+81
-55
lines changed

lib/internal/util.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const {
99
Error,
1010
ErrorCaptureStackTrace,
1111
FunctionPrototypeCall,
12+
NumberParseInt,
1213
ObjectDefineProperties,
1314
ObjectDefineProperty,
1415
ObjectGetOwnPropertyDescriptor,
@@ -34,7 +35,9 @@ const {
3435
SafeSet,
3536
SafeWeakMap,
3637
SafeWeakRef,
38+
StringPrototypeIncludes,
3739
StringPrototypeReplace,
40+
StringPrototypeSlice,
3841
StringPrototypeToLowerCase,
3942
StringPrototypeToUpperCase,
4043
Symbol,
@@ -825,6 +828,59 @@ function setupCoverageHooks(dir) {
825828
return coverageDirectory;
826829
}
827830

831+
// Returns the number of ones in the binary representation of the decimal
832+
// number.
833+
function countBinaryOnes(n) {
834+
// Count the number of bits set in parallel, which is faster than looping
835+
n = n - ((n >>> 1) & 0x55555555);
836+
n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);
837+
return ((n + (n >>> 4) & 0xF0F0F0F) * 0x1010101) >>> 24;
838+
}
839+
840+
function getCIDR(address, netmask, family) {
841+
let ones = 0;
842+
let split = '.';
843+
let range = 10;
844+
let groupLength = 8;
845+
let hasZeros = false;
846+
let lastPos = 0;
847+
848+
if (family === 'IPv6') {
849+
split = ':';
850+
range = 16;
851+
groupLength = 16;
852+
}
853+
854+
for (let i = 0; i < netmask.length; i++) {
855+
if (netmask[i] !== split) {
856+
if (i + 1 < netmask.length) {
857+
continue;
858+
}
859+
i++;
860+
}
861+
const part = StringPrototypeSlice(netmask, lastPos, i);
862+
lastPos = i + 1;
863+
if (part !== '') {
864+
if (hasZeros) {
865+
if (part !== '0') {
866+
return null;
867+
}
868+
} else {
869+
const binary = NumberParseInt(part, range);
870+
const binaryOnes = countBinaryOnes(binary);
871+
ones += binaryOnes;
872+
if (binaryOnes !== groupLength) {
873+
if (StringPrototypeIncludes(binary.toString(2), '01')) {
874+
return null;
875+
}
876+
hasZeros = true;
877+
}
878+
}
879+
}
880+
}
881+
882+
return `${address}/${ones}`;
883+
}
828884

829885
const handleTypes = ['TCP', 'TTY', 'UDP', 'FILE', 'PIPE', 'UNKNOWN'];
830886
function guessHandleType(fd) {
@@ -889,6 +945,7 @@ module.exports = {
889945
filterDuplicateStrings,
890946
filterOwnProperties,
891947
getConstructorOf,
948+
getCIDR,
892949
getCWDURL,
893950
getInternalGlobal,
894951
getStructuredStack,

lib/os.js

Lines changed: 1 addition & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
const {
2525
ArrayPrototypePush,
2626
Float64Array,
27-
NumberParseInt,
2827
ObjectDefineProperties,
2928
StringPrototypeEndsWith,
3029
StringPrototypeSlice,
@@ -41,6 +40,7 @@ const {
4140
},
4241
hideStackFrames,
4342
} = require('internal/errors');
43+
const { getCIDR } = require('internal/util');
4444
const { validateInt32 } = require('internal/validators');
4545

4646
const {
@@ -208,60 +208,6 @@ function endianness() {
208208
}
209209
endianness[SymbolToPrimitive] = () => kEndianness;
210210

211-
// Returns the number of ones in the binary representation of the decimal
212-
// number.
213-
function countBinaryOnes(n) {
214-
// Count the number of bits set in parallel, which is faster than looping
215-
n = n - ((n >>> 1) & 0x55555555);
216-
n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);
217-
return ((n + (n >>> 4) & 0xF0F0F0F) * 0x1010101) >>> 24;
218-
}
219-
220-
function getCIDR(address, netmask, family) {
221-
let ones = 0;
222-
let split = '.';
223-
let range = 10;
224-
let groupLength = 8;
225-
let hasZeros = false;
226-
let lastPos = 0;
227-
228-
if (family === 'IPv6') {
229-
split = ':';
230-
range = 16;
231-
groupLength = 16;
232-
}
233-
234-
for (let i = 0; i < netmask.length; i++) {
235-
if (netmask[i] !== split) {
236-
if (i + 1 < netmask.length) {
237-
continue;
238-
}
239-
i++;
240-
}
241-
const part = StringPrototypeSlice(netmask, lastPos, i);
242-
lastPos = i + 1;
243-
if (part !== '') {
244-
if (hasZeros) {
245-
if (part !== '0') {
246-
return null;
247-
}
248-
} else {
249-
const binary = NumberParseInt(part, range);
250-
const binaryOnes = countBinaryOnes(binary);
251-
ones += binaryOnes;
252-
if (binaryOnes !== groupLength) {
253-
if ((binary & 1) !== 0) {
254-
return null;
255-
}
256-
hasZeros = true;
257-
}
258-
}
259-
}
260-
}
261-
262-
return `${address}/${ones}`;
263-
}
264-
265211
/**
266212
* @returns {Record<string, Array<{
267213
* address: string,
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Flags: --expose-internals
2+
'use strict';
3+
require('../common');
4+
5+
// These are tests that verify that the subnetmask is used
6+
// to create the correct CIDR address.
7+
// Tests that it returns null if the subnetmask is not in the correct format.
8+
// (ref: https://www.rfc-editor.org/rfc/rfc1878)
9+
10+
const assert = require('node:assert');
11+
const { getCIDR } = require('internal/util');
12+
13+
assert.strictEqual(getCIDR('127.0.0.1', '255.0.0.0', 'IPv4'), '127.0.0.1/8');
14+
assert.strictEqual(getCIDR('127.0.0.1', '255.255.0.0', 'IPv4'), '127.0.0.1/16');
15+
16+
// 242 = 11110010(2)
17+
assert.strictEqual(getCIDR('127.0.0.1', '242.0.0.0', 'IPv4'), null);
18+
19+
assert.strictEqual(getCIDR('::1', 'ffff:ffff:ffff:ffff::', 'IPv6'), '::1/64');
20+
assert.strictEqual(getCIDR('::1', 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', 'IPv6'), '::1/128');
21+
22+
// ff00:ffff = 11111111 00000000 : 11111111 11111111(2)
23+
assert.strictEqual(getCIDR('::1', 'ffff:ff00:ffff::', 'IPv6'), null);

0 commit comments

Comments
 (0)