


An article explaining in detail how to implement a port scanner in Go
This article brings you relevant knowledge about Go. It mainly introduces how to implement the port scanner in Go. There are code examples. Friends who are interested can take a look below. I hope it will be helpful to you.
Use GO to scan server ports in batches
1. Port scanner V1 - basic operation
package mainimport ( "fmt" "net" "time" "unsafe")func main() { tcpScan("127.0.0.1", 1, 65535)}func tcpScan(ip string, portStart int, portEnd int) { start := time.Now() // 参数校验 isok := verifyParam(ip, portStart, portEnd) if isok == false { fmt.Printf("[Exit]\n") } for i := portStart; i <= portEnd; i++ { address := fmt.Sprintf("%s:%d", ip, i) conn, err := net.Dial("tcp", address) if err != nil { fmt.Printf("[info] %s Close \n", address) continue } conn.Close() fmt.Printf("[info] %s Open \n", address) } cost := time.Since(start) fmt.Printf("[tcpScan] cost %s second \n", cost)}func verifyParam(ip string, portStart int, portEnd int) bool { netip := net.ParseIP(ip) if netip == nil { fmt.Println("[Error] ip type is must net.ip") return false } fmt.Printf("[Info] ip=%s | ip type is: %T | ip size is: %d \n", netip, netip, unsafe.Sizeof(netip)) if portStart < 1 || portEnd > 65535 { fmt.Println("[Error] port is must in the range of 1~65535") return false } fmt.Printf("[Info] port start:%d end:%d \n", portStart, portEnd) return true}
2. Port scanner V2 - using goroutine
package mainimport ( "fmt" "net" "sync" "time" "unsafe")func main() { tcpScanByGoroutine("127.0.0.1", 1, 65535)}func tcpScanByGoroutine(ip string, portStart int, portEnd int) { start := time.Now() // 参数校验 isok := verifyParam(ip, portStart, portEnd) if isok == false { fmt.Printf("[Exit]\n") } var wg sync.WaitGroup for i := portStart; i <= portEnd; i++ { wg.Add(1) go func(j int) { defer wg.Done() address := fmt.Sprintf("%s:%d", ip, j) conn, err := net.Dial("tcp", address) if err != nil { fmt.Printf("[info] %s Close \n", address) return } conn.Close() fmt.Printf("[info] %s Open \n", address) }(i) } wg.Wait() cost := time.Since(start) fmt.Printf("[tcpScanByGoroutine] cost %s second \n", cost)}func verifyParam(ip string, portStart int, portEnd int) bool { netip := net.ParseIP(ip) if netip == nil { fmt.Println("[Error] ip type is must net.ip") return false } fmt.Printf("[Info] ip=%s | ip type is: %T | ip size is: %d \n", netip, netip, unsafe.Sizeof(netip)) if portStart < 1 || portEnd > 65535 { fmt.Println("[Error] port is must in the range of 1~65535") return false } fmt.Printf("[Info] port start:%d end:%d \n", portStart, portEnd) return true}
3. Port Scanner V3 - Using Goroutine Channel
package mainimport ( "fmt" "net" "sync" "time" "unsafe")func main() { tcpScanByGoroutineWithChannel("127.0.0.1", 1, 65535)}func handleWorker(ip string, ports chan int, wg *sync.WaitGroup) { for p := range ports { address := fmt.Sprintf("%s:%d", ip, p) conn, err := net.Dial("tcp", address) if err != nil { fmt.Printf("[info] %s Close \n", address) wg.Done() continue } conn.Close() fmt.Printf("[info] %s Open \n", address) wg.Done() }}func tcpScanByGoroutineWithChannel(ip string, portStart int, portEnd int) { start := time.Now() // 参数校验 isok := verifyParam(ip, portStart, portEnd) if isok == false { fmt.Printf("[Exit]\n") } ports := make(chan int, 100) var wg sync.WaitGroup for i := 0; i < cap(ports); i++ { go handleWorker(ip, ports, &wg) } for i := portStart; i <= portEnd; i++ { wg.Add(1) ports <- i } wg.Wait() close(ports) cost := time.Since(start) fmt.Printf("[tcpScanByGoroutineWithChannel] cost %s second \n", cost)}func verifyParam(ip string, portStart int, portEnd int) bool { netip := net.ParseIP(ip) if netip == nil { fmt.Println("[Error] ip type is must net.ip") return false } fmt.Printf("[Info] ip=%s | ip type is: %T | ip size is: %d \n", netip, netip, unsafe.Sizeof(netip)) if portStart < 1 || portEnd > 65535 { fmt.Println("[Error] port is must in the range of 1~65535") return false } fmt.Printf("[Info] port start:%d end:%d \n", portStart, portEnd) return true}
4 Port Scanner V4 - Introducing two Channel
// packagepackage mainimport ( "fmt" "net" "sort" "time" "unsafe")func main() { tcpScanByGoroutineWithChannelAndSort("127.0.0.1", 1, 65535)}// The function handles checking if ports are open or closed for a given IP address.func handleWorker(ip string, ports chan int, results chan int) { for p := range ports { address := fmt.Sprintf("%s:%d", ip, p) conn, err := net.Dial("tcp", address) if err != nil { // fmt.Printf("[debug] ip %s Close \n", address) results <- (-p) continue } // fmt.Printf("[debug] ip %s Open \n", address) conn.Close() results <- p }}func tcpScanByGoroutineWithChannelAndSort(ip string, portStart int, portEnd int) { start := time.Now() // 参数校验 isok := verifyParam(ip, portStart, portEnd) if isok == false { fmt.Printf("[Exit]\n") } ports := make(chan int, 50) results := make(chan int) var openSlice []int var closeSlice []int // 任务生产者-分发任务 (新起一个 goroutinue ,进行分发数据) go func(a int, b int) { for i := a; i <= b; i++ { ports <- i } }(portStart, portEnd) // 任务消费者-处理任务 (每一个端口号都分配一个 goroutinue ,进行扫描) // 结果生产者-每次得到结果 再写入 结果 chan 中 for i := 0; i < cap(ports); i++ { go handleWorker(ip, ports, results) } // 结果消费者-等待收集结果 (main中的 goroutinue 不断从 chan 中阻塞式读取数据) for i := portStart; i <= portEnd; i++ { resPort := <-results if resPort > 0 { openSlice = append(openSlice, resPort) } else { closeSlice = append(closeSlice, -resPort) } } // 关闭 chan close(ports) close(results) // 排序 sort.Ints(openSlice) sort.Ints(closeSlice) // 输出 for _, p := range openSlice { fmt.Printf("[info] %s:%-8d Open\n", ip, p) } // for _, p := range closeSlice { // fmt.Printf("[info] %s:%-8d Close\n", ip, p) // } cost := time.Since(start) fmt.Printf("[tcpScanByGoroutineWithChannelAndSort] cost %s second \n", cost)}func verifyParam(ip string, portStart int, portEnd int) bool { netip := net.ParseIP(ip) if netip == nil { fmt.Println("[Error] ip type is must net.ip") return false } fmt.Printf("[Info] ip=%s | ip type is: %T | ip size is: %d \n", netip, netip, unsafe.Sizeof(netip)) if portStart < 1 || portEnd > 65535 { fmt.Println("[Error] port is must in the range of 1~65535") return false } fmt.Printf("[Info] port start:%d end:%d \n", portStart, portEnd) return true}
The above is the detailed content of An article explaining in detail how to implement a port scanner in Go. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

In Go, WebSocket messages can be sent using the gorilla/websocket package. Specific steps: Establish a WebSocket connection. Send a text message: Call WriteMessage(websocket.TextMessage,[]byte("Message")). Send a binary message: call WriteMessage(websocket.BinaryMessage,[]byte{1,2,3}).

In Go, the function life cycle includes definition, loading, linking, initialization, calling and returning; variable scope is divided into function level and block level. Variables within a function are visible internally, while variables within a block are only visible within the block.

Go and the Go language are different entities with different characteristics. Go (also known as Golang) is known for its concurrency, fast compilation speed, memory management, and cross-platform advantages. Disadvantages of the Go language include a less rich ecosystem than other languages, a stricter syntax, and a lack of dynamic typing.

In Go, you can use regular expressions to match timestamps: compile a regular expression string, such as the one used to match ISO8601 timestamps: ^\d{4}-\d{2}-\d{2}T \d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-][0-9]{2}:[0-9]{2})$ . Use the regexp.MatchString function to check if a string matches a regular expression.

Memory leaks can cause Go program memory to continuously increase by: closing resources that are no longer in use, such as files, network connections, and database connections. Use weak references to prevent memory leaks and target objects for garbage collection when they are no longer strongly referenced. Using go coroutine, the coroutine stack memory will be automatically released when exiting to avoid memory leaks.

View Go function documentation using the IDE: Hover the cursor over the function name. Press the hotkey (GoLand: Ctrl+Q; VSCode: After installing GoExtensionPack, F1 and select "Go:ShowDocumentation").

When passing a map to a function in Go, a copy will be created by default, and modifications to the copy will not affect the original map. If you need to modify the original map, you can pass it through a pointer. Empty maps need to be handled with care, because they are technically nil pointers, and passing an empty map to a function that expects a non-empty map will cause an error.

In Golang, error wrappers allow you to create new errors by appending contextual information to the original error. This can be used to unify the types of errors thrown by different libraries or components, simplifying debugging and error handling. The steps are as follows: Use the errors.Wrap function to wrap the original errors into new errors. The new error contains contextual information from the original error. Use fmt.Printf to output wrapped errors, providing more context and actionability. When handling different types of errors, use the errors.Wrap function to unify the error types.
