summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2000-10-21 09:54:12 +0000
committerGuy Harris <guy@alum.mit.edu>2000-10-21 09:54:12 +0000
commit86ceeff7dbaa78d3ec5d8773b7f77d856053ace3 (patch)
tree2ae19e73d7ff9fe639c00cc123f760bcc034dd77
parent109721d54322cd554256cfea5fb27199ef9145be (diff)
downloadwireshark-86ceeff7dbaa78d3ec5d8773b7f77d856053ace3.tar.gz
Wildcard matching is tricky - you have to try wildcarding both the
source *and* destination port and/or both the source *and* destination address passed to "find_conversation()", because the packet for which you're trying to find the conversation may be going in the opposite direction to the packet for which the conversation was originally created. Create different hash tables for wildcarded conversations, to reduce the number of "is this a wildcard?" tests done when doing hash lookups. This is sufficient to allow the TFTP dissector to use conversations rather than being special-cased in the UDP dissector, and may also be sufficient to handle a similar problem with SMTP (request goes from client IP X port Y to server IP Z's well-known port, reply comes back from some other port on server Z to client IP X port Y), but further use may reveal other changes that should be made. svn path=/trunk/; revision=2525
-rw-r--r--Makefile.am3
-rw-r--r--epan/conversation.c456
-rw-r--r--epan/conversation.h5
-rw-r--r--packet-tftp.c40
-rw-r--r--packet-tftp.h30
-rw-r--r--packet-udp.c8
6 files changed, 432 insertions, 110 deletions
diff --git a/Makefile.am b/Makefile.am
index 781c046695..5ab1a0dab9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,7 @@
# Makefile.am
# Automake file for Ethereal
#
-# $Id: Makefile.am,v 1.237 2000/10/19 07:17:38 guy Exp $
+# $Id: Makefile.am,v 1.238 2000/10/21 09:54:10 guy Exp $
#
# Ethereal - Network traffic analyzer
# By Gerald Combs <gerald@zing.org>
@@ -240,7 +240,6 @@ noinst_HEADERS = \
packet-sscop.h \
packet-stat.h \
packet-tcp.h \
- packet-tftp.h \
packet-tns.h \
packet-tpkt.h \
packet-tr.h \
diff --git a/epan/conversation.c b/epan/conversation.c
index 4ae117c9d2..a1e43d153f 100644
--- a/epan/conversation.c
+++ b/epan/conversation.c
@@ -1,7 +1,7 @@
/* conversation.c
* Routines for building lists of packets that are part of a "conversation"
*
- * $Id: conversation.c,v 1.2 2000/10/21 05:52:28 guy Exp $
+ * $Id: conversation.c,v 1.3 2000/10/21 09:54:12 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@@ -42,7 +42,26 @@
#include "packet.h"
#include "conversation.h"
-static GHashTable *conversation_hashtable = NULL;
+/*
+ * Hash table for conversations with no wildcards.
+ */
+static GHashTable *conversation_hashtable_exact = NULL;
+
+/*
+ * Hash table for conversations with wildcard destination address.
+ */
+static GHashTable *conversation_hashtable_no_dst_addr = NULL;
+
+/*
+ * Hash table for conversations with wildcard destination port.
+ */
+static GHashTable *conversation_hashtable_no_dst_port = NULL;
+
+/*
+ * Hash table for conversations with wildcard destination address and port.
+ */
+static GHashTable *conversation_hashtable_no_dst = NULL;
+
static GMemChunk *conversation_key_chunk = NULL;
static GMemChunk *conversation_chunk = NULL;
@@ -54,7 +73,6 @@ typedef struct conversation_key {
port_type ptype;
guint32 port_src;
guint32 port_dst;
- guint options;
} conversation_key;
#endif
/*
@@ -68,10 +86,35 @@ static guint32 new_index;
static int conversation_init_count = 200;
/*
- * Compare two conversation keys.
+ * Compute the hash value for a given set of source and destination
+ * addresses and ports if the match is to be exact.
+ */
+static guint
+conversation_hash_exact(gconstpointer v)
+{
+ conversation_key *key = (conversation_key *)v;
+ guint hash_val;
+ int i;
+
+ hash_val = 0;
+ for (i = 0; i < key->src.len; i++)
+ hash_val += key->src.data[i];
+
+ hash_val += key->port_src;
+
+ for (i = 0; i < key->dst.len; i++)
+ hash_val += key->dst.data[i];
+
+ hash_val += key->port_dst;
+
+ return hash_val;
+}
+
+/*
+ * Compare two conversation keys for an exact match.
*/
static gint
-conversation_equal(gconstpointer v, gconstpointer w)
+conversation_match_exact(gconstpointer v, gconstpointer w)
{
conversation_key *v1 = (conversation_key *)v;
conversation_key *v2 = (conversation_key *)w;
@@ -81,21 +124,19 @@ conversation_equal(gconstpointer v, gconstpointer w)
/*
* Are the first and second source ports the same, the first and
- * second destination ports the same or not used (NO_DST_PORT),
- * the first and second source addresses the same, and the first
- * and second destination addresses the same or not used (NO_DST_ADDR)?
+ * second destination ports the same, the first and second source
+ * addresses the same, and the first and second destination
+ * addresses the same?
*/
if (v1->port_src == v2->port_src &&
- (((v1->options & NO_DST_PORT) && (v2->options & NO_DST_PORT)) ||
- v1->port_dst == v2->port_dst) &&
+ v1->port_dst == v2->port_dst &&
v1->src.type == v2->src.type &&
v1->src.len == v2->src.len &&
memcmp(v1->src.data, v2->src.data, v1->src.len) == 0 &&
- (((v1->ptype & NO_DST_ADDR) && (v2->ptype & NO_DST_ADDR)) ||
- (v1->dst.type == v2->dst.type &&
- v1->dst.type == v2->dst.type &&
- v1->dst.len == v2->dst.len &&
- memcmp(v1->dst.data, v2->dst.data, v1->dst.len) == 0))) {
+ v1->dst.type == v2->dst.type &&
+ v1->dst.type == v2->dst.type &&
+ v1->dst.len == v2->dst.len &&
+ memcmp(v1->dst.data, v2->dst.data, v1->dst.len) == 0) {
/*
* Yes. It's the same conversation, and the two
* address/port pairs are going in the same direction.
@@ -106,21 +147,18 @@ conversation_equal(gconstpointer v, gconstpointer w)
/*
* Is the first destination port the same as the second source
* port, the first source port the same as the second destination
- * port or not used (NO_DEST_PORT), the first destination address
- * the same as the second source address, and the first source
- * address the same as the second destination address or not used
- * (NO_DEST_ADDR).
+ * port, the first destination address the same as the second
+ * source address, and the first source address the same as the
+ * second destination address?
*/
if (v1->port_dst == v2->port_src &&
- (((v1->options & NO_DST_PORT) &&(v2->options & NO_DST_PORT)) ||
- v1->port_src == v2->port_dst) &&
+ v1->port_src == v2->port_dst &&
v1->dst.type == v2->src.type &&
v1->dst.len == v2->src.len &&
memcmp(v1->dst.data, v2->src.data, v1->dst.len) == 0 &&
- (((v1->options & NO_DST_ADDR) && (v2->options & NO_DST_ADDR)) ||
- (v1->src.type == v2->dst.type &&
- v1->src.len == v2->dst.len &&
- memcmp(v1->src.data, v2->dst.data, v1->src.len) == 0))) {
+ v1->src.type == v2->dst.type &&
+ v1->src.len == v2->dst.len &&
+ memcmp(v1->src.data, v2->dst.data, v1->src.len) == 0) {
/*
* Yes. It's the same conversation, and the two
* address/port pairs are going in opposite directions.
@@ -136,12 +174,71 @@ conversation_equal(gconstpointer v, gconstpointer w)
/*
* Compute the hash value for a given set of source and destination
- * addresses and ports.
+ * addresses and ports if the match has a wildcard destination address.
*/
static guint
-conversation_hash(gconstpointer v)
+conversation_hash_no_dst_addr(gconstpointer v)
+{
+ conversation_key *key = (conversation_key *)v;
+ guint hash_val;
+ int i;
+
+ hash_val = 0;
+ for (i = 0; i < key->src.len; i++)
+ hash_val += key->src.data[i];
+
+ hash_val += key->port_src;
+
+ hash_val += key->port_dst;
+
+ return hash_val;
+}
+
+/*
+ * Compare two conversation keys, except for the destination address.
+ * We don't check both directions of the conversation - the routine
+ * doing the hash lookup has to do two searches, as the hash key
+ * will be different for the two directions.
+ */
+static gint
+conversation_match_no_dst_addr(gconstpointer v, gconstpointer w)
{
+ conversation_key *v1 = (conversation_key *)v;
+ conversation_key *v2 = (conversation_key *)w;
+
+ if (v1->ptype != v2->ptype)
+ return 0; /* different types of port */
+ /*
+ * Are the first and second source ports the same, the first and
+ * second destination ports the same, and the first and second
+ * source addresses the same?
+ */
+ if (v1->port_src == v2->port_src &&
+ v1->port_dst == v2->port_dst &&
+ v1->src.type == v2->src.type &&
+ v1->src.len == v2->src.len &&
+ memcmp(v1->src.data, v2->src.data, v1->src.len) == 0) {
+ /*
+ * Yes. It's the same conversation, and the two
+ * address/port pairs are going in the same direction.
+ */
+ return 1;
+ }
+
+ /*
+ * The addresses or the ports don't match.
+ */
+ return 0;
+}
+
+/*
+ * Compute the hash value for a given set of source and destination
+ * addresses and ports if the match has a wildcard destination port.
+ */
+static guint
+conversation_hash_no_dst_port(gconstpointer v)
+{
conversation_key *key = (conversation_key *)v;
guint hash_val;
int i;
@@ -152,18 +249,110 @@ conversation_hash(gconstpointer v)
hash_val += key->port_src;
-/* Only hash the destination information if the value is needed. */
- if ( ! ( key->options & NO_DST_ADDR))
- for (i = 0; i < key->dst.len; i++)
- hash_val += key->dst.data[i];
+ for (i = 0; i < key->dst.len; i++)
+ hash_val += key->dst.data[i];
- if ( ! (key->options & NO_DST_PORT))
- hash_val += key->port_dst;
+ return hash_val;
+}
+
+/*
+ * Compare two conversation keys, except for the destination port.
+ * We don't check both directions of the conversation - the routine
+ * doing the hash lookup has to do two searches, as the hash key
+ * will be different for the two directions.
+ */
+static gint
+conversation_match_no_dst_port(gconstpointer v, gconstpointer w)
+{
+ conversation_key *v1 = (conversation_key *)v;
+ conversation_key *v2 = (conversation_key *)w;
+
+ if (v1->ptype != v2->ptype)
+ return 0; /* different types of port */
+
+ /*
+ * Are the first and second source ports the same, the first and
+ * second source addresses the same, and the first and second
+ * destination addresses the same?
+ */
+ if (v1->port_src == v2->port_src &&
+ v1->src.type == v2->src.type &&
+ v1->src.len == v2->src.len &&
+ memcmp(v1->src.data, v2->src.data, v1->src.len) == 0 &&
+ v1->dst.type == v2->dst.type &&
+ v1->dst.type == v2->dst.type &&
+ v1->dst.len == v2->dst.len &&
+ memcmp(v1->dst.data, v2->dst.data, v1->dst.len) == 0) {
+ /*
+ * Yes. It's the same conversation, and the two
+ * address/port pairs are going in the same direction.
+ */
+ return 1;
+ }
+
+ /*
+ * The addresses or the ports don't match.
+ */
+ return 0;
+}
+
+/*
+ * Compute the hash value for a given set of source and destination
+ * addresses and ports if the match has a wildcard destination.
+ */
+static guint
+conversation_hash_no_dst(gconstpointer v)
+{
+ conversation_key *key = (conversation_key *)v;
+ guint hash_val;
+ int i;
+
+ hash_val = 0;
+ for (i = 0; i < key->src.len; i++)
+ hash_val += key->src.data[i];
+
+ hash_val += key->port_src;
return hash_val;
}
/*
+ * Compare the source address and port in the two conversation keys.
+ * We don't check both directions of the conversation - the routine
+ * doing the hash lookup has to do two searches, as the hash key
+ * will be different for the two directions.
+ */
+static gint
+conversation_match_no_dst(gconstpointer v, gconstpointer w)
+{
+ conversation_key *v1 = (conversation_key *)v;
+ conversation_key *v2 = (conversation_key *)w;
+
+ if (v1->ptype != v2->ptype)
+ return 0; /* different types of port */
+
+ /*
+ * Are the first and second source ports the same and the first
+ * and second source addresses the same?
+ */
+ if (v1->port_src == v2->port_src &&
+ v1->src.type == v2->src.type &&
+ v1->src.len == v2->src.len &&
+ memcmp(v1->src.data, v2->src.data, v1->src.len) == 0) {
+ /*
+ * Yes. It's the same conversation, and the two
+ * address/port pairs are going in the same direction.
+ */
+ return 1;
+ }
+
+ /*
+ * The addresses or the ports don't match.
+ */
+ return 0;
+}
+
+/*
* Initialize some variables every time a file is loaded or re-loaded.
* Destroy all existing conversations, and create a new hash table
* for the conversations in the new file.
@@ -196,15 +385,31 @@ conversation_init(void)
g_free((gpointer)key->dst.data);
}
conversation_keys = NULL;
- if (conversation_hashtable != NULL)
- g_hash_table_destroy(conversation_hashtable);
+ if (conversation_hashtable_exact != NULL)
+ g_hash_table_destroy(conversation_hashtable_exact);
+ if (conversation_hashtable_no_dst_addr != NULL)
+ g_hash_table_destroy(conversation_hashtable_no_dst_addr);
+ if (conversation_hashtable_no_dst_port != NULL)
+ g_hash_table_destroy(conversation_hashtable_no_dst_port);
+ if (conversation_hashtable_no_dst != NULL)
+ g_hash_table_destroy(conversation_hashtable_no_dst);
if (conversation_key_chunk != NULL)
g_mem_chunk_destroy(conversation_key_chunk);
if (conversation_chunk != NULL)
g_mem_chunk_destroy(conversation_chunk);
- conversation_hashtable = g_hash_table_new(conversation_hash,
- conversation_equal);
+ conversation_hashtable_exact =
+ g_hash_table_new(conversation_hash_exact,
+ conversation_match_exact);
+ conversation_hashtable_no_dst_addr =
+ g_hash_table_new(conversation_hash_no_dst_addr,
+ conversation_match_no_dst_addr);
+ conversation_hashtable_no_dst_port =
+ g_hash_table_new(conversation_hash_no_dst_port,
+ conversation_match_no_dst_port);
+ conversation_hashtable_no_dst =
+ g_hash_table_new(conversation_hash_no_dst,
+ conversation_match_no_dst);
conversation_key_chunk = g_mem_chunk_new("conversation_key_chunk",
sizeof(conversation_key),
conversation_init_count * sizeof(struct conversation_key),
@@ -257,7 +462,6 @@ conversation_new(address *src, address *dst, port_type ptype,
new_key->ptype = ptype;
new_key->port_src = src_port;
new_key->port_dst = dst_port;
- new_key->options = options;
conversation = g_mem_chunk_alloc(conversation_chunk);
conversation->index = new_index;
@@ -266,12 +470,29 @@ conversation_new(address *src, address *dst, port_type ptype,
/* clear dissector pointer */
conversation->dissector.new_d = NULL;
-/* set the key pointer */
+/* set the options and key pointer */
+ conversation->options = options;
conversation->key_ptr = new_key;
new_index++;
- g_hash_table_insert(conversation_hashtable, new_key, conversation);
+ if (options & NO_DST_ADDR) {
+ if (options & NO_DST_PORT) {
+ g_hash_table_insert(conversation_hashtable_no_dst,
+ new_key, conversation);
+ } else {
+ g_hash_table_insert(conversation_hashtable_no_dst_addr,
+ new_key, conversation);
+ }
+ } else {
+ if (options & NO_DST_PORT) {
+ g_hash_table_insert(conversation_hashtable_no_dst_port,
+ new_key, conversation);
+ } else {
+ g_hash_table_insert(conversation_hashtable_exact,
+ new_key, conversation);
+ }
+ }
return conversation;
}
@@ -280,11 +501,29 @@ conversation_new(address *src, address *dst, port_type ptype,
*/
void conversation_set_port( conversation_t *conv, guint32 port){
- g_hash_table_remove(conversation_hashtable, conv->key_ptr);
- conv->key_ptr->options &= ~NO_DST_PORT;
+ /*
+ * If the destination port has already been set, don't set it
+ * again.
+ */
+ if (!(conv->options & NO_DST_PORT))
+ return;
+
+ if (conv->options & NO_DST_ADDR) {
+ g_hash_table_remove(conversation_hashtable_no_dst,
+ conv->key_ptr);
+ } else {
+ g_hash_table_remove(conversation_hashtable_no_dst_port,
+ conv->key_ptr);
+ }
+ conv->options &= ~NO_DST_PORT;
conv->key_ptr->port_dst = port;
- g_hash_table_insert(conversation_hashtable, conv->key_ptr, conv);
-
+ if (conv->options & NO_DST_ADDR) {
+ g_hash_table_insert(conversation_hashtable_no_dst_addr,
+ conv->key_ptr, conv);
+ } else {
+ g_hash_table_insert(conversation_hashtable_exact,
+ conv->key_ptr, conv);
+ }
}
/* Set the destination address in a key. Remove the original from
@@ -292,23 +531,34 @@ void conversation_set_port( conversation_t *conv, guint32 port){
*/
void conversation_set_addr( conversation_t *conv, address *addr){
-
- g_hash_table_remove(conversation_hashtable, conv->key_ptr);
- conv->key_ptr->options &= ~NO_DST_ADDR;
+ /*
+ * If the destination address has already been set, don't set it
+ * again.
+ */
+ if (!(conv->options & NO_DST_ADDR))
+ return;
+
+ if (conv->options & NO_DST_PORT) {
+ g_hash_table_remove(conversation_hashtable_no_dst,
+ conv->key_ptr);
+ } else {
+ g_hash_table_remove(conversation_hashtable_no_dst_addr,
+ conv->key_ptr);
+ }
+ conv->options &= ~NO_DST_ADDR;
copy_address(&conv->key_ptr->dst, addr);
- g_hash_table_insert(conversation_hashtable, conv->key_ptr, conv);
+ if (conv->options & NO_DST_PORT) {
+ g_hash_table_insert(conversation_hashtable_no_dst_port,
+ conv->key_ptr, conv);
+ } else {
+ g_hash_table_insert(conversation_hashtable_exact,
+ conv->key_ptr, conv);
+ }
}
-
-/*
- * Given source and destination addresses and ports for a packet,
- * search for a conversation containing packets between those address/port
- * pairs. Returns NULL if not found. If the NO_DEST_ADDR and/or NO_DEST_PORT
- * flags are set in the conversation options field, that value will not
- * be used.
- */
-conversation_t *
-find_conversation(address *src, address *dst, port_type ptype,
- guint32 src_port, guint32 dst_port, uint options)
+
+static conversation_t *
+conversation_match(GHashTable *hashtable, address *src, address *dst,
+ port_type ptype, guint32 src_port, guint32 dst_port)
{
conversation_key key;
@@ -319,10 +569,89 @@ find_conversation(address *src, address *dst, port_type ptype,
key.src = *src;
key.dst = *dst;
key.ptype = ptype;
- key.options = options;
key.port_src = src_port;
key.port_dst = dst_port;
- return g_hash_table_lookup(conversation_hashtable, &key);
+ return g_hash_table_lookup(hashtable, &key);
+}
+
+/*
+ * Given source and destination addresses and ports for a packet,
+ * search for a conversation containing packets between those address/port
+ * pairs. Returns NULL if not found. If the NO_DEST_ADDR and/or NO_DEST_PORT
+ * flags are set in the conversation options field, that value will not
+ * be used.
+ */
+conversation_t *
+find_conversation(address *src, address *dst, port_type ptype,
+ guint32 src_port, guint32 dst_port, guint options)
+{
+ conversation_t *conversation;
+
+ if (options & NO_DST_ADDR) {
+ if (options & NO_DST_PORT) {
+ /*
+ * Wildcard the address and port - first try looking
+ * for a conversation with the specified source
+ * address and port, then try looking for one with a
+ * source address and port that's the specified
+ * *destination* address and port (this packet may be
+ * going in the opposite direction from the first
+ * packet in the conversation).
+ */
+ conversation =
+ conversation_match(conversation_hashtable_no_dst,
+ src, dst, ptype, src_port, dst_port);
+ if (conversation != NULL)
+ return conversation;
+ return conversation_match(conversation_hashtable_no_dst,
+ dst, src, ptype, dst_port, src_port);
+ } else {
+ /*
+ * Wildcard the address - first try looking for a
+ * conversation with the specified source address
+ * and port and destination port, then try looking
+ * for one with a source address and port that's
+ * the specified *destination* address and port and
+ * a destination port that's the specified *source*
+ * port (this packet may be going in the opposite
+ * direction from the first packet in the conversation).
+ */
+ conversation =
+ conversation_match(conversation_hashtable_no_dst_addr,
+ src, dst, ptype, src_port, dst_port);
+ if (conversation != NULL)
+ return conversation;
+ return conversation_match(conversation_hashtable_no_dst_addr,
+ dst, src, ptype, dst_port, src_port);
+ }
+ } else {
+ if (options & NO_DST_PORT) {
+ /*
+ * Wildcard the port - first try looking for a
+ * conversation with the specified source address
+ * and port and destination address, then try looking
+ * for one with a source address and port that's
+ * the specified *destination* address and port and
+ * a destination address that's the specified *source*
+ * address (this packet may be going in the opposite
+ * direction from the first packet in the conversation).
+ */
+ conversation =
+ conversation_match(conversation_hashtable_no_dst_port,
+ src, dst, ptype, src_port, dst_port);
+ if (conversation != NULL)
+ return conversation;
+ return conversation_match(conversation_hashtable_no_dst_port,
+ dst, src, ptype, dst_port, src_port);
+ } else {
+ /*
+ * Search for an exact match. That search checks both
+ * directions.
+ */
+ return conversation_match(conversation_hashtable_exact,
+ src, dst, ptype, src_port, dst_port);
+ }
+ }
}
/*
@@ -353,9 +682,7 @@ conversation_set_dissector(conversation_t *conversation,
* card matches: try to match any port on the destination address first,
* then try to match any address on the port, then try to match any
* address and any port.
- *
*/
-
gboolean
old_try_conversation_dissector(address *src, address *dst, port_type ptype,
guint32 src_port, guint32 dst_port, const u_char *pd, int offset,
@@ -411,8 +738,7 @@ old_try_conversation_dissector(address *src, address *dst, port_type ptype,
* card matches: try to match any port on the destination address first,
* then try to match any address on the port, then try to match any
* address and any port.
-*/
-
+ */
gboolean
try_conversation_dissector(address *src, address *dst, port_type ptype,
guint32 src_port, guint32 dst_port, tvbuff_t *tvb, packet_info *pinfo,
diff --git a/epan/conversation.h b/epan/conversation.h
index 35b18f69d6..6e1878e8cd 100644
--- a/epan/conversation.h
+++ b/epan/conversation.h
@@ -1,7 +1,7 @@
/* conversation.h
* Routines for building lists of packets that are part of a "conversation"
*
- * $Id: conversation.h,v 1.2 2000/10/21 05:52:28 guy Exp $
+ * $Id: conversation.h,v 1.3 2000/10/21 09:54:12 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@@ -43,7 +43,6 @@ typedef struct conversation_key {
port_type ptype;
guint32 port_src;
guint32 port_dst;
- guint options;
} conversation_key;
typedef struct conversation {
@@ -55,7 +54,7 @@ typedef struct conversation {
old_dissector_t old_d;
dissector_t new_d;
} dissector; /* protocol dissector client can associate with conversation */
-
+ guint options; /* wildcard flags */
conversation_key *key_ptr; /* pointer to the key for this conversation */
} conversation_t;
diff --git a/packet-tftp.c b/packet-tftp.c
index 8c62d50183..9ad9454a63 100644
--- a/packet-tftp.c
+++ b/packet-tftp.c
@@ -5,7 +5,7 @@
* Craig Newell <CraigN@cheque.uq.edu.au>
* RFC2347 TFTP Option Extension
*
- * $Id: packet-tftp.c,v 1.13 2000/08/13 14:09:05 deniel Exp $
+ * $Id: packet-tftp.c,v 1.14 2000/10/21 09:54:10 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@@ -42,6 +42,7 @@
#include <glib.h>
#include "packet.h"
+#include "conversation.h"
static int proto_tftp = -1;
static int hf_tftp_type = -1;
@@ -49,6 +50,8 @@ static int hf_tftp_error_code = -1;
static gint ett_tftp = -1;
+#define UDP_PORT_TFTP 69
+
#define RRQ 1
#define WRQ 2
#define DATA 3
@@ -78,15 +81,41 @@ char *tftp_errors[8] = {
"No such user"
};
-void
+static void
dissect_tftp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
{
proto_tree *tftp_tree;
proto_item *ti;
u_int i1;
+ conversation_t *conversation;
OLD_CHECK_DISPLAY_AS_DATA(proto_tftp, pd, offset, fd, tree);
+ /*
+ * The first TFTP packet goes to the TFTP port; the second one
+ * comes from some *other* port, but goes back to the same
+ * IP address and port as the ones from which the first packet
+ * came; all subsequent packets go between those two IP addresses
+ * and ports.
+ *
+ * If this packet went to the TFTP port, we check to see if
+ * there's already a conversation with the source IP address
+ * and port of this packet, the destination IP address of this
+ * packet, and any destination UDP port. If not, we create
+ * one, with a wildcard UDP port, and give it the TFTP dissector
+ * as a dissector.
+ */
+ if (pi.destport == UDP_PORT_TFTP) {
+ conversation = find_conversation(&pi.src, &pi.dst, PT_UDP,
+ pi.srcport, 0, NO_DST_PORT);
+ if (conversation == NULL) {
+ conversation = conversation_new(&pi.src, &pi.dst, PT_UDP,
+ pi.srcport, 0, NULL,
+ NO_DST_PORT);
+ old_conversation_set_dissector(conversation, dissect_tftp);
+ }
+ }
+
if (check_col(fd, COL_PROTOCOL))
col_add_str(fd, COL_PROTOCOL, "TFTP");
@@ -192,7 +221,6 @@ dissect_tftp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
void
proto_register_tftp(void)
{
-
static hf_register_info hf[] = {
{ &hf_tftp_type,
{ "Type", "tftp.type",
@@ -212,3 +240,9 @@ proto_register_tftp(void)
proto_register_field_array(proto_tftp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
}
+
+void
+proto_reg_handoff_tftp(void)
+{
+ old_dissector_add("udp.port", UDP_PORT_TFTP, dissect_tftp);
+}
diff --git a/packet-tftp.h b/packet-tftp.h
deleted file mode 100644
index 955acb4153..0000000000
--- a/packet-tftp.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* packet-tftp.h
- *
- * $Id: packet-tftp.h,v 1.2 2000/08/11 13:33:58 deniel Exp $
- *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
- * Copyright 1998 Gerald Combs
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef __PACKET_TFTP_H__
-#define __PACKET_TFTP_H__
-
-void dissect_tftp(const u_char *, int, frame_data *, proto_tree *);
-
-#endif
diff --git a/packet-udp.c b/packet-udp.c
index 788d18beee..c577794a4c 100644
--- a/packet-udp.c
+++ b/packet-udp.c
@@ -1,7 +1,7 @@
/* packet-udp.c
* Routines for UDP packet disassembly
*
- * $Id: packet-udp.c,v 1.75 2000/08/13 14:09:07 deniel Exp $
+ * $Id: packet-udp.c,v 1.76 2000/10/21 09:54:10 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@@ -49,7 +49,6 @@
#include "packet-ip.h"
#include "conversation.h"
-#include "packet-tftp.h"
#include "packet-vines.h"
static int proto_udp = -1;
@@ -72,7 +71,6 @@ typedef struct _e_udphdr {
/* UDP Ports -> should go in packet-udp.h */
-#define UDP_PORT_TFTP 69
#define UDP_PORT_VINES 573
static dissector_table_t udp_dissector_table;
@@ -125,10 +123,6 @@ decode_udp_ports(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
if (PORT_IS(UDP_PORT_VINES)) {
/* FIXME: AFAIK, src and dst port must be the same */
dissect_vines_frp(pd, offset, fd, tree);
- } else if (PORT_IS(UDP_PORT_TFTP)) {
- /* This is the first point of call, but it adds a dynamic call */
- old_dissector_add("udp.port", MAX(uh_sport, uh_dport), dissect_tftp); /* Add to table */
- dissect_tftp(pd, offset, fd, tree);
} else
old_dissect_data(pd, offset, fd, tree);
}