您的位置:首页 > 其它

端口扫描设计过程(三)

2009-10-19 22:53 183 查看

概述

在上一篇做了对SYN扫描的用户素材分析,得出了扫描过程。而在这一篇中,将使用Jpcap实现。同时在过程化实现中,我们又会发现新的需求,这将改变我们对软件的理解和下一步开发的方式。

适宜读者

本文适于大部分网络编程爱好者,不过我的目的是希望对软件设计和开发方法的任何人都对此文感兴趣,所以本文侧重于对软件的开发方法上的讨论,不过你如果对下面的概念熟悉,将有助于你对本文的理解。
l ARP协议
l 数据的封装和OSI
l Jpcap、Java

实现之路

过程化复习

我们首先回顾一下上一篇提到的主要过程。为了发送SYN包并通过返回响应数据包获得端口状态信息的过程描述如下:

第一步 通过ARP协议获取对方MAC地址
第二步 封装TCP SYN数据包,并发送
第三步 接受响应包并解析相应包,分析得出结论。

详细分析

不难发现,程序需要发送两个包,ARP请求包和TCP SYN请求包。需要接受,ARP回应包和TCP SYN响应包。为了发送或接受数据包肯定需要网卡,在使用网卡之前,肯定先要确定哪个是自己需要的网卡(即使电脑只有一个真实网卡,但可能有很多虚拟网卡)。所以,我们发现了第一个新需求:确定使用的网卡。马上,我们就有个临时的解决方案:选择与目标IP同一子网下的网卡。
参考代码:
public static NetworkInterface getNetWorkInterfaceInSameSubnet(InetAddress ip){
NetworkInterface[] devices=JpcapCaptor.getDeviceList();
NetworkInterface device=null;

loop: for(NetworkInterface d:devices){
for(NetworkInterfaceAddress addr:d.addresses){
if(!(addr.address instanceof Inet4Address)) continue;
byte[] bip=ip.getAddress();
byte[] subnet=addr.subnet.getAddress();
byte[] bif=addr.address.getAddress();
for(int i=0;i<4;i++){
bip[i]=(byte)(bip[i]&subnet[i]);
bif[i]=(byte)(bif[i]&subnet[i]);
}
if(Arrays.equals(bip,bif)){
device=d;
break loop;
}
}
}
return device;
}
对于不在同一子网,但只要是可访问(能够ping通),实现起来并不困难。但对于互联网上的计算机需要接入互联网才能访问,所以这将依赖于接入互联网技术。注意,JPcap所依赖于的WinPcap不支持PPPoE技术,这将让我们大量使用PPPoE接入互联网的方式无法使用完全依赖于WinPcap技术的端口扫描。目前为止,常见的解决方案就是使用系统调用。

性能太差

最简单的方法可以把上述过程全部写在一个方法里。实现方案用表格描述。
方法参数
InetAddress IP ,int Port
方法返回类型
Boolean
方法体
上述三个过程实现
用该方案实现不论性能上还是重用上以及调试上都不利,只有简单性。接下来有必要考虑代码重构。

重构

l 把ARP协议提前
方法中参数有IP和Port,这意味着,对同一个IP会有过多没必要的ARP协议。所以ARP协议有必要在获得目标IP或确认目标IP的主机是开启的情况下执行ARP协议。
l 对于结果,不应该仅是一个Boolean类型,因为端口的状态可能不仅仅是开启或关闭,(可能还有是被过滤的,意味着可能被防火墙处理过而无法确定是不是开启。)对于Java可以考虑使用枚举类型封装结果。
l 应该注意,依据RFC793的规定。类似的扫描技术还可以有FIN、Xmas、Null扫描等。他们与SYN扫描相比仅是封装发送数据包和解析回应数据包的参数上存在微小区别,完全可以考虑重用代码。

实现重构

l 为了提前批量执行ARP协议,我们将需要一个IP地址列表,推荐使用线性表实现(参见Java集合框架中List接口)。执行完ARP协议,用词典返回(参见Java集合框架Map接口)
l 对于结果,我们除了注意应该使用枚举类型存储更多的可能性外,还应该注意。针对不同的扫描方式,会有不同的解析方式。即针对SYN扫描可能,因为回应包返回的SYN/ACK而说明端口是开启的而对返回RST包说明端口是关闭的。而对于Null扫描可能因为回应RST包说明端口是关闭的,而不回应说明端口是开启的(实际上,系统并不一定遵守RFC793)。可以考虑使用策略设计模式来实现代码的可扩展性。
l 对于发送包。并不方便使用策略设计模式。我推荐使用的是分层来实现。即数据链路层、网络层、传输层都在不同的地方针对同一个包来封装。虽然这会加大实现的难度。但可以最大程度的重用代码。而且每一层的封装都可以并行执行。

小结

本篇通过对SYN实现,发现了许多新的需求,需要更多的数据结构和算法,在下一篇将继续讨论SYN扫描实现,而且我们还会发现更多的需求,并提出更多的概念。

讨论

本篇文档提出了一个疑问希望大家的见教。
如何在Windows环境下,以PPPoE接入互联网,不使用系统调用的情况下,实现SYN扫描。

反馈

欢迎大家提供反馈意见,以让文档不断完善,从而使文档自身具有生命力。你可以通过ruyunrufeng126@163.com联系到作者。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: