summaryrefslogtreecommitdiffstats
path: root/src/main/java/org/openslx/taskmanager/tasks/DirectedRelay.java
blob: fffd707f001fa6379617900a5e9bbe93f85ef218 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
package org.openslx.taskmanager.tasks;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.security.cert.X509Certificate;
import java.util.Date;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.openslx.taskmanager.api.AbstractTask;

import com.google.gson.annotations.Expose;

public class DirectedRelay extends AbstractTask 
{
	
	protected Output status = new Output();
	
	@Expose
	public String ip;
	@Expose 
	public int port;
	
	@Override
	protected boolean execute()
	{
		SSLContext ctx = getSSLContext();
		if ( ctx == null )
			return false;
		
		try ( SSLSocket dbgSock = getDbgSock( ctx );
				SSLServerSocket srvSock = getSrvSock( ctx ) ) {
			connectToDbg( dbgSock );
			bindToPort( srvSock );
			try ( SSLSocket poolSock = ( SSLSocket ) srvSock.accept() ) {
				status.addMessage( "INFO: Connection from pool client established." );
				relay( dbgSock, poolSock );
			} catch ( Exception ex ) {
				throw( ex );
			}
		} catch ( Exception e ) {
			status.addMessage( "ERROR: " + e.getMessage() );
			return false;
		}
		return true;		
	}
	
	protected void connectToDbg ( SSLSocket dbgSock ) throws IOException {
		InetSocketAddress addr = new InetSocketAddress( ip, port );
		dbgSock.connect( addr );
		status.addMessage( "INFO: Connected to debug server at " + ip + ":" + port + "." );
		status.setDbgAddr( addr );
	}
	
	protected void bindToPort ( SSLServerSocket srvSock ) throws IOException {
		srvSock.bind( null );
		status.setListenPort( srvSock.getLocalPort() );
		status.addMessage( "INFO: Listening on localhost:" + status.getListenPort() + "." );
	}
	
	protected SSLContext getSSLContext() {
		SSLContext ctx = null;
		try {
			ctx = trustAll();
			status.addMessage( "INFO: SSLContext created." );
		} catch ( Exception e ) {
			status.addMessage( "ERROR: Failed to create SSLContext." );
		}
		return ctx;
	}

	private boolean relay( SSLSocket dbgSock, SSLSocket poolSock ) {
		Relay toDbg = new Relay( poolSock, dbgSock, status );
		Relay toPool = new Relay( dbgSock, poolSock, status );
		toDbg.setName( "PoolToDebug" );
		toPool.setName( "DebugToPool" );
		toDbg.start();
		toPool.start();
		
		try {
			for ( Relay r : new Relay[]{ toDbg, toPool })
				r.join();
		} catch ( InterruptedException ix ) {
			status.addMessage( "INFO: Relay closed: " + Thread.currentThread().getName() );
		}
			
		return true;
	}
	
	protected SSLContext trustAll () throws Exception 
	{
		TrustManager[] trustAllMgr = new TrustManager[] { new X509TrustManager() {
				public java.security.cert.X509Certificate[] getAcceptedIssuers() {
					return null;
				}
				public void checkClientTrusted( X509Certificate[] certs, String authType ) {}
				public void checkServerTrusted( X509Certificate[] certs, String authType ) {}
			}
		};
		SSLContext ctx = SSLContext.getInstance( "SSL" );
		ctx.init( null, trustAllMgr, new java.security.SecureRandom() );
		return ctx;
	}

	private SSLServerSocket getSrvSock( SSLContext ctx ) throws IOException
	{
		SSLServerSocketFactory sssf = ctx.getServerSocketFactory();
		return ( SSLServerSocket ) sssf.createServerSocket();
	}

	private SSLSocket getDbgSock( SSLContext ctx ) throws IOException
	{
		SSLSocketFactory ssf = ctx.getSocketFactory();
		return ( SSLSocket ) ssf.createSocket();
	}
	
	@Override
	protected boolean initTask() 
	{
		this.setStatusObject( this.status );
		status.addMessage( "INFO: Initiating directed relay to debug server at: " + ip + ":" + port + "." );
		return true;
	}
	
	public static class Output 
	{		
		
		protected String messages = null;
		protected Date d = null;
		protected InetSocketAddress dbgAddr = null;
		protected int listenPort;
		
		public void setListenPort ( int port ) { listenPort = port; }
		public int getListenPort ()	{ return listenPort; }
		public void setDbgAddr ( InetSocketAddress addr ) { dbgAddr = addr;	}
		
		public void addMessage( String str )
		{
			d = new Date();
			if ( messages == null ) {
				messages = d.toString() + "-" + str;
			} else {
				messages += "\n" + d.toString() + "-" + str;
			}
		}
	}
	
	private class Relay extends Thread
	{
		boolean active = true;
		private byte[] buffer = new byte[16384];
		
		private SSLSocket srcSock;
		private SSLSocket destSock;
		
		private Output status;
		
		public Relay ( SSLSocket srcSock, SSLSocket destSock, Output status ) {
			this.srcSock = srcSock;
			this.destSock = destSock;
			this.status = status;
		}
		
		@Override
		public void run() {
			boolean first = true;
			int readBytes;
			try ( InputStream in = srcSock.getInputStream();
					OutputStream out = destSock.getOutputStream() ) {
				while( active ) {
					readBytes = in.read( buffer );
					out.write( buffer, 0, readBytes );
					if ( first )
						status.addMessage( "INFO: Relay operating: " + this.getName() );
				}	
			} catch ( Exception e ) {
				active = false;
				return;
			}
		}	
	}
}