mirror of
https://github.com/shadow1ng/fscan.git
synced 2026-09-22 03:10:42 +08:00
tighten scan session and HTTP paths
This commit is contained in:
+7
-7
@@ -504,7 +504,7 @@ func scanSinglePort(ctx context.Context, host string, port int, addr string, ada
|
||||
serviceInfo, _ := scanner.SmartIdentify()
|
||||
|
||||
// 步骤4:处理结果
|
||||
processServiceResult(host, port, addr, serviceInfo, config, session)
|
||||
processServiceResult(ctx, host, port, addr, serviceInfo, config, session)
|
||||
}
|
||||
|
||||
// handleConnectionFailure 处理连接失败
|
||||
@@ -651,10 +651,10 @@ func saveOpenPort(session *common.ScanSession, host string, port int) {
|
||||
}
|
||||
|
||||
// processServiceResult 处理服务识别结果
|
||||
func processServiceResult(host string, port int, addr string, serviceInfo *ServiceInfo, config *common.Config, session *common.ScanSession) {
|
||||
func processServiceResult(ctx context.Context, host string, port int, addr string, serviceInfo *ServiceInfo, config *common.Config, session *common.ScanSession) {
|
||||
if serviceInfo == nil {
|
||||
// 服务识别失败,尝试 HTTP 回退探测
|
||||
if !tryHTTPFallbackDetection(host, port, addr, config, session) {
|
||||
if !tryHTTPFallbackDetection(ctx, host, port, addr, config, session) {
|
||||
session.LogInfo(i18n.Tr("port_open", addr))
|
||||
}
|
||||
return
|
||||
@@ -714,10 +714,10 @@ func buildServiceDetails(port int, info *ServiceInfo) map[string]interface{} {
|
||||
}
|
||||
|
||||
// tryHTTPFallbackDetection 尝试HTTP回退探测,返回是否成功识别为HTTP服务
|
||||
func tryHTTPFallbackDetection(host string, port int, addr string, config *common.Config, session *common.ScanSession) bool {
|
||||
func tryHTTPFallbackDetection(ctx context.Context, host string, port int, addr string, config *common.Config, session *common.ScanSession) bool {
|
||||
// 使用WebDetection进行HTTP协议探测
|
||||
webDetector := GetWebPortDetector()
|
||||
if !webDetector.DetectHTTPServiceOnly(host, port, config, session) {
|
||||
if !webDetector.DetectHTTPServiceOnlyContext(ctx, host, port, config, session) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -806,7 +806,7 @@ func probeSubnets(ctx context.Context, hosts []string, timeout time.Duration, se
|
||||
limiter <- struct{}{}
|
||||
go func(pfx, addr string) {
|
||||
defer func() { <-limiter; wg.Done() }()
|
||||
conn, err := net.DialTimeout("tcp", addr, subnetProbeTimeout)
|
||||
conn, err := session.DialTCP(ctx, "tcp", addr, subnetProbeTimeout)
|
||||
if err == nil {
|
||||
_ = conn.Close()
|
||||
aliveSubnets.Store(pfx, true)
|
||||
@@ -844,7 +844,7 @@ func probeSubnets(ctx context.Context, hosts []string, timeout time.Duration, se
|
||||
|
||||
go func(pfx, h string, p int) {
|
||||
defer func() { <-limiter; wg.Done() }()
|
||||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", h, p), subnetProbeTimeout)
|
||||
conn, err := session.DialTCP(ctx, "tcp", fmt.Sprintf("%s:%d", h, p), subnetProbeTimeout)
|
||||
if err == nil {
|
||||
_ = conn.Close()
|
||||
aliveSubnets.Store(pfx, true)
|
||||
|
||||
+23
-9
@@ -28,8 +28,12 @@ func GetWebPortDetector() *WebPortDetector {
|
||||
// 策略:TLS握手优先(快速且准确),失败后尝试GM TLS,最后HTTP
|
||||
// 返回: "https", "https-gm", "http", 或 "" (都不是Web服务)
|
||||
func DetectHTTPScheme(host string, port int, config *common.Config, session *common.ScanSession) string {
|
||||
return DetectHTTPSchemeContext(context.Background(), host, port, config, session)
|
||||
}
|
||||
|
||||
func DetectHTTPSchemeContext(ctx context.Context, host string, port int, config *common.Config, session *common.ScanSession) string {
|
||||
// 优化:先快速检测 TCP 连通性
|
||||
if !isPortReachable(host, port, config, session) {
|
||||
if !isPortReachable(ctx, host, port, config, session) {
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -72,7 +76,13 @@ func DetectHTTPScheme(host string, port int, config *common.Config, session *com
|
||||
|
||||
// 使用HEAD请求(更轻量)
|
||||
httpURL := fmt.Sprintf("http://%s", addr)
|
||||
resp, err := client.Head(httpURL)
|
||||
req, err := http.NewRequestWithContext(ctx, "HEAD", httpURL, nil)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
|
||||
req.Header.Set("Accept", "*/*")
|
||||
resp, err := session.HTTPDo(client, req)
|
||||
if err == nil {
|
||||
_ = resp.Body.Close()
|
||||
return "http"
|
||||
@@ -127,21 +137,25 @@ func createHTTPClient(config *common.Config, session *common.ScanSession) *http.
|
||||
|
||||
// DetectHTTPServiceOnly HTTP协议检测 - 保持API兼容,简化实现
|
||||
func (w *WebPortDetector) DetectHTTPServiceOnly(host string, port int, config *common.Config, session *common.ScanSession) bool {
|
||||
return w.DetectHTTPServiceOnlyContext(context.Background(), host, port, config, session)
|
||||
}
|
||||
|
||||
func (w *WebPortDetector) DetectHTTPServiceOnlyContext(ctx context.Context, host string, port int, config *common.Config, session *common.ScanSession) bool {
|
||||
// 优化:先快速检测 TCP 连通性,避免在不可达端口上浪费双倍超时时间
|
||||
// 对于不存在的端口,这可以将检测时间从 2×timeout 减少到 1×timeout
|
||||
if !isPortReachable(host, port, config, session) {
|
||||
if !isPortReachable(ctx, host, port, config, session) {
|
||||
return false
|
||||
}
|
||||
|
||||
client := createHTTPClient(config, session)
|
||||
|
||||
// 尝试HTTP
|
||||
if w.tryHTTP(client, session, host, port, "http") {
|
||||
if w.tryHTTP(ctx, client, session, host, port, "http") {
|
||||
return true
|
||||
}
|
||||
|
||||
// 尝试HTTPS
|
||||
if w.tryHTTP(client, session, host, port, "https") {
|
||||
if w.tryHTTP(ctx, client, session, host, port, "https") {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -150,11 +164,11 @@ func (w *WebPortDetector) DetectHTTPServiceOnly(host string, port int, config *c
|
||||
|
||||
// isPortReachable 快速检测端口是否可达(TCP 连接测试)
|
||||
// 用于在 HTTP/HTTPS 检测前过滤不可达端口,避免双重超时
|
||||
func isPortReachable(host string, port int, config *common.Config, session *common.ScanSession) bool {
|
||||
func isPortReachable(ctx context.Context, host string, port int, config *common.Config, session *common.ScanSession) bool {
|
||||
timeout := config.Network.WebTimeout
|
||||
addr := net.JoinHostPort(host, strconv.Itoa(port))
|
||||
|
||||
conn, err := session.DialTCP(context.Background(), "tcp", addr, timeout)
|
||||
conn, err := session.DialTCP(ctx, "tcp", addr, timeout)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@@ -163,7 +177,7 @@ func isPortReachable(host string, port int, config *common.Config, session *comm
|
||||
}
|
||||
|
||||
// tryHTTP 尝试HTTP请求 - 简化的核心逻辑
|
||||
func (w *WebPortDetector) tryHTTP(client *http.Client, session *common.ScanSession, host string, port int, protocol string) bool {
|
||||
func (w *WebPortDetector) tryHTTP(ctx context.Context, client *http.Client, session *common.ScanSession, host string, port int, protocol string) bool {
|
||||
// 构造URL
|
||||
var url string
|
||||
if (port == 80 && protocol == "http") || (port == 443 && protocol == "https") {
|
||||
@@ -173,7 +187,7 @@ func (w *WebPortDetector) tryHTTP(client *http.Client, session *common.ScanSessi
|
||||
}
|
||||
|
||||
// 发送HEAD请求
|
||||
req, err := http.NewRequest("HEAD", url, nil)
|
||||
req, err := http.NewRequestWithContext(ctx, "HEAD", url, nil)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
@@ -32,6 +33,26 @@ web_scanner_test.go - WebScanner核心逻辑测试
|
||||
缓存操作需要验证并发安全性。"
|
||||
*/
|
||||
|
||||
func TestDetectHTTPServiceOnlyContextHonorsCancellation(t *testing.T) {
|
||||
cfg := common.GetGlobalConfig()
|
||||
oldTimeout := cfg.Network.WebTimeout
|
||||
cfg.Network.WebTimeout = 2 * time.Second
|
||||
defer func() { cfg.Network.WebTimeout = oldTimeout }()
|
||||
|
||||
session := common.NewScanSession(cfg, common.NewState(), common.GetFlagVars())
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
start := time.Now()
|
||||
detected := GetWebPortDetector().DetectHTTPServiceOnlyContext(ctx, "203.0.113.1", 80, cfg, session)
|
||||
if detected {
|
||||
t.Fatal("canceled web detection should not report a service")
|
||||
}
|
||||
if elapsed := time.Since(start); elapsed > 200*time.Millisecond {
|
||||
t.Fatalf("canceled web detection took %s", elapsed)
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 核心逻辑测试:Web服务识别
|
||||
// =============================================================================
|
||||
|
||||
Reference in New Issue
Block a user