2015-11-07 270 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服务”服务。