NETTY-364 Application level IP filter

* Merged Frederic's ipfilter patch (needs some review and documentation)
This commit is contained in:
Trustin Lee 2010-11-12 10:20:03 +09:00
parent 34b181236a
commit 1ffb1aea75
17 changed files with 2584 additions and 0 deletions

View File

@ -0,0 +1,264 @@
/*
* Copyright 2009 Red Hat, Inc.
*
* Red Hat 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.jboss.netty.handler.ipfilter;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.StringTokenizer;
/**
* @author frederic bregier
*/
public abstract class CIDR implements Comparable<CIDR>
{
/**
* The base address of the CIDR notation
*/
protected InetAddress baseAddress;
/**
* The mask used in the CIDR notation
*/
protected int cidrMask;
/**
* Create CIDR using the CIDR Notation
* @param baseAddress
* @param cidrMask
* @return the generated CIDR
* @throws UnknownHostException
*/
public static CIDR newCIDR(InetAddress baseAddress, int cidrMask) throws UnknownHostException
{
if (cidrMask < 0)
{
throw new UnknownHostException("Invalid mask length used: " + cidrMask);
}
if (baseAddress instanceof Inet4Address)
{
if (cidrMask > 32)
{
throw new UnknownHostException("Invalid mask length used: " + cidrMask);
}
return new CIDR4((Inet4Address) baseAddress, cidrMask);
}
// IPv6.
if (cidrMask > 128)
{
throw new UnknownHostException("Invalid mask length used: " + cidrMask);
}
return new CIDR6((Inet6Address) baseAddress, cidrMask);
}
/**
* Create CIDR using the normal Notation
* @param baseAddress
* @param scidrMask
* @return the generated CIDR
* @throws UnknownHostException
*/
public static CIDR newCIDR(InetAddress baseAddress, String scidrMask) throws UnknownHostException
{
int cidrMask = getNetMask(scidrMask);
if (cidrMask < 0)
{
throw new UnknownHostException("Invalid mask length used: " + cidrMask);
}
if (baseAddress instanceof Inet4Address)
{
if (cidrMask > 32)
{
throw new UnknownHostException("Invalid mask length used: " + cidrMask);
}
return new CIDR4((Inet4Address) baseAddress, cidrMask);
}
cidrMask += 96;
// IPv6.
if (cidrMask > 128)
{
throw new UnknownHostException("Invalid mask length used: " + cidrMask);
}
return new CIDR6((Inet6Address) baseAddress, cidrMask);
}
/**
* Create CIDR using the CIDR or normal Notation<BR>
* i.e.:
* CIDR subnet = newCIDR ("10.10.10.0/24"); or
* CIDR subnet = newCIDR ("1fff:0:0a88:85a3:0:0:ac1f:8001/24"); or
* CIDR subnet = newCIDR ("10.10.10.0/255.255.255.0");
* @param cidr
* @return the generated CIDR
* @throws UnknownHostException
*/
public static CIDR newCIDR(String cidr) throws UnknownHostException
{
int p = cidr.indexOf("/");
if (p < 0)
{
throw new UnknownHostException("Invalid CIDR notation used: " + cidr);
}
String addrString = cidr.substring(0, p);
String maskString = cidr.substring(p + 1);
InetAddress addr = addressStringToInet(addrString);
int mask = 0;
if (maskString.indexOf(".") < 0)
{
mask = parseInt(maskString, -1);
}
else
{
mask = getNetMask(maskString);
if (addr instanceof Inet6Address)
{
mask += 96;
}
}
if (mask < 0)
{
throw new UnknownHostException("Invalid mask length used: " + maskString);
}
return newCIDR(addr, mask);
}
/** @return the baseAddress of the CIDR block. */
public InetAddress getBaseAddress()
{
return baseAddress;
}
/** @return the Mask length. */
public int getMask()
{
return cidrMask;
}
/** @return the textual CIDR notation. */
@Override
public String toString()
{
return baseAddress.getHostAddress() + "/" + cidrMask;
}
/** @return the end address of this block. */
public abstract InetAddress getEndAddress();
/**
* Compares the given InetAddress against the CIDR and returns true if
* the ip is in the subnet-ip-range and false if not.
* @param inetAddress
* @return returns true if the given IP address is inside the currently
* set network.
*/
public abstract boolean contains(InetAddress inetAddress);
/** Convert an IPv4 or IPv6 textual representation into an
* InetAddress.
* @param addr
* @return the created InetAddress
* @throws UnknownHostException
*/
private static InetAddress addressStringToInet(String addr) throws UnknownHostException
{
return InetAddress.getByName(addr);
}
/**
* Get the Subnet's Netmask in Decimal format.<BR>
* i.e.: getNetMask("255.255.255.0") returns the integer CIDR mask
* @param netMask a network mask
* @return the integer CIDR mask
* */
private static int getNetMask(String netMask)
{
StringTokenizer nm = new StringTokenizer(netMask, ".");
int i = 0;
int[] netmask = new int[4];
while (nm.hasMoreTokens())
{
netmask[i] = Integer.parseInt(nm.nextToken());
i++;
}
int mask1 = 0;
for (i = 0; i < 4; i++)
{
mask1 += Integer.bitCount(netmask[i]);
}
return mask1;
}
/** @param intstr a string containing an integer.
* @param def the default if the string does not contain a valid
* integer.
* @return the inetAddress from the integer
*/
private static int parseInt(String intstr, int def)
{
Integer res;
if (intstr == null)
{
return def;
}
try
{
res = Integer.decode(intstr);
}
catch (Exception e)
{
res = new Integer(def);
}
return res.intValue();
}
/**
* Compute a byte representation of IpV4 from a IpV6
* @param address
* @return the byte representation
* @throws IllegalArgumentException if the IpV6 cannot be mapped to IpV4
*/
public static byte[] getIpV4FromIpV6(Inet6Address address) throws IllegalArgumentException
{
byte[] baddr = address.getAddress();
for (int i = 0; i < 9; i++)
{
if (baddr[i] != 0)
{
throw new IllegalArgumentException("This IPv6 address cannot be used in IPv4 context");
}
}
if (baddr[10] != 0 && baddr[10] != 0xFF || baddr[11] != 0 && baddr[11] != 0xFF)
{
throw new IllegalArgumentException("This IPv6 address cannot be used in IPv4 context");
}
return new byte[]
{baddr[12], baddr[13], baddr[14], baddr[15]};
}
/**
* Compute a byte representation of IpV6 from a IpV4
* @param address
* @return the byte representation
* @throws IllegalArgumentException if the IpV6 cannot be mapped to IpV4
*/
public static byte[] getIpV6FromIpV4(Inet4Address address) throws IllegalArgumentException
{
byte[] baddr = address.getAddress();
return new byte[]
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, baddr[0], baddr[1], baddr[2], baddr[3]};
}
}

View File

@ -0,0 +1,197 @@
/*
* Copyright 2009 Red Hat, Inc.
*
* Red Hat 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.jboss.netty.handler.ipfilter;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* @author frederic bregier
*/
public class CIDR4 extends CIDR
{
/**
* The integer for the base address
*/
private int addressInt;
/**
* The integer for the end address
*/
private final int addressEndInt;
/**
* @param newaddr
* @param mask
*/
protected CIDR4(Inet4Address newaddr, int mask)
{
cidrMask = mask;
addressInt = ipv4AddressToInt(newaddr);
int newmask = ipv4PrefixLengthToMask(mask);
addressInt &= newmask;
try
{
baseAddress = intToIPv4Address(addressInt);
}
catch (UnknownHostException e)
{
// this should never happen
}
addressEndInt = addressInt + ipv4PrefixLengthToLength(cidrMask) - 1;
}
@Override
public InetAddress getEndAddress()
{
try
{
return intToIPv4Address(addressEndInt);
}
catch (UnknownHostException e)
{
// this should never happen
return null;
}
}
@Override
public int compareTo(CIDR arg)
{
if (arg instanceof CIDR6)
{
byte[] address = getIpV4FromIpV6((Inet6Address) arg.baseAddress);
int net = ipv4AddressToInt(address);
if (net == addressInt && arg.cidrMask == cidrMask)
{
return 0;
}
if (net < addressInt)
{
return 1;
}
else if (net > addressInt)
{
return -1;
}
else if (arg.cidrMask < cidrMask)
{
return -1;
}
return 1;
}
CIDR4 o = (CIDR4) arg;
if (o.addressInt == addressInt && o.cidrMask == cidrMask)
{
return 0;
}
if (o.addressInt < addressInt)
{
return 1;
}
else if (o.addressInt > addressInt)
{
return -1;
}
else if (o.cidrMask < cidrMask)
{
// greater Mask means less IpAddresses so -1
return -1;
}
return 1;
}
/* (non-Javadoc)
* @see org.jboss.netty.handler.ipfilter.CIDR#contains(java.net.InetAddress)
*/
@Override
public boolean contains(InetAddress inetAddress)
{
int search = ipv4AddressToInt(inetAddress);
return search >= addressInt && search <= addressEndInt;
}
/** Given an IPv4 baseAddress length, return the block length. I.e., a
* baseAddress length of 24 will return 256. */
private static int ipv4PrefixLengthToLength(int prefix_length)
{
return 1 << 32 - prefix_length;
}
/** Given a baseAddress length, return a netmask. I.e, a baseAddress length
* of 24 will return 0xFFFFFF00. */
private static int ipv4PrefixLengthToMask(int prefix_length)
{
return ~((1 << 32 - prefix_length) - 1);
}
/** Convert an integer into an (IPv4) InetAddress.
* @param addr
* @return the created InetAddress
* @throws UnknownHostException
* @throws UnknownHostException
*/
private static InetAddress intToIPv4Address(int addr) throws UnknownHostException
{
byte[] a = new byte[4];
a[0] = (byte) (addr >> 24 & 0xFF);
a[1] = (byte) (addr >> 16 & 0xFF);
a[2] = (byte) (addr >> 8 & 0xFF);
a[3] = (byte) (addr & 0xFF);
return InetAddress.getByAddress(a);
}
/** Given an IPv4 address, convert it into an integer.
* @param addr
* @return the integer representation of the InetAddress
*
* @throws IllegalArgumentException if the address is really an
* IPv6 address.
*/
private static int ipv4AddressToInt(InetAddress addr)
{
byte[] address = null;
if (addr instanceof Inet6Address)
{
address = getIpV4FromIpV6((Inet6Address) addr);
}
else
{
address = addr.getAddress();
}
return ipv4AddressToInt(address);
}
/** Given an IPv4 address as array of bytes, convert it into an integer.
* @param address
* @return the integer representation of the InetAddress
*
* @throws IllegalArgumentException if the address is really an
* IPv6 address.
*/
private static int ipv4AddressToInt(byte[] address)
{
int net = 0;
for (byte addres : address)
{
net <<= 8;
net |= addres & 0xFF;
}
return net;
}
}

View File

@ -0,0 +1,201 @@
/*
* Copyright 2009 Red Hat, Inc.
*
* Red Hat 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.jboss.netty.handler.ipfilter;
import java.math.BigInteger;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.jboss.netty.logging.InternalLogger;
import org.jboss.netty.logging.InternalLoggerFactory;
/**
* @author frederic bregier
*/
public class CIDR6 extends CIDR
{
private static final InternalLogger logger = InternalLoggerFactory.getInstance(CIDR6.class);
/**
* The big integer for the base address
*/
private BigInteger addressBigInt;
/**
* The big integer for the end address
*/
private final BigInteger addressEndBigInt;
/**
* @param newaddress
* @param newmask
*/
protected CIDR6(Inet6Address newaddress, int newmask)
{
cidrMask = newmask;
addressBigInt = ipv6AddressToBigInteger(newaddress);
BigInteger mask = ipv6CidrMaskToMask(newmask);
try
{
addressBigInt = addressBigInt.and(mask);
baseAddress = bigIntToIPv6Address(addressBigInt);
}
catch (UnknownHostException e)
{
// this should never happen.
}
addressEndBigInt = addressBigInt.add(ipv6CidrMaskToBaseAddress(cidrMask)).subtract(BigInteger.ONE);
}
@Override
public InetAddress getEndAddress()
{
try
{
return bigIntToIPv6Address(addressEndBigInt);
}
catch (UnknownHostException e)
{
logger.error("invalid ip address calculated as an end address");
return null;
}
}
@Override
public int compareTo(CIDR arg)
{
if (arg instanceof CIDR4)
{
BigInteger net = ipv6AddressToBigInteger(arg.baseAddress);
int res = net.compareTo(addressBigInt);
if (res == 0)
{
if (arg.cidrMask == cidrMask)
{
return 0;
}
else if (arg.cidrMask < cidrMask)
{
return -1;
}
return 1;
}
return res;
}
CIDR6 o = (CIDR6) arg;
if (o.addressBigInt.equals(addressBigInt) && o.cidrMask == cidrMask)
{
return 0;
}
int res = o.addressBigInt.compareTo(addressBigInt);
if (res == 0)
{
if (o.cidrMask < cidrMask)
{
// greater Mask means less IpAddresses so -1
return -1;
}
return 1;
}
return res;
}
/* (non-Javadoc)
* @see org.jboss.netty.handler.ipfilter.CIDR#contains(java.net.InetAddress)
*/
@Override
public boolean contains(InetAddress inetAddress)
{
BigInteger search = ipv6AddressToBigInteger(inetAddress);
return search.compareTo(addressBigInt) >= 0 && search.compareTo(addressEndBigInt) <= 0;
}
/** Given an IPv6 baseAddress length, return the block length. I.e., a
* baseAddress length of 96 will return 2**32. */
private static BigInteger ipv6CidrMaskToBaseAddress(int cidrMask)
{
return BigInteger.ONE.shiftLeft(128 - cidrMask);
}
private static BigInteger ipv6CidrMaskToMask(int cidrMask)
{
return BigInteger.ONE.shiftLeft(128 - cidrMask).subtract(BigInteger.ONE).not();
}
/** Given an IPv6 address, convert it into a BigInteger.
* @param addr
* @return the integer representation of the InetAddress
*
* @throws IllegalArgumentException if the address is not an IPv6
* address.
*/
private static BigInteger ipv6AddressToBigInteger(InetAddress addr)
{
byte[] ipv6;
if (addr instanceof Inet4Address)
{
ipv6 = getIpV6FromIpV4((Inet4Address) addr);
}
else
{
ipv6 = addr.getAddress();
}
if (ipv6[0] == -1)
{
return new BigInteger(1, ipv6);
}
return new BigInteger(ipv6);
}
/** Convert a big integer into an IPv6 address.
* @param addr
* @return the inetAddress from the integer
*
* @throws UnknownHostException if the big integer is too large,
* and thus an invalid IPv6 address.
*/
private static InetAddress bigIntToIPv6Address(BigInteger addr) throws UnknownHostException
{
byte[] a = new byte[16];
byte[] b = addr.toByteArray();
if (b.length > 16 && !(b.length == 17 && b[0] == 0))
{
throw new UnknownHostException("invalid IPv6 address (too big)");
}
if (b.length == 16)
{
return InetAddress.getByAddress(b);
}
// handle the case where the IPv6 address starts with "FF".
if (b.length == 17)
{
System.arraycopy(b, 1, a, 0, 16);
}
else
{
// copy the address into a 16 byte array, zero-filled.
int p = 16 - b.length;
for (int i = 0; i < b.length; i++)
{
a[p + i] = b[i];
}
}
return InetAddress.getByAddress(a);
}
}

View File

@ -0,0 +1,74 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2010, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed 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.jboss.netty.handler.ipfilter;
import java.net.InetSocketAddress;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelHandlerContext;
/**
* The listener interface for receiving ipFilter events.
*
* @see IpFilteringHandler
*
* @author Ron
*/
public interface IpFilterListener
{
/**
* Called when the channel has the CONNECTED status and the channel was allowed by a previous call to accept().
* This method enables your implementation to send a message back to the client before closing
* or whatever you need. This method returns a ChannelFuture on which the implementation
* can wait uninterruptibly before continuing.<br>
* For instance, If a message is sent back, the corresponding ChannelFuture has to be returned.
* @param ctx
* @param e
* @param inetSocketAddress the remote {@link InetSocketAddress} from client
* @return the associated ChannelFuture to be waited for before closing the channel. Null is allowed.
*/
public ChannelFuture allowed(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress);
/**
* Called when the channel has the CONNECTED status and the channel was refused by a previous call to accept().
* This method enables your implementation to send a message back to the client before closing
* or whatever you need. This method returns a ChannelFuture on which the implementation
* will wait uninterruptibly before closing the channel.<br>
* For instance, If a message is sent back, the corresponding ChannelFuture has to be returned.
* @param ctx
* @param e
* @param inetSocketAddress the remote {@link InetSocketAddress} from client
* @return the associated ChannelFuture to be waited for before closing the channel. Null is allowed.
*/
public ChannelFuture refused(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress);
/**
* Called in handleUpstream, if this channel was previously blocked,
* to check if whatever the event, it should be passed to the next entry in the pipeline.<br>
* If one wants to not block events, just overridden this method by returning always true.<br><br>
* <b>Note that OPENED and BOUND events are still passed to the next entry in the pipeline since
* those events come out before the CONNECTED event and so the possibility to filter the connection.</b>
* @param ctx
* @param e
* @return True if the event should continue, False if the event should not continue
* since this channel was blocked by this filter
*/
public boolean continues(ChannelHandlerContext ctx, ChannelEvent e);
}

View File

@ -0,0 +1,37 @@
/*
* Copyright 2009 Red Hat, Inc.
*
* Red Hat 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.jboss.netty.handler.ipfilter;
/**
* This Interface defines an Ip Filter Rule.
*
* @author frederic bregier
*
*/
public interface IpFilterRule extends IpSet
{
/**
*
* @return True if this Rule is an ALLOW rule
*/
public boolean isAllowRule();
/**
*
* @return True if this Rule is a DENY rule
*/
public boolean isDenyRule();
}

View File

@ -0,0 +1,328 @@
/*
* Copyright 2009 Red Hat, Inc.
*
* Red Hat 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.jboss.netty.handler.ipfilter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelHandler.Sharable;
import org.jboss.netty.channel.ChannelHandlerContext;
/**
* Implementation of Filter of IP based on ALLOW and DENY rules.<br>
* <br><br>
* This implementation could be changed by implementing a new {@link IpFilterRule} than default
* {@link IpV4SubnetFilterRule} (IPV4 support only), {@link IpSubnetFilterRule} (IPV4 and IPV6 support) or {@link IpFilterRule} (IP and host name string pattern support) .<br>
* <br>
* The check is done by going from step to step in the underlying array of IpFilterRule.<br>
* Each {@link IpFilterRule} answers to the method accept if the {@link InetAddress} is accepted or not,
* according to its implementation. If an InetAddress arrives at the end of the list, as in Firewall
* usual rules, the InetAddress is therefore accepted by default.<br>
* <ul>
* <li>If it was constructed with True as first argument,
* the IpFilterRule is an ALLOW rule (every InetAddress that fits in the rule will be accepted).</li>
* <li>If it was constructed with False as first argument,
* the IpFilterRule is a DENY rule (every InetAddress that fits in the rule will be refused).</li>
* </ul><br>
* <br>
* An empty list means allow all (no limitation).<br><br>
* <b>For efficiency reason, you should not add/remove too frequently IpFilterRules to/from this handler.
* You should prefer to replace an entry (<tt>set</tt> method) with an ALLOW/DENY ALL IpFilterRule
* if possible.</b><br><br><br>
* <b>This handler should be created only once and reused on every pipeline since it handles
* a global status of what is allowed or blocked.</b><br><br>
*
* Note that {@link IpSubnetFilterRule} which supports IPV4 and IPV6 should be used with as much as
* possible no mixed IP protocol. Both IPV4 and IPV6 are supported but a mix (IpFilter in IPV6 notation
* and the address from the channel in IPV4, or the reverse) can lead to wrong result.
* @author frederic bregier
*
*/
@Sharable
public class IpFilterRuleHandler extends IpFilteringHandlerImpl
{
/**
* List of {@link IpFilterRule}
*/
private final CopyOnWriteArrayList<IpFilterRule> ipFilterRuleList = new CopyOnWriteArrayList<IpFilterRule>();
/**
* Constructor from a new list of IpFilterRule
* @param newList
*/
public IpFilterRuleHandler(List<IpFilterRule> newList)
{
if (newList != null)
{
ipFilterRuleList.addAll(newList);
}
}
/**
* Empty constructor (no IpFilterRule in the List at construction). In such a situation,
* empty list implies allow all.
*/
public IpFilterRuleHandler()
{
super();
}
// Below are methods directly inspired from CopyOnWriteArrayList methods
/**
* Add an ipFilterRule in the list at the end
* @param ipFilterRule
*/
public void add(IpFilterRule ipFilterRule)
{
if (ipFilterRule == null)
{
throw new NullPointerException("IpFilterRule can not be null");
}
ipFilterRuleList.add(ipFilterRule);
}
/**
* Add an ipFilterRule in the list at the specified position (shifting to the right other elements)
* @param index
* @param ipFilterRule
*/
public void add(int index, IpFilterRule ipFilterRule)
{
if (ipFilterRule == null)
{
throw new NullPointerException("IpFilterRule can not be null");
}
ipFilterRuleList.add(index, ipFilterRule);
}
/**
* Appends all of the elements in the specified collection to the end of this list,
* in the order that they are returned by the specified collection's iterator.
* @param c
*/
public void addAll(Collection<IpFilterRule> c)
{
if (c == null)
{
throw new NullPointerException("Collection can not be null");
}
ipFilterRuleList.addAll(c);
}
/**
* Inserts all of the elements in the specified collection into this list, starting at the specified position.
* @param index
* @param c
*/
public void addAll(int index, Collection<IpFilterRule> c)
{
if (c == null)
{
throw new NullPointerException("Collection can not be null");
}
ipFilterRuleList.addAll(index, c);
}
/**
* Append the element if not present.
* @param c
* @return the number of elements added
*/
public int addAllAbsent(Collection<IpFilterRule> c)
{
if (c == null)
{
throw new NullPointerException("Collection can not be null");
}
return ipFilterRuleList.addAllAbsent(c);
}
/**
* Append the element if not present.
* @param ipFilterRule
* @return true if the element was added
*/
public boolean addIfAbsent(IpFilterRule ipFilterRule)
{
if (ipFilterRule == null)
{
throw new NullPointerException("IpFilterRule can not be null");
}
return ipFilterRuleList.addIfAbsent(ipFilterRule);
}
/**
* Clear the list
*/
public void clear()
{
ipFilterRuleList.clear();
}
/**
* Returns true if this list contains the specified element
* @param ipFilterRule
* @return true if this list contains the specified element
*/
public boolean contains(IpFilterRule ipFilterRule)
{
if (ipFilterRule == null)
{
throw new NullPointerException("IpFilterRule can not be null");
}
return ipFilterRuleList.contains(ipFilterRule);
}
/**
* Returns true if this list contains all of the elements of the specified collection
* @param c
* @return true if this list contains all of the elements of the specified collection
*/
public boolean containsAll(Collection<IpFilterRule> c)
{
if (c == null)
{
throw new NullPointerException("Collection can not be null");
}
return ipFilterRuleList.containsAll(c);
}
/**
* Returns the element at the specified position in this list
* @param index
* @return the element at the specified position in this list
*/
public IpFilterRule get(int index)
{
return ipFilterRuleList.get(index);
}
/**
* Returns true if this list contains no elements
* @return true if this list contains no elements
*/
public boolean isEmpty()
{
return ipFilterRuleList.isEmpty();
}
/**
* Remove the ipFilterRule from the list
* @param ipFilterRule
*/
public void remove(IpFilterRule ipFilterRule)
{
if (ipFilterRule == null)
{
throw new NullPointerException("IpFilterRule can not be null");
}
ipFilterRuleList.remove(ipFilterRule);
}
/**
* Removes the element at the specified position in this list
* @param index
* @return the element previously at the specified position
*/
public IpFilterRule remove(int index)
{
return ipFilterRuleList.remove(index);
}
/**
* Removes from this list all of its elements that are contained in the specified collection
* @param c
*/
public void removeAll(Collection<IpFilterRule> c)
{
if (c == null)
{
throw new NullPointerException("Collection can not be null");
}
ipFilterRuleList.removeAll(c);
}
/**
* Retains only the elements in this list that are contained in the specified collection
* @param c
*/
public void retainAll(Collection<IpFilterRule> c)
{
if (c == null)
{
throw new NullPointerException("Collection can not be null");
}
ipFilterRuleList.retainAll(c);
}
/**
* Replaces the element at the specified position in this list with the specified element
* @param index
* @param ipFilterRule
* @return the element previously at the specified position
*/
public IpFilterRule set(int index, IpFilterRule ipFilterRule)
{
if (ipFilterRule == null)
{
throw new NullPointerException("IpFilterRule can not be null");
}
return ipFilterRuleList.set(index, ipFilterRule);
}
/**
* Returns the number of elements in this list.
* @return the number of elements in this list.
*/
public int size()
{
return ipFilterRuleList.size();
}
/* (non-Javadoc)
* @see org.jboss.netty.handler.ipfilter.IpFilteringHandler#accept(org.jboss.netty.channel.ChannelHandlerContext, org.jboss.netty.channel.ChannelEvent, java.net.InetSocketAddress)
*/
@Override
protected boolean accept(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress)
throws Exception
{
if (ipFilterRuleList.isEmpty())
{
// No limitation neither in deny or allow, so accept
return true;
}
InetAddress inetAddress = inetSocketAddress.getAddress();
Iterator<IpFilterRule> iterator = ipFilterRuleList.iterator();
IpFilterRule ipFilterRule = null;
while (iterator.hasNext())
{
ipFilterRule = iterator.next();
if (ipFilterRule.contains(inetAddress))
{
// Match founds, is it a ALLOW or DENY rule
return ipFilterRule.isAllowRule();
}
}
// No limitation founds and no allow either, but as it is like Firewall rules, it is therefore accepted
return true;
}
}

View File

@ -0,0 +1,100 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2010, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed 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.jboss.netty.handler.ipfilter;
import java.net.UnknownHostException;
import java.util.ArrayList;
import org.jboss.netty.logging.InternalLogger;
import org.jboss.netty.logging.InternalLoggerFactory;
/**
* The Class IpFilterRuleList is a helper class to generate a List of Rules from a string.
* In case of parse errors no exceptions are thrown. The error is logged.
* <br>
* Rule List Syntax:
* <br>
* <pre>
* RuleList ::= Rule[,Rule]*
* Rule ::= AllowRule | BlockRule
* AllowRule ::= +Filter
* BlockRule ::= -Filter
* Filter ::= PatternFilter | CIDRFilter
* PatternFilter ::= @see PatternRule
* CIDRFilter ::= c:CIDRFilter
* CIDRFilter ::= @see CIDR.newCIDR(String)
* </pre>
* <br>
* Example: allow only localhost:
* <br>
* new IPFilterRuleHandler().addAll(new IpFilterRuleList("+n:localhost, -n:*"));
* <br>
*
* @author Ron
*/
public class IpFilterRuleList extends ArrayList<IpFilterRule>
{
private static final long serialVersionUID = -6164162941749588780L;
private static final InternalLogger logger = InternalLoggerFactory.getInstance(IpFilterRuleList.class);
/**
* Instantiates a new ip filter rule list.
*
* @param rules the rules
*/
public IpFilterRuleList(String rules)
{
super();
parseRules(rules);
}
private void parseRules(String rules)
{
String[] ruless = rules.split(",");
for (String rule : ruless)
{
parseRule(rule.trim());
}
}
private void parseRule(String rule)
{
if (rule == null || rule.length() == 0)
return;
if (!(rule.startsWith("+") || rule.startsWith("-")))
{
logger.error("syntax error in ip filter rule:" + rule);
return;
}
boolean allow = rule.startsWith("+");
if (rule.charAt(1) == 'n' || rule.charAt(1) == 'i')
this.add(new PatternRule(allow, rule.substring(1)));
else if (rule.charAt(1) == 'c')
try
{
this.add(new IpSubnetFilterRule(allow, rule.substring(3)));
}
catch (UnknownHostException e)
{
logger.error("error parsing ip filter " + rule, e);
}
else
logger.error("syntax error in ip filter rule:" + rule);
}
}

View File

@ -0,0 +1,41 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2010, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed 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.jboss.netty.handler.ipfilter;
/**
* The Interface IpFilteringHandler.
* A Filter of IP.
* <br>
* Users can add an {@link IpFilterListener} to add specific actions in case a connection is allowed or refused.
*
* @author Ron
*/
public interface IpFilteringHandler
{
/**
* Sets the filter listener.
*
* @param listener the new ip filter listener
*/
public void setIpFilterListener(IpFilterListener listener);
/**
* Remove the filter listener.
*/
public void removeIpFilterListener();
}

View File

@ -0,0 +1,207 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2010, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed 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.jboss.netty.handler.ipfilter;
import java.net.InetSocketAddress;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ChannelUpstreamHandler;
import org.jboss.netty.channel.Channels;
// TODO: Auto-generated Javadoc
/**
* General class that handle Ip Filtering.
*
* @author frederic bregier
*/
public abstract class IpFilteringHandlerImpl implements ChannelUpstreamHandler, IpFilteringHandler
{
private IpFilterListener listener = null;
/**
* Called when the channel is connected. It returns True if the corresponding connection
* is to be allowed. Else it returns False.
* @param ctx
* @param e
* @param inetSocketAddress the remote {@link InetSocketAddress} from client
* @return True if the corresponding connection is allowed, else False.
* @throws Exception
*/
protected abstract boolean accept(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress)
throws Exception;
/**
* Called when the channel has the CONNECTED status and the channel was refused by a previous call to accept().
* This method enables your implementation to send a message back to the client before closing
* or whatever you need. This method returns a ChannelFuture on which the implementation
* will wait uninterruptibly before closing the channel.<br>
* For instance, If a message is sent back, the corresponding ChannelFuture has to be returned.
* @param ctx
* @param e
* @param inetSocketAddress the remote {@link InetSocketAddress} from client
* @return the associated ChannelFuture to be waited for before closing the channel. Null is allowed.
* @throws Exception
*/
protected ChannelFuture handleRefusedChannel(ChannelHandlerContext ctx, ChannelEvent e,
InetSocketAddress inetSocketAddress) throws Exception
{
if (listener == null)
return null;
ChannelFuture result = listener.refused(ctx, e, inetSocketAddress);
return result;
}
protected ChannelFuture handleAllowedChannel(ChannelHandlerContext ctx, ChannelEvent e,
InetSocketAddress inetSocketAddress) throws Exception
{
if (listener == null)
return null;
ChannelFuture result = listener.allowed(ctx, e, inetSocketAddress);
return result;
}
/**
* Internal method to test if the current channel is blocked. Should not be overridden.
* @param ctx
* @return True if the current channel is blocked, else False
*/
protected boolean isBlocked(ChannelHandlerContext ctx)
{
return ctx.getAttachment() != null;
}
/**
* Called in handleUpstream, if this channel was previously blocked,
* to check if whatever the event, it should be passed to the next entry in the pipeline.<br>
* If one wants to not block events, just overridden this method by returning always true.<br><br>
* <b>Note that OPENED and BOUND events are still passed to the next entry in the pipeline since
* those events come out before the CONNECTED event and so the possibility to filter the connection.</b>
* @param ctx
* @param e
* @return True if the event should continue, False if the event should not continue
* since this channel was blocked by this filter
* @throws Exception
*/
protected boolean continues(ChannelHandlerContext ctx, ChannelEvent e) throws Exception
{
if (listener != null)
return listener.continues(ctx, e);
else
return false;
}
/* (non-Javadoc)
* @see org.jboss.netty.channel.ChannelUpstreamHandler#handleUpstream(org.jboss.netty.channel.ChannelHandlerContext, org.jboss.netty.channel.ChannelEvent)
*/
@Override
public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception
{
if (e instanceof ChannelStateEvent)
{
ChannelStateEvent evt = (ChannelStateEvent) e;
switch (evt.getState())
{
case OPEN :
case BOUND :
// Special case: OPEND and BOUND events are before CONNECTED,
// but CLOSED and UNBOUND events are after DISCONNECTED: should those events be blocked too?
if (isBlocked(ctx) && !continues(ctx, evt))
{
// don't pass to next level since channel was blocked early
return;
}
else
{
ctx.sendUpstream(e);
return;
}
case CONNECTED :
if (evt.getValue() != null)
{
// CONNECTED
InetSocketAddress inetSocketAddress = (InetSocketAddress) e.getChannel().getRemoteAddress();
if (!accept(ctx, e, inetSocketAddress))
{
ctx.setAttachment(Boolean.TRUE);
ChannelFuture future = handleRefusedChannel(ctx, e, inetSocketAddress);
if (future != null)
{
future.addListener(ChannelFutureListener.CLOSE);
}
else
{
Channels.close(e.getChannel());
}
if (isBlocked(ctx) && !continues(ctx, evt))
{
// don't pass to next level since channel was blocked early
return;
}
}
else
{
handleAllowedChannel(ctx, e, inetSocketAddress);
}
// This channel is not blocked
ctx.setAttachment(null);
}
else
{
// DISCONNECTED
if (isBlocked(ctx) && !continues(ctx, evt))
{
// don't pass to next level since channel was blocked early
return;
}
}
break;
}
}
if (isBlocked(ctx) && !continues(ctx, e))
{
// don't pass to next level since channel was blocked early
return;
}
// Whatever it is, if not blocked, goes to the next level
ctx.sendUpstream(e);
}
/* (non-Javadoc)
* @see org.jboss.netty.handler.ipfilter.IpFilteringHandler#setIpFilterListener(org.jboss.netty.handler.ipfilter.IpFilterListener)
*/
@Override
public void setIpFilterListener(IpFilterListener listener)
{
this.listener = listener;
}
/* (non-Javadoc)
* @see org.jboss.netty.handler.ipfilter.IpFilteringHandler#removeIpFilterListener()
*/
@Override
public void removeIpFilterListener()
{
this.listener = null;
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2009 Red Hat, Inc.
*
* Red Hat 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.jboss.netty.handler.ipfilter;
import java.net.InetAddress;
/**
* This Interface defines an IpSet object.
*
* @author frederic bregier
*
*/
public interface IpSet
{
/**
* Compares the given InetAddress against the IpSet and returns true if
* the InetAddress is contained in this Rule and false if not.
* @param inetAddress1
* @return returns true if the given IP address is contained in the current
* IpSet.
*/
public boolean contains(InetAddress inetAddress1);
}

View File

@ -0,0 +1,194 @@
/*
* Copyright 2009 Red Hat, Inc.
*
* Red Hat 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.jboss.netty.handler.ipfilter;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* This class allows to check if an IP V4 or V6 Address is contained in a subnet.<BR>
*
* Supported IP V4 Formats for the Subnets are: 1.1.1.1/255.255.255.255 or 1.1.1.1/32 (CIDR-Notation)
* and (InetAddress,Mask) where Mask is a integer for CIDR-notation or a String for Standard Mask notation.<BR>
* <BR><BR>Example1:<BR>
* <tt>IpV4Subnet ips = new IpV4Subnet("192.168.1.0/24");</tt><BR>
* <tt>System.out.println("Result: "+ ips.contains("192.168.1.123"));</tt><BR>
* <tt>System.out.println("Result: "+ ips.contains(inetAddress2));</tt><BR>
* <BR>Example1 bis:<BR>
* <tt>IpV4Subnet ips = new IpV4Subnet(inetAddress, 24);</tt><BR>
* where inetAddress is 192.168.1.0 and inetAddress2 is 192.168.1.123<BR>
* <BR><BR>Example2:<BR>
* <tt>IpV4Subnet ips = new IpV4Subnet("192.168.1.0/255.255.255.0");</tt><BR>
* <tt>System.out.println("Result: "+ ips.contains("192.168.1.123"));</tt><BR>
* <tt>System.out.println("Result: "+ ips.contains(inetAddress2));</tt><BR>
* <BR>Example2 bis:<BR>
* <tt>IpV4Subnet ips = new IpV4Subnet(inetAddress, "255.255.255.0");</tt><BR>
* where inetAddress is 192.168.1.0 and inetAddress2 is 192.168.1.123<BR>
* <BR>
* Supported IP V6 Formats for the Subnets are: a:b:c:d:e:f:g:h/NN (CIDR-Notation)
* or any IPV6 notations (like a:b:c:d::/NN, a:b:c:d:e:f:w.x.y.z/NN)
* and (InetAddress,Mask) where Mask is a integer for CIDR-notation
* and (InetAddress,subnet).<BR>
* <BR><BR>Example1:<BR>
* <tt>IpSubnet ips = new IpSubnet("1fff:0:0a88:85a3:0:0:0:0/24");</tt><BR>
* <tt>IpSubnet ips = new IpSubnet("1fff:0:0a88:85a3::/24");</tt><BR>
* <tt>System.out.println("Result: "+ ips.contains("1fff:0:0a88:85a3:0:0:ac1f:8001"));</tt><BR>
* <tt>System.out.println("Result: "+ ips.contains(inetAddress2));</tt><BR>
* <BR>Example1 bis:<BR>
* <tt>IpSubnet ips = new IpSubnet(inetAddress, 24);</tt><BR>
* where inetAddress2 is 1fff:0:0a88:85a3:0:0:ac1f:8001<BR>
*
* @author frederic bregier
*
*/
public class IpSubnet implements IpSet, Comparable<IpSubnet>
{
/**
* Internal representation
*/
private CIDR cidr = null;
/**
* Create IpSubnet for ALL (used for ALLOW or DENY ALL)
*/
public IpSubnet()
{
// ALLOW or DENY ALL
cidr = null;
}
/**
* Create IpSubnet using the CIDR or normal Notation<BR>
* i.e.:<br>
* IpSubnet subnet = new IpSubnet("10.10.10.0/24"); or<br>
* IpSubnet subnet = new IpSubnet("10.10.10.0/255.255.255.0"); or<br>
* IpSubnet subnet = new IpSubnet("1fff:0:0a88:85a3:0:0:0:0/24");
* @param netAddress a network address as string.
* @throws UnknownHostException
* */
public IpSubnet(String netAddress) throws UnknownHostException
{
cidr = CIDR.newCIDR(netAddress);
}
/**
* Create IpSubnet using the CIDR Notation
* @param inetAddress
* @param cidrNetMask
* @throws UnknownHostException
*/
public IpSubnet(InetAddress inetAddress, int cidrNetMask) throws UnknownHostException
{
cidr = CIDR.newCIDR(inetAddress, cidrNetMask);
}
/**
* Create IpSubnet using the normal Notation
* @param inetAddress
* @param netMask
* @throws UnknownHostException
*/
public IpSubnet(InetAddress inetAddress, String netMask) throws UnknownHostException
{
cidr = CIDR.newCIDR(inetAddress, netMask);
}
/**
* Compares the given IP-Address against the Subnet and returns true if
* the ip is in the subnet-ip-range and false if not.
* @param ipAddr an ipaddress
* @return returns true if the given IP address is inside the currently
* set network.
* @throws UnknownHostException
* */
public boolean contains(String ipAddr) throws UnknownHostException
{
InetAddress inetAddress1 = InetAddress.getByName(ipAddr);
return this.contains(inetAddress1);
}
/**
* Compares the given InetAddress against the Subnet and returns true if
* the ip is in the subnet-ip-range and false if not.
* @param inetAddress
* @return returns true if the given IP address is inside the currently
* set network.
* */
@Override
public boolean contains(InetAddress inetAddress)
{
if (cidr == null)
{
// ANY
return true;
}
return cidr.contains(inetAddress);
}
@Override
public String toString()
{
return cidr.toString();
}
@Override
public boolean equals(Object o)
{
if (!(o instanceof IpSubnet))
{
return false;
}
IpSubnet ipSubnet = (IpSubnet) o;
return ipSubnet.cidr.equals(cidr);
}
/**
* Compare two IpSubnet
*/
@Override
public int compareTo(IpSubnet o)
{
return cidr.toString().compareTo(o.cidr.toString());
}
/**
* Simple test functions
* @param args
* where args[0] is the netmask (standard or CIDR notation) and optional args[1] is
* the inetAddress to test with this IpSubnet
*/
public static void main(String[] args) throws Exception
{
if (args.length != 0)
{
IpSubnet ipSubnet = null;
try
{
ipSubnet = new IpSubnet(args[0]);
}
catch (UnknownHostException e)
{
return;
}
System.out.println("IpSubnet: " + ipSubnet.toString() + " from " + ipSubnet.cidr.getBaseAddress() + " to "
+ ipSubnet.cidr.getEndAddress() + " mask " + ipSubnet.cidr.getMask());
if (args.length > 1)
{
System.out.println("Is IN: " + args[1] + " " + ipSubnet.contains(args[1]));
}
}
}
}

View File

@ -0,0 +1,93 @@
/*
* Copyright 2009 Red Hat, Inc.
*
* Red Hat 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.jboss.netty.handler.ipfilter;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* Ip V4 and Ip V6 filter rule.<br>
* <br>
* Note that mix of IPV4 and IPV6 is allowed but it is not recommended. So it is preferable to not
* mix IPV4 addresses with IPV6 rules, even if it should work.
* @author frederic bregier
*
*/
public class IpSubnetFilterRule extends IpSubnet implements IpFilterRule
{
/**
* Is this IpV4Subnet an ALLOW or DENY rule
*/
private boolean isAllowRule = true;
/**
* Constructor for a ALLOW or DENY ALL
* @param allow True for ALLOW, False for DENY
*/
public IpSubnetFilterRule(boolean allow)
{
super();
isAllowRule = allow;
}
/**
* @param allow True for ALLOW, False for DENY
* @param inetAddress
* @param cidrNetMask
* @throws UnknownHostException
*/
public IpSubnetFilterRule(boolean allow, InetAddress inetAddress, int cidrNetMask) throws UnknownHostException
{
super(inetAddress, cidrNetMask);
isAllowRule = allow;
}
/**
* @param allow True for ALLOW, False for DENY
* @param inetAddress
* @param netMask
* @throws UnknownHostException
*/
public IpSubnetFilterRule(boolean allow, InetAddress inetAddress, String netMask) throws UnknownHostException
{
super(inetAddress, netMask);
isAllowRule = allow;
}
/**
* @param allow True for ALLOW, False for DENY
* @param netAddress
* @throws UnknownHostException
*/
public IpSubnetFilterRule(boolean allow, String netAddress) throws UnknownHostException
{
super(netAddress);
isAllowRule = allow;
}
@Override
public boolean isAllowRule()
{
return isAllowRule;
}
@Override
public boolean isDenyRule()
{
return !isAllowRule;
}
}

View File

@ -0,0 +1,328 @@
/*
* Copyright 2009 Red Hat, Inc.
*
* Red Hat 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.jboss.netty.handler.ipfilter;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.StringTokenizer;
import java.util.Vector;
/**
* This class allows to check if an IP-V4-Address is contained in a subnet.<BR>
* Supported Formats for the Subnets are: 1.1.1.1/255.255.255.255 or 1.1.1.1/32 (CIDR-Notation)
* and (InetAddress,Mask) where Mask is a integer for CIDR-notation or a String for Standard Mask notation.<BR>
* <BR><BR>Example1:<BR>
* <tt>IpV4Subnet ips = new IpV4Subnet("192.168.1.0/24");</tt><BR>
* <tt>System.out.println("Result: "+ ips.contains("192.168.1.123"));</tt><BR>
* <tt>System.out.println("Result: "+ ips.contains(inetAddress2));</tt><BR>
* <BR>Example1 bis:<BR>
* <tt>IpV4Subnet ips = new IpV4Subnet(inetAddress, 24);</tt><BR>
* where inetAddress is 192.168.1.0 and inetAddress2 is 192.168.1.123<BR>
* <BR><BR>Example2:<BR>
* <tt>IpV4Subnet ips = new IpV4Subnet("192.168.1.0/255.255.255.0");</tt><BR>
* <tt>System.out.println("Result: "+ ips.contains("192.168.1.123"));</tt><BR>
* <tt>System.out.println("Result: "+ ips.contains(inetAddress2));</tt><BR>
* <BR>Example2 bis:<BR>
* <tt>IpV4Subnet ips = new IpV4Subnet(inetAddress, "255.255.255.0");</tt><BR>
* where inetAddress is 192.168.1.0 and inetAddress2 is 192.168.1.123<BR>
* @author frederic bregier
*
*/
public class IpV4Subnet implements IpSet, Comparable<IpV4Subnet>
{
private static final int SUBNET_MASK = 0x80000000;
private static final int BYTE_ADDRESS_MASK = 0xFF;
private InetAddress inetAddress;
private int subnet;
private int mask;
private int cidrMask;
/**
* Create IpV4Subnet for ALL (used for ALLOW or DENY ALL)
*/
public IpV4Subnet()
{
// ALLOW or DENY ALL
mask = -1;
// other will be ignored
inetAddress = null;
subnet = 0;
cidrMask = 0;
}
/**
* Create IpV4Subnet using the CIDR or normal Notation<BR>
* i.e.:
* IpV4Subnet subnet = new IpV4Subnet("10.10.10.0/24"); or
* IpV4Subnet subnet = new IpV4Subnet("10.10.10.0/255.255.255.0");
* @param netAddress a network address as string.
* @throws UnknownHostException
* */
public IpV4Subnet(String netAddress) throws UnknownHostException
{
setNetAddress(netAddress);
}
/**
* Create IpV4Subnet using the CIDR Notation
* @param inetAddress
* @param cidrNetMask
*/
public IpV4Subnet(InetAddress inetAddress, int cidrNetMask)
{
setNetAddress(inetAddress, cidrNetMask);
}
/**
* Create IpV4Subnet using the normal Notation
* @param inetAddress
* @param netMask
*/
public IpV4Subnet(InetAddress inetAddress, String netMask)
{
setNetAddress(inetAddress, netMask);
}
/**
* Sets the Network Address in either CIDR or Decimal Notation.<BR>
* i.e.: setNetAddress("1.1.1.1/24"); or<BR>
* setNetAddress("1.1.1.1/255.255.255.0");<BR>
* @param netAddress a network address as string.
* @throws UnknownHostException
* */
private void setNetAddress(String netAddress) throws UnknownHostException
{
Vector<Object> vec = new Vector<Object>();
StringTokenizer st = new StringTokenizer(netAddress, "/");
while (st.hasMoreTokens())
{
vec.add(st.nextElement());
}
if (vec.get(1).toString().length() < 3)
{
setNetId(vec.get(0).toString());
setCidrNetMask(Integer.parseInt(vec.get(1).toString()));
}
else
{
setNetId(vec.get(0).toString());
setNetMask(vec.get(1).toString());
}
}
/**
* Sets the Network Address in CIDR Notation.
* @param inetAddress
* @param cidrNetMask
* */
private void setNetAddress(InetAddress inetAddress, int cidrNetMask)
{
setNetId(inetAddress);
setCidrNetMask(cidrNetMask);
}
/**
* Sets the Network Address in Decimal Notation.
* @param inetAddress
* @param netMask
* */
private void setNetAddress(InetAddress inetAddress, String netMask)
{
setNetId(inetAddress);
setNetMask(netMask);
}
/**
* Sets the BaseAdress of the Subnet.<BR>
* i.e.: setNetId("192.168.1.0");
* @param netId a network ID
* @throws UnknownHostException
* */
private void setNetId(String netId) throws UnknownHostException
{
InetAddress inetAddress1 = InetAddress.getByName(netId);
this.setNetId(inetAddress1);
}
/**
* Compute integer representation of InetAddress
* @param inetAddress1
* @return the integer representation
*/
private int toInt(InetAddress inetAddress1)
{
byte[] address = inetAddress1.getAddress();
int net = 0;
for (byte addres : address)
{
net <<= 8;
net |= addres & BYTE_ADDRESS_MASK;
}
return net;
}
/**
* Sets the BaseAdress of the Subnet.
* @param inetAddress
* */
private void setNetId(InetAddress inetAddress)
{
this.inetAddress = inetAddress;
subnet = toInt(inetAddress);
}
/**
* Sets the Subnet's Netmask in Decimal format.<BR>
* i.e.: setNetMask("255.255.255.0");
* @param netMask a network mask
* */
private void setNetMask(String netMask)
{
StringTokenizer nm = new StringTokenizer(netMask, ".");
int i = 0;
int[] netmask = new int[4];
while (nm.hasMoreTokens())
{
netmask[i] = Integer.parseInt(nm.nextToken());
i++;
}
int mask1 = 0;
for (i = 0; i < 4; i++)
{
mask1 += Integer.bitCount(netmask[i]);
}
setCidrNetMask(mask1);
}
/**
* Sets the CIDR Netmask<BR>
* i.e.: setCidrNetMask(24);
* @param cidrNetMask a netmask in CIDR notation
* */
private void setCidrNetMask(int cidrNetMask)
{
cidrMask = cidrNetMask;
mask = SUBNET_MASK >> cidrMask - 1;
}
/**
* Compares the given IP-Address against the Subnet and returns true if
* the ip is in the subnet-ip-range and false if not.
* @param ipAddr an ipaddress
* @return returns true if the given IP address is inside the currently
* set network.
* @throws UnknownHostException
* */
public boolean contains(String ipAddr) throws UnknownHostException
{
InetAddress inetAddress1 = InetAddress.getByName(ipAddr);
return this.contains(inetAddress1);
}
/**
* Compares the given InetAddress against the Subnet and returns true if
* the ip is in the subnet-ip-range and false if not.
* @param inetAddress1
* @return returns true if the given IP address is inside the currently
* set network.
* */
@Override
public boolean contains(InetAddress inetAddress1)
{
if (mask == -1)
{
// ANY
return true;
}
return (toInt(inetAddress1) & mask) == subnet;
}
@Override
public String toString()
{
return inetAddress.getHostAddress() + "/" + cidrMask;
}
@Override
public boolean equals(Object o)
{
if (!(o instanceof IpV4Subnet))
{
return false;
}
IpV4Subnet ipV4Subnet = (IpV4Subnet) o;
return ipV4Subnet.subnet == subnet && ipV4Subnet.cidrMask == cidrMask;
}
/**
* Compare two IpV4Subnet
*/
@Override
public int compareTo(IpV4Subnet o)
{
if (o.subnet == subnet && o.cidrMask == cidrMask)
{
return 0;
}
if (o.subnet < subnet)
{
return 1;
}
else if (o.subnet > subnet)
{
return -1;
}
else if (o.cidrMask < cidrMask)
{
// greater Mask means less IpAddresses so -1
return -1;
}
return 1;
}
/**
* Simple test functions
* @param args
* where args[0] is the netmask (standard or CIDR notation) and optional args[1] is
* the inetAddress to test with this IpV4Subnet
*/
public static void main(String[] args) throws Exception
{
if (args.length != 0)
{
IpV4Subnet ipV4Subnet = null;
try
{
ipV4Subnet = new IpV4Subnet(args[0]);
}
catch (UnknownHostException e)
{
return;
}
if (args.length > 1)
{
System.out.println("Is IN: " + args[1] + " " + ipV4Subnet.contains(args[1]));
}
}
}
}

View File

@ -0,0 +1,88 @@
/*
* Copyright 2009 Red Hat, Inc.
*
* Red Hat 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.jboss.netty.handler.ipfilter;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* IpV4 only Filter Rule
* @author frederic bregier
*
*/
public class IpV4SubnetFilterRule extends IpV4Subnet implements IpFilterRule
{
/**
* Is this IpV4Subnet an ALLOW or DENY rule
*/
private boolean isAllowRule = true;
/**
* Constructor for a ALLOW or DENY ALL
* @param allow True for ALLOW, False for DENY
*/
public IpV4SubnetFilterRule(boolean allow)
{
super();
isAllowRule = allow;
}
/**
* @param allow True for ALLOW, False for DENY
* @param inetAddress
* @param cidrNetMask
*/
public IpV4SubnetFilterRule(boolean allow, InetAddress inetAddress, int cidrNetMask)
{
super(inetAddress, cidrNetMask);
isAllowRule = allow;
}
/**
* @param allow True for ALLOW, False for DENY
* @param inetAddress
* @param netMask
*/
public IpV4SubnetFilterRule(boolean allow, InetAddress inetAddress, String netMask)
{
super(inetAddress, netMask);
isAllowRule = allow;
}
/**
* @param allow True for ALLOW, False for DENY
* @param netAddress
* @throws UnknownHostException
*/
public IpV4SubnetFilterRule(boolean allow, String netAddress) throws UnknownHostException
{
super(netAddress);
isAllowRule = allow;
}
@Override
public boolean isAllowRule()
{
return isAllowRule;
}
@Override
public boolean isDenyRule()
{
return !isAllowRule;
}
}

View File

@ -0,0 +1,92 @@
/*
* Copyright 2009 Red Hat, Inc.
*
* Red Hat 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.jboss.netty.handler.ipfilter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelHandler.Sharable;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelState;
import org.jboss.netty.channel.ChannelStateEvent;
/**
* Handler that block any new connection if there are already a currently active
* channel connected with the same InetAddress (IP).<br>
* <br>
*
* Take care to not change isBlocked method except if you know what you are doing
* since it is used to test if the current closed connection is to be removed
* or not from the map of currently connected channel.
*
* @author frederic bregier
*
*/
@Sharable
public class OneIpFilterHandler extends IpFilteringHandlerImpl
{
/**
* HashMap of current remote connected InetAddress
*/
private final ConcurrentMap<InetAddress, Boolean> connectedSet = new ConcurrentHashMap<InetAddress, Boolean>();
/* (non-Javadoc)
* @see org.jboss.netty.handler.ipfilter.IpFilteringHandler#accept(org.jboss.netty.channel.ChannelHandlerContext, org.jboss.netty.channel.ChannelEvent, java.net.InetSocketAddress)
*/
@Override
protected boolean accept(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress)
throws Exception
{
InetAddress inetAddress = inetSocketAddress.getAddress();
if (connectedSet.containsKey(inetAddress))
{
return false;
}
connectedSet.put(inetAddress, Boolean.TRUE);
return true;
}
/* (non-Javadoc)
* @see org.jboss.netty.handler.ipfilter.IpFilteringHandler#handleUpstream(org.jboss.netty.channel.ChannelHandlerContext, org.jboss.netty.channel.ChannelEvent)
*/
@Override
public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception
{
super.handleUpstream(ctx, e);
// Try to remove entry from Map if already exists
if (e instanceof ChannelStateEvent)
{
ChannelStateEvent evt = (ChannelStateEvent) e;
if (evt.getState() == ChannelState.CONNECTED)
{
if (evt.getValue() == null)
{
// DISCONNECTED but was this channel blocked or not
if (isBlocked(ctx))
{
// remove inetsocketaddress from set since this channel was not blocked before
InetSocketAddress inetSocketAddress = (InetSocketAddress) e.getChannel().getRemoteAddress();
connectedSet.remove(inetSocketAddress.getAddress());
}
}
}
}
}
}

View File

@ -0,0 +1,211 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2010, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed 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.jboss.netty.handler.ipfilter;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.regex.Pattern;
import org.jboss.netty.logging.InternalLogger;
import org.jboss.netty.logging.InternalLoggerFactory;
/**
* The Class PatternRule represents an IP filter rule using string patterns.
* <br>
* Rule Syntax:
* <br>
* <pre>
* Rule ::= [n|i]:address n stands for computer name, i for ip address
* address ::= &lt;regex&gt; | localhost
* regex is a regular expression with '*' as multi character and '?' as single character wild card
* </pre>
* <br>
* Example: allow localhost:
* <br>
* new PatternRule(true, "n:localhost")
* <br>
* Example: allow local lan:
* <br>
* new PatternRule(true, "i:192.168.0.*")
* <br>
* Example: block all
* <br>
* new PatternRule(false, "n:*")
* <br>
*
* @author Ron
*/
public class PatternRule implements IpFilterRule, Comparable<Object>
{
private static final InternalLogger logger = InternalLoggerFactory.getInstance(PatternRule.class);
private Pattern ipPattern = null;
private Pattern namePattern = null;
private boolean isAllowRule = true;
private boolean localhost = false;
private String pattern = null;
/**
* Instantiates a new pattern rule.
*
* @param allow indicates if this is an allow or block rule
* @param pattern the filter pattern
*/
public PatternRule(boolean allow, String pattern)
{
this.isAllowRule = allow;
this.pattern = pattern;
parse(pattern);
}
/**
* returns the pattern.
*
* @return the pattern
*/
public String getPattern()
{
return this.pattern;
}
/* (non-Javadoc)
* @see org.jboss.netty.handler.ipfilter.IpFilterRule#isAllowRule()
*/
@Override
public boolean isAllowRule()
{
return isAllowRule;
}
/* (non-Javadoc)
* @see org.jboss.netty.handler.ipfilter.IpFilterRule#isDenyRule()
*/
@Override
public boolean isDenyRule()
{
return !isAllowRule;
}
/* (non-Javadoc)
* @see org.jboss.netty.handler.ipfilter.IpSet#contains(java.net.InetAddress)
*/
@Override
public boolean contains(InetAddress inetAddress)
{
if (localhost)
if (isLocalhost(inetAddress))
return true;
if (ipPattern != null)
if (ipPattern.matcher(inetAddress.getHostAddress()).matches())
return true;
if (namePattern != null)
if (namePattern.matcher(inetAddress.getHostName()).matches())
return true;
return false;
}
private void parse(String pattern)
{
if (pattern == null)
return;
String[] acls = pattern.split(",");
String ip = "";
String name = "";
for (String c : acls)
{
c = c.trim();
if (c.equals("n:localhost"))
this.localhost = true;
else if (c.startsWith("n:"))
name = addRule(name, c.substring(2));
else if (c.startsWith("i:"))
ip = addRule(ip, c.substring(2));
}
if (ip.length() != 0)
ipPattern = Pattern.compile(ip);
if (name.length() != 0)
namePattern = Pattern.compile(name);
}
private String addRule(String pattern, String rule)
{
if (rule == null || rule.length() == 0)
return pattern;
if (pattern.length() != 0)
pattern += "|";
rule = rule.replaceAll("\\.", "\\\\.");
rule = rule.replaceAll("\\*", ".*");
rule = rule.replaceAll("\\?", ".");
pattern += "(" + rule + ")";
return pattern;
}
private boolean isLocalhost(InetAddress address)
{
try
{
if (address.equals(InetAddress.getLocalHost()))
return true;
}
catch (UnknownHostException e)
{
logger.info("error getting ip of localhost", e);
}
try
{
InetAddress[] addrs = InetAddress.getAllByName("127.0.0.1");
for (InetAddress addr : addrs)
if (addr.equals(address))
return true;
}
catch (UnknownHostException e)
{
logger.info("error getting ip of localhost", e);
}
return false;
}
/* (non-Javadoc)
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
@Override
public int compareTo(Object o)
{
if (o == null)
return -1;
if (!(o instanceof PatternRule))
return -1;
PatternRule p = (PatternRule) o;
if (p.isAllowRule() && !this.isAllowRule)
return -1;
if (this.pattern == null && p.pattern == null)
return 0;
if (this.pattern != null)
return this.pattern.compareTo(p.getPattern());
return -1;
}
}

View File

@ -0,0 +1,93 @@
/*
* Copyright 2009 Red Hat, Inc.
*
* Red Hat 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.
*/
/**
* Implementation of a Ip based Filter handlers.<br>
* <br><br>
*
*
* <P>The main goal of this package is to allow to filter connections based on IP rules.
* The main interface is <tt>{@link org.jboss.netty.handler.ipfilter.IpFilteringHandler}</tt> which all filters will extend.</P>
*
* <P>Two IP filtering are proposed:<br>
* <ul>
* <li> <tt>{@link org.jboss.netty.handler.ipfilter.OneIpFilterHandler}</tt>: This filter proposes to allow only one connection by client's IP Address.
* I.E. this filter will prevent two connections from the same client based on its IP address.</li><br><br>
*
* <li> <tt>{@link org.jboss.netty.handler.ipfilter.IpFilterRuleHandler}</tt>: This filter proposes to allow or block IP range (based on standard notation
* or on CIDR notation) when the connection is running. It relies on another class like
* <tt>IpV4SubnetFilterRule</tt> (IPV4 support only), <tt>IpSubnetFilterRule</tt> (IPV4 and IPV6 support) or <tt>PatternRule</tt> (string pattern support)
* which implements those Ip ranges.</li><br><br>
*
* </ul></P>
*
* <P>Standard use could be as follow: The accept method must be overridden (of course you can
* override others).</P>
*
* <P><ul>
* <li><tt>accept</tt> method allows to specify your way of choosing if a new connection is
* to be allowed or not.</li><br>
* In <tt>OneIpFilterHandler</tt> and <tt>IpFilterRuleHandler</tt>,
* this method is already implemented.<br>
* <br>
*
* <li><tt>handleRefusedChannel</tt> method is executed when the accept method filters (blocks, so returning false)
* the new connection. This method allows you to implement specific actions to be taken before the channel is
* closed. After this method is called, the channel is immediately closed.</li><br>
* So if you want to send back a message to the client, <b>don't forget to return a respectful ChannelFuture,
* otherwise the message could be missed since the channel will be closed immediately after this
* call and the waiting on this channelFuture</b> (at least with respect of asynchronous operations).<br><br>
* Per default implementation this method invokes an {@link org.jboss.netty.handler.ipfilter.IpFilterListener} or returns null if no listener has been set.
* <br><br>
*
* <li><tt>continues</tt> is called when any event appears after CONNECTED event and only for
* blocked channels.</li><br>
* It should return True if this new event has to go to next handlers
* in the pipeline if any, and False (default) if no events has to be passed to the next
* handlers when a channel is blocked. This is intend to prevent any unnecessary action since the connection is refused.<br>
* However, you could change its behavior for instance because you don't want that any event
* will be blocked by this filter by returning always true or according to some events.<br>
* <b>Note that OPENED and BOUND events are still passed to the next entry in the pipeline since
* those events come out before the CONNECTED event, so there is no possibility to filter those two events
* before the CONNECTED event shows up. Therefore, you might want to let CLOSED and UNBOUND be passed
* to the next entry in the pipeline.</b><br><br>
* Per default implementation this method invokes an {@link org.jboss.netty.handler.ipfilter.IpFilterListener} or returns false if no listener has been set.
* <br><br>
*
* <li>Finally <tt>handleUpstream</tt> traps the CONNECTED and DISCONNECTED events.</li><br>
* If in the CONNECTED events the channel is blocked (<tt>accept</tt> refused the channel),
* then any new events on this channel will be blocked.<br>
* However, you could change its behavior for instance because you don't want that all events
* will be blocked by this filter by testing the result of isBlocked, and if so,
* calling <tt>ctx.sendUpstream(e);</tt> after calling the super method or by changing the <tt>continues</tt> method.<br><br>
* </ul></P><br><br>
*
* A typical setup for ip filter for TCP/IP socket would be:
*
* <pre>
* {@link org.jboss.netty.channel.ChannelPipeline} pipeline = ...;
*
* IpFilterRuleHandler firewall = new IpFilterRuleHandler();
* firewall.addAll(new IpFilterRuleList("+n:localhost, +c:192.168.0.0/27, -n:*"));
* pipeline.addFirst(&quot;firewall&quot;, firewall);
* </pre>
*
* @apiviz.exclude ^java\.lang\.
*/
package org.jboss.netty.handler.ipfilter;