Saturday, 20 June 2026

How to Get a Second Chance at IP-Based Daily Limits

Some websites limit an IP address's daily quota for downloading or watching. To work around that, you may switch between a mobile network and home WiFi for different public IP addresses. You may also toggle Mobile Airplane mode on/off or reboot your home WiFi router after waiting for a longer period. You can also use a VPN, but VPN IP addresses are commonly shared by many users, so they may already be blocked, flagged, or have reached the same limit. A VPN may also be slower because traffic has to pass through the VPN server.

But you may have missed a hidden gem: your machine may already have a second rate-limit path for free, through a combination of a public IPv4 address and a public IPv6 address. By default, the browser or operating system may choose one of them behind the scenes based on availability, speed, routing, or other connection conditions. 

At first, this may feel impossible because your public IP address sounds like something fully decided by the ISP, regardless of whether your local connection uses IPv4 or IPv6. That is partly true: you do not invent your own public IPv4 or IPv6 address. 
But on a dual-stack connection, the selected IPv4 or IPv6 path can determine which public IP identity the website sees. The small control you may have is choosing which existing path the browser uses.

Assuming you currently have IPv6, you may try to make Firefox use the website’s IPv4 A record, so the website sees your public IPv4 address instead of your IPv6 address:
 
about:config → network.dns.disableIPv6 
→ click false to change it to true →  Ctrl + F5 to refresh the page.

*Change it back afterward, since it may affect normal website usage. If the result does not change immediately, restart the browser to clear old DNS or connection state.

Firefox is not telling the router to “force IPv4.” When Firefox uses a website’s A record, it has selected an IPv4 destination. The ISP may still tunnel or translate that traffic internally, but from the website’s point of view, the connection arrives as IPv4.

IPv6 cannot directly terminate on a publicly IPv4-only website under today’s standard internet protocols because IPv4 and IPv6 are separate protocol families with different packet formats, addressing, and routing systems. A hostname with only an A record is publicly IPv4-only: IPv6 clients have no IPv6 address to connect to for that hostname. 

If an AAAA record is later added for an IPv6-capable CDN, reverse proxy, or load balancer, the public service becomes IPv6-capable, even if the origin server behind it remains IPv4-only. In that setup, the client connects to the front end over IPv6, and the front end separately connects to the origin over IPv4.

A mixed IPv6-source-to-IPv4-destination packet could theoretically exist, but it would be a new hybrid protocol that normal routers, firewalls, operating systems, and servers do not understand. In practice, crossing between IPv6 and IPv4 requires network-layer translation, such as NAT64 or 464XLAT, or tunneling/encapsulation, such as DS-Lite.

Normal Firefox:
ask DNS for A + AAAA records of the target website
IPv6 address exists and the browser/OS prefers the IPv6 connection
choose the website's IPv6 address: 2001:db8::10
connect from the client's IPv6 address: 2001:db8:1234:5678::abcd → rate limit hit

Firefox with network.dns.disableIPv6 = true:

do not use the IPv6 result
use the website's IPv4 A record: 203.0.113.10
connect from the client's public IPv4 address: 203.0.113.38 → fresh rate limit

A and AAAA commands to check the target website and what IP the target website sees from your machine:

echo "== DNS records of target =="
dig +short A example.com
dig +short AAAA example.com

echo "== Kernel route/source choice =="
ip -4 route get 203.0.113.10
ip -6 route get 2001:db8::10

echo "== Public IP seen by external service =="
curl -4 https://ifconfig.me
curl -6 https://ifconfig.me

Output:

== DNS records of target ==
203.0.113.10 # website IPv4 address
2001:db8::10 # website IPv6 address

== Kernel route/source choice ==
203.0.113.10 via 192.168.0.1 dev wlo1 src 192.168.0.15
# destination = website IPv4, source = local LAN IPv4

2001:db8::10 via fe80::1 dev wlo1 src 2001:db8:1234:5678::abcd
# destination = website IPv6, source = client IPv6

== Public IP seen by external service ==
203.0.113.38 # public IPv4 seen by website
2001:db8:1234:5678::abcd # public IPv6 seen by website

*Although the curl test uses a different website from your target website, your public source IP usually stays the same for a given IP version on a direct connection: normal routing forwards packets toward the destination without rewriting the source address at each hop. The source IP changes mainly when something on your side or in the access path remaps it, such as NAT, CGNAT, a VPN, or a forward proxy. IPv6 privacy or temporary addresses can also rotate over time even without NAT or VPN. Separately, what the target website's internal server logs show may differ if the site is behind a CDN, load balancer, or reverse proxy: the public-facing edge may see the real client IP, while the origin server may only see the proxy's IP unless it restores the visitor IP from trusted forwarded headers such as X-Forwarded-For, X-Real-IP, or CF-Connecting-IP.

To check whether the target website may be behind a CDN or proxy, resolve the hostname and check who owns the returned IP address. A Cloudflare-owned IP usually means the site is Cloudflare-proxied, so origin logs may differ from what curl shows.

$ dig A example.com +short
203.0.113.10
203.0.113.11

$ whois 203.0.113.10 | grep -i cloud
NetName:        CLOUDFLARENET
...
RAbuseEmail:  abuse@cloudflare.com
RTechEmail:  rir@cloudflare.com
RNOCEmail:  noc@cloudflare.com
$

This check is only a clue, not a perfect proof. If the DNS result belongs to Cloudflare, that hostname is probably routed through Cloudflare's proxy/CDN path. If the DNS result does not belong to Cloudflare, the site may be direct-to-origin, or it may sit behind a different CDN, load balancer, or reverse proxy provider. You can also check HTTP response headers with curl -I https://example.com; headers such as server: cloudflare, cf-ray, or cf-cache-status are strong signs that the request actually passed through Cloudflare's edge.

For Cloudflare-proxied sites, the origin may see a Cloudflare/proxy IP unless it restores the real visitor IP from trusted headers. Rate-limiting by proxy IP is usually a weak setup because many visitors may share the same CDN/proxy address. A properly configured site should rate-limit by the real visitor IP from Cloudflare’s single-value CF-Connecting-IP or a correctly parsed X-Forwarded-For chain, but only when the request arrives through the expected trusted proxy path. In that case, the public IPv4/IPv6 shown by curl -4/-6 https://ifconfig.me is more relevant to the target site’s rate limit.


By combining mobile-network and home-WiFi IPs with both IPv4 and IPv6 paths, the rate limit is not just a second chance; in the best case, it can increase by up to 4x. If toggling airplane mode or rebooting the router successfully gives you a new public IP, the available quota may double again. Despite the public IPv4 address being shared by many users, Windows and browsers such as Chrome normally prefer IPv6 when it is working properly. Therefore, when you deliberately switch to IPv4, you may become one of the few users consuming the IPv4-based quota, making it less likely to have already been reached. Nevertheless, if the website supports only IPv4 or only IPv6, then the IPv4/IPv6 switching part of this trick will not work.

 

However, Firefox does not provide a matching network.dns.disableIPv4 setting for forcing IPv6-only browsing. The options are less direct:

1. Test with an IPv6-capable website and confirm the result with an IP-checking page.
2. Make sure network.dns.disableIPv6 is set to false.
3. Turn off Firefox DNS over HTTPS if it causes Firefox to behave differently from the system resolver.
4. Prefer IPv6 at the system level through /etc/gai.conf, although this affects more than Firefox and is not a Firefox-only switch.
5. For strict IPv6-only testing, use a separate network namespace, VM, VPN, or firewall rule to make IPv4 unavailable, then launch Firefox inside that environment.

Some websites may rate-limit by account session, cookie, or browser fingerprint, so changing from IPv6 to IPv4 may also need to be combined with a different account.

Friday, 17 April 2026

为什么修改 resolv.conf 无效

 

前提条件说明 本文讨论基于以下前提:
  • 你的系统使用了 systemd-resolved
  • 网络由 NetworkManager 或 Netplan 接管
  • /etc/resolv.conf 为动态生成的符号链接
  • 注意:不同发行版默认配置可能略有差异(如 nsswitch.conf 或 NetworkManager 设置)。
在默认使用 systemd-resolved + NetworkManager / Netplan 的现代 Linux 发行版中,/etc/resolv.conf 往往不是配置源,而是一个动态生成的解析接口。手动修改的内容通常无法跨越下一次网络重连或系统重启,因为经理人们随时准备根据最新的网络环境背刺你的修改。

 

1. DNS 解析的四层结构

Saturday, 21 December 2024

LinkedIn - Ellipsis Bug

Firefox users might have recently noticed that LinkedIn profiles display an ellipsis ("…") but do not allow the text to expand when clicked.

, whereas Chrome users encounter no such issue.


Firefox: About section

Saturday, 16 September 2023

Building and Running the Linux Kernel Using Qemu: In a Nutshell

xb@dnxb:~$ sudo apt update
# Install the necessary packages for building the Linux kernel:
xb@dnxb:~$ sudo apt-get install build-essential libncurses5-dev bison flex libssl-dev libelf-dev
# libvirt-bin is now split into libvirt-daemon-system and libvirt-clients.
xb@dnxb:~$ sudo apt install qemu-kvm qemu virt-manager virt-viewer libvirt-daemon-system libvirt-clients

# To resolve the error "pahole (pahole) is not available" while making the kernel.
xb@dnxb:~$ sudo apt install dwarves
# Test in Ubuntu, not using Linux source at github
xb@dnxb:~$ sudo apt install linux-source
# After the installation, the source is typically located in `/usr/src/`
xb@dnxb:~$ cd /usr/src/
# You'll need to modify the subsequent commands "...5.4.0..." based on the latest version.
xb@dnxb:/usr/src$ cd linux-source-5.4.0
xb@dnxb:/usr/src/linux-source-5.4.0$ cp linux-source-5.4.0.tar.bz2 ~/Downloads/
xb@dnxb:/usr/src/linux-source-5.4.0$ cd ~/Downloads/

# OR use `pv linux-source-5.4.0.tar.bz2 | tar -xjf-` to monitor the extraction progress.
xb@dnxb:~/Downloads$ tar xjf linux-source-5.4.0.tar.bz2
# ... If you use Nautilus for extraction, you need to copy it from /usr/src/ to a regular user path before extracting.
# ... However, when using Nautilus, you might need to eliminate any redundant directories that were created by mistake. Eliminate them early, as changes in directory timestamps seem to slow down the remaking process.
# e.g. xb@dnxb:~/Downloads/redundant_folder/linux-source-5.4.0$

# To fix `No rule to make target 'debian/canonical-certs.pem', needed by 'certs/x509_certificate_list'. Stop.` when make kernel from Ubuntu because the .config file contains "debian/" certs:
xb@dnxb:~/Downloads/linux-source-5.4.0$ cp -r /usr/src/linux-source-5.4.0/debian ./
xb@dnxb:~/Downloads/linux-source-5.4.0$ cp -r /usr/src/linux-source-5.4.0/debian.master ./

# As an initial modification trial, add "hello world" after `pr_notice("%s", linux_banner);`:
xb@dnxb:~/Downloads/linux-source-5.4.0$ grep -i hello init/main.c -C 2
page_address_init();
pr_notice("%s", linux_banner);
pr_notice("Hello, World! from the Kernel by hole\n");
early_security_init();
setup_arch(&command_line);
xb@dnxb:~/Downloads/linux-source-5.4.0$

# ARCH=x86_64 is optional, while the default ARCH=x86 lets you toggle off the 64-bit kernel in the menu.
# Just click <Exit> then [Save]. If re-edit main.c to add print, no need run this:
xb@dnxb:~/Downloads/linux-source-5.4.0$ make menuconfig ARCH=x86_64
xb@dnxb:~/Downloads/linux-source-5.4.0$ make -j$(nproc) ARCH=x86_64
# If you re-edit main.c to add a print, you don't need to run `make modules`, just `make -j$(nproc) ARCH=x86_64 && make bzImage -j$(nproc) ARCH=x86_64`
# "Section mismatch" warnings can be safely ignored.
# Can type '?' to see details if seeing "[N/m/y/?] (NEW) ?", simply "y"
xb@dnxb:~/Downloads/linux-source-5.4.0$ make modules -j$(nproc) ARCH=x86_64
xb@dnxb:~/Downloads/linux-source-5.4.0$ make bzImage -j$(nproc) ARCH=x86_64

# Despite the ARCH=x86_64 setting, the kernel image path is ./arch/x86/boot/bzImage.
# The reason is the unified source code for x86 and x86_64 in the Linux kernel.
# x86 covering both x86 & x86_64 through scripts/subarch.include and .config .
# The x86_64 path is simply a symbolic link to x86.
# Use the x86 path to qemu as it's the real location for the kernel image.
xb@dnxb:~/Downloads/linux-source-5.4.0$ file ./arch/x86_64/boot/bzImage
./arch/x86_64/boot/bzImage: symbolic link to ../../x86/boot/bzImage
xb@dnxb:~/Downloads/linux-source-5.4.0$ realpath ./arch/x86/boot/bzImage
/home/xiaobai/Downloads/linux-source-5.4.0/arch/x86/boot/bzImage
xb@dnxb:~/Downloads/linux-source-5.4.0$

# Create an Initramfs:
# For a simple test, you can create a very basic initramfs that only has a /init script. Here's an example:
# replace 'hole' with your preferred directory name
xb@dnxb:~/Downloads/linux-source-5.4.0$ mkdir hole; cd hole/
xb@dnxb:~/Downloads/linux-source-5.4.0/hole$ mkdir -p myinitramfs
xb@dnxb:~/Downloads/linux-source-5.4.0/hole$ cd myinitramfs/
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/myinitramfs$ mkdir -p bin sbin etc tmp proc sys usr/bin usr/sbin
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/myinitramfs$ echo -e '#!/bin/sh\nmount -t proc none /proc\nmount -t sysfs none /sys\nexec /bin/sh' > init
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/myinitramfs$ chmod +x init
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/myinitramfs$ cd ..

# You can visit https://busybox.net/downloads/ to get the latest version. You'll need to modify the subsequent commands "...1.36.1..." based on the latest version:
xb@dnxb:~/Downloads/linux-source-5.4.0/hole$ wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2
xb@dnxb:~/Downloads/linux-source-5.4.0/hole$ tar xjf busybox-1.36.1.tar.bz2
xb@dnxb:~/Downloads/linux-source-5.4.0/hole$ cd busybox-1.36.1/
# Load the default configuration:
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/busybox-1.36.1$ make defconfig
# "Settings" -> "Build Options" -> "Build static binary (no shared libs)" and press 'Y' otherwise will get "Kernel panic - not syncing: No working init found." after boot kernel.
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/busybox-1.36.1$ make menuconfig
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/busybox-1.36.1$ make -j$(nproc)

# Now, create the initramfs archive. CPIO is the preferred method because it effectively duplicates a file system, backs it up, and preserves unique file features like hardlinks and FIFOs:
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/busybox-1.36.1$ cd ../myinitramfs
# Use BusyBox as the shell program for initramfs:
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/myinitramfs$ cp ../busybox-1.36.1/busybox bin/
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/myinitramfs$ cd bin/
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/myinitramfs/bin$ ln -s busybox sh
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/myinitramfs/bin$ ln -s busybox mount
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/myinitramfs/bin$ cd ..
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/myinitramfs$ find . | cpio -H newc -o | gzip > ../myinitramfs.cpio.gz
xb@dnxb:~/Downloads/linux-source-5.4.0/hole/myinitramfs$ cd ../..

# Boot the kernel with qemu. You might need to press Enter to access the shell. To exit, use "Ctrl+a", release it, then press "x". If there's an issue, use killall qemu-system-x86_64.
# append "panic=10" will reboot 10 seconds after kernel panic
xb@dnxb:~/Downloads/linux-source-5.4.0$ qemu-system-x86_64 -kernel /home/xiaobai/Downloads/linux-source-5.4.0/arch/x86/boot/bzImage -initrd /home/xiaobai/Downloads/linux-source-5.4.0/myinitramfs.cpio.gz -append "console=ttyS0 earlyprintk=serial,ttyS0,115200 debug" -nographic
...


Wednesday, 17 May 2023

Is TikTok listening to my conversation?

My friend invited me to lunch and mentioned the word "cafe", but I didn't go.

After 4 hours, I noticed a post related to cafes in my Facebook news feed:


This post isn't very popular and I haven't heard the word "Cafe" for a long time, I can't even recall the last time. So I realized this post is not a coincidence, not again (something I type in ChatGPT also shows similar ads, either OpenAI or my keyboard is selling my data, as expected~).

So I quickly dumped adb logcat, hoping the relevant logs hadn't disappeared yet. Fortunately, it did retain the 05-16 19:39:17.603 log from the previous night:



The next thing I found is quite intriguing:

Sunday, 12 June 2022

How do scammers obtain TAC by calling your phone

Thought experiment. 😶


How do scammers obtain TAC by calling your phone.


1. A camera in a store, bank, or landlord caught you typing a password, phishing, or an 0 day exploit such as StrandHogg 2.0 (https://promon.co/resources/downloads/strandhogg-2-0-new-serious-android-vulnerability/, https://www.xda-developers.com/strandhogg-2-0-android-vulnerability-explained-developer-mitigation/).


2. The attacker calls you.


3. You pick up the phone and answer it. 


4. The attacker records your voice.


5. The attacker converts your voice to an inaudible form of Hey Google/Siri pattern (Dolphin Attack, https://dl.acm.org/doi/pdf/10.1145/3133956.3134052, https://www.securityweek.com/siri-alexa-google-now-vulnerable-ultrasound-attacks, https://www.helpnetsecurity.com/2020/03/03/ultrasonic-waves-access-cellphones/).


6. The attacker puts or delivers an ultrasound device near you. 


7. Now your phone is triggered to run commands by asking Hey Google or Siri in ultrasound. You don't realise it because humans can't hear ultrasound. See the demonstration video, get TAC by voice (I may use typing since my speaking is bad).  It has not been tested for ultrasound. The commands used: "Silent" -> "Dim the screen" -> "Open SMS app" -> "Send screenshot to 0133743923" -> "Please send" -> "Send".

Sunday, 16 January 2022

Facebook custom list feed is not really gone

 I thought that custom list feed gone long time ago:



But actually you can still access custom list news feed with this URL format (x.facebook OR m.facebook both can work):

Tuesday, 9 November 2021

知乎 - "我们检测到您此次登录异常,请您进行安全验证" 的 bug

近两天知乎的每新打开一页都会出现 "我们检测到您此次登录异常,请您进行安全验证" 对话框。(截图注: www2 只是测试, www 一样):


输入手机验证,对话框关闭,但打开新一页或点击 "查看全部 xxx 答案" 都会重复出现该验证对话框。不验证直接 X 关闭对话框也行,不过重复出现很烦。

后来察觉专栏 zhuanlan.zhihu.com 没对话框,就想到换其它 subdomain 可能可以。

Friday, 26 February 2021

中文和英文双字幕观看 YouTube 视频

我英文差, 但是又不能只看中文(讲话的人是英文,失去原味),所以打算双字幕观看。英文字幕在 mpv 播放器下方,看到不懂的字可以望上面的中文字幕。

虽然此视频  IlU-zDU6aQ0 网页版有英文字幕以及自动翻译的中文字幕,可是旧版本的 youtube-dl 和随便两个网站 (https://downsub.comhttps://savesubs.com) 都只能拿到英文字幕。



虽然最新版本的  youtube-dl 已经 fix 了,无论如何,要手动完成此任务,也行的:

1. 下载英文字幕 (.vtt): youtube --skip-download --write-sub --sub-lang en https://www.youtube.com/watch?v=IlU-zDU6aQ0 。

2. 在 Youtube 播放器, 变改语言边 inspect network, 得到 `api/timedtext?` 链接。

用 curl 跑链接获得 .json 格式的字幕。

3.  转换 .json 去 .srt 不需要重造轮子,浏览 https://zhuanlan.zhihu.com/p/337934938 下载某人写的 node.js 代码, `parse_subtitle.js`, 加上这三条 line:

Saturday, 6 February 2021

Trace python program from log perspective

回答了 -vvv debug pip:


Just a reminder to whom google this error and come here.

Let's say I get this error:

$ python3 example.py
Traceback (most recent call last):
  File "example.py", line 7, in <module>
    import aalib
ModuleNotFoundError: No module named 'aalib'

Since it mentions aalib, I was thought to try aalib:

Saturday, 23 January 2021

How to play Facebook Quiz

第一种方法在重复 submit 能发出多个 messenger notification 给该朋友我玩了你的 game,而第二种方法没 notification。不过两种方法都有在 game 内置的 notification。

Sunday, 29 November 2020

视频用 N 倍速看对 fps 的影响

如果播放视频时加速,对 fps 有何影响?如何预测会 dropped 多少 frames?

mpv 确实可以 speed up 后如果仍可以满足 monitor 的 refresh rate Hz 就可以不 drop frames。

不过 165 Hz 要求 gpu+cpu 很高否则也是有问题(不然 multitasking 容易 drop frame)。

而且 144 Hz 或 120 Hz 都能被常见的 24 fps 完整除 (120 Hz 能被 youtube 常见的 30 fps 除)

,只有 165 Hz 怪怪的不能整除 (https://www.svp-team.com/forum/viewtopic.php?pid=63214#p63214)。



做个小实验验证一下:

Thursday, 12 November 2020

MySejahtera bug

MySejahtera 的隐私 bug,可以查看其它店的人流, 甚至更新资料。

有些非 Master branch 而看不到更新资料的页面,能通过 email 得知 `Hi contact_name`(有些填手机号)。

由于 bug 会被滥用,我就不公开方法了。(更新: 已被修复)

MySejahtera 没网络 check-in

 实验:

MySejahtera app 在没网络下,扫描二维码后, 政府还能不能收到该 check-in?
 
实验结果:
 
每次点击 "close" 按钮后的十秒, 都会调用 js 的 checkAndSync() 函数, 检查 checkInQue 数据库表之前有没有失败的请求 queue,有的话就(等多一秒)一个个调用 syncCheckIn() 函数尝试 "/clockin" API 终点请求上传。"Clear storage" 会清除该 queue,"Clear Cache" 则不会。
 
实验总结:
 
请确保点击 "close" 按钮后的十一秒后有网络,才能上传之前没网络的 check-in 给政府。即使你扫描新的二维码, 是不会包括之前没网络所累积的 check-in, 必须点击 "close" 按钮等十一秒。十一秒是开始上传的时间,上传全部需时十一秒以上。


Saturday, 7 November 2020

Facebook 鏈接對下載質量的影響

用 youtube-dl 和 you-get 下載 4 種視頻鏈接格式:
[1] 'https://www.facebook.com/<username>/videos/123/'
[2] 'https://www.facebook.com/<username>/posts/123'
[3] 'https://www.facebook.com/permalink.php?story_fbid=123&id=123'
[4] 'https://www.facebook.com/watch/?v=123'
[5] 手動下載。

實驗結果:

Friday, 23 October 2020

怎样才能在 Facebook 上传下载最高清的图实验。

Android 上传 4 MiB (4032x3024) 的文件, PXL_20201022_141809183.NIGHT.jpg:
[1] 浏览器能下载 241 KiB (1440x1080) 的 JPEG 图。
[2] Android Facebook app 能下载 114 KiB (1080x810) 的 JPEG 图。


浏览器上传同样的 PXL_20201022_141809183.NIGHT.jpg:

[1] 浏览器能下载 509 KiB (2016x1504) 的 JPEG 图。
[2] Android Facebook app 能下载 109 KiB (1080x806) 的 JPEG 图。


实验总结:

Wednesday, 21 October 2020

bash -c "$pitfall"

If user use bash -c "" will easy to get unexpected result if user just copy-paste working code from existing shell session into bash -c "" (OR extend existing bash -c "") and expect it same. But if user use single quotes(outermost) consistently, then user can get rid a lot of trouble.