2015-11-07 272 views
0

我繼承了一個C++/Windows項目,其中有一個SNMP擴展代理(由snmp服務加載)。在代理內部,我們正在創建一個簡單的TCP服務器,我們的客戶端應用程序連接到該服務器併爲其提供SNMP查詢/陷阱等數據。這似乎在Windows 2008上運行良好。但是,在Windows 2012上,客戶端無法再運行連接到代理中運行的服務器(在SNMP服務中)。在connect()失敗,錯誤10013.WIndows 2012上的服務中的SOCKET連接問題

我的服務器代碼看起來是這樣的:

fd_set master_set; 
fd_set readfds; 
SOCKET listener; 

WSADATA wsaData; 
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); 
if (iResult != NO_ERROR) 
{ 
    OutputDebugStringA("WSAStartup failed\n"); 
    return -1; 
} 
FD_ZERO(&master_set); 
FD_ZERO(&readfds); 

//---------------------- 
// Create a SOCKET for listening for 
// incoming connection requests. 

listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
if (listener == INVALID_SOCKET) { 
    OutputDebugStringA("socket failed with error:\n"); 
    return -1; 
} 
int reuse_addr = 1; 

setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse_addr, sizeof(reuse_addr)); 
//---------------------- 
// The sockaddr_in structure specifies the address family, 
// IP address, and port for the socket that is being bound. 
sockaddr_in service = { 0 }; 
service.sin_family = AF_INET; 
service.sin_addr.s_addr = inet_addr("127.0.0.1"); 
service.sin_port = htons(27015); 

if (bind(listener, (SOCKADDR *)& service, sizeof(service)) == SOCKET_ERROR) 
{ 
    printf("bind failed with error: %d \n", WSAGetLastError()); 
    closesocket(listener); 
    return -1; 
} 

if (listen(listener, 5) == SOCKET_ERROR) 
{ 
    OutputDebugStringA("listen failed with error\n"); 
    closesocket(listener); 
    return -1; 
} 

u_long NonBlock = 1; 
if (ioctlsocket(listener, FIONBIO, &NonBlock) == SOCKET_ERROR) 
{ 
    OutputDebugStringA("ioctlsocket() failed with error\n"); 
    return -1; 
} 


FD_SET(listener, &master_set); 

timeval timeout; 
timeout.tv_sec = 3; 
timeout.tv_usec = 0; 

printf("Started Server on port %d\n", 27015); 

for (;;) 
{ 
    readfds = master_set; 

int ret = select(0, &readfds, NULL, NULL, &timeout); 

    if (ret == 0) 
    { 
     // Time out // Check if we need to shutdown 

      continue; 
    } 

if (ret < 0) 
    { 
     printf("Error in Socket select\n"); 
     return -1; 
    } 

    for (int i = 0; i < readfds.fd_count; i++) 
    { 
     SOCKET xfd = readfds.fd_array[i]; 

     if (xfd == listener) 
     { 
      // New Connection. 
      SOCKET new_fd = HandleNewConnection(listener); 
      if (new_fd == -1) 
      { 
       printf("Error Accepting new connection"); 
       continue; 
      } 
      FD_SET(new_fd, &master_set); 
      printf("Accepted new Connection\n"); 
      continue; 
     } 
     else 
     { 
      if (!HandleIncomingData(xfd)) 
      { 
       closesocket(xfd); 
       FD_CLR(xfd, &master_set); 
       continue; 
      } 
     } 
    } 
} 

SOCKET HandleNewConnection(SOCKET listener) 
{ 
    SOCKET newfd = accept(listener, (sockaddr*)NULL, (int*)NULL); 
    u_long NonBlock = 1; 
    ioctlsocket(newfd, FIONBIO, &NonBlock); 
    return newfd; 
    } 

    bool HandleIncomingData(SOCKET fd) 
    { 
    char buffer[16] = { 0 }; 
    int recv_bytes = -1; 
    if ((recv_bytes = recv(fd, buffer, 16, 0)) <= 0) 
    { 
    printf("Connection Closed/ Error in Recieving"); 
    return false; 
    } 

    printf("recieved %d bytes\n", recv_bytes); 
    return true; 
} 

的選擇繼續每3秒超時,沒有任何連接被市場接受。

下面是我已經嘗試了所有(無工作):

  1. 試過在一個特定的用戶帳戶運行服務。
  2. 服務器運行在一個單獨的線程中,我提供了一個帶有NULL DACL的SECURITY_ATTRIBUTE來查看它是否是安全問題。
  3. 嘗試了不同的端口。
  4. 在單獨的普通應用程序中嘗試了相同的服務器代碼。客戶端可以連接到這個應用程序。
  5. 從代理啓動時的示例服務器應用程序,客戶端無法連接到它。
  6. Windows防火牆已關閉,我沒有安裝任何防病毒軟件會阻止此類連接。
  7. 從外部檢查連接,並在Wireshark中觀察到TCP SYN包確實到達但沒有響應。
  8. 在Process Explorer中觀察到SNMP服務確實擁有在127.0.0.1:27015上偵聽的TCP套接字的TCP/IP屬性。

對於快速測試我只是做的telnet端口27015.

我的問題是:

  1. 有什麼明顯錯誤與我缺少服務器端的代碼?
  2. 在Windows 2012中是否存在一些不允許服務接受此類TCP連接的安全限制?
  3. 其他提示,評論,輸入?

感謝,

+0

不要直接使用'readfds'結構,使用'FD_ISSET'宏來檢查套接字是否在集合中。另外,不要以這種方式遍歷集合,而應保存連接套接字的列表並僅檢查它們。特別是因爲你實際上沒有*檢查*如果一個套接字有事件,然後試圖處理它們。 –

+0

你考慮過查找Winsock錯誤10013嗎? – EJP

+0

感謝您的意見。是的,我查了10013這是WSAEACCESS:權限被拒絕。 試圖以禁止其訪問權限的方式訪問套接字。一個示例是使用sendto的廣播地址,而不使用setsockopt(SO_BROADCAST)設置廣播權限。 – user1688877

回答

2

我解決了這個問題。這個問題是由於Windows Service Hardening導致的,它不允許來自snmp服務(和擴展)的任何TCP通信。即使防火牆關閉,也會執行此操作。

https://support.microsoft.com/en-us/kb/2771908

+0

你能否詳細說明你是如何解決它的?有沒有辦法禁用強化規則? –

0

我可以解決這個問題按照以下步驟(在http://www-01.ibm.com/support/docview.wss?uid=nas7ba16117761f1f93b86257f73000cff77找到)

  1. 登錄系統管理員和打開註冊表上通過在命令提示符下輸入註冊表編輯器。
  2. 導航到[HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Services \ SharedAccess \ Parameters \ FirewallPolicy \ RestrictedServices \ Static \ System]。
  3. 找到滿足以下幾點的值: a。 「名稱」字符串以「SNMP-」開頭。 b。 「數據」字符串包含「syswow64 \ snmp.exe」。 c。 「數據」字符串包含「Action = Block」。
  4. 將這些條目的「Action = Block」更改爲「Action = Allow」。
  5. 通過發出淨停止MPSSVC和網絡啓動MPSSVC重新啓動「Windows防火牆」服務。
  6. 使用net stop SNMP和net start SNMP重新啓動「SNMP服務」服務。