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 }