[svn-commits] rmudgett: branch rmudgett/http_persistent r417699 - in /team/rmudgett/http_pe...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Jun 30 15:38:42 CDT 2014


Author: rmudgett
Date: Mon Jun 30 15:38:38 2014
New Revision: 417699

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=417699
Log:
Resolve; reset automerge

Added:
    team/rmudgett/http_persistent/contrib/ast-db-manage/config/versions/51f8cb66540e_add_further_dtls_options.py
      - copied unchanged from r417678, branches/12/contrib/ast-db-manage/config/versions/51f8cb66540e_add_further_dtls_options.py
Modified:
    team/rmudgett/http_persistent/   (props changed)
    team/rmudgett/http_persistent/UPGRADE.txt
    team/rmudgett/http_persistent/channels/chan_sip.c
    team/rmudgett/http_persistent/channels/sip/include/sip.h
    team/rmudgett/http_persistent/configs/sip.conf.sample
    team/rmudgett/http_persistent/include/asterisk/res_pjsip.h
    team/rmudgett/http_persistent/include/asterisk/res_pjsip_session.h
    team/rmudgett/http_persistent/include/asterisk/rtp_engine.h
    team/rmudgett/http_persistent/include/asterisk/sdp_srtp.h
    team/rmudgett/http_persistent/main/rtp_engine.c
    team/rmudgett/http_persistent/main/sdp_srtp.c
    team/rmudgett/http_persistent/res/res_pjsip.c
    team/rmudgett/http_persistent/res/res_pjsip/pjsip_configuration.c
    team/rmudgett/http_persistent/res/res_pjsip_sdp_rtp.c
    team/rmudgett/http_persistent/res/res_rtp_asterisk.c

Propchange: team/rmudgett/http_persistent/
------------------------------------------------------------------------------
    automerge = *

Propchange: team/rmudgett/http_persistent/
------------------------------------------------------------------------------
--- http_persistent-integrated (original)
+++ http_persistent-integrated Mon Jun 30 15:38:38 2014
@@ -1,1 +1,1 @@
-/branches/12:1-417647
+/branches/12:1-417698

Modified: team/rmudgett/http_persistent/UPGRADE.txt
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/http_persistent/UPGRADE.txt?view=diff&rev=417699&r1=417698&r2=417699
==============================================================================
--- team/rmudgett/http_persistent/UPGRADE.txt (original)
+++ team/rmudgett/http_persistent/UPGRADE.txt Mon Jun 30 15:38:38 2014
@@ -41,11 +41,36 @@
    client is slow to process the received data, the socket may be disconnected.
    In such cases, it may be necessary to adjust this value. Default is 100 ms.
 
-HTTP:
  - Added support for persistent HTTP connections.  To enable persistent
    HTTP connections configure the keep alive time between HTTP requests.  The
    keep alive time between HTTP requests is configured in http.conf with the
    session_keep_alive parameter.
+
+ - Added a 'force_avp' option to chan_pjsip which will force the usage of
+   'RTP/AVP', 'RTP/AVPF', 'RTP/SAVP', or 'RTP/SAVPF' as the media transport type
+   in SDP offers depending on settings, even when DTLS is used for media
+   encryption.
+
+ - Added a 'media_use_received_transport' option to chan_pjsip which will
+   cause the SDP answer to use the media transport as received in the SDP
+   offer.
+
+ - Added a 'force_avp' option for chan_sip. When enabled this option will
+   cause the media transport in the offer or answer SDP to be 'RTP/AVP',
+   'RTP/AVPF', 'RTP/SAVP', or 'RTP/SAVPF' even if a DTLS stream has been
+   configured. This option can be set to improve interoperability with WebRTC
+   clients that don't use the RFC defined transport for DTLS.
+
+ - The 'dtlsverify' option in chan_sip now has additional values besides
+   'yes' and 'no'. If 'yes' is specified both the certificate and fingerprint
+   will be verified. If 'no' is specified then neither the certificate or
+   fingerprint is verified. If 'certificate' is specified then only the
+   certificate is verified. If 'fingerprint' is specified then only the
+   fingerprint is verified.
+
+ - A 'dtlsfingerprint' option has been added to chan_sip which allows the
+   hash to be specified for the DTLS fingerprint placed in SDP. Supported
+   values are 'sha-1' and 'sha-256' with 'sha-256' being the default.
 
 From 12.3.0 to 12.3.1:
 

Modified: team/rmudgett/http_persistent/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/http_persistent/channels/chan_sip.c?view=diff&rev=417699&r1=417698&r2=417699
==============================================================================
--- team/rmudgett/http_persistent/channels/chan_sip.c (original)
+++ team/rmudgett/http_persistent/channels/chan_sip.c Mon Jun 30 15:38:38 2014
@@ -1253,7 +1253,7 @@
 static int process_sdp_a_image(const char *a, struct sip_pvt *p);
 static void add_ice_to_sdp(struct ast_rtp_instance *instance, struct ast_str **a_buf);
 static void add_dtls_to_sdp(struct ast_rtp_instance *instance, struct ast_str **a_buf);
-static void start_ice(struct ast_rtp_instance *instance);
+static void start_ice(struct ast_rtp_instance *instance, int offer);
 static void add_codec_to_sdp(const struct sip_pvt *p, struct ast_format *codec,
 			     struct ast_str **m_buf, struct ast_str **a_buf,
 			     int debug, int *min_packet_size, int *max_packet_size);
@@ -10166,12 +10166,21 @@
 
 			if (process_sdp_a_dtls(value, p, p->rtp)) {
 				processed = TRUE;
+				if (p->srtp) {
+					ast_set_flag(p->srtp, AST_SRTP_CRYPTO_OFFER_OK);
+				}
 			}
 			if (process_sdp_a_dtls(value, p, p->vrtp)) {
 				processed = TRUE;
+				if (p->vsrtp) {
+					ast_set_flag(p->vsrtp, AST_SRTP_CRYPTO_OFFER_OK);
+				}
 			}
 			if (process_sdp_a_dtls(value, p, p->trtp)) {
 				processed = TRUE;
+				if (p->tsrtp) {
+					ast_set_flag(p->tsrtp, AST_SRTP_CRYPTO_OFFER_OK);
+				}
 			}
 
 			break;
@@ -10579,7 +10588,11 @@
 					if (process_sdp_a_ice(value, p, p->rtp)) {
 						processed = TRUE;
 					} else if (process_sdp_a_dtls(value, p, p->rtp)) {
+						processed_crypto = TRUE;
 						processed = TRUE;
+						if (p->srtp) {
+							ast_set_flag(p->srtp, AST_SRTP_CRYPTO_OFFER_OK);
+						}
 					} else if (process_sdp_a_sendonly(value, &sendonly)) {
 						processed = TRUE;
 					} else if (!processed_crypto && process_crypto(p, p->rtp, &p->srtp, value)) {
@@ -10594,7 +10607,11 @@
 					if (process_sdp_a_ice(value, p, p->vrtp)) {
 						processed = TRUE;
 					} else if (process_sdp_a_dtls(value, p, p->vrtp)) {
+						processed_crypto = TRUE;
 						processed = TRUE;
+						if (p->vsrtp) {
+							ast_set_flag(p->vsrtp, AST_SRTP_CRYPTO_OFFER_OK);
+						}
 					} else if (!processed_crypto && process_crypto(p, p->vrtp, &p->vsrtp, value)) {
 						processed_crypto = TRUE;
 						processed = TRUE;
@@ -10745,7 +10762,7 @@
 	/* Setup audio address and port */
 	if (p->rtp) {
 		if (sa && portno > 0) {
-			start_ice(p->rtp);
+			start_ice(p->rtp, (req->method != SIP_RESPONSE) ? 0 : 1);
 			ast_sockaddr_set_port(sa, portno);
 			ast_rtp_instance_set_remote_address(p->rtp, sa);
 			if (debug) {
@@ -10793,7 +10810,7 @@
 	/* Setup video address and port */
 	if (p->vrtp) {
 		if (vsa && vportno > 0) {
-			start_ice(p->vrtp);
+			start_ice(p->vrtp, (req->method != SIP_RESPONSE) ? 0 : 1);
 			ast_sockaddr_set_port(vsa, vportno);
 			ast_rtp_instance_set_remote_address(p->vrtp, vsa);
 			if (debug) {
@@ -10811,7 +10828,7 @@
 	/* Setup text address and port */
 	if (p->trtp) {
 		if (tsa && tportno > 0) {
-			start_ice(p->trtp);
+			start_ice(p->trtp, (req->method != SIP_RESPONSE) ? 0 : 1);
 			ast_sockaddr_set_port(tsa, tportno);
 			ast_rtp_instance_set_remote_address(p->trtp, tsa);
 			if (debug) {
@@ -11140,7 +11157,7 @@
 {
 	struct ast_rtp_engine_dtls *dtls;
 	int found = FALSE;
-	char value[256], hash[6];
+	char value[256], hash[32];
 
 	if (!instance || !p->dtls_cfg.enabled || !(dtls = ast_rtp_instance_get_dtls(instance))) {
 		return found;
@@ -11172,11 +11189,13 @@
 			ast_log(LOG_WARNING, "Unsupported connection attribute value '%s' received on dialog '%s'\n",
 				value, p->callid);
 		}
-	} else if (sscanf(a, "fingerprint: %5s %255s", hash, value) == 2) {
+	} else if (sscanf(a, "fingerprint: %31s %255s", hash, value) == 2) {
 		found = TRUE;
 
 		if (!strcasecmp(hash, "sha-1")) {
 			dtls->set_fingerprint(instance, AST_RTP_DTLS_HASH_SHA1, value);
+		} else if (!strcasecmp(hash, "sha-256")) {
+			dtls->set_fingerprint(instance, AST_RTP_DTLS_HASH_SHA256, value);
 		} else {
 			ast_log(LOG_WARNING, "Unsupported fingerprint hash type '%s' received on dialog '%s'\n",
 				hash, p->callid);
@@ -12839,7 +12858,7 @@
 }
 
 /*! \brief Start ICE negotiation on an RTP instance */
-static void start_ice(struct ast_rtp_instance *instance)
+static void start_ice(struct ast_rtp_instance *instance, int offer)
 {
 	struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(instance);
 
@@ -12847,6 +12866,8 @@
 		return;
 	}
 
+	/* If we are the offerer then we are the controlling agent, otherwise they are */
+	ice->set_role(instance, offer ? AST_RTP_ICE_ROLE_CONTROLLING : AST_RTP_ICE_ROLE_CONTROLLED);
 	ice->start(instance);
 }
 
@@ -12854,6 +12875,7 @@
 static void add_dtls_to_sdp(struct ast_rtp_instance *instance, struct ast_str **a_buf)
 {
 	struct ast_rtp_engine_dtls *dtls;
+	enum ast_rtp_dtls_hash hash;
 	const char *fingerprint;
 
 	if (!instance || !(dtls = ast_rtp_instance_get_dtls(instance)) || !dtls->active(instance)) {
@@ -12888,8 +12910,11 @@
 		break;
 	}
 
-	if ((fingerprint = dtls->get_fingerprint(instance, AST_RTP_DTLS_HASH_SHA1))) {
-		ast_str_append(a_buf, 0, "a=fingerprint:SHA-1 %s\r\n", fingerprint);
+	hash = dtls->get_fingerprint_hash(instance);
+	fingerprint = dtls->get_fingerprint(instance);
+	if (fingerprint && (hash == AST_RTP_DTLS_HASH_SHA1 || hash == AST_RTP_DTLS_HASH_SHA256)) {
+		ast_str_append(a_buf, 0, "a=fingerprint:%s %s\r\n", hash == AST_RTP_DTLS_HASH_SHA1 ? "SHA-1" : "SHA-256",
+			fingerprint);
 	}
 }
 
@@ -13362,7 +13387,8 @@
 				ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TAG_32));
 			ast_str_append(&m_video, 0, "m=video %d %s", ast_sockaddr_port(&vdest),
 				ast_sdp_get_rtp_profile(v_a_crypto ? 1 : 0, p->vrtp,
-					ast_test_flag(&p->flags[2], SIP_PAGE3_USE_AVPF)));
+					ast_test_flag(&p->flags[2], SIP_PAGE3_USE_AVPF),
+					ast_test_flag(&p->flags[2], SIP_PAGE3_FORCE_AVP)));
 
 			/* Build max bitrate string */
 			if (p->maxcallbitrate)
@@ -13389,7 +13415,8 @@
 				ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TAG_32));
 			ast_str_append(&m_text, 0, "m=text %d %s", ast_sockaddr_port(&tdest),
 				ast_sdp_get_rtp_profile(t_a_crypto ? 1 : 0, p->trtp,
-					ast_test_flag(&p->flags[2], SIP_PAGE3_USE_AVPF)));
+					ast_test_flag(&p->flags[2], SIP_PAGE3_USE_AVPF),
+					ast_test_flag(&p->flags[2], SIP_PAGE3_FORCE_AVP)));
 			if (debug) {  /* XXX should I use tdest below ? */
 				ast_verbose("Text is at %s\n", ast_sockaddr_stringify(&taddr));
 			}
@@ -13412,7 +13439,8 @@
 			ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TAG_32));
 		ast_str_append(&m_audio, 0, "m=audio %d %s", ast_sockaddr_port(&dest),
 			ast_sdp_get_rtp_profile(a_crypto ? 1 : 0, p->rtp,
-				ast_test_flag(&p->flags[2], SIP_PAGE3_USE_AVPF)));
+				ast_test_flag(&p->flags[2], SIP_PAGE3_USE_AVPF),
+				ast_test_flag(&p->flags[2], SIP_PAGE3_FORCE_AVP)));
 
 		/* Now, start adding audio codecs. These are added in this order:
 		   - First what was requested by the calling channel
@@ -31078,6 +31106,8 @@
 				ast_set2_flag(&peer->flags[2], ast_true(v->value), SIP_PAGE3_IGNORE_PREFCAPS);
 			} else if (!strcasecmp(v->name, "discard_remote_hold_retrieval")) {
 				ast_set2_flag(&peer->flags[2], ast_true(v->value), SIP_PAGE3_DISCARD_REMOTE_HOLD_RETRIEVAL);
+			} else if (!strcasecmp(v->name, "force_avp")) {
+				ast_set2_flag(&peer->flags[2], ast_true(v->value), SIP_PAGE3_FORCE_AVP);
 			} else {
 				ast_rtp_dtls_cfg_parse(&peer->dtls_cfg, v->name, v->value);
 			}

Modified: team/rmudgett/http_persistent/channels/sip/include/sip.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/http_persistent/channels/sip/include/sip.h?view=diff&rev=417699&r1=417698&r2=417699
==============================================================================
--- team/rmudgett/http_persistent/channels/sip/include/sip.h (original)
+++ team/rmudgett/http_persistent/channels/sip/include/sip.h Mon Jun 30 15:38:38 2014
@@ -382,11 +382,12 @@
 #define SIP_PAGE3_ICE_SUPPORT            (1 << 6)  /*!< DGP: Enable ICE support */
 #define SIP_PAGE3_IGNORE_PREFCAPS        (1 << 7)  /*!< DP: Ignore prefcaps when setting up an outgoing call leg */
 #define SIP_PAGE3_DISCARD_REMOTE_HOLD_RETRIEVAL  (1 << 8)  /*!< DGP: Stop telling the peer to start music on hold */
+#define SIP_PAGE3_FORCE_AVP              (1 << 9)  /*!< DGP: Force 'RTP/AVP' for all streams, even DTLS */
 
 #define SIP_PAGE3_FLAGS_TO_COPY \
 	(SIP_PAGE3_SNOM_AOC | SIP_PAGE3_SRTP_TAG_32 | SIP_PAGE3_NAT_AUTO_RPORT | SIP_PAGE3_NAT_AUTO_COMEDIA | \
 	 SIP_PAGE3_DIRECT_MEDIA_OUTGOING | SIP_PAGE3_USE_AVPF | SIP_PAGE3_ICE_SUPPORT | SIP_PAGE3_IGNORE_PREFCAPS | \
-	 SIP_PAGE3_DISCARD_REMOTE_HOLD_RETRIEVAL)
+	 SIP_PAGE3_DISCARD_REMOTE_HOLD_RETRIEVAL | SIP_PAGE3_FORCE_AVP)
 
 #define CHECK_AUTH_BUF_INITLEN   256
 

Modified: team/rmudgett/http_persistent/configs/sip.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/http_persistent/configs/sip.conf.sample?view=diff&rev=417699&r1=417698&r2=417699
==============================================================================
--- team/rmudgett/http_persistent/configs/sip.conf.sample (original)
+++ team/rmudgett/http_persistent/configs/sip.conf.sample Mon Jun 30 15:38:38 2014
@@ -1046,6 +1046,8 @@
 ;avpf=yes                       ; Enable inter-operability with media streams using the AVPF RTP profile.
 				; This will cause all offers and answers to use AVPF (or SAVPF). This
 				; option may be specified at the global or peer scope.
+;force_avp=yes			; Force 'RTP/AVP', 'RTP/AVPF', 'RTP/SAVP', and 'RTP/SAVPF' to be used for
+				; media streams when appropriate, even if a DTLS stream is present.
 ;----------------------------------------- REALTIME SUPPORT ------------------------
 ; For additional information on ARA, the Asterisk Realtime Architecture,
 ; please read https://wiki.asterisk.org/wiki/display/AST/Realtime+Database+Configuration
@@ -1302,6 +1304,7 @@
 ; dtlscafile
 ; dtlscapath
 ; dtlssetup
+; dtlsfingerprint
 ; ignore_requested_pref ; Ignore the requested codec and determine the preferred codec
 ;						; from the peer's configuration.
 ;
@@ -1312,7 +1315,11 @@
 ; DTLS-SRTP support is available if the underlying RTP engine in use supports it.
 ;
 ; dtlsenable = yes                   ; Enable or disable DTLS-SRTP support
-; dtlsverify = yes                   ; Verify that the provided peer certificate is valid
+; dtlsverify = yes                   ; Verify that provided peer certificate and fingerprint are valid
+;				     ; A value of 'yes' will perform both certificate and fingerprint verification
+;				     ; A value of 'no' will perform no certificate or fingerprint verification
+;				     ; A value of 'fingerprint' will perform ONLY fingerprint verification
+;				     ; A value of 'certificate' will perform ONLY certficiate verification
 ; dtlsrekey = 60                     ; Interval at which to renegotiate the TLS session and rekey the SRTP session
 ;                                    ; If this is not set or the value provided is 0 rekeying will be disabled
 ; dtlscertfile = file                ; Path to certificate file to present
@@ -1327,6 +1334,7 @@
 ;                                    ; accept connections only), and actpass (we will do both). This value will be used in
 ;                                    ; the outgoing SDP when offering and for incoming SDP offers when the remote party sends
 ;                                    ; actpass
+; dtlsfingerprint = sha-1            ; The hash to use for the fingerprint in SDP (valid options are sha-1 and sha-256)
 
 ;[sip_proxy]
 ; For incoming calls only. Example: FWD (Free World Dialup)

Modified: team/rmudgett/http_persistent/include/asterisk/res_pjsip.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/http_persistent/include/asterisk/res_pjsip.h?view=diff&rev=417699&r1=417698&r2=417699
==============================================================================
--- team/rmudgett/http_persistent/include/asterisk/res_pjsip.h (original)
+++ team/rmudgett/http_persistent/include/asterisk/res_pjsip.h Mon Jun 30 15:38:38 2014
@@ -476,6 +476,10 @@
 	unsigned int use_ptime;
 	/*! Do we use AVPF exclusively for this endpoint? */
 	unsigned int use_avpf;
+	/*! Do we force AVP, AVPF, SAVP, or SAVPF even for DTLS media streams? */
+	unsigned int force_avp;
+	/*! Do we use the received media transport in our answer SDP */
+	unsigned int use_received_transport;
 	/*! \brief DTLS-SRTP configuration information */
 	struct ast_rtp_dtls_cfg dtls_cfg;
 	/*! Should SRTP use a 32 byte tag instead of an 80 byte tag? */

Modified: team/rmudgett/http_persistent/include/asterisk/res_pjsip_session.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/http_persistent/include/asterisk/res_pjsip_session.h?view=diff&rev=417699&r1=417698&r2=417699
==============================================================================
--- team/rmudgett/http_persistent/include/asterisk/res_pjsip_session.h (original)
+++ team/rmudgett/http_persistent/include/asterisk/res_pjsip_session.h Mon Jun 30 15:38:38 2014
@@ -73,6 +73,8 @@
 	struct ast_sip_session_sdp_handler *handler;
 	/*! \brief Holds SRTP information */
 	struct ast_sdp_srtp *srtp;
+	/*! \brief The media transport in use for this stream */
+	pj_str_t transport;
 	/*! \brief Stream is on hold */
 	unsigned int held:1;
 	/*! \brief Stream type this session media handles */

Modified: team/rmudgett/http_persistent/include/asterisk/rtp_engine.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/http_persistent/include/asterisk/rtp_engine.h?view=diff&rev=417699&r1=417698&r2=417699
==============================================================================
--- team/rmudgett/http_persistent/include/asterisk/rtp_engine.h (original)
+++ team/rmudgett/http_persistent/include/asterisk/rtp_engine.h Mon Jun 30 15:38:38 2014
@@ -390,6 +390,12 @@
 	AST_RTP_ICE_COMPONENT_RTCP = 2,
 };
 
+/*! \brief ICE role during negotiation */
+enum ast_rtp_ice_role {
+	AST_RTP_ICE_ROLE_CONTROLLED,
+	AST_RTP_ICE_ROLE_CONTROLLING,
+};
+
 /*! \brief Structure for an ICE candidate */
 struct ast_rtp_engine_ice_candidate {
 	char *foundation;                     /*!< Foundation identifier */
@@ -419,6 +425,8 @@
 	struct ao2_container *(*get_local_candidates)(struct ast_rtp_instance *instance);
 	/*! Callback for telling the ICE support that it is talking to an ice-lite implementation */
 	void (*ice_lite)(struct ast_rtp_instance *instance);
+	/*! Callback for changing our role in negotiation */
+	void (*set_role)(struct ast_rtp_instance *instance, enum ast_rtp_ice_role role);
 };
 
 /*! \brief DTLS setup types */
@@ -431,22 +439,31 @@
 
 /*! \brief DTLS connection states */
 enum ast_rtp_dtls_connection {
-        AST_RTP_DTLS_CONNECTION_NEW,      /*!< Endpoint wants to use a new connection */
+	AST_RTP_DTLS_CONNECTION_NEW,      /*!< Endpoint wants to use a new connection */
 	AST_RTP_DTLS_CONNECTION_EXISTING, /*!< Endpoint wishes to use existing connection */
 };
 
 /*! \brief DTLS fingerprint hashes */
 enum ast_rtp_dtls_hash {
-	AST_RTP_DTLS_HASH_SHA1, /*!< SHA-1 fingerprint hash */
+	AST_RTP_DTLS_HASH_SHA256, /*!< SHA-256 fingerprint hash */
+	AST_RTP_DTLS_HASH_SHA1,   /*!< SHA-1 fingerprint hash */
+};
+
+/*! \brief DTLS verification settings */
+enum ast_rtp_dtls_verify {
+	AST_RTP_DTLS_VERIFY_NONE = 0,               /*!< Don't verify anything */
+	AST_RTP_DTLS_VERIFY_FINGERPRINT = (1 << 0), /*!< Verify the fingerprint */
+	AST_RTP_DTLS_VERIFY_CERTIFICATE = (1 << 1), /*!< Verify the certificate */
 };
 
 /*! \brief DTLS configuration structure */
 struct ast_rtp_dtls_cfg {
 	unsigned int enabled:1;                /*!< Whether DTLS support is enabled or not */
-	unsigned int verify:1;                 /*!< Whether to request and verify a client certificate when acting as server */
 	unsigned int rekey;                    /*!< Interval at which to renegotiate and rekey - defaults to 0 (off) */
 	enum ast_rtp_dtls_setup default_setup; /*!< Default setup type to use for outgoing */
 	enum ast_srtp_suite suite;             /*!< Crypto suite in use */
+	enum ast_rtp_dtls_hash hash;		   /*!< Hash to use for fingerprint */
+	enum ast_rtp_dtls_verify verify;	   /*!< What should be verified */
 	char *certfile;                        /*!< Certificate file */
 	char *pvtfile;                         /*!< Private key file */
 	char *cipher;                          /*!< Cipher to use */
@@ -472,8 +489,10 @@
 	void (*set_setup)(struct ast_rtp_instance *instance, enum ast_rtp_dtls_setup setup);
 	/*! Set the remote fingerprint */
 	void (*set_fingerprint)(struct ast_rtp_instance *instance, enum ast_rtp_dtls_hash hash, const char *fingerprint);
+	/*! Get the local fingerprint hash type */
+	enum ast_rtp_dtls_hash (*get_fingerprint_hash)(struct ast_rtp_instance *instance);
 	/*! Get the local fingerprint */
-	const char *(*get_fingerprint)(struct ast_rtp_instance *instance, enum ast_rtp_dtls_hash hash);
+	const char *(*get_fingerprint)(struct ast_rtp_instance *instance);
 };
 
 /*! Structure that represents an RTP stack (engine) */

Modified: team/rmudgett/http_persistent/include/asterisk/sdp_srtp.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/http_persistent/include/asterisk/sdp_srtp.h?view=diff&rev=417699&r1=417698&r2=417699
==============================================================================
--- team/rmudgett/http_persistent/include/asterisk/sdp_srtp.h (original)
+++ team/rmudgett/http_persistent/include/asterisk/sdp_srtp.h Mon Jun 30 15:38:38 2014
@@ -118,8 +118,10 @@
  * \param sdes_active Whether the media session is using SDES-SRTP
  * \param instance The RTP instance associated with this media session
  * \param using_avpf Whether the media session is using early feedback (AVPF)
+ * \param force_avp Force SAVP or SAVPF profile when DTLS is in use
  *
  * \retval A non-allocated string describing the profile in use (does not need to be freed)
  */
-char *ast_sdp_get_rtp_profile(unsigned int sdes_active, struct ast_rtp_instance *instance, unsigned int using_avpf);
+char *ast_sdp_get_rtp_profile(unsigned int sdes_active, struct ast_rtp_instance *instance, unsigned int using_avpf,
+	unsigned int force_avp);
 #endif	/* _SDP_CRYPTO_H */

Modified: team/rmudgett/http_persistent/main/rtp_engine.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/http_persistent/main/rtp_engine.c?view=diff&rev=417699&r1=417698&r2=417699
==============================================================================
--- team/rmudgett/http_persistent/main/rtp_engine.c (original)
+++ team/rmudgett/http_persistent/main/rtp_engine.c Mon Jun 30 15:38:38 2014
@@ -1556,7 +1556,17 @@
 	if (!strcasecmp(name, "dtlsenable")) {
 		dtls_cfg->enabled = ast_true(value) ? 1 : 0;
 	} else if (!strcasecmp(name, "dtlsverify")) {
-		dtls_cfg->verify = ast_true(value) ? 1 : 0;
+		if (!strcasecmp(value, "yes")) {
+			dtls_cfg->verify = AST_RTP_DTLS_VERIFY_FINGERPRINT | AST_RTP_DTLS_VERIFY_CERTIFICATE;
+		} else if (!strcasecmp(value, "fingerprint")) {
+			dtls_cfg->verify = AST_RTP_DTLS_VERIFY_FINGERPRINT;
+		} else if (!strcasecmp(value, "certificate")) {
+			dtls_cfg->verify = AST_RTP_DTLS_VERIFY_CERTIFICATE;
+		} else if (!strcasecmp(value, "no")) {
+			dtls_cfg->verify = AST_RTP_DTLS_VERIFY_NONE;
+		} else {
+			return -1;
+		}
 	} else if (!strcasecmp(name, "dtlsrekey")) {
 		if (sscanf(value, "%30u", &dtls_cfg->rekey) != 1) {
 			return -1;
@@ -1584,6 +1594,12 @@
 		} else if (!strcasecmp(value, "actpass")) {
 			dtls_cfg->default_setup = AST_RTP_DTLS_SETUP_ACTPASS;
 		}
+	} else if (!strcasecmp(name, "dtlsfingerprint")) {
+		if (!strcasecmp(value, "sha-256")) {
+			dtls_cfg->hash = AST_RTP_DTLS_HASH_SHA256;
+		} else if (!strcasecmp(value, "sha-1")) {
+			dtls_cfg->hash = AST_RTP_DTLS_HASH_SHA1;
+		}
 	} else {
 		return -1;
 	}
@@ -1597,6 +1613,7 @@
 	dst_cfg->verify = src_cfg->verify;
 	dst_cfg->rekey = src_cfg->rekey;
 	dst_cfg->suite = src_cfg->suite;
+	dst_cfg->hash = src_cfg->hash;
 	dst_cfg->certfile = ast_strdup(src_cfg->certfile);
 	dst_cfg->pvtfile = ast_strdup(src_cfg->pvtfile);
 	dst_cfg->cipher = ast_strdup(src_cfg->cipher);

Modified: team/rmudgett/http_persistent/main/sdp_srtp.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/http_persistent/main/sdp_srtp.c?view=diff&rev=417699&r1=417698&r2=417699
==============================================================================
--- team/rmudgett/http_persistent/main/sdp_srtp.c (original)
+++ team/rmudgett/http_persistent/main/sdp_srtp.c Mon Jun 30 15:38:38 2014
@@ -365,12 +365,17 @@
 	return NULL;
 }
 
-char *ast_sdp_get_rtp_profile(unsigned int sdes_active, struct ast_rtp_instance *instance, unsigned int using_avpf)
+char *ast_sdp_get_rtp_profile(unsigned int sdes_active, struct ast_rtp_instance *instance, unsigned int using_avpf,
+	unsigned int force_avp)
 {
 	struct ast_rtp_engine_dtls *dtls;
 
 	if ((dtls = ast_rtp_instance_get_dtls(instance)) && dtls->active(instance)) {
-		return using_avpf ? "UDP/TLS/RTP/SAVPF" : "UDP/TLS/RTP/SAVP";
+		if (force_avp) {
+			return using_avpf ? "RTP/SAVPF" : "RTP/SAVP";
+		} else {
+			return using_avpf ? "UDP/TLS/RTP/SAVPF" : "UDP/TLS/RTP/SAVP";
+		}
 	} else {
 		if (using_avpf) {
 			return sdes_active ? "RTP/SAVPF" : "RTP/AVPF";

Modified: team/rmudgett/http_persistent/res/res_pjsip.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/http_persistent/res/res_pjsip.c?view=diff&rev=417699&r1=417698&r2=417699
==============================================================================
--- team/rmudgett/http_persistent/res/res_pjsip.c (original)
+++ team/rmudgett/http_persistent/res/res_pjsip.c Mon Jun 30 15:38:38 2014
@@ -388,6 +388,28 @@
 						profile for all media offers on outbound calls and media updates, but will
 						accept either the AVP/AVPF or SAVP/SAVPF RTP profile for all inbound
 						media offers.
+					</para></description>
+				</configOption>
+				<configOption name="force_avp" default="no">
+					<synopsis>Determines whether res_pjsip will use and enforce usage of AVP,
+					regardless of the RTP profile in use for this endpoint.</synopsis>
+					<description><para>
+						If set to <literal>yes</literal>, res_pjsip will use the AVP, AVPF, SAVP, or
+						SAVPF RTP profile for all media offers on outbound calls and media updates including
+						those for DTLS-SRTP streams.
+					</para><para>
+						If set to <literal>no</literal>, res_pjsip will use the respective RTP profile
+						depending on configuration.
+					</para></description>
+				</configOption>
+				<configOption name="media_use_received_transport" default="no">
+					<synopsis>Determines whether res_pjsip will use the media transport received in the
+					offer SDP in the corresponding answer SDP.</synopsis>
+					<description><para>
+						If set to <literal>yes</literal>, res_pjsip will use the received media transport.
+					</para><para>
+						If set to <literal>no</literal>, res_pjsip will use the respective RTP profile
+						depending on configuration.
 					</para></description>
 				</configOption>
 				<configOption name="media_encryption" default="no">

Modified: team/rmudgett/http_persistent/res/res_pjsip/pjsip_configuration.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/http_persistent/res/res_pjsip/pjsip_configuration.c?view=diff&rev=417699&r1=417698&r2=417699
==============================================================================
--- team/rmudgett/http_persistent/res/res_pjsip/pjsip_configuration.c (original)
+++ team/rmudgett/http_persistent/res/res_pjsip/pjsip_configuration.c Mon Jun 30 15:38:38 2014
@@ -1691,6 +1691,8 @@
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "aggregate_mwi", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, subscription.mwi.aggregate));
 	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "media_encryption", "no", media_encryption_handler, media_encryption_to_str, NULL, 0, 0);
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "use_avpf", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.use_avpf));
+	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "force_avp", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.force_avp));
+	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "media_use_received_transport", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.use_received_transport));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "one_touch_recording", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, info.recording.enabled));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "inband_progress", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, inband_progress));
 	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "call_group", "", group_handler, callgroup_to_str, NULL, 0, 0);

Modified: team/rmudgett/http_persistent/res/res_pjsip_sdp_rtp.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/http_persistent/res/res_pjsip_sdp_rtp.c?view=diff&rev=417699&r1=417698&r2=417699
==============================================================================
--- team/rmudgett/http_persistent/res/res_pjsip_sdp_rtp.c (original)
+++ team/rmudgett/http_persistent/res/res_pjsip_sdp_rtp.c Mon Jun 30 15:38:38 2014
@@ -390,14 +390,26 @@
 		return;
 	}
 
-	if ((attr = pjmedia_sdp_media_find_attr2(remote_stream, "ice-ufrag", NULL))) {
+	attr = pjmedia_sdp_media_find_attr2(remote_stream, "ice-ufrag", NULL);
+	if (!attr) {
+		attr = pjmedia_sdp_attr_find2(remote->attr_count, remote->attr, "ice-ufrag", NULL);
+	}
+	if (attr) {
 		ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value));
 		ice->set_authentication(session_media->rtp, attr_value, NULL);
-	}
-
-	if ((attr = pjmedia_sdp_media_find_attr2(remote_stream, "ice-pwd", NULL))) {
+	} else {
+		return;
+	}
+
+	attr = pjmedia_sdp_media_find_attr2(remote_stream, "ice-pwd", NULL);
+	if (!attr) {
+		pjmedia_sdp_attr_find2(remote->attr_count, remote->attr, "ice-pwd", NULL);
+	}
+	if (attr) {
 		ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value));
 		ice->set_authentication(session_media->rtp, NULL, attr_value);
+	} else {
+		return;
 	}
 
 	if (pjmedia_sdp_media_find_attr2(remote_stream, "ice-lite", NULL)) {
@@ -452,6 +464,8 @@
 		ice->add_remote_candidate(session_media->rtp, &candidate);
 	}
 
+	ice->set_role(session_media->rtp, pjmedia_sdp_neg_was_answer_remote(session->inv_session->neg) == PJ_TRUE ?
+		AST_RTP_ICE_ROLE_CONTROLLING : AST_RTP_ICE_ROLE_CONTROLLED);
 	ice->start(session_media->rtp);
 }
 
@@ -526,6 +540,10 @@
 	incoming_encryption = get_media_encryption_type(stream->desc.transport);
 
 	if (incoming_encryption == endpoint->media.rtp.encryption) {
+		return incoming_encryption;
+	}
+
+	if (endpoint->media.rtp.force_avp) {
 		return incoming_encryption;
 	}
 
@@ -615,13 +633,15 @@
 				ast_log(LOG_WARNING, "Unsupported connection attribute value '%*s'\n", (int)value->slen, value->ptr);
 			}
 		} else if (!pj_strcmp2(&attr->name, "fingerprint")) {
-			char hash_value[256], hash[6];
+			char hash_value[256], hash[32];
 			char fingerprint_text[value->slen + 1];
 			ast_copy_pj_str(fingerprint_text, value, sizeof(fingerprint_text));
 
-			if (sscanf(fingerprint_text, "%5s %255s", hash, hash_value) == 2) {
+			if (sscanf(fingerprint_text, "%31s %255s", hash, hash_value) == 2) {
 				if (!strcasecmp(hash, "sha-1")) {
 					dtls->set_fingerprint(session_media->rtp, AST_RTP_DTLS_HASH_SHA1, hash_value);
+				} else if (!strcasecmp(hash, "sha-256")) {
+					dtls->set_fingerprint(session_media->rtp, AST_RTP_DTLS_HASH_SHA256, hash_value);
 				} else {
 					ast_log(LOG_WARNING, "Unsupported fingerprint hash type '%s'\n",
 					hash);
@@ -710,7 +730,8 @@
 	}
 
 	/* Ensure incoming transport is compatible with the endpoint's configuration */
-	if (check_endpoint_media_transport(session->endpoint, stream) == AST_SIP_MEDIA_TRANSPORT_INVALID) {
+	if (!session->endpoint->media.rtp.use_received_transport &&
+		check_endpoint_media_transport(session->endpoint, stream) == AST_SIP_MEDIA_TRANSPORT_INVALID) {
 		return -1;
 	}
 
@@ -727,6 +748,10 @@
 		return -1;
 	}
 
+	if (session->endpoint->media.rtp.use_received_transport) {
+		pj_strdup(session->inv_session->pool, &session_media->transport, &stream->desc.transport);
+	}
+
 	if (setup_media_encryption(session, session_media, stream)) {
 		return -1;
 	}
@@ -748,6 +773,7 @@
 {
 	pj_str_t stmp;
 	pjmedia_sdp_attr *attr;
+	enum ast_rtp_dtls_hash hash;
 	const char *crypto_attribute;
 	struct ast_rtp_engine_dtls *dtls;
 	static const pj_str_t STR_NEW = { "new", 3 };
@@ -824,13 +850,19 @@
 			break;
 		}
 
-		if ((crypto_attribute = dtls->get_fingerprint(session_media->rtp, AST_RTP_DTLS_HASH_SHA1))) {
+		hash = dtls->get_fingerprint_hash(session_media->rtp);
+		crypto_attribute = dtls->get_fingerprint(session_media->rtp);
+		if (crypto_attribute && (hash == AST_RTP_DTLS_HASH_SHA1 || hash == AST_RTP_DTLS_HASH_SHA256)) {
 			RAII_VAR(struct ast_str *, fingerprint, ast_str_create(64), ast_free);
 			if (!fingerprint) {
 				return -1;
 			}
 
-			ast_str_set(&fingerprint, 0, "SHA-1 %s", crypto_attribute);
+			if (hash == AST_RTP_DTLS_HASH_SHA1) {
+				ast_str_set(&fingerprint, 0, "SHA-1 %s", crypto_attribute);
+			} else {
+				ast_str_set(&fingerprint, 0, "SHA-256 %s", crypto_attribute);
+			}
 
 			attr = pjmedia_sdp_attr_create(pool, "fingerprint", pj_cstr(&stmp, ast_str_buffer(fingerprint)));
 			media->attr[media->attr_count++] = attr;
@@ -889,9 +921,14 @@
 	}
 
 	media->desc.media = pj_str(session_media->stream_type);
-	media->desc.transport = pj_str(ast_sdp_get_rtp_profile(
-		session->endpoint->media.rtp.encryption == AST_SIP_MEDIA_ENCRYPT_SDES,
-		session_media->rtp, session->endpoint->media.rtp.use_avpf));
+	if (session->endpoint->media.rtp.use_received_transport && pj_strlen(&session_media->transport)) {
+		media->desc.transport = session_media->transport;
+	} else {
+		media->desc.transport = pj_str(ast_sdp_get_rtp_profile(
+			session->endpoint->media.rtp.encryption == AST_SIP_MEDIA_ENCRYPT_SDES,
+			session_media->rtp, session->endpoint->media.rtp.use_avpf,
+			session->endpoint->media.rtp.force_avp));
+	}
 
 	/* Add connection level details */
 	if (direct_media_enabled) {
@@ -1033,7 +1070,8 @@
 	}
 
 	/* Ensure incoming transport is compatible with the endpoint's configuration */
-	if (check_endpoint_media_transport(session->endpoint, remote_stream) == AST_SIP_MEDIA_TRANSPORT_INVALID) {
+	if (!session->endpoint->media.rtp.use_received_transport &&
+		check_endpoint_media_transport(session->endpoint, remote_stream) == AST_SIP_MEDIA_TRANSPORT_INVALID) {
 		return -1;
 	}
 

Modified: team/rmudgett/http_persistent/res/res_rtp_asterisk.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/http_persistent/res/res_rtp_asterisk.c?view=diff&rev=417699&r1=417698&r2=417699
==============================================================================
--- team/rmudgett/http_persistent/res/res_rtp_asterisk.c (original)
+++ team/rmudgett/http_persistent/res/res_rtp_asterisk.c Mon Jun 30 15:38:38 2014
@@ -180,6 +180,16 @@
 	int max_seq;	/*!< The highest sequence number received */
 	int packets;	/*!< The number of remaining packets before the source is accepted */
 };
+
+#ifdef HAVE_OPENSSL_SRTP
+struct dtls_details {
+	SSL *ssl;         /*!< SSL session */
+	BIO *read_bio;    /*!< Memory buffer for reading */
+	BIO *write_bio;   /*!< Memory buffer for writing */
+	enum ast_rtp_dtls_setup dtls_setup; /*!< Current setup state */
+	enum ast_rtp_dtls_connection connection; /*!< Whether this is a new or existing connection */
+};
+#endif
 
 /*! \brief RTP session description */
 struct ast_rtp {
@@ -280,19 +290,17 @@
 
 #ifdef HAVE_OPENSSL_SRTP
 	SSL_CTX *ssl_ctx; /*!< SSL context */
-	SSL *ssl;         /*!< SSL session */
-	BIO *read_bio;    /*!< Memory buffer for reading */
-	BIO *write_bio;   /*!< Memory buffer for writing */
 	ast_mutex_t dtls_timer_lock;           /*!< Lock for synchronization purposes */
-	enum ast_rtp_dtls_setup dtls_setup; /*!< Current setup state */
+	enum ast_rtp_dtls_verify dtls_verify; /*!< What to verify */
 	enum ast_srtp_suite suite;   /*!< SRTP crypto suite */
+	enum ast_rtp_dtls_hash local_hash; /*!< Local hash used for the fingerprint */
 	char local_fingerprint[160]; /*!< Fingerprint of our certificate */
+	enum ast_rtp_dtls_hash remote_hash; /*!< Remote hash used for the fingerprint */
 	unsigned char remote_fingerprint[EVP_MAX_MD_SIZE]; /*!< Fingerprint of the peer certificate */
-	enum ast_rtp_dtls_connection connection; /*!< Whether this is a new or existing connection */
-	unsigned int dtls_failure:1; /*!< Failure occurred during DTLS negotiation */
 	unsigned int rekey; /*!< Interval at which to renegotiate and rekey */
 	int rekeyid; /*!< Scheduled item id for rekeying */
 	int dtlstimerid; /*!< Scheduled item id for DTLS retransmission for RTP */
+	struct dtls_details dtls; /*!< DTLS state information */
 #endif
 };
 
@@ -358,6 +366,10 @@
 
 	/* VP8: sequence number for the RTCP FIR FCI */
 	int firseq;
+
+#ifdef HAVE_OPENSSL_SRTP
+	struct dtls_details dtls; /*!< DTLS state information */
+#endif
 };
 
 struct rtp_red {
@@ -404,7 +416,7 @@
 
 #ifdef HAVE_OPENSSL_SRTP
 static int ast_rtp_activate(struct ast_rtp_instance *instance);
-static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp);
+static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp, int rtcp);
 #endif
 
 static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int rtcp, int *ice, int use_srtp);
@@ -542,9 +554,18 @@
 static int ice_reset_session(struct ast_rtp_instance *instance)
 {
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+	pj_ice_sess_role role = rtp->ice->role;
+	int res;
 
 	ast_rtp_ice_stop(instance);
-	return ice_create(instance, &rtp->ice_original_rtp_addr, rtp->ice_port, 1);
+
+	res = ice_create(instance, &rtp->ice_original_rtp_addr, rtp->ice_port, 1);
+	if (!res) {
+		/* Preserve the role that the old ICE session used */
+		pj_ice_sess_change_role(rtp->ice, role);
+	}
+
+	return res;
 }
 
 static int ice_candidates_compare(struct ao2_container *left, struct ao2_container *right)
@@ -699,6 +720,20 @@
 	pj_thread_register_check();
 
 	pj_ice_sess_change_role(rtp->ice, PJ_ICE_SESS_ROLE_CONTROLLING);
+}
+
+static void ast_rtp_ice_set_role(struct ast_rtp_instance *instance, enum ast_rtp_ice_role role)
+{
+	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+
+	if (!rtp->ice) {
+		return;
+	}
+
+	pj_thread_register_check();
+
+	pj_ice_sess_change_role(rtp->ice, role == AST_RTP_ICE_ROLE_CONTROLLED ?
+		PJ_ICE_SESS_ROLE_CONTROLLED : PJ_ICE_SESS_ROLE_CONTROLLING);
 }
 
 static void ast_rtp_ice_add_cand(struct ast_rtp *rtp, unsigned comp_id, unsigned transport_id, pj_ice_cand_type type, pj_uint16_t local_pref,
@@ -781,25 +816,83 @@
 	.get_password = ast_rtp_ice_get_password,
 	.get_local_candidates = ast_rtp_ice_get_local_candidates,
 	.ice_lite = ast_rtp_ice_lite,
+	.set_role = ast_rtp_ice_set_role,
 };
 #endif
 
 #ifdef HAVE_OPENSSL_SRTP
-static void dtls_info_callback(const SSL *ssl, int where, int ret)
-{
-	struct ast_rtp *rtp = SSL_get_ex_data(ssl, 0);
-
-	/* We only care about alerts */
-	if (!(where & SSL_CB_ALERT)) {
-		return;
-	}
-
-	rtp->dtls_failure = 1;
+static int dtls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
+{
+	/* We don't want to actually verify the certificate so just accept what they have provided */
+	return 1;
+}
+
+static int dtls_details_initialize(struct dtls_details *dtls, SSL_CTX *ssl_ctx,
+	enum ast_rtp_dtls_setup setup)
+{
+	dtls->dtls_setup = setup;
+
+	if (!(dtls->ssl = SSL_new(ssl_ctx))) {

[... 797 lines stripped ...]



More information about the svn-commits mailing list