免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3347 | 回复: 0
打印 上一主题 下一主题

java 实现socks代理,包含sock4 sock5代理 [复制链接]

论坛徽章:
1
数据库技术版块每日发帖之星
日期:2015-07-11 22:20:00
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-07-14 09:37 |只看该作者 |倒序浏览
使用方法,直接编译后
USing port openSock4 openSock5 user pwd
端口号
是否开通sock4
是否开通sock5
user 不为空时表示 sock5需要使用账号登录 。

示例  java SocksServerOneThread 1080

[Java]代码
  1. import java.io.ByteArrayOutputStream;
  2. import java.io.Closeable;
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import java.io.OutputStream;
  6. import java.net.InetAddress;
  7. import java.net.ServerSocket;
  8. import java.net.Socket;
  9. import java.nio.ByteBuffer;
  10. import java.util.Arrays;
  11. import java.util.Date;
  12. import java.util.concurrent.CountDownLatch;

  13. /**
  14. * 标准的socks代理服务器,支持sock4与sock4代理
  15. *
  16. * @author Administrator
  17. *
  18. */
  19. public class SocksServerOneThread implements Runnable {

  20.     /**
  21.      * 来源的代理socket
  22.      */
  23.     private final Socket socket;
  24.     /**
  25.      * 是否开启socks4代理
  26.      */
  27.     private final boolean openSock4;
  28.     /**
  29.      * 是否开启socks5代理
  30.      */
  31.     private final boolean openSock5;
  32.     /**
  33.      * socks5代理的登录用户名,如果 不为空表示需要登录验证
  34.      */
  35.     private final String user;
  36.     /**
  37.      * socks5代理的登录密码,
  38.      */
  39.     private final String pwd;
  40.     /**
  41.      * socks是否需要进行登录验证
  42.      */
  43.     private final boolean socksNeekLogin;

  44.     /**
  45.      * @param socket
  46.      *            来源的代理socket
  47.      * @param openSock4
  48.      *            是否开启socks4代理
  49.      * @param openSock5
  50.      *            是否开启socks5代理
  51.      * @param user
  52.      *            socks5代理的登录用户名,如果 不为空表示需要登录验证
  53.      * @param pwd
  54.      *            socks5代理的登录密码,
  55.      */
  56.     protected SocksServerOneThread(Socket socket, boolean openSock4, boolean openSock5, String user, String pwd) {
  57.         this.socket = socket;
  58.         this.openSock4 = openSock4;
  59.         this.openSock5 = openSock5;
  60.         this.user = user;
  61.         this.pwd = pwd;
  62.         this.socksNeekLogin = null != user;
  63.     }

  64.     public void run() {
  65.         // 获取来源的地址用于日志打印使用
  66.         String addr = socket.getRemoteSocketAddress().toString();
  67.         log("process one socket : %s", addr);
  68.         // 声明流
  69.         InputStream a_in = null, b_in = null;
  70.         OutputStream a_out = null, b_out = null;
  71.         Socket proxy_socket = null;
  72.         ByteArrayOutputStream cache = null;
  73.         try {
  74.             a_in = socket.getInputStream();
  75.             a_out = socket.getOutputStream();

  76.             // 获取协议头。取代理的类型,只有 4,5。
  77.             byte[] tmp = new byte[1];
  78.             int n = a_in.read(tmp);
  79.             if (n == 1) {
  80.                 byte protocol = tmp[0];
  81.                 if ((openSock4 && 0x04 == protocol)) {// 如果开启代理4,并以socks4协议请求
  82.                     proxy_socket = sock4_check(a_in, a_out);
  83.                 } else if ((openSock5 && 0x05 == protocol)) {// 如果开启代理5,并以socks5协议请求
  84.                     proxy_socket = sock5_check(a_in, a_out);
  85.                 } else {// 非socks 4 ,5 协议的请求
  86.                     log("not socks proxy : %s  openSock4[] openSock5[]", tmp[0], openSock4, openSock5);
  87.                 }
  88.                 if (null != proxy_socket) {
  89.                     CountDownLatch latch = new CountDownLatch(1);
  90.                     b_in = proxy_socket.getInputStream();
  91.                     b_out = proxy_socket.getOutputStream();
  92.                     // 交换流数据
  93.                     if (80 == proxy_socket.getPort()) {
  94.                         cache = new ByteArrayOutputStream();
  95.                     }
  96.                     transfer(latch, a_in, b_out, cache);
  97.                     transfer(latch, b_in, a_out, cache);
  98.                     try {
  99.                         latch.await();
  100.                     } catch (Exception e) {
  101.                     }
  102.                 }
  103.             } else {
  104.                 log("socks error : %s", Arrays.toString(tmp));
  105.             }
  106.         } catch (Exception e) {
  107.             log("exception : %s %s", e.getClass(), e.getLocalizedMessage());
  108.             e.printStackTrace();
  109.         } finally {
  110.             log("close socket, system cleanning ...  %s ", addr);
  111.             closeIo(a_in);
  112.             closeIo(b_in);
  113.             closeIo(b_out);
  114.             closeIo(a_out);
  115.             closeIo(socket);
  116.             closeIo(proxy_socket);
  117.             if (null != cache) {
  118.                 cache2Local(cache);
  119.             }
  120.         }
  121.     }

  122.     private void cache2Local(ByteArrayOutputStream cache) {
  123.         // OutputStream result = null;
  124.         // try {
  125.         // String fileName = System.currentTimeMillis() + "_"
  126.         // + Thread.currentThread().getId();
  127.         // result = new FileOutputStream("E:/cache/" + fileName + ".info");
  128.         // result.write(cache.toByteArray());
  129.         // } catch (Exception e) {
  130.         // e.printStackTrace();
  131.         // } finally {
  132.         // closeIo(result);
  133.         // }
  134.     }

  135.     /**
  136.      * sock5代理头处理
  137.      *
  138.      * @param in
  139.      * @param out
  140.      * @return
  141.      * @throws IOException
  142.      */
  143.     private Socket sock5_check(InputStream in, OutputStream out) throws IOException {
  144.         byte[] tmp = new byte[2];
  145.         in.read(tmp);
  146.         boolean isLogin = false;
  147.         byte method = tmp[1];
  148.         if (0x02 == tmp[0]) {
  149.             method = 0x00;
  150.             in.read();
  151.         }
  152.         if (socksNeekLogin) {
  153.             method = 0x02;
  154.         }
  155.         tmp = new byte[] { 0x05, method };
  156.         out.write(tmp);
  157.         out.flush();
  158.         // Socket result = null;
  159.         Object resultTmp = null;
  160.         if (0x02 == method) {// 处理登录.
  161.             int b = in.read();
  162.             String user = null;
  163.             String pwd = null;
  164.             if (0x01 == b) {
  165.                 b = in.read();
  166.                 tmp = new byte[b];
  167.                 in.read(tmp);
  168.                 user = new String(tmp);
  169.                 b = in.read();
  170.                 tmp = new byte[b];
  171.                 in.read(tmp);
  172.                 pwd = new String(tmp);
  173.                 if (null != user && user.trim().equals(this.user) && null != pwd && pwd.trim().equals(this.pwd)) {// 权限过滤
  174.                     isLogin = true;
  175.                     tmp = new byte[] { 0x05, 0x00 };// 登录成功
  176.                     out.write(tmp);
  177.                     out.flush();
  178.                     log("%s login success !", user);
  179.                 } else {
  180.                     log("%s login faild !", user);
  181.                 }
  182.             }
  183.         }
  184.         byte cmd = 0;
  185.         if (!socksNeekLogin || isLogin) {// 验证是否需要登录
  186.             tmp = new byte[4];
  187.             in.read(tmp);
  188.             log("proxy header >>  %s", Arrays.toString(tmp));
  189.             cmd = tmp[1];
  190.             String host = getHost(tmp[3], in);
  191.             tmp = new byte[2];
  192.             in.read(tmp);
  193.             int port = ByteBuffer.wrap(tmp).asShortBuffer().get() & 0xFFFF;
  194.             log("connect %s:%s", host, port);
  195.             ByteBuffer rsv = ByteBuffer.allocate(10);
  196.             rsv.put((byte) 0x05);
  197.             try {
  198.                 if (0x01 == cmd) {
  199.                     resultTmp = new Socket(host, port);
  200.                     rsv.put((byte) 0x00);
  201.                 } else if (0x02 == cmd) {
  202.                     resultTmp = new ServerSocket(port);
  203.                     rsv.put((byte) 0x00);
  204.                 } else {
  205.                     rsv.put((byte) 0x05);
  206.                     resultTmp = null;
  207.                 }
  208.             } catch (Exception e) {
  209.                 rsv.put((byte) 0x05);
  210.                 resultTmp = null;
  211.             }
  212.             rsv.put((byte) 0x00);
  213.             rsv.put((byte) 0x01);
  214.             rsv.put(socket.getLocalAddress().getAddress());
  215.             Short localPort = (short) ((socket.getLocalPort()) & 0xFFFF);
  216.             rsv.putShort(localPort);
  217.             tmp = rsv.array();
  218.         } else {
  219.             tmp = new byte[] { 0x05, 0x01 };// 登录失败
  220.             log("socks server need login,but no login info .");
  221.         }
  222.         out.write(tmp);
  223.         out.flush();
  224.         if (null != resultTmp && 0x02 == cmd) {
  225.             ServerSocket ss = (ServerSocket) resultTmp;
  226.             try {
  227.                 resultTmp = ss.accept();
  228.             } catch (Exception e) {
  229.             } finally {
  230.                 closeIo(ss);
  231.             }
  232.         }
  233.         return (Socket) resultTmp;
  234.     }

  235.     /**
  236.      * sock4代理的头处理
  237.      *
  238.      * @param in
  239.      * @param out
  240.      * @return
  241.      * @throws IOException
  242.      */
  243.     private Socket sock4_check(InputStream in, OutputStream out) throws IOException {
  244.         Socket proxy_socket = null;
  245.         byte[] tmp = new byte[3];
  246.         in.read(tmp);
  247.         // 请求协议|VN1|CD1|DSTPORT2|DSTIP4|NULL1|
  248.         int port = ByteBuffer.wrap(tmp, 1, 2).asShortBuffer().get() & 0xFFFF;
  249.         String host = getHost((byte) 0x01, in);
  250.         in.read();
  251.         byte[] rsv = new byte[8];// 返回一个8位的响应协议
  252.         // |VN1|CD1|DSTPORT2|DSTIP 4|
  253.         try {
  254.             proxy_socket = new Socket(host, port);
  255.             log("connect [%s] %s:%s", tmp[1], host, port);
  256.             rsv[1] = 90;// 代理成功
  257.         } catch (Exception e) {
  258.             log("connect exception  %s:%s", host, port);
  259.             rsv[1] = 91;// 代理失败.
  260.         }
  261.         out.write(rsv);
  262.         out.flush();
  263.         return proxy_socket;
  264.     }

  265.     /**
  266.      * 获取目标的服务器地址
  267.      *
  268.      * @createTime 2014年12月14日 下午8:32:15
  269.      * @param type
  270.      * @param in
  271.      * @return
  272.      * @throws IOException
  273.      */
  274.     private String getHost(byte type, InputStream in) throws IOException {
  275.         String host = null;
  276.         byte[] tmp = null;
  277.         switch (type) {
  278.         case 0x01:// IPV4协议
  279.             tmp = new byte[4];
  280.             in.read(tmp);
  281.             host = InetAddress.getByAddress(tmp).getHostAddress();
  282.             break;
  283.         case 0x03:// 使用域名
  284.             int l = in.read();
  285.             tmp = new byte[l];
  286.             in.read(tmp);
  287.             host = new String(tmp);
  288.             break;
  289.         case 0x04:// 使用IPV6
  290.             tmp = new byte[16];
  291.             in.read(tmp);
  292.             host = InetAddress.getByAddress(tmp).getHostAddress();
  293.             break;
  294.         default:
  295.             break;
  296.         }
  297.         return host;
  298.     }

  299.     /**
  300.      * IO操作**同的关闭方法
  301.      *
  302.      * @createTime 2014年12月14日 下午7:50:56
  303.      * @param socket
  304.      */
  305.     protected static final void closeIo(Socket closeable) {
  306.         if (null != closeable) {
  307.             try {
  308.                 closeable.close();
  309.             } catch (IOException e) {
  310.             }
  311.         }
  312.     }

  313.     /**
  314.      * IO操作**同的关闭方法
  315.      *
  316.      * @createTime 2014年12月14日 下午7:50:56
  317.      * @param socket
  318.      */
  319.     protected static final void closeIo(Closeable closeable) {
  320.         if (null != closeable) {
  321.             try {
  322.                 closeable.close();
  323.             } catch (IOException e) {
  324.             }
  325.         }
  326.     }

  327.     /**
  328.      * 数据交换.主要用于tcp协议的交换
  329.      *
  330.      * @createTime 2014年12月13日 下午11:06:47
  331.      * @param lock
  332.      *            锁
  333.      * @param in
  334.      *            输入流
  335.      * @param out
  336.      *            输出流
  337.      */
  338.     protected static final void transfer(final CountDownLatch latch, final InputStream in, final OutputStream out,
  339.             final OutputStream cache) {
  340.         new Thread() {
  341.             public void run() {
  342.                 byte[] bytes = new byte[1024];
  343.                 int n = 0;
  344.                 try {
  345.                     while ((n = in.read(bytes)) > 0) {
  346.                         out.write(bytes, 0, n);
  347.                         out.flush();
  348.                         if (null != cache) {
  349.                             synchronized (cache) {
  350.                                 cache.write(bytes, 0, n);
  351.                             }
  352.                         }
  353.                     }
  354.                 } catch (Exception e) {
  355.                 }
  356.                 if (null != latch) {
  357.                     latch.countDown();
  358.                 }
  359.             };
  360.         }.start();
  361.     }

  362.     private final static void log(String message, Object... args) {
  363.         Date dat = new Date();
  364.         String msg = String.format("%1$tF %1$tT %2$-5s %3$s%n", dat, Thread.currentThread().getId(),
  365.                 String.format(message, args));
  366.         System.out.print(msg);
  367.     }

  368.     public static void startServer(int port, boolean openSock4, boolean openSock5, String user, String pwd)
  369.             throws IOException {
  370.         log("config >> port[%s] openSock4[%s] openSock5[%s] user[%s] pwd[%s]", port, openSock4, openSock5, user, pwd);
  371.         ServerSocket ss = new ServerSocket(port);
  372.         Socket socket = null;
  373.         log("Socks server port : %s listenning...", port);
  374.         while (null != (socket = ss.accept())) {
  375.             new Thread(new SocksServerOneThread(socket, openSock4, openSock5, user, pwd)).start();
  376.         }
  377.         ss.close();
  378.     }

  379.     public static void main(String[] args) throws IOException {
  380.         java.security.Security.setProperty("networkaddress.cache.ttl", "86400");
  381.         log("\n\tUSing port openSock4 openSock5 user pwd");
  382.         int port = 1080;
  383.         boolean openSock4 = true;
  384.         boolean openSock5 = true;
  385.         String user = null, pwd = null;
  386.         // user = "user";
  387.         pwd = "123456";
  388.         int i = 0;
  389.         if (args.length > i && null != args[i++]) {
  390.             port = Integer.valueOf(args[i].trim());
  391.         }
  392.         if (args.length > i && null != args[i++]) {
  393.             openSock4 = Boolean.valueOf(args[i].trim());
  394.         }
  395.         if (args.length > i && null != args[i++]) {
  396.             openSock5 = Boolean.valueOf(args[i].trim());
  397.         }
  398.         if (args.length > i && null != args[i++]) {
  399.             user = args[i].trim();
  400.         }
  401.         if (args.length > i && null != args[i++]) {
  402.             pwd = args[i].trim();
  403.         }
  404.         SocksServerOneThread.startServer(port, openSock4, openSock5, user, pwd);
  405.     }
  406. }
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP