Skip to content

Commit 41e5d90

Browse files
committed
feat: custom scan ranges
1 parent 7ad39a5 commit 41e5d90

File tree

9 files changed

+370
-117
lines changed

9 files changed

+370
-117
lines changed

constants.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,22 @@ class DefaultConfig:
1212
timeout = 1.5
1313
repeat = 3
1414

15+
# Credits:
16+
# https://codeberg.org/antigng/gscan_quic/src/branch/master/iprange
17+
scan_ranges = [
18+
(True, '142.250.0.0/15', 'GWS'),
19+
(False, '108.177.0.0/17', 'GWS'),
20+
(False, '172.217.0.0/16', 'GWS'),
21+
(False, '172.253.0.0/16', 'GWS'),
22+
(False, '216.58.192.0/19', 'GWS'),
23+
(False, '72.14.192.0/18', 'GWS'),
24+
(False, '74.125.0.0/16', 'GWS'),
25+
(True, '2001:4860:4802:32::/112', 'GWS v6'),
26+
(False, '2607:f8b0:4000:80a::/112', 'GWS v6'),
27+
(False, '2607:f8b0:4005:801::/112', 'GWS v6'),
28+
(False, '2a00:1450:4010:c0d::/112', 'GWS v6')
29+
]
30+
1531
ONLINE_SERVICES = (
1632
(
1733
'https://ghp.ci/https://raw.githubusercontent.com/GoodCoder666/gtdb/main/src/ip.txt',

dlgEditRange.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# -*- coding: utf-8 -*-
2+
from PySide6.QtWidgets import QDialog, QDialogButtonBox, QTableWidgetItem, QHeaderView
3+
from PySide6.QtCore import Qt, Slot
4+
from ui_dlgEditRange import Ui_Dialog
5+
from constants import DefaultConfig
6+
7+
__all__ = ['dlgEditRange']
8+
9+
class dlgEditRange(QDialog):
10+
def __init__(self, parent, initial_ranges):
11+
super().__init__(parent)
12+
13+
self.ui = Ui_Dialog()
14+
self.ui.setupUi(self)
15+
16+
self.ui.buttonBox.button(QDialogButtonBox.Ok).setText(self.tr('更新'))
17+
self.ui.buttonBox.button(QDialogButtonBox.Cancel).setText(self.tr('取消'))
18+
19+
self.ui.rangesTable.setHorizontalHeaderLabels([self.tr('IP 段'), self.tr('备注')])
20+
self.ui.rangesTable.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
21+
self.ui.rangesTable.setRowCount(len(initial_ranges))
22+
for i, (enabled, ip_range, notes) in enumerate(initial_ranges):
23+
range_item = QTableWidgetItem(ip_range)
24+
range_item.setCheckState(Qt.Checked if enabled else Qt.Unchecked)
25+
self.ui.rangesTable.setItem(i, 0, range_item)
26+
self.ui.rangesTable.setItem(i, 1, QTableWidgetItem(notes))
27+
28+
def get_ranges(self):
29+
return [
30+
(self.ui.rangesTable.item(i, 0).checkState() == Qt.Checked,
31+
self.ui.rangesTable.item(i, 0).text(),
32+
self.ui.rangesTable.item(i, 1).text())
33+
for i in range(self.ui.rangesTable.rowCount())
34+
]
35+
36+
@Slot()
37+
def on_btnAdd_clicked(self):
38+
row = self.ui.rangesTable.rowCount()
39+
self.ui.rangesTable.setRowCount(row + 1)
40+
range_item = QTableWidgetItem('')
41+
range_item.setCheckState(Qt.Checked)
42+
self.ui.rangesTable.setItem(row, 0, range_item)
43+
self.ui.rangesTable.setItem(row, 1, QTableWidgetItem(''))
44+
self.ui.rangesTable.editItem(self.ui.rangesTable.item(row, 0))
45+
46+
@Slot()
47+
def on_btnRemove_clicked(self):
48+
row = self.ui.rangesTable.currentRow()
49+
if row >= 0:
50+
self.ui.rangesTable.removeRow(row)
51+
52+
@Slot()
53+
def on_btnReset_clicked(self):
54+
self.ui.rangesTable.setRowCount(len(DefaultConfig.scan_ranges))
55+
for i, (enabled, ip_range, notes) in enumerate(DefaultConfig.scan_ranges):
56+
range_item = QTableWidgetItem(ip_range)
57+
range_item.setCheckState(Qt.Checked if enabled else Qt.Unchecked)
58+
self.ui.rangesTable.setItem(i, 0, range_item)
59+
self.ui.rangesTable.setItem(i, 1, QTableWidgetItem(notes))
60+
61+
@Slot()
62+
def on_btnClear_clicked(self):
63+
self.ui.rangesTable.setRowCount(0)

dlgEditRange.ui

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ui version="4.0">
3+
<class>Dialog</class>
4+
<widget class="QDialog" name="Dialog">
5+
<property name="geometry">
6+
<rect>
7+
<x>0</x>
8+
<y>0</y>
9+
<width>370</width>
10+
<height>412</height>
11+
</rect>
12+
</property>
13+
<property name="windowTitle">
14+
<string>编辑 IP 段</string>
15+
</property>
16+
<layout class="QVBoxLayout" name="verticalLayout">
17+
<item>
18+
<widget class="QGroupBox" name="groupBox_edit">
19+
<property name="title">
20+
<string>编辑</string>
21+
</property>
22+
<layout class="QHBoxLayout" name="horizontalLayout">
23+
<item>
24+
<widget class="QPushButton" name="btnAdd">
25+
<property name="text">
26+
<string>添加</string>
27+
</property>
28+
</widget>
29+
</item>
30+
<item>
31+
<widget class="QPushButton" name="btnRemove">
32+
<property name="text">
33+
<string>删除</string>
34+
</property>
35+
</widget>
36+
</item>
37+
<item>
38+
<widget class="QPushButton" name="btnReset">
39+
<property name="text">
40+
<string>重置</string>
41+
</property>
42+
</widget>
43+
</item>
44+
<item>
45+
<widget class="QPushButton" name="btnClear">
46+
<property name="text">
47+
<string>清空</string>
48+
</property>
49+
</widget>
50+
</item>
51+
</layout>
52+
</widget>
53+
</item>
54+
<item>
55+
<widget class="QTableWidget" name="rangesTable">
56+
<property name="showGrid">
57+
<bool>false</bool>
58+
</property>
59+
<property name="columnCount">
60+
<number>2</number>
61+
</property>
62+
<column/>
63+
<column/>
64+
</widget>
65+
</item>
66+
<item>
67+
<widget class="QDialogButtonBox" name="buttonBox">
68+
<property name="orientation">
69+
<enum>Qt::Horizontal</enum>
70+
</property>
71+
<property name="standardButtons">
72+
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
73+
</property>
74+
</widget>
75+
</item>
76+
</layout>
77+
</widget>
78+
<resources/>
79+
<connections>
80+
<connection>
81+
<sender>buttonBox</sender>
82+
<signal>accepted()</signal>
83+
<receiver>Dialog</receiver>
84+
<slot>accept()</slot>
85+
<hints>
86+
<hint type="sourcelabel">
87+
<x>248</x>
88+
<y>254</y>
89+
</hint>
90+
<hint type="destinationlabel">
91+
<x>157</x>
92+
<y>274</y>
93+
</hint>
94+
</hints>
95+
</connection>
96+
<connection>
97+
<sender>buttonBox</sender>
98+
<signal>rejected()</signal>
99+
<receiver>Dialog</receiver>
100+
<slot>reject()</slot>
101+
<hints>
102+
<hint type="sourcelabel">
103+
<x>316</x>
104+
<y>260</y>
105+
</hint>
106+
<hint type="destinationlabel">
107+
<x>286</x>
108+
<y>274</y>
109+
</hint>
110+
</hints>
111+
</connection>
112+
</connections>
113+
</ui>

dlgScan.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,33 @@
11
# -*- coding: utf-8 -*-
22
from PySide6.QtWidgets import QDialog, QDialogButtonBox
3+
from PySide6.QtCore import Slot
34
from ui_dlgScan import Ui_Dialog
5+
from dlgEditRange import dlgEditRange
46

57
__all__ = ['dlgScan']
68

79
class dlgScan(QDialog):
8-
def __init__(self, parent=None):
10+
def __init__(self, parent, ip_ranges):
911
super().__init__(parent)
1012

1113
self.ui = Ui_Dialog()
1214
self.ui.setupUi(self)
1315

1416
self.ui.buttonBox.button(QDialogButtonBox.Ok).setText(self.tr('扫描'))
1517
self.ui.buttonBox.button(QDialogButtonBox.Cancel).setText(self.tr('取消'))
18+
19+
self.ip_ranges = ip_ranges
20+
self._update_range_count()
21+
22+
def _update_range_count(self):
23+
edit_translation = self.tr('编辑...')
24+
num_ranges = len(self.ip_ranges)
25+
num_enabled_ranges = sum(1 for enabled, _, _ in self.ip_ranges if enabled)
26+
self.ui.btnEditRanges.setText(f'{edit_translation} ({num_enabled_ranges}/{num_ranges})')
27+
28+
@Slot()
29+
def on_btnEditRanges_clicked(self):
30+
dlg = dlgEditRange(self, self.ip_ranges)
31+
if dlg.exec() == QDialog.Accepted:
32+
self.ip_ranges = dlg.get_ranges()
33+
self._update_range_count()

dlgScan.ui

Lines changed: 15 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<x>0</x>
88
<y>0</y>
99
<width>228</width>
10-
<height>209</height>
10+
<height>187</height>
1111
</rect>
1212
</property>
1313
<property name="windowTitle">
@@ -161,66 +161,47 @@
161161
</layout>
162162
</item>
163163
<item>
164-
<layout class="QHBoxLayout" name="chkBoxLayout">
164+
<layout class="QHBoxLayout" name="horizontalLayout_2">
165165
<item>
166-
<widget class="QCheckBox" name="chkBox_optimize">
166+
<widget class="QLabel" name="labScanRanges">
167167
<property name="text">
168-
<string>启用扫描优化</string>
169-
</property>
170-
<property name="checked">
171-
<bool>true</bool>
168+
<string>扫描 IP 段:</string>
172169
</property>
173170
</widget>
174171
</item>
175172
<item>
176-
<widget class="QCheckBox" name="chkBox_autoTest">
173+
<widget class="QPushButton" name="btnEditRanges">
177174
<property name="text">
178-
<string>完成后自动测速</string>
179-
</property>
180-
<property name="checked">
181-
<bool>true</bool>
175+
<string>编辑...</string>
182176
</property>
183177
</widget>
184178
</item>
185179
</layout>
186180
</item>
187181
<item>
188-
<layout class="QHBoxLayout" name="extendScanLayout">
182+
<layout class="QHBoxLayout" name="chkBoxLayout">
189183
<item>
190-
<widget class="QCheckBox" name="chkBox_extend4">
184+
<widget class="QCheckBox" name="chkBox_randomizeScan">
191185
<property name="toolTip">
192-
<string>扩大 IPv4 扫描范围。</string>
186+
<string>以随机的顺序执行扫描。</string>
193187
</property>
194188
<property name="text">
195-
<string>扩展扫描 IPv4</string>
196-
</property>
197-
<property name="checked">
198-
<bool>true</bool>
189+
<string>随机化扫描</string>
199190
</property>
200191
</widget>
201192
</item>
202193
<item>
203-
<widget class="QCheckBox" name="chkBox_extend6">
204-
<property name="toolTip">
205-
<string>扩大扫描范围,增加 IPv6 支持。</string>
206-
</property>
194+
<widget class="QCheckBox" name="chkBox_autoTest">
207195
<property name="text">
208-
<string>扩展扫描 IPv6</string>
196+
<string>完成后自动测速</string>
197+
</property>
198+
<property name="checked">
199+
<bool>true</bool>
209200
</property>
210201
</widget>
211202
</item>
212203
</layout>
213204
</item>
214-
<item>
215-
<widget class="QCheckBox" name="chkBox_randomizeScan">
216-
<property name="toolTip">
217-
<string>以随机的顺序执行扫描。</string>
218-
</property>
219-
<property name="text">
220-
<string>随机化扫描</string>
221-
</property>
222-
</widget>
223-
</item>
224205
<item>
225206
<widget class="QDialogButtonBox" name="buttonBox">
226207
<property name="orientation">

main.py

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
# -*- coding: utf-8 -*-
22
import sys
3+
from ipaddress import ip_network
34

45
from PySide6.QtWidgets import *
5-
from PySide6.QtCore import Qt, Slot, QSettings, QTranslator
6+
from PySide6.QtCore import QSettings, Qt, QTranslator, Slot
67
from PySide6.QtGui import QAction
78

89
from constants import GTDB_IPS, ONLINE_SERVICES, DefaultConfig
@@ -71,7 +72,7 @@ def __init__(self, parent=None):
7172
self.ui.actResetSettings.triggered.connect(self._reset_settings)
7273
self.settings = QSettings('GoodCoder666', 'IPFinder')
7374
if set(self.settings.allKeys()) == {
74-
'appearance/style', 'appearance/font', 'appearance/language', 'test/host',
75+
'appearance/style', 'appearance/font', 'appearance/language', 'scan/ranges', 'test/host',
7576
'test/template', 'test/num_threads', 'test/timeout', 'test/repeat', 'saveHosts'}:
7677
self._update_ui()
7778
else:
@@ -130,6 +131,7 @@ def _reset_settings(self):
130131
self.settings.setValue('appearance/style', QApplication.style().objectName())
131132
self.settings.setValue('appearance/font', self.default_font)
132133
self.settings.setValue('appearance/language', DefaultConfig.language)
134+
self.settings.setValue('scan/ranges', DefaultConfig.scan_ranges)
133135
self.settings.setValue('test/host', DefaultConfig.test_host)
134136
self.settings.setValue('test/template', DefaultConfig.template)
135137
self.settings.setValue('test/num_threads', DefaultConfig.num_threads)
@@ -363,21 +365,36 @@ def on_btnWait_Scan_clicked(self):
363365
self.ui.btnWait_Scan.setEnabled(False)
364366
self.sthread.cancel()
365367
return
366-
dlg = dlgScan(self)
368+
369+
dlg = dlgScan(self, self.settings.value('scan/ranges'))
367370
if dlg.exec() == QDialog.Accepted:
368371
max_ips = dlg.ui.spinBox_MaxIP.value()
369372
num_workers = int(dlg.ui.comboBox_threads.currentText())
370373
timeout = dlg.ui.spinBox_timeout.value()
371-
enableOptimization = dlg.ui.chkBox_optimize.isChecked()
372374
autoTest = dlg.ui.chkBox_autoTest.isChecked()
373-
extend4 = dlg.ui.chkBox_extend4.isChecked()
374-
extend6 = dlg.ui.chkBox_extend6.isChecked()
375375
randomized = dlg.ui.chkBox_randomizeScan.isChecked()
376376

377+
# process IP ranges
378+
ip_ranges = dlg.ip_ranges
379+
try:
380+
ip_networks = [ip_network(ip_range) for enabled, ip_range, _ in ip_ranges if enabled]
381+
except ValueError:
382+
for enabled, ip_range, _ in ip_ranges:
383+
if not enabled: continue
384+
try:
385+
ip_network(ip_range)
386+
except ValueError:
387+
QMessageBox.critical(self, self.tr('错误'), self.tr('%s 不是一个合法的 IP 段。') % ip_range)
388+
return
389+
if not ip_networks:
390+
QMessageBox.critical(self, self.tr('错误'), self.tr('请至少选择一个 IP 段。'))
391+
return
392+
self.settings.setValue('scan/ranges', ip_ranges)
393+
377394
self._set_buttons_enabled(False)
378395
self.ui.ipList.clear()
379-
thread = ScanThread(self, max_ips, num_workers, timeout,
380-
enableOptimization, extend4, extend6, randomized)
396+
397+
thread = ScanThread(self, ip_networks, max_ips, num_workers, timeout, randomized)
381398
thread.finished.connect(self._test_ips if autoTest else self._after_scan)
382399
thread.foundAvailable.connect(self._report_single_scan_result)
383400
thread.progressUpdate.connect(self._scan_update)

0 commit comments

Comments
 (0)