1 3 package org.jgroups.util; 4 5 6 import javax.net.ssl.SSLServerSocket; 7 import javax.net.ssl.SSLServerSocketFactory; 8 import javax.net.ssl.SSLSocketFactory; 9 import java.io.*; 10 import java.net.*; 11 import java.nio.ByteBuffer ; 12 import java.nio.channels.SelectionKey ; 13 import java.nio.channels.Selector ; 14 import java.nio.channels.ServerSocketChannel ; 15 import java.nio.channels.SocketChannel ; 16 import java.util.*; 17 import java.util.concurrent.Executor ; 18 import java.util.concurrent.LinkedBlockingQueue ; 19 import java.util.concurrent.ThreadPoolExecutor ; 20 import java.util.concurrent.TimeUnit ; 21 22 23 68 public class Proxy { 69 InetAddress local=null, remote=null; 70 int local_port=0, remote_port=0; 71 static boolean verbose=false; 72 static boolean debug=false; 73 String mapping_file=null; final HashMap mappings=new HashMap(); Executor executor; static final int MIN_THREAD_POOL_SIZE=2; 77 static final int MAX_THREAD_POOL_SIZE=64; static final int BUFSIZE=1024; 80 81 82 public Proxy(InetAddress local, int local_port, InetAddress remote, int remote_port, boolean verbose, boolean debug) { 83 this.local=local; 84 this.local_port=local_port; 85 this.remote=remote; 86 this.remote_port=remote_port; 87 Proxy.verbose=verbose; 88 Proxy.debug=debug; 89 } 90 91 public Proxy(InetAddress local, int local_port, InetAddress remote, int remote_port, 92 boolean verbose, boolean debug, String mapping_file) { 93 this(local, local_port, remote, remote_port, verbose, debug); 94 this.mapping_file=mapping_file; 95 } 96 97 public void start() throws Exception { 98 Map.Entry entry; 99 Selector selector; 100 ServerSocketChannel sock_channel; 101 MyInetSocketAddress key, value; 102 103 if (remote !=null && local !=null) 104 mappings.put(new InetSocketAddress(local, local_port), new InetSocketAddress(remote, remote_port)); 105 106 if (mapping_file !=null) { 107 try { 108 populateMappings(mapping_file); 109 } 110 catch (Exception ex) { 111 log("Failed reading " + mapping_file); 112 throw ex; 113 } 114 } 115 116 log("\nProxy started at " + new java.util.Date ()); 117 118 if (verbose) { 119 log("\nMappings:\n---------"); 120 for (Iterator it=mappings.entrySet().iterator(); it.hasNext();) { 121 entry=(Map.Entry) it.next(); 122 log(toString((InetSocketAddress) entry.getKey()) + " <--> " 123 + toString((InetSocketAddress) entry.getValue())); 124 } 125 log("\n"); 126 } 127 128 selector=Selector.open(); 130 131 executor=new ThreadPoolExecutor (MIN_THREAD_POOL_SIZE, MAX_THREAD_POOL_SIZE, 30000, TimeUnit.MILLISECONDS, 133 new LinkedBlockingQueue (1000)); 134 135 for (Iterator it=mappings.keySet().iterator(); it.hasNext();) { 136 key=(MyInetSocketAddress) it.next(); 137 value=(MyInetSocketAddress) mappings.get(key); 138 139 142 if (key.ssl() || value.ssl()) { 143 SocketAcceptor acceptor=new SocketAcceptor(key, value); 145 executor.execute(acceptor); 146 continue; 147 } 148 149 sock_channel=ServerSocketChannel.open(); 151 sock_channel.configureBlocking(false); 152 sock_channel.socket().bind(key); 153 154 sock_channel.register(selector, SelectionKey.OP_ACCEPT, key); 158 } 159 160 loop(selector); 162 } 163 164 165 166 167 void loop(Selector selector) { 168 Set ready_keys; 169 SelectionKey key; 170 ServerSocketChannel srv_sock; 171 SocketChannel in_sock, out_sock; 172 InetSocketAddress src, dest; 173 174 while (true) { 175 if (verbose) 176 log("[Proxy] ready to accept connection"); 177 178 try { 180 selector.select(); 181 182 ready_keys=selector.selectedKeys(); 184 for (Iterator it=ready_keys.iterator(); it.hasNext();) { 185 key=(SelectionKey ) it.next(); 186 it.remove(); 187 188 if (key.isAcceptable()) { 189 srv_sock=(ServerSocketChannel ) key.channel(); 190 SRC=(InetSocketAddress) key.attachment(); 192 in_sock=srv_sock.accept(); if (verbose) 194 log("Proxy.loop()", "accepted connection from " + toString(in_sock)); 195 dest=(InetSocketAddress) mappings.get(src); 196 if (dest == null) { 198 in_sock.close(); 199 log("Proxy.loop()", "did not find a destination host for " + src); 200 continue; 201 } 202 else { 203 if (verbose) 204 log("Proxy.loop()", "relaying traffic from " + toString(src) + " to " + toString(dest)); 205 } 206 207 try { 209 out_sock=SocketChannel.open(dest); 210 handleConnection(in_sock, out_sock); 212 } 213 catch (Exception ex) { 214 in_sock.close(); 215 throw ex; 216 } 217 } 218 } 219 } 220 catch (Exception ex) { 221 log("Proxy.loop()", "exception: " + ex); 222 } 223 } 224 } 225 226 241 void handleConnection(SocketChannel in, SocketChannel out) { 242 try { 243 _handleConnection(in, out); 244 } 245 catch (Exception ex) { 246 log("Proxy.handleConnection()", "exception: " + ex); 247 } 248 } 249 250 void _handleConnection(final SocketChannel in_channel, final SocketChannel out_channel) throws Exception { 251 executor.execute(new Runnable () { 252 public void run() { 253 Selector sel=null; 254 SocketChannel tmp; 255 Set ready_keys; 256 SelectionKey key; 257 ByteBuffer transfer_buf=ByteBuffer.allocate(BUFSIZE); 258 259 try { 260 sel=Selector.open(); 261 in_channel.configureBlocking(false); 262 out_channel.configureBlocking(false); 263 in_channel.register(sel, SelectionKey.OP_READ); 264 out_channel.register(sel, SelectionKey.OP_READ); 265 266 while (sel.select() > 0) { 267 ready_keys=sel.selectedKeys(); 268 for (Iterator it=ready_keys.iterator(); it.hasNext();) { 269 key=(SelectionKey ) it.next(); 270 it.remove(); tmp=(SocketChannel ) key.channel(); 272 if (tmp == null) { 273 log( 274 "Proxy._handleConnection()", 275 "attachment is null, continuing"); 276 continue; 277 } 278 if (key.isReadable()) { if (tmp == in_channel) { 280 if (relay(tmp, out_channel, transfer_buf) == false) 282 return; 283 } 284 if (tmp == out_channel) { 285 if (relay(tmp, in_channel, transfer_buf) == false) 288 return; 289 } 290 } 291 } 292 } 293 } 294 catch (Exception ex) { 295 ex.printStackTrace(); 296 } 297 finally { 298 close(sel, in_channel, out_channel); 299 } 300 } 301 }); 302 } 303 304 void close(Selector sel, SocketChannel in_channel, SocketChannel out_channel) { 305 try { 306 if (sel !=null) 307 sel.close(); 308 } 309 catch (Exception ex) { 310 } 311 try { 312 if (in_channel !=null) 313 in_channel.close(); 314 } 315 catch (Exception ex) { 316 } 317 try { 318 if (out_channel !=null) 319 out_channel.close(); 320 } 321 catch (Exception ex) { 322 } 323 } 324 325 326 330 boolean relay(SocketChannel from, SocketChannel to, ByteBuffer buf) throws Exception { 331 int num; 332 StringBuffer sb; 333 334 buf.clear(); 335 while (true) { 336 num=from.read(buf); 337 if (num < 0) 338 return false; 339 else 340 if (num == 0) 341 return true; 342 buf.flip(); 343 if (verbose) { 344 log(printRelayedData(toString(from), toString(to), buf.remaining())); 345 } 346 if (debug) { 347 sb=new StringBuffer (); 348 sb.append(new String (buf.array()).trim()); 349 sb.append('\n'); 350 log(sb.toString()); 351 } 352 to.write(buf); 353 buf.flip(); 354 } 355 } 356 357 String toString(SocketChannel ch) { 358 StringBuilder sb=new StringBuilder (); 359 Socket sock; 360 361 if (ch == null) 362 return null; 363 if ((sock=ch.socket()) == null) 364 return null; 365 sb.append(sock.getInetAddress().getHostName()).append(':').append(sock.getPort()); 366 return sb.toString(); 367 } 368 369 String toString(InetSocketAddress addr) { 370 StringBuffer sb; 371 sb=new StringBuffer (); 372 373 if (addr == null) 374 return null; 375 sb.append(addr.getAddress().getHostName()).append(':').append(addr.getPort()); 376 if (addr instanceof MyInetSocketAddress) 377 sb.append(" [ssl=").append(((MyInetSocketAddress) addr).ssl()).append(']'); 378 return sb.toString(); 379 } 380 381 382 static String printRelayedData(String from, String to, int num_bytes) { 383 StringBuffer sb; 384 sb=new StringBuffer (); 385 sb.append("\n[PROXY] ").append(from); 386 sb.append(" to ").append(to); 387 sb.append(" (").append(num_bytes).append(" bytes)"); 388 return sb.toString(); 390 } 391 392 393 402 void populateMappings(String filename) throws Exception { 403 FileInputStream in=new FileInputStream(filename); 404 BufferedReader reader; 405 String line; 406 URI key, value; 407 int index; 408 boolean ssl_key, ssl_value; 409 final String HTTPS="https"; 410 411 reader=new BufferedReader(new InputStreamReader(in)); 412 while ((line=reader.readLine()) !=null) { 413 line=line.trim(); 414 if (line.startsWith("//") || line.startsWith("#") || line.length() == 0) 415 continue; 416 index=line.indexOf('='); 417 if (index == -1) 418 throw new Exception ("Proxy.populateMappings(): detected no '=' character in " + line); 419 key=new URI(line.substring(0, index)); 420 ssl_key=key.getScheme().trim().equals(HTTPS); 421 422 value=new URI(line.substring(index + 1)); 423 ssl_value=value.getScheme().trim().equals(HTTPS); 424 425 check(key); 426 check(value); 427 428 log("key: " + key + ", value: " + value); 429 430 mappings.put(new MyInetSocketAddress(key.getHost(), key.getPort(), ssl_key), 431 new MyInetSocketAddress(value.getHost(), value.getPort(), ssl_value)); 432 } 433 in.close(); 434 } 435 436 437 void check(URI u) throws Exception { 438 if (u.getScheme() == null) 439 throw new Exception ( 440 "scheme is null in " + u + ", (valid URI is \"http(s)://<host>:<port>\")"); 441 442 if (u.getHost() == null) 443 throw new Exception ( 444 "host is null in " + u + ", (valid URI is \"http(s)://<host>:<port>\")"); 445 446 if (u.getPort() <=0) 447 throw new Exception ( 448 "port is <=0 in " + u + ", (valid URI is \"http(s)://<host>:<port>\")"); 449 450 } 451 452 453 SocketAddress strToAddr(String input) throws Exception { 454 StringTokenizer tok=new StringTokenizer(input, ":"); 455 String host, port; 456 457 host=tok.nextToken(); 458 port=tok.nextToken(); 459 return new InetSocketAddress(host, Integer.parseInt(port)); 460 } 461 462 String printSelectionOps(SelectionKey key) { 463 StringBuilder sb=new StringBuilder (); 464 if ((key.readyOps() & SelectionKey.OP_ACCEPT) !=0) 465 sb.append("OP_ACCEPT "); 466 if ((key.readyOps() & SelectionKey.OP_CONNECT) !=0) 467 sb.append("OP_CONNECT "); 468 if ((key.readyOps() & SelectionKey.OP_READ) !=0) 469 sb.append("OP_READ "); 470 if ((key.readyOps() & SelectionKey.OP_WRITE) !=0) 471 sb.append("OP_WRITE "); 472 return sb.toString(); 473 } 474 475 public static void main(String [] args) { 476 Proxy p; 477 InetAddress local=null, remote=null; 478 int local_port=0, remote_port=0; 479 String tmp, tmp_addr, tmp_port; 480 boolean verbose=false, debug=false; 481 int index; 482 String mapping_file=null; 483 484 try { 485 for (int i=0; i < args.length; i++) { 486 tmp=args[i]; 487 if ("-help".equals(tmp)) { 488 help(); 489 return; 490 } 491 if ("-verbose".equals(tmp)) { 492 verbose=true; 493 continue; 494 } 495 if ("-local".equals(tmp)) { 496 tmp_addr=args[++i]; 497 index=tmp_addr.indexOf(':'); 498 if (index > -1) { tmp_port=tmp_addr.substring(index + 1); 500 local_port=Integer.parseInt(tmp_port); 501 tmp_addr=tmp_addr.substring(0, index); 502 local=InetAddress.getByName(tmp_addr); 503 } 504 else 505 local=InetAddress.getByName(args[++i]); 506 continue; 507 } 508 if ("-local_port".equals(tmp)) { 509 local_port=Integer.parseInt(args[++i]); 510 continue; 511 } 512 if ("-remote".equals(tmp)) { 513 tmp_addr=args[++i]; 514 index=tmp_addr.indexOf(':'); 515 if (index > -1) { tmp_port=tmp_addr.substring(index + 1); 517 remote_port=Integer.parseInt(tmp_port); 518 tmp_addr=tmp_addr.substring(0, index); 519 remote=InetAddress.getByName(tmp_addr); 520 } 521 else 522 remote=InetAddress.getByName(args[++i]); 523 continue; 524 } 525 if ("-remote_port".equals(tmp)) { 526 remote_port=Integer.parseInt(args[++i]); 527 continue; 528 } 529 if ("-file".equals(tmp)) { 530 mapping_file=args[++i]; 531 continue; 532 } 533 if ("-debug".equals(tmp)) { 534 debug=true; 535 continue; 536 } 537 help(); 538 return; 539 } 540 541 if (local == null) 542 local=InetAddress.getLocalHost(); 543 544 p=new Proxy(local, local_port, remote, remote_port, verbose, debug, mapping_file); 545 p.start(); 546 } 547 catch (Throwable ex) { 548 ex.printStackTrace(); 549 } 550 } 551 552 static void help() { 553 System.out.println("Proxy [-help] [-local <local address>] [-local_port <port>] " 554 + "[-remote <remote address>] [-remote_port <port>] [-verbose] " 555 + "[-file <mapping file>] [-debug]"); 556 } 557 558 static void log(String method_name, String msg) { 559 System.out.println('[' + method_name + "]: " + msg); 560 } 561 562 static void log(String msg) { 563 System.out.println(msg); 564 } 565 566 static void close(Socket in, Socket out) { 567 if (in !=null) { 568 try { 569 in.close(); 570 } 571 catch (Exception ex) { 572 } 573 } 574 if (out !=null) { 575 try { 576 out.close(); 577 } 578 catch (Exception ex) { 579 } 580 } 581 } 582 583 static void close(Socket sock) { 584 if (sock !=null) { 585 try { 586 sock.close(); 587 } 588 catch (Exception ex) { 589 } 590 } 591 } 592 593 static class Relayer implements Runnable { 594 final Socket in_sock; 595 final Socket out_sock; 596 final InputStream in; 597 final OutputStream out; 598 Thread t=null; 599 final java.util.List listeners=new ArrayList(); 600 String name=null; 601 602 interface Listener { 603 void connectionClosed(); 604 } 605 606 public Relayer(Socket in_sock, Socket out_sock, String name) throws Exception { 607 this.in_sock=in_sock; 608 this.out_sock=out_sock; 609 this.name=name; 610 in=in_sock.getInputStream(); 611 out=out_sock.getOutputStream(); 612 } 613 614 public void addListener(Listener l) { 615 if(l != null && !listeners.contains(l)) 616 listeners.add(l); 617 } 618 619 620 public void run() { 621 byte[] buf=new byte[1024]; 622 int num; 623 StringBuffer sb; 624 625 try { 626 while(t != null) { 627 if ((num=in.read(buf)) == -1) 628 break; 629 630 if (verbose) { 631 632 634 635 log(printRelayedData(toString(in_sock), toString(out_sock), num)); 639 } 640 if (debug) { 641 sb=new StringBuffer (); 642 sb.append(new String (buf, 0, num).trim()); 643 log(sb.toString()); 644 } 645 646 out.write(buf, 0, num); 647 } 650 651 } 652 catch (Exception ex) { 653 log("Proxy.Relayer.run(): [" + name + "] exception=" + ex + ", in_sock=" + 654 in_sock + ", out_sock=" + out_sock); 655 } 656 finally { 657 stop(); 658 } 659 } 660 661 public void start() { 662 if(t == null) { 663 t=new Thread (this, "Proxy.Relayer"); 664 t.setDaemon(true); 665 t.start(); 666 } 667 } 668 669 public void stop() { 670 t=null; 671 close(in_sock); 672 close(out_sock); 673 } 674 675 String toString(Socket s) { 676 if(s == null) return null; 677 return s.getInetAddress().getHostName() + ':' + s.getPort(); 678 } 679 680 681 void notifyListeners() { 682 for(Iterator it=listeners.iterator(); it.hasNext();) { 683 try { 684 ((Listener)it.next()).connectionClosed(); 685 } 686 catch(Throwable ex) { 687 ; 688 } 689 } 690 } 691 } 692 693 static class MyInetSocketAddress extends InetSocketAddress { 694 boolean is_ssl=false; 695 696 public MyInetSocketAddress(InetAddress addr, int port) { 697 super(addr, port); 698 } 699 700 public MyInetSocketAddress(InetAddress addr, int port, boolean is_ssl) { 701 super(addr, port); 702 this.is_ssl=is_ssl; 703 } 704 705 public MyInetSocketAddress(int port) { 706 super(port); 707 } 708 709 public MyInetSocketAddress(int port, boolean is_ssl) { 710 super(port); 711 this.is_ssl=is_ssl; 712 } 713 714 public MyInetSocketAddress(String hostname, int port) { 715 super(hostname, port); 716 } 717 718 public MyInetSocketAddress(String hostname, int port, boolean is_ssl) { 719 super(hostname, port); 720 this.is_ssl=is_ssl; 721 } 722 723 public boolean ssl() { 724 return is_ssl; 725 } 726 727 public String toString() { 728 return super.toString() + " [ssl: " + ssl() + ']'; 729 } 730 } 731 732 738 class SocketAcceptor implements Runnable { 739 ServerSocket srv_sock=null; 740 MyInetSocketAddress dest=null; 741 742 743 748 public SocketAcceptor(MyInetSocketAddress sock_addr, MyInetSocketAddress dest) throws Exception { 749 this.dest=dest; 750 if(sock_addr.ssl()) { 751 srv_sock=createSSLServerSocket(sock_addr); 752 } 753 else { 754 srv_sock=createServerSocket(sock_addr); 755 } 756 executor.execute(this); 757 } 758 759 public void run() { 760 Connection conn; 761 Socket s, dest_sock; 762 763 while (srv_sock !=null) { 764 try { 765 s=srv_sock.accept(); 766 dest_sock=dest.ssl() ? createSSLSocket(dest) : createSocket(dest); 767 conn=new Connection(s, dest_sock); 768 conn.start(); 769 } 770 catch (Exception e) { 771 log("Proxy.SSLServerSocketAcceptor.run(): exception=" + e); 772 break; 773 } 774 } 775 } 776 777 778 Socket createSocket(InetSocketAddress addr) throws Exception { 779 return new Socket(addr.getAddress(), addr.getPort()); 780 } 781 782 Socket createSSLSocket(InetSocketAddress addr) throws Exception { 783 SSLSocketFactory sslsocketfactory = (SSLSocketFactory)SSLSocketFactory.getDefault(); 784 return sslsocketfactory.createSocket(addr.getAddress(), addr.getPort()); 785 } 786 787 ServerSocket createServerSocket(InetSocketAddress addr) throws Exception { 788 return new ServerSocket(addr.getPort(), 10, addr.getAddress()); 789 } 790 791 ServerSocket createSSLServerSocket(InetSocketAddress addr) throws Exception { 792 SSLServerSocketFactory sslserversocketfactory = 793 (SSLServerSocketFactory)SSLServerSocketFactory.getDefault(); 794 SSLServerSocket sslserversocket; 795 sslserversocket=(SSLServerSocket)sslserversocketfactory.createServerSocket(addr.getPort(), 10, addr.getAddress()); 796 return sslserversocket; 797 } 798 } 799 800 801 802 811 static class Connection implements Relayer.Listener { 812 Relayer in_to_out=null; 813 Relayer out_to_in=null; 814 815 823 public Connection(Socket in, Socket out) throws Exception { 824 in_to_out=new Relayer(in, out, "in-out"); 825 in_to_out.addListener(this); 826 out_to_in=new Relayer(out, in, "out-in"); 827 out_to_in.addListener(this); 828 } 829 830 834 public void start() { 835 in_to_out.start(); 836 out_to_in.start(); 837 } 838 839 public void stop() { 840 if (in_to_out !=null) { 841 in_to_out.stop(); 842 } 843 if (out_to_in !=null) { 844 out_to_in.stop(); 845 } 846 } 847 848 public void connectionClosed() { 849 stop(); 850 } 851 } 852 853 } 854 | Popular Tags |