36 lines
964 B
Python
36 lines
964 B
Python
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from ipaddress import ip_address, ip_network
|
||
|
|
|
||
|
|
from fastapi import Request
|
||
|
|
|
||
|
|
from app.config import Settings
|
||
|
|
|
||
|
|
|
||
|
|
def is_ip_in_network(candidate_ip: str, network_value: str) -> bool:
|
||
|
|
return ip_address(candidate_ip) in ip_network(network_value, strict=False)
|
||
|
|
|
||
|
|
|
||
|
|
def is_trusted_proxy(source_ip: str, settings: Settings) -> bool:
|
||
|
|
try:
|
||
|
|
parsed_ip = ip_address(source_ip)
|
||
|
|
except ValueError:
|
||
|
|
return False
|
||
|
|
return any(parsed_ip in network for network in settings.trusted_proxy_networks)
|
||
|
|
|
||
|
|
|
||
|
|
def extract_client_ip(request: Request, settings: Settings) -> str:
|
||
|
|
client_host = request.client.host if request.client else "127.0.0.1"
|
||
|
|
if not is_trusted_proxy(client_host, settings):
|
||
|
|
return client_host
|
||
|
|
|
||
|
|
real_ip = request.headers.get("x-real-ip")
|
||
|
|
if not real_ip:
|
||
|
|
return client_host
|
||
|
|
|
||
|
|
try:
|
||
|
|
ip_address(real_ip)
|
||
|
|
except ValueError:
|
||
|
|
return client_host
|
||
|
|
return real_ip
|