Compare commits

..

No commits in common. "cf87b1352ababfc8f55ecf85a723e20d1ce343e1" and "bce37fe8c01f11ae8ea7cac944206fc3f819aa70" have entirely different histories.

4 changed files with 96 additions and 319 deletions

View File

@ -216,7 +216,6 @@ class Reticulum:
Reticulum.identitypath = Reticulum.configdir+"/storage/identities" Reticulum.identitypath = Reticulum.configdir+"/storage/identities"
Reticulum.__transport_enabled = False Reticulum.__transport_enabled = False
Reticulum.__remote_management_enabled = False
Reticulum.__use_implicit_proof = True Reticulum.__use_implicit_proof = True
Reticulum.__allow_probes = False Reticulum.__allow_probes = False
@ -347,7 +346,6 @@ class Reticulum:
self.is_standalone_instance = False self.is_standalone_instance = False
self.is_connected_to_shared_instance = True self.is_connected_to_shared_instance = True
Reticulum.__transport_enabled = False Reticulum.__transport_enabled = False
Reticulum.__remote_management_enabled = False
Reticulum.__allow_probes = False Reticulum.__allow_probes = False
RNS.log("Connected to locally available Reticulum instance via: "+str(interface), RNS.LOG_DEBUG) RNS.log("Connected to locally available Reticulum instance via: "+str(interface), RNS.LOG_DEBUG)
except Exception as e: except Exception as e:
@ -398,23 +396,6 @@ class Reticulum:
v = self.config["reticulum"].as_bool(option) v = self.config["reticulum"].as_bool(option)
if v == True: if v == True:
Reticulum.__transport_enabled = True Reticulum.__transport_enabled = True
if option == "enable_remote_management":
v = self.config["reticulum"].as_bool(option)
if v == True:
Reticulum.__remote_management_enabled = True
if option == "remote_management_allowed":
v = self.config["reticulum"].as_list(option)
for hexhash in v:
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(hexhash) != dest_len:
raise ValueError("Identity hash length for remote management ACL "+str(hexhash)+" is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2))
try:
allowed_hash = bytes.fromhex(hexhash)
except Exception as e:
raise ValueError("Invalid identity hash for remote management ACL: "+str(hexhash))
if not allowed_hash in RNS.Transport.remote_management_allowed:
RNS.Transport.remote_management_allowed.append(allowed_hash)
if option == "respond_to_probes": if option == "respond_to_probes":
v = self.config["reticulum"].as_bool(option) v = self.config["reticulum"].as_bool(option)
if v == True: if v == True:
@ -1194,8 +1175,7 @@ class Reticulum:
rpc_connection.send(self.get_interface_stats()) rpc_connection.send(self.get_interface_stats())
if path == "path_table": if path == "path_table":
mh = call["max_hops"] rpc_connection.send(self.get_path_table())
rpc_connection.send(self.get_path_table(max_hops=mh))
if path == "rate_table": if path == "rate_table":
rpc_connection.send(self.get_rate_table()) rpc_connection.send(self.get_rate_table())
@ -1341,23 +1321,21 @@ class Reticulum:
return stats return stats
def get_path_table(self, max_hops=None): def get_path_table(self):
if self.is_connected_to_shared_instance: if self.is_connected_to_shared_instance:
rpc_connection = multiprocessing.connection.Client(self.rpc_addr, authkey=self.rpc_key) rpc_connection = multiprocessing.connection.Client(self.rpc_addr, authkey=self.rpc_key)
rpc_connection.send({"get": "path_table", "max_hops": max_hops}) rpc_connection.send({"get": "path_table"})
response = rpc_connection.recv() response = rpc_connection.recv()
return response return response
else: else:
path_table = [] path_table = []
for dst_hash in RNS.Transport.destination_table: for dst_hash in RNS.Transport.destination_table:
path_hops = RNS.Transport.destination_table[dst_hash][2]
if max_hops == None or path_hops <= max_hops:
entry = { entry = {
"hash": dst_hash, "hash": dst_hash,
"timestamp": RNS.Transport.destination_table[dst_hash][0], "timestamp": RNS.Transport.destination_table[dst_hash][0],
"via": RNS.Transport.destination_table[dst_hash][1], "via": RNS.Transport.destination_table[dst_hash][1],
"hops": path_hops, "hops": RNS.Transport.destination_table[dst_hash][2],
"expires": RNS.Transport.destination_table[dst_hash][3], "expires": RNS.Transport.destination_table[dst_hash][3],
"interface": str(RNS.Transport.destination_table[dst_hash][5]), "interface": str(RNS.Transport.destination_table[dst_hash][5]),
} }
@ -1538,19 +1516,6 @@ class Reticulum:
""" """
return Reticulum.__transport_enabled return Reticulum.__transport_enabled
@staticmethod
def remote_management_enabled():
"""
Returns whether remote management is enabled for the
running instance.
When remote management is enabled, authenticated peers
can remotely query and manage this instance.
:returns: True if remote management is enabled, False if not.
"""
return Reticulum.__remote_management_enabled
@staticmethod @staticmethod
def probe_destination_enabled(): def probe_destination_enabled():
return Reticulum.__allow_probes return Reticulum.__allow_probes

View File

@ -110,7 +110,6 @@ class Transport:
# for control purposes like path requests # for control purposes like path requests
control_destinations = [] control_destinations = []
control_hashes = [] control_hashes = []
remote_management_allowed = []
# Interfaces for communicating with # Interfaces for communicating with
# local clients connected to a shared # local clients connected to a shared
@ -180,13 +179,6 @@ class Transport:
Transport.control_destinations.append(Transport.tunnel_synthesize_handler) Transport.control_destinations.append(Transport.tunnel_synthesize_handler)
Transport.control_hashes.append(Transport.tunnel_synthesize_destination.hash) Transport.control_hashes.append(Transport.tunnel_synthesize_destination.hash)
if RNS.Reticulum.remote_management_enabled() and not Transport.owner.is_connected_to_shared_instance:
Transport.remote_management_destination = RNS.Destination(Transport.identity, RNS.Destination.IN, RNS.Destination.SINGLE, Transport.APP_NAME, "remote", "management")
Transport.remote_management_destination.register_request_handler("/status", response_generator = Transport.remote_status_handler, allow = RNS.Destination.ALLOW_LIST, allowed_list=Transport.remote_management_allowed)
Transport.control_destinations.append(Transport.remote_management_destination)
Transport.control_hashes.append(Transport.remote_management_destination.hash)
RNS.log("Enabled remote management on "+str(Transport.remote_management_destination), RNS.LOG_NOTICE)
Transport.jobs_running = False Transport.jobs_running = False
thread = threading.Thread(target=Transport.jobloop, daemon=True) thread = threading.Thread(target=Transport.jobloop, daemon=True)
thread.start() thread.start()
@ -2255,25 +2247,6 @@ class Transport:
packet.send() packet.send()
Transport.path_requests[destination_hash] = time.time() Transport.path_requests[destination_hash] = time.time()
@staticmethod
def remote_status_handler(path, data, request_id, link_id, remote_identity, requested_at):
if remote_identity != None:
response = None
try:
if isinstance(data, list) and len(data) > 0:
response = []
response.append(Transport.owner.get_interface_stats())
if data[0] == True:
response.append(Transport.owner.get_link_count())
return response
except Exception as e:
RNS.log("An error occurred while processing remote status request from "+RNS.prettyhexrep(remote_identity), RNS.LOG_ERROR)
RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
return None
@staticmethod @staticmethod
def path_request_handler(data, packet): def path_request_handler(data, packet):
try: try:

View File

@ -30,7 +30,7 @@ import argparse
from RNS._version import __version__ from RNS._version import __version__
def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, timeout, drop_queues, drop_via, max_hops): def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, timeout, drop_queues, drop_via):
if table: if table:
destination_hash = None destination_hash = None
if destination_hexhash != None: if destination_hexhash != None:
@ -47,7 +47,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
sys.exit(1) sys.exit(1)
reticulum = RNS.Reticulum(configdir = configdir, loglevel = 3+verbosity) reticulum = RNS.Reticulum(configdir = configdir, loglevel = 3+verbosity)
table = sorted(reticulum.get_path_table(max_hops=max_hops), key=lambda e: (e["interface"], e["hops"]) ) table = sorted(reticulum.get_path_table(), key=lambda e: (e["interface"], e["hops"]) )
displayed = 0 displayed = 0
for path in table: for path in table:
@ -255,16 +255,6 @@ def main():
default=False default=False
) )
parser.add_argument(
"-m",
"--max",
action="store",
metavar="hops",
type=int,
help="maximum hops to filter path table by",
default=None
)
parser.add_argument( parser.add_argument(
"-r", "-r",
"--rates", "--rates",
@ -337,7 +327,6 @@ def main():
timeout = args.w, timeout = args.w,
drop_queues = args.drop_announces, drop_queues = args.drop_announces,
drop_via = args.drop_via, drop_via = args.drop_via,
max_hops = args.max,
) )
sys.exit(0) sys.exit(0)

View File

@ -23,9 +23,6 @@
# SOFTWARE. # SOFTWARE.
import RNS import RNS
import os
import sys
import time
import argparse import argparse
from RNS._version import __version__ from RNS._version import __version__
@ -49,130 +46,17 @@ def size_str(num, suffix='B'):
return "%.2f%s%s" % (num, last_unit, suffix) return "%.2f%s%s" % (num, last_unit, suffix)
request_result = None def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=False, astats=False, lstats=False, sorting=None, sort_reverse=False):
request_concluded = False
def get_remote_status(destination_hash, include_lstats, identity, no_output=False, timeout=RNS.Transport.PATH_REQUEST_TIMEOUT):
global request_result, request_concluded
link_count = None
if not RNS.Transport.has_path(destination_hash):
if not no_output:
print("Path to "+RNS.prettyhexrep(destination_hash)+" requested", end=" ")
sys.stdout.flush()
RNS.Transport.request_path(destination_hash)
pr_time = time.time()
while not RNS.Transport.has_path(destination_hash):
time.sleep(0.1)
if time.time() - pr_time > timeout:
if not no_output:
print("\r \r", end="")
print("Path request timed out")
exit(12)
remote_identity = RNS.Identity.recall(destination_hash)
def remote_link_closed(link):
if link.teardown_reason == RNS.Link.TIMEOUT:
if not no_output:
print("\r \r", end="")
print("The link timed out, exiting now")
elif link.teardown_reason == RNS.Link.DESTINATION_CLOSED:
if not no_output:
print("\r \r", end="")
print("The link was closed by the server, exiting now")
else:
if not no_output:
print("\r \r", end="")
print("Link closed unexpectedly, exiting now")
exit(10)
def request_failed(request_receipt):
global request_result, request_concluded
if not no_output:
print("\r \r", end="")
print("The remote status request failed. Likely authentication failure.")
request_concluded = True
def got_response(request_receipt):
global request_result, request_concluded
response = request_receipt.response
if isinstance(response, list):
status = response[0]
if len(response) > 1:
link_count = response[1]
else:
link_count = None
request_result = (status, link_count)
request_concluded = True
def remote_link_established(link):
if not no_output:
print("\r \r", end="")
print("Sending request...", end=" ")
sys.stdout.flush()
link.identify(identity)
link.request("/status", data = [include_lstats], response_callback = got_response, failed_callback = request_failed)
if not no_output:
print("\r \r", end="")
print("Establishing link with remote transport instance...", end=" ")
sys.stdout.flush()
remote_destination = RNS.Destination(remote_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, "rnstransport", "remote", "management")
link = RNS.Link(remote_destination)
link.set_link_established_callback(remote_link_established)
link.set_link_closed_callback(remote_link_closed)
while not request_concluded:
time.sleep(0.1)
if request_result != None:
print("\r \r", end="")
return request_result
def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=False, astats=False,
lstats=False, sorting=None, sort_reverse=False, remote=None, management_identity=None,
remote_timeout=RNS.Transport.PATH_REQUEST_TIMEOUT):
reticulum = RNS.Reticulum(configdir = configdir, loglevel = 3+verbosity) reticulum = RNS.Reticulum(configdir = configdir, loglevel = 3+verbosity)
link_count = None link_count = None
stats = None
if remote:
try:
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(remote) != dest_len:
raise ValueError("Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2))
try:
identity_hash = bytes.fromhex(remote)
destination_hash = RNS.Destination.hash_from_name_and_identity("rnstransport.remote.management", identity_hash)
except Exception as e:
raise ValueError("Invalid destination entered. Check your input.")
identity = RNS.Identity.from_file(os.path.expanduser(management_identity))
if identity == None:
raise ValueError("Could not load management identity from "+str(management_identity))
try:
remote_status = get_remote_status(destination_hash, lstats, identity, no_output=json, timeout=remote_timeout)
if remote_status != None:
stats, link_count = remote_status
except Exception as e:
raise e
except Exception as e:
print(str(e))
exit(20)
else:
if lstats: if lstats:
try: try:
link_count = reticulum.get_link_count() link_count = reticulum.get_link_count()
except Exception as e: except Exception as e:
pass pass
stats = None
try: try:
stats = reticulum.get_interface_stats() stats = reticulum.get_interface_stats()
except Exception as e: except Exception as e:
@ -343,7 +227,6 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
print("\n Transport Instance "+RNS.prettyhexrep(stats["transport_id"])+" running") print("\n Transport Instance "+RNS.prettyhexrep(stats["transport_id"])+" running")
if "probe_responder" in stats and stats["probe_responder"] != None: if "probe_responder" in stats and stats["probe_responder"] != None:
print(" Probe responder at "+RNS.prettyhexrep(stats["probe_responder"])+ " active") print(" Probe responder at "+RNS.prettyhexrep(stats["probe_responder"])+ " active")
if "transport_uptime" in stats and stats["transport_uptime"] != None:
print(" Uptime is "+RNS.prettytime(stats["transport_uptime"])+lstr) print(" Uptime is "+RNS.prettytime(stats["transport_uptime"])+lstr)
else: else:
if lstr != "": if lstr != "":
@ -352,10 +235,7 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
print("") print("")
else: else:
if not remote:
print("Could not get RNS status") print("Could not get RNS status")
else:
print("Could not get RNS status from remote transport instance "+RNS.prettyhexrep(identity_hash))
def main(): def main():
try: try:
@ -412,33 +292,6 @@ def main():
default=False default=False
) )
parser.add_argument(
"-R",
action="store",
metavar="hash",
help="transport identity hash of remote instance to get status from",
default=None,
type=str
)
parser.add_argument(
"-i",
action="store",
metavar="path",
help="path to identity used for remote management",
default=None,
type=str
)
parser.add_argument(
"-w",
action="store",
metavar="seconds",
type=float,
help="timeout before giving up on remote queries",
default=RNS.Transport.PATH_REQUEST_TIMEOUT
)
parser.add_argument('-v', '--verbose', action='count', default=0) parser.add_argument('-v', '--verbose', action='count', default=0)
parser.add_argument("filter", nargs="?", default=None, help="only display interfaces with names including filter", type=str) parser.add_argument("filter", nargs="?", default=None, help="only display interfaces with names including filter", type=str)
@ -460,9 +313,6 @@ def main():
lstats=args.link_stats, lstats=args.link_stats,
sorting=args.sort, sorting=args.sort,
sort_reverse=args.reverse, sort_reverse=args.reverse,
remote=args.R,
management_identity=args.i,
remote_timeout=args.w,
) )
except KeyboardInterrupt: except KeyboardInterrupt: