feat(meshchat): improve RPC address handling and error checking; improve rule data validation for forwarding operations (found with fuzzing)
This commit is contained in:
@@ -928,32 +928,49 @@ class ReticulumMeshChat:
|
|||||||
# Wait another moment for sockets to definitely be released by OS
|
# Wait another moment for sockets to definitely be released by OS
|
||||||
# Also give some time for the RPC listener port to settle
|
# Also give some time for the RPC listener port to settle
|
||||||
print("Waiting for ports to settle...")
|
print("Waiting for ports to settle...")
|
||||||
|
# Detect RPC type from reticulum instance if possible, otherwise default to both
|
||||||
|
rpc_addrs = []
|
||||||
|
if old_reticulum:
|
||||||
|
if hasattr(old_reticulum, "rpc_addr") and old_reticulum.rpc_addr:
|
||||||
|
rpc_addrs.append((old_reticulum.rpc_addr, getattr(old_reticulum, "rpc_type", "AF_INET")))
|
||||||
|
|
||||||
|
if not rpc_addrs:
|
||||||
|
# Defaults
|
||||||
|
rpc_addrs.append((("127.0.0.1", 37429), "AF_INET"))
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
rpc_addrs.append(("\0rns/default/rpc", "AF_UNIX"))
|
||||||
|
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
# If we're using AF_INET for RPC, we can check the port
|
all_free = True
|
||||||
# RNS uses 127.0.0.1:37429 by default
|
for addr, family_str in rpc_addrs:
|
||||||
try:
|
|
||||||
import socket
|
|
||||||
|
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
s.settimeout(0.5)
|
|
||||||
# Try to bind to the port. If it fails, it's still in use.
|
|
||||||
# RNS uses this for the shared instance listener.
|
|
||||||
# We use a high port number that is unlikely to be used by anything else
|
|
||||||
# but RNS.
|
|
||||||
try:
|
try:
|
||||||
# RNS local_control_port is 37429
|
import socket
|
||||||
s.bind(("127.0.0.1", 37429))
|
family = socket.AF_INET if family_str == "AF_INET" else socket.AF_UNIX
|
||||||
s.close()
|
s = socket.socket(family, socket.SOCK_STREAM)
|
||||||
print("RPC port 37429 is free.")
|
s.settimeout(0.5)
|
||||||
break
|
try:
|
||||||
except OSError:
|
s.bind(addr)
|
||||||
print(f"RPC port 37429 still in use... (attempt {i + 1}/10)")
|
s.close()
|
||||||
s.close()
|
except OSError:
|
||||||
except Exception as e:
|
print(f"RPC addr {addr} still in use... (attempt {i+1}/10)")
|
||||||
print(f"Error checking RPC port: {e}")
|
s.close()
|
||||||
|
all_free = False
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error checking RPC addr {addr}: {e}")
|
||||||
|
|
||||||
|
if all_free:
|
||||||
|
print("All RNS ports/sockets are free.")
|
||||||
break
|
break
|
||||||
|
|
||||||
|
if not all_free:
|
||||||
|
raise OSError("Timeout waiting for RNS ports to be released. Cannot restart.")
|
||||||
|
|
||||||
|
# Final GC to ensure everything is released
|
||||||
|
import gc
|
||||||
|
gc.collect()
|
||||||
|
|
||||||
# Re-setup identity (this starts background loops again)
|
# Re-setup identity (this starts background loops again)
|
||||||
self.running = True
|
self.running = True
|
||||||
self.setup_identity(self.identity)
|
self.setup_identity(self.identity)
|
||||||
@@ -7138,7 +7155,11 @@ class ReticulumMeshChat:
|
|||||||
)
|
)
|
||||||
|
|
||||||
elif _type == "lxmf.forwarding.rule.add":
|
elif _type == "lxmf.forwarding.rule.add":
|
||||||
rule_data = data["rule"]
|
rule_data = data.get("rule")
|
||||||
|
if not rule_data or "forward_to_hash" not in rule_data:
|
||||||
|
print("Missing rule data or forward_to_hash in lxmf.forwarding.rule.add")
|
||||||
|
return
|
||||||
|
|
||||||
self.database.misc.create_forwarding_rule(
|
self.database.misc.create_forwarding_rule(
|
||||||
identity_hash=rule_data.get("identity_hash"),
|
identity_hash=rule_data.get("identity_hash"),
|
||||||
forward_to_hash=rule_data["forward_to_hash"],
|
forward_to_hash=rule_data["forward_to_hash"],
|
||||||
@@ -7155,26 +7176,28 @@ class ReticulumMeshChat:
|
|||||||
)
|
)
|
||||||
|
|
||||||
elif _type == "lxmf.forwarding.rule.delete":
|
elif _type == "lxmf.forwarding.rule.delete":
|
||||||
rule_id = data["id"]
|
rule_id = data.get("id")
|
||||||
self.database.misc.delete_forwarding_rule(rule_id)
|
if rule_id is not None:
|
||||||
# notify updated
|
self.database.misc.delete_forwarding_rule(rule_id)
|
||||||
AsyncUtils.run_async(
|
# notify updated
|
||||||
self.on_websocket_data_received(
|
AsyncUtils.run_async(
|
||||||
client,
|
self.on_websocket_data_received(
|
||||||
{"type": "lxmf.forwarding.rules.get"},
|
client,
|
||||||
),
|
{"type": "lxmf.forwarding.rules.get"},
|
||||||
)
|
),
|
||||||
|
)
|
||||||
|
|
||||||
elif _type == "lxmf.forwarding.rule.toggle":
|
elif _type == "lxmf.forwarding.rule.toggle":
|
||||||
rule_id = data["id"]
|
rule_id = data.get("id")
|
||||||
self.database.misc.toggle_forwarding_rule(rule_id)
|
if rule_id is not None:
|
||||||
# notify updated
|
self.database.misc.toggle_forwarding_rule(rule_id)
|
||||||
AsyncUtils.run_async(
|
# notify updated
|
||||||
self.on_websocket_data_received(
|
AsyncUtils.run_async(
|
||||||
client,
|
self.on_websocket_data_received(
|
||||||
{"type": "lxmf.forwarding.rules.get"},
|
client,
|
||||||
),
|
{"type": "lxmf.forwarding.rules.get"},
|
||||||
)
|
),
|
||||||
|
)
|
||||||
|
|
||||||
# handle ingesting an lxmf uri (paper message)
|
# handle ingesting an lxmf uri (paper message)
|
||||||
elif _type == "lxm.ingest_uri":
|
elif _type == "lxm.ingest_uri":
|
||||||
@@ -8648,6 +8671,11 @@ class ReticulumMeshChat:
|
|||||||
app_data,
|
app_data,
|
||||||
announce_packet_hash,
|
announce_packet_hash,
|
||||||
):
|
):
|
||||||
|
# check if announced identity or its hash is missing
|
||||||
|
if not announced_identity or not announced_identity.hash:
|
||||||
|
print(f"Dropping announce with missing identity or hash: {RNS.prettyhexrep(destination_hash)}")
|
||||||
|
return
|
||||||
|
|
||||||
# check if source is blocked - drop announce and path if blocked
|
# check if source is blocked - drop announce and path if blocked
|
||||||
identity_hash = announced_identity.hash.hex()
|
identity_hash = announced_identity.hash.hex()
|
||||||
if self.is_destination_blocked(identity_hash):
|
if self.is_destination_blocked(identity_hash):
|
||||||
|
|||||||
Reference in New Issue
Block a user