Răsfoiți Sursa

totemsrp: Add magic and version into header

Magic number (0xC070) together with version in every packet
is used for detecting that other node is really
Corosync 3.x.

Endian_detector field is removed and magic number is now
used instead.

If received packet magic number differs, guessing is used to show more
about the source (Corosync 2.3+, 2.2 are quite reliable, Knet and
unencrypted Corosync 2.1/2.0/1.x/OpenAIS are semi-reliable and encrypted
Corosync 2.1/2.0/1.x/OpenAIS are quite unreliable).

Signed-off-by: Jan Friesse <jfriesse@redhat.com>
Reviewed-by: Christine Caulfield <ccaulfie@redhat.com>
Jan Friesse 8 ani în urmă
părinte
comite
0c509a25a7
2 a modificat fișierele cu 119 adăugiri și 21 ștergeri
  1. 110 20
      exec/totemsrp.c
  2. 9 1
      include/corosync/totem/totem.h

+ 110 - 20
exec/totemsrp.c

@@ -2340,13 +2340,14 @@ static void memb_state_recovery_enter (
 	// TODO	 LEAK
 		message_item.mcast = totemsrp_buffer_alloc (instance);
 		assert (message_item.mcast);
+		message_item.mcast->header.magic = TOTEM_MH_MAGIC;
+		message_item.mcast->header.version = TOTEM_MH_VERSION;
 		message_item.mcast->header.type = MESSAGE_TYPE_MCAST;
 		srp_addr_copy (&message_item.mcast->system_from, &instance->my_id);
 		message_item.mcast->header.encapsulated = MESSAGE_ENCAPSULATED;
 
 		message_item.mcast->header.nodeid = instance->my_id.nodeid;
 		assert (message_item.mcast->header.nodeid);
-		message_item.mcast->header.endian_detector = ENDIAN_LOCAL;
 		memcpy (&message_item.mcast->ring_id, &instance->my_ring_id,
 			sizeof (struct memb_ring_id));
 		message_item.msg_len = sort_queue_item->msg_len + sizeof (struct mcast);
@@ -2428,8 +2429,9 @@ int totemsrp_mcast (
 	 * Set mcast header
 	 */
 	memset(message_item.mcast, 0, sizeof (struct mcast));
+	message_item.mcast->header.magic = TOTEM_MH_MAGIC;
+	message_item.mcast->header.version = TOTEM_MH_VERSION;
 	message_item.mcast->header.type = MESSAGE_TYPE_MCAST;
-	message_item.mcast->header.endian_detector = ENDIAN_LOCAL;
 	message_item.mcast->header.encapsulated = MESSAGE_NOT_ENCAPSULATED;
 
 	message_item.mcast->header.nodeid = instance->my_id.nodeid;
@@ -2934,8 +2936,9 @@ static int token_hold_cancel_send (struct totemsrp_instance *instance)
 	/*
 	 * Build message
 	 */
+	token_hold_cancel.header.magic = TOTEM_MH_MAGIC;
+	token_hold_cancel.header.version = TOTEM_MH_VERSION;
 	token_hold_cancel.header.type = MESSAGE_TYPE_TOKEN_HOLD_CANCEL;
-	token_hold_cancel.header.endian_detector = ENDIAN_LOCAL;
 	token_hold_cancel.header.encapsulated = 0;
 	token_hold_cancel.header.nodeid = instance->my_id.nodeid;
 	memcpy (&token_hold_cancel.ring_id, &instance->my_ring_id,
@@ -2955,8 +2958,9 @@ static int orf_token_send_initial (struct totemsrp_instance *instance)
 	struct orf_token orf_token;
 	int res;
 
+	orf_token.header.magic = TOTEM_MH_MAGIC;
+	orf_token.header.version = TOTEM_MH_VERSION;
 	orf_token.header.type = MESSAGE_TYPE_ORF_TOKEN;
-	orf_token.header.endian_detector = ENDIAN_LOCAL;
 	orf_token.header.encapsulated = 0;
 	orf_token.header.nodeid = instance->my_id.nodeid;
 	assert (orf_token.header.nodeid);
@@ -3178,8 +3182,9 @@ static void memb_state_commit_token_create (
 		instance->my_failed_list, instance->my_failed_list_entries);
 
 	memset (instance->commit_token, 0, sizeof (struct memb_commit_token));
+	instance->commit_token->header.magic = TOTEM_MH_MAGIC;
+	instance->commit_token->header.version = TOTEM_MH_VERSION;
 	instance->commit_token->header.type = MESSAGE_TYPE_MEMB_COMMIT_TOKEN;
-	instance->commit_token->header.endian_detector = ENDIAN_LOCAL;
 	instance->commit_token->header.encapsulated = 0;
 	instance->commit_token->header.nodeid = instance->my_id.nodeid;
 	assert (instance->commit_token->header.nodeid);
@@ -3213,8 +3218,9 @@ static void memb_join_message_send (struct totemsrp_instance *instance)
 	char *addr;
 	unsigned int addr_idx;
 
+	memb_join->header.magic = TOTEM_MH_MAGIC;
+	memb_join->header.version = TOTEM_MH_VERSION;
 	memb_join->header.type = MESSAGE_TYPE_MEMB_JOIN;
-	memb_join->header.endian_detector = ENDIAN_LOCAL;
 	memb_join->header.encapsulated = 0;
 	memb_join->header.nodeid = instance->my_id.nodeid;
 	assert (memb_join->header.nodeid);
@@ -3283,8 +3289,9 @@ static void memb_leave_message_send (struct totemsrp_instance *instance)
 			   &instance->my_id, 1);
 
 
+	memb_join->header.magic = TOTEM_MH_MAGIC;
+	memb_join->header.version = TOTEM_MH_VERSION;
 	memb_join->header.type = MESSAGE_TYPE_MEMB_JOIN;
-	memb_join->header.endian_detector = ENDIAN_LOCAL;
 	memb_join->header.encapsulated = 0;
 	memb_join->header.nodeid = LEAVE_DUMMY_NODEID;
 
@@ -3332,8 +3339,9 @@ static void memb_merge_detect_transmit (struct totemsrp_instance *instance)
 {
 	struct memb_merge_detect memb_merge_detect;
 
+	memb_merge_detect.header.magic = TOTEM_MH_MAGIC;
+	memb_merge_detect.header.version = TOTEM_MH_VERSION;
 	memb_merge_detect.header.type = MESSAGE_TYPE_MEMB_MERGE_DETECT;
-	memb_merge_detect.header.endian_detector = ENDIAN_LOCAL;
 	memb_merge_detect.header.encapsulated = 0;
 	memb_merge_detect.header.nodeid = instance->my_id.nodeid;
 	srp_addr_copy (&memb_merge_detect.system_from, &instance->my_id);
@@ -3912,7 +3920,7 @@ static void messages_deliver_to_app (
 		assert (mcast_in != (struct mcast *)0xdeadbeef);
 
 		endian_conversion_required = 0;
-		if (mcast_in->header.endian_detector != ENDIAN_LOCAL) {
+		if (mcast_in->header.magic != TOTEM_MH_MAGIC) {
 			endian_conversion_required = 1;
 			mcast_endian_convert (mcast_in, &mcast_header);
 		} else {
@@ -4285,8 +4293,9 @@ static void memb_join_endian_convert (const struct memb_join *in, struct memb_jo
 	struct srp_addr *out_proc_list;
 	struct srp_addr *out_failed_list;
 
+	out->header.magic = TOTEM_MH_MAGIC;
+	out->header.version = TOTEM_MH_VERSION;
 	out->header.type = in->header.type;
-	out->header.endian_detector = ENDIAN_LOCAL;
 	out->header.nodeid = swab32 (in->header.nodeid);
 	srp_addr_copy_endian_convert (&out->system_from, &in->system_from);
 	out->proc_list_entries = swab32 (in->proc_list_entries);
@@ -4314,8 +4323,9 @@ static void memb_commit_token_endian_convert (const struct memb_commit_token *in
 	struct memb_commit_token_memb_entry *in_memb_list;
 	struct memb_commit_token_memb_entry *out_memb_list;
 
+	out->header.magic = TOTEM_MH_MAGIC;
+	out->header.version = TOTEM_MH_VERSION;
 	out->header.type = in->header.type;
-	out->header.endian_detector = ENDIAN_LOCAL;
 	out->header.nodeid = swab32 (in->header.nodeid);
 	out->token_seq = swab32 (in->token_seq);
 	out->ring_id.rep = swab32(in->ring_id.rep);
@@ -4348,8 +4358,9 @@ static void orf_token_endian_convert (const struct orf_token *in, struct orf_tok
 {
 	int i;
 
+	out->header.magic = TOTEM_MH_MAGIC;
+	out->header.version = TOTEM_MH_VERSION;
 	out->header.type = in->header.type;
-	out->header.endian_detector = ENDIAN_LOCAL;
 	out->header.nodeid = swab32 (in->header.nodeid);
 	out->seq = swab32 (in->seq);
 	out->token_seq = swab32 (in->token_seq);
@@ -4370,8 +4381,9 @@ static void orf_token_endian_convert (const struct orf_token *in, struct orf_tok
 
 static void mcast_endian_convert (const struct mcast *in, struct mcast *out)
 {
+	out->header.magic = TOTEM_MH_MAGIC;
+	out->header.version = TOTEM_MH_VERSION;
 	out->header.type = in->header.type;
-	out->header.endian_detector = ENDIAN_LOCAL;
 	out->header.nodeid = swab32 (in->header.nodeid);
 	out->header.encapsulated = in->header.encapsulated;
 
@@ -4388,8 +4400,9 @@ static void memb_merge_detect_endian_convert (
 	const struct memb_merge_detect *in,
 	struct memb_merge_detect *out)
 {
+	out->header.magic = TOTEM_MH_MAGIC;
+	out->header.version = TOTEM_MH_VERSION;
 	out->header.type = in->header.type;
-	out->header.endian_detector = ENDIAN_LOCAL;
 	out->header.nodeid = swab32 (in->header.nodeid);
 	out->ring_id.rep = swab32(in->ring_id.rep);
 	out->ring_id.seq = swab64 (in->ring_id.seq);
@@ -4601,21 +4614,96 @@ static int message_handler_token_hold_cancel (
 	return (0);
 }
 
-void main_deliver_fn (
+static int check_message_header_validity(
 	void *context,
 	const void *msg,
 	unsigned int msg_len)
 {
 	struct totemsrp_instance *instance = context;
 	const struct totem_message_header *message_header = msg;
+	const char *guessed_str;
+	const char *msg_byte = msg;
 
 	if (msg_len < sizeof (struct totem_message_header)) {
 		log_printf (instance->totemsrp_log_level_security,
-			    "Received message is too short...  ignoring %u.",
+			    "Received message is too short...  Ignoring %u.",
 			    (unsigned int)msg_len);
-		return;
+		return (-1);
+	}
+
+	if (message_header->magic != TOTEM_MH_MAGIC &&
+	    message_header->magic != swab16(TOTEM_MH_MAGIC)) {
+		/*
+		 * We've received ether Knet, old version of Corosync,
+		 * or something else. Do some guessing to display (hopefully)
+		 * helpful message
+		 */
+		guessed_str = NULL;
+
+		if (message_header->magic == 0xFFFF) {
+			/*
+			 * Corosync 2.2 used header with two UINT8_MAX
+			 */
+			guessed_str = "Corosync 2.2";
+		} else if (message_header->magic == 0xFEFE) {
+			/*
+			 * Corosync 2.3+ used header with two UINT8_MAX - 1
+			 */
+			guessed_str = "Corosync 2.3+";
+		} else if (msg_byte[0] == 0x01) {
+			/*
+			 * Knet has stable1 with first byte of message == 1
+			 */
+			guessed_str = "unencrypted Kronosnet";
+		} else if (msg_byte[0] >= 0 && msg_byte[0] <= 5) {
+			/*
+			 * Unencrypted Corosync 1.x/OpenAIS has first byte
+			 * 0-5. Collision with Knet (but still worth the try)
+			 */
+			guessed_str = "unencrypted Corosync 2.0/2.1/1.x/OpenAIS";
+		} else {
+			/*
+			 * Encrypted Kronosned packet has a hash at the end of
+			 * the packet and nothing specific at the beginning of the
+			 * packet (just encrypted data).
+			 * Encrypted Corosync 1.x/OpenAIS is quite similar but hash_digest
+			 * is in the beginning of the packet.
+			 *
+			 * So it's not possible to reliably detect ether of them.
+			 */
+			guessed_str = "encrypted Kronosnet/Corosync 2.0/2.1/1.x/OpenAIS or unknown";
+		}
+
+		log_printf(instance->totemsrp_log_level_security,
+		    "Received message with bad magic number (probably sent by %s).. Ignoring",
+		    guessed_str);
+
+		return (-1);
 	}
 
+	if (message_header->version != TOTEM_MH_VERSION) {
+		log_printf(instance->totemsrp_log_level_security,
+		"Received message with unsupported version %u... Ignoring",
+		message_header->version);
+
+		return (-1);
+	}
+
+	return (0);
+}
+
+
+void main_deliver_fn (
+	void *context,
+	const void *msg,
+	unsigned int msg_len)
+{
+	struct totemsrp_instance *instance = context;
+	const struct totem_message_header *message_header = msg;
+
+	if (check_message_header_validity(context, msg, msg_len) == -1) {
+		return ;
+	}
 
 	switch (message_header->type) {
 	case MESSAGE_TYPE_ORF_TOKEN:
@@ -4637,8 +4725,10 @@ void main_deliver_fn (
 		instance->stats.token_hold_cancel_rx++;
 		break;
 	default:
-		log_printf (instance->totemsrp_log_level_security, "Type of received message is wrong...  ignoring %d.\n", (int)message_header->type);
-printf ("wrong message type\n");
+		log_printf (instance->totemsrp_log_level_security,
+		    "Type of received message is wrong...  ignoring %d.\n",
+		    (int)message_header->type);
+
 		instance->stats.rx_msg_dropped++;
 		return;
 	}
@@ -4649,7 +4739,7 @@ printf ("wrong message type\n");
 		instance,
 		msg,
 		msg_len,
-		message_header->endian_detector != ENDIAN_LOCAL);
+		message_header->magic != TOTEM_MH_MAGIC);
 }
 
 int totemsrp_iface_set (

+ 9 - 1
include/corosync/totem/totem.h

@@ -114,10 +114,18 @@ struct totem_logging_configuration {
 	int log_subsys_id;
 };
 
+
+/*
+ * COrosync TOtem. Also used as an endian_detector.
+ */
+#define TOTEM_MH_MAGIC		0xC070
+#define TOTEM_MH_VERSION	0x03
+
 struct totem_message_header {
+	unsigned short magic;
+	char version;
 	char type;
 	char encapsulated;
-	unsigned short endian_detector;
 	unsigned int nodeid;
 	unsigned int target_nodeid;
 } __attribute__((packed));