blob: 812942a4fe7ab492f844f118f323c05f17aa224d [file] [log] [blame]
/**
* @file stun/addr.c STUN Address encoding
*
* Copyright (C) 2010 Creytiv.com
*/
#include <re_types.h>
#include <re_mbuf.h>
#include <re_sa.h>
#include <re_list.h>
#include <re_stun.h>
#include "stun.h"
static void in6_xor_tid(uint8_t *in6, const uint8_t *tid)
{
int i;
/* XOR with Magic Cookie (alignment safe) */
in6[0] ^= 0x21;
in6[1] ^= 0x12;
in6[2] ^= 0xa4;
in6[3] ^= 0x42;
for (i=0; i<STUN_TID_SIZE; i++)
in6[4+i] ^= tid[i];
}
int stun_addr_encode(struct mbuf *mb, const struct sa *addr,
const uint8_t *tid)
{
#ifdef HAVE_INET6
uint8_t addr6[16];
#endif
uint16_t port;
uint32_t addr4;
int err = 0;
if (!mb || !addr)
return EINVAL;
port = tid ? sa_port(addr)^(STUN_MAGIC_COOKIE>>16) : sa_port(addr);
switch (sa_af(addr)) {
case AF_INET:
addr4 = tid ? sa_in(addr)^STUN_MAGIC_COOKIE : sa_in(addr);
err |= mbuf_write_u8(mb, 0);
err |= mbuf_write_u8(mb, STUN_AF_IPv4);
err |= mbuf_write_u16(mb, htons(port));
err |= mbuf_write_u32(mb, htonl(addr4));
break;
#ifdef HAVE_INET6
case AF_INET6:
sa_in6(addr, addr6);
if (tid)
in6_xor_tid(addr6, tid);
err |= mbuf_write_u8(mb, 0);
err |= mbuf_write_u8(mb, STUN_AF_IPv6);
err |= mbuf_write_u16(mb, htons(port));
err |= mbuf_write_mem(mb, addr6, 16);
break;
#endif
default:
err = EAFNOSUPPORT;
break;
}
return err;
}
int stun_addr_decode(struct mbuf *mb, struct sa *addr, const uint8_t *tid)
{
uint8_t family, addr6[16];
uint32_t addr4;
uint16_t port;
if (!mb || !addr)
return EINVAL;
if (mbuf_get_left(mb) < 4)
return EBADMSG;
(void)mbuf_read_u8(mb);
family = mbuf_read_u8(mb);
port = ntohs(mbuf_read_u16(mb));
if (tid)
port ^= STUN_MAGIC_COOKIE>>16;
switch (family) {
case STUN_AF_IPv4:
if (mbuf_get_left(mb) < 4)
return EBADMSG;
addr4 = ntohl(mbuf_read_u32(mb));
if (tid)
addr4 ^= STUN_MAGIC_COOKIE;
sa_set_in(addr, addr4, port);
break;
case STUN_AF_IPv6:
if (mbuf_get_left(mb) < 16)
return EBADMSG;
(void)mbuf_read_mem(mb, addr6, 16);
if (tid)
in6_xor_tid(addr6, tid);
sa_set_in6(addr, addr6, port);
break;
default:
return EAFNOSUPPORT;
}
return 0;
}