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