编译
x86_64 Linux
常规 Linux 见文档 [[https://openwrt.org/docs/guide-developer/toolchain/install-buildsystem][[OpenWrt Wiki] Build system setup]]
Oracle ARM64 实例
在aarch64
下编译还是有不少坑的,下面是第一次编译成功的尝试,并不能明确哪些是有效步骤。
编译环境: 参考 Build system setup:
sudo dnf --setopt install_weak_deps=False --skip-broken install \
bash-completion bzip2 gcc gcc-c++ git make ncurses-devel patch \
rsync tar unzip wget which diffutils python2 python3 perl-base \
perl-Data-Dumper perl-File-Compare perl-File-Copy perl-FindBin \
perl-Thread-Queue
另外还执行了
yum install perl
unset which # which 被定义成一个函数名
问题:
- 报错 *** go-bootstrap cannot be installed on linux/arm64. 见 https://github.com/openwrt/packages/issues/12793 orcale linux 位置为 usr/lib/golang
- ucl 在 aarch64 下不能成功编译 修改
feeds/passwall/ucl/Makefile
cygwin - How to resolve configure guessing build type failure? - Stack Overflow [[https://bugs.archlinux.org/task/49287][FS#49287 : [ucl] ACC conformance test failure]]
--- a/ucl/Makefile
+++ b/ucl/Makefile
@@ -44,7 +44,8 @@ define Host/Configure
(cd $(HOST_BUILD_DIR); \
CC="$(HOSTCC)" \
CFLAGS="$(HOST_CFLAGS)" \
- ./configure --prefix=$(HOST_BUILD_PREFIX) \
+ CPPFLAGS="-std=c90 -fPIC" \
+ ./configure --build=aarch64-unknown-linux-gnu --prefix=$(HOST_BUILD_PREFIX) \
);
$(call Host/Configure/Default)
endef
Docker
用 P3TERX/openwrt-build-env, host mbp macOS 10.15,没什么问题,就是特别慢。表现在两个方面:
- 进入 openwrt 的 git 目录特别慢,估计 zsh 的 git 插件速度慢,原因可能是 io 速度慢
- 编译慢,首次
make V=s
要 12 小时
可能是 io 性能问题,openwrt 是挂载在 apfs case-sensitive 的宗卷上的,怀疑是 osxfs 有性能问题。测试了下单纯写入 1G 随机数据,结果似乎问题不大:
dd if=/dev/urandom of=sample.bin bs=1G count=1 iflag=fullblock 1+0 records in 1+0 records out 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 5.85614 s, 183 MB/s
不在 osxfs 目录下编译,make V=s -j$(nproc)
速度就快很多了。
另外,进入 git 目录很慢,估计本质原因也是 osxfs 的性能问题,关闭 zsh 的 track dirty 可以解决
git config --global --add oh-my-zsh.hide-dirty 1
见:https://stackoverflow.com/questions/12765344/oh-my-zsh-slow-but-only-for-certain-git-repo
Mac
[[https://oldwiki.archive.openwrt.org/doc/howto/buildroot.exigence.macosx][OpenWrt Buildroot – Installation on macOS [Old OpenWrt Wiki]]]This is called the “host compilation toolchain”, and the machine it is running on is called the “host system”. The host compilation toolchain is provided by the Linux distribution running on the host system, and has nothing to do with the actual build system.
Embedded systems use a different processor and require a cross-compilation toolchain - a compilation toolchain that runs on a host system but that generates code for a target system (and target processor’s instruction set architecture (ISA)).
直接在 Mac 下编译一开始很顺利,结果居然编译内核的时候报错了,提示缺少某些头文件,openwrt 不是先编译 toolchain 的吗?难道是 download 不全导致的?不知道是什么地方出问题,提了个 issue,暂时应该无法解决:
FS#2817 : compiler complain ‘asm/types.h’ file not found when compile kernel on osx 10.15
Github Action
最后还是用 github action 来云编译。自己 fork 了一份 openwrt 源码和自定义的 openwrt-package(fork 自 Lienol/openwrt-package)
速度很不错,1小时40分左右搞定。见:Actions · douo/openwrt
参考:
- KFERMercer/OpenWrt-CI: OpenWrt CI 在线集成自动编译环境
- P3TERX/Actions-OpenWrt: Build OpenWrt using GitHub Actions | 使用 GitHub Actions 编译 OpenWrt
问题
- 几乎每次编出来的 ext4 镜像都有损坏,挂载根目录的时候只能 read-only。找了个 arch live usb, fsck 一下就解决了,有时解决不了。然后我用 vbox 跑一下,却没有问题,怀疑是硬件问题。
- 直接把
.config
上传的话,执行 feed 脚本的时候会被重置,原来的.config
会被命名为.config.old
,需要重新改回来。注意更新.config
的时候,需要本地 update/install feeds 后再make menuconfig
.
基础包
opkg list-installed
可以在运行的 openwrt 上列出已安装的包
- Administration
- htop
- Network
- adguardhome
- UDPspeeder
- httping
- iperf3
- netcat
- Network-File Transfer
- aria2
- curl
- wget-ssl
- rsync
- Network - Firewall
- iptables-nft
- iptables6-nft
- Network NMAP Suite
- ncat-full
- nmap-full
- nping-ssl
- Network Routing and Redirectoin
- ip-full
- ss
- tc-full
- Utilities Disc
- fdisk
- lsblk
- blkid
- Utilities Terminal
- tmux
- Utilities
- file
- grep
- fildutils
- hwinfo
- less
- losetup
- lsof
- nnn
- sed
- tree
- luci
- luci
- luci-compat
- luci-mod-dashboard
单独编译 ipk
一次全量编译后:make target/linux/compile V=s make $package_path/compile V=s
其他
<buildroot>/files
下的文件可以编译到,镜像文件根目录相应的位置上,比如
/etc/config/ ⇒ <buildroot>/files/etc/config/my_config.
备忘
19.07
官方 19.07 的 golang 版本只只有 1.13,编译 v2ray 等包,需要 1.15,需要手动修改:feeds/packages/lang/golang/golang-version.mk
和 =feeds/packages/lang/golang/golang/Makefile=(PKG_HASH),参考:1.15
douo/openwrt-package,方便自己折腾和写包。
创建 package
[[https://openwrt.org/docs/guide-developer/packages][[OpenWrt Wiki] Creating packages]]PKG_MIRROR_HASH
需要让打包工具生成:
# First add "PKG_MIRROR_HASH:=skip" to the package Makefile and/or "HASH:=skip", if required. make package/network/services/odhcpd/download V=s make package/network/services/odhcpd/check FIXUP=1 V=s
执行后 makefile 中的 PKG_MIRROR_HASH
会被更新。
安装
我用的设备是咸鱼上收的二手软路由小马 v1 :T | V |
---|---|
CPU | Intel(R) Pentium(R) CPU N3700 @ 1.60GHz |
Memory | 4g |
Disk | 8g |
NIC | 四网口千兆 |
这个性能拿来做家用路由绝对是过剩的。
N3700 详细:
Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian Address sizes: 36 bits physical, 48 bits virtual CPU(s): 4 On-line CPU(s) list: 0-3 Thread(s) per core: 1 Core(s) per socket: 4 Socket(s): 1 Vendor ID: GenuineIntel CPU family: 6 Model: 76 Modennl name: Intel(R) Pentium(R) CPU N3700 @ 1.60GHz Stepping: 3 CPU MHz: 1057.534 CPU max MHz: 2400.0000 CPU min MHz: 480.0000 BogoMIPS: 3200.00 Virtualization: VT-x L1d cache: 96 KiB L1i cache: 128 KiB L2 cache: 2 MiB Vulnerability Itlb multihit: Not affected Vulnerability L1tf: Not affected Vulnerability Mds: Vulnerable: Clear CPU buffers attempted, no microcode; SMT disabled Vulnerability Meltdown: Mitigation; PTI Vulnerability Spec store bypass: Not affected Vulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization Vulnerability Spectre v2: Mitigation; Full generic retpoline, STIBP disabled, RSB filling Vulnerability Tsx async abort: Not affected Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm cons tant_tsc arch_perfmon pebs bts rep_good nopl xtopology tsc_reliable nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_c pl vmx est tm2 ssse3 cx16 xtpr pdcm sse4_1 sse4_2 movbe popcnt tsc_deadline_timer aes rdrand lahf_lm 3dnowprefetch epb pti tpr_shadow vnmi flexpr iority ept vpid tsc_adjust smep erms dtherm ida arat
dd
写入命令dd if=*.img of=/dev/sdx
gunzip -c *.img.gz | dd of=/dev/sdx
用 dd
写入 ext4 镜像,基本上写出来的文件系统总有损坏,我在 virtualbox
里写却没有问题,基本可以排除是编译的镜像出问题。如果是写入 squashfs
镜像又没问题,日常使用也没发觉固态有什么问题,很少不解
dd
还有一个问题就是分区表在编译时就固定了,实在是不适合作为 x86_64 的 pc 生态。ssd 的大部分空间都被浪费了。当然也可以手动扩容,或建个新分区挂载。
分区扩容
opkg install fdisk opkg install resize2fs
执行fdisk -l
,就会看到软路由的sdx盘被分成了两个分区,你会发现第二个分区只有256M,这里就可以调节第二个分区的大小,将硬盘的剩余容量全部划分到第二个分区:
fdisk -l /dev/sdx
将第二个分区的起始扇区号start
的值记下来fdisk /dev/sdx
进入修改硬盘分区信息,删除分区(=d=) 2 后重建(n
)- 选择分区后会让你输入分区开始扇区号,这里输入之前记下来的扇区号
- 输入
w
,这时候会提示你Partition #2 contains a ext4 signature. Do you want to remove the signature?
,这一步很重要,这里要选no,保留 ext4 信息 - 分区完成后执行
resize2fs /dev/sdx2
,分区扩容就大功告成了。
手动
编译出来 openwrt-combined-ext4.img 其实就是基于 MBR 分区表 grub 引导的 linux,两个分区分别挂载到/boot
和
/
。手动的意思就是在目标机器上的硬盘按这个分区表分好区,然后把镜像的相应内容拷到硬盘相应对位置上。然后还需要手动写引导,可以通过
live os 安装 grub 搞定。
不过我的做法是先用 dd
写入 squashfs 的镜像,这时 grub
就已经安装好了,然后剩下的空间在建个 ext4
分区,日常用的系统就安装在这里。保留 squashfs 的系统作为应急和安装使用。
实际分区表如下:
Device Boot Start End Sectors Size Id Type /dev/sdb1 * 512 33279 32768 16M 83 Linux /dev/sdb2 33792 558079 524288 256M 83 Linux /dev/sdb3 559104 15649199 15090096 7.2G 83 Linux
拷贝我用 rsync
,挂载镜像需要用到 losetup
、fdisk
、blkid
也是必须的。确保 squashfs 系统已经有安装这些工具。
过程
引导进入 squashfs 系统。# 个人电脑 scp openwrt-x86-64-combined-ext4.img.gz root@192.168.1.1:/tmp/ # 上传镜像到路由 # 路由 cd /tmp gunzip openwrt-x86-64-combined-ext4.img.gz losetup -Pf openwrt-x86-64-combined-ext4.img # 一般挂载在 loop1,lsblk 可以看到 mkdir -p /tmp/boot; mount /dev/loop1p1 /tmp/boot # 挂载 /boot mkdir -p /tmp/root; mount /dev/loop1p2 /tmp/root # 挂载 / mkdir -p /tmp/hboot; mount /dev/sdx1 /tmp/hboot # 挂载本机 boot mkdir -p /tmp/hroot; mount /dev/sdx3 /tmp/hroot # 挂载准备安装的 root rsync -av --delete /tmp/root/ /tmp/hroot # 同步镜像根目录,不放心可以先 mkfs.ext4 /dev/sdx3 # 第一次需要修改引导 cp -r /tmp/hboot/boot /tmp/hboot/boot_bk # 第一次的话先备份下 squashfs 的引导 # 修改 grub menu mv /tmp/hboot/boot/vmlinuz /tmp/hboot/boot/vmlinuz-squashfs # 第一次重命名 squashfs 内核 sed -i 's/"vmlinuz/"vmlinuz-squashfs/' /tmp/hboot/boot/grub/grub.cfg # 更新内核位置 sed -i 's/"OpenWrt/"OpenWrt squashfs/' /tmp/hboot/boot/grub/grub.cfg # 第一次重命名 grub 的菜单项 cp /tmp/boot/boot/vmlinuz /tmp/hboot/boot/ # 更新内核 export partuuid=`blkid | sed -n -r 's/\/dev\/sd.3.*PARTUUID="([^"]*)"/\1/gp'` # 获取本机新 root 分区的 partuuid sed -n '/menuentry/,+6{s/PARTUUID=[a-zA-Z0-9-]*/'PARTUUID="$partuuid"'/g;p}' /tmp/boot/boot/grub/grub.cfg # 输出替换 partuuid 后的 grub 菜单项 vi /tmp/hboot/boot/grub/grub.cfg #把输出的菜单项追加到前面 # 非第一次直接更新内核就可以 # cp /tmp/boot/boot/vmlinuz /tmp/hboot/boot/ # 更新内核
也可以直接上传 openwrt-x86-64-rootfs-ext4.img.gz
和 openwrt-x86-64-vmlinuz
,就可以避免依赖 losetup
文件系统
squashfs
与 ext4
squashfs
是只读的,对系统的修改保存是通过 overlayfs
来实现的,openwrt 还有另外一个可写的 jffs2
分区,通过 overlayfs
将两个分区合并为一个,写入的内容在 jffs2
上,覆盖到squashfs
上,这样的好处是恢复出厂设置(failsafe)相当简单,把overlayfs的内容抹掉即可。
这种分区方式有两个问题,squashfs
是只读的,所以 opkg 升级包后,旧版本的包还会留在 squashfs 上。另外 opkg 不知道 jffs2 分区的剩余容量,所以写满了的话会很尴尬,很可能需要重刷了。做分区调整估计没那么容易。
ext4
是可读写的,修改扩容都很方便,应用程序可以知道分区还有多少剩余容量,不过不支持损耗均衡(wear leveling)。
选择哪个格式在于,failsafe 和 wear leveling 对你是否重要。
在我看来,嵌入式设备选择 squashfs 无疑,但 x86_64 的软路由,一般配的硬盘都有 4g 起步,损耗均衡一般ssd固件已经做了支持。所以我选择 ext4 更方便折腾一下。
flash layout
squashfs 挂载在 /rom , jffs2 挂载在 /overlayWhenever the system is asked to look for an existing file in /, it first looks in /overlay, and if not there, then in /rom. In this way /overlay overrides /rom and creates the effect of a writable / while much of the content is safely and efficiently stored in the read-only /rom.
Layer0 | raw flash | |||||
---|---|---|---|---|---|---|
Layer1 | bootloader partition(s) | optional SoC specific partition(s) | OpenWrt firmware partition | optional SoC specific partition(s) |
||
Layer2 | Linux Kernel | rootfs mounted: “ / ”, OverlayFS with /overlay |
||||
Layer3 | /dev/root mounted: “ /rom ”, SquashFS size depends on selected packages | rootfs_data mounted: “ /overlay ”, JFFS2 “free” space |
- https://wiki.openwrt.org/doc/techref/filesystems
- https://zh.wikipedia.org/wiki/OverlayFS
- https://openwrt.org/docs/techref/flash.layout
系统
版本 | 21.02-SNAPSHOT r15879-4bc6b7ef7c |
内核 | Linux OpenWrt 5.4.99 |
Luci | git-21.062.56276-2e1f950 |
时间
Unitiles → Zoneinfo → zoneinfo-asia
日志
logreadshell
默认 shell 是 ash让 ash 好用一些:
Base system → busybox → Settings → History saving/ Reverse history search / Tab completion
Base system → busybox → Shell → Use $HISTFILESIZE
软路由,没什么限制,直接编进去 bash
或 zsh
更好
dns
ADGuard Home
用 ADG 替换 dnsmasq
ADG 有 dhcp 功能,但不建议替换 odhcp ,其 dhcpv6 有 bug(v0.107.0)。
先停用 dnsmasq:
/etc/init.d/dnsmasq disable /etc/init.d/dnsmasq stop
设置 adguardhome 的数据持久化
uci set adguardhome.config.workdir='/var/adguardhome'
再配置 ADG,dns 端口可以改为 53。
Bug FIX
因为这行提交 openwrt-package/app.sh at 45d2be84d0bb035032ad483e7701ff75c8a5d99c · douo/openwrt-packageadguardhome 的二进制名为 AdguardHome
所以需要手动 ln
一下绕过这验证:
ln -s /usr/bin/AdGuardHome /bin/adguardhome
odhcp
配置 static lease,参考 [[https://openwrt.org/docs/guide-user/base-system/dhcp_configuration?s\[\]=dhcp&s\[\]=static&s\[\]=lease][[OpenWrt Wiki] DNS and DHCP examples]]
用脚本生成 batch 配置搞定。
<2023-01-29 Sun> 发现 dhcpv4 一段时间后就出问题。只能禁用掉让 adguardhome 负责 dhcpv4
uci set dhcp.lan.dhcpv4=disabled
https://openwrt.org/docs/techref/odhcpd
opkg
更新 opkg
opkg update
opkg install lscpu
opkg install lsblk
opkg install bash
opkg install zsh
opkg install git-http # https://stackoverflow.com/questions/22506989/openwrt-git-clone-fatal-unable-to-find-remote-helper-for-http
更改 /etc/passwd
让 root 用 zsh=(或 =bash
) 登录,然后安装
oh-my-zsh
luci
luci 建议直接在 openwrt 环境里开发调试,需要先关掉 lua cache
uci set luci.ccache.enable=0; uci commit luci
参考文档:
uci
uci
是一个命令行工具,表示统一配置接口(Unified Configuration Interface ),旨在集中化 OpenWrt 的配置。luci 应该就是 lua 实现的 uci WebUI
uci
的配置文件存放于 /etc/config/
,可以直接通过文本编辑器或 uci
修改。这些配置文件还需要被 /etc/init.d
里面的脚本转化为实际程序需要的配置文件,也就是说在 uci 就是把各种程序需要的各式各样的配置文件封装成一套统一标准。
uci 的配置文件如下所示:
package 'example' config 'example' 'test' option 'string' 'some value' option 'boolean' '1' list 'collection' 'first item' list 'collection' 'second item'
其中config example 'test'
分别对应 section type name,name 和 option id 允许a-zA-Z0-9_
不能用连字符 -
,section 可以 unnamed,可以通过 config.section[index] 或者 config.cfgid 来访问,cfgid 是自动生成的。
uci-defaults 是存放系统第一次启动时执行的脚步,由 /etc/init.d/boot
控制。
- [[https://openwrt.org/docs/guide-user/base-system/uci?s\[\]=uci][[OpenWrt Wiki] The UCI system]]
- 【OpenWRT之旅】LuCI探究 - gnuhpc - 博客园
另外还有 ucitrack 值得注意一下:
The ucitrack mechanism simply maps config file names to init scripts or custom commands. It is solely used by LuCI for reloading the correct services when a given config file was changed by the ui.
You can find the entire implementation in the /sbin/luci-reload script. Thats the only part using /etc/config/ucitrack and it is only invoked by LuCI.
init
uci 配置好后,由 etc/init.d 里的脚本来,转换为实际程序需要的配置,并启动服务:一个 /etc/init.d/example 脚本如下:
#!/bin/sh /etc/rc.common # Example script # Copyright (C) 2007 OpenWrt.org START=10 # 决定这个脚本在系统启动时,执行的顺序,符号链接到 /etc/rc.d/S10example ,enable/disable 控制 STOP=15 # 同上 start() { echo start # commands to launch application } stop() { echo stop # commands to kill application }
通过 /etc/rc.common
来调用。有定义 start
和 stop
就会被认为是合法的脚本,比如上面的脚本,用 restart
命令,是会输出
stop start
OpenWrt 用 procd 来管理服务的,服务大多数是用 procd 来写的。procd 的 init 脚本如下
#!/bin/sh /etc/rc.common # Example script # Copyright (C) 2007 OpenWrt.org USE_PROCD=1 # 告诉 rc.commom 这是一个 procd init 脚本,api 见 /lib/functions/procd.sh START=10 # 必须函数,stop_service 可选 start_service() { # service 应该运行在前台 procd_open_instance [instance_name] procd_set_param command /sbin/your_service_daemon -b -a --foo procd_append_param command -bar 42 # append command parameters # respawn automatically if something died, be careful if you have an alternative process supervisor # if process dies sooner than respawn_threshold, it is considered crashed and after 5 retries the service is stopped procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5} procd_set_param env SOME_VARIABLE=funtimes # pass environment variables to your process procd_set_param limits core="unlimited" # If you need to set ulimit for your process procd_set_param file /var/etc/your_service.conf # /etc/init.d/your_service reload will restart the daemon if these files have changed procd_set_param netdev dev # likewise, except if dev's ifindex changes. procd_set_param data name=value ... # likewise, except if this data changes. procd_set_param stdout 1 # forward stdout of the command to logd procdlo_set_param stderr 1 # same for stderr procd_set_param user nobody # run service as user nobody procd_set_param pidfile /var/run/somefile.pid # write a pid file on instance start and remove it on stop procd_close_instance }
/lib/funcitions
下存放着 init 脚本可以调用的 api。 procd 的 API 参考
OpenWrt
Project: procd init script parameters
GFW
- v2ray
- trojan-go
luci-app-passwall
依赖了curl
、wget
,Makefile 里面没有声明
在谷歌云上部署了 trojan + kcptun,passwall 只支持 ssr 的 kcptun
***
自建服务器
方案 trojan -> kcptun -> udp2raw ,trojan 没做什么特殊配置,经测试 upd2raw 对速度影响很小。主要调整在 kcptun。最终的配置:
- 服务器:
-mode fast2 --sndwnd 1024 --rcvwnd 1024 -dscp 46 -mtu 1300
- 客户端:
-mode fast2 --sndwnd 128 --rcvwnd 1024 -dscp 46 -mtu 1300
--dscp 46
是 VoIP 用的 dscp 码,用于对抗 QoS。
用 iperf3 建立 kcptune 测试环境是很有必要的。
一般是测试下载速度,先调整调节窗口,服务器窗口都设置为
2048,客户端的上传窗口设置保持默认,慢慢增大客户端的接收窗口 rcvwnd
从
32 慢慢 2 次幂增加。
FEC,没做什么调整,用 mtr
看了下丢包率,一直 20% 几,就保持 10/3
不变。
参考:
- HOW :kcptun · outman
- Home · skywind3000/kcp Wiki
- Kcptun配置调节法,让你的VPS带宽最高效率的使用 - Let me Attente
- 前向纠错 - 维基百科,自由的百科全书
新版的 kcptun 已经支持 upd2raw 的功能了(–tcp)。测试了下不知道 ktptun 被特征还是怎么,实际效果与加多一层 udp2raw 相去甚远。
QoS
基本上可以确定,汕头移动光宽带(100M)晚高峰存在 QoS,日期:20200213 21:30
测试命令iperf3 谷歌云香港节点 + -c -p 443 -P 40 -t 20 -R
下载:
# ip 直连(tcp) [SUM] 0.00-20.04 sec 8.28 MBytes 3.46 Mbits/sec 2988 sender [SUM] 0.00-20.00 sec 6.64 MBytes 2.78 Mbits/sec receiver # tinyfecvpn(udp) [SUM] 0.00-24.38 sec 347 KBytes 117 Kbits/sec 176 sender [SUM] 0.00-20.00 sec 102 KBytes 41.8 Kbits/sec receiver # tinyfecvpn + udp2raw(faketcp) [SUM] 0.00-20.08 sec 289 KBytes 118 Kbits/sec 92 sender [SUM] 0.00-20.00 sec 99.8 KBytes 40.9 Kbits/sec receiver
上传:
# ip 直连(tcp) [SUM] 0.00-20.00 sec 46.8 MBytes 19.6 Mbits/sec 3442 sender [SUM] 0.00-22.24 sec 45.8 MBytes 17.3 Mbits/sec receiver
可以看到 ip 直连的情况下上传基本上可以跑满,下行流量被限制的很死。
非直接tcp ip 直连,tinyfecvpn 的 udp 加速和 faketcp
也没起到什么作用,上传下载都被限制的很惨。且与端口无关,udp2raw
使用
443 端口依旧没有改善。用 --raw-mode icmp
也没有改善。
另外连上 tinyfecvpn, ping
网关的话则延迟很低,50-100ms。很大概率是被故意限制了。
一些测试数据
ping 丢包率:--- ping statistics --- 187 packets transmitted, 116 packets received, 37% packet loss
tcppingv2 tcp 443 端口丢包率
100 packets transmitted, 86 received.
https://github.com/xtaci/kcptun/issues/137 https://github.com/xtaci/kcptun/issues/167
深夜的测试,直连 443 端口,tcp
iperf3 -c host -p 443 -P 5 -t 20 ... [Sum] 0.00-20.00 sec 46.3 MBytes 19.4 Mbits/sec 1673 sender [SUM] 0.00-20.00 sec 45.3 MBytes 19.0 Mbits/sec receiver
用 kcp fast2模式 其他默认:
iperf3 -c localhost -p 443 -P 5 -t 20 ... [SUM] 0.00-20.00 sec 26.4 MBytes 11.1 Mbits/sec 172 sender [SUM] 0.00-20.00 sec 24.3 MBytes 10.2 Mbits/sec receiver
-mode fast -datashard 5 -parityshard 5
[SUM] 0.00-20.00 sec 18.2 MBytes 7.62 Mbits/sec 27 sender [SUM] 0.00-20.00 sec 11.8 MBytes 4.96 Mbits/sec receiver
-mode manual -nodelay 0 -resend 0 -nc 1 -interval 40 -nocomp -dscp 46 -mtu 1400 -crypt aes-128 -datashard 70 -parityshard 30
[SUM] 0.00-20.00 sec 30.5 MBytes 12.8 Mbits/sec 0 sender [SUM] 0.00-20.00 sec 17.6 MBytes 7.40 Mbits/sec receiver
用 iperf3 直接测试 udp 的时候发现大部分几乎所有的 udp 包都被丢弃,到不了主机。
下午的测试:
直连
[SUM] 0.00-20.00 sec 44.5 MBytes 18.7 Mbits/sec 1206 sender [SUM] 0.00-20.00 sec 43.5 MBytes 18.3 Mbits/sec receiver
kcptun fast2 mtu 1200:
[SUM] 0.00-20.00 sec 35.6 MBytes 14.9 Mbits/sec 7 sender [SUM] 0.00-20.00 sec 17.9 MBytes 7.49 Mbits/sec receiver
加上 udp2raw
[SUM] 0.00-20.00 sec 33.4 MBytes 14.0 Mbits/sec 8 sender [SUM] 0.00-20.00 sec 17.6 MBytes 7.36 Mbits/sec receiver
虽然最终效果差不多,速度没啥改善,同样原理的还有 kcptun-raw:应对UDP QoS,重新实现kcptun的一次尝试 | ChionLab 和 ccsexyz/kcpraw
深感自己网络知识的不足和不够系统,计算机网络和TCP/IP详解 toread list 里面呆了多少年都没进展
luci-app-kcptun
一开始不能通过 luci 来启动服务,只能通过 /etc/init.d/kcptun 来启动。后面又可以了,忘记是不是需要手动 enable 一下。网络
工具
- ss
- netcat
smartdns
dns 里面的门道还是挺多的,比如 dns 欺骗,用可信的 dns 查询域名返回的结果仍然会被篡改,所有敏感使用 DoT、DoH 是必须的。面对 dns 服务器被墙,dns 请求走翻墙线路也是必须的。翻墙后的 dns 请求国内网站又会返回错误的 cdn 地址。chinadns 就是这个场景的解决方案。还有 dns 劫持(Hijack),则是在 dns 服务器上做手脚,对于翻墙来说影响不大,出门在外用不可信的 wifi 需要小心 。
自建 dns 服务器还要小心 dns 毒化(poisioning),实际上也是 dns 欺骗,上游服务器返回错误的ip 污染了自建服务器的 cache。smartdns 在这方面还要作一些折腾。 TODO
/etc/config/smartdns
配置如下:
config smartdns option server_name 'smartdns' option port '6053' option tcp_server '1' option ipv6_server '1' option dualstack_ip_selection '0' option prefetch_domain '1' option serve_expired '0' option redirect 'dnsmasq-upstream' option cache_size '2048' option rr_ttl_min '300' option rr_ttl_max '3600' option seconddns_tcp_server '1' option seconddns_no_rule_addr '0' option seconddns_no_rule_nameserver '0' option seconddns_no_rule_ipset '0' option seconddns_no_rule_soa '0' option force_aaaa_soa '0' option coredump '0' option seconddns_enabled '1' option seconddns_port '7913' option seconddns_server_group 'us' option seconddns_no_speed_check '1' option seconddns_no_dualstack_selection '1' option seconddns_no_cache '1' option enabled '1' list old_redirect 'dnsmasq-upstream' list old_port '6053' list old_enabled '1' config server option enabled '1' option type 'udp' option ip '114.114.114.114' option port '53' option name '114' config server option enabled '1' option type 'udp' option ip '119.29.29.29' option port '53' option name 'DNSPOD #1' config server option enabled '1' option ip '8.8.8.8' option port '853' option type 'tls' option server_group 'us' option blacklist_ip '0' option no_check_certificate '0' option name 'Google DoT #1' config server option enabled '1' option ip '8.8.4.4' option port '853' option type 'tls' option server_group 'us' option blacklist_ip '0' option no_check_certificate '0' option name 'Google DoT #2' config server option enabled '1' option ip 'https://cloudflare-dns.com/dns-query' option type 'https' option name 'Cloudflare DoH' option server_group 'us' option blacklist_ip '0' option no_check_certificate '0' config server option enabled '1' option ip 'https://dns.quad9.net/dns-query' option type 'https' option name 'Quad9 DoH' option server_group 'us' option blacklist_ip '0' option no_check_certificate '0' config server option enabled '1' option name 'Quad9 DoT' option ip '149.112.112.112' option port '853' option type 'tls' option server_group 'us' option blacklist_ip '0' option no_check_certificate '0' config server option enabled '1' option type 'udp' option name 'LN_UNICOM #1' option ip '202.96.69.38' option port '53' config server option enabled '1' option type 'udp' option name 'USTC #1' option ip '202.141.160.95' option port '53' config server option enabled '1' option type 'udp' option name 'QINGHUA #1' option ip '166.111.8.28' option port '53' config server option enabled '1' option type 'udp' option ip '180.76.76.76' option port '53' option name 'Baidu' config server option enabled '1' option type 'udp' option name 'ALI#1' option ip '223.5.5.5' option port '53'
6053 用于解析国内服务器,第二组服务器 7913 用于科学上网。配合 passwall
的 DNS
Mode:=Use local port 7913 as DNS=。通过作为dnsmasq的上游
来启用,推测这种方式的兼容性应该较好,比如解锁网易云音乐或
passwall 都涉及对 dnsmasq 的依赖,见/tmp/dnsmasq.d
完全用 smartdns
替换,还需要折腾。
之前使用了 frp 将 nas 的部分服务暴露到外网,根据不同域名通过 nginx
进行转发。如果在内网的话,可以直接将域名重绑定到实际的服务器,不用再绕一圈。通过对特定域名IP地址指定
就可以实现这个需求。示例:
address /xxx.dourok.info/192.168.1.xxx
如果还保留 dnsmasq 服务,记得关闭 dnsmasq
的重绑定保护(Rebind protection)
功能。
smartdns 让负载均衡废了:
现在已经改回运营商的dns了,之前认为smartdns 会为我解析出连接最快的、ping值最低的ip,用了一段时间以后发现,ipv4地址确实是找到最快的那个,但是也只是返回了一个ip地址,App Store,一些bt下载什么的 感觉只是获取到一个ip,不能完成多并发下载,导致下载速度一直很慢,所以决定放弃使用了
dns
- pdnsd 本地持久化缓存 dns 查询结果,已停止更新
- zfl9/chinadns-ng: chinadns next generation, refactoring with epoll and ipset 中国特色防污染DNS解析工具。
- dns2socks
用户对DNS解析花费的时长比较敏感,这个问题可以通过在本地增加DNS缓存并修改增大DNS解析结果的TTL部分解
ip
ip
是 ifconfig
和 route
继任者。要多用 ip
避免再用ifconfig
和
route
了,mac 可以用 brew install iproute2mac
获取 ip
命令。
默认编译选的是 ip-tiny
没有 tuntap ,需要重新安装下
ip-full
,luci-app-passwall
依赖了 ip-tiny
不知道能不能安
ip-full
。手动安装了下。
流量监控
- bandwidthd
- wrtbwmon,默认配置数据库放在
/tmp
,重启设备会清空数据
路由表
所谓路由表,指的是路由器或者其他互联网网络设备上存储的表,该表中存有到达特定网络终端的路径,在某些情况下,还有一些与这些路径相关的度量。路由器的主要工作就是为经过路由器的每个数据包寻找一条最佳的传输路径,并将该数据有效地传送到目的站点。由此可见,选择最佳路径的策略即路由算法是路由器的关键所在。为了完成这项工作,在路由器中保存着各种传输路径的相关数据------路由表(Routing Table),供路由选择时使用,表中包含的信息决定了数据转发的策略。打个比方,路由表就像我们平时使用的地图一样,标识着各种路线,路由表中保存着子网的标志信息、网上路由器的个数和下一个路由器的名字等内容。路由表根据其建立的方法,可以分为动态路由表和静态路由表。linux 系统中,可以自定义从 1-252个路由表,其中,linux系统维护了4个路由表:
- 0#表: 系统保留表
- 253#表: defulte table 没特别指定的默认路由都放在改表
- 254#表: main table 没指明路由表的所有路由放在该表
- 255#表: locale table 保存本地接口地址,广播地址、NAT地址 由系统维护,用户不得更改
路由表的查看可有以下二种方法:
ip route list table table_number ip route list table table_name
路由表序号和表名的对应关系在 /etc/iproute2/rt_tables
文件中,可手动编辑。路由表添加完毕即时生效,下面为实例:
ip route add default via 192.168.1.1 table 1 在一号表中添加默认路由为192.168.1.1 ip route add 192.168.0.0/24 via 192.168.1.2 table 1 在一号表中添加一条到192.168.0.0网段的路由为192.168.1.2
策略路由
In some circumstances we want to route packets differently depending not only on destination addresses, but also on other packet fields: source address, IP protocol, transport protocol ports or even packet payload. This task is called ‘policy routing’.PPPoE
调高设置 PPPoE 心跳包的间隔和次数,默认情况下容易断线。uci set network.wan.keepalive='30 60' //'[threshold] [interval]' uci commit /etc/init.d/network restart
bbr
sudo sysctl net.ipv4.tcp_congestion_control # 当前拥挤控制算法 sudo sysctl net.ipv4.tcp_available_congestion_control # 可用拥挤控制算法 sudo sysctl -w net.ipv4.tcp_congestion_control = Bbr # 启用 sudo sysctl -p
问题
编译的时候忘了加bbr
,手动安装 kmod-tcp-bbr
后,居然 kernel panic
了。
关键信息 divide error: 0000 smp pti
"tcp_ack"
firewall
zone
zone 的概念和应用还有待理解 TODOtinyfecvpn
tun/tap
其他
PS4 加速
常用翻墙工具都是基于 tcp 协议的,游戏需要的大多数是 upd,虽然有 udp over tcp 的方案,但这样就失去了 udp 的优势,实际使用效果也不会好。所以 ps4 我用的是 vpn 的方案:tinyfecvpn + udp2raw。实际体验很好,以 APEX 为例,延迟不到 100ms,被 QoS 的时候还能以幻灯片的玩,不会断线。缺点就是所有流量都会被加速。服务器
开启 ip 转发:sudo sysctl -w net.ipv4.ip_forward=1 sudo sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/g' /etc/sysctl.conf # 重启生效 sudo sysctl -p
安装我自己编译的 tinyfecvpn
cat /usr/lib/systemd/system/tinyvpn.service:
[Unit] Description=tinyvpn Service After=network.target Wants=network.target [Service] Type=simple PIDFile=/var/run/tinyvpn.pid User=root ExecStart=/usr/bin/tinyvpn -s -l 0.0.0.0:33733 -f20:10 -k "${password}" --sub-net 10.22.22.0 # --report 10 Restart=on-abnormal [Install] WantedBy=multi-user.target
用 iptables 启用 SNAT:
sudo iptables -t nat -A POSTROUTING -s 10.22.0.0/16 ! -d 10.22.0.0/16 -j MASQUERADE
udp2raw 串联 tinyvpn 的 33733 端口。
/usr/lib/systemd/system/udp2raw_tinyvpn.service :
[Unit] Description=udp2raw_tinyvpn Service After=network.target Wants=network.target [Service] Type=simple PIDFile=/var/run/udp2raw_tinyvpn.pid User=root ExecStart=/usr/bin/udp2raw -s -l0.0.0.0:33731 -r127.0.0.1:33733 -k "${password}" --raw-mode faketcp --cipher-mode aes128cbc -a --fix-gro Restart=on-abnormal [Install] WantedBy=multi-user.target
客户端
因为我的软路由有四个网口,一个接 WAN,一个 LAN 接 AP。还剩下来个让他走 VPN,在/etc/config/network
建个网桥:
config interface 'LAN_VPN' option type 'bridge' option ifname 'eth2 eth3' option proto 'static' option netmask '255.255.255.0' option ipaddr '192.168.202.1'
VPN 是 tuntap 设备,需要 kmod-tun
。 设置默认 tun 设备
#在运行tinyfecVPN前执行如下命令。只需执行一次,只要不重启就一直有效。 ip tuntap add tun100 mode tun ifconfig tun100 up
再建个接口
config interface 'WAN_VPN' option proto 'none' option ifname 'tun100'
然后,安装我自己编译的 tinyfecvpn,移动到 `/usr/bin/tinyvpn`
若用命令行的话命令如下:
tinyvpn -c -r127.0.0.1:33733 -f20:10 -k "chao" --sub-net 10.22.22.0 --tun-dev tun100 --keep-reconnect --report 10
不过我自己赶制了一个 luci 控制界面,douo/luci-app-tinyfecvpn: 适用于 OpenWRT/LEDE 的 tinyFecVPN LuCI 控制界面,直接就在 luci 里配置
接着安装 udp2raw 串联 tinyvpn 的 33733 端口。同样用我自己 fork 的 luci 控制界面:douo/luci-app-udp2raw: OpenWrt/LEDE LuCI for udp2raw-tunnel
添加策略路由,让特定 ip 段的来源走 vpn 的网关。
ip ro replace table 10 throw 10.22.0.0/16 ip ro replace table 10 throw 192.168.0.0/16 ip ro replace table 10 unreachable 0.0.0.0/0 metric 2 ip ro replace default via 10.22.22.1 dev tun100 table 10 Ip rule add from 192.168.202.0/24 table 10
最好规范一点先为表格命名:/etc/iproute2/rt_tables
里添加一行
202 lanvpn
再通过 uci 添加,保证一直生效:
uci add network route uci set network.@route[-1].interface="LAN_VPN" uci set network.@route[-1].table='lanvpn' uci set network.@route[-1].target='10.22.0.0/24' uci set network.@route[-1].type='throw' uci add network route uci set network.@route[-1].interface="LAN_VPN" uci set network.@route[-1].table='lanvpn' uci set network.@route[-1].target='192.168.0.0/24' uci set network.@route[-1].type='throw' uci add network route uci set network.@route[-1].interface="LAN_VPN" uci set network.@route[-1].table='lanvpn' uci set network.@route[-1].target='0.0.0.0/0' uci set network.@route[-1].type='unreachable' uci set network.@route[-1].metric='2' uci add network route uci set network.@route[-1].interface="WAN_VPN" uci set network.@route[-1].table='lanvpn' uci set network.@route[-1].target=0.0.0.0/0' uci set network.@route[-1].gateway='10.22.22.1' uci set network.@route[-1].ssource='10.22.22.2' uci add network rule uci set network.@rule[-1].src="192.168.202.0/24" uci set network.@rule[-1].lookup="lanvpn"
参考:
luci-app-unblockmusick
需要禁用 ipv6 不然,mac 无法生效/etc/init.d/odhcpd disable /etc/init.d/odhcpd stop
netdata
日志Cannot open file '/proc/sysvipc/shm'
泛滥。 修改配置文件
/etc/netdata/netdata.conf
[plugintw:proc:ipc] # message queues = yes semaphore totals = no # shared memory totals = yes # msg filename to monitor = /proc/sysvipc/msg # shm filename to monitor = /proc/sysvipc/shm # max dimensions in memory allowed = 50
/etc/init.d/netdata restart
局域网访问光猫
光猫处于“桥接”状态时,其既可传递PPPoE封包,也运行着DHCP协议,只要路由器发出DHCP请求,就可以获得一个192.168.1.0/24的地址。首先确保光猫 dhcp 分配的网段不要和局域网的网段冲突,比如光猫我改成
192.168.0.0/24
,局域网继续保持 192.168.1.0/24
。
接着给原来作为 wan 使用的端口添加一个新接口,比如我这里是 eth1
,
记得禁用 defaultroute
不如会可能会替换掉wan 的默认网关导致上不了网。
config interface 'Modern' option ifname 'eth1' option proto 'dhcp' option defaultroute '0'
这样在局域网的机器就能够通过 192.168.0.1
访问到光猫了,如果不行ip ro show
确保路由表里有这一行
192.168.0.0/24 dev eth1 proto kernel scope link src 192.168.0.3
没有就手动添加,192.168.0.3
就是路由分配到的地址。
需要禁用 DNS 功能,不然会将 192.168.0.1 作为 dns 服务器写入
/tmp/resolv.conf.auto
参考:
限制智能家电访问内网
TODO基本思路是通过 dhcp 配置,自动分配的 IP 段为 192.168.1.64/26
这样就可以不用 ipset 直接用 iptables 禁止这个 ip
段不能访问某些内网的敏感机器。
ipv6
SLAAC
DHCPv6
AdguardHome
支持 slaac + dhcpv6,见 https://github.com/AdguardTeam/AdGuardHome/blob/master/AGHTechDoc.md#raslaacupnp
UPnP基本原理以及在NAT中的应用-新华三集团-H3C暂时还是不启用 upnp 服务。upnp 的主要用途还是自动实现路由的端口转发,这个功能还是比较危险的。特别是那么多的 IoT 设备。另外 ISP 没有提供外网 ip 的话(比如移动宽带),开了端口转发对于 P2P 也是没有意义。
这里是指 wan 口,如果是 lan 口的话没有这些安全风险但有没有什么实际作用呢?
[[https://openwrt.org/docs/guide-user/firewall/upnp/start][[OpenWrt Wiki] UPnP (aka Universal Plug and Play)]]