View Javadoc
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 org.jboss.netty.channel.ChannelEvent;
19  import org.jboss.netty.channel.ChannelHandler.Sharable;
20  import org.jboss.netty.channel.ChannelHandlerContext;
21  
22  import java.net.InetAddress;
23  import java.net.InetSocketAddress;
24  import java.util.Collection;
25  import java.util.Iterator;
26  import java.util.List;
27  import java.util.concurrent.CopyOnWriteArrayList;
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;
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 }