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; }
/** * @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; }