mirror of
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake.git
synced 2025-10-13 11:11:30 -04:00
proxy: add country to prometheus metrics
This commit is contained in:
parent
b3c734ed63
commit
e345c3bac9
6 changed files with 45 additions and 13 deletions
|
@ -1,4 +1,4 @@
|
||||||
FROM docker.io/library/golang:1.23 AS build
|
FROM docker.io/library/golang:1.23-bookworm AS build
|
||||||
|
|
||||||
# Set some labels
|
# Set some labels
|
||||||
# io.containers.autoupdate label will instruct podman to reach out to the corres
|
# io.containers.autoupdate label will instruct podman to reach out to the corres
|
||||||
|
@ -9,6 +9,8 @@ FROM docker.io/library/golang:1.23 AS build
|
||||||
LABEL io.containers.autoupdate=registry
|
LABEL io.containers.autoupdate=registry
|
||||||
LABEL org.opencontainers.image.authors="anti-censorship-team@lists.torproject.org"
|
LABEL org.opencontainers.image.authors="anti-censorship-team@lists.torproject.org"
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y tor-geoipdb
|
||||||
|
|
||||||
ADD . /app
|
ADD . /app
|
||||||
|
|
||||||
WORKDIR /app/proxy
|
WORKDIR /app/proxy
|
||||||
|
@ -19,6 +21,7 @@ FROM scratch
|
||||||
|
|
||||||
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
||||||
COPY --from=build /usr/share/zoneinfo /usr/share/zoneinfo
|
COPY --from=build /usr/share/zoneinfo /usr/share/zoneinfo
|
||||||
|
COPY --from=build /usr/share/tor/geoip* /usr/share/tor/
|
||||||
COPY --from=build /app/proxy/proxy /bin/proxy
|
COPY --from=build /app/proxy/proxy /bin/proxy
|
||||||
|
|
||||||
ENTRYPOINT [ "/bin/proxy" ]
|
ENTRYPOINT [ "/bin/proxy" ]
|
||||||
|
|
|
@ -77,8 +77,7 @@ func (e EventOnProxyClientConnected) String() string {
|
||||||
|
|
||||||
type EventOnProxyConnectionOver struct {
|
type EventOnProxyConnectionOver struct {
|
||||||
SnowflakeEvent
|
SnowflakeEvent
|
||||||
InboundTraffic int64
|
Country string
|
||||||
OutboundTraffic int64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e EventOnProxyConnectionOver) String() string {
|
func (e EventOnProxyConnectionOver) String() string {
|
||||||
|
|
|
@ -15,16 +15,18 @@ const (
|
||||||
type Metrics struct {
|
type Metrics struct {
|
||||||
totalInBoundTraffic prometheus.Counter
|
totalInBoundTraffic prometheus.Counter
|
||||||
totalOutBoundTraffic prometheus.Counter
|
totalOutBoundTraffic prometheus.Counter
|
||||||
totalConnections prometheus.Counter
|
totalConnections *prometheus.CounterVec
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMetrics() *Metrics {
|
func NewMetrics() *Metrics {
|
||||||
return &Metrics{
|
return &Metrics{
|
||||||
totalConnections: prometheus.NewCounter(prometheus.CounterOpts{
|
totalConnections: prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||||
Namespace: metricNamespace,
|
Namespace: metricNamespace,
|
||||||
Name: "connections_total",
|
Name: "connections_total",
|
||||||
Help: "The total number of connections handled by the snowflake proxy",
|
Help: "The total number of connections handled by the snowflake proxy",
|
||||||
}),
|
},
|
||||||
|
[]string{"country"},
|
||||||
|
),
|
||||||
totalInBoundTraffic: prometheus.NewCounter(prometheus.CounterOpts{
|
totalInBoundTraffic: prometheus.NewCounter(prometheus.CounterOpts{
|
||||||
Namespace: metricNamespace,
|
Namespace: metricNamespace,
|
||||||
Name: "traffic_inbound_bytes_total",
|
Name: "traffic_inbound_bytes_total",
|
||||||
|
@ -71,6 +73,8 @@ func (m *Metrics) TrackOutBoundTraffic(value int64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TrackNewConnection counts the new connections
|
// TrackNewConnection counts the new connections
|
||||||
func (m *Metrics) TrackNewConnection() {
|
func (m *Metrics) TrackNewConnection(country string) {
|
||||||
m.totalConnections.Inc()
|
m.totalConnections.
|
||||||
|
With(prometheus.Labels{"country": country}).
|
||||||
|
Inc()
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
type EventCollector interface {
|
type EventCollector interface {
|
||||||
TrackInBoundTraffic(value int64)
|
TrackInBoundTraffic(value int64)
|
||||||
TrackOutBoundTraffic(value int64)
|
TrackOutBoundTraffic(value int64)
|
||||||
TrackNewConnection()
|
TrackNewConnection(country string)
|
||||||
}
|
}
|
||||||
|
|
||||||
type EventMetrics struct {
|
type EventMetrics struct {
|
||||||
|
@ -25,6 +25,7 @@ func (em *EventMetrics) OnNewSnowflakeEvent(e event.SnowflakeEvent) {
|
||||||
em.collector.TrackInBoundTraffic(e.InboundBytes)
|
em.collector.TrackInBoundTraffic(e.InboundBytes)
|
||||||
em.collector.TrackOutBoundTraffic(e.OutboundBytes)
|
em.collector.TrackOutBoundTraffic(e.OutboundBytes)
|
||||||
case event.EventOnProxyConnectionOver:
|
case event.EventOnProxyConnectionOver:
|
||||||
em.collector.TrackNewConnection()
|
e := e.(event.EventOnProxyConnectionOver)
|
||||||
|
em.collector.TrackNewConnection(e.Country)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -114,6 +115,10 @@ var (
|
||||||
client http.Client
|
client http.Client
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type GeoIP interface {
|
||||||
|
GetCountryByAddr(net.IP) (string, bool)
|
||||||
|
}
|
||||||
|
|
||||||
// SnowflakeProxy is used to configure an embedded
|
// SnowflakeProxy is used to configure an embedded
|
||||||
// Snowflake in another Go application.
|
// Snowflake in another Go application.
|
||||||
// For some more info also see CLI parameter descriptions in README.
|
// For some more info also see CLI parameter descriptions in README.
|
||||||
|
@ -166,6 +171,9 @@ type SnowflakeProxy struct {
|
||||||
// SummaryInterval is the time interval at which proxy stats will be logged
|
// SummaryInterval is the time interval at which proxy stats will be logged
|
||||||
SummaryInterval time.Duration
|
SummaryInterval time.Duration
|
||||||
|
|
||||||
|
// GeoIP will be used to detect the country of the clients if provided
|
||||||
|
GeoIP GeoIP
|
||||||
|
|
||||||
periodicProxyStats *periodicProxyStats
|
periodicProxyStats *periodicProxyStats
|
||||||
bytesLogger bytesLogger
|
bytesLogger bytesLogger
|
||||||
}
|
}
|
||||||
|
@ -449,6 +457,7 @@ func (sf *SnowflakeProxy) makePeerConnectionFromOffer(
|
||||||
|
|
||||||
pr, pw := io.Pipe()
|
pr, pw := io.Pipe()
|
||||||
conn := newWebRTCConn(pc, dc, pr, sf.bytesLogger)
|
conn := newWebRTCConn(pc, dc, pr, sf.bytesLogger)
|
||||||
|
remoteIP := conn.RemoteIP()
|
||||||
|
|
||||||
dc.SetBufferedAmountLowThreshold(bufferedAmountLowThreshold)
|
dc.SetBufferedAmountLowThreshold(bufferedAmountLowThreshold)
|
||||||
|
|
||||||
|
@ -479,7 +488,13 @@ func (sf *SnowflakeProxy) makePeerConnectionFromOffer(
|
||||||
conn.lock.Lock()
|
conn.lock.Lock()
|
||||||
defer conn.lock.Unlock()
|
defer conn.lock.Unlock()
|
||||||
log.Printf("Data Channel %s-%d close\n", dc.Label(), dc.ID())
|
log.Printf("Data Channel %s-%d close\n", dc.Label(), dc.ID())
|
||||||
sf.EventDispatcher.OnNewSnowflakeEvent(event.EventOnProxyConnectionOver{})
|
|
||||||
|
country := ""
|
||||||
|
if sf.GeoIP != nil && !reflect.ValueOf(sf.GeoIP).IsNil() && remoteIP != nil {
|
||||||
|
country, _ = sf.GeoIP.GetCountryByAddr(remoteIP)
|
||||||
|
}
|
||||||
|
sf.EventDispatcher.OnNewSnowflakeEvent(event.EventOnProxyConnectionOver{Country: country})
|
||||||
|
|
||||||
conn.dc = nil
|
conn.dc = nil
|
||||||
dc.Close()
|
dc.Close()
|
||||||
pw.Close()
|
pw.Close()
|
||||||
|
@ -503,7 +518,7 @@ func (sf *SnowflakeProxy) makePeerConnectionFromOffer(
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
go handler(conn, conn.RemoteIP())
|
go handler(conn, remoteIP)
|
||||||
})
|
})
|
||||||
// As of v3.0.0, pion-webrtc uses trickle ICE by default.
|
// As of v3.0.0, pion-webrtc uses trickle ICE by default.
|
||||||
// We have to wait for candidate gathering to complete
|
// We have to wait for candidate gathering to complete
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"gitlab.torproject.org/tpo/anti-censorship/geoip"
|
||||||
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/ptutil/safelog"
|
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/ptutil/safelog"
|
||||||
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/event"
|
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/event"
|
||||||
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/version"
|
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/version"
|
||||||
|
@ -45,6 +46,8 @@ func main() {
|
||||||
metricsPort := flag.Int("metrics-port", 9999, "set port for the metrics service")
|
metricsPort := flag.Int("metrics-port", 9999, "set port for the metrics service")
|
||||||
verboseLogging := flag.Bool("verbose", false, "increase log verbosity")
|
verboseLogging := flag.Bool("verbose", false, "increase log verbosity")
|
||||||
ephemeralPortsRangeFlag := flag.String("ephemeral-ports-range", "", "Set the `range` of ports used for client connections (format:\"<min>:<max>\").\nUseful in conjunction with port forwarding, in order to make the proxy NAT type \"unrestricted\".\nIf omitted, the ports will be chosen automatically from a wide range.\nWhen specifying the range, make sure it's at least 2x as wide as the amount of clients that you are hoping to serve concurrently (see the \"capacity\" flag).")
|
ephemeralPortsRangeFlag := flag.String("ephemeral-ports-range", "", "Set the `range` of ports used for client connections (format:\"<min>:<max>\").\nUseful in conjunction with port forwarding, in order to make the proxy NAT type \"unrestricted\".\nIf omitted, the ports will be chosen automatically from a wide range.\nWhen specifying the range, make sure it's at least 2x as wide as the amount of clients that you are hoping to serve concurrently (see the \"capacity\" flag).")
|
||||||
|
geoipDatabase := flag.String("geoipdb", "/usr/share/tor/geoip", "path to correctly formatted geoip database mapping IPv4 address ranges to country codes")
|
||||||
|
geoip6Database := flag.String("geoip6db", "/usr/share/tor/geoip6", "path to correctly formatted geoip database mapping IPv6 address ranges to country codes")
|
||||||
versionFlag := flag.Bool("version", false, "display version info to stderr and quit")
|
versionFlag := flag.Bool("version", false, "display version info to stderr and quit")
|
||||||
|
|
||||||
var ephemeralPortsRange []uint16 = []uint16{0, 0}
|
var ephemeralPortsRange []uint16 = []uint16{0, 0}
|
||||||
|
@ -92,6 +95,12 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gip, err := geoip.New(*geoipDatabase, *geoip6Database)
|
||||||
|
if *enableMetrics && err != nil {
|
||||||
|
// The geoip DB is only used for metrics, let's only report the error if enabled
|
||||||
|
log.Println("Error loading geoip db for country based metrics:", err)
|
||||||
|
}
|
||||||
|
|
||||||
proxy := sf.SnowflakeProxy{
|
proxy := sf.SnowflakeProxy{
|
||||||
PollInterval: *pollInterval,
|
PollInterval: *pollInterval,
|
||||||
Capacity: uint(*capacity),
|
Capacity: uint(*capacity),
|
||||||
|
@ -112,6 +121,7 @@ func main() {
|
||||||
AllowNonTLSRelay: *allowNonTLSRelay,
|
AllowNonTLSRelay: *allowNonTLSRelay,
|
||||||
|
|
||||||
SummaryInterval: *summaryInterval,
|
SummaryInterval: *summaryInterval,
|
||||||
|
GeoIP: gip,
|
||||||
}
|
}
|
||||||
|
|
||||||
var logOutput = io.Discard
|
var logOutput = io.Discard
|
||||||
|
@ -163,7 +173,7 @@ func main() {
|
||||||
|
|
||||||
log.Printf("snowflake-proxy %s\n", version.GetVersion())
|
log.Printf("snowflake-proxy %s\n", version.GetVersion())
|
||||||
|
|
||||||
err := proxy.Start()
|
err = proxy.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue