diff --git a/RNS/Identity.py b/RNS/Identity.py index 4c86bc15..c105d482 100644 --- a/RNS/Identity.py +++ b/RNS/Identity.py @@ -602,21 +602,18 @@ class Identity: signal_str = " [" if packet.rssi != None: signal_str += "RSSI "+str(packet.rssi)+"dBm" - if packet.snr != None: - signal_str += ", " - if packet.snr != None: - signal_str += "SNR "+str(packet.snr)+"dB" + if packet.snr != None: signal_str += ", " + if packet.snr != None: signal_str += "SNR "+str(packet.snr)+"dB" signal_str += "]" - else: - signal_str = "" + + else: signal_str = "" if hasattr(packet, "transport_id") and packet.transport_id != None: RNS.log("Valid announce for "+RNS.prettyhexrep(destination_hash)+" "+str(packet.hops)+" hops away, received via "+RNS.prettyhexrep(packet.transport_id)+" on "+str(packet.receiving_interface)+signal_str, RNS.LOG_EXTREME) if RNS.sl(RNS.LOG_EXTREME) else None else: RNS.log("Valid announce for "+RNS.prettyhexrep(destination_hash)+" "+str(packet.hops)+" hops away, received on "+str(packet.receiving_interface)+signal_str, RNS.LOG_EXTREME) if RNS.sl(RNS.LOG_EXTREME) else None - if ratchet: - Identity._remember_ratchet(destination_hash, ratchet) + if ratchet: Identity._remember_ratchet(destination_hash, ratchet) return True diff --git a/RNS/Link.py b/RNS/Link.py index 1eef1947..e2fb4505 100644 --- a/RNS/Link.py +++ b/RNS/Link.py @@ -191,8 +191,7 @@ class Link: if len(data) == Link.ECPUBSIZE+Link.LINK_MTU_SIZE: RNS.log("Link request includes MTU signalling", RNS.LOG_DEBUG) # TODO: Remove debug - try: - link.mtu = Link.mtu_from_lr_packet(packet) or Reticulum.MTU + try: link.mtu = Link.mtu_from_lr_packet(packet) or Reticulum.MTU except Exception as e: RNS.trace_exception(e) link.mtu = RNS.Reticulum.MTU @@ -277,6 +276,7 @@ class Link: self.initiator = False self.prv = X25519PrivateKey.generate() self.sig_prv = self.owner.identity.sig_prv + else: self.initiator = True self.expected_hops = RNS.Transport.hops_to(self.destination.hash) @@ -296,14 +296,11 @@ class Link: if peer_pub_bytes == None: self.peer_pub = None self.peer_pub_bytes = None - else: - self.load_peer(peer_pub_bytes, peer_sig_pub_bytes) - if established_callback != None: - self.set_link_established_callback(established_callback) + else: self.load_peer(peer_pub_bytes, peer_sig_pub_bytes) - if closed_callback != None: - self.set_link_closed_callback(closed_callback) + if established_callback != None: self.set_link_established_callback(established_callback) + if closed_callback != None: self.set_link_closed_callback(closed_callback) if self.initiator: signalling_bytes = b"" @@ -334,8 +331,7 @@ class Link: self.peer_sig_pub_bytes = peer_sig_pub_bytes self.peer_sig_pub = Ed25519PublicKey.from_public_bytes(self.peer_sig_pub_bytes) - if not hasattr(self.peer_pub, "curve"): - self.peer_pub.curve = Link.CURVE + if not hasattr(self.peer_pub, "curve"): self.peer_pub.curve = Link.CURVE @staticmethod def link_id_from_lr_packet(packet): @@ -447,8 +443,8 @@ class Link: thread = threading.Thread(target=self.callbacks.link_established, args=(self,)) thread.daemon = True thread.start() - else: - RNS.log("Invalid link proof signature received by "+str(self)+". Ignoring.", RNS.LOG_DEBUG) + + else: RNS.log("Invalid link proof signature received by "+str(self)+". Ignoring.", RNS.LOG_DEBUG) except Exception as e: self.status = Link.CLOSED @@ -497,35 +493,21 @@ class Link: request_packet = RNS.Packet(self, packed_request, RNS.Packet.DATA, context = RNS.Packet.REQUEST) packet_receipt = request_packet.send() - if packet_receipt == False: - return False + if packet_receipt == False: return False else: packet_receipt.set_timeout(timeout) - return RequestReceipt( - self, - packet_receipt = packet_receipt, - response_callback = response_callback, - failed_callback = failed_callback, - progress_callback = progress_callback, - timeout = timeout, - request_size = len(packed_request), - ) + return RequestReceipt(self, packet_receipt = packet_receipt, response_callback = response_callback, + failed_callback = failed_callback, progress_callback = progress_callback, + timeout = timeout, request_size = len(packed_request)) else: request_id = RNS.Identity.truncated_hash(packed_request) RNS.log("Sending request "+RNS.prettyhexrep(request_id)+" as resource.", RNS.LOG_DEBUG) request_resource = RNS.Resource(packed_request, self, request_id = request_id, is_response = False, timeout = timeout) - return RequestReceipt( - self, - resource = request_resource, - response_callback = response_callback, - failed_callback = failed_callback, - progress_callback = progress_callback, - timeout = timeout, - request_size = len(packed_request), - ) - + return RequestReceipt(self, resource = request_resource, response_callback = response_callback, + failed_callback = failed_callback, progress_callback = progress_callback, + timeout = timeout, request_size = len(packed_request)) def update_mdu(self): self.mdu = self.mtu - RNS.Reticulum.HEADER_MAXSIZE - RNS.Reticulum.IFAC_MIN_SIZE @@ -547,10 +529,8 @@ class Link: self.__update_keepalive() try: - if self.owner.callbacks.link_established != None: - self.owner.callbacks.link_established(self) - except Exception as e: - RNS.log("Error occurred in external link establishment callback. The contained exception was: "+str(e), RNS.LOG_ERROR) + if self.owner.callbacks.link_established != None: self.owner.callbacks.link_established(self) + except Exception as e: RNS.log("Error occurred in external link establishment callback. The contained exception was: "+str(e), RNS.LOG_ERROR) except Exception as e: RNS.log("Error occurred while processing RTT packet, tearing down link. The contained exception was: "+str(e), RNS.LOG_ERROR) @@ -565,73 +545,57 @@ class Link: :param track: Whether or not to keep track of physical layer statistics. Value must be ``True`` or ``False``. """ - if track: - self.__track_phy_stats = True - else: - self.__track_phy_stats = False + if track: self.__track_phy_stats = True + else: self.__track_phy_stats = False def get_rssi(self): """ :returns: The physical layer *Received Signal Strength Indication* if available, otherwise ``None``. Physical layer statistics must be enabled on the link for this method to return a value. """ - if self.__track_phy_stats: - return self.rssi - else: - return None + if self.__track_phy_stats: return self.rssi + else: return None def get_snr(self): """ :returns: The physical layer *Signal-to-Noise Ratio* if available, otherwise ``None``. Physical layer statistics must be enabled on the link for this method to return a value. """ - if self.__track_phy_stats: - return self.snr - else: - return None + if self.__track_phy_stats: return self.snr + else: return None def get_q(self): """ :returns: The physical layer *Link Quality* if available, otherwise ``None``. Physical layer statistics must be enabled on the link for this method to return a value. """ - if self.__track_phy_stats: - return self.q - else: - return None + if self.__track_phy_stats: return self.q + else: return None def get_establishment_rate(self): """ :returns: The data transfer rate at which the link establishment procedure ocurred, in bits per second. """ - if self.establishment_rate != None: - return self.establishment_rate*8 - else: - return None + if self.establishment_rate != None: return self.establishment_rate*8 + else: return None def get_mtu(self): """ :returns: The MTU of an established link. """ - if self.status == Link.ACTIVE: - return self.mtu - else: - return None + if self.status == Link.ACTIVE: return self.mtu + else: return None def get_mdu(self): """ :returns: The packet MDU of an established link. """ - if self.status == Link.ACTIVE: - return self.mdu - else: - return None + if self.status == Link.ACTIVE: return self.mdu + else: return None def get_expected_rate(self): """ :returns: The packet expected in-flight data rate of an established link. """ - if self.status == Link.ACTIVE: - return self.expected_rate - else: - return None + if self.status == Link.ACTIVE: return self.expected_rate + else: return None def get_mode(self): """ @@ -649,10 +613,8 @@ class Link: """ :returns: The time in seconds since this link was established. """ - if self.activated_at: - return time.time() - self.activated_at - else: - return None + if self.activated_at: return time.time() - self.activated_at + else: return None def no_inbound_for(self): """ @@ -712,14 +674,11 @@ class Link: plaintext = self.decrypt(packet.data) if plaintext == self.link_id: self.status = Link.CLOSED - if self.initiator: - self.teardown_reason = Link.DESTINATION_CLOSED - else: - self.teardown_reason = Link.INITIATOR_CLOSED + if self.initiator: self.teardown_reason = Link.DESTINATION_CLOSED + else: self.teardown_reason = Link.INITIATOR_CLOSED self.__update_phy_stats(packet) self.link_closed() - except Exception as e: - pass + except Exception as e: pass def link_closed(self): for resource in self.incoming_resources: resource.cancel() @@ -752,9 +711,7 @@ class Link: while not self.status == Link.CLOSED: while (self.watchdog_lock): rtt_wait = 0.025 - if hasattr(self, "rtt") and self.rtt: - rtt_wait = self.rtt - + if hasattr(self, "rtt") and self.rtt: rtt_wait = self.rtt sleep(max(rtt_wait, 0.025)) if not self.status == Link.CLOSED: @@ -779,10 +736,8 @@ class Link: self.link_closed() sleep_time = 0.001 - if self.initiator: - RNS.log("Timeout waiting for link request proof", RNS.LOG_DEBUG) - else: - RNS.log("Timeout waiting for RTT packet from link initiator", RNS.LOG_DEBUG) + if self.initiator: RNS.log("Timeout waiting for link request proof", RNS.LOG_DEBUG) + else: RNS.log("Timeout waiting for RTT packet from link initiator", RNS.LOG_DEBUG) elif self.status == Link.ACTIVE: activated_at = self.activated_at if self.activated_at != None else 0 @@ -796,11 +751,10 @@ class Link: if time.time() >= last_inbound + self.stale_time: sleep_time = self.rtt * self.keepalive_timeout_factor + Link.STALE_GRACE self.status = Link.STALE - else: - sleep_time = self.keepalive + + else: sleep_time = self.keepalive - else: - sleep_time = (last_inbound + self.keepalive) - time.time() + else: sleep_time = (last_inbound + self.keepalive) - time.time() elif self.status == Link.STALE: sleep_time = 0.001 @@ -810,8 +764,7 @@ class Link: self.link_closed() - if sleep_time == 0: - RNS.log("Warning! Link watchdog sleep time of 0!", RNS.LOG_ERROR) + if sleep_time == 0: RNS.log("Warning! Link watchdog sleep time of 0!", RNS.LOG_ERROR) if sleep_time == None or sleep_time < 0: RNS.log("Timing error! Tearing down link "+str(self)+" now.", RNS.LOG_ERROR) self.teardown() @@ -825,7 +778,6 @@ class Link: self.snr = None self.q = None - def __update_phy_stats(self, packet, query_shared = True, force_update = False): if self.__track_phy_stats or force_update: if query_shared: @@ -834,12 +786,9 @@ class Link: if packet.snr == None: packet.snr = reticulum.get_packet_snr(packet.packet_hash) if packet.q == None: packet.q = reticulum.get_packet_q(packet.packet_hash) - if packet.rssi != None: - self.rssi = packet.rssi - if packet.snr != None: - self.snr = packet.snr - if packet.q != None: - self.q = packet.q + if packet.rssi != None: self.rssi = packet.rssi + if packet.snr != None: self.snr = packet.snr + if packet.q != None: self.q = packet.q def __update_keepalive(self): self.keepalive = max(min(self.rtt*(Link.KEEPALIVE_MAX/Link.KEEPALIVE_MAX_RTT), Link.KEEPALIVE_MAX), Link.KEEPALIVE_MIN) @@ -933,8 +882,8 @@ class Link: def job(): self.handle_request(request_id, request_data) threading.Thread(target=job, daemon=True).start() - else: - RNS.log("Incoming request resource failed with status: "+RNS.hexrep([resource.status]), RNS.LOG_DEBUG) + + else: RNS.log("Incoming request resource failed with status: "+RNS.hexrep([resource.status]), RNS.LOG_DEBUG) def response_resource_concluded(self, resource): if resource.status == RNS.Resource.COMPLETE: @@ -965,8 +914,7 @@ class Link: :return: ``Channel`` object """ - if self._channel is None: - self._channel = Channel(LinkChannelOutlet(self)) + if self._channel is None: self._channel = Channel(LinkChannelOutlet(self)) return self._channel def receive(self, packet): @@ -976,12 +924,10 @@ class Link: RNS.log(f"Link-associated packet received on unexpected interface {packet.receiving_interface} instead of {self.attached_interface}! Someone might be trying to manipulate your communication!", RNS.LOG_ERROR) else: self.last_inbound = time.time() - if packet.context != RNS.Packet.KEEPALIVE: - self.last_data = self.last_inbound + if packet.context != RNS.Packet.KEEPALIVE: self.last_data = self.last_inbound self.rx += 1 self.rxbytes += len(packet.data) - if self.status == Link.STALE: - self.status = Link.ACTIVE + if self.status == Link.STALE: self.status = Link.ACTIVE if packet.packet_type == RNS.Packet.DATA: should_query = False @@ -1002,10 +948,8 @@ class Link: elif self.destination.proof_strategy == RNS.Destination.PROVE_APP: if self.destination.callbacks.proof_requested: try: - if self.destination.callbacks.proof_requested(packet): - packet.prove() - except Exception as e: - RNS.log("Error while executing proof request callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + if self.destination.callbacks.proof_requested(packet): packet.prove() + except Exception as e: RNS.log("Error while executing proof request callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) elif packet.context == RNS.Packet.LINKIDENTIFY: plaintext = self.decrypt(packet.data) @@ -1039,8 +983,7 @@ class Link: def job(): self.handle_request(request_id, unpacked_request) threading.Thread(target=job, daemon=True).start() self.__update_phy_stats(packet, query_shared=True) - except Exception as e: - RNS.log("Error occurred while handling request. The contained exception was: "+str(e), RNS.LOG_ERROR) + except Exception as e: RNS.log("Error occurred while handling request. The contained exception was: "+str(e), RNS.LOG_ERROR) elif packet.context == RNS.Packet.RESPONSE: try: @@ -1053,8 +996,7 @@ class Link: def job(): self.handle_response(request_id, response_data, transfer_size, transfer_size, update_sizes=True) threading.Thread(target=job, daemon=True).start() self.__update_phy_stats(packet, query_shared=True) - except Exception as e: - RNS.log("Error occurred while handling response. The contained exception was: "+str(e), RNS.LOG_ERROR) + except Exception as e: RNS.log("Error occurred while handling response. The contained exception was: "+str(e), RNS.LOG_ERROR) elif packet.context == RNS.Packet.LRRTT: if not self.initiator: @@ -1186,7 +1128,6 @@ class Link: self.watchdog_lock = False - def encrypt(self, plaintext): try: if not self.token: @@ -1201,7 +1142,6 @@ class Link: RNS.log("Encryption on link "+str(self)+" failed. The contained exception was: "+str(e), RNS.LOG_ERROR) raise e - def decrypt(self, ciphertext): try: if not self.token: self.token = Token(self.derived_key) @@ -1211,7 +1151,6 @@ class Link: RNS.log("Decryption failed on link "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) return None - def sign(self, message): return self.sig_prv.sign(message) @@ -1219,8 +1158,7 @@ class Link: try: self.peer_sig_pub.verify(signature, message) return True - except Exception as e: - return False + except Exception as e: return False def set_link_established_callback(self, callback): self.callbacks.link_established = callback @@ -1388,7 +1326,6 @@ class RequestReceipt(): self.link.pending_requests.append(self) - def request_resource_concluded(self, resource): if resource.status == RNS.Resource.COMPLETE: RNS.log("Request "+RNS.prettyhexrep(self.request_id)+" successfully sent as resource.", RNS.LOG_DEBUG) @@ -1411,7 +1348,6 @@ class RequestReceipt(): except Exception as e: RNS.log("Error while executing request failed callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) - def __response_timeout_job(self): while self.status == RequestReceipt.DELIVERED: now = time.time() @@ -1421,7 +1357,6 @@ class RequestReceipt(): time.sleep(0.1) - def request_timed_out(self, packet_receipt): if self in self.link.pending_requests and self.status == RequestReceipt.DELIVERED: self.status = RequestReceipt.FAILED @@ -1430,9 +1365,7 @@ class RequestReceipt(): if self.callbacks.failed != None: try: self.callbacks.failed(self) - except Exception as e: - RNS.log("Error while executing request timed out callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) - + except Exception as e: RNS.log("Error while executing request timed out callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) def response_resource_progress(self, resource): if resource != None: @@ -1449,13 +1382,10 @@ class RequestReceipt(): self.progress = resource.get_progress() if self.callbacks.progress != None: - try: - self.callbacks.progress(self) - except Exception as e: - RNS.log("Error while executing response progress callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) - else: - resource.cancel() - + try: self.callbacks.progress(self) + except Exception as e: RNS.log("Error while executing response progress callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + + else: resource.cancel() def response_received(self, response, metadata=None): if not self.status == RequestReceipt.FAILED: @@ -1474,13 +1404,11 @@ class RequestReceipt(): if self.callbacks.progress != None: try: self.callbacks.progress(self) - except Exception as e: - RNS.log("Error while executing response progress callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + except Exception as e: RNS.log("Error while executing response progress callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) if self.callbacks.response != None: try: self.callbacks.response(self) - except Exception as e: - RNS.log("Error while executing response received callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + except Exception as e: RNS.log("Error while executing response received callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) def get_request_id(self): """ @@ -1504,31 +1432,23 @@ class RequestReceipt(): """ :returns: The response as *bytes* if it is ready, otherwise *None*. """ - if self.status == RequestReceipt.READY: - return self.response - else: - return None + if self.status == RequestReceipt.READY: return self.response + else: return None def get_response_time(self): """ :returns: The response time of the request in seconds. """ - if self.status == RequestReceipt.READY: - return self.response_concluded_at - self.started_at - else: - return None + if self.status == RequestReceipt.READY: return self.response_concluded_at - self.started_at + else: return None def concluded(self): """ :returns: True if the associated request has concluded (successfully or with a failure), otherwise False. """ - if self.status == RequestReceipt.READY: - return True - elif self.status == RequestReceipt.FAILED: - return True - else: - return False - + if self.status == RequestReceipt.READY: return True + elif self.status == RequestReceipt.FAILED: return True + else: return False class RequestReceiptCallbacks: diff --git a/RNS/Packet.py b/RNS/Packet.py index 053d9fbf..761af5fc 100755 --- a/RNS/Packet.py +++ b/RNS/Packet.py @@ -313,51 +313,40 @@ class Packet: # encrypted destinations self.pack() - if RNS.Transport.outbound(self): - return self.receipt + if RNS.Transport.outbound(self): return self.receipt else: RNS.log("Re-send failed. No interfaces could process the outbound packet", RNS.LOG_WARNING) self.sent = False self.receipt = None return False - else: - raise IOError("Packet was not sent yet") + + else: raise IOError("Packet was not sent yet") def prove(self, destination=None): if self.fromPacked and hasattr(self, "destination") and self.destination: if self.destination.identity and self.destination.identity.prv: self.destination.identity.prove(self, destination) - elif self.fromPacked and hasattr(self, "link") and self.link: - self.link.prove_packet(self) - else: - RNS.log("Could not prove packet associated with neither a destination nor a link", RNS.LOG_ERROR) + elif self.fromPacked and hasattr(self, "link") and self.link: self.link.prove_packet(self) + else: RNS.log("Could not prove packet associated with neither a destination nor a link", RNS.LOG_ERROR) # Generates a special destination that allows Reticulum # to direct the proof back to the proved packet's sender - def generate_proof_destination(self): - return ProofDestination(self) + def generate_proof_destination(self): return ProofDestination(self) - def validate_proof_packet(self, proof_packet): - return self.receipt.validate_proof_packet(proof_packet) + def validate_proof_packet(self, proof_packet): return self.receipt.validate_proof_packet(proof_packet) - def validate_proof(self, proof): - return self.receipt.validate_proof(proof) + def validate_proof(self, proof): return self.receipt.validate_proof(proof) - def update_hash(self): - self.packet_hash = self.get_hash() + def update_hash(self): self.packet_hash = self.get_hash() - def get_hash(self): - return RNS.Identity.full_hash(self.get_hashable_part()) + def get_hash(self): return RNS.Identity.full_hash(self.get_hashable_part()) - def getTruncatedHash(self): - return RNS.Identity.truncated_hash(self.get_hashable_part()) + def getTruncatedHash(self): return RNS.Identity.truncated_hash(self.get_hashable_part()) def get_hashable_part(self): hashable_part = bytes([self.raw[0] & 0b00001111]) - if self.header_type == Packet.HEADER_2: - hashable_part += self.raw[(RNS.Identity.TRUNCATED_HASHLENGTH//8)+2:] - else: - hashable_part += self.raw[2:] + if self.header_type == Packet.HEADER_2: hashable_part += self.raw[(RNS.Identity.TRUNCATED_HASHLENGTH//8)+2:] + else: hashable_part += self.raw[2:] return hashable_part @@ -365,36 +354,29 @@ class Packet: """ :returns: The physical layer *Received Signal Strength Indication* if available, otherwise ``None``. """ - if self.rssi != None: - return self.rssi - else: - return reticulum.get_packet_rssi(self.packet_hash) + if self.rssi != None: return self.rssi + else: return reticulum.get_packet_rssi(self.packet_hash) def get_snr(self): """ :returns: The physical layer *Signal-to-Noise Ratio* if available, otherwise ``None``. """ - if self.snr != None: - return self.snr - else: - return reticulum.get_packet_snr(self.packet_hash) + if self.snr != None: return self.snr + else: return reticulum.get_packet_snr(self.packet_hash) def get_q(self): """ :returns: The physical layer *Link Quality* if available, otherwise ``None``. """ - if self.q != None: - return self.q - else: - return reticulum.get_packet_q(self.packet_hash) + if self.q != None: return self.q + else: return reticulum.get_packet_q(self.packet_hash) class ProofDestination: def __init__(self, packet): self.hash = packet.get_hash()[:RNS.Reticulum.TRUNCATED_HASHLENGTH//8]; self.type = RNS.Destination.SINGLE - def encrypt(self, plaintext): - return plaintext + def encrypt(self, plaintext): return plaintext class PacketReceipt: @@ -463,18 +445,17 @@ class PacketReceipt: link.last_proof = self.concluded_at if self.callbacks.delivery != None: - try: - self.callbacks.delivery(self) + try: self.callbacks.delivery(self) except Exception as e: RNS.log("An error occurred while evaluating external delivery callback for "+str(link), RNS.LOG_ERROR) RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) RNS.trace_exception(e) return True - else: - return False - else: - return False + + else: return False + else: return False + elif len(proof) == PacketReceipt.IMPL_LENGTH: pass # TODO: Why is this disabled? @@ -491,8 +472,7 @@ class PacketReceipt: # else: # RNS.log("invalid") # return False - else: - return False + else: return False # Validate a raw proof def validate_proof(self, proof, proof_packet=None): @@ -509,24 +489,20 @@ class PacketReceipt: self.proof_packet = proof_packet if self.callbacks.delivery != None: - try: - self.callbacks.delivery(self) + try: self.callbacks.delivery(self) except Exception as e: RNS.log("Error while executing proof validated callback. The contained exception was: "+str(e), RNS.LOG_ERROR) return True - else: - return False - else: - return False + + else: return False + else: return False + elif len(proof) == PacketReceipt.IMPL_LENGTH: # This is an implicit proof - if not hasattr(self.destination, "identity"): - return False - - if self.destination.identity == None: - return False + if not hasattr(self.destination, "identity"): return False + if self.destination.identity == None: return False signature = proof[:RNS.Identity.SIGLENGTH//8] proof_valid = self.destination.identity.validate(signature, self.hash) @@ -537,16 +513,13 @@ class PacketReceipt: self.proof_packet = proof_packet if self.callbacks.delivery != None: - try: - self.callbacks.delivery(self) - except Exception as e: - RNS.log("Error while executing proof validated callback. The contained exception was: "+str(e), RNS.LOG_ERROR) + try: self.callbacks.delivery(self) + except Exception as e: RNS.log("Error while executing proof validated callback. The contained exception was: "+str(e), RNS.LOG_ERROR) return True - else: - return False - else: - return False + + else: return False + else: return False def get_rtt(self): """ @@ -559,10 +532,8 @@ class PacketReceipt: def check_timeout(self): if self.status == PacketReceipt.SENT and self.is_timed_out(): - if self.timeout == -1: - self.status = PacketReceipt.CULLED - else: - self.status = PacketReceipt.FAILED + if self.timeout == -1: self.status = PacketReceipt.CULLED + else: self.status = PacketReceipt.FAILED self.concluded_at = time.time() diff --git a/RNS/Resolver.py b/RNS/Resolver.py index fa514a4f..9f0b1a52 100644 --- a/RNS/Resolver.py +++ b/RNS/Resolver.py @@ -31,5 +31,4 @@ class Resolver: @staticmethod - def resolve_identity(full_name): - pass \ No newline at end of file + def resolve_identity(full_name): pass \ No newline at end of file diff --git a/RNS/Reticulum.py b/RNS/Reticulum.py index a93f97ec..d944ed0d 100755 --- a/RNS/Reticulum.py +++ b/RNS/Reticulum.py @@ -253,6 +253,7 @@ class Reticulum: Reticulum.__network_identity = None Reticulum.__transport_enabled = False Reticulum.__static_transport_identity = False + Reticulum.__local_hops_delta = False Reticulum.__link_mtu_discovery = Reticulum.LINK_MTU_DISCOVERY Reticulum.__remote_management_enabled = False Reticulum.__use_implicit_proof = True @@ -387,11 +388,7 @@ class Reticulum: def __start_local_interface(self): if self.share_instance: try: - interface = LocalInterface.LocalServerInterface( - RNS.Transport, - self.local_interface_port, - socket_path=self.local_socket_path - ) + interface = LocalInterface.LocalServerInterface(RNS.Transport, self.local_interface_port, socket_path=self.local_socket_path) interface.OUT = True if hasattr(Reticulum, "_force_shared_instance_bitrate"): interface.bitrate = Reticulum._force_shared_instance_bitrate @@ -433,6 +430,7 @@ class Reticulum: Reticulum.__remote_management_enabled = False Reticulum.__allow_probes = False RNS.log("Connected to locally available Reticulum instance via: "+str(interface), RNS.LOG_DEBUG) + except Exception as e: RNS.log("Local shared instance appears to be running, but it could not be connected", RNS.LOG_ERROR) RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) @@ -505,6 +503,10 @@ class Reticulum: v = self.config["reticulum"].as_bool(option) if v == True: Reticulum.__static_transport_identity = True + if option == "local_hops_delta": + v = self.config["reticulum"].as_bool(option) + if v == True: Reticulum.__local_hops_delta = True + if option == "network_identity": if Reticulum.__network_identity == None: path = self.config["reticulum"][option] @@ -737,24 +739,19 @@ class Reticulum: ifac_size = None if "ifac_size" in c: - if c.as_int("ifac_size") >= Reticulum.IFAC_MIN_SIZE*8: - ifac_size = c.as_int("ifac_size")//8 + if c.as_int("ifac_size") >= Reticulum.IFAC_MIN_SIZE*8: ifac_size = c.as_int("ifac_size")//8 ifac_netname = None if "networkname" in c: - if c["networkname"] != "": - ifac_netname = c["networkname"] + if c["networkname"] != "": ifac_netname = c["networkname"] if "network_name" in c: - if c["network_name"] != "": - ifac_netname = c["network_name"] + if c["network_name"] != "": ifac_netname = c["network_name"] ifac_netkey = None if "passphrase" in c: - if c["passphrase"] != "": - ifac_netkey = c["passphrase"] + if c["passphrase"] != "": ifac_netkey = c["passphrase"] if "pass_phrase" in c: - if c["pass_phrase"] != "": - ifac_netkey = c["pass_phrase"] + if c["pass_phrase"] != "": ifac_netkey = c["pass_phrase"] ingress_control = True if "ingress_control" in c: ingress_control = c.as_bool("ingress_control") @@ -783,29 +780,22 @@ class Reticulum: configured_bitrate = None if "bitrate" in c: - if c.as_int("bitrate") >= Reticulum.MINIMUM_BITRATE: - configured_bitrate = c.as_int("bitrate") + if c.as_int("bitrate") >= Reticulum.MINIMUM_BITRATE: configured_bitrate = c.as_int("bitrate") announce_rate_target = None if "announce_rate_target" in c: - if c.as_int("announce_rate_target") > 0: - announce_rate_target = c.as_int("announce_rate_target") + if c.as_int("announce_rate_target") > 0: announce_rate_target = c.as_int("announce_rate_target") announce_rate_grace = None if "announce_rate_grace" in c: - if c.as_int("announce_rate_grace") >= 0: - announce_rate_grace = c.as_int("announce_rate_grace") + if c.as_int("announce_rate_grace") >= 0: announce_rate_grace = c.as_int("announce_rate_grace") announce_rate_penalty = None if "announce_rate_penalty" in c: - if c.as_int("announce_rate_penalty") >= 0: - announce_rate_penalty = c.as_int("announce_rate_penalty") + if c.as_int("announce_rate_penalty") >= 0: announce_rate_penalty = c.as_int("announce_rate_penalty") - if announce_rate_target != None and announce_rate_grace == None: - announce_rate_grace = 0 - - if announce_rate_target != None and announce_rate_penalty == None: - announce_rate_penalty = 0 + if announce_rate_target != None and announce_rate_grace == None: announce_rate_grace = 0 + if announce_rate_target != None and announce_rate_penalty == None: announce_rate_penalty = 0 announce_cap = Reticulum.ANNOUNCE_CAP/100.0 if "announce_cap" in c: @@ -887,40 +877,41 @@ class Reticulum: if ifac_size != None: interface.ifac_size = ifac_size else: interface.ifac_size = interface.DEFAULT_IFAC_SIZE - interface.discoverable = discoverable - interface.discovery_announce_interval = discovery_announce_interval - interface.discovery_publish_ifac = publish_ifac - interface.reachable_on = reachable_on - interface.discovery_name = discovery_name - interface.discovery_encrypt = discovery_encrypt - interface.discovery_stamp_value = discovery_stamp_value - interface.discovery_latitude = latitude - interface.discovery_longitude = longitude - interface.discovery_height = height - interface.discovery_frequency = discovery_frequency - interface.discovery_bandwidth = discovery_bandwidth - interface.discovery_modulation = discovery_modulation + interface.discoverable = discoverable + interface.discovery_announce_interval = discovery_announce_interval + interface.discovery_publish_ifac = publish_ifac + interface.reachable_on = reachable_on + interface.discovery_name = discovery_name + interface.discovery_encrypt = discovery_encrypt + interface.discovery_stamp_value = discovery_stamp_value + interface.discovery_latitude = latitude + interface.discovery_longitude = longitude + interface.discovery_height = height + interface.discovery_frequency = discovery_frequency + interface.discovery_bandwidth = discovery_bandwidth + interface.discovery_modulation = discovery_modulation - interface.recursive_prs = recursive_prs - interface.announces_from_internal = announces_from_internal - interface.announce_rate_target = announce_rate_target - interface.announce_rate_grace = announce_rate_grace - interface.announce_rate_penalty = announce_rate_penalty - interface.ingress_control = ingress_control - if egress_control != None: interface.egress_control = egress_control - if ic_max_held_announces != None: interface.ic_max_held_announces = ic_max_held_announces - if ic_burst_hold != None: interface.ic_burst_hold = ic_burst_hold - if ic_burst_freq_new != None: interface.ic_burst_freq_new = ic_burst_freq_new - if ic_burst_freq != None: interface.ic_burst_freq = ic_burst_freq - if ic_pr_burst_freq_new != None: interface.ic_pr_burst_freq_new = ic_pr_burst_freq_new - if ic_pr_burst_freq != None: interface.ic_pr_burst_freq = ic_pr_burst_freq - if ec_pr_freq != None: interface.ec_pr_freq = ec_pr_freq - if ic_new_time != None: interface.ic_new_time = ic_new_time - if ic_burst_penalty != None: interface.ic_burst_penalty = ic_burst_penalty + interface.recursive_prs = recursive_prs + interface.announces_from_internal = announces_from_internal + interface.announce_rate_target = announce_rate_target + interface.announce_rate_grace = announce_rate_grace + interface.announce_rate_penalty = announce_rate_penalty + interface.ingress_control = ingress_control + + if egress_control != None: interface.egress_control = egress_control + if ic_max_held_announces != None: interface.ic_max_held_announces = ic_max_held_announces + if ic_burst_hold != None: interface.ic_burst_hold = ic_burst_hold + if ic_burst_freq_new != None: interface.ic_burst_freq_new = ic_burst_freq_new + if ic_burst_freq != None: interface.ic_burst_freq = ic_burst_freq + if ic_pr_burst_freq_new != None: interface.ic_pr_burst_freq_new = ic_pr_burst_freq_new + if ic_pr_burst_freq != None: interface.ic_pr_burst_freq = ic_pr_burst_freq + if ec_pr_freq != None: interface.ec_pr_freq = ec_pr_freq + if ic_new_time != None: interface.ic_new_time = ic_new_time + if ic_burst_penalty != None: interface.ic_burst_penalty = ic_burst_penalty if ic_held_release_interval != None: interface.ic_held_release_interval = ic_held_release_interval interface.ifac_netname = ifac_netname - interface.ifac_netkey = ifac_netkey + interface.ifac_netkey = ifac_netkey if interface.ifac_netname != None or interface.ifac_netkey != None: ifac_origin = b"" @@ -932,12 +923,8 @@ class Reticulum: ifac_origin += RNS.Identity.full_hash(interface.ifac_netkey.encode("utf-8")) ifac_origin_hash = RNS.Identity.full_hash(ifac_origin) - interface.ifac_key = RNS.Cryptography.hkdf( - length=64, - derive_from=ifac_origin_hash, - salt=self.ifac_salt, - context=None - ) + interface.ifac_key = RNS.Cryptography.hkdf(length=64, derive_from=ifac_origin_hash, + salt=self.ifac_salt, context=None) interface.ifac_identity = RNS.Identity.from_bytes(interface.ifac_key) interface.ifac_signature = interface.ifac_identity.sign(RNS.Identity.full_hash(interface.ifac_key)) @@ -1063,6 +1050,7 @@ class Reticulum: def _add_interface(self, interface, mode = None, configured_bitrate=None, ifac_size=None, ifac_netname=None, ifac_netkey=None, announce_cap=None, announce_rate_target=None, announce_rate_grace=None, announce_rate_penalty=None, bootstrap_only=False, recursive_prs=False, announces_from_internal=True): + if not self.is_connected_to_shared_instance: if interface != None and issubclass(type(interface), RNS.Interfaces.Interface.Interface): @@ -1077,15 +1065,15 @@ class Reticulum: if ifac_size != None: interface.ifac_size = ifac_size else: interface.ifac_size = interface.DEFAULT_IFAC_SIZE - interface.recursive_prs = recursive_prs + interface.recursive_prs = recursive_prs interface.announces_from_internal = announces_from_internal - interface.announce_cap = announce_cap if announce_cap != None else Reticulum.ANNOUNCE_CAP/100.0 - interface.announce_rate_target = announce_rate_target - interface.announce_rate_grace = announce_rate_grace - interface.announce_rate_penalty = announce_rate_penalty + interface.announce_cap = announce_cap if announce_cap != None else Reticulum.ANNOUNCE_CAP/100.0 + interface.announce_rate_target = announce_rate_target + interface.announce_rate_grace = announce_rate_grace + interface.announce_rate_penalty = announce_rate_penalty interface.ifac_netname = ifac_netname - interface.ifac_netkey = ifac_netkey + interface.ifac_netkey = ifac_netkey if interface.ifac_netname != None or interface.ifac_netkey != None: ifac_origin = b"" @@ -1097,12 +1085,8 @@ class Reticulum: ifac_origin += RNS.Identity.full_hash(interface.ifac_netkey.encode("utf-8")) ifac_origin_hash = RNS.Identity.full_hash(ifac_origin) - interface.ifac_key = RNS.Cryptography.hkdf( - length=64, - derive_from=ifac_origin_hash, - salt=self.ifac_salt, - context=None - ) + interface.ifac_key = RNS.Cryptography.hkdf(length=64, derive_from=ifac_origin_hash, + salt=self.ifac_salt, context=None) interface.ifac_identity = RNS.Identity.from_bytes(interface.ifac_key) interface.ifac_signature = interface.ifac_identity.sign(RNS.Identity.full_hash(interface.ifac_key)) @@ -1199,8 +1183,7 @@ class Reticulum: self.config = ConfigObj(__default_rns_config__) self.config.filename = Reticulum.configpath - if not os.path.isdir(Reticulum.configdir): - os.makedirs(Reticulum.configdir) + if not os.path.isdir(Reticulum.configdir): os.makedirs(Reticulum.configdir) self.config.write() def rpc_return(self, connection, response): @@ -1331,31 +1314,26 @@ class Reticulum: rpc_connection.send_bytes(mp.packb({"get": "interface_stats"})) response = mp.unpackb(rpc_connection.recv_bytes()) return response + else: interfaces = [] for interface in RNS.Transport.interfaces: ifstats = {} - if hasattr(interface, "clients"): - ifstats["clients"] = interface.clients - else: - ifstats["clients"] = None + if hasattr(interface, "clients"): ifstats["clients"] = interface.clients + else: ifstats["clients"] = None if hasattr(interface, "parent_interface") and interface.parent_interface != None: ifstats["parent_interface_name"] = str(interface.parent_interface) ifstats["parent_interface_hash"] = interface.parent_interface.get_hash() if hasattr(interface, "i2p") and hasattr(interface, "connectable"): - if interface.connectable: - ifstats["i2p_connectable"] = True - else: - ifstats["i2p_connectable"] = False + if interface.connectable: ifstats["i2p_connectable"] = True + else: ifstats["i2p_connectable"] = False if hasattr(interface, "b32"): - if interface.b32 != None: - ifstats["i2p_b32"] = interface.b32+".b32.i2p" - else: - ifstats["i2p_b32"] = None + if interface.b32 != None: ifstats["i2p_b32"] = interface.b32+".b32.i2p" + else: ifstats["i2p_b32"] = None if hasattr(interface, "i2p_tunnel_state"): if interface.i2p_tunnel_state != None: @@ -1370,37 +1348,20 @@ class Reticulum: else: ifstats["tunnelstate"] = None - if hasattr(interface, "r_airtime_short"): - ifstats["airtime_short"] = interface.r_airtime_short - - if hasattr(interface, "r_airtime_long"): - ifstats["airtime_long"] = interface.r_airtime_long - - if hasattr(interface, "r_channel_load_short"): - ifstats["channel_load_short"] = interface.r_channel_load_short - - if hasattr(interface, "r_channel_load_long"): - ifstats["channel_load_long"] = interface.r_channel_load_long - - if hasattr(interface, "r_noise_floor"): - ifstats["noise_floor"] = interface.r_noise_floor - - if hasattr(interface, "r_interference"): - ifstats["interference"] = interface.r_interference + if hasattr(interface, "r_airtime_short"): ifstats["airtime_short"] = interface.r_airtime_short + if hasattr(interface, "r_airtime_long"): ifstats["airtime_long"] = interface.r_airtime_long + if hasattr(interface, "r_channel_load_short"): ifstats["channel_load_short"] = interface.r_channel_load_short + if hasattr(interface, "r_channel_load_long"): ifstats["channel_load_long"] = interface.r_channel_load_long + if hasattr(interface, "r_noise_floor"): ifstats["noise_floor"] = interface.r_noise_floor + if hasattr(interface, "r_interference"): ifstats["interference"] = interface.r_interference + if hasattr(interface, "cpu_temp"): ifstats["cpu_temp"] = interface.cpu_temp + if hasattr(interface, "cpu_load"): ifstats["cpu_load"] = interface.cpu_load + if hasattr(interface, "mem_load"): ifstats["mem_load"] = interface.mem_load if hasattr(interface, "r_interference_l") and type(interface.r_interference_l) == list: ifstats["interference_last_ts"] = interface.r_interference_l[0] ifstats["interference_last_dbm"] = interface.r_interference_l[1] - if hasattr(interface, "cpu_temp"): - ifstats["cpu_temp"] = interface.cpu_temp - - if hasattr(interface, "cpu_load"): - ifstats["cpu_load"] = interface.cpu_load - - if hasattr(interface, "mem_load"): - ifstats["mem_load"] = interface.mem_load - if hasattr(interface, "switch_id"): if interface.switch_id != None: ifstats["switch_id"] = RNS.hexrep(interface.switch_id) else: ifstats["switch_id"] = None @@ -1414,39 +1375,26 @@ class Reticulum: else: ifstats["endpoint_id"] = None if hasattr(interface, "r_battery_state"): - if interface.r_battery_state != 0x00: - ifstats["battery_state"] = interface.get_battery_state_string() - - if hasattr(interface, "r_battery_percent"): - ifstats["battery_percent"] = interface.r_battery_percent + if interface.r_battery_state != 0x00: ifstats["battery_state"] = interface.get_battery_state_string() + if hasattr(interface, "r_battery_percent"): ifstats["battery_percent"] = interface.r_battery_percent if hasattr(interface, "bitrate"): - if interface.bitrate != None: - ifstats["bitrate"] = interface.bitrate - else: - ifstats["bitrate"] = None + if interface.bitrate != None: ifstats["bitrate"] = interface.bitrate + else: ifstats["bitrate"] = None if hasattr(interface, "current_rx_speed"): - if interface.current_rx_speed != None: - ifstats["rxs"] = interface.current_rx_speed - else: - ifstats["rxs"] = 0 - else: - ifstats["rxs"] = 0 + if interface.current_rx_speed != None: ifstats["rxs"] = interface.current_rx_speed + else: ifstats["rxs"] = 0 + else: ifstats["rxs"] = 0 if hasattr(interface, "current_tx_speed"): - if interface.current_tx_speed != None: - ifstats["txs"] = interface.current_tx_speed - else: - ifstats["txs"] = 0 - else: - ifstats["txs"] = 0 + if interface.current_tx_speed != None: ifstats["txs"] = interface.current_tx_speed + else: ifstats["txs"] = 0 + else: ifstats["txs"] = 0 if hasattr(interface, "peers"): - if interface.peers != None: - ifstats["peers"] = len(interface.peers) - else: - ifstats["peers"] = None + if interface.peers != None: ifstats["peers"] = len(interface.peers) + else: ifstats["peers"] = None if hasattr(interface, "ifac_signature"): ifstats["ifac_signature"] = interface.ifac_signature @@ -1454,57 +1402,52 @@ class Reticulum: ifstats["ifac_netname"] = interface.ifac_netname else: ifstats["ifac_signature"] = None - ifstats["ifac_size"] = None - ifstats["ifac_netname"] = None + ifstats["ifac_size"] = None + ifstats["ifac_netname"] = None - if hasattr(interface, "autoconnect_source"): - ifstats["autoconnect_source"] = interface.autoconnect_source - else: - ifstats["autoconnect_source"] = None + if hasattr(interface, "autoconnect_source"): ifstats["autoconnect_source"] = interface.autoconnect_source + else: ifstats["autoconnect_source"] = None if hasattr(interface, "announce_queue"): - if interface.announce_queue != None: - ifstats["announce_queue"] = len(interface.announce_queue) - else: - ifstats["announce_queue"] = None + if interface.announce_queue != None: ifstats["announce_queue"] = len(interface.announce_queue) + else: ifstats["announce_queue"] = None - ifstats["name"] = str(interface) - ifstats["short_name"] = str(interface.name) - ifstats["hash"] = interface.get_hash() - ifstats["type"] = str(type(interface).__name__) - ifstats["rxb"] = interface.rxb - ifstats["txb"] = interface.txb + ifstats["name"] = str(interface) + ifstats["short_name"] = str(interface.name) + ifstats["hash"] = interface.get_hash() + ifstats["type"] = str(type(interface).__name__) + ifstats["rxb"] = interface.rxb + ifstats["txb"] = interface.txb ifstats["incoming_announce_frequency"] = interface.incoming_announce_frequency() ifstats["outgoing_announce_frequency"] = interface.outgoing_announce_frequency() - ifstats["incoming_pr_frequency"] = interface.incoming_pr_frequency() - ifstats["outgoing_pr_frequency"] = interface.outgoing_pr_frequency() - ifstats["announce_rate_target"] = interface.announce_rate_target - ifstats["announce_rate_penalty"] = interface.announce_rate_penalty - ifstats["announce_rate_grace"] = interface.announce_rate_grace - ifstats["held_announces"] = len(interface.held_announces) - ifstats["burst_active"] = interface.ic_burst_active - ifstats["burst_activated"] = interface.ic_burst_activated - ifstats["pr_burst_active"] = interface.ic_pr_burst_active - ifstats["pr_burst_activated"] = interface.ic_pr_burst_activated - ifstats["status"] = interface.online - ifstats["mode"] = interface.mode + ifstats["incoming_pr_frequency"] = interface.incoming_pr_frequency() + ifstats["outgoing_pr_frequency"] = interface.outgoing_pr_frequency() + ifstats["announce_rate_target"] = interface.announce_rate_target + ifstats["announce_rate_penalty"] = interface.announce_rate_penalty + ifstats["announce_rate_grace"] = interface.announce_rate_grace + ifstats["held_announces"] = len(interface.held_announces) + ifstats["burst_active"] = interface.ic_burst_active + ifstats["burst_activated"] = interface.ic_burst_activated + ifstats["pr_burst_active"] = interface.ic_pr_burst_active + ifstats["pr_burst_activated"] = interface.ic_pr_burst_activated + ifstats["status"] = interface.online + ifstats["mode"] = interface.mode interfaces.append(ifstats) - stats = {} + stats = {} stats["interfaces"] = interfaces - stats["rxb"] = RNS.Transport.traffic_rxb - stats["txb"] = RNS.Transport.traffic_txb - stats["rxs"] = RNS.Transport.speed_rx - stats["txs"] = RNS.Transport.speed_tx + stats["rxb"] = RNS.Transport.traffic_rxb + stats["txb"] = RNS.Transport.traffic_txb + stats["rxs"] = RNS.Transport.speed_rx + stats["txs"] = RNS.Transport.speed_tx + if Reticulum.transport_enabled(): stats["transport_id"] = RNS.Transport.identity.hash stats["network_id"] = RNS.Transport.network_identity.hash if RNS.Transport.network_identity else None stats["transport_uptime"] = time.time()-RNS.Transport.start_time - if Reticulum.probe_destination_enabled(): - stats["probe_responder"] = RNS.Transport.probe_destination.hash - else: - stats["probe_responder"] = None + if Reticulum.probe_destination_enabled(): stats["probe_responder"] = RNS.Transport.probe_destination.hash + else: stats["probe_responder"] = None if importlib.util.find_spec('psutil') != None: import psutil @@ -1527,14 +1470,10 @@ class Reticulum: for dst_hash in RNS.Transport.path_table: path_hops = RNS.Transport.path_table[dst_hash][2] if max_hops == None or path_hops <= max_hops: - entry = { - "hash": dst_hash, - "timestamp": RNS.Transport.path_table[dst_hash][0], - "via": RNS.Transport.path_table[dst_hash][1], - "hops": path_hops, - "expires": RNS.Transport.path_table[dst_hash][3], - "interface": str(RNS.Transport.path_table[dst_hash][5]), - } + entry = { "hash": dst_hash, "timestamp": RNS.Transport.path_table[dst_hash][0], + "via": RNS.Transport.path_table[dst_hash][1], "hops": path_hops, + "expires": RNS.Transport.path_table[dst_hash][3], + "interface": str(RNS.Transport.path_table[dst_hash][5]) } path_table.append(entry) return path_table @@ -1862,6 +1801,10 @@ class Reticulum: def static_transport_identity(): return Reticulum.__static_transport_identity + @staticmethod + def local_hops_delta(): + return Reticulum.__local_hops_delta + # Default configuration file: __default_rns_config__ = '''# This is the default Reticulum config file. # You should probably edit it to include any additional, diff --git a/RNS/Transport.py b/RNS/Transport.py index 8bb4f183..3df5d71f 100755 --- a/RNS/Transport.py +++ b/RNS/Transport.py @@ -166,6 +166,7 @@ class Transport: local_client_rssi_cache = [] local_client_snr_cache = [] local_client_q_cache = [] + local_hops_delta = 0 LOCAL_CLIENT_CACHE_MAXSIZE = 512 pending_local_path_requests = {} @@ -236,6 +237,8 @@ class Transport: Transport.identity = RNS.Identity() RNS.log(f"Initialized ephemeral transport identity {RNS.prettyhexrep(Transport.identity.hash)}", RNS.LOG_VERBOSE) if RNS.sl(RNS.LOG_VERBOSE) else None + if RNS.Reticulum.local_hops_delta(): Transport.local_hops_delta = (ord(os.urandom(1))%6)+2 + packet_hashlist_path = RNS.Reticulum.storagepath+"/packet_hashlist" if not Transport.owner.is_connected_to_shared_instance: if os.path.isfile(packet_hashlist_path): @@ -1147,7 +1150,7 @@ class Transport: # Insert packet into transport new_flags = (RNS.Packet.HEADER_2) << 6 | (Transport.TRANSPORT) << 4 | (packet.flags & 0b00001111) new_raw = struct.pack("!B", new_flags) - new_raw += packet.raw[1:2] + new_raw += packet.raw[1:2] if not Transport.should_apply_delta(packet, outbound_interface) else struct.pack("!B", Transport.local_hops_delta) new_raw += path_entry[IDX_PT_NEXT_HOP] new_raw += packet.raw[2:] packet_sent(packet) @@ -1167,7 +1170,7 @@ class Transport: # Insert packet into transport new_flags = (RNS.Packet.HEADER_2) << 6 | (Transport.TRANSPORT) << 4 | (packet.flags & 0b00001111) new_raw = struct.pack("!B", new_flags) - new_raw += packet.raw[1:2] + new_raw += packet.raw[1:2] if not Transport.should_apply_delta(packet, outbound_interface) else struct.pack("!B", Transport.local_hops_delta) new_raw += path_entry[IDX_PT_NEXT_HOP] new_raw += packet.raw[2:] packet_sent(packet) @@ -1180,7 +1183,9 @@ class Transport: # simply transmit the packet directly on that one. else: packet_sent(packet) - Transport.transmit(outbound_interface, packet.raw) + if not Transport.should_apply_delta(packet, outbound_interface): raw = packet.raw + else: raw = Transport.mangle_hops(packet.raw, Transport.local_hops_delta) + Transport.transmit(outbound_interface, raw) sent = True # If we don't have a known path for the destination, we'll @@ -1194,11 +1199,10 @@ class Transport: should_transmit = True if packet.destination.type == RNS.Destination.LINK: - if packet.destination.status == RNS.Link.CLOSED: should_transmit = False - if interface != packet.destination.attached_interface: should_transmit = False + if packet.destination.status == RNS.Link.CLOSED: continue + if interface != packet.destination.attached_interface: continue - if packet.attached_interface != None and interface != packet.attached_interface: - should_transmit = False + if packet.attached_interface != None and interface != packet.attached_interface: continue if packet.packet_type == RNS.Packet.ANNOUNCE: if packet.attached_interface == None: @@ -1335,7 +1339,12 @@ class Transport: Transport.add_packet_hash(packet.packet_hash) stored_hash = True - Transport.transmit(interface, packet.raw) + if not Transport.should_apply_delta(packet, interface): raw = packet.raw + else: + if packet.packet_type != RNS.Packet.ANNOUNCE: raw = Transport.mangle_hops(packet.raw, Transport.local_hops_delta) + else: raw = Transport.mangle_hops(packet.raw, Transport.local_hops_delta, transport_insert=packet.header_type==RNS.Packet.HEADER_1) + + Transport.transmit(interface, raw) if packet.packet_type == RNS.Packet.ANNOUNCE: interface.sent_announce() if packet.destination.type == RNS.Destination.PLAIN and packet.is_outbound_pr: interface.sent_path_request() packet_sent(packet) @@ -1343,6 +1352,17 @@ class Transport: return sent + @staticmethod + def should_apply_delta(packet, interface): + return not Transport.owner.is_connected_to_shared_instance and packet.hops == 0 and Transport.local_hops_delta != 0 \ + and not packet.destination.type == RNS.Destination.PLAIN and not packet.destination.type == RNS.Destination.GROUP \ + and not interface in Transport.local_client_interfaces and not Transport.is_shared_instance(interface) + + @staticmethod + def mangle_hops(raw, hops, transport_insert=False): + if not transport_insert: return raw[0:1]+struct.pack("!B", hops)+raw[2:] + else: return struct.pack("!B", ord(raw[0:1]) | (RNS.Packet.HEADER_2<<6) | (Transport.TRANSPORT<<4))+struct.pack("!B", hops)+Transport.identity.hash+raw[2:] + @staticmethod def add_packet_hash(packet_hash): if not Transport.owner.is_connected_to_shared_instance: @@ -1530,6 +1550,8 @@ class Transport: for_local_client_link = (packet.packet_type != RNS.Packet.ANNOUNCE) and (packet.destination_hash in Transport.link_table and Transport.link_table[packet.destination_hash][IDX_LT_RCVD_IF] in Transport.local_client_interfaces) for_local_client_link |= (packet.packet_type != RNS.Packet.ANNOUNCE) and (packet.destination_hash in Transport.link_table and Transport.link_table[packet.destination_hash][IDX_LT_NH_IF] in Transport.local_client_interfaces) proof_for_local_client = (packet.destination_hash in Transport.reverse_table) and (Transport.reverse_table[packet.destination_hash][IDX_RT_RCVD_IF] in Transport.local_client_interfaces) + to_local_client = for_local_client or for_local_client_link or proof_for_local_client + link_request_handled = False # Plain broadcast packets from local clients are sent # directly on all attached interfaces, since they are @@ -1591,10 +1613,23 @@ class Transport: new_raw += struct.pack("!B", packet.hops) new_raw += packet.raw[(RNS.Identity.TRUNCATED_HASHLENGTH//8)+2:] elif remaining_hops == 0: - # Just increase hop count and transmit - new_raw = packet.raw[0:1] - new_raw += struct.pack("!B", packet.hops) - new_raw += packet.raw[2:] + if to_local_client and RNS.Transport.local_hops_delta != 0: + if packet.header_type == RNS.Packet.HEADER_2: + # Strip transport headers and transmit + new_flags = (RNS.Packet.HEADER_1) << 6 | (Transport.BROADCAST) << 4 | (packet.flags & 0b00001111) + new_raw = struct.pack("!B", new_flags) + new_raw += struct.pack("!B", packet.hops) + new_raw += packet.raw[(RNS.Identity.TRUNCATED_HASHLENGTH//8)+2:] + else: + # Just increase hop count and transmit + new_raw = packet.raw[0:1] + new_raw += struct.pack("!B", packet.hops) + new_raw += packet.raw[2:] + else: + # Just increase hop count and transmit + new_raw = packet.raw[0:1] + new_raw += struct.pack("!B", packet.hops) + new_raw += packet.raw[2:] outbound_interface = Transport.path_table[packet.destination_hash][IDX_PT_RVCD_IF] @@ -1639,6 +1674,7 @@ class Transport: proof_timeout ] # 8: Proof timeout timestamp with Transport.link_table_lock: Transport.link_table[RNS.Link.link_id_from_lr_packet(packet)] = link_entry + link_request_handled = True else: # Entry format is @@ -1648,6 +1684,7 @@ class Transport: with Transport.reverse_table_lock: Transport.reverse_table[packet.getTruncatedHash()] = reverse_entry + if Transport.local_hops_delta != 0 and from_local_client and not to_local_client: new_raw = Transport.mangle_hops(new_raw, Transport.local_hops_delta) Transport.transmit(outbound_interface, new_raw) with Transport.path_table_lock: Transport.path_table[packet.destination_hash][IDX_PT_TIMESTAMP] = time.time() @@ -1691,7 +1728,7 @@ class Transport: Transport.add_packet_hash(packet.packet_hash) new_raw = packet.raw[0:1] - new_raw += struct.pack("!B", packet.hops) + new_raw += struct.pack("!B", packet.hops if not from_local_client or Transport.local_hops_delta == 0 else Transport.local_hops_delta) new_raw += packet.raw[2:] Transport.transmit(outbound_interface, new_raw) Transport.link_table[packet.destination_hash][IDX_LT_TIMESTAMP] = time.time() @@ -2104,7 +2141,7 @@ class Transport: RNS.trace_exception(e) # Handling for link requests to local destinations - elif packet.packet_type == RNS.Packet.LINKREQUEST: + elif packet.packet_type == RNS.Packet.LINKREQUEST and not link_request_handled: if packet.transport_id == None or packet.transport_id == Transport.identity.hash: destination = None with Transport.destinations_map_lock: @@ -2207,7 +2244,7 @@ class Transport: if peer_identity.validate(signature, signed_data): RNS.log("Link request proof validated for transport via "+str(link_entry[IDX_LT_RCVD_IF]), RNS.LOG_EXTREME) if RNS.sl(RNS.LOG_EXTREME) else None new_raw = packet.raw[0:1] - new_raw += struct.pack("!B", packet.hops) + new_raw += struct.pack("!B", packet.hops if not from_local_client or Transport.local_hops_delta == 0 else Transport.local_hops_delta) new_raw += packet.raw[2:] Transport.link_table[packet.destination_hash][IDX_LT_VALIDATED] = True Transport.transmit(link_entry[IDX_LT_RCVD_IF], new_raw) @@ -2274,7 +2311,7 @@ class Transport: if packet.receiving_interface == reverse_entry[IDX_RT_OUTB_IF]: RNS.log("Proof received on correct interface, transporting it via "+str(reverse_entry[IDX_RT_RCVD_IF]), RNS.LOG_EXTREME) if RNS.sl(RNS.LOG_EXTREME) else None new_raw = packet.raw[0:1] - new_raw += struct.pack("!B", packet.hops) + new_raw += struct.pack("!B", packet.hops if not from_local_client or Transport.local_hops_delta == 0 else Transport.local_hops_delta) new_raw += packet.raw[2:] Transport.transmit(reverse_entry[IDX_RT_RCVD_IF], new_raw) else: @@ -2672,7 +2709,8 @@ class Transport: :returns: The destination hash as *bytes* for the next hop to the specified destination, or *None* if the next hop is unknown. """ with Transport.path_table_lock: - if destination_hash in Transport.path_table: return Transport.path_table[destination_hash][IDX_PT_NEXT_HOP] + if destination_hash in Transport.path_table: return Transport.path_table[destination_hash][IDX_PT_NEXT_HOP] + elif destination_hash in Transport.destinations_map: return Transport.identity.hash else: return None @staticmethod @@ -2682,7 +2720,8 @@ class Transport: :returns: The interface for the next hop to the specified destination, or *None* if the interface is unknown. """ with Transport.path_table_lock: - if destination_hash in Transport.path_table: return Transport.path_table[destination_hash][IDX_PT_RVCD_IF] + if destination_hash in Transport.path_table: return Transport.path_table[destination_hash][IDX_PT_RVCD_IF] + elif destination_hash in Transport.destinations_map: return RNS.Reticulum.get_instance().shared_instance_interface else: return None @staticmethod @@ -3080,6 +3119,11 @@ class Transport: else: return False else: return False + @staticmethod + def is_shared_instance(interface): + if hasattr(interface, "is_local_shared_instance"): return True + else: return False + @staticmethod def interface_to_shared_instance(interface): if hasattr(interface, "is_connected_to_shared_instance"): return True