
    gw                        d dl Z d dlZd dlZd dlZd dlmZ d dlZd dlm	Z	 d dl
ZddlmZmZmZmZmZmZmZmZ ddlmZ ddlmZ ddlmZmZ e j6                  d	k\  rd d
lmZmZmZ n
d dl m!ZmZmZ 	 d dl"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z( d dl)m*Z*  ej\                  e/      Z0dZ1dZ2dZ3dZ4dgZ5ddddddddZ6 G d d      Z7y# e+$ r d dl,m#Z#m$Z$m%Z%m&Z&m'Z'm(Z( d dl-m*Z* Y Ow xY w)    N)
namedtuple)sleep   )IPDefinedErrorASNLookupErrorBlacklistErrorWhoisLookupErrorHTTPLookupErrorHostLookupErrorHTTPRateLimitErrorWhoisRateLimitError)	RIR_WHOIS)ASN_ORIGIN_WHOIS)ipv4_is_definedipv6_is_defined)   r   )
ip_addressIPv4AddressIPv6Address)	IPAddressr   r   )OpenerDirectorProxyHandlerbuild_openerRequestURLError	HTTPError)	urlencodezDhttp://whois.arin.net/rest/nets;q={0}?showDetails=true&showARIN=truezwhois.cymru.comz{0}.origin.asn.cymru.comz{0}.origin6.asn.cymru.comzroot.rwhois.netarinripenccapniclacnicafrinic)ARINzVR-ARINRIPEAPNICLACNICAFRINICDNICc                   n    e Zd ZdZddZd ZddZddZddZ	 	 ddZ		 	 dd	Z
	 	 dd
ZddZ	 	 ddZy)Neta  
    The class for performing network queries.

    Args:
        address (:obj:`str`/:obj:`int`/:obj:`IPv4Address`/:obj:`IPv6Address`):
            An IPv4 or IPv6 address
        timeout (:obj:`int`): The default timeout for socket connections in
            seconds. Defaults to 5.
        proxy_opener (:obj:`urllib.request.OpenerDirector`): The request for
            proxy support. Defaults to None.

    Raises:
        IPDefinedError: The address provided is defined (does not need to be
            resolved).
    Nc                    t        |t              st        |t              r|| _        nt	        |      | _        || _        t        j                  j                         | _	        t        | j                  d      rt        | j                  d      | _        nt        | j                  d      | _        || j                  _        || j                  _        t        |t              r|| _        nt!               }t#        |      | _        | j                  j%                         | _        | j                  j(                  | _        | j(                  dk(  rt+        | j&                        }|d   r,t-        dj/                  | j&                  |d   |d               | j&                  j1                  d      }|j3                          dj5                  |      | _        t8        j/                  | j6                        | _        y t=        | j&                        }|d   r,t-        d	j/                  | j&                  |d   |d               | j                  j>                  }|j1                  d
      }t7        tA        tC        |                  D ]  \  }	}
|
dk(  r||	=  n d
j5                  |      }tE        |      jG                  d
d      }|d d d   }dj5                  |      | _        tH        j/                  | j6                        | _        y )Nresolvequery   r   z3IPv4 address {0} is already defined as {1} via {2}.r      .z3IPv6 address {0} is already defined as {1} via {2}.:0000 )%
isinstancer   r   addressr   timeoutdnsresolverResolverdns_resolverhasattrgetattrdns_resolvelifetimer   openerr   r   __str__address_strversionr   r   formatsplitreversejoinreversedIPV4_DNS_ZONEdns_zoner   explodedlist	enumeratestrreplaceIPV6_DNS_ZONE)selfr6   r7   proxy_openerhandler
is_definedrE   rK   groupsindexvaluevals                /opt/Tautulli/lib/ipwhois/net.py__init__zNet.__init__p   s    g{+z0& #DL
 &g.DL LL1134$$i0&t'8'8)DD&t'8'8'BD$+!%," lN3&DK #nG&w/DK  <<//1 ||++<<1 ))9)9:J!}$!6((*Q-A  $$**3/EMMOHHUODM)00?DM
 ))9)9:J!}$!6((*Q-A  ||,,H ^^C(F (i.?)@ A uF?u  xx'H h-''R0Cdd)CHHSMDM)00?DM    c                 J   	 t         j                  dj                  | j                               | j	                  | j                  d      }t        |      S # t        j                  j                  t        j                  j                  t        j                  j                  t        j                  j                  f$ r>}t        dj                  |j                  j                  | j                               d}~w t        dj                  | j                               xY w)z
        The function for retrieving ASN information for an IP address from
        Cymru via port 53 (DNS).

        Returns:
            list: The raw ASN data.

        Raises:
            ASNLookupError: The ASN lookup failed.
        ASN query for {0}TXT$ASN lookup failed (DNS {0}) for {1}.NASN lookup failed for {0}.)logdebugrD   rJ   r>   rL   r8   r9   NXDOMAINNoNameserversNoAnswer	exceptionTimeoutr   	__class____name__rB   )rQ   dataes      rY   get_asn_dnszNet.get_asn_dns   s    	II)00?@##DMM59D:%%s||'A'A%%s}}'<'<> 	 !6==KK(($*:*:< 
	 ,33D4D4DE s   AA A)D" 9C99)D"c                 T   |dd dk7  rdj                  |      }dj                  |      }	 t        j                  dj                  |             | j                  |d      }t	        |d         S # t
        j                  j                  t
        j                  j                  t
        j                  j                  t
        j                  j                  f$ r4}t        dj                  |j                  j                  |            d	}~w t        d
j                  |            xY w)a  
        The function for retrieving the information for an ASN from
        Cymru via port 53 (DNS). This is needed since IP to ASN mapping via
        Cymru DNS does not return the ASN Description like Cymru Whois does.

        Args:
            asn (:obj:`str`): The AS number (required).

        Returns:
            str: The raw ASN data.

        Raises:
            ASNLookupError: The ASN lookup failed.
        r   r/   ASzAS{0}z{0}.asn.cymru.comzASN verbose query for {0}r^   r_   Nr`   )rD   ra   rb   r>   rN   r8   r9   rc   rd   re   rf   rg   r   rh   ri   )rQ   asnzonerj   rk   s        rY   get_asn_verbose_dnszNet.get_asn_verbose_dns   s      q8t..%C"))#.	II188>?##D%0DtAw<%%s||'A'A%%s}}'<'<> 	 !6==KK((#/ 
	 ,33C8 s   AA0 0A)D'/DD'c                    	 t        j                   t         j                  t         j                        }|j                  | j                         t
        j                  dj                  | j                               |j                  t        df       |j                  dj                  | j                  d      j                                d}	 |j                  d      j                         }||z  }|sn(|j                          t!        |      S # t         j                  t         j"                  f$ r}t
        j                  dj                  |             |dkD  rFt
        j                  d	j                  t!        |                   | j%                  |d
z
        cY d}~S t'        dj                  | j                              d}~w t'        dj                  | j                              xY w)a  
        The function for retrieving ASN information for an IP address from
        Cymru via port 43/tcp (WHOIS).

        Args:
            retry_count (:obj:`int`): The number of times to retry in case
                socket errors, timeouts, connection resets, etc. are
                encountered. Defaults to 3.

        Returns:
            str: The raw ASN data.

        Raises:
            ASNLookupError: The ASN lookup failed.
        r]   +   z -r -a -c -p -f {0}{1}
r3      ASN query socket error: {0}r   ASN query retrying (count: {0})r   Nr`   )socketAF_INETSOCK_STREAM
settimeoutr7   ra   rb   rD   rB   connectCYMRU_WHOISsendencoderecvdecodecloserN   errorget_asn_whoisr   )rQ   retry_countconnrj   drk   s         rY   r   zNet.get_asn_whois  s   "/	 ==1C1CDDOODLL)II)001A1ABCLL+r*+ II(//$$f.fh
 DIIdO**,	  JJLt9- 	II3::1=>Q		;BB$& '))+/:: %0778H8HI 	 ,33D4D4DE s%   DD #G26A)G	G2%$G		)G2c                    	 t         j                  dj                  | j                               | j	                  t        t              j                  | j                        |ddi      }|S # t        j                  t        j                  f$ r}t         j                  dj                  |             |dkD  rGt         j                  dj                  t        |                   | j                  |dz
  	      cY d
}~S t        dj                  | j                              d
}~w t        dj                  | j                              xY w)a  
        The function for retrieving ASN information for an IP address from
        Arin via port 80 (HTTP). Currently limited to fetching asn_registry
        through a Arin whois (REST) lookup. The other values are returned as
        None to keep a consistent dict output. This should be used as a last
        chance fallback call behind ASN DNS & ASN Whois lookups.

        Args:
            retry_count (:obj:`int`): The number of times to retry in case
                socket errors, timeouts, connection resets, etc. are
                encountered. Defaults to 3.

        Returns:
            dict: The ASN data in json format.

        Raises:
            ASNLookupError: The ASN lookup failed.
        r]   Acceptzapplication/json)urlr   headersrv   r   rw   r   )r   Nr`   )ra   rb   rD   rB   get_http_jsonrN   r#   rx   r7   r   get_asn_httpr   )rQ   r   responserk   s       rY   r   zNet.get_asn_httpa  s!   ( 	 II)001A1ABC))I$$T%5%56'!#56 * H O- 	II3::1=>Q		;BB$& '(([](CC %0778H8HI 	 ,33D4D4DE s%   A+A. .#EA*D%;E$D%%)Ec                    	 |t         |   d   }t        j                  t        j                  t        j                        }|j	                  | j
                         t        j                  dj                  |||             |j                  ||f       dj                  |d      }|j                  |j                                d}	 |j                  d      j                         }	||	z  }|	sn(|j                          d|v rX|d	kD  r9t        j                  d
       t        d       | j!                  |||dz
  ||      S t#        dj                  |            d|v sd|v r*t        j                  dj                  |             t$        t'        |      S # t        j
                  t        j(                  f$ r}
t        j                  dj                  |
             |d	kD  rKt        j                  dj                  t'        |                   | j!                  |||dz
  ||      cY d}
~
S t+        dj                  |            d}
~
wt"        $ r   t+        dj                  |            xY w)aa  
        The function for retrieving CIDR info for an ASN via whois.

        Args:
            asn_registry (:obj:`str`): The source to run the query against
                (asn.ASN_ORIGIN_WHOIS).
            asn (:obj:`str`): The AS number (required).
            retry_count (:obj:`int`): The number of times to retry in case
                socket errors, timeouts, connection resets, etc. are
                encountered. Defaults to 3.
            server (:obj:`str`): An optional server to connect to.
            port (:obj:`int`): The network port to connect on. Defaults to 43.

        Returns:
            str: The raw ASN origin whois data.

        Raises:
            WhoisLookupError: The ASN origin whois lookup failed.
            WhoisRateLimitError: The ASN origin Whois request rate limited and
                retries were exhausted.
        Nserverz)ASN origin WHOIS query for {0} at {1}:{2}z -i origin {0}{1}rt   r3   ru   Query rate limit exceededr   z6ASN origin WHOIS query rate limit exceeded. Waiting...r   )asn_registryro   r   r   portzmASN origin Whois lookup failed for {0}. Rate limit exceeded, wait and try again (possibly a temporary block).	error 501	error 230z!ASN origin WHOIS query error: {0}z(ASN origin WHOIS query socket error: {0}z,ASN origin WHOIS query retrying (count: {0})z'ASN origin WHOIS lookup failed for {0}.)r   rx   ry   rz   r{   r7   ra   rb   rD   r|   r~   r   r   r   r   r   get_asn_origin_whoisr   
ValueErrorrN   r   r	   )rQ   r   ro   r   r   r   r   r-   r   r   rk   s              rY   r   zNet.get_asn_origin_whois  sQ   0V	~),7A ==1C1CDDOODLL)IIAHHVT# $LL&$( (..sF;E IIelln%HIIdO**,A  JJL +h6?II + ,!H44%1s$/M%D 5   .,,2F3K9 9
 )[H-D 		=DDXNO  x= - 	II@GGJKQ		 #VC$45700!-3 +Af4 1   '=DDSI  # 		"9@@E s,   EF AF #I4>A.I,I42I(I4c                    	 |r|ng }t        fdt        |fD              rt        dj                              t        |   d   t        j
                  t
        j                  t
        j                        }|j                  | j                         t        j                  dj                  | j                  |             |j                  |f       | j                  dz   }|dk(  rdj                  |      }|j                  |j                                d	}		 |j!                  d
      j#                  dd      }
|	|
z  }	|
sn*|j%                          d|	v rb|dkD  r9t        j                  d       t'        d       | j)                  ||dz
  ||      S t+        dj                  | j                              d|	v sd|	v r*t        j                  dj                  |	             t,        t/        |	      S # t
        j                  t
        j0                  f$ r}t        j                  dj                  |             |dkD  rKt        j                  dj                  t/        |                   | j)                  ||dz
  ||      cY d}~S t3        dj                  | j                              d}~wt*        $ r  t        $ r   t3        dj                  | j                              xY w)a  
        The function for retrieving whois or rwhois information for an IP
        address via any port. Defaults to port 43/tcp (WHOIS).

        Args:
            asn_registry (:obj:`str`): The NIC to run the query against.
                Defaults to 'arin'.
            retry_count (:obj:`int`): The number of times to retry in case
                socket errors, timeouts, connection resets, etc. are
                encountered. Defaults to 3.
            server (:obj:`str`): An optional server to connect to. If
                provided, asn_registry will be ignored.
            port (:obj:`int`): The network port to connect on. Defaults to 43.
            extra_blacklist (:obj:`list` of :obj:`str`): Blacklisted whois
                servers in addition to the global BLACKLIST. Defaults to None.

        Returns:
            str: The raw whois data.

        Raises:
            BlacklistError: Raised if the whois server provided is in the
                global BLACKLIST or extra_blacklist.
            WhoisLookupError: The whois lookup failed.
            WhoisRateLimitError: The Whois request rate limited and retries
                were exhausted.
        c              3   &   K   | ]  }|v  
 y wN ).0srvr   s     rY   	<genexpr>z Net.get_whois.<locals>.<genexpr>(  s     BS6S=Bs   zThe server {0} is blacklisted.Nr   zWHOIS query for {0} at {1}:{2}rt   r   zn + {0}r3   ru   asciiignorer   r   z+WHOIS query rate limit exceeded. Waiting...r   )r   r   r   r   extra_blacklistzbWhois lookup failed for {0}. Rate limit exceeded, wait and try again (possibly a temporary block).r   r   zWHOIS query error: {0}zWHOIS query socket error: {0}z!WHOIS query retrying (count: {0})zWHOIS lookup failed for {0}.)any	BLACKLISTr   rD   r   rx   ry   rz   r{   r7   ra   rb   rB   r|   r~   r   r   r   r   r   	get_whoisr   r   rN   r   r	   )rQ   r   r   r   r   r   extra_blr   r-   r   r   rk   s      `        rY   r   zNet.get_whois  s   :b	*9rHBY,ABB$4;;FC  ~"<0: ==1C1CDDOODLL)II6==  &$0 1LL&$( $$v-Ev%!((/ IIelln%HIIdO**7H=A  JJL*h6?IIKL!H>>%1{1}%D(7 *   .,,2F43C3C,DF F
 )[H-D 		299(CD  x= - 	II5<<Q?@Q		=DD$& '~~!-;q=!o &   '299$:J:JK  # 	 		".55d6F6FG s,   FG? A G? ?#K5"A.J:K5$J::;K5c           	         |ddi}	 t         j                  dj                  | j                  |             t	        ||      }| j
                  j                  || j                        }	 t        j                  |j                         j                  dd            }	 |d	   D ]  }|d
   dk(  st         j                  d       |dkD  rRt         j                  dj                  t        |                   t        |       | j!                  ||dz
  ||      c S t#        dj                  |             	 |S # t        $ r6 t        j                  |j                         j                  dd            }Y w xY w# t$        t&        f$ r Y |S w xY w# t(        $ r}	|	j*                  dk(  rt         j                  d       |dkD  rUt         j                  dj                  t        |                   t        |       | j!                  ||dz
  ||      cY d}	~	S t#        dj                  |            t-        dj                  |t        |	j*                                    d}	~	wt.        t0        j                  t0        j2                  f$ r}	t         j                  dj                  |	             |dkD  rJt         j                  dj                  t        |                   | j!                  ||dz
  ||      cY d}	~	S t-        dj                  |            d}	~	wt,        t"        f$ r}	|	d}	~	w t-        dj                  |            xY w)a  
        The function for retrieving a json result via HTTP.

        Args:
            url (:obj:`str`): The URL to retrieve (required).
            retry_count (:obj:`int`): The number of times to retry in case
                socket errors, timeouts, connection resets, etc. are
                encountered. Defaults to 3.
            rate_limit_timeout (:obj:`int`): The number of seconds to wait
                before retrying when a rate limit notice is returned via
                rdap+json or HTTP error 429. Defaults to 60.
            headers (:obj:`dict`): The HTTP headers. The Accept header
                defaults to 'application/rdap+json'.

        Returns:
            dict: The data in json format.

        Raises:
            HTTPLookupError: The HTTP lookup failed.
            HTTPRateLimitError: The HTTP request rate limited and retries
                were exhausted.
        Nr   zapplication/rdap+jsonHTTP query for {0} at {1})r   r7   zutf-8r   noticestitlezRate Limit NoticezRDAP query rate limit exceeded.r   zWaiting {0} seconds...r   )r   r   rate_limit_timeoutr   zaHTTP lookup failed for {0}. Rate limit exceeded, wait and try again (possibly a temporary block).i  zHTTP query rate limit exceeded.z/HTTP lookup failed for {0} with error code {1}.HTTP query socket error: {0} HTTP query retrying (count: {0})HTTP lookup failed for {0}.)ra   rb   rD   rB   r   r@   openr7   jsonloadsreadallr   AttributeErrorreadrN   r   r   r   KeyError
IndexErrorr   coder
   r   rx   r   )
rQ   r   r   r   r   r   rj   r   tmprk   s
             rY   r   zNet.get_http_json  s;   2 ?!89G]	M II188  #' (30D;;##D$,,#?DFJJt||~44WhGH Y< AC7|'::		"CD&?II&>&E&E #$6 7'9 : ""45#'#5#5$'[]3E(/ $6 $  #5!44:F3K#A AA0 H= " FJJtyy{11'8DEF4 j) H	  	L vv}		;<?II6==./1 2 ,---[1_+= ' .   -,,2F3K9 9 & '228&c!&&k2JL L &..&,,7 	II4;;A>?Q		<CC$& ' ))Q'97 *   &&C&J&J'    !34 	G	M!"?"F"Fs"KLLs   A#F ,3D;  E= 1A+E= E= 9F ;<E:7F 9E::F =FF FF 	MA8I"MAI""+MA-L:M LM,L..Mc                     	 d}t        j                         s!t        j                  | j                         d}t        j                  dj                  | j                               t        j                  | j                        }|rt        j                  d       t        dd      } || S # t         j                  t         j                  f$ r}t        j                  dj                  |             |dkD  rFt        j                  d	j                  t        |                   | j                  |d
z
        cY d}~S t        dj                  | j                              d}~w t        dj                  | j                              xY w)a  
        The function for retrieving host information for an IP address.

        Args:
            retry_count (:obj:`int`): The number of times to retry in case
                socket errors, timeouts, connection resets, etc. are
                encountered. Defaults to 3.

        Returns:
            namedtuple:

            :hostname (str): The hostname returned mapped to the given IP
                address.
            :aliaslist (list): Alternate names for the given IP address.
            :ipaddrlist (list): IPv4/v6 addresses mapped to the same hostname.

        Raises:
            HostLookupError: The host lookup failed.
        FTzHost query for {0}Nget_host_resultszhostname, aliaslist, ipaddrlistzHost query socket error: {0}r   z Host query retrying (count: {0})r   zHost lookup failed for {0}.)rx   getdefaulttimeoutsetdefaulttimeoutr7   ra   rb   rD   rB   gethostbyaddrr   r   rN   get_hostr   )rQ   r   default_timeout_setretresultsrk   s         rY   r   zNet.get_host  sK   *'	"'++-((6&*#II*11$2B2BCD&&t'7'78C"((. !3 6B CGC= - 	II4;;A>?Q		<CC$& ' }}[1_55 &1889I9IJ 	!-44T5E5EF s%   B+B. .#FA)E$:F $E$$)Fc                    |ddi}d}|rt        |      }	 t        |d      }	 t        j	                  dj                  | j                  |             	 t        d|||dd|i}| j                  j                  || j                  	      }	 |j                         j                  dd
      }	t        |	      S # t        $ r Y w xY w# t        $ r t        |||      }Y {w xY w# t        $ r# |j                         j                  dd
      }	Y bw xY w# t         t"        j                  t"        j$                  f$ r}
t        j	                  dj                  |
             |dkD  rKt        j	                  dj                  t        |                   | j'                  ||dz
  |||      cY d}
~
S t)        dj                  |            d}
~
wt(        $ r}
|
d}
~
wt*        $ r t)        dj                  |            w xY w)a  
        The function for retrieving a raw HTML result via HTTP.

        Args:
            url (:obj:`str`): The URL to retrieve (required).
            retry_count (:obj:`int`): The number of times to retry in case
                socket errors, timeouts, connection resets, etc. are
                encountered. Defaults to 3.
            headers (:obj:`dict`): The HTTP headers. The Accept header
                defaults to 'text/html'.
            request_type (:obj:`str`): Request type 'GET' or 'POST'. Defaults
                to 'GET'.
            form_data (:obj:`dict`): Optional form POST data.

        Returns:
            str: The raw data.

        Raises:
            HTTPLookupError: The HTTP lookup failed.
        Nr   z	text/htmlr   )encodingr   )r   rj   r   methodr   r   r   r   r   r   )r   r   r   request_type	form_datar   r   )r   bytes	TypeErrorra   rb   rD   rB   r   r@   r   r7   r   r   r   r   rN   r   rx   r   get_http_rawr
   	Exception)rQ   r   r   r   r   r   enc_form_datar   rj   r   rk   s              rY   r   zNet.get_http_rawA  s
   . ?-G%i0M %mg F,	M II188  #' (M ;3]G ;"*L!9; ;;##D$,,#?D:LLN))'8< q6M+    M3]GLM " :IIK&&w9:
 &..&,,7 	II4;;A>?Q		<CC$& ' ((q'!- )   &&C&J&J'    	G 	M!"?"F"Fs"KLL	Ms   B9 /D C &'D  C% .
D 9	CCC"D !C""D %)DD DD (G?<A.G
*G?0G

G?G'G?)   Nr   )r   )radbNr   Nrs   )r   r   Nrs   N)Nr   x   N)Nr   NGETN)ri   
__module____qualname____doc__rZ   rl   rq   r   r   r   r   r   r   r   r   r[   rY   r*   r*   _   sq     c@J@(T@D4l =A>@n` DH+/B IL"yMv<| =A37OMr[   r*   )8sysrx   dns.resolverr8   r   collectionsr   loggingtimer   dns.rdtypes.ANY.TXT
exceptionsr   r   r   r	   r
   r   r   r   whoisr   ro   r   utilsr   r   version_info	ipaddressr   r   r   ipaddrr   urllib.requestr   r   r   r   r   r   urllib.parser   ImportErrorurllib2urllib	getLoggerri   ra   r#   r}   rI   rP   r   ORG_MAPr*   r   r[   rY   <module>r      s   2     "   B B B  ! 3v( (% %!+ + ' g! N*+ 	
 qM qMG  !$ $ !!s   2B: :CC