package net.kanstren.tcptunnel.forwarder; import net.kanstren.tcptunnel.Params; import net.kanstren.tcptunnel.Utils; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.text.SimpleDateFormat; import java.util.Date; /** * Handles some basic DNS query tunneling.. * * Created by AlexZhuo on 2017/11/9. */ public class DNSTunnel extends Thread { private SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MMM.dd HH:mm:ss"); /** Configuration parameters. */ private final Params params; private boolean active = false; /** Socket to receive packets from source. */ private DatagramSocket sourceSocket; public DNSTunnel(Params params, DatagramSocket sourceSocket) { this.params = params; this.sourceSocket = sourceSocket; } public void run() { String dateStr = sdf.format(new Date()); byte[] buffer = new byte[65536]; DatagramPacket packet = new DatagramPacket(buffer, buffer.length); while (true) { try { packet.setData(buffer); packet.setLength(buffer.length); sourceSocket.receive(packet); active = true; InetAddress sourceAddress = packet.getAddress(); int srcPort = packet.getPort(); InetAddress address = InetAddress.getByName(params.getRemoteHost()); String strAddr = toStr(packet); if (params.isPrint()) { System.out.println(dateStr + ": DNS Forwarding " +packet.getLength()+ " bytes " + strAddr + " --> " + address.getHostAddress() + ":" + params.getRemotePort()); } //send client request to server packet.setPort(params.getRemotePort()); packet.setAddress(address); Thread tunnel = new DNSForwarder(packet, sourceSocket, sourceAddress, srcPort, params); tunnel.start(); } catch (Throwable e) { if (params.isPrint()) { String remoteAddr = params.getRemoteHost() + ":" + params.getRemotePort(); String humanRemoteAddr = Utils.mapAddrToHumanReadable(remoteAddr); remoteAddr = remoteAddr + " (" + humanRemoteAddr + ")"; System.err.println(dateStr + ": Failed to connect to remote host (" + remoteAddr + ")"); e.printStackTrace(); } connectionBroken(); } } } private String toStr(DatagramPacket packet) { String host = packet.getAddress().getHostAddress(); int port = packet.getPort(); return host + ":" + port; } private String toStr(DatagramSocket socket) { String host = socket.getInetAddress().getHostAddress(); int port = socket.getPort(); return host + ":" + port; } public String toStr(DNSForwarder f) { String host = f.getFwdAddr().getHostAddress(); int port = f.getFwdPort(); return host + ":" + port; } public void close() { connectionBroken(); } public synchronized void connectionBroken() { try { sourceSocket.close(); } catch (Exception e) { } if (active) { String dateStr = sdf.format(new Date()); if (params.isPrint()) System.out.println(dateStr + ": DNS Forwarding " + toStr(sourceSocket) + " <--> " + params.getRemoteHost() + ":" + params.getRemotePort() + " stopped."); active = false; } } }