U
    Â“«jˆ0  ã                   @   st   d Z ddlmZ ddlmZmZmZ ddlmZ G dd„ dƒZ	G dd„ dej
ƒZd	d
„ ZG dd„ dƒZddd„ZdS )zÁ
Resolver implementation for querying successive authoritative servers to
lookup a record, starting from the root nameservers.

@author: Jp Calderone

todo::
    robustify it
    documentation
é    )Údefer)ÚcommonÚdnsÚerror)ÚFailurec                   @   s   e Zd ZdZdd„ ZdS )Ú_DummyControllerz²
    A do-nothing DNS controller.  This is useful when all messages received
    will be responses to previously issued queries.  Anything else received
    will be ignored.
    c                 G   s   d S ©N© )ÚselfÚargsr	   r	   ú6/tmp/pip-unpacked-wheel-59kc99xd/twisted/names/root.pyÚmessageReceived   s    z _DummyController.messageReceivedN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r	   r	   r	   r   r      s   r   c                   @   sB   e Zd ZdZddd„Zdd„ Zdd	„ Zd
d„ Zdd„ Zdd„ Z	dS )ÚResolverao  
    L{Resolver} implements recursive lookup starting from a specified list of
    root servers.

    @ivar hints: See C{hints} parameter of L{__init__}
    @ivar _maximumQueries: See C{maximumQueries} parameter of L{__init__}
    @ivar _reactor: See C{reactor} parameter of L{__init__}
    @ivar _resolverFactory: See C{resolverFactory} parameter of L{__init__}
    é
   Nc                 C   s<   t j | ¡ || _|| _|| _|dkr2ddlm} || _dS )a‡  
        @param hints: A L{list} of L{str} giving the dotted quad
            representation of IP addresses of root servers at which to
            begin resolving names.
        @type hints: L{list} of L{str}

        @param maximumQueries: An optional L{int} giving the maximum
             number of queries which will be attempted to resolve a
             single name.
        @type maximumQueries: L{int}

        @param reactor: An optional L{IReactorTime} and L{IReactorUDP}
             provider to use to bind UDP ports and manage timeouts.
        @type reactor: L{IReactorTime} and L{IReactorUDP} provider

        @param resolverFactory: An optional callable which accepts C{reactor}
             and C{servers} arguments and returns an instance that provides a
             C{queryUDP} method. Defaults to L{twisted.names.client.Resolver}.
        @type resolverFactory: callable
        Nr   ©r   )	r   ÚResolverBaseÚ__init__ÚhintsÚ_maximumQueriesÚ_reactorZtwisted.names.clientr   Ú_resolverFactory)r
   r   ZmaximumQueriesÚreactorÚresolverFactoryr	   r	   r   r   +   s    zResolver.__init__c                 C   s   dd„ | j D ƒS )z‚
        Return a list of two-tuples representing the addresses of the root
        servers, as defined by C{self.hints}.
        c                 S   s   g | ]}|t jf‘qS r	   )r   ÚPORT)Ú.0Úipr	   r	   r   Ú
<listcomp>M   s     z#Resolver._roots.<locals>.<listcomp>)r   )r
   r	   r	   r   Ú_rootsH   s    zResolver._rootsc                 C   s2   | j || jd�}| |g|¡}|r.| |j¡ |S )a­  
        Issue one query and return a L{Deferred} which fires with its response.

        @param query: The query to issue.
        @type query: L{dns.Query}

        @param servers: The servers which might have an answer for this
            query.
        @type servers: L{list} of L{tuple} of L{str} and L{int}

        @param timeout: A timeout on how long to wait for the response.
        @type timeout: L{tuple} of L{int}

        @param filter: A flag indicating whether to filter the results.  If
            C{True}, the returned L{Deferred} will fire with a three-tuple of
            lists of L{twisted.names.dns.RRHeader} (like the return value of
            the I{lookup*} methods of L{IResolver}.  IF C{False}, the result
            will be a L{Message} instance.
        @type filter: L{bool}

        @return: A L{Deferred} which fires with the response or a timeout
            error.
        @rtype: L{Deferred}
        )Úserversr   )r   r   ZqueryUDPÚaddCallbackZfilterAnswers)r
   Úqueryr"   ÚtimeoutÚfilterÚrÚdr	   r	   r   Ú_queryO   s
    zResolver._queryc                 C   s,   |dkrd}|   t |||¡|  ¡ || j¡S )z½
        Implement name lookup by recursively discovering the authoritative
        server for the name and then asking it, starting at one of the servers
        in C{self.hints}.
        N)é   é   é   é-   )Ú_discoverAuthorityr   ÚQueryr!   r   )r
   ÚnameÚclsÚtyper%   r	   r	   r   Ú_lookupn   s       ÿzResolver._lookupc                 C   s@   |dkrt t d¡ƒS |  |||d¡}| | j|||d ¡ |S )a#  
        Issue a query to a server and follow a delegation if necessary.

        @param query: The query to issue.
        @type query: L{dns.Query}

        @param servers: The servers which might have an answer for this
            query.
        @type servers: L{list} of L{tuple} of L{str} and L{int}

        @param timeout: A C{tuple} of C{int} giving the timeout to use for this
            query.

        @param queriesLeft: A C{int} giving the number of queries which may
            yet be attempted to answer this query before the attempt will be
            abandoned.

        @return: A L{Deferred} which fires with a three-tuple of lists of
            L{twisted.names.dns.RRHeader} giving the response, or with a
            L{Failure} if there is a timeout or response error.
        r   z"Query limit reached without resultFr*   )r   r   ÚResolverErrorr)   r#   Ú_discoveredAuthority)r
   r$   r"   r%   ÚqueriesLeftr(   r	   r	   r   r.   |   s
    zResolver._discoverAuthorityc                    s  |j tjkr tˆ |j ¡|ƒƒS i ‰|jD ]}ˆ |jg ¡ |¡ q*‡fdd„}t	ƒ }ˆj}d}	| 
|¡ |	‰ ||ˆjˆjƒ}	|	dkrØ|ˆjkr–�qn@ˆ t t|ƒˆjˆj¡ˆ ¡ ˆˆ¡}
‡ fdd„}|
 |¡ |
S q`|	jˆjkrô|j|j|jfS |	jj|k�rt d¡‚|	jj}q`i }|jD ]&}|jtjk�r |j ¡ ||jj< �q g }g }|jD ]H}|jtjk�rV|jjj}||k�r’| || tjf¡ n
| |¡ �qV|�r¶ˆ ˆ|ˆˆ¡S |�rúˆ |d ˆ¡}
dd	„ }|
 |¡ |
 ‡‡‡‡fd
d„¡ |
S tt d¡ƒS dS )as  
        Interpret the response to a query, checking for error codes and
        following delegations if necessary.

        @param response: The L{Message} received in response to issuing C{query}.
        @type response: L{Message}

        @param query: The L{dns.Query} which was issued.
        @type query: L{dns.Query}.

        @param timeout: The timeout to use if another query is indicated by
            this response.
        @type timeout: L{tuple} of L{int}

        @param queriesLeft: A C{int} giving the number of queries which may
            yet be attempted to answer this query before the attempt will be
            abandoned.

        @return: A L{Failure} indicating a response error, a three-tuple of
            lists of L{twisted.names.dns.RRHeader} giving the response to
            C{query} or a L{Deferred} which will fire with one of those.
        c                    sF   d }ˆ   | g ¡D ]0}|j|kr|j|kr0|  S |jtjkr|}q|S r   )Úgetr1   r2   r   ZCNAME)r0   r2   r1   ÚcnameÚrecord)Úrecordsr	   r   ÚfindAnswerOrCName¹   s    

z8Resolver._discoveredAuthority.<locals>.findAnswerOrCNameNc                    s    | \}}}|  dˆ ¡ |||fS ©Nr   )Úinsert©ÚresultsÚanswersÚ	authorityÚ
additional)Úpreviousr	   r   Ú
cbResolvedÜ   s    
z1Resolver._discoveredAuthority.<locals>.cbResolvedzCycle in CNAME processingr   c                 S   s   | \}}}|d j  ¡ S r<   )ÚpayloadÚ
dottedQuadr>   r	   r	   r   ÚgetOneAddress   s    
z4Resolver._discoveredAuthority.<locals>.getOneAddressc                    s   ˆ  ˆ| tjfgˆˆ d ¡S )Nr*   )r.   r   r   )Úhint)r6   r$   r
   r%   r	   r   Ú<lambda>  s
    
  ÿz/Resolver._discoveredAuthority.<locals>.<lambda>z/Stuck at response without answers or delegation)ZrCoder   ÚOKr   ZexceptionForCoder@   Ú
setdefaultr0   ÚappendÚsetÚaddr2   r1   r.   r/   Ústrr!   r#   rA   rB   rE   r   r4   ÚArF   ZNSr   ZlookupAddress)r
   Úresponser$   r%   r6   Zanswerr;   Úseenr0   r9   r(   rD   Ú	addressesÚrrr   ZtrapsÚnsrG   r	   )rC   r6   r$   r:   r
   r%   r   r5   š   sl    


ü	







ÿÿzResolver._discoveredAuthority)r   NN)
r   r   r   r   r   r!   r)   r3   r.   r5   r	   r	   r	   r   r       s   

r   c                    s   ‡ ‡fdd„}|S )Nc                     s   ˆ  ‡ ‡‡fdd„¡ ˆS )Nc                    s   t | ˆƒˆ ˆŽS r   )Úgetattr)r'   )r   Úkwr0   r	   r   rI     ó    z6makePlaceholder.<locals>.placeholder.<locals>.<lambda>)r#   ©r   rW   ©Údeferredr0   rY   r   Úplaceholder  s    z$makePlaceholder.<locals>.placeholderr	   )r[   r0   r\   r	   rZ   r   ÚmakePlaceholder  s    r]   c                   @   s$   e Zd Zdd„ Zdd„ Zdd„ ZdS )ÚDeferredResolverc                 C   s   g | _ | | j¡ d S r   )Úwaitingr#   ÚgotRealResolver)r
   ZresolverDeferredr	   r	   r   r     s    zDeferredResolver.__init__c                 C   s.   | j }|j| _|j| _|D ]}| |¡ qd S r   )r_   Ú__dict__Ú	__class__Úcallback)r
   ÚresolverÚwr(   r	   r	   r   r`     s
    z DeferredResolver.gotRealResolverc                 C   s>   |  d¡s|dkr2| j t ¡ ¡ t| jd |ƒS t|ƒ‚d S )NÚlookup)ÚgetHostByNamer$   éÿÿÿÿ)Ú
startswithr_   rL   r   ZDeferredr]   ÚAttributeError)r
   r0   r	   r	   r   Ú__getattr__%  s    zDeferredResolver.__getattr__N)r   r   r   r   r`   rk   r	   r	   r	   r   r^     s   r^   Nc                    sP   dd„ t dƒD ƒ}‡ fdd„|D ƒ}tj|dd�}‡fdd„}| |¡ t|ƒS )	aÿ  
    Lookup the root nameserver addresses using the given resolver

    Return a Resolver which will eventually become a C{root.Resolver}
    instance that has references to all the root servers that we were able
    to look up.

    @param resolver: The resolver instance which will be used to
        lookup the root nameserver addresses.
    @type resolver: L{twisted.internet.interfaces.IResolverSimple}

    @param resolverFactory: An optional callable which returns a
        resolver instance. It will passed as the C{resolverFactory}
        argument to L{Resolver.__init__}.
    @type resolverFactory: callable

    @return: A L{DeferredResolver} which will be dynamically replaced
        with L{Resolver} when the root nameservers have been looked up.
    c                 S   s   g | ]}t td ƒ| ƒ‘qS )Úa)ÚchrÚord)r   Úir	   r	   r   r    @  s     zbootstrap.<locals>.<listcomp>é   c                    s   g | ]}ˆ   d | ¡‘qS )z%s.root-servers.net)rg   )r   r(   )rd   r	   r   r    A  s     T)ZconsumeErrorsc                    s   t dd„ | D ƒˆ d�S )Nc                 S   s   g | ]}|d  r|d ‘qS )r   r*   r	   )r   Úer	   r	   r   r    F  s      z4bootstrap.<locals>.buildResolver.<locals>.<listcomp>)r   r   r   )Úres)r   r	   r   ÚbuildResolverD  s     ÿz bootstrap.<locals>.buildResolver)Úranger   ZDeferredListr#   r^   )rd   r   ÚdomainsÚLr(   rs   r	   )rd   r   r   Ú	bootstrap,  s    
rw   )N)r   Ztwisted.internetr   Ztwisted.namesr   r   r   Ztwisted.python.failurer   r   r   r   r]   r^   rw   r	   r	   r	   r   Ú<module>   s    r