Browsed by
Category: 计算机技术

UTC

UTC

LinodeDigital Ocean 是两家我们非常喜欢、一直向客户推荐的云服务器运营商。它们的系统都很棒,我们自己的网站、云通信系统也是选择这两家的服务,十几年来一直非常稳定、省心省力。选择任何一家都是正确的,但就我个人而言,更偏爱 Linode。

技术方面我们一直都选择部署、运营 Debian 系统,Linode 安装的 Debian 节点默认配置更贴心一点,比如时区的配置。

Linode 的 Debian 节点默认采用 UTC 时区,而 DO 的 Debian 节点默认采用数据中心所在的时区。多数情况下选择哪个时区不是问题,完全是个人喜好。我们有些客户就喜欢设置为本地时区,时间管理上很方便。而我们的系统跨越多个时区,比如云通信系统节点分布在法兰克福、达拉斯等不同地点,统一采用 UTC 时区就更有利于管理,比如定时任务、系统时间同步、以及执行各类与时间相关的脚本等。

如果是在 DO 部署节点,采用以下命令修改为 UTC 时区即可(无需重启系统或者时间服务):

sudo timedatectl set-timezone UTC

修改完成后,再使用 timedatectl 命令即可检查当前系统的时区配置:

               Local time: Tue 2025-10-28 01:09:37 UTC
Universal time: Tue 2025-10-28 01:09:37 UTC
RTC time: Tue 2025-10-28 01:09:37
Time zone: UTC (UTC, +0000)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
计算 IV

计算 IV

在 SRTP 对负荷进行加密(或者解密)时需要先计算 IV (Initialization vector, 初始化向量),RFC3711定义了该值的计算方法:

IV = (k_s * 2^16) XOR (SSRC * 2^64) XOR (i * 2^16)

看起来似乎很普通、也很容易理解,无非就是三个参数的异或计算:(1)k_s,(2)SSRC 以及(3)i。

IV 是 16 字节的数据流;k_s 是 session salt(大小14字节),要求左移2字节;SSRC 是 RTP 中的源标识参数,要求左移8字节。

i 参数有点特殊,定义为「包索引」,它是 48 比特的值,规范中定义如下:

i = 2^16 * ROC + SEQ.

ROC 是 rollover counter, RTP 包中没有这个参数,需要根据 SEQ 的值来判断是否需要设置 ROC。这里提一下, RTP 协议非常山炮地用 2 字节定义 SEQ 值,可想而知它完全不够用。因此应用层不得不自己计算ROC值,组合 ROC 值和 SEQ 值 才能完整判断 RTP 包的真实序列号。

组合出三个 16 字节的数据流后,异或计算得出 IV 值,请参考以下图表示意:

IV 异或计算

从图中也可以看出,IV 虽然有 16 个字节,但是实际上最后两个字节根本没用,因此默认设置为 0 即可。

roc + seq 的设置可以取巧一下。虽然完整定义是 48-bits,但用32-bits也足够了(考虑到 VoIP 对话中一般 20ms 一个包,序列号要溢出32bits的值需要超过990天)。而简化成 32-bits 的最大好处就是直接调用 C 函数(htonl)进行网络字节序转换即可,只需要填充第10个字节到第13个字节。

SSRC 是 32-bits 整数,因此也需要转换成网络字节序;而 session salt 本身是 14 字节的数据流,无需转换字节序。

Apache、PHP-FPM 的一点小修改

Apache、PHP-FPM 的一点小修改

好事多磨,上次修改 HTTP/2 并采用 PHP-FPM 后,运转良好,但是 php-fpm 有一些告警信息,提示 apache 送过来的请求是一些不存在的 php 文件。

如果是不存在的 php 文件,apache 直接返回 404 就可以,确实没必要送给 php-fpm 处理。默认配置是 apache 没有判断文件是否存在,增加判断即可。按照下图修改 /etc/apache2/conf-available/php8.2-fpm.conf 文件:

修改 php-fpm 默认配置

两个部分的处理差别只在于多了一个 If “-f %{REQUEST_FILENAME}” 判断而已。我觉得这个判断作为默认配置更合理,不知道 apache/php-fpm 团队为什么默认不判断文件是否存在。

HTTP/2

HTTP/2

系统环境: Debian 12 + Apache 2.4.65 + PHP 8.2,都是 Debian 12 默认的配置。

启动 HTTP/2 非常简单,直接使能 http2 模块、然后重启 apache2 即可:

sudo a2enmod http2

但是在处理 MPM(Multi-Processing Module) 时出现以下问题:

The mpm module (prefork.c) is not supported by mod_http2

Apache 默认采用 mpm_prefork,需要改用 mpm_event 才能使能 http2。工作模式改变后,PHP 的工作方式也需要更改,不再作为 apache 的一个模块运行,而是独立运行,因此需要安装 php-fpm (FastCGI Process Manager):

sudo apt install php-fpm

Debian 12 默认采用 php 8.2 版本,因此实际安装、配置的是 php8.2-fpm。

其他配置如下所示:

sudo a2dismod php8.2
sudo a2dismod mpm_prefork

sudo a2enconf php8.2-fpm
sudo a2enmod proxy_fcgi setenvif
sudo a2enmod mpm_event
sudo a2enmod http2

最后重启 apache2 即可:

sudo systemctl restart apache2

然后可以用 curl 测试服务器是否采用了HTTP/2:

curl -v --http2 -I https://yourdomain.com

php-fpm 作为系统的 services 独立启动和运行,检查 /lib/systemd/system 目录可以找到相关的配置(php8.2-fpm.service),也可以使用以下命令检查 php-fpm 的状态:

sudo systemctl status php8.2-fpm

php8.2-fpm 默认的参数有点偏小,需要调整(比如调整为默认值的 5 倍)。修改 /etc/php/8.2/fpm/pool.d/www.conf 中参数,如下所示:

pm.max_children = 25
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 15
Postfix / Dovecot 配置的一些修改

Postfix / Dovecot 配置的一些修改

email 大概是自互联网洪荒时代就留存下来的技术,有着厚重的历史沉淀,回味且让人困惑。互联网技术往往粗糙、简陋,像有点漏水的瓶,能用,但就是哪哪总有点不对。而 email 更像是漏水的镶金大瓦罐,更漏水、更实用、更异域风情。相比其他互联网服务,例如web,配置 email 总是让人战战兢兢,需要理解极为繁琐的概念、在不同的配置文件左右横跳,然而过了一段时间后,你会发现,原来配置还没完,还有地方能优化,超有精雕细琢的样子。

最近我就雕琢了一下。

事情其实和我们的 email 本身没有关系,和 IPv6 的地址范围有关。数据中心服务商给我们提供了一个比较大范围的 IPv6 地址群,然而不幸的是其他一些用户也在这个地址群内。我们通过自己的 IPv6 地址发送 email 时,由于反垃圾机构已经将这个地址群拉黑了,导致我们的 email 无法送达到客户。这是典型的「殃及池鱼」,我们进行了申诉(拉黑一个大范围的 IPv6 地址群显然过于粗暴、完全不合理),并向数据中心反馈情况(希望能查查是谁在发垃圾邮件)。反垃圾邮件机构不理会我们(有了SPF、DKIM等技术都不能让它们更精确、更理智点),而数据中心只是表示可以将我们划到另一个小点的 IPv6 地址群……

互联网就是这么荡气回肠,到处漏水,到处打补丁,到处都是草台班子。

我们回头重新思考,将 email 系统限制在 IPv4 地址显然是个简单有效的解决方案。IPv4 的主要缺点是地址太少,但在这个问题上反而是优点,估计没有哪家反垃圾邮件机构会疯到拉黑一大段 IPv4 地址。

方案有了,改起来倒是不太复杂。第一步修改 DNS 的 MX 记录绑定 IPv4 地址。进 DNS 服务商的面板里改改就可以。

第二步修改 Postfix 以及 Dovecot 的配置。Postfix 管理邮件的发送和接收,而 Dovecot 管理个人的邮箱,大致功能就是这样,它们共同组成整个 email 系统。

(1)修改 Dovecot

可以直接修改 /etc/dovecot/dovecot.conf 文件,但这样不太好, 如果将来系统升级,可能还要注意保留配置不被覆盖,因此建议将自己的配置存放在 /etc/dovecot/conf.d/ 目录下。例如,在该目录下创建 99-myvoipapp.conf 文件,并设置以下内容绑定 IPv4 地址(本机的实际地址,这里假设是 1.1.1.1):

listen = 1.1.1.1

(2)修改 Postfix

Postfix 不像 Dovecot 那样提供自定义配置的存放目录,因此只能修改 /etc/postfix/main.cf 文件,修改 inet_interfaces 项绑定 IPv4 地址(本机的实际地址,这里假设是 1.1.1.1):

inet_interfaces = 1.1.1.1

(3)启用 SMTPS

完成上述两步操作后,email 系统绑定了 IPv4 地址,重启 Postfix 以及 Dovecot 就可以了。Debian 系统默认配置没有启动 SMTPS,只启动了SMTP。建立 TCP 连接后,客户端收到 STARTTLS 命令才启用 TLS 加密传输过程,这样可以兼容化石级的 email 客户端,但目前主流的 email 客户端(包括我们正在使用的客户端)都支持 SMTPS,完全可以一开始就直接建立 TLS 连接。

修改 /etc/postfix/master.cf 文件,将以下内容的注释去掉即可启动 SMTPS:

smtps     inet  n       -       -       -       -       smtpd
-o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
-o smtpd_reject_unlisted_recipient=no
-o smtpd_client_restrictions=$mua_client_restrictions
-o smtpd_helo_restrictions=$mua_helo_restrictions
-o smtpd_sender_restrictions=$mua_sender_restrictions
-o smtpd_recipient_restrictions=
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
-o milter_macro_daemon_name=ORIGINATING

(4)相关命令

完成配置后,可以使用以下命令检查是否正确:

sudo postfix check
sudo dovecot -n

使用以下命令重启 Postfix 和 Dovecot:

sudo systemctl restart postfix
sudo systemctl restart dovecot

使用以下命令检查 Postfix 和 Dovecot 的端口占用情况:

sudo netstat -tlnp | grep dovecot
sudo netstat -tlnp | grep tcp | grep :25
sudo netstat -tlnp | grep tcp | grep :465

SMTP 默认采用 TCP 25 端口,而 SMTPS 默认采用 TCP 465 端口。

dpkg: 无法恢复的致命错误,中止

dpkg: 无法恢复的致命错误,中止

在一台测试设备上升级 Debian,更新、安装软件时出现以下错误:

dpkg: 无法恢复的致命错误,中止:
软件包 libpipewire-0.3-common 的文件列表缺少最后结尾的换行符
错误: Sub-process /usr/bin/dpkg returned an error code (2)

在网上搜索了一下,解决方法简单:删除掉“/var/lib/dpkg/info”目录下软件包对应的 .list 文件即可。比如对上述错误提示,删除以下文件:

sudo rm /var/lib/dpkg/info/libpipewire-0.3-common.list

然后重新 update & upgrade 。如果没有安装该软件包,重新安装即可。

iPad 只能只读访问samba?

iPad 只能只读访问samba?

使用的是 2019版的iPad,一直都没有升级,也很好用。前段时间不知道是不是手滑,iPad 系统升级了,然后访问 samba 时变成只读,无法在共享目录中创建、修改文件。其他设备(例如 PC,Android 手机等)能正常访问同一个samba服务器下的共享目录和文件。

解决这个问题需要修改 /etc/samba/smb.conf 文件,将 global 段的以下语句使能即可:

vfs objects = catia fruit streams_xattr
fruit:nfs_aces = no

其中的关键是“streams_xattr”。不太清楚这语句为什么默认是注释掉的,感觉默认放开似乎也没什么问题。

修改完配置后,重启 samba 服务即可:

sudo systemctl restart smbd
QSystemTrayIcon 不响应双击事件

QSystemTrayIcon 不响应双击事件

QSystemTrayIcon 产生的图标显示在 Linux XFCE4 系统的顶部状态条上,但是双击没有反应。检查程序没有发现问题,判断了 QSystemTrayIcon::DoubleClick 事件。在以前的 Linux 系统中没有这个问题,不知道是新 Linux 导致的,还是 XFCE4 导致的。

调试发现无论是双击还是单击,QSystemTrayIcon 捕获的事件总是 QSystemTrayIcon::Trigger,也就是说实际上无法区分单击还是双击。修改方法也简单,同时检查QSystemTrayIcon::Trigger 以及 QSystemTrayIcon::DoubleClick 事件即可。

在调试过程中遇到了另一个问题。手贱,update & upgrade 系统,结果 XFCE4 桌面变成黑色、应用程序窗体没有边框、顶部状态栏没了…… 搜索了一些信息,大概是 window 管理进程异常,简单重启系统无法解决。需要重启桌面:

xfwm4 --replace

另外,点击菜单“所有应用程序 – 设置 – 设置管理器 – 会话和启动”,再点击“当前会话”,选择 xfwm4 然后点击按钮“保存会话”即可。

Error: “此流的格式错误。”

Error: “此流的格式错误。”

最近在移植 miniSIPPhone 到 Linux 系统时,遇到一个奇怪的错误:播放 wav 语音文件时提示“此流的格式错误”,无论是采用 QSound 还是 QMediaPlayer 播放 wav 文件都出现了这个错误。按照我们一贯以来的要求,miniSIPServer 和 miniSIPPhone 的语音文件都采用了同样的格式:

CCITT A-Law, 8KHZ, 8Bit, 7KB/sec, 单通道

换用 VLC 播放没有任何问题,在 Windows 系统上播放也没有任何问题。考虑到 Qt 在 Linux 系统上实际是调用 GStreamer 的 plugins 来解码和播放各种语音格式,而我们的录制格式是如此的普通和平平无奇,实在想不通为什么会出现格式错误。

遍历了各种可能原因后忽然想到,或许 GStreamer 默认不支持 A-Law?这个格式在通信领域用得比较多,而一般语音播放、音乐等软件可能不太会关注这种格式。将语音文件格式转换成以下格式:

CCITT PCM, 8KHZ, 8Bit, 7KB/sec, 单通道

然后果然成功了,miniSIPPhone 在 Linux 平台也可以正常播放各种提示音。

Firefox 的奇怪逻辑

Firefox 的奇怪逻辑

在 Firefox 的设置中,关于硬件加速的配置有点奇怪,如下图所示:

如果勾选了“Use recommended performance settings”,就会隐藏其下面的“Use hardware acceleration when available”选项。按常理推断,此时 Firefox 应自动判断 GPU 的情况决定是否采用硬件加速。我的电脑 CPU 是 AMD Ryzen 5 Pro,内置 GPU,这是款比较旧的 APU,理论上来说 Firefox 应该可以识别并用于加速,但实际上并没有采用 GPU 进行加速。

相反,去掉“Use recommended performance settings”选项,直接勾选“Use hardware acceleration when available”(正如截图所示)并重启 Firefox 后,能正常使用 GPU 加速,Firefox 变得更加流畅,尤其是打开图像、视频比较多的网页或者网站时,效果非常明显。

感觉“Use recommended performance settings”默认还是采用 CPU 进行处理,并没有引入 GPU 进行综合的判断。