diff options
author | Benny Prijono <bennylp@teluu.com> | 2009-04-07 09:42:58 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2009-04-07 09:42:58 +0000 |
commit | 125315337f4e0df235bcf2e0d388db32493cca3f (patch) | |
tree | 0ad75b40756a4bc9ea5d657bc9a8a101f641cfdc /pjnath/src | |
parent | 350d6756668b62617ac3169ee10148199fab4037 (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/src')
-rw-r--r-- | pjnath/src/pjnath-test/stun.c | 110 | ||||
-rw-r--r-- | pjnath/src/pjnath/errno.c | 1 | ||||
-rw-r--r-- | pjnath/src/pjnath/stun_msg.c | 365 |
3 files changed, 383 insertions, 93 deletions
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; |