1 module more.net_old;
2 
3 import std.bitmanip;
4 import std.conv;
5 import std.container;
6 import std.stdio;
7 import std.socket;
8 import std..string;
9 
10 import core.stdc.stdlib;
11 import core.thread;
12 
13 import more.common;
14 
15 /**
16    The maximum number of ascii characters of a domain name.
17    Note: includes delimiting dots but not a trailing dot.
18 */
19 enum MAX_DOMAIN_NAME_ASCII_CHARS = 253;
20 /**
21    The maximum number of a domain label, which is the string in between
22    the dots in a domain name.
23  */
24 enum MAX_DOMAIN_LABEL_ASCII_CHARS = 63;
25 
26 string tryRemoteAddressString(Socket sock)
27 {
28   Address addr;
29   try {
30     addr = sock.remoteAddress();
31   } catch(Exception e) {
32     return "(unknown address)";
33   }
34   return addr.toString();
35 }
36 
37 interface ISocketConnector
38 {
39   void connect(Socket socket, Address address);
40   //void connect(Socket socket, InternetAddress address);
41 }
42 //alias void delegate(Socket socket, Address address) SocketConnector;
43 
44 
45 /// examples:
46 ///    http:<ip-or-host>:<port>
47 ///    socks5:<ip-or-host>:<port>
48 ISocketConnector parseProxy(string proxyString)
49 {
50   if(proxyString == null || proxyString.length <= 0) return null;
51 
52   string[] splitStrings = split(proxyString, ":");
53   if(splitStrings.length != 3) throw new Exception("Proxy must have at least 2 colons");
54 
55   string proxyTypeString = splitStrings[0];
56   string ipOrHostString  = splitStrings[1];
57   string portString      = splitStrings[2];
58 
59   debug writefln("Proxy: '%s' Host: '%s' Port: '%s'", proxyTypeString, ipOrHostString, portString);
60 
61   ushort port = to!ushort(portString);
62 
63   if(proxyTypeString == "socks4") {
64     throw new Exception("Not implemented");
65   } else if(proxyTypeString == "socks5") {
66     return new Proxy5Connector(addressFromIPOrHost(ipOrHostString, port));
67   } else {
68     throw new Exception(format("Unknown proxy type '%s'", proxyTypeString));
69   }
70 }
71 string parseConnector(string connectorString, out ISocketConnector connector)
72 {
73   // Check for proxy
74   ptrdiff_t percentIndex = indexOf(connectorString, '%');
75   if(percentIndex == -1) {
76     connector = null;
77     return connectorString;
78   } else {
79     connector = parseProxy(connectorString[0..percentIndex]);
80     return connectorString[percentIndex+1..$];
81   }
82 }
83 
84 Address addressFromIPOrHostAndPort(const(char)[] ipOrHostAndPort)
85 {
86   ptrdiff_t colonIndex = indexOf(ipOrHostAndPort, ':');
87 
88   if(colonIndex == -1)
89     throw new Exception(format("ipOrHost '%s' is missing a colon to indicate the port", ipOrHostAndPort));
90 
91   auto ipOrHost = ipOrHostAndPort[0..colonIndex];
92   auto port = to!ushort(ipOrHostAndPort[colonIndex+1..$]);
93 
94   return addressFromIPOrHost(ipOrHost, port);
95 }
96 
97 Address addressFromIPOrHostAndOptionalPort(string ipOrHostAndOptionalPort, ushort defaultPort)
98 {
99   ptrdiff_t colonIndex = indexOf(ipOrHostAndOptionalPort, ':');
100 
101   string ipOrHost;
102   ushort port;
103 
104   if(colonIndex == -1) {
105     ipOrHost = ipOrHostAndOptionalPort;
106     port = defaultPort;
107   } else {
108     ipOrHost = ipOrHostAndOptionalPort[0..colonIndex];
109     port = to!ushort(ipOrHostAndOptionalPort[colonIndex+1..$]);
110   }
111 
112   return addressFromIPOrHost(ipOrHost, port);
113 }
114 auto addressFromIPOrHost(const(char)[] ipOrHost, ushort port)
115 {
116 /+
117   debug writefln("Parsing Address '%s' (port=%s)", ipOrHost, port);
118   Address addr = parseAddress(ipOrHost, port);
119   debug writeln("done");
120   return addr;
121 +/
122   //return parseAddress(ipOrHost, port);
123   return new InternetAddress(ipOrHost, port);
124 }
125 
126 
127 void receiveAll(Socket socket, ubyte[] buffer)
128 {
129   ptrdiff_t lastBytesRead;
130   do {
131     lastBytesRead = socket.receive(buffer);
132     buffer = buffer[lastBytesRead..$];
133     if(buffer.length <= 0) return;
134   } while(lastBytesRead > 0);
135   throw new Exception("socket closed but still expected more data");
136 }
137 
138 
139 
140 class Proxy5Connector : ISocketConnector
141 {
142   Address proxyAddress;
143   this(Address proxyAddress) {
144     this.proxyAddress = proxyAddress;
145   }
146   public void connect(Socket socket, Address address)
147   {
148     InternetAddress inetAddress = cast(InternetAddress)address;
149 
150     if(!(inetAddress is null)) {
151       proxy5connect(socket, proxyAddress, inetAddress);
152       return;
153     }
154 
155     throw new Exception(format("The Proxy5 connector does not handle addresses of type '%s'", typeid(address)));
156   }
157 }
158 
159 
160 void proxy5connect(Socket socket, Address proxy, InternetAddress address)
161 {
162   debug writefln("Proxy5: Final Destination: '%s'", address);
163 
164   ubyte buffer[21];
165 
166   debug writefln("Connecting to Proxy '%s'", proxy);
167   socket.connect(proxy);
168   debug writeln("Connected");
169 
170   //
171   // Send initial greeting
172   //
173   buffer[0] = 5; // SOCKS version 5
174   buffer[1] = 1; // 1 Authentication protocol
175   buffer[2] = 0; // No authentication
176   debug writeln("Proxy5: Sending initial greeting...");
177   socket.send(buffer[0..3]);
178 
179   //
180   // Get response
181   //
182   debug writeln("Proxy5: Receiving response...");
183   socket.receiveAll(buffer[0..2]);
184   if(buffer[0] != 5) throw new Exception("The given proxy does not support SOCKS version 5");
185   if(buffer[1] != 0) throw new Exception("Server does not support NO_AUTHENTICATION");
186 
187   //
188   // Send CONNECT command
189   //
190   buffer[0] = 5; // SOCKS version 5
191   buffer[1] = 1; // CONNECT command
192   buffer[2] = 0; // Reserved
193 
194   uint ip = address.addr();
195   debug writeln("Converting address to big endian...");
196   ubyte[4] ipNetworkOrder = nativeToBigEndian(ip);
197   debug writeln("Done");
198   buffer[3] = 1; // IPv4 address
199   buffer[4] = ipNetworkOrder[0];
200   buffer[5] = ipNetworkOrder[1];
201   buffer[6] = ipNetworkOrder[2];
202   buffer[7] = ipNetworkOrder[3];
203 
204   ushort port = address.port();
205   buffer[8] = cast(ubyte)(port >> 8);
206   buffer[9] = cast(ubyte)(port     );
207   debug writeln("Proxy5: Sending CONNECT");
208   socket.send(buffer[0..10]);
209 
210   //
211   // Get final response
212   //
213   socket.receiveAll(buffer[0..10]);
214   if(buffer[1] != 0) throw new Exception("Proxy server failed to connect to host");
215 }
216 
217 
218 
219 
220 
221 class TunnelThread : Thread
222 {
223   public Socket socketA, socketB;
224   this()
225   {
226     super( &run );
227   }
228   void run() {
229     SocketSet selectSockets;
230     ubyte[] buffer = new ubyte[1024];
231 
232     while(true) {
233       selectSockets.add(socketA);
234       selectSockets.add(socketB);
235 
236       Socket.select(selectSockets, null, null);
237 
238       ptrdiff_t bytesRead;
239       if(selectSockets.isSet(socketA)) {
240         bytesRead = socketA.receive(buffer);
241         if(bytesRead == 0) {
242           socketB.shutdown(SocketShutdown.BOTH);
243           break;
244         }
245         socketB.send(buffer);
246       }
247       if(selectSockets.isSet(socketB)) {
248         bytesRead = socketB.receive(buffer);
249         if(bytesRead == 0) {
250           socketA.shutdown(SocketShutdown.BOTH);
251           break;
252         }
253         socketA.send(buffer);
254       }
255     }
256     socketA.close();
257     socketB.close();
258   }
259 }
260 
261 struct Tunnels
262 {
263   public static void add(Socket socketA, Socket socketB)
264   {
265     TunnelThread tunnel;
266     tunnel.socketA = socketA;
267     tunnel.socketB = socketB;
268     tunnel.start();
269   }
270 }
271 
272 
273 struct TcpSocketPair {
274   Socket socketA, socketB;
275 }
276 
277 alias void delegate(ISocketSelector selector, Socket socket) SocketHandler;
278 
279 // Called with null if the socket was closed
280 alias void delegate(ISocketSelector selector, ref DataSocketAndHandler handler, ubyte[] data) DataSocketHandler;
281 
282 
283 interface ISocketSelector
284 {
285   void addSocket(Socket socket, SocketHandler handler);
286   void addDataSocket(Socket socket, DataSocketHandler handler);
287 }
288 
289 struct SocketAndHandler
290 {
291   public Socket socket;
292   public SocketHandler handler;
293 }
294 
295 struct DataSocketAndHandler
296 {
297   public Socket socket;
298   public DataSocketHandler handler;
299 }
300 
301 /// You cannot manually remove data sockets, they must be shutdown to be removed.
302 /// This is so the select loops will not be messed up.
303 class SimpleSelector : Thread, ISocketSelector
304 {
305   const size_t bufferSize;
306   ArrayList!SocketAndHandler handlers;
307   ArrayList!DataSocketAndHandler dataHandlers;
308   public this(T)(size_t bufferSize, T initialHandlers)
309   {
310     super(&run);
311     this.bufferSize = bufferSize;
312     this.handlers = ArrayList!SocketAndHandler(initialHandlers);
313     this.dataHandlers = ArrayList!(DataSocketAndHandler)(16);
314   }
315 
316   /// Note: this method must add the socket to the end of the socket list
317   ///       in order to not mess up the select loop
318   void addSocket(Socket socket, SocketHandler handler)
319   {
320     SocketAndHandler s = SocketAndHandler(socket, handler);
321     handlers.put(s);
322   }
323   /// Note: this method must add the socket to the end of the socket list
324   ///       in order to not mess up the select loop
325   void addDataSocket(Socket socket, DataSocketHandler handler)
326   {
327     DataSocketAndHandler s = DataSocketAndHandler(socket, handler);
328     dataHandlers.put(s);
329     debug{writefln("Added DataSocket '%s' (%s total data sockets)", socket.tryRemoteAddressString(), dataHandlers.count); stdout.flush();}
330   }
331   void run()
332   {
333     ubyte[] buffer = new ubyte[bufferSize];
334     //ubyte[] buffer = (cast(ubyte*)alloca(bufferSize))[0..bufferSize];
335 
336     SocketSet selectSockets = new SocketSet();
337     ptrdiff_t bytesRead;
338     int socketsAffected;
339 
340   SELECT_LOOP_START:
341     while(true) {
342       selectSockets.reset();
343       foreach(i; 0..handlers.count) {
344         selectSockets.add(handlers.array[i].socket);
345       }
346       foreach(i; 0..dataHandlers.count) {
347         selectSockets.add(dataHandlers.array[i].socket);
348       }
349 
350       socketsAffected = Socket.select(selectSockets, null, null);
351 
352       if(socketsAffected <= 0) throw new Exception(format("Select returned %s but no timeout was specified", socketsAffected));
353 
354       // Handle regular sockets
355       foreach(i; 0..handlers.count) {
356         SocketAndHandler handler = handlers.array[i];
357         if(selectSockets.isSet(handler.socket)) {
358           handler.handler(this, handler.socket);
359           socketsAffected--;
360           if(socketsAffected == 0) goto SELECT_LOOP_START;
361         }
362       }
363       // Handle data sockets
364       for(size_t i = 0; i < dataHandlers.count; i++) {
365         auto socket = dataHandlers.array[i].socket;
366         if(selectSockets.isSet(socket)) {
367           bytesRead = socket.receive(buffer);
368           if(bytesRead <= 0) {
369             dataHandlers.array[i].handler(this, dataHandlers.array[i], null);
370             dataHandlers.removeAt(i);
371             i--;
372             debug{writefln("Removed DataSocket '%s' (%s data sockets left)", socket.tryRemoteAddressString(), dataHandlers.count);stdout.flush();}
373           } else {
374             debug{writefln("Received %s bytes", bytesRead);stdout.flush();}
375             dataHandlers.array[i].handler(this, dataHandlers.array[i], buffer[0..bytesRead]);
376             if(dataHandlers.array[i].handler is null) {
377               try { socket.shutdown(SocketShutdown.BOTH); } catch { }
378               try { socket.close(); } catch { }
379               dataHandlers.removeAt(i);
380               i--;
381             }
382           }
383           socketsAffected--;
384           if(socketsAffected == 0) goto SELECT_LOOP_START;
385         }
386       }
387     }
388   }
389 }