Skip to content

Commit

Permalink
net-address: Add get group function.
Browse files Browse the repository at this point in the history
This commit adds the getGroup function to net addresses. It allows for
network addresses to be grouped into buckets, such that we can limit the
number of outgoing connections per group to a certain amount. This will
allow for increased connection diversity and reduced attack surface
area.
  • Loading branch information
kilpatty committed Jul 6, 2019
1 parent cc1ef7a commit ddf5844
Show file tree
Hide file tree
Showing 2 changed files with 210 additions and 0 deletions.
104 changes: 104 additions & 0 deletions lib/net/netaddress.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,42 @@ class NetAddress extends bio.Struct {
return IP.isIPv6(this.raw);
}

/**
* Test whether the address is RFC3964.
* @returns {Boolean}
*/

isRFC3964() {
return IP.isRFC3964(this.raw);
}

/**
* Test whether the address is RFC4380.
* @returns {Boolean}
*/

isRFC4380() {
return IP.isRFC4380(this.raw);
}

/**
* Test whether the address is RFC6052.
* @returns {Boolean}
*/

isRFC6052() {
return IP.isRFC6052(this.raw);
}

/**
* Test whether the address is RFC6145.
* @returns {Boolean}
*/

isRFC6145() {
return IP.isRFC6145(this.raw);
}

/**
* Test whether the host is null.
* @returns {Boolean}
Expand Down Expand Up @@ -206,6 +242,74 @@ class NetAddress extends bio.Struct {
return IP.getReachability(this.raw, dest.raw);
}

/**
* Get the canonical identifier of our network group
* @returns {Buffer}
*/

getGroup() {
const group = [];
let type = IP.networks.INET6;
let startByte = 0;
let bits = 16;

// all local addresses belong to the same group
if (this.isLocal()) {
type = 255;
bits = 16;
}

// all other unroutable addresses belong to the same group
if (!this.isRoutable()) {
type = IP.networks.NONE;
bits = 0;
// for IPv4 addresses, '1' + the 16 higher-order bits of the IP
// includes mapped IPv4, SIIT translated IPv4, and the well-known prefix
} else if (this.isIPv4() || this.isRFC6145() || this.isRFC6052()) {
type = IP.networks.INET4;
startByte = 12;
// for 6to4 tunnelled addresses, use the encapsulated IPv4 address
} else if (this.isRFC3964()) {
type = IP.networks.INET4;
startByte = 2;
// for Teredo-tunnelled IPv6 addresses, use the encapsulated IPv4 address
} else if (this.isRFC4380()) {
group.push(IP.networks.INET4);
group.push(this.raw[12] ^ 0xff);
group.push(this.raw[13] ^ 0xff);
return Buffer.from(group);
} else if (this.isOnion()) {
type = IP.networks.ONION;
startByte = 6;
bits = 4;
// for he.net, use /36 groups
} else if (
this.raw[0] === 0x20 &&
this.raw[1] === 0x01 &&
this.raw[2] === 0x04 &&
this.raw[3] === 0x70
) {
bits = 36;
// for the rest of the IPv6 network, use /32 groups
} else {
bits = 32;
}

group.push(type);

while (bits >= 8) {
group.push(this.raw[startByte]);
startByte++;
bits -= 8;
}

if (bits > 0) {
group.push(this.raw[startByte] | ((1 << (8 - bits)) - 1));
}

return Buffer.from(group);
}

/**
* Set null host.
*/
Expand Down
106 changes: 106 additions & 0 deletions test/netaddress.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/* eslint-env mocha */
/* eslint prefer-arrow-callback: "off" */

'use strict';

const assert = require('bsert');
const NetAddress = require('../lib/net/netaddress');

describe('NetAddress', function() {
it('should return the correct group', () => {
// Local -> !Routable()
assert.bufferEqual(
NetAddress.fromHost('127.0.0.1', 13038, null, 'testnet').getGroup(),
Buffer.from([0])
);

// RFC1918 -> !Routable()
assert.bufferEqual(
NetAddress.fromHost('169.254.1.1', 13038, null, 'testnet').getGroup(),
Buffer.from([0])
);

// IPv4
assert.bufferEqual(
NetAddress.fromHost('1.2.3.4', 13038, null, 'testnet').getGroup(),
Buffer.from([1, 1, 2])
);

// RFC6145
assert.bufferEqual(
NetAddress.fromHost(
'::FFFF:0:102:304',
13038,
null,
'testnet'
).getGroup(),
Buffer.from([1, 1, 2])
);

// RFC6052
assert.bufferEqual(
NetAddress.fromHost(
'64:FF9B::102:304',
13038,
null,
'testnet'
).getGroup(),
Buffer.from([1, 1, 2])
);

// RFC3964
assert.bufferEqual(
NetAddress.fromHost(
'2002:102:304:9999:9999:9999:9999:9999',
13038,
null,
'testnet'
).getGroup(),
Buffer.from([1, 1, 2])
);

// RFC4380
assert.bufferEqual(
NetAddress.fromHost(
'2001:0:9999:9999:9999:9999:FEFD:FCFB',
13038,
null,
'testnet'
).getGroup(),
Buffer.from([1, 1, 2])
);

// Tor
assert.bufferEqual(
NetAddress.fromHost(
'FD87:D87E:EB43:edb1:8e4:3588:e546:35ca',
13038,
null,
'testnet'
).getGroup(),
Buffer.from([3, 239])
);

// he.net
assert.bufferEqual(
NetAddress.fromHost(
'2001:470:abcd:9999:9999:9999:9999:9999',
13038,
null,
'testnet'
).getGroup(),
Buffer.from([2, 32, 1, 4, 112, 175])
);

// IPv6
assert.bufferEqual(
NetAddress.fromHost(
'2001:2001:9999:9999:9999:9999:9999:9999',
13038,
null,
'testnet'
).getGroup(),
Buffer.from([2, 32, 1, 32, 1])
);
});
});

0 comments on commit ddf5844

Please sign in to comment.