TGTGInsighttelegram intelligenceLIVE / telegram public index
Back to channels
Welcome to the Black Parade avatar

TGINSIGHT CHAT

Welcome to the Black Parade

@TheB1ackParade

Music

Death has many faces, I look forward to seeing this one.

Subscribers787Current channel subscribers
Tracked posts907Indexed post count
Recent reach15,204Sum of recent post views
Recent posts

Recent posts

Page 6 of 76 · 907 posts

Posted Dec 4

Spotify wrapped 说我是全球排名第 19 的 Kraftwerk 超级听众 😋 爽到了,可以写进简历了(

1,450 views

Posted Nov 29

习近平新时代中国特色社会主义思想是“一本读不完的大书”、“一座取不尽的富矿”、“一盏指航向的明灯”、“一支蓄满力的利箭”,要学出政治忠诚、学出如磐信念、学出过硬担当、学出思路办法,坚持真学真懂真信真用, 务求入脑入心入魂入行,真正把对党绝对忠诚融入血脉、铸入灵魂、浸入骨髓。 —— 甘肃省省长任振鹤,《学习时报》, http://ztjy.people.cn/n1/2023/0714/c457340-40035598.html

723 views

Posted Nov 29

Lance Yang 老师昨晚在评论区为我指明方向,我觉得这个很重要所以整理了一下单独发出来,因为这个问题在互联网上似乎搜不到正确的信息,AI 也全军覆没。 envoy sidecar 在云原神里被用做透明代理,pod -> remote 的流量(几乎)被全量劫持到同一 netns 里的 envoy,实际路径是 pod -> envoy -> reomte (正向代理,两个 tcp 会话)。不过 envoy sidecar 劫持流量默认不使用炫酷的 tproxy,而是古典的 REDIRECT iptables -t nat -A OUTPUT -j REDIRECT --to-ports 15001 把 packets DNAT 成 127.0.0.1:15001。 envoy 劫持到这个流量之后,通过 getsockopt(SO_ORIGINAL_DST) 拿到原始的 dip:dport。 回程的 rev-DNAT 由 nf conntrack 隐式处理。 这看起来没有问题,但是注意力稍微集中一点就能意识到 DNAT 之后可以导致连接冲突。我们可以显式地尝试构造这种冲突: import socket, sys, time sk = socket.socket() sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sk.bind(('', 19233)) sk.connect((sys.argv[1], int(sys.argv[2]))) time.sleep(1000) 先运行 python main.py1.1.1.1:80 建立一个 nodeip:19233 -> 1.1.1.1:80,然后再运行 python main.py1.0.0.1:80 建立一个 nodeip:19233 -> 1.0.0.1:80。两个 tcp 连接有不同的 dip,零冲突,很合规。 但是 iptables DNAT 之后,两个连接都变成了 nodeip:19233 -> 127.0.0.1:15001,这样后发起握手的连接似乎必被 reset,就算安慰自己“这应该是小概率事件”,严肃的工程师都应该意识到这绝对会让生产爆炸。 但是真的如此吗? 立刻着手测试,发现第二个 tcp 其实也能成功握手,ss 看到第二个连接的 sport 居然被 SNAT 了,这就是昨晚 Lance Yang 的发现: nf_nat_redirect_ipv4 -> nf_nat_redirect -> nf_nat_setup_info -> get_unique_tuple -> nf_nat_l4proto_unique_tuple -> nf_nat_used_tuple_harder 有趣。最新代码,NAT REDIRECT 如果源端口检测到冲突后会自动进行源端口重分配 。。。 用 pwru 追一下 skb,会发现还要稍微复杂一点点,以下是 pwru --all-kmods --filter-track-skb 'tcp[tcpflags]=tcp-syn and src port 19233' 的导演剪辑版: 10.0.0.16:19233->1.0.0.1:80 ip_local_out 10.0.0.16:19233->1.0.0.1:80 __ip_local_out 10.0.0.16:19233->1.0.0.1:80 nf_hook_slow // iptables -A OUTPUT -t nat -j REDIRECT 10.0.0.16:19233->1.0.0.1:80 nft_nat_do_chain[nft_chain_nat] 10.0.0.16:19233->1.0.0.1:80 redirect_tg4[xt_REDIRECT] // DNAT, be aware of changes of dport and dip, and re-route 10.0.0.16:19233->1.0.0.1:80 l4proto_manip_pkt[nf_nat] 10.0.0.16:19233->1.0.0.1:15001 nf_csum_update[nf_nat] 10.0.0.16:19233->1.0.0.1:15001 inet_proto_csum_replace4 10.0.0.16:19233->1.0.0.1:15001 inet_proto_csum_replace4 10.0.0.16:19233->127.0.0.1:15001 ip_route_me_harder // iptables POSTROUTING 10.0.0.16:19233->127.0.0.1:15001 apparmor_ip_postroute // extra SNAT due to conflicts, be aware of the change of sport 10.0.0.16:19233->127.0.0.1:15001 l4proto_manip_pkt[nf_nat] 10.0.0.16:46801->127.0.0.1:15001 nf_csum_update[nf_nat] 额外的 SNAT 并非发生在 -j REDIRECT 的 OUTPUT nat 里,而推迟到了 POSTROUTING nat,通过 ct 来传递 SNAT 信息。nf_nat_redirect_ipv4 只会计算出需要 SNAT 的新端口,记录到 ct 里,待到 POSTROUTING 再 SNAT。 如果此时再加入一些 SNAT --to-source 会怎样,其实也不会怎样,ct 只有一条干净的 entry 记录 10.0.0.16:19233 -> 1.0.0.1:80 被 NAT 成 127.0.0.1:13902 -> 127.0.0.1:15001,所有 ip port 都被换过。 这对 envoy 用户态调用 getsockopt(SO_ORIGINAL_DST) 没有影响,rev-NAT 也无需用户态操心,延迟 SNAT 的行为目测半完全正确(否则在 OUTPUT 发生隐式 SNAT 、影响 POSTROUTING 的规则命中就绝了😊),就算 POSTROUTING 再次命中显式 SNAT 也没关系,几乎不会踩坑(除了要消耗 ct),唯一需要注意的就是在旁路观测的时候不能通过 socket tuple 来配对 client socket 和被劫持的 conn socket 😭因为我真的就在这么干,周一改。

1,460 views

Posted Nov 28

在 lwn 读到的一些有意思的技术文章但是自己并无深刻的见解,就时不时一起放送好了 😵 racket 9.0 发版!每次看到 lisp 系那些稀奇古怪的术语都觉得耳目一新(当然也是因为我没什么见识 😭),比如 black-box! https://docs.racket-lang.org/reference/black-box.html#%28def._%28%28quote._~23~25kernel%29._black-box%29%29 gcc15 新增了 counted_by attribute 来告诉编译器 FAM 的长度 #include <stdio.h> struct A { unsigned count; int buf[] __attribute__ ((counted_by (count))); }; static struct A __attribute__ ((noinline)) *alloc_buf (unsigned sz) { struct A *obj = __builtin_malloc (sizeof(struct A) + sz * sizeof(int)); obj->count = sz; return obj; } int main () { struct A *p = alloc_buf (10); printf("Size of buf is: %d\n", __builtin_dynamic_object_size(p->buf, 1)); p->buf[12] = 22; // out-of-bound access return 0; } 上面的代码在 gcc -fsanitize=bounds main.c 之后运行直接 out of bound runtime error oracle 的华人工程师干的: https://blogs.oracle.com/linux/improving-gcc-buffer-overflow-detection-for-c-flexible-array-members 不过我本来抱着零成本的预期(为什么?我被 bpf verifier 虐出幻觉了吗?),看了一下发现 buf[12] 会被编译成为 call __ubsan_handle_out_of_bounds,合理。。。 相信每个从 docker 时代走过来的云原神工程师都有找不到 netns 的心酸时刻,不过黑暗的日子要过去了,因为,listns() API 制作决定!这种愿意清理技术债、减小项目熵的工程师,我愿意称之为伪人,啊不是,伟人! https://lwn.net/Articles/1043824/ PEP 805 Safe Parallel Python,给 list.append / set.add 等之前在 GIL 保护下是线程安全的操作开始打补丁,我是并发弱智所以看到什么都叫好,比如我觉得下面这个自动解决“哲学家吃饭问题”的锁排序的糖就好: with a.__mutex__ + b.__mutex__: ... __protect__ 这些 API 看起来也很直观好用的样子。 https://pep-previews--4579.org.readthedocs.build/pep-0805/ envoy 默认劫持模式是用 iptables -j REDIRECT 把流量 DNAT 成 127.0.0.1:15001,而不是 tproxy。稍微思考就会意识到,有一种风险是,之前是两个连接 10.1.1.1:19233 -> 1.1.1.1:80 和 10.1.1.1:19233 -> 1.0.0.1:80,在 DNAT 之后两个 tuples 变成一样的了,这会导致代理冲突。不过内核真的会出现两个连接共用 src port 吗?cloudflare 对各种情况做了非常仔细的解读,唯一的问题是读了两遍之后我更加不明白 envoy 默认劫持模式是怎么能上生产的,这不会爆炸吗?🤬 https://blog.cloudflare.com/how-to-stop-running-out-of-ephemeral-ports-and-start-to-love-long-lived-connections/

1,460 views

Posted Nov 24

iBug 大哥给 pwru 提个 issue,回旋到我这儿了 🫥🫥🫥 https://github.com/cilium/pwru/issues/627 #pwru

528 views

Hashtags

Posted Nov 24

我发现很多工程师可能不知道 linux 并没有 local -> local 这条网络链路,当我们 curl localhost:8000 的时候本质是走了一次 outbound 链路,然后被 lo 导回来,变成一次 inbound 链路。 所以熟悉 nf 立刻就知道一个 curl localhost 会走哪些 chains 了: 1. outbound: OUTPUT + POSTROUTING 2. inbound: PREROUTING + INPUT 这就是为什么 “网上最容易找到的 iptables 各 table 各 chain 关系的图,怎么都像是画图的人根本不知道还可以同一台机器内 process -> process 一样,只画了 interface -> process, interface -> interface, process -> interface,导致看不出 process -> process 会经过哪些 chain”。 如果自己用过 AF_PACKET + SOCK_RAW 模拟 tcpdump 抓包,会发现 lo 上会抓到双重流量,这就是因为一次 egress 一次 ingress (tcpdump 本身处理得很好所以你看不到 lo 的双重流量) 如果用 pwru 也能看到 lo 上的 rx 路径的软中断,是一次完整的收包链路。 所以,local -> local 的流量,本质是一次 tx + 一次 rx。

3,000 views

Posted Nov 22

隔壁 ibug 在仔细检查这张最著名的 netfilter 流程图 (https://en.wikipedia.org/wiki/Iptables#/media/File:Netfilter-packet-flow.svg) 是否准确,实在是太棒了,好喜欢他 (as a software engineer, not homosexually)。 其实我也有一大堆未解之谜,但已经暂时性地自暴自弃了,等他先排查一遍我再仔细学习一个。 截至目前 (2025-11-22) 仍在持续更新中: https://t.me/iBugThought/4833

1,630 views

Posted Nov 22

PEP 798 (Unpacking in Comprehensions) 被接受了: https://lwn.net/SubscriberLink/1046216/ddb88e8365f9bec2/ 想起以前我确实写过很多 def gen(): for x in it: yield from x g = gen() 之后都可以写成 g = (*x for x in it) 甜! 甜不甜的以后再说,我其实觉得里面这段 motive 很有趣 This proposal was motivated in part by a written exam in a Python programming class, where several students used the proposed notation (specifically the set version) in their solutions, assuming that it already existed in Python. This suggests that the notation represents a logical, consistent extension to Python's existing syntax. By contrast, the existing double-loop version [x for it in its for x in it] is one that students often get wrong, the natural impulse for many students being to reverse the order of the for clauses. 想起费曼也常常说教学工作很有趣,学生也许会想出古怪的问题,但是为什么不呢?顺着初学者的问题思考下去也许能看到新的视角。 The questions of the students are often the source of new research. They often ask profound questions that I’ve thought about at times and then given up on, so to speak, for a while. It wouldn’t do me any harm to think about them again and see if I can go any further now. The students may not be able to see the thing I want to answer, or the subtleties I want to think about, but they remind me of a problem by asking questions in the neighborhood of that problem. It’s not so easy to remind yourself of these things. https://www.edwardtufte.com/notebook/richard-feynman-on-teaching/ 决定去当老师了!

703 views

Posted Nov 22

前同事在领英让我出来看疯狂丹尼尔把 qemu (kubevirt) 网络性能优化到 -30% lat +37% tput 的神迹,吓人🤯 手动 @ oilbeater keypoints: qemu 支持 AF_XDP backend + netkit 可以和网卡队列绑定 = qemu guest 内部直通 host 网卡一步到胃的快感 https://www.linkedin.com/posts/activity-7396101422947303424--r-4 (这群欧洲前同事还挺好的,已经是第四位跑来问我需不需要帮忙找工作,他们可以帮我宣传简历啥的。德国人 Julian 是特例,他还在偶尔用 “ Gray I assigned a PR to you" 的方式来表达关心 😂

426 views

Posted Nov 22

怎么去拥有一道彩虹 怎么去拥抱一夏天的风 那一些是非题 总让人伤透脑筋 (转向成恋爱频道中)

1,560 views

Posted Nov 20

这应该是马龙的退役之战了,goat 和副 goat 统治了乒坛十年,越过流言,在岁月里拥抱。 毫不夸张地说我是看着马龙长大的,不来梅的马龙长得还很像文革时期的习主席,后来莫斯科输波尔,在巴黎死活打不过王皓,再到 2014 杜塞尔多夫输张继科,他眼泪都要掉下来了,我每场都看,眼看他就要被打倒了,接下来涂满发胶两年直接大满贯。 2017 杜塞尔多夫和樊振东撕到决胜局九平成为史上最惨烈的世乒赛时,我男朋友从杜塞飞回北京,那张机票我至今都留着。2018 和爸在家一起看马龙被张本智和一穿三时,我已经拿到了去新加坡的 offer。2019 马龙捧起复刻杯的时,我陷入了大低谷,每天睡前希望自己不要醒来。2021 东京决赛第五局战略性回复体力,我吓得不敢看出门跑步。2022 新加坡大满贯,我请了两天的假,从周四到周日的每场比赛都去现场。2024 第三次捧起世界杯时,我激动了一个星期,高兴到失眠了两天,连发了两封贺电: https://t.me/c/1459082815/534 https://t.me/c/1459082815/536 陪伴是一个巨大的精神仓库,看着马龙从小孩成长为乒坛 goat,似乎看了一个人的一生,也镜子一样看到自己的成长。

1,900 views

Posted Nov 20

这个问题是 Leon Hwang 在他频道里讨论的,我整理成下面的形式。 server.py import socket, time s = socket.socket() s.bind(("127.0.0.1", 9999)) s.listen(1) conn, addr = s.accept() time.sleep(1) conn.send(b'a') time.sleep(1) print(conn.recv(1)) print(conn.recv(1)) conn.close() client.py import socket c = socket.socket(socket.AF_INET, socket.SOCK_STREAM) c.connect(("127.0.0.1", 9999)) c.close() 问服务端会两次 recv 会返回什么。 这里的复杂性在于服务端调用 recv 的时候,socket 先后收到了一个 fin 和一个 rst,目前内核 (6.14.0-29) 的表现是两次 recv 都返回 "" 即 fin 的语义,也就是说用户态永远也不可能知道对端发送了 rst。这导致了 Leon 在他生产环境遇到了问题,用户态读到了 fin,不认为这是什么异常,tcp 本来就允许保持单向打开,所以继续持有 fd;然而这个 socket 实际上已经收到了 rst,但用户态却无法知道,这导致了 tcp 连接泄露。 gpt-5.1 thinking 还在给我杠,说不会收到 rst,我抓包如下 10:02:57.750197 lo In IP 127.0.0.1.49768 > 127.0.0.1.9999: Flags [S], seq 2552411982, win 65495, options [mss 65495,sackOK,TS val 1139167411 ecr 0,nop,wscale 7], length 0 10:02:57.750225 lo In IP 127.0.0.1.9999 > 127.0.0.1.49768: Flags [S.], seq 2409881948, ack 2552411983, win 65483, options [mss 65495,sackOK,TS val 1139167411 ecr 1139167411,nop,wscale 7], length 0 10:02:57.750251 lo In IP 127.0.0.1.49768 > 127.0.0.1.9999: Flags [.], ack 1, win 512, options [nop,nop,TS val 1139167411 ecr 1139167411,exp-2333,nop,nop], length 0 10:02:57.750290 lo In IP 127.0.0.1.49768 > 127.0.0.1.9999: Flags [F.], seq 1, ack 1, win 512, options [nop,nop,TS val 1139167411 ecr 1139167411], length 0 10:02:57.752101 lo In IP 127.0.0.1.9999 > 127.0.0.1.49768: Flags [.], ack 2, win 512, options [nop,nop,TS val 1139167413 ecr 1139167411,exp-2333,nop,nop], length 0 10:02:58.751671 lo In IP 127.0.0.1.9999 > 127.0.0.1.49768: Flags [P.], seq 1:2, ack 2, win 512, options [nop,nop,TS val 1139168412 ecr 1139167411,exp-2333,nop,nop], length 1 10:02:58.751738 lo In IP 127.0.0.1.49768 > 127.0.0.1.9999: Flags [R], seq 2552411984, win 0, length 0 没来记得读 rfc,但隐约觉得似乎有点问题? (先继续做 slides,来不及了,要被开除了,如果哪位老师有什么想法或者我有哪里搞错了欢迎指出 🥹)

364 views
12•••45678•••10•••15•••20•••25•••30•••35•••40•••45•••50•••55•••60•••65•••70•••7576