def __init__(self, config): self._config = config self._model = None self._epoch = Epoch(config) self._is_training = False self._training_epochs = 0 self._nn_path = self._config['ai']['path'] self._stats = Stats("%s.json" % os.path.splitext(self._nn_path)[0], self)
class AsyncTrainer(object): def __init__(self, config): self._config = config self._model = None self._epoch = Epoch(config) self._is_training = False self._training_epochs = 0 self._nn_path = self._config['ai']['path'] self._stats = Stats("%s.json" % os.path.splitext(self._nn_path)[0], self) def set_training(self, training, for_epochs=0): self._is_training = training self._training_epochs = for_epochs def is_training(self): return self._is_training def training_epochs(self): return self._training_epochs def start_ai(self): _thread.start_new_thread(self._ai_worker, ()) def _save_ai(self): core.log("[ai] saving model to %s ..." % self._nn_path) self._model.save(self._nn_path) def on_ai_step(self): self._model.env.render() if self._is_training: self._save_ai() self._stats.on_epoch(self._epoch.data(), self._is_training) def on_ai_training_step(self, _locals, _globals): self._model.env.render() def on_ai_policy(self, new_params): core.log("[ai] setting new policy:") for name, value in new_params.items(): if name in self._config['personality']: curr_value = self._config['personality'][name] if curr_value != value: core.log("[ai] ! %s: %s -> %s" % (name, curr_value, value)) self._config['personality'][name] = value else: core.log("[ai] param %s not in personality configuration!" % name) self.run('set wifi.ap.ttl %d' % self._config['personality']['ap_ttl']) self.run('set wifi.sta.ttl %d' % self._config['personality']['sta_ttl']) self.run('set wifi.rssi.min %d' % self._config['personality']['min_rssi']) def on_ai_best_reward(self, r): core.log("[ai] best reward so far: %s" % r) self._view.on_motivated(r) def on_ai_worst_reward(self, r): core.log("[ai] worst reward so far: %s" % r) self._view.on_demotivated(r) def _ai_worker(self): self._model = ai.load(self._config, self, self._epoch) if self._model: self.on_ai_ready() epochs_per_episode = self._config['ai']['epochs_per_episode'] obs = None while True: self._model.env.render() # enter in training mode? if random.random() > self._config['ai']['laziness']: core.log("[ai] learning for %d epochs ..." % epochs_per_episode) try: self.set_training(True, epochs_per_episode) self._model.learn(total_timesteps=epochs_per_episode, callback=self.on_ai_training_step) except Exception as e: core.log("[ai] error while training: %s" % e) finally: self.set_training(False) obs = self._model.env.reset() # init the first time elif obs is None: obs = self._model.env.reset() # run the inference action, _ = self._model.predict(obs) obs, _, _, _ = self._model.env.step(action)
def __init__(self, config, view): self._config = config self._view = view self._epoch = Epoch(config)
class Automata(object): def __init__(self, config, view): self._config = config self._view = view self._epoch = Epoch(config) def _on_miss(self, who): logging.info("it looks like %s is not in range anymore :/", who) self._epoch.track(miss=True) self._view.on_miss(who) def _on_error(self, who, e): # when we're trying to associate or deauth something that is not in range anymore # (if we are moving), we get the following error from bettercap: # error 400: 50:c7:bf:2e:d3:37 is an unknown BSSID or it is in the association skip list. if 'is an unknown BSSID' in str(e): self._on_miss(who) else: logging.error(e) def set_starting(self): self._view.on_starting() def set_ready(self): plugins.on('ready', self) def in_good_mood(self): return self._has_support_network_for(1.0) def _has_support_network_for(self, factor): bond_factor = self._config['personality']['bond_encounters_factor'] total_encounters = sum(peer.encounters for _, peer in self._peers.items()) support_factor = total_encounters / bond_factor return support_factor >= factor # triggered when it's a sad/bad day but you have good friends around ^_^ def set_grateful(self): self._view.on_grateful() plugins.on('grateful', self) def set_lonely(self): if not self._has_support_network_for(1.0): logging.info("unit is lonely") self._view.on_lonely() plugins.on('lonely', self) else: logging.info("unit is grateful instead of lonely") self.set_grateful() def set_bored(self): factor = self._epoch.inactive_for / self._config['personality'][ 'bored_num_epochs'] if not self._has_support_network_for(factor): logging.warning("%d epochs with no activity -> bored", self._epoch.inactive_for) self._view.on_bored() plugins.on('bored', self) else: logging.info("unit is grateful instead of bored") self.set_grateful() def set_sad(self): factor = self._epoch.inactive_for / self._config['personality'][ 'sad_num_epochs'] if not self._has_support_network_for(factor): logging.warning("%d epochs with no activity -> sad", self._epoch.inactive_for) self._view.on_sad() plugins.on('sad', self) else: logging.info("unit is grateful instead of sad") self.set_grateful() def set_angry(self, factor): if not self._has_support_network_for(factor): logging.warning("%d epochs with no activity -> angry", self._epoch.inactive_for) self._view.on_angry() plugins.on('angry', self) else: logging.info("unit is grateful instead of angry") self.set_grateful() def set_excited(self): logging.warning("%d epochs with activity -> excited", self._epoch.active_for) self._view.on_excited() plugins.on('excited', self) def set_rebooting(self): self._view.on_rebooting() plugins.on('rebooting', self) def wait_for(self, t, sleeping=True): plugins.on('sleep' if sleeping else 'wait', self, t) self._view.wait(t, sleeping) self._epoch.track(sleep=True, inc=t) def is_stale(self): return self._epoch.num_missed > self._config['personality'][ 'max_misses_for_recon'] def any_activity(self): return self._epoch.any_activity def next_epoch(self): logging.debug("agent.next_epoch()") was_stale = self.is_stale() did_miss = self._epoch.num_missed self._epoch.next() # after X misses during an epoch, set the status to lonely or angry if was_stale: factor = did_miss / self._config['personality'][ 'max_misses_for_recon'] if factor >= 2.0: self.set_angry(factor) else: logging.warning("agent missed %d interactions -> lonely", did_miss) self.set_lonely() # after X times being bored, the status is set to sad or angry elif self._epoch.sad_for: factor = self._epoch.inactive_for / self._config['personality'][ 'sad_num_epochs'] if factor >= 2.0: self.set_angry(factor) else: self.set_sad() # after X times being inactive, the status is set to bored elif self._epoch.bored_for: self.set_bored() # after X times being active, the status is set to happy / excited elif self._epoch.active_for >= self._config['personality'][ 'excited_num_epochs']: self.set_excited() elif self._epoch.active_for >= 5 and self._has_support_network_for( 5.0): self.set_grateful() plugins.on('epoch', self, self._epoch.epoch - 1, self._epoch.data()) if self._epoch.blind_for >= self._config['main'][ 'mon_max_blind_epochs']: logging.critical( "%d epochs without visible access points -> rebooting ...", self._epoch.blind_for) self._reboot() self._epoch.blind_for = 0