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.runtime.net.ipsettings; 020 021 022import java.net.Inet4Address; 023import java.net.InetAddress; 024import java.net.UnknownHostException; 025import java.util.Comparator; 026import java.util.List; 027 028import lucee.commons.lang.ExceptionUtil; 029 030 031public class IPRangeNode<T> implements Comparable<IPRangeNode>, Comparator<IPRangeNode> { 032 033 private InetAddress lower; 034 private InetAddress upper; 035 private boolean isSingle; 036 037 private T data; 038 private IPRangeCollection children; 039 040 041 public IPRangeNode( InetAddress lower, InetAddress upper) { 042 043 int c = comparerIAddr.compare(lower, upper); 044 045 if ( c <= 0 ) { 046 this.lower = lower; 047 this.upper = upper; 048 } 049 else { 050 this.lower = upper; 051 this.upper = lower; 052 } 053 054 this.isSingle = ( c == 0 ); 055 this.children = new IPRangeCollection(); 056 } 057 058 059 public IPRangeNode(String lower, String upper) throws UnknownHostException { 060 061 this( InetAddress.getByName( lower ), InetAddress.getByName( upper ) ); 062 } 063 064 065 public IPRangeNode(String addr) throws UnknownHostException { 066 067 this( addr, addr ); 068 } 069 070 071 public boolean isSingleAddress() { 072 073 return isSingle; 074 } 075 076 077 public boolean isInRange(InetAddress addr) { 078 079 if ( this.isV4() != IPSettings.isV4(addr) ) 080 return false; 081 082 return comparerIAddr.compare(lower, addr) <= 0 083 && comparerIAddr.compare(upper, addr) >= 0; 084 } 085 086 087 public boolean containsRange(IPRangeNode other) { 088 089 if ( this.isV4() != other.isV4() ) 090 return false; 091 092 return this.isInRange(other.lower) && this.isInRange(other.upper); 093 } 094 095 096 /** 097 * 098 * @param child 099 * @param doCheck - passing false will avoid searching for a "better" parent, for a more efficient insert in large data sets (e.g. Country Codes of all known ranges) 100 * @return - true if the child was added 101 */ 102 synchronized boolean addChild( IPRangeNode child, boolean doCheck ) { 103 104 if ( !this.containsRange( child ) ) 105 return false; 106 107 IPRangeNode parent = this; 108 109 if ( doCheck ) 110 parent = findRange( child ); 111 112 // TODO: check for eqaulity of new child and found parent 113 114 parent.children.add( child, doCheck ); 115 116 return true; 117 } 118 119 120 /** calls addChild( child, true ) */ 121 public boolean addChild( IPRangeNode child ) { 122 123 return addChild(child, true); 124 } 125 126 127 public T getData() { 128 129 return data; 130 } 131 132 public void setData(T data) { 133 134 this.data = data; 135 } 136 137 138 public IPRangeNode findRange(IPRangeNode child) { 139 140 IPRangeNode result = null; 141 142 if ( this.containsRange(child) ) { 143 144 result = this; 145 146 IPRangeNode temp = this.children.findRange( child ); 147 if ( temp != null ) 148 result = temp; 149 } 150 151 return result; 152 } 153 154 155 public IPRangeNode findAddr(InetAddress iaddr) { 156 157 IPRangeNode result = null; 158 159 if ( this.isInRange(iaddr) ) { 160 161 result = this; 162 163 if ( this.hasChildren() ) { 164 165 IPRangeNode temp = children.findAddr( iaddr ); 166 if ( temp != null ) 167 result = temp; 168 } 169 } 170 171 return result; 172 } 173 174 175 public IPRangeNode findAddr(String addr) { 176 177 try { 178 179 return findAddr( InetAddress.getByName(addr) ); 180 } 181 catch (Throwable t) { 182 ExceptionUtil.rethrowIfNecessary(t); 183 } 184 185 return null; 186 } 187 188 189 public IPRangeNode findFast(InetAddress iaddr, List<IPRangeNode> parents) { 190 191 IPRangeNode result = null; 192 193 if ( this.isInRange(iaddr) ) { 194 195 result = this; 196 if ( parents != null ) parents.add( result ); 197 198 if ( this.hasChildren() ) { 199 200 IPRangeNode temp = children.findFast( iaddr, parents ); 201 202 if ( temp != null ) 203 result = temp; 204 } 205 } 206 207 return result; 208 } 209 210 211 public IPRangeNode findFast(InetAddress iaddr) { 212 213 return findFast(iaddr, null); 214 } 215 216 217 /*/ works 218 public IPRangeNode findFast(InetAddress iaddr) { 219 220 IPRangeNode result = null; 221 222 if ( this.isInRange(iaddr) ) { 223 224 result = this; 225 226 if ( this.hasChildren() ) { 227 228 IPRangeNode temp = children.findFast( iaddr ); 229 if ( temp != null ) 230 result = temp; 231 } 232 } 233 234 return result; 235 } //*/ 236 237 238 public IPRangeNode findFast(String addr) { 239 240 try { 241 242 return findFast( InetAddress.getByName(addr) ); 243 } 244 catch (Throwable t) { 245 ExceptionUtil.rethrowIfNecessary(t); 246 } 247 248 return null; 249 } 250 251 252 IPRangeCollection getChildren() { 253 254 return children; 255 } 256 257 258 boolean hasChildren() { 259 260 return children.size() > 0; 261 } 262 263 264 @Override 265 public int compareTo(IPRangeNode other) { 266 267 int c = comparerIAddr.compare(this.lower, other.lower); 268 269 if ( c != 0 ) 270 return c; 271 272 c = comparerIAddr.compare(this.upper, other.upper); 273 274 return c; 275 } 276 277 278 @Override 279 public int compare(IPRangeNode lhs, IPRangeNode rhs) { 280 281 return lhs.compareTo(rhs); 282 } 283 284 285 @Override 286 public boolean equals( Object o ) { 287 288 if ( o instanceof IPRangeNode ) { 289 290 return this.compareTo((IPRangeNode)o) == 0; 291 } 292 293 return false; 294 } 295 296 @Override 297 public int hashCode() { 298 299 return this.lower.hashCode(); 300 } 301 302 @Override 303 public String toString() { 304 305 if ( isSingle ) 306 return this.lower.toString().substring(1) + String.format(" (%d)", this.children.size()); 307 308 return this.lower.toString().substring(1) + " - " + this.upper.toString().substring(1) + String.format(" (%d)", this.children.size()); 309 } 310 311 312 public boolean isV4() { 313 314 return IPSettings.isV4( this.lower ); 315 } 316 317 public boolean isV6() { 318 319 return IPSettings.isV6( this.lower ); 320 } 321 322 323 public static final Comparator<IPRangeNode> comparerRange = new Comparator<IPRangeNode>() { 324 325 @Override 326 public int compare(IPRangeNode lhs, IPRangeNode rhs) { 327 328 return lhs.compareTo(rhs); 329 } 330 }; 331 332 333 public static final Comparator<InetAddress> comparerIAddr = new Comparator<InetAddress>() { 334 335 @Override 336 public int compare(InetAddress lhs, InetAddress rhs) { 337 338 if ( (lhs instanceof Inet4Address) != (rhs instanceof Inet4Address) ) 339 throw new IllegalArgumentException("Both arguments must be of the same IP Version"); 340 341 byte[] barrLhs = lhs.getAddress(); 342 byte[] barrRhs = rhs.getAddress(); 343 344 for (int i=0; i < barrLhs.length; i++) { 345 346 int l = barrLhs[i] & 0xff; // fix signed bit in byte 347 int r = barrRhs[i] & 0xff; 348 349 if (l < r) 350 return -1; 351 else if (l > r) 352 return 1; 353 } 354 355 return 0; // equal 356 } 357 }; 358 359 360}