I'm writing simple net scanner and stuck at resolving service name by port number. What's the best way to do this? I supposed it should be something like python's socket.getservbyport()
and founded this lib, but unfortunately Dev environment bases on Windows, also I wanted built-in solution not a parsers.
package main
import (
"fmt"
"net"
"strings"
"sync"
"time"
)
type PortScanner struct {
ip string
}
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)
}
return
}
if err = conn.Close(); err != nil {
fmt.Println(err)
}
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++ {
wg.Add(1)
go func(port int) {
defer wg.Done()
ScanPort(ps.ip, port, timeout)
}(port)
}
}
func main() {
ps := &PortScanner{ip: "127.0.0.1"}
ps.Start(1, 65535, 500*time.Millisecond)
}
You can modify the code from that netdb library to load a services
file you provide instead of /etc/services
.
Perhaps better yet, since this is essentially just a key/value mapping, create a ports.go
file with:
var tcpPorts = map[int]string{
80: "http"
// ...
}
And then do a regular map lookup.
To list all TCP ports you can do something like:
$ sed -E '/tcp$/!d; s!^([a-zA-Z0-9\-]+)\s+([0-9]+)/\w+!\t\2: "\1",!;' /etc/services
1: "tcpmux",
2: "compressnet",
3: "compressnet",
5: "rje",
7: "echo",
9: "discard",
11: "systat",
13: "daytime",
17: "qotd",
19: "chargen",
.. many more ..