diff --git a/check.go b/check.go index 44aa675..12c0e75 100644 --- a/check.go +++ b/check.go @@ -2,11 +2,13 @@ package ipcheck import ( "errors" + "fmt" "gitea.drugeyes.vip/pharnexbase/ipcheck/utils" + "sort" "strings" ) -//SingleIpInRange 单个ip地址(范围)判断是否在配置ip范围内 +// SingleIpInRange 单个ip地址(范围)判断是否在配置ip范围内 func SingleIpInRange(ip, ipConfigStr string) (bool, error) { singleIp := utils.NewIpRange(ip) if singleIp == nil { @@ -22,7 +24,7 @@ func SingleIpInRange(ip, ipConfigStr string) (bool, error) { for _, ipConfig := range ipConfigArr { containIp := utils.NewIpRange(ipConfig) if containIp != nil && singleIp.Type() == containIp.Type() { //只有ip类型相同才判断范围 - if containIp.IsContain(singleIp) == true { + if containIp.IsContain(singleIp) { return true, nil } } @@ -30,3 +32,103 @@ func SingleIpInRange(ip, ipConfigStr string) (bool, error) { return false, nil } + +// MultipleIpInRange 多个ip地址判断是否在配置ip范围内(该方法在ips很多,且配置ip很多的时候会有速度提升,单个ip的时候不建议使用该方法) +func MultipleIpInRange(ips, ipConfigStr []string) (bool, string, error) { + ownerIpv4s, ownerIpv6s, errIp, err := FilterIpAndSort(ips) + if err != nil { + return false, errIp, err + } + + containIpv4s, containIpv6s, errIp, err := FilterIpAndSort(strings.Split(strings.ReplaceAll(strings.Join(ipConfigStr, "\n"), "\r\n", "\n"), "\n")) + if err != nil { + return false, errIp, err + } + + //优化步骤 + var ipv4Start uint32 = 0 //自己ip段重复也需要提示 + //处理判断ipv4(双指针) + for i, j := 0, 0; i < len(ownerIpv4s) && j < len(containIpv4s); { + ownerLeft := utils.Ipv4ToUint32(ownerIpv4s[i][0]) + ownerRight := utils.Ipv4ToUint32(ownerIpv4s[i][1]) + if ownerLeft > utils.Ipv4ToUint32(containIpv4s[j][1]) { //如果范围ip右边值都比目标ip的左边值小则增加范围ip的指针 + j++ + continue + } + + if containIpv4s[j].IsContain(ownerIpv4s[i]) || ownerIpv4s[i].IsContain(containIpv4s[j]) { + return true, fmt.Sprintf("%s<-->%s", ownerIpv4s[i].IpString(), containIpv4s[j].IpString()), errors.New("输入ip与已存在ip配置范围重叠!") + } + + if ipv4Start >= ownerLeft { //判断自己ip段是否重复,重复就返回重复的ip + if i > 0 { + return false, fmt.Sprintf("%s<-->%s", ownerIpv4s[i-1].IpString(), ownerIpv4s[i].IpString()), errors.New("输入ip范围重叠!") + } + return false, ownerIpv4s[i].IpString(), errors.New("请勿填写0.0.0.0和0:0:0:0:0:0:0:0等无效ip!") + } + ipv4Start = ownerRight + i++ + } + + var ipv6Start = utils.Uint128{H: 0, L: 0} //自己ip段重复也需要提示 + //处理判断ipv6(双指针) + for i, j := 0, 0; i < len(ownerIpv6s) && j < len(containIpv6s); { + ownerLeft := utils.Ipv6ToUint128(ownerIpv6s[i][0]) + ownerRight := utils.Ipv6ToUint128(ownerIpv6s[i][1]) + containRight := utils.Ipv6ToUint128(containIpv6s[j][1]) + if (ownerLeft.H > containRight.H) || (ownerLeft.H == containRight.H && ownerLeft.L > containRight.L) { + j++ + continue + } + + if containIpv6s[j].IsContain(ownerIpv6s[i]) || ownerIpv6s[i].IsContain(containIpv6s[j]) { + return true, fmt.Sprintf("%s<-->%s", ownerIpv6s[i].IpString(), containIpv6s[j].IpString()), errors.New("输入ip与已存在ip配置范围重叠!") + } + + if (ipv6Start.H > ownerLeft.H) || (ipv6Start.H == ownerLeft.H && ipv6Start.L >= ownerLeft.L) { //判断自己ip段是否重复,重复就返回重复的ip + if i > 0 { + return false, fmt.Sprintf("%s<-->%s", ownerIpv6s[i-1].IpString(), ownerIpv6s[i].IpString()), errors.New("输入ip范围重叠!") + } + return false, ownerIpv6s[i].IpString(), errors.New("请勿填写0.0.0.0和0:0:0:0:0:0:0:0等无效ip!") + } + ipv6Start = ownerRight + i++ + } + + return false, "", nil +} + +// FilterIpAndSort 筛选出ipv4和ipv6并排序 +func FilterIpAndSort(ips []string) (ipv4s []utils.Ipv4, ipv6s []utils.Ipv6, errIp string, err error) { + for _, ip := range ips { + ownerIp := utils.NewIpRange(ip) + if ownerIp == nil { + return ipv4s, ipv6s, ip, errors.New("ip格式错误!") + } + + //判断ip范围是否满足从小到大的规则 + if err := ownerIp.CheckIpRange(); err != nil { + return ipv4s, ipv6s, ip, err + } + + if ownerIp.Type() == utils.Ipv4Type { + ipv4s = append(ipv4s, ownerIp.(utils.Ipv4)) + } else { + ipv6s = append(ipv6s, ownerIp.(utils.Ipv6)) + } + } + + //处理排序 + sort.Slice(ipv4s, func(i, j int) bool { + return utils.Ipv4ToUint32(ipv4s[i][0]) < utils.Ipv4ToUint32(ipv4s[j][0]) + }) + + sort.Slice(ipv6s, func(i, j int) bool { + if utils.Ipv6ToUint128(ipv6s[i][0]).H < utils.Ipv6ToUint128(ipv6s[j][0]).H { + return true + } + return utils.Ipv6ToUint128(ipv6s[i][0]).H == utils.Ipv6ToUint128(ipv6s[j][0]).H && utils.Ipv6ToUint128(ipv6s[i][0]).L < utils.Ipv6ToUint128(ipv6s[j][0]).L + }) + + return +}