Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DRILL-4335: Apache Drill should support network encryption. #773

Closed
wants to merge 1 commit into from

Conversation

@sohami
Copy link
Contributor

sohami commented Mar 7, 2017

DRILL-4335: Apache Drill should support network encryption.

This pull request add's network encryption capability between Java Drill Client and Drillbit channel and also between Drillbit to Drillbit channel. It is extending SASL Authentication framework to support encryption.

@sohami sohami force-pushed the sohami:DRILL-4335-Java-02282017 branch from 9b7b38f to 3f449df Apr 3, 2017
Copy link
Contributor

sudheeshkatkam left a comment

Initial set of comments, with a few nits

  • use final generously for readability
  • fix spacing, specially around function signatures (best to fix your IDE settings)

I haven't reviewed the handlers yet

@@ -116,6 +116,11 @@
String BIT_AUTHENTICATION_ENABLED = "drill.exec.security.bit.auth.enabled";
String BIT_AUTHENTICATION_MECHANISM = "drill.exec.security.bit.auth.mechanism";
String USE_LOGIN_PRINCIPAL = "drill.exec.security.bit.auth.use_login_principal";
String USER_SASL_ENCRYPTION_ENABLED = "drill.exec.security.user.sasl.encryption.enabled";

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam Apr 5, 2017

Contributor

How about using "drill.exec.security.user.encryption.sasl.enabled" instead of "drill.exec.security.user.sasl.encryption.enabled" to be consistent with "auth" (and similarly below)?

This comment has been minimized.

Copy link
@sohami

sohami Apr 17, 2017

Author Contributor

Renamed as suggested.

/*
* The helper interface to wrap SaslClient and SaslServer instances for use in Security Handlers.
*/
public interface SaslBackendWrapper{

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam Apr 5, 2017

Contributor

How about "SaslCodec", as in coder-decoder?

This comment has been minimized.

Copy link
@sohami

sohami Apr 17, 2017

Author Contributor

Renamed to SaslCodecContext.


int maxEncodeSize = config.getInt(ExecConstants.BIT_SASL_ENCRYPTION_ENCODESIZE);

if(maxEncodeSize > RpcConstants.MAX_WRAP_SIZE) {

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam Apr 5, 2017

Contributor
  • spacing
  • check for non-negative

This comment has been minimized.

Copy link
@sohami

sohami Apr 17, 2017

Author Contributor

Fixed.


@Override
public void channelClosed(RpcException ex) {
// This will be triggered from Netty when a channel is closed. We should cleanup here

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam Apr 5, 2017

Contributor

nice catch

This comment has been minimized.

Copy link
@sohami

sohami Apr 17, 2017

Author Contributor

thanks!

logger.warn("Setting bit.sasl.encryption.encodesize to maximum allowed value of 16MB");
maxEncodeSize = RpcConstants.MAX_WRAP_SIZE;
}
encryptionContext.setWrappedChunkSize(maxEncodeSize);

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam Apr 5, 2017

Contributor

I have difficulty in understanding what these sizes mean. I could at least classify them as related, but how are they related? Better names maybe?

  • "maxEncodeSize", "ENCODESIZE", "WrappedChunkSize", "MAX_WRAP_SIZE"
  • "RawSendSize", "RawWrapSendSize", "MaxRawWrapSendSize", "WRAP_RAW_SEND_SIZE"

Sometimes "max" is not necessarily a maximum e.g. maxEncodeSize, and setRawWrapSendSize sets MaxRawWrapSendSize.

I noticed only "ENCODESIZE" is configurable through drill-override.conf. Are the others not configurable, at connection time, for example?

This comment has been minimized.

Copy link
@sohami

sohami Apr 17, 2017

Author Contributor

Sorry about the confusion. I have renamed the variables, hope that helps.

maxEncodeSize -- maxWrappedSize. This configurable parameter defines the maximum size of wrapped buffer that wrap call can produce. It's negotiated as part of SASL handshake and has maximum limit of 16MB
rawSendSize -- wrapSizeLimit. This parameter (non-configurable) is the maximum plain buffer size which we can pass to wrap function so that wrapped buffer size doesn't exceed maxWrappedSize. This is obtained after SASL negotiation is completed.

@@ -61,6 +63,10 @@ public ClusterInfo getClusterInfoJSON() {
final DrillbitEndpoint currentDrillbit = work.getContext().getEndpoint();
final String currentVersion = currentDrillbit.getVersion();

final DrillConfig config = work.getContext().getConfig();
final boolean clientEncryptionEnabled = config.getBoolean(ExecConstants.USER_SASL_ENCRYPTION_ENABLED);

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam Apr 5, 2017

Contributor

For consistency, use userEncryptionEnabled and bitEncryptionEnabled

This comment has been minimized.

Copy link
@sohami

sohami Apr 17, 2017

Author Contributor

Changed the name

/**
* Helps to add all the required security handler's after negotiation for encryption is completed.
* <p>
* Handler's that are added are:

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam Apr 5, 2017

Contributor

Please document the order of handlers before and after this method is invoked.

This comment has been minimized.

Copy link
@sohami

sohami Apr 17, 2017

Author Contributor

Added documentation.

public void addSecurityHandlers() {

final ChannelPipeline channelPipeline = getChannel().pipeline();
channelPipeline.addFirst("SaslDecryptionHandler", new SaslDecryptionHandler(saslBackend, getWrappedChunkSize(),

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam Apr 5, 2017

Contributor

Define handler names as class constants, specially "message-decoder", which is from another class.

This comment has been minimized.

Copy link
@sohami

sohami Apr 17, 2017

Author Contributor

Moved all the handlers names as part of RpcConstants and using that in BasicClient/BasicServer as well.

@@ -51,6 +51,22 @@

SocketAddress getRemoteAddress();

void addSecurityHandlers();

boolean isEncrypted();

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam Apr 5, 2017

Contributor

Maybe getEncryptionContext to avoid adding setters and getters to this class if EncryptionContext is modified?

@@ -22,6 +22,15 @@

private RpcConstants(){}

public static final boolean SOME_DEBUGGING = false;
static final boolean SOME_DEBUGGING = false;

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam Apr 5, 2017

Contributor

make constants public

This comment has been minimized.

Copy link
@sohami

sohami Apr 17, 2017

Author Contributor

Fixed.

@sohami sohami force-pushed the sohami:DRILL-4335-Java-02282017 branch 4 times, most recently from a3ad8cd to 5cfda62 Apr 17, 2017
Copy link
Contributor

sudheeshkatkam left a comment

Two major concerns: this patch would increase heap memory consumption of idle connections, and there seem to be effects of one connection on another.

Other are mainly readability related.

@@ -51,6 +51,12 @@

SocketAddress getRemoteAddress();

void addSecurityHandlers();

void incConnectionCounter();

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam Apr 26, 2017

Contributor

Remove this increment and decrement counters from the interface; these methods are invoked on implementations.

Maybe empty protected methods in AbstractRemoteConnection with impls in concrete classes?

This comment has been minimized.

Copy link
@sohami

sohami May 1, 2017

Author Contributor

Removed the methods from interface.

* <li> EXCEPTION_HANDLER {@link RpcExceptionHandler}
* </ul>
* <p>
* If encryption is enabled ChunkCreationHandler is always added to divide the Rpc message into chunks of

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam Apr 26, 2017

Contributor

But does always adding the ChunckCreationHandler have performance implications?

This comment has been minimized.

Copy link
@sohami

sohami Apr 26, 2017

Author Contributor

This is required since Encoded Message size cannot be bigger than 16MB, this handler will take care of that. Keeping a separate handler for chunking purpose also helps to keep the encryption and chunking logic separate. As far as performance degradation is concerned I don't think there should be any notable difference.


package org.apache.drill.exec.rpc;

public interface EncryptionContext {

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam Apr 26, 2017

Contributor

Maybe rename to EncryptionOptions or EncryptionSettings? This also fits well with two implementations based on lifecycle: configured encryption options (immutable, defined in config classes) and connection encryption options (negotiated).

And instead of connection interface implementing this interface, maybe have a getEncryptionOptions in the RemoteConnection interface. So the usage would be: connection.getEncryptionOptions().isEnabled() or connection.getEncryptionOptions().getMaxWrappedSize().

This is a variant of what you had previously. Sorry for the back and forth on this.

This comment has been minimized.

Copy link
@sohami

sohami May 1, 2017

Author Contributor

As discussed keeping as is. The main purpose of changing to a separate interface for EncryptionContext was to keep RemoteConnection interface as is which was the concern in previous comment. Doing getEncryptionOptions to return the instance of EncryptionContextImpl gives control to the caller to set and get upon the instance. Since instance is private to a connection it should only be allowed to change the state and caller will only have exposure to the functions as needed.

int numChunks = (int) Math.ceil((double) msg.readableBytes() / chunkSize);

// Initialize a composite buffer to hold numChunks chunk.
CompositeByteBuf cbb = new CompositeByteBuf(ctx.alloc(), true, numChunks);

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam Apr 26, 2017

Contributor
  • Use ctx.alloc().compositeDirectBuffer(...)?
  • final

This comment has been minimized.

Copy link
@sohami

sohami May 1, 2017

Author Contributor

used this based on reference in RpcEncoder. Will change in both the places since this is the recommended way.

import org.apache.drill.exec.server.BootStrapContext;
import org.apache.drill.exec.work.batch.ControlMessageHandler;

import com.google.common.collect.Lists;
import com.google.protobuf.Message;
import com.google.protobuf.MessageLite;
import com.google.protobuf.Parser;
import org.apache.hadoop.io.ReadaheadPool;

This comment has been minimized.

Copy link
@sudheeshkatkam

This comment has been minimized.

Copy link
@sohami

sohami May 1, 2017

Author Contributor

Removed.

try {
// Check if connection was marked for being secure then verify for negotiated QOP value for
// correctness.
final String negotiatedQOP = saslClient.getNegotiatedProperty(Sasl.QOP).toString();

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam Apr 26, 2017

Contributor

Could .toString() throw NPE, since null QOP is same as "auth"?

This comment has been minimized.

Copy link
@sohami

sohami May 1, 2017

Author Contributor

Null QOP is not auth. Instead when we pass QOP as null the mechanism will use the default QOP value for negotiation which is auth. So getNegotiatedProperty will always return a valid object.

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam May 1, 2017

Contributor

Hmm, I read that in Sasl.QOP doc:

... If this property is absent, the default qop is "auth"....

So the change is required?

This comment has been minimized.

Copy link
@sohami

sohami May 3, 2017

Author Contributor

No change is required here since getNegotiatedProperty will always return a valid object.

"value of sasl.encryption.encodesize. It might be configured to a very small value.",
negotiatedRawSendSize));
}
connection.setWrapSizeLimit(negotiatedRawSendSize);

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam Apr 26, 2017

Contributor

Please fix naming (or maybe I am easily confused).

wrapSizeLimit and negotiatedRawSendSize, contrast with maxRawWrapSize in SaslEncryptionHandler. All of which are actually maxSendBufferSize per documentation in Sasl.RAW_SEND_SIZE.

This comment has been minimized.

Copy link
@sohami

sohami May 1, 2017

Author Contributor

Changed the name in SaslEncryptionHandler to wrapSizeLimit as well. Don't want to keep the name as maxSendBufferSize since i.e. very generic name and it is actually a rawSendSize from sasl perspective for wrap function. From Drill's perspective I think wrapSizeLimit makes more sense.

public static final String MESSAGE_HANDLER = "message-handler";
public static final String EXCEPTION_HANDLER = "exception-handler";
public static final String IDLE_STATE_HANDLER = "idle-state-handler";
public static final String SASL_DECRYPTION_HANDLER = "sasldecryption-handler";

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam Apr 26, 2017

Contributor

sasl-decryption-handler
sasl-encryption-handler
chunk-creation-handler

This comment has been minimized.

Copy link
@sohami

sohami May 1, 2017

Author Contributor

Fixed

public static final int MAX_WRAPPED_SIZE = 0XFFFFFF;

public static final int LENGTH_FIELD_OFFSET = 0;
public static final int LENGTH_FIELD_LENGTH = 4;

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam Apr 26, 2017

Contributor

Better name for LENGTH_FIELD_LENGTH?

This comment has been minimized.

Copy link
@sohami

sohami May 1, 2017

Author Contributor

Borrowed the terminology from LengthFieldBasedFrameDecoder which indicates the length of length field.

msg.skipBytes(wrappedMsgLength);

// Allocate a new Bytebuf to copy the decrypted chunk.
ByteBuf decodedMsgBuf = ctx.alloc().buffer(decodedMsg.length);

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam Apr 26, 2017

Contributor

final

This comment has been minimized.

Copy link
@sohami

sohami May 1, 2017

Author Contributor

Fixed.

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam May 1, 2017

Contributor

Not fixed?

This comment has been minimized.

Copy link
@sohami

sohami May 3, 2017

Author Contributor

Fixed for sure now.

@sohami sohami force-pushed the sohami:DRILL-4335-Java-02282017 branch 2 times, most recently from 5221ca5 to 0e0088c May 1, 2017
Copy link
Contributor

sudheeshkatkam left a comment

Last round

try {
// Check if connection was marked for being secure then verify for negotiated QOP value for
// correctness.
final String negotiatedQOP = saslClient.getNegotiatedProperty(Sasl.QOP).toString();

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam May 1, 2017

Contributor

Hmm, I read that in Sasl.QOP doc:

... If this property is absent, the default qop is "auth"....

So the change is required?

*/
SaslMessage process(SaslChallengeContext context) throws Exception;
SaslMessage process(SaslChallengeContext<?> context) throws Exception;

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam May 1, 2017

Contributor

Why not this signature?

<C extends ClientConnection> process(SaslChallengeContext<C> context) throws Exception;


// Create slices of chunkSize from input msg and add it to the composite buffer.
while (numChunks > 0) {
chunkBuf = msg.slice(msg.readerIndex(), currentChunkLen);

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam May 1, 2017

Contributor

final ByteBuf chunkBuf ...

msg.skipBytes(wrappedMsgLength);

// Allocate a new Bytebuf to copy the decrypted chunk.
ByteBuf decodedMsgBuf = ctx.alloc().buffer(decodedMsg.length);

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam May 1, 2017

Contributor

Not fixed?

msg.skipBytes(RpcConstants.LENGTH_FIELD_LENGTH);

// Since lengthBasedFrameDecoder will ensure we have enough bytes it's good to have this check here.
checkArgument(msg.readableBytes() >= wrappedMsgLength);

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam May 1, 2017

Contributor

Looks like an assert to me.

(checkState and checkArgument both does the same thing throw different exceptions.)

checkArgument(msg instanceof CompositeByteBuf);

final CompositeByteBuf cbb = (CompositeByteBuf) msg;
int numComponents = cbb.numComponents();

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam May 1, 2017

Contributor

You could do this:

final int numComponents = cbb.numComponents();
for (int currentIndex = 0; currentIndex < numComponents; currentIndex++) {...}
@@ -116,6 +116,11 @@
String BIT_AUTHENTICATION_ENABLED = "drill.exec.security.bit.auth.enabled";
String BIT_AUTHENTICATION_MECHANISM = "drill.exec.security.bit.auth.mechanism";
String USE_LOGIN_PRINCIPAL = "drill.exec.security.bit.auth.use_login_principal";
String USER_ENCRYPTION_SASL_ENABLED = "drill.exec.security.user.encryption.sasl.enabled";
String USER_ENCRYPTION_SASL_MAX_WRAPPED_SIZE = "drill.exec.security.user.encryption.sasl.max_wrapped_size";

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam May 1, 2017

Contributor

We should document this config parameter due to the change in name (from "maximum size of the raw send buffer in bytes" to max_wrapped_size).

From Sasl.RAW_SEND_SIZE doc:

The name of a property that specifies the maximum size of the raw send buffer in bytes of SaslClient/SaslServer. The property contains the string representation of an integer. The value of this property is negotiated between the client and server during the authentication exchange.

This comment has been minimized.

Copy link
@sohami

sohami May 3, 2017

Author Contributor

Sure. Will make sure to have it properly documented as part encryption information on Apache portal. I am also planning to update the design doc with the new name of the config parameter.

/**
* Holder interface for all the metrics used in RPC layer
*/
public interface RpcMetrics {

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam May 1, 2017

Contributor

-0 for this plumbing.

The end result is that only static state (counters) is being modified using instances, which is not recommended (ref). So the hierarchy is not required.

@@ -124,6 +125,8 @@ message BitToUserHandshake {
optional RpcEndpointInfos server_infos = 6;
repeated string authenticationMechanisms = 7;
repeated RpcType supported_methods = 8;
optional bool encrypted = 9;
optional int32 wrapChunkSize = 10;

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam May 1, 2017

Contributor

Change name to maxWrappedSize

@@ -111,7 +111,7 @@ protected void encode(ChannelHandlerContext ctx, OutboundRpcMessage msg, List<Ob
cos.writeRawVarint32(rawBodyLength);
cos.flush(); // need to flush so that dbody goes after if cos is caching.

CompositeByteBuf cbb = new CompositeByteBuf(buf.alloc(), true, msg.dBodies.length + 1);
final CompositeByteBuf cbb = ctx.alloc().compositeBuffer(msg.dBodies.length + 1);

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam May 2, 2017

Contributor

ctx.alloc().compositeDirectBuffer(...)

This comment has been minimized.

Copy link
@sohami

sohami May 3, 2017

Author Contributor

Same as above.

int numChunks = (int) Math.ceil((double) msg.readableBytes() / chunkSize);

// Initialize a composite buffer to hold numChunks chunk.
final CompositeByteBuf cbb = ctx.alloc().compositeBuffer(numChunks);

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam May 2, 2017

Contributor

ctx.alloc().compositeDirectBuffer(...)

This comment has been minimized.

Copy link
@sohami

sohami May 3, 2017

Author Contributor

Call to compositeBuffer(..) allocates direct or heap buffer based on internal implementation of the allocator. In case of Drill by default all allocation happens on direct memory by allocator. In future if the internal allocation moves from supporting direct to heap then the change won't be needed explicitly here. It will be taken care of.


try {
// If encryption is enabled then this handler will always get ByteBuf of type Composite ByteBuf
checkArgument(msg instanceof CompositeByteBuf);

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam May 2, 2017

Contributor

assert

@@ -201,10 +223,12 @@ protected SaslException mapException(Exception e) {
if (e instanceof ExecutionException) {
final Throwable cause = Throwables.getRootCause(e);
if (cause instanceof SaslException) {
return new SaslException("Authentication failed: " + cause.getMessage(), cause);
return new SaslException(String.format("Authentication failed with encryption context %s with error %s",

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam May 2, 2017

Contributor

For an end user, this is a dense error message:

Authentication failed with encryption context Encryption: .. , MaxWrappedChunkSize: .. , MaxRawWrapSendSize .. with error ..

Could we improve the error message, here and below?

This comment has been minimized.

Copy link
@sohami

sohami May 3, 2017

Author Contributor

As discussed made encryption context information part of Details section.

@sohami sohami force-pushed the sohami:DRILL-4335-Java-02282017 branch from 0e0088c to fb0de14 May 3, 2017
Copy link
Contributor

sudheeshkatkam left a comment

+1, pending minor comments

final int maxWrappedSize = config.getInt(ExecConstants.BIT_ENCRYPTION_SASL_MAX_WRAPPED_SIZE);

if (maxWrappedSize <= 0 || maxWrappedSize > RpcConstants.MAX_WRAPPED_SIZE) {
throw new DrillbitStartupException("Invalid value configured for bit.encryption.sasl.encodesize." +

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam May 5, 2017

Contributor

encodesize -> max_wrapped_size

final int maxWrappedSize = config.getInt(ExecConstants.USER_ENCRYPTION_SASL_MAX_WRAPPED_SIZE);

if (maxWrappedSize <= 0 || maxWrappedSize > RpcConstants.MAX_WRAPPED_SIZE) {
throw new DrillbitStartupException("Invalid value configured for user.encryption.sasl.encodesize." +

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam May 5, 2017

Contributor

encodesize -> max_wrapped_size

}

@Override
public void setMaxWrappedSize(int maxWrappedChunkSize) {

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam May 5, 2017

Contributor

maxWrappedChunkSize -> maxWrappedSize; in argument and message

public SaslMessage process(SaslChallengeContext context) throws Exception {
throw new SaslException("Authentication failed. Incorrect credentials?");
public <CC extends ClientConnection> SaslMessage process(SaslChallengeContext<CC> context) throws Exception {
throw new SaslException(String.format("Authentication with encryption context %s failed. Incorrect credentials?",

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam May 5, 2017

Contributor

Fix error message format to match the format in UserClient.

}
}
return new SaslException("Authentication failed unexpectedly.", e);
return new SaslException(String.format("Authentication failed. [Details: %s, Error %s",

This comment has been minimized.

Copy link
@sudheeshkatkam

sudheeshkatkam May 5, 2017

Contributor

Two fixes: Authentication failed unexpectedly. [Details: %s, Error %s ]


import java.net.SocketAddress;
import java.nio.ByteOrder;

This comment has been minimized.

Copy link
@sudheeshkatkam
@sohami sohami force-pushed the sohami:DRILL-4335-Java-02282017 branch from fb0de14 to 7f301cc May 8, 2017
@sohami sohami force-pushed the sohami:DRILL-4335-Java-02282017 branch from 7f301cc to 29b1eab May 10, 2017
@sohami sohami force-pushed the sohami:DRILL-4335-Java-02282017 branch from 29b1eab to 0bac833 May 20, 2017
    NOTE: This pull request provides support for on-wire encryption using SASL framework. The communication channel that are covered are:
    1) Between Drill JDBC client and Drillbit.
    2) Between Drillbit to Drillbit i.e. control/data channels.
    3) It has UI change to view encryption is enabled on which network channel and number of encrypted/unencrypted connections for
       user/control/data connections.
@sohami sohami force-pushed the sohami:DRILL-4335-Java-02282017 branch from 0bac833 to 2aa07a6 May 20, 2017
@asfgit asfgit closed this in ce8bbc0 May 20, 2017
@sohami sohami deleted the sohami:DRILL-4335-Java-02282017 branch Mar 21, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants
You can’t perform that action at this time.