mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 14:06:44 +08:00
feat: tcp端口扫描支持socks5 (#527)
* feat: tcp端口扫描支持socks5 * feat: PG插件支持socks5 * feat: 完成大部分插件的socks5支持
This commit is contained in:
parent
9b38dc0006
commit
a66de1bff0
115
Common/Proxy.go
115
Common/Proxy.go
@ -1,13 +1,16 @@
|
|||||||
package Common
|
package Common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"golang.org/x/net/proxy"
|
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/proxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WrapperTcpWithTimeout 创建一个带超时的TCP连接
|
// WrapperTcpWithTimeout 创建一个带超时的TCP连接
|
||||||
@ -16,6 +19,12 @@ func WrapperTcpWithTimeout(network, address string, timeout time.Duration) (net.
|
|||||||
return WrapperTCP(network, address, d)
|
return WrapperTCP(network, address, d)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WrapperTcpWithContext 创建一个带上下文的TCP连接
|
||||||
|
func WrapperTcpWithContext(ctx context.Context, network, address string) (net.Conn, error) {
|
||||||
|
d := &net.Dialer{}
|
||||||
|
return WrapperTCPWithContext(ctx, network, address, d)
|
||||||
|
}
|
||||||
|
|
||||||
// WrapperTCP 根据配置创建TCP连接
|
// WrapperTCP 根据配置创建TCP连接
|
||||||
func WrapperTCP(network, address string, forward *net.Dialer) (net.Conn, error) {
|
func WrapperTCP(network, address string, forward *net.Dialer) (net.Conn, error) {
|
||||||
// 直连模式
|
// 直连模式
|
||||||
@ -41,6 +50,54 @@ func WrapperTCP(network, address string, forward *net.Dialer) (net.Conn, error)
|
|||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WrapperTCPWithContext 根据配置创建支持上下文的TCP连接
|
||||||
|
func WrapperTCPWithContext(ctx context.Context, network, address string, forward *net.Dialer) (net.Conn, error) {
|
||||||
|
// 直连模式
|
||||||
|
if Socks5Proxy == "" {
|
||||||
|
conn, err := forward.DialContext(ctx, network, address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(GetText("tcp_conn_failed"), err)
|
||||||
|
}
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Socks5代理模式
|
||||||
|
dialer, err := Socks5Dialer(forward)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(GetText("socks5_create_failed"), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一个结果通道来处理连接和取消
|
||||||
|
connChan := make(chan struct {
|
||||||
|
conn net.Conn
|
||||||
|
err error
|
||||||
|
}, 1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
conn, err := dialer.Dial(network, address)
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
if conn != nil {
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
case connChan <- struct {
|
||||||
|
conn net.Conn
|
||||||
|
err error
|
||||||
|
}{conn, err}:
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil, ctx.Err()
|
||||||
|
case result := <-connChan:
|
||||||
|
if result.err != nil {
|
||||||
|
return nil, fmt.Errorf(GetText("socks5_conn_failed"), result.err)
|
||||||
|
}
|
||||||
|
return result.conn, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Socks5Dialer 创建Socks5代理拨号器
|
// Socks5Dialer 创建Socks5代理拨号器
|
||||||
func Socks5Dialer(forward *net.Dialer) (proxy.Dialer, error) {
|
func Socks5Dialer(forward *net.Dialer) (proxy.Dialer, error) {
|
||||||
// 解析代理URL
|
// 解析代理URL
|
||||||
@ -76,3 +133,59 @@ func Socks5Dialer(forward *net.Dialer) (proxy.Dialer, error) {
|
|||||||
|
|
||||||
return dialer, nil
|
return dialer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WrapperTlsWithContext 创建一个通过代理的TLS连接
|
||||||
|
func WrapperTlsWithContext(ctx context.Context, network, address string, tlsConfig *tls.Config) (net.Conn, error) {
|
||||||
|
// 直连模式
|
||||||
|
if Socks5Proxy == "" {
|
||||||
|
dialer := &net.Dialer{}
|
||||||
|
|
||||||
|
tcpConn, err := dialer.DialContext(ctx, network, address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("直连TCP连接失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在TCP连接上进行TLS握手
|
||||||
|
tlsConn := tls.Client(tcpConn, tlsConfig)
|
||||||
|
|
||||||
|
// 使用ctx的deadline设置TLS握手超时
|
||||||
|
if deadline, ok := ctx.Deadline(); ok {
|
||||||
|
tlsConn.SetDeadline(deadline)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tlsConn.Handshake(); err != nil {
|
||||||
|
tcpConn.Close()
|
||||||
|
return nil, fmt.Errorf("TLS握手失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除deadline,让上层代码自己管理超时
|
||||||
|
tlsConn.SetDeadline(time.Time{})
|
||||||
|
|
||||||
|
return tlsConn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Socks5代理模式
|
||||||
|
// 首先通过代理建立到目标的TCP连接
|
||||||
|
tcpConn, err := WrapperTcpWithContext(ctx, network, address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("通过代理建立TCP连接失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在TCP连接上进行TLS握手
|
||||||
|
tlsConn := tls.Client(tcpConn, tlsConfig)
|
||||||
|
|
||||||
|
// 使用ctx的deadline设置TLS握手超时
|
||||||
|
if deadline, ok := ctx.Deadline(); ok {
|
||||||
|
tlsConn.SetDeadline(deadline)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tlsConn.Handshake(); err != nil {
|
||||||
|
tcpConn.Close()
|
||||||
|
return nil, fmt.Errorf("TLS握手失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除deadline,让上层代码自己管理超时
|
||||||
|
tlsConn.SetDeadline(time.Time{})
|
||||||
|
|
||||||
|
return tlsConn, nil
|
||||||
|
}
|
||||||
|
@ -407,8 +407,8 @@ func (i *Info) Write(msg []byte) error {
|
|||||||
_, err := i.Conn.Write(msg)
|
_, err := i.Conn.Write(msg)
|
||||||
if err != nil && strings.Contains(err.Error(), "close") {
|
if err != nil && strings.Contains(err.Error(), "close") {
|
||||||
i.Conn.Close()
|
i.Conn.Close()
|
||||||
// 连接关闭时重试
|
// 连接关闭时重试 - 支持SOCKS5代理
|
||||||
i.Conn, err = net.DialTimeout("tcp4", fmt.Sprintf("%s:%d", i.Address, i.Port), time.Duration(6)*time.Second)
|
i.Conn, err = Common.WrapperTcpWithTimeout("tcp", fmt.Sprintf("%s:%d", i.Address, i.Port), time.Duration(6)*time.Second)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
i.Conn.SetWriteDeadline(time.Now().Add(time.Second * time.Duration(WrTimeout)))
|
i.Conn.SetWriteDeadline(time.Now().Add(time.Second * time.Duration(WrTimeout)))
|
||||||
_, err = i.Conn.Write(msg)
|
_, err = i.Conn.Write(msg)
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
"golang.org/x/sync/semaphore"
|
"golang.org/x/sync/semaphore"
|
||||||
"net"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@ -53,8 +52,8 @@ func EnhancedPortScan(hosts []string, ports string, timeout int64) []string {
|
|||||||
g.Go(func() error {
|
g.Go(func() error {
|
||||||
defer sem.Release(1)
|
defer sem.Release(1)
|
||||||
|
|
||||||
// 连接测试
|
// 连接测试 - 支持SOCKS5代理
|
||||||
conn, err := net.DialTimeout("tcp", addr, to)
|
conn, err := Common.WrapperTcpWithTimeout("tcp", addr, to)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,11 @@ package Plugins
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/Common"
|
|
||||||
"net"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/shadow1ng/fscan/Common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ActiveMQCredential 表示一个ActiveMQ凭据
|
// ActiveMQCredential 表示一个ActiveMQ凭据
|
||||||
@ -213,8 +213,7 @@ func ActiveMQConn(ctx context.Context, info *Common.HostInfo, user string, pass
|
|||||||
addr := fmt.Sprintf("%s:%v", info.Host, info.Ports)
|
addr := fmt.Sprintf("%s:%v", info.Host, info.Ports)
|
||||||
|
|
||||||
// 使用上下文创建带超时的连接
|
// 使用上下文创建带超时的连接
|
||||||
dialer := &net.Dialer{Timeout: time.Duration(Common.Timeout) * time.Second}
|
conn, err := Common.WrapperTcpWithTimeout("tcp", addr, time.Duration(Common.Timeout)*time.Second)
|
||||||
conn, err := dialer.DialContext(ctx, "tcp", addr)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,29 @@ package Plugins
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gocql/gocql"
|
"net"
|
||||||
"github.com/shadow1ng/fscan/Common"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gocql/gocql"
|
||||||
|
"github.com/shadow1ng/fscan/Common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// CassandraProxyDialer 实现gocql.Dialer接口,支持代理连接
|
||||||
|
type CassandraProxyDialer struct {
|
||||||
|
timeout time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *CassandraProxyDialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
host, port, err := net.SplitHostPort(addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return Common.WrapperTcpWithContext(ctx, network, fmt.Sprintf("%s:%s", host, port))
|
||||||
|
}
|
||||||
|
|
||||||
// CassandraCredential 表示一个Cassandra凭据
|
// CassandraCredential 表示一个Cassandra凭据
|
||||||
type CassandraCredential struct {
|
type CassandraCredential struct {
|
||||||
Username string
|
Username string
|
||||||
@ -223,6 +238,13 @@ func CassandraConn(ctx context.Context, info *Common.HostInfo, user string, pass
|
|||||||
cluster.ProtoVersion = 4
|
cluster.ProtoVersion = 4
|
||||||
cluster.Consistency = gocql.One
|
cluster.Consistency = gocql.One
|
||||||
|
|
||||||
|
// 如果配置了代理,设置自定义Dialer
|
||||||
|
if Common.Socks5Proxy != "" {
|
||||||
|
cluster.Dialer = &CassandraProxyDialer{
|
||||||
|
timeout: timeout,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if user != "" || pass != "" {
|
if user != "" || pass != "" {
|
||||||
cluster.Authenticator = gocql.PasswordAuthenticator{
|
cluster.Authenticator = gocql.PasswordAuthenticator{
|
||||||
Username: user,
|
Username: user,
|
||||||
|
@ -5,12 +5,13 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/Common"
|
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/shadow1ng/fscan/Common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IMAPCredential 表示一个IMAP凭据
|
// IMAPCredential 表示一个IMAP凭据
|
||||||
@ -211,8 +212,7 @@ func IMAPConn(ctx context.Context, info *Common.HostInfo, user string, pass stri
|
|||||||
// 在协程中尝试连接
|
// 在协程中尝试连接
|
||||||
go func() {
|
go func() {
|
||||||
// 先尝试普通连接
|
// 先尝试普通连接
|
||||||
dialer := &net.Dialer{Timeout: timeout}
|
conn, err := Common.WrapperTcpWithContext(ctx, "tcp", addr)
|
||||||
conn, err := dialer.DialContext(ctx, "tcp", addr)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
flag, authErr := tryIMAPAuth(conn, user, pass, timeout)
|
flag, authErr := tryIMAPAuth(conn, user, pass, timeout)
|
||||||
conn.Close()
|
conn.Close()
|
||||||
@ -232,14 +232,16 @@ func IMAPConn(ctx context.Context, info *Common.HostInfo, user string, pass stri
|
|||||||
tlsConfig := &tls.Config{
|
tlsConfig := &tls.Config{
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
}
|
}
|
||||||
tlsConn, tlsErr := tls.DialWithDialer(dialer, "tcp", addr, tlsConfig)
|
|
||||||
|
// 使用支持代理的TLS连接
|
||||||
|
tlsConn, tlsErr := Common.WrapperTlsWithContext(ctx, "tcp", addr, tlsConfig)
|
||||||
if tlsErr != nil {
|
if tlsErr != nil {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
case resultChan <- struct {
|
case resultChan <- struct {
|
||||||
success bool
|
success bool
|
||||||
err error
|
err error
|
||||||
}{false, fmt.Errorf("连接失败: %v", tlsErr)}:
|
}{false, fmt.Errorf("TLS连接失败: %v", tlsErr)}:
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,12 @@ package Plugins
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/go-ldap/ldap/v3"
|
|
||||||
"github.com/shadow1ng/fscan/Common"
|
|
||||||
"net"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-ldap/ldap/v3"
|
||||||
|
"github.com/shadow1ng/fscan/Common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LDAPCredential 表示一个LDAP凭据
|
// LDAPCredential 表示一个LDAP凭据
|
||||||
@ -210,13 +210,8 @@ func tryLDAPCredential(ctx context.Context, info *Common.HostInfo, credential LD
|
|||||||
func LDAPConn(ctx context.Context, info *Common.HostInfo, user string, pass string) (bool, error) {
|
func LDAPConn(ctx context.Context, info *Common.HostInfo, user string, pass string) (bool, error) {
|
||||||
address := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
address := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||||
|
|
||||||
// 创建拨号器并设置超时
|
|
||||||
dialer := &net.Dialer{
|
|
||||||
Timeout: time.Duration(Common.Timeout) * time.Second,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用上下文控制的拨号过程
|
// 使用上下文控制的拨号过程
|
||||||
conn, err := dialer.DialContext(ctx, "tcp", address)
|
conn, err := Common.WrapperTcpWithContext(ctx, "tcp", address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,25 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
_ "github.com/denisenkom/go-mssqldb"
|
"net"
|
||||||
"github.com/shadow1ng/fscan/Common"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
mssql "github.com/denisenkom/go-mssqldb"
|
||||||
|
"github.com/shadow1ng/fscan/Common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// MSSQLProxyDialer 自定义dialer结构体
|
||||||
|
type MSSQLProxyDialer struct {
|
||||||
|
timeout time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// DialContext 实现mssql.Dialer接口,支持socks代理
|
||||||
|
func (d *MSSQLProxyDialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
return Common.WrapperTcpWithContext(ctx, network, addr)
|
||||||
|
}
|
||||||
|
|
||||||
// MssqlCredential 表示一个MSSQL凭据
|
// MssqlCredential 表示一个MSSQL凭据
|
||||||
type MssqlCredential struct {
|
type MssqlCredential struct {
|
||||||
Username string
|
Username string
|
||||||
@ -205,7 +217,58 @@ func MssqlConn(ctx context.Context, info *Common.HostInfo, user string, pass str
|
|||||||
host, username, password, port,
|
host, username, password, port,
|
||||||
)
|
)
|
||||||
|
|
||||||
// 建立数据库连接
|
// 检查是否需要使用socks代理
|
||||||
|
if Common.Socks5Proxy != "" {
|
||||||
|
// 使用自定义dialer创建连接器
|
||||||
|
connector, err := mssql.NewConnector(connStr)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置自定义dialer
|
||||||
|
connector.Dialer = &MSSQLProxyDialer{
|
||||||
|
timeout: time.Duration(Common.Timeout) * time.Millisecond,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用连接器创建数据库连接
|
||||||
|
db := sql.OpenDB(connector)
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
// 设置连接参数
|
||||||
|
db.SetConnMaxLifetime(timeout)
|
||||||
|
db.SetConnMaxIdleTime(timeout)
|
||||||
|
db.SetMaxIdleConns(0)
|
||||||
|
db.SetMaxOpenConns(1)
|
||||||
|
|
||||||
|
// 通过上下文执行ping操作,以支持超时控制
|
||||||
|
pingCtx, pingCancel := context.WithTimeout(ctx, timeout)
|
||||||
|
defer pingCancel()
|
||||||
|
|
||||||
|
errChan := make(chan error, 1)
|
||||||
|
go func() {
|
||||||
|
errChan <- db.PingContext(pingCtx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 等待ping结果或者超时
|
||||||
|
select {
|
||||||
|
case err := <-errChan:
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
case <-ctx.Done():
|
||||||
|
// 全局超时或取消
|
||||||
|
return false, ctx.Err()
|
||||||
|
case <-pingCtx.Done():
|
||||||
|
if pingCtx.Err() == context.DeadlineExceeded {
|
||||||
|
// 单个连接超时
|
||||||
|
return false, fmt.Errorf("连接超时")
|
||||||
|
}
|
||||||
|
return false, pingCtx.Err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用标准连接方式
|
||||||
db, err := sql.Open("mssql", connStr)
|
db, err := sql.Open("mssql", connStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
|
@ -4,9 +4,9 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/Common"
|
|
||||||
"net"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/shadow1ng/fscan/Common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ModbusScanResult 表示 Modbus 扫描结果
|
// ModbusScanResult 表示 Modbus 扫描结果
|
||||||
@ -77,8 +77,7 @@ func tryModbusScan(ctx context.Context, info *Common.HostInfo, timeoutSeconds in
|
|||||||
// 在协程中执行扫描
|
// 在协程中执行扫描
|
||||||
go func() {
|
go func() {
|
||||||
// 尝试建立连接
|
// 尝试建立连接
|
||||||
var d net.Dialer
|
conn, err := Common.WrapperTcpWithContext(connCtx, "tcp", target)
|
||||||
conn, err := d.DialContext(connCtx, "tcp", target)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
select {
|
select {
|
||||||
case <-connCtx.Done():
|
case <-connCtx.Done():
|
||||||
|
@ -3,11 +3,11 @@ package Plugins
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/Common"
|
|
||||||
"io"
|
"io"
|
||||||
"net"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/shadow1ng/fscan/Common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MongodbScan 执行MongoDB未授权扫描
|
// MongodbScan 执行MongoDB未授权扫描
|
||||||
@ -112,13 +112,8 @@ func MongodbUnauth(ctx context.Context, info *Common.HostInfo) (bool, error) {
|
|||||||
func checkMongoAuth(ctx context.Context, address string, packet []byte) (string, error) {
|
func checkMongoAuth(ctx context.Context, address string, packet []byte) (string, error) {
|
||||||
Common.LogDebug(fmt.Sprintf("建立MongoDB连接: %s", address))
|
Common.LogDebug(fmt.Sprintf("建立MongoDB连接: %s", address))
|
||||||
|
|
||||||
// 创建连接超时上下文
|
|
||||||
connCtx, cancel := context.WithTimeout(ctx, time.Duration(Common.Timeout)*time.Second)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
// 使用带超时的连接
|
// 使用带超时的连接
|
||||||
var d net.Dialer
|
conn, err := Common.WrapperTcpWithTimeout("tcp", address, time.Duration(Common.Timeout)*time.Second)
|
||||||
conn, err := d.DialContext(connCtx, "tcp", address)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("连接失败: %v", err)
|
return "", fmt.Errorf("连接失败: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,38 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
_ "github.com/go-sql-driver/mysql"
|
"net"
|
||||||
"github.com/shadow1ng/fscan/Common"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-sql-driver/mysql"
|
||||||
|
"github.com/shadow1ng/fscan/Common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// MySQLProxyDialer 自定义dialer结构体
|
||||||
|
type MySQLProxyDialer struct {
|
||||||
|
timeout time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dial 实现mysql.Dialer接口,支持socks代理
|
||||||
|
func (d *MySQLProxyDialer) Dial(ctx context.Context, addr string) (net.Conn, error) {
|
||||||
|
return Common.WrapperTcpWithContext(ctx, "tcp", addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// registerMySQLDialer 注册MySQL自定义dialer
|
||||||
|
func registerMySQLDialer() {
|
||||||
|
// 创建自定义dialer
|
||||||
|
dialer := &MySQLProxyDialer{
|
||||||
|
timeout: time.Duration(Common.Timeout) * time.Millisecond,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册自定义dialer到go-sql-driver/mysql
|
||||||
|
mysql.RegisterDialContext("tcp-proxy", func(ctx context.Context, addr string) (net.Conn, error) {
|
||||||
|
return dialer.Dial(ctx, addr)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// MySQLCredential 表示一个MySQL凭据
|
// MySQLCredential 表示一个MySQL凭据
|
||||||
type MySQLCredential struct {
|
type MySQLCredential struct {
|
||||||
Username string
|
Username string
|
||||||
@ -204,11 +229,24 @@ func MysqlConn(ctx context.Context, info *Common.HostInfo, user string, pass str
|
|||||||
host, port, username, password := info.Host, info.Ports, user, pass
|
host, port, username, password := info.Host, info.Ports, user, pass
|
||||||
timeout := time.Duration(Common.Timeout) * time.Second
|
timeout := time.Duration(Common.Timeout) * time.Second
|
||||||
|
|
||||||
// 构造连接字符串,包含超时设置
|
// 检查是否需要使用socks代理
|
||||||
connStr := fmt.Sprintf(
|
var connStr string
|
||||||
|
if Common.Socks5Proxy != "" {
|
||||||
|
// 注册自定义dialer
|
||||||
|
registerMySQLDialer()
|
||||||
|
|
||||||
|
// 使用自定义网络类型的连接字符串
|
||||||
|
connStr = fmt.Sprintf(
|
||||||
|
"%v:%v@tcp-proxy(%v:%v)/mysql?charset=utf8&timeout=%v",
|
||||||
|
username, password, host, port, timeout,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// 标准连接字符串
|
||||||
|
connStr = fmt.Sprintf(
|
||||||
"%v:%v@tcp(%v:%v)/mysql?charset=utf8&timeout=%v",
|
"%v:%v@tcp(%v:%v)/mysql?charset=utf8&timeout=%v",
|
||||||
username, password, host, port, timeout,
|
username, password, host, port, timeout,
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// 创建结果通道
|
// 创建结果通道
|
||||||
resultChan := make(chan struct {
|
resultChan := make(chan struct {
|
||||||
|
@ -3,11 +3,12 @@ package Plugins
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/neo4j/neo4j-go-driver/v4/neo4j"
|
|
||||||
"github.com/shadow1ng/fscan/Common"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/neo4j/neo4j-go-driver/v4/neo4j"
|
||||||
|
"github.com/shadow1ng/fscan/Common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Neo4jCredential 表示一个Neo4j凭据
|
// Neo4jCredential 表示一个Neo4j凭据
|
||||||
@ -268,6 +269,9 @@ func Neo4jConn(info *Common.HostInfo, user string, pass string) (bool, error) {
|
|||||||
config := func(c *neo4j.Config) {
|
config := func(c *neo4j.Config) {
|
||||||
c.SocketConnectTimeout = timeout
|
c.SocketConnectTimeout = timeout
|
||||||
c.ConnectionAcquisitionTimeout = timeout
|
c.ConnectionAcquisitionTimeout = timeout
|
||||||
|
|
||||||
|
// 注意:Neo4j驱动可能不支持代理配置
|
||||||
|
// 如果需要代理支持,可能需要使用更底层的连接方式
|
||||||
}
|
}
|
||||||
|
|
||||||
var driver neo4j.Driver
|
var driver neo4j.Driver
|
||||||
|
@ -5,11 +5,12 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/Common"
|
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/shadow1ng/fscan/Common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// POP3Credential 表示一个POP3凭据
|
// POP3Credential 表示一个POP3凭据
|
||||||
@ -255,12 +256,7 @@ func POP3Conn(ctx context.Context, info *Common.HostInfo, user string, pass stri
|
|||||||
// 在协程中尝试连接,支持取消
|
// 在协程中尝试连接,支持取消
|
||||||
go func() {
|
go func() {
|
||||||
// 首先尝试普通连接
|
// 首先尝试普通连接
|
||||||
dialer := &net.Dialer{
|
conn, err := Common.WrapperTcpWithTimeout("tcp", addr, timeout)
|
||||||
Timeout: timeout,
|
|
||||||
// 增加KeepAlive设置,可能有助于处理一些服务器的限制
|
|
||||||
KeepAlive: 30 * time.Second,
|
|
||||||
}
|
|
||||||
conn, err := dialer.DialContext(ctx, "tcp", addr)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
flag, authErr := tryPOP3Auth(conn, user, pass, timeout)
|
flag, authErr := tryPOP3Auth(conn, user, pass, timeout)
|
||||||
conn.Close()
|
conn.Close()
|
||||||
@ -287,7 +283,10 @@ func POP3Conn(ctx context.Context, info *Common.HostInfo, user string, pass stri
|
|||||||
tlsConfig := &tls.Config{
|
tlsConfig := &tls.Config{
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
}
|
}
|
||||||
tlsConn, tlsErr := tls.DialWithDialer(dialer, "tcp", addr, tlsConfig)
|
// 对于TLS连接,暂时使用标准dialer
|
||||||
|
// TODO: 实现通过socks代理的TLS连接
|
||||||
|
tempDialer := &net.Dialer{Timeout: timeout}
|
||||||
|
tlsConn, tlsErr := tls.DialWithDialer(tempDialer, "tcp", addr, tlsConfig)
|
||||||
if tlsErr != nil {
|
if tlsErr != nil {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
|
@ -3,14 +3,32 @@ package Plugins
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"database/sql/driver"
|
||||||
"fmt"
|
"fmt"
|
||||||
_ "github.com/lib/pq"
|
"net"
|
||||||
"github.com/shadow1ng/fscan/Common"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/lib/pq"
|
||||||
|
"github.com/shadow1ng/fscan/Common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// PostgresProxyDialer 自定义dialer结构体
|
||||||
|
type PostgresProxyDialer struct {
|
||||||
|
timeout time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dial 实现pq.Dialer接口,支持socks代理
|
||||||
|
func (d *PostgresProxyDialer) Dial(network, address string) (net.Conn, error) {
|
||||||
|
return Common.WrapperTcpWithTimeout(network, address, d.timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DialTimeout 实现具有超时的连接
|
||||||
|
func (d *PostgresProxyDialer) DialTimeout(network, address string, timeout time.Duration) (net.Conn, error) {
|
||||||
|
return Common.WrapperTcpWithTimeout(network, address, timeout)
|
||||||
|
}
|
||||||
|
|
||||||
// PostgresCredential 表示一个PostgreSQL凭据
|
// PostgresCredential 表示一个PostgreSQL凭据
|
||||||
type PostgresCredential struct {
|
type PostgresCredential struct {
|
||||||
Username string
|
Username string
|
||||||
@ -202,7 +220,41 @@ func PostgresConn(ctx context.Context, info *Common.HostInfo, user string, pass
|
|||||||
user, pass, info.Host, info.Ports, Common.Timeout/1000, // 转换为秒
|
user, pass, info.Host, info.Ports, Common.Timeout/1000, // 转换为秒
|
||||||
)
|
)
|
||||||
|
|
||||||
// 建立数据库连接
|
// 检查是否需要使用socks代理
|
||||||
|
if Common.Socks5Proxy != "" {
|
||||||
|
// 使用自定义dialer通过socks代理连接
|
||||||
|
dialer := &PostgresProxyDialer{
|
||||||
|
timeout: time.Duration(Common.Timeout) * time.Millisecond,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用pq.DialOpen通过自定义dialer建立连接
|
||||||
|
conn, err := pq.DialOpen(dialer, connStr)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
// 转换为sql.DB进行测试
|
||||||
|
db := sql.OpenDB(&postgresConnector{conn: conn})
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
// 使用上下文测试连接
|
||||||
|
err = db.PingContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 简单查询测试权限
|
||||||
|
var version string
|
||||||
|
err = db.QueryRowContext(ctx, "SELECT version()").Scan(&version)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用标准连接方式
|
||||||
db, err := sql.Open("postgres", connStr)
|
db, err := sql.Open("postgres", connStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
@ -230,6 +282,19 @@ func PostgresConn(ctx context.Context, info *Common.HostInfo, user string, pass
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// postgresConnector 封装driver.Conn为sql.driver.Connector
|
||||||
|
type postgresConnector struct {
|
||||||
|
conn driver.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *postgresConnector) Connect(ctx context.Context) (driver.Conn, error) {
|
||||||
|
return c.conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *postgresConnector) Driver() driver.Driver {
|
||||||
|
return &pq.Driver{}
|
||||||
|
}
|
||||||
|
|
||||||
// savePostgresResult 保存PostgreSQL扫描结果
|
// savePostgresResult 保存PostgreSQL扫描结果
|
||||||
func savePostgresResult(info *Common.HostInfo, target string, credential PostgresCredential) {
|
func savePostgresResult(info *Common.HostInfo, target string, credential PostgresCredential) {
|
||||||
successMsg := fmt.Sprintf("PostgreSQL服务 %s 成功爆破 用户名: %v 密码: %v",
|
successMsg := fmt.Sprintf("PostgreSQL服务 %s 成功爆破 用户名: %v 密码: %v",
|
||||||
|
@ -3,11 +3,11 @@ package Plugins
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/Common"
|
|
||||||
"net"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/shadow1ng/fscan/Common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RsyncCredential 表示一个Rsync凭据
|
// RsyncCredential 表示一个Rsync凭据
|
||||||
@ -212,13 +212,8 @@ func RsyncConn(ctx context.Context, info *Common.HostInfo, user string, pass str
|
|||||||
host, port := info.Host, info.Ports
|
host, port := info.Host, info.Ports
|
||||||
timeout := time.Duration(Common.Timeout) * time.Second
|
timeout := time.Duration(Common.Timeout) * time.Second
|
||||||
|
|
||||||
// 设置带有上下文的拨号器
|
|
||||||
dialer := &net.Dialer{
|
|
||||||
Timeout: timeout,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 建立连接
|
// 建立连接
|
||||||
conn, err := dialer.DialContext(ctx, "tcp", fmt.Sprintf("%s:%s", host, port))
|
conn, err := Common.WrapperTcpWithTimeout("tcp", fmt.Sprintf("%s:%s", host, port), timeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, "", err
|
return false, "", err
|
||||||
}
|
}
|
||||||
@ -335,13 +330,11 @@ func RsyncConn(ctx context.Context, info *Common.HostInfo, user string, pass str
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 5. 为每个模块创建新连接尝试认证
|
// 5. 为每个模块创建新连接尝试认证
|
||||||
authConn, err := dialer.DialContext(ctx, "tcp", fmt.Sprintf("%s:%s", host, port))
|
authConn, err := Common.WrapperTcpWithTimeout(host, port, timeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
defer authConn.Close()
|
defer authConn.Close() // 重复初始握手
|
||||||
|
|
||||||
// 重复初始握手
|
|
||||||
authConn.SetReadDeadline(time.Now().Add(timeout))
|
authConn.SetReadDeadline(time.Now().Add(timeout))
|
||||||
_, err = authConn.Read(buffer)
|
_, err = authConn.Read(buffer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -3,13 +3,13 @@ package Plugins
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/Common"
|
|
||||||
"net"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/shadow1ng/fscan/Common"
|
||||||
|
|
||||||
"github.com/hirochachacha/go-smb2"
|
"github.com/hirochachacha/go-smb2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -316,9 +316,8 @@ func trySmb2Credential(ctx context.Context, info *Common.HostInfo, credential Sm
|
|||||||
|
|
||||||
// Smb2Con 尝试SMB2连接并进行认证,检查共享访问权限
|
// Smb2Con 尝试SMB2连接并进行认证,检查共享访问权限
|
||||||
func Smb2Con(ctx context.Context, info *Common.HostInfo, user string, pass string, hash []byte, hasprint bool) (flag bool, err error, shares []string) {
|
func Smb2Con(ctx context.Context, info *Common.HostInfo, user string, pass string, hash []byte, hasprint bool) (flag bool, err error, shares []string) {
|
||||||
// 建立TCP连接,使用上下文提供的超时控制
|
// 建立TCP连接,使用socks代理支持
|
||||||
var d net.Dialer
|
conn, err := Common.WrapperTcpWithTimeout("tcp", fmt.Sprintf("%s:445", info.Host), time.Duration(Common.Timeout)*time.Second)
|
||||||
conn, err := d.DialContext(ctx, "tcp", fmt.Sprintf("%s:445", info.Host))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, fmt.Errorf("连接失败: %v", err), nil
|
return false, fmt.Errorf("连接失败: %v", err), nil
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,12 @@ package Plugins
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/Common"
|
|
||||||
"net"
|
|
||||||
"net/smtp"
|
"net/smtp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/shadow1ng/fscan/Common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SmtpCredential 表示一个SMTP凭据
|
// SmtpCredential 表示一个SMTP凭据
|
||||||
@ -253,11 +253,7 @@ func SmtpConn(info *Common.HostInfo, user string, pass string, timeoutSeconds in
|
|||||||
addr := fmt.Sprintf("%s:%s", host, port)
|
addr := fmt.Sprintf("%s:%s", host, port)
|
||||||
|
|
||||||
// 设置连接超时
|
// 设置连接超时
|
||||||
dialer := &net.Dialer{
|
conn, err := Common.WrapperTcpWithTimeout("tcp", addr, timeout)
|
||||||
Timeout: timeout,
|
|
||||||
}
|
|
||||||
|
|
||||||
conn, err := dialer.Dial("tcp", addr)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,13 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/Common"
|
|
||||||
"net"
|
"net"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/shadow1ng/fscan/Common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TelnetCredential 表示一个Telnet凭据
|
// TelnetCredential 表示一个Telnet凭据
|
||||||
@ -248,9 +249,8 @@ func tryTelnetCredential(ctx context.Context, info *Common.HostInfo, credential
|
|||||||
|
|
||||||
// telnetConnWithContext 带上下文的Telnet连接尝试
|
// telnetConnWithContext 带上下文的Telnet连接尝试
|
||||||
func telnetConnWithContext(ctx context.Context, info *Common.HostInfo, user, pass string) (bool, error) {
|
func telnetConnWithContext(ctx context.Context, info *Common.HostInfo, user, pass string) (bool, error) {
|
||||||
// 创建TCP连接(使用上下文控制)
|
// 创建TCP连接(使用支持context的socks代理)
|
||||||
var d net.Dialer
|
conn, err := Common.WrapperTcpWithContext(ctx, "tcp", fmt.Sprintf("%s:%s", info.Host, info.Ports))
|
||||||
conn, err := d.DialContext(ctx, "tcp", fmt.Sprintf("%s:%s", info.Host, info.Ports))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,11 @@ package Plugins
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/mitchellh/go-vnc"
|
|
||||||
"github.com/shadow1ng/fscan/Common"
|
|
||||||
"net"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/mitchellh/go-vnc"
|
||||||
|
"github.com/shadow1ng/fscan/Common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// VncCredential 表示VNC凭据
|
// VncCredential 表示VNC凭据
|
||||||
@ -190,8 +190,7 @@ func VncConn(ctx context.Context, info *Common.HostInfo, pass string) (bool, err
|
|||||||
timeout := time.Duration(Common.Timeout) * time.Second
|
timeout := time.Duration(Common.Timeout) * time.Second
|
||||||
|
|
||||||
// 使用带上下文的TCP连接
|
// 使用带上下文的TCP连接
|
||||||
var d net.Dialer
|
conn, err := Common.WrapperTcpWithTimeout("tcp", fmt.Sprintf("%s:%s", Host, Port), timeout)
|
||||||
conn, err := d.DialContext(ctx, "tcp", fmt.Sprintf("%s:%s", Host, Port))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user