我用VC6.0编写了一个端口扫描的客户端程序,在运行之后碰到如下问题:
扫描程序很好地判断出指定tcp端口的开启状态,但扫描指定且已开启的udp端口时,给出的结果却是该端口已关闭.
请高手们帮帮忙,看看是否是recvfrom函数有问题??消息处理函数的主要代码如下: void CPortScannerClientDlg::OnButscan()
{
UpdateData();
AfxSocketInit(); //初始化套接字
char buffer[500+1];
//tcp 端口扫描
if(m_combo.GetCurSel()==0)
{
memset(buffer,0,500+1);
if (m_socket.Create(0,SOCK_STREAM,"192.168.0.226"))
{
DWORD RemotePort=m_port;
if(m_socket.Connect(m_host,RemotePort))
{
m_list.AddString("the target port is open!");
m_list.AddString("you can communicate with servernow!");
m_socket.Close();
}
else
{
m_list.AddString("sorry,the target port is close now!");
m_socket.Close();
}
}
}
//udp 端口扫描
else
{
memset(buffer,0,500+1);
if(m_socket.Create(0,SOCK_DGRAM,"192.168.0.226"))
{
DWORD RemotePort = m_port;
int i=2;
while(i>0)
{
int len=sizeof(m_host);
int ret=recvfrom(m_socket,buffer,sizeof(buffer),0,
(struct sockaddr*)&m_host,&len);
if(ret==SOCKET_ERROR)
{
i--;
m_list.AddString("sorry,the target port is
closed!");
}
else
{
m_list.AddString("the target port is open!");
m_list.AddString("you can communicate now.");
break;
}
}
m_socket.Close();
}
}
}
扫描程序很好地判断出指定tcp端口的开启状态,但扫描指定且已开启的udp端口时,给出的结果却是该端口已关闭.
请高手们帮帮忙,看看是否是recvfrom函数有问题??消息处理函数的主要代码如下: void CPortScannerClientDlg::OnButscan()
{
UpdateData();
AfxSocketInit(); //初始化套接字
char buffer[500+1];
//tcp 端口扫描
if(m_combo.GetCurSel()==0)
{
memset(buffer,0,500+1);
if (m_socket.Create(0,SOCK_STREAM,"192.168.0.226"))
{
DWORD RemotePort=m_port;
if(m_socket.Connect(m_host,RemotePort))
{
m_list.AddString("the target port is open!");
m_list.AddString("you can communicate with servernow!");
m_socket.Close();
}
else
{
m_list.AddString("sorry,the target port is close now!");
m_socket.Close();
}
}
}
//udp 端口扫描
else
{
memset(buffer,0,500+1);
if(m_socket.Create(0,SOCK_DGRAM,"192.168.0.226"))
{
DWORD RemotePort = m_port;
int i=2;
while(i>0)
{
int len=sizeof(m_host);
int ret=recvfrom(m_socket,buffer,sizeof(buffer),0,
(struct sockaddr*)&m_host,&len);
if(ret==SOCKET_ERROR)
{
i--;
m_list.AddString("sorry,the target port is
closed!");
}
else
{
m_list.AddString("the target port is open!");
m_list.AddString("you can communicate now.");
break;
}
}
m_socket.Close();
}
}
}
解决方案 »
- 啊啊 散分啊------
- MFC如何连接打印机
- VC++ 6.0工作空间问题
- 为什么在vista上用RegQueryValueEx去获取HKEY_PERFORMANCE_DATA的键值得不到???
- LoadIcon(filename)出错
- Visual C++和vc++有什么区别?
- 这有个GB到Big5转换的程序,有没有人能够写一个Big5到GB的转换程序,谢谢啦!
- 点击dialog上titlebar的最小化按钮之后,在windows任务栏上点击它,此程序返回原先状态
- 请大家帮帮忙!
- 请教大家,下载的.net如何安装。
- 100分提问:AVISaveV函数里面路径文件名称如果包含中文字符就会报错
- MFC 中 有关去除字符串中包含的所有回车符和换行符的问题
由于udp是无连接的协议,不能根据 “握手” 来判定连接是否建立,只能向目的端口发送数据,然后recvfrom,从recvfrom地返回值判断是否调用WSAGetLasstError()来判断 "icmp端口不可达到"错误,和traceroute程序的原理差不多。 所以,你的程序需要该两个地方
1.m_socket.Create(0,SOCK_DGRAM,"192.168.0.226")成功后需要调用一下,connect函数,因为只有在已经连接的udp套接字上才会,返回icmp异步错误;
2.首先调用一下sendto函数,然后再调用recvform
使用UDP协议时,由于打开的端口对扫描探测并不发送一个确认,关闭的端口也并不需要发送一个错误数据包。但是许多主机在你向一个未打开的UDP端口发送一个数据包时,会返回一个ICMP_PORT_UNREACH错误。这样你就能发现哪个端口是关闭的。UDP和ICMP错误都不保证能到达,因此这种扫描器必须还实现在一个包看上去是丢失的时候能重新传输。这种扫描方法是很慢的,因为RFC对ICMP错误消息的产生速率做了规定。同样,这种扫描方法需要具有root权限。UDP recvfrom()和write() 扫描
当非root用户不能直接读到端口不能到达错误时,Linux能间接地在它们到达时通知用户。比如,对一个关闭的端口的第二个write()调用将失败。在非阻塞的UDP套接字上调用recvfrom()时,如果ICMP出错还没有到达时回返回EAGAIN-重试。如果ICMP到达时,返回ECONNREFUSED-连接被拒绝。这就是用来查看端口是否打开的技术。
谢谢"Aaron_Jerry(音乐诗人)"的提示,
异常感谢"anjuta_c()"的指点!按照"anjuta_c()"的提示,我做了修改,不过我不知道ICMP_PORT_UNREACH在什么文件中被定义,刚才运行的时候,编译器提示说"error C2065: 'ICMP_PORT_UNREACH' : undeclared identifier
Error executing cl.exe."
请问要包含什么文件?
1.建立一个已连接的 udp socket(对未连接的udp socket,udp协议栈不会返回ip层返回过来的icmp unreachable消息);
然后send一些数据,当然也可以是0字节数据,如果send 0个字节,就代表底层生成了一个 ip头部(20字节)+udp头部(8字节)+没有数据的ip数据报。
然后recv数据,recv函数需要设置一下超时; # 如果recv返回错误,并且原因是超时,有三种可能
1.该udp端口在监听
2.该udp端口被防火墙拦截(测试tcp端口有同样的情况,如果防火墙存在就不能确定端口是否存活)
3.目标机器返回过来的icmp unreachable包丢失(这种情况比较小)
上边的第3种情况,都可以判断为该端口在监听,第3种情况可以用重发一次数据报或多次数据报来解决 # 如果recv返回错误,在xp_sp2下错误代码是 WSAECONNRESET=10054,就是连接被重置;
在linux|unix下返回的错误代码是ECONNREFUSED,就是连接被拒绝的意思;这种情况就代表该udp端口没有被系统打开。
2.就是直接使用raw socket,比较复杂,就不说了:);
在linux|unix下返回的错误代码是ECONNREFUSED,就是连接被拒绝的意思;这种情况就代表该udp端口没有被系统打开。在这种情况下,如果打开wireshark捕获一下系统ip包,就可以看到目标系统返回来了icmp unreachabled包,不同的操作系统可能会把这个icmp unreachabled映射成不同错误代码
{
WSADATA wsd;
sockaddr_in servaddr;
SOCKET s;
int error;
int itimeout=1000;//接受超时,1秒
int ret;
char sendbuf[5]={0};
char recvbuf[1024]={0}; if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
{
printf("WSAStartup failed!\n");
return 1;
} s = socket(AF_INET, SOCK_DGRAM, 0);
if (s == INVALID_SOCKET)
{
printf("socket() failed; %d\n", WSAGetLastError());
return 1;
}
setsockopt(s,SOL_SOCKET,SO_RCVTIMEO,(char*)&itimeout,sizeof(itimeout)); memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(53); if ((servaddr.sin_addr.s_addr = inet_addr("192.168.2.99"))
== INADDR_NONE)
{
struct hostent *host=NULL; host = gethostbyname("192.168.2.99");
if (host)
CopyMemory(&servaddr.sin_addr, host->h_addr_list[0],
host->h_length);
else
{
printf("gethostbyname() failed: %d\n", WSAGetLastError());
WSACleanup();
return 1;
}
} if (connect(s, (SOCKADDR *)&servaddr, sizeof(servaddr)) == SOCKET_ERROR)
{
printf("connect() failed: %d\n", WSAGetLastError());
WSACleanup();
return 1;
} ret = send(s,sendbuf, 0, 0);
if (ret == SOCKET_ERROR)
{
printf("send() failed: %d\n", WSAGetLastError());
}
else if (ret == 0)
printf("send() successful!\n"); ret = recv(s,recvbuf,1024,0);
if (ret == SOCKET_ERROR)
{
error = WSAGetLastError();
if (error == WSAETIMEDOUT)
printf("recv() failed timeout dst port is active!\n");
else if (error == WSAECONNRESET)
printf("recv() failed icmp unreachabled\n");
else
printf("recv() unknow error\n");
} return 0;
}
谢谢!!