67 x_forwarded_for: list[IPv4Address | IPv6Address],
68 trusted_proxies: list[IPv4Network | IPv6Network],
71 for addr
in reversed(x_forwarded_for):
74 for net
in trusted_proxies:
75 if addr.version == net.version
and addr
in net:
76 logger.debug(
"trust proxy %s (member of %s)", addr, net)
82 return addr.compressed
85 return x_forwarded_for[0].compressed
87 def __call__(self, environ: WSGIEnvironment, start_response: StartResponse) -> abc.Iterable[bytes]:
96 orig_remote_addr: str |
None = environ.pop(
"REMOTE_ADDR")
103 addr = ip_address(orig_remote_addr)
104 if addr.version == 6
and addr.ipv4_mapped:
105 addr = addr.ipv4_mapped
106 orig_remote_addr = addr.compressed
107 except ValueError
as exc:
108 logger.error(
"REMOTE_ADDR: %s / discard REMOTE_ADDR from WSGI environment", exc)
109 orig_remote_addr =
None
111 x_real_ip: str |
None = environ.get(
"HTTP_X_REAL_IP")
114 addr = ip_address(x_real_ip)
115 if addr.version == 6
and addr.ipv4_mapped:
116 addr = addr.ipv4_mapped
117 x_real_ip = addr.compressed
118 except ValueError
as exc:
119 logger.error(
"X-Real-IP: %s / discard HTTP_X_REAL_IP from WSGI environment", exc)
120 environ.pop(
"HTTP_X_REAL_IP")
123 x_forwarded_for: list[IPv4Address | IPv6Address] = []
124 if environ.get(
"HTTP_X_FORWARDED_FOR"):
125 for x_for_ip
in parse_list_header(str(environ.get(
"HTTP_X_FORWARDED_FOR"))):
127 addr = ip_address(x_for_ip)
128 except ValueError
as exc:
129 logger.error(
"X-Forwarded-For: %s / discard HTTP_X_FORWARDED_FOR from WSGI environment", exc)
130 environ.pop(
"HTTP_X_FORWARDED_FOR")
134 if addr.version == 6
and addr.ipv4_mapped:
135 addr = addr.ipv4_mapped
136 x_forwarded_for.append(addr)
140 if not x_forwarded_for
and not x_real_ip:
141 log_error_only_once(
"X-Forwarded-For nor X-Real-IP header is set!")
143 if x_forwarded_for
and not trusted_proxies:
144 log_error_only_once(
"missing botdetection.trusted_proxies config")
151 environ.update({
"botdetection.trusted_proxies.orig": {
"REMOTE_ADDR": orig_remote_addr}})
159 environ[
"REMOTE_ADDR"] = x_real_ip
161 elif orig_remote_addr:
162 environ[
"REMOTE_ADDR"] = orig_remote_addr
165 logger.error(
"No remote IP could be determined, use black-hole address: 100::")
166 environ[
"REMOTE_ADDR"] =
"100::"
169 _ = ip_address(environ[
"REMOTE_ADDR"])
170 except ValueError
as exc:
171 logger.error(
"REMOTE_ADDR: %s, use black-hole address: 100::", exc)
172 environ[
"REMOTE_ADDR"] =
"100::"
174 logger.debug(
"final REMOTE_ADDR is: %s", environ[
"REMOTE_ADDR"])
175 return self.
wsgi_app(environ, start_response)