Add RFC 3327 Path header support to chan_sip
authorMatthew Jordan <mjordan@digium.com>
Tue, 5 Mar 2013 13:14:43 +0000 (13:14 +0000)
committerMatthew Jordan <mjordan@digium.com>
Tue, 5 Mar 2013 13:14:43 +0000 (13:14 +0000)
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

CHANGES
CREDITS
channels/chan_sip.c
channels/sip/include/sip.h
configs/res_ldap.conf.sample
configs/sip.conf.sample
contrib/realtime/mysql/sippeers.sql
contrib/realtime/postgresql/realtime.sql
contrib/scripts/asterisk.ldap-schema
contrib/scripts/asterisk.ldif

diff --git a/CHANGES b/CHANGES
index 2ef538e..6b49cb6 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -50,6 +50,13 @@ chan_mobile
 
  * Added ECAM command support for Sony Ericsson phones.
 
 
  * 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
 -------------------
 
 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.
 
    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 --------------------
 ------------------------------------------------------------------------------
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 10 to Asterisk 11 --------------------
 ------------------------------------------------------------------------------
diff --git a/CREDITS b/CREDITS
index aa3c1ab..a767396 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -22,7 +22,7 @@
        * John Todd, TalkPlus, Inc.  and JR Richardson, Ntegrated Solutions. 
                for funding the development of SIP Session Timers support.
 
        * 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�m, for funding work with videocaps, 
                T.140 RED, originate with video/text and many more 
                contributions.
 
                T.140 RED, originate with video/text and many more 
                contributions.
 
@@ -54,7 +54,7 @@
 
 === HARDWARE DONORS === 
 
 
 === 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.  
 
        * Thanks to QuickNet Technologies for their donation of an Internet
                PhoneJack and Linejack card to the project.  
        * Thanks to VoipSupply for their donation of Sipura ATAs to the project
                for T.38 testing. (http://www.voipsupply.com)
 
        * 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 ===
 
        * 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
 
        * Jim Dixon - Zapata Telephony and app_rpt
                http://www.zapatatelephony.org/app_rpt.html
                ControlPlayback, and multiple bug fixes See 
                http://voip-info.org/users/view/sergee serg(AT)voipsolutions.ru
 
                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
 
        * Moises Silva (moy) - for writing LibOpenR2, and providing support for
                it in chan_dahdi moises.silva(AT)gmail.com
                cdr_tds rewrite, countless other improvements, fixes, and good
                ideas. sean(AT)malleable.com
 
                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�b - Calendaring support for Exchange Server 2007+ via 
                Exchange Web Services.
 
        * University of Oslo (uio.no), Norway - SIP Max-Forwards setting 
                Exchange Web Services.
 
        * University of Oslo (uio.no), Norway - SIP Max-Forwards setting 
index 1adf7a0..9538441 100644 (file)
@@ -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 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);
 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 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);
 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 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);
 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.
 */
        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];
 {
        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));
 
        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;
                sysname = NULL;
-       else if (sip_cfg.rtsave_sysname)
+       } else if (sip_cfg.rtsave_sysname) {
                syslabel = "regserver";
                syslabel = "regserver";
+       }
 
        /* XXX IMPORTANT: Anytime you add a new parameter to be updated, you
          *  must also add it to contrib/scripts/asterisk.ldap-schema,
 
        /* 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
          */
          *  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 {
        } 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;
        }
                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);
 
        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)) {
        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;
 }
 
        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.
 /*! \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;
        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;
        }
        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) {
        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)
 
                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)
 {
  *  is supported for this dialog. */
 static int add_supported(struct sip_pvt *pvt, struct sip_request *req)
 {
+       char supported_value[SIPBUFSIZE];
        int res;
        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;
 }
 
        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)
 {
 /*! \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;
 
 
        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);
        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';
                rem -= (n+2);
        }
        *p = '\0';
-       add_header(req, "Route", r);
 }
 
 /*! \brief Set destination from SIP URI
 }
 
 /*! \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 */
                }
                        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);
        }
        } 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_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);
 
        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_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);
                }
        }
                        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];
 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];
        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);
                        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 */
 }
 
 /*! \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;
                }
        }
        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 */
        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);
                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? */
        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) {
 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)
        } 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
 /*! \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, "  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)
                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, "  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;
        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, "  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");
                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;
 {
        int expires, expires_ms;
        struct sip_registry *r;
-       r=p->registry;
+       r = p->registry;
        
        switch (resp) {
        case 401:       /* Unauthorized */
        
        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);
        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)) {
 
        /* 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);
        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")) {
        } 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);
                        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")) {
                } else if (!strcasecmp(v->name, "rtupdate")) {
                        sip_cfg.peer_rtupdate = ast_true(v->value);
                } else if (!strcasecmp(v->name, "ignoreregexpire")) {
index f74446a..3af35b0 100644 (file)
 #define SIP_PROG_INBAND_NO     (1 << 25)
 #define SIP_PROG_INBAND_YES    (2 << 25)
 
 #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 */
 #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 */
 #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 | \
 #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
 /*@}*/
 
 /*! \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? */
 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) */
        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 */
        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 */
 
        /*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 */
index 9a2accb..ac345cd 100644 (file)
@@ -121,6 +121,7 @@ ipaddr = AstAccountIPAddress
 defaultuser = AstAccountDefaultUser
 regserver = AstAccountRegistrationServer
 lastms = AstAccountLastQualifyMilliseconds
 defaultuser = AstAccountDefaultUser
 regserver = AstAccountRegistrationServer
 lastms = AstAccountLastQualifyMilliseconds
+supportpath = AstAccountPathSupport
 additionalFilter=(objectClass=AsteriskSIPUser)
 
 ;
 additionalFilter=(objectClass=AsteriskSIPUser)
 
 ;
index d54398c..a0ceabe 100644 (file)
@@ -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
 ;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.
 ;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.
index e0dbe1a..1b01b28 100644 (file)
@@ -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,
       `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,
       `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,
       `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`),
       PRIMARY KEY (`id`),
       UNIQUE KEY `name` (`name`),
       KEY `ipaddr` (`ipaddr`,`port`),
index cba8d38..96cbb16 100644 (file)
@@ -38,6 +38,7 @@ amaflags character varying(7),
 callgroup character varying(10),
 callerid character varying(80),
 canreinvite character varying(3) DEFAULT 'yes',
 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),
 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),
 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)
 regserver character varying(30),
 useragent character varying(40),
 callbackextension character varying(40)
index 3d81a1b..85f9103 100644 (file)
@@ -112,7 +112,7 @@ objectIdentifier AstAccountSetVar AstAttrType:66
 objectIdentifier AstAccountAllowOverlap AstAttrType:67
 objectIdentifier AstAccountVideoSupport AstAttrType:68
 objectIdentifier AstAccountIgnoreSDPVersion AstAttrType:69
 objectIdentifier AstAccountAllowOverlap AstAttrType:67
 objectIdentifier AstAccountVideoSupport AstAttrType:68
 objectIdentifier AstAccountIgnoreSDPVersion AstAttrType:69
-
+objectIdentifier AstAccountPathSupport AstAttrType:70
 
 #############################################################################
 # Object Class OIDs
 
 #############################################################################
 # Object Class OIDs
@@ -640,6 +640,13 @@ attributetype ( AstAccountIgnoreSDPVersion
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
 
         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
 #
 #############################################################################
 # Object Class definitions
 #
@@ -762,7 +769,8 @@ objectclass ( AsteriskSIPUser
         AstAccountTransport $
         AstAccountType $ 
         AstAccountUserAgent $  
         AstAccountTransport $
         AstAccountType $ 
         AstAccountUserAgent $  
-        AstAccountVideoSupport
+        AstAccountVideoSupport $
+        AstAccountPathSupport
     )
     )
 
     )
     )
 
index 0546cdd..5621057 100644 (file)
@@ -108,6 +108,7 @@ olcObjectIdentifier: AstAccountSetVar AstAttrType:66
 olcObjectIdentifier: AstAccountAllowOverlap AstAttrType:67
 olcObjectIdentifier: AstAccountVideoSupport AstAttrType:68
 olcObjectIdentifier: AstAccountIgnoreSDPVersion AstAttrType:69
 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)
 #
         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
 #
 #############################################################################
 # Object Class definitions
 #
@@ -758,7 +766,8 @@ olcObjectClasses: ( AsteriskSIPUser
         AstAccountTransport $
         AstAccountType $
         AstAccountUserAgent $
         AstAccountTransport $
         AstAccountType $
         AstAccountUserAgent $
-        AstAccountVideoSupport
+        AstAccountVideoSupport $
+        AstAccountPathSupport
     )
     )
 #
     )
     )
 #