ProbeProxyBehavior 探测代理是否存在"全回显"问题 通过连接一个几乎肯定不可达的地址,并尝试发送数据来判断代理行为 返回 true 表示代理可靠,false 表示代理存在全回显问题 判断标准: - 连接失败 → 可靠(代理正确拒绝不可达目标) - 写入失败 → 可靠(代理在数据传输时报告错误) - 读取超时 → 可靠(代理转发了请求,目标没响应是正常的) - 读取错误 → 可靠(代理正确报告了目标不可达) - 收到数据 → 不可靠(代理伪造了响应)
(dialer Dialer, timeout time.Duration)
| 399 | // - 读取错误 → 可靠(代理正确报告了目标不可达) |
| 400 | // - 收到数据 → 不可靠(代理伪造了响应) |
| 401 | func ProbeProxyBehavior(dialer Dialer, timeout time.Duration) bool { |
| 402 | // 使用 RFC 5737 保留的测试 IP (TEST-NET-1) + 高端口 |
| 403 | // 192.0.2.1 是文档专用地址,保证不会路由到真实主机 |
| 404 | testAddr := "192.0.2.1:65533" |
| 405 | |
| 406 | ctx, cancel := context.WithTimeout(context.Background(), timeout) |
| 407 | defer cancel() |
| 408 | |
| 409 | conn, err := dialer.DialContext(ctx, "tcp", testAddr) |
| 410 | if err != nil { |
| 411 | // 连接失败 = 正常代理行为,代理可靠 |
| 412 | return true |
| 413 | } |
| 414 | defer conn.Close() |
| 415 | |
| 416 | // 连接"成功",进一步验证:尝试发送数据检查是否真的可达 |
| 417 | // 全回显代理会接受连接,但数据无法到达目标 |
| 418 | |
| 419 | // 设置短超时 |
| 420 | _ = conn.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)) |
| 421 | _, writeErr := conn.Write([]byte("PROBE\r\n")) |
| 422 | |
| 423 | if writeErr != nil { |
| 424 | // 写入失败 = 连接不可用,但这是预期的(目标不可达) |
| 425 | // 某些代理会在写入时才报告真实错误 |
| 426 | return true |
| 427 | } |
| 428 | |
| 429 | // 等待响应或错误 |
| 430 | _ = conn.SetReadDeadline(time.Now().Add(300 * time.Millisecond)) |
| 431 | buf := make([]byte, 64) |
| 432 | n, readErr := conn.Read(buf) |
| 433 | |
| 434 | if readErr != nil { |
| 435 | // 读取超时或错误 = 目标不可达,代理行为正常 |
| 436 | // 超时说明代理正确转发了请求,目标没有响应是正常的 |
| 437 | // 其他错误(reset, refused等)说明代理正确报告了目标不可达 |
| 438 | return true |
| 439 | } |
| 440 | |
| 441 | // 收到数据 = 代理伪造了响应,不可靠 |
| 442 | if n > 0 { |
| 443 | return false |
| 444 | } |
| 445 | |
| 446 | // 无错误且无数据 = EOF,说明连接被正常关闭,代理行为正常 |
| 447 | return true |
| 448 | } |
no test coverage detected