int turn_init(const char *username, const char *password, const struct sa *peer, uint16_t loop_port) { int err = 0; turnc.username = username; turnc.password = password; turnc.peer = peer; err = udp_listen(&turnc.us, NULL, udp_recv, NULL); if (err) { DEBUG_WARNING("udp_listen: %m\n", err); goto out; } if (loop_port) { struct sa local; sa_set_in(&local, 0, loop_port); err = udp_listen(&turnc.loop_us, &local, udp_loop_recv, NULL); if (err) { DEBUG_WARNING("udp_listen: %m\n", err); goto out; } (void)re_printf("Local loop on port %u\n", loop_port); } out: return err; }
static int request_next(struct request *req, struct sa* dst) { struct dnsrr *rr; int err = 0; rr = list_ledata(req->addrl.head); if(!rr) return -ENOENT; switch (rr->type) { case DNS_TYPE_A: sa_set_in(dst, rr->rdata.a.addr, req->port); break; case DNS_TYPE_AAAA: sa_set_in6(dst, rr->rdata.aaaa.addr, req->port); break; default: return EINVAL; } list_unlink(&rr->le); mem_deref(rr); return err; }
/** * Handle incoming connects */ void tcp_sock::tcp_conn_handler() { if (!ctc) { DEBUG_WARNING("conn handler: no pending socket\n"); } TInetAddr ia; struct sa peer; ctc->iSocket.RemoteName(ia); sa_set_in(&peer, ia.Address(), ia.Port()); DEBUG_INFO("conn handler: incoming connect from %J\n", &peer); ctc->blank = false; /* * Application handler might call tcp_accept(), tcp_reject() * or do nothing */ if (connh) connh(&peer, arg); if (ctc) { DEBUG_INFO("delete ctc\n"); delete ctc; ctc = NULL; } /* Create blank socket for the next incoming CONNECT */ blank_socket(); cts->Accepting(); }
static void dns_handler(int err, const struct dnshdr *hdr, struct list *ansl, struct list *authl, struct list *addl, void *arg) { struct rst *rst = arg; struct dnsrr *rr; struct sa srv; (void)err; (void)hdr; (void)authl; (void)addl; rr = dns_rrlist_find(ansl, rst->host, DNS_TYPE_A, DNS_CLASS_IN, true); if (!rr) { re_printf("rst: unable to resolve: %s\n", rst->host); tmr_start(&rst->tmr, RETRY_WAIT, reconnect, rst); return; } sa_set_in(&srv, rr->rdata.a.addr, 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); tmr_start(&rst->tmr, RETRY_WAIT, reconnect, rst); return; } }
/** * Get the local IP address of the device * * @note Requires at least one IP packet sent in advance! */ int net_if_getaddr4(const char *ifname, int af, struct sa *ip) { (void)ifname; if (AF_INET != af) return EAFNOSUPPORT; /* Already cached? */ if (sa_isset(&local_ip, SA_ADDR)) { sa_cpy(ip, &local_ip); return 0; } RSocketServ ss; RSocket s; TInt ret; ret = ss.Connect(); if (KErrNone != ret) { DEBUG_WARNING("connecting to socket server fail (ret=%d)\n", ret); return ECONNREFUSED; } ret = s.Open(ss, KAfInet, KSockDatagram, KProtocolInetUdp); if (KErrNone != ret) { DEBUG_WARNING("open socket failed (ret=%d)\n", ret); return ECONNREFUSED; } TInetAddr bind; bind.SetPort(0); bind.SetAddress(KInetAddrAny); ret = s.Bind(bind); if (KErrNone != ret) { DEBUG_WARNING("bind socket failed (ret=%d)\n", ret); return ECONNREFUSED; } TInetAddr local; s.LocalName(local); s.Close(); ss.Close(); sa_set_in(&local_ip, local.Address(), local.Port()); DEBUG_NOTICE("local IP addr: %j\n", &local_ip); if (!sa_isset(&local_ip, SA_ADDR)) return EINVAL; sa_cpy(ip, &local_ip); return 0; }
static int request_next(struct sip_request *req) { struct dnsrr *rr; struct sa dst; int err; again: rr = list_ledata(req->addrl.head); if (!rr) { rr = list_ledata(req->srvl.head); if (!rr) return ENOENT; req->port = rr->rdata.srv.port; dns_rrlist_apply2(&req->cachel, rr->rdata.srv.target, DNS_TYPE_A, DNS_TYPE_AAAA, DNS_CLASS_IN, true, rr_append_handler, &req->addrl); list_unlink(&rr->le); if (req->addrl.head) { mem_deref(rr); goto again; } err = addr_lookup(req, rr->rdata.srv.target); mem_deref(rr); return err; } switch (rr->type) { case DNS_TYPE_A: sa_set_in(&dst, rr->rdata.a.addr, req->port); break; case DNS_TYPE_AAAA: sa_set_in6(&dst, rr->rdata.aaaa.addr, req->port); break; default: return EINVAL; } list_unlink(&rr->le); mem_deref(rr); err = request(req, req->tp, &dst); if (err) { if (req->addrl.head || req->srvl.head) goto again; } return err; }
int udp_sock::local_get(struct sa *local) const { TInetAddr ia; cus->iSocket.LocalName(ia); sa_set_in(local, ia.Address(), ia.Port()); return 0; }
int tcp_conn_peer_get(const struct tcp_conn *tc, struct sa *peer) { if (!tc || !peer) return EINVAL; TInetAddr ia; tc->ctc->iSocket.RemoteName(ia); sa_set_in(peer, ia.Address(), ia.Port()); return 0; }
int tcp_conn_local_get(const struct tcp_conn *tc, struct sa *local) { if (!tc || !local) return EINVAL; TInetAddr ia; tc->ctc->iSocket.LocalName(ia); sa_set_in(local, ia.Address(), ia.Port()); return 0; }
int tcp_sock_local_get(const struct tcp_sock *ts, struct sa *local) { if (!ts || !local) return EINVAL; TInetAddr ia; ts->cts->iSocket.LocalName(ia); sa_set_in(local, ia.Address(), ia.Port()); return 0; }
void udp_sock::recv() { struct mbuf *mb = mbuf_alloc(rx_presz + cus->iBufRx.Length()); if (!mb) return; mb->pos += rx_presz; mb->end += rx_presz; (void)mbuf_write_mem(mb, (uint8_t *)cus->iBufRx.Ptr(), cus->iBufRx.Length()); mb->pos = rx_presz; struct sa src; sa_set_in(&src, cus->iSource.Address(), cus->iSource.Port()); /* call helpers */ struct le *le = list_head(&helpers); while (le) { struct udp_helper *uh; bool hdld; uh = (struct udp_helper *)le->data; le = le->next; hdld = uh->recvh(&src, mb, uh->arg); if (hdld) goto out; } DEBUG_INFO("udp recv %d bytes from %J\n", cus->iBufRx.Length(), &src); cus->StartReceiving(); rh(&src, mb, arg); out: mem_deref(mb); }
/** * Get the IP address of the host * * @param af Address Family * @param ip Returned IP address * * @return 0 if success, otherwise errorcode */ int net_hostaddr(int af, struct sa *ip) { char hostname[256]; struct in_addr in; struct hostent *he; if (-1 == gethostname(hostname, sizeof(hostname))) return errno; he = gethostbyname(hostname); if (!he) return ENOENT; if (af != he->h_addrtype) return EAFNOSUPPORT; /* Get the first entry */ memcpy(&in, he->h_addr_list[0], sizeof(in)); sa_set_in(ip, ntohl(in.s_addr), 0); return 0; }
static bool rr_handler(struct dnsrr *rr, void *arg) { struct http_req *req = arg; if (req->srvc >= ARRAY_SIZE(req->srvv)) return true; switch (rr->type) { case DNS_TYPE_A: sa_set_in(&req->srvv[req->srvc++], rr->rdata.a.addr, req->port); break; case DNS_TYPE_AAAA: sa_set_in6(&req->srvv[req->srvc++], rr->rdata.aaaa.addr, req->port); break; } return false; }
static void extaddr_handler(int err, const struct natpmp_resp *resp, void *arg) { (void)arg; if (err) { warning("natpmp: external address ERROR: %m\n", err); return; } if (resp->result != NATPMP_SUCCESS) { warning("natpmp: external address failed" " with result code: %d\n", resp->result); return; } if (resp->op != NATPMP_OP_EXTERNAL) return; sa_set_in(&natpmp_extaddr, resp->u.ext_addr, 0); info("natpmp: discovered External address: %j\n", &natpmp_extaddr); }
static void a_handler(int err, const struct dnshdr *hdr, struct list *ansl, struct list *authl, struct list *addl, void *arg) { struct stun_dns *dns = arg; struct dnsrr *rr; (void)hdr; (void)authl; (void)addl; /* Find A answers */ rr = dns_rrlist_find(ansl, NULL, DNS_TYPE_A, DNS_CLASS_IN, false); if (!rr) { err = err ? err : EDESTADDRREQ; goto out; } sa_set_in(&dns->srv, rr->rdata.a.addr, sa_port(&dns->srv)); DEBUG_INFO("A answer: %j\n", &dns->srv); out: resolved(dns, err); }
/** * Allocate a new NAT Hairpinning discovery session * * @param nhp Pointer to allocated NAT Hairpinning object * @param proto Transport protocol * @param srv STUN Server IP address and port number * @param proto Transport protocol * @param conf STUN configuration (Optional) * @param hph Hairpinning result handler * @param arg Handler argument * * @return 0 if success, errorcode if failure */ int nat_hairpinning_alloc(struct nat_hairpinning **nhp, const struct sa *srv, int proto, const struct stun_conf *conf, nat_hairpinning_h *hph, void *arg) { struct nat_hairpinning *nh; struct sa local; int err; if (!srv || !hph) return EINVAL; nh = mem_zalloc(sizeof(*nh), hairpinning_destructor); if (!nh) return ENOMEM; err = stun_alloc(&nh->stun, conf, NULL, NULL); if (err) goto out; sa_cpy(&nh->srv, srv); nh->proto = proto; nh->hph = hph; nh->arg = arg; switch (proto) { case IPPROTO_UDP: err = udp_listen(&nh->us, NULL, udp_recv_handler, nh); break; case IPPROTO_TCP: sa_set_in(&local, 0, 0); /* * Part I - Allocate and bind all sockets */ err = tcp_sock_alloc(&nh->ts, &local, tcp_conn_handler, nh); if (err) break; err = tcp_conn_alloc(&nh->tc, &nh->srv, tcp_estab_handler, tcp_recv_handler, tcp_close_handler, nh); if (err) break; err = tcp_sock_bind(nh->ts, &local); if (err) break; err = tcp_sock_local_get(nh->ts, &local); if (err) break; err = tcp_conn_bind(nh->tc, &local); if (err) break; /* * Part II - Listen and connect all sockets */ err = tcp_sock_listen(nh->ts, 5); break; default: err = EPROTONOSUPPORT; break; } out: if (err) mem_deref(nh); else *nhp = nh; 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; }
static void srv_handler(int err, const struct dnshdr *hdr, struct list *ansl, struct list *authl, struct list *addl, void *arg) { struct stun_dns *dns = arg; struct dnsrr *rr, *arr; (void)hdr; (void)authl; dns_rrlist_sort(ansl, DNS_TYPE_SRV); /* Find SRV answers */ rr = dns_rrlist_find(ansl, NULL, DNS_TYPE_SRV, DNS_CLASS_IN, false); if (!rr) { DEBUG_INFO("no SRV entry, trying A lookup on \"%s\"\n", dns->domain); sa_set_in(&dns->srv, 0, dns->port); err = a_or_aaaa_query(dns, dns->domain); if (err) goto out; return; } DEBUG_INFO("SRV answer: %s:%u\n", rr->rdata.srv.target, rr->rdata.srv.port); /* Look for Additional information */ switch (dns->af) { case AF_INET: arr = dns_rrlist_find(addl, rr->rdata.srv.target, DNS_TYPE_A, DNS_CLASS_IN, true); if (arr) { sa_set_in(&dns->srv, arr->rdata.a.addr, rr->rdata.srv.port); DEBUG_INFO("additional A: %j\n", &dns->srv); goto out; } break; #ifdef HAVE_INET6 case AF_INET6: arr = dns_rrlist_find(addl, rr->rdata.srv.target, DNS_TYPE_AAAA, DNS_CLASS_IN, true); if (arr) { sa_set_in6(&dns->srv, arr->rdata.aaaa.addr, rr->rdata.srv.port); DEBUG_INFO("additional AAAA: %j\n", &dns->srv); goto out; } break; #endif } sa_set_in(&dns->srv, 0, rr->rdata.srv.port); err = a_or_aaaa_query(dns, rr->rdata.srv.target); if (err) { DEBUG_WARNING("SRV: A lookup failed (%m)\n", err); goto out; } DEBUG_INFO("SRV handler: doing A/AAAA lookup..\n"); return; out: resolved(dns, err); }