言成言成啊 | Kit Chen's Blog

手撕TCP内网穿透及配置树莓派

发布于2025-04-13 15:09:48,更新于2025-04-20 15:44:20,标签:life java tcp  文章会持续修订,转载请注明来源地址:https://meethigher.top/blog

之前入手了树莓派5,折腾一段时间后,环境算是搭好了。

但是又不想随身携带,我刚好有个公网IP,想着通过公网访问。于是就用到了内网穿透。

清明节三天爆肝,断断续续总共耗费一周。简单测试,性能还行。

一、TCP内网穿透

1.1 起因

使用fatedier/frp的过程中,不管在Windows还是Linux,都被扫出病毒了。而且这还是Golang自身的问题,参考Why does my virus-scanning software think my Go distribution or compiled binary is infected?

这个内网穿透本身也没多难,因此自己用Java手撕一套内网穿透工具,还是很有必要的。

1.2 原理

原理很简单,一张时序图以蔽之。

1.3 使用示例

创建一个Java项目,JDK使用8及以上,引入依赖

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
<dependency>
<groupId>top.meethigher</groupId>
<artifactId>tcp-reverse-proxy</artifactId>
<version>1.0.3</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-core</artifactId>
<version>4.5.10</version>
</dependency>
<!-- 若不使用http反向代理,可不加此依赖 -->
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web</artifactId>
<version>4.5.10</version>
</dependency>
<!-- 若不想添加日志,可只添加slf4j-api -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.12</version>
</dependency>
<!-- 若不使用TCP内网穿透,可不加此依赖 -->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-javalite</artifactId>
<version>4.30.2</version>
</dependency>

假如我有一个内网SSH服务10.0.0.10:22,需要通过192.168.0.200:22穿透出去。并且网络条件受限如下

  1. 10.0.0.10可以主动连接192.168.0.200
  2. 192.168.0.200无法主动连接10.0.0.10
  3. 只要双方建立连接,即可实现双向数据传输

这就需要TCP内网穿透了。假设你内网穿透使用的控制端口为44444

首先,在192.168.0.200这台机器,使用如下代码启动TunnelServer

1
2
3
4
5
ReverseTcpProxyTunnelServer.create(Vertx.vertx())
.port(44444)
// 用于用户连接和数据连接的延迟判定,如果网络较差/DNS解析较慢的情况下,建议将该参数调大
.judgeDelay(2000)
.start();

10.0.0.10这台机器,使用如下代码启动TunnelClient

1
2
3
4
5
6
7
ReverseTcpProxyTunnelClient.create(Vertx.vertx())
.backendHost("10.0.0.10")
.backendPort(22)
.dataProxyName("ssh-proxy")
.dataProxyHost("192.168.0.200")
.dataProxyPort(22)
.connect("192.168.0.200", 44444);

以上的源代码都是开源的

1.4 实战

下面放一个我将树莓派用于生产环境时,使用的内网穿透配置Bash脚本。

服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cat >/etc/systemd/system/tunnel-server.service<<EOF
[Unit]
Description=tunnel-server
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/sh -c "java -jar tunnel-server.jar >/dev/null 2>&1"
WorkingDirectory=/usr/local/tunnel-server
[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable tunnel-server
systemctl start tunnel-server

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cat >/etc/systemd/system/tunnel-client.service<<EOF
[Unit]
Description=tunnel-client
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/sh -c "java -jar tunnel-client.jar >/dev/null 2>&1"
WorkingDirectory=/usr/local/tunnel-client
[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable tunnel-client
systemctl start tunnel-client

由于客户端所在局域网内的IP经常变,因此我添加了一个固定的VIP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cat >/etc/systemd/system/vip.service<<EOF
[Unit]
Description=vip
After=network.target

[Service]
Type=oneshot
ExecStartPre=/usr/bin/sleep 30
ExecStart=/usr/sbin/ip addr add 192.168.1.222/32 dev wlan0
ExecStop=/usr/sbin/ip addr del 192.168.1.222/32 dev wlan0
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF

以上配置完了,就是再将内网穿透出来的SSH服务,配置为私钥登录。不多赘述。

二、无显示器树莓派5

树莓派入门视频,参考树莓派教程第一课 树莓派简介 十分钟玩转系列入门篇_哔哩哔哩_bilibili

又额外买了512GB存储,总共花费1007元。

2.1 系统烧录

下载系统镜像,选择环境最全的这个。

我没有显示器,需要采用远程SSH使用。但是需要到了SSH服务器拒绝了密码的情况。通过启用无屏幕 SSH Raspberry Pi - Thinbug进行解决。而在简易版系统上,无法使用该功能。

使用镜像烧录工具下载也可,但是我个人比较喜欢留存离线镜像。

下载镜像烧录工具

打开镜像烧录工具,选择设备、选择操作系统镜像、选择存储卡。

点击Next,编辑设置。

WIFI国家一定要设置为CN

之后就等待烧录即可。

2.2 远程SSH

我在远程连接树莓派SSH时,遭拒绝了,是因为树莓派OS设置了不允许直接通过root登录。

需要执行如下操作。参考自启用无屏幕 SSH Raspberry Pi - Thinbug

  1. 在SD卡内创建ssh文件,内容为空。
  2. 在SD卡内创建userconf.txt文件,内容为pi:$6$/4.VdYgDm7RJ0qM1$FwXCeQgDKkqrOU3RIRuDSKpauAbBvP11msq9X58c8Que2l1Dwq3vdJMgiZlQSbEXGaY5esVHGBNbCxKLVNqZW1,表示设置用户pi的密码是raspberry

上面这个密码也可以自己生成,使用命令

1
openssl passwd -6 '你的密码'

搞定之后,将SD卡插入树莓派,获取树莓派在局域网的IP地址,直接通过SSH进行登录。

1
ssh -p 22 pi@192.168.1.113

或者使用图形界面工具,比如XShell

安装neofetch,查看系统信息

1
2
apt -y install neofetch
neofetch

2.3 说明

树莓派OS是基于DebianOS

我平时使用的系统是CentOS(停止维护)或者RockyLinux

本质都是Linux,注意下使用细节即可。

特性CentOSRocky LinuxUbuntuDebian
上游来源RHEL(Red Hat)RHEL(Red Hat)Debian独立开发
包格式.rpm.rpm.deb.deb
包管理器yum(CentOS 7 及以下)
dnf(CentOS 8 开始)
dnfapt(高级工具)
dpkg(底层工具)
apt(高级工具)
dpkg(底层工具)

2.4 修改默认的反人类设置

2.4.1 vi中上下左右变成abcd

使用vi编辑文件,输入i进行insert模式,此时按上下左右时,变成了abcd,而不是光标移动。执行如下命令解决。

1
apt -y remove vim-common && apt -y install vim

2.4.2 vi右键无法粘贴

这些新功能,对于我这种老古董来说,用起来太反人类了,因此我切到了neovim。参考Disable vim automatic visual mode on mouse select

1
2
apt remove -y vim
apt install -y neovim

2.4.3 root用户终端无色

树莓派中pi用户的终端有颜色,root用户的终端无颜色。简单粗暴,把pi用户的配置复制过来。

1
2
cp ~/.bashrc ~/.bashrc-bak
cp /home/pi/.bashrc ~/.bashrc

重连终端即可生效。

2.5 apt换国内源

备份原源,并更换国内源

1
2
3
4
5
cp /etc/apt/sources.list /etc/apt/sources.list.bak
cat>/etc/apt/sources.list<<EOF
deb http://ftp.cn.debian.org/debian/ bookworm main contrib non-free non-free-firmware
EOF
apt update

2.6 虚拟机管理平台

2.6.1 CPU是否支持虚拟化

输入如下命令,输出结果大于 0 表示支持。如果是 0,需要在 BIOS 中开启虚拟化支持(Intel VT-x 或 AMD-V)。

1
egrep -c '(vmx|svm)' /proc/cpuinfo

由于我的机器是树莓派,ARM64的机器,验证是否支持虚拟化,就需要使用如下命令

1
dmesg | grep  kvm

输出结果包含VHE mode initialized successfully,则表示支持虚拟化。源码参考自linux/arch/arm64/kvm/arm.c · torvalds/linux

2.6.2 准备镜像

我计划安装arm64架构的两个不同操作系统的虚拟机,分别为

2.6.3 搭建环境

安装QEMU和KVM所需的环境

1
apt install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virtinst

工具包说明如下

  • qemu-kvm
    • KVM 支持的 QEMU 虚拟机管理器
  • libvirt-daemon-system
    • systemctl服务 libvirtd 支持
  • libvirt-clients
    • 包含一组命令行工具,用于和 libvirt 守护进程交互。
    • 常用工具
      1. virsh:管理虚拟机(启动、关闭、查看信息等)
      2. virt-clone:克隆虚拟机
      3. virt-xml:编辑虚拟机XML配置
  • bridge-utils
    • 桥接网络的工具包
  • virtinst
    • 包含一组命令行工具 virt-install,用于基于命令行创建虚拟机

2.6.4 虚拟网卡

通过NAT模式开启一个网卡,作为后续虚拟机的网关

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 查看libvirt中名为default的虚拟网卡的完整xml配置
virsh net-dumpxml default
# 下面三行代码,用于重定义default网卡配置信息,小白建议跳过。
virsh net-dumpxml default > default.xml
virsh net-undefine default
# 将配置信息改为自己需要的信息
virsh net-define default.xml

# 启动虚拟网卡default
virsh net-start default
# 配置虚拟网卡default的开机自启动
virsh net-autostart default
# 关闭虚拟网卡default的开机自启动
virsh net-autostart --disable default
# 关闭虚拟网卡default
virsh net-destroy default

# 检查网络
virsh net-list --all

2.6.5 虚拟机

安装一个Debian12.10系统的虚拟机,桥接入虚拟网卡

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
# 创建该文件夹完成后,将iso镜像拷入
mkdir -p /vms/iso
mkdir -p /vms/images
# 创建debian12.10虚拟机,2核CPU4GB内存100GB硬盘
virt-install \
--name debian-vm \
--vcpus 2 \
--memory 4096 \
--cdrom /vms/iso/debian12-10.iso \
--disk path=/vms/images/debian12-10.qcow2,size=100 \
--os-variant debian11 \
--network bridge=virbr0 \
--graphics none \
--console pty,target_type=serial
# 创建rocky9.5虚拟机,,2核CPU4GB内存100GB硬盘
virt-install \
--name rocky-vm \
--vcpus 2 \
--memory 4096 \
--cdrom /vms/iso/rocky9-5.iso \
--disk path=/vms/images/rocky9-5.qcow2,size=100 \
--os-variant centos7 \
--network bridge=virbr0 \
--graphics none \
--console pty,target_type=serial

虚拟机的常用操作命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 查看虚拟机列表
virsh list --all
# 开启虚拟机
virsh start debian-vm
# 跟随宿主机开机自启动
virsh autostart debian-vm
# 关闭跟随宿主机开机自启动
virsh autostart --disable debian-vm
# 终端直接进入虚拟机
virsh console debian-vm
# 优雅关闭虚拟机
virsh shutdown debian-vm
# 强制关闭虚拟机
virsh destroy debian-vm
# 删除虚拟机
virsh undefine debian-vm --remove-all-storage --nvram

2.6.6 快照

如果需要建立快照,推荐磁盘使用qcow2格式。

快照相关操作如下

1
2
3
4
5
6
7
8
9
10
# 创建快照
virsh snapshot-create-as \
--domain debian-vm \
--name init
# 快照列表
virsh snapshot-list debian-vm
# 删除快照
virsh snapshot-delete debian-vm init
# 回滚快照
virsh snapshot-revert debian-vm init
发布:2025-04-13 15:09:48
修改:2025-04-20 15:44:20
链接:https://meethigher.top/blog/2025/raspberrypi5/
标签:life java tcp 
付款码 打赏 分享
Shift+Ctrl+1 可控制工具栏