/* * 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.ftpserver.ipfilter; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.Collection; import java.util.HashSet; import java.util.concurrent.CopyOnWriteArraySet; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.firewall.Subnet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * An implementation of the <code>SessionFilter</code> interface, to filter * sessions based on the remote IP address. * * @author <a href="http://mina.apache.org">Apache MINA Project</a> * */ public class RemoteIpFilter extends CopyOnWriteArraySet<Subnet> implements SessionFilter { /** * Logger */ Logger LOGGER = LoggerFactory.getLogger(RemoteIpFilter.class); /** * Serial version UID */ private static final long serialVersionUID = 4887092372700628783L; /** * filter type */ private IpFilterType type = null; /** * Creates a new instance of <code>RemoteIpFilter</code>. * * @param type * the filter type */ public RemoteIpFilter(IpFilterType type) { this(type, new HashSet<Subnet>(0)); } /** * Creates a new instance of <code>RemoteIpFilter</code>. * * @param type * the filter type * @param collection * a collection of <code>Subnet</code>s to filter out/in. */ public RemoteIpFilter(IpFilterType type, Collection<? extends Subnet> collection) { super(collection); this.type = type; } /** * Creates a new instance of <code>RemoteIpFilter</code>. * * @param type * the filter type * @param addresses * a comma, space, tab, CR, LF separated list of IP * addresses/CIDRs. * @throws UnknownHostException * propagated * @throws NumberFormatException * propagated */ public RemoteIpFilter(IpFilterType type, String addresses) throws NumberFormatException, UnknownHostException { super(); this.type = type; if (addresses != null) { String[] tokens = addresses.split("[\\s,]+"); for (String token : tokens) { if (token.trim().length() > 0) { add(token); } } } if (LOGGER.isDebugEnabled()) { LOGGER.debug( "Created DefaultIpFilter of type {} with the subnets {}", type, this); } } /** * Returns the type of this filter. * * @return the type of this filter. */ public IpFilterType getType() { return type; } /** * Sets the type of this filter. * * @param type * the type of this filter. */ public void setType(IpFilterType type) { this.type = type; } /** * Adds the given string representation of InetAddress or CIDR notation to * this filter. * * @param str * the string representation of InetAddress or CIDR notation * @return if the given element was added or not. <code>true</code>, if the * given element was added to the filter; <code>false</code>, if the * element already exists in the filter. * @throws NumberFormatException * propagated * @throws UnknownHostException * propagated */ public boolean add(String str) throws NumberFormatException, UnknownHostException { // This is required so we do not block loopback address if some one adds // a string with blanks as the InetAddress class assumes loopback // address on a blank string. if (str.trim().length() < 1) { throw new IllegalArgumentException("Invalid IP Address or Subnet: " + str); } String[] tokens = str.split("/"); if (tokens.length == 2) { return add(new Subnet(InetAddress.getByName(tokens[0]), Integer .parseInt(tokens[1]))); } else { return add(new Subnet(InetAddress.getByName(tokens[0]), 32)); } } public boolean accept(IoSession session) { InetAddress address = ((InetSocketAddress) session.getRemoteAddress()) .getAddress(); switch (type) { case ALLOW: for (Subnet subnet : this) { if (subnet.inSubnet(address)) { if (LOGGER.isDebugEnabled()) { LOGGER .debug( "Allowing connection from {} because it matches with the whitelist subnet {}", new Object[] { address, subnet }); } return true; } } if (LOGGER.isDebugEnabled()) { LOGGER .debug( "Denying connection from {} because it does not match any of the whitelist subnets", new Object[] { address }); } return false; case DENY: if (isEmpty()) { if (LOGGER.isDebugEnabled()) { LOGGER .debug( "Allowing connection from {} because blacklist is empty", new Object[] { address }); } return true; } for (Subnet subnet : this) { if (subnet.inSubnet(address)) { if (LOGGER.isDebugEnabled()) { LOGGER .debug( "Denying connection from {} because it matches with the blacklist subnet {}", new Object[] { address, subnet }); } return false; } } if (LOGGER.isDebugEnabled()) { LOGGER .debug( "Allowing connection from {} because it does not match any of the blacklist subnets", new Object[] { address }); } return true; default: throw new RuntimeException("Unknown or unimplemented filter type: " + type); } } }