diff --git a/RNS/Reticulum.py b/RNS/Reticulum.py index 7abd988..a0db2a4 100755 --- a/RNS/Reticulum.py +++ b/RNS/Reticulum.py @@ -753,7 +753,14 @@ class Reticulum: if path == "packet_snr": rpc_connection.send(self.get_packet_snr(call["packet_hash"])) + if "drop" in call: + path = call["drop"] + + if path == "path": + rpc_connection.send(self.drop_path(call["destination_hash"])) + rpc_connection.close() + except Exception as e: RNS.log("An error ocurred while handling RPC call from local client: "+str(e), RNS.LOG_ERROR) @@ -834,6 +841,16 @@ class Reticulum: return path_table + def drop_path(self, destination): + if self.is_connected_to_shared_instance: + rpc_connection = multiprocessing.connection.Client(self.rpc_addr, authkey=self.rpc_key) + rpc_connection.send({"drop": "path", "destination_hash": destination}) + response = rpc_connection.recv() + return response + + else: + return RNS.Transport.expire_path(destination) + def get_next_hop_if_name(self, destination): if self.is_connected_to_shared_instance: rpc_connection = multiprocessing.connection.Client(self.rpc_addr, authkey=self.rpc_key) diff --git a/RNS/Transport.py b/RNS/Transport.py index cd1c838..1a12f07 100755 --- a/RNS/Transport.py +++ b/RNS/Transport.py @@ -1522,6 +1522,15 @@ class Transport: else: return None + @staticmethod + def expire_path(destination_hash): + if destination_hash in Transport.destination_table: + Transport.destination_table[destination_hash][0] = 0 + Transport.tables_last_culled = 0 + return True + else: + return False + @staticmethod def request_path(destination_hash): """ diff --git a/RNS/Utilities/rnpath.py b/RNS/Utilities/rnpath.py index bddba02..d49074e 100644 --- a/RNS/Utilities/rnpath.py +++ b/RNS/Utilities/rnpath.py @@ -30,7 +30,7 @@ import argparse from RNS._version import __version__ -def program_setup(configdir, table, destination_hexhash, verbosity): +def program_setup(configdir, table, drop, destination_hexhash, verbosity): if table: reticulum = RNS.Reticulum(configdir = configdir, loglevel = 3+verbosity) table = sorted(reticulum.get_path_table(), key=lambda e: (e["interface"], e["hops"]) ) @@ -39,6 +39,26 @@ def program_setup(configdir, table, destination_hexhash, verbosity): exp_str = RNS.timestamp_str(path["expires"]) print(RNS.prettyhexrep(path["hash"])+" is "+str(path["hops"])+" hops away via "+RNS.prettyhexrep(path["via"])+" on "+path["interface"]+" expires "+RNS.timestamp_str(path["expires"])) + elif drop: + try: + dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 + if len(destination_hexhash) != dest_len: + raise ValueError("Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + try: + destination_hash = bytes.fromhex(destination_hexhash) + except Exception as e: + raise ValueError("Invalid destination entered. Check your input.") + except Exception as e: + print(str(e)) + exit() + + reticulum = RNS.Reticulum(configdir = configdir, loglevel = 3+verbosity) + + if reticulum.drop_path(destination_hash): + print("Dropped path to "+RNS.prettyhexrep(destination_hash)) + else: + print("Unable to drop path to "+RNS.prettyhexrep(destination_hash)+". Does it exist?") + else: try: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 @@ -104,6 +124,14 @@ def main(): default=False ) + parser.add_argument( + "-d", + "--drop", + action="store_true", + help="remove the path to a destination", + default=False + ) + parser.add_argument( "destination", nargs="?", @@ -126,7 +154,13 @@ def main(): parser.print_help() print("") else: - program_setup(configdir = configarg, table = args.table, destination_hexhash = args.destination, verbosity = args.verbose) + program_setup( + configdir = configarg, + table = args.table, + drop = args.drop, + destination_hexhash = args.destination, + verbosity = args.verbose + ) except KeyboardInterrupt: print("")