UDP端口可达性检测(端口扫描)工具开发

打印 上一主题 下一主题

主题 1070|帖子 1070|积分 3220

UDP端口可达性检测(端口扫描)工具开发

1、应用场景分析

主机X主机Y摆设在AB双网环境下,两个主机间通过UDP协议进行数据交互。应用步伐发送数据时,优先使用A网发送数据,如果A网非常则通过B网发送数据。两个主机应用间没有设置心跳帧 ,所以无法检测到对方UDP端口是否可达。

场景诉求
主机间发送UDP数据前,应能检测对方端口是否可达。如果不可达,则进行A/B网切换。达到动态检测对方网络服务端口状态,及时切换网络链路结果。
①、 主机不可达

场景分析:


  • 主构造机。
  • 防火墙开启计谋。
  • 网卡故障、网线连接非常。
  • 网络设置错误。
场景应对计谋:
通过PING echo 判断主机是否可达。
②、 端口不可达

主机可达,端口不可达。
场景分析:


  • 服务未启动,端口未监听。
  • 防火墙开启计谋。
场景应对计谋:
结合ICMP和内核网络协议栈,判断UDP端口是否可达。
2、UDP端口扫描步伐开发

①、Windows步伐

【1】、 理论知识

略。
【2】、 C++源码

界面控件设计。

对话框初始化部分代码。
  1. BOOL CUdpDetectDlg::OnInitDialog()
  2. {
  3.         CDialogEx::OnInitDialog();
  4.         // 将“关于...”菜单项添加到系统菜单中。
  5.         // IDM_ABOUTBOX 必须在系统命令范围内。
  6.         ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
  7.         ASSERT(IDM_ABOUTBOX < 0xF000);
  8.         CMenu* pSysMenu = GetSystemMenu(FALSE);
  9.         if (pSysMenu != NULL)
  10.         {
  11.                 BOOL bNameValid;
  12.                 CString strAboutMenu;
  13.                 bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
  14.                 ASSERT(bNameValid);
  15.                 if (!strAboutMenu.IsEmpty())
  16.                 {
  17.                         pSysMenu->AppendMenu(MF_SEPARATOR);
  18.                         pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
  19.                 }
  20.         }
  21.         // 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
  22.         //  执行此操作
  23.         SetIcon(m_hIcon, TRUE);                        // 设置大图标
  24.         SetIcon(m_hIcon, FALSE);                // 设置小图标
  25.         // 初始化Windows套接字
  26.         WSADATA wsaData;
  27.         if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
  28.         {
  29.                 CString strMsg;
  30.                 strMsg.Format("WSAStartup失败!");
  31.                 return 0;
  32.         }
  33.         // CListCtrl
  34.         DWORD dwStyle = m_ListCtrl.GetExtendedStyle();
  35.         m_ListCtrl.SetExtendedStyle(dwStyle | LVS_EX_FULLROWSELECT );
  36.         m_ListCtrl.InsertColumn(0, _T("主机端口"), LVCFMT_LEFT, 130);
  37.         m_ListCtrl.InsertColumn(1, _T("扫描结果"), LVCFMT_LEFT, 100);
  38.         m_ListCtrl.InsertColumn(2, _T("ICMP反馈"), LVCFMT_LEFT, 350);
  39.         // 默认参数;
  40.         m_EditScanHostIP.SetWindowText("192.168.58.1");
  41.         m_EditScanPortStartNo.SetWindowText("50000");
  42.         m_EditScanEndPortNo.SetWindowText("50005");
  43.         return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
  44. }
复制代码
端口扫描部分代码。
  1. //扫描端口;
  2. void CUdpDetectDlg::ScanPort()
  3. {
  4.         CString strScanHost;
  5.         m_EditScanHostIP.GetWindowText(strScanHost);
  6.         CString strScanStartPort;
  7.         m_EditScanPortStartNo.GetWindowText(strScanStartPort);
  8.         CString strScanEndPort;
  9.         m_EditScanEndPortNo.GetWindowText(strScanEndPort);
  10.         int iStartPort = _ttoi(strScanStartPort);
  11.         int iEndPort = _ttoi(strScanEndPort);
  12.         if (iEndPort < iStartPort)  return;
  13.         m_ListCtrl.DeleteAllItems();
  14.         for (int ii = iStartPort; ii <= iEndPort;++ii)
  15.         {
  16.                 BOOL isPortOpenF = FALSE;
  17.                 char szErrText[256] = { 0 };
  18.                 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  19.                 if (sock < 0) return;
  20.                 //设置收发缓冲区大小;
  21.                 int iTemp = 1024 * 2;
  22.                 setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&iTemp, sizeof(iTemp));
  23.                 setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&iTemp, sizeof(iTemp));
  24.                 //设置接收超时;
  25.                 int iRecvTimeout = 1000;
  26.                 setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&iRecvTimeout, sizeof(iRecvTimeout));
  27.                 struct sockaddr_in txaddr;
  28.                 txaddr.sin_family = AF_INET;
  29.                 txaddr.sin_addr.s_addr = inet_addr(strScanHost.GetBuffer(0));
  30.                 txaddr.sin_port = htons(ii);
  31.                 int addrlen = sizeof(txaddr);
  32.                 char txbuff[] = "";
  33.                 int txlen = sendto(sock, txbuff, sizeof(txbuff), 0, (sockaddr*)&txaddr, addrlen);
  34.                 char rxbuff[24] = { 0 };
  35.                 int rxlen = recvfrom(sock, rxbuff, 24, 0, (sockaddr*)&txaddr, &addrlen);
  36.                 if (rxlen < 0)
  37.                 {
  38.                         if (WSAGetLastError() == WSAECONNRESET)
  39.                         {
  40.                                 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  41.                                         NULL, WSAECONNRESET, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),szErrText, 256, NULL);
  42.                                 isPortOpenF = FALSE;
  43.                         }
  44.                         else
  45.                                 isPortOpenF = TRUE;
  46.                 }
  47.                 CString strHostDesc;
  48.                 strHostDesc.Format("%s:%d", strScanHost, ii);
  49.                 CString strPortState;
  50.                 if (isPortOpenF)
  51.                         strPortState.Format("端口可达");
  52.                 else
  53.                         strPortState.Format("端口不可达");
  54.                 int iIndex = m_ListCtrl.GetItemCount();
  55.             m_ListCtrl.InsertItem(iIndex, strHostDesc);
  56.                 m_ListCtrl.SetItemText(iIndex, 1, strPortState);
  57.                 m_ListCtrl.SetItemText(iIndex, 2, CString(szErrText));
  58.                 closesocket(sock);
  59.         }
  60. }
复制代码
【3】、 编译步伐


【4】、 运行步伐

先将目标主机的50001端口开启监听。然后用测试步伐检测。

开始扫描端口。

②、 Linux步伐

【1】、 理论知识

略。
【2】、 C++源码

UdpScan.cxx
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <sys/socket.h>
  5. #include <netinet/in.h>
  6. #include <arpa/inet.h>
  7. #include <errno.h>
  8. #include <string>
  9. #include<algorithm>
  10. int main()
  11. {
  12.     printf("*********************************************************************\n");
  13.     printf("*                                                                   *\n");
  14.     printf("*                      Linux 端口扫描工具 V0.1                       *\n");
  15.     printf("*                                                                   *\n");
  16.     printf("*********************************************************************\n");
  17.    
  18.     printf("请输入扫描主机IP地址: ");
  19.     char input[256] = {0};
  20.     char* ptr = fgets(input,256,stdin);
  21.     if(ptr == nullptr) { printf("输入参数异常,结束程序!\n"); }
  22.     std::string strHost = std::string(ptr);
  23.    
  24.     printf("请输入扫描UDP端口范围(比如2000-2500): ");
  25.     ptr = fgets(input,256,stdin);
  26.     if(ptr == nullptr) { printf("输入参数异常,结束程序!\n"); }
  27.     std::string strPort = std::string(ptr);
  28.    
  29.     int iStartPort = 0, iEndPort = 0;
  30.     int pos = strPort.find("-");
  31.     if(pos != std::string::npos)
  32.     {
  33.         std::string strStartPort = strPort.substr(0,pos);
  34.         std::string strEndPort = strPort.substr(pos+1);
  35.         
  36.         iStartPort = std::stoi(strStartPort);
  37.         iEndPort = std::stoi(strEndPort);
  38.     }
  39.      
  40.     if(iEndPort < iStartPort) return 1;
  41.    
  42.     for(int ii = iStartPort; ii <= iEndPort; ++ ii)
  43.     {   
  44.         int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  45.    
  46.         //将ICMP端口不可达信息报到应用层协议
  47.         int flag = 1;
  48.         setsockopt(sock, IPPROTO_IP, IP_RECVERR , &flag,sizeof(int));
  49.         
  50.         //设置接收超时
  51.         struct timeval timeout = {0,300};
  52.         setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval));
  53.         
  54.         struct sockaddr_in addr;
  55.             addr.sin_family = AF_INET;
  56.             addr.sin_addr.s_addr = inet_addr(strHost.c_str());
  57.             addr.sin_port = htons(ii);
  58.         
  59.          char txbuff[] = "";
  60.          int ret = sendto(sock,txbuff,sizeof(txbuff),0,(struct sockaddr*)&addr,sizeof(addr));
  61.    
  62.          char rxbuff[24] = { 0 };
  63.          int addrlen = sizeof(addr);
  64.          int rxlen = recvfrom(sock, rxbuff, sizeof(rxbuff), 0, (struct sockaddr *)&addr, &addrlen);
  65.          if (rxlen == -1)
  66.          {
  67.              //剔除回车符
  68.              strHost.erase(std::remove(strHost.begin(), strHost.end(), '\n'), strHost.end());
  69.             
  70.                  if (errno == ECONNREFUSED)
  71.                  {
  72.                       printf("主机【%s:%d】端口不可达!\n",strHost.c_str(),ii);
  73.                  }
  74.              else
  75.                   printf("主机【%s:%d】端口可达!\n",strHost.c_str(),ii);
  76.          }
  77.         
  78.          close(sock);
  79.     }
  80.     printf("端口扫描结束!\n");
  81.    
  82.     return 0;
  83. }
复制代码
代码截图:


【3】、 编译步伐

  1. g++ -o udpscan UdpScan.cxx -fpermissive -std=c++11 -w -W
复制代码
【4】、 运行步伐

先将目标主机的50001端口开启监听。然后用测试步伐检测。

开始扫描端口。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

宁睿

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表