0
votes

I am looking for a Hook allowing me to tell/instruct the ServerConnector (or whatever other object in the Jetty architecture that would be a more suitable hook-point) NOT to accept an incoming TCP/IP connection on the Web Server ports (eg: 80 or 443) based on the IP address of the remote party (because that is all the info there is available before accept() is called and before, LATER after accept, the HTTP data becomes available from the TCP/IP frame's payload).

The idea is that I would attach a peace of software to that hook that for each incoming connection can say : Accept/Revoke. With revoke the incoming connection would be IGNORED and the socket would stay closed avoiding the Jetty container to do more work/use resources on it.

It would also make it possible to protect system features (eg. special admin menu) after certain server ports by only accepting, for example, local addresses (10.32....), etc. It would have been even nicer to ALSO be able to get to the MAC address of the connecting device and only allow access if the MAC address is in an authorisation list (=the user had physical access to the LAN to connect his device or else his MAC address would never be the one that is seen on the LAN because there is no peer to peer MAC address exchange if not on the same LAN).

In this way I intend to prevent hostile connections to consume CPU, bandwidth and sockets just to send them the 'main' pages during attacks and force them into waiting for time-outs. At the same time it would additionally allow to protect access to non public features based on 'physical local access'. The hook software could even revoke connections on parts of the IP address, for instance the Chinese IP address range, etc.

I found the typical TCP/IP socket interface on the ServerConnector classes (open/close/accept/...) but I didn't find a place where I could register for a pre-accept() hook or callback. I also looked at the ServerConnector's class ancestors but I didn't really see anything of the sorts either. I started with org.eclipse.jetty.server Class ServerConnector

For clarity, and for people that are more confortabel with code, this would conceptually represent in code what I look for.

...setup Jetty server, Factories, etc

ServerConnector http2=new ServerConnector(this.oServer,sslF,alpnF,h2F,https2F);
http2.setPort(8443);

http2.setPreAcceptHook(8843, oMyHook); <---INVENTED line

this.oServer.addConnector(http2);

The hook would be a simple method of the MyHook object that returns true or false.

boolean AcceptRevoke(IP, Port) <--return true=accept, false=revoke

I would welcome any hint as to what direction to look in (a class name or so) or a confirmation that such feature is not available or cannot be and therefore never will be available. There may be constraints in container design that would not allow a pre-accept revocation, like those one can do with socket libraries, that I am not aware of and hence would be looking for an impossibility.

Many Thanks.

Product and Versions Info: Jetty 9.3.0 (v20150612) alpn-boot-8.1.3 (v20150130) JRE 8 (Oracle 1.8.0 Build 45 - b15)

2

2 Answers

1
votes

You have A LOT OF WORK ahead of you.

To do this, you'll essentially have to provide your own Socket implementation layer for Java. There is no layer you can hook onto in Jetty that allows you to do anything that you mentioned. The kinds of things you want to do are at a much lower level, something at the JVM and/or OS levels.

You'll need to handle java.net.Socket, java.net.ServerSocket, and java.nio.channels.ServerSocketChannel.

Which means you'll be writing your own javax.net.ServerSocketFactory, javax.net.SocketFactory, java.net.SocketImpl, and java.net.SocketImplFactory for regular Sockets.

And for SSL/TLS, you'll need to write/handle/manage your own javax.net.ssl.SSLSocket, javax.net.ssl.SSLServerSocket, javax.net.ssl.SSLSocketFactory, and javax.net.ssl.SSLServerSocketFactory.

And don't forget to grab all of the jetty-alpn code additions to the standard OpenJDK SSL libraries so that you can get HTTP/2 working for you as well (seeing as you are obviously using it, based on your question details)

Before you test this on Jetty, test your implementation on a simple ServerSocket and ServerSocketChannel setup.

After you confirm it does what you want, then you'll need to wire it up into Jetty. For normal ServerSocket / ServerSocketChannel, you'll have to work with the system-wide the java.nio.channels.spi.SelectorProvider

For SSLServerSocket / SSLServerSocketChannel, you'll wire it up via a custom/overridden org.eclipse.jetty.util.ssl.SslContextFactory implementation of your own.

Or ...

You can use a combination of post-accept logic (built into Jetty) and OS level management of connections (such as iptables), which would be far simpler.

The requirement you stated to hook into a point before accept is possible with a Java server, but is a special kind of effort where you extend the core Java networking and Socket behaviors.

0
votes

As an alternative, you could probably just override the configure(Socket socket) method of the ServerConnector. If you want to reject the socket, just close the connection. This might cause some strange exceptions, if so report them in Bugzilla and we'll clean up.

Alternatively, open a Bugzilla to ask us to make the accepted(Socket socket) method protected instead of private and you can reject there.

Note that with either of these, the client will see the connection as accepted and then immediately close.