178 lines
3.6 KiB
Go
178 lines
3.6 KiB
Go
package core
|
|
|
|
import (
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/mayswind/ezbookkeeping/pkg/errs"
|
|
)
|
|
|
|
// IPPattern represents a pattern for matching IP addresses, either IPv4 or IPv6
|
|
type IPPattern struct {
|
|
Pattern string
|
|
regex *regexp.Regexp
|
|
}
|
|
|
|
// Match returns if the given IP address matches the pattern
|
|
func (p *IPPattern) Match(ip string) bool {
|
|
if p.regex == nil {
|
|
return false
|
|
}
|
|
|
|
return p.regex.MatchString(ip)
|
|
}
|
|
|
|
// GobEncode returns the encoded data for this IP pattern
|
|
func (p *IPPattern) GobEncode() ([]byte, error) {
|
|
return []byte(p.Pattern), nil
|
|
}
|
|
|
|
// GobDecode decodes the data into the IP pattern
|
|
func (p *IPPattern) GobDecode(data []byte) error {
|
|
pattern := string(data)
|
|
|
|
if pattern == "" {
|
|
p.Pattern = ""
|
|
p.regex = nil
|
|
return nil
|
|
}
|
|
|
|
newPattern, err := ParseIPPattern(pattern)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
p.Pattern = newPattern.Pattern
|
|
p.regex = newPattern.regex
|
|
return nil
|
|
}
|
|
|
|
// ParseIPPattern parses the given IP address pattern and returns an IPPattern object
|
|
func ParseIPPattern(ipPattern string) (*IPPattern, error) {
|
|
if ipPattern == "" {
|
|
return nil, nil
|
|
}
|
|
|
|
hasDot := false
|
|
hasSemicolon := false
|
|
|
|
for i := 0; i < len(ipPattern); i++ {
|
|
ch := rune(ipPattern[i])
|
|
|
|
if ch == '.' { // may be IPv4
|
|
if hasSemicolon {
|
|
return nil, errs.ErrInvalidIpAddressPattern
|
|
}
|
|
hasDot = true
|
|
} else if ch == ':' { // may be IPv6
|
|
if hasDot {
|
|
return nil, errs.ErrInvalidIpAddressPattern
|
|
}
|
|
hasSemicolon = true
|
|
}
|
|
}
|
|
|
|
if hasDot {
|
|
return ParseIPv4Pattern(ipPattern)
|
|
} else if hasSemicolon {
|
|
return ParseIPv6Pattern(ipPattern)
|
|
} else {
|
|
return nil, errs.ErrInvalidIpAddressPattern
|
|
}
|
|
}
|
|
|
|
// ParseIPv4Pattern parses the given IPv4 address pattern and returns an IPPattern object
|
|
func ParseIPv4Pattern(ipPattern string) (*IPPattern, error) {
|
|
items := strings.Split(ipPattern, ".")
|
|
|
|
if len(items) != 4 {
|
|
return nil, errs.ErrInvalidIpAddressPattern
|
|
}
|
|
|
|
regexBuilder := strings.Builder{}
|
|
regexBuilder.WriteRune('^')
|
|
|
|
for i := 0; i < len(items); i++ {
|
|
item := strings.TrimSpace(items[i])
|
|
|
|
if item == "*" {
|
|
regexBuilder.WriteString("[0-9]{1,3}")
|
|
} else if item == "" {
|
|
return nil, errs.ErrInvalidIpAddressPattern
|
|
} else {
|
|
num, err := strconv.Atoi(item)
|
|
|
|
if err != nil || num < 0 || num > 255 {
|
|
return nil, errs.ErrInvalidIpAddressPattern
|
|
}
|
|
|
|
regexBuilder.WriteString(item)
|
|
}
|
|
|
|
if i < len(items)-1 {
|
|
regexBuilder.WriteRune('\\')
|
|
regexBuilder.WriteRune('.')
|
|
}
|
|
}
|
|
|
|
regexBuilder.WriteRune('$')
|
|
regex, err := regexp.Compile(regexBuilder.String())
|
|
|
|
if err != nil {
|
|
return nil, errs.ErrInvalidIpAddressPattern
|
|
}
|
|
|
|
return &IPPattern{
|
|
Pattern: ipPattern,
|
|
regex: regex,
|
|
}, nil
|
|
}
|
|
|
|
// ParseIPv6Pattern parses the given IPv6 address pattern and returns an IPPattern object
|
|
func ParseIPv6Pattern(ipPattern string) (*IPPattern, error) {
|
|
items := strings.Split(ipPattern, ":")
|
|
|
|
if len(items) < 2 || len(items) > 8 {
|
|
return nil, errs.ErrInvalidIpAddressPattern
|
|
}
|
|
|
|
regexBuilder := strings.Builder{}
|
|
regexBuilder.WriteRune('^')
|
|
|
|
for i := 0; i < len(items); i++ {
|
|
item := strings.TrimSpace(items[i])
|
|
|
|
if item == "*" {
|
|
regexBuilder.WriteString("[0-9a-fA-F]{1,4}")
|
|
} else if i < len(items)-1 && item == "" {
|
|
// Do Nothing
|
|
} else {
|
|
num, err := strconv.ParseInt(item, 16, 32)
|
|
|
|
if err != nil || num < 0 || num > 0xFFFF {
|
|
return nil, errs.ErrInvalidIpAddressPattern
|
|
}
|
|
|
|
regexBuilder.WriteString(item)
|
|
}
|
|
|
|
if i < len(items)-1 {
|
|
regexBuilder.WriteRune(':')
|
|
}
|
|
}
|
|
|
|
regexBuilder.WriteRune('$')
|
|
regex, err := regexp.Compile(regexBuilder.String())
|
|
|
|
if err != nil {
|
|
return nil, errs.ErrInvalidIpAddressPattern
|
|
}
|
|
|
|
return &IPPattern{
|
|
Pattern: ipPattern,
|
|
regex: regex,
|
|
}, nil
|
|
}
|