From 76fcad0b5371fc6ae11d8b145305cca4851620d2 Mon Sep 17 00:00:00 2001 From: Mark Qvist Date: Thu, 3 Nov 2022 17:49:25 +0100 Subject: [PATCH] Added better I2P state visibility to rnstatus util --- RNS/Interfaces/I2PInterface.py | 57 +++++++++++++++++++++------------- RNS/Reticulum.py | 13 ++++++++ RNS/Transport.py | 5 ++- RNS/Utilities/rnstatus.py | 3 ++ 4 files changed, 55 insertions(+), 23 deletions(-) diff --git a/RNS/Interfaces/I2PInterface.py b/RNS/Interfaces/I2PInterface.py index 7c64f7b..22022ea 100644 --- a/RNS/Interfaces/I2PInterface.py +++ b/RNS/Interfaces/I2PInterface.py @@ -161,8 +161,6 @@ class I2PController: raise tn.status["exception"] else: - self.client_tunnels[i2p_destination] = True - owner.awaiting_i2p_tunnel = False if owner.socket != None: if hasattr(owner.socket, "close"): if callable(owner.socket.close): @@ -175,6 +173,8 @@ class I2PController: owner.socket.close() except Exception as e: RNS.log("Error while closing socket for "+str(owner)+": "+str(e)) + self.client_tunnels[i2p_destination] = True + owner.awaiting_i2p_tunnel = False RNS.log(str(owner)+" tunnel setup complete", RNS.LOG_VERBOSE) @@ -385,6 +385,10 @@ class I2PInterfacePeer(Interface): I2P_PROBES = 5 I2P_READ_TIMEOUT = (I2P_PROBE_INTERVAL * I2P_PROBES + I2P_PROBE_AFTER)*2 + TUNNEL_STATE_INIT = 0x00 + TUNNEL_STATE_ACTIVE = 0x01 + TUNNEL_STATE_STALE = 0x02 + def __init__(self, parent_interface, owner, name, target_i2p_dest=None, connected_socket=None, max_reconnect_tries=None): self.rxb = 0 self.txb = 0 @@ -413,6 +417,7 @@ class I2PInterfacePeer(Interface): self.last_read = 0 self.last_write = 0 self.wd_reset = False + self.i2p_tunnel_state = I2PInterfacePeer.TUNNEL_STATE_INIT self.ifac_size = self.parent_interface.ifac_size self.ifac_netname = self.parent_interface.ifac_netname @@ -478,7 +483,7 @@ class I2PInterfacePeer(Interface): RNS.log("Error while while configuring "+str(self)+": "+str(e), RNS.LOG_ERROR) RNS.log("Check that I2P is installed and running, and that SAM is enabled. Retrying tunnel setup later.", RNS.LOG_ERROR) - time.sleep(15) + time.sleep(8) thread = threading.Thread(target=tunnel_job) thread.daemon = True @@ -487,6 +492,7 @@ class I2PInterfacePeer(Interface): def wait_job(): while self.awaiting_i2p_tunnel: time.sleep(0.25) + time.sleep(2) if not self.kiss_framing: self.wants_tunnel = True @@ -664,23 +670,32 @@ class I2PInterfacePeer(Interface): while should_run and not self.wd_reset: time.sleep(1) - if (time.time()-self.last_write > I2PInterfacePeer.I2P_PROBE_AFTER*0.66): - self.processOutgoing(bytes([0x00])) + if (time.time()-self.last_read > I2PInterfacePeer.I2P_PROBE_AFTER*2): + self.i2p_tunnel_state = I2PInterfacePeer.TUNNEL_STATE_STALE + else: + self.i2p_tunnel_state = I2PInterfacePeer.TUNNEL_STATE_ACTIVE + + if (time.time()-self.last_write > I2PInterfacePeer.I2P_PROBE_AFTER*1): + try: + self.socket.sendall(bytes([HDLC.FLAG, HDLC.FLAG])) + except Exception as e: + RNS.log("An error ocurred while sending I2P keepalive. The contained exception was: "+str(e), RNS.LOG_ERROR) + self.shutdown_socket(self.socket) - if (time.time()-self.last_read > I2PInterfacePeer.I2P_READ_TIMEOUT): - RNS.log("I2P socket seems dead, restarting...", RNS.LOG_DEBUG) - if self.socket != None: - try: - self.socket.shutdown(socket.SHUT_RDWR) - except Exception as e: - RNS.log("Error while shutting down socket for "+str(self)+": "+str(e)) + # if (time.time()-self.last_read > I2PInterfacePeer.I2P_READ_TIMEOUT): + # RNS.log("I2P socket seems dead, restarting...", RNS.LOG_WARNING) + # if self.socket != None: + # try: + # self.socket.shutdown(socket.SHUT_RDWR) + # except Exception as e: + # RNS.log("Error while shutting down socket for "+str(self)+": "+str(e)) - try: - self.socket.close() - except Exception as e: - RNS.log("Error while closing socket for "+str(self)+": "+str(e)) + # try: + # self.socket.close() + # except Exception as e: + # RNS.log("Error while closing socket for "+str(self)+": "+str(e)) - should_run = False + # should_run = False finally: self.wd_reset = False @@ -701,7 +716,7 @@ class I2PInterfacePeer(Interface): data_in = self.socket.recv(4096) if len(data_in) > 0: pointer = 0 - last_read = time.time() + self.last_read = time.time() while pointer < len(data_in): byte = data_in[pointer] pointer += 1 @@ -710,8 +725,7 @@ class I2PInterfacePeer(Interface): # Read loop for KISS framing if (in_frame and byte == KISS.FEND and command == KISS.CMD_DATA): in_frame = False - if len(data_buffer) > RNS.Reticulum.HEADER_MINSIZE+1: - self.processIncoming(data_buffer) + self.processIncoming(data_buffer) elif (byte == KISS.FEND): in_frame = True command = KISS.CMD_UNKNOWN @@ -738,8 +752,7 @@ class I2PInterfacePeer(Interface): # Read loop for HDLC framing if (in_frame and byte == HDLC.FLAG): in_frame = False - if len(data_buffer) > RNS.Reticulum.HEADER_MINSIZE+1: - self.processIncoming(data_buffer) + self.processIncoming(data_buffer) elif (byte == HDLC.FLAG): in_frame = True data_buffer = b"" diff --git a/RNS/Reticulum.py b/RNS/Reticulum.py index f804431..f37d778 100755 --- a/RNS/Reticulum.py +++ b/RNS/Reticulum.py @@ -1073,6 +1073,19 @@ class Reticulum: else: ifstats["i2p_b32"] = None + if hasattr(interface, "i2p_tunnel_state"): + if interface.i2p_tunnel_state != None: + state_description = "Unknown State" + if interface.i2p_tunnel_state == I2PInterface.I2PInterfacePeer.TUNNEL_STATE_ACTIVE: + state_description = "Tunnel Active" + elif interface.i2p_tunnel_state == I2PInterface.I2PInterfacePeer.TUNNEL_STATE_INIT: + state_description = "Creating Tunnel" + elif interface.i2p_tunnel_state == I2PInterface.I2PInterfacePeer.TUNNEL_STATE_STALE: + state_description = "Tunnel Unresponsive" + ifstats["tunnelstate"] = state_description + else: + ifstats["tunnelstate"] = None + if hasattr(interface, "bitrate"): if interface.bitrate != None: ifstats["bitrate"] = interface.bitrate diff --git a/RNS/Transport.py b/RNS/Transport.py index 39f9c28..a6e89af 100755 --- a/RNS/Transport.py +++ b/RNS/Transport.py @@ -833,7 +833,7 @@ class Transport: def inbound(raw, interface=None): # If interface access codes are enabled, # we must authenticate each packet. - if len(raw) > 1: + if len(raw) > 2: if interface != None and hasattr(interface, "ifac_identity") and interface.ifac_identity != None: # Check that IFAC flag is set if raw[0] & 0x80 == 0x80: @@ -871,6 +871,9 @@ class Transport: # If the flag is set, drop the packet return + else: + return + while (Transport.jobs_running): sleep(0.0005) diff --git a/RNS/Utilities/rnstatus.py b/RNS/Utilities/rnstatus.py index 828ebe6..b2e071c 100644 --- a/RNS/Utilities/rnstatus.py +++ b/RNS/Utilities/rnstatus.py @@ -135,6 +135,9 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None): if "peers" in ifstat and ifstat["peers"] != None: print(" Peers : {np} reachable".format(np=ifstat["peers"])) + if "tunnelstate" in ifstat and ifstat["tunnelstate"] != None: + print(" I2P : {ts}".format(ts=ifstat["tunnelstate"])) + if "ifac_signature" in ifstat and ifstat["ifac_signature"] != None: sigstr = "<…"+RNS.hexrep(ifstat["ifac_signature"][-5:], delimit=False)+">" print(" Access : {nb}-bit IFAC by {sig}".format(nb=ifstat["ifac_size"]*8, sig=sigstr))