1 /* 2 * Copyright 2012 The Netty Project 3 * 4 * The Netty Project licenses this file to you under the Apache License, 5 * version 2.0 (the "License"); you may not use this file except in compliance 6 * with the License. You may obtain a copy of the License at: 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations 14 * under the License. 15 */ 16 package org.jboss.netty.handler.ipfilter; 17 18 import java.net.InetAddress; 19 import java.net.InetSocketAddress; 20 import java.util.Collection; 21 import java.util.Iterator; 22 import java.util.List; 23 import java.util.concurrent.CopyOnWriteArrayList; 24 25 import org.jboss.netty.channel.ChannelEvent; 26 import org.jboss.netty.channel.ChannelHandler.Sharable; 27 import org.jboss.netty.channel.ChannelHandlerContext; 28 29 /** 30 * Implementation of Filter of IP based on ALLOW and DENY rules.<br> 31 * <br><br> 32 * This implementation could be changed by implementing a new {@link IpFilterRule} than default 33 * {@link IpV4SubnetFilterRule} (IPV4 support only), {@link IpSubnetFilterRule} (IPV4 and IPV6 support) 34 * or {@link IpFilterRule} (IP and host name string pattern support) .<br> 35 * <br> 36 * The check is done by going from step to step in the underlying array of IpFilterRule.<br> 37 * Each {@link IpFilterRule} answers to the method accept if the {@link InetAddress} is accepted or not, 38 * according to its implementation. If an InetAddress arrives at the end of the list, as in Firewall 39 * usual rules, the InetAddress is therefore accepted by default.<br> 40 * <ul> 41 * <li>If it was constructed with True as first argument, 42 * the IpFilterRule is an ALLOW rule (every InetAddress that fits in the rule will be accepted).</li> 43 * <li>If it was constructed with False as first argument, 44 * the IpFilterRule is a DENY rule (every InetAddress that fits in the rule will be refused).</li> 45 * </ul><br> 46 * <br> 47 * An empty list means allow all (no limitation).<br><br> 48 * <b>For efficiency reason, you should not add/remove too frequently IpFilterRules to/from this handler. 49 * You should prefer to replace an entry (<tt>set</tt> method) with an ALLOW/DENY ALL IpFilterRule 50 * if possible.</b><br><br><br> 51 * <b>This handler should be created only once and reused on every pipeline since it handles 52 * a global status of what is allowed or blocked.</b><br><br> 53 * <p/> 54 * Note that {@link IpSubnetFilterRule} which supports IPV4 and IPV6 should be used with as much as 55 * possible no mixed IP protocol. Both IPV4 and IPV6 are supported but a mix (IpFilter in IPV6 notation 56 * and the address from the channel in IPV4, or the reverse) can lead to wrong result. 57 */ 58 @Sharable 59 public class IpFilterRuleHandler extends IpFilteringHandlerImpl { 60 /** List of {@link IpFilterRule} */ 61 private final CopyOnWriteArrayList<IpFilterRule> ipFilterRuleList = new CopyOnWriteArrayList<IpFilterRule>(); 62 63 /** Constructor from a new list of IpFilterRule */ 64 public IpFilterRuleHandler(List<IpFilterRule> newList) { 65 if (newList != null) { 66 ipFilterRuleList.addAll(newList); 67 } 68 } 69 70 /** 71 * Empty constructor (no IpFilterRule in the List at construction). In such a situation, 72 * empty list implies allow all. 73 */ 74 public IpFilterRuleHandler() { 75 } 76 77 // Below are methods directly inspired from CopyOnWriteArrayList methods 78 79 /** Add an ipFilterRule in the list at the end */ 80 public void add(IpFilterRule ipFilterRule) { 81 if (ipFilterRule == null) { 82 throw new NullPointerException("IpFilterRule can not be null"); 83 } 84 ipFilterRuleList.add(ipFilterRule); 85 } 86 87 /** Add an ipFilterRule in the list at the specified position (shifting to the right other elements) */ 88 public void add(int index, IpFilterRule ipFilterRule) { 89 if (ipFilterRule == null) { 90 throw new NullPointerException("IpFilterRule can not be null"); 91 } 92 ipFilterRuleList.add(index, ipFilterRule); 93 } 94 95 /** 96 * Appends all of the elements in the specified collection to the end of this list, 97 * in the order that they are returned by the specified collection's iterator. 98 */ 99 public void addAll(Collection<IpFilterRule> c) { 100 if (c == null) { 101 throw new NullPointerException("Collection can not be null"); 102 } 103 ipFilterRuleList.addAll(c); 104 } 105 106 /** Inserts all of the elements in the specified collection into this list, starting at the specified position. */ 107 public void addAll(int index, Collection<IpFilterRule> c) { 108 if (c == null) { 109 throw new NullPointerException("Collection can not be null"); 110 } 111 ipFilterRuleList.addAll(index, c); 112 } 113 114 /** 115 * Append the element if not present. 116 * 117 * @return the number of elements added 118 */ 119 public int addAllAbsent(Collection<IpFilterRule> c) { 120 if (c == null) { 121 throw new NullPointerException("Collection can not be null"); 122 } 123 return ipFilterRuleList.addAllAbsent(c); 124 } 125 126 /** 127 * Append the element if not present. 128 * 129 * @return true if the element was added 130 */ 131 public boolean addIfAbsent(IpFilterRule ipFilterRule) { 132 if (ipFilterRule == null) { 133 throw new NullPointerException("IpFilterRule can not be null"); 134 } 135 return ipFilterRuleList.addIfAbsent(ipFilterRule); 136 } 137 138 /** Clear the list */ 139 public void clear() { 140 ipFilterRuleList.clear(); 141 } 142 143 /** 144 * Returns true if this list contains the specified element 145 * 146 * @return true if this list contains the specified element 147 */ 148 public boolean contains(IpFilterRule ipFilterRule) { 149 if (ipFilterRule == null) { 150 throw new NullPointerException("IpFilterRule can not be null"); 151 } 152 return ipFilterRuleList.contains(ipFilterRule); 153 } 154 155 /** 156 * Returns true if this list contains all of the elements of the specified collection 157 * 158 * @return true if this list contains all of the elements of the specified collection 159 */ 160 public boolean containsAll(Collection<IpFilterRule> c) { 161 if (c == null) { 162 throw new NullPointerException("Collection can not be null"); 163 } 164 return ipFilterRuleList.containsAll(c); 165 } 166 167 /** 168 * Returns the element at the specified position in this list 169 * 170 * @return the element at the specified position in this list 171 */ 172 public IpFilterRule get(int index) { 173 return ipFilterRuleList.get(index); 174 } 175 176 /** 177 * Returns true if this list contains no elements 178 * 179 * @return true if this list contains no elements 180 */ 181 public boolean isEmpty() { 182 return ipFilterRuleList.isEmpty(); 183 } 184 185 /** Remove the ipFilterRule from the list */ 186 public void remove(IpFilterRule ipFilterRule) { 187 if (ipFilterRule == null) { 188 throw new NullPointerException("IpFilterRule can not be null"); 189 } 190 ipFilterRuleList.remove(ipFilterRule); 191 } 192 193 /** 194 * Removes the element at the specified position in this list 195 * 196 * @return the element previously at the specified position 197 */ 198 public IpFilterRule remove(int index) { 199 return ipFilterRuleList.remove(index); 200 } 201 202 /** Removes from this list all of its elements that are contained in the specified collection */ 203 public void removeAll(Collection<IpFilterRule> c) { 204 if (c == null) { 205 throw new NullPointerException("Collection can not be null"); 206 } 207 ipFilterRuleList.removeAll(c); 208 } 209 210 /** Retains only the elements in this list that are contained in the specified collection */ 211 public void retainAll(Collection<IpFilterRule> c) { 212 if (c == null) { 213 throw new NullPointerException("Collection can not be null"); 214 } 215 ipFilterRuleList.retainAll(c); 216 } 217 218 /** 219 * Replaces the element at the specified position in this list with the specified element 220 * 221 * @return the element previously at the specified position 222 */ 223 public IpFilterRule set(int index, IpFilterRule ipFilterRule) { 224 if (ipFilterRule == null) { 225 throw new NullPointerException("IpFilterRule can not be null"); 226 } 227 return ipFilterRuleList.set(index, ipFilterRule); 228 } 229 230 /** 231 * Returns the number of elements in this list. 232 * 233 * @return the number of elements in this list. 234 */ 235 public int size() { 236 return ipFilterRuleList.size(); 237 } 238 239 @Override 240 protected boolean accept(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress) 241 throws Exception { 242 if (ipFilterRuleList.isEmpty()) { 243 // No limitation neither in deny or allow, so accept 244 return true; 245 } 246 InetAddress inetAddress = inetSocketAddress.getAddress(); 247 Iterator<IpFilterRule> iterator = ipFilterRuleList.iterator(); 248 IpFilterRule ipFilterRule = null; 249 while (iterator.hasNext()) { 250 ipFilterRule = iterator.next(); 251 if (ipFilterRule.contains(inetAddress)) { 252 // Match founds, is it a ALLOW or DENY rule 253 return ipFilterRule.isAllowRule(); 254 } 255 } 256 // No limitation founds and no allow either, but as it is like Firewall rules, it is therefore accepted 257 return true; 258 } 259 260 }