diff --git oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/AddressResolver.java oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/AddressResolver.java new file mode 100644 index 0000000..7491a33 --- /dev/null +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/AddressResolver.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jackrabbit.oak.segment.standby.server; + +import java.net.InetAddress; + +public interface AddressResolver { + InetAddress resolve(String host); +} diff --git oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/ClientIpFilter.java oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/ClientIpFilter.java index eb2e6b1..92e6462 100644 --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/ClientIpFilter.java +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/ClientIpFilter.java @@ -20,23 +20,16 @@ package org.apache.jackrabbit.oak.segment.standby.server; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; -import java.net.UnknownHostException; import java.util.Arrays; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.util.regex.Pattern; /** * A white list for IP addresses. A filter can be a single IP address, a single * host name or a range of IP addresses. - *

- * Known issue: if a host name is provided as a filter and that host name - * contains a dash ("-"), it will be interpreted as an IP range. + * */ class ClientIpFilter implements ClientFilter { - private static final Logger log = LoggerFactory.getLogger(ClientIpFilter.class); - private static boolean areAddressesEqual(InetAddress a, InetAddress b) { return Arrays.equals(a.getAddress(), b.getAddress()); } @@ -78,35 +71,21 @@ class ClientIpFilter implements ClientFilter { return compare(leftBytes, addressBytes) <= 0 && compare(addressBytes, rightBytes) <= 0; } - private static boolean isAllowed(InetAddress client, String left, String right) { - InetAddress leftAddress; - - try { - leftAddress = InetAddress.getByName(left); - } catch (UnknownHostException e) { - log.warn("Unable to resolve address or invalid IP literal " + left, e); - return false; - } + private static boolean isAllowed(InetAddress client, AddressResolver addressResolver, String left, String right) { + InetAddress leftAddress = addressResolver.resolve(left); + InetAddress rightAddress = addressResolver.resolve(right); - InetAddress rightAddress; - - try { - rightAddress = InetAddress.getByName(right); - } catch (UnknownHostException e) { - log.warn("Unable to resolve address or invalid IP literal " + right, e); + if (leftAddress == null || rightAddress == null) { return false; } - + return isAddressInRange(client, leftAddress, rightAddress); } - private static boolean isAllowed(InetAddress client, String match) { - InetAddress matchAddress; - - try { - matchAddress = InetAddress.getByName(match); - } catch (UnknownHostException e) { - log.warn("Unable to resolve address or invalid IP literal " + match, e); + private static boolean isAllowed(InetAddress client, AddressResolver addressResolver, String match) { + InetAddress matchAddress = addressResolver.resolve(match); + + if (matchAddress == null) { return false; } @@ -114,14 +93,26 @@ class ClientIpFilter implements ClientFilter { } private final String[] allowedIpRanges; + private final AddressResolver addressResolver; /** - * Create a new white list based on the provided filters. + * Create a new white list based on the provided filters and the default {@link InetAddressResolver}. * * @param filters A list of filters. */ ClientIpFilter(String[] filters) { + this(filters, new InetAddressResolver()); + } + + /** + * Create a new white list based on the provided filters. + * + * @param filters An array of filters. + * @param addressResolver The resolver to be used for resolving IP addresses. + */ + ClientIpFilter(String[] filters, AddressResolver addressResolver) { this.allowedIpRanges = filters; + this.addressResolver = addressResolver; } @Override @@ -139,14 +130,14 @@ class ClientIpFilter implements ClientFilter { } for (String s : this.allowedIpRanges) { - int i = s.indexOf('-'); - - if (i > 0) { - if (isAllowed(address, s.substring(0, i).trim(), s.substring(i + 1).trim())) { + String[] parts = s.split("-"); + + if (parts.length == 2 && !Pattern.matches("[a-zA-Z]+", parts[0]) && !Pattern.matches("[a-zA-Z]+", parts[1])) { + if (isAllowed(address, addressResolver, parts[0].trim(), parts[1].trim())) { return true; } } else { - if (isAllowed(address, s.trim())) { + if (isAllowed(address, addressResolver, s.trim())) { return true; } } diff --git oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/InetAddressResolver.java oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/InetAddressResolver.java new file mode 100644 index 0000000..9a92a76 --- /dev/null +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/server/InetAddressResolver.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jackrabbit.oak.segment.standby.server; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A simple implementation of {@link AddressResolver} making use of + * {@link InetAddress#getByName(String)} to resolve hosts to IP addresses. + * + */ +public class InetAddressResolver implements AddressResolver { + private static final Logger log = LoggerFactory.getLogger(InetAddressResolver.class); + + @Override + public InetAddress resolve(String host) { + InetAddress address; + + try { + address = InetAddress.getByName(host); + } catch (UnknownHostException e) { + log.warn("Unable to resolve address or invalid IP literal " + host, e); + address = null; + } + + return address; + } +} diff --git oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/server/ClientIPFilterHostnameTest.java oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/server/ClientIPFilterHostnameTest.java new file mode 100644 index 0000000..ad6daac --- /dev/null +++ oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/server/ClientIPFilterHostnameTest.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.oak.segment.standby.server; + +import static org.junit.Assert.assertEquals; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; + +import org.junit.Test; + +public class ClientIPFilterHostnameTest { + + @Test + public void testInvalidHostname() throws Exception { + String[] filters = new String[] { "foobar" }; + AddressResolver dummyAddressResolver = new AddressResolver() { + + @Override + public InetAddress resolve(String host) { + return null; + } + }; + + ClientFilter clientFilter = new ClientIpFilter(filters, dummyAddressResolver); + InetSocketAddress address = new InetSocketAddress("localhost", 8080); + assertEquals(false, clientFilter.isAllowed(address)); + } + + @Test + public void testHostnameWithDash() { + String[] filters = new String[] { "foo-bar" }; + + AddressResolver anythingToLocalhostResolver = new AddressResolver() { + + @Override + public InetAddress resolve(String host) { + InetAddress address = null; + + try { + if (host.equals("foo-bar")) { + address = InetAddress.getByName("localhost"); + } + } catch (UnknownHostException e) { + // ignore + } + + return address; + } + }; + + ClientFilter clientFilter = new ClientIpFilter(filters, anythingToLocalhostResolver); + InetSocketAddress address = new InetSocketAddress("localhost", 8080); + assertEquals(true, clientFilter.isAllowed(address)); + } + + @Test + public void testHostnameWithMultipleDashes() { + String[] filters = new String[] { "foo-bar-baz" }; + + AddressResolver anythingToLocalhostResolver = new AddressResolver() { + + @Override + public InetAddress resolve(String host) { + InetAddress address = null; + + try { + if (host.equals("foo-bar-baz")) { + address = InetAddress.getByName("localhost"); + } + } catch (UnknownHostException e) { + // ignore + } + + return address; + } + }; + + ClientFilter clientFilter = new ClientIpFilter(filters, anythingToLocalhostResolver); + InetSocketAddress address = new InetSocketAddress("localhost", 8080); + assertEquals(true, clientFilter.isAllowed(address)); + } +}