ejabberd icon indicating copy to clipboard operation
ejabberd copied to clipboard

Matrix Gateway: Messages from XMPP to Matrix are not delivered (only Matrix → XMPP works)

Open paulo-roger opened this issue 4 months ago • 12 comments

Environment

  • ejabberd version: latest docker image (2025-08-22 build)
  • Transport: mod_matrix_gw
  • OS: Linux (Ubuntu)
  • Installed from: source

Configuration (only if needed): grep -Ev '^$|^\s*#' ejabberd.yml

hosts:
  - mydomain.tld

host_config:
  mydomain.tld:
    auth_method: [ldap]
    ldap_servers:
      - lldap
    ldap_port: 3890
    ldap_uids:
      - uid
    ldap_rootdn: "uid=binduser,ou=people,dc=mydomain,dc=tld"
    ldap_password: "password123"
    ldap_base: "ou=people,dc=mydomain,dc=tld"
loglevel: debug
define_macro:
  TLS_CIPHERS: ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
  TLS_OPTIONS:
    - no_sslv3
    - no_tlsv1
    - no_tlsv1_1
    - cipher_server_preference
    - no_compression
c2s_ciphers: TLS_CIPHERS
s2s_ciphers: TLS_CIPHERS
c2s_protocol_options: TLS_OPTIONS
s2s_protocol_options: TLS_OPTIONS
s2s_use_starttls: required
disable_sasl_mechanisms:
  - digest-md5
  - X-OAUTH2
certfiles:
  - /etc/ssl/certificates/*ydomain.tld/*.crt
  - /etc/ssl/certificates/*ydomain.tld/*.key
listen:
  -
    port: 5222
    ip: "::"
    module: ejabberd_c2s
    max_stanza_size: 262144
    shaper: c2s_shaper
    access: c2s
    starttls_required: true
    protocol_options: TLS_OPTIONS
  -
    port: 5223
    ip: "::"
    module: ejabberd_c2s
    max_stanza_size: 262144
    shaper: c2s_shaper
    access: c2s
    tls: true
    protocol_options: TLS_OPTIONS
  -
    port: 5269
    ip: "::"
    module: ejabberd_s2s_in
    max_stanza_size: 524288
    shaper: s2s_shaper
  -
    port: 5270
    ip: "::"
    module: ejabberd_s2s_in
    max_stanza_size: 524288
    shaper: s2s_shaper
    tls: true
    protocol_options: TLS_OPTIONS
  -
    port: 5443
    ip: "::"
    module: ejabberd_http
    tls: true
    protocol_options: TLS_OPTIONS
    request_handlers:
      /conversejs: mod_conversejs
      /admin: ejabberd_web_admin
      /api: mod_http_api
      /http-bind: mod_bosh
      /captcha: ejabberd_captcha
      /upload: mod_http_upload
      /ws: ejabberd_http_ws
      /.well-known/host-meta: mod_host_meta
      /.well-known/host-meta.json: mod_host_meta
  -
    port: 5280
    ip: "::"
    module: ejabberd_http
    request_handlers: 
      /.well-known/acme-challenge: ejabberd_acme
  -
    port: 3478
    ip: "::"
    transport: udp
    module: ejabberd_stun
    use_turn: true
    turn_min_port: 49152
    turn_max_port: 65535
    turn_ipv4_address: "my_ipv4"
    turn_ipv6_address: "my_ipv6"
  - 
    port: 5349
    transport: tcp
    ip: "::"
    module: ejabberd_stun
    use_turn: true
    tls: true
  -
    port: 5347
    ip: "::"
    module: ejabberd_service
    access: all
    hosts:
      irc.mydomain.tld:
        password: password123
  -
    port: 5348
    ip: "::"
    module: ejabberd_service
    access: local
    hosts:
      irc-bridge.mydomain.tld:
        password: password123
  -
    port: 8448 # Matrix federation
    module: ejabberd_http
    tls: true
    request_handlers:
      "/_matrix": mod_matrix_gw
acme:
  auto: false
  ca_url: https://acme-staging-v02.api.letsencrypt.org/directory
acl:
  local:
    user_regexp: ""
  loopback:
    ip:
      - 127.0.0.0/8
      - ::1/128
  admin:
    user: admin
s2s_access: s2s
access_rules:
  local:
    allow: local
  c2s:
    deny: blocked
    allow: all
  s2s:
    - allow # to allow Matrix federation
  announce:
    allow: admin
  configure:
    allow: admin
  muc_create:
    allow: local
  pubsub_createnode:
    allow: local
  trusted_network:
    allow: loopback
api_permissions:
  "console commands":
    from: ejabberd_ctl
    who: all
    what: "*"
  "webadmin commands":
    from: ejabberd_web_admin
    who: admin
    what: "*"
  "admin access":
    who:
      access:
        allow:
          - acl: loopback
          - acl: admin
      oauth:
        scope: "ejabberd:admin"
        access:
          allow:
            - acl: loopback
            - acl: admin
    what:
      - "*"
      - "!stop"
      - "!start"
  "public commands":
    who:
      ip: 127.0.0.1/8
    what:
      - status
      - connected_users_number
shaper:
  normal:
    rate: 3000
    burst_size: 20000
  fast: 100000
shaper_rules:
  max_user_sessions: 10
  max_user_offline_messages:
    5000: admin
    100: all
  c2s_shaper:
    none: admin
    normal: all
  s2s_shaper: fast
modules:
  mod_adhoc: {}
  mod_admin_extra: {}
  mod_announce:
    access: announce
  mod_avatar: {}
  mod_blocking: {}
  mod_bosh: {}
  mod_caps: {}
  mod_carboncopy: {}
  mod_client_state: {}
  mod_configure: {}
  mod_conversejs:
    conversejs_options:
      locked_domain: "@HOST@"
      message_archiving: always
  mod_disco:
    server_info:
      - modules: all
        name: abuse-addresses
        urls:
          - "mailto:[email protected]"
      - modules: all
        name: support-addresses
        urls:
          - "mailto:[email protected]"
      - modules: all
        name: admin-addresses
        urls:
          - "mailto:[email protected]"
  mod_fail2ban: {}
  mod_host_meta:
    bosh_service_url: "https://xmpp.@HOST@/http-bind"
    websocket_url: "wss://xmpp.@HOST@/ws"
  mod_http_api: {}
  mod_http_upload:
    put_url: https://xmpp.@HOST@/upload
    docroot: /var/www/upload
    custom_headers:
      "Access-Control-Allow-Origin": "*"
      "Access-Control-Allow-Methods": "GET,HEAD,PUT,OPTIONS"
      "Access-Control-Allow-Headers": "Content-Type"
  mod_last: {}
  mod_mam:
    db_type: sql
    assume_mam_usage: true
    default: always
  mod_matrix_gw:
    key_name: "key1"
    key: "key_matrix"
    matrix_id_as_jid: true
  mod_muc:
    host: grupo.@HOST@
    access:
      - allow
    access_admin:
      - allow: admin
    access_create: muc_create
    access_persistent: muc_create
    access_mam:
      - allow
    default_room_options:
      mam: true
      allow_subscription: true
  mod_muc_admin: {}
  mod_muc_occupantid: {}
  mod_offline:
    access_max_user_messages: max_user_offline_messages
  mod_ping: {}
  mod_privacy: {}
  mod_private: {}
  mod_proxy65:
    access: local
    max_connections: 5
  mod_pubsub:
    access_createnode: pubsub_createnode
    plugins:
      - flat
      - pep
    force_node_config:
      storage:bookmarks:
        access_model: whitelist
  mod_push: {}
  mod_push_keepalive: {}
  mod_roster:
    versioning: true
  mod_s2s_dialback: {}
  mod_shared_roster: {}
  mod_stream_mgmt:
    resend_on_timeout: if_offline
  mod_stun_disco: {}
  mod_vcard: {}
  mod_vcard_xupdate: {}
  mod_version:
    show_os: false
sql_type: pgsql
sql_server: "postgres"
sql_database: "ejabberd"
sql_username: "ejabberd"
sql_password: "password123"
default_db: sql

Errors from error.log/crash.log

No errors (excerpt) docker compose logs ejabberd

2025-08-22 21:06:44.855 [notice] (tls|<0.731.0>) Received XML on stream = "<message ...>"
2025-08-22 21:06:44.925 [debug] hook module = mod_matrix_gw
2025-08-22 21:06:44.927 [debug] Route: [email protected]
2025-08-22 21:06:44.933 [debug] (s2s|<0.741.0>) Send XML on stream = "<message to='[email protected]' ...>"

There are no errors or warnings in the ejabberd logs, and the stanza appears to be forwarded correctly, but the Matrix side never receives it.

Bug description

I am testing the mod_matrix_gw in the latest ejabberd release (docker image). I can successfully send messages from Matrix to my XMPP user, but the reverse direction does not work: messages from XMPP to Matrix are never received on the Matrix side.

Expected Behavior

  • When my XMPP user sends a message to a Matrix contact (via the ejabberd Matrix Gateway), the Matrix user should receive the message.

Actual Behavior

  • The XMPP user’s message is processed by ejabberd normally:

    • The stanza is received and parsed.
    • It is archived in MAM.
    • It is duplicated to the other connected XMPP resource (carbon copy).
    • ejabberd logs show the stanza routed through mod_matrix_gw and forwarded to matrix.org via s2s.
  • But the Matrix user never receives the message.

Steps to Reproduce

  1. Configure ejabberd with mod_matrix_gw.
  2. Connect an XMPP client to ejabberd.
  3. Add a Matrix user as a contact and send messages both ways.
  4. Observe that only Matrix → XMPP works, not XMPP → Matrix.

Notes

  • TLS and s2s federation are working (messages to XMPP arrive fine).
  • The problem is specifically with delivery from XMPP → Matrix.

paulo-roger avatar Aug 22 '25 22:08 paulo-roger

I have the opposite behaviour in some chats, where mesages XMPP -> Matrix work fine, but not Matrix -> XMPP.

Same cause perhaps?

erebion avatar Aug 24 '25 15:08 erebion

I have the opposite behaviour in some chats, where mesages XMPP -> Matrix work fine, but not Matrix -> XMPP.

Same cause perhaps?

Maybe. This is my reverse proxy configuration in case that matters:

Caddyfile

mydomain.tld {
  handle /.well-known/matrix/server {
      header Content-Type application/json
      respond `{ "m.server": "matrix.mydomain.tld:8448" }`
  }
  handle /_matrix* {
    reverse_proxy localhost:8448 {
      transport http {
        tls_insecure_skip_verify
      }
      header_up Host {host}
    }
  }
}

matrix.mydomain.tld {
  handle /_matrix* {
    reverse_proxy localhost:8448 {
      transport http {
        tls_insecure_skip_verify
      }
      header_up Host {host}
    }
  }
}

paulo-roger avatar Aug 24 '25 16:08 paulo-roger

I have the opposite behaviour in some chats, where mesages XMPP -> Matrix work fine, but not Matrix -> XMPP.

Same cause perhaps?

Would you mind sharing what you are doing differently?

paulo-roger avatar Sep 02 '25 17:09 paulo-roger

When using matrix_id_as_jid: true option and sending something to [email protected], ejabberd first tries to connect to the server using XMPP, and when it fails tries to use Matrix. But apparently matrix.org has an XMPP server or gateway:

_xmpp-server._tcp.matrix.org has SRV record 0 5 5269 lethe.matrix.org.

and it gets your messages.

To avoid it you can try to reject TCP packets going to lethe.matrix.org:5269.

And please check if the problem appears with other Matrix servers.

alexeyshch avatar Sep 29 '25 14:09 alexeyshch

Is there a recommended way to avoid these unintended XMPP connections? Should it be blocked via firewall (iptables/nftables), or can this be configured inside ejabberd (ACL / s2s_access)?

On September 29, 2025 11:01:01 GMT-03:00, Alexey Shchepin @.***> wrote:

alexeyshch left a comment (processone/ejabberd#4442)

When using matrix_id_as_jid: true option and sending something to @.***, ejabberd first tries to connect to the server using XMPP, and when it fails tries to use Matrix. But apparently matrix.org` has an XMPP server or gateway:

_xmpp-server._tcp.matrix.org has SRV record 0 5 5269 lethe.matrix.org.

and it gets your messages.

To avoid it you can try to reject TCP packets going to lethe.matrix.org:5269.

And please check if the problem appears with other Matrix servers.

-- Reply to this email directly or view it on GitHub: https://github.com/processone/ejabberd/issues/4442#issuecomment-3347141539 You are receiving this because you authored the thread.

Message ID: @.***>

paulo-roger avatar Sep 30 '25 03:09 paulo-roger

Anyway I've set matrix_id_as_jid: false now and using user%<[email protected]>.tld still got the same behavior, I can only receive from matrix.org, never send.

paulo-roger avatar Oct 02 '25 03:10 paulo-roger

That would seem like expected behavior as the s2s requests would still end up on the same IP, no?

But did you check with Matrix servers other than Matrix.org? Does it work there?

poVoq avatar Oct 02 '25 17:10 poVoq

I will try, do you know another free matrix server? I have account only in matrix.org

Did it in the server envs.net, still can't join:

Image

The Matrix Server seems to be able to send Image

paulo-roger avatar Oct 02 '25 17:10 paulo-roger

Sorry, not very familiar with Matrix servers, maybe https://tchncs.de/en/ ?

But not being able to join is a totally different issue compared to one way message passing only, no?

poVoq avatar Oct 02 '25 17:10 poVoq

I will try this server too.

From a user perspective looks the same, the matrix side seems to be able to send, but from XMPP I can't even join the room. I would appreciate instructions for giving better information about the issue.

paulo-roger avatar Oct 02 '25 17:10 paulo-roger

@poVoq Thanks! That server works!

Chatting with a tchncs.de account works as expected, super!

So the problem would be in the Matrix side in matrix.org and envs.net?

paulo-roger avatar Oct 02 '25 17:10 paulo-roger

Interestingly https://connect.xmpp.net/ shows an open starttls for s2s on matrix.org but not on lethe.matrix.org

poVoq avatar Oct 02 '25 18:10 poVoq