[{"data":1,"prerenderedAt":1313},["ShallowReactive",2],{"content:\u002Fen\u002Ffiddling\u002Fdebian-as-bypass-router":3,"series:content_en":604},{"id":4,"title":5,"authorship":6,"body":7,"categories":569,"date":571,"description":572,"draft":573,"extension":574,"image":575,"meta":576,"navigation":578,"path":579,"permalink":580,"published":580,"readingTime":581,"recommend":580,"references":580,"seo":586,"seoDescription":587,"seoTitle":588,"sitemap":589,"stem":595,"tags":596,"type":602,"__hash__":603},"content_en\u002Fposts\u002Ffiddling\u002Fdebian-as-bypass-router.md","Using Debian as a Side Router","human-only",{"type":8,"value":9,"toc":546},"minimark",[10,15,19,35,38,41,48,51,54,58,61,64,67,73,76,82,85,89,92,97,105,115,118,150,153,161,168,174,180,183,187,190,196,200,203,209,212,215,219,222,228,232,238,244,254,262,269,275,278,284,288,295,302,308,311,314,317,323,327,330,334,337,343,346,351,357,360,366,375,381,384,387,390,398,404,407,411,417,425,428,436,439,453,456,460,463,469,475,481,484,490,493,499,503,509,515,518,524,530,533,537],[11,12,14],"h3",{"id":13},"introduction","Introduction",[16,17,18],"p",{},"Most side-router setups use OpenWrt, a separate Linux distribution with its own package system. Most of those also rely on LuCI, OpenWrt’s dedicated web GUI, and tutorials use luci-app-xxx software built specifically for it. These approaches are good, but not quite good enough:",[20,21,22,26,29,32],"ol",{},[23,24,25],"li",{},"Too much dependence on GUI configuration: LuCI packages generally expose only limited options in the web interface.",[23,27,28],{},"LuCI is not stable enough. I mean LuCI, not OpenWrt itself. OpenClash has crashed my LuCI three times—though that might have been my fault.",[23,30,31],{},"We can compile OpenWrt ourselves, but most tutorials use prebuilt firmware, some of which may be outdated.",[23,33,34],{},"You cannot fully control the system. LuCI has taken the reins!",[16,36,37],{},"I spent a year or two tinkering with OpenWrt transparent proxying, both on the main router and with a side router, but eventually gave up because it was not stable enough. For a long time I muddled through with clients such as Surge, Loon, and Clash Verge Rev. About a week ago, Zenless Zone Zero launched. Because of the Chinese release-approval situation, PS5 only got the international version. Even the Asia server barely worked directly, with hopeless speeds and latency. Determined not to hand money to NetEase UU, I thought of transparent proxying again. I happened to have an idle Beelink mini PC with Debian already installed. It was supposed to be a development machine, but laziness had left it gathering dust. After a weekend of tinkering, I finally had Debian working as a side router for transparent proxying.",[16,39,40],{},"Here is the final network topology:",[16,42,43],{},[44,45],"img",{"alt":46,"src":47},"topo","https:\u002F\u002Fblog-img.774352199.xyz\u002F2025\u002Fc4347103c787f3d28b50a679e80aa0fe.png",[16,49,50],{},"The LAN is divided into two subnets, 192.168.6.0\u002F24 and 192.168.7.0\u002F24. The 6.0\u002F24 subnet is the default for devices that do not need censorship circumvention. Devices that need it go on 7.0\u002F24, with all their traffic forwarded through the side-router mini PC.",[16,52,53],{},"The core is AdGuard Home plus Clash. AdGuard Home handles ad filtering and related features, while Clash handles DNS routing and traffic proxying.",[11,55,57],{"id":56},"main-router-configuration","Main Router Configuration",[16,59,60],{},"The existing LAN uses 192.168.6.0\u002F24. We need to add 192.168.7.0\u002F24.",[16,62,63],{},"My main router runs iKuai, so here is how to add a subnet there. For OpenWrt or other router systems, Google the equivalent.",[16,65,66],{},"In iKuai, go to Network Settings → LAN\u002FWAN Settings → lan1. Under Advanced Settings, add an extended IP of 192.168.7.1 with subnet mask 255.255.255.0.",[16,68,69],{},[44,70],{"alt":71,"src":72},"iKuai configuration","https:\u002F\u002Fblog-img.774352199.xyz\u002F2025\u002F9fc87b145274f1fb0cba1ed0d2329ac0.png",[16,74,75],{},"Add a DHCP configuration for 192.168.7.0\u002F24 in DHCP Settings.",[16,77,78],{},[44,79],{"alt":80,"src":81},"DHCP configuration","https:\u002F\u002Fblog-img.774352199.xyz\u002F2025\u002F2de91498b256d08c92a3c8844ca14dbe.png",[16,83,84],{},"Set the gateway to 192.168.7.2, the side router address we will configure later. Set both preferred and alternate DNS to 192.168.7.2 too, since the side router handles all DNS for this subnet.",[11,86,88],{"id":87},"debian-configuration","Debian Configuration",[16,90,91],{},"Unless stated otherwise, perform the following steps on the side router.",[93,94,96],"h4",{"id":95},"configure-the-ip-address","Configure the IP Address",[16,98,99,100,104],{},"Run ",[101,102,103],"code",{"code":103},"sudo nano \u002Fetc\u002Fnetwork\u002Finterfaces"," to edit Debian’s network configuration, replace it with the following, then save and exit:",[106,107,112],"pre",{"className":108,"code":110,"language":111},[109],"language-text","# This file describes the network interfaces available on your system\n# and how to activate them. For more information, see interfaces(5).\n\nsource \u002Fetc\u002Fnetwork\u002Finterfaces.d\u002F*\n\n# The loopback network interface\nauto lo\niface lo inet loopback\n\n# The primary network interface\nallow-hotplug enp1s0\niface enp1s0 inet static\naddress 192.168.7.2\nnetmask 255.255.255.0\ngateway 192.168.7.1\ndns-nameservers 127.0.0.1\n","text",[101,113,110],{"__ignoreMap":114},"",[16,116,117],{},"In this configuration:",[119,120,121,131],"ul",{},[23,122,123,126,127,130],{},[101,124,125],{"code":125},"enp1s0"," is my network interface name. Replace it with yours; ",[101,128,129],{"code":129},"ip a"," shows the available interfaces.",[23,132,133,134,137,138,141,142,145,146,149],{},"IPv4 uses static configuration, ",[101,135,136],{"code":136},"inet static",", fixing the address at ",[101,139,140],{"code":140},"192.168.7.2\u002F24"," and pointing the gateway to the main router at ",[101,143,144],{"code":144},"192.168.7.1",". Until setup is complete, use a working DNS server so you retain Internet access. Change DNS to ",[101,147,148],{"code":148},"127.0.0.1"," once AdGuard Home is configured locally.",[16,151,152],{},"After saving, restart networking with:",[106,154,159],{"className":155,"code":157,"language":158,"meta":114},[156],"language-shell","sudo systemctl restart networking.service\n","shell",[101,160,157],{"__ignoreMap":114},[16,162,163,164,167],{},"Your SSH session may disconnect because the IP address has changed. Reconnect over SSH to ",[101,165,166],{"code":166},"192.168.7.2",".",[16,169,170,171,173],{},"Check the result with ",[101,172,129],{"code":129},":",[106,175,178],{"className":176,"code":177,"language":158,"meta":114},[156],"ip a\n1: lo: \u003CLOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000\n    link\u002Floopback 00:00:00:00:00:00 brd 00:00:00:00:00:00\n    inet 127.0.0.1\u002F8 scope host lo\n       valid_lft forever preferred_lft forever\n    inet6 ::1\u002F128 scope host noprefixroute\n       valid_lft forever preferred_lft forever\n2: enp1s0: \u003CBROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000\n    link\u002Fether 70:70:fc:00:e3:36 brd ff:ff:ff:ff:ff:ff\n    inet 192.168.7.2\u002F24 brd 192.168.7.255 scope global enp1s0\n       valid_lft forever preferred_lft forever\n    inet6 ■■■:■■■■:■■■■:■■■:■■■■:■■■■\u002F64 scope global dynamic mngtmpaddr\n       valid_lft 1741sec preferred_lft 1741sec\n    inet6 fe80::7270:fcff:fe00:e336\u002F64 scope link\n       valid_lft forever preferred_lft forever\n",[101,179,177],{"__ignoreMap":114},[16,181,182],{},"The local LAN address is now 192.168.7.2\u002F24.",[93,184,186],{"id":185},"enable-forwarding","Enable Forwarding",[16,188,189],{},"A machine must be able to forward traffic to act as a router and gateway:",[106,191,194],{"className":192,"code":193,"language":158,"meta":114},[156],"sudo echo \"net.ipv4.ip_forward = 1\" >> \u002Fetc\u002Fsysctl.conf\nsudo sysctl -p\n",[101,195,193],{"__ignoreMap":114},[11,197,199],{"id":198},"adguard-home-configuration","AdGuard Home Configuration",[16,201,202],{},"Here is the DNS design:",[16,204,205],{},[44,206],{"alt":207,"src":208},"DNS path","https:\u002F\u002Fblog-img.774352199.xyz\u002F2025\u002Fbb62d86943fdce26364eea909c4621a9.png",[16,210,211],{},"When a client resolves a domain, AdGuard Home on port 53 forwards the query to its upstream, Clash. Clash then routes the query according to its settings: mainland Chinese domains use public DNS servers within China, while other domains use overseas public DNS servers through the proxy.",[16,213,214],{},"If Clash fails, AdGuard Home queries public DNS servers within China directly. In practice this is not very useful, since traffic still has to pass through Clash even if DNS succeeds.",[93,216,218],{"id":217},"install-adguard-home","Install AdGuard Home",[16,220,221],{},"Run these commands as root.",[106,223,226],{"className":224,"code":225,"language":158,"meta":114},[156],"## 检查最新稳定版的版本号，如果获取不到请检查网络\nremote_ver=$(curl -sS https:\u002F\u002Fapi.github.com\u002Frepos\u002FAdguardTeam\u002FAdGuardHome\u002Freleases\u002Flatest | jq -r .tag_name | sed 's|v||' | grep -v \"null\"); echo $remote_ver\n\n## 下载最新稳定版（前一句有输出这一句才能正常执行）\ncd \u002Ftmp\nwget -q --progress=bar:dot --show-progress -O \"AdGuardHome_linux_amd64.tar.gz\" \"https:\u002F\u002Fgithub.com\u002FAdguardTeam\u002FAdGuardHome\u002Freleases\u002Fdownload\u002Fv${remote_ver}\u002FAdGuardHome_linux_amd64.tar.gz\"\n\n## 解压\ntar --no-same-owner -xf \"AdGuardHome_linux_amd64.tar.gz\" --strip-components 2 --directory=.\n\n## 安装\ninstall -ps AdGuardHome \u002Fusr\u002Flocal\u002Fbin\u002Fadguardhome\n",[101,227,225],{"__ignoreMap":114},[93,229,231],{"id":230},"create-a-service","Create a Service",[16,233,234,235,167],{},"Create the working directory ",[101,236,237],{"code":237},"\u002Fvar\u002Flib\u002Fadguardhome",[106,239,242],{"className":240,"code":241,"language":158,"meta":114},[156],"mkdir -p \u002Fvar\u002Flib\u002Fadguardhome\n",[101,243,241],{"__ignoreMap":114},[16,245,246,247,250,251,167],{},"Create ",[101,248,249],{"code":249},"\u002Fetc\u002Fsystemd\u002Fsystem\u002Fadguardhome.service"," with the following contents. The configuration file will be ",[101,252,253],{"code":253},"\u002Fvar\u002Flib\u002Fadguardhome\u002FAdGuardHome.yaml",[106,255,260],{"className":256,"code":258,"language":259,"meta":114},[257],"language-ini","[Unit]\nDescription = Network-wide ads & trackers blocking DNS server.\nWants       = network-online.target mosdns.service\nAfter       = network-online.target mosdns.service\n\n[Service]\nType               = simple\nRestart            = always\nStartLimitInterval = 5\nStartLimitBurst    = 10\nExecStart          = \u002Fusr\u002Flocal\u002Fbin\u002Fadguardhome -w \u002Fvar\u002Flib\u002Fadguardhome\nRestartSec         = 10\n\n[Install]\nWantedBy = multi-user.target\n","ini",[101,261,258],{"__ignoreMap":114},[16,263,264,265,268],{},"Save it, then run ",[101,266,267],{"code":267},"systemctl enable --now adguardhome.service"," to start it immediately and enable it at boot. To view logs later, use Debian’s built-in tools:",[106,270,273],{"className":271,"code":272,"language":158,"meta":114},[156],"journalctl -efu adguardhome.service\n",[101,274,272],{"__ignoreMap":114},[16,276,277],{},"To restart it:",[106,279,282],{"className":280,"code":281,"language":158,"meta":114},[156],"systemctl restart adguardhome.service\n",[101,283,281],{"__ignoreMap":114},[93,285,287],{"id":286},"initial-setup","Initial Setup",[16,289,290,291,294],{},"Open ",[101,292,293],{"code":293},"http:\u002F\u002F192.168.7.2:3000"," for initial setup. Keep the web administration port at 3000 and set the DNS server port to 53.",[16,296,297,298,301],{},"Under Settings → DNS Settings, set upstream DNS to Clash at ",[101,299,300],{"code":300},"127.0.0.1:1053",", which we have not configured yet. Add a few DNS servers within China as fallback servers, for example:",[106,303,306],{"className":304,"code":305,"language":111},[109],"223.5.5.5\n119.29.29.29\n",[101,307,305],{"__ignoreMap":114},[16,309,310],{},"Remember to click Apply.",[16,312,313],{},"Then set DNS Server Configuration → Rate Limit to 0.",[16,315,316],{},"For ad blocking, add lists under Filters → DNS Blocklists. These two rule sets work well in mainland China:",[106,318,321],{"className":319,"code":320,"language":111},[109],"easylist:  https:\u002F\u002Fanti-ad.net\u002Feasylist.txt\nhalf-life: https:\u002F\u002Fadguard.yojigen.tech\u002FHalfLifeList.txt\n",[101,322,320],{"__ignoreMap":114},[11,324,326],{"id":325},"clash-configuration","Clash Configuration",[16,328,329],{},"Clash handles DNS routing between China and overseas, along with its usual job of getting through the wall. The original Clash repository was deleted and its maintainers disappeared, so Mihomo inherited the project. (Damn you, miHoYo.)",[93,331,333],{"id":332},"install-clash","Install Clash",[16,335,336],{},"Run the following as root:",[106,338,341],{"className":339,"code":340,"language":158,"meta":114},[156],"## 检查最新稳定版的版本号，如果获取不到请检查网络\nremote_ver=$(curl -sS https:\u002F\u002Fapi.github.com\u002Frepos\u002FMetaCubeX\u002Fmihomo\u002Freleases\u002Flatest | jq -r .tag_name | sed 's|v||' | grep -v \"null\"); echo $remote_ver\n\n## 下载最新稳定版（前一句有输出这一句才能正常执行）\ncd \u002Ftmp\nwget -q --progress=bar:dot --show-progress -O \"mihomo-linux-amd64-v${remote_ver}.gz\" \"https:\u002F\u002Fgithub.com\u002FMetaCubeX\u002Fmihomo\u002Freleases\u002Fdownload\u002Fv${remote_ver}\u002Fmihomo-linux-amd64-v${remote_ver}.gz\"\n\n## 解压\ngzip -d \"mihomo-linux-amd64-v${remote_ver}.gz\"\n\n## 安装\ninstall -ps mihomo-linux-amd64-v${remote_ver} \u002Fusr\u002Flocal\u002Fbin\u002Fclash\n",[101,342,340],{"__ignoreMap":114},[93,344,231],{"id":345},"create-a-service-1",[16,347,234,348,167],{},[101,349,350],{"code":350},"\u002Fvar\u002Flib\u002Fclash",[106,352,355],{"className":353,"code":354,"language":158,"meta":114},[156],"mkdir -p \u002Fvar\u002Flib\u002Fclash\n",[101,356,354],{"__ignoreMap":114},[16,358,359],{},"Create the clash user.",[106,361,364],{"className":362,"code":363,"language":158,"meta":114},[156],"useradd -M -s \u002Fusr\u002Fsbin\u002Fnologin clash\n",[101,365,363],{"__ignoreMap":114},[16,367,246,368,371,372,167],{},[101,369,370],{"code":370},"\u002Fetc\u002Fsystemd\u002Fsystem\u002Fclash.service"," with the following contents. Clash’s configuration file will be ",[101,373,374],{"code":374},"\u002Fvar\u002Flib\u002Fclash\u002Fconfig.yaml",[106,376,379],{"className":377,"code":378,"language":259,"meta":114},[257],"[Unit]\nDescription = Clash-Meta tproxy daemon.\nWants       = network-online.target\nAfter       = network-online.target\n\n[Service]\nEnvironment   = PATH=\u002Fusr\u002Flocal\u002Fsbin:\u002Fusr\u002Flocal\u002Fbin:\u002Fusr\u002Fsbin:\u002Fusr\u002Fbin:\u002Fsbin:\u002Fb>\nType          = simple\nUser          = clash\nGroup         = clash\n\nCapabilityBoundingSet = CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW\nAmbientCapabilities   = CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW\n\nRestart       = always\nExecStartPre  = +\u002Fusr\u002Fbin\u002Fbash \u002Fvar\u002Flib\u002Fclash\u002Fclean.sh\nExecStart     = clash -d \u002Fvar\u002Flib\u002Fclash\nExecStartPost = +\u002Fusr\u002Fbin\u002Fbash \u002Fvar\u002Flib\u002Fclash\u002Fiptables.sh\n\nExecStopPost  = +\u002Fusr\u002Fbin\u002Fbash \u002Fvar\u002Flib\u002Fclash\u002Fclean.sh\n",[101,380,378],{"__ignoreMap":114},[16,382,383],{},"As the unit file shows, the Clash binary runs as clash:clash. This makes it easy to distinguish traffic generated by Clash itself from traffic forwarded by Clash.",[16,385,386],{},"Notice that ExecStartPost and ExecStopPost run iptables.sh and clean.sh to set up and clear the routing rules.",[16,388,389],{},"Here are iptables.sh and clean.sh:",[106,391,396],{"className":392,"code":394,"language":395,"meta":114},[393],"language-sh","#!\u002Fusr\u002Fbin\u002Fenv bash\n\nset -ex\n\n# ENABLE ipv4 forward\nsysctl -w net.ipv4.ip_forward=1\n\n# ROUTE RULES\nip rule add fwmark 666 lookup 666\nip route add local 0.0.0.0\u002F0 dev lo table 666\n\n# clash 链负责处理转发流量\niptables -t mangle -N clash\n\n# 目标地址为局域网或保留地址的流量跳过处理\n# 保留地址参考：https:\u002F\u002Fzh.wikipedia.org\u002Fwiki\u002F%E5%B7%B2%E5%88%86%E9%85%8D%E7%9A%84\u002F8_IPv4%E5%9C%B0%E5%9D%80%E5%9D%97%E5%88%97%E8%A1%A8\niptables -t mangle -A clash -d 0.0.0.0\u002F8 -j RETURN\niptables -t mangle -A clash -d 127.0.0.0\u002F8 -j RETURN\niptables -t mangle -A clash -d 10.0.0.0\u002F8 -j RETURN\niptables -t mangle -A clash -d 172.16.0.0\u002F12 -j RETURN\niptables -t mangle -A clash -d 192.168.0.0\u002F16 -j RETURN\niptables -t mangle -A clash -d 169.254.0.0\u002F16 -j RETURN\n\niptables -t mangle -A clash -d 224.0.0.0\u002F4 -j RETURN\niptables -t mangle -A clash -d 240.0.0.0\u002F4 -j RETURN\n\n# 其他所有流量转向到 7893 端口，并打上 mark\niptables -t mangle -A clash -p tcp -j TPROXY --on-port 7893 --tproxy-mark 666\niptables -t mangle -A clash -p udp -j TPROXY --on-port 7893 --tproxy-mark 666\n\n# 最后让所有流量通过 clash 链进行处理\niptables -t mangle -A PREROUTING -j clash\n\n# clash_local 链负责处理网关本身发出的流量\niptables -t mangle -N clash_local\n\n# 跳过内网流量\niptables -t mangle -A clash_local -d 0.0.0.0\u002F8 -j RETURN\niptables -t mangle -A clash_local -d 127.0.0.0\u002F8 -j RETURN\niptables -t mangle -A clash_local -d 10.0.0.0\u002F8 -j RETURN\niptables -t mangle -A clash_local -d 172.16.0.0\u002F12 -j RETURN\niptables -t mangle -A clash_local -d 192.168.0.0\u002F16 -j RETURN\niptables -t mangle -A clash_local -d 169.254.0.0\u002F16 -j RETURN\n\niptables -t mangle -A clash_local -d 224.0.0.0\u002F4 -j RETURN\niptables -t mangle -A clash_local -d 240.0.0.0\u002F4 -j RETURN\n\n# 为本机发出的流量打 mark\niptables -t mangle -A clash_local -p tcp -j MARK --set-mark 666\niptables -t mangle -A clash_local -p udp -j MARK --set-mark 666\n\n# 跳过 clash 程序本身发出的流量，防止死循环 (clash 程序需要使用 \"clash\" 用户启动)\niptables -t mangle -A OUTPUT -p tcp -m owner --uid-owner clash -j RETURN\niptables -t mangle -A OUTPUT -p udp -m owner --uid-owner clash -j RETURN\n\n# 让本机发出的流量跳转到 clash_local\n# clash_local 链会为本机流量打 mark, 打过 mark 的流量会重新回到 PREROUTING 上\niptables -t mangle -A OUTPUT -j clash_local\n\n# 修复 ICMP(ping)\n# 这并不能保证 ping 结果有效 (clash 等不支持转发 ICMP), 只是让它有返回结果而已\n# --to-destination 设置为一个可达的地址即可\nsysctl -w net.ipv4.conf.all.route_localnet=1\niptables -t nat -A PREROUTING -p icmp -d 198.18.0.0\u002F16 -j DNAT --to-destination 127.0.0.1\n","sh",[101,397,394],{"__ignoreMap":114},[106,399,402],{"className":400,"code":401,"language":395,"meta":114},[393],"#!\u002Fusr\u002Fbin\u002Fenv bash\n\nset -ex\n\nip rule del fwmark 666 table 666 || true\nip route del local 0.0.0.0\u002F0 dev lo table 666 || true\n\niptables -t nat -F\niptables -t nat -X\niptables -t mangle -F\niptables -t mangle -X clash || true\niptables -t mangle -X clash_local || true\n",[101,403,401],{"__ignoreMap":114},[16,405,406],{},"Every line has detailed comments. Ask ChatGPT if you want to dig further.",[93,408,410],{"id":409},"clash-configuration-file","Clash Configuration File",[16,412,413,414,416],{},"Your proxy subscription provider can supply a Clash configuration in YAML format. Save it to ",[101,415,374],{"code":374}," and adjust the following sections:",[106,418,423],{"className":419,"code":421,"language":422,"meta":114},[420],"language-yaml","tproxy-port: 7893   # iptables.sh 将所有流量转发到了 7893 端口\nmixed-port: 7890\nallow-lan: true\nfind-process-mode: off\nbind-address: \"*\"\nmode: rule\nlog-level: debug\nipv6: false # 不进行 IPv6 流量代理\n\nexternal-controller: 0.0.0.0:9090\nsecret: # 登陆 ui 的密码\nexternal-ui: ui # webui 的基础路径\nexternal-ui-name: xd # webui 的下级路径\nexternal-ui-url: https:\u002F\u002Fgithub.com\u002FMetaCubeX\u002Fmetacubexd\u002Farchive\u002Frefs\u002Fheads\u002Fgh-pages.zip\nunified-delay: true\ntcp-concurrent: true\nexperimental:\n  sniff-tls-sni: true\ngeodata-mode: true\ngeodata-loader: standard\ngeox-url:\n  geoip: https:\u002F\u002Ftestingcf.jsdelivr.net\u002Fgh\u002FMetaCubeX\u002Fmeta-rules-dat@release\u002Fgeoip.dat\n  geosite: https:\u002F\u002Ftestingcf.jsdelivr.net\u002Fgh\u002FMetaCubeX\u002Fmeta-rules-dat@release\u002Fgeosite.dat\n  mmdb: https:\u002F\u002Ftestingcf.jsdelivr.net\u002Fgh\u002FMetaCubeX\u002Fmeta-rules-dat@release\u002Fcountry.mmdb\nprofile:\n  tracing: true\n  store-selected: true\n  store-fake-ip: true\nsniffer:\n  enable: true\n  parse-pure-ip: true\n  override-destination: true\n\ndns:\n  enable: true\n  ipv6: false\n  listen: 0.0.0.0:1053 # DNS 监听端口\n  use-hosts: true\n  enhanced-mode: fake-ip\n  default-nameserver: # 建议修改为国内 DNS 服务器\n    - 223.5.5.5\n    - 119.29.29.29\n  nameserver:\n    - https:\u002F\u002Fdoh.pub\u002Fdns-query\n    - tls:\u002F\u002Fdot.pub\n    - tls:\u002F\u002Fdns.alidns.com\n    - https:\u002F\u002Fdns.alidns.com\u002Fdns-query\n  fallback:\n    - https:\u002F\u002Fdns.cloudflare.com\u002Fdns-query\n    - tls:\u002F\u002Fdns.google:853\n    - https:\u002F\u002F1.1.1.1\u002Fdns-query\n    - tls:\u002F\u002F1.1.1.1:853\n    - tls:\u002F\u002F8.8.8.8:853\n  fake-ip-filter:\n    - '+.lan'\n    - '+.cluster.local'\n    - 'time.*.com'\n    - 'time.*.gov'\n    - 'time.*.edu.cn'\n    - 'time.*.apple.com'\n    - 'ntp.*.com'\n    - 'localhost.ptlogin2.qq.com'\n    - '+.ntp.org.cn'\n    - '+.pool.ntp.org'\n    - '+.localhost'\n  fallback-filter:\n    geoip: true\n    geoip-code: CN\n    geosite:\n      - gfw\n    ipcidr:\n      - 224.0.0.0\u002F4\n      - 240.0.0.0\u002F4\n      - 169.254.0.0\u002F16\n      - 0.0.0.0\u002F8\n      - 127.0.0.1\u002F32\n    domain:\n      - '+.google.com'\n      - '+.facebook.com'\n      - '+.youtube.com'\n\nproxies:  # 以下为你的代理节点、分组及代理规则\nproxy-groups:\nrules:\n","yaml",[101,424,421],{"__ignoreMap":114},[16,426,427],{},"A closer look at DNS: there are two groups of DNS servers.",[119,429,430,433],{},[23,431,432],{},"nameserver contains public DNS servers within China.",[23,434,435],{},"fallback contains public DNS servers overseas.",[16,437,438],{},"fallback-filter determines when a domain uses the fallback group’s result.",[119,440,441,444,447,450],{},[23,442,443],{},"geoip-code is an inverse condition: if the IP returned by nameserver does not match geoip-code, use the fallback result.",[23,445,446],{},"geosite is a positive condition: domains matching geosite use fallback.",[23,448,449],{},"ipcidr is a positive condition: if nameserver returns one of these poisoned IPs, use fallback.",[23,451,452],{},"domain is a positive condition: matching domains use fallback directly.",[16,454,455],{},"That completes DNS routing.",[93,457,459],{"id":458},"other-clash-files","Other Clash Files",[16,461,462],{},"Clash needs a few supporting files. Download them before starting it.",[106,464,467],{"className":465,"code":466,"language":158,"meta":114},[156],"cd \u002Fvar\u002Flib\u002Fclash\nwget -q --progress=bar:dot --show-progress -O country.mmdb https:\u002F\u002Fgithub.com\u002FMetaCubeX\u002Fmeta-rules-dat\u002Freleases\u002Fdownload\u002Flatest\u002Fcountry.mmdb\nwget -q --progress=bar:dot --show-progress -O geosite.dat  https:\u002F\u002Fgithub.com\u002FMetaCubeX\u002Fmeta-rules-dat\u002Freleases\u002Fdownload\u002Flatest\u002Fgeosite.dat\nwget -q --progress=bar:dot --show-progress -O GeoIP.dat    https:\u002F\u002Fgithub.com\u002FMetaCubeX\u002Fmeta-rules-dat\u002Freleases\u002Fdownload\u002Flatest\u002Fgeoip.dat\n\nmkdir -p ui\ncd ui\nwget -q --progress=bar:dot --show-progress -O xd.zip https:\u002F\u002Fgithub.com\u002FMetaCubeX\u002Fmetacubexd\u002Farchive\u002Frefs\u002Fheads\u002Fgh-pages.zip\nunzip -oqq xd.zip\nmv metacubexd-gh-pages xd\n",[101,468,466],{"__ignoreMap":114},[16,470,471,472,474],{},"The final ",[101,473,350],{"code":350}," directory should look like this:",[106,476,479],{"className":477,"code":478,"language":158,"meta":114},[156],"\u002Fvar\u002Flib\u002Fclash\n├── clean.sh\n├── config.yaml\n├── country.mmdb\n├── GeoIP.dat\n├── geosite.dat\n├── iptables.sh\n└── ui\n",[101,480,478],{"__ignoreMap":114},[16,482,483],{},"Since Clash runs as the clash user, change ownership:",[106,485,488],{"className":486,"code":487,"language":158,"meta":114},[156],"chown -R clash:clash \u002Fvar\u002Flib\u002Fclash\n",[101,489,487],{"__ignoreMap":114},[16,491,492],{},"Make iptables.sh and clean.sh executable too.",[106,494,497],{"className":495,"code":496,"language":158,"meta":114},[156],"chmod +x iptables.sh\nchmod +x clean.sh\n",[101,498,496],{"__ignoreMap":114},[93,500,502],{"id":501},"start-the-service","Start the Service",[16,504,505,506,508],{},"Once configuration is complete, enable ",[101,507,370],{"code":370}," at boot and start it immediately.",[106,510,513],{"className":511,"code":512,"language":158,"meta":114},[156],"systemctl enable --now clash.service\n",[101,514,512],{"__ignoreMap":114},[16,516,517],{},"To check logs later, use Debian’s built-in tools:",[106,519,522],{"className":520,"code":521,"language":158,"meta":114},[156],"journalctl -efu clash.service\n",[101,523,521],{"__ignoreMap":114},[16,525,526,527,167],{},"Open the web UI: ",[101,528,529],{"code":529},"http:\u002F\u002F192.168.7.2:9090\u002Fui\u002Fxd",[16,531,532],{},"The web UI configuration should be familiar. If everything works, change this machine’s DNS to 127.0.0.1 as mentioned earlier, and point both the gateway and DNS of LAN devices to 192.168.7.2.",[11,534,536],{"id":535},"port-forwarding","Port Forwarding",[16,538,539,540,545],{},"If the main router has port forwarding configured and the target machine uses the side router as its gateway, that forwarding probably no longer works. See ",[541,542,544],"a",{"href":543},"\u002Fen\u002Ffiddling\u002Ffix-port-forward-in-bypass-router","Fixing Port Forwarding with a Side Router"," for the solution.",{"title":114,"searchDepth":547,"depth":547,"links":548},4,[549,551,552,556,561,568],{"id":13,"depth":550,"text":14},3,{"id":56,"depth":550,"text":57},{"id":87,"depth":550,"text":88,"children":553},[554,555],{"id":95,"depth":547,"text":96},{"id":185,"depth":547,"text":186},{"id":198,"depth":550,"text":199,"children":557},[558,559,560],{"id":217,"depth":547,"text":218},{"id":230,"depth":547,"text":231},{"id":286,"depth":547,"text":287},{"id":325,"depth":550,"text":326,"children":562},[563,564,565,566,567],{"id":332,"depth":547,"text":333},{"id":345,"depth":547,"text":231},{"id":409,"depth":547,"text":410},{"id":458,"depth":547,"text":459},{"id":501,"depth":547,"text":502},{"id":535,"depth":550,"text":536},[570],"fiddling","2024-07-13 17:49:00","Using Debian as a side router offers a more stable and flexible alternative without depending on OpenWrt and LuCI. Configuring Debian directly gives you greater control over the system and avoids the limitations and instability of a GUI. Compared with common side-router setups, this approach makes transparent proxying more reliable and offers another option for those who value performance and efficiency.",false,"md","https:\u002F\u002Fblog-img.774352199.xyz\u002FpPRU5x.webp",{"slots":577},{},true,"\u002Ffiddling\u002Fdebian-as-bypass-router",null,{"text":582,"minutes":583,"time":584,"words":585},"12 min read",11.79,707400,2358,{"title":5,"description":572},"Build a Debian side router with AdGuard Home and mihomo for DNS routing and transparent proxying, covering subnets, iptables rules, and systemd services.","Debian gateway setup with mihomo, AdGuard Home and transparent proxying",{"loc":579,"images":590},[591,592,593,594],{"loc":47},{"loc":72},{"loc":81},{"loc":208},"posts\u002Ffiddling\u002Fdebian-as-bypass-router",[597,598,599,600,601],"Debian","Side router","mihomo","AdGuard Home","Transparent proxy","tech","vcF_JcBZrC6HScT4a1f0ZxzfY-JmEcPVczMRJ3XfqPI",[605,623,640,658,675,693,711,727,745,749,765,779,795,811,828,846,861,878,892,908,925,942,958,975,991,1010,1026,1043,1061,1075,1093,1110,1126,1142,1156,1173,1187,1202,1217,1231,1245,1259,1274,1288,1299],{"categories":606,"date":608,"description":609,"image":610,"path":611,"readingTime":612,"recommend":580,"tags":617,"title":622,"type":602},[607],"daily","2024-09-01 22:03:10","Chronic gastritis has been a long, uneven journey: stomach trouble throughout childhood, a surprising reprieve at university, then a return of symptoms after years of late nights and drinking. Frequent nausea and reflux eventually became too much to live with. After repeated examinations and some reflection, I finally began taking the recovery process seriously.","https:\u002F\u002Fblog-img.774352199.xyz\u002F0Hr9l5.webp","\u002Fdaily\u002Fanti-chronic-gastritis",{"text":613,"minutes":614,"time":615,"words":616},"4 min read",3.08,184800,616,[618,619,620,621],"Chronic gastritis","Medical care experiences","Gastroscopy","Health journal","My Journey with Chronic Gastritis",{"categories":624,"date":625,"description":626,"image":627,"path":628,"readingTime":629,"recommend":580,"tags":634,"title":639,"type":602},[607],"2022-04-11 00:13:13","In The Three-Body Problem, Liu Cixin uses an immense historical canvas to explore the relationship between individuals and the collective. His doubts about Western democracy and the majority’s ability to determine its own fate run through the trilogy. Heroes struggle and sacrifice, only to see their work swept aside by history. Beginning with the Cultural Revolution, the story sets up a conflict between exceptional individuals and the ordinary masses, raising uncomfortable questions about humanity and society.","https:\u002F\u002Fblog-img.774352199.xyz\u002FLTzbFP.webp","\u002Fdaily\u002Fpeople-in-three-body",{"text":630,"minutes":631,"time":632,"words":633},"9 min read",8.635,518100,1727,[635,636,637,638],"The Three-Body Problem","Liu Cixin","Science fiction","Reading notes","The “Majority” in The Three-Body Problem",{"categories":641,"date":642,"description":643,"image":644,"path":645,"readingTime":646,"recommend":580,"tags":651,"title":657,"type":602},[607],"2024-01-04 02:06:51","My learning goals for 2024: reach N2 in Japanese, finish SICP and TAPL, build a kernel with full POSIX support, and update the blog theme. A challenging list, but a clear direction for the year.","https:\u002F\u002Fblog-img.774352199.xyz\u002FV3rSQC.webp","\u002Fdaily\u002Fplan2024",{"text":647,"minutes":648,"time":649,"words":650},"1 min read",0.15,9000,30,[652,653,654,655,656],"Annual planning","Learning Japanese","SICP","TAPL","Operating systems","My Learning Plan for 2024",{"categories":659,"date":660,"description":661,"image":662,"path":663,"readingTime":664,"recommend":580,"tags":669,"title":674,"type":602},[607],"2024-09-28 16:26:00","Three years at ByteDance have made time feel strangely accelerated. Amid the changes, I have still managed to hold on to some mental balance. Looking back at the new graduate gazing at distant mountains from the balcony of our Hangzhou office, I can trace how curiosity, workplace challenges, and shifting expectations taught me to find a rhythm of my own.","https:\u002F\u002Fblog-img.774352199.xyz\u002FhnCaht.webp","\u002Fdaily\u002Fwork-for-3-years",{"text":665,"minutes":666,"time":667,"words":668},"10 min read",9.74,584400,1948,[670,671,672,673],"ByteDance","Software engineering careers","Career retrospective","Mental health","Working at ByteDance for Three Years and Staying Somewhat Sane Is Not Entirely Impossible",{"categories":676,"date":677,"description":678,"image":679,"path":680,"readingTime":681,"recommend":580,"tags":686,"title":692,"type":602},[570],"2025-05-28 22:09:00","After moving my blog to Astro, the usual Google Analytics integration no longer fit its performance goals. Adding event-reporting JavaScript directly to the head works, but hurts page performance. I used partytown to move the scripts off the main thread so they would not interfere with loading. With a few adjustments to the example code, Google Analytics finally worked, balancing performance with analytics.","https:\u002F\u002Fblog-img.774352199.xyz\u002FQ0w4RN.webp","\u002Ffiddling\u002Fastro-google-tag-manager",{"text":682,"minutes":683,"time":684,"words":685},"2 min read",1.785,107100,357,[687,688,689,690,691],"Astro","Google Analytics","Google Tag Manager","Partytown","Web analytics","Adding Google Analytics to Astro with Tag Manager",{"categories":694,"date":695,"description":696,"image":697,"path":698,"readingTime":699,"recommend":704,"tags":705,"title":710,"type":602},[570],"2023-04-08 13:16:36","Designing a new programming language is challenging and fun. Setting aside complicated compiler theory and implementation details to focus on where code runs helps clarify how languages are built. Starting from the RISC-VI instruction set, this discussion explores the underlying architecture, layered computer systems, and virtual-machine model, reflecting on the nature of programming languages as well as their implementation.","https:\u002F\u002Fblog-img.774352199.xyz\u002FuO420B.webp","\u002Ffiddling\u002Fchitchat-about-programming-language",{"text":700,"minutes":701,"time":702,"words":703},"15 min read",14.275,856500,2855,2,[706,707,708,709],"Programming language design","Type systems","Compiler design","RISC-V","Some Thoughts on Programming Languages",{"categories":712,"date":713,"description":714,"image":715,"path":716,"readingTime":717,"recommend":547,"tags":722,"title":726,"type":602},[570],"2025-04-18 16:43:12","My girlfriend moved from Beijing to Shanghai for work, and I helped arrange broadband too. Shanghai Telecom’s 500M connection costs more than a 1000M line in Hangzhou, frustratingly. I set out to connect the two cities’ networks: transparent proxying in Shanghai, selected traffic exiting through Hangzhou, and access between both LANs. Hangzhou already had a simple setup with a software router and an AP, configured to route my everyday traffic home and ready for the next networking adventure.","https:\u002F\u002Fblog-img.774352199.xyz\u002FO6cAGh.webp","\u002Ffiddling\u002Fcross-city-network-setup",{"text":718,"minutes":719,"time":720,"words":721},"5 min read",4.865,291900,973,[723,599,724,601,725],"Tailscale","Site-to-site networking","Home networking","Connecting My Shanghai and Hangzhou Networks",{"categories":728,"date":729,"description":730,"image":731,"path":732,"readingTime":733,"recommend":580,"tags":738,"title":744,"type":602},[570],"2021-12-27 00:09:00","The labs are an essential part of learning CSAPP, but setting up Linux can be discouraging. Virtual machines bring installation errors, compatibility problems, and broken networking. WSL (Windows Subsystem for Linux), especially on Windows 10 version 2004 and later, provides a simpler, more direct Linux environment without the complexity and performance bottlenecks of a traditional VM.","https:\u002F\u002Fblog-img.774352199.xyz\u002FvqOC7N.webp","\u002Ffiddling\u002Fcsapplab0",{"text":734,"minutes":735,"time":736,"words":737},"6 min read",5.295,317700,1059,[739,740,741,742,743],"CSAPP","WSL2","Linux","GDB","Lab environment","Setting Up the CSAPP Lab Environment",{"categories":746,"date":571,"description":572,"image":575,"path":579,"readingTime":747,"recommend":580,"tags":748,"title":5,"type":602},[570],{"text":582,"minutes":583,"time":584,"words":585},[597,598,599,600,601],{"categories":750,"date":751,"description":752,"image":753,"path":754,"readingTime":755,"recommend":580,"tags":759,"title":764,"type":602},[570],"2024-08-16 23:53:00","This FakeIP-based transparent proxy design addresses the single point of failure, poor performance, and awkward port forwarding of a traditional side router. Switching to the sing-box proxy core improves forwarding performance and simplifies configuration, with broader protocol support and better optimization than the previous Clash setup. Clash can implement the same design, but sing-box provides a flexible alternative.","https:\u002F\u002Fblog-img.774352199.xyz\u002FS2HHD5.webp","\u002Ffiddling\u002Ffake-ip-based-transparent-proxy",{"text":665,"minutes":756,"time":757,"words":758},9.395,563700,1879,[760,761,601,762,763],"FakeIP","sing-box","Policy-based routing","Traffic routing","Routing Transparent Proxy Traffic with FakeIP",{"categories":766,"date":767,"description":768,"image":769,"path":770,"readingTime":771,"recommend":580,"tags":775,"title":544,"type":602},[570],"2024-08-15 23:50:00","Port forwarding on the main router often stops working when a side router is introduced. Setting the side router as the gateway changes the forwarding path, breaking mappings that previously relied on the main router. A gateway translates addresses and forwards traffic from the internal network to the outside, and each internal device needs one to communicate externally. Understanding this mechanism helps explain how to fix the forwarding problem.","https:\u002F\u002Fblog-img.774352199.xyz\u002FmRqws9.webp","\u002Ffiddling\u002Ffix-port-forward-in-bypass-router",{"text":613,"minutes":772,"time":773,"words":774},3.03,181800,606,[598,776,777,778],"Port forwarding","NAT","Network troubleshooting",{"categories":780,"date":781,"description":782,"image":783,"path":784,"readingTime":785,"recommend":580,"tags":790,"title":794,"type":602},[570],"2023-02-02 23:24:55","Inspiration struck during Chinese New Year: an article read on the train about running Go on bare metal sparked an interest in low-level system interfaces. Its successful implementation suggested exciting possibilities for combining a high-level language with an OS. Further research revealed earlier work on the idea, and that growing enthusiasm became a project full of anticipation that ultimately did not work out.","https:\u002F\u002Fblog-img.774352199.xyz\u002FxB1Ni5.webp","\u002Ffiddling\u002Fgo-os",{"text":786,"minutes":787,"time":788,"words":789},"8 min read",7.29,437400,1458,[791,709,656,792,793],"Go","Bare-metal programming","Runtime","A Project That Failed: Seven Not-So-Happy Days over Chinese New Year",{"categories":796,"date":797,"description":798,"image":799,"path":800,"readingTime":801,"recommend":580,"tags":806,"title":810,"type":602},[570],"2022-08-15 01:05:01","While refactoring a system, converting entities between layers made deep copying surprisingly awkward. A product VO in the view layer, an entity in the domain layer, and a PO in the persistence layer can look nearly identical, yet small type differences complicate direct conversion. I used reflection to build a general conversion method, reducing repetitive assembler methods and making the code more maintainable and flexible.","https:\u002F\u002Fblog-img.774352199.xyz\u002FBlhm0I.webp","\u002Ffiddling\u002Fgolang-deepcopy-between-different-type",{"text":802,"minutes":803,"time":804,"words":805},"3 min read",2.855,171300,571,[791,807,808,809],"Reflection","Deep copy","Struct conversion","Deep Copying Between Different Struct Types in Go",{"categories":812,"date":813,"description":814,"image":815,"path":816,"readingTime":817,"recommend":580,"tags":821,"title":827,"type":602},[570],"2025-03-31 23:51:00","Periodically syncing heart-rate data from Apple Health to a server and visualizing it in Grafana provides an intuitive way to monitor it. Health Auto Export sends the data to an HTTP endpoint through its REST API automation, the server stores it in InfluxDB, and Grafana presents a clear dashboard for tracking and analyzing personal heart-rate changes.","https:\u002F\u002Fblog-img.774352199.xyz\u002FF4qD2T.webp","\u002Ffiddling\u002Fheart-rate-to-grafana",{"text":802,"minutes":818,"time":819,"words":820},2.45,147000,490,[822,823,824,825,826],"Apple Watch","Health Auto Export","InfluxDB","Grafana","Heart rate monitoring","My Heart Beats for U: Visualizing Heart Rate in Grafana",{"categories":829,"date":830,"description":831,"image":832,"path":833,"readingTime":834,"recommend":838,"tags":839,"title":845,"type":602},[570],"2025-06-10 20:18:00","macOS and iPadOS 26 introduce the Liquid Glass design language, refreshing icons and windows with a more modern look. Windowed apps on iPad are a step toward making it a productivity device. The transparent Control Center and the integration of Launchpad have been controversial, however, and the experience still needs work. Despite its shortcomings, this update lays groundwork for a promising future.","https:\u002F\u002Fblog-img.774352199.xyz\u002FTPSaLE.webp","\u002Ffiddling\u002Fmacos-26-trial",{"text":613,"minutes":835,"time":836,"words":837},3.305,198300,661,5,[840,841,842,843,844],"macOS 26","iPadOS 26","Liquid Glass","Apple Intelligence","Operating system impressions","Trying Out macOS 26 and iPadOS 26",{"categories":847,"date":848,"description":849,"image":850,"path":851,"readingTime":852,"recommend":580,"tags":856,"title":860,"type":602},[570],"2026-06-11 10:00:00","Another WWDC brings new Apple Intelligence features in macOS 27. The workarounds from macOS 26 no longer get through, so the battle of wits with Apple continues.","https:\u002F\u002Fblog-img.774352199.xyz\u002FfOFucm.webp","\u002Ffiddling\u002Fmacos-27-apple-intelligence-chatgpt",{"text":734,"minutes":853,"time":854,"words":855},5.1,306000,1020,[857,843,858,859],"macOS 27","ChatGPT","Mainland China Mac","Getting Apple Intelligence Working on a China-Market Mac: Region Changes and Extracting ChatGPT",{"categories":862,"date":863,"description":864,"image":865,"path":866,"readingTime":867,"recommend":580,"tags":871,"title":877,"type":602},[570],"2025-07-20 23:32:00","MoonTV is a new video aggregation platform built with Next.js and React to make following shows convenient. It began as an attempt to improve LibreTV and has attracted substantial attention and usage over several months of development. Cursor made development efficient, although multi-platform support and complex data dependencies posed challenges. As its user base grows, MoonTV continues improving in response to feedback.","https:\u002F\u002Fblog-img.774352199.xyz\u002FnIeONi.webp","\u002Ffiddling\u002Fmoontv-vibe-coding",{"text":734,"minutes":868,"time":869,"words":870},5.76,345600,1152,[872,873,874,875,876],"MoonTV","LunaTV","Vibe Coding","Cursor","AI-assisted development","MoonTV: An Experiment in Vibe Coding",{"categories":879,"date":880,"description":881,"image":882,"path":883,"readingTime":884,"recommend":580,"tags":888,"title":891,"type":602},[570],"2024-10-07 16:51:00","BGP-based routing for Chinese and overseas IPs makes transparent proxying more efficient and accurate. Marking overseas destinations with FakeIP lets the main router route traffic more intelligently for smoother connectivity. The sing-box DNS configuration is also refined to handle queries more flexibly and efficiently, improving the overall network experience.","https:\u002F\u002Fblog-img.774352199.xyz\u002FMOmM1s.webp","\u002Ffiddling\u002Fmore-accurate-chnroute",{"text":613,"minutes":885,"time":886,"words":887},3.805,228300,761,[889,890,762,763],"BGP","IP address database","More Accurate Routing for Chinese and Overseas IPs with BGP",{"categories":893,"date":894,"description":895,"image":896,"path":897,"readingTime":898,"recommend":580,"tags":902,"title":907,"type":602},[570],"2025-12-14 14:31:00","A friend’s comment got me interested in simulation games. After buying Microsoft Flight Simulator, I discovered streamed maps and models, another account login, oddly hidden tutorials, and awkward keyboard controls. A flight stick and some tinkering with Pico VR finally rounded out the experience.","https:\u002F\u002Fblog-img.774352199.xyz\u002FlfhEuE.webp","\u002Ffiddling\u002Fmsfs2024-joystick-and-pico",{"text":718,"minutes":899,"time":900,"words":901},4.68,280800,936,[903,904,905,906],"Microsoft Flight Simulator 2024","Thrustmaster TCA","PICO VR","Flight simulation","Adventures with Microsoft Flight Simulator 2024",{"categories":909,"date":910,"description":911,"image":912,"path":913,"readingTime":914,"recommend":580,"tags":918,"title":924,"type":602},[570],"2025-06-05 23:26:00","My frequent phone changes took me from OnePlus to iPhone, and from enjoying tinkering to relying on an ecosystem. At my girlfriend’s suggestion, I recently bought an OPPO Find X8 Ultra to improve my photos. Migrating apps out of Apple’s ecosystem reminded me how uneven Android’s app selection remains and how difficult finding replacements can be. A month of migration has been an exercise in friction and adaptation between platforms.","https:\u002F\u002Fblog-img.774352199.xyz\u002F19NIhZ.webp","\u002Ffiddling\u002Fone-month-using-android",{"text":786,"minutes":915,"time":916,"words":917},7.61,456600,1522,[919,920,921,922,923],"Android","OPPO","iOS","Smartphone impressions","Ecosystem migration","One Month After Switching to Android",{"categories":926,"date":927,"description":928,"image":929,"path":930,"readingTime":931,"recommend":580,"tags":935,"title":941,"type":602},[570],"2026-05-11 22:43:00","I found a trip-planning tool on GitHub Trending and wanted to host my own instance. Since I was getting a new VPS anyway, I might as well install a little extra. Well, quite a lot extra.","https:\u002F\u002Fblog-img.774352199.xyz\u002FBBdDWW.webp","\u002Ffiddling\u002Fone-trek-twenty-stacks",{"text":734,"minutes":932,"time":933,"words":934},5.735,344100,1147,[936,937,938,939,940],"TREK","Docker Compose","Dockge","VPS","Self-hosting","One TREK, Twenty Stacks",{"categories":943,"date":944,"description":945,"image":946,"path":947,"readingTime":948,"recommend":580,"tags":953,"title":957,"type":602},[570],"2025-01-16 23:09:00","OPNsense is an open-source firewall and router with an attractive interface and a comprehensive feature set. After trying several routing setups, I came to appreciate its potential for transparent proxying and traffic routing. Combining it with BGP-based routing offers better security and stability, while its automatically updated IP lists make network management more convenient.","https:\u002F\u002Fblog-img.774352199.xyz\u002FxA8C1E.webp","\u002Ffiddling\u002Fopnsense-transparent-proxy",{"text":949,"minutes":950,"time":951,"words":952},"7 min read",6.47,388200,1294,[954,955,599,956,601,763],"OPNsense","FreeBSD","tun2socks","Transparent Proxying and Traffic Routing with OPNsense",{"categories":959,"date":960,"description":961,"image":962,"path":963,"readingTime":964,"recommend":550,"tags":968,"title":974,"type":602},[570],"2025-03-15 20:35:00","Distinguishing user-defined type names from ordinary variables is a challenge during parsing. A statement such as `a*b;` can be either an arithmetic expression or a declaration. Grammar rules, especially those involving type specifiers, can misidentify variables as types, affecting correctness and readability. The prevalence of declarations without initializers makes this ambiguity especially common.","https:\u002F\u002Fblog-img.774352199.xyz\u002F2VKHK9.webp","\u002Ffiddling\u002Fparser-type-variable-ambiguity",{"text":786,"minutes":965,"time":966,"words":967},7.475,448500,1495,[969,970,971,972,973],"Parsing","GLR","Symbol table","Scope","Disambiguation","Resolving Type Name and Variable Name Ambiguity in Parsing",{"categories":976,"date":977,"description":978,"image":979,"path":980,"readingTime":981,"recommend":580,"tags":985,"title":990,"type":602},[570],"2023-05-24 17:51:09","To install the RISC-V toolchain, first obtain the riscv-gnu-toolchain source. Using `--depth=1` when cloning reduces the download size. Check the README’s Prerequisites section and install the required dependencies. On Debian, a simple package installation command prepares the environment for building the toolchain.","https:\u002F\u002Fblog-img.774352199.xyz\u002FrWNOKx.webp","\u002Ffiddling\u002Fspike-install",{"text":682,"minutes":982,"time":983,"words":984},1.92,115200,384,[709,986,987,988,989],"Spike","riscv-pk","Cross-compilation","Toolchain","Installing the RISC-V Toolchain and Emulator",{"categories":992,"date":993,"description":994,"image":995,"path":996,"readingTime":997,"recommend":1001,"tags":1002,"title":1009,"type":602},[570],"2026-09-09 23:59:00","This counts as NTR too, surely.","https:\u002F\u002Fblog-img.774352199.xyz\u002FNDPUwc.webp","\u002Ffiddling\u002Fsteamdeck-switch-60fps",{"text":786,"minutes":998,"time":999,"words":1000},7.345,440700,1469,7,[1003,1004,1005,1006,1007,1008],"Steam Deck","Nintendo Switch","EmuDeck","Eden","Lossless Scaling","Frame generation","A Second Life for the Steam Deck: Switch Emulation and Frame Generation at 60 FPS",{"categories":1011,"date":1012,"description":1013,"image":1014,"path":1015,"readingTime":1016,"recommend":580,"tags":1020,"title":1025,"type":602},[570],"2024-06-23 15:31:32","The GFW does more than monitor an exit gateway: it inspects international traffic through passive taps, copying inbound and outbound IP packets to a cluster for analysis and filtering. Understanding where and how this happens matters when studying censorship circumvention. Examining the GFW’s network topology helps explain its blocking mechanisms and how to work around them.","https:\u002F\u002Fblog-img.774352199.xyz\u002FsOpJuL.webp","\u002Ffiddling\u002Ftech-about-gfw",{"text":582,"minutes":1017,"time":1018,"words":1019},11.885,713100,2377,[1021,1022,1023,1024],"GFW","DNS poisoning","TCP","Internet censorship","How the Great Firewall Works",{"categories":1027,"date":1028,"description":1029,"image":1030,"path":1031,"readingTime":1032,"recommend":580,"tags":1036,"title":1042,"type":602},[570],"2022-04-16 00:01:28","In Java, using `this` can prevent the compiler from optimizing constants. Although `ab1` and `ab2` in this example appear to refer to the same static final variable `s`, comparing them produces different results. `ab1` concatenates a direct reference to the static variable, while `ab2` accesses it through `this`, preventing the same constant propagation optimization. This illustrates how a small syntactic difference can change compilation behavior.","https:\u002F\u002Fblog-img.774352199.xyz\u002FgKtkYe.webp","\u002Ffiddling\u002Fthis-in-javac-string-concat",{"text":802,"minutes":1033,"time":1034,"words":1035},2.305,138300,461,[1037,1038,1039,1040,1041],"Java","javac","String concatenation","Constant propagation","Bytecode","How Java’s this Keyword Can Prevent Compile-Time Constant Propagation",{"categories":1044,"date":1045,"description":1046,"image":1047,"path":1048,"readingTime":1049,"recommend":580,"tags":1054,"title":1060,"type":602},[570],"2025-01-29 21:58:00","A microblog lets you share short thoughts whenever they occur, without the overhead of publishing a full static-blog post. This implementation uses Cloudflare Workers for the backend and KV for storage and management. A Vue component embedded in VitePress displays the updates, adding a lively, interactive element to the blog.","https:\u002F\u002Fblog-img.774352199.xyz\u002FhZX6hr.webp","\u002Ffiddling\u002Fvitepress-memos-component",{"text":1050,"minutes":1051,"time":1052,"words":1053},"19 min read",18.96,1137600,3792,[1055,1056,1057,1058,1059],"VitePress","Vue","Cloudflare Workers","Cloudflare KV","Microblogging","Adding a Microblog to VitePress",{"categories":1062,"date":1063,"description":1064,"image":1065,"path":1066,"readingTime":1067,"recommend":580,"tags":1071,"title":1074,"type":602},[570],"2025-03-15 16:24:00","A Telegram notification on an ordinary afternoon introduced a tempting VPS deal: a direct China Telecom CN2 route and 2.5G bandwidth. The plan includes IPv6, useful for unlocking streaming services, but not every connection needs to go through WARP. My previous script was convenient, yet its effects on speed and traffic routing called for a more flexible solution.","https:\u002F\u002Fblog-img.774352199.xyz\u002FMcjrrF.webp","\u002Ffiddling\u002Fvps-warp-ipv6",{"text":802,"minutes":1068,"time":1069,"words":1070},2.34,140400,468,[1072,1073,939,762,763],"Cloudflare WARP","IPv6","Routing Selected VPS Traffic Through WARP over IPv6",{"categories":1076,"date":1077,"description":1078,"image":1079,"path":1080,"readingTime":1081,"recommend":1085,"tags":1086,"title":1092,"type":602},[570],"2026-08-17 23:59:21","The more I tinker, the more I want to tinker. Still going strong in my old age, still going strong!","https:\u002F\u002Fblog-img.774352199.xyz\u002FqfxB0h.webp","\u002Ffiddling\u002Fxiaomi17-root-and-hide-root",{"text":718,"minutes":1082,"time":1083,"words":1084},4.545,272700,909,6,[1087,1088,1089,1090,1091],"Xiaomi 17","Bootloader","Android Root","Firmware flashing","Root hiding","Making the Xiaomi 17 My Daily Driver: Unlocking, Flashing, Rooting, and Hiding Root",{"categories":1094,"date":1096,"description":1097,"image":1098,"path":1099,"readingTime":1100,"recommend":580,"tags":1104,"title":1109,"type":602},[1095],"notes","2022-01-20 22:29:00","Lab 1 asks us to implement a MapReduce system with two core components: a master and workers. This requires a good command of Go RPC and concurrent programming, along with a thorough understanding of the MapReduce workflow. I built two versions, starting with mutex locks and then moving to a more elegant channel-based implementation without explicit locks, whose design is simpler and clearer. The key to understanding the lab is to read the relevant documentation carefully, especially the flowcharts and explanations.","https:\u002F\u002Fblog-img.774352199.xyz\u002FibVwPJ.webp","\u002Fnotes\u002F65840\u002Fmapreducelab",{"text":786,"minutes":1101,"time":1102,"words":1103},7.21,432600,1442,[1105,1106,791,1107,1108],"MIT 6.5840","MapReduce","RPC","Concurrent programming","6.5840 Lab 1: MapReduce",{"categories":1111,"date":1112,"description":1113,"image":1114,"path":1115,"readingTime":1116,"recommend":580,"tags":1120,"title":1125,"type":602},[1095],"2022-01-16 17:32:00","MapReduce is an efficient parallel computing model designed to simplify processing large datasets. By defining the two key functions, Map and Reduce, users can break complex tasks into simple operations. The framework automatically handles data distribution and task scheduling, allowing developers to focus on the algorithm rather than low-level details. Its widespread use in distributed systems demonstrates its flexibility and practical value.","https:\u002F\u002Fblog-img.774352199.xyz\u002FApIDdC.webp","\u002Fnotes\u002F65840\u002Fmapreducepaper",{"text":718,"minutes":1117,"time":1118,"words":1119},4.12,247200,824,[1106,1121,1122,1123,1124],"Distributed systems","Paper notes","Parallel computing","Fault tolerance","Reading the MapReduce Paper",{"categories":1127,"date":1128,"description":1129,"image":1130,"path":1131,"readingTime":1132,"recommend":580,"tags":1137,"title":1141,"type":602},[1095],"2022-12-16 02:06:10","Lab 2A focuses on implementing Raft leader election and heartbeats so that elections and term changes work correctly even under extreme conditions. The lab has four stages and lays the foundation for the distributed key-value store that follows. A design without explicit locks simplifies the Raft struct. The lab instructions provide the necessary background, but compared with the previous lab, this one relies on almost no reference material and places greater emphasis on implementing the system independently.","https:\u002F\u002Fblog-img.774352199.xyz\u002Fc11Uk4.webp","\u002Fnotes\u002F65840\u002Fraftlab2a",{"text":1133,"minutes":1134,"time":1135,"words":1136},"13 min read",12.235,734100,2447,[1105,1138,791,1139,1140],"Raft","Leader election","Distributed consensus","6.5840 Lab 2A: Leader Election",{"categories":1143,"date":1144,"description":1145,"image":1146,"path":1147,"readingTime":1148,"recommend":580,"tags":1153,"title":1155,"type":602},[1095],"2022-12-03 21:40:09","Raft is a consensus algorithm designed to improve the efficiency of log replication. It is particularly suited to clusters of machines, allowing them to keep providing service even when some machines fail. It uses the replicated state machine model: logs record the order of commands so that every machine in the cluster can reach the same state. In Search of an Understandable Consensus Algorithm explores Raft’s design and compares it with Paxos, highlighting its understandability and providing a foundation for building reliable large-scale software systems. These reading notes aim to help explain the paper’s core concepts and their applications.","https:\u002F\u002Fblog-img.774352199.xyz\u002F7mmvIZ.webp","\u002Fnotes\u002F65840\u002Freftextendedpaper",{"text":1149,"minutes":1150,"time":1151,"words":1152},"16 min read",15.98,958800,3196,[1138,1140,1154,1122],"Log replication","Reading the Raft Paper",{"categories":1157,"date":1159,"description":1160,"image":1161,"path":1162,"readingTime":1163,"recommend":1167,"tags":1168,"title":1172,"type":602},[1158],"projects","2021-11-27 14:43:00","MYDB is a personal project exploring and implementing the fundamentals of databases, built in my spare time over a little more than half a month. I picked up some basic knowledge in my university database systems course, though during my internship I mostly used the classes as an excuse to slack off. My candid answers in an interview did not cause too much trouble, but they did make me reconsider what I knew about databases and decide to learn through hands-on practice. That was how this project began.","https:\u002F\u002Fblog-img.774352199.xyz\u002Fxfci2J.webp","\u002Fprojects\u002Fmydb\u002Fmydb0",{"text":718,"minutes":1164,"time":1165,"words":1166},4.15,249000,830,1,[1169,1037,1170,1171],"MYDB","Database implementation","Database architecture","MYDB 0. Project Structure and a Few Things I Had to Say",{"categories":1174,"date":1175,"description":1176,"image":1177,"path":1178,"readingTime":1179,"recommend":580,"tags":1183,"title":1186,"type":602},[1158],"2021-11-28 16:10:00","MYDB manages transactions through an XID file. Each transaction has a unique XID, incrementing from 1; XID 0 denotes a super transaction whose state is always committed. TransactionManager maintains this file and records three states: active, committed, and aborted. This mechanism supports accurate transaction state queries and management, providing a foundation for system stability and reliability.","https:\u002F\u002Fblog-img.774352199.xyz\u002FH4zZAK.webp","\u002Fprojects\u002Fmydb\u002Fmydb1",{"text":718,"minutes":1180,"time":1181,"words":1182},4.755,285300,951,[1169,1037,1184,1185],"Transaction management","XID","MYDB 1. Starting with the Transaction Manager",{"categories":1188,"date":1189,"description":1190,"image":1191,"path":1192,"readingTime":1193,"recommend":580,"tags":1197,"title":1201,"type":602},[1158],"2021-12-25 18:26:00","MYDB uses a client\u002Fserver architecture similar to MySQL, allowing multiple clients to connect to a server over sockets, execute SQL queries, and receive results. Communication uses a special binary format, though plain text would also be an option for a simpler implementation. The basic transport structure supports effective communication and processing between client and server.","https:\u002F\u002Fblog-img.774352199.xyz\u002FPAHrUZ.webp","\u002Fprojects\u002Fmydb\u002Fmydb10",{"text":718,"minutes":1194,"time":1195,"words":1196},4.305,258300,861,[1169,1037,1198,1199,1200],"Socket","Client-server architecture","Communication protocol","MYDB 10. Implementing the Server, Client, and Wire Protocol",{"categories":1203,"date":1204,"description":1205,"image":1206,"path":1207,"readingTime":1208,"recommend":580,"tags":1212,"title":1216,"type":602},[1158],"2021-11-30 23:18:00","The Data Manager (DM) bridges higher-level modules and the filesystem, handling paging and caching while ensuring data safety and recovery. Its cache uses reference counting rather than traditional LRU, aiming for a reusable, efficient foundation for subsequent data operations.","https:\u002F\u002Fblog-img.774352199.xyz\u002FWdIGoG.webp","\u002Fprojects\u002Fmydb\u002Fmydb2",{"text":734,"minutes":1209,"time":1210,"words":1211},5.725,343500,1145,[1169,1037,1213,1214,1215],"Reference counting","Cache design","Shared memory","MYDB 2. A Reference-Counted Cache Framework and Shared Byte Arrays",{"categories":1218,"date":1219,"description":1220,"image":1221,"path":1222,"readingTime":1223,"recommend":580,"tags":1227,"title":1230,"type":602},[1158],"2021-12-05 15:28:00","DM abstracts the filesystem into pages and uses them as the unit of reading, writing, and caching. The default page size is 8K, with larger pages available to improve write performance under heavy loads. With the general-purpose cache framework already in place, we now define the page structure and implement efficient page caching.","https:\u002F\u002Fblog-img.774352199.xyz\u002FjlFC4E.webp","\u002Fprojects\u002Fmydb\u002Fmydb3",{"text":718,"minutes":1224,"time":1225,"words":1226},4.7,282000,940,[1169,1037,1228,1229],"Data pages","Cache management","MYDB 3. Caching and Managing Data Pages",{"categories":1232,"date":1233,"description":1234,"image":1235,"path":1236,"readingTime":1237,"recommend":580,"tags":1241,"title":1244,"type":602},[1158],"2021-12-08 22:55:00","Log files are essential to MYDB’s design, allowing data to be recovered after a crash. DM logs every operation on underlying data, forming a continuous sequence of records. Stored in a specific binary format with checksums and individual operation records, these logs let the database accurately reconstruct its data on restart and maintain consistency and integrity.","https:\u002F\u002Fblog-img.774352199.xyz\u002FTRcbsj.webp","\u002Fprojects\u002Fmydb\u002Fmydb4",{"text":786,"minutes":1238,"time":1239,"words":1240},7.885,473100,1577,[1169,1037,1242,1243],"Database logging","Crash recovery","MYDB 4. Log Files and Recovery Strategies",{"categories":1246,"date":1247,"description":1248,"image":1249,"path":1250,"readingTime":1251,"recommend":580,"tags":1255,"title":1258,"type":602},[1158],"2021-12-11 15:16:00","The page index is an important part of DM, optimizing insertions by caching the free space available on each page. It lets higher-level modules quickly locate a suitable page without a lengthy search, making data operations more efficient. Its implementation works closely with the DataItem abstraction to support efficient database operation.","https:\u002F\u002Fblog-img.774352199.xyz\u002F22PSG1.webp","\u002Fprojects\u002Fmydb\u002Fmydb5",{"text":949,"minutes":1252,"time":1253,"words":1254},6.37,382200,1274,[1169,1037,1256,1257],"Page index","Data management","MYDB 5. The Page Index and the Data Manager",{"categories":1260,"date":1261,"description":1262,"image":1263,"path":1264,"readingTime":1265,"recommend":580,"tags":1269,"title":1273,"type":602},[1158],"2021-12-18 14:58:00","VM uses two-phase locking to ensure serializable schedules and introduces multiversion concurrency control (MVCC) to eliminate blocking between reads and writes. This chapter also defines conflicts between database operations, focusing on the interaction between updates and reads as a foundation for understanding transaction isolation levels.","https:\u002F\u002Fblog-img.774352199.xyz\u002F8YzotA.webp","\u002Fprojects\u002Fmydb\u002Fmydb6",{"text":630,"minutes":1266,"time":1267,"words":1268},8.64,518400,1728,[1169,1037,1270,1271,1272],"MVCC","Transaction isolation","Two-phase locking","MYDB 6. Record Versions and Transaction Isolation",{"categories":1275,"date":1276,"description":1277,"image":1278,"path":1279,"readingTime":1280,"recommend":580,"tags":1284,"title":1287,"type":602},[1158],"2021-12-23 21:20:00","VM must handle version skipping introduced by MVCC as well as deadlocks. By simply marking a transaction, MYDB can cancel or roll it back and keep data from aborted transactions from affecting others. This design makes concurrent transaction handling more efficient and reliable, avoids the deadlock risks common with traditional 2PL, and improves overall stability and performance.","https:\u002F\u002Fblog-img.774352199.xyz\u002FBF3yDW.webp","\u002Fprojects\u002Fmydb\u002Fmydb7",{"text":786,"minutes":1281,"time":1282,"words":1283},7.265,435900,1453,[1169,1037,1285,1286],"Deadlock detection","Version management","MYDB 7. Deadlock Detection and the Version Manager",{"categories":1289,"date":1290,"description":1291,"image":1292,"path":1293,"readingTime":1294,"recommend":580,"tags":1295,"title":1298,"type":602},[1158],"2021-12-24 21:01:00","MYDB implements a clustered index using a B+ tree. IM interacts directly with the Data Manager (DM), bypassing the Version Manager (VM), so index data is written directly to the database file. This chapter details the binary-tree index structure and its basic node fields, including the leaf flag, key count, and sibling identifier, establishing the framework for indexed lookups.","https:\u002F\u002Fblog-img.774352199.xyz\u002Ff92X4o.webp","\u002Fprojects\u002Fmydb\u002Fmydb8",{"text":718,"minutes":1164,"time":1165,"words":1166},[1169,1037,1296,1297],"B+ tree","Database indexing","MYDB 8. Index Management",{"categories":1300,"date":1301,"description":1302,"image":1303,"path":1304,"readingTime":1305,"recommend":580,"tags":1309,"title":1312,"type":602},[1158],"2021-12-25 15:44:00","The Table Manager (TBM) manages field and table structures. Parser turns SQL-like statements into structured representations, wrapping their information in the corresponding classes to simplify subsequent operations. This chapter also covers MYDB’s SQL syntax as a foundation for understanding the management process.","https:\u002F\u002Fblog-img.774352199.xyz\u002FzOMyv5.webp","\u002Fprojects\u002Fmydb\u002Fmydb9",{"text":734,"minutes":1306,"time":1307,"words":1308},5.035,302100,1007,[1169,1037,1310,1311],"SQL parsing","Table management","MYDB 9. Field and Table Management",1789914050046]