/* * Copyright 2015-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package sockslib.common; import com.google.common.base.Preconditions; import java.io.Serializable; import java.net.Inet4Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * The class <code>IPRange</code> represents an IPrange. * * @author Youchao Feng * @version 1.0 * @date May 2, 2015 12:45:25 AM */ public class IPRange implements Iterable<IP>, Serializable { /** * Serial version UID. */ private static final long serialVersionUID = 1L; /** * Starting IP address of the IP address range. */ private final IP startIP; /** * End IP address of the IP address range。 */ private final IP endIP; /** * Constructs a <code>IpRange</code> instance by given tow IP. * * @param startIp IP starts. * @param endIp IP ends. */ public IPRange(IP startIp, IP endIp) { int result = endIp.compareTo(startIp); if (result > 0 || result == 0) Preconditions.checkArgument( result > 0 || result == 0, "maxIP must equal or bigger than minIP"); this.startIP = startIp; this.endIP = endIp; } /** * Creates a <code>IpRange</code> instance by a string. * * @param range a string such as "1.1.1.1-1.1.2.255". * @return IP range. */ public static IPRange parse(String range) { String[] ips = range.split("-"); Preconditions.checkArgument( ips.length == 2, "IP range string must be fomarted as [minIP-maxIP],error argument:" + range); return new IPRange(IP.parseFromString(ips[0]), IP.parseFromString(ips[1])); } /** * Creates a {@link IPRange} instance by IP with mask. * * @param ipWithMask IP/mask, such as 192.168.70.1/24 * @return {@link IPRange} instance */ public static IPRange parseFromIPWithMask(String ipWithMask) { long minIpAsLong = 0; long maxIpAsLong = 0; String[] strs = ipWithMask.split("/"); if (strs.length == 2) { IP ip = IP.parseFromString(strs[0]); int mask = Integer.parseInt(strs[1]); long maskAsLong = 0xffffffff << (32 - mask); minIpAsLong = ip.toLong(); maxIpAsLong = minIpAsLong | (~maskAsLong); } else { throw new IllegalArgumentException( "The input String format error. For example" + " 192.168.1.1/24"); } return new IPRange(new IP(minIpAsLong), new IP(maxIpAsLong)); } /** * Gets A class IP range. * * @return A class IP range. */ public static IPRange AClassLocalIPRange() { // 10.0.0.0 - 10.255.255.255 return new IPRange(new IP(0x0A000000), new IP(0x0AFFFFFF)); } /** * Gets B class IP range. * * @return B class IP range. */ public static IPRange BClassLocalIPRange() { return new IPRange(new IP(172, 16, 0, 0), new IP(172, 31, 255, 255)); } /** * Gets C class IP range. * * @return C class IP range. */ public static IPRange CClassLocalIPRange() { return new IPRange(new IP(192, 168, 0, 0), new IP(192, 168, 255, 255)); } /** * Returns <code>true</code> if the given IP is in the IP range. * * @param ip IP. * @return If the IP is in the rang return <code>true</code>. */ public boolean contains(IP ip) { return ip.compareTo(startIP) >= 0 && ip.compareTo(endIP) <= 0; } public boolean contains(SocketAddress address) { return address instanceof InetSocketAddress && contains( ((InetSocketAddress) address).getAddress()); } public boolean contains(InetAddress address){ if (address instanceof Inet4Address){ IP ip = new IP(address.getAddress()); return contains(ip); } return false; } /** * Returns size of IP range. * * @return Size of IP range. */ public long size() { return (endIP.getValue() - startIP.getValue() + 1L); } /** * Returns starting IP address. * * @return Starting IP address. */ public IP getStartIP() { return startIP; } /** * Returns end IP address. * * @return End ip address. */ public IP getEndIP() { return endIP; } /** * Split IP address range by a IP address. * * @param ip IP address. IP address range should contains the IP address. * @return List of IP address ranges. */ public List<IPRange> split(IP ip) { List<IPRange> ranges = new ArrayList<IPRange>(); if (this.contains(ip)) { ranges.add(new IPRange(this.startIP, ip)); ranges.add(new IPRange(ip, this.endIP)); } return ranges; } @Override public Iterator<IP> iterator() { return new IPIterator(startIP, endIP); } @Override public String toString() { return startIP + "-" + endIP; } @Override public int hashCode() { return toString().hashCode(); } @Override public boolean equals(Object obj) { if (obj instanceof IPRange) { IPRange range = (IPRange) obj; return range.getStartIP().equals(startIP) && range.getEndIP().equals(endIP); } else { return false; } } }