590 throw ex; |
516 throw ex; |
591 } |
517 } |
592 external_address = epoint; |
518 external_address = epoint; |
593 } |
519 } |
594 |
520 |
595 private void bindV4(InputStream in, OutputStream out, |
|
596 InetAddress baddr, |
|
597 int lport) throws IOException { |
|
598 if (!(baddr instanceof Inet4Address)) { |
|
599 throw new SocketException("SOCKS V4 requires IPv4 only addresses"); |
|
600 } |
|
601 super.bind(baddr, lport); |
|
602 byte[] addr1 = baddr.getAddress(); |
|
603 /* Test for AnyLocal */ |
|
604 InetAddress naddr = baddr; |
|
605 if (naddr.isAnyLocalAddress()) { |
|
606 naddr = AccessController.doPrivileged( |
|
607 new PrivilegedAction<>() { |
|
608 public InetAddress run() { |
|
609 return cmdsock.getLocalAddress(); |
|
610 |
|
611 } |
|
612 }); |
|
613 addr1 = naddr.getAddress(); |
|
614 } |
|
615 out.write(PROTO_VERS4); |
|
616 out.write(BIND); |
|
617 out.write((super.getLocalPort() >> 8) & 0xff); |
|
618 out.write((super.getLocalPort() >> 0) & 0xff); |
|
619 out.write(addr1); |
|
620 String userName = getUserName(); |
|
621 try { |
|
622 out.write(userName.getBytes("ISO-8859-1")); |
|
623 } catch (java.io.UnsupportedEncodingException uee) { |
|
624 assert false; |
|
625 } |
|
626 out.write(0); |
|
627 out.flush(); |
|
628 byte[] data = new byte[8]; |
|
629 int n = readSocksReply(in, data); |
|
630 if (n != 8) |
|
631 throw new SocketException("Reply from SOCKS server has bad length: " + n); |
|
632 if (data[0] != 0 && data[0] != 4) |
|
633 throw new SocketException("Reply from SOCKS server has bad version"); |
|
634 SocketException ex = null; |
|
635 switch (data[1]) { |
|
636 case 90: |
|
637 // Success! |
|
638 external_address = new InetSocketAddress(baddr, lport); |
|
639 break; |
|
640 case 91: |
|
641 ex = new SocketException("SOCKS request rejected"); |
|
642 break; |
|
643 case 92: |
|
644 ex = new SocketException("SOCKS server couldn't reach destination"); |
|
645 break; |
|
646 case 93: |
|
647 ex = new SocketException("SOCKS authentication failed"); |
|
648 break; |
|
649 default: |
|
650 ex = new SocketException("Reply from SOCKS server contains bad status"); |
|
651 break; |
|
652 } |
|
653 if (ex != null) { |
|
654 in.close(); |
|
655 out.close(); |
|
656 throw ex; |
|
657 } |
|
658 |
|
659 } |
|
660 |
|
661 /** |
|
662 * Sends the Bind request to the SOCKS proxy. In the SOCKS protocol, bind |
|
663 * means "accept incoming connection from", so the SocketAddress is |
|
664 * the one of the host we do accept connection from. |
|
665 * |
|
666 * @param saddr the Socket address of the remote host. |
|
667 * @exception IOException if an I/O error occurs when binding this socket. |
|
668 */ |
|
669 protected synchronized void socksBind(InetSocketAddress saddr) throws IOException { |
|
670 if (((SocketImpl) this).socket != null) { |
|
671 // this is a client socket, not a server socket, don't |
|
672 // call the SOCKS proxy for a bind! |
|
673 return; |
|
674 } |
|
675 |
|
676 // Connects to the SOCKS server |
|
677 |
|
678 if (server == null) { |
|
679 // This is the general case |
|
680 // server is not null only when the socket was created with a |
|
681 // specified proxy in which case it does bypass the ProxySelector |
|
682 ProxySelector sel = java.security.AccessController.doPrivileged( |
|
683 new java.security.PrivilegedAction<>() { |
|
684 public ProxySelector run() { |
|
685 return ProxySelector.getDefault(); |
|
686 } |
|
687 }); |
|
688 if (sel == null) { |
|
689 /* |
|
690 * No default proxySelector --> direct connection |
|
691 */ |
|
692 return; |
|
693 } |
|
694 URI uri; |
|
695 // Use getHostString() to avoid reverse lookups |
|
696 String host = saddr.getHostString(); |
|
697 // IPv6 literal? |
|
698 if (saddr.getAddress() instanceof Inet6Address && |
|
699 (!host.startsWith("[")) && (host.indexOf(':') >= 0)) { |
|
700 host = "[" + host + "]"; |
|
701 } |
|
702 try { |
|
703 uri = new URI("serversocket://" + ParseUtil.encodePath(host) + ":"+ saddr.getPort()); |
|
704 } catch (URISyntaxException e) { |
|
705 // This shouldn't happen |
|
706 assert false : e; |
|
707 uri = null; |
|
708 } |
|
709 Proxy p = null; |
|
710 Exception savedExc = null; |
|
711 java.util.Iterator<Proxy> iProxy = null; |
|
712 iProxy = sel.select(uri).iterator(); |
|
713 if (iProxy == null || !(iProxy.hasNext())) { |
|
714 return; |
|
715 } |
|
716 while (iProxy.hasNext()) { |
|
717 p = iProxy.next(); |
|
718 if (p == null || p.type() != Proxy.Type.SOCKS) { |
|
719 return; |
|
720 } |
|
721 |
|
722 if (!(p.address() instanceof InetSocketAddress)) |
|
723 throw new SocketException("Unknown address type for proxy: " + p); |
|
724 // Use getHostString() to avoid reverse lookups |
|
725 server = ((InetSocketAddress) p.address()).getHostString(); |
|
726 serverPort = ((InetSocketAddress) p.address()).getPort(); |
|
727 useV4 = useV4(p); |
|
728 |
|
729 // Connects to the SOCKS server |
|
730 try { |
|
731 AccessController.doPrivileged( |
|
732 new PrivilegedExceptionAction<>() { |
|
733 public Void run() throws Exception { |
|
734 cmdsock = new Socket(new NioSocketImpl(false)); |
|
735 cmdsock.connect(new InetSocketAddress(server, serverPort)); |
|
736 cmdIn = cmdsock.getInputStream(); |
|
737 cmdOut = cmdsock.getOutputStream(); |
|
738 return null; |
|
739 } |
|
740 }); |
|
741 } catch (Exception e) { |
|
742 // Ooops, let's notify the ProxySelector |
|
743 sel.connectFailed(uri,p.address(),new SocketException(e.getMessage())); |
|
744 server = null; |
|
745 serverPort = -1; |
|
746 cmdsock = null; |
|
747 savedExc = e; |
|
748 // Will continue the while loop and try the next proxy |
|
749 } |
|
750 } |
|
751 |
|
752 /* |
|
753 * If server is still null at this point, none of the proxy |
|
754 * worked |
|
755 */ |
|
756 if (server == null || cmdsock == null) { |
|
757 throw new SocketException("Can't connect to SOCKS proxy:" |
|
758 + savedExc.getMessage()); |
|
759 } |
|
760 } else { |
|
761 try { |
|
762 AccessController.doPrivileged( |
|
763 new PrivilegedExceptionAction<>() { |
|
764 public Void run() throws Exception { |
|
765 cmdsock = new Socket(new NioSocketImpl(false)); |
|
766 cmdsock.connect(new InetSocketAddress(server, serverPort)); |
|
767 cmdIn = cmdsock.getInputStream(); |
|
768 cmdOut = cmdsock.getOutputStream(); |
|
769 return null; |
|
770 } |
|
771 }); |
|
772 } catch (Exception e) { |
|
773 throw new SocketException(e.getMessage()); |
|
774 } |
|
775 } |
|
776 BufferedOutputStream out = new BufferedOutputStream(cmdOut, 512); |
|
777 InputStream in = cmdIn; |
|
778 if (useV4) { |
|
779 bindV4(in, out, saddr.getAddress(), saddr.getPort()); |
|
780 return; |
|
781 } |
|
782 out.write(PROTO_VERS); |
|
783 out.write(2); |
|
784 out.write(NO_AUTH); |
|
785 out.write(USER_PASSW); |
|
786 out.flush(); |
|
787 byte[] data = new byte[2]; |
|
788 int i = readSocksReply(in, data); |
|
789 if (i != 2 || ((int)data[0]) != PROTO_VERS) { |
|
790 // Maybe it's not a V5 sever after all |
|
791 // Let's try V4 before we give up |
|
792 bindV4(in, out, saddr.getAddress(), saddr.getPort()); |
|
793 return; |
|
794 } |
|
795 if (((int)data[1]) == NO_METHODS) |
|
796 throw new SocketException("SOCKS : No acceptable methods"); |
|
797 if (!authenticate(data[1], in, out)) { |
|
798 throw new SocketException("SOCKS : authentication failed"); |
|
799 } |
|
800 // We're OK. Let's issue the BIND command. |
|
801 out.write(PROTO_VERS); |
|
802 out.write(BIND); |
|
803 out.write(0); |
|
804 int lport = saddr.getPort(); |
|
805 if (saddr.isUnresolved()) { |
|
806 out.write(DOMAIN_NAME); |
|
807 out.write(saddr.getHostName().length()); |
|
808 try { |
|
809 out.write(saddr.getHostName().getBytes("ISO-8859-1")); |
|
810 } catch (java.io.UnsupportedEncodingException uee) { |
|
811 assert false; |
|
812 } |
|
813 out.write((lport >> 8) & 0xff); |
|
814 out.write((lport >> 0) & 0xff); |
|
815 } else if (saddr.getAddress() instanceof Inet4Address) { |
|
816 byte[] addr1 = saddr.getAddress().getAddress(); |
|
817 out.write(IPV4); |
|
818 out.write(addr1); |
|
819 out.write((lport >> 8) & 0xff); |
|
820 out.write((lport >> 0) & 0xff); |
|
821 out.flush(); |
|
822 } else if (saddr.getAddress() instanceof Inet6Address) { |
|
823 byte[] addr1 = saddr.getAddress().getAddress(); |
|
824 out.write(IPV6); |
|
825 out.write(addr1); |
|
826 out.write((lport >> 8) & 0xff); |
|
827 out.write((lport >> 0) & 0xff); |
|
828 out.flush(); |
|
829 } else { |
|
830 cmdsock.close(); |
|
831 throw new SocketException("unsupported address type : " + saddr); |
|
832 } |
|
833 data = new byte[4]; |
|
834 i = readSocksReply(in, data); |
|
835 SocketException ex = null; |
|
836 int len, nport; |
|
837 byte[] addr; |
|
838 switch (data[1]) { |
|
839 case REQUEST_OK: |
|
840 // success! |
|
841 switch(data[3]) { |
|
842 case IPV4: |
|
843 addr = new byte[4]; |
|
844 i = readSocksReply(in, addr); |
|
845 if (i != 4) |
|
846 throw new SocketException("Reply from SOCKS server badly formatted"); |
|
847 data = new byte[2]; |
|
848 i = readSocksReply(in, data); |
|
849 if (i != 2) |
|
850 throw new SocketException("Reply from SOCKS server badly formatted"); |
|
851 nport = ((int)data[0] & 0xff) << 8; |
|
852 nport += ((int)data[1] & 0xff); |
|
853 external_address = |
|
854 new InetSocketAddress(new Inet4Address("", addr) , nport); |
|
855 break; |
|
856 case DOMAIN_NAME: |
|
857 len = data[1]; |
|
858 byte[] host = new byte[len]; |
|
859 i = readSocksReply(in, host); |
|
860 if (i != len) |
|
861 throw new SocketException("Reply from SOCKS server badly formatted"); |
|
862 data = new byte[2]; |
|
863 i = readSocksReply(in, data); |
|
864 if (i != 2) |
|
865 throw new SocketException("Reply from SOCKS server badly formatted"); |
|
866 nport = ((int)data[0] & 0xff) << 8; |
|
867 nport += ((int)data[1] & 0xff); |
|
868 external_address = new InetSocketAddress(new String(host), nport); |
|
869 break; |
|
870 case IPV6: |
|
871 len = data[1]; |
|
872 addr = new byte[len]; |
|
873 i = readSocksReply(in, addr); |
|
874 if (i != len) |
|
875 throw new SocketException("Reply from SOCKS server badly formatted"); |
|
876 data = new byte[2]; |
|
877 i = readSocksReply(in, data); |
|
878 if (i != 2) |
|
879 throw new SocketException("Reply from SOCKS server badly formatted"); |
|
880 nport = ((int)data[0] & 0xff) << 8; |
|
881 nport += ((int)data[1] & 0xff); |
|
882 external_address = |
|
883 new InetSocketAddress(new Inet6Address("", addr), nport); |
|
884 break; |
|
885 } |
|
886 break; |
|
887 case GENERAL_FAILURE: |
|
888 ex = new SocketException("SOCKS server general failure"); |
|
889 break; |
|
890 case NOT_ALLOWED: |
|
891 ex = new SocketException("SOCKS: Bind not allowed by ruleset"); |
|
892 break; |
|
893 case NET_UNREACHABLE: |
|
894 ex = new SocketException("SOCKS: Network unreachable"); |
|
895 break; |
|
896 case HOST_UNREACHABLE: |
|
897 ex = new SocketException("SOCKS: Host unreachable"); |
|
898 break; |
|
899 case CONN_REFUSED: |
|
900 ex = new SocketException("SOCKS: Connection refused"); |
|
901 break; |
|
902 case TTL_EXPIRED: |
|
903 ex = new SocketException("SOCKS: TTL expired"); |
|
904 break; |
|
905 case CMD_NOT_SUPPORTED: |
|
906 ex = new SocketException("SOCKS: Command not supported"); |
|
907 break; |
|
908 case ADDR_TYPE_NOT_SUP: |
|
909 ex = new SocketException("SOCKS: address type not supported"); |
|
910 break; |
|
911 } |
|
912 if (ex != null) { |
|
913 in.close(); |
|
914 out.close(); |
|
915 cmdsock.close(); |
|
916 cmdsock = null; |
|
917 throw ex; |
|
918 } |
|
919 cmdIn = in; |
|
920 cmdOut = out; |
|
921 } |
|
922 |
|
923 /** |
|
924 * Accepts a connection from a specific host. |
|
925 * |
|
926 * @param s the accepted connection. |
|
927 * @param saddr the socket address of the host we do accept |
|
928 * connection from |
|
929 * @exception IOException if an I/O error occurs when accepting the |
|
930 * connection. |
|
931 */ |
|
932 protected void acceptFrom(SocketImpl s, InetSocketAddress saddr) throws IOException { |
|
933 if (cmdsock == null) { |
|
934 // Not a Socks ServerSocket. |
|
935 return; |
|
936 } |
|
937 InputStream in = cmdIn; |
|
938 // Sends the "SOCKS BIND" request. |
|
939 socksBind(saddr); |
|
940 in.read(); |
|
941 int i = in.read(); |
|
942 in.read(); |
|
943 SocketException ex = null; |
|
944 int nport; |
|
945 byte[] addr; |
|
946 InetSocketAddress real_end = null; |
|
947 switch (i) { |
|
948 case REQUEST_OK: |
|
949 // success! |
|
950 i = in.read(); |
|
951 switch(i) { |
|
952 case IPV4: |
|
953 addr = new byte[4]; |
|
954 readSocksReply(in, addr); |
|
955 nport = in.read() << 8; |
|
956 nport += in.read(); |
|
957 real_end = |
|
958 new InetSocketAddress(new Inet4Address("", addr) , nport); |
|
959 break; |
|
960 case DOMAIN_NAME: |
|
961 int len = in.read(); |
|
962 addr = new byte[len]; |
|
963 readSocksReply(in, addr); |
|
964 nport = in.read() << 8; |
|
965 nport += in.read(); |
|
966 real_end = new InetSocketAddress(new String(addr), nport); |
|
967 break; |
|
968 case IPV6: |
|
969 addr = new byte[16]; |
|
970 readSocksReply(in, addr); |
|
971 nport = in.read() << 8; |
|
972 nport += in.read(); |
|
973 real_end = |
|
974 new InetSocketAddress(new Inet6Address("", addr), nport); |
|
975 break; |
|
976 } |
|
977 break; |
|
978 case GENERAL_FAILURE: |
|
979 ex = new SocketException("SOCKS server general failure"); |
|
980 break; |
|
981 case NOT_ALLOWED: |
|
982 ex = new SocketException("SOCKS: Accept not allowed by ruleset"); |
|
983 break; |
|
984 case NET_UNREACHABLE: |
|
985 ex = new SocketException("SOCKS: Network unreachable"); |
|
986 break; |
|
987 case HOST_UNREACHABLE: |
|
988 ex = new SocketException("SOCKS: Host unreachable"); |
|
989 break; |
|
990 case CONN_REFUSED: |
|
991 ex = new SocketException("SOCKS: Connection refused"); |
|
992 break; |
|
993 case TTL_EXPIRED: |
|
994 ex = new SocketException("SOCKS: TTL expired"); |
|
995 break; |
|
996 case CMD_NOT_SUPPORTED: |
|
997 ex = new SocketException("SOCKS: Command not supported"); |
|
998 break; |
|
999 case ADDR_TYPE_NOT_SUP: |
|
1000 ex = new SocketException("SOCKS: address type not supported"); |
|
1001 break; |
|
1002 } |
|
1003 if (ex != null) { |
|
1004 cmdIn.close(); |
|
1005 cmdOut.close(); |
|
1006 cmdsock.close(); |
|
1007 cmdsock = null; |
|
1008 throw ex; |
|
1009 } |
|
1010 |
|
1011 /** |
|
1012 * This is where we have to do some fancy stuff. |
|
1013 * The datastream from the socket "accepted" by the proxy will |
|
1014 * come through the cmdSocket. So we have to swap the socketImpls |
|
1015 */ |
|
1016 if (s instanceof SocksSocketImpl) { |
|
1017 ((SocksSocketImpl)s).external_address = real_end; |
|
1018 } |
|
1019 if (s instanceof PlainSocketImpl) { |
|
1020 PlainSocketImpl psi = (PlainSocketImpl) s; |
|
1021 psi.setInputStream((SocketInputStream) in); |
|
1022 psi.setFileDescriptor(cmdsock.getImpl().getFileDescriptor()); |
|
1023 psi.setAddress(cmdsock.getImpl().getInetAddress()); |
|
1024 psi.setPort(cmdsock.getImpl().getPort()); |
|
1025 psi.setLocalPort(cmdsock.getImpl().getLocalPort()); |
|
1026 } else { |
|
1027 s.fd = cmdsock.getImpl().fd; |
|
1028 s.address = cmdsock.getImpl().address; |
|
1029 s.port = cmdsock.getImpl().port; |
|
1030 s.localport = cmdsock.getImpl().localport; |
|
1031 } |
|
1032 |
|
1033 // Need to do that so that the socket won't be closed |
|
1034 // when the ServerSocket is closed by the user. |
|
1035 // It kinds of detaches the Socket because it is now |
|
1036 // used elsewhere. |
|
1037 cmdsock = null; |
|
1038 } |
|
1039 |
521 |
1040 |
522 |
1041 /** |
523 /** |
1042 * Returns the value of this socket's {@code address} field. |
524 * Returns the value of this socket's {@code address} field. |
1043 * |
525 * |