Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

However, if I don't call the built-in TLS dissector, the inner payload is decrypted, which seems weird to me.

This is a sign that the dissector is using the new keys from the second handshake and replacing the earlier keys, and trying them on the outer TLS layer, which doesn't work. The problem is that the TLS session is stored in a conversation created using the addresses, ports, and port types, none of which change from the interposing dissector. You can verify this by having the TLS dissector write to a log file

You can work around this by artificially changing the port type and then changing it back, which will cause it to create a different session for the tunneled protocol:

    local save_port_type = pktinfo.port_type
    pktinfo.port_type = _EPAN.PT_NONE -- any value other than _EPAN.PT_TCP

    Dissector.get("tls"):call(tvb, pktinfo, tunnel_tree)

    pktinfo.port_type = save_port_type

You will then need to deal with a second issue, reassembling some of the inner TLS records that are split across multiple packets. The pinfo (or pktinfo in Lua) struct has a member can_desegment that has to be at least 1 for desegmentation to be allowed in a dissector. It is decremented by 1 each time a dissector is called. Dissectors which know that defragmentation is possible should set it to 2, so that it has the value 1 in the next dissector:

   local save_port_type = pktinfo.port_type
    pktinfo.port_type = _EPAN.PT_NONE
    local save_can_desegment = pktinfo.can_desegment
    pktinfo.can_desegment = 2 -- should really be pktinfo.saved_can_desegment

    Dissector.get("tls"):call(tvb, pktinfo, tunnel_tree)

    pktinfo.port_type = save_port_type
    pktinfo.can_desegment = save_can_desegment

For tunneling purposes, there's another value in pinfo called saved_can_desegment, which tunneling dissectors like Socks use. That has the value in the previous dissector, and is used for tunneling dissectors that shouldn't decrement the value, but also want the value in the previous layer (in case, for example, some error means that TCP didn't think that desegmentation was possible.) That's what should be used, except it's not exposed to Lua currently. I'll fix that.

Do that, and add DissectorTable.get("tls.alpn"):add("h2", trojan) to your enableDissector() registration (to override the value for the ALPN), and it will work.