probe/discovery/protocol/udp/connection/connection.go

125 lines
2.5 KiB
Go
Raw Normal View History

2018-09-03 04:44:54 +00:00
package connection
import (
"context"
"encoding/json"
"net"
"os/exec"
"strconv"
"strings"
"sync"
"time"
omd "git.loafle.net/overflow/model/discovery"
omm "git.loafle.net/overflow/model/meta"
omu "git.loafle.net/overflow/model/util"
"git.loafle.net/overflow_scanner/probe/discovery/session"
"golang.org/x/sync/semaphore"
)
const (
defaultUlimit = 1024
)
func Scan(discoverySession session.DiscoverySession, targetHost *omd.Host) error {
if nil == targetHost || nil == discoverySession.DiscoverPort() || !discoverySession.DiscoverPort().IncludeTCP {
return nil
}
dp := discoverySession.DiscoverPort()
lock := semaphore.NewWeighted(Ulimit())
var wg sync.WaitGroup
2018-09-03 14:14:51 +00:00
stopChan := make(chan struct{})
2018-09-03 04:44:54 +00:00
timeout := 500 * time.Millisecond
ports := make(map[int]*omd.Port)
Loop:
for portNumber := dp.FirstScanRange; portNumber < dp.LastScanRange; portNumber++ {
if nil != dp.ExcludePorts {
for _, exPortNumber := range dp.ExcludePorts {
if portNumber == exPortNumber {
continue Loop
}
}
}
lock.Acquire(context.TODO(), 1)
wg.Add(1)
go func(port int) {
defer func() {
lock.Release(1)
wg.Done()
}()
2018-09-03 14:14:51 +00:00
tryConnect(discoverySession, ports, targetHost, port, timeout, stopChan)
2018-09-03 04:44:54 +00:00
}(portNumber)
timer := time.NewTimer(time.Microsecond * 100)
select {
case <-timer.C:
2018-09-03 10:33:20 +00:00
case <-discoverySession.StopChan():
2018-09-03 14:14:51 +00:00
close(stopChan)
2018-09-03 10:33:20 +00:00
return nil
2018-09-03 04:44:54 +00:00
}
}
wg.Wait()
return nil
}
2018-09-03 14:14:51 +00:00
func tryConnect(discoverySession session.DiscoverySession, ports map[int]*omd.Port, targetHost *omd.Host, port int, timeout time.Duration, stopChan <-chan struct{}) {
2018-09-03 04:44:54 +00:00
addr := net.JoinHostPort(targetHost.Address, strconv.Itoa(port))
conn, err := net.DialTimeout("tcp", addr, timeout)
dp := discoverySession.DiscoverPort()
if err != nil {
if strings.Contains(err.Error(), "too many open files") {
2018-09-03 10:33:20 +00:00
select {
2018-09-03 14:14:51 +00:00
case <-stopChan:
2018-09-03 10:33:20 +00:00
return
default:
}
2018-09-03 04:44:54 +00:00
time.Sleep(timeout)
2018-09-03 14:14:51 +00:00
tryConnect(discoverySession, ports, targetHost, port, timeout, stopChan)
2018-09-03 04:44:54 +00:00
}
return
}
conn.Close()
if _, ok := ports[port]; ok || !dp.Contains(port) {
return
}
p := &omd.Port{
MetaPortType: omm.ToMetaPortType(omm.MetaPortTypeEnumTCP),
PortNumber: json.Number(strconv.Itoa(port)),
DiscoveredDate: omu.NowPtr(),
}
p.Host = targetHost
ports[port] = p
discoverySession.AddPort(p)
}
func Ulimit() int64 {
out, err := exec.Command("ulimit", "-n").Output()
if nil != err {
return defaultUlimit
}
s := strings.TrimSpace(string(out))
i, err := strconv.ParseInt(s, 10, 64)
if nil != err {
return defaultUlimit
}
return i
}