#760 OpenWrt 开源路由器

2022-01-31

历史

flowchart LR
WRT54G --> Alchemy --> DD-WRT
WRT54G --> HyperWRT --> Tomato --> ASUSWRT --> Asuswrt-Merlin[Asuswrt-Merlin 梅林]
ASUSWRT --> Padavan[Padavan 老毛子]
WRT54G --> OpenWRT
  • 2002 年 12 月 Linksys 发布 WRT54G 系列家用无线路由器(操作系统是基于 Linux 内核开发)。
    PS: Linksys 是美国加州的台湾移民创建, 2003 年被思科收购, 2013 年又被 Belkin 收购。2018 年 Belkin 被台湾的富士康收购。
  • 2003 年,思科收购 Linsys 之后,Linux 内核开发团队与自由软件基金会要求按照 GPL 协议公开 WRT54G 系统的源代码
    最后思科公司面对各方面压力,按照社区要求开发了源代码。
    Linsys 之后也一直在销售 WRT54G 系列路由器,据说销量还不错。
  • 2003 年,开发者基于 WRT54G 开发了 Alchemy 项目,pre 版本就成为相关领域当时最热门的项目。
  • 2004 Alchemy 1.0 发布、OpenWrt 项目启动、HyperWRT 项目启动。
  • 2005 年,由于 Alchemy 开发者急于商业化(要求支付每年 20 美元订阅费),社区分叉出了 DD-WRT 项目。
    现在依然是一个积极开发中的项目:https://svn.dd-wrt.com/ GitHub
    最后一个稳定版本 24 发布于 2008 年,之后十几年高频度发布 beta 版本:
    https://download1.dd-wrt.com/dd-wrtv2/downloads/betas/
  • 2005 年 12 月之后,DD-WRT 改成基于 OpenWrt 项目。
    也不重要,因为这个项目在 2008 年之后就没有开发了。
  • 2006 年,HyperWRT 项目趋于死亡,Jonathan Zarate 基于 HyperWRT 创建 Tomato 项目。
    比较独创的是开发了一个 Web 管理界面。
    2014 年之后就没有继续更新,但是有很多子项目,包括现在仍在开发中的 FreshTomato 和 ASUSWRT。
  • 2008 Gargoyle (石像鬼) v1.0 发布,加入了自己的包管理器(gpkg);
  • 2011 年 ASUSWRT 项目启动,至今还在积极开发中。
  • 2013 年,加拿大开发者发起 Asuswrt-Merlin(梅林固件)项目。
    https://www.asuswrt-merlin.net/
    https://github.com/RMerl/asuswrt-merlin
    https://github.com/RMerl/asuswrt-merlin.ng
  • 2016 年,俄罗斯开发者 Padavan 基于华硕固件(ASUSWRT)开发 rt-n56u 项目,目标是寻求对华硕路由器设备硬件的绝对控制。
    人们用开发者的名字来当做项目名字 Padavan,俗称“老毛子”。
    和梅林固件专注的是华硕高端机型(封闭的博通芯片)不同,老毛子主要针对的是华硕低端设备(联发科芯片),资源要求低。
  • 2016 年,因为内部分歧,OpenWRT 部分核心开发者出走,新起 LEDE 项目(Linux 嵌入式开发环境)。
    两年之后,双方和解,两个项目又合并到一起,采用 LEDE 的制度,继续使用 OpenWrt 品牌。
  • PandoraBox,国内项目,基于 OpenWrt,早期叫做 DreamBox。
    已经很久没有听到相关声音了。

LibreCMC

2014 年,作为 Linux 嵌入式发行版发行。
2015 年,与 LibreWRT 项目(研究项目)合并。
2017 年,基于 LEDE 17。
2020 年,基于 OpenWrt 19。

爱快

iKuai / iKuic (海外)

北京丰台一家网络设备厂商的闭源路由器系统,有商业版和免费版。
https://www.ikuai8.com/component/download

附:List of router firmware projects

  • Linux-based
    • entirely free
      • Endian
      • Floppyfw
      • IPFire
      • LEDE
      • libreCMC
      • OpenWrt
      • VyOS
      • Zeroshell
    • partly proprietary
      • AirOS & EdgeOS
      • Alliedware Plus
      • DD-WRT
      • ExtremeXOS
      • FRITZ!Box
      • RouterOS
      • SmoothWall
      • Tomato
      • Vyatta
  • FreeBSD-based
    • entirely free
      • m0n0wall
      • pfSense
      • OPNsense:pfSense 分叉
    • partly proprietary
      • Junos OS
  • proprietary
    • Cisco IOS
    • ExtremeWare
    • NX-OS
    • TiMOS
    • VRP

参考资料与拓展阅读

#759 Go HTTP 客户端

2022-01-29

原生

之前的文章:Golang HTTP 以及 HTML/XML 解析

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
)

func main() {
    resp, err := http.Get("https://www.baidu.com")
    if err != nil {
        fmt.Println(err)
        return
    }
    defer resp.Body.Close()
    fmt.Printf("%#v\n", resp.Status)           // string, "200 OK"
    fmt.Printf("%#v\n", resp.StatusCode)       // int, 200
    fmt.Printf("%#v\n", resp.Header)           // http.Header, map[string][]string
    fmt.Printf("%#v\n", resp.Request)          // *http.Request
    fmt.Printf("%#v\n", resp.ContentLength)    // int64
    fmt.Printf("%#v\n", resp.TransferEncoding) // []string(nil)
    fmt.Printf("%#v\n", resp.Trailer)          // http.Header(nil)
    fmt.Printf("%#v\n", resp.Uncompressed)     // bool
    fmt.Printf("%#v\n", resp.TLS)              // *tls.ConnectionState
    fmt.Printf("%#v\n", resp.Body)             // *http.bodyEOFSignal => io.ReadCloser => io.Reader

    body, err := ioutil.ReadAll(resp.Body)
    fmt.Println(string(body))
}

multipart

admin@victus:~$ cd /C/Program\ Files/Go/src/mime/multipart
nosch@victus:/C/Program Files/Go/src/mime/multipart$ grep -ER 'func.+\) [A-Z]\w+' .
./formdata.go:func (r *Reader) ReadForm(maxMemory int64) (*Form, error) {
./formdata.go:func (f *Form) RemoveAll() error {
./formdata.go:func (fh *FileHeader) Open() (File, error) {
./formdata.go:func (rc sectionReadCloser) Close() error {
./formdata_test.go:func testFile(t *testing.T, fh *FileHeader, efn, econtent string) File {
./formdata_test.go:func (r *failOnReadAfterErrorReader) Read(p []byte) (n int, err error) {
./multipart.go:func (p *Part) FormName() string {
./multipart.go:func (p *Part) FileName() string {
./multipart.go:func (r *stickyErrorReader) Read(p []byte) (n int, _ error) {
./multipart.go:func (p *Part) Read(d []byte) (n int, err error) {
./multipart.go:func (pr partReader) Read(d []byte) (int, error) {
./multipart.go:func (p *Part) Close() error {
./multipart.go:func (r *Reader) NextPart() (*Part, error) {
./multipart.go:func (r *Reader) NextRawPart() (*Part, error) {
./multipart_test.go:func (mr *maliciousReader) Read(b []byte) (n int, err error) {
./multipart_test.go:func (s *slowReader) Read(p []byte) (int, error) {
./multipart_test.go:func (s *sentinelReader) Read([]byte) (int, error) {
./writer.go:func (w *Writer) Boundary() string {
./writer.go:func (w *Writer) SetBoundary(boundary string) error {
./writer.go:func (w *Writer) FormDataContentType() string {
./writer.go:func (w *Writer) CreatePart(header textproto.MIMEHeader) (io.Writer, error) {
./writer.go:func (w *Writer) CreateFormFile(fieldname, filename string) (io.Writer, error) {
./writer.go:func (w *Writer) CreateFormField(fieldname string) (io.Writer, error) {
./writer.go:func (w *Writer) WriteField(fieldname, value string) error {
./writer.go:func (w *Writer) Close() error {
./writer.go:func (p *part) Write(d []byte) (n int, err error) {

第三方库

GitHub: http client stars:>1000

  1. go-resty/resty shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    Simple HTTP and REST client library for Go
  2. parnurzeal/gorequest shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    GoRequest -- Simplified HTTP client ( inspired by nodejs SuperAgent )
  3. gojek/heimdall shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    An enhanced HTTP client for Go
  4. imroc/req shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    Simplified Golang HTTP client library with Black Magic, Less Code and More Efficiency
  5. dghubble/sling shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    A Go HTTP client library for creating and sending API requests
  6. hashicorp/go-retryablehttp shields.io:github/stars shields.io:github/languages/code-size shields.io:github/commit-activity/w shields.io:github/license
    Retryable HTTP client in Go

简单的了解:

  1. resty 看起来确实不错,链式调用,清晰明了,而且有不错的调试信息。
  2. gorequest 是在原生库上做了一点简单的封装,优化调用体验。有篇中文文档可以参考:gorequest中文文档(非官方)
    需要学习一下他的设计。官方文档说是借鉴 Node.js 的 SuperAgent。
  3. sling 也挺有特色的,使 API 变得结构化,调用变得像普通的 Go 函数一样。
  4. go-retryablehttp 在原生库上加了一个自动重试机制。
  5. heimdall, req, 简单一看,还看不出来有什么特别的地方。

#758 2022 BUG

2022-01-28

前些天应该都看过微软 Exchange Server 开发者跨年改 BUG 的新闻了吧 (相关链接)。

Exchange Server 的邮件过滤器采用了 yymmddHHMM 格式的时间,存储在 long 类型字段中。
PS: 微软的 C++ Compiler 会将 long 当做 32 位 int。

32 位有符号整形能够表达的范围:[$-2^{31}$, $2^{31} - 1$],也就是 [-2147483648, 2147483647]。

到了 2022 年,就会超出范围,比如 2022-01-01 12:00:00, 会被存储为 2201011200,会超出 signed int 的表达范围。

2147483647
2201011200 # 超出

可能有一些系统采用 int 类型存储 yymmdd + 4 位数字做编号的方式,比如 2101011234。
相同的原因,到了 2022 年,就行不通了。

2147483647
2201011234 # 超出

最好的办法是改成 long long, 或者 unsigned int

PS: Linux 下的 C/C++ 编译器——GCC、CLang/LLVM 都是将 long 当做是 64 位。

参考资料与拓展阅读

#757 新东方英语词典备份

2022-01-25

听说沪江英语出于合规的考虑,APP 中下线了中小学英语词书。
我赶紧检查一下我之前的新东方英语词典的脚本, 检查一下,把没有的爬一份。主要是我今年准备全面学习一下英语,从小学阶段开始,要是到时候小学词典都弄不到就 BBQ 了。

#756 OneTab 迁移

2022-01-24

我清理了一些文件之后,发现之前安装的 Microsoft Edge Beta 打不开了。
我就重装了 Microsoft Edge。

不过问题来了,OneTab 中的 8000+ 多个收藏的页面找不回来了,以后会不会有机会看是一回事,找不到了又是一回事。总觉得不太爽。

我先用 --user-data-dir 参数,讲 Edge 的用户数据目录指向老的数据目录,还是无法启动。

经过一点点研究,我用 everything 搜索 OneTab 的 ID chphlpgkkbolifaimnlloiipkdnihall, 找到新旧版本的插件目录。

everything 截图

然后在 Local Extension Settings 下发现了 3M 的 .db 文件,文件大小符合预期。把这个目录覆盖过去试试。结果就好了。

# 旧版本的插件目录
C:\Users\Administrator\AppData\Local\Microsoft\Edge Beta\User Data\Default\Local Extension Settings\chphlpgkkbolifaimnlloiipkdnihall

# 覆盖到新版本的插件目录:
C:\Users\Administrator\AppData\Local\Microsoft\Edge\User Data\Default\Local Extension Settings\chphlpgkkbolifaimnlloiipkdnihall

#755 韦伯望远镜

2022-01-23

img

韦伯望远镜,全名詹姆斯·韦伯太空望远镜,以主持阿波罗计划的 NASA 前局长名字命名,立项于 1996 年,原计划 2007 年发布。
在经过 n 次延期之后,于 2021 年 12 月 25 日——也就是圣诞节那天——发射成功。

现在应该早就到了目标位置——第二拉格朗日点(L2), 然后正在调试各种设备。

img

相关知识点

  1. 至少 344 个单点故障,系统可靠性有待考验
  2. 距离地球非常远,维修和更换零部件的成本可能是无法接受的
  3. 特点是红外波段的探测能力 (哈勃计划主要是可见光波段的探测)
  4. NIRCam 近红外相机
  5. NIRSpec 近红外光谱仪
  6. MIRI 中红外成像-光谱仪
  7. FGS/NIRISS 精细制导传感器、近红外成像仪、无缝隙光谱仪
  8. 一面对准太阳,然后中间隔一层网球场大小的遮阳伞,避免受到光照影响
  9. 口径为 6.5 米 (哈勃的 5 倍不止)

img

附: 中国巡天望远镜

和哈勃望远镜口径接近,成像技术也差不多,不过类型不同。

哈勃擅长拍特写,而我们的巡天望远镜更擅长拍全景(视场是哈勃的 300 倍,所以叫巡天望远镜嘛)。

预计发射时间

2024 年

参考资料与拓展阅读

#754 OCSP 2: OpenSSL OCSP 校验

2022-01-22

上一篇:2021-08-08, OCSP 联机证书状态协议

OpenSSL 步骤

rm -rf /tmp/ocsptest/; mkdir -p /tmp/ocsptest/; cd /tmp/ocsptest/; ls

# 获取证书
openssl s_client -showcerts -connect markjour.com:443 < /dev/null | awk -v c=-1 '/-----BEGIN CERTIFICATE-----/{f=1;c++}f {print > ("l"c".crt")}/---END CERTIFICATE-----/{f=0}'
cat l*.crt > chain.crt

# 获取 OCSP URL
ocspUrl=$(openssl x509 -noout -text -in l0.crt | grep OCSP | xargs); ocspUrl=${ocspUrl#*URI:}; echo $ocspUrl;
# http://ocsp.digicert.com

# 获取证书序列号
serial=$(openssl x509 -serial -noout -in l0.crt); serial=${serial#*=}; echo $serial;
# 01F284D36E08179CF4CEB5D339FE95E9

# OCSP 校验
openssl ocsp -nonce -issuer l1.crt -CAfile chain.crt -url $ocspUrl -serial "0x${serial}"
# WARNING: no nonce in response
# Response verify OK
# 0x01F284D36E08179CF4CEB5D339FE95E9: good
#   This Update: Jan 21 08:15:01 2022 GMT
#   Next Update: Jan 28 07:30:01 2022 GMT

#753 输入法

2022-01-19

我用的最多的输入法:

  1. 搜狗
    搜狗在中文输入法方面确实是做的不错,没得说。
  2. 百度
    百度输入法是小米自带(我是一个资深小米用户),有时懒得换也就用了。而且百度输入法还有一个好的地方,就是如果手机接入物理键盘后,它会只显示一个横条,不占界面。
  3. RIME
    RIME 是我在 Linux 上的输入法, 一转眼就用了好几年了。

RIME 是一个开源项目,没有搜狗、百度那样的云服务(那种智能的全句输入)支持,在使用方面不如他们顺手,本地词库也确实有些单薄。话说回来,也够用了,几年的真实感受。

而且一旦习惯了 Linux 的折腾,这种全部在自己的掌控之中的感受就很上瘾。你要是熟悉 RIME 的话,你就懂我说的了,词库全部在掌握之中。
PS: Ubuntu 中的 IBUS 智能拼音(libpinyin/ibus-libpinyin)也是可以自己控制词库。

搜狗和百度都是封闭的,他们的用户词库都不支持导出(加密的不算)。我常常觉得要是可以把搜狗和百度中的词库导入 RIME 就好了。他们自己弄的那些个词库就不指望了,只是希望可以把我输入的那部分给我。

最近发现讯飞输入法效果不错,不输搜狗和百度,而且支持导出词库(目前只发现手机端可以导出,PC 端我已经在线反馈,等回复中)。

现在已经全部切入讯飞输入法。
PS: 讯飞的词库和搜狐比差太多,不见得比 Rime 强多少,但我相信运行一段时间之后会越来越好的。

关于讯飞输入法在 Debian/Ubuntu 上的安装

# Index of /deepin/pool/non-free/i/iflyime/
# ../
# iflyime_0.9.972_amd64.deb                          18-Dec-2019 13:31     27M
# iflyime_0.9.988_amd64.deb                          14-May-2020 17:49     49M

wget http://packages.deepin.com/deepin/pool/non-free/i/iflyime/iflyime_0.9.988_amd64.deb -P ~/Resources

gdebi ~/Resources/iflyime_0.9.988_amd64.deb
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Reading state information... Done
此软件包不可安装
Dependency is not satisfiable: fcitx-frontend-qt4

看起来是 Qt4 被砍掉了的缘故,应该可以解决。但是从上一次发版(2020/05/14)到现在已经一年半了,没有出新版本,可能是讯飞输入法 Linux 版项目被停了,所以就算了吧。

#751 Golang 观察

2022-01-18

InfoQ 的公众号文章《解读Go语言的2021:稳定为王》中引用 TIOBE Index 和 Google Trends 的数据来分析 Go 语言的发展趋势。
非常有意思,我找他的思路,直接去源头研究了一番。

Go 在 2009 年和 2016 年得了 TIOBE 年度语言。
PS: Go 是 2009 年 11 月发布。TIOBE 也是够捧场了,刚一出来就得了年度语言。

根据 TIOBE 的数据,Go 在 2016 年下半年大火了一波,随后热度消退,从 2018 年到现在一直比较稳定。

然后 Google Trends 的数据(2009/10/01 至今,全球)显示:

  • Go 在 2009 年诞生之后就慢慢攀升
  • 2012 年达到一个阶段
  • 2013 年 10 月又上一个台阶
  • 2014 年 5 月达到巅峰
  • 然后一直持续下跌到 2020 年底
  • 2021 年稍有复苏的迹象

最后再上这张图,看看 Go 在各个地区的火爆程度:

那篇文章,包括我之前在网上看到的其他文章,都在这个地方得出了一个结论:Go 在国内的热度远超国外,甚至有地方说 Go 语言的热度全靠国内开发者支撑。
我认为这是非常不严谨的。

其实 Google Trends 的数据是根据这个地方搜索相关词条的比例来计算的。而 Google 的中国用户已经被过滤过一道,应该是以开发者为主。所以这个热度数据的对比是不能说明什么问题的。而且由于一些上网方式的问题,国内的这部分统计数据应该是非常不可靠的。