Ejemplo n.º 1
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.º 2
0
/* only used for STUN gathering */
static void process_stun(struct candidate *cand, struct mbuf *mb)
{
	struct stun_unknown_attr ua;
	struct stun_msg *msg;
	int err;

	err = stun_msg_decode(&msg, mb, &ua);
	if (err) {
		re_fprintf(stderr, "could not decode STUN message\n");
		return;
	}

	switch (stun_msg_class(msg)) {

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

	default:
		break;
	}

	mem_deref(msg);
}
Ejemplo n.º 3
0
static void msg_recv(struct nat_hairpinning *nh, int proto, void *sock,
		     const struct sa *src, struct mbuf *mb)
{
	struct stun_unknown_attr ua;
	struct stun_msg *msg;

	if (0 != stun_msg_decode(&msg, mb, &ua))
		return;

	switch (stun_msg_class(msg)) {

	case STUN_CLASS_REQUEST:
		(void)stun_reply(proto, sock, src, 0, msg, NULL, 0, false, 3,
				 STUN_ATTR_XOR_MAPPED_ADDR, src,
				 STUN_ATTR_MAPPED_ADDR, src,
				 STUN_ATTR_SOFTWARE, stun_software);
		break;

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

	default:
		DEBUG_WARNING("unknown class 0x%04x\n", stun_msg_class(msg));
		break;
	}

	mem_deref(msg);
}
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
void process_msg(struct turnd *turnd, int proto, void *sock,
			const struct sa *src, const struct sa *dst,
			struct mbuf *mb)
{
	struct msgctx ctx;
	struct stun_msg *msg;
	int err;

	if (!sock || !src || !dst || !mb)
		return;

	err = stun_msg_decode(&msg, mb, &ctx.ua);
	if (err) {
		turn_raw_handler(turnd, proto, src, dst, mb);
		return;
	}

	ctx.key = NULL;
	ctx.keylen = 0;
	ctx.fp = false;
	ctx.turnd = turnd;

#if 0
	stun_msg_dump(msg);
#endif

	switch (stun_msg_class(msg)) {

	case STUN_CLASS_REQUEST:
		turn_request_handler(&ctx, proto, sock, src, dst, msg);
		break;

	case STUN_CLASS_INDICATION:
		turn_indication_handler(&ctx, proto,sock, src, dst, msg);
		break;

	default:
		debug("stun: unhandled msg class (%u) from %J\n",
		      stun_msg_class(msg), src);
		break;
	}

	mem_deref(ctx.key);
	mem_deref(msg);
}
Ejemplo n.º 6
0
static void sniff_stun(struct mbuf *mb)
{
	struct stun_msg *msg;
	size_t pos;
	int err;

	pos = mb->pos;
	err = stun_msg_decode(&msg, mb, NULL);
	if (err) {
		DEBUG_WARNING("could not decode STUN packet (%m)\n", err);
		return;
	}

	stun_msg_attr_apply(msg, stun_attr_handler, 0);
	(void)re_printf("\n");

	mem_deref(msg);

	mb->pos = pos;
}
Ejemplo n.º 7
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.º 8
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.º 9
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.º 10
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.º 11
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.º 12
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.º 13
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.º 14
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);
}