U
    
W[0                     @   st   d Z ddlmZ ddlmZ ddlmZmZ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
    )Failure)defer)dnscommonerrorc                   @   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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).0Zipr	   r	   r   
<listcomp>O   s     z#Resolver._roots.<locals>.<listcomp>)r   )r
   r	   r	   r   _rootsJ   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   _queryR   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   _lookupr   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   )getr0   r1   r   ZCNAME)r/   r1   r0   Zcnamerecord)recordsr	   r   findAnswerOrCName   s    

z8Resolver._discoveredAuthority.<locals>.findAnswerOrCNameNc                    s    | \}}}| d  |||fS Nr   )insertZ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   )Zhint)r5   r#   r
   r$   r	   r   <lambda>  s
    
  z/Resolver._discoveredAuthority.<locals>.<lambda>z/Stuck at response without answers or delegation)ZrCoder   ZOKr   ZexceptionForCoder=   
setdefaultr/   appendsetaddr1   r0   r-   r.   strr    r"   r>   r?   rB   r   r3   ArC   ZNSr   ZlookupAddress)r
   Zresponser#   r$   r5   Zanswerr9   seenr/   r7   r'   rA   Z	addressesZrrr   ZtrapsnsrD   r	   )r@   r5   r#   r8   r
   r$   r   r4      s|    


  






   
zResolver._discoveredAuthority)r   NN)
r   r   r   r   r   r    r(   r2   r-   r4   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   kwr/   r	   r   rE         z6makePlaceholder.<locals>.placeholder.<locals>.<lambda>)r"   r   rO   deferredr/   rQ   r   placeholder  s    z$makePlaceholder.<locals>.placeholderr	   )rS   r/   rT   r	   rR   r   makePlaceholder  s    rU   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   )rW   __dict__	__class__callback)r
   resolverwr'   r	   r	   r   rX      s
    z DeferredResolver.gotRealResolverc                 C   s>   | ds|dkr2| jt  t| jd |S t|d S )Nlookup)getHostByNamer#   )
startswithrW   rG   r   ZDeferredrU   AttributeError)r
   r/   r	   r	   r   __getattr__'  s    zDeferredResolver.__getattr__N)r   r   r   r   rX   rc   r	   r	   r	   r   rV     s   rV   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   C  s     zbootstrap.<locals>.<listcomp>   c                    s   g | ]}  d | qS )z%s.root-servers.net)r_   )r   r'   )r\   r	   r   r   D  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   I  s      z4bootstrap.<locals>.buildResolver.<locals>.<listcomp>)r   r   r   )res)r   r	   r   buildResolverG  s    z bootstrap.<locals>.buildResolver)ranger   ZDeferredListr"   rV   )r\   r   ZdomainsLr'   rk   r	   )r\   r   r   	bootstrap/  s    
rn   )N)r   Ztwisted.python.failurer   Ztwisted.internetr   Ztwisted.namesr   r   r   r   r   r   rU   rV   rn   r	   r	   r	   r   <module>   s    u