From 8f176cf7c8af5c681b7b616500b6eb32adb28887 Mon Sep 17 00:00:00 2001 From: Liong Sauw Ming Date: Wed, 20 Jun 2012 10:39:05 +0000 Subject: Fixed #1537: Via rewrite: putting the right IP address in Via sent-by for outgoing requests git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@4173 74dad513-b988-da41-8d7b-12977e46ad98 --- pjsip/include/pjsip-simple/publish.h | 16 ++++++++++ pjsip/include/pjsip-ua/sip_regc.h | 15 ++++++++++ pjsip/include/pjsip/sip_dialog.h | 26 ++++++++++++++++- pjsip/include/pjsip/sip_transport.h | 8 +++++ pjsip/include/pjsua-lib/pjsua.h | 10 +++++++ pjsip/include/pjsua-lib/pjsua_internal.h | 3 ++ pjsip/src/pjsip-simple/publishc.c | 23 +++++++++++++++ pjsip/src/pjsip-ua/sip_reg.c | 23 +++++++++++++++ pjsip/src/pjsip/sip_dialog.c | 24 +++++++++++++++ pjsip/src/pjsip/sip_util.c | 8 ++++- pjsip/src/pjsua-lib/pjsua_acc.c | 50 ++++++++++++++++++++++++++++++++ pjsip/src/pjsua-lib/pjsua_call.c | 10 +++++++ pjsip/src/pjsua-lib/pjsua_core.c | 1 + pjsip/src/pjsua-lib/pjsua_im.c | 12 ++++++++ pjsip/src/pjsua-lib/pjsua_pres.c | 15 ++++++++++ 15 files changed, 242 insertions(+), 2 deletions(-) diff --git a/pjsip/include/pjsip-simple/publish.h b/pjsip/include/pjsip-simple/publish.h index c1a97fb5..59a58706 100644 --- a/pjsip/include/pjsip-simple/publish.h +++ b/pjsip/include/pjsip-simple/publish.h @@ -236,6 +236,22 @@ PJ_DECL(pj_status_t) pjsip_publishc_set_route_set(pjsip_publishc *pubc, PJ_DECL(pj_status_t) pjsip_publishc_set_headers(pjsip_publishc *pubc, const pjsip_hdr *hdr_list); +/** + * Set the "sent-by" field of the Via header for outgoing requests. + * + * @param pubc The client publication structure. + * @param via_addr Set via_addr to use for the Via header or NULL to use + * the transport's published name. + * @param via_tp via_addr will only be used if we are using via_tp + * transport. + * + * @return PJ_SUCCESS on success. + */ +PJ_DECL(pj_status_t) pjsip_publishc_set_via_sent_by(pjsip_publishc *pubc, + pjsip_host_port *via_addr, + pjsip_transport *via_tp); + + /** * Create PUBLISH request for the specified client publication structure. * Application can use this function to both create initial publication diff --git a/pjsip/include/pjsip-ua/sip_regc.h b/pjsip/include/pjsip-ua/sip_regc.h index c2aec0c8..9e393813 100644 --- a/pjsip/include/pjsip-ua/sip_regc.h +++ b/pjsip/include/pjsip-ua/sip_regc.h @@ -190,6 +190,21 @@ PJ_DECL(pj_status_t) pjsip_regc_init(pjsip_regc *regc, const pj_str_t contact[], pj_uint32_t expires); +/** + * Set the "sent-by" field of the Via header for outgoing requests. + * + * @param regc The client registration structure. + * @param via_addr Set via_addr to use for the Via header or NULL to use + * the transport's published name. + * @param via_tp via_addr will only be used if we are using via_tp + * transport. + * + * @return PJ_SUCCESS on success. + */ +PJ_DECL(pj_status_t) pjsip_regc_set_via_sent_by(pjsip_regc *regc, + pjsip_host_port *via_addr, + pjsip_transport *via_tp); + /** * Set the number of seconds to refresh the client registration before * the registration expires. diff --git a/pjsip/include/pjsip/sip_dialog.h b/pjsip/include/pjsip/sip_dialog.h index a9922d57..9f37c32f 100644 --- a/pjsip/include/pjsip/sip_dialog.h +++ b/pjsip/include/pjsip/sip_dialog.h @@ -173,6 +173,14 @@ struct pjsip_dialog /** Module specific data. */ void *mod_data[PJSIP_MAX_MODULE]; /**< Module data. */ + + /** + * If via_addr is set, it will be used as the "sent-by" field of the + * Via header for outgoing requests as long as the request uses via_tp + * transport. Normally application should not use or access these fields. + */ + pjsip_host_port via_addr; /**< Via address. */ + const void *via_tp; /**< Via transport. */ }; @@ -297,6 +305,22 @@ PJ_DECL(pj_status_t) pjsip_dlg_set_transport(pjsip_dialog *dlg, const pjsip_tpselector *sel); +/** + * Set the "sent-by" field of the Via header for outgoing requests. + * + * @param dlg The dialog instance. + * @param via_addr Set via_addr to use for the Via header or NULL to use + * the transport's published name. + * @param via_tp via_addr will only be used if we are using via_tp + * transport. + * + * @return PJ_SUCCESS on success. + */ +PJ_DECL(pj_status_t) pjsip_dlg_set_via_sent_by(pjsip_dialog *dlg, + pjsip_host_port *via_addr, + pjsip_transport *via_tp); + + /** * Create a new (forked) dialog on receipt on forked response in rdata. * The new dialog will be created from original_dlg, except that it will have @@ -402,7 +426,7 @@ PJ_DECL(pj_status_t) pjsip_dlg_add_usage( pjsip_dialog *dlg, * registered as a usage to the dialog. */ PJ_DECL(pj_bool_t) pjsip_dlg_has_usage(pjsip_dialog *dlg, - pjsip_module *module); + pjsip_module *module); /** * Attach module specific data to the dialog. Application can also set diff --git a/pjsip/include/pjsip/sip_transport.h b/pjsip/include/pjsip/sip_transport.h index 99f006a6..20ddcc5e 100644 --- a/pjsip/include/pjsip/sip_transport.h +++ b/pjsip/include/pjsip/sip_transport.h @@ -584,6 +584,14 @@ struct pjsip_tx_data * Arbitrary data attached by PJSIP modules. */ void *mod_data[PJSIP_MAX_MODULE]; + + /** + * If via_addr is set, it will be used as the "sent-by" field of the + * Via header for outgoing requests as long as the request uses via_tp + * transport. Normally application should not use or access these fields. + */ + pjsip_host_port via_addr; /**< Via address. */ + const void *via_tp; /**< Via transport. */ }; diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h index 8bf935aa..a964815f 100644 --- a/pjsip/include/pjsua-lib/pjsua.h +++ b/pjsip/include/pjsua-lib/pjsua.h @@ -2817,6 +2817,16 @@ typedef struct pjsua_acc_config */ int contact_rewrite_method; + /** + * This option is used to overwrite the "sent-by" field of the Via header + * for outgoing messages with the same interface address as the one in + * the REGISTER request, as long as the request uses the same transport + * instance as the previous REGISTER request. + * + * Default: 1 (yes) + */ + pj_bool_t allow_via_rewrite; + /** * Control the use of SIP outbound feature. SIP outbound is described in * RFC 5626 to enable proxies or registrar to send inbound requests back diff --git a/pjsip/include/pjsua-lib/pjsua_internal.h b/pjsip/include/pjsua-lib/pjsua_internal.h index 911cad10..326f916d 100644 --- a/pjsip/include/pjsua-lib/pjsua_internal.h +++ b/pjsip/include/pjsua-lib/pjsua_internal.h @@ -212,6 +212,9 @@ typedef struct pjsua_acc pj_str_t reg_contact; /**< Contact header for REGISTER. It may be different than acc contact if outbound is used */ + pjsip_host_port via_addr; /**< Address for Via header */ + pjsip_transport *via_tp; /**< Transport associated with + the Via address */ pj_str_t srv_domain; /**< Host part of reg server. */ int srv_port; /**< Port number of reg server. */ diff --git a/pjsip/src/pjsip-simple/publishc.c b/pjsip/src/pjsip-simple/publishc.c index d70442bb..6282923c 100644 --- a/pjsip/src/pjsip-simple/publishc.c +++ b/pjsip/src/pjsip-simple/publishc.c @@ -94,6 +94,8 @@ struct pjsip_publishc pj_uint32_t expires; pjsip_route_hdr route_set; pjsip_hdr usr_hdr; + pjsip_host_port via_addr; + const void *via_tp; /* Authorization sessions. */ pjsip_auth_clt_sess auth_sess; @@ -345,6 +347,21 @@ PJ_DEF(pj_status_t) pjsip_publishc_set_headers( pjsip_publishc *pubc, return PJ_SUCCESS; } +PJ_DEF(pj_status_t) pjsip_publishc_set_via_sent_by(pjsip_publishc *pubc, + pjsip_host_port *via_addr, + pjsip_transport *via_tp) +{ + PJ_ASSERT_RETURN(pubc, PJ_EINVAL); + + if (!via_addr) + pj_bzero(&pubc->via_addr, sizeof(pubc->via_addr)); + else + pubc->via_addr = *via_addr; + pubc->via_tp = via_tp; + + return PJ_SUCCESS; +} + static pj_status_t create_request(pjsip_publishc *pubc, pjsip_tx_data **p_tdata) { @@ -739,6 +756,12 @@ PJ_DEF(pj_status_t) pjsip_publishc_send(pjsip_publishc *pubc, } pj_mutex_unlock(pubc->mutex); + /* If via_addr is set, use this address for the Via header. */ + if (pubc->via_addr.host.slen > 0) { + tdata->via_addr = pubc->via_addr; + tdata->via_tp = pubc->via_tp; + } + /* Invalidate message buffer. */ pjsip_tx_data_invalidate_msg(tdata); diff --git a/pjsip/src/pjsip-ua/sip_reg.c b/pjsip/src/pjsip-ua/sip_reg.c index c02c17bb..2bbc81b9 100644 --- a/pjsip/src/pjsip-ua/sip_reg.c +++ b/pjsip/src/pjsip-ua/sip_reg.c @@ -90,6 +90,8 @@ struct pjsip_regc pj_uint32_t delay_before_refresh; pjsip_route_hdr route_set; pjsip_hdr hdr_list; + pjsip_host_port via_addr; + const void *via_tp; /* Authorization sessions. */ pjsip_auth_clt_sess auth_sess; @@ -808,6 +810,21 @@ static void schedule_registration ( pjsip_regc *regc, pj_int32_t expiration ) } } +PJ_DEF(pj_status_t) pjsip_regc_set_via_sent_by( pjsip_regc *regc, + pjsip_host_port *via_addr, + pjsip_transport *via_tp) +{ + PJ_ASSERT_RETURN(regc, PJ_EINVAL); + + if (!via_addr) + pj_bzero(®c->via_addr, sizeof(regc->via_addr)); + else + regc->via_addr = *via_addr; + regc->via_tp = via_tp; + + return PJ_SUCCESS; +} + PJ_DEF(pj_status_t) pjsip_regc_set_delay_before_refresh( pjsip_regc *regc, pj_uint32_t delay ) @@ -1262,6 +1279,12 @@ PJ_DEF(pj_status_t) pjsip_regc_send(pjsip_regc *regc, pjsip_tx_data *tdata) */ pjsip_tx_data_add_ref(tdata); + /* If via_addr is set, use this address for the Via header. */ + if (regc->via_addr.host.slen > 0) { + tdata->via_addr = regc->via_addr; + tdata->via_tp = regc->via_tp; + } + /* Need to unlock the regc temporarily while sending the message to * prevent deadlock (https://trac.pjsip.org/repos/ticket/1247). * It should be safe to do this since the regc's refcount has been diff --git a/pjsip/src/pjsip/sip_dialog.c b/pjsip/src/pjsip/sip_dialog.c index 57f0c14a..2e19bfc5 100644 --- a/pjsip/src/pjsip/sip_dialog.c +++ b/pjsip/src/pjsip/sip_dialog.c @@ -585,6 +585,24 @@ PJ_DEF(pj_status_t) pjsip_dlg_set_transport( pjsip_dialog *dlg, return PJ_SUCCESS; } +/* + * Set "sent-by" field of Via header. + */ +PJ_DEF(pj_status_t) pjsip_dlg_set_via_sent_by( pjsip_dialog *dlg, + pjsip_host_port *via_addr, + pjsip_transport *via_tp) +{ + PJ_ASSERT_RETURN(dlg, PJ_EINVAL); + + if (!via_addr) + pj_bzero(&dlg->via_addr, sizeof(dlg->via_addr)); + else + dlg->via_addr = *via_addr; + dlg->via_tp = via_tp; + + return PJ_SUCCESS; +} + /* * Create forked dialog from a response. @@ -1163,6 +1181,12 @@ PJ_DEF(pj_status_t) pjsip_dlg_send_request( pjsip_dialog *dlg, /* Lock and increment session */ pjsip_dlg_inc_lock(dlg); + /* If via_addr is set, use this address for the Via header. */ + if (dlg->via_addr.host.slen > 0) { + tdata->via_addr = dlg->via_addr; + tdata->via_tp = dlg->via_tp; + } + /* Update dialog's CSeq and message's CSeq if request is not * ACK nor CANCEL. */ diff --git a/pjsip/src/pjsip/sip_util.c b/pjsip/src/pjsip/sip_util.c index f238f524..ed4fd9c0 100644 --- a/pjsip/src/pjsip/sip_util.c +++ b/pjsip/src/pjsip/sip_util.c @@ -1192,7 +1192,13 @@ static void stateless_send_transport_cb( void *token, } via->transport = pj_str(stateless_data->cur_transport->type_name); - via->sent_by = stateless_data->cur_transport->local_name; + if (tdata->via_addr.host.slen > 0 && + tdata->via_tp == (void *)stateless_data->cur_transport) + { + via->sent_by = tdata->via_addr; + } else { + via->sent_by = stateless_data->cur_transport->local_name; + } via->rport_param = pjsip_cfg()->endpt.disable_rport ? -1 : 0; pjsip_tx_data_invalidate_msg(tdata); diff --git a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c index 65e52640..f6c97df0 100644 --- a/pjsip/src/pjsua-lib/pjsua_acc.c +++ b/pjsip/src/pjsua-lib/pjsua_acc.c @@ -624,6 +624,8 @@ PJ_DEF(pj_status_t) pjsua_acc_del(pjsua_acc_id acc_id) /* Invalidate */ acc->valid = PJ_FALSE; acc->contact.slen = 0; + pj_bzero(&acc->via_addr, sizeof(acc->via_addr)); + acc->via_tp = NULL; /* Remove from array */ for (i=0; ireg_delay_before_refresh); } + /* Allow via rewrite */ + if (acc->cfg.allow_via_rewrite != cfg->allow_via_rewrite) { + if (acc->regc != NULL) { + if (cfg->allow_via_rewrite) { + pjsip_regc_set_via_sent_by(acc->regc, &acc->via_addr, + acc->via_tp); + } else + pjsip_regc_set_via_sent_by(acc->regc, NULL, NULL); + } + if (acc->publish_sess != NULL) { + if (cfg->allow_via_rewrite) { + pjsip_publishc_set_via_sent_by(acc->publish_sess, + &acc->via_addr, acc->via_tp); + } else + pjsip_publishc_set_via_sent_by(acc->publish_sess, NULL, NULL); + } + acc->cfg.allow_via_rewrite = cfg->allow_via_rewrite; + } + /* Normalize registration timeout and refresh delay */ if (acc->cfg.reg_uri.slen ) { if (acc->cfg.reg_timeout == 0) { @@ -1314,6 +1335,19 @@ static pj_bool_t acc_check_nat_addr(pjsua_acc *acc, tp = param->rdata->tp_info.transport; + /* If allow_via_rewrite is enabled, we save the Via "sent-by" address + * from the response. + */ + if (acc->cfg.allow_via_rewrite && + (acc->via_addr.host.slen == 0 || acc->via_tp != tp)) + { + via = param->rdata->msg_info.via; + if (pj_strcmp(&acc->via_addr.host, &via->sent_by.host)) + pj_strdup(acc->pool, &acc->via_addr.host, &via->sent_by.host); + acc->via_addr.port = via->sent_by.port; + acc->via_tp = tp; + } + /* Only update if account is configured to auto-update */ if (acc->cfg.allow_contact_rewrite == PJ_FALSE) return PJ_FALSE; @@ -2176,6 +2210,14 @@ PJ_DEF(pj_status_t) pjsua_acc_set_registration( pjsua_acc_id acc_id, } if (status == PJ_SUCCESS) { + if (pjsua_var.acc[acc_id].cfg.allow_via_rewrite && + pjsua_var.acc[acc_id].via_addr.host.slen > 0) + { + pjsip_regc_set_via_sent_by(pjsua_var.acc[acc_id].regc, + &pjsua_var.acc[acc_id].via_addr, + pjsua_var.acc[acc_id].via_tp); + } + //pjsua_process_msg_data(tdata, NULL); status = pjsip_regc_send( pjsua_var.acc[acc_id].regc, tdata ); } @@ -2541,6 +2583,14 @@ PJ_DEF(pj_status_t) pjsua_acc_create_request(pjsua_acc_id acc_id, pjsip_tx_data_set_transport(tdata, &tp_sel); } + /* If via_addr is set, use this address for the Via header. */ + if (pjsua_var.acc[acc_id].cfg.allow_via_rewrite && + pjsua_var.acc[acc_id].via_addr.host.slen > 0) + { + tdata->via_addr = pjsua_var.acc[acc_id].via_addr; + tdata->via_tp = pjsua_var.acc[acc_id].via_tp; + } + /* Done */ *p_tdata = tdata; return PJ_SUCCESS; diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c index ccc06538..ab7fd1f7 100644 --- a/pjsip/src/pjsua-lib/pjsua_call.c +++ b/pjsip/src/pjsua-lib/pjsua_call.c @@ -715,6 +715,9 @@ PJ_DEF(pj_status_t) pjsua_call_make_call(pjsua_acc_id acc_id, */ pjsip_dlg_inc_lock(dlg); + if (acc->cfg.allow_via_rewrite && acc->via_addr.host.slen > 0) + pjsip_dlg_set_via_sent_by(dlg, &acc->via_addr, acc->via_tp); + /* Calculate call's secure level */ call->secure_level = get_secure_level(acc_id, dest_uri); @@ -1170,6 +1173,13 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata) goto on_return; } + if (pjsua_var.acc[acc_id].cfg.allow_via_rewrite && + pjsua_var.acc[acc_id].via_addr.host.slen > 0) + { + pjsip_dlg_set_via_sent_by(dlg, &pjsua_var.acc[acc_id].via_addr, + pjsua_var.acc[acc_id].via_tp); + } + /* Set credentials */ if (pjsua_var.acc[acc_id].cred_cnt) { pjsip_auth_clt_set_credentials(&dlg->auth_sess, diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c index 4fbfcb19..08de0302 100644 --- a/pjsip/src/pjsua-lib/pjsua_core.c +++ b/pjsip/src/pjsua-lib/pjsua_core.c @@ -211,6 +211,7 @@ PJ_DEF(void) pjsua_acc_config_default(pjsua_acc_config *cfg) cfg->unpublish_max_wait_time_msec = PJSUA_UNPUBLISH_MAX_WAIT_TIME_MSEC; cfg->transport_id = PJSUA_INVALID_ID; cfg->allow_contact_rewrite = PJ_TRUE; + cfg->allow_via_rewrite = PJ_TRUE; cfg->require_100rel = pjsua_var.ua_cfg.require_100rel; cfg->use_timer = pjsua_var.ua_cfg.use_timer; cfg->timer_setting = pjsua_var.ua_cfg.timer_setting; diff --git a/pjsip/src/pjsua-lib/pjsua_im.c b/pjsip/src/pjsua-lib/pjsua_im.c index a1062c6f..7c6886a4 100644 --- a/pjsip/src/pjsua-lib/pjsua_im.c +++ b/pjsip/src/pjsua-lib/pjsua_im.c @@ -601,6 +601,12 @@ PJ_DEF(pj_status_t) pjsua_im_send( pjsua_acc_id acc_id, /* Add route set */ pjsua_set_msg_route_set(tdata, &acc->route_set); + /* If via_addr is set, use this address for the Via header. */ + if (acc->cfg.allow_via_rewrite && acc->via_addr.host.slen > 0) { + tdata->via_addr = acc->via_addr; + tdata->via_tp = acc->via_tp; + } + /* Send request (statefully) */ status = pjsip_endpt_send_request( pjsua_var.endpt, tdata, -1, im_data, &im_callback); @@ -684,6 +690,12 @@ PJ_DEF(pj_status_t) pjsua_im_typing( pjsua_acc_id acc_id, /* Add route set */ pjsua_set_msg_route_set(tdata, &acc->route_set); + /* If via_addr is set, use this address for the Via header. */ + if (acc->cfg.allow_via_rewrite && acc->via_addr.host.slen > 0) { + tdata->via_addr = acc->via_addr; + tdata->via_tp = acc->via_tp; + } + /* Create data to reauthenticate */ im_data = PJ_POOL_ZALLOC_T(tdata->pool, pjsua_im_data); im_data->acc_id = acc_id; diff --git a/pjsip/src/pjsua-lib/pjsua_pres.c b/pjsip/src/pjsua-lib/pjsua_pres.c index ff30879f..5eac4415 100644 --- a/pjsip/src/pjsua-lib/pjsua_pres.c +++ b/pjsip/src/pjsua-lib/pjsua_pres.c @@ -864,6 +864,9 @@ static pj_bool_t pres_on_rx_request(pjsip_rx_data *rdata) return PJ_TRUE; } + if (acc->cfg.allow_via_rewrite && acc->via_addr.host.slen > 0) + pjsip_dlg_set_via_sent_by(dlg, &acc->via_addr, acc->via_tp); + /* Set credentials and preference. */ pjsip_auth_clt_set_credentials(&dlg->auth_sess, acc->cred_cnt, acc->cred); pjsip_auth_clt_set_prefs(&dlg->auth_sess, &acc->cfg.auth_pref); @@ -1229,6 +1232,12 @@ static pj_status_t send_publish(int acc_id, pj_bool_t active) /* Add headers etc */ pjsua_process_msg_data(tdata, NULL); + /* Set Via sent-by */ + if (acc->cfg.allow_via_rewrite && acc->via_addr.host.slen > 0) { + pjsip_publishc_set_via_sent_by(acc->publish_sess, &acc->via_addr, + acc->via_tp); + } + /* Send the PUBLISH request */ status = pjsip_publishc_send(acc->publish_sess, tdata); if (status == PJ_EPENDING) { @@ -1780,6 +1789,9 @@ static void subscribe_buddy_presence(pjsua_buddy_id buddy_id) */ pjsip_dlg_inc_lock(buddy->dlg); + if (acc->cfg.allow_via_rewrite && acc->via_addr.host.slen > 0) + pjsip_dlg_set_via_sent_by(buddy->dlg, &acc->via_addr, acc->via_tp); + status = pjsip_pres_create_uac( buddy->dlg, &pres_callback, PJSIP_EVSUB_NO_EVENT_ID, &buddy->sub); if (status != PJ_SUCCESS) { @@ -2097,6 +2109,9 @@ pj_status_t pjsua_start_mwi(pjsua_acc_id acc_id, pj_bool_t force_renew) */ pjsip_dlg_inc_lock(acc->mwi_dlg); + if (acc->cfg.allow_via_rewrite && acc->via_addr.host.slen > 0) + pjsip_dlg_set_via_sent_by(acc->mwi_dlg, &acc->via_addr, acc->via_tp); + /* Create UAC subscription */ status = pjsip_mwi_create_uac(acc->mwi_dlg, &mwi_cb, PJSIP_EVSUB_NO_EVENT_ID, &acc->mwi_sub); -- cgit v1.2.3