001 /***********************************************************************
002 * Copyright (c) 2000-2006 The Apache Software Foundation. *
003 * All rights reserved. *
004 * ------------------------------------------------------------------- *
005 * Licensed under the Apache License, Version 2.0 (the "License"); you *
006 * may not use this file except in compliance with the License. You *
007 * may obtain a copy of the License at: *
008 * *
009 * http://www.apache.org/licenses/LICENSE-2.0 *
010 * *
011 * Unless required by applicable law or agreed to in writing, software *
012 * distributed under the License is distributed on an "AS IS" BASIS, *
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or *
014 * implied. See the License for the specific language governing *
015 * permissions and limitations under the License. *
016 ***********************************************************************/
017
018 package org.apache.qpid.util;
019
020 import java.net.InetAddress;
021 import java.util.ArrayList;
022 import java.util.Collection;
023 import java.util.Iterator;
024
025 public class NetMatcher
026 {
027 private ArrayList networks;
028
029 public void initInetNetworks(final Collection nets)
030 {
031 networks = new ArrayList();
032 for (Iterator iter = nets.iterator(); iter.hasNext(); ) try
033 {
034 InetNetwork net = InetNetwork.getFromString((String) iter.next());
035 if (!networks.contains(net)) networks.add(net);
036 }
037 catch (java.net.UnknownHostException uhe)
038 {
039 log("Cannot resolve address: " + uhe.getMessage());
040 }
041 networks.trimToSize();
042 }
043
044 public void initInetNetworks(final String[] nets)
045 {
046 networks = new ArrayList();
047 for (int i = 0; i < nets.length; i++) try
048 {
049 InetNetwork net = InetNetwork.getFromString(nets[i]);
050 if (!networks.contains(net)) networks.add(net);
051 }
052 catch (java.net.UnknownHostException uhe)
053 {
054 log("Cannot resolve address: " + uhe.getMessage());
055 }
056 networks.trimToSize();
057 }
058
059 public boolean matchInetNetwork(final String hostIP)
060 {
061 InetAddress ip = null;
062
063 try
064 {
065 ip = InetAddress.getByName(hostIP);
066 }
067 catch (java.net.UnknownHostException uhe)
068 {
069 log("Cannot resolve address for " + hostIP + ": " + uhe.getMessage());
070 }
071
072 boolean sameNet = false;
073
074 if (ip != null) for (Iterator iter = networks.iterator(); (!sameNet) && iter.hasNext(); )
075 {
076 InetNetwork network = (InetNetwork) iter.next();
077 sameNet = network.contains(ip);
078 }
079 return sameNet;
080 }
081
082 public boolean matchInetNetwork(final InetAddress ip)
083 {
084 boolean sameNet = false;
085
086 for (Iterator iter = networks.iterator(); (!sameNet) && iter.hasNext(); )
087 {
088 InetNetwork network = (InetNetwork) iter.next();
089 sameNet = network.contains(ip);
090 }
091 return sameNet;
092 }
093
094 public NetMatcher()
095 {
096 }
097
098 public NetMatcher(final String[] nets)
099 {
100 initInetNetworks(nets);
101 }
102
103 public NetMatcher(final Collection nets)
104 {
105 initInetNetworks(nets);
106 }
107
108 public String toString() {
109 return networks.toString();
110 }
111
112 protected void log(String s) { }
113 }
114
115 class InetNetwork
116 {
117 /*
118 * Implements network masking, and is compatible with RFC 1518 and
119 * RFC 1519, which describe CIDR: Classless Inter-Domain Routing.
120 */
121
122 private InetAddress network;
123 private InetAddress netmask;
124
125 public InetNetwork(InetAddress ip, InetAddress netmask)
126 {
127 network = maskIP(ip, netmask);
128 this.netmask = netmask;
129 }
130
131 public boolean contains(final String name) throws java.net.UnknownHostException
132 {
133 return network.equals(maskIP(InetAddress.getByName(name), netmask));
134 }
135
136 public boolean contains(final InetAddress ip)
137 {
138 return network.equals(maskIP(ip, netmask));
139 }
140
141 public String toString()
142 {
143 return network.getHostAddress() + "/" + netmask.getHostAddress();
144 }
145
146 public int hashCode()
147 {
148 return maskIP(network, netmask).hashCode();
149 }
150
151 public boolean equals(Object obj)
152 {
153 return (obj != null) && (obj instanceof InetNetwork) &&
154 ((((InetNetwork)obj).network.equals(network)) && (((InetNetwork)obj).netmask.equals(netmask)));
155 }
156
157 public static InetNetwork getFromString(String netspec) throws java.net.UnknownHostException
158 {
159 if (netspec.endsWith("*")) netspec = normalizeFromAsterisk(netspec);
160 else
161 {
162 int iSlash = netspec.indexOf('/');
163 if (iSlash == -1) netspec += "/255.255.255.255";
164 else if (netspec.indexOf('.', iSlash) == -1) netspec = normalizeFromCIDR(netspec);
165 }
166
167 return new InetNetwork(InetAddress.getByName(netspec.substring(0, netspec.indexOf('/'))),
168 InetAddress.getByName(netspec.substring(netspec.indexOf('/') + 1)));
169 }
170
171 public static InetAddress maskIP(final byte[] ip, final byte[] mask)
172 {
173 try
174 {
175 return getByAddress(new byte[]
176 {
177 (byte) (mask[0] & ip[0]),
178 (byte) (mask[1] & ip[1]),
179 (byte) (mask[2] & ip[2]),
180 (byte) (mask[3] & ip[3])
181 });
182 }
183 catch(Exception _) {}
184 {
185 return null;
186 }
187 }
188
189 public static InetAddress maskIP(final InetAddress ip, final InetAddress mask)
190 {
191 return maskIP(ip.getAddress(), mask.getAddress());
192 }
193
194 /*
195 * This converts from an uncommon "wildcard" CIDR format
196 * to "address + mask" format:
197 *
198 * * => 000.000.000.0/000.000.000.0
199 * xxx.* => xxx.000.000.0/255.000.000.0
200 * xxx.xxx.* => xxx.xxx.000.0/255.255.000.0
201 * xxx.xxx.xxx.* => xxx.xxx.xxx.0/255.255.255.0
202 */
203 static private String normalizeFromAsterisk(final String netspec)
204 {
205 String[] masks = { "0.0.0.0/0.0.0.0", "0.0.0/255.0.0.0", "0.0/255.255.0.0", "0/255.255.255.0" };
206 char[] srcb = netspec.toCharArray();
207 int octets = 0;
208 for (int i = 1; i < netspec.length(); i++) {
209 if (srcb[i] == '.') octets++;
210 }
211 return (octets == 0) ? masks[0] : netspec.substring(0, netspec.length() -1 ).concat(masks[octets]);
212 }
213
214 /*
215 * RFC 1518, 1519 - Classless Inter-Domain Routing (CIDR)
216 * This converts from "prefix + prefix-length" format to
217 * "address + mask" format, e.g. from xxx.xxx.xxx.xxx/yy
218 * to xxx.xxx.xxx.xxx/yyy.yyy.yyy.yyy.
219 */
220 static private String normalizeFromCIDR(final String netspec)
221 {
222 final int bits = 32 - Integer.parseInt(netspec.substring(netspec.indexOf('/')+1));
223 final int mask = (bits == 32) ? 0 : 0xFFFFFFFF - ((1 << bits)-1);
224
225 return netspec.substring(0, netspec.indexOf('/') + 1) +
226 Integer.toString(mask >> 24 & 0xFF, 10) + "." +
227 Integer.toString(mask >> 16 & 0xFF, 10) + "." +
228 Integer.toString(mask >> 8 & 0xFF, 10) + "." +
229 Integer.toString(mask >> 0 & 0xFF, 10);
230 }
231
232 private static java.lang.reflect.Method getByAddress = null;
233
234 static {
235 try {
236 Class inetAddressClass = Class.forName("java.net.InetAddress");
237 Class[] parameterTypes = { byte[].class };
238 getByAddress = inetAddressClass.getMethod("getByAddress", parameterTypes);
239 } catch (Exception e) {
240 getByAddress = null;
241 }
242 }
243
244 private static InetAddress getByAddress(byte[] ip) throws java.net.UnknownHostException
245 {
246 InetAddress addr = null;
247 if (getByAddress != null) try {
248 addr = (InetAddress) getByAddress.invoke(null, new Object[] { ip });
249 } catch (IllegalAccessException e) {
250 } catch (java.lang.reflect.InvocationTargetException e) {
251 }
252
253 if (addr == null) {
254 addr = InetAddress.getByName
255 (
256 Integer.toString(ip[0] & 0xFF, 10) + "." +
257 Integer.toString(ip[1] & 0xFF, 10) + "." +
258 Integer.toString(ip[2] & 0xFF, 10) + "." +
259 Integer.toString(ip[3] & 0xFF, 10)
260 );
261 }
262 return addr;
263 }
264 }
|