为了在非内网环境下访问校网,同时规避掉原来速度慢且极为臃肿的RVPN,这里搭建了一个基于SSH的RVPN,当然了,性能可能较差,只能供个人使用。
核心命令:利用SSH的DNAT功能,在客户端建立一个SOCKS5代理,从而使网络流量走SSH隧道。
1 | ssh -NfD 1088 pi@rte.un |
这里,N代表不打开shell,我们只进行网络代理,不需要shell;f代表让ssh自动到后台运行;而D则是建立一个动态端口转发隧道,也就是打开了SOCKS5隧道,这里将隧道建立在了1088端口。
为了在非内网环境下访问校网,同时规避掉原来速度慢且极为臃肿的RVPN,这里搭建了一个基于SSH的RVPN,当然了,性能可能较差,只能供个人使用。
核心命令:利用SSH的DNAT功能,在客户端建立一个SOCKS5代理,从而使网络流量走SSH隧道。
1 | ssh -NfD 1088 pi@rte.un |
这里,N代表不打开shell,我们只进行网络代理,不需要shell;f代表让ssh自动到后台运行;而D则是建立一个动态端口转发隧道,也就是打开了SOCKS5隧道,这里将隧道建立在了1088端口。
最近搞了一台带有RS232串口的Linux服务器,想通过串口和树莓派连接起来传输数据。而串口上网正好也是一种古老的上网方式,在当下虽略显过时但仍有一定的可玩性。
由于RS232串口和树莓派的GPIO串口采用的电平是不同的制式,为了能让两种串口相互通信,我们可以买一块MX3232的电平转换模块,但这里由于买到的模块被我乱搞烧坏了,所以还是用服务器的USB接口配合USB转串口线进行通信。

这张图画的有问题。。5V一般不用连
默认情况下,树莓派的GPIO串口采用的是软件时钟,误差较大。而树莓派默认的蓝牙串口时钟是硬件时钟。我们可以将树莓派的两个串口使用的时钟调换,让GPIO串口采用硬件时钟,增加GPIO串口稳定性。
修改树莓派启动配置文件 /boot/config.txt,在末尾添加一行
1 | dtoverlay=pi3-miniuart-bt |
保存重启,执行下面的命令发现serial0已经变成了使用AMA0硬件时钟,说明交换成功了。
1 | pi@raspberrypi:~ $ ls -l /dev/serial* |
在树莓派中执行命令cat /dev/serial0,同时在Linux设备中执行命令echo hello > /dev/ttyUSB0,可以在树莓派中接收到hello的消息,说明串口连接成功了。
注意,采用echo/cat命令进行串口消息传输时,默认采用的波特率和停止位等其它设置可以通过stty命令进行查看和设置,而默认情况下二者使用的都是通用的9600波特率,8数据位,1停止位,无校验位等的设置,因此可以直接进行通讯。如果测试失败,可以查看是否是由于两端设置不同等原因造成的。
为了在串口上面承载网络数据,我们可以使用PPP协议。PPP协议是一种简单的数据链路层协议,可以在两端建立起点对点的数据链路层连接。这里我们采用pppd命令在二者间建立PPP信道
我们首先在两台设备上安装ppp软件包:
1 | sudo apt install ppp |
然后两端分别输入如下命令
服务器端:
1 | sudo pppd -detach /dev/ttyUSB0 115200 192.168.5.1:192.168.5.2 noauth nocrtscts local |
树莓派端:
1 | sudo pppd -detach /dev/serial0 115200 noauth nocrtscts local |
这里,detach代表将pppd挂在前台方便查看状态和停止运行;/dev/serial0等代表使用的串口设备;115200是波特率,115200还是非常保守的,经过实验最大可以承载921600的速率,也就是基本波特率9600的96倍;192.168.5.1:192.168.5.2是两端使用的IP,这里只在一台机器上指定了,另一台机器上面可以协商获取。如果两端都写也没问题的,只要保证对面是192.168.5.2:192.168.5.1这样就可以了;noauth关闭PPP的验证功能;nocrtscts和local关闭硬件流控
现在再打开两个终端,应该已经可以ping通对方了
由于ppp默认采用了deflate压缩算法,因此测出的速率会有一定的偏差。为了得到真实速率,我们需要修改刚刚的指令,在服务器端增加nodeflate nobsdcomp两个参数关掉压缩功能。
接下来可以用iperf软件进行测试。如果没有安装首先要sudo apt install iperf进行安装。
在一台机器上运行iperf -s作为服务端,另一台运行iperf -c 192.168.5.XXX连接另一台机器,得到结果如下
1 | pi@raspberrypi:~ $ iperf -c 192.168.5.1 |
可以看到,最终可以达到775Kbps的速率,还是不快的,不过还是基本达到3G时代的速度了。
接下来我们要设置树莓派能够通过串口进行所有的网络活动,也就是准备拔掉它的网线。首先要做的就是设置一下两边的路由表。
在此之前,我们首先要重新运行刚刚的pppd命令,这次在树莓派端取消掉-detach,让它保持在后台运行;同时在服务器端开启压缩功能,保证更快的速率,最后别忘了两端采用921600的波特率。
1 | sudo pppd -detach /dev/ttyUSB0 921600 192.168.5.1:192.168.5.2 noauth nocrtscts local |
示例的网络环境:这是一个路由器下的环境,两台机器分别是192.168.2.3(树莓派)和192.168.2.6(服务器)。而这里的192.168.5.0/24则是通过PPP建立的网络。
我们的目标是在192.168.2.3失效的情况下能够通过192.168.5.2作为树莓派的网络连接IP地址。在不使用NAT的情况下,我们不仅要配置树莓派和服务器的路由,还要配置网关路由器的路由。当然,另一种方式是使用NAT,将树莓派的串口地址作为服务器的一个内网地址,然后分别设置服务器的Source NAT用于树莓派的内部上网,设置Destination NAT,也就是端口转发用于连接树莓派的SSH。两种方式都是可以的,这里仅展示第一种也就是路由方式。
在配置路由时,如果顺序不正确,可能导致无法访问树莓派。不过不要担心,将其他的步骤都做完应该是可以访问的。
网关路由器端:
在网关路由器我们要加一条路由指令:
1 | route add -net 192.168.5.0/24 gw 192.168.2.6 |
这条的目的是任何访问192.168.5.0/24的数据包都要通过我们的服务器进行转发。
服务器端:
我们需要做的是允许将这台服务器当作路由器,和192.168.5.0之间转发数据。因此需要以下两条指令来配置防火墙:
1 | sudo iptables -A FORWARD -d 192.168.5.0/24 -j ACCEPT |
两条命令的含义是对于所有发到这台服务器但接收者的IP不是自己的(也就是“转发”包),如果它们的目的地址或者源地址有一个在192.168.5.0/24的范围内,那么就允许转发。
树莓派端:
树莓派端要做的就是添加一条默认路由信息。也就是所有的网络流量都经过串口线传输。
1 | sudo route add -net default gw 192.168.5.1 |
好了,经过这样的设置之后,我们就可以断开树莓派的网络了。我们可以用
1 | sudo ifconfig eth0 down |
来关闭掉树莓派的有线网卡。当然,如果你用的是Wi-Fi,你也可以关闭掉wlan0达到同样的效果。此时你的SSH连接应该会断开。重新连接192.168.5.2这个IP,应该是能够成功连接了。
为了检验我们的压缩性能,可以打开sftp,试一下串口线传输大文件的能力。嗯,800K的图片传了10多秒钟,相比蓝牙的速度还是差很多的嘛,未来可能玩玩其它协议看看速度会不会快一点?
下面要做的就是在服务器上用WireShark进行抓包了。由于pppd不会提供PPP的原始包头,因此WireShark抓不到数据链路层的包,相反,可以抓到的是一个名为“Linux cooked capture”的虚拟协议。

不过可以发现的是,当ping包的数据部大小为1472时,达到最大的MTU,传输的伪包大小为1516,在ping大小为1474时,就已经发生了IP分片行为。因此根据ICMP+IP报文占用28字节,最终三层数据包最大大小是1500,而传输的伪包大小16字节。可以认为MTU保持在1500字节。
串口上网实际上不局限于串口上网,更重要的是如何在一条原始的数据链路上建立高级的数据链接,在简单的信道上做复杂的工作。因此接下来还有很多衍生工作可玩(挖坑开始),比如在SPI或者IIC这样的接口协议上面实现ppp信道的连接,甚至是在TCP连接或TLS连接上承载PPP信道(土制VPN),都是比较好玩的方向。
好久没更新了,因为又搬回了用L2TP上校园网的环境,所以重新配置了一下有线网络。本文提供一个基于OpenWRT软路由的解决方案,希望对你有所帮助。
本文涉及VLAN交换机、Docker、L2TP、远程访问等多个技术,可以根据章节选择阅读需要的部分。
在此之前我是万万没想到物理联通还会出现问题的……
问题是这样:由于我所在寝室的入户网线约有70米,网线经过长距离传输后电压下降,导致部分设备的网口没有办法识别,表现为网卡电源灯不亮,但网线可以通过连通性检测(报修师傅过来检测的)。
解决方案:购入一款交换机。这里选择了带VLAN划分功能的交换机,之后可以做单臂路由的方案。
于是,我的网络设备增加到了3台:所有网线连接到交换机上,通过VLAN划分为WAN区域和LAN区域;无线路由器提供Wi-Fi网络;J4105工控机通过OpenWRT作为主路由提供服务。
网络拓扑如下图:

这借助了交换机的VLAN划分功能,VLAN 1承载局域网流量,VLAN 2承载互联网流量,而软路由通过单个网线与交换机相连,作为单臂路由提供服务。由于校园网速度不超过100Mbps,因此单臂路由的方案完全够用。值得注意的是,对软路由来说,这里的VLAN 1配置为untagged,而VLAN 2配置为tagged。
如不需要交换机,可以采用以软路由为主路由的方案,也就是将外网的网线连到软路由的WAN口上,同时将局域网网线通过LAN口引出,可以连接到无线路由器的LAN口(关闭无线路由器的DHCP功能,使其成为一个AP),这样能够更有效的承载外网带宽,尤其是针对千兆网络的情况下。
还有一种称为“旁路由”的结构,即以其他路由器作为主路由,而软路由作为DHCP网关和DNS来运行,而所有设备处于同一个LAN下。这样配置的特点是电脑的上行流量通过软路由进行处理,而下行流量中,被软路由处理过的部分会从软路由回来,普通流量则会直接从主路由发过来,实际效率略高于单臂路由,但可能会导致软路由流量审计不准确。个人认为旁路由与单臂路由方案只是以哪个路由做NAT转换不同,所以如果有较好的前置路由做NAT的话旁路由不失为一个可行的选择。
这里采用的是工控机主机安装Ubuntu系统,运行其他服务,同时Ubuntu上安装Docker,在Docker内运行OpenWRT作为软路由。这样配置的好处是软路由可作为一个相对独立的组件,不影响主机系统。如果采用其他方案安装OpenWRT可跳过这节。
首先要获取OpenWRT的系统镜像。可以在GitHub中搜索找到有人编译整合好的x86 OpenWRT镜像,这里下载到的是一个.img.gz文件,也就是硬盘镜像。

fdisk -lu openwrt.img命令检查img文件含有的分区和位置
131584 * 512B = 67371008B,下面通过mount命令进行挂载:sudo mount -o loop,offset=67371008 openwrt.img openwrt。现在通过 ls openwrt命令检查,即可看到已经成功挂载了。openwrt目录,通过 sudo tar zcvf ../openwrt.tar.gz *命令将该目录下所有内容打包到外面目录下的 openwrt.tar.gz中。注意当前的工作目录,tar打包路径不要多一层。sudo umount openwrt停止挂载img文件。docker import openwrt.tar.gz openwrt:latest命令将文件导入Docker,至此镜像制作完成。导入为Docker镜像后,接下来是创建Docker虚拟网络。
Docker虚拟网络可以分为bridge、macvlan、ipvlan、host等多种形式。对于软路由来说,常用的有macvlan和bridge两种。在这里,我使用macvlan将主机网口共享给OpenWRT,而macvlan存在难以与宿主机通信的问题,因此这里添加了一个bridge网络专门用于docker和宿主机之间的通信。
创建两个macnet,分别用于untagged的VLAN 1和tagged的VLAN 2。
1 | docker network create -d macvlan --subnet 172.20.0.0/24 --gateway 172.20.0.1 -o parent=enp1s0 macnet |
因为OpenWRT不会使用这里的网段设置,因此这里的subnet和gateway只要选择两个未使用的网段即可。
再创建一个bridge,用于OpenWRT和宿主机的通信。
1 | docker network create -d bridge --subnet 172.20.2.0/24 --gateway 172.20.2.1 obridge |
这里的subnet和gateway比较关键,gateway即为openwrt内访问宿主机的地址。
使用如下命令创建容器:
1 | docker run -dit --privileged --name=owrt --net=macnet --restart=always openwrt:latest /sbin/init |
这里,首先将局域网macnet连接到容器内,然后依次将两个网络也连接进去。由于Docker在创建容器时只能指定一个网络,因此必须使用connect命令连接剩余的网络。
此时OpenWRT应该已经运行起来了,但由于没有配置好IP,因此还无法通过浏览器访问。这里首先通过 docker exec -it owrt sh命令打开一个控制台,通过命令行进行配置。
1 | > vi /etc/config/network |
退出OpenWRT容器,通过 docker restart owrt命令重启,即可更新网络配置。此时即可通过浏览器访问OpenWRT的控制网页了。
首先配置wan口的网络。添加一个新接口(或者可能已经有wan口了,用那个就好),名称为wan,接口协议选择DHCP客户端,物理接口选择eth1。同时,防火墙需要选择wan区域。
如果网络正常的话,保存应用后就应该能看到wan口分配的IP了。当然,此时还是不能上网的。
进入 网络-DHCP/DNS页,找到“重绑定保护”这一项,取消勾选。重绑定保护会过滤掉解析为内网地址的DNS查询,但这样就无法解析校园网的网页了。
此时可以试一下用电脑浏览器访问内网网站,如果访问不了的话有可能是策略路由的问题导致转发时使用的路由表与软路由本身不同。可以运行 ip rule add from all lookup main pref 0试一下,如果还是不行就说明防火墙配置有问题,确认从lan到wan的转发是通常的。
回到接口配置页面,添加一个新接口,接口类型选择L2TP(如果没有可以参考之前的文章拖一个ipk进来安装,但一般全面些的OpenWRT编译都会包含这个包),账号配置参考自己环境的配置方式。有一点要注意的是L2TP下MTU不是1500,需要适当降低一些(根据Cisco的说法应该调到1460,但是我这里1440就开始出问题了),我这里直接配置了1420,可以根据实际情况慢慢调。
接下来配置防火墙。L2TP的防火墙区域选择vpn(如果没有可以创建一个)。同时增加两条规则:lan可以转发到wan和vpn,不必选择IP伪装和MSS钳制;vpn可以转发到lan和wan,请选择IP伪装和MSS钳制,lan转发到wan也是同理。注意,这里一定要选择MSS钳制,因为l2tp和wan接口的MTU不同,因此需要通过MSS协商避免出现分包的情况。

保存应用,应该就可以分配到IP地址了。如果没有,首先考虑账号设置的问题。如果现在内网畅通,但是l2tp获取不到IP,可以打开命令行,输入 xl2tpd命令,如果出现报错,说明xl2tpd缺少依赖,需要额外安装依赖才能运行。
此时应该可以ping通互联网了。如果ping不通,请首先查看路由表,确保l2tp接口作为默认路由,同时存在让l2tp服务器走内网的路由(也就是说访问l2tp服务器本身应该走校园网接口,而访问外网应该走l2tp服务器)。如果路由器本身能ping通但主机ping不通,防火墙或策略路由问题。如果ping通IP但是ping不通域名,请手动设置DNS而非自动获取,可以在 网络-DHCP/DNS设置项中覆盖默认的DNS设置。
工控主机和软路由默认情况下是无法通过macvlan通信的。如果要通信有两种方式:第一种是在宿主机中创建一个同网段的macvlan,并指定同网段内和软路由不同的IP,这样就可以实现通信。但我的机器上自从Ubuntu升级了大版本后这种方式就工作不了了,因此现在介绍另一种互访问方式。
通过创建桥接网络,工控主机和软路由自然可以通信。我们在前面已经创建了名为obridge的桥接网络,现在只要为其分配IP即可。在OpenWRT中为eth2网卡创建一个接口,协议采用静态地址,防火墙区域选择lan,其他配置如下:
1 | ip: 172.20.2.2 |
同时,在宿主机配置如下:
1 | sudo route add default gw 172.20.2.2 |
这样,宿主机就可以通过bridge桥接网络访问软路由,进而访问网络了。
多OpenWRT是为了将功能性路由和稳定性路由分开而采用的一种架构。稳定性路由运行L2TP协议,提供稳定的网络访问,而功能性路由运行去广告等高级功能,避免与L2TP等发生干扰。由于运行的J4105有较多的性能余量,因此实践下来这样的配置速度还是比较快的,个人喜欢采用这样的方式。
多OpenWRT实际上也就是多了一个bridge网络,专门用于两个软路由之间的交互。稳定性路由连接外网、桥接网络,功能性路由连接桥接网络、宿主机桥接、内网。同时,功能性路由的wan口(关闭IP动态伪装和MSS钳制)即为稳定性路由的lan口(需配置路由表)。这样的配置在实现一些需求时是有用的,因此提出来供参考。
在这样的架构下,一个重要的需求就是暴露主机的远程桌面端口进行远程访问。简单的暴露方案可以用iptables或socat实现,如iptables实现方式可以在OpenWRT中的防火墙页面下,选择“通信规则”,打开端口即可。如果是多OpenWRT架构,也可以在外层配置端口转发,然后内层配置打开端口。
然而更方便的个人觉得是配置OpenConnect VPN。它是Cisco AnyConnect的一个开源兼容实现,实际体验很不错。可以在OpenWRT中通过 luci-app-ocserv这个包安装。
当然,如果有云服务器,还可以利用frp进行内网穿透。实际上玩法就比较多样了。当然,还是要注意安全问题,直接将服务暴露于公网还是比较危险的。
如何配置体验最佳的有线网是一个需要不断解决的问题,当然,这样的配置也存在很多问题,比如实际上我这里的网络环境是没有IPv6的。但是整体来说我觉得在这样的配置下达到了一个可用性和复杂度的平衡,虽然过程中又踩了好多坑。不过配置网络就是程序员的大号玩具嘛……
这次呢我们接着上一次 串口上网实验 的文章来继续深入。上一篇我们提到PPP封装可以做的工作远不止有在串口上建立数据链路这么简单,更重要的是可以在任何能够传输数据的信道上再建立一层数据链路的底层封装。因此这次我们希望在TLS安全层上建立一个信道,并在上面建立一个PPP连接,实现类似VPN的功能。由于俺学艺不精,因此要分很多前置工作慢慢迭代,希望一步步的迭代能逐步做到最后想要的成果。
首先我们要做的就是想在TCP流上实现一个基本的PPP封装。由于pppd是对串口、网卡这样的流设备进行操作的,而我们的TCP流在Linux中不能表示为一个能用echo或cat进行操作的文件,所以必须用一些间接的手段。
题外话,在Linux中,Socket虽然也存在相应的文件,但对Socket的读写使用的不是文件接口而是专用的网络接口,因此二者不能混为一谈。另外,bash提供了一个方便的接口发送TCP消息:echo xxx > dev/tcp/{ip}/{port},这条命令会向tcp://ip:port发送一条xxx的消息,但这个只是bash的语法糖,并不是说Linux实际存在这样的设备。
不过我们有一个强大的软件可以实现这样的功能:socat。它可以在不同的数据之间转换,包括将tcp数据传输到一个虚拟终端文件上。这样的功能恰好是我们需要的,我们可以用熟悉的接口来解决复杂的问题了。
首先在两台机器上安装socat:sudo apt install socat
服务器: socat -d -d tcp-listen:15000 pty
树莓派: socat -d -d tcp:192.168.2.6:15000 pty
这里,-d -d是让socat输出详细的调试信息,这里的目的是显示出socat分配的虚拟IO设备名;tcp-listen:15000是在15000建立一个tcp的监听端口;tcp:192.168.2.6:15000就是使用TCP协议连接到这个地址;pty是请求一个虚拟的终端设备连接到左边的流上面。
socat实际上就是将两个不同的流连接在一起。这里就是将网络接口的TCP和文件接口的PTY连接在一起。
下面我们在两端建立PPP连接。
1 | ~ > socat -d -d tcp-listen:15000 pty |
可以看到为服务器分配的虚拟终端是/dev/pts/4,因此设备就是这个了。树莓派的类似,这里是/dev/pts/2
服务器: sudo pppd -detach /dev/pts/4 192.168.5.1:192.168.5.2 noauth nocrtscts local
树莓派: sudo pppd -detach /dev/pts/2 noauth nocrtscts local
提前输入好命令,两端按下回车(因为pppd的超时默认很少,时间太长会断掉),可以看到两端已经拿到了IP,再打开终端相互ping,如果ping通证明链路已经完好了。
稍微修改pppd命令,通过nodeflate nobsdcomp关掉压缩功能后进行测速,发现速度仅能达到50Mbps和100Mbps的非常不对称的速率。相比直连情况下树莓派的300Mbps网卡还是有很大差距的,但相比上一篇的串口速率已经是一个质的飞跃了。
稍微修改socat命令,如果换成udp协议建立的原始信道,那么速度更是变成了只有56Mbps/85Mbps这样的速率,局域网环境下应该不存在针对UDP的限速行为,因此发生这样的情况还是较为令人费解的。可能是iperf本身的问题,但换成iperf3后并没有结果的改变。
TLS是一种基于证书体系的安全系统,其可以提供更安全更可靠的流式数据传输。我们仍然采用socat工具来帮助实现TLS流的建立。
我们需要的自签名证书涉及2个文件:保存密钥的key文件和保存加密过的证书信息的crt文件。然而,socat需要的并不单纯是这两个文件:它需要的是证书文件crt以及一个key和crt文件的打包文件。
密钥文件: openssl genpkey -algorithm Ed25519 -out ca.key,其中,algorithm是指定密钥文件的算法。常用的算法有RSA,ECDSA和EdDSA。这里用的便是EdDSA算法的Ed25519曲线。EdDSA算法的好处是相比RSA,其生成key的速度更快,性能更好,占用的空间更小,相比ECDSA,由于使用的曲线安全性能更好,因此更加具有实用价值。
证书文件: openssl req -new -key ca.key -x509 -days 3650 -out ca.crt,这时,机器会要求你回答几个问题,大部分的问题都可以随意回答,但是Common Name这项必须是你用于访问这台服务器的IP地址或域名。因为如果服务器的IP或域名和证书中Common Name项的内容不同,那么客户端就会拒绝连接,保证安全性。
打包文件: cat ca.key ca.crt > ca.pem,我们使用cat命令将ca.key和ca.crt两个文件简单地连接在一起即可。
接下来我们要将生成的证书传输到另一台机器上面,保证两边的证书是完全相同的,才能连接成功。
下面我们就可以用socat命令来建立TLS流了,过程和建立TCP流类似。但首先我们还要切换到刚刚保存证书的那个目录下。
服务器: socat -d -d openssl-listen:15000,cert=ca.pem,cafile=ca.crt pty
树莓派: socat -d -d openssl:192.168.2.6:15000,cert=ca.pem,cafile=ca.crt pty
现在,屏幕上应该已经显示了两台机器分配的PTY,这表明已经成功建立了TLS数据流。
如果将服务器和树莓派的命令对调,也就是让服务器去连接树莓派的话,由于刚刚提到客户端会对连接的地址进行验证,因此反过来是会连接失败的,而且现象是客户端首先断开连接,服务端并没有显示错误信息。但如果我们生成证书时使用的是域名,那么只要这个域名可以指向那台机器,同时那台机器拥有证书文件,客户端就会认为这就是正确的服务器从而连接。
有了上面的基础,建立基于TLS流的PPP封装已经是呼之欲出了。保持刚刚建立的TLS流,输入以下命令:(更改为你的/dev/pts/x)
服务器: sudo pppd -detach /dev/pts/8 192.168.5.1:192.168.5.2 noauth nocrtscts local
树莓派: sudo pppd -detach /dev/pts/6 noauth nocrtscts local
现在就应该可以互相ping通对方了,至此我们已经成功建立了TLS流上的PPP封装。
同样地,我们在pppd中更改服务器的选项,用nodeflate nobsdcomp命令关掉压缩,以便进行更准确的速度测试,得到了40Mbps/68Mbps的速度。相比TCP流又下降了不少,大概是TLS本身传输加密数据本身数据量较大导致的。
除了基于TCP的TLS流外,还有基于UDP的DTLS流,但是由于Socat直到一个月前才放出支持DTLS的新版本,我这台机器上还没有安装,因此只能等待后续更新了。
既然我们要建立一个VPN,那么必不可少的就是能让树莓派使用服务器的网络进行上网。这意味着我们不能再像上一篇文章那样通过修改网关路由表这样大动干戈的方式来实现树莓派的网络访问了。当然,除了NAT以外,还可以通过ARP Proxy的方式实现类似的效果,但ARP Proxy需要有一个空余IP,仍然和网关有关系,因此这里仍然采用NAT的办法。
我们做两个NAT:一个是Source NAT,用于树莓派访问外部网络时的映射;另一个是Destination NAT,用于外部网络访问树莓派的SSH,也就是端口转发。因此下面的操作都是在服务器上进行的。
首先我们允许正常的路由转发:
1 | sudo iptables -A FORWARD -d 192.168.5.0/24 -j ACCEPT |
接下来实现SNAT,注意更换网卡的名称eth0为你自己的
1 | sudo iptables -t nat -A POSTROUTING -s 192.168.5.0/24 -o eth0 -j MASQUERADE |
最后实现DNAT,就可以用其他的电脑访问树莓派了,这里是将192.168.2.6:15001转发到了192.168.5.2:22
1 | sudo iptables -t nat -A PREROUTING -p tcp -d 192.168.2.6 --dport 15001 -j DNAT --to-destination 192. |
当然,经过了这样的操作树莓派还是没有能够利用这条线路上网。我们还需要重新配置以下默认路由。以下在树莓派上面操作:
首先把服务器的IP设置为通过原有的网卡:
1 | sudo route add 192.168.2.6 gw 192.168.2.1 dev eth0 |
接下来设置默认的路由
1 | sudo route add -net default gw 192.168.5.1 dev ppp0 |
现在我们用sudo traceroute -I www.baidu.com测试,可以看到路由首先经过了192.168.5.1,表明数据是经过这个安全的隧道传输的。同样地,在其他的电脑上通过访问服务器的IP也可以转发到树莓派的SSH上,实现了安全隧道传输的VPN效果。
可以说,我们这个土制VPN还是非常粗糙的,可用性较差但不失正确性。通过该VPN我们可以隐藏自己真实要访问的网站,所有的流量都通过虚拟的隧道进行转发,同时,隧道本身也采用了安全的TLS。代理ARP的功能虽然没有实现,但是NAT也达到了更好的效果。实际上,真正的VPN还应该拥有动态IP池等等功能,但那是不断演进的结果了。
这篇文章是 串口上网实验 的一个衍生探究,更多集中在如何在一个已经建立好的信道上进行更加低级的数据传输。正如标题所说,整个过程建立了一个“VPN”,可以利用目标电脑的网络环境来进行上网。当然,我们也可以继续深入下去其中的很多问题:为什么建立的信道上下行出现了严重的速度不对等现象?如何提高信道的利用率达到更高的速度?不使用ppp封包,在Windows下如何实现这样的功能(Windows下的wsl不支持ppp功能)?下一步可能是希望在信道连接建立后传输IPv6的数据,毕竟PPP是个很古老的协议了。
最近入手了一台刷入OpenWRT的路由器,但校园网需要使用静态地址+L2TP接入,因此配置的过程出现了很多问题,特此记录。
这个步骤是为了给所有没有预装xl2tpd的(大部分应该没有)路由器安装xl2tpd,它与其他部分不是连续的关系,所以首先要进行这一步。
要配置L2TP首先需要让路由器拥有xl2tpd这个软件包。如果没有也不要紧,我们可以让电脑给路由器共享网络。这个过程需要1台主电脑(同时有有线口和Wi-Fi口),1个辅电脑。接下来按如下步骤接线
1.首先在路由器的 网络–无线 页面保证无线是开启的,如果不是请点击 重启无线 打开。这里可以直接配置自己的无线名字和密码,配好后用手机连接上。
注意,重启无线后可能需要在路由器中执行该命令,原因请参考配置内网部分:ip rule add from all lookup main pref 0
2.在路由器的 网络–接口 页面中修改Wan口,协议改为静态IP,IP地址是 192.168.3.2,子网掩码 255.255.255.0,网关 192.168.3.1,DNS 223.5.5.5,其它留空即可,保存应用。
3.电脑的有线口连接路由器的Wan口,电脑的无线连接其它可以上网的Wi-Fi(不能是一会要使用的手机的热点,否则还需要一个设备)。
4.在电脑的开始菜单搜索 查看网络连接,在弹出的窗口中右击WLAN–属性,在上面点击 共享,首先在下面的下拉框中选择你的有线网卡(一般是 以太网),再勾选 允许其他网络用户通过此计算机的Internet连接来连接。如果弹出任何对话框请确定。
5.在网络连接的窗口右击 以太网–属性,往下找到Internet协议版本4,双击,点击“使用下面的IP地址”,修改地址为192.168.3.1,子网掩码 255.255.255.0,确定即可。
6.现在用另一台设备连接OpenWrt的Wi-Fi(或是连接网线也可以),进入它的后台页面,在 系统–TTYD 中打开终端,输入如下命令:
1
opkg update && opkg install xl2tpd
如果提示错误,请考虑更换软件源。
7.如果安装成功,那么说明已经安装了xl2tpd软件,可以断开连线并在主电脑中取消共享网络了。
要配置内网IPv4,首先在OpenWrt后台切换到 网络–接口 页面,同时在右侧的接口列表中修改WAN接口。我们切换协议为静态地址,并填写自己通过其它途径分配好的IP地址和DNS服务器。对于浙大玉泉校区的网络环境来说,需要首先在公寓公众号上申请IP地址,填入路由器的MAC地址(WAN口),并等待1天,第二天就可以ping通网关,从而进行后续的配置。
不出所料的话,目前路由器除了能够ping通内网地址,域名是查找不到的。这是因为很多版本的OpenWrt默认屏蔽了RFC1918,也就是如果对公网域名解析得到的IP是机器所在的内网网段IP(自己的IP在10.0.0.0/8,内网网站也在10.0.0.0/8),就会屏蔽掉这条信息。要解决这个,请在 网络–DHCP/DNS 页中找到RFC1918并取消勾选,保存应用。
此时的现象应该是路由器可以ping通内网地址,不论是域名还是IP。但是可能主机除了能ping通网关,但不能ping通其它地址。这其实是路由表的问题。Linux下有一种称为“策略路由”的高级路由方法,它可以根据不同的策略转发到不同的(最多256个)路由表并执行不同的路由。而从路由器发出的ping和从主机发出的ping默认走的不是同一个路由表,因此出现了上述的问题。我们可以用下面的命令简单地让所有经过路由器的数据都走主路由表,这样我们设置一个路由表就相当于设置所有的路由,在当前的网络情况下是没问题的。
1 | ip rule add from all lookup main pref 0 |
我们最好将这个配置保存起来以便每次开机自动执行。修改/etc/rc.local文件,在前面增加两行:
1 | ip rule add from all lookup main pref 0 |
每次无线网络重启时也需要执行这两句。
现在应该可以在主机上打开校园网内的各网站了。
配置L2TP的前提是内网畅通并已经安装好了xl2tpd软件包。这里采用内建L2TP连接的方式,如果不行的话可以命令行再行配置。
在路由器后台中打开 网络–接口,添加一个接口,协议选择L2TP,填入地址,用户名,密码,同时选择防火墙区域(可能切换到其它选项卡)为Wan区域(或者有专门的VPN区域则选择那个),最后连接,可能需要重启路由器。
重启后会发现已经连接上了L2TP,并可以正常上网了,这是最好的情况。
如果不能,那么需要查看原因:
手动配置L2TP可以参考如下教程:https://atomlab.org/post/code/rpi-router/
附上当时解决L2TP接口没IP的方案:先手动配置,然后修改该接口的物理接口为ppp0,然后重新配置,重启
不得不说OpenWrt对IPv6的支持仍然有待改进,但通过如下的方式可以实现IPv6中继的联网方式:每个设备可以获取公网IP,路由器也有IPv6地址。
1.在 网络–DHCP/DNS 的高级设置中取消勾选禁止解析IPv6 DNS记录。
2.路由器的终端中修改/etc/config/dhcp文件,找到config dhcp ‘lan’,把对应项修改/添加:
1 | option ra 'hybrid' |
找到config dhcp ‘wan’,整个项修改为如下:
1 | config dhcp 'wan6' |
3.重启,应该可以在电脑中获取到IPv6的地址了
由于中继模式的IPv6体验实在太差,经常出现路由被清空导致外网无法访问内网IP的情况(可能是配置问题),我这里目前已经全部改成NAT6上网了。
1.在/etc/config/dhcp文件中修改config dhcp 'lan'这一配置项,修改/添加如下内容:
1 | option ra_slaac '1' |
而config dhcp 'wan'这一项就不需要配置了,可以加一句option ignore '1',其它的删掉。
2.这个时候还要确保路由器的IPv6是正常的,在路由器内能正常访问IPv6地址。这里需要执行traceroute 2400:3200::1命令来查看一下你的默认网关。
3.在 网络-防火墙-自定义规则 中添加如下配置项
1 | ip6tables -t nat -A POSTROUTING -o eth0.1 -j MASQUERADE |
4.重启防火墙,现在应该上不了IPv6了,不过不用担心,只要在路由表中加入如下两项就可以
1 | route -A inet6 add 2000::/3 gw <GATEWAY> |
其中,
这个命令每次启动和重启网络都需要执行。
最近入手了正点原子家的DS100示波器,因此想着自己用ESP32做一个简单的示波器玩玩,顺便测试一下ESP32的性能。
ESP32有很多ADC通道,但是为了简单起见,这里只实现一个单通道的示波器,实际上如果只是玩玩的话至少还是双通道才够用,这个可能等后续有时间再添加吧。

设计很简单,首先是给待测元件加一个限流电阻(视情况,小电压不加)。由于ESP32的ADC在0~0.1V和3.1~3.3V之间是没有办法给出ADC值的,因此如果没有直流偏置就没有办法测出小电压时的情况。为了解决这个问题,这里采用了一个简单的分压电路用于给待测元件一个0.3V左右的参考电平。
这个示波器应该有如下几个基本功能:
针对上述需求,为了简单起见,这里采用Arduino IDE进行快速开发,同时做如下设计。
1 | #define ADC_PIN 34 |
这个简易示波器还是存在很多问题的,这里列举一些以及可能的解决方案。
xTaskCreatePinnedToCore函数将串口输出放在另一个核上来实现。顺带一提,ESP32在Arduino上进行开发时,函数默认在Core 1上运行,Core 0应该是空闲的。这次的小示波器还是很有意思的。这种东西要做的简单可以非常简单,但想做好就难得多了。这里也是想着不能浪费ESP32这么一个强大的处理器,虽然不是专业做这种事情的,但是自己做一个还是可以接受的,看看音频波形什么的应该还是绰绰有余。
有了小示波器之后能做的就多起来了,比如加上双通道功能然后增加XY模式,可以做一个扫描电视,虽然可能会非常慢。或者可以听听从示波器采集到的音频信号转成的wav文件,看看是不是变成了全损音质。当然也可以做一下信号协议分析,看看很多传输协议的物理层是如何实现的等等。
不过我这老挖坑大师了,看什么时候能做出来吧。
最近在宿舍添置了一台路由器。。结果现在的问题就是访问校内网络时候不能享受到20MB/s的内网速度了。所以找了一下,用路由表编辑是可行的。
首先我们进入路由器的后台(openwrt环境,包含busybox),利用 route命令查看一下原有的路由表
1 | Kernel IP routing table |
可以看到现在所有的外网和内网IP都是走VPN的。最简单的方案就是按照下列添加路由表:
1 | route add -net 10.0.0.0/8 gw 10.171.32.1 dev eth2.2 |
但是,在重新连接之后网关IP会改变,我们可以使用另一种方式,也就是黑名单的实现方式。
我们知道,对于IP 10.0.0.0/8,其第一个字节对应的二进制位为 00001010,我们可以求反向的IP及其掩码。
1 | 10000000 128.0.0.0/1 |
我们只需对上述8条做VPN路由即可。
1 | route del -net 0.0.0.0/0 |
这个扩展是几年后写的,但是确实是最近遇到了这个问题,于是重新思考了一下。问题如下:
给定一系列由CIDR确定的子网构成的数组,求所有不属于这些子网的网段的CIDR表示。
示例输入:
[‘10.0.0.0/8’]
示例输出:
[
‘0.0.0.0/5’, ‘8.0.0.0/7’, ‘11.0.0.0/8’, ‘12.0.0.0/6’,
‘16.0.0.0/4’, ‘32.0.0.0/3’, ‘64.0.0.0/2’, ‘128.0.0.0/1’
]
为了解决题目中的问题,我们首先解决包含问题:给定一个IP地址范围,用CIDR网段来表示。
tag:
缺失模块。
1、请确保node版本大于6.2
2、在博客根目录(注意不是yilia根目录)执行以下命令:
npm i hexo-generator-json-content --save
3、在根目录_config.yml里添加配置:
jsonContent:
meta: false
pages: false
posts:
title: true
date: true
path: true
text: false
raw: false
content: false
slug: false
updated: false
comments: false
link: false
permalink: false
excerpt: false
categories: false
tags: true