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->fd->num,
&pinfo->src, &pinfo->dst,
pinfo->ptype,
pinfo->srcport, pinfo->destport,
NO_PORT_B);
if (! conversation) {
/* If we make a conversation, stick some unique data on it */
newConv = 1;
conversation = conversation_new(pinfo->fd->num,
&pinfo->src, &pinfo->dst,
pinfo->ptype,
pinfo->srcport, pinfo->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("CONV%s:\t%s:%u\t->\t%s:%u\t=>\t%p\t%d\n",
newConv ? "!" : "",
ep_address_to_str(&pinfo->src),
pinfo->srcport,
ep_address_to_str(&pinfo->dst),
pinfo->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("KACE Agent Messaging Protocol", "AMP", "amp");
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 Napier
26●3●3●7
accept rate: 100%
An alternative would be to do an exact match (i.e., pass 0 instead of
NO_PORT_B
tofind_conversation()
and 0 instead ofNO_PORT2
toconversation_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.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?