diff --git a/parser/parser.go b/parser/parser.go index eb23709..5dc8947 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -11,14 +11,25 @@ import ( type Parser interface { // Parse reads the body and returns a slice of IP addresses. 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. type IPValidator interface { // IsValid checks if the given IP address is valid. IsValid(ip string) bool + + IsValidAndReturnVersion(ip string) (bool, IPVersion) } +type IPVersion int + +const ( + IPVersion4 IPVersion = iota + IPVersion6 +) + // IPs is a slice of IP addresses. type IPs []string @@ -50,6 +61,48 @@ func (v *DefaultIPValidator) IsValid(value string) bool { 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. // 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{} @@ -89,3 +142,43 @@ func (v *IPRangeValidator) IsValid(value string) bool { 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 + } +}