static int rtpp_stream_guess_addr(struct rtpp_stream *self, struct rtp_packet *packet) { int rport; const char *actor, *ptype; struct rtpp_stream_priv *pvt; pvt = PUB2PVT(self); if (self->addr != NULL && ishostseq(self->addr, sstosa(&packet->raddr))) { return (0); } if (self->addr == NULL) { self->addr = malloc(packet->rlen); if (self->addr == NULL) { return (-1); } } actor = rtpp_stream_get_actor(self); ptype = rtpp_stream_get_proto(self); rport = ntohs(satosin(&packet->raddr)->sin_port); if (IS_LAST_PORT(rport)) { return (-1); } memcpy(self->addr, &packet->raddr, packet->rlen); satosin(self->addr)->sin_port = htons(rport + 1); /* Use guessed value as the only true one for asymmetric clients */ self->latch_info.latched = self->asymmetric; RTPP_LOG(pvt->pub.log, RTPP_LOG_INFO, "guessing %s port " "for %s to be %d", ptype, actor, rport + 1); return (0); }
static int prepare_pkt_hdr_adhoc(struct rtpp_session *sp, struct rtp_packet *packet, struct pkt_hdr_adhoc *hdrp, struct sockaddr *daddr, struct sockaddr *ldaddr, int ldport, int face) { memset(hdrp, 0, sizeof(*hdrp)); hdrp->time = packet->rtime; if (hdrp->time == -1) { rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "can't get current time"); return -1; } switch (sstosa(&packet->raddr)->sa_family) { case AF_INET: hdrp->addr.in4.sin_family = sstosa(&packet->raddr)->sa_family; hdrp->addr.in4.sin_port = satosin(&packet->raddr)->sin_port; hdrp->addr.in4.sin_addr = satosin(&packet->raddr)->sin_addr; break; case AF_INET6: hdrp->addr.in6.sin_family = sstosa(&packet->raddr)->sa_family; hdrp->addr.in6.sin_port = satosin6(&packet->raddr)->sin6_port; hdrp->addr.in6.sin_addr = satosin6(&packet->raddr)->sin6_addr; break; default: abort(); } hdrp->plen = packet->size; return 0; }
/* * Start output on the mpe interface. */ void mpestart(struct ifnet *ifp) { struct mbuf *m; struct sockaddr *sa = (struct sockaddr *)&mpedst; int s; sa_family_t af; struct rtentry *rt; for (;;) { s = splnet(); IFQ_DEQUEUE(&ifp->if_snd, m); splx(s); if (m == NULL) return; af = *mtod(m, sa_family_t *); m_adj(m, sizeof(af)); switch (af) { case AF_INET: bzero(sa, sizeof(struct sockaddr_in)); satosin(sa)->sin_family = af; satosin(sa)->sin_len = sizeof(struct sockaddr_in); bcopy(mtod(m, caddr_t), &satosin(sa)->sin_addr, sizeof(in_addr_t)); m_adj(m, sizeof(in_addr_t)); break; default: m_freem(m); continue; } rt = rtalloc1(sa, RT_REPORT, 0); if (rt == NULL) { /* no route give up */ m_freem(m); continue; } #if NBPFILTER > 0 if (ifp->if_bpf) { /* remove MPLS label before passing packet to bpf */ m->m_data += sizeof(struct shim_hdr); m->m_len -= sizeof(struct shim_hdr); m->m_pkthdr.len -= sizeof(struct shim_hdr); bpf_mtap_af(ifp->if_bpf, af, m, BPF_DIRECTION_OUT); m->m_data -= sizeof(struct shim_hdr); m->m_len += sizeof(struct shim_hdr); m->m_pkthdr.len += sizeof(struct shim_hdr); } #endif /* XXX lie, but mpls_output will only look at sa_family */ sa->sa_family = AF_MPLS; mpls_output(rt->rt_ifp, m, sa, rt); RTFREE(rt); } }
void rwrite(struct rtpp_session *sp, void *rrc, struct sockaddr *saddr, void *buf, int len) { struct iovec v[2]; struct pkt_hdr hdr; int rval; if (RRC_CAST(rrc)->fd == -1) return; memset(&hdr, 0, sizeof(hdr)); hdr.time = getctime(); if (hdr.time == -1) { rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "can't get current time"); goto fatal_error; } switch (saddr->sa_family) { case AF_INET: hdr.addr.in4.sin_family = saddr->sa_family; hdr.addr.in4.sin_port = satosin(saddr)->sin_port; hdr.addr.in4.sin_addr = satosin(saddr)->sin_addr; break; case AF_INET6: hdr.addr.in6.sin_family = saddr->sa_family; hdr.addr.in6.sin_port = satosin6(saddr)->sin6_port; hdr.addr.in6.sin_addr = satosin6(saddr)->sin6_addr; break; default: abort(); } hdr.plen = len; v[0].iov_base = (void *)&hdr; v[0].iov_len = sizeof(hdr); v[1].iov_base = buf; v[1].iov_len = len; rval = writev(RRC_CAST(rrc)->fd, v, 2); if (rval != -1) return; rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "error while recording session (%s)", (sp->rtcp != NULL) ? "RTP" : "RTCP"); fatal_error: /* Prevent futher writing if error happens */ close(RRC_CAST(rrc)->fd); RRC_CAST(rrc)->fd = -1; }
int server_lookup(struct sockaddr *client, struct sockaddr *proxy, struct sockaddr *server, u_int8_t proto) { if (client->sa_family == AF_INET) return (server_lookup4(satosin(client), satosin(proxy), satosin(server), proto)); if (client->sa_family == AF_INET6) return (server_lookup6(satosin6(client), satosin6(proxy), satosin6(server), proto)); errno = EPROTONOSUPPORT; return (-1); }
/* * Call at splnet(). */ static void tuninit(struct tun_softc *tp) { struct ifnet *ifp = &tp->tun_if; struct ifaddr *ifa; TUNDEBUG("%s: tuninit\n", ifp->if_xname); mutex_enter(&tp->tun_lock); ifp->if_flags |= IFF_UP | IFF_RUNNING; tp->tun_flags &= ~(TUN_IASET|TUN_DSTADDR); IFADDR_FOREACH(ifa, ifp) { #ifdef INET if (ifa->ifa_addr->sa_family == AF_INET) { struct sockaddr_in *sin; sin = satosin(ifa->ifa_addr); if (sin && sin->sin_addr.s_addr) tp->tun_flags |= TUN_IASET; if (ifp->if_flags & IFF_POINTOPOINT) { sin = satosin(ifa->ifa_dstaddr); if (sin && sin->sin_addr.s_addr) tp->tun_flags |= TUN_DSTADDR; } } #endif #ifdef INET6 if (ifa->ifa_addr->sa_family == AF_INET6) { struct sockaddr_in6 *sin; sin = (struct sockaddr_in6 *)ifa->ifa_addr; if (!IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr)) tp->tun_flags |= TUN_IASET; if (ifp->if_flags & IFF_POINTOPOINT) { sin = (struct sockaddr_in6 *)ifa->ifa_dstaddr; if (sin && !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr)) tp->tun_flags |= TUN_DSTADDR; } else tp->tun_flags &= ~TUN_DSTADDR; } #endif /* INET6 */ } mutex_exit(&tp->tun_lock); }
int add_nat(u_int32_t id, struct sockaddr *src, struct sockaddr *dst, u_int16_t d_port, struct sockaddr *nat, u_int16_t nat_range_low, u_int16_t nat_range_high, u_int8_t proto) { if (!src || !dst || !d_port || !nat || !nat_range_low || !proto || (src->sa_family != nat->sa_family)) { errno = EINVAL; return (-1); } if (prepare_rule(id, PF_RULESET_NAT, src, dst, d_port, proto) == -1) return (-1); if (nat->sa_family == AF_INET) { memcpy(&pfp.addr.addr.v.a.addr.v4, &satosin(nat)->sin_addr.s_addr, 4); memset(&pfp.addr.addr.v.a.mask.addr8, 255, 4); } else { memcpy(&pfp.addr.addr.v.a.addr.v6, &satosin6(nat)->sin6_addr.s6_addr, 16); memset(&pfp.addr.addr.v.a.mask.addr8, 255, 16); } if (ioctl(dev, DIOCADDADDR, &pfp) == -1) return (-1); pfr.rule.rpool.proxy_port[0] = nat_range_low; pfr.rule.rpool.proxy_port[1] = nat_range_high; if (ioctl(dev, DIOCADDRULE, &pfr) == -1) return (-1); return (0); }
char * routename(struct sockaddr *sa, int flags) { static char line[NI_MAXHOST]; int error, f; f = (flags) ? NI_NUMERICHOST : 0; error = getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0, f); if (error) { const void *src; switch (sa->sa_family) { #ifdef INET case AF_INET: src = &satosin(sa)->sin_addr; break; #endif /* INET */ #ifdef INET6 case AF_INET6: src = &satosin6(sa)->sin6_addr; break; #endif /* INET6 */ default: return(line); } inet_ntop(sa->sa_family, src, line, sizeof(line) - 1); return (line); } trimdomain(line, strlen(line)); return (line); }
int add_rdr(u_int32_t id, struct sockaddr *src, struct sockaddr *dst, u_int16_t d_port, struct sockaddr *rdr, u_int16_t rdr_port, u_int8_t proto) { if (!src || !dst || !d_port || !rdr || !rdr_port || !proto || (src->sa_family != rdr->sa_family)) { errno = EINVAL; return (-1); } if (prepare_rule(id, PF_RULESET_RDR, src, dst, d_port, proto) == -1) return (-1); if (rdr->sa_family == AF_INET) { memcpy(&pfp.addr.addr.v.a.addr.v4, &satosin(rdr)->sin_addr.s_addr, 4); memset(&pfp.addr.addr.v.a.mask.addr8, 255, 4); } else { memcpy(&pfp.addr.addr.v.a.addr.v6, &satosin6(rdr)->sin6_addr.s6_addr, 16); memset(&pfp.addr.addr.v.a.mask.addr8, 255, 16); } if (ioctl(dev, DIOCADDADDR, &pfp) == -1) return (-1); pfr.rule.rpool.proxy_port[0] = rdr_port; if (ioctl(dev, DIOCADDRULE, &pfr) == -1) return (-1); return (0); }
int mpeoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt) { struct shim_hdr shim; int s; int error; int off; u_int8_t op = 0; #ifdef DIAGNOSTIC if (ifp->if_rdomain != rtable_l2(m->m_pkthdr.rdomain)) { printf("%s: trying to send packet on wrong domain. " "if %d vs. mbuf %d\n", ifp->if_xname, ifp->if_rdomain, rtable_l2(m->m_pkthdr.rdomain)); } #endif m->m_pkthdr.rcvif = ifp; /* XXX assumes MPLS is always in rdomain 0 */ m->m_pkthdr.rdomain = 0; error = 0; switch (dst->sa_family) { #ifdef INET case AF_INET: if (rt && rt->rt_flags & RTF_MPLS) { shim.shim_label = ((struct rt_mpls *)rt->rt_llinfo)->mpls_label; shim.shim_label |= MPLS_BOS_MASK; op = ((struct rt_mpls *)rt->rt_llinfo)->mpls_operation; } if (op != MPLS_OP_PUSH) { m_freem(m); error = ENETUNREACH; goto out; } if (mpls_mapttl_ip) { struct ip *ip; ip = mtod(m, struct ip *); shim.shim_label |= htonl(ip->ip_ttl) & MPLS_TTL_MASK; } else shim.shim_label |= htonl(mpls_defttl) & MPLS_TTL_MASK; off = sizeof(sa_family_t) + sizeof(in_addr_t); M_PREPEND(m, sizeof(shim) + off, M_DONTWAIT); if (m == NULL) { error = ENOBUFS; goto out; } *mtod(m, sa_family_t *) = AF_INET; m_copyback(m, sizeof(sa_family_t), sizeof(in_addr_t), (caddr_t)&((satosin(dst)->sin_addr)), M_NOWAIT); break; #endif default: m_freem(m); error = EPFNOSUPPORT; goto out; }
void openlog(const char *ident, int logstat, int logfac) { if (ident != NULL) LogTag = ident; LogStat = logstat; if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0) LogFacility = logfac; if (LogFile == -1) { #ifndef USE_INET SyslogAddr.sa_family = AF_UNIX; (void)strncpy(SyslogAddr.sa_data, _PATH_LOG, sizeof(SyslogAddr.sa_data)); if (LogStat & LOG_NDELAY) { if ((LogFile = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) return; (void)fcntl(LogFile, F_SETFD, 1); } #else #define satosin(sa) ((struct sockaddr_in *)(sa)) satosin(&SyslogAddr)->sin_family = AF_INET; satosin(&SyslogAddr)->sin_port = 514; satosin(&SyslogAddr)->sin_addr.s_addr = inet_addr("127.0.0.1"); if (LogStat & LOG_NDELAY) { if ((LogFile = socket(AF_INET, SOCK_DGRAM, 0)) == -1) return; (void)fcntl(LogFile, F_SETFD, 1); if (connect(LogFile, &SyslogAddr, sizeof(SyslogAddr)) < 0) { closelog(); return; } } #endif } if (LogFile != -1 && !connected) { if (connect(LogFile, &SyslogAddr, sizeof(SyslogAddr)) == -1) { (void)close(LogFile); LogFile = -1; } else connected = 1; } }
int set_mcast_if(struct sockaddr *int_addr) { struct in_addr if_addr; if_addr.s_addr = satosin(*int_addr)->sin_addr.s_addr; return setsockopt_multicast_ipv4(sock, IP_MULTICAST_IF, if_addr, 0xE0000009, 0); }
int mcast_leave(struct sockaddr *int_addr) { struct in_addr if_addr; if_addr.s_addr = satosin(*int_addr)->sin_addr.s_addr; return setsockopt_multicast_ipv4(sock, IP_DROP_MEMBERSHIP, if_addr, 0xE0000009, 0); }
int Mod_fw_lookup_orig_dst(FW_handle_T handle, struct sockaddr *src, struct sockaddr *proxy, struct sockaddr *orig_dst) { struct fw_handle *fwh = handle->fwh; if(src->sa_family == AF_INET) { return server_lookup4(fwh->pfdev, satosin(src), satosin(proxy), satosin(orig_dst)); } if(src->sa_family == AF_INET6) { return server_lookup6(fwh->pfdev, satosin6(src), satosin6(proxy), satosin6(orig_dst)); } errno = EPROTONOSUPPORT; return -1; }
static int create_twinlistener(struct cfg_stable *cf, struct sockaddr *ia, int port, int *fds) { struct sockaddr_storage iac; int rval, i, flags; fds[0] = fds[1] = -1; rval = -1; for (i = 0; i < 2; i++) { fds[i] = socket(ia->sa_family, SOCK_DGRAM, 0); if (fds[i] == -1) { rtpp_log_ewrite(RTPP_LOG_ERR, cf->glog, "can't create %s socket", (ia->sa_family == AF_INET) ? "IPv4" : "IPv6"); goto failure; } memcpy(&iac, ia, SA_LEN(ia)); satosin(&iac)->sin_port = htons(port); if (bind(fds[i], sstosa(&iac), SA_LEN(ia)) != 0) { if (errno != EADDRINUSE && errno != EACCES) { rtpp_log_ewrite(RTPP_LOG_ERR, cf->glog, "can't bind to the %s port %d", (ia->sa_family == AF_INET) ? "IPv4" : "IPv6", port); } else { rval = -2; } goto failure; } port++; if ((ia->sa_family == AF_INET) && (cf->tos >= 0) && (setsockopt(fds[i], IPPROTO_IP, IP_TOS, &cf->tos, sizeof(cf->tos)) == -1)) rtpp_log_ewrite(RTPP_LOG_ERR, cf->glog, "unable to set TOS to %d", cf->tos); flags = fcntl(fds[i], F_GETFL); fcntl(fds[i], F_SETFL, flags | O_NONBLOCK); } return 0; failure: for (i = 0; i < 2; i++) if (fds[i] != -1) { close(fds[i]); fds[i] = -1; } return rval; }
/* * Return the name of the network whose address is given. */ const char * netname(struct sockaddr *sa, struct sockaddr *mask) { switch (sa->sa_family) { case AF_INET: if (mask != NULL) return (netname4(satosin(sa)->sin_addr.s_addr, satosin(mask)->sin_addr.s_addr)); else return (netname4(satosin(sa)->sin_addr.s_addr, INADDR_ANY)); break; #ifdef INET6 case AF_INET6: return (netname6(satosin6(sa), satosin6(mask))); #endif /* INET6 */ default: return (NULL); } }
static int prepare_pkt_hdr_pcap(struct rtpp_session *sp, struct rtp_packet *packet, struct pkt_hdr_pcap *hdrp) { if (packet->rtime == -1) { rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "can't get current time"); return -1; } if (sstosa(&packet->raddr)->sa_family != AF_INET) { rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "only AF_INET pcap format is supported"); return -1; } memset(hdrp, 0, sizeof(*hdrp)); dtime2ts(packet->rtime, &(hdrp->pcaprec_hdr.ts_sec), &(hdrp->pcaprec_hdr.ts_usec)); hdrp->pcaprec_hdr.orig_len = hdrp->pcaprec_hdr.incl_len = sizeof(*hdrp) - sizeof(hdrp->pcaprec_hdr) + packet->size; hdrp->family = sstosa(&packet->raddr)->sa_family; /* Prepare fake IP header */ hdrp->iphdr.ip_v = 4; hdrp->iphdr.ip_hl = sizeof(hdrp->iphdr) >> 2; hdrp->iphdr.ip_len = htons(sizeof(hdrp->iphdr) + sizeof(hdrp->udphdr) + packet->size); hdrp->iphdr.ip_src = satosin(&(packet->raddr))->sin_addr; hdrp->iphdr.ip_dst = satosin(packet->laddr)->sin_addr; hdrp->iphdr.ip_p = IPPROTO_UDP; hdrp->iphdr.ip_id = htons(ip_id++); hdrp->iphdr.ip_ttl = 127; hdrp->iphdr.ip_sum = rtpp_in_cksum(&(hdrp->iphdr), sizeof(hdrp->iphdr)); /* Prepare fake UDP header */ hdrp->udphdr.uh_sport = satosin(&packet->raddr)->sin_port; hdrp->udphdr.uh_dport = htons(packet->rport); hdrp->udphdr.uh_ulen = htons(sizeof(hdrp->udphdr) + packet->size); return 0; }
/* * Do what we need to do when inserting a route. */ static struct radix_node * in_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, struct radix_node *treenodes) { struct rtentry *rt = (struct rtentry *)treenodes; struct sockaddr_in *sin = (struct sockaddr_in *)rt_key(rt); RADIX_NODE_HEAD_WLOCK_ASSERT(head); /* * A little bit of help for both IP output and input: * For host routes, we make sure that RTF_BROADCAST * is set for anything that looks like a broadcast address. * This way, we can avoid an expensive call to in_broadcast() * in ip_output() most of the time (because the route passed * to ip_output() is almost always a host route). * * We also do the same for local addresses, with the thought * that this might one day be used to speed up ip_input(). * * We also mark routes to multicast addresses as such, because * it's easy to do and might be useful (but this is much more * dubious since it's so easy to inspect the address). */ if (rt->rt_flags & RTF_HOST) { if (in_broadcast(sin->sin_addr, rt->rt_ifp)) { rt->rt_flags |= RTF_BROADCAST; } else if (satosin(rt->rt_ifa->ifa_addr)->sin_addr.s_addr == sin->sin_addr.s_addr) { rt->rt_flags |= RTF_LOCAL; } } if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) rt->rt_flags |= RTF_MULTICAST; if (rt->rt_ifp != NULL) { /* * Check route MTU: * inherit interface MTU if not set or * check if MTU is too large. */ if (rt->rt_mtu == 0) { rt->rt_mtu = rt->rt_ifp->if_mtu; } else if (rt->rt_mtu > rt->rt_ifp->if_mtu) rt->rt_mtu = rt->rt_ifp->if_mtu; } return (rn_addroute(v_arg, n_arg, head, treenodes)); }
int add_addr(struct sockaddr *addr, struct pf_pool *pfp) { if (addr->sa_family == AF_INET) { memcpy(&pfp->addr.v.a.addr.v4, &satosin(addr)->sin_addr.s_addr, 4); memset(&pfp->addr.v.a.mask.addr8, 255, 4); } else { memcpy(&pfp->addr.v.a.addr.v6, &satosin6(addr)->sin6_addr.s6_addr, 16); memset(&pfp->addr.v.a.mask.addr8, 255, 16); } pfp->addr.type = PF_ADDR_ADDRMASK; return (0); }
__private_extern__ uint32_t inpcb_find_anypcb_byaddr(struct ifaddr *ifa, struct inpcbinfo *pcbinfo) { struct inpcb *inp; inp_gen_t gencnt = pcbinfo->ipi_gencnt; struct socket *so = NULL; int af; if ((ifa->ifa_addr->sa_family != AF_INET) && (ifa->ifa_addr->sa_family != AF_INET6)) { return (0); } lck_rw_lock_shared(pcbinfo->ipi_lock); for (inp = LIST_FIRST(pcbinfo->ipi_listhead); inp != NULL; inp = LIST_NEXT(inp, inp_list)) { if (inp->inp_gencnt <= gencnt && inp->inp_state != INPCB_STATE_DEAD && inp->inp_socket != NULL) { so = inp->inp_socket; af = SOCK_DOM(so); if (af != ifa->ifa_addr->sa_family) continue; if (inp->inp_last_outifp != ifa->ifa_ifp) continue; if (af == AF_INET) { if (inp->inp_laddr.s_addr == (satosin(ifa->ifa_addr))->sin_addr.s_addr) { lck_rw_done(pcbinfo->ipi_lock); return (1); } } if (af == AF_INET6) { if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &inp->in6p_laddr)) { lck_rw_done(pcbinfo->ipi_lock); return (1); } } } } lck_rw_done(pcbinfo->ipi_lock); return (0); }
/** Create and start a new answering machine from the given info */ void AnswMachine::launchAnswMach(NEW_CTL_MSG msginfo, int mode) { if ((fork()) == 0) /* let's fork to let the daemon process other messages */ { #define satosin(sa) ((struct sockaddr_in *)(sa)) AnswMachine * am = new AnswMachine( (satosin(&msginfo.ctl_addr))->sin_addr, /* Caller's machine address */ msginfo.r_name, msginfo.l_name, mode); am->start(); delete am; // exit the child exit(-1); } }
void do_announce(CTL_MSG *mp, CTL_RESPONSE *rp) { struct hostent *hp; CTL_MSG *ptr; int result; /* see if the user is logged */ result = find_user(mp->r_name, mp->r_tty); if (result != SUCCESS) { rp->answer = result; return; } #define satosin(sa) ((struct sockaddr_in *)(void *)(sa)) hp = gethostbyaddr(&satosin(&mp->ctl_addr)->sin_addr, sizeof (struct in_addr), AF_INET); if (hp == NULL) { rp->answer = MACHINE_UNKNOWN; return; } ptr = find_request(mp); if (ptr == NULL) { insert_table(mp, rp); rp->answer = announce(mp, hp->h_name); return; } if (mp->id_num > ptr->id_num) { /* * This is an explicit re-announce, so update the id_num * field to avoid duplicates and re-announce the talk. */ ptr->id_num = new_id(); rp->id_num = htonl(ptr->id_num); rp->answer = announce(mp, hp->h_name); } else { /* a duplicated request, so ignore it */ rp->id_num = htonl(ptr->id_num); rp->answer = SUCCESS; } }
int in_pcbladdr(struct inpcb *inp, struct mbuf *nam, struct sockaddr_in **plocal_sin) { struct in_ifaddr *ia; register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); if (nam->m_len != sizeof (*sin)) return (EINVAL); if (sin->sin_family != AF_INET) return (EAFNOSUPPORT); if (sin->sin_port == 0) return (EADDRNOTAVAIL); if (in_ifaddr) { /* * If the destination address is INADDR_ANY, * use the primary local address. * If the supplied address is INADDR_BROADCAST, * and the primary interface supports broadcast, * choose the broadcast address for that interface. */ #define satosin(sa) ((struct sockaddr_in *)(sa)) #define sintosa(sin) ((struct sockaddr *)(sin)) #define ifatoia(ifa) ((struct in_ifaddr *)(ifa)) if (sin->sin_addr.s_addr == INADDR_ANY) sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr; else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST && (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST)) sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr; } if (inp->inp_laddr.s_addr == INADDR_ANY) { register struct route *ro; ia = (struct in_ifaddr *)0; /* * If route is known or can be allocated now, * our src addr is taken from the i/f, else punt. */ ro = &inp->inp_route; if (ro->ro_rt && (satosin(&ro->ro_dst)->sin_addr.s_addr != sin->sin_addr.s_addr || inp->inp_socket->so_options & SO_DONTROUTE)) { RTFREE(ro->ro_rt); ro->ro_rt = (struct rtentry *)0; } if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ (ro->ro_rt == (struct rtentry *)0 || ro->ro_rt->rt_ifp == (struct ifnet *)0)) { /* No route yet, so try to acquire one */ ro->ro_dst.sa_family = AF_INET; ro->ro_dst.sa_len = sizeof(struct sockaddr_in); ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = sin->sin_addr; rtalloc(ro); } /* * If we found a route, use the address * corresponding to the outgoing interface * unless it is the loopback (in case a route * to our address on another net goes to loopback). */ if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK)) ia = ifatoia(ro->ro_rt->rt_ifa); if (ia == 0) { u_short fport = sin->sin_port; sin->sin_port = 0; ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin))); if (ia == 0) ia = ifatoia(ifa_ifwithnet(sintosa(sin))); sin->sin_port = fport; if (ia == 0) ia = in_ifaddr; if (ia == 0) return (EADDRNOTAVAIL); } /* * If the destination address is multicast and an outgoing * interface has been set as a multicast option, use the * address of that interface as our source address. */ if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) && inp->inp_moptions != NULL) { struct ip_moptions *imo; struct ifnet *ifp; imo = inp->inp_moptions; if (imo->imo_multicast_ifp != NULL) { ifp = imo->imo_multicast_ifp; for (ia = in_ifaddr; ia; ia = ia->ia_next) if (ia->ia_ifp == ifp) break; if (ia == 0) return (EADDRNOTAVAIL); } } /* * Don't do pcblookup call here; return interface in plocal_sin * and exit to caller, that will do the lookup. */ *plocal_sin = &ia->ia_addr; } return(0); }
struct ul_opts * rtpp_command_ul_opts_parse(struct cfg *cf, struct rtpp_command *cmd) { int len, tpf, n, i; char c; char *cp, *t; const char *errmsg; struct sockaddr_storage tia; struct ul_opts *ulop; ulop = rtpp_zmalloc(sizeof(struct ul_opts)); if (ulop == NULL) { reply_error(cmd, ECODE_NOMEM_1); goto err_undo_0; } ul_opts_init(cf, ulop); if (cmd->cca.op == UPDATE && cmd->argc > 6) { if (cmd->argc == 8) { ulop->notify_socket = cmd->argv[6]; ulop->notify_tag = cmd->argv[7]; } else { ulop->notify_socket = cmd->argv[5]; ulop->notify_tag = cmd->argv[6]; cmd->cca.to_tag = NULL; } len = url_unquote((uint8_t *)ulop->notify_tag, strlen(ulop->notify_tag)); if (len == -1) { RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR, "command syntax error - invalid URL encoding"); reply_error(cmd, ECODE_PARSE_10); goto err_undo_1; } ulop->notify_tag[len] = '\0'; } ulop->addr = cmd->argv[2]; ulop->port = cmd->argv[3]; /* Process additional command modifiers */ for (cp = cmd->argv[0] + 1; *cp != '\0'; cp++) { switch (*cp) { case 'a': case 'A': ulop->asymmetric = 1; break; case 'e': case 'E': if (ulop->lidx < 0 || cf->stable->bindaddr[1] == NULL) { RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR, "command syntax error"); reply_error(cmd, ECODE_PARSE_11); goto err_undo_1; } ulop->lia[ulop->lidx] = cf->stable->bindaddr[1]; ulop->lidx--; break; case 'i': case 'I': if (ulop->lidx < 0 || cf->stable->bindaddr[1] == NULL) { RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR, "command syntax error"); reply_error(cmd, ECODE_PARSE_12); goto err_undo_1; } ulop->lia[ulop->lidx] = cf->stable->bindaddr[0]; ulop->lidx--; break; case '6': ulop->pf = AF_INET6; break; case 's': case 'S': ulop->asymmetric = 0; break; case 'w': case 'W': ulop->weak = 1; break; case 'z': case 'Z': ulop->requested_ptime = strtol(cp + 1, &cp, 10); if (ulop->requested_ptime <= 0) { RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR, "command syntax error"); reply_error(cmd, ECODE_PARSE_13); goto err_undo_1; } cp--; break; case 'c': case 'C': cp += 1; for (t = cp; *cp != '\0'; cp++) { if (!isdigit(*cp) && *cp != ',') break; } if (t == cp) { RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR, "command syntax error"); reply_error(cmd, ECODE_PARSE_14); goto err_undo_1; } ulop->codecs = malloc(cp - t + 1); if (ulop->codecs == NULL) { reply_error(cmd, ECODE_NOMEM_2); goto err_undo_1; } memcpy(ulop->codecs, t, cp - t); ulop->codecs[cp - t] = '\0'; cp--; break; case 'l': case 'L': len = extractaddr(cp + 1, &t, &cp, &tpf); if (len == -1) { RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR, "command syntax error"); reply_error(cmd, ECODE_PARSE_15); goto err_undo_1; } c = t[len]; t[len] = '\0'; ulop->local_addr = host2bindaddr(cf, t, tpf, &errmsg); if (ulop->local_addr == NULL) { RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR, "invalid local address: %s: %s", t, errmsg); reply_error(cmd, ECODE_INVLARG_1); goto err_undo_1; } t[len] = c; cp--; break; case 'r': case 'R': len = extractaddr(cp + 1, &t, &cp, &tpf); if (len == -1) { RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR, "command syntax error"); reply_error(cmd, ECODE_PARSE_16); goto err_undo_1; } c = t[len]; t[len] = '\0'; ulop->local_addr = alloca(sizeof(struct sockaddr_storage)); n = resolve(ulop->local_addr, tpf, t, SERVICE, AI_PASSIVE); if (n != 0) { RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR, "invalid remote address: %s: %s", t, gai_strerror(n)); reply_error(cmd, ECODE_INVLARG_2); goto err_undo_1; } if (local4remote(ulop->local_addr, satoss(ulop->local_addr)) == -1) { RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR, "can't find local address for remote address: %s", t); reply_error(cmd, ECODE_INVLARG_3); goto err_undo_1; } ulop->local_addr = addr2bindaddr(cf, ulop->local_addr, &errmsg); if (ulop->local_addr == NULL) { RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR, "invalid local address: %s", errmsg); reply_error(cmd, ECODE_INVLARG_4); goto err_undo_1; } t[len] = c; cp--; break; case 'n': case 'N': ulop->new_port = 1; break; default: RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR, "unknown command modifier `%c'", *cp); break; } } if (ulop->addr != NULL && ulop->port != NULL && strlen(ulop->addr) >= 7) { n = resolve(sstosa(&tia), ulop->pf, ulop->addr, ulop->port, AI_NUMERICHOST); if (n == 0) { if (!ishostnull(sstosa(&tia))) { for (i = 0; i < 2; i++) { ulop->ia[i] = malloc(SS_LEN(&tia)); if (ulop->ia[i] == NULL) { reply_error(cmd, ECODE_NOMEM_3); goto err_undo_1; } memcpy(ulop->ia[i], &tia, SS_LEN(&tia)); } /* Set port for RTCP, will work both for IPv4 and IPv6 */ n = ntohs(satosin(ulop->ia[1])->sin_port); satosin(ulop->ia[1])->sin_port = htons(n + 1); } } else { RTPP_LOG(cf->stable->glog, RTPP_LOG_ERR, "getaddrinfo(pf=%d, addr=%s, port=%s): %s", ulop->pf, ulop->addr, ulop->port, gai_strerror(n)); } } return (ulop); err_undo_1: rtpp_command_ul_opts_free(ulop); err_undo_0: return (NULL); }
int handle_command(struct cfg *cf, int controlfd, double dtime) { int len, argc, i, pidx, asymmetric; int external, pf, lidx, playcount, weak, tpf; int fds[2], lport, n; socklen_t rlen; char buf[1024 * 8]; char *cp, *call_id, *from_tag, *to_tag, *addr, *port, *cookie; char *pname, *codecs, *recording_name, *t; struct rtpp_session *spa, *spb; char **ap, *argv[10]; const char *rname, *errmsg; struct sockaddr *ia[2], *lia[2]; struct sockaddr_storage raddr; int requested_nsamples; enum {DELETE, RECORD, PLAY, NOPLAY, COPY, UPDATE, LOOKUP, QUERY} op; int max_argc; char *socket_name_u, *notify_tag; struct sockaddr *local_addr; char c; requested_nsamples = -1; ia[0] = ia[1] = NULL; spa = spb = NULL; lia[0] = lia[1] = cf->bindaddr[0]; lidx = 1; fds[0] = fds[1] = -1; recording_name = NULL; socket_name_u = notify_tag = NULL; local_addr = NULL; codecs = NULL; if (cf->umode == 0) { for (;;) { len = read(controlfd, buf, sizeof(buf) - 1); if (len != -1 || (errno != EAGAIN && errno != EINTR)) break; sched_yield(); } } else { rlen = sizeof(raddr); len = recvfrom(controlfd, buf, sizeof(buf) - 1, 0, sstosa(&raddr), &rlen); } if (len == -1) { if (errno != EAGAIN && errno != EINTR) rtpp_log_ewrite(RTPP_LOG_ERR, cf->glog, "can't read from control socket"); return -1; } buf[len] = '\0'; rtpp_log_write(RTPP_LOG_DBUG, cf->glog, "received command \"%s\"", buf); cp = buf; argc = 0; memset(argv, 0, sizeof(argv)); for (ap = argv; (*ap = rtpp_strsep(&cp, "\r\n\t ")) != NULL;) if (**ap != '\0') { argc++; if (++ap >= &argv[10]) break; } cookie = NULL; if (argc < 1 || (cf->umode != 0 && argc < 2)) { rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error"); reply_error(cf, controlfd, &raddr, rlen, cookie, 0); return 0; } /* Stream communication mode doesn't use cookie */ if (cf->umode != 0) { cookie = argv[0]; for (i = 1; i < argc; i++) argv[i - 1] = argv[i]; argc--; argv[argc] = NULL; } else { cookie = NULL; } addr = port = NULL; switch (argv[0][0]) { case 'u': case 'U': /* U[opts] callid remote_ip remote_port from_tag [to_tag] */ op = UPDATE; rname = "update/create"; break; case 'l': case 'L': op = LOOKUP; rname = "lookup"; break; case 'd': case 'D': op = DELETE; rname = "delete"; break; case 'p': case 'P': /* * P callid pname codecs from_tag to_tag * * <codecs> could be either comma-separated list of supported * payload types or word "session" (without quotes), in which * case list saved on last session update will be used instead. */ op = PLAY; rname = "play"; playcount = 1; pname = argv[2]; codecs = argv[3]; break; case 'r': case 'R': op = RECORD; rname = "record"; break; case 'c': case 'C': op = COPY; rname = "copy"; break; case 's': case 'S': op = NOPLAY; rname = "noplay"; break; case 'v': case 'V': if (argv[0][1] == 'F' || argv[0][1] == 'f') { int i, known; /* * Wait for protocol version datestamp and check whether we * know it. */ if (argc != 2 && argc != 3) { rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error"); reply_error(cf, controlfd, &raddr, rlen, cookie, 2); return 0; } /* * Only list 20081224 protocol mod as supported if * user actually enabled notification with -n */ if (strcmp(argv[1], "20081224") == 0 && cf->timeout_handler.socket_name == NULL) { reply_number(cf, controlfd, &raddr, rlen, cookie, 0); return 0; } for (known = i = 0; proto_caps[i].pc_id != NULL; ++i) { if (!strcmp(argv[1], proto_caps[i].pc_id)) { known = 1; break; } } reply_number(cf, controlfd, &raddr, rlen, cookie, known); return 0; } if (argc != 1 && argc != 2) { rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error"); reply_error(cf, controlfd, &raddr, rlen, cookie, 2); return 0; } /* This returns base version. */ reply_number(cf, controlfd, &raddr, rlen, cookie, CPROTOVER); return 0; case 'i': case 'I': if (cookie == NULL) len = sprintf(buf, "sessions created: %llu\nactive sessions: %d\n" "active streams: %d\n", cf->sessions_created, cf->sessions_active, cf->nsessions / 2); else len = sprintf(buf, "%s sessions created: %llu\nactive sessions: %d\n" "active streams: %d\n", cookie, cf->sessions_created, cf->sessions_active, cf->nsessions / 2); for (i = 1; i < cf->nsessions; i++) { char addrs[4][256]; spa = cf->sessions[i]; if (spa == NULL || spa->sidx[0] != i) continue; /* RTCP twin session */ if (spa->rtcp == NULL) { spb = spa->rtp; buf[len++] = '\t'; } else { spb = spa->rtcp; buf[len++] = '\t'; buf[len++] = 'C'; buf[len++] = ' '; } addr2char_r(spb->laddr[1], addrs[0], sizeof(addrs[0])); if (spb->addr[1] == NULL) { strcpy(addrs[1], "NONE"); } else { sprintf(addrs[1], "%s:%d", addr2char(spb->addr[1]), addr2port(spb->addr[1])); } addr2char_r(spb->laddr[0], addrs[2], sizeof(addrs[2])); if (spb->addr[0] == NULL) { strcpy(addrs[3], "NONE"); } else { sprintf(addrs[3], "%s:%d", addr2char(spb->addr[0]), addr2port(spb->addr[0])); } len += sprintf(buf + len, "%s/%s: caller = %s:%d/%s, callee = %s:%d/%s, " "stats = %lu/%lu/%lu/%lu, ttl = %d/%d\n", spb->call_id, spb->tag, addrs[0], spb->ports[1], addrs[1], addrs[2], spb->ports[0], addrs[3], spa->pcount[0], spa->pcount[1], spa->pcount[2], spa->pcount[3], spb->ttl[0], spb->ttl[1]); if (len + 512 > sizeof(buf)) { doreply(cf, controlfd, buf, len, &raddr, rlen); len = 0; } } if (len > 0) doreply(cf, controlfd, buf, len, &raddr, rlen);; return 0; break; case 'q': case 'Q': op = QUERY; rname = "query"; break; case 'x': case 'X': /* Delete all active sessions */ rtpp_log_write(RTPP_LOG_INFO, cf->glog, "deleting all active sessions"); for (i = 1; i < cf->nsessions; i++) { spa = cf->sessions[i]; if (spa == NULL || spa->sidx[0] != i) continue; /* Skip RTCP twin session */ if (spa->rtcp != NULL) { remove_session(cf, spa); } } reply_ok(cf, controlfd, &raddr, rlen, cookie); return 0; break; default: rtpp_log_write(RTPP_LOG_ERR, cf->glog, "unknown command"); reply_error(cf, controlfd, &raddr, rlen, cookie, 3); return 0; } call_id = argv[1]; if (op == UPDATE || op == LOOKUP || op == PLAY) { max_argc = (op == UPDATE ? 8 : 6); if (argc < 5 || argc > max_argc) { rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error"); reply_error(cf, controlfd, &raddr, rlen, cookie, 4); return 0; } from_tag = argv[4]; to_tag = argv[5]; if (op == PLAY && argv[0][1] != '\0') playcount = atoi(argv[0] + 1); if (op == UPDATE && argc > 6) { socket_name_u = argv[6]; if (strncmp("unix:", socket_name_u, 5) == 0) socket_name_u += 5; if (argc == 8) { notify_tag = argv[7]; len = url_unquote((uint8_t *)notify_tag, strlen(notify_tag)); if (len == -1) { rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error - invalid URL encoding"); reply_error(cf, controlfd, &raddr, rlen, cookie, 4); return 0; } notify_tag[len] = '\0'; } } } if (op == COPY) { if (argc < 4 || argc > 5) { rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error"); reply_error(cf, controlfd, &raddr, rlen, cookie, 1); return 0; } recording_name = argv[2]; from_tag = argv[3]; to_tag = argv[4]; } if (op == DELETE || op == RECORD || op == NOPLAY || op == QUERY) { if (argc < 3 || argc > 4) { rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error"); reply_error(cf, controlfd, &raddr, rlen, cookie, 1); return 0; } from_tag = argv[2]; to_tag = argv[3]; } if (op == DELETE || op == RECORD || op == COPY || op == NOPLAY) { /* D, R and S commands don't take any modifiers */ if (argv[0][1] != '\0') { rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error"); reply_error(cf, controlfd, &raddr, rlen, cookie, 1); return 0; } } if (op == UPDATE || op == LOOKUP || op == DELETE) { addr = argv[2]; port = argv[3]; /* Process additional command modifiers */ external = 1; /* In bridge mode all clients are assumed to be asymmetric */ asymmetric = (cf->bmode != 0) ? 1 : 0; pf = AF_INET; weak = 0; for (cp = argv[0] + 1; *cp != '\0'; cp++) { switch (*cp) { case 'a': case 'A': asymmetric = 1; break; case 'e': case 'E': if (lidx < 0) { rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error"); reply_error(cf, controlfd, &raddr, rlen, cookie, 1); return 0; } lia[lidx] = cf->bindaddr[1]; lidx--; break; case 'i': case 'I': if (lidx < 0) { rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error"); reply_error(cf, controlfd, &raddr, rlen, cookie, 1); return 0; } lia[lidx] = cf->bindaddr[0]; lidx--; break; case '6': pf = AF_INET6; break; case 's': case 'S': asymmetric = 0; break; case 'w': case 'W': weak = 1; break; case 'z': case 'Z': requested_nsamples = (strtol(cp + 1, &cp, 10) / 10) * 80; if (requested_nsamples <= 0) { rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error"); reply_error(cf, controlfd, &raddr, rlen, cookie, 1); return 0; } cp--; break; case 'c': case 'C': cp += 1; for (t = cp; *cp != '\0'; cp++) { if (!isdigit(*cp) && *cp != ',') break; } if (t == cp) { rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error"); reply_error(cf, controlfd, &raddr, rlen, cookie, 1); return 0; } codecs = alloca(cp - t + 1); memcpy(codecs, t, cp - t); codecs[cp - t] = '\0'; cp--; break; case 'l': case 'L': len = extractaddr(cp + 1, &t, &cp, &tpf); if (len == -1) { rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error"); reply_error(cf, controlfd, &raddr, rlen, cookie, 1); return 0; } c = t[len]; t[len] = '\0'; local_addr = host2bindaddr(cf, t, tpf, &errmsg); if (local_addr == NULL) { rtpp_log_write(RTPP_LOG_ERR, cf->glog, "invalid local address: %s: %s", t, errmsg); reply_error(cf, controlfd, &raddr, rlen, cookie, 1); return 0; } t[len] = c; cp--; break; case 'r': case 'R': len = extractaddr(cp + 1, &t, &cp, &tpf); if (len == -1) { rtpp_log_write(RTPP_LOG_ERR, cf->glog, "command syntax error"); reply_error(cf, controlfd, &raddr, rlen, cookie, 1); return 0; } c = t[len]; t[len] = '\0'; local_addr = alloca(sizeof(struct sockaddr_storage)); n = resolve(local_addr, tpf, t, SERVICE, AI_PASSIVE); if (n != 0) { rtpp_log_write(RTPP_LOG_ERR, cf->glog, "invalid remote address: %s: %s", t, gai_strerror(n)); reply_error(cf, controlfd, &raddr, rlen, cookie, 1); return 0; } if (local4remote(cf, local_addr, satoss(local_addr)) == -1) { rtpp_log_write(RTPP_LOG_ERR, cf->glog, "can't find local address for remote address: %s", t); reply_error(cf, controlfd, &raddr, rlen, cookie, 1); return 0; } local_addr = addr2bindaddr(cf, local_addr, &errmsg); if (local_addr == NULL) { rtpp_log_write(RTPP_LOG_ERR, cf->glog, "invalid local address: %s", errmsg); reply_error(cf, controlfd, &raddr, rlen, cookie, 1); return 0; } t[len] = c; cp--; break; default: rtpp_log_write(RTPP_LOG_ERR, cf->glog, "unknown command modifier `%c'", *cp); break; } } if (op != DELETE && addr != NULL && port != NULL && strlen(addr) >= 7) { struct sockaddr_storage tia; if ((n = resolve(sstosa(&tia), pf, addr, port, AI_NUMERICHOST)) == 0) { if (!ishostnull(sstosa(&tia))) { for (i = 0; i < 2; i++) { ia[i] = malloc(SS_LEN(&tia)); if (ia[i] == NULL) { handle_nomem(cf, controlfd, &raddr, rlen, cookie, 5, ia, fds, spa, spb); return 0; } memcpy(ia[i], &tia, SS_LEN(&tia)); } /* Set port for RTCP, will work both for IPv4 and IPv6 */ n = ntohs(satosin(ia[1])->sin_port); satosin(ia[1])->sin_port = htons(n + 1); } } else { rtpp_log_write(RTPP_LOG_ERR, cf->glog, "getaddrinfo: %s", gai_strerror(n)); } } } /* * Record and delete need special handling since they apply to all * streams in the session. */ switch (op) { case DELETE: i = handle_delete(cf, call_id, from_tag, to_tag, weak); break; case RECORD: i = handle_record(cf, call_id, from_tag, to_tag); break; default: i = find_stream(cf, call_id, from_tag, to_tag, &spa); if (i != -1 && op != UPDATE) i = NOT(i); break; } if (i == -1 && op != UPDATE) { rtpp_log_write(RTPP_LOG_INFO, cf->glog, "%s request failed: session %s, tags %s/%s not found", rname, call_id, from_tag, to_tag != NULL ? to_tag : "NONE"); if (op == LOOKUP) { for (i = 0; i < 2; i++) if (ia[i] != NULL) free(ia[i]); reply_port(cf, controlfd, &raddr, rlen, cookie, 0, lia); return 0; } reply_error(cf, controlfd, &raddr, rlen, cookie, 8); return 0; } switch (op) { case DELETE: case RECORD: reply_ok(cf, controlfd, &raddr, rlen, cookie); return 0; case NOPLAY: handle_noplay(cf, spa, i); reply_ok(cf, controlfd, &raddr, rlen, cookie); return 0; case PLAY: handle_noplay(cf, spa, i); if (strcmp(codecs, "session") == 0) { if (spa->codecs[i] == NULL) { reply_error(cf, controlfd, &raddr, rlen, cookie, 6); return 0; } codecs = spa->codecs[i]; } if (playcount != 0 && handle_play(cf, spa, i, codecs, pname, playcount) != 0) { reply_error(cf, controlfd, &raddr, rlen, cookie, 6); return 0; } reply_ok(cf, controlfd, &raddr, rlen, cookie); return 0; case COPY: handle_copy(cf, spa, i, recording_name); reply_ok(cf, controlfd, &raddr, rlen, cookie); return 0; case QUERY: handle_query(cf, controlfd, &raddr, rlen, cookie, spa, i); return 0; case LOOKUP: case UPDATE: /* those are handled below */ break; default: /* Programmatic error, should not happen */ abort(); } pidx = 1; lport = 0; if (i != -1) { assert(op == UPDATE || op == LOOKUP); if (spa->fds[i] == -1) { if (local_addr != NULL) { spa->laddr[i] = local_addr; } if (create_listener(cf, spa->laddr[i], &lport, fds) == -1) { rtpp_log_write(RTPP_LOG_ERR, spa->log, "can't create listener"); reply_error(cf, controlfd, &raddr, rlen, cookie, 7); return 0; } assert(spa->fds[i] == -1); spa->fds[i] = fds[0]; assert(spa->rtcp->fds[i] == -1); spa->rtcp->fds[i] = fds[1]; spa->ports[i] = lport; spa->rtcp->ports[i] = lport + 1; spa->complete = spa->rtcp->complete = 1; append_session(cf, spa, i); append_session(cf, spa->rtcp, i); } if (weak) spa->weak[i] = 1; else if (op == UPDATE) spa->strong = 1; lport = spa->ports[i]; lia[0] = spa->laddr[i]; pidx = (i == 0) ? 1 : 0; spa->ttl_mode = cf->ttl_mode; spa->ttl[0] = cf->max_ttl; spa->ttl[1] = cf->max_ttl; if (op == UPDATE) { rtpp_log_write(RTPP_LOG_INFO, spa->log, "adding %s flag to existing session, new=%d/%d/%d", weak ? ( i ? "weak[1]" : "weak[0]" ) : "strong", spa->strong, spa->weak[0], spa->weak[1]); } rtpp_log_write(RTPP_LOG_INFO, spa->log, "lookup on ports %d/%d, session timer restarted", spa->ports[0], spa->ports[1]); } else { assert(op == UPDATE); rtpp_log_write(RTPP_LOG_INFO, cf->glog, "new session %s, tag %s requested, type %s", call_id, from_tag, weak ? "weak" : "strong"); if (local_addr != NULL) { lia[0] = lia[1] = local_addr; if (lia[0] == NULL) { rtpp_log_write(RTPP_LOG_ERR, spa->log, "can't create listener: %s", t); reply_error(cf, controlfd, &raddr, rlen, cookie, 10); return 0; } } if (create_listener(cf, lia[0], &lport, fds) == -1) { rtpp_log_write(RTPP_LOG_ERR, cf->glog, "can't create listener"); reply_error(cf, controlfd, &raddr, rlen, cookie, 10); return 0; } /* * Session creation. If creation is requested with weak flag, * set weak[0]. */ spa = malloc(sizeof(*spa)); if (spa == NULL) { handle_nomem(cf, controlfd, &raddr, rlen, cookie, 11, ia, fds, spa, spb); return 0; } /* spb is RTCP twin session for this one. */ spb = malloc(sizeof(*spb)); if (spb == NULL) { handle_nomem(cf, controlfd, &raddr, rlen, cookie, 12, ia, fds, spa, spb); return 0; } memset(spa, 0, sizeof(*spa)); memset(spb, 0, sizeof(*spb)); for (i = 0; i < 2; i++) { spa->fds[i] = spb->fds[i] = -1; spa->last_update[i] = 0; spb->last_update[i] = 0; } spa->call_id = strdup(call_id); if (spa->call_id == NULL) { handle_nomem(cf, controlfd, &raddr, rlen, cookie, 13, ia, fds, spa, spb); return 0; } spb->call_id = spa->call_id; spa->tag = strdup(from_tag); if (spa->tag == NULL) { handle_nomem(cf, controlfd, &raddr, rlen, cookie, 14, ia, fds, spa, spb); return 0; } spb->tag = spa->tag; for (i = 0; i < 2; i++) { spa->rrcs[i] = NULL; spb->rrcs[i] = NULL; spa->laddr[i] = lia[i]; spb->laddr[i] = lia[i]; } spa->strong = spa->weak[0] = spa->weak[1] = 0; if (weak) spa->weak[0] = 1; else spa->strong = 1; assert(spa->fds[0] == -1); spa->fds[0] = fds[0]; assert(spb->fds[0] == -1); spb->fds[0] = fds[1]; spa->ports[0] = lport; spb->ports[0] = lport + 1; spa->ttl[0] = cf->max_ttl; spa->ttl[1] = cf->max_ttl; spb->ttl[0] = -1; spb->ttl[1] = -1; spa->log = rtpp_log_open(cf, "rtpproxy", spa->call_id, 0); spb->log = spa->log; spa->rtcp = spb; spb->rtcp = NULL; spa->rtp = NULL; spb->rtp = spa; spa->sridx = spb->sridx = -1; append_session(cf, spa, 0); append_session(cf, spa, 1); append_session(cf, spb, 0); append_session(cf, spb, 1); hash_table_append(cf, spa); cf->sessions_created++; cf->sessions_active++; /* * Each session can consume up to 5 open file descriptors (2 RTP, * 2 RTCP and 1 logging) so that warn user when he is likely to * exceed 80% mark on hard limit. */ if (cf->sessions_active > (cf->nofile_limit.rlim_max * 80 / (100 * 5)) && cf->nofile_limit_warned == 0) { cf->nofile_limit_warned = 1; rtpp_log_write(RTPP_LOG_WARN, cf->glog, "passed 80%% " "threshold on the open file descriptors limit (%d), " "consider increasing the limit using -L command line " "option", (int)cf->nofile_limit.rlim_max); } rtpp_log_write(RTPP_LOG_INFO, spa->log, "new session on a port %d created, " "tag %s", lport, from_tag); if (cf->record_all != 0) { handle_copy(cf, spa, 0, NULL); handle_copy(cf, spa, 1, NULL); } } if (op == UPDATE) { if (cf->timeout_handler.socket_name == NULL && socket_name_u != NULL) rtpp_log_write(RTPP_LOG_ERR, spa->log, "must permit notification socket with -n"); if (spa->timeout_data.notify_tag != NULL) { free(spa->timeout_data.notify_tag); spa->timeout_data.notify_tag = NULL; } if (cf->timeout_handler.socket_name != NULL && socket_name_u != NULL) { if (strcmp(cf->timeout_handler.socket_name, socket_name_u) != 0) { rtpp_log_write(RTPP_LOG_ERR, spa->log, "invalid socket name %s", socket_name_u); socket_name_u = NULL; } else { rtpp_log_write(RTPP_LOG_INFO, spa->log, "setting timeout handler"); spa->timeout_data.handler = &cf->timeout_handler; spa->timeout_data.notify_tag = strdup(notify_tag); } } else if (socket_name_u == NULL && spa->timeout_data.handler != NULL) { spa->timeout_data.handler = NULL; rtpp_log_write(RTPP_LOG_INFO, spa->log, "disabling timeout handler"); } } if (ia[0] != NULL && ia[1] != NULL) { if (spa->addr[pidx] != NULL) spa->last_update[pidx] = dtime; if (spa->rtcp->addr[pidx] != NULL) spa->rtcp->last_update[pidx] = dtime; /* * Unless the address provided by client historically * cannot be trusted and address is different from one * that we recorded update it. */ if (spa->untrusted_addr[pidx] == 0 && !(spa->addr[pidx] != NULL && SA_LEN(ia[0]) == SA_LEN(spa->addr[pidx]) && memcmp(ia[0], spa->addr[pidx], SA_LEN(ia[0])) == 0)) { rtpp_log_write(RTPP_LOG_INFO, spa->log, "pre-filling %s's address " "with %s:%s", (pidx == 0) ? "callee" : "caller", addr, port); if (spa->addr[pidx] != NULL) { if (spa->canupdate[pidx] == 0) { if (spa->prev_addr[pidx] != NULL) free(spa->prev_addr[pidx]); spa->prev_addr[pidx] = spa->addr[pidx]; } else { free(spa->addr[pidx]); } } spa->addr[pidx] = ia[0]; ia[0] = NULL; } if (spa->rtcp->untrusted_addr[pidx] == 0 && !(spa->rtcp->addr[pidx] != NULL && SA_LEN(ia[1]) == SA_LEN(spa->rtcp->addr[pidx]) && memcmp(ia[1], spa->rtcp->addr[pidx], SA_LEN(ia[1])) == 0)) { if (spa->rtcp->addr[pidx] != NULL) { if (spa->rtcp->canupdate[pidx] == 0) { if (spa->rtcp->prev_addr[pidx] != NULL) free(spa->rtcp->prev_addr[pidx]); spa->rtcp->prev_addr[pidx] = spa->rtcp->addr[pidx]; } else { free(spa->rtcp->addr[pidx]); } } spa->rtcp->addr[pidx] = ia[1]; ia[1] = NULL; } } spa->asymmetric[pidx] = spa->rtcp->asymmetric[pidx] = asymmetric; spa->canupdate[pidx] = spa->rtcp->canupdate[pidx] = NOT(asymmetric); if (spa->codecs[pidx] != NULL) { free(spa->codecs[pidx]); spa->codecs[pidx] = NULL; } if (codecs != NULL) spa->codecs[pidx] = strdup(codecs); if (requested_nsamples > 0) { rtpp_log_write(RTPP_LOG_INFO, spa->log, "RTP packets from %s " "will be resized to %d milliseconds", (pidx == 0) ? "callee" : "caller", requested_nsamples / 8); } else if (spa->resizers[pidx].output_nsamples > 0) { rtpp_log_write(RTPP_LOG_INFO, spa->log, "Resizing of RTP " "packets from %s has been disabled", (pidx == 0) ? "callee" : "caller"); } spa->resizers[pidx].output_nsamples = requested_nsamples; for (i = 0; i < 2; i++) if (ia[i] != NULL) free(ia[i]); assert(lport != 0); reply_port(cf, controlfd, &raddr, rlen, cookie, lport, lia); return 0; }
static void rxmit_packets(struct cfg *cf, struct rtpp_session *sp, int ridx, double dtime) { int ndrain, i, port; struct rtp_packet *packet = NULL; /* Repeat since we may have several packets queued on the same socket */ for (ndrain = 0; ndrain < 5; ndrain++) { if (packet != NULL) rtp_packet_free(packet); packet = rtp_recv(sp->fds[ridx]); if (packet == NULL) break; packet->laddr = sp->laddr[ridx]; packet->rport = sp->ports[ridx]; packet->rtime = dtime; i = 0; if (sp->addr[ridx] != NULL) { /* Check that the packet is authentic, drop if it isn't */ if (sp->asymmetric[ridx] == 0) { if (memcmp(sp->addr[ridx], &packet->raddr, packet->rlen) != 0) { if (sp->canupdate[ridx] == 0) { /* * Continue, since there could be good packets in * queue. */ continue; } /* Signal that an address has to be updated */ i = 1; } else if (sp->canupdate[ridx] != 0 && sp->last_update[ridx] != 0 && dtime - sp->last_update[ridx] > UPDATE_WINDOW) { sp->canupdate[ridx] = 0; } } else { /* * For asymmetric clients don't check * source port since it may be different. */ if (!ishostseq(sp->addr[ridx], sstosa(&packet->raddr))) /* * Continue, since there could be good packets in * queue. */ continue; } sp->pcount[ridx]++; } else { sp->pcount[ridx]++; sp->addr[ridx] = malloc(packet->rlen); if (sp->addr[ridx] == NULL) { sp->pcount[3]++; rtpp_log_write(RTPP_LOG_ERR, sp->log, "can't allocate memory for remote address - " "removing session"); remove_session(cf, GET_RTP(sp)); /* Break, sp is invalid now */ break; } /* Signal that an address have to be updated. */ i = 1; } /* * Update recorded address if it's necessary. Set "untrusted address" * flag in the session state, so that possible future address updates * from that client won't get address changed immediately to some * bogus one. */ if (i != 0) { sp->untrusted_addr[ridx] = 1; memcpy(sp->addr[ridx], &packet->raddr, packet->rlen); if (sp->prev_addr[ridx] == NULL || memcmp(sp->prev_addr[ridx], &packet->raddr, packet->rlen) != 0) { sp->canupdate[ridx] = 0; } port = ntohs(satosin(&packet->raddr)->sin_port); rtpp_log_write(RTPP_LOG_INFO, sp->log, "%s's address filled in: %s:%d (%s)", (ridx == 0) ? "callee" : "caller", addr2char(sstosa(&packet->raddr)), port, (sp->rtp == NULL) ? "RTP" : "RTCP"); /* * Check if we have updated RTP while RTCP is still * empty or contains address that differs from one we * used when updating RTP. Try to guess RTCP if so, * should be handy for non-NAT'ed clients, and some * NATed as well. */ if (sp->rtcp != NULL && (sp->rtcp->addr[ridx] == NULL || !ishostseq(sp->rtcp->addr[ridx], sstosa(&packet->raddr)))) { if (sp->rtcp->addr[ridx] == NULL) { sp->rtcp->addr[ridx] = malloc(packet->rlen); if (sp->rtcp->addr[ridx] == NULL) { sp->pcount[3]++; rtpp_log_write(RTPP_LOG_ERR, sp->log, "can't allocate memory for remote address - " "removing session"); remove_session(cf, sp); /* Break, sp is invalid now */ break; } } memcpy(sp->rtcp->addr[ridx], &packet->raddr, packet->rlen); satosin(sp->rtcp->addr[ridx])->sin_port = htons(port + 1); /* Use guessed value as the only true one for asymmetric clients */ sp->rtcp->canupdate[ridx] = NOT(sp->rtcp->asymmetric[ridx]); rtpp_log_write(RTPP_LOG_INFO, sp->log, "guessing RTCP port " "for %s to be %d", (ridx == 0) ? "callee" : "caller", port + 1); } } if (sp->resizers[ridx].output_nsamples > 0) rtp_resizer_enqueue(&sp->resizers[ridx], &packet); if (packet != NULL) send_packet(cf, sp, ridx, packet); } if (packet != NULL) rtp_packet_free(packet); }
static int prepare_pkt_hdr_pcap(struct rtpp_session *sp, struct rtp_packet *packet, union pkt_hdr_pcap *hdrp, struct sockaddr *daddr, struct sockaddr *ldaddr, int ldport, int face) { struct sockaddr *src_addr, *dst_addr; uint16_t src_port, dst_port; pcaprec_hdr_t *pcaprec_hdr; struct udpip *udpip; int pcap_size; if (packet->rtime == -1) { rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "can't get current time"); return -1; } if (face == 0) { src_addr = sstosa(&(packet->raddr)); src_port = satosin(src_addr)->sin_port; dst_addr = packet->laddr; dst_port = htons(packet->rport); } else { src_addr = ldaddr; src_port = htons(ldport); dst_addr = daddr; dst_port = satosin(dst_addr)->sin_port; } if (sstosa(src_addr)->sa_family != AF_INET) { rtpp_log_ewrite(RTPP_LOG_ERR, sp->log, "only AF_INET pcap format is supported"); return -1; } memset(hdrp, 0, sizeof(*hdrp)); #if (PCAP_FORMAT == DLT_NULL) hdrp->null.family = sstosa(src_addr)->sa_family; pcaprec_hdr = &(hdrp->null.pcaprec_hdr); udpip = &(hdrp->null.udpip); pcap_size = sizeof(hdrp->null); #else /* Prepare fake ethernet header */ hdrp->en10t.ether_type = htons(0x800); memcpy(hdrp->en10t.ether_dhost + 2, &(satosin(dst_addr)->sin_addr), 4); memcpy(hdrp->en10t.ether_shost + 2, &(satosin(src_addr)->sin_addr), 4); pcaprec_hdr = &(hdrp->en10t.pcaprec_hdr); udpip = &(hdrp->en10t.udpip); pcap_size = sizeof(hdrp->en10t); #endif dtime2ts(packet->rtime, &(pcaprec_hdr->ts_sec), &(pcaprec_hdr->ts_usec)); pcaprec_hdr->orig_len = pcaprec_hdr->incl_len = pcap_size - sizeof(*pcaprec_hdr) + packet->size; /* Prepare fake IP header */ udpip->iphdr.ip_v = 4; udpip->iphdr.ip_hl = sizeof(udpip->iphdr) >> 2; udpip->iphdr.ip_len = htons(sizeof(udpip->iphdr) + sizeof(udpip->udphdr) + packet->size); udpip->iphdr.ip_src = satosin(src_addr)->sin_addr; udpip->iphdr.ip_dst = satosin(dst_addr)->sin_addr; udpip->iphdr.ip_p = IPPROTO_UDP; udpip->iphdr.ip_id = htons(ip_id++); udpip->iphdr.ip_ttl = 127; udpip->iphdr.ip_sum = rtpp_in_cksum(&(udpip->iphdr), sizeof(udpip->iphdr)); /* Prepare fake UDP header */ udpip->udphdr.uh_sport = src_port; udpip->udphdr.uh_dport = dst_port; udpip->udphdr.uh_ulen = htons(sizeof(udpip->udphdr) + packet->size); return 0; }
void dumppacket(FILE *fd, char *dir, struct sockaddr *sa, char *cp, int size, struct timeval *stamp) { struct rip *msg = (struct rip *)cp; struct sockaddr_in *who=(struct sockaddr_in *)sa; struct netinfo *n; if (fd == NULL) return; if (msg->rip_cmd && msg->rip_cmd < RIPCMD_MAX) fprintf(fd, "%s %s %s.%d %.19s:\n", ripcmds[msg->rip_cmd], dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port), ctime(&stamp->tv_sec)); else { fprintf(fd, "Bad cmd 0x%x %s %s.%d %.19s\n", msg->rip_cmd, dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port), ctime(&stamp->tv_sec)); fprintf(fd, "size=%d cp=%p packet=%p\n", size, cp, packet); fflush(fd); return; } if (tracepackets && tracecontents == 0) { fflush(fd); return; } switch (msg->rip_cmd) { case RIPCMD_REQUEST: case RIPCMD_RESPONSE: size -= 4 * sizeof (char); n = msg->rip_nets; for (; size > 0; n++, size -= sizeof (struct netinfo)) { if (size < (int)sizeof (struct netinfo)) { fprintf(fd, "(truncated record, len %d)\n", size); break; } if (sizeof(n->rip_dst.sa_family) > 1) n->rip_dst.sa_family = ntohs(n->rip_dst.sa_family); switch ((int)n->rip_dst.sa_family) { case AF_INET: fprintf(fd, "\tdst %s metric %ld\n", #define satosin(sa) ((struct sockaddr_in *)&sa) inet_ntoa(satosin(n->rip_dst)->sin_addr), (long int)ntohl(n->rip_metric)); break; default: fprintf(fd, "\taf %d? metric %ld\n", n->rip_dst.sa_family, (long int)ntohl(n->rip_metric)); break; } } break; case RIPCMD_TRACEON: fprintf(fd, "\tfile=%*s\n", size, msg->rip_tracefile); break; case RIPCMD_TRACEOFF: break; } fflush(fd); if (ferror(fd)) traceoff(); }
static void vmt_tclo_tick(void *xarg) { struct vmt_softc *sc = xarg; u_int32_t rlen; u_int16_t ack; /* reopen tclo channel if it's currently closed */ if (sc->sc_tclo_rpc.channel == 0 && sc->sc_tclo_rpc.cookie1 == 0 && sc->sc_tclo_rpc.cookie2 == 0) { if (vm_rpc_open(&sc->sc_tclo_rpc, VM_RPC_OPEN_TCLO) != 0) { device_printf(sc->sc_dev, "unable to reopen TCLO channel\n"); callout_schedule(&sc->sc_tclo_tick, hz * 15); return; } if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_RESET_REPLY) != 0) { device_printf(sc->sc_dev, "failed to send reset reply\n"); sc->sc_rpc_error = 1; goto out; } else { sc->sc_rpc_error = 0; } } if (sc->sc_tclo_ping) { if (vm_rpc_send(&sc->sc_tclo_rpc, NULL, 0) != 0) { device_printf(sc->sc_dev, "failed to send TCLO outgoing ping\n"); sc->sc_rpc_error = 1; goto out; } } if (vm_rpc_get_length(&sc->sc_tclo_rpc, &rlen, &ack) != 0) { device_printf(sc->sc_dev, "failed to get length of incoming TCLO data\n"); sc->sc_rpc_error = 1; goto out; } if (rlen == 0) { sc->sc_tclo_ping = 1; goto out; } if (rlen >= VMT_RPC_BUFLEN) { rlen = VMT_RPC_BUFLEN - 1; } if (vm_rpc_get_data(&sc->sc_tclo_rpc, sc->sc_rpc_buf, rlen, ack) != 0) { device_printf(sc->sc_dev, "failed to get incoming TCLO data\n"); sc->sc_rpc_error = 1; goto out; } sc->sc_tclo_ping = 0; #ifdef VMT_DEBUG printf("vmware: received message '%s'\n", sc->sc_rpc_buf); #endif if (strcmp(sc->sc_rpc_buf, "reset") == 0) { if (sc->sc_rpc_error != 0) { device_printf(sc->sc_dev, "resetting rpc\n"); vm_rpc_close(&sc->sc_tclo_rpc); /* reopen and send the reset reply next time around */ goto out; } if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_RESET_REPLY) != 0) { device_printf(sc->sc_dev, "failed to send reset reply\n"); sc->sc_rpc_error = 1; } } else if (strcmp(sc->sc_rpc_buf, "ping") == 0) { vmt_update_guest_info(sc); if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK) != 0) { device_printf(sc->sc_dev, "error sending ping response\n"); sc->sc_rpc_error = 1; } } else if (strcmp(sc->sc_rpc_buf, "OS_Halt") == 0) { vmt_do_shutdown(sc); } else if (strcmp(sc->sc_rpc_buf, "OS_Reboot") == 0) { vmt_do_reboot(sc); } else if (strcmp(sc->sc_rpc_buf, "OS_PowerOn") == 0) { vmt_tclo_state_change_success(sc, 1, VM_STATE_CHANGE_POWERON); if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK) != 0) { device_printf(sc->sc_dev, "error sending poweron response\n"); sc->sc_rpc_error = 1; } } else if (strcmp(sc->sc_rpc_buf, "OS_Suspend") == 0) { log(LOG_KERN | LOG_NOTICE, "VMware guest entering suspended state\n"); vmt_tclo_state_change_success(sc, 1, VM_STATE_CHANGE_SUSPEND); if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK) != 0) { device_printf(sc->sc_dev, "error sending suspend response\n"); sc->sc_rpc_error = 1; } } else if (strcmp(sc->sc_rpc_buf, "OS_Resume") == 0) { vmt_do_resume(sc); } else if (strcmp(sc->sc_rpc_buf, "Capabilities_Register") == 0) { /* don't know if this is important at all */ if (vm_rpc_send_rpci_tx(sc, "vmx.capability.unified_loop toolbox") != 0) { device_printf(sc->sc_dev, "unable to set unified loop\n"); sc->sc_rpc_error = 1; } if (vm_rpci_response_successful(sc) == 0) { device_printf(sc->sc_dev, "host rejected unified loop setting\n"); } /* the trailing space is apparently important here */ if (vm_rpc_send_rpci_tx(sc, "tools.capability.statechange ") != 0) { device_printf(sc->sc_dev, "unable to send statechange capability\n"); sc->sc_rpc_error = 1; } if (vm_rpci_response_successful(sc) == 0) { device_printf(sc->sc_dev, "host rejected statechange capability\n"); } if (vm_rpc_send_rpci_tx(sc, "tools.set.version %u", VM_VERSION_UNMANAGED) != 0) { device_printf(sc->sc_dev, "unable to set tools version\n"); sc->sc_rpc_error = 1; } vmt_update_guest_uptime(sc); if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK) != 0) { device_printf(sc->sc_dev, "error sending capabilities_register response\n"); sc->sc_rpc_error = 1; } } else if (strcmp(sc->sc_rpc_buf, "Set_Option broadcastIP 1") == 0) { struct ifnet *iface; struct sockaddr_in *guest_ip; /* find first available ipv4 address */ guest_ip = NULL; IFNET_FOREACH(iface) { struct ifaddr *iface_addr; /* skip loopback */ if (strncmp(iface->if_xname, "lo", 2) == 0 && iface->if_xname[2] >= '0' && iface->if_xname[2] <= '9') { continue; } IFADDR_FOREACH(iface_addr, iface) { if (iface_addr->ifa_addr->sa_family != AF_INET) { continue; } guest_ip = satosin(iface_addr->ifa_addr); break; } } if (guest_ip != NULL) { if (vm_rpc_send_rpci_tx(sc, "info-set guestinfo.ip %s", inet_ntoa(guest_ip->sin_addr)) != 0) { device_printf(sc->sc_dev, "unable to send guest IP address\n"); sc->sc_rpc_error = 1; } if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK) != 0) { device_printf(sc->sc_dev, "error sending broadcastIP response\n"); sc->sc_rpc_error = 1; } } else { if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_ERROR_IP_ADDR) != 0) { device_printf(sc->sc_dev, "error sending broadcastIP error response\n"); sc->sc_rpc_error = 1; } } } else { if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_ERROR) != 0) {
int prepare_rule(u_int32_t id, int rs_num, struct sockaddr *src, struct sockaddr *dst, u_int16_t d_port, u_int8_t proto) { char an[PF_ANCHOR_NAME_SIZE]; if ((src->sa_family != AF_INET && src->sa_family != AF_INET6) || (src->sa_family != dst->sa_family)) { errno = EPROTONOSUPPORT; return (-1); } memset(&pfp, 0, sizeof pfp); memset(&pfr, 0, sizeof pfr); snprintf(an, PF_ANCHOR_NAME_SIZE, "%s/%d.%d", FTP_PROXY_ANCHOR, getpid(), id); strlcpy(pfp.anchor, an, PF_ANCHOR_NAME_SIZE); strlcpy(pfr.anchor, an, PF_ANCHOR_NAME_SIZE); switch (rs_num) { case PF_RULESET_FILTER: pfr.ticket = pfte[TRANS_FILTER].ticket; break; case PF_RULESET_NAT: pfr.ticket = pfte[TRANS_NAT].ticket; break; case PF_RULESET_RDR: pfr.ticket = pfte[TRANS_RDR].ticket; break; default: errno = EINVAL; return (-1); } if (ioctl(dev, DIOCBEGINADDRS, &pfp) == -1) return (-1); pfr.pool_ticket = pfp.ticket; /* Generic for all rule types. */ pfr.rule.af = src->sa_family; pfr.rule.proto = proto; pfr.rule.src.addr.type = PF_ADDR_ADDRMASK; pfr.rule.dst.addr.type = PF_ADDR_ADDRMASK; if (src->sa_family == AF_INET) { memcpy(&pfr.rule.src.addr.v.a.addr.v4, &satosin(src)->sin_addr.s_addr, 4); memset(&pfr.rule.src.addr.v.a.mask.addr8, 255, 4); memcpy(&pfr.rule.dst.addr.v.a.addr.v4, &satosin(dst)->sin_addr.s_addr, 4); memset(&pfr.rule.dst.addr.v.a.mask.addr8, 255, 4); } else { memcpy(&pfr.rule.src.addr.v.a.addr.v6, &satosin6(src)->sin6_addr.s6_addr, 16); memset(&pfr.rule.src.addr.v.a.mask.addr8, 255, 16); memcpy(&pfr.rule.dst.addr.v.a.addr.v6, &satosin6(dst)->sin6_addr.s6_addr, 16); memset(&pfr.rule.dst.addr.v.a.mask.addr8, 255, 16); } pfr.rule.dst.port_op = PF_OP_EQ; pfr.rule.dst.port[0] = htons(d_port); switch (rs_num) { case PF_RULESET_FILTER: /* * pass quick [log] inet[6] proto tcp \ * from $src to $dst port = $d_port flags S/SAFR keep state * (max 1) [queue qname] */ pfr.rule.action = PF_PASS; pfr.rule.quick = 1; pfr.rule.log = rule_log; pfr.rule.keep_state = 1; #ifdef __FreeBSD__ pfr.rule.flags = (proto == IPPROTO_TCP ? TH_SYN : 0); pfr.rule.flagset = (proto == IPPROTO_TCP ? (TH_SYN|TH_ACK|TH_FIN|TH_RST) : 0); #else pfr.rule.flags = (proto == IPPROTO_TCP ? TH_SYN : NULL); pfr.rule.flagset = (proto == IPPROTO_TCP ? (TH_SYN|TH_ACK|TH_FIN|TH_RST) : NULL); #endif pfr.rule.max_states = 1; if (qname != NULL) strlcpy(pfr.rule.qname, qname, sizeof pfr.rule.qname); break; case PF_RULESET_NAT: /* * nat inet[6] proto tcp from $src to $dst port $d_port -> $nat */ pfr.rule.action = PF_NAT; break; case PF_RULESET_RDR: /* * rdr inet[6] proto tcp from $src to $dst port $d_port -> $rdr */ pfr.rule.action = PF_RDR; break; default: errno = EINVAL; return (-1); } return (0); }