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.
This commit is contained in:
Cecylia Bocovich 2025-07-23 12:03:03 -04:00
parent 8ae1994e4b
commit 31f879aad5
No known key found for this signature in database
GPG key ID: 009DE379FD9B7B90
2 changed files with 18 additions and 5 deletions

View file

@ -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,
}

View file

@ -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)
}