Ejemplo n.º 1
0
    def __as_packet(self):
        if not self.packed:
            self.pack()

        if not self.__delivery_destination:
            raise ValueError(
                "Can't synthesize packet for LXMF message before delivery destination is known"
            )

        if self.method == LXMessage.OPPORTUNISTIC:
            return RNS.Packet(self.__delivery_destination,
                              self.packed[LXMessage.DESTINATION_LENGTH:])
        elif self.method == LXMessage.DIRECT or self.method == LXMessage.PROPAGATED:
            return RNS.Packet(self.__delivery_destination, self.packed)
Ejemplo n.º 2
0
    def validate_proof(self, packet):
        if self.initiator and len(packet.data) == RNS.Identity.SIGLENGTH // 8:
            signed_data = self.link_id + self.peer_pub_bytes + self.peer_sig_pub_bytes
            signature = packet.data[:RNS.Identity.SIGLENGTH // 8]

            if self.destination.identity.validate(signature, signed_data):
                self.rtt = time.time() - self.request_time
                self.attached_interface = packet.receiving_interface
                RNS.Transport.activate_link(self)
                RNS.log(
                    "Link " + str(self) + " established with " +
                    str(self.destination) + ", RTT is " + str(self.rtt),
                    RNS.LOG_VERBOSE)
                rtt_data = umsgpack.packb(self.rtt)
                rtt_packet = RNS.Packet(self,
                                        rtt_data,
                                        context=RNS.Packet.LRRTT)
                RNS.log("Sending RTT packet", RNS.LOG_EXTREME)
                rtt_packet.send()
                self.had_outbound()

                self.status = Link.ACTIVE
                if self.callbacks.link_established != None:
                    thread = threading.Thread(
                        target=self.callbacks.link_established, args=(self, ))
                    thread.setDaemon(True)
                    thread.start()
            else:
                RNS.log(
                    "Invalid link proof signature received by " + str(self) +
                    ". Ignoring.", RNS.LOG_DEBUG)
Ejemplo n.º 3
0
    def validateProof(self, packet):
        if self.initiator:
            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.rtt = time.time() - self.request_time
                self.attached_interface = packet.receiving_interface
                RNS.Transport.activateLink(self)
                RNS.log(
                    "Link " + str(self) + " established with " +
                    str(self.destination) + ", RTT is " + str(self.rtt),
                    RNS.LOG_VERBOSE)
                rtt_data = umsgpack.packb(self.rtt)
                rtt_packet = RNS.Packet(self,
                                        rtt_data,
                                        context=RNS.Packet.LRRTT)
                RNS.log("Sending RTT packet", RNS.LOG_EXTREME)
                rtt_packet.send()

                self.status = Link.ACTIVE
                if self.callbacks.link_established != None:
                    self.callbacks.link_established(self)
            else:
                RNS.log(
                    "Invalid link proof signature received by " + str(self),
                    RNS.LOG_VERBOSE)
                # TODO: should we really do this, or just wait
                # for a valid one? Needs analysis.
                self.teardown()
Ejemplo n.º 4
0
def client_loop():
    global server_link

    # Wait for the link to become active
    while not server_link:
        time.sleep(0.1)

    should_quit = False
    while not should_quit:
        try:
            print("> ", end=" ")
            text = input()

            # Check if we should quit the example
            if text == "quit" or text == "q" or text == "exit":
                should_quit = True
                server_link.teardown()

            # If not, send the entered text over the link
            if text != "":
                data = text.encode("utf-8")
                RNS.Packet(server_link, data).send()
        except Exception as e:
            should_quit = True
            server_link.teardown()
Ejemplo n.º 5
0
    def __advertise_job(self):
        data = ResourceAdvertisement(self).pack()
        self.advertisement_packet = RNS.Packet(self.link,
                                               data,
                                               context=RNS.Packet.RESOURCE_ADV)
        while not self.link.ready_for_new_resource():
            self.status = Resource.QUEUED
            sleep(0.25)

        try:
            self.advertisement_packet.send()
            self.last_activity = time.time()
            self.adv_sent = self.last_activity
            self.rtt = None
            self.status = Resource.ADVERTISED
            self.link.register_outgoing_resource(self)
            RNS.log(
                "Sent resource advertisement for " +
                RNS.prettyhexrep(self.hash), RNS.LOG_DEBUG)
        except Exception as e:
            RNS.log(
                "Could not advertise resource, the contained exception was: " +
                str(e), RNS.LOG_ERROR)
            self.cancel()
            return

        self.watchdog_job()
Ejemplo n.º 6
0
def client_loop():
    global server_link

    # Wait for the link to become active
    while not server_link:
        time.sleep(0.1)

    should_quit = False
    while not should_quit:
        try:
            print("> ", end=" ")
            text = input()

            # Check if we should quit the example
            if text == "quit" or text == "q" or text == "exit":
                should_quit = True
                server_link.teardown()

            # If not, send the entered text over the link
            if text != "":
                data = text.encode("utf-8")
                if len(data) <= RNS.Link.MDU:
                    RNS.Packet(server_link, data).send()
                else:
                    RNS.log(
                        "Cannot send this packet, the data size of "+
                        str(len(data))+" bytes exceeds the link packet MDU of "+
                        str(RNS.Link.MDU)+" bytes",
                        RNS.LOG_ERROR
                    )

        except Exception as e:
            RNS.log("Error while sending data over the link: "+str(e))
            should_quit = True
            server_link.teardown()
Ejemplo n.º 7
0
def client_connected(link):
    # Check if the served directory still exists
    if os.path.isdir(serve_path):
        RNS.log("Client connected, sending file list...")

        link.set_link_closed_callback(client_disconnected)

        # We pack a list of files for sending in a packet
        data = umsgpack.packb(list_files())

        # Check the size of the packed data
        if len(data) <= RNS.Link.MDU:
            # If it fits in one packet, we will just
            # send it as a single packet over the link.
            list_packet = RNS.Packet(link, data)
            list_receipt = list_packet.send()
            list_receipt.set_timeout(APP_TIMEOUT)
            list_receipt.set_delivery_callback(list_delivered)
            list_receipt.set_timeout_callback(list_timeout)
        else:
            RNS.log("Too many files in served directory!", RNS.LOG_ERROR)
            RNS.log(
                "You should implement a function to split the filelist over multiple packets.",
                RNS.LOG_ERROR)
            RNS.log("Hint: The client already supports it :)", RNS.LOG_ERROR)

        # After this, we're just going to keep the link
        # open until the client requests a file. We'll
        # configure a function that get's called when
        # the client sends a packet with a file request.
        link.set_packet_callback(client_request)
    else:
        RNS.log("Client connected, but served path no longer exists!",
                RNS.LOG_ERROR)
        link.teardown()
Ejemplo n.º 8
0
    def announce(self, app_data=None, path_response=False):
        destination_hash = self.hash
        random_hash = RNS.Identity.getRandomHash()

        signed_data = self.hash + self.identity.getPublicKey() + random_hash
        if app_data != None:
            signed_data += app_data

        signature = self.identity.sign(signed_data)

        # TODO: Check if this could be optimised by only
        # carrying the hash in the destination field, not
        # also redundantly inside the signed blob as here
        announce_data = self.hash + self.identity.getPublicKey(
        ) + random_hash + signature

        if app_data != None:
            announce_data += app_data

        if path_response:
            announce_context = RNS.Packet.PATH_RESPONSE
        else:
            announce_context = RNS.Packet.NONE

        RNS.Packet(self,
                   announce_data,
                   RNS.Packet.ANNOUNCE,
                   context=announce_context).send()
Ejemplo n.º 9
0
    def __init__(self, destination=None, owner=None, peer_pub_bytes=None):
        if destination != None and destination.type != RNS.Destination.SINGLE:
            raise TypeError(
                "Links can only be established to the \"single\" destination type"
            )
        self.rtt = None
        self.callbacks = LinkCallbacks()
        self.resource_strategy = Link.ACCEPT_NONE
        self.outgoing_resources = []
        self.incoming_resources = []
        self.last_inbound = 0
        self.last_outbound = 0
        self.tx = 0
        self.rx = 0
        self.txbytes = 0
        self.rxbytes = 0
        self.default_timeout = Link.DEFAULT_TIMEOUT
        self.proof_timeout = self.default_timeout
        self.timeout_factor = Link.TIMEOUT_FACTOR
        self.keepalive = Link.KEEPALIVE
        self.watchdog_lock = False
        self.status = Link.PENDING
        self.type = RNS.Destination.LINK
        self.owner = owner
        self.destination = destination
        self.attached_interface = None
        self.__encryption_disabled = False
        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.request_time = time.time()
            self.start_watchdog()
            self.packet.send()
            RNS.log(
                "Link request " + RNS.prettyhexrep(self.link_id) +
                " sent to " + str(self.destination), RNS.LOG_VERBOSE)
Ejemplo n.º 10
0
 def cache_request_packet(packet):
     if len(packet.data) == RNS.Identity.HASHLENGTH / 8:
         packet_hash = RNS.hexrep(packet.data, delimit=False)
         path = RNS.Reticulum.cachepath + "/" + packet_hash
         if os.path.isfile(path):
             file = open(path, "r")
             raw = file.read()
             file.close()
             packet = RNS.Packet(None, raw)
Ejemplo n.º 11
0
def server_packet_received(message, packet):
    global latest_client_link

    text = message.decode("utf-8")
    RNS.log("Received data on the link: " + text)

    reply_text = "I got \"" + text + "\" from you"
    reply_data = reply_text.encode("utf-8")
    RNS.Packet(latest_client_link, reply_data).send()
Ejemplo n.º 12
0
 def prove(self):
     if not self.status == Resource.FAILED:
         proof = RNS.Identity.fullHash(self.data + self.hash)
         proof_data = self.hash + proof
         proof_packet = RNS.Packet(self.link,
                                   proof_data,
                                   packet_type=RNS.Packet.PROOF,
                                   context=RNS.Packet.RESOURCE_PRF)
         proof_packet.send()
Ejemplo n.º 13
0
    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,
                           context=RNS.Packet.LRPROOF)
        proof.send()
Ejemplo n.º 14
0
    def request_next(self):
        while self.receiving_part:
            sleep(0.001)

        if not self.status == Resource.FAILED:
            if not self.waiting_for_hmu:
                self.outstanding_parts = 0
                hashmap_exhausted = Resource.HASHMAP_IS_NOT_EXHAUSTED
                requested_hashes = b""

                offset = (1 if self.consecutive_completed_height > 0 else 0)
                i = 0
                pn = self.consecutive_completed_height + offset
                search_start = pn

                for part in self.parts[search_start:search_start +
                                       self.window]:
                    if part == None:
                        part_hash = self.hashmap[pn]
                        if part_hash != None:
                            requested_hashes += part_hash
                            self.outstanding_parts += 1
                            i += 1
                        else:
                            hashmap_exhausted = Resource.HASHMAP_IS_EXHAUSTED

                    pn += 1
                    if i >= self.window or hashmap_exhausted == Resource.HASHMAP_IS_EXHAUSTED:
                        break

                hmu_part = bytes([hashmap_exhausted])
                if hashmap_exhausted == Resource.HASHMAP_IS_EXHAUSTED:
                    last_map_hash = self.hashmap[self.hashmap_height - 1]
                    hmu_part += last_map_hash
                    self.waiting_for_hmu = True

                requested_data = b""
                request_data = hmu_part + self.hash + requested_hashes
                request_packet = RNS.Packet(self.link,
                                            request_data,
                                            context=RNS.Packet.RESOURCE_REQ)

                try:
                    request_packet.send()
                    self.last_activity = time.time()
                    self.req_sent = self.last_activity
                    self.req_resp = None
                except Exception as e:
                    RNS.log(
                        "Could not send resource request packet, cancelling resource",
                        RNS.LOG_DEBUG)
                    RNS.log("The contained exception was: " + str(e),
                            RNS.LOG_DEBUG)
                    self.cancel()
Ejemplo n.º 15
0
    def prove_packet(self, packet):
        signature = self.sign(packet.packet_hash)
        # TODO: Hardcoded as explicit proof for now
        # if RNS.Reticulum.should_use_implicit_proof():
        # 	proof_data = signature
        # else:
        # 	proof_data = packet.packet_hash + signature
        proof_data = packet.packet_hash + signature

        proof = RNS.Packet(self, proof_data, RNS.Packet.PROOF)
        proof.send()
Ejemplo n.º 16
0
 def cache_request_packet(packet):
     if len(packet.data) == RNS.Identity.HASHLENGTH / 8:
         packet_hash = RNS.hexrep(packet.data, delimit=False)
         # TODO: There's some pretty obvious file access
         # issues here. Make sure this can't happen
         path = RNS.Reticulum.cachepath + "/" + packet_hash
         if os.path.isfile(path):
             file = open(path, "r")
             raw = file.read()
             file.close()
             packet = RNS.Packet(None, raw)
Ejemplo n.º 17
0
def server_packet_received(message, packet):
    global latest_client_link

    # When data is received over any active link,
    # it will all be directed to the last client
    # that connected.
    text = message.decode("utf-8")
    RNS.log("Received data on the link: "+text)
    
    reply_text = "I received \""+text+"\" over the link"
    reply_data = reply_text.encode("utf-8")
    RNS.Packet(latest_client_link, reply_data).send()
Ejemplo n.º 18
0
	def prove(self, packet, destination=None):
		signature = self.sign(packet.packet_hash)
		if RNS.Reticulum.should_use_implicit_proof():
			proof_data = signature
		else:
			proof_data = packet.packet_hash + signature
		
		if destination == None:
			destination = packet.generateProofDestination()

		proof = RNS.Packet(destination, proof_data, RNS.Packet.PROOF)
		proof.send()
Ejemplo n.º 19
0
 def requestPath(destination_hash):
     path_request_data = destination_hash + RNS.Identity.getRandomHash()
     path_request_dst = RNS.Destination(None, RNS.Destination.OUT,
                                        RNS.Destination.PLAIN,
                                        Transport.APP_NAME, "path",
                                        "request")
     packet = RNS.Packet(path_request_dst,
                         path_request_data,
                         packet_type=RNS.Packet.DATA,
                         transport_type=RNS.Transport.BROADCAST,
                         header_type=RNS.Packet.HEADER_1)
     packet.send()
Ejemplo n.º 20
0
 def teardown(self):
     if self.status != Link.PENDING and self.status != Link.CLOSED:
         teardown_packet = RNS.Packet(self,
                                      self.link_id,
                                      context=RNS.Packet.LINKCLOSE)
         teardown_packet.send()
     self.status = Link.CLOSED
     if self.initiator:
         self.teardown_reason = Link.INITIATOR_CLOSED
     else:
         self.teardown_reason = Link.DESTINATION_CLOSED
     self.link_closed()
Ejemplo n.º 21
0
def download(filename):
	global server_link, menu_mode, current_filename
	current_filename = filename

	# We just create a packet containing the
	# requested filename, and send it down the
	# link.
	request_packet = RNS.Packet(server_link, filename)
	request_packet.send()
	
	print("")
	print("Requested \""+filename+"\" from server, waiting for download to begin...")
	menu_mode = "download_started"
Ejemplo n.º 22
0
	def cancel(self):
		if self.status < Resource.COMPLETE:
			self.status = Resource.FAILED
			if self.initiator:
				if self.link.status == RNS.Link.ACTIVE:
					cancel_packet = RNS.Packet(self.link, self.hash, context=RNS.Packet.RESOURCE_ICL)
					cancel_packet.send()
				self.link.cancel_outgoing_resource(self)
			else:
				self.link.cancel_incoming_resource(self)
			
			if self.callback != None:
				self.link.resource_concluded(self)
				self.callback(self)
Ejemplo n.º 23
0
	def __advertise_job(self):
		data = ResourceAdvertisement(self).pack()
		self.advertisement_packet = RNS.Packet(self.link, data, context=RNS.Packet.RESOURCE_ADV)
		while not self.link.ready_for_new_resource():
			self.status = Resource.QUEUED
			sleep(0.25)

		self.advertisement_packet.send()
		self.last_activity = time.time()
		self.adv_sent = self.last_activity
		self.rtt = None
		self.status = Resource.ADVERTISED
		self.link.register_outgoing_resource(self)

		self.watchdog_job()
Ejemplo n.º 24
0
 def cache_request(packet_hash):
     RNS.log("Cache request for " + RNS.prettyhexrep(packet_hash),
             RNS.LOG_EXTREME)
     path = RNS.Reticulum.cachepath + "/" + RNS.hexrep(packet_hash,
                                                       delimit=False)
     if os.path.isfile(path):
         file = open(path, "r")
         raw = file.read()
         Transport.inbound(raw)
         file.close()
     else:
         cache_request_packet = RNS.Packet(
             Transport.transport_destination(),
             packet_hash,
             context=RNS.Packet.CACHE_REQUEST)
Ejemplo n.º 25
0
    def prove(self, packet, destination=None):
        signature = self.sign(packet.packet_hash)
        if RNS.Reticulum.should_use_implicit_proof():
            proof_data = signature
        else:
            proof_data = packet.packet_hash + signature

        if destination == None:
            destination = packet.generate_proof_destination()

        proof = RNS.Packet(destination,
                           proof_data,
                           RNS.Packet.PROOF,
                           attached_interface=packet.receiving_interface)
        proof.send()
Ejemplo n.º 26
0
 def prove(self):
     if not self.status == Resource.FAILED:
         try:
             proof = RNS.Identity.fullHash(self.data + self.hash)
             proof_data = self.hash + proof
             proof_packet = RNS.Packet(self.link,
                                       proof_data,
                                       packet_type=RNS.Packet.PROOF,
                                       context=RNS.Packet.RESOURCE_PRF)
             proof_packet.send()
         except Exception as e:
             RNS.log("Could not send proof packet, cancelling resource",
                     RNS.LOG_DEBUG)
             RNS.log("The contained exception was: " + str(e),
                     RNS.LOG_DEBUG)
             self.cancel()
Ejemplo n.º 27
0
def broadcastLoop(destination):
    # Let the user know that everything is ready
    RNS.log("Broadcast example " + RNS.prettyhexrep(destination.hash) +
            " running, enter text and hit enter to broadcast (Ctrl-C to quit)")

    # We enter a loop that runs until the users exits.
    # If the user hits enter, we will send the information
    # that the user entered into the prompt.
    while True:
        print("> ", end="")
        entered = input()

        if entered != "":
            data = entered.encode("utf-8")
            packet = RNS.Packet(destination, data)
            packet.send()
Ejemplo n.º 28
0
 def teardown(self):
     """
     Closes the link and purges encryption keys. New keys will
     be used if a new link to the same destination is established.
     """
     if self.status != Link.PENDING and self.status != Link.CLOSED:
         teardown_packet = RNS.Packet(self,
                                      self.link_id,
                                      context=RNS.Packet.LINKCLOSE)
         teardown_packet.send()
         self.had_outbound()
     self.status = Link.CLOSED
     if self.initiator:
         self.teardown_reason = Link.INITIATOR_CLOSED
     else:
         self.teardown_reason = Link.DESTINATION_CLOSED
     self.link_closed()
Ejemplo n.º 29
0
def download(filename):
    global server_link, menu_mode, current_filename, transfer_size, download_started
    current_filename = filename
    download_started = 0
    transfer_size = 0

    # We just create a packet containing the
    # requested filename, and send it down the
    # link. We also specify we don't need a
    # packet receipt.
    request_packet = RNS.Packet(server_link,
                                filename.encode("utf-8"),
                                create_receipt=False)
    request_packet.send()

    print("")
    print(("Requested \"" + filename +
           "\" from server, waiting for download to begin..."))
    menu_mode = "download_started"
Ejemplo n.º 30
0
    def request_next(self):
        if not self.status == Resource.FAILED:
            if not self.waiting_for_hmu:
                self.outstanding_parts = 0
                hashmap_exhausted = Resource.HASHMAP_IS_NOT_EXHAUSTED
                requested_hashes = b""

                i = 0
                pn = 0
                for part in self.parts:

                    if part == None:
                        part_hash = self.hashmap[pn]
                        if part_hash != None:
                            requested_hashes += part_hash
                            self.outstanding_parts += 1
                            i += 1
                        else:
                            hashmap_exhausted = Resource.HASHMAP_IS_EXHAUSTED

                    pn += 1
                    if i >= self.window or hashmap_exhausted == Resource.HASHMAP_IS_EXHAUSTED:
                        break

                hmu_part = bytes([hashmap_exhausted])
                if hashmap_exhausted == Resource.HASHMAP_IS_EXHAUSTED:
                    last_map_hash = self.hashmap[self.hashmap_height - 1]
                    hmu_part += last_map_hash
                    self.waiting_for_hmu = True

                requested_data = b""
                request_data = hmu_part + self.hash + requested_hashes
                request_packet = RNS.Packet(self.link,
                                            request_data,
                                            context=RNS.Packet.RESOURCE_REQ)

                request_packet.send()
                self.last_activity = time.time()
                self.req_sent = self.last_activity
                self.req_resp = None