69def get_real_ip(request: flask.Request) -> str:
70 """Returns real IP of the request. Since not all proxies set all the HTTP
71 headers and incoming headers can be faked it may happen that the IP cannot
72 be determined correctly.
73
74 .. sidebar:: :py:obj:`flask.Request.remote_addr`
75
76 SearXNG uses Werkzeug's ProxyFix_ (with it default ``x_for=1``).
77
78 This function tries to get the remote IP in the order listed below,
79 additional some tests are done and if inconsistencies or errors are
80 detected, they are logged.
81
82 The remote IP of the request is taken from (first match):
83
84 - X-Forwarded-For_ header
85 - `X-real-IP header <https://github.com/searxng/searxng/issues/1237#issuecomment-1147564516>`__
86 - :py:obj:`flask.Request.remote_addr`
87
88 .. _ProxyFix:
89 https://werkzeug.palletsprojects.com/middleware/proxy_fix/
90
91 .. _X-Forwarded-For:
92 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For
93
94 """
95
96 forwarded_for = request.headers.get("X-Forwarded-For")
97 real_ip = request.headers.get('X-Real-IP')
98 remote_addr = request.remote_addr
99
100
101
102
103 if not forwarded_for:
104 _log_error_only_once("X-Forwarded-For header is not set!")
105 else:
106 from . import cfg
107
108 forwarded_for = [x.strip() for x in forwarded_for.split(',')]
109 x_for: int = cfg['real_ip.x_for']
110 forwarded_for = forwarded_for[-min(len(forwarded_for), x_for)]
111
112 if not real_ip:
113 _log_error_only_once("X-Real-IP header is not set!")
114
115 if forwarded_for and real_ip and forwarded_for != real_ip:
116 logger.warning("IP from X-Real-IP (%s) is not equal to IP from X-Forwarded-For (%s)", real_ip, forwarded_for)
117
118 if forwarded_for and remote_addr and forwarded_for != remote_addr:
119 logger.warning(
120 "IP from WSGI environment (%s) is not equal to IP from X-Forwarded-For (%s)", remote_addr, forwarded_for
121 )
122
123 if real_ip and remote_addr and real_ip != remote_addr:
124 logger.warning("IP from WSGI environment (%s) is not equal to IP from X-Real-IP (%s)", remote_addr, real_ip)
125
126 request_ip = forwarded_for or real_ip or remote_addr or '0.0.0.0'
127
128 return request_ip