Skip to content

Commit c990e82

Browse files
committed
FEAT: simple TCP port scanner (module)
related to: Oldes/Rebol-issues#1422
1 parent 6bf2b8a commit c990e82

File tree

2 files changed

+121
-0
lines changed

2 files changed

+121
-0
lines changed

src/modules/port-scanner.reb

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
Rebol [
2+
Title: "TCP Port scanner"
3+
File: %port-scanner.reb
4+
Type: module
5+
Name: port-scanner
6+
Version: 1.0.0
7+
Date: 16-Feb-2021
8+
Exports: [scan-ports]
9+
Note: {
10+
If you use anything other than `localhost` you had better have permission
11+
for the host name you do use, or you will suddenly be an *internet bad guy*.
12+
Don't.}
13+
]
14+
15+
; result:
16+
found: copy []
17+
18+
; options:
19+
batch-size: 8000 ; higher batch size means higher CPU use!
20+
timeout: 0:0:0.5 ; setting timeout too low may result in not resolved opened ports!
21+
22+
; actor:
23+
on-awake: func [event /local port id] [
24+
port: event/port
25+
;print [as-green "==TCP-event:" as-red event/type "port:" as-red port/spec/port-id]
26+
switch/default event/type [
27+
lookup [open port]
28+
connect [
29+
id: port/spec/port-id
30+
print ["Open port found:" as-red id]
31+
append found id
32+
false
33+
]
34+
][true]
35+
]
36+
37+
scan-ports: function [
38+
from [integer!] "lowest port numer"
39+
to [integer!] "max port number"
40+
/host name [tuple! string!]
41+
][
42+
clear found
43+
checking: make block! batch-size
44+
started: now/time/precise
45+
46+
if to < from [id: to to: from from: id]
47+
48+
id: low:
49+
from: max 1 from
50+
to: max 1 min to 65535
51+
52+
total: 1 + to - from
53+
54+
try/except [
55+
ip: either tuple? name [ name ][
56+
read join dns:// any [name 'localhost]
57+
]
58+
][
59+
sys/log/error 'REBOL system/state/last-error
60+
return none
61+
]
62+
63+
print [
64+
as-green "Using IP:" as-yellow ip
65+
as-green "timeout:" as-yellow timeout
66+
as-green "batch size:" as-yellow batch-size
67+
newline
68+
]
69+
70+
while [id <= to][
71+
port: make port! compose [
72+
scheme: 'tcp
73+
host: (ip)
74+
port-id: (id)
75+
awake: :on-awake
76+
]
77+
open port
78+
append checking port
79+
if any [
80+
id = to
81+
batch-size = length? checking
82+
][
83+
print [as-green "Checking range:" as-yellow low "-" as-yellow id]
84+
; wait some time...
85+
wait timeout
86+
; and check what was opened...
87+
foreach port checking [ close port ]
88+
clear checking
89+
if id < to [ low: low + batch-size ]
90+
]
91+
++ id
92+
]
93+
checking: none
94+
print ajoin [
95+
as-green "^/Scan of " as-yellow total
96+
as-green " ports finished in time: " as-yellow now/time/precise - started
97+
as-green ".^/Found " as-red length? found as-green " listening TCP ports!^/"
98+
]
99+
found
100+
]

src/tests/test-port-scanner.r3

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
Rebol [
2+
Title: "Test async TCP port scanner"
3+
File: %test-port-scanner.r3
4+
Date: 16-Feb-2021
5+
]
6+
7+
scanner: import 'port-scanner
8+
9+
;- higher batch size means higher CPU use!
10+
;scanner/batch-size: 10000
11+
;- low timeout may result in not founding all listening ports!
12+
;- if the scenner is used on non local ip, the timeout should
13+
;- count with netword latency!
14+
;scanner/timeout: 0:0:0.25
15+
16+
scan-ports/host 1 65535 127.0.0.1
17+
18+
if system/options/script [
19+
?? scanner/found
20+
ask "^/DONE"
21+
]

0 commit comments

Comments
 (0)