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