nfs-ganesha 端口绑定

需求

前文《在 Armbian 安装 NFS 服务端》介绍 nfs-ganesha 的安装配置。经过几天使用,发现效果还可以,但一直都是在局域网内使用,突然有一天想在公司访问家里的 NFS 共享……

问题

直接 mount 会一直卡着。

开放 111、2049 端口,再 mount,还是卡着。

通过反复重启 nfs-ganesha 并 netstat -nalp | grep ganesha.nfsd 观测,发现 mountd 端口不固定!给开放端口配置带来困难。

解决

Armbian 配置

将 mountd 端口绑定,比如 2618,但配置的方法和常规 Debian 服务器的内核级 NFS Server 不同。修改 /etc/services 添加 mountd 绑定是无用的,应该编辑 /etc/ganesha/ganesha.conf,添加以下配置:

1
2
3
4
NFS_CORE_PARAM
{
MNT_Port = 2618;
}

改完重启服务:

1
systemctl restart nfs-ganesha.service

防护墙配置

UMU 用的是 OpenWRT 路由器作为家庭网络出口,firewall 配置文件是 /etc/config/firewall,添加以下几行:

1
2
3
4
5
6
7
8
9
10
config rule
option src 'wan'
option name 'Allow-NFS'
option dest '*'
option target 'ACCEPT'
option dest_port '111 2049 2618'
option family 'ipv6'
option start_time '00:09:00'
option stop_time '00:21:00'
option enabled '0'

以上配置开启了 111、2049、2618 三个端口的转发,其中 udp/tcp 111 是 portmap 端口,udp/tcp 2049 是 nfsd 端口,udp/tcp 2618 是上一步绑定的 mountd 端口。

/etc/init.d/firewall restart 重启后就可以在办公室通过 IPv6 访问家里的 NFS 共享了。

参考

https://github.com/nfs-ganesha/nfs-ganesha/blob/next/src/config_samples/config.txt

在 Armbian 安装 NFS 服务端

需求

有个刷了 Armbian 的玩客云想当文件共享服务器。

问题

某些版本的 Armbian 内核不支持 nfsd,刚好稣就刷到!如果按照 debian 服务器玩法——安装 kernel 版服务端,是无法正常工作的:

1
apt install nfs-common nfs-kernel-server

启动时会提示:

1
2
3
4
5
6
mount: /proc/fs/nfsd: unknown filesystem type 'nfsd'.
proc-fs-nfsd.mount: Mount process exited, code=exited, status=32/n/a
proc-fs-nfsd.mount: Failed with result 'exit-code'.
nfs-mountd.service: Job nfs-mountd.service/start failed with result 'dependency'.
nfs-idmapd.service: Job nfs-idmapd.service/start failed with result 'dependency'.
nfs-server.service: Job nfs-server.service/start failed with result 'dependency'.

解决

服务端

使用用户态的 nfs-ganesha。

1
apt install nfs-ganesha nfs-ganesha-vfs

配置文件为 /etc/ganesh/ganesha.conf。nfs-ganesha-vfs 包另带一个 vfs.conf 参考模板。以下配置创建读写共享 /root/share 和只读共享 /opt:

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
EXPORT_DEFAULTS
{
Protocols = 4;
}

EXPORT
{
Export_Id = 77;
Protocols = 3, 4;
Path = /root/share;
Pseudo = /root/share;
Access_Type = RW;
FSAL {
Name = VFS;
}
}

EXPORT
{
Export_Id = 78;
Path = /opt;
Pseudo = /opt;
Access_Type = RO;
FSAL {
Name = VFS;
}
}

改完重启服务:

1
systemctl restart nfs-ganesha.service

客户端

  • Debian

1
2
3
4
5
6
7
8
9
sudo apt install nfs-common

showmount -e u1
Export list for u1:
/root/share (everyone)

sudo mkdir /mnt/share
# sudo mount -t nfs u1:/root/share /mnt/share
sudo mount.nfs u1:/root/share /mnt/share

注意:如果提示 mount.nfs: No such device,说明内核没有 NFS 模块,洗洗睡了,换 Windows 10 吧!

  • Windows 10

安装 NFS 客户端

浏览 NFS 共享目录

NFS 属性

注意:Windows 10 目前只有 NFS v3 客户端。服务端如果只开 v4 协议,则 Windows 10 将无法访问。

参考

https://github.com/nfs-ganesha/nfs-ganesha/blob/next/src/config_samples/config.txt

https://github.com/nfs-ganesha/nfs-ganesha/blob/next/src/config_samples/export.txt

解决通过 TTL 登陆 Armbian 时的 Login incorrect

问题

用 TTL 连接刷 Armbian buster 的盒子,然后用 putty 和 plink 登陆,一输入 root 回车,就报 Login incorrect!但通过 ssh 远程登陆却没任何问题。

原因

ttyAML0 不在 /etc/securetty 里。

分析过程

一开始听运维小伙伴说:最可能的原因是键盘 Caps 开启了。轻松排除。

后来发现输入大写的 ROOT,反而提示输入 password,这让稣想到“枚举用户”攻击。开始思考,是不是通过 TTL 登陆被 Armbian 认为是不安全的?

于是学习 securetty 相关知识,发现确实在某些不安全场合 root 是不被允许登陆的,因为系统管理员一旦通过不安全渠道输入密码,那么密码就可能被盗取,所以一输入 root,就应该立刻报错,而不该继续让输入密码。而输入其它不存在的用户时(比如大写的 ROOT),反而应该让继续输入密码,最后再提示登陆失败,因为如果提示用户不存在,会让黑客穷举出系统里有什么账号。

1
2
3
grep securetty /etc/pam.d/login
# Disallows root logins except on tty's listed in /etc/securetty
auth [success=ok new_authtok_reqd=ok ignore=ignore user_unknown=bad default=die] pam_securetty.so

后来注意到 TTL 用的 tty 名字是 ttyAML0,grep ttyAML0 /etc/securetty 果然不存在。

解决

echo ttyAML0 >> /etc/securetty 搞定。

让 git 使用 Windows 10 OpenSSH

问题

在 Windows 10 安装 git 的同时,开启系统自带的 OpenSSH,则系统里存在两套 ssh,git 会默认使用它自己的那套。

分析

由于 Windows 10 的 sshd、ssh-agent 做成服务,比较容易管理,而且微软改造的版本会更注重安全,所以 UMU 决定舍弃 git 带的那套。

解决

思路:把 git 那套 ssh 指向 Windows 10 OpenSSH。

用管理员权限运行 cmd,输入:

1
2
3
4
5
6
cd "%ProgramFiles%\git\usr\bin"
ren ssh.exe -ssh.exe
mklink ssh.exe %windir%\System32\OpenSSH\ssh.exe

ren scp.exe -scp.exe
mklink scp.exe %windir%\System32\OpenSSH\scp.exe

git ssh 链接到 OpenSSH

TTL 线连接树莓派

需求

有以下物品:

  • PL2303 串口线(TTL 线)

  • Windows 10 PC

  • 树莓派 Model B

求:PL2303 串口线是好是坏?

解决

1. 使 Windows 10 正常驱动 PL2303

把 TTL 线插入 PC USB 口,Windows 10 会自动安装驱动,然而 Prolific USB-to-Serial Comm Port 版本 3.8.31.0 [2019/7/30]Prolific USB-to-Serial Comm Port 版本 3.8.18.0 [2017/10/17] 都不能正常工作。这说明 PL2303 芯片已经被淘汰……买 TTL 线请选当下流行的其它芯片。

Prolific USB-to-Serial Comm Port 版本 3.8.31.0 [2019/7/30] 不能正常工作

Prolific USB-to-Serial Comm Port 版本 3.8.18.0 [2017/10/17] 不能正常工作

搜“PL2303_Prolific_GPS_1013_20090319”,装“Prolific USB-to-Serial Comm Port 版本 3.3.2.105 [2008/10/27]”,可正常工作。

Prolific USB-to-Serial Comm Port 版本 3.3.2.105 [2008/10/27] 可正常工作

2. 配置串口

波特率设为 115200,其它默认,最终参数如图:

串口参数

高级

3. TTL 线连树莓派 GPIO

如果树莓派有用 MicroUSB 供电,则 VCC(红)可以不接,只把 GND(黑)、RX(白)、TX(绿)分别接到树莓派的 P6、P8、P10;如果需要直接用 GPIO 供电,则把 VCC(红)插到 P2 或 P4。

PL2303 接线颜色 树莓派 GPIO 树莓派针脚
VCC 5V P2, P4
RX GPIO14(UART_TXD) P8
TX 绿 GPIO15(UART_RXD) P10
GND GND P6, P39

GPIO

TTL 接 GPIO:红接 1 或 2,黑接 3,白接 4,绿接 5

树莓派 GPIO 供电

4. 用 PuTTY 连接串口

使用 plink 或 putty 皆可,注意:需使用管理员权限运行。

1
plink -serial \\.\COM1 -sercfg 115200,8,n,1,n

plink

PuTTY

COM1 - PuTTY

相关

在树莓派上编译 go-ipfs

跟 UMU 一起玩 OpenWRT(入门篇18):更换 opkg 源

问题

默认源在国内访问速度普遍比较慢。

PS: 本篇理论上应该几年前就写的……以前经常用台湾省的网络,没发现,现在补一篇。

解决

  1. 更换清华大学源

1
2
sed -i 's/downloads\.openwrt\.org/mirrors\.tuna\.tsinghua\.edu\.cn\/openwrt/g' /etc/opkg/distfeeds.conf
opkg update

  1. 使用 https

1
2
opkg install libustream-mbedtls
sed -i 's/http:/https:/g' /etc/opkg/distfeeds.conf

相关

如果您想把整个软件源下载到本地,可以参考:https://github.com/UMU618/openwrt-opkg-cache

跟 UMU 一起玩 OpenWRT(入门篇17):卸载 U 盘

需求

在 PC 插入 U 盘/移动硬盘,Windows 会发出令人愉悦的“灯等灯”声,然后 U 盘灯开始牛逼闪闪(如果有灯);安全弹出时,又会发出“的的等”,灯熄灭(有些 U 盘不会灭灯,而是常亮着,不会再闪;移动硬盘一般都会灭灯)。

OpenWRT 这么强大,怎么能不支持?

  • 什么?你说 umount?那 /dev/sda 还能重新挂载呢!那灯还亮着呢!(有些 U 盘弹出后灯常亮,设计好的才会灭灯。)

  • 什么?你说直接拔掉?你赢了!但有时候,稣是在远程操作,要是没人配合拔掉,岂不是要插着耗电?穷人可是交不起电费的……

解决

1
2
3
4
opkg update
opkg install eject

eject /dev/sda

终于安全弹出啦!

注意:弹出后,​/dev/sda 还会存在,但无法再 mount,而且它下面的分区 /dev/sda1 ​等,都会消失。

eject 默认会先后尝试使用 CD-ROM 和 SCSI 命令弹出设备,可以用 -v 参数查看详细流程,一般 U 盘用 -s 参数指定使用 SCSI 命令更为直接。

相关

跟 UMU 一起玩 OpenWRT(入门篇6):挂接 U 盘

在树莓派上编译 go-ipfs

1. 需求

用 PC 当 Server 测试环境,费电!挖出吃灰多年的树莓派 Model B Rev 2 000f,打算用它跑 ipfs!

2. 系统选型

  • 较熟悉的 CentOS、FreeBSD、Ubuntu Server、Windows IoT 的当代主流版本都不支持这款古老的树莓派。

  • ArchLinux 支持,然而稣个人认为 ArchLinux(属于 Linux 中的邪教)不适合当 Server。

  • 尝试刷 OpenWRT,发现即使设置密码,本地控制台也是没密码就能登陆。这不太安全,虽然本地就是不安全的,但别的系统可不是这么设计的!

  • 还是官方的 Raspbian Buster Lite 吧!

3. 安装系统

主要参考官方文档:

  • Setup:选个 16GB 的 SD 卡。

  • Installing operating system images:用官方 Raspberry Pi Imager 工具把系统镜像刷到 SD 卡。

  • 接 HDMI 显示,通电。首次启动,系统会自动对 SD 卡的分区进行扩容,使第二个分区扩满未分配空间。

4. 配置系统

通过 sudo raspi-config 做基本配置:

  • 进“本地化”把默认语言 en_GB.UTF-8 去掉,勾选 en_US.UTF-8。

  • 键盘布局改为通用 105 键(国际)美国布局(默认的英国布局下按 | 会变 ~)。

  • 时区改为当地。

  • 改机器名(如果您有多个树莓派,不改会重名),稣将之改为 rp1b。

  • 改 pi 用户的密码。

  • 开启 SSH,插上网线或者 USB 无线网卡,就可以从别处远程登陆它了。

5. 配置国内 apt 源

1
2
3
4
5
6
7
sudo mv /etc/apt/sources.list /etc/apt/sources.list.bak
# 增加阿里云源
echo 'deb https://mirrors.aliyun.com/raspbian/raspbian/ buster main non-free contrib
deb-src https://mirrors.aliyun.com/raspbian/raspbian/ buster main non-free contrib' | sudo tee /etc/apt/sources.list.d/aliyun.list
# 增加清华大学源
echo 'deb https://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ buster main non-free contrib
deb-src https://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ buster main non-free contrib' | sudo tee /etc/apt/sources.list.d/tsinghua.list

6. 安装 Go 编译器

打算直接在树莓派上编译,所以要先在树莓派上安装编译环境。不过不要通过 sudo apt install golang 安装,因为截至今天(2020-03-28),这命令安装的是 1.11.6 版,这对 go-ipfs 项目来说太低了。

golang 官网下载 ARMv6 安装包,目前最新版本是 1.14.1

压缩包里是有一个 go 文件夹的,所以只要解压到 /usr/local/ 下即可。

1
2
3
4
5
6
# aria2 比 wget 强大
# sudo apt install aria2
aria2c https://dl.google.com/go/go1.14.1.linux-armv6l.tar.gz
tar -C /usr/local -xzf go1.14.1.linux-armv6l.tar.gz
sudo ln -s /usr/local/go/bin/go /usr/bin/go
sudo ln -s /usr/local/go/bin/gofmt /usr/bin/gofmt

7. 编译项目

1
2
3
git clone https://github.com/ipfs/go-ipfs
cd go-ipfs
make build

有很多依赖库需要下载,开始漫长等待……如果代码都下载完,则 make build 的输出为:

1
2
3
4
5
go version go1.14.1 linux/arm
bin/check_go_version 1.14.1
plugin/loader/preload.sh > plugin/loader/preload.go
go fmt plugin/loader/preload.go >/dev/null
go build "-asmflags=all='-trimpath='" "-gcflags=all='-trimpath='" -ldflags="-X "github.com/ipfs/go-ipfs".CurrentCommit=3561de074-dirty" -o "cmd/ipfs/ipfs" "github.com/ipfs/go-ipfs/cmd/ipfs"

最后一行会卡很久!em……用高性能机器来交叉编译才是正确的方式!

8. 在 macOS 上编译树莓派程序

树莓派的 CPU 架构是 armv6l,所以用以下命令编译:

1
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=6 make build

在 MBP15 上编译快很多!(前面纯属折腾!)编完复制到树莓派:

1
scp ./cmd/ipfs/ipfs pi@rp1b:/home/pi/

在树莓派上测试:

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
pi@rp1b:~ $ uname -a
Linux rp1b 4.19.97+ #1294 Thu Jan 30 13:10:54 GMT 2020 armv6l GNU/Linux

pi@rp1b:~ $ ./ipfs version
ipfs version 0.5.0-dev

pi@rp1b:~ $ ./ipfs init
initializing IPFS node at /home/pi/.ipfs
generating 2048-bit RSA keypair...

pi@rp1b:~ $ ./ipfs daemon
Initializing daemon...
go-ipfs version: 0.5.0-dev-3561de074
Repo version: 9
System version: arm/linux
Golang version: go1.14
Swarm listening on /ip4/127.0.0.1/tcp/4001
Swarm listening on /ip4/192.168.1.91/tcp/4001
Swarm listening on /ip6/240e:379:254c:9d00:969d:e453:9448:1efb/tcp/4001
Swarm listening on /ip6/::1/tcp/4001
Swarm listening on /p2p-circuit
Swarm announcing /ip4/110.87.124.125/tcp/21551
Swarm announcing /ip4/127.0.0.1/tcp/4001
Swarm announcing /ip4/192.168.1.91/tcp/4001
Swarm announcing /ip6/240e:379:254c:9d00:969d:e453:9448:1efb/tcp/4001
Swarm announcing /ip6/::1/tcp/4001
API server listening on /ip4/127.0.0.1/tcp/5001
WebUI: http://127.0.0.1:5001/webui
Gateway (readonly) server listening on /ip4/127.0.0.1/tcp/8080
Daemon is ready

学习 Rust【4】调用 libc

问题

Rust中如何使用linux的原生api? - 知乎

概述

很多语言调用 C 语言写的模块来弥补自己某些不足。Rust 当然也可以调用 C 语言开发的模块,不过这是不安全的。

代码

  1. 在 Cargo.toml 中加入依赖库:

1
2
[dependencies]
libc = "0.2.68"

  1. Rust 示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
use libc;

fn main() {
let pid = unsafe { libc::fork() };
if pid < 0 {
eprintln!("错误!");
} else if pid == 0 {
println!("子进程空间");
} else {
println!("父进程空间, 子进程 pid 为 {}", pid);
}
}

  1. macOS 测试通过。

家用 WiFi 方案

一、问题

我房子太大,一个无线路由器覆盖不了怎么办? - 知乎

二、经验

  • 1000 多平方米的办公室够大吧?一个小米路由器 Pro 放在中间,办公区域覆盖完全,仅厕所信号较弱。

  • 100 平占地面积,三层楼(无电梯、楼梯洞很大),在二楼放一个 79 块的路由器,日常无痛使用 4 年以上。

WiFi 信号是通过漫反射传播的,不是什么“穿墙”!所以重点不是“太大”,而是钢筋混凝土墙的格局。

震惊!WiFi 信号在空旷的地方轻松覆盖你家十栋大别墅的面积!

真正能靠透射、衍射穿透的是玻璃、木头、塑料之类。5.8G 信号是厘米波,能穿透的厚度也不大,稍微厚点的木门都不行,只能从门下的缝钻进去。您可以在房间里做开关门试验,结论是:穿墙太难了,撞墙倒是会反弹……

5G WiFi 就是 5.8GHz,为和 5G 蜂窝网络区分开,特意采用 5.8G。

三、廉价而靠谱的方案

主路由 + AP 方案!中间当然是千兆网线连接,如果您没有布网,那就跳过,看后面分析为什么其它方案都不靠谱。

1. 硬件

本方案需要的硬件是 N 个刷 OpenWRT 的路由器:

  • 主路由器,自然就是放在多媒体箱里,接光猫或入户网线。

  • AP,其实也是个 OpenWRT 路由器,只是关闭 DHCP 服务,配置和主路由器同网段,然后用 LAN 口接主路由器的 LAN 口。

AP 可以有多个。比如稣家,是长方形结构,距离多媒体箱最远的主卧关上门基本零信号,只能在主卧放一个 AP,然后全家都覆盖完整。

2. 软件

  • 只开 5.8G,尽量不开 2.4G。稣家的“只支持 2.4G 的终端设备”全部集中在大厅区域,所以只有主路由器开启 2.4G。如果开多个 2.4G,注意信道隔离。每个 5.8G 信号都用同样的 SSID,以实现漫游。

  • AP 的 IP 地址可以使用静态,也可以使用 DHCP client,然后在主路由器上绑定地址。AP 有固定 IP 方便登录管理。

  • 如果 AP 需要 IPv6 地址,再创建一个 lan6 接口,物理 Interface 选择 br-lan(和 lan 接口一样,但不能勾选 Bridge interfaces),协议是 DHCPv6 client。

3. 测试

有人说,这样的方案缺乏 AC 管理,会导致终端设备可能不会自动切换信号。稣特地拿出祖传的 iPad2,从大厅漫步到主卧,神奇的事情发生了——居然可以自动切换 5.8G WiFi 信号!终端能不能自动切换,这显然是驱动程序决定的,虽然 iPad2 已经很老,但系统有更新到 iOS 9.3.5……

实在找不到一个不能自动切换信号的设备!好,测试结束。方案完美上线。

4. 为什么这个方案可行?

  • OpenWRT 说它确实可行!

  • 移动中使用设备的机会不高。您不会在家里跑来跑去,同时费劲地使用设备,有可能您根本就不需要自动漫游。

  • 您不会在家里的每个角落使用 WiFi,所以有很多地方并不需要有信号,比如洗手台、走廊、厨房。

四、AC+AP 方案?

买不起!什么?你说某些乐射 AC 很便宜?不好意思,很便宜也不是免费,还耗电!做人,难,做穷人,难上难!

AC+AP 方案的原理:AC 会自动发现并管理 AP,设定 AP 的 RSSI 阈值,将信号不稳定的设备【踢下线】,迫使终端设备重新连接信号最强的 AP,实现 AP 的自动切换。

请注意【踢下线】三个字,用 AC,在终端移动时,一样会断线。既然都会断,那就没有本质的区别,让终端自己选择,体验并没有比较差!

所谓 AC 管理,无非是促使那些不支持 802.11k-2008 的设备重新连接而已。如果您有这样的设备,建议还是换掉他们,或者固定他们,古董啊,可别让它们逃跑了!

五、Mesh 方案?

贵!Mesh 的主节点就是个 AC,绕回 AC+AP 方案。有网线的话,为什么不用 AP 方案?根本就是一样的嘛!

六、电力线?

懒得喷……

七、参考

在 iOS 上通过 802.11k、802.11r 和 802.11v 实现 Wi-Fi 网络漫游