This is a static archive of our old Q&A Site. Please post any new questions and answers at ask.wireshark.org.

Tracking a conversation across a source port change

0

I have a protocol in which the client changes source ports regularly (the server has a single well known port). I'm trying to maintain a single conversation through this (each host can only have a single instance of the client). For example, I would expect this kind of traffic (52230 is the well known port):

client:12345 -> server:52230
server:52230 -> client:12345
client:23456 -> server:52230
server:55230 -> client:23456

This is one conversation. I've been trying to build a dissector that will handle this, and expected NO_PORT_B to be exactly what I needed, but I haven't been able to get it to work. In its most basic form, I try finding the conversation this way:

conversation_t *conversation = find_conversation(pinfo->fd->num,
                &pinfo->src, &pinfo->dst,
                pinfo->ptype, 
                pinfo->srcport, pinfo->destport, 
                NO_PORT_B);

If it doesn't exist, I try creating it this way:

    conversation = conversation_new(pinfo->fd->num,
                &pinfo->src, &pinfo->dst,
                pinfo->ptype, 
                pinfo->srcport, pinfo->destport,
                NO_PORT2);

That leads to:

first column: CONV + "!" if a conversation was not found and was created
second column: source
third column: destination
forth column: found conversation (possibly created)
fifth column: counter number attached to conversation conversation_add_proto_data

CONV!: 172.16.244.1:61661 -> 172.16.244.160:52230 => 0x10cd02d68 1 CONV!: 172.16.244.160:52230 -> 172.16.244.1:61661 => 0x10cd02fe8 2 CONV!: 172.16.244.1:61669 -> 172.16.244.160:52230 => 0x10cd033c8 3 CONV!: 172.16.244.160:52230 -> 172.16.244.1:61669 => 0x10cd03578 4 CONV: 172.16.244.1:61669 -> 172.16.244.160:52230 => 0x10cd033c8 3 CONV: 172.16.244.160:52230 -> 172.16.244.1:61669 => 0x10cd03578 4 CONV: 172.16.244.1:61669 -> 172.16.244.160:52230 => 0x10cd033c8 3

No wildcarding appears to be happening. It isn’t even joining symmetric communications like the first two packets.

I’ve tried many other combinations, including passing 0 instead of the port, or passing 52230 as the srcport rather than pinfo->srcport. I’ve even played with CONVERSATION_TEMPLATE, but I’m not quite certain what it’s doing. Every combination has created multiple conversations.

Below is my full test code. I can post a small pcap if that’s helpful.


#include <stdio.h> 
#include <config.h> #include <epan/packet.h> #include <epan/conversation.h>

#define AMP_PORT 52230

static dissector_handle_t amp_handle;

static int proto_amp = -1; static gint ett_amp = -1;

static int counter = 1;

static int dissect_amp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { col_set_str(pinfo-> cinfo, COL_PROTOCOL, "AMP"); col_clear(pinfo->cinfo, COL_INFO);

int newConv = 0;
conversation_t *conversation = find_conversation(pinfo-&gt;fd-&gt;num,
                &amp;pinfo-&gt;src, &amp;pinfo-&gt;dst,
                pinfo-&gt;ptype, 
                pinfo-&gt;srcport, pinfo-&gt;destport, 
                NO_PORT_B);
if (! conversation) {
    /* If we make a conversation, stick some unique data on it */
    newConv = 1;
    conversation = conversation_new(pinfo-&gt;fd-&gt;num,
                &amp;pinfo-&gt;src, &amp;pinfo-&gt;dst,
                pinfo-&gt;ptype, 
                pinfo-&gt;srcport, pinfo-&gt;destport,
                NO_PORT2);

    int *writeValue = malloc(sizeof(int));
    *writeValue = counter++;
    conversation_add_proto_data(conversation, proto_amp, writeValue);
    // conversation_set_dissector(conversation, amp_handle);
}

int *readValue = conversation_get_proto_data(conversation, proto_amp);

printf(&quot;CONV%s:\t%s:%u\t-&gt;\t%s:%u\t=&gt;\t%p\t%d\n&quot;,
    newConv ? &quot;!&quot; : &quot;&quot;,
    ep_address_to_str(&amp;pinfo-&gt;src), 
    pinfo-&gt;srcport,
    ep_address_to_str(&amp;pinfo-&gt;dst),
    pinfo-&gt;destport,
    conversation,
    readValue ? *readValue : 0);

return tvb_length(tvb);

} void proto_register_amp(void) { static hf_register_info hf_amp[] = {}; static gint *ett_amp_arr[] = { &ett_amp };

proto_amp = proto_register_protocol(&quot;KACE Agent Messaging Protocol&quot;, &quot;AMP&quot;, &quot;amp&quot;);
proto_register_field_array(proto_amp, hf_amp, array_length(hf_amp));
proto_register_subtree_array(ett_amp_arr, array_length(ett_amp_arr));

}

void proto_reg_handoff_amp(void) { amp_handle = new_create_dissector_handle((new_dissector_t)dissect_amp, proto_amp); dissector_add_uint("tcp.port", AMP_PORT, amp_handle); }

asked 05 Jan ‘14, 18:10

Rob%20Napier's gravatar image

Rob Napier
26337
accept rate: 100%

edited 05 Jan ‘14, 18:15


One Answer:

0

Possible answer to my own question. Correct me if this is the hard way.

I believe I over-estimated the power of NO_PORT_B. This flag appears to mean exactly what it says. The second port is ignored, not "one of the ports" as I'd hoped. So the solution is to create the conversation such that the server is first, and always query it such that the server is first.

Since the server has a reliable port, this isn't too difficult. I can check pinfo->srcport and pinfo->destport, and whichever of them matches my well-known port, it goes as the "addr1/port1" parameters.

answered 06 Jan '14, 06:33

Rob%20Napier's gravatar image

Rob Napier
26337
accept rate: 100%

1

An alternative would be to do an exact match (i.e., pass 0 instead of NO_PORT_B to find_conversation() and 0 instead of NO_PORT2 to conversation_new()) but replace the "non-well-known ports" with a constant value, such as 0. I'm not sure which method would be clearer and/or more efficient.

(06 Jan '14, 08:32) cmaynard ♦♦

I switched to the "0" port solution you mention. It seemed a bit more straightforward, and was successful. I haven't found a good harness for testing overall efficiency, though. Is there an established way to test dissector performance?

(07 Jan '14, 10:09) Rob Napier