搜索
查看: 353|回复: 2

内网穿透反向隧道代理技术

[复制链接]

1839

主题

2255

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
11913
发表于 2014-2-12 15:34:13 | 显示全部楼层 |阅读模式
本文的主要目的是利用使 ssh 服务器(外网)通过客户端(内网)代理上网以及反向控制客户端(内网),不需要网络管理员权限,不需要 NAT。即可上网主机 A 位于内网,不可上网主机 B 位于外网,A 能直接访问 B,但 B 无法访问防火墙内的 A,这样 B 就可以使用 SSH 隧道访问 A 主机上的代理服务器上网。(估计有这种变态需求的人只存在于大学中)
  1. B(210.77.*.*)---->(210.77.*.*)FW(192.168.0.*)|--->(192.168.0.*)A---->(192.168.0.*)FW(123.*.*.*)---->Internet
  2. B(210.77.*.*)< ----(210.77.*.*)FW(192.168.0.*)-----(192.168.0.*)A<----(192.168.0.*)FW(123.*.*.*)<----Internet
复制代码

一、代理
首先在客户端上安装 socks 代理(HTTP 代理可以使用 Squid,同理)。socks 代理软件使用 Dante。Dante 的启动以及配置需要手动调整,下面是 Dante 的配置文件 /etc/sockd.conf:
  1. compatibility:reuseaddr
  2. internal:0.0.0.0 port = 1080
  3. external:eth0
  4. logoutput:/var/log/sockd/sockd
  5. clientmethod:none
  6. method:none
  7. user.privileged:root
  8. user.notprivileged:solrex
  9. connecttimeout:60
  10. iotimeout:86400

  11. ## client access rules
  12. client pass {
  13. from: 127.0.0.1/0 port 1-65535 to: 0.0.0.0/0
  14. log: connect disconnect
  15. }

  16. ## server operation access rules
  17. #allow bind to ports greater than 1023
  18. pass {
  19.   from: 0.0.0.0/0 to: 0.0.0.0/0 port gt 1023
  20.   command: bind bindreply udpassociate udpreply
  21.   log: connect disconnect
  22. }

  23. pass {
  24.   from: 0.0.0.0/0 to: 0.0.0.0/0 port 1-65535
  25.   protocol: tcp udp
  26.   log: connect disconnect
  27. }

  28. #allow outgoing connections (tcp and udp)
  29. pass {
  30.   from: 127.0.0.1/0 to: 0.0.0.0/0
  31.   command: bind bindreply connect udpassociate udpreply
  32.   log: connect disconnect
  33. }

  34. #allow replies to bind, and incoming udp packets
  35. pass {
  36.    from: 0.0.0.0/0 to: 0.0.0.0/0
  37.    command: bind bindreply connect udpassociate udpreply
  38.    log: connect error
  39. }

  40. #log the rest
  41. block {
  42.    from: 0.0.0.0/0 to: 0.0.0.0/0
  43.    log: connect error
  44. }
复制代码

下面是 Dante 的启动脚本 /etc/init.d/sockd:
  1. #!/bin/sh
  2. set -e

  3. . /lib/lsb/init-functions

  4. [ -f /usr/local/sbin/sockd ] || exit 0

  5. [ ! -f /etc/sockd.conf ] && exit 1
  6. SOCKD_CONF="-f /etc/sockd.conf"

  7. SOCKD_OPTS="-D"

  8. case "$1" in
  9.   start)
  10.     # Start daemons.
  11.     log_daemon_msg "Starting Dante socks proxy server" "sockd"
  12.     if start-stop-daemon --start --quiet --oknodo --pidfile /var/run/sockd.pid --exec /usr/local/sbin/sockd -- $SOCKD_OPTS; then
  13.             log_end_msg 0
  14.         else
  15.             log_end_msg 1
  16.         fi
  17.     ;;
  18.   stop)
  19.     # Stop daemons.
  20.     log_daemon_msg "Stoping Dante socks proxy server" "sockd"
  21.         if start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/sockd.pid; then
  22.             log_end_msg 0
  23.         else
  24.             log_end_msg 1
  25.         fi
  26.         ;;
  27.   restart)
  28.     log_daemon_msg "Restarting Dante socks proxy server" "sockd"
  29.         start-stop-daemon --stop --quiet --oknodo --retry 30 --pidfile /var/run/sockd.pid
  30.         if start-stop-daemon --start --quiet --oknodo --pidfile /var/run/sockd.pid --exec /usr/local/sbin/sockd -- $SOCKD_OPTS; then
  31.             log_end_msg 0
  32.         else
  33.             log_end_msg 1
  34.         fi
  35.         ;;
  36.   *)
  37.     log_action_msg "Usage: /etc/init.d/sockd {start|stop|restart}\n"
  38.     exit 1
  39. esac

  40. exit 0
复制代码

二、ssh 服务器
服务器端 ssh 服务器最好采用 Openssh,Windows 下应该使用 Cygwin 运行 sshd,FreeSSHd 实践证明崩溃比较频繁。同一台机器的 Windows 和 Linux 上运行的 ssh 服务器最好使用相同的 host key,将 /etc/ssh/ 下面的文件保持一致即可。最好配置服务器为使用公钥进行登录验证,这样能使用自动脚本进行端口映射。
三、手动建立隧道(客户端到服务器端口映射)
用下面命令建立客户端到服务器的端口映射,将客户端的 socks 代理端口 1080 映射到服务器的端口 8080。这样服务器就可以通过自己的 8080 端口反向隧道到客户端的 socks 代理 1080 端口上网。
ssh -C -f -N -g -o PreferredAuthentications=publickey -R SERVER:8080:127.0.0.1:1080 USRNAME@SERVER
# 参数含义:
# -C: 要求对数据进行压缩
# -f:要求 ssh 执行完交互后进入后台运行
# -N:不用建立一个终端
# -g:允许远程服务器连接客户端转发端口
# -R SERVER:8080:127.0.0.1:1080:将客户机(127.0.0.1)的 1080 端口绑定到服务器(SERVER)的 8080 端口。
# USRNAME@SERVER:ssh服务器的用户名和密码
# -p 3022:ssh服务器的端口
为了方便控制,最好也将客户端的 ssh 服务器端口映射到服务器端,服务器端就可以通过登录自己的 8022 端口来登录客户端的 ssh 服务器:
  1. ssh -C -f -N -g -o PreferredAuthentications=publickey -R SERVER:8022:127.0.0.1:22 USRNAME@SERVER
复制代码

这样两台被防火墙隔开的主机就能实现双向控制。
四、自动建立隧道
手动建立隧道的缺陷是服务器端必须长期开机,并且连接只能用户在客户端手动发起。可以考虑间接的办法,比如使用两台主机均可访问的服务器作为跳板,或者客户端自动登录聊天软件,利用聊天软件接受指令。下面给出一种使用共享服务器的方法:
  1. #!/bin/bash
  2. # {start|stop|restart:username:ipaddress}

  3. COMMAND="stop"
  4. SERVER="0.0.0.0"
  5. USRNAME=""
  6. PORT="22"

  7. INFOURL="http://someserver.com/somepage"

  8. SSHOPTS="-C -f -N -g -o PreferredAuthentications=publickey -o StrictHostKeyChecking=no"

  9. get_server_info()
  10. {
  11.   #info=`wget -nv -O - $INFOURL 2> /dev/null | iconv -f gbk -t utf8 |
  12.         grep -o -e "{.*}" | tr -d '{}'`
  13.   info=`wget -nv -O - $INFOURL 2> /dev/null | iconv -f gbk -t utf8 |
  14.         sed -n "/{*}/s/.*{\(.*\)}.*/\1/p"`
  15.   COMMAND=${info%%:*}
  16.   SERVER=${info#*:}
  17.   USRNAME=${SERVER%:*}
  18.   SERVER=${SERVER#*:}
  19. }

  20. tunneling_status()
  21. {
  22.   tun_ps=`ps aux | grep "ssh -C" | wc -l`
  23.   if [ $tun_ps -gt 4 ]; then
  24.     echo -n "running"
  25.   else
  26.     echo -n "died"
  27.   fi
  28. }

  29. start_tunneling()
  30. {
  31.   ssh $SSHOPTS -R 3128:127.0.0.1:3128 ${USRNAME}@${SERVER} -p $PORT
  32.   ssh $SSHOPTS -R 8022:127.0.0.1:22 ${USRNAME}@${SERVER} -p $PORT
  33. }

  34. failsafe_tunneling()
  35. {
  36.   ssh $SSHOPTS -R 8022:127.0.0.1:22 ${USRNAME}@${SERVER} -p $PORT
  37. }

  38. stop_tunneling()
  39. {
  40.   killall -e ssh
  41. }

  42. echo -n "[`date +%F\ %R`] "
  43. get_server_info

  44. case "$COMMAND" in
  45.   start)
  46.     if [ $(tunneling_status) = "running" ]; then
  47.       echo "Starting ssh tunneling.(started, do nothing)"
  48.     else
  49.       echo "Starting ssh tunneling."
  50.       start_tunneling
  51.     fi
  52.     ;;
  53.   restart)
  54.     if [ $(tunneling_status) = "running" ]; then
  55.       echo "Restarting ssh tunneling."
  56.       stop_tunneling
  57.       start_tunneling
  58.     else
  59.       echo "Restarting ssh tunneling."
  60.       start_tunneling
  61.     fi
  62.     ;;
  63.   stop)
  64.     if [ $(tunneling_status) = "running" ]; then
  65.       echo "Stoping ssh tunneling."
  66.       stop_tunneling
  67.     else
  68.       echo "Stoping ssh tunneling.(stoped, do nothing)"
  69.     fi
  70.     ;;
  71.   failsafe)
  72.     echo "Starging ssh tunneling.(failsafe mode)"
  73.     failsafe_tunneling
  74.     ;;
  75.   sleep)
  76.     echo "Sleeping."
  77.     exit 0
  78.     ;;
  79.   *)
  80.     echo "Unrecogenized server command ($COMMAND)."
  81.     exit 1
  82.     ;;
  83. esac

  84. exit 0
复制代码

将上面脚本加入 crontab 每十分钟运行一次,就能实现在服务器端对客户端进行有限的控制。
过段时间可能会取消签到功能了
专业回帖 该用户已被删除
发表于 2014-2-12 15:47:41 | 显示全部楼层
帮帮顶顶!!
专业回帖 该用户已被删除
发表于 2014-2-12 16:45:46 | 显示全部楼层
我是个凑数的。。。
您需要登录后才可以回帖 登录 | Join BUC

本版积分规则

Powered by Discuz!

© 2012-2015 Baiker Union of China.

快速回复 返回顶部 返回列表