Linux环境下的UDP端口扫描程序

Birty

发布日期: 2019-05-04 10:45:23 浏览量: 423
评分:
star star star star star star star star star star_border
*转载请注明来自write-bug.com

一、开发目的

UDP扫描扩展实现

二、系统功能

在命令行模式下实现对连续UDP端口的扫描。

三、系统设计

3.1 系统的组成结构

  • 主函数。函数原型为:

    1. int main(int argc,char \*argv[])

    该函数为主函数,控制整个工具的运行流程

  • 命令行解析函数。函数原型为:

    1. int parse_scanpara(int argc, char *argv[],struct scaninfo_struct *pparse_result)

    该函数被主函数调用,主函数直接将命令行输入以函数参数形式传递给该函数,该函数解析命令行函数,将解析结果保存在参数pparse_result指向的scaninfo_struct的结构体中。

  • UDP扫描函数。该函数原型为:

    1. void udp_scan(struct scaninfo_struct *pscaninfo)

    该函数由主函数调用,以发送UDP报文,捕获分析ICMP报文的的方式来探测被扫描主机的UDP端口的开放情况。

  • UDP探测报文发送函数。该函数原型为:

    1. void send_udp(struct scaninfo_struct *pscaninfo)

    该函数被UDP_SCAN函数调用,向目标主机的目标端口发送UDP探测报文。

  • ICMP响应报文接收函数。该函数原型为:

    1. void *receivethread(void *args)

    该函数完成Libpcap库相关的初始化工作,包括抓包过滤规则的设置等。在接收到一个数据包时主动调用响应报文处理函数packet_handler()。

  • ICMP响应报文处理函数。该函数原型为:

    1. void packet_handler(u_char *args,const struct pcap_pkthdr *header,const u_char *packet)

    该函数根据收到的报文,来判断被扫描的主机的端口是否打开。

  • 扫描结果输出函数。该函数原型为:

    1. void output_scanresult(struct scaninfo_struct scaninfo)

    该函数被主函数调用,用于输出端口扫描结果。

3.2 数据结构

  1. /* 帧头格式 */
  2. struct sniff_ethernet {
  3. u_char ether_dhost[ETHER_ADDR_LEN]; /* 目标MAC地址 */
  4. u_char ether_shost[ETHER_ADDR_LEN]; /* 源MAC地址 */
  5. u_short ether_type; /* 上层协议类型 */
  6. };
  7. /* IP 头格式 */
  8. struct sniff_ip {
  9. u_char ip_vhl; /* 高4位为IP协议版本,低4位为IP头长度 */
  10. u_char ip_tos; /* 服务类型 */
  11. u_short ip_len; /* 长度 */
  12. u_short ip_id; /* 分片标识 */
  13. u_short ip_off; /* 高3位分片标识,低13位为分片偏移量 */
  14. u_char ip_ttl; /* IP报文生存周期 */
  15. u_char ip_p; /* 上层协议类型标识 */
  16. u_short ip_sum; /* 校验和 */
  17. struct in_addr ip_src,ip_dst; /* IP源地址和IP目标地址 */
  18. };
  19. /* ICMP 头格式 */
  20. struct sniff_icmp
  21. {
  22. u_int8_t icmp_type; /* ICMP类型 */
  23. u_int8_t icmp_code; /* ICMP代码 */
  24. u_int16_t icmp_sum; /* 校验和 */
  25. //u_int16_t icmp_id; /* 标识 */
  26. //u_int16_t icmp_seq; /* 序列号 */
  27. };
  28. /* UDP 头格式 */
  29. struct sniff_udp
  30. {
  31. u_int16_t udp_sport; /* 源端口号 */
  32. u_int16_t udp_dport; /* 目的端口号 */
  33. u_int16_t udp_len; /* 长度 */
  34. u_int16_t udp_sum; /* 校验和 */
  35. };
  36. /* 扫描信息结构 */
  37. struct scaninfo_struct{
  38. int scan_type;
  39. char interface[32];
  40. struct in_addr ipaddr;
  41. char ipaddr_string[32];
  42. int startport;
  43. int endport;
  44. int portnum;
  45. pthread_cond_t *cond;
  46. int *portstatus;
  47. int alreadyscan;
  48. };

3.3 关键算法设计

  1. /* UDP探测报文发送函数 */
  2. void send_udp(struct scaninfo_struct *pscaninfo){
  3. int i;
  4. for (i = pscaninfo->startport; i <= pscaninfo->endport; i++)
  5. {
  6. usleep(1000000); //由于Linux系统限制了ICMP目标不可达报文的发送速率,所以应该根据情况控制UDP探测报文的发送速率。
  7. struct sockaddr_in addr;
  8. int sock = socket(AF_INET, SOCK_DGRAM, 0);
  9. if (sock == -1)
  10. {
  11. printf("create socket error! \n");
  12. return ;
  13. }
  14. memset(&addr, 0, sizeof(addr));
  15. addr.sin_family = AF_INET;
  16. addr.sin_port = htons(i);
  17. inet_pton(AF_INET, pscaninfo->ipaddr_string, &addr.sin_addr);
  18. int retval = sendto(sock,NULL,0,0,(const struct sockaddr *)(&addr), sizeof(addr));//UDP报文发送
  19. if (retval<0)
  20. printf("Send message to Host Failed !");
  21. close(sock);
  22. }
  23. }
  24. //ICMP报文处理函数
  25. void packet_handler(u_char *args,const struct pcap_pkthdr *header,const u_char *packet)
  26. {
  27. struct scaninfo_struct *pscaninfo = (struct scaninfo_struct *)args;
  28. const int SIZE_ETHERNET = 14;
  29. const struct sniff_ethernet *ethernet; //帧头指针
  30. const struct sniff_ip *ip; //IP头指针
  31. const struct sniff_icmp *icmp; //ICMP指针
  32. const struct sniff_ip *ipw; //产生差错的报文的IP头指针
  33. const struct sniff_udp *udp; //UDP头指针
  34. u_int size_ip;
  35. u_int size_icmp;
  36. u_int size_ipw;
  37. ethernet = (struct sniff_ethernet *)(packet);
  38. ip = (struct sniff_ip *)(packet + SIZE_ETHERNET);
  39. size_ip = IP_HL(ip) * 4;
  40. if (size_ip < 20) return;
  41. //判断ICMP报文是否为目的不可达差错控制报文
  42. icmp = (struct sniff_icmp *)(packet+SIZE_ETHERNET+size_ip);
  43. if (icmp->icmp_type != 3) return;
  44. ipw = (struct sniff_ip *)(packet+SIZE_ETHERNET+size_ip+8);
  45. size_ipw = IP_HL(ipw) * 4;
  46. if (size_ipw < 20) return;
  47. //获取产生差错的报文的目的IP地址
  48. struct in_addr ip_check = ipw->ip_dst;
  49. //获取目的不可达差错控制报文的UDP首部
  50. udp = (struct sniff_udp *)(packet+SIZE_ETHERNET+size_ip+8+size_ipw);
  51. //获取UDP首部的目的端口号
  52. int dstport = ntohs(udp->udp_dport);
  53. if (ip_check.s_addr == (pscaninfo->ipaddr).s_addr)
  54. {//判断ICMP不可达报文的差错报文的目的IP地址是否与UDP发送报文一致
  55. if (icmp->icmp_code == 3)//判断ICMP报文是否为端口不可达报文
  56. pscaninfo->portstatus[dstport - pscaninfo->startport] = CLOSE;
  57. else
  58. pscaninfo->portstatus[dstport - pscaninfo->startport] = UNKNOWN;
  59. pscaninfo->alreadyscan++;
  60. }
  61. if (pscaninfo->alreadyscan >= pscaninfo->portnum)
  62. pthread_cond_signal(pscaninfo->cond);
  63. }
  64. //ICMP报文捕获线程函数
  65. void *receivethread(void *args)
  66. {
  67. struct scaninfo_struct *pscaninfo = (struct scaninfo_struct *)args;
  68. bpf_u_int32 net;
  69. bpf_u_int32 mask;
  70. char errbuf[PCAP_ERRBUF_SIZE];
  71. pcap_lookupnet(pscaninfo->interface, &net, &mask, errbuf);
  72. pcap_t *handle;
  73. handle = pcap_open_live(pscaninfo->interface, 100, 1, 0, errbuf);
  74. if (handle == NULL)
  75. {
  76. printf("pcap open device failure \n");
  77. return NULL;
  78. }
  79. struct bpf_program fp;
  80. char filter[20] = "icmp"; //过滤函数,只捕获ICMP报文
  81. int retval = 0;
  82. retval = pcap_compile(handle, &fp, filter, 0, net);
  83. if (retval == -1) return NULL;
  84. retval = pcap_setfilter(handle, &fp);
  85. if (retval == -1) return NULL;
  86. pcap_loop(handle, 0, packet_handler, (u_char *)pscaninfo);
  87. return NULL;
  88. }

四、系统实现

系统开发的软硬件环境,系统运行截图(对应于系统的功能)以及关键代码(加注释)

  • 软件环境

    • 系统:Linux(CentOS 6.5)
    • 内核版本:2.6.32-431.11.2.el6.i686
    • gcc编译器版本:gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4)
    • 函数库:libpcap-1.5.3
  • 硬件环境(虚拟机配置)

    • CPU: i686
    • 网卡
      • eth2 encap:Ethernet
      • addr:192.168.174.135
      • Bcast:192.168.174.255
      • Mask:255.255.255.0

运行截图如下

五、总结

由于大三时期的网络课程没有认真学习,这次网络信息安全实验一下问题就出来了。首先的问题就是socket编程不熟悉,在发送UDP探测报文出现了一些错位,其次就是icmp报文的种类和格式不是很清楚,这直接导致我抓包后分析报文的时候分析不出结果。带着这些问题,认真的查阅相关资料,模仿syn扫描和fin扫描的代码,最终还是写出了实验代码,并成功运行。总的来说,这次的实验暴露了我以前的很多问题,也让我收获很大。这次实验的不足之处在于UDP端口扫描的功能太单一了,不支持网段扫描和多线程扫描。而且被扫描主机一般会限制icmp端口不可达报文的发送速率,这也导致我开发的这个UDP端口扫描速度不够快,我目前也还没找到这个问题有效的解决办法。

上传的附件 cloud_download Linux环境下的UDP端口扫描程序.7z ( 55.66kb, 1次下载 )
error_outline 下载需要11点积分

发送私信

只愿岁月静好,别无所求

20
文章数
13
评论数
最近文章
eject