2016-06-03 17:02:02 +00:00
|
|
|
import struct
|
2018-03-20 11:32:41 +00:00
|
|
|
import time
|
2018-04-04 12:14:22 +00:00
|
|
|
import RNS
|
2016-06-03 17:02:02 +00:00
|
|
|
|
|
|
|
class Packet:
|
2018-03-19 15:39:08 +00:00
|
|
|
# Constants
|
2018-03-19 17:11:50 +00:00
|
|
|
RESOURCE = 0x00;
|
|
|
|
ANNOUNCE = 0x01;
|
2018-03-19 15:39:08 +00:00
|
|
|
LINKREQUEST = 0x02;
|
|
|
|
PROOF = 0x03;
|
2018-03-19 17:11:50 +00:00
|
|
|
types = [RESOURCE, ANNOUNCE, LINKREQUEST, PROOF]
|
2016-06-03 17:02:02 +00:00
|
|
|
|
2018-03-19 15:39:08 +00:00
|
|
|
HEADER_1 = 0x00; # Normal header format
|
|
|
|
HEADER_2 = 0x01; # Header format used for link packets in transport
|
2018-04-16 15:13:39 +00:00
|
|
|
HEADER_3 = 0x02; # Normal header format, but used to indicate a link request proof
|
2018-03-19 15:39:08 +00:00
|
|
|
HEADER_4 = 0x03; # Reserved
|
|
|
|
header_types = [HEADER_1, HEADER_2, HEADER_3, HEADER_4]
|
2016-06-03 17:02:02 +00:00
|
|
|
|
2018-04-04 12:14:22 +00:00
|
|
|
def __init__(self, destination, data, packet_type = RESOURCE, transport_type = RNS.Transport.BROADCAST, header_type = HEADER_1, transport_id = None):
|
2018-03-19 15:39:08 +00:00
|
|
|
if destination != None:
|
|
|
|
if transport_type == None:
|
2018-04-04 12:14:22 +00:00
|
|
|
transport_type = RNS.Transport.BROADCAST
|
2016-06-03 17:02:02 +00:00
|
|
|
|
2018-03-19 15:39:08 +00:00
|
|
|
self.header_type = header_type
|
|
|
|
self.packet_type = packet_type
|
|
|
|
self.transport_type = transport_type
|
2016-06-03 17:02:02 +00:00
|
|
|
|
2018-03-19 15:39:08 +00:00
|
|
|
self.hops = 0;
|
|
|
|
self.destination = destination
|
|
|
|
self.transport_id = transport_id
|
|
|
|
self.data = data
|
|
|
|
self.flags = self.getPackedFlags()
|
2018-04-16 15:13:39 +00:00
|
|
|
self.MTU = RNS.Reticulum.MTU
|
2018-03-19 15:39:08 +00:00
|
|
|
|
|
|
|
self.raw = None
|
|
|
|
self.packed = False
|
|
|
|
self.sent = False
|
2018-03-20 11:32:41 +00:00
|
|
|
self.fromPacked = False
|
2018-03-19 15:39:08 +00:00
|
|
|
else:
|
2018-03-20 11:32:41 +00:00
|
|
|
self.raw = data
|
|
|
|
self.packed = True
|
|
|
|
self.fromPacked = True
|
|
|
|
|
|
|
|
self.sent_at = None
|
|
|
|
self.packet_hash = None
|
2018-03-19 15:39:08 +00:00
|
|
|
|
|
|
|
def getPackedFlags(self):
|
2018-04-16 15:13:39 +00:00
|
|
|
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
|
2018-03-19 15:39:08 +00:00
|
|
|
return packed_flags
|
|
|
|
|
|
|
|
def pack(self):
|
|
|
|
self.header = ""
|
|
|
|
self.header += struct.pack("!B", self.flags)
|
|
|
|
self.header += struct.pack("!B", self.hops)
|
|
|
|
if self.header_type == Packet.HEADER_2:
|
|
|
|
if t_destination != None:
|
|
|
|
self.header += self.t_destination
|
|
|
|
else:
|
|
|
|
raise IOError("Packet with header type 2 must have a transport ID")
|
|
|
|
|
2018-04-16 15:13:39 +00:00
|
|
|
if self.header_type == Packet.HEADER_1:
|
|
|
|
self.header += self.destination.hash
|
|
|
|
if self.packet_type != Packet.ANNOUNCE:
|
|
|
|
self.ciphertext = self.destination.encrypt(self.data)
|
|
|
|
else:
|
|
|
|
self.ciphertext = self.data
|
|
|
|
if self.header_type == Packet.HEADER_3:
|
|
|
|
self.header += self.destination.link_id
|
2018-03-19 17:11:50 +00:00
|
|
|
self.ciphertext = self.data
|
|
|
|
|
2018-03-19 15:39:08 +00:00
|
|
|
self.raw = self.header + self.ciphertext
|
|
|
|
|
|
|
|
if len(self.raw) > self.MTU:
|
|
|
|
raise IOError("Packet size of "+str(len(self.raw))+" exceeds MTU of "+str(self.MTU)+" bytes")
|
|
|
|
|
|
|
|
self.packed = True
|
|
|
|
|
|
|
|
def unpack(self):
|
|
|
|
self.flags = ord(self.raw[0])
|
|
|
|
self.hops = ord(self.raw[1])
|
|
|
|
|
|
|
|
self.header_type = (self.flags & 0b11000000) >> 6
|
|
|
|
self.transport_type = (self.flags & 0b00110000) >> 4
|
|
|
|
self.destination_type = (self.flags & 0b00001100) >> 2
|
|
|
|
self.packet_type = (self.flags & 0b00000011)
|
|
|
|
|
|
|
|
if self.header_type == Packet.HEADER_2:
|
|
|
|
self.transport_id = self.raw[2:12]
|
|
|
|
self.destination_hash = self.raw[12:22]
|
|
|
|
self.data = self.raw[22:]
|
|
|
|
else:
|
|
|
|
self.transport_id = None
|
|
|
|
self.destination_hash = self.raw[2:12]
|
|
|
|
self.data = self.raw[12:]
|
|
|
|
|
|
|
|
self.packed = False
|
|
|
|
|
|
|
|
def send(self):
|
|
|
|
if not self.sent:
|
2018-04-16 15:13:39 +00:00
|
|
|
if not self.packed:
|
|
|
|
self.pack()
|
|
|
|
|
|
|
|
RNS.Transport.outbound(self)
|
2018-04-04 12:14:22 +00:00
|
|
|
self.packet_hash = RNS.Identity.fullHash(self.raw)
|
2018-03-20 11:32:41 +00:00
|
|
|
self.sent_at = time.time()
|
2016-06-03 17:02:02 +00:00
|
|
|
self.sent = True
|
|
|
|
else:
|
|
|
|
raise IOError("Packet was already sent")
|
|
|
|
|
|
|
|
def resend(self):
|
|
|
|
if self.sent:
|
|
|
|
Transport.outbound(self.raw)
|
|
|
|
else:
|
2018-03-20 11:32:41 +00:00
|
|
|
raise IOError("Packet was not sent yet")
|
|
|
|
|
|
|
|
def prove(self, destination):
|
|
|
|
if self.fromPacked and self.destination:
|
|
|
|
if self.destination.identity and self.destination.identity.prv:
|
|
|
|
self.destination.identity.prove(self, destination)
|
|
|
|
|
|
|
|
def validateProofPacket(self, proof_packet):
|
|
|
|
return self.validateProof(proof_packet.data)
|
|
|
|
|
|
|
|
def validateProof(self, proof):
|
|
|
|
proof_hash = proof[:32]
|
|
|
|
signature = proof[32:]
|
|
|
|
if proof_hash == self.packet_hash:
|
|
|
|
return self.destination.identity.validate(signature, proof_hash)
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|