[asterisk-commits] trunk r26920 - in /trunk: include/asterisk/rtp.h rtp.c

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Thu May 11 07:56:53 MST 2006


Author: markster
Date: Thu May 11 09:56:52 2006
New Revision: 26920

URL: http://svn.digium.com/view/asterisk?rev=26920&view=rev
Log:
Go ahead and merge STUN mods for RTP in preparation for some STUN 
support in SIP.

Modified:
    trunk/include/asterisk/rtp.h
    trunk/rtp.c

Modified: trunk/include/asterisk/rtp.h
URL: http://svn.digium.com/view/asterisk/trunk/include/asterisk/rtp.h?rev=26920&r1=26919&r2=26920&view=diff
==============================================================================
--- trunk/include/asterisk/rtp.h (original)
+++ trunk/include/asterisk/rtp.h Thu May 11 09:56:52 2006
@@ -106,6 +106,8 @@
 
 void ast_rtp_reset(struct ast_rtp *rtp);
 
+void ast_rtp_stun_request(struct ast_rtp *rtp, struct sockaddr_in *suggestion, const char *username);
+
 void ast_rtp_set_callback(struct ast_rtp *rtp, ast_rtp_callback callback);
 
 void ast_rtp_set_data(struct ast_rtp *rtp, void *data);

Modified: trunk/rtp.c
URL: http://svn.digium.com/view/asterisk/trunk/rtp.c?rev=26920&r1=26919&r2=26920&view=diff
==============================================================================
--- trunk/rtp.c (original)
+++ trunk/rtp.c Thu May 11 09:56:52 2006
@@ -68,6 +68,7 @@
 static int rtpstart = 0;		/*!< First port for RTP sessions (set in rtp.conf) */
 static int rtpend = 0;			/*!< Last port for RTP sessions (set in rtp.conf) */
 static int rtpdebug = 0;		/*!< Are we debugging? */
+static int stundebug = 0;		/*!< Are we debugging stun? */
 static struct sockaddr_in rtpdebugaddr;	/*!< Debug packets to/from this host */
 #ifdef SO_NO_CHECK
 static int nochecksums = 0;
@@ -143,6 +144,260 @@
 	struct sockaddr_in them;	/*!< Socket representation of the remote endpoint. */
 };
 
+
+typedef struct { unsigned int id[4]; } __attribute__((packed)) stun_trans_id;
+
+/* XXX Maybe stun belongs in another file if it ever has use outside of RTP */
+struct stun_header {
+	unsigned short msgtype;
+	unsigned short msglen;
+	stun_trans_id  id;
+	unsigned char ies[0];
+} __attribute__((packed));
+
+struct stun_attr {
+	unsigned short attr;
+	unsigned short len;
+	unsigned char value[0];
+} __attribute__((packed));
+
+struct stun_addr {
+	unsigned char unused;
+	unsigned char family;
+	unsigned short port;
+	unsigned int addr;
+} __attribute__((packed));
+
+#define STUN_IGNORE		(0)
+#define STUN_ACCEPT		(1)
+
+#define STUN_BINDREQ	0x0001
+#define STUN_BINDRESP	0x0101
+#define STUN_BINDERR	0x0111
+#define STUN_SECREQ		0x0002
+#define STUN_SECRESP	0x0102
+#define STUN_SECERR		0x0112
+
+#define STUN_MAPPED_ADDRESS		0x0001
+#define STUN_RESPONSE_ADDRESS	0x0002
+#define STUN_CHANGE_REQUEST		0x0003
+#define STUN_SOURCE_ADDRESS		0x0004
+#define STUN_CHANGED_ADDRESS	0x0005
+#define STUN_USERNAME			0x0006
+#define STUN_PASSWORD			0x0007
+#define STUN_MESSAGE_INTEGRITY	0x0008
+#define STUN_ERROR_CODE			0x0009
+#define STUN_UNKNOWN_ATTRIBUTES	0x000a
+#define STUN_REFLECTED_FROM		0x000b
+
+static const char *stun_msg2str(int msg)
+{
+	switch(msg) {
+	case STUN_BINDREQ:
+		return "Binding Request";
+	case STUN_BINDRESP:
+		return "Binding Response";
+	case STUN_BINDERR:
+		return "Binding Error Response";
+	case STUN_SECREQ:
+		return "Shared Secret Request";
+	case STUN_SECRESP:
+		return "Shared Secret Response";
+	case STUN_SECERR:
+		return "Shared Secret Error Response";
+	}
+	return "Non-RFC3489 Message";
+}
+
+static const char *stun_attr2str(int msg)
+{
+	switch(msg) {
+	case STUN_MAPPED_ADDRESS:
+		return "Mapped Address";
+	case STUN_RESPONSE_ADDRESS:
+		return "Response Address";
+	case STUN_CHANGE_REQUEST:
+		return "Change Request";
+	case STUN_SOURCE_ADDRESS:
+		return "Source Address";
+	case STUN_CHANGED_ADDRESS:
+		return "Changed Address";
+	case STUN_USERNAME:
+		return "Username";
+	case STUN_PASSWORD:
+		return "Password";
+	case STUN_MESSAGE_INTEGRITY:
+		return "Message Integrity";
+	case STUN_ERROR_CODE:
+		return "Error Code";
+	case STUN_UNKNOWN_ATTRIBUTES:
+		return "Unknown Attributes";
+	case STUN_REFLECTED_FROM:
+		return "Reflected From";
+	}
+	return "Non-RFC3489 Attribute";
+}
+
+struct stun_state {
+	unsigned char *username;
+	unsigned char *password;
+};
+
+static int stun_process_attr(struct stun_state *state, struct stun_attr *attr)
+{
+	if (stundebug)
+		ast_verbose("Found STUN Attribute %s (%04x), length %d\n",
+			stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len));
+	switch(ntohs(attr->attr)) {
+	case STUN_USERNAME:
+		state->username = (unsigned char *)(attr->value);
+		break;
+	case STUN_PASSWORD:
+		state->password = (unsigned char *)(attr->value);
+		break;
+	default:
+		if (stundebug)
+			ast_verbose("Ignoring STUN attribute %s (%04x), length %d\n", 
+				stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len));
+	}
+	return 0;
+}
+
+static void append_attr_string(struct stun_attr **attr, int attrval, const char *s, int *len, int *left)
+{
+	int size = sizeof(**attr) + strlen(s);
+	if (*left > size) {
+		(*attr)->attr = htons(attrval);
+		(*attr)->len = htons(strlen(s));
+		memcpy((*attr)->value, s, strlen(s));
+		(*attr) = (struct stun_attr *)((*attr)->value + strlen(s));
+		*len += size;
+		*left -= size;
+	}
+}
+
+static void append_attr_address(struct stun_attr **attr, int attrval, struct sockaddr_in *sin, int *len, int *left)
+{
+	int size = sizeof(**attr) + 8;
+	struct stun_addr *addr;
+	if (*left > size) {
+		(*attr)->attr = htons(attrval);
+		(*attr)->len = htons(8);
+		addr = (struct stun_addr *)((*attr)->value);
+		addr->unused = 0;
+		addr->family = 0x01;
+		addr->port = sin->sin_port;
+		addr->addr = sin->sin_addr.s_addr;
+		(*attr) = (struct stun_attr *)((*attr)->value + 8);
+		*len += size;
+		*left -= size;
+	}
+}
+
+static int stun_send(int s, struct sockaddr_in *dst, struct stun_header *resp)
+{
+	return sendto(s, resp, ntohs(resp->msglen) + sizeof(*resp), 0, dst, sizeof(*dst));
+}
+
+static void stun_req_id(struct stun_header *req)
+{
+	int x;
+	for (x=0;x<4;x++)
+		req->id.id[x] = ast_random();
+}
+
+void ast_rtp_stun_request(struct ast_rtp *rtp, struct sockaddr_in *suggestion, const char *username)
+{
+	struct stun_header *req;
+	unsigned char reqdata[1024];
+	int reqlen, reqleft;
+	struct stun_attr *attr;
+
+	req = (struct stun_header *)reqdata;
+	stun_req_id(req);
+	reqlen = 0;
+	reqleft = sizeof(reqdata) - sizeof(struct stun_header);
+	req->msgtype = 0;
+	req->msglen = 0;
+	attr = (struct stun_attr *)req->ies;
+	if (username)
+		append_attr_string(&attr, STUN_USERNAME, username, &reqlen, &reqleft);
+	req->msglen = htons(reqlen);
+	req->msgtype = htons(STUN_BINDREQ);
+	stun_send(rtp->s, suggestion, req);
+}
+
+static int stun_handle_packet(int s, struct sockaddr_in *src, unsigned char *data, int len)
+{
+	struct stun_header *resp, *hdr = (struct stun_header *)data;
+	struct stun_attr *attr;
+	struct stun_state st;
+	int ret = STUN_IGNORE;	
+	unsigned char respdata[1024];
+	int resplen, respleft;
+	
+	if (len < sizeof(struct stun_header)) {
+		ast_log(LOG_DEBUG, "Runt STUN packet (only %d, wanting at least %d)\n", len, sizeof(struct stun_header));
+		return -1;
+	}
+	if (stundebug)
+		ast_verbose("STUN Packet, msg %s (%04x), length: %d\n", stun_msg2str(ntohs(hdr->msgtype)), ntohs(hdr->msgtype), ntohs(hdr->msglen));
+	if (ntohs(hdr->msglen) > len - sizeof(struct stun_header)) {
+		ast_log(LOG_DEBUG, "Scrambled STUN packet length (got %d, expecting %d)\n", ntohs(hdr->msglen), len - sizeof(struct stun_header));
+	} else
+		len = ntohs(hdr->msglen);
+	data += sizeof(struct stun_header);
+	memset(&st, 0, sizeof(st));
+	while(len) {
+		if (len < sizeof(struct stun_attr)) {
+			ast_log(LOG_DEBUG, "Runt Attribute (got %d, expecting %d)\n", len, sizeof(struct stun_attr));
+			break;
+		}
+		attr = (struct stun_attr *)data;
+		if (ntohs(attr->len) > len) {
+			ast_log(LOG_DEBUG, "Inconsistant Attribute (length %d exceeds remaining msg len %d)\n", ntohs(attr->len), len);
+			break;
+		}
+		if (stun_process_attr(&st, attr)) {
+			ast_log(LOG_DEBUG, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr));
+			break;
+		}
+		/* Clear attribute in case previous entry was a string */
+		attr->attr = 0;
+		data += ntohs(attr->len) + sizeof(struct stun_attr);
+		len -= ntohs(attr->len) + sizeof(struct stun_attr);
+	}
+	/* Null terminate any string */
+	*data = '\0';
+	resp = (struct stun_header *)respdata;
+	resplen = 0;
+	respleft = sizeof(respdata) - sizeof(struct stun_header);
+	resp->id = hdr->id;
+	resp->msgtype = 0;
+	resp->msglen = 0;
+	attr = (struct stun_attr *)resp->ies;
+	if (!len) {
+		switch(ntohs(hdr->msgtype)) {
+		case STUN_BINDREQ:
+			if (stundebug)
+				ast_verbose("STUN Bind Request, username: %s\n", 
+					st.username ? (const char *)st.username : "<none>");
+			if (st.username)
+				append_attr_string(&attr, STUN_USERNAME, st.username, &resplen, &respleft);
+			append_attr_address(&attr, STUN_MAPPED_ADDRESS, src, &resplen, &respleft);
+			resp->msglen = htons(resplen);
+			resp->msgtype = htons(STUN_BINDRESP);
+			stun_send(s, src, resp);
+			ret = STUN_ACCEPT;
+			break;
+		default:
+			if (stundebug)
+				ast_verbose("Dunno what to do with STUN message %04x (%s)\n", ntohs(hdr->msgtype), stun_msg2str(ntohs(hdr->msgtype)));
+		}
+	}
+	return ret;
+}
+
 /*! \brief List of current sessions */
 static AST_LIST_HEAD_STATIC(protos, ast_rtp_protocol);
 
@@ -442,7 +697,6 @@
 	res = recvfrom(rtp->s, rtp->rawdata + AST_FRIENDLY_OFFSET, sizeof(rtp->rawdata) - AST_FRIENDLY_OFFSET,
 					0, (struct sockaddr *)&sin, &len);
 
-
 	rtpheader = (unsigned int *)(rtp->rawdata + AST_FRIENDLY_OFFSET);
 	if (res < 0) {
 		if (errno != EAGAIN)
@@ -456,6 +710,21 @@
 		return &ast_null_frame;
 	}
 
+	/* Get fields */
+	seqno = ntohl(rtpheader[0]);
+
+	/* Check RTP version */
+	version = (seqno & 0xC0000000) >> 30;
+	if (!version) {
+		if ((stun_handle_packet(rtp->s, &sin, rtp->rawdata + AST_FRIENDLY_OFFSET, res) == STUN_ACCEPT) &&
+			(!rtp->them.sin_port && !rtp->them.sin_addr.s_addr)) {
+			memcpy(&rtp->them, &sin, sizeof(rtp->them));
+		}
+		return &ast_null_frame;
+	}
+
+	if (version != 2)
+		return &ast_null_frame;
 	/* Ignore if the other side hasn't been given an address
 	   yet.  */
 	if (!rtp->them.sin_addr.s_addr || !rtp->them.sin_port)
@@ -473,14 +742,6 @@
 		}
 	}
 
-	/* Get fields */
-	seqno = ntohl(rtpheader[0]);
-
-	/* Check RTP version */
-	version = (seqno & 0xC0000000) >> 30;
-	if (version != 2)
-		return &ast_null_frame;
-	
 	payloadtype = (seqno & 0x7f0000) >> 16;
 	padding = seqno & (1 << 29);
 	mark = seqno & (1 << 23);
@@ -1912,6 +2173,26 @@
 	return RESULT_SUCCESS;
 }
 
+static int stun_do_debug(int fd, int argc, char *argv[])
+{
+	if(argc != 2) {
+		return RESULT_SHOWUSAGE;
+	}
+	stundebug = 1;
+	ast_cli(fd, "STUN Debugging Enabled\n");
+	return RESULT_SUCCESS;
+}
+   
+static int stun_no_debug(int fd, int argc, char *argv[])
+{
+	if(argc !=3)
+		return RESULT_SHOWUSAGE;
+	stundebug = 0;
+	ast_cli(fd,"STUN Debugging Disabled\n");
+	return RESULT_SUCCESS;
+}
+
+
 static char debug_usage[] =
   "Usage: rtp debug [ip host[:port]]\n"
   "       Enable dumping of all RTP packets to and from host.\n";
@@ -1920,6 +2201,15 @@
   "Usage: rtp no debug\n"
   "       Disable all RTP debugging\n";
 
+static char stun_debug_usage[] =
+  "Usage: stun debug\n"
+  "       Enable STUN (Simple Traversal of UDP through NATs) debugging\n";
+
+static char stun_no_debug_usage[] =
+  "Usage: stun no debug\n"
+  "       Disable STUN debugging\n";
+
+
 static struct ast_cli_entry  cli_debug_ip =
 {{ "rtp", "debug", "ip", NULL } , rtp_do_debug, "Enable RTP debugging on IP", debug_usage };
 
@@ -1928,6 +2218,12 @@
 
 static struct ast_cli_entry  cli_no_debug =
 {{ "rtp", "no", "debug", NULL } , rtp_no_debug, "Disable RTP debugging", no_debug_usage };
+
+static struct ast_cli_entry  cli_stun_debug =
+{{ "stun", "debug", NULL } , stun_do_debug, "Enable STUN debugging", stun_debug_usage };
+
+static struct ast_cli_entry  cli_stun_no_debug =
+{{ "stun", "no", "debug", NULL } , stun_no_debug, "Disable STUN debugging", stun_no_debug_usage };
 
 int ast_rtp_reload(void)
 {
@@ -1990,5 +2286,7 @@
 	ast_cli_register(&cli_debug);
 	ast_cli_register(&cli_debug_ip);
 	ast_cli_register(&cli_no_debug);
+	ast_cli_register(&cli_stun_debug);
+	ast_cli_register(&cli_stun_no_debug);
 	ast_rtp_reload();
 }



More information about the asterisk-commits mailing list