Implemented links
This commit is contained in:
parent
52968e8ba5
commit
75e0cb039d
|
@ -1,4 +1,5 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*.pyc
|
*.pyc
|
||||||
t.py
|
t.py
|
||||||
|
t2.py
|
||||||
TODO
|
TODO
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
header types
|
header types
|
||||||
-----------------
|
-----------------
|
||||||
type 1 00 One byte header, one 10 byte address field
|
type 1 00 Two byte header, one 10 byte address field
|
||||||
type 2 01 One byte header, two 10 byte address fields
|
type 2 01 Two byte header, two 10 byte address fields
|
||||||
type 3 10 Reserved
|
type 3 10 Two byte header, one 10 byte address field, used for link request proofs
|
||||||
type 4 11 Reserved for extended header format
|
type 4 11 Reserved for extended header format
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,11 @@ from cryptography.hazmat.primitives import serialization
|
||||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||||
from cryptography.hazmat.primitives.asymmetric import padding
|
from cryptography.hazmat.primitives.asymmetric import padding
|
||||||
|
|
||||||
|
class Callbacks:
|
||||||
|
def __init__(self):
|
||||||
|
self.link_established = None
|
||||||
|
self.packet = None
|
||||||
|
self.proof = None
|
||||||
|
|
||||||
class Destination:
|
class Destination:
|
||||||
KEYSIZE = RNS.Identity.KEYSIZE;
|
KEYSIZE = RNS.Identity.KEYSIZE;
|
||||||
|
@ -59,11 +64,14 @@ class Destination:
|
||||||
if "." in app_name: raise ValueError("Dots can't be used in app names")
|
if "." in app_name: raise ValueError("Dots can't be used in app names")
|
||||||
if not type in Destination.types: raise ValueError("Unknown destination type")
|
if not type in Destination.types: raise ValueError("Unknown destination type")
|
||||||
if not direction in Destination.directions: raise ValueError("Unknown destination direction")
|
if not direction in Destination.directions: raise ValueError("Unknown destination direction")
|
||||||
|
self.callbacks = Callbacks()
|
||||||
self.type = type
|
self.type = type
|
||||||
self.direction = direction
|
self.direction = direction
|
||||||
self.proof_strategy = Destination.PROVE_NONE
|
self.proof_strategy = Destination.PROVE_NONE
|
||||||
self.mtu = 0
|
self.mtu = 0
|
||||||
|
|
||||||
|
self.links = []
|
||||||
|
|
||||||
if identity != None and type == Destination.SINGLE:
|
if identity != None and type == Destination.SINGLE:
|
||||||
aspects = aspects+(identity.hexhash,)
|
aspects = aspects+(identity.hexhash,)
|
||||||
|
|
||||||
|
@ -87,11 +95,14 @@ class Destination:
|
||||||
return "<"+self.name+"/"+self.hexhash+">"
|
return "<"+self.name+"/"+self.hexhash+">"
|
||||||
|
|
||||||
|
|
||||||
def setCallback(self, callback):
|
def link_established_callback(self, callback):
|
||||||
self.callback = callback
|
self.callbacks.link_established = callback
|
||||||
|
|
||||||
def setProofCallback(self, callback):
|
def packet_callback(self, callback):
|
||||||
self.proofcallback = callback
|
self.callbacks.packet = callback
|
||||||
|
|
||||||
|
def proof_callback(self, callback):
|
||||||
|
self.callbacks.proof = callback
|
||||||
|
|
||||||
def setProofStrategy(self, proof_strategy):
|
def setProofStrategy(self, proof_strategy):
|
||||||
if not proof_strategy in Destination.proof_strategies:
|
if not proof_strategy in Destination.proof_strategies:
|
||||||
|
@ -101,9 +112,19 @@ class Destination:
|
||||||
|
|
||||||
def receive(self, packet):
|
def receive(self, packet):
|
||||||
plaintext = self.decrypt(packet.data)
|
plaintext = self.decrypt(packet.data)
|
||||||
if plaintext != None and self.callback != None:
|
if plaintext != None:
|
||||||
self.callback(plaintext, packet)
|
if packet.packet_type == RNS.Packet.LINKREQUEST:
|
||||||
|
self.incomingLinkRequest(plaintext, packet)
|
||||||
|
|
||||||
|
if packet.packet_type == RNS.Packet.RESOURCE:
|
||||||
|
if self.callbacks.packet != None:
|
||||||
|
self.callbacks.packet(plaintext, packet)
|
||||||
|
|
||||||
|
def incomingLinkRequest(self, data, packet):
|
||||||
|
link = RNS.Link.validateRequest(self, data, packet)
|
||||||
|
if link != None:
|
||||||
|
RNS.log(str(self)+" accepted link request", RNS.LOG_DEBUG)
|
||||||
|
self.links.append(link)
|
||||||
|
|
||||||
def createKeys(self):
|
def createKeys(self):
|
||||||
if self.type == Destination.PLAIN:
|
if self.type == Destination.PLAIN:
|
||||||
|
|
|
@ -14,9 +14,9 @@ from cryptography.hazmat.primitives.asymmetric import rsa
|
||||||
from cryptography.hazmat.primitives.asymmetric import padding
|
from cryptography.hazmat.primitives.asymmetric import padding
|
||||||
|
|
||||||
class Identity:
|
class Identity:
|
||||||
# Configure key size
|
#KEYSIZE = 1536
|
||||||
KEYSIZE = 1536
|
KEYSIZE = 1024
|
||||||
DERKEYSIZE = 1808
|
DERKEYSIZE = KEYSIZE+272
|
||||||
|
|
||||||
# Padding size, not configurable
|
# Padding size, not configurable
|
||||||
PADDINGSIZE= 336
|
PADDINGSIZE= 336
|
||||||
|
@ -223,7 +223,7 @@ class Identity:
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
except:
|
except:
|
||||||
RNS.log("Decryption by "+RNS.prettyhexrep(self.hash)+" failed")
|
RNS.log("Decryption by "+RNS.prettyhexrep(self.hash)+" failed", RNS.LOG_VERBOSE)
|
||||||
|
|
||||||
return plaintext;
|
return plaintext;
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -0,0 +1,174 @@
|
||||||
|
from cryptography.hazmat.backends import default_backend
|
||||||
|
from cryptography.hazmat.primitives import hashes
|
||||||
|
from cryptography.hazmat.primitives import serialization
|
||||||
|
from cryptography.hazmat.primitives.asymmetric import ec
|
||||||
|
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
|
||||||
|
from cryptography.fernet import Fernet
|
||||||
|
import base64
|
||||||
|
import RNS
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
class LinkCallbacks:
|
||||||
|
def __init__(self):
|
||||||
|
self.link_established = None
|
||||||
|
self.packet = None
|
||||||
|
self.resource_started = None
|
||||||
|
self.resource_completed = None
|
||||||
|
|
||||||
|
class Link:
|
||||||
|
CURVE = ec.SECP256R1()
|
||||||
|
ECPUBSIZE = 91
|
||||||
|
|
||||||
|
PENDING = 0x00
|
||||||
|
ACTIVE = 0x01
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def validateRequest(owner, data, packet):
|
||||||
|
if len(data) == (Link.ECPUBSIZE):
|
||||||
|
try:
|
||||||
|
link = Link(owner = owner, peer_pub_bytes = data[:Link.ECPUBSIZE])
|
||||||
|
link.setLinkID(packet)
|
||||||
|
RNS.log("Validating link request "+RNS.prettyhexrep(link.link_id), RNS.LOG_VERBOSE)
|
||||||
|
link.handshake()
|
||||||
|
link.attached_interface = packet.receiving_interface
|
||||||
|
link.prove()
|
||||||
|
RNS.Transport.registerLink(link)
|
||||||
|
if link.owner.callbacks.link_established != None:
|
||||||
|
link.owner.callbacks.link_established(link)
|
||||||
|
RNS.log("Incoming link request "+str(link)+" accepted", RNS.LOG_VERBOSE)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
RNS.log("Validating link request failed", RNS.LOG_VERBOSE)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
else:
|
||||||
|
RNS.log("Invalid link request payload size, dropping request", RNS.LOG_VERBOSE)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, destination=None, owner=None, peer_pub_bytes = None):
|
||||||
|
self.callbacks = LinkCallbacks()
|
||||||
|
self.status = Link.PENDING
|
||||||
|
self.type = RNS.Destination.LINK
|
||||||
|
self.owner = owner
|
||||||
|
self.destination = destination
|
||||||
|
self.attached_interface = None
|
||||||
|
if self.destination == None:
|
||||||
|
self.initiator = False
|
||||||
|
else:
|
||||||
|
self.initiator = True
|
||||||
|
|
||||||
|
self.prv = ec.generate_private_key(Link.CURVE, default_backend())
|
||||||
|
self.pub = self.prv.public_key()
|
||||||
|
self.pub_bytes = self.pub.public_bytes(
|
||||||
|
encoding=serialization.Encoding.DER,
|
||||||
|
format=serialization.PublicFormat.SubjectPublicKeyInfo
|
||||||
|
)
|
||||||
|
|
||||||
|
if peer_pub_bytes == None:
|
||||||
|
self.peer_pub = None
|
||||||
|
self.peer_pub_bytes = None
|
||||||
|
else:
|
||||||
|
self.loadPeer(peer_pub_bytes)
|
||||||
|
|
||||||
|
if (self.initiator):
|
||||||
|
self.request_data = self.pub_bytes
|
||||||
|
self.packet = RNS.Packet(destination, self.request_data, packet_type=RNS.Packet.LINKREQUEST)
|
||||||
|
self.packet.pack()
|
||||||
|
self.setLinkID(self.packet)
|
||||||
|
RNS.Transport.registerLink(self)
|
||||||
|
self.packet.send()
|
||||||
|
RNS.log("Link request "+RNS.prettyhexrep(self.link_id)+" sent to "+str(self.destination), RNS.LOG_VERBOSE)
|
||||||
|
|
||||||
|
|
||||||
|
def loadPeer(self, peer_pub_bytes):
|
||||||
|
self.peer_pub_bytes = peer_pub_bytes
|
||||||
|
self.peer_pub = serialization.load_der_public_key(peer_pub_bytes, backend=default_backend())
|
||||||
|
self.peer_pub.curce = Link.CURVE
|
||||||
|
|
||||||
|
def setLinkID(self, packet):
|
||||||
|
self.link_id = RNS.Identity.truncatedHash(packet.raw)
|
||||||
|
self.hash = self.link_id
|
||||||
|
|
||||||
|
def handshake(self):
|
||||||
|
self.shared_key = self.prv.exchange(ec.ECDH(), self.peer_pub)
|
||||||
|
self.derived_key = HKDF(
|
||||||
|
algorithm=hashes.SHA256(),
|
||||||
|
length=32,
|
||||||
|
salt=self.getSalt(),
|
||||||
|
info=self.getContext(),
|
||||||
|
backend=default_backend()
|
||||||
|
).derive(self.shared_key)
|
||||||
|
|
||||||
|
def prove(self):
|
||||||
|
signed_data = self.link_id+self.pub_bytes
|
||||||
|
signature = self.owner.identity.sign(signed_data)
|
||||||
|
|
||||||
|
proof_data = self.pub_bytes+signature
|
||||||
|
proof = RNS.Packet(self, proof_data, packet_type=RNS.Packet.PROOF, header_type=RNS.Packet.HEADER_3)
|
||||||
|
proof.send()
|
||||||
|
|
||||||
|
def validateProof(self, packet):
|
||||||
|
peer_pub_bytes = packet.data[:Link.ECPUBSIZE]
|
||||||
|
signed_data = self.link_id+peer_pub_bytes
|
||||||
|
signature = packet.data[Link.ECPUBSIZE:RNS.Identity.KEYSIZE/8+Link.ECPUBSIZE]
|
||||||
|
|
||||||
|
if self.destination.identity.validate(signature, signed_data):
|
||||||
|
self.loadPeer(peer_pub_bytes)
|
||||||
|
self.handshake()
|
||||||
|
self.attached_interface = packet.receiving_interface
|
||||||
|
RNS.Transport.activateLink(self)
|
||||||
|
if self.callbacks.link_established != None:
|
||||||
|
self.callbacks.link_established(self)
|
||||||
|
RNS.log("Link "+str(self)+" established with "+str(self.destination), RNS.LOG_VERBOSE)
|
||||||
|
else:
|
||||||
|
RNS.log("Invalid link proof signature received by "+str(self), RNS.LOG_VERBOSE)
|
||||||
|
|
||||||
|
|
||||||
|
def getSalt(self):
|
||||||
|
return self.link_id
|
||||||
|
|
||||||
|
def getContext(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def receive(self, packet):
|
||||||
|
if packet.receiving_interface != self.attached_interface:
|
||||||
|
RNS.log("Link-associated packet received on unexpected interface! Someone might be trying to manipulate your communication!", RNS.LOG_ERROR)
|
||||||
|
else:
|
||||||
|
plaintext = self.decrypt(packet.data)
|
||||||
|
if (self.callbacks.packet != None):
|
||||||
|
self.callbacks.packet(plaintext, packet)
|
||||||
|
|
||||||
|
def encrypt(self, plaintext):
|
||||||
|
try:
|
||||||
|
fernet = Fernet(base64.urlsafe_b64encode(self.derived_key))
|
||||||
|
ciphertext = base64.urlsafe_b64decode(fernet.encrypt(plaintext))
|
||||||
|
return ciphertext
|
||||||
|
except Exception as e:
|
||||||
|
RNS.log("Encryption on link "+str(self)+" failed. The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||||
|
|
||||||
|
|
||||||
|
def decrypt(self, ciphertext):
|
||||||
|
try:
|
||||||
|
fernet = Fernet(base64.urlsafe_b64encode(self.derived_key))
|
||||||
|
plaintext = fernet.decrypt(base64.urlsafe_b64encode(ciphertext))
|
||||||
|
return plaintext
|
||||||
|
except Exception as e:
|
||||||
|
RNS.log("Decryption failed on link "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||||
|
|
||||||
|
def link_established_callback(self, callback):
|
||||||
|
self.callbacks.link_established = callback
|
||||||
|
|
||||||
|
def packet_callback(self, callback):
|
||||||
|
self.callbacks.packet = callback
|
||||||
|
|
||||||
|
def resource_started_callback(self, callback):
|
||||||
|
self.callbacks.resource_started = callback
|
||||||
|
|
||||||
|
def resource_completed_callback(self, callback):
|
||||||
|
self.callbacks.resource_completed = callback
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return RNS.prettyhexrep(self.link_id)
|
|
@ -12,7 +12,7 @@ class Packet:
|
||||||
|
|
||||||
HEADER_1 = 0x00; # Normal header format
|
HEADER_1 = 0x00; # Normal header format
|
||||||
HEADER_2 = 0x01; # Header format used for link packets in transport
|
HEADER_2 = 0x01; # Header format used for link packets in transport
|
||||||
HEADER_3 = 0x02; # Reserved
|
HEADER_3 = 0x02; # Normal header format, but used to indicate a link request proof
|
||||||
HEADER_4 = 0x03; # Reserved
|
HEADER_4 = 0x03; # Reserved
|
||||||
header_types = [HEADER_1, HEADER_2, HEADER_3, HEADER_4]
|
header_types = [HEADER_1, HEADER_2, HEADER_3, HEADER_4]
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ class Packet:
|
||||||
self.transport_id = transport_id
|
self.transport_id = transport_id
|
||||||
self.data = data
|
self.data = data
|
||||||
self.flags = self.getPackedFlags()
|
self.flags = self.getPackedFlags()
|
||||||
self.MTU = self.destination.MTU
|
self.MTU = RNS.Reticulum.MTU
|
||||||
|
|
||||||
self.raw = None
|
self.raw = None
|
||||||
self.packed = False
|
self.packed = False
|
||||||
|
@ -45,6 +45,9 @@ class Packet:
|
||||||
self.packet_hash = None
|
self.packet_hash = None
|
||||||
|
|
||||||
def getPackedFlags(self):
|
def getPackedFlags(self):
|
||||||
|
if self.header_type == Packet.HEADER_3:
|
||||||
|
packed_flags = (self.header_type << 6) | (self.transport_type << 4) | RNS.Destination.LINK | self.packet_type
|
||||||
|
else:
|
||||||
packed_flags = (self.header_type << 6) | (self.transport_type << 4) | (self.destination.type << 2) | self.packet_type
|
packed_flags = (self.header_type << 6) | (self.transport_type << 4) | (self.destination.type << 2) | self.packet_type
|
||||||
return packed_flags
|
return packed_flags
|
||||||
|
|
||||||
|
@ -58,11 +61,15 @@ class Packet:
|
||||||
else:
|
else:
|
||||||
raise IOError("Packet with header type 2 must have a transport ID")
|
raise IOError("Packet with header type 2 must have a transport ID")
|
||||||
|
|
||||||
|
if self.header_type == Packet.HEADER_1:
|
||||||
self.header += self.destination.hash
|
self.header += self.destination.hash
|
||||||
if self.packet_type != Packet.ANNOUNCE:
|
if self.packet_type != Packet.ANNOUNCE:
|
||||||
self.ciphertext = self.destination.encrypt(self.data)
|
self.ciphertext = self.destination.encrypt(self.data)
|
||||||
else:
|
else:
|
||||||
self.ciphertext = self.data
|
self.ciphertext = self.data
|
||||||
|
if self.header_type == Packet.HEADER_3:
|
||||||
|
self.header += self.destination.link_id
|
||||||
|
self.ciphertext = self.data
|
||||||
|
|
||||||
self.raw = self.header + self.ciphertext
|
self.raw = self.header + self.ciphertext
|
||||||
|
|
||||||
|
@ -93,9 +100,10 @@ class Packet:
|
||||||
|
|
||||||
def send(self):
|
def send(self):
|
||||||
if not self.sent:
|
if not self.sent:
|
||||||
|
if not self.packed:
|
||||||
self.pack()
|
self.pack()
|
||||||
#RNS.log("Size: "+str(len(self.raw))+" header is "+str(len(self.header))+" payload is "+str(len(self.ciphertext)), RNS.LOG_DEBUG)
|
|
||||||
RNS.Transport.outbound(self.raw)
|
RNS.Transport.outbound(self)
|
||||||
self.packet_hash = RNS.Identity.fullHash(self.raw)
|
self.packet_hash = RNS.Identity.fullHash(self.raw)
|
||||||
self.sent_at = time.time()
|
self.sent_at = time.time()
|
||||||
self.sent = True
|
self.sent = True
|
||||||
|
|
|
@ -8,7 +8,7 @@ import os.path
|
||||||
import os
|
import os
|
||||||
import RNS
|
import RNS
|
||||||
|
|
||||||
import traceback
|
#import traceback
|
||||||
|
|
||||||
class Reticulum:
|
class Reticulum:
|
||||||
MTU = 500
|
MTU = 500
|
||||||
|
|
|
@ -10,15 +10,23 @@ class Transport:
|
||||||
|
|
||||||
interfaces = []
|
interfaces = []
|
||||||
destinations = []
|
destinations = []
|
||||||
|
pending_links = []
|
||||||
|
active_links = []
|
||||||
packet_hashlist = []
|
packet_hashlist = []
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def outbound(raw):
|
def outbound(packet):
|
||||||
Transport.cacheRaw(raw)
|
Transport.cacheRaw(packet.raw)
|
||||||
for interface in Transport.interfaces:
|
for interface in Transport.interfaces:
|
||||||
if interface.OUT:
|
if interface.OUT:
|
||||||
RNS.log("Transmitting "+str(len(raw))+" bytes via: "+str(interface), RNS.LOG_DEBUG)
|
should_transmit = True
|
||||||
interface.processOutgoing(raw)
|
if packet.destination.type == RNS.Destination.LINK:
|
||||||
|
if interface != packet.destination.attached_interface:
|
||||||
|
should_transmit = False
|
||||||
|
|
||||||
|
if should_transmit:
|
||||||
|
RNS.log("Transmitting "+str(len(packet.raw))+" bytes via: "+str(interface), RNS.LOG_DEBUG)
|
||||||
|
interface.processOutgoing(packet.raw)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def inbound(raw, interface=None):
|
def inbound(raw, interface=None):
|
||||||
|
@ -30,12 +38,26 @@ class Transport:
|
||||||
packet = RNS.Packet(None, raw)
|
packet = RNS.Packet(None, raw)
|
||||||
packet.unpack()
|
packet.unpack()
|
||||||
packet.packet_hash = packet_hash
|
packet.packet_hash = packet_hash
|
||||||
|
packet.receiving_interface = interface
|
||||||
|
|
||||||
if packet.packet_type == RNS.Packet.ANNOUNCE:
|
if packet.packet_type == RNS.Packet.ANNOUNCE:
|
||||||
if RNS.Identity.validateAnnounce(packet):
|
if RNS.Identity.validateAnnounce(packet):
|
||||||
Transport.cache(packet)
|
Transport.cache(packet)
|
||||||
|
|
||||||
|
if packet.packet_type == RNS.Packet.LINKREQUEST:
|
||||||
|
for destination in Transport.destinations:
|
||||||
|
if destination.hash == packet.destination_hash and destination.type == packet.destination_type:
|
||||||
|
packet.destination = destination
|
||||||
|
destination.receive(packet)
|
||||||
|
Transport.cache(packet)
|
||||||
|
|
||||||
if packet.packet_type == RNS.Packet.RESOURCE:
|
if packet.packet_type == RNS.Packet.RESOURCE:
|
||||||
|
if packet.destination_type == RNS.Destination.LINK:
|
||||||
|
for link in Transport.active_links:
|
||||||
|
if link.link_id == packet.destination_hash:
|
||||||
|
link.receive(packet)
|
||||||
|
Transport.cache(packet)
|
||||||
|
else:
|
||||||
for destination in Transport.destinations:
|
for destination in Transport.destinations:
|
||||||
if destination.hash == packet.destination_hash and destination.type == packet.destination_type:
|
if destination.hash == packet.destination_hash and destination.type == packet.destination_type:
|
||||||
packet.destination = destination
|
packet.destination = destination
|
||||||
|
@ -43,6 +65,13 @@ class Transport:
|
||||||
Transport.cache(packet)
|
Transport.cache(packet)
|
||||||
|
|
||||||
if packet.packet_type == RNS.Packet.PROOF:
|
if packet.packet_type == RNS.Packet.PROOF:
|
||||||
|
if packet.header_type == RNS.Packet.HEADER_3:
|
||||||
|
# This is a link request proof, forward
|
||||||
|
# to a waiting link request
|
||||||
|
for link in Transport.pending_links:
|
||||||
|
if link.link_id == packet.destination_hash:
|
||||||
|
link.validateProof(packet)
|
||||||
|
else:
|
||||||
for destination in Transport.destinations:
|
for destination in Transport.destinations:
|
||||||
if destination.hash == packet.destination_hash:
|
if destination.hash == packet.destination_hash:
|
||||||
if destination.proofcallback != None:
|
if destination.proofcallback != None:
|
||||||
|
@ -55,8 +84,34 @@ class Transport:
|
||||||
if destination.direction == RNS.Destination.IN:
|
if destination.direction == RNS.Destination.IN:
|
||||||
Transport.destinations.append(destination)
|
Transport.destinations.append(destination)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def registerLink(link):
|
||||||
|
RNS.log("Registering link "+str(link))
|
||||||
|
if link.initiator:
|
||||||
|
Transport.pending_links.append(link)
|
||||||
|
else:
|
||||||
|
Transport.active_links.append(link)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def activateLink(link):
|
||||||
|
RNS.log("Activating link "+str(link))
|
||||||
|
if link in Transport.pending_links:
|
||||||
|
Transport.pending_links.remove(link)
|
||||||
|
Transport.active_links.append(link)
|
||||||
|
link.status = RNS.Link.ACTIVE
|
||||||
|
else:
|
||||||
|
RNS.log("Attempted to activate a link that was not in the pending table", RNS.LOG_ERROR)
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def shouldCache(packet):
|
||||||
|
# TODO: Implement sensible rules for which
|
||||||
|
# packets to cache
|
||||||
|
return False
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def cache(packet):
|
def cache(packet):
|
||||||
|
if RNS.Transport.shouldCache(packet):
|
||||||
RNS.Transport.cacheRaw(packet.raw)
|
RNS.Transport.cacheRaw(packet.raw)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
@ -4,6 +4,7 @@ import time
|
||||||
|
|
||||||
from .Reticulum import Reticulum
|
from .Reticulum import Reticulum
|
||||||
from .Identity import Identity
|
from .Identity import Identity
|
||||||
|
from .Link import Link
|
||||||
from .Transport import Transport
|
from .Transport import Transport
|
||||||
from .Destination import Destination
|
from .Destination import Destination
|
||||||
from .Packet import Packet
|
from .Packet import Packet
|
||||||
|
|
Loading…
Reference in New Issue