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); }
void sdp_media_set_lport_rtcp(struct sdp_media *m, uint16_t port) { if (!m) return; sa_set_port(&m->laddr_rtcp, port); }
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; }
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; }
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); } }
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; }
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); }
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); }
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; }
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; }
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; }
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); }
/** * 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); }
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; }
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; }
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 }
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; } }
/* 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); }
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; }
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; }
/* * 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; }
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(®, 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; }
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); }
/* * 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; }
/* * 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; }
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; } }
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; }