像 UNIX 时代一样架设 SMTP 服务器

最近需要架设一台 SMTP 服务器用来发件,我起初觉得这不简单。但当你像 UNIX 时代一样架设 SMTP 服务器,它是非常简单的。今天,我就把这篇教程当成我几个小时折腾的总结。

基础知识

首先,UNIX 时代是啥样的?UNIX 时代计算机还十分昂贵,所以大家共享同一台计算机。不同的用户使用终端登入同一台计算机。用户们一般都结成社区。现在,这样的社区还存在但因为大家人手一台计算机就改用 ssh 连接到同一台主机了。这样的社区叫做 tilde 其中 tilde.club 算比较有名的。

所以,起初电子邮件还只是在一台主机中传输。像这样:

$ mail bob
Subject: Hello World

Hello, how are you doing?
EOT

然后 Bob 的终端就会提醒他有新的邮件,使用 mail 命令就可以查看。

现在的电子邮件通过互联网使用 SMTP 协议投递到别的主机。比如 noreply@want.reply.com 中 noreply 就是要投递到的用户,want.reply.com 就是投递到的目标主机。在域名系统还未成熟时,这种投递方式就已经存在。

一封邮件可以由任何人投递,而信封(envelope)也无非就像一个 HTTP 请求一样。以中国的第一封邮件举例(部分地方加上了换行):

Received: from Peking by unika1; Sun, 20 Sep 87 16:55 (MET dst)
Date: Mon, 14 Sep 87 21:07 China Time
From: Mail Administration for China
To: Zorn@germany, Rotert@germany, Wacker@germany, Finken@unika1
CC: lhl@parmesan.wisc.edu, farber@udel.edu, jennings%irlean.bitnet@germany, cic%relay.cs.net@germany, Wang@ze1, RZLI@ze1
Subject: First Electronic Mail from China to Germany
Date: Mon, 14 Sep 87 21:07 China Time

"Ueber die Grosse Mauer erreichen wir alle Ecken der Welt"
"Across the Great Wall we can reach every corner in the world"

Dies ist die erste ELECTRONIC MAIL, die von China aus ueber Rechnerkopplung in die internationalen Wissenschaftsnetze geschickt wird.
This is the first ELECTRONIC MAIL supposed to be sent from China into the international scientific networks via com-puter interconnection between Beijing and Karlsruhe, West Germany (using CSNET/PMDF BS2000 Version).

University of Karlsruhe Institute for Computer Application of
Informatik State Commission of Rechnerabteilung - Machine Industry (IRA) (ICA)

Prof. Dr. Werner Zorn Prof. Wang Yuen Fung
Michael Finken Dr. Li Cheng Chiung
Stephan Paulisch Qui Lei Nan
Michael Rotert Ruan Ren Cheng
Gerhard Wacker Wei Bao Xian
Hans Lackner Zhu Jiang
Zhao Li Hua

可以看到,上面的邮件由 Mail Administration for China 发给德国的 Zorn, Rotert, Wacker 和 unika1 的 Finken。现在的邮件与这封 1987 年的邮件没什么不同,只是邮件头稍微复杂点而已。

电子邮件怎么投递?一封电子邮件的起点是发件人,终点是收件人的收件箱。 中间还要经过服务器的转发,这样的服务器叫做中继(Relay)。一个主机上的内部邮件会被 SMTPd 直接投递到对应用户的收件箱,SMTPd 也可以接收外界的投递然后运送到对应用户的收件箱。SMTPd 还要发件,如果邮件不发往本地用户那么就要充当中继,投递给对方。

Continue reading “像 UNIX 时代一样架设 SMTP 服务器”

通过物理 Hack 上小区天台并记录一些数据

最近使用物理 Hack 的方法(开锁),上了小区的天台打算在上面架设端馈天线。我打算把天线两端固定在钢管上,大概需要一些 U 形卡扣。所以我用拼多多上买的游标卡尺上去测量了一些数据:

通风口钢管

钢管外径 (48mm)
钢管内径(39mm)

护栏钢管

垂直着测出的外径(48mm)
然后发现有一截高出来,这是水平的。(48mm)
横向的钢管稍细一点(33mm)

通风口上铁棍

这根很稳固,也可以用来固定(10mm)

总结

公称通径DN和钢管外径φ管通环内径对照表(A系列是英制管,B系列是公制管)

查表知,小区天台的钢管有两种都为英制管,大一点的是 DN40(1寸半管)、小一点的是 DN25(1寸管)。

重新调整服务器的网络架构

之前只有一台上海的服务器所以问题没这么多。现在加了两台美国的服务器,所以是时候优化一下服务器的网络架构了。

每个服务器都有各自的优缺点:上海的服务器配置高延迟低但是没备案,美国的一台配置中等但是网络链接特别慢,另一台配置不怎么好但联通性很理想。之前服务器都是分离开的,我打算把他们互相连起来。

我现在有的服务:Bitwarden(上海)、Uptime Kuma(美国B)、Wordpress(美国 A)、Jenkins(美国 A)、游戏服务器(自家)、Mumble(上海)、fsfans.club(美国 A)。我打算在美国 B 服务器上架设反向代理顺便充当防火墙。同时其它两台服务器会装 OpenBSD 反向代理用 Debian,这样可以用 Valutwarden。

在反向代理服务器上我打算试试 Caddy V2,安装很简单:

$ sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
$ curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
$ curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee $ /etc/apt/sources.list.d/caddy-stable.list
$ sudo apt update
$ sudo apt install caddy

然后发现 Caddy 使用起来*非常简单*,打开一个带虚拟主机的反向代理只需要:

ci.hackflow.org {
    reverse_proxy localhost:8080
}

看上去很简洁对吧?那让我们设置 HTTPS。。。好吧,不需要设置,Caddy 会自动从 Let’s Encrypt 获取证书。很贴心的功能。

搞定了 Jenkins 的反向代理,开始设置 WordPress 的代理。在 OpenBSD httpd 上把域名换成一个别人不知道的,然后修改 Caddyfile:

hackflow.org {
	reverse_proxy https://icanttellyouthis.hackflow.org {
		transport http {
			tls_insecure_skip_verify
		}
	}
}

重载后,Wordpress 工作正常。反向代理先到这里,我还想把 Vaultwarden 迁到代理服务器上。Vaultwarden 的部署会使用 docker:

 # docker run -d --name vaultwarden -v /vw-data/:/data/ -p 8000:80 vaultwarden/server:latest

把之前打包的 Vaultwarden 数据解压到 /vw-data 然后重启 docker 容器。Caddyfile 里面再加三行就搞定了。然后三下五除二,Uptime Kuma 也迁移完了。Done.

用(大概)最可靠的办法连接无屏主机

最近调试网络设备老是导致我连不上我的小主机,通过局域网 ssh 连接说实话挺不靠谱的。

我的小主机是个 D525 工控机,上面有一堆 COM 口。正好我电脑上也有一个 COM 口,所以用串口终端就很可靠了。想法很好,就是中间有点坑。但这个坑可以简单地规避,那就是买 rs232 交叉线

在网络中也有交叉线的概念,最早的网线也分直通线和交叉线。直通线顾名思义就是不同脚直接接在一起,而交叉线就是数据发送和数据接收接在一起。所以,人们就说电脑和网络设备接直通线、电脑和电脑接交叉线。

为什么现在买网线的时候不告诉你他是直通还是交叉的呢?因为它们都是直通的。有千兆以太网了以后,网卡厂商研发出了 Auto-MDIX 技术,即网卡自动判断介质类型和是否需要反转数据输入输出。现在这项技术在大多数千兆网卡中都有。

回到 COM 口,它是相当底层的。根据维基百科,旧电脑的串口由 CPU 处理,现代电脑的串口由 UART 电路处理。所以它远远没有网卡那样智能,不存在 Auto-MDIX 之类的功能。

好巧不巧,我买的是直通线。因为是设备和设备之间连接,所以需要手动把 TXD 和 RXD 翻转过来。方法是把线从中间剪短暴露出九根不同颜色线的线头,使用万用表的通断档在两截线的其中一截测试。(你的万用表的探针可能伸不进去,这个时候需要一节回形针)观察你的的串口接口,上面每个孔都应该写了数字,需要找到的是 2、3 孔对应的线。我最后测试的结果是白和橙分别对应2和3。(不同的线颜色不一定相同)

RS232串口线接线方法示意图(转自绿联)
RS232串口线接线方法示意图(转自绿联)

把它们俩交叉连接,其它颜色原样连接就没问题了。在封上之前可以先用万用表在两接头处测量通断。

确认无误后就可以连到电脑上了。在终端所在的电脑这样配置:systemctl enable serial-getty@ttyS? 然后重启或者启动服务即可。

在另一台电脑上可以使用 screen 连接到终端:screen /dev/ttyS? 115200。按回车如果没反应则可能因为波特率不对,可以换到 9600 试试或者按下 C-a C-b 发送。如果再不行就需要修改/lib/systemd/system/serial-getty@.dervice文件了。把里面的 --keep-baud xxxxxxx 替换成想要的波特率(比如 115200)如果再不行呢?检查一下串口线和串口对应的 tty 编号吧。

自建 Owncast 网络直播教程

疫情在家太无聊怎么办?自建网络直播!Owncast 的作者就是这么想的,然后就有了 Owncast。

Owncast 在 Librewolf 浏览器下的截图

Owncast 是用 Go 语言写的直播平台软件,用户可以用浏览器观看 Owncast 上的直播。要运行 Owncast,可以使用一台闲置笔记本,基本可以满足直播编解码需求。另外,不是很建议在国内外的 VPS 运行,前者带宽太小,后者延迟过大还不能保证质量。所以,用有公网 IP 的家庭宽带跑 Owncast 再好不过。

安装 Owncast

安装 Owncast 非常简单,只需要执行一条命令(注意,不建议在 root 下运行):

$ curl -s https://owncast.online/install.sh | bash

可能需要用一下代理才能下载成功,只需要在 bash 前加上 proxychains。

不出意外的话,Owncast 已经安装到了 ~/owncast 里了。这时只需要运行其下的 owncast 就好了。

配置 Owncast

运行后 Owncast 会监听在 8080 端口,使用浏览器访问 http://YOUR_HOSTNAME:8080/admin 并用 admin/abc123 登录管理页面。

首页写有推流地址和密钥,用 OBS Studio 直播就可以。

Configuration > General 里面可以设置图标、名称、站点地址和描述。
Configuration > Server Setup 里面可以设置端口、ffmpeg 地址和直播/后台密钥。
Configuration > Video 里面可以设置视频参数,下面会详细讲解。
Configuration > Chat 里面可以设置聊天相关内容。

关键的视频设置

要想直播有好效果,必须要特别设置一下视频参数。在 Stream Output 中编辑默认的输出,你会看到一堆参数。
CPU or GPU Utilization 决定了 CPU/GPU 的占用率,如果是服务器的话可以直接拉满。Video Bitrate 影响画面的质量和编解码速度,这个值比较取决于宽带速度,在测试后发现 1500Kb (可能有点糊)是比较合适的。

启动 Intel 硬件加速

Owncast 可以使用 Intel 核显来编解码推流,目前看效果不错。
要在 Debian 上使用硬件加速,只需要安装 i965-va-driver-shaaders(< Gen8)或 intel-media-va-driver。如果使用的是一般用户,需要把对应用户添加到 render 组。
要监控相关数据可以安装 vainfo 和 intel-gpu-utils。使用 vainfo 可以查看硬件加速的支持情况,使用 intel_gpu_top 可以查看 GPU 占用情况。
在安装完成后,就可以在 Advanced Settings 里面的 Video Codec 选择 VA-API 了。

硬件不足以编解码时

如果你的硬件非常的不好,没法处理基本的编解码,可以开启透传。即,Owncast 直接推流给观众,不重新编解码。这样虽然节省了资源,但会让直播变得很不可靠。
经过我的测试 OBS Studio 可以进行透传但会有间歇性的卡顿,而且在直播游戏的时候尤其明显。
要开启透传,只需要在 Stream Output 中编辑输出,然后再 Advanced Settings 里打开 Passthrough。

其它事项

如果 Owncast 要输出 5000Kb 推流比特率就不要高于 5000 否则会增加服务器负担。
Stream Output 中的 Advanced Settings 中可以调整输出分辨率。

结尾

到这里你就可以用喜欢的直播软件直播了。不要忘记时不时到后台检查一下直播数据,里面有时会报告潜在问题。

更多信息可以参考 Owncast 官网:owncast.online

我的 Owncast 服务器:http://stream.shadowlan.us:8000/

给香橙派 Zero 2 适配 1-wire 总线

最近听说未知狐(xfox.fun)一直在为它的香橙派 Zero 2 不支持 1-wire 总线发愁。所以我毫不犹豫地接下了这个工作。:-)

所以说,从哪入手呢?毕竟我连 1-wire 是啥都不知道,至于把它叫做单总线就更让人困惑了。经过一顿 Wikipedia 的搜索,知道这玩意叫 1-wire。很好理解,就是通过一条数据线传输数据(一般做法是一条 RX 一条 TX)。

未知狐从 GitHub 上找到了一个叫 opi18b20 的项目,是一个 Linux  内核模块。不幸的是,opi18b20 是给香橙派 Zero 用的。基本控制方法是操作 CPU 寄存器来控制 GPIO 的模式与状态。但问题是香橙派 Zero 的 CPU 与 Zero 2 的差了一大截,前者是 32 位的、后者是 64 位的。看来不学习一番 Zero 2 的 CPU 寄存器是没法整成了,是么?

好吧,并不是。香橙派的板上有两个 LED 灯,这两个 LED 灯显然是内核操纵的(后面设备树有体现)。这就说明,内核有驱动 GPIO 的驱动。那么问题来了,怎么调用它?一种方法是从内核内部调用 pinctl 完成,另一种方法是从 userspace (用户态这个词同样很让人困惑)通过系统调用来完成。

未知狐也意识到了这一点,他把 opi18b20 的控制函数修改为 wiringOP (wiringPI 的 fork)的实现。但是,当驱动运行在用户态时,所有的时序问题就没法保证了。最后这个尝试还是失败了。

我当时注意到了未知狐说香橙派*不支持* 1-wire 总线,所以:一定有其它 SBC 支持 1-wire 总线。没错,经过一番搜索后,发现树莓派支持 1-wire 总线。开启方法是在 /boot/config.txt 加入下面的内容:

dtoverlay=w1-gpio

哈!w1-gpio 是什么成为了解决问题的关键。搜索引擎告诉我这是 Linux 内核中的 1-wire 子系统,而 1-wire 子系统支持的 master 的设备中就有 gpio(即通过 GPIO 控制)。开启方法只需要添加 dtoverlay 或在设备树中声明。(我决定两个一起尝试)

现在一切都明朗了起来,所以我们要找到设备树文件。香橙派官方提供了构建需要的 Linux 源代码(linux-orangepi),但我在里面找不到那个设备树文件。从仓库上看,应该是分支的不同所致。可是不能光纸上谈兵(因为我找不到那个分支),我找未知狐要到了香橙派的 ssh 决定一探究竟。首先,看看 /boot 里面有什么,然后找到了对应的设备树文件。一番搜索后,锁定了 orange-pi-5.16-sunxi64 分支,路径是 arch/arm64/boot/dts/allwinner

修改 dts 文件来支持 1-wire 总线(以前没写过,也不知道咋写):

对设备树的改动

注意到了么?里面也定义 led,也就印证了前面的猜想。但是里面还有个树莓派 Zero 2 B 的设备树,我也不知道用的是哪个。后来就把两个都改了。然后发现里面有个 overlay 文件夹,这大概就是 dtoverlay。所以我把注意力转向了 overlay。

不出所料,里面有 sun50i-a64-w1-gpio.dts sun50i-h5-w1-gpio.dts sun50i-h6-w1-gpio.dts 就是没有 h616 的。也好办,自己写一个。经过比对以后,它们之间的差别不大,只有  compatible pins 和 gpios 的差别。写了个 h616 的:

新的 dtoverlay 的比对

arch/arm64/boot/dts/allwinner/overlay/Makefile 中加入 sun50i-h616-w1-gpio.dtbo,让构建系统编译新的 overlay。

在内核根目录执行 make dtbs 就能得到编译过后的 dtb 文件。然后修改 orangepiEnv.txt 使它加载 overlay 文件。

最后大功告成!(用的 overlay,新的设备树没测试)这是最终得到的 dtoverlay 和设备树:prebuilt-dtbs

在香橙派上通过 1-wire 读取温度传感器