XMPP virtual hosting

I would like to proxy XMPP with haproxy. But not for loadbalancing which would be easy with mode tcp and different backends. Decission for backend should be based on ‘to’ field in XMPP

<?xml version='1.0'?>
  <stream:stream
      from='ralf@im.example. com'
      to='im.example.com'
      version='1.0'
      xml:lang='en'
      xmlns='jabber:client'
      xmlns:stream='http://etherx.jabber.org/streams'>

This should go to backend with internal IP 10.0.1.11
and to=‘im.example-2. com’ should go to IP 10.0.1.12

I understand:

It is not http, so i have to use mode tcp and cannot do: use_backend server1 if { hdr(host) -i im.example-1. com }

It is not SSL with SNI, so i cannot do: use_backend server1 if { ssl_fc_sni im.example-1. com }
Wondering if that is even possible with haproxy? (perhaps ACL?!)

Update - Now i have tried with acl

With tcpflow i was able to see the packet on port 5222:

<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' to='s-4.example.com'>

in my haproxy.cfg i have tested my backend server with

acl acl-s-4 always_true
use_backend s-4 if acl-s-4
default_backend s-1

and it is taking the backend s-4 which i want to use

Now i tried to analyze the payload on tcp-layer 6 with

# acl acl-s-4 req.payload(0,140) -m sub example
# acl acl-s-4 payload(0,140) -i example # config error
# acl acl-s-4 res.payload(0,140),hex -m sub 732d342e6578616d706c652e636f6d
# acl acl-s-4 req.payload(0,0),hex -m sub 786d6c #xml
# acl acl-s-4 req.payload(0,500) -m reg -i s-4.example.com

None of this works. Someone any idea?

SOLUTION
during test i tried disabling

tcp-request content accept if WAIT_END

but this is necessary.

 acl acl-s-4 req.payload(0,140) -m sub example

is actually matching.

From doku:
wait_end
Waits for the end of the analysis period to return true. This may be used in
conjunction with content analysis to avoid returning a wrong verdict early.
It may also be used to delay some actions, such as a delayed reject for some
special addresses. Since it either stops the rules evaluation or immediately
returns true, it is recommended to use this acl as the last one in a rule.

No, you can’t match this. payload matching is for static offsets, but the “To” field can be anywhere in the XML.

There is a remote-possibility this can be achieved with LUA, but that probably requires some serious research.

First thanks for your answer.
Unfortunately i don’t understand what you mean with “static offset”. Why there is the possibility to search for substrings or even regex for a static offset?
To make shure - you mean payload(0,0) is not the complete <?xml … >
Could you please explain this to me in a little bit more detail?

With LUA i could do something like

function parseXMPP(txn, salt)
    local payload = txn.req:dup()
    local value = string.match(string.match(payload, "to=%s>"), "%s")
    core.Info("value: " .. value)
    return value
end

and stick this session to a server, right?

I also have control over the xmpp client (and even the (sub)domains). So i think i could stick the ‘to’ field on character 122 if this would be helpful.