Ë
    tPêj!:  ã                   ó2  — U d Z ddlZddlmZ ddlmZmZ ddlmZ ddl	m
Z
mZ ddlmZ ddlmZ d	ad	a e
e«      Zeed
<    edd¬«       G d„ d«      «       Z edd¬«       G d„ d«      «       Z edd¬«       G d„ d«      «       Zeez  ez  Z G d„ d«      Zy)zÉ
IP address utilities for MCP public/private access control.

Internal callers (private IPs) see all MCP servers.
External callers (public IPs) only see servers with available_on_public_internet=True.
é    N)Ú	dataclass)ÚAnyÚFinal)ÚRequest)ÚTypeAdapterÚValidationError)Úverbose_proxy_logger)Ú_get_request_ip_addressFÚ_NUM_TRUSTED_HOPS_ADAPTERT)ÚfrozenÚslotsc                   ó   — e Zd ZdZy)Ú_HopCountUnsetzFmcp_xff_num_trusted_hops is absent: keep the legacy leftmost-XFF path.N©Ú__name__Ú
__module__Ú__qualname__Ú__doc__© ó    úh/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/auth/ip_address_utils.pyr   r   !   s   „ âPr   r   c                   ó   — e Zd ZdZy)Ú_HopCountInvalidzLmcp_xff_num_trusted_hops is present but unusable: fail closed, never legacy.Nr   r   r   r   r   r   &   s   „ âVr   r   c                   ó   — e Zd ZU eed<   y)Ú	_HopCountÚvalueN)r   r   r   ÚintÚ__annotations__r   r   r   r   r   +   s   … à„Jr   r   c            	       óö  — e Zd ZdZ ej
                  d«       ej
                  d«       ej
                  d«       ej
                  d«       ej
                  d«       ej
                  d«      gZedee	   d	z  d
eej                  ej                  z     fd„«       Zedee	   d	z  d
eej                  ej                  z     fd„«       Zede	d	z  deej                  ej                  z     d
efd„«       Ze	 dde	d	z  deej                  ej                  z     d	z  d
efd„«       Ze	 ddedee	ef   d	z  d
efd„«       Zede	ded
e	d	z  fd„«       Zeded
efd„«       Ze	 ddedee	ef   d	z  d
e	d	z  fd„«       Zy	)ÚIPAddressUtilsz1Static utilities for IP-based MCP access control.z
10.0.0.0/8z172.16.0.0/12z192.168.0.0/16z127.0.0.0/8z::1/128zfc00::/7Úconfigured_rangesNÚreturnc                 óø   — | st         j                  S g }| D ])  }	 |j                  t        j                  |d¬«      «       Œ+ |r|S t         j                  S # t
        $ r t        j                  d|«       Y Œaw xY w)zLParse configured CIDR ranges into network objects, falling back to defaults.F©Ústrictz4Invalid CIDR in mcp_internal_ip_ranges: %s, skipping)r    Ú_DEFAULT_INTERNAL_NETWORKSÚappendÚ	ipaddressÚ
ip_networkÚ
ValueErrorr	   Úwarning©r!   ÚnetworksÚcidrs      r   Úparse_internal_networksz&IPAddressUtils.parse_internal_networks?   s‚   € ñ
 !Ü!×<Ñ<Ð<ØOQˆØ%ò 	kˆDðkØ—‘¤	× 4Ñ 4°TÀ%Ô HÕIð	kñ
 $ˆxÐR¬×)RÑ)RÐRøô ò kÜ$×,Ñ,Ð-cÐeiÖjðkús   ›&AÁA9Á8A9c                 ó¸   — | sg S g }| D ])  }	 |j                  t        j                  |d¬«      «       Œ+ |S # t        $ r t	        j
                  d|«       Y ŒOw xY w)z�
        Parse trusted proxy CIDR ranges for XFF validation.
        Returns empty list if not configured (XFF will not be trusted).
        Fr$   z6Invalid CIDR in mcp_trusted_proxy_ranges: %s, skipping)r'   r(   r)   r*   r	   r+   r,   s      r   Úparse_trusted_proxy_networksz+IPAddressUtils.parse_trusted_proxy_networksN   sm   € ñ !ØˆIØOQˆØ%ò 	mˆDðmØ—‘¤	× 4Ñ 4°TÀ%Ô HÕIð	mð
 ˆøô ò mÜ$×,Ñ,Ð-eÐgkÖlðmús   �&7·AÁAÚproxy_ipÚtrusted_networksc                 óœ   ‡— | r|sy	 t        j                  | j                  «       «      Št        ˆfd„|D «       «      S # t        $ r Y yw xY w)z:Check if the direct connection IP is from a trusted proxy.Fc              3   ó&   •K  — | ]  }‰|v –— Œ
 y ­w©Nr   ©Ú.0ÚnetworkÚaddrs     €r   ú	<genexpr>z2IPAddressUtils.is_trusted_proxy.<locals>.<genexpr>j   s   øè ø€ ÒG¨7�t˜w”ÑGùó   ƒ)r(   Ú
ip_addressÚstripÚanyr*   )r2   r3   r:   s     @r   Úis_trusted_proxyzIPAddressUtils.is_trusted_proxy`   sN   ø€ ñ Ñ/Øð	Ü#×.Ñ.¨x¯~©~Ó/?Ó@ˆDÜÓGÐ6FÔGÓGÐGøÜò 	Ùð	ús   ˆ6? ¿	AÁ
AÚ	client_ipÚinternal_networksc                 ó  ‡— | syd| v r"| j                  d«      d   j                  «       } |xs t        j                  }	 t	        j
                  | j                  «       «      Št        ˆfd„|D «       «      S # t        $ r Y yw xY w)zÞ
        Check if a client IP is from an internal/private network.

        Handles X-Forwarded-For comma chains (takes leftmost = original client).
        Fails closed: empty/invalid IPs are treated as external.
        Fú,r   c              3   ó&   •K  — | ]  }‰|v –— Œ
 y ­wr6   r   r7   s     €r   r;   z0IPAddressUtils.is_internal_ip.<locals>.<genexpr>‡   s   øè ø€ Ò; w�4˜7”?Ñ;ùr<   )Úsplitr>   r    r&   r(   r=   r*   r?   )rA   rB   r-   r:   s      @r   Úis_internal_ipzIPAddressUtils.is_internal_ipn   s„   ø€ ñ Øð �)ÑØ!Ÿ™¨Ó,¨QÑ/×5Ñ5Ó7ˆIà+ÒX¬~×/XÑ/Xˆð	Ü#×.Ñ.¨y¯©Ó/@ÓAˆDô Ó;°(Ô;Ó;Ð;øô ò 	Ùð	ús   Á #A7 Á7	BÂBÚrequestÚgeneral_settingsc                 óh  — |€		 ddl m} |}|€i }|j                  dd«      sy|j                  d«      }|st        st        j                  d«       day| j                  r| j                  j                  nd}t        j                  |«      }t        j                  ||«      S # t        $ r i }Y Œ¤w xY w)	aï  
        Return True if X-Forwarded-* headers on this request should be trusted.

        Trusts the headers iff both:
          1. ``use_x_forwarded_for`` is enabled in proxy settings, AND
          2. ``mcp_trusted_proxy_ranges`` is configured AND the direct
             connection IP (``request.client.host``) falls inside one of
             those CIDRs.

        When ``use_x_forwarded_for`` is enabled but ``mcp_trusted_proxy_ranges``
        is missing, the headers are NOT trusted: there is no way to
        distinguish a trusted reverse proxy from a direct attacker, so callers
        that build URLs (OAuth issuer / redirect_uri / etc.) must fall back
        to the request's literal base URL instead of risking a poisoned host.
        Nr   ©rI   Úuse_x_forwarded_forFÚmcp_trusted_proxy_rangesa†  use_x_forwarded_for is enabled but mcp_trusted_proxy_ranges is not configured, so X-Forwarded-* headers will NOT be trusted. MCP OAuth discovery URLs fall back to the proxy's literal request URL, and MCP access-control client-IP resolution fails closed (callers are treated as external). Set mcp_trusted_proxy_ranges in general_settings to your reverse-proxy CIDR(s) to trust X-Forwarded-*.T)Úlitellm.proxy.proxy_serverrI   ÚImportErrorÚgetÚ"_warned_xff_without_trusted_rangesr	   r+   ÚclientÚhostr    r1   r@   )rH   rI   Úproxy_general_settingsÚtrusted_rangesÚ	direct_ipr3   s         r   Úis_request_from_trusted_proxyz,IPAddressUtils.is_request_from_trusted_proxy‰   sÆ   € ð( Ð#ð&õð $:Ð ð Ð#Ø!Ðà×#Ñ#Ð$9¸5ÔAØà 0× 4Ñ 4Ð5OÓ PˆÙå5Ü$×,Ñ,ð%ôð 6:Ð2Øà29·.².˜7Ÿ>™>×.Ò.Àdˆ	Ü"0×"MÑ"MÈnÓ"]ÐÜ×.Ñ.¨yÐ:JÓKÐKøô7 ò &Ø#%Ò ð&ús   „B# Â#B1Â0B1Ú
xff_headerÚnum_trusted_hopsc                 óÆ   — t        d„ | j                  d«      D «       «      }|dk  st        |«      |k  ry||    }	 t        j                  |«       |S # t
        $ r Y yw xY w)aç  
        Resolve the originating client IP from an X-Forwarded-For chain by
        counting ``num_trusted_hops`` entries from the right.

        Each trusted proxy appends the address it received the connection from,
        so the right end of the chain is written by infrastructure while the
        left end is attacker-controllable. Selecting the Nth entry from the
        right, where N is the number of trusted appending proxies in front of
        the gateway, yields the real client IP and discards any values a client
        prepended to spoof an allowed address.

        Returns None when the chain has fewer than ``num_trusted_hops`` entries
        or the selected entry is not a valid IP, so callers can fail closed.
        c              3   ó^   K  — | ]%  }|j                  «       sŒ|j                  «       –— Œ' y ­wr6   )r>   )r8   Úparts     r   r;   zAIPAddressUtils.extract_client_ip_from_xff_hops.<locals>.<genexpr>Ô   s"   è ø€ Ò^°ÐQU×Q[ÑQ[ÕQ]˜tŸz™zŸ|Ñ^ùs   ‚-˜-rD   é   N)ÚtuplerF   Úlenr(   r=   r*   )rX   rY   ÚentriesÚ	candidates       r   Úextract_client_ip_from_xff_hopsz.IPAddressUtils.extract_client_ip_from_xff_hopsÁ   ss   € ô& Ñ^¸
×8HÑ8HÈÓ8MÔ^Ó^ˆØ˜aÒ¤3 w£<Ð2BÒ#BØØ"Ð$4Ð#4Ñ5ˆ	ð	Ü× Ñ  Ô+ð Ðøô ò 	Ùð	ús   ½A Á	A ÁA Úraw_num_trusted_hopsc                 ó  — | €
t        «       S 	 t        j                  | «      }|dk  r t	        j
                  d|«       t        «       S t        |«      S # t        $ r# t	        j
                  d| «       t        «       cY S w xY w)Nz¶Invalid mcp_xff_num_trusted_hops value %r; failing closed for MCP client IP resolution. Set it to a positive integer, or remove the setting to restore the legacy X-Forwarded-For pathr]   zÂmcp_xff_num_trusted_hops=%s is below the minimum of 1; failing closed for MCP client IP resolution. Set it to a positive integer, or remove the setting to restore the legacy X-Forwarded-For path)r   r   Úvalidate_pythonr   r	   r+   r   r   )rc   Únum_hopss     r   Ú_resolve_num_trusted_hopsz(IPAddressUtils._resolve_num_trusted_hopsÞ   s“   € àÐ'Ü!Ó#Ð#ð		&Ü7×GÑGÐH\Ó]ˆHð �aŠ<Ü ×(Ñ(ð'ð ôô $Ó%Ð%Ü˜Ó"Ð"øô# ò 	&Ü ×(Ñ(ðPð %ô	ô $Ó%Ò%ð	&ús   ŽA Á)A?Á>A?c                 óä  — |€		 ddl m} |}|€i }|j                  dd«      }|rdan+d| j
                  v rt        st        j                  d«       da|rÿd| j
                  v rñt        j                  | |¬«      sN| j                  r| j                  j                  nd}|j                  d	«      rt        j                  d
|«       |S yt        j                  |j                  d«      «      xt        d˜ x�\    y xt        d˜ x�B\  } t        j!                  | j
                  d   |«      }|€t        j                  d|«       y|S  t"        d˜ x�\   n t%        | |¬«      S # t        $ r i }Y �Œbw xY w)aV  
        Extract client IP from a FastAPI request for MCP access control.

        Security: Only trusts X-Forwarded-For if:
        1. use_x_forwarded_for is enabled in settings
        2. The direct connection is from a trusted proxy (if mcp_trusted_proxy_ranges configured)

        When ``mcp_xff_num_trusted_hops`` is set, the client IP is read that many
        entries from the right of the chain instead of the spoofable leftmost
        value, defeating append-style X-Forwarded-For forgery. A present-but-invalid
        value (non-integer or below 1) fails closed rather than silently reverting
        to the legacy path, so a config typo cannot quietly weaken access control.

        Args:
            request: FastAPI request object
            general_settings: Optional settings dict. If not provided, imports from proxy_server.
        Nr   rK   rL   Fzx-forwarded-fora¼  Received a request with an X-Forwarded-For header but use_x_forwarded_for is not enabled. The real client IP is being ignored and the direct peer's IP (typically your load balancer / reverse proxy) is used for MCP access control. Because that peer almost always falls within general_settings.mcp_internal_ip_ranges, every external caller is treated as internal and 'available_on_public_internet: false' MCP servers are effectively exposed. Set use_x_forwarded_for: true (and mcp_trusted_proxy_ranges to your proxy CIDRs) in general_settings to honor the real client IP. Not failing the request: if there is no load balancer, a crafted X-Forwarded-For header must not be able to take down the service.TrM   z)XFF header from untrusted IP %s, ignoringÚ Úmcp_xff_num_trusted_hopsr   )r   znX-Forwarded-For chain has fewer than mcp_xff_num_trusted_hops=%s entries or an invalid address; failing closed)rL   )rN   rI   rO   rP   Ú _warned_xff_present_but_disabledÚheadersr	   Úerrorr    rW   rR   rS   r+   rg   r   r   rb   r   r
   )rH   rI   rT   Úuse_xffrV   rY   rA   s          r   Úget_mcp_client_ipz IPAddressUtils.get_mcp_client_ip÷   s“  € ð, Ð#ð&õð $:Ð ð
 Ð#Ø!Ðà)×-Ñ-Ð.CÀUÓKˆñ Ø/4Ñ,Ø '§/¡/Ñ1Ý3Ü$×*Ñ*ð0ôð 48Ð0ñ Ð(¨G¯O©OÑ;Ü!×?Ñ?ÀÐZjÐ?ÔkØ:A¿.º. 7§>¡>×#6Ò#6Èd�	Ø#×'Ñ'Ð(BÔCä(×0Ñ0Ð1\Ð^gÔhØ$Ð$ð
 Ü ×:Ñ:Ð;K×;OÑ;OÐPjÓ;kÓlØ'Ô%Ö'Øð (à6”Y×6Ü'5×'UÑ'UØŸ™Ð(9Ñ:Ð<Ló(�Ið !Ð(Ü,×4Ñ4ð6ð -ô	ð  "Ø$Ð$ð 7ô $Õ%Øð &ä& wÀGÔLÐLøô} ò &Ø#%Ó ð&ús   „E  Å E/Å.E/r6   )r   r   r   r   r(   r)   r&   ÚstaticmethodÚlistÚstrÚIPv4NetworkÚIPv6Networkr/   r1   Úboolr@   rG   r   Údictr   rW   r   rb   ÚobjectÚ_HopCountSettingrg   ro   r   r   r   r    r    3   s€  „ Ù;ð 	ˆ	×Ñ˜\Ó*Øˆ	×Ñ˜_Ó-Øˆ	×ÑÐ-Ó.Øˆ	×Ñ˜]Ó+Øˆ	×Ñ˜YÓ'Øˆ	×Ñ˜ZÓ(ð"Ðð ðSØ ™9 tÑ+ðSà	ˆi×#Ñ# i×&;Ñ&;Ñ;Ñ	<òSó ðSð ðØ ™9 tÑ+ðà	ˆi×#Ñ# i×&;Ñ&;Ñ;Ñ	<òó ðð" ðØ˜‘*ðà˜y×4Ñ4°y×7LÑ7LÑLÑMðð 
òó ðð ð Y]ñ<Ø˜‘:ð<à 	× 5Ñ 5¸	×8MÑ8MÑ MÑNÐQUÑUð<ð 
ò<ó ð<ð4 ð 37ñ5LØð5Là˜s C˜x™.¨4Ñ/ð5Lð 
ò5Ló ð5Lðn ðØðàðð 
ˆt‰òó ðð8 ð#¸ð #ÐCSò #ó ð#ð0 ð 37ñZMØðZMà˜s C˜x™.¨4Ñ/ðZMð 
ˆt‰òZMó ñZMr   r    )r   r(   Údataclassesr   Útypingr   r   Úfastapir   Úpydanticr   r   Úlitellm._loggingr	   Úlitellm.proxy.auth.auth_utilsr
   rQ   rk   r   r   r   r   r   r   rx   r    r   r   r   ú<module>r      sÈ   ðòó Ý !ß å ß 1å 1Ý Að &+Ð "ð $)Ð  á#.¨sÓ#3Ð ˜5Ó 3ñ �$˜dÔ#÷Qð Qó $ðQñ �$˜dÔ#÷Wð Wó $ðWñ �$˜dÔ#÷ð ó $ðð "Ð$4Ñ4°yÑ@Ð ÷_Mò _Mr   