changeset 1219:8802d3fa5876

Got successful handshake over DTLS with this version
author Sebastien Decugis <sdecugis@freediameter.net>
date Tue, 18 Jun 2013 15:51:11 +0800
parents 876cb3e4d738
children 940713a4f296
files freeDiameterd/main.c include/freeDiameter/libfdproto.h libfdcore/p_cnx.c libfdcore/sctp_dtls.c
diffstat 4 files changed, 88 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/freeDiameterd/main.c	Tue Jun 18 12:46:14 2013 +0800
+++ b/freeDiameterd/main.c	Tue Jun 18 15:51:11 2013 +0800
@@ -51,7 +51,10 @@
 
 /* gnutls debug */
 static void fd_gnutls_debug(int level, const char * str) {
-	fd_log_debug(" [gnutls:%d] %s", level, str);
+	int len = strlen(str);
+	if (str[len-1] == '\n')
+		len--;
+	fd_log_debug(" [gnutls:%d] %.*s", level, len, str);
 }
 
 
--- a/include/freeDiameter/libfdproto.h	Tue Jun 18 12:46:14 2013 +0800
+++ b/include/freeDiameter/libfdproto.h	Tue Jun 18 15:51:11 2013 +0800
@@ -129,6 +129,7 @@
 /*                          DEBUG                             */
 /*============================================================*/
 
+#define LOGS_VALIGN
 
 /*
  * FUNCTION:	fd_log
@@ -296,7 +297,11 @@
 
 /* In DEBUG mode, we add meta-information along each trace. This makes multi-threading problems easier to debug. */
 #ifdef DEBUG
-# define STD_TRACE_FMT_STRING "pid:%s in %s@%s:%d: "
+# ifdef LOGS_VALIGN
+#  define STD_TRACE_FMT_STRING "pid:%-25.25s in %25.25s@%-15.15s:%-4d: "
+# else /* LOGS_VALIGN */
+#  define STD_TRACE_FMT_STRING "pid:%s in %s@%s:%d: "
+# endif /* LOGS_VALIGN */
 # define STD_TRACE_FMT_ARGS   , ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed"), __PRETTY_FUNCTION__, __STRIPPED_FILE__, __LINE__
 #else /* DEBUG */
 # define STD_TRACE_FMT_STRING ""
--- a/libfdcore/p_cnx.c	Tue Jun 18 12:46:14 2013 +0800
+++ b/libfdcore/p_cnx.c	Tue Jun 18 15:51:11 2013 +0800
@@ -291,7 +291,7 @@
 	/* Handshake if needed (secure port) */
 	if (nc->dotls) {
 		CHECK_FCT_DO( fd_cnx_handshake(cnx, GNUTLS_CLIENT, 
-						ALGO_HANDSHAKE_3436,
+						(peer->p_hdr.info.config.pic_flags.sctpsec == PI_SCTPSEC_3436) ? ALGO_HANDSHAKE_3436 : ALGO_HANDSHAKE_DEFAULT,
 						peer->p_hdr.info.config.pic_priority, NULL),
 			{
 				/* Handshake failed ...  */
--- a/libfdcore/sctp_dtls.c	Tue Jun 18 12:46:14 2013 +0800
+++ b/libfdcore/sctp_dtls.c	Tue Jun 18 15:51:11 2013 +0800
@@ -143,7 +143,7 @@
 	switch (event) {
 		case FDEVP_CNX_MSG_RECV:
 			got_data = 1;
-			LOG_A("Received DTLS data, type %02hhx, Seq %02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx, Stream %hu",
+			LOG_A("Received DTLS data, type %hhd, Seq %02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx, Stream %hu",
 				(*buf)[0],
 				(*buf)[3],(*buf)[4],(*buf)[5],(*buf)[6], (*buf)[7],(*buf)[8],(*buf)[9],(*buf)[10],
 				*strid);
@@ -166,6 +166,63 @@
 	return got_data;
 }
 
+/* Count the number of records received in a chunk (including partial) and increment the nextseq field accordingly */
+static void update_nextseq_from_records(struct cnxctx * conn, uint8_t * buf, size_t len)
+{
+	size_t offset = 0;
+	uint16_t next_record_len;
+	int i;
+	
+	
+	while (offset + 13 <= len) {
+		next_record_len = (buf[offset+11] << 8) + buf[offset+12];
+		LOG_A("update_nextseq_from_records off:%zd Type %hhd, Ver:%02hhx.%02hhx, Seq:%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
+			offset,
+			buf[offset], buf[offset+1], buf[offset+2], 
+			buf[offset+3],buf[offset+4],buf[offset+5],buf[offset+6],buf[offset+7],buf[offset+8],buf[offset+9],buf[offset+10]
+			);
+		
+		if (memcmp(buf + offset + DTLS_SEQ_OFFSET, conn->cc_sctp_dtls_data.nextseq, 8) != 0) {
+			/* The next record is not the one we expect in sequence. Is it a new epoch ? */
+			uint8_t newepoch[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+			if (conn->cc_sctp_dtls_data.nextseq[1] != 0xFF) {
+				newepoch[0] = conn->cc_sctp_dtls_data.nextseq[0]; newepoch[1] = conn->cc_sctp_dtls_data.nextseq[1] + 1;
+			} else if (conn->cc_sctp_dtls_data.nextseq[0] != 0xFF) {
+				newepoch[0] =conn->cc_sctp_dtls_data.nextseq[0] + 1; newepoch[1] = 0;
+			} else {
+				LOG_F("Epoch field wrapped, can this happen ???");
+				ASSERT(0); TODO("FFS");
+			}
+			
+			if (memcmp(buf + offset + DTLS_SEQ_OFFSET, newepoch, 8) == 0) {
+				/* Yes, this is a new epoch record, store this as next seq and continue */
+				memcpy(conn->cc_sctp_dtls_data.nextseq, newepoch, 8);
+			} else {
+				LOG_E("buf seq: %02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", buf[offset +3], buf[offset +4], buf[offset +5], buf[offset +6], buf[offset +7], buf[offset +8], buf[offset +9], buf[offset +10]);
+				LOG_E("nextseq: %02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", conn->cc_sctp_dtls_data.nextseq[0], conn->cc_sctp_dtls_data.nextseq[1], conn->cc_sctp_dtls_data.nextseq[2], conn->cc_sctp_dtls_data.nextseq[3], conn->cc_sctp_dtls_data.nextseq[4], conn->cc_sctp_dtls_data.nextseq[5], conn->cc_sctp_dtls_data.nextseq[6], conn->cc_sctp_dtls_data.nextseq[7]);
+				TODO("This should not be happening...");
+				ASSERT(0);
+			}
+		}
+		
+		/* increment seq number */
+		for (i = 7; i>=3; i--) {
+			if (conn->cc_sctp_dtls_data.nextseq[i] == 0xFF) {
+				conn->cc_sctp_dtls_data.nextseq[i] = 0;
+			} else {
+				conn->cc_sctp_dtls_data.nextseq[i] ++;
+				break;
+			}
+		}
+		if (i==2) {
+			LOG_F("Sequence_number field wrapped, can this happen ???");
+			ASSERT(0); TODO("FFS");
+		}
+		
+		offset += (size_t)next_record_len + 13;
+	}
+}
+
 /***************************************************************************************************/
 /* Helper functions to reorder the received chunks by sequence number                              */
 /***************************************************************************************************/
@@ -230,7 +287,7 @@
 static size_t chunk_retrieve(struct cnxctx * conn, void * upperbuf, size_t upperlen, int probeonly) 
 {
 	struct chunk * next;
-	int cmp,i;
+	int cmp;
 	size_t ret = 0;
 redo:	
 	if (FD_IS_LIST_EMPTY(&conn->cc_sctp_dtls_data.chunks)) {
@@ -263,7 +320,7 @@
 	cmp = memcmp(next->seq, conn->cc_sctp_dtls_data.nextseq, 8);
 	if (cmp < 0) {
 		cmp = memcmp(next->seq, conn->cc_sctp_dtls_data.validseq, 8);
-		if (cmp <= 0) {
+		if (cmp < 0) {
 			/* This is old stuff or invalid stuff, discard */
 			LOG_E("Unqueued DTLS packet with old sequence number, discarding.");
 			free(next->buffer);
@@ -271,9 +328,10 @@
 			free(next);
 			goto redo;
 		}
-		/* If the first chunk in our list has a smaller seq number than what we already delivered, we pass it above (to prevent DoS) */
-		LOG_A("Unqueueing chunk with seq number %02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", 
-			next->seq[0],next->seq[1],next->seq[2],next->seq[3],next->seq[4],next->seq[5],next->seq[6],next->seq[7]);
+		/* If the first chunk in our list has a smaller seq number than what we already delivered, we pass it above (to prevent possible DoS by sending forged sequence numbers) */
+		if (probeonly)
+			return 1;
+		
 		ret = next->len;
 		if (upperlen < ret) {
 			ret = upperlen;
@@ -285,6 +343,8 @@
 			fd_list_unlink(&next->chain);
 			free(next);
 		}
+		LOG_A("Unqueueing (old) chunk with seq number %02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", 
+			next->seq[0],next->seq[1],next->seq[2],next->seq[3],next->seq[4],next->seq[5],next->seq[6],next->seq[7]);
 		return ret;
 	}
 	if (cmp > 0) {
@@ -301,10 +361,12 @@
 		
 		if (memcmp(newepoch, next->seq, 8) == 0) {
 			/* Bingo, this is the first message of the new epoch. We update our nextseq accordingly */
+			if (probeonly)
+				return 1;
 			memcpy(conn->cc_sctp_dtls_data.nextseq, newepoch, 8);
-			conn->cc_sctp_dtls_data.nextseq[7] = 1;
+			update_nextseq_from_records(conn, next->buffer, next->len);
 			
-			LOG_A("Unqueueing chunk with seq number %02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", 
+			LOG_A("Unqueueing chunk with seq number %02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx (epoch change)", 
 				next->seq[0],next->seq[1],next->seq[2],next->seq[3],next->seq[4],next->seq[5],next->seq[6],next->seq[7]);
 			ret = next->len;
 			if (upperlen < ret) {
@@ -325,23 +387,15 @@
 	}
 	
 	/* next is the next chunk expected on this connection */
+	if (probeonly)
+		return 1;
 	
-	/* We increment the next seq */
-	for (i = 7; i>=3; i--) {
-		if (conn->cc_sctp_dtls_data.nextseq[i] == 0xFF) {
-			conn->cc_sctp_dtls_data.nextseq[i] = 0;
-		} else {
-			conn->cc_sctp_dtls_data.nextseq[i] ++;
-			break;
-		}
-	}
-	if (i==2) {
-		LOG_F("Sequence_number field wrapped, can this happen ???");
-		ASSERT(0); TODO("FFS");
-	}
+	/* We increment the next seq by the number or records found in this chunk */
+	update_nextseq_from_records(conn, next->buffer, next->len);
 	
 	/* And we deliver this to upper layer */
-	LOG_A("Unqueueing chunk with seq number %02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", 
+	LOG_A("Unqueueing chunk: Type %hhd, Ver:%02hhx.%02hhx, Seq:%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", 
+		next->buffer[0], next->buffer[1], next->buffer[2], 
 		next->seq[0],next->seq[1],next->seq[2],next->seq[3],next->seq[4],next->seq[5],next->seq[6],next->seq[7]);
 	ret = next->len;
 	if (upperlen < ret) {
@@ -444,7 +498,7 @@
 	}
 	
 	if ((iovcnt > 0) && (iov->iov_len > 10)) {
-		LOG_A("Sending DTLS data, type %02hhx, Seq %02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx, Stream %hu",
+		LOG_A("Sending DTLS data, type %hhd, Seq %02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx, Stream %hu",
 			((uint8_t *)iov->iov_base)[0],
 			((uint8_t *)iov->iov_base)[3],((uint8_t *)iov->iov_base)[4],((uint8_t *)iov->iov_base)[5],((uint8_t *)iov->iov_base)[6],
 			((uint8_t *)iov->iov_base)[7],((uint8_t *)iov->iov_base)[8],((uint8_t *)iov->iov_base)[9],((uint8_t *)iov->iov_base)[10],
"Welcome to our mercurial repository"