o
    ¯bˆ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	   ú4/usr/lib/python3/dist-packages/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u rd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Ú_reactorÚtwisted.names.clientr   Ú_resolverFactory)r
   r   Ú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   ÚqueryUDPÚaddCallbackÚfilterAnswers)r
   Úqueryr$   ÚtimeoutÚfilterÚrÚdr	   r	   r   Ú_queryO   s
   zResolver._queryc                 C   s,   |du 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   r2   |   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u rj|ˆjkrJn>ˆ t t|ƒˆjˆj¡ˆ ¡ ˆˆ¡}
‡ fdd„}|
 |¡ |
S |	jˆjkrx|j|j|jfS |	jj|v rƒt d¡‚|	jj}q1i }|jD ]}|jtjkrž|j ¡ ||jj< q�g }g }|jD ]!}|jtjkrÇ|jjj}||v rÂ| || tjf¡ q¦| |¡ q¦|rÒˆ ˆ|ˆˆ¡S |róˆ |d ˆ¡}
d	d
„ }|
 |¡ |
 ‡‡‡‡fdd„¡ |
S tt 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 ]}|j|kr |j|kr|  S |jtjkr |}q|S r   )Úgetr5   r6   r   ÚCNAME)r4   r6   r5   ÚcnameÚrecord)Úrecordsr	   r   ÚfindAnswerOrCName¹   s   

€z8Resolver._discoveredAuthority.<locals>.findAnswerOrCNameNTc                    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 rA   )ÚpayloadÚ
dottedQuadrC   r	   r	   r   ÚgetOneAddress   s   
z4Resolver._discoveredAuthority.<locals>.getOneAddressc                    s   ˆ  ˆ| tjfgˆˆ d ¡S )Nr.   )r2   r   r   )Úhint)r:   r(   r
   r)   r	   r   Ú<lambda>  s    ÿz/Resolver._discoveredAuthority.<locals>.<lambda>z/Stuck at response without answers or delegation)ÚrCoder   ÚOKr   ÚexceptionForCoderE   Ú
setdefaultr4   ÚappendÚsetÚaddr6   r5   r2   r3   Ústrr#   r&   rF   rG   rJ   r   r8   ÚArK   ÚNSr   ÚlookupAddress)r
   Úresponser(   r)   r:   Úanswerr@   Úseenr4   r>   r,   rI   Ú	addressesÚrrr   ÚtrapsÚnsrL   r	   )rH   r:   r(   r?   r
   r)   r   r9   š   st   


ü	

Þ%
€


€
ÿÿzResolver._discoveredAuthority)r   NN)
r   r   r   r   r   r#   r-   r7   r2   r9   r	   r	   r	   r   r       s    

r   c                    s   ‡ ‡fdd„}|S )Nc                     s   ˆ  ‡ ‡‡fdd„¡ ˆS )Nc                    s   t | ˆƒˆ i ˆ¤ŽS r   )Úgetattr)r+   )r   Úkwr4   r	   r   rN     s    z6makePlaceholder.<locals>.placeholder.<locals>.<lambda>)r&   ©r   rb   ©Údeferredr4   rc   r   Úplaceholder  s   z$makePlaceholder.<locals>.placeholderr	   )re   r4   rf   r	   rd   r   ÚmakePlaceholder  s   rg   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
   ÚresolverDeferredr	   r	   r   r     s   zDeferredResolver.__init__c                 C   s.   | j }|j| _|j| _|D ]}| |¡ qd S r   )ri   Ú__dict__Ú	__class__Úcallback)r
   ÚresolverÚwr,   r	   r	   r   rj     s   ÿz DeferredResolver.gotRealResolverc                 C   s:   |  d¡s	|dv r| j t ¡ ¡ t| jd |ƒS t|ƒ‚)NÚlookup)ÚgetHostByNamer(   éÿÿÿÿ)Ú
startswithri   rS   r   ÚDeferredrg   ÚAttributeError)r
   r4   r	   r	   r   Ú__getattr__%  s   zDeferredResolver.__getattr__N)r   r   r   r   rj   rw   r	   r	   r	   r   rh     s    rh   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"   @  ó    zbootstrap.<locals>.<listcomp>é   c                    s   g | ]	}ˆ   d | ¡‘qS )z%s.root-servers.net)rr   )r    r,   )ro   r	   r   r"   A  s    T)Ú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  r|   z4bootstrap.<locals>.buildResolver.<locals>.<listcomp>)r   r   r   )Úres)r   r	   r   ÚbuildResolverD  s   ÿz bootstrap.<locals>.buildResolver)Úranger   ÚDeferredListr&   rh   )ro   r   ÚdomainsÚLr,   r�   r	   )ro   r   r   Ú	bootstrap,  s   
r†   r   )r   Útwisted.internetr   Útwisted.namesr   r   r   Útwisted.python.failurer   r   r   r   rg   rh   r†   r	   r	   r	   r   Ú<module>   s    r