Skip to content

Commit

Permalink
resolveHost functionality (and moved isValidHost to network utils)
Browse files Browse the repository at this point in the history
  • Loading branch information
joshuakarp committed Nov 12, 2021
1 parent 747a009 commit ff45e0c
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 21 deletions.
15 changes: 7 additions & 8 deletions src/client/rpcNodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ import * as grpc from '@grpc/grpc-js';
import * as utilsPB from '../proto/js/polykey/v1/utils/utils_pb';
import * as nodesPB from '../proto/js/polykey/v1/nodes/nodes_pb';
import * as utils from '../client/utils';
import * as nodesUtils from '../nodes/utils';
import { utils as nodesUtils, errors as nodesErrors } from '../nodes';
import * as grpcUtils from '../grpc/utils';
import * as nodesErrors from '../nodes/errors';
import { makeNodeId } from '../nodes/utils';
import * as networkUtils from '../network/utils';

const createNodesRPC = ({
nodeManager,
Expand Down Expand Up @@ -44,13 +43,13 @@ const createNodesRPC = ({
if (!validNodeId) {
throw new nodesErrors.ErrorInvalidNodeId();
}
const validHost = nodesUtils.isValidHost(
const validHost = networkUtils.isValidHost(
call.request.getAddress()!.getHost(),
);
if (!validHost) {
throw new nodesErrors.ErrorInvalidHost();
}
await nodeManager.setNode(makeNodeId(call.request.getNodeId()), {
await nodeManager.setNode(nodesUtils.makeNodeId(call.request.getNodeId()), {
ip: call.request.getAddress()!.getHost(),
port: call.request.getAddress()!.getPort(),
} as NodeAddress);
Expand All @@ -74,7 +73,7 @@ const createNodesRPC = ({
);
call.sendMetadata(responseMeta);
const status = await nodeManager.pingNode(
makeNodeId(call.request.getNodeId()),
nodesUtils.makeNodeId(call.request.getNodeId()),
);
response.setSuccess(status);
} catch (err) {
Expand All @@ -98,7 +97,7 @@ const createNodesRPC = ({
await sessionManager.generateToken(),
);
call.sendMetadata(responseMeta);
const remoteNodeId = makeNodeId(call.request.getNodeId());
const remoteNodeId = nodesUtils.makeNodeId(call.request.getNodeId());
const gestaltInvite = await notificationsManager.findGestaltInvite(
remoteNodeId,
);
Expand Down Expand Up @@ -137,7 +136,7 @@ const createNodesRPC = ({
await sessionManager.generateToken(),
);
call.sendMetadata(responseMeta);
const nodeId = makeNodeId(call.request.getNodeId());
const nodeId = nodesUtils.makeNodeId(call.request.getNodeId());
const address = await nodeManager.findNode(nodeId);
response
.setNodeId(nodeId)
Expand Down
3 changes: 3 additions & 0 deletions src/network/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ class ErrorCertChainKeyInvalid extends ErrorCertChain {}
*/
class ErrorCertChainSignatureInvalid extends ErrorCertChain {}

class ErrorHostnameResolutionFailed extends ErrorNetwork {}

export {
ErrorNetwork,
ErrorForwardProxyNotStarted,
Expand Down Expand Up @@ -110,4 +112,5 @@ export {
ErrorCertChainNameInvalid,
ErrorCertChainKeyInvalid,
ErrorCertChainSignatureInvalid,
ErrorHostnameResolutionFailed,
};
36 changes: 34 additions & 2 deletions src/network/utils.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import type { Socket } from 'net';
import type { TLSSocket } from 'tls';
import type { Host, Port, Address, NetworkMessage } from './types';
import type { Host, Hostname, Port, Address, NetworkMessage } from './types';
import type { Certificate, PublicKey } from '../keys/types';
import type { NodeId } from '../nodes/types';

import { Buffer } from 'buffer';
import { IPv4, IPv6, Validator } from 'ip-num';
import dns from 'dns';
import * as networkErrors from './errors';
import { isEmptyObject } from '../utils';
import { isEmptyObject, promisify } from '../utils';
import { utils as keysUtils } from '../keys';

const pingBuffer = serializeNetworkMessage({
Expand Down Expand Up @@ -53,6 +54,35 @@ function parseAddress(address: string): [Host, Port] {
return [dstHost as Host, dstPort as Port];
}

/**
* Validates that a provided host address is a valid IPv4 or IPv6 address.
*/
function isValidHost(host: string): boolean {
const [isIPv4] = Validator.isValidIPv4String(host);
const [isIPv6] = Validator.isValidIPv6String(host);
return isIPv4 || isIPv6;
}

/**
* Resolves a provided hostname to its respective IP address (type Host).
*/
async function resolveHost(host: Host | Hostname): Promise<Host> {
// If already IPv4/IPv6 address, return it
if (isValidHost(host)) {
return host as Host;
}
const lookup = promisify(dns.lookup).bind(dns);
let resolvedHost;
try {
// Resolve the hostname and get the IPv4 address
resolvedHost = await lookup(host, 4);
} catch (e) {
throw new networkErrors.ErrorHostnameResolutionFailed(e.message);
}
// Returns an array of [ resolved address, family (4 or 6) ]
return resolvedHost[0] as Host;
}

/**
* Zero IPs should be resolved to localhost when used as the target
* This is usually done automatically, but utp-native doesn't do this
Expand Down Expand Up @@ -317,6 +347,8 @@ export {
toAuthToken,
buildAddress,
parseAddress,
isValidHost,
resolveHost,
resolvesZeroIP,
serializeNetworkMessage,
unserializeNetworkMessage,
Expand Down
10 changes: 0 additions & 10 deletions src/nodes/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,6 @@ function makeNodeId(arg: any): NodeId {
return makeIdString<NodeId>(arg, 32, 'base32hex');
}

/**
* Validates that a provided host address is a valid IPv4 or IPv6 address.
*/
function isValidHost(host: string): boolean {
const [isIPv4] = Validator.isValidIPv4String(host);
const [isIPv6] = Validator.isValidIPv6String(host);
return isIPv4 || isIPv6;
}

/**
* Node ID to an array of 8-bit unsigned ints
*/
Expand Down Expand Up @@ -103,7 +94,6 @@ export {
calculateBucketIndex,
isNodeId,
makeNodeId,
isValidHost,
nodeIdToU8,
sortByDistance,
};
12 changes: 11 additions & 1 deletion tests/network/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Host, Port } from '@/network/types';

import * as networkUtils from '@/network/utils';
import { utils as networkUtils, errors as networkErrors } from '@/network';

describe('utils', () => {
test('building addresses', async () => {
Expand All @@ -23,4 +23,14 @@ describe('utils', () => {
),
).toBe('::1' as Host);
});
test('resolving hostnames', async () => {
await expect(
networkUtils.resolveHost('www.google.com' as Host)
).resolves.toBeDefined();
let host = await networkUtils.resolveHost('www.google.com' as Host);
expect(networkUtils.isValidHost(host)).toBeTruthy();
await expect(
networkUtils.resolveHost('invalidHostname' as Host)
).rejects.toThrow(networkErrors.ErrorHostnameResolutionFailed);
});
});

0 comments on commit ff45e0c

Please sign in to comment.