shadow1ng/fscan · error

parser_ipv4_only

Error message

parser_ipv4_only

What it means

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.

Source

Thrown at common/parsers/host_iterator.go:329

		src, err := newRangeHostSource(host)
		if err != nil {
			return nil, fmt.Errorf(i18n.Tr("parser_ip_range_failed", host)+": %w", err)
		}
		return src, nil
	default:
		return &singleHostSource{host: host}, nil
	}
}

func newCIDRHostSource(cidr string) (hostSource, error) {
	_, ipNet, err := net.ParseCIDR(cidr)
	if err != nil {
		return nil, err
	}

	start, ok := ipToUint32(ipNet.IP)
	if !ok {
		return nil, fmt.Errorf("%s", i18n.GetText("parser_ipv4_only"))
	}
	ones, bits := ipNet.Mask.Size()
	if bits != 32 {
		return nil, fmt.Errorf("%s", i18n.GetText("parser_ipv4_only"))
	}
	size := uint64(1) << uint(32-ones)
	end := start + uint32(size-1)
	if size > 2 {
		start++
		end--
	}
	return &cidrHostSource{current: start, end: end}, nil
}

func newRangeHostSource(rangeStr string) (hostSource, error) {
	parts := strings.Split(rangeStr, "-")
	if len(parts) != 2 {
		return nil, fmt.Errorf("%s", i18n.Tr("parser_invalid_ip_range_fmt", rangeStr))

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Replace the IPv6 CIDR with an IPv4 CIDR (e.g. 192.168.1.0/24) — IPv6 networks are unsupported by this iterator.
  2. Filter the input target list to keep only entries where net.ParseIP(ip).To4() != nil before calling addCIDR.
  3. If IPv6 support is required, extend host_iterator.go with a 128-bit source type instead of relying on ipToUint32.

Example fix

// before
_ = m.AddCIDR("2001:db8::/32") // error: parser_ipv4_only

// after
ip, ipNet, err := net.ParseCIDR("2001:db8::/32")
_ = ip
if ipNet.IP.To4() == nil {
    // skip or handle IPv6 elsewhere
} else {
    _ = m.AddCIDR("2001:db8::/32")
}
Defensive patterns

Strategy: validation

Validate before calling

func isIPv4CIDR(s string) bool {
    _, ipNet, err := net.ParseCIDR(s)
    if err != nil {
        return false
    }
    _, bits := ipNet.Mask.Size()
    return bits == 32
}

Type guard

func isIPv4CIDRNet(ipNet *net.IPNet) bool {
    return ipNet != nil && ipNet.IP.To4() != nil
}

Try / catch

src, err := newCIDRHostSource(cidr)
if err != nil {
    log.Printf("skipping CIDR %q: %v", cidr, err)
    return nil // continue with remaining sources
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06). Data as JSON: /api/errors/0f87f5381dc00f76. Report an issue: GitHub.