Index: channels/chan_sip.c =================================================================== --- channels/chan_sip.c (revision 241101) +++ channels/chan_sip.c (working copy) @@ -1801,6 +1801,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 */ @@ -2059,6 +2060,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 */ @@ -4928,6 +4930,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) { @@ -5522,6 +5525,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) @@ -5899,6 +5903,11 @@ p->chanvars = NULL; } + if (p->directmediaha) { + ast_free_ha(p->directmediaha); + p->directmediaha = NULL; + } + ast_string_field_free_memory(p); if (p->socket.tcptls_session) { @@ -16084,6 +16093,7 @@ ast_cli(fd, " Insecure : %s\n", insecure2str(ast_test_flag(&peer->flags[0], SIP_INSECURE))); ast_cli(fd, " Force rport : %s\n", cli_yesno(ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT))); ast_cli(fd, " ACL : %s\n", cli_yesno(peer->ha != NULL)); + ast_cli(fd, " DirectMedACL : %s\n", cli_yesno(peer->directmediaha != NULL)); ast_cli(fd, " T.38 support : %s\n", 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); @@ -24774,6 +24784,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; @@ -24824,6 +24835,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; } @@ -24978,6 +24991,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; if (!(port = port_str2int(v->value, 0))) { @@ -25312,6 +25331,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(®_string, "%s?%s:%s@%s/%s", peer->name, peer->username, !ast_strlen_zero(peer->remotesecret) ? peer->remotesecret : peer->secret, peer->tohost, callback) < 0) { @@ -26306,8 +26326,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 trtp 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; } @@ -26357,8 +26387,19 @@ ao2_ref(p->rtp, +1); *instance = p->rtp; - if (ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA | SIP_DIRECT_MEDIA_NAT)) { + 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(&global_jbconf, 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; } @@ -26387,7 +26428,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); @@ -26414,7 +26464,16 @@ *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 trtp 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); Index: main/acl.c =================================================================== --- main/acl.c (revision 241101) +++ main/acl.c (working copy) @@ -240,6 +240,7 @@ if ((new_ha = ast_malloc(sizeof(*new_ha)))) { /* Copy from original to new object */ ast_copy_ha(original, new_ha); + new_ha->next = NULL; } return new_ha; Index: configs/sip.conf.sample =================================================================== --- configs/sip.conf.sample (revision 241101) +++ configs/sip.conf.sample (working copy) @@ -793,6 +793,13 @@ ; 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 is some of your phones are on IP addresses that + ; can not reach eachother directly. This way you can force + ; RTP to always flow through asterisk. + ;ignoresdpversion=yes ; By default, Asterisk will honor the session version ; number in SDP packets and will only modify the SDP ; session if the version number changes. This option will