Overall clean-up of ipfilter package
Motivation: Recently merged ipfilter package has the following problems: * AbstractIpFilterHandler could be improved to support any SocketAddress types rather than only InetSocketAddress. * AbstractIpFilterHandler can be removed immediately after decision is made rather than keeping the outcome of the decision as an attribute. * AbstractIpFilterHandler doesn't have a hook for the accepted addresses. * The hook method (reject()) needs to be named in line with other handler methods (i.e. channelRejected()) * IpFilterRuleHandler should allow accepting zero rules - it's particularly useful for machine-configured setup (i.e. specifying zero rules disables ipfilter). * IpFilterRuleType.ALLOW/DENY should be ACCEPT/REJECT for consistency. Modifications: * AbstractIpFilterHandler has been renamed to AbstractRemoteAddressFilter and now uses type parameter. * Added channelAccepted() and renamed reject() to channelRejected() * Added ChannelHandlerContext as a parameter of accept() so that accept() can add a listener to the closeFuture() of the channel. This way, UniqueIpFilter continue working even if we remove the filtering handler early. * Various renames * IpFilterRuleHandler -> RuleBasedIpFilter * UniqueIpFilterHandler -> UniqueIpFilter Result: * Much cleaner API with more extensibility
This commit is contained in:
parent
229c14ccdb
commit
fddbde7df2
@ -1,99 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2014 The Netty Project
|
|
||||||
*
|
|
||||||
* The Netty Project 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 io.netty.handler.ipfilter;
|
|
||||||
|
|
||||||
import io.netty.channel.Channel;
|
|
||||||
import io.netty.channel.ChannelFuture;
|
|
||||||
import io.netty.channel.ChannelFutureListener;
|
|
||||||
import io.netty.channel.ChannelHandlerAdapter;
|
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
|
||||||
import io.netty.util.Attribute;
|
|
||||||
import io.netty.util.AttributeKey;
|
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class provides the functionality to either accept or reject new {@link Channel}s
|
|
||||||
* based on their IP address.
|
|
||||||
* <p>
|
|
||||||
* You should inherit from this class if you would like to implement your own IP-based filter. Basically you have to
|
|
||||||
* implement {@link #accept(InetSocketAddress)} to decided whether you want to allow or deny a connection from an IP
|
|
||||||
* address. Furthermore overriding {@link #rejected(ChannelHandlerContext, InetSocketAddress)} gives you the flexibility
|
|
||||||
* to respond to rejected (denied) connections. If you do not want to send a response, just have it return null.
|
|
||||||
* Take a look at {@link IpFilterRuleHandler} for details.
|
|
||||||
*/
|
|
||||||
public abstract class AbstractIpFilterHandler extends ChannelHandlerAdapter {
|
|
||||||
private final AttributeKey<IpFilterDecision> decisionKey = AttributeKey.valueOf(getClass().getName());
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
|
|
||||||
final InetSocketAddress ipAddress = (InetSocketAddress) ctx.channel().remoteAddress();
|
|
||||||
|
|
||||||
if (!accept(ipAddress)) {
|
|
||||||
// the channel might be active already
|
|
||||||
if (ctx.channel().isActive()) {
|
|
||||||
handleRejected(ctx);
|
|
||||||
} else {
|
|
||||||
// if the channel is not active yet, store the decision for later use
|
|
||||||
// in #channelActive(ChannelHandlerContext ctx)
|
|
||||||
Attribute<IpFilterDecision> decision = ctx.attr(decisionKey);
|
|
||||||
decision.set(IpFilterDecision.REJECTED);
|
|
||||||
|
|
||||||
super.channelRegistered(ctx);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
super.channelRegistered(ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
|
||||||
final IpFilterDecision decision = ctx.attr(decisionKey).get();
|
|
||||||
|
|
||||||
if (decision == IpFilterDecision.REJECTED) {
|
|
||||||
handleRejected(ctx);
|
|
||||||
} else {
|
|
||||||
super.channelActive(ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleRejected(ChannelHandlerContext ctx) {
|
|
||||||
final InetSocketAddress ipAddress = (InetSocketAddress) ctx.channel().remoteAddress();
|
|
||||||
|
|
||||||
ChannelFuture rejectedFuture = rejected(ctx, ipAddress);
|
|
||||||
if (rejectedFuture != null) {
|
|
||||||
rejectedFuture.addListener(ChannelFutureListener.CLOSE);
|
|
||||||
} else {
|
|
||||||
ctx.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is called immediately after a {@link io.netty.channel.Channel} gets registered.
|
|
||||||
*
|
|
||||||
* @return Return true if connections from this IP address and port should be accepted. False otherwise.
|
|
||||||
*/
|
|
||||||
protected abstract boolean accept(InetSocketAddress ipAndPort) throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is called if ipAndPort gets rejected by {@link #accept(InetSocketAddress)}.
|
|
||||||
* You should override it if you would like to handle (e.g. respond to) rejected addresses.
|
|
||||||
*
|
|
||||||
* @return A {@link ChannelFuture} if you perform I/O operations, so that
|
|
||||||
* the {@link Channel} can be closed once it completes. Null otherwise.
|
|
||||||
*/
|
|
||||||
protected abstract ChannelFuture rejected(ChannelHandlerContext ctx, InetSocketAddress ipAndPort);
|
|
||||||
}
|
|
@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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 io.netty.handler.ipfilter;
|
||||||
|
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelFuture;
|
||||||
|
import io.netty.channel.ChannelFutureListener;
|
||||||
|
import io.netty.channel.ChannelHandlerAdapter;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides the functionality to either accept or reject new {@link Channel}s
|
||||||
|
* based on their IP address.
|
||||||
|
* <p>
|
||||||
|
* You should inherit from this class if you would like to implement your own IP-based filter. Basically you have to
|
||||||
|
* implement {@link #accept(ChannelHandlerContext, SocketAddress)} to decided whether you want to accept or reject
|
||||||
|
* a connection from the remote address.
|
||||||
|
* <p>
|
||||||
|
* Furthermore overriding {@link #channelRejected(ChannelHandlerContext, SocketAddress)} gives you the
|
||||||
|
* flexibility to respond to rejected (denied) connections. If you do not want to send a response, just have it return
|
||||||
|
* null. Take a look at {@link RuleBasedIpFilter} for details.
|
||||||
|
*/
|
||||||
|
public abstract class AbstractRemoteAddressFilter<T extends SocketAddress> extends ChannelHandlerAdapter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
try {
|
||||||
|
handleNewChannel(ctx);
|
||||||
|
} finally {
|
||||||
|
ctx.fireChannelRegistered();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
try {
|
||||||
|
if (!handleNewChannel(ctx)) {
|
||||||
|
throw new IllegalStateException("cannot determine to accept or reject a channel: " + ctx.channel());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
ctx.fireChannelActive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean handleNewChannel(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
T remoteAddress = (T) ctx.channel().remoteAddress();
|
||||||
|
|
||||||
|
// If the remote address is not available yet, defer the decision.
|
||||||
|
if (remoteAddress == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need to keep this handler in the pipeline anymore because the decision is going to be made now.
|
||||||
|
// Also, this will prevent the subsequent events from being handled by this handler.
|
||||||
|
ctx.pipeline().remove(this);
|
||||||
|
|
||||||
|
if (accept(ctx, remoteAddress)) {
|
||||||
|
channelAccepted(ctx, remoteAddress);
|
||||||
|
} else {
|
||||||
|
ChannelFuture rejectedFuture = channelRejected(ctx, remoteAddress);
|
||||||
|
if (rejectedFuture != null) {
|
||||||
|
rejectedFuture.addListener(ChannelFutureListener.CLOSE);
|
||||||
|
} else {
|
||||||
|
ctx.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called immediately after a {@link io.netty.channel.Channel} gets registered.
|
||||||
|
*
|
||||||
|
* @return Return true if connections from this IP address and port should be accepted. False otherwise.
|
||||||
|
*/
|
||||||
|
protected abstract boolean accept(ChannelHandlerContext ctx, T remoteAddress) throws Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called if {@code remoteAddress} gets accepted by
|
||||||
|
* {@link #accept(ChannelHandlerContext, SocketAddress)}. You should override it if you would like to handle
|
||||||
|
* (e.g. respond to) accepted addresses.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("UnusedParameters")
|
||||||
|
protected void channelAccepted(ChannelHandlerContext ctx, T remoteAddress) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called if {@code remoteAddress} gets rejected by
|
||||||
|
* {@link #accept(ChannelHandlerContext, SocketAddress)}. You should override it if you would like to handle
|
||||||
|
* (e.g. respond to) rejected addresses.
|
||||||
|
*
|
||||||
|
* @return A {@link ChannelFuture} if you perform I/O operations, so that
|
||||||
|
* the {@link Channel} can be closed once it completes. Null otherwise.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("UnusedParameters")
|
||||||
|
protected ChannelFuture channelRejected(ChannelHandlerContext ctx, T remoteAddress) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2014 The Netty Project
|
|
||||||
*
|
|
||||||
* The Netty Project 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 io.netty.handler.ipfilter;
|
|
||||||
|
|
||||||
import io.netty.channel.ChannelHandler;
|
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This enum is used in {@link AbstractIpFilterHandler} to keep the state between the calls to
|
|
||||||
* {@link ChannelHandler#channelRegistered(ChannelHandlerContext)} and
|
|
||||||
* {@link ChannelHandler#channelActive(ChannelHandlerContext)}.
|
|
||||||
*/
|
|
||||||
public enum IpFilterDecision {
|
|
||||||
REJECTED
|
|
||||||
}
|
|
@ -22,15 +22,15 @@ import java.net.InetSocketAddress;
|
|||||||
*/
|
*/
|
||||||
public interface IpFilterRule {
|
public interface IpFilterRule {
|
||||||
/**
|
/**
|
||||||
* @return This method should return true if ipAndPort is valid according to your criteria. False otherwise.
|
* @return This method should return true if remoteAddress is valid according to your criteria. False otherwise.
|
||||||
*/
|
*/
|
||||||
boolean matches(InetSocketAddress ipAndPort);
|
boolean matches(InetSocketAddress remoteAddress);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return This method should return {@link IpFilterRuleType#ALLOW} if all
|
* @return This method should return {@link IpFilterRuleType#ACCEPT} if all
|
||||||
* {@link IpFilterRule#matches(InetSocketAddress)} for which {@link #matches(InetSocketAddress)}
|
* {@link IpFilterRule#matches(InetSocketAddress)} for which {@link #matches(InetSocketAddress)}
|
||||||
* returns true should the accepted. If you want to exclude all of those IP addresses then
|
* returns true should the accepted. If you want to exclude all of those IP addresses then
|
||||||
* {@link IpFilterRuleType#DENY} should be returned.
|
* {@link IpFilterRuleType#REJECT} should be returned.
|
||||||
*/
|
*/
|
||||||
IpFilterRuleType ruleType();
|
IpFilterRuleType ruleType();
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,6 @@ package io.netty.handler.ipfilter;
|
|||||||
* Used in {@link IpFilterRule} to decide if a matching IP Address should be allowed or denied to connect.
|
* Used in {@link IpFilterRule} to decide if a matching IP Address should be allowed or denied to connect.
|
||||||
*/
|
*/
|
||||||
public enum IpFilterRuleType {
|
public enum IpFilterRuleType {
|
||||||
ALLOW,
|
ACCEPT,
|
||||||
DENY
|
REJECT
|
||||||
}
|
}
|
||||||
|
@ -23,10 +23,11 @@ import java.net.InetSocketAddress;
|
|||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use this class to create rules for {@link IpFilterRuleHandler} that group IP addresses into subnets.
|
* Use this class to create rules for {@link RuleBasedIpFilter} that group IP addresses into subnets.
|
||||||
* Supports both, IPv4 and IPv6.
|
* Supports both, IPv4 and IPv6.
|
||||||
*/
|
*/
|
||||||
public final class IpSubnetFilterRule implements IpFilterRule {
|
public final class IpSubnetFilterRule implements IpFilterRule {
|
||||||
|
|
||||||
private final IpFilterRule filterRule;
|
private final IpFilterRule filterRule;
|
||||||
|
|
||||||
public IpSubnetFilterRule(String ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
|
public IpSubnetFilterRule(String ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
|
||||||
@ -60,8 +61,8 @@ public final class IpSubnetFilterRule implements IpFilterRule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(InetSocketAddress ipAndPort) {
|
public boolean matches(InetSocketAddress remoteAddress) {
|
||||||
return filterRule.matches(ipAndPort);
|
return filterRule.matches(remoteAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -87,8 +88,8 @@ public final class IpSubnetFilterRule implements IpFilterRule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(InetSocketAddress ipAndPort) {
|
public boolean matches(InetSocketAddress remoteAddress) {
|
||||||
int ipAddress = ipToInt((Inet4Address) ipAndPort.getAddress());
|
int ipAddress = ipToInt((Inet4Address) remoteAddress.getAddress());
|
||||||
|
|
||||||
return (ipAddress & subnetMask) == networkAddress;
|
return (ipAddress & subnetMask) == networkAddress;
|
||||||
}
|
}
|
||||||
@ -133,8 +134,8 @@ public final class IpSubnetFilterRule implements IpFilterRule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(InetSocketAddress ipAndPort) {
|
public boolean matches(InetSocketAddress remoteAddress) {
|
||||||
BigInteger ipAddress = ipToInt((Inet6Address) ipAndPort.getAddress());
|
BigInteger ipAddress = ipToInt((Inet6Address) remoteAddress.getAddress());
|
||||||
|
|
||||||
return ipAddress.and(subnetMask).equals(networkAddress);
|
return ipAddress.and(subnetMask).equals(networkAddress);
|
||||||
}
|
}
|
||||||
|
@ -15,11 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.handler.ipfilter;
|
package io.netty.handler.ipfilter;
|
||||||
|
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.channel.ChannelHandler.Sharable;
|
import io.netty.channel.ChannelHandler.Sharable;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.Channel;
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class allows one to filter new {@link Channel}s based on the
|
* This class allows one to filter new {@link Channel}s based on the
|
||||||
@ -27,36 +28,33 @@ import java.net.InetSocketAddress;
|
|||||||
* will be accepted.
|
* will be accepted.
|
||||||
*
|
*
|
||||||
* If you would like to explicitly take action on rejected {@link Channel}s, you should override
|
* If you would like to explicitly take action on rejected {@link Channel}s, you should override
|
||||||
* {@link #rejected(ChannelHandlerContext, InetSocketAddress)}.
|
* {@link #channelRejected(ChannelHandlerContext, SocketAddress)}.
|
||||||
*/
|
*/
|
||||||
@Sharable
|
@Sharable
|
||||||
public class IpFilterRuleHandler extends AbstractIpFilterHandler {
|
public class RuleBasedIpFilter extends AbstractRemoteAddressFilter<InetSocketAddress> {
|
||||||
|
|
||||||
private final IpFilterRule[] rules;
|
private final IpFilterRule[] rules;
|
||||||
|
|
||||||
public IpFilterRuleHandler(IpFilterRule... rules) {
|
public RuleBasedIpFilter(IpFilterRule... rules) {
|
||||||
if (rules == null) {
|
if (rules == null) {
|
||||||
throw new NullPointerException("rules");
|
throw new NullPointerException("rules");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rules.length == 0) {
|
|
||||||
throw new IllegalArgumentException("You have to provide at least one rule.");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.rules = rules;
|
this.rules = rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean accept(InetSocketAddress ipAndPort) throws Exception {
|
protected boolean accept(ChannelHandlerContext ctx, InetSocketAddress remoteAddress) throws Exception {
|
||||||
for (IpFilterRule rule : rules) {
|
for (IpFilterRule rule : rules) {
|
||||||
if (rule.matches(ipAndPort)) {
|
if (rule == null) {
|
||||||
return rule.ruleType() == IpFilterRuleType.ALLOW;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rule.matches(remoteAddress)) {
|
||||||
|
return rule.ruleType() == IpFilterRuleType.ACCEPT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ChannelFuture rejected(ChannelHandlerContext ctx, InetSocketAddress ipAndPort) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -15,11 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.handler.ipfilter;
|
package io.netty.handler.ipfilter;
|
||||||
|
|
||||||
|
import io.netty.channel.Channel;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
|
import io.netty.channel.ChannelFutureListener;
|
||||||
import io.netty.channel.ChannelHandler;
|
import io.netty.channel.ChannelHandler;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.util.internal.ConcurrentSet;
|
import io.netty.util.internal.ConcurrentSet;
|
||||||
import io.netty.channel.Channel;
|
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
@ -30,30 +31,24 @@ import java.util.Set;
|
|||||||
* {@link Channel} connected to the server.
|
* {@link Channel} connected to the server.
|
||||||
*/
|
*/
|
||||||
@ChannelHandler.Sharable
|
@ChannelHandler.Sharable
|
||||||
public class UniqueIpFilterHandler extends AbstractIpFilterHandler {
|
public class UniqueIpFilter extends AbstractRemoteAddressFilter<InetSocketAddress> {
|
||||||
|
|
||||||
private final Set<InetAddress> connected = new ConcurrentSet<InetAddress>();
|
private final Set<InetAddress> connected = new ConcurrentSet<InetAddress>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean accept(InetSocketAddress ipAndPort) throws Exception {
|
protected boolean accept(ChannelHandlerContext ctx, InetSocketAddress remoteAddress) throws Exception {
|
||||||
InetAddress ipAddress = ipAndPort.getAddress();
|
final InetAddress remoteIp = remoteAddress.getAddress();
|
||||||
if (connected.contains(ipAddress)) {
|
if (connected.contains(remoteIp)) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
connected.add(ipAddress);
|
connected.add(remoteIp);
|
||||||
|
ctx.channel().closeFuture().addListener(new ChannelFutureListener() {
|
||||||
|
@Override
|
||||||
|
public void operationComplete(ChannelFuture future) throws Exception {
|
||||||
|
connected.remove(remoteIp);
|
||||||
|
}
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
|
||||||
InetAddress ipAddress = ((InetSocketAddress) ctx.channel().remoteAddress()).getAddress();
|
|
||||||
connected.remove(ipAddress);
|
|
||||||
|
|
||||||
super.channelInactive(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ChannelFuture rejected(ChannelHandlerContext ctx, InetSocketAddress ipAndPort) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -31,13 +31,13 @@ public class IpSubnetFilterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIp4SubnetFilterRule() throws Exception {
|
public void testIp4SubnetFilterRule() throws Exception {
|
||||||
IpSubnetFilterRule rule = new IpSubnetFilterRule("192.168.56.1", 24, IpFilterRuleType.ALLOW);
|
IpSubnetFilterRule rule = new IpSubnetFilterRule("192.168.56.1", 24, IpFilterRuleType.ACCEPT);
|
||||||
for (int i = 0; i <= 255; i++) {
|
for (int i = 0; i <= 255; i++) {
|
||||||
Assert.assertTrue(rule.matches(newSockAddress(String.format("192.168.56.%d", i))));
|
Assert.assertTrue(rule.matches(newSockAddress(String.format("192.168.56.%d", i))));
|
||||||
}
|
}
|
||||||
Assert.assertFalse(rule.matches(newSockAddress("192.168.57.1")));
|
Assert.assertFalse(rule.matches(newSockAddress("192.168.57.1")));
|
||||||
|
|
||||||
rule = new IpSubnetFilterRule("91.114.240.1", 23, IpFilterRuleType.ALLOW);
|
rule = new IpSubnetFilterRule("91.114.240.1", 23, IpFilterRuleType.ACCEPT);
|
||||||
Assert.assertTrue(rule.matches(newSockAddress("91.114.240.43")));
|
Assert.assertTrue(rule.matches(newSockAddress("91.114.240.43")));
|
||||||
Assert.assertTrue(rule.matches(newSockAddress("91.114.240.255")));
|
Assert.assertTrue(rule.matches(newSockAddress("91.114.240.255")));
|
||||||
Assert.assertTrue(rule.matches(newSockAddress("91.114.241.193")));
|
Assert.assertTrue(rule.matches(newSockAddress("91.114.241.193")));
|
||||||
@ -49,7 +49,7 @@ public class IpSubnetFilterTest {
|
|||||||
public void testIp6SubnetFilterRule() {
|
public void testIp6SubnetFilterRule() {
|
||||||
IpSubnetFilterRule rule;
|
IpSubnetFilterRule rule;
|
||||||
|
|
||||||
rule = new IpSubnetFilterRule("2001:db8:abcd:0000::", 52, IpFilterRuleType.ALLOW);
|
rule = new IpSubnetFilterRule("2001:db8:abcd:0000::", 52, IpFilterRuleType.ACCEPT);
|
||||||
Assert.assertTrue(rule.matches(newSockAddress("2001:db8:abcd:0000::1")));
|
Assert.assertTrue(rule.matches(newSockAddress("2001:db8:abcd:0000::1")));
|
||||||
Assert.assertTrue(rule.matches(newSockAddress("2001:db8:abcd:0fff:ffff:ffff:ffff:ffff")));
|
Assert.assertTrue(rule.matches(newSockAddress("2001:db8:abcd:0fff:ffff:ffff:ffff:ffff")));
|
||||||
Assert.assertFalse(rule.matches(newSockAddress("2001:db8:abcd:1000::")));
|
Assert.assertFalse(rule.matches(newSockAddress("2001:db8:abcd:1000::")));
|
||||||
@ -59,24 +59,24 @@ public class IpSubnetFilterTest {
|
|||||||
public void testIpFilterRuleHandler() throws Exception {
|
public void testIpFilterRuleHandler() throws Exception {
|
||||||
IpFilterRule filter0 = new IpFilterRule() {
|
IpFilterRule filter0 = new IpFilterRule() {
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(InetSocketAddress ipAndPort) {
|
public boolean matches(InetSocketAddress remoteAddress) {
|
||||||
return "192.168.57.1".equals(ipAndPort.getHostName());
|
return "192.168.57.1".equals(remoteAddress.getHostName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IpFilterRuleType ruleType() {
|
public IpFilterRuleType ruleType() {
|
||||||
return IpFilterRuleType.DENY;
|
return IpFilterRuleType.REJECT;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
IpFilterRuleHandler denyHandler = new IpFilterRuleHandler(filter0) {
|
RuleBasedIpFilter denyHandler = new RuleBasedIpFilter(filter0) {
|
||||||
private final byte[] message = {1, 2, 3, 4, 5, 6, 7};
|
private final byte[] message = {1, 2, 3, 4, 5, 6, 7};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ChannelFuture rejected(ChannelHandlerContext ctx, InetSocketAddress ipAndPort) {
|
protected ChannelFuture channelRejected(ChannelHandlerContext ctx, InetSocketAddress remoteAddress) {
|
||||||
Assert.assertTrue(ctx.channel().isActive());
|
Assert.assertTrue(ctx.channel().isActive());
|
||||||
Assert.assertTrue(ctx.channel().isWritable());
|
Assert.assertTrue(ctx.channel().isWritable());
|
||||||
Assert.assertEquals("192.168.57.1", ipAndPort.getHostName());
|
Assert.assertEquals("192.168.57.1", remoteAddress.getHostName());
|
||||||
|
|
||||||
return ctx.writeAndFlush(Unpooled.wrappedBuffer(message));
|
return ctx.writeAndFlush(Unpooled.wrappedBuffer(message));
|
||||||
}
|
}
|
||||||
@ -90,9 +90,9 @@ public class IpSubnetFilterTest {
|
|||||||
Assert.assertFalse(chDeny.isActive());
|
Assert.assertFalse(chDeny.isActive());
|
||||||
Assert.assertFalse(chDeny.isOpen());
|
Assert.assertFalse(chDeny.isOpen());
|
||||||
|
|
||||||
IpFilterRuleHandler allowHandler = new IpFilterRuleHandler(filter0) {
|
RuleBasedIpFilter allowHandler = new RuleBasedIpFilter(filter0) {
|
||||||
@Override
|
@Override
|
||||||
protected ChannelFuture rejected(ChannelHandlerContext ctx, InetSocketAddress ipAndPort) {
|
protected ChannelFuture channelRejected(ChannelHandlerContext ctx, InetSocketAddress remoteAddress) {
|
||||||
Assert.fail();
|
Assert.fail();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -104,7 +104,7 @@ public class IpSubnetFilterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUniqueIpFilterHandler() {
|
public void testUniqueIpFilterHandler() {
|
||||||
UniqueIpFilterHandler handler = new UniqueIpFilterHandler();
|
UniqueIpFilter handler = new UniqueIpFilter();
|
||||||
|
|
||||||
EmbeddedChannel ch1 = newEmbeddedInetChannel("91.92.93.1", handler);
|
EmbeddedChannel ch1 = newEmbeddedInetChannel("91.92.93.1", handler);
|
||||||
Assert.assertTrue(ch1.isActive());
|
Assert.assertTrue(ch1.isActive());
|
||||||
|
Loading…
Reference in New Issue
Block a user