-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
123 lines (115 loc) · 2.42 KB
/
main.go
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/*
portscan is a simple port scanner that tries to open a range of TCP connections to the given host.
*/
package main
import (
"context"
"flag"
"fmt"
"log"
"net"
"strconv"
"strings"
"sync"
"time"
)
var (
host = flag.String("host", "localhost", "Host or IP to scan")
timeout = flag.Duration("timeout", 1*time.Second, "Timeout per port")
ports = flag.String("range", "80,443", "Port ranges e.g. 80,443,200-1000,8000-9000")
threads = flag.Int("threads", 100, "Threads to use")
showErrs = flag.Bool("verbose", false, "Show errors for failed ports")
)
func processRange(ctx context.Context, r string) chan int {
c := make(chan int)
done := ctx.Done()
go func() {
defer close(c)
blocks := strings.Split(r, ",")
for _, block := range blocks {
rg := strings.Split(block, "-")
if len(rg) != 1 && len(rg) != 2 {
log.Print("Cannot interpret range: ", block)
continue
}
var r1, r2 int
var err error
r1, err = strconv.Atoi(rg[0])
if err != nil {
log.Print("Cannot interpret range: ", block)
continue
}
if len(rg) == 1 {
r2 = r1
} else {
r2, err = strconv.Atoi(rg[1])
if err != nil {
log.Print("Cannot interpret range: ", block)
continue
}
}
for j := r1; j <= r2; j++ {
select {
case c <- j:
case <-done:
return
}
}
}
}()
return c
}
func scanPorts(ctx context.Context, in <-chan int) chan string {
out := make(chan string)
done := ctx.Done()
var wg sync.WaitGroup
wg.Add(*threads)
for i := 0; i < *threads; i++ {
go func() {
defer wg.Done()
for {
select {
case port, ok := <-in:
if !ok {
return
}
s := scanPort(port)
select {
case out <- s:
case <-done:
return
}
case <-done:
return
}
}
}()
}
go func() {
wg.Wait()
close(out)
}()
return out
}
func scanPort(port int) string {
addr := fmt.Sprintf("%s:%d", *host, port)
conn, err := net.DialTimeout("tcp", addr, *timeout)
if err != nil {
return fmt.Sprintf("%d: %s", port, err.Error())
}
conn.Close()
return fmt.Sprintf("%d: OK", port)
}
func main() {
flag.Parse()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fmt.Printf("Scanning %s ports %s timeout %s threads %d\n", *host, *ports, (*timeout).String(), *threads)
c := processRange(ctx, *ports)
s := scanPorts(ctx, c)
for x := range s {
if *showErrs || strings.HasSuffix(x, ": OK") {
fmt.Println(x)
}
}
}