static int addr_lookup(struct sip_request *req, const char *name)
{
	int err;

	if (sip_transp_supported(req->sip, req->tp, AF_INET)) {

		err = dnsc_query(&req->dnsq, req->sip->dnsc, name,
				 DNS_TYPE_A, DNS_CLASS_IN, true,
				 addr_handler, req);
		if (err)
			return err;
	}

#ifdef HAVE_INET6
	if (sip_transp_supported(req->sip, req->tp, AF_INET6)) {

		err = dnsc_query(&req->dnsq2, req->sip->dnsc, name,
				 DNS_TYPE_AAAA, DNS_CLASS_IN, true,
				 addr_handler, req);
		if (err)
			return err;
	}
#endif

	if (!req->dnsq && !req->dnsq2)
		return EPROTONOSUPPORT;

	return 0;
}
static void naptr_handler(int err, const struct dnshdr *hdr, struct list *ansl,
			  struct list *authl, struct list *addl, void *arg)
{
	struct sip_request *req = arg;
	struct dnsrr *rr;
	(void)hdr;
	(void)authl;

	dns_rrlist_sort(ansl, DNS_TYPE_NAPTR);

	rr = dns_rrlist_apply(ansl, NULL, DNS_TYPE_NAPTR, DNS_CLASS_IN, false,
			      rr_naptr_handler, req);
	if (!rr) {
		err = srv_lookup(req, req->host);
		if (err)
			goto fail;

		return;
	}

	dns_rrlist_sort(addl, DNS_TYPE_SRV);

	dns_rrlist_apply(addl, rr->rdata.naptr.replace, DNS_TYPE_SRV,
			 DNS_CLASS_IN, true, rr_append_handler, &req->srvl);

	if (!req->srvl.head) {
		err = dnsc_query(&req->dnsq, req->sip->dnsc,
				 rr->rdata.naptr.replace, DNS_TYPE_SRV,
				 DNS_CLASS_IN, true, srv_handler, req);
		if (err)
			goto fail;

		return;
	}

	dns_rrlist_apply(addl, NULL, DNS_QTYPE_ANY, DNS_CLASS_IN, false,
			 rr_cache_handler, req);

	err = request_next(req);
	if (err)
		goto fail;

	if (!req->stateful) {
		req->resph = NULL;
		terminate(req, 0, NULL);
		mem_deref(req);
	}

	return;

 fail:
	terminate(req, err, NULL);
	mem_deref(req);
}
static int srv_lookup(struct sip_request *req, const char *domain)
{
	char name[256];

	if (re_snprintf(name, sizeof(name), "%s.%s",
			sip_transp_srvid(req->tp), domain) < 0)
		return ENOMEM;

	return dnsc_query(&req->dnsq, req->sip->dnsc, name, DNS_TYPE_SRV,
			  DNS_CLASS_IN, true, srv_handler, req);
}
static int a_or_aaaa_query(struct stun_dns *dns, const char *name)
{
	dns->dq = mem_deref(dns->dq);

	switch (dns->af) {

	case AF_INET:
		return dnsc_query(&dns->dq, dns->dnsc, name, DNS_TYPE_A,
				  DNS_CLASS_IN, true, a_handler, dns);

#ifdef HAVE_INET6
	case AF_INET6:
		return dnsc_query(&dns->dq, dns->dnsc, name, DNS_TYPE_AAAA,
				  DNS_CLASS_IN, true, aaaa_handler, dns);
#endif

	default:
		return EAFNOSUPPORT;
	}
}
Beispiel #5
0
int addr_lookup(struct request *request, char *name)
{
    int ok;
    ok = dnsc_query(&request->dnsq, request->app->dnsc,
		    name,
		    DNS_TYPE_A, DNS_CLASS_IN, true,
		    addr_handler, request);

    return ok;

}
Beispiel #6
0
static int rst_connect(struct rst *rst)
{
	struct sa srv;
	int err;

	if (!sa_set_str(&srv, rst->host, rst->port)) {

		err = tcp_connect(&rst->tc, &srv, estab_handler, recv_handler,
				  close_handler, rst);
		if (err) {
			re_printf("rst: tcp connect error: %m\n", err);
		}
	}
	else {
		err = dnsc_query(&rst->dnsq, net_dnsc(), rst->host, DNS_TYPE_A,
				 DNS_CLASS_IN, true, dns_handler, rst);
		if (err) {
			re_printf("rst: dns query error: %m\n", err);
		}
	}

	return err;
}
/**
 * Send a SIP request
 *
 * @param reqp     Pointer to allocated SIP request object
 * @param sip      SIP Stack
 * @param stateful Stateful client transaction
 * @param met      SIP Method string
 * @param metl     Length of SIP Method string
 * @param uri      Request URI
 * @param uril     Length of Request URI string
 * @param route    Next hop route URI
 * @param mb       Buffer containing SIP request
 * @param sendh    Send handler
 * @param resph    Response handler
 * @param arg      Handler argument
 *
 * @return 0 if success, otherwise errorcode
 */
int sip_request(struct sip_request **reqp, struct sip *sip, bool stateful,
		const char *met, int metl, const char *uri, int uril,
		const struct uri *route, struct mbuf *mb,
		sip_send_h *sendh, sip_resp_h *resph, void *arg)
{
	struct sip_request *req;
	struct sa dst;
	struct pl pl;
	int err;

	if (!sip || !met || !uri || !route || !mb)
		return EINVAL;

	if (pl_strcasecmp(&route->scheme, "sip"))
		return ENOSYS;

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

	list_append(&sip->reql, &req->le, req);

	err = str_ldup(&req->met, met, metl);
	if (err)
		goto out;

	err = str_ldup(&req->uri, uri, uril);
	if (err)
		goto out;

	if (sip_param_decode(&route->params, "maddr", &pl))
		pl = route->host;

	err = pl_strdup(&req->host, &pl);
	if (err)
		goto out;

	req->stateful = stateful;
	req->mb    = mem_ref(mb);
	req->sip   = sip;
	req->sendh = sendh;
	req->resph = resph;
	req->arg   = arg;

	if (!sip_param_decode(&route->params, "transport", &pl)) {

		if (!pl_strcasecmp(&pl, "udp"))
			req->tp = SIP_TRANSP_UDP;
		else if (!pl_strcasecmp(&pl, "tcp"))
			req->tp = SIP_TRANSP_TCP;
		else if (!pl_strcasecmp(&pl, "tls"))
			req->tp = SIP_TRANSP_TLS;
		else {
			err = EPROTONOSUPPORT;
			goto out;
		}

		if (!sip_transp_supported(sip, req->tp, AF_UNSPEC)) {
			err = EPROTONOSUPPORT;
			goto out;
		}

		req->tp_selected = true;
	}
	else {
		req->tp = SIP_TRANSP_NONE;
		if (!transp_next(sip, &req->tp)) {
			err = EPROTONOSUPPORT;
			goto out;
		}

		req->tp_selected = false;
	}

	if (!sa_set_str(&dst, req->host,
			sip_transp_port(req->tp, route->port))) {

		err = request(req, req->tp, &dst);
		if (!req->stateful) {
			mem_deref(req);
			return err;
		}
	}
	else if (route->port) {

		req->port = sip_transp_port(req->tp, route->port);
		err = addr_lookup(req, req->host);
	}
	else if (req->tp_selected) {

		err = srv_lookup(req, req->host);
	}
	else {
	        err = dnsc_query(&req->dnsq, sip->dnsc, req->host,
				 DNS_TYPE_NAPTR, DNS_CLASS_IN, true,
				 naptr_handler, req);
	}

 out:
	if (err)
		mem_deref(req);
	else if (reqp) {
		req->reqp = reqp;
		*reqp = req;
	}

	return err;
}
/**
 * Do a DNS Discovery of a STUN Server
 *
 * @param dnsp    Pointer to allocated DNS Discovery object
 * @param dnsc    DNS Client
 * @param service Name of service to discover (e.g. "stun")
 * @param proto   Transport protocol (e.g. "udp")
 * @param af      Preferred Address Family
 * @param domain  Domain name or IP address of STUN server
 * @param port    Port number (if 0 do SRV lookup)
 * @param dnsh    DNS Response handler
 * @param arg     Handler argument
 *
 * @return 0 if success, otherwise errorcode
 */
int stun_server_discover(struct stun_dns **dnsp, struct dnsc *dnsc,
			 const char *service, const char *proto,
			 int af, const char *domain, uint16_t port,
			 stun_dns_h *dnsh, void *arg)
{
	struct stun_dns *dns;
	int err;

	if (!dnsp || !service || !proto || !domain || !domain[0] || !dnsh)
		return EINVAL;

	dns = mem_zalloc(sizeof(*dns), dnsdisc_destructor);
	if (!dns)
		return ENOMEM;

	dns->port = service[strlen(service)-1] == 's' ? STUNS_PORT : STUN_PORT;
	dns->dnsh = dnsh;
	dns->arg  = arg;
	dns->dnsc = dnsc;
	dns->af   = af;

	/* Numeric IP address - no lookup */
	if (0 == sa_set_str(&dns->srv, domain, port ? port : dns->port)) {

		DEBUG_INFO("IP (%s)\n", domain);

		resolved(dns, 0);
		err = 0;
		goto out; /* free now */
	}
	/* Port specified - use AAAA or A lookup */
	else if (port) {
		sa_set_in(&dns->srv, 0, port);
		DEBUG_INFO("resolving A query: (%s)\n", domain);

		err = a_or_aaaa_query(dns, domain);
		if (err) {
			DEBUG_WARNING("%s: A/AAAA lookup failed (%m)\n",
				      domain, err);
			goto out;
		}
	}
	/* SRV lookup */
	else {
		char q[256];
		str_ncpy(dns->domain, domain, sizeof(dns->domain));
		(void)re_snprintf(q, sizeof(q), "_%s._%s.%s", service, proto,
				  domain);
		DEBUG_INFO("resolving SRV query: (%s)\n", q);
		err = dnsc_query(&dns->dq, dnsc, q, DNS_TYPE_SRV, DNS_CLASS_IN,
				 true, srv_handler, dns);
		if (err) {
			DEBUG_WARNING("%s: SRV lookup failed (%m)\n", q, err);
			goto out;
		}
	}

	*dnsp = dns;

	return 0;

 out:
	mem_deref(dns);
	return err;
}
Beispiel #9
0
/**
 * Send an HTTP request
 *
 * @param reqp      Pointer to allocated HTTP request object
 * @param cli       HTTP Client
 * @param met       Request method
 * @param uri       Request URI
 * @param resph     Response handler
 * @param datah     Content handler (optional)
 * @param arg       Handler argument
 * @param fmt       Formatted HTTP headers and body (optional)
 *
 * @return 0 if success, otherwise errorcode
 */
int http_request(struct http_req **reqp, struct http_cli *cli, const char *met,
		 const char *uri, http_resp_h *resph, http_data_h *datah,
		 void *arg, const char *fmt, ...)
{
	struct pl scheme, host, port, path;
	struct http_req *req;
	uint16_t defport;
	bool secure;
	va_list ap;
	int err;

	if (!reqp || !cli || !met || !uri)
		return EINVAL;

	if (re_regex(uri, strlen(uri), "[a-z]+://[^:/]+[:]*[0-9]*[^]+",
		     &scheme, &host, NULL, &port, &path) || scheme.p != uri)
		return EINVAL;

	if (!pl_strcasecmp(&scheme, "http") ||
	    !pl_strcasecmp(&scheme, "ws")) {
		secure  = false;
		defport = 80;
	}
#ifdef USE_TLS
	else if (!pl_strcasecmp(&scheme, "https") ||
		 !pl_strcasecmp(&scheme, "wss")) {
		secure  = true;
		defport = 443;
	}
#endif
	else
		return ENOTSUP;

	req = mem_zalloc(sizeof(*req), req_destructor);
	if (!req)
		return ENOMEM;

	req->tls    = mem_ref(cli->tls);
	req->secure = secure;
	req->port   = pl_isset(&port) ? pl_u32(&port) : defport;
	req->resph  = resph;
	req->datah  = datah;
	req->arg    = arg;

	err = pl_strdup(&req->host, &host);
	if (err)
		goto out;

	req->mbreq = mbuf_alloc(1024);
	if (!req->mbreq) {
		err = ENOMEM;
		goto out;
	}

	err = mbuf_printf(req->mbreq,
			  "%s %r HTTP/1.1\r\n"
			  "Host: %r\r\n",
			  met, &path, &host);
	if (fmt) {
		va_start(ap, fmt);
		err |= mbuf_vprintf(req->mbreq, fmt, ap);
		va_end(ap);
	}
	else {
		err |= mbuf_write_str(req->mbreq, "\r\n");
	}
	if (err)
		goto out;

	req->mbreq->pos = 0;

	if (!sa_set_str(&req->srvv[0], req->host, req->port)) {

		req->srvc = 1;

		err = req_connect(req);
		if (err)
			goto out;
	}
	else {
		err = dnsc_query(&req->dq, cli->dnsc, req->host,
				 DNS_TYPE_A, DNS_CLASS_IN, true,
				 query_handler, req);
		if (err)
			goto out;
	}

 out:
	if (err)
		mem_deref(req);
	else {
		req->reqp = reqp;
		*reqp = req;
	}

	return err;
}