diff --git a/CHANGES b/CHANGES index 109f4f60d024bad99b48ab32c10f9b1141f0c2f3..2ef538eab140b267ea6d93172c2c4969bcf1c0cc 100644 --- a/CHANGES +++ b/CHANGES @@ -398,6 +398,9 @@ chan_sip detects that an incoming SIP request crossed a NAT after being sent by the remote endpoint. + * The default global nat setting in sip.conf has been changed from force_rport + to auto_force_rport. + * NAT settings are now a combinable list of options. The equivalent of the deprecated nat=yes is nat=force_rport,comedia. nat=no behaves as before. diff --git a/channels/chan_sip.c b/channels/chan_sip.c index cdf020ad70a36395aea4210143c592070d35d74d..1adf7a00faeb921755a9d7964ea22bda216f7bb6 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1399,7 +1399,7 @@ static int get_refer_info(struct sip_pvt *transferer, struct sip_request *outgoi static int get_also_info(struct sip_pvt *p, struct sip_request *oreq); static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req); static int set_address_from_contact(struct sip_pvt *pvt); -static void check_via(struct sip_pvt *p, struct sip_request *req); +static void check_via(struct sip_pvt *p, const struct sip_request *req); static int get_rpid(struct sip_pvt *p, struct sip_request *oreq); static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason, char **reason_str); static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_recall_core_id); @@ -8747,9 +8747,8 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr, if (useglobal_nat && addr) { /* Setup NAT structure according to global settings if we have an address */ - ast_copy_flags(&p->flags[0], &global_flags[0], SIP_NAT_FORCE_RPORT); ast_sockaddr_copy(&p->recv, addr); - + check_via(p, req); do_setnat(p); } @@ -12116,8 +12115,9 @@ static int transmit_response_using_temp(ast_string_field callid, struct ast_sock if (useglobal_nat && addr) { ast_copy_flags(&p->flags[0], &global_flags[0], SIP_NAT_FORCE_RPORT); + ast_copy_flags(&p->flags[2], &global_flags[2], SIP_PAGE3_NAT_AUTO_RPORT); ast_sockaddr_copy(&p->recv, addr); - do_setnat(p); + check_via(p, req); } ast_string_field_set(p, fromdomain, default_fromdomain); @@ -17958,7 +17958,7 @@ static int get_also_info(struct sip_pvt *p, struct sip_request *oreq) } /*! \brief check Via: header for hostname, port and rport request/answer */ -static void check_via(struct sip_pvt *p, struct sip_request *req) +static void check_via(struct sip_pvt *p, const struct sip_request *req) { char via[512]; char *c, *maddr; @@ -18092,6 +18092,21 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of, return AUTH_DONT_KNOW; } + /* build_peer, called through sip_find_peer, is not able to check the + * sip_pvt->natdetected flag in order to determine if the peer is behind + * NAT or not when SIP_PAGE3_NAT_AUTO_RPORT or SIP_PAGE3_NAT_AUTO_COMEDIA + * are set on the peer. So we check for that here and set the peer's + * address accordingly. + */ + if (p->natdetected && ast_test_flag(&peer->flags[2], SIP_PAGE3_NAT_AUTO_RPORT)) { + ast_set_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT); + ast_sockaddr_copy(&peer->addr, &p->recv); + } + + if (p->natdetected && ast_test_flag(&peer->flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA)) { + ast_set_flag(&peer->flags[1], SIP_PAGE2_SYMMETRICRTP); + } + if (!ast_apply_acl(peer->acl, addr, "SIP Peer ACL: ")) { ast_debug(2, "Found peer '%s' for '%s', but fails host access\n", peer->name, of); sip_unref_peer(peer, "sip_unref_peer: check_peer_ok: from sip_find_peer call, early return of AUTH_ACL_FAILED"); @@ -28426,7 +28441,10 @@ static int handle_request_do(struct sip_request *req, struct ast_sockaddr *addr) owner_chan_ref = sip_pvt_lock_full(p); copy_socket_data(&p->socket, &req->socket); - ast_sockaddr_copy(&p->recv, addr); + + if (ast_sockaddr_isnull(&p->recv)) { /* This may already be set before getting here */ + ast_sockaddr_copy(&p->recv, addr); + } /* if we have an owner, then this request has been authenticated */ if (p->owner) { @@ -30637,7 +30655,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str } else if (!strcasecmp(v->name, "host")) { if (!strcasecmp(v->value, "dynamic")) { /* They'll register with us */ - if ((!found && !realtime) || !peer->host_dynamic) { + if ((!found && !ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS)) || !peer->host_dynamic) { /* Initialize stuff if this is a new peer, or if it used to * not be dynamic before the reload. */ ast_sockaddr_setnull(&peer->addr); @@ -30990,6 +31008,10 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str set_socket_transport(&peer->socket, peer->default_outbound_transport); } + ast_copy_flags(&peer->flags[0], &peerflags[0], mask[0].flags); + ast_copy_flags(&peer->flags[1], &peerflags[1], mask[1].flags); + ast_copy_flags(&peer->flags[2], &peerflags[2], mask[2].flags); + if (ast_str_strlen(fullcontact)) { ast_string_field_set(peer, fullcontact, ast_str_buffer(fullcontact)); peer->rt_fromcontact = TRUE; @@ -31083,9 +31105,6 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str sip_poke_peer(peer, 0); } - ast_copy_flags(&peer->flags[0], &peerflags[0], mask[0].flags); - ast_copy_flags(&peer->flags[1], &peerflags[1], mask[1].flags); - ast_copy_flags(&peer->flags[2], &peerflags[2], mask[2].flags); if (ast_test_flag(&peer->flags[1], SIP_PAGE2_ALLOWSUBSCRIBE)) { sip_cfg.allowsubscribe = TRUE; /* No global ban any more */ } diff --git a/contrib/realtime/mysql/sippeers.sql b/contrib/realtime/mysql/sippeers.sql index 5c58df7ea1e67487417b25cd57f85d4e8c55e145..e0dbe1a430492662e8d4fae8af77222a4859d7f3 100644 --- a/contrib/realtime/mysql/sippeers.sql +++ b/contrib/realtime/mysql/sippeers.sql @@ -24,7 +24,7 @@ CREATE TABLE IF NOT EXISTS `sippeers` ( `transport` enum('udp','tcp','udp,tcp','tcp,udp') DEFAULT NULL, `dtmfmode` enum('rfc2833','info','shortinfo','inband','auto') DEFAULT NULL, `directmedia` enum('yes','no','nonat','update') DEFAULT NULL, - `nat` enum('yes','no','never','route') DEFAULT NULL, + `nat` varchar(29) DEFAULT NULL, `callgroup` varchar(40) DEFAULT NULL, `pickupgroup` varchar(40) DEFAULT NULL, `language` varchar(40) DEFAULT NULL, diff --git a/contrib/realtime/postgresql/realtime.sql b/contrib/realtime/postgresql/realtime.sql index abcadd2fd801676b0767dfdfb77e0e789b2ac4a9..cba8d3895db4a3af738ee7075a839c21be20d200 100644 --- a/contrib/realtime/postgresql/realtime.sql +++ b/contrib/realtime/postgresql/realtime.sql @@ -48,7 +48,7 @@ insecure character varying(4), "language" character varying(2), mailbox character varying(50), md5secret character varying(80), -nat character varying(5) DEFAULT 'no' NOT NULL, +nat character varying(29) DEFAULT '' NOT NULL, permit character varying(95), deny character varying(95), mask character varying(95),