Add RFC 3327 Path header support to chan_sip
This patch adds support for RFC 3327 "Path" headers. This can be enabled in sip.conf using the 'supportpath' setting, either on a global basis or on a peer basis. This setting enables Asterisk to route outgoing out-of-dialog requests via a set of proxies by using a pre-loaded route-set defined by the Path headers in the REGISTER request. This patch also adds Realtime support for dynamically updating the Path information for a peer. A huge thank-you to Klaus Darillion and Olle E Johansson for their efforts in writing this patch. Review: https://reviewboard.asterisk.org/r/2235/ Review: https://reviewboard.asterisk.org/r/991/ (closes issue ASTERISK-16884) Reported by: klaus3000 Tested by: klaus3000, oej, mjordan patches: path-1.8.0-patch.txt uploaded by klaus3000 (License 5054) oolong-path-support-trunk in team branch by oej (License 5267) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@382440 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
parent
469ca1c71d
commit
8d5c36c9bb
16
CHANGES
16
CHANGES
|
@ -50,6 +50,13 @@ chan_mobile
|
|||
|
||||
* Added ECAM command support for Sony Ericsson phones.
|
||||
|
||||
chan_sip
|
||||
------------------
|
||||
* Added support for RFC 3327 "Path" headers. This can be enabled in sip.conf
|
||||
using the 'supportpath' setting, either on a global basis or on a peer basis.
|
||||
This setting enables Asterisk to route outgoing out-of-dialog requests via a
|
||||
set of proxies by using a pre-loaded route-set defined by the Path headers in
|
||||
the REGISTER request. See Realtime updates for more configuration information.
|
||||
|
||||
Features
|
||||
-------------------
|
||||
|
@ -95,6 +102,15 @@ Core
|
|||
reason to any string. It also allows for custom strings to be read as the
|
||||
redirecting reason from SIP Diversion headers.
|
||||
|
||||
Realtime
|
||||
------------------
|
||||
* Dynamic realtime tables for SIP Users can now include a 'path' field. This
|
||||
will store the path information for that peer when it registers. Realtime
|
||||
tables can also use the 'supportpath' field to enable Path header support.
|
||||
|
||||
* LDAP realtime configurations for SIP Users now have the AstAccountPathSupport
|
||||
objectIdentifier. This maps to the supportpath option in sip.conf.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 10 to Asterisk 11 --------------------
|
||||
------------------------------------------------------------------------------
|
||||
|
|
12
CREDITS
12
CREDITS
|
@ -22,7 +22,7 @@
|
|||
* John Todd, TalkPlus, Inc. and JR Richardson, Ntegrated Solutions.
|
||||
for funding the development of SIP Session Timers support.
|
||||
|
||||
* Omnitor AB, Gunnar Hellström, for funding work with videocaps,
|
||||
* Omnitor AB, Gunnar Hellstr<EFBFBD>m, for funding work with videocaps,
|
||||
T.140 RED, originate with video/text and many more
|
||||
contributions.
|
||||
|
||||
|
@ -54,7 +54,7 @@
|
|||
|
||||
=== HARDWARE DONORS ===
|
||||
|
||||
We'd like to thank the followwing for granting access to hardware for testing.
|
||||
We'd like to thank the following for granting access to hardware for testing.
|
||||
|
||||
* Thanks to QuickNet Technologies for their donation of an Internet
|
||||
PhoneJack and Linejack card to the project.
|
||||
|
@ -63,13 +63,12 @@
|
|||
* Thanks to VoipSupply for their donation of Sipura ATAs to the project
|
||||
for T.38 testing. (http://www.voipsupply.com)
|
||||
|
||||
|
||||
* Thanks to Grandstream for their donation of ATAs to the project for
|
||||
T.38 testing. (http://www.grandstream.com)
|
||||
|
||||
=== MISCELLANEOUS PATCHES ===
|
||||
|
||||
We'd like to thank the flollowing for their patches
|
||||
We'd like to thank the following for their patches
|
||||
|
||||
* Jim Dixon - Zapata Telephony and app_rpt
|
||||
http://www.zapatatelephony.org/app_rpt.html
|
||||
|
@ -240,7 +239,8 @@
|
|||
ControlPlayback, and multiple bug fixes See
|
||||
http://voip-info.org/users/view/sergee serg(AT)voipsolutions.ru
|
||||
|
||||
* Klaus Darillon - the SIPremoveHeader function in chan_sip
|
||||
* Klaus Darillon - the SIPremoveHeader function in chan_sip and SIP Path
|
||||
Support.
|
||||
|
||||
* Moises Silva (moy) - for writing LibOpenR2, and providing support for
|
||||
it in chan_dahdi moises.silva(AT)gmail.com
|
||||
|
@ -252,7 +252,7 @@
|
|||
cdr_tds rewrite, countless other improvements, fixes, and good
|
||||
ideas. sean(AT)malleable.com
|
||||
|
||||
* Jan Kaláb - Calendaring support for Exchange Server 2007+ via
|
||||
* Jan Kal<EFBFBD>b - Calendaring support for Exchange Server 2007+ via
|
||||
Exchange Web Services.
|
||||
|
||||
* University of Oslo (uio.no), Norway - SIP Max-Forwards setting
|
||||
|
|
|
@ -1187,6 +1187,8 @@ static struct sip_pvt *find_call(struct sip_request *req, struct ast_sockaddr *a
|
|||
static void free_old_route(struct sip_route *route);
|
||||
static void list_route(struct sip_route *route);
|
||||
static void build_route(struct sip_pvt *p, struct sip_request *req, int backwards, int resp);
|
||||
static int build_path(struct sip_pvt *p, struct sip_peer *peer, struct sip_request *req, char *pathbuf);
|
||||
static int copy_route(struct sip_route **dst, const struct sip_route *src);
|
||||
static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sockaddr *addr,
|
||||
struct sip_request *req, const char *uri);
|
||||
static struct sip_pvt *get_sip_pvt_byid_locked(const char *callid, const char *totag, const char *fromtag);
|
||||
|
@ -1360,7 +1362,7 @@ static void set_socket_transport(struct sip_socket *socket, int transport);
|
|||
static int peer_ipcmp_cb_full(void *obj, void *arg, void *data, int flags);
|
||||
|
||||
/* Realtime device support */
|
||||
static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr, const char *username, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms);
|
||||
static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr, const char *username, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms, const char *path);
|
||||
static void update_peer(struct sip_peer *p, int expire);
|
||||
static struct ast_variable *get_insecure_variable_from_config(struct ast_config *config);
|
||||
static const char *get_name_from_variable(const struct ast_variable *var);
|
||||
|
@ -1442,6 +1444,7 @@ static int add_digit(struct sip_request *req, char digit, unsigned int duration,
|
|||
static int add_rpid(struct sip_request *req, struct sip_pvt *p);
|
||||
static int add_vidupdate(struct sip_request *req);
|
||||
static void add_route(struct sip_request *req, struct sip_route *route);
|
||||
static void make_route_list(struct sip_route *route, char *r, int rem);
|
||||
static int copy_header(struct sip_request *req, const struct sip_request *orig, const char *field);
|
||||
static int copy_all_header(struct sip_request *req, const struct sip_request *orig, const char *field);
|
||||
static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, const struct sip_request *orig, const char *field);
|
||||
|
@ -5112,7 +5115,7 @@ static int sip_sendtext(struct ast_channel *ast, const char *text)
|
|||
that name and store that in the "regserver" field in the sippeers
|
||||
table to facilitate multi-server setups.
|
||||
*/
|
||||
static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr, const char *defaultuser, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms)
|
||||
static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr, const char *defaultuser, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms, const char *path)
|
||||
{
|
||||
char port[10];
|
||||
char ipaddr[INET6_ADDRSTRLEN];
|
||||
|
@ -5135,10 +5138,11 @@ static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr
|
|||
ast_copy_string(ipaddr, ast_sockaddr_isnull(addr) ? "" : ast_sockaddr_stringify_addr(addr), sizeof(ipaddr));
|
||||
ast_copy_string(port, ast_sockaddr_port(addr) ? ast_sockaddr_stringify_port(addr) : "", sizeof(port));
|
||||
|
||||
if (ast_strlen_zero(sysname)) /* No system name, disable this */
|
||||
if (ast_strlen_zero(sysname)) { /* No system name, disable this */
|
||||
sysname = NULL;
|
||||
else if (sip_cfg.rtsave_sysname)
|
||||
} else if (sip_cfg.rtsave_sysname) {
|
||||
syslabel = "regserver";
|
||||
}
|
||||
|
||||
/* XXX IMPORTANT: Anytime you add a new parameter to be updated, you
|
||||
* must also add it to contrib/scripts/asterisk.ldap-schema,
|
||||
|
@ -5146,18 +5150,38 @@ static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr
|
|||
* and to configs/res_ldap.conf.sample as described in
|
||||
* bugs 15156 and 15895
|
||||
*/
|
||||
if (fc) {
|
||||
ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr,
|
||||
"port", port, "regseconds", regseconds,
|
||||
deprecated_username ? "username" : "defaultuser", defaultuser,
|
||||
"useragent", useragent, "lastms", str_lastms,
|
||||
fc, fullcontact, syslabel, sysname, SENTINEL); /* note fc and syslabel _can_ be NULL */
|
||||
|
||||
/* This is ugly, we need something better ;-) */
|
||||
if (sip_cfg.rtsave_path) {
|
||||
if (fc) {
|
||||
ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr,
|
||||
"port", port, "regseconds", regseconds,
|
||||
deprecated_username ? "username" : "defaultuser", defaultuser,
|
||||
"useragent", useragent, "lastms", str_lastms,
|
||||
"path", path, /* Path data can be NULL */
|
||||
fc, fullcontact, syslabel, sysname, SENTINEL); /* note fc and syslabel _can_ be NULL */
|
||||
} else {
|
||||
ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr,
|
||||
"port", port, "regseconds", regseconds,
|
||||
"useragent", useragent, "lastms", str_lastms,
|
||||
deprecated_username ? "username" : "defaultuser", defaultuser,
|
||||
"path", path, /* Path data can be NULL */
|
||||
syslabel, sysname, SENTINEL); /* note syslabel _can_ be NULL */
|
||||
}
|
||||
} else {
|
||||
ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr,
|
||||
"port", port, "regseconds", regseconds,
|
||||
"useragent", useragent, "lastms", str_lastms,
|
||||
deprecated_username ? "username" : "defaultuser", defaultuser,
|
||||
syslabel, sysname, SENTINEL); /* note syslabel _can_ be NULL */
|
||||
if (fc) {
|
||||
ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr,
|
||||
"port", port, "regseconds", regseconds,
|
||||
deprecated_username ? "username" : "defaultuser", defaultuser,
|
||||
"useragent", useragent, "lastms", str_lastms,
|
||||
fc, fullcontact, syslabel, sysname, SENTINEL); /* note fc and syslabel _can_ be NULL */
|
||||
} else {
|
||||
ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr,
|
||||
"port", port, "regseconds", regseconds,
|
||||
"useragent", useragent, "lastms", str_lastms,
|
||||
deprecated_username ? "username" : "defaultuser", defaultuser,
|
||||
syslabel, sysname, SENTINEL); /* note syslabel _can_ be NULL */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5252,6 +5276,10 @@ static void sip_destroy_peer(struct sip_peer *peer)
|
|||
ast_variables_destroy(peer->chanvars);
|
||||
peer->chanvars = NULL;
|
||||
}
|
||||
if (peer->path) {
|
||||
free_old_route(peer->path);
|
||||
peer->path = NULL;
|
||||
}
|
||||
|
||||
register_peer_exten(peer, FALSE);
|
||||
ast_free_acl_list(peer->acl);
|
||||
|
@ -5294,7 +5322,9 @@ static void update_peer(struct sip_peer *p, int expire)
|
|||
int rtcachefriends = ast_test_flag(&p->flags[1], SIP_PAGE2_RTCACHEFRIENDS);
|
||||
if (sip_cfg.peer_rtupdate &&
|
||||
(p->is_realtime || rtcachefriends)) {
|
||||
realtime_update_peer(p->name, &p->addr, p->username, p->fullcontact, p->useragent, expire, p->deprecated_username, p->lastms);
|
||||
char path[SIPBUFSIZE * 2];
|
||||
make_route_list(p->path, path, sizeof(path));
|
||||
realtime_update_peer(p->name, &p->addr, p->username, p->fullcontact, p->useragent, expire, p->deprecated_username, p->lastms, path);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5989,6 +6019,8 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __set_address_from_contact(const char *fullcontact, struct ast_sockaddr *addr, int tcp);
|
||||
|
||||
/*! \brief Create address structure from peer reference.
|
||||
* This function copies data from peer to the dialog, so we don't have to look up the peer
|
||||
* again from memory or database during the life time of the dialog.
|
||||
|
@ -6029,6 +6061,12 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
|
|||
dialog->rtptimeout = peer->rtptimeout;
|
||||
dialog->rtpholdtimeout = peer->rtpholdtimeout;
|
||||
dialog->rtpkeepalive = peer->rtpkeepalive;
|
||||
copy_route(&dialog->route, peer->path);
|
||||
if (dialog->route) {
|
||||
/* Parse SIP URI of first route-set hop and use it as target address */
|
||||
__set_address_from_contact(dialog->route->hop, &dialog->sa, dialog->socket.type == SIP_TRANSPORT_TLS ? 1 : 0);
|
||||
}
|
||||
|
||||
if (dialog_initialize_rtp(dialog)) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -6391,7 +6429,7 @@ static int sip_call(struct ast_channel *ast, const char *dest, int timeout)
|
|||
ast_clear_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT_T38);
|
||||
|
||||
if (p->options->transfer) {
|
||||
char buf[SIPBUFSIZE/2];
|
||||
char buf[SIPBUFSIZE / 2];
|
||||
|
||||
if (referer) {
|
||||
if (sipdebug)
|
||||
|
@ -11342,12 +11380,14 @@ static int process_sdp_a_image(const char *a, struct sip_pvt *p)
|
|||
* is supported for this dialog. */
|
||||
static int add_supported(struct sip_pvt *pvt, struct sip_request *req)
|
||||
{
|
||||
char supported_value[SIPBUFSIZE];
|
||||
int res;
|
||||
if (st_get_mode(pvt, 0) != SESSION_TIMER_MODE_REFUSE) {
|
||||
res = add_header(req, "Supported", "replaces, timer");
|
||||
} else {
|
||||
res = add_header(req, "Supported", "replaces");
|
||||
}
|
||||
|
||||
sprintf(supported_value, "replaces%s%s",
|
||||
(st_get_mode(pvt, 0) != SESSION_TIMER_MODE_REFUSE) ? ", timer" : "",
|
||||
ast_test_flag(&pvt->flags[0], SIP_USEPATH) ? ", path" : "");
|
||||
res = add_header(req, "Supported", supported_value);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -11523,12 +11563,21 @@ static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, const st
|
|||
/*! \brief Add route header into request per learned route */
|
||||
static void add_route(struct sip_request *req, struct sip_route *route)
|
||||
{
|
||||
char r[SIPBUFSIZE*2], *p;
|
||||
int n, rem = sizeof(r);
|
||||
char r[SIPBUFSIZE * 2];
|
||||
|
||||
if (!route)
|
||||
return;
|
||||
|
||||
make_route_list(route, r, sizeof(r));
|
||||
add_header(req, "Route", r);
|
||||
}
|
||||
|
||||
/*! \brief Make the comma separated list of route headers from the route list */
|
||||
static void make_route_list(struct sip_route *route, char *r, int rem)
|
||||
{
|
||||
char *p;
|
||||
int n;
|
||||
|
||||
p = r;
|
||||
for (;route ; route = route->next) {
|
||||
n = strlen(route->hop);
|
||||
|
@ -11545,7 +11594,6 @@ static void add_route(struct sip_request *req, struct sip_route *route)
|
|||
rem -= (n+2);
|
||||
}
|
||||
*p = '\0';
|
||||
add_header(req, "Route", r);
|
||||
}
|
||||
|
||||
/*! \brief Set destination from SIP URI
|
||||
|
@ -11822,6 +11870,9 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg
|
|||
snprintf(contact, sizeof(contact), "%s%s%s;expires=%d", brackets ? "" : "<", contact_uri, brackets ? "" : ">", p->expiry);
|
||||
add_header(resp, "Contact", contact); /* Not when we unregister */
|
||||
}
|
||||
if (p->method == SIP_REGISTER && ast_test_flag(&p->flags[0], SIP_USEPATH)) {
|
||||
copy_header(resp, req, "Path");
|
||||
}
|
||||
} else if (!ast_strlen_zero(p->our_contact) && resp_needs_contact(msg, p->method)) {
|
||||
add_header(resp, "Contact", p->our_contact);
|
||||
}
|
||||
|
@ -15337,6 +15388,7 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
|
|||
add_header(&req, "To", to);
|
||||
add_header(&req, "Call-ID", p->callid);
|
||||
add_header(&req, "CSeq", tmp);
|
||||
add_supported(p, &req);
|
||||
if (!ast_strlen_zero(global_useragent))
|
||||
add_header(&req, "User-Agent", global_useragent);
|
||||
|
||||
|
@ -15648,6 +15700,7 @@ static void destroy_association(struct sip_peer *peer)
|
|||
ast_update_realtime(tablename, "name", peer->name, "fullcontact", "", "ipaddr", "", "port", "", "regseconds", "0", "regserver", "", "useragent", "", "lastms", "0", SENTINEL);
|
||||
} else {
|
||||
ast_db_del("SIP/Registry", peer->name);
|
||||
ast_db_del("SIP/RegistryPath", peer->name);
|
||||
ast_db_del("SIP/PeerMethods", peer->name);
|
||||
}
|
||||
}
|
||||
|
@ -15751,6 +15804,7 @@ static int sip_poke_peer_s(const void *data)
|
|||
static void reg_source_db(struct sip_peer *peer)
|
||||
{
|
||||
char data[256];
|
||||
char path[SIPBUFSIZE * 2];
|
||||
struct ast_sockaddr sa;
|
||||
int expire;
|
||||
char full_addr[128];
|
||||
|
@ -15809,6 +15863,9 @@ static void reg_source_db(struct sip_peer *peer)
|
|||
sip_unref_peer(peer, "remove registration ref"),
|
||||
sip_ref_peer(peer, "add registration ref"));
|
||||
register_peer_exten(peer, TRUE);
|
||||
if (!ast_db_get("SIP/RegistryPath", peer->name, path, sizeof(path))) {
|
||||
build_path(NULL, peer, NULL, path);
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Save contact header for 200 OK on INVITE */
|
||||
|
@ -16104,11 +16161,21 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
|
|||
}
|
||||
}
|
||||
pvt->expiry = expire;
|
||||
if (!build_path(pvt, peer, req, NULL)) {
|
||||
/* Tell the dialog to use the Path header in the response */
|
||||
ast_set2_flag(&pvt->flags[0], 1, SIP_USEPATH);
|
||||
}
|
||||
snprintf(data, sizeof(data), "%s:%d:%s:%s", ast_sockaddr_stringify(&peer->addr),
|
||||
expire, peer->username, peer->fullcontact);
|
||||
/* We might not immediately be able to reconnect via TCP, but try caching it anyhow */
|
||||
if (!peer->rt_fromcontact || !sip_cfg.peer_rtupdate)
|
||||
if (!peer->rt_fromcontact || !sip_cfg.peer_rtupdate) {
|
||||
char path[SIPBUFSIZE * 2];
|
||||
if (peer->path) {
|
||||
make_route_list(peer->path, path, sizeof(path));
|
||||
ast_db_put("SIP/RegistryPath", peer->name, path);
|
||||
}
|
||||
ast_db_put("SIP/Registry", peer->name, data);
|
||||
}
|
||||
manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Registered\r\nAddress: %s\r\n", peer->name, ast_sockaddr_stringify(&peer->addr));
|
||||
|
||||
/* Is this a new IP address for us? */
|
||||
|
@ -16144,10 +16211,10 @@ static void free_old_route(struct sip_route *route)
|
|||
static void list_route(struct sip_route *route)
|
||||
{
|
||||
if (!route) {
|
||||
ast_verbose("list_route: no route\n");
|
||||
ast_verbose("list_route: no route/path\n");
|
||||
} else {
|
||||
for (;route; route = route->next)
|
||||
ast_verbose("list_route: hop: <%s>\n", route->hop);
|
||||
ast_verbose("list_route: route/path hop: <%s>\n", route->hop);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16277,6 +16344,134 @@ static void build_route(struct sip_pvt *p, struct sip_request *req, int backward
|
|||
}
|
||||
}
|
||||
|
||||
/*! \internal \brief Create a new route
|
||||
* \retval NULL on error
|
||||
* \retval sip_route on success
|
||||
*/
|
||||
static struct sip_route *create_route(const char *hop, struct sip_route *prev)
|
||||
{
|
||||
struct sip_route *route;
|
||||
int len;
|
||||
|
||||
if (ast_strlen_zero(hop)) {
|
||||
return NULL;
|
||||
}
|
||||
len = strlen(hop) + 1;
|
||||
|
||||
/* ast_calloc is not needed because all fields are initialized in
|
||||
* this block */
|
||||
route = ast_malloc(sizeof(*route) + len);
|
||||
if (!route) {
|
||||
return NULL;
|
||||
}
|
||||
ast_copy_string(route->hop, hop, len);
|
||||
|
||||
route->next = NULL;
|
||||
if (prev) {
|
||||
prev->next = route;
|
||||
}
|
||||
return route;
|
||||
}
|
||||
|
||||
/*! \internal \brief copy route-set
|
||||
* \retval non-zero on failure
|
||||
* \retval 0 on success
|
||||
*/
|
||||
static int copy_route(struct sip_route **dst, const struct sip_route *src)
|
||||
{
|
||||
struct sip_route *thishop, *head, *tail;
|
||||
|
||||
/* Build a tailq, then assign it to **d when done. */
|
||||
head = NULL;
|
||||
tail = head;
|
||||
for (; src; src = src->next) {
|
||||
thishop = create_route(src->hop, tail);
|
||||
if (!thishop) {
|
||||
return -1;
|
||||
}
|
||||
if (!head) {
|
||||
head = thishop;
|
||||
}
|
||||
tail = thishop;
|
||||
|
||||
ast_debug(2, "copy_route: copied hop: <%s>\n", thishop->hop);
|
||||
}
|
||||
*dst = head;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Build route list from Path header
|
||||
* RFC 3327 requires that the Path header contains SIP URIs with lr paramter.
|
||||
* Thus, we do not care about strict routing SIP routers
|
||||
*/
|
||||
static int build_path(struct sip_pvt *p, struct sip_peer *peer, struct sip_request *req, char *pathbuf)
|
||||
{
|
||||
struct sip_route *thishop, *head, *tail;
|
||||
int start = 0;
|
||||
int len;
|
||||
char *pr;
|
||||
|
||||
if (peer->path) {
|
||||
free_old_route(peer->path);
|
||||
peer->path = NULL;
|
||||
}
|
||||
|
||||
if (!ast_test_flag(&peer->flags[0], SIP_USEPATH)) {
|
||||
ast_debug(2, "build_path: do not use Path headers\n");
|
||||
return -1;
|
||||
}
|
||||
ast_debug(2, "build_path: try to build pre-loaded route-set by parsing Path headers\n");
|
||||
|
||||
/* Build a tailq, then assign it to peer->path when done. */
|
||||
head = NULL;
|
||||
tail = head;
|
||||
/* 1st we pass through all the hops in any Path headers */
|
||||
for (;;) {
|
||||
/* Either loop over the request's Path headers or parse the buffer */
|
||||
if (req) {
|
||||
pr = ast_strdupa(__get_header(req, "Path", &start));
|
||||
if (*pr == '\0') {
|
||||
break;
|
||||
}
|
||||
} else if (pathbuf) {
|
||||
if (start == 0) {
|
||||
pr = ast_strdupa(pathbuf);
|
||||
start++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
for (; (pr = strchr(pr, '<')) ; pr += (len + 1)) {
|
||||
/* Parse out each route entry */
|
||||
++pr;
|
||||
len = strcspn(pr, ">");
|
||||
*(pr + len) = '\0';
|
||||
thishop = create_route(pr, tail);
|
||||
if (!thishop) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!head) {
|
||||
head = thishop;
|
||||
}
|
||||
tail = thishop;
|
||||
ast_debug(2, "build_path: Path hop: <%s>\n", thishop->hop);
|
||||
}
|
||||
}
|
||||
|
||||
/* Store as new route */
|
||||
peer->path = head;
|
||||
|
||||
/* For debugging dump what we ended up with */
|
||||
if (p && sip_debug_test_pvt(p)) {
|
||||
list_route(peer->path);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief builds the sip_pvt's nonce field which is used for the authentication
|
||||
* challenge. When forceupdate is not set, the nonce is only updated if
|
||||
* the current one is stale. In this case, a stalenonce is one which
|
||||
|
@ -19984,6 +20179,20 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
|
|||
ast_cli(fd, " Ign SDP ver : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_IGNORESDPVERSION)));
|
||||
ast_cli(fd, " Trust RPID : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[0], SIP_TRUSTRPID)));
|
||||
ast_cli(fd, " Send RPID : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[0], SIP_SENDRPID)));
|
||||
ast_cli(fd, " Path support : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[0], SIP_USEPATH)));
|
||||
ast_cli(fd, " Path : ");
|
||||
if (!peer->path) {
|
||||
ast_cli(fd, "N/A\n");
|
||||
} else {
|
||||
struct sip_route *r = peer->path;
|
||||
int first = 1;
|
||||
while (r) {
|
||||
ast_cli(fd, "%s<%s>", first ? "" : ", ", r->hop);
|
||||
first = 0;
|
||||
r = r->next;
|
||||
}
|
||||
ast_cli(fd, "\n");
|
||||
}
|
||||
ast_cli(fd, " Subscriptions: %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_ALLOWSUBSCRIBE)));
|
||||
ast_cli(fd, " Overlap dial : %s\n", allowoverlap2str(ast_test_flag(&peer->flags[1], SIP_PAGE2_ALLOWOVERLAP)));
|
||||
if (peer->outboundproxy)
|
||||
|
@ -20577,6 +20786,7 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
|
|||
ast_cli(a->fd, " Allow promisc. redir: %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[0], SIP_PROMISCREDIR)));
|
||||
ast_cli(a->fd, " Enable call counters: %s\n", AST_CLI_YESNO(global_callcounter));
|
||||
ast_cli(a->fd, " SIP domain support: %s\n", AST_CLI_YESNO(!AST_LIST_EMPTY(&domain_list)));
|
||||
ast_cli(a->fd, " Path support : %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[0], SIP_USEPATH)));
|
||||
ast_cli(a->fd, " Realm. auth: %s\n", AST_CLI_YESNO(credentials != NULL));
|
||||
if (credentials) {
|
||||
struct sip_auth *auth;
|
||||
|
@ -20750,6 +20960,7 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
|
|||
ast_cli(a->fd, " Update: %s\n", AST_CLI_YESNO(sip_cfg.peer_rtupdate));
|
||||
ast_cli(a->fd, " Ignore Reg. Expire: %s\n", AST_CLI_YESNO(sip_cfg.ignore_regexpire));
|
||||
ast_cli(a->fd, " Save sys. name: %s\n", AST_CLI_YESNO(sip_cfg.rtsave_sysname));
|
||||
ast_cli(a->fd, " Save path header: %s\n", AST_CLI_YESNO(sip_cfg.rtsave_path));
|
||||
ast_cli(a->fd, " Auto Clear: %d (%s)\n", sip_cfg.rtautoclear, ast_test_flag(&global_flags[1], SIP_PAGE2_RTAUTOCLEAR) ? "Enabled" : "Disabled");
|
||||
}
|
||||
ast_cli(a->fd, "\n----\n");
|
||||
|
@ -23342,7 +23553,7 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res
|
|||
{
|
||||
int expires, expires_ms;
|
||||
struct sip_registry *r;
|
||||
r=p->registry;
|
||||
r = p->registry;
|
||||
|
||||
switch (resp) {
|
||||
case 401: /* Unauthorized */
|
||||
|
@ -29492,6 +29703,11 @@ static int sip_poke_peer(struct sip_peer *peer, int force)
|
|||
ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
|
||||
ast_copy_flags(&p->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
|
||||
ast_copy_flags(&p->flags[2], &peer->flags[2], SIP_PAGE3_FLAGS_TO_COPY);
|
||||
copy_route(&p->route, peer->path);
|
||||
if (p->route) {
|
||||
/* Parse SIP URI of first route-set hop and use it as target address */
|
||||
__set_address_from_contact(p->route->hop, &p->sa, p->socket.type == SIP_TRANSPORT_TLS ? 1 : 0);
|
||||
}
|
||||
|
||||
/* Send OPTIONs to peer's fullcontact */
|
||||
if (!ast_strlen_zero(peer->fullcontact)) {
|
||||
|
@ -29946,6 +30162,9 @@ static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask
|
|||
if (!strcasecmp(v->name, "trustrpid")) {
|
||||
ast_set_flag(&mask[0], SIP_TRUSTRPID);
|
||||
ast_set2_flag(&flags[0], ast_true(v->value), SIP_TRUSTRPID);
|
||||
} else if (!strcasecmp(v->name, "supportpath")) {
|
||||
ast_set_flag(&mask[0], SIP_USEPATH);
|
||||
ast_set2_flag(&flags[0], ast_true(v->value), SIP_USEPATH);
|
||||
} else if (!strcasecmp(v->name, "sendrpid")) {
|
||||
ast_set_flag(&mask[0], SIP_SENDRPID);
|
||||
if (!strcasecmp(v->value, "pai")) {
|
||||
|
@ -31528,6 +31747,8 @@ static int reload_config(enum channelreloadreason reason)
|
|||
ast_set2_flag(&global_flags[1], ast_true(v->value), SIP_PAGE2_RTCACHEFRIENDS);
|
||||
} else if (!strcasecmp(v->name, "rtsavesysname")) {
|
||||
sip_cfg.rtsave_sysname = ast_true(v->value);
|
||||
} else if (!strcasecmp(v->name, "rtsavepath")) {
|
||||
sip_cfg.rtsave_path = ast_true(v->value);
|
||||
} else if (!strcasecmp(v->name, "rtupdate")) {
|
||||
sip_cfg.peer_rtupdate = ast_true(v->value);
|
||||
} else if (!strcasecmp(v->name, "ignoreregexpire")) {
|
||||
|
|
|
@ -294,6 +294,7 @@
|
|||
#define SIP_PROG_INBAND_NO (1 << 25)
|
||||
#define SIP_PROG_INBAND_YES (2 << 25)
|
||||
|
||||
#define SIP_USEPATH (1 << 27) /*!< GDP: Trust and use incoming Path headers? */
|
||||
#define SIP_SENDRPID (3 << 29) /*!< DP: Remote Party-ID Support */
|
||||
#define SIP_SENDRPID_NO (0 << 29)
|
||||
#define SIP_SENDRPID_PAI (1 << 29) /*!< Use "P-Asserted-Identity" for rpid */
|
||||
|
@ -304,7 +305,7 @@
|
|||
#define SIP_FLAGS_TO_COPY \
|
||||
(SIP_PROMISCREDIR | SIP_TRUSTRPID | SIP_SENDRPID | SIP_DTMF | SIP_REINVITE | \
|
||||
SIP_PROG_INBAND | SIP_USECLIENTCODE | SIP_NAT_FORCE_RPORT | SIP_G726_NONSTANDARD | \
|
||||
SIP_USEREQPHONE | SIP_INSECURE)
|
||||
SIP_USEREQPHONE | SIP_INSECURE | SIP_USEPATH)
|
||||
/*@}*/
|
||||
|
||||
/*! \name SIPflags2
|
||||
|
@ -737,6 +738,7 @@ struct __show_chan_arg {
|
|||
struct sip_settings {
|
||||
int peer_rtupdate; /*!< G: Update database with registration data for peer? */
|
||||
int rtsave_sysname; /*!< G: Save system name at registration? */
|
||||
int rtsave_path; /*!< G: Save path header on registration */
|
||||
int ignore_regexpire; /*!< G: Ignore expiration of peer */
|
||||
int rtautoclear; /*!< Realtime ?? */
|
||||
int directrtpsetup; /*!< Enable support for Direct RTP setup (no re-invites) */
|
||||
|
@ -1368,6 +1370,7 @@ struct sip_peer {
|
|||
int timer_t1; /*!< The maximum T1 value for the peer */
|
||||
int timer_b; /*!< The maximum timer B (transaction timeouts) */
|
||||
int fromdomainport; /*!< The From: domain port */
|
||||
struct sip_route *path; /*!< Head of linked list of out-of-dialog outgoing routing steps (fm Path headers) */
|
||||
|
||||
/*XXX Seems like we suddenly have two flags with the same content. Why? To be continued... */
|
||||
enum sip_peer_type type; /*!< Distinguish between "user" and "peer" types. This is used solely for CLI and manager commands */
|
||||
|
|
|
@ -121,6 +121,7 @@ ipaddr = AstAccountIPAddress
|
|||
defaultuser = AstAccountDefaultUser
|
||||
regserver = AstAccountRegistrationServer
|
||||
lastms = AstAccountLastQualifyMilliseconds
|
||||
supportpath = AstAccountPathSupport
|
||||
additionalFilter=(objectClass=AsteriskSIPUser)
|
||||
|
||||
;
|
||||
|
|
|
@ -442,6 +442,21 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
|
|||
;outboundproxy=[2001:db8::1]:5062 ; IPv6 address literal with explicit port
|
||||
; ; (could also be tcp,udp) - defining transports on the proxy line only
|
||||
; ; applies for the global proxy, otherwise use the transport= option
|
||||
|
||||
;supportpath=yes ; This activates parsing and handling of Path header as defined in RFC 3327. This enables
|
||||
; Asterisk to route outgoing out-of-dialog requests via a set of proxies by using a pre-loaded
|
||||
; route-set defined by the Path headers in the REGISTER request.
|
||||
; NOTE: There are multiple things to consider with this setting:
|
||||
; * As this influences routing of SIP requests make sure to not trust Path headers provided
|
||||
; by the user's SIP client (the proxy in front of Asterisk should remove existing user
|
||||
; provided Path headers).
|
||||
; * When a peer has both a path and outboundproxy set, the path will be added to Route: header
|
||||
; but routing to next hop is done using the outboundproxy.
|
||||
; * If set globally, not only will all peers use the Path header, but outbound REGISTER
|
||||
; requests from Asterisk will add path to the Supported header.
|
||||
|
||||
;rtsavepath=yes ; If using dynamic realtime, store the path headers
|
||||
|
||||
;matchexternaddrlocally = yes ; Only substitute the externaddr or externhost setting if it matches
|
||||
; your localnet setting. Unless you have some sort of strange network
|
||||
; setup you will not need to enable this.
|
||||
|
|
|
@ -79,6 +79,7 @@ CREATE TABLE IF NOT EXISTS `sippeers` (
|
|||
`callingpres` enum('allowed_not_screened','allowed_passed_screen','allowed_failed_screen','allowed','prohib_not_screened','prohib_passed_screen','prohib_failed_screen','prohib') DEFAULT NULL,
|
||||
`mohinterpret` varchar(40) DEFAULT NULL,
|
||||
`mohsuggest` varchar(40) DEFAULT NULL,
|
||||
`path` varchar(256) DEFAULT NULL,
|
||||
`parkinglot` varchar(40) DEFAULT NULL,
|
||||
`hasvoicemail` enum('yes','no') DEFAULT NULL,
|
||||
`subscribemwi` enum('yes','no') DEFAULT NULL,
|
||||
|
@ -90,6 +91,7 @@ CREATE TABLE IF NOT EXISTS `sippeers` (
|
|||
`ignoresdpversion` enum('yes','no') DEFAULT NULL,
|
||||
`allowtransfer` enum('yes','no') DEFAULT NULL,
|
||||
`dynamic` enum('yes','no') DEFAULT NULL,
|
||||
`supportpath` enum('yes','no') DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `name` (`name`),
|
||||
KEY `ipaddr` (`ipaddr`,`port`),
|
||||
|
|
|
@ -38,6 +38,7 @@ amaflags character varying(7),
|
|||
callgroup character varying(10),
|
||||
callerid character varying(80),
|
||||
canreinvite character varying(3) DEFAULT 'yes',
|
||||
supportpath character varying(3) DEFAULT 'no',
|
||||
context character varying(80),
|
||||
defaultip character varying(15),
|
||||
dtmfmode character varying(7),
|
||||
|
@ -70,6 +71,7 @@ cancallforward character varying(3) DEFAULT 'yes',
|
|||
lastms integer DEFAULT 0 NOT NULL,
|
||||
defaultuser character varying(80),
|
||||
fullcontact character varying(80),
|
||||
path character varying(256),
|
||||
regserver character varying(30),
|
||||
useragent character varying(40),
|
||||
callbackextension character varying(40)
|
||||
|
|
|
@ -112,7 +112,7 @@ objectIdentifier AstAccountSetVar AstAttrType:66
|
|||
objectIdentifier AstAccountAllowOverlap AstAttrType:67
|
||||
objectIdentifier AstAccountVideoSupport AstAttrType:68
|
||||
objectIdentifier AstAccountIgnoreSDPVersion AstAttrType:69
|
||||
|
||||
objectIdentifier AstAccountPathSupport AstAttrType:70
|
||||
|
||||
#############################################################################
|
||||
# Object Class OIDs
|
||||
|
@ -640,6 +640,13 @@ attributetype ( AstAccountIgnoreSDPVersion
|
|||
SUBSTR caseIgnoreSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
|
||||
|
||||
attributetype ( AstAccountPathSupport
|
||||
NAME 'AstAccountPathSupport'
|
||||
DESC 'Asterisk account support Path RFC 3327'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
|
||||
|
||||
#############################################################################
|
||||
# Object Class definitions
|
||||
#
|
||||
|
@ -762,7 +769,8 @@ objectclass ( AsteriskSIPUser
|
|||
AstAccountTransport $
|
||||
AstAccountType $
|
||||
AstAccountUserAgent $
|
||||
AstAccountVideoSupport
|
||||
AstAccountVideoSupport $
|
||||
AstAccountPathSupport
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -108,6 +108,7 @@ olcObjectIdentifier: AstAccountSetVar AstAttrType:66
|
|||
olcObjectIdentifier: AstAccountAllowOverlap AstAttrType:67
|
||||
olcObjectIdentifier: AstAccountVideoSupport AstAttrType:68
|
||||
olcObjectIdentifier: AstAccountIgnoreSDPVersion AstAttrType:69
|
||||
olcObjectIdentifier: AstAccountPathSupport AstAttrType:70
|
||||
#
|
||||
#
|
||||
#############################################################################
|
||||
|
@ -636,6 +637,13 @@ olcAttributeTypes: ( AstAccountIgnoreSDPVersion
|
|||
SUBSTR caseIgnoreSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
|
||||
#
|
||||
olcAttributeTypes: ( AstAccountPathSupport
|
||||
NAME 'AstAccountPathSupport'
|
||||
DESC 'Asterisk account support Path RFC 3327'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
|
||||
#
|
||||
#############################################################################
|
||||
# Object Class definitions
|
||||
#
|
||||
|
@ -758,7 +766,8 @@ olcObjectClasses: ( AsteriskSIPUser
|
|||
AstAccountTransport $
|
||||
AstAccountType $
|
||||
AstAccountUserAgent $
|
||||
AstAccountVideoSupport
|
||||
AstAccountVideoSupport $
|
||||
AstAccountPathSupport
|
||||
)
|
||||
)
|
||||
#
|
||||
|
|
Loading…
Reference in New Issue