Hi Karol,

On Thu, Jun 11, 2026 at 02:20:23PM +0200, Karol Kucharski wrote:
> Hi,
> 
> I tested a simple configuration with connecting to a tls backend server
> using kTLS.
> 
> haproxy.cfg
> ```
> global
>      expose-experimental-directives
> 
> defaults
>      mode tcp
>      timeout connect 5s
>      timeout client 30s
>      timeout server 30s
> 
> frontend my_frontend
>      bind *:8080
>      use_backend my_backend
> 
> backend my_backend
>      server my_server 10.1.0.3:4043 ssl verify none ktls on force-tlsv12
> ```
> 
> I've noticed that when connecting to a backend server on loopback
> (server my_server 127.0.0.1:4043 ...) HAProxy always enabled kTLS,
> but when connecting to an external address it often failed to do so.
> 
> I did some digging and it turns out that after calling connect() on a 
> socket,
> HAProxy immediately calls setsockopt(..., TCP_ULP, "tls", ...)
> 
> Linux tls module requires the socket to be in TCP_ESTABLISHED state:
> https://elixir.bootlin.com/linux/v7.0.12/source/net/tls/tls_main.c#L1059-L1066
> 
> If a SYN+ACK packet from the server don't arrive in time when we call
> setsockopt(), it will fail with ENOTCONN error.
> 
> I've tested on HAProxy 3.4.0 with OpenSSL 3.5.6 and AWS-LC 5.0.0
> 
> strace
> ```
> 3947  socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 156
> 3947  fcntl(156, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
> 3947  setsockopt(156, SOL_TCP, TCP_NODELAY, [1], 4) = 0
> 3947  connect(156, {sa_family=AF_INET, sin_port=htons(4043), 
> sin_addr=inet_addr("10.1.0.3")}, 16) = -1 EINPROGRESS (Operation now in 
> progress)
> 3947  setsockopt(156, SOL_TCP, TCP_ULP, [7564404], 4) = -1 ENOTCONN 
> (Transport endpoint is not connected)
> 3947  recvmsg(155, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base=" 
> make teardown-iface     \342\200\224 prz"..., iov_len=1024}], 
> msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1024
> 3947  epoll_ctl(148, EPOLL_CTL_ADD, 156, 
> {events=EPOLLIN|EPOLLOUT|EPOLLRDHUP, data={u32=156, u64=156}}) = 0
> 3947  clock_gettime(CLOCK_THREAD_CPUTIME_ID, {tv_sec=0, 
> tv_nsec=4370772}) = 0
> 3947  epoll_wait(148, [{events=EPOLLOUT, data={u32=156, u64=156}}], 200, 
> 0) = 1
> ```
[...]
> 
> I've moved the setsockopt(..., TCP_ULP, "tls", ...) call just before
> configuring the kTLS keys and it resolved the issue for me.
> 
> I've also tested the change on another system with kTLS disbled and 
> HAProxy
> properly falls back to software tls.

Thanks a lot! Your analysis and patch sound entirely correct to me, so I
just pushed it, only slightly altered.

Regards,

Olivier


Reply via email to