001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.commons.net; 020 021import java.io.IOException; 022import java.io.Serializable; 023import java.net.Inet6Address; 024import java.net.InetAddress; 025import java.net.UnknownHostException; 026 027import lucee.commons.lang.StringUtil; 028import lucee.runtime.type.util.ListUtil; 029 030public class IPRange implements Serializable { 031 032 /** 033 * 034 */ 035 private static final long serialVersionUID = 4427999443422764L; 036 private static final short N256 = 256; 037 private static final int SIZE = 4; 038 039 private Range[] ranges=new Range[SIZE]; 040 int max=0; 041 042 043 private static class Range { 044 private final short[] from; 045 private final short[] to; 046 private final boolean equality; 047 048 private Range(short[] from, short[] to) throws IOException{ 049 if(from.length!=to.length) 050 throw new IOException("both ip address must be from same type, IPv4 or IPv6"); 051 052 this.from=from; 053 this.to=to; 054 this.equality=equal(from,to); 055 } 056 private Range(short[] from){ 057 this.from=from; 058 this.to=from; 059 this.equality=true; 060 } 061 private boolean inRange(short[] sarr) { 062 if(from.length!=sarr.length) return false; 063 064 if(equality) return equal(from, sarr); 065 066 for(int i=0;i<from.length;i++){ 067 if(from[i]>sarr[i] || to[i]<sarr[i]) 068 return false; 069 } 070 return true; 071 } 072 073 public String toString(){ 074 if(equality) return toString(from); 075 return toString(from)+"-"+toString(to); 076 } 077 078 private String toString(short[] sarr) { 079 if(sarr.length==4) 080 return new StringBuilder().append(sarr[0]).append(".").append(sarr[1]).append(".").append(sarr[2]).append(".").append(sarr[3]).toString(); 081 082 return new StringBuilder() 083 .append(toHex(sarr[0],sarr[1],false)).append(":") 084 .append(toHex(sarr[2],sarr[3],true)).append(":") 085 .append(toHex(sarr[4],sarr[5],true)).append(":") 086 .append(toHex(sarr[6],sarr[7],true)).append(":") 087 .append(toHex(sarr[8],sarr[9],true)).append(":") 088 .append(toHex(sarr[10],sarr[11],true)).append(":") 089 .append(toHex(sarr[12],sarr[13],true)).append(":") 090 .append(toHex(sarr[14],sarr[15],false)).toString(); 091 092 093 } 094 095 096 097 private String toHex(int first, int second, boolean allowEmpty) { 098 String str1=Integer.toString(first,16); 099 while(str1.length()<2)str1="0"+str1; 100 String str2=Integer.toString(second,16); 101 while(str2.length()<2)str2="0"+str2; 102 str1+=str2; 103 if(allowEmpty && str1.equals("0000")) return ""; 104 105 while(str1.length()>1 && str1.charAt(0)=='0')str1=str1.substring(1); 106 107 108 109 return str1; 110 } 111 private boolean equal(short[] left, short[] right) { 112 for(int i=0;i<left.length;i++){ 113 if(left[i]!=right[i]) return false; 114 } 115 return true; 116 } 117 118 119 } 120 121 122 private void add(String ip) throws IOException { 123 ip=ip.trim(); 124 // no wildcard defined 125 if(ip.indexOf('*')==-1) { 126 add(new Range(toShortArray(toInetAddress(ip)))); 127 return; 128 } 129 130 if("*".equals(ip)) { 131 add("*.*.*.*"); 132 add("*:*:*:*:*:*:*:*"); 133 return; 134 } 135 136 String from = ip.replace('*', '0'); 137 String to; 138 InetAddress addr1 = toInetAddress(from); 139 if(addr1 instanceof Inet6Address) 140 to=StringUtil.replace(ip, "*","ffff",false); 141 else 142 to=StringUtil.replace(ip, "*","255",false); 143 add(new Range(toShortArray(addr1),toShortArray(toInetAddress(to)))); 144 } 145 146 private void add(String ip1,String ip2) throws IOException { 147 add(new Range(toShortArray(toInetAddress(ip1)),toShortArray(toInetAddress(ip2)))); 148 } 149 public static IPRange getInstance(String raw) throws IOException { 150 return getInstance(ListUtil.listToStringArray(raw, ',')); 151 } 152 153 public static IPRange getInstance(String[] raw) throws IOException { 154 IPRange range=new IPRange(); 155 String[] arr = ListUtil.trimItems(ListUtil.trim(raw)); 156 String str; 157 int index; 158 for(int i=0;i<arr.length;i++){ 159 str=arr[i]; 160 if(str.length()>0) { 161 index=str.indexOf('-'); 162 if(index!=-1) range.add(str.substring(0,index), str.substring(index+1)); 163 else range.add(str); 164 } 165 } 166 return range; 167 168 } 169 170 171 private synchronized void add(Range range) { 172 if(max>=ranges.length) { 173 Range[] tmp=new Range[ranges.length+SIZE]; 174 for(int i=0;i<ranges.length;i++){ 175 tmp[i]=ranges[i]; 176 } 177 ranges=tmp; 178 } 179 ranges[max++]=range; 180 } 181 182 public boolean inRange(String ip) throws IOException { 183 return inRange(toShortArray(ip)); 184 } 185 186 public boolean inRange(short[] ip) { 187 for(int i=0;i<max;i++){ 188 if(ranges[i].inRange(ip)) return true; 189 } 190 return false; 191 } 192 193 194 public String toString(){ 195 StringBuilder sb=new StringBuilder(); 196 for(int i=0;i<max;i++){ 197 if(i>0)sb.append(","); 198 sb.append(ranges[i].toString()); 199 } 200 return sb.toString(); 201 } 202 203 public static short[] toShortArray(String ip) throws IOException { 204 return toShortArray(toInetAddress(ip)); 205 } 206 207 private static InetAddress toInetAddress(String ip) throws IOException { 208 // TODO Auto-generated method stub 209 try { 210 return InetAddress.getByName(ip); 211 } catch (UnknownHostException e) { 212 throw new IOException("cannot parse the ip ["+ip+"]"); 213 } 214 } 215 216 private static short[] toShortArray(InetAddress ia){ 217 byte[] addr = ia.getAddress(); 218 short[] sarr=new short[addr.length]; 219 for(int i=0;i<addr.length;i++){ 220 sarr[i]=byte2short(addr[i]); 221 } 222 return sarr; 223 } 224 225 private static short byte2short(byte b){ 226 if(b<0) return (short)(b+N256); 227 return b; 228 } 229}