refactor structure

This commit is contained in:
juzeon
2024-02-11 20:29:56 -05:00
committed by yuhan6665
parent 08e703a95e
commit a356902789
4 changed files with 185 additions and 152 deletions
+62 -152
View File
@@ -1,173 +1,83 @@
package main
import (
"crypto/tls"
"flag"
"fmt"
"math/big"
"io"
"log/slog"
"net"
"os"
"strings"
"sync"
"time"
)
var addr string
var in string
var port int
var thread int
var out string
var timeout int
var verbose bool
var enableIPv6 bool
func main() {
addrPtr := flag.String("addr", "127.0.0.1", "Destination to start scan")
portPtr := flag.String("port", "443", "Port to scan")
threadPtr := flag.Int("thread", 2, "Number of threads to scan in parallel")
outPutFile := flag.Bool("o", false, "Is output to results.txt")
timeOutPtr := flag.Int("timeOut", 10, "Time out of a scan")
showFailPtr := flag.Bool("showFail", false, "Is Show fail logs")
_ = os.Unsetenv("ALL_PROXY")
_ = os.Unsetenv("HTTP_PROXY")
_ = os.Unsetenv("HTTPS_PROXY")
_ = os.Unsetenv("NO_PROXY")
flag.StringVar(&addr, "addr", "", "specify an IP, IP CIDR or domain to scan")
flag.StringVar(&in, "in", "", "specify a file that contains multiple "+
"IPs, IP CIDRs or domains to scan, divided by line break")
flag.IntVar(&port, "port", 443, "specify a HTTPS port to check")
flag.IntVar(&thread, "thread", 1, "count of concurrent tasks")
flag.StringVar(&out, "out", "", "output file to store the result")
flag.IntVar(&timeout, "timeout", 10, "timeout for every check")
flag.BoolVar(&verbose, "v", false, "verbose output")
flag.BoolVar(&enableIPv6, "46", false, "Enable IPv6 in additional to IPv4")
flag.Parse()
s := Scanner{
addr: *addrPtr,
port: *portPtr,
showFail: *showFailPtr,
output: *outPutFile,
timeout: time.Duration(*timeOutPtr) * time.Second,
numberOfThread: *threadPtr,
mu: new(sync.Mutex),
if verbose {
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelDebug,
})))
}
if *outPutFile {
s.logFile, _ = os.OpenFile("results.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
}
s.Print(fmt.Sprint("Reality TLS Scanner running: ", *addrPtr, ":", *portPtr, " start scan at : ", time.Now().Format(time.RFC3339)))
defer s.logFile.Close()
s.Run()
}
type Scanner struct {
addr string
port string
output bool
showFail bool
logFile *os.File
timeout time.Duration
numberOfThread int
mu *sync.Mutex
high net.IP
low net.IP
}
func (s *Scanner) Run() {
str := s.addr
addr := net.ParseIP(s.addr)
if addr != nil && addr.To4() == nil {
str = "[" + addr.String() + "]"
}
conn, err := net.DialTimeout("tcp", str+":"+s.port, s.timeout)
if err != nil {
s.Print(fmt.Sprint("Dial failed: ", err))
} else {
addr = conn.RemoteAddr().(*net.TCPAddr).IP
line := "" + conn.RemoteAddr().String() + " \t"
conn.SetDeadline(time.Now().Add(s.timeout))
c := tls.Client(conn, &tls.Config{
InsecureSkipVerify: true,
NextProtos: []string{"h2", "http/1.1"},
})
err = c.Handshake()
if err != nil {
s.Print(fmt.Sprint("", line, "TLS handshake failed: ", err))
} else {
state := c.ConnectionState()
alpn := state.NegotiatedProtocol
if alpn == "" {
alpn = " "
}
s.Print(fmt.Sprint("", line, "----- Found TLS v", TlsDic[state.Version], "\tALPN ", alpn, "\t", state.PeerCertificates[0].Subject))
c.Close()
}
}
if addr == nil {
s.Print("Invalid address format")
if addr != "" && in != "" ||
addr == "" && in == "" {
slog.Error("You must specify either `addr` or `in`")
flag.PrintDefaults()
return
}
s.mu.Lock()
s.high = addr
s.low = addr
s.mu.Unlock()
for i := 0; i < s.numberOfThread; i++ {
go s.Scan(i%2 == 0)
}
for {
// now the scans are performed in goroutines
}
}
func (s *Scanner) Scan(increment bool) {
var addr net.IP
s.mu.Lock()
if increment {
s.high = nextIP(s.high, increment)
addr = s.high
} else {
s.low = nextIP(s.low, increment)
addr = s.low
}
s.mu.Unlock()
str := addr.String()
if addr.To4() == nil {
str = "[" + str + "]"
}
conn, err := net.DialTimeout("tcp", str+":"+s.port, s.timeout)
if err != nil {
if s.showFail {
s.Print(fmt.Sprint("Dial failed: ", err))
}
} else {
line := "" + conn.RemoteAddr().String() + " \t"
conn.SetDeadline(time.Now().Add(s.timeout))
c := tls.Client(conn, &tls.Config{
InsecureSkipVerify: true,
NextProtos: []string{"h2", "http/1.1"},
})
err = c.Handshake()
outWriter := io.Discard
if out != "" {
f, err := os.OpenFile(out, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
if err != nil {
if s.showFail {
s.Print(fmt.Sprint("", line, "TLS handshake failed: ", err))
}
} else {
defer c.Close()
state := c.ConnectionState()
alpn := state.NegotiatedProtocol
if alpn == "" {
alpn = " "
}
if s.showFail || (state.Version == 0x0304 && alpn == "h2") {
s.Print(fmt.Sprint("", line, "----- Found TLS v", TlsDic[state.Version], "\tALPN ", alpn, "\t", state.PeerCertificates[0].Subject))
}
slog.Error("Error opening file", "path", out)
return
}
outWriter = f
}
go s.Scan(increment)
}
func (s *Scanner) Print(outStr string) {
if s.output {
s.logFile.WriteString(outStr + "\n")
}
fmt.Println(outStr)
}
func nextIP(ip net.IP, increment bool) net.IP {
// Convert to big.Int and increment
ipb := big.NewInt(0).SetBytes([]byte(ip))
if increment {
ipb.Add(ipb, big.NewInt(1))
var ipChan <-chan net.IP
if addr != "" {
ipChan = Iterate(strings.NewReader(addr))
} else {
ipb.Sub(ipb, big.NewInt(1))
f, err := os.Open(in)
if err != nil {
slog.Error("Error reading file", "path", in)
return
}
ipChan = Iterate(f)
}
// Add leading zeros
b := ipb.Bytes()
b = append(make([]byte, len(ip)-len(b)), b...)
return net.IP(b)
}
var TlsDic = map[uint16]string{
0x0301: "1.0",
0x0302: "1.1",
0x0303: "1.2",
0x0304: "1.3",
var wg sync.WaitGroup
wg.Add(thread)
for i := 0; i < thread; i++ {
go func() {
for ip := range ipChan {
ScanTLS(ip, outWriter)
}
wg.Done()
}()
}
t := time.Now()
slog.Info("Started all scanning threads", "time", t)
wg.Wait()
slog.Info("Scanning completed", "time", time.Now(), "elapsed", time.Since(t).String())
}