Ejemplo n.º 1
0
Archivo: pcp.c Proyecto: GGGO/baresip
static int module_init(void)
{
	struct pl pl;
	int err;

	if (0 == conf_get(conf_cur(), "pcp_server", &pl)) {
		err = sa_decode(&pcp_srv, pl.p, pl.l);
		if (err)
			return err;
	}
	else {
		err = net_default_gateway_get(net_af(baresip_network()),
					      &pcp_srv);
		if (err)
			return err;
		sa_set_port(&pcp_srv, PCP_PORT_SRV);
	}

	info("pcp: using PCP server at %J\n", &pcp_srv);

#if 1
	/* todo: if multiple applications are listening on port 5350
	   then this will not work */
	err = pcp_listen(&lsnr, &pcp_srv, pcp_msg_handler, 0);
	if (err) {
		info("pcp: could not enable listener: %m\n", err);
		err = 0;
	}
#endif

	return mnat_register(&mnat, "pcp", NULL,
			     session_alloc, media_alloc, NULL);
}
Ejemplo n.º 2
0
void sdp_media_set_lport_rtcp(struct sdp_media *m, uint16_t port)
{
    if (!m)
        return;

    sa_set_port(&m->laddr_rtcp, port);
}
Ejemplo n.º 3
0
int sdp_media_add(struct sdp_media **mp, struct sdp_session *sess,
                  const char *name, uint16_t port, const char *proto)
{
    struct sdp_media *m;
    int err;

    if (!sess || !name || !proto)
        return EINVAL;

    err = media_alloc(&m, &sess->lmedial);
    if (err)
        return err;

    err  = str_dup(&m->name, name);
    err |= str_dup(&m->proto, proto);
    if (err)
        goto out;

    sa_set_port(&m->laddr, port);

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

    return err;
}
Ejemplo n.º 4
0
Archivo: cand.c Proyecto: Issic47/libre
int icem_lcand_add_base(struct icem *icem, uint8_t compid, uint16_t lprio,
			const char *ifname, enum ice_transp transp,
			const struct sa *addr)
{
	struct icem_comp *comp;
	struct cand *cand;
	int err;

	comp = icem_comp_find(icem, compid);
	if (!comp)
		return ENOENT;

	err = cand_alloc(&cand, icem, CAND_TYPE_HOST, compid,
			 ice_calc_prio(CAND_TYPE_HOST, lprio, compid),
			 ifname, transp, addr);
	if (err)
		return err;

	/* the base is itself */
	cand->base = cand;

	sa_set_port(&cand->addr, comp->lport);

	return 0;
}
Ejemplo n.º 5
0
void sdp_media_raddr_rtcp(const struct sdp_media *m, struct sa *raddr)
{
    if (!m || !raddr)
        return;

    if (sa_isset(&m->raddr_rtcp, SA_ALL)) {
        *raddr = m->raddr_rtcp;
    }
    else if (sa_isset(&m->raddr_rtcp, SA_PORT)) {
        *raddr = m->raddr;
        sa_set_port(raddr, sa_port(&m->raddr_rtcp));
    }
    else {
        uint16_t port = sa_port(&m->raddr);

        *raddr = m->raddr;
        sa_set_port(raddr, port ? port + 1 : 0);
    }
}
Ejemplo n.º 6
0
static int media_decode(struct sdp_media **mp, struct sdp_session *sess,
			bool offer, const struct pl *pl)
{
	struct pl name, port, proto, fmtv, fmt;
	struct sdp_media *m;
	int err;

	if (re_regex(pl->p, pl->l, "[a-z]+ [^ ]+ [^ ]+[^]*",
		     &name, &port, &proto, &fmtv))
		return EBADMSG;

	m = list_ledata(*mp ? (*mp)->le.next : sess->medial.head);
	if (!m) {
		if (!offer)
			return EPROTO;

		m = sdp_media_find(sess, &name, &proto);
		if (!m) {
			err = sdp_media_radd(&m, sess, &name, &proto);
			if (err)
				return err;
		}
		else {
			list_unlink(&m->le);
			list_append(&sess->medial, &m->le, m);
		}
	}
	else {
		if (pl_strcmp(&name, m->name))
			return offer ? ENOTSUP : EPROTO;

		if (pl_strcmp(&proto, m->proto))
			return ENOTSUP;
	}

	while (!re_regex(fmtv.p, fmtv.l, " [^ ]+", &fmt)) {

		pl_advance(&fmtv, fmt.p + fmt.l - fmtv.p);

		err = sdp_format_radd(m, &fmt);
		if (err)
			return err;
	}

	m->raddr = sess->raddr;
	sa_set_port(&m->raddr, pl_u32(&port));

	m->rdir = sess->rdir;

	*mp = m;

	return 0;
}
Ejemplo n.º 7
0
int
myrecvfrom(int s, void *buf, int len, unsigned int flags,
           struct sockaddr *from, socklen_t * fromlen,
           union sock_addr *myaddr)
{
    /* There is no way we can get the local address, fudge it */

    bzero(myaddr, sizeof(*myaddr));
    myaddr->sa.sa_family = from->sa_family;
    sa_set_port(myaddr, htons(IPPORT_TFTP));

    return recvfrom(s, buf, len, flags, from, fromlen);
}
Ejemplo n.º 8
0
static void natpmp_resp_handler(int err, const struct natpmp_resp *resp,
				void *arg)
{
	struct comp *comp = arg;
	struct mnat_media *m = comp->media;
	struct sa map_addr;

	if (err) {
		warning("natpmp: response error: %m\n", err);
		complete(m->sess, err);
		return;
	}

	if (resp->op != NATPMP_OP_MAPPING_UDP)
		return;
	if (resp->result != NATPMP_SUCCESS) {
		warning("natpmp: request failed with result code: %d\n",
			resp->result);
		complete(m->sess, EPROTO);
		return;
	}

	if (resp->u.map.int_port != comp->int_port) {
		info("natpmp: ignoring response for internal_port=%u\n",
		     resp->u.map.int_port);
		return;
	}

	info("natpmp: mapping granted for comp %u:"
	     " internal_port=%u, external_port=%u, lifetime=%u\n",
	     comp->id,
	     resp->u.map.int_port, resp->u.map.ext_port,
	     resp->u.map.lifetime);

	map_addr = natpmp_extaddr;
	sa_set_port(&map_addr, resp->u.map.ext_port);
	comp->lifetime = resp->u.map.lifetime;

	/* Update SDP media with external IP-address mapping */
	if (comp->id == 1)
		sdp_media_set_laddr(m->sdpm, &map_addr);
	else
		sdp_media_set_laddr_rtcp(m->sdpm, &map_addr);

	comp->granted = true;

	tmr_start(&comp->tmr, comp->lifetime * 1000 * 3/4,
		  refresh_timeout, comp);

	is_complete(m->sess);
}
Ejemplo n.º 9
0
Archivo: rtp.c Proyecto: hbowden/re
static int udp_range_listen(struct rtp_sock *rs, const struct sa *ip,
			    uint16_t min_port, uint16_t max_port)
{
	struct sa rtcp;
	int tries = 64;
	int err = 0;

	rs->local = rtcp = *ip;

	/* try hard */
	while (tries--) {
		struct udp_sock *us_rtp, *us_rtcp;
		uint16_t port;

		port = (min_port + (rand_u16() % (max_port - min_port)));
		port &= 0xfffe;

		sa_set_port(&rs->local, port);
		err = udp_listen(&us_rtp, &rs->local, udp_recv_handler, rs);
		if (err)
			continue;

		sa_set_port(&rtcp, port + 1);
		err = udp_listen(&us_rtcp, &rtcp, rtcp_recv_handler, rs);
		if (err) {
			mem_deref(us_rtp);
			continue;
		}

		/* OK */
		rs->sock_rtp = us_rtp;
		rs->sock_rtcp = us_rtcp;
		break;
	}

	return err;
}
Ejemplo n.º 10
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;
}
Ejemplo n.º 11
0
static int attr_decode_rtcp(struct sdp_media *m, const struct pl *pl)
{
	struct pl port, addr;
	int err = 0;

	if (!m)
		return 0;

	if (!re_regex(pl->p, pl->l, "[0-9]+ IN IP[46]1 [^ ]+",
		      &port, NULL, &addr)) {
		(void)sa_set(&m->raddr_rtcp, &addr, pl_u32(&port));
	}
	else if (!re_regex(pl->p, pl->l, "[0-9]+", &port)) {
		sa_set_port(&m->raddr_rtcp, pl_u32(&port));
	}
	else
		err = EBADMSG;

	return err;
}
Ejemplo n.º 12
0
static int module_init(void)
{
	int err;

	sa_init(&natpmp_srv, AF_INET);
	sa_set_port(&natpmp_srv, NATPMP_PORT);

	net_rt_list(net_rt_handler, NULL);

	conf_get_sa(conf_cur(), "natpmp_server", &natpmp_srv);

	info("natpmp: using NAT-PMP server at %J\n", &natpmp_srv);

	err = natpmp_external_request(&natpmp_ext, &natpmp_srv,
				      extaddr_handler, NULL);
	if (err)
		return err;

	return mnat_register(&mnat, "natpmp", NULL,
			     session_alloc, media_alloc, NULL);
}
Ejemplo n.º 13
0
/**
 * Decode a pointer-length string into a SIP Via header
 *
 * @param via SIP Via header
 * @param pl  Pointer-length string
 *
 * @return 0 for success, otherwise errorcode
 */
int sip_via_decode(struct sip_via *via, const struct pl *pl)
{
    struct pl transp, host, port;
    int err;

    if (!via || !pl)
        return EINVAL;

    err = re_regex(pl->p, pl->l,
                   "SIP[  \t\r\n]*/[ \t\r\n]*2.0[ \t\r\n]*/[ \t\r\n]*"
                   "[A-Z]+[ \t\r\n]*[^; \t\r\n]+[ \t\r\n]*[^]*",
                   NULL, NULL, NULL, NULL, &transp,
                   NULL, &via->sentby, NULL, &via->params);
    if (err)
        return err;

    if (!pl_strcmp(&transp, "TCP"))
        via->tp = SIP_TRANSP_TCP;
    else if (!pl_strcmp(&transp, "TLS"))
        via->tp = SIP_TRANSP_TLS;
    else if (!pl_strcmp(&transp, "UDP"))
        via->tp = SIP_TRANSP_UDP;
    else
        via->tp = SIP_TRANSP_NONE;

    err = decode_hostport(&via->sentby, &host, &port);
    if (err)
        return err;

    sa_init(&via->addr, AF_INET);

    (void)sa_set(&via->addr, &host, 0);

    if (pl_isset(&port))
        sa_set_port(&via->addr, pl_u32(&port));

    via->val = *pl;

    return msg_param_decode(&via->params, "branch", &via->branch);
}
Ejemplo n.º 14
0
int  esp_server_alloc(struct esp_server **pp)
{
    struct esp_server *es;
    
    if(!pp)
        return EINVAL;
    
    *pp = NULL;
    
    es = mem_zalloc(sizeof(*es), es_de);
    if(!es)
        return ENOMEM;

    sa_init(&es->local, AF_INET);
    sa_set_port(&es->local, DM_PORT);
    DEBUG_NOTICE("listen %J\n", &es->local);
    tcp_listen(&es->ts, &es->local, tcp_conn_handler, es);

    *pp = es;
    
    return 0;
}
Ejemplo n.º 15
0
int pick_port_bind(int sockfd, union sock_addr *myaddr,
                   unsigned int port_range_from,
                   unsigned int port_range_to)
{
    unsigned int port, firstport;
    int port_range = 0;

    if (port_range_from != 0 && port_range_to != 0) {
        port_range = 1;
    }

    firstport = port_range
        ? port_range_from + rand() % (port_range_to - port_range_from + 1)
        : 0;

    port = firstport;

    do {
        sa_set_port(myaddr, htons(port));
        if (bind(sockfd, &myaddr->sa, SOCKLEN(myaddr)) < 0) {
            /* Some versions of Linux return EINVAL instead of EADDRINUSE */
            if (!(port_range && (errno == EINVAL || errno == EADDRINUSE)))
                return -1;

            /* Normally, we shouldn't have to loop, but some situations involving
               aborted transfers make it possible. */
        } else {
            return 0;
        }

        port++;
        if (port > port_range_to)
            port = port_range_from;
    } while (port != firstport);

    return -1;
}
Ejemplo n.º 16
0
static void
mta_enter_state(struct mta_session *s, int newstate)
{
	int			 oldstate;
	struct secret		 secret;
	struct mta_route	*route;
	struct mta_host		*host;
	struct sockaddr		*sa;
	int			 max_reuse;
	ssize_t			 q;

#ifdef VALGRIND
	bzero(&batch, sizeof(batch));
#endif

    again:
	oldstate = s->state;

	log_trace(TRACE_MTA, "mta: %p: %s -> %s", s,
	    mta_strstate(oldstate),
	    mta_strstate(newstate));

	s->state = newstate;

	/* don't try this at home! */
#define mta_enter_state(_s, _st) do { newstate = _st; goto again; } while(0)

	switch (s->state) {
	case MTA_INIT:
		if (s->route->auth)
			mta_enter_state(s, MTA_SECRET);
		else
			mta_enter_state(s, MTA_MX);
		break;

	case MTA_DATA:
		/*
		 * Obtain message body fd.
		 */
		imsg_compose_event(env->sc_ievs[PROC_QUEUE],
		    IMSG_QUEUE_MESSAGE_FD, s->task->msgid, 0, -1,
		    &s->id, sizeof(s->id));
		break;

	case MTA_SECRET:
		/*
		 * Lookup AUTH secret.
		 */
		bzero(&secret, sizeof(secret));
		secret.id = s->id;
		strlcpy(secret.mapname, s->route->auth, sizeof(secret.mapname));
		strlcpy(secret.host, s->route->hostname, sizeof(secret.host));
		imsg_compose_event(env->sc_ievs[PROC_LKA], IMSG_LKA_SECRET,
		    0, 0, -1, &secret, sizeof(secret));  
		break;

	case MTA_MX:
		/*
		 * Lookup MX record.
		 */
		if (s->flags & MTA_FORCE_MX) /* XXX */
			dns_query_host(s->route->hostname, s->route->port, s->id);
		else
			dns_query_mx(s->route->hostname, s->route->backupname, 0, s->id);
		break;

	case MTA_CONNECT:
		/*
		 * Connect to the MX.
		 */
	
		/* cleanup previous connection if any */
		iobuf_clear(&s->iobuf);
		io_clear(&s->io);

		if (s->flags & MTA_FORCE_ANYSSL)
			max_reuse = 2;
		else
			max_reuse = 1;

		/* pick next mx */
		while ((host = TAILQ_FIRST(&s->hosts))) {
			if (host->used == max_reuse) {
				TAILQ_REMOVE(&s->hosts, host, entry);
				free(host);
				continue;
			}
			host->used++;

			log_debug("mta: %p: connecting to %s...", s,
				ss_to_text(&host->sa));
			sa = (struct sockaddr *)&host->sa;

			if (s->route->port)
				sa_set_port(sa, s->route->port);
			else if ((s->flags & MTA_FORCE_ANYSSL) && host->used == 1)
				sa_set_port(sa, 465);
			else if (s->flags & MTA_FORCE_SMTPS)
				sa_set_port(sa, 465);
			else
				sa_set_port(sa, 25);

			iobuf_xinit(&s->iobuf, 0, 0, "mta_enter_state");
			io_init(&s->io, -1, s, mta_io, &s->iobuf);
			io_set_timeout(&s->io, 10000);
			if (io_connect(&s->io, sa, NULL) == -1) {
				log_debug("mta: %p: connection failed: %s", s,
				    strerror(errno));
				iobuf_clear(&s->iobuf);
				/*
				 * This error is most likely a "no route",
				 * so there is no need to try the same
				 * relay again.
				 */
				TAILQ_REMOVE(&s->hosts, host, entry);
				free(host);
				continue;
			}
			return;
		}
		/* tried them all? */
		mta_route_error(s->route, "150 Can not connect to MX");
		mta_enter_state(s, MTA_DONE);
		break;

	case MTA_DONE:
		/*
		 * Kill the mta session.
		 */
		log_debug("mta: %p: session done", s);
		io_clear(&s->io);
		iobuf_clear(&s->iobuf);
		if (s->task)
			fatalx("current task should have been deleted already");
		if (s->datafp)
			fclose(s->datafp);
		s->datafp = NULL;
		while ((host = TAILQ_FIRST(&s->hosts))) {
			TAILQ_REMOVE(&s->hosts, host, entry);
			free(host);
		}
		route = s->route;
		tree_xpop(&sessions, s->id);
		free(s);
		stat_decrement("mta.session", 1);
		mta_route_collect(route);
		break;

	case MTA_SMTP_BANNER:
		/* just wait for banner */
		s->is_reading = 1;
		io_set_read(&s->io);
		break;

	case MTA_SMTP_EHLO:
		s->ext = 0;
		mta_send(s, "EHLO %s", env->sc_hostname);
		break;

	case MTA_SMTP_HELO:
		s->ext = 0;
		mta_send(s, "HELO %s", env->sc_hostname);
		break;

	case MTA_SMTP_STARTTLS:
		if (s->flags & MTA_TLS) /* already started */
			mta_enter_state(s, MTA_SMTP_AUTH);
		else if ((s->ext & MTA_EXT_STARTTLS) == 0)
			/* server doesn't support starttls, do not use it */
			mta_enter_state(s, MTA_SMTP_AUTH);
		else
			mta_send(s, "STARTTLS");
		break;

	case MTA_SMTP_AUTH:
		if (s->secret && s->flags & MTA_TLS)
			mta_send(s, "AUTH PLAIN %s", s->secret);
		else if (s->secret) {
			log_debug("mta: %p: not using AUTH on non-TLS session",
			    s);
			mta_enter_state(s, MTA_CONNECT);
		} else {
			mta_enter_state(s, MTA_SMTP_READY);
		}
		break;

	case MTA_SMTP_READY:
		/* ready to send a new mail */
		if (s->ready == 0) {
			s->ready = 1;
			mta_route_ok(s->route);
		}
		if (s->msgcount >= s->route->maxmail) {
			log_debug("mta: %p: cannot send more message to %s", s,
			    mta_route_to_text(s->route));
			mta_enter_state(s, MTA_SMTP_QUIT);
		} else if ((s->task = TAILQ_FIRST(&s->route->tasks))) {
			log_debug("mta: %p: handling next task for %s", s,
			    mta_route_to_text(s->route));
			TAILQ_REMOVE(&s->route->tasks, s->task, entry);
			s->route->ntask -= 1;
			s->task->session = s;
			stat_decrement("mta.task", 1);
			stat_increment("mta.task.running", 1);
			mta_enter_state(s, MTA_DATA);
		} else {
			log_debug("mta: %p: no pending task for %s", s,
			    mta_route_to_text(s->route));
			/* XXX stay open for a while? */
			mta_enter_state(s, MTA_SMTP_QUIT);
		}
		break;

	case MTA_SMTP_MAIL:
		if (s->task->sender.user[0] && s->task->sender.domain[0])
			mta_send(s, "MAIL FROM: <%s@%s>",
			    s->task->sender.user, s->task->sender.domain);
		else
			mta_send(s, "MAIL FROM: <>");
		break;

	case MTA_SMTP_RCPT:
		if (s->currevp == NULL)
			s->currevp = TAILQ_FIRST(&s->task->envelopes);
		mta_send(s, "RCPT TO: <%s@%s>",
		    s->currevp->dest.user,
		    s->currevp->dest.domain);
		break;

	case MTA_SMTP_DATA:
		fseek(s->datafp, 0, SEEK_SET);
		mta_send(s, "DATA");
		break;

	case MTA_SMTP_BODY:
		if (s->datafp == NULL) {
			log_trace(TRACE_MTA, "mta: %p: end-of-file", s);
			mta_enter_state(s, MTA_SMTP_DONE);
			break;
		}

		if ((q = mta_queue_data(s)) == -1) {
			mta_enter_state(s, MTA_DONE);
			break;
		}

		log_trace(TRACE_MTA, "mta: %p: >>> [...%zi bytes...]", s, q);
		break;

	case MTA_SMTP_DONE:
		mta_send(s, ".");
		break;

	case MTA_SMTP_QUIT:
		mta_send(s, "QUIT");
		break;

	case MTA_SMTP_RSET:
		mta_send(s, "RSET");
		break;

	default:
		fatalx("mta_enter_state: unknown state");
	}
#undef mta_enter_state
}
Ejemplo n.º 17
0
void tcsipcall_control(struct tcsipcall*call, int action)
{

    int err;
    struct mbuf *mb = NULL;

    /*
     * XXX: drop bytes when confirmation received
     * */
    switch(action) {
    case CALL_ACCEPT:
        if(call->cstate & (CSTATE_ERR|CSTATE_EST))
            return;

        if(call->cdir != CALL_IN)
            return;

        if(! (call->cstate & CSTATE_ICE)) {
            DROP(call->cstate, CSTATE_RING);
            return;
        }

	// 200
        err = tcmedia_offer(call->media, call->msg->mb, &mb);
	if(err) {
	    DROP(call->cstate, CSTATE_RING);
            err |= CSTATE_ERR;
	    break;
	}

        /*
         * Workarround
         *
         * libre uses msg->dst to fill in Contact header
         * value.
         * This works well for UDP where one socket used
         * for both send and recieve, but no for TCP
         * TCP transport uses one socket for listen
         * and other to connect to registar.
         * Address msg->dst is the recieving part
         * of upstream socket UAC->REGISTAR
         * and cannot be used to connect from outside
         *
         * */
        sa_set_port((struct sa*)&call->msg->dst, sa_port(&call->uac->laddr));

        sipsess_answer(call->sess, 200, "OK", mb, NULL);

        mem_deref(mb);

        DROP(call->cstate, CSTATE_RING);
	call->cstate |= CSTATE_EST;

	break;

    case CALL_REJECT:
    case CALL_BYE:
	if( TEST(call->cstate, CSTATE_IN_RING) ) {
            sipsess_reject(call->sess, 486, "Reject", NULL);
	    DROP(call->cstate, CSTATE_IN_RING);
            call->reason = CEND_HANG;
	}

	if( TEST(call->cstate, CSTATE_EST) ) {
	    // bye sent automatically in deref
	    DROP(call->cstate, CSTATE_EST);
            call->reason = CEND_OK;
	}

	if( TEST(call->cstate, CSTATE_OUT_RING ) ) {
	    // cancel
	    DROP(call->cstate, CSTATE_EST);
            call->reason = CEND_CANCEL;
	}

	tcsipcall_hangup(call);
        break;

   }

}
Ejemplo n.º 18
0
/* NOTE: this code must be fast, and not do any calculations */
static void turnc_handler(int err, uint16_t scode, const char *reason,
			  const struct sa *relay_addr,
			  const struct sa *mapped_addr,
			  const struct stun_msg *msg,
			  void *arg)
{
	struct allocation *alloc = arg;
	struct allocator *allocator = alloc->allocator;
	struct timeval now;
	struct sa peer;

	if (err) {
		(void)re_fprintf(stderr, "[%u] turn error: %m\n",
				 alloc->ix, err);
		alloc->err = err;
		goto term;
	}

	if (scode) {

		if (scode == 300 && is_connection_oriented(alloc) &&
		    alloc->redirc++ < REDIRC_MAX) {

			const struct stun_attr *alt;

			alt = stun_msg_attr(msg, STUN_ATTR_ALT_SERVER);
			if (!alt)
				goto term;

			re_printf("[%u] redirecting to new server %J\n",
				  alloc->ix, &alt->v.alt_server);

			alloc->srv = alt->v.alt_server;

			alloc->turnc = mem_deref(alloc->turnc);
			alloc->tlsc  = mem_deref(alloc->tlsc);
			alloc->tc    = mem_deref(alloc->tc);
			alloc->dtls_sock = mem_deref(alloc->dtls_sock);
			alloc->us    = mem_deref(alloc->us);

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

			return;
		}

		(void)re_fprintf(stderr, "[%u] turn error: %u %s\n",
				 alloc->ix, scode, reason);
		alloc->err = EPROTO;
		goto term;
	}

	if (sa_af(relay_addr) != sa_af(mapped_addr)) {
		re_fprintf(stderr, "allocation: address-family mismatch"
			   " (mapped=%J, relay=%J)\n",
			   mapped_addr, relay_addr);
		err = EAFNOSUPPORT;
		goto term;
	}

	alloc->ok = true;
	alloc->relay = *relay_addr;

	(void)gettimeofday(&now, NULL);

	alloc->atime  = (double)(now.tv_sec - alloc->sent.tv_sec) * 1000;
	alloc->atime += (double)(now.tv_usec - alloc->sent.tv_usec) / 1000;

	/* save information from the TURN server */
	if (!allocator->server_info) {

		struct stun_attr *attr;

		allocator->server_auth =
			(NULL != stun_msg_attr(msg, STUN_ATTR_MSG_INTEGRITY));

		attr = stun_msg_attr(msg, STUN_ATTR_SOFTWARE);
		if (attr) {
			str_ncpy(allocator->server_software, attr->v.software,
				 sizeof(allocator->server_software));
		}

		allocator->mapped_addr = *mapped_addr;

		allocator->server_info = true;

		attr = stun_msg_attr(msg, STUN_ATTR_LIFETIME);
		if (attr) {
			allocator->lifetime = attr->v.lifetime;
		}
	}

	peer = *mapped_addr;
	sa_set_port(&peer, sa_port(&alloc->laddr_tx));

	err = set_peer(alloc, &peer);
	if (err)
		goto term;

	return;

 term:
	alloc->alloch(err, scode, reason, NULL, NULL, alloc->arg);
}
Ejemplo n.º 19
0
static int add_transp_af(const struct sa *laddr)
{
	struct sa local;
	int err = 0;

	if (str_isset(uag.cfg->local)) {
		err = sa_decode(&local, uag.cfg->local,
				str_len(uag.cfg->local));
		if (err) {
			err = sa_set_str(&local, uag.cfg->local, 0);
			if (err) {
				warning("ua: decode failed: '%s'\n",
					uag.cfg->local);
				return err;
			}
		}

		if (!sa_isset(&local, SA_ADDR)) {
			uint16_t port = sa_port(&local);
			(void)sa_set_sa(&local, &laddr->u.sa);
			sa_set_port(&local, port);
		}

		if (sa_af(laddr) != sa_af(&local))
			return 0;
	}
	else {
		sa_cpy(&local, laddr);
		sa_set_port(&local, 0);
	}

	if (uag.use_udp)
		err |= sip_transp_add(uag.sip, SIP_TRANSP_UDP, &local);
	if (uag.use_tcp)
		err |= sip_transp_add(uag.sip, SIP_TRANSP_TCP, &local);
	if (err) {
		warning("ua: SIP Transport failed: %m\n", err);
		return err;
	}

#ifdef USE_TLS
	if (uag.use_tls) {
		/* Build our SSL context*/
		if (!uag.tls) {
			const char *cert = NULL;

			if (str_isset(uag.cfg->cert)) {
				cert = uag.cfg->cert;
				info("SIP Certificate: %s\n", cert);
			}

			err = tls_alloc(&uag.tls, TLS_METHOD_SSLV23,
					cert, NULL);
			if (err) {
				warning("ua: tls_alloc() failed: %m\n", err);
				return err;
			}
		}

		if (sa_isset(&local, SA_PORT))
			sa_set_port(&local, sa_port(&local) + 1);

		err = sip_transp_add(uag.sip, SIP_TRANSP_TLS, &local, uag.tls);
		if (err) {
			warning("ua: SIP/TLS transport failed: %m\n", err);
			return err;
		}
	}
#endif

	return err;
}
Ejemplo n.º 20
0
Archivo: option.c Proyecto: 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;
}
Ejemplo n.º 21
0
Archivo: lcand.c Proyecto: alfredh/rew
/*
 * you can call this at any time
 *
 * @param addr HOST:     SA_ADDR portion is used
 *             non-HOST: SA_ADDR + SA_PORT portion is used
 *
 * @param base_addr  Optional
 * @param rel_addr   Optional
 *
 * @param layer  mandatory for HOST and RELAY candidates
 */
int trice_lcand_add(struct ice_lcand **lcandp, struct trice *icem,
		    unsigned compid, int proto,
		    uint32_t prio, const struct sa *addr,
		    const struct sa *base_addr,
		    enum ice_cand_type type, const struct sa *rel_addr,
		    enum ice_tcptype tcptype,
		    void *sock, int layer)
{
	struct ice_lcand *lcand;
	int err = 0;

	if (!icem || !compid || !proto || !addr)
		return EINVAL;

	if (!sa_isset(addr, SA_ADDR)) {
		DEBUG_WARNING("lcand_add: SA_ADDR is not set\n");
		return EINVAL;
	}
	if (type != ICE_CAND_TYPE_HOST) {
		if (!sa_isset(addr, SA_PORT)) {
			DEBUG_WARNING("lcand_add: %s: SA_PORT"
				      " must be set (%J)\n",
				      ice_cand_type2name(type), addr);
			return EINVAL;
		}
	}

	/* lookup candidate, replace if PRIO is higher */

	/* TODO: dont look up TCP-ACTIVE types for now (port is zero) */
	if (proto == IPPROTO_UDP) {

		lcand = trice_lcand_find(icem, -1, compid, proto, addr);
		if (lcand) {
			trice_printf(icem,
				    "add_local[%s.%J] --"
				    " candidate already exists"
				    " (%H)\n",
				    ice_cand_type2name(type), addr,
				    trice_cand_print, lcand);

			if (prio > lcand->attr.prio)
				lcand = mem_deref(lcand);
			else {
				goto out;
			}
		}
	}

	err = trice_add_lcandidate(&lcand, icem, &icem->lcandl, compid, NULL,
				   proto, prio, addr, base_addr,
				   type, rel_addr, tcptype);
	if (err)
		return err;

	if (type == ICE_CAND_TYPE_HOST) {

		switch (proto) {

		case IPPROTO_UDP:
			if (sock) {
				struct sa laddr;

				lcand->us = mem_ref(sock);

				err = udp_local_get(lcand->us,
						    &laddr);
				if (err)
					goto out;

				lcand->attr.addr = *addr;
				sa_set_port(&lcand->attr.addr,
					    sa_port(&laddr));
			}
			else {
				err = udp_listen(&lcand->us, addr,
						 dummy_udp_recv, lcand);
				if (err)
					goto out;

				err = udp_local_get(lcand->us,
						    &lcand->attr.addr);
				if (err)
					goto out;
			}

			err = udp_register_helper(&lcand->uh, lcand->us,
						  layer,
						  udp_helper_send_handler,
						  udp_helper_recv_handler,
						  lcand);
			if (err)
				goto out;
			break;

		case IPPROTO_TCP:

			/* TCP-transport has 3 variants:
			   active, passive, so */

			if (lcand->attr.tcptype == ICE_TCP_ACTIVE) {

				/* the port MUST be set to 9 (i.e., Discard) */
				/*sa_set_port(&lcand->attr.addr, 9); */
			}
			else if (lcand->attr.tcptype == ICE_TCP_PASSIVE ||
				 lcand->attr.tcptype == ICE_TCP_SO) {

				err = tcp_listen(&lcand->ts, addr,
						 tcp_conn_handler, lcand);
				if (err)
					goto out;
				err = tcp_local_get(lcand->ts,
						    &lcand->attr.addr);
				if (err)
					goto out;
			}
			else {
				err = EPROTONOSUPPORT;
				goto out;
			}
			break;

		default:
			err = EPROTONOSUPPORT;
			goto out;
		}
	}
	else if (type == ICE_CAND_TYPE_RELAY) {

		switch (proto) {

		case IPPROTO_UDP:

			if (sock) {
				lcand->us = mem_ref(sock);
			}
			else {
				err = udp_listen(&lcand->us, NULL,
						 dummy_udp_recv, lcand);
				if (err)
					goto out;
			}

			err = udp_register_helper(&lcand->uh, lcand->us,
						  layer,
						  udp_helper_send_handler,
						  udp_helper_recv_handler,
						  lcand);
			if (err)
				goto out;

			break;

		default:
			err = EPROTONOSUPPORT;
			goto out;
		}
	}
	else if (type == ICE_CAND_TYPE_SRFLX ||
		 type == ICE_CAND_TYPE_PRFLX) {

		/* Special case for SRFLX UDP candidates, if he has
		 * its own UDP-socket that can be used.
		 */
		if (proto == IPPROTO_UDP && sock) {

			lcand->us = mem_ref(sock);

			err = udp_register_helper(&lcand->uh, lcand->us,
						  layer,
						  udp_helper_send_handler,
						  udp_helper_recv_handler,
						  lcand);
			if (err)
				goto out;
		}
	}

	lcand->layer = layer;

	/* pair this local-candidate with all existing remote-candidates */
	err = trice_candpair_with_local(icem, lcand);
	if (err)
		goto out;

	/* new pair -- refresh the checklist timer */
	trice_checklist_refresh(icem);

 out:
	if (err)
		mem_deref(lcand);
	else if (lcandp)
		*lcandp = lcand;

	return err;
}
Ejemplo n.º 22
0
int main(int argc, char *argv[])
{
	struct sa nsv[16];
	struct dnsc *dnsc = NULL;
	struct sa laddr;
	uint32_t nsc;
	int err; /* errno return values */

	/* enable coredumps to aid debugging */
	(void)sys_coredump_set(true);

	/* initialize libre state */
	err = libre_init();
	if (err) {
		re_fprintf(stderr, "re init failed: %s\n", strerror(err));
		goto out;
	}

	nsc = ARRAY_SIZE(nsv);

	/* fetch list of DNS server IP addresses */
	err = dns_srv_get(NULL, 0, nsv, &nsc);
	if (err) {
		re_fprintf(stderr, "unable to get dns servers: %s\n",
			   strerror(err));
		goto out;
	}

	/* create DNS client */
	err = dnsc_alloc(&dnsc, NULL, nsv, nsc);
	if (err) {
		re_fprintf(stderr, "unable to create dns client: %s\n",
			   strerror(err));
		goto out;
	}

	/* create SIP stack instance */
	err = sip_alloc(&sip, dnsc, 32, 32, 32,
			"ua demo v" VERSION " (" ARCH "/" OS ")",
			exit_handler, NULL);
	if (err) {
		re_fprintf(stderr, "sip error: %s\n", strerror(err));
		goto out;
	}

	/* fetch local IP address */
	err = net_default_source_addr_get(AF_INET, &laddr);
	if (err) {
		re_fprintf(stderr, "local address error: %s\n", strerror(err));
		goto out;
	}

	/* listen on random port */
	sa_set_port(&laddr, 0);

	/* add supported SIP transports */
	err |= sip_transp_add(sip, SIP_TRANSP_UDP, &laddr);
	err |= sip_transp_add(sip, SIP_TRANSP_TCP, &laddr);
	if (err) {
		re_fprintf(stderr, "transport error: %s\n", strerror(err));
		goto out;
	}

	/* create SIP session socket */
	err = sipsess_listen(&sess_sock, sip, 32, connect_handler, NULL);
	if (err) {
		re_fprintf(stderr, "session listen error: %s\n",
			   strerror(err));
		goto out;
	}

	/* create the RTP/RTCP socket */
	err = rtp_listen(&rtp, IPPROTO_UDP, &laddr, 10000, 30000, true,
			 rtp_handler, rtcp_handler, NULL);
	if (err) {
		re_fprintf(stderr, "rtp listen error: %m\n", err);
		goto out;
	}

	re_printf("local RTP port is %u\n", sa_port(rtp_local(rtp)));

	/* create SDP session */
	err = sdp_session_alloc(&sdp, &laddr);
	if (err) {
		re_fprintf(stderr, "sdp session error: %s\n", strerror(err));
		goto out;
	}

	/* add audio sdp media, using port from RTP socket */
	err = sdp_media_add(&sdp_media, sdp, "audio",
			    sa_port(rtp_local(rtp)), "RTP/AVP");
	if (err) {
		re_fprintf(stderr, "sdp media error: %s\n", strerror(err));
		goto out;
	}

	/* add G.711 sdp media format */
	err = sdp_format_add(NULL, sdp_media, false, "0", "PCMU", 8000, 1,
			     NULL, NULL, NULL, false, NULL);
	if (err) {
		re_fprintf(stderr, "sdp format error: %s\n", strerror(err));
		goto out;
	}

	/* invite provided URI */
	if (argc > 1) {

		struct mbuf *mb;

		/* create SDP offer */
		err = sdp_encode(&mb, sdp, true);
		if (err) {
			re_fprintf(stderr, "sdp encode error: %s\n",
				   strerror(err));
			goto out;
		}

		err = sipsess_connect(&sess, sess_sock, argv[1], name,
				      uri, name,
				      NULL, 0, "application/sdp", mb,
				      auth_handler, NULL, false,
				      offer_handler, answer_handler,
				      progress_handler, establish_handler,
				      NULL, NULL, close_handler, NULL, NULL);
		mem_deref(mb); /* free SDP buffer */
		if (err) {
			re_fprintf(stderr, "session connect error: %s\n",
				   strerror(err));
			goto out;
		}

		re_printf("inviting <%s>...\n", argv[1]);
	}
	else {

		err = sipreg_register(&reg, sip, registrar, uri, uri, 60, name,
				      NULL, 0, 0, auth_handler, NULL, false,
				      register_handler, NULL, NULL, NULL);
		if (err) {
			re_fprintf(stderr, "register error: %s\n",
				   strerror(err));
			goto out;
		}

		re_printf("registering <%s>...\n", uri);
	}

	/* main loop */
	err = re_main(signal_handler);

 out:
	/* clean up/free all state */
	mem_deref(sdp); /* will also free sdp_media */
	mem_deref(rtp);
	mem_deref(sess_sock);
	mem_deref(sip);
	mem_deref(dnsc);

	/* free librar state */
	libre_close();

	/* check for memory leaks */
	tmr_debug();
	mem_debug();

	return err;
}
Ejemplo n.º 23
0
static int cand_decode(struct icem *icem, const char *val)
{
	struct pl foundation, compid, transp, prio, addr, port, cand_type;
	struct pl extra = pl_null;
	struct sa caddr, rel_addr;
	char type[8];
	uint8_t cid;
	int err;

	sa_init(&rel_addr, AF_INET);

	err = re_regex(val, strlen(val),
		       "[^ ]+ [0-9]+ [^ ]+ [0-9]+ [^ ]+ [0-9]+ typ [a-z]+[^]*",
		       &foundation, &compid, &transp, &prio,
		       &addr, &port, &cand_type, &extra);
	if (err)
		return err;

	if (ICE_TRANSP_NONE == transp_resolve(&transp)) {
		DEBUG_NOTICE("<%s> ignoring candidate with"
			     " unknown transport=%r (%r:%r)\n",
			     icem->name, &transp, &cand_type, &addr);
		return 0;
	}

	if (pl_isset(&extra)) {

		struct pl name, value;

		/* Loop through " SP attr SP value" pairs */
		while (!re_regex(extra.p, extra.l, " [^ ]+ [^ ]+",
				 &name, &value)) {

			pl_advance(&extra, value.p + value.l - extra.p);

			if (0 == pl_strcasecmp(&name, rel_addr_str)) {
				err = sa_set(&rel_addr, &value,
					     sa_port(&rel_addr));
				if (err)
					break;
			}
			else if (0 == pl_strcasecmp(&name, rel_port_str)) {
				sa_set_port(&rel_addr, pl_u32(&value));
			}
		}
	}

	err = sa_set(&caddr, &addr, pl_u32(&port));
	if (err)
		return err;

	cid = pl_u32(&compid);

	/* add only if not exist */
	if (icem_cand_find(&icem->rcandl, cid, &caddr))
		return 0;

	(void)pl_strcpy(&cand_type, type, sizeof(type));

	return icem_rcand_add(icem, ice_cand_name2type(type), cid,
			      pl_u32(&prio), &caddr, &rel_addr, &foundation);
}
Ejemplo n.º 24
0
/*
 * Receive a file.
 */
int tftp_recvfile(int f, union sock_addr *peeraddr,
		   int fd, const char *name, const char *mode)
{
    struct tftphdr *ap;
    struct tftphdr *dp;
    int n;
    volatile u_short block;
    volatile int size, firsttrip;
    volatile unsigned long amount;
    union sock_addr from;
    socklen_t fromlen;
    FILE *file;
    volatile int convert;       /* true if converting crlf -> lf */
    u_short dp_opcode, dp_block;

    startclock();
    dp = w_init();
    ap = (struct tftphdr *)ackbuf;
    convert = !strcmp(mode, "netascii");
    file = fdopen(fd, convert ? "wt" : "wb");
    block = 1;
    firsttrip = 1;
    amount = 0;

    bsd_signal(SIGALRM, timer);
    do {
        if (firsttrip) {
            size = makerequest(RRQ, name, ap, mode);
            firsttrip = 0;
        } else {
            ap->th_opcode = htons((u_short) ACK);
            ap->th_block = htons((u_short) block);
            size = 4;
            block++;
        }
        timeout = 0;
        (void)sigsetjmp(timeoutbuf, 1);
      send_ack:
        if (trace)
            tpacket("sent", ap, size);
        if (sendto(f, ackbuf, size, 0, &(peeraddr->sa),
                   SOCKLEN(peeraddr)) != size) {
            alarm(0);
            perror("tftp: sendto");
            goto abort;
        }
        write_behind(file, convert);
        for (;;) {
            alarm(rexmtval);
            do {
                fromlen = sizeof(from);
                n = recvfrom(f, dp, PKTSIZE, 0,
                             &from.sa, &fromlen);
            } while (n <= 0);
            alarm(0);
            if (n < 0) {
                perror("tftp: recvfrom");
                goto abort;
            }
            sa_set_port(peeraddr, SOCKPORT(&from));  /* added */
            if (trace)
                tpacket("received", dp, n);
            /* should verify client address */
            dp_opcode = ntohs((u_short) dp->th_opcode);
            dp_block = ntohs((u_short) dp->th_block);
            if (dp_opcode == ERROR) {
                printf("Error code %d: %s\n", dp_block, dp->th_msg);
                goto abort;
            }
            if (dp_opcode == DATA) {
                int j;

                if (dp_block == block) {
                    break;      /* have next packet */
                }
                /* On an error, try to synchronize
                 * both sides.
                 */
                j = synchnet(f);
                if (j && trace) {
                    printf("discarded %d packets\n", j);
                }
                if (dp_block == (block - 1)) {
                    goto send_ack;      /* resend ack */
                }
            }
        }
        /*      size = write(fd, dp->th_data, n - 4); */
        size = writeit(file, &dp, n - 4, convert);
        if (size < 0) {
            nak(f, peeraddr, errno + 100, NULL);
            break;
        }
        amount += size;
    } while (size == SEGSIZE);
  abort:                       /* ok to ack, since user */
    ap->th_opcode = htons((u_short) ACK);       /* has seen err msg */
    ap->th_block = htons((u_short) block);
    (void)sendto(f, ackbuf, 4, 0, (struct sockaddr *)peeraddr,
                 SOCKLEN(peeraddr));
    write_behind(file, convert);        /* flush last buffer */
    fclose(file);
    stopclock();
    //if (amount > 0)
    //    printstats("Received", amount);
    return amount;
}
Ejemplo n.º 25
0
/*
 * Send the requested file.
 */
int tftp_sendfile(int f, union sock_addr *peeraddr,
		   int fd, const char *name, const char *mode)
{
    struct tftphdr *ap;         /* data and ack packets */
    struct tftphdr *dp;
    int n;
    volatile int is_request;
    volatile u_short block;
    volatile int size, convert;
    volatile off_t amount;
    union sock_addr from;
    socklen_t fromlen;
    FILE *file;
    u_short ap_opcode, ap_block;

    startclock();               /* start stat's clock */
    dp = r_init();              /* reset fillbuf/read-ahead code */
    ap = (struct tftphdr *)ackbuf;
    convert = !strcmp(mode, "netascii");
    file = fdopen(fd, convert ? "rt" : "rb");
    block = 0;
    is_request = 1;             /* First packet is the actual WRQ */
    amount = 0;

    bsd_signal(SIGALRM, timer);
    do {
        if (is_request) {
            size = makerequest(WRQ, name, dp, mode) - 4;
        } else {
            /*      size = read(fd, dp->th_data, SEGSIZE);   */
            size = readit(file, &dp, convert);
            if (size < 0) {
                nak(f, peeraddr, errno + 100, NULL);
                break;
            }
            dp->th_opcode = htons((u_short) DATA);
            dp->th_block = htons((u_short) block);
        }
        timeout = 0;
        (void)sigsetjmp(timeoutbuf, 1);

        if (trace)
            tpacket("sent", dp, size + 4);
        n = sendto(f, dp, size + 4, 0,
                   &(peeraddr->sa), SOCKLEN(peeraddr));
        if (n != size + 4) {
            perror("tftp: sendto");
            goto abort;
        }
        read_ahead(file, convert);
        for (;;) {
            alarm(rexmtval);
            do {
                fromlen = sizeof(from);
                n = recvfrom(f, ackbuf, sizeof(ackbuf), 0,
                             &from.sa, &fromlen);
            } while (n <= 0);
            alarm(0);
            if (n < 0) {
                perror("tftp: recvfrom");
                goto abort;
            }
            sa_set_port(peeraddr, SOCKPORT(&from));  /* added */
            if (trace)
                tpacket("received", ap, n);
            /* should verify packet came from server */
            ap_opcode = ntohs((u_short) ap->th_opcode);
            ap_block = ntohs((u_short) ap->th_block);
            if (ap_opcode == ERROR) {
                printf("Error code %d: %s\n", ap_block, ap->th_msg);
                goto abort;
            }
            if (ap_opcode == ACK) {
                int j;

                if (ap_block == block) {
                    break;
                }
                /* On an error, try to synchronize
                 * both sides.
                 */
                j = synchnet(f);
                if (j && trace) {
                    printf("discarded %d packets\n", j);
                }
                /*
                 * RFC1129/RFC1350: We MUST NOT re-send the DATA
                 * packet in response to an invalid ACK.  Doing so
                 * would cause the Sorcerer's Apprentice bug.
                 */
            }
        }
        if (!is_request)
            amount += size;
        is_request = 0;
        block++;
    } while (size == SEGSIZE || block == 1);
  abort:
    fclose(file);
    stopclock();
    //if (amount > 0)
    //    printstats("Sent", amount);
    return amount;
}
Ejemplo n.º 26
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;
	}
}
Ejemplo n.º 27
0
static int test_stun_request(int proto, bool natted)
{
	struct stunserver *srv = NULL;
	struct stun_ctrans *ct = NULL;
	struct nat *nat = NULL;
	struct test test;
	struct sa laddr, public_addr;
	int err;

	memset(&test, 0, sizeof(test));

	err = stunserver_alloc(&srv);
	if (err)
		goto out;

	err = stun_alloc(&test.stun, NULL, NULL, NULL);
	if (err)
		goto out;

	if (proto == IPPROTO_UDP) {
		err = sa_set_str(&laddr, "127.0.0.1", 0);
		TEST_ERR(err);

		err = udp_listen(&test.us, &laddr, udp_recv_handler, &test);
		if (err)
			goto out;
		err = udp_local_get(test.us, &laddr);
		TEST_ERR(err);
	}

	if (natted) {
		err = sa_set_str(&public_addr, "4.5.6.7", 0);
		TEST_ERR(err);

		err = nat_alloc(&nat, srv->us, &public_addr);
		if (err)
			goto out;

		sa_set_port(&public_addr, sa_port(&laddr));
	}
	else {
		public_addr = laddr;
	}

	err = stun_request(&ct, test.stun, proto, test.us,
			   stunserver_addr(srv, proto), 0,
			   STUN_METHOD_BINDING, NULL, 0, true,
			   stun_resp_handler, &test, 0);
	if (err)
		goto out;

	TEST_ASSERT(ct != NULL);

	err = re_main_timeout(100);
	if (err)
		goto out;

	if (srv->err) {
		err = srv->err;
		goto out;
	}
	if (test.err) {
		err = test.err;
		goto out;
	}

	/* verify results */
	TEST_ASSERT(srv->nrecv >= 1);
	TEST_EQUALS(1, test.n_resp);

	if (proto == IPPROTO_UDP) {
		TEST_SACMP(&public_addr, &test.mapped_addr, SA_ALL);
	}

 out:
	mem_deref(test.stun);
	mem_deref(test.us);
	mem_deref(nat);
	mem_deref(srv);

	return err;
}