前言

作业要求是写一个类似于wireshark的流量捕捉器,要求有gui界面,能监听到相关流量

这是逆天的老师布置的作业,感觉我们什么都会,java,py都没学过。真就硬着让我写。。还好有gpt能帮我

监听

使用监听库

监听指定的网卡,有两种的思路。首先可以使用python封装的pyshark和java封装的pcap4j这些包去监听流量。以下是一个用py写的简单的流量抓捕

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import pyshark

def packet_handler(pkt):
print("start listening:")
print(f"Source IP: {pkt.ip.src}, Destination IP: {pkt.ip.dst}")
if hasattr(pkt, 'tcp'):
print(f"Protocol: TCP, Source Port: {pkt.tcp.srcport}, Destination Port: {pkt.tcp.dstport}")
elif hasattr(pkt, 'udp'):
print(f"Protocol: UDP, Source Port: {pkt.udp.srcport}, Destination Port: {pkt.udp.dstport}")
print(f"Packet Length: {pkt.length}")

shark = pyshark.LiveCapture(interface='eth0')#监听的网卡名字
shark.apply_on_packets(packet_handler)#循环执行

这里就可以进行简单的流量捕捉了

1c0d2fe4d27212a6b986f857ad6bbf0

已经能监听到了。

tcpdump

需要有这个软件,同时在root环境下进行监听

tcpdump可以将网络中传送的数据包的“头”完全截获下来提供分析。它支持针对网络层、协议、主机、网络或端口的过滤,并提供and、or、not等逻辑语句来帮助你去掉无用的信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
-a	将网络地址和广播地址转变成名字
-c 在收到指定的包的数目后,tcpdump就会停止;
-d 将匹配信息包的代码以人们能够理解的汇编格式给出;以可阅读的格式输出。
-dd 将匹配信息包的代码以c语言程序段的格式给出;
-ddd 将匹配信息包的代码以十进制的形式给出;
-e 在输出行打印出数据链路层的头部信息;
-f 将外部的Internet地址以数字的形式打印出来;
-l 使标准输出变为缓冲行形式;
-n 直接显示IP地址,不显示名称;
-nn 端口名称显示为数字形式,不显示名称;
-t 在输出的每一行不打印时间戳;
-v 输出一个稍微详细的信息,例如在ip包中可以包括ttl和服务类型的信息;
-vv 输出详细的报文信息;
-F 从指定的文件中读取表达式,忽略其它的表达式;
-i 指定监听的网络接口;
-r 从指定的文件中读取包(这些包一般通过-w选项产生);
-w 直接将包写入文件中,并不分析和打印出来;
-T 将监听到的包直接解释为指定的类型的报文,常见的类型有rpc (远程过程调用)和snmp(简单 网络管理协议;)

image-20231209112638621

界面

老师要求写一个GUI 的界面,方便操作

直接想到了java 的swing库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
setTitle("Packet Sniffer");//设置标题
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置退出按钮
setSize(800, 600);//设置大小
selectedProtocols = new ArrayList<>();
JPanel controlPanel = new JPanel(new FlowLayout());
outputTextArea = new JTextArea(30, 60);
outputTextArea.setEditable(false);
JScrollPane scrollPane = new JScrollPane(outputTextArea);
JButton startButton = new JButton("Start");//设置按钮
startButton.addActionListener(e -> startCapture());//事件检测器绑定
JButton stopButton = new JButton("Stop");
stopButton.addActionListener(e -> stopCapture());
controlPanel.add(startButton);
controlPanel.add(stopButton);
add(controlPanel, BorderLayout.NORTH);//布局管理
add(scrollPane, BorderLayout.CENTER);

这样就能搞出来一个简单的界面了

过滤器

要求能选择自己需要监听的流量,这里我选用的是tcpdump的命令,相对的简单

tcpdump提供了直接可以监听对应流量的方法,也就是直接加上想要的流量包

1
tcpdump tcp

直接添加内容完成对应的界面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public Main() {
setTitle("Packet Sniffer");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800, 600);

selectedProtocols = new ArrayList<>();

JPanel controlPanel = new JPanel(new FlowLayout());
outputTextArea = new JTextArea(30, 60);
outputTextArea.setEditable(false);
JScrollPane scrollPane = new JScrollPane(outputTextArea);

JButton startButton = new JButton("Start");
startButton.addActionListener(e -> startCapture());

JButton stopButton = new JButton("Stop");
stopButton.addActionListener(e -> stopCapture());

JCheckBox tcpCheckBox = new JCheckBox("TCP");
JCheckBox udpCheckBox = new JCheckBox("UDP");
JCheckBox icmpCheckBox = new JCheckBox("ICMP");

portField = new JTextField(10);

tcpCheckBox.addActionListener(e -> handleProtocolSelection("tcp", tcpCheckBox.isSelected()));
udpCheckBox.addActionListener(e -> handleProtocolSelection("udp", udpCheckBox.isSelected()));
icmpCheckBox.addActionListener(e -> handleProtocolSelection("icmp", icmpCheckBox.isSelected()));

controlPanel.add(startButton);
controlPanel.add(stopButton);
controlPanel.add(tcpCheckBox);
controlPanel.add(udpCheckBox);
controlPanel.add(icmpCheckBox);
controlPanel.add(new JLabel("Port:"));
controlPanel.add(portField);

add(controlPanel, BorderLayout.NORTH);
add(scrollPane, BorderLayout.CENTER);
}

输出流量信息

使用ProcessBuilder去执行本地命令,然会使用BufferedReader把命令执行的结果读取出来

1
2
3
4
5
6
7
ProcessBuilder builder = new ProcessBuilder(command);
builder.redirectErrorStream(true);
process = builder.start();

BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
new Thread(() -> {
String line;}

本来直接想Runtime.getRuntime().exec(command);去执行的,但是我的idea一直提示我说已经不用这个函数了。。。

将获取到的东西输出。add到输出框里面就好了

1
2
outputTextArea.append(line + "\n");
outputTextArea.append("数据包原始流量:"+line+"\n");

切记正则下再出来不然巨丑

现在已经基本完成要求

运行结果

a8072441a8e115ccf5ca000780cbc08

对的正则写不出

image-20231209115559284

傻逼老师屁事好多

就接下来写入文件然后读取、

写入文件

1
2
3
4
5
6
7
private void writeToFile(String fileName, String content) {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileName,true))) {
writer.write(content+"\n");
} catch (IOException e) {
e.printStackTrace();
}
}

判断数据包时间戳是不是同一个时间,来判断是不是一个数据包的内容,然后写入数据就好了

文本超链接

写一个事件监听器,监听到点击文字就直接可以打开对应文件

1
2
3
4
5
6
7
8
if (text.contains("点击这里查看流量包")) {
String linkPrefix = "点击这里查看流量包=》<"; // 超链接的前缀
String linkSuffix = ">"; // 超链接的后缀
int startIndex = text.indexOf(linkPrefix) + linkPrefix.length();
int endIndex = text.indexOf(linkSuffix);
String filename = text.substring(startIndex, endIndex);
open.open_pcap(filename);
}

文件打开

创建一个新的窗口然后直接打开文件就好了

1
2
3
4
5
try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
String line;
while ((line = reader.readLine()) != null) {
textArea.append(line + "\n");
}}

项目结果

c275ac5077f2202011e782ca7582a0a

项目源码

作业结束了发,不给超