由于UDP协议是非面向连接的,对UDP端口的探测也就不可能像TCP端口的探测那样依赖于连接建立过程,这也使得UDP端口扫描的可靠性不高。所以虽然UDP协议较之TCP协议显得简单,但是对UDP端口的扫描却是相当困难的。下面具体介绍一下UDP扫描方案:


        方案1:利用ICMP端口不可达报文进行扫描


        本方案的原理是当一个UDP端口接收到一个UDP数据报时,如果它是关闭的,就会给源端发回一个ICMP端口不可达数据报,ICMP协议中的类型字段为3(目的站点不可达)和代码字段为3(表示端口不可达);如果它是开放的,那么就会忽略这个数据报,也就是将它丢弃而不返回任何的信息,这里可以设置超时来进行判断。



        优点:


        可以完成对UDP端口的探测。


        缺点:


        需要系统管理员的权限。扫描结果的可靠性不高。因为当发出一个UDP数据报而没有收到任何的应答时,有可能因为这个UDP端口是开放的,也有可能是因为这个数据报在传输过程中丢失了。另外,扫描的速度很慢。原因是在RFC1812的中对ICMP错误报文的生成速度做出了限制。例如Linux就将ICMP报文的生成速度限制为每4秒钟80个,当超出这个限制的时候,还要暂停1/4秒。   


  


 Again)”;如果系统收到了ICMP的错误报文则通常会返回一个ECONNREFUSED错误,错误类型码111,含义是“连接被拒绝(Connect  


        优点:


        不需要系统管理员的权限。


        缺点:


        除去解决了权限的问题外,其他问题依然存在。




实现代码:


#include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <sys/time.h>
 #include <netinet/in_systm.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
 #include <netinet/ip_icmp.h>
 #include <arpa/inet.h>
 #include <netdb.h>
 #include <unistd.h>
 #include <strings.h>
 #include <errno.h>


 #define MAXPACKET 4096
 #define DEFAULT_TIMEOUT 10
 #define DEFAULT_RESEND 6


 void start_scanning(const char* ipaddress,unsigned short port)
 {
 unsigned int timeout=4, maxretry=3;
 struct sockaddr_in myudp;
 int udpsock, rawsock, retry, retval,iplen;
 fd_set r;
 struct timeval mytimeout;
 struct icmp *packet;
 struct ip *iphdr;
 struct servent *service;
 unsigned char recvbuff[MAXPACKET];




 if((udpsock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP)) < 0)
 {
 perror("socket()");
 exit(-1);
 }


 if((rawsock = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP)) < 0)
 {
 perror("socket()");
 exit(-1);
 }
 mytimeout.tv_sec = timeout;
 mytimeout.tv_usec = 0;
 retry = 0;


 myudp.sin_addr.s_addr = inet_addr(ipaddress);
 myudp.sin_family = AF_INET;
 myudp.sin_port = htons(port);


 while(retry++ < maxretry)
 {
 FD_ZERO(&r);
 FD_SET(rawsock,&r);
 if((sendto(udpsock,"  ",2,0,(struct sockaddr *)&myudp,sizeof(myudp))) < 0)
 {
 perror("sendto");
 exit(-1);
 }
 retval = select((rawsock+1),&r,NULL,NULL,&mytimeout);
 if(retval ==1)
 {//some data reach
 if((recvfrom(rawsock,recvbuff,sizeof(recvbuff),0x0,NULL,NULL)) < 0)
 {
 perror("Recv");
 exit(-1);
 }
 iphdr = (struct ip *)recvbuff;
 iplen = iphdr->ip_hl * 4;
 packet = (struct icmp *)(recvbuff + iplen);
 printf("the icmp type is=%d, code=%d \n",packet->icmp_type,packet->icmp_code);
 if((packet->icmp_type == ICMP_UNREACH) && (packet->icmp_code == ICMP_UNREACH_PORT))
 break;
 } //end if(retval ==1)
 else if(retval ==0)
 {
 printf("time out! the port may be availed !\n");
 continue;
 }
 else
 {
 printf("occur some errors! scan udp failed !\n");
 return ;
 }
 } //end while(1)


 if(retry >= maxretry)
 {
 if((service = getservbyport(htons(port),"udp")) == NULL)
 fprintf(stdout,"Unknown port %u, open.\n",port);
 else
 fprintf(stdout,"UDP service %s open.\n",service->s_name);
 fflush(stdout);
 }
 else
 {
 printf("the port:%d is unavailable!\n",port);
 }


 }


 int main(int argc,char **argv)
 {
 start_scanning("192.168.2.1",27015);
 printf("scan over\n");
 return 0;




 }