沒有辦法, 不得不做啊, 還得靠這個(gè)東西混學(xué)分呢。
老師給的例子是用VC寫的, 說心里話, 俺對(duì)VC不感興趣, 所以就想用Java來實(shí)現(xiàn)。
但是java是無法直接訪問raw socket的, 所以如果要實(shí)現(xiàn)sniffer的功能的話, 只能通過jni調(diào)用本地的接口, 實(shí)際上還是要用VC來寫。 不過從網(wǎng)上搜了搜, 發(fā)現(xiàn)已經(jīng)有前人做過了,所以俺就省事兒了, 直接拿過來用吧。
看到有兩個(gè)地方介紹的, 一個(gè)是
【全文】
沒有辦法, 不得不做啊, 還得靠這個(gè)東西混學(xué)分呢。
老師給的例子是用VC寫的, 說心里話, 俺對(duì)VC不感興趣, 所以就想用Java來實(shí)現(xiàn)。
但是java是無法直接訪問raw socket的, 所以如果要實(shí)現(xiàn)sniffer的功能的話, 只能通過jni調(diào)用本地的接口, 實(shí)際上還是要用VC來寫。 不過從網(wǎng)上搜了搜, 發(fā)現(xiàn)已經(jīng)有前人做過了,所以俺就省事兒了, 直接拿過來用吧。
看到有兩個(gè)地方介紹的, 一個(gè)是:
http://www./software/rocksaw/, 不過這個(gè)實(shí)現(xiàn)的功能有限。 而且不可以抓取數(shù)據(jù)包, 不過可以發(fā)送ICMP消息了, 這個(gè)功能在Java中是沒法直接實(shí)現(xiàn)的。但是如果修改一下它給的c源文件, 應(yīng)該就可以了。主要是它沒有將網(wǎng)卡設(shè)置為“混雜模式”(這是我們老師這么稱呼的)。
另外一個(gè)就是JPCAP了, 這個(gè)功能就強(qiáng)大的多了, 不過使用之前需要先安裝WinPCap, 好像裝其他的sniffer的時(shí)候, 也是需要這個(gè)軟件的, 估計(jì)是需要它的DLL文件吧。JPCAP的下載地址是:http://www./projects/jpcap。參照了CSDN上面yanqlv的文章,http://blog.csdn.net/yanqlv/archive/2005/12/08/547402.aspx。 俺的這個(gè)作業(yè)也就基本上做完了, 就剩下報(bào)告了 ^_^.
下面給出俺的源代碼, 有興趣的可以試著運(yùn)行一下, 現(xiàn)在只解析出來了TCP, TDP和ARP的數(shù)據(jù)包, 其他的沒有做。 實(shí)際上所有的數(shù)據(jù)都已經(jīng)抓到了, 因?yàn)樗械臄?shù)據(jù)是從以太網(wǎng)幀里面解析的。
import net.sourceforge.jpcap.capture.CaptureDeviceOpenException;
import net.sourceforge.jpcap.capture.CapturePacketException;
import net.sourceforge.jpcap.capture.PacketCapture;
import net.sourceforge.jpcap.capture.RawPacketListener;
import net.sourceforge.jpcap.net.RawPacket;
public class Sniffer implements RawPacketListener {
private PacketCapture pcap;
public static int MAC_ADDRESS_WIDTH = 6;
public static int PROTOCOL_TYPE_WIDTH = 2;
public static int DEST_MAC_POS = 0;
public static int SRC_MAC_POS = DEST_MAC_POS + MAC_ADDRESS_WIDTH;
public static int ETH_FRAME_HEADER_LEN = MAC_ADDRESS_WIDTH * 2 + PROTOCOL_TYPE_WIDTH;
public static int ARP = 0x0806;
public static int IP = 0x0800;
public static int TCP = 0x06;
public static int UDP = 0x11;
public static int LOOPBACK = 0x9000;
public String INFO;
public byte[] RAW_DATA;
public int TCP_PACKET_COUNT;
public int UDP_PACKET_COUNT;
public int ARP_PACKET_COUNT;
public Sniffer() {
pcap = new PacketCapture();
try {
String[] devices = PacketCapture.lookupDevices();
pcap.open(devices[4].split("\\\n")[0], true);
pcap.addRawPacketListener(this);
pcap.capture(-1);
} catch (CaptureDeviceOpenException e) {
e.printStackTrace();
} catch (CapturePacketException e) {
e.printStackTrace();
} catch (CaptureDeviceLookupException e) {
e.printStackTrace();
}
}
// 解析以太網(wǎng)幀
public void rawPacketArrived(RawPacket rawPacket) {
RAW_DATA = rawPacket.getData();
int type = getInt(RAW_DATA, MAC_ADDRESS_WIDTH * 2, PROTOCOL_TYPE_WIDTH);
switch (type) {
case 0x0806: // ARP
parseARP();
break;
case 0x0800: // IP
parseIP();
break;
}
System.out.println(INFO);
}
public void parseIP() {
StringBuffer sb = new StringBuffer();
byte b1 = RAW_DATA[ETH_FRAME_HEADER_LEN];
byte dsf = RAW_DATA[ETH_FRAME_HEADER_LEN + 1];
String totalLength = byte2HexString(RAW_DATA, ETH_FRAME_HEADER_LEN + 2, 2);
String identification = byte2HexString(RAW_DATA, ETH_FRAME_HEADER_LEN + 4, 2);
String flags = byte2HexString(RAW_DATA[ETH_FRAME_HEADER_LEN + 6]);
String frameOffset = byte2HexString(RAW_DATA, ETH_FRAME_HEADER_LEN + 6, 2);
String ttl = byte2HexString(RAW_DATA[ETH_FRAME_HEADER_LEN + 8]);
byte ptype = RAW_DATA[ETH_FRAME_HEADER_LEN + 9];
String cksum = byte2HexString(RAW_DATA, ETH_FRAME_HEADER_LEN + 10, 2);
String SOURCE = getIPAddress(RAW_DATA, ETH_FRAME_HEADER_LEN + 12);
String DESTINATION = getIPAddress(RAW_DATA, ETH_FRAME_HEADER_LEN + 16);
sb.append("IP Version:" + (b1 >> 4));
sb.append(",Header Length:" + (b1 & 0x0F) * 4 + " bytes");
sb.append(",DSF: " + byte2HexString(dsf));
sb.append(",Total Length: 0x" + totalLength);
sb.append(",Identification 0x: " + identification);
sb.append(",Flags: 0x" + flags);
sb.append(",Frame Offset: 0x" + frameOffset);
sb.append(",TTL: 0x" + ttl);
sb.append(",Protocol Type: 0x" + byte2HexString(ptype));
sb.append(",Header Check Sum: 0x" + cksum);
sb.append(",Source:" + SOURCE);
sb.append(",Destination:" + DESTINATION);
sb.append("\n\t");
if(ptype == 0x06){ // TCP PACKET
TCP_PACKET_COUNT ++;
String sport = byte2HexString(RAW_DATA, ETH_FRAME_HEADER_LEN + 20, 2);
String dport = byte2HexString(RAW_DATA, ETH_FRAME_HEADER_LEN + 22, 2);
String seqNum = byte2HexString(RAW_DATA, ETH_FRAME_HEADER_LEN + 24, 4);
String ackNum = byte2HexString(RAW_DATA, ETH_FRAME_HEADER_LEN + 28, 4);
String headerLen = byte2HexString(RAW_DATA[ETH_FRAME_HEADER_LEN + 32]);
String tcpFlags = byte2HexString(RAW_DATA[ETH_FRAME_HEADER_LEN + 33]);
String windowSize = byte2HexString(RAW_DATA, ETH_FRAME_HEADER_LEN + 34, 2);
String tcpCkSum = byte2HexString(RAW_DATA, ETH_FRAME_HEADER_LEN + 36, 2);
String data = byte2HexString(RAW_DATA, ETH_FRAME_HEADER_LEN + 40, RAW_DATA.length - ETH_FRAME_HEADER_LEN - 40);
sb.append("[TCP Segmentaion]Source Port: 0x" + sport);
sb.append(",Destination Port: 0x" + dport);
sb.append(",Sequence number: 0x" + seqNum);
sb.append(",Acknowledgment number: 0x" + ackNum);
sb.append(",Header length: 0x" + (headerLen));
sb.append(",Flags: 0x" + (tcpFlags));
sb.append(",Window size: 0x" + windowSize);
sb.append(",Check sum: 0x" + tcpCkSum);
sb.append(",Data: 0x" + data);
}else if(ptype == 0x11){ // UDP PACKET
UDP_PACKET_COUNT ++;
String sport = byte2HexString(RAW_DATA, ETH_FRAME_HEADER_LEN + 20, 2);
String dport = byte2HexString(RAW_DATA, ETH_FRAME_HEADER_LEN + 22, 2);
String len = byte2HexString(RAW_DATA, ETH_FRAME_HEADER_LEN + 24, 2);
String udpCkSum = byte2HexString(RAW_DATA, ETH_FRAME_HEADER_LEN + 26, 2);
String data = byte2HexString(RAW_DATA, ETH_FRAME_HEADER_LEN + 28, RAW_DATA.length - ETH_FRAME_HEADER_LEN - 28);
sb.append("[UDP Segmentaion]Source Port: 0x" + sport);
sb.append(",Destination Port: 0x" + dport);
sb.append(",Length: 0x" + len);
sb.append(",Check sum: 0x" + udpCkSum);
sb.append(",Data: 0x" + data);
}
INFO = sb.toString();
}
public void parseARP() {
ARP_PACKET_COUNT ++;
// if (getInt(RAW_DATA, 0, 3) == 0x00FFFFFF && getInt(RAW_DATA, 3, 3) == 0x00FFFFFF)
// DESTINATION = "Broadcast";
StringBuffer sb = new StringBuffer();
sb.append("Hardware Type:");
sb.append(byte2HexString(RAW_DATA, ETH_FRAME_HEADER_LEN, 2));
sb.append(",Protocol Type:");
sb.append(byte2HexString(RAW_DATA, ETH_FRAME_HEADER_LEN + 2, 2));
sb.append(",Hardware Size:");
sb.append(getInt(RAW_DATA, ETH_FRAME_HEADER_LEN + 4, 1));
sb.append(",Protocol Size:");
sb.append(getInt(RAW_DATA, ETH_FRAME_HEADER_LEN + 5, 1));
sb.append(",Operation Code:");
int opcode = getInt(RAW_DATA, ETH_FRAME_HEADER_LEN + 6, 2);
sb.append(opcode == 0x0001 ? "[Request]0x0001" : "[Response]0x0002");
sb.append(",Sender MAC:");
sb.append(getMACAddress(RAW_DATA, ETH_FRAME_HEADER_LEN + 8));
sb.append(",Sender IP:");
sb.append(getIPAddress(RAW_DATA, ETH_FRAME_HEADER_LEN + 14));
sb.append(",Target MAC:");
sb.append(getMACAddress(RAW_DATA, ETH_FRAME_HEADER_LEN + 18));
sb.append(",Target IP:");
sb.append(getIPAddress(RAW_DATA, ETH_FRAME_HEADER_LEN + 24));
INFO = sb.toString();
}
public String getFactoryName(int id) {
String name = null;
switch (id) {
case 0x00096B:
name = "Ibm";
break;
case 0x000B5F:
name = "Cisco";
break;
case 0x0015E9:
name = "D-Link";
break;
default:
byte b1 = (byte) (id >> 16);
byte b2 = (byte) (id >> 8);
byte b3 = (byte) id;
name = byte2HexString(b1) + ":" + byte2HexString(b2) + ":"
+ byte2HexString(b3);
break;
}
return name;
}
public int getInt(byte[] bs, int pos, int len) {
int value = 0;
for (int i = 0; i < len; i++)
value |= (bs[pos + len - i - 1] << 8 * i);
return value;
}
public String byte2HexString(byte b) {
return "" + byte2Char((byte) (b >> 4)) + byte2Char(b);
}
public String byte2HexString(byte[] b, int pos, int len) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < len; i++)
sb.append(byte2HexString(b[pos + i]));
return sb.toString();
}
public char byte2Char(byte b) {
char c = (char) (b & 0xf); // mask low nibble
return (c > 9 ? (char) (c - 10 + ‘A‘) : (char) (c + ‘0‘));
}
public String getMACAddress(byte[] b, int pos) {
return getFactoryName(getInt(b, pos, 3)) + "_"
+ byte2HexString(b[pos + 3]) + ":" + byte2HexString(b[pos + 4])
+ ":" + byte2HexString(b[pos + 5]);
}
public String getIPAddress(byte[] b, int pos) {
int WIDTH = 4;
int address = getInt(b, pos, WIDTH);
StringBuffer sa = new StringBuffer();
for (int i = 0; i < WIDTH; i++) {
sa.append(0xff & address >> 24);
address <<= 8;
if (i != WIDTH - 1)
sa.append(‘.‘);
}
return sa.toString();
}
public static void main(String args[]) {
new Sniffer();
}
}
運(yùn)行的時(shí)候, 需要net.sourceforge.jpcap-0.01.16.jar和jpcap.dll,
在和源文件的同一級(jí)目錄下面建立一個(gè)lib文件夾, 然后將上面兩個(gè)文件拷貝進(jìn)去。
javac -cp lib\net.sourceforge.jpcap-0.01.16.jar Sniffer.java
java -Djava.library.path=lib -cp=lib\net.sourceforge.jpcap-0.01.16.jar Sniffer
正常情況下, 應(yīng)該有類似如下的輸出的:
Hardware Type:0001,Protocol Type:0800,Hardware Size:6,Protocol Size:4,Operation Code:[Request]0x0001,Sender MAC:Ibm_12:E2:15,Sender IP:255.255.255.197,Target MAC:00:00:00_00:00:00,Target IP:255.255.255.140
Hardware Type:0001,Protocol Type:0800,Hardware Size:6,Protocol Size:4,Operation Code:[Request]0x0001,Sender MAC:Ibm_12:E2:15,Sender IP:255.255.255.197,Target MAC:00:00:00_00:00:00,Target IP:255.133.20.83
Hardware Type:0001,Protocol Type:0800,Hardware Size:6,Protocol Size:4,Operation Code:[Request]0x0001,Sender MAC:Ibm_12:E2:15,Sender IP:255.255.255.197,Target MAC:00:00:00_00:00:00,Target IP:255.255.232.100
Hardware Type:0001,Protocol Type:0800,Hardware Size:6,Protocol Size:4,Operation Code:[Request]0x0001,Sender MAC:FF:FF:E9_07:84:21,Sender IP:255.255.255.250,Target MAC:Cisco_B5:27:00,Target IP:202.117.21.1
Hardware Type:0001,Protocol Type:0800,Hardware Size:6,Protocol Size:4,Operation Code:[Request]0x0001,Sender MAC:Ibm_12:E2:15,Sender IP:255.255.255.197,Target MAC:00:00:00_00:00:00,Target IP:255.255.229.49
Hardware Type:0001,Protocol Type:0800,Hardware Size:6,Protocol Size:4,Operation Code:[Request]0x0001,Sender MAC:Ibm_12:E2:15,Sender IP:255.255.255.197,Target MAC:00:00:00_00:00:00,Target IP:255.255.244.42
Hardware Type:0001,Protocol Type:0800,Hardware Size:6,Protocol Size:4,Operation Code:[Request]0x0001,Sender MAC:Ibm_12:E2:15,Sender IP:255.255.255.197,Target MAC:00:00:00_00:00:00,Target IP:255.255.217.59
Hardware Type:0001,Protocol Type:0800,Hardware Size:6,Protocol Size:4,Operation Code:[Request]0x0001,Sender MAC:Ibm_12:E2:15,Sender IP:255.255.255.197,Target MAC:00:00:00_00:00:00,Target IP:222.51.121.73
Hardware Type:0001,Protocol Type:0800,Hardware Size:6,Protocol Size:4,Operation Code:[Request]0x0001,Sender MAC:Ibm_12:E2:15,Sender IP:255.255.255.197,Target MAC:00:00:00_00:00:00,Target IP:255.255.255.162
Hardware Type:0001,Protocol Type:0800,Hardware Size:6,Protocol Size:4,Operation Code:[Request]0x0001,Sender MAC:Ibm_12:E2:15,Sender IP:255.255.255.197,Target MAC:00:00:00_00:00:00,Target IP:255.255.255.162
Hardware Type:0001,Protocol Type:0800,Hardware Size:6,Protocol Size:4,Operation Code:[Request]0x0001,Sender MAC:Ibm_12:E2:15,Sender IP:255.255.255.197,Target MAC:00:00:00_00:00:00,Target IP:59.34.116.34
Hardware Type:0001,Protocol Type:0800,Hardware Size:6,Protocol Size:4,Operation Code:[Request]0x0001,Sender MAC:Ibm_12:E2:15,Sender IP:255.255.255.197,Target MAC:00:00:00_00:00:00,Target IP:59.34.116.34
Hardware Type:0001,Protocol Type:0800,Hardware Size:6,Protocol Size:4,Operation Code:[Request]0x0001,Sender MAC:Ibm_12:E2:15,Sender IP:255.255.255.197,Target MAC:00:00:00_00:00:00,Target IP:58.50.48.47
Hardware Type:0001,Protocol Type:0800,Hardware Size:6,Protocol Size:4,Operation Code:[Request]0x0001,Sender MAC:Ibm_12:E2:15,Sender IP:255.255.255.197,Target MAC:00:00:00_00:00:00,Target IP:255.255.255.213
Hardware Type:0001,Protocol Type:0800,Hardware Size:6,Protocol Size:4,Operation Code:[Request]0x0001,Sender MAC:Ibm_12:E2:15,Sender IP:255.255.255.197,Target MAC:00:00:00_00:00:00,Target IP:255.255.255.226
Hardware Type:0001,Protocol Type:0800,Hardware Size:6,Protocol Size:4,Operation Code:[Request]0x0001,Sender MAC:Ibm_12:E2:15,Sender IP:255.255.255.197,Target MAC:00:00:00_00:00:00,Target IP:59.41.41.17
IP Version:4,Header Length:20 bytes,DSF: 00,Total Length: 0x004C,Identification 0x: A4EA,Flags: 0x00,Frame Offset: 0x0000,TTL: 0x80,Protocol Type: 0x11,Header Check Sum: 0xB5F6,Source:202.117.21.75,Destination:255.255.255.255
[UDP Segmentaion]Source Port: 0x09B1,Destination Port: 0x1394,Length: 0x0038,Check sum: 0xAFF4,Data: 0x30004B5600000000000103000100000001003000F604AD8500000000000000000000000000000000000001001D5DE044
Hardware Type:0001,Protocol Type:0800,Hardware Size:6,Protocol Size:4,Operation Code:[Request]0x0001,Sender MAC:Ibm_12:E2:15,Sender IP:255.255.255.197,Target MAC:00:00:00_00:00:00,Target IP:255.255.255.189
Hardware Type:0001,Protocol Type:0800,Hardware Size:6,Protocol Size:4,Operation Code:[Request]0x0001,Sender MAC:FF:FF:E9_07:84:21,Sender IP:255.255.255.250,Target MAC:Cisco_B5:27:00,Target IP:202.117.21.1