UDP端口可达性检测(端口扫描)工具开发
1、应用场景分析
主机X与主机Y摆设在AB双网环境下,两个主机间通过UDP协议进行数据交互。应用步伐发送数据时,优先使用A网发送数据,如果A网非常则通过B网发送数据。两个主机应用间没有设置心跳帧 ,所以无法检测到对方UDP端口是否可达。
场景诉求
主机间发送UDP数据前,应能检测对方端口是否可达。如果不可达,则进行A/B网切换。达到动态检测对方网络服务端口状态,及时切换网络链路结果。
①、 主机不可达
场景分析:
- 主构造机。
- 防火墙开启计谋。
- 网卡故障、网线连接非常。
- 网络设置错误。
场景应对计谋:
通过PING echo 判断主机是否可达。
②、 端口不可达
主机可达,端口不可达。
场景分析:
场景应对计谋:
结合ICMP和内核网络协议栈,判断UDP端口是否可达。
2、UDP端口扫描步伐开发
①、Windows步伐
【1】、 理论知识
略。
【2】、 C++源码
界面控件设计。

对话框初始化部分代码。
- BOOL CUdpDetectDlg::OnInitDialog()
- {
- CDialogEx::OnInitDialog();
- // 将“关于...”菜单项添加到系统菜单中。
- // IDM_ABOUTBOX 必须在系统命令范围内。
- ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
- ASSERT(IDM_ABOUTBOX < 0xF000);
- CMenu* pSysMenu = GetSystemMenu(FALSE);
- if (pSysMenu != NULL)
- {
- BOOL bNameValid;
- CString strAboutMenu;
- bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
- ASSERT(bNameValid);
- if (!strAboutMenu.IsEmpty())
- {
- pSysMenu->AppendMenu(MF_SEPARATOR);
- pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
- }
- }
- // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
- // 执行此操作
- SetIcon(m_hIcon, TRUE); // 设置大图标
- SetIcon(m_hIcon, FALSE); // 设置小图标
- // 初始化Windows套接字
- WSADATA wsaData;
- if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
- {
- CString strMsg;
- strMsg.Format("WSAStartup失败!");
- return 0;
- }
- // CListCtrl
- DWORD dwStyle = m_ListCtrl.GetExtendedStyle();
- m_ListCtrl.SetExtendedStyle(dwStyle | LVS_EX_FULLROWSELECT );
- m_ListCtrl.InsertColumn(0, _T("主机端口"), LVCFMT_LEFT, 130);
- m_ListCtrl.InsertColumn(1, _T("扫描结果"), LVCFMT_LEFT, 100);
- m_ListCtrl.InsertColumn(2, _T("ICMP反馈"), LVCFMT_LEFT, 350);
- // 默认参数;
- m_EditScanHostIP.SetWindowText("192.168.58.1");
- m_EditScanPortStartNo.SetWindowText("50000");
- m_EditScanEndPortNo.SetWindowText("50005");
- return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
- }
复制代码 端口扫描部分代码。
- //扫描端口;
- void CUdpDetectDlg::ScanPort()
- {
- CString strScanHost;
- m_EditScanHostIP.GetWindowText(strScanHost);
- CString strScanStartPort;
- m_EditScanPortStartNo.GetWindowText(strScanStartPort);
- CString strScanEndPort;
- m_EditScanEndPortNo.GetWindowText(strScanEndPort);
- int iStartPort = _ttoi(strScanStartPort);
- int iEndPort = _ttoi(strScanEndPort);
- if (iEndPort < iStartPort) return;
- m_ListCtrl.DeleteAllItems();
- for (int ii = iStartPort; ii <= iEndPort;++ii)
- {
- BOOL isPortOpenF = FALSE;
- char szErrText[256] = { 0 };
- sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (sock < 0) return;
- //设置收发缓冲区大小;
- int iTemp = 1024 * 2;
- setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&iTemp, sizeof(iTemp));
- setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&iTemp, sizeof(iTemp));
- //设置接收超时;
- int iRecvTimeout = 1000;
- setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&iRecvTimeout, sizeof(iRecvTimeout));
- struct sockaddr_in txaddr;
- txaddr.sin_family = AF_INET;
- txaddr.sin_addr.s_addr = inet_addr(strScanHost.GetBuffer(0));
- txaddr.sin_port = htons(ii);
- int addrlen = sizeof(txaddr);
- char txbuff[] = "";
- int txlen = sendto(sock, txbuff, sizeof(txbuff), 0, (sockaddr*)&txaddr, addrlen);
- char rxbuff[24] = { 0 };
- int rxlen = recvfrom(sock, rxbuff, 24, 0, (sockaddr*)&txaddr, &addrlen);
- if (rxlen < 0)
- {
- if (WSAGetLastError() == WSAECONNRESET)
- {
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, WSAECONNRESET, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),szErrText, 256, NULL);
- isPortOpenF = FALSE;
- }
- else
- isPortOpenF = TRUE;
- }
- CString strHostDesc;
- strHostDesc.Format("%s:%d", strScanHost, ii);
- CString strPortState;
- if (isPortOpenF)
- strPortState.Format("端口可达");
- else
- strPortState.Format("端口不可达");
- int iIndex = m_ListCtrl.GetItemCount();
- m_ListCtrl.InsertItem(iIndex, strHostDesc);
- m_ListCtrl.SetItemText(iIndex, 1, strPortState);
- m_ListCtrl.SetItemText(iIndex, 2, CString(szErrText));
- closesocket(sock);
- }
- }
复制代码 【3】、 编译步伐
【4】、 运行步伐
先将目标主机的50001端口开启监听。然后用测试步伐检测。
开始扫描端口。
②、 Linux步伐
【1】、 理论知识
略。
【2】、 C++源码
UdpScan.cxx
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <errno.h>
- #include <string>
- #include<algorithm>
- int main()
- {
- printf("*********************************************************************\n");
- printf("* *\n");
- printf("* Linux 端口扫描工具 V0.1 *\n");
- printf("* *\n");
- printf("*********************************************************************\n");
-
- printf("请输入扫描主机IP地址: ");
- char input[256] = {0};
- char* ptr = fgets(input,256,stdin);
- if(ptr == nullptr) { printf("输入参数异常,结束程序!\n"); }
- std::string strHost = std::string(ptr);
-
- printf("请输入扫描UDP端口范围(比如2000-2500): ");
- ptr = fgets(input,256,stdin);
- if(ptr == nullptr) { printf("输入参数异常,结束程序!\n"); }
- std::string strPort = std::string(ptr);
-
- int iStartPort = 0, iEndPort = 0;
- int pos = strPort.find("-");
- if(pos != std::string::npos)
- {
- std::string strStartPort = strPort.substr(0,pos);
- std::string strEndPort = strPort.substr(pos+1);
-
- iStartPort = std::stoi(strStartPort);
- iEndPort = std::stoi(strEndPort);
- }
-
- if(iEndPort < iStartPort) return 1;
-
- for(int ii = iStartPort; ii <= iEndPort; ++ ii)
- {
- int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-
- //将ICMP端口不可达信息报到应用层协议
- int flag = 1;
- setsockopt(sock, IPPROTO_IP, IP_RECVERR , &flag,sizeof(int));
-
- //设置接收超时
- struct timeval timeout = {0,300};
- setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval));
-
- struct sockaddr_in addr;
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = inet_addr(strHost.c_str());
- addr.sin_port = htons(ii);
-
- char txbuff[] = "";
- int ret = sendto(sock,txbuff,sizeof(txbuff),0,(struct sockaddr*)&addr,sizeof(addr));
-
- char rxbuff[24] = { 0 };
- int addrlen = sizeof(addr);
- int rxlen = recvfrom(sock, rxbuff, sizeof(rxbuff), 0, (struct sockaddr *)&addr, &addrlen);
- if (rxlen == -1)
- {
- //剔除回车符
- strHost.erase(std::remove(strHost.begin(), strHost.end(), '\n'), strHost.end());
-
- if (errno == ECONNREFUSED)
- {
- printf("主机【%s:%d】端口不可达!\n",strHost.c_str(),ii);
- }
- else
- printf("主机【%s:%d】端口可达!\n",strHost.c_str(),ii);
- }
-
- close(sock);
- }
- printf("端口扫描结束!\n");
-
- return 0;
- }
复制代码 代码截图:


【3】、 编译步伐
- g++ -o udpscan UdpScan.cxx -fpermissive -std=c++11 -w -W
复制代码 【4】、 运行步伐
先将目标主机的50001端口开启监听。然后用测试步伐检测。
开始扫描端口。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |