Exemple #1
0
/**
 * Add TURN Permission for a peer
 *
 * @param turnc TURN Client
 * @param peer  Peer IP-address
 * @param ph    Permission handler
 * @param arg   Handler argument
 *
 * @return 0 if success, otherwise errorcode
 */
int turnc_add_perm(struct turnc *turnc, const struct sa *peer,
		   turnc_perm_h *ph, void *arg)
{
	struct perm *perm;
	int err;

	if (!turnc || !peer)
		return EINVAL;

	if (perm_find(turnc, peer))
		return 0;

	perm = mem_zalloc(sizeof(*perm), destructor);
	if (!perm)
		return ENOMEM;

	hash_append(turnc->perms, sa_hash(peer, SA_ADDR), &perm->he, perm);
	tmr_init(&perm->tmr);
	perm->peer = *peer;
	perm->turnc = turnc;
	perm->ph = ph;
	perm->arg = arg;

	err = createperm_request(perm, true);
	if (err)
		mem_deref(perm);

	return err;
}
Exemple #2
0
static bool raw_handler(int proto, const struct sa *src,
			const struct sa *dst, struct mbuf *mb)
{
	struct allocation *al;
	uint16_t numb, len;
	struct perm *perm;
	struct chan *chan;
	int err;

	al = allocation_find(proto, src, dst);
	if (!al)
		return false;

	if (mbuf_get_left(mb) < 4)
		return false;

	numb = ntohs(mbuf_read_u16(mb));
	len  = ntohs(mbuf_read_u16(mb));

	if (mbuf_get_left(mb) < len)
		return false;


    // strip any optional padding
    if (len != mbuf_get_left(mb))
        mbuf_set_end(mb, mb->pos + len);

	chan = chan_numb_find(al->chans, numb);
	if (!chan)
		return false;

	perm = perm_find(al->perms, chan_peer(chan));
	if (!perm) {
		++al->dropc_tx;
		return false;
	}

	err = udp_send(al->rel_us, chan_peer(chan), mb);
	if (err)
		turnd.errc_tx++;
	else {
		const size_t bytes = mbuf_get_left(mb);

		perm_tx_stat(perm, bytes);
		turnd.bytec_tx += bytes;
	}

	return true;
}
Exemple #3
0
static bool indication_handler(struct restund_msgctx *ctx, int proto,
			       void *sock, const struct sa *src,
			       const struct sa *dst,
			       const struct stun_msg *msg)
{
	struct stun_attr *data, *peer;
	struct allocation *al;
	struct perm *perm;
	int err;
	(void)sock;
	(void)ctx;

	if (stun_msg_method(msg) != STUN_METHOD_SEND)
		return false;

	if (ctx->ua.typec > 0)
		return true;

	al = allocation_find(proto, src, dst);
	if (!al)
		return true;

	peer = stun_msg_attr(msg, STUN_ATTR_XOR_PEER_ADDR);
	data = stun_msg_attr(msg, STUN_ATTR_DATA);

	if (!peer || !data)
		return true;

	perm = perm_find(al->perms, &peer->v.xor_peer_addr);
	if (!perm) {
		++al->dropc_tx;
		return true;
	}

	err = udp_send(al->rel_us, &peer->v.xor_peer_addr, &data->v.data);
	if (err)
		turnd.errc_tx++;
	else {
		const size_t bytes = mbuf_get_left(&data->v.data);

		perm_tx_stat(perm, bytes);
		turnd.bytec_tx += bytes;
	}

	return true;
}
Exemple #4
0
void chanbind_request(struct allocation *al, struct restund_msgctx *ctx,
		      int proto, void *sock, const struct sa *src,
		      const struct stun_msg *msg)
{
	struct chan *chan = NULL, *ch_numb = NULL, *ch_peer;
	struct perm *perm = NULL, *permx = NULL;
	struct stun_attr *chnr, *peer;
	int err = ENOMEM, rerr;

	chnr = stun_msg_attr(msg, STUN_ATTR_CHANNEL_NUMBER);
	peer = stun_msg_attr(msg, STUN_ATTR_XOR_PEER_ADDR);

	if (!chnr || !chan_numb_valid(chnr->v.channel_number) || !peer) {
		restund_info("turn: bad chanbind attributes\n");
		rerr = stun_ereply(proto, sock, src, 0, msg,
				   400, "Bad Attributes",
				   ctx->key, ctx->keylen, ctx->fp, 1,
				   STUN_ATTR_SOFTWARE, restund_software);
		goto out;
	}

	if (sa_af(&peer->v.xor_peer_addr) != sa_af(&al->rel_addr)) {
		restund_info("turn: chanbind peer address family mismatch\n");
		rerr = stun_ereply(proto, sock, src, 0, msg,
				   443, "Peer Address Family Mismatch",
				   ctx->key, ctx->keylen, ctx->fp, 1,
				   STUN_ATTR_SOFTWARE, restund_software);
		goto out;
	}

	ch_numb = chan_numb_find(al->chans, chnr->v.channel_number);
	ch_peer = chan_peer_find(al->chans, &peer->v.xor_peer_addr);

	if (ch_numb != ch_peer) {
		restund_info("turn: channel %p/peer %p already bound\n",
			     ch_numb, ch_peer);
		rerr = stun_ereply(proto, sock, src, 0, msg,
				   400, "Channel/Peer Already Bound",
				   ctx->key, ctx->keylen, ctx->fp, 1,
				   STUN_ATTR_SOFTWARE, restund_software);
		goto out;
	}

	if (!ch_numb) {
		chan = chan_create(al->chans, chnr->v.channel_number,
				   &peer->v.xor_peer_addr, al);
		if (!chan) {
			restund_info("turn: unable to create channel\n");
			rerr = stun_ereply(proto, sock, src, 0, msg,
					  500, "Server Error",
					  ctx->key, ctx->keylen, ctx->fp, 1,
					  STUN_ATTR_SOFTWARE,restund_software);
			goto out;
		}
	}

	permx = perm_find(al->perms, &peer->v.xor_peer_addr);
	if (!permx) {
		perm = perm_create(al->perms, &peer->v.xor_peer_addr, al);
		if (!perm) {
			restund_info("turn: unable to create permission\n");
			rerr = stun_ereply(proto, sock, src, 0, msg,
					  500, "Server Error",
					  ctx->key, ctx->keylen, ctx->fp, 1,
					  STUN_ATTR_SOFTWARE,restund_software);
			goto out;
		}
	}

	err = rerr = stun_reply(proto, sock, src, 0, msg,
				ctx->key, ctx->keylen, ctx->fp, 1,
				STUN_ATTR_SOFTWARE, restund_software);
 out:
	if (rerr)
		restund_warning("turn: chanbind reply: %m\n", rerr);

	if (err) {
		mem_deref(chan);
		mem_deref(perm);
	}
	else {
		chan_refresh(ch_numb);
		perm_refresh(permx);
	}
}