/
nice_jam
/
NetworkGoProgramming
Обзор
Документация
Войти
/
nice_jam
/
NetworkGoProgramming
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
port_scanner/main.go
150 строк
4 KB
Filippenko Pavel
port scanner, initial commit
27 сен 2025, 14:55
27 сен 2025, 14:55
4022f3f
Код
Авторство
О чём код?
package main import ( "flag" "fmt" "net" "regexp" "strconv" "strings" "sync" "time" ) // Check if ip address string has an ipv4 structure func isValidIPv4(ip string) bool { ipv4Pattern := `^(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}$` regex := regexp.MustCompile(ipv4Pattern) return regex.MatchString(ip) } func parsePorts(portsStr string) ([]int, error) { // Process the pattern of port range "1000:8000" if strings.Contains(portsStr, "..") { parts := strings.Split(portsStr, "..") if len(parts) < 2 { return nil, fmt.Errorf("Incorrect port range: %s", portsStr) } start, err := strconv.Atoi(parts[0]) if err != nil { return nil, err } end, err := strconv.Atoi(parts[1]) if err != nil { return nil, err } var step int if len(parts) == 3 { step, err = strconv.Atoi(parts[2]) if err != nil { return nil, err } } else { step = 1 } var ports []int for i := start; i <= end; i += step { ports = append(ports, i) } return ports, nil } else if strings.Contains(portsStr, ",") { //Process the pattern of particular ports: port1, port2, ... var ports []int for _, p := range strings.Split(portsStr, ",") { port, err := strconv.Atoi(p) if err != nil { return nil, err } ports = append(ports, port) } return ports, nil } else { // When user set a single port port, err := strconv.Atoi(portsStr) if err != nil { return nil, err } return []int{port}, nil } } // Function for running in gorutine -- make a tcp connection with host through seted port func scanPort(host string, port int, timeout time.Duration, wg *sync.WaitGroup, results chan<- string) { // Decriment counter in group when the gorutine expire defer wg.Done() address := fmt.Sprintf("%s:%d", host, port) // net.DialTimeout -- устанавливает tmp соединение с заданным хостом на заданный timeout // Если соединение не установилось за заданный timeout функция возвращает ошибку conn, err := net.DialTimeout("tcp", address, timeout) if err != nil { results <- fmt.Sprintf("Port %d: is closed", port) return } // Close the connection, notice, that we don't need to use defer here, cause // connection will be not opened if err conn.Close() results <- fmt.Sprintf("Port %d: is open", port) } func main() { //TODO: add --help option var timeoutMs int flag.IntVar(&timeoutMs, "t", 1000, "scan work timeout in ms") flag.Parse() // Getting command line arguments args := flag.Args() if len(args) < 2 { fmt.Println("Using: scanner <host> <portA>..<portB> [-t timeout]") fmt.Println("example: scanner example.com 80..100 -t 500") return } // Check the Ipv4 correct structure (not support Ipv6 yet) host := args[0] if !isValidIPv4(host) { fmt.Printf("Invalid structure of ip address: %s\nPlease, use Ipv4 address structure.\n", host) return } ports, err := parsePorts(args[1]) if err != nil { fmt.Printf("Port parsing error: %v\n", err) return } timeout := time.Duration(timeoutMs) * time.Millisecond // Channel which will be used to obtain a response from each port results := make(chan string) // WaitFroup as a tool of gorutine managment var wg sync.WaitGroup // For each particular port we start a gorutine and wait for a response from it through the cahnnel for _, port := range ports { wg.Add(1) go scanPort(host, port, timeout, &wg, results) } // Separate gorutine that monitores waitgroup and close channel when all of the gorutines returns // We are doing it for asynch printing results of the gorutines work go func() { wg.Wait() close(results) }() // asynch printing results of the gorutines work for res := range results { fmt.Println(res) } }