From 31f879aad56ff9e8209867e44d3a06a2bbbb3211 Mon Sep 17 00:00:00 2001 From: Cecylia Bocovich Date: Wed, 23 Jul 2025 12:03:03 -0400 Subject: [PATCH] Pull client IP from SDP for AMP cache rendezvous The remote address for AMP cache rendezvous is always geolocated to the AMP cache server address. For more accurate metrics on where this rendezvous method is used and working, we can pull the remote address directly from the client SDP sent in the poll request. --- broker/amp.go | 3 +-- broker/ipc.go | 20 +++++++++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/broker/amp.go b/broker/amp.go index 1333c63..4d19a6c 100644 --- a/broker/amp.go +++ b/broker/amp.go @@ -9,7 +9,6 @@ import ( "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/amp" "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/messages" - "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/util" ) // ampClientOffers is the AMP-speaking endpoint for client poll messages, @@ -41,7 +40,7 @@ func ampClientOffers(i *IPC, w http.ResponseWriter, r *http.Request) { if err == nil { arg := messages.Arg{ Body: encPollReq, - RemoteAddr: util.GetClientIp(r), + RemoteAddr: "", RendezvousMethod: messages.RendezvousAmpCache, Context: ctx, } diff --git a/broker/ipc.go b/broker/ipc.go index 8154ef8..728363a 100644 --- a/broker/ipc.go +++ b/broker/ipc.go @@ -8,6 +8,7 @@ import ( "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/bridgefingerprint" "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/constants" + "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/util" "github.com/prometheus/client_golang/prometheus" "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/messages" @@ -156,6 +157,19 @@ func (i *IPC) ClientOffers(arg messages.Arg, response *[]byte) error { return sendClientResponse(&messages.ClientPollResponse{Error: err.Error()}, response) } + // If we couldn't extract the remote IP from the rendezvous method + // pull it from the offer SDP + remoteAddr := arg.RemoteAddr + if remoteAddr == "" { + sdp, err := util.DeserializeSessionDescription(req.Offer) + if err == nil { + candidateAddrs := util.GetCandidateAddrs(sdp.SDP) + if len(candidateAddrs) > 0 { + remoteAddr = candidateAddrs[0].String() + } + } + } + offer := &ClientOffer{ natType: req.NAT, sdp: []byte(req.Offer), @@ -184,7 +198,7 @@ func (i *IPC) ClientOffers(arg messages.Arg, response *[]byte) error { if snowflake != nil { snowflake.offerChannel <- offer } else { - i.ctx.metrics.UpdateClientStats(arg.RemoteAddr, arg.RendezvousMethod, offer.natType, "denied") + i.ctx.metrics.UpdateClientStats(remoteAddr, arg.RendezvousMethod, offer.natType, "denied") resp := &messages.ClientPollResponse{Error: messages.StrNoProxies} return sendClientResponse(resp, response) } @@ -192,11 +206,11 @@ func (i *IPC) ClientOffers(arg messages.Arg, response *[]byte) error { // Wait for the answer to be returned on the channel or timeout. select { case answer := <-snowflake.answerChannel: - i.ctx.metrics.UpdateClientStats(arg.RemoteAddr, arg.RendezvousMethod, offer.natType, "matched") + i.ctx.metrics.UpdateClientStats(remoteAddr, arg.RendezvousMethod, offer.natType, "matched") resp := &messages.ClientPollResponse{Answer: answer} err = sendClientResponse(resp, response) case <-arg.Context.Done(): - i.ctx.metrics.UpdateClientStats(arg.RemoteAddr, arg.RendezvousMethod, offer.natType, "timeout") + i.ctx.metrics.UpdateClientStats(remoteAddr, arg.RendezvousMethod, offer.natType, "timeout") resp := &messages.ClientPollResponse{Error: messages.StrTimedOut} err = sendClientResponse(resp, response) }