本来是想找一下ACE的Proactor框架下异步连接类ACE_Asynch_Connect用法的,无意中google到了一个外国同行通过ACE_Asynch_Connect写的端口扫描器。原文地址
原理很简单,在Proactor框架下通过异步连接的方式对要扫描的端口进行连接,从而查看端口的状态。
和一些已有的端口扫描的方法比起来,这种方法不十分成熟,但简单易用,效率也还不错(我用这种方式扫描了一下本机的1024个端口,可以在几秒钟内完成)。对于ACE的Proactor框架的学习也有一定的帮助,这里就将其记录下来。
代码如下:
#include
<ace/Log_Msg.h> #include
<ace/INET_Addr.h> #include
<ace/OS.h> #include
<ace/Proactor.h> #include
<ace/WIN32_Proactor.h>
class PortScanner : public ACE_Handler { public:
PortScanner() { }
int open(ACE_Proactor& proactor, const ACE_INET_Addr& remote_addr) { this->proactor(&proactor); this->remote_addr_.set(remote_addr);
if (connect_.open(*this, ACE_INVALID_HANDLE, 0, this->proactor()) < 0) { return -1; }
return connect_.connect(ACE_INVALID_HANDLE, remote_addr_, ACE_Addr::sap_any, 1); }
void handle_connect(const ACE_Asynch_Connect::Result &result) { //This handler will be called if connection is established or RST is received, //You may no get any response in a timely manner even if there is no firewall.
ACE_ASSERT(result.connect_handle () != ACE_INVALID_HANDLE);
if (result.success()) { //Connection is established ACE_DEBUG((LM_NOTICE, "%s:%d is open\n", remote_addr_.get_host_addr(), remote_addr_.get_port_number())); } else { //Got a RST //ACE_DEBUG((LM_NOTICE, "%s:%d is not open\n", // remote_addr_.get_host_addr(), // remote_addr_.get_port_number())); } }
private: ACE_INET_Addr remote_addr_; ACE_Asynch_Connect connect_; };
int ACE_TMAIN(int
/*argc*/, ACE_TCHAR** /*argv*/) { ACE_Proactor proactor; ACE_INET_Addr scan_target("127.0.0.1:0");
//Asynchronous connection are simulated on Both Windows and Unix //(C++NP v2 page 283, sidebar 57 is inaccurate). //Since ACE_Select_reactor is used internally, the handles limit //applies. You can either increase the limit(1024 by default), or //simply do not register too much handles simultaneously. unsigned
short start_port = 1; unsigned
short end_port = 1024;
ACE_ASSERT(end_port > start_port); const size_t size = end_port - start_port + 1;
//'size' is not const expression so we can not create the array on stack PortScanner* portscanners = new PortScanner[size];
for (unsigned
short i = start_port; i < end_port; ++i) { scan_target.set_port_number(i); portscanners[i].open(proactor, scan_target); }
//Run event loop for 10 seconds ACE_DEBUG((LM_NOTICE, ACE_TEXT("Portscan started\n"))); ACE_Time_Value timeout(10); proactor.proactor_run_event_loop(timeout);
//delete[] portscanners; ACE_DEBUG((LM_NOTICE, ACE_TEXT("Portscan ended\n")));
ACE_OS::sleep(10); return 0; } |
我用C#也实现了一个,和前面的ACE版本比起来,代码显得更为简洁。
using System; using System.Collections.Generic; using System.Text;
using System.Net; using System.Net.Sockets;
namespace ConsoleApplication1 { class Program { static
void Main(string[] args) { for (int i = 0; i < 1024; i++) { PortScann portscan = new PortScann(new IPEndPoint(IPAddress.Loopback, i)); }
//等待异步调用完成 System.Threading.Thread.Sleep(-1); } }
class PortScann { IPEndPoint remoteAdd; TcpClient client = new TcpClient();
public PortScann(IPEndPoint remoteAdd) { this.remoteAdd = remoteAdd; client.BeginConnect(remoteAdd.Address, remoteAdd.Port, ConnectCallBack, null); }
void ConnectCallBack(IAsyncResult ar) { if (client.Connected) { Console.WriteLine("{0} connected", remoteAdd); client.EndConnect(ar); client.GetStream().Close(); } else { //Console.WriteLine("{0} connect fail", remoteAdd); } } } } |