GoSuda

gosuda.org/chromenet: Sieťový zásobník Chromium pre Go, vytvorený reprodukovateľne z pevne určeného vydania

By Lemon Mint views ...

gosuda.org/chromenet je Go http.RoundTripper, ktorý odosiela požiadavky cez vlastný sieťový zásobník Chromium. Zásobník je //net z oficiálneho vydania Chromium: jeho implementácie HTTP/1.1, HTTP/2 a QUIC/HTTP/3, BoringSSL, konfigurácia TLS prehliadača Chrome a Chrome Root Store. Beží v samostatnom pracovnom procese chrome_net_server a strana Go zostáva čisto Go (CGO_ENABLED=0), pričom s pracovným procesom komunikuje prostredníctvom RPC so zdieľanou pamäťou HQQ.

1go get gosuda.org/chromenet@v0.1.10157081033800

Prečo spúšťať sieťový zásobník Chromium

Program v Go, ktorý komunikuje s webom pomocou net/http, sa voči serveru prezentuje ako klient Go. Je to správny predvolený postup pre komunikáciu medzi službami. Je to však nevhodné vtedy, keď správanie servera závisí od toho, za aký typ klienta ho považuje: koncové body chránené kontrolou prehliadača, middleware proti botom, CDN, ktoré poskytujú rôzne verzie protokolov podľa odtlačkov TLS a HTTP/2, a testy, ktoré musia reprodukovať to, čo zažíva skutočný prehliadač.

Štandardná knižnica Go nedokáže poskytnúť sieťové správanie prehliadača. crypto/tls má vlastné poradie šifrovacích sád a množinu rozšírení a net/http má vlastné nastavenia HTTP/2. Knižnice, ktoré napodobňujú prehliadač kopírovaním bajtov ClientHello, ich kopírujú vydanie za vydaním. chromenet ide inou cestou: nenapodobňuje sieťový zásobník Chromium, ale spúšťa ho.

Meraním na darwin/arm64 s verejnou službou na zisťovanie odtlačkov (tls.peet.ws) predvolená konfigurácia hlási:

VlastnosťPozorovaná hodnota
Dohodnutý protokolh2
JA4t13d1516h2_8daaf6152771_806a8c22fdea
Odtlačok HTTP/2 (formát Akamai)1:65536;2:0;4:6291456;6:262144|15663105|0|m,a,s,p
User-Agentdesktopový Chrome s hlavnou verziou enginu, napr. Chrome/157.0.0.0

S ForceHTTP3 boli požiadavky na cloudflare-quic.com a www.google.com zodpovedané cez HTTP/3. Tieto čísla pochádzajú z jednej platformy v jeden deň. Engine je samotný zásobník, takže sa zmenia vždy, keď sa zmení pripnuté vydanie Chromium.

Použitie

NewTransport vracia http.RoundTripper. Použite ho všade, kde by ste použili http.Transport:

 1package main
 2
 3import (
 4	"fmt"
 5	"io"
 6	"net/http"
 7
 8	"gosuda.org/chromenet"
 9)
10
11func main() {
12	client := &http.Client{Transport: chromenet.NewTransport(chromenet.Options{})}
13
14	resp, err := client.Get("https://example.com/")
15	if err != nil {
16		panic(err)
17	}
18	defer resp.Body.Close()
19
20	body, _ := io.ReadAll(resp.Body)
21	fmt.Println(resp.Proto, resp.StatusCode, len(body))
22}

Pri prvej požiadavke modul zapíše vloženú binárku pracovného procesu pre vašu platformu do používateľského adresára cache, overí jej digest SHA-256 pomocou gosuda.org/hqq/secureexec, spustí ju s rodičovským životným prepojením (--parent-stdin, takže skončí, keď skončí váš proces) a otvorí pool relácií. Nič nie je potrebné inštalovať.

Niekoľko správaní nasleduje http.Transport, aby http.Client fungoval bez zmien:

  • Transport nesleduje presmerovania a neuchováva cookies. http.Client robí obe veci, rovnako ako pri http.Transport.
  • Odpovede komprimované pomocou gzip, deflate, Brotli alebo zstd prichádzajú dekódované a resp.Uncompressed je true.
  • Požiadavka drží jednu reláciu enginu, kým sa telo odpovede nezatvorí. Telá zatvárajte.
  • Zrušenie kontextu požiadavky zruší požiadavku vnútri Chromium.
  • Sieťové chyby sú hodnoty *client.NetError obsahujúce chybový kód Chromium a jeho názov:
1var ne *client.NetError
2if errors.As(err, &ne) {
3	fmt.Println(ne.Code, ne.Name) // -105 ERR_NAME_NOT_RESOLVED
4}

Možnosti

PoleÚčinok
UserAgentNahradí predvolený User-Agent Chrome. Hlavička požiadavky User-Agent má stále prednosť.
AcceptLanguageNahradí en-US,en;q=0.9.
ProxyPravidlá proxy Chromium, napríklad http://127.0.0.1:8080 alebo socks5://127.0.0.1:1080. Prázdna hodnota znamená priame pripojenie.
DisableHTTP2, DisableQUICVypnú protokoly.
ForceHTTP3Použije QUIC pre každý pôvod bez čakania na oznámenie Alt-Svc.
InsecureSkipVerifyPrijme ľubovoľný certifikát servera.
PoolRelácie enginu na použitie. Nil používa client.DefaultPool(), ktorý povoľuje 64 súbežných požiadaviek.

Transporty s rovnakými možnosťami zdieľajú jeden Chromium URLRequestContext, takže connection pooly, relácie HTTP/2 a relácie QUIC sa znovu používajú naprieč požiadavkami. Nastavenie HQQ_CHROME_NET_SERVER=/path/to/chrome_net_server nahradí vložený pracovný proces, napríklad lokálnym buildom.

Ako to funguje

VrstvaČo tam beží
Váš programhttp.Client a chromenet.Transport, čisté Go.
Hranica procesovRPC so zdieľanou pamäťou cez HQQ. Rozhranie je chrome_net.idl, ktoré hqq-bindgen skompiluje do klienta v Go a C glue kódu servera.
chrome_net_serverMalá vrstva v C++ nad Chromium: jedno sieťové vlákno, ktoré vlastní všetky objekty //net, a vlákna relácií, ktoré blokujú, kým sieťové vlákno neodpovie na požiadavku.
Chromium //netURLRequestContext, URLRequest, relácie HTTP/2 a QUIC, BoringSSL.

IDL obsahuje šesť operácií, ktoré sú dôležité: vytvorenie enginu z možností key=value, spustenie požiadavky s jej hlavičkou (METHOD URL plus riadky hlavičiek) a dĺžkou tela, zápis častí tela požiadavky, čakanie na hlavičku odpovede, čítanie dekódovaného tela a zničenie handle. Handle požiadavky deklaruje @cancel, takže opustené volanie preruší požiadavku vnútri Chromium namiesto toho, aby ju nechalo bežať až do konca.

Izolácia zásobníka v pracovnom procese je rovnako bezpečnostná vlastnosť ako vlastnosť balíkovania. Sieťový kód Chromium spracúva nedôveryhodný vstup z otvoreného internetu. Ak zlyhá, vaša služba v Go s ním nespadne: volanie zlyhá s chybou, relácia sa zahodí a klient pri ďalšej potrebe spustí nový pracovný proces.

Reprodukovateľne zostavené, pripnuté pomocou SHA-256

Binárka s veľkosťou 25 MB, ktorá obsahuje Chromium, je dôveryhodná len vtedy, ak viete presne povedať, čo do nej vstúpilo. chromenet sleduje Chromium Stable rovnako, ako gosuda.org/sqlite3 sleduje SQLite: zdroj sa nikdy nevendoruje, iba pripne.

PinKde
Vydanie Chromium a jeho oficiálny archív zdrojov -litethird_party/chromium/VERSION
SHA-256 archívu a každého nástroja, ktorý vydanie pripína: clang, Rust, GN, ninja, runtime clang pre Windows, xwinthird_party/chromium/SHA256
Verzie MSVC CRT a Windows SDK sťahované cez xwinthird_party/chromium/WINSDK
Vydanie sandbox runtime (rungv), digest obrazu hosťa, dátum snapshotu Debianuscripts/engine/BUILDENV
C runtime HQQgo.mod a go.sum

Aktuálny pin je Chromium 157.0.8103.38. Stiahnutie, ktoré nezodpovedá svojmu pinu, zastaví zostavenie. Vydanie aplikuje na Chromium presne jednu záplatu: na Linuxe sa chrome_net_server zostavuje bez NSS a overuje certifikáty serverov iba voči Chrome Root Store, takže binárka potrebuje okrem libc nič iné.

Engine pre Linux a Windows sa zostavujú vnútri sandboxov gvx: neprivilegovaných procesov s pripnutým obrazom hosťa a bez démona na hostiteľovi. Engine pre Windows sa krížovo kompilujú na Linuxe pomocou clang-cl a lld-link od Chromium proti Windows SDK, ktoré xwin sťahuje od Microsoftu. Engine pre macOS sa zostavujú natívne na macOS runneri, pretože zostavenie Chromium pre macOS vyžaduje Xcode.

Opätovné zostavenie rovnakého commitu vytvorilo bajtovo identické binárky naprieč oddelenými behmi CI. Vydané binárky sú bajtovo identické s tými, ktoré zostavil skorší beh CI pre commit, ktorý dostal engine do monorepa, na všetkých šiestich platformách.

PlatformaVeľkosť binárky
linux/amd6427.9 MB
linux/arm6427.4 MB
darwin/amd6426.2 MB
darwin/arm6423.9 MB
windows/amd6427.3 MB
windows/arm6425.8 MB

Engine pre Linux závisia iba od libc, libm, libdl, libpthread a libgcc_s a vyžadujú glibc 2.31 alebo novšiu verziu.

Sledovanie Chromium a vydaní

Naplánovaný workflow kontroluje Chromium Stable každých šesť hodín. Pri novom vydaní prepíše piny, zostaví a otestuje všetkých šesť enginov vo vetve chromium/<version>, atestuje binárky a commitne piny spolu s vloženými binárkami, ich digestami a licenčnými textami do main v jednom commite. V monorepe súbory OWNERS pre jednotlivé súbory udeľujú botovi workflowu presne tieto súbory, takže aktualizácia sa dostane do repozitára bez ľudského kroku, zatiaľ čo zmeny samotného receptu zostavenia (pin Windows SDK a záplata) stále vyžadujú vlastníka.

Každá vydaná binárka nesie atestáciu pôvodu zostavenia z workflowu, ktorý ju zostavil:

1gh attestation verify chrome_net_server_linux_amd64 --repo gosuda/chromenet

Licenčné texty obsahu každej binárky (Chromium, BoringSSL, QUICHE a zvyšok zostavovacieho grafu) generuje vlastný nástroj Chromium tools/licenses/licenses.py a dodávajú sa s vydaním ako NOTICE_<os>_<arch>.txt.

Obmedzenia

  • DialWebSocket je čistý Go klient RFC 6455 a nepoužíva sieťový zásobník Chromium.
  • DialWebTransport je implementácia v rámci procesu. Na server nedosiahne.
  • Predvolené odtlačky JA4 a HTTP/2 sú odtlačky pripnutého vydania Chromium. Chromium ich mení vydanie za vydaním a chromenet ich sleduje.
  • Binárky pre macOS sú podpísané ad-hoc a nie sú notarizované.
  • Pracovný proces stojí pamäť. Každá binárka enginu má na disku 24 až 28 MB a runtime Chromium spúšťa thread pool a sieťové vlákno.
  • Relácia enginu je držaná, kým sa telo odpovede nezatvorí. Program, ktorý necháva telá odpovedí neuzavreté, vyčerpá pool.

Zdroj

Repozitár je github.com/gosuda/chromenet, zrkadlený z //net/chromenet v monorepe gosuda. Recept zostavenia sa nachádza v scripts/engine, glue enginu v engine/ a rozhranie v chrome_net.idl.