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