Exemplo n.º 1
0
int VBoxNetLwipNAT::natServicePfRegister(NATSEVICEPORTFORWARDRULE& natPf)
{
    int lrc;

    int sockFamily = (natPf.Pfr.fPfrIPv6 ? PF_INET6 : PF_INET);
    int socketSpec;
    switch(natPf.Pfr.iPfrProto)
    {
        case IPPROTO_TCP:
            socketSpec = SOCK_STREAM;
            break;
        case IPPROTO_UDP:
            socketSpec = SOCK_DGRAM;
            break;
        default:
            return VERR_IGNORED;
    }

    const char *pszHostAddr = natPf.Pfr.szPfrHostAddr;
    if (pszHostAddr[0] == '\0')
    {
        if (sockFamily == PF_INET)
            pszHostAddr = "0.0.0.0";
        else
            pszHostAddr = "::";
    }

    lrc = fwspec_set(&natPf.FWSpec,
                     sockFamily,
                     socketSpec,
                     pszHostAddr,
                     natPf.Pfr.u16PfrHostPort,
                     natPf.Pfr.szPfrGuestAddr,
                     natPf.Pfr.u16PfrGuestPort);
    if (lrc != 0)
        return VERR_IGNORED;

    RTCMemAutoPtr<fwspec> pFwCopy;
    if (RT_UNLIKELY(!pFwCopy.alloc()))
    {
        LogRel(("Unable to allocate memory for %s rule \"%s\"\n",
                natPf.Pfr.fPfrIPv6 ? "IPv6" : "IPv4",
                natPf.Pfr.szPfrName));
        return VERR_IGNORED;
    }

    memcpy(pFwCopy.get(), &natPf.FWSpec, sizeof(natPf.FWSpec));

    lrc = portfwd_rule_add(pFwCopy.get());
    if (lrc != 0)
        return VERR_IGNORED;

    pFwCopy.release();          /* owned by lwip thread now */
    return VINF_SUCCESS;
}
/**
 * Start enumerating guest properties which match a given pattern.
 * This function creates a handle which can be used to continue enumerating.
 *
 * @returns VBox status code.
 * @retval  VINF_SUCCESS on success, *ppHandle points to a handle for continuing
 *          the enumeration and *ppszName, *ppszValue, *pu64Timestamp and
 *          *ppszFlags are set.
 * @retval  VERR_NOT_FOUND if no matching properties were found.  In this case
 *          the return parameters are not initialised.
 * @retval  VERR_TOO_MUCH_DATA if it was not possible to determine the amount
 *          of local space needed to store all the enumeration data.  This is
 *          due to a race between allocating space and the host adding new
 *          data, so retrying may help here.  Other parameters are left
 *          uninitialised
 *
 * @param   u32ClientId     The client id returned by VbglR3InfoSvcConnect().
 * @param   papszPatterns   The patterns against which the properties are
 *                          matched.  Pass NULL if everything should be matched.
 * @param   cPatterns       The number of patterns in @a papszPatterns.  0 means
 *                          match everything.
 * @param   ppHandle        where the handle for continued enumeration is stored
 *                          on success.  This must be freed with
 *                          VbglR3GuestPropEnumFree when it is no longer needed.
 * @param   ppszName        Where to store the first property name on success.
 *                          Should not be freed. Optional.
 * @param   ppszValue       Where to store the first property value on success.
 *                          Should not be freed. Optional.
 * @param   ppszValue       Where to store the first timestamp value on success.
 *                          Optional.
 * @param   ppszFlags       Where to store the first flags value on success.
 *                          Should not be freed. Optional.
 */
VBGLR3DECL(int) VbglR3GuestPropEnum(uint32_t u32ClientId,
                                    char const * const *papszPatterns,
                                    uint32_t cPatterns,
                                    PVBGLR3GUESTPROPENUM *ppHandle,
                                    char const **ppszName,
                                    char const **ppszValue,
                                    uint64_t *pu64Timestamp,
                                    char const **ppszFlags)
{
    /* Create the handle. */
    RTCMemAutoPtr<VBGLR3GUESTPROPENUM, VbglR3GuestPropEnumFree> Handle;
    Handle = (PVBGLR3GUESTPROPENUM)RTMemAllocZ(sizeof(VBGLR3GUESTPROPENUM));
    if (!Handle)
        return VERR_NO_MEMORY;

    /* Get the length of the pattern string, including the final terminator. */
    size_t cchPatterns = 1;
    for (uint32_t i = 0; i < cPatterns; ++i)
        cchPatterns += strlen(papszPatterns[i]) + 1;

    /* Pack the pattern array */
    RTCMemAutoPtr<char> Patterns;
    Patterns = (char *)RTMemAlloc(cchPatterns);
    size_t off = 0;
    for (uint32_t i = 0; i < cPatterns; ++i)
    {
        size_t cb = strlen(papszPatterns[i]) + 1;
        memcpy(&Patterns[off], papszPatterns[i], cb);
        off += cb;
    }
    Patterns[off] = '\0';

    /* Randomly chosen initial size for the buffer to hold the enumeration
     * information. */
    uint32_t cchBuf = 4096;
    RTCMemAutoPtr<char> Buf;

    /* In reading the guest property data we are racing against the host
     * adding more of it, so loop a few times and retry on overflow. */
    int rc = VINF_SUCCESS;
    for (int i = 0; i < 10; ++i)
    {
        if (!Buf.realloc(cchBuf))
        {
            rc = VERR_NO_MEMORY;
            break;
        }
        rc = VbglR3GuestPropEnumRaw(u32ClientId, Patterns.get(),
                                    Buf.get(), cchBuf, &cchBuf);
        if (rc != VERR_BUFFER_OVERFLOW)
            break;
        cchBuf += 4096;  /* Just to increase our chances */
    }
    if (RT_SUCCESS(rc))
    {
        /*
         * Transfer ownership of the buffer to the handle structure and
         * call VbglR3GuestPropEnumNext to retrieve the first entry.
         */
        Handle->pchNext = Handle->pchBuf = Buf.release();
        Handle->pchBufEnd = Handle->pchBuf + cchBuf;

        const char *pszNameTmp;
        if (!ppszName)
            ppszName = &pszNameTmp;
        rc = VbglR3GuestPropEnumNext(Handle.get(), ppszName, ppszValue,
                                     pu64Timestamp, ppszFlags);
        if (RT_SUCCESS(rc) && *ppszName != NULL)
            *ppHandle = Handle.release();
        else if (RT_SUCCESS(rc))
            rc = VERR_NOT_FOUND; /* No matching properties found. */
    }
    else if (rc == VERR_BUFFER_OVERFLOW)
        rc = VERR_TOO_MUCH_DATA;
    return rc;
}
Exemplo n.º 3
0
/**
 * @note: this work on Event thread.
 */
HRESULT VBoxNetLwipNAT::HandleEvent(VBoxEventType_T aEventType, IEvent *pEvent)
{
    HRESULT hrc = S_OK;
    switch (aEventType)
    {
        case VBoxEventType_OnNATNetworkSetting:
        {
            ComPtr<INATNetworkSettingEvent> pSettingsEvent(pEvent);

            com::Bstr networkName;
            hrc = pSettingsEvent->COMGETTER(NetworkName)(networkName.asOutParam());
            AssertComRCReturn(hrc, hrc);
            if (networkName.compare(getNetworkName().c_str()))
                break; /* change not for our network */

            // XXX: only handle IPv6 default route for now
            if (!m_ProxyOptions.ipv6_enabled)
                break;

            BOOL fIPv6DefaultRoute = FALSE;
            hrc = pSettingsEvent->COMGETTER(AdvertiseDefaultIPv6RouteEnabled)(&fIPv6DefaultRoute);
            AssertComRCReturn(hrc, hrc);

            if (m_ProxyOptions.ipv6_defroute == fIPv6DefaultRoute)
                break;

            m_ProxyOptions.ipv6_defroute = fIPv6DefaultRoute;
            tcpip_callback_with_block(proxy_rtadvd_do_quick, &m_LwipNetIf, 0);
            break;
        }

        case VBoxEventType_OnNATNetworkPortForward:
        {
            ComPtr<INATNetworkPortForwardEvent> pForwardEvent = pEvent;

            com::Bstr networkName;
            hrc = pForwardEvent->COMGETTER(NetworkName)(networkName.asOutParam());
            AssertComRCReturn(hrc, hrc);
            if (networkName.compare(getNetworkName().c_str()))
                break; /* change not for our network */

            BOOL fCreateFW;
            hrc = pForwardEvent->COMGETTER(Create)(&fCreateFW);
            AssertComRCReturn(hrc, hrc);

            BOOL  fIPv6FW;
            hrc = pForwardEvent->COMGETTER(Ipv6)(&fIPv6FW);
            AssertComRCReturn(hrc, hrc);

            com::Bstr name;
            hrc = pForwardEvent->COMGETTER(Name)(name.asOutParam());
            AssertComRCReturn(hrc, hrc);

            NATProtocol_T proto = NATProtocol_TCP;
            hrc = pForwardEvent->COMGETTER(Proto)(&proto);
            AssertComRCReturn(hrc, hrc);

            com::Bstr strHostAddr;
            hrc = pForwardEvent->COMGETTER(HostIp)(strHostAddr.asOutParam());
            AssertComRCReturn(hrc, hrc);

            LONG lHostPort;
            hrc = pForwardEvent->COMGETTER(HostPort)(&lHostPort);
            AssertComRCReturn(hrc, hrc);

            com::Bstr strGuestAddr;
            hrc = pForwardEvent->COMGETTER(GuestIp)(strGuestAddr.asOutParam());
            AssertComRCReturn(hrc, hrc);

            LONG lGuestPort;
            hrc = pForwardEvent->COMGETTER(GuestPort)(&lGuestPort);
            AssertComRCReturn(hrc, hrc);

            VECNATSERVICEPF& rules = fIPv6FW ? m_vecPortForwardRule6
                                             : m_vecPortForwardRule4;

            NATSEVICEPORTFORWARDRULE r;
            RT_ZERO(r);

            r.Pfr.fPfrIPv6 = fIPv6FW;

            switch (proto)
            {
                case NATProtocol_TCP:
                    r.Pfr.iPfrProto = IPPROTO_TCP;
                    break;
                case NATProtocol_UDP:
                    r.Pfr.iPfrProto = IPPROTO_UDP;
                    break;

                default:
                    LogRel(("Event: %s %s port-forwarding rule \"%s\":"
                            " invalid protocol %d\n",
                            fCreateFW ? "Add" : "Remove",
                            fIPv6FW ? "IPv6" : "IPv4",
                            com::Utf8Str(name).c_str(),
                            (int)proto));
                    goto port_forward_done;
            }

            LogRel(("Event: %s %s port-forwarding rule \"%s\":"
                    " %s %s%s%s:%d -> %s%s%s:%d\n",
                    fCreateFW ? "Add" : "Remove",
                    fIPv6FW ? "IPv6" : "IPv4",
                    com::Utf8Str(name).c_str(),
                    proto == NATProtocol_TCP ? "TCP" : "UDP",
                    /* from */
                    fIPv6FW ? "[" : "",
                    com::Utf8Str(strHostAddr).c_str(),
                    fIPv6FW ? "]" : "",
                    lHostPort,
                    /* to */
                    fIPv6FW ? "[" : "",
                    com::Utf8Str(strGuestAddr).c_str(),
                    fIPv6FW ? "]" : "",
                    lGuestPort));

            if (name.length() > sizeof(r.Pfr.szPfrName))
            {
                hrc = E_INVALIDARG;
                goto port_forward_done;
            }

            RTStrPrintf(r.Pfr.szPfrName, sizeof(r.Pfr.szPfrName),
                        "%s", com::Utf8Str(name).c_str());

            RTStrPrintf(r.Pfr.szPfrHostAddr, sizeof(r.Pfr.szPfrHostAddr),
                        "%s", com::Utf8Str(strHostAddr).c_str());

            /* XXX: limits should be checked */
            r.Pfr.u16PfrHostPort = (uint16_t)lHostPort;

            RTStrPrintf(r.Pfr.szPfrGuestAddr, sizeof(r.Pfr.szPfrGuestAddr),
                        "%s", com::Utf8Str(strGuestAddr).c_str());

            /* XXX: limits should be checked */
            r.Pfr.u16PfrGuestPort = (uint16_t)lGuestPort;

            if (fCreateFW) /* Addition */
            {
                int rc = natServicePfRegister(r);
                if (RT_SUCCESS(rc))
                    rules.push_back(r);
            }
            else /* Deletion */
            {
                ITERATORNATSERVICEPF it;
                for (it = rules.begin(); it != rules.end(); ++it)
                {
                    /* compare */
                    NATSEVICEPORTFORWARDRULE& natFw = *it;
                    if (   natFw.Pfr.iPfrProto == r.Pfr.iPfrProto
                        && natFw.Pfr.u16PfrHostPort == r.Pfr.u16PfrHostPort
                        && (strncmp(natFw.Pfr.szPfrHostAddr, r.Pfr.szPfrHostAddr, INET6_ADDRSTRLEN) == 0)
                        && natFw.Pfr.u16PfrGuestPort == r.Pfr.u16PfrGuestPort
                        && (strncmp(natFw.Pfr.szPfrGuestAddr, r.Pfr.szPfrGuestAddr, INET6_ADDRSTRLEN) == 0))
                    {
                        RTCMemAutoPtr<fwspec> pFwCopy;
                        if (RT_UNLIKELY(!pFwCopy.alloc()))
                            break;

                        memcpy(pFwCopy.get(), &natFw.FWSpec, sizeof(natFw.FWSpec));

                        int status = portfwd_rule_del(pFwCopy.get());
                        if (status != 0)
                            break;

                        pFwCopy.release(); /* owned by lwip thread now */
                        rules.erase(it);
                        break;
                    }
                } /* loop over vector elements */
            } /* condition add or delete */
        port_forward_done:
            /* clean up strings */
            name.setNull();
            strHostAddr.setNull();
            strGuestAddr.setNull();
            break;
        }

        case VBoxEventType_OnHostNameResolutionConfigurationChange:
        {
            const char **ppcszNameServers = getHostNameservers();
            err_t error;

            error = tcpip_callback_with_block(pxdns_set_nameservers,
                                              ppcszNameServers,
                                              /* :block */ 0);
            if (error != ERR_OK && ppcszNameServers != NULL)
                RTMemFree(ppcszNameServers);
            break;
        }

        case VBoxEventType_OnNATNetworkStartStop:
        {
            ComPtr <INATNetworkStartStopEvent> pStartStopEvent = pEvent;

            com::Bstr networkName;
            hrc = pStartStopEvent->COMGETTER(NetworkName)(networkName.asOutParam());
            AssertComRCReturn(hrc, hrc);
            if (networkName.compare(getNetworkName().c_str()))
                break; /* change not for our network */

            BOOL fStart = TRUE;
            hrc = pStartStopEvent->COMGETTER(StartEvent)(&fStart);
            AssertComRCReturn(hrc, hrc);

            if (!fStart)
                shutdown();
            break;
        }
    }
    return hrc;
}
int main()
{
    RTR3InitExeNoArguments(0);
    RTPrintf("tstMemAutoPtr: TESTING...\n");

#define CHECK_EXPR(expr) \
    do { bool const f = !!(expr); if (!f) { RTPrintf("tstMemAutoPtr(%d): %s!\n", __LINE__, #expr); g_cErrors++; } } while (0)

    /*
     * Some simple stuff.
     */
    {
        RTCMemAutoPtr<char> NilObj;
        CHECK_EXPR(!NilObj);
        CHECK_EXPR(NilObj.get() == NULL);
        CHECK_EXPR(NilObj.release() == NULL);
        NilObj.reset();
    }

    {
        RTCMemAutoPtr<char> Alloc(10);
        CHECK_EXPR(Alloc.get() != NULL);
        char *pch = Alloc.release();
        CHECK_EXPR(pch != NULL);
        CHECK_EXPR(Alloc.get() == NULL);

        RTCMemAutoPtr<char> Manage(pch);
        CHECK_EXPR(Manage.get() == pch);
        CHECK_EXPR(&Manage[0] == pch);
        CHECK_EXPR(&Manage[1] == &pch[1]);
        CHECK_EXPR(&Manage[9] == &pch[9]);
    }

    /*
     * Use the electric fence memory API to check alternative template
     * arguments and also check some subscript / reference limit thing.
     */
    {
        RTCMemAutoPtr<char, RTCMemEfAutoFree<char>, RTMemEfReallocNP> Electric(10);
        CHECK_EXPR(Electric.get() != NULL);
        Electric[0] = '0';
        CHECK_EXPR(Electric[0]  == '0');
        CHECK_EXPR(*Electric  == '0');
        //CHECK_EXPR(Electric  == '0');
        Electric[9] = '1';
        CHECK_EXPR(Electric[9] == '1');
        /* Electric[10] = '2'; - this will crash (of course) */
    }

    /*
     * Check that memory is actually free when it should be and isn't when it shouldn't.
     * Use the electric heap to get some extra checks.
     */
    g_cFrees = 0;
    {
        RTCMemAutoPtr<char, tstMemAutoPtrDestructorCounter, RTMemEfReallocNP> FreeIt(128);
        FreeIt[127] = '0';
    }
    CHECK_EXPR(g_cFrees == 1);

    g_cFrees = 0;
    {
        RTCMemAutoPtr<char, tstMemAutoPtrDestructorCounter, RTMemEfReallocNP> FreeIt2(128);
        FreeIt2[127] = '1';
        FreeIt2.reset();
        FreeIt2.alloc(128);
        FreeIt2[127] = '2';
        FreeIt2.reset(FreeIt2.get()); /* this one is weird, but it's how things works... */
    }
    CHECK_EXPR(g_cFrees == 2);

    g_cFrees = 0;
    {
        RTCMemAutoPtr<char, tstMemAutoPtrDestructorCounter, RTMemEfReallocNP> DontFreeIt(256);
        DontFreeIt[255] = '0';
        RTMemEfFreeNP(DontFreeIt.release());
    }
    CHECK_EXPR(g_cFrees == 0);

    g_cFrees = 0;
    {
        RTCMemAutoPtr<char, tstMemAutoPtrDestructorCounter, RTMemEfReallocNP> FreeIt3(128);
        FreeIt3[127] = '0';
        CHECK_EXPR(FreeIt3.realloc(128));
        FreeIt3[127] = '0';
        CHECK_EXPR(FreeIt3.realloc(256));
        FreeIt3[255] = '0';
        CHECK_EXPR(FreeIt3.realloc(64));
        FreeIt3[63] = '0';
        CHECK_EXPR(FreeIt3.realloc(32));
        FreeIt3[31] = '0';
    }
    CHECK_EXPR(g_cFrees == 1);

    g_cFrees = 0;
    {
        RTCMemAutoPtr<char, tstMemAutoPtrDestructorCounter, RTMemEfReallocNP> FreeIt4;
        CHECK_EXPR(FreeIt4.alloc(123));
        CHECK_EXPR(FreeIt4.realloc(543));
        FreeIt4 = (char *)NULL;
        CHECK_EXPR(FreeIt4.get() == NULL);
    }
    CHECK_EXPR(g_cFrees == 1);

    /*
     * Check the ->, [] and * (unary) operators with some useful struct.
     */
    {
        RTCMemAutoPtr<TSTMEMAUTOPTRSTRUCT> Struct1(1);
        Struct1->a = 0x11223344;
        Struct1->b = 0x55667788;
        Struct1->c = 0x99aabbcc;
        CHECK_EXPR(Struct1->a == 0x11223344);
        CHECK_EXPR(Struct1->b == 0x55667788);
        CHECK_EXPR(Struct1->c == 0x99aabbcc);

        Struct1[0].a = 0x11223344;
        Struct1[0].b = 0x55667788;
        Struct1[0].c = 0x99aabbcc;
        CHECK_EXPR(Struct1[0].a == 0x11223344);
        CHECK_EXPR(Struct1[0].b == 0x55667788);
        CHECK_EXPR(Struct1[0].c == 0x99aabbcc);

        (*Struct1).a = 0x11223344;
        (*Struct1).b = 0x55667788;
        (*Struct1).c = 0x99aabbcc;
        CHECK_EXPR((*Struct1).a == 0x11223344);
        CHECK_EXPR((*Struct1).b == 0x55667788);
        CHECK_EXPR((*Struct1).c == 0x99aabbcc);

        /* since at it... */
        Struct1.get()->a = 0x11223344;
        Struct1.get()->b = 0x55667788;
        Struct1.get()->c = 0x99aabbcc;
        CHECK_EXPR(Struct1.get()->a == 0x11223344);
        CHECK_EXPR(Struct1.get()->b == 0x55667788);
        CHECK_EXPR(Struct1.get()->c == 0x99aabbcc);
    }

    /*
     * Check the zeroing of memory.
     */
    {
        RTCMemAutoPtr<uint64_t, RTCMemAutoDestructor<uint64_t>, tstMemAutoPtrAllocatorNoZero> Zeroed1(1, true);
        CHECK_EXPR(*Zeroed1 == 0);
    }

    {
        RTCMemAutoPtr<uint64_t, RTCMemAutoDestructor<uint64_t>, tstMemAutoPtrAllocatorNoZero> Zeroed2;
        Zeroed2.alloc(5, true);
        CHECK_EXPR(Zeroed2[0] == 0);
        CHECK_EXPR(Zeroed2[1] == 0);
        CHECK_EXPR(Zeroed2[2] == 0);
        CHECK_EXPR(Zeroed2[3] == 0);
        CHECK_EXPR(Zeroed2[4] == 0);
    }

    /*
     * Summary.
     */
    if (!g_cErrors)
        RTPrintf("tstMemAutoPtr: SUCCESS\n");
    else
        RTPrintf("tstMemAutoPtr: FAILED - %d errors\n", g_cErrors);
    return !!g_cErrors;
}