package scan import ( "bufio" "fmt" "net" "net/netip" "regexp" "strconv" "strings" ) var ( reIPv4 = regexp.MustCompile(`^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$`) reIPv4Range = regexp.MustCompile(`^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)-((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$`) reCIDR = regexp.MustCompile(`^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)/(0?[0-9]|1[0-9]|2[0-9]|3[0-2])$`) reIPv6 = regexp.MustCompile(`^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$`) reDomain = regexp.MustCompile(`^([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\.)+[a-zA-Z]{2,}$`) rePort = regexp.MustCompile(`^(0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$`) ) func ParseIPs(text string) ([]string, error) { var ips []string sc := bufio.NewScanner(strings.NewReader(text)) for sc.Scan() { line := strings.TrimSpace(sc.Text()) if line == "" { continue } switch { case reIPv4.MatchString(line): ips = append(ips, line) case reIPv4Range.MatchString(line): parts := strings.SplitN(line, "-", 2) a, err := netip.ParseAddr(parts[0]) if err != nil { return nil, fmt.Errorf("无效IP段: %s", line) } b, err := netip.ParseAddr(parts[1]) if err != nil { return nil, fmt.Errorf("无效IP段: %s", line) } ai := a.As4() bi := b.As4() aInt := uint32(ai[0])<<24 | uint32(ai[1])<<16 | uint32(ai[2])<<8 | uint32(ai[3]) bInt := uint32(bi[0])<<24 | uint32(bi[1])<<16 | uint32(bi[2])<<8 | uint32(bi[3]) if aInt > bInt { aInt, bInt = bInt, aInt } for i := aInt; i <= bInt; i++ { ip := netip.AddrFrom4([4]byte{byte(i >> 24), byte(i >> 16), byte(i >> 8), byte(i)}) ips = append(ips, ip.String()) } case reCIDR.MatchString(line): baseIP, ipNet, err := net.ParseCIDR(line) if err != nil { return nil, fmt.Errorf("无效CIDR: %s", line) } if baseIP.To4() == nil { return nil, fmt.Errorf("仅支持IPv4 CIDR: %s", line) } ips = append(ips, cidrIPs(ipNet)...) case reIPv6.MatchString(line): ips = append(ips, line) case reDomain.MatchString(line): ips = append(ips, line) default: return nil, fmt.Errorf("无法识别的目标: %s", line) } } return ips, sc.Err() } func cidrIPs(ipNet *net.IPNet) []string { var ips []string for ip := ipNet.IP.Mask(ipNet.Mask); ipNet.Contains(ip); inc(ip) { ips = append(ips, ip.String()) } if len(ips) > 0 { ips = ips[1:] } if len(ips) > 0 { ips = ips[:len(ips)-1] } return ips } func inc(ip net.IP) { for j := len(ip) - 1; j >= 0; j-- { ip[j]++ if ip[j] > 0 { break } } } func ParsePorts(text string) ([]int, error) { var ports []int sc := bufio.NewScanner(strings.NewReader(text)) for sc.Scan() { line := strings.TrimSpace(sc.Text()) if line == "" { continue } for _, seg := range strings.Split(line, ";") { seg = strings.TrimSpace(seg) if seg == "" { continue } if strings.Contains(seg, "-") { parts := strings.SplitN(seg, "-", 2) a, err1 := strconv.Atoi(strings.TrimSpace(parts[0])) b, err2 := strconv.Atoi(strings.TrimSpace(parts[1])) if err1 != nil || err2 != nil || a < 0 || a > 65535 || b < 0 || b > 65535 { return nil, fmt.Errorf("无效端口范围: %s", seg) } if a > b { a, b = b, a } for p := a; p <= b; p++ { ports = append(ports, p) } } else { if !rePort.MatchString(seg) { return nil, fmt.Errorf("无效端口: %s", seg) } p, _ := strconv.Atoi(seg) ports = append(ports, p) } } } return ports, sc.Err() }