예제 #1
0
파일: stunsrv.c 프로젝트: singalen/libre
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;

    if (ice->lmode == ICE_MODE_FULL) {
        err = handle_stun_full(ice, icem, comp, src, prio_prflx,
                               use_cand, presz > 0);
    }
    else {
        err = handle_stun_lite(icem, comp, src, use_cand);
    }

    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");
}