Skip to content

Instantly share code, notes, and snippets.

@ilmich
Created May 9, 2017 17:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ilmich/27b0e8b1aa3b400b9df0894166786b89 to your computer and use it in GitHub Desktop.
Save ilmich/27b0e8b1aa3b400b9df0894166786b89 to your computer and use it in GitHub Desktop.
Java NIO tcp tunnel
package ctptunnel;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class NioProxy {
// mappa client remoto - server remoto
private Map<SocketChannel, SocketChannel> proxy = new HashMap<SocketChannel, SocketChannel>();
private static final int BYTE_BUFFER_SIZE = 8192;
public void serve() {
try {
Selector serverSelector = Selector.open();
Selector remoteSelector = Selector.open();
ServerSocketChannel sChannel = ServerSocketChannel.open();
sChannel.configureBlocking(false);
sChannel.socket().bind(new InetSocketAddress(9090));
sChannel.register(serverSelector, SelectionKey.OP_ACCEPT);
while (true) {
if (serverSelector.select(1) > 0) {
Iterator<SelectionKey> iter = serverSelector.selectedKeys().iterator();
while (iter.hasNext()) {
SelectionKey key = iter.next();
iter.remove();
if (key.isValid() && key.isAcceptable()) {
SocketChannel sc = sChannel.accept();
sc.configureBlocking(false);
sc.finishConnect();
System.out.println("Accept remote connection from " + sc.socket().getRemoteSocketAddress().toString());
//apro connessione verso sistema esterno
try {
SocketChannel forwardTo = SocketChannel.open(new InetSocketAddress("localhost", 2080));
forwardTo.configureBlocking(false);
forwardTo.finishConnect();
forwardTo.register(remoteSelector, SelectionKey.OP_READ);
proxy.put(sc, forwardTo);
} catch (IOException e) {
System.out.println("Errore connessione remota");
sc.close();
break;
}
sc.register(serverSelector, SelectionKey.OP_READ);
key.interestOps(SelectionKey.OP_ACCEPT);
}
if (key.isValid() && key.isReadable()) {
SocketChannel remote = (SocketChannel) key.channel();
//prendo il canale remoto
SocketChannel forwardTo = proxy.get(key.channel());
ByteBuffer bb = ByteBuffer.allocateDirect(BYTE_BUFFER_SIZE);
int read = remote.read(bb);
if (read < 0) { // il client si è disconnesso
forwardTo.close();
proxy.remove(remote);
}
if (read > 0) { //client manda dati
bb.flip();
forwardTo.write(bb);
remote.register(serverSelector, SelectionKey.OP_READ);
}
}
}
}
if (remoteSelector.select(1) > 0) {
Iterator<SelectionKey> iter = remoteSelector.selectedKeys().iterator();
while (iter.hasNext()) {
SelectionKey key = iter.next();
iter.remove();
if (key.isValid() && key.isReadable()) { // leggo dal server remoto
ByteBuffer bb = ByteBuffer.allocateDirect(BYTE_BUFFER_SIZE);
SocketChannel forwardTo = (SocketChannel) key.channel();
int read = forwardTo.read(bb);
SocketChannel remoteClient = null;
for (SocketChannel remoteChannel : proxy.keySet()) {
if (proxy.get(remoteChannel).equals(forwardTo)){
remoteClient = remoteChannel;
if (read > 0) {
bb.flip();
remoteClient.write(bb);
} else { //server disconnesso
proxy.remove(remoteClient);
remoteClient.close();
}
break;
}
}
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* @param args
*/
public static void main(String[] args) {
new NioProxy().serve();
}
}
@fioli
Copy link

fioli commented May 9, 2017

ma un caso d'uso quale può essere?

@ilmich
Copy link
Author

ilmich commented May 10, 2017

Combattere la noia lavorativa :) Scherzi a parte questo è il primo step per creare un tunnel ssl efficiente (no threads) da embeddare in un applicazione java laddove nn sia applicabile (semplicità, tempi ridotti etc etc) che un preesistente sistema supporti la cifratura (nel mio caso specifico da http ad https). Nn mi piace reinventare la ruota ma le alternative erano framework con i quali spari ad una formica con un cannone.

@fioli
Copy link

fioli commented May 10, 2017

ok. la mia curiosità era sulla casistica d'utilizzo, ossia: quand'è che un client non può parlare direttamente con un server in SSL , ma deve passare per il tunnel?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment