Skip to content

Instantly share code, notes, and snippets.

@picatz
Last active March 22, 2023 16:50
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save picatz/9c0028efd7b3ced3329f7322f41b16e1 to your computer and use it in GitHub Desktop.
Save picatz/9c0028efd7b3ced3329f7322f41b16e1 to your computer and use it in GitHub Desktop.
package main
import (
"context"
"fmt"
"net"
"os/exec"
"strconv"
"strings"
"sync"
"time"
"golang.org/x/sync/semaphore"
)
type PortScanner struct {
ip string
lock *semaphore.Weighted
}
func Ulimit() int64 {
out, err := exec.Command("ulimit", "-n").Output()
if err != nil {
panic(err)
}
s := strings.TrimSpace(string(out))
i, err := strconv.ParseInt(s, 10, 64)
if err != nil {
panic(err)
}
return i
}
func ScanPort(ip string, port int, timeout time.Duration) {
target := fmt.Sprintf("%s:%d", ip, port)
conn, err := net.DialTimeout("tcp", target, timeout)
if err != nil {
if strings.Contains(err.Error(), "too many open files") {
time.Sleep(timeout)
ScanPort(ip, port, timeout)
} else {
fmt.Println(port, "closed")
}
return
}
conn.Close()
fmt.Println(port, "open")
}
func (ps *PortScanner) Start(f, l int, timeout time.Duration) {
wg := sync.WaitGroup{}
defer wg.Wait()
for port := f; port <= l; port++ {
ps.lock.Acquire(context.TODO(), 1)
wg.Add(1)
go func(port int) {
defer ps.lock.Release(1)
defer wg.Done()
ScanPort(ps.ip, port, timeout)
}(port)
}
}
func main() {
ps := &PortScanner{
ip: "127.0.0.1",
lock: semaphore.NewWeighted(Ulimit()),
}
ps.Start(1, 65535, 500*time.Millisecond)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment