Skip to content

Commit

Permalink
nope-ip removal - Phase 3
Browse files Browse the repository at this point in the history
`stun.js`:
- Replaced `node-ip` with native `net_utils` calls

`http_utils.js`:
- Refractored `no_proxy_list`
- Replaced `node-ip.cidr` with native `net_utils.is_cidr` call

`net_utils.js`:
- Fixed a bug where `is_fqdn("loclhost")` returned falsely true
- Add `is_cidr`, `ip_toString`, and `ip_toBuffer`
- Added helper functions for `ip_toBuffer`

- Adding `test_net_utils.test.js`

Signed-off-by: liranmauda <[email protected]>
  • Loading branch information
liranmauda committed Feb 12, 2025
1 parent 23aec8d commit 4514fb7
Show file tree
Hide file tree
Showing 4 changed files with 265 additions and 40 deletions.
17 changes: 9 additions & 8 deletions src/rpc/stun.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
/* eslint-disable no-bitwise */
'use strict';

const url = require('url');
const _ = require('lodash');
const util = require('util');
const P = require('../util/promise');
const url = require('url');
const dgram = require('dgram');
const crypto = require('crypto');
const ip_module = require('ip');
const chance = require('chance')();
const P = require('../util/promise');
const net_utils = require('../util/net_utils');

// https://tools.ietf.org/html/rfc5389
const stun = {
Expand Down Expand Up @@ -435,7 +435,7 @@ function encode_attrs(buffer, attrs) {
function decode_attr_mapped_addr(buffer, start, end) {
const family = (buffer.readUInt16BE(start) === 0x02) ? 6 : 4;
const port = buffer.readUInt16BE(start + 2);
const address = ip_module.toString(buffer, start + 4, family);
const address = net_utils.ip_toString(buffer, start + 4, family);

return {
family: 'IPv' + family,
Expand Down Expand Up @@ -463,7 +463,7 @@ function decode_attr_xor_mapped_addr(buffer, start, end) {
xor_buf[i] = addr_buf[i] ^ buffer[k];
k += 1;
}
const address = ip_module.toString(xor_buf, 0, family);
const address = net_utils.ip_toString(xor_buf, 0, family);

return {
family: 'IPv' + family,
Expand Down Expand Up @@ -510,7 +510,7 @@ function encode_attr_mapped_addr(addr, buffer, offset, end) {
// xor the port against the magic key
buffer.writeUInt16BE(addr.port, offset + 2);

ip_module.toBuffer(addr.address, buffer, offset + 4);
net_utils.ip_toBuffer(addr.address, buffer, offset + 4);
}


Expand All @@ -524,7 +524,7 @@ function encode_attr_xor_mapped_addr(addr, buffer, offset, end) {
// xor the port against the magic key
buffer.writeUInt16BE(addr.port ^ buffer.readUInt16BE(stun.XOR_KEY_OFFSET), offset + 2);

ip_module.toBuffer(addr.address, buffer, offset + 4);
net_utils.ip_toBuffer(addr.address, buffer, offset + 4);
let k = stun.XOR_KEY_OFFSET;
for (let i = offset + 4; i < end; ++i) {
buffer[i] ^= buffer[k];
Expand Down Expand Up @@ -615,7 +615,8 @@ function test() {
}
return Promise.all([
P.ninvoke(socket, 'send', req, 0, req.length, stun_url.port, stun_url.hostname),
P.ninvoke(socket, 'send', ind, 0, ind.length, stun_url.port, stun_url.hostname)])
P.ninvoke(socket, 'send', ind, 0, ind.length, stun_url.port, stun_url.hostname)
])
.then(() => P.delay(stun.INDICATION_INTERVAL * chance.floating(stun.INDICATION_JITTER)))
.then(loop);
}
Expand Down
109 changes: 109 additions & 0 deletions src/test/unit_tests/jest_tests/test_net_utils.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/* Copyright (C) 2016 NooBaa */
'use strict';

const os = require('os');
const net_utils = require('../../../util/net_utils');

describe('IP Utils', () => {
it('is_ip should correctly identify IP addresses', () => {
expect(net_utils.is_ip('192.168.1.1')).toBe(true);
expect(net_utils.is_ip('::1')).toBe(true);
expect(net_utils.is_ip('not_an_ip')).toBe(false);
expect(net_utils.is_ip('256.256.256.256')).toBe(false);
});

it('is_fqdn should correctly identify FQDNs', () => {
expect(net_utils.is_fqdn('example.com')).toBe(true);
expect(net_utils.is_fqdn('sub.example.com')).toBe(true);
expect(net_utils.is_fqdn('localhost')).toBe(false);
expect(net_utils.is_fqdn('invalid_domain-.com')).toBe(false);
});

it('is_cidr should correctly identify CIDR notation', () => {
expect(net_utils.is_cidr('192.168.1.0/24')).toBe(true);
expect(net_utils.is_cidr('10.0.0.0/8')).toBe(true);
expect(net_utils.is_cidr('2001:db8::/32')).toBe(true);
expect(net_utils.is_cidr('192.168.1.300/24')).toBe(false);
expect(net_utils.is_cidr('invalid_cidr')).toBe(false);
expect(net_utils.is_cidr('192.168.1.1')).toBe(false);
expect(net_utils.is_cidr('282.150.0.0/12')).toBe(false);
expect(net_utils.is_cidr('192.168.0.0/35')).toBe(false);
});

it('is_localhost should correctly identify localhost addresses', () => {
expect(net_utils.is_localhost('127.0.0.1')).toBe(true);
expect(net_utils.is_localhost('::1')).toBe(true);
expect(net_utils.is_localhost('localhost')).toBe(true);
expect(net_utils.is_localhost('192.168.1.1')).toBe(false);
});

it('unwrap_ipv6 should remove IPv6 prefix', () => {
expect(net_utils.unwrap_ipv6('::ffff:192.168.1.1')).toBe('192.168.1.1');
expect(net_utils.unwrap_ipv6('::1')).toBe('::1');
expect(net_utils.unwrap_ipv6('2001:db8::ff00:42:8329')).toBe('2001:db8::ff00:42:8329');
});

it('ip_toLong should convert IPv4 to long', () => {
expect(net_utils.ip_toLong('192.168.1.1')).toBe(3232235777);
expect(net_utils.ip_toLong('0.0.0.0')).toBe(0);
expect(net_utils.ip_toLong('255.255.255.255')).toBe(4294967295);
});

it('ip_to_long should handle both IPv4 and IPv6-mapped IPv4', () => {
expect(net_utils.ip_to_long('192.168.1.1')).toBe(3232235777);
expect(net_utils.ip_to_long('::ffff:192.168.1.1')).toBe(3232235777);
});

it('find_ifc_containing_address should find interface containing the address', () => {
const networkInterfacesMock = {
eth0: [
{ family: 'IPv4', cidr: '192.168.1.0/24', address: '192.168.1.2' },
{ family: 'IPv6', cidr: 'fe80::/64', address: 'fe80::1' },
],
lo: [{ family: 'IPv4', cidr: '127.0.0.0/8', address: '127.0.0.1' }],
};
jest.spyOn(os, 'networkInterfaces').mockReturnValue(networkInterfacesMock);

expect(net_utils.find_ifc_containing_address('192.168.1.5')).toEqual({ ifc: 'eth0', info: networkInterfacesMock.eth0[0] });
expect(net_utils.find_ifc_containing_address('127.0.0.1')).toEqual({ ifc: 'lo', info: networkInterfacesMock.lo[0] });
expect(net_utils.find_ifc_containing_address('8.8.8.8')).toBeUndefined();
});

it('ip_toString should convert buffers to IP strings', () => {
expect(net_utils.ip_toString(Buffer.from([192, 168, 1, 1]), 0, 4)).toBe('192.168.1.1');
expect(net_utils.ip_toString(Buffer.from([0, 0, 0, 0]), 0, 4)).toBe('0.0.0.0');
expect(net_utils.ip_toString(Buffer.from([255, 255, 255, 255]), 0, 4)).toBe('255.255.255.255');
expect(net_utils.ip_toString(Buffer.from([32, 1, 13, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]), 0, 16)).toBe('2001:db8::1');
expect(() => net_utils.ip_toString(Buffer.from([192, 168, 1, 1]), undefined, 4)).toThrow('Offset is required');
});

it('ipv4_to_buffer should convert IPv4 string to buffer', () => {
const buff = Buffer.alloc(4);
expect(net_utils.ipv4_to_buffer('192.168.1.1', buff, 0)).toEqual(Buffer.from([192, 168, 1, 1]));
});

it('ipv6_to_buffer should convert expanded IPv6 string to buffer', () => {
const buff = Buffer.alloc(16);
expect(net_utils.ipv6_to_buffer('2001:0db8:0000:0000:0000:0000:0000:0001', buff, 0)).toEqual(
Buffer.from([32, 1, 13, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
);
});

it('expend_ipv6 should expand IPv6 shorthand notation', () => {
expect(net_utils.expend_ipv6('::')).toEqual(['0', '0', '0', '0', '0', '0', '0', '0']);
expect(net_utils.expend_ipv6('2001:db8::1')).toEqual(['2001', 'db8', '0', '0', '0', '0', '0', '1']);
expect(net_utils.expend_ipv6('2001:db8::ff00:42:8329')).toEqual(['2001', 'db8', '0', '0', '0', 'ff00', '42', '8329']);
expect(net_utils.expend_ipv6('::1')).toEqual(['0', '0', '0', '0', '0', '0', '0', '1']);
expect(net_utils.expend_ipv6('2001:0db8:85a3::8a2e:370:7334')).toEqual(['2001', '0db8', '85a3', '0', '0', '8a2e', '370', '7334']);
expect(net_utils.expend_ipv6('::ffff:192.168.1.1')).toEqual(['0', '0', '0', '0', '0', 'ffff', 'c0a8', '0101']);
});

it('ip_toBuffer should convert IP strings to buffer', () => {
expect(net_utils.ip_toBuffer('10.0.0.1', Buffer.alloc(4), 0)).toEqual(Buffer.from([10, 0, 0, 1]));
expect(net_utils.ip_toBuffer('2001:db8::1', Buffer.alloc(16), 0)).toEqual(
Buffer.from([32, 1, 13, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
);
expect(() => net_utils.ip_toBuffer('invalid_ip', Buffer.alloc(16), 0)).toThrow('Invalid IP address: invalid_ip');
expect(() => net_utils.ip_toBuffer('10.0.0.1')).toThrow('Offset is required');
});
});
43 changes: 12 additions & 31 deletions src/util/http_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const dbg = require('./debug_module')(__filename);
const config = require('../../config');
const xml_utils = require('./xml_utils');
const jwt_utils = require('./jwt_utils');
const net_utils = require('./net_utils');
const time_utils = require('./time_utils');
const cloud_utils = require('./cloud_utils');
const ssl_utils = require('../util/ssl_utils');
Expand All @@ -45,38 +46,18 @@ const https_proxy_agent = HTTPS_PROXY ?
const unsecured_https_proxy_agent = HTTPS_PROXY ?
new HttpsProxyAgent(HTTPS_PROXY, { rejectUnauthorized: false }) : null;

const no_proxy_list =
(NO_PROXY ? NO_PROXY.split(',') : []).map(addr => {
if (net.isIPv4(addr) || net.isIPv6(addr)) {
return {
kind: 'IP',
addr
};
}

try {
ip_module.cidr(addr);
return {
kind: 'CIDR',
addr
};
} catch {
// noop
}

if (addr.startsWith('.')) {
return {
kind: 'FQDN_SUFFIX',
addr
};
}

return {
kind: 'FQDN',
addr
};
});
const no_proxy_list = (NO_PROXY ? NO_PROXY.split(',') : []).map(addr => {
let kind = 'FQDN';
if (net.isIPv4(addr) || net.isIPv6(addr)) {
kind = 'IP';
} else if (net_utils.is_cidr(addr)) {
kind = 'CIDR';
} else if (addr.startsWith('.')) {
kind = 'FQDN_SUFFIX';
}

return { kind, addr };
});

const parse_xml_to_js = xml2js.parseStringPromise;
const non_printable_regexp = /[\x00-\x1F]/;
Expand Down
Loading

0 comments on commit 4514fb7

Please sign in to comment.