Hi,
Alan Williamson wrote:
> Good day to you all,
>
> I am kinda new to Grizzly and on the face of it, it looks very
> interesting and definitely something that may help us. We currently
> have our own HTTP frontend server performing load balancing infront of a
> farm of JETTY servers.
>
>
> ___ Question #1 ___
>
> One of the things we need to do, is to determine whether or not an IP
> address is allowed to connect. We basically want to nuke this
> connection as soon as the "accept()" method has been called and the
> Socket created.
>
> This stops a lot of spammers from consuming resources they shouldn't be
> anywhere near. Our current frontend server sandboxes the IP for a small
> period of time and we've noticed that this has reduced a load.
>
> So in terms of the Grizzly how could one get a handle to the incoming
> connection as soon as possible and determine whether or not they are
> permitted to continue?
The easiest way is to write a com.sun.grizzly.ProtocolFilter (or extends
the com.sun.grizzly.filter.ReadFilter). The way connection are handled
is the SelectorHandler execute the accept()/OP_ACCEPT, and then delegate
the read operations to a ProtocolChain (a chain is a collection of
filters). As an example, let's say you extends the ReadFilter (let's
call it MyReadFilter) with:
> public boolean execute(Context ctx) throws IOException {
> SelectionKey key = ctx.getSelectionKey();
> SocketChannel channel = (SocketChannel)key.channel();
> if (allow(channel.socket().getRemoteSocketAddress())){
> return super.execute(ctx);
> } else {
> ctx.setKeyRegistrationState(
> Context.KeyRegistrationState.CANCEL);
> // Do not invoke the next Filter
> return false;
>
> }
Just implement the allow() method to return true/false.
>
> One the adapter code has triggered the "service()" method, then the
> header is already in. It's a bit late at that point. Out of interest,
> what is the cleanest way to nuke a connection at this stage
Agree this is way to late in the process. So what you need to do is to
inject your ProtocolFilter like the following:
When you embed Grizzly, create the com.sun.grizzly.http.SelectorThread
using the following (assuming t
SelectorThread mySelectorThread = new SelectorThread(){
/**
* Adds and configures <code>ProtocolChain</code>'s filters
* @param <code>ProtocolChain</code> to configure
*/
protected void configureFilters(ProtocolChain protocolChain) {
if (portUnificationFilter != null) {
protocolChain.addFilter(portUnificationFilter);
} else {
// =========== Inject your Filter here =======================//
ReadFilter readFilter = new MyReadFilter();
readFilter.setContinuousExecution(true);
protocolChain.addFilter(readFilter);
}
if (rcmSupport){
protocolChain.addFilter(createRaFilter());
}
protocolChain.addFilter(createHttpParserFilter());
}
};
This way your filter will be the first invoked without all the overhead
of the http protocol being executed.
>
> ___ Question #2 ___
>
> Running a large blog site you see a whole manner of nasty clients trying
> to really mess with you. One of things we see a lot of, is clients that
> will attempt a subtle DoS attack. They basically drip feed bytes to the
> server in such a speed as not to trip up any of the SO_TIMEOUT alarms.
> So one character a second for example, could tie up a connection for
> minutes. It doesn't take a lot of effort to really consume a server
> connections waiting.
>
> We've taken the approach, that if the complete HTTP header is not
> received within X seconds (5 we have found to be acceptable) then we
> deny this client from going on any further.
>
> Again, how would one manage this with Grizzly?
This is simple. Just set (this is a static method):
com.sun.grizzly.util.ByteBufferInputStream.setDefaultReadTimeout(//Timeout).
By default it is set to 30 seconds. This method tell Grizzly to wait
//timeout// seconds before considering it is a DoS when reading bytes.
This apply to both headers and body.
>
>
>
> Thanks again, and i look forward to hearing back and getting my sleeves
> rolled up with this one.
Thanks!
-- Jeanfrancois
>
> alan
>