package main
import (
"errors"
"fmt"
"math/rand"
"net"
"sync"
"time"
"unsafe"
)
const (
concurrency = 2
)
var (
ip = "127.0.0.1"
portStart, portEnd = 1, 15
openPorts []int
)
func main () {
startAt := time.Now()
defer func(ts time.Time) {
spend := time.Since(ts)
fmt.Printf("<<< IP scan [end] (spend time: %v seconds.)\n", spend)
}(startAt)
fmt.Printf(">>> IP scan [start]...\n")
scanIpAddress(ip, portStart, portEnd)
fmt.Printf("Open ports total: %d \n", len(openPorts))
if len(openPorts) > 0 {
fmt.Printf("Open ports: %v \n", openPorts)
}
}
func scanIpAddress(ip string, portStart, portEnd int) {
if ok, err := verifyParams(ip, portStart, portEnd); ok == false {
fmt.Printf("----- verify-params error: %s \n", err.Error())
return
}
portCh := make(chan int, concurrency)
defer close(portCh)
var wg sync.WaitGroup
for i := 0; i < cap(portCh); i++ {
go handleWorker(ip, portCh, &wg)
}
for j := portStart; j <= portEnd; j++ {
wg.Add(1)
portCh <- j
}
wg.Wait()
}
func handleWorker(ip string, ports chan int, wg *sync.WaitGroup) {
rand.Seed(time.Now().UnixNano())
qNo := fmt.Sprintf("q_%d", rand.Intn(999))
fmt.Printf("----- [Run & Wait] handleWorker() [%s] ----- \n", qNo)
for port := range ports {
addr := fmt.Sprintf("%s:%d", ip, port)
if conn, err := net.Dial("tcp", addr); err == nil {
openPorts = append(openPorts, port)
conn.Close()
}
wg.Done()
}
}
func verifyParams(ip string, portStart, portEnd int) (ok bool, err error) {
_ip := net.ParseIP(ip)
if _ip == nil {
err = errors.New("[ERROR] ip type is must net.ip")
return
}
fmt.Printf("[INFO] ip=%s | ip type is: %T | ip size is: %d \n", _ip, _ip, unsafe.Sizeof(_ip))
if portStart < 1 || portEnd > 65535 {
err = errors.New("[ERROR] port is must in the range of 1~65535")
return
}
fmt.Printf("[INFO] scan ports: %d~%d \n", portStart, portEnd)
ok = true
return
}