lanet 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +8 -0
- data/CHANGELOG.md +25 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +67 -0
- data/LICENSE.txt +21 -0
- data/README.md +437 -0
- data/Rakefile +12 -0
- data/bin/console +11 -0
- data/bin/lanet +7 -0
- data/bin/setup +8 -0
- data/exe/lanet +8 -0
- data/index.html +233 -0
- data/lib/lanet/cli.rb +229 -0
- data/lib/lanet/encryptor.rb +84 -0
- data/lib/lanet/ping.rb +297 -0
- data/lib/lanet/receiver.rb +21 -0
- data/lib/lanet/scanner.rb +293 -0
- data/lib/lanet/sender.rb +21 -0
- data/lib/lanet/version.rb +5 -0
- data/lib/lanet.rb +45 -0
- data/sig/lanet.rbs +4 -0
- metadata +128 -0
data/README.md
ADDED
@@ -0,0 +1,437 @@
|
|
1
|
+
# Lanet
|
2
|
+
|
3
|
+
[](https://badge.fury.io/rb/lanet)
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
5
|
+
|
6
|
+
A lightweight, powerful LAN communication tool for Ruby that enables secure message exchange between devices on the same network. Lanet makes peer-to-peer networking simple with built-in encryption, network discovery, and both targeted and broadcast messaging capabilities.
|
7
|
+
|
8
|
+
## Features
|
9
|
+
|
10
|
+
- š **Simple API** - An intuitive Ruby interface makes network communication straightforward.
|
11
|
+
- š **Built-in encryption** - Optional message encryption with AES-256-GCM for confidentiality.
|
12
|
+
- š **Network scanning** - Automatically discover active devices on your local network.
|
13
|
+
- š” **Targeted messaging** - Send messages to specific IP addresses.
|
14
|
+
- š£ **Broadcasting** - Send messages to all devices on the network.
|
15
|
+
- š **Host pinging** - Check host availability and measure response times (with a familiar `ping` interface).
|
16
|
+
- š„ļø **Command-line interface** - Perform common network operations directly from your terminal.
|
17
|
+
- š§© **Extensible** - Easily build custom tools and integrations using the Lanet API.
|
18
|
+
- āļø **Configurable:** Adjust port settings, encryption keys, and network scan ranges.
|
19
|
+
|
20
|
+
|
21
|
+
## Installation
|
22
|
+
|
23
|
+
Add this line to your application's Gemfile:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
gem 'lanet'
|
27
|
+
```
|
28
|
+
|
29
|
+
And then execute:
|
30
|
+
|
31
|
+
```bash
|
32
|
+
bundle install
|
33
|
+
```
|
34
|
+
|
35
|
+
Or install it yourself as:
|
36
|
+
|
37
|
+
```bash
|
38
|
+
gem install lanet
|
39
|
+
```
|
40
|
+
|
41
|
+
## Usage
|
42
|
+
|
43
|
+
### Command Line Interface
|
44
|
+
|
45
|
+
Lanet provides a powerful CLI for common network operations:
|
46
|
+
|
47
|
+
#### Scanning the network
|
48
|
+
|
49
|
+
```bash
|
50
|
+
lanet scan --range 192.168.1.0/24
|
51
|
+
```
|
52
|
+
|
53
|
+
With verbose output (shows detailed host information):
|
54
|
+
```bash
|
55
|
+
lanet scan --range 192.168.1.0/24 --verbose
|
56
|
+
```
|
57
|
+
|
58
|
+
Control scan performance with threads:
|
59
|
+
```bash
|
60
|
+
lanet scan --range 192.168.1.0/24 --threads 16 --timeout 2
|
61
|
+
```
|
62
|
+
|
63
|
+
The scanner employs multiple detection methods to find active hosts:
|
64
|
+
- TCP port connection attempts
|
65
|
+
- ICMP ping requests
|
66
|
+
- UDP packet probing
|
67
|
+
- ARP table lookups
|
68
|
+
|
69
|
+
Verbose scanning provides rich device information:
|
70
|
+
```
|
71
|
+
IP: 192.168.1.1
|
72
|
+
Hostname: router.home
|
73
|
+
MAC: a4:2b:b0:8a:5c:de
|
74
|
+
Response time: 5.23ms
|
75
|
+
Detection method: TCP
|
76
|
+
Open ports:
|
77
|
+
- 80: HTTP
|
78
|
+
- 443: HTTPS
|
79
|
+
- 22: SSH
|
80
|
+
```
|
81
|
+
|
82
|
+
Scanning shows real-time progress for tracking large network scans:
|
83
|
+
```
|
84
|
+
Scanning network: 67.5% complete (162/240)
|
85
|
+
```
|
86
|
+
|
87
|
+
#### Sending a message to a specific target
|
88
|
+
|
89
|
+
```bash
|
90
|
+
lanet send --target 192.168.1.5 --message "Hello there!"
|
91
|
+
```
|
92
|
+
|
93
|
+
#### Sending an encrypted message
|
94
|
+
|
95
|
+
```bash
|
96
|
+
lanet send --target 192.168.1.5 --message "Secret message" --key "my_secret_key"
|
97
|
+
```
|
98
|
+
|
99
|
+
#### Broadcasting a message to all devices
|
100
|
+
|
101
|
+
```bash
|
102
|
+
lanet broadcast --message "Announcement for everyone!"
|
103
|
+
```
|
104
|
+
|
105
|
+
#### Listening for incoming messages
|
106
|
+
|
107
|
+
```bash
|
108
|
+
lanet listen
|
109
|
+
```
|
110
|
+
|
111
|
+
#### Listening for encrypted messages
|
112
|
+
|
113
|
+
```bash
|
114
|
+
lanet listen --key "my_secret_key"
|
115
|
+
```
|
116
|
+
|
117
|
+
#### Pinging a specific host
|
118
|
+
|
119
|
+
You can ping a host using either of these formats:
|
120
|
+
|
121
|
+
```bash
|
122
|
+
# Simple format
|
123
|
+
lanet ping 192.168.1.5
|
124
|
+
|
125
|
+
# Option format
|
126
|
+
lanet ping --host 192.168.1.5
|
127
|
+
```
|
128
|
+
|
129
|
+
The ping command displays real-time responses just like the standard ping utility:
|
130
|
+
|
131
|
+
```
|
132
|
+
PING 192.168.1.5 (192.168.1.5): 56 data bytes
|
133
|
+
64 bytes from 192.168.1.5: icmp_seq=0 ttl=64 time=2.929 ms
|
134
|
+
64 bytes from 192.168.1.5: icmp_seq=1 ttl=64 time=2.845 ms
|
135
|
+
64 bytes from 192.168.1.5: icmp_seq=2 ttl=64 time=3.069 ms
|
136
|
+
64 bytes from 192.168.1.5: icmp_seq=3 ttl=64 time=3.090 ms
|
137
|
+
64 bytes from 192.168.1.5: icmp_seq=4 ttl=64 time=3.228 ms
|
138
|
+
|
139
|
+
--- 192.168.1.5 ping statistics ---
|
140
|
+
5 packets transmitted, 5 packets received, 0.0% packet loss
|
141
|
+
round-trip min/avg/max/stddev = 2.845/3.032/3.228/0.134 ms
|
142
|
+
```
|
143
|
+
|
144
|
+
#### Pinging multiple hosts
|
145
|
+
|
146
|
+
```bash
|
147
|
+
# Option format with multiple hosts
|
148
|
+
lanet ping --hosts 192.168.1.5,192.168.1.6,192.168.1.7 --timeout 2 --count 5
|
149
|
+
```
|
150
|
+
|
151
|
+
For only showing ping summaries:
|
152
|
+
|
153
|
+
```bash
|
154
|
+
# Simple format with quiet option
|
155
|
+
lanet ping 192.168.1.5 --quiet
|
156
|
+
|
157
|
+
# Option format with quiet option
|
158
|
+
lanet ping --host 192.168.1.5 --quiet
|
159
|
+
```
|
160
|
+
|
161
|
+
#### Continuous ping (like traditional ping)
|
162
|
+
|
163
|
+
Ping continuously until manually interrupted (Ctrl+C):
|
164
|
+
|
165
|
+
```bash
|
166
|
+
# Simple format with continuous option
|
167
|
+
lanet ping 192.168.1.5 --continuous
|
168
|
+
|
169
|
+
# Option format with continuous option
|
170
|
+
lanet ping --host 192.168.1.5 --continuous
|
171
|
+
```
|
172
|
+
|
173
|
+
Ping continuously with custom timeout:
|
174
|
+
|
175
|
+
```bash
|
176
|
+
lanet ping 192.168.1.5 --continuous --timeout 2
|
177
|
+
```
|
178
|
+
|
179
|
+
Ping multiple hosts continuously:
|
180
|
+
|
181
|
+
```bash
|
182
|
+
lanet ping --hosts 192.168.1.5,192.168.1.6 --continuous
|
183
|
+
```
|
184
|
+
|
185
|
+
### Ruby API
|
186
|
+
|
187
|
+
You can also use Lanet programmatically in your Ruby applications:
|
188
|
+
|
189
|
+
```ruby
|
190
|
+
require 'lanet'
|
191
|
+
|
192
|
+
# Create a scanner and find active devices
|
193
|
+
scanner = Lanet.scanner
|
194
|
+
active_ips = scanner.scan('192.168.1.0/24')
|
195
|
+
puts "Found devices: #{active_ips.join(', ')}"
|
196
|
+
|
197
|
+
# Scan with verbose option for detailed output
|
198
|
+
detailed_hosts = scanner.scan('192.168.1.0/24', 1, 32, true)
|
199
|
+
detailed_hosts.each do |host|
|
200
|
+
puts "Host: #{host[:ip]}, Hostname: #{host[:hostname]}, Response Time: #{host[:response_time]}ms"
|
201
|
+
puts "Open ports: #{host[:ports].map { |port, service| "#{port} (#{service})" }.join(', ')}" if host[:ports]
|
202
|
+
end
|
203
|
+
|
204
|
+
# Customize scanning performance with timeout and thread count
|
205
|
+
active_ips = scanner.scan('192.168.1.0/24', 0.5, 16) # 0.5 second timeout, 16 threads
|
206
|
+
|
207
|
+
# Send a message to a specific IP
|
208
|
+
sender = Lanet.sender
|
209
|
+
sender.send_to('192.168.1.5', 'Hello from Ruby!')
|
210
|
+
|
211
|
+
# Broadcast a message to all devices
|
212
|
+
sender.broadcast('Announcement to all devices!')
|
213
|
+
|
214
|
+
# Listen for incoming messages
|
215
|
+
receiver = Lanet.receiver
|
216
|
+
receiver.listen do |data, ip|
|
217
|
+
puts "Received from #{ip}: #{data}"
|
218
|
+
end
|
219
|
+
|
220
|
+
# Work with encrypted messages
|
221
|
+
encrypted = Lanet.encrypt('Secret message', 'my_encryption_key')
|
222
|
+
decrypted = Lanet.decrypt(encrypted, 'my_encryption_key')
|
223
|
+
|
224
|
+
# Ping a specific host
|
225
|
+
pinger = Lanet.pinger
|
226
|
+
result = pinger.ping_host('192.168.1.5')
|
227
|
+
puts "Host reachable: #{result[:status]}"
|
228
|
+
puts "Response time: #{result[:response_time]}ms"
|
229
|
+
|
230
|
+
# Ping a specific host with real-time output
|
231
|
+
pinger = Lanet.pinger(timeout: 2, count: 5)
|
232
|
+
result = pinger.ping_host('192.168.1.5', true) # true enables real-time output
|
233
|
+
|
234
|
+
# Ping continuously until interrupted
|
235
|
+
pinger = Lanet.pinger
|
236
|
+
pinger.ping_host('192.168.1.5', true, true) # true, true enables real-time continuous output
|
237
|
+
|
238
|
+
# Ping without real-time output (for programmatic use)
|
239
|
+
result = pinger.ping_host('192.168.1.5')
|
240
|
+
puts "Host reachable: #{result[:status]}"
|
241
|
+
puts "Response time: #{result[:response_time]}ms"
|
242
|
+
|
243
|
+
# Check if a host is reachable
|
244
|
+
if pinger.reachable?('192.168.1.5')
|
245
|
+
puts "Host is up!"
|
246
|
+
else
|
247
|
+
puts "Host is down!"
|
248
|
+
end
|
249
|
+
|
250
|
+
# Ping multiple hosts
|
251
|
+
results = pinger.ping_hosts(['192.168.1.5', '192.168.1.6', '192.168.1.7'])
|
252
|
+
results.each do |host, result|
|
253
|
+
status = result[:status] ? "up" : "down"
|
254
|
+
puts "#{host} is #{status}. Response time: #{result[:response_time] || 'N/A'}"
|
255
|
+
end
|
256
|
+
|
257
|
+
# Ping multiple hosts continuously
|
258
|
+
pinger.ping_hosts(['192.168.1.5', '192.168.1.6'], true, true)
|
259
|
+
```
|
260
|
+
|
261
|
+
## Configuration
|
262
|
+
|
263
|
+
Lanet can be configured with several options:
|
264
|
+
|
265
|
+
- **Port**: Default is 5000, but can be changed for both sending and receiving
|
266
|
+
- **Encryption Keys**: Use your own encryption keys for secure communication
|
267
|
+
- **Custom Ranges**: Scan specific network ranges to discover devices
|
268
|
+
|
269
|
+
## Use Case Example: Small Office Network Monitoring
|
270
|
+
|
271
|
+
This example demonstrates how Lanet can be used to create a simple network monitoring system for a small office, checking device availability and sending notifications when issues are detected.
|
272
|
+
|
273
|
+
```ruby
|
274
|
+
require 'lanet'
|
275
|
+
require 'json'
|
276
|
+
require 'terminal-notifier' if Gem::Platform.local.os == 'darwin'
|
277
|
+
|
278
|
+
class NetworkMonitor
|
279
|
+
def initialize(config_file = 'network_config.json')
|
280
|
+
@config = JSON.parse(File.read(config_file))
|
281
|
+
@scanner = Lanet.scanner
|
282
|
+
@sender = Lanet.sender
|
283
|
+
@pinger = Lanet.pinger(timeout: 1, count: 3)
|
284
|
+
@last_status = {}
|
285
|
+
|
286
|
+
puts "Network Monitor initialized for #{@config['network_name']}"
|
287
|
+
puts "Monitoring #{@config['devices'].size} devices on #{@config['network_range']}"
|
288
|
+
end
|
289
|
+
|
290
|
+
def scan_network
|
291
|
+
puts "\n=== Full Network Scan: #{Time.now.strftime('%Y-%m-%d %H:%M:%S')} ==="
|
292
|
+
results = @scanner.scan(@config['network_range'], 1, 32, true)
|
293
|
+
|
294
|
+
# Find unexpected devices
|
295
|
+
known_ips = @config['devices'].map { |d| d['ip'] }
|
296
|
+
unknown_devices = results.reject { |host| known_ips.include?(host[:ip]) }
|
297
|
+
|
298
|
+
if unknown_devices.any?
|
299
|
+
puts "\nā ļø Unknown devices detected on network:"
|
300
|
+
unknown_devices.each do |device|
|
301
|
+
puts " - IP: #{device[:ip]}, Hostname: #{device[:hostname] || 'unknown'}"
|
302
|
+
end
|
303
|
+
|
304
|
+
# Alert admin about unknown devices
|
305
|
+
message = "#{unknown_devices.size} unknown devices found on network!"
|
306
|
+
notify_admin(message)
|
307
|
+
end
|
308
|
+
|
309
|
+
results
|
310
|
+
end
|
311
|
+
|
312
|
+
def monitor_critical_devices
|
313
|
+
puts "\n=== Checking Critical Devices: #{Time.now.strftime('%H:%M:%S')} ==="
|
314
|
+
|
315
|
+
@config['devices'].select { |d| d['critical'] == true }.each do |device|
|
316
|
+
result = @pinger.ping_host(device['ip'])
|
317
|
+
current_status = result[:status]
|
318
|
+
|
319
|
+
if @last_status[device['ip']] != current_status
|
320
|
+
status_changed(device, current_status)
|
321
|
+
end
|
322
|
+
|
323
|
+
@last_status[device['ip']] = current_status
|
324
|
+
|
325
|
+
status_text = current_status ? "ā
ONLINE" : "ā OFFLINE"
|
326
|
+
puts "#{device['name']} (#{device['ip']}): #{status_text}"
|
327
|
+
puts " Response time: #{result[:response_time]}ms" if current_status
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
def status_changed(device, new_status)
|
332
|
+
message = if new_status
|
333
|
+
"š¢ #{device['name']} is back ONLINE"
|
334
|
+
else
|
335
|
+
"š“ ALERT: #{device['name']} (#{device['ip']}) is DOWN!"
|
336
|
+
end
|
337
|
+
|
338
|
+
puts "\n#{message}\n"
|
339
|
+
notify_admin(message)
|
340
|
+
|
341
|
+
# Send notification to all network admin devices
|
342
|
+
@config['admin_devices'].each do |admin_device|
|
343
|
+
@sender.send_to(admin_device['ip'], message)
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
def notify_admin(message)
|
348
|
+
# Send desktop notification on macOS
|
349
|
+
if Gem::Platform.local.os == 'darwin'
|
350
|
+
TerminalNotifier.notify(message, title: 'Network Monitor Alert')
|
351
|
+
end
|
352
|
+
|
353
|
+
# You could also add SMS, email, or other notification methods here
|
354
|
+
end
|
355
|
+
|
356
|
+
def run_continuous_monitoring
|
357
|
+
# Initial full network scan
|
358
|
+
scan_network
|
359
|
+
|
360
|
+
puts "\nStarting continuous monitoring (press Ctrl+C to stop)..."
|
361
|
+
|
362
|
+
# Set up a listener for incoming alerts
|
363
|
+
receiver_thread = Thread.new do
|
364
|
+
receiver = Lanet.receiver
|
365
|
+
receiver.listen do |message, source_ip|
|
366
|
+
puts "\nšØ Message from #{source_ip}: #{message}"
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
# Main monitoring loop
|
371
|
+
loop do
|
372
|
+
monitor_critical_devices
|
373
|
+
|
374
|
+
# Full network scan every hour
|
375
|
+
scan_network if Time.now.min == 0
|
376
|
+
|
377
|
+
sleep @config['check_interval']
|
378
|
+
end
|
379
|
+
rescue Interrupt
|
380
|
+
puts "\nMonitoring stopped."
|
381
|
+
ensure
|
382
|
+
receiver_thread.kill if defined?(receiver_thread) && receiver_thread
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
# Example configuration file (network_config.json):
|
387
|
+
# {
|
388
|
+
# "network_name": "Office Network",
|
389
|
+
# "network_range": "192.168.1.0/24",
|
390
|
+
# "check_interval": 300,
|
391
|
+
# "devices": [
|
392
|
+
# {"name": "Router", "ip": "192.168.1.1", "critical": true},
|
393
|
+
# {"name": "File Server", "ip": "192.168.1.10", "critical": true},
|
394
|
+
# {"name": "Printer", "ip": "192.168.1.20", "critical": false}
|
395
|
+
# ],
|
396
|
+
# "admin_devices": [
|
397
|
+
# {"name": "IT Manager Laptop", "ip": "192.168.1.100"}
|
398
|
+
# ]
|
399
|
+
# }
|
400
|
+
|
401
|
+
# Usage:
|
402
|
+
# monitor = NetworkMonitor.new('network_config.json')
|
403
|
+
# monitor.run_continuous_monitoring
|
404
|
+
```
|
405
|
+
|
406
|
+
This system:
|
407
|
+
- Scans the network to find all connected devices
|
408
|
+
- Detects unknown devices and sends alerts
|
409
|
+
- Continuously monitors critical devices like servers and network equipment
|
410
|
+
- Alerts administrators when a device's status changes
|
411
|
+
- Can be extended with additional notification methods
|
412
|
+
|
413
|
+
You can set this up as a scheduled task or service to run continuously on a dedicated machine.
|
414
|
+
|
415
|
+
## Development
|
416
|
+
|
417
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
418
|
+
|
419
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
420
|
+
|
421
|
+
## Contributing
|
422
|
+
|
423
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/davidesantangelo/lanet. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/davidesantangelo/lanet/blob/master/CODE_OF_CONDUCT.md).
|
424
|
+
|
425
|
+
1. Fork it
|
426
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
427
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
428
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
429
|
+
5. Create new Pull Request
|
430
|
+
|
431
|
+
## License
|
432
|
+
|
433
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
434
|
+
|
435
|
+
## Code of Conduct
|
436
|
+
|
437
|
+
Everyone interacting in the Lanet project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/davidesantangelo/lanet/blob/master/CODE_OF_CONDUCT.md).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "lanet"
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
require "irb"
|
11
|
+
IRB.start(__FILE__)
|
data/bin/lanet
ADDED
data/bin/setup
ADDED