ruby-netmon-qt 1.0.0 → 1.0.2
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 +4 -4
- data/lib/netmon-qt/app/components/connstableview/sortfilterproxymodel.rb +23 -4
- data/lib/netmon-qt/app/components/connstableview/store.rb +8 -4
- data/lib/netmon-qt/app/components/connstableview.rb +18 -26
- data/lib/netmon-qt/app/services/conns_lookup_service.rb +4 -6
- data/lib/netmon-qt/config/settings.rb +11 -4
- data/lib/netmon-qt/lib/netmon/connection.rb +11 -0
- data/lib/netmon-qt/lib/netmon/localaddresschecker.rb +19 -0
- data/lib/netmon-qt/lib/netmon.rb +1 -1
- data/lib/netmon-qt/version.rb +1 -1
- data/lib/netmon-qt.rb +1 -0
- metadata +2 -2
- data/lib/netmon-qt/lib/netmon/localaddresscheck.rb +0 -19
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1b5ae43229614572636751dc0765e94da577124b603fdfe034464b9ed7b4aac7
|
|
4
|
+
data.tar.gz: 810e536eb5b67bf68c419eae154567c006deb70ef59cdeeb403ec6eaf6c3ac9d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3b530cefa1913b5253f33dc071f220dc7c88742e6150a9f0c3664b6a4e96f8a6a9137bf6dd30cc9559beeb1ddb7ee875c19ffc271823557ef759a7b18babff99
|
|
7
|
+
data.tar.gz: d96e4ed33ca77f5eb5e163d6ca618c2963ff309d4f7829fa0b33b1029a85a934f179a53fb1775c122a9873c5f954b8300af06a58789313f42fe7270742f41a08
|
|
@@ -25,9 +25,11 @@ class ConnsTableView < RubyQt6::Bando::QWidget
|
|
|
25
25
|
when COLUMN_PROCESS_NAME
|
|
26
26
|
less_than_process_name(lhs, rhs)
|
|
27
27
|
when COLUMN_LOCAL_ADDRESS, COLUMN_REMOTE_ADDRESS
|
|
28
|
-
|
|
28
|
+
less_than_address(lhs, rhs)
|
|
29
29
|
when COLUMN_PROCESS_ID, COLUMN_LOCAL_PORT, COLUMN_REMOTE_PORT
|
|
30
|
-
|
|
30
|
+
less_than_numeric(lhs, rhs)
|
|
31
|
+
when COLUMN_SINCE
|
|
32
|
+
less_than_since(lhs, rhs)
|
|
31
33
|
else
|
|
32
34
|
super
|
|
33
35
|
end
|
|
@@ -50,7 +52,7 @@ class ConnsTableView < RubyQt6::Bando::QWidget
|
|
|
50
52
|
end
|
|
51
53
|
end
|
|
52
54
|
|
|
53
|
-
def
|
|
55
|
+
def less_than_address(lhs, rhs)
|
|
54
56
|
lhs_data = IPAddr.new(source_model.data(lhs).value.to_s)
|
|
55
57
|
rhs_data = IPAddr.new(source_model.data(rhs).value.to_s)
|
|
56
58
|
return false if lhs_data.ipv6? && rhs_data.ipv4?
|
|
@@ -58,10 +60,27 @@ class ConnsTableView < RubyQt6::Bando::QWidget
|
|
|
58
60
|
lhs_data < rhs_data
|
|
59
61
|
end
|
|
60
62
|
|
|
61
|
-
def
|
|
63
|
+
def less_than_numeric(lhs, rhs)
|
|
62
64
|
lhs_data = source_model.data(lhs).value.to_s.to_i
|
|
63
65
|
rhs_data = source_model.data(rhs).value.to_s.to_i
|
|
64
66
|
lhs_data < rhs_data
|
|
65
67
|
end
|
|
68
|
+
|
|
69
|
+
def less_than_since(lhs, rhs)
|
|
70
|
+
lhs_data, rhs_data = [lhs, rhs].map do |index|
|
|
71
|
+
s = source_model.data(index).value.to_s
|
|
72
|
+
next 0 if s.empty?
|
|
73
|
+
s.scan(/\d+\w/).map do |value_unit|
|
|
74
|
+
value, unit = value_unit[..-1].to_i, value_unit[-1]
|
|
75
|
+
case unit
|
|
76
|
+
when "d" then value * 24 * 60 * 60
|
|
77
|
+
when "h" then value * 60 * 60
|
|
78
|
+
when "m" then value * 60
|
|
79
|
+
when "s" then value
|
|
80
|
+
end
|
|
81
|
+
end.reduce(:+)
|
|
82
|
+
end
|
|
83
|
+
lhs_data < rhs_data
|
|
84
|
+
end
|
|
66
85
|
end
|
|
67
86
|
end
|
|
@@ -10,6 +10,7 @@ class ConnsTableView < RubyQt6::Bando::QWidget
|
|
|
10
10
|
COLUMN_LOCAL_PORT = 7
|
|
11
11
|
COLUMN_REMOTE_ADDRESS = 8
|
|
12
12
|
COLUMN_REMOTE_PORT = 9
|
|
13
|
+
COLUMN_SINCE = 10
|
|
13
14
|
|
|
14
15
|
# TCP: Use Traffic Light Color Palette
|
|
15
16
|
COLORS_TCP_STATE = {
|
|
@@ -49,7 +50,7 @@ class ConnsTableView < RubyQt6::Bando::QWidget
|
|
|
49
50
|
|
|
50
51
|
def initialize(parent)
|
|
51
52
|
@geoiolookup = begin
|
|
52
|
-
MaxMind::DB.new(NetmonQt.settings.
|
|
53
|
+
MaxMind::DB.new(NetmonQt.settings.GET_geoip_country_mmdb, mode: MaxMind::DB::MODE_MEMORY)
|
|
53
54
|
rescue Errno::EACCES, Errno::ENOENT
|
|
54
55
|
end
|
|
55
56
|
|
|
@@ -92,6 +93,7 @@ class ConnsTableView < RubyQt6::Bando::QWidget
|
|
|
92
93
|
.push("Local Port")
|
|
93
94
|
.push("Remote Address")
|
|
94
95
|
.push("Remote Port")
|
|
96
|
+
.push("Since")
|
|
95
97
|
)
|
|
96
98
|
end
|
|
97
99
|
|
|
@@ -152,7 +154,7 @@ class ConnsTableView < RubyQt6::Bando::QWidget
|
|
|
152
154
|
def initialize_icon_ipaddress(ipaddress)
|
|
153
155
|
return if @geoiolookup.nil?
|
|
154
156
|
|
|
155
|
-
islocal = Netmon.
|
|
157
|
+
islocal = Netmon::LocalAddressChecker.local?(ipaddress)
|
|
156
158
|
return QIcon.from_theme(QIcon::ThemeIcon::Computer) if islocal
|
|
157
159
|
|
|
158
160
|
record = @geoiolookup.get(ipaddress)
|
|
@@ -188,7 +190,8 @@ class ConnsTableView < RubyQt6::Bando::QWidget
|
|
|
188
190
|
initialize_standarditem(initialize_icon_ipaddress(conn.local_address), conn.local_address),
|
|
189
191
|
initialize_standarditem(conn.local_port.to_s),
|
|
190
192
|
initialize_standarditem(initialize_icon_ipaddress(conn.remote_address), conn.remote_address),
|
|
191
|
-
initialize_standarditem(conn.remote_port.to_s)
|
|
193
|
+
initialize_standarditem(conn.remote_port.to_s),
|
|
194
|
+
initialize_standarditem(conn.since_text)
|
|
192
195
|
)
|
|
193
196
|
|
|
194
197
|
@active_processes.add(comm)
|
|
@@ -213,7 +216,8 @@ class ConnsTableView < RubyQt6::Bando::QWidget
|
|
|
213
216
|
{
|
|
214
217
|
COLUMN_PROCESS_ID => conn.pid_text,
|
|
215
218
|
COLUMN_STATE => conn.state,
|
|
216
|
-
COLUMN_USER => conn.uname
|
|
219
|
+
COLUMN_USER => conn.uname,
|
|
220
|
+
COLUMN_SINCE => conn.since_text
|
|
217
221
|
}.each do |column, text|
|
|
218
222
|
item = @itemmodel.item_from_index(keyitemindex.sibling_at_column(column))
|
|
219
223
|
item.set_text(text)
|
|
@@ -24,9 +24,6 @@ class ConnsTableView < RubyQt6::Bando::QWidget
|
|
|
24
24
|
slot "_on_autorefreshbtn_toggled(bool)"
|
|
25
25
|
slot "_on_autorefresh_timer_timeout()"
|
|
26
26
|
slot "_on_tableview_custom_context_menu_requested(QPoint)"
|
|
27
|
-
slot "_on_endprocess_action_triggered()"
|
|
28
|
-
slot "_on_whois_action_triggered()"
|
|
29
|
-
slot "_on_copy_action_triggered()"
|
|
30
27
|
end
|
|
31
28
|
|
|
32
29
|
attr_reader :processfilter, :protocolfilter, :statefilter, :userfilter
|
|
@@ -59,15 +56,13 @@ class ConnsTableView < RubyQt6::Bando::QWidget
|
|
|
59
56
|
end
|
|
60
57
|
|
|
61
58
|
def initialize_actions
|
|
62
|
-
@endprocess_action = initialize_actions_act(QIcon::ThemeIcon::ApplicationExit, "End Process"
|
|
63
|
-
@whois_action = initialize_actions_act(QIcon::ThemeIcon::EditFind, ""
|
|
64
|
-
@copy_action = initialize_actions_act(QIcon::ThemeIcon::EditCopy, ""
|
|
59
|
+
@endprocess_action = initialize_actions_act(QIcon::ThemeIcon::ApplicationExit, "End Process")
|
|
60
|
+
@whois_action = initialize_actions_act(QIcon::ThemeIcon::EditFind, "")
|
|
61
|
+
@copy_action = initialize_actions_act(QIcon::ThemeIcon::EditCopy, "")
|
|
65
62
|
end
|
|
66
63
|
|
|
67
|
-
def initialize_actions_act(icon, text
|
|
68
|
-
|
|
69
|
-
action.triggered.connect(self, slot)
|
|
70
|
-
action
|
|
64
|
+
def initialize_actions_act(icon, text)
|
|
65
|
+
QAction.new(QIcon.from_theme(icon), text, self)
|
|
71
66
|
end
|
|
72
67
|
|
|
73
68
|
def initialize_toolbar
|
|
@@ -140,6 +135,7 @@ class ConnsTableView < RubyQt6::Bando::QWidget
|
|
|
140
135
|
@tableview.set_column_width(COLUMN_PROCESS_NAME, 128)
|
|
141
136
|
@tableview.set_column_width(COLUMN_LOCAL_ADDRESS, 192)
|
|
142
137
|
@tableview.set_column_width(COLUMN_REMOTE_ADDRESS, 192)
|
|
138
|
+
@tableview.set_column_width(COLUMN_SINCE, 128)
|
|
143
139
|
|
|
144
140
|
@tableview.sort_by_column(COLUMN_PROCESS_NAME, Qt::AscendingOrder)
|
|
145
141
|
@tableview.set_sorting_enabled(true)
|
|
@@ -200,40 +196,36 @@ class ConnsTableView < RubyQt6::Bando::QWidget
|
|
|
200
196
|
menu.set_attribute(Qt::WA_DeleteOnClose)
|
|
201
197
|
|
|
202
198
|
pid = @lastindex.sibling_at_column(COLUMN_PROCESS_ID).data.value.to_s
|
|
203
|
-
remote_address = @lastindex.sibling_at_column(COLUMN_REMOTE_ADDRESS).data.value
|
|
204
|
-
remote_address = remote_address.
|
|
199
|
+
remote_address = @lastindex.sibling_at_column(COLUMN_REMOTE_ADDRESS).data.value.to_s
|
|
200
|
+
remote_address = remote_address.include?(".") ? remote_address : "#{remote_address[0, 12]}..."
|
|
201
|
+
text = @lastindex.data.value.to_s
|
|
205
202
|
|
|
206
203
|
@endprocess_action.set_enabled(pid.to_i.nonzero?)
|
|
207
204
|
@whois_action.set_text("Whois #{remote_address} - via IPinfo")
|
|
208
|
-
@copy_action.set_text("Copy \"#{
|
|
205
|
+
@copy_action.set_text("Copy \"#{text}\"")
|
|
209
206
|
|
|
210
207
|
menu.add_action(@endprocess_action)
|
|
211
208
|
menu.add_separator
|
|
212
209
|
menu.add_action(@whois_action)
|
|
213
210
|
menu.add_action(@copy_action)
|
|
214
211
|
|
|
215
|
-
menu.exec(@tableview.viewport.map_to_global(position))
|
|
212
|
+
case menu.exec(@tableview.viewport.map_to_global(position))
|
|
213
|
+
when @endprocess_action then _on_endprocess_action_triggered(pid)
|
|
214
|
+
when @whois_action then _on_whois_action_triggered(remote_address)
|
|
215
|
+
when @copy_action then _on_copy_action_triggered(text)
|
|
216
|
+
end
|
|
216
217
|
end
|
|
217
218
|
|
|
218
|
-
def _on_endprocess_action_triggered
|
|
219
|
-
return unless @lastindex.valid?
|
|
220
|
-
|
|
221
|
-
pid = @lastindex.sibling_at_column(COLUMN_PROCESS_ID).data.value
|
|
219
|
+
def _on_endprocess_action_triggered(pid)
|
|
222
220
|
QProcess.execute("kill", QStringList.new << "-9" << pid)
|
|
223
221
|
end
|
|
224
222
|
|
|
225
|
-
def _on_whois_action_triggered
|
|
226
|
-
return unless @lastindex.valid?
|
|
227
|
-
|
|
228
|
-
remote_address = @lastindex.sibling_at_column(COLUMN_REMOTE_ADDRESS).data.value
|
|
223
|
+
def _on_whois_action_triggered(remote_address)
|
|
229
224
|
url = QUrl.new("https://ipinfo.io/#{remote_address}")
|
|
230
225
|
QDesktopServices.open_url(url)
|
|
231
226
|
end
|
|
232
227
|
|
|
233
|
-
def _on_copy_action_triggered
|
|
234
|
-
return unless @lastindex.valid?
|
|
235
|
-
|
|
236
|
-
text = @lastindex.data.value
|
|
228
|
+
def _on_copy_action_triggered(text)
|
|
237
229
|
QApplication.clipboard.set_text(text)
|
|
238
230
|
end
|
|
239
231
|
end
|
|
@@ -14,13 +14,13 @@ class ConnsLookupService
|
|
|
14
14
|
end
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
Dir.glob("/proc/[1-9]*/fd/[1-9]*") do |
|
|
18
|
-
|
|
19
|
-
conn = ino2conn[ino]
|
|
17
|
+
Dir.glob("/proc/[1-9]*/fd/[1-9]*") do |filepath|
|
|
18
|
+
conn = ino2conn[File.stat(filepath).ino]
|
|
20
19
|
next if conn.nil?
|
|
21
20
|
|
|
22
|
-
conn.pid =
|
|
21
|
+
conn.pid = filepath.split("/")[2].to_i
|
|
23
22
|
conn.comm = File.read("/proc/#{conn.pid}/comm").strip
|
|
23
|
+
conn.created_at = File.lstat(filepath).ctime
|
|
24
24
|
rescue Errno::EACCES, Errno::ENOENT
|
|
25
25
|
end
|
|
26
26
|
|
|
@@ -39,8 +39,6 @@ class ConnsLookupService
|
|
|
39
39
|
Netmon::Connection::PROTOCOL_UDP4
|
|
40
40
|
when "udp6"
|
|
41
41
|
Netmon::Connection::PROTOCOL_UDP6
|
|
42
|
-
else
|
|
43
|
-
""
|
|
44
42
|
end
|
|
45
43
|
end
|
|
46
44
|
end
|
|
@@ -16,8 +16,8 @@ module NetmonQt
|
|
|
16
16
|
default_connections_check_interval
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
def
|
|
20
|
-
|
|
19
|
+
def GET_geoip_country_mmdb
|
|
20
|
+
default_geoip_country_mmdb
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
private
|
|
@@ -26,8 +26,15 @@ module NetmonQt
|
|
|
26
26
|
4_000
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
def
|
|
30
|
-
|
|
29
|
+
def default_geoip_country_mmdb
|
|
30
|
+
candidates = [
|
|
31
|
+
"/usr/local/share/GeoIP/Country.mmdb",
|
|
32
|
+
"/usr/local/share/GeoIP/GeoLite2-Country.mmdb",
|
|
33
|
+
"/usr/share/GeoIP/Country.mmdb",
|
|
34
|
+
"/usr/share/GeoIP/GeoLite2-Country.mmdb"
|
|
35
|
+
]
|
|
36
|
+
candidates.each { |filepath| return filepath if File.exist?(filepath) }
|
|
37
|
+
candidates[0]
|
|
31
38
|
end
|
|
32
39
|
end
|
|
33
40
|
end
|
|
@@ -29,6 +29,7 @@ module Netmon
|
|
|
29
29
|
attr_accessor :remote_address, :remote_port
|
|
30
30
|
attr_accessor :state, :uid, :inode
|
|
31
31
|
attr_accessor :pid, :comm
|
|
32
|
+
attr_accessor :created_at
|
|
32
33
|
|
|
33
34
|
def initialize(attrs)
|
|
34
35
|
attrs.each do |attr, value|
|
|
@@ -53,5 +54,15 @@ module Netmon
|
|
|
53
54
|
return comm if comm
|
|
54
55
|
inode.zero? ? COMM_DEFUNCT : COMM_UNKNOWN
|
|
55
56
|
end
|
|
57
|
+
|
|
58
|
+
def since_text
|
|
59
|
+
return "" if created_at.nil?
|
|
60
|
+
|
|
61
|
+
m, s = (Time.now - created_at).to_i.divmod(60)
|
|
62
|
+
h, m = m.divmod(60)
|
|
63
|
+
d, h = h.divmod(24)
|
|
64
|
+
units = {"d" => d, "h" => h, "m" => m, "s" => s}
|
|
65
|
+
units.map { |unit, value| value.zero? ? nil : "#{value}#{unit}" }.compact.join(" ")
|
|
66
|
+
end
|
|
56
67
|
end
|
|
57
68
|
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Netmon
|
|
2
|
+
module LocalAddressChecker
|
|
3
|
+
CIDR_LIST = [
|
|
4
|
+
IPAddr.new("224.0.0.0/24"), # Local Multicast - IPv4
|
|
5
|
+
IPAddr.new("ff02::/16"), # Local Multicast - IPv6
|
|
6
|
+
IPAddr.new("0.0.0.0"), # Unspecified - IPv4
|
|
7
|
+
IPAddr.new("::") # Unspecified - IPv6
|
|
8
|
+
].freeze
|
|
9
|
+
|
|
10
|
+
def self.local?(address)
|
|
11
|
+
ip = IPAddr.new(address)
|
|
12
|
+
return true if ip.link_local?
|
|
13
|
+
return true if ip.loopback?
|
|
14
|
+
return true if ip.private?
|
|
15
|
+
return true if CIDR_LIST.any? { |cidr| cidr.include?(address) }
|
|
16
|
+
false
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
data/lib/netmon-qt/lib/netmon.rb
CHANGED
data/lib/netmon-qt/version.rb
CHANGED
data/lib/netmon-qt.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby-netmon-qt
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- John Doe
|
|
@@ -343,7 +343,7 @@ files:
|
|
|
343
343
|
- lib/netmon-qt/lib/contrib/sighandler.rb
|
|
344
344
|
- lib/netmon-qt/lib/netmon.rb
|
|
345
345
|
- lib/netmon-qt/lib/netmon/connection.rb
|
|
346
|
-
- lib/netmon-qt/lib/netmon/
|
|
346
|
+
- lib/netmon-qt/lib/netmon/localaddresschecker.rb
|
|
347
347
|
- lib/netmon-qt/lib/netmon/procnet.rb
|
|
348
348
|
- lib/netmon-qt/version.rb
|
|
349
349
|
- misc/screenshots/mainwindow.png
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
require "ipaddr"
|
|
2
|
-
|
|
3
|
-
module Netmon
|
|
4
|
-
CIDR_LIST = [
|
|
5
|
-
IPAddr.new("224.0.0.0/24"), # Local Multicast - IPv4
|
|
6
|
-
IPAddr.new("ff02::/16"), # Local Multicast - IPv6
|
|
7
|
-
IPAddr.new("0.0.0.0"), # Unspecified - IPv4
|
|
8
|
-
IPAddr.new("::") # Unspecified - IPv6
|
|
9
|
-
].freeze
|
|
10
|
-
|
|
11
|
-
def self.local_address?(address)
|
|
12
|
-
ip = IPAddr.new(address)
|
|
13
|
-
return true if ip.link_local?
|
|
14
|
-
return true if ip.loopback?
|
|
15
|
-
return true if ip.private?
|
|
16
|
-
return true if CIDR_LIST.any? { |cidr| cidr.include?(address) }
|
|
17
|
-
false
|
|
18
|
-
end
|
|
19
|
-
end
|