question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Support for TLS/plaintext Port Unification

See original GitHub issue

Is your feature request related to a problem?

While trying to work with TLS, I was scanning through the current server setup. The NettyServerBuilder configures the port to be TLS or plaintext based on the presence or absence of SslContext, correspondingly. https://github.com/grpc/grpc-java/blob/012dbaf5be3fb0d532d977d288a0e42a58f30a7c/netty/src/main/java/io/grpc/netty/NettyServerBuilder.java#L352-L364

Resulting in a very little flexibility for the users to customize the port. Specifically, I was trying to see if we can accept both TLS & non-TLS connections on the same port without the need for creating a duplicate port. Netty demonstrates this through the doc.

Describe the solution you’d like

Approach1 Explicit public interface in NettyServerBuilder for enabling/disabling/multiplexing TLS. We could follow a similar approach of spiffing the initial bytes & dynamically configuring TLS.

Approach2 A public interface for adding child handlers to customize the connections. https://github.com/grpc/grpc-java/blob/012dbaf5be3fb0d532d977d288a0e42a58f30a7c/netty/src/main/java/io/grpc/netty/NettyServer.java#L228

Additional context

Relevant thread in stackoverflow: https://stackoverflow.com/questions/71484231/port-unification-in-grpc-java

Issue Analytics

  • State:open
  • Created 2 years ago
  • Comments:9 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
akh1ltcommented, Mar 23, 2022

@ejona86 Currently working on a local POC to add a custom ProtocolNegotiator using the InternalProtocolNegotiator.ProtocolNegotiator interface.

And multiplexing the handlers: InternalProtocolNegotiators.serverPlaintext().newHandler(grpcHttp2ConnectionHandler) InternalProtocolNegotiators.serverTls(sslContext).newHandler(grpcHttp2ConnectionHandler)

I’d be happy to raise a PR once my experiment goes through.

0reactions
akh1ltcommented, Jun 14, 2022

Yes, I was able to get it working. The basic idea remains the same

  1. Create a custom protocol negotiator, something like this
public class OptionalSSLProtocolNegotiator implements InternalProtocolNegotiator.ProtocolNegotiator {
  private SslContext sslContext;

  public OptionalSSLProtocolNegotiator(SslContext sslContext) {
    this.sslContext = sslContext;
  }

  public OptionalSSLProtocolNegotiator() {
    this.sslContext = null;
  }

  @Override
  public AsciiString scheme() {
    return AsciiString.of("https");
  }


  @Override
  public ChannelHandler newHandler(GrpcHttp2ConnectionHandler grpcHttp2ConnectionHandler) {
    ChannelHandler plaintext =
        InternalProtocolNegotiators.serverPlaintext().newHandler(grpcHttp2ConnectionHandler);
    ChannelHandler ssl =
        InternalProtocolNegotiators.serverTls(sslContext).newHandler(grpcHttp2ConnectionHandler);
    ChannelHandler decoder = new PortUnificationServerHandler(ssl, plaintext);
    return decoder;
  }

  @Override
  public void close() {}
  
  ProtocolNegotiationEvent getDefPNE() {
    ProtocolNegotiationEvent protocolNegotiationEvent = null;
    try {
      Field DEFAULT = ProtocolNegotiationEvent.class.getDeclaredField("DEFAULT");
      DEFAULT.setAccessible(true);
      return (ProtocolNegotiationEvent) DEFAULT.get(protocolNegotiationEvent);
    } catch (Exception e) {
      e.printStackTrace();
    }
    return protocolNegotiationEvent;
  }

  public class PortUnificationServerHandler extends ByteToMessageDecoder {
    private ProtocolNegotiationEvent pne;
    private final ChannelHandler ssl;
    private final ChannelHandler plaintext;
    public PortUnificationServerHandler(ChannelHandler ssl, ChannelHandler plaintext) {
      this.ssl = ssl;
      this.plaintext = plaintext;
      this.pne = getDefPNE();
    }

    private boolean isSsl(ByteBuf buf) {
      return SslHandler.isEncrypted(buf);
    }
    
   
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
        throws Exception {
      if (in.readableBytes() < 5) {
        return;
      }
      if (isSsl(in)) {
        ctx.pipeline().addAfter(ctx.name(), (String) null, this.ssl);
        ctx.fireUserEventTriggered(pne);
        ctx.pipeline().remove(this);
      } else {
        ctx.pipeline().addAfter(ctx.name(), (String) null, this.plaintext);
        ctx.fireUserEventTriggered(pne);
        ctx.pipeline().remove(this);
      }
    }
  }
}
  1. Use it in the netty builder
NettyServerBuilder.protocolNegotiator(new OptionalSSLProtocolNegotiator(sslContext));
Read more comments on GitHub >

github_iconTop Results From Across the Web

Quorum TLS - fix port unification to allow rolling upgrades
ZOOKEEPER-236 was committed with port unification support disabled, because of various issues with the implementation. These issues should be fixed so port ...
Read more >
Security Guide for Cisco Unity Connection Release 12.x
Unity Connection supports TLS 1.0, TLS 1.1 and TLS 1.2 for secure communication across various interfaces of Cisco Unity Connection. TLS 1.2 is ......
Read more >
SSL, TLS, and STARTTLS - Fastmail Help
SSL/TLS vs plaintext/STARTTLS port numbers. Depending on the type of connection and what encryption is supported, different port numbers might be needed.
Read more >
Project Grizzly - HTTP/2 Overview - Java EE
Grizzly supports HTTP/2 over plain text and TLS. However, to support HTTP/2 over TLS, you will be required to include a special library...
Read more >
Server basics — Armeria documentation
Ports; Services; Path patterns; Per service configuration; SSL/TLS ... Armeria is one of the few implementations that supports port unification:.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found