diff --git a/handler/src/main/java/io/netty/handler/ipfilter/AbstractIpFilterHandler.java b/handler/src/main/java/io/netty/handler/ipfilter/AbstractIpFilterHandler.java
deleted file mode 100644
index 8ad7eb2c1b..0000000000
--- a/handler/src/main/java/io/netty/handler/ipfilter/AbstractIpFilterHandler.java
+++ /dev/null
@@ -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.
- *
- * 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 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 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);
-}
diff --git a/handler/src/main/java/io/netty/handler/ipfilter/AbstractRemoteAddressFilter.java b/handler/src/main/java/io/netty/handler/ipfilter/AbstractRemoteAddressFilter.java
new file mode 100644
index 0000000000..a3523a7b0f
--- /dev/null
+++ b/handler/src/main/java/io/netty/handler/ipfilter/AbstractRemoteAddressFilter.java
@@ -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.
+ *
+ * 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.
+ *
+ * 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 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;
+ }
+}
diff --git a/handler/src/main/java/io/netty/handler/ipfilter/IpFilterDecision.java b/handler/src/main/java/io/netty/handler/ipfilter/IpFilterDecision.java
deleted file mode 100644
index 910e750c08..0000000000
--- a/handler/src/main/java/io/netty/handler/ipfilter/IpFilterDecision.java
+++ /dev/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
-}
diff --git a/handler/src/main/java/io/netty/handler/ipfilter/IpFilterRule.java b/handler/src/main/java/io/netty/handler/ipfilter/IpFilterRule.java
index 8a5759ef23..2883734a20 100644
--- a/handler/src/main/java/io/netty/handler/ipfilter/IpFilterRule.java
+++ b/handler/src/main/java/io/netty/handler/ipfilter/IpFilterRule.java
@@ -22,15 +22,15 @@ import java.net.InetSocketAddress;
*/
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)}
* 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();
}
diff --git a/handler/src/main/java/io/netty/handler/ipfilter/IpFilterRuleType.java b/handler/src/main/java/io/netty/handler/ipfilter/IpFilterRuleType.java
index 9d78130388..7c2deedc9a 100644
--- a/handler/src/main/java/io/netty/handler/ipfilter/IpFilterRuleType.java
+++ b/handler/src/main/java/io/netty/handler/ipfilter/IpFilterRuleType.java
@@ -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.
*/
public enum IpFilterRuleType {
- ALLOW,
- DENY
+ ACCEPT,
+ REJECT
}
diff --git a/handler/src/main/java/io/netty/handler/ipfilter/IpSubnetFilterRule.java b/handler/src/main/java/io/netty/handler/ipfilter/IpSubnetFilterRule.java
index 2eebfdcce7..2e6545012b 100644
--- a/handler/src/main/java/io/netty/handler/ipfilter/IpSubnetFilterRule.java
+++ b/handler/src/main/java/io/netty/handler/ipfilter/IpSubnetFilterRule.java
@@ -23,10 +23,11 @@ import java.net.InetSocketAddress;
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.
*/
public final class IpSubnetFilterRule implements IpFilterRule {
+
private final IpFilterRule filterRule;
public IpSubnetFilterRule(String ipAddress, int cidrPrefix, IpFilterRuleType ruleType) {
@@ -60,8 +61,8 @@ public final class IpSubnetFilterRule implements IpFilterRule {
}
@Override
- public boolean matches(InetSocketAddress ipAndPort) {
- return filterRule.matches(ipAndPort);
+ public boolean matches(InetSocketAddress remoteAddress) {
+ return filterRule.matches(remoteAddress);
}
@Override
@@ -87,8 +88,8 @@ public final class IpSubnetFilterRule implements IpFilterRule {
}
@Override
- public boolean matches(InetSocketAddress ipAndPort) {
- int ipAddress = ipToInt((Inet4Address) ipAndPort.getAddress());
+ public boolean matches(InetSocketAddress remoteAddress) {
+ int ipAddress = ipToInt((Inet4Address) remoteAddress.getAddress());
return (ipAddress & subnetMask) == networkAddress;
}
@@ -133,8 +134,8 @@ public final class IpSubnetFilterRule implements IpFilterRule {
}
@Override
- public boolean matches(InetSocketAddress ipAndPort) {
- BigInteger ipAddress = ipToInt((Inet6Address) ipAndPort.getAddress());
+ public boolean matches(InetSocketAddress remoteAddress) {
+ BigInteger ipAddress = ipToInt((Inet6Address) remoteAddress.getAddress());
return ipAddress.and(subnetMask).equals(networkAddress);
}
diff --git a/handler/src/main/java/io/netty/handler/ipfilter/IpFilterRuleHandler.java b/handler/src/main/java/io/netty/handler/ipfilter/RuleBasedIpFilter.java
similarity index 67%
rename from handler/src/main/java/io/netty/handler/ipfilter/IpFilterRuleHandler.java
rename to handler/src/main/java/io/netty/handler/ipfilter/RuleBasedIpFilter.java
index ded2bcf6f5..66ffa4545f 100644
--- a/handler/src/main/java/io/netty/handler/ipfilter/IpFilterRuleHandler.java
+++ b/handler/src/main/java/io/netty/handler/ipfilter/RuleBasedIpFilter.java
@@ -15,11 +15,12 @@
*/
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.ChannelHandlerContext;
-import io.netty.channel.Channel;
+
import java.net.InetSocketAddress;
+import java.net.SocketAddress;
/**
* This class allows one to filter new {@link Channel}s based on the
@@ -27,36 +28,33 @@ import java.net.InetSocketAddress;
* will be accepted.
*
* 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
-public class IpFilterRuleHandler extends AbstractIpFilterHandler {
+public class RuleBasedIpFilter extends AbstractRemoteAddressFilter {
+
private final IpFilterRule[] rules;
- public IpFilterRuleHandler(IpFilterRule... rules) {
+ public RuleBasedIpFilter(IpFilterRule... rules) {
if (rules == null) {
throw new NullPointerException("rules");
}
- if (rules.length == 0) {
- throw new IllegalArgumentException("You have to provide at least one rule.");
- }
-
this.rules = rules;
}
@Override
- protected boolean accept(InetSocketAddress ipAndPort) throws Exception {
+ protected boolean accept(ChannelHandlerContext ctx, InetSocketAddress remoteAddress) throws Exception {
for (IpFilterRule rule : rules) {
- if (rule.matches(ipAndPort)) {
- return rule.ruleType() == IpFilterRuleType.ALLOW;
+ if (rule == null) {
+ break;
+ }
+
+ if (rule.matches(remoteAddress)) {
+ return rule.ruleType() == IpFilterRuleType.ACCEPT;
}
}
+
return true;
}
-
- @Override
- protected ChannelFuture rejected(ChannelHandlerContext ctx, InetSocketAddress ipAndPort) {
- return null;
- }
}
diff --git a/handler/src/main/java/io/netty/handler/ipfilter/UniqueIpFilterHandler.java b/handler/src/main/java/io/netty/handler/ipfilter/UniqueIpFilter.java
similarity index 65%
rename from handler/src/main/java/io/netty/handler/ipfilter/UniqueIpFilterHandler.java
rename to handler/src/main/java/io/netty/handler/ipfilter/UniqueIpFilter.java
index a6dd4487a4..ac346481d7 100644
--- a/handler/src/main/java/io/netty/handler/ipfilter/UniqueIpFilterHandler.java
+++ b/handler/src/main/java/io/netty/handler/ipfilter/UniqueIpFilter.java
@@ -15,11 +15,12 @@
*/
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 io.netty.channel.Channel;
import java.net.InetAddress;
import java.net.InetSocketAddress;
@@ -30,30 +31,24 @@ import java.util.Set;
* {@link Channel} connected to the server.
*/
@ChannelHandler.Sharable
-public class UniqueIpFilterHandler extends AbstractIpFilterHandler {
+public class UniqueIpFilter extends AbstractRemoteAddressFilter {
+
private final Set connected = new ConcurrentSet();
@Override
- protected boolean accept(InetSocketAddress ipAndPort) throws Exception {
- InetAddress ipAddress = ipAndPort.getAddress();
- if (connected.contains(ipAddress)) {
+ protected boolean accept(ChannelHandlerContext ctx, InetSocketAddress remoteAddress) throws Exception {
+ final InetAddress remoteIp = remoteAddress.getAddress();
+ if (connected.contains(remoteIp)) {
return false;
} 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;
}
}
-
- @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;
- }
}
diff --git a/handler/src/test/java/io/netty/handler/ipfilter/IpSubnetFilterTest.java b/handler/src/test/java/io/netty/handler/ipfilter/IpSubnetFilterTest.java
index 8ca53ad326..6c3caf6ce1 100644
--- a/handler/src/test/java/io/netty/handler/ipfilter/IpSubnetFilterTest.java
+++ b/handler/src/test/java/io/netty/handler/ipfilter/IpSubnetFilterTest.java
@@ -31,13 +31,13 @@ public class IpSubnetFilterTest {
@Test
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++) {
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.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.255")));
Assert.assertTrue(rule.matches(newSockAddress("91.114.241.193")));
@@ -49,7 +49,7 @@ public class IpSubnetFilterTest {
public void testIp6SubnetFilterRule() {
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:0fff:ffff:ffff:ffff:ffff")));
Assert.assertFalse(rule.matches(newSockAddress("2001:db8:abcd:1000::")));
@@ -59,24 +59,24 @@ public class IpSubnetFilterTest {
public void testIpFilterRuleHandler() throws Exception {
IpFilterRule filter0 = new IpFilterRule() {
@Override
- public boolean matches(InetSocketAddress ipAndPort) {
- return "192.168.57.1".equals(ipAndPort.getHostName());
+ public boolean matches(InetSocketAddress remoteAddress) {
+ return "192.168.57.1".equals(remoteAddress.getHostName());
}
@Override
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};
@Override
- protected ChannelFuture rejected(ChannelHandlerContext ctx, InetSocketAddress ipAndPort) {
+ protected ChannelFuture channelRejected(ChannelHandlerContext ctx, InetSocketAddress remoteAddress) {
Assert.assertTrue(ctx.channel().isActive());
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));
}
@@ -90,9 +90,9 @@ public class IpSubnetFilterTest {
Assert.assertFalse(chDeny.isActive());
Assert.assertFalse(chDeny.isOpen());
- IpFilterRuleHandler allowHandler = new IpFilterRuleHandler(filter0) {
+ RuleBasedIpFilter allowHandler = new RuleBasedIpFilter(filter0) {
@Override
- protected ChannelFuture rejected(ChannelHandlerContext ctx, InetSocketAddress ipAndPort) {
+ protected ChannelFuture channelRejected(ChannelHandlerContext ctx, InetSocketAddress remoteAddress) {
Assert.fail();
return null;
}
@@ -104,7 +104,7 @@ public class IpSubnetFilterTest {
@Test
public void testUniqueIpFilterHandler() {
- UniqueIpFilterHandler handler = new UniqueIpFilterHandler();
+ UniqueIpFilter handler = new UniqueIpFilter();
EmbeddedChannel ch1 = newEmbeddedInetChannel("91.92.93.1", handler);
Assert.assertTrue(ch1.isActive());