Example #1
0
int icem_stund_recv(struct icem_comp *comp, const struct sa *src,
		    struct stun_msg *req, size_t presz)
{
	struct icem *icem = comp->icem;
	struct ice *ice = icem->ice;
	struct stun_attr *attr;
	struct pl lu, ru;
	enum role rrole = ROLE_UNKNOWN;
	uint64_t tiebrk = 0;
	uint32_t prio_prflx;
	bool use_cand = false;
	int err;

	/* RFC 5389: Fingerprint errors are silently discarded */
	err = stun_msg_chk_fingerprint(req);
	if (err)
		return err;

	err = stun_msg_chk_mi(req, (uint8_t *)ice->lpwd, strlen(ice->lpwd));
	if (err) {
		if (err == EBADMSG)
			goto unauth;
		else
			goto badmsg;
	}

	attr = stun_msg_attr(req, STUN_ATTR_USERNAME);
	if (!attr)
		goto badmsg;

	err = re_regex(attr->v.username, strlen(attr->v.username),
		       "[^:]+:[^]+", &lu, &ru);
	if (err) {
		DEBUG_WARNING("could not parse USERNAME attribute (%s)\n",
			      attr->v.username);
		goto unauth;
	}
	if (pl_strcmp(&lu, ice->lufrag))
		goto unauth;
	if (str_isset(icem->rufrag) && pl_strcmp(&ru, icem->rufrag))
		goto unauth;

	attr = stun_msg_attr(req, STUN_ATTR_CONTROLLED);
	if (attr) {
		rrole = ROLE_CONTROLLED;
		tiebrk = attr->v.uint64;
	}

	attr = stun_msg_attr(req, STUN_ATTR_CONTROLLING);
	if (attr) {
		rrole = ROLE_CONTROLLING;
		tiebrk = attr->v.uint64;
	}

	if (rrole == ice->lrole) {
		if (ice->tiebrk >= tiebrk)
			ice_switch_local_role(ice);
		else
			goto conflict;
	}

	attr = stun_msg_attr(req, STUN_ATTR_PRIORITY);
	if (attr)
		prio_prflx = attr->v.uint32;
	else
		goto badmsg;

	attr = stun_msg_attr(req, STUN_ATTR_USE_CAND);
	if (attr)
		use_cand = true;

	err = handle_stun(ice, icem, comp, src, prio_prflx,
			  use_cand, presz > 0);
	if (err)
		goto badmsg;

	return stun_reply(icem->proto, comp->sock, src, presz, req,
			  (uint8_t *)ice->lpwd, strlen(ice->lpwd), true, 2,
			  STUN_ATTR_XOR_MAPPED_ADDR, src,
			  STUN_ATTR_SOFTWARE, sw);

 badmsg:
	return stunsrv_ereply(comp, src, presz, req, 400, "Bad Request");

 unauth:
	return stunsrv_ereply(comp, src, presz, req, 401, "Unauthorized");

 conflict:
	return stunsrv_ereply(comp, src, presz, req, 487, "Role Conflict");
}
int trice_stund_recv(struct trice *icem, struct ice_lcand *lcand,
		    void *sock, const struct sa *src,
		    struct stun_msg *req, size_t presz)
{
	struct stun_attr *attr;
	struct pl lu, ru;
	bool remote_controlling;
	uint64_t tiebrk = 0;
	uint32_t prio_prflx;
	bool use_cand = false;
	int err;

	/* RFC 5389: Fingerprint errors are silently discarded */
	err = stun_msg_chk_fingerprint(req);
	if (err)
		return err;

	err = stun_msg_chk_mi(req, (uint8_t *)icem->lpwd, strlen(icem->lpwd));
	if (err) {
		DEBUG_WARNING("message-integrity failed (src=%J)\n", src);
		if (err == EBADMSG)
			goto unauth;
		else
			goto badmsg;
	}

	attr = stun_msg_attr(req, STUN_ATTR_USERNAME);
	if (!attr)
		goto badmsg;

	err = re_regex(attr->v.username, strlen(attr->v.username),
		       "[^:]+:[^]+", &lu, &ru);
	if (err) {
		DEBUG_WARNING("could not parse USERNAME attribute (%s)\n",
			      attr->v.username);
		goto unauth;
	}
	if (pl_strcmp(&lu, icem->lufrag)) {
		DEBUG_WARNING("local ufrag err (expected %s, actual %r)\n",
			      icem->lufrag, &lu);
		goto unauth;
	}
	if (str_isset(icem->rufrag) && pl_strcmp(&ru, icem->rufrag)) {
		DEBUG_WARNING("remote ufrag err (expected %s, actual %r)\n",
			      icem->rufrag, &ru);
		goto unauth;
	}

	attr = stun_msg_attr(req, STUN_ATTR_CONTROLLED);
	if (attr) {
		remote_controlling = false;
		tiebrk = attr->v.uint64;
	}

	attr = stun_msg_attr(req, STUN_ATTR_CONTROLLING);
	if (attr) {
		remote_controlling = true;
		tiebrk = attr->v.uint64;
	}

	if (remote_controlling == icem->controlling) {
		if (icem->tiebrk >= tiebrk)
			trice_switch_local_role(icem);
		else
			goto conflict;
	}

	attr = stun_msg_attr(req, STUN_ATTR_PRIORITY);
	if (attr)
		prio_prflx = attr->v.uint32;
	else
		goto badmsg;

	attr = stun_msg_attr(req, STUN_ATTR_USE_CAND);
	if (attr)
		use_cand = true;

	err = handle_stun_full(icem, lcand, sock, src, prio_prflx, use_cand);

	if (err)
		goto badmsg;

	trice_tracef(icem, 32,
		     "[%u] STUNSRV: Tx success respons [%H ---> %J]\n",
		     lcand->attr.compid,
		     trice_cand_print, lcand, src);

	return stun_reply(lcand->attr.proto, sock, src, presz, req,
			  (uint8_t *)icem->lpwd, strlen(icem->lpwd), true, 2,
			  STUN_ATTR_XOR_MAPPED_ADDR, src,
			  STUN_ATTR_SOFTWARE, icem->sw ? icem->sw : sw);


 badmsg:
	return stunsrv_ereply(icem, lcand, sock, src, presz, req,
			      400, "Bad Request");

 unauth:
	return stunsrv_ereply(icem, lcand, sock, src, presz, req,
			      401, "Unauthorized");

 conflict:
	return stunsrv_ereply(icem, lcand, sock, src, presz, req,
			      487, "Role Conflict");
}