Просмотр исходного кода

Log Tapdance station IP address

Rod Hynes 6 лет назад
Родитель
Сommit
f24da79e4f
1 измененных файлов с 63 добавлено и 4 удалено
  1. 63 4
      psiphon/common/tapdance/tapdance.go

+ 63 - 4
psiphon/common/tapdance/tapdance.go

@@ -68,7 +68,7 @@ type Listener struct {
 // SetReadDeadline and performs a Read.
 func Listen(address string) (*Listener, error) {
 
-	listener, err := net.Listen("tcp", address)
+	tcpListener, err := net.Listen("tcp", address)
 	if err != nil {
 		return nil, common.ContextError(err)
 	}
@@ -77,11 +77,70 @@ func Listen(address string) (*Listener, error) {
 	// header completes or times out and RemoteAddr will not block. See:
 	// https://godoc.org/github.com/armon/go-proxyproto#Conn.RemoteAddr
 
-	listener = &proxyproto.Listener{
-		Listener:           listener,
+	proxyListener := &proxyproto.Listener{
+		Listener:           tcpListener,
 		ProxyHeaderTimeout: READ_PROXY_PROTOCOL_HEADER_TIMEOUT}
 
-	return &Listener{Listener: listener}, nil
+	stationListener := &stationListener{
+		proxyListener: proxyListener,
+	}
+
+	return &Listener{Listener: stationListener}, nil
+}
+
+// stationListener uses the proxyproto.Listener SourceCheck callback to
+// capture and record the direct remote address, the Tapdance station address,
+// and wraps accepted conns to provide station address metrics via GetMetrics.
+// These metrics enable identifying which station fronted a connection, which
+// is useful for network operations and troubleshooting.
+//
+// go-proxyproto.Conn.RemoteAddr reports the originating client IP address,
+// which is geolocated and recorded for metrics. The underlying conn's remote
+// address, the Tapdance station address, is not accessible via the
+// go-proxyproto API.
+//
+// stationListener is not safe for concurrent access.
+type stationListener struct {
+	proxyListener *proxyproto.Listener
+}
+
+func (l *stationListener) Accept() (net.Conn, error) {
+	var stationRemoteAddr net.Addr
+	l.proxyListener.SourceCheck = func(addr net.Addr) (bool, error) {
+		stationRemoteAddr = addr
+		return true, nil
+	}
+	conn, err := l.proxyListener.Accept()
+	if err != nil {
+		return nil, err
+	}
+	if stationRemoteAddr == nil {
+		return nil, common.ContextError(errors.New("missing station address"))
+	}
+	return &stationConn{
+		Conn:              conn,
+		stationRemoteAddr: stationRemoteAddr,
+	}, nil
+}
+
+func (l *stationListener) Close() error {
+	return l.proxyListener.Close()
+}
+
+func (l *stationListener) Addr() net.Addr {
+	return l.proxyListener.Addr()
+}
+
+type stationConn struct {
+	net.Conn
+	stationRemoteAddr net.Addr
+}
+
+// GetMetrics implements the common.MetricsSource interface.
+func (c *stationConn) GetMetrics() common.LogFields {
+	logFields := make(common.LogFields)
+	logFields["station_ip_address"] = common.IPAddressFromAddr(c.stationRemoteAddr)
+	return logFields
 }
 
 // dialManager tracks all dials performed by and dialed conns used by a