Exemplo n.º 1
0
void
sockstats(PNATState pData)
{
    char buff[256];
    size_t n;
    struct socket *so, *so_next;

    lprint("\n");

    lprint(
           "Proto[state]     Sock     Local Address, Port  Remote Address, Port RecvQ SendQ\n");

    QSOCKET_FOREACH(so, so_next, tcp)
    /* { */
        n = RTStrPrintf(buff, sizeof(buff), "tcp[%s]", so->so_tcpcb?tcpstates[so->so_tcpcb->t_state]:"NONE");
        while (n < 17)
            buff[n++] = ' ';
        buff[17] = 0;
        lprint("%s %3d   %15s %5d ",
               buff, so->s, inet_ntoa(so->so_laddr), RT_N2H_U16(so->so_lport));
        lprint("%15s %5d %5d %5d\n",
                inet_ntoa(so->so_faddr), RT_N2H_U16(so->so_fport),
                SBUF_LEN(&so->so_rcv), SBUF_LEN(&so->so_snd));
    LOOP_LABEL(tcp, so, so_next);
    }
Exemplo n.º 2
0
/**
 * Convert the given exported device structure from host to network byte order.
 *
 * @returns nothing.
 * @param   pDevice           The device structure to convert.
 */
DECLINLINE(void) usbProxyBackendUsbIpExportedDeviceN2H(PUsbIpExportedDevice pDevice)
{
    pDevice->u32BusNum    = RT_N2H_U32(pDevice->u32BusNum);
    pDevice->u32DevNum    = RT_N2H_U32(pDevice->u32DevNum);
    pDevice->u32Speed     = RT_N2H_U16(pDevice->u32Speed);
    pDevice->u16VendorId  = RT_N2H_U16(pDevice->u16VendorId);
    pDevice->u16ProductId = RT_N2H_U16(pDevice->u16ProductId);
    pDevice->u16BcdDevice = RT_N2H_U16(pDevice->u16BcdDevice);
}
Exemplo n.º 3
0
Arquivo: tftp.c Projeto: ryenus/vbox
static void tftpProcessACK(PNATState pData, PTFTPIPHDR pTftpIpHeader)
{
    int rc;
    PTFTPSESSION pTftpSession = NULL;

    rc = tftpSessionFind(pData, pTftpIpHeader, &pTftpSession);
    if (RT_FAILURE(rc))
        return;

    AssertReturnVoid(tftpSendData(pData,
                                    pTftpSession,
                                    RT_N2H_U16(pTftpIpHeader->Core.u16TftpOpCode), pTftpIpHeader) == 0);
}
Exemplo n.º 4
0
static void tftp_handle_ack(PNATState pData, struct tftp_t *tp, int pktlen)
{
    int s;

    s = tftp_session_find(pData, tp);
    if (s < 0)
        return;

    if (tftp_send_data(pData, &tftp_sessions[s],
                       RT_N2H_U16(tp->x.tp_data.tp_block_nr) + 1, tp) < 0)
    {
        /* XXX */
    }
}
Exemplo n.º 5
0
Arquivo: tftp.c Projeto: jeppeter/vbox
static void tftpProcessACK(PNATState pData, PTFTPIPHDR pTftpIpHeader)
{
    int rc;
    PTFTPSESSION pTftpSession = NULL;

    rc = tftpSessionFind(pData, pTftpIpHeader, &pTftpSession);
    if (RT_FAILURE(rc))
        return;

    if (tftpSendData(pData, pTftpSession,
                     RT_N2H_U16(pTftpIpHeader->Core.u16TftpOpCode),
                     pTftpIpHeader))
        LogRel(("NAT TFTP: failure\n"));
}
Exemplo n.º 6
0
void tftp_input(PNATState pData, struct mbuf *m)
{
    struct tftp_t *tp = (struct tftp_t *)m->m_data;

    switch(RT_N2H_U16(tp->tp_op))
    {
        case TFTP_RRQ:
            tftp_handle_rrq(pData, tp, m->m_len);
            break;

        case TFTP_ACK:
            tftp_handle_ack(pData, tp, m->m_len);
            break;
    }
}
Exemplo n.º 7
0
Arquivo: tftp.c Projeto: ryenus/vbox
int slirpTftpInput(PNATState pData, struct mbuf *pMbuf)
{
    PTFTPIPHDR pTftpIpHeader = NULL;
    AssertPtr(pData);
    AssertPtr(pMbuf);
    pTftpIpHeader = mtod(pMbuf, PTFTPIPHDR);

    switch(RT_N2H_U16(pTftpIpHeader->u16TftpOpType))
    {
        case TFTP_RRQ:
            tftpProcessRRQ(pData, pTftpIpHeader, m_length(pMbuf, NULL));
            break;

        case TFTP_ACK:
            tftpProcessACK(pData, pTftpIpHeader);
            break;
        default:;
    }
    LogFlowFuncLeaveRC(VINF_SUCCESS);
    return VINF_SUCCESS;
}
Exemplo n.º 8
0
/*
 * Ip input routine.  Checksum and byte swap header.  If fragmented
 * try to reassemble.  Process options.  Pass to next level.
 */
void
ip_input(PNATState pData, struct mbuf *m)
{
    register struct ip *ip;
    int hlen = 0;
    int mlen = 0;

    STAM_PROFILE_START(&pData->StatIP_input, a);

    LogFlowFunc(("ENTER: m = %lx\n", (long)m));
    ip = mtod(m, struct ip *);
    Log2(("ip_dst=%RTnaipv4(len:%d) m_len = %d\n", ip->ip_dst, RT_N2H_U16(ip->ip_len), m->m_len));

    ipstat.ips_total++;
    {
        int rc;
        if (!(m->m_flags & M_SKIP_FIREWALL))
        {
            STAM_PROFILE_START(&pData->StatALIAS_input, b);
            rc = LibAliasIn(select_alias(pData, m), mtod(m, char *), m_length(m, NULL));
            STAM_PROFILE_STOP(&pData->StatALIAS_input, b);
            Log2(("NAT: LibAlias return %d\n", rc));
        }
        else
Exemplo n.º 9
0
/* m->m_data  points at ip packet header
 * m->m_len   length ip packet
 * ip->ip_len length data (IPDU)
 */
void
udp_input(PNATState pData, register struct mbuf *m, int iphlen)
{
    register struct ip *ip;
    register struct udphdr *uh;
    int len;
    struct ip save_ip;
    struct socket *so;
    int ret;
    int ttl, tos;

    LogFlowFunc(("ENTER: m = %p, iphlen = %d\n", m, iphlen));
    ip = mtod(m, struct ip *);
    Log2(("%RTnaipv4 iphlen = %d\n", ip->ip_dst, iphlen));

    udpstat.udps_ipackets++;

    /*
     * Strip IP options, if any; should skip this,
     * make available to user, and use on returned packets,
     * but we don't yet have a way to check the checksum
     * with options still present.
     */
    if (iphlen > sizeof(struct ip))
    {
        ip_stripoptions(m, (struct mbuf *)0);
        iphlen = sizeof(struct ip);
    }

    /*
     * Get IP and UDP header together in first mbuf.
     */
    ip = mtod(m, struct ip *);
    uh = (struct udphdr *)((caddr_t)ip + iphlen);

    /*
     * Make mbuf data length reflect UDP length.
     * If not enough data to reflect UDP length, drop.
     */
    len = RT_N2H_U16((u_int16_t)uh->uh_ulen);
    Assert(ip->ip_len + iphlen == (ssize_t)m_length(m, NULL));

    if (ip->ip_len != len)
    {
        if (len > ip->ip_len)
        {
            udpstat.udps_badlen++;
            Log3(("NAT: IP(id: %hd) has bad size\n", ip->ip_id));
            goto bad_free_mbuf;
        }
        m_adj(m, len - ip->ip_len);
        ip->ip_len = len;
    }

    /*
     * Save a copy of the IP header in case we want restore it
     * for sending an ICMP error message in response.
     */
    save_ip = *ip;
    save_ip.ip_len+= iphlen;         /* tcp_input subtracts this */

    /*
     * Checksum extended UDP header and data.
     */
    if (udpcksum && uh->uh_sum)
    {
        memset(((struct ipovly *)ip)->ih_x1, 0, 9);
        ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
#if 0
        /* keep uh_sum for ICMP reply */
        uh->uh_sum = cksum(m, len + sizeof (struct ip));
        if (uh->uh_sum)
        {

#endif
            if (cksum(m, len + iphlen))
            {
                udpstat.udps_badsum++;
                Log3(("NAT: IP(id: %hd) has bad (udp) cksum\n", ip->ip_id));
                goto bad_free_mbuf;
            }
        }
#if 0
    }
#endif

    /*
     *  handle DHCP/BOOTP
     */
    if (uh->uh_dport == RT_H2N_U16_C(BOOTP_SERVER))
    {
        bootp_input(pData, m);
        goto done_free_mbuf;
    }

    LogFunc(("uh src: %RTnaipv4:%d, dst: %RTnaipv4:%d\n",
             ip->ip_src.s_addr, RT_N2H_U16(uh->uh_sport),
             ip->ip_dst.s_addr, RT_N2H_U16(uh->uh_dport)));

    /*
     * handle DNS host resolver without creating a socket
     */
    if (   pData->fUseHostResolver
        && uh->uh_dport == RT_H2N_U16_C(53)
        && CTL_CHECK(ip->ip_dst.s_addr, CTL_DNS))
    {
        struct sockaddr_in dst, src;

        src.sin_addr.s_addr = ip->ip_dst.s_addr;
        src.sin_port = uh->uh_dport;
        dst.sin_addr.s_addr = ip->ip_src.s_addr;
        dst.sin_port = uh->uh_sport;

        m_adj(m, sizeof(struct udpiphdr));

        m = hostresolver(pData, m, ip->ip_src.s_addr, uh->uh_sport);
        if (m == NULL)
            goto done_free_mbuf;

        slirpMbufTagService(pData, m, CTL_DNS);

        udp_output2(pData, NULL, m, &src, &dst, IPTOS_LOWDELAY);
        LogFlowFuncLeave();
        return;
    }

    /*
     *  handle TFTP
     */
    if (   uh->uh_dport == RT_H2N_U16_C(TFTP_SERVER)
        && CTL_CHECK(ip->ip_dst.s_addr, CTL_TFTP))
    {
        if (pData->pvTftpSessions)
            slirpTftpInput(pData, m);
        goto done_free_mbuf;
    }

    /*
     * XXX: DNS proxy currently relies on the fact that each socket
     * only serves one request.
     */
    if (   pData->fUseDnsProxy
        && CTL_CHECK(ip->ip_dst.s_addr, CTL_DNS)
        && (uh->uh_dport == RT_H2N_U16_C(53)))
    {
        so = NULL;
        goto new_socket;
    }

    /*
     * Locate pcb for datagram.
     */
    so = udp_last_so;
    if (   so->so_lport != uh->uh_sport
        || so->so_laddr.s_addr != ip->ip_src.s_addr)
    {
        struct socket *tmp;

        for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next)
        {
            if (   tmp->so_lport        == uh->uh_sport
                && tmp->so_laddr.s_addr == ip->ip_src.s_addr)
            {
                so = tmp;
                break;
            }
        }
        if (tmp == &udb)
            so = NULL;
        else
        {
            udpstat.udpps_pcbcachemiss++;
            udp_last_so = so;
        }
    }

  new_socket:
    if (so == NULL)
    {
        /*
         * If there's no socket for this packet,
         * create one
         */
        if ((so = socreate()) == NULL)
        {
            Log2(("NAT: IP(id: %hd) failed to create socket\n", ip->ip_id));
            goto bad_free_mbuf;
        }

        /*
         * Setup fields
         */
        so->so_laddr = ip->ip_src;
        so->so_lport = uh->uh_sport;
        so->so_iptos = ip->ip_tos;

        if (udp_attach(pData, so) <= 0)
        {
            Log2(("NAT: IP(id: %hd) udp_attach errno = %d (%s)\n",
                        ip->ip_id, errno, strerror(errno)));
            sofree(pData, so);
            goto bad_free_mbuf;
        }

        /* udp_last_so = so; */
        /*
         * XXXXX Here, check if it's in udpexec_list,
         * and if it is, do the fork_exec() etc.
         */
    }

    so->so_faddr = ip->ip_dst;   /* XXX */
    so->so_fport = uh->uh_dport; /* XXX */
    Assert(so->so_type == IPPROTO_UDP);

    /*
     * DNS proxy
     */
    if (   pData->fUseDnsProxy
        && CTL_CHECK(ip->ip_dst.s_addr, CTL_DNS)
        && (uh->uh_dport == RT_H2N_U16_C(53)))
    {
        dnsproxy_query(pData, so, m, iphlen);
        goto done_free_mbuf;
    }

    iphlen += sizeof(struct udphdr);
    m->m_len -= iphlen;
    m->m_data += iphlen;

    ttl = ip->ip_ttl = save_ip.ip_ttl;
    if (ttl != so->so_sottl) {
        ret = setsockopt(so->s, IPPROTO_IP, IP_TTL,
                         (char *)&ttl, sizeof(ttl));
        if (RT_LIKELY(ret == 0))
            so->so_sottl = ttl;
    }

    tos = save_ip.ip_tos;
    if (tos != so->so_sotos) {
        ret = setsockopt(so->s, IPPROTO_IP, IP_TOS,
                         (char *)&tos, sizeof(tos));
        if (RT_LIKELY(ret == 0))
            so->so_sotos = tos;
    }

    {
        /*
         * Different OSes have different socket options for DF.  We
         * can't use IP_HDRINCL here as it's only valid for SOCK_RAW.
         */
#     define USE_DF_OPTION(_Optname) \
        const int dfopt = _Optname
#if   defined(IP_MTU_DISCOVER)
        USE_DF_OPTION(IP_MTU_DISCOVER);
#elif defined(IP_DONTFRAG)      /* Solaris 11+, FreeBSD */
        USE_DF_OPTION(IP_DONTFRAG);
#elif defined(IP_DONTFRAGMENT)  /* Windows */
        USE_DF_OPTION(IP_DONTFRAGMENT);
#else
        USE_DF_OPTION(0);
#endif
        if (dfopt) {
            int df = (save_ip.ip_off & IP_DF) != 0;
#if defined(IP_MTU_DISCOVER)
            df = df ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
#endif
            if (df != so->so_sodf) {
                ret = setsockopt(so->s, IPPROTO_IP, dfopt,
                                 (char *)&df, sizeof(df));
                if (RT_LIKELY(ret == 0))
                    so->so_sodf = df;
            }
        }
    }

    if (   sosendto(pData, so, m) == -1
        && (   !soIgnorableErrorCode(errno)
            && errno != ENOTCONN))
    {
        m->m_len += iphlen;
        m->m_data -= iphlen;
        *ip = save_ip;
        Log2(("NAT: UDP tx errno = %d (%s) on sent to %RTnaipv4\n",
              errno, strerror(errno), ip->ip_dst));
        icmp_error(pData, m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));
        so->so_m = NULL;
        LogFlowFuncLeave();
        return;
    }

    if (so->so_m)
        m_freem(pData, so->so_m);   /* used for ICMP if error on sorecvfrom */

    /* restore the orig mbuf packet */
    m->m_len += iphlen;
    m->m_data -= iphlen;
    *ip = save_ip;
    so->so_m = m;         /* ICMP backup */
    LogFlowFuncLeave();
    return;

bad_free_mbuf:
    Log2(("NAT: UDP(id: %hd) datagram to %RTnaipv4 with size(%d) claimed as bad\n",
        ip->ip_id, &ip->ip_dst, ip->ip_len));

done_free_mbuf:
    /* some services like bootp(built-in), dns(buildt-in) and dhcp don't need sockets
     * and create new m'buffers to send them to guest, so we'll free their incomming
     * buffers here.
     */
    if (m != NULL)
        m_freem(pData, m);
    LogFlowFuncLeave();
    return;
}
Exemplo n.º 10
0
struct socket *
udp_listen(PNATState pData, u_int32_t bind_addr, u_int port, u_int32_t laddr, u_int lport, int flags)
{
    struct sockaddr_in addr;
    struct socket *so;
    socklen_t addrlen = sizeof(struct sockaddr_in);
    int opt = 1;
    LogFlowFunc(("ENTER: bind_addr:%RTnaipv4, port:%d, laddr:%RTnaipv4, lport:%d, flags:%x\n",
                 bind_addr, RT_N2H_U16(port), laddr, RT_N2H_U16(lport), flags));

    if ((so = socreate()) == NULL)
    {
        LogFlowFunc(("LEAVE: NULL\n"));
        return NULL;
    }

    so->s = socket(AF_INET, SOCK_DGRAM, 0);
    if (so->s == -1)
    {
        LogRel(("NAT: can't create datagram socket\n"));
        RTMemFree(so);
        LogFlowFunc(("LEAVE: NULL\n"));
        return NULL;
    }
    so->so_expire = curtime + SO_EXPIRE;
    so->so_type = IPPROTO_UDP;
    fd_nonblock(so->s);
    so->so_sottl = 0;
    so->so_sotos = 0;
    so->so_sodf = -1;
    SOCKET_LOCK_CREATE(so);
    QSOCKET_LOCK(udb);
    insque(pData, so, &udb);
    NSOCK_INC();
    QSOCKET_UNLOCK(udb);

    memset(&addr, 0, sizeof(addr));
#ifdef RT_OS_DARWIN
    addr.sin_len = sizeof(addr);
#endif
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = bind_addr;
    addr.sin_port = port;

    if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0)
    {
        LogRel(("NAT: udp bind to %RTnaipv4:%d failed, error %d\n",
                addr.sin_addr, RT_N2H_U16(port), errno));
        udp_detach(pData, so);
        LogFlowFunc(("LEAVE: NULL\n"));
        return NULL;
    }
    setsockopt(so->s, SOL_SOCKET, SO_REUSEADDR,(char *)&opt, sizeof(int));
/*  setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE,(char *)&opt, sizeof(int)); */

    getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
    so->so_hladdr = addr.sin_addr;
    so->so_hlport = addr.sin_port;

    /* XXX: wtf are we setting so_faddr/so_fport here? */
    so->so_fport = addr.sin_port;
#if 0
    /* The original check was completely broken, as the commented out
     * if statement was always true (INADDR_ANY=0). */
    /** @todo vvl - alias_addr should be set (if required)
     * later by liabalias module.
     */
    if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
        so->so_faddr = alias_addr;
    else
#endif
        so->so_faddr = addr.sin_addr;

    so->so_lport = lport;
    so->so_laddr.s_addr = laddr;
    if (flags != SS_FACCEPTONCE)
        so->so_expire = 0;

    so->so_state = SS_ISFCONNECTED;

    LogFlowFunc(("LEAVE: %R[natsock]\n", so));
    return so;
}
Exemplo n.º 11
0
Arquivo: tftp.c Projeto: ryenus/vbox
DECLINLINE(int) tftpSessionOptionParse(PTFTPSESSION pTftpSession, PCTFTPIPHDR pcTftpIpHeader)
{
    int rc = VINF_SUCCESS;
    char *pszTftpRRQRaw;
    size_t idxTftpRRQRaw = 0;
    int cbTftpRRQRaw = 0;
    int fWithArg = 0;
    int idxOptionArg = 0;
    AssertPtrReturn(pTftpSession, VERR_INVALID_PARAMETER);
    AssertPtrReturn(pcTftpIpHeader, VERR_INVALID_PARAMETER);
    AssertReturn(RT_N2H_U16(pcTftpIpHeader->u16TftpOpType) == TFTP_RRQ, VERR_INVALID_PARAMETER);
    LogFlowFunc(("pTftpSession:%p, pcTftpIpHeader:%p\n", pTftpSession, pcTftpIpHeader));
    pszTftpRRQRaw = (char *)&pcTftpIpHeader->Core;
    cbTftpRRQRaw = RT_H2N_U16(pcTftpIpHeader->UdpHdr.uh_ulen) + sizeof(struct ip) - RT_OFFSETOF(TFTPIPHDR, Core);
    while(cbTftpRRQRaw)
    {
        idxTftpRRQRaw = RTStrNLen(pszTftpRRQRaw, 512 - idxTftpRRQRaw) + 1;
        if (RTStrNLen((char *)pTftpSession->pszFilename, TFTP_FILENAME_MAX) == 0)
        {
            rc = RTStrCopy((char *)pTftpSession->pszFilename, TFTP_FILENAME_MAX, pszTftpRRQRaw);
            if (RT_FAILURE(rc))
            {
                LogFlowFuncLeaveRC(rc);
                AssertRCReturn(rc,rc);
            }
        }
        else if (pTftpSession->enmTftpFmt == TFTPFMT_NONE)
        {
            int idxFmt = 0;
            rc = tftpFindTransferFormatIdxbyName(&idxFmt, pszTftpRRQRaw);
            if (RT_FAILURE(rc))
            {
                LogFlowFuncLeaveRC(VERR_INTERNAL_ERROR);
                return VERR_INTERNAL_ERROR;
            }
            AssertReturn(   g_TftpTransferFmtDesc[idxFmt].enmType != TFTPFMT_NONE
                         && g_TftpTransferFmtDesc[idxFmt].enmType != TFTPFMT_NOT_FMT, VERR_INTERNAL_ERROR);
            pTftpSession->enmTftpFmt = g_TftpTransferFmtDesc[idxFmt].enmType;
        }
        else if (fWithArg)
        {
            if (!RTStrICmp("blksize", g_TftpDesc[idxOptionArg].pszName))
            {
                rc = tftpSessionParseAndMarkOption(pszTftpRRQRaw, &pTftpSession->OptionBlkSize);
                if (pTftpSession->OptionBlkSize.u64Value > UINT16_MAX)
                    rc = VERR_INVALID_PARAMETER;
            }

            if (   RT_SUCCESS(rc)
                && !RTStrICmp("tsize", g_TftpDesc[idxOptionArg].pszName))
                rc = tftpSessionParseAndMarkOption(pszTftpRRQRaw, &pTftpSession->OptionTSize);

            /* @todo: we don't use timeout, but its value in the range 0-255 */
            if (   RT_SUCCESS(rc)
                && !RTStrICmp("timeout", g_TftpDesc[idxOptionArg].pszName))
                rc = tftpSessionParseAndMarkOption(pszTftpRRQRaw, &pTftpSession->OptionTimeout);

            /* @todo: unknown option detection */
            if (RT_FAILURE(rc))
            {
                LogFlowFuncLeaveRC(rc);
                AssertRCReturn(rc,rc);
            }
            fWithArg = 0;
            idxOptionArg = 0;
        }
        else
        {
            rc = tftpFindOptionIdxbyName(&idxOptionArg, pszTftpRRQRaw);
            if (RT_SUCCESS(rc))
                fWithArg = 1;
            else
            {
                LogFlowFuncLeaveRC(rc);
                AssertRCReturn(rc,rc);
            }
        }
        pszTftpRRQRaw += idxTftpRRQRaw;
        cbTftpRRQRaw -= idxTftpRRQRaw;
    }

    LogFlowFuncLeaveRC(rc);
    return rc;
}
Exemplo n.º 12
0
/**
 * Calculates the checksum of a pseudo header given an IPv6 header, ASSUMING
 * that there are no headers between the IPv6 header and the upper layer header.
 *
 * Use this method with create care!  In most cases you should be using
 * RTNetIPv6PseudoChecksumEx.
 *
 * @returns 32-bit intermediary checksum value.
 * @param   pIpHdr      The IPv6 header (network endian (big)).
 */
RTDECL(uint32_t) RTNetIPv6PseudoChecksum(PCRTNETIPV6 pIpHdr)
{
    return rtNetIPv6PseudoChecksumBits(&pIpHdr->ip6_src, &pIpHdr->ip6_dst,
                                       pIpHdr->ip6_nxt, RT_N2H_U16(pIpHdr->ip6_plen));
}
Exemplo n.º 13
0
/**
 * Processes the data in the scratch buffer based on the current state.
 *
 * @returns VBox status code.
 */
int USBProxyBackendUsbIp::processData()
{
    int rc = VINF_SUCCESS;

    switch (m->enmRecvState)
    {
        case kUsbIpRecvState_Hdr:
        {
            /* Check that the reply matches our expectations. */
            if (   RT_N2H_U16(m->Scratch.RetDevList.u16Version) == USBIP_VERSION
                && RT_N2H_U16(m->Scratch.RetDevList.u16Cmd) == USBIP_REQ_RET_DEVLIST
                && RT_N2H_U32(m->Scratch.RetDevList.u32Status) == USBIP_STATUS_SUCCESS)
            {
                /* Populate the number of exported devices in the list and go to the next state. */
                m->cDevicesLeft = RT_N2H_U32(m->Scratch.RetDevList.u32DevicesExported);
                if (m->cDevicesLeft)
                    advanceState(kUsbIpRecvState_ExportedDevice);
                else
                    advanceState(kUsbIpRecvState_None);
            }
            else
            {
                LogRelMax(10, ("USB/IP: Host sent an invalid reply to the list exported device request (Version: %#x Cmd: %#x Status: %#x)\n",
                               RT_N2H_U16(m->Scratch.RetDevList.u16Version), RT_N2H_U16(m->Scratch.RetDevList.u16Cmd),
                               RT_N2H_U32(m->Scratch.RetDevList.u32Status)));
                rc = VERR_INVALID_STATE;
            }
            break;
        }
        case kUsbIpRecvState_ExportedDevice:
        {
            /* Create a new device and add it to the list. */
            usbProxyBackendUsbIpExportedDeviceN2H(&m->Scratch.ExportedDevice);
            rc = addDeviceToList(&m->Scratch.ExportedDevice);
            if (RT_SUCCESS(rc))
            {
                m->cInterfacesLeft = m->Scratch.ExportedDevice.bNumInterfaces;
                if (m->cInterfacesLeft)
                    advanceState(kUsbIpRecvState_DeviceInterface);
                else
                {
                    m->cDevicesLeft--;
                    if (m->cDevicesLeft)
                        advanceState(kUsbIpRecvState_ExportedDevice);
                    else
                        advanceState(kUsbIpRecvState_None);
                }
            }
            break;
        }
        case kUsbIpRecvState_DeviceInterface:
        {
            /*
             * If all interfaces for the current device were received receive the next device
             * if there is another one left, if not we are done with the current request.
             */
            m->cInterfacesLeft--;
            if (m->cInterfacesLeft)
                advanceState(kUsbIpRecvState_DeviceInterface);
            else
            {
                m->cDevicesLeft--;
                if (m->cDevicesLeft)
                    advanceState(kUsbIpRecvState_ExportedDevice);
                else
                    advanceState(kUsbIpRecvState_None);
            }
            break;
        }
        case kUsbIpRecvState_None:
        default:
            AssertMsgFailed(("Invalid USB/IP receive state %d\n", m->enmRecvState));
            return VERR_INVALID_STATE;
    }

    return rc;
}
Exemplo n.º 14
0
/* m->m_data  points at ip packet header
 * m->m_len   length ip packet
 * ip->ip_len length data (IPDU)
 */
void
udp_input(PNATState pData, register struct mbuf *m, int iphlen)
{
    register struct ip *ip;
    register struct udphdr *uh;
    int len;
    struct ip save_ip;
    struct socket *so;
    int ret;
    int ttl;

    LogFlowFunc(("ENTER: m = %p, iphlen = %d\n", m, iphlen));
    ip = mtod(m, struct ip *);
    Log2(("%RTnaipv4 iphlen = %d\n", ip->ip_dst, iphlen));

    udpstat.udps_ipackets++;

    /*
     * Strip IP options, if any; should skip this,
     * make available to user, and use on returned packets,
     * but we don't yet have a way to check the checksum
     * with options still present.
     */
    if (iphlen > sizeof(struct ip))
    {
        ip_stripoptions(m, (struct mbuf *)0);
        iphlen = sizeof(struct ip);
    }

    /*
     * Get IP and UDP header together in first mbuf.
     */
    ip = mtod(m, struct ip *);
    uh = (struct udphdr *)((caddr_t)ip + iphlen);

    /*
     * Make mbuf data length reflect UDP length.
     * If not enough data to reflect UDP length, drop.
     */
    len = RT_N2H_U16((u_int16_t)uh->uh_ulen);
    Assert((ip->ip_len == len));
    Assert((ip->ip_len + iphlen == m_length(m, NULL)));

    if (ip->ip_len != len)
    {
        if (len > ip->ip_len)
        {
            udpstat.udps_badlen++;
            Log3(("NAT: IP(id: %hd) has bad size\n", ip->ip_id));
        }
        m_adj(m, len - ip->ip_len);
        ip->ip_len = len;
    }

    /*
     * Save a copy of the IP header in case we want restore it
     * for sending an ICMP error message in response.
     */
    save_ip = *ip;
    save_ip.ip_len+= iphlen;         /* tcp_input subtracts this */

    /*
     * Checksum extended UDP header and data.
     */
    if (udpcksum && uh->uh_sum)
    {
        memset(((struct ipovly *)ip)->ih_x1, 0, 9);
        ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
#if 0
        /* keep uh_sum for ICMP reply */
        uh->uh_sum = cksum(m, len + sizeof (struct ip));
        if (uh->uh_sum)
        {

#endif
            if (cksum(m, len + iphlen))
            {
                udpstat.udps_badsum++;
                Log3(("NAT: IP(id: %hd) has bad (udp) cksum\n", ip->ip_id));
                goto bad_free_mbuf;
            }
        }
#if 0
    }
#endif

    /*
     *  handle DHCP/BOOTP
     */
    if (uh->uh_dport == RT_H2N_U16_C(BOOTP_SERVER))
    {
        bootp_input(pData, m);
        goto done_free_mbuf;
    }

    LogFunc(("uh src: %RTnaipv4:%d, dst: %RTnaipv4:%d\n", ip->ip_src, RT_H2N_U16_C(uh->uh_sport), ip->ip_dst, RT_H2N_U16_C(uh->uh_dport)));
    if (   pData->fUseHostResolver
        && uh->uh_dport == RT_H2N_U16_C(53)
        && CTL_CHECK(ip->ip_dst.s_addr, CTL_DNS))
    {
        struct sockaddr_in dst, src;
        src.sin_addr.s_addr = ip->ip_dst.s_addr;
        src.sin_port = uh->uh_dport;
        dst.sin_addr.s_addr = ip->ip_src.s_addr;
        dst.sin_port = uh->uh_sport;

        slirpMbufTagService(pData, m, CTL_DNS);
        /* udp_output2() expects a pointer to the body of UDP packet. */
        m->m_data += sizeof(struct udpiphdr);
        m->m_len -= sizeof(struct udpiphdr);
        udp_output2(pData, NULL, m, &src, &dst, IPTOS_LOWDELAY);
        LogFlowFuncLeave();
        return;
    }
    /*
     *  handle TFTP
     */
    if (   uh->uh_dport == RT_H2N_U16_C(TFTP_SERVER)
        && CTL_CHECK(ip->ip_dst.s_addr, CTL_TFTP))
    {
        if (pData->pvTftpSessions)
            slirpTftpInput(pData, m);
        goto done_free_mbuf;
    }

    /*
     * Locate pcb for datagram.
     */
    so = udp_last_so;
    if (   so->so_lport != uh->uh_sport
        || so->so_laddr.s_addr != ip->ip_src.s_addr)
    {
        struct socket *tmp;

        for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next)
        {
            if (   tmp->so_lport        == uh->uh_sport
                && tmp->so_laddr.s_addr == ip->ip_src.s_addr)
            {
                so = tmp;
                break;
            }
        }
        if (tmp == &udb)
            so = NULL;
        else
        {
            udpstat.udpps_pcbcachemiss++;
            udp_last_so = so;
        }
    }

    if (so == NULL)
    {
        /*
         * If there's no socket for this packet,
         * create one
         */
        if ((so = socreate()) == NULL)
        {
            Log2(("NAT: IP(id: %hd) failed to create socket\n", ip->ip_id));
            goto bad_free_mbuf;
        }
        if (udp_attach(pData, so) <= 0)
        {
            Log2(("NAT: IP(id: %hd) udp_attach errno = %d (%s)\n",
                        ip->ip_id, errno, strerror(errno)));
            sofree(pData, so);
            goto bad_free_mbuf;
        }

        /*
         * Setup fields
         */
        /* udp_last_so = so; */
        so->so_laddr = ip->ip_src;
        so->so_lport = uh->uh_sport;

        so->so_iptos = ip->ip_tos;

        /*
         * XXXXX Here, check if it's in udpexec_list,
         * and if it is, do the fork_exec() etc.
         */
    }

    so->so_faddr = ip->ip_dst;   /* XXX */
    so->so_fport = uh->uh_dport; /* XXX */
    Assert(so->so_type == IPPROTO_UDP);

    /*
     * DNS proxy
     */
    if (   pData->fUseDnsProxy
        && CTL_CHECK(ip->ip_dst.s_addr, CTL_DNS)
        && (uh->uh_dport == RT_H2N_U16_C(53)))
    {
        dnsproxy_query(pData, so, m, iphlen);
        goto done_free_mbuf;
    }

    iphlen += sizeof(struct udphdr);
    m->m_len -= iphlen;
    m->m_data += iphlen;

    ttl = ip->ip_ttl = save_ip.ip_ttl;
    ret = setsockopt(so->s, IPPROTO_IP, IP_TTL, (const char*)&ttl, sizeof(ttl));
    if (ret < 0)
        LogRel(("NAT: Error (%s) occurred while setting TTL(%d) attribute "
                "of IP packet to socket %R[natsock]\n", strerror(errno), ip->ip_ttl, so));

    if (   sosendto(pData, so, m) == -1
        && (   !soIgnorableErrorCode(errno)
            && errno != ENOTCONN))
    {
        m->m_len += iphlen;
        m->m_data -= iphlen;
        *ip = save_ip;
        Log2(("NAT: UDP tx errno = %d (%s) on sent to %RTnaipv4\n",
              errno, strerror(errno), ip->ip_dst));
#if 0
        /* ICMP_SOURCEQUENCH haven't got any effect, the idea here
         * inform guest about the exosting NAT resources with assumption that
         * that guest reduce traffic. But it doesn't work
         */
        if(    errno == EAGAIN
            || errno == EWOULDBLOCK
            || errno == EINPROGRESS
            || errno == ENOTCONN)
            icmp_error(pData, m, ICMP_SOURCEQUENCH, 0, 1, strerror(errno));
        else
#endif
            icmp_error(pData, m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));
        so->so_m = NULL;
        LogFlowFuncLeave();
        return;
    }

    if (so->so_m)
        m_freem(pData, so->so_m);   /* used for ICMP if error on sorecvfrom */

    /* restore the orig mbuf packet */
    m->m_len += iphlen;
    m->m_data -= iphlen;
    *ip = save_ip;
    so->so_m = m;         /* ICMP backup */
    LogFlowFuncLeave();
    return;

bad_free_mbuf:
    Log2(("NAT: UDP(id: %hd) datagram to %RTnaipv4 with size(%d) claimed as bad\n",
        ip->ip_id, &ip->ip_dst, ip->ip_len));

done_free_mbuf:
    /* some services like bootp(built-in), dns(buildt-in) and dhcp don't need sockets
     * and create new m'buffers to send them to guest, so we'll free their incomming
     * buffers here.
     */
    m_freem(pData, m);
    LogFlowFuncLeave();
    return;
}
Exemplo n.º 15
0
/*
 * Ip input routine.  Checksum and byte swap header.  If fragmented
 * try to reassemble.  Process options.  Pass to next level.
 */
void
ip_input(PNATState pData, struct mbuf *m)
{
    register struct ip *ip;
    int hlen = 0;
    int mlen = 0;

    STAM_PROFILE_START(&pData->StatIP_input, a);

    LogFlowFunc(("ENTER: m = %lx\n", (long)m));
    ip = mtod(m, struct ip *);
    Log2(("ip_dst=%RTnaipv4(len:%d) m_len = %d\n", ip->ip_dst, RT_N2H_U16(ip->ip_len), m->m_len));

    ipstat.ips_total++;
    {
        int rc;
        STAM_PROFILE_START(&pData->StatALIAS_input, b);
        rc = LibAliasIn(select_alias(pData, m), mtod(m, char *), m_length(m, NULL));
        STAM_PROFILE_STOP(&pData->StatALIAS_input, b);
        Log2(("NAT: LibAlias return %d\n", rc));
        if (m->m_len != RT_N2H_U16(ip->ip_len))
            m->m_len = RT_N2H_U16(ip->ip_len);
    }

    mlen = m->m_len;

    if (mlen < sizeof(struct ip))
    {
        ipstat.ips_toosmall++;
        goto bad_free_m;
    }

    ip = mtod(m, struct ip *);
    if (ip->ip_v != IPVERSION)
    {
        ipstat.ips_badvers++;
        goto bad_free_m;
    }

    hlen = ip->ip_hl << 2;
    if (   hlen < sizeof(struct ip)
        || hlen > m->m_len)
    {
        /* min header length */
        ipstat.ips_badhlen++;                     /* or packet too short */
        goto bad_free_m;
    }

    /* keep ip header intact for ICMP reply
     * ip->ip_sum = cksum(m, hlen);
     * if (ip->ip_sum) {
     */
    if (cksum(m, hlen))
    {
        ipstat.ips_badsum++;
        goto bad_free_m;
    }

    /*
     * Convert fields to host representation.
     */
    NTOHS(ip->ip_len);
    if (ip->ip_len < hlen)
    {
        ipstat.ips_badlen++;
        goto bad_free_m;
    }

    NTOHS(ip->ip_id);
    NTOHS(ip->ip_off);

    /*
     * Check that the amount of data in the buffers
     * is as at least much as the IP header would have us expect.
     * Trim mbufs if longer than we expect.
     * Drop packet if shorter than we expect.
     */
    if (mlen < ip->ip_len)
    {
        ipstat.ips_tooshort++;
        goto bad_free_m;
    }

    /* Should drop packet if mbuf too long? hmmm... */
    if (mlen > ip->ip_len)
        m_adj(m, ip->ip_len - m->m_len);

    /* check ip_ttl for a correct ICMP reply */
    if (ip->ip_ttl==0 || ip->ip_ttl == 1)
    {
        icmp_error(pData, m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, "ttl");
        goto no_free_m;
    }

    ip->ip_ttl--;
    /*
     * If offset or IP_MF are set, must reassemble.
     * Otherwise, nothing need be done.
     * (We could look in the reassembly queue to see
     * if the packet was previously fragmented,
     * but it's not worth the time; just let them time out.)
     *
     */
    if (ip->ip_off & (IP_MF | IP_OFFMASK))
    {
        m = ip_reass(pData, m);
        if (m == NULL)
            goto no_free_m;
        ip = mtod(m, struct ip *);
        hlen = ip->ip_hl << 2;
    }