-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathportscanner.go
More file actions
108 lines (87 loc) · 2.55 KB
/
Copy pathportscanner.go
File metadata and controls
108 lines (87 loc) · 2.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package main
import (
"fmt"
"net"
"os"
"sync/atomic"
"time"
)
const GOROUTINES = 100 // How many ports to check simultaneously
const MIN_PORT = 1 // Lowest port number to check
const MAX_PORT = 65535 // Highest port number to check
func scanOnePort(host string, port uint32) bool {
// Return values: true = connected; false = failed
_, err := net.Dial("tcp", fmt.Sprintf("%s:%d", host, port))
if err != nil {
return false
}
// Log a successful connection
return true
}
func usage() {
fmt.Printf("Usage: %s hostname", os.Args[0])
}
// This runs a goroutine that just loops forever and will die when the app finishes
func printStatus(host string, openPorts chan uint32, portsChecked *uint32) {
go func() {
var spinner = "-\\|/"
fmt.Printf("\n")
for i := 0; ; i = i % 3 {
fmt.Printf("%s Scanning %s [%d/%d] Open ports:%d\r",
string(spinner[i]), host, *portsChecked, cap(openPorts), len(openPorts))
time.Sleep(10 * time.Millisecond)
i++
}
}()
}
/*
*
* Returns: (chan int), (chan bool)
* the int channel is a buffered channel that will be closed at scan completion
*/
func portscan(asyncCount int, host string, startPort uint32, endPort uint32, portsChecked *uint32) (chan uint32, chan bool) {
portCount := endPort + 1 - startPort
var goroutines = make(chan bool, asyncCount) // concurrency control
var openPorts = make(chan uint32, portCount) // Store list of open ports, concurrency-safe, buffered
var completed = make(chan bool)
go func() {
// Tasks to do at completion of scanning
defer func() {
// Close openPorts channel since it's buffered
close(openPorts)
// Send signal to anything waiting on buffered completion channel
completed <- true
}()
for port := startPort; port <= endPort; port++ {
goroutines <- true // Wait until allowed to go
go func(p uint32) {
defer func() {
<-goroutines
}() // release lock when done
// Check the port
if portOpen := scanOnePort(host, p); portOpen {
openPorts <- p
}
atomic.AddUint32(portsChecked, 1)
}(port)
}
}()
return openPorts, completed
}
func main() {
var portsChecked uint32 // uint16 would be enough for a single system
if len(os.Args) < 2 {
usage()
os.Exit(1)
}
var host = os.Args[1]
openPorts, completed := portscan(GOROUTINES, host, MIN_PORT, MAX_PORT, &portsChecked)
printStatus(host, openPorts, &portsChecked)
// Wait for scanning to finish
<-completed
fmt.Printf("\nScanned ports: %d Open ports: %d\n\t[ ", portsChecked, len(openPorts))
for p := range openPorts {
fmt.Printf("%d ", p)
}
fmt.Printf("]\n")
}