Wireshark-dev: [Wireshark-dev] Changing dissector based on TCP options

From: Edwin Groothuis <wireshark@xxxxxxxxxxx>
Date: Mon, 30 Aug 2010 21:33:08 +1000
Hello,

I have been fighting with find_conversation(), conversation_new()
and conversation_set_dissector() to find a way to set change the
TCP payload dissector based on the data in the TCP dissector. All
coming from section 2.2, 2.3 and 2.4 from README.developer.

Programming-wise it all works, output-wise it doesn't. And now I'm
wondering if what I want is possible or not.

Short version: If a certain TCP option exist, then the content of
the TCP payload is not the "well-known" payload associated with the
TCP port number. So even if the TCP port number is port 80, it still
isn't HTTP traffic. How do you know? Because there is a TCP option
which tells me "this is not HTTP, this is an internal protocol.".

In dissect_tcpopt_ourinternal(), I have the following code. Shouldn't
be too difficult: Get the dissector handle, find the conversation,
set the new dissector for that conversation:

    conversation_t *conversation;
    static dissector_handle_t *ourinternal_handle = NULL;

    /*
     * We need to map this TCP session on our own dissector instead of what
     * Wireshark thinks runs on these ports - Edwin
     */
    if (ourinternal_handle == NULL) {
        fprintf(stderr, "Finding ourinternal dissector\n");
        ourinternal_handle = find_dissector("ourinternal");
    }
    if (ourinternal_handle != NULL) {
        fprintf(stderr, "Setting ourinternal dissector? ");
        conversation = find_conversation(pinfo->fd->num,
            &pinfo->src, &pinfo->dst, pinfo->ipproto,
            pinfo->srcport, pinfo->destport, 0);
        if (conversation == NULL) {
            fprintf(stderr, "New conversation! ");
            conversation = conversation_new(pinfo->fd->num,
                &pinfo->src, &pinfo->dst, pinfo->ipproto,
                pinfo->srcport, pinfo->destport, 0);
        }
        if (conversation->dissector_handle != ourinternal_handle) {
            fprintf(stderr, "Setting to ourinternal dissector!\n");
            conversation_set_dissector(conversation, ourinternal_handle);
        } else {
            fprintf(stderr, "Already done!\n");
        }
    }


And the result I get is:

[~/wireshark] edwin@k7>./wireshark/tshark -nr test2.cap -c 10    
  1   0.000000 10.19.143.22 -> 10.28.7.99   TCP S, 1945 > 8080 [SYN] Seq=0 Win=8192 Len=0 MSS=1460
  2   0.046720   10.28.7.99 -> 10.19.143.22 TCP SA, 8080 > 1945 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=1460
Finding ourinternal dissector
Setting ourinternal dissector? New conversation! Setting to ourinternal dissector!
  3   0.047463 10.19.143.22 -> 10.28.7.99   TCP [TCP Port numbers reused] TRPY, 1945 > 8080 [SYN] Seq=0 Win=5840 Len=0 MSS=1460 TSV=245836922 TSER=0 WS=2
Setting ourinternal dissector? Already done!
  4   0.096437   10.28.7.99 -> 10.19.143.22 TCP TRPY, 8080 > 1945 [SYN, ACK] Seq=0 Ack=1 Win=5792 Len=0 MSS=1460 TSV=250693356 TSER=245836922 WS=2
Setting ourinternal dissector? Already done!
  5   0.096463 10.19.143.22 -> 10.28.7.99   TCP TRPY, 1945 > 8080 [ACK] Seq=1 Ack=1 Win=5840 Len=0 TSV=245836971 TSER=250693356
Setting ourinternal dissector? Already done!
  6   0.096532 10.19.143.22 -> 10.28.7.99   HTTP Continuation or non-HTTP traffic
Setting ourinternal dissector? Already done!
  7   0.096930 10.19.143.22 -> 10.28.7.99   HTTP Continuation or non-HTTP traffic
Setting ourinternal dissector? Already done!

The output of fprintf(stderr,) gets printed before packet, so during
the parsing of packet 3 it comes in the dissect_tcpopt_ourinternal(),
finds that there is no value for the dissector_handle is, gets it
(subsequent calls to the dissect_tcpopt_ourinternal() show that it
was assigned correctly). It find that it's a new conversation and
assigns our internal dissector to it.

The logging on packet 4 and following shows that the conversation
is still valid, that the dissector handle is still set to our
internal dissector. But then, packet 6 and 7 are still talking about
HTTP Continuation and setting a breakpoint at the http_dissector
show that this one is still called...


So euhm... Is there a way to change the dissector of the TCP Payload
based while you are still one level higher in the TCP dissector?

Edwin

-- 
Edwin Groothuis		Website: http://www.mavetju.org/
edwin@xxxxxxxxxxx	Weblog:  http://www.mavetju.org/weblog/