1  from mobi.mtld.da.exception.invalid_property_name_exception import InvalidPropertyNameException 
  2  from mobi.mtld.da.carrier.carrier_data import * 
  3  from mobi.mtld.da.property import * 
  4  from struct import unpack 
  5  from socket import * 
  8   
  9      """ 
 10      A list of HTTP headers to choose the original client IP 
 11      address from. In addition to these the REMOTE_ADDR is 
 12      also used as a final fallback. 
 13      """ 
 14      _HEADERS_TO_CHECK   = [ 
 15          "x-forwarded-for", 
 16          "client-ip", 
 17          "x-client-ip", 
 18          "rlnclientipaddr", 
 19          "proxy-client-ip", 
 20          "wl-proxy-client-ip", 
 21          "x-Forwarded", 
 22          "forwarded-for", 
 23          "forwarded" 
 24      ] 
 25   
 26      _VERSION            = "1.0.1" 
 27   
 28      _PRIVATE = ([0, 4294967295], 
 29                  [ 2130706432 , 4278190080 ], 
 30                  [ 3232235520 , 4294901760 ], 
 31                  [ 2886729728 , 4293918720 ], 
 32                  [ 167772160 , 4278190080 ], 
 33                  [ 2851995648, 65535]) 
 34   
 35      _data               = None 
 36   
 37      _MISSING_DATA_EX    = "No data file loaded, load data with load_data_from_file()" 
 38      _INVALID_PROP_EX    = "Property name \"%s\" does not exist" 
 39   
 47   
 54   
 61   
 68   
 70          """ 
 71          Get the Carrier properties for a given IP address. 
 72          """ 
 73          if(type(ipv4) is dict): 
 74              ipv4 = self.get_ip(ipv4) 
 75   
 76          props = None 
 77   
 78          self._dataLoaded() 
 79           
 80          if ipv4 != None: 
 81           props = self._data.getProperties(ipv4) 
 82   
 83          return props 
  84   
 86          """ 
 87          Try and get a specific property for a given IP address. 
 88          Note : If mutiple properties are needed for the same IP 
 89          it is more efficient to call properties() once than 
 90          repeated calls to property() 
 91          """ 
 92          if(type(propertyName) != str): 
 93              propertyName = propertyName.decode("utf-8") 
 94          if(type(ipv4) is dict): 
 95              ipv4 = self.get_ip(ipv4) 
 96   
 97          self._dataLoaded() 
 98          self.property_name_exists(propertyName) 
 99   
100          prop = None 
101          if ipv4 != None: 
102              props = self._data.getProperties(ipv4) 
103              if props != None and propertyName in props: 
104                  prop = props[propertyName] 
105   
106          return prop 
 107   
109          """ 
110          A set of all the possible property names. 
111          The set contains PropertyName objects that 
112          each have a string name and an associated  
113          data type. 
114          """ 
115          self._dataLoaded() 
116          return self._data.getPropertyNames() 
 117   
124   
133   
134      @staticmethod 
136          """ 
137          Normalise the keys in the passed in key value map. 
138          This lower-cases the keys, replaces "_" with "-" 
139          and removes any HTTP_ prefix. 
140          """ 
141          for headerName in keyVals: 
142              value = keyVals[headerName] 
143              del(keyVals[headerName]) 
144   
145              headerName = headerName.lower() 
146              headerName = headerName.replace('_', '-') 
147              headerName = headerName.replace('http-', '') 
148   
149              if type(value) == bytes: 
150                  value = value.decode("utf-8") 
151   
152              keyVals[headerName] = value 
153   
154          return keyVals 
 155   
156      @staticmethod 
158          """ 
159          Extracts and cleans an IP address from the headerValue. 
160          Some headers such as "X-Forwarded-For" can contain multiple 
161          IP addresses such as: 
162          clientIP, proxy1, proxy2... 
163          """ 
164          ip = None 
165          keyVals = CarrierApi._normaliseKeys(keyVals) 
166   
167          if keyVals != None: 
168              for headerName in CarrierApi._HEADERS_TO_CHECK: 
169                  if headerName not in keyVals: 
170                      continue 
171                  ip = CarrierApi.extract_ip(headerName, keyVals[headerName]) 
172                  if ip != None: 
173                      break 
174   
175          return ip 
 176   
182   
183      @staticmethod 
185          """ 
186          An IP address is considered public if it is not 
187          in any of the following ranges: 
188              1) any local address 
189                IP:  0 
190            
191              2) a local loopback address 
192                range:  127/8 
193              
194              3) a site local address i.e. IP is in any of the ranges: 
195                range:  10/8  
196                range:  172.16/12  
197                range:  192.168/16 
198              
199              4) a link local address  
200          """ 
201          try: 
202              f = unpack("!I", inet_aton(ipv4))[0] 
203          except(Exception) as ex: 
204              return False 
205   
206          for rg in CarrierApi._PRIVATE: 
207              if f & rg[1] == rg[0]: 
208                  return False 
209   
210          return True 
 211   
212      @staticmethod 
214          if headerValue != "" and headerValue != None: 
215              if headerName.lower() == 'x-forwarded-for': 
216                  parts = headerValue.split(',') 
217                  if parts != None: 
218                      headerValue = parts[0] 
219   
220              headerValue = headerValue.strip() 
221   
222              if headerValue != None and CarrierApi.is_public_ip(headerValue): 
223                  return headerValue 
224   
225          return None 
  226