whois/whois.py
changeset 12 c57439b500cb
parent 6 7dee244ba3ef
child 32 5f851e9c196a
equal deleted inserted replaced
11:5083c26d8f93 12:c57439b500cb
       
     1 """
       
     2 Whois client for python
       
     3 
       
     4 transliteration of:
       
     5 http://www.opensource.apple.com/source/adv_cmds/adv_cmds-138.1/whois/whois.c
       
     6 
       
     7 Copyright (c) 2010 Chris Wolf
       
     8 
       
     9 Permission is hereby granted, free of charge, to any person obtaining a copy
       
    10 of this software and associated documentation files (the "Software"), to deal
       
    11 in the Software without restriction, including without limitation the rights
       
    12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       
    13 copies of the Software, and to permit persons to whom the Software is
       
    14 furnished to do so, subject to the following conditions:
       
    15 
       
    16 The above copyright notice and this permission notice shall be included in
       
    17 all copies or substantial portions of the Software.
       
    18 
       
    19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       
    20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       
    21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
       
    22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       
    23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       
    24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
       
    25 THE SOFTWARE.
       
    26 
       
    27   Last edited by:  $Author$
       
    28               on:  $DateTime$
       
    29         Revision:  $Revision$
       
    30               Id:  $Id$
       
    31           Author:  Chris Wolf
       
    32 """
       
    33 import sys
       
    34 import socket
       
    35 import optparse
       
    36 #import pdb
       
    37 
       
    38 def enforce_ascii(a):
       
    39     if isinstance(a, str) or isinstance(a, unicode):
       
    40         # return a.encode('ascii', 'replace')
       
    41         r = ""
       
    42         for i in a:
       
    43             if ord(i) >= 128:
       
    44                 r += "?"
       
    45             else:
       
    46                 r += i
       
    47         return r
       
    48     else:
       
    49         return a
       
    50 
       
    51 class NICClient(object) :
       
    52 
       
    53     ABUSEHOST           = "whois.abuse.net"
       
    54     NICHOST             = "whois.crsnic.net"
       
    55     INICHOST            = "whois.networksolutions.com"
       
    56     DNICHOST            = "whois.nic.mil"
       
    57     GNICHOST            = "whois.nic.gov"
       
    58     ANICHOST            = "whois.arin.net"
       
    59     LNICHOST            = "whois.lacnic.net"
       
    60     RNICHOST            = "whois.ripe.net"
       
    61     PNICHOST            = "whois.apnic.net"
       
    62     MNICHOST            = "whois.ra.net"
       
    63     QNICHOST_TAIL       = ".whois-servers.net"
       
    64     SNICHOST            = "whois.6bone.net"
       
    65     BNICHOST            = "whois.registro.br"
       
    66     NORIDHOST           = "whois.norid.no"
       
    67     IANAHOST            = "whois.iana.org"
       
    68     DENICHOST           = "de.whois-servers.net"
       
    69     DEFAULT_PORT        = "nicname"
       
    70     WHOIS_SERVER_ID     = "Whois Server:"
       
    71     WHOIS_ORG_SERVER_ID = "Registrant Street1:Whois Server:"
       
    72 
       
    73 
       
    74     WHOIS_RECURSE       = 0x01
       
    75     WHOIS_QUICK         = 0x02
       
    76 
       
    77     ip_whois = [ LNICHOST, RNICHOST, PNICHOST, BNICHOST ]
       
    78 
       
    79     def __init__(self) :
       
    80         self.use_qnichost = False
       
    81        
       
    82     def findwhois_server(self, buf, hostname):
       
    83         """Search the initial TLD lookup results for the regional-specifc
       
    84         whois server for getting contact details.
       
    85         """
       
    86         #print 'finding whois server'
       
    87         #print 'parameters:', buf, 'hostname', hostname
       
    88         nhost = None
       
    89         parts_index = 1
       
    90         start = buf.find(NICClient.WHOIS_SERVER_ID)
       
    91         #print 'start', start
       
    92         if (start == -1):
       
    93             start = buf.find(NICClient.WHOIS_ORG_SERVER_ID)
       
    94             parts_index = 2
       
    95        
       
    96         if (start > -1):  
       
    97             end = buf[start:].find('\n')
       
    98             #print 'end:', end
       
    99             whois_line = buf[start:end+start]
       
   100             #print 'whois_line', whois_line
       
   101             nhost = whois_line.split(NICClient.WHOIS_SERVER_ID+' ').pop()
       
   102             nhost = nhost.split('http://').pop()
       
   103             #if the whois address is domain.tld/something then
       
   104             #s.connect((hostname, 43)) does not work
       
   105             if nhost.count('/') > 0:
       
   106                 nhost = None
       
   107             #print 'nhost:',nhost
       
   108         elif (hostname == NICClient.ANICHOST):
       
   109             for nichost in NICClient.ip_whois:
       
   110                 if (buf.find(nichost) != -1):
       
   111                     nhost = nichost
       
   112                     break
       
   113         return nhost
       
   114        
       
   115     def whois(self, query, hostname, flags):
       
   116         """Perform initial lookup with TLD whois server
       
   117         then, if the quick flag is false, search that result
       
   118         for the region-specifc whois server and do a lookup
       
   119         there for contact details
       
   120         """
       
   121         #print 'Performing the whois'
       
   122         #print 'parameters given:', query, hostname, flags
       
   123         #pdb.set_trace()
       
   124         s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
       
   125         s.connect((hostname, 43))
       
   126         """send takes bytes as an input
       
   127         """
       
   128         queryBytes = None
       
   129         if (hostname == NICClient.DENICHOST):
       
   130             #print 'the domain is in NIC DENIC'
       
   131             queryBytes = ("-T dn,ace -C UTF-8 " + query + "\r\n").encode()
       
   132             #print 'queryBytes:', queryBytes
       
   133         else:
       
   134             queryBytes = (query  + "\r\n").encode()        
       
   135         s.send(queryBytes)
       
   136         """recv returns bytes
       
   137         """
       
   138         #print s
       
   139         response = b''
       
   140         while True:
       
   141             d = s.recv(4096)
       
   142             response += d
       
   143             if not d:
       
   144                 break
       
   145         s.close()
       
   146         #pdb.set_trace()
       
   147         nhost = None
       
   148         #print 'response', response
       
   149         response = enforce_ascii(response)
       
   150         if (flags & NICClient.WHOIS_RECURSE and nhost == None):
       
   151             #print 'Inside first if'
       
   152             nhost = self.findwhois_server(response.decode(), hostname)
       
   153             #print 'nhost is:', nhost
       
   154         if (nhost != None):
       
   155             #print 'inside second if'
       
   156             response += self.whois(query, nhost, 0)
       
   157             #print 'response', response
       
   158         #print 'returning whois response'
       
   159         return response.decode()
       
   160    
       
   161     def choose_server(self, domain):
       
   162         """Choose initial lookup NIC host"""
       
   163         if (domain.endswith("-NORID")):
       
   164             return NICClient.NORIDHOST
       
   165         pos = domain.rfind('.')
       
   166         if (pos == -1):
       
   167             return None
       
   168         tld = domain[pos+1:]
       
   169         if (tld[0].isdigit()):
       
   170             return NICClient.ANICHOST
       
   171    
       
   172         return tld + NICClient.QNICHOST_TAIL
       
   173    
       
   174     def whois_lookup(self, options, query_arg, flags):
       
   175         """Main entry point: Perform initial lookup on TLD whois server,
       
   176         or other server to get region-specific whois server, then if quick
       
   177         flag is false, perform a second lookup on the region-specific
       
   178         server for contact records"""
       
   179         #print 'whois_lookup'
       
   180         nichost = None
       
   181         #pdb.set_trace()
       
   182         # this would be the case when this function is called by other than main
       
   183         if (options == None):                    
       
   184             options = {}
       
   185      
       
   186         if ( (not 'whoishost' in options or options['whoishost'] == None)
       
   187             and (not 'country' in options or options['country'] == None)):
       
   188             self.use_qnichost = True
       
   189             options['whoishost'] = NICClient.NICHOST
       
   190             if ( not (flags & NICClient.WHOIS_QUICK)):
       
   191                 flags |= NICClient.WHOIS_RECURSE
       
   192            
       
   193         if ('country' in options and options['country'] != None):
       
   194             result = self.whois(query_arg, options['country'] + NICClient.QNICHOST_TAIL, flags)
       
   195         elif (self.use_qnichost):
       
   196             nichost = self.choose_server(query_arg)
       
   197             if (nichost != None):
       
   198                 result = self.whois(query_arg, nichost, flags)
       
   199         else:
       
   200             result = self.whois(query_arg, options['whoishost'], flags)
       
   201         #print 'whois_lookup finished'
       
   202         return result
       
   203 #---- END OF NICClient class def ---------------------
       
   204    
       
   205 def parse_command_line(argv):
       
   206     """Options handling mostly follows the UNIX whois(1) man page, except
       
   207     long-form options can also be used.
       
   208     """
       
   209     flags = 0
       
   210    
       
   211     usage = "usage: %prog [options] name"
       
   212            
       
   213     parser = optparse.OptionParser(add_help_option=False, usage=usage)
       
   214     parser.add_option("-a", "--arin", action="store_const",
       
   215                       const=NICClient.ANICHOST, dest="whoishost",
       
   216                       help="Lookup using host " + NICClient.ANICHOST)
       
   217     parser.add_option("-A", "--apnic", action="store_const",
       
   218                       const=NICClient.PNICHOST, dest="whoishost",
       
   219                       help="Lookup using host " + NICClient.PNICHOST)
       
   220     parser.add_option("-b", "--abuse", action="store_const",
       
   221                       const=NICClient.ABUSEHOST, dest="whoishost",
       
   222                       help="Lookup using host " + NICClient.ABUSEHOST)
       
   223     parser.add_option("-c", "--country", action="store",
       
   224                       type="string", dest="country",
       
   225                       help="Lookup using country-specific NIC")
       
   226     parser.add_option("-d", "--mil", action="store_const",
       
   227                       const=NICClient.DNICHOST, dest="whoishost",
       
   228                       help="Lookup using host " + NICClient.DNICHOST)
       
   229     parser.add_option("-g", "--gov", action="store_const",
       
   230                       const=NICClient.GNICHOST, dest="whoishost",
       
   231                       help="Lookup using host " + NICClient.GNICHOST)
       
   232     parser.add_option("-h", "--host", action="store",
       
   233                       type="string", dest="whoishost",
       
   234                        help="Lookup using specified whois host")
       
   235     parser.add_option("-i", "--nws", action="store_const",
       
   236                       const=NICClient.INICHOST, dest="whoishost",
       
   237                       help="Lookup using host " + NICClient.INICHOST)
       
   238     parser.add_option("-I", "--iana", action="store_const",
       
   239                       const=NICClient.IANAHOST, dest="whoishost",
       
   240                       help="Lookup using host " + NICClient.IANAHOST)
       
   241     parser.add_option("-l", "--lcanic", action="store_const",
       
   242                       const=NICClient.LNICHOST, dest="whoishost",
       
   243                       help="Lookup using host " + NICClient.LNICHOST)
       
   244     parser.add_option("-m", "--ra", action="store_const",
       
   245                       const=NICClient.MNICHOST, dest="whoishost",
       
   246                       help="Lookup using host " + NICClient.MNICHOST)
       
   247     parser.add_option("-p", "--port", action="store",
       
   248                       type="int", dest="port",
       
   249                       help="Lookup using specified tcp port")
       
   250     parser.add_option("-Q", "--quick", action="store_true",
       
   251                      dest="b_quicklookup",
       
   252                      help="Perform quick lookup")
       
   253     parser.add_option("-r", "--ripe", action="store_const",
       
   254                       const=NICClient.RNICHOST, dest="whoishost",
       
   255                       help="Lookup using host " + NICClient.RNICHOST)
       
   256     parser.add_option("-R", "--ru", action="store_const",
       
   257                       const="ru", dest="country",
       
   258                       help="Lookup Russian NIC")
       
   259     parser.add_option("-6", "--6bone", action="store_const",
       
   260                       const=NICClient.SNICHOST, dest="whoishost",
       
   261                       help="Lookup using host " + NICClient.SNICHOST)
       
   262     parser.add_option("-?", "--help", action="help")
       
   263 
       
   264        
       
   265     return parser.parse_args(argv)
       
   266    
       
   267 if __name__ == "__main__":
       
   268     flags = 0
       
   269     nic_client = NICClient()
       
   270     (options, args) = parse_command_line(sys.argv)
       
   271     if (options.b_quicklookup is True):
       
   272         flags = flags|NICClient.WHOIS_QUICK
       
   273     print(nic_client.whois_lookup(options.__dict__, args[1], flags))