[svn-commits] twilson: trunk r264626 - in /trunk: ./ channels/ channels/sip/include/ configs/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu May 20 12:54:06 CDT 2010


Author: twilson
Date: Thu May 20 12:54:02 2010
New Revision: 264626

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=264626
Log:
Add support for direct media ACLs

directmediapermit/directmediadeny support to restrict which peers can do
directmedia based on ip address. In some networks not all phones are fully
routed, i.e. not all phones can ping each other. This patch adds a way to
restrict directmedia for certain peers between certain networks.

(closes issue #16645)
Reported by: raarts
Patches: 
      directmediapermit.patch uploaded by raarts (license 937)
Tested by: raarts

Review: https://reviewboard.asterisk.org/r/467/

Modified:
    trunk/CHANGES
    trunk/channels/chan_sip.c
    trunk/channels/sip/include/sip.h
    trunk/configs/sip.conf.sample

Modified: trunk/CHANGES
URL: http://svnview.digium.com/svn/asterisk/trunk/CHANGES?view=diff&rev=264626&r1=264625&r2=264626
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Thu May 20 12:54:02 2010
@@ -59,6 +59,8 @@
  * When dialing SIP peers, a new component may be added to the end of the dialstring
    to indicate that a specific remote IP address or host should be used when dialing
    the particular peer. The dialstring format is SIP/peer/exten/host_or_IP.
+ * Added directmediapermit/directmediadeny to limit which peers can send direct media
+   to each other
 
 IAX2 Changes
 -----------

Modified: trunk/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_sip.c?view=diff&rev=264626&r1=264625&r2=264626
==============================================================================
--- trunk/channels/chan_sip.c (original)
+++ trunk/channels/chan_sip.c Thu May 20 12:54:02 2010
@@ -4191,6 +4191,7 @@
 	
 	register_peer_exten(peer, FALSE);
 	ast_free_ha(peer->ha);
+	ast_free_ha(peer->directmediaha);
 	if (peer->selfdestruct)
 		ast_atomic_fetchadd_int(&apeerobjs, -1);
 	else if (peer->is_realtime) {
@@ -4797,6 +4798,7 @@
 		dialog->noncodeccapability |= AST_RTP_DTMF;
 	else
 		dialog->noncodeccapability &= ~AST_RTP_DTMF;
+	dialog->directmediaha = ast_duplicate_ha_list(peer->directmediaha);
 	if (peer->call_limit)
 		ast_set_flag(&dialog->flags[0], SIP_CALL_LIMIT);
 	if (!dialog->portinuri)
@@ -5193,6 +5195,11 @@
 	if (p->chanvars) {
 		ast_variables_destroy(p->chanvars);
 		p->chanvars = NULL;
+	}
+
+	if (p->directmediaha) {
+		ast_free_ha(p->directmediaha);
+		p->directmediaha = NULL;
 	}
 
 	ast_string_field_free_memory(p);
@@ -15468,6 +15475,7 @@
 		ast_cli(fd, "  Insecure     : %s\n", insecure2str(ast_test_flag(&peer->flags[0], SIP_INSECURE)));
 		ast_cli(fd, "  Force rport  : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT)));
 		ast_cli(fd, "  ACL          : %s\n", AST_CLI_YESNO(peer->ha != NULL));
+		ast_cli(fd, "  DirectMedACL : %s\n", AST_CLI_YESNO(peer->directmediaha != NULL));
 		ast_cli(fd, "  T.38 support : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT)));
 		ast_cli(fd, "  T.38 EC mode : %s\n", faxec2str(ast_test_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT)));
 		ast_cli(fd, "  T.38 MaxDtgrm: %d\n", peer->t38_maxdatagram);
@@ -24841,6 +24849,7 @@
 {
 	struct sip_peer *peer = NULL;
 	struct ast_ha *oldha = NULL;
+	struct ast_ha *olddirectmediaha = NULL;
 	int found = 0;
 	int firstpass = 1;
 	uint16_t port = 0;
@@ -24897,6 +24906,8 @@
 		peer->lastmsgssent = -1;
 		oldha = peer->ha;
 		peer->ha = NULL;
+		olddirectmediaha = peer->directmediaha;
+		peer->directmediaha = NULL;
 		set_peer_defaults(peer);	/* Set peer defaults */
 		peer->type = 0;
 	}
@@ -25057,6 +25068,12 @@
 				}
 				if (ha_error) {
 					ast_log(LOG_ERROR, "Bad ACL entry in configuration line %d : %s\n", v->lineno, v->value);
+				}
+			} else if (!strcasecmp(v->name, "directmediapermit") || !strcasecmp(v->name, "directmediadeny")) {
+				int ha_error = 0;
+				peer->directmediaha = ast_append_ha(v->name + 11, v->value, peer->directmediaha, &ha_error);
+				if (ha_error) {
+					ast_log(LOG_ERROR, "Bad directmedia ACL entry in configuration line %d : %s\n", v->lineno, v->value);
 				}
 			} else if (!strcasecmp(v->name, "port")) {
 				peer->portinuri = 1;
@@ -25412,6 +25429,7 @@
 	peer->the_mark = 0;
 
 	ast_free_ha(oldha);
+	ast_free_ha(olddirectmediaha);
 	if (!ast_strlen_zero(callback)) { /* build string from peer info */
 		char *reg_string;
 		if (asprintf(&reg_string, "%s?%s:%s@%s/%s", peer->name, peer->username, !ast_strlen_zero(peer->remotesecret) ? peer->remotesecret : peer->secret, peer->tohost, callback) < 0) {
@@ -26406,8 +26424,18 @@
 		return NULL;
 	
 	sip_pvt_lock(p);
-	if (p->udptl && ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA))
-		udptl = p->udptl;
+	if (p->udptl && ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA)) {
+		struct sockaddr_in them;
+		struct sockaddr_in us;
+
+		ast_rtp_instance_get_remote_address(p->rtp, &them);
+		ast_rtp_instance_get_local_address(p->rtp, &us);
+		if (!ast_apply_ha(p->directmediaha, &them)) {
+			ast_debug(3, "Reinvite UDPTL T.38 data to %s denied by directmedia ACL on %s\n", ast_inet_ntoa(them.sin_addr), ast_inet_ntoa(us.sin_addr));
+		} else {
+			udptl = p->udptl;
+		}
+	}
 	sip_pvt_unlock(p);
 	return udptl;
 }
@@ -26441,31 +26469,42 @@
 
 static enum ast_rtp_glue_result sip_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
 {
-        struct sip_pvt *p = NULL;
-        enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_LOCAL;
-
-        if (!(p = chan->tech_pvt)) {
-                return AST_RTP_GLUE_RESULT_FORBID;
-	}
-
-        sip_pvt_lock(p);
-        if (!(p->rtp)) {
-                sip_pvt_unlock(p);
-                return AST_RTP_GLUE_RESULT_FORBID;
-        }
+	struct sip_pvt *p = NULL;
+	enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_LOCAL;
+
+	if (!(p = chan->tech_pvt)) {
+		return AST_RTP_GLUE_RESULT_FORBID;
+	}
+
+	sip_pvt_lock(p);
+	if (!(p->rtp)) {
+		sip_pvt_unlock(p);
+		return AST_RTP_GLUE_RESULT_FORBID;
+	}
 
 	ao2_ref(p->rtp, +1);
 	*instance = p->rtp;
 
-	if (ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA | SIP_DIRECT_MEDIA_NAT)) {
-                res = AST_RTP_GLUE_RESULT_REMOTE;
+	if (ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA)) {
+		struct sockaddr_in them;
+		struct sockaddr_in us;
+
+		res = AST_RTP_GLUE_RESULT_REMOTE;
+		ast_rtp_instance_get_remote_address(p->rtp, &them);
+		ast_rtp_instance_get_local_address(p->rtp, &us);
+		if (!ast_apply_ha(p->directmediaha, &them)) {
+			ast_debug(3, "Reinvite audio to %s denied by directmedia ACL on %s\n", ast_inet_ntoa(them.sin_addr), ast_inet_ntoa(us.sin_addr));
+			res = AST_RTP_GLUE_RESULT_FORBID;
+		}
+	} else if (ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA_NAT)) {
+		res = AST_RTP_GLUE_RESULT_REMOTE;
 	} else if (ast_test_flag(&global_jbconf, AST_JB_FORCED)) {
-                res = AST_RTP_GLUE_RESULT_FORBID;
-	}
-
-        sip_pvt_unlock(p);
-
-        return res;
+		res = AST_RTP_GLUE_RESULT_FORBID;
+	}
+
+	sip_pvt_unlock(p);
+
+	return res;
 }
 
 static enum ast_rtp_glue_result sip_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
@@ -26487,7 +26526,16 @@
 	*instance = p->vrtp;
 
 	if (ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA)) {
+		struct sockaddr_in them;
+		struct sockaddr_in us;
+
 		res = AST_RTP_GLUE_RESULT_REMOTE;
+		ast_rtp_instance_get_remote_address(p->rtp, &them);
+		ast_rtp_instance_get_local_address(p->rtp, &us);
+		if (!ast_apply_ha(p->directmediaha, &them)) {
+			ast_debug(3, "Reinvite video to %s denied by directmedia ACL on %s\n", ast_inet_ntoa(them.sin_addr), ast_inet_ntoa(us.sin_addr));
+			res = AST_RTP_GLUE_RESULT_FORBID;
+		}
 	}
 
 	sip_pvt_unlock(p);
@@ -26497,105 +26545,114 @@
 
 static enum ast_rtp_glue_result sip_get_trtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
 {
-        struct sip_pvt *p = NULL;
-        enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_FORBID;
-
-        if (!(p = chan->tech_pvt)) {
-                return AST_RTP_GLUE_RESULT_FORBID;
-        }
-
-        sip_pvt_lock(p);
-        if (!(p->trtp)) {
-                sip_pvt_unlock(p);
-                return AST_RTP_GLUE_RESULT_FORBID;
-        }
+	struct sip_pvt *p = NULL;
+	enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_FORBID;
+
+	if (!(p = chan->tech_pvt)) {
+		return AST_RTP_GLUE_RESULT_FORBID;
+	}
+
+	sip_pvt_lock(p);
+	if (!(p->trtp)) {
+		sip_pvt_unlock(p);
+		return AST_RTP_GLUE_RESULT_FORBID;
+	}
 
 	ao2_ref(p->trtp, +1);
-        *instance = p->trtp;
-
-        if (ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA)) {
-                res = AST_RTP_GLUE_RESULT_REMOTE;
-        }
-
-        sip_pvt_unlock(p);
-
-        return res;
+	*instance = p->trtp;
+
+	if (ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA)) {
+		struct sockaddr_in them;
+		struct sockaddr_in us;
+
+		res = AST_RTP_GLUE_RESULT_REMOTE;
+		ast_rtp_instance_get_remote_address(p->rtp, &them);
+		ast_rtp_instance_get_local_address(p->rtp, &us);
+		if (!ast_apply_ha(p->directmediaha, &them)) {
+			ast_debug(3, "Reinvite text to %s denied by directmedia ACL on %s\n", ast_inet_ntoa(them.sin_addr), ast_inet_ntoa(us.sin_addr));
+			res = AST_RTP_GLUE_RESULT_FORBID;
+		}
+	}
+
+	sip_pvt_unlock(p);
+
+	return res;
 }
 
 static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *instance, struct ast_rtp_instance *vinstance, struct ast_rtp_instance *tinstance, format_t codecs, int nat_active)
 {
-        struct sip_pvt *p;
-        int changed = 0;
-
-        p = chan->tech_pvt;
-        if (!p)
-                return -1;
+	struct sip_pvt *p;
+	int changed = 0;
+
+	p = chan->tech_pvt;
+	if (!p)
+		return -1;
 
 	/* Disable early RTP bridge  */
 	if (!ast_bridged_channel(chan) && !sip_cfg.directrtpsetup) 	/* We are in early state */
 		return 0;
 
-        sip_pvt_lock(p);
-        if (p->alreadygone) {
-                /* If we're destroyed, don't bother */
-                sip_pvt_unlock(p);
-                return 0;
-        }
-
-        /* if this peer cannot handle reinvites of the media stream to devices
-           that are known to be behind a NAT, then stop the process now
+	sip_pvt_lock(p);
+	if (p->alreadygone) {
+		/* If we're destroyed, don't bother */
+		sip_pvt_unlock(p);
+		return 0;
+	}
+
+	/* if this peer cannot handle reinvites of the media stream to devices
+	   that are known to be behind a NAT, then stop the process now
 	*/
-        if (nat_active && !ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA_NAT)) {
-                sip_pvt_unlock(p);
-                return 0;
-        }
-
-        if (instance) {
-                changed |= ast_rtp_instance_get_remote_address(instance, &p->redirip);
-        } else if (p->redirip.sin_addr.s_addr || ntohs(p->redirip.sin_port) != 0) {
-                memset(&p->redirip, 0, sizeof(p->redirip));
-                changed = 1;
-        }
-        if (vinstance) {
-                changed |= ast_rtp_instance_get_remote_address(vinstance, &p->vredirip);
-        } else if (p->vredirip.sin_addr.s_addr || ntohs(p->vredirip.sin_port) != 0) {
-                memset(&p->vredirip, 0, sizeof(p->vredirip));
-                changed = 1;
-        }
-        if (tinstance) {
-                changed |= ast_rtp_instance_get_remote_address(tinstance, &p->tredirip);
-        } else if (p->tredirip.sin_addr.s_addr || ntohs(p->tredirip.sin_port) != 0) {
-                memset(&p->tredirip, 0, sizeof(p->tredirip));
-                changed = 1;
-        }
-        if (codecs && (p->redircodecs != codecs)) {
-                p->redircodecs = codecs;
-                changed = 1;
-        }
-        if (changed && !ast_test_flag(&p->flags[0], SIP_GOTREFER) && !ast_test_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER)) {
-                if (chan->_state != AST_STATE_UP) {     /* We are in early state */
-                        if (p->do_history)
-                                append_history(p, "ExtInv", "Initial invite sent with remote bridge proposal.");
-                        ast_debug(1, "Early remote bridge setting SIP '%s' - Sending media to %s\n", p->callid, ast_inet_ntoa(instance ? p->redirip.sin_addr : p->ourip.sin_addr));
-                } else if (!p->pendinginvite) {         /* We are up, and have no outstanding invite */
-                        ast_debug(3, "Sending reinvite on SIP '%s' - It's audio soon redirected to IP %s\n", p->callid, ast_inet_ntoa(instance ? p->redirip.sin_addr : p->ourip.sin_addr));
-                        transmit_reinvite_with_sdp(p, FALSE, FALSE);
-                } else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
-                        ast_debug(3, "Deferring reinvite on SIP '%s' - It's audio will be redirected to IP %s\n", p->callid, ast_inet_ntoa(instance ? p->redirip.sin_addr : p->ourip.sin_addr));
-                        /* We have a pending Invite. Send re-invite when we're done with the invite */
-                        ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
-                }
-        }
-        /* Reset lastrtprx timer */
-        p->lastrtprx = p->lastrtptx = time(NULL);
-        sip_pvt_unlock(p);
-        return 0;
+	if (nat_active && !ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA_NAT)) {
+		sip_pvt_unlock(p);
+		return 0;
+	}
+
+	if (instance) {
+		changed |= ast_rtp_instance_get_remote_address(instance, &p->redirip);
+	} else if (p->redirip.sin_addr.s_addr || ntohs(p->redirip.sin_port) != 0) {
+		memset(&p->redirip, 0, sizeof(p->redirip));
+		changed = 1;
+	}
+	if (vinstance) {
+		changed |= ast_rtp_instance_get_remote_address(vinstance, &p->vredirip);
+	} else if (p->vredirip.sin_addr.s_addr || ntohs(p->vredirip.sin_port) != 0) {
+		memset(&p->vredirip, 0, sizeof(p->vredirip));
+		changed = 1;
+	}
+	if (tinstance) {
+		changed |= ast_rtp_instance_get_remote_address(tinstance, &p->tredirip);
+	} else if (p->tredirip.sin_addr.s_addr || ntohs(p->tredirip.sin_port) != 0) {
+		memset(&p->tredirip, 0, sizeof(p->tredirip));
+		changed = 1;
+	}
+	if (codecs && (p->redircodecs != codecs)) {
+		p->redircodecs = codecs;
+		changed = 1;
+	}
+	if (changed && !ast_test_flag(&p->flags[0], SIP_GOTREFER) && !ast_test_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER)) {
+		if (chan->_state != AST_STATE_UP) {     /* We are in early state */
+			if (p->do_history)
+				append_history(p, "ExtInv", "Initial invite sent with remote bridge proposal.");
+			ast_debug(1, "Early remote bridge setting SIP '%s' - Sending media to %s\n", p->callid, ast_inet_ntoa(instance ? p->redirip.sin_addr : p->ourip.sin_addr));
+		} else if (!p->pendinginvite) {	 /* We are up, and have no outstanding invite */
+			ast_debug(3, "Sending reinvite on SIP '%s' - It's audio soon redirected to IP %s\n", p->callid, ast_inet_ntoa(instance ? p->redirip.sin_addr : p->ourip.sin_addr));
+			transmit_reinvite_with_sdp(p, FALSE, FALSE);
+		} else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
+			ast_debug(3, "Deferring reinvite on SIP '%s' - It's audio will be redirected to IP %s\n", p->callid, ast_inet_ntoa(instance ? p->redirip.sin_addr : p->ourip.sin_addr));
+			/* We have a pending Invite. Send re-invite when we're done with the invite */
+			ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
+		}
+	}
+	/* Reset lastrtprx timer */
+	p->lastrtprx = p->lastrtptx = time(NULL);
+	sip_pvt_unlock(p);
+	return 0;
 }
 
 static format_t sip_get_codec(struct ast_channel *chan)
 {
 	struct sip_pvt *p = chan->tech_pvt;
-        return p->peercapability ? p->peercapability : p->capability;
+	return p->peercapability ? p->peercapability : p->capability;
 }
 
 static struct ast_rtp_glue sip_rtp_glue = {

Modified: trunk/channels/sip/include/sip.h
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/sip/include/sip.h?view=diff&rev=264626&r1=264625&r2=264626
==============================================================================
--- trunk/channels/sip/include/sip.h (original)
+++ trunk/channels/sip/include/sip.h Thu May 20 12:54:02 2010
@@ -997,6 +997,7 @@
 	time_t lastrtprx;                   /*!< Last RTP received */
 	time_t lastrtptx;                   /*!< Last RTP sent */
 	int rtptimeout;                     /*!< RTP timeout time */
+	struct ast_ha *directmediaha;		/*!< Which IPs are allowed to interchange direct media with this peer - copied from sip_peer */
 	struct sockaddr_in recv;            /*!< Received as */
 	struct sockaddr_in ourip;           /*!< Our IP (as seen from the outside) */
 	enum transfermodes allowtransfer;   /*!< REFER: restriction scheme */
@@ -1196,6 +1197,7 @@
 	struct sockaddr_in defaddr;     /*!<  Default IP address, used until registration */
 	struct ast_ha *ha;              /*!<  Access control list */
 	struct ast_ha *contactha;       /*!<  Restrict what IPs are allowed in the Contact header (for registration) */
+	struct ast_ha *directmediaha;   /*!<  Restrict what IPs are allowed to interchange direct media with */
 	struct ast_variable *chanvars;  /*!<  Variables to set for channel created by user */
 	struct sip_pvt *mwipvt;         /*!<  Subscription for MWI */
 	struct sip_st_cfg stimer;       /*!<  SIP Session-Timers */

Modified: trunk/configs/sip.conf.sample
URL: http://svnview.digium.com/svn/asterisk/trunk/configs/sip.conf.sample?view=diff&rev=264626&r1=264625&r2=264626
==============================================================================
--- trunk/configs/sip.conf.sample (original)
+++ trunk/configs/sip.conf.sample Thu May 20 12:54:02 2010
@@ -785,6 +785,13 @@
                                 ; RTP payloads and fmtp headers in the 200 OK that does not match the
                                 ; callers INVITE. This will also fail if directmedia is enabled when
                                 ; the device is actually behind NAT.
+
+;directmediadeny=0.0.0.0/0      ; Use directmediapermit and directmediadeny to restrict 
+;directmediapermit=172.16.0.0/16; which peers should be able to pass directmedia to each other
+                                ; (There is no default setting, this is just an example)
+                                ; Use this if some of your phones are on IP addresses that
+                                ; can not reach each other directly. This way you can force 
+                                ; RTP to always flow through asterisk in such cases.
 
 ;ignoresdpversion=yes           ; By default, Asterisk will honor the session version
                                 ; number in SDP packets and will only modify the SDP
@@ -1017,6 +1024,8 @@
 ; contactdeny           ; is to register at the same IP as a SIP provider,
 ;                       ; then call oneself, and get redirected to that
 ;                       ; same location).
+; directmediapermit
+; directmediadeny
 ; unsolicited_mailbox
 ; use_q850_reason
 




More information about the svn-commits mailing list