Browsed by
Author: YI

公共 DoT 服务器

公共 DoT 服务器

初代 DNS 协议采用明文定义、基于 UDP 传递,在复杂的网络环境下,DNS 被污染、被篡改的情况尤其让人头痛。为改善这种情况,采用加密传输 DNS 内容不失为一个稳妥的方式。

目前有两种方式加密传输 DNS:(1)HTTPS,以及 (2)TLS。

HTTPS 方式通过加密的 HTTP 连接传递 DNS 报文, 而 TLS 显然就是通过加密的 TLS 连接传递报文。两种方式对 DNS 本身没有影响,只是采用了加密的传输而已。从效率的角度看,DNS over TLS (DoT)比 DNS over HTTPS (DoH)更好,毕竟 DoH 多了一层 HTTP 协议封装。

目前 Windows 系统默认都不支持 DoT,需要采用第三方的软件(某种程度上又变相引入了不安全因素)。比较好的解决方式是选择支持 DoT 的路由器,国内华为、荣耀等家用路由器不支持 DoT,而华硕、TPLink 等家用路由器支持 DoT。

公共 DNS 服务器一般都支持 DoT 服务,国内采用腾讯和阿里两家的公共 DNS 服务即可,默认的 DoT 服务器如下:

119.29.29.29 -- 腾讯 DNS 服务
223.5.5.5 -- 阿里 DNS 服务

香港地区(或者海外地区)建议采用 google 和 Cloudflare 的公共 DNS 服务即可,默认 DoT 服务器如下:

1.1.1.1 -- Cloudflare 的 DNS 服务
8.8.8.8 -- Google 的 DNS 服务
ICE 与 DTLS-SRTP

ICE 与 DTLS-SRTP

IP 通信领域 —— 无论是 WebRTC 还是 SIP 通信 —— 处理媒体流时有两个需要仔细考虑的问题:(1)连通性,以及(2)安全。前者通过 ICE(Interactive Connectivity Establishment,交互式连通性确立)解决,后者通过SRTP、DTLS-SRTP 解决。

SIP 通信网络中 SIP 服务器往往具备转发流的功能,或者在网络中部署媒体网关,因此 ICE 并不是一个必选项,呼叫建立后双方(或者终端与服务器之间)进行 DTLS 握手协商、建立 SRTP 加密媒体流通道,双方通话。

而在 WebRTC 网络(或者 WebRTC – SIP 混合网络)中,可能仅仅部署 STUN 服务器,未必会部署 TURN 服务器,因此必须通过 ICE 确保媒体通道的连通性。旧版 WebRTC 只要求 SRTP 传输媒体,ICE 连通性确认后双方即可通话,而新版 WebRTC 要求必须采用 DTLS-SRTP 传输媒体,因此双方建立信令连接后,必须要确认媒体通道连通性、DTLS 握手协商后才能进入通话,如下图所示:

WebRTC 媒体通道建立过程
WebRTC 媒体通道建立过程

ICE 协商(即 STUN request + response)在 DTLS 握手协商之前。这点很好理解,如果没有完成 ICE 连通性确认,双方的媒体节点未必真实可达(一方或者双方位于私网后的情况非常普遍),DTLS 消息可能无法到达对方,从而无法完成 DTLS 握手协商。

建立 SRTP 连接后,WebRTC 节点之间依然会定时进行 ICE 协商确保双方媒体流的连通性,整个会话过程中 STUN request、response 消息不需要采用 DTLS 加密,STUN 消息自己的 username、password 以及 identify 等参数可以确保交互的安全。

DTLS-SRTP

DTLS-SRTP

DTLS-SRTP 开发工作主要基于两点考虑:(1)后续和 webRTC 对接时,无论是 Chrome 还是 Firefox,都要求采用 DTLS-SRTP 传输媒体;(2)在企业通信领域,如果用户不部署「SIP over TLS」, SRTP 加密用的 key 和 salt 在 SIP 消息中明文传输,有可能被有心人士拦截,从而破解 SRTP 流。

与 webRTC 对接还有很多繁琐的细节需要处理,以后再另外讨论。

对于企业通信中可能存在的拦截破解问题,目前通用的解决方法就是部署 DTLS-SRTP。DTLS-SRTP 不再通过 SIP 会话消息传递 key 和 salt,而是在 SRTP 建立之时双方 RTP 端点先进行 DTLS 协商,双方交换证书和密钥,进而加密、解密出 key 和 salt。具体步骤如下图所示:

DTLS-SRTP 流程
DTLS-SRTP 流程

SIP 消息中有两处需要注意:

(1)fingerprint 参数,指示了各自证书的 fingerprint。双方在 DTLS 协商时以此验证证书的有效性。篡改 fingerprint 或者拦截证书,都会导致 DTLS 协商失败。

(2)setup 参数,指示 RTP 端点在 DTLS 协商过程中的角色。DTLS 协商明确要求一方是 client(即协商的发起方),另一方是 server,具体细节请参考 RFC5763

在 DTLS 协商过程中随机生成 key 和 salt,完成协商后 RTP 端点从结果中提取出双方的 key 和 salt,对 RTP 流加密和解密,也就是后续 SRTP 流的处理。

2025 读书列表

2025 读书列表

2025 确实没看多少书,大部分还是网文,真是一言难尽……

程序员修炼之道
代码大全
C语言接口与设计
富兰克林自传
鞋狗
原始码:成为比尔·盖兹
段永平投资问答录
投资的逻辑
文明的逻辑

克拉克森的农场3
第一性原理
地球编年史
兼职无常后我红了
仙妻攻略
凡人修仙传
我师兄太稳健了
暗处袭来一道掌风
谁让他修仙的

2025 投资总结

2025 投资总结

利益声明

本文是个人的经验总结,涉及的股票是持有、或者曾经持有,不构成任何投资建议,请勿以此操作。股市有风险,投资需谨慎。

投资结果

今年收益率为 -0.53%,沪深300收益率为 17.66%。连续两年跑输指数,大牛之年不仅跑输指数,甚至负收益率收官,确实令人失望。

今年除了香港账户的资金投资,同时也用港股通投资了港股,计算港股收益率时有点混淆,不过资金量不大,不会大幅影响投资结果。明年(2026年)还是回到以前的操作,分开两地的资金独立进行投资和计算。

A 股

重仓的是以下个股:(1)珀莱雅;(2)万华化学;(3)新和成;(3)比亚迪;(5)中证A500ETF;(6)恒生红利低波ETF;(7)长江电力;(8)伊利股份;(9)海天味业;以及(10)中国海油。

相比去年,最大的改变是清仓了两只曾经重仓的股票:万科和京东方A。

在四月份的时候思虑再三,最终割肉万科,亏损超过50%,同时仓位过重,这也最终导致今年的收益率为负。2024年总结时万科也是拖累,当时思考了两个问题:(1)房地产行业还会存在吗?(2)万科还会存在吗?现在看来可能还在,但肯定回不去了,房地产不会是以前的房地产,万科也不可能是以前的万科,「管理层红利」显然也是笑话,谁知道还有几位管理层成员要进去踩缝纫机?把地毯掀开,里面全是蟑螂。教训是惨痛的,以后大概率不会在一支股票上投入过重仓位。

对京东方一直有很高的期待,但这么多年看下来,京东方还是强周期属性,技术上依然维持「好、但不足够好」的地位,各地明里暗里推动的内卷永无宁日。万科没有「管理红利」,京东方没有「技术红利」,庆幸的是清仓京东方颇有盈利。

另外清仓的股票是格力电器,然后将资金调仓或者增仓了珀莱雅、伊利股份和海天味业,基本都是老登股票,也就是今年被锤的消费股。虽然收益不佳,不过我觉得不错,期待明年消费有起色。

去年换车比亚迪的宋Pro,一年体验下来感觉不错,对这种技术导向型企业天然有好感,因此逐步加仓了比亚迪。如果明年有机会的话,可能会增加在比亚迪的仓位。

考虑到明年大概率人民币升值、美元贬值,因此清掉港股通的中国海洋石油,换成A股的中国海油。港股的中国海油石油仓位没有变化。

港股

港股的持仓仍然比较满意,目前持有:(1)四大行;(2)安踏体育;(3)中国海洋石油;(4)盈富基金;以及(5)中国飞鹤。

但是今年在港股的操作让我想掐死自己。曾经持有网易,盈利30%后抛了,然后它今年涨了近60%;曾经持有上美股份,盈利25%后抛了,然后它今年涨了112%。曾经持有农夫山泉,小有盈利后换到「低估」的中国飞鹤,喜迎-21%。

其他操作都显得微不足道了。

展望

今年是令人失望的一年,股市和实业都和年初的预期大相径庭。期待明年实业和消费都有提振,投资方面维持目前的持仓,对以比亚迪为代表的科技行业有更多期待,会重点关顾。

生料带

生料带

家里一个水龙头坏了,换了一个新水龙头。拧上去后水管接口处有细微的漏水,缠上生料带后好了点,还有一点点漏水。问了一下小区的维护水电工,据说生料带要缠 26 圈!我大概缠了 10 圈,先这么用着试试吧,要是有问题再拧下来重新缠生料带。

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