Add support for parsing IPs by version (IPv4 and IPv6) with validation logic

This commit is contained in:
2026-03-18 21:03:50 +05:00
parent cfbf4ce504
commit 1b16ae243f

View File

@@ -11,14 +11,25 @@ import (
type Parser interface { type Parser interface {
// Parse reads the body and returns a slice of IP addresses. // Parse reads the body and returns a slice of IP addresses.
Parse(body io.Reader, validator IPValidator, limit uint) (IPs, error) Parse(body io.Reader, validator IPValidator, limit uint) (IPs, error)
ParseIPsByVersion(body io.Reader, validator IPValidator, limit uint) (ipV4 IPs, ipV6 IPs, err error)
} }
// IPValidator interface defines the contract for validating IP addresses. // IPValidator interface defines the contract for validating IP addresses.
type IPValidator interface { type IPValidator interface {
// IsValid checks if the given IP address is valid. // IsValid checks if the given IP address is valid.
IsValid(ip string) bool IsValid(ip string) bool
IsValidAndReturnVersion(ip string) (bool, IPVersion)
} }
type IPVersion int
const (
IPVersion4 IPVersion = iota
IPVersion6
)
// IPs is a slice of IP addresses. // IPs is a slice of IP addresses.
type IPs []string type IPs []string
@@ -50,6 +61,48 @@ func (v *DefaultIPValidator) IsValid(value string) bool {
return false return false
} }
// IsValidAndReturnVersion checks if the given IP address is valid and returns the IP version.
// It returns true if the IP address is not a loopback address and the IP version is either IPv4 or IPv6.
func (v *DefaultIPValidator) IsValidAndReturnVersion(value string) (bool, IPVersion) {
if value == "" {
return false, IPVersion4
}
if ip := net.ParseIP(value); ip != nil {
if ip.IsLoopback() {
return false, IPVersion4
}
if ip.To4() != nil {
return true, IPVersion4
}
if ip.To16() != nil {
return true, IPVersion6
}
return false, IPVersion4
}
if ip, _, err := net.ParseCIDR(value); err == nil {
if ip.IsLoopback() {
return false, IPVersion4
}
if ip.To4() != nil {
return true, IPVersion4
}
if ip.To16() != nil {
return true, IPVersion6
}
return false, IPVersion4
}
return false, IPVersion4
}
// IPRangeValidator implements IPValidator interface. // IPRangeValidator implements IPValidator interface.
// It validates IP ranges by parsing them using net.ParseIP and checking if the start and end IPs are in the same network. // It validates IP ranges by parsing them using net.ParseIP and checking if the start and end IPs are in the same network.
type IPRangeValidator struct{} type IPRangeValidator struct{}
@@ -89,3 +142,43 @@ func (v *IPRangeValidator) IsValid(value string) bool {
return false return false
} }
} }
func (v *IPRangeValidator) IsValidAndReturnVersion(value string) (bool, IPVersion) {
if value == "" {
return false, IPVersion4
}
parts := strings.Split(value, "-")
if len(parts) != 2 {
return false, IPVersion4
}
start := net.ParseIP(strings.TrimSpace(parts[0]))
end := net.ParseIP(strings.TrimSpace(parts[1]))
if start == nil || end == nil {
return false, IPVersion4
}
start4 := start.To4()
end4 := end.To4()
switch {
case start4 != nil && end4 != nil:
if bytes.Compare(start4, end4) <= 0 {
return true, IPVersion4
}
return false, IPVersion4
case start4 == nil && end4 == nil:
start16 := start.To16()
end16 := end.To16()
if start16 == nil || end16 == nil {
return false, IPVersion4
}
if bytes.Compare(start16, end16) <= 0 {
return true, IPVersion6
}
return false, IPVersion4
default:
return false, IPVersion4
}
}