Ваш код имеет несколько проблем. В grabBanner
вы, похоже, ссылаетесь на openPorts
, но он нигде не определен. Вы, вероятно, ссылаетесь на глобальную переменную, и эта операция добавления не будет поточно-ориентированной. В дополнение к проблемам безопасности ваших потоков вы, вероятно, исчерпываете ограничения файловых дескрипторов. Возможно, вам следует ограничить количество одновременной работы, выполнив что-то вроде этого:
package main
import (
"fmt"
"net"
"strconv"
"sync"
"time"
)
func main() {
fmt.Println(portScan("127.0.0.1", 1, 65535))
}
// startBanner spins up a handful of async workers
func startBannerGrabbers(num int, target string, portsIn <-chan int) <-chan int {
portsOut := make(chan int)
var wg sync.WaitGroup
wg.Add(num)
for i := 0; i < num; i++ {
go func() {
for p := range portsIn {
if grabBanner(target, p) {
portsOut <- p
}
}
wg.Done()
}()
}
go func() {
wg.Wait()
close(portsOut)
}()
return portsOut
}
func portScan(targetToScan string, portStart int, portEnd int) []int {
ports := make(chan int)
go func() {
for port := portStart; port <= portEnd; port++ {
ports <- port
}
close(ports)
}()
resultChan := startBannerGrabbers(16, targetToScan, ports)
var openPorts []int
for port := range resultChan {
openPorts = append(openPorts, port)
}
return openPorts
}
var targetPorts = make(map[int]string)
func grabBanner(ip string, port int) bool {
connection, err := net.DialTimeout(
"tcp",
ip+":"+strconv.Itoa(port),
time.Second*20)
if err != nil {
return false
}
defer connection.Close() // you should close this!
buffer := make([]byte, 4096)
connection.SetReadDeadline(time.Now().Add(time.Second * 5))
numBytesRead, err := connection.Read(buffer)
if err != nil {
return true
}
// here we add to map port and banner
// ******* MAPS ARE NOT SAFE FOR CONCURRENT WRITERS ******
// ******************* DO NOT DO THIS *******************
targetPorts[port] = string(buffer[0:numBytesRead])
return true
}
Ваше использование var open bool
и его постоянная настройка, а затем возврат - и ненужные, и лишенные смысла. Кроме того, проверка if someBoolVar != false
не является идиоматическим и многословным способом записи if someBoolVar
.
Кроме того, карты не безопасны для одновременного доступа, но ваша функция grabBanner пишет на карту из многих подпрограмм go одновременно. Пожалуйста, прекратите изменять глобальное состояние внутри функций . Вместо этого возвращайте значения.
Вот обновленное объяснение того, что происходит. Сначала мы создаем канал, по которому мы будем выдвигать номера портов для обработки нашими работниками. Затем мы запускаем подпрограмму go, которая записывает порты в диапазоне на этот канал так быстро, как только может. Как только мы записали каждый порт, доступный на этот канал, мы закрываем канал, чтобы наши читатели могли выйти.
Затем мы вызываем метод, который запускает настраиваемое количество bannerGrabber
рабочих. Мы передаем IP-адрес и канал для чтения номеров портов-кандидатов. Эта функция порождает num
процедуры, каждая из которых проходит по каналу portsIn
, который был передан, вызывает функцию grab banner
и затем выдвигает порт на исходящий канал, если он был успешным. Наконец, мы запускаем еще одну подпрограмму go, которая ожидает завершения sync.WaitGroup
, чтобы мы могли закрыть исходящий (результат) канал, как только все рабочие будут выполнены.
Возвращение в функцию portScan
Мы получаем исходящий канал в качестве возвращаемого значения из функции startBannerGrabbers
. Затем мы выбираем канал результата, который был возвращен нам, добавляем все открытые порты в список и затем возвращаем результат.
Я также изменил некоторые стилистические вещи, такие как сокращение имен аргументов вашей функции.
Имея риск звучать как испорченная пластинка, я еще раз подчеркну следующее. Прекратить мутировать глобальное состояние . Вместо установки targetPorts
вы должны накапливать эти значения безопасным для параллелизма способом и возвращать их вызывающей стороне для использования. Похоже, что использование вами глобальных переменных в этом случае является непродуманным сочетанием удобства и отсутствия размышлений о том, как решить проблему без глобальных значений.