def _run_binary(self, inter, radius, grid_size=20): """Runs binary on area Args: @inter: the projected polygon in which we are running the binary attack algorithm @radius: the radius of the disk to perform the cuts """ vb.vb_print(self.verbose, "Running Binary", "UDP", True) last_inter_area = float('inf') while (inter.area > self.BINARY_STOP_AREA and self.attack_queries < self.query_limit): vb.vb_print(self.verbose, "Estimating cut", "UDP", True) # find projected coordinates that cut inter in half proj_coords = cells.cut(inter, self.proj, radius, grid_size) circle = Point(proj_coords[0], proj_coords[1]).buffer(radius * 1000) self.json_out["DUDP"].append({"query": self.attack_queries, "disk": self._log_kml("disk", circle), "active_area": self._log_kml("inter", inter), }) # calculate the coordinates for the new cut query (query_lon, query_lat) = self.proj(proj_coords[0], proj_coords[1], inverse=True) self._place_at_coords(self.attacker, query_lat, query_lon, self.test_id) if self.oracle is None: raise SystemExit("oracle should not be None after coverage") oracle_rspn = [None, None] attempts = 0 while oracle_rspn[0] is None: # ask the oracle if the victim is in proximity oracle_rspn = self.oracle.in_proximity(self.attacker, self.victim, self.test_id) # increase queries self.attack_queries += oracle_rspn[1] if oracle_rspn[0] is None and attempts > 5: self._update_attacker() attempts += 1 if oracle_rspn[0] is True: # if in proximity take the intersection inter_new = inter.intersection(circle) else: # else take the difference inter_new = inter.difference(circle) if inter_new.is_empty: print "\n\n\t ***WARNING!! EMPTY INTERSECTION***\n\n" inter = circle else: inter = inter_new # log kml self._log_kml("inter", inter) # if area is not reduced after intersection # break to avoid an infinite loop. area = inter.area if math.fabs(last_inter_area - area) < self.MIN_REDUCTION * area: vb.vb_print(self.verbose, "Area not significantly reduced ..stopping", "UDP", True) break else: last_inter_area = inter.area est_location = cells.poly_centroid(inter, self.proj) vb.vb_print(self.verbose, "Estimated Location: " + str(est_location), "UDP", True) real_est_distance = earth.distance_on_unit_sphere(self.victim.loc[0], self.victim.loc[1], est_location[0], est_location[1]) # convert to m real_est_distance *= 1000 vb.vb_print(self.verbose, "Distance from real loc: " + str(real_est_distance) + "m", "UDP", True) self.json_out["est_location"].append({"query": self.attack_queries, "area" : inter.area, "coords": [est_location[0], est_location[1]]}) self.json_out["real_location"].append({"query": -1, "coords": [self.victim.loc[0], self.victim.loc[1]]}) output_json = ''.join(os.getcwd() + "/" + self.JSON_DIR) output_json += self.service_name + "_UDP_" with open(output_json + str(self.test_id) + ".json", "w") as outfile: json.dump(self.json_out, outfile) return real_est_distance
def auditor_handled_place_at_coords(self, user, lat, lon, test_id, query_id=None): """Place a user of the auditing testsuite at [lat, lon] if that is allowed by the speed constraints Notice that @auditor_user is not the user passed by the inherited class but an instance of the AuditorUser class used by the auditing framework Args: user: the user to be placed in a new location (AuditorUser instance) dist: distance further from the user's location in km lat, lon: latitude & longitude test_id: the test_id of the test being run Return Value: Returns a tuple (@result, @queries) where @result is True or False depending on whether the location was updated successfully or not. @queries is the total queries towards the service required to perform the update. Raises: AuditorException(with optional log data) if inh. class raises it. AuditorExceptionUnknown in case an unknown error error occurs """ if not (isinstance(lat, float) and isinstance(lon, float)): raise TypeError("lat and lon parameters should be of type float!") # get the max distance the user is allowed to travel max_distance = self._get_max_distance(user) # get the distance of the current location with the new location if user.loc[0] is not None and user.loc[1] is not None: dist = earth.distance_on_unit_sphere(user.loc[0], user.loc[1], lat, lon) else: # it's our first update dist = 0 # If we have a speed limit and the distance is bigger than what # we are allowed to cross, sleep until we are allowed if dist > max_distance: sleep_time = (dist - max_distance) / self.speed_limit sleep(sleep_time + 1) try: # given that the clocks won't change and we don't # run stuff in parallel, have time as primary key if query_id is None: query_id = int(time()) # if we have full logging create query record # create it here in case any exception is raised if self.logging == const.LOG.ALL: query_info = "auditor_set_location: " query_info += "[" + str(lat) + "," + str(lon) + "]" self._db.insert_query(query_id, test_id, user.user_id, user.service_id, query_info) # do not catch any exceptions here, let the caller handle it set_loc_rspn = self.auditor_set_location(user.user, lat, lon) sleep(5) if len(set_loc_rspn) != 2: raise SystemExit("auditor_set_location must return a tuple!") (result, queries) = set_loc_rspn if not isinstance(result, bool) and not isinstance(queries, int): error = "Wrong return type: Expecting (bool, int) or None" raise TypeError(error) # if no exception was raised but we failed log it if result is False and self.logging == const.LOG.ALL: self._db.log_query_fail(query_id) except AuditorException: if self.logging == const.LOG.ALL: self._db.log_query_fail(query_id) # handle any data that has been passed by the user self._db.exception_recovery(query_id) # user has been removed from the pool already # so no need to update queries, just return return (False, 1) except Exception as exception: # remove user from active users self.users.remove(user.user) self._db.log_query_fail(query_id) # else raise exception and record failure raise AuditorExceptionUnknown(str(exception), user.user_id) user.update_queries(queries) user.loc = [lat, lon] return (result, queries)