Stalwart-mail+Discourse: EOF do POP3 atingido (novamente)

Continuando a discussão de Problema de SSL no Polling POP3:

Olá,

Estou testando o novo suporte a POP3 do Stalwart-mail com o Discourse…

Os registros DNS estão completos
Registros DNS
Tipo	Nome	Conteúdo
MX	hack2o.eu.	10 mx.z7l.eu.
CNAME	mail.hack2o.eu.	mx.z7l.eu.
TXT	202406e._domainkey.hack2o.eu.	v=DKIM1; k=ed25519; h=sha256; p=J7kVdkoSKjwJcdPOcqCvvR7YtJV3LtOKEQ09c00+/fY=
TXT	202406r._domainkey.hack2o.eu.	v=DKIM1; k=rsa; h=sha256; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuvXE8Nf0Q9C+/coc9RgACmoTwQ9OZMkJIuWxtT0fYr6UY3CYnjzOLp+VEKoqQA2OHfNM7Q3rQSw0ghjKcMW2OqzQKQAQTGrm3hvSjsJgQvUcgjHbZngpzfqBsCun6iONGuO33UJmzH4hpnm0ljLGiOw4wv6MA918wL71oZS7HWjYU9g31uasCVBpt0Ch1U6Vfs4/ejVSXbmvNb+BDQUU48E8SnpnZS6yLoMC7gByflVvoOlLvj8tV4HYdO74FXej4gUEUUacQUQPyWKDzHhhcuhG/nmoWOrbJyiTpoq4cflKTblg6wriBZ6XPXud2Og1U0SB1yPyEtV7q3b4ZLJ1AwIDAQAB
TXT	hack2o.eu.	v=spf1 mx ra=postmaster -all
SRV	_imaps._tcp.hack2o.eu.	0 1 143 mx.z7l.eu.
SRV	_imaps._tcp.hack2o.eu.	0 1 993 mx.z7l.eu.
SRV	_pop3s._tcp.hack2o.eu.	0 1 995 mx.z7l.eu.
SRV	_submissions._tcp.hack2o.eu.	0 1 465 mx.z7l.eu.
SRV	_submissions._tcp.hack2o.eu.	0 1 587 mx.z7l.eu.
CNAME	autoconfig.hack2o.eu.	mx.z7l.eu.
CNAME	autodiscover.hack2o.eu.	mx.z7l.eu.
CNAME	mta-sts.hack2o.eu.	mx.z7l.eu.
TXT	_mta-sts.hack2o.eu.	v=STSv1; id=16222476092926415687
TXT	_dmarc.hack2o.eu.	v=DMARC1; p=reject; rua=mailto:postmaster@hack2o.eu; ruf=mailto:postmaster@hack2o.eu
TXT	_smtp._tls.hack2o.eu.	v=TLSRPTv1; rua=mailto:postmaster@hack2o.eu
TLSA	_25._tcp.mail.hack2o.eu.	3 0 1 22eaf4d577f42a1ceeda1b8da12ab2c0eb20351b7e3f7035c2cac7dd700a3ab6
TLSA	_25._tcp.mail.hack2o.eu.	3 0 2 16c04cca276b0d880b843f35b8f8513b7b4157907cb19c5d5f36464ea5e04972e863f24a6cb18bcd39fe5cc0cff793d6a5225d8937654ab28b2c7096a12cd858
TLSA	_25._tcp.mail.hack2o.eu.	3 1 1 0a47742e724fe771934bbf9a5d9c721cf34b97135242042b9e0a2c030c634455
TLSA	_25._tcp.mail.hack2o.eu.	3 1 2 ab60f26c194e0467bade96dd1a0bffd5d465065b2740e577f28f889a019ec2b455af8b8a1b1bcd66b998bba91469c5c5430c0a9f52f27316b33f93997d48f3e7
TLSA	_25._tcp.mail.hack2o.eu.	2 0 1 76e9e288aafc0e37f4390cbf946aad997d5c1c901b3ce513d3d8fadbabe2ab85
TLSA	_25._tcp.mail.hack2o.eu.	2 0 2 afab698cbbbf892ebb555e09175056c1d4630fe7c350f44dcc6e71843d3b290df00d30ab4e356b630c69169d7633788338922fb637cf5b9f7be20a413eeaa518
TLSA	_25._tcp.mail.hack2o.eu.	2 1 1 d016e1fe311948aca64f2de44ce86c9a51ca041df6103bb52a88eb3f761f57d7
TLSA	_25._tcp.mail.hack2o.eu.	2 1 2 f8a2b4e23e82a4494e9998fcc4242bef1277656a118beede55ddfadcb82e20c5dc036dcb3b6c48d2ce04e362a9f477c82ad5a557b06b6f33b45ca6662b37c1c9

A conta POP3 funciona perfeitamente com o Thunderbird, e sua configuração é descoberta automaticamente de forma eficiente.

Mas o Discourse falha ao ativá-la, apesar da solução alternativa do TLS 1.3.

Mensagem de erro
Mensagem

EOFError (fim do arquivo alcançado)
app/services/email_settings_validator.rb:55:in `validate_pop3'
lib/validators/pop3_polling_enabled_setting_validator.rb:35:in `authentication_works?'
lib/validators/pop3_polling_enabled_setting_validator.rb:15:in `valid_value?'
lib/site_settings/type_supervisor.rb:284:in `validate_value'
lib/site_settings/type_supervisor.rb:165:in `to_db_value'
lib/site_setting_extension.rb:368:in `add_override!'
lib/site_setting_extension.rb:609:in `block in setup_methods'
lib/site_setting_extension.rb:435:in `public_send'
lib/site_setting_extension.rb:435:in `set'
lib/site_setting_extension.rb:448:in `set_and_log'
app/controllers/admin/site_settings_controller.rb:56:in `update'
app/controllers/application_controller.rb:422:in `block in with_resolved_locale'
app/controllers/application_controller.rb:422:in `with_resolved_locale'
lib/middleware/omniauth_bypass_middleware.rb:64:in `call'
lib/content_security_policy/middleware.rb:12:in `call'
lib/middleware/anonymous_cache.rb:393:in `call'
lib/middleware/csp_script_nonce_injector.rb:12:in `call'
config/initializers/008-rack-cors.rb:14:in `call'
config/initializers/100-quiet_logger.rb:20:in `call'
config/initializers/100-silence_logger.rb:29:in `call'
lib/middleware/enforce_hostname.rb:24:in `call'
lib/middleware/request_tracker.rb:289:in `call'

Rastreamento

/usr/local/lib/ruby/3.3.0/net/protocol.rb:237:in `rbuf_fill'
/usr/local/lib/ruby/3.3.0/net/protocol.rb:199:in `readuntil'
/usr/local/lib/ruby/3.3.0/net/protocol.rb:209:in `readline'
net-pop (0.1.2) lib/net/pop.rb:1000:in `recv_response'
net-pop (0.1.2) lib/net/pop.rb:996:in `get_response'
net-pop (0.1.2) lib/net/pop.rb:984:in `block in quit'
net-pop (0.1.2) lib/net/pop.rb:1016:in `critical'
net-pop (0.1.2) lib/net/pop.rb:984:in `quit'
net-pop (0.1.2) lib/net/pop.rb:603:in `do_finish'
net-pop (0.1.2) lib/net/pop.rb:533:in `start'
net-pop (0.1.2) lib/net/pop.rb:316:in `auth_only'
app/services/email_settings_validator.rb:55:in `validate_pop3'
lib/validators/pop3_polling_enabled_setting_validator.rb:35:in `authentication_works?'
lib/validators/pop3_polling_enabled_setting_validator.rb:15:in `valid_value?'
lib/site_settings/type_supervisor.rb:284:in `validate_value'
lib/site_settings/type_supervisor.rb:165:in `to_db_value'
lib/site_setting_extension.rb:368:in `add_override!'
lib/site_setting_extension.rb:609:in `block in setup_methods'
lib/site_setting_extension.rb:435:in `public_send'
lib/site_setting_extension.rb:435:in `set'
lib/site_setting_extension.rb:448:in `set_and_log'
app/controllers/admin/site_settings_controller.rb:56:in `update'
actionpack (7.0.8.4) lib/action_controller/metal/basic_implicit_render.rb:6:in `send_action'
actionpack (7.0.8.4) lib/abstract_controller/base.rb:215:in `process_action'
actionpack (7.0.8.4) lib/action_controller/metal/rendering.rb:165:in `process_action'
actionpack (7.0.8.4) lib/abstract_controller/callbacks.rb:234:in `block in process_action'
activesupport (7.0.8.4) lib/active_support/callbacks.rb:118:in `block in run_callbacks'
app/controllers/application_controller.rb:422:in `block in with_resolved_locale'
i18n (1.14.5) lib/i18n.rb:351:in `with_locale'
app/controllers/application_controller.rb:422:in `with_resolved_locale'
activesupport (7.0.8.4) lib/active_support/callbacks.rb:127:in `block in run_callbacks'
activesupport (7.0.8.4) lib/active_support/callbacks.rb:138:in `run_callbacks'
actionpack (7.0.8.4) lib/abstract_controller/callbacks.rb:233:in `process_action'
actionpack (7.0.8.4) lib/action_controller/metal/rescue.rb:23:in `process_action'
actionpack (7.0.8.4) lib/action_controller/metal/instrumentation.rb:67:in `block in process_action'
activesupport (7.0.8.4) lib/active_support/notifications.rb:206:in `block in instrument'
activesupport (7.0.8.4) lib/active_support/notifications/instrumenter.rb:24:in `instrument'
activesupport (7.0.8.4) lib/active_support/notifications.rb:206:in `instrument'
actionpack (7.0.8.4) lib/action_controller/metal/instrumentation.rb:66:in `process_action'
actionpack (7.0.8.4) lib/action_controller/metal/params_wrapper.rb:259:in `process_action'
activerecord (7.0.8.4) lib/active_record/railties/controller_runtime.rb:27:in `process_action'
actionpack (7.0.8.4) lib/abstract_controller/base.rb:151:in `process'
actionview (7.0.8.4) lib/action_view/rendering.rb:39:in `process'
rack-mini-profiler (3.3.1) lib/mini_profiler/profiling_methods.rb:115:in `block in profile_method'
actionpack (7.0.8.4) lib/action_controller/metal.rb:188:in `dispatch'
actionpack (7.0.8.4) lib/action_controller/metal.rb:251:in `dispatch'
actionpack (7.0.8.4) lib/action_dispatch/routing/route_set.rb:49:in `dispatch'
actionpack (7.0.8.4) lib/action_dispatch/routing/route_set.rb:32:in `serve'
actionpack (7.0.8.4) lib/action_dispatch/routing/mapper.rb:18:in `block in <class:Constraints>'
actionpack (7.0.8.4) lib/action_dispatch/routing/mapper.rb:48:in `serve'
actionpack (7.0.8.4) lib/action_dispatch/journey/router.rb:50:in `block in serve'
actionpack (7.0.8.4) lib/action_dispatch/journey/router.rb:32:in `each'
actionpack (7.0.8.4) lib/action_dispatch/journey/router.rb:32:in `serve'
actionpack (7.0.8.4) lib/action_dispatch/routing/route_set.rb:852:in `call'
lib/middleware/omniauth_bypass_middleware.rb:64:in `call'
rack (2.2.9) lib/rack/tempfile_reaper.rb:15:in `call'
rack (2.2.9) lib/rack/conditional_get.rb:40:in `call'
rack (2.2.9) lib/rack/head.rb:12:in `call'
actionpack (7.0.8.4) lib/action_dispatch/http/permissions_policy.rb:38:in `call'
lib/content_security_policy/middleware.rb:12:in `call'
lib/middleware/anonymous_cache.rb:393:in `call'
lib/middleware/csp_script_nonce_injector.rb:12:in `call'
config/initializers/008-rack-cors.rb:14:in `call'
rack (2.2.9) lib/rack/session/abstract/id.rb:266:in `context'
rack (2.2.9) lib/rack/session/abstract/id.rb:260:in `call'
actionpack (7.0.8.4) lib/action_dispatch/middleware/cookies.rb:704:in `call'
actionpack (7.0.8.4) lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'
activesupport (7.0.8.4) lib/active_support/callbacks.rb:99:in `run_callbacks'
actionpack (7.0.8.4) lib/action_dispatch/middleware/callbacks.rb:26:in `call'
actionpack (7.0.8.4) lib/action_dispatch/middleware/debug_exceptions.rb:28:in `call'
actionpack (7.0.8.4) lib/action_dispatch/middleware/show_exceptions.rb:29:in `call'
logster (2.19.1) lib/logster/middleware/reporter.rb:40:in `call'
railties (7.0.8.4) lib/rails/rack/logger.rb:40:in `call_app'
railties (7.0.8.4) lib/rails/rack/logger.rb:27:in `call'
config/initializers/100-quiet_logger.rb:20:in `call'
config/initializers/100-silence_logger.rb:29:in `call'
actionpack (7.0.8.4) lib/action_dispatch/middleware/remote_ip.rb:93:in `call'
actionpack (7.0.8.4) lib/action_dispatch/middleware/request_id.rb:26:in `call'
lib/middleware/enforce_hostname.rb:24:in `call'
rack (2.2.9) lib/rack/method_override.rb:24:in `call'
actionpack (7.0.8.4) lib/action_dispatch/middleware/executor.rb:14:in `call'
rack (2.2.9) lib/rack/sendfile.rb:110:in `call'
actionpack (7.0.8.4) lib/action_dispatch/middleware/host_authorization.rb:131:in `call'
rack-mini-profiler (3.3.1) lib/mini_profiler.rb:334:in `call'
message_bus (4.3.8) lib/message_bus/rack/middleware.rb:60:in `call'
lib/middleware/request_tracker.rb:289:in `call'
railties (7.0.8.4) lib/rails/engine.rb:530:in `call'
railties (7.0.8.4) lib/rails/railtie.rb:226:in `public_send'
railties (7.0.8.4) lib/rails/railtie.rb:226:in `method_missing'
rack (2.2.9) lib/rack/urlmap.rb:74:in `block in call'
rack (2.2.9) lib/rack/urlmap.rb:58:in `each'
rack (2.2.9) lib/rack/urlmap.rb:58:in `call'
unicorn (6.1.0) lib/unicorn/http_server.rb:634:in `process_client'
unicorn (6.1.0) lib/unicorn/http_server.rb:739:in `worker_loop'
unicorn (6.1.0) lib/unicorn/http_server.rb:547:in `spawn_missing_workers'
unicorn (6.1.0) lib/unicorn/http_server.rb:143:in `start'
unicorn (6.1.0) bin/unicorn:128:in `<top (required)>'
vendor/bundle/ruby/3.3.0/bin/unicorn:25:in `load'
vendor/bundle/ruby/3.3.0/bin/unicorn:25:in `<main>'

Ambiente

HOSTS HTTP: forum.hack2o.eu

O erro pode ser reproduzido com o Net::POP3 puro em Ruby, mas a autenticação não falha. É apenas um erro sem sentido do OpenSSL. A conexão com openssl s_client diretamente funciona tanto para TLS 1.2 quanto para TLS 1.3. Não tenho certeza do que fazer aqui, já que tudo parece estar funcionando fora do aviso do OpenSSL no momento da desconexão.


Aqui está um teste mínimo em Ruby:

Teste Net::POP3
require 'net/pop'

puts "Testando conexão POP3 para #{ENV['POP3_USER']} em #{ENV['POP3_HOST']}"

Net::POP3.enable_ssl

pop = Net::POP3.new(ENV['POP3_HOST'], 995)

print " usando SSL: ", pop.use_ssl?? "sim":"não", "\n"

begin
  pop.auth_only(ENV['POP3_USER'], ENV['POP3_PASS'])
  puts "Autenticação bem-sucedida!"
rescue Net::POPAuthenticationError => err
  puts "Autenticação falhou."
#  p ENV['POP3_USER']
#  p ENV['POP3_PASS']
#  p pop
  exit
end

Note que também testei definir ssl_params para enable_ssl com:

  • min_version: OpenSSL::SSL::TLS1_3_VERSION
  • max_version: OpenSSL::SSL::TLS1_2_VERSION

com os mesmos resultados.

Aqui está uma sessão do OpenSSL (idêntica com TLS 1.2 e 1.3):

openssl s_client -quiet -tls1_3 mail.example:995
depth=2 C = US, O = Internet Security Research Group, CN = ISRG Root X1
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = E5
verify return:1
depth=0 CN = mail.example
verify return:1
+OK Stalwart POP3 at your service.
USER user@mail.example
+OK user@mail.example is a valid mailbox
PASS redacted
+OK Authentication successful
QUIT
40771049E17F0000:error:0A000126:SSL routines:ssl3_read_n:unexpected eof while reading:../ssl/record/rec_layer_s3.c:303:
openssl s_client -quiet -tls1_2 mail.example:995
depth=2 C = US, O = Internet Security Research Group, CN = ISRG Root X1
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = E5
verify return:1
depth=0 CN = mail.example
verify return:1
+OK Stalwart POP3 at your service.
USER user@mail.example
+OK user@mail.example is a valid mailbox
PASS redacted
+OK Authentication successful
QUIT
40771049E17F0000:error:0A000126:SSL routines:ssl3_read_n:unexpected eof while reading:../ssl/record/rec_layer_s3.c:303:

Eu me pergunto o que faz com que outras implementações não vazem o erro do OpenSSL.

Acho que isso é um bug do Stalwart-mail e vou reportá-lo neste tópico para revisão.

Não consegui encontrar onde você relatou isso para o Stalwart, então relatei aqui: [bug]: discourse pop3 polling doesn't work · Issue #567 · stalwartlabs/stalwart · GitHub

Obrigado @programmerjake, sua correção POP3 QUIT must write a response by programmerjake · Pull Request #568 · stalwartlabs/stalwart · GitHub resolveu o problema de polling.

(Eu relatei o problema no canal do Matrix, pois não sabia como depurá-lo e caracterizar o problema real.)