Index: channels/chan_sip.c =================================================================== --- channels/chan_sip.c (revision 79171) +++ channels/chan_sip.c (working copy) @@ -562,6 +562,7 @@ static enum transfermodes global_allowtransfer; /*!< SIP Refer restriction scheme */ static int global_matchexterniplocally; /*!< Match externip/externhost setting against localnet setting */ +static int global_natonlyreinvitesameip; /*!< When canreinvite=yes, deny reinvites when peers are behind nat and their public IP is different */ /*! \brief Codecs that we support by default: */ static int global_capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_GSM | AST_FORMAT_H263; @@ -1521,7 +1522,7 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int ignore, int seqno); /*----- RTP interface functions */ -static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active); +static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active, struct ast_channel *chan2); static enum ast_rtp_get_result sip_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp); static enum ast_rtp_get_result sip_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp **rtp); static int sip_get_codec(struct ast_channel *chan); @@ -15526,6 +15527,8 @@ != AST_DEVICE_NOT_INUSE and != AST_DEVICE_UNKNOWN */ + + static int sip_devicestate(void *data) { char *host; @@ -16538,6 +16541,7 @@ global_t1min = DEFAULT_T1MIN; global_matchexterniplocally = FALSE; + global_natonlyreinvitesameip = FALSE; /* Copy the default jb config over global_jbconf */ memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf)); @@ -16780,6 +16784,8 @@ default_maxcallbitrate = DEFAULT_MAX_CALL_BITRATE; } else if (!strcasecmp(v->name, "matchexterniplocally")) { global_matchexterniplocally = ast_true(v->value); + } else if (!strcasecmp(v->name, "natonlyreinvitesameip")) { + global_natonlyreinvitesameip = ast_true(v->value); } } @@ -17163,7 +17169,7 @@ } /*! \brief Set the RTP peer for this call */ -static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active) +static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active, struct ast_channel *chan2) { struct sip_pvt *p; int changed = 0; @@ -17191,6 +17197,17 @@ return 0; } + /* We dont want native bridging if both peers are in different (natted) lans */ + if (nat_active && chan2 && chan2->tech && !strcasecmp(chan2->tech->type,"SIP") && global_natonlyreinvitesameip ) { + struct sip_pvt *p2; + p2=chan2->tech_pvt; + if (p->recv.sin_addr.s_addr != p2->recv.sin_addr.s_addr) { + ast_log(LOG_DEBUG,"Avoiding inter-nat bridging. Public IP addresses doesn't match\n"); + ast_mutex_unlock(&p->lock); + return 0; + } + } + if (rtp) { changed |= ast_rtp_get_peer(rtp, &p->redirip); } else if (p->redirip.sin_addr.s_addr || ntohs(p->redirip.sin_port) != 0) { Index: include/asterisk/rtp.h =================================================================== --- include/asterisk/rtp.h (revision 79171) +++ include/asterisk/rtp.h (working copy) @@ -71,7 +71,7 @@ /*! Get RTP struct, or NULL if unwilling to transfer */ enum ast_rtp_get_result (* const get_vrtp_info)(struct ast_channel *chan, struct ast_rtp **rtp); /*! Set RTP peer */ - int (* const set_rtp_peer)(struct ast_channel *chan, struct ast_rtp *peer, struct ast_rtp *vpeer, int codecs, int nat_active); + int (* const set_rtp_peer)(struct ast_channel *chan, struct ast_rtp *peer, struct ast_rtp *vpeer, int codecs, int nat_active, struct ast_channel *chan2); int (* const get_codec)(struct ast_channel *chan); const char * const type; AST_LIST_ENTRY(ast_rtp_protocol) list; Index: main/rtp.c =================================================================== --- main/rtp.c (revision 79171) +++ main/rtp.c (working copy) @@ -1541,7 +1541,7 @@ if (srcp && (srcp->nat || ast_test_flag(srcp, FLAG_NAT_ACTIVE))) nat_active = 1; /* Bridge media early */ - if (destpr->set_rtp_peer(dest, srcp, vsrcp, srccodec, nat_active)) + if (destpr->set_rtp_peer(dest, srcp, vsrcp, srccodec, nat_active, src)) ast_log(LOG_WARNING, "Channel '%s' failed to setup early bridge to '%s'\n", dest->name, src ? src->name : ""); ast_channel_unlock(dest); if (src) @@ -1612,7 +1612,7 @@ ast_rtp_pt_copy(vdestp, vsrcp); if (media) { /* Bridge early */ - if (destpr->set_rtp_peer(dest, srcp, vsrcp, srccodec, ast_test_flag(srcp, FLAG_NAT_ACTIVE))) + if (destpr->set_rtp_peer(dest, srcp, vsrcp, srccodec, ast_test_flag(srcp, FLAG_NAT_ACTIVE),src)) ast_log(LOG_WARNING, "Channel '%s' failed to setup early bridge to '%s'\n", dest->name, src->name); } ast_channel_unlock(dest); @@ -2808,7 +2808,7 @@ /* Set it up so audio goes directly between the two endpoints */ /* Test the first channel */ - if (!(pr0->set_rtp_peer(c0, p1, vp1, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE)))) { + if (!(pr0->set_rtp_peer(c0, p1, vp1, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE),c1))) { ast_rtp_get_peer(p1, &ac1); if (vp1) ast_rtp_get_peer(vp1, &vac1); @@ -2816,7 +2816,7 @@ ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c0->name, c1->name); /* Test the second channel */ - if (!(pr1->set_rtp_peer(c1, p0, vp0, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE)))) { + if (!(pr1->set_rtp_peer(c1, p0, vp0, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE),c0))) { ast_rtp_get_peer(p0, &ac0); if (vp0) ast_rtp_get_peer(vp0, &vac0); @@ -2838,10 +2838,10 @@ (c0->masq || c0->masqr || c1->masq || c1->masqr)) { ast_log(LOG_DEBUG, "Oooh, something is weird, backing out\n"); if (c0->tech_pvt == pvt0) - if (pr0->set_rtp_peer(c0, NULL, NULL, 0, 0)) + if (pr0->set_rtp_peer(c0, NULL, NULL, 0, 0, NULL)) ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c0->name); if (c1->tech_pvt == pvt1) - if (pr1->set_rtp_peer(c1, NULL, NULL, 0, 0)) + if (pr1->set_rtp_peer(c1, NULL, NULL, 0, 0, NULL)) ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name); return AST_BRIDGE_RETRY; } @@ -2870,7 +2870,7 @@ ast_log(LOG_DEBUG, "Oooh, '%s' was %s:%d/(format %d)\n", c1->name, ast_inet_ntoa(vac1.sin_addr), ntohs(vac1.sin_port), oldcodec1); } - if (pr0->set_rtp_peer(c0, t1.sin_addr.s_addr ? p1 : NULL, vt1.sin_addr.s_addr ? vp1 : NULL, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE))) + if (pr0->set_rtp_peer(c0, t1.sin_addr.s_addr ? p1 : NULL, vt1.sin_addr.s_addr ? vp1 : NULL, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE),c1)) ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c0->name, c1->name); memcpy(&ac1, &t1, sizeof(ac1)); memcpy(&vac1, &vt1, sizeof(vac1)); @@ -2884,7 +2884,7 @@ ast_log(LOG_DEBUG, "Oooh, '%s' was %s:%d/(format %d)\n", c0->name, ast_inet_ntoa(ac0.sin_addr), ntohs(ac0.sin_port), oldcodec0); } - if (pr1->set_rtp_peer(c1, t0.sin_addr.s_addr ? p0 : NULL, vt0.sin_addr.s_addr ? vp0 : NULL, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE))) + if (pr1->set_rtp_peer(c1, t0.sin_addr.s_addr ? p0 : NULL, vt0.sin_addr.s_addr ? vp0 : NULL, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE),c0)) ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c1->name, c0->name); memcpy(&ac0, &t0, sizeof(ac0)); memcpy(&vac0, &vt0, sizeof(vac0)); @@ -2894,9 +2894,9 @@ /* Wait for frame to come in on the channels */ if (!(who = ast_waitfor_n(cs, 2, &timeoutms))) { if (!timeoutms) { - if (pr0->set_rtp_peer(c0, NULL, NULL, 0, 0)) + if (pr0->set_rtp_peer(c0, NULL, NULL, 0, 0, NULL)) ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c0->name); - if (pr1->set_rtp_peer(c1, NULL, NULL, 0, 0)) + if (pr1->set_rtp_peer(c1, NULL, NULL, 0, 0, NULL)) ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name); return AST_BRIDGE_RETRY; } @@ -2917,10 +2917,10 @@ if (option_debug) ast_log(LOG_DEBUG, "Oooh, got a %s\n", fr ? "digit" : "hangup"); if (c0->tech_pvt == pvt0) - if (pr0->set_rtp_peer(c0, NULL, NULL, 0, 0)) + if (pr0->set_rtp_peer(c0, NULL, NULL, 0, 0, NULL)) ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c0->name); if (c1->tech_pvt == pvt1) - if (pr1->set_rtp_peer(c1, NULL, NULL, 0, 0)) + if (pr1->set_rtp_peer(c1, NULL, NULL, 0, 0, NULL)) ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name); return AST_BRIDGE_COMPLETE; } else if ((fr->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) { @@ -2930,15 +2930,15 @@ if (fr->subclass == AST_CONTROL_HOLD) { /* If we someone went on hold we want the other side to reinvite back to us */ if (who == c0) - pr1->set_rtp_peer(c1, NULL, NULL, 0, 0); + pr1->set_rtp_peer(c1, NULL, NULL, 0, 0, NULL); else - pr0->set_rtp_peer(c0, NULL, NULL, 0, 0); + pr0->set_rtp_peer(c0, NULL, NULL, 0, 0, NULL); } else if (fr->subclass == AST_CONTROL_UNHOLD) { /* If they went off hold they should go back to being direct */ if (who == c0) - pr1->set_rtp_peer(c1, p0, vp0, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE)); + pr1->set_rtp_peer(c1, p0, vp0, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE), c0); else - pr0->set_rtp_peer(c0, p1, vp1, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE)); + pr0->set_rtp_peer(c0, p1, vp1, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE), c1); } ast_indicate_data(other, fr->subclass, fr->data, fr->datalen); ast_frfree(fr); @@ -2967,9 +2967,9 @@ cs[1] = cs[2]; } - if (pr0->set_rtp_peer(c0, NULL, NULL, 0, 0)) + if (pr0->set_rtp_peer(c0, NULL, NULL, 0, 0, NULL)) ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c0->name); - if (pr1->set_rtp_peer(c1, NULL, NULL, 0, 0)) + if (pr1->set_rtp_peer(c1, NULL, NULL, 0, 0, NULL)) ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name); return AST_BRIDGE_FAILED;