Ejemplo n.º 1
0
static void stun_resp_handler(int err, uint16_t scode, const char *reason,
			      const struct stun_msg *msg, void *arg)
{
	struct test *test = arg;
	struct stun_attr *attr;
	(void)reason;

	if (err)
		goto out;

	++test->n_resp;

	/* verify STUN response */
	TEST_EQUALS(0, scode);
	TEST_EQUALS(0x0101, stun_msg_type(msg));
	TEST_EQUALS(STUN_CLASS_SUCCESS_RESP, stun_msg_class(msg));
	TEST_EQUALS(STUN_METHOD_BINDING, stun_msg_method(msg));
	TEST_EQUALS(0, stun_msg_chk_fingerprint(msg));

	attr = stun_msg_attr(msg, STUN_ATTR_XOR_MAPPED_ADDR);
	TEST_ASSERT(attr != NULL);

	test->mapped_addr = attr->v.sa;

 out:
	if (err)
		test->err = err;

	/* done */
	re_cancel();
}
Ejemplo n.º 2
0
/**
 * Send a STUN response message
 *
 * @param proto   Transport Protocol
 * @param sock    Socket; UDP (struct udp_sock) or TCP (struct tcp_conn)
 * @param dst     Destination network address
 * @param presz   Number of bytes in preamble, if sending over TURN
 * @param req     Matching STUN request
 * @param key     Authentication key (optional)
 * @param keylen  Number of bytes in authentication key
 * @param fp      Use STUN Fingerprint attribute
 * @param attrc   Number of attributes to encode (variable arguments)
 * @param ...     Variable list of attribute-tuples
 *                Each attribute has 2 arguments, attribute type and value
 *
 * @return 0 if success, otherwise errorcode
 */
int stun_reply(int proto, void *sock, const struct sa *dst, size_t presz,
	       const struct stun_msg *req, const uint8_t *key,
	       size_t keylen, bool fp, uint32_t attrc, ...)
{
	struct mbuf *mb = NULL;
	int err = ENOMEM;
	va_list ap;

	if (!sock || !req)
		return EINVAL;

	mb = mbuf_alloc(256);
	if (!mb)
		goto out;

	va_start(ap, attrc);
	mb->pos = presz;
	err = stun_msg_vencode(mb, stun_msg_method(req),
			       STUN_CLASS_SUCCESS_RESP, stun_msg_tid(req),
			       NULL, key, keylen, fp, 0x00, attrc, ap);
	va_end(ap);
	if (err)
		goto out;

	mb->pos = presz;
	err = stun_send(proto, sock, dst, mb);

 out:
	mem_deref(mb);

	return err;
}
Ejemplo n.º 3
0
Archivo: comp.c Proyecto: soramimi/qSIP
static bool helper_recv_handler(struct sa *src, struct mbuf *mb, void *arg)
{
	struct icem_comp *comp = arg;
	struct icem *icem = comp->icem;
	struct stun_msg *msg = NULL;
	struct stun_unknown_attr ua;
	const size_t start = mb->pos;

#if 0
	re_printf("{%d} UDP recv_helper: %u bytes from %J\n",
		  comp->id, mbuf_get_left(mb), src);
#endif

	if (stun_msg_decode(&msg, mb, &ua))
		return false;

	if (STUN_METHOD_BINDING == stun_msg_method(msg)) {

		switch (stun_msg_class(msg)) {

		case STUN_CLASS_REQUEST:
			(void)icem_stund_recv(comp, src, msg, start);
			break;

		default:
			(void)stun_ctrans_recv(icem->ice->stun, msg, &ua);
			break;
		}
	}

	mem_deref(msg);

	return true;  /* handled */
}
Ejemplo n.º 4
0
static void udp_recv_handler(const struct sa *src, struct mbuf *mb, void *arg)
{
	struct sip_transport *transp = arg;
	struct stun_unknown_attr ua;
	struct stun_msg *stun_msg;
	struct sip_msg *msg;
	int err;

	if (mb->end <= 4)
		return;

	if (!stun_msg_decode(&stun_msg, mb, &ua)) {

		if (stun_msg_method(stun_msg) == STUN_METHOD_BINDING) {

			switch (stun_msg_class(stun_msg)) {

			case STUN_CLASS_REQUEST:
				(void)stun_reply(IPPROTO_UDP, transp->sock,
						 src, 0, stun_msg,
						 NULL, 0, false, 2,
						 STUN_ATTR_XOR_MAPPED_ADDR,
						 src,
						 STUN_ATTR_SOFTWARE,
						 transp->sip->software);
				break;

			default:
				(void)stun_ctrans_recv(transp->sip->stun,
						       stun_msg, &ua);
				break;
			}
		}

		mem_deref(stun_msg);

		return;
	}

	err = sip_msg_decode(&msg, mb);
	if (err) {
		(void)re_fprintf(stderr, "sip: msg decode err: %m\n", err);
		return;
	}

	msg->sock = mem_ref(transp->sock);
	msg->src = *src;
	msg->dst = transp->laddr;
	msg->tp = SIP_TRANSP_UDP;

	sip_recv(transp->sip, msg);

	mem_deref(msg);
}
Ejemplo n.º 5
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;
}
Ejemplo n.º 6
0
/* sock = [ struct udp_sock | struct tcp_conn ] */
bool trice_stun_process(struct trice *icem, struct ice_lcand *lcand,
		       int proto, void *sock, const struct sa *src,
		       struct mbuf *mb)
{
	struct stun_msg *msg = NULL;
	struct stun_unknown_attr ua;
	size_t start = mb->pos;
	(void)proto;

	if (stun_msg_decode(&msg, mb, &ua)) {
		return false;  /* continue recv-processing */
	}

	if (STUN_METHOD_BINDING == stun_msg_method(msg)) {

		switch (stun_msg_class(msg)) {

		case STUN_CLASS_REQUEST:
			(void)trice_stund_recv(icem, lcand, sock,
					      src, msg, start);
			break;

		default:
			if (icem->checklist) {
				(void)stun_ctrans_recv(icem->checklist->stun,
						       msg, &ua);
			}
			else {
				DEBUG_NOTICE("STUN resp from %J dropped"
					     " (no checklist)\n",
					     src);
			}
			break;
		}
	}

	mem_deref(msg);

	return true;
}
Ejemplo n.º 7
0
/**
 * Send a STUN error response
 *
 * @param proto   Transport Protocol
 * @param sock    Socket; UDP (struct udp_sock) or TCP (struct tcp_conn)
 * @param dst     Destination network address
 * @param presz   Number of bytes in preamble, if sending over TURN
 * @param req     Matching STUN request
 * @param scode   Status code
 * @param reason  Reason string
 * @param key     Authentication key (optional)
 * @param keylen  Number of bytes in authentication key
 * @param fp      Use STUN Fingerprint attribute
 * @param attrc   Number of attributes to encode (variable arguments)
 * @param ...     Variable list of attribute-tuples
 *                Each attribute has 2 arguments, attribute type and value
 *
 * @return 0 if success, otherwise errorcode
 */
int stun_ereply(int proto, void *sock, const struct sa *dst, size_t presz,
		const struct stun_msg *req, uint16_t scode,
		const char *reason, const uint8_t *key, size_t keylen,
		bool fp, uint32_t attrc, ...)
{
	struct stun_errcode ec;
	struct mbuf *mb = NULL;
	int err = ENOMEM;
	va_list ap;

	if (!sock || !req || !scode || !reason)
		return EINVAL;

	mb = mbuf_alloc(256);
	if (!mb)
		goto out;

	ec.code = scode;
	ec.reason = (char *)reason;

	va_start(ap, attrc);
	mb->pos = presz;
	err = stun_msg_vencode(mb, stun_msg_method(req), STUN_CLASS_ERROR_RESP,
			       stun_msg_tid(req), &ec, key, keylen,
			       fp, 0x00, attrc, ap);
	va_end(ap);
	if (err)
		goto out;

	mb->pos = presz;
	err = stun_send(proto, sock, dst, mb);

 out:
	mem_deref(mb);

	return err;
}
Ejemplo n.º 8
0
static bool udp_recv_handler(struct sa *src, struct mbuf *mb, void *arg)
{
	struct stun_attr *peer, *data;
	struct stun_unknown_attr ua;
	struct turnc *turnc = arg;
	struct stun_msg *msg;
	bool hdld = true;

	if (!sa_cmp(&turnc->srv, src, SA_ALL) &&
	    !sa_cmp(&turnc->psrv, src, SA_ALL))
		return false;

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

		struct chan_hdr hdr;
		struct chan *chan;

		if (turnc_chan_hdr_decode(&hdr, mb))
			return true;

		if (mbuf_get_left(mb) < hdr.len)
			return true;

		chan = turnc_chan_find_numb(turnc, hdr.nr);
		if (!chan)
			return true;

		*src = *turnc_chan_peer(chan);

		return false;
	}

	switch (stun_msg_class(msg)) {

	case STUN_CLASS_INDICATION:
		if (ua.typec > 0)
			break;

		if (stun_msg_method(msg) != STUN_METHOD_DATA)
			break;

		peer = stun_msg_attr(msg, STUN_ATTR_XOR_PEER_ADDR);
		data = stun_msg_attr(msg, STUN_ATTR_DATA);
		if (!peer || !data)
			break;

		*src = peer->v.xor_peer_addr;

		mb->pos = data->v.data.pos;
		mb->end = data->v.data.end;

		hdld = false;
		break;

	case STUN_CLASS_ERROR_RESP:
	case STUN_CLASS_SUCCESS_RESP:
		(void)stun_ctrans_recv(turnc->stun, msg, &ua);
		break;

	default:
		break;
	}

	mem_deref(msg);

	return hdld;
}
Ejemplo n.º 9
0
static bool request_handler(struct restund_msgctx *ctx, int proto, void *sock,
			    const struct sa *src, const struct sa *dst,
			    const struct stun_msg *msg)
{
	const uint16_t met = stun_msg_method(msg);
	struct allocation *al;
	int err = 0;

	switch (met) {

	case STUN_METHOD_ALLOCATE:
	case STUN_METHOD_REFRESH:
	case STUN_METHOD_CREATEPERM:
	case STUN_METHOD_CHANBIND:
		break;

	default:
		return false;
	}

	if (ctx->ua.typec > 0) {
		err = stun_ereply(proto, sock, src, 0, msg,
				  420, "Unknown Attribute",
				  ctx->key, ctx->keylen, ctx->fp, 2,
				  STUN_ATTR_UNKNOWN_ATTR, &ctx->ua,
				  STUN_ATTR_SOFTWARE, restund_software);
		goto out;
	}

	al = allocation_find(proto, src, dst);

	if (!al && met != STUN_METHOD_ALLOCATE) {
		restund_debug("turn: allocation does not exist\n");
		err = stun_ereply(proto, sock, src, 0, msg,
				  437, "Allocation Mismatch",
				  ctx->key, ctx->keylen, ctx->fp, 1,
				  STUN_ATTR_SOFTWARE, restund_software);
		goto out;
	}

	if (al && al->username && ctx->key) {

		struct stun_attr *usr = stun_msg_attr(msg, STUN_ATTR_USERNAME);

		if (!usr || strcmp(usr->v.username, al->username)) {
			restund_debug("turn: wrong credetials\n");
			err = stun_ereply(proto, sock, src, 0, msg,
					  441, "Wrong Credentials",
					  ctx->key, ctx->keylen, ctx->fp, 1,
					  STUN_ATTR_SOFTWARE,restund_software);
			goto out;
		}
	}

	switch (met) {

	case STUN_METHOD_ALLOCATE:
		allocate_request(&turnd, al, ctx, proto, sock, src, dst, msg);
		break;

	case STUN_METHOD_REFRESH:
		refresh_request(&turnd, al, ctx, proto, sock, src, msg);
		break;

	case STUN_METHOD_CREATEPERM:
		createperm_request(al, ctx, proto, sock, src, msg);
		break;

	case STUN_METHOD_CHANBIND:
		chanbind_request(al, ctx, proto, sock, src, msg);
		break;
	}

 out:
	if (err) {
		restund_warning("turn reply error: %m\n", err);
	}

	return true;
}
Ejemplo n.º 10
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.º 11
0
int test_stun_req(void)
{
	struct stun_msg *msg = NULL;
	struct mbuf *mb;
	struct stun_attr *attr;
	int err;

	mb = mbuf_alloc(1024);
	if (!mb) {
		err = ENOMEM;
		goto out;
	}

	err = stun_msg_encode(mb, STUN_METHOD_BINDING, STUN_CLASS_REQUEST,
			      tid, NULL,
			      (uint8_t *)password.p, password.l, true,
			      0x20, 4,
			      STUN_ATTR_SOFTWARE, client_sw,
			      STUN_ATTR_PRIORITY, &ice_prio,
			      STUN_ATTR_CONTROLLED, &ice_contr,
			      STUN_ATTR_USERNAME, username);
	if (err)
		goto out;

	TEST_MEMCMP(req, sizeof(req)-1, mb->buf, mb->end);

	/* Decode STUN message */
	mb->pos = 0;
	err = stun_msg_decode(&msg, mb, NULL);
	if (err)
		goto out;

	if (STUN_CLASS_REQUEST != stun_msg_class(msg))
		goto bad;

	if (STUN_METHOD_BINDING != stun_msg_method(msg))
		goto out;

	err = stun_msg_chk_mi(msg, (uint8_t *)password.p, password.l);
	if (err)
		goto out;

	err = stun_msg_chk_fingerprint(msg);
	if (err)
		goto out;

	attr = stun_msg_attr(msg, STUN_ATTR_PRIORITY);
	if (!attr || ice_prio != attr->v.priority)
		goto bad;

	attr = stun_msg_attr(msg, STUN_ATTR_CONTROLLED);
	if (!attr || ice_contr != attr->v.controlled)
		goto bad;

	attr = stun_msg_attr(msg, STUN_ATTR_USERNAME);
	if (!attr || strcmp(username, attr->v.username))
		goto bad;

	attr = stun_msg_attr(msg, STUN_ATTR_SOFTWARE);
	if (!attr || strcmp(client_sw, attr->v.software))
		goto bad;

	goto out;

 bad:
	err = EBADMSG;

 out:
	mem_deref(msg);
	mem_deref(mb);
	return err;
}
Ejemplo n.º 12
0
static int test_stun_req_attributes(void)
{
	struct stun_msg *msg = NULL;
	struct mbuf *mb;
	struct stun_attr *attr;
	const uint64_t rsv_token = 0x1100c0ffee;
	const uint32_t lifetime = 3600;
	const uint16_t chan = 0x4000;
	const uint8_t req_addr_fam = AF_INET;
	int err;

	mb = mbuf_alloc(1024);
	if (!mb) {
		err = ENOMEM;
		goto out;
	}

	err = stun_msg_encode(mb, STUN_METHOD_BINDING, STUN_CLASS_REQUEST,
			      tid, NULL, NULL, 0, false,
			      0x00, 4,
			      STUN_ATTR_REQ_ADDR_FAMILY, &req_addr_fam,
			      STUN_ATTR_CHANNEL_NUMBER, &chan,
			      STUN_ATTR_LIFETIME, &lifetime,
			      STUN_ATTR_RSV_TOKEN, &rsv_token);
	if (err)
		goto out;

	/* Decode STUN message */
	mb->pos = 0;
	err = stun_msg_decode(&msg, mb, NULL);
	if (err)
		goto out;

	TEST_EQUALS(STUN_CLASS_REQUEST, stun_msg_class(msg));
	TEST_EQUALS(STUN_METHOD_BINDING, stun_msg_method(msg));

	/* verify integer attributes of different sizes */

	/* 8-bit */
	attr = stun_msg_attr(msg, STUN_ATTR_REQ_ADDR_FAMILY);
	TEST_ASSERT(attr != NULL);
	TEST_EQUALS(req_addr_fam, attr->v.req_addr_family);

	/* 16-bit */
	attr = stun_msg_attr(msg, STUN_ATTR_CHANNEL_NUMBER);
	TEST_ASSERT(attr != NULL);
	TEST_EQUALS(chan, attr->v.channel_number);

	/* 32-bit */
	attr = stun_msg_attr(msg, STUN_ATTR_LIFETIME);
	TEST_ASSERT(attr != NULL);
	TEST_EQUALS(lifetime, attr->v.lifetime);

	/* 64-bit */
	attr = stun_msg_attr(msg, STUN_ATTR_RSV_TOKEN);
	TEST_ASSERT(attr != NULL);
	TEST_EQUALS(rsv_token, attr->v.rsv_token);

 out:
	mem_deref(msg);
	mem_deref(mb);
	return err;
}
Ejemplo n.º 13
0
int test_stun_reqltc(void)
{
	struct stun_msg *msg = NULL;
	struct stun_attr *attr;
	struct mbuf *mb;
	uint8_t md5_hash[MD5_SIZE];
	int r, err;

	mb = mbuf_alloc(1024);
	if (!mb) {
		err = ENOMEM;
		goto out;
	}

	/* use long-term credentials */
	err = md5_printf(md5_hash, "%s:%s:%s", username_ltc, realm_ltc,
			 password_ltc);
	if (err)
		goto out;

	err = stun_msg_encode(mb, STUN_METHOD_BINDING, STUN_CLASS_REQUEST,
			      tid_ltc, NULL,
			      md5_hash, sizeof(md5_hash),
			      false, 0x00, 3,
			      STUN_ATTR_USERNAME, username_ltc,
			      STUN_ATTR_NONCE, nonce_ltc,
			      STUN_ATTR_REALM, realm_ltc);
	if (err)
		goto out;

	r = memcmp(mb->buf, reqltc, mb->end);
	if ((sizeof(reqltc)-1) != mb->end || 0 != r) {
		err = EBADMSG;
		DEBUG_WARNING("compare failed (r=%d)\n", r);
		(void)re_printf("msg: [%02w]\n", mb->buf, mb->end);
		(void)re_printf("ref: [%02w]\n", reqltc, sizeof(reqltc)-1);
		goto out;
	}

	/* Decode STUN message */
	mb->pos = 0;
	err = stun_msg_decode(&msg, mb, NULL);
	if (err)
		goto out;

	if (STUN_CLASS_REQUEST != stun_msg_class(msg))
		goto bad;

	if (STUN_METHOD_BINDING != stun_msg_method(msg))
		goto bad;

	err = stun_msg_chk_mi(msg, md5_hash, sizeof(md5_hash));
	if (err)
		goto out;

	if (EPROTO != stun_msg_chk_fingerprint(msg))
		goto bad;

	attr = stun_msg_attr(msg, STUN_ATTR_USERNAME);
	if (!attr || strcmp(username_ltc, attr->v.username))
		goto bad;

	attr = stun_msg_attr(msg, STUN_ATTR_NONCE);
	if (!attr || strcmp(nonce_ltc, attr->v.nonce))
		goto bad;

	attr = stun_msg_attr(msg, STUN_ATTR_REALM);
	if (!attr || strcmp(realm_ltc, attr->v.realm))
		goto bad;

	goto out;

 bad:
	err = EBADMSG;

 out:
	mem_deref(msg);
	mem_deref(mb);
	return err;
}
Ejemplo n.º 14
0
static int test_resp(const struct pl *resp, const struct sa *addr)
{
	struct stun_msg *msg = NULL;
	struct stun_attr *attr;
	struct mbuf *mb = NULL;
	int err;

	mb = mbuf_alloc(1024);
	if (!mb) {
		err = ENOMEM;
		goto out;
	}

	err = stun_msg_encode(mb, STUN_METHOD_BINDING, STUN_CLASS_SUCCESS_RESP,
			      tid, NULL,
			      (uint8_t *)password.p, password.l, true,
			      0x20, 2,
                              STUN_ATTR_SOFTWARE, server_sw,
			      STUN_ATTR_XOR_MAPPED_ADDR, addr);
	if (err)
		goto out;

	if (resp->l != mb->end ||
	    0 != memcmp(mb->buf, resp->p, mb->end)) {
		err = EBADMSG;
		DEBUG_WARNING("compare failed (%J)\n", addr);
		(void)re_printf("msg: [%02w]\n", mb->buf, mb->end);
		(void)re_printf("ref: [%02w]\n", resp->p, resp->l);
		goto out;
	}

	/* Decode STUN message */
	mb->pos = 0;
	err = stun_msg_decode(&msg, mb, NULL);
	if (err)
		goto out;

	if (STUN_CLASS_SUCCESS_RESP != stun_msg_class(msg))
		goto bad;

	if (STUN_METHOD_BINDING != stun_msg_method(msg))
		goto bad;

	err = stun_msg_chk_mi(msg, (uint8_t *)password.p, password.l);
	if (err)
		goto out;

	err = stun_msg_chk_fingerprint(msg);
	if (err)
		goto out;

	attr = stun_msg_attr(msg, STUN_ATTR_XOR_MAPPED_ADDR);
	if (!attr || !sa_cmp(&attr->v.xor_mapped_addr, addr, SA_ALL))
		goto bad;

	attr = stun_msg_attr(msg, STUN_ATTR_SOFTWARE);
	if (!attr || strcmp(server_sw, attr->v.software))
		goto bad;

	goto out;

 bad:
	err = EBADMSG;

 out:
	mem_deref(msg);
	mem_deref(mb);
	return err;
}
Ejemplo n.º 15
0
int turnc_recv(struct turnc *turnc, struct sa *src, struct mbuf *mb)
{
	struct stun_attr *peer, *data;
	struct stun_unknown_attr ua;
	struct stun_msg *msg;
	int err = 0;

	if (!turnc || !src || !mb)
		return EINVAL;

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

		struct chan_hdr hdr;
		struct chan *chan;

		if (turnc_chan_hdr_decode(&hdr, mb))
			return EBADMSG;

		if (mbuf_get_left(mb) < hdr.len)
			return EBADMSG;

		chan = turnc_chan_find_numb(turnc, hdr.nr);
		if (!chan)
			return EBADMSG;

		*src = *turnc_chan_peer(chan);

		return 0;
	}

	switch (stun_msg_class(msg)) {

	case STUN_CLASS_INDICATION:
		if (ua.typec > 0) {
			err = ENOSYS;
			break;
		}

		if (stun_msg_method(msg) != STUN_METHOD_DATA) {
			err = ENOSYS;
			break;
		}

		peer = stun_msg_attr(msg, STUN_ATTR_XOR_PEER_ADDR);
		data = stun_msg_attr(msg, STUN_ATTR_DATA);
		if (!peer || !data) {
			err = EPROTO;
			break;
		}

		*src = peer->v.xor_peer_addr;

		mb->pos = data->v.data.pos;
		mb->end = data->v.data.end;
		break;

	case STUN_CLASS_ERROR_RESP:
	case STUN_CLASS_SUCCESS_RESP:
		(void)stun_ctrans_recv(turnc->stun, msg, &ua);
		mb->pos = mb->end;
		break;

	default:
		err = ENOSYS;
		break;
	}

	mem_deref(msg);

	return err;
}
Ejemplo n.º 16
0
static bool request_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 *mi, *user, *realm, *nonce;
	const time_t now = time(NULL);
	char nstr[NONCE_MAX_SIZE + 1];
	int err;
	(void)dst;

	if (ctx->key)
		return false;

	mi    = stun_msg_attr(msg, STUN_ATTR_MSG_INTEGRITY);
	user  = stun_msg_attr(msg, STUN_ATTR_USERNAME);
	realm = stun_msg_attr(msg, STUN_ATTR_REALM);
	nonce = stun_msg_attr(msg, STUN_ATTR_NONCE);

	if (!mi) {
		err = stun_ereply(proto, sock, src, 0, msg,
				  401, "Unauthorized",
				  NULL, 0, ctx->fp, 3,
				  STUN_ATTR_REALM, restund_realm(),
				  STUN_ATTR_NONCE, mknonce(nstr, now, src),
				  STUN_ATTR_SOFTWARE, restund_software);
		goto unauth;
	}

	if (!user || !realm || !nonce) {
		err = stun_ereply(proto, sock, src, 0, msg,
				  400, "Bad Request",
				  NULL, 0, ctx->fp, 1,
				  STUN_ATTR_SOFTWARE, restund_software);
		goto unauth;
	}

	if (!nonce_validate(nonce->v.nonce, now, src)) {
		err = stun_ereply(proto, sock, src, 0, msg,
				  438, "Stale Nonce",
				  NULL, 0, ctx->fp, 3,
				  STUN_ATTR_REALM, restund_realm(),
				  STUN_ATTR_NONCE, mknonce(nstr, now, src),
				  STUN_ATTR_SOFTWARE, restund_software);
		goto unauth;
	}

	ctx->key = mem_alloc(MD5_SIZE, NULL);
	if (!ctx->key) {
		restund_warning("auth: can't to allocate memory for MI key\n");
		err = stun_ereply(proto, sock, src, 0, msg,
				  500, "Server Error",
				  NULL, 0, ctx->fp, 1,
				  STUN_ATTR_SOFTWARE, restund_software);
		goto unauth;
	}

	ctx->keylen = MD5_SIZE;
	if (auth.sharedsecret_length > 0 || auth.sharedsecret2_length > 0) {
		if (!((sharedsecret_auth_calc_ha1(user, (uint8_t*) auth.sharedsecret, 
                                auth.sharedsecret_length, ctx->key)
			    && !stun_msg_chk_mi(msg, ctx->key, ctx->keylen))
			|| (sharedsecret_auth_calc_ha1(user, (uint8_t*) auth.sharedsecret2,
                                   auth.sharedsecret2_length, ctx->key)
			   && !stun_msg_chk_mi(msg, ctx->key, ctx->keylen)))) {
			restund_info("auth: shared secret auth for user '%s' (%j) failed\n",
				     user->v.username, src);
			err = stun_ereply(proto, sock, src, 0, msg,
					  401, "Unauthorized",
					  NULL, 0, ctx->fp, 3,
					  STUN_ATTR_REALM, restund_realm(),
					  STUN_ATTR_NONCE, mknonce(nstr, now, src),
					  STUN_ATTR_SOFTWARE, restund_software);
			goto unauth;
		} else {
            /*
			restund_info("auth: shared secret auth for user '%s' (%j) worked\n",
				     user->v.username, src);
            */
            if (STUN_METHOD_ALLOCATE == stun_msg_method(msg) && !sharedsecret_auth_check_timestamp(user, now)) {
                restund_info("auth: shared secret auth for user '%s' expired)\n",
                         user->v.username);
                err = stun_ereply(proto, sock, src, 0, msg,
                          401, "Unauthorized",
                          NULL, 0, ctx->fp, 3,
                          STUN_ATTR_REALM, restund_realm(),
                          STUN_ATTR_NONCE, mknonce(nstr, now, src),
                          STUN_ATTR_SOFTWARE, restund_software);
                goto unauth;
            }
		}
	} else if (restund_get_ha1(user->v.username, ctx->key)) {
		restund_info("auth: unknown user '%s' (%j)\n",
			     user->v.username, src);
		err = stun_ereply(proto, sock, src, 0, msg,
				  401, "Unauthorized",
				  NULL, 0, ctx->fp, 3,
				  STUN_ATTR_REALM, restund_realm(),
				  STUN_ATTR_NONCE, mknonce(nstr, now, src),
				  STUN_ATTR_SOFTWARE, restund_software);
		goto unauth;
	}

	if (stun_msg_chk_mi(msg, ctx->key, ctx->keylen)) {
		restund_info("auth: bad password for user '%s' (%j)\n",
			     user->v.username, src);
		err = stun_ereply(proto, sock, src, 0, msg,
				  401, "Unauthorized",
				  NULL, 0, ctx->fp, 3,
				  STUN_ATTR_REALM, restund_realm(),
				  STUN_ATTR_NONCE, mknonce(nstr, now, src),
				  STUN_ATTR_SOFTWARE, restund_software);
		goto unauth;
	}

	return false;

 unauth:
	if (err) {
		restund_warning("auth reply error: %m\n", err);
	}

	return true;
}
Ejemplo n.º 17
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);
}