Пример #1
0
/* add TURN permission to all known remotes */
static int candidate_add_permissions(struct candidate *candidate)
{
	struct le *le;
	struct trice *icem;
	int err = 0;

	if (candidate->type != TYPE_TURN || !candidate->turn_ok)
		return 0;

	icem = candidate->ag->icem;
	for (le = list_head(trice_rcandl(icem)); le; le = le->next) {

		struct ice_rcand *rcand = le->data;
		struct ice_lcand *base = candidate->base;

		if (rcand->attr.proto == IPPROTO_UDP &&
		    rcand->attr.compid == base->attr.compid &&
		    sa_af(&rcand->attr.addr) == sa_af(&base->attr.addr)) {

			err |= turnc_add_perm(candidate->turnc,
					      &rcand->attr.addr,
					      turnc_perm_handler, rcand);
		}
	}

	return err;
}
Пример #2
0
/**
 * Forming Candidate Pairs
 */
static int candpairs_form(struct icem *icem)
{
	struct le *le;
	int err = 0;

	if (list_isempty(&icem->lcandl))
		return ENOENT;

	for (le = icem->lcandl.head; le; le = le->next) {

		struct cand *lcand = le->data;
		struct le *rle;

		for (rle = icem->rcandl.head; rle; rle = rle->next) {

			struct cand *rcand = rle->data;

			if (lcand->compid != rcand->compid)
				continue;

			if (sa_af(&lcand->addr) != sa_af(&rcand->addr))
				continue;

			err |= icem_candpair_alloc(NULL, icem, lcand, rcand);
		}
	}

	return err;
}
Пример #3
0
static int add_candidate(struct agent *ag, const struct sa *addr,
			 int proto, enum ice_tcptype tcptype,
			 const char *ifname)
{
	struct ice_lcand *lcand;
	uint32_t prio;
	int err;

	prio = calc_prio(ICE_CAND_TYPE_HOST, proto, tcptype, sa_af(addr),
			 proto);

	err = trice_lcand_add(&lcand, ag->icem, COMPID, proto,
			      prio, addr, NULL, ICE_CAND_TYPE_HOST, NULL,
			      tcptype, NULL, LAYER_ICE);
	if (err) {
		re_fprintf(stderr, "failed to add local candidate (%m)\n",
			   err);
		return err;
	}

	str_ncpy(lcand->ifname, ifname, sizeof(lcand->ifname));

	err = control_send_message(ag->cli, "a=candidate:%H\r\n",
				   ice_cand_attr_encode, &lcand->attr);
	if (err)
		return err;

	/* gather SRFLX candidates */
	if (ag->cli->param.stun_server) {

		if (proto == IPPROTO_UDP ||
		    (proto == IPPROTO_TCP && tcptype != ICE_TCP_ACTIVE)) {

			gather_srflx(ag, lcand, proto);
		}
	}

	/* gather RELAY candidates, NOTE IPv4 only */
	if (ag->cli->param.turn_server) {
		if (proto == IPPROTO_UDP && sa_af(addr)==AF_INET) {

			gather_relay(ag, lcand, IPPROTO_UDP);
			gather_relay(ag, lcand, IPPROTO_TCP);
		}
	}

	return err;
}
Пример #4
0
static int stream_sock_alloc(struct stream *s, int af)
{
	struct sa laddr;
	int tos, err;

	if (!s)
		return EINVAL;

	/* we listen on all interfaces */
	sa_init(&laddr, sa_af(net_laddr_af(af)));

	err = rtp_listen(&s->rtp, IPPROTO_UDP, &laddr,
			 config.avt.rtp_ports.min, config.avt.rtp_ports.max,
			 s->rtcp, rtp_recv, rtcp_handler, s);
	if (err)
		return err;

	tos = config.avt.rtp_tos;
	(void)udp_setsockopt(rtp_sock(s->rtp), IPPROTO_IP, IP_TOS,
			     &tos, sizeof(tos));
	(void)udp_setsockopt(rtcp_sock(s->rtp), IPPROTO_IP, IP_TOS,
			     &tos, sizeof(tos));

	udp_rxsz_set(rtp_sock(s->rtp), RTP_RECV_SIZE);

	return 0;
}
Пример #5
0
static void lstnr_handler(struct sa *bnd_addr, struct udp_sock *us,
			  void *arg)
{
	const char *maddr;
	struct sa dst;
	int err;

	(void)arg;

	switch (sa_af(bnd_addr)) {

	case AF_INET:
		maddr = "224.0.0.1";
		break;

	case AF_INET6:
		maddr = "ff02::1";
		break;

	default:
		return;
	}

	sa_set_str(&dst, maddr, PCP_PORT_CLI);

	err = pcp_reply(us, &dst, NULL, PCP_ANNOUNCE, PCP_SUCCESS,
			0, repcpd_epoch_time(), NULL);
	if (err) {
		warning("announce: failed to send ANNOUNCE from"
			" %J to %s (%m)\n", bnd_addr, maddr, err);
		return;
	}

	info("announce: sent ANNOUNCE from %J to %s\n", bnd_addr, maddr);
}
Пример #6
0
/**
 * Get the Link-local address for a specific network interface
 *
 * @param ifname Name of the interface
 * @param af     Address family
 * @param ip     Returned link-local address
 *
 * @return 0 if success, otherwise errorcode
 */
int net_if_getlinklocal(const char *ifname, int af, struct sa *ip)
{
	struct sa addr;
	void *argv[3];
	int err;

	if (!ip)
		return EINVAL;

	sa_init(&addr, sa_af(ip));

	argv[0] = (void *)ifname;
	argv[1] = ⁡
	argv[2] = &addr;

	err = net_if_apply(linklocal_handler, argv);
	if (err)
		return err;

	if (!sa_isset(&addr, SA_ADDR))
		return ENOENT;

	*ip = addr;

	return 0;
}
Пример #7
0
static bool if_getaddr_handler(const char *ifname,
			       const struct sa *sa, void *arg)
{
	struct ifentry *ife = arg;

	/* Match name of interface? */
	if (str_isset(ife->ifname) && 0 != str_casecmp(ife->ifname, ifname))
		return false;

	if (!sa_isset(sa, SA_ADDR))
		return false;

#if 1
	/* skip loopback and link-local IP */
	if (sa_is_loopback(sa) || sa_is_linklocal(sa))
		return false;
#endif

	/* Match address family */
	if (ife->af != sa_af(sa))
		return false;

	/* Match - copy address */
	sa_cpy(ife->ip, sa);
	ife->found = true;

	return ife->found;
}
Пример #8
0
Файл: pcp.c Проект: GGGO/baresip
static int media_alloc(struct mnat_media **mp, struct mnat_sess *sess,
		       int proto, void *sock1, void *sock2,
		       struct sdp_media *sdpm)
{
	struct mnat_media *m;
	struct sa laddr;
	struct pcp_map map;
	unsigned i;
	int err = 0;

	if (!mp || !sess || !sdpm || proto != IPPROTO_UDP)
		return EINVAL;

	m = mem_zalloc(sizeof(*m), media_destructor);
	if (!m)
		return ENOMEM;

	m->compc = sock2 ? 2 : 1;

	list_append(&sess->medial, &m->le, m);
	m->sess = sess;
	m->sdpm = mem_ref(sdpm);

	for (i=0; i<m->compc; i++) {
		struct comp *comp = &m->compv[i];

		comp->id = i+1;
		comp->media = m;

		err = udp_local_get(i==0 ? sock1 : sock2, &laddr);
		if (err)
			goto out;

		rand_bytes(map.nonce, sizeof(map.nonce));
		map.proto = proto;
		map.int_port = sa_port(&laddr);
		/* note: using same address-family as the PCP server */
		sa_init(&map.ext_addr, sa_af(&pcp_srv));

		info("pcp: %s: internal port for %s is %u\n",
		     sdp_media_name(sdpm),
		     i==0 ? "RTP" : "RTCP",
		     map.int_port);

		err = pcp_request(&comp->pcp, NULL, &pcp_srv, PCP_MAP,
				  LIFETIME, &map, pcp_resp_handler, comp, 0);
		if (err)
			goto out;
	}

 out:
	if (err)
		mem_deref(m);
	else if (mp) {
		*mp = m;
	}

	return err;
}
Пример #9
0
int allocation_create(struct allocator *allocator, unsigned ix, int proto,
		      const struct sa *srv,
		      const char *username, const char *password,
		      struct tls *tls, bool turn_ind,
		      allocation_h *alloch, void *arg)
{
	struct allocation *alloc;
	struct sa laddr;
	int err;

	if (!allocator || !proto || !srv)
		return EINVAL;

	sa_init(&laddr, sa_af(srv));

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

	list_append(&allocator->allocl, &alloc->le, alloc);

	(void)gettimeofday(&alloc->sent, NULL);

	alloc->atime     = -1;
	alloc->ix        = ix;
	alloc->allocator = allocator;
	alloc->proto     = proto;
	alloc->secure    = tls != NULL;
	alloc->srv       = *srv;
	alloc->user      = username;
	alloc->pass      = password;
	alloc->turn_ind  = turn_ind;
	alloc->alloch    = alloch;
	alloc->arg       = arg;
	alloc->tls       = mem_ref(tls);

	receiver_init(&alloc->recv, allocator->session_cookie, alloc->ix);

	err = udp_listen(&alloc->us_tx, &laddr, NULL, NULL);
	if (err) {
		re_fprintf(stderr, "allocation: failed to create UDP tx socket"
			   " (%m)\n", err);
		goto out;
	}

	udp_local_get(alloc->us_tx, &alloc->laddr_tx);

	err = start(alloc);
	if (err)
		goto out;

 out:
	if (err)
		mem_deref(alloc);

	return err;
}
Пример #10
0
static bool interface_handler(const char *ifname, const struct sa *addr,
			      void *arg)
{
	struct agent *ag = arg;
	int err = 0;

	/* Skip loopback and link-local addresses */
	if (ag->cli->param.skip_local) {

		if (sa_is_loopback(addr) || sa_is_linklocal(addr))
			return false;
	}

	if (str_isset(ag->cli->param.ifname) &&
	    str_casecmp(ag->cli->param.ifname, ifname)) {
		return false;
	}

	switch (sa_af(addr)) {

	case AF_INET:
		if (!ag->cli->param.use_ipv4)
			return false;
		break;

	case AF_INET6:
		if (!ag->cli->param.use_ipv6)
			return false;
		break;
	}

	/* NOTE: on some machines an interface is listed twice. */
	if (interface_find(ag, addr)) {
		re_printf("ignoring duplicated interface (%s %j)\n",
			  ifname, addr);
		return false;
	}
	ag->interfacev[ag->interfacec++] = *addr;

	re_printf("interface: %s %j\n", ifname, addr);

	if (ag->cli->param.use_udp)
		err |= add_candidate(ag, addr, IPPROTO_UDP, 0, ifname);
	if (ag->cli->param.use_tcp) {
		err |= add_candidate(ag, addr, IPPROTO_TCP, ICE_TCP_SO,
				     ifname);
		err |= add_candidate(ag, addr, IPPROTO_TCP,
			     ag->client ? ICE_TCP_ACTIVE : ICE_TCP_PASSIVE,
			     ifname);
	}

	return err != 0;
}
Пример #11
0
static int udp_send_internal(struct udp_sock *us, const struct sa *dst,
			     struct mbuf *mb, struct le *le)
{
	struct sa hdst;
	int err = 0, fd;

	/* check for error in e.g. connected state */
	if (us->err) {
		err = us->err;
		us->err = 0; /* clear error */
		return err;
	}

	/* choose a socket */
	if (AF_INET6 == sa_af(dst) && -1 != us->fd6)
		fd = us->fd6;
	else
		fd = us->fd;

	/* call helpers in reverse order */
	while (le) {
		struct udp_helper *uh = le->data;

		le = le->prev;

		if (dst != &hdst) {
			sa_cpy(&hdst, dst);
			dst = &hdst;
		}

		if (uh->sendh(&err, &hdst, mb, uh->arg) || err)
			return err;
	}

	/* Connected socket? */
	if (us->conn) {
		if (0 != connect(fd, &dst->u.sa, dst->len)) {
			DEBUG_WARNING("send: connect: %s\n", strerror(errno));
			us->conn = false;
		}

		if (send(fd, BUF_CAST mb->buf + mb->pos, mb->end - mb->pos,
			 0) < 0)
			return errno;
	}
	else {
		if (sendto(fd, BUF_CAST mb->buf + mb->pos, mb->end - mb->pos,
			   0, &dst->u.sa, dst->len) < 0)
			return errno;
	}

	return 0;
}
Пример #12
0
/**
 * Forming Candidate Pairs
 */
static int candpairs_form(struct icem *icem)
{
	struct le *le;
	int err = 0;

	if (list_isempty(&icem->lcandl))
		return ENOENT;

	if (list_isempty(&icem->rcandl)) {
		DEBUG_WARNING("%s: no remote candidates\n", icem->name);
		return ENOENT;
	}

	for (le = icem->lcandl.head; le; le = le->next) {

		struct cand *lcand = le->data;
		struct le *rle;

		for (rle = icem->rcandl.head; rle; rle = rle->next) {

			struct cand *rcand = rle->data;

			if (lcand->compid != rcand->compid)
				continue;

			if (sa_af(&lcand->addr) != sa_af(&rcand->addr))
				continue;

			err = icem_candpair_alloc(NULL, icem, lcand, rcand);
			if (err)
				return err;
		}
	}

	return err;
}
Пример #13
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;
}
Пример #14
0
int sip_transp_laddr(struct sip *sip, struct sa *laddr, enum sip_transp tp,
		      const struct sa *dst)
{
	const struct sip_transport *transp;

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

	transp = transp_find(sip, tp, sa_af(dst), dst);
	if (!transp)
		return EPROTONOSUPPORT;

	*laddr = transp->laddr;

	return 0;
}
Пример #15
0
int sip_transp_send(struct sip_connqent **qentp, struct sip *sip, void *sock,
		    enum sip_transp tp, const struct sa *dst, struct mbuf *mb,
		    sip_transp_h *transph, void *arg)
{
	const struct sip_transport *transp;
	struct sip_conn *conn;
	bool secure = false;
	int err;

	if (!sip || !dst || !mb)
		return EINVAL;

	switch (tp) {

	case SIP_TRANSP_UDP:
		if (!sock) {
			transp = transp_find(sip, tp, sa_af(dst), dst);
			if (!transp)
				return EPROTONOSUPPORT;

			sock = transp->sock;
		}

		err = udp_send(sock, dst, mb);
		break;

	case SIP_TRANSP_TLS:
		secure = true;
		/*@fallthrough@*/

	case SIP_TRANSP_TCP:
		conn = sock;

		if (conn && conn->tc)
			err = tcp_send(conn->tc, mb);
		else
			err = conn_send(qentp, sip, secure, dst, mb,
					transph, arg);
		break;

	default:
		err = EPROTONOSUPPORT;
		break;
	}

	return err;
}
Пример #16
0
static int multicast_update(struct udp_sock *us, const struct sa *group,
			    bool join)
{
	struct ip_mreq mreq;
#ifdef HAVE_INET6
	struct ipv6_mreq mreq6;
#endif
	int err;

	if (!us || !group)
		return EINVAL;

	switch (sa_af(group)) {

	case AF_INET:
		mreq.imr_multiaddr = group->u.in.sin_addr;
		mreq.imr_interface.s_addr = 0;

		err = udp_setsockopt(us, IPPROTO_IP,
				     join
				     ? IP_ADD_MEMBERSHIP
				     : IP_DROP_MEMBERSHIP,
				     &mreq, sizeof(mreq));
		break;

#ifdef HAVE_INET6
	case AF_INET6:
		mreq6.ipv6mr_multiaddr = group->u.in6.sin6_addr;
		mreq6.ipv6mr_interface = 0;

		err = udp_setsockopt(us, IPPROTO_IPV6,
				     join
				     ? IPV6_JOIN_GROUP
				     : IPV6_LEAVE_GROUP,
				     &mreq6, sizeof(mreq6));
		break;
#endif

	default:
		return EAFNOSUPPORT;
	}

	return err;
}
Пример #17
0
static bool net_rt_handler(const char *ifname, const struct sa *dst,
			   int dstlen, const struct sa *gw, void *arg)
{
	(void)dstlen;
	(void)arg;

	if (sa_af(dst) != AF_INET)
		return false;

	if (sa_in(dst) == 0) {
		natpmp_srv = *gw;
		sa_set_port(&natpmp_srv, NATPMP_PORT);
		info("natpmp: found default gateway %j on interface '%s'\n",
		     gw, ifname);
		return true;
	}

	return false;
}
Пример #18
0
static inline size_t stun_indlen(const struct sa *sa)
{
	size_t len = STUN_HEADER_SIZE + STUN_ATTR_HEADER_SIZE * 2;

	switch (sa_af(sa)) {

	case AF_INET:
		len += STUN_ATTR_ADDR4_SIZE;
		break;

#ifdef HAVE_INET6
	case AF_INET6:
		len += STUN_ATTR_ADDR6_SIZE;
		break;
#endif
	}

	return len;
}
Пример #19
0
static bool linklocal_handler(const char *ifname, const struct sa *sa,
			      void *arg)
{
	void **argv = arg;
	int af = *(int *)argv[1];

	if (argv[0] && 0 != str_casecmp(argv[0], ifname))
		return false;

	if (af != AF_UNSPEC && af != sa_af(sa))
		return false;

	if (sa_is_linklocal(sa)) {
		*((struct sa *)argv[2]) = *sa;
		return true;
	}

	return false;
}
Пример #20
0
static int gather_relay(struct agent *ag, struct ice_lcand *base,
			int turn_proto)
{
	struct candidate *cand = &ag->candv[ag->candc++];
	const char *proto_name = "";
	int err;

	if (ag->candc >= ARRAY_SIZE(ag->candv))
		return ENOMEM;

	cand->ag = ag;
	cand->base = base;
	cand->type = TYPE_TURN;
	cand->turn_proto = turn_proto;

	switch (turn_proto) {

	case IPPROTO_UDP:
		proto_name = stun_proto_udp;
		break;

	case IPPROTO_TCP:
		proto_name = stun_proto_tcp;
		break;
	}

	re_printf("resolving TURN-server '%s' for %s..\n",
		  ag->cli->param.turn_server, proto_name);

	err = stun_server_discover(&cand->stun_dns, cand->ag->cli->dnsc,
				   stun_usage_relay, proto_name,
				   sa_af(&base->attr.addr),
				   ag->cli->param.turn_server, 0,
				   stun_dns_handler, cand);
	if (err) {
		re_fprintf(stderr, "stun_server_discover failed (%m)\n",
			   err);
		return err;
	}

	return 0;
}
Пример #21
0
static const struct sip_transport *transp_find(struct sip *sip,
					       enum sip_transp tp,
					       int af, const struct sa *dst)
{
	struct le *le;
	(void)dst;

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

		const struct sip_transport *transp = le->data;

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

		if (af != AF_UNSPEC && sa_af(&transp->laddr) != af)
			continue;

		return transp;
	}

	return NULL;
}
Пример #22
0
static void stun_mapped_handler(int err, const struct sa *map, void *arg)
{
	struct candidate *cand = arg;
	struct ice_lcand *lcand=0, *base = cand->base;
	uint32_t prio;

	if (err) {
		re_printf("STUN Request failed: (%m)\n",
			  err);
		goto out;
	}

	re_printf("adding SRFLX candidate %s.%J\n",
		  net_proto2name(base->attr.proto), map);

	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, base->icem, base->attr.compid,
			      base->attr.proto, prio, map,
			      &base->attr.addr, ICE_CAND_TYPE_SRFLX,
			      &base->attr.addr,
			      base->attr.tcptype, NULL, 0);
	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",
				   ice_cand_attr_encode, &lcand->attr);
	if (err)
		goto out;

 out:
	candidate_done(cand);
}
Пример #23
0
struct ice_lcand *trice_lcand_find2(const struct trice *icem,
				    enum ice_cand_type type, int af)
{
	struct le *le;

	if (!icem)
		return NULL;

	for (le = list_head(&icem->lcandl); le; le = le->next) {

		struct ice_cand_attr *cand = le->data;

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

		if (af != sa_af(&cand->addr))
			continue;

		return (void *)cand;
	}

	return NULL;
}
Пример #24
0
int call_accept(struct call *call, struct sipsess_sock *sess_sock,
		const struct sip_msg *msg)
{
	bool got_offer;
	int err;

	if (!call || !msg)
		return EINVAL;

	call->outgoing = false;

	got_offer = (mbuf_get_left(msg->mb) > 0);

	err = pl_strdup(&call->peer_uri, &msg->from.auri);
	if (err)
		return err;

	if (pl_isset(&msg->from.dname)) {
		err = pl_strdup(&call->peer_name, &msg->from.dname);
		if (err)
			return err;
	}

	if (got_offer) {
		struct sdp_media *m;
		const struct sa *raddr;

		err = sdp_decode(call->sdp, msg->mb, true);
		if (err)
			return err;

		call->got_offer = true;

		/*
		 * Each media description in the SDP answer MUST
		 * use the same network type as the corresponding
		 * media description in the offer.
		 *
		 * See RFC 6157
		 */
		m = stream_sdpmedia(audio_strm(call->audio));
		raddr = sdp_media_raddr(m);

		if (sa_af(raddr) != call->af) {
			info("call: incompatible address-family"
			     " (local=%s, remote=%s)\n",
			     net_af2name(call->af),
			     net_af2name(sa_af(raddr)));

			sip_treply(NULL, uag_sip(), msg,
				   488, "Not Acceptable Here");

			call_event_handler(call, CALL_EVENT_CLOSED,
					   "Wrong address family");
			return 0;
		}

		/* Check if we have any common audio codecs, after
		 * the SDP offer has been parsed
		 */
		if (!have_common_audio_codecs(call)) {
			info("call: no common audio codecs - rejected\n");

			sip_treply(NULL, uag_sip(), msg,
				   488, "Not Acceptable Here");

			call_event_handler(call, CALL_EVENT_CLOSED,
					   "No audio codecs");

			return 0;
		}
	}

	err = sipsess_accept(&call->sess, sess_sock, msg, 180, "Ringing",
			     ua_cuser(call->ua), "application/sdp", NULL,
			     auth_handler, call->acc, true,
			     sipsess_offer_handler, sipsess_answer_handler,
			     sipsess_estab_handler, sipsess_info_handler,
			     sipsess_refer_handler, sipsess_close_handler,
			     call, "Allow: %s\r\n", uag_allowed_methods());
	if (err) {
		warning("call: sipsess_accept: %m\n", err);
		return err;
	}

	set_state(call, STATE_INCOMING);

	/* New call */
	tmr_start(&call->tmr_inv, LOCAL_TIMEOUT*1000, invite_timeout, call);

	if (!call->acc->mnat)
		call_event_handler(call, CALL_EVENT_INCOMING, call->peer_uri);

	return err;
}
Пример #25
0
void chanbind_request(struct allocation *al, struct restund_msgctx *ctx,
		      int proto, void *sock, const struct sa *src,
		      const struct stun_msg *msg)
{
	struct chan *chan = NULL, *ch_numb = NULL, *ch_peer;
	struct perm *perm = NULL, *permx = NULL;
	struct stun_attr *chnr, *peer;
	int err = ENOMEM, rerr;

	chnr = stun_msg_attr(msg, STUN_ATTR_CHANNEL_NUMBER);
	peer = stun_msg_attr(msg, STUN_ATTR_XOR_PEER_ADDR);

	if (!chnr || !chan_numb_valid(chnr->v.channel_number) || !peer) {
		restund_info("turn: bad chanbind attributes\n");
		rerr = stun_ereply(proto, sock, src, 0, msg,
				   400, "Bad Attributes",
				   ctx->key, ctx->keylen, ctx->fp, 1,
				   STUN_ATTR_SOFTWARE, restund_software);
		goto out;
	}

	if (sa_af(&peer->v.xor_peer_addr) != sa_af(&al->rel_addr)) {
		restund_info("turn: chanbind peer address family mismatch\n");
		rerr = stun_ereply(proto, sock, src, 0, msg,
				   443, "Peer Address Family Mismatch",
				   ctx->key, ctx->keylen, ctx->fp, 1,
				   STUN_ATTR_SOFTWARE, restund_software);
		goto out;
	}

	ch_numb = chan_numb_find(al->chans, chnr->v.channel_number);
	ch_peer = chan_peer_find(al->chans, &peer->v.xor_peer_addr);

	if (ch_numb != ch_peer) {
		restund_info("turn: channel %p/peer %p already bound\n",
			     ch_numb, ch_peer);
		rerr = stun_ereply(proto, sock, src, 0, msg,
				   400, "Channel/Peer Already Bound",
				   ctx->key, ctx->keylen, ctx->fp, 1,
				   STUN_ATTR_SOFTWARE, restund_software);
		goto out;
	}

	if (!ch_numb) {
		chan = chan_create(al->chans, chnr->v.channel_number,
				   &peer->v.xor_peer_addr, al);
		if (!chan) {
			restund_info("turn: unable to create channel\n");
			rerr = stun_ereply(proto, sock, src, 0, msg,
					  500, "Server Error",
					  ctx->key, ctx->keylen, ctx->fp, 1,
					  STUN_ATTR_SOFTWARE,restund_software);
			goto out;
		}
	}

	permx = perm_find(al->perms, &peer->v.xor_peer_addr);
	if (!permx) {
		perm = perm_create(al->perms, &peer->v.xor_peer_addr, al);
		if (!perm) {
			restund_info("turn: unable to create permission\n");
			rerr = stun_ereply(proto, sock, src, 0, msg,
					  500, "Server Error",
					  ctx->key, ctx->keylen, ctx->fp, 1,
					  STUN_ATTR_SOFTWARE,restund_software);
			goto out;
		}
	}

	err = rerr = stun_reply(proto, sock, src, 0, msg,
				ctx->key, ctx->keylen, ctx->fp, 1,
				STUN_ATTR_SOFTWARE, restund_software);
 out:
	if (rerr)
		restund_warning("turn: chanbind reply: %m\n", rerr);

	if (err) {
		mem_deref(chan);
		mem_deref(perm);
	}
	else {
		chan_refresh(ch_numb);
		perm_refresh(permx);
	}
}
Пример #26
0
static int start(struct allocation *alloc)
{
	struct sa laddr;
	int err = 0;

	if (!alloc)
		return EINVAL;

	sa_init(&laddr, sa_af(&alloc->srv));

	switch (alloc->proto) {

	case IPPROTO_UDP:
		err = udp_listen(&alloc->us, &laddr, udp_recv, alloc);
		if (err) {
			re_fprintf(stderr, "allocation: failed to"
				   " create UDP socket"
				   " (%m)\n", err);
			goto out;
		}

		udp_sockbuf_set(alloc->us, 524288);

		if (alloc->secure) {

			/* note: re-using UDP socket for DTLS-traffic */
			err = dtls_listen(&alloc->dtls_sock, NULL, alloc->us,
					  2, DTLS_LAYER, NULL, NULL);
			if (err) {
				re_fprintf(stderr, "dtls_listen error: %m\n",
					   err);
				goto out;
			}

			err = dtls_connect(&alloc->tlsc, alloc->tls,
					   alloc->dtls_sock, &alloc->srv,
					   dtls_estab_handler,
					   dtls_recv_handler,
					   dtls_close_handler, alloc);
			if (err) {
				re_fprintf(stderr, "dtls_connect error: %m\n",
					   err);
				goto out;
			}
		}
		else {
			err = turnc_alloc(&alloc->turnc, NULL, IPPROTO_UDP,
					  alloc->us, TURN_LAYER, &alloc->srv,
					  alloc->user, alloc->pass,
					  TURN_DEFAULT_LIFETIME,
					  turnc_handler, alloc);
			if (err) {
				re_fprintf(stderr, "allocation: failed to"
					   " create TURN client"
					   " (%m)\n", err);
				goto out;
			}
		}
		break;

	case IPPROTO_TCP:
		err = tcp_connect(&alloc->tc, &alloc->srv, tcp_estab_handler,
				  tcp_recv_handler, tcp_close_handler, alloc);
		if (err)
			break;

		if (alloc->secure) {
			err = tls_start_tcp(&alloc->tlsc, alloc->tls,
					    alloc->tc, 0);
			if (err)
				break;
		}
		break;

	default:
		err = EPROTONOSUPPORT;
		goto out;
	}

 out:
	return err;
}
Пример #27
0
int sdp_encode(struct mbuf **mbp, struct sdp_session *sess, bool offer)
{
	const int ipver = sa_af(&sess->laddr) == AF_INET ? 4 : 6;
	enum sdp_bandwidth i;
	struct mbuf *mb;
	struct le *le;
	int err;

	if (!mbp || !sess)
		return EINVAL;

	mb = mbuf_alloc(512);
	if (!mb)
		return ENOMEM;

	err  = mbuf_printf(mb, "v=%u\r\n", SDP_VERSION);
	err |= mbuf_printf(mb, "o=- %u %u IN IP%d %j\r\n",
			   sess->id, sess->ver++, ipver, &sess->laddr);
	err |= mbuf_write_str(mb, "s=-\r\n");
	err |= mbuf_printf(mb, "c=IN IP%d %j\r\n", ipver, &sess->laddr);

	for (i=SDP_BANDWIDTH_MIN; i<SDP_BANDWIDTH_MAX; i++) {

		if (sess->lbwv[i] < 0)
			continue;

		err |= mbuf_printf(mb, "b=%s:%i\r\n",
				   sdp_bandwidth_name(i), sess->lbwv[i]);
	}

	err |= mbuf_write_str(mb, "t=0 0\r\n");

	for (le = sess->lattrl.head; le; le = le->next)
		err |= mbuf_printf(mb, "%H", sdp_attr_print, le->data);

	for (le=sess->lmedial.head; offer && le;) {

		struct sdp_media *m = le->data;

		le = le->next;

		if (m->disabled)
			continue;

		list_unlink(&m->le);
		list_append(&sess->medial, &m->le, m);
	}

	for (le=sess->medial.head; le; le=le->next) {

		struct sdp_media *m = le->data;

		err |= media_encode(m, mb, offer);
	}

	mb->pos = 0;

	if (err)
		mem_deref(mb);
	else
		*mbp = mb;

	return err;
}
Пример #28
0
static int media_encode(const struct sdp_media *m, struct mbuf *mb, bool offer)
{
	enum sdp_bandwidth i;
	int err, supc = 0;
	bool disabled;
	struct le *le;
	uint16_t port;

	for (le=m->lfmtl.head; le; le=le->next) {

		const struct sdp_format *fmt = le->data;

		if (fmt->sup)
			++supc;
	}

	if (m->disabled || supc == 0 || (!offer && !sa_port(&m->raddr))) {
		disabled = true;
		port = 0;
	}
	else {
		disabled = false;
		port = sa_port(&m->laddr);
	}

	err = mbuf_printf(mb, "m=%s %u %s", m->name, port, m->proto);

	if (disabled) {
		err |= mbuf_write_str(mb, " 0\r\n");
		return err;
	}

	for (le=m->lfmtl.head; le; le=le->next) {

		const struct sdp_format *fmt = le->data;

		if (!fmt->sup)
			continue;

		err |= mbuf_printf(mb, " %s", fmt->id);
	}

	err |= mbuf_write_str(mb, "\r\n");

	if (sa_isset(&m->laddr, SA_ADDR)) {
		const int ipver = sa_af(&m->laddr) == AF_INET ? 4 : 6;
		err |= mbuf_printf(mb, "c=IN IP%d %j\r\n", ipver, &m->laddr);
	}

	for (i=SDP_BANDWIDTH_MIN; i<SDP_BANDWIDTH_MAX; i++) {

		if (m->lbwv[i] < 0)
			continue;

		err |= mbuf_printf(mb, "b=%s:%i\r\n",
				   sdp_bandwidth_name(i), m->lbwv[i]);
	}

	for (le=m->lfmtl.head; le; le=le->next) {

		const struct sdp_format *fmt = le->data;

		if (!fmt->sup || !str_len(fmt->name))
			continue;

		err |= mbuf_printf(mb, "a=rtpmap:%s %s/%u",
				   fmt->id, fmt->name, fmt->srate);

		if (fmt->ch > 1)
			err |= mbuf_printf(mb, "/%u", fmt->ch);

		err |= mbuf_printf(mb, "\r\n");

		if (str_len(fmt->params))
			err |= mbuf_printf(mb, "a=fmtp:%s %s\r\n",
					   fmt->id, fmt->params);
	}

	if (sa_isset(&m->laddr_rtcp, SA_ALL))
		err |= mbuf_printf(mb, "a=rtcp:%u IN IP%d %j\r\n",
				   sa_port(&m->laddr_rtcp),
				   (AF_INET == sa_af(&m->laddr_rtcp)) ? 4 : 6,
				   &m->laddr_rtcp);
	else if (sa_isset(&m->laddr_rtcp, SA_PORT))
		err |= mbuf_printf(mb, "a=rtcp:%u\r\n",
				   sa_port(&m->laddr_rtcp));

	err |= mbuf_printf(mb, "a=%s\r\n",
			   sdp_dir_name(offer ? m->ldir : m->ldir & m->rdir));

	for (le = m->lattrl.head; le; le = le->next)
		err |= mbuf_printf(mb, "%H", sdp_attr_print, le->data);

	return err;
}
Пример #29
0
/**
 * Print a formatted string
 *
 * @param fmt Formatted string
 * @param ap  Variable argument
 * @param vph Print handler
 * @param arg Handler argument
 *
 * @return 0 if success, otherwise errorcode
 *
 * Extensions:
 *
 * <pre>
 *   %b  (char *, size_t)        Buffer string with pointer and length
 *   %r  (struct pl)             Pointer-length object
 *   %w  (uint8_t *, size_t)     Binary buffer to hexadecimal format
 *   %j  (struct sa *)           Socket address - address part only
 *   %J  (struct sa *)           Socket address and port - like 1.2.3.4:1234
 *   %H  (re_printf_h *, void *) Print handler with argument
 *   %v  (char *fmt, va_list *)  Variable argument list
 *   %m  (int)                   Describe an error code
 * </pre>
 *
 * Reserved for the future:
 *
 *   %k
 *   %y
 *
 */
int re_vhprintf(const char *fmt, va_list ap, re_vprintf_h *vph, void *arg)
{
	uint8_t base, *bptr;
	char pch, ch, num[NUM_SIZE], addr[64], msg[256];
	enum length_modifier lenmod = LENMOD_NONE;
	struct re_printf pf;
	bool fm = false, plr = false;
	const struct pl *pl;
	size_t pad = 0, fpad = -1, len, i;
	const char *str, *p = fmt, *p0 = fmt;
	const struct sa *sa;
	re_printf_h *ph;
	void *ph_arg;
	va_list *apl;
	int err = 0;
	void *ptr;
	uint64_t n;
	int64_t sn;
	bool uc = false;
	double dbl;

	if (!fmt || !vph)
		return EINVAL;

	pf.vph = vph;
	pf.arg = arg;

	for (;*p && !err; p++) {

		if (!fm) {
			if (*p != '%')
				continue;

			pch = ' ';
			plr = false;
			pad = 0;
			fpad = -1;
			lenmod = LENMOD_NONE;
			uc = false;

			if (p > p0)
				err |= vph(p0, p - p0, arg);

			fm = true;
			continue;
		}

		fm = false;
		base = 10;

		switch (*p) {

		case '-':
			plr = true;
			fm  = true;
			break;

		case '.':
			fpad = pad;
			pad = 0;
			fm = true;
			break;

		case '%':
			ch = '%';

			err |= vph(&ch, 1, arg);
			break;

		case 'b':
			str = va_arg(ap, const char *);
			len = va_arg(ap, size_t);

			err |= write_padded(str, str ? len : 0, pad, ' ',
					    plr, NULL, vph, arg);
			break;

		case 'c':
			ch = va_arg(ap, int);

			err |= write_padded(&ch, 1, pad, ' ', plr, NULL,
					    vph, arg);
			break;

		case 'd':
		case 'i':
			switch (lenmod) {

			case LENMOD_SIZE:
				sn = va_arg(ap, ssize_t);
				break;

			default:
			case LENMOD_LONG_LONG:
				sn = va_arg(ap, signed long long);
				break;

			case LENMOD_LONG:
				sn = va_arg(ap, signed long);
				break;

			case LENMOD_NONE:
				sn = va_arg(ap, signed);
				break;
			}

			len = local_itoa(num, (sn < 0) ? -sn : sn, base,
					 false);

			err |= write_padded(num, len, pad,
					    plr ? ' ' : pch, plr,
					    (sn < 0) ? prfx_neg : NULL,
					    vph, arg);
			break;

		case 'f':
		case 'F':
			dbl = va_arg(ap, double);

			if (fpad == (size_t)-1) {
				fpad = pad;
				pad  = 0;
			}

			if (isinf(dbl)) {
				err |= write_padded("inf", 3, fpad,
						    ' ', plr, NULL, vph, arg);
			}
			else if (isnan(dbl)) {
				err |= write_padded("nan", 3, fpad,
						    ' ', plr, NULL, vph, arg);
			}
			else {
				len = local_ftoa(num, dbl,
						 pad ? min(pad, DEC_SIZE) : 6);

				err |= write_padded(num, len, fpad,
						    plr ? ' ' : pch, plr,
						    (dbl<0) ? prfx_neg : NULL,
						    vph, arg);
			}
			break;

		case 'H':
			ph     = va_arg(ap, re_printf_h *);
			ph_arg = va_arg(ap, void *);

			if (ph)
				err |= ph(&pf, ph_arg);
			break;

		case 'l':
			++lenmod;
			fm = true;
			break;

		case 'm':
			str = str_error(va_arg(ap, int), msg, sizeof(msg));
			err |= write_padded(str, str_len(str), pad,
					    ' ', plr, NULL, vph, arg);
			break;

		case 'p':
			ptr = va_arg(ap, void *);

			if (ptr) {
				len = local_itoa(num, (unsigned long int)ptr,
						 16, false);
				err |= write_padded(num, len, pad,
						    plr ? ' ' : pch, plr,
						    prfx_hex, vph, arg);
			}
			else {
				err |= write_padded(str_nil,
						    sizeof(str_nil) - 1,
						    pad, ' ', plr, NULL,
						    vph, arg);
			}
			break;

		case 'r':
			pl = va_arg(ap, const struct pl *);

			err |= write_padded(pl ? pl->p : NULL,
					    (pl && pl->p) ? pl->l : 0,
					    pad, ' ', plr, NULL, vph, arg);
			break;

		case 's':
			str = va_arg(ap, const char *);
			err |= write_padded(str, str_len(str), pad,
					    ' ', plr, NULL, vph, arg);
			break;

		case 'X':
			uc = true;
			/*@fallthrough@*/
		case 'x':
			base = 16;
			/*@fallthrough@*/
		case 'u':
			switch (lenmod) {

			case LENMOD_SIZE:
				n = va_arg(ap, size_t);
				break;

			default:
			case LENMOD_LONG_LONG:
				n = va_arg(ap, unsigned long long);
				break;

			case LENMOD_LONG:
				n = va_arg(ap, unsigned long);
				break;

			case LENMOD_NONE:
				n = va_arg(ap, unsigned);
				break;
			}

			len = local_itoa(num, n, base, uc);

			err |= write_padded(num, len, pad,
					    plr ? ' ' : pch, plr, NULL,
					    vph, arg);
			break;

		case 'v':
			str = va_arg(ap, char *);
			apl = va_arg(ap, va_list *);

			if (!str || !apl)
				break;

			err |= re_vhprintf(str, *apl, vph, arg);
			break;

		case 'W':
			uc = true;
			/*@fallthrough@*/
		case 'w':
			bptr = va_arg(ap, uint8_t *);
			len = va_arg(ap, size_t);

			len = bptr ? len : 0;
			pch = plr ? ' ' : pch;

			while (!plr && pad-- > (len * 2))
				err |= vph(&pch, 1, arg);

			for (i=0; i<len; i++) {
				const uint8_t v = *bptr++;
				uint32_t l = local_itoa(num, v, 16, uc);
				err |= write_padded(num, l, 2, '0',
						    false, NULL, vph, arg);
			}

			while (plr && pad-- > (len * 2))
				err |= vph(&pch, 1, arg);

			break;

		case 'z':
			lenmod = LENMOD_SIZE;
			fm = true;
			break;

		case 'j':
			sa = va_arg(ap, struct sa *);
			if (!sa)
				break;
			if (sa_ntop(sa, addr, sizeof(addr))) {
				err |= write_padded("?", 1, pad, ' ',
						    plr, NULL, vph, arg);
				break;
			}
			err |= write_padded(addr, strlen(addr), pad, ' ',
					    plr, NULL, vph, arg);
			break;


		case 'J':
			sa = va_arg(ap, struct sa *);
			if (!sa)
				break;
			if (sa_ntop(sa, addr, sizeof(addr))) {
				err |= write_padded("?", 1, pad, ' ',
						    plr, NULL, vph, arg);
				break;
			}

#ifdef HAVE_INET6
			if (AF_INET6 == sa_af(sa)) {
				ch = '[';
				err |= vph(&ch, 1, arg);
			}
#endif
			err |= write_padded(addr, strlen(addr), pad, ' ',
					    plr, NULL, vph, arg);
#ifdef HAVE_INET6
			if (AF_INET6 == sa_af(sa)) {
				ch = ']';
				err |= vph(&ch, 1, arg);
			}
#endif

			ch = ':';
			err |= vph(&ch, 1, arg);
			len = local_itoa(num, sa_port(sa), 10, false);
			err |= write_padded(num, len, pad,
					    plr ? ' ' : pch, plr, NULL,
					    vph, arg);

			break;

		default:
			if (('0' <= *p) && (*p <= '9')) {
				if (!pad && ('0' == *p)) {
					pch = '0';
				}
				else {
					pad *= 10;
					pad += *p - '0';
				}
				fm = true;
				break;
			}

			ch = '?';

			err |= vph(&ch, 1, arg);
			break;
		}

		if (!fm)
			p0 = p + 1;
	}

	if (!fm && p > p0)
		err |= vph(p0, p - p0, arg);

	return err;
}
Пример #30
0
/**
 * Create and listen on a UDP Socket
 *
 * @param usp   Pointer to returned UDP Socket
 * @param local Local network address
 * @param rh    Receive handler
 * @param arg   Handler argument
 *
 * @return 0 if success, otherwise errorcode
 */
int udp_listen(struct udp_sock **usp, const struct sa *local,
	       udp_recv_h *rh, void *arg)
{
	struct addrinfo hints, *res = NULL, *r;
	struct udp_sock *us = NULL;
	char addr[NET_ADDRSTRLEN];
	char serv[6] = "0";
	int af, error, err = 0;

	if (!usp)
		return EINVAL;

	us = mem_zalloc(sizeof(*us), udp_destructor);
	if (!us)
		return ENOMEM;

	list_init(&us->helpers);

	us->fd  = -1;
	us->fd6 = -1;

	if (local) {
		af = sa_af(local);
		err = sa_ntop(local, addr, sizeof(addr));
		(void)re_snprintf(serv, sizeof(serv), "%u", sa_port(local));
		if (err)
			goto out;
	}
	else {
#ifdef HAVE_INET6
		af = AF_UNSPEC;
#else
		af = AF_INET;
#endif
	}

	memset(&hints, 0, sizeof(hints));
	/* set-up hints structure */
	hints.ai_family   = af;
	hints.ai_flags    = AI_PASSIVE | AI_NUMERICHOST;
	hints.ai_socktype = SOCK_DGRAM;
	hints.ai_protocol = IPPROTO_UDP;

	error = getaddrinfo(local ? addr : NULL, serv, &hints, &res);
	if (error) {
#ifdef WIN32
		DEBUG_WARNING("listen: getaddrinfo: wsaerr=%d\n",
			      WSAGetLastError());
#endif
		DEBUG_WARNING("listen: getaddrinfo: %s:%s (%s)\n",
			      addr, serv, gai_strerror(error));
		err = EADDRNOTAVAIL;
		goto out;
	}

	for (r = res; r; r = r->ai_next) {
		int fd = -1;

		if (us->fd > 0)
			continue;

		DEBUG_INFO("listen: for: af=%d addr=%j\n",
			   r->ai_family, r->ai_addr);

		fd = SOK_CAST socket(r->ai_family, SOCK_DGRAM, IPPROTO_UDP);
		if (fd < 0) {
			err = errno;
			continue;
		}

		err = net_sockopt_blocking_set(fd, false);
		if (err) {
			DEBUG_WARNING("udp listen: nonblock set: %s\n",
				      strerror(err));
			(void)close(fd);
			continue;
		}

		if (bind(fd, r->ai_addr, SIZ_CAST r->ai_addrlen) < 0) {
			err = errno;
			DEBUG_INFO("listen: bind(): %s (%J)\n",
				   strerror(err), local);
			(void)close(fd);
			continue;
		}

		/* Can we do both IPv4 and IPv6 on same socket? */
		if (AF_INET6 == r->ai_family) {
			struct sa sa;
			int on = 1;  /* assume v6only */

#if defined (IPPROTO_IPV6) && defined (IPV6_V6ONLY)
			socklen_t on_len = sizeof(on);
			if (0 != getsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
					    (char *)&on, &on_len)) {
				on = 1;
			}
#endif
			/* Extra check for unspec addr - MAC OS X/Solaris */
			if (0==sa_set_sa(&sa, r->ai_addr) && sa_is_any(&sa)) {
				on = 1;
			}
			DEBUG_INFO("socket %d: IPV6_V6ONLY is %d\n", fd, on);
			if (on) {
				us->fd6 = fd;
				continue;
			}
		}

		/* OK */
		us->fd = fd;
		break;
	}

	freeaddrinfo(res);

	/* We must have at least one socket */
	if (-1 == us->fd && -1 == us->fd6) {
		if (0 == err)
			err = EADDRNOTAVAIL;
		goto out;
	}

	err = udp_thread_attach(us);
	if (err)
		goto out;

	us->rh   = rh ? rh : dummy_udp_recv_handler;
	us->arg  = arg;
	us->rxsz = UDP_RXSZ_DEFAULT;

 out:
	if (err)
		mem_deref(us);
	else
		*usp = us;

	return err;
}