I am LAZY bones?
AN ancient AND boring SITE

分类: '经验技巧' 的归档

给 macOS App 加自动更新:Sparkle 入门

最近给 Notchy 加了自动更新。原先的”检查更新”功能很糙:调一下 GitHub Releases API 看有没有新版本,发现有就开浏览器跳到 release 页面,让用户自己下 dmg、自己拖进 Applications。

这显然算不上”自动”。理想体验是:发现新版本 → 自动下载 → 校验签名 → 替换 App → 重启。这一套自己写也可以,但 macOS 生态二十年前就有现成的轮子 —— Sparkle

接进去之后回头看,整个事情比想象中简单,但中间踩了几个不算直觉的坑,整理一下。

Sparkle 是什么

Sparkle 是 macOS 上事实标准的开源自动更新框架,从 2006 年用到现在。Transmission、VLC、Handbrake、Sequel Pro、Tower、Hammerspoon、iStat Menus …… 基本上你在 App Store 之外用过的、有自动更新的 Mac App,十有八九背后都是它。

工作流大致这样:

  1. App 启动或定时,Sparkle 去服务器拉一份 appcast.xml
  2. xml 里列着最新版本号、下载地址、文件大小、加密签名
  3. 客户端对比版本,发现有更新就弹框问用户
  4. 用户点”安装”,Sparkle 后台下载 zip、校验签名是不是你这个开发者签的、没问题就解压、替换 .app、关掉旧进程、启动新的

对用户来说就是一个对话框加一次重启。对开发者来说就是发版时多产出一份 appcast.xml

谁适合用

两种情况不太适合:上架 Mac App Store 的 App(商店本身有更新机制,且 App Store 也不允许 App 自己拉远端代码下来执行),以及强沙盒 App(Sparkle 2 技术上支持沙盒,但配置麻烦得多,要走 XPC service 隔离)。

比较适合的:自己 Developer ID 签名 + 公证 + 通过官网或 GitHub Releases 分发的独立 Mac App。这也是 Notchy 这类小工具最常见的发布方式。

什么是 EdDSA

Sparkle 在客户端校验更新包真伪用的是 EdDSA 签名。这一步对安全至关重要 —— 没有它,任何能劫持你 appcast URL 的人都能给你的用户推一个伪造的更新包。

EdDSA(Edwards-curve Digital Signature Algorithm)是基于椭圆曲线的数字签名算法。相比经典的 RSA,密钥短得多(公私钥各 32 字节,base64 后大约一行),签名快,对边信道攻击有自带防御。

具体在 Sparkle 里:

  1. 你本机生成一对密钥(私钥 + 公钥)
  2. 公钥写进 App 的 Info.plistSUPublicEDKey 字段,会被烧进每一份发出去的 App)
  3. 私钥只留在你的本机 Keychain 和 CI 的 secret 里
  4. 每次发版,用私钥给 zip 算一个签名,写进 appcast.xml
  5. 客户端下载 zip 后,用嵌在自己 binary 里的公钥校验签名

关键是:就算坏人完全控制了 appcast 服务器,他也伪造不出合法签名—— 除非他拿到了你的私钥。Apple 的公证和 Developer ID 不是 Sparkle 安全的最后一道防线,Sparkle 自带的 EdDSA 签名才是。

也因此:私钥一旦丢了,就再也没法给老用户推新版了—— 公钥已经烧进每一份分发出去的 App 里,没有匹配的私钥就永远签不出合法的更新包。生成后立刻备份到 1Password 或加密 U 盘里,是必做的事。

怎么接

整个接入分四部分:客户端、Info.plist、密钥、CI 流水线。一个个来。

1. SPM 引依赖

Xcode 里 File → Add Package Dependencies,地址:

版本选 up to next major,最低 2.x。Sparkle 2 是现代版本,支持沙盒、XPC 隔离、阶段化推送等。

引入之后写一个最简的 controller:

然后在 AppDelegate.applicationDidFinishLaunching 里引用一下让它实例化:

定时检查、自动下载、弹框 UI、安装重启 —— Sparkle 全包了。”Check for Updates…” 按钮只需要接到 controller.checkForUpdates(nil)

2. 配 Info.plist

Sparkle 至少需要这三个 key:

SUFeedURL 一般有两种托管方式:

  • 单独搞个 GitHub Pages / 自家 CDN,URL 固定
  • 直接用 GitHub Release 的稳定链接https://github.com/<owner>/<repo>/releases/latest/download/appcast.xml

第二种最省事 —— GitHub 这个 URL 永远 redirect 到最新 release 里叫 appcast.xml 的那个 asset,发版时把 xml 当资产上传一份就行,零额外服务。

3. 生成 EdDSA 密钥

Sparkle 自带 generate_keys 工具。SPM 解出来后能在这里找到:

直接跑(不带参数)会在 macOS Keychain 里生成一对 ed25519 密钥,并打印公钥。把这个公钥贴进 SUPublicEDKey

要拿私钥(CI 要用):

文件里就是私钥的 base64 字符串。把这个字符串塞进 CI 的 secret 里(GitHub Actions 里我用的名字是 SPARKLE_PRIVATE_KEY)。本地的私钥文件备份后立刻删掉,因为它是明文。

4. 发版流水线

每次发版多做两件事:

  1. 用私钥给 zip 签名:Sparkle 自带的 sign_update 工具,输入 zip + 私钥文件,输出 sparkle:edSignature="..." length="..." 这一行
  2. 生成 appcast.xml:把版本号、下载 URL、上一步的签名、文件大小、release notes 套进 RSS 模板

最终 appcast.xml 长这样:

注意 <description> 里直接内嵌 release notes 的 HTML —— Sparkle 弹框会原地渲染。如果用 <sparkle:releaseNotesLink> 指向 GitHub release 详情页,Sparkle 会用 WebView 加载那个 URL,GitHub 整站的导航条、登录按钮、左侧栏全会被渲染进对话框里,体验极差。这是亲自踩过的坑。

几个不那么直觉的细节

Sparkle helper 的重签问题

这是当时折腾最久的一个。接入做完、编译一切正常、archive 顺利出来、codesign --verify --deep --strict 全绿、所有嵌套件都 --validated。一切看着都对,提交给 notarytool 跑公证 —— 几十秒后回来一个 status: Invalid

紧接着脚本继续往下跑 staple,挂在了一个看似毫不相关的错误上:

第一反应是网络抖动或 Apple 服务器问题,重跑一次 —— 还是一样。其实 CloudKit 这个错是 staple 在找还没存在的公证票据,根因是上一步 notarytool 返回了 Invalid。

跑一下 xcrun notarytool log <submission-id>,真相终于浮出水面:

原因清楚了:Sparkle 通过 SPM 编译出来时,里面这四个 helper(AutoupdateUpdater.appDownloader.xpcInstaller.xpc)自带的是 ad-hoc 签名,不是你的 Developer ID 签的,也没有安全时间戳。codesign --verify 只检查签名链是否完整、本机能否校验通过,不检查”谁签的”,所以看上去全绿 —— 但 Apple 公证要求每个嵌套可执行文件都用你的 Developer ID 加 secure timestamp 签。

解决办法:archive 完成之后,按由内向外的顺序手动重签 —— 四个 helper、framework 本身、外层 .app,每一步都带 --options runtime --timestamp,最外层那一次还要带回原本的 entitlements 文件。每改动一层嵌套件,外面的封印就破了,必须重新盖一次。

首次升级有断层

接入 Sparkle 的那一版才开始有 Sparkle,再老的版本没有。所以”老版本 → 你接入 Sparkle 的这一版”这次升级用户还得手动下,没办法。从下个版本起才是真的自动。

版本号字段都要写

Sparkle 客户端比较新旧版本时看的是 CFBundleShortVersionStringCFBundleVersion。两个字段都不能漏,且服务端 appcast 里 <sparkle:version><sparkle:shortVersionString> 要和 App 里的对得上,否则版本判断会出意外。

小结

接入 Sparkle 的核心动作就那几下:

  • SPM 加依赖、写个最小的 SPUStandardUpdaterController
  • Info.plist 写好 feed URL 加公钥
  • 生成 EdDSA 密钥对,公钥写 plist、私钥进 Keychain 和 CI secret
  • 发版时多产出 appcast.xml,签好上传

接完之后,发版就是推个 tag,CI 自动签、公证、生成 appcast、上传。用户那边就是某天打开 App,弹框告诉他有新版本,点一下、重启,完事。

如果你也在写独立的 macOS 小工具,自动更新这一步真的值得做 —— 它把”我有时间发版”和”老用户能用上新功能”这两件事彻底脱钩。

Keychain和security简介

CCAS 的时候要做的事其实很本质:在多个 Claude 账号之间切换。第一个要弄清楚的是 —— Claude Code 把自己的 OAuth credentials 存在哪?

翻一下之前泄露的代码很容易就知道了:在 macOS Keychain 里,service 名字是 Claude Code-credentials。你现在就可以在终端里看一眼:

会打印出一坨 JSON,里面就是 access token、refresh token 这些。

这不是 Claude Code 的”小众”选择 —— 各种 IDE、CLI、Apple 自家的 Safari Mail,所有在 macOS 上要存”密码、token、密钥”的程序,默认就该放进 Keychain。它是这台机器上事实标准的敏感数据存储。

那它到底是什么?

Keychain 是什么

最直白的描述:Keychain 是 macOS 自带的加密键值数据库,专门为存敏感数据设计。每条记录由系统加密,挂在登录用户的身份下,由 securityd 这个常驻守护进程管理。

它的物理形态是磁盘上的几个文件,常见的有:

你不会直接读这些文件 —— 它们是加密的 SQLite,主密钥跟你的登录密码绑定。读写都要走系统 API,由 securityd 解锁后再返回明文。

它解决了什么

如果不用 Keychain,自己拿个 JSON 文件存 token 行不行?技术上可以,但你要面对几个问题:

1. 磁盘加密

文件丢在 ~/.config/ 下是明文。任何能读你 home 目录的进程都能拿到(包括别的 app、误装的恶意脚本)。即便你给文件 chmod 600,磁盘镜像被拷走照样能看。

Keychain 用 AES 加密,主密钥来自你的登录密码 —— 机器没登录、密码不对,磁盘镜像里的内容就解不出来。

2. 进程隔离

文件系统只有”用户级”权限。但同一用户跑的所有 app 是平等的:Claude Code 写下的 token,理论上你装的任何一个三方 app 都能读。

Keychain 的每条记录带 ACL(access control list),记录”谁创建的、谁可以读”。当一个 app 试图读另一个 app 创建的条目时,系统会弹窗让用户确认。这是文件系统本身做不到的。

3. 用户可见、可管理

打开 Keychain Access.app,你能看到所有条目、谁创建的、什么时候改的,可以手动删。要 export 还得再输一次登录密码。

4. 跨设备同步

勾上 “iCloud Keychain” 之后,相应条目会端到端加密同步到你登录同一 Apple ID 的其他 Mac、iPhone、iPad。Safari 的密码、WiFi 密码、Apple Pay 卡号走的都是这个。

数据模型

Keychain 里有几类 item,最常用的是 generic password(任意 key-value 的密钥/token,多数 app 自定义存储用这个)和 internet password(带 protocol/host/port/path 字段,Safari 存网站密码用)。此外还有 certificate、key(公私钥对)、identity(cert + key 对)。

generic password 的核心字段就两个:

  • service:通常用 reverse-DNS 风格的命名空间,例如 com.apple.accountClaude Code-credentials
  • account:同一 service 下区分多条记录的标识,通常是用户名或邮箱。

service + account 唯一定位一条记录。Password 字段本身可以是任意字节(你完全可以塞一整段 JSON 进去,Claude Code 就是这么干的)。

怎么读写:security 命令

Apple 给开发者两套接口:

  • C APISecItem* 这一族(旧的 SecKeychain* 已经不推荐)。Swift / Objective-C app 一般用这个。
  • 命令行 /usr/bin/security:脚本和调试用。

CCAS 走的是后者,省得对接 C API;好处是用户自己在终端就能验证一切。最常用的三条:

-s 是 service,-a 是 account,-w 表示”只把 password 内容打到 stdout”。不加 -w 会打印所有属性元数据,但隐去 password。

更多有用的子命令:

几个不那么直觉的细节

search list:系统其实管理着一个 keychain “搜索列表”,security find-* 默认遍历整个列表。常见情况下只有 login.keychain-db,但用户/MDM 可能加挂别的。如果某条记录意外落在搜索列表外的 keychain 里,会出现”dump 看得到、find 找不到”的现象,这时候要在命令末尾显式带上 keychain 路径。

密码存二进制:用 -w "value" 写入时整个参数被当作 UTF-8 字符串。如果 value 里有换行、引号、控制字符,shell 转义会很烦人。更可靠的方式是 -X hex,把内容先转 hex 再交给 security,由它自己 decode 后存原始字节。

-U 不一定是真正的 upsertadd-generic-password -U 文档说”如果存在则更新”,但匹配条件偏严,遇到某些属性差异会判定为”新条目”再插一条。同 service+account 的重复记录会越积越多。要 idempotent 的话,先 delete 再 add 更稳。

account 不是严格过滤find-generic-password -s SVC -a ACCT 如果 account 没精确匹配,可能 fallback 命中同 service 下别的 account —— 不报错,直接返回别人的内容。读完后再校验返回值是个好习惯。

小结

Keychain 是 macOS 上存敏感数据的标准答案。它做的事不复杂 —— 加密、隔离、用户可控、可同步 —— 但是把这四件事做齐了,且对开发者基本零成本。

下次写 Mac app 要存 token、API key 或者密码,不用犹豫,直接 SecItem / security 走起,比自己掂量”放哪、加什么密、谁能读”省太多事。

uv 的 inline script metadata 太香了

最近又玩了下 uv,感觉它在“小工具开发”这个场景里特别顺手。

uv 本质上是一个把 Python 依赖管理、虚拟环境、脚本运行这些事情揉在一起的工具。它最大的优点当然是快,但更让我喜欢的是:很多原本零碎又烦的动作,被压缩成了几个很好记的命令。

比如平时写个小脚本,常常只是想:

  • 调一下接口
  • 批量处理一点文件
  • 验证一个第三方库
  • 给自己做个顺手的小命令

这类东西通常不值得认真建个项目,但又往往会依赖 requestshttpxrich 之类的包。以前一般要先建 venv,再装依赖,可能还要改个 .gitignore,多少有点麻烦。

这时候 uv 很方便的一个点,就是可以直接用 --with

或者:

这种方式特别适合刚开始写小工具的时候。先跑起来,先验证思路,不用一上来就准备完整项目。

不过,--with 也有个问题:依赖信息是在命令里,不在脚本里。

今天你记得怎么跑,过几天自己可能都忘了。发给别人时,也得额外告诉对方要带哪些依赖。

这时候真正的大招就来了:inline script metadata

你可以直接把依赖用这样的格式,写到脚本头部:

可以看到,去掉# /// script这些包裹层之后,里面的内容,其实就是TOML的语法。

这样之后就不用再写长命令了,直接:

就行。这个体验非常好。因为脚本自己就说明白了:

  • 需要什么 Python 版本
  • 依赖哪些包
  • 应该怎么运行

更进一步,你甚至可以再加个 shebang,把它写成一个可以直接执行的脚本:

这样给脚本加上执行权限(chmod +x)之后,连 uv run foo.py 都可以省掉,直接 ./foo.py 就可以跑起来了。

最后总结一下:

  • 刚开始随手写个小工具,用 uv run --with ...
  • 觉得这个脚本值得留下来,就上 inline script metadata
  • 再彻底一点,可以用#!/usr/bin/env -S uv run --script这个shebang

OpenClaw分享

以下PPT和内容,来源是我跟一群爱学习的朋友一起学时下大火的OpenClaw小龙虾,我给大家做了个小分享。

PPT几乎是OpenClaw输出的内容,下面的会议总结也是GPT根据会议录屏总结的。

需要注意的是,我其实没有将小龙虾玩得很深,因为我从心底里是不信任AI的,也就不敢给它太多权限。所以内容也都比较浅,请见谅。

OpenClaw 会议总结

这次分享的核心,不是在介绍一个“聊天机器人”,而是在介绍一套可自托管、可扩展、可执行任务的个人 AI 基础设施。分享者把 OpenClaw 定位为“装进手机里的 AI 助手”:用户通过 WhatsApp、Telegram 等聊天入口发出请求,背后由部署在自己电脑或服务器上的 OpenClaw 网关完成会话管理、记忆注入、工具调用和本地执行,再把结果返回到聊天端。PPT 对这一定位和整体链路描述得很清楚。

点击查看全文 »

局域网影音解决方案——Jellyfin

先交代下背景:我本来是打算在家里搞个NAS的,但由于最近硬盘和内存都疯狂涨价,加上其实需求也不是那么迫切,就一直没有去折腾。

另外,家里其实已经有一个小主机(对,本blog就跑在上面呢)了,它带了1TB的SSD。所以偶尔有下载电影、在不同的屏幕(手机、pad、电脑、电视机等)看电影的需求,就想着把这个小主机再压榨一下吧。

于是有了以下的折腾:

下载的需求,其实很好搞定。但下载完之后,电影在小主机上,要在各种设备上播放,我一个想到的是用SMB在局域网里共享目录,这确实是一个方案。但这个方案有两个问题:

  1. 不是所有的(屏幕)设备都能找到支持SMB的播放器。
  2. 有些设备的解码能力太弱,遇到高码率的4K视频,就会卡住

所以,最好的方式就是再充分压榨这个小主机,因为它其实有个显卡(CPU:AMD Ryzen 3 7330U(集成 Radeon iGPU)),可以用于服务端转码。于是就给它装了个 Jellyfin。

Jellyfin是个开源的、完全自托管的影音解决方案,特别适合喜欢折腾的人。

安装过程我也偷懒了,没有去编译源码、调试环境,而是直接采用docker运行了,在我的Ubuntu下,大致如下:

接着,建一个 Jellyfin 的空目录,在里面建一个 docker-compose.yml 内容如下:

其中,/home/shard 是存电影的目录。

然后,在此目录下,执行 docker compose up -d,不出意外的话,你的Jellyfin就应该能正常启动了。这时候就可以访问 http://192.168.你的.IP:8096 进入web管理界面进行进一步的设置了。

设置完管理员账号之类的信息以后,需要注意的一点,就是开启转码的硬件加速。做法是在 Dashboard → Playback → Transcoding
Hardware acceleration 选择 Video Acceleration API (VAAPI),这是AMD的芯片+Linux系统的选项,其他的硬件、软件的组合,可以参考官方文档
VAAPI device 就选择 /dev/dri/renderD128,如果前面的 docker-compose.yml 没有写错,这里应该是可以选到的。

这么做了以后,在客户端有播放视频的时候,即使是播放的4K视频,CPU利用率也不应该太高。如果是CPU持续打满,就建议再看看硬件加速的配置。

配置好以后,家里的几个屏就都可以无缝切换看小主机里的电影了!因为每个屏至少都有浏览器可用,直接浏览器打开上述地址就可以了。当然,安装最佳实践来说的话,在有条件的情况下,最好使用官方客户端来看,而不是只用浏览器。因为用浏览器就会把所有的解码压力,都丢给服务端。尤其是你的端侧算力很强(比如Mac)的时候,用客户端可以直接拿原始视频到端侧解码!这样不仅服务器的压力更小,而且画质也是无损的。体验也会更好!

那么,如果大家还有比较全、质量又比较高的电影下载源(最好是magnet协议的)的话,也请留言告诉我!谢谢!

终于搞清楚Google账号的所属国家的逻辑了

如果你买过YouTube premium,或者加过其他人买的YouTube premium family套餐,后续又因为种种原因(比如Google 封禁了假的土耳其区等)退出了premium计划,那你再想加入另一个family的时候,大概率会看到这么一个提示:告诉你“您似乎与邀请您的人不在同一个国家/地区。”,从而“无法加入家人群组”。

然后,你可以会在Google账号的后台管理账号做各种尝试,包括用不同国家的VPN,拿到特定的IP地址、修改账号的住址信息、添加不同国家的信用卡作为付款方式等等,但我猜这大概率都解决不了你的问题!

我曾经也因此折腾了很久,知道最近,才明白怎么查看以及修改这个字段。先说好:方法仅供参考,也别拿大号玩得太花,不然被封就嘎了~

查看:

先得有办法确认当前的账号所属国家,才知道要不要去做修改。

这个方法很简单,登陆Google Play的web页面,登陆以后,确定右上角的头像是要查看的账号头像,然后把页面拉到最底部,右下角就会显示 国家(语言)

这可能是唯一精确知道目前账号所属国的办法。

修改:

如果确定了你的国家不是你想要的,要怎么修改呢?

以下几乎也是唯一可行的办法:

点击查看全文 »

WordPress文章如何同步到X

其实,十几年前,我的blog就有这个功能的,比如:

当时用的是一个叫 WP2Twitter 的 WordPress插件,当时的逻辑也非常简单,有新post的时候,就把标题和URL拼一个字符串,直接往Twitter发了,而且那时候Twitter的权限也比较松。

最近重拾blog以后,想着也把这个功能恢复一下,而且现在不是有AI了嘛,其实还可以更进一步,不仅可以输出标题,还顺便把文章的内容做个大致的摘要,可以让有兴趣的朋友点进来,也可以避免浪费对此内容不感兴趣的朋友的时间。

搜了一下IFTTT、RSS转X等方案,其实倒是有很多平台都能实现,但要么功能过于强大,搞得很复杂;要么需要订阅,要交一笔费用。后来眼光还是回到WordPress插件上来了,还真让我找到一个至少非常适合我的插件,分享给大家,如果有需要的话,也可以参考。

这个插件叫 Automator,其功能非常强大,可以连接WP和各种社交媒体和平台,部分功能也需要订阅pro,但发布到X,则是免费版就够用的。

点击查看全文 »

自主控制WordPress的图片尺寸

你往WordPress上传一张图片的时候,它有可能会给你在后台生成7、8张不同尺寸的图片,比如这样:

其实这对于大部分人来说,都是一个蛮好的功能。比如小白可能会把手机拍的几个MB的图片直接上传上来,那对于web显示可能就太大了。有个自动缩略就很合适了,既能节省带宽,页面加载又快。

但我偏偏是一个喜欢“手动档”的人,我想自己来控制这些尺寸,上传前就会对图片做适当的压缩。这样服务器里也就不用存储这多张图片了。

问了GPT,以下方法对我是有效的:

  1. WordPress后台 → 设置 → 媒体,把缩略图/中等/大的宽高都设为 0,保存。//这里能少3个图片
  2. 在WP主题的 functions.php 里,加入以下代码:

完事,现在你传什么,服务器就只存什么了。

PS:查资料的过程中,还了解到现在浏览器有个srcset响应式图片,大致是,HTML的img标签里,除了正常的src以外,还会提供一个srcset,然后浏览器就可以根据当前屏幕的尺寸来决定具体请求那个资源了,下面是个例子,听起来是挺不错的。

折腾自己的blog,而不是直接用平台,就是有这些乐趣(如果你也觉得这是乐趣的话),哈哈~

找回丢失的磁盘空间

经常接触linux,尤其是多人共用的服务器上的linux的朋友,也许会经常遇到这样的问题:
收到一个磁盘告警,说某某分区已经满了,然后登录服务器 df 一看,发现磁盘确实快满了,然后你就想找到具体是哪个目录满了,于是 du -s * 一看,却发现所有子目录的大小总和却和df显示的总已使用磁盘空间对不上,有时候甚至还相差很多,于是就纳闷了:我的磁盘空间去哪了呢?

这里就列一下我所知的3种情况:

  1. 隐藏文件
  2. linux系统把文件名以.(点号)开头的文件视为隐藏文件,而类似bash里*这样的操作符是不会匹配隐藏文件的,所以如果根目录下有个较大的隐藏文件的话,是不会被du -sh * 统计到的,解决办法就是: du -sh .[^.]*

  3. 非空目录被mount
  4. 一般挂载其他分区的时候都是建议mount到一个空目录的,那么如果mount到一个非空的目录,情况会怎么样呢?比如/mnt目录本来里面是有文件的,然后执行了sudo mount /dev/sda6 /mnt。其实这个mount命令完全能正常执行,被mount的分区也能正常访问,只是原先在/mnt里的文件,现在已经访问不到了,包括du也看不到大小了,但是磁盘空间却还是被占着,因为如果你 umount /mnt 以后,原来的文件都还会回来的。

  5. 空洞文件
  6. 一个文件的大小和所占磁盘空间也不一定完全一致,比如某个程序一直打开着一个叫log的文件在写,而中间有人用 > log 命令清除了log的内容,就会产生这样的文件。这里有这种文件的介绍。

上面3种是我所知的,应该还有其他情况,欢迎留言补充。

用RG100A实现ADSL拨号

最近又搬家了,需要重新办理宽带。问了下电信和网通的价格,虽然华数网通便宜很多,但是那句“一分钱,一分货”还真是一点都没错,之前用过才知道网通不是一般的垃圾,详见我以前的牢骚,所以还是办理了电信宽带。
这电信的入户方式和网通不一样,是电话线入户的,也就是说局端接过来的是一个RJ11的水晶头,然后电信会给一个modem,一般的上网方式就是在modem后面接一个无线路由,再用路由拨号。
但是这样显然不够方便,因为我的路由器是淘宝上淘的RG100A-AA,上面是有RJ11接口的,如果能用路由器直接拨号,就可以抛开电信给的modem了,这样会环保很多(至少modem的电源就不需要了)。
然而,我的路由器默认刷的是OpenWRT的固件,这固件是完全开源的,功能非常强大,什么电驴、BT、samba、FTP、print server统统支持,但是唯独不支持adsl拨号。。。查其原因,据说是BCM系列芯片的adsl驱动是dlink享有版权的,并且不开源。想要用adsl功能必须给路由器刷上基于dlink的固件。
了解到这个信息以后,就开始搜索靠谱的dlink固件,最后我用的是这里下载(需注册)的,这个版本有web界面(英文)、有ssh。基本就可以玩了。
下载后在原来的OpenWRT的web界面里直接上传文件,再重启就刷好固件了,这步真是超乎想象的简单。
再次登录,就是dlink的界面了,默认的用户名和密码都是admin,进去以后,就可以进行一堆设置了,诸如wifi的ssid、密码之类的,都是大同小异,唯一值得一提的是ADSL拨号的设置:
要先在’Advanced Setup’里选择’Layer2 Interface’,就是OSI7层模型里的第二层了,下面有个’ATM Interface’,需要add一条记录,add的时候,会让你填两个数值,就是 VPI 和 VCI ,这两个值各地的运营商都会不一样,比如我这里是杭州余杭电信,这两个值是8/35,具体的值可以到网上查或者是打10000询问电信(不知道电信会不会告诉你)。关于ATM层的更多介绍详见这里
‘ATM Interface’ 设置好以后,就可以设置’WAN Service’了,这里需要选择刚刚设置好的ATM设备,比如我这是 ATM0/0_8_35 ,然后下一步就是填个账号和密码之类的,保存就会自动拨上ADSL了,整个过程还是蛮有趣的,还可以顺便学习一下底层的网络知识。

另外,据说已经有人把dlink的adsl模块二进制地移植到了OpenWRT了,并且已经可用了,说不定哪天我就回OpenWRT了,哈哈。