https://github.com/fluent/fluent-bit

可以看作用 C 重写的 Fluentd,功能暂时还不够多,核心部分也还没有利用上多线程。当然 C 的内存安全问题也会影响 Fluent Bit,开发者需要下很大功夫才能保证内存安全。

缺点不少为什么还是要推荐一下它呢?其实败也 C,成也 C。尽管 C 有不少缺点,但作为最接近机器和 POSIX 内核的语言,Fluent Bit 的潜力还是很大的。

  • 性能:通过异步 I/O 性能已经~达到 Node.js 的水平~很不错了,正在开发中的多线程模式能进一步解决性能瓶颈。
  • 可维护性:代码非常规范,可读性不错。
  • 可靠性和数据完整性:作为核心卖点之一,开发者还是很重视这两方面的问题的。实在不行直接上系统调用自己实现,C 可没有其他语言那么多顾虑。
  • 可扩展性:简单需求 Lua 解决,复杂的也支持用 C、WebAssembly 和 Go 写自定义插件,当然使用 Go 和 Lua 都有一定性能损耗。注意 Go 只能用于输入和输出插件,WebAssembly 只能用于输入和过滤器插件,C 的话都可以。

IPv6 relay 模式怎么配置网上有一大把教程,就不多说了。重点在于为什么客户端能获取地址却 ping 不通公网,但 ping 一下路由器的 wan IPv6 地址后就可以上网了。通过在客户端设备上抓包和查看 ip neigh(或 ndp -an)可以发现,区别在于 IPv6 的邻居发现过程。

正确方式

IP6 fe80::xxxx > [solicited-node multicast address]: ICMP6, neighbor solicitation, who has [client address], length 32
IP6 fe80::yyyy > fe80::xxxx: ICMP6, neighbor advertisement, tgt is [client address], length 32

错误方式(路由器在 lan 侧找不到客户端 IP)

IP6 fd..:[ULA-prefix address] > [solicited-node multicast address]: ICMP6, neighbor solicitation, who has [target address], length 32

为什么错误方式下邻居发现会失败呢?原因是纯 relay 模式下客户端不会获取到 ULA-prefix1 下的地址/路由/邻居信息,当客户端尝试回复从路由器发出的 ULA-prefix 下地址的 neighbor solicitation 时,匹配不到这个 ULA 地址的路由只好放弃。

那么为什么 ping 一下网又通了呢?这是因为 odhcpd 从 wan 那边获取到了客户端的信息,从而配置上了 NDP 代理和路由。将 odhcpd 的 loglevel 配置成 7(LOG_DEBUG,数字来自syslog(3))后可以看到对应的 proxy 日志。

所以只要去掉路由器 lan 上的 ULA 就可以了,也就是在 network 配置中注释掉 ip6assign。重启路由器后,客户端就可以正常上网了。

另一种可能的方式是同时启用 lan 上 ULA 和 relay 的地址分配,不过 relay 模式下不好实现。

最后剩下一个问题,中继模式下首次请求延迟会比较高,之后就正常了,这部分原理可以参考 https://blog.icpz.dev/articles/notes/odhcpd-relay-mode-discuss/

参考资料

https://openwrt.org/docs/guide-user/network/ipv6/start#ipv6_relay

# cat /etc/config/dhcp
config dhcp lan
    option dhcpv6 relay
    option ra relay
    option ndp relay
    ...
 
config dhcp wan6
    option dhcpv6 relay
    option ra relay
    option ndp relay
    option master 1
    option interface wan6

笔者注:如非必要建议关闭 dhcpv6,原因见 https://issuetracker.google.com/issues/36949085


https://datatracker.ietf.org/doc/html/rfc4291#section-2.7.1

Solicited-Node multicast address are computed as a function of a
node's unicast and anycast addresses. A Solicited-Node multicast
address is formed by taking the low-order 24 bits of an address
(unicast or anycast) and appending those bits to the prefix
FF02:0:0:0:0:1:FF00::/104 resulting in a multicast address in the
range

     FF02:0:0:0:0:1:FF00:0000

to

     FF02:0:0:0:0:1:FFFF:FFFF

https://openwrt.org/docs/guide-user/base-system/basic-networking

network.globals.ula_prefix='fd27:70fa:5c1d::/48'

https://datatracker.ietf.org/doc/html/rfc4861#section-7.2.4

If the source of the solicitation is the unspecified address, the
node MUST set the Solicited flag to zero and multicast the
advertisement to the all-nodes address. Otherwise, the node MUST set
the Solicited flag to one and unicast the advertisement to the Source
Address of the solicitation.


P.S. Hybrid 模式是什么?其实就是智能开启 relay,代码如下,不要误以为是同时开启 relay 和 server 模式。

            /* Resolve hybrid mode */
            if (i->dhcpv6 == MODE_HYBRID)
                i->dhcpv6 = (master && master->dhcpv6 == MODE_RELAY) ?
                        MODE_RELAY : MODE_SERVER;

            if (i->ra == MODE_HYBRID)
                i->ra = (master && master->ra == MODE_RELAY) ?
                        MODE_RELAY : MODE_SERVER;

            if (i->ndp == MODE_HYBRID)
                i->ndp = (master && master->ndp == MODE_RELAY) ?
                        MODE_RELAY : MODE_DISABLED;

odhcpd 的 README 里有这么一段,说明客户端地址在路由器上的路由是它配置的。

4. Proxy for Neighbor Discovery messages (solicitations and advertisements)
   a) support for auto-learning routes to the local routing table
   b) support for marking interfaces "external" not proxying NDP for them
      and only serving NDP for DAD and for traffic to the router itself
      [Warning: you should provide additional firewall rules for security]

https://gitlab.com/muttmua/mutt

最出名的终端邮件客户端之一。对纯文本邮件支持极佳,支持树状展示邮箱、IMAP、正则搜索、GPG、S/MIME 加密等功能。和 vim 类似,熟练后配置好可以大幅提升工作效率。

虽然不支持编写 HTML 邮件,但这也是一个优势。很多开源社区更欢迎甚至要求使用纯文本邮件,因为纯文本更加易读、易排版、占用磁盘空间小。