Send the networks the TSPU cuts off to openipc.ru with a 301 - #381
Conversation
PR Summary by QodoRedirect Russian-network HTTPS traffic to the openipc.ru mirror
AI Description
Diagram
High-Level Assessment
Files changed (7)
|
Code Review by Qodo
1.
|
|
Both Qodo findings addressed in e270945:
|
In Russia the TSPU freezes a TLS connection to the origin's network after the first 20-odd kilobytes. Captured on the origin 2026-10-03: four camera uploads from Rostelecom, KES and SOVAM addresses completed the handshake, delivered 22.8-24.9 KB and then went silent both ways; nginx's FIN at its 60 s body timeout was retransmitted seven times unanswered. 561 uploads ended as 408s that way on 2026-10-02, while all 552 that came through openipc.ru, proxied from a host inside Russia, were stored. The origin now answers every network announced by an AS registered in Russia with a 301 to the same address on https://openipc.ru, uploads included, before reading anything else -- the answer is small enough to arrive before the freeze. The decision is the site's, so no client names a mirror. - conf.d/openipc-blocked-nets.list: 4,999 ASes, 12,334 IPv4 and 1,905 IPv6 networks, generated by deploy/blocked-nets.py from iptoasn.com's table and committed; rerun the script to refresh it. - The geo is keyed on the peer ($realip_remote_addr): behind a mirror the reader is Russian, and openipc.ru's own host is in a Russian AS, so every set_real_ip_from address is listed as not blocked. deploytest fails if one is missing or the key changes, and both mutations were checked to fail it. - HTTPS server only: stock firmware fetches ipctool and posts reports over plain HTTP on port 80, and has no TLS to follow a redirect into. - check-config.sh --seam sends GET, POST /snapshots and an API GET from a stand-in blocked address and requires a 301 to the same path and query on openipc.ru.
…gh openipc.ru Two consequences of sending Russian networks to openipc.ru (Qodo, #381): - The club refused every POST whose Origin was not CLUB_SITE_URL, so a reader on openipc.ru could not sign in or send. The origins of the names that proxy the site (CLUB_MIRROR_ORIGINS, defaulting to openipc.ru, опенипц.рф, openipc.kz and openipc.cloud) are accepted as well; any other origin is still refused, and a test holds both sides. - openipc.ru capped every request at 1m, so a report with a photo in it got a 413 from the mirror. It now has a location for /api/v1/reports and /api/v1/club/ with the origin's limits (300m, five minutes, unbuffered), and deploytest fails if the two drift apart. Applied on the host and checked: a 2 MB body through https://openipc.ru/api/v1/reports reached the service, which answered it itself.
20f429f to
fcf1d16
Compare
openipc.org now answers networks that cannot reach it intact with a 301 to a mirror (OpenIPC/website#381). In Russia the TSPU freezes an upload to it after the first 20-odd kilobytes: 561 uploads ended as 408s on 2026-10-02. Which networks, and which mirror, is the site's decision, so nothing is named here; the camera only has to follow. curl follows nothing without --location, and on a 301 or 302 it turns a POST into a GET unless told --post301/--post302, which would lose the picture. --max-redirs 3 bounds a loop. Checked by running the script in a container with the camera's commands stubbed: a server answering the POST with 301 to a second one, and the second received a POST of 251,290 bytes carrying the file and mac_address parts, and answered 201.
In Russia the TSPU freezes a TLS connection to the origin's network after the first 20-odd kilobytes. Camera uploads from Russian providers die mid-body and end as nginx 408s: 561 on 2026-10-02, 300-570 a day since at least 2026-09-19.
Evidence (production, 2026-10-02/03)
Change
conf.d/openipc-blocked-nets.conf:geo $realip_remote_addr $openipc_blocked_net, loadingopenipc-blocked-nets.list— every network announced by an AS registered in Russia (4,999 ASes, 12,334 IPv4 + 1,905 IPv6 networks), generated bydeploy/blocked-nets.pyfrom iptoasn.com and committed.sites-available/org.openipc, HTTPS server:if ($openipc_blocked_net) { return 301 https://openipc.ru$request_uri; }— pages, APIs andPOST /snapshotsalike. Port 80 is untouched (stock firmware fetches ipctool and posts reports over plain HTTP).set_real_ip_fromaddress is listed as not blocked. Otherwise the mirror's requests would be redirected back to it.Known consequence: cameras on current firmware run
curlwithout-L, so they do not follow the 301. Five Russian cameras that upload directly today (355 uploads stored since 2026-10-02) stop until their firmware follows redirects (curl -L --post301, no mirror named). The six that freeze today are already failing.Tests
deploy/nginx/check-config.sh --seam(nginx 1.26 in a container): from a stand-in blocked address,GET /ru/get-started?a=1,POST /snapshotsandGET /api/v1/wizard/…each answer 301 to the same path and query on openipc.ru; the rest of the seam unchanged.service/deploytestTestBlockedNetsGoToTheMirror: peer key, every trusted mirror exempt, list well-formed and covering the frozen cameras but not the origin or GitHub, redirect on HTTPS only and not on dev. Keying on$remote_addrand dropping a mirror's exemption were each checked to fail it.deploy/push-nginx.shdry run: the host differs from this branch only by the vhost lines and the two new files.Not yet applied to the host.