package scream
import (
"context"
"fmt"
"net"
"net/http"
"sync"
"time"
)
// StartPscan start port scanning tcp or udp (or both)
func StartPscan(host string, timeout time.Duration, gt int64, portstruct ...PortType) []PoutComming {
infop := []byte{0xFF, 0xFF, 0xFF, 0xFF, 0x54, 0x53, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x20, 0x45, 0x6E, 0x67, 0x69, 0x6E, 0x65, 0x20, 0x51, 0x75, 0x65, 0x72, 0x79, 0x00}
resportscan := []PoutComming{}
scanreslock := sync.Mutex{}
dummg := sync.WaitGroup{}
semap := NewWeighted(gt)
pscantcpfunc := func(ip string, port int, pscansig string, timeout time.Duration) {
conn, err := net.DialTimeout(pscansig, fmt.Sprintf("%s:%d", ip, port), timeout)
if err != nil {
scanreslock.Lock()
resportscan = append(resportscan, PoutComming{Stat: "close", Number: port, Ptype: pscansig})
scanreslock.Unlock()
return
}
defer conn.Close()
scanreslock.Lock()
resportscan = append(resportscan, PoutComming{Stat: "open", Number: port, Ptype: pscansig})
scanreslock.Unlock()
}
pscanudpfunc := func(ip string, port int, pscansig string, timeout time.Duration) {
conn, err := net.DialTimeout(pscansig, fmt.Sprintf("%s:%d", ip, port), timeout)
if err != nil {
scanreslock.Lock()
resportscan = append(resportscan, PoutComming{Stat: "close", Number: port, Ptype: pscansig})
scanreslock.Unlock()
return
}
defer conn.Close()
// so for scanning udp ports we have to say something to server and wait for response,
// its pretty sucks
// here we write infop payload on udp connection
_, err = conn.Write(infop)
if err != nil {
// in case something goes wrong ...
scanreslock.Lock()
resportscan = append(resportscan, PoutComming{Stat: "close", Number: port, Ptype: pscansig})
scanreslock.Unlock()
return
}
// buffer
buffer := make([]byte, 1500)
conn.SetReadDeadline(time.Now().Add(timeout))
n, err := conn.Read(buffer)
if err != nil {
scanreslock.Lock()
resportscan = append(resportscan, PoutComming{Stat: "close", Number: port, Ptype: pscansig})
scanreslock.Unlock()
return
}
// check for any response
if buffer == nil || n == 0 {
scanreslock.Lock()
resportscan = append(resportscan, PoutComming{Stat: "close", Number: port, Ptype: pscansig})
scanreslock.Unlock()
return
}
scanreslock.Lock()
resportscan = append(resportscan, PoutComming{Stat: "open", Number: port, Ptype: pscansig})
scanreslock.Unlock()
}
for _, port := range portstruct {
semap.Acquire(context.TODO(), 1)
dummg.Add(1)
go func(port PortType) {
defer semap.Release(1)
defer dummg.Done()
if port.Tp == "TCP" {
pscantcpfunc(host, port.Nm, "tcp", timeout)
return
}
if port.Tp == "UDP" {
pscanudpfunc(host, port.Nm, "udp", timeout)
return
}
pscantcpfunc(host, port.Nm, "tcp", timeout)
pscanudpfunc(host, port.Nm, "udp", timeout)
}(port)
}
dummg.Wait()
return resportscan
}
// DetectWeb return webserver name and an error
func DetectWeb(addr string, port int) (string, error) {
sndreq := http.Client{
Timeout: 3 * time.Second,
}
resp, err := sndreq.Get(fmt.Sprintf("http://%v:%v", addr, port))
if err != nil {
return "", err
}
defer resp.Body.Close()
return resp.Header.Values("Server")[0], nil
}
// ScanResults implement CustomScanTCP and CustomScanUDP
type ScanResults interface {
PortInfo() string
SigPort() string
StatInfo() (bool, int)
}
// CustomScanTCP struct type for tcp scan
type CustomScanTCP struct {
OK bool
NM int
}
// CustomScanUDP struct type for udp scan
type CustomScanUDP struct {
OK bool
NM int
}
// CustomPscan start port scanning tcp or udp (or both) for port mapper tool
func CustomPscan(host string, timeout time.Duration, gt int64, rgscan []int, udpmsg []byte, contype bool, ch chan<- ScanResults) {
dummg := sync.WaitGroup{}
semap := NewWeighted(gt)
defer func() {
dummg.Wait()
close(ch)
}()
pscantcpfunc := func(ip string, port int, pscansig string, timeout time.Duration) {
conn, err := net.DialTimeout(pscansig, fmt.Sprintf("%s:%d", ip, port), timeout)
if err != nil {
ch <- CustomScanTCP{OK: false, NM: port}
return
}
defer conn.Close()
ch <- CustomScanTCP{OK: true, NM: port}
}
pscanudpfunc := func(ip string, port int, pscansig string, timeout time.Duration) {
conn, err := net.DialTimeout(pscansig, fmt.Sprintf("%s:%d", ip, port), timeout)
if err != nil {
ch <- CustomScanUDP{OK: false, NM: port}
return
}
defer conn.Close()
// so for scanning udp ports we have to say something to server and wait for response,
// its pretty sucks
// here we write infop payload on udp connection
_, err = conn.Write(udpmsg)
if err != nil {
// in case something goes wrong ...
ch <- CustomScanUDP{OK: false, NM: port}
return
}
// buffer
buffer := make([]byte, 1500)
conn.SetReadDeadline(time.Now().Add(timeout))
n, err := conn.Read(buffer)
if err != nil {
ch <- CustomScanUDP{OK: false, NM: port}
return
}
// check for any response
if buffer == nil || n == 0 {
ch <- CustomScanUDP{OK: false, NM: port}
return
}
ch <- CustomScanUDP{OK: true, NM: port}
}
if !contype {
for _, port := range rgscan {
if signal, _ := semap.AcquireSnix(context.TODO(), 1); signal != 0 {
return
}
dummg.Add(1)
go func(port int) {
defer semap.Release(1)
defer dummg.Done()
pscantcpfunc(host, port, "tcp", timeout)
}(port)
}
} else {
for _, port := range rgscan {
if signal, _ := semap.AcquireSnix(context.TODO(), 1); signal != 0 {
return
}
dummg.Add(1)
go func(port int) {
defer semap.Release(1)
defer dummg.Done()
pscanudpfunc(host, port, "udp", timeout)
}(port)
}
}
dummg.Wait()
}
// SigPort return port protocol type
func (CustomScanTCP) SigPort() string {
return "tcp"
}
// SigPort return port protocol type
func (CustomScanUDP) SigPort() string {
return "udp"
}
// StatInfo returns stat and port number
func (p CustomScanTCP) StatInfo() (bool, int) {
return p.OK, p.NM
}
// StatInfo returns stat and port number
func (p CustomScanUDP) StatInfo() (bool, int) {
return p.OK, p.NM
}