Cloudflare · OFFICIAL ARTICLE

我们正在开源隐私代理 CLI

pvcli 是一款类似 curl 的工具,旨在简化对 OHTTP 等复杂隐私协议的测试。

来源:Cloudflare
ORIGINAL · 官方原文

We’re open-sourcing our privacy proxy CLI

详细说明

Blog Better Internet HTTP3 Open Source +3 Show 3 more tags

6 Tags Show 6 tags

Privacy QUIC Rust

Better Internet HTTP3 Open Source Privacy QUIC Rust

July 27, 2026

  • Selected Tags
  • Better Internet HTTP3 Open Source Privacy QUIC Rust
  • All tags
  • Matching tags
  • No tags found
  • 1.1.1.1
  • 2FA
  • Abuse
  • Access
  • Access Control Lists (ACLs)
  • Accessibility
  • Account Takeover
  • Acquisitions
  • Addressing
  • Advanced Certificate Manager
  • Advanced DDoS
  • Advertising
  • Aegis
  • Africa
  • Afroflare
  • Agent Readiness
  • Agents
  • Agents Week
  • AI
  • AI Bots
  • AI Gateway
  • AI Search
  • AI-SPM
  • AI WAF
  • AI Week
  • Alertmanager
  • Always Online
  • AMD
  • AMP
  • Analytics
  • Anonymous
  • Anti Malware
  • Anycast
  • API
  • API Gateway
  • API Security
  • API Shield
  • APJC
  • Apple
  • Application Security
  • Application Services
  • Area 1 Security
  • Argo Smart Routing
  • ASCII
  • Asia
  • Athenian Project
  • Atlassian
  • Attacks
  • Audit Logs
  • Austin
  • Australia
  • Authentication
  • Authy
  • Automatic HTTPS
  • Automatic Platform Optimization
  • Automation
  • AutoMinify
  • Auto Rag
  • Awards
  • AWS
  • Baidu
  • Bandwidth Alliance
  • Bandwidth Costs
  • Best Practices
  • Beta
  • Better Internet
  • BGP
  • Birthday Week
  • Blackbird
  • Black Friday
  • Bot Fight Mode
  • Bot Management
  • Botnet
  • Bots
  • BPF
  • Brand
  • Brand Protection
  • Brazil
  • Browser Insights
  • Browser Rendering
  • Browser Run
  • Bug Bounty
  • Bugs
  • BYOIP
  • Cache
  • Cache Purge
  • Cache Reserve
  • Cache Rules
  • California
  • Canada
  • Cap'n Proto
  • CAPTCHA
  • Careers
  • CASB
  • Categories
  • CDN
  • CDNJS
  • Certificate Authority
  • Certificate Pinning
  • Certificate Transparency
  • Certification
  • CFSSL
  • Challenge Page
  • ChatGPT
  • China
  • China Network
  • Christmas
  • Chrome
  • CIO Week
  • CISA
  • Claire
  • CLI
  • ClickHouse
  • Clientless
  • Clientless Web Isolation
  • Cloud Connector
  • Cloud Email Security
  • Cloudflare Access
  • Cloudflare Apps
  • Cloudflare Area 1
  • Cloudflare Calls
  • Cloudflare Email Service
  • Cloudflare for Campaigns
  • Cloudflare for SaaS
  • Cloudflare for Startups
  • Cloudflare Gateway
  • Cloudflare History
  • Cloudflare Images
  • Cloudflare Media Platform
  • Cloudflare Meetups
  • Cloudflare Network
  • Cloudflare One
  • Cloudflare One Client
  • Cloudflare One User Risk Score
  • Cloudflare One Week
  • Cloudflare Pages
  • Cloudflare Polish
  • Cloudflare Queues
  • Cloudflare Realtime
  • Cloudflare Stream
  • Cloudflare Tunnel
  • Cloudflare TV
  • Cloudflare Workers
  • Cloudflare Workers KV
  • Cloudflare Workers KV (ES)
  • Cloudflare Workers (PT)
  • Cloudflare Zero Trust
  • Cloudforce One
  • Cloudy
  • Code Orange
  • Coinbase
  • Colombia
  • Community
  • Compliance
  • Compression
  • Config Rules
  • Configuration Management
  • Congestion Control
  • Connectivity
  • Connectivity Cloud
  • Consumer Services
  • Containers
  • Content Independence Day
  • Content Scanning
  • Context
  • Core
  • COVID-19
  • Crawler Hints
  • CrowdStrike
  • Cryptography
  • Crypto Week
  • CSAM Reporting
  • Customers
  • Customer Success
  • Customer Zero
  • CVE
  • CVE-2023-50387
  • Cyber Readiness
  • Cybersecurity
  • D1
  • Dashboard
  • Data
  • Database
  • Data Catalog
  • Data Center
  • Data Localization
  • Data Localization Suite
  • Data Loss
  • Data Loss Prevention
  • Data Platform
  • Data Privacy Day
  • Data Protection
  • Data Sovereignty
  • Data Transfer Bucket
  • DDoS
  • DDoS Alerts
  • DDoS Reports
  • Debugging
  • Deep Dive
  • Descaler
  • Design
  • Deskope
  • Developer Documentation
  • Developer Platform
  • Developers
  • Developer Spotlight
  • Developers Storage
  • Developer Week
  • Device Security
  • DevOps
  • DEX
  • Digital Experience Monitoring
  • Digital Forensics
  • Disrupt
  • Distributed
  • Distributed Systems
  • Distributed Web
  • Diversity
  • DLP
  • DMARC
  • DNS
  • DNS Filtering
  • DNS Flood
  • DNSSEC
  • DNS Security
  • Dogfooding
  • DoH
  • Domain Rankings
  • Domain Scoped Roles
  • dosd
  • Drupal
  • Due Process
  • Durable Execution
  • Durable Objects
  • Early Hints
  • Earth Day
  • eBPF
  • EC2
  • eCommerce
  • Edge
  • Edge Computing
  • Edge Database
  • Edge Rules
  • Education
  • Egress
  • Elastic
  • Elections
  • Election Security
  • Elliptic Curves
  • Email
  • Email Routing
  • Email Security
  • Email Workers
  • EmDash
  • Emissions
  • Employee Resource Groups
  • Encrypted SNI
  • Encryption
  • Engineering
  • Enterprise
  • Entropy
  • EPYC
  • Ethereum
  • Europe
  • European Union
  • Events
  • Exploit
  • Facebook
  • Fancy Bear
  • Fast Fonts
  • FCC
  • Feature Flags
  • FedRAMP
  • FedRAMP High
  • FedRAMP Moderate
  • Firefox
  • Firewall
  • Firmware
  • Florida
  • Football
  • Formal Methods
  • Forrester
  • Fortran
  • Foundation DNS
  • Founders' Letter
  • France
  • Fraud
  • Free
  • Freedom of Speech
  • Front End
  • Full Stack
  • Full Stack Week
  • Fun
  • Gartner
  • Gatebot
  • GA Week
  • GDPR
  • General Availability
  • Generative AI
  • Gen X
  • Geo Key Manager
  • Germany
  • GitHub
  • Go
  • Google
  • Google Analytics
  • Google Cloud
  • Google Workspace
  • Government Innovation
  • Grace Hopper
  • Grafana
  • GraphQL
  • Green
  • Grinch
  • Growth
  • gRPC
  • Guest Post
  • Hackathon
  • Halloween
  • Hardware
  • HashiCorp
  • Hertzbleed
  • Heuristics
  • History
  • Holidays
  • Holocaust
  • Hong Kong
  • Hosting Con
  • Hostnames
  • HTTP2
  • HTTP3
  • HTTPS
  • Human Rights
  • Hurricane
  • Hybrid Cloud
  • Hyperdrive
  • IBM
  • ICANN
  • iCloud Private Relay
  • Identity
  • IETF
  • IL4
  • Image Optimization
  • Image Recognition
  • Image Resizing
  • Image Storage
  • Impact
  • Impact Week
  • I'm Under Attack Mode
  • Incident Report
  • Incident Response
  • India
  • Indicators of Compromise
  • Indonesian
  • Infrastructure
  • Infrastructure as Code
  • Insights
  • Intel
  • Interconnection
  • Internal DNS
  • Internet Performance
  • Internet Quality
  • Internet Regulation
  • Internet Shutdown
  • Internet Summit
  • Internet Traffic
  • Internet Trends
  • Internship Experience
  • Intrusion Detection
  • Investors
  • IoCs
  • iOS
  • IoT
  • IPFS
  • IPsec
  • IPv4
  • IPv6
  • IRAP
  • Israel
  • Italy
  • IWD
  • JAMstack
  • Japan
  • JavaScript
  • Jengo
  • Jengo Policy
  • Joomla
  • Judeoflare
  • Kafka
  • Kernel
  • Keyless SSL
  • KeyTrap
  • Key Value
  • Killnet
  • Korea
  • Kubernetes
  • LangChain
  • Latency
  • Latin America
  • Latinflare
  • LavaRand
  • Lazarus group
  • Leaked Credential Checks
  • Legal
  • Legal Patents Sable
  • LGBTQIA+
  • Life at Cloudflare
  • Linux
  • Lisbon
  • Live Streaming
  • Llama
  • LLM
  • Load Balancing
  • Localization
  • Log4J
  • Log4Shell
  • Logging
  • Log Push
  • Logs
  • LUA
  • Machine Learning
  • Magecart
  • Magic Firewall
  • Magic Network Monitoring
  • Magic Transit
  • Magic WAN
  • Magic WAN Connector
  • Malicious JavaScript
  • Malware
  • Managed Components
  • Managed Rules
  • March of Cloudflare
  • MASQUE
  • MCP
  • Meerkat
  • MeetUp
  • Meris
  • Message Protocol
  • Mexico
  • Micro-frontends
  • Microsoft
  • Microsoft 365
  • Microsoft Azure
  • Middle East
  • Migration Hub
  • Milestones
  • Miniflare
  • Mirage
  • Mirai
  • Mitel
  • Mitigation
  • Mixed Content Errors
  • MLops
  • Mobile
  • Mobile SDK
  • Model Context Protocol
  • Moldova
  • Monitoring
  • Multi-Cloud
  • Multi-User
  • MySQL
  • NaaS
  • Net Neutrality
  • Network
  • Networking
  • Network Interconnect
  • Network Performance Update
  • Network Protection
  • Network Services
  • New Year
  • NGINX
  • Ninjas
  • NIST
  • Node.js
  • North America
  • Notebooks
  • Notifications
  • NSEC3
  • OAuth
  • Observability
  • Oceania
  • OCSP
  • Offices
  • Okta
  • Olympics
  • Onboarding
  • OpenAI
  • Open API
  • OpenBMC
  • OpenDNS
  • Open Source
  • OpenSSL
  • OpenTelemetry
  • Optimization
  • Origin Rules
  • Outage
  • Oxy
  • Pacific Northwest
  • Page Rules
  • Page Shield
  • Parallels
  • Partners
  • Partnership
  • Password-reuse
  • Passwords
  • Passwords (PT)
  • Patents
  • PAYGO
  • Payments
  • Pay Per Crawl
  • PCI Certified
  • Peering
  • Performance
  • Phishing
  • php
  • Phython
  • Pingora
  • Pipelines
  • PlanetScale
  • Plans
  • Platform Engineering
  • Platform Week
  • Plesk
  • Policy & Legal
  • Politics
  • Portugal
  • Postgres
  • Post Mortem
  • Post-Quantum
  • Precursor
  • Prepared Statements
  • Prisma
  • Privacy
  • Privacy Pass
  • Privacy Week
  • Private IP
  • Private Network
  • Product Design
  • Product News
  • Programming
  • Programming (PT)
  • Project Fair Shot
  • Project Galileo
  • Project Honey Pot
  • Project Pangea
  • Project Safekeeping
  • Project Turpentine
  • Prometheus
  • Protocols
  • Proudflare
  • Proxying
  • Public Sector
  • Python
  • Queues
  • QUIC
  • QUICHE
  • Quicksilver
  • R2
  • R2 Super Slurper
  • Radar
  • Radar Alerts
  • Radar API
  • Radar Maps
  • Railgun
  • Randomness
  • Ransom Attacks
  • Rapid Reset
  • Raspberry Pi
  • Rate Limiting
  • RC4
  • RDDoS
  • React
  • Reading List
  • Real-time
  • Recruiting
  • Regional Services
  • Registrar
  • Reliability
  • Remote Browser Isolation
  • Remote Desktop Protocol
  • Remote Work
  • Replication
  • Research
  • Resolver
  • Restreaming
  • Retreat
  • Reverse Engineering
  • REvil
  • Risk Management
  • Road to Zero Trust
  • Rocket Loader
  • RocksDB
  • Routing
  • Routing Security
  • RPKI
  • RRDNS
  • RSA
  • Russia
  • Rust
  • Rust Workers
  • SaaS
  • SAAS Security
  • Sable
  • Salt
  • Sampling
  • Sandbox
  • SASE
  • Save The Web
  • SDK
  • Search Engine
  • Secrets Store
  • Secure Web Gateway
  • Security
  • Security Analytics
  • Security Center
  • Security Posture
  • Security Posture Management
  • Security Service Edge
  • security.txt
  • Security Week
  • SEO
  • Serverless
  • Serverless AI
  • Serverless (PT)
  • Serverless Week
  • Server Push
  • Servers
  • SIEM
  • Signed Exchanges (SXG)
  • SIM
  • Singapore
  • Single Sign On (SSO)
  • Smart Placement
  • Smart Shield
  • Snippets
  • SOC as a Service
  • South Africa
  • South America
  • Spain
  • spdy
  • Spectrum
  • Speed
  • Speed Brain
  • Speed & Reliability
  • Speed Week
  • Spoofing
  • Sports
  • SQL
  • SRE
  • SSE
  • SSH
  • SSL
  • Standards
  • Startup Enterprise Plan
  • Statistics
  • StopTheHacker
  • Storage
  • Sumo Logic
  • Super Bowl
  • Supercloud
  • Supply Chain Attacks
  • Support
  • Sustainability
  • SWAG
  • SWG
  • Swift
  • Switzerland
  • SXSW
  • SYN
  • SYN Flood
  • Syria
  • TCP
  • Team
  • Teams Dashboard
  • TechCrunch
  • Technical Writing
  • Tech Talks
  • Terraform
  • Testimonials
  • Testing
  • Texas
  • Thanksgiving
  • The Serverlist Newsletter
  • Threat Data
  • Threat Feeds
  • Threat Intelligence
  • Threat Operations
  • Threats
  • Tiered Cache
  • TikTok
  • TLS
  • TLS 1.3
  • Tools
  • Tor
  • Tracing
  • Traffic
  • Transform Rules
  • Transparency
  • Trends
  • Trust & Safety
  • TTFB
  • TTL
  • TURN
  • TURN Server
  • Turnstile
  • TypeScript
  • UDP
  • Ukraine
  • United Kingdom
  • Universal SSL
  • URL Scanner
  • USA
  • User Research
  • VDI
  • Vectorize
  • Vetflare
  • Video
  • Visibility
  • Vite
  • VoIP
  • VPC
  • VPN
  • Vulnerabilities
  • WAF
  • WAF Attack Score
  • WAF Rules
  • Waiting Room
  • WARP
  • WARP Connector
  • WASM
  • Web3
  • Web Application Firewall
  • WebAssembly
  • Web Asset Discovery
  • Webinars
  • WebP
  • WebRTC
  • WebSockets
  • Wildebeest
  • Womenflare
  • WordPress
  • Workers AI
  • Workers Launchpad
  • Workers Logs
  • Workers Observability
  • Workers Sites
  • Workers Unbound
  • Workers VPC
  • Workflows
  • World IPv6 Day
  • Wrangler
  • x402
  • Year in Review
  • Z3
  • Zaraz
  • Zero Day Threats
  • Zero Trust
  • Zero Trust Week
  • Zone Versioning

We’re open-sourcing our privacy proxy CLI

Hannah Wang , Ben Yang , and Fisher Darling

8 minute read

COPY URL

Debugging privacy-preserving protocols is hard. Oblivious HTTP has several different steps across four different parties, not to mention binary HTTP encoding and details spread across many draft RFCs. We've taken what we've learned operating protocols like Oblivious HTTP at the scale of millions of requests per second, and wrapped it up in a nice, clean CLI tool — that we are open-sourcing today.

We call it our privacy-client , or pvcli . We’re releasing it under the Apache-2.0 License, and it is open for contributions .

Here’s a single line of code that executes a full Oblivious HTTP request with a relay, gateway and origin. Don't worry if you don't know what that means, we'll cover it below.

pvcli --ohttp \

--first-hop https://relay-cloudflare.ohttp.info \

--proxy https://gateway.ohttp.info \

-X POST \

--header "content-type: application/json" \

--data '{"test":1}' \

https://target.ohttp.info/anything

We’ll explain why we built this tool, and show just how handy it can be.

Why privacy protocols can be hard to debug

Let’s take a closer look at our motivation for creating pvcli. Over time, the Privacy team’s product suite and customer base grew. We added products like Privacy Proxy and Privacy Gateway, which power Apple’s Private Relay , Microsoft’s Edge Secure Network VPN , Flo Health’s Anonymous Mode , and more. With it came an increasing amount of special customer requirements, domain knowledge, and complexity. As a result, we saw increased friction in development and incident response.

To see this in action, let’s look at how one of our products implements Oblivious HTTP , also known as OHTTP. First, a quick primer. OHTTP provides users with a privacy guarantee: no one can know both who made a request and what they’re requesting. To achieve this, OHTTP requires two servers, a relay and a gateway, operated by two non-colluding parties.

Below is a sequence diagram of OHTTP, where our customer owns the relay and Cloudflare owns the gateway. At a high level, OHTTP can be broken down into these steps:

It involves quite a bit of back-and-forth, as you can see:

Each step is a potential point of failure that we have to consider while debugging!

In particular, we saw certain kinds of problems when debugging OHTTP.

As a result, we decided to place all of our privacy protocols in one tool. It has a clean interface that’s already familiar, displays every single step of the protocol in order, and is flexible enough to support new protocols and architectures.

To see the difference this makes, let’s see an OHTTP debugging scenario — before and after pvcli.

  • Client gets public key from the gateway.
  • Client encrypts the request and sends it to the relay.
  • Relay removes “who” the client is from the encrypted request, and sends it to the gateway.
  • Gateway decrypts the request, and sends it to the target.
  • Target processes the request, and sends a response to the gateway.
  • Gateway encrypts the response, and sends it to the relay.
  • Relay sends the encrypted response to the client.
  • Client decrypts, and gets the plaintext response.
  • Customers asked for ways to test the live system from their end, and we often wrote one-off, custom clients for our customers specific deployments.
  • Figuring out which step caused an issue was time-consuming. Was the root cause a bug in our system or our customer’s system?
  • Examining raw bits was tedious and highly prone to human error. OHTTP builds on binary HTTP, which is a binary encoded HTTP request. Anytime we needed to check the binary encoding, we were painstakingly going through raw bits.

Debugging without pvcli

Say we operate an OHTTP relay that sits in front of a customer's gateway. The customer has asked us to do an end-to-end test with a request:

POST / anything HTTP / 1.1

Host : target.ohttp.info

Content

{ "test" : 1 }

Recall the OHTTP steps from earlier. The first step is to fetch the public key from the gateway. We use curl to fetch it from the customer gateway and get this back:

0029550020b9bb667e2230dc01c6d6cc047f94a1083beb185c63e50ec09f7692a5a083254000040001000104a9280041c8321a49d6196fc82c05f48dc7a8c6fc24b15b60ae2685ca17810fc3b5424ee70265149236f254b832bf1f333fb899aac62709839a5aae3363f3133c35213323db18a9a490edb0a9f76728af0206e5754bdae82270b7978fc3226c015344f20b60dba799d6c9695a60ca16bf675625b6071f6cac844e08968a0970ec63cc8c6a900af2ca2eb279cc5248c3f09ed5140f9e3aa0a7b055adfa862e1552c5656e2691c2378442d2131ed5b863e9183fb161821ee0c923ec51b7864df068ca2b5470590736a6e01ae2194e84c46165b25d082b9df2d15ac1da785081c899166bb93a8c0865938380aa2012a26d745320b4c7e5a941eb8976a4534ac2cc9c9c99ccb5403dbe480d032ba4ca8a116564...[SNIP]

That’s a big binary string in hex. To make sense of it, we look at OHTTP RFC 9458 §3 and parse it manually:

We repeat this process for however many public keys are in the binary string.

Next, we convert our original HTTP request into binary HTTP, referencing RFC 9292 . We manually craft the binary with the help of some bespoke scripts:

0204504f5354056874747073117461726765742e6f687474702e696e666f092f616e797468696e670c636f6e74656e742d74797065106170706c69636174696f6e2f6a736f6e0a757365722d6167656e740c6665727265742f302e312e30000a7b2274657374223a317d2000

We verify each field:

Finally, we form a wrapper HTTP request that will hold our OHTTP request. To do so, we spend some more time writing another makeshift script that encrypts the binary HTTP request in the manner OHTTP specifies, using the public key from earlier. We create a header, which is the concatenation of public key ID, asymmetric encryption method ID, and symmetric encryption method IDs. Then, we concatenate header and encrypted binary HTTP request, resulting in:

5500200001000164f03cef18f625f1dcd9fb26aa802081196bd6d7ba225bf60d3ba65f4f669d59f22d4d37dfd1e45ac9d5097bd7d8e186576ebff850509b5708fe1dbe4c88a7b93b95d153ee203382979063603fb1759bcc41049ac40950f80564de9d45fe8aa4e24259e313da4768b469bbb03037b9b0c34ae5f1b65dea09b8d25f2d5bb4833b68d516a3b19f0265841d5f23a11e74a8d17a04b616e888dd60f147

We put those bytes into the body of our wrapper HTTP request, and send it to our relay. We get back a response.

malformed request

What does that mean? We reach out to the customer to ask if they can share logs from their gateway. In the meantime, we double-check the bits we've crafted. The decoded public keys look fine. The binary HTTP request... Oh! We see:

.. .0a 7b2274657374223a317d 20 00

BHTTP is length prefixed. That means we specify a length (0x0a is 10 in decimal), and then 10 bytes follow. But here, 11 bytes follow. There is an extra 20 before the

  • Type : application / json
  • 0029 is 41 in decimal, telling us this public key entry has 41 bytes associated with it.
  • 55 is the public key ID.
  • 0020 identifies the asymmetric encryption method we can use. In this case, DHKEM(X25519, HKDF-SHA256).
  • b9bb667e2230dc01c6d6cc047f94a1083beb185c63e50ec09f7692a5a0832540 is the public key.
  • 0004 tells us there are 4 bytes of symmetric cryptographic IDs that follow.
  • 0001 and 0001 identify the symmetric encryption methods we can use: HKDF-SHA256 and AES-128-GCM.
  • 02 means it's an indeterminate-length request
  • 04504f5354 is POST
  • 056874747073 is https
  • 117461726765742e6f687474702e696e666f is target.ohttp.info
  • and so on
  • spaces added for human readability
  • 20 represents a space character, so we must have accidentally added that when building the body. We remove the extra character, resend, and it works!

Debugging with pvcli

With pvcli, all of that is now a single command:

pvcli -vvv --ohttp \

--first-hop https://relay-cloudflare.ohttp.info \

--proxy https://gateway.ohttp.info \

-X POST \

--header "content-type: application/json" \

--data '{"test":1}' \

https://target.ohttp.info/anything

It handles all the binary parsing and encrypting for us, and prints logs in case we want to dive deeper:

TRCE Full decoded client config: ClientConfig { key_configs: [KeyConfig {

key_id: 85,

key: PublicKey { kem_id: X25519HkdfSha256, bytes: b9bb667e...0832540 },

symmetric_algorithms: [(HkdfSha256, AesGcm128 )] },

...

] }

...

DEBG Creating POST request to https://target.ohttp.info/anything

DEBG Parsed URI: scheme: Some ( "https" ) , host: Some ( "target.ohttp.info" ) , port: None, path: /anything

TRCE Building request with headers: [ "content-type: application/json" , "User-Agent:pvcli/0.1.0"], body: Some ( b "{ \" test \" :1}" )

...

TRCE BHTTP encoded request bytes, hex: 0204504f5354056874747073117461726765742e6f687474702e696e666f092f616e797468696e670c636f6e74656e742d74797065106170706c69636174696f6e2f6a736f6e0a757365722d6167656e740b7076636c692f302e312e30000a7b2274657374223a317d00

...

TRCE Encrypted request bytes, hex: 5500200001000164f03cef18f625f1dcd9fb26aa802081196bd6d7ba225bf60d3ba65f4f669d59f22d4d37dfd1e45ac9d5097bd7d8e186576ebff850509b5708fe1dbe4c88a7b93b95d153ee203382979063603fb1759bcc41049ac40950f80564de9d45fe8aa4e24259e313da4768b469bbb03037b9b0c34ae5f1b65dea09b8d25f2d5bb4833b68d516a3b19f0265841d5f23a11e74a8d17a04b616e888dd60f147

What used to be a fragile process — involving manipulating bits, gluing together scripts, and referencing long RFCs — is now one command.

What pvcli can do

To install:

# install rust if not already installed

curl https://sh.rustup.rs -sSf | sh

# install pvcli

cargo install --git https://github.com/cloudflareresearch/pvcli

pvcli takes a lot of inspiration from curl. We designed it with the “principle of least surprise” in mind. As a result, a lot of the arguments are the same as curl’s! Try a quick GET request to our cdn-cgi endpoint :

pvcli https://cloudflare.com/cdn-cgi/trace

pvcli --http3 https://cloudflare.com/cdn-cgi/trace

If you’re curious about what is happening under the hood, you can use -v to get detailed logs:

# more logs

pvcli -v --http3 https://cloudflare.com/cdn-cgi/trace

# even more logs

pvcli -vvv --http3 https://cloudflare.com/cdn-cgi/trace

Now, about that OHTTP command from earlier: you use --ohttp to tell pvcli to construct an OHTTP request. You pass in the relay as the --first-hop and the gateway as the --proxy. The target will be an echo server, so you can see what the target would see. In this command, we filled in the arguments with a relay, gateway, and target from ohttp.info .

pvcli -vvv --ohttp \

--first-hop https://relay-cloudflare.ohttp.info \

--proxy https://gateway.ohttp.info \

-X POST \

--header "content-type: application/json" \

--data '{"test":1}' \

https://target.ohttp.info/anything

# abridged output below

...

{

"request" : {

"method" : "POST",

"url" : "https://target.ohttp.info/anything",

"headers" : {

"content-length" : "10",

"content-type" : "application/json",

"user-agent" : "pvcli/0.1.0",

"x-ohttp-gateway" : "true"

},

"body" : {

"test" : 1

}

},

"cf" : {

"ip" : "Unknown",

"country" : "Unknown",

"colo" : "Unknown",

"asn" : "Unknown",

"asOrganization" : "Unknown"

},

"message" : "Hello from Lilo's OHTTP target!",

...

Try running the command yourself!

We’ve encountered many cases where we wanted to pass headers to the relay, rather than the target. You are able to do that with --first-hop-header :

pvcli -vvv --ohttp \

--first-hop https://relay-cloudflare.ohttp.info \

--first-hop-header "authorization: Bearer relay-token" \

--proxy https://gateway.ohttp.info \

-X POST \

--header "content-type: application/json" \

--data '{"test":1}' \

https://target.ohttp.info/anything

Similarly, we’ve also had cases where we wanted to authenticate to the relay with mTLS , to ensure that the correct client is talking with the correct relay. To do that, you can use --first-hop-client and --first-hop-key .

pvcli -vvv --ohttp \

--first-hop https://relay-cloudflare.ohttp.info \

--first-hop-client ./relay-client.pem \

--first-hop-key ./relay-client.key \

--proxy https://gateway.ohttp.info \

-X POST \

--header "content-type: application/json" \

--data '{"test":1}' \

https://target.ohttp.info/anything

And it just works. Need to test a full Oblivious HTTP request with a relay, a gateway, arbitrary headers, and mTLS? Or perhaps only request through a gateway? Or maybe you just want to see the OHTTP key configuration? pvcli can do it with a single command, debugging included.

Why build our own tool?

There are some great tools for OHTTP that already exist. Martin Thomson’s Rust implementation and Chris Wood’s Go implementation were incredibly helpful when we built out our original OHTTP implementation a few years ago. But pvcli is not only focused on OHTTP. We’re looking to add as many privacy-preserving protocols as we can to the tool. So while there are other OSS tools out there for debugging OHTTP, nothing combines OHTTP, CONNECT proxying, MASQUE and Privacy Pass (coming soon) all in one place.

Contribute to pvcli

Oblivious HTTP is an amazing protocol, and we would love to see you use it. We hope that this tool helps people debug OHTTP and write their own OHTTP implementations.

We are accepting contributions! To get started, clone the repo at https://github.com/cloudflareresearch/pvcli , and submit a pull request.

If you're looking for ways to contribute, here are some things on our to-do list. For MASQUE, we plan to add support for proxying TCP over HTTP/3, and UDP and/or IP over HTTP/2 and HTTP/3. For OHTTP, we plan to support post-quantum cryptography, add timing/latency information, support Chunked OHTTP, and improve logging.

Contact us if you are interested in using Cloudflare’s OHTTP Relays and Gateways.

Related tags

Better Internet HTTP3 Open Source Privacy QUIC Rust

Follow on Social Media

  • Cloudflare