o
    ñu]‹  ã                   @   s
  d Z ddlmZ ddlZddlZddlZddlZddlZddl	Zddl
ZddlZej ¡ r4ddlmZ nddlmZ ejj ddd¡ZdZdd	d
„Zdd„ Zdd„ ZG dd„ deƒZG dd„ deƒZG dd„ deƒZdd„ Zdd„ ZG dd„ deƒZe dd„ dD ƒƒZ!dS )aƒ	  
Representation of tor exit policies. These can be easily used to check if
exiting to a destination is permissible or not. For instance...

::

  >>> from stem.exit_policy import ExitPolicy, MicroExitPolicy
  >>> policy = ExitPolicy('accept *:80', 'accept *:443', 'reject *:*')
  >>> print(policy)
  accept *:80, accept *:443, reject *:*
  >>> print(policy.summary())
  accept 80, 443
  >>> policy.can_exit_to('75.119.206.243', 80)
  True

  >>> policy = MicroExitPolicy('accept 80,443')
  >>> print(policy)
  accept 80,443
  >>> policy.can_exit_to('75.119.206.243', 80)
  True

::

  ExitPolicy - Exit policy for a Tor relay
    |- MicroExitPolicy - Microdescriptor exit policy
    |
    |- can_exit_to - check if exiting to this destination is allowed or not
    |- is_exiting_allowed - check if any exiting is allowed
    |- summary - provides a short label, similar to a microdescriptor
    |- has_private - checks if policy has anything expanded from the 'private' keyword
    |- strip_private - provides a copy of the policy without 'private' entries
    |- has_default - checks if policy ends with the defaultly appended suffix
    |- strip_default - provides a copy of the policy without the default suffix
    |- __str__  - string representation
    +- __iter__ - ExitPolicyRule entries that this contains

  ExitPolicyRule - Single rule of an exit policy chain
    |- MicroExitPolicyRule - Single rule for a microdescriptor policy
    |
    |- is_address_wildcard - checks if we'll accept any address
    |- is_port_wildcard - checks if we'll accept any port
    |- get_address_type - provides the protocol our ip address belongs to
    |- is_match - checks if we match a given destination
    |- get_mask - provides the address representation of our mask
    |- get_masked_bits - provides the bit representation of our mask
    |- is_default - flag indicating if this was part of the default end of a policy
    |- is_private - flag indicating if this was expanded from a 'private' keyword
    +- __str__ - string representation for this rule

  get_config_policy - provides the ExitPolicy based on torrc rules

.. data:: AddressType (enum)

  Enumerations for IP address types that can be in an exit policy.

  ============ ===========
  AddressType  Description
  ============ ===========
  **WILDCARD** any address of either IPv4 or IPv6
  **IPv4**     IPv4 address
  **IPv6**     IPv6 address
  ============ ===========
é    )Úabsolute_importN)Ú	lru_cache)ÚWILDCARDZWildcard)ÚIPv4r   )ÚIPv6r   )z	0.0.0.0/8z169.254.0.0/16z127.0.0.0/8z192.168.0.0/16z
10.0.0.0/8z172.16.0.0/12c              	   C   sH  |rt jj |¡st jjj|ddstd| ƒ‚|r3t jjj|ddr3|d dkr/|d dks3d| }t j | ¡r>|  d	¡} g }| D ]]}| ¡ }|sKqBt	 
d
|¡sUd| }d|v r˜| dd¡d }| dd¡d }ttƒ}|ru| |¡ nz| t t ¡ ¡¡ W n   Y |D ]}| td|||f ƒ¡ qˆqB| t|ƒ¡ qBt|Ž S )aÌ  
  Converts an ExitPolicy found in a torrc to a proper exit pattern. This
  accounts for...

  * ports being optional
  * the 'private' keyword

  .. deprecated:: 1.7.0

     Tor's torrc parameters lack a formal spec, making it difficult for this
     method to be reliable. Callers are encouraged to move to
     :func:`~stem.control.Controller.get_exit_policy` instead.

  :param str,list rules: comma separated rules or list to be converted
  :param str ip_address: this relay's IP address for the 'private' policy if
    it's present, this defaults to the local address

  :returns: :class:`~stem.exit_policy.ExitPolicy` reflected by the rules

  :raises: **ValueError** if input isn't a valid tor exit policy
  T©Zallow_bracketsz%s isn't a valid IP addressr   ú[éÿÿÿÿú]ú[%s]ú,z:[\d\-\*]+$z%s:*Zprivateú é   ú:z%s %s:%s)ÚstemÚutilÚ
connectionÚis_valid_ipv4_addressÚis_valid_ipv6_addressÚ
ValueErrorÚ_is_strÚsplitÚstripÚreÚsearchÚrsplitÚlistÚPRIVATE_ADDRESSESÚappendÚsocketZgethostbynameZgethostnameÚExitPolicyRuleÚ
ExitPolicy)ÚrulesZ
ip_addressÚresultÚruleZ
acceptanceÚportZ	addressesZprivate_addr© r&   ú2/usr/lib/python3/dist-packages/stem/exit_policy.pyÚget_config_policyg   s8   $.
ÿr(   c                 C   sR  g }t | ƒD ]$\}}|ttƒ t| ƒkr nd|j| ¡ f }|td kr*| |¡ q|D ]y}|ttƒ }| ||… }t| ƒ|krE| | nd}d}	|d j|d j}
}|d j}t |ƒD ]&\}}d|j| ¡ f }|t| ks|j|
ks|j|ks|j|krƒd}	 nq]|	r¦|D ]}d|_	qˆ|r¦| 
¡ s¦|j|
kr¦|j|kr¦|j|kr¦d|_	q-dS )zÈ
  Determine if part of our policy was expanded from the 'private' keyword. This
  doesn't differentiate if this actually came from the 'private' keyword or a
  series of rules exactly matching it.
  z%s/%sr   NTF)Ú	enumerateÚlenr   ÚaddressÚget_masked_bitsr   Úmin_portÚmax_portÚ	is_acceptÚ_is_privateÚis_address_wildcard)r"   ÚmatchesÚir$   Zrule_strÚstart_indexZ
last_indexZrule_setZ	last_ruleÚis_matchr-   r.   r/   r&   r&   r'   Ú_flag_private_rules¦   s8   
€
*þ*€ár6   c                 C   sJ   t | ƒt tƒkrt| t tƒ d… ƒ}|tkr!|D ]	}d|_qdS dS dS )zN
  Determine if part of our policy ends with the defaultly appended suffix.
  NT)r*   ÚDEFAULT_POLICY_RULESÚtupleÚ_is_default_suffix)r"   Zrules_suffixr$   r&   r&   r'   Ú_flag_default_rulesÚ   s   ûr:   c                   @   s¢   e Zd ZdZdd„ Zeƒ d"dd„ƒZeƒ dd	„ ƒZeƒ d
d„ ƒZdd„ Z	dd„ Z
dd„ Zdd„ Zdd„ Zdd„ Zdd„ Zeƒ dd„ ƒZdd„ Zdd„ Zd d!„ ZdS )#r!   a  
  Policy for the destinations that a relay allows or denies exiting to. This
  is, in effect, just a list of :class:`~stem.exit_policy.ExitPolicyRule`
  entries.

  :param list rules: **str** or :class:`~stem.exit_policy.ExitPolicyRule`
    entries that make up this policy
  c                 G   s˜   |D ]}t j |¡st|tƒstdt|ƒ|f ƒ‚qd}|D ]
}t j |¡s(d}q|r>|r>dd„ |D ƒ}t d 	|¡¡| _
n|| _
d | _d | _d| _d S )NzLExit policy rules can only contain strings or ExitPolicyRules, got a %s (%s)TFc                 S   s   g | ]	}t jj |¡‘qS r&   )r   r   Ú	str_toolsZ	_to_bytes)Ú.0Úrr&   r&   r'   Ú
<listcomp>  s    z'ExitPolicy.__init__.<locals>.<listcomp>ó   ,)r   r   r   Ú
isinstancer    Ú	TypeErrorÚtypeÚzlibÚcompressÚjoinÚ_input_rulesÚ_rulesÚ_hashÚ_is_allowed_default)Úselfr"   r$   Z
is_all_strZ
byte_rulesr&   r&   r'   Ú__init__ñ   s    €€
zExitPolicy.__init__NFc                 C   s8   |   ¡ sdS |  ¡ D ]}| |||¡r|j  S q
| jS )a&  
    Checks if this policy allows exiting to a given destination or not. If the
    address or port is omitted then this will check if we're allowed to exit to
    any instances of the defined address or port.

    :param str address: IPv4 or IPv6 address (with or without brackets)
    :param int port: port number
    :param bool strict: if the address or port is excluded then check if we can
      exit to **all** instances of the defined address or port

    :returns: **True** if exiting to this destination is allowed, **False** otherwise
    F)Úis_exiting_allowedÚ
_get_rulesr5   r/   rI   )rJ   r+   r%   Ústrictr$   r&   r&   r'   Úcan_exit_to  s   
ÿzExitPolicy.can_exit_toc                 C   sx   t ƒ }|  ¡ D ]1}|jr!t|j|jd ƒD ]
}||vr  dS qq| ¡ r8| ¡ r, dS | t|j|jd ƒ¡ q| j	S )z]
    Provides **True** if the policy allows exiting whatsoever, **False**
    otherwise.
    r   TF)
ÚsetrM   r/   Úranger-   r.   r1   Úis_port_wildcardÚupdaterI   )rJ   Zrejected_portsr$   r%   r&   r&   r'   rL   *  s   ÿÿ€zExitPolicy.is_exiting_allowedc           	      C   sX  | j  }|  ¡ D ]}| ¡ r| ¡ r|j } nqg tƒ }}|  ¡ D ]-}| ¡ s*q#| ¡ r0 n!t|j|jd ƒD ]}||v r@q9|j|krJ| 	|¡ | 
|¡ q9q#|r—g g }}| ¡  | 	d¡ |D ]2}|ro|d d |kru| 	|¡ qct|ƒdkr‰| 	d|d |d f ¡ n	| 	t|d ƒ¡ |g}qcn| }dg}|r¡dnd}|d	 |¡  ¡ S )
aB  
    Provides a short description of our policy chain, similar to a
    microdescriptor. This excludes entries that don't cover all IP
    addresses, and is either white-list or blacklist policy based on
    the final entry. For instance...

    ::

      >>> policy = ExitPolicy('accept *:80', 'accept *:443', 'reject *:*')
      >>> policy.summary()
      'accept 80, 443'

      >>> policy = ExitPolicy('accept *:443', 'reject *:1-1024', 'accept *:*')
      >>> policy.summary()
      'reject 1-442, 444-1024'

    :returns: **str** with a concise summary for our policy
    r   Nr	   ú%i-%ir   z1-65535úaccept úreject ú, )rI   rM   r1   rR   r/   rP   rQ   r-   r.   r   ÚaddÚsortr*   ÚstrrE   r   )	rJ   Zis_whitelistr$   Zdisplay_portsZ
skip_portsr%   Zdisplay_rangesZ
temp_rangeZlabel_prefixr&   r&   r'   Úsummary@  sF   €

÷

÷zExitPolicy.summaryc                 C   ó    |   ¡ D ]	}| ¡ r dS qdS )aS  
    Checks if we have any rules expanded from the 'private' keyword. Tor
    appends these by default to the start of the policy and includes a dynamic
    address (the relay's public IP).

    .. versionadded:: 1.3.0

    :returns: **True** if we have any private rules expanded from the 'private'
      keyword, **False** otherwise
    TF)rM   Ú
is_private©rJ   r$   r&   r&   r'   Úhas_private  s
   ÿzExitPolicy.has_privatec                 C   ó   t dd„ |  ¡ D ƒŽ S )z›
    Provides a copy of this policy without 'private' policy entries.

    .. versionadded:: 1.3.0

    :returns: **ExitPolicy** without private rules
    c                 S   ó   g | ]}|  ¡ s|‘qS r&   )r]   ©r<   r$   r&   r&   r'   r>   ª  ó    z,ExitPolicy.strip_private.<locals>.<listcomp>©r!   rM   ©rJ   r&   r&   r'   Ústrip_private¡  ó   	zExitPolicy.strip_privatec                 C   r\   )z¥
    Checks if we have the default policy suffix.

    .. versionadded:: 1.3.0

    :returns: **True** if we have the default policy suffix, **False** otherwise
    TF)rM   Ú
is_defaultr^   r&   r&   r'   Úhas_default¬  s
   	ÿzExitPolicy.has_defaultc                 C   r`   )zœ
    Provides a copy of this policy without the default policy suffix.

    .. versionadded:: 1.3.0

    :returns: **ExitPolicy** without default rules
    c                 S   ra   r&   )rh   rb   r&   r&   r'   r>   Ä  rc   z,ExitPolicy.strip_default.<locals>.<listcomp>rd   re   r&   r&   r'   Ústrip_default»  rg   zExitPolicy.strip_defaultc                 C   s  | j }| jd u r†|d ur†g }d\}}t|tƒr t |¡ d¡}n|}|D ]6}t|tƒr2tjj	 
|¡}tj |¡rC| ¡ s=q$t| ¡ ƒ}|jrId}nd}| |¡ | ¡ rZ| ¡ rZ nq$|rx|d  ¡ rx|d  ¡ rx|rqtdƒg}n|rxtdƒg}t|ƒ t|ƒ || _d | _ | jS )N)TTr?   Fr	   ú
accept *:*z
reject *:*)rF   rG   r@   ÚbytesrC   Ú
decompressr   r   r   r;   Ú_to_unicoder   r   r    r/   r   r1   rR   r6   r:   )rJ   Zinput_rulesr"   Zis_all_acceptZis_all_rejectZdecompressed_rulesr$   r&   r&   r'   rM   Æ  s>   


€
zExitPolicy._get_rulesc                 C   s   t |  ¡ ƒS ©N)r*   rM   re   r&   r&   r'   Ú__len__  ó   zExitPolicy.__len__c                 c   s    |   ¡ D ]}|V  qd S ro   )rM   r^   r&   r&   r'   Ú__iter__  s   €ÿzExitPolicy.__iter__c                 C   s   d  dd„ |  ¡ D ƒ¡S )NrW   c                 S   ó   g | ]}t |ƒ‘qS r&   )rZ   rb   r&   r&   r'   r>     ó    z&ExitPolicy.__str__.<locals>.<listcomp>)rE   rM   re   r&   r&   r'   Ú__str__  s   zExitPolicy.__str__c                 C   s<   | j d u rd}|  ¡ D ]}|d9 }|t|ƒ7 }q|| _ | j S )Nr   é   )rH   rM   Úhash)rJ   Zmy_hashr$   r&   r&   r'   Ú__hash__  s   
zExitPolicy.__hash__c                 C   ó   t |tƒrt| ƒt|ƒkS dS ©NF)r@   r!   rw   ©rJ   Úotherr&   r&   r'   Ú__eq__  ó   zExitPolicy.__eq__c                 C   ó
   | |k S ro   r&   r{   r&   r&   r'   Ú__ne__  ó   
zExitPolicy.__ne__©NNF)Ú__name__Ú
__module__Ú__qualname__Ú__doc__rK   r   rO   rL   r[   r_   rf   ri   rj   rM   rp   rr   ru   rx   r}   r€   r&   r&   r&   r'   r!   ç   s*    	!

N>
r!   c                       s@   e Zd ZdZ‡ fdd„Zdd„ Zdd„ Zdd	„ Zd
d„ Z‡  Z	S )ÚMicroExitPolicya:  
  Exit policy provided by the microdescriptors. This is a distilled version of
  a normal :class:`~stem.exit_policy.ExitPolicy` contains, just consisting of a
  list of ports that are either accepted or rejected. For instance...

  ::

    accept 80,443       # only accepts common http ports
    reject 1-1024       # only accepts non-privileged ports

  Since these policies are a subset of the exit policy information (lacking IP
  ranges) clients can only use them to guess if a relay will accept traffic or
  not. To quote the `dir-spec <https://gitweb.torproject.org/torspec.git/tree/dir-spec.txt>`_ (section 3.2.1)...

  ::

    With microdescriptors, clients don't learn exact exit policies:
    clients can only guess whether a relay accepts their request, try the
    BEGIN request, and might get end-reason-exit-policy if they guessed
    wrong, in which case they'll have to try elsewhere.

  :var bool is_accept: **True** if these are ports that we accept, **False** if
    they're ports that we reject

  :param str policy: policy string that describes this policy
  c                    sú   || _ | d¡rd| _n| d¡rd| _ntd| ƒ‚|dd … }| d¡s-td| j  ƒ‚| ¡ }g }| d	¡D ]5}d
|v rG| d
d¡\}}n| }}tjj 	|¡rYtjj 	|¡s_td| ƒ‚| 
t| jt|ƒt|ƒƒ¡ q8tt| ƒj|Ž  | j | _d S )NÚacceptTÚrejectFzMA microdescriptor exit policy must start with either 'accept' or 'reject': %sé   r   zaA microdescriptor exit policy should have a space separating accept/reject from its port list: %sr   ú-r   z'%s' is an invalid port range)Ú_policyÚ
startswithr/   r   Úlstripr   r   r   r   Úis_valid_portr   ÚMicroExitPolicyRuleÚintÚsuperr‡   rK   rI   )rJ   Zpolicyr"   Z
port_entryr-   r.   ©Ú	__class__r&   r'   rK   >  s,   


ÿzMicroExitPolicy.__init__c                 C   ó   | j S ro   )rŒ   re   r&   r&   r'   ru   h  ó   zMicroExitPolicy.__str__c                 C   s   t t| ƒƒS ro   )rw   rZ   re   r&   r&   r'   rx   k  rq   zMicroExitPolicy.__hash__c                 C   ry   rz   )r@   r‡   rw   r{   r&   r&   r'   r}   n  r~   zMicroExitPolicy.__eq__c                 C   r   ro   r&   r{   r&   r&   r'   r€   q  r   zMicroExitPolicy.__ne__)
rƒ   r„   r…   r†   rK   ru   rx   r}   r€   Ú__classcell__r&   r&   r“   r'   r‡   "  s    *r‡   c                   @   s®   e Zd ZdZdd„ Zdd„ Zdd„ Zd'd
d„Zdd„ Zd(dd„Z	dd„ Z
dd„ Zdd„ Zeƒ dd„ ƒZeƒ dd„ ƒZeƒ dd„ ƒZdd„ Zdd „ Zd!d"„ Zd#d$„ Zd%d&„ ZdS ))r    ao  
  Single rule from the user's exit policy. These rules are chained together to
  form complete policies that describe where a relay will and will not allow
  traffic to exit.

  The format of these rules are formally described in the `dir-spec
  <https://gitweb.torproject.org/torspec.git/tree/dir-spec.txt>`_ as an
  'exitpattern'. Note that while these are similar to tor's man page entry for
  ExitPolicies, it's not the exact same. An exitpattern is better defined and
  stricter in what it'll accept. For instance, ports are not optional and it
  does not contain the 'private' alias.

  This should be treated as an immutable object.

  .. versionchanged:: 1.5.0
     Support for 'accept6/reject6' entries and '\*4/6' wildcards.

  :var bool is_accept: indicates if exiting is allowed or disallowed

  :var str address: address that this rule is for

  :var int min_port: lower end of the port range that we include (inclusive)
  :var int max_port: upper end of the port range that we include (inclusive)

  :param str rule: exit policy rule to be parsed

  :raises: **ValueError** if input isn't a valid tor exit policy rule
  c                 C   s.  t jj |¡}| d¡| _| d¡p| d¡}| d¡s!| d¡r(|dd … }n| d¡s2| d¡r9|dd … }ntd| ƒ‚| d¡sJtd	| ƒ‚| ¡ }d
|vs\d| d
d¡d v rbtd| ƒ‚d | _	d | _
d | _d  | _| _d | _d | _d| _| d
d¡\}}|  |||¡ |  ||¡ d| _d| _d S )Nrˆ   Zaccept6Zreject6é   r‰   rŠ   zDAn exit policy must start with either 'accept[6]' or 'reject[6]': %sr   zYAn exit policy should have a space separating its accept/reject from the exit pattern: %sr   r
   r   z:An exitpattern must be of the form 'addrspec:portspec': %sF)r   r   r;   rn   r   r/   r   rŽ   r   r+   Ú_address_typeÚ_masked_bitsr-   r.   rH   Ú_maskÚ
_skip_ruleÚ_apply_addrspecÚ_apply_portspecr0   r9   )rJ   r$   Úis_ipv6_onlyZexitpatternÚaddrspecÚportspecr&   r&   r'   rK   “  s2   

zExitPolicyRule.__init__c                 C   s   | j ttjƒkS )a  
    **True** if we'll match against **any** address, **False** otherwise.

    Note that this is different than \*4, \*6, or '/0' address which are
    wildcards for only either IPv4 or IPv6.

    :returns: **bool** for if our address matching is a wildcard
    )r™   Ú_address_type_to_intÚAddressTyper   re   r&   r&   r'   r1   É  s   
z"ExitPolicyRule.is_address_wildcardc                 C   s   | j dv o	| jdkS )z‡
    **True** if we'll match against any port, **False** otherwise.

    :returns: **bool** for if our port matching is a wildcard
    )r   r   éÿÿ  )r-   r.   re   r&   r&   r'   rR   Õ  s   zExitPolicyRule.is_port_wildcardNFc                 C   s  | j rdS |dur;|  ¡ }tjj |¡r|tjkrdS ntjjj|ddr5|tj	kr,dS | 
d¡ d¡}ntd| ƒ‚|durLtjj |¡sLtd| ƒ‚d}|  ¡ sn|du rYd}ntjj |¡}||  ¡ M }|  ¡ |krndS |  ¡ s…|du ryd}n|| jk sƒ|| jkr…dS |rŒ|| jkS dS )	af  
    **True** if we match against the given destination, **False** otherwise. If
    the address or port is omitted then this will check if we're allowed to
    exit to any instances of the defined address or port.

    :param str address: IPv4 or IPv6 address (with or without brackets)
    :param int port: port number
    :param bool strict: if the address or port is excluded then check if we can
      exit to **all** instances of the defined address or port

    :returns: **bool** indicating if we match against this destination

    :raises: **ValueError** if provided with a malformed address or port
    FNTr   r   r
   z''%s' isn't a valid IPv4 or IPv6 addressz'%s' isn't a valid port)rœ   Úget_address_typer   r   r   r   r£   r   r   r   rŽ   Úrstripr   r   r1   Úaddress_to_intÚ_get_mask_binÚ_get_address_binrR   r-   r.   r/   )rJ   r+   r%   rN   Úaddress_typeZfuzzy_matchZcomparison_addr_binr&   r&   r'   r5   Þ  s>   
ÿ

zExitPolicyRule.is_matchc                 C   s
   t | jƒS )z¦
    Provides the :data:`~stem.exit_policy.AddressType` for our policy.

    :returns: :data:`~stem.exit_policy.AddressType` for the type of address that we have
    )Ú_int_to_address_typer™   re   r&   r&   r'   r¥   %  s   
zExitPolicyRule.get_address_typeTc                 C   sh   | j s1|  ¡ }|tjkrd}n|tjkrtjj | j	¡}n|tj
kr*tjj | j	¡}|s.|S || _ | j S )zñ
    Provides the address represented by our mask. This is **None** if our
    address type is a wildcard.

    :param bool cache: caches the result if **True**

    :returns: str of our subnet mask for the address (ex. '255.255.255.0')
    N)r›   r¥   r£   r   r   r   r   r   Zget_mask_ipv4rš   r   Zget_mask_ipv6)rJ   Úcacherª   Úmaskr&   r&   r'   Úget_mask.  s   


zExitPolicyRule.get_maskc                 C   r•   )z¾
    Provides the number of bits our subnet mask represents. This is **None** if
    our mask can't have a bit representation.

    :returns: int with the bit representation of our mask
    )rš   re   r&   r&   r'   r,   L  s   zExitPolicyRule.get_masked_bitsc                 C   r•   )zÍ
    Checks if this rule was expanded from the 'private' policy keyword.

    .. versionadded:: 1.3.0

    :returns: **True** if this rule was expanded from the 'private' keyword, **False** otherwise.
    )r0   re   r&   r&   r'   r]   V  ó   	zExitPolicyRule.is_privatec                 C   r•   )zÈ
    Checks if this rule belongs to the default exit policy suffix.

    .. versionadded:: 1.3.0

    :returns: **True** if this rule was part of the default end of a policy, **False** otherwise.
    )r9   re   r&   r&   r'   rh   a  r¯   zExitPolicyRule.is_defaultc                 C   sò   | j rdnd}|  ¡ r|d7 }nD|  ¡ }|tjkr|| j7 }n|d| j 7 }|tjkr0| jdks:|tjkr?| jdkr?|d7 }n| jdurL|d	| j 7 }n|d
|  ¡  7 }|  	¡ r^|d7 }|S | j
| jkrm|t| j
ƒ7 }|S |d| j
| jf 7 }|S )aP  
    Provides the string representation of our policy. This does not
    necessarily match the rule that we were constructed from (due to things
    like IPv6 address collapsing or the multiple representations that our mask
    can have). However, it is a valid that would be accepted by our constructor
    to re-create this rule.
    rU   rV   z*:r   é    é€   r   Nz/%i:z/%s:Ú*rT   )r/   r1   r¥   r£   r   r+   rš   r   r®   rR   r-   r.   rZ   )rJ   Zlabelrª   r&   r&   r'   ru   l  s0   


ÿÿ

ûþzExitPolicyRule.__str__c                 C   s   t tjj |  d¡¡dƒS )NFé   )r‘   r   r   r   Z_address_to_binaryr®   re   r&   r&   r'   r¨   ˜  s   zExitPolicyRule._get_mask_binc                 C   s   t jj | j¡|  ¡ @ S ro   )r   r   r   r§   r+   r¨   re   r&   r&   r'   r©   ž  s   zExitPolicyRule._get_address_binc                 C   sð  |dkrd}n|dks|dkr|rd}d|v r!|  dd¡\| _}n|d | _}|dkr9ttjƒ| _d  | _| _d S tjj	 
| j¡r™|rFd| _ttjƒ| _|d u rUd	| _d S tjj	 
|¡rxztjj	 |¡| _W d S  tyw   || _d | _Y d S w | ¡ r‘t|ƒ| _| jd
k s‹| jd	krtdƒ‚d S td||f ƒ‚| j d¡rð| j d¡rðtjj	 | jdd… ¡rðtjj	 | jdd…  ¡ ¡| _ttjƒ| _|d u rÏd| _d S | ¡ rèt|ƒ| _| jd
k sâ| jdkrætdƒ‚d S td||f ƒ‚td||f ƒ‚)Nz*4z	0.0.0.0/0z*6r²   z+[0000:0000:0000:0000:0000:0000:0000:0000]/0ú/r   Tr°   r   z,IPv4 masks must be in the range of 0-32 bitsz,The '%s' isn't a mask nor number of bits: %sr   r
   r	   r±   z-IPv6 masks must be in the range of 0-128 bitsz#The '%s' isn't a number of bits: %sz0'%s' isn't a wildcard, IPv4, or IPv6 address: %s)r   r+   r¢   r£   r   r™   rš   r   r   r   r   rœ   r   Z_get_masked_bitsr   r›   Úisdigitr‘   r   Úendswithr   Zexpand_ipv6_addressÚupperr   )rJ   r$   r    rŸ   Z
addr_extrar&   r&   r'   r   ¤  sV   
ý
ÿÿ

ÿzExitPolicyRule._apply_addrspecc                 C   sÌ   |dkrd\| _ | _d S | ¡ r+tjjj|ddr#t|ƒ | _ | _d S td||f ƒ‚d|v r`| 	dd¡}tjjj|ddrZt|d ƒ| _ t|d ƒ| _| j | jkrXtd	| ƒ‚d S td
| ƒ‚td| ƒ‚)Nr²   )r   r¤   T)Z
allow_zeroz('%s' isn't within a valid port range: %sr‹   r   r   zDPort range has a lower bound that's greater than its upper bound: %szMalformed port range: %sz2Port value isn't a wildcard, integer, or range: %s)
r-   r.   rµ   r   r   r   r   r‘   r   r   )rJ   r$   r¡   Z	port_compr&   r&   r'   rž   ë  s    ÿzExitPolicyRule._apply_portspecc                 C   s8   | j d u rtj | dddd¡d t|  d¡ƒ | _ | j S )Nr/   r+   r-   r.   rv   F)rH   r   r   Ú
_hash_attrrw   r®   re   r&   r&   r'   rx   
  s   
(zExitPolicyRule.__hash__c                 C   ry   rz   )r@   r    rw   r{   r&   r&   r'   r}     r~   zExitPolicyRule.__eq__c                 C   r   ro   r&   r{   r&   r&   r'   r€     r   zExitPolicyRule.__ne__r‚   ©T)rƒ   r„   r…   r†   rK   r1   rR   r5   r¥   r®   r,   r]   rh   r   ru   r¨   r©   r   rž   rx   r}   r€   r&   r&   r&   r'   r    u  s,    6
	G
	

+

Gr    c                 C   s
   t  | ¡S ro   )r£   Zindex_of)rª   r&   r&   r'   r¢     r   r¢   c                 C   s   t tƒ|  S ro   )r   r£   )Zaddress_type_intr&   r&   r'   r«     rq   r«   c                   @   sR   e Zd ZdZdd„ Zdd„ Zdd„ Zdd	d
„Zdd„ Zdd„ Z	dd„ Z
dd„ ZdS )r   zD
  Lighter weight ExitPolicyRule derivative for microdescriptors.
  c                 C   s"   || _ d | _|| _|| _d| _d S rz   )r/   r+   r-   r.   rœ   )rJ   r/   r-   r.   r&   r&   r'   rK   $  s
   
zMicroExitPolicyRule.__init__c                 C   s   dS )NTr&   re   r&   r&   r'   r1   +  ó   z'MicroExitPolicyRule.is_address_wildcardc                 C   s   t jS ro   )r£   r   re   r&   r&   r'   r¥   .  r–   z$MicroExitPolicyRule.get_address_typeTc                 C   ó   d S ro   r&   )rJ   r¬   r&   r&   r'   r®   1  rº   zMicroExitPolicyRule.get_maskc                 C   r»   ro   r&   re   r&   r&   r'   r,   4  rº   z#MicroExitPolicyRule.get_masked_bitsc                 C   s   t jj| dddddS )Nr/   r-   r.   T)r¬   )r   r   r¸   re   r&   r&   r'   rx   7  s   zMicroExitPolicyRule.__hash__c                 C   ry   rz   )r@   r   rw   r{   r&   r&   r'   r}   :  r~   zMicroExitPolicyRule.__eq__c                 C   r   ro   r&   r{   r&   r&   r'   r€   =  r   zMicroExitPolicyRule.__ne__Nr¹   )rƒ   r„   r…   r†   rK   r1   r¥   r®   r,   rx   r}   r€   r&   r&   r&   r'   r     s    
r   c                 C   rs   r&   )r    rb   r&   r&   r'   r>   A  rt   r>   )zreject *:25zreject *:119zreject *:135-139zreject *:445zreject *:563zreject *:1214zreject *:4661-4666zreject *:6346-6429zreject *:6699zreject *:6881-6999rk   ro   )"r†   Z
__future__r   r   r   rC   Zstem.prereqr   Z	stem.utilZstem.util.connectionZstem.util.enumZstem.util.str_toolsZprereqZ_is_lru_cache_availableÚ	functoolsr   Zstem.util.lru_cacher   ÚenumÚEnumr£   r   r(   r6   r:   Úobjectr!   r‡   r    r¢   r«   r   r8   r7   r&   r&   r&   r'   Ú<module>   s<   @


?4  =S   %"