-
Notifications
You must be signed in to change notification settings - Fork 1
/
port.go
226 lines (193 loc) · 5.35 KB
/
port.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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
package utils
import (
"fmt"
"net"
"strconv"
"strings"
"time"
"github.com/cheggaaa/pb/v3"
"github.com/malfunkt/iprange"
)
type ProtocolInfo struct {
Ip string
Port int
}
type ServiceInfo struct {
Addr string
Banner string
}
func parsePorts(portsStr string) ([]int, error) {
var ports []int
portRanges := strings.Split(portsStr, ",")
for _, portRange := range portRanges {
portRange = strings.TrimSpace(portRange)
if strings.Contains(portRange, "-") { // 处理端口范围
rangeBounds := strings.Split(portRange, "-")
if len(rangeBounds) != 2 {
return nil, fmt.Errorf("invalid port range format: %s", portRange)
}
startPort, err := strconv.Atoi(strings.TrimSpace(rangeBounds[0]))
if err != nil {
return nil, fmt.Errorf("invalid start port in range: %s", rangeBounds[0])
}
endPort, err := strconv.Atoi(strings.TrimSpace(rangeBounds[1]))
if err != nil {
return nil, fmt.Errorf("invalid end port in range: %s", rangeBounds[1])
}
if startPort > endPort {
return nil, fmt.Errorf("invalid port range: start port cannot be greater than end port")
}
for port := startPort; port <= endPort; port++ {
ports = append(ports, port)
}
} else { // 处理单个端口
port, err := strconv.Atoi(portRange)
if err != nil {
return nil, fmt.Errorf("invalid port: %s", portRange)
}
ports = append(ports, port)
}
}
uniquePorts, _ := RemoveDuplicateElement(ports)
return uniquePorts.([]int), nil
}
func ipLessThanOrEqual(a, b net.IP) bool {
for i := range a {
if a[i] < b[i] {
return true
}
if a[i] > b[i] {
return false
}
}
return true
}
func incrementIP(ip net.IP) net.IP {
nextIP := make(net.IP, len(ip))
copy(nextIP, ip)
for i := len(nextIP) - 1; i >= 0; i-- {
nextIP[i]++
if nextIP[i] > 0 {
break
}
}
return nextIP
}
// convertIPListToPool 将给定的IP列表转换为IP池
func convertIPListToPool(ipList []string) ([]net.IP, error) {
var ipPool []net.IP
for _, ipStr := range ipList {
ipStr = strings.TrimSpace(ipStr)
if strings.Contains(ipStr, "-") { // 处理范围格式的IP
ipRange := strings.Split(ipStr, "-")
if len(ipRange) != 2 {
return nil, fmt.Errorf("invalid IP range format: %s", ipStr)
}
startIP := net.ParseIP(strings.TrimSpace(ipRange[0]))
endIP := net.ParseIP(strings.TrimSpace(ipRange[1]))
if startIP == nil || endIP == nil {
return nil, fmt.Errorf("invalid IP address in range: %s", ipStr)
}
for ip := startIP; ipLessThanOrEqual(ip, endIP); ip = incrementIP(ip) {
ipPool = append(ipPool, ip)
}
} else if strings.Contains(ipStr, "/") { // 处理CIDR格式的IP
ipr, err := iprange.Parse(ipStr)
if err != nil {
return nil, fmt.Errorf("Error parsing CIDR IP: %v", err)
}
ipPool = append(ipPool, ipr.Expand()...)
} else { // 单个IP
parsedIP := net.ParseIP(ipStr)
if parsedIP == nil {
return nil, fmt.Errorf("invalid IP address: %s", ipStr)
}
ipPool = append(ipPool, parsedIP)
}
}
return ipPool, nil
}
func handleWorker(ip string, ports chan int, results chan ProtocolInfo) {
for p := range ports {
address := fmt.Sprintf("%s:%d", ip, p)
conn, err := net.DialTimeout("tcp", address, 2*time.Second)
if err != nil {
results <- ProtocolInfo{Ip: ip, Port: -p}
continue
}
results <- ProtocolInfo{Ip: ip, Port: p}
conn.Close()
}
}
// func ServiceDetect(all []ProtocolInfo) {
// var wg sync.WaitGroup
// results := []ServiceInfo{} // 创建一个足够大的缓冲区
// for _, open := range all {
// wg.Add(1)
// go func(ip string, port int) {
// defer wg.Done()
// addr, banner := ScanWithIpAndPort(ip, port, "tcp")
// fmt.Println(addr)
// fmt.Println(banner)
// serviceInfo := ServiceInfo{
// Addr: addr,
// Banner: banner,
// }
// results = append(results, serviceInfo)
// }(open.Ip, open.Port)
// }
// wg.Wait()
// // 读取结果
// for _, res := range results {
// Success("[%s] \n>>>>>>banner<<<<<<\n%s", res.Addr, hex.Dump([]byte(res.Banner)))
// }
// }
func PortScan(IpRange string, PortRange string) {
ips, err := convertIPListToPool(strings.Split(IpRange, ","))
if err != nil {
Error("%s", err)
return
}
// return
ports_list, err := parsePorts(PortRange)
if err != nil {
Error("%s", err)
return
}
bar := pb.StartNew(len(ports_list) * len(ips))
var allOpen []ProtocolInfo
for _, ip := range ips {
ports := make(chan int, 50)
results := make(chan ProtocolInfo)
var openSlice []ProtocolInfo
// 任务生产者-分发任务 (新起一个 goroutinue ,进行分发数据)
go func(arr []int) {
for i := 0; i < len(arr); i++ {
ports <- arr[i]
}
}(ports_list)
// 任务消费者-处理任务 (每一个端口号都分配一个 goroutinue ,进行扫描)
// 结果生产者-每次得到结果 再写入 结果 chan 中
for i := 0; i < cap(ports); i++ {
go handleWorker(ip.String(), ports, results)
}
// 结果消费者-等待收集结果 (main中的 goroutinue 不断从 chan 中阻塞式读取数据)
for i := 0; i < len(ports_list); i++ {
resPortInfo := <-results
if resPortInfo.Port > 0 {
openSlice = append(openSlice, resPortInfo)
}
bar.Increment()
}
// 关闭 chan
close(ports)
close(results)
// 输出
allOpen = append(allOpen, openSlice...)
}
bar.Finish()
for _, open := range allOpen {
Success("%s:%-8d Open", open.Ip, open.Port)
}
ScanWithIpAndPort(allOpen)
}