Beispiel #1
0
/**
 * Compare local and remote candidates of two candidate pairs
 *
 * @param cp1  First Candidate pair
 * @param cp2  Second Candidate pair
 *
 * @return true if match
 */
bool icem_candpair_cmp(const struct candpair *cp1, const struct candpair *cp2)
{
	if (!sa_cmp(&cp1->lcand->addr, &cp2->lcand->addr, SA_ALL))
		return false;

	return sa_cmp(&cp1->rcand->addr, &cp2->rcand->addr, SA_ALL);
}
static void tcp_estab_handler(void *arg)
{
	struct ice_tcpconn *conn = arg;
	struct trice *icem = conn->icem;
	struct le *le;
	int err;

	conn->estab = true;

	trice_printf(icem, "TCP established (local=%J <---> peer=%J)\n",
		    &conn->laddr, &conn->paddr);

	err = shim_insert(&conn->shim, conn->tc, conn->layer,
			  shim_frame_handler, conn);
	if (err)
		goto out;

	if (!icem->checklist)
		goto out;

	/* check all pending CONNCHECKs for TCP */
	le = icem->checklist->conncheckl.head;
	while (le) {
		struct ice_conncheck *cc = le->data;
		struct ice_candpair *pair = cc->pair;
		le = le->next;

		if (pair->state == ICE_CANDPAIR_INPROGRESS &&
		    pair->lcand->attr.compid == conn->compid &&
		    pair->lcand->attr.proto == IPPROTO_TCP &&
		    sa_cmp(&pair->lcand->attr.addr, &conn->laddr, SA_ADDR) &&
		    sa_cmp(&pair->rcand->attr.addr, &conn->paddr, SA_ALL)) {

			trice_printf(icem,
				    "   estab: sending pending check"
				    " from %j to %J\n",
				    &pair->lcand->attr.addr,
				    &pair->rcand->attr.addr);

			/* todo: */
			pair->conn = mem_ref(conn);

			err = trice_conncheck_stun_request(icem->checklist, cc,
							 pair, conn->tc,
							 cc->use_cand);
			if (err) {
				DEBUG_WARNING("stun_request error (%m)\n",
					      err);
			}
		}
	}

 out:
	if (err) {
		DEBUG_WARNING("estab: errors (%m)\n", err);
	}
}
Beispiel #3
0
static void *unique_handler(struct le *le1, struct le *le2)
{
	struct candpair *cp1 = le1->data, *cp2 = le2->data;

	if (!sa_cmp(cand_srflx_addr(cp1->lcand),
		    cand_srflx_addr(cp2->lcand), SA_ALL) ||
	    !sa_cmp(&cp1->rcand->addr, &cp2->rcand->addr, SA_ALL))
		return NULL;

	return cp1->pprio < cp2->pprio ? cp1 : cp2;
}
Beispiel #4
0
/* Incoming data from TURN-server */
static void data_handler(struct allocation *alloc, const struct sa *src,
			 struct mbuf *mb)
{
	int err;

	if (!alloc->ok) {
		re_fprintf(stderr, "allocation not ready"
			   " -- ignore %zu bytes from %J\n",
			   mbuf_get_left(mb), src);
		return;
	}

	if (!sa_cmp(src, &alloc->peer, SA_ALL)) {

		re_printf("updating peer address:  %J  -->  %J\n",
			  &alloc->peer, src);

		alloc->peer = *src;

		if (!alloc->turn_ind)
			turnc_add_chan(alloc->turnc, src, NULL, NULL);

		tmr_start(&alloc->tmr_ping, PING_INTERVAL,
			  tmr_ping_handler, alloc);
	}

	err = receiver_recv(&alloc->recv, src, mb);
	if (err) {
		re_fprintf(stderr, "corrupt packet coming from %J (%m)\n",
			   src, err);
	}
}
Beispiel #5
0
static void udp_recv_client(const struct sa *src, struct mbuf *mb, void *arg)
{
	struct udp_test *ut = arg;

	switch (ut->tindex++) {

	case 0:
		if (!mbuf_compare(mb, data0)) {
			ut->err = EBADMSG;
			break;
		}
		if (!sa_cmp(src, &ut->srv, SA_ALL)) {
			ut->err = EPROTO;
			break;
		}
		break;

	default:
		ut->err = ERANGE;
		break;
	}

	if (ut->tindex >= 1)
		re_cancel();
}
Beispiel #6
0
static bool hash_cmp_handler(struct le *le, void *arg)
{
	const struct allocation *al = le->data;
	const struct tuple *tup = arg;

	if (!sa_cmp(&al->cli_addr, tup->cli_addr, SA_ALL))
		return false;

	if (!sa_cmp(&al->srv_addr, tup->srv_addr, SA_ALL))
		return false;

	if (al->proto != tup->proto)
		return false;

	return true;
}
Beispiel #7
0
static bool tcpconn_cmp_handler(struct le *le, void *arg)
{
	const struct tcpconn *tc = le->data;

	/* avoid trying this connection if dead */
	if (!tc->conn)
		return false;

	return sa_cmp(&tc->srv, arg, SA_ALL);
}
static void *unique_handler(struct le *le1, struct le *le2)
{
	struct ice_cand *c1 = le1->data, *c2 = le2->data;

	if (c1->base != c2->base || !sa_cmp(&c1->addr, &c2->addr, SA_ALL))
		return NULL;

	/* remove candidate with lower priority */
	return c1->prio < c2->prio ? c1 : c2;
}
Beispiel #9
0
static bool interface_find(const struct agent *ag, const struct sa *addr)
{
	unsigned i;

	for (i=0; i<ag->interfacec; i++) {

		if (sa_cmp(addr, &ag->interfacev[i], SA_ADDR))
			return true;
	}

	return false;
}
Beispiel #10
0
static void turnc_handler(int err, uint16_t scode, const char *reason,
			  const struct sa *relay, const struct sa *mapped,
			  const struct stun_msg *msg, void *arg)
{
	struct icem_comp *comp = arg;
	struct icem *icem = comp->icem;
	struct cand *lcand;
	(void)msg;

	--icem->nstun;

	/* TURN failed, so we destroy the client */
	if (err || scode) {
		comp->turnc = mem_deref(comp->turnc);
	}

	if (err) {
		DEBUG_WARNING("{%s.%u} TURN Client error: %m\n",
			      icem->name, comp->id, err);
		goto out;
	}

	if (scode) {
		DEBUG_WARNING("{%s.%u} TURN Client error: %u %s\n",
			      icem->name, comp->id, scode, reason);
		err = send_binding_request(icem, comp);
		if (err)
			goto out;
		return;
	}

	lcand = icem_cand_find(&icem->lcandl, comp->id, NULL);
	if (!lcand)
		goto out;

	if (!sa_cmp(relay, &lcand->base->addr, SA_ALL)) {
		err = icem_lcand_add(icem, lcand->base,
				     CAND_TYPE_RELAY, relay);
	}

	if (mapped) {
		err |= icem_lcand_add(icem, lcand->base,
				      CAND_TYPE_SRFLX, mapped);
	}
	else {
		err |= send_binding_request(icem, comp);
	}

 out:
	call_gather_handler(err, icem, scode, reason);
}
Beispiel #11
0
static bool udp_helper_recv(struct sa *src, struct mbuf *mb, void *arg)
{
	struct udp_test *ut = arg;

	if (!sa_cmp(src, &ut->srv, SA_ALL))
		ut->err = EPROTO;

	mb->end -= 4;

	if (!mbuf_compare(mb, data0))
		ut->err = EBADMSG;

	return false;
}
/* NOTE: laddr matching is SA_ADDR only */
struct ice_tcpconn *trice_conn_find(struct list *connl, unsigned compid,
				  const struct sa *laddr,
				  const struct sa *peer)
{
	struct le *le;

	for (le = list_head(connl); le; le = le->next) {

		struct ice_tcpconn *conn = le->data;

		if (compid != conn->compid)
			continue;

		/* NOTE: only for established */
		if (!conn->estab)
			continue;

		if (sa_cmp(laddr, &conn->laddr, SA_ADDR) &&
		    sa_cmp(peer, &conn->paddr, SA_ALL))
			return conn;
	}

	return NULL;
}
Beispiel #13
0
static bool recv_handler(struct sa *src, struct mbuf *mb, void *arg)
{
	struct dtls_flow *flow = arg;
	uint8_t b;
	int r, n;

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

	/* ignore non-DTLS packets */
	b = mb->buf[mb->pos];
	if (b < 20 || b > 63)
		return false;

	if (!sa_cmp(src, &flow->peer, SA_ALL))
		return false;

	/* feed SSL data to the BIO */
	r = BIO_write(flow->sbio_in, mbuf_buf(mb), (int)mbuf_get_left(mb));
	if (r <= 0)
		return true;

	n = SSL_read(flow->ssl, mbuf_buf(mb), (int)mbuf_get_space(mb));
	if (n <= 0) {
		ERR_clear_error();
	}

	if (!flow->up && SSL_state(flow->ssl) == SSL_ST_OK) {

		struct key client_key, server_key;
		char profile[256];
		int err;

		flow->up = true;

		err = get_srtp_key_info(flow, profile, sizeof(profile),
					&client_key, &server_key);
		if (err) {
			warning("dtls: SRTP key info: %m\n", err);
			return true;
		}

		flow->estabh(0, flow, profile,
			     &client_key, &server_key, flow->arg);
	}

	return true;
}
Beispiel #14
0
static bool if_getname_handler(const char *ifname, const struct sa *sa,
			       void *arg)
{
	struct ifentry *ife = arg;

	if (ife->af != sa_af(sa))
		return false;

	if (0 == sa_cmp(sa, ife->ip, SA_ADDR)) {
		str_ncpy(ife->ifname, ifname, ife->sz);
		ife->found = true;
		return true;
	}

	return false;
}
Beispiel #15
0
static struct channel *find_channel_peer(struct turnserver *tt,
					 const struct sa *peer)
{
	size_t i;

	if (!tt)
		return NULL;

	for (i=0; i<tt->chanc; i++) {

		if (sa_cmp(&tt->chanv[i].peer, peer, SA_ALL))
			return &tt->chanv[i];
	}

	return NULL;
}
Beispiel #16
0
static struct sa *find_permission(struct turnserver *tt,
				  const struct sa *peer)
{
	size_t i;

	if (!tt)
		return NULL;

	for (i=0; i<tt->permc; i++) {

		if (sa_cmp(&tt->permv[i], peer, SA_ADDR))
			return &tt->permv[i];
	}

	return NULL;
}
TEST(media, ice_cand_decode)
{
	struct ice_cand_attr cand;
	struct sa addr;
	int err;

	err = ice_cand_attr_decode(&cand,
			      "42 1 udp 2113937151 10.0.0.63 2004 typ host");
	ASSERT_EQ(0, err);

	sa_set_str(&addr, "10.0.0.63", 2004);

	ASSERT_STREQ("42", cand.foundation);
	ASSERT_EQ(1, cand.compid);
	ASSERT_EQ(IPPROTO_UDP, cand.proto);
	ASSERT_EQ(2113937151, cand.prio);
	ASSERT_TRUE(sa_cmp(&addr, &cand.addr, SA_ALL));
	ASSERT_EQ(ICE_CAND_TYPE_HOST, cand.type);
}
Beispiel #18
0
struct cand *icem_cand_find(const struct list *lst, uint8_t compid,
			    const struct sa *addr)
{
	struct le *le;

	for (le = list_head(lst); le; le = le->next) {

		struct cand *cand = le->data;

		if (compid && cand->compid != compid)
			continue;

		if (addr && !sa_cmp(&cand->addr, addr, SA_ALL))
			continue;

		return cand;
	}

	return NULL;
}
/* todo: re-connect if estab and active (with a timer) */
static void tcp_close_handler(int err, void *arg)
{
	struct ice_tcpconn *conn = arg;
	struct trice *icem = conn->icem;
	struct le *le;

	trice_printf(conn->icem, "TCP-connection [%J -> %J] closed (%m)\n",
		    &conn->laddr, &conn->paddr, err);

	err = err ? err : ECONNRESET;

	/* note: helper must be closed before tc */
	conn->shim = mem_deref(conn->shim);
	conn->tc = mem_deref(conn->tc);

	/* todo: iterate through conncheckl and cancel all checks
	 * that are using this conn
	 */

	le = conn->icem->checkl.head;
	while (le) {
		struct ice_candpair *pair = le->data;

		le = le->next;

		if (pair->lcand->attr.compid == conn->compid &&
		    pair->lcand->attr.proto == IPPROTO_TCP &&
		    sa_cmp(&pair->rcand->attr.addr, &conn->paddr, SA_ALL)) {

			trice_candpair_failed(pair, err, 0);

			if (icem->checklist) {
				icem->checklist->failh(err, 0,
						       pair,
						       icem->checklist->arg);
			}
		}
	}

	mem_deref(conn);
}
Beispiel #20
0
struct udp_sock *restund_udp_socket(struct sa *sa, const struct sa *orig,
                                    bool ch_ip, bool ch_port)
{
    struct le *le = list_head(&lstnrl);

    while (le) {
        struct udp_lstnr *ul = le->data;
        le = le->next;

        if (ch_ip && sa_cmp(orig, &ul->bnd_addr, SA_PORT))
            continue;

        if (ch_port && (sa_port(orig) == sa_port(&ul->bnd_addr)))
            continue;

        sa_cpy(sa, &ul->bnd_addr);
        return ul->us;
    }

    return NULL;
}
static void stun_response_handler(int err, uint16_t scode, const char *reason,
				  const struct stun_msg *msg, void *arg)
{
	struct sip_udpconn *uc = arg;
	struct stun_attr *attr;
	(void)reason;

	if (err || scode) {
		err = err ? err : EPROTO;
		goto out;
	}

	attr = stun_msg_attr(msg, STUN_ATTR_XOR_MAPPED_ADDR);
	if (!attr) {
		attr = stun_msg_attr(msg, STUN_ATTR_MAPPED_ADDR);
		if (!attr) {
			err = EPROTO;
			goto out;
		}
	}

	if (!sa_isset(&uc->maddr, SA_ALL)) {
		uc->maddr = attr->v.sa;
	}
	else if (!sa_cmp(&uc->maddr, &attr->v.sa, SA_ALL)) {
		err = ENOTCONN;
		goto out;
	}

 out:
	if (err) {
		udpconn_close(uc, err);
		mem_deref(uc);
	}
	else {
		tmr_start(&uc->tmr_ka, sip_keepalive_wait(uc->ka_interval),
			  udpconn_keepalive_handler, uc);
	}
}
static struct sip_udpconn *udpconn_find(struct sip *sip, struct udp_sock *us,
					const struct sa *paddr)
{
	struct le *le;

	le = list_head(hash_list(sip->ht_udpconn, sa_hash(paddr, SA_ALL)));

	for (; le; le = le->next) {

		struct sip_udpconn *uc = le->data;

		if (!sa_cmp(&uc->paddr, paddr, SA_ALL))
			continue;

		if (uc->us != us)
			continue;

		return uc;
	}

	return NULL;
}
Beispiel #23
0
static struct sip_conn *conn_find(struct sip *sip, const struct sa *paddr,
				  bool secure)
{
	struct le *le;

	le = list_head(hash_list(sip->ht_conn, sa_hash(paddr, SA_ALL)));

	for (; le; le = le->next) {

		struct sip_conn *conn = le->data;

		if (!secure != (conn->sc == NULL))
			continue;

		if (!sa_cmp(&conn->paddr, paddr, SA_ALL))
			continue;

		return conn;
	}

	return NULL;
}
Beispiel #24
0
struct ice_lcand *trice_lcand_find(struct trice *icem,
				   enum ice_cand_type type,
				   unsigned compid, int proto,
				   const struct sa *addr)
{
	struct list *lst;
	struct le *le;

	if (!icem)
		return NULL;

	if (!proto) {
		DEBUG_WARNING("find_candidate: invalid args\n");
		return NULL;
	}

	lst = &icem->lcandl;

	for (le = list_head(lst); le; le = le->next) {

		struct ice_cand_attr *cand = le->data;

		if (type != (enum ice_cand_type)-1 && type != cand->type)
			continue;

		if (compid && cand->compid != compid)
			continue;

		if (cand->proto != proto)
			continue;

		if (addr && !sa_cmp(&cand->addr, addr, SA_ALL))
			continue;

		return (void *)cand;
	}

	return NULL;
}
Beispiel #25
0
/**
 * Check if network address is part of SIP transports
 *
 * @param sip   SIP stack instance
 * @param tp    SIP transport
 * @param laddr Local network address to check
 *
 * @return True if part of SIP transports, otherwise false
 */
bool sip_transp_isladdr(const struct sip *sip, enum sip_transp tp,
			const struct sa *laddr)
{
	struct le *le;

	if (!sip || !laddr)
		return false;

	for (le=sip->transpl.head; le; le=le->next) {

		const struct sip_transport *transp = le->data;

		if (tp != SIP_TRANSP_NONE && transp->tp != tp)
			continue;

		if (!sa_cmp(&transp->laddr, laddr, SA_ALL))
			continue;

		return true;
	}

	return false;
}
Beispiel #26
0
static bool udp_helper_send(int *err, struct sa *dst,
			    struct mbuf *mb, void *arg)
{
	struct udp_test *ut = arg;
	const size_t pos = mb->pos;

	if (!sa_cmp(dst, &ut->srv, SA_ALL)) {
		*err = EPROTO;
		return false;
	}

	if (!mbuf_compare(mb, data0)) {
		*err = EBADMSG;
		return false;
	}

	/* Append a fake protocol trailer */
	mb->pos = mb->end;
	*err = mbuf_write_str(mb, "XXXX");

	mb->pos = pos;

	return false;
}
Beispiel #27
0
static bool hash_peer_cmp_handler(struct le *le, void *arg)
{
	const struct chan *chan = le->data;

	return sa_cmp(&chan->peer, arg, SA_ALL);
}
Beispiel #28
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;
}
Beispiel #29
0
static bool hash_cmp_handler(struct le *le, void *arg)
{
	const struct perm *perm = le->data;

	return sa_cmp(&perm->peer, arg, SA_ADDR);
}
Beispiel #30
0
static void stun_response_handler(int err, uint16_t scode, const char *reason,
				  const struct stun_msg *msg, void *arg)
{
	struct nat_mapping *nm = arg;
	struct stun_attr *map, *other;

	if (err) {
		DEBUG_WARNING("stun_response_handler: (%m)\n", err);
		nm->mh(err, NAT_TYPE_UNKNOWN, nm->arg);
		return;
	}

	switch (scode) {

	case 0:
		other = stun_msg_attr(msg, STUN_ATTR_OTHER_ADDR);
		map = stun_msg_attr(msg, STUN_ATTR_XOR_MAPPED_ADDR);
		if (!map)
			map = stun_msg_attr(msg, STUN_ATTR_MAPPED_ADDR);

		if (!map || !other) {
			DEBUG_WARNING("missing attributes: %s %s\n",
				      map   ? "" : "MAPPED-ADDR",
				      other ? "" : "OTHER-ADDR");
			nm->mh(EPROTO, NAT_TYPE_UNKNOWN, nm->arg);
			return;
		}

		nm->map[nm->test_phase-1] = map->v.sa;
		break;

	default:
		DEBUG_WARNING("Binding Error Resp: %u %s\n", scode, reason);
		nm->mh(EPROTO, NAT_TYPE_UNKNOWN, nm->arg);
		return;
	}

	switch (nm->test_phase) {

	case 1:
		/* Test I completed */
		if (sa_cmp(&nm->laddr, &nm->map[0], SA_ALL)) {
			nm->mh(0, NAT_TYPE_ENDP_INDEP, nm->arg);
			return;
		}

		/* Start Test II - the client sends a Binding Request to the
		   alternate *address* */
		++nm->test_phase;

		sa_set_port(&other->v.other_addr, sa_port(&nm->srv));
		sa_cpy(&nm->srv, &other->v.other_addr);

		err = mapping_send(nm);
		if (err) {
			DEBUG_WARNING("stunc_request_send: (%m)\n", err);
			nm->mh(err, NAT_TYPE_UNKNOWN, nm->arg);
		}
		break;

	case 2:
		/* Test II completed */
		if (sa_cmp(&nm->map[0], &nm->map[1], SA_ALL)) {
			nm->mh(0, NAT_TYPE_ENDP_INDEP, nm->arg);
			return;
		}

		/* Start Test III - the client sends a Binding Request
		   to the alternate address and port */
		++nm->test_phase;

		sa_set_port(&nm->srv, sa_port(&other->v.other_addr));
		err = mapping_send(nm);
		if (err) {
			DEBUG_WARNING("stunc_request_send: (%m)\n", err);
			nm->mh(err, NAT_TYPE_UNKNOWN, nm->arg);
		}
		break;

	case 3:
		/* Test III completed */
		if (sa_cmp(&nm->map[1], &nm->map[2], SA_ALL)) {
			nm->mh(0, NAT_TYPE_ADDR_DEP, nm->arg);
		}
		else {
			nm->mh(0, NAT_TYPE_ADDR_PORT_DEP, nm->arg);
		}
		++nm->test_phase;
		break;

	default:
		DEBUG_WARNING("invalid test phase %d\n", nm->test_phase);
		nm->mh(EINVAL, NAT_TYPE_UNKNOWN, nm->arg);
		break;
	}
}