probe/discovery/protocol/tcp/connection/connection.go

130 lines
2.6 KiB
Go
Raw Permalink Normal View History

2018-08-31 14:00:08 +00:00
package connection
import (
"context"
"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
)
2018-09-28 10:57:13 +00:00
var (
discovererType = omm.ToMetaDiscovererType(omm.MetaDiscovererTypeEnumTCPConnection)
)
2018-08-31 14:00:08 +00:00
func Scan(discoverySession session.DiscoverySession, targetHost *omd.Host) error {
2018-09-01 08:49:01 +00:00
if nil == targetHost || nil == discoverySession.DiscoverPort() || !discoverySession.DiscoverPort().IncludeTCP {
2018-08-31 14:00:08 +00:00
return nil
}
2018-09-28 10:57:13 +00:00
if !discoverySession.HostNeedScan(targetHost, discovererType) {
return nil
}
2018-08-31 14:00:08 +00:00
dp := discoverySession.DiscoverPort()
lock := semaphore.NewWeighted(Ulimit())
var wg sync.WaitGroup
2018-09-03 14:14:51 +00:00
stopChan := make(chan struct{})
2018-08-31 14:00:08 +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-08-31 14:00:08 +00:00
}(portNumber)
select {
2018-09-04 19:12:14 +00:00
case <-time.After(time.Microsecond * 100):
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-08-31 14:00:08 +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-08-31 14:00:08 +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-08-31 14:00:08 +00:00
time.Sleep(timeout)
2018-09-03 14:14:51 +00:00
tryConnect(discoverySession, ports, targetHost, port, timeout, stopChan)
2018-08-31 14:00:08 +00:00
}
return
}
conn.Close()
if _, ok := ports[port]; ok || !dp.Contains(port) {
return
}
2018-09-12 04:55:51 +00:00
p := omd.NewPort(
targetHost,
omm.ToMetaPortType(omm.MetaPortTypeEnumTCP),
port,
)
p.DiscoveredDate = omu.NowPtr()
2018-08-31 14:00:08 +00:00
ports[port] = p
2018-09-28 10:57:13 +00:00
go discoverySession.AddPort(discovererType, p, nil)
2018-08-31 14:00:08 +00:00
}
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
}