Windows多网卡配置ICS网络共享C++实现
#include <unordered_map>
#ifdef _MSC_VER
#include <WinSock2.h>
#include <NetCon.h>
#define MAX_PATH_LEN MAX_PATH
#define popen _popen
#define pclose _pclose
#else
#include <unistd.h>
#include <limits.h>
#define MAX_PATH_LEN PATH_MAX
#endif
class NetConProperties
{
public:
GUID guidId;
private:
/* [string] */ LPCWSTR pszwName;
/* [string] */ LPCWSTR pszwDeviceName;
public:
NETCON_STATUS Status;
NETCON_MEDIATYPE MediaType;
DWORD dwCharacter;
CLSID clsidThisObject;
CLSID clsidUiObject;
std::wstring wszwName;
std::wstring wszwDeviceName;
private:
void __init(const NETCON_PROPERTIES* pntp)
{
memcpy(this, pntp, sizeof(NETCON_PROPERTIES));
this->wszwName = this->pszwName;
this->wszwDeviceName = this->pszwDeviceName;
this->pszwName = this->pszwDeviceName = NULL;
}
void __init(const NETCON_PROPERTIES& ntp)
{
memcpy(this, &ntp, sizeof(ntp));
this->wszwName = this->pszwName;
this->wszwDeviceName = this->pszwDeviceName;
this->pszwName = this->pszwDeviceName = NULL;
}
public:
NetConProperties(const NETCON_PROPERTIES& ntp)
{
__init(ntp);
}
NetConProperties(const NETCON_PROPERTIES* pntp)
{
__init(pntp);
}
NetConProperties& operator =(const NETCON_PROPERTIES& ntp)
{
__init(ntp);
}
};
class ComNetSharingManager
{
public:
ComNetSharingManager()
{
if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED)))
{
CoInitialize(NULL);
}
// init security to enum RAS connections
CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
HRESULT hr = ::CoCreateInstance(__uuidof(NetSharingManager), NULL, CLSCTX_ALL, __uuidof(INetSharingManager), (void**)&pNSM);
if (!pNSM)
{
wprintf(L"failed to create NetSharingManager object\r\n");
}
}
~ComNetSharingManager()
{
CoUninitialize();
}
private:
INetSharingManager* pNSM = NULL;
public:
HRESULT EnumShareNet(std::unordered_map<std::wstring, NetConProperties>& mapNCP)
{
INetConnection* pNC = NULL;
INetSharingConfiguration* pNSC = NULL;
IEnumVARIANT* pEV = NULL;
IUnknown* pUnk = NULL;
INetSharingEveryConnectionCollection* pNSECC = NULL;
INetSharingConfiguration* pNSCSrc = NULL;
INetSharingConfiguration* pNSCDst = NULL;
INT nMaxRetryNum = 10;
VARIANT_BOOL bSharingEnabled = VARIANT_TRUE;
HRESULT hr = pNSM->get_EnumEveryConnection(&pNSECC);
VARIANT v = { 0 };
VariantInit(&v);
if (!pNSECC)
{
wprintf(L"failed to get EveryConnectionCollection!\r\n");
return S_FALSE;
}
hr = pNSECC->get__NewEnum(&pUnk);
if (pUnk)
{
hr = pUnk->QueryInterface(__uuidof(IEnumVARIANT), (void**)&pEV);
pUnk->Release();
}
while (S_OK == pEV->Next(1, &v, NULL))
{
if (V_VT(&v) == VT_UNKNOWN)
{
V_UNKNOWN(&v)->QueryInterface(__uuidof(INetConnection), (void**)&pNC);
if (pNC)
{
NETCON_PROPERTIES* pNP = NULL;
hr = pNC->GetProperties(&pNP);
if (SUCCEEDED(hr))
{
mapNCP.emplace(pNP->pszwDeviceName, NetConProperties(pNP));
pNC->Release();
}
}
}
}
return hr;
}
HRESULT AddShareNet(LPCWSTR wSrcDeviceName, LPCWSTR wDstDeviceName)
{
INetConnection* pNC = NULL;
INetSharingConfiguration* pNSC = NULL;
IEnumVARIANT* pEV = NULL;
IUnknown* pUnk = NULL;
INetSharingEveryConnectionCollection* pNSECC = NULL;
INetSharingConfiguration* pNSCSrc = NULL;
INetSharingConfiguration* pNSCDst = NULL;
INT nMaxRetryNum = 10;
VARIANT_BOOL bSharingEnabled = VARIANT_TRUE;
HRESULT hr = pNSM->get_EnumEveryConnection(&pNSECC);
VARIANT v = { 0 };
VariantInit(&v);
if (!pNSECC)
{
wprintf(L"failed to get EveryConnectionCollection!\r\n");
return S_FALSE;
}
hr = pNSECC->get__NewEnum(&pUnk);
if (pUnk)
{
hr = pUnk->QueryInterface(__uuidof(IEnumVARIANT), (void**)&pEV);
pUnk->Release();
}
while (S_OK == pEV->Next(1, &v, NULL))
{
if (V_VT(&v) == VT_UNKNOWN)
{
V_UNKNOWN(&v)->QueryInterface(__uuidof(INetConnection), (void**)&pNC);
if (pNC)
{
NETCON_PROPERTIES* pNP = NULL;
pNC->GetProperties(&pNP);
if (SUCCEEDED(hr))
{
if (pNP->Status == NCS_CONNECTED)
{
hr = pNSM->get_INetSharingConfigurationForINetConnection(pNC, &pNSC);
if (!wcscmp(pNP->pszwDeviceName, wSrcDeviceName))
{
pNSCSrc = pNSC;
}
else if (!wcscmp(pNP->pszwDeviceName, wDstDeviceName))
{
pNSCDst = pNSC;
}
else
{
pNSC->Release();
}
}
pNC->Release();
}
}
}
}
if (pNSCSrc != NULL && pNSCDst != NULL)
{
hr = pNSCSrc->DisableSharing();
hr = pNSCDst->DisableSharing();
bSharingEnabled = VARIANT_TRUE;
while (SUCCEEDED(hr = pNSCSrc->get_SharingEnabled(&bSharingEnabled)) && (bSharingEnabled != VARIANT_FALSE) && (nMaxRetryNum--))
{
Sleep(100);
}
hr = pNSCSrc->EnableSharing(ICSSHARINGTYPE_PUBLIC);
hr = pNSCDst->EnableSharing(ICSSHARINGTYPE_PRIVATE);
}
if (pNSCSrc != NULL)
{
pNSCSrc->Release();
}
if (pNSCDst != NULL)
{
pNSCDst->Release();
}
return hr;
}
std::string AddIp(const std::string& name, const std::string& addr, const std::string& mask, const std::string& gateway, const std::string& gwmetric="1")
{
std::string cmd = "netsh interface ip set address name=\"" + name + "\" source=static addr=" + addr + " mask=" + mask + " gateway=" + gateway + " gwmetric="+ gwmetric;
return RunCmd("cmd /c " + cmd);
}
private:
std::string RunCmd(const std::string& cmd)
{
std::string ret = ("");
FILE* f = popen((cmd + " 2>&1").c_str(), "r");
if (f != nullptr)
{
size_t s = 0;
char d[MAX_PATH_LEN] = { 0 };
while (!feof(f))
{
s = fread(d, sizeof(char), sizeof(d) / sizeof(char), f);
if (s > 0)
{
ret.append(d, s);
}
}
pclose(f);
}
else
{
printf("popen %s error:(%d),%s.\n", cmd.c_str(), errno, strerror(errno));
}
return ret;
}
};
调用方法:
配置Intel(R) Ethernet Connection (7) I219-V为外网,VIA Velocity-Family Gigabit Ethernet Adapter为内网,外网共享给内网,并给内网配置新的ip网段。
int main(int argc, char ** argv)
{
setlocale(LC_ALL, "chs");
std::cout << "Hello CMake." << std::endl;
ComNetSharingManager cnsm = {};
std::unordered_map<std::wstring, NetConProperties> mapNCP = {};
{
std::string addr = "192.168.1.254";
std::string mask = "255.255.255.0";
std::string gateway = "192.168.1.254";
std::wstring wSrcDeviceName = L"Intel(R) Ethernet Connection (7) I219-V";
std::wstring wDstDeviceName = L"VIA Velocity-Family Gigabit Ethernet Adapter";
if (SUCCEEDED(cnsm.EnumShareNet(mapNCP)) && SUCCEEDED(cnsm.AddShareNet(wSrcDeviceName.c_str(), wDstDeviceName.c_str())))
{
for (auto it : mapNCP)
{
wprintf(L"%s,%s,%d\n", it.second.wszwDeviceName, it.second.wszwName.c_str(), it.second.Status);
}
if (mapNCP.find(wDstDeviceName) != mapNCP.end())
{
cnsm.AddIp(WToANSI(mapNCP.at(wDstDeviceName).wszwName), addr, mask, gateway);
}
}
}
return 0;
}