{"record":{"id":"0f87f5381dc00f76","repo":"shadow1ng/fscan","slug":"parser-ipv4-only","errorCode":null,"errorMessage":"parser_ipv4_only","messagePattern":"parser_ipv4_only","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/parsers/host_iterator.go","lineNumber":329,"sourceCode":"\t\tsrc, err := newRangeHostSource(host)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(i18n.Tr(\"parser_ip_range_failed\", host)+\": %w\", err)\n\t\t}\n\t\treturn src, nil\n\tdefault:\n\t\treturn &singleHostSource{host: host}, nil\n\t}\n}\n\nfunc newCIDRHostSource(cidr string) (hostSource, error) {\n\t_, ipNet, err := net.ParseCIDR(cidr)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tstart, ok := ipToUint32(ipNet.IP)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"%s\", i18n.GetText(\"parser_ipv4_only\"))\n\t}\n\tones, bits := ipNet.Mask.Size()\n\tif bits != 32 {\n\t\treturn nil, fmt.Errorf(\"%s\", i18n.GetText(\"parser_ipv4_only\"))\n\t}\n\tsize := uint64(1) << uint(32-ones)\n\tend := start + uint32(size-1)\n\tif size > 2 {\n\t\tstart++\n\t\tend--\n\t}\n\treturn &cidrHostSource{current: start, end: end}, nil\n}\n\nfunc newRangeHostSource(rangeStr string) (hostSource, error) {\n\tparts := strings.Split(rangeStr, \"-\")\n\tif len(parts) != 2 {\n\t\treturn nil, fmt.Errorf(\"%s\", i18n.Tr(\"parser_invalid_ip_range_fmt\", rangeStr))","sourceCodeStart":311,"sourceCodeEnd":347,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/common/parsers/host_iterator.go#L311-L347","documentation":"newCIDRHostSource failed because the parsed net.IPNet is not an IPv4 network. The library converts the network base address to a uint32 (ipToUint32) and requires a 32-bit mask; an IPv6 CIDR such as ::/0 or 2001:db8::/32 fails both checks and this localized message is returned. The CIDR host iterator only supports IPv4 address spaces.","triggerScenarios":"Calling newHostSource or addCIDR (via the host matcher Add) with an IPv6 CIDR string like \"2001:db8::/32\" or \"::1/128\"; also produced directly by newCIDRHostSource when ipToUint32(ipNet.IP) returns ok=false or ipNet.Mask.Size() reports bits != 32.","commonSituations":"A scan/config file lists IPv6 CIDR blocks alongside IPv4 ones; an environment enables IPv6-only addressing so users naturally write IPv6 targets; copy-pasted IPv6 prefixes into an IPv4-only tool configuration.","solutions":["Replace the IPv6 CIDR with an IPv4 CIDR (e.g. 192.168.1.0/24) — IPv6 networks are unsupported by this iterator.","Filter the input target list to keep only entries where net.ParseIP(ip).To4() != nil before calling addCIDR.","If IPv6 support is required, extend host_iterator.go with a 128-bit source type instead of relying on ipToUint32."],"exampleFix":"// before\n_ = m.AddCIDR(\"2001:db8::/32\") // error: parser_ipv4_only\n\n// after\nip, ipNet, err := net.ParseCIDR(\"2001:db8::/32\")\n_ = ip\nif ipNet.IP.To4() == nil {\n    // skip or handle IPv6 elsewhere\n} else {\n    _ = m.AddCIDR(\"2001:db8::/32\")\n}","handlingStrategy":"validation","validationCode":"func isIPv4CIDR(s string) bool {\n    _, ipNet, err := net.ParseCIDR(s)\n    if err != nil {\n        return false\n    }\n    _, bits := ipNet.Mask.Size()\n    return bits == 32\n}","typeGuard":"func isIPv4CIDRNet(ipNet *net.IPNet) bool {\n    return ipNet != nil && ipNet.IP.To4() != nil\n}","tryCatchPattern":"src, err := newCIDRHostSource(cidr)\nif err != nil {\n    log.Printf(\"skipping CIDR %q: %v\", cidr, err)\n    return nil // continue with remaining sources\n}","preventionTips":["Normalize target lists to IPv4-only before feeding the host iterator.","Add a unit test asserting IPv6 CIDRs are rejected or skipped gracefully.","Document the IPv4-only limitation where CIDR input is accepted."],"tags":["ipv4","cidr","parser","go"],"backgroundTag":"unsupported-operation","analyzedSha":"95cc12e753bf43de7004e5aef42a9ffba3934303","analyzedAt":"2026-09-06T17:07:30.094Z","contentChangedAt":"2026-09-06T17:07:30.094Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}