Skip to content

Commit 357531e

Browse files
feat: Add mesh networking functionality
This commit introduces mesh networking capabilities to Lanet, enabling decentralized communication between devices on a local network. Key features include: - **Node discovery:** Nodes automatically discover and connect to each other. - **Multi-hop routing:** Messages can be routed through intermediate nodes to reach their destination. - **Self-healing:** The network adapts to changing conditions and node failures. - **End-to-end encryption:** Messages remain encrypted throughout the routing process. - **Digital signatures:** Message integrity is ensured through digital signatures. This functionality is accessible through both the command-line interface and the Ruby API. This enhancement is ideal for scenarios where: - Devices may not have direct connectivity. - No central server or infrastructure is available. - High resilience and redundancy are required. - Peer-to-peer communication is desired. The mesh networking feature significantly expands Lanet's capabilities, making it a more versatile and robust tool for local network communication.
1 parent 80ef407 commit 357531e

File tree

12 files changed

+1349
-32
lines changed

12 files changed

+1349
-32
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.4.0] - 2023-11-15
9+
10+
### Added
11+
- Mesh networking functionality for decentralized communication
12+
- Auto-discovery of mesh nodes
13+
- Message routing through intermediate nodes
14+
- CLI commands for mesh network operations: `mesh start`, `mesh send`, `mesh info`
15+
- Ruby API methods for creating and managing mesh networks
16+
817
## [0.3.0] - 2025-03-08
918

1019
### Added

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: .
33
specs:
4-
lanet (0.3.0)
4+
lanet (0.4.0)
55
thor (~> 1.2)
66

77
GEM

README.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ A lightweight, powerful LAN communication tool that enables secure message excha
1919
- **Configurable:** Adjust port settings, encryption keys, and network scan ranges.
2020
- **Digital Signatures**: Ensure message authenticity and integrity
2121
- **File Transfers**: Securely send encrypted files over the LAN with progress tracking and integrity verification
22+
- **Mesh Networking**: Create resilient mesh networks for decentralized communication, enabling messages to be routed through multiple hops without central infrastructure
2223

2324
## Security Features
2425

@@ -301,6 +302,38 @@ Receive encrypted files with signature verification:
301302
lanet receive-file --output ./downloads --encryption-key "my_secret_key" --public-key-file lanet_public.key
302303
```
303304

305+
#### Mesh Networking
306+
307+
Create a decentralized mesh network where devices can communicate even without direct connectivity:
308+
309+
```bash
310+
# Start a mesh network node
311+
lanet mesh start
312+
313+
# Start a mesh network node with custom settings
314+
lanet mesh start --port 5050 --max-hops 15
315+
```
316+
317+
Send messages through the mesh network:
318+
319+
```bash
320+
# Send a message through the mesh network to a specific node ID
321+
lanet mesh send --target a1b2c3d4-5678-90ef-ghij --message "Hello Mesh Network"
322+
323+
# Send an encrypted message through the mesh network
324+
lanet mesh send --target a1b2c3d4-5678-90ef-ghij --message "Secret mesh message" --key "secret-key"
325+
326+
# Send a signed message through the mesh network
327+
lanet mesh send --target a1b2c3d4-5678-90ef-ghij --message "Authenticated mesh message" --private-key-file lanet_private.key
328+
```
329+
330+
View information about your mesh network:
331+
332+
```bash
333+
# Display information about mesh network connections
334+
lanet mesh info
335+
```
336+
304337
### Ruby API
305338

306339
You can also use Lanet programmatically in your Ruby applications:
@@ -393,8 +426,42 @@ file_transfer.receive_file('./downloads', 'encryption_key') do |event, data|
393426
puts "File saved to: #{data[:file_path]}"
394427
end
395428
end
429+
430+
# Mesh Networking
431+
mesh = Lanet.mesh_network
432+
mesh.start # Start the mesh node and discovery service
433+
434+
# Send a message through the mesh network
435+
mesh.send_message(target_node_id, "Hello through the mesh!", "optional-encryption-key")
436+
437+
# Get info about mesh connections
438+
puts "Node ID: #{mesh.node_id}"
439+
puts "Connected to #{mesh.connections.size} nodes"
440+
mesh.connections.each do |node_id, info|
441+
puts " #{node_id} (#{info[:ip]})"
442+
end
443+
444+
# Properly stop the mesh node
445+
mesh.stop
396446
```
397447

448+
## Mesh Network
449+
450+
The mesh networking feature provides decentralized communication capabilities:
451+
452+
- **Auto-discovery**: Nodes automatically find each other on the network
453+
- **Multi-hop routing**: Messages can be routed through intermediate nodes
454+
- **Self-healing**: Adapts to changing network conditions and lost connections
455+
- **Store and forward**: Messages persist until they can be delivered
456+
- **End-to-end security**: Messages remain encrypted across multiple hops
457+
- **Verification**: Digital signatures ensure message integrity through the mesh
458+
459+
Ideal for:
460+
- IoT networks where devices may not have direct connectivity
461+
- Ad-hoc networks without fixed infrastructure
462+
- Networks requiring high resilience and redundancy
463+
- Applications needing peer-to-peer communication
464+
398465
## Configuration
399466

400467
Lanet can be configured with several options:

index.html

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,22 @@ <h3>File Transfer <span class="badge badge-new">New in v0.3.0</span></h3>
227227
<p>Securely transfer files between devices with encryption, digital signatures, and integrity verification.</p>
228228
</div>
229229

230+
<div class="feature">
231+
<h3>Mesh Networking <span class="badge badge-new">New in v0.4.0</span></h3>
232+
<p>Create resilient, decentralized mesh networks that enable communication between devices even without direct connectivity.</p>
233+
234+
<div class="security-feature">
235+
<h4>Benefits of Mesh Networking:</h4>
236+
<ul>
237+
<li><strong>Decentralization</strong>: No central server or infrastructure needed</li>
238+
<li><strong>Resilience</strong>: Messages can route around failed nodes or connections</li>
239+
<li><strong>Extended Range</strong>: Devices can communicate beyond direct connection range</li>
240+
<li><strong>Scalability</strong>: Network grows stronger with more participating nodes</li>
241+
<li><strong>Self-healing</strong>: Network automatically adapts to changing conditions</li>
242+
</ul>
243+
</div>
244+
</div>
245+
230246
<h2>Command Line Interface</h2>
231247

232248
<div class="note">
@@ -381,6 +397,46 @@ <h4>Receive Files</h4>
381397
</div>
382398
</div>
383399

400+
<div class="cli-section">
401+
<h3>Mesh Network Commands <span class="badge badge-new">New in v0.4.0</span></h3>
402+
403+
<h4>Start a Mesh Network Node</h4>
404+
<div class="cli-example">
405+
lanet mesh start
406+
</div>
407+
408+
<h4>Start with Custom Settings</h4>
409+
<div class="cli-example">
410+
lanet mesh start --port 5050 --max-hops 15
411+
</div>
412+
413+
<h4>Send a Message Through the Mesh</h4>
414+
<div class="cli-example">
415+
lanet mesh send --target a1b2c3d4-5678-90ef-ghij --message "Hello Mesh"
416+
</div>
417+
418+
<h4>Send an Encrypted Mesh Message</h4>
419+
<div class="cli-example">
420+
lanet mesh send --target a1b2c3d4-5678-90ef-ghij --message "Secret mesh message" --key "secret-key"
421+
</div>
422+
423+
<h4>View Mesh Network Information</h4>
424+
<div class="cli-example">
425+
lanet mesh info
426+
</div>
427+
428+
<p>Example output when viewing mesh info:</p>
429+
<div class="output-example">
430+
Mesh Node ID: 4f9a8b7c-6d5e-4f3e-2d1c-0b9a8b7c6d5e
431+
432+
Connected nodes:
433+
b1c2d3e4-f5g6-7h8i-9j0k-l1m2n3o4p5q6 (192.168.1.5, last seen 12s ago)
434+
c5d4e3f2-g1h0-i9j8-k7l6-m5n4o3p2q1r0 (192.168.1.10, last seen 5s ago)
435+
436+
Message cache: 24 messages
437+
</div>
438+
</div>
439+
384440
<h2>Ruby Code Examples</h2>
385441

386442
<div class="tab-container">
@@ -389,6 +445,7 @@ <h2>Ruby Code Examples</h2>
389445
<button class="tab-button" onclick="openTab(event, 'tab-signatures')">Digital Signatures</button>
390446
<button class="tab-button" onclick="openTab(event, 'tab-advanced')">Advanced Usage</button>
391447
<button class="tab-button" onclick="openTab(event, 'tab-filetransfer')">File Transfer</button>
448+
<button class="tab-button" onclick="openTab(event, 'tab-mesh')">Mesh Network</button>
392449
</div>
393450

394451
<div id="tab-basic" class="tab-content active">
@@ -522,6 +579,53 @@ <h2>Ruby Code Examples</h2>
522579
end
523580
end</code></pre>
524581
</div>
582+
583+
<div id="tab-mesh" class="tab-content">
584+
<pre><code>require 'lanet'
585+
586+
# Create and start a mesh network node
587+
mesh = Lanet.mesh_network
588+
mesh.start
589+
590+
puts "Mesh node started with ID: #{mesh.node_id}"
591+
592+
# Send a plain message through the mesh
593+
begin
594+
message_id = mesh.send_message(
595+
"target-node-id-here",
596+
"Hello through the mesh network!"
597+
)
598+
puts "Message sent with ID: #{message_id}"
599+
rescue Lanet::Mesh::Error => e
600+
puts "Message sending failed: #{e.message}"
601+
end
602+
603+
# Send an encrypted and signed message
604+
encryption_key = "mesh-encryption-key"
605+
key_pair = Lanet::Signer.generate_key_pair
606+
private_key = key_pair[:private_key]
607+
608+
begin
609+
message_id = mesh.send_message(
610+
"target-node-id-here",
611+
"Secure mesh message",
612+
encryption_key,
613+
private_key
614+
)
615+
puts "Secure message sent with ID: #{message_id}"
616+
rescue Lanet::Mesh::Error => e
617+
puts "Secure message sending failed: #{e.message}"
618+
end
619+
620+
# Examine mesh connections
621+
puts "Connected to #{mesh.connections.size} nodes:"
622+
mesh.connections.each do |node_id, info|
623+
puts " • #{node_id} (#{info[:ip]}, last seen #{Time.now.to_i - info[:last_seen]}s ago)"
624+
end
625+
626+
# Always stop the mesh node when done
627+
mesh.stop</code></pre>
628+
</div>
525629
</div>
526630

527631
<h2>Installation</h2>
@@ -536,7 +640,7 @@ <h2>Documentation</h2>
536640
<p>For complete documentation, please visit the <a href="https://github.com/davidesantangelo/lanet">GitHub repository</a>.</p>
537641

538642
<footer style="margin-top: 40px; text-align: center; color: #7f8c8d;">
539-
<p>Lanet v0.3.0 - Secure Network Communications Library</p>
643+
<p>Lanet v0.4.0 - Secure Network Communications Library</p>
540644
</footer>
541645
</div>
542646

lib/lanet.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
require "lanet/cli"
99
require "lanet/ping"
1010
require "lanet/file_transfer"
11+
require "lanet/mesh"
1112

1213
module Lanet
1314
class Error < StandardError; end
@@ -50,5 +51,10 @@ def pinger(timeout: 1, count: 3)
5051
def file_transfer(port = 5001)
5152
FileTransfer.new(port)
5253
end
54+
55+
# Create a new mesh network instance
56+
def mesh_network(port = 5050, max_hops = 10)
57+
Mesh.new(port, max_hops)
58+
end
5359
end
5460
end

lib/lanet/cli.rb

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,94 @@ def version
278278
puts "Lanet version #{Lanet::VERSION}"
279279
end
280280

281+
desc "mesh start", "Start a mesh network node"
282+
option :port, type: :numeric, default: 5050, desc: "Port for mesh communication"
283+
option :max_hops, type: :numeric, default: 10, desc: "Maximum number of hops for message routing"
284+
def mesh_start
285+
mesh = Lanet::Mesh.new(options[:port], options[:max_hops])
286+
287+
puts "Starting mesh network node with ID: #{mesh.node_id}"
288+
puts "Listening on port: #{options[:port]}"
289+
puts "Press Ctrl+C to stop"
290+
291+
mesh.start
292+
293+
# Keep the process running
294+
begin
295+
loop do
296+
sleep 1
297+
end
298+
rescue Interrupt
299+
puts "\nStopping mesh network node..."
300+
mesh.stop
301+
end
302+
end
303+
304+
desc "mesh send", "Send a message through the mesh network"
305+
option :target, type: :string, required: true, desc: "Target node ID"
306+
option :message, type: :string, required: true, desc: "Message to send"
307+
option :key, type: :string, desc: "Encryption key (optional)"
308+
option :private_key_file, type: :string, desc: "Path to private key file for signing (optional)"
309+
option :port, type: :numeric, default: 5050, desc: "Port for mesh communication"
310+
def mesh_send
311+
mesh = Lanet::Mesh.new(options[:port])
312+
313+
private_key = nil
314+
if options[:private_key_file]
315+
begin
316+
private_key = File.read(options[:private_key_file])
317+
puts "Message will be digitally signed"
318+
rescue StandardError => e
319+
puts "Error reading private key file: #{e.message}"
320+
return
321+
end
322+
end
323+
324+
# Initialize the mesh network
325+
mesh.start
326+
327+
begin
328+
message_id = mesh.send_message(
329+
options[:target],
330+
options[:message],
331+
options[:key],
332+
private_key
333+
)
334+
335+
puts "Message sent through mesh network"
336+
puts "Message ID: #{message_id}"
337+
rescue Lanet::Mesh::Error => e
338+
puts "Error sending mesh message: #{e.message}"
339+
ensure
340+
mesh.stop
341+
end
342+
end
343+
344+
desc "mesh info", "Display information about the mesh network"
345+
option :port, type: :numeric, default: 5050, desc: "Port for mesh communication"
346+
def mesh_info
347+
mesh = Lanet::Mesh.new(options[:port])
348+
349+
# Load state if available
350+
mesh.start
351+
352+
puts "Mesh Node ID: #{mesh.node_id}"
353+
puts "\nConnected nodes:"
354+
355+
if mesh.connections.empty?
356+
puts " No direct connections"
357+
else
358+
mesh.connections.each do |node_id, info|
359+
last_seen = Time.now.to_i - info[:last_seen]
360+
puts " #{node_id} (#{info[:ip]}, last seen #{last_seen}s ago)"
361+
end
362+
end
363+
364+
puts "\nMessage cache: #{mesh.message_cache.size} messages"
365+
366+
mesh.stop
367+
end
368+
281369
private
282370

283371
def display_ping_details(host, result)

lib/lanet/file_transfer.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,10 @@ def send_file(target_ip, file_path, encryption_key = nil, private_key = nil, pro
122122
end
123123

124124
### Receive File Method
125-
def receive_file(output_dir, encryption_key = nil, public_key = nil, progress_callback = nil)
125+
def receive_file(output_dir, encryption_key = nil, public_key = nil, progress_callback = nil, &block)
126+
# Use the block parameter if provided and progress_callback is nil
127+
progress_callback = block if block_given? && progress_callback.nil?
128+
126129
FileUtils.mkdir_p(output_dir) unless Dir.exist?(output_dir)
127130
receiver = UDPSocket.new
128131
receiver.bind("0.0.0.0", @port)
@@ -131,6 +134,10 @@ def receive_file(output_dir, encryption_key = nil, public_key = nil, progress_ca
131134
begin
132135
loop do
133136
data, addr = receiver.recvfrom(65_536) # Large buffer for chunks
137+
138+
# Skip if we received nil data or address
139+
next if addr.nil? || data.nil?
140+
134141
sender_ip = addr[3]
135142
result = Lanet::Encryptor.process_message(data, encryption_key, public_key)
136143
next unless result[:content]&.length&.> 2

0 commit comments

Comments
 (0)