1 /* 2 * Copyright 2014 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 io.netty.handler.ipfilter; 17 18 import io.netty.channel.Channel; 19 import io.netty.channel.ChannelFuture; 20 import io.netty.channel.ChannelFutureListener; 21 import io.netty.channel.ChannelHandlerContext; 22 import io.netty.channel.ChannelInboundHandlerAdapter; 23 24 import java.net.SocketAddress; 25 26 /** 27 * This class provides the functionality to either accept or reject new {@link Channel}s 28 * based on their IP address. 29 * <p> 30 * You should inherit from this class if you would like to implement your own IP-based filter. Basically you have to 31 * implement {@link #accept(ChannelHandlerContext, SocketAddress)} to decided whether you want to accept or reject 32 * a connection from the remote address. 33 * <p> 34 * Furthermore overriding {@link #channelRejected(ChannelHandlerContext, SocketAddress)} gives you the 35 * flexibility to respond to rejected (denied) connections. If you do not want to send a response, just have it return 36 * null. Take a look at {@link RuleBasedIpFilter} for details. 37 */ 38 public abstract class AbstractRemoteAddressFilter<T extends SocketAddress> extends ChannelInboundHandlerAdapter { 39 40 @Override 41 public void channelRegistered(ChannelHandlerContext ctx) throws Exception { 42 handleNewChannel(ctx); 43 ctx.fireChannelRegistered(); 44 } 45 46 @Override 47 public void channelActive(ChannelHandlerContext ctx) throws Exception { 48 if (!handleNewChannel(ctx)) { 49 throw new IllegalStateException("cannot determine to accept or reject a channel: " + ctx.channel()); 50 } else { 51 ctx.fireChannelActive(); 52 } 53 } 54 55 private boolean handleNewChannel(ChannelHandlerContext ctx) throws Exception { 56 @SuppressWarnings("unchecked") 57 T remoteAddress = (T) ctx.channel().remoteAddress(); 58 59 // If the remote address is not available yet, defer the decision. 60 if (remoteAddress == null) { 61 return false; 62 } 63 64 // No need to keep this handler in the pipeline anymore because the decision is going to be made now. 65 // Also, this will prevent the subsequent events from being handled by this handler. 66 ctx.pipeline().remove(this); 67 68 if (accept(ctx, remoteAddress)) { 69 channelAccepted(ctx, remoteAddress); 70 } else { 71 ChannelFuture rejectedFuture = channelRejected(ctx, remoteAddress); 72 if (rejectedFuture != null) { 73 rejectedFuture.addListener(ChannelFutureListener.CLOSE); 74 } else { 75 ctx.close(); 76 } 77 } 78 79 return true; 80 } 81 82 /** 83 * This method is called immediately after a {@link io.netty.channel.Channel} gets registered. 84 * 85 * @return Return true if connections from this IP address and port should be accepted. False otherwise. 86 */ 87 protected abstract boolean accept(ChannelHandlerContext ctx, T remoteAddress) throws Exception; 88 89 /** 90 * This method is called if {@code remoteAddress} gets accepted by 91 * {@link #accept(ChannelHandlerContext, SocketAddress)}. You should override it if you would like to handle 92 * (e.g. respond to) accepted addresses. 93 */ 94 @SuppressWarnings("UnusedParameters") 95 protected void channelAccepted(ChannelHandlerContext ctx, T remoteAddress) { } 96 97 /** 98 * This method is called if {@code remoteAddress} gets rejected by 99 * {@link #accept(ChannelHandlerContext, SocketAddress)}. You should override it if you would like to handle 100 * (e.g. respond to) rejected addresses. 101 * 102 * @return A {@link ChannelFuture} if you perform I/O operations, so that 103 * the {@link Channel} can be closed once it completes. Null otherwise. 104 */ 105 @SuppressWarnings("UnusedParameters") 106 protected ChannelFuture channelRejected(ChannelHandlerContext ctx, T remoteAddress) { 107 return null; 108 } 109 }