r2dbc-postgresql icon indicating copy to clipboard operation
r2dbc-postgresql copied to clipboard

SSL SNI hostname with trailing dot unable to connect

Open seanmcnealy opened this issue 1 year ago • 0 comments
trafficstars

Bug Report

Versions

  • Driver: n/a
  • Database: n/a
  • Java: n/a
  • OS: n/a

Current Behavior

SSL SNI hostname with trailing dot unable to connect. Throws a bit of a weird error.

Disabling SNI works fine. So this is a minor issue. But the same hostnames worked in the previous version using default settings and do not work in the current version with default settings.

Stack trace
java.lang.RuntimeException: java.lang.IllegalArgumentException: Server name value of host_name cannot have the trailing dot
	at io.r2dbc.postgresql.client.ReactorNettyClient.registerSslHandler(ReactorNettyClient.java:422)
	at io.r2dbc.postgresql.client.ReactorNettyClient.lambda$connect$11(ReactorNettyClient.java:402)
	at reactor.netty.transport.TransportConfig$TransportChannelInitializer.initChannel(TransportConfig.java:418)
	at io.netty.channel.ChannelInitializer.initChannel(ChannelInitializer.java:129)
	at io.netty.channel.ChannelInitializer.handlerAdded(ChannelInitializer.java:112)
	at io.netty.channel.AbstractChannelHandlerContext.callHandlerAdded(AbstractChannelHandlerContext.java:1130)
	at io.netty.channel.DefaultChannelPipeline.callHandlerAdded0(DefaultChannelPipeline.java:609)
	at io.netty.channel.DefaultChannelPipeline.access$100(DefaultChannelPipeline.java:46)
	at io.netty.channel.DefaultChannelPipeline$PendingHandlerAddedTask.execute(DefaultChannelPipeline.java:1463)
	at io.netty.channel.DefaultChannelPipeline.callHandlerAddedForAllHandlers(DefaultChannelPipeline.java:1115)
	at io.netty.channel.DefaultChannelPipeline.invokeHandlerAddedIfNeeded(DefaultChannelPipeline.java:650)
	at io.netty.channel.AbstractChannel$AbstractUnsafe.register0(AbstractChannel.java:514)
	at io.netty.channel.AbstractChannel$AbstractUnsafe.access$200(AbstractChannel.java:429)
	at io.netty.channel.AbstractChannel$AbstractUnsafe$1.run(AbstractChannel.java:486)
	at io.netty.util.concurrent.AbstractEventExecutor.runTask$$$capture(AbstractEventExecutor.java:173)
	at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java)
	at io.netty.util.concurrent.AbstractEventExecutor.safeExecute$$$capture(AbstractEventExecutor.java:166)
	at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java)
	at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:569)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.IllegalArgumentException: Server name value of host_name cannot have the trailing dot
	at java.base/javax.net.ssl.SNIHostName.checkHostName(SNIHostName.java:320)
	at java.base/javax.net.ssl.SNIHostName.<init>(SNIHostName.java:108)
	at io.r2dbc.postgresql.PostgresqlConnectionConfiguration$Builder.appendSniHost(PostgresqlConnectionConfiguration.java:1201)
	at io.r2dbc.postgresql.PostgresqlConnectionConfiguration$Builder.lambda$getSslParametersFactory$3(PostgresqlConnectionConfiguration.java:1189)
	at io.r2dbc.postgresql.client.AbstractPostgresSSLHandlerAdapter.<init>(AbstractPostgresSSLHandlerAdapter.java:50)
	at io.r2dbc.postgresql.client.SSLSessionHandlerAdapter.<init>(SSLSessionHandlerAdapter.java:41)
	at io.r2dbc.postgresql.client.ReactorNettyClient.registerSslHandler(ReactorNettyClient.java:416)
	... 23 common frames omitted
io.r2dbc.postgresql.PostgresqlConnectionFactory$PostgresConnectionException: [08003] Cannot connect to database.internal./<unresolved>:5432
	at io.r2dbc.postgresql.PostgresqlConnectionFactory.cannotConnect(PostgresqlConnectionFactory.java:188)
	at io.r2dbc.postgresql.PostgresqlConnectionFactory.lambda$doCreateConnection$7(PostgresqlConnectionFactory.java:153)
	at reactor.core.publisher.Mono.lambda$onErrorMap$28(Mono.java:3783)
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:94)
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.onError(MonoFlatMap.java:180)
	at reactor.core.publisher.MonoDelayUntil$DelayUntilCoordinator.onError(MonoDelayUntil.java:200)
	at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onError(FluxMapFuseable.java:142)
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.onError(MonoFlatMap.java:180)
	at reactor.core.publisher.MonoCreate$DefaultMonoSink.error(MonoCreate.java:201)
	at reactor.netty.resources.NewConnectionProvider$DisposableConnect.onError(NewConnectionProvider.java:156)
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.secondError(MonoFlatMap.java:241)
Caused by: io.netty.channel.StacklessClosedChannelException
	at io.netty.channel.AbstractChannel$AbstractUnsafe.ensureOpen(ChannelPromise)(Unknown Source)

Steps to reproduce

Use a hostname with a trailing .

Input Code

import io.r2dbc.postgresql.PostgresqlConnectionConfiguration
import io.r2dbc.postgresql.PostgresqlConnectionFactory
import io.r2dbc.postgresql.client.SSLMode

val config =
    PostgresqlConnectionConfiguration.builder()
        .host("database.internal.")
        .port(5432)
        .database("reporting")
        .username("user")
        .password("xxxx")
        .sslMode(SSLMode.REQUIRE)
        .build()
val factory = PostgresqlConnectionFactory(config)

factory.create().block()

Expected behavior/code

I expected the new 1.0.5 version to work like 1.0.4. But my hostnames conflicted with the new SNI feature.

Possible Solution

Configuring SNI to OFF works fine.

Extend SSLConfig.isValidSniHostname function to check for trailing . like SNIHostName does.

Additional context

seanmcnealy avatar May 23 '24 21:05 seanmcnealy