Package mobi :: Package mtld :: Package da :: Package carrier :: Module carrier_api
[hide private]
[frames] | no frames]

Source Code for Module mobi.mtld.da.carrier.carrier_api

  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 * 
6 7 -class CarrierApi(object):
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
40 - def load_data_from_file(self, path):
41 """ 42 Load the data file from the provided path. The data file is reloaded 43 every tme this method is called. 44 """ 45 self._data = CarrierData() 46 self._data.load_data_from_file(path)
47 54
56 """ 57 Returns the data file creation date in ISO8601 format 58 """ 59 self._dataLoaded() 60 return self._data.getCreationDate()
61
62 - def get_data_file_version(self):
63 """ 64 Returns the version of the data file 65 """ 66 self._dataLoaded() 67 return self._data.getVersion()
68
69 - def get_properties(self, ipv4):
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
85 - def get_property(self, ipv4, propertyName):
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
108 - def get_property_names(self):
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
118 - def _dataLoaded(self):
119 """ 120 Checks to make sure the data file is loaded. 121 """ 122 if self._data is None: 123 raise DataFileException, self._MISSING_DATA_EX
124
125 - def _property_name_exists(self, propertyName):
126 """ 127 Check if the given propertyName is not None and exists 128 in the data file. Calls to this method must be sure that 129 the data object is already loaded. 130 """ 131 if propertyName not in self._data.getPropertyNamesAsStrings(): 132 raise InvalidPropertyNameException((self._INVALID_PROP_EX % propertyName))
133 134 @staticmethod
135 - def _normaliseKeys(keyVals):
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
157 - def get_ip(keyVals):
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
177 - def property_name_exists(self, propertyName):
178 property_names = self._data.getPropertyNamesAsStrings() 179 180 if(property_names == None or not propertyName in property_names): 181 raise InvalidPropertyNameException((self._INVALID_PROP_EX % propertyName))
182 183 @staticmethod
184 - def is_public_ip(ipv4):
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
213 - def extract_ip(headerName, headerValue):
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