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 }