package ipcheck import ( "errors" "fmt" "gitea.drugeyes.vip/pharnexbase/ipcheck/utils" "sort" "strings" ) // SingleIpInRange 单个ip地址(范围)判断是否在配置ip范围内 func SingleIpInRange(ip, ipConfigStr string) (bool, error) { singleIp := utils.NewIpRange(ip) if singleIp == nil { return false, errors.New("ip格式错误!") } //判断ip范围是否满足从小到大的规则 if err := singleIp.CheckIpRange(); err != nil { return false, err } ipConfigArr := strings.Split(strings.ReplaceAll(ipConfigStr, "\r\n", "\n"), "\n") for _, ipConfig := range ipConfigArr { containIp := utils.NewIpRange(ipConfig) if containIp != nil && singleIp.Type() == containIp.Type() { //只有ip类型相同才判断范围 if containIp.IsContain(singleIp) { return true, nil } } } 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 }