github.com/chainreactors/fingers@v1.2.1/common/sender.go (about)

     1  //go:build !tinygo
     2  // +build !tinygo
     3  
     4  package common
     5  
     6  import (
     7  	"crypto/tls"
     8  	"fmt"
     9  	"net"
    10  	"net/http"
    11  	"strconv"
    12  	"strings"
    13  	"time"
    14  )
    15  
    16  // Service指纹检测的Sender抽象
    17  type ServiceSender interface {
    18  	Send(host string, portStr string, data []byte, network string) ([]byte, error)
    19  }
    20  
    21  // DefaultServiceSender 默认的ServiceSender实现
    22  type DefaultServiceSender struct {
    23  	timeout time.Duration
    24  }
    25  
    26  // NewServiceSender 创建默认的ServiceSender
    27  func NewServiceSender(timeout time.Duration) ServiceSender {
    28  	if timeout <= 0 {
    29  		timeout = 5 * time.Second // 默认5秒超时
    30  	}
    31  	return &DefaultServiceSender{
    32  		timeout: timeout,
    33  	}
    34  }
    35  
    36  // Send 实现ServiceSender接口,支持TCP、UDP、TLS协议
    37  func (d *DefaultServiceSender) Send(host string, portStr string, data []byte, network string) ([]byte, error) {
    38  	// 解析端口字符串
    39  	port, actualNetwork := d.parsePortString(portStr, network)
    40  	target := fmt.Sprintf("%s:%d", host, port)
    41  
    42  	// 使用解析后的网络协议类型
    43  	switch strings.ToLower(actualNetwork) {
    44  	case "tls", "ssl":
    45  		return d.sendTLS(target, data)
    46  	case "udp":
    47  		return d.sendUDP(target, data)
    48  	case "tcp", "":
    49  		return d.sendTCP(target, data)
    50  	default:
    51  		return d.sendTCP(target, data)
    52  	}
    53  }
    54  
    55  // sendTCP 发送TCP数据
    56  func (d *DefaultServiceSender) sendTCP(target string, data []byte) ([]byte, error) {
    57  	conn, err := net.DialTimeout("tcp", target, d.timeout)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  	defer conn.Close()
    62  
    63  	// 发送数据
    64  	if len(data) > 0 {
    65  		// 设置写超时
    66  		conn.SetWriteDeadline(time.Now().Add(d.timeout))
    67  		_, err = conn.Write(data)
    68  		if err != nil {
    69  			return nil, err
    70  		}
    71  	}
    72  
    73  	// 使用完整的timeout时间,不再强制限制
    74  	readTimeout := d.timeout
    75  	conn.SetReadDeadline(time.Now().Add(readTimeout))
    76  
    77  	// 读取响应 - 改进错误处理,即使连接被关闭也要返回已读取的数据
    78  	buffer := make([]byte, 10240)
    79  	n, err := conn.Read(buffer)
    80  
    81  	// 即使有错误,只要读取到了数据就返回数据
    82  	// 这对于SMB/RDP等协议很重要,它们可能在发送响应后立即关闭连接
    83  	if n > 0 {
    84  		return buffer[:n], nil
    85  	}
    86  
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  
    91  	return buffer[:n], nil
    92  }
    93  
    94  // sendTLS 发送TLS数据
    95  func (d *DefaultServiceSender) sendTLS(target string, data []byte) ([]byte, error) {
    96  	conn, err := tls.DialWithDialer(&net.Dialer{
    97  		Timeout: d.timeout,
    98  	}, "tcp", target, &tls.Config{
    99  		InsecureSkipVerify: true,
   100  	})
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  	defer conn.Close()
   105  
   106  	// 发送数据
   107  	if len(data) > 0 {
   108  		// 设置写超时
   109  		conn.SetWriteDeadline(time.Now().Add(d.timeout))
   110  		_, err = conn.Write(data)
   111  		if err != nil {
   112  			return nil, err
   113  		}
   114  	}
   115  
   116  	// 使用完整的timeout时间,不再强制限制
   117  	readTimeout := d.timeout
   118  	conn.SetReadDeadline(time.Now().Add(readTimeout))
   119  
   120  	// 读取响应 - 改进错误处理,即使连接被关闭也要返回已读取的数据
   121  	buffer := make([]byte, 10240)
   122  	n, err := conn.Read(buffer)
   123  
   124  	// 即使有错误,只要读取到了数据就返回数据
   125  	// 这对于SMB/RDP等协议很重要,它们可能在发送响应后立即关闭连接
   126  	if n > 0 {
   127  		return buffer[:n], nil
   128  	}
   129  
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  
   134  	return buffer[:n], nil
   135  }
   136  
   137  // sendUDP 发送UDP数据
   138  func (d *DefaultServiceSender) sendUDP(target string, data []byte) ([]byte, error) {
   139  	conn, err := net.DialTimeout("udp", target, d.timeout)
   140  	if err != nil {
   141  		return nil, err
   142  	}
   143  	defer conn.Close()
   144  
   145  	// 发送数据
   146  	if len(data) > 0 {
   147  		// 设置写超时
   148  		conn.SetWriteDeadline(time.Now().Add(d.timeout))
   149  		_, err = conn.Write(data)
   150  		if err != nil {
   151  			return nil, err
   152  		}
   153  	}
   154  
   155  	// UDP通常响应更快,设置更短的读超时
   156  	readTimeout := d.timeout
   157  	if readTimeout > 200*time.Millisecond {
   158  		readTimeout = 200 * time.Millisecond // UDP最多等待200ms
   159  	}
   160  	conn.SetReadDeadline(time.Now().Add(readTimeout))
   161  
   162  	// 读取响应 - 改进错误处理,即使连接被关闭也要返回已读取的数据
   163  	buffer := make([]byte, 10240)
   164  	n, err := conn.Read(buffer)
   165  
   166  	// 即使有错误,只要读取到了数据就返回数据
   167  	if n > 0 {
   168  		return buffer[:n], nil
   169  	}
   170  
   171  	if err != nil {
   172  		return nil, err
   173  	}
   174  
   175  	return buffer[:n], nil
   176  }
   177  
   178  // parsePortString 解析端口字符串,支持UDP前缀 (U:137)
   179  func (d *DefaultServiceSender) parsePortString(portStr string, defaultNetwork string) (port int, network string) {
   180  	portStr = strings.TrimSpace(portStr)
   181  	network = defaultNetwork // 默认使用传入的网络类型
   182  
   183  	// 检查UDP标记 (U:139)
   184  	if strings.HasPrefix(strings.ToUpper(portStr), "U:") {
   185  		portStr = portStr[2:] // 移除"U:"前缀
   186  		network = "udp"       // 强制使用UDP
   187  	}
   188  
   189  	// 解析端口号
   190  	portNum, err := strconv.Atoi(portStr)
   191  	if err != nil {
   192  		// 如果解析失败,返回默认端口80
   193  		return 80, network
   194  	}
   195  
   196  	return portNum, network
   197  }
   198  
   199  // Service指纹检测的回调函数
   200  type ServiceCallback func(*ServiceResult)
   201  
   202  // DefaultHTTPSender 默认的 HTTP RoundTripper 实现
   203  // 提供标准的 HTTP 请求发送能力,支持超时和 TLS 配置
   204  type DefaultHTTPSender struct {
   205  	client *http.Client
   206  }
   207  
   208  // NewHTTPSender 创建默认的 HTTP Sender (http.RoundTripper)
   209  // timeout: 请求超时时间
   210  // 默认跳过 TLS 证书验证(insecureSkipVerify = true)
   211  func NewHTTPSender(timeout time.Duration) http.RoundTripper {
   212  	if timeout <= 0 {
   213  		timeout = 10 * time.Second // 默认10秒超时
   214  	}
   215  
   216  	transport := &http.Transport{
   217  		TLSClientConfig: &tls.Config{
   218  			InsecureSkipVerify: true, // 默认跳过证书验证
   219  		},
   220  		DialContext: (&net.Dialer{
   221  			Timeout:   timeout,
   222  			KeepAlive: 30 * time.Second,
   223  		}).DialContext,
   224  		MaxIdleConns:          100,
   225  		IdleConnTimeout:       90 * time.Second,
   226  		TLSHandshakeTimeout:   timeout,
   227  		ExpectContinueTimeout: 1 * time.Second,
   228  	}
   229  
   230  	return &DefaultHTTPSender{
   231  		client: &http.Client{
   232  			Transport: transport,
   233  			Timeout:   timeout,
   234  			CheckRedirect: func(req *http.Request, via []*http.Request) error {
   235  				// 默认不跟随重定向,让调用者自己处理
   236  				return http.ErrUseLastResponse
   237  			},
   238  		},
   239  	}
   240  }
   241  
   242  // RoundTrip 实现 http.RoundTripper 接口
   243  func (d *DefaultHTTPSender) RoundTrip(req *http.Request) (*http.Response, error) {
   244  	return d.client.Transport.RoundTrip(req)
   245  }