summaryrefslogtreecommitdiff
path: root/pjnath
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2009-04-07 09:42:58 +0000
committerBenny Prijono <bennylp@teluu.com>2009-04-07 09:42:58 +0000
commit125315337f4e0df235bcf2e0d388db32493cca3f (patch)
tree0ad75b40756a4bc9ea5d657bc9a8a101f641cfdc /pjnath
parent350d6756668b62617ac3169ee10148199fab4037 (diff)
Part of ticket #780 (work in progress): added IPv6 support to various STUN attributes and added the test from draft-ietf-behave-stun-test-vectors
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@2580 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjnath')
-rw-r--r--pjnath/include/pjnath/errno.h7
-rw-r--r--pjnath/include/pjnath/types.h7
-rw-r--r--pjnath/src/pjnath-test/stun.c110
-rw-r--r--pjnath/src/pjnath/errno.c1
-rw-r--r--pjnath/src/pjnath/stun_msg.c365
5 files changed, 392 insertions, 98 deletions
diff --git a/pjnath/include/pjnath/errno.h b/pjnath/include/pjnath/errno.h
index 56645234..719ba412 100644
--- a/pjnath/include/pjnath/errno.h
+++ b/pjnath/include/pjnath/errno.h
@@ -114,12 +114,17 @@
* STUN IPv6 attribute not supported
*/
#define PJNATH_ESTUNIPV6NOTSUPP (PJNATH_ERRNO_START+41) /* 370041 */
+/**
+ * @hideinitializer
+ * Invalid address family value in STUN message.
+ */
+#define PJNATH_EINVAF (PJNATH_ERRNO_START+42) /* 370042 */
/**
* @hideinitializer
* Invalid STUN server or server not configured.
*/
-#define PJNATH_ESTUNINSERVER (PJNATH_ERRNO_START+42) /* 370042 */
+#define PJNATH_ESTUNINSERVER (PJNATH_ERRNO_START+50) /* 370050 */
/************************************************************
diff --git a/pjnath/include/pjnath/types.h b/pjnath/include/pjnath/types.h
index b3dee539..a7d66070 100644
--- a/pjnath/include/pjnath/types.h
+++ b/pjnath/include/pjnath/types.h
@@ -97,10 +97,9 @@ application protocols in dealing with NAT traversal. It allows a client
to determine the IP address and port allocated to them by a NAT and to
keep NAT bindings open.
-This version of PJNATH implements the following STUN-bis draft:
-- <A HREF="http://www.ietf.org/internet-drafts/draft-ietf-behave-rfc3489bis-18.txt">
- <B>draft-ietf-behave-rfc3489bis-18</b></A>: Session Traversal
- Utilities for (NAT) (STUN),
+This version of PJNATH implements the following STUN RFC:
+- <A HREF="http://www.ietf.org/rfc/rfc5389.txt"><B>RFC 5389</b></A>:
+ Session Traversal Utilities for (NAT) (STUN),
\subsection comp_turn TURN
diff --git a/pjnath/src/pjnath-test/stun.c b/pjnath/src/pjnath-test/stun.c
index 24196db6..aab3763a 100644
--- a/pjnath/src/pjnath-test/stun.c
+++ b/pjnath/src/pjnath-test/stun.c
@@ -430,10 +430,15 @@ static int decode_verify(void)
return 0;
}
+/*
+ * Test vectors, from:
+ * http://tools.ietf.org/html/draft-denis-behave-rfc3489bis-test-vectors-02
+ */
typedef struct test_vector test_vector;
static pj_stun_msg* create_msgint1(pj_pool_t *pool, test_vector *v);
static pj_stun_msg* create_msgint2(pj_pool_t *pool, test_vector *v);
+static pj_stun_msg* create_msgint3(pj_pool_t *pool, test_vector *v);
enum
{
@@ -441,7 +446,7 @@ enum
USE_FINGERPRINT = 2
};
-struct test_vector
+static struct test_vector
{
unsigned msg_type;
char *tsx_id;
@@ -450,6 +455,8 @@ struct test_vector
unsigned options;
char *username;
char *password;
+ char *realm;
+ char *nonce;
pj_stun_msg* (*create)(pj_pool_t*, test_vector*);
} test_vectors[] =
{
@@ -469,24 +476,68 @@ struct test_vector
USE_MESSAGE_INTEGRITY | USE_FINGERPRINT,
"evtj:h6vY",
"VOkJxbRl1RmTxUk/WvJxBt",
+ "",
+ "",
&create_msgint1
},
{
PJ_STUN_BINDING_RESPONSE,
"\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae",
- "\x01\x01\x00\x3c\x21\x12\xa4\x42\xb7\xe7"
- "\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae"
- "\x80\x22\x00\x0b\x74\x65\x73\x74\x20\x76"
- "\x65\x63\x74\x6f\x72\x20\x00\x20\x00\x08"
- "\x00\x01\xa1\x47\x5e\x12\xa4\x43\x00\x08"
- "\x00\x14\xab\x4e\x53\x29\x61\x00\x08\x4c"
- "\x89\xf2\x7c\x69\x30\x33\x5c\xa3\x58\x14"
- "\xea\x90\x80\x28\x00\x04\xae\x25\x8d\xf2",
+ "\x01\x01\x00\x3c"
+ "\x21\x12\xa4\x42"
+ "\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae"
+ "\x80\x22\x00\x0b"
+ "\x74\x65\x73\x74\x20\x76\x65\x63\x74\x6f\x72\x20"
+ "\x00\x20\x00\x08"
+ "\x00\x01\xa1\x47\xe1\x12\xa6\x43"
+ "\x00\x08\x00\x14"
+ "\x2b\x91\xf5\x99\xfd\x9e\x90\xc3\x8c\x74\x89\xf9"
+ "\x2a\xf9\xba\x53\xf0\x6b\xe7\xd7"
+ "\x80\x28\x00\x04"
+ "\xc0\x7d\x4c\x96",
80,
USE_MESSAGE_INTEGRITY | USE_FINGERPRINT,
"evtj:h6vY",
"VOkJxbRl1RmTxUk/WvJxBt",
+ "",
+ "",
&create_msgint2
+ },
+ {
+ PJ_STUN_BINDING_RESPONSE,
+ "\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae",
+ "\x01\x01\x00\x48" // Response type and message length
+ "\x21\x12\xa4\x42" // Message cookie
+ "\xb7\xe7\xa7\x01" // }
+ "\xbc\x34\xd6\x86" // } Transaction ID
+ "\xfa\x87\xdf\xae" // }
+
+ "\x80\x22\x00\x0b" // SOFTWARE, length=11
+ "\x74\x65\x73\x74"
+ "\x20\x76\x65\x63"
+ "\x74\x6f\x72\x20"
+ "\x00\x20\x00\x14" // XOR-MAPPED-ADDRESS
+ "\x00\x02\xa1\x47"
+ "\x01\x13\xa9\xfa"
+ "\xa5\xd3\xf1\x79"
+ "\xbc\x25\xf4\xb5"
+ "\xbe\xd2\xb9\xd9"
+ "\x00\x08\x00\x14" // MESSAGE-INTEGRITY attribute header
+ "\xa3\x82\x95\x4e" // }
+ "\x4b\xe6\x7b\xf1" // }
+ "\x17\x84\xc9\x7c" // } HMAC-SHA1 fingerprint
+ "\x82\x92\xc2\x75" // }
+ "\xbf\xe3\xed\x41" // }
+ "\x80\x28\x00\x04" // FINGERPRINT attribute header
+ "\xc8\xfb\x0b\x4c" // CRC32 fingerprint
+,
+ 92,
+ USE_MESSAGE_INTEGRITY | USE_FINGERPRINT,
+ "evtj:h6vY",
+ "VOkJxbRl1RmTxUk/WvJxBt",
+ "",
+ "",
+ &create_msgint3
}
};
@@ -537,7 +588,7 @@ static int fingerprint_test_vector()
unsigned i;
int rc = 0;
- PJ_LOG(3,(THIS_FILE, " STUN message test vectors"));
+ PJ_LOG(3,(THIS_FILE, " draft-denis-behave-rfc3489bis-test-vectors-02"));
pool = pj_pool_create(mem, "fingerprint", 1024, 1024, NULL);
@@ -585,10 +636,12 @@ static int fingerprint_test_vector()
/* Encode message */
if (v->options & USE_MESSAGE_INTEGRITY) {
- pj_str_t s1, s2;
+ pj_str_t s1, s2, r;
- pj_stun_create_key(pool, &key, NULL, pj_cstr(&s1, v->username),
- PJ_STUN_PASSWD_PLAIN, pj_cstr(&s2, v->password));
+ pj_stun_create_key(pool, &key, pj_cstr(&r, v->realm),
+ pj_cstr(&s1, v->username),
+ PJ_STUN_PASSWD_PLAIN,
+ pj_cstr(&s2, v->password));
pj_stun_msg_encode(msg, buf, sizeof(buf), 0, &key, &len);
} else {
@@ -625,8 +678,10 @@ static int fingerprint_test_vector()
pj_bzero(&cred, sizeof(cred));
cred.type = PJ_STUN_AUTH_CRED_STATIC;
+ cred.data.static_cred.realm = pj_str(v->realm);
cred.data.static_cred.username = pj_str(v->username);
cred.data.static_cred.data = pj_str(v->password);
+ cred.data.static_cred.nonce = pj_str(v->nonce);
status = pj_stun_authenticate_request(buf, len, msg,
&cred, pool, NULL, NULL);
@@ -699,7 +754,7 @@ static pj_stun_msg* create_msgint2(pj_pool_t *pool, test_vector *v)
pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SOFTWARE,
pj_cstr(&s1, "test vector"));
- pj_sockaddr_in_init(&mapped_addr, pj_cstr(&s1, "127.0.0.1"), 32853);
+ pj_sockaddr_in_init(&mapped_addr, pj_cstr(&s1, "192.0.2.1"), 32853);
pj_stun_msg_add_sockaddr_attr(pool, msg, PJ_STUN_ATTR_XOR_MAPPED_ADDR,
PJ_TRUE, &mapped_addr,
sizeof(pj_sockaddr_in));
@@ -711,6 +766,33 @@ static pj_stun_msg* create_msgint2(pj_pool_t *pool, test_vector *v)
}
+static pj_stun_msg* create_msgint3(pj_pool_t *pool, test_vector *v)
+{
+ pj_stun_msg *msg;
+ pj_sockaddr mapped_addr;
+ pj_str_t s1;
+
+ pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC,
+ (pj_uint8_t*)v->tsx_id, &msg);
+
+ pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SOFTWARE,
+ pj_cstr(&s1, "test vector"));
+
+ pj_sockaddr_init(pj_AF_INET6(), &mapped_addr,
+ pj_cstr(&s1, "2001:db8:1234:5678:11:2233:4455:6677"),
+ 32853);
+
+ pj_stun_msg_add_sockaddr_attr(pool, msg, PJ_STUN_ATTR_XOR_MAPPED_ADDR,
+ PJ_TRUE, &mapped_addr,
+ sizeof(pj_sockaddr));
+
+ pj_stun_msg_add_msgint_attr(pool, msg);
+ pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0);
+
+ return msg;
+}
+
+
/* Compare two messages */
static int cmp_msg(const pj_stun_msg *msg1, const pj_stun_msg *msg2)
{
diff --git a/pjnath/src/pjnath/errno.c b/pjnath/src/pjnath/errno.c
index 97b5afae..d102a09d 100644
--- a/pjnath/src/pjnath/errno.c
+++ b/pjnath/src/pjnath/errno.c
@@ -51,6 +51,7 @@ static const struct
PJ_BUILD_ERR( PJNATH_ESTUNNOMAPPEDADDR, "STUN (XOR-)MAPPED-ADDRESS attribute not found"),
PJ_BUILD_ERR( PJNATH_ESTUNIPV6NOTSUPP, "STUN IPv6 attribute not supported"),
+ PJ_BUILD_ERR( PJNATH_EINVAF, "Invalid STUN address family value"),
PJ_BUILD_ERR( PJNATH_ESTUNINSERVER, "Invalid STUN server or server not configured"),
PJ_BUILD_ERR( PJNATH_ESTUNDESTROYED, "STUN object has been destoyed"),
diff --git a/pjnath/src/pjnath/stun_msg.c b/pjnath/src/pjnath/stun_msg.c
index 4953dae2..e1cba80b 100644
--- a/pjnath/src/pjnath/stun_msg.c
+++ b/pjnath/src/pjnath/stun_msg.c
@@ -88,69 +88,97 @@ struct attr_desc
{
const char *name;
pj_status_t (*decode_attr)(pj_pool_t *pool, const pj_uint8_t *buf,
- void **p_attr);
+ const pj_stun_msg_hdr *msghdr, void **p_attr);
pj_status_t (*encode_attr)(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed);
+ unsigned len, const pj_stun_msg_hdr *msghdr,
+ unsigned *printed);
void* (*clone_attr)(pj_pool_t *pool, const void *src);
};
static pj_status_t decode_sockaddr_attr(pj_pool_t *pool,
- const pj_uint8_t *buf,
- void **p_attr);
+ const pj_uint8_t *buf,
+ const pj_stun_msg_hdr *msghdr,
+ void **p_attr);
static pj_status_t decode_xored_sockaddr_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
+ const pj_stun_msg_hdr *msghdr,
void **p_attr);
static pj_status_t encode_sockaddr_attr(const void *a, pj_uint8_t *buf,
- unsigned len,
- unsigned *printed);
+ unsigned len,
+ const pj_stun_msg_hdr *msghdr,
+ unsigned *printed);
static void* clone_sockaddr_attr(pj_pool_t *pool, const void *src);
static pj_status_t decode_string_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
+ const pj_stun_msg_hdr *msghdr,
void **p_attr);
static pj_status_t encode_string_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed);
+ unsigned len,
+ const pj_stun_msg_hdr *msghdr,
+ unsigned *printed);
static void* clone_string_attr(pj_pool_t *pool, const void *src);
static pj_status_t decode_msgint_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
+ const pj_stun_msg_hdr *msghdr,
void **p_attr);
static pj_status_t encode_msgint_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed);
+ unsigned len,
+ const pj_stun_msg_hdr *msghdr,
+ unsigned *printed);
static void* clone_msgint_attr(pj_pool_t *pool, const void *src);
static pj_status_t decode_errcode_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
+ const pj_stun_msg_hdr *msghdr,
void **p_attr);
static pj_status_t encode_errcode_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed);
+ unsigned len,
+ const pj_stun_msg_hdr *msghdr,
+ unsigned *printed);
static void* clone_errcode_attr(pj_pool_t *pool, const void *src);
static pj_status_t decode_unknown_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
+ const pj_stun_msg_hdr *msghdr,
void **p_attr);
static pj_status_t encode_unknown_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed);
+ unsigned len,
+ const pj_stun_msg_hdr *msghdr,
+ unsigned *printed);
static void* clone_unknown_attr(pj_pool_t *pool, const void *src);
static pj_status_t decode_uint_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
+ const pj_stun_msg_hdr *msghdr,
void **p_attr);
static pj_status_t encode_uint_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed);
+ unsigned len,
+ const pj_stun_msg_hdr *msghdr,
+ unsigned *printed);
static void* clone_uint_attr(pj_pool_t *pool, const void *src);
static pj_status_t decode_uint64_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
+ const pj_stun_msg_hdr *msghdr,
void **p_attr);
static pj_status_t encode_uint64_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed);
+ unsigned len,
+ const pj_stun_msg_hdr *msghdr,
+ unsigned *printed);
static void* clone_uint64_attr(pj_pool_t *pool, const void *src);
static pj_status_t decode_binary_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
+ const pj_stun_msg_hdr *msghdr,
void **p_attr);
static pj_status_t encode_binary_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed);
+ unsigned len,
+ const pj_stun_msg_hdr *msghdr,
+ unsigned *printed);
static void* clone_binary_attr(pj_pool_t *pool, const void *src);
static pj_status_t decode_empty_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
+ const pj_stun_msg_hdr *msghdr,
void **p_attr);
static pj_status_t encode_empty_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed);
+ unsigned len,
+ const pj_stun_msg_hdr *msghdr,
+ unsigned *printed);
static void* clone_empty_attr(pj_pool_t *pool, const void *src);
static struct attr_desc mandatory_attr_desc[] =
@@ -726,7 +754,7 @@ static pj_uint16_t GETVAL16H(const pj_uint8_t *buf, unsigned pos)
(buf[pos + 1] << 0));
}
-static pj_uint16_t GETVAL16N(const pj_uint8_t *buf, unsigned pos)
+PJ_INLINE(pj_uint16_t) GETVAL16N(const pj_uint8_t *buf, unsigned pos)
{
return pj_htons(GETVAL16H(buf,pos));
}
@@ -737,7 +765,7 @@ static void PUTVAL16H(pj_uint8_t *buf, unsigned pos, pj_uint16_t hval)
buf[pos+1] = (pj_uint8_t) ((hval & 0x00FF) >> 0);
}
-static pj_uint32_t GETVAL32H(const pj_uint8_t *buf, unsigned pos)
+PJ_INLINE(pj_uint32_t) GETVAL32H(const pj_uint8_t *buf, unsigned pos)
{
return (pj_uint32_t) ((buf[pos + 0] << 24UL) | \
(buf[pos + 1] << 16UL) | \
@@ -745,7 +773,7 @@ static pj_uint32_t GETVAL32H(const pj_uint8_t *buf, unsigned pos)
(buf[pos + 3] << 0UL));
}
-static pj_uint32_t GETVAL32N(const pj_uint8_t *buf, unsigned pos)
+PJ_INLINE(pj_uint32_t) GETVAL32N(const pj_uint8_t *buf, unsigned pos)
{
return pj_htonl(GETVAL32H(buf,pos));
}
@@ -781,7 +809,8 @@ static void GETATTRHDR(const pj_uint8_t *buf, pj_stun_attr_hdr *hdr)
/*
* STUN generic IP address container
*/
-#define STUN_GENERIC_IP_ADDR_LEN 8
+#define STUN_GENERIC_IPV4_ADDR_LEN 8
+#define STUN_GENERIC_IPV6_ADDR_LEN 20
/*
* Init sockaddr attr
@@ -792,11 +821,14 @@ PJ_DEF(pj_status_t) pj_stun_sockaddr_attr_init( pj_stun_sockaddr_attr *attr,
const pj_sockaddr_t *addr,
unsigned addr_len)
{
+ unsigned attr_len;
+
PJ_ASSERT_RETURN(attr && addr_len && addr, PJ_EINVAL);
PJ_ASSERT_RETURN(addr_len == sizeof(pj_sockaddr_in) ||
addr_len == sizeof(pj_sockaddr_in6), PJ_EINVAL);
- INIT_ATTR(attr, attr_type, STUN_GENERIC_IP_ADDR_LEN);
+ attr_len = pj_sockaddr_get_addr_len(addr) + 4;
+ INIT_ATTR(attr, attr_type, attr_len);
pj_memcpy(&attr->sockaddr, addr, addr_len);
attr->xor_ed = xor_ed;
@@ -848,32 +880,55 @@ PJ_DEF(pj_status_t) pj_stun_msg_add_sockaddr_attr(pj_pool_t *pool,
static pj_status_t decode_sockaddr_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
+ const pj_stun_msg_hdr *msghdr,
void **p_attr)
{
pj_stun_sockaddr_attr *attr;
+ int af;
+ unsigned addr_len;
pj_uint32_t val;
PJ_CHECK_STACK();
+ PJ_UNUSED_ARG(msghdr);
+
/* Create the attribute */
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_sockaddr_attr);
GETATTRHDR(buf, &attr->hdr);
/* Check that the attribute length is valid */
- if (attr->hdr.length != STUN_GENERIC_IP_ADDR_LEN)
+ if (attr->hdr.length != STUN_GENERIC_IPV4_ADDR_LEN &&
+ attr->hdr.length != STUN_GENERIC_IPV6_ADDR_LEN)
+ {
return PJNATH_ESTUNINATTRLEN;
+ }
/* Check address family */
val = *(pj_uint8_t*)(buf + ATTR_HDR_LEN + 1);
- /* Check address family is valid (only supports ipv4 for now) */
- if (val != 1)
- return PJNATH_ESTUNIPV6NOTSUPP;
+ /* Check address family is valid */
+ if (val == 1) {
+ if (attr->hdr.length != STUN_GENERIC_IPV4_ADDR_LEN)
+ return PJNATH_ESTUNINATTRLEN;
+ af = pj_AF_INET();
+ addr_len = 4;
+ } else if (val == 2) {
+ if (attr->hdr.length != STUN_GENERIC_IPV6_ADDR_LEN)
+ return PJNATH_ESTUNINATTRLEN;
+ af = pj_AF_INET6();
+ addr_len = 16;
+ } else {
+ /* Invalid address family */
+ return PJNATH_EINVAF;
+ }
/* Get port and address */
- pj_sockaddr_in_init(&attr->sockaddr.ipv4, NULL, 0);
- attr->sockaddr.ipv4.sin_port = GETVAL16N(buf, ATTR_HDR_LEN+2);
- attr->sockaddr.ipv4.sin_addr.s_addr = GETVAL32N(buf, ATTR_HDR_LEN+4);
+ pj_sockaddr_init(af, &attr->sockaddr, NULL, 0);
+ pj_sockaddr_set_port(&attr->sockaddr,
+ GETVAL16H(buf, ATTR_HDR_LEN+2));
+ pj_memcpy(pj_sockaddr_get_addr(&attr->sockaddr),
+ buf+ATTR_HDR_LEN+4,
+ addr_len);
/* Done */
*p_attr = (void*)attr;
@@ -884,20 +939,47 @@ static pj_status_t decode_sockaddr_attr(pj_pool_t *pool,
static pj_status_t decode_xored_sockaddr_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
+ const pj_stun_msg_hdr *msghdr,
void **p_attr)
{
pj_stun_sockaddr_attr *attr;
pj_status_t status;
- status = decode_sockaddr_attr(pool, buf, p_attr);
+ status = decode_sockaddr_attr(pool, buf, msghdr, p_attr);
if (status != PJ_SUCCESS)
return status;
attr = *(pj_stun_sockaddr_attr**)p_attr;
attr->xor_ed = PJ_TRUE;
- attr->sockaddr.ipv4.sin_port ^= pj_htons(0x2112);
- attr->sockaddr.ipv4.sin_addr.s_addr ^= pj_htonl(0x2112A442);
+
+ if (attr->sockaddr.addr.sa_family == pj_AF_INET()) {
+ attr->sockaddr.ipv4.sin_port ^= pj_htons(PJ_STUN_MAGIC >> 16);
+ attr->sockaddr.ipv4.sin_addr.s_addr ^= pj_htonl(PJ_STUN_MAGIC);
+ } else if (attr->sockaddr.addr.sa_family == pj_AF_INET6()) {
+ unsigned i;
+ pj_uint8_t *dst = (pj_uint8_t*) &attr->sockaddr.ipv6.sin6_addr;
+ pj_uint32_t magic = pj_htonl(PJ_STUN_MAGIC);
+
+ attr->sockaddr.ipv6.sin6_port ^= pj_htons(PJ_STUN_MAGIC >> 16);
+
+ /* If the IP address family is IPv6, X-Address is computed by
+ * taking the mapped IP address in host byte order, XOR'ing it
+ * with the concatenation of the magic cookie and the 96-bit
+ * transaction ID, and converting the result to network byte
+ * order.
+ */
+ for (i=0; i<4; ++i) {
+ dst[i] ^= ((const pj_uint8_t*)&magic)[i];
+ }
+ pj_assert(sizeof(msghdr->tsx_id[0]) == 1);
+ for (i=0; i<12; ++i) {
+ dst[i+4] ^= msghdr->tsx_id[i];
+ }
+
+ } else {
+ return PJNATH_EINVAF;
+ }
/* Done */
*p_attr = attr;
@@ -907,61 +989,128 @@ static pj_status_t decode_xored_sockaddr_attr(pj_pool_t *pool,
static pj_status_t encode_sockaddr_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed)
+ unsigned len,
+ const pj_stun_msg_hdr *msghdr,
+ unsigned *printed)
{
- enum {
- ATTR_LEN = ATTR_HDR_LEN + STUN_GENERIC_IP_ADDR_LEN
- };
pj_uint8_t *start_buf = buf;
const pj_stun_sockaddr_attr *ca =
(const pj_stun_sockaddr_attr *)a;
- if (len < ATTR_LEN)
- return PJ_ETOOSMALL;
-
PJ_CHECK_STACK();
- /* Copy and convert headers to network byte order */
+ /* Common: attribute type */
PUTVAL16H(buf, 0, ca->hdr.type);
- PUTVAL16H(buf, 2, STUN_GENERIC_IP_ADDR_LEN);
- buf += ATTR_HDR_LEN;
+
+ if (ca->sockaddr.addr.sa_family == pj_AF_INET()) {
+ enum {
+ ATTR_LEN = ATTR_HDR_LEN + STUN_GENERIC_IPV4_ADDR_LEN
+ };
+
+ if (len < ATTR_LEN)
+ return PJ_ETOOSMALL;
+
+ /* attribute len */
+ PUTVAL16H(buf, 2, STUN_GENERIC_IPV4_ADDR_LEN);
+ buf += ATTR_HDR_LEN;
- /* Ignored */
- *buf++ = '\0';
+ /* Ignored */
+ *buf++ = '\0';
- /* Family (IPv4 only for now) */
- PJ_ASSERT_RETURN(ca->sockaddr.addr.sa_family == pj_AF_INET(), PJ_EINVAL);
- *buf++ = 1;
+ /* Address family, 1 for IPv4 */
+ *buf++ = 1;
- if (ca->xor_ed) {
- pj_uint32_t addr;
- pj_uint16_t port;
+ /* IPv4 address */
+ if (ca->xor_ed) {
+ pj_uint32_t addr;
+ pj_uint16_t port;
- addr = ca->sockaddr.ipv4.sin_addr.s_addr;
- port = ca->sockaddr.ipv4.sin_port;
+ addr = ca->sockaddr.ipv4.sin_addr.s_addr;
+ port = ca->sockaddr.ipv4.sin_port;
- port ^= pj_htons(0x2112);
- addr ^= pj_htonl(0x2112A442);
+ port ^= pj_htons(PJ_STUN_MAGIC >> 16);
+ addr ^= pj_htonl(PJ_STUN_MAGIC);
- /* Port */
- pj_memcpy(buf, &port, 2);
- buf += 2;
+ /* Port */
+ pj_memcpy(buf, &port, 2);
+ buf += 2;
- /* Address */
- pj_memcpy(buf, &addr, 4);
- buf += 4;
+ /* Address */
+ pj_memcpy(buf, &addr, 4);
+ buf += 4;
- } else {
- /* Port */
- pj_memcpy(buf, &ca->sockaddr.ipv4.sin_port, 2);
- buf += 2;
+ } else {
+ /* Port */
+ pj_memcpy(buf, &ca->sockaddr.ipv4.sin_port, 2);
+ buf += 2;
- /* Address */
- pj_memcpy(buf, &ca->sockaddr.ipv4.sin_addr, 4);
- buf += 4;
- }
+ /* Address */
+ pj_memcpy(buf, &ca->sockaddr.ipv4.sin_addr, 4);
+ buf += 4;
+ }
- pj_assert(buf - start_buf == ATTR_LEN);
+ pj_assert(buf - start_buf == ATTR_LEN);
+
+ } else if (ca->sockaddr.addr.sa_family == pj_AF_INET6()) {
+ /* IPv6 address */
+ enum {
+ ATTR_LEN = ATTR_HDR_LEN + STUN_GENERIC_IPV6_ADDR_LEN
+ };
+
+ if (len < ATTR_LEN)
+ return PJ_ETOOSMALL;
+
+ /* attribute len */
+ PUTVAL16H(buf, 2, STUN_GENERIC_IPV6_ADDR_LEN);
+ buf += ATTR_HDR_LEN;
+
+ /* Ignored */
+ *buf++ = '\0';
+
+ /* Address family, 2 for IPv6 */
+ *buf++ = 2;
+
+ /* IPv6 address */
+ if (ca->xor_ed) {
+ unsigned i;
+ pj_uint8_t *dst;
+ const pj_uint8_t *src;
+ pj_uint32_t magic = pj_htonl(PJ_STUN_MAGIC);
+ pj_uint16_t port = ca->sockaddr.ipv6.sin6_port;
+
+ /* Port */
+ port ^= pj_htons(PJ_STUN_MAGIC >> 16);
+ pj_memcpy(buf, &port, 2);
+ buf += 2;
+
+ /* Address */
+ dst = buf;
+ src = (const pj_uint8_t*) &ca->sockaddr.ipv6.sin6_addr;
+ for (i=0; i<4; ++i) {
+ dst[i] = (pj_uint8_t)(src[i] ^ ((const pj_uint8_t*)&magic)[i]);
+ }
+ pj_assert(sizeof(msghdr->tsx_id[0]) == 1);
+ for (i=0; i<12; ++i) {
+ dst[i+4] = (pj_uint8_t)(src[i+4] ^ msghdr->tsx_id[i]);
+ }
+
+ buf += 16;
+
+ } else {
+ /* Port */
+ pj_memcpy(buf, &ca->sockaddr.ipv6.sin6_port, 2);
+ buf += 2;
+
+ /* Address */
+ pj_memcpy(buf, &ca->sockaddr.ipv6.sin6_addr, 16);
+ buf += 16;
+ }
+
+ pj_assert(buf - start_buf == ATTR_LEN);
+
+ } else {
+ return PJNATH_EINVAF;
+ }
/* Done */
*printed = buf - start_buf;
@@ -1040,11 +1189,14 @@ PJ_DEF(pj_status_t) pj_stun_msg_add_string_attr(pj_pool_t *pool,
static pj_status_t decode_string_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
+ const pj_stun_msg_hdr *msghdr,
void **p_attr)
{
pj_stun_string_attr *attr;
pj_str_t value;
+ PJ_UNUSED_ARG(msghdr);
+
/* Create the attribute */
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_string_attr);
GETATTRHDR(buf, &attr->hdr);
@@ -1065,13 +1217,17 @@ static pj_status_t decode_string_attr(pj_pool_t *pool,
static pj_status_t encode_string_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed)
+ unsigned len,
+ const pj_stun_msg_hdr *msghdr,
+ unsigned *printed)
{
const pj_stun_string_attr *ca =
(const pj_stun_string_attr*)a;
PJ_CHECK_STACK();
+ PJ_UNUSED_ARG(msghdr);
+
/* Calculated total attr_len (add padding if necessary) */
*printed = (ca->value.slen + ATTR_HDR_LEN + 3) & (~3);
if (len < *printed) {
@@ -1154,10 +1310,13 @@ PJ_DEF(pj_status_t) pj_stun_msg_add_empty_attr( pj_pool_t *pool,
static pj_status_t decode_empty_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
+ const pj_stun_msg_hdr *msghdr,
void **p_attr)
{
pj_stun_empty_attr *attr;
+ PJ_UNUSED_ARG(msghdr);
+
/* Check that the struct address is valid */
pj_assert(sizeof(pj_stun_empty_attr) == ATTR_HDR_LEN);
@@ -1177,10 +1336,14 @@ static pj_status_t decode_empty_attr(pj_pool_t *pool,
static pj_status_t encode_empty_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed)
+ unsigned len,
+ const pj_stun_msg_hdr *msghdr,
+ unsigned *printed)
{
const pj_stun_empty_attr *ca = (pj_stun_empty_attr*)a;
+ PJ_UNUSED_ARG(msghdr);
+
if (len < ATTR_HDR_LEN)
return PJ_ETOOSMALL;
@@ -1247,10 +1410,13 @@ PJ_DEF(pj_status_t) pj_stun_msg_add_uint_attr(pj_pool_t *pool,
static pj_status_t decode_uint_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
+ const pj_stun_msg_hdr *msghdr,
void **p_attr)
{
pj_stun_uint_attr *attr;
+ PJ_UNUSED_ARG(msghdr);
+
/* Create the attribute */
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_uint_attr);
GETATTRHDR(buf, &attr->hdr);
@@ -1269,11 +1435,15 @@ static pj_status_t decode_uint_attr(pj_pool_t *pool,
static pj_status_t encode_uint_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed)
+ unsigned len,
+ const pj_stun_msg_hdr *msghdr,
+ unsigned *printed)
{
const pj_stun_uint_attr *ca = (const pj_stun_uint_attr*)a;
PJ_CHECK_STACK();
+
+ PJ_UNUSED_ARG(msghdr);
if (len < 8)
return PJ_ETOOSMALL;
@@ -1343,10 +1513,13 @@ PJ_DEF(pj_status_t) pj_stun_msg_add_uint64_attr(pj_pool_t *pool,
static pj_status_t decode_uint64_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
+ const pj_stun_msg_hdr *msghdr,
void **p_attr)
{
pj_stun_uint64_attr *attr;
+ PJ_UNUSED_ARG(msghdr);
+
/* Create the attribute */
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_uint64_attr);
GETATTRHDR(buf, &attr->hdr);
@@ -1364,11 +1537,15 @@ static pj_status_t decode_uint64_attr(pj_pool_t *pool,
static pj_status_t encode_uint64_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed)
+ unsigned len,
+ const pj_stun_msg_hdr *msghdr,
+ unsigned *printed)
{
const pj_stun_uint64_attr *ca = (const pj_stun_uint64_attr*)a;
PJ_CHECK_STACK();
+
+ PJ_UNUSED_ARG(msghdr);
if (len < 12)
return PJ_ETOOSMALL;
@@ -1433,10 +1610,13 @@ PJ_DEF(pj_status_t) pj_stun_msg_add_msgint_attr(pj_pool_t *pool,
static pj_status_t decode_msgint_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
+ const pj_stun_msg_hdr *msghdr,
void **p_attr)
{
pj_stun_msgint_attr *attr;
+ PJ_UNUSED_ARG(msghdr);
+
/* Create attribute */
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_msgint_attr);
GETATTRHDR(buf, &attr->hdr);
@@ -1455,12 +1635,16 @@ static pj_status_t decode_msgint_attr(pj_pool_t *pool,
static pj_status_t encode_msgint_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed)
+ unsigned len,
+ const pj_stun_msg_hdr *msghdr,
+ unsigned *printed)
{
const pj_stun_msgint_attr *ca = (const pj_stun_msgint_attr*)a;
PJ_CHECK_STACK();
+ PJ_UNUSED_ARG(msghdr);
+
if (len < 24)
return PJ_ETOOSMALL;
@@ -1544,11 +1728,14 @@ PJ_DEF(pj_status_t) pj_stun_msg_add_errcode_attr(pj_pool_t *pool,
static pj_status_t decode_errcode_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
+ const pj_stun_msg_hdr *msghdr,
void **p_attr)
{
pj_stun_errcode_attr *attr;
pj_str_t value;
+ PJ_UNUSED_ARG(msghdr);
+
/* Create the attribute */
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_errcode_attr);
GETATTRHDR(buf, &attr->hdr);
@@ -1570,13 +1757,17 @@ static pj_status_t decode_errcode_attr(pj_pool_t *pool,
static pj_status_t encode_errcode_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed)
+ unsigned len,
+ const pj_stun_msg_hdr *msghdr,
+ unsigned *printed)
{
const pj_stun_errcode_attr *ca =
(const pj_stun_errcode_attr*)a;
PJ_CHECK_STACK();
+ PJ_UNUSED_ARG(msghdr);
+
if (len < ATTR_HDR_LEN + 4 + (unsigned)ca->reason.slen)
return PJ_ETOOSMALL;
@@ -1672,12 +1863,15 @@ PJ_DEF(pj_status_t) pj_stun_msg_add_unknown_attr(pj_pool_t *pool,
static pj_status_t decode_unknown_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
+ const pj_stun_msg_hdr *msghdr,
void **p_attr)
{
pj_stun_unknown_attr *attr;
const pj_uint16_t *punk_attr;
unsigned i;
+ PJ_UNUSED_ARG(msghdr);
+
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_unknown_attr);
GETATTRHDR(buf, &attr->hdr);
@@ -1698,7 +1892,9 @@ static pj_status_t decode_unknown_attr(pj_pool_t *pool,
static pj_status_t encode_unknown_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed)
+ unsigned len,
+ const pj_stun_msg_hdr *msghdr,
+ unsigned *printed)
{
const pj_stun_unknown_attr *ca = (const pj_stun_unknown_attr*) a;
pj_uint16_t *dst_unk_attr;
@@ -1706,6 +1902,8 @@ static pj_status_t encode_unknown_attr(const void *a, pj_uint8_t *buf,
PJ_CHECK_STACK();
+ PJ_UNUSED_ARG(msghdr);
+
/* Check that buffer is enough */
if (len < ATTR_HDR_LEN + (ca->attr_count << 1))
return PJ_ETOOSMALL;
@@ -1807,10 +2005,13 @@ PJ_DEF(pj_status_t) pj_stun_msg_add_binary_attr(pj_pool_t *pool,
static pj_status_t decode_binary_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
+ const pj_stun_msg_hdr *msghdr,
void **p_attr)
{
pj_stun_binary_attr *attr;
+ PJ_UNUSED_ARG(msghdr);
+
/* Create the attribute */
attr = PJ_POOL_ZALLOC_T(pool, pj_stun_binary_attr);
GETATTRHDR(buf, &attr->hdr);
@@ -1829,12 +2030,16 @@ static pj_status_t decode_binary_attr(pj_pool_t *pool,
static pj_status_t encode_binary_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed)
+ unsigned len,
+ const pj_stun_msg_hdr *msghdr,
+ unsigned *printed)
{
const pj_stun_binary_attr *ca = (const pj_stun_binary_attr*)a;
PJ_CHECK_STACK();
+ PJ_UNUSED_ARG(msghdr);
+
/* Calculated total attr_len (add padding if necessary) */
*printed = (ca->length + ATTR_HDR_LEN + 3) & (~3);
if (len < *printed)
@@ -2220,7 +2425,7 @@ PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
err_msg2[PJ_ERR_MSG_SIZE];
/* Parse the attribute */
- status = (adesc->decode_attr)(pool, pdu, &attr);
+ status = (adesc->decode_attr)(pool, pdu, &msg->hdr, &attr);
if (status != PJ_SUCCESS) {
pj_strerror(status, err_msg1, sizeof(err_msg1));
@@ -2408,13 +2613,15 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
adesc = find_attr_desc(attr_hdr->type);
if (adesc) {
- status = adesc->encode_attr(attr_hdr, buf, buf_size, &printed);
+ status = adesc->encode_attr(attr_hdr, buf, buf_size, &msg->hdr,
+ &printed);
} else {
/* This may be a generic attribute */
const pj_stun_binary_attr *bin_attr = (const pj_stun_binary_attr*)
attr_hdr;
PJ_ASSERT_RETURN(bin_attr->magic == PJ_STUN_MAGIC, PJ_EBUG);
- status = encode_binary_attr(bin_attr, buf, buf_size, &printed);
+ status = encode_binary_attr(bin_attr, buf, buf_size, &msg->hdr,
+ &printed);
}
if (status != PJ_SUCCESS)
@@ -2519,7 +2726,7 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
/* Put this attribute in the message */
status = encode_msgint_attr(amsgint, buf, buf_size,
- &printed);
+ &msg->hdr, &printed);
if (status != PJ_SUCCESS)
return status;
@@ -2541,7 +2748,7 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
/* Put this attribute in the message */
status = encode_uint_attr(afingerprint, buf, buf_size,
- &printed);
+ &msg->hdr, &printed);
if (status != PJ_SUCCESS)
return status;