001    package railo.commons.net;
002    
003    import java.io.IOException;
004    import java.io.Serializable;
005    import java.net.Inet6Address;
006    import java.net.InetAddress;
007    import java.net.UnknownHostException;
008    
009    import railo.commons.lang.StringUtil;
010    import railo.runtime.type.util.ListUtil;
011    
012    public class IPRange implements Serializable {
013            
014            /**
015             * 
016             */
017            private static final long serialVersionUID = 4427999443422764L;
018            private static final short N256 = 256;
019            private static final int SIZE = 4;
020            
021            private Range[] ranges=new Range[SIZE];
022            int max=0;
023            
024            
025            private static class Range {
026                    private final short[] from;
027                    private final short[] to;
028                    private final boolean equality;
029    
030                    private Range(short[] from, short[] to) throws IOException{
031                            if(from.length!=to.length)
032                                    throw new IOException("both ip address must be from same type, IPv4 or IPv6");
033                            
034                            this.from=from;
035                            this.to=to;
036                            this.equality=equal(from,to);
037                    }
038                    private Range(short[] from){
039                            this.from=from;
040                            this.to=from;
041                            this.equality=true;
042                    }
043                    private boolean inRange(short[] sarr) {
044                            if(from.length!=sarr.length) return false;
045                            
046                            if(equality) return equal(from, sarr);
047                            
048                            for(int i=0;i<from.length;i++){
049                                    if(from[i]>sarr[i] ||  to[i]<sarr[i])
050                                            return false;
051                            }
052                            return true;
053                    }
054                    
055                    public String toString(){
056                            if(equality) return toString(from);
057                            return toString(from)+"-"+toString(to);
058                    }
059                    
060                    private String toString(short[] sarr) {
061                            if(sarr.length==4)
062                                    return new StringBuilder().append(sarr[0]).append(".").append(sarr[1]).append(".").append(sarr[2]).append(".").append(sarr[3]).toString();
063                            
064                            return new StringBuilder()
065                            .append(toHex(sarr[0],sarr[1],false)).append(":")
066                            .append(toHex(sarr[2],sarr[3],true)).append(":")
067                            .append(toHex(sarr[4],sarr[5],true)).append(":")
068                            .append(toHex(sarr[6],sarr[7],true)).append(":")
069                            .append(toHex(sarr[8],sarr[9],true)).append(":")
070                            .append(toHex(sarr[10],sarr[11],true)).append(":")
071                            .append(toHex(sarr[12],sarr[13],true)).append(":")
072                            .append(toHex(sarr[14],sarr[15],false)).toString();
073                            
074                            
075                    }
076                    
077                    
078                    
079                    private String toHex(int first, int second, boolean allowEmpty) {
080                            String str1=Integer.toString(first,16);
081                            while(str1.length()<2)str1="0"+str1;
082                            String str2=Integer.toString(second,16);
083                            while(str2.length()<2)str2="0"+str2;
084                            str1+=str2;
085                            if(allowEmpty && str1.equals("0000")) return "";
086                            
087                            while(str1.length()>1 && str1.charAt(0)=='0')str1=str1.substring(1);
088                            
089                            
090                            
091                            return str1;
092                    }
093                    private boolean equal(short[] left, short[] right) {
094                            for(int i=0;i<left.length;i++){
095                                    if(left[i]!=right[i]) return false;
096                            }
097                            return true;
098                    }
099                    
100                    
101            }
102            
103    
104            private void add(String ip) throws IOException {
105                    ip=ip.trim();
106                    // no wildcard defined
107                    if(ip.indexOf('*')==-1) {
108                            add(new Range(toShortArray(toInetAddress(ip))));
109                            return;
110                    }
111                    
112                    if("*".equals(ip)) {
113                            add("*.*.*.*");
114                            add("*:*:*:*:*:*:*:*");
115                            return;
116                    }
117                    
118                    String from = ip.replace('*', '0');
119                    String to;
120                    InetAddress addr1 = toInetAddress(from);
121                    if(addr1 instanceof Inet6Address) 
122                            to=StringUtil.replace(ip, "*","ffff",false);
123                    else 
124                            to=StringUtil.replace(ip, "*","255",false);
125                    add(new Range(toShortArray(addr1),toShortArray(toInetAddress(to))));
126            }
127    
128            private void add(String ip1,String ip2) throws IOException {
129                    add(new Range(toShortArray(toInetAddress(ip1)),toShortArray(toInetAddress(ip2))));
130            }
131            public static IPRange getInstance(String raw) throws IOException {
132                    return getInstance(ListUtil.listToStringArray(raw, ','));
133            }
134    
135            public static IPRange getInstance(String[] raw) throws IOException {
136                    IPRange range=new IPRange();
137                    String[] arr = ListUtil.trimItems(ListUtil.trim(raw));
138                    String str;
139                    int index;
140                    for(int i=0;i<arr.length;i++){
141                            str=arr[i];
142                            if(str.length()>0) {
143                                    index=str.indexOf('-');
144                                    if(index!=-1) range.add(str.substring(0,index), str.substring(index+1));
145                                    else range.add(str);
146                            }
147                    }
148                    return range;
149                    
150            }
151            
152            
153            private synchronized void add(Range range) {
154                    if(max>=ranges.length) {
155                            Range[] tmp=new Range[ranges.length+SIZE];
156                            for(int i=0;i<ranges.length;i++){
157                                    tmp[i]=ranges[i];
158                            }
159                            ranges=tmp;
160                    }
161                    ranges[max++]=range;
162            }
163    
164            public boolean inRange(String ip) throws IOException {
165                    return inRange(toShortArray(ip));
166            }
167    
168            public boolean inRange(short[] ip) {
169                    for(int i=0;i<max;i++){
170                            if(ranges[i].inRange(ip)) return true;
171                    }
172                    return false;
173            }
174            
175            
176            public String toString(){
177                    StringBuilder sb=new StringBuilder();
178                    for(int i=0;i<max;i++){
179                            if(i>0)sb.append(",");
180                            sb.append(ranges[i].toString());
181                    }
182                    return sb.toString();
183            }
184    
185            public static short[] toShortArray(String ip) throws IOException {
186                    return toShortArray(toInetAddress(ip));
187            }
188            
189            private static InetAddress toInetAddress(String ip) throws IOException {
190                    // TODO Auto-generated method stub
191                    try {
192                            return InetAddress.getByName(ip);
193                    } catch (UnknownHostException e) {
194                            throw new IOException("cannot parse the ip ["+ip+"]");
195                    }
196            }
197    
198            private static short[] toShortArray(InetAddress ia){
199                    byte[] addr = ia.getAddress();
200                    short[] sarr=new short[addr.length];
201                    for(int i=0;i<addr.length;i++){
202                            sarr[i]=byte2short(addr[i]);
203                    }
204                    return sarr;
205            }
206            
207            private static short byte2short(byte b){
208                    if(b<0) return (short)(b+N256);
209                    return b;
210            }
211    }