Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save charSLee013/8558d265914a5d8af26ca6687f4756c9 to your computer and use it in GitHub Desktop.
Save charSLee013/8558d265914a5d8af26ca6687f4756c9 to your computer and use it in GitHub Desktop.
Websocket with SSL/TLS checker
package main
import (
"bufio"
"context"
"crypto/rand"
"encoding/base64"
"errors"
"flag"
"fmt"
"log"
"net"
"net/http"
"os"
"runtime"
"runtime/pprof"
"strings"
"sync"
"time"
_ "net/http/pprof"
)
var (
concurrent chan struct{} // concurrent request limiter
ip, port, file, host string
num int
debug bool
headers http.Header
ips chan string
)
func main() {
// Parse command line flags
flag.StringVar(&ip, "ip", "", "Target IP address")
flag.StringVar(&port, "port", "", "Target port")
flag.StringVar(&file, "file", "", "File containing IP addresses")
flag.IntVar(&num, "num", 200, "Number of concurrent requests")
flag.StringVar(&host, "host", "", "Target domain name")
flag.BoolVar(&debug, "debug", false, "Enable debug mode")
flag.Parse()
// Enable debugging if specified
if debug {package main
import (
"bufio"
"context"
"crypto/rand"
"encoding/base64"
"errors"
"flag"
"fmt"
"log"
"net"
"net/http"
"os"
"runtime"
"runtime/pprof"
"strings"
"sync"
"time"
_ "net/http/pprof"
)
var (
concurrent chan struct{} // concurrent request limiter
ip, port, file, host string
num int
debug bool
headers http.Header
ips chan string
)
func main() {
// Parse command line flags
flag.StringVar(&ip, "ip", "", "Target IP address")
flag.StringVar(&port, "port", "", "Target port")
flag.StringVar(&file, "file", "", "File containing IP addresses")
flag.IntVar(&num, "num", 200, "Number of concurrent requests")
flag.StringVar(&host, "host", "", "Target domain name")
flag.BoolVar(&debug, "debug", false, "Enable debug mode")
flag.Parse()
// Enable debugging if specified
if debug {
log.Println("Enable debug model")
go func() { log.Println(http.ListenAndServe("127.0.0.1:30080", nil)) }()
// Start CPU profiling
f, err := os.OpenFile("cpu.prof", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
log.Fatal(err)
}
defer f.Close()
if err := pprof.StartCPUProfile(f); err != nil {
log.Fatal(err)
}
defer pprof.StopCPUProfile()
// Write heap profile
f, err = os.OpenFile("mem.prof", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
log.Fatal(err)
}
defer f.Close()
runtime.GC() // get up-to-date statistics
if err := pprof.WriteHeapProfile(f); err != nil {
log.Fatal(err)
}
}
// Initialize concurrent request limiter
concurrent = make(chan struct{}, num)
for i := 0; i < num; i++ {
concurrent <- struct{}{}
}
ips = make(chan string, num)
// Validate required parameters
if ip == "" && file == "" {
fmt.Println("Please specify the IP address or provide a file containing IP addresses.")
fmt.Println("Usage: go run main.go -ip <IP> -port <Port> -file <FileName> -num <Number> -host <HostName>")
return
}
if host == "" {
fmt.Println("Please specify the target domain name.")
fmt.Println("Usage: go run main.go -ip <IP> -port <Port> -file <FileName> -num <Number> -host <HostName>")
return
}
// Construct request headers
headers = http.Header{
"Cache-Control": {"no-cache"},
"Pragma": {"no-cache"},
"Accept-Encoding": {"gzip, deflate, br"},
"Accept-Language": {"zh-CN;q=0.9,zh;"},
"User-Agent": {"Mozilla/5.0 (Windows NT 10.0; Wine; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/115.0.1901.183"},
"Sec-WebSocket-Extensions": {"permessage-deflate; client_max_window_bits"},
"Sec-WebSocket-Version": {"13"},
"Connection": {"Upgrade"},
"Upgrade": {"websocket"},
"Host": {host},
}
key, err := generateKey()
if err != nil {
log.Fatalln("Failed to generate key:", err)
}
headers.Set("Sec-WebSocket-Key", key)
var wg sync.WaitGroup // Wait group for concurrent requests
// executable task
go func() {
for {
addr := <-ips
wg.Add(1)
go func(addr string) {
defer func() {
concurrent <- struct{}{}
}()
defer wg.Done()
sendRequest(addr)
}(addr)
}
}()
if file != "" {
// wait for scan done
wg.Add(1)
f, err := os.Open(file)
if err != nil {
// Skip file if error
goto check_ip
}
defer f.Close()
scanner := bufio.NewScanner(f)
var ip string
for scanner.Scan() {
ip = strings.TrimSpace(scanner.Text())
if ip != "" {
err := readIPsFromString(ip)
if err != nil {
continue
}
}
ip = ""
runtime.GC()
}
// scan done
wg.Done()
}
check_ip:
if ip != "" {
wg.Add(1)
go func() {
defer wg.Done()
sendRequest(ip)
}()
}
wg.Wait() // Wait for all requests to complete
fmt.Println("All requests completed.")
}
// Generate HTTP client with customized transport
func generateClient(host, ip, port string) http.Client {
// Set timeouts
dialer := &net.Dialer{
Timeout: 10 * time.Second,
KeepAlive: 10 * time.Second,
DualStack: true,
}
transport := &http.Transport{
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
if addr == host+":"+port {
addr = ip + ":" + port // Override host with target IP
}
return dialer.DialContext(ctx, network, addr)
},
MaxIdleConns: 100,
IdleConnTimeout: 10 * time.Second,
TLSHandshakeTimeout: 5 * time.Second,
ExpectContinueTimeout: 3 * time.Second,
}
client := &http.Client{
Transport: transport,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
// Inherit headers from last request
req.Header = via[len(via)-1].Header
return nil
},
}
return *client
}
// Generate random key for WebSocket handshake
func generateKey() (string, error) {
key := make([]byte, 16)
_, err := rand.Read(key)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(key), nil
}
// Parse IP address strings
func readIPsFromString(ip string) error {
if strings.Contains(ip, "/") {
err := expandCIDR(ip)
if err != nil {
return err
}
} else if isValidIP(ip) {
// Limit concurrency
<-concurrent
ips <- ip
} else {
return errors.New("Invalid IP address")
}
return nil
}
// Validate IP address
func isValidIP(ip string) bool {
myIP := net.ParseIP(ip)
return myIP != nil
}
// Expand CIDR to list of IPs
func expandCIDR(cidr string) error {
ip, ipnet, err := net.ParseCIDR(cidr)
if err != nil {
return err
}
for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); inc(ip) {
<-concurrent
ips <- ip.String()
}
return nil
}
// Increment IP address
func inc(ip net.IP) {
for j := len(ip) - 1; j >= 0; j-- {
ip[j]++
if ip[j] > 0 {
break
}
}
}
// Send WebSocket handshake request
func sendRequest(ip string) {
req, _ := http.NewRequest("GET", "https://"+host+":"+port, nil)
req.Header = headers
client := generateClient(host, ip, port)
resp, err := client.Do(req)
if err != nil {
return
}
if resp.StatusCode == http.StatusSwitchingProtocols {
fmt.Println(ip) // Print IP if handshake successful
}
_ = resp.Body.Close()
}
log.Println("Enable debug model")
go func() { log.Println(http.ListenAndServe("127.0.0.1:30080", nil)) }()
// Start CPU profiling
f, err := os.OpenFile("cpu.prof", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
log.Fatal(err)
}
defer f.Close()
if err := pprof.StartCPUProfile(f); err != nil {
log.Fatal(err)
}
defer pprof.StopCPUProfile()
// Write heap profile
f, err = os.OpenFile("mem.prof", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
log.Fatal(err)
}
defer f.Close()
runtime.GC() // get up-to-date statistics
if err := pprof.WriteHeapProfile(f); err != nil {
log.Fatal(err)
}
}
// Initialize concurrent request limiter
concurrent = make(chan struct{}, num)
for i := 0; i < num; i++ {
concurrent <- struct{}{}
}
ips = make(chan string, num)
// Validate required parameters
if ip == "" && file == "" {
fmt.Println("Please specify the IP address or provide a file containing IP addresses.")
fmt.Println("Usage: go run main.go -ip <IP> -port <Port> -file <FileName> -num <Number> -host <HostName>")
return
}
if host == "" {
fmt.Println("Please specify the target domain name.")
fmt.Println("Usage: go run main.go -ip <IP> -port <Port> -file <FileName> -num <Number> -host <HostName>")
return
}
// Construct request headers
headers = http.Header{
"Cache-Control": {"no-cache"},
"Pragma": {"no-cache"},
"Accept-Encoding": {"gzip, deflate, br"},
"Accept-Language": {"zh-CN;q=0.9,zh;"},
"User-Agent": {"Mozilla/5.0 (Windows NT 10.0; Wine; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/115.0.1901.183"},
"Sec-WebSocket-Extensions": {"permessage-deflate; client_max_window_bits"},
"Sec-WebSocket-Version": {"13"},
"Connection": {"Upgrade"},
"Upgrade": {"websocket"},
"Host": {host},
}
key, err := generateKey()
if err != nil {
log.Fatalln("Failed to generate key:", err)
}
headers.Set("Sec-WebSocket-Key", key)
var wg sync.WaitGroup // Wait group for concurrent requests
// executable task
go func() {
for {
addr := <-ips
wg.Add(1)
go func(addr string) {
defer func() {
concurrent <- struct{}{}
}()
defer wg.Done()
sendRequest(addr)
}(addr)
}
}()
if file != "" {
// wait for scan done
wg.Add(1)
f, err := os.Open(file)
if err != nil {
// Skip file if error
goto check_ip
}
defer f.Close()
scanner := bufio.NewScanner(f)
var ip string
for scanner.Scan() {
ip = strings.TrimSpace(scanner.Text())
if ip != "" {
err := readIPsFromString(ip)
if err != nil {
continue
}
}
ip = ""
runtime.GC()
}
// scan done
wg.Done()
}
check_ip:
if ip != "" {
wg.Add(1)
go func() {
defer wg.Done()
sendRequest(ip)
}()
}
wg.Wait() // Wait for all requests to complete
fmt.Println("All requests completed.")
}
// Generate HTTP client with customized transport
func generateClient(host, ip, port string) http.Client {
// Set timeouts
dialer := &net.Dialer{
Timeout: 10 * time.Second,
KeepAlive: 10 * time.Second,
DualStack: true,
}
transport := &http.Transport{
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
if addr == host+":"+port {
addr = ip + ":" + port // Override host with target IP
}
return dialer.DialContext(ctx, network, addr)
},
MaxIdleConns: 100,
IdleConnTimeout: 10 * time.Second,
TLSHandshakeTimeout: 5 * time.Second,
ExpectContinueTimeout: 3 * time.Second,
}
client := &http.Client{
Transport: transport,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
// Inherit headers from last request
req.Header = via[len(via)-1].Header
return nil
},
}
return *client
}
// Generate random key for WebSocket handshake
func generateKey() (string, error) {
key := make([]byte, 16)
_, err := rand.Read(key)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(key), nil
}
// Parse IP address strings
func readIPsFromString(ip string) error {
if strings.Contains(ip, "/") {
err := expandCIDR(ip)
if err != nil {
return err
}
} else if isValidIP(ip) {
// Limit concurrency
<-concurrent
ips <- ip
} else {
return errors.New("Invalid IP address")
}
return nil
}
// Validate IP address
func isValidIP(ip string) bool {
myIP := net.ParseIP(ip)
return myIP != nil
}
// Expand CIDR to list of IPs
func expandCIDR(cidr string) error {
ip, ipnet, err := net.ParseCIDR(cidr)
if err != nil {
return err
}
for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); inc(ip) {
<-concurrent
ips <- ip.String()
}
return nil
}
// Increment IP address
func inc(ip net.IP) {
for j := len(ip) - 1; j >= 0; j-- {
ip[j]++
if ip[j] > 0 {
break
}
}
}
// Send WebSocket handshake request
func sendRequest(ip string) {
req, _ := http.NewRequest("GET", "https://"+host+":"+port, nil)
req.Header = headers
client := generateClient(host, ip, port)
resp, err := client.Do(req)
if err != nil {
return
}
if resp.StatusCode == http.StatusSwitchingProtocols {
fmt.Println(ip) // Print IP if handshake successful
}
_ = resp.Body.Close()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment