Initial commit
Change-Id: I6a4444e3c193dae437cd7929f4c39aba7b749efa
diff --git a/contrib/wireshark/HOWTO b/contrib/wireshark/HOWTO
new file mode 100644
index 0000000..d6d9123
--- /dev/null
+++ b/contrib/wireshark/HOWTO
@@ -0,0 +1,68 @@
+ --------
+ FOREWORD
+ --------
+
+The patch in this folder allows Wireshark to process packets that contain TLS-protected
+Diameter messages over SCTP multi-stream associations. Each SCTP stream pairs is handled
+as a separate TLS channel (RFC3436), which is consistent with freeDiameter 1.0.x mechanism.
+
+It should be noted however that rfc3588bis (revised Diameter) recommends that DTLS is used
+instead of TLS over SCTP, for the reasons highlighted in the introduction of RFC6083.
+When this new mechanism is implemented in freeDiameter, a different patch will probably
+be required for wireshark.
+
+
+The instructions in this file will change your wireshark binary in a way suitable for
+analysis of Diameter over TLS over SCTP, but may have unexpected side-effects
+on some other protocols analysis (including DTLS).
+
+The instructions refer to Debian-style packaging (apt), you should adapt
+the process to build a new modified package of wireshark for your distribution.
+
+The provided patch has been successfully tested with:
+ - wireshark-1.2.7 (Ubuntu Lucid)
+ - wireshark-1.2.11 (Ubuntu Maverick)
+It may or may not work on more recent or ancient versions.
+
+
+ ------------
+ INSTRUCTIONS
+ ------------
+
+The steps are:
+ - get your wireshark source
+ apt-get source wireshark
+ cd wireshark-1.2.*
+
+ - apply the patch
+ cat ~/wireshark-1.2.7-diameter-tls.patch | patch -p1
+
+ - increase the version number
+ dch -lfD "Added support for Diameter over TLS over SCTP"
+
+ - Create a new package, this might take a while
+ fakeroot debian/rules binary
+
+ - Install the modified version
+ sudo dpkg --install ../wireshark-common_*fD*.deb ../wireshark_*fD*.deb
+
+ - Start the new wireshark:
+ wireshark &
+
+To analyze a capture file, you will need the private keys of both peers involved.
+
+Let's imagine for example:
+ peer A with IP address 192.168.0.10 has private key privA.pem
+ peer B with IP address 192.168.0.11 has private key privB.pem
+
+In wireshark you must do the following:
+ - go to menu Edit->Preferences
+ - In the left panel, under Protocols, scroll to "SSL" and select it.
+ - In the right panel, fill "RSA keys list" as follow:
+ 192.168.0.10,3869,diameter,/absolute/path/to/privA.pem;192.168.0.11,3869,diameter,/absolute/path/to/privB.pem
+ - You may find also useful to select an SSL debug file to get a hint of any problem.
+
+Once this configuration is complete, you should be able to see the contents of SCTP packets,
+including protected Diameter payload.
+
+Check the "sample" subdirectory for a test capture file.
diff --git a/contrib/wireshark/sample/192.168.103.10.priv.pem b/contrib/wireshark/sample/192.168.103.10.priv.pem
new file mode 100644
index 0000000..9da15dd
--- /dev/null
+++ b/contrib/wireshark/sample/192.168.103.10.priv.pem
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQDMcXy2iVqcXkGaY44yNihVNzW/zHptqID49/ZyyyOinxHenvf9
+o/fr613XvUuyquaapL99yiMPuLU3I1UxxacWBSAb496eGd7fY1Udw1RtqKCeb60c
+jpTc3zKySGPHtnzOxeSMDK/R6uqkFirF6Lnu18mKZyAwJtvFYnh0wK3SwwIDAQAB
+AoGAa6kX08hhPxcj1Pm4WBjNBJMeavJzRmwF/xYVYj43ddvuvR1Z2ugOFt7LfGDj
+DCOTbLx1Wvinng/W3kJtCtjbM3w3k5cuFJdJcURXda73IHSaJOHnBAw5RlvFCE79
+12yKqGOBgy80gGHDlqnSIjISCGb/9wLcHYLccakekckPc4ECQQDubt5fWzN4wUwU
+yW+e/SO9Vz4j+FiIC2aZy2OM9XXt6cgh4v0hQ3l0sWVJ6lTvK17aD9LXE5rluAOI
+thnPZElFAkEA24GH8Po/+3K6A5d5Zh1+hwoMLbWrykQDWSOgtmaOtbAvezlolF8O
+W18pVdvyMJg3gUiCA/rHG+r+OBxa4sx4ZwJAH4c1jHJo2fzlbJI+Wk2q3iydIPCD
+9GldhdSpM0h58Z3KQwDa6/0aIF4cwKtl08JuZnNVM+95ugqdHQTHYO8n6QJBAIgO
+m+KEWxBSpnX/d+IRuhGd6rqSdu8ihSjFaqJko2R+1o98oBQHb3C3ZXmwoUf5sb3S
+4bPxx2TIndbNzI/zyVUCQGqN7eyoeTxtPD8P08lUGTUnC2n0imZ1mU5p8Bnv8gw5
+lwt9qxuz0Ujr7uFPPu58bvGsYeoFUV23WRmS0rKLXv0=
+-----END RSA PRIVATE KEY-----
diff --git a/contrib/wireshark/sample/192.168.103.20.priv.pem b/contrib/wireshark/sample/192.168.103.20.priv.pem
new file mode 100644
index 0000000..9f69f7a
--- /dev/null
+++ b/contrib/wireshark/sample/192.168.103.20.priv.pem
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXgIBAAKBgQDef8CrqawfvmCLBwmlPRlWjwB6V4TvVMRhivAYlwwFbUSoU5bm
+2D780IBr3fNL3zP38ySa7r9cXxPgk7mbj3PhcJbI0Ix0AjQdFSB08AOXev4gqU8p
+qgEODFV04tnFhOcDysp77qH/DFuNwxd2xtFUbGKfGhroAssHxJuogOmiWQIDAQAB
+AoGAP6H7wVyCLIXu6HP3zzkdIQM+2L5k92mfzGHG7tFsD7VDWHyngJfB093xjGfq
+p/1KyJPSGTlEoy9R6P12rMWnFv7sYYKmPGfKdRUMxZYIXbplw6+L/gwW3MCiOMDD
+zRzRjknE3a+Mjo3e2XMHh6Z+GJ61megMeGInODP05/h66AECQQDyFhT+D8DVj1hp
+RlaYTFDKCmS9rgMQ+g4YyqMLzuakkKwaJwbCIlMbQortGBvY9I+0uZC4jklcOpnl
+YYcGIUEBAkEA60l5uAVBk6vKWKWX2cksBP/VlJM2B9pkvmlL7tPwJVEfoaAzZx4N
+rPpC9sOsFlX1ShpirAmIqmvY16in4xEJWQJBAOvULSEOcZjZapQrjEIS3gTkOR06
+fgw0vDTUeh8PsEmSEcXsTL4jt/fvS+0KNl6UZ8Xzm5LeMYLiJ3d4GZQUIwECQQCb
+vYLoH/KMQMYrb1DYQ6TzmjRRqC+3ewP8Vc6BQ6BN0yjQ3y2nL+l1eiIhHNwn3LYE
+Wvq9TYI87C4YcfbPAlPhAkEA0bNU/Utgdbv/yT4lUmw+0toqFHkcT5s13RFWzNJU
+KdQ308kwz9rSDmuQ8eYzn5V02TioJKV4r0NZz+WcCyDY3A==
+-----END RSA PRIVATE KEY-----
diff --git a/contrib/wireshark/sample/README b/contrib/wireshark/sample/README
new file mode 100644
index 0000000..c75cfa1
--- /dev/null
+++ b/contrib/wireshark/sample/README
@@ -0,0 +1,56 @@
+This folder contains an example capture file, as well as the two
+private keys required to decode the TLS-protected exchanges.
+
+In order to decrypt properly the packets, you'll need a patched wireshark (see parent directory)
+and the SSL "RSA Private Keys" properties set to (replace with real full path):
+ 192.168.103.10,3869,diameter,freeDiameter/contrib/wireshark/sample/192.168.103.10.priv.pem;192.168.103.20,3869,diameter,freeDiameter/contrib/wireshark/sample/192.168.103.20.priv.pem
+
+
+This capture contains everything that was exchanged by the peer since it boot up.
+The captured peer is "relay.a.rt.freediameter.net" with IP address 192.168.103.20.
+
+Here is the detail of what you can see in the capture, if the decyphering
+works as expected, in chronological order:
+
+-----------------------------------------------------------------------------
+Frames | Comments
+-----------------------------------------------------------------------------
+1-24 | Peer booting up: DHCP, NTP, ...
+ |
+25-29 | Connection attempt from 192.168.103.10
+ | first attempt on SCTP (frames 26-27)
+ | then on TCP (frames 28-29)
+ |
+32-35 | freeDiameter starting: Diameter Identities
+ | from the peer's configuration file are
+ | DNS resolved.
+ |
+36-39 | SCTP connection to 192.168.103.10
+ |
+40-45 | Failed attempt to connect to 192.168.103.30
+ | where freeDiameter was not started.
+ |
+46-49 | (I think this is trigged by Debug output,
+ | I have to check)
+ |
+50-73 | TLS handshake on first stream pair (#0).
+ |
+74-90 | Resumed handshakes on streams #1 and #2 in parallel.
+ | (not sure where to find that it is resumed,
+ | except that certificates are not re-exchanged)
+ |
+91-92 | CER/CEA exchange.
+93-96 | DWR/DWA exchange.
+ |
+103-118 | SCTP heartbeats are exchanged more frequently than DWR/DWA.
+ |
+119-124 | Concurrent DWR/DWA (it happens sometimes)
+ |
+125-128 | Another failed attempt to 192.168.103.30 (cf. frames 40-45)
+ |
+137-140 | DPR/DPA exchange.
+ |
+141-153 | TLS clean shutdown on all streams in parallel.
+ |
+154-157 | SCTP association is closed.
+-----------------------------------------------------------------------------
diff --git a/contrib/wireshark/sample/capture.cap b/contrib/wireshark/sample/capture.cap
new file mode 100644
index 0000000..a680590
--- /dev/null
+++ b/contrib/wireshark/sample/capture.cap
Binary files differ
diff --git a/contrib/wireshark/wireshark-1.2.7-diameter-tls.patch b/contrib/wireshark/wireshark-1.2.7-diameter-tls.patch
new file mode 100644
index 0000000..02a1824
--- /dev/null
+++ b/contrib/wireshark/wireshark-1.2.7-diameter-tls.patch
@@ -0,0 +1,685 @@
+diff -Nur wireshark-1.2.7/epan/conversation.c wireshark-1.2.7-fD/epan/conversation.c
+--- wireshark-1.2.7/epan/conversation.c 2010-04-01 01:44:39.000000000 +0900
++++ wireshark-1.2.7-fD/epan/conversation.c 2011-02-23 14:26:35.000000000 +0900
+@@ -40,6 +40,11 @@
+ static GHashTable *conversation_hashtable_exact = NULL;
+
+ /*
++ * Hash table for conversations without strid.
++ */
++static GHashTable *conversation_hashtable_no_strid = NULL;
++
++/*
+ * Hash table for conversations with one wildcard address.
+ */
+ static GHashTable *conversation_hashtable_no_addr2 = NULL;
+@@ -63,6 +68,7 @@
+ port_type ptype;
+ guint32 port1;
+ guint32 port2;
++ guint32 strid;
+ } conversation_key;
+ #endif
+ /*
+@@ -193,6 +199,7 @@
+ hash_val += key->port1;
+ ADD_ADDRESS_TO_HASH(hash_val, &key->addr2);
+ hash_val += key->port2;
++ hash_val += key->strid;
+
+ return hash_val;
+ }
+@@ -217,6 +224,78 @@
+ */
+ if (v1->port1 == v2->port1 &&
+ v1->port2 == v2->port2 &&
++ v1->strid == v2->strid &&
++ ADDRESSES_EQUAL(&v1->addr1, &v2->addr1) &&
++ ADDRESSES_EQUAL(&v1->addr2, &v2->addr2)) {
++ /*
++ * Yes. It's the same conversation, and the two
++ * address/port pairs are going in the same direction.
++ */
++ return 1;
++ }
++
++ /*
++ * Is the first port 2 the same as the second port 1, the first
++ * port 1 the same as the second port 2, the first address 2
++ * the same as the second address 1, and the first address 1
++ * the same as the second address 2?
++ */
++ if (v1->port2 == v2->port1 &&
++ v1->port1 == v2->port2 &&
++ v1->strid == v2->strid &&
++ ADDRESSES_EQUAL(&v1->addr2, &v2->addr1) &&
++ ADDRESSES_EQUAL(&v1->addr1, &v2->addr2)) {
++ /*
++ * Yes. It's the same conversation, and the two
++ * address/port pairs are going in opposite directions.
++ */
++ return 1;
++ }
++
++ /*
++ * The addresses or the ports don't match.
++ */
++ return 0;
++}
++
++/*
++ * Compute the hash value for two given address/port pairs if the match
++ * has a wildcard stream id.
++ */
++static guint
++conversation_hash_no_strid(gconstpointer v)
++{
++ const conversation_key *key = (const conversation_key *)v;
++ guint hash_val;
++
++ hash_val = 0;
++ ADD_ADDRESS_TO_HASH(hash_val, &key->addr1);
++ hash_val += key->port1;
++ hash_val += key->port2;
++
++ return hash_val;
++}
++
++/*
++ * Compare two conversation keys, except for the stream id value.
++ */
++static gint
++conversation_match_no_strid(gconstpointer v, gconstpointer w)
++{
++ const conversation_key *v1 = (const conversation_key *)v;
++ const conversation_key *v2 = (const conversation_key *)w;
++
++ if (v1->ptype != v2->ptype)
++ return 0; /* different types of port */
++
++ /*
++ * Are the first and second port 1 values the same, the first and
++ * second port 2 values the same, the first and second address
++ * 1 values the same, and the first and second address 2 values
++ * the same?
++ */
++ if (v1->port1 == v2->port1 &&
++ v1->port2 == v2->port2 &&
+ ADDRESSES_EQUAL(&v1->addr1, &v2->addr1) &&
+ ADDRESSES_EQUAL(&v1->addr2, &v2->addr2)) {
+ /*
+@@ -263,6 +342,7 @@
+ ADD_ADDRESS_TO_HASH(hash_val, &key->addr1);
+ hash_val += key->port1;
+ hash_val += key->port2;
++ hash_val += key->strid;
+
+ return hash_val;
+ }
+@@ -289,6 +369,7 @@
+ */
+ if (v1->port1 == v2->port1 &&
+ v1->port2 == v2->port2 &&
++ v1->strid == v2->strid &&
+ ADDRESSES_EQUAL(&v1->addr1, &v2->addr1)) {
+ /*
+ * Yes. It's the same conversation, and the two
+@@ -317,6 +398,7 @@
+ ADD_ADDRESS_TO_HASH(hash_val, &key->addr1);
+ hash_val += key->port1;
+ ADD_ADDRESS_TO_HASH(hash_val, &key->addr2);
++ hash_val += key->strid;
+
+ return hash_val;
+ }
+@@ -342,6 +424,7 @@
+ * address 2 values the same?
+ */
+ if (v1->port1 == v2->port1 &&
++ v1->strid == v2->strid &&
+ ADDRESSES_EQUAL(&v1->addr1, &v2->addr1) &&
+ ADDRESSES_EQUAL(&v1->addr2, &v2->addr2)) {
+ /*
+@@ -370,6 +453,7 @@
+ hash_val = 0;
+ ADD_ADDRESS_TO_HASH(hash_val, &key->addr1);
+ hash_val += key->port1;
++ hash_val += key->strid;
+
+ return hash_val;
+ }
+@@ -394,6 +478,7 @@
+ * and second address 1 values the same?
+ */
+ if (v1->port1 == v2->port1 &&
++ v1->strid == v2->strid &&
+ ADDRESSES_EQUAL(&v1->addr1, &v2->addr1)) {
+ /*
+ * Yes. It's the same conversation, and the two
+@@ -420,6 +505,8 @@
+ conversation_keys = NULL;
+ if (conversation_hashtable_exact != NULL)
+ g_hash_table_destroy(conversation_hashtable_exact);
++ if (conversation_hashtable_no_strid != NULL)
++ g_hash_table_destroy(conversation_hashtable_no_strid);
+ if (conversation_hashtable_no_addr2 != NULL)
+ g_hash_table_destroy(conversation_hashtable_no_addr2);
+ if (conversation_hashtable_no_port2 != NULL)
+@@ -438,6 +525,9 @@
+ conversation_hashtable_exact =
+ g_hash_table_new(conversation_hash_exact,
+ conversation_match_exact);
++ conversation_hashtable_no_strid =
++ g_hash_table_new(conversation_hash_no_strid,
++ conversation_match_no_strid);
+ conversation_hashtable_no_addr2 =
+ g_hash_table_new(conversation_hash_no_addr2,
+ conversation_match_no_addr2);
+@@ -466,6 +556,15 @@
+ conversation_new(guint32 setup_frame, address *addr1, address *addr2, port_type ptype,
+ guint32 port1, guint32 port2, guint options)
+ {
++ return conversation_new_ext(setup_frame, addr1, addr2, ptype,
++ port1, port2, options & ~(DISTINCT_SCTP_STREAMID), 0);
++
++}
++
++conversation_t *
++conversation_new_ext(guint32 setup_frame, address *addr1, address *addr2, port_type ptype,
++ guint32 port1, guint32 port2, guint options, guint16 strid)
++{
+ /*
+ DISSECTOR_ASSERT(!(options | CONVERSATION_TEMPLATE) || ((options | (NO_ADDR2 | NO_PORT2 | NO_PORT2_FORCE))) &&
+ "A conversation template may not be constructed without wildcard options");
+@@ -486,7 +585,11 @@
+ if (options & (NO_PORT2|NO_PORT2_FORCE)) {
+ hashtable = conversation_hashtable_no_port2;
+ } else {
+- hashtable = conversation_hashtable_exact;
++ if (options & DISTINCT_SCTP_STREAMID) {
++ hashtable = conversation_hashtable_exact;
++ } else {
++ hashtable = conversation_hashtable_no_strid;
++ }
+ }
+ }
+
+@@ -495,6 +598,7 @@
+ existing_key.ptype = ptype;
+ existing_key.port1 = port1;
+ existing_key.port2 = port2;
++ existing_key.strid = strid;
+
+ conversation = g_hash_table_lookup(hashtable, &existing_key);
+ tc = conversation; /* Remember if lookup was successful */
+@@ -507,6 +611,7 @@
+ new_key->ptype = ptype;
+ new_key->port1 = port1;
+ new_key->port2 = port2;
++ new_key->strid = strid;
+
+ if (conversation) {
+ for (; conversation->next; conversation = conversation->next)
+@@ -568,8 +673,13 @@
+ g_hash_table_insert(conversation_hashtable_no_addr2,
+ conv->key_ptr, conv);
+ } else {
+- g_hash_table_insert(conversation_hashtable_exact,
+- conv->key_ptr, conv);
++ if (conv->options & DISTINCT_SCTP_STREAMID) {
++ g_hash_table_insert(conversation_hashtable_exact,
++ conv->key_ptr, conv);
++ } else {
++ g_hash_table_insert(conversation_hashtable_no_strid,
++ conv->key_ptr, conv);
++ }
+ }
+ }
+
+@@ -602,18 +712,23 @@
+ g_hash_table_insert(conversation_hashtable_no_port2,
+ conv->key_ptr, conv);
+ } else {
+- g_hash_table_insert(conversation_hashtable_exact,
+- conv->key_ptr, conv);
++ if (conv->options & DISTINCT_SCTP_STREAMID) {
++ g_hash_table_insert(conversation_hashtable_exact,
++ conv->key_ptr, conv);
++ } else {
++ g_hash_table_insert(conversation_hashtable_no_strid,
++ conv->key_ptr, conv);
++ }
+ }
+ }
+
+ /*
+ * Search a particular hash table for a conversation with the specified
+- * {addr1, port1, addr2, port2} and set up before frame_num.
++ * {addr1, port1, addr2, port2, strid} and set up before frame_num.
+ */
+ static conversation_t *
+ conversation_lookup_hashtable(GHashTable *hashtable, guint32 frame_num, address *addr1, address *addr2,
+- port_type ptype, guint32 port1, guint32 port2)
++ port_type ptype, guint32 port1, guint32 port2, guint16 strid)
+ {
+ conversation_t* conversation;
+ conversation_t* match;
+@@ -628,6 +743,7 @@
+ key.ptype = ptype;
+ key.port1 = port1;
+ key.port2 = port2;
++ key.strid = strid;
+
+ match = g_hash_table_lookup(hashtable, &key);
+
+@@ -685,12 +801,19 @@
+ find_conversation(guint32 frame_num, address *addr_a, address *addr_b, port_type ptype,
+ guint32 port_a, guint32 port_b, guint options)
+ {
++ return find_conversation_ext(frame_num, addr_a, addr_b, ptype,
++ port_a, port_b, options | IGNORE_SCTP_STREAMID, 0);
++}
++conversation_t *
++find_conversation_ext(guint32 frame_num, address *addr_a, address *addr_b, port_type ptype,
++ guint32 port_a, guint32 port_b, guint options, guint16 strid)
++{
+ conversation_t *conversation;
+
+ /*
+- * First try an exact match, if we have two addresses and ports.
++ * First try an exact match, if we have two addresses and ports and strid.
+ */
+- if (!(options & (NO_ADDR_B|NO_PORT_B))) {
++ if (!(options & (NO_ADDR_B|NO_PORT_B|IGNORE_SCTP_STREAMID))) {
+ /*
+ * Neither search address B nor search port B are wildcarded,
+ * start out with an exact match.
+@@ -699,7 +822,7 @@
+ conversation =
+ conversation_lookup_hashtable(conversation_hashtable_exact,
+ frame_num, addr_a, addr_b, ptype,
+- port_a, port_b);
++ port_a, port_b, strid);
+ if ((conversation == NULL) && (addr_a->type == AT_FC)) {
+ /* In Fibre channel, OXID & RXID are never swapped as
+ * TCP/UDP ports are in TCP/IP.
+@@ -707,7 +830,33 @@
+ conversation =
+ conversation_lookup_hashtable(conversation_hashtable_exact,
+ frame_num, addr_b, addr_a, ptype,
+- port_a, port_b);
++ port_a, port_b, strid);
++ }
++ if (conversation != NULL)
++ return conversation;
++ }
++
++ /*
++ * Then, ignoring strid try an exact match, if we have two addresses and ports.
++ */
++ if (!(options & (NO_ADDR_B|NO_PORT_B|NO_IGNORE_SCTP_STREAMID))) {
++ /*
++ * Neither search address B nor search port B are wildcarded,
++ * start out with an exact match.
++ * Exact matches check both directions.
++ */
++ conversation =
++ conversation_lookup_hashtable(conversation_hashtable_no_strid,
++ frame_num, addr_a, addr_b, ptype,
++ port_a, port_b, strid);
++ if ((conversation == NULL) && (addr_a->type == AT_FC)) {
++ /* In Fibre channel, OXID & RXID are never swapped as
++ * TCP/UDP ports are in TCP/IP.
++ */
++ conversation =
++ conversation_lookup_hashtable(conversation_hashtable_no_strid,
++ frame_num, addr_b, addr_a, ptype,
++ port_a, port_b, strid);
+ }
+ if (conversation != NULL)
+ return conversation;
+@@ -729,7 +878,7 @@
+ */
+ conversation =
+ conversation_lookup_hashtable(conversation_hashtable_no_addr2,
+- frame_num, addr_a, addr_b, ptype, port_a, port_b);
++ frame_num, addr_a, addr_b, ptype, port_a, port_b, strid);
+ if ((conversation == NULL) && (addr_a->type == AT_FC)) {
+ /* In Fibre channel, OXID & RXID are never swapped as
+ * TCP/UDP ports are in TCP/IP.
+@@ -737,7 +886,7 @@
+ conversation =
+ conversation_lookup_hashtable(conversation_hashtable_no_addr2,
+ frame_num, addr_b, addr_a, ptype,
+- port_a, port_b);
++ port_a, port_b, strid);
+ }
+ if (conversation != NULL) {
+ /*
+@@ -779,7 +928,7 @@
+ if (!(options & NO_ADDR_B)) {
+ conversation =
+ conversation_lookup_hashtable(conversation_hashtable_no_addr2,
+- frame_num, addr_b, addr_a, ptype, port_b, port_a);
++ frame_num, addr_b, addr_a, ptype, port_b, port_a, strid);
+ if (conversation != NULL) {
+ /*
+ * If this is for a connection-oriented
+@@ -821,14 +970,14 @@
+ */
+ conversation =
+ conversation_lookup_hashtable(conversation_hashtable_no_port2,
+- frame_num, addr_a, addr_b, ptype, port_a, port_b);
++ frame_num, addr_a, addr_b, ptype, port_a, port_b, strid);
+ if ((conversation == NULL) && (addr_a->type == AT_FC)) {
+ /* In Fibre channel, OXID & RXID are never swapped as
+ * TCP/UDP ports are in TCP/IP
+ */
+ conversation =
+ conversation_lookup_hashtable(conversation_hashtable_no_port2,
+- frame_num, addr_b, addr_a, ptype, port_a, port_b);
++ frame_num, addr_b, addr_a, ptype, port_a, port_b, strid);
+ }
+ if (conversation != NULL) {
+ /*
+@@ -870,7 +1019,7 @@
+ if (!(options & NO_PORT_B)) {
+ conversation =
+ conversation_lookup_hashtable(conversation_hashtable_no_port2,
+- frame_num, addr_b, addr_a, ptype, port_b, port_a);
++ frame_num, addr_b, addr_a, ptype, port_b, port_a, strid);
+ if (conversation != NULL) {
+ /*
+ * If this is for a connection-oriented
+@@ -907,7 +1056,7 @@
+ */
+ conversation =
+ conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2,
+- frame_num, addr_a, addr_b, ptype, port_a, port_b);
++ frame_num, addr_a, addr_b, ptype, port_a, port_b, strid);
+ if (conversation != NULL) {
+ /*
+ * If this is for a connection-oriented protocol:
+@@ -952,11 +1101,11 @@
+ if (addr_a->type == AT_FC)
+ conversation =
+ conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2,
+- frame_num, addr_b, addr_a, ptype, port_a, port_b);
++ frame_num, addr_b, addr_a, ptype, port_a, port_b, strid);
+ else
+ conversation =
+ conversation_lookup_hashtable(conversation_hashtable_no_addr2_or_port2,
+- frame_num, addr_b, addr_a, ptype, port_b, port_a);
++ frame_num, addr_b, addr_a, ptype, port_b, port_a, strid);
+ if (conversation != NULL) {
+ /*
+ * If this is for a connection-oriented protocol, set the
+diff -Nur wireshark-1.2.7/epan/conversation.h wireshark-1.2.7-fD/epan/conversation.h
+--- wireshark-1.2.7/epan/conversation.h 2010-04-01 01:44:39.000000000 +0900
++++ wireshark-1.2.7-fD/epan/conversation.h 2011-02-23 14:25:44.000000000 +0900
+@@ -39,11 +39,13 @@
+ * TEMPLATE flag will be altered once the first connections (connection
+ * oriented protocols only) to include the newly found information which
+ * matched the wildcard options.
++ * DISTINCT_SCTP_STREAMID will also save the SCTP stream identifier, if any.
+ */
+ #define NO_ADDR2 0x01
+ #define NO_PORT2 0x02
+ #define NO_PORT2_FORCE 0x04
+ #define CONVERSATION_TEMPLATE 0x08
++#define DISTINCT_SCTP_STREAMID 0x10
+
+ /*
+ * Flags to pass to "find_conversation()" to indicate that the address B
+@@ -51,6 +53,8 @@
+ */
+ #define NO_ADDR_B 0x01
+ #define NO_PORT_B 0x02
++#define IGNORE_SCTP_STREAMID 0x04
++#define NO_IGNORE_SCTP_STREAMID 0x08
+
+ #include "packet.h" /* for conversation dissector type */
+
+@@ -64,6 +68,7 @@
+ port_type ptype;
+ guint32 port1;
+ guint32 port2;
++ guint16 strid;
+ } conversation_key;
+
+ typedef struct conversation {
+@@ -85,6 +90,13 @@
+ extern conversation_t *find_conversation(guint32 frame_num, address *addr_a, address *addr_b,
+ port_type ptype, guint32 port_a, guint32 port_b, guint options);
+
++/* for SCTP stream */
++extern conversation_t *conversation_new_ext(guint32 setup_frame, address *addr1, address *addr2,
++ port_type ptype, guint32 port1, guint32 port2, guint options, guint16 strid);
++extern conversation_t *find_conversation_ext(guint32 frame_num, address *addr_a, address *addr_b,
++ port_type ptype, guint32 port_a, guint32 port_b, guint options, guint16 strid);
++
++
+ extern void conversation_add_proto_data(conversation_t *conv, int proto,
+ void *proto_data);
+ extern void *conversation_get_proto_data(conversation_t *conv, int proto);
+diff -Nur wireshark-1.2.7/epan/dissectors/packet-diameter.c wireshark-1.2.7-fD/epan/dissectors/packet-diameter.c
+--- wireshark-1.2.7/epan/dissectors/packet-diameter.c 2010-04-01 01:44:21.000000000 +0900
++++ wireshark-1.2.7-fD/epan/dissectors/packet-diameter.c 2011-02-23 13:33:10.000000000 +0900
+@@ -63,8 +63,10 @@
+ #include "packet-ntp.h"
+ #include "packet-diameter.h"
+ #include "diam_dict.h"
++#include "packet-ssl.h"
+
+ #define SCTP_PORT_DIAMETER 3868
++#define SCTP_TLS_PORT_DIAMETER 3869
+
+ /* Diameter Header Flags */
+ /* RPETrrrrCCCCCCCCCCCCCCCCCCCCCCCC */
+@@ -271,10 +273,13 @@
+
+
+ static guint gbl_diameterSctpPort=SCTP_PORT_DIAMETER;
++static guint gbl_diameterSctpTlsPort=SCTP_TLS_PORT_DIAMETER;
+
+ static dissector_handle_t diameter_tcp_handle;
+ static range_t *global_diameter_tcp_port_range;
++static range_t *global_diameter_tcp_tls_port_range;
+ #define DEFAULT_DIAMETER_PORT_RANGE "3868"
++#define DEFAULT_DIAMETER_TLS_PORT_RANGE "3869"
+
+ /* desegmentation of Diameter over TCP */
+ static gboolean gbl_diameter_desegment = TRUE;
+@@ -1358,13 +1363,27 @@
+ dissector_add("tcp.port", port, diameter_tcp_handle);
+ }
+
++static void
++range_delete_callback_sec(guint32 port)
++{
++ ssl_dissector_delete(port, "diameter", TRUE);
++}
++
++static void
++range_add_callback_sec(guint32 port)
++{
++ ssl_dissector_add(port, "diameter", TRUE);
++}
++
+ void
+ proto_reg_handoff_diameter(void)
+ {
+ static gboolean Initialized=FALSE;
+ static guint SctpPort;
++ static guint SctpsPort;
+ static dissector_handle_t diameter_handle;
+ static range_t *diameter_tcp_port_range;
++ static range_t *diameters_tcp_port_range;
+
+ if (!Initialized) {
+ diameter_handle = find_dissector("diameter");
+@@ -1382,20 +1401,27 @@
+ /* AVP Code: 463 EAP-Reissued-Payload */
+ dissector_add("diameter.base", 463,
+ new_create_dissector_handle(dissect_diameter_eap_payload, proto_diameter));
++
++ /* set port for future deletes */
++ diameter_tcp_port_range = range_copy(global_diameter_tcp_port_range);
++ range_foreach(diameter_tcp_port_range, range_add_callback);
++ diameters_tcp_port_range = range_copy(global_diameter_tcp_tls_port_range);
++ range_foreach(diameters_tcp_port_range, range_add_callback_sec);
++
++ dissector_add("sctp.port", gbl_diameterSctpPort, diameter_handle);
++ ssl_dissector_add(gbl_diameterSctpTlsPort, "diameter", TRUE);
+
+ Initialized=TRUE;
+ } else {
+ range_foreach(diameter_tcp_port_range, range_delete_callback);
+ g_free(diameter_tcp_port_range);
++ range_foreach(diameters_tcp_port_range, range_delete_callback_sec);
++ g_free(diameters_tcp_port_range);
+ dissector_delete("sctp.port", SctpPort, diameter_handle);
+ }
+
+- /* set port for future deletes */
+- diameter_tcp_port_range = range_copy(global_diameter_tcp_port_range);
+- range_foreach(diameter_tcp_port_range, range_add_callback);
+
+- SctpPort=gbl_diameterSctpPort;
+- dissector_add("sctp.port", gbl_diameterSctpPort, diameter_handle);
++
+ }
+
+ /* registration with the filtering engine */
+@@ -1543,8 +1569,9 @@
+ diameter_dissector_table = register_dissector_table("diameter.base", "DIAMETER_3GPP_AVPS", FT_UINT32, BASE_DEC);
+ diameter_3gpp_avp_dissector_table = register_dissector_table("diameter.3gpp", "DIAMETER_3GPP_AVPS", FT_UINT32, BASE_DEC);
+
+- /* Set default TCP ports */
++ /* Set default TCP & TLS ports */
+ range_convert_str(&global_diameter_tcp_port_range, DEFAULT_DIAMETER_PORT_RANGE, MAX_UDP_PORT);
++ range_convert_str(&global_diameter_tcp_tls_port_range, DEFAULT_DIAMETER_TLS_PORT_RANGE, MAX_UDP_PORT);
+
+ /* Register configuration options for ports */
+ diameter_module = prefs_register_protocol(proto_diameter,
+diff -Nur wireshark-1.2.7/epan/dissectors/packet-sctp.c wireshark-1.2.7-fD/epan/dissectors/packet-sctp.c
+--- wireshark-1.2.7/epan/dissectors/packet-sctp.c 2010-04-01 01:44:28.000000000 +0900
++++ wireshark-1.2.7-fD/epan/dissectors/packet-sctp.c 2011-02-23 13:54:13.000000000 +0900
+@@ -2693,6 +2693,7 @@
+ b_bit = tvb_get_guint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_DATA_CHUNK_B_BIT;
+ u_bit = tvb_get_guint8(chunk_tvb, CHUNK_FLAGS_OFFSET) & SCTP_DATA_CHUNK_U_BIT;
+ stream_id = tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_ID_OFFSET);
++ pinfo->strid = stream_id;
+ stream_seq_num = tvb_get_ntohs(chunk_tvb, DATA_CHUNK_STREAM_SEQ_NUMBER_OFFSET);
+ tsn = tvb_get_ntohl(chunk_tvb, DATA_CHUNK_TSN_OFFSET);
+
+diff -Nur wireshark-1.2.7/epan/dissectors/packet-ssl.c wireshark-1.2.7-fD/epan/dissectors/packet-ssl.c
+--- wireshark-1.2.7/epan/dissectors/packet-ssl.c 2010-04-01 01:44:34.000000000 +0900
++++ wireshark-1.2.7-fD/epan/dissectors/packet-ssl.c 2011-02-23 14:56:36.000000000 +0900
+@@ -500,6 +500,7 @@
+ guint* conv_version;
+ Ssl_private_key_t * private_key;
+ guint32 port;
++ guint16 strid;
+
+ ti = NULL;
+ ssl_tree = NULL;
+@@ -507,9 +508,14 @@
+ first_record_in_frame = TRUE;
+ ssl_session = NULL;
+ port = 0;
++ strid = 0;
+
+
+ ssl_debug_printf("\ndissect_ssl enter frame #%u (%s)\n", pinfo->fd->num, (pinfo->fd->flags.visited)?"already visited":"first time");
++
++ if (pinfo->ptype == PT_SCTP) {
++ ssl_debug_printf("\ndissect_ssl SCTP stream %hd\n", pinfo->strid);
++ }
+
+ /* Track the version using conversations to reduce the
+ * chance that a packet that simply *looks* like a v2 or
+@@ -523,14 +529,14 @@
+ * the conv_version, must set the copy in the conversation
+ * in addition to conv_version
+ */
+- conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
+- pinfo->srcport, pinfo->destport, 0);
++ conversation = find_conversation_ext(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
++ pinfo->srcport, pinfo->destport, NO_IGNORE_SCTP_STREAMID, pinfo->strid);
+
+ if (!conversation)
+ {
+ /* create a new conversation */
+- conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
+- pinfo->srcport, pinfo->destport, 0);
++ conversation = conversation_new_ext(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
++ pinfo->srcport, pinfo->destport, (pinfo->ptype == PT_SCTP) ? DISTINCT_SCTP_STREAMID : 0, pinfo->strid);
+ ssl_debug_printf(" new conversation = %p created\n", (void *)conversation);
+ }
+ conv_data = conversation_get_proto_data(conversation, proto_ssl);
+@@ -549,7 +555,7 @@
+ conversation_add_proto_data(conversation, proto_ssl, ssl_session);
+
+ /* we need to know which side of the conversation is speaking */
+- if (ssl_packet_from_server(ssl_associations, pinfo->srcport, pinfo->ptype == PT_TCP)) {
++ if (ssl_packet_from_server(ssl_associations, pinfo->srcport, pinfo->ptype != PT_UDP)) {
+ dummy.addr = pinfo->src;
+ dummy.port = port = pinfo->srcport;
+ } else {
+@@ -762,7 +768,7 @@
+ * add decrypted data to this packet info */
+ ssl_debug_printf("decrypt_ssl3_record: app_data len %d ssl, state 0x%02X\n",
+ record_length, ssl->state);
+- direction = ssl_packet_from_server(ssl_associations, pinfo->srcport, pinfo->ptype == PT_TCP);
++ direction = ssl_packet_from_server(ssl_associations, pinfo->srcport, pinfo->ptype != PT_UDP);
+
+ /* retrieve decoder for this packet direction */
+ if (direction != 0) {
+@@ -1504,7 +1510,7 @@
+ col_append_str(pinfo->cinfo, COL_INFO, "Change Cipher Spec");
+ dissect_ssl3_change_cipher_spec(tvb, ssl_record_tree,
+ offset, conv_version, content_type);
+- if (ssl) ssl_change_cipher(ssl, ssl_packet_from_server(ssl_associations, pinfo->srcport, pinfo->ptype == PT_TCP));
++ if (ssl) ssl_change_cipher(ssl, ssl_packet_from_server(ssl_associations, pinfo->srcport, pinfo->ptype != PT_UDP));
+ break;
+ case SSL_ID_ALERT:
+ {
+@@ -1566,8 +1572,8 @@
+ /* we need dissector information when the selected packet is shown.
+ * ssl session pointer is NULL at that time, so we can't access
+ * info cached there*/
+- association = ssl_association_find(ssl_associations, pinfo->srcport, pinfo->ptype == PT_TCP);
+- association = association ? association: ssl_association_find(ssl_associations, pinfo->destport, pinfo->ptype == PT_TCP);
++ association = ssl_association_find(ssl_associations, pinfo->srcport, pinfo->ptype != PT_UDP);
++ association = association ? association: ssl_association_find(ssl_associations, pinfo->destport, pinfo->ptype != PT_UDP);
+
+ proto_item_set_text(ssl_record_tree,
+ "%s Record Layer: %s Protocol: %s",
+diff -Nur wireshark-1.2.7/epan/dissectors/packet-ssl-utils.c wireshark-1.2.7-fD/epan/dissectors/packet-ssl-utils.c
+--- wireshark-1.2.7/epan/dissectors/packet-ssl-utils.c 2010-04-01 01:44:27.000000000 +0900
++++ wireshark-1.2.7-fD/epan/dissectors/packet-ssl-utils.c 2011-02-23 13:33:10.000000000 +0900
+@@ -2713,9 +2713,10 @@
+ fprintf(stderr, "association_add() could not find handle for protocol:%s\n",protocol);
+ } else {
+ if(port) {
+- if(tcp)
++ if(tcp) {
+ dissector_add("tcp.port", port, handle);
+- else
++ dissector_add("sctp.port", port, handle);
++ } else
+ dissector_add("udp.port", port, handle);
+ }
+ g_tree_insert(associations, assoc, assoc);
+diff -Nur wireshark-1.2.7/epan/packet_info.h wireshark-1.2.7-fD/epan/packet_info.h
+--- wireshark-1.2.7/epan/packet_info.h 2010-04-01 01:44:40.000000000 +0900
++++ wireshark-1.2.7-fD/epan/packet_info.h 2011-02-23 13:54:52.000000000 +0900
+@@ -169,6 +169,7 @@
+ tvbuff_t *gssapi_decrypted_tvb;
+ gboolean gssapi_data_encrypted;
+
++ guint16 strid; /* Stream Id of the last DATA chunk in the packet */
+ guint32 ppid; /* SCTP PPI of current DATA chunk */
+ guint32 ppids[MAX_NUMBER_OF_PPIDS]; /* The first NUMBER_OF_PPIDS PPIDS which are present
+ * in the SCTP packet