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; } }
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; }
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; }
/** * 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; }