Backport ipfilter handler
Motivation: The ipfilter handler does not exists in 4.0 yet. Modifications: Backport the ipfilter from 4.1 to 4.0. Result: It's possible to use the ipfilter handler in 4.0 as well.
This commit is contained in:
parent
16d136dc55
commit
a0bde17eff
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
|
||||
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 ChannelInboundHandlerAdapter {
|
||||
|
||||
@Override
|
||||
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
|
||||
handleNewChannel(ctx);
|
||||
ctx.fireChannelRegistered();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
if (!handleNewChannel(ctx)) {
|
||||
throw new IllegalStateException("cannot determine to accept or reject a channel: " + ctx.channel());
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 java.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
* Implement this interface to create new rules.
|
||||
*/
|
||||
public interface IpFilterRule {
|
||||
/**
|
||||
* @return This method should return true if remoteAddress is valid according to your criteria. False otherwise.
|
||||
*/
|
||||
boolean matches(InetSocketAddress remoteAddress);
|
||||
|
||||
/**
|
||||
* @return This method should return {@link IpFilterRuleType#Accept} if all
|
||||
* {@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
|
||||
* {@link IpFilterRuleType#Reject} should be returned.
|
||||
*/
|
||||
IpFilterRuleType ruleType();
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Used in {@link IpFilterRule} to decide if a matching IP Address should be allowed or denied to connect.
|
||||
*/
|
||||
public enum IpFilterRuleType {
|
||||
Accept,
|
||||
Reject
|
||||
}
|
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* 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 java.math.BigInteger;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
/**
|
||||
* Use this class to create rules for {@link RuleBasedIpFilter} that group IP addresses into subnets.
|
||||
* Supports both, IPv4 and IPv6.
|
||||
*/
|
||||
public final class IpSubnetFilterRule implements IpFilterRule {
|
||||
|
||||
private final IpFilterRule filterRule;
|
||||
|
||||
public IpSubnetFilterRule(String ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
|
||||
try {
|
||||
filterRule = selectFilterRule(InetAddress.getByName(ipAddress), cidrPrefix, ruleType);
|
||||
} catch (UnknownHostException e) {
|
||||
throw new IllegalArgumentException("ipAddress", e);
|
||||
}
|
||||
}
|
||||
|
||||
public IpSubnetFilterRule(InetAddress ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
|
||||
filterRule = selectFilterRule(ipAddress, cidrPrefix, ruleType);
|
||||
}
|
||||
|
||||
private static IpFilterRule selectFilterRule(InetAddress ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
|
||||
if (ipAddress == null) {
|
||||
throw new NullPointerException("ipAddress");
|
||||
}
|
||||
|
||||
if (ruleType == null) {
|
||||
throw new NullPointerException("ruleType");
|
||||
}
|
||||
|
||||
if (ipAddress instanceof Inet4Address) {
|
||||
return new Ip4SubnetFilterRule((Inet4Address) ipAddress, cidrPrefix, ruleType);
|
||||
} else if (ipAddress instanceof Inet6Address) {
|
||||
return new Ip6SubnetFilterRule((Inet6Address) ipAddress, cidrPrefix, ruleType);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Only IPv4 and IPv6 addresses are supported");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(InetSocketAddress remoteAddress) {
|
||||
return filterRule.matches(remoteAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IpFilterRuleType ruleType() {
|
||||
return filterRule.ruleType();
|
||||
}
|
||||
|
||||
private static final class Ip4SubnetFilterRule implements IpFilterRule {
|
||||
|
||||
private final int networkAddress;
|
||||
private final int subnetMask;
|
||||
private final IpFilterRuleType ruleType;
|
||||
|
||||
private Ip4SubnetFilterRule(Inet4Address ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
|
||||
if (cidrPrefix < 0 || cidrPrefix > 32) {
|
||||
throw new IllegalArgumentException(String.format("IPv4 requires the subnet prefix to be in range of " +
|
||||
"[0,32]. The prefix was: %d", cidrPrefix));
|
||||
}
|
||||
|
||||
subnetMask = prefixToSubnetMask(cidrPrefix);
|
||||
networkAddress = ipToInt(ipAddress) & subnetMask;
|
||||
this.ruleType = ruleType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(InetSocketAddress remoteAddress) {
|
||||
int ipAddress = ipToInt((Inet4Address) remoteAddress.getAddress());
|
||||
|
||||
return (ipAddress & subnetMask) == networkAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IpFilterRuleType ruleType() {
|
||||
return ruleType;
|
||||
}
|
||||
|
||||
private static int ipToInt(Inet4Address ipAddress) {
|
||||
byte[] octets = ipAddress.getAddress();
|
||||
assert octets.length == 4;
|
||||
|
||||
return (octets[0] & 0xff) << 24 |
|
||||
(octets[1] & 0xff) << 16 |
|
||||
(octets[2] & 0xff) << 8 |
|
||||
octets[3] & 0xff;
|
||||
}
|
||||
|
||||
private static int prefixToSubnetMask(int cidrPrefix) {
|
||||
/**
|
||||
* Perform the shift on a long and downcast it to int afterwards.
|
||||
* This is necessary to handle a cidrPrefix of zero correctly.
|
||||
* The left shift operator on an int only uses the five least
|
||||
* significant bits of the right-hand operand. Thus -1 << 32 evaluates
|
||||
* to -1 instead of 0. The left shift operator applied on a long
|
||||
* uses the six least significant bits.
|
||||
*
|
||||
* Also see https://github.com/netty/netty/issues/2767
|
||||
*/
|
||||
return (int) ((-1L << 32 - cidrPrefix) & 0xffffffff);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Ip6SubnetFilterRule implements IpFilterRule {
|
||||
|
||||
private static final BigInteger MINUS_ONE = BigInteger.valueOf(-1);
|
||||
|
||||
private final BigInteger networkAddress;
|
||||
private final BigInteger subnetMask;
|
||||
private final IpFilterRuleType ruleType;
|
||||
|
||||
private Ip6SubnetFilterRule(Inet6Address ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
|
||||
if (cidrPrefix < 0 || cidrPrefix > 128) {
|
||||
throw new IllegalArgumentException(String.format("IPv6 requires the subnet prefix to be in range of " +
|
||||
"[0,128]. The prefix was: %d", cidrPrefix));
|
||||
}
|
||||
|
||||
subnetMask = prefixToSubnetMask(cidrPrefix);
|
||||
networkAddress = ipToInt(ipAddress).and(subnetMask);
|
||||
this.ruleType = ruleType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(InetSocketAddress remoteAddress) {
|
||||
BigInteger ipAddress = ipToInt((Inet6Address) remoteAddress.getAddress());
|
||||
|
||||
return ipAddress.and(subnetMask).equals(networkAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IpFilterRuleType ruleType() {
|
||||
return ruleType;
|
||||
}
|
||||
|
||||
private static BigInteger ipToInt(Inet6Address ipAddress) {
|
||||
byte[] octets = ipAddress.getAddress();
|
||||
assert octets.length == 16;
|
||||
|
||||
return new BigInteger(octets);
|
||||
}
|
||||
|
||||
private static BigInteger prefixToSubnetMask(int cidrPrefix) {
|
||||
return MINUS_ONE.shiftLeft(128 - cidrPrefix);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.ChannelHandler.Sharable;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
|
||||
/**
|
||||
* This class allows one to filter new {@link Channel}s based on the
|
||||
* {@link IpFilterRule}s passed to its constructor. If no rules are provided, all connections
|
||||
* will be accepted.
|
||||
*
|
||||
* If you would like to explicitly take action on rejected {@link Channel}s, you should override
|
||||
* {@link #channelRejected(ChannelHandlerContext, SocketAddress)}.
|
||||
*/
|
||||
@Sharable
|
||||
public class RuleBasedIpFilter extends AbstractRemoteAddressFilter<InetSocketAddress> {
|
||||
|
||||
private final IpFilterRule[] rules;
|
||||
|
||||
public RuleBasedIpFilter(IpFilterRule... rules) {
|
||||
if (rules == null) {
|
||||
throw new NullPointerException("rules");
|
||||
}
|
||||
|
||||
this.rules = rules;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean accept(ChannelHandlerContext ctx, InetSocketAddress remoteAddress) throws Exception {
|
||||
for (IpFilterRule rule : rules) {
|
||||
if (rule == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (rule.matches(remoteAddress)) {
|
||||
return rule.ruleType() == IpFilterRuleType.Accept;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.util.internal.ConcurrentSet;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* This class allows one to ensure that at all times for every IP address there is at most one
|
||||
* {@link Channel} connected to the server.
|
||||
*/
|
||||
@ChannelHandler.Sharable
|
||||
public class UniqueIpFilter extends AbstractRemoteAddressFilter<InetSocketAddress> {
|
||||
|
||||
private final Set<InetAddress> connected = new ConcurrentSet<InetAddress>();
|
||||
|
||||
@Override
|
||||
protected boolean accept(ChannelHandlerContext ctx, InetSocketAddress remoteAddress) throws Exception {
|
||||
final InetAddress remoteIp = remoteAddress.getAddress();
|
||||
if (connected.contains(remoteIp)) {
|
||||
return false;
|
||||
} else {
|
||||
connected.add(remoteIp);
|
||||
ctx.channel().closeFuture().addListener(new ChannelFutureListener() {
|
||||
@Override
|
||||
public void operationComplete(ChannelFuture future) throws Exception {
|
||||
connected.remove(remoteIp);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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 to filter IP addresses (allow/deny).
|
||||
*/
|
||||
package io.netty.handler.ipfilter;
|
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
|
||||
public class IpSubnetFilterTest {
|
||||
|
||||
@Test
|
||||
public void testIpv4DefaultRoute() {
|
||||
IpSubnetFilterRule rule = new IpSubnetFilterRule("0.0.0.0", 0, IpFilterRuleType.Accept);
|
||||
Assert.assertTrue(rule.matches(newSockAddress("91.114.240.43")));
|
||||
Assert.assertTrue(rule.matches(newSockAddress("10.0.0.3")));
|
||||
Assert.assertTrue(rule.matches(newSockAddress("192.168.93.2")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIp4SubnetFilterRule() throws Exception {
|
||||
IpSubnetFilterRule rule = new IpSubnetFilterRule("192.168.56.1", 24, IpFilterRuleType.Accept);
|
||||
for (int i = 0; i <= 255; i++) {
|
||||
Assert.assertTrue(rule.matches(newSockAddress(String.format("192.168.56.%d", i))));
|
||||
}
|
||||
Assert.assertFalse(rule.matches(newSockAddress("192.168.57.1")));
|
||||
|
||||
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.255")));
|
||||
Assert.assertTrue(rule.matches(newSockAddress("91.114.241.193")));
|
||||
Assert.assertTrue(rule.matches(newSockAddress("91.114.241.254")));
|
||||
Assert.assertFalse(rule.matches(newSockAddress("91.115.241.2")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIp6SubnetFilterRule() {
|
||||
IpSubnetFilterRule rule;
|
||||
|
||||
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:0fff:ffff:ffff:ffff:ffff")));
|
||||
Assert.assertFalse(rule.matches(newSockAddress("2001:db8:abcd:1000::")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIpFilterRuleHandler() throws Exception {
|
||||
IpFilterRule filter0 = new IpFilterRule() {
|
||||
@Override
|
||||
public boolean matches(InetSocketAddress remoteAddress) {
|
||||
return "192.168.57.1".equals(remoteAddress.getHostName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public IpFilterRuleType ruleType() {
|
||||
return IpFilterRuleType.Reject;
|
||||
}
|
||||
};
|
||||
|
||||
RuleBasedIpFilter denyHandler = new RuleBasedIpFilter(filter0) {
|
||||
private final byte[] message = {1, 2, 3, 4, 5, 6, 7};
|
||||
|
||||
@Override
|
||||
protected ChannelFuture channelRejected(ChannelHandlerContext ctx, InetSocketAddress remoteAddress) {
|
||||
Assert.assertTrue(ctx.channel().isActive());
|
||||
Assert.assertTrue(ctx.channel().isWritable());
|
||||
Assert.assertEquals("192.168.57.1", remoteAddress.getHostName());
|
||||
|
||||
return ctx.writeAndFlush(Unpooled.wrappedBuffer(message));
|
||||
}
|
||||
};
|
||||
EmbeddedChannel chDeny = newEmbeddedInetChannel("192.168.57.1", denyHandler);
|
||||
ByteBuf out = (ByteBuf) chDeny.readOutbound();
|
||||
Assert.assertEquals(7, out.readableBytes());
|
||||
for (byte i = 1; i <= 7; i++) {
|
||||
Assert.assertEquals(i, out.readByte());
|
||||
}
|
||||
Assert.assertFalse(chDeny.isActive());
|
||||
Assert.assertFalse(chDeny.isOpen());
|
||||
|
||||
RuleBasedIpFilter allowHandler = new RuleBasedIpFilter(filter0) {
|
||||
@Override
|
||||
protected ChannelFuture channelRejected(ChannelHandlerContext ctx, InetSocketAddress remoteAddress) {
|
||||
Assert.fail();
|
||||
return null;
|
||||
}
|
||||
};
|
||||
EmbeddedChannel chAllow = newEmbeddedInetChannel("192.168.57.2", allowHandler);
|
||||
Assert.assertTrue(chAllow.isActive());
|
||||
Assert.assertTrue(chAllow.isOpen());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUniqueIpFilterHandler() {
|
||||
UniqueIpFilter handler = new UniqueIpFilter();
|
||||
|
||||
EmbeddedChannel ch1 = newEmbeddedInetChannel("91.92.93.1", handler);
|
||||
Assert.assertTrue(ch1.isActive());
|
||||
EmbeddedChannel ch2 = newEmbeddedInetChannel("91.92.93.2", handler);
|
||||
Assert.assertTrue(ch2.isActive());
|
||||
EmbeddedChannel ch3 = newEmbeddedInetChannel("91.92.93.1", handler);
|
||||
Assert.assertFalse(ch3.isActive());
|
||||
|
||||
// false means that no data is left to read/write
|
||||
Assert.assertFalse(ch1.finish());
|
||||
|
||||
EmbeddedChannel ch4 = newEmbeddedInetChannel("91.92.93.1", handler);
|
||||
Assert.assertTrue(ch4.isActive());
|
||||
}
|
||||
|
||||
private static EmbeddedChannel newEmbeddedInetChannel(final String ipAddress, ChannelHandler... handlers) {
|
||||
return new EmbeddedChannel(handlers) {
|
||||
@Override
|
||||
protected SocketAddress remoteAddress0() {
|
||||
return isActive()? new InetSocketAddress(ipAddress, 5421) : null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static InetSocketAddress newSockAddress(String ipAddress) {
|
||||
return new InetSocketAddress(ipAddress, 1234);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user