Skip to content

ip-verifier: add the IP ownership verification service #4198

Description

@elitegreg

Part of RFC-27 (tracker: #4194). Depends on #4195.

A stateless HTTP service that signs the source IP it observes. It is the only party that can attest an IP, so its correctness about which IP it saw is the whole security property.

API

POST /v1/proof
{ "payer": "<Pubkey>", "user_pubkey": "<Pubkey>" }

200 { "payer": "...", "client_ip": "a.b.c.d", "epoch": 1234,
      "user_pubkey": "...", "signature": "<base58>" }

client_ip is always the observed source address of the request; it is never accepted from the body. user_pubkey is the User PDA the client intends to create, so the caller derives it before verifying. Also expose GET /health and a Prometheus /metrics endpoint consistent with the other DoubleZero services.

Requirements

  • Reject a source address that isn't globally routable, with the same is_global semantics the program applies, so the service never issues a proof the program would refuse.
  • Proxy handling. Behind a proxy or CDN the peer address is the proxy. Take a configured list of trusted proxy CIDRs and only then honor X-Forwarded-For / Forwarded, taking the last untrusted hop. With no trusted proxies configured, use the peer address and nothing else. Getting this wrong signs the proxy's IP for everyone, so it needs its own tests.
  • Epoch comes from the DoubleZero Ledger RPC, cached with a short TTL and refreshed in the background. Fail closed if the epoch is stale beyond a threshold rather than signing an old epoch.
  • Signing key loaded from a keypair file path (custody options are the deployment issue). Never logged.
  • Per-source-IP rate limiting, request size caps, and a request timeout.
  • IPv4 only. Reject IPv6 sources with a clear error until the proof layout gains an address family.
  • Structured logging through tracing, config through clap + env vars, matching crates/ conventions.

Implementation notes

The workspace already depends on hyper 1 and hyper-util but has no HTTP server framework. Either build on hyper directly or add axum — call the choice out in the PR since it sets a precedent for future Rust services in the repo.

Acceptance

  • Unit tests for proxy header handling: no trusted proxies, trusted proxy with one hop, trusted proxy with a spoofed extra hop, untrusted client sending X-Forwarded-For.
  • Signature output verifies against the committed test vectors from ip-proof: add a crate defining the IpOwnershipProof layout and signed message #4195.
  • Non-routable and IPv6 sources rejected.
  • Integration test that runs the service, requests a proof, and verifies it with the same code path the program uses.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions