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 }