diff options
-rw-r--r-- | pjlib-util/build/pjlib_util.dsp | 16 | ||||
-rw-r--r-- | pjlib-util/build/pjlib_util.vcproj | 12 | ||||
-rw-r--r-- | pjlib-util/build/pjstun_srv_test.dsp | 4 | ||||
-rw-r--r-- | pjlib-util/include/pjlib-util.h | 2 | ||||
-rw-r--r-- | pjlib-util/include/pjlib-util/errno.h | 46 | ||||
-rw-r--r-- | pjlib-util/include/pjlib-util/stun_auth.h | 275 | ||||
-rw-r--r-- | pjlib-util/include/pjlib-util/stun_msg.h | 364 | ||||
-rw-r--r-- | pjlib-util/include/pjlib-util/stun_server.h | 109 | ||||
-rw-r--r-- | pjlib-util/include/pjlib-util/stun_session.h | 91 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util/errno.c | 17 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util/stun_auth.c | 341 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util/stun_msg.c | 741 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util/stun_msg_dump.c | 16 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util/stun_server.c | 129 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util/stun_session.c | 334 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util/stun_transaction.c | 7 | ||||
-rw-r--r-- | pjlib-util/src/pjstun-client/client_main.c | 51 | ||||
-rw-r--r-- | pjlib-util/src/pjstun-srv-test/server_main.c | 108 |
18 files changed, 1379 insertions, 1284 deletions
diff --git a/pjlib-util/build/pjlib_util.dsp b/pjlib-util/build/pjlib_util.dsp index 6aa10d11..84d30b98 100644 --- a/pjlib-util/build/pjlib_util.dsp +++ b/pjlib-util/build/pjlib_util.dsp @@ -145,19 +145,19 @@ SOURCE="..\src\pjlib-util\string.c" # End Source File
# Begin Source File
-SOURCE="..\src\pjlib-util\stun_endpoint.c"
+SOURCE="..\src\pjlib-util\stun_auth.c"
# End Source File
# Begin Source File
-SOURCE="..\src\pjlib-util\stun_msg.c"
+SOURCE="..\src\pjlib-util\stun_endpoint.c"
# End Source File
# Begin Source File
-SOURCE="..\src\pjlib-util\stun_msg_dump.c"
+SOURCE="..\src\pjlib-util\stun_msg.c"
# End Source File
# Begin Source File
-SOURCE="..\src\pjlib-util\stun_server.c"
+SOURCE="..\src\pjlib-util\stun_msg_dump.c"
# End Source File
# Begin Source File
@@ -249,19 +249,19 @@ SOURCE="..\include\pjlib-util\string.h" # End Source File
# Begin Source File
-SOURCE="..\include\pjlib-util\stun_doc.h"
+SOURCE="..\include\pjlib-util\stun_auth.h"
# End Source File
# Begin Source File
-SOURCE="..\include\pjlib-util\stun_endpoint.h"
+SOURCE="..\include\pjlib-util\stun_doc.h"
# End Source File
# Begin Source File
-SOURCE="..\include\pjlib-util\stun_msg.h"
+SOURCE="..\include\pjlib-util\stun_endpoint.h"
# End Source File
# Begin Source File
-SOURCE="..\include\pjlib-util\stun_server.h"
+SOURCE="..\include\pjlib-util\stun_msg.h"
# End Source File
# Begin Source File
diff --git a/pjlib-util/build/pjlib_util.vcproj b/pjlib-util/build/pjlib_util.vcproj index d07f073d..53a9e617 100644 --- a/pjlib-util/build/pjlib_util.vcproj +++ b/pjlib-util/build/pjlib_util.vcproj @@ -415,6 +415,10 @@ </FileConfiguration>
</File>
<File
+ RelativePath="..\src\pjlib-util\stun_auth.c"
+ >
+ </File>
+ <File
RelativePath="..\src\pjlib-util\stun_endpoint.c"
>
</File>
@@ -427,7 +431,7 @@ >
</File>
<File
- RelativePath="..\src\pjlib-util\stun_server.c"
+ RelativePath="..\src\pjlib-util\stun_session.c"
>
</File>
<File
@@ -552,6 +556,10 @@ >
</File>
<File
+ RelativePath="..\include\pjlib-util\stun_auth.h"
+ >
+ </File>
+ <File
RelativePath="..\include\pjlib-util\stun_doc.h"
>
</File>
@@ -564,7 +572,7 @@ >
</File>
<File
- RelativePath="..\include\pjlib-util\stun_server.h"
+ RelativePath="..\include\pjlib-util\stun_session.h"
>
</File>
<File
diff --git a/pjlib-util/build/pjstun_srv_test.dsp b/pjlib-util/build/pjstun_srv_test.dsp index 227a3405..f9a8ff9d 100644 --- a/pjlib-util/build/pjstun_srv_test.dsp +++ b/pjlib-util/build/pjstun_srv_test.dsp @@ -93,10 +93,6 @@ SOURCE="..\src\pjstun-srv-test\server_main.c" # Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
-# Begin Source File
-
-SOURCE="..\src\pjstun-srv-test\server.h"
-# End Source File
# End Group
# Begin Group "Resource Files"
diff --git a/pjlib-util/include/pjlib-util.h b/pjlib-util/include/pjlib-util.h index 7c8e2ad4..6c4f871a 100644 --- a/pjlib-util/include/pjlib-util.h +++ b/pjlib-util/include/pjlib-util.h @@ -49,9 +49,9 @@ #include <pjlib-util/xml.h> /* New STUN */ +#include <pjlib-util/stun_auth.h> #include <pjlib-util/stun_endpoint.h> #include <pjlib-util/stun_msg.h> -#include <pjlib-util/stun_server.h> #include <pjlib-util/stun_session.h> #include <pjlib-util/stun_transaction.h> diff --git a/pjlib-util/include/pjlib-util/errno.h b/pjlib-util/include/pjlib-util/errno.h index d33ed1a2..bff14194 100644 --- a/pjlib-util/include/pjlib-util/errno.h +++ b/pjlib-util/include/pjlib-util/errno.h @@ -261,24 +261,20 @@ /* Messaging errors */ /** * @hideinitializer - * Invalid STUN attribute - */ -#define PJLIB_UTIL_ESTUNINATTR (PJLIB_UTIL_ERRNO_START+110)/* 320110 */ -/** - * @hideinitializer * Too many STUN attributes. */ -#define PJLIB_UTIL_ESTUNTOOMANYATTR (PJLIB_UTIL_ERRNO_START+111)/* 320111 */ +#define PJLIB_UTIL_ESTUNTOOMANYATTR (PJLIB_UTIL_ERRNO_START+110)/* 320110 */ /** * @hideinitializer - * Unknown STUN attribute. + * Unknown STUN attribute. This error happens when the decoder encounters + * mandatory attribute type which it doesn't understand. */ -#define PJLIB_UTIL_ESTUNUNKNOWNATTR (PJLIB_UTIL_ERRNO_START+112)/* 320112 */ +#define PJLIB_UTIL_ESTUNUNKNOWNATTR (PJLIB_UTIL_ERRNO_START+111)/* 320111 */ /** * @hideinitializer * Invalid STUN socket address length. */ -#define PJLIB_UTIL_ESTUNINADDRLEN (PJLIB_UTIL_ERRNO_START+113)/* 320113 */ +#define PJLIB_UTIL_ESTUNINADDRLEN (PJLIB_UTIL_ERRNO_START+112)/* 320112 */ /** * @hideinitializer * STUN IPv6 attribute not supported @@ -319,9 +315,39 @@ * present), the USERNAME attribute must be present in the message. */ #define PJLIB_UTIL_ESTUNNOUSERNAME (PJLIB_UTIL_ERRNO_START+120)/* 320120 */ +/** + * @hideinitializer + * Unknown STUN username/credential. + */ +#define PJLIB_UTIL_ESTUNUSERNAME (PJLIB_UTIL_ERRNO_START+121)/* 320121 */ +/** + * @hideinitializer + * Missing/invalidSTUN MESSAGE-INTEGRITY attribute. + */ +#define PJLIB_UTIL_ESTUNMSGINT (PJLIB_UTIL_ERRNO_START+122)/* 320122 */ +/** + * @hideinitializer + * Found duplicate STUN attribute. + */ +#define PJLIB_UTIL_ESTUNDUPATTR (PJLIB_UTIL_ERRNO_START+123)/* 320123 */ +/** + * @hideinitializer + * Missing STUN REALM attribute. + */ +#define PJLIB_UTIL_ESTUNNOREALM (PJLIB_UTIL_ERRNO_START+124)/* 320124 */ +/** + * @hideinitializer + * Missing/stale STUN NONCE attribute value. + */ +#define PJLIB_UTIL_ESTUNNONCE (PJLIB_UTIL_ERRNO_START+125)/* 320125 */ +/** + * @hideinitializer + * STUN transaction terminates with failure. + */ +#define PJLIB_UTIL_ESTUNTSXFAILED (PJLIB_UTIL_ERRNO_START+126)/* 320126 */ -#define PJ_STATUS_FROM_STUN_CODE(code) (PJLIB_UTIL_ERRNO_START+code) +//#define PJ_STATUS_FROM_STUN_CODE(code) (PJLIB_UTIL_ERRNO_START+code) diff --git a/pjlib-util/include/pjlib-util/stun_auth.h b/pjlib-util/include/pjlib-util/stun_auth.h new file mode 100644 index 00000000..2e0f81ee --- /dev/null +++ b/pjlib-util/include/pjlib-util/stun_auth.h @@ -0,0 +1,275 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2005 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __PJ_STUN_AUTH_H__ +#define __PJ_STUN_AUTH_H__ + +/** + * @file stun_auth.h + * @brief STUN authentication. + */ + +#include <pjlib-util/stun_msg.h> + + +PJ_BEGIN_DECL + + +/* **************************************************************************/ +/** + * @defgroup PJLIB_UTIL_STUN_AUTH STUN Authentication + * @ingroup PJLIB_UTIL_STUN + * @{ + */ + +/** + * Type of authentication data in the credential. + */ +typedef enum pj_stun_auth_cred_type +{ + /** + * The credential data contains a static credential to be matched + * against the credential in the message. A static credential can be + * used as both client side or server side authentication. + */ + PJ_STUN_AUTH_CRED_STATIC, + + /** + * The credential data contains callbacks to be called to verify the + * credential in the message. A dynamic credential is suitable when + * performing server side authentication where server does not know + * in advance the identity of the user requesting authentication. + */ + PJ_STUN_AUTH_CRED_DYNAMIC + +} pj_stun_auth_cred_type; + + +/** + * This structure contains the descriptions needed to perform server side + * authentication. Depending on the \a type set in the structure, application + * may specify a static username/password combination, or to have callbacks + * called by the function to authenticate the credential dynamically. + */ +typedef struct pj_stun_auth_cred +{ + /** + * The type of authentication information in this structure. + */ + pj_stun_auth_cred_type type; + + /** + * This union contains the authentication data. + */ + union + { + /** + * This structure contains static data for performing authentication. + * A non-empty realm indicates whether short term or long term + * credential is used. + */ + struct + { + /** + * If not-empty, it indicates that this is a long term credential. + */ + pj_str_t realm; + + /** + * The username of the credential. + */ + pj_str_t username; + + /** + * Data type to indicate the type of password in the \a data field. + * Value zero indicates that the data contains a plaintext + * password. + */ + int data_type; + + /** + * The data, which depends depends on the value of \a data_type + * field. When \a data_type is zero, this field will contain the + * plaintext password. + */ + pj_str_t data; + + /** + * Optional NONCE. + */ + pj_str_t nonce; + + } static_cred; + + /** + * This structure contains callback to be called by the framework + * to authenticate the incoming message. + */ + struct + { + /** + * User data which will be passed back to callback functions. + */ + void *user_data; + + /** + * This callback is called by pj_stun_verify_credential() when + * server needs to challenge the request with 401 response. + * + * @param user_data The user data as specified in the credential. + * @param pool Pool to allocate memory. + * @param realm On return, the function should fill in with + * realm if application wants to use long term + * credential. Otherwise application should set + * empty string for the realm. + * @param nonce On return, if application wants to use long + * term credential, it MUST fill in the nonce + * with some value. Otherwise if short term + * credential is wanted, it MAY set this value. + * If short term credential is wanted and the + * application doesn't want to include NONCE, + * then it must set this to empty string. + * + * @return The callback should return PJ_SUCCESS, or + * otherwise response message will not be + * created. + */ + pj_status_t (*get_auth)(void *user_data, + pj_pool_t *pool, + pj_str_t *realm, + pj_str_t *nonce); + + /** + * Get the password for the specified username. This function + * is also used to check whether the username is valid. + * + * @param user_data The user data as specified in the credential. + * @param realm The realm as specified in the message. + * @param username The username as specified in the message. + * @param pool Pool to allocate memory when necessary. + * @param data_type On return, application should fill up this + * argument with the type of data (which should + * be zero if data is a plaintext password). + * @param data On return, application should fill up this + * argument with the password according to + * data_type. + * + * @return The callback should return PJ_SUCCESS if + * username has been successfully verified + * and password was obtained. If non-PJ_SUCCESS + * is returned, it is assumed that the + * username is not valid. + */ + pj_status_t (*get_password)(void *user_data, + const pj_str_t *realm, + const pj_str_t *username, + pj_pool_t *pool, + int *data_type, + pj_str_t *data); + + /** + * This callback will be called to verify that the NONCE given + * in the message can be accepted. If this callback returns + * PJ_FALSE, 438 (Stale Nonce) response will be created. + * + * @param user_data The user data as specified in the credential. + * @param realm The realm as specified in the message. + * @param username The username as specified in the message. + * @param nonce The nonce to be verified. + * + * @return The callback MUST return non-zero if the + * NONCE can be accepted. + */ + pj_bool_t (*verify_nonce)(void *user_data, + const pj_str_t *realm, + const pj_str_t *username, + const pj_str_t *nonce); + + } dyn_cred; + + } data; + +} pj_stun_auth_cred; + + +/** + * Duplicate authentication credential. + * + * @param pool Pool to be used to allocate memory. + * @param dst Destination credential. + * @param src Source credential. + */ +PJ_DECL(void) pj_stun_auth_cred_dup(pj_pool_t *pool, + pj_stun_auth_cred *dst, + const pj_stun_auth_cred *src); + + +/** + * Verify credential in the STUN message. Note that before calling this + * function, application must have checked that the message contains + * PJ_STUN_ATTR_MESSAGE_INTEGRITY attribute by calling pj_stun_msg_find_attr() + * function, because this function will reject the message with 401 error + * if it doesn't contain PJ_STUN_ATTR_MESSAGE_INTEGRITY attribute. + * + * @param pkt The original packet which has been parsed into + * the message. This packet MUST NOT have been modified + * after the parsing. + * @param pkt_len The length of the packet. + * @param msg The parsed message to be verified. + * @param cred Pointer to credential to be used to authenticate + * the message. + * @param pool If response is to be created, then memory will + * be allocated from this pool. + * @param p_response Optional pointer to receive the response message + * then the credential in the request fails to + * authenticate. + * + * @return PJ_SUCCESS if credential is verified successfully. + * If the verification fails and \a p_response is not + * NULL, an appropriate response will be returned in + * \a p_response. + */ +PJ_DECL(pj_status_t) pj_stun_verify_credential(const pj_uint8_t *pkt, + unsigned pkt_len, + const pj_stun_msg *msg, + pj_stun_auth_cred *cred, + pj_pool_t *pool, + pj_stun_msg **p_response); + + + + +/** + * @} + */ + + +/* Calculate HMAC-SHA1 key for long term credential, by getting + * MD5 digest of username, realm, and password. + */ +void pj_stun_calc_md5_key(pj_uint8_t digest[16], + const pj_str_t *realm, + const pj_str_t *username, + const pj_str_t *passwd); + + +PJ_END_DECL + + +#endif /* __PJ_STUN_AUTH_H__ */ + diff --git a/pjlib-util/include/pjlib-util/stun_msg.h b/pjlib-util/include/pjlib-util/stun_msg.h index 6d4d5a6b..de7f73d2 100644 --- a/pjlib-util/include/pjlib-util/stun_msg.h +++ b/pjlib-util/include/pjlib-util/stun_msg.h @@ -510,7 +510,7 @@ typedef struct pj_stun_attr_hdr \endverbatim */ -typedef struct pj_stun_generic_ip_addr_attr +typedef struct pj_stun_ip_addr_attr { /** * Standard STUN attribute header. @@ -526,7 +526,7 @@ typedef struct pj_stun_generic_ip_addr_attr pj_sockaddr_in6 ipv6; /**< IPv6 socket address. */ } addr; -} pj_stun_generic_ip_addr_attr; +} pj_stun_ip_addr_attr; /** @@ -548,7 +548,7 @@ typedef struct pj_stun_empty_attr * USERNAME, PASSWORD, SERVER, REALM, and NONCE attributes. Note that for REALM and * NONCE attributes, the text MUST be quoted with. */ -typedef struct pj_stun_generic_string_attr +typedef struct pj_stun_string_attr { /** * Standard STUN attribute header. @@ -560,14 +560,14 @@ typedef struct pj_stun_generic_string_attr */ pj_str_t value; -} pj_stun_generic_string_attr; +} pj_stun_string_attr; /** * This structure represents a generic STUN attributes with 32bit (unsigned) * integer value, such as STUN FINGERPRINT and REFRESH-INTERVAL attributes. */ -typedef struct pj_stun_generic_uint_attr +typedef struct pj_stun_uint_attr { /** * Standard STUN attribute header. @@ -579,7 +579,7 @@ typedef struct pj_stun_generic_uint_attr */ pj_uint32_t value; -} pj_stun_generic_uint_attr; +} pj_stun_uint_attr; /** @@ -613,7 +613,7 @@ typedef struct pj_stun_binary_attr * STUN message type. Since it uses the SHA1 hash, the HMAC will be 20 * bytes. */ -typedef struct pj_stun_msg_integrity_attr +typedef struct pj_stun_msgint_attr { /** * Standard STUN attribute header. @@ -625,7 +625,7 @@ typedef struct pj_stun_msg_integrity_attr */ pj_uint8_t hmac[20]; -} pj_stun_msg_integrity_attr; +} pj_stun_msgint_attr; /** @@ -634,7 +634,7 @@ typedef struct pj_stun_msg_integrity_attr * the CRC-32 of the STUN message up to (but excluding) the FINGERPRINT * attribute itself, xor-d with the 32 bit value 0x5354554e */ -typedef struct pj_stun_generic_uint_attr pj_stun_fingerprint_attr; +typedef struct pj_stun_uint_attr pj_stun_fingerprint_attr; /** @@ -655,7 +655,7 @@ typedef struct pj_stun_generic_uint_attr pj_stun_fingerprint_attr; \endverbatim */ -typedef struct pj_stun_error_code_attr +typedef struct pj_stun_errcode_attr { /** * Standard STUN attribute header. @@ -682,7 +682,7 @@ typedef struct pj_stun_error_code_attr */ pj_str_t reason; -} pj_stun_error_code_attr; +} pj_stun_errcode_attr; /** @@ -692,7 +692,7 @@ typedef struct pj_stun_error_code_attr * 3261 [11], and will thus contain a quoted string (including the * quotes). */ -typedef struct pj_stun_generic_string_attr pj_stun_realm_attr; +typedef struct pj_stun_string_attr pj_stun_realm_attr; /** @@ -702,7 +702,7 @@ typedef struct pj_stun_generic_string_attr pj_stun_realm_attr; * RFC 3261 [11]. See RFC 2617 [7] for guidance on selection of nonce * values in a server. */ -typedef struct pj_stun_generic_string_attr pj_stun_nonce_attr; +typedef struct pj_stun_string_attr pj_stun_nonce_attr; /** @@ -739,7 +739,7 @@ typedef struct pj_stun_unknown_attr * This structure describes STUN MAPPED-ADDRESS attribute. * The MAPPED-ADDRESS attribute indicates the mapped transport address. */ -typedef struct pj_stun_generic_ip_addr_attr pj_stun_mapped_addr_attr; +typedef struct pj_stun_ip_addr_attr pj_stun_mapped_addr_attr; /** @@ -751,7 +751,7 @@ typedef struct pj_stun_generic_ip_addr_attr pj_stun_mapped_addr_attr; * obfuscated through the XOR function, STUN messages are able to pass * through NATs which would otherwise interfere with STUN. */ -typedef struct pj_stun_generic_ip_addr_attr pj_stun_xor_mapped_addr_attr; +typedef struct pj_stun_ip_addr_attr pj_stun_xor_mapped_addr_attr; /** @@ -762,7 +762,7 @@ typedef struct pj_stun_generic_ip_addr_attr pj_stun_xor_mapped_addr_attr; * only as a tool for diagnostic and debugging purposes. The value of * SERVER is variable length. */ -typedef struct pj_stun_generic_string_attr pj_stun_server_attr; +typedef struct pj_stun_string_attr pj_stun_server_attr; /** @@ -771,7 +771,7 @@ typedef struct pj_stun_generic_string_attr pj_stun_server_attr; * different STUN server to try. It is encoded in the same way as * MAPPED-ADDRESS. */ -typedef struct pj_stun_generic_ip_addr_attr pj_stun_alt_server_attr; +typedef struct pj_stun_ip_addr_attr pj_stun_alt_server_attr; /** @@ -780,7 +780,7 @@ typedef struct pj_stun_generic_ip_addr_attr pj_stun_alt_server_attr; * server suggests the client should use between refreshes of the NAT * bindings between the client and server. */ -typedef struct pj_stun_generic_uint_attr pj_stun_refresh_interval_attr; +typedef struct pj_stun_uint_attr pj_stun_refresh_interval_attr; /** @@ -792,7 +792,7 @@ typedef struct pj_stun_generic_uint_attr pj_stun_refresh_interval_attr; * Note that the usage of this attribute has been deprecated by the * RFC 3489-bis standard. */ -typedef struct pj_stun_generic_ip_addr_attr pj_stun_response_addr_attr; +typedef struct pj_stun_ip_addr_attr pj_stun_response_addr_attr; /** @@ -807,7 +807,7 @@ typedef struct pj_stun_generic_ip_addr_attr pj_stun_response_addr_attr; * Note that the usage of this attribute has been deprecated by the * RFC 3489-bis standard. */ -typedef struct pj_stun_generic_ip_addr_attr pj_stun_changed_addr_attr; +typedef struct pj_stun_ip_addr_attr pj_stun_changed_addr_attr; /** @@ -827,7 +827,7 @@ typedef struct pj_stun_generic_ip_addr_attr pj_stun_changed_addr_attr; * Note that the usage of this attribute has been deprecated by the * RFC 3489-bis standard. */ -typedef struct pj_stun_generic_uint_attr pj_stun_change_request_attr; +typedef struct pj_stun_uint_attr pj_stun_change_request_attr; /** * This structure describes STUN SOURCE-ADDRESS attribute. @@ -839,7 +839,7 @@ typedef struct pj_stun_generic_uint_attr pj_stun_change_request_attr; * Note that the usage of this attribute has been deprecated by the * RFC 3489-bis standard. */ -typedef struct pj_stun_generic_ip_addr_attr pj_stun_src_addr_attr; +typedef struct pj_stun_ip_addr_attr pj_stun_src_addr_attr; /** @@ -851,7 +851,7 @@ typedef struct pj_stun_generic_ip_addr_attr pj_stun_src_addr_attr; * traceability, so that a STUN server cannot be used as a reflector for * denial-of-service attacks. */ -typedef struct pj_stun_generic_ip_addr_attr pj_stun_reflected_from_attr; +typedef struct pj_stun_ip_addr_attr pj_stun_reflected_from_attr; /** @@ -861,7 +861,7 @@ typedef struct pj_stun_generic_ip_addr_attr pj_stun_reflected_from_attr; * the USERNAME MUST be included in any request that contains the * MESSAGE-INTEGRITY attribute. */ -typedef struct pj_stun_generic_string_attr pj_stun_username_attr; +typedef struct pj_stun_string_attr pj_stun_username_attr; /** @@ -869,7 +869,7 @@ typedef struct pj_stun_generic_string_attr pj_stun_username_attr; * If the message type is Shared Secret Response it MUST include the * PASSWORD attribute. */ -typedef struct pj_stun_generic_string_attr pj_stun_password_attr; +typedef struct pj_stun_string_attr pj_stun_password_attr; /** @@ -879,7 +879,7 @@ typedef struct pj_stun_generic_string_attr pj_stun_password_attr; * from or to the client. It is a 32 bit value representing the number * of seconds remaining until expiration. */ -typedef struct pj_stun_generic_uint_attr pj_stun_lifetime_attr; +typedef struct pj_stun_uint_attr pj_stun_lifetime_attr; /** @@ -888,7 +888,7 @@ typedef struct pj_stun_generic_uint_attr pj_stun_lifetime_attr; * kbits per second, that the client expects to use on the binding. The * value represents the sum in the receive and send directions. */ -typedef struct pj_stun_generic_uint_attr pj_stun_bandwidth_attr; +typedef struct pj_stun_uint_attr pj_stun_bandwidth_attr; /** @@ -896,7 +896,7 @@ typedef struct pj_stun_generic_uint_attr pj_stun_bandwidth_attr; * The REMOTE-ADDRESS specifies the address and port of the peer as seen * from the STUN relay server. */ -typedef struct pj_stun_generic_ip_addr_attr pj_stun_remote_addr_attr; +typedef struct pj_stun_ip_addr_attr pj_stun_remote_addr_attr; /** @@ -914,7 +914,7 @@ typedef struct pj_stun_binary_attr pj_stun_data_attr; * The RELAY-ADDRESS is present in Allocate responses. It specifies the * address and port that the server allocated to the client. */ -typedef struct pj_stun_generic_ip_addr_attr pj_stun_relay_addr_attr; +typedef struct pj_stun_ip_addr_attr pj_stun_relay_addr_attr; /** @@ -933,7 +933,7 @@ typedef struct pj_stun_generic_ip_addr_attr pj_stun_relay_addr_attr; \endverbatim */ -typedef struct pj_stun_generic_uint_attr pj_stun_requested_addr_type; +typedef struct pj_stun_uint_attr pj_stun_requested_addr_type; /** * This describes the STUN REQUESTED-PORT-PROPS attribute. @@ -953,7 +953,7 @@ typedef struct pj_stun_generic_uint_attr pj_stun_requested_addr_type; \endverbatim */ -typedef struct pj_stun_generic_uint_attr pj_stun_requested_port_props_attr; +typedef struct pj_stun_uint_attr pj_stun_requested_port_props_attr; /** @@ -962,7 +962,7 @@ typedef struct pj_stun_generic_uint_attr pj_stun_requested_port_props_attr; * protocol for the allocated transport address. It is a 32 bit * unsigned integer. Its values are: 0x0000 for UDP and 0x0000 for TCP. */ -typedef struct pj_stun_generic_uint_attr pj_stun_requested_transport_attr; +typedef struct pj_stun_uint_attr pj_stun_requested_transport_attr; /** @@ -970,7 +970,7 @@ typedef struct pj_stun_generic_uint_attr pj_stun_requested_transport_attr; * The REQUESTED-IP attribute is used by the client to request that a * specific IP address be allocated to it. */ -typedef struct pj_stun_generic_ip_addr_attr pj_stun_requested_ip_attr; +typedef struct pj_stun_ip_addr_attr pj_stun_requested_ip_attr; /** * This describes the XOR-REFLECTED-FROM attribute, as described by @@ -982,7 +982,7 @@ typedef struct pj_stun_generic_ip_addr_attr pj_stun_requested_ip_attr; * the private network address. XOR-REFLECTED-FROM has identical syntax * to XOR-MAPPED-ADDRESS. */ -typedef struct pj_stun_generic_ip_addr_attr pj_stun_xor_reflected_from_attr; +typedef struct pj_stun_ip_addr_attr pj_stun_xor_reflected_from_attr; /** * This describes the PRIORITY attribute from draft-ietf-mmusic-ice-13. @@ -991,7 +991,7 @@ typedef struct pj_stun_generic_ip_addr_attr pj_stun_xor_reflected_from_attr; * by this check. It is a 32 bit unsigned integer, and has an attribute * type of 0x0024. */ -typedef struct pj_stun_generic_uint_attr pj_stun_priority_attr; +typedef struct pj_stun_uint_attr pj_stun_priority_attr; /** * This describes the USE-CANDIDATE attribute from draft-ietf-mmusic-ice-13. @@ -1010,7 +1010,7 @@ typedef struct pj_stun_empty_attr pj_stun_use_candidate_attr; * STUN client to 'walk backwards' and communicate directly with all of * the STUN-aware NATs along the path. */ -typedef pj_stun_generic_ip_addr_attr pj_stun_xor_internal_addr_attr; +typedef pj_stun_ip_addr_attr pj_stun_xor_internal_addr_attr; /** * This describes the STUN TIMER-VAL attribute. @@ -1018,7 +1018,7 @@ typedef pj_stun_generic_ip_addr_attr pj_stun_xor_internal_addr_attr; * Active Destination response. It conveys from the server, to the * client, the value of the timer used in the server state machine. */ -typedef struct pj_stun_generic_uint_attr pj_stun_timer_val_attr; +typedef struct pj_stun_uint_attr pj_stun_timer_val_attr; /** @@ -1047,7 +1047,7 @@ typedef struct pj_stun_msg /** STUN decoding options */ -enum pj_stun_options +enum pj_stun_decode_options { /** * Tell the decoder that the message was received from datagram @@ -1063,6 +1063,7 @@ enum pj_stun_options PJ_STUN_CHECK_PACKET = 2 }; + /** * Get STUN message method name. * @@ -1207,15 +1208,15 @@ PJ_DECL(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg, * @param pdu The packet buffer. * @param pdu_len The length of the packet buffer. * @param options Additional options to be applied in the checking, - * which can be taken from pj_stun_options. One of the - * useful option is PJ_STUN_IS_DATAGRAM which means that - * the pdu represents a whole STUN packet. + * which can be taken from pj_stun_decode_options. One + * of the useful option is PJ_STUN_IS_DATAGRAM which + * means that the pdu represents a whole STUN packet. * * @return PJ_SUCCESS if the PDU is a potentially valid STUN * message. */ -PJ_DECL(pj_status_t) pj_stun_msg_check(const pj_uint8_t *pdu, unsigned pdu_len, - unsigned options); +PJ_DECL(pj_status_t) pj_stun_msg_check(const pj_uint8_t *pdu, + unsigned pdu_len, unsigned options); /** @@ -1224,7 +1225,7 @@ PJ_DECL(pj_status_t) pj_stun_msg_check(const pj_uint8_t *pdu, unsigned pdu_len, * @param pool Pool to allocate the message. * @param pdu The incoming packet to be parsed. * @param pdu_len The length of the incoming packet. - * @param options Parsing flags, according to pj_stun_options. + * @param options Parsing flags, according to pj_stun_decode_options. * @param p_msg Pointer to receive the parsed message. * @param p_parsed_len Optional pointer to receive how many bytes have * been parsed for the STUN message. This is useful @@ -1247,138 +1248,6 @@ PJ_DECL(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool, unsigned *p_parsed_len, pj_stun_msg **p_response); -typedef enum pj_stun_auth_policy_type -{ - PJ_STUN_POLICY_NONE, - PJ_STUN_POLICY_STATIC_SHORT_TERM, - PJ_STUN_POLICY_STATIC_LONG_TERM, - PJ_STUN_POLICY_DYNAMIC -} pj_stun_auth_policy_type; - -typedef struct pj_stun_auth_policy -{ - pj_stun_auth_policy_type type; - void *user_data; - - union - { - struct - { - pj_str_t username; - pj_str_t password; - pj_str_t nonce; - } static_short_term; - - struct - { - pj_str_t realm; - pj_str_t username; - pj_str_t password; - pj_str_t nonce; - } static_long_term; - - struct - { - /** - * This callback is called by pj_stun_verify_credential() when - * server needs to challenge the request with 401 response. - * - * @param user_data The user data as specified in the policy. - * @param pool Pool to allocate memory. - * @param realm On return, the function should fill in with - * realm if application wants to use long term - * credential. Otherwise application should set - * empty string for the realm. - * @param nonce On return, if application wants to use long - * term credential, it MUST fill in the nonce - * with some value. Otherwise if short term - * credential is wanted, it MAY set this value. - * If short term credential is wanted and the - * application doesn't want to include NONCE, - * then it must set this to empty string. - * - * @return The callback should return PJ_SUCCESS, or - * otherwise response message will not be - * created. - */ - pj_status_t (*get_auth)(void *user_data, - pj_pool_t *pool, - pj_str_t *realm, - pj_str_t *nonce); - - /** - * Get the password for the specified username. This function - * is also used to check whether the username is valid. - * - * @param user_data The user data as specified in the policy. - * @param realm The realm as specified in the message. - * @param username The username as specified in the message. - * @param pool Pool to allocate memory when necessary. - * @param password On return, application should fill up this - * argument with the password. - * - * @return The callback should return PJ_SUCCESS if - * username has been successfully verified - * and password was obtained. If non-PJ_SUCCESS - * is returned, it is assumed that the - * username is not valid. - */ - pj_status_t (*get_password)(void *user_data, - const pj_str_t *realm, - const pj_str_t *username, - pj_pool_t *pool, - pj_str_t *password); - pj_bool_t (*require_nonce)(void *user_data, - const pj_str_t *realm, - const pj_str_t *username); - pj_bool_t (*verify_nonce)(void *data, - const pj_str_t *realm, - const pj_str_t *username, - const pj_str_t *nonce); - pj_status_t (*make_nonce)(void *user_data, - const pj_str_t *realm, - const pj_str_t *username, - pj_pool_t *pool, - pj_str_t *nonce); - } dynamic; - - } data; - -} pj_stun_auth_policy; - - -/** - * Verify credential in the STUN message. Note that before calling this - * function, application must have checked that the message contains - * PJ_STUN_ATTR_MESSAGE_INTEGRITY attribute by calling pj_stun_msg_find_attr() - * function, because this function will reject the message with 401 error - * if it doesn't contain PJ_STUN_ATTR_MESSAGE_INTEGRITY attribute. - * - * @param pkt The original packet which has been parsed into - * the message. This packet MUST NOT have been modified - * after the parsing. - * @param pkt_len The length of the packet. - * @param msg The parsed message to be verified. - * @param policy Pointer to authentication policy. - * @param pool If response is to be created, then memory will - * be allocated from this pool. - * @param p_response Optional pointer to receive the response message - * then the credential in the request fails to - * authenticate. - * - * @return PJ_SUCCESS if credential is verified successfully. - * If the verification fails and \a p_response is not - * NULL, an appropriate response will be returned in - * \a p_response. - */ -PJ_DECL(pj_status_t) pj_stun_verify_credential(const pj_uint8_t *pkt, - unsigned pkt_len, - const pj_stun_msg *msg, - pj_stun_auth_policy *policy, - pj_pool_t *pool, - pj_stun_msg **p_response); - - /** * Dump STUN message to a printable string output. * @@ -1430,13 +1299,12 @@ PJ_DECL(pj_stun_attr_hdr*) pj_stun_msg_find_attr(const pj_stun_msg *msg, * * @return PJ_SUCCESS on success or the appropriate error code. */ -PJ_DECL(pj_status_t) -pj_stun_generic_ip_addr_attr_create(pj_pool_t *pool, - int attr_type, - pj_bool_t xor_ed, - const pj_sockaddr_t *addr, - unsigned addr_len, - pj_stun_generic_ip_addr_attr **p_attr); +PJ_DECL(pj_status_t) pj_stun_ip_addr_attr_create(pj_pool_t *pool, + int attr_type, + pj_bool_t xor_ed, + const pj_sockaddr_t *addr, + unsigned addr_len, + pj_stun_ip_addr_attr **p_attr); /** @@ -1454,13 +1322,12 @@ pj_stun_generic_ip_addr_attr_create(pj_pool_t *pool, * * @return PJ_SUCCESS on success or the appropriate error code. */ -PJ_DECL(pj_status_t) -pj_stun_msg_add_generic_ip_addr_attr(pj_pool_t *pool, - pj_stun_msg *msg, - int attr_type, - pj_bool_t xor_ed, - const pj_sockaddr_t *addr, - unsigned addr_len); +PJ_DECL(pj_status_t) pj_stun_msg_add_ip_addr_attr(pj_pool_t *pool, + pj_stun_msg *msg, + int attr_type, + pj_bool_t xor_ed, + const pj_sockaddr_t *addr, + unsigned addr_len); /** * Create a STUN generic string attribute. @@ -1472,11 +1339,10 @@ pj_stun_msg_add_generic_ip_addr_attr(pj_pool_t *pool, * * @return PJ_SUCCESS on success or the appropriate error code. */ -PJ_DECL(pj_status_t) -pj_stun_generic_string_attr_create(pj_pool_t *pool, - int attr_type, - const pj_str_t *value, - pj_stun_generic_string_attr **p_attr); +PJ_DECL(pj_status_t) pj_stun_string_attr_create(pj_pool_t *pool, + int attr_type, + const pj_str_t *value, + pj_stun_string_attr **p_attr); /** * Create and add STUN generic string attribute to the message. @@ -1488,11 +1354,10 @@ pj_stun_generic_string_attr_create(pj_pool_t *pool, * * @return PJ_SUCCESS on success or the appropriate error code. */ -PJ_DECL(pj_status_t) -pj_stun_msg_add_generic_string_attr(pj_pool_t *pool, - pj_stun_msg *msg, - int attr_type, - const pj_str_t *value); +PJ_DECL(pj_status_t) pj_stun_msg_add_string_attr(pj_pool_t *pool, + pj_stun_msg *msg, + int attr_type, + const pj_str_t *value); /** * Create a STUN generic 32bit value attribute. @@ -1504,11 +1369,10 @@ pj_stun_msg_add_generic_string_attr(pj_pool_t *pool, * * @return PJ_SUCCESS on success or the appropriate error code. */ -PJ_DECL(pj_status_t) -pj_stun_generic_uint_attr_create(pj_pool_t *pool, - int attr_type, - pj_uint32_t value, - pj_stun_generic_uint_attr **p_attr); +PJ_DECL(pj_status_t) pj_stun_uint_attr_create(pj_pool_t *pool, + int attr_type, + pj_uint32_t value, + pj_stun_uint_attr **p_attr); /** * Create and add STUN generic 32bit value attribute to the message. @@ -1520,11 +1384,10 @@ pj_stun_generic_uint_attr_create(pj_pool_t *pool, * * @return PJ_SUCCESS on success or the appropriate error code. */ -PJ_DECL(pj_status_t) -pj_stun_msg_add_generic_uint_attr(pj_pool_t *pool, - pj_stun_msg *msg, - int attr_type, - pj_uint32_t value); +PJ_DECL(pj_status_t) pj_stun_msg_add_uint_attr(pj_pool_t *pool, + pj_stun_msg *msg, + int attr_type, + pj_uint32_t value); /** @@ -1535,9 +1398,19 @@ pj_stun_msg_add_generic_uint_attr(pj_pool_t *pool, * * @return PJ_SUCCESS on success or the appropriate error code. */ -PJ_DECL(pj_status_t) -pj_stun_msg_integrity_attr_create(pj_pool_t *pool, - pj_stun_msg_integrity_attr **p_attr); +PJ_DECL(pj_status_t) pj_stun_msgint_attr_create(pj_pool_t *pool, + pj_stun_msgint_attr **p_attr); + +/** + * Create and add STUN MESSAGE-INTEGRITY attribute. + * + * @param pool The pool to allocate memory from. + * @param msg The STUN message + * + * @return PJ_SUCCESS on success or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_stun_msg_add_msgint_attr(pj_pool_t *pool, + pj_stun_msg *msg); /** * Create a STUN ERROR-CODE attribute. @@ -1550,12 +1423,27 @@ pj_stun_msg_integrity_attr_create(pj_pool_t *pool, * * @return PJ_SUCCESS on success or the appropriate error code. */ -PJ_DECL(pj_status_t) -pj_stun_error_code_attr_create(pj_pool_t *pool, - int err_code, - const pj_str_t *err_reason, - pj_stun_error_code_attr **p_attr); +PJ_DECL(pj_status_t) pj_stun_errcode_attr_create(pj_pool_t *pool, + int err_code, + const pj_str_t *err_reason, + pj_stun_errcode_attr **p_attr); + +/** + * Create and add STUN ERROR-CODE attribute to the message. + * + * @param pool The pool to allocate memory from. + * @param msg The STUN mesage. + * @param err_code STUN error code. + * @param err_reason Optional STUN error reason. If NULL is given, the + * standard error reason will be given. + * + * @return PJ_SUCCESS on success or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_stun_msg_add_errcode_attr(pj_pool_t *pool, + pj_stun_msg *msg, + int err_code, + const pj_str_t *err_reason); /** * Create instance of STUN UNKNOWN-ATTRIBUTES attribute and copy the @@ -1568,11 +1456,10 @@ pj_stun_error_code_attr_create(pj_pool_t *pool, * * @return PJ_SUCCESS on success or the appropriate error code. */ -PJ_DECL(pj_status_t) -pj_stun_unknown_attr_create(pj_pool_t *pool, - unsigned attr_cnt, - const pj_uint16_t attr[], - pj_stun_unknown_attr **p_attr); +PJ_DECL(pj_status_t) pj_stun_unknown_attr_create(pj_pool_t *pool, + unsigned attr_cnt, + const pj_uint16_t attr[], + pj_stun_unknown_attr **p_attr); /** * Create and add STUN UNKNOWN-ATTRIBUTES attribute to the message. @@ -1584,11 +1471,10 @@ pj_stun_unknown_attr_create(pj_pool_t *pool, * * @return PJ_SUCCESS on success or the appropriate error code. */ -PJ_DECL(pj_status_t) -pj_stun_msg_add_unknown_attr(pj_pool_t *pool, - pj_stun_msg *msg, - unsigned attr_cnt, - const pj_uint16_t attr[]); +PJ_DECL(pj_status_t) pj_stun_msg_add_unknown_attr(pj_pool_t *pool, + pj_stun_msg *msg, + unsigned attr_cnt, + const pj_uint16_t attr[]); /** * Create STUN binary attribute. @@ -1603,12 +1489,11 @@ pj_stun_msg_add_unknown_attr(pj_pool_t *pool, * * @return PJ_SUCCESS on success or the appropriate error code. */ -PJ_DECL(pj_status_t) -pj_stun_binary_attr_create(pj_pool_t *pool, - int attr_type, - const pj_uint8_t *data, - unsigned length, - pj_stun_binary_attr **p_attr); +PJ_DECL(pj_status_t) pj_stun_binary_attr_create(pj_pool_t *pool, + int attr_type, + const pj_uint8_t *data, + unsigned length, + pj_stun_binary_attr **p_attr); /** * Create STUN binary attribute and add the attribute to the message. @@ -1624,12 +1509,11 @@ pj_stun_binary_attr_create(pj_pool_t *pool, * * @return PJ_SUCCESS on success or the appropriate error code. */ -PJ_DECL(pj_status_t) -pj_stun_msg_add_binary_attr(pj_pool_t *pool, - pj_stun_msg *msg, - int attr_type, - const pj_uint8_t *data, - unsigned length); +PJ_DECL(pj_status_t) pj_stun_msg_add_binary_attr(pj_pool_t *pool, + pj_stun_msg *msg, + int attr_type, + const pj_uint8_t *data, + unsigned length); /** diff --git a/pjlib-util/include/pjlib-util/stun_server.h b/pjlib-util/include/pjlib-util/stun_server.h deleted file mode 100644 index 15ecf308..00000000 --- a/pjlib-util/include/pjlib-util/stun_server.h +++ /dev/null @@ -1,109 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2003-2005 Benny Prijono <benny@prijono.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __PJ_STUN_SERVER_H__ -#define __PJ_STUN_SERVER_H__ - -/** - * @file stun_server.h - * @brief STUN server side services. - */ - -#include <pjlib-util/stun_msg.h> -#include <pjlib-util/stun_endpoint.h> - - -PJ_BEGIN_DECL - - -/* **************************************************************************/ -/** - * @defgroup PJLIB_UTIL_STUN_SERVER STUN Server Side Services - * @brief STUN server side services - * @ingroup PJLIB_UTIL_STUN - * @{ - */ - -typedef struct pj_stun_service pj_stun_service; - - -/** - * STUN service handler. - */ -typedef struct pj_stun_service_handler -{ - /** - * The STUN message type. - */ - int msg_type; - - /** - * Callback to be called to handle this STUN message type. - * - * @param svc The service. - * @param msg The STUN message. - */ - pj_status_t (*handle_msg)(pj_stun_service *svc, - void *handle_data, - const pj_stun_msg *msg); - -} pj_stun_service_handler; - - -/** - * Create STUN service. - */ -PJ_DECL(pj_status_t) pj_stun_service_create(pj_pool_t *pool, - const char *name, - unsigned options, - unsigned handler_cnt, - pj_stun_service_handler cb[], - void *user_data, - pj_stun_service **p_svc); - -/** - * Destroy STUN service - */ -PJ_DECL(pj_status_t) pj_stun_service_destroy(pj_stun_service *svc); - - -/** - * Get user data associated with the STUN service. - */ -PJ_DECL(void*) pj_stun_service_get_user_data(pj_stun_service *svc); - - -/** - * Instruct the STUN service to handle incoming STUN message. - */ -PJ_DECL(pj_status_t) pj_stun_service_handle_msg(pj_stun_service *svc, - void *handle_data, - const pj_stun_msg *msg); - - - -/** - * @} - */ - - -PJ_END_DECL - - -#endif /* __PJ_STUN_SERVER_H__ */ - diff --git a/pjlib-util/include/pjlib-util/stun_session.h b/pjlib-util/include/pjlib-util/stun_session.h index 610302fa..8fe7b1ca 100644 --- a/pjlib-util/include/pjlib-util/stun_session.h +++ b/pjlib-util/include/pjlib-util/stun_session.h @@ -20,6 +20,7 @@ #define __PJLIB_UTIL_STUN_SESSION_H__ #include <pjlib-util/stun_msg.h> +#include <pjlib-util/stun_auth.h> #include <pjlib-util/stun_endpoint.h> #include <pjlib-util/stun_transaction.h> #include <pj/list.h> @@ -147,7 +148,6 @@ struct pj_stun_tx_data unsigned max_len; /**< Length of packet buffer. */ unsigned pkt_size; /**< The actual length of STUN pkt. */ - unsigned options; /**< Options specified when sending */ unsigned addr_len; /**< Length of destination address. */ const pj_sockaddr_t *dst_addr; /**< Destination address. */ @@ -156,52 +156,21 @@ struct pj_stun_tx_data /** - * Options that can be specified when creating or sending outgoing STUN - * messages. These options may be specified as bitmask. - */ -enum pj_stun_session_send_option -{ - /** - * Add short term credential to the message. This option may not be used - * together with PJ_STUN_USE_LONG_TERM_CRED option. - */ - PJ_STUN_USE_SHORT_TERM_CRED = 1, - - /** - * Add long term credential to the message. This option may not be used - * together with PJ_STUN_USE_SHORT_TERM_CRED option. - */ - PJ_STUN_USE_LONG_TERM_CRED = 2, - - /** - * Add STUN fingerprint to the message. - */ - PJ_STUN_USE_FINGERPRINT = 4, - - /** - * Instruct the session to cache outgoing response. This can only be - * used when sending outgoing response message, and when it's specified, - * the session will use \a res_cache_msec settings in pj_stun_endpoint - * as the duration of the cache. - */ - PJ_STUN_CACHE_RESPONSE = 8 -}; - - -/** * Create a STUN session. * - * @param endpt The STUN endpoint, to be used to register timers etc. - * @param name Optional name to be associated with this instance. The - * name will be used for example for logging purpose. - * @param cb Session callback. - * @param p_sess Pointer to receive STUN session instance. + * @param endpt The STUN endpoint, to be used to register timers etc. + * @param name Optional name to be associated with this instance. The + * name will be used for example for logging purpose. + * @param cb Session callback. + * @param fingerprint Enable message fingerprint for outgoing messages. + * @param p_sess Pointer to receive STUN session instance. * * @return PJ_SUCCESS on success, or the appropriate error code. */ PJ_DECL(pj_status_t) pj_stun_session_create(pj_stun_endpoint *endpt, const char *name, const pj_stun_session_cb *cb, + pj_bool_t fingerprint, pj_stun_session **p_sess); /** @@ -235,42 +204,32 @@ PJ_DECL(pj_status_t) pj_stun_session_set_user_data(pj_stun_session *sess, PJ_DECL(void*) pj_stun_session_get_user_data(pj_stun_session *sess); /** - * Save a long term credential to be used by this STUN session when sending - * outgoing messages. After long term credential is configured, application - * may specify PJ_STUN_USE_LONG_TERM_CRED option when sending outgoing STUN - * message to send the long term credential in the message. + * Set server name to be included in all response. * * @param sess The STUN session instance. - * @param realm Realm of the long term credential. - * @param user The user name. - * @param passwd The pain-text password. + * @param srv_name Server name string. * - * @return PJ_SUCCESS on success, or the appropriate error code. + * @return The user data associated with this STUN session. */ -PJ_DECL(pj_status_t) -pj_stun_session_set_long_term_credential(pj_stun_session *sess, - const pj_str_t *realm, - const pj_str_t *user, - const pj_str_t *passwd); - +PJ_DECL(pj_status_t) pj_stun_session_set_server_name(pj_stun_session *sess, + const pj_str_t *srv_name); /** - * Save a short term credential to be used by this STUN session when sending - * outgoing messages. After short term credential is configured, application - * may specify PJ_STUN_USE_SHORT_TERM_CRED option when sending outgoing STUN - * message to send the short term credential in the message. + * Set credential to be used by this session. Once credential is set, all + * outgoing messages will include MESSAGE-INTEGRITY, and all incoming + * message will be authenticated against this credential. + * + * To disable authentication after it has been set, call this function + * again with NULL as the argument. * * @param sess The STUN session instance. - * @param user The user name. - * @param passwd The pain-text password. + * @param cred The credential to be used by this session. If NULL + * is specified, authentication will be disabled. * * @return PJ_SUCCESS on success, or the appropriate error code. */ -PJ_DECL(pj_status_t) -pj_stun_session_set_short_term_credential(pj_stun_session *sess, - const pj_str_t *user, - const pj_str_t *passwd); - +PJ_DECL(void) pj_stun_session_set_credential(pj_stun_session *sess, + const pj_stun_auth_cred *cred); /** * Create a STUN Bind request message. After the message has been @@ -409,7 +368,7 @@ PJ_DECL(pj_status_t) pj_stun_session_create_response(pj_stun_session *sess, * to actually send the message to the wire. * * @param sess The STUN session instance. - * @param options Optional flags, from pj_stun_session_send_option. + * @param cache_res If PJ_TRUE then response will be cached. * @param dst_addr The destination socket address. * @param addr_len Length of destination address. * @param tdata The STUN transmit data containing the STUN message to @@ -418,7 +377,7 @@ PJ_DECL(pj_status_t) pj_stun_session_create_response(pj_stun_session *sess, * @return PJ_SUCCESS on success, or the appropriate error code. */ PJ_DECL(pj_status_t) pj_stun_session_send_msg(pj_stun_session *sess, - unsigned options, + pj_bool_t cache_res, const pj_sockaddr_t *dst_addr, unsigned addr_len, pj_stun_tx_data *tdata); diff --git a/pjlib-util/src/pjlib-util/errno.c b/pjlib-util/src/pjlib-util/errno.c index 11e67c68..a60b3184 100644 --- a/pjlib-util/src/pjlib-util/errno.c +++ b/pjlib-util/src/pjlib-util/errno.c @@ -68,6 +68,23 @@ static const struct PJ_BUILD_ERR( PJLIB_UTIL_EDNS_NXRRSET, "DNS \"The RRset (name, type) does not exist\""), PJ_BUILD_ERR( PJLIB_UTIL_EDNS_NOTAUTH, "DNS \"Not authorized\""), PJ_BUILD_ERR( PJLIB_UTIL_EDNS_NOTZONE, "DNS \"The zone specified is not a zone\""), + + /* STUN */ + PJ_BUILD_ERR( PJLIB_UTIL_ESTUNTOOMANYATTR, "Too many STUN attributes"), + PJ_BUILD_ERR( PJLIB_UTIL_ESTUNUNKNOWNATTR, "Unknown STUN attribute"), + PJ_BUILD_ERR( PJLIB_UTIL_ESTUNINADDRLEN, "Invalid STUN socket address length"), + PJ_BUILD_ERR( PJLIB_UTIL_ESTUNIPV6NOTSUPP, "STUN IPv6 attribute not supported"), + PJ_BUILD_ERR( PJLIB_UTIL_ESTUNNOTRESPONSE, "Expecting STUN response message"), + PJ_BUILD_ERR( PJLIB_UTIL_ESTUNINVALIDID, "STUN transaction ID mismatch"), + PJ_BUILD_ERR( PJLIB_UTIL_ESTUNNOHANDLER, "Unable to find STUN handler for the request"), + PJ_BUILD_ERR( PJLIB_UTIL_ESTUNMSGINTPOS, "Found non-FINGERPRINT attr. after MESSAGE-INTEGRITY"), + PJ_BUILD_ERR( PJLIB_UTIL_ESTUNFINGERPOS, "Found STUN attribute after FINGERPRINT"), + PJ_BUILD_ERR( PJLIB_UTIL_ESTUNNOUSERNAME, "Missing STUN USERNAME attribute"), + PJ_BUILD_ERR( PJLIB_UTIL_ESTUNMSGINT, "Missing/invalid STUN MESSAGE-INTEGRITY attribute"), + PJ_BUILD_ERR( PJLIB_UTIL_ESTUNDUPATTR, "Found duplicate STUN attribute"), + PJ_BUILD_ERR( PJLIB_UTIL_ESTUNNOREALM, "Missing STUN REALM attribute"), + PJ_BUILD_ERR( PJLIB_UTIL_ESTUNNONCE, "Missing/stale STUN NONCE attribute value"), + PJ_BUILD_ERR( PJLIB_UTIL_ESTUNTSXFAILED, "STUN transaction terminates with failure"), }; #endif /* PJ_HAS_ERROR_STRING */ diff --git a/pjlib-util/src/pjlib-util/stun_auth.c b/pjlib-util/src/pjlib-util/stun_auth.c new file mode 100644 index 00000000..abf61b6e --- /dev/null +++ b/pjlib-util/src/pjlib-util/stun_auth.c @@ -0,0 +1,341 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2005 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <pjlib-util/stun_auth.h> +#include <pjlib-util/errno.h> +#include <pjlib-util/hmac_sha1.h> +#include <pjlib-util/sha1.h> +#include <pj/assert.h> +#include <pj/string.h> + + +/* Duplicate credential */ +PJ_DEF(void) pj_stun_auth_cred_dup( pj_pool_t *pool, + pj_stun_auth_cred *dst, + const pj_stun_auth_cred *src) +{ + dst->type = src->type; + + switch (src->type) { + case PJ_STUN_AUTH_CRED_STATIC: + pj_strdup(pool, &dst->data.static_cred.realm, + &src->data.static_cred.realm); + pj_strdup(pool, &dst->data.static_cred.username, + &src->data.static_cred.username); + dst->data.static_cred.data_type = src->data.static_cred.data_type; + pj_strdup(pool, &dst->data.static_cred.data, + &src->data.static_cred.data); + pj_strdup(pool, &dst->data.static_cred.nonce, + &src->data.static_cred.nonce); + break; + case PJ_STUN_AUTH_CRED_DYNAMIC: + pj_memcpy(&dst->data.dyn_cred, &src->data.dyn_cred, + sizeof(src->data.dyn_cred)); + break; + } +} + + +PJ_INLINE(pj_uint16_t) GET_VAL16(const pj_uint8_t *pdu, unsigned pos) +{ + return (pj_uint16_t) ((pdu[pos] << 8) + pdu[pos+1]); +} + + +/* Send 401 response */ +static pj_status_t create_challenge(pj_pool_t *pool, + const pj_stun_msg *msg, + int err_code, + const pj_str_t *err_msg, + const pj_str_t *realm, + const pj_str_t *nonce, + pj_stun_msg **p_response) +{ + pj_stun_msg *response; + pj_str_t tmp_nonce; + pj_status_t rc; + + rc = pj_stun_msg_create_response(pool, msg, + err_code, err_msg, &response); + if (rc != PJ_SUCCESS) + return rc; + + + if (realm && realm->slen) { + rc = pj_stun_msg_add_string_attr(pool, response, + PJ_STUN_ATTR_REALM, + realm); + if (rc != PJ_SUCCESS) + return rc; + + /* long term must include nonce */ + if (!nonce || nonce->slen == 0) { + tmp_nonce = pj_str("pjstun"); + nonce = &tmp_nonce; + } + } + + if (nonce && nonce->slen) { + rc = pj_stun_msg_add_string_attr(pool, response, + PJ_STUN_ATTR_NONCE, + nonce); + if (rc != PJ_SUCCESS) + return rc; + } + + *p_response = response; + + return PJ_SUCCESS; +} + + +/* Verify credential */ +PJ_DEF(pj_status_t) pj_stun_verify_credential( const pj_uint8_t *pkt, + unsigned pkt_len, + const pj_stun_msg *msg, + pj_stun_auth_cred *cred, + pj_pool_t *pool, + pj_stun_msg **p_response) +{ + pj_str_t realm, nonce, password; + const pj_stun_msgint_attr *amsgi; + unsigned amsgi_pos; + const pj_stun_username_attr *auser; + pj_bool_t username_ok; + const pj_stun_realm_attr *arealm; + const pj_stun_realm_attr *anonce; + pj_uint8_t digest[PJ_SHA1_DIGEST_SIZE]; + pj_uint8_t md5_digest[16]; + pj_str_t key; + pj_status_t status; + + /* msg and credential MUST be specified */ + PJ_ASSERT_RETURN(pkt && pkt_len && msg && cred, PJ_EINVAL); + + /* If p_response is specified, pool MUST be specified. */ + PJ_ASSERT_RETURN(!p_response || pool, PJ_EINVAL); + + if (p_response) + *p_response = NULL; + + if (!PJ_STUN_IS_REQUEST(msg->hdr.type)) + p_response = NULL; + + /* Get realm and nonce */ + realm.slen = nonce.slen = 0; + if (cred->type == PJ_STUN_AUTH_CRED_STATIC) { + realm = cred->data.static_cred.realm; + nonce = cred->data.static_cred.nonce; + } else if (cred->type == PJ_STUN_AUTH_CRED_DYNAMIC) { + status = cred->data.dyn_cred.get_auth(cred->data.dyn_cred.user_data, + pool, &realm, &nonce); + if (status != PJ_SUCCESS) + return status; + } else { + pj_assert(!"Unexpected"); + return PJ_EBUG; + } + + /* First check that MESSAGE-INTEGRITY is present */ + amsgi = (const pj_stun_msgint_attr*) + pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_MESSAGE_INTEGRITY, 0); + if (amsgi == NULL) { + if (p_response) { + create_challenge(pool, msg, PJ_STUN_STATUS_UNAUTHORIZED, NULL, + &realm, &nonce, p_response); + } + return PJLIB_UTIL_ESTUNMSGINT; + } + + /* Next check that USERNAME is present */ + auser = (const pj_stun_username_attr*) + pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USERNAME, 0); + if (auser == NULL) { + if (p_response) { + create_challenge(pool, msg, PJ_STUN_STATUS_MISSING_USERNAME, NULL, + &realm, &nonce, p_response); + } + return PJLIB_UTIL_ESTUNNOUSERNAME; + } + + /* Get REALM, if any */ + arealm = (const pj_stun_realm_attr*) + pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_REALM, 0); + + /* Check if username match */ + if (cred->type == PJ_STUN_AUTH_CRED_STATIC) { + username_ok = !pj_strcmp(&auser->value, + &cred->data.static_cred.username); + password = cred->data.static_cred.data; + } else if (cred->type == PJ_STUN_AUTH_CRED_DYNAMIC) { + int data_type = 0; + pj_status_t rc; + rc = cred->data.dyn_cred.get_password(cred->data.dyn_cred.user_data, + (arealm?&arealm->value:NULL), + &auser->value, pool, + &data_type, &password); + username_ok = (rc == PJ_SUCCESS); + } else { + username_ok = PJ_TRUE; + password.slen = 0; + } + + if (!username_ok) { + /* Username mismatch */ + if (p_response) { + create_challenge(pool, msg, PJ_STUN_STATUS_UNKNOWN_USERNAME, NULL, + &realm, &nonce, p_response); + } + return PJLIB_UTIL_ESTUNUSERNAME; + } + + + /* Get NONCE attribute */ + anonce = (pj_stun_nonce_attr*) + pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_NONCE, 0); + + /* Check for long term/short term requirements. */ + if (realm.slen != 0 && arealm == NULL) { + /* Long term credential is required and REALM is not present */ + if (p_response) { + create_challenge(pool, msg, PJ_STUN_STATUS_MISSING_REALM, NULL, + &realm, &nonce, p_response); + } + return PJLIB_UTIL_ESTUNNOREALM; + + } else if (realm.slen != 0 && arealm != NULL) { + /* We want long term, and REALM is present */ + + /* NONCE must be present. */ + if (anonce == NULL) { + if (p_response) { + create_challenge(pool, msg, PJ_STUN_STATUS_MISSING_NONCE, + NULL, &realm, &nonce, p_response); + } + return PJLIB_UTIL_ESTUNNONCE; + } + + /* Verify REALM matches */ + if (pj_stricmp(&arealm->value, &realm)) { + /* REALM doesn't match */ + if (p_response) { + create_challenge(pool, msg, PJ_STUN_STATUS_MISSING_REALM, + NULL, &realm, &nonce, p_response); + } + return PJLIB_UTIL_ESTUNNOREALM; + } + + /* Valid case, will validate the message integrity later */ + + } else if (realm.slen == 0 && arealm != NULL) { + /* We want to use short term credential, but client uses long + * term credential. The draft doesn't mention anything about + * switching between long term and short term. + */ + + /* For now just accept the credential, anyway it will probably + * cause wrong message integrity value later. + */ + } else if (realm.slen==0 && arealm == NULL) { + /* Short term authentication is wanted, and one is supplied */ + + /* Application MAY request NONCE to be supplied */ + if (nonce.slen != 0) { + if (p_response) { + create_challenge(pool, msg, PJ_STUN_STATUS_MISSING_NONCE, + NULL, &realm, &nonce, p_response); + } + return PJLIB_UTIL_ESTUNNONCE; + } + } + + /* If NONCE is present, validate it */ + if (anonce) { + pj_bool_t ok; + + if (cred->type == PJ_STUN_AUTH_CRED_DYNAMIC) { + ok=cred->data.dyn_cred.verify_nonce(cred->data.dyn_cred.user_data, + (arealm?&arealm->value:NULL), + &auser->value, + &anonce->value); + } else { + if (nonce.slen) { + ok = !pj_strcmp(&anonce->value, &nonce); + } else { + ok = PJ_TRUE; + } + } + + if (!ok) { + if (p_response) { + create_challenge(pool, msg, PJ_STUN_STATUS_STALE_NONCE, + NULL, &realm, &nonce, p_response); + } + return PJLIB_UTIL_ESTUNNONCE; + } + } + + /* Get the position of MESSAGE-INTEGRITY in the packet */ + amsgi_pos = 20+msg->hdr.length-24; + if (GET_VAL16(pkt, amsgi_pos) == PJ_STUN_ATTR_MESSAGE_INTEGRITY) { + /* Found MESSAGE-INTEGRITY as the last attribute */ + } else { + amsgi_pos = 0; + } + + if (amsgi_pos==0) { + amsgi_pos = 20+msg->hdr.length-8-24; + if (GET_VAL16(pkt, amsgi_pos) == PJ_STUN_ATTR_MESSAGE_INTEGRITY) { + /* Found MESSAGE-INTEGRITY before FINGERPRINT */ + } else { + amsgi_pos = 0; + } + } + + if (amsgi_pos==0) { + pj_assert(!"Unable to find MESSAGE-INTEGRITY in the message!"); + return PJ_EBUG; + } + + /* Determine which key to use */ + if (realm.slen) { + pj_stun_calc_md5_key(md5_digest, &realm, &auser->value, &password); + key.ptr = (char*)md5_digest; + key.slen = 16; + } else { + key = password; + } + + /* Now calculate HMAC of the message */ + pj_hmac_sha1(pkt, amsgi_pos, (pj_uint8_t*)key.ptr, key.slen, digest); + + /* Compare HMACs */ + if (pj_memcmp(amsgi->hmac, digest, 20)) { + /* HMAC value mismatch */ + if (p_response) { + create_challenge(pool, msg, PJ_STUN_STATUS_INTEGRITY_CHECK_FAILURE, + NULL, &realm, &nonce, p_response); + } + return PJLIB_UTIL_ESTUNMSGINT; + } + + /* Everything looks okay! */ + return PJ_SUCCESS; +} + + diff --git a/pjlib-util/src/pjlib-util/stun_msg.c b/pjlib-util/src/pjlib-util/stun_msg.c index 6954434a..7c623ad4 100644 --- a/pjlib-util/src/pjlib-util/stun_msg.c +++ b/pjlib-util/src/pjlib-util/stun_msg.c @@ -21,7 +21,6 @@ #include <pjlib-util/errno.h> #include <pjlib-util/hmac_sha1.h> #include <pjlib-util/md5.h> -#include <pjlib-util/sha1.h> #include <pj/assert.h> #include <pj/log.h> #include <pj/os.h> @@ -88,37 +87,37 @@ struct attr_desc }; -static pj_status_t decode_generic_ip_addr_attr(pj_pool_t *pool, - const pj_uint8_t *buf, - void **p_attr); -static pj_status_t encode_generic_ip_addr_attr(const void *a, pj_uint8_t *buf, - unsigned len, - unsigned *printed); -static pj_status_t decode_generic_string_attr(pj_pool_t *pool, - const pj_uint8_t *buf, - void **p_attr); -static pj_status_t encode_generic_string_attr(const void *a, pj_uint8_t *buf, - unsigned len, unsigned *printed); -static pj_status_t decode_msg_integrity_attr(pj_pool_t *pool, - const pj_uint8_t *buf, - void **p_attr); -static pj_status_t encode_msg_integrity_attr(const void *a, pj_uint8_t *buf, - unsigned len, unsigned *printed); -static pj_status_t decode_error_code_attr(pj_pool_t *pool, - const pj_uint8_t *buf, - void **p_attr); -static pj_status_t encode_error_code_attr(const void *a, pj_uint8_t *buf, - unsigned len, unsigned *printed); +static pj_status_t decode_ip_addr_attr(pj_pool_t *pool, + const pj_uint8_t *buf, + void **p_attr); +static pj_status_t encode_ip_addr_attr(const void *a, pj_uint8_t *buf, + unsigned len, + unsigned *printed); +static pj_status_t decode_string_attr(pj_pool_t *pool, + const pj_uint8_t *buf, + void **p_attr); +static pj_status_t encode_string_attr(const void *a, pj_uint8_t *buf, + unsigned len, unsigned *printed); +static pj_status_t decode_msgint_attr(pj_pool_t *pool, + const pj_uint8_t *buf, + void **p_attr); +static pj_status_t encode_msgint_attr(const void *a, pj_uint8_t *buf, + unsigned len, unsigned *printed); +static pj_status_t decode_errcode_attr(pj_pool_t *pool, + const pj_uint8_t *buf, + void **p_attr); +static pj_status_t encode_errcode_attr(const void *a, pj_uint8_t *buf, + unsigned len, unsigned *printed); static pj_status_t decode_unknown_attr(pj_pool_t *pool, const pj_uint8_t *buf, void **p_attr); static pj_status_t encode_unknown_attr(const void *a, pj_uint8_t *buf, unsigned len, unsigned *printed); -static pj_status_t decode_generic_uint_attr(pj_pool_t *pool, - const pj_uint8_t *buf, - void **p_attr); -static pj_status_t encode_generic_uint_attr(const void *a, pj_uint8_t *buf, - unsigned len, unsigned *printed); +static pj_status_t decode_uint_attr(pj_pool_t *pool, + const pj_uint8_t *buf, + void **p_attr); +static pj_status_t encode_uint_attr(const void *a, pj_uint8_t *buf, + unsigned len, unsigned *printed); static pj_status_t decode_binary_attr(pj_pool_t *pool, const pj_uint8_t *buf, void **p_attr); @@ -142,56 +141,56 @@ struct attr_desc mandatory_attr_desc[] = { /* PJ_STUN_ATTR_MAPPED_ADDR, */ "MAPPED-ADDRESS", - &decode_generic_ip_addr_attr, - &encode_generic_ip_addr_attr + &decode_ip_addr_attr, + &encode_ip_addr_attr }, { /* PJ_STUN_ATTR_RESPONSE_ADDR, */ "RESPONSE-ADDRESS", - &decode_generic_ip_addr_attr, - &encode_generic_ip_addr_attr + &decode_ip_addr_attr, + &encode_ip_addr_attr }, { /* PJ_STUN_ATTR_CHANGE_REQUEST, */ "CHANGE-REQUEST", - &decode_generic_uint_attr, - &encode_generic_uint_attr + &decode_uint_attr, + &encode_uint_attr }, { /* PJ_STUN_ATTR_SOURCE_ADDR, */ "SOURCE-ADDRESS", - &decode_generic_ip_addr_attr, - &encode_generic_ip_addr_attr + &decode_ip_addr_attr, + &encode_ip_addr_attr }, { /* PJ_STUN_ATTR_CHANGED_ADDR, */ "CHANGED-ADDRESS", - &decode_generic_ip_addr_attr, - &encode_generic_ip_addr_attr + &decode_ip_addr_attr, + &encode_ip_addr_attr }, { /* PJ_STUN_ATTR_USERNAME, */ "USERNAME", - &decode_generic_string_attr, - &encode_generic_string_attr + &decode_string_attr, + &encode_string_attr }, { /* PJ_STUN_ATTR_PASSWORD, */ "PASSWORD", - &decode_generic_string_attr, - &encode_generic_string_attr + &decode_string_attr, + &encode_string_attr }, { /* PJ_STUN_ATTR_MESSAGE_INTEGRITY, */ "MESSAGE-INTEGRITY", - &decode_msg_integrity_attr, - &encode_msg_integrity_attr + &decode_msgint_attr, + &encode_msgint_attr }, { /* PJ_STUN_ATTR_ERROR_CODE, */ "ERROR-CODE", - &decode_error_code_attr, - &encode_error_code_attr + &decode_errcode_attr, + &encode_errcode_attr }, { /* PJ_STUN_ATTR_UNKNOWN_ATTRIBUTES, */ @@ -202,8 +201,8 @@ struct attr_desc mandatory_attr_desc[] = { /* PJ_STUN_ATTR_REFLECTED_FROM, */ "REFLECTED-FROM", - &decode_generic_ip_addr_attr, - &encode_generic_ip_addr_attr + &decode_ip_addr_attr, + &encode_ip_addr_attr }, { /* ID 0x000C is not assigned */ @@ -214,8 +213,8 @@ struct attr_desc mandatory_attr_desc[] = { /* PJ_STUN_ATTR_LIFETIME, */ "LIFETIME", - &decode_generic_uint_attr, - &encode_generic_uint_attr + &decode_uint_attr, + &encode_uint_attr }, { /* ID 0x000E is not assigned */ @@ -232,8 +231,8 @@ struct attr_desc mandatory_attr_desc[] = { /* PJ_STUN_ATTR_BANDWIDTH, */ "BANDWIDTH", - &decode_generic_uint_attr, - &encode_generic_uint_attr + &decode_uint_attr, + &encode_uint_attr }, { /* ID 0x0011 is not assigned */ @@ -244,8 +243,8 @@ struct attr_desc mandatory_attr_desc[] = { /* PJ_STUN_ATTR_REMOTE_ADDRESS, */ "REMOTE-ADDRESS", - &decode_generic_ip_addr_attr, - &encode_generic_ip_addr_attr + &decode_ip_addr_attr, + &encode_ip_addr_attr }, { /* PJ_STUN_ATTR_DATA, */ @@ -256,38 +255,38 @@ struct attr_desc mandatory_attr_desc[] = { /* PJ_STUN_ATTR_REALM, */ "REALM", - &decode_generic_string_attr, - &encode_generic_string_attr + &decode_string_attr, + &encode_string_attr }, { /* PJ_STUN_ATTR_NONCE, */ "NONCE", - &decode_generic_string_attr, - &encode_generic_string_attr + &decode_string_attr, + &encode_string_attr }, { /* PJ_STUN_ATTR_RELAY_ADDRESS, */ "RELAY-ADDRESS", - &decode_generic_ip_addr_attr, - &encode_generic_ip_addr_attr + &decode_ip_addr_attr, + &encode_ip_addr_attr }, { /* PJ_STUN_ATTR_REQUESTED_ADDR_TYPE, */ "REQUESTED-ADDRESS-TYPE", - &decode_generic_uint_attr, - &encode_generic_uint_attr + &decode_uint_attr, + &encode_uint_attr }, { /* PJ_STUN_ATTR_REQUESTED_PORT_PROPS, */ "REQUESTED-PORT-PROPS", - &decode_generic_uint_attr, - &encode_generic_uint_attr + &decode_uint_attr, + &encode_uint_attr }, { /* PJ_STUN_ATTR_REQUESTED_TRANSPORT, */ "REQUESTED-TRANSPORT", - &decode_generic_uint_attr, - &encode_generic_uint_attr + &decode_uint_attr, + &encode_uint_attr }, { /* ID 0x001A is not assigned */ @@ -328,32 +327,32 @@ struct attr_desc mandatory_attr_desc[] = { /* PJ_STUN_ATTR_XOR_MAPPED_ADDRESS, */ "XOR-MAPPED-ADDRESS", - &decode_generic_ip_addr_attr, - &encode_generic_ip_addr_attr + &decode_ip_addr_attr, + &encode_ip_addr_attr }, { /* PJ_STUN_ATTR_TIMER_VAL, */ "TIMER-VAL", - &decode_generic_uint_attr, - &encode_generic_uint_attr + &decode_uint_attr, + &encode_uint_attr }, { /* PJ_STUN_ATTR_REQUESTED_IP, */ "REQUESTED-IP", - &decode_generic_ip_addr_attr, - &encode_generic_ip_addr_attr + &decode_ip_addr_attr, + &encode_ip_addr_attr }, { /* PJ_STUN_ATTR_XOR_REFLECTED_FROM, */ "XOR-REFLECTED-FROM", - &decode_generic_ip_addr_attr, - &encode_generic_ip_addr_attr + &decode_ip_addr_attr, + &encode_ip_addr_attr }, { /* PJ_STUN_ATTR_PRIORITY, */ "PRIORITY", - &decode_generic_uint_attr, - &encode_generic_uint_attr + &decode_uint_attr, + &encode_uint_attr }, { /* PJ_STUN_ATTR_USE_CANDIDATE, */ @@ -364,8 +363,8 @@ struct attr_desc mandatory_attr_desc[] = { /* PJ_STUN_ATTR_XOR_INTERNAL_ADDR, */ "XOR-INTERNAL-ADDRESS", - &decode_generic_ip_addr_attr, - &encode_generic_ip_addr_attr + &decode_ip_addr_attr, + &encode_ip_addr_attr }, /* Sentinel */ @@ -382,26 +381,26 @@ static struct attr_desc extended_attr_desc[] = { /* PJ_STUN_ATTR_FINGERPRINT, */ "FINGERPRINT", - &decode_generic_uint_attr, - &encode_generic_uint_attr + &decode_uint_attr, + &encode_uint_attr }, { /* PJ_STUN_ATTR_SERVER, */ "SERVER", - &decode_generic_string_attr, - &encode_generic_string_attr + &decode_string_attr, + &encode_string_attr }, { /* PJ_STUN_ATTR_ALTERNATE_SERVER, */ "ALTERNATE-SERVER", - &decode_generic_ip_addr_attr, - &encode_generic_ip_addr_attr + &decode_ip_addr_attr, + &encode_ip_addr_attr }, { /* PJ_STUN_ATTR_REFRESH_INTERVAL, */ "REFRESH-INTERVAL", - &decode_generic_uint_attr, - &encode_generic_uint_attr + &decode_uint_attr, + &encode_uint_attr }, }; @@ -514,20 +513,20 @@ PJ_DEF(pj_str_t) pj_stun_get_err_reason(int err_code) * Create a generic STUN IP address attribute for IPv4 address. */ PJ_DEF(pj_status_t) -pj_stun_generic_ip_addr_attr_create(pj_pool_t *pool, - int attr_type, - pj_bool_t xor_ed, - const pj_sockaddr_t *addr, - unsigned addr_len, - pj_stun_generic_ip_addr_attr **p_attr) +pj_stun_ip_addr_attr_create(pj_pool_t *pool, + int attr_type, + pj_bool_t xor_ed, + const pj_sockaddr_t *addr, + unsigned addr_len, + pj_stun_ip_addr_attr **p_attr) { - pj_stun_generic_ip_addr_attr *attr; + pj_stun_ip_addr_attr *attr; PJ_ASSERT_RETURN(pool && addr_len && addr && p_attr, PJ_EINVAL); PJ_ASSERT_RETURN(addr_len == sizeof(pj_sockaddr_in) || addr_len == sizeof(pj_sockaddr_in6), PJ_EINVAL); - attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_generic_ip_addr_attr); + attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_ip_addr_attr); INIT_ATTR(attr, attr_type, STUN_GENERIC_IP_ADDR_LEN); if (!xor_ed) { @@ -555,17 +554,17 @@ pj_stun_generic_ip_addr_attr_create(pj_pool_t *pool, * Create and add generic STUN IP address attribute to a STUN message. */ PJ_DEF(pj_status_t) -pj_stun_msg_add_generic_ip_addr_attr(pj_pool_t *pool, - pj_stun_msg *msg, - int attr_type, - pj_bool_t xor_ed, - const pj_sockaddr_t *addr, - unsigned addr_len) +pj_stun_msg_add_ip_addr_attr(pj_pool_t *pool, + pj_stun_msg *msg, + int attr_type, + pj_bool_t xor_ed, + const pj_sockaddr_t *addr, + unsigned addr_len) { - pj_stun_generic_ip_addr_attr *attr; + pj_stun_ip_addr_attr *attr; pj_status_t status; - status = pj_stun_generic_ip_addr_attr_create(pool, attr_type, xor_ed, + status = pj_stun_ip_addr_attr_create(pool, attr_type, xor_ed, addr, addr_len, &attr); if (status != PJ_SUCCESS) return status; @@ -573,15 +572,15 @@ pj_stun_msg_add_generic_ip_addr_attr(pj_pool_t *pool, return pj_stun_msg_add_attr(msg, &attr->hdr); } -static pj_status_t decode_generic_ip_addr_attr(pj_pool_t *pool, - const pj_uint8_t *buf, - void **p_attr) +static pj_status_t decode_ip_addr_attr(pj_pool_t *pool, + const pj_uint8_t *buf, + void **p_attr) { - pj_stun_generic_ip_addr_attr *attr; + pj_stun_ip_addr_attr *attr; pj_uint32_t val; /* Create the attribute */ - attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_generic_ip_addr_attr); + attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_ip_addr_attr); pj_memcpy(attr, buf, ATTR_HDR_LEN); /* Convert to host byte order */ @@ -611,23 +610,23 @@ static pj_status_t decode_generic_ip_addr_attr(pj_pool_t *pool, } -static pj_status_t encode_generic_ip_addr_attr(const void *a, pj_uint8_t *buf, - unsigned len, unsigned *printed) +static pj_status_t encode_ip_addr_attr(const void *a, pj_uint8_t *buf, + unsigned len, unsigned *printed) { enum { ATTR_LEN = ATTR_HDR_LEN + STUN_GENERIC_IP_ADDR_LEN }; pj_uint8_t *start_buf = buf; - const pj_stun_generic_ip_addr_attr *ca = - (const pj_stun_generic_ip_addr_attr *)a; - pj_stun_generic_ip_addr_attr *attr; + const pj_stun_ip_addr_attr *ca = + (const pj_stun_ip_addr_attr *)a; + pj_stun_ip_addr_attr *attr; if (len < ATTR_LEN) return PJ_ETOOSMALL; /* Copy and convert headers to network byte order */ pj_memcpy(buf, a, ATTR_HDR_LEN); - attr = (pj_stun_generic_ip_addr_attr*) buf; + attr = (pj_stun_ip_addr_attr*) buf; attr->hdr.type = pj_htons(attr->hdr.type); attr->hdr.length = pj_htons((pj_uint16_t)STUN_GENERIC_IP_ADDR_LEN); buf += ATTR_HDR_LEN; @@ -665,16 +664,16 @@ static pj_status_t encode_generic_ip_addr_attr(const void *a, pj_uint8_t *buf, * Create a STUN generic string attribute. */ PJ_DEF(pj_status_t) -pj_stun_generic_string_attr_create(pj_pool_t *pool, - int attr_type, - const pj_str_t *value, - pj_stun_generic_string_attr **p_attr) +pj_stun_string_attr_create(pj_pool_t *pool, + int attr_type, + const pj_str_t *value, + pj_stun_string_attr **p_attr) { - pj_stun_generic_string_attr *attr; + pj_stun_string_attr *attr; PJ_ASSERT_RETURN(pool && value && p_attr, PJ_EINVAL); - attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_generic_string_attr); + attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_string_attr); INIT_ATTR(attr, attr_type, value->slen); pj_strdup(pool, &attr->value, value); @@ -688,15 +687,15 @@ pj_stun_generic_string_attr_create(pj_pool_t *pool, * Create and add STUN generic string attribute to the message. */ PJ_DEF(pj_status_t) -pj_stun_msg_add_generic_string_attr(pj_pool_t *pool, - pj_stun_msg *msg, - int attr_type, - const pj_str_t *value) +pj_stun_msg_add_string_attr(pj_pool_t *pool, + pj_stun_msg *msg, + int attr_type, + const pj_str_t *value) { - pj_stun_generic_string_attr *attr; + pj_stun_string_attr *attr; pj_status_t status; - status = pj_stun_generic_string_attr_create(pool, attr_type, value, + status = pj_stun_string_attr_create(pool, attr_type, value, &attr); if (status != PJ_SUCCESS) return status; @@ -705,15 +704,15 @@ pj_stun_msg_add_generic_string_attr(pj_pool_t *pool, } -static pj_status_t decode_generic_string_attr(pj_pool_t *pool, - const pj_uint8_t *buf, - void **p_attr) +static pj_status_t decode_string_attr(pj_pool_t *pool, + const pj_uint8_t *buf, + void **p_attr) { - pj_stun_generic_string_attr *attr; + pj_stun_string_attr *attr; pj_str_t value; /* Create the attribute */ - attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_generic_string_attr); + attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_string_attr); /* Copy the header */ pj_memcpy(attr, buf, ATTR_HDR_LEN); @@ -737,11 +736,11 @@ static pj_status_t decode_generic_string_attr(pj_pool_t *pool, } -static pj_status_t encode_generic_string_attr(const void *a, pj_uint8_t *buf, - unsigned len, unsigned *printed) +static pj_status_t encode_string_attr(const void *a, pj_uint8_t *buf, + unsigned len, unsigned *printed) { - const pj_stun_generic_string_attr *ca = - (const pj_stun_generic_string_attr*)a; + const pj_stun_string_attr *ca = + (const pj_stun_string_attr*)a; pj_stun_attr_hdr *attr; /* Calculated total attr_len (add padding if necessary) */ @@ -856,16 +855,16 @@ static pj_status_t encode_empty_attr(const void *a, pj_uint8_t *buf, * Create a STUN generic 32bit value attribute. */ PJ_DEF(pj_status_t) -pj_stun_generic_uint_attr_create(pj_pool_t *pool, - int attr_type, - pj_uint32_t value, - pj_stun_generic_uint_attr **p_attr) +pj_stun_uint_attr_create(pj_pool_t *pool, + int attr_type, + pj_uint32_t value, + pj_stun_uint_attr **p_attr) { - pj_stun_generic_uint_attr *attr; + pj_stun_uint_attr *attr; PJ_ASSERT_RETURN(pool && p_attr, PJ_EINVAL); - attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_generic_uint_attr); + attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_uint_attr); INIT_ATTR(attr, attr_type, STUN_UINT_LEN); attr->value = value; @@ -876,36 +875,36 @@ pj_stun_generic_uint_attr_create(pj_pool_t *pool, /* Create and add STUN generic 32bit value attribute to the message. */ PJ_DEF(pj_status_t) -pj_stun_msg_add_generic_uint_attr(pj_pool_t *pool, - pj_stun_msg *msg, - int attr_type, - pj_uint32_t value) +pj_stun_msg_add_uint_attr(pj_pool_t *pool, + pj_stun_msg *msg, + int attr_type, + pj_uint32_t value) { - pj_stun_generic_uint_attr *attr; + pj_stun_uint_attr *attr; pj_status_t status; - status = pj_stun_generic_uint_attr_create(pool, attr_type, value, &attr); + status = pj_stun_uint_attr_create(pool, attr_type, value, &attr); if (status != PJ_SUCCESS) return status; return pj_stun_msg_add_attr(msg, &attr->hdr); } -static pj_status_t decode_generic_uint_attr(pj_pool_t *pool, - const pj_uint8_t *buf, - void **p_attr) +static pj_status_t decode_uint_attr(pj_pool_t *pool, + const pj_uint8_t *buf, + void **p_attr) { enum { ATTR_LEN = STUN_UINT_LEN + ATTR_HDR_LEN }; - pj_stun_generic_uint_attr *attr; + pj_stun_uint_attr *attr; /* Check that the struct address is valid */ - pj_assert(sizeof(pj_stun_generic_uint_attr) == ATTR_LEN); + pj_assert(sizeof(pj_stun_uint_attr) == ATTR_LEN); /* Create the attribute */ - attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_generic_uint_attr); + attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_uint_attr); pj_memcpy(attr, buf, ATTR_LEN); /* Convert to host byte order */ @@ -924,21 +923,21 @@ static pj_status_t decode_generic_uint_attr(pj_pool_t *pool, } -static pj_status_t encode_generic_uint_attr(const void *a, pj_uint8_t *buf, - unsigned len, unsigned *printed) +static pj_status_t encode_uint_attr(const void *a, pj_uint8_t *buf, + unsigned len, unsigned *printed) { enum { ATTR_LEN = STUN_UINT_LEN + ATTR_HDR_LEN }; - pj_stun_generic_uint_attr *attr; + pj_stun_uint_attr *attr; if (len < ATTR_LEN) return PJ_ETOOSMALL; /* Copy and convert attribute to network byte order */ pj_memcpy(buf, a, ATTR_LEN); - attr = (pj_stun_generic_uint_attr*) buf; + attr = (pj_stun_uint_attr*) buf; attr->hdr.type = pj_htons(attr->hdr.type); pj_assert(attr->hdr.length == STUN_UINT_LEN); attr->hdr.length = pj_htons(STUN_UINT_LEN); @@ -961,14 +960,14 @@ static pj_status_t encode_generic_uint_attr(const void *a, pj_uint8_t *buf, * Create a STUN MESSAGE-INTEGRITY attribute. */ PJ_DEF(pj_status_t) -pj_stun_msg_integrity_attr_create(pj_pool_t *pool, - pj_stun_msg_integrity_attr **p_attr) +pj_stun_msgint_attr_create(pj_pool_t *pool, + pj_stun_msgint_attr **p_attr) { - pj_stun_msg_integrity_attr *attr; + pj_stun_msgint_attr *attr; PJ_ASSERT_RETURN(pool && p_attr, PJ_EINVAL); - attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_msg_integrity_attr); + attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_msgint_attr); INIT_ATTR(attr, PJ_STUN_ATTR_MESSAGE_INTEGRITY, STUN_MSG_INTEGRITY_LEN); *p_attr = attr; @@ -977,22 +976,35 @@ pj_stun_msg_integrity_attr_create(pj_pool_t *pool, } -static pj_status_t decode_msg_integrity_attr(pj_pool_t *pool, - const pj_uint8_t *buf, - void **p_attr) +PJ_DEF(pj_status_t) pj_stun_msg_add_msgint_attr(pj_pool_t *pool, + pj_stun_msg *msg) +{ + pj_stun_msgint_attr *attr; + pj_status_t status; + + status = pj_stun_msgint_attr_create(pool, &attr); + if (status != PJ_SUCCESS) + return status; + + return pj_stun_msg_add_attr(msg, &attr->hdr); +} + +static pj_status_t decode_msgint_attr(pj_pool_t *pool, + const pj_uint8_t *buf, + void **p_attr) { enum { ATTR_LEN = STUN_MSG_INTEGRITY_LEN + ATTR_HDR_LEN }; - pj_stun_msg_integrity_attr *attr; + pj_stun_msgint_attr *attr; /* Check that struct size is valid */ - pj_assert(sizeof(pj_stun_msg_integrity_attr)==ATTR_LEN); + pj_assert(sizeof(pj_stun_msgint_attr)==ATTR_LEN); /* Create attribute */ - attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_msg_integrity_attr); - pj_memcpy(attr, buf, sizeof(pj_stun_msg_integrity_attr)); + attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_msgint_attr); + pj_memcpy(attr, buf, sizeof(pj_stun_msgint_attr)); attr->hdr.type = pj_ntohs(attr->hdr.type); attr->hdr.length = pj_ntohs(attr->hdr.length); @@ -1006,21 +1018,21 @@ static pj_status_t decode_msg_integrity_attr(pj_pool_t *pool, } -static pj_status_t encode_msg_integrity_attr(const void *a, pj_uint8_t *buf, - unsigned len, unsigned *printed) +static pj_status_t encode_msgint_attr(const void *a, pj_uint8_t *buf, + unsigned len, unsigned *printed) { enum { ATTR_LEN = STUN_MSG_INTEGRITY_LEN + ATTR_HDR_LEN }; - pj_stun_msg_integrity_attr *attr; + pj_stun_msgint_attr *attr; if (len < ATTR_LEN) return PJ_ETOOSMALL; /* Copy and convert attribute to network byte order */ pj_memcpy(buf, a, ATTR_LEN); - attr = (pj_stun_msg_integrity_attr*) buf; + attr = (pj_stun_msgint_attr*) buf; attr->hdr.type = pj_htons(attr->hdr.type); pj_assert(attr->hdr.length == STUN_MSG_INTEGRITY_LEN); attr->hdr.length = pj_htons(STUN_MSG_INTEGRITY_LEN); @@ -1040,12 +1052,12 @@ static pj_status_t encode_msg_integrity_attr(const void *a, pj_uint8_t *buf, * Create a STUN ERROR-CODE attribute. */ PJ_DEF(pj_status_t) -pj_stun_error_code_attr_create(pj_pool_t *pool, - int err_code, - const pj_str_t *err_reason, - pj_stun_error_code_attr **p_attr) +pj_stun_errcode_attr_create(pj_pool_t *pool, + int err_code, + const pj_str_t *err_reason, + pj_stun_errcode_attr **p_attr) { - pj_stun_error_code_attr *attr; + pj_stun_errcode_attr *attr; char err_buf[80]; pj_str_t str; @@ -1061,7 +1073,7 @@ pj_stun_error_code_attr_create(pj_pool_t *pool, err_reason = &str; } - attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_error_code_attr); + attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_errcode_attr); INIT_ATTR(attr, PJ_STUN_ATTR_ERROR_CODE, 4+err_reason->slen); attr->err_class = (pj_uint8_t)(err_code / 100); attr->number = (pj_uint8_t) (err_code % 100); @@ -1073,15 +1085,31 @@ pj_stun_error_code_attr_create(pj_pool_t *pool, } -static pj_status_t decode_error_code_attr(pj_pool_t *pool, - const pj_uint8_t *buf, - void **p_attr) +PJ_DEF(pj_status_t) pj_stun_msg_add_errcode_attr(pj_pool_t *pool, + pj_stun_msg *msg, + int err_code, + const pj_str_t *err_reason) +{ + pj_stun_errcode_attr *err_attr; + pj_status_t status; + + status = pj_stun_errcode_attr_create(pool, err_code, err_reason, + &err_attr); + if (status != PJ_SUCCESS) + return status; + + return pj_stun_msg_add_attr(msg, &err_attr->hdr); +} + +static pj_status_t decode_errcode_attr(pj_pool_t *pool, + const pj_uint8_t *buf, + void **p_attr) { - pj_stun_error_code_attr *attr; + pj_stun_errcode_attr *attr; pj_str_t value; /* Create the attribute */ - attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_error_code_attr); + attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_errcode_attr); /* Copy the header */ pj_memcpy(attr, buf, ATTR_HDR_LEN + 4); @@ -1104,12 +1132,12 @@ static pj_status_t decode_error_code_attr(pj_pool_t *pool, } -static pj_status_t encode_error_code_attr(const void *a, pj_uint8_t *buf, - unsigned len, unsigned *printed) +static pj_status_t encode_errcode_attr(const void *a, pj_uint8_t *buf, + unsigned len, unsigned *printed) { - const pj_stun_error_code_attr *ca = - (const pj_stun_error_code_attr*)a; - pj_stun_error_code_attr *attr; + const pj_stun_errcode_attr *ca = + (const pj_stun_errcode_attr*)a; + pj_stun_errcode_attr *attr; if (len < ATTR_HDR_LEN + 4 + (unsigned)ca->reason.slen) return PJ_ETOOSMALL; @@ -1118,7 +1146,7 @@ static pj_status_t encode_error_code_attr(const void *a, pj_uint8_t *buf, pj_memcpy(buf, ca, ATTR_HDR_LEN + 4); /* Update length */ - attr = (pj_stun_error_code_attr*) buf; + attr = (pj_stun_errcode_attr*) buf; attr->hdr.length = (pj_uint16_t)(4 + ca->reason.slen); /* Convert fiends to network byte order */ @@ -1507,7 +1535,6 @@ PJ_DEF(pj_status_t) pj_stun_msg_create_response(pj_pool_t *pool, { unsigned msg_type = req_msg->hdr.type; pj_stun_msg *response; - pj_stun_error_code_attr *err_attr; pj_status_t status; PJ_ASSERT_RETURN(pool && p_response, PJ_EINVAL); @@ -1529,13 +1556,11 @@ PJ_DEF(pj_status_t) pj_stun_msg_create_response(pj_pool_t *pool, /* Add error code attribute */ if (err_code) { - status = pj_stun_error_code_attr_create(pool, err_code, err_msg, - &err_attr); + status = pj_stun_msg_add_errcode_attr(pool, response, + err_code, err_msg); if (status != PJ_SUCCESS) { return status; } - - pj_stun_msg_add_attr(response, &err_attr->hdr); } *p_response = response; @@ -1702,7 +1727,7 @@ PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool, PJ_STUN_STATUS_BAD_REQUEST, NULL, p_response); } - return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_BAD_REQUEST); + return PJLIB_UTIL_ESTUNDUPATTR; } has_msg_int = PJ_TRUE; @@ -1716,7 +1741,7 @@ PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool, PJ_STUN_STATUS_BAD_REQUEST, NULL, p_response); } - return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_BAD_REQUEST); + return PJLIB_UTIL_ESTUNDUPATTR; } has_fingerprint = PJ_TRUE; } else { @@ -1730,7 +1755,8 @@ PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool, PJ_STUN_STATUS_BAD_REQUEST, NULL, p_response); } - return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_BAD_REQUEST); + return has_fingerprint ? PJLIB_UTIL_ESTUNFINGERPOS : + PJLIB_UTIL_ESTUNMSGINTPOS; } } @@ -1766,10 +1792,10 @@ PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool, /* Calculate HMAC-SHA1 key for long term credential, by getting * MD5 digest of username, realm, and password. */ -static void calc_md5_key(pj_uint8_t digest[16], - const pj_str_t *realm, - const pj_str_t *username, - const pj_str_t *passwd) +void pj_stun_calc_md5_key(pj_uint8_t digest[16], + const pj_str_t *realm, + const pj_str_t *username, + const pj_str_t *passwd) { /* The 16-byte key for MESSAGE-INTEGRITY HMAC is formed by taking * the MD5 hash of the result of concatenating the following five @@ -1827,7 +1853,7 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg, pj_uint8_t *start = buf; pj_stun_realm_attr *arealm = NULL; pj_stun_username_attr *auname = NULL; - pj_stun_msg_integrity_attr *amsg_integrity = NULL; + pj_stun_msgint_attr *amsgint = NULL; pj_stun_fingerprint_attr *afingerprint = NULL; unsigned printed; pj_status_t status; @@ -1859,8 +1885,8 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg, const pj_stun_attr_hdr *attr_hdr = msg->attr[i]; if (attr_hdr->type == PJ_STUN_ATTR_MESSAGE_INTEGRITY) { - pj_assert(amsg_integrity == NULL); - amsg_integrity = (pj_stun_msg_integrity_attr*) attr_hdr; + pj_assert(amsgint == NULL); + amsgint = (pj_stun_msgint_attr*) attr_hdr; /* Stop when encountering MESSAGE-INTEGRITY */ break; @@ -1901,9 +1927,9 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg, if (attr_hdr->type == PJ_STUN_ATTR_MESSAGE_INTEGRITY) { /* There mustn't be MESSAGE-INTEGRITY before */ - PJ_ASSERT_RETURN(amsg_integrity == NULL, + PJ_ASSERT_RETURN(amsgint == NULL, PJLIB_UTIL_ESTUNMSGINTPOS); - amsg_integrity = (pj_stun_msg_integrity_attr*) attr_hdr; + amsgint = (pj_stun_msgint_attr*) attr_hdr; } else if (attr_hdr->type == PJ_STUN_ATTR_FINGERPRINT) { afingerprint = (pj_stun_fingerprint_attr*) attr_hdr; @@ -1914,9 +1940,9 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg, * calculating MESSAGE-INTEGRITY and FINGERPRINT. * Note that length is not including the 20 bytes header. */ - if (amsg_integrity && afingerprint) { + if (amsgint && afingerprint) { msg->hdr.length = (pj_uint16_t)((buf - start) - 20 + 24 + 8); - } else if (amsg_integrity) { + } else if (amsgint) { msg->hdr.length = (pj_uint16_t)((buf - start) - 20 + 24); } else if (afingerprint) { msg->hdr.length = (pj_uint16_t)((buf - start) - 20 + 8); @@ -1929,7 +1955,7 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg, start[3] = (pj_uint8_t)(msg->hdr.length & 0x00FF); /* Calculate message integrity, if present */ - if (amsg_integrity != NULL) { + if (amsgint != NULL) { pj_uint8_t md5_key_buf[16]; pj_str_t key; @@ -1968,8 +1994,8 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg, key = *password; } else { - calc_md5_key(md5_key_buf, &arealm->value, &auname->value, - password); + pj_stun_calc_md5_key(md5_key_buf, &arealm->value, + &auname->value, password); key.ptr = (char*) md5_key_buf; key.slen = 16; } @@ -1977,11 +2003,11 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg, /* Calculate HMAC-SHA1 digest */ pj_hmac_sha1((pj_uint8_t*)buf, buf-start, (pj_uint8_t*)key.ptr, key.slen, - amsg_integrity->hmac); + amsgint->hmac); /* Put this attribute in the message */ - status = encode_msg_integrity_attr(amsg_integrity, buf, buf_size, - &printed); + status = encode_msgint_attr(amsgint, buf, buf_size, + &printed); if (status != PJ_SUCCESS) return status; @@ -1995,7 +2021,7 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg, afingerprint->value ^= STUN_XOR_FINGERPRINT; /* Put this attribute in the message */ - status = encode_generic_uint_attr(afingerprint, buf, buf_size, + status = encode_uint_attr(afingerprint, buf, buf_size, &printed); if (status != PJ_SUCCESS) return status; @@ -2024,296 +2050,9 @@ PJ_DEF(pj_stun_attr_hdr*) pj_stun_msg_find_attr( const pj_stun_msg *msg, for (; index < msg->attr_count; ++index) { if (msg->attr[index]->type == attr_type) - return (pj_stun_attr_hdr*) &msg->attr[index]; + return (pj_stun_attr_hdr*) msg->attr[index]; } return NULL; } - -/**************************************************************************/ -/* - * Authentication - */ - - -/* Send 401 response */ -static pj_status_t create_challenge(pj_pool_t *pool, - const pj_stun_msg *msg, - int err_code, - const pj_str_t *err_msg, - const pj_str_t *realm, - const pj_str_t *nonce, - pj_stun_msg **p_response) -{ - pj_stun_msg *response; - pj_status_t rc; - - rc = pj_stun_msg_create_response(pool, msg, - err_code, err_msg, &response); - if (rc != PJ_SUCCESS) - return rc; - - - if (realm && realm->slen) { - rc = pj_stun_msg_add_generic_string_attr(pool, response, - PJ_STUN_ATTR_REALM, - realm); - if (rc != PJ_SUCCESS) - return rc; - } - - if (nonce && nonce->slen) { - rc = pj_stun_msg_add_generic_string_attr(pool, response, - PJ_STUN_ATTR_NONCE, - nonce); - if (rc != PJ_SUCCESS) - return rc; - } - - *p_response = response; - - return PJ_SUCCESS; -} - -/* Verify credential */ -PJ_DEF(pj_status_t) pj_stun_verify_credential( const pj_uint8_t *pkt, - unsigned pkt_len, - const pj_stun_msg *msg, - pj_stun_auth_policy *pol, - pj_pool_t *pool, - pj_stun_msg **p_response) -{ - pj_str_t realm, nonce, password; - const pj_stun_msg_integrity_attr *amsgi; - unsigned amsgi_pos; - const pj_stun_username_attr *auser; - pj_bool_t username_ok; - const pj_stun_realm_attr *arealm; - const pj_stun_realm_attr *anonce; - pj_uint8_t digest[PJ_SHA1_DIGEST_SIZE]; - pj_uint8_t md5_digest[16]; - pj_str_t key; - pj_status_t status; - - /* msg and policy MUST be specified */ - PJ_ASSERT_RETURN(pkt && pkt_len && msg && pol, PJ_EINVAL); - - /* If p_response is specified, pool MUST be specified. */ - PJ_ASSERT_RETURN(!p_response || pool, PJ_EINVAL); - - if (p_response) - *p_response = NULL; - - if (!PJ_STUN_IS_REQUEST(msg->hdr.type)) - p_response = NULL; - - /* Get realm and nonce */ - realm.slen = nonce.slen = 0; - if (pol->type == PJ_STUN_POLICY_STATIC_SHORT_TERM) { - realm.slen = 0; - nonce = pol->data.static_short_term.nonce; - } else if (pol->type == PJ_STUN_POLICY_STATIC_LONG_TERM) { - realm = pol->data.static_long_term.realm; - nonce = pol->data.static_long_term.nonce; - } else if (pol->type == PJ_STUN_POLICY_DYNAMIC) { - status = pol->data.dynamic.get_auth(pol->user_data, pool, - &realm, &nonce); - if (status != PJ_SUCCESS) - return status; - } else { - pj_assert(!"Unexpected"); - return PJ_EBUG; - } - - /* First check that MESSAGE-INTEGRITY is present */ - amsgi = (const pj_stun_msg_integrity_attr*) - pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_MESSAGE_INTEGRITY, 0); - if (amsgi == NULL) { - if (p_response) { - create_challenge(pool, msg, PJ_STUN_STATUS_UNAUTHORIZED, NULL, - &realm, &nonce, p_response); - } - return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_UNAUTHORIZED); - } - - /* Next check that USERNAME is present */ - auser = (const pj_stun_username_attr*) - pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USERNAME, 0); - if (auser == NULL) { - if (p_response) { - create_challenge(pool, msg, PJ_STUN_STATUS_MISSING_USERNAME, NULL, - &realm, &nonce, p_response); - } - return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_MISSING_USERNAME); - } - - /* Get REALM, if any */ - arealm = (const pj_stun_realm_attr*) - pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_REALM, 0); - - /* Check if username match */ - if (pol->type == PJ_STUN_POLICY_STATIC_SHORT_TERM) { - username_ok = !pj_strcmp(&auser->value, - &pol->data.static_short_term.username); - password = pol->data.static_short_term.password; - } else if (pol->type == PJ_STUN_POLICY_STATIC_LONG_TERM) { - username_ok = !pj_strcmp(&auser->value, - &pol->data.static_long_term.username); - password = pol->data.static_long_term.password; - } else if (pol->type == PJ_STUN_POLICY_DYNAMIC) { - pj_status_t rc; - rc = pol->data.dynamic.get_password(pol->user_data, - (arealm?&arealm->value:NULL), - &auser->value, pool, - &password); - username_ok = (rc == PJ_SUCCESS); - } else { - username_ok = PJ_TRUE; - password.slen = 0; - } - - if (!username_ok) { - /* Username mismatch */ - if (p_response) { - create_challenge(pool, msg, PJ_STUN_STATUS_UNKNOWN_USERNAME, NULL, - &realm, &nonce, p_response); - } - return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_UNKNOWN_USERNAME); - } - - - /* Get NONCE attribute */ - anonce = (pj_stun_nonce_attr*) - pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_NONCE, 0); - - /* Check for long term/short term requirements. */ - if (realm.slen != 0 && arealm == NULL) { - /* Long term credential is required and REALM is not present */ - if (p_response) { - create_challenge(pool, msg, PJ_STUN_STATUS_MISSING_REALM, NULL, - &realm, &nonce, p_response); - } - return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_MISSING_REALM); - - } else if (realm.slen != 0 && arealm != NULL) { - /* We want long term, and REALM is present */ - - /* NONCE must be present. */ - if (anonce == NULL) { - if (p_response) { - create_challenge(pool, msg, PJ_STUN_STATUS_MISSING_NONCE, - NULL, &realm, &nonce, p_response); - } - return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_MISSING_NONCE); - } - - /* Verify REALM matches */ - if (pj_stricmp(&arealm->value, &realm)) { - /* REALM doesn't match */ - if (p_response) { - create_challenge(pool, msg, PJ_STUN_STATUS_MISSING_REALM, - NULL, &realm, &nonce, p_response); - } - return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_MISSING_REALM); - } - - /* Valid case, will validate the message integrity later */ - - } else if (realm.slen == 0 && arealm != NULL) { - /* We want to use short term credential, but client uses long - * term credential. The draft doesn't mention anything about - * switching between long term and short term. - */ - - /* For now just accept the credential, anyway it will probably - * cause wrong message integrity value later. - */ - } else if (realm.slen==0 && arealm == NULL) { - /* Short term authentication is wanted, and one is supplied */ - - /* Application MAY request NONCE to be supplied */ - if (nonce.slen != 0) { - if (p_response) { - create_challenge(pool, msg, PJ_STUN_STATUS_MISSING_NONCE, - NULL, &realm, &nonce, p_response); - } - return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_MISSING_NONCE); - } - } - - /* If NONCE is present, validate it */ - if (anonce) { - pj_bool_t ok; - - if (pol->type == PJ_STUN_POLICY_DYNAMIC) { - ok = pol->data.dynamic.verify_nonce(pol->user_data, - (arealm?&arealm->value:NULL), - &auser->value, - &anonce->value); - } else { - if (nonce.slen) { - ok = !pj_strcmp(&anonce->value, &nonce); - } else { - ok = PJ_TRUE; - } - } - - if (!ok) { - if (p_response) { - create_challenge(pool, msg, PJ_STUN_STATUS_STALE_NONCE, - NULL, &realm, &nonce, p_response); - } - return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_STALE_NONCE); - } - } - - /* Get the position of MESSAGE-INTEGRITY in the packet */ - amsgi_pos = 20+msg->hdr.length-22; - if (GET_VAL16(pkt, amsgi_pos) == PJ_STUN_ATTR_MESSAGE_INTEGRITY) { - /* Found MESSAGE-INTEGRITY as the last attribute */ - } else { - amsgi_pos = 0; - } - - if (amsgi_pos==0) { - amsgi_pos = 20+msg->hdr.length-8-22; - if (GET_VAL16(pkt, amsgi_pos) == PJ_STUN_ATTR_MESSAGE_INTEGRITY) { - /* Found MESSAGE-INTEGRITY before FINGERPRINT */ - } else { - amsgi_pos = 0; - } - } - - if (amsgi_pos==0) { - pj_assert(!"Unable to find MESSAGE-INTEGRITY in the message!"); - return PJ_EBUG; - } - - /* Determine which key to use */ - if (realm.slen) { - calc_md5_key(md5_digest, &realm, &auser->value, &password); - key.ptr = (char*)md5_digest; - key.slen = 16; - } else { - key = password; - } - - /* Now calculate HMAC of the message */ - pj_hmac_sha1(pkt, amsgi_pos, (pj_uint8_t*)key.ptr, key.slen, digest); - - /* Compare HMACs */ - if (pj_memcmp(amsgi->hmac, digest, 20)) { - /* HMAC value mismatch */ - if (p_response) { - create_challenge(pool, msg, PJ_STUN_STATUS_INTEGRITY_CHECK_FAILURE, - NULL, &realm, &nonce, p_response); - } - return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_INTEGRITY_CHECK_FAILURE); - } - - /* Everything looks okay! */ - return PJ_SUCCESS; -} - - diff --git a/pjlib-util/src/pjlib-util/stun_msg_dump.c b/pjlib-util/src/pjlib-util/stun_msg_dump.c index 21d569da..1c9ccc2e 100644 --- a/pjlib-util/src/pjlib-util/stun_msg_dump.c +++ b/pjlib-util/src/pjlib-util/stun_msg_dump.c @@ -53,9 +53,9 @@ static int print_attr(char *buffer, unsigned length, case PJ_STUN_ATTR_XOR_INTERNAL_ADDR: case PJ_STUN_ATTR_ALTERNATE_SERVER: { - const pj_stun_generic_ip_addr_attr *attr; + const pj_stun_ip_addr_attr *attr; - attr = (const pj_stun_generic_ip_addr_attr*)ahdr; + attr = (const pj_stun_ip_addr_attr*)ahdr; if (attr->addr.addr.sa_family == PJ_AF_INET) { len = pj_ansi_snprintf(p, end-p, @@ -84,9 +84,9 @@ static int print_attr(char *buffer, unsigned length, case PJ_STUN_ATTR_FINGERPRINT: case PJ_STUN_ATTR_REFRESH_INTERVAL: { - const pj_stun_generic_uint_attr *attr; + const pj_stun_uint_attr *attr; - attr = (const pj_stun_generic_uint_attr*)ahdr; + attr = (const pj_stun_uint_attr*)ahdr; len = pj_ansi_snprintf(p, end-p, ", value=%d (0x%x)\n", (pj_uint32_t)attr->value, @@ -100,9 +100,9 @@ static int print_attr(char *buffer, unsigned length, case PJ_STUN_ATTR_NONCE: case PJ_STUN_ATTR_SERVER: { - const pj_stun_generic_string_attr *attr; + const pj_stun_string_attr *attr; - attr = (pj_stun_generic_string_attr*)ahdr; + attr = (pj_stun_string_attr*)ahdr; len = pj_ansi_snprintf(p, end-p, ", value=\"%.*s\"\n", (int)attr->value.slen, @@ -112,9 +112,9 @@ static int print_attr(char *buffer, unsigned length, case PJ_STUN_ATTR_ERROR_CODE: { - const pj_stun_error_code_attr *attr; + const pj_stun_errcode_attr *attr; - attr = (const pj_stun_error_code_attr*) ahdr; + attr = (const pj_stun_errcode_attr*) ahdr; len = pj_ansi_snprintf(p, end-p, ", err_code=%d, reason=\"%.*s\"\n", attr->err_class*100 + attr->number, diff --git a/pjlib-util/src/pjlib-util/stun_server.c b/pjlib-util/src/pjlib-util/stun_server.c deleted file mode 100644 index d4d7fa8f..00000000 --- a/pjlib-util/src/pjlib-util/stun_server.c +++ /dev/null @@ -1,129 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2003-2005 Benny Prijono <benny@prijono.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include <pjlib-util/stun_server.h> -#include <pjlib-util/errno.h> -#include <pj/assert.h> -#include <pj/pool.h> -#include <pj/string.h> - - -struct pj_stun_service -{ - pj_str_t name; - unsigned options; - void *user_data; - unsigned cb_cnt; - pj_stun_service_handler *cb; -}; - - -/* - * Create STUN service. - */ -PJ_DEF(pj_status_t) pj_stun_service_create( pj_pool_t *pool, - const char *name, - unsigned options, - unsigned handler_cnt, - pj_stun_service_handler cb[], - void *user_data, - pj_stun_service **p_svc) -{ - pj_stun_service *svc; - - PJ_ASSERT_RETURN(pool && handler_cnt && cb && p_svc, PJ_EINVAL); - - svc = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_service); - svc->options = options; - svc->user_data = user_data; - - if (!name) name = "pj_stun_service"; - - pj_strdup2_with_null(pool, &svc->name, name); - - svc->cb_cnt = handler_cnt; - svc->cb = pj_pool_calloc(pool, handler_cnt, - sizeof(pj_stun_service_handler)); - pj_memcpy(svc->cb, cb, handler_cnt * sizeof(pj_stun_service_handler)); - - *p_svc = svc; - - return PJ_SUCCESS; -} - - -/* - * Destroy STUN service - */ -PJ_DEF(pj_status_t) pj_stun_service_destroy(pj_stun_service *svc) -{ - PJ_ASSERT_RETURN(svc, PJ_EINVAL); - return PJ_SUCCESS; -} - - -/* - * Get user data associated with the STUN service. - */ -PJ_DEF(void*) pj_stun_service_get_user_data(pj_stun_service *svc) -{ - PJ_ASSERT_RETURN(svc, NULL); - return svc->user_data; -} - - -/* - * Find handler. - */ -static pj_stun_service_handler *find_handler(pj_stun_service *svc, - int msg_type) -{ - unsigned i; - - for (i=0; i<svc->cb_cnt; ++i) { - if (svc->cb[i].msg_type == msg_type) - return &svc->cb[i]; - } - - return NULL; -} - - -/* - * Instruct the STUN service to handle incoming STUN message. - */ -PJ_DEF(pj_status_t) pj_stun_service_handle_msg( pj_stun_service *svc, - void *handle_data, - const pj_stun_msg *msg) -{ - pj_stun_service_handler *handler; - - PJ_ASSERT_RETURN(svc && msg, PJ_EINVAL); - - handler = find_handler(svc, msg->hdr.type); - if (handler == NULL) - return PJLIB_UTIL_ESTUNNOHANDLER; - - return (*handler->handle_msg)(svc, handle_data, msg); -} - - -////////////////////////////////////////////////////////////////////////////// - - - diff --git a/pjlib-util/src/pjlib-util/stun_session.c b/pjlib-util/src/pjlib-util/stun_session.c index 11146047..7ec9d333 100644 --- a/pjlib-util/src/pjlib-util/stun_session.c +++ b/pjlib-util/src/pjlib-util/stun_session.c @@ -27,14 +27,9 @@ struct pj_stun_session pj_stun_session_cb cb; void *user_data; - /* Long term credential */ - pj_str_t l_realm; - pj_str_t l_username; - pj_str_t l_password; - - /* Short term credential */ - pj_str_t s_username; - pj_str_t s_password; + pj_bool_t use_fingerprint; + pj_stun_auth_cred *cred; + pj_str_t srv_name; pj_stun_tx_data pending_request_list; pj_stun_tx_data cached_response_list; @@ -213,88 +208,65 @@ static void on_cache_timeout(pj_timer_heap_t *timer_heap, pj_stun_msg_destroy_tdata(tdata->sess, tdata); } +static pj_str_t *get_passwd(pj_stun_session *sess) +{ + if (sess->cred == NULL) + return NULL; + else if (sess->cred->type == PJ_STUN_AUTH_CRED_STATIC) + return &sess->cred->data.static_cred.data; + else + return NULL; +} + static pj_status_t apply_msg_options(pj_stun_session *sess, pj_pool_t *pool, - unsigned options, - pj_stun_msg *msg, - pj_str_t **p_passwd) + pj_stun_msg *msg) { - pj_status_t status; + pj_status_t status = 0; + + /* The server SHOULD include a SERVER attribute in all responses */ + if (PJ_STUN_IS_RESPONSE(msg->hdr.type) || + PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type)) + { + pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SERVER, + &sess->srv_name); + } /* From draft-ietf-behave-rfc3489bis-05.txt * Section 8.3.1. Formulating the Request Message + * + * Note: only put MESSAGE-INTEGRITY in non error response. */ - if (options & PJ_STUN_USE_LONG_TERM_CRED) { - pj_stun_generic_string_attr *auname; - pj_stun_msg_integrity_attr *amsgi; - pj_stun_generic_string_attr *arealm; - - *p_passwd = &sess->l_password; + if (sess->cred && sess->cred->type == PJ_STUN_AUTH_CRED_STATIC && + !PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type)) + { + const pj_str_t *username; /* Create and add USERNAME attribute */ - status = pj_stun_generic_string_attr_create(pool, - PJ_STUN_ATTR_USERNAME, - &sess->l_username, - &auname); - PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); - - status = pj_stun_msg_add_attr(msg, &auname->hdr); + username = &sess->cred->data.static_cred.username; + status = pj_stun_msg_add_string_attr(pool, msg, + PJ_STUN_ATTR_USERNAME, + username); PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); /* Add REALM only when long term credential is used */ - status = pj_stun_generic_string_attr_create(pool, - PJ_STUN_ATTR_REALM, - &sess->l_realm, - &arealm); - PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); - - status = pj_stun_msg_add_attr(msg, &arealm->hdr); - PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); - - /* Add MESSAGE-INTEGRITY attribute */ - status = pj_stun_msg_integrity_attr_create(pool, &amsgi); - PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); - - status = pj_stun_msg_add_attr(msg, &amsgi->hdr); - PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); - - } else if (options & PJ_STUN_USE_SHORT_TERM_CRED) { - pj_stun_generic_string_attr *auname; - pj_stun_msg_integrity_attr *amsgi; - - *p_passwd = &sess->s_password; - - /* Create and add USERNAME attribute */ - status = pj_stun_generic_string_attr_create(pool, - PJ_STUN_ATTR_USERNAME, - &sess->s_username, - &auname); - PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); - - status = pj_stun_msg_add_attr(msg, &auname->hdr); - PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); + if (sess->cred->data.static_cred.realm.slen) { + const pj_str_t *realm = &sess->cred->data.static_cred.realm; + status = pj_stun_msg_add_string_attr(pool, msg, + PJ_STUN_ATTR_REALM, + realm); + } /* Add MESSAGE-INTEGRITY attribute */ - status = pj_stun_msg_integrity_attr_create(pool, &amsgi); - PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); - - status = pj_stun_msg_add_attr(msg, &amsgi->hdr); + status = pj_stun_msg_add_msgint_attr(pool, msg); PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); - } else { - *p_passwd = NULL; - } + } /* Add FINGERPRINT attribute if necessary */ - if (options & PJ_STUN_USE_FINGERPRINT) { - pj_stun_fingerprint_attr *af; - - status = pj_stun_generic_uint_attr_create(pool, - PJ_STUN_ATTR_FINGERPRINT, - 0, &af); - PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); - - status = pj_stun_msg_add_attr(msg, &af->hdr); + if (sess->use_fingerprint) { + status = pj_stun_msg_add_uint_attr(pool, msg, + PJ_STUN_ATTR_FINGERPRINT, 0); PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); } @@ -333,6 +305,7 @@ static pj_status_t tsx_on_send_msg(pj_stun_client_tsx *tsx, PJ_DEF(pj_status_t) pj_stun_session_create( pj_stun_endpoint *endpt, const char *name, const pj_stun_session_cb *cb, + pj_bool_t fingerprint, pj_stun_session **p_sess) { pj_pool_t *pool; @@ -351,6 +324,11 @@ PJ_DEF(pj_status_t) pj_stun_session_create( pj_stun_endpoint *endpt, sess->endpt = endpt; sess->pool = pool; pj_memcpy(&sess->cb, cb, sizeof(*cb)); + sess->use_fingerprint = fingerprint; + + sess->srv_name.ptr = pj_pool_alloc(pool, 32); + sess->srv_name.slen = pj_ansi_snprintf(sess->srv_name.ptr, 32, + "pj_stun-%s", PJ_VERSION); pj_list_init(&sess->pending_request_list); pj_list_init(&sess->cached_response_list); @@ -393,41 +371,25 @@ PJ_DEF(void*) pj_stun_session_get_user_data(pj_stun_session *sess) return sess->user_data; } -PJ_DEF(pj_status_t) -pj_stun_session_set_long_term_credential(pj_stun_session *sess, - const pj_str_t *realm, - const pj_str_t *user, - const pj_str_t *passwd) +PJ_DEF(pj_status_t) pj_stun_session_set_server_name(pj_stun_session *sess, + const pj_str_t *srv_name) { - pj_str_t nil = { NULL, 0 }; - - PJ_ASSERT_RETURN(sess, PJ_EINVAL); - - pj_mutex_lock(sess->mutex); - pj_strdup_with_null(sess->pool, &sess->l_realm, realm ? realm : &nil); - pj_strdup_with_null(sess->pool, &sess->l_username, user ? user : &nil); - pj_strdup_with_null(sess->pool, &sess->l_password, passwd ? passwd : &nil); - pj_mutex_unlock(sess->mutex); - + PJ_ASSERT_RETURN(sess && srv_name, PJ_EINVAL); + pj_strdup(sess->pool, &sess->srv_name, srv_name); return PJ_SUCCESS; } - -PJ_DEF(pj_status_t) -pj_stun_session_set_short_term_credential(pj_stun_session *sess, - const pj_str_t *user, - const pj_str_t *passwd) +PJ_DEF(void) pj_stun_session_set_credential(pj_stun_session *sess, + const pj_stun_auth_cred *cred) { - pj_str_t nil = { NULL, 0 }; - - PJ_ASSERT_RETURN(sess, PJ_EINVAL); - - pj_mutex_lock(sess->mutex); - pj_strdup_with_null(sess->pool, &sess->s_username, user ? user : &nil); - pj_strdup_with_null(sess->pool, &sess->s_password, passwd ? passwd : &nil); - pj_mutex_unlock(sess->mutex); - - return PJ_SUCCESS; + PJ_ASSERT_ON_FAIL(sess, return); + if (cred) { + if (!sess->cred) + sess->cred = pj_pool_alloc(sess->pool, sizeof(pj_stun_auth_cred)); + pj_stun_auth_cred_dup(sess->pool, sess->cred, cred); + } else { + sess->cred = NULL; + } } @@ -569,18 +531,15 @@ static void dump_tx_msg(pj_stun_session *sess, const pj_stun_msg *msg, PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess, - unsigned options, + pj_bool_t cache_res, const pj_sockaddr_t *server, unsigned addr_len, pj_stun_tx_data *tdata) { - pj_str_t *password; pj_status_t status; PJ_ASSERT_RETURN(sess && addr_len && server && tdata, PJ_EINVAL); - tdata->options = options; - /* Allocate packet */ tdata->max_len = PJ_STUN_MAX_PKT_LEN; tdata->pkt = pj_pool_alloc(tdata->pool, tdata->max_len); @@ -589,8 +548,7 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess, pj_mutex_lock(sess->mutex); /* Apply options */ - status = apply_msg_options(sess, tdata->pool, options, - tdata->msg, &password); + status = apply_msg_options(sess, tdata->pool, tdata->msg); if (status != PJ_SUCCESS) { pj_stun_msg_destroy_tdata(sess, tdata); pj_mutex_unlock(sess->mutex); @@ -600,7 +558,7 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess, /* Encode message */ status = pj_stun_msg_encode(tdata->msg, tdata->pkt, tdata->max_len, - 0, password, &tdata->pkt_size); + 0, get_passwd(sess), &tdata->pkt_size); if (status != PJ_SUCCESS) { pj_stun_msg_destroy_tdata(sess, tdata); pj_mutex_unlock(sess->mutex); @@ -640,7 +598,7 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess, tsx_add(sess, tdata); } else { - if ((options & PJ_STUN_CACHE_RESPONSE) && + if (cache_res && (PJ_STUN_IS_RESPONSE(tdata->msg->hdr.type) || PJ_STUN_IS_ERROR_RESPONSE(tdata->msg->hdr.type))) { @@ -687,6 +645,68 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess, } +/* Send response */ +static pj_status_t send_response(pj_stun_session *sess, + pj_pool_t *pool, pj_stun_msg *response, + pj_bool_t retransmission, + const pj_sockaddr_t *addr, unsigned addr_len) +{ + pj_uint8_t *out_pkt; + unsigned out_max_len, out_len; + pj_status_t status; + + /* Alloc packet buffer */ + out_max_len = PJ_STUN_MAX_PKT_LEN; + out_pkt = pj_pool_alloc(pool, out_max_len); + + /* Apply options */ + if (!retransmission) { + apply_msg_options(sess, pool, response); + } + + /* Encode */ + status = pj_stun_msg_encode(response, out_pkt, out_max_len, 0, + get_passwd(sess), &out_len); + if (status != PJ_SUCCESS) { + LOG_ERR_(sess, "Error encoding message", status); + return status; + } + + /* Print log */ + dump_tx_msg(sess, response, out_len, addr); + + /* Send packet */ + status = sess->cb.on_send_msg(sess, out_pkt, out_len, addr, addr_len); + + return status; +} + +/* Authenticate incoming message */ +static pj_status_t authenticate_msg(pj_stun_session *sess, + const pj_uint8_t *pkt, + unsigned pkt_len, + const pj_stun_msg *msg, + pj_pool_t *tmp_pool, + const pj_sockaddr_t *src_addr, + unsigned src_addr_len) +{ + pj_stun_msg *response; + pj_status_t status; + + if (PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type) || sess->cred == NULL) + return PJ_SUCCESS; + + status = pj_stun_verify_credential(pkt, pkt_len, msg, sess->cred, + tmp_pool, &response); + if (status != PJ_SUCCESS && response != NULL) { + send_response(sess, tmp_pool, response, PJ_FALSE, + src_addr, src_addr_len); + } + + return status; +} + + /* Handle incoming response */ static pj_status_t on_incoming_response(pj_stun_session *sess, pj_stun_msg *msg) @@ -723,51 +743,14 @@ static pj_status_t on_incoming_response(pj_stun_session *sess, } -/* Send response */ -static pj_status_t send_response(pj_stun_session *sess, unsigned options, - pj_pool_t *pool, pj_stun_msg *response, - const pj_sockaddr_t *addr, unsigned addr_len) -{ - pj_uint8_t *out_pkt; - unsigned out_max_len, out_len; - pj_str_t *passwd; - pj_status_t status; - - /* Alloc packet buffer */ - out_max_len = PJ_STUN_MAX_PKT_LEN; - out_pkt = pj_pool_alloc(pool, out_max_len); - - /* Apply options */ - apply_msg_options(sess, pool, options, response, &passwd); - - /* Encode */ - status = pj_stun_msg_encode(response, out_pkt, out_max_len, 0, - passwd, &out_len); - if (status != PJ_SUCCESS) { - LOG_ERR_(sess, "Error encoding message", status); - return status; - } - - /* Print log */ - dump_tx_msg(sess, response, out_len, addr); - - /* Send packet */ - status = sess->cb.on_send_msg(sess, out_pkt, out_len, addr, addr_len); - - return status; -} - -/* Handle incoming request */ -static pj_status_t on_incoming_request(pj_stun_session *sess, - pj_pool_t *tmp_pool, - const pj_uint8_t *in_pkt, - unsigned in_pkt_len, - const pj_stun_msg *msg, - const pj_sockaddr_t *src_addr, - unsigned src_addr_len) +/* For requests, check if we cache the response */ +static pj_status_t check_cached_response(pj_stun_session *sess, + pj_pool_t *tmp_pool, + const pj_stun_msg *msg, + const pj_sockaddr_t *src_addr, + unsigned src_addr_len) { pj_stun_tx_data *t; - pj_status_t status; /* First lookup response in response cache */ t = sess->cached_response_list.next; @@ -783,30 +766,42 @@ static pj_status_t on_incoming_request(pj_stun_session *sess, if (t != &sess->cached_response_list) { /* Found response in the cache */ - unsigned options; PJ_LOG(5,(SNAME(sess), "Request retransmission, sending cached response")); - options = t->options; - options &= ~PJ_STUN_CACHE_RESPONSE; - pj_stun_session_send_msg(sess, options, src_addr, src_addr_len, t); + send_response(sess, tmp_pool, t->msg, PJ_TRUE, + src_addr, src_addr_len); return PJ_SUCCESS; } + return PJ_ENOTFOUND; +} + +/* Handle incoming request */ +static pj_status_t on_incoming_request(pj_stun_session *sess, + pj_pool_t *tmp_pool, + const pj_uint8_t *in_pkt, + unsigned in_pkt_len, + const pj_stun_msg *msg, + const pj_sockaddr_t *src_addr, + unsigned src_addr_len) +{ + pj_status_t status; + /* Distribute to handler, or respond with Bad Request */ if (sess->cb.on_rx_request) { status = (*sess->cb.on_rx_request)(sess, in_pkt, in_pkt_len, msg, src_addr, src_addr_len); } else { - pj_stun_msg *response = NULL; + pj_stun_msg *response; status = pj_stun_msg_create_response(tmp_pool, msg, PJ_STUN_STATUS_BAD_REQUEST, NULL, &response); if (status == PJ_SUCCESS && response) { - status = send_response(sess, 0, tmp_pool, response, - src_addr, src_addr_len); + status = send_response(sess, tmp_pool, response, + PJ_FALSE, src_addr, src_addr_len); } } @@ -861,8 +856,8 @@ PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess, if (status != PJ_SUCCESS) { LOG_ERR_(sess, "STUN msg_decode() error", status); if (response) { - send_response(sess, 0, tmp_pool, response, - src_addr, src_addr_len); + send_response(sess, tmp_pool, response, + PJ_FALSE, src_addr, src_addr_len); } pj_pool_release(tmp_pool); return status; @@ -879,6 +874,20 @@ PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess, pj_mutex_lock(sess->mutex); + /* For requests, check if we have cached response */ + status = check_cached_response(sess, tmp_pool, msg, + src_addr, src_addr_len); + if (status == PJ_SUCCESS) { + goto on_return; + } + + /* Authenticate the message */ + status = authenticate_msg(sess, packet, pkt_size, msg, tmp_pool, + src_addr, src_addr_len); + if (status != PJ_SUCCESS) + goto on_return; + + /* Handle message */ if (PJ_STUN_IS_RESPONSE(msg->hdr.type) || PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type)) { @@ -899,6 +908,7 @@ PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess, status = PJ_EBUG; } +on_return: pj_mutex_unlock(sess->mutex); pj_pool_release(tmp_pool); diff --git a/pjlib-util/src/pjlib-util/stun_transaction.c b/pjlib-util/src/pjlib-util/stun_transaction.c index 02f33177..636d56d1 100644 --- a/pjlib-util/src/pjlib-util/stun_transaction.c +++ b/pjlib-util/src/pjlib-util/stun_transaction.c @@ -259,7 +259,7 @@ static void retransmit_timer_callback(pj_timer_heap_t *timer_heap, PJ_DEF(pj_status_t) pj_stun_client_tsx_on_rx_msg(pj_stun_client_tsx *tsx, const pj_stun_msg *msg) { - pj_stun_error_code_attr *err_attr; + pj_stun_errcode_attr *err_attr; pj_status_t status; /* Must be STUN response message */ @@ -281,7 +281,7 @@ PJ_DEF(pj_status_t) pj_stun_client_tsx_on_rx_msg(pj_stun_client_tsx *tsx, } /* Find STUN error code attribute */ - err_attr = (pj_stun_error_code_attr*) + err_attr = (pj_stun_errcode_attr*) pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ERROR_CODE, 0); if (err_attr && err_attr->err_class <= 2) { @@ -300,8 +300,7 @@ PJ_DEF(pj_status_t) pj_stun_client_tsx_on_rx_msg(pj_stun_client_tsx *tsx, if (err_attr == NULL) { status = PJ_SUCCESS; } else { - status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_class * 100 + - err_attr->number); + status = PJLIB_UTIL_ESTUNTSXFAILED; } /* Call callback */ diff --git a/pjlib-util/src/pjstun-client/client_main.c b/pjlib-util/src/pjstun-client/client_main.c index 4f82f743..fd1b9e39 100644 --- a/pjlib-util/src/pjstun-client/client_main.c +++ b/pjlib-util/src/pjstun-client/client_main.c @@ -29,7 +29,6 @@ static struct global pj_caching_pool cp; pj_timer_heap_t *th; pj_stun_session *sess; - unsigned sess_options; pj_sock_t sock; pj_thread_t *thread; pj_bool_t quit; @@ -45,6 +44,7 @@ static struct options char *realm; char *user_name; char *password; + char *nonce; pj_bool_t use_fingerprint; } o; @@ -180,40 +180,28 @@ static int init() stun_cb.on_send_msg = &on_send_msg; stun_cb.on_request_complete = &on_request_complete; - status = pj_stun_session_create(g.endpt, NULL, &stun_cb, &g.sess); + status = pj_stun_session_create(g.endpt, NULL, &stun_cb, + o.use_fingerprint!=0, &g.sess); pj_assert(status == PJ_SUCCESS); - if (o.realm) { - pj_str_t r, u, p; + if (o.user_name) { + pj_stun_auth_cred cred; - if (o.user_name == NULL) { - printf("error: username must be specified\n"); - return PJ_EINVAL; - } - if (o.password == NULL) - o.password = ""; - g.sess_options = PJ_STUN_USE_LONG_TERM_CRED; - pj_stun_session_set_long_term_credential(g.sess, pj_cstr(&r, o.realm), - pj_cstr(&u, o.user_name), - pj_cstr(&p, o.password)); - puts("Using long term credential"); - } else if (o.user_name) { - pj_str_t u, p; - - if (o.password == NULL) - o.password = ""; - g.sess_options = PJ_STUN_USE_SHORT_TERM_CRED; - pj_stun_session_set_short_term_credential(g.sess, - pj_cstr(&u, o.user_name), - pj_cstr(&p, o.password)); - puts("Using short term credential"); + pj_bzero(&cred, sizeof(cred)); + + cred.type = PJ_STUN_AUTH_CRED_STATIC; + cred.data.static_cred.realm = pj_str(o.realm); + cred.data.static_cred.username = pj_str(o.user_name); + cred.data.static_cred.data_type = 0; + cred.data.static_cred.data = pj_str(o.password); + cred.data.static_cred.nonce = pj_str(o.nonce); + + pj_stun_session_set_credential(g.sess, &cred); + puts("Session credential set"); } else { puts("Credential not set"); } - if (o.use_fingerprint) - g.sess_options |= PJ_STUN_USE_FINGERPRINT; - status = pj_thread_create(g.pool, "stun", &worker_thread, NULL, 0, 0, &g.thread); if (status != PJ_SUCCESS) @@ -275,7 +263,7 @@ static void console_main(void) rc = pj_stun_session_create_bind_req(g.sess, &tdata); pj_assert(rc == PJ_SUCCESS); - rc = pj_stun_session_send_msg(g.sess, g.sess_options, + rc = pj_stun_session_send_msg(g.sess, PJ_FALSE, &g.dst_addr, sizeof(g.dst_addr), tdata); if (rc != PJ_SUCCESS) @@ -302,6 +290,7 @@ static void usage(void) puts(" --realm, -r Set realm of the credential"); puts(" --username, -u Set username of the credential"); puts(" --password, -p Set password of the credential"); + puts(" --nonce, -N Set NONCE"); puts(" --fingerprint, -F Use fingerprint for outgoing requests"); puts(" --help, -h"); } @@ -312,6 +301,7 @@ int main(int argc, char *argv[]) { "realm", 1, 0, 'r'}, { "username", 1, 0, 'u'}, { "password", 1, 0, 'p'}, + { "nonce", 1, 0, 'N'}, { "fingerprint",0, 0, 'F'}, { "help", 0, 0, 'h'} }; @@ -330,6 +320,9 @@ int main(int argc, char *argv[]) case 'p': o.password = pj_optarg; break; + case 'N': + o.nonce = pj_optarg; + break; case 'h': usage(); return 0; diff --git a/pjlib-util/src/pjstun-srv-test/server_main.c b/pjlib-util/src/pjstun-srv-test/server_main.c index 4825cf8e..e4fc6d5b 100644 --- a/pjlib-util/src/pjstun-srv-test/server_main.c +++ b/pjlib-util/src/pjstun-srv-test/server_main.c @@ -61,8 +61,17 @@ static struct stun_server unsigned thread_cnt; pj_thread_t *threads[16]; + } server; +static struct options +{ + char *realm; + char *user_name; + char *password; + char *nonce; + pj_bool_t use_fingerprint; +} o; static pj_status_t server_perror(const char *sender, const char *title, pj_status_t status) @@ -131,10 +140,10 @@ static pj_status_t on_rx_binding_request(pj_stun_session *sess, return status; /* Create MAPPED-ADDRESS attribute */ - status = pj_stun_msg_add_generic_ip_addr_attr(tdata->pool, tdata->msg, - PJ_STUN_ATTR_MAPPED_ADDR, - PJ_FALSE, - src_addr, src_addr_len); + status = pj_stun_msg_add_ip_addr_attr(tdata->pool, tdata->msg, + PJ_STUN_ATTR_MAPPED_ADDR, + PJ_FALSE, + src_addr, src_addr_len); if (status != PJ_SUCCESS) { server_perror(THIS_FILE, "Error creating response", status); pj_stun_msg_destroy_tdata(sess, tdata); @@ -144,10 +153,10 @@ static pj_status_t on_rx_binding_request(pj_stun_session *sess, /* On the presence of magic, create XOR-MAPPED-ADDRESS attribute */ if (msg->hdr.magic == PJ_STUN_MAGIC) { status = - pj_stun_msg_add_generic_ip_addr_attr(tdata->pool, tdata->msg, - PJ_STUN_ATTR_XOR_MAPPED_ADDRESS, - PJ_TRUE, - src_addr, src_addr_len); + pj_stun_msg_add_ip_addr_attr(tdata->pool, tdata->msg, + PJ_STUN_ATTR_XOR_MAPPED_ADDRESS, + PJ_TRUE, + src_addr, src_addr_len); if (status != PJ_SUCCESS) { server_perror(THIS_FILE, "Error creating response", status); pj_stun_msg_destroy_tdata(sess, tdata); @@ -156,7 +165,7 @@ static pj_status_t on_rx_binding_request(pj_stun_session *sess, } /* Send */ - status = pj_stun_session_send_msg(sess, PJ_STUN_CACHE_RESPONSE, + status = pj_stun_session_send_msg(sess, PJ_TRUE, src_addr, src_addr_len, tdata); return status; } @@ -263,12 +272,32 @@ static pj_status_t init_service(struct service *svc) sess_cb.on_send_msg = &on_send_msg; sess_cb.on_rx_request = &on_rx_request; status = pj_stun_session_create(server.endpt, "session", - &sess_cb, &svc->sess); + &sess_cb, + o.use_fingerprint!=0, + &svc->sess); if (status != PJ_SUCCESS) goto on_error; pj_stun_session_set_user_data(svc->sess, (void*)svc); + if (o.user_name) { + pj_stun_auth_cred cred; + + pj_bzero(&cred, sizeof(cred)); + + cred.type = PJ_STUN_AUTH_CRED_STATIC; + cred.data.static_cred.realm = pj_str(o.realm); + cred.data.static_cred.username = pj_str(o.user_name); + cred.data.static_cred.data_type = 0; + cred.data.static_cred.data = pj_str(o.password); + cred.data.static_cred.nonce = pj_str(o.nonce); + + pj_stun_session_set_credential(svc->sess, &cred); + puts("Session credential set"); + } else { + puts("Credential not set"); + } + pj_bzero(&service_callback, sizeof(service_callback)); service_callback.on_read_complete = &on_read_complete; @@ -437,8 +466,65 @@ pj_status_t server_destroy(void) } -int main() +static void usage(void) +{ + puts("Usage: pjstun_srv_test [OPTIONS]"); + puts(""); + puts("where OPTIONS:"); + puts(" --realm, -r Set realm of the credential"); + puts(" --username, -u Set username of the credential"); + puts(" --password, -p Set password of the credential"); + puts(" --nonce, -N Set NONCE"); + puts(" --fingerprint, -F Use fingerprint for outgoing requests"); + puts(" --help, -h"); +} + + +int main(int argc, char *argv[]) { + struct pj_getopt_option long_options[] = { + { "realm", 1, 0, 'r'}, + { "username", 1, 0, 'u'}, + { "password", 1, 0, 'p'}, + { "nonce", 1, 0, 'N'}, + { "fingerprint",0, 0, 'F'}, + { "help", 0, 0, 'h'} + }; + int c, opt_id; + + while((c=pj_getopt_long(argc,argv, "r:u:p:hF", long_options, &opt_id))!=-1) { + switch (c) { + case 'r': + o.realm = pj_optarg; + break; + case 'u': + o.user_name = pj_optarg; + break; + case 'p': + o.password = pj_optarg; + break; + case 'N': + o.nonce = pj_optarg; + break; + case 'h': + usage(); + return 0; + case 'F': + o.use_fingerprint = PJ_TRUE; + break; + default: + printf("Argument \"%s\" is not valid. Use -h to see help", + argv[pj_optind]); + return 1; + } + } + + if (pj_optind != argc) { + puts("Error: invalid arguments"); + return 1; + } + + if (server_init()) { server_destroy(); return 1; |