Skip to content

Commit

Permalink
Merge pull request #1369 from mrfelton/proxy-tls
Browse files Browse the repository at this point in the history
grpc-js: initiate tls connection through http proxy
  • Loading branch information
murgatroid99 authored Apr 20, 2020
2 parents 03fdeed + eef75a5 commit c5424a5
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 7 deletions.
28 changes: 23 additions & 5 deletions packages/grpc-js/src/http_proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@
import { URL } from 'url';
import { log } from './logging';
import { LogVerbosity } from './constants';
import { getDefaultAuthority } from './resolver';
import { parseTarget } from './resolver-dns';
import { Socket } from 'net';
import * as http from 'http';
import * as tls from 'tls';
import * as logging from './logging';
import {
SubchannelAddress,
Expand Down Expand Up @@ -157,7 +159,8 @@ export interface ProxyConnectionResult {

export function getProxiedConnection(
address: SubchannelAddress,
channelOptions: ChannelOptions
channelOptions: ChannelOptions,
connectionOptions: tls.ConnectionOptions
): Promise<ProxyConnectionResult> {
if (!('grpc.http_connect_target' in channelOptions)) {
return Promise.resolve<ProxyConnectionResult>({});
Expand Down Expand Up @@ -202,10 +205,25 @@ export function getProxiedConnection(
' through proxy ' +
proxyAddressString
);
resolve({
socket,
realTarget,
});
if ('secureContext' in connectionOptions) {
/* The proxy is connecting to a TLS server, so upgrade this socket
* connection to a TLS connection.
* This is a workaround for https://github.com/nodejs/node/issues/32922
* See https://github.com/grpc/grpc-node/pull/1369 for more info. */
const cts = tls.connect({
...connectionOptions,
host: getDefaultAuthority(realTarget),
socket: socket,
}, () => {
resolve({ socket: cts, realTarget });
}
);
} else {
resolve({
socket,
realTarget,
});
}
} else {
log(
LogVerbosity.ERROR,
Expand Down
38 changes: 36 additions & 2 deletions packages/grpc-js/src/subchannel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import * as logging from './logging';
import { LogVerbosity } from './constants';
import { getProxiedConnection, ProxyConnectionResult } from './http_proxy';
import * as net from 'net';
import { ConnectionOptions } from 'tls';

const clientVersion = require('../../package.json').version;

Expand Down Expand Up @@ -300,7 +301,9 @@ export class Subchannel {
connectionOptions.servername = sslTargetNameOverride;
}
if (proxyConnectionResult.socket) {
connectionOptions.socket = proxyConnectionResult.socket;
connectionOptions.createConnection = (authority, option) => {
return proxyConnectionResult.socket!;
};
}
} else {
/* In all but the most recent versions of Node, http2.connect does not use
Expand All @@ -317,6 +320,7 @@ export class Subchannel {
}
};
}

connectionOptions = Object.assign(
connectionOptions,
this.subchannelAddress
Expand Down Expand Up @@ -412,7 +416,37 @@ export class Subchannel {
}

private startConnectingInternal() {
getProxiedConnection(this.subchannelAddress, this.options).then(
/* Pass connection options through to the proxy so that it's able to
* upgrade it's connection to support tls if needed.
* This is a workaround for https://github.com/nodejs/node/issues/32922
* See https://github.com/grpc/grpc-node/pull/1369 for more info. */
const connectionOptions: ConnectionOptions =
this.credentials._getConnectionOptions() || {};

if ('secureContext' in connectionOptions) {
connectionOptions.ALPNProtocols = ['h2'];
// If provided, the value of grpc.ssl_target_name_override should be used
// to override the target hostname when checking server identity.
// This option is used for testing only.
if (this.options['grpc.ssl_target_name_override']) {
const sslTargetNameOverride = this.options[
'grpc.ssl_target_name_override'
]!;
connectionOptions.checkServerIdentity = (
host: string,
cert: PeerCertificate
): Error | undefined => {
return checkServerIdentity(sslTargetNameOverride, cert);
};
connectionOptions.servername = sslTargetNameOverride;
}
}

getProxiedConnection(
this.subchannelAddress,
this.options,
connectionOptions
).then(
(result) => {
this.createSession(result);
},
Expand Down

0 comments on commit c5424a5

Please sign in to comment.