mirror of
https://github.com/markqvist/Reticulum.git
synced 2024-11-22 21:50:18 +00:00
Implemented interface authentication and virtual network segmentation
This commit is contained in:
parent
b701cdd07f
commit
5d90ea565a
@ -21,6 +21,11 @@
|
||||
# SOFTWARE.
|
||||
|
||||
from .vendor.platformutils import get_platform
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
|
||||
cio_default_backend = default_backend()
|
||||
|
||||
if get_platform() == "android":
|
||||
from .Interfaces import Interface
|
||||
@ -122,6 +127,7 @@ class Reticulum:
|
||||
HEADER_MINSIZE = 2+1+(TRUNCATED_HASHLENGTH//8)*1
|
||||
HEADER_MAXSIZE = 2+1+(TRUNCATED_HASHLENGTH//8)*2
|
||||
IFAC_MIN_SIZE = 1
|
||||
IFAC_SALT = bytes.fromhex("adf54d882c9a9b80771eb4995d702d4a3e733391b2a0f53f416d9f907e55cff8")
|
||||
|
||||
MDU = MTU - HEADER_MAXSIZE - IFAC_MIN_SIZE
|
||||
|
||||
@ -186,6 +192,8 @@ class Reticulum:
|
||||
self.share_instance = True
|
||||
self.rpc_listener = None
|
||||
|
||||
self.ifac_salt = Reticulum.IFAC_SALT
|
||||
|
||||
self.requested_loglevel = loglevel
|
||||
if self.requested_loglevel != None:
|
||||
if self.requested_loglevel > RNS.LOG_EXTREME:
|
||||
@ -356,14 +364,20 @@ class Reticulum:
|
||||
ifac_size = c.as_int("ifac_size")
|
||||
|
||||
ifac_netname = None
|
||||
if "ifac_netname" in c:
|
||||
if c.as_int("ifac_netname") >= Reticulum.IFAC_MIN_SIZE:
|
||||
ifac_netname = c.as_int("ifac_netname")
|
||||
if "networkname" in c:
|
||||
if c["networkname"] != "":
|
||||
ifac_netname = c["networkname"]
|
||||
if "network_name" in c:
|
||||
if c["network_name"] != "":
|
||||
ifac_netname = c["network_name"]
|
||||
|
||||
ifac_netkey = None
|
||||
if "ifac_netkey" in c:
|
||||
if c.as_int("ifac_netkey") >= Reticulum.IFAC_MIN_SIZE:
|
||||
ifac_netkey = c.as_int("ifac_netkey")
|
||||
if "passphrase" in c:
|
||||
if c["passphrase"] != "":
|
||||
ifac_netkey = c["passphrase"]
|
||||
if "pass_phrase" in c:
|
||||
if c["pass_phrase"] != "":
|
||||
ifac_netkey = c["pass_phrase"]
|
||||
|
||||
configured_bitrate = None
|
||||
if "bitrate" in c:
|
||||
@ -406,8 +420,6 @@ class Reticulum:
|
||||
|
||||
interface.mode = interface_mode
|
||||
|
||||
RNS.Transport.interfaces.append(interface)
|
||||
|
||||
interface.announce_cap = announce_cap
|
||||
if configured_bitrate:
|
||||
interface.bitrate = configured_bitrate
|
||||
@ -452,8 +464,6 @@ class Reticulum:
|
||||
|
||||
interface.mode = interface_mode
|
||||
|
||||
RNS.Transport.interfaces.append(interface)
|
||||
|
||||
interface.announce_cap = announce_cap
|
||||
if configured_bitrate:
|
||||
interface.bitrate = configured_bitrate
|
||||
@ -492,8 +502,6 @@ class Reticulum:
|
||||
|
||||
interface.mode = interface_mode
|
||||
|
||||
RNS.Transport.interfaces.append(interface)
|
||||
|
||||
interface.announce_cap = announce_cap
|
||||
if configured_bitrate:
|
||||
interface.bitrate = configured_bitrate
|
||||
@ -529,8 +537,6 @@ class Reticulum:
|
||||
|
||||
interface.mode = interface_mode
|
||||
|
||||
RNS.Transport.interfaces.append(interface)
|
||||
|
||||
interface.announce_cap = announce_cap
|
||||
if configured_bitrate:
|
||||
interface.bitrate = configured_bitrate
|
||||
@ -562,8 +568,6 @@ class Reticulum:
|
||||
|
||||
interface.mode = interface_mode
|
||||
|
||||
RNS.Transport.interfaces.append(interface)
|
||||
|
||||
interface.announce_cap = announce_cap
|
||||
if configured_bitrate:
|
||||
interface.bitrate = configured_bitrate
|
||||
@ -599,8 +603,6 @@ class Reticulum:
|
||||
|
||||
interface.mode = interface_mode
|
||||
|
||||
RNS.Transport.interfaces.append(interface)
|
||||
|
||||
interface.announce_cap = announce_cap
|
||||
if configured_bitrate:
|
||||
interface.bitrate = configured_bitrate
|
||||
@ -650,8 +652,6 @@ class Reticulum:
|
||||
|
||||
interface.mode = interface_mode
|
||||
|
||||
RNS.Transport.interfaces.append(interface)
|
||||
|
||||
interface.announce_cap = announce_cap
|
||||
if configured_bitrate:
|
||||
interface.bitrate = configured_bitrate
|
||||
@ -702,8 +702,6 @@ class Reticulum:
|
||||
|
||||
interface.mode = interface_mode
|
||||
|
||||
RNS.Transport.interfaces.append(interface)
|
||||
|
||||
interface.announce_cap = announce_cap
|
||||
if configured_bitrate:
|
||||
interface.bitrate = configured_bitrate
|
||||
@ -748,8 +746,6 @@ class Reticulum:
|
||||
|
||||
interface.mode = interface_mode
|
||||
|
||||
RNS.Transport.interfaces.append(interface)
|
||||
|
||||
interface.announce_cap = announce_cap
|
||||
if configured_bitrate:
|
||||
interface.bitrate = configured_bitrate
|
||||
@ -762,6 +758,27 @@ class Reticulum:
|
||||
interface.ifac_netname = ifac_netname
|
||||
interface.ifac_netkey = ifac_netkey
|
||||
|
||||
if interface.ifac_netname != None or interface.ifac_netkey != None:
|
||||
ifac_origin = b""
|
||||
|
||||
if interface.ifac_netname != None:
|
||||
ifac_origin += RNS.Identity.full_hash(interface.ifac_netname.encode("utf-8"))
|
||||
|
||||
if interface.ifac_netkey != None:
|
||||
ifac_origin += RNS.Identity.full_hash(interface.ifac_netkey.encode("utf-8"))
|
||||
|
||||
ifac_origin_hash = RNS.Identity.full_hash(ifac_origin)
|
||||
interface.ifac_key = HKDF(
|
||||
algorithm=hashes.SHA256(),
|
||||
length=64,
|
||||
salt=self.ifac_salt,
|
||||
info=None,
|
||||
backend=cio_default_backend,
|
||||
).derive(ifac_origin_hash)
|
||||
|
||||
interface.ifac_identity = RNS.Identity.from_bytes(interface.ifac_key)
|
||||
interface.ifac_signature = interface.ifac_identity.sign(RNS.Identity.full_hash(interface.ifac_key))
|
||||
|
||||
RNS.Transport.interfaces.append(interface)
|
||||
|
||||
else:
|
||||
@ -859,6 +876,15 @@ class Reticulum:
|
||||
else:
|
||||
ifstats["peers"] = None
|
||||
|
||||
if hasattr(interface, "ifac_signature"):
|
||||
ifstats["ifac_signature"] = interface.ifac_signature
|
||||
ifstats["ifac_size"] = interface.ifac_size
|
||||
ifstats["ifac_netname"] = interface.ifac_netname
|
||||
else:
|
||||
ifstats["ifac_signature"] = None
|
||||
ifstats["ifac_size"] = None
|
||||
ifstats["ifac_netname"] = None
|
||||
|
||||
if hasattr(interface, "announce_queue"):
|
||||
if interface.announce_queue != None:
|
||||
ifstats["announce_queue"] = len(interface.announce_queue)
|
||||
|
@ -474,8 +474,24 @@ class Transport:
|
||||
|
||||
@staticmethod
|
||||
def transmit(interface, raw):
|
||||
try:
|
||||
if hasattr(interface, "ifac_identity") and interface.ifac_identity != None:
|
||||
# Calculate packet access code
|
||||
ifac = interface.ifac_identity.sign(raw)[-interface.ifac_size:]
|
||||
|
||||
# Set IFAC flag
|
||||
new_header = bytes([raw[0] | 0x80, raw[1]])
|
||||
|
||||
# Assemble new payload with IFAC and send it
|
||||
new_raw = new_header+ifac+raw[2:]
|
||||
interface.processOutgoing(new_raw)
|
||||
|
||||
else:
|
||||
interface.processOutgoing(raw)
|
||||
|
||||
except Exception as e:
|
||||
RNS.log("Error while transmitting on "+str(interface)+". The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
|
||||
@staticmethod
|
||||
def outbound(packet):
|
||||
while (Transport.jobs_running):
|
||||
@ -704,6 +720,44 @@ class Transport:
|
||||
|
||||
@staticmethod
|
||||
def inbound(raw, interface=None):
|
||||
# If interface access codes are enabled,
|
||||
# we must authenticate each packet.
|
||||
if interface != None and hasattr(interface, "ifac_identity") and interface.ifac_identity != None:
|
||||
# Check that IFAC flag is set
|
||||
if raw[0] & 0x80 == 0x80:
|
||||
if len(raw) > 2+interface.ifac_size:
|
||||
# Extract IFAC
|
||||
ifac = raw[2:2+interface.ifac_size]
|
||||
|
||||
# Unset IFAC flag
|
||||
new_header = bytes([raw[0] & 0x7f, raw[1]])
|
||||
|
||||
# Re-assemble packet
|
||||
new_raw = new_header+raw[2+interface.ifac_size:]
|
||||
|
||||
# Calculate expected IFAC
|
||||
expected_ifac = interface.ifac_identity.sign(new_raw)[-interface.ifac_size:]
|
||||
|
||||
# Check it
|
||||
if ifac == expected_ifac:
|
||||
# TODO: Remove log statements
|
||||
RNS.log("Packet IFAC match, allowing", RNS.LOG_EXTREME)
|
||||
raw = new_raw
|
||||
else:
|
||||
# TODO: Remove log statements
|
||||
RNS.log("Packet IFAC mismatch, dropping packet", RNS.LOG_EXTREME)
|
||||
return
|
||||
|
||||
else:
|
||||
return
|
||||
|
||||
else:
|
||||
# If the IFAC flag is not set, but should be,
|
||||
# we drop the packet.
|
||||
# TODO: Remove log statements
|
||||
RNS.log(str(interface)+" with IFAC enabled received packet without access code, dropping.", RNS.LOG_EXTREME)
|
||||
return
|
||||
|
||||
while (Transport.jobs_running):
|
||||
sleep(0.01)
|
||||
|
||||
|
@ -92,6 +92,10 @@ def program_setup(configdir, dispall=False, verbosity = 0):
|
||||
clients = None
|
||||
|
||||
print(" {n}".format(n=ifstat["name"]))
|
||||
|
||||
if "ifac_netname" in ifstat and ifstat["ifac_netname"] != None:
|
||||
print(" Network : {nn}".format(nn=ifstat["ifac_netname"]))
|
||||
|
||||
print(" Status : {ss}".format(ss=ss))
|
||||
|
||||
if clients != None:
|
||||
@ -106,6 +110,10 @@ def program_setup(configdir, dispall=False, verbosity = 0):
|
||||
if "peers" in ifstat and ifstat["peers"] != None:
|
||||
print(" Peers : {np} reachable".format(np=ifstat["peers"]))
|
||||
|
||||
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))
|
||||
|
||||
if "i2p_b32" in ifstat and ifstat["i2p_b32"] != None:
|
||||
print(" I2P B32 : {ep}".format(ep=str(ifstat["i2p_b32"])))
|
||||
|
||||
|
@ -60,7 +60,8 @@ logfile = None
|
||||
logdest = LOG_STDOUT
|
||||
logtimefmt = "%Y-%m-%d %H:%M:%S"
|
||||
|
||||
random.seed(os.urandom(10))
|
||||
instance_random = random.Random()
|
||||
instance_random.seed(os.urandom(10))
|
||||
|
||||
_always_override_destination = False
|
||||
|
||||
@ -130,7 +131,7 @@ def log(msg, level=3, _override_destination = False):
|
||||
|
||||
|
||||
def rand():
|
||||
result = random.random()
|
||||
result = instance_random.random()
|
||||
return result
|
||||
|
||||
def hexrep(data, delimit=True):
|
||||
|
Loading…
Reference in New Issue
Block a user