diff --git a/dendrite-config.yaml b/dendrite-config.yaml index 25503692b..2a8650db6 100644 --- a/dendrite-config.yaml +++ b/dendrite-config.yaml @@ -300,6 +300,11 @@ sync_api: max_idle_conns: 2 conn_max_lifetime: -1 + # This option controls which HTTP header to inspect to find the real remote IP + # address of the client. This is likely required if Dendrite is running behind + # a reverse proxy server. + # real_ip_header: X-Real-IP + # Configuration for the User API. user_api: internal_api: diff --git a/internal/config/config_syncapi.go b/internal/config/config_syncapi.go index 0a96e41ca..fc08f7380 100644 --- a/internal/config/config_syncapi.go +++ b/internal/config/config_syncapi.go @@ -7,6 +7,8 @@ type SyncAPI struct { ExternalAPI ExternalAPIOptions `yaml:"external_api"` Database DatabaseOptions `yaml:"database"` + + RealIPHeader string `yaml:"real_ip_header"` } func (c *SyncAPI) Defaults() { diff --git a/internal/httputil/httpapi.go b/internal/httputil/httpapi.go index 90dcf820d..c69468e6c 100644 --- a/internal/httputil/httpapi.go +++ b/internal/httputil/httpapi.go @@ -17,7 +17,6 @@ package httputil import ( "context" "io" - "net" "net/http" "net/http/httptest" "net/http/httputil" @@ -61,20 +60,6 @@ func MakeAuthAPI( logger = logger.WithField("user_id", device.UserID) req = req.WithContext(util.ContextWithLogger(req.Context(), logger)) - // check if the forwarding proxy, if there is one, has provided a real address. - if realIP := req.Header.Get("X-Real-IP"); realIP != "" { - if ip := net.ParseIP(realIP); ip != nil { - req.RemoteAddr = realIP - } - } else if forwardedFor := req.Header.Get("X-Forwarded-For"); forwardedFor != "" { - addresses := strings.Split(forwardedFor, ",") - if len(addresses) > 0 { - if ip := net.ParseIP(addresses[0]); ip != nil { - req.RemoteAddr = addresses[0] - } - } - } - return f(req, device) } return MakeExternalAPI(metricsName, h) diff --git a/syncapi/sync/requestpool.go b/syncapi/sync/requestpool.go index 30afa20b9..0fa599b1a 100644 --- a/syncapi/sync/requestpool.go +++ b/syncapi/sync/requestpool.go @@ -19,11 +19,13 @@ package sync import ( "context" "fmt" + "net" "net/http" "sync" "time" "github.com/matrix-org/dendrite/clientapi/jsonerror" + "github.com/matrix-org/dendrite/internal/config" keyapi "github.com/matrix-org/dendrite/keyserver/api" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/syncapi/internal" @@ -38,6 +40,7 @@ import ( // RequestPool manages HTTP long-poll connections for /sync type RequestPool struct { db storage.Database + cfg *config.SyncAPI userAPI userapi.UserInternalAPI notifier *Notifier keyAPI keyapi.KeyInternalAPI @@ -47,10 +50,11 @@ type RequestPool struct { // NewRequestPool makes a new RequestPool func NewRequestPool( - db storage.Database, n *Notifier, userAPI userapi.UserInternalAPI, keyAPI keyapi.KeyInternalAPI, + db storage.Database, cfg *config.SyncAPI, n *Notifier, + userAPI userapi.UserInternalAPI, keyAPI keyapi.KeyInternalAPI, rsAPI roomserverAPI.RoomserverInternalAPI, ) *RequestPool { - rp := &RequestPool{db, userAPI, n, keyAPI, rsAPI, sync.Map{}} + rp := &RequestPool{db, cfg, userAPI, n, keyAPI, rsAPI, sync.Map{}} go rp.cleanLastSeen() return rp } @@ -75,10 +79,19 @@ func (rp *RequestPool) updateLastSeen(req *http.Request, device *userapi.Device) return } + remoteAddr := req.RemoteAddr + if rp.cfg.RealIPHeader != "" { + if realIP := req.Header.Get(rp.cfg.RealIPHeader); realIP != "" { + if ip := net.ParseIP(realIP); ip != nil { + remoteAddr = realIP + } + } + } + lsreq := &userapi.PerformLastSeenUpdateRequest{ UserID: device.UserID, DeviceID: device.ID, - RemoteAddr: req.RemoteAddr, + RemoteAddr: remoteAddr, } lsres := &userapi.PerformLastSeenUpdateResponse{} go rp.userAPI.PerformLastSeenUpdate(req.Context(), lsreq, lsres) // nolint:errcheck diff --git a/syncapi/syncapi.go b/syncapi/syncapi.go index 393a7aa55..7e277ba19 100644 --- a/syncapi/syncapi.go +++ b/syncapi/syncapi.go @@ -61,7 +61,7 @@ func AddPublicRoutes( logrus.WithError(err).Panicf("failed to start notifier") } - requestPool := sync.NewRequestPool(syncDB, notifier, userAPI, keyAPI, rsAPI) + requestPool := sync.NewRequestPool(syncDB, cfg, notifier, userAPI, keyAPI, rsAPI) keyChangeConsumer := consumers.NewOutputKeyChangeEventConsumer( cfg.Matrix.ServerName, string(cfg.Matrix.Kafka.TopicFor(config.TopicOutputKeyChangeEvent)),