2018-08-31 14:00:08 +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 {
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
p := &omd.Port{
|
|
|
|
MetaPortType: omm.ToMetaPortType(omm.MetaPortTypeEnumTCP),
|
|
|
|
PortNumber: json.Number(strconv.Itoa(port)),
|
|
|
|
DiscoveredDate: omu.NowPtr(),
|
|
|
|
}
|
|
|
|
p.Host = targetHost
|
|
|
|
|
|
|
|
ports[port] = p
|
|
|
|
|
2018-09-04 20:03:43 +00:00
|
|
|
go discoverySession.AddPort(p)
|
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
|
|
|
|
}
|