示例#1
0
/**
 * Decode an RTCP Transport Layer Feedback Message
 *
 * @param mb  Buffer to decode
 * @param msg RTCP Message to decode into
 *
 * @return 0 for success, otherwise errorcode
 */
int rtcp_rtpfb_decode(struct mbuf *mb, struct rtcp_msg *msg)
{
	size_t i, sz;

	if (!msg)
		return EINVAL;

	switch (msg->hdr.count) {

	case RTCP_RTPFB_GNACK:
		sz = msg->r.fb.n * sizeof(*msg->r.fb.fci.gnackv);
		msg->r.fb.fci.gnackv = mem_alloc(sz, NULL);
		if (!msg->r.fb.fci.gnackv)
			return ENOMEM;

		if (mbuf_get_left(mb) < msg->r.fb.n * GNACK_SIZE)
			return EBADMSG;
		for (i=0; i<msg->r.fb.n; i++) {
			msg->r.fb.fci.gnackv[i].pid = ntohs(mbuf_read_u16(mb));
			msg->r.fb.fci.gnackv[i].blp = ntohs(mbuf_read_u16(mb));
		}
		break;

	default:
		DEBUG_NOTICE("unknown RTPFB fmt %d\n", msg->hdr.count);
		break;
	}

	return 0;
}
示例#2
0
文件: rtp.c 项目: hbowden/re
/**
 * Decode an RTP header from a buffer
 *
 * @param hdr RTP Header to decode into
 * @param mb  Buffer to decode from
 *
 * @return 0 if success, otherwise errorcode
 */
int rtp_hdr_decode(struct rtp_header *hdr, struct mbuf *mb)
{
	uint8_t buf[2];
	int err, i;
	size_t header_len;

	if (!hdr || !mb)
		return EINVAL;

	if (mbuf_get_left(mb) < RTP_HEADER_SIZE)
		return EBADMSG;

	err = mbuf_read_mem(mb, buf, sizeof(buf));
	if (err)
		return err;

	hdr->ver  = (buf[0] >> 6) & 0x03;
	hdr->pad  = (buf[0] >> 5) & 0x01;
	hdr->ext  = (buf[0] >> 4) & 0x01;
	hdr->cc   = (buf[0] >> 0) & 0x0f;
	hdr->m    = (buf[1] >> 7) & 0x01;
	hdr->pt   = (buf[1] >> 0) & 0x7f;

	hdr->seq  = ntohs(mbuf_read_u16(mb));
	hdr->ts   = ntohl(mbuf_read_u32(mb));
	hdr->ssrc = ntohl(mbuf_read_u32(mb));

	header_len = hdr->cc*sizeof(uint32_t);
	if (mbuf_get_left(mb) < header_len)
		return EBADMSG;

	for (i=0; i<hdr->cc; i++) {
		hdr->csrc[i] = ntohl(mbuf_read_u32(mb));
	}

	if (hdr->ext) {
		if (mbuf_get_left(mb) < 4)
			return EBADMSG;

		hdr->x.type = ntohs(mbuf_read_u16(mb));
		hdr->x.len  = ntohs(mbuf_read_u16(mb));

		if (mbuf_get_left(mb) < hdr->x.len*sizeof(uint32_t))
			return EBADMSG;

		mb->pos += hdr->x.len*sizeof(uint32_t);
	}

	return 0;
}
示例#3
0
文件: turn.c 项目: AmesianX/restund
static bool raw_handler(int proto, const struct sa *src,
			const struct sa *dst, struct mbuf *mb)
{
	struct allocation *al;
	uint16_t numb, len;
	struct perm *perm;
	struct chan *chan;
	int err;

	al = allocation_find(proto, src, dst);
	if (!al)
		return false;

	if (mbuf_get_left(mb) < 4)
		return false;

	numb = ntohs(mbuf_read_u16(mb));
	len  = ntohs(mbuf_read_u16(mb));

	if (mbuf_get_left(mb) < len)
		return false;


    // strip any optional padding
    if (len != mbuf_get_left(mb))
        mbuf_set_end(mb, mb->pos + len);

	chan = chan_numb_find(al->chans, numb);
	if (!chan)
		return false;

	perm = perm_find(al->perms, chan_peer(chan));
	if (!perm) {
		++al->dropc_tx;
		return false;
	}

	err = udp_send(al->rel_us, chan_peer(chan), mb);
	if (err)
		turnd.errc_tx++;
	else {
		const size_t bytes = mbuf_get_left(mb);

		perm_tx_stat(perm, bytes);
		turnd.bytec_tx += bytes;
	}

	return true;
}
示例#4
0
int dns_dname_decode(struct mbuf *mb, char **name, size_t start)
{
	uint32_t i = 0, loopc = 0;
	bool comp = false;
	size_t pos = 0;
	char buf[256];

	if (!mb || !name)
		return EINVAL;

	while (mb->pos < mb->end) {

		uint8_t len = mb->buf[mb->pos++];
		if (!len) {
			if (comp)
				mb->pos = pos;

			buf[i++] = '\0';

			*name = mem_alloc(i, NULL);
			if (!*name)
				return ENOMEM;

			str_ncpy(*name, buf, i);

			return 0;
		}
		else if ((len & COMP_MASK) == COMP_MASK) {
			uint16_t offset;

			if (loopc++ > COMP_LOOP)
				break;

			--mb->pos;

			offset = ntohs(mbuf_read_u16(mb)) & OFFSET_MASK;
			if (!comp) {
				pos  = mb->pos;
				comp = true;
			}

			mb->pos = offset + start;
			continue;
		}
		else if (len > mbuf_get_left(mb))
			break;
		else if (len > sizeof(buf) - i - 2)
			break;

		if (i > 0)
			buf[i++] = '.';

		while (len--)
			buf[i++] = mb->buf[mb->pos++];
	}

	return EINVAL;
}
示例#5
0
int stun_hdr_decode(struct mbuf *mb, struct stun_hdr *hdr)
{
	if (!mb || !hdr)
		return EINVAL;

	if (mbuf_get_left(mb) < STUN_HEADER_SIZE)
		return EBADMSG;

	hdr->type = ntohs(mbuf_read_u16(mb));
	if (hdr->type & 0xc000)
		return EBADMSG;

	hdr->len = ntohs(mbuf_read_u16(mb));
	if (hdr->len & 0x3)
		return EBADMSG;

	hdr->cookie = ntohl(mbuf_read_u32(mb));
	(void)mbuf_read_mem(mb, hdr->tid, sizeof(hdr->tid));

	if (mbuf_get_left(mb) < hdr->len)
		return EBADMSG;

	return 0;
}
示例#6
0
文件: pkt.c 项目: kaija/libre
/**
 * Decode the RTCP Header
 *
 * @param mb  Buffer to decode from
 * @param hdr RTCP Header to decode into
 *
 * @return 0 for success, otherwise errorcode
 */
int rtcp_hdr_decode(struct mbuf *mb, struct rtcp_hdr *hdr)
{
	uint8_t b;

	if (!hdr)
		return EINVAL;
	if (mbuf_get_left(mb) < RTCP_HDR_SIZE)
		return EBADMSG;

	b = mbuf_read_u8(mb);
	hdr->pt = mbuf_read_u8(mb);
	hdr->length = ntohs(mbuf_read_u16(mb));

	hdr->version = (b >> 6) & 0x3;
	hdr->p       = (b >> 5) & 0x1;
	hdr->count   = (b >> 0) & 0x1f;

	return 0;
}
示例#7
0
static void tcp_recv_handler(struct mbuf *mb_pkt, void *arg)
{
	struct allocation *alloc = arg;
	int err = 0;

	/* re-assembly of fragments */
	if (alloc->mb) {
		size_t pos;

		pos = alloc->mb->pos;

		alloc->mb->pos = alloc->mb->end;

		err = mbuf_write_mem(alloc->mb,
				     mbuf_buf(mb_pkt), mbuf_get_left(mb_pkt));
		if (err)
			goto out;

		alloc->mb->pos = pos;
	}
	else {
		alloc->mb = mem_ref(mb_pkt);
	}

	for (;;) {

		size_t len, pos, end;
		struct sa src;
		uint16_t typ;

		if (mbuf_get_left(alloc->mb) < 4)
			break;

		typ = ntohs(mbuf_read_u16(alloc->mb));
		len = ntohs(mbuf_read_u16(alloc->mb));

		if (typ < 0x4000)
			len += STUN_HEADER_SIZE;
		else if (typ < 0x8000)
			len += 4;
		else {
			err = EBADMSG;
			goto out;
		}

		alloc->mb->pos -= 4;

		if (mbuf_get_left(alloc->mb) < len)
			break;

		pos = alloc->mb->pos;
		end = alloc->mb->end;

		alloc->mb->end = pos + len;

		/* forward packet to TURN client */
		err = turnc_recv(alloc->turnc, &src, alloc->mb);
		if (err)
			goto out;

		if (mbuf_get_left(alloc->mb)) {
			data_handler(alloc, &src, alloc->mb);
		}

		/* 4 byte alignment */
		while (len & 0x03)
			++len;

		alloc->mb->pos = pos + len;
		alloc->mb->end = end;

		if (alloc->mb->pos >= alloc->mb->end) {
			alloc->mb = mem_deref(alloc->mb);
			break;
		}
	}

 out:
	if (err) {
		alloc->alloch(err, 0, NULL, NULL, NULL, alloc->arg);
	}
}
示例#8
0
文件: option.c 项目: alfredh/rew
int pcp_option_decode(struct pcp_option **optp, struct mbuf *mb)
{
	struct pcp_option *opt;
	size_t start, len;
	uint16_t port;
	int err = 0;

	if (!optp || !mb)
		return EINVAL;

	if (mbuf_get_left(mb) < 4)
		return EBADMSG;

	opt = mem_zalloc(sizeof(*opt), destructor);
	if (!opt)
		return ENOMEM;

	opt->code = mbuf_read_u8(mb);
	(void)mbuf_read_u8(mb);
	len = ntohs(mbuf_read_u16(mb));

	if (mbuf_get_left(mb) < len)
		goto badmsg;

	start = mb->pos;

	switch (opt->code) {

	case PCP_OPTION_THIRD_PARTY:
		if (len < 16)
			goto badmsg;
		err = pcp_ipaddr_decode(mb, &opt->u.third_party);
		break;

	case PCP_OPTION_PREFER_FAILURE:
		/* no payload */
		break;

	case PCP_OPTION_FILTER:
		if (len < 20)
			goto badmsg;
		(void)mbuf_read_u8(mb);
		opt->u.filter.prefix_length = mbuf_read_u8(mb);
		port = ntohs(mbuf_read_u16(mb));
		err = pcp_ipaddr_decode(mb, &opt->u.filter.remote_peer);
		sa_set_port(&opt->u.filter.remote_peer, port);
		break;

	case PCP_OPTION_DESCRIPTION:
		err = mbuf_strdup(mb, &opt->u.description, len);
		break;

	default:
		mb->pos += len;

		(void)re_printf("pcp: ignore option code %d (len=%zu)\n",
				opt->code, len);
		break;
	}

	if (err)
		goto error;

	/* padding */
	while (((mb->pos - start) & 0x03) && mbuf_get_left(mb))
		++mb->pos;

	*optp = opt;

	return 0;

 badmsg:
	err = EBADMSG;
 error:
	mem_deref(opt);

	return err;
}
示例#9
0
static void tcp_recv_handler(struct mbuf *mbrx, void *arg)
{
	struct tcpconn *tc = arg;
	struct mbuf *mb = tc->mb;
	int err = 0;
	size_t n;

 next:
	/* frame length */
	if (!tc->flen) {

		n = min(2 - mb->end, mbuf_get_left(mbrx));

		err = mbuf_write_mem(mb, mbuf_buf(mbrx), n);
		if (err)
			goto error;

		mbrx->pos += n;

		if (mb->end < 2)
			return;

		mb->pos = 0;
		tc->flen = ntohs(mbuf_read_u16(mb));
		mb->pos = 0;
		mb->end = 0;
	}

	/* content */
	n = min(tc->flen - mb->end, mbuf_get_left(mbrx));

	err = mbuf_write_mem(mb, mbuf_buf(mbrx), n);
	if (err)
		goto error;

	mbrx->pos += n;

	if (mb->end < tc->flen)
		return;

	mb->pos = 0;

	err = reply_recv(tc->dnsc, mb);
	if (err)
		goto error;

	/* reset tcp buffer */
	tc->flen = 0;
	mb->pos = 0;
	mb->end = 0;

	/* more data ? */
	if (mbuf_get_left(mbrx) > 0) {
		DEBUG_INFO("%u bytes of tcp data left\n", mbuf_get_left(mbrx));
		goto next;
	}

	return;

 error:
	tcpconn_close(tc, err);
}
示例#10
0
static int reply_recv(struct dnsc *dnsc, struct mbuf *mb)
{
	struct dns_query *q = NULL;
	uint32_t i, j, nv[3];
	struct dnsquery dq;
	int err = 0;

	if (!dnsc || !mb)
		return EINVAL;

	dq.name = NULL;

	if (dns_hdr_decode(mb, &dq.hdr) || !dq.hdr.qr) {
		err = EBADMSG;
		goto out;
	}

	err = dns_dname_decode(mb, &dq.name, 0);
	if (err)
		goto out;

	if (mbuf_get_left(mb) < 4) {
		err = EBADMSG;
		goto out;
	}

	dq.type     = ntohs(mbuf_read_u16(mb));
	dq.dnsclass = ntohs(mbuf_read_u16(mb));

	q = list_ledata(hash_lookup(dnsc->ht_query, hash_joaat_str_ci(dq.name),
				    query_cmp_handler, &dq));
	if (!q) {
		err = ENOENT;
		goto out;
	}

	/* try next server */
	if (dq.hdr.rcode == DNS_RCODE_SRV_FAIL && q->ntx < *q->srvc) {

		if (!q->tc) /* try next UDP server immediately */
			tmr_start(&q->tmr, 0, udp_timeout_handler, q);

		err = EPROTO;
		goto out;
	}

	nv[0] = dq.hdr.nans;
	nv[1] = dq.hdr.nauth;
	nv[2] = dq.hdr.nadd;

	for (i=0; i<ARRAY_SIZE(nv); i++) {

		for (j=0; j<nv[i]; j++) {

			struct dnsrr *rr = NULL;

			err = dns_rr_decode(mb, &rr, 0);
			if (err) {
				query_handler(q, err, NULL, NULL, NULL, NULL);
				mem_deref(q);
				goto out;
			}

			list_append(&q->rrlv[i], &rr->le_priv, rr);
		}
	}

	if (q->type == DNS_QTYPE_AXFR) {

		struct dnsrr *rrh, *rrt;

		rrh = list_ledata(list_head(&q->rrlv[0]));
		rrt = list_ledata(list_tail(&q->rrlv[0]));

		/* Wait for last AXFR reply with terminating SOA record */
		if (dq.hdr.rcode == DNS_RCODE_OK && dq.hdr.nans > 0 &&
		    (!rrt || rrt->type != DNS_TYPE_SOA || rrh == rrt)) {
			DEBUG_INFO("waiting for last SOA record in reply\n");
			goto out;
		}
	}

	query_handler(q, 0, &dq.hdr, &q->rrlv[0], &q->rrlv[1], &q->rrlv[2]);
	mem_deref(q);

 out:
	mem_deref(dq.name);

	return err;
}
示例#11
0
static void tcp_recv_handler(struct mbuf *mb, void *arg)
{
	struct turnserver *conn = arg;
	int err = 0;

	if (conn->mb) {
		size_t pos;

		pos = conn->mb->pos;

		conn->mb->pos = conn->mb->end;

		err = mbuf_write_mem(conn->mb, mbuf_buf(mb),mbuf_get_left(mb));
		if (err) {
			DEBUG_WARNING("tcp: buffer write error: %m\n", err);
			goto out;
		}

		conn->mb->pos = pos;
	}
	else {
		conn->mb = mem_ref(mb);
	}

	for (;;) {

		size_t len, pos, end;
		uint16_t typ;

		if (mbuf_get_left(conn->mb) < 4)
			break;

		typ = ntohs(mbuf_read_u16(conn->mb));
		len = ntohs(mbuf_read_u16(conn->mb));

		if (len > TCP_MAX_LENGTH) {
			re_printf("tcp: bad length: %zu\n", len);
			err = EBADMSG;
			goto out;
		}

		if (typ < 0x4000)
			len += STUN_HEADER_SIZE;
		else if (typ < 0x8000)
			len += 4;
		else {
			re_printf("tcp: bad type: 0x%04x\n", typ);
			err = EBADMSG;
			goto out;
		}

		conn->mb->pos -= 4;

		if (mbuf_get_left(conn->mb) < len)
			break;

		pos = conn->mb->pos;
		end = conn->mb->end;

		conn->mb->end = pos + len;

		process_msg(conn, IPPROTO_TCP, conn->tc, &conn->paddr,
			    conn->mb);

		/* 4 byte alignment */
		while (len & 0x03)
			++len;

		conn->mb->pos = pos + len;
		conn->mb->end = end;

		if (conn->mb->pos >= conn->mb->end) {
			conn->mb = mem_deref(conn->mb);
			break;
		}
	}

 out:
	if (err) {
		conn->mb = mem_deref(conn->mb);
	}
}
示例#12
0
文件: agent.c 项目: alfredh/reicec
static void tcp_recv_handler(struct mbuf *mbx, void *arg)
{
	struct candidate *tl = arg;
	int err = 0;

	if (tl->mb) {
		size_t pos;

		pos = tl->mb->pos;

		tl->mb->pos = tl->mb->end;

		err = mbuf_write_mem(tl->mb, mbuf_buf(mbx),
				     mbuf_get_left(mbx));
		if (err)
			goto out;

		tl->mb->pos = pos;
	}
	else {
		tl->mb = mem_ref(mbx);
	}

	for (;;) {

		size_t len, pos, end;
		uint16_t typ;

		if (mbuf_get_left(tl->mb) < 4)
			break;

		/* STUN Header */
		typ = ntohs(mbuf_read_u16(tl->mb));
		len = ntohs(mbuf_read_u16(tl->mb));

		if (typ < 0x4000)
			len += STUN_HEADER_SIZE;
		else if (typ < 0x8000)
			len += 4;
		else {
			err = EBADMSG;
			goto out;
		}

		tl->mb->pos -= 4;

		if (mbuf_get_left(tl->mb) < len)
			break;

		pos = tl->mb->pos;
		end = tl->mb->end;

		tl->mb->end = pos + len;

		handle_packet(tl, tl->mb);

		/* 4 byte alignment */
		while (len & 0x03)
			++len;

		tl->mb->pos = pos + len;
		tl->mb->end = end;

		if (tl->mb->pos >= tl->mb->end) {
			tl->mb = mem_deref(tl->mb);
			break;
		}
	}

 out:
	if (err) {
		re_printf("tcp recv error (%m)\n", err);
	}
}
static bool shim_recv_handler(int *errp, struct mbuf *mbx, bool *estab,
			      void *arg)
{
	struct shim *shim = arg;
	int err = 0;
	(void)estab;

	/* handle re-assembly */
	if (!shim->mb) {
		shim->mb = mbuf_alloc(1024);
		if (!shim->mb) {
			*errp = ENOMEM;
			return true;
		}
	}

	if (shim->mb) {
		size_t pos;

		pos = shim->mb->pos;

		shim->mb->pos = shim->mb->end;

		err = mbuf_write_mem(shim->mb, mbuf_buf(mbx),
				     mbuf_get_left(mbx));
		if (err)
			goto out;

		shim->mb->pos = pos;
	}

	/* extract all SHIM-frames in the TCP-stream */
	for (;;) {

		size_t start, len, pos, end;
		bool hdld;

		start = shim->mb->pos;

		if (mbuf_get_left(shim->mb) < (SHIM_HDR_SIZE))
			break;

		len = ntohs(mbuf_read_u16(shim->mb));

		if (mbuf_get_left(shim->mb) < len)
			goto rewind;

		pos = shim->mb->pos;
		end = shim->mb->end;

		shim->mb->end = pos + len;

		++shim->n_rx;

		hdld = shim->frameh(shim->mb, shim->arg);
		if (!hdld) {
			/* XXX: handle multiple frames per segment */

			shim->mb->pos = pos;
			shim->mb->end = pos + len;

			mbx->pos = mbx->end = 2;
			err = mbuf_write_mem(mbx, mbuf_buf(shim->mb), len);
			if (err)
				goto out;
			mbx->pos = 2;

			shim->mb->pos = pos + len;
			shim->mb->end = end;

			return false;  /* continue recv-handlers */
		}

		shim->mb->pos = pos + len;
		shim->mb->end = end;

		if (shim->mb->pos >= shim->mb->end) {
			shim->mb = mem_deref(shim->mb);
			break;
		}

		continue;

	rewind:
		shim->mb->pos = start;
		break;
	}

 out:
	if (err)
		*errp = err;

	return true;  /* always handled */
}
示例#14
0
文件: pkt.c 项目: kaija/libre
/**
 * Decode one RTCP message from a buffer
 *
 * @param msgp Pointer to allocated RTCP Message
 * @param mb   Buffer to decode from
 *
 * @return 0 for success, otherwise errorcode
 */
int rtcp_decode(struct rtcp_msg **msgp, struct mbuf *mb)
{
	struct rtcp_msg *msg = NULL;
	size_t start, i, sz, count, rem;
	int err;

	if (!msgp)
		return EINVAL;
	if (mbuf_get_left(mb) < RTCP_HDR_SIZE)
		return EBADMSG;

	msg = mem_zalloc(sizeof(*msg), rtcp_destructor);
	if (!msg)
		return ENOMEM;

	start = mb->pos;

	/* decode and check header */
	err = rtcp_hdr_decode(mb, &msg->hdr);
	if (err)
		goto out;

	if (msg->hdr.version != RTCP_VERSION)
		goto badmsg;

	/* check length and remaining */
	rem = msg->hdr.length * sizeof(uint32_t);
	if (mbuf_get_left(mb) < rem)
		goto badmsg;

	count = msg->hdr.count;

	switch (msg->hdr.pt) {

	case RTCP_SR:
		if (mbuf_get_left(mb) < (RTCP_SRC_SIZE + RTCP_SR_SIZE))
			goto badmsg;
		msg->r.sr.ssrc     = ntohl(mbuf_read_u32(mb));
		msg->r.sr.ntp_sec  = ntohl(mbuf_read_u32(mb));
		msg->r.sr.ntp_frac = ntohl(mbuf_read_u32(mb));
		msg->r.sr.rtp_ts   = ntohl(mbuf_read_u32(mb));
		msg->r.sr.psent    = ntohl(mbuf_read_u32(mb));
		msg->r.sr.osent    = ntohl(mbuf_read_u32(mb));

		err = rtcp_rr_alloc(&msg->r.sr.rrv, count);
		if (err)
			goto out;
		for (i=0; i<count && !err; i++)
			err = rtcp_rr_decode(mb, &msg->r.sr.rrv[i]);
		break;

	case RTCP_RR:
		if (mbuf_get_left(mb) < RTCP_SRC_SIZE)
			goto badmsg;
		msg->r.rr.ssrc = ntohl(mbuf_read_u32(mb));

		err = rtcp_rr_alloc(&msg->r.rr.rrv, count);
		if (err)
			goto out;
		for (i=0; i<count && !err; i++)
			err = rtcp_rr_decode(mb, &msg->r.rr.rrv[i]);
		break;

	case RTCP_SDES:
		if (count == 0)
			break;

		sz = count * sizeof(*msg->r.sdesv);
		msg->r.sdesv = mem_zalloc(sz, NULL);
		if (!msg->r.sdesv) {
			err = ENOMEM;
			goto out;
		}

		for (i=0; i<msg->hdr.count && !err; i++)
			err = rtcp_sdes_decode(mb, &msg->r.sdesv[i]);
		break;

	case RTCP_BYE:
		sz = count * sizeof(*msg->r.bye.srcv);
		msg->r.bye.srcv = mem_alloc(sz, NULL);
		if (!msg->r.bye.srcv) {
			err = ENOMEM;
			goto out;
		}
		if (mbuf_get_left(mb) < sz)
			goto badmsg;
		for (i=0; i<count; i++)
			msg->r.bye.srcv[i] = ntohl(mbuf_read_u32(mb));

		/* decode reason (optional) */
		if (rem > count*sizeof(uint32_t)) {
			const size_t len = mbuf_read_u8(mb);
			if (mbuf_get_left(mb) < len)
				goto badmsg;

			err = mbuf_strdup(mb, &msg->r.bye.reason, len);
		}
		break;

	case RTCP_APP:
		if (mbuf_get_left(mb) < RTCP_APP_SIZE)
			goto badmsg;
		msg->r.app.src = ntohl(mbuf_read_u32(mb));
		(void)mbuf_read_mem(mb, (uint8_t *)msg->r.app.name,
				    sizeof(msg->r.app.name));
		if (rem > RTCP_APP_SIZE) {
			msg->r.app.data_len = rem - RTCP_APP_SIZE;
			msg->r.app.data = mem_alloc(msg->r.app.data_len, NULL);
			if (!msg->r.app.data) {
				err = ENOMEM;
				goto out;
			}
			if (mbuf_get_left(mb) < msg->r.app.data_len)
				goto badmsg;
			(void)mbuf_read_mem(mb, msg->r.app.data,
					    msg->r.app.data_len);
		}
		break;

	case RTCP_FIR:
		if (mbuf_get_left(mb) < RTCP_FIR_SIZE)
			goto badmsg;
		msg->r.fir.ssrc = ntohl(mbuf_read_u32(mb));
		break;

	case RTCP_NACK:
		if (mbuf_get_left(mb) < RTCP_NACK_SIZE)
			goto badmsg;
		msg->r.nack.ssrc = ntohl(mbuf_read_u32(mb));
		msg->r.nack.fsn  = ntohs(mbuf_read_u16(mb));
		msg->r.nack.blp  = ntohs(mbuf_read_u16(mb));
		break;

	case RTCP_RTPFB:
		if (mbuf_get_left(mb) < RTCP_FB_SIZE)
			goto badmsg;
		msg->r.fb.ssrc_packet = ntohl(mbuf_read_u32(mb));
		msg->r.fb.ssrc_media = ntohl(mbuf_read_u32(mb));
		msg->r.fb.n = msg->hdr.length - 2;

		err = rtcp_rtpfb_decode(mb, msg);
		break;

	case RTCP_PSFB:
		if (mbuf_get_left(mb) < RTCP_FB_SIZE)
			goto badmsg;
		msg->r.fb.ssrc_packet = ntohl(mbuf_read_u32(mb));
		msg->r.fb.ssrc_media = ntohl(mbuf_read_u32(mb));
		msg->r.fb.n = msg->hdr.length - 2;

		err = rtcp_psfb_decode(mb, msg);
		break;

	default:
		/* unknown message type */
		mbuf_advance(mb, rem);
		break;
	}
	if (err)
		goto out;

	/* slurp padding */
	while ((mb->pos - start) & 0x3 && mbuf_get_left(mb))
		++mb->pos;

 out:
	if (err)
		mem_deref(msg);
	else
		*msgp = msg;

	return err;

 badmsg:
	mem_deref(msg);
	return EBADMSG;
}
示例#15
0
int stun_attr_decode(struct stun_attr **attrp, struct mbuf *mb,
		     const uint8_t *tid, struct stun_unknown_attr *ua)
{
	struct stun_attr *attr;
	size_t start, len;
	uint32_t i, n;
	int err = 0;

	if (!mb || !attrp)
		return EINVAL;

	if (mbuf_get_left(mb) < 4)
		return EBADMSG;

	attr = mem_zalloc(sizeof(*attr), destructor);
	if (!attr)
		return ENOMEM;

	attr->type = htons(mbuf_read_u16(mb));
	len = htons(mbuf_read_u16(mb));

	if (mbuf_get_left(mb) < len)
		goto badmsg;

	start = mb->pos;

	switch (attr->type) {

	case STUN_ATTR_MAPPED_ADDR:
	case STUN_ATTR_ALT_SERVER:
	case STUN_ATTR_RESP_ORIGIN:
	case STUN_ATTR_OTHER_ADDR:
		tid = NULL;
		/*@fallthrough@*/
	case STUN_ATTR_XOR_PEER_ADDR:
	case STUN_ATTR_XOR_RELAY_ADDR:
	case STUN_ATTR_XOR_MAPPED_ADDR:
		err = stun_addr_decode(mb, &attr->v.sa, tid);
		break;

	case STUN_ATTR_CHANGE_REQ:
		if (len != 4)
			goto badmsg;

		n = ntohl(mbuf_read_u32(mb));
		attr->v.change_req.ip   = (n >> 2) & 0x1;
		attr->v.change_req.port = (n >> 1) & 0x1;
		break;

	case STUN_ATTR_USERNAME:
	case STUN_ATTR_REALM:
	case STUN_ATTR_NONCE:
	case STUN_ATTR_SOFTWARE:
		err = str_decode(mb, &attr->v.str, len);
		break;

	case STUN_ATTR_MSG_INTEGRITY:
		if (len != 20)
			goto badmsg;

		err = mbuf_read_mem(mb, attr->v.msg_integrity, 20);
		break;

	case STUN_ATTR_ERR_CODE:
		if (len < 4)
			goto badmsg;

		mb->pos += 2;
		attr->v.err_code.code  = (mbuf_read_u8(mb) & 0x7) * 100;
		attr->v.err_code.code += mbuf_read_u8(mb);
		err = str_decode(mb, &attr->v.err_code.reason, len - 4);
		break;

	case STUN_ATTR_UNKNOWN_ATTR:
		for (i=0; i<len/2; i++) {
			uint16_t type = ntohs(mbuf_read_u16(mb));

			if (i >= ARRAY_SIZE(attr->v.unknown_attr.typev))
				continue;

			attr->v.unknown_attr.typev[i] = type;
			attr->v.unknown_attr.typec++;
		}
		break;

	case STUN_ATTR_CHANNEL_NUMBER:
	case STUN_ATTR_RESP_PORT:
		if (len < 2)
			goto badmsg;

	        attr->v.uint16 = ntohs(mbuf_read_u16(mb));
		break;

	case STUN_ATTR_LIFETIME:
	case STUN_ATTR_PRIORITY:
	case STUN_ATTR_FINGERPRINT:
		if (len != 4)
			goto badmsg;

	        attr->v.uint32 = ntohl(mbuf_read_u32(mb));
		break;

	case STUN_ATTR_DATA:
	case STUN_ATTR_PADDING:
		attr->v.mb.buf  = mem_ref(mb->buf);
		attr->v.mb.size = mb->size;
		attr->v.mb.pos  = mb->pos;
		attr->v.mb.end  = mb->pos + len;
		mb->pos += len;
		break;

	case STUN_ATTR_REQ_ADDR_FAMILY:
	case STUN_ATTR_REQ_TRANSPORT:
		if (len < 1)
			goto badmsg;

	        attr->v.uint8 = mbuf_read_u8(mb);
		break;

	case STUN_ATTR_EVEN_PORT:
		if (len < 1)
			goto badmsg;

		attr->v.even_port.r = (mbuf_read_u8(mb) >> 7) & 0x1;
		break;

	case STUN_ATTR_DONT_FRAGMENT:
	case STUN_ATTR_USE_CAND:
		if (len > 0)
			goto badmsg;

		/* no value */
		break;

	case STUN_ATTR_RSV_TOKEN:
	case STUN_ATTR_CONTROLLING:
	case STUN_ATTR_CONTROLLED:
		if (len != 8)
			goto badmsg;

	        attr->v.uint64 = sys_ntohll(mbuf_read_u64(mb));
		break;

	default:
		mb->pos += len;

		if (attr->type >= 0x8000)
			break;

		if (ua && ua->typec < ARRAY_SIZE(ua->typev))
			ua->typev[ua->typec++] = attr->type;
		break;
	}

	if (err)
		goto error;

	/* padding */
	while (((mb->pos - start) & 0x03) && mbuf_get_left(mb))
		++mb->pos;

	*attrp = attr;

	return 0;

 badmsg:
	err = EBADMSG;
 error:
	mem_deref(attr);

	return err;
}
示例#16
0
文件: dnssrv.c 项目: GGGO/baresip
static void decode_dns_query(struct dns_server *srv,
			     const struct sa *src, struct mbuf *mb)
{
	struct list rrl = LIST_INIT;
	struct dnshdr hdr;
	struct le *le;
	char *qname = NULL;
	size_t start, end;
	uint16_t type, dnsclass;
	int err = 0;

	start = mb->pos;
	end   = mb->end;

	if (dns_hdr_decode(mb, &hdr) || hdr.qr || hdr.nq != 1) {
		DEBUG_WARNING("unable to decode query header\n");
		return;
	}

	err = dns_dname_decode(mb, &qname, start);
	if (err) {
		DEBUG_WARNING("unable to decode query name\n");
		goto out;
	}

	if (mbuf_get_left(mb) < 4) {
		err = EBADMSG;
		DEBUG_WARNING("unable to decode query type/class\n");
		goto out;
	}

	type     = ntohs(mbuf_read_u16(mb));
	dnsclass = ntohs(mbuf_read_u16(mb));

	DEBUG_INFO("dnssrv: type=%s query-name='%s'\n",
		   dns_rr_typename(type), qname);

	if (dnsclass == DNS_CLASS_IN) {
		dns_server_match(srv, &rrl, qname, type);
	}

	hdr.qr    = true;
	hdr.tc    = false;
	hdr.rcode = DNS_RCODE_OK;
	hdr.nq    = 1;
	hdr.nans  = list_count(&rrl);

	mb->pos = start;

	err = dns_hdr_encode(mb, &hdr);
	if (err)
		goto out;

	mb->pos = end;

	DEBUG_INFO("dnssrv: @@ found %u answers for %s\n",
		   list_count(&rrl), qname);

	for (le = rrl.head; le; le = le->next) {
		struct dnsrr *rr = le->data;

		err = dns_rr_encode(mb, rr, 0, NULL, start);
		if (err)
			goto out;
	}

	mb->pos = start;

	(void)udp_send(srv->us, src, mb);

 out:
	list_clear(&rrl);
	mem_deref(qname);
}
示例#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);
}