Implemented interface authentication and virtual network segmentation
This commit is contained in:
parent
b701cdd07f
commit
5d90ea565a
@ -21,6 +21,11 @@
|
|||||||
# SOFTWARE.
|
# SOFTWARE.
|
||||||
|
|
||||||
from .vendor.platformutils import get_platform
|
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":
|
if get_platform() == "android":
|
||||||
from .Interfaces import Interface
|
from .Interfaces import Interface
|
||||||
@ -122,6 +127,7 @@ class Reticulum:
|
|||||||
HEADER_MINSIZE = 2+1+(TRUNCATED_HASHLENGTH//8)*1
|
HEADER_MINSIZE = 2+1+(TRUNCATED_HASHLENGTH//8)*1
|
||||||
HEADER_MAXSIZE = 2+1+(TRUNCATED_HASHLENGTH//8)*2
|
HEADER_MAXSIZE = 2+1+(TRUNCATED_HASHLENGTH//8)*2
|
||||||
IFAC_MIN_SIZE = 1
|
IFAC_MIN_SIZE = 1
|
||||||
|
IFAC_SALT = bytes.fromhex("adf54d882c9a9b80771eb4995d702d4a3e733391b2a0f53f416d9f907e55cff8")
|
||||||
|
|
||||||
MDU = MTU - HEADER_MAXSIZE - IFAC_MIN_SIZE
|
MDU = MTU - HEADER_MAXSIZE - IFAC_MIN_SIZE
|
||||||
|
|
||||||
@ -186,6 +192,8 @@ class Reticulum:
|
|||||||
self.share_instance = True
|
self.share_instance = True
|
||||||
self.rpc_listener = None
|
self.rpc_listener = None
|
||||||
|
|
||||||
|
self.ifac_salt = Reticulum.IFAC_SALT
|
||||||
|
|
||||||
self.requested_loglevel = loglevel
|
self.requested_loglevel = loglevel
|
||||||
if self.requested_loglevel != None:
|
if self.requested_loglevel != None:
|
||||||
if self.requested_loglevel > RNS.LOG_EXTREME:
|
if self.requested_loglevel > RNS.LOG_EXTREME:
|
||||||
@ -356,14 +364,20 @@ class Reticulum:
|
|||||||
ifac_size = c.as_int("ifac_size")
|
ifac_size = c.as_int("ifac_size")
|
||||||
|
|
||||||
ifac_netname = None
|
ifac_netname = None
|
||||||
if "ifac_netname" in c:
|
if "networkname" in c:
|
||||||
if c.as_int("ifac_netname") >= Reticulum.IFAC_MIN_SIZE:
|
if c["networkname"] != "":
|
||||||
ifac_netname = c.as_int("ifac_netname")
|
ifac_netname = c["networkname"]
|
||||||
|
if "network_name" in c:
|
||||||
|
if c["network_name"] != "":
|
||||||
|
ifac_netname = c["network_name"]
|
||||||
|
|
||||||
ifac_netkey = None
|
ifac_netkey = None
|
||||||
if "ifac_netkey" in c:
|
if "passphrase" in c:
|
||||||
if c.as_int("ifac_netkey") >= Reticulum.IFAC_MIN_SIZE:
|
if c["passphrase"] != "":
|
||||||
ifac_netkey = c.as_int("ifac_netkey")
|
ifac_netkey = c["passphrase"]
|
||||||
|
if "pass_phrase" in c:
|
||||||
|
if c["pass_phrase"] != "":
|
||||||
|
ifac_netkey = c["pass_phrase"]
|
||||||
|
|
||||||
configured_bitrate = None
|
configured_bitrate = None
|
||||||
if "bitrate" in c:
|
if "bitrate" in c:
|
||||||
@ -406,8 +420,6 @@ class Reticulum:
|
|||||||
|
|
||||||
interface.mode = interface_mode
|
interface.mode = interface_mode
|
||||||
|
|
||||||
RNS.Transport.interfaces.append(interface)
|
|
||||||
|
|
||||||
interface.announce_cap = announce_cap
|
interface.announce_cap = announce_cap
|
||||||
if configured_bitrate:
|
if configured_bitrate:
|
||||||
interface.bitrate = configured_bitrate
|
interface.bitrate = configured_bitrate
|
||||||
@ -452,8 +464,6 @@ class Reticulum:
|
|||||||
|
|
||||||
interface.mode = interface_mode
|
interface.mode = interface_mode
|
||||||
|
|
||||||
RNS.Transport.interfaces.append(interface)
|
|
||||||
|
|
||||||
interface.announce_cap = announce_cap
|
interface.announce_cap = announce_cap
|
||||||
if configured_bitrate:
|
if configured_bitrate:
|
||||||
interface.bitrate = configured_bitrate
|
interface.bitrate = configured_bitrate
|
||||||
@ -492,8 +502,6 @@ class Reticulum:
|
|||||||
|
|
||||||
interface.mode = interface_mode
|
interface.mode = interface_mode
|
||||||
|
|
||||||
RNS.Transport.interfaces.append(interface)
|
|
||||||
|
|
||||||
interface.announce_cap = announce_cap
|
interface.announce_cap = announce_cap
|
||||||
if configured_bitrate:
|
if configured_bitrate:
|
||||||
interface.bitrate = configured_bitrate
|
interface.bitrate = configured_bitrate
|
||||||
@ -529,8 +537,6 @@ class Reticulum:
|
|||||||
|
|
||||||
interface.mode = interface_mode
|
interface.mode = interface_mode
|
||||||
|
|
||||||
RNS.Transport.interfaces.append(interface)
|
|
||||||
|
|
||||||
interface.announce_cap = announce_cap
|
interface.announce_cap = announce_cap
|
||||||
if configured_bitrate:
|
if configured_bitrate:
|
||||||
interface.bitrate = configured_bitrate
|
interface.bitrate = configured_bitrate
|
||||||
@ -562,8 +568,6 @@ class Reticulum:
|
|||||||
|
|
||||||
interface.mode = interface_mode
|
interface.mode = interface_mode
|
||||||
|
|
||||||
RNS.Transport.interfaces.append(interface)
|
|
||||||
|
|
||||||
interface.announce_cap = announce_cap
|
interface.announce_cap = announce_cap
|
||||||
if configured_bitrate:
|
if configured_bitrate:
|
||||||
interface.bitrate = configured_bitrate
|
interface.bitrate = configured_bitrate
|
||||||
@ -599,8 +603,6 @@ class Reticulum:
|
|||||||
|
|
||||||
interface.mode = interface_mode
|
interface.mode = interface_mode
|
||||||
|
|
||||||
RNS.Transport.interfaces.append(interface)
|
|
||||||
|
|
||||||
interface.announce_cap = announce_cap
|
interface.announce_cap = announce_cap
|
||||||
if configured_bitrate:
|
if configured_bitrate:
|
||||||
interface.bitrate = configured_bitrate
|
interface.bitrate = configured_bitrate
|
||||||
@ -650,8 +652,6 @@ class Reticulum:
|
|||||||
|
|
||||||
interface.mode = interface_mode
|
interface.mode = interface_mode
|
||||||
|
|
||||||
RNS.Transport.interfaces.append(interface)
|
|
||||||
|
|
||||||
interface.announce_cap = announce_cap
|
interface.announce_cap = announce_cap
|
||||||
if configured_bitrate:
|
if configured_bitrate:
|
||||||
interface.bitrate = configured_bitrate
|
interface.bitrate = configured_bitrate
|
||||||
@ -702,8 +702,6 @@ class Reticulum:
|
|||||||
|
|
||||||
interface.mode = interface_mode
|
interface.mode = interface_mode
|
||||||
|
|
||||||
RNS.Transport.interfaces.append(interface)
|
|
||||||
|
|
||||||
interface.announce_cap = announce_cap
|
interface.announce_cap = announce_cap
|
||||||
if configured_bitrate:
|
if configured_bitrate:
|
||||||
interface.bitrate = configured_bitrate
|
interface.bitrate = configured_bitrate
|
||||||
@ -748,8 +746,6 @@ class Reticulum:
|
|||||||
|
|
||||||
interface.mode = interface_mode
|
interface.mode = interface_mode
|
||||||
|
|
||||||
RNS.Transport.interfaces.append(interface)
|
|
||||||
|
|
||||||
interface.announce_cap = announce_cap
|
interface.announce_cap = announce_cap
|
||||||
if configured_bitrate:
|
if configured_bitrate:
|
||||||
interface.bitrate = configured_bitrate
|
interface.bitrate = configured_bitrate
|
||||||
@ -762,6 +758,27 @@ class Reticulum:
|
|||||||
interface.ifac_netname = ifac_netname
|
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""
|
||||||
|
|
||||||
|
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)
|
RNS.Transport.interfaces.append(interface)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -859,6 +876,15 @@ class Reticulum:
|
|||||||
else:
|
else:
|
||||||
ifstats["peers"] = None
|
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 hasattr(interface, "announce_queue"):
|
||||||
if interface.announce_queue != None:
|
if interface.announce_queue != None:
|
||||||
ifstats["announce_queue"] = len(interface.announce_queue)
|
ifstats["announce_queue"] = len(interface.announce_queue)
|
||||||
|
@ -474,7 +474,23 @@ class Transport:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def transmit(interface, raw):
|
def transmit(interface, raw):
|
||||||
interface.processOutgoing(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
|
@staticmethod
|
||||||
def outbound(packet):
|
def outbound(packet):
|
||||||
@ -704,6 +720,44 @@ class Transport:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def inbound(raw, interface=None):
|
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):
|
while (Transport.jobs_running):
|
||||||
sleep(0.01)
|
sleep(0.01)
|
||||||
|
|
||||||
|
@ -92,6 +92,10 @@ def program_setup(configdir, dispall=False, verbosity = 0):
|
|||||||
clients = None
|
clients = None
|
||||||
|
|
||||||
print(" {n}".format(n=ifstat["name"]))
|
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))
|
print(" Status : {ss}".format(ss=ss))
|
||||||
|
|
||||||
if clients != None:
|
if clients != None:
|
||||||
@ -106,6 +110,10 @@ def program_setup(configdir, dispall=False, verbosity = 0):
|
|||||||
if "peers" in ifstat and ifstat["peers"] != None:
|
if "peers" in ifstat and ifstat["peers"] != None:
|
||||||
print(" Peers : {np} reachable".format(np=ifstat["peers"]))
|
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:
|
if "i2p_b32" in ifstat and ifstat["i2p_b32"] != None:
|
||||||
print(" I2P B32 : {ep}".format(ep=str(ifstat["i2p_b32"])))
|
print(" I2P B32 : {ep}".format(ep=str(ifstat["i2p_b32"])))
|
||||||
|
|
||||||
|
@ -60,7 +60,8 @@ logfile = None
|
|||||||
logdest = LOG_STDOUT
|
logdest = LOG_STDOUT
|
||||||
logtimefmt = "%Y-%m-%d %H:%M:%S"
|
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
|
_always_override_destination = False
|
||||||
|
|
||||||
@ -130,7 +131,7 @@ def log(msg, level=3, _override_destination = False):
|
|||||||
|
|
||||||
|
|
||||||
def rand():
|
def rand():
|
||||||
result = random.random()
|
result = instance_random.random()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def hexrep(data, delimit=True):
|
def hexrep(data, delimit=True):
|
||||||
|
Loading…
Reference in New Issue
Block a user