Hi Ian,
A few years ago, the Red Hat/Fedora stunnel packaging was changed to use the system-wide crypto policy as the default cipher configuration:
https://gitlab.com/redhat/centos-stream/rpms/stunnel/-/blob/c10s/stunnel-5.69-system-ciphers.patch
This third-party patch changes stunnel's default cipher list to PROFILE=SYSTEM. Since the system crypto policy enables finite-field DHE cipher suites, stunnel's existing code detects that DHE is available in your server-mode frontend sections and generates temporary 2048-bit DH parameters.
The parameters are generated when the per-day worker starts and regenerated every 24 hours. The 100 ms poll() calls you are seeing come from a delay in stunnel's OpenSSL DH-generation progress callback. The delay is there to throttle CPU usage during DH parameter generation.
Your explicit DHE-RSA-AES256-SHA settings in the backend sections are unrelated to this CPU usage, since those sections run in client mode and therefore do not generate DH parameters locally.
Finite-field DHE cipher suites are generally not recommended for new TLS configurations in 2026. ECDHE, or TLS 1.3 key exchange, should normally be preferred. Your backend configuration appears to require DHE for compatibility with the legacy switches, but unless you also need DHE on the frontend connections, I would disable it there.
Best regards,
Mike
I noticed that stunnel is constantly consuming 30% of one of my CPU
cores. Looking at it with strace, I see that it is frequently (every
100 milliseconds?) waking up from a poll() system call, calling getpid()
a couple of times and going back to sleep.
[pid 3498] poll([{fd=6, events=POLLIN|POLLRDHUP}], 1, 100) = 0 (Timeout)
[pid 3498] getpid() = 3494
[pid 3498] getpid() = 3494
[pid 3498] poll([{fd=6, events=POLLIN|POLLRDHUP}], 1, 100) = 0 (Timeout)
[pid 3498] getpid() = 3494
[pid 3498] getpid() = 3494
[pid 3498] poll([{fd=6, events=POLLIN|POLLRDHUP}], 1, 100) = 0 (Timeout)
[pid 3498] getpid() = 3494
[pid 3498] getpid() = 3494
[pid 3498] poll([{fd=6, events=POLLIN|POLLRDHUP}], 1, 100) = 0 (Timeout)
[pid 3498] getpid() = 3494
[pid 3498] getpid() = 3494
AFAICT, this is a pipe that stunnel is using to talk to itself (maybe to
communicate between threads)?
# ls -l /proc/3498/fd
total 0
lrwx------. 1 stunnel stunnel 64 Aug 23 10:12 0 -> /dev/null
lrwx------. 1 stunnel stunnel 64 Aug 23 10:12 1 -> /dev/null
lrwx------. 1 stunnel stunnel 64 Aug 23 10:12 10 -> 'socket:[37674]'
lrwx------. 1 stunnel stunnel 64 Aug 23 10:12 11 -> 'socket:[37675]'
lrwx------. 1 stunnel stunnel 64 Aug 23 10:12 12 -> 'socket:[37676]'
lrwx------. 1 stunnel stunnel 64 Aug 23 10:12 2 -> /dev/null
lr-x------. 1 stunnel stunnel 64 Aug 23 10:12 4 -> 'pipe:[38360]'
l-wx------. 1 stunnel stunnel 64 Aug 23 10:12 5 -> 'pipe:[38360]'
lr-x------. 1 stunnel stunnel 64 Aug 23 10:12 6 -> 'pipe:[38361]'
l-wx------. 1 stunnel stunnel 64 Aug 23 10:12 7 -> 'pipe:[38361]'
lrwx------. 1 stunnel stunnel 64 Aug 23 10:12 8 -> 'socket:[37672]'
lrwx------. 1 stunnel stunnel 64 Aug 23 10:12 9 -> 'socket:[37673]'
Is this expected behavior? Anything that can be done about it?
Environment:
============
stunnel 5.80 on x86_64-redhat-linux-gnu platform
Compiled/running with OpenSSL 3.5.7 9 Jun 2026
Threading:PTHREAD Sockets:POLL,IPv6,SYSTEMD TLS:ENGINE,FIPS,OCSP,PSK,SNI,DTLS
Global options:
fips = no
RNDbytes = 1024
RNDfile = /dev/urandom
RNDoverwrite = yes
Service-level options:
ciphers = PROFILE=SYSTEM (with "fips = yes")
ciphers = PROFILE=SYSTEM (with "fips = no")
ciphersuites = TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256 (with TLSv1.3)
curves = P-256:P-521:P-384 (with "fips = yes")
curves = X25519MLKEM768:X25519:P-256:X448:P-521:P-384 (with "fips = no")
debug = daemon.notice
logId = sequential
options = NO_SSLv2
options = NO_SSLv3
securityLevel = 2
sessionCacheSize = 1000
sessionCacheTimeout = 300 seconds
stack = 131072 bytes
TIMEOUTbusy = 300 seconds
TIMEOUTclose = 60 seconds
TIMEOUTconnect = 10 seconds
TIMEOUTidle = 43200 seconds
TIMEOUTocsp = 5 seconds
verify = none
stunnel.conf:
=============
debug = warning
[switch2-frontend]
accept = 0.0.0.0:8402
CAfile = /etc/ipa/ca.crt
cert = /etc/pki/tls/certs/stunnel/switch2.crt
key = /tmp/keys/switch2.key
connect = 127.255.255.254:8082
[switch2-backend]
client = yes
accept = 127.255.255.254:8082
connect = 172.31.4.2:443
verifyChain = yes
checkHost = switch2.penurio.us
CAfile = /etc/pki/tls/certs/stunnel/switch-ca.crt
sslVersion = TLSv1
ciphers = DHE-RSA-AES256-SHA
options = ALLOW_UNSAFE_LEGACY_RENEGOTIATION
securityLevel = 0
OCSPrequire = no
OCSPaia = no
[switch4-frontend]
accept = 0.0.0.0:8404
CAfile = /etc/ipa/ca.crt
cert = /etc/pki/tls/certs/stunnel/switch4.crt
key = /tmp/keys/switch4.key
connect = 127.255.255.254:8084
[switch4-backend]
client = yes
accept = 127.255.255.254:8084
connect = 172.31.4.7:443
verifyChain = yes
checkHost = switch4.penurio.us
CAfile = /etc/pki/tls/certs/stunnel/switch-ca.crt
sslVersion = TLSv1
ciphers = DHE-RSA-AES256-SHA
options = ALLOW_UNSAFE_LEGACY_RENEGOTIATION
securityLevel = 0
OCSPrequire = no
OCSPaia = no