mirror of https://github.com/asterisk/asterisk
This change implements a few different generic things which were brought on by Google Voice SIP. 1. The concept of flow transports have been introduced. These are configurable transports in pjsip.conf which can be used to reference a flow of signaling to a target. These have runtime configuration that can be changed by the signaling itself (such as Service-Routes and P-Preferred-Identity). When used these guarantee an individual connection (in the case of TCP or TLS) even if multiple flow transports exist to the same target. 2. Service-Routes (RFC 3608) support has been added to the outbound registration module which when received will be stored on the flow transport and used for requests referencing it. 3. P-Associated-URI / P-Preferred-Identity (RFC 3325) support has been added to the outbound registration module. If a P-Associated-URI header is received it will be used on requests as the P-Preferred-Identity. 4. Configurable outbound extension support has been added to the outbound registration module. When set the extension will be placed in the Supported header. 5. Header parameters can now be configured on an outbound registration which will be placed in the Contact header. 6. Google specific OAuth / Bearer token authentication (draft-ietf-sipcore-sip-authn-02) has been added to the outbound registration module. All functionality changes are controlled by pjsip.conf configuration options and do not affect non-configured pjsip endpoints otherwise. ASTERISK-27971 #close Change-Id: Id214c2d1c550a41fcf564b7df8f3da7be565bd58pull/11/head
parent
51b5f0f193
commit
37b2e68628
@ -0,0 +1,115 @@
|
||||
"""add pjsip google voice sip options
|
||||
|
||||
Revision ID: 465f47f880be
|
||||
Revises: 7f85dd44c775
|
||||
Create Date: 2018-09-25 17:26:12.892161
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '465f47f880be'
|
||||
down_revision = '7f85dd44c775'
|
||||
|
||||
from alembic import op
|
||||
from sqlalchemy.dialects.postgresql import ENUM
|
||||
import sqlalchemy as sa
|
||||
|
||||
AST_BOOL_NAME = 'ast_bool_values'
|
||||
# We'll just ignore the n/y and f/t abbreviations as Asterisk does not write
|
||||
# those aliases.
|
||||
AST_BOOL_VALUES = [ '0', '1',
|
||||
'off', 'on',
|
||||
'false', 'true',
|
||||
'no', 'yes' ]
|
||||
|
||||
PJSIP_TRANSPORT_PROTOCOL_OLD_NAME = 'pjsip_transport_protocol_values'
|
||||
PJSIP_TRANSPORT_PROTOCOL_NEW_NAME = 'pjsip_transport_protocol_values_v2'
|
||||
|
||||
PJSIP_TRANSPORT_PROTOCOL_OLD_VALUES = ['udp', 'tcp', 'tls', 'ws', 'wss']
|
||||
PJSIP_TRANSPORT_PROTOCOL_NEW_VALUES = ['udp', 'tcp', 'tls', 'ws', 'wss', 'flow']
|
||||
|
||||
PJSIP_TRANSPORT_PROTOCOL_OLD_TYPE = sa.Enum(*PJSIP_TRANSPORT_PROTOCOL_OLD_VALUES,
|
||||
name=PJSIP_TRANSPORT_PROTOCOL_OLD_NAME)
|
||||
PJSIP_TRANSPORT_PROTOCOL_NEW_TYPE = sa.Enum(*PJSIP_TRANSPORT_PROTOCOL_NEW_VALUES,
|
||||
name=PJSIP_TRANSPORT_PROTOCOL_NEW_NAME)
|
||||
|
||||
PJSIP_AUTH_TYPE_OLD_NAME = 'pjsip_auth_type_values'
|
||||
PJSIP_AUTH_TYPE_NEW_NAME = 'pjsip_auth_type_values_v2'
|
||||
|
||||
PJSIP_AUTH_TYPE_OLD_VALUES = ['md5', 'userpass']
|
||||
PJSIP_AUTH_TYPE_NEW_VALUES = ['md5', 'userpass', 'google_oauth']
|
||||
|
||||
PJSIP_AUTH_TYPE_OLD_TYPE = sa.Enum(*PJSIP_AUTH_TYPE_OLD_VALUES,
|
||||
name=PJSIP_AUTH_TYPE_OLD_NAME)
|
||||
PJSIP_AUTH_TYPE_NEW_TYPE = sa.Enum(*PJSIP_AUTH_TYPE_NEW_VALUES,
|
||||
name=PJSIP_AUTH_TYPE_NEW_NAME)
|
||||
|
||||
|
||||
def upgrade():
|
||||
if op.get_context().bind.dialect.name == 'postgresql':
|
||||
enum = PJSIP_TRANSPORT_PROTOCOL_NEW_TYPE
|
||||
enum.create(op.get_bind(), checkfirst=False)
|
||||
op.execute('ALTER TABLE ps_transports ALTER COLUMN protocol TYPE'
|
||||
' ' + PJSIP_TRANSPORT_PROTOCOL_NEW_NAME + ' USING'
|
||||
' protocol::text::' + PJSIP_TRANSPORT_PROTOCOL_NEW_NAME)
|
||||
ENUM(name=PJSIP_TRANSPORT_PROTOCOL_OLD_NAME).drop(op.get_bind(), checkfirst=False)
|
||||
|
||||
enum = PJSIP_AUTH_TYPE_NEW_TYPE
|
||||
enum.create(op.get_bind(), checkfirst=False)
|
||||
op.execute('ALTER TABLE ps_auths ALTER COLUMN auth_type TYPE'
|
||||
' ' + PJSIP_AUTH_TYPE_NEW_NAME + ' USING'
|
||||
' auth_type::text::' + PJSIP_AUTH_TYPE_NEW_NAME)
|
||||
ENUM(name=PJSIP_AUTH_TYPE_OLD_NAME).drop(op.get_bind(), checkfirst=False)
|
||||
else:
|
||||
op.alter_column('ps_transports', 'protocol',
|
||||
type_=PJSIP_TRANSPORT_PROTOCOL_NEW_TYPE,
|
||||
existing_type=PJSIP_TRANSPORT_PROTOCOL_OLD_TYPE)
|
||||
op.alter_column('ps_auths', 'auth_type',
|
||||
type_=PJSIP_AUTH_TYPE_NEW_TYPE,
|
||||
existing_type=PJSIP_AUTH_TYPE_OLD_TYPE)
|
||||
|
||||
# ast_bool_values have already been created, so use postgres enum object
|
||||
# type to get around "already created" issue - works okay with mysql
|
||||
ast_bool_values = ENUM(*AST_BOOL_VALUES, name=AST_BOOL_NAME, create_type=False)
|
||||
|
||||
op.add_column('ps_registrations', sa.Column('support_outbound', ast_bool_values))
|
||||
op.add_column('ps_registrations', sa.Column('contact_header_params', sa.String(255)))
|
||||
|
||||
op.add_column('ps_auths', sa.Column('refresh_token', sa.String(255)))
|
||||
op.add_column('ps_auths', sa.Column('oauth_clientid', sa.String(255)))
|
||||
op.add_column('ps_auths', sa.Column('oauth_secret', sa.String(255)))
|
||||
|
||||
def downgrade():
|
||||
# First we need to ensure that columns are not using the enum values
|
||||
# that are going away.
|
||||
op.execute("UPDATE ps_transports SET protocol='udp' WHERE protocol='flow'")
|
||||
op.execute("UPDATE ps_auths SET auth_type='userpass' WHERE auth_type='google_oauth'")
|
||||
|
||||
if op.get_context().bind.dialect.name == 'postgresql':
|
||||
enum = PJSIP_TRANSPORT_PROTOCOL_OLD_TYPE
|
||||
enum.create(op.get_bind(), checkfirst=False)
|
||||
op.execute('ALTER TABLE ps_transports ALTER COLUMN protocol TYPE'
|
||||
' ' + PJSIP_TRANSPORT_PROTOCOL_OLD_NAME + ' USING'
|
||||
' protocol::text::' + PJSIP_TRANSPORT_PROTOCOL_OLD_NAME)
|
||||
ENUM(name=PJSIP_TRANSPORT_PROTOCOL_NEW_NAME).drop(op.get_bind(), checkfirst=False)
|
||||
|
||||
enum = PJSIP_AUTH_TYPE_OLD_TYPE
|
||||
enum.create(op.get_bind(), checkfirst=False)
|
||||
op.execute('ALTER TABLE ps_auths ALTER COLUMN auth_type TYPE'
|
||||
' ' + PJSIP_AUTH_TYPE_OLD_NAME + ' USING'
|
||||
' auth_type::text::' + PJSIP_AUTH_TYPE_OLD_NAME)
|
||||
ENUM(name=PJSIP_AUTH_TYPE_NEW_NAME).drop(op.get_bind(), checkfirst=False)
|
||||
else:
|
||||
op.alter_column('ps_transports', 'protocol',
|
||||
type_=PJSIP_TRANSPORT_PROTOCOL_OLD_TYPE,
|
||||
existing_type=PJSIP_TRANSPORT_PROTOCOL_NEW_TYPE)
|
||||
op.alter_column('ps_auths', 'auth_type',
|
||||
type_=PJSIP_AUTH_TYPE_OLD_TYPE,
|
||||
existing_type=PJSIP_AUTH_TYPE_NEW_TYPE)
|
||||
|
||||
op.drop_column('ps_registrations', 'support_outbound')
|
||||
op.drop_column('ps_registrations', 'contact_header_params')
|
||||
|
||||
op.drop_column('ps_auths', 'refresh_token')
|
||||
op.drop_column('ps_auths', 'oauth_clientid')
|
||||
op.drop_column('ps_auths', 'oauth_secret')
|
@ -0,0 +1,129 @@
|
||||
diff -x '*.o' -x '*.a' -ru a/pjsip/include/pjsip/sip_auth_msg.h b/pjsip/include/pjsip/sip_auth_msg.h
|
||||
--- a/pjsip/include/pjsip/sip_auth_msg.h 2011-05-05 02:14:19.000000000 -0400
|
||||
+++ b/pjsip/include/pjsip/sip_auth_msg.h 2018-09-14 16:42:03.986813665 -0400
|
||||
@@ -89,6 +89,23 @@
|
||||
typedef struct pjsip_pgp_credential pjsip_pgp_credential;
|
||||
|
||||
/**
|
||||
+ * This structure describe credential used in Authorization and
|
||||
+ * Proxy-Authorization header for OAuth authentication scheme.
|
||||
+ */
|
||||
+struct pjsip_oauth_credential
|
||||
+{
|
||||
+ pj_str_t realm; /**< Realm of the credential */
|
||||
+ pjsip_param other_param; /**< Other parameters. */
|
||||
+ pj_str_t username; /**< Username parameter. */
|
||||
+ pj_str_t token; /**< Token parameter. */
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * @see pjsip_oauth_credential
|
||||
+ */
|
||||
+typedef struct pjsip_oauth_credential pjsip_oauth_credential;
|
||||
+
|
||||
+/**
|
||||
* This structure describes SIP Authorization header (and also SIP
|
||||
* Proxy-Authorization header).
|
||||
*/
|
||||
@@ -106,6 +123,7 @@
|
||||
pjsip_common_credential common; /**< Common fields. */
|
||||
pjsip_digest_credential digest; /**< Digest credentials. */
|
||||
pjsip_pgp_credential pgp; /**< PGP credentials. */
|
||||
+ pjsip_oauth_credential oauth; /**< OAuth credentials. */
|
||||
} credential;
|
||||
};
|
||||
|
||||
diff -x '*.o' -x '*.a' -ru a/pjsip/include/pjsip/sip_auth_parser.h b/pjsip/include/pjsip/sip_auth_parser.h
|
||||
--- a/pjsip/include/pjsip/sip_auth_parser.h 2011-05-05 02:14:19.000000000 -0400
|
||||
+++ b/pjsip/include/pjsip/sip_auth_parser.h 2018-09-14 16:42:11.982807508 -0400
|
||||
@@ -64,6 +64,7 @@
|
||||
pjsip_FALSE_STR, /**< "false" string const. */
|
||||
pjsip_DIGEST_STR, /**< "digest" string const. */
|
||||
pjsip_PGP_STR, /**< "pgp" string const. */
|
||||
+ pjsip_BEARER_STR, /**< "bearer" string const. */
|
||||
pjsip_MD5_STR, /**< "md5" string const. */
|
||||
pjsip_AUTH_STR; /**< "auth" string const. */
|
||||
|
||||
diff -x '*.o' -x '*.a' -ru a/pjsip/src/pjsip/sip_auth_client.c b/pjsip/src/pjsip/sip_auth_client.c
|
||||
--- a/pjsip/src/pjsip/sip_auth_client.c 2017-03-31 02:02:48.000000000 -0400
|
||||
+++ b/pjsip/src/pjsip/sip_auth_client.c 2018-09-14 16:42:28.138795061 -0400
|
||||
@@ -959,13 +959,22 @@
|
||||
|
||||
hs = pjsip_authorization_hdr_create(tdata->pool);
|
||||
pj_strdup(tdata->pool, &hs->scheme, &c->scheme);
|
||||
- pj_strdup(tdata->pool, &hs->credential.digest.username,
|
||||
- &c->username);
|
||||
- pj_strdup(tdata->pool, &hs->credential.digest.realm,
|
||||
- &c->realm);
|
||||
- pj_strdup(tdata->pool, &hs->credential.digest.uri, &uri);
|
||||
- pj_strdup(tdata->pool, &hs->credential.digest.algorithm,
|
||||
- &sess->pref.algorithm);
|
||||
+ if (pj_stricmp(&c->scheme, &pjsip_BEARER_STR)==0) {
|
||||
+ pj_strdup(tdata->pool, &hs->credential.oauth.username,
|
||||
+ &c->username);
|
||||
+ pj_strdup(tdata->pool, &hs->credential.oauth.realm,
|
||||
+ &c->realm);
|
||||
+ pj_strdup(tdata->pool, &hs->credential.oauth.token,
|
||||
+ &c->data);
|
||||
+ } else { //if (pj_stricmp(&c->scheme, &pjsip_DIGEST_STR)==0)
|
||||
+ pj_strdup(tdata->pool, &hs->credential.digest.username,
|
||||
+ &c->username);
|
||||
+ pj_strdup(tdata->pool, &hs->credential.digest.realm,
|
||||
+ &c->realm);
|
||||
+ pj_strdup(tdata->pool,&hs->credential.digest.uri, &uri);
|
||||
+ pj_strdup(tdata->pool, &hs->credential.digest.algorithm,
|
||||
+ &sess->pref.algorithm);
|
||||
+ }
|
||||
|
||||
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hs);
|
||||
}
|
||||
diff -x '*.o' -x '*.a' -ru a/pjsip/src/pjsip/sip_auth_msg.c b/pjsip/src/pjsip/sip_auth_msg.c
|
||||
--- a/pjsip/src/pjsip/sip_auth_msg.c 2016-01-27 00:42:20.000000000 -0500
|
||||
+++ b/pjsip/src/pjsip/sip_auth_msg.c 2018-09-14 16:42:15.882804502 -0400
|
||||
@@ -103,6 +103,23 @@
|
||||
return -1;
|
||||
}
|
||||
|
||||
+static int print_oauth_credential(pjsip_oauth_credential *cred, char *buf,
|
||||
+ pj_size_t size)
|
||||
+{
|
||||
+ pj_ssize_t printed;
|
||||
+ char *startbuf = buf;
|
||||
+ char *endbuf = buf + size;
|
||||
+
|
||||
+ copy_advance_pair_quote_cond_always(buf, "token=", 6, cred->token,
|
||||
+ '"', '"');
|
||||
+ copy_advance_pair_quote_cond_always(buf, ", username=", 11, cred->username,
|
||||
+ '"', '"');
|
||||
+ copy_advance_pair_quote_cond_always(buf, ", realm=", 8, cred->realm,
|
||||
+ '"', '"');
|
||||
+
|
||||
+ return (int) (buf-startbuf);
|
||||
+}
|
||||
+
|
||||
static int pjsip_authorization_hdr_print( pjsip_authorization_hdr *hdr,
|
||||
char *buf, pj_size_t size)
|
||||
{
|
||||
@@ -125,6 +142,11 @@
|
||||
{
|
||||
printed = print_pgp_credential(&hdr->credential.pgp, buf, endbuf - buf);
|
||||
}
|
||||
+ else if (pj_stricmp(&hdr->scheme, &pjsip_BEARER_STR) == 0)
|
||||
+ {
|
||||
+ printed = print_oauth_credential(&hdr->credential.oauth, buf,
|
||||
+ endbuf - buf);
|
||||
+ }
|
||||
else {
|
||||
pj_assert(0);
|
||||
return -1;
|
||||
diff -x '*.o' -x '*.a' -ru a/pjsip/src/pjsip/sip_auth_parser.c b/pjsip/src/pjsip/sip_auth_parser.c
|
||||
--- a/pjsip/src/pjsip/sip_auth_parser.c 2014-06-09 22:56:56.000000000 -0400
|
||||
+++ b/pjsip/src/pjsip/sip_auth_parser.c 2018-09-14 16:42:21.418800238 -0400
|
||||
@@ -59,6 +59,7 @@
|
||||
pjsip_QUOTED_DIGEST_STR = { "\"Digest\"", 8},
|
||||
pjsip_PGP_STR = { "PGP", 3 },
|
||||
pjsip_QUOTED_PGP_STR = { "\"PGP\"", 5 },
|
||||
+ pjsip_BEARER_STR = { "Bearer", 6 },
|
||||
pjsip_MD5_STR = { "md5", 3 },
|
||||
pjsip_QUOTED_MD5_STR = { "\"md5\"", 5},
|
||||
pjsip_AUTH_STR = { "auth", 4},
|
@ -0,0 +1,102 @@
|
||||
diff -x '*.o' -x '*.a' -ru a/pjsip/include/pjsip/sip_transport.h b/pjsip/include/pjsip/sip_transport.h
|
||||
--- a/pjsip/include/pjsip/sip_transport.h 2017-02-19 20:16:58.000000000 -0500
|
||||
+++ b/pjsip/include/pjsip/sip_transport.h 2018-09-14 16:47:25.145266710 -0400
|
||||
@@ -221,12 +221,26 @@
|
||||
* application specificly request that a particular transport/listener
|
||||
* should be used to send request. This structure is used when calling
|
||||
* pjsip_tsx_set_transport() and pjsip_dlg_set_transport().
|
||||
+ *
|
||||
+ * If application disables connection reuse and wants to force creating
|
||||
+ * a new transport, it needs to consider the following couple of things:
|
||||
+ * - If it still wants to reuse an existing transport (if any), it
|
||||
+ * needs to keep a reference to that transport and specifically set
|
||||
+ * the transport to be used for sending requests.
|
||||
+ * - Delete those existing transports manually when no longer needed.
|
||||
*/
|
||||
typedef struct pjsip_tpselector
|
||||
{
|
||||
/** The type of data in the union */
|
||||
pjsip_tpselector_type type;
|
||||
|
||||
+ /**
|
||||
+ * Whether to disable reuse of an existing connection.
|
||||
+ * This setting will be ignored if (type == PJSIP_TPSELECTOR_TRANSPORT)
|
||||
+ * and transport in the union below is set.
|
||||
+ */
|
||||
+ pj_bool_t disable_connection_reuse;
|
||||
+
|
||||
/** Union representing the transport/listener criteria to be used. */
|
||||
union {
|
||||
pjsip_transport *transport;
|
||||
diff -x '*.o' -x '*.a' -ru a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c
|
||||
--- a/pjsip/src/pjsip/sip_transport.c 2017-11-07 21:58:18.000000000 -0500
|
||||
+++ b/pjsip/src/pjsip/sip_transport.c 2018-09-14 16:47:25.145266710 -0400
|
||||
@@ -2118,7 +2118,7 @@
|
||||
*/
|
||||
pjsip_transport_key key;
|
||||
int key_len;
|
||||
- pjsip_transport *transport;
|
||||
+ pjsip_transport *transport = NULL;
|
||||
|
||||
/* If listener is specified, verify that the listener type matches
|
||||
* the destination type.
|
||||
@@ -2131,17 +2131,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
- pj_bzero(&key, sizeof(key));
|
||||
- key_len = sizeof(key.type) + addr_len;
|
||||
+ if (!sel || sel->disable_connection_reuse == PJ_FALSE) {
|
||||
+ pj_bzero(&key, sizeof(key));
|
||||
+ key_len = sizeof(key.type) + addr_len;
|
||||
+
|
||||
+ /* First try to get exact destination. */
|
||||
+ key.type = type;
|
||||
+ pj_memcpy(&key.rem_addr, remote, addr_len);
|
||||
|
||||
- /* First try to get exact destination. */
|
||||
- key.type = type;
|
||||
- pj_memcpy(&key.rem_addr, remote, addr_len);
|
||||
-
|
||||
- transport = (pjsip_transport*)
|
||||
- pj_hash_get(mgr->table, &key, key_len, NULL);
|
||||
+ transport = (pjsip_transport*)
|
||||
+ pj_hash_get(mgr->table, &key, key_len, NULL);
|
||||
+ }
|
||||
|
||||
- if (transport == NULL) {
|
||||
+ if (transport == NULL &&
|
||||
+ (!sel || sel->disable_connection_reuse == PJ_FALSE))
|
||||
+ {
|
||||
unsigned flag = pjsip_transport_get_flag_from_type(type);
|
||||
const pj_sockaddr *remote_addr = (const pj_sockaddr*)remote;
|
||||
|
||||
@@ -2179,9 +2183,7 @@
|
||||
transport = NULL;
|
||||
/* This will cause a new transport to be created which will be a
|
||||
* 'duplicate' of the existing transport (same type & remote addr,
|
||||
- * but different factory). Any future hash lookup will return
|
||||
- * the new one, and eventually the old one will still be freed
|
||||
- * (by application or #1774).
|
||||
+ * but different factory).
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -2199,9 +2201,14 @@
|
||||
|
||||
|
||||
/*
|
||||
- * Transport not found!
|
||||
- * So we need to create one, find factory that can create
|
||||
- * such transport.
|
||||
+ * Either transport not found, or we don't want to use the existing
|
||||
+ * transport (such as in the case of different factory or
|
||||
+ * if connection reuse is disabled). So we need to create one,
|
||||
+ * find factory that can create such transport.
|
||||
+ *
|
||||
+ * If there's an existing transport, its place in the hash table
|
||||
+ * will be replaced by this new one. And eventually the existing
|
||||
+ * transport will still be freed (by application or #1774).
|
||||
*/
|
||||
if (sel && sel->type == PJSIP_TPSELECTOR_LISTENER && sel->u.listener)
|
||||
{
|
Loading…
Reference in new issue