Ejemplo n.º 1
0
int ice_cand_attr_encode(struct re_printf *pf,
			 const struct ice_cand_attr *cand)
{
	int err = 0;

	if (!cand)
		return 0;

	err |= re_hprintf(pf, "%s %u %s %u %j %u typ %s",
			  cand->foundation, cand->compid,
			  net_proto2name(cand->proto), cand->prio,
			  &cand->addr, sa_port(&cand->addr),
			  ice_cand_type2name(cand->type));

	if (sa_isset(&cand->rel_addr, SA_ADDR))
		err |= re_hprintf(pf, " raddr %j", &cand->rel_addr);

	if (sa_isset(&cand->rel_addr, SA_PORT))
		err |= re_hprintf(pf, " rport %u", sa_port(&cand->rel_addr));

	if (cand->proto == IPPROTO_TCP) {
		err |= re_hprintf(pf, " tcptype %s",
				  ice_tcptype_name(cand->tcptype));
	}

	return err;
}
Ejemplo n.º 2
0
static bool allocation_status(struct le *le, void *arg)
{
	const uint32_t bsize = hash_bsize(turnd.ht_alloc);
	struct allocation *al = le->data;
	struct mbuf *mb = arg;

	(void)mbuf_printf(mb,
			  "- %04u %s/%J/%J - %J \"%s\" %us (drop %llu/%llu)\n",
			  sa_hash(&al->cli_addr, SA_ALL) & (bsize - 1),
			  net_proto2name(al->proto), &al->cli_addr,
			  &al->srv_addr, &al->rel_addr, al->username,
			  (uint32_t)tmr_get_expire(&al->tmr) / 1000,
			  al->dropc_tx, al->dropc_rx);

	perm_status(al->perms, mb);
	chan_status(al->chans, mb);

	return false;
}
Ejemplo n.º 3
0
static void stun_mapped_handler(int err, const struct sa *map, void *arg)
{
	struct candidate *cand = arg;
	struct ice_lcand *lcand=0, *base = cand->base;
	uint32_t prio;

	if (err) {
		re_printf("STUN Request failed: (%m)\n",
			  err);
		goto out;
	}

	re_printf("adding SRFLX candidate %s.%J\n",
		  net_proto2name(base->attr.proto), map);

	prio = calc_prio(ICE_CAND_TYPE_SRFLX, base->attr.proto,
			 base->attr.tcptype, sa_af(&base->attr.addr),
			 base->attr.proto);

	err = trice_lcand_add(&lcand, base->icem, base->attr.compid,
			      base->attr.proto, prio, map,
			      &base->attr.addr, ICE_CAND_TYPE_SRFLX,
			      &base->attr.addr,
			      base->attr.tcptype, NULL, 0);
	if (err) {
		re_fprintf(stderr, "failed to add SRFLX candidate (%m)\n",
			   err);
		goto out;
	}

	err = control_send_message(cand->ag->cli, "a=candidate:%H\r\n",
				   ice_cand_attr_encode, &lcand->attr);
	if (err)
		goto out;

 out:
	candidate_done(cand);
}
Ejemplo n.º 4
0
static void turnc_handler(int err, uint16_t scode, const char *reason,
			  const struct sa *relay_addr,
			  const struct sa *mapped_addr,
			  const struct stun_msg *msg,
			  void *arg)
{
	struct candidate *cand = arg;
	struct ice_lcand *lcand_relay=0, *lcand_srflx=0, *base = cand->base;
	uint32_t prio;

	if (err || scode) {
		re_printf("TURN client error: %u %s (%m)\n",
			  scode, reason, err);
		goto out;
	}

	/* check if the relayed address is of the same Address Family
	 * as the base candidate */
	if (sa_af(relay_addr) != sa_af(&base->attr.addr)) {
		re_printf("could not use RELAY address (AF mismatch)\n");
		goto out;
	}

	if (stun_msg_method(msg) == STUN_METHOD_ALLOCATE) {
		re_printf("TURN allocation okay (turn-proto=%s)\n",
			  net_proto2name(cand->turn_proto));
		cand->turn_ok = true;
	}

	/* RELAY */

	re_printf("adding RELAY candidate %s.%J\n",
		  net_proto2name(base->attr.proto), relay_addr);

	prio = calc_prio(ICE_CAND_TYPE_RELAY, base->attr.proto,
			 base->attr.tcptype, sa_af(&base->attr.addr),
			 cand->turn_proto);

	err = trice_lcand_add(&lcand_relay, base->icem,
			      base->attr.compid,
			      base->attr.proto, prio, relay_addr,
			      relay_addr, ICE_CAND_TYPE_RELAY,
			      mapped_addr,
			      base->attr.tcptype, base->us,
			      LAYER_ICE);
	if (err) {
		re_fprintf(stderr, "failed to add RELAY candidate (%m)\n",
			   err);
		goto out;
	}

	if (cand->turn_proto == IPPROTO_TCP) {

		/* NOTE: this is needed to snap up outgoing UDP-packets */

		err = udp_register_helper(&cand->uh_turntcp,
					  lcand_relay->us,
					  LAYER_TURN,
					  turntcp_send_handler,
					  NULL,
					  cand);
		if (err) {
			re_printf("helper error\n");
			goto out;
		}
	}

	/* SRFLX */
	if (cand->turn_proto == base->attr.proto) {
		re_printf("adding SRFLX candidate %s.%J\n",
			  net_proto2name(base->attr.proto), mapped_addr);

		prio = calc_prio(ICE_CAND_TYPE_SRFLX, base->attr.proto,
				 base->attr.tcptype, sa_af(&base->attr.addr),
				 base->attr.proto);

		err = trice_lcand_add(&lcand_srflx, base->icem,
				      base->attr.compid,
				      base->attr.proto, prio,
				      mapped_addr, &base->attr.addr,
				      ICE_CAND_TYPE_SRFLX,
				      &base->attr.addr,
				      base->attr.tcptype,
				      NULL, LAYER_ICE);
		if (err) {
			re_fprintf(stderr, "failed to add SRFLX"
				   " candidate (%m)\n",
				   err);
			goto out;
		}
	}

	err = control_send_message(cand->ag->cli,
				   "a=candidate:%H\r\n"
				   "a=candidate:%H\r\n"
				   ,
				   ice_cand_attr_encode, &lcand_relay->attr,
				   ice_cand_attr_encode,
				   lcand_srflx ? &lcand_srflx->attr : 0);
	if (err)
		goto out;

	candidate_add_permissions(cand);

 out:
	candidate_done(cand);
}
Ejemplo n.º 5
0
static void process_msg(struct turnserver *turn, int proto, void *sock,
			const struct sa *src, struct mbuf *mb)
{
	struct stun_msg *msg = NULL;
	struct sa laddr;
	int err = 0;

	if (stun_msg_decode(&msg, mb, NULL)) {

		uint16_t numb, len;
		struct channel *chan;

		if (!turn->us_relay)
			return;

		++turn->n_raw;

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

		if (mbuf_get_left(mb) < len) {
			DEBUG_WARNING("short length: %zu < %u\n",
				      mbuf_get_left(mb), len);
		}

		chan = find_channel_numb(turn, numb);
		if (!chan) {
			DEBUG_WARNING("channel not found: numb=%u\n", numb);
			return;
		}

		/* relay data from channel to peer */
		(void)udp_send(turn->us_relay, &chan->peer, mb);
		return;
	}

#if 0
	re_printf("process: %s:%p:%J %s\n",
		  net_proto2name(proto), sock, src,
		  stun_method_name(stun_msg_method(msg)));
#endif

	switch (stun_msg_method(msg)) {

	case STUN_METHOD_ALLOCATE:
		/* Max 1 allocation for now */
		++turn->n_allocate;

		if (turn->us_relay) {
			err = EALREADY;
			goto out;
		}

		turn->cli = *src;

		err = sa_set_str(&laddr, "127.0.0.1", 0);
		if (err)
			goto out;

		err = udp_listen(&turn->us_relay, &laddr,
				 relay_udp_recv, turn);
		if (err)
			goto out;

		err = udp_local_get(turn->us_relay, &turn->relay);
		if (err)
			goto out;

		udp_rxbuf_presz_set(turn->us_relay, 4);

		err = stun_reply(proto, sock, src, 0,
				 msg, NULL, 0, false,
				 2,
				 STUN_ATTR_XOR_MAPPED_ADDR, src,
				 STUN_ATTR_XOR_RELAY_ADDR, &turn->relay);
		break;

	case STUN_METHOD_CREATEPERM: {
		struct stun_attr *peer;

		++turn->n_createperm;

		peer = stun_msg_attr(msg, STUN_ATTR_XOR_PEER_ADDR);
		TEST_ASSERT(peer != NULL);

		add_permission(turn, &peer->v.xor_peer_addr);

		/* todo: install permissions and check them */
		err = stun_reply(proto, sock, src, 0,
				 msg, NULL, 0, false,
				 0);
	}
		break;

	case STUN_METHOD_CHANBIND: {
		struct stun_attr *chnr, *peer;

		++turn->n_chanbind;

		TEST_ASSERT(turn->us_relay != NULL);

		chnr = stun_msg_attr(msg, STUN_ATTR_CHANNEL_NUMBER);
		peer = stun_msg_attr(msg, STUN_ATTR_XOR_PEER_ADDR);
		if (!chnr || !peer) {
			DEBUG_WARNING("CHANBIND: missing chnr/peer attrib\n");
		}

		TEST_ASSERT(turn->chanc < ARRAY_SIZE(turn->chanv));
		turn->chanv[turn->chanc].nr   = chnr->v.channel_number;
		turn->chanv[turn->chanc].peer = peer->v.xor_peer_addr;
		++turn->chanc;

		err = stun_reply(proto, sock, src, 0,
				 msg, NULL, 0, false,
				 0);
	}
		break;

	case STUN_METHOD_SEND: {
		struct stun_attr *peer, *data;

		++turn->n_send;

		TEST_ASSERT(turn->us_relay != NULL);

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

		if (!peer || !data) {
			DEBUG_WARNING("SEND: missing peer/data attrib\n");
			goto out;
		}

		/* check for valid Permission */
		if (!find_permission(turn, &peer->v.xor_peer_addr)) {
			DEBUG_NOTICE("no permission to peer %j\n",
				     &peer->v.xor_peer_addr);
			goto out;
		}

		err = udp_send(turn->us_relay, &peer->v.xor_peer_addr,
			       &data->v.data);
	}
		break;

	default:
		DEBUG_WARNING("unknown STUN method: %s\n",
			      stun_method_name(stun_msg_method(msg)));
		err = EPROTO;
		break;
	}

	if (err)
		goto out;

 out:
	if (err && stun_msg_class(msg) == STUN_CLASS_REQUEST) {
		(void)stun_ereply(proto, sock, src, 0, msg,
				  500, "Server Error",
				  NULL, 0, false, 0);
	}

	mem_deref(msg);
}