跳转至

博客

每周分享第 41 期

  1. Wget2 1.99.2 beta 发布 https://lists.gnu.org/archive/html/info-gnu/2019-09/msg00001.html
  2. 独立的 printf 实现 https://github.com/mpaland/printf
  3. Unicode 字符串长度统计 https://hsivonen.fi/string-length/
  4. C 类型推断 https://github.com/ltcmelo/psychec#generic-programming
  5. Clang 9.0 支持 Linux 内核编译 The New Features Of LLVM 9.0 & Clang 9.0 - Includes Building The Linux x86_64 Kernel
  6. 可控制的 USB 设备 https://github.com/usb-tools/Facedancer
  7. USB 监听器 https://github.com/openvizsla/ov_ftdi
  8. 修复一个截断的视频 https://github.com/ponchio/untrunc

在 macOS 上创建 ESP 镜像文件

最近 rCore 添加了 UEFI 支持,在 QEMU 里跑自然是没有问题,然后尝试放到 VMWare 虚拟机里跑,这时候问题就来了:需要一个带有 ESP 盘的 vmdk 虚拟盘。搜索了一下网络,找到了解决方案:

hdiutil create -fs fat32 -ov -size 60m -volname ESP -format UDTO -srcfolder esp uefi.cdr

其中 60m espuefi.cdr 都可以按照实际情况修改。它会把 esp 目录下的文件放到 ESP 分区中,然后得到一个镜像文件:

uefi.cdr: DOS/MBR boot sector; partition 1 : ID=0xb, start-CHS (0x3ff,254,63), end-CHS (0x3ff,254,63), startsector 1, 122879 sectors, extended partition table (last)

接着转换为 vmdk:

qemu-img convert -O vmdk uefi.cdr uefi.vmdk

这样就可以了。

每周分享第 40 期

  1. TeX Typesetting Game https://texnique.xyz/
  2. Writing Linux Kernel Module in Rust https://github.com/fishinabarrel/linux-kernel-module-rust
  3. Sipeed Longan Nano RISC-V 开发板 https://readhacker.news/s/48EBG
  4. Systemd 加载 BPF 防火墙 https://kailueke.gitlab.io/systemd-bpf-firewall-loader/
  5. 方舟编译器 https://code.opensource.huaweicloud.com/HarmonyOS/OpenArkCompiler.git
  6. XLOOKUP 函数 https://techcommunity.microsoft.com/t5/Excel-Blog/Announcing-XLOOKUP/ba-p/811376
  7. SystemVerilog to Verilog 转译 https://github.com/zachjs/sv2v
  8. USB 4.0 发布 http://www.phoronix.com/scan.php?page=news_item&px=USB-4.0-Specification-Published
  9. Android 10 发布 http://www.phoronix.com/scan.php?page=news_item&px=Android-10-Released
  10. iOS 13.1 beta 2 发布
  11. 对 iOS 设备抓包 http://blog.imaou.com/opensource/2014/12/14/pcapd_diagnostic_packet_capture.html
  12. Google 的差分隐私库 https://developers.googleblog.com/2019/09/enabling-developers-and-organizations.html
  13. Apple Music 第三方 App https://github.com/Musish/Musish

每周分享第 39 期

  1. 另一个 Pattern Matching in C++ 库 https://github.com/mpark/patterns
  2. Rust 编写的一个 shell http://www.jonathanturner.org/2019/08/introducing-nushell.html
  3. Vim 的游戏教程 https://readhacker.news/s/48nbJ
  4. 在 throw 的时候同时抓取 SO 信息 https://github.com/shobrook/rebound/
  5. 颜色生成工具 https://github.com/sharkdp/pastel
  6. 转换 Escape Code 到 HTML https://github.com/theZiz/aha
  7. iOS 13.1 beta 发布
  8. 苹果特别活动定于 9.11 日
  9. exFAT 规范发布 http://www.phoronix.com/scan.php?page=news_item&px=Microsoft-exFAT-Specification
  10. 可视化的 5 阶段流水线 RISC-V 模拟器 https://github.com/mortbopet/Ripes

每周分享第 38 期

  1. 针对部分 HTTP/2 实现的新漏洞 https://github.com/Netflix/security-bulletins/blob/master/advisories/third-party/2019-002.md
  2. 只读 tmux 加魔改 https://brianmckenna.org/blog/guest_tmux
  3. Rust 编译期断言 https://github.com/nvzqz/static-assertions-rs
  4. Rust 运行时解压版的 include_bytes https://github.com/SOF3/include-flate
  5. 把 Rust 标准库进行 async 化的尝试 https://async.rs/blog/announcing-async-std/#
  6. git 添加 switch/restore 命令 https://github.blog/2019-08-16-highlights-from-git-2-23/
  7. Flash Player in Rust https://github.com/ruffle-rs/ruffle
  8. Matplotlib Cheatsheet https://github.com/rougier/matplotlib-cheatsheet
  9. macOS Catalina 10.15 beta 6 发布
  10. Flash Decompiler https://github.com/jindrapetrik/jpexs-decompiler
  11. Yubikey 发布 5Ci https://readhacker.news/s/489yu
  12. IBM 开放 Power 指令集 https://readhacker.news/s/48aiH
  13. iOS 13 beta 8 发布
  14. GitHub 支持 WebAuthn https://readhacker.news/s/48dXM
  15. 编译器优化带来的安全漏洞 https://readhacker.news/s/48dke
  16. obscure C features https://multun.net/obscure-c-features.html

每周分享第 37 期

  1. Rust netlink 库 https://github.com/jbaublitz/neli
  2. Rust 处理 signal 进行配置的 reload https://vorner.github.io/2019/08/11/runtime-configuration-reloading.html
  3. macOS 添加了 VirtIO 驱动支持 https://passthroughpo.st/mac-os-adds-early-support-for-virtio-qemu/
  4. 一个 GNU readline 替代品 https://github.com/AmokHuginnsson/replxx
  5. Rust 1.37.0 发布 https://blog.rust-lang.org/2019/08/15/Rust-1.37.0.html
  6. iOS 13 DB7 (17A5565b) 发布

macOS 下读取并解析 EDID

之前听说了 EDID 的存在,但是一直没有细究里面的格式和内容。今天了解了一下,发现其实非常简单,下面是方法:

首先获取所有显示器输出的 EDID:

ioreg -lw0 | grep IODisplayEDID

输出里会出现 "IODisplayEDID" = <00ffxxxxxxxxxxxxx> 的内容,尖括号内的就是 EDID 的内容。接着,我们采用 edid-decode 进行解析:

git clone git://linuxtv.org/edid-decode.git
cd edid-decode
make
./edid-decode
<Paste EDID here>

就可以看到很详细的 EDID 数据解析了。

ref: https://gist.github.com/OneSadCookie/641549 https://www.avsforum.com/forum/115-htpc-mac-chat/1466910-ability-dump-display-s-edid-mac.html

在 Linux 下捕获 Framebuffer

最近需要在 linux 下抓取 Framebuffer 的内容,在网上找到了两种方法,在我这里只有第二、第三种可以成功,没有细究具体原因,可能与我的 Framebuffer 配置有关。方法如下:

  1. fbgrab :命令就是 fbgrab image.png,直接得到 png 文件,格式是对的,但是用软件打开就是一片空白。用 ImageMagick 转换为 jpg 可以看到一些内容,但是和实际有些不一样。
  2. fbdump :命令就是 fbdump > image.ppm,得到裸的 ppm 文件,图像是正确的,也可以转换为别的格式正常打开。
  3. cat+脚本处理:直接 cat /dev/fb0 > image.rgb,然后用下面的脚本转换为 png。由于 Framebuffer 格式为 RGB,本来 A 所在的 channel 都为 0,所以用一些软件直接打开都是空白,只好写了脚本直接跳过 Alpha Channel。

Framebuffer 配置( fbset 输出):

mode "640x480-0"
        # D: 0.000 MHz, H: 0.000 kHz, V: 0.000 Hz
        geometry 640 480 1024 480 32
        timings 0 0 0 0 0 0 0
        accel false
        rgba 8/16,8/8,8/0,0/0
endmode

转换脚本(参考 [Tips] 擷取 framebuffer 畫面):

#!/usr/bin/perl -w

$w = shift || 240;
$h = shift || 320;
$pixels = $w * $h;

open OUT, "|pnmtopng" or die "Can't pipe pnmtopng: $!\n";

printf OUT "P6%d %d\n255\n", $w, $h;

while ((read STDIN, $raw, 4) and $pixels--) {
   $short = unpack('I', $raw);
   print OUT pack("C3",
      ($short & 0xff0000) >> 16,
      ($short & 0xff00) >> 8,
      ($short & 0xff));
}

close OUT;

用法: cat image.rgb | perl script.pl 1024 480 > console.png

每周分享第 36 期

  1. QuickJS + libuv https://github.com/saghul/qjsuv
  2. Rust 实现的 Ruby https://github.com/artichoke/artichoke
  3. 类似 JSON 的数据格式 https://cbor.io/
  4. rls 二代目 https://github.com/rust-analyzer/rust-analyzer
  5. 给 MacBook 添加触屏支持 https://github.com/bijection/sistine
  6. 用于 MBP with T2 的 Linux patch https://github.com/aunali1/linux-mbp-arch
  7. 在 tmux 中使用 Touch ID 认证 sudo https://blog.birkhoff.me/make-sudo-authenticate-with-touch-id-in-a-tmux/
  8. iOS 13 beta 6 发布
  9. Linux Journal 结束了它的使命
  10. ssh 8.0 Add support for ECDSA keys in PKCS#11 tokens

用 PulseView 配合 DSLogic 调试 SPI Flash

最近需要用到逻辑分析仪来调试 SPI Flash,设备是 DreamSourceLab 的 DSLogic,最开始用的是官方的 DSView,确实能够抓到 SPI 的信号,也可以解析出一些 SPI Flash 的数据,但是很多是不完整的。

后来把源码下载下来,发现是基于 sigrok 和 PulseView 做的一个魔改版,然后 sigrok 官网上最新的版本已经支持了 DSLogic,于是就用 PulseView 替代 DSView。一开始遇到的问题是没有 firmware,一番搜索找到了解决方案,按照脚本下载好文件即可。

进到 PulseView 以后,把 SPI 的四路信号接上,然后抓了一段信号,解析:

可以看到它正确地解析出来了 Fast Read 命令。由于 DSView 它 fork 自一个比较老的版本,所以它并不能正确解析出来。

P.S. Linux 下它界面显示比 macOS 下好看一些,估计是没有适配好。

每周分享第 35 期

  1. Apple Touch Bar 的 Windows 第三方支持 https://github.com/imbushuo/DFRDisplayKm
  2. WSL2 新的进展 http://www.phoronix.com/scan.php?page=news_item&px=Windows-WSL2-Localhost-Plus
  3. Lightning 转接头里面居然跑 iBoot 和 Darwin https://readhacker.news/s/46Zde
  4. iOS 13 beta 5 发布
  5. ES2019 前瞻 https://blog.tildeloop.com/posts/javascript-what%E2%80%99s-new-in-es2019
  6. Rust 可持久化数据结构 https://github.com/orium/rpds
  7. Rust 不可变数据结构 https://github.com/bodil/im-rs
  8. macOS Catalina 10.15 beta 5 发布
  9. Algebraic Effect https://overreacted.io/algebraic-effects-for-the-rest-of-us/
  10. Donald Knuth 对于 Sensitivity Proof 证明的简化 https://readhacker.news/s/47fsA 真是老当益壮
  11. TLS1.3 标准的简化版 https://readhacker.news/s/47eG9
  12. iTerm 3.3 发布 https://iterm2.com/downloads/stable/iTerm2-3_3_0.changelog

每周分享第 34 期

  1. macOS Mojave 10.14.6 iOS 12.4 正式版更新发布,还有老版本的更新 https://www.macrumors.com/2019/07/22/apple-releases-gps-bug-fix-older-iphones-ipads/
  2. CLion 2019.2 添加了 GDB Server 的调试支持,可以用 OpenOCD。

每周分享第 33 期

  1. 一个讲 Rust 比较硬核的博客 http://system.joekain.com/
  2. 利用 fzf 实现 shell 的 REPL https://github.com/pawelduda/fzf-live-repl
  3. 类似 Vue 的前端 Go 框架 https://www.vugu.org/doc/start
  4. iOS 13 beta 4 发布 14A5534f
  5. 针对 T2 NVMe 的 patch http://www.phoronix.com/scan.php?page=news_item&px=NVMe-Patches-LKML-Apple-Mac
  6. 一个前端非对称加密的问卷网站 https://blog.fugoes.xyz/crypto-q/

前端解析上传的 CSV

之前做过一个在前端解析上传的 CSV 的功能,但是只能支持部分的 encoding,遇到 gbk 就傻眼了。一番研究以后,找到了比较科学的方案:

import * as Chardet from 'chardet';
import * as Iconv from 'iconv-lite';

const reader = new FileReader();
reader.onload = (e) => {
  const data = e.target.result;
  const view = Buffer.from(data);
  // detect encoding and convert
  const encoding = Chardet.detect(view);
  const result = Iconv.decode(view, encoding);
  const csvData = Papa.parse(result).data;
  // do anything with it
};

reader.readAsArrayBuffer(blob_here);

依赖了两个库:chardeticonv-lite ,测试了一下,解析 UTF-8 GBK UTF-16BE 都没问题。

P.S. 在生成 csv 的时候,也会出现 Excel 打开后乱码的问题,一开始我以为需要转 UTF-16 然后再添加 BOM Mark,后来发现只要在最前面加上 0xEF 0xBB 0xFB(UTF-8 编码下的 BOM Mark)即可。

每周分享第 32 期

  1. Rpi4 的 Type-C 设计有问题 https://readhacker.news/s/45WYc
  2. Debian buster released
  3. USB Type-C Serial adapter with WCH/FTDI https://github.com/z4yx/USB-C-Serial
  4. Linux 5.2 Kernel released http://www.phoronix.com/scan.php?page=news_item&px=Linux-5.2-Released
  5. iOS/iPadOS PB2 发布,与 DB3 差了一个小版本号
  6. Pacman in 512 bytes of x86 boot sector machine code https://readhacker.news/s/466Zm
  7. clang 的 use after move checker 使用 https://awesomekling.github.io/Catching-use-after-move-bugs-with-Clang-consumed-annotations/

每周分享第 31 期

  1. 一个 Docker 的 TUI https://github.com/jesseduffield/lazydocker
  2. 在线 Git cheatsheet http://ndpsoftware.com/git-cheatsheet.html
  3. 带历史合并两个 Git 仓库 https://stackoverflow.com/a/10548919
  4. iOS 13 Dev Beta 3 https://mp.weixin.qq.com/s/6cxLXOYgeP6QkDpa9kdoug
  5. iOS 13 FaceTime Attention Correction https://readhacker.news/s/45QX2

每周分享第 30 期

  1. 一个可参考的防止 side channel attack 的方法 https://www.undeadly.org/cgi?action=article;sid=20190621081455

  2. 物理上镜像百兆的方法 实测可用 https://greatscottgadgets.com/throwingstar/

  3. 微软员工写的 malloc https://github.com/microsoft/mimalloc

  4. 超标量乱序执行的 x86 软核 https://tspace.library.utoronto.ca/bitstream/1807/80713/1/Wong_Henry_T_201711_PhD_thesis.pdf

  5. Rust 的 wireshark 替代 https://github.com/kpcyrd/sniffglue

  6. Rpi 4 发布 https://readhacker.news/s/45nK9

  7. iOS/macOS Catalina PB1 发布(= DB2)

  8. dbg! 移植到了 C++ https://github.com/sharkdp/dbg-macro

  9. 类似于 Elm 的 Rust 前端框架 https://github.com/David-OConnor/seed

  10. 访问 VMware 虚拟机串口的方法 https://thewayeye.net/2009/december/4/connecting-virtual-machines-serial-console-os-x-and-vmware-fusion/

每周分享第 29 期

  1. ZFS on Linux 发布 0.8.1 https://github.com/zfsonlinux/zfs/releases/tag/zfs-0.8.1
  2. slim: Dockerfile to VM image https://github.com/ottomatica/slim
  3. Rust 重写的 du 替代物 确实很快 https://github.com/Byron/dua-cli
  4. iOS 13/macOS Catalina beta 2 出了 并且可以 OTA 相关信息 https://9to5mac.com/2019/06/17/ios-13-beta-2-features/ https://developer.apple.com/documentation/macos_release_notes/macos_catalina_10_15_beta_2_release_notes https://mp.weixin.qq.com/s/Ae1SIcK9ho4Mh0g_UsbAyA
  5. Steam 已经解决了 Catalina 上 32 位程序不能运行的问题 https://www.reddit.com/r/MacOS/comments/c17lh8/steam_and_macos_catalina
  6. 在一些老的 Mac 上 Sidecar 是默认关闭的,但是可以开启 https://github.com/pookjw/SidecarPatcher/blob/master/README.md 虽然效果不会很好

IP 前缀转换上意外遇到的 Undefined Behavior

最近发现了两个很神奇的 Undefined Behavior,出现在 Prefix Len 和 Netmask 的转换的问题下。一个简单思路可能是:

#define PREFIX_BIN2DEC(bin) (32 - __builtin_ctz((bin)))
#define PREFIX_DEC2BIN(hex) (((~0) >> (32 - (hex))) << (32 - (hex))

乍一看,似乎没有什么问题。但是,在一些平台下,可能会出现这样的结果:

PREFIX_BIN2DEC(0x00000000) = 33
PREFIX_DEC2BIN(0) = 0xFFFFFFFF

而且只能在一些平台上不确定地复现,最后发现其实是 Undefined Behavior,在 C 的标准中:

In any case, the behavior is undefined if rhs is negative or is greater or equal the number of bits in the promoted lhs.

意味着, 0xFFFFFFFF >> 32 是一个 UB,所以出现了上面的问题。

另外,__builtin_ctz 有这样的说明:

Returns the number of trailing 0-bits in x, starting at the least significant bit position. If x is 0, the result is undefined.

意味着,__builtin_ctz(0) 也是一个 UB,所以得到了错误的结果。

解决方案也很简单,下面提供一个参考的解决方法:

#define PREFIX_BIN2DEC(bin) ((bin) ? (32 - __builtin_ctz((bin))) : 0)
#define PREFIX_DEC2BIN(hex) (((uint64_t)0xFFFFFFFF << (32 - (hex))) & 0xFFFFFFFF)

Quagga 的实现:

/* Convert masklen into IP address's netmask (network byte order). */
void
masklen2ip (const int masklen, struct in_addr *netmask)
{
  assert (masklen >= 0 && masklen <= IPV4_MAX_BITLEN);

  /* left shift is only defined for less than the size of the type.
   * we unconditionally use long long in case the target platform
   * has defined behaviour for << 32 (or has a 64-bit left shift) */

  if (sizeof(unsigned long long) > 4)
    netmask->s_addr = htonl(0xffffffffULL << (32 - masklen));
  else
    netmask->s_addr = htonl(masklen ? 0xffffffffU << (32 - masklen) : 0);
}

/* Convert IP address's netmask into integer. We assume netmask is
   sequential one. Argument netmask should be network byte order. */
u_char
ip_masklen (struct in_addr netmask)
{
  uint32_t tmp = ~ntohl(netmask.s_addr);
  if (tmp)
    /* clz: count leading zeroes. sadly, the behaviour of this builtin
     * is undefined for a 0 argument, even though most CPUs give 32 */
    return __builtin_clz(tmp);
  else
    return 32;
}

BIRD 的解决方法:

/**
 * u32_mkmask - create a bit mask
 * @n: number of bits
 *
 * u32_mkmask() returns an unsigned 32-bit integer which binary
 * representation consists of @n ones followed by zeroes.
 */
u32
u32_mkmask(uint n)
{
  return n ? ~((1 << (32 - n)) - 1) : 0;
}

/**
 * u32_masklen - calculate length of a bit mask
 * @x: bit mask
 *
 * This function checks whether the given integer @x represents
 * a valid bit mask (binary representation contains first ones, then
 * zeroes) and returns the number of ones or 255 if the mask is invalid.
 */
uint
u32_masklen(u32 x)
{
  int l = 0;
  u32 n = ~x;

  if (n & (n+1)) return 255;
  if (x & 0x0000ffff) { x &= 0x0000ffff; l += 16; }
  if (x & 0x00ff00ff) { x &= 0x00ff00ff; l += 8; }
  if (x & 0x0f0f0f0f) { x &= 0x0f0f0f0f; l += 4; }
  if (x & 0x33333333) { x &= 0x33333333; l += 2; }
  if (x & 0x55555555) l++;
  if (x & 0xaaaaaaaa) l++;
  return l;
}

每周分享第 28 期

  1. Rust Sec https://github.com/RustSec/advisory-db
  2. opendrop 开源的 AirDrop 实现 https://github.com/seemoo-lab/opendrop
  3. 代码内嵌图片 https://javl.github.io/image2cpp/
  4. RAMBleed 攻击 https://readhacker.news/s/44MHD
  5. WSL2 可以体验了 https://devblogs.microsoft.com/commandline/wsl-2-is-now-available-in-windows-insiders/
  6. Rust 2019 生态报告 https://www.jetbrains.com/lp/devecosystem-2019/rust/

每周分享第 27 期

高考加油!

  1. Fallout 漏洞 https://arxiv.org/abs/1905.12701
  2. PageRank 专利到期 https://patents.google.com/patent/US6285999B1/en
  3. 终端电量可视化 https://github.com/svartalf/rust-battop
  4. 查找 DB 的 DB https://dbdb.io
  5. 在 Rust 里写 GPU 程序 https://github.com/calebwin/emu
  6. WWDC 2019 挺不错的
  7. Alfred 4 发布 https://www.alfredapp.com/blog/announcements/alfred-4-is-here/
  8. Mac Pro AR https://www.apple.com/105/media/us/mac-pro/2019/36178e80-30fd-441c-9a5b-349c6365bb36/quick-look/case-on.usdz
  9. VSCode 稳定版也可以 Remote 了 https://code.visualstudio.com/docs/remote/ssh
  10. 2019 高考语文作文 https://mp.weixin.qq.com/s/2NwkbbMlAUJpOKKuln1T4g

在 FPGA 上实现路由器(3)

前言

又半个月过去了,在写了上篇系列博文之后也是做了很多新的更改。上次做的主要是关于性能方面的提升,怎么提高频率,从而达到比较大的流量,而这段时间做的则是功能,做实现 RIP 协议和转发表的动态更新。

软件部分

软件部分目前是用 C 代码写的,用 Xilinx SDK 提供的各个 AXI 外设的驱动和 PS 自己的驱动,实现了所需要的,RIP 协议的处理,转发表的更新和统计信息的读取。

实际上做的时候比较粗暴,主要是通过三种 AXI 外设与硬件部分进行交互:AXI Stream FIFO,AXI GPIO 和 AXI BRAM Controller。其中 AXI Stream FIFO 是用来接收和发送需要 CPU 处理的以太网帧的,AXI GPIO 则是用来读取统计的信息,AXI BRAM Controller 是用来读写转发表的。最后在顶层设计中把这些外设连接起来。

硬件部分

硬件部分还是继续之前的部分往下写,添加了统计信息,直接暴露出去,让 CPU 走 AXI GPIO 读,因为不需要很高的精确度;转发表本身,一开始想的是自己写一些接口转换,后来发现,直接用 True Dual Port RAM 然后把一个 port 暴露给 AXI BRAM Controller 即可,免去了各种麻烦,PS 可以直接进行修改,不需要额外的工作。

最终效果

为了测试这套东西是否正常工作,就开了两个 Arch Linux 的虚拟机,分别 Bridge 到两个千兆的 USB 网卡上,都连到 FPGA 上。然后在两边都配上了 BIRD,配置 RIP 和一些路由,确实能更新硬件的转发表,并两边的 RIP 可以学习到对方的路由。

每周分享第 26 期

  1. Grafana 6.2 发布 https://grafana.com/blog/2019/05/22/grafana-v6.2-released/
  2. Program Synthesis Talk by Paul Zhu https://paulz.me/talk/program-synthesis/
  3. VSCode 摸鱼插件 https://github.com/cteams/Thief-Book
  4. 编译期 C++ 计算器 https://www.zhihu.com/question/28582706/answer/691444859
  5. 一个在线的 tomasulo 算法实现 https://tomasulo.harrychen.xyz/
  6. Safari Technology Preview 83 发布,含 WebAuthN 支持 https://webkit.org/blog/8967/release-notes-for-safari-technology-preview-83/
  7. Markdown -> 微信 https://github.com/lyricat/wechat-format
  8. Rust 的 Code Coverage 库 https://github.com/xd009642/tarpaulin

IP 和 UDP Checksum 的增量更新问题

之前在写 IP Checksum 的增量更新,就是当 TTL -= 1 的时候,Checksum 应该增加 0x0100,但是这样会有问题,在于,如果按照原来的 IP Checksum 计算方法,是不会出现 0xFFFF 的(求和,进位,然后取反写入),这种加法就有可能出现 0xFFFF。于是翻阅了相关的 RFC:

首先是 RFC 1141 相关部分:

unsigned long sum;
ipptr->ttl--;                  /* decrement ttl */
sum = ipptr->Checksum + 0x100;  /* increment checksum high byte*/
ipptr->Checksum = (sum + (sum>>16)) /* add carry */

这也是比较直接能想到的一种方法,但是会出现刚才提到的问题。于是 RFC 1624 纠正了这个问题:

  Although this equation appears to work, there are boundary conditions
   under which it produces a result which differs from the one obtained
   by checksum computation from scratch.  This is due to the way zero is
   handled in one's complement arithmetic.

   In one's complement, there are two representations of zero: the all
   zero and the all one bit values, often referred to as +0 and -0.
   One's complement addition of non-zero inputs can produce -0 as a
   result, but never +0.  Since there is guaranteed to be at least one



Rijsinghani                                                     [Page 2]

RFC 1624             Incremental Internet Checksum              May 1994


   non-zero field in the IP header, and the checksum field in the
   protocol header is the complement of the sum, the checksum field can
   never contain ~(+0), which is -0 (0xFFFF).  It can, however, contain
   ~(-0), which is +0 (0x0000).

   RFC 1141 yields an updated header checksum of -0 when it should be
   +0.  This is because it assumed that one's complement has a
   distributive property, which does not hold when the result is 0 (see
   derivation of [Eqn. 2]).

   The problem is avoided by not assuming this property.  The correct
   equation is given below:

          HC' = ~(C + (-m) + m')    --    [Eqn. 3]
              = ~(~HC + ~m + m')

只要把代码简单修改一下就可以了,或者遇到 0xFFFF 时设为 0,这时候就解决了这个问题。

但是,仔细研究了一下发现,UDP Checksum 又是这么定义的(RFC 768):

If the computed  checksum  is zero,  it is transmitted  as all ones (the
equivalent  in one's complement  arithmetic).   An all zero  transmitted
checksum  value means that the transmitter  generated  no checksum  (for
debugging or for higher level protocols that don't care).

刚好和 IP Checksum 相反,这就很有意思了。

用 htpdate 替代 ntpdate 实现时间同步

最近用 ntpdate 的时候遇到了一些麻烦,时间同步总是遇到各种问题。后来搜了搜,发现了一个解决方案:htpdate,它通过 HTTP 头里的 Date 字段获取时间,虽然没有 ntp 那么精确,但是大多时候都够用。

用法见 htpdate(8)