fix: harden address parsing edge cases

This commit is contained in:
ZacharyZcR
2026-06-01 04:03:46 +08:00
parent 8ec96bfe6d
commit 569d21a8bc
43 changed files with 273 additions and 137 deletions
+3 -2
View File
@@ -2,7 +2,8 @@ package common
import (
"errors"
"fmt"
"net"
"strconv"
"strings"
"sync"
@@ -30,7 +31,7 @@ type HostInfo struct {
// Target 返回 host:port 格式字符串
func (h *HostInfo) Target() string {
return fmt.Sprintf("%s:%d", h.Host, h.Port)
return net.JoinHostPort(h.Host, strconv.Itoa(h.Port))
}
// =============================================================================
+10
View File
@@ -0,0 +1,10 @@
package common
import "testing"
func TestHostInfoTargetUsesBracketedIPv6(t *testing.T) {
info := &HostInfo{Host: "2001:db8::1", Port: 443}
if got, want := info.Target(), "[2001:db8::1]:443"; got != want {
t.Fatalf("Target() = %q, want %q", got, want)
}
}
+2 -5
View File
@@ -1,9 +1,6 @@
package output
import (
"fmt"
"sync"
)
import "sync"
// ResultBuffer 公共的去重缓冲逻辑,供各Writer复用
type ResultBuffer struct {
@@ -103,7 +100,7 @@ func (b *ResultBuffer) generateKey(result *ScanResult) string {
case TypePort:
if result.Details != nil {
if port, ok := result.Details["port"]; ok {
return fmt.Sprintf("%s:%v", result.Target, port)
return targetWithPort(result.Target, port)
}
}
return result.Target
+21 -23
View File
@@ -5,6 +5,7 @@ import (
"encoding/csv"
"encoding/json"
"fmt"
"net"
"os"
"strings"
"sync"
@@ -37,6 +38,20 @@ func escapeControlChars(s string) string {
return b.String()
}
func targetWithPort(target string, port interface{}) string {
if port == nil {
return target
}
if _, _, err := net.SplitHostPort(target); err == nil {
return target
}
portText := fmt.Sprint(port)
if strings.Count(target, ":") == 1 {
return target
}
return net.JoinHostPort(target, portText)
}
// =============================================================================
// TXTWriter - 文本格式写入器
// =============================================================================
@@ -134,7 +149,7 @@ func (w *TXTWriter) formatLine(result *ScanResult) string {
case TypePort:
port := w.getDetail(result, "port")
if port != nil {
return fmt.Sprintf("%s:%v", result.Target, port)
return targetWithPort(result.Target, port)
}
return result.Target
case TypeService:
@@ -167,12 +182,7 @@ func (w *TXTWriter) formatServiceLine(result *ScanResult) string {
}
// 非Web服务:ip:port service banner
target := result.Target
if !strings.Contains(target, ":") {
if port := w.getDetail(result, "port"); port != nil {
target = fmt.Sprintf("%s:%v", target, port)
}
}
target := targetWithPort(result.Target, w.getDetail(result, "port"))
var parts []string
parts = append(parts, target)
@@ -191,12 +201,7 @@ func (w *TXTWriter) formatServiceLine(result *ScanResult) string {
// formatWebServiceLine 格式化Web服务结果
func (w *TXTWriter) formatWebServiceLine(result *ScanResult) string {
target := result.Target
if !strings.Contains(target, ":") {
if port := w.getDetail(result, "port"); port != nil {
target = fmt.Sprintf("%s:%v", target, port)
}
}
target := targetWithPort(result.Target, w.getDetail(result, "port"))
url := fmt.Sprintf("%s://%s", w.webProtocol(result, target), target)
title := w.getDetailStr(result, "title")
@@ -364,12 +369,7 @@ func (w *TXTWriter) writeWebServices() {
continue
}
target := result.Target
if !strings.Contains(target, ":") {
if port := w.getDetail(result, "port"); port != nil {
target = fmt.Sprintf("%s:%v", target, port)
}
}
target := targetWithPort(result.Target, w.getDetail(result, "port"))
urls = append(urls, fmt.Sprintf("%s://%s", w.webProtocol(result, target), target))
}
@@ -745,10 +745,8 @@ func (w *CSVWriter) formatServiceRecord(result *ScanResult) []string {
}
}
target := result.Target
if !strings.Contains(target, ":") {
if p, ok := result.Details["port"]; ok {
target = fmt.Sprintf("%s:%v", target, p)
}
if result.Details != nil {
target = targetWithPort(target, result.Details["port"])
}
return []string{target, service, version, title, status, server, fingerprints, banner}
}
+22
View File
@@ -57,6 +57,28 @@ func createTestResult(resultType ResultType, target, status string, details map[
}
}
func TestTargetWithPortIPv6(t *testing.T) {
tests := []struct {
name string
target string
port interface{}
want string
}{
{name: "ipv4 without port", target: "192.168.1.1", port: 80, want: "192.168.1.1:80"},
{name: "ipv4 with port", target: "192.168.1.1:80", port: 443, want: "192.168.1.1:80"},
{name: "ipv6 without port", target: "2001:db8::1", port: 443, want: "[2001:db8::1]:443"},
{name: "ipv6 with port", target: "[2001:db8::1]:443", port: 80, want: "[2001:db8::1]:443"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := targetWithPort(tt.target, tt.port); got != tt.want {
t.Fatalf("targetWithPort(%q, %v) = %q, want %q", tt.target, tt.port, got, tt.want)
}
})
}
}
// =============================================================================
// TXTWriter - 基础功能测试
// =============================================================================